ChatGPTからの返答をVOICEVOXの合成音声を使ってDiscordに返す
はじめに
今回は以下の記事の続きです
Discord・VOICEVOX・OpenAIのAPIを使います
始め方
Dockerを利用するのであれば、pullしてrunですぐ実施可能!
(すごくありがたい)
docker pull voicevox/voicevox_engine:nvidia-ubuntu20.04-latest
docker run --rm --gpus all -p '127.0.0.1:50021:50021' voicevox/voicevox_engine:nvidia-ubuntu20.04-latest
しかし、上記のコマンドを叩くと以下のエラーが...
docker: Invalid ip address: '127.0.0.1.
See 'docker run --help'.
検索してもあまり良い記事がヒットせず...
公式の「ポートの公開と露出(-p、--expose)」のサンプルを見ると以下のようにIPアドレスとポートを''を囲まず実行しています
docker run -p 127.0.0.1:80:8080 ubuntu bash
同様に以下のように実行すると成功...
docker run --rm -p 127.0.0.1:50021:50021 voicevox/voicevox_engine:cpu-ubuntu20.04-latest
http://localhost:50021/docs にアクセスするとAPI仕様書が確認できました
axiosを使ってVOICEVOXと通信をする
axiosの新しいインスタンスを作成
axios.get("http://localhost:50021")と同じ動作をする
複数のエンドポイントを持つときエンドポイントごとにインスタンスを作成しておくと便利
const instance = axios.create({
baseURL: "http://localhost:50021",
});
その他、リクエストのconfigは以下の公式ページ
application/x-www-form-urlencoded形式でPOSTしたいが、以下のエラーが出てしまいうまくできない...
const instance = axios.create({
baseURL: "http://localhost:50021",
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
});
const params = new URLSearchParams();
params.append("text", getResponse.data.choices[0].message.content);
params.append("speaker", 1);
const audio_query = await instance.post("/audio_query", params);
AxiosError: Request failed with status code 422
at settle (C:\Users\XXXX\MyApps\chatgpt-chatbot\node_modules\axios\dist\node\axios.cjs:1900:12)
at IncomingMessage.handleStreamEnd (C:\Users\XXXX\MyApps\chatgpt-chatbot\node_modules\axios\dist\node\axios.cjs:2952:11)
POSTなのにURIの後にクエリパラメータをつけてますが、ひとまずこれで動いたのでこのまま
いまだにbodyで送る方法がわからないので今後も調べます
postの第二引数のdataはrequest bodyとして扱われるためクエリリクエストがうまくできていない?のかと思いましたがまだよくわかっていません
VOICEVOXの/audio_queryのRequest URLが以下のような形になるので、postのURLを直接作って送ることにしたら成功しました
const audio_query = await instance.post(
"audio_query?text=" +
encodeURI(getResponse.data.choices[0].message.content) +
"&speaker=1"
);
あとは受け取った音声合成用のクエリを音声合成します
const synthesis = await instance.post(
"synthesis?speaker=1",
JSON.stringify(audio_query.data),
{
responseType: "arraybuffer",
headers: {
accept: "audio/wav",
"Content-Type": "application/json",
},
}
);
fs.writeFileSync("demo.wav", new Buffer.from(synthesis.data), "binary");
あとはwavファイルをdiscordに送信する仕組みをいれて完成です
await message.channel.send({
files: ["./demo.wav"],
});
最終的にできたコードがこちら
require("dotenv").config();
const { Client, GatewayIntentBits, Attachment } = require("discord.js");
const { Configuration, OpenAIApi } = require("openai");
const axios = require("axios").default;
const fs = require("fs");
const clientData = {
intents: [
GatewayIntentBits.Guilds,
GatewayIntentBits.GuildMessages,
GatewayIntentBits.MessageContent,
],
};
const configurationData = {
organization: process.env.OPENAI_ORG,
apiKey: process.env.OPENAI_KEY,
};
//prepare to connect
const client = new Client(clientData);
const configuration = new Configuration(configurationData);
const openai = new OpenAIApi(configuration);
const instance = axios.create({
baseURL: "http://localhost:50021",
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
});
//check for when a message on discord
client.on("messageCreate", async function (message) {
try {
//don't response
if (message.author.bot) return;
if (message.channel.name !== "chatgpt") return;
const getResponse = await openai.createChatCompletion({
model: "gpt-3.5-turbo",
messages: [{ role: "user", content: `${message.content}` }],
});
const audio_query = await instance.post(
"audio_query?text=" +
getResponse.data.choices[0].message.content +
"&speaker=1"
);
const synthesis = await instance.post(
"synthesis?speaker=1",
JSON.stringify(audio_query.data),
{
responseType: "arraybuffer",
headers: {
accept: "audio/wav",
"Content-Type": "application/json",
},
}
);
fs.writeFileSync("demo.wav", new Buffer.from(synthesis.data), "binary");
await message.channel.send({
files: ["./demo.wav"],
});
message.reply(`${getResponse.data.choices[0].message.content}`);
return;
} catch (err) {
console.log(err);
}
});
client.login(process.env.DISCORD_TOKEN);
console.log("ChatGPT Bot is Online on Discord");
ChatGPTからの返答をVOICEVOXを使って合成音声化した後、Discordにwavファイルとして送信する仕組みを作りました。
ずんだもんがしゃべってくれるのでかわいいですね。
今後はwavファイルを読み上げてくれる仕組みも作りたいですね。
参考サイト
Discussion