#pragma once #include #include #include #define CURL_STATICLIB #include "mg_curl_export.h" #define RAPIDJSON_HAS_STDSTRING 1 #include "rapidjson/document.h" #include "rapidjson/encodings.h" #include "rapidjson/stringbuffer.h" #include "rapidjson/filereadstream.h" #include "rapidjson/filewritestream.h" #include "rapidjson/encodedstream.h" #include "rapidjson/prettywriter.h" #pragma comment (lib,"wldap32.lib") #pragma comment (lib,"ws2_32.lib") #pragma comment (lib,"Crypt32.lib") #pragma comment (lib,"Normaliz.lib") namespace AIJSON { std::string w2utf(LPCTSTR s, DWORD cp = CP_UTF8); std::string w2utf(const std::wstring &s, DWORD cp = CP_UTF8); std::wstring utf2w(LPCSTR s, DWORD cp = CP_UTF8); std::wstring utf2w(const std::string &s, DWORD cp = CP_UTF8); using namespace rapidjson; typedef GenericDocument > Document8; typedef GenericValue > Value8; typedef const GenericValue > CValue8; typedef GenericArray Arr8; typedef GenericArray CArr8; typedef Value8::ConstMemberIterator CMIt8; typedef Value8::MemberIterator MIt8; typedef Value8::ConstValueIterator CVIt8; typedef Value8::ValueIterator VIt8; typedef GenericStringBuffer > StringBuffer8; typedef PrettyWriter, UTF8<>> PrettyWriter8; typedef Writer, UTF8<>> Writer8; Document8::AllocatorType &getJsonAllocator(); Value8& addMember(Value8 &v, LPCSTR name, Value8 &value); Value8& addMember(Value8 &v, LPCSTR name, LPCSTR value); Value8& addMember(Value8 &v, LPCSTR name, const int &value); Value8& addMember(Value8 &v, LPCSTR name, const bool &value); Value8& addMember(Value8 &v, LPCSTR name, const float &value); Value8& pushBack(Value8 &arr, Value8 &value); Value8& pushBack(Value8 &arr, LPCSTR value); Value8& pushBack(Value8 &arr, const int &value); Value8& pushBack(Value8 &arr, const bool &value); Value8& pushBack(Value8 &arr, const float &value); std::string write2Json(const Value8 &v, bool pretty); bool json2File(LPCTSTR path, const Value8 &v, bool pretty = false); bool file2Json(LPCTSTR pszJson, Document8 &doc); template bool parseValue(CValue8 &v, LPCSTR key, T &t) { if (!key) return false; CMIt8 it = v.FindMember(key); if (it != v.MemberEnd() && it->value.Is()) { if (it->value.IsNull()) return false; t = it->value.Get(); return true; } return false; } } namespace SHAI { class initCurl { public: initCurl() { mg_curl_httpGlobalInit(); } ~initCurl() { mg_curl_httpGlobalCleanup(); } }; class Response; class Request { public: enum roleType { RT_SYSTEM, RT_USER, RT_ASSISTANT, RT_TOOL }; struct message { roleType role; std::string content; }; public: Request(LPCSTR apikey , LPCSTR model , LPCSTR url , const bool &stream ); Request(); void setapikey(LPCSTR apikey) { _apiKey = apikey; } void setmodel(LPCSTR model) { _model = model; } void seturl(LPCSTR url) { _apiEndpoint = url; } void setstream(const bool &stream) { _stream = stream; if (_stream) _stream_options_include_usage = true; } int send(Response &response) const; std::string requestBody() const; void addUserMessage(LPCSTR content); void addSystemMessage(LPCSTR content); void addAssistantMessage(LPCSTR content); void clearMessages(); void addHeaders(LPCSTR key, LPCSTR value); std::string apiEndPoint() const; void set_frequency_penalty(const float &f){ _frequency_penalty = f;} void set_top_p(const float &f) { _top_p = f;} void set_temperature(const float &f) { _temperature = f;} void set_max_tokens(const int &d) { _max_tokens = d;} void set_presence_penalty(const float &f) { _presence_penalty = f;} void set_top_k(const int &n){ _top_k = n;} // 清除最后一个消息 void popbackMessage(); private: void addMessage(const roleType &rt, LPCSTR content); std::string getRole(const roleType &rt) const; private: std::string _apiKey; std::string _apiEndpoint; std::map _headers; std::string _model; /*对话的消息列表。*/ std::vector _messages; /* 如果设置为 True,将会以 SSE(server-sent events)的形式以流式发送消息增量。 消息流以 data: [DONE] 结尾。 */ bool _stream; /* 流式输出相关选项。只有在 stream 参数为 true 时,才可设置此参数。 如果设置为 true,在流式消息最后的 data: [DONE] 之前将会传输一个额外的块。 此块上的 usage 字段显示整个请求的 token 使用统计信息,而 choices 字段将始终是一个空数组。 所有其他块也将包含一个 usage 字段,但其值为 null。 */ bool _stream_options_include_usage; /* 介于 -2.0 和 2.0 之间的数字。 如果该值为正,那么新 token 会根据其在已有文本中的出现频率受到相应的惩罚,降低模型重复相同内容的可能性。 default : 0 */ float _frequency_penalty; /* 介于 1 到 8192 间的整数,限制一次请求中模型生成 completion 的最大 token 数。 输入 token 和输出 token 的总长度受模型的上下文长度的限制。 如未指定 max_tokens参数,默认使用 4096。 */ int _max_tokens; /* 介于 -2.0 和 2.0 之间的数字。 如果该值为正,那么新 token 会根据其是否已在已有文本中出现受到相应的惩罚,从而增加模型谈论新主题的可能性。 default : 0 */ float _presence_penalty; /* 一个 object,指定模型必须输出的格式。 可以设置为 { "type": "plain_text" } 以启用纯文本模式,该模式保证模型生成的消息是有效的纯文本。 设置为 { "type": "json_object" } 以启用 JSON 模式,该模式保证模型生成的消息是有效的 JSON。 注意: 使用 JSON 模式时,你还必须通过系统或用户消息指示模型生成 JSON。 否则,模型可能会生成不断的空白字符,直到生成达到令牌限制,从而导致请求长时间运行并显得“卡住”。 此外,如果 finish_reason="length",这表示生成超过了 max_tokens 或对话超过了最大上下文长度,消息内容可能会被部分截断。 可能的值: "text" , "json_object" default: "text" */ std::string _response_format_type; /* 一个 string 或最多包含 16 个 string 的 list,在遇到这些词时,API 将停止生成更多的 token。 */ std::vector _stop; /* 采样温度,介于 0 和 2 之间。 更高的值,如 0.8,会使输出更随机,而更低的值,如 0.2,会使其更加集中和确定。 我们通常建议可以更改这个值或者更改 top_p,但不建议同时对两者进行修改。 default:1 */ float _temperature; /* 作为调节采样温度的替代方案,模型会考虑前 top_p 概率的 token 的结果。 所以 0.1 就意味着只有包括在最高 10% 概率中的 token 会被考虑。 我们通常建议修改这个值或者更改 temperature,但不建议同时对两者进行修改。 */ float _top_p; /* 是否返回所输出 token 的对数概率。如果为 true,则在 message 的 content 中返回每个输出 token 的对数概率。 */ bool _logprobs; /* 一个介于 0 到 20 之间的整数 N,指定每个输出位置返回输出概率 top N 的 token,且返回这些 token 的对数概率。 指定此参数时,logprobs 必须为 true。 */ int _top_logprobs; /**/ int _top_k; }; class Response { public: Response(); public: void readResponse(const std::string &s); bool isUsageTokens() const { return _bUsageTokens; } const std::string& content() const { return _content; } const std::string& reasoningContent() const { return _reasoning_content; } const std::string& allreasoningContent() const { return _all_reasoning_content; } const std::string& allContent() const { return _all_content; } int promptTokens() const { return _prompt_tokens; } int completionTokens() const { return _completion_tokens; } int totalTokens() const { return _total_tokens; } void clear(); bool showThinkingContent() { return _bShowThinkingContent; } void setShowThinkingContent(const bool &bShow) { _bShowThinkingContent = bShow; } void appendOriginalResponse(const std::string &s) { _allOriginalResponse.push_back(s); } const std::vector &originalResponses() { return _allOriginalResponse; } void setRecordContext(const bool &b) { _bRecordContext = b; } bool needRecordContext() { return _bRecordContext; } void set_finish_reason(LPCSTR s) { _finish_reason = s;} const std::string& finish_reason() { return _finish_reason; } private: void parseChoices(AIJSON::CValue8 &v); private: // tokens bool _bUsageTokens; // finish_reason 类型 std::string _finish_reason; // 单次思考内容 std::string _reasoning_content; // 单次回答内容 std::string _content; // 全部思考内容 std::string _all_reasoning_content; // 全部回答内容 std::string _all_content; // 提问的 token 数 int _prompt_tokens; // 完成的 token 数 int _completion_tokens; // 总 token 数 int _total_tokens; // 是否显示思考内容 bool _bShowThinkingContent; // 是否记录上下文 bool _bRecordContext; // 全部返回 std::vector _allOriginalResponse; }; #pragma region AICloud // 智能云提供商 class AICloud { protected: // 智能云提供商名称 std::string _cloudName; // apiKey std::string _apiKey; // api endpoint std::string _endpoint; // 模型列表 std::vector _models; // 当前模型 std::string _current_model; // 当前使用云 bool _current_select; public: // 构造函数 AICloud() { } ~AICloud() { } AICloud(LPCSTR name, LPCSTR key, LPCSTR endpoint) : _apiKey(key) , _endpoint(endpoint) , _cloudName(name) , _current_select(false) { } std::string cloudName()const {return _cloudName;} void setCloudName(LPCSTR name) { _cloudName = name; } // 设置和获取 apiKey void setApiKey(LPCSTR key) { _apiKey = key; } std::string apiKey() const { return _apiKey; } // 设置和获取 endpoint void setEndpoint(LPCSTR endpoint) { this->_endpoint = endpoint; } std::string endpoint() const { return _endpoint; } // 设置获取 当前模型 void setCurrentModel(const int &idx); void setCurrentModel(LPCSTR model){ _current_model = model;} std::string currentModel() const { return _current_model; } void setModels(const std::vector& models) { _models = models;} void insertModel(LPCSTR model) { _models.push_back(model); } const std::vector& models() const { return _models; } void setCurrentSelect(const bool &b) {_current_select = b;} bool currentSelect() const { return _current_select; } // 解析服务器返回的模型列表json // 支持硅基和deepseek模型 static void parseModelsJson(LPCSTR js, std::vector &models); virtual void getModels() {} struct IS_EQUAL { IS_EQUAL(AICloud *p): _p(p) {} AICloud *_p; bool operator () (AICloud *p) const { return p->_cloudName == _p->_cloudName; } }; static AICloud* createCloud(LPCSTR name); static bool IsCustomCloud(AICloud *p); }; class AliyunBailian : public AICloud { public: AliyunBailian() { } ~AliyunBailian() { } AliyunBailian(LPCSTR key) : AICloud(AIJSON::w2utf(_T("阿里云百炼")).c_str() , key , "https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions") { } virtual void getModels(); }; class SiliconFlow : public AICloud { public: SiliconFlow() { } ~SiliconFlow() { } SiliconFlow(LPCSTR key) : AICloud(AIJSON::w2utf(_T("硅基流动")).c_str() , key , "https://api.siliconflow.cn/v1/chat/completions") { } virtual void getModels(); }; class DeepSeek : public AICloud { public: DeepSeek() { } ~DeepSeek() { } DeepSeek(LPCSTR key) : AICloud("DeepSeek", key, "https://api.deepseek.com/chat/completions") { } virtual void getModels(); }; class Hyperbolic : public AICloud { public: Hyperbolic() { } ~Hyperbolic() { } Hyperbolic(LPCSTR key) : AICloud("Hyperbolic", key, "https://api.hyperbolic.xyz/v1/chat/completions") { } virtual void getModels(); }; class CustomCloud : public AICloud { public: CustomCloud() { } ~CustomCloud() { } CustomCloud(LPCSTR name, LPCSTR key, LPCSTR endpoint) : AICloud(name, key, endpoint) { } virtual void getModels() {}; }; #pragma endregion class ChatConfig { private: std::string _system_prompt; int _max_tokens; float _top_p; float _temperature; int _top_k; float _frequency_penalty; public: ChatConfig() : _system_prompt("") , _max_tokens(4096) , _top_p(.7f) , _temperature(.6f) , _top_k(50) , _frequency_penalty(0.0f) { } void set_system_prompt(LPCTSTR psz) { _system_prompt = AIJSON::w2utf(psz); } void set_system_prompt(LPCSTR psz) { _system_prompt = psz; } std::wstring system_prompt_w()const { return AIJSON::utf2w(_system_prompt); }; std::string system_prompt()const { return _system_prompt; } void set_max_tokens(const int &i) { _max_tokens = i; } int max_tokens()const { return _max_tokens;} void set_top_k(const int &i){ _top_k = i;} int top_k()const { return _top_k;} void set_top_p(const float &f){ _top_p = f;} float top_p()const { return _top_p;} void set_temperature(const float &f){ _temperature = f;} float temperature()const { return _temperature;} void set_frequency_penalty(const float &f){ _frequency_penalty = f;} float frequency_penalty()const { return _frequency_penalty;} }; }