feat: use VOICEVOX API for TTS

This commit is contained in:
2025-06-04 11:26:55 +09:00
parent b8d53f31c7
commit 7193dd8bb7

View File

@ -1,37 +1,69 @@
import fs from "fs";
import path from "path";
import { PollyClient, SynthesizeSpeechCommand } from "@aws-sdk/client-polly";
import fetch from "node-fetch";
const polly = new PollyClient({ region: "ap-northeast-1" });
// VOICEVOX APIの設定
const VOICEVOX_HOST = "http://localhost:50021";
interface VoiceStyle {
speakerId: number;
styleId: number;
}
// 仮の声設定(例: サイドM = 3
const defaultVoiceStyle: VoiceStyle = {
speakerId: 3,
styleId: 2,
};
export async function generateTTS(
itemId: string,
scriptText: string,
): Promise<string> {
const params = {
OutputFormat: "mp3",
Text: scriptText,
VoiceId: "Mizuki",
LanguageCode: "ja-JP",
};
const command = new SynthesizeSpeechCommand(params);
const response = await polly.send(command);
// 音声合成クエリの生成
const queryResponse = await fetch(`${VOICEVOX_HOST}/audio_query`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
text: scriptText,
speaker: defaultVoiceStyle.speakerId,
}),
});
if (!response.AudioStream) {
throw new Error("TTSのAudioStreamが空です");
if (!queryResponse.ok) {
throw new Error("VOICEVOX 音声合成クエリ生成に失敗しました");
}
const audioQuery = await queryResponse.json();
// 音声合成
const audioResponse = await fetch(`${VOICEVOX_HOST}/synthesis`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
audio_query: audioQuery,
speaker: defaultVoiceStyle.speakerId,
}),
});
if (!audioResponse.ok) {
throw new Error("VOICEVOX 音声合成に失敗しました");
}
const audioBuffer = await audioResponse.buffer();
// 出力ディレクトリの準備
const outputDir = path.join(__dirname, "../public/podcast_audio");
if (!fs.existsSync(outputDir)) {
fs.mkdirSync(outputDir, { recursive: true });
}
const filePath = path.resolve(outputDir, `${itemId}.mp3`);
const chunks: Uint8Array[] = [];
for await (const chunk of response.AudioStream as any) {
chunks.push(chunk);
}
const buffer = Buffer.concat(chunks);
fs.writeFileSync(filePath, buffer);
const filePath = path.resolve(outputDir, `${itemId}.mp3`);
fs.writeFileSync(filePath, audioBuffer);
return filePath;
}