test(addon/aikefu): 还原原先的kefu.app 方便测试

This commit is contained in:
2025-12-06 16:54:34 +08:00
parent a90a081973
commit 6a44d27fd3

View File

@@ -131,6 +131,7 @@ class Kefu extends BaseApi
], 500);
}
}
/**
* 获得AI服务的配置信息发送给客户端
* @return \think\response\Json
@@ -325,6 +326,175 @@ class Kefu extends BaseApi
return $this->response($this->error('请求失败:' . $e->getMessage()));
}
}
/**
* 智能客服聊天流式接口
*/
public function chatStream()
{
// 获取请求参数
$message = $this->params['message'] ?? '';
$user_id = $this->params['user_id'] ?? $this->member_id;
$conversation_id = $this->params['conversation_id'] ?? '';
$stream = true;
// (可选获取站点ID和会员ID可以通过事件数据传递
$site_id = $this->params['uniacid'] ?? $this->site_id; // 使用 uniacid, 方便以后迁移而且uniacid 是唯一的, site_id 不是同时被params给过滤了
$member_id = $this->params['member_id'] ?? $this->member_id;
$token = $this->params['token'] ?? $this->token;
// 验证参数
if (empty($message)) {
$this->sendStreamError('请输入消息内容');
exit;
}
// 准备事件数据
$event_data = [
'message' => $message,
'user_id' => $user_id,
'conversation_id' => $conversation_id,
'stream' => $stream,
'site_id' =>$site_id,
'member_id' => $member_id,
'token' => $token,
'request_id' => uniqid('stream_', true),
'timestamp' => time(),
];
try {
// 设置流式响应头
$this->setStreamHeaders();
// 发送开始事件
$this->sendStreamEvent('start', [
'request_id' => $event_data['request_id'],
'timestamp' => $event_data['timestamp'],
'message' => '开始处理请求'
]);
// 触发流式聊天事件
$result = Event::trigger('KefuChatStream', $event_data);
// 处理事件结果并流式输出
$this->processStreamResults($result, $event_data);
} catch (\Exception $e) {
$this->sendStreamError('请求失败:' . $e->getMessage());
}
}
/**
* 设置流式响应头
*/
private function setStreamHeaders()
{
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');
header('Connection: keep-alive');
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Headers: Cache-Control, Content-Type');
header('X-Accel-Buffering: no'); // 禁用nginx缓冲
if (function_exists('apache_setenv')) {
apache_setenv('no-gzip', '1');
}
}
/**
* 发送流式事件
*/
private function sendStreamEvent($event_type, $data)
{
$payload = [
'id' => uniqid(),
'event' => $event_type,
'timestamp' => time(),
'data' => $data
];
echo "event: {$event_type}\n";
echo "data: " . json_encode($payload, JSON_UNESCAPED_UNICODE) . "\n\n";
if (ob_get_level()) {
ob_flush();
}
flush();
}
/**
* 发送流式错误
*/
private function sendStreamError($message)
{
if (!headers_sent()) {
$this->setStreamHeaders();
}
$this->sendStreamEvent('error', [
'error' => $message,
'finished' => true
]);
exit;
}
/**
* 处理流式结果
*/
private function processStreamResults($results, $event_data)
{
try {
if (is_array($results) && !empty($results)) {
foreach ($results as $result) {
if (isset($result['type'])) {
switch ($result['type']) {
case 'chunk':
// 发送内容块
$this->sendStreamEvent('message', [
'content' => $result['content'] ?? '',
'conversation_id' => $result['conversation_id'] ?? $event_data['conversation_id'],
'message_id' => $result['message_id'] ?? '',
'finished' => $result['finished'] ?? false
]);
break;
case 'error':
// 发送错误
$this->sendStreamEvent('error', [
'error' => $result['message'] ?? '未知错误',
'conversation_id' => $result['conversation_id'] ?? $event_data['conversation_id']
]);
break;
case 'complete':
// 发送完成事件
$this->sendStreamEvent('complete', [
'conversation_id' => $result['conversation_id'] ?? $event_data['conversation_id'],
'message_id' => $result['message_id'] ?? '',
'usage' => $result['usage'] ?? [],
'finish_reason' => $result['finish_reason'] ?? ''
]);
break;
}
}
}
} else {
// 如果没有事件处理器或结果为空,发送完成事件
$this->sendStreamEvent('complete', [
'conversation_id' => $event_data['conversation_id'],
'message' => '暂无可用响应'
]);
}
// 发送结束事件
$this->sendStreamEvent('end', [
'request_id' => $event_data['request_id'],
'status' => 'completed'
]);
} catch (\Exception $e) {
$this->sendStreamError('处理流式结果失败:' . $e->getMessage());
}
}
/**
* 创建新会话