go で Google Cloud Text-to-Speech のチュートリアルをやってみた

はじめに

Google Cloud Text-to-Speech API で、テキストから音声を作成する方法を理解するため、以下のチュートリアルをやってみた。

go のソースは、オリジナルから変更しており、テキストをファイルから読み込めるようにし、SSML 形式も利用できるようにしている。

チュートリアルを実施している様子を、YouTube にアップロードした。

利用 API

  • Cloud Text-to-Speech API

事前準備

Google Cloud のプロジェクトは、作成済みとする。課金可能であること。
go 言語をインストール済みとする。
gcloud コマンドが利用可能とする。
gcloud のデフォルトプロジェクトは、以下のように設定済みとする。
gcloud config set project YOUR_PROJECT_ID

チュートリアル実施

Cloud Text-to-Speech API を有効化する

gcloud コマンドの場合

gcloud services enable texttospeech.googleapis.com

Cloud コンソールの場合

「ナビゲーションメニュー」→「API とサービス」→「ライブラリ」を選択。
「Cloud Text-to-Speech API」を検索して選択する。
「有効にする」ボタンをクリックする。

サービスアカウントを作成する

gcloud コマンドの場合

gcloud iam service-accounts create text-to-speech --display-name="text-to-speech"

Cloud コンソールの場合

「ナビゲーションメニュー」→「IAM と管理」→「サービス アカウント」を選択。
「サービス アカウントを作成」をクリックする。
任意の「サービスアカウント名」および、「サービスアカウント ID」を入力する(ここでは、両方とも「text-to-speech」)。
「完了」ボタンをクリックする。

サービス アカウントの「認証情報キーファイル」をダウンロードする

gcloud コマンドの場合

「YOUR_PROJECT_ID」の部分は、プロジェクト ID に置換すること。
gcloud iam service-accounts keys create text-to-speech_key1.json --iam-account=text-to-speech@YOUR_PROJECT_ID.iam.gserviceaccount.com

Cloud コンソールの場合

「ナビゲーションメニュー」→「IAM と管理」→「サービス アカウント」を選択。
名前項目が、「text-to-speech」となっている行のメール部分をクリックする。
「キー」タブをクリックする。
「鍵を追加」ボタンをクリックし、「新しい鍵を作成」を選択する。
キーのタイプは、「JSON」を選択し、「作成」ボタンをクリックする。
JSON 形式の「認証情報キーファイル」がダウンロードされる。

ソースコードを作成する

mkdir text-to-speech-client
cd text-to-speech-client
go mod init text-to-speech-client
go get cloud.google.com/go/texttospeech/apiv1
main.go ファイルを以下の内容で作成する。
package main

import (
	texttospeech "cloud.google.com/go/texttospeech/apiv1"
	"cloud.google.com/go/texttospeech/apiv1/texttospeechpb"
	"context"
	"flag"
	"fmt"
	"log"
	"os"
	"path/filepath"
)

func main() {
	// 音声名
	voiceName := flag.String("name", "ja-JP-Wavenet-B", "voice name")
	// 出力ファイル名
	out := flag.String("out", "", "output filename")
	flag.Parse()

	// 入力ファイル名
	inFile := flag.Arg(0)
	if inFile == "" {
		log.Fatalln("Please specify an input file.")
	}
	ext := filepath.Ext(inFile)
	outFile := *out
	if outFile == "" {
		outFile = inFile[0:len(inFile)-len(ext)] + ".mp3"
	}
	isSsml := ext == ".ssml"

	data, err := os.ReadFile(inFile)
	if err != nil {
		log.Fatal(err)
	}
	text := string(data)

	ctx := context.Background()
	client, err := texttospeech.NewClient(ctx)
	if err != nil {
		log.Fatal(err)
	}
	defer func() {
		err := client.Close()
		if err != nil {
			log.Fatal(err)
		}
	}()

	var input *texttospeechpb.SynthesisInput
	if isSsml {
		input = &texttospeechpb.SynthesisInput{
			InputSource: &texttospeechpb.SynthesisInput_Ssml{Ssml: text},
		}
	} else {
		input = &texttospeechpb.SynthesisInput{
			InputSource: &texttospeechpb.SynthesisInput_Text{Text: text},
		}
	}

	req := texttospeechpb.SynthesizeSpeechRequest{
		Input: input,
		Voice: &texttospeechpb.VoiceSelectionParams{
			LanguageCode: "ja-JP",
			Name:         *voiceName,
		},
		AudioConfig: &texttospeechpb.AudioConfig{
			AudioEncoding: texttospeechpb.AudioEncoding_MP3,
		},
	}

	resp, err := client.SynthesizeSpeech(ctx, &req)
	if err != nil {
		log.Fatal(err)
	}

	err = os.WriteFile(outFile, resp.AudioContent, 0644)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("Audio content written to file: %v\n", outFile)
}

入力ファイルを作成する

data.ssml ファイルを以下の内容で作成する。
<speak>
    今日な
    <break strength="weak" />
    <voice name="ja-JP-Wavenet-C">うん</voice>
    <break strength="weak" />
    <say-as interpret-as="characters">SSML</say-as>が、難しかった
    <break strength="weak" />
    <voice name="ja-JP-Wavenet-C"><prosody pitch="-10%">うん</prosody></voice>
    <break strength="weak" />
    よくわからんかった
    <break strength="weak" />
    <voice name="ja-JP-Wavenet-C"><prosody pitch="-20%">うん</prosody></voice>
    <break time="2s" />
    一億もらうね
    <voice name="ja-JP-Wavenet-C"><prosody pitch="-30%">うん</prosody></voice>
    <par>
        <media>
            <speak>
                <prosody rate="x-fast">よし</prosody>
            </speak>
        </media>
        <media begin="0.3s">
            <speak>
                <voice name="ja-JP-Wavenet-C">え?</voice>
            </speak>
        </media>
    </par>
</speak>

入力ファイルを音声データに変換する

ダウンロードした「認証情報キーファイル」をカレントディレクトリにコピーする。 コマンドの「認証情報キーファイル名」部分を置き換えること。
go mod tidy
go build .
set GOOGLE_APPLICATION_CREDENTIALS=認証情報キーファイル名
text-to-speech-client data.ssml
コマンドの実行が完了すると、data.mp3 ファイルが作成される。

出力ファイル名は、入力ファイル名の拡張子を .mp3 に変えたものとなる。--out オプションで指定する事も可能。
拡張子が .ssml 以外(.txt など)の入力ファイルを渡した場合は、SSML タグを解析せずに、そのまま読み上げる mp3 ファイルとなる。
デフォルトの音声は、--name オプションで指定可能。指定可能な音声はサポートされている音声と言語を参照。

後片付け

サービスアカウントを削除する

gcloud コマンドの場合

gcloud iam service-accounts delete text-to-speech

Cloud コンソールの場合

「ナビゲーションメニュー」→「IAM と管理」→「サービス アカウント」を選択。
名前項目が、「text-to-speech」となっている行をチェックし、上部の「削除」をクリックする。
開いたダイアログで、「削除」をクリックする。

Cloud Text-to-Speech API を無効化する

gcloud コマンドの場合

gcloud services disable texttospeech.googleapis.com

Cloud コンソールの場合

「ナビゲーションメニュー」→「API とサービス」→「有効な API とサービス」を選択。
一覧の「Cloud Text-to-Speech API」をクリックする。
上部の「API を無効にする」ボタンをクリックする。
開いたダイアログで、「無効にする」ボタンをクリックする。

参考資料