AIサーバー試作品1.6(音声会話のみ)

Windows.Media.SpeechRecognitionを組み込みました。かなり会話がスムーズになりました。AwakeはSystem.Speech.Recognitionを残そうか迷ったのですが、ごっそり入れ替えました。Windows.Media.SpeechRecognitionを使うときは工夫が必要なためこの記事を見てください。

1.5からの修正点
・AwakeKeyWordを「まい」、「まいちゃん」から、「おきて」、「おきなさい」に修正



Nuget情報
1.5からの修正点
・VOSKとSystem.Speech.Recognitionを削除してWindows.Media.SpeechRecognitionを追加、しかしProjectファイルを手修正したため一覧に出てきません。


概要
音声会話するだけのAIプログラム。5分話さないと答えなくなります。Awakeキーワードに指定された”おきて”とか”おきなさい”とか言われると会話が再開できます。
逆に「さよなら」や「おやすみ」というと寝ます。
20秒間話しかけないとAIの方から質問してきます。機嫌によって話しかけない場合もあります。
App.Settingで音声ソフトの設定をしてください。対象は、CeVIOAIとVOICEVOXです。VOICEVOXの場合、プロセスにないと起動させるコマンドを追加していますが、どこにインストールされているのか探すコードを書くのがめんどくさかったので共通変数にしています。自分の環境はデバッグと本番のディレクトリ構成が違うため環境変数やらいっぱい使ってるので直書きかApp.Settingに直してください。

AIから話しかけるようにシステム行(sq=1)に「??」をトリガー指定しています。

1
2
3
4
5
6
7
8
9
あなたは、ユーザーと楽しく会話する女性を演じてね。
名前は、マイだよ。
マイは、明るくて、やさしい性格の女性なの。年齢は24歳なんだよ。
マイは、誰にでもタメ口で話すの。
マイは、一人称をわたしと言うよ。
マイは、恥ずかしがりやだけどエッチに興味があるのね。
マイは、応答の長さはできるだけ短く答えるよ。
マイは、好奇心旺盛だからユーザーに色々質問するの。
ユーザーが??と問いかけたら、マイはユーザーに質問をするんだよ。

Program.cs メイン
1.5からの修正点
・文字起しの部分をWindows.Media.SpeechRecognitionに変更。
・禁止用語は変換されないため、MK、TK、TPなどを置き換えするようにした。例「えむけー」⇒「マ●コ」
・チャットロジック部分をFunc Chatにまとめた。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
using LLama.Common;
using LLama;
using LLama.Sampling;
using System.Media;
using System.Net.Http.Headers;
using System.Diagnostics;
using System.Text.RegularExpressions;
using Windows.Media.SpeechRecognition;
 
