75 lines
		
	
	
		
			1.9 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			75 lines
		
	
	
		
			1.9 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
import fs from "fs";
 | 
						|
import path from "path";
 | 
						|
 | 
						|
// VOICEVOX APIの設定
 | 
						|
const VOICEVOX_HOST =
 | 
						|
  import.meta.env["VOICEVOX_HOST"] ?? "http://localhost:50021";
 | 
						|
const VOICEVOX_SPEAKER_ID = parseInt(
 | 
						|
  import.meta.env["VOICEVOX_SPEAKER_ID"] ?? "3",
 | 
						|
);
 | 
						|
const VOICEVOX_STYLE_ID = parseInt(import.meta.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;
 | 
						|
}
 |