Files
envi-code/SourceCode/Code2026/CoreCommand/SH_AI.h
T
gjm 164968b62e chore
把非utf8-bom编码的cpp/h文件改为 utf8 bom 编码, msvc识别utf8编码时,如果不是bom格式的,会使用当前cp_oem来解码.
2026-10-04 00:04:20 +08:00

530 lines
14 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#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;}
};
}