├── 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 | [![MFC](https://img.shields.io/badge/Framework-MFC-008080.svg)]() 4 | [![C++](https://img.shields.io/badge/Language-C%2B%2B-00599C.svg)]() 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 | ![界面截图](image/设置.gif) 28 | - **可以查看本地保存的历史记录** 29 | ![界面截图](image/历史记录.gif) 30 | - **开启新聊天后,可以实时查看AI的回复** 31 | ![界面截图](image/新聊天.gif) 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 | ![界面截图](image/server目录.png) 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 | ![界面截图](image/server目录.png) 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 21 | #include 22 | #include 23 | 24 | #endif //PCH_H 25 | -------------------------------------------------------------------------------- /src/AIChatBox/AIChatBox/res/123.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mouseminar/MFC-AIChatBox/f0a73c2b07f5a4cb6b499b851d02d3f175890f40/src/AIChatBox/AIChatBox/res/123.ico -------------------------------------------------------------------------------- /src/AIChatBox/AIChatBox/res/AIChatBox.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mouseminar/MFC-AIChatBox/f0a73c2b07f5a4cb6b499b851d02d3f175890f40/src/AIChatBox/AIChatBox/res/AIChatBox.ico -------------------------------------------------------------------------------- /src/AIChatBox/AIChatBox/res/AIChatBox.rc2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mouseminar/MFC-AIChatBox/f0a73c2b07f5a4cb6b499b851d02d3f175890f40/src/AIChatBox/AIChatBox/res/AIChatBox.rc2 -------------------------------------------------------------------------------- /src/AIChatBox/AIChatBox/res/robot.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mouseminar/MFC-AIChatBox/f0a73c2b07f5a4cb6b499b851d02d3f175890f40/src/AIChatBox/AIChatBox/res/robot.ico -------------------------------------------------------------------------------- /src/AIChatBox/AIChatBox/resource.h: -------------------------------------------------------------------------------- 1 | //{{NO_DEPENDENCIES}} 2 | // Microsoft Visual C++ 生成的包含文件。 3 | // 供 AIChatBox.rc 使用 4 | // 5 | #define IDM_ABOUTBOX 0x0010 6 | #define IDD_ABOUTBOX 100 7 | #define IDS_ABOUTBOX 101 8 | #define IDD_AICHATBOX_DIALOG 102 9 | #define IDP_SOCKETS_INIT_FAILED 103 10 | #define IDR_MAINFRAME 128 11 | #define IDD_SETTING_DIALOG 130 12 | #define IDD_NEWCHAT_DIALOG 133 13 | #define IDR_MENU1 135 14 | #define IDI_ICON2 137 15 | #define IDI_ICON1 138 16 | #define IDD_PROMPT_DIALOG 139 17 | #define IDD_RENAME_DIALOG 142 18 | #define IDC_LIST_HISTORY 1000 19 | #define IDC_BUTTON_NEW_CHAT 1001 20 | #define IDC_BUTTON_SETTING 1002 21 | #define IDC_BUTTON_ABOUT 1003 22 | #define IDC_RICHEDIT_CHAT_HISTORY 1004 23 | #define IDC_RICHEDIT_SYSTEM_PROMPT 1005 24 | #define IDC_IPADDRESS1 1005 25 | #define IDC_RICHEDIT_USER_INPUT 1006 26 | #define IDC_EDIT_PORT 1006 27 | #define IDC_EDIT_MODEL_PATH 1007 28 | #define IDC_EDIT_HISTORY_PATH 1008 29 | #define IDC_BUTTON_SELECT_PATH 1009 30 | #define IDC_COMBO_SELECT_MODEL 1010 31 | #define IDC_MFCCOLORBUTTON1 1011 32 | #define IDC_MFCCOLORBUTTON2 1012 33 | #define IDC_MFCFONTCOMBO1 1013 34 | #define IDC_COMBO_FONT_SIZE 1014 35 | #define IDC_CHECK_BOLD 1015 36 | #define IDC_CHECK_ITALIC 1016 37 | #define IDC_BUTTON_START_SERVER 1017 38 | #define IDC_BUTTON_STOP_SERVER 1018 39 | #define IDC_BUTTON_SEND_MESSAGE 1018 40 | #define IDC_BUTTON_HISTORY_PATH 1019 41 | #define IDC_BUTTON_CLEAR_MESSAGE2 1019 42 | #define IDC_EDIT_CHAT_NAME 1019 43 | #define IDC_BUTTON_CLEAR_MESSAGE 1019 44 | #define IDC_COMBO_SELECT_PROMPT 1020 45 | #define IDC_MFCCOLORBUTTON3 1020 46 | #define IDC_BUTTON_WITHDRAW_MESSAGE 1020 47 | #define IDC_EDIT_USER_NAME 1021 48 | #define IDC_MFCCOLORBUTTON4 1021 49 | #define IDC_EDIT_AI_NAME 1022 50 | #define IDC_BUTTON_SET_PROMPT 1022 51 | #define IDC_EDIT_SYSTEM_PROMPT 1023 52 | #define IDC_EDIT1 1023 53 | #define ID_32771 32771 54 | #define ID_LISTBOX_DELETE 32772 55 | #define ID_32773 32773 56 | #define ID_32774 32774 57 | #define ID_32775 32775 58 | #define ID_32776 32776 59 | #define ID_32777 32777 60 | #define ID_32778 32778 61 | #define ID_DELETE 32779 62 | #define ID_RENAME 32780 63 | #define ID_DELETE_ITEM 32888 64 | 65 | // Next default values for new objects 66 | // 67 | #ifdef APSTUDIO_INVOKED 68 | #ifndef APSTUDIO_READONLY_SYMBOLS 69 | #define _APS_NEXT_RESOURCE_VALUE 144 70 | #define _APS_NEXT_COMMAND_VALUE 32781 71 | #define _APS_NEXT_CONTROL_VALUE 1024 72 | #define _APS_NEXT_SYMED_VALUE 101 73 | #endif 74 | #endif 75 | -------------------------------------------------------------------------------- /src/AIChatBox/AIChatBox/server/ggml-base.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mouseminar/MFC-AIChatBox/f0a73c2b07f5a4cb6b499b851d02d3f175890f40/src/AIChatBox/AIChatBox/server/ggml-base.dll -------------------------------------------------------------------------------- /src/AIChatBox/AIChatBox/server/ggml-cpu.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mouseminar/MFC-AIChatBox/f0a73c2b07f5a4cb6b499b851d02d3f175890f40/src/AIChatBox/AIChatBox/server/ggml-cpu.dll -------------------------------------------------------------------------------- /src/AIChatBox/AIChatBox/server/ggml-rpc.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mouseminar/MFC-AIChatBox/f0a73c2b07f5a4cb6b499b851d02d3f175890f40/src/AIChatBox/AIChatBox/server/ggml-rpc.dll -------------------------------------------------------------------------------- /src/AIChatBox/AIChatBox/server/ggml.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mouseminar/MFC-AIChatBox/f0a73c2b07f5a4cb6b499b851d02d3f175890f40/src/AIChatBox/AIChatBox/server/ggml.dll -------------------------------------------------------------------------------- /src/AIChatBox/AIChatBox/server/llama-server.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mouseminar/MFC-AIChatBox/f0a73c2b07f5a4cb6b499b851d02d3f175890f40/src/AIChatBox/AIChatBox/server/llama-server.exe -------------------------------------------------------------------------------- /src/AIChatBox/AIChatBox/server/llama.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mouseminar/MFC-AIChatBox/f0a73c2b07f5a4cb6b499b851d02d3f175890f40/src/AIChatBox/AIChatBox/server/llama.dll -------------------------------------------------------------------------------- /src/AIChatBox/AIChatBox/server/llava_shared.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mouseminar/MFC-AIChatBox/f0a73c2b07f5a4cb6b499b851d02d3f175890f40/src/AIChatBox/AIChatBox/server/llava_shared.dll -------------------------------------------------------------------------------- /src/AIChatBox/AIChatBox/server/start_server_qwen_3b.bat: -------------------------------------------------------------------------------- 1 | llama-server.exe -m ..\models\DeepSeek-R1-Distill-Qwen-7B-Q4_K_M.gguf -------------------------------------------------------------------------------- /src/AIChatBox/AIChatBox/server/测试.bat: -------------------------------------------------------------------------------- 1 | llama-server.exe -h 2 | pause -------------------------------------------------------------------------------- /src/AIChatBox/AIChatBox/sjson.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mouseminar/MFC-AIChatBox/f0a73c2b07f5a4cb6b499b851d02d3f175890f40/src/AIChatBox/AIChatBox/sjson.cpp -------------------------------------------------------------------------------- /src/AIChatBox/AIChatBox/sjson.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mouseminar/MFC-AIChatBox/f0a73c2b07f5a4cb6b499b851d02d3f175890f40/src/AIChatBox/AIChatBox/sjson.h -------------------------------------------------------------------------------- /src/AIChatBox/AIChatBox/targetver.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 包括 SDKDDKVer.h 将定义可用的最高版本的 Windows 平台。 4 | 5 | //如果要为以前的 Windows 平台生成应用程序,请包括 WinSDKVer.h,并 6 | // 将 _WIN32_WINNT 宏设置为要支持的平台,然后再包括 SDKDDKVer.h。 7 | 8 | #include 9 | -------------------------------------------------------------------------------- /src/AIChatBox/AIChatBox/utils.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mouseminar/MFC-AIChatBox/f0a73c2b07f5a4cb6b499b851d02d3f175890f40/src/AIChatBox/AIChatBox/utils.cpp -------------------------------------------------------------------------------- /src/AIChatBox/AIChatBox/utils.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mouseminar/MFC-AIChatBox/f0a73c2b07f5a4cb6b499b851d02d3f175890f40/src/AIChatBox/AIChatBox/utils.h --------------------------------------------------------------------------------