9
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Go】Echo × VOICEVOX で謎言語をずんだもんに読み上げてもらう

9
Last updated at Posted at 2025-11-27

1. 概要

以前、「ぱ行で会話するための変換プログラムを作成」という記事を書きました。
今回は、その変換プログラムで生成されたテキストをずんだもんで読み上げる機能を実施します。

2. 環境・技術スタック

  • OS: Windows11
  • 開発言語: Go 1.23
  • Webフレームワーク:Echo v4
  • 音声合成:エンジンVOICEVOX Engine

3. 構成図

今回はWindows環境で動作するのを目的としています。

image.png

4. VOICEVOXのセットアップ

VOICEVOXは無料で使える高品質な音声合成エンジンです。ずんだもん四国めたんなど、様々なキャラクターの声で音声を生成できます。

VOICEVOX公式サイトからダウンロード

環境に合わせてダウンロードしてください。私はこのままの設定でダウンロードしました。

image.png

② インストールして起動

アプリが立ち上がりますが、今回は GUI ではなく API の利用が目的なので、この画面は使いません。

image.png

③ 起動確認

ブラウザで確認

開発で使用するVOICEVOXのAPIが正常に起動しているか確認します。

http://localhost:50021/docsにアクセスすると、APIのドキュメントが見えると思います。

image.png

CURLで確認

curl http://localhost:50021/speakers

以下のようなJSONが返ってくればOKです:

[
  {
    "name": "四国めたん",
    "speaker_uuid": "...",
    "styles": [...]
  },
  {
    "name": "ずんだもん",
    "speaker_uuid": "...",
    "styles": [...]
  },
  ...
]

5. GOプログラム実装

以下がGoで書いたコードです。ざっくりとコメントで処理の内容を記載しました。

handlers/handlers.go
package handlers

import (
	"bytes"
	"fmt"
	"io"
	"net/http"
	"net/url"
	"os"
	"strconv"

	"github.com/labstack/echo/v4"
)

// VOICEVOX APIのベースURL取得
func getVoicevoxBaseURL() string {
	if url := os.Getenv("VOICEVOX_URL"); url != "" {
		return url
	}
	return "http://localhost:50021"
}

// リクエストボディの構造体
type VoiceRequest struct {
	Text string `json:"text"`
}

// 音声生成ハンドラ
func GenerateVoiceHandler(c echo.Context) error {
    // 1. VOICEVOX サーバーの URL を取得
	baseURL := getVoicevoxBaseURL()

	// 2. リクエストから text を取得
	var req VoiceRequest
	if err := c.Bind(&req); err != nil || req.Text == "" {
		req.Text = c.QueryParam("text")
	}

	if req.Text == "" {
		return c.JSON(http.StatusBadRequest, map[string]string{
			"error": "textが指定されていません",
		})
	}

	speakerID := 3 // ずんだもんを指定

	// 3. VOICEVOX に audio_query を投げる
	params := url.Values{}
	params.Set("text", req.Text)
	params.Set("speaker", strconv.Itoa(speakerID))
	audioQueryURL := fmt.Sprintf("%s/audio_query?%s", baseURL, params.Encode())

	resp, err := http.Post(audioQueryURL, "application/json", nil)
	if err != nil {
		return c.JSON(http.StatusInternalServerError, map[string]string{
			"error": "audio_queryに失敗しました",
		})
	}
	defer resp.Body.Close()

	audioQuery, err := io.ReadAll(resp.Body)
	if err != nil {
		return c.JSON(http.StatusInternalServerError, map[string]string{
			"error": "audio_queryの応答取得に失敗しました",
		})
	}

	// 4. クエリをもとに実際の音声(WAV)を生成
	synthesisURL := fmt.Sprintf("%s/synthesis?speaker=%d", baseURL, speakerID)

	resp2, err := http.Post(synthesisURL, "application/json", bytes.NewReader(audioQuery))
	if err != nil {
		return c.JSON(http.StatusInternalServerError, map[string]string{
			"error": "synthesisに失敗しました",
		})
	}
	defer resp2.Body.Close()

	wavData, err := io.ReadAll(resp2.Body)
	if err != nil {
		return c.JSON(http.StatusInternalServerError, map[string]string{
			"error": "音声データの読み取りに失敗しました",
		})
	}

	// 5. WAVを返す
	c.Response().Header().Set("Content-Type", "audio/wav")
	return c.Blob(http.StatusOK, "audio/wav", wavData)
}

6. 実際にできたもの

以下は実際に動かしたときの画面(GIF)です。
残念ながら、音声は載せられませんでしたが、ずんだもんを感じ取ってください。

Animation1.gif

7. おわりに

Go と VOICEVOX を組み合わせることで、手軽に音声合成 API を構築できました。
このクオリティを無料で提供してくださっている VOICEVOX の開発者の皆さんには感謝しかありません。

ソースコードは以下のリポジトリで公開しています。
興味のある方はぜひチェックしてみてください。

ここまで読んで頂きありがとうございました。

9
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?