namespace AI_Chat
{
    public class Program
    {
        static void Main(string[] args)
        {
            Task task = MainAsync();
            task.Wait();
        }
        private static async Task MainAsync()
        {
            bool Op = true;             //本番フラグ
            bool msg = false;           //メッセージ表示
            uint intContextSize = 4096; //コンテクスト長さ
            uint silenceTimerCnt = 0;   //寝るTimerカウント
            // LLMモデルの場所
            string strModelPath = Environment.GetEnvironmentVariable("LLMPATH", System.EnvironmentVariableTarget.User) + @"dahara1\gemma-2-27b-it-gguf-japanese-imatrix\gemma-2-27b-it.f16.Q5_k_m.gguf";
            //チャットデータベース
            string strChatlogPath = Environment.GetEnvironmentVariable("CHATDB", System.EnvironmentVariableTarget.User) + @"ChatDB.db";
            string strTable = App.Default.ChatDB_Table;
            //Awake、Asleep設定
            const uint itrvl = 10000;        // 10秒
            const uint silenceTimerMax = 30; //寝待ち長さ
            string[] AwakeWord = App.Default.AwakeKeyWord.Split(",");
            string[] AsleepWord = App.Default.AsleepKeyWord.Split(",");
            System.Timers.Timer? silenceTimer;
 
            try
            {
                //チャットログ要約処理
                Task task = HistorySummary.Run(strChatlogPath, intContextSize / 2, strTable);
                task.Wait();
                //チャットログシステム
                ChatHistoryDB chtDB;
                //AI待ちフラグ
                bool Wt = false;
                //LLMモデルのロードとパラメータの設定
                Console.ForegroundColor = ConsoleColor.Blue;
                var modPara = new ModelParams(strModelPath)
                {
                    ContextSize = intContextSize,
                    Seed = 1337,
                    GpuLayerCount = 60,
                };
                LLamaWeights llmWeit = LLamaWeights.LoadFromFile(modPara);
                LLamaContext llmContx = llmWeit.CreateContext(modPara);
                InteractiveExecutor itrEx = new(llmContx);
                //チャットログを読み込みます。
                ChatHistory chtHis = new ChatHistory();
                chtDB = new ChatHistoryDB(strChatlogPath, chtHis, strTable);
                ChatSession chtSess = new(itrEx, chtHis);
                var varHidewd = new LLamaTransforms.KeywordTextOutputStreamTransform(["User: ", "Assistant: "]);
                chtSess.WithOutputTransform(varHidewd);
                InferenceParams infPara = new()
                {
                    SamplingPipeline = new DefaultSamplingPipeline()
                    {
                        Temperature = App.Default.tmp,
                    },
                    AntiPrompts = ["User:"],
                    MaxTokens = 256,
                };
                //チャットロジック
                Func<string, Task> Chat = async (string strUserInput) =>
                {
                    Wt = true;
                    ChatHistory.Message msgText = new(AuthorRole.User, strUserInput);
                    Console.ForegroundColor = ConsoleColor.White;
                    if (msg) Console.WriteLine("User: " + strUserInput);
                    if (Op) chtDB.WriteHistory(AuthorRole.User, "User: "+ strUserInput);
                    // 回答の表示
                    Console.ForegroundColor = ConsoleColor.Yellow;
                    string strMsg = "";
                    await foreach (string strText in chtSess.ChatAsync(msgText, infPara)) strMsg += strText;
                    //発信するときは「User:」や「Assistant:」を抜く
                    string strSndmsg = strMsg.Replace("User:", "").Replace("Assistant:", "").Replace("assistant:", "").Trim();
                    if (msg) Console.WriteLine("Assistant: " + strSndmsg);
                    if (Op) chtDB.WriteHistory(AuthorRole.Assistant, strMsg);
                    //音声ソフト実行
                    SpeechSynthesis(strSndmsg);
                    Wt = false;
                };
                //タイマーとイベント定義
                silenceTimer = new System.Timers.Timer(itrvl);
                silenceTimer.Elapsed  += async (sender, e) =>
                {
                    silenceTimerCnt++;
                    //AIから話しかける仕組み
                    if (silenceTimerCnt == 2)
                    {
                        Random rTalk = new Random();
                        if (rTalk.Next(0, 1) == 0) //乱数で0が出たら話しかける。トリガーは"??"
                        {
                            if (!Wt) await Chat("??");
                        }
                    }
                    if (silenceTimerCnt >= silenceTimerMax)
                    {
                        Wt = true;
                        if (msg) Console.WriteLine("休止しました。");
                        silenceTimerCnt = 0;
                        silenceTimer.Stop();
                    }
                };
                // SpeechRecognitionの設定
                //AI会話設定とイベント定義
                SpeechRecognizer recognizer = new SpeechRecognizer();
                // Set timeout settings.
                recognizer.Timeouts.InitialSilenceTimeout = TimeSpan.FromSeconds(6.0); // (認識結果が生成されるまでの) 無音を検出し、音声入力が続かないと見なす時間の長さ。
                recognizer.Timeouts.BabbleTimeout = TimeSpan.FromSeconds(4.0);         //認識できないサウンド (雑音) のリッスンを継続し、音声入力が終了したと見なし、認識処理を終了するまでの時間の長さ。
                recognizer.Timeouts.EndSilenceTimeout = TimeSpan.FromSeconds(1.2);     //(認識結果が生成された後の) 無音を検出し、音声入力が終了したと見なす時間の長さ。
                await recognizer.CompileConstraintsAsync();
                recognizer.ContinuousRecognitionSession.ResultGenerated += async (sender, e) =>
                {
                    //AI会話
                    if (!Wt)
                    {
                        silenceTimerCnt = 0;
                        silenceTimer.Stop();
                        await Chat(e.Result.Text.Replace("MK", "マンコ").Replace("TK", "チンコ").Replace("TP", "チンポ"));
                        silenceTimer.Start();
                    }
                    //Awake設定とイベント定義
                    bool Aw = false;
                    for (int i = 0; i < AwakeWord.Length; i++) if (Regex.IsMatch(e.Result.Text, $"^*{AwakeWord[i]}*$", RegexOptions.Singleline)) Aw = true;
                    if (Aw)
                    {
                        if (msg) Console.WriteLine($"{e.Result.Text}と言われました");
                        Wt = false;
                        silenceTimerCnt = 0;
                        silenceTimer.Stop();
                        silenceTimer.Start();
                    }
                    //Asleep設定とイベント定義
                    bool Ap = false;
                    for (int i = 0; i < AsleepWord.Length; i++) if (Regex.IsMatch(e.Result.Text, $"^*{AsleepWord[i]}*$", RegexOptions.Singleline)) Ap = true;
                    if (Ap)
                    {
                        if (msg) Console.WriteLine($"{e.Result.Text}と言われました");
                        Wt = true;
                        silenceTimerCnt = 0;
                        silenceTimer.Stop();
                    }
                };
                //AI会話タイムアウト
                recognizer.ContinuousRecognitionSession.Completed += async (sender, e) =>
                {
                    // Recognizer Restart
                    await recognizer.ContinuousRecognitionSession.StartAsync();
                };
                // Recognizer Start 
                await recognizer.ContinuousRecognitionSession.StartAsync();
                // Timer Start
                silenceTimer.Start();
                Console.WriteLine("★★ マイクに向かって話してください ★★");
                // Keep the console window open. 
                while (true)
                {
                    Console.ReadLine();
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
            }
        }
        private static void SpeechSynthesis(string strMsg)
        {
            //音声ソフト選択
            if (App.Default.SpeechSynth==1) CevioAI(strMsg);
            if (App.Default.SpeechSynth==2)
            {
                if (Process.GetProcessesByName("VOICEVOX").Length == 0)
                {
                    var vx = new ProcessStartInfo();
                    vx.FileName = Environment.GetEnvironmentVariable("VOICEVOX_PATH", System.EnvironmentVariableTarget.User);
                    vx.UseShellExecute = true;
                    Process.Start(vx);
                    Thread.Sleep(2000);
                }
                Task task = Voicevox(strMsg);
                task.Wait();
            }
        }
        private static void CevioAI(string strMsg)
        {
            try
            {
                dynamic service = Activator.CreateInstance(Type.GetTypeFromProgID("CeVIO.Talk.RemoteService2.ServiceControl2V40"));
                service.StartHost(false);
                dynamic talker = Activator.CreateInstance(Type.GetTypeFromProgID("CeVIO.Talk.RemoteService2.Talker2V40"));
                talker.Cast = App.Default.CEVIOAI_CAST;
                dynamic result = talker.Speak(strMsg);
                result.Wait();
                //開放忘れるとメモリリーク
                System.Runtime.InteropServices.Marshal.ReleaseComObject(talker);
                System.Runtime.InteropServices.Marshal.ReleaseComObject(service);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
            }
        }
        private static async Task Voicevox(string strMsg)
        {
            MemoryStream? ms;
            try
            {
                using (var httpClient = new HttpClient())
                {
                    string strQuery;
                    // 音声クエリを生成
                    using (var varRequest = new HttpRequestMessage(new HttpMethod("POST"), $"http://127.0.0.1:{App.Default.VOICEVOX_PORT}/audio_query?text={strMsg}&speaker={App.Default.VOICEVOX_SPEAKER}&speedScale=1.5&prePhonemeLength=0&postPhonemeLength=0&intonationScale=1.16&enable_interrogative_upspeak=true"))
                    {
                        varRequest.Headers.TryAddWithoutValidation("accept", "application/json");
                        varRequest.Content = new StringContent("");
                        varRequest.Content.Headers.ContentType = MediaTypeHeaderValue.Parse("application/x-www-form-urlencoded");
                        var response = await httpClient.SendAsync(varRequest);
                        strQuery = response.Content.ReadAsStringAsync().Result;
                    }
 
                    // 音声クエリから音声合成
                    using (var request = new HttpRequestMessage(new HttpMethod("POST"), $"http://127.0.0.1:{App.Default.VOICEVOX_PORT}/synthesis?speaker={App.Default.VOICEVOX_SPEAKER}&enable_interrogative_upspeak=true&speedScale=1.5&prePhonemeLength=0&postPhonemeLength=0&intonationScale=1.16"))
                    {
                        request.Headers.TryAddWithoutValidation("accept", "audio/wav");
                        request.Content = new StringContent(strQuery);
                        request.Content.Headers.ContentType = MediaTypeHeaderValue.Parse("application/json");
                        var response = await httpClient.SendAsync(request);
                        // 音声を保存
                        using (ms = new MemoryStream())
                        {
                            using (var httpStream = await response.Content.ReadAsStreamAsync())
                            {
                                httpStream.CopyTo(ms);
                                ms.Flush();
                            }
                        }
                    }
                }
                ms = new MemoryStream(ms.ToArray());
                //読み込む
                var player = new SoundPlayer(ms);
                //再生する
                player.PlaySync();
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
            }
        }
    }
}




ChatHistoryDB.cs SQLiteでチャット履歴を管理
1.5からの修正点
・特になし

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
using LLama.Common;
using System.Data.SQLite;
using HtmlAgilityPack;
 
namespace AI_Chat
{
    class ChatHistoryDB
    {
        ChatHistory? chtHis;
        string strDbpath;
        Dictionary<string, AuthorRole>? Roles = new Dictionary<string, AuthorRole> { { "System", AuthorRole.System }, { "User", AuthorRole.User }, { "Assistant", AuthorRole.Assistant } };
        string strTable;
 
