Skip to content

Commit 8c98278

Browse files
committed
added:set role and history support for ai module
1 parent 49351b2 commit 8c98278

File tree

5 files changed

+276
-70
lines changed

5 files changed

+276
-70
lines changed

XEngine_Module/XEngine_AIApi/AIApi_Chat/AIApi_Chat.cpp

Lines changed: 204 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -48,12 +48,17 @@ CAIApi_Chat::~CAIApi_Chat()
4848
类型:无类型指针
4949
可空:Y
5050
意思:回调函数自定义参数
51+
参数.六:bHistory
52+
In/Out:In
53+
类型:逻辑型
54+
可空:Y
55+
意思:是否启用历史会话功能
5156
返回值
5257
类型:逻辑型
5358
意思:是否成功
5459
备注:
5560
*********************************************************************/
56-
bool CAIApi_Chat::AIApi_Chat_Create(XNETHANDLE* pxhToken, LPCXSTR lpszAPIUrl, LPCXSTR lpszAPIKey, CALLBACK_XENGINE_MODULE_AIAPI_CHAT fpCall_Chat, XPVOID lParam /* = NULL */)
61+
bool CAIApi_Chat::AIApi_Chat_Create(XNETHANDLE* pxhToken, LPCXSTR lpszAPIUrl, LPCXSTR lpszAPIKey, CALLBACK_XENGINE_MODULE_AIAPI_CHAT fpCall_Chat, XPVOID lParam /* = NULL */, bool bHistory /* = true */)
5762
{
5863
AIApi_IsErrorOccur = true;
5964

@@ -70,21 +75,31 @@ bool CAIApi_Chat::AIApi_Chat_Create(XNETHANDLE* pxhToken, LPCXSTR lpszAPIUrl, LP
7075
AIApi_dwErrorCode = ERROR_XENGINE_MODULE_AIAPI_CHAT_MALLOC;
7176
return false;
7277
}
78+
*pSt_AIClient = {};
79+
pSt_AIClient->bHistory = true;
7380
pSt_AIClient->lParam = lParam;
7481
pSt_AIClient->lpCall_Chat = fpCall_Chat;
7582

7683
pSt_AIClient->nTimeStart = time(NULL);
7784
_xstrcpy(pSt_AIClient->tszAPIUrl, lpszAPIUrl, sizeof(pSt_AIClient->tszAPIUrl));
7885
_xsntprintf(pSt_AIClient->tszAPIHdr, sizeof(pSt_AIClient->tszAPIHdr), _X("Content-Type: application/json\r\nAuthorization: Bearer %s"), lpszAPIKey);
7986

87+
pSt_AIClient->pStl_ListHistory = std::make_unique<std::list<AICLIENT_HISTORY>>();
88+
if (NULL == pSt_AIClient->pStl_ListHistory)
89+
{
90+
AIApi_IsErrorOccur = true;
91+
AIApi_dwErrorCode = ERROR_XENGINE_MODULE_AIAPI_CHAT_MALLOC;
92+
return false;
93+
}
8094
if (!APIClient_Http_Create(&pSt_AIClient->xhToken, AIApi_Chat_CBRecv, pSt_AIClient))
8195
{
8296
AIApi_IsErrorOccur = true;
8397
AIApi_dwErrorCode = APIClient_GetLastError();
8498
return false;
8599
}
86100
XCLIENT_APIHTTP st_HTTPParam = {};
87-
st_HTTPParam.nTimeConnect = 2000;
101+
st_HTTPParam.nTimeConnect = 60000;
102+
st_HTTPParam.nTimeOperator = 60000;
88103
if (!APIClient_Http_SetParam(pSt_AIClient->xhToken, &st_HTTPParam))
89104
{
90105
AIApi_IsErrorOccur = true;
@@ -105,36 +120,6 @@ bool CAIApi_Chat::AIApi_Chat_Create(XNETHANDLE* pxhToken, LPCXSTR lpszAPIUrl, LP
105120
return true;
106121
}
107122
/********************************************************************
108-
函数名称:AIApi_Chat_Destory
109-
函数功能:销毁一个对话模型
110-
参数.一:xhToken
111-
In/Out:In
112-
类型:句柄
113-
可空:N
114-
意思:要操作的模型句柄
115-
返回值
116-
类型:逻辑型
117-
意思:是否成功
118-
备注:
119-
*********************************************************************/
120-
bool CAIApi_Chat::AIApi_Chat_Destory(XNETHANDLE xhToken)
121-
{
122-
AIApi_IsErrorOccur = false;
123-
124-
st_Locker.lock();
125-
auto stl_MapIterator = stl_MapAIClient.find(xhToken);
126-
if (stl_MapIterator != stl_MapAIClient.end())
127-
{
128-
APIClient_Http_Close(stl_MapIterator->second->xhToken);
129-
130-
delete stl_MapIterator->second;
131-
stl_MapIterator->second = NULL;
132-
stl_MapAIClient.erase(stl_MapIterator);
133-
}
134-
st_Locker.unlock();
135-
return true;
136-
}
137-
/********************************************************************
138123
函数名称:AIApi_Chat_Excute
139124
函数功能:执行对话
140125
参数.一:xhToken
@@ -182,22 +167,45 @@ bool CAIApi_Chat::AIApi_Chat_Excute(XNETHANDLE xhToken, LPCXSTR lpszModelName, L
182167
}
183168
Json::Value st_JsonRoot;
184169
Json::Value st_JsonArray;
185-
Json::Value st_JsonObject;
186170
Json::StreamWriterBuilder st_JsonBuilder;
187171

188172
st_JsonBuilder["emitUTF8"] = true;
173+
//主要帮助角色信息
174+
if (_tcsxlen(stl_MapIterator->second->tszAPIRole) > 0)
175+
{
176+
Json::Value st_JsonSystemRole;
177+
st_JsonSystemRole["role"] = _X("system");
178+
st_JsonSystemRole["content"] = stl_MapIterator->second->tszAPIRole;
189179

180+
st_JsonArray.append(st_JsonSystemRole);
181+
}
182+
//准备数据
183+
Json::Value st_JsonObject;
184+
AICLIENT_HISTORY st_AIHistory = {};
185+
_xstrcpy(st_AIHistory.tszRoleName, _X("user"), sizeof(st_AIHistory.tszRoleName));
190186
#ifdef _MSC_BUILD
191-
XCHAR tszUTFBuffer[8192] = {};
192-
BaseLib_Charset_AnsiToUTF(lpszMSGBuffer, tszUTFBuffer, &nMSGLen);
193-
st_JsonObject["content"] = tszUTFBuffer;
187+
BaseLib_Charset_AnsiToUTF(lpszMSGBuffer, st_AIHistory.tszRoleContent, &nMSGLen);
194188
#else
195-
st_JsonObject["content"] = lpszMSGBuffer;
189+
_xstrcpy(st_AIHistory.tszRoleContent, lpszMSGBuffer, sizeof(st_AIHistory.tszRoleContent));
196190
#endif
197-
st_JsonObject["role"] = "user";
198-
191+
//是否启用了历史会话
192+
if (stl_MapIterator->second->bHistory)
193+
{
194+
for (const auto& stl_ListHistory : *(stl_MapIterator->second->pStl_ListHistory))
195+
{
196+
Json::Value st_JsonHistory;
197+
st_JsonHistory["role"] = stl_ListHistory.tszRoleName;
198+
st_JsonHistory["content"] = stl_ListHistory.tszRoleContent;
199+
st_JsonArray.append(st_JsonHistory);
200+
}
201+
//需要加入对话列表
202+
stl_MapIterator->second->pStl_ListHistory->push_back(st_AIHistory);
203+
}
204+
//发送的内容
205+
st_JsonObject["content"] = st_AIHistory.tszRoleContent;
206+
st_JsonObject["role"] = st_AIHistory.tszRoleName;
199207
st_JsonArray.append(st_JsonObject);
200-
208+
201209
st_JsonRoot["model"] = lpszModelName;
202210
st_JsonRoot["stream"] = bStream;
203211
st_JsonRoot["messages"] = st_JsonArray;
@@ -216,6 +224,78 @@ bool CAIApi_Chat::AIApi_Chat_Excute(XNETHANDLE xhToken, LPCXSTR lpszModelName, L
216224
return true;
217225
}
218226
/********************************************************************
227+
函数名称:AIApi_Chat_SetRole
228+
函数功能:设置系统角色
229+
参数.一:xhToken
230+
In/Out:In
231+
类型:句柄
232+
可空:N
233+
意思:输入要操作的句柄
234+
参数.二:lpszModelName
235+
In/Out:In
236+
类型:常量字符指针
237+
可空:N
238+
意思:输入系统角色信息,比如:你是一个C/C++语言的开发大师
239+
返回值
240+
类型:逻辑型
241+
意思:是否成功
242+
备注:
243+
*********************************************************************/
244+
bool CAIApi_Chat::AIApi_Chat_SetRole(XNETHANDLE xhToken, LPCXSTR lpszRoleName)
245+
{
246+
AIApi_IsErrorOccur = false;
247+
248+
st_Locker.lock_shared();
249+
auto stl_MapIterator = stl_MapAIClient.find(xhToken);
250+
if (stl_MapIterator == stl_MapAIClient.end())
251+
{
252+
AIApi_IsErrorOccur = true;
253+
AIApi_dwErrorCode = ERROR_XENGINE_MODULE_AIAPI_CHAT_NOTFOUND;
254+
st_Locker.unlock_shared();
255+
return false;
256+
}
257+
#ifdef _MSC_BUILD
258+
int nLen = _tcsxlen(lpszRoleName);
259+
XCHAR tszUTFBuffer[8192] = {};
260+
BaseLib_Charset_AnsiToUTF(lpszRoleName, stl_MapIterator->second->tszAPIRole, &nLen);
261+
#else
262+
_xstrcpy(stl_MapIterator->second->tszAPIRole, lpszRoleName, sizeof(stl_MapIterator->second->tszAPIRole));
263+
#endif
264+
265+
st_Locker.unlock_shared();
266+
return true;
267+
}
268+
/********************************************************************
269+
函数名称:AIApi_Chat_Clear
270+
函数功能:清理对话历史记录
271+
参数.一:xhToken
272+
In/Out:In
273+
类型:句柄
274+
可空:N
275+
意思:输入要操作的句柄
276+
返回值
277+
类型:逻辑型
278+
意思:是否成功
279+
备注:
280+
*********************************************************************/
281+
bool CAIApi_Chat::AIApi_Chat_Clear(XNETHANDLE xhToken)
282+
{
283+
AIApi_IsErrorOccur = false;
284+
285+
st_Locker.lock_shared();
286+
auto stl_MapIterator = stl_MapAIClient.find(xhToken);
287+
if (stl_MapIterator == stl_MapAIClient.end())
288+
{
289+
AIApi_IsErrorOccur = true;
290+
AIApi_dwErrorCode = ERROR_XENGINE_MODULE_AIAPI_CHAT_NOTFOUND;
291+
st_Locker.unlock_shared();
292+
return false;
293+
}
294+
stl_MapIterator->second->pStl_ListHistory->clear();
295+
st_Locker.unlock_shared();
296+
return true;
297+
}
298+
/********************************************************************
219299
函数名称:AIApi_Chat_GetStatus
220300
函数功能:获取执行状态
221301
参数.一:xhToken
@@ -228,17 +308,22 @@ bool CAIApi_Chat::AIApi_Chat_Excute(XNETHANDLE xhToken, LPCXSTR lpszModelName, L
228308
类型:逻辑型指针
229309
可空:N
230310
意思:输出是否执行完毕
231-
参数.:pInt_HTTPCode
311+
参数.:pInt_HTTPCode
232312
In/Out:Out
233313
类型:整数型指针
234314
可空:Y
235315
意思:输出HTTP状态码
316+
参数.四:bWaitExist
317+
In/Out:In
318+
类型:逻辑型
319+
可空:Y
320+
意思:是否等待执行完毕
236321
返回值
237322
类型:逻辑型
238323
意思:是否成功
239324
备注:pbComplete没有执行完毕需要等待执行完毕
240325
*********************************************************************/
241-
bool CAIApi_Chat::AIApi_Chat_GetStatus(XNETHANDLE xhToken, bool* pbComplete, int* pInt_HTTPCode /* = NULL */)
326+
bool CAIApi_Chat::AIApi_Chat_GetStatus(XNETHANDLE xhToken, bool* pbComplete, int* pInt_HTTPCode /* = NULL */, bool bWaitExist /* = true */)
242327
{
243328
AIApi_IsErrorOccur = false;
244329

@@ -251,7 +336,8 @@ bool CAIApi_Chat::AIApi_Chat_GetStatus(XNETHANDLE xhToken, bool* pbComplete, int
251336
st_Locker.unlock_shared();
252337
return false;
253338
}
254-
if (!APIClient_Http_GetResult(xhToken, pbComplete, pInt_HTTPCode))
339+
340+
if (!APIClient_Http_GetResult(xhToken, pbComplete, pInt_HTTPCode, bWaitExist))
255341
{
256342
AIApi_IsErrorOccur = true;
257343
AIApi_dwErrorCode = APIClient_GetLastError();
@@ -262,6 +348,36 @@ bool CAIApi_Chat::AIApi_Chat_GetStatus(XNETHANDLE xhToken, bool* pbComplete, int
262348
st_Locker.unlock_shared();
263349
return true;
264350
}
351+
/********************************************************************
352+
函数名称:AIApi_Chat_Destory
353+
函数功能:销毁一个对话模型
354+
参数.一:xhToken
355+
In/Out:In
356+
类型:句柄
357+
可空:N
358+
意思:要操作的模型句柄
359+
返回值
360+
类型:逻辑型
361+
意思:是否成功
362+
备注:
363+
*********************************************************************/
364+
bool CAIApi_Chat::AIApi_Chat_Destory(XNETHANDLE xhToken)
365+
{
366+
AIApi_IsErrorOccur = false;
367+
368+
st_Locker.lock();
369+
auto stl_MapIterator = stl_MapAIClient.find(xhToken);
370+
if (stl_MapIterator != stl_MapAIClient.end())
371+
{
372+
APIClient_Http_Close(stl_MapIterator->second->xhToken);
373+
374+
delete stl_MapIterator->second;
375+
stl_MapIterator->second = NULL;
376+
stl_MapAIClient.erase(stl_MapIterator);
377+
}
378+
st_Locker.unlock();
379+
return true;
380+
}
265381
//////////////////////////////////////////////////////////////////////////
266382
// 保护函数
267383
//////////////////////////////////////////////////////////////////////////
@@ -292,6 +408,10 @@ bool CAIApi_Chat::AIApi_Chat_Parse(AICLIENT_CHAT* pSt_AIClient, LPCXSTR lpszMSGB
292408
{
293409
continue;
294410
}
411+
if (st_JsonMessage["content"].isNull() || st_JsonMessage["role"].isNull())
412+
{
413+
continue;
414+
}
295415
}
296416
else
297417
{
@@ -300,15 +420,27 @@ bool CAIApi_Chat::AIApi_Chat_Parse(AICLIENT_CHAT* pSt_AIClient, LPCXSTR lpszMSGB
300420
{
301421
continue;
302422
}
423+
if (st_JsonMessage["content"].isNull() || st_JsonMessage["role"].isNull())
424+
{
425+
continue;
426+
}
303427
}
304-
#ifdef _MSC_BUILD
428+
AICLIENT_HISTORY st_AIHistory = {};
305429
int nGBKLen = st_JsonMessage["content"].asString().length();
430+
_xstrcpy(st_AIHistory.tszRoleName, st_JsonMessage["role"].asCString(), sizeof(st_AIHistory.tszRoleName));
431+
_xstrcpy(st_AIHistory.tszRoleContent, st_JsonMessage["content"].asString().c_str(), sizeof(st_AIHistory.tszRoleContent));
432+
#ifdef _MSC_BUILD
306433
XCHAR tszGBKBuffer[8192] = {};
307434
BaseLib_Charset_UTFToAnsi(st_JsonMessage["content"].asString().c_str(), tszGBKBuffer, &nGBKLen);
308435
pSt_AIClient->lpCall_Chat(pSt_AIClient->xhToken, st_JsonRoot["model"].asCString(), tszGBKBuffer, nGBKLen, pSt_AIClient->lParam);
309436
#else
310437
pSt_AIClient->lpCall_Chat(pSt_AIClient->xhToken, st_JsonRoot["model"].asCString(), st_JsonMessage["content"].asString().c_str(), st_JsonMessage["content"].asString().length(), pSt_AIClient->lParam);
311438
#endif
439+
440+
if (pSt_AIClient->bHistory)
441+
{
442+
pSt_AIClient->pStl_ListHistory->push_back(st_AIHistory);
443+
}
312444
}
313445

314446
return true;
@@ -320,14 +452,38 @@ void CAIApi_Chat::AIApi_Chat_CBRecv(XNETHANDLE xhToken, XPVOID lpszMsgBuffer, in
320452
{
321453
AICLIENT_CHAT* pSt_AIClient = (AICLIENT_CHAT*)lParam;
322454
CAIApi_Chat* pClass_This = (CAIApi_Chat*)pSt_AIClient->lClass;
323-
455+
//SSE
324456
int nPos = 0;
325457
bool bSSEReply = false;
326458
LPCXSTR lpszSSEStr = _X("data: ");
327-
if (0 == _tcsxnicmp((LPCXSTR)lpszMsgBuffer, lpszSSEStr, _tcsxlen(lpszSSEStr)))
459+
460+
if (pSt_AIClient->bStream)
328461
{
329-
nPos = _tcsxlen(lpszSSEStr);
330-
bSSEReply = true;
462+
xstring m_StrBuffer;
463+
XCHAR tszMSGBuffer[8192] = {};
464+
memcpy(tszMSGBuffer, lpszMsgBuffer, nMsgLen);
465+
//stream可能会有chunk回车情况
466+
XCHAR* ptszTokNext = NULL;
467+
XCHAR* ptszTokStr = _tcsxtok_s(tszMSGBuffer, _X("\r\n\r\n"), &ptszTokNext);
468+
if (NULL == ptszTokStr)
469+
{
470+
m_StrBuffer = (LPCXSTR)lpszMsgBuffer;
471+
//头为data:
472+
if (0 == _tcsxnicmp((LPCXSTR)lpszMsgBuffer, lpszSSEStr, _tcsxlen(lpszSSEStr)))
473+
{
474+
nPos = _tcsxlen(lpszSSEStr);
475+
bSSEReply = true;
476+
}
477+
}
478+
else
479+
{
480+
while (NULL != ptszTokStr)
481+
{
482+
m_StrBuffer += ptszTokStr;
483+
ptszTokStr = _tcsxtok_s(NULL, _X("\r\n\r\n"), &ptszTokNext);
484+
}
485+
}
331486
}
487+
332488
pClass_This->AIApi_Chat_Parse(pSt_AIClient, (LPCXSTR)lpszMsgBuffer + nPos, nMsgLen - nPos, bSSEReply);
333489
}

0 commit comments

Comments
 (0)