@@ -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\n Authorization: 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