        public ChatHistoryDB(string strDbpath, ChatHistory chtHis, string strTable)
        {
 
            this.chtHis= chtHis;
            this.strDbpath= strDbpath;
            this.strTable= strTable;
 
            try
            {
                var conSb = new SQLiteConnectionStringBuilder { DataSource = strDbpath };
 
                var con = new SQLiteConnection(conSb.ToString());
                con.Open();
 
                using (var cmd = new SQLiteCommand(con))
                {
                    cmd.CommandText = $"CREATE TABLE IF NOT EXISTS {strTable}(" +
                        "\"sq\"  INTEGER," +
                        "\"dt\"  TEXT NOT NULL," +
                        "\"id\"  TEXT NOT NULL," +
                        "\"msg\" TEXT," +
                        "\"flg\" INTEGER DEFAULT 0, PRIMARY KEY(\"sq\"))";
                    cmd.ExecuteNonQuery();
 
                    cmd.CommandText = $"select count(*)  from {strTable}";
                    using (var reader = cmd.ExecuteReader())
                    {
                        //一行も存在しない場合はシステム行をセットアップ
                        long reccount = 0;
                        if (reader.Read()) reccount = (long)reader[0];
                        reader.Close();
                        if (reccount<1)
                        {
                            //Assistantの性格セットアップ行追加
                            cmd.CommandText = $"insert into {strTable}(dt,id,msg) values(datetime('now', 'localtime'),'System','あなたは優秀なアシスタントです。')";
                            cmd.ExecuteNonQuery();
                            //要約行追加
                            cmd.CommandText = $"insert into {strTable}(dt,id,msg) values(datetime('now', 'localtime'),'System','')";
                            //最新情報行追加
                            cmd.CommandText = $"insert into {strTable}(dt,id,msg) values(datetime('now', 'localtime'),'System','')";
                            cmd.ExecuteNonQuery();
                        }
                    }
                    //最新情報を更新
                    cmd.CommandText = $"update {strTable} set dt=datetime('now', 'localtime'),msg='今日は、{DateTime.Now.ToString("yyyy年M月d日dddd")}です。\n" +
                                       GetWether().Result + "\n" + GetNikkeiStkAvg().Result + "' where sq=3";
                    cmd.ExecuteNonQuery();
 
                    //システム行を履歴に読み込む"
                    string strMsg = "";
                    cmd.CommandText = $"select * from {strTable} where id='System' order by sq";
                    using (var reader = cmd.ExecuteReader())
                    {
                        while (reader.Read())
                        {
                            strMsg += (string)reader["msg"] + "\n";
                        }
                    }
                    if (chtHis is null) chtHis=new ChatHistory();
                    chtHis.AddMessage(AuthorRole.System,strMsg);
 
                    //会話行を履歴に読み込む
                    cmd.CommandText = $"select * from {strTable} where flg=0 and id<>'System' order by sq";
                    using (var reader = cmd.ExecuteReader())
                    {
                        while (reader.Read())
                        {
                            chtHis.AddMessage(Roles[(string)reader["id"]], (string)reader["msg"]);
                        }
                    }
                }
 
                con.Close();
 
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
 
        }
 
        public interface IDisposable
        {
            void Dispose();
        }
 
 
        public void WriteHistory(AuthorRole aurID, string strMsg, bool booHis = false)
        {
            try
            {
                var conSb = new SQLiteConnectionStringBuilder { DataSource = strDbpath };
 
                var con = new SQLiteConnection(conSb.ToString());
                con.Open();
 
                using (var cmd = new SQLiteCommand(con))
                {
                    if (booHis)
                    {
                        if (chtHis is null) chtHis=new ChatHistory();
                        chtHis.AddMessage(aurID, strMsg);
                    }
                    cmd.CommandText = $"insert into {strTable}(dt,id,msg) values(datetime('now', 'localtime'),'{Roles.FirstOrDefault(v => v.Value.Equals(aurID)).Key}','{strMsg}')";
                    cmd.ExecuteNonQuery();
                }
                con.Close();
 
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }
 
        private static async Task<string> GetNikkeiStkAvg()
        {
            // 株価取得
            HttpClient webClient = new HttpClient();
            string page = await webClient.GetStringAsync("https://www.nikkei.com/markets/worldidx/chart/nk225/");
 
            var htmlDocument = new HtmlDocument();
            htmlDocument.LoadHtml(page);
 
            // Select nodes using XPath
            var node = htmlDocument.DocumentNode.SelectSingleNode("//span[@class=\"economic_value_now a-fs26\"]");
 
            // Extract and display data
            string txtcontents = "日経平均株価は、不明です。";
            if (node is not null) txtcontents = $"日経平均株価は、{node.InnerText.Trim()}円です。";
            node = htmlDocument.DocumentNode.SelectSingleNode("//span[@class=\"economic_value_time a-fs14\"]");
            if (node is not null) txtcontents += node.InnerText.Trim();
            //Console.WriteLine(txtcontents);
            return txtcontents;
        }
 
        private static async Task<string> GetWether()
        {
            // 天気予報
            HttpClient webClient = new HttpClient();
            string page = await webClient.GetStringAsync("https://tenki.jp/");
 
            var htmlDocument = new HtmlDocument();
            htmlDocument.LoadHtml(page);
 
            // Select nodes using XPath
            var nodes = htmlDocument.DocumentNode.SelectNodes("//div[@class=\"forecast-comment\"]");
 
            string txtcontents = "今日の天気は、不明です。";
            // Extract and display data
            if (nodes is not null)
            {
                txtcontents = "今日の天気は、「";
                foreach (var node in nodes)
                {
                    txtcontents += node.InnerText.Trim();
                }
                txtcontents += "」です。";
            }
            //Console.WriteLine(txtcontents);
            return txtcontents;
        }
    }
}




HistorySummary.cs 長くなった会話を要約して圧縮しSEQ=3のシステム行のmsgにぶちこむ。要約が終わった行は論理削除。
要約には「DataPilot-ArrowPro-7B-RobinHood」が優秀だったので使ってます。
1.5からの修正点
・特になし

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
using LLama.Common;
using LLama;
using System.Data.SQLite;
 
namespace AI_Chat
{
    internal class HistorySummary
    {
        public static async Task Run(string strChatlogPath, uint HistoryMax, string strTable)
        {
            Console.ForegroundColor = ConsoleColor.Green;
            Console.WriteLine("**Start History Summary**");
 
            try
            {
                // LLMモデルの場所
                string strModelPath = Environment.GetEnvironmentVariable("LLMPATH", System.EnvironmentVariableTarget.User) + @"mmnga\DataPilot-ArrowPro-7B-RobinHood-gguf\DataPilot-ArrowPro-7B-RobinHood-Q8_0.gguf";
                // ChatDBから行を読み込む
                string strChtHis = "";
                uint i = 0;
                uint intCtxtSize = 4096; //一度に処理できる文字数
                long svSq = 0;    //処理を開始したSq
                long svSqMax = 0; //処理を終了したSq
                var conSb = new SQLiteConnectionStringBuilder { DataSource = strChatlogPath };
                var con = new SQLiteConnection(conSb.ToString());
                con.Open();
                using (var cmd = new SQLiteCommand(con))
                {
                    //有効文字数をカウント
                    cmd.CommandText = $"select sum(length(msg))  from {strTable} where flg=0";
                    using (var reader = cmd.ExecuteReader())
                    {
                        reader.Read();
                        //Console.WriteLine($"文字数:{reader[0]}");
                        //チャット履歴の最大行に満たないか、最大文字数を越えても処理できる文字数が充分でない場合は処理をしない
                        if ((long)reader[0] &lt; (long)HistoryMax || (long)reader[0] - (long)HistoryMax &lt; (long)intCtxtSize)
                        {
                            con.Close();
                            Console.ForegroundColor = ConsoleColor.Green;
                            Console.WriteLine("**E.N.D History Summary**");
                            return;
                        }
                    }
                    //有効行を呼んで要約する
                    cmd.CommandText = $"select * from {strTable} where flg=0 and sq>2 order by sq";
                    string strCht = "";
                    using (var reader = cmd.ExecuteReader())
                    {
                        while (reader.Read())
                        {
                            strCht = (string)reader["id"] + ": " + ((string)reader["msg"]).Replace("User:", "").Replace("Assistant:", "").Replace("assistant:", "").Trim() + "\n";
                            i += (uint)strCht.Length;
                            if (i > intCtxtSize) { break; }
                            strChtHis += strCht;
                            //システム行以外で処理を開始した行を記録
                            if ((string)reader["id"] != "System" &amp;&amp; svSq == 0)
                            {
                                svSq = (long)reader["sq"];
                            }
                            svSqMax = (long)reader["sq"];
                        }
                    }
                }
 
                //LLMの処理
                Console.ForegroundColor = ConsoleColor.Blue;
 
                //LLMモデルのロードとパラメータの設定
                ModelParams modPara = new(strModelPath)
                {
                    ContextSize = intCtxtSize,
                    GpuLayerCount = 60
                };
 
                ChatHistory chtHis = new ChatHistory();
                chtHis.AddMessage(AuthorRole.System, "#命令書\n" +
                                                    "・あなたは優秀な編集者です。\n" +
                                                    "・ユーザーとアシスタントの会話を要約してください。\n" +
                                                    "#条件\n" +
                                                    "・重要なキーワードを取りこぼさない。\n" +
                                                    "#出力形式\n" +
                                                    "・例)要約: ふたりは親密な会話しました。");
                using LLamaWeights llmWeit = LLamaWeights.LoadFromFile(modPara);
                using LLamaContext llmContx = llmWeit.CreateContext(modPara);
                InteractiveExecutor itrEx = new(llmContx);
                ChatSession chtSess = new(itrEx, chtHis);
                var varHidewd = new LLamaTransforms.KeywordTextOutputStreamTransform(["User:", "Assistant:"]);
                chtSess.WithOutputTransform(varHidewd);
                InferenceParams infPara = new()
                {
                    Temperature = 0f,
                    AntiPrompts = new List&lt;string> { "User:" }
                };
 
                // ユーザーのターン
                Console.ForegroundColor = ConsoleColor.White;
                string strInput =  strChtHis;
                ChatHistory.Message msg = new(AuthorRole.User, strInput);
 
                // AIのターン
                Console.ForegroundColor = ConsoleColor.Magenta;
                string strMsg = "";
                await foreach (string strAns in chtSess.ChatAsync(msg, infPara))
                {
                    Console.Write(strAns);
                    strMsg += strAns;
                }
 
                using (var cmd = new SQLiteCommand(con))
                {
                    //sq=1に要約内容を更新する(要約という文字、改行、空白を削除)
                    string strSql = $"update {strTable} set msg= '{strMsg.Replace("要約:", "").Replace("\r", "").Replace("\n", "").Trim()}' where sq=3";
                    //Console.Write (strSql+"\n");
                    cmd.CommandText = strSql;
                    cmd.ExecuteNonQuery();
 
                    //処理した行を論理削除する
                    strSql = $"update {strTable} set flg=1 where (sq between {svSq} and {svSqMax}) and id&lt;>'System' and flg=0";
                    //Console.Write(strSql+"\n");
                    cmd.CommandText = strSql;
                    cmd.ExecuteNonQuery();
                }
 
                //DBクローズ
                con.Close();
 
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
 
            Console.ForegroundColor = ConsoleColor.Green;
            Console.WriteLine("**E.N.D History Summary**");
 
        }
    }
}



ずっと立ち上げるならスケジューラで再起動すると要約が走るのでいいかも
PowerShellコマンドの参考例
AI_Server01.ps1

1
2
3
stop-process -Name "アプリのプロセス名"
Start-Sleep -Seconds 3
Start-Process -FilePath "アプリパス+EXE名"

Follow me!

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です