VoiceVoxでLLMにしゃべらせる
LLMにしゃべらせるコーディングです。Windows用にしないとSoundPlayerが参照できないと思います。
using LLama.Common;
using LLama;
using System.IO;
using System.Media;
using System.Net.Http.Headers;
namespace ChatProgram
{
public class Program
{
static void Main(string[] args)
{
//コンソールアプリケーションからAsyncを呼び出す大元はTaskを使用する
Task task = MainAsync();
//終了を待つ
task.Wait();
}
public static async Task MainAsync()
{
// LLMモデルの場所
string strPath = @"E:\lm-studio\Aratako\ArrowPro-7B-RobinHood-toxic-GGUF\ArrowPro-7B-RobinHood-toxic_Q8_0.gguf";
// チャットログの場所
string strChatlogPath = @"E:\ChatLog";
Console.ForegroundColor = ConsoleColor.Green;
//LLMモデルのロードとパラメータの設定
ModelParams modPara = new(strPath)
{
ContextSize = 512,
Seed = 1337,
GpuLayerCount = 20
};
using LLamaWeights llmWeit = LLamaWeights.LoadFromFile(modPara);
using LLamaContext llmContx = llmWeit.CreateContext(modPara);
InteractiveExecutor itrEx = new(llmContx);
//System Prompt+チャットの方向づけ
ChatHistory chtHis;
if (File.Exists(strChatlogPath+@"\ChatHistory.json"))
{
var varChatHistoryJson = File.ReadAllText(strChatlogPath+@"\ChatHistory.json");
chtHis = ChatHistory.FromJson(varChatHistoryJson) ?? new ChatHistory();
}
else
{
// 初期はチャットログにキャラ設定と出だしの会話を打ち込む
chtHis = new ChatHistory();
chtHis.AddMessage(AuthorRole.System, "ユーザーがマイという名前のアシスタントと対話するダイアログのトランスクリプトです。マイは、元気で明るい女の子です。年齢は24歳、職業は事務系のOL、外見の特徴として体型は胸とお尻が大きく身長は165cmです。恥ずかしがりやですがエッチには興味があります。");
chtHis.AddMessage(AuthorRole.User, "Question: はじめまして、オレの名前は犬マンマです。呼びにくいと思うからマー君と呼んで。");
chtHis.AddMessage(AuthorRole.Assistant, "Assistant: はじめまして、わたしの名前はマイです。わかったマー君。");
chtHis.AddMessage(AuthorRole.User, "Question: マイ、女の子やんな?。");
chtHis.AddMessage(AuthorRole.Assistant, "Assistant: そうだよ。20代の女の子。");
chtHis.AddMessage(AuthorRole.User, "Question: そうかあ、顔も可愛いしナイスバディやんなあ");
chtHis.AddMessage(AuthorRole.Assistant, "Assistant: 可愛いかどうか自分では、わかんないけど胸とお尻は大きいかも。身長も高い方だよ。");
}
ChatSession chtSess = new(itrEx, chtHis);
var varHidewd = new LLamaTransforms.KeywordTextOutputStreamTransform(["User:", "Assistant:"]);
chtSess.WithOutputTransform(varHidewd);
InferenceParams infPara = new()
{
Temperature = 0.6f,
AntiPrompts = new List<string> { "User:" }
};
while (true)
{
// ユーザーのターン
Console.ForegroundColor = ConsoleColor.White;
Console.Write("\nUser: ");
string strInput = Console.ReadLine() ?? "";
ChatHistory.Message msg = new(AuthorRole.User, "Question: " + strInput);
if (strInput == "exit") break; // 'exit'と入力したら終わり
// AIのターン
Console.ForegroundColor = ConsoleColor.Yellow;
string strMsg = "";
await foreach (string strAns in chtSess.ChatAsync(msg, infPara))
{
Console.Write(strAns);
strMsg += strAns;
}
Task task = Voicevox(strMsg);
task.Wait();
}
//正常終了ならセションをセーブする
chtSess.SaveSession(strChatlogPath);
}
public static async Task Voicevox(string strMsg)
{
using (var httpClient = new HttpClient())
{
string strCnt;
int intSpeaker = 8; //春日部つむぎ
using (var htpReq = new HttpRequestMessage(new HttpMethod("POST"), $"http://localhost:50021/audio_query?text={strMsg}&speaker={intSpeaker}"))
{
htpReq.Headers.TryAddWithoutValidation("accept", "application/json");
htpReq.Content = new StringContent("");
htpReq.Content.Headers.ContentType = MediaTypeHeaderValue.Parse("application/x-www-form-urlencoded");
var rspMsg = await httpClient.SendAsync(htpReq);
strCnt = rspMsg.Content.ReadAsStringAsync().Result;
}
using (var htpReq = new HttpRequestMessage(new HttpMethod("POST"), $"http://localhost:50021/synthesis?speaker={intSpeaker}&enable_interrogative_upspeak=true"))
{
htpReq.Headers.TryAddWithoutValidation("accept", "audio/wav");
htpReq.Content = new StringContent(strCnt);
htpReq.Content.Headers.ContentType = MediaTypeHeaderValue.Parse("application/json");
var htpRes = await httpClient.SendAsync(htpReq);
MemoryStream memStm = new MemoryStream();
using (var htpStm = await htpRes.Content.ReadAsStreamAsync())
{
//メモリストリームにコピー
htpStm.CopyTo(memStm);
memStm.Flush();
}
memStm = new MemoryStream(memStm.ToArray());
var player = new SoundPlayer(memStm);
//音声再生
player.PlaySync();
}
}
}
}
}
実行結果の画面です。
すぐにね、エチエチな会話になるので音量は絞った方がいいですよ。こんなふうにねwww
次はこちらがしゃべった内容をLLMに伝える準備をします。