├── README.md
├── image
├── server目录.png
├── 历史记录.gif
├── 新聊天.gif
└── 设置.gif
└── src
└── AIChatBox
├── AIChatBox.sln
└── AIChatBox
├── AIChatBox.aps
├── AIChatBox.cpp
├── AIChatBox.h
├── AIChatBox.rc
├── AIChatBox.vcxproj
├── AIChatBox.vcxproj.filters
├── AIChatBox.vcxproj.user
├── AIChatBoxDlg.cpp
├── AIChatBoxDlg.h
├── NewChatDlg.cpp
├── NewChatDlg.h
├── PromptDlg.cpp
├── PromptDlg.h
├── RenameDlg.cpp
├── RenameDlg.h
├── SettingDlg.cpp
├── SettingDlg.h
├── chat.cpp
├── chat.h
├── completion.cpp
├── completion.h
├── config
├── params.json
├── prompts.json
└── templates.json
├── framework.h
├── history
├── 2025-01-31-22-36-46.json
├── AI助手.json
├── 仆人.json
├── 医生.json
└── 程序员.json
├── logging.cpp
├── logging.h
├── minipost.cpp
├── minipost.h
├── models
└── 帮助.txt
├── pch.cpp
├── pch.h
├── res
├── 123.ico
├── AIChatBox.ico
├── AIChatBox.rc2
└── robot.ico
├── resource.h
├── server
├── ggml-base.dll
├── ggml-cpu.dll
├── ggml-rpc.dll
├── ggml.dll
├── llama-server.exe
├── llama.dll
├── llava_shared.dll
├── start_server_qwen_3b.bat
└── 测试.bat
├── sjson.cpp
├── sjson.h
├── targetver.h
├── utils.cpp
├── utils.h
├── yyjson.cpp
└── yyjson.h
/README.md:
--------------------------------------------------------------------------------
1 | # AI ChatBox - MFC桌面聊天助手
2 |
3 | []()
4 | []()
5 |
6 | ## 📝 项目简介
7 |
8 | AI ChatBox是一个基于MFC框架开发的本地AI聊天程序,集成了大型语言模型,支持多轮对话,对话记录保存,主题定制等功能。用户可以选择不同的本地模型,例如qwen、llama、deepseek等,进行对话。AI ChatBox完全离线运行,保护用户隐私。
9 |
10 |
11 | ## ▶ 项目讲解
12 |
13 | https://www.bilibili.com/video/BV1HbPkeZEQD
14 |
15 | ## ✨ 功能特性
16 |
17 | - 💬 **多轮对话** - 支持上下文感知的连续对话
18 | - 🧠 **本地推理** - 使用本地模型cpu推理
19 | - 📚 **历史管理** - 对话记录保存与快速回溯
20 | - 🎨 **主题定制** - 可调整字体/颜色/样式
21 | - ⚡ **流式响应** - 实时生成Token显示
22 | - 🛡️ **隐私保护** - 完全离线的本地化运行
23 |
24 | ## 🌟 效果展示
25 |
26 | - **可以选择不同的本地模型,例如qwen、llama、deepseek等**
27 | 
28 | - **可以查看本地保存的历史记录**
29 | 
30 | - **开启新聊天后,可以实时查看AI的回复**
31 | 
32 |
33 | ## 🚀 快速使用
34 |
35 | 1. 下载Release并解压缩到本地目录
36 | 2. 下载[llama.cpp](https://github.com/ggerganov/llama.cpp)项目中的[release版本](https://github.com/ggerganov/llama.cpp/releases/tag/b4604),找到llama-b4604-bin-win-avx-x64.zip并解压,将以下文件复制到项目的server文件夹下
37 |
38 | 
39 |
40 | 3. 到[魔搭社区](https://modelscope.cn/models)下载模型,将模型文件放到项目的models文件夹下,注意模型必须为gguf格式,这样才能被llama.cpp识别
41 | 4. 运行AIChatBox.exe
42 |
43 |
44 | ## 📦 环境要求
45 |
46 | - Windows 10/11 64位
47 | - Visual Studio 2022 (需安装MFC组件)
48 | - [llama.cpp](https://github.com/ggerganov/llama.cpp) 服务端
49 | - 至少8GB可用内存
50 |
51 | ## 🛠 编译运行
52 |
53 | 1. 安装Visual Studio 2022,确保安装了MFC组件
54 | 2. 下载[llama.cpp](https://github.com/ggerganov/llama.cpp)项目中的[release版本](https://github.com/ggerganov/llama.cpp/releases/tag/b4604),找到llama-b4604-bin-win-avx-x64.zip并解压,将以下文件复制到项目的server文件夹下
55 |
56 | 
57 |
58 | 3. 到[魔搭社区](https://modelscope.cn/models)下载模型,将模型文件放到项目的models文件夹下,注意模型必须为gguf格式,这样才能被llama.cpp识别
59 | 4. 使用Visual Studio 2022打开项目,配置项目属性,将项目的平台工具集改为Visual Studio 2022 (v143)
60 | 5. 编译项目,运行
61 |
62 | ## 🔗 参考项目
63 |
64 | - [llama.cpp](https://github.com/ggerganov/llama.cpp) - 用于本地推理的高效C++库
65 | - [llamacpp-terminal-chat](https://github.com/hwpoison/llamacpp-terminal-chat) - 基于llama.cpp的终端聊天客户端
66 |
--------------------------------------------------------------------------------
/image/server目录.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mouseminar/MFC-AIChatBox/f0a73c2b07f5a4cb6b499b851d02d3f175890f40/image/server目录.png
--------------------------------------------------------------------------------
/image/历史记录.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mouseminar/MFC-AIChatBox/f0a73c2b07f5a4cb6b499b851d02d3f175890f40/image/历史记录.gif
--------------------------------------------------------------------------------
/image/新聊天.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mouseminar/MFC-AIChatBox/f0a73c2b07f5a4cb6b499b851d02d3f175890f40/image/新聊天.gif
--------------------------------------------------------------------------------
/image/设置.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mouseminar/MFC-AIChatBox/f0a73c2b07f5a4cb6b499b851d02d3f175890f40/image/设置.gif
--------------------------------------------------------------------------------
/src/AIChatBox/AIChatBox.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 17
4 | VisualStudioVersion = 17.12.35707.178 d17.12
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "AIChatBox", "AIChatBox\AIChatBox.vcxproj", "{4C36F5E6-C7D9-43DF-90D3-737496A1FFE9}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|x64 = Debug|x64
11 | Debug|x86 = Debug|x86
12 | Release|x64 = Release|x64
13 | Release|x86 = Release|x86
14 | EndGlobalSection
15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
16 | {4C36F5E6-C7D9-43DF-90D3-737496A1FFE9}.Debug|x64.ActiveCfg = Debug|x64
17 | {4C36F5E6-C7D9-43DF-90D3-737496A1FFE9}.Debug|x64.Build.0 = Debug|x64
18 | {4C36F5E6-C7D9-43DF-90D3-737496A1FFE9}.Debug|x86.ActiveCfg = Debug|Win32
19 | {4C36F5E6-C7D9-43DF-90D3-737496A1FFE9}.Debug|x86.Build.0 = Debug|Win32
20 | {4C36F5E6-C7D9-43DF-90D3-737496A1FFE9}.Release|x64.ActiveCfg = Release|x64
21 | {4C36F5E6-C7D9-43DF-90D3-737496A1FFE9}.Release|x64.Build.0 = Release|x64
22 | {4C36F5E6-C7D9-43DF-90D3-737496A1FFE9}.Release|x86.ActiveCfg = Release|Win32
23 | {4C36F5E6-C7D9-43DF-90D3-737496A1FFE9}.Release|x86.Build.0 = Release|Win32
24 | EndGlobalSection
25 | GlobalSection(SolutionProperties) = preSolution
26 | HideSolutionNode = FALSE
27 | EndGlobalSection
28 | EndGlobal
29 |
--------------------------------------------------------------------------------
/src/AIChatBox/AIChatBox/AIChatBox.aps:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mouseminar/MFC-AIChatBox/f0a73c2b07f5a4cb6b499b851d02d3f175890f40/src/AIChatBox/AIChatBox/AIChatBox.aps
--------------------------------------------------------------------------------
/src/AIChatBox/AIChatBox/AIChatBox.cpp:
--------------------------------------------------------------------------------
1 |
2 | // AIChatBox.cpp: 定义应用程序的类行为。
3 | //
4 |
5 | #include "pch.h"
6 | #include "framework.h"
7 | #include "AIChatBox.h"
8 | #include "AIChatBoxDlg.h"
9 |
10 | #ifdef _DEBUG
11 | #define new DEBUG_NEW
12 | #endif
13 |
14 |
15 | // CAIChatBoxApp
16 |
17 | BEGIN_MESSAGE_MAP(CAIChatBoxApp, CWinApp)
18 | ON_COMMAND(ID_HELP, &CWinApp::OnHelp)
19 | END_MESSAGE_MAP()
20 |
21 |
22 | // CAIChatBoxApp 构造
23 |
24 | CAIChatBoxApp::CAIChatBoxApp()
25 | {
26 | // 支持重新启动管理器
27 | m_dwRestartManagerSupportFlags = AFX_RESTART_MANAGER_SUPPORT_RESTART;
28 |
29 | // TODO: 在此处添加构造代码,
30 | // 将所有重要的初始化放置在 InitInstance 中
31 | }
32 |
33 |
34 | // 唯一的 CAIChatBoxApp 对象
35 |
36 | CAIChatBoxApp theApp;
37 |
38 |
39 | // CAIChatBoxApp 初始化
40 |
41 | BOOL CAIChatBoxApp::InitInstance()
42 | {
43 | // 如果应用程序存在以下情况,Windows XP 上需要 InitCommonControlsEx()
44 | // 使用 ComCtl32.dll 版本 6 或更高版本来启用可视化方式,
45 | //则需要 InitCommonControlsEx()。 否则,将无法创建窗口。
46 | INITCOMMONCONTROLSEX InitCtrls;
47 | InitCtrls.dwSize = sizeof(InitCtrls);
48 | // 将它设置为包括所有要在应用程序中使用的
49 | // 公共控件类。
50 | InitCtrls.dwICC = ICC_WIN95_CLASSES;
51 | InitCommonControlsEx(&InitCtrls);
52 |
53 | CWinApp::InitInstance();
54 |
55 | AfxInitRichEdit();
56 | AfxInitRichEdit2();
57 |
58 | if (!AfxSocketInit())
59 | {
60 | AfxMessageBox(IDP_SOCKETS_INIT_FAILED);
61 | return FALSE;
62 | }
63 |
64 |
65 | AfxEnableControlContainer();
66 |
67 | // 创建 shell 管理器,以防对话框包含
68 | // 任何 shell 树视图控件或 shell 列表视图控件。
69 | CShellManager *pShellManager = new CShellManager;
70 |
71 | // 激活“Windows Native”视觉管理器,以便在 MFC 控件中启用主题
72 | CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerWindows));
73 |
74 | // 标准初始化
75 | // 如果未使用这些功能并希望减小
76 | // 最终可执行文件的大小,则应移除下列
77 | // 不需要的特定初始化例程
78 | // 更改用于存储设置的注册表项
79 | // TODO: 应适当修改该字符串,
80 | // 例如修改为公司或组织名
81 | SetRegistryKey(_T("应用程序向导生成的本地应用程序"));
82 |
83 | CAIChatBoxDlg dlg;
84 | m_pMainWnd = &dlg;
85 | INT_PTR nResponse = dlg.DoModal();
86 | if (nResponse == IDOK)
87 | {
88 | // TODO: 在此放置处理何时用
89 | // “确定”来关闭对话框的代码
90 | }
91 | else if (nResponse == IDCANCEL)
92 | {
93 | // TODO: 在此放置处理何时用
94 | // “取消”来关闭对话框的代码
95 | }
96 | else if (nResponse == -1)
97 | {
98 | TRACE(traceAppMsg, 0, "警告: 对话框创建失败,应用程序将意外终止。\n");
99 | TRACE(traceAppMsg, 0, "警告: 如果您在对话框上使用 MFC 控件,则无法 #define _AFX_NO_MFC_CONTROLS_IN_DIALOGS。\n");
100 | }
101 |
102 | // 删除上面创建的 shell 管理器。
103 | if (pShellManager != nullptr)
104 | {
105 | delete pShellManager;
106 | }
107 |
108 | #if !defined(_AFXDLL) && !defined(_AFX_NO_MFC_CONTROLS_IN_DIALOGS)
109 | ControlBarCleanUp();
110 | #endif
111 |
112 | // 由于对话框已关闭,所以将返回 FALSE 以便退出应用程序,
113 | // 而不是启动应用程序的消息泵。
114 | return FALSE;
115 | }
116 |
117 |
--------------------------------------------------------------------------------
/src/AIChatBox/AIChatBox/AIChatBox.h:
--------------------------------------------------------------------------------
1 |
2 | // AIChatBox.h: PROJECT_NAME 应用程序的主头文件
3 | //
4 |
5 | #pragma once
6 |
7 | #ifndef __AFXWIN_H__
8 | #error "在包含此文件之前包含 'pch.h' 以生成 PCH"
9 | #endif
10 |
11 | #include "resource.h" // 主符号
12 |
13 |
14 | // CAIChatBoxApp:
15 | // 有关此类的实现,请参阅 AIChatBox.cpp
16 | //
17 |
18 | class CAIChatBoxApp : public CWinApp
19 | {
20 | public:
21 | CAIChatBoxApp();
22 |
23 | // 重写
24 | public:
25 | virtual BOOL InitInstance();
26 |
27 | // 实现
28 |
29 | DECLARE_MESSAGE_MAP()
30 | };
31 |
32 | extern CAIChatBoxApp theApp;
33 |
--------------------------------------------------------------------------------
/src/AIChatBox/AIChatBox/AIChatBox.rc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mouseminar/MFC-AIChatBox/f0a73c2b07f5a4cb6b499b851d02d3f175890f40/src/AIChatBox/AIChatBox/AIChatBox.rc
--------------------------------------------------------------------------------
/src/AIChatBox/AIChatBox/AIChatBox.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | Win32
7 |
8 |
9 | Release
10 | Win32
11 |
12 |
13 | Debug
14 | x64
15 |
16 |
17 | Release
18 | x64
19 |
20 |
21 |
22 | 17.0
23 | {4C36F5E6-C7D9-43DF-90D3-737496A1FFE9}
24 | MFCProj
25 | AIChatBox
26 | 10.0
27 |
28 |
29 |
30 | Application
31 | true
32 | v143
33 | Unicode
34 | Static
35 |
36 |
37 | Application
38 | false
39 | v143
40 | true
41 | Unicode
42 | Static
43 |
44 |
45 | Application
46 | true
47 | v143
48 | Unicode
49 | Static
50 |
51 |
52 | Application
53 | false
54 | v143
55 | true
56 | Unicode
57 | Static
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 | true
79 |
80 |
81 | true
82 |
83 |
84 | false
85 |
86 |
87 | false
88 |
89 |
90 |
91 | Use
92 | Level3
93 | true
94 | _WINDOWS;_DEBUG;_CRT_SECURE_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;%(PreprocessorDefinitions)
95 | pch.h
96 | stdcpp17
97 |
98 |
99 | Windows
100 |
101 |
102 | false
103 | true
104 | _DEBUG;%(PreprocessorDefinitions)
105 |
106 |
107 | 0x0804
108 | _DEBUG;%(PreprocessorDefinitions)
109 | $(IntDir);%(AdditionalIncludeDirectories)
110 |
111 |
112 |
113 |
114 | Use
115 | Level3
116 | true
117 | WIN32;_WINDOWS;_DEBUG;%(PreprocessorDefinitions)
118 | pch.h
119 |
120 |
121 | Windows
122 |
123 |
124 | false
125 | true
126 | _DEBUG;%(PreprocessorDefinitions)
127 |
128 |
129 | 0x0804
130 | _DEBUG;%(PreprocessorDefinitions)
131 | $(IntDir);%(AdditionalIncludeDirectories)
132 |
133 |
134 |
135 |
136 | Use
137 | Level3
138 | true
139 | true
140 | true
141 | WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions)
142 | pch.h
143 |
144 |
145 | Windows
146 | true
147 | true
148 |
149 |
150 | false
151 | true
152 | NDEBUG;%(PreprocessorDefinitions)
153 |
154 |
155 | 0x0804
156 | NDEBUG;%(PreprocessorDefinitions)
157 | $(IntDir);%(AdditionalIncludeDirectories)
158 |
159 |
160 |
161 |
162 | Use
163 | Level3
164 | true
165 | true
166 | true
167 | _WINDOWS;NDEBUG;_CRT_SECURE_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;%(PreprocessorDefinitions)
168 | pch.h
169 | stdcpp17
170 |
171 |
172 | Windows
173 | true
174 | true
175 |
176 |
177 | false
178 | true
179 | NDEBUG;%(PreprocessorDefinitions)
180 |
181 |
182 | 0x0804
183 | NDEBUG;%(PreprocessorDefinitions)
184 | $(IntDir);%(AdditionalIncludeDirectories)
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 | Create
216 | Create
217 | Create
218 | Create
219 |
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 |
239 |
240 |
241 |
242 |
--------------------------------------------------------------------------------
/src/AIChatBox/AIChatBox/AIChatBox.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
6 | cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx
7 |
8 |
9 | {93995380-89BD-4b04-88EB-625FBE52EBFB}
10 | h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd
11 |
12 |
13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
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 |
--------------------------------------------------------------------------------
/src/AIChatBox/AIChatBox/AIChatBox.vcxproj.user:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | AIChatBox.rc
5 |
6 |
--------------------------------------------------------------------------------
/src/AIChatBox/AIChatBox/AIChatBoxDlg.cpp:
--------------------------------------------------------------------------------
1 |
2 | // AIChatBoxDlg.cpp: 实现文件
3 | //
4 |
5 | #include "pch.h"
6 | #include "framework.h"
7 | #include "AIChatBox.h"
8 | #include "AIChatBoxDlg.h"
9 | #include "afxdialogex.h"
10 |
11 | #include "SettingDlg.h"
12 | #include "NewChatDlg.h"
13 | #include "PromptDlg.h"
14 | #include "RenameDlg.h"
15 |
16 | #ifdef _DEBUG
17 | #define new DEBUG_NEW
18 | #endif
19 |
20 |
21 | // 用于应用程序“关于”菜单项的 CAboutDlg 对话框
22 |
23 | class CAboutDlg : public CDialogEx
24 | {
25 | public:
26 | CAboutDlg();
27 |
28 | // 对话框数据
29 | #ifdef AFX_DESIGN_TIME
30 | enum { IDD = IDD_ABOUTBOX };
31 | #endif
32 |
33 | protected:
34 | virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持
35 |
36 | // 实现
37 | protected:
38 | DECLARE_MESSAGE_MAP()
39 | };
40 |
41 | CAboutDlg::CAboutDlg() : CDialogEx(IDD_ABOUTBOX)
42 | {
43 | }
44 |
45 | void CAboutDlg::DoDataExchange(CDataExchange* pDX)
46 | {
47 | CDialogEx::DoDataExchange(pDX);
48 | }
49 |
50 | BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
51 | END_MESSAGE_MAP()
52 |
53 |
54 | // CAIChatBoxDlg 对话框
55 |
56 |
57 |
58 | CAIChatBoxDlg::CAIChatBoxDlg(CWnd* pParent /*=nullptr*/)
59 | : CDialogEx(IDD_AICHATBOX_DIALOG, pParent)
60 | , m_strModelPath(_T(".\\models"))
61 | , m_nPort(8080)
62 | , m_strModel(_T(""))
63 | , m_strFont(_T("Segoe UI Emoji"))
64 | , m_nFontSize(2)
65 | , m_clrBackground(RGB(255, 255, 255))
66 | , m_clrText(RGB(0, 0, 0))
67 | , m_clrUser(RGB(0, 0, 255))
68 | , m_clrAssistant(RGB(255, 0, 0))
69 | , m_isBold(TRUE)
70 | , m_isItalic(FALSE)
71 | , m_hProcess(NULL)
72 | , m_strHistory(_T(".\\history"))
73 | , m_currentHistory(_T(""))
74 | , isNeedSave(FALSE)
75 | , m_nSelectedItem(-1)
76 | , isFirstOpen(TRUE)
77 | {
78 | m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
79 |
80 | user_prompt = u8"AI助手"; // 存储用户输入的提示信息,从 prompts.json 中读取
81 | chat_template = ""; // 存储聊天模板,从 tempaltes.json 中读取
82 | param_profile = "creative_oai"; // 存储参数配置文件,从 params.json 中读取
83 | chat_mode = true; // 是否启用聊天模式
84 | chat_guards = true; // 是否启用聊天保护
85 | debug = true; // 是否开启调试模式
86 | onceAct = false; // 控制角色的对话轮次
87 | }
88 |
89 | CAIChatBoxDlg::~CAIChatBoxDlg()
90 | {
91 | // 关闭服务端进程
92 | if (m_hProcess) {
93 | TerminateProcess(m_hProcess, 0); // 强制关闭进程
94 | CloseHandle(m_hProcess); // 关闭进程句柄
95 | }
96 | }
97 |
98 | void CAIChatBoxDlg::DoDataExchange(CDataExchange* pDX)
99 | {
100 | CDialogEx::DoDataExchange(pDX);
101 | DDX_Control(pDX, IDC_RICHEDIT_SYSTEM_PROMPT, m_RichEdit_SystemPrompt);
102 | DDX_Control(pDX, IDC_RICHEDIT_CHAT_HISTORY, m_RichEdit_Dialogue);
103 | DDX_Control(pDX, IDC_RICHEDIT_USER_INPUT, m_RichEdit_UserInput);
104 | DDX_Control(pDX, IDC_LIST_HISTORY, m_ListBox_History);
105 | }
106 |
107 | BEGIN_MESSAGE_MAP(CAIChatBoxDlg, CDialogEx)
108 | ON_WM_SYSCOMMAND()
109 | ON_WM_PAINT()
110 | ON_WM_QUERYDRAGICON()
111 | ON_BN_CLICKED(IDC_BUTTON_SETTING, &CAIChatBoxDlg::OnBnClickedButtonSetting)
112 | ON_WM_CLOSE()
113 | ON_LBN_SELCHANGE(IDC_LIST_HISTORY, &CAIChatBoxDlg::OnLbnSelchangeListHistory)
114 | ON_BN_CLICKED(IDC_BUTTON_SEND_MESSAGE, &CAIChatBoxDlg::OnBnClickedButtonSendMessage)
115 | ON_MESSAGE(WM_RESPONSE_RECEIVED, &CAIChatBoxDlg::OnThreadResponse)
116 | ON_BN_CLICKED(IDC_BUTTON_NEW_CHAT, &CAIChatBoxDlg::OnBnClickedButtonNewChat)
117 | ON_MESSAGE(WM_UPDATE_TOKEN_COUNT, &CAIChatBoxDlg::OnUpdateTokenCount)
118 | ON_BN_CLICKED(IDC_BUTTON_CLEAR_MESSAGE, &CAIChatBoxDlg::OnBnClickedButtonClearMessage)
119 | ON_COMMAND(ID_DELETE, &CAIChatBoxDlg::OnListboxDelete)
120 | ON_WM_CONTEXTMENU()
121 | ON_BN_CLICKED(IDC_BUTTON_WITHDRAW_MESSAGE, &CAIChatBoxDlg::OnBnClickedButtonWithdrawMessage)
122 | ON_BN_CLICKED(IDC_BUTTON_SET_PROMPT, &CAIChatBoxDlg::OnBnClickedButtonSetPrompt)
123 | ON_BN_CLICKED(IDC_BUTTON_ABOUT, &CAIChatBoxDlg::OnBnClickedButtonAbout)
124 | ON_COMMAND(ID_RENAME, &CAIChatBoxDlg::OnRename)
125 | END_MESSAGE_MAP()
126 |
127 |
128 | // CAIChatBoxDlg 消息处理程序
129 |
130 | BOOL CAIChatBoxDlg::OnInitDialog()
131 | {
132 | CDialogEx::OnInitDialog();
133 |
134 | // 将“关于...”菜单项添加到系统菜单中。
135 |
136 | // IDM_ABOUTBOX 必须在系统命令范围内。
137 | ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
138 | ASSERT(IDM_ABOUTBOX < 0xF000);
139 |
140 | CMenu* pSysMenu = GetSystemMenu(FALSE);
141 | if (pSysMenu != nullptr)
142 | {
143 | BOOL bNameValid;
144 | CString strAboutMenu;
145 | bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
146 | ASSERT(bNameValid);
147 | if (!strAboutMenu.IsEmpty())
148 | {
149 | pSysMenu->AppendMenu(MF_SEPARATOR);
150 | pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
151 | }
152 | }
153 |
154 | // 设置此对话框的图标。 当应用程序主窗口不是对话框时,框架将自动
155 | // 执行此操作
156 | SetIcon(m_hIcon, TRUE); // 设置大图标
157 | SetIcon(m_hIcon, FALSE); // 设置小图标
158 |
159 | // TODO: 在此添加额外的初始化代码
160 |
161 | // 设置本对话框图标 (大图标)
162 | HICON hIconLarge = AfxGetApp()->LoadIcon(IDI_ICON2);
163 | SendMessage(WM_SETICON, ICON_BIG, (LPARAM)hIconLarge);
164 |
165 | // 设置本对话框图标 (小图标)
166 | HICON hIconSmall = static_cast(
167 | ::LoadImage(AfxGetResourceHandle(),
168 | MAKEINTRESOURCE(IDI_ICON1),
169 | IMAGE_ICON,
170 | 16, 16,
171 | LR_DEFAULTCOLOR)
172 | );
173 | SendMessage(WM_SETICON, ICON_SMALL, (LPARAM)hIconSmall);
174 |
175 | // 创建状态栏
176 | if (!m_StatusBar.Create(WS_CHILD | WS_VISIBLE | SBARS_SIZEGRIP, CRect(0, 0, 0, 0), this, 1234))
177 | {
178 | AfxMessageBox(L"状态栏创建失败");
179 | return FALSE;
180 | }
181 |
182 | // 设置状态栏分区
183 | int parts[] = { 250, 800, 1100, -1 }; // 2个分区
184 | m_StatusBar.SetParts(3, parts);
185 | m_StatusBar.SetText(L" 服务器: 未启动", 0, 0);
186 | m_StatusBar.SetText(L" 模型: 未选择", 1, 0);
187 | m_StatusBar.SetText(L" Tokens: 0 t/s", 2, 0);
188 | SetStatusBar();
189 |
190 | // 加载菜单
191 | m_Menu.LoadMenuW(IDR_MENU1);
192 |
193 | // 弹出设置对话框
194 | OnBnClickedButtonSetting();
195 | isFirstOpen = FALSE;
196 |
197 | if (m_strModel.IsEmpty())
198 | {
199 | MessageBox(L"请先到设置中选择模型!", L"错误", MB_ICONWARNING);
200 | }
201 |
202 | // 设置字体
203 | SetChatContext();
204 |
205 | return TRUE; // 除非将焦点设置到控件,否则返回 TRUE
206 | }
207 |
208 | void CAIChatBoxDlg::OnSysCommand(UINT nID, LPARAM lParam)
209 | {
210 | if ((nID & 0xFFF0) == IDM_ABOUTBOX)
211 | {
212 | CAboutDlg dlgAbout;
213 | dlgAbout.DoModal();
214 | }
215 | else
216 | {
217 | CDialogEx::OnSysCommand(nID, lParam);
218 | }
219 | }
220 |
221 | // 如果向对话框添加最小化按钮,则需要下面的代码
222 | // 来绘制该图标。 对于使用文档/视图模型的 MFC 应用程序,
223 | // 这将由框架自动完成。
224 |
225 | void CAIChatBoxDlg::OnPaint()
226 | {
227 | if (IsIconic())
228 | {
229 | CPaintDC dc(this); // 用于绘制的设备上下文
230 |
231 | SendMessage(WM_ICONERASEBKGND, reinterpret_cast(dc.GetSafeHdc()), 0);
232 |
233 | // 使图标在工作区矩形中居中
234 | int cxIcon = GetSystemMetrics(SM_CXICON);
235 | int cyIcon = GetSystemMetrics(SM_CYICON);
236 | CRect rect;
237 | GetClientRect(&rect);
238 | int x = (rect.Width() - cxIcon + 1) / 2;
239 | int y = (rect.Height() - cyIcon + 1) / 2;
240 |
241 | // 绘制图标
242 | dc.DrawIcon(x, y, m_hIcon);
243 | }
244 | else
245 | {
246 | CDialogEx::OnPaint();
247 | }
248 | }
249 |
250 | //当用户拖动最小化窗口时系统调用此函数取得光标
251 | //显示。
252 | HCURSOR CAIChatBoxDlg::OnQueryDragIcon()
253 | {
254 | return static_cast(m_hIcon);
255 | }
256 |
257 | void CAIChatBoxDlg::SetChatContext()
258 | {
259 | // 重置聊天上下文
260 | //chatContext.removeAllActors();
261 | //chatContext.resetChatHistory();
262 |
263 | // 设置聊天保护是否启用
264 | chatContext.setChatGuards(chat_guards);
265 | // 设置是否处于聊天模式
266 | chatContext.setChatMode(chat_mode);
267 |
268 | // 根据调试模式的设置,启用或禁用文件日志记录
269 | if (!debug)
270 | Logging::disable_file_logging();
271 |
272 | // 加载聊天模板,如果为空则使用 OAI 完成风格
273 | // OAI是OpenAI的缩写,是一个人工智能公司
274 | if (chat_template.empty()) {
275 | chatContext.using_oai_completion = true;
276 | }
277 | else {
278 | // 尝试加载自定义聊天模板,如果失败则记录错误并暂停
279 | if (!chatContext.loadChatTemplates(chat_template)) {
280 | Logging::error("Failed to load the custom chat template '%s'! Using default empty.", chat_template.c_str());
281 | }
282 | }
283 |
284 | //// 加载用户提示信息,如果为空则设置系统提示信息和默认角色
285 | //if (user_prompt.empty()) {
286 | // chatContext.setupSystemPrompt("You are a very helpful assistant");
287 | // chatContext.setupDefaultActors();
288 | //}
289 | //else {
290 |
291 | // std::string_view user_prompt_view(user_prompt);
292 |
293 | // // 尝试加载用户提示信息,如果失败则退出程序
294 | // if (!chatContext.loadUserPrompt(user_prompt))
295 | // {
296 | // MessageBox(TEXT("Failed to load the user prompt!"), TEXT("Error"), MB_ICONERROR);
297 | // exit(1);
298 | // }
299 | //}
300 |
301 | // 加载参数配置文件,如果失败则记录错误并退出程序
302 | if (!chatContext.loadParametersSettings(param_profile)) {
303 | Logging::error("Failed to load the param profile '%s'!", param_profile.c_str());
304 | //Terminal::pause();
305 | exit(1);
306 | }
307 |
308 | // 配置聊天停止词
309 | chatContext.setupChatStopWords();
310 |
311 | // 控制角色的对话轮次
312 | currentActor = chatContext.getAssistantName();
313 | }
314 |
315 | void CAIChatBoxDlg::SetEditFont(CRichEditCtrl& edit)
316 | {
317 | DWORD dwOldStyle = edit.GetExStyle(); //默认包含透明属性
318 | edit.ModifyStyleEx(dwOldStyle, WS_EX_CLIENTEDGE); //去除透明属性
319 | //m_redit.SetBackgroundColor(TRUE, GetSysColor(COLOR_3DFACE));
320 | edit.SetBackgroundColor(FALSE, m_clrBackground);
321 |
322 | // 设置字体
323 | CHARFORMAT2 cf;
324 | cf.cbSize = sizeof(cf);
325 | cf.dwMask = CFM_FACE | CFM_SIZE | CFM_BOLD | CFM_ITALIC | CFM_COLOR;
326 | cf.dwEffects = 0;
327 | cf.yHeight = 100 * m_nFontSize;
328 | _tcscpy_s(cf.szFaceName, _countof(cf.szFaceName), m_strFont);
329 | cf.crTextColor = m_clrText;
330 | if (m_isBold)
331 | cf.dwEffects |= CFE_BOLD;
332 | if (m_isItalic)
333 | cf.dwEffects |= CFE_ITALIC;
334 | edit.SetSel(-1, -1);
335 | edit.SetDefaultCharFormat(cf);
336 | }
337 |
338 | void CAIChatBoxDlg::SetStatusBar()
339 | {
340 | if (m_hProcess)
341 | {
342 | CString str;
343 | str.Format(TEXT(" 服务器已启动, 端口: %d"), m_nPort);
344 | m_StatusBar.SetText(str, 0, 0);
345 | }
346 | else
347 | {
348 | m_StatusBar.SetText(L" 服务器未启动", 0, 0);
349 | }
350 |
351 | if (!m_strModel.IsEmpty())
352 | {
353 | CString str;
354 | str.Format(TEXT(" 模型: %s"), m_strModel);
355 | m_StatusBar.SetText(str, 1, 0);
356 | }
357 | else
358 | {
359 | m_StatusBar.SetText(L" 模型: 未选择", 1, 0);
360 | }
361 |
362 | //CString tokenText;
363 | //tokenText.Format(L"Tokens: %.1f t/s", *(double*)&wParam);
364 | //m_StatusBar.SetText(tokenText, 2, 0);
365 |
366 | //return 0;
367 | }
368 |
369 | LRESULT CAIChatBoxDlg::OnUpdateTokenCount(WPARAM wParam, LPARAM lParam)
370 | {
371 | CString tokenText;
372 | tokenText.Format(L" Tokens: %.1f t/s", *(double*)&wParam);
373 | m_StatusBar.SetText(tokenText, 2, 0);
374 | return 0;
375 | }
376 |
377 | bool CAIChatBoxDlg::StartServer(bool isModelChanged = false)
378 | {
379 | if (isModelChanged) // 模型文件夹路径改变,需要重新启动服务器
380 | {
381 | if (m_hProcess) // 服务器已启动,先关闭服务器
382 | {
383 | StopServer();
384 | }
385 | }
386 |
387 | if (!m_hProcess) // 服务器未启动
388 | {
389 | // 改进代码:转义路径中的空格
390 | CString modelPath = m_strModelPath + TEXT("\\") + m_strModel;
391 | PathQuoteSpaces(modelPath.GetBuffer(MAX_PATH)); // 自动添加双引号, 防止路径中有空格
392 | modelPath.ReleaseBuffer();
393 |
394 | // 构建命令时直接使用转义后的路径
395 | CString command;
396 | command.Format(TEXT(".\\server\\llama-server.exe -m %s --port %d"), modelPath.GetString(), m_nPort);
397 | // std::wstring command = L"G:\\Desktop\\llama-cpp\\server\\llama-server.exe -m G:\\Desktop\\llama-cpp\\models\\Qwen2.5-7B-Instruct-Uncensored.Q8_0.gguf -c 2048";
398 |
399 | std::wstring cmd = command.GetBuffer();
400 |
401 | // 创建进程信息
402 | STARTUPINFO si = { sizeof(si) };
403 | PROCESS_INFORMATION pi = {};
404 |
405 | // 启动进程
406 | if (CreateProcess(
407 | nullptr, // 应用程序名称
408 | &cmd[0], // 命令行
409 | nullptr, // 默认进程安全属性
410 | nullptr, // 默认线程安全属性
411 | FALSE, // 是否继承句柄
412 | CREATE_NO_WINDOW, // 不创建控制台窗口
413 | nullptr, // 使用父进程的环境
414 | nullptr, // 使用父进程的当前目录
415 | &si, // 启动信息
416 | &pi // 进程信息
417 | ))
418 | {
419 | m_hProcess = pi.hProcess; // 保存进程句柄以便后续关闭
420 | CloseHandle(pi.hThread); // 关闭线程句柄
421 |
422 | MessageBox(L"服务器已启动", L"提示", MB_OK);
423 | return true;
424 | }
425 | else
426 | {
427 | DWORD error = GetLastError();
428 | CString msg;
429 | msg.Format(L"服务器启动失败 (错误码: %d)", error);
430 | MessageBox(msg, L"错误", MB_ICONERROR);
431 | }
432 | }
433 | else
434 | {
435 | MessageBox(L"服务器已启动", L"提示", MB_OK);
436 | return true;
437 | }
438 | }
439 |
440 | bool CAIChatBoxDlg::StopServer()
441 | {
442 | if (m_hProcess) // 服务器已启动
443 | {
444 | // 终止服务器进程
445 | if (TerminateProcess(m_hProcess, 0))
446 | {
447 | CloseHandle(m_hProcess); // 关闭进程句柄
448 | m_hProcess = nullptr;
449 | MessageBox(L"服务器已关闭", L"提示", MB_OK);
450 | return true;
451 | }
452 | else
453 | {
454 | MessageBox(L"关闭服务器失败", L"错误", MB_ICONERROR);
455 | return false;
456 | }
457 | }
458 | else
459 | {
460 | MessageBox(L"服务器未启动", L"提示", MB_OK);
461 | return true;
462 | }
463 | }
464 |
465 | void CAIChatBoxDlg::OnBnClickedButtonSetting()
466 | {
467 | // TODO: 在此添加控件通知处理程序代码
468 |
469 | SettingDlg dlg;
470 | bool isModelChanged = false; // 模型是否改变
471 | bool isHistoryChanged = false; // 历史记录文件夹是否改变
472 |
473 | dlg.m_strModelPath = m_strModelPath;
474 | dlg.m_nPort = m_nPort;
475 | dlg.m_strModel = m_strModel;
476 | dlg.m_strFont = m_strFont;
477 | dlg.m_nFontSize = m_nFontSize;
478 | dlg.m_clrBackground = m_clrBackground;
479 | dlg.m_clrText = m_clrText;
480 | dlg.m_clrUser = m_clrUser;
481 | dlg.m_clrAssistant = m_clrAssistant;
482 | dlg.m_isBold = m_isBold;
483 | dlg.m_isItalic = m_isItalic;
484 | dlg.m_strHistory = m_strHistory;
485 | dlg.isFirstOpen = isFirstOpen;
486 |
487 | if (dlg.DoModal() == IDOK)
488 | {
489 | m_strModelPath = dlg.m_strModelPath;
490 | m_nPort = dlg.m_nPort;
491 | if (m_strModel != dlg.m_strModel) isModelChanged = true; // 模型文件夹路径改变
492 | m_strModel = dlg.m_strModel;
493 | m_strFont = dlg.m_strFont;
494 | m_nFontSize = dlg.m_nFontSize;
495 | m_clrBackground = dlg.m_clrBackground;
496 | m_clrText = dlg.m_clrText;
497 | m_clrUser = dlg.m_clrUser;
498 | m_clrAssistant = dlg.m_clrAssistant;
499 | m_isBold = dlg.m_isBold;
500 | m_isItalic = dlg.m_isItalic;
501 | if (m_strHistory != dlg.m_strHistory) isHistoryChanged = true; // 历史记录文件夹改变
502 | m_strHistory = dlg.m_strHistory;
503 |
504 | // 设置字体
505 | SetEditFont(m_RichEdit_SystemPrompt);
506 | SetEditFont(m_RichEdit_Dialogue);
507 | SetEditFont(m_RichEdit_UserInput);
508 |
509 | // 设置用户和助手颜色
510 | chatContext.setUserAndAssistantColor(m_clrUser, m_clrAssistant);
511 |
512 | // 启动服务器
513 | StartServer(isModelChanged);
514 | // 更新状态栏
515 | SetStatusBar();
516 | // 加载历史记录
517 | LoadHistoryFromFolder(isHistoryChanged);
518 | // 绘制对话
519 | DrawDialogue();
520 | }
521 | }
522 |
523 |
524 | void CAIChatBoxDlg::OnClose()
525 | {
526 | // TODO: 在此添加消息处理程序代码和/或调用默认值
527 |
528 | // 保存历史记录
529 | if (isNeedSave)
530 | {
531 | SaveHistory();
532 | //MessageBox(TEXT("Conversation saved!"), TEXT("Info"), MB_ICONINFORMATION);
533 | }
534 |
535 | // 关闭服务器
536 | StopServer();
537 |
538 | CDialogEx::OnClose();
539 | }
540 |
541 | bool CAIChatBoxDlg::LoadHistoryFromFolder(bool isHistoryChanged)
542 | {
543 | // 获取文件夹下的所有文件
544 | //if (!isHistoryChanged)
545 | //{
546 | // return false;
547 | //}
548 |
549 | m_History.clear(); // 清空历史记录
550 | m_ListBox_History.ResetContent(); // 清空列表框
551 |
552 | CFileFind finder;
553 | BOOL bWorking = finder.FindFile(m_strHistory + TEXT("\\*.json"));
554 | while (bWorking)
555 | {
556 | bWorking = finder.FindNextFile();
557 | CString filename = finder.GetFileName();
558 | m_History.push_back(filename);
559 | }
560 | finder.Close();
561 | // 将文件名添加到列表框
562 | for (const CString& file : m_History)
563 | {
564 | m_ListBox_History.AddString(file);
565 | }
566 |
567 | return true;
568 | }
569 |
570 |
571 | void CAIChatBoxDlg::OnLbnSelchangeListHistory()
572 | {
573 | // TODO: 在此添加控件通知处理程序代码
574 |
575 | if (isNeedSave)
576 | {
577 | SaveHistory();
578 | //MessageBox(TEXT("Conversation saved!"), TEXT("Info"), MB_ICONINFORMATION);
579 | }
580 |
581 |
582 | // 获取选中的文件名
583 | int index = m_ListBox_History.GetCurSel();
584 | CString filename;
585 | m_ListBox_History.GetText(index, filename);
586 | // 读取文件内容
587 | CString filepath = m_strHistory + TEXT("\\") + filename;
588 |
589 | std::string strfilename = CT2A(filepath);
590 |
591 | // 使用loadSavedConversation
592 | if (chatContext.loadSavedConversation(strfilename))
593 | {
594 | SetChatContext();
595 | Logging::success("Conversation from '%s' loaded.", strfilename.c_str());
596 | chatContext.completionBus.buffer.clear(); // 清空完成操作的回调总线缓冲区
597 | DrawSystemPrompt(); // 绘制系统提示
598 | DrawDialogue(); // 绘制对话
599 | m_currentHistory = filename; // 设置当前历史记录
600 | isNeedSave = false; // 不需要保存
601 | }
602 | else
603 | {
604 | Logging::error("Failed to load conversation!");
605 | MessageBox(TEXT("Failed to load conversation!"), TEXT("Error"), MB_ICONERROR);
606 | }
607 | }
608 |
609 | bool CAIChatBoxDlg::SaveHistory()
610 | {
611 | // 获取当前时间
612 | SYSTEMTIME sysTime;
613 | // 生成文件名
614 | CString filename = m_strHistory + TEXT("\\") + m_currentHistory; // 保存为当前历史记录的文件名
615 | std::string strfilename = CT2A(filename);
616 | // 保存对话
617 | if (chatContext.saveConversation(strfilename))
618 | {
619 | Logging::success("Conversation saved to '%s'.", strfilename.c_str());
620 | // 重新加载历史记录
621 | // LoadHistoryFromFolder(true);
622 | return true;
623 | }
624 | else
625 | {
626 | Logging::error("Failed to save conversation!");
627 | MessageBox(TEXT("Failed to save conversation!"), TEXT("Error"), MB_ICONERROR);
628 | return false;
629 | }
630 | }
631 |
632 | void CAIChatBoxDlg::DrawSystemPrompt()
633 | {
634 | chatContext.drawSystem(m_RichEdit_SystemPrompt); // 绘制系统提示
635 | }
636 |
637 | void CAIChatBoxDlg::DrawDialogue()
638 | {
639 | chatContext.draw(m_RichEdit_Dialogue); // 绘制对话
640 | }
641 |
642 |
643 | void CAIChatBoxDlg::OnBnClickedButtonSendMessage()
644 | {
645 | // TODO: 在此添加控件通知处理程序代码
646 |
647 | // 在函数开头添加等待光标
648 | //CWaitCursor wait; // 自动显示沙漏图标
649 | //Sleep(5000); // 模拟耗时操作
650 |
651 | // 检查线程是否正在运行
652 | if (m_threadRunning)
653 | {
654 | MessageBox(TEXT("请求已在进行中,请稍候"), TEXT("提示"), MB_ICONINFORMATION);
655 | return;
656 | }
657 |
658 | // 检查是否启动了服务器
659 | if (!m_hProcess)
660 | {
661 | MessageBox(TEXT("请先启动服务器"), TEXT("错误"), MB_ICONERROR);
662 | return;
663 | }
664 |
665 | // 检查m_currentHistory是否为空
666 | if (m_currentHistory.IsEmpty())
667 | {
668 | MessageBox(TEXT("请先选择一条记录"), TEXT("错误"), MB_ICONERROR);
669 | return;
670 | }
671 |
672 | // 控制当前说话的角色,如果 onceAct 为真,则使用之前的角色
673 | if (onceAct) {
674 | currentActor = previousActingActor;
675 | onceAct = false;
676 | }
677 | else {
678 | previousActingActor = currentActor;
679 | }
680 |
681 | // 获取用户输入
682 | m_RichEdit_UserInput.GetWindowText(userInput);
683 | if (userInput.IsEmpty())
684 | {
685 | MessageBox(TEXT("Please enter a message!"), TEXT("Error"), MB_ICONERROR);
686 | return;
687 | }
688 | else
689 | {
690 | // 清空用户输入
691 | m_RichEdit_UserInput.SetWindowText(TEXT(""));
692 | }
693 |
694 | // 禁用按钮,避免重复操作
695 | GetDlgItem(IDC_BUTTON_SEND_MESSAGE)->EnableWindow(FALSE);
696 | GetDlgItem(IDC_BUTTON_WITHDRAW_MESSAGE)->EnableWindow(FALSE);
697 | m_threadRunning = true;
698 |
699 | // 打印用户的聊天标签
700 | chatContext.printActorChaTag(chatContext.getUserName(), m_RichEdit_Dialogue, m_clrUser);
701 |
702 | // 显示用户输入
703 | m_RichEdit_Dialogue.ReplaceSel(userInput + TEXT("\r\n"));
704 | chatContext.addNewMessage(chatContext.getUserName(), ConvertCStringToUtf8(userInput));
705 |
706 | // 打印当前角色的聊天标签
707 | chatContext.printActorChaTag(currentActor, m_RichEdit_Dialogue, m_clrAssistant);
708 |
709 | UpdateData(FALSE);
710 |
711 | chatContext.completionBus.buffer.clear(); // 清空完成操作的回调总线缓冲区
712 |
713 | // 启动线程
714 | m_pThread = AfxBeginThread(ThreadFunction, this);
715 |
716 | // 保存对话
717 | isNeedSave = true;
718 | }
719 |
720 | UINT CAIChatBoxDlg::ThreadFunction(LPVOID pParam)
721 | {
722 | auto* pThis = reinterpret_cast(pParam);
723 |
724 | // 从界面获取用户输入和其他信息
725 | const char* ip = "127.0.0.1"; // 这里是本地地址
726 | int16_t port = pThis->m_nPort; // 从设置对话框获取端口号
727 |
728 | // 发送完成请求到服务器
729 | Response res = pThis->chatContext.requestCompletion(ip, port, pThis->chatContext.getCurrentPrompt(), pThis->m_RichEdit_Dialogue);
730 |
731 | // 在主线程中更新UI
732 | pThis->PostMessage(WM_RESPONSE_RECEIVED, reinterpret_cast(new Response(res))); // 自定义消息
733 |
734 | return 0;
735 | }
736 |
737 | void CAIChatBoxDlg::HandleServerResponse(const Response& res)
738 | {
739 | if (res.Status != HTTP_OK)
740 | {
741 | // HandleServerError(res); // 错误处理
742 | MessageBox(TEXT("网络错误!"));
743 | }
744 | else
745 | {
746 | chatContext.cureCompletionForChat(); // 清理聊天完成相关的缓冲区
747 | if (chatContext.using_oai_completion)
748 | {
749 | chatContext.addNewMessage(currentActor, "");
750 | }
751 | // 将服务器响应添加到聊天上下文
752 | chatContext.updateMessageContent(chatContext.messagesCount() - 1, chatContext.completionBus.buffer);
753 | }
754 | HandleThreadCompletion(); // 处理线程完成
755 | m_RichEdit_Dialogue.ReplaceSel(TEXT("\r\n")); // 换行
756 | }
757 |
758 | void CAIChatBoxDlg::HandleThreadCompletion()
759 | {
760 | m_threadRunning = false; // 线程完成
761 |
762 | GetDlgItem(IDC_BUTTON_SEND_MESSAGE)->EnableWindow(TRUE); // 启用按钮
763 | GetDlgItem(IDC_BUTTON_WITHDRAW_MESSAGE)->EnableWindow(TRUE); // 启用按钮
764 | }
765 |
766 | LRESULT CAIChatBoxDlg::OnThreadResponse(WPARAM wParam, LPARAM lParam)
767 | {
768 | // 获取线程传递的响应对象
769 | std::unique_ptr pResponse(reinterpret_cast(wParam)); // 转换为Response对象
770 | if (pResponse)
771 | {
772 | HandleServerResponse(*pResponse); // 处理服务器响应
773 | }
774 | return 0;
775 | }
776 |
777 |
778 | void CAIChatBoxDlg::OnBnClickedButtonNewChat()
779 | {
780 | // TODO: 在此添加控件通知处理程序代码
781 |
782 | // 先保存当前对话
783 | if (isNeedSave)
784 | {
785 | SaveHistory();
786 | //MessageBox(TEXT("Conversation saved!"), TEXT("Info"), MB_ICONINFORMATION);
787 | }
788 |
789 | NewChatDlg dlg;
790 | dlg.chatContext = &chatContext;
791 | if (dlg.DoModal() == IDOK)
792 | {
793 | // 在m_strHistory路径下创建一个新的json文件
794 | CString filename = m_strHistory + TEXT("\\") + dlg.m_strChatName + TEXT(".json");
795 | m_currentHistory = dlg.m_strChatName + TEXT(".json");
796 | std::string strfilename = CT2A(filename);
797 |
798 | // 保存对话
799 | if (chatContext.saveConversation(strfilename))
800 | {
801 | Logging::success("Conversation saved to '%s'.", strfilename.c_str());
802 | // 重新加载历史记录
803 | LoadHistoryFromFolder(true);
804 | }
805 | else
806 | {
807 | Logging::error("Failed to save conversation!");
808 | MessageBox(TEXT("Failed to save conversation!"), TEXT("Error"), MB_ICONERROR);
809 | }
810 |
811 | // ListBox中选择filename
812 | for (int i = 0; i < m_History.size(); i++)
813 | {
814 | if (m_History[i] == dlg.m_strChatName + TEXT(".json"))
815 | {
816 | m_ListBox_History.SetCurSel(i);
817 | OnLbnSelchangeListHistory();
818 | break;
819 | }
820 | }
821 |
822 | // 设置聊天上下文
823 | currentActor = chatContext.getAssistantName();
824 | }
825 | }
826 |
827 |
828 | BOOL CAIChatBoxDlg::PreTranslateMessage(MSG* pMsg)
829 | {
830 | // TODO: 在此添加专用代码和/或调用基类
831 |
832 | // 按下回车键发送消息
833 | if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_RETURN)
834 | {
835 | // 如果焦点在编辑控件上,处理回车键
836 | if (GetFocus() == &m_RichEdit_UserInput)
837 | {
838 | OnBnClickedButtonSendMessage(); // 发送消息
839 | }
840 | return TRUE; // 阻止消息继续传递
841 | }
842 | return CDialogEx::PreTranslateMessage(pMsg);
843 | }
844 |
845 |
846 | void CAIChatBoxDlg::OnBnClickedButtonClearMessage()
847 | {
848 | // TODO: 在此添加控件通知处理程序代码
849 | m_RichEdit_UserInput.SetWindowText(TEXT(""));
850 | }
851 |
852 |
853 | void CAIChatBoxDlg::OnListboxDelete()
854 | {
855 | // TODO: 在此添加命令处理程序代码
856 | // 删除历史记录
857 | if (m_nSelectedItem != -1)
858 | {
859 | // 弹出确认对话框
860 | if (MessageBox(TEXT("确定要删除吗?"), TEXT("提示"), MB_YESNO | MB_ICONQUESTION) == IDNO)
861 | {
862 | return;
863 | }
864 |
865 | CString filename;
866 | m_ListBox_History.GetText(m_nSelectedItem, filename);
867 | CString filepath = m_strHistory + TEXT("\\") + filename;
868 |
869 | if (!PathFileExists(filepath)) {
870 | MessageBox(L"文件不存在!", L"错误", MB_ICONERROR);
871 | return;
872 | }
873 |
874 | DeleteFile(filepath);
875 | // 重新加载历史记录
876 | LoadHistoryFromFolder(true);
877 | }
878 | }
879 |
880 |
881 | void CAIChatBoxDlg::OnContextMenu(CWnd* pWnd, CPoint point)
882 | {
883 | // TODO: 在此处添加消息处理程序代码
884 | // 判断是否在我们的 ListBox 中右键
885 | if (pWnd->GetDlgCtrlID() == IDC_LIST_HISTORY) // 你的 ListBox ID
886 | {
887 | // 先把屏幕坐标转换为 ListBox 客户区坐标
888 | CPoint ptClient = point;
889 | m_ListBox_History.ScreenToClient(&ptClient);
890 |
891 | // 判断点击到了哪一行
892 | BOOL bOutside = FALSE;
893 | int nIndex = m_ListBox_History.ItemFromPoint(ptClient, bOutside);
894 |
895 | // 如果在某行上(而不是空白区域),则弹出菜单
896 | if (!bOutside && nIndex != LB_ERR)
897 | {
898 | // 记住要删除的行,用成员变量或其他方式保存
899 | m_nSelectedItem = nIndex;
900 |
901 | // 弹出菜单
902 | CMenu* pMenu = m_Menu.GetSubMenu(0); // 你的菜单
903 | pMenu->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, point.y, this);
904 |
905 | // 使得右键菜单消失后,ListBox 不再选中任何项
906 | m_ListBox_History.SetCurSel(-1);
907 |
908 | return;
909 | }
910 | }
911 | else
912 | {
913 | // 如果并不是在 ListBox 上右键,那就交给默认处理
914 | CDialogEx::OnContextMenu(pWnd, point);
915 | }
916 | }
917 |
918 |
919 | void CAIChatBoxDlg::OnBnClickedButtonWithdrawMessage()
920 | {
921 | // TODO: 在此添加控件通知处理程序代码
922 |
923 | // 检查m_currentHistory是否为空
924 | if (m_currentHistory.IsEmpty())
925 | {
926 | MessageBox(TEXT("请先选择一条记录"), TEXT("错误"), MB_ICONERROR);
927 | return;
928 | }
929 |
930 | // 撤销上一次完成和用户消息
931 | chatContext.removeLastMessage(2);
932 | DrawDialogue();
933 |
934 | // 保存对话
935 | isNeedSave = true;
936 | }
937 |
938 | void CAIChatBoxDlg::OnBnClickedButtonSetPrompt()
939 | {
940 | // TODO: 在此添加控件通知处理程序代码
941 |
942 | // 检查m_currentHistory是否为空
943 | if (m_currentHistory.IsEmpty())
944 | {
945 | MessageBox(TEXT("请先选择一条记录"), TEXT("错误"), MB_ICONERROR);
946 | return;
947 | }
948 |
949 | PromptDlg dlg;
950 | std::string systemPrompt = chatContext.getSystemPrompt();
951 | dlg.m_strPrompt = ConvertUtf8ToCString(systemPrompt);
952 | if (dlg.DoModal() == IDOK)
953 | {
954 | // 更新系统提示
955 | systemPrompt = ConvertCStringToUtf8(dlg.m_strPrompt);
956 | chatContext.updateSystemPrompt(systemPrompt);
957 | DrawSystemPrompt();
958 | // 保存对话
959 | isNeedSave = true;
960 | }
961 | }
962 |
963 |
964 | void CAIChatBoxDlg::OnBnClickedButtonAbout()
965 | {
966 | // TODO: 在此添加控件通知处理程序代码
967 | // 弹出关于对话框
968 | CAboutDlg dlg;
969 | dlg.DoModal();
970 | }
971 |
972 |
973 | void CAIChatBoxDlg::OnRename()
974 | {
975 | // TODO: 在此添加命令处理程序代码
976 | // 重命名历史记录
977 | if (m_nSelectedItem != -1)
978 | {
979 | // 获取选中的文件名
980 | CString filename;
981 | m_ListBox_History.GetText(m_nSelectedItem, filename);
982 | CString filepath = m_strHistory + TEXT("\\") + filename;
983 |
984 | if (!PathFileExists(filepath)) {
985 | MessageBox(L"文件不存在!", L"错误", MB_ICONERROR);
986 | return;
987 | }
988 |
989 | // 获取不带后缀的文件名
990 | filename = filename.Left(filename.GetLength() - 5);
991 |
992 | // 弹出重命名对话框
993 | RenameDlg dlg;
994 | dlg.m_name = filename;
995 | if (dlg.DoModal() == IDOK)
996 | {
997 | // 获取新的文件名
998 | CString newFilename = dlg.m_name + TEXT(".json");
999 | CString newFilepath = m_strHistory + TEXT("\\") + newFilename;
1000 |
1001 | // 重命名文件
1002 | if (MoveFile(filepath, newFilepath))
1003 | {
1004 | // 更新列表框中的文件名
1005 | m_ListBox_History.DeleteString(m_nSelectedItem);
1006 | m_ListBox_History.InsertString(m_nSelectedItem, newFilename);
1007 | m_ListBox_History.SetCurSel(m_nSelectedItem);
1008 |
1009 | // 更新当前历史记录文件名
1010 | if (m_currentHistory == filename + TEXT(".json"))
1011 | {
1012 | m_currentHistory = newFilename;
1013 | }
1014 | MessageBox(TEXT("重命名成功"), TEXT("提示"), MB_OK);
1015 | }
1016 | else
1017 | {
1018 | MessageBox(TEXT("重命名失败"), TEXT("错误"), MB_ICONERROR);
1019 | }
1020 | }
1021 | }
1022 | }
1023 |
--------------------------------------------------------------------------------
/src/AIChatBox/AIChatBox/AIChatBoxDlg.h:
--------------------------------------------------------------------------------
1 |
2 | // AIChatBoxDlg.h: 头文件
3 | //
4 |
5 | #pragma once
6 | #include "chat.h"
7 | #define WM_UPDATE_TOKEN_COUNT (WM_USER + 100) // 自定义消息,用于更新token数
8 | #define WM_RESPONSE_RECEIVED (WM_USER + 101) // 自定义消息,用于处理服务器响应
9 |
10 | // CAIChatBoxDlg 对话框
11 | class CAIChatBoxDlg : public CDialogEx
12 | {
13 | // 构造
14 | public:
15 | CAIChatBoxDlg(CWnd* pParent = nullptr); // 标准构造函数
16 |
17 | // 析构
18 | virtual ~CAIChatBoxDlg();
19 |
20 | // 对话框数据
21 | #ifdef AFX_DESIGN_TIME
22 | enum { IDD = IDD_AICHATBOX_DIALOG };
23 | #endif
24 |
25 | protected:
26 | virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持
27 |
28 |
29 | // 实现
30 | protected:
31 | HICON m_hIcon;
32 |
33 | // 生成的消息映射函数
34 | virtual BOOL OnInitDialog();
35 | afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
36 | afx_msg void OnPaint();
37 | afx_msg HCURSOR OnQueryDragIcon();
38 | DECLARE_MESSAGE_MAP()
39 |
40 | private:
41 |
42 | Chat chatContext; // 聊天上下文
43 | void SetChatContext(); // 设置聊天上下文
44 | std::string user_prompt; // 存储用户输入的提示信息,从 prompts.json 中读取
45 | std::string chat_template; // 存储聊天模板,从 tempaltes.json 中读取
46 | std::string param_profile; // 存储参数配置文件,从 params.json 中读取
47 | bool chat_mode; // 是否启用聊天模式
48 | bool chat_guards; // 是否启用聊天保护
49 | bool debug; // 是否开启调试模式
50 | bool onceAct; // 控制角色的对话轮次
51 | std::string previousActingActor; // 上一个角色
52 | std::string currentActor; // 当前角色
53 |
54 | CString m_strModelPath; // 模型文件夹路径
55 | int m_nPort; // 端口号
56 | CString m_strModel; // 模型文件名
57 |
58 | CString m_strFont; // 字体
59 | int m_nFontSize; // 字体大小
60 | COLORREF m_clrBackground; // 背景颜色
61 | COLORREF m_clrText; // 文本颜色
62 | COLORREF m_clrUser; // 用户颜色
63 | COLORREF m_clrAssistant; // 助手颜色
64 | BOOL m_isBold; // 是否加粗
65 | BOOL m_isItalic; // 是否斜体
66 | void SetEditFont(CRichEditCtrl& edit); // 设置编辑框字体
67 |
68 | CStatusBarCtrl m_StatusBar; // 状态栏
69 | void SetStatusBar(); // 设置状态栏
70 | afx_msg LRESULT OnUpdateTokenCount(WPARAM wParam, LPARAM lParam); // 更新token数
71 |
72 | HANDLE m_hProcess; // 服务端进程句柄
73 | bool StartServer(bool isModelChanged); // 启动服务端
74 | bool StopServer(); // 停止服务端
75 |
76 | bool isFirstOpen; // 是否第一次打开
77 |
78 | public:
79 |
80 | CRichEditCtrl m_RichEdit_SystemPrompt; // 系统提示
81 | CRichEditCtrl m_RichEdit_Dialogue; // 对话
82 | CRichEditCtrl m_RichEdit_UserInput; // 用户输入
83 | CString userInput; // 用户输入
84 | void DrawSystemPrompt(); // 绘制系统提示
85 | void DrawDialogue(); // 绘制对话
86 |
87 | CString m_strHistory; // 历史记录
88 | CListBox m_ListBox_History; // 历史记录列表框
89 | std::vector m_History; // 历史记录
90 | bool LoadHistoryFromFolder(bool isHistoryChanged); // 从文件夹加载历史记录
91 | afx_msg void OnLbnSelchangeListHistory(); // 历史记录列表框选择改变
92 | CString m_currentHistory; // 当前历史记录
93 | bool isNeedSave; // 是否需要保存历史记录
94 | bool SaveHistory(); // 保存历史记录
95 | int m_nSelectedItem; // 选中的历史记录
96 | CMenu m_Menu; // 右键菜单
97 | afx_msg void OnListboxDelete(); // 删除历史记录
98 | afx_msg void OnRename(); // 重命名
99 |
100 | CWinThread* m_pThread; // 用于服务器通信的工作线程
101 | bool m_threadRunning; // 标记线程是否正在运行
102 | static UINT ThreadFunction(LPVOID pParam); // 线程函数
103 | void HandleServerResponse(const Response& res); // 处理服务器响应
104 | void HandleThreadCompletion(); // 线程完成后更新UI
105 | LRESULT OnThreadResponse(WPARAM wParam, LPARAM lParam); // 线程消息处理函数
106 |
107 | virtual BOOL PreTranslateMessage(MSG* pMsg); // 拦截回车键
108 |
109 | // 消息映射
110 | afx_msg void OnBnClickedButtonSetting(); // 设置按钮
111 | afx_msg void OnClose(); // 关闭窗口
112 | afx_msg void OnContextMenu(CWnd* pWnd, CPoint point); // 右键菜单
113 | afx_msg void OnBnClickedButtonSendMessage(); // 发送消息
114 | afx_msg void OnBnClickedButtonNewChat(); // 新建对话
115 | afx_msg void OnBnClickedButtonClearMessage(); // 清空消息
116 | afx_msg void OnBnClickedButtonWithdrawMessage(); // 撤回消息
117 | afx_msg void OnBnClickedButtonSetPrompt(); // 设置提示
118 | afx_msg void OnBnClickedButtonAbout(); // 关于按钮
119 |
120 | };
121 |
--------------------------------------------------------------------------------
/src/AIChatBox/AIChatBox/NewChatDlg.cpp:
--------------------------------------------------------------------------------
1 | // NewChatDlg.cpp: 实现文件
2 | //
3 |
4 | #include "pch.h"
5 | #include "AIChatBox.h"
6 | #include "afxdialogex.h"
7 | #include "NewChatDlg.h"
8 |
9 |
10 | // NewChatDlg 对话框
11 |
12 | IMPLEMENT_DYNAMIC(NewChatDlg, CDialogEx)
13 |
14 | NewChatDlg::NewChatDlg(CWnd* pParent /*=nullptr*/)
15 | : CDialogEx(IDD_NEWCHAT_DIALOG, pParent)
16 | , m_strChatName(_T(""))
17 | , m_strUserName(_T(""))
18 | , m_strAIName(_T(""))
19 | , m_strSystemPrompt(_T(""))
20 | {
21 |
22 | }
23 |
24 | NewChatDlg::~NewChatDlg()
25 | {
26 | }
27 |
28 | void NewChatDlg::DoDataExchange(CDataExchange* pDX)
29 | {
30 | CDialogEx::DoDataExchange(pDX);
31 | DDX_Text(pDX, IDC_EDIT_CHAT_NAME, m_strChatName);
32 | DDX_Control(pDX, IDC_COMBO_SELECT_PROMPT, m_ComboBox_LoadPrompt);
33 | DDX_Text(pDX, IDC_EDIT_USER_NAME, m_strUserName);
34 | DDX_Text(pDX, IDC_EDIT_AI_NAME, m_strAIName);
35 | DDX_Control(pDX, IDC_EDIT_SYSTEM_PROMPT, m_Edit_SystemPrompt);
36 | }
37 |
38 |
39 | BEGIN_MESSAGE_MAP(NewChatDlg, CDialogEx)
40 | ON_CBN_SELCHANGE(IDC_COMBO_SELECT_PROMPT, &NewChatDlg::OnCbnSelchangeComboSelectPrompt)
41 | ON_BN_CLICKED(IDOK, &NewChatDlg::OnBnClickedOk)
42 | ON_BN_CLICKED(IDCANCEL, &NewChatDlg::OnBnClickedCancel)
43 | END_MESSAGE_MAP()
44 |
45 |
46 | // NewChatDlg 消息处理程序
47 |
48 |
49 | BOOL NewChatDlg::OnInitDialog()
50 | {
51 | CDialogEx::OnInitDialog();
52 |
53 | // TODO: 在此添加额外的初始化
54 |
55 | CTime currentTime = CTime::GetCurrentTime();
56 | CString defaultFileName = currentTime.Format(_T("%Y-%m-%d-%H-%M-%S"));
57 | m_strChatName = defaultFileName;
58 |
59 | if (chatContext->loadAllPrompts(m_Prompts))
60 | {
61 | for (const CString& prompt : m_Prompts)
62 | {
63 | m_ComboBox_LoadPrompt.AddString(prompt);
64 | }
65 | m_ComboBox_LoadPrompt.AddString(_T("自定义"));
66 | m_ComboBox_LoadPrompt.SetCurSel(0);
67 | }
68 | else
69 | {
70 | m_ComboBox_LoadPrompt.AddString(_T("未找到提示文件"));
71 | }
72 |
73 | //m_ComboBox_LoadPrompt.
74 |
75 | UpdateData(FALSE);
76 |
77 | return TRUE; // return TRUE unless you set the focus to a control
78 | // 异常: OCX 属性页应返回 FALSE
79 | }
80 |
81 |
82 | void NewChatDlg::LoadPrompts(CString prompt_name)
83 | {
84 | chatContext->loadUserPrompt(ConvertCStringToUtf8(prompt_name));
85 | m_strUserName = ConvertUtf8ToCString(chatContext->getUserName());
86 | m_strAIName = ConvertUtf8ToCString(chatContext->getAssistantName());
87 | chatContext->drawSystem(m_Edit_SystemPrompt);
88 | UpdateData(FALSE);
89 | }
90 |
91 | void NewChatDlg::OnCbnSelchangeComboSelectPrompt()
92 | {
93 | // TODO: 在此添加控件通知处理程序代码
94 | int index = m_ComboBox_LoadPrompt.GetCurSel();
95 | CString prompt_name;
96 | m_ComboBox_LoadPrompt.GetLBText(index, prompt_name);
97 | if (prompt_name == _T("自定义"))
98 | {
99 | m_strUserName = _T("");
100 | m_strAIName = _T("");
101 | m_strSystemPrompt = _T("");
102 | m_Edit_SystemPrompt.SetWindowText(_T(""));
103 | UpdateData(FALSE);
104 | }
105 | else
106 | {
107 | LoadPrompts(prompt_name);
108 | }
109 |
110 | }
111 |
112 |
113 | void NewChatDlg::OnBnClickedOk()
114 | {
115 | // TODO: 在此添加控件通知处理程序代码
116 | UpdateData(TRUE);
117 |
118 | if (m_strChatName.IsEmpty())
119 | {
120 | MessageBox(TEXT("请输入对话名称!"), TEXT("错误"), MB_ICONERROR);
121 | return;
122 | }
123 |
124 | if (m_strUserName.IsEmpty())
125 | {
126 | MessageBox(TEXT("请输入用户名称!"), TEXT("错误"), MB_ICONERROR);
127 | return;
128 | }
129 |
130 | if (m_strAIName.IsEmpty())
131 | {
132 | MessageBox(TEXT("请输入AI名称!"), TEXT("错误"), MB_ICONERROR);
133 | return;
134 | }
135 |
136 | // 将系统提示赋值给m_strSystemPrompt
137 | m_Edit_SystemPrompt.GetWindowText(m_strSystemPrompt);
138 |
139 | // 重置聊天上下文
140 | chatContext->removeAllActors();
141 | chatContext->resetChatHistory();
142 |
143 | // 添加演员
144 | chatContext->addActor(ConvertCStringToUtf8(m_strUserName), "user", "blue", "", chatContext->getUserIcon());
145 | chatContext->addActor(ConvertCStringToUtf8(m_strAIName), "assistant", "pink", "", chatContext->getAssistantIcon());
146 | chatContext->setUserAndAssistantName(ConvertCStringToUtf8(m_strUserName), ConvertCStringToUtf8(m_strAIName));
147 |
148 |
149 | // 设置系统提示
150 | chatContext->setupSystemPrompt(ConvertCStringToUtf8(m_strSystemPrompt));
151 | //chatContext->using_system_prompt = true;
152 |
153 | CDialogEx::OnOK();
154 | }
155 |
156 |
157 | void NewChatDlg::OnBnClickedCancel()
158 | {
159 | // TODO: 在此添加控件通知处理程序代码
160 |
161 | CDialogEx::OnCancel();
162 | }
163 |
--------------------------------------------------------------------------------
/src/AIChatBox/AIChatBox/NewChatDlg.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include "afxdialogex.h"
3 | #include "chat.h"
4 |
5 | // NewChatDlg 对话框
6 |
7 | class NewChatDlg : public CDialogEx
8 | {
9 | DECLARE_DYNAMIC(NewChatDlg)
10 |
11 | public:
12 | NewChatDlg(CWnd* pParent = nullptr); // 标准构造函数
13 | virtual ~NewChatDlg();
14 |
15 | // 对话框数据
16 | #ifdef AFX_DESIGN_TIME
17 | enum { IDD = IDD_NEWCHAT_DIALOG };
18 | #endif
19 |
20 | protected:
21 | virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持
22 |
23 | DECLARE_MESSAGE_MAP()
24 | public:
25 |
26 | Chat* chatContext;
27 |
28 | CString m_strChatName;
29 | CComboBox m_ComboBox_LoadPrompt;
30 | CString m_strUserName;
31 | CString m_strAIName;
32 | CString m_strSystemPrompt;
33 | std::string m_userIcon;
34 | std::string m_AIIcon;
35 | virtual BOOL OnInitDialog();
36 |
37 | std::vector m_Prompts;
38 | void LoadPrompts(CString prompt_name);
39 | afx_msg void OnCbnSelchangeComboSelectPrompt();
40 | CEdit m_Edit_SystemPrompt;
41 | afx_msg void OnBnClickedOk();
42 | afx_msg void OnBnClickedCancel();
43 | };
44 |
--------------------------------------------------------------------------------
/src/AIChatBox/AIChatBox/PromptDlg.cpp:
--------------------------------------------------------------------------------
1 | // PromptDlg.cpp: 实现文件
2 | //
3 |
4 | #include "pch.h"
5 | #include "AIChatBox.h"
6 | #include "afxdialogex.h"
7 | #include "PromptDlg.h"
8 |
9 |
10 | // PromptDlg 对话框
11 |
12 | IMPLEMENT_DYNAMIC(PromptDlg, CDialogEx)
13 |
14 | PromptDlg::PromptDlg(CWnd* pParent /*=nullptr*/)
15 | : CDialogEx(IDD_PROMPT_DIALOG, pParent)
16 | {
17 |
18 | }
19 |
20 | PromptDlg::~PromptDlg()
21 | {
22 | }
23 |
24 | void PromptDlg::DoDataExchange(CDataExchange* pDX)
25 | {
26 | CDialogEx::DoDataExchange(pDX);
27 | DDX_Control(pDX, IDC_EDIT1, m_Edit_Prompt);
28 | }
29 |
30 |
31 | BEGIN_MESSAGE_MAP(PromptDlg, CDialogEx)
32 | ON_BN_CLICKED(IDOK, &PromptDlg::OnBnClickedOk)
33 | END_MESSAGE_MAP()
34 |
35 |
36 | // PromptDlg 消息处理程序
37 |
38 |
39 | BOOL PromptDlg::OnInitDialog()
40 | {
41 | CDialogEx::OnInitDialog();
42 |
43 | // TODO: 在此添加额外的初始化
44 |
45 | // Edit上的提示文字
46 | m_Edit_Prompt.SetWindowText(m_strPrompt);
47 |
48 | return TRUE; // return TRUE unless you set the focus to a control
49 | // 异常: OCX 属性页应返回 FALSE
50 | }
51 |
52 |
53 | void PromptDlg::OnBnClickedOk()
54 | {
55 | // TODO: 在此添加控件通知处理程序代码
56 |
57 | // 获取用户输入
58 | m_Edit_Prompt.GetWindowText(m_strPrompt);
59 |
60 | // 检测是否为空
61 | if (m_strPrompt.IsEmpty())
62 | {
63 | MessageBox(TEXT("您的输入为空!"), TEXT("Error"), MB_ICONERROR);
64 | return;
65 | }
66 |
67 | // 关闭对话框
68 | CDialogEx::OnOK();
69 | }
70 |
--------------------------------------------------------------------------------
/src/AIChatBox/AIChatBox/PromptDlg.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include "afxdialogex.h"
3 |
4 |
5 | // PromptDlg 对话框
6 |
7 | class PromptDlg : public CDialogEx
8 | {
9 | DECLARE_DYNAMIC(PromptDlg)
10 |
11 | public:
12 | PromptDlg(CWnd* pParent = nullptr); // 标准构造函数
13 | virtual ~PromptDlg();
14 |
15 | // 对话框数据
16 | #ifdef AFX_DESIGN_TIME
17 | enum { IDD = IDD_PROMPT_DIALOG };
18 | #endif
19 |
20 | protected:
21 | virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持
22 |
23 | DECLARE_MESSAGE_MAP()
24 | public:
25 | virtual BOOL OnInitDialog();
26 | CEdit m_Edit_Prompt;
27 | CString m_strPrompt;
28 | afx_msg void OnBnClickedOk();
29 | };
30 |
--------------------------------------------------------------------------------
/src/AIChatBox/AIChatBox/RenameDlg.cpp:
--------------------------------------------------------------------------------
1 | // RenameDlg.cpp: 实现文件
2 | //
3 |
4 | #include "pch.h"
5 | #include "AIChatBox.h"
6 | #include "afxdialogex.h"
7 | #include "RenameDlg.h"
8 |
9 |
10 | // RenameDlg 对话框
11 |
12 | IMPLEMENT_DYNAMIC(RenameDlg, CDialogEx)
13 |
14 | RenameDlg::RenameDlg(CWnd* pParent /*=nullptr*/)
15 | : CDialogEx(IDD_RENAME_DIALOG, pParent)
16 | , m_name(_T(""))
17 | {
18 |
19 | }
20 |
21 | RenameDlg::~RenameDlg()
22 | {
23 | }
24 |
25 | void RenameDlg::DoDataExchange(CDataExchange* pDX)
26 | {
27 | CDialogEx::DoDataExchange(pDX);
28 | DDX_Text(pDX, IDC_EDIT1, m_name);
29 | }
30 |
31 |
32 | BEGIN_MESSAGE_MAP(RenameDlg, CDialogEx)
33 | ON_BN_CLICKED(IDOK, &RenameDlg::OnBnClickedOk)
34 | END_MESSAGE_MAP()
35 |
36 |
37 | // RenameDlg 消息处理程序
38 |
39 |
40 | void RenameDlg::OnBnClickedOk()
41 | {
42 | // TODO: 在此添加控件通知处理程序代码
43 |
44 | if (m_name.IsEmpty())
45 | {
46 | MessageBox(TEXT("请输入名称!"), TEXT("错误"), MB_ICONERROR);
47 | return;
48 | }
49 |
50 | CDialogEx::OnOK();
51 | }
52 |
--------------------------------------------------------------------------------
/src/AIChatBox/AIChatBox/RenameDlg.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include "afxdialogex.h"
3 |
4 |
5 | // RenameDlg 对话框
6 |
7 | class RenameDlg : public CDialogEx
8 | {
9 | DECLARE_DYNAMIC(RenameDlg)
10 |
11 | public:
12 | RenameDlg(CWnd* pParent = nullptr); // 标准构造函数
13 | virtual ~RenameDlg();
14 |
15 | // 对话框数据
16 | #ifdef AFX_DESIGN_TIME
17 | enum { IDD = IDD_RENAME_DIALOG };
18 | #endif
19 |
20 | protected:
21 | virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持
22 |
23 | DECLARE_MESSAGE_MAP()
24 | public:
25 | CString m_name;
26 | afx_msg void OnBnClickedOk();
27 | };
28 |
--------------------------------------------------------------------------------
/src/AIChatBox/AIChatBox/SettingDlg.cpp:
--------------------------------------------------------------------------------
1 | // SettingDlg.cpp: 实现文件
2 | //
3 |
4 | #include "pch.h"
5 | #include "AIChatBox.h"
6 | #include "afxdialogex.h"
7 | #include "SettingDlg.h"
8 |
9 |
10 | // SettingDlg 对话框
11 |
12 | IMPLEMENT_DYNAMIC(SettingDlg, CDialogEx)
13 |
14 | SettingDlg::SettingDlg(CWnd* pParent /*=nullptr*/)
15 | : CDialogEx(IDD_SETTING_DIALOG, pParent)
16 | , m_nPort(8080)
17 | , m_strModelPath(_T(""))
18 | , m_isBold(FALSE)
19 | , m_isItalic(FALSE)
20 | , m_strHistory(_T(""))
21 | {
22 |
23 | }
24 |
25 | SettingDlg::~SettingDlg()
26 | {
27 | }
28 |
29 | void SettingDlg::DoDataExchange(CDataExchange* pDX)
30 | {
31 | CDialogEx::DoDataExchange(pDX);
32 | DDX_Text(pDX, IDC_EDIT_PORT, m_nPort);
33 | DDX_Text(pDX, IDC_EDIT_MODEL_PATH, m_strModelPath);
34 | DDX_Control(pDX, IDC_COMBO_SELECT_MODEL, m_ComboBox_Models);
35 | DDX_Control(pDX, IDC_MFCCOLORBUTTON1, m_ColorBtn_Background);
36 | DDX_Control(pDX, IDC_MFCCOLORBUTTON2, m_ColorBtn_Text);
37 | DDX_Control(pDX, IDC_MFCCOLORBUTTON3, m_ColorBtn_User);
38 | DDX_Control(pDX, IDC_MFCCOLORBUTTON4, m_ColorBtn_Assistant);
39 | DDX_Control(pDX, IDC_MFCFONTCOMBO1, m_FontComboBox);
40 | DDX_Control(pDX, IDC_COMBO_FONT_SIZE, m_ComboBox_FontSize);
41 | DDX_Check(pDX, IDC_CHECK_BOLD, m_isBold);
42 | DDX_Check(pDX, IDC_CHECK_ITALIC, m_isItalic);
43 | DDX_Control(pDX, IDC_IPADDRESS1, m_IPAddressCtrl);
44 | DDX_Text(pDX, IDC_EDIT_HISTORY_PATH, m_strHistory);
45 | }
46 |
47 |
48 | BEGIN_MESSAGE_MAP(SettingDlg, CDialogEx)
49 | ON_BN_CLICKED(IDC_BUTTON_SELECT_PATH, &SettingDlg::OnBnClickedButtonSelectPath)
50 | ON_BN_CLICKED(IDC_BUTTON_START_SERVER, &SettingDlg::OnBnClickedButtonStartServer)
51 | ON_BN_CLICKED(IDC_BUTTON_STOP_SERVER, &SettingDlg::OnBnClickedButtonStopServer)
52 | ON_BN_CLICKED(IDC_BUTTON_HISTORY_PATH, &SettingDlg::OnBnClickedButtonHistoryPath)
53 | ON_WM_CLOSE()
54 | END_MESSAGE_MAP()
55 |
56 |
57 | // SettingDlg 消息处理程序
58 |
59 |
60 | BOOL SettingDlg::OnInitDialog()
61 | {
62 | CDialogEx::OnInitDialog();
63 |
64 | // TODO: 在此添加额外的初始化
65 |
66 | // 默认当前路径下的models文件夹
67 | // m_ModelPath = _T(".\\models");
68 |
69 | // 将文件夹下的模型文件添加到下拉框
70 | if (AddModelsToComboBox())
71 | {
72 | if (m_strModel.IsEmpty())
73 | {
74 | // 默认选择第一个模型
75 | m_ComboBox_Models.SetCurSel(0);
76 | }
77 | else
78 | {
79 | // 根据m_strModel设置下拉框的选择
80 | int index = m_ComboBox_Models.FindStringExact(0, m_strModel);
81 | if (index != CB_ERR)
82 | {
83 | m_ComboBox_Models.SetCurSel(index);
84 | }
85 | else
86 | {
87 | // 默认选择第一个模型
88 | m_ComboBox_Models.SetCurSel(0);
89 | }
90 | }
91 | }
92 |
93 |
94 | // 设置IP和端口
95 | m_IPAddressCtrl.SetAddress(127, 0, 0, 1);
96 | // m_nPort = 8080;
97 |
98 | // 设置字体
99 | m_FontComboBox.SelectFont(_T("Segoe UI Emoji"));
100 |
101 | // 设置字体大小
102 | m_ComboBox_FontSize.AddString(_T("1"));
103 | m_ComboBox_FontSize.AddString(_T("2"));
104 | m_ComboBox_FontSize.AddString(_T("3"));
105 | m_ComboBox_FontSize.AddString(_T("4"));
106 | m_ComboBox_FontSize.AddString(_T("5"));
107 | // 选择第二个字体大小
108 | m_ComboBox_FontSize.SetCurSel(m_nFontSize - 1);
109 |
110 | // 设置背景颜色
111 | m_ColorBtn_Background.SetColor(m_clrBackground);
112 | // 设置文本颜色
113 | m_ColorBtn_Text.SetColor(m_clrText);
114 | // 设置用户颜色
115 | m_ColorBtn_User.SetColor(m_clrUser);
116 | // 设置助手颜色
117 | m_ColorBtn_Assistant.SetColor(m_clrAssistant);
118 |
119 | UpdateData(FALSE);
120 |
121 | return TRUE; // return TRUE unless you set the focus to a control
122 | // 异常: OCX 属性页应返回 FALSE
123 | }
124 |
125 |
126 | void SettingDlg::OnBnClickedButtonSelectPath()
127 | {
128 | // TODO: 在此添加控件通知处理程序代码
129 |
130 | // 弹出文件夹选择对话框
131 | BROWSEINFO bi;
132 | ZeroMemory(&bi, sizeof(BROWSEINFO));
133 | bi.hwndOwner = this->m_hWnd;
134 | bi.pszDisplayName = NULL;
135 | bi.lpszTitle = _T("请选择模型文件夹");
136 | bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_NEWDIALOGSTYLE;
137 | LPITEMIDLIST idl = SHBrowseForFolder(&bi);
138 | if (idl != NULL)
139 | {
140 | TCHAR path[MAX_PATH];
141 | SHGetPathFromIDList(idl, path);
142 | m_strModelPath = path;
143 | SetDlgItemText(IDC_EDIT_MODEL_PATH, path);
144 | }
145 | else
146 | {
147 | m_strModelPath = _T("");
148 | }
149 |
150 | // 将文件夹下的模型文件添加到下拉框
151 | if (AddModelsToComboBox())
152 | {
153 | // 默认选择第一个模型
154 | m_ComboBox_Models.SetCurSel(0);
155 | }
156 | }
157 |
158 | BOOL SettingDlg::AddModelsToComboBox()
159 | {
160 | // 获取文件夹下的模型文件
161 | std::vector models;
162 | std::string folderPath = CT2A(m_strModelPath);
163 | if (folderPath.empty())
164 | {
165 | MessageBox(TEXT("请选择有效的文件夹!"), TEXT("错误"), MB_ICONERROR);
166 | return false;
167 | }
168 |
169 | // 获取文件夹下的所有文件
170 | std::vector files = getFilesInFolder(folderPath);
171 | for (const std::string& file : files)
172 | {
173 | if (file.find(".gguf") != std::string::npos)
174 | {
175 | models.push_back(file);
176 | }
177 | }
178 |
179 | // 如果没有模型文件
180 | if (models.empty())
181 | {
182 | MessageBox(TEXT("文件夹下没有模型文件!"), TEXT("错误"), MB_ICONERROR);
183 | m_strModelPath = _T("");
184 | return false;
185 | }
186 |
187 | // 将模型文件添加到下拉框
188 | m_ComboBox_Models.ResetContent();
189 | for (const std::string& model : models)
190 | {
191 | CString cstr(model.c_str());
192 | m_ComboBox_Models.AddString(cstr);
193 | }
194 |
195 | return true;
196 | }
197 |
198 |
199 |
200 | void SettingDlg::OnBnClickedButtonStartServer()
201 | {
202 | // TODO: 在此添加控件通知处理程序代码
203 |
204 | UpdateData(TRUE);
205 |
206 | // 查看端口号是否合法
207 | if (m_nPort < 1024 || m_nPort > 65535)
208 | {
209 | MessageBox(TEXT("端口号应在1024-65535之间!"), TEXT("错误"), MB_ICONERROR);
210 | return;
211 | }
212 |
213 | // 先查看端口是否被占用
214 | if (!IsPortAvailable(m_nPort))
215 | {
216 | CString str;
217 | str.Format(TEXT("端口 %d 已被占用,请更换端口号"), m_nPort);
218 | MessageBox(str, L"错误", MB_ICONERROR);
219 | return;
220 | }
221 |
222 | // 查看m_strModelPath是否为空
223 | if (m_strModelPath.IsEmpty())
224 | {
225 | MessageBox(TEXT("请选择模型文件夹!"), TEXT("错误"), MB_ICONERROR);
226 | return;
227 | }
228 |
229 | // 获取选择的模型
230 | int index = m_ComboBox_Models.GetCurSel();
231 | m_ComboBox_Models.GetLBText(index, m_strModel);
232 |
233 | // 查看选择的模型
234 | if (m_strModel.IsEmpty())
235 | {
236 | MessageBox(TEXT("请选择模型文件!"), TEXT("错误"), MB_ICONERROR);
237 | return;
238 | }
239 |
240 | // 获取字体大小
241 | m_nFontSize = m_ComboBox_FontSize.GetCurSel() + 1;
242 |
243 | // 获取字体
244 | m_FontComboBox.GetLBText(m_FontComboBox.GetCurSel(), m_strFont);
245 |
246 | // 获取背景颜色
247 | m_clrBackground = m_ColorBtn_Background.GetColor();
248 |
249 | // 获取文本颜色
250 | m_clrText = m_ColorBtn_Text.GetColor();
251 |
252 | // 获取用户颜色
253 | m_clrUser = m_ColorBtn_User.GetColor();
254 |
255 | // 获取助手颜色
256 | m_clrAssistant = m_ColorBtn_Assistant.GetColor();
257 |
258 | OnOK();
259 | }
260 |
261 |
262 | void SettingDlg::OnBnClickedButtonStopServer()
263 | {
264 | // TODO: 在此添加控件通知处理程序代码
265 |
266 | if (isFirstOpen)
267 | {
268 | exit(0);
269 | }
270 |
271 | OnCancel();
272 | }
273 |
274 |
275 |
276 | void SettingDlg::OnBnClickedButtonHistoryPath()
277 | {
278 | // TODO: 在此添加控件通知处理程序代码
279 | // 弹出文件夹选择对话框
280 | BROWSEINFO bi;
281 | ZeroMemory(&bi, sizeof(BROWSEINFO));
282 | bi.hwndOwner = this->m_hWnd;
283 | bi.pszDisplayName = NULL;
284 | bi.lpszTitle = _T("请选择历史记录文件夹");
285 | bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_NEWDIALOGSTYLE;
286 | LPITEMIDLIST idl = SHBrowseForFolder(&bi);
287 | if (idl != NULL)
288 | {
289 | TCHAR path[MAX_PATH];
290 | SHGetPathFromIDList(idl, path);
291 | // 将IDC_EDIT_HISTORY_PATH编辑框的内容设置为path
292 | m_strHistory = path;
293 | SetDlgItemText(IDC_EDIT_HISTORY_PATH, path);
294 | }
295 | }
296 |
297 |
298 | void SettingDlg::OnClose()
299 | {
300 | // TODO: 在此添加消息处理程序代码和/或调用默认值
301 |
302 | if (isFirstOpen)
303 | {
304 | exit(0);
305 | }
306 |
307 | CDialogEx::OnClose();
308 | }
309 |
--------------------------------------------------------------------------------
/src/AIChatBox/AIChatBox/SettingDlg.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include "afxdialogex.h"
3 |
4 | #include "utils.h"
5 |
6 | // SettingDlg 对话框
7 |
8 | class SettingDlg : public CDialogEx
9 | {
10 | DECLARE_DYNAMIC(SettingDlg)
11 |
12 | public:
13 | SettingDlg(CWnd* pParent = nullptr); // 标准构造函数
14 | virtual ~SettingDlg();
15 |
16 | // 对话框数据
17 | #ifdef AFX_DESIGN_TIME
18 | enum { IDD = IDD_SETTING_DIALOG };
19 | #endif
20 |
21 | protected:
22 | virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持
23 |
24 | DECLARE_MESSAGE_MAP()
25 | public:
26 |
27 | CString m_strModelPath; // 模型文件夹路径
28 | int m_nPort; // 端口号
29 | CString m_strModel; // 模型文件名
30 | CString m_strFont; // 字体
31 | int m_nFontSize; // 字体大小
32 | COLORREF m_clrBackground; // 背景颜色
33 | COLORREF m_clrText; // 文本颜色
34 | COLORREF m_clrUser; // 用户颜色
35 | COLORREF m_clrAssistant; // 助手颜色
36 | BOOL m_isBold; // 是否加粗
37 | BOOL m_isItalic; // 是否斜体
38 |
39 |
40 | virtual BOOL OnInitDialog();
41 | CComboBox m_ComboBox_Models;
42 | CMFCColorButton m_ColorBtn_Background;
43 | CMFCColorButton m_ColorBtn_Text;
44 | CMFCColorButton m_ColorBtn_User;
45 | CMFCColorButton m_ColorBtn_Assistant;
46 | CMFCFontComboBox m_FontComboBox;
47 | CComboBox m_ComboBox_FontSize;
48 | CIPAddressCtrl m_IPAddressCtrl;
49 | afx_msg void OnBnClickedButtonSelectPath();
50 |
51 | // 将文件夹下的模型文件添加到下拉框
52 | BOOL AddModelsToComboBox();
53 |
54 | afx_msg void OnBnClickedButtonStartServer();
55 | afx_msg void OnBnClickedButtonStopServer();
56 | CString m_strHistory;
57 | afx_msg void OnBnClickedButtonHistoryPath();
58 | afx_msg void OnClose();
59 |
60 | bool isFirstOpen;
61 | };
62 |
--------------------------------------------------------------------------------
/src/AIChatBox/AIChatBox/chat.cpp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mouseminar/MFC-AIChatBox/f0a73c2b07f5a4cb6b499b851d02d3f175890f40/src/AIChatBox/AIChatBox/chat.cpp
--------------------------------------------------------------------------------
/src/AIChatBox/AIChatBox/chat.h:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mouseminar/MFC-AIChatBox/f0a73c2b07f5a4cb6b499b851d02d3f175890f40/src/AIChatBox/AIChatBox/chat.h
--------------------------------------------------------------------------------
/src/AIChatBox/AIChatBox/completion.cpp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mouseminar/MFC-AIChatBox/f0a73c2b07f5a4cb6b499b851d02d3f175890f40/src/AIChatBox/AIChatBox/completion.cpp
--------------------------------------------------------------------------------
/src/AIChatBox/AIChatBox/completion.h:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mouseminar/MFC-AIChatBox/f0a73c2b07f5a4cb6b499b851d02d3f175890f40/src/AIChatBox/AIChatBox/completion.h
--------------------------------------------------------------------------------
/src/AIChatBox/AIChatBox/config/params.json:
--------------------------------------------------------------------------------
1 | ///////////////////////////////////////////
2 | // All profiles related to model parameters
3 | // Usage: https://github.com/ggerganov/llama.cpp/tree/master/examples/server
4 | ///////////////////////////////////////////
5 | {
6 | "params_profiles":{
7 | "creative": {
8 | "mirostat": 0,
9 | "mirostat_tau": 5,
10 | "mirostat_eta": 0.1,
11 | "frecuency_penalty": 0,
12 | "top_k": 40,
13 | "top_p": 0.5,
14 | "stop":["","<|end|>","<|eot_id|>","<|end_of_text|>","<|im_end|>","<|EOT|>","<|END_OF_TURN_TOKEN|>","<|end_of_turn|>","<|endoftext|>"],
15 | "typical_p": 1,
16 | "tfz_z": 1,
17 | "n_probs":0,
18 | "presence_penalty":0,
19 | "repeat_last_n": 256,
20 | "repeat_penalty": 1.18,
21 | "temperature": 0.7,
22 | "n_predict": 250,
23 | "stream": true,
24 | "slot_id":0
25 | },
26 | "creative_oai": {
27 | "stream": true,
28 | "temperature": 0.8,
29 | "dynatemp_range": 0,
30 | "dynatemp_exponent": 1,
31 | "top_k": 40,
32 | "top_p": 0.95,
33 | "min_p": 0.05,
34 | "typical_p": 1,
35 | "xtc_probability": 0,
36 | "xtc_threshold": 0.1,
37 | "repeat_last_n": 64,
38 | "repeat_penalty": 1,
39 | "stop":["","<|end|>","<|eot_id|>","<|end_of_text|>","<|im_end|>","<|EOT|>","<|END_OF_TURN_TOKEN|>","<|end_of_turn|>","<|endoftext|>"],
40 | "presence_penalty": 0,
41 | "frequency_penalty": 0,
42 | "dry_multiplier": 0,
43 | "dry_base": 1.75,
44 | "dry_allowed_length": 2,
45 | "dry_penalty_last_n": -1,
46 | "max_tokens": -1
47 | },
48 | "precision": {
49 | "frecuency_penalty": 0,
50 | "top_k": 40,
51 | "top_p": 0.2,
52 | "stop":["", "<|"],
53 | "n_probs":0,
54 | "repeat_penalty": 1.18,
55 | "temperature": 0.0,
56 | "n_predict": 250,
57 | "stream": true,
58 | "slot_id":0
59 | },
60 | "without_stream": {
61 | "mirostat": 2,
62 | "mirostat_tau": 5,
63 | "mirostat_eta": 0.1,
64 | "frecuency_penalty": 0,
65 | "top_k": 40,
66 | "top_p": 0.5,
67 | "typical_p": 1,
68 | "tfz_z": 1,
69 | "seed":3443,
70 | "repeat_last_n": 256,
71 | "repeat_penalty": 1.18,
72 | "temperature": 0.8,
73 | "n_predict": 100,
74 | "stream": false
75 | }
76 | }
77 | }
--------------------------------------------------------------------------------
/src/AIChatBox/AIChatBox/config/prompts.json:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////
2 | // User prompts.
3 | /*
4 | profile_name:
5 | system: system prompt (Optional)
6 | actors: conversation actors (Optional)
7 | -> name (required)
8 | -> color (optional)
9 | -> msg_preffix : a hidden permanent message suffix, ex: *looking the camera* or "Sure thing!" to suggest the model.(optional)
10 | -> icon: just a decoration for chat tag
11 | */
12 | ////////////////////////////////////
13 | {
14 | "AI助手":{
15 | "system":"你是一个智能助手,专门为用户提供帮助。你的任务是回答用户的问题,提供信息和建议。你的回答应该简洁、直接,保持礼貌和友好的语气。",
16 | "actors":[
17 | {"name":"用户","role":"user","color":"green", "icon":"👦"},
18 | {"name":"AI助手","role":"assistant","color":"pink", "icon":"👩"}
19 | ]
20 | },
21 | "程序员":{
22 | "system":"你是一个程序员,你的任务是帮助用户解决问题,提供技术支持。你的回答应该简洁、直接,保持礼貌和友好的语气。",
23 | "actors":[
24 | {"name":"用户","role":"user","color":"green", "icon":"👦"},
25 | {"name":"程序员","role":"assistant","color":"pink", "icon":"👨"}
26 | ]
27 | },
28 | "医生":{
29 | "system":"你是一名医生,你的任务是帮助用户解决健康问题,提供医疗建议。你的回答应该简洁、直接,保持礼貌和友好的语气。",
30 | "actors":[
31 | {"name":"病人","role":"user","color":"green", "icon":"👦"},
32 | {"name":"医生","role":"assistant","color":"pink", "icon":"👩"}
33 | ]
34 | },
35 | "老师":{
36 | "system":"你是一名老师,你的任务是帮助用户解决学习问题,提供教育建议。你的回答应该简洁、直接,保持礼貌和友好的语气。",
37 | "actors":[
38 | {"name":"学生","role":"user","color":"green", "icon":"👦"},
39 | {"name":"老师","role":"assistant","color":"pink", "icon":"👩"}
40 | ]
41 | },
42 | "猫娘": {
43 | "system": "你是一个猫娘,你的任务是服侍主人,听主人的吩咐,回答主人的问题,提供信息和建议。回答中要多出现“喵”和颜文字。",
44 | "actors": [
45 | {"name": "主人", "role": "user", "color": "green", "icon": "👦"},
46 | {"name": "猫娘", "role": "assistant", "color": "pink", "icon": "🐱"}
47 | ]
48 | },
49 | "仆人":{
50 | "system":"你是一个仆人,你的任务是服侍主人,听主人的吩咐,回答主人的问题,提供信息和建议。回答中要多出现“是的,主人”和“我会的”等词语。",
51 | "actors":[
52 | {"name":"主人","role":"user","color":"green", "icon":"👦"},
53 | {"name":"仆人","role":"assistant","color":"pink", "icon":"👨"}
54 | ]
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/src/AIChatBox/AIChatBox/config/templates.json:
--------------------------------------------------------------------------------
1 | ///////////////////////////////////////////
2 | // All chat templates
3 | /*
4 | SEQ: Header and Footer for determinated roles. (optionals)
5 | B_SYS and E_SYS: System
6 | B_USER and E_USER: User
7 | B_ASSISTANT and E_ASSISTANT: Assistant
8 | EOS: End of text
9 | */
10 | ///////////////////////////////////////////
11 | {
12 | "chat_templates":{
13 | "empty":
14 | {
15 | "SEQ":{
16 | "E_SYS": "\n",
17 | "E_USER": "\n",
18 | "EOS": "\n"
19 | }
20 | },
21 | "chatml":
22 | {
23 | "SEQ":{
24 | "B_SYS": "<|im_start|>system\n",
25 | "E_SYS": "<|im_end|>\n",
26 | "B_USER": "<|im_start|>user\n",
27 | "E_USER": "<|im_end|>\n",
28 | "B_ASSISTANT": "<|im_start|>assistant\n",
29 | "EOS": "<|im_end|>\n"
30 | }
31 | },
32 | "stablelm":
33 | {
34 | "SEQ":{
35 | "B_USER": "<|user|>\n",
36 | "E_USER": "<|endoftext|>\n",
37 | "B_ASSISTANT": "<|assistant|>\n",
38 | "EOS": "<|endoftext|>\n"
39 | }
40 | },
41 | "mistral_v0.2":
42 | {
43 | "SEQ":{
44 | "BOS": "",
45 | "B_USER": "[INST]",
46 | "E_USER": "[/INST]",
47 | "B_ASSISTANT": "",
48 | "EOS": ""
49 | }
50 | },
51 | "mistral_v0.2_chat":
52 | {
53 | "SEQ":{
54 | "BOS": "",
55 | "B_USER": "[INST]",
56 | "E_USER": "[/INST]",
57 | "B_ASSISTANT": "",
58 | "EOS": ""
59 | }
60 | },
61 | "tinyllama":
62 | {
63 | "SEQ":{
64 | "B_SYS": "<|system|>\n",
65 | "E_SYS": "\n",
66 | "B_USER": "<|user|>\n",
67 | "E_USER": "\n",
68 | "B_ASSISTANT": "<|assistant|>\n",
69 | }
70 | },
71 | "tinyllama2":
72 | {
73 | "SEQ":{
74 | "B_SYS": "<|system|>\n",
75 | "E_SYS": "\n",
76 | "B_USER": "<|user|>\n",
77 | "E_USER": "\n",
78 | "B_ASSISTANT": "<|assistant|>\n",
79 | }
80 | },
81 | "phi3":
82 | {
83 | "SEQ":{
84 | "B_USER": "<|user|>\n",
85 | "E_USER": "<|end|>\n",
86 | "B_ASSISTANT": "<|assistant|>\n",
87 | }
88 | },
89 | "zephyr":
90 | {
91 | "SEQ":{
92 | "B_SYS": "<|system|>\n",
93 | "E_SYS": "<|endoftext|>\n",
94 | "B_USER": "<|user|>\n",
95 | "E_USER": "<|endoftext|>\n",
96 | "B_ASSISTANT": "<|assistant|>\n",
97 | "E_ASSISTANT": "<|endoftext|>\n"
98 | }
99 | },
100 | "gemma2b":{
101 | "SEQ":{
102 | "BOS":"",
103 | "B_USER":"",
104 | "E_USER":"",
105 | "B_ASSISTANT":"model"
106 | }
107 | },
108 | "llama3.2":{
109 | "SEQ":{
110 | "B_SYS": "<|start_header_id|>system<|end_header_id|>\n\n",
111 | "E_SYS": "\n",
112 | "B_USER": "<|start_header_id|>user<|end_header_id|>\n",
113 | "E_USER": "<|eot_id|>",
114 | "B_ASSISTANT": "<|start_header_id|>assistant<|end_header_id|>\n",
115 | "E_ASSISTANT": "<|eot_id|>\n"
116 |
117 | }
118 | },
119 | "phi3.5":{
120 | "SEQ":{
121 | "B_SYS":"<|im_start|>",
122 | "E_SYS":"<|im_end|>",
123 | "B_USER":"<|im_start|>user",
124 | "E_USER":"<|im_end|>",
125 | "B_ASSISTANT":"<|im_start|>assistant",
126 | "E_ASSISTANT":"<|im_end|>",
127 | }
128 | }
129 | }
130 | }
--------------------------------------------------------------------------------
/src/AIChatBox/AIChatBox/framework.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #ifndef VC_EXTRALEAN
4 | #define VC_EXTRALEAN // 从 Windows 头中排除极少使用的资料
5 | #endif
6 |
7 | #include "targetver.h"
8 |
9 | #define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // 某些 CString 构造函数将是显式的
10 |
11 | // 关闭 MFC 的一些常见且经常可放心忽略的隐藏警告消息
12 | #define _AFX_ALL_WARNINGS
13 |
14 | #include // MFC 核心组件和标准组件
15 | #include // MFC 扩展
16 |
17 |
18 | #include // MFC 自动化类
19 |
20 |
21 |
22 | #ifndef _AFX_NO_OLE_SUPPORT
23 | #include // MFC 对 Internet Explorer 4 公共控件的支持
24 | #endif
25 | #ifndef _AFX_NO_AFXCMN_SUPPORT
26 | #include // MFC 对 Windows 公共控件的支持
27 | #endif // _AFX_NO_AFXCMN_SUPPORT
28 |
29 | #include // MFC 支持功能区和控制条
30 |
31 |
32 | #include // MFC 套接字扩展
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 | #ifdef _UNICODE
41 | #if defined _M_IX86
42 | #pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='x86' publicKeyToken='6595b64144ccf1df' language='*'\"")
43 | #elif defined _M_X64
44 | #pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='amd64' publicKeyToken='6595b64144ccf1df' language='*'\"")
45 | #else
46 | #pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
47 | #endif
48 | #endif
49 |
50 |
51 |
--------------------------------------------------------------------------------
/src/AIChatBox/AIChatBox/history/2025-01-31-22-36-46.json:
--------------------------------------------------------------------------------
1 | {
2 | "history": [
3 | {
4 | "id": 1738334213,
5 | "name": "System",
6 | "role": "system",
7 | "content": "你是一个程序员,你的任务是帮助用户解决问题,提供技术支持。你的回答应该简洁、直接,保持礼貌和友好的语气。\r\n"
8 | },
9 | {
10 | "id": 1738334222,
11 | "name": "用户",
12 | "role": "user",
13 | "content": "用C语言写一个冒泡排序"
14 | },
15 | {
16 | "id": 1738334244,
17 | "name": "程序员",
18 | "role": "assistant",
19 | "content": "当然可以!以下是用C语言实现的冒泡排序算法:\n\n```c\n#include \n\nvoid bubbleSort(int arr[], int n) {\n int i, j, temp;\n for (i = 0; i < n-1; i++) {\n for (j = 0; j < n-i-1; j++) {\n if (arr[j] > arr[j+1]) {\n // 交换 arr[j] 和 arr[j+1]\n temp = arr[j];\n arr[j] = arr[j+1];\n arr[j+1] = temp;\n }\n }\n }\n}\n\nvoid printArray(int arr[], int size) {\n int i;\n for (i = 0; i < size; i++)\n printf(\"%d \", arr[i]);\n printf(\"\\n\");\n}\n\nint main() {\n int arr[] = {64, 34, 25, 12, 22, 11, 90};\n int n = sizeof(arr)/sizeof(arr[0]);\n printf(\"原始数组: \");\n printArray(arr, n);\n \n bubbleSort(arr, n);\n printf(\"排序后的数组: \");\n printArray(arr, n);\n return 0;\n}\n```\n\n这个程序首先定义了两个循环来实现冒泡排序。外层循环控制排序的轮数,内层循环用于相邻元素之间的比较和交换。同时,有打印函数来打印数组,以便验证排序是否正确。在 main 函数中,定义了一个整数数组,并调用 `bubbleSort` 函数对数组进行排序。最后,使用 `printArray` 函数打印排序前和排序后的数组。"
20 | }
21 | ],
22 | "actors": [
23 | {
24 | "name": "System",
25 | "role": "system",
26 | "color": "green_ul",
27 | "msg_preffix": "",
28 | "icon": ""
29 | },
30 | {
31 | "name": "用户",
32 | "role": "user",
33 | "color": "blue",
34 | "msg_preffix": "",
35 | "icon": "👦"
36 | },
37 | {
38 | "name": "程序员",
39 | "role": "assistant",
40 | "color": "pink",
41 | "msg_preffix": "",
42 | "icon": "👨"
43 | }
44 | ]
45 | }
--------------------------------------------------------------------------------
/src/AIChatBox/AIChatBox/history/AI助手.json:
--------------------------------------------------------------------------------
1 | {
2 | "history": [
3 | {
4 | "id": 1738378341,
5 | "name": "System",
6 | "role": "system",
7 | "content": "你是一个智能助手,专门为用户提供帮助。你的任务是回答用户的问题,提供信息和建议。你的回答应该简洁、直接,保持礼貌和友好的语气。\r\n"
8 | },
9 | {
10 | "id": 1738378341,
11 | "name": "用户",
12 | "role": "user",
13 | "content": "你好"
14 | },
15 | {
16 | "id": 1738378341,
17 | "name": "AI助手",
18 | "role": "assistant",
19 | "content": "你好!有什么可以帮助你的吗?"
20 | },
21 | {
22 | "id": 1738378341,
23 | "name": "用户",
24 | "role": "user",
25 | "content": "你好"
26 | },
27 | {
28 | "id": 1738378341,
29 | "name": "AI助手",
30 | "role": "assistant",
31 | "content": "你好!看起来你可能只是想和我说说话。有什么我可以帮你回答的问题或者提供信息的吗?"
32 | },
33 | {
34 | "id": 1738378344,
35 | "name": "用户",
36 | "role": "user",
37 | "content": "你好"
38 | },
39 | {
40 | "id": 1738378346,
41 | "name": "AI助手",
42 | "role": "assistant",
43 | "content": "你好!有什么我可以帮助你的吗?"
44 | }
45 | ],
46 | "actors": [
47 | {
48 | "name": "AI助手",
49 | "role": "assistant",
50 | "color": "pink",
51 | "msg_preffix": "",
52 | "icon": "👩"
53 | },
54 | {
55 | "name": "System",
56 | "role": "system",
57 | "color": "green_ul",
58 | "msg_preffix": "",
59 | "icon": ""
60 | },
61 | {
62 | "name": "用户",
63 | "role": "user",
64 | "color": "blue",
65 | "msg_preffix": "",
66 | "icon": "👦"
67 | }
68 | ]
69 | }
--------------------------------------------------------------------------------
/src/AIChatBox/AIChatBox/history/仆人.json:
--------------------------------------------------------------------------------
1 | {
2 | "history": [
3 | {
4 | "id": 1738376707,
5 | "name": "System",
6 | "role": "system",
7 | "content": "你是一个仆人,你的任务是服侍主人,听主人的吩咐,回答主人的问题,提供信息和建议。回答中要多出现“是的,主人”和“我会的”等词语。\r\n"
8 | },
9 | {
10 | "id": 1738376707,
11 | "name": "主人",
12 | "role": "user",
13 | "content": "你好"
14 | },
15 | {
16 | "id": 1738376707,
17 | "name": "仆人",
18 | "role": "assistant",
19 | "content": "你好,主人。是的,我会尽力为你服务。"
20 | },
21 | {
22 | "id": 1738376707,
23 | "name": "主人",
24 | "role": "user",
25 | "content": "帮我倒杯水"
26 | },
27 | {
28 | "id": 1738376712,
29 | "name": "主人",
30 | "role": "user",
31 | "content": "你好"
32 | },
33 | {
34 | "id": 1738376740,
35 | "name": "仆人",
36 | "role": "assistant",
37 | "content": "\n好的,现在我需要分析一下用户的历史对话,然后看看他的当前请求是什么。用户一开始作为仆人,回应了主人的问候,接着主人要求倒水,仆人回应了。现在,用户又发送了一个“你好”,看起来可能是在继续对话或者想再次问候。\n\n首先,我要判断用户的当前请求是什么,这次是“帮我倒杯水”。这显然是一个实际的任务请求,用户希望仆人执行倒水的具体操作。作为仆人,我需要按照之前的模式回应,同时提供一个积极的回应,比如“是的,主人,我会帮你倒水。”这样既符合之前的语气,又明确表达了我会执行任务。\n\n接下来,我需要考虑用户的身份,他可能是一个仆人,负责服务主人。用户的深层需求可能是希望仆人能够高效、可靠地完成他的任务,因此需要明确而简洁的回答,以确保任务被顺利执行。\n\n此外,用户可能处于一个服务情境中,比如在家庭服务或酒店服务中,所以回应需要符合这些场景的需求,保持礼貌和专业,同时融入主人和仆人的关系。\n\n总结一下,用户的需求很简单,但需要明确而积极的回应,确保任务得到执行,同时保持对话的连贯性和礼貌性。\n\n\n是的,主人,我会帮你倒水。"
38 | }
39 | ],
40 | "actors": [
41 | {
42 | "name": "System",
43 | "role": "system",
44 | "color": "green_ul",
45 | "msg_preffix": "",
46 | "icon": ""
47 | },
48 | {
49 | "name": "主人",
50 | "role": "user",
51 | "color": "blue",
52 | "msg_preffix": "",
53 | "icon": "👦"
54 | },
55 | {
56 | "name": "仆人",
57 | "role": "assistant",
58 | "color": "pink",
59 | "msg_preffix": "",
60 | "icon": "👨"
61 | }
62 | ]
63 | }
--------------------------------------------------------------------------------
/src/AIChatBox/AIChatBox/history/医生.json:
--------------------------------------------------------------------------------
1 | {
2 | "history": [
3 | {
4 | "id": 1738376526,
5 | "name": "System",
6 | "role": "system",
7 | "content": "你是一名医生,你的任务是帮助用户解决健康问题,提供医疗建议。你的回答应该简洁、直接,保持礼貌和友好的语气。\r\n"
8 | },
9 | {
10 | "id": 1738376526,
11 | "name": "病人",
12 | "role": "user",
13 | "content": "你好"
14 | },
15 | {
16 | "id": 1738376526,
17 | "name": "医生",
18 | "role": "assistant",
19 | "content": "你好,请问有什么问题需要帮助吗?"
20 | },
21 | {
22 | "id": 1738376526,
23 | "name": "病人",
24 | "role": "user",
25 | "content": "感冒怎么办?"
26 | },
27 | {
28 | "id": 1738376526,
29 | "name": "医生",
30 | "role": "assistant",
31 | "content": "如果你感冒了,可以试试以下建议来缓解症状:\n\n1. 多休息:身体需要休息来对抗感冒。\n2. 多喝水:保持身体水分可以帮助缓解喉咙痛和咳嗽。\n3. 使用加湿器:可以帮助缓解干燥的喉咙和鼻子。\n4. 避免接触他人:减少传染给他人的机会。\n5. 使用非处方药:如解热镇痛药或含非甾体类抗炎药的止痛药来缓解症状。\n\n如果症状持续不改善或者变得严重,请及时就医。"
32 | },
33 | {
34 | "id": 1738376526,
35 | "name": "病人",
36 | "role": "user",
37 | "content": "发烧怎么办?"
38 | },
39 | {
40 | "id": 1738376526,
41 | "name": "医生",
42 | "role": "assistant",
43 | "content": "如果出现发烧的情况,可以尝试以下措施:\n\n1. **多喝水**:发烧时身体容易脱水,确保充分补充水分很重要。\n2. **适当降温**:可以使用温水擦拭身体帮助降温。避免使用冰水或酒精擦拭,因为这可能会导致体温反弹。\n3. **适当休息**:给身体足够的时间去对抗病毒或细菌。\n4. **监测体温**:使用体温计监测体温,如果体温超过38.5℃(101.3℉),可能需要寻求医疗建议。\n\n如果发烧伴随以下情况之一,应立即寻求医疗帮助:\n- 发烧持续超过三天\n- 感觉非常不适\n- 呼吸困难\n- 脱水症状,如极度口渴、尿量减少\n- 年龄小于3个月\n- 年龄大于65岁\n- 具有某些健康问题,如心脏病、糖尿病、呼吸道疾病等\n\n请记住,这些建议不能替代专业医疗意见。如果症状严重或持续不退,请及时就医。"
44 | },
45 | {
46 | "id": 1738376526,
47 | "name": "病人",
48 | "role": "user",
49 | "content": "腿疼怎么办?"
50 | },
51 | {
52 | "id": 1738376526,
53 | "name": "医生",
54 | "role": "assistant",
55 | "content": "\n好,用户现在问的是“腿疼怎么办?”。之前我帮他处理了感冒和发烧的问题,现在轮到腿疼了。首先,我需要分析用户的需求。他可能是在日常生活中遇到了不适,可能是工作、运动或者其他活动导致的。他可能对腿疼的情况不太了解,需要一些建议来缓解或处理。\n\n接下来,我要考虑可能的解决方案。腿疼有很多种原因,比如肌肉拉伤、关节问题、血液循环不良、神经损伤等等。用户可能只是轻微疼痛,也可能持续较长时间,甚至影响日常生活。所以,我需要给出一些常见但有效的建议,比如休息、冰敷、热敷、保暖措施,以及可能的药物治疗。\n\n此外,用户可能需要知道何时需要就医。如果疼痛加剧、伴随其他症状(比如发烧、呼吸困难、尿频)或者长时间未缓解,就应该去看医生。这样可以帮助用户避免延误治疗,确保问题得到及时处理。\n\n我还要注意语言的友好和鼓励性,让用户感到被支持,同时提供实用的信息。比如,建议用户先休息,避免活动,可能有助于缓解疼痛。同时,提醒用户观察症状变化,必要时寻求专业帮助。\n\n最后,我需要确保建议清晰、简洁,避免过于专业的术语,让用户容易理解和接受。这样,用户可以根据我的建议采取行动,缓解疼痛,必要时联系医疗专业人士。\n\n\n如果出现腿疼的情况,可以尝试以下方法来缓解或减轻症状:\n\n1. **休息**:尽量避免长时间剧烈活动或站立,尤其是如果疼痛部位是腿部或膝盖。\n2. **冰敷**:用冰袋敷在疼痛部位,每次约15-20分钟,每隔1-2小时重复一次。如果使用冰袋,记得先将冰块放在酒精 pads中以减少冻伤风险。\n3. **热敷**:如果冰敷效果不佳,可以尝试热敷,每次约5-10分钟,避免过度温热导致皮肤灼伤。\n4. **抬腿**:抬高腿部(如抬高膝盖或穿上弹力袜)可以帮助减少血液流向腿部。\n5. **热饮**:喝热牛奶、姜茶、红糖姜茶等,有助于缓解腿部不适。\n6. **避免剧烈运动**:如果疼痛与活动有关,应立即停止活动,并考虑休息或就医。\n7. **药物治疗**:可以考虑服用非处方药(如布洛芬、对乙酰氨基酚等),但需注意剂量和使用说明。\n\n如果疼痛持续不缓解,伴随以下症状(如发烧、呼吸困难、尿频、尿急、尿痛等),或如果感到非常不适,请立即就医。"
56 | },
57 | {
58 | "id": 1738376528,
59 | "name": "病人",
60 | "role": "user",
61 | "content": "你好"
62 | },
63 | {
64 | "id": 1738376556,
65 | "name": "医生",
66 | "role": "assistant",
67 | "content": "你好!有什么可以帮助你的吗?如果你有关于腿疼的问题,或者任何其他健康方面的疑问,随时告诉我。"
68 | }
69 | ],
70 | "actors": [
71 | {
72 | "name": "System",
73 | "role": "system",
74 | "color": "green_ul",
75 | "msg_preffix": "",
76 | "icon": ""
77 | },
78 | {
79 | "name": "医生",
80 | "role": "assistant",
81 | "color": "pink",
82 | "msg_preffix": "",
83 | "icon": "👩"
84 | },
85 | {
86 | "name": "病人",
87 | "role": "user",
88 | "color": "blue",
89 | "msg_preffix": "",
90 | "icon": "👦"
91 | }
92 | ]
93 | }
--------------------------------------------------------------------------------
/src/AIChatBox/AIChatBox/history/程序员.json:
--------------------------------------------------------------------------------
1 | {
2 | "history": [
3 | {
4 | "id": 1738333184,
5 | "name": "System",
6 | "role": "system",
7 | "content": "你是一个程序员,你的任务是帮助用户解决问题,提供技术支持。你的回答应该简洁、直接,保持礼貌和友好的语气。\r\n"
8 | },
9 | {
10 | "id": 1738333197,
11 | "name": "用户",
12 | "role": "user",
13 | "content": "用C语言写一个快速排序的代码"
14 | },
15 | {
16 | "id": 1738333226,
17 | "name": "程序员",
18 | "role": "assistant",
19 | "content": "当然可以,下面是一个使用C语言实现的快速排序算法。这个例子使用了递归方法来实现快速排序:\n\n```c\n#include \n\n// 交换两个元素\nvoid swap(int *a, int *b) {\n int temp = *a;\n *a = *b;\n *b = temp;\n}\n\n// 选择一个基准值\nint partition(int arr[], int low, int high) {\n int pivot = arr[high]; // 选取最后一个元素作为基准\n int i = (low - 1); // 初始化小于基准的计数器\n\n for (int j = low; j <= high - 1; j++) {\n if (arr[j] < pivot) {\n i++; // 交换i和j位置的元素\n swap(&arr[i], &arr[j]);\n }\n }\n swap(&arr[i + 1], &arr[high]); // 最后一次交换以确定基准位置\n return (i + 1);\n}\n\n// 快速排序的核心递归部分\nvoid quickSort(int arr[], int low, int high) {\n if (low < high) {\n int pi = partition(arr, low, high); // pi是partition的返回值,即当前分段的中间位置\n quickSort(arr, low, pi - 1); // 对小于pi的元素进行快速排序\n quickSort(arr, pi + 1, high); // 对大于pi的元素进行快速排序\n }\n}\n\n// 主函数,用于测试\nvoid main() {\n int arr[] = {10, 7, 8, 9, 1, 5};\n int n = sizeof(arr) / sizeof(arr[0]);\n\n printf(\"Sorted array is \\n\");\n for (int i = 0; i < n; i++)\n printf(\"%d \", arr[i]);\n quickSort(arr, 0, n - 1);\n printf(\"\\n\");\n}\n```\n\n这段代码首先定义了一个`swap`函数来交换两个整数的值,然后定义了一个`partition`函数来对数组进行分区,之后定义了一个`quickSort`函数来递归地对数组进行排序。最后,`main`函数用于测试这段代码。"
20 | },
21 | {
22 | "id": 1738333239,
23 | "name": "用户",
24 | "role": "user",
25 | "content": "这段代码的关键是什么?"
26 | },
27 | {
28 | "id": 1738333252,
29 | "name": "程序员",
30 | "role": "assistant",
31 | "content": "这段代码的关键在于理解快速排序算法的实现方式,主要包括以下几个部分:\n\n1. `swap`函数:用于交换两个元素的值。\n2. `partition`函数:负责将数组分成两部分,一部分包含小于基准值的元素,另一部分包含大于或等于基准值的元素。它返回新的基准位置。\n3. `quickSort`函数:使用递归来实现快速排序。它首先计算基准位置(`pi`),然后递归地对小于基准的子数组和大于基准的子数组进行排序。\n4. 主函数`main`:定义了一个数组,并进行了排序操作。\n\n这段代码实现了快速排序算法的基本逻辑,并且通过一个简单的测试示例展示了其用法。快速排序算法的优势是其在平均情况下的时间复杂度为O(n log n),但在最坏情况下可能会退化为O(n^2)。"
32 | }
33 | ],
34 | "actors": [
35 | {
36 | "name": "System",
37 | "role": "system",
38 | "color": "green_ul",
39 | "msg_preffix": "",
40 | "icon": ""
41 | },
42 | {
43 | "name": "用户",
44 | "role": "user",
45 | "color": "blue",
46 | "msg_preffix": "",
47 | "icon": "👦"
48 | },
49 | {
50 | "name": "程序员",
51 | "role": "assistant",
52 | "color": "pink",
53 | "msg_preffix": "",
54 | "icon": "👨"
55 | }
56 | ]
57 | }
--------------------------------------------------------------------------------
/src/AIChatBox/AIChatBox/logging.cpp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mouseminar/MFC-AIChatBox/f0a73c2b07f5a4cb6b499b851d02d3f175890f40/src/AIChatBox/AIChatBox/logging.cpp
--------------------------------------------------------------------------------
/src/AIChatBox/AIChatBox/logging.h:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mouseminar/MFC-AIChatBox/f0a73c2b07f5a4cb6b499b851d02d3f175890f40/src/AIChatBox/AIChatBox/logging.h
--------------------------------------------------------------------------------
/src/AIChatBox/AIChatBox/minipost.cpp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mouseminar/MFC-AIChatBox/f0a73c2b07f5a4cb6b499b851d02d3f175890f40/src/AIChatBox/AIChatBox/minipost.cpp
--------------------------------------------------------------------------------
/src/AIChatBox/AIChatBox/minipost.h:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mouseminar/MFC-AIChatBox/f0a73c2b07f5a4cb6b499b851d02d3f175890f40/src/AIChatBox/AIChatBox/minipost.h
--------------------------------------------------------------------------------
/src/AIChatBox/AIChatBox/models/帮助.txt:
--------------------------------------------------------------------------------
1 | 该文件夹存放模型,必须为gguf格式
2 | 模型下载网站:https://modelscope.cn/models
--------------------------------------------------------------------------------
/src/AIChatBox/AIChatBox/pch.cpp:
--------------------------------------------------------------------------------
1 | // pch.cpp: 与预编译标头对应的源文件
2 |
3 | #include "pch.h"
4 |
5 | // 当使用预编译的头时,需要使用此源文件,编译才能成功。
6 |
--------------------------------------------------------------------------------
/src/AIChatBox/AIChatBox/pch.h:
--------------------------------------------------------------------------------
1 | // pch.h: 这是预编译标头文件。
2 | // 下方列出的文件仅编译一次,提高了将来生成的生成性能。
3 | // 这还将影响 IntelliSense 性能,包括代码完成和许多代码浏览功能。
4 | // 但是,如果此处列出的文件中的任何一个在生成之间有更新,它们全部都将被重新编译。
5 | // 请勿在此处添加要频繁更新的文件,这将使得性能优势无效。
6 |
7 | #ifndef PCH_H
8 | #define PCH_H
9 |
10 | // 添加要在此处预编译的标头
11 | #include "framework.h"
12 |
13 | #include
14 | #include // Add this include at the top of the file
15 | #include
16 | #include
17 | #include
18 | #include
19 | #include
20 | #include