Files
VoiceRSSSummary/services/tts.ts

72 lines
1.9 KiB
TypeScript

import fs from "fs";
import path from "path";
// VOICEVOX APIの設定
const VOICEVOX_HOST = process.env.VOICEVOX_HOST ?? "http://localhost:50021";
const VOICEVOX_SPEAKER_ID = parseInt(process.env.VOICEVOX_SPEAKER_ID ?? "3");
const VOICEVOX_STYLE_ID = parseInt(process.env.VOICEVOX_STYLE_ID ?? "2");
interface VoiceStyle {
speakerId: number;
styleId: number;
}
// 環境変数からデフォルトの声設定を取得
const defaultVoiceStyle: VoiceStyle = {
speakerId: VOICEVOX_SPEAKER_ID,
styleId: VOICEVOX_STYLE_ID,
};
export async function generateTTS(
itemId: string,
scriptText: string,
): Promise<string> {
// 音声合成クエリの生成
const queryResponse = await fetch(`${VOICEVOX_HOST}/audio_query`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
text: scriptText,
speaker: defaultVoiceStyle.speakerId,
}),
});
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 audioArrayBuffer = await audioResponse.arrayBuffer();
const audioBuffer = Buffer.from(audioArrayBuffer);
// 出力ディレクトリの準備
const outputDir = path.join(__dirname, "../public/podcast_audio");
if (!fs.existsSync(outputDir)) {
fs.mkdirSync(outputDir, { recursive: true });
}
const filePath = path.resolve(outputDir, `${itemId}.mp3`);
fs.writeFileSync(filePath, audioBuffer);
return filePath;
}