Files
envi-code/SourceCode/Code2026/CoreCommand/SH_AI.h
T

529 lines
13 KiB
C++
Raw Normal View History

2026-09-28 15:28:50 +08:00
#pragma once
#include <string>
#include <vector>
#include <map>
#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<UTF8<> > Document8;
typedef GenericValue<UTF8<> > Value8;
typedef const GenericValue<UTF8<> > CValue8;
typedef GenericArray<false, Value8> Arr8;
typedef GenericArray<true, Value8> CArr8;
typedef Value8::ConstMemberIterator CMIt8;
typedef Value8::MemberIterator MIt8;
typedef Value8::ConstValueIterator CVIt8;
typedef Value8::ValueIterator VIt8;
typedef GenericStringBuffer<UTF8<> > StringBuffer8;
typedef PrettyWriter<StringBuffer8, UTF8<>, UTF8<>> PrettyWriter8;
typedef Writer<StringBuffer8, UTF8<>, 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 <typename T>
bool parseValue(CValue8 &v, LPCSTR key, T &t)
{
if (!key) return false;
CMIt8 it = v.FindMember(key);
if (it != v.MemberEnd() && it->value.Is<T>())
{
if (it->value.IsNull()) return false;
t = it->value.Get<T>();
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<std::string, std::string> _headers;
std::string _model;
/*对话的消息列表。*/
std::vector<message> _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<std::string> _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<std::string> &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<std::string> _allOriginalResponse;
};
#pragma region AICloud
// 智能云提供商
class AICloud
{
protected:
// 智能云提供商名称
std::string _cloudName;
// apiKey
std::string _apiKey;
// api endpoint
std::string _endpoint;
// 模型列表
std::vector<std::string> _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<std::string>& models) { _models = models;}
void insertModel(LPCSTR model) { _models.push_back(model); }
const std::vector<std::string>& 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<std::string> &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;}
};
}