AI对话功能优化
This commit is contained in:
@@ -76,7 +76,7 @@ class CozeAI extends Controller
|
|||||||
$result = requestCurl($this->apiUrl . '/v1/bot/create', $params, 'POST', $this->headers, 'json');
|
$result = requestCurl($this->apiUrl . '/v1/bot/create', $params, 'POST', $this->headers, 'json');
|
||||||
$result = json_decode($result, true);
|
$result = json_decode($result, true);
|
||||||
if ($result['code'] != 0) {
|
if ($result['code'] != 0) {
|
||||||
return errorJson($result['msg'], $result['code']);
|
return json_encode(['code' => $result['code'], 'msg' => $result['msg'], 'data' => []]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return json_encode(['code' => 200, 'msg' => '创建成功', 'data' => $result['data']]);
|
return json_encode(['code' => 200, 'msg' => '创建成功', 'data' => $result['data']]);
|
||||||
@@ -136,9 +136,9 @@ class CozeAI extends Controller
|
|||||||
$result = requestCurl($this->apiUrl . '/v1/bot/update', $params, 'POST', $this->headers, 'json');
|
$result = requestCurl($this->apiUrl . '/v1/bot/update', $params, 'POST', $this->headers, 'json');
|
||||||
$result = json_decode($result, true);
|
$result = json_decode($result, true);
|
||||||
if ($result['code'] != 0) {
|
if ($result['code'] != 0) {
|
||||||
return errorJson($result['msg'], $result['code']);
|
return json_encode(['code' => $result['code'], 'msg' => $result['msg'], 'data' => []]);
|
||||||
}
|
}
|
||||||
return json_encode(['code' => 200, 'msg' => '获取成功']);
|
return json_encode(['code' => 200, 'msg' => '更新成功', 'data' => []]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -162,9 +162,9 @@ class CozeAI extends Controller
|
|||||||
$result = requestCurl($this->apiUrl . '/v1/bot/publish', $params, 'POST', $this->headers, 'json');
|
$result = requestCurl($this->apiUrl . '/v1/bot/publish', $params, 'POST', $this->headers, 'json');
|
||||||
$result = json_decode($result, true);
|
$result = json_decode($result, true);
|
||||||
if ($result['code'] != 0) {
|
if ($result['code'] != 0) {
|
||||||
return errorJson($result['msg'], $result['code']);
|
return json_encode(['code' => $result['code'], 'msg' => $result['msg'], 'data' => []]);
|
||||||
}
|
}
|
||||||
return json_encode(['code' => 200, 'msg' => '发布成功']);
|
return json_encode(['code' => 200, 'msg' => '发布成功', 'data' => []]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -191,7 +191,7 @@ class CozeAI extends Controller
|
|||||||
$result = json_decode($result, true);
|
$result = json_decode($result, true);
|
||||||
|
|
||||||
if ($result['code'] != 0) {
|
if ($result['code'] != 0) {
|
||||||
return errorJson($result['msg'], $result['code']);
|
return json_encode(['code' => $result['code'], 'msg' => $result['msg'], 'data' => []]);
|
||||||
}
|
}
|
||||||
return json_encode(['code' => 200, 'msg' => '创建成功','data' => $result['data']]);
|
return json_encode(['code' => 200, 'msg' => '创建成功','data' => $result['data']]);
|
||||||
}
|
}
|
||||||
@@ -231,7 +231,7 @@ class CozeAI extends Controller
|
|||||||
$result = requestCurl($this->apiUrl . '/open_api/knowledge/document/create', $params, 'POST', $headers, 'json');
|
$result = requestCurl($this->apiUrl . '/open_api/knowledge/document/create', $params, 'POST', $headers, 'json');
|
||||||
$result = json_decode($result, true);
|
$result = json_decode($result, true);
|
||||||
if ($result['code'] != 0) {
|
if ($result['code'] != 0) {
|
||||||
return errorJson($result['msg'], $result['code']);
|
return json_encode(['code' => $result['code'], 'msg' => $result['msg'], 'data' => []]);
|
||||||
}
|
}
|
||||||
return json_encode(['code' => 200, 'msg' => '创建成功','data' => $result['document_infos']]);
|
return json_encode(['code' => 200, 'msg' => '创建成功','data' => $result['document_infos']]);
|
||||||
}
|
}
|
||||||
@@ -254,9 +254,9 @@ class CozeAI extends Controller
|
|||||||
$result = requestCurl($this->apiUrl . '/open_api/knowledge/document/delete', $params, 'POST', $headers, 'json');
|
$result = requestCurl($this->apiUrl . '/open_api/knowledge/document/delete', $params, 'POST', $headers, 'json');
|
||||||
$result = json_decode($result, true);
|
$result = json_decode($result, true);
|
||||||
if ($result['code'] != 0) {
|
if ($result['code'] != 0) {
|
||||||
return errorJson($result['msg'], $result['code']);
|
return json_encode(['code' => $result['code'], 'msg' => $result['msg'], 'data' => []]);
|
||||||
}
|
}
|
||||||
return json_encode(['code' => 200, 'msg' => '删除成功']);
|
return json_encode(['code' => 200, 'msg' => '删除成功', 'data' => []]);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -285,7 +285,7 @@ class CozeAI extends Controller
|
|||||||
$result = requestCurl($this->apiUrl . '/v1/conversation/create', $params, 'POST', $this->headers, 'json');
|
$result = requestCurl($this->apiUrl . '/v1/conversation/create', $params, 'POST', $this->headers, 'json');
|
||||||
$result = json_decode($result, true);
|
$result = json_decode($result, true);
|
||||||
if ($result['code'] != 0) {
|
if ($result['code'] != 0) {
|
||||||
return errorJson($result['msg'], $result['code']);
|
return json_encode(['code' => $result['code'], 'msg' => $result['msg'], 'data' => []]);
|
||||||
}
|
}
|
||||||
return json_encode(['code' => 200, 'msg' => '创建成功','data' => $result['data']]);
|
return json_encode(['code' => 200, 'msg' => '创建成功','data' => $result['data']]);
|
||||||
}
|
}
|
||||||
@@ -306,15 +306,15 @@ class CozeAI extends Controller
|
|||||||
|
|
||||||
|
|
||||||
if(empty($bot_id)){
|
if(empty($bot_id)){
|
||||||
return errorJson('智能体ID不能为空');
|
return json_encode(['code' => 500, 'msg' => '智能体ID不能为空', 'data' => []]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(empty($conversation_id)){
|
if(empty($conversation_id)){
|
||||||
return errorJson('会话ID不能为空');
|
return json_encode(['code' => 500, 'msg' => '会话ID不能为空', 'data' => []]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(empty($question)){
|
if(empty($question)){
|
||||||
return errorJson('问题不能为空');
|
return json_encode(['code' => 500, 'msg' => '问题不能为空', 'data' => []]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 构建请求数据
|
// 构建请求数据
|
||||||
@@ -330,16 +330,21 @@ class CozeAI extends Controller
|
|||||||
$result = requestCurl($url, $params, 'POST', $this->headers, 'json');
|
$result = requestCurl($url, $params, 'POST', $this->headers, 'json');
|
||||||
$result = json_decode($result, true);
|
$result = json_decode($result, true);
|
||||||
if ($result['code'] != 0) {
|
if ($result['code'] != 0) {
|
||||||
return errorJson($result['msg'], $result['code']);
|
return json_encode(['code' => $result['code'], 'msg' => $result['msg'], 'data' => []]);
|
||||||
}
|
}
|
||||||
return json_encode(['code' => 200, 'msg' => '发送成功','data' => $result['data']]);
|
return json_encode(['code' => 200, 'msg' => '发送成功','data' => $result['data']]);
|
||||||
|
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
return errorJson('创建对话失败:' . $e->getMessage());
|
return json_encode(['code' => 500, 'msg' => '创建对话失败:' . $e->getMessage(), 'data' => []]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查看对话详情
|
||||||
|
* @param $data
|
||||||
|
* @return false|string|\think\response\Json
|
||||||
|
*/
|
||||||
public function getConversationChat($data = [])
|
public function getConversationChat($data = [])
|
||||||
{
|
{
|
||||||
$conversation_id = !empty($data['conversation_id']) ? $data['conversation_id'] : '';
|
$conversation_id = !empty($data['conversation_id']) ? $data['conversation_id'] : '';
|
||||||
@@ -348,12 +353,17 @@ class CozeAI extends Controller
|
|||||||
$result = requestCurl($url, [], 'GET', $this->headers, 'json');
|
$result = requestCurl($url, [], 'GET', $this->headers, 'json');
|
||||||
$result = json_decode($result, true);
|
$result = json_decode($result, true);
|
||||||
if ($result['code'] != 0) {
|
if ($result['code'] != 0) {
|
||||||
return errorJson($result['msg'], $result['code']);
|
return json_encode(['code' => $result['code'], 'msg' => $result['msg'], 'data' => []]);
|
||||||
}
|
}
|
||||||
return json_encode(['code' => 200, 'msg' => '发送成功','data' => $result['data']]);
|
return json_encode(['code' => 200, 'msg' => '获取成功','data' => $result['data']]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查看对话消息详情
|
||||||
|
* @param $data
|
||||||
|
* @return false|string|\think\response\Json
|
||||||
|
*/
|
||||||
public function listConversationMessage($data = [])
|
public function listConversationMessage($data = [])
|
||||||
{
|
{
|
||||||
$conversation_id = !empty($data['conversation_id']) ? $data['conversation_id'] : '';
|
$conversation_id = !empty($data['conversation_id']) ? $data['conversation_id'] : '';
|
||||||
@@ -362,9 +372,35 @@ class CozeAI extends Controller
|
|||||||
$result = requestCurl($url, [], 'GET', $this->headers, 'json');
|
$result = requestCurl($url, [], 'GET', $this->headers, 'json');
|
||||||
$result = json_decode($result, true);
|
$result = json_decode($result, true);
|
||||||
if ($result['code'] != 0) {
|
if ($result['code'] != 0) {
|
||||||
return errorJson($result['msg'], $result['code']);
|
return json_encode(['code' => $result['code'], 'msg' => $result['msg'], 'data' => []]);
|
||||||
}
|
}
|
||||||
return json_encode(['code' => 200, 'msg' => '发送成功','data' => $result['data']]);
|
return json_encode(['code' => 200, 'msg' => '获取成功','data' => $result['data']]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 取消进行中的对话
|
||||||
|
* @param $data
|
||||||
|
* @return false|string|\think\response\Json
|
||||||
|
*/
|
||||||
|
public function cancelConversationChat($data = [])
|
||||||
|
{
|
||||||
|
$conversation_id = !empty($data['conversation_id']) ? $data['conversation_id'] : '';
|
||||||
|
$chat_id = !empty($data['chat_id']) ? $data['chat_id'] : '';
|
||||||
|
|
||||||
|
// 构建请求数据
|
||||||
|
$params = [
|
||||||
|
'conversation_id' => (string) $conversation_id,
|
||||||
|
'chat_id' => (string) $chat_id
|
||||||
|
];
|
||||||
|
|
||||||
|
$url = $this->apiUrl . '/v3/chat/cancel';
|
||||||
|
$result = requestCurl($url, $params, 'POST', $this->headers, 'json');
|
||||||
|
$result = json_decode($result, true);
|
||||||
|
if ($result['code'] != 0) {
|
||||||
|
return json_encode(['code' => $result['code'], 'msg' => $result['msg'], 'data' => []]);
|
||||||
|
}
|
||||||
|
return json_encode(['code' => 200, 'msg' => '取消成功', 'data' => []]);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -12,10 +12,12 @@ Route::group('v1/', function () {
|
|||||||
//好友相关
|
//好友相关
|
||||||
Route::group('wechatFriend/', function () {
|
Route::group('wechatFriend/', function () {
|
||||||
Route::get('list', 'app\chukebao\controller\WechatFriendController@getList'); // 获取好友列表
|
Route::get('list', 'app\chukebao\controller\WechatFriendController@getList'); // 获取好友列表
|
||||||
|
Route::get('detail', 'app\chukebao\controller\WechatFriendController@getDetail'); // 获取好友详情
|
||||||
});
|
});
|
||||||
//群相关
|
//群相关
|
||||||
Route::group('wechatChatroom/', function () {
|
Route::group('wechatChatroom/', function () {
|
||||||
Route::get('list', 'app\chukebao\controller\WechatChatroomController@getList'); // 获取好友列表
|
Route::get('list', 'app\chukebao\controller\WechatChatroomController@getList'); // 获取好友列表
|
||||||
|
Route::get('detail', 'app\chukebao\controller\WechatChatroomController@getDetail'); // 获取群详情
|
||||||
Route::post('aiAnnouncement', 'app\chukebao\controller\WechatChatroomController@aiAnnouncement'); // AI群公告
|
Route::post('aiAnnouncement', 'app\chukebao\controller\WechatChatroomController@aiAnnouncement'); // AI群公告
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,9 @@ use app\chukebao\model\FriendSettings;
|
|||||||
use app\chukebao\model\TokensCompany;
|
use app\chukebao\model\TokensCompany;
|
||||||
use library\ResponseHelper;
|
use library\ResponseHelper;
|
||||||
use think\Db;
|
use think\Db;
|
||||||
|
use think\facade\Cache;
|
||||||
|
use think\facade\Log;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* AI聊天控制器
|
* AI聊天控制器
|
||||||
@@ -27,8 +30,16 @@ class AiChatController extends BaseController
|
|||||||
const STATUS_CANCELED = 'canceled'; // 对话已取消
|
const STATUS_CANCELED = 'canceled'; // 对话已取消
|
||||||
|
|
||||||
// 轮询配置
|
// 轮询配置
|
||||||
const MAX_RETRY_TIMES = 30; // 最大重试次数
|
const MAX_RETRY_TIMES = 1000; // 最大重试次数
|
||||||
const RETRY_INTERVAL = 2; // 重试间隔(秒)
|
const RETRY_INTERVAL = 500000; // 重试间隔(微秒,即500毫秒)
|
||||||
|
|
||||||
|
// 并发控制
|
||||||
|
const CACHE_EXPIRE = 30; // 缓存过期时间(秒)
|
||||||
|
|
||||||
|
// 请求唯一标识符
|
||||||
|
private $requestKey = '';
|
||||||
|
private $requestId = '';
|
||||||
|
private $currentStep = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* AI聊天主入口
|
* AI聊天主入口
|
||||||
@@ -40,59 +51,219 @@ class AiChatController extends BaseController
|
|||||||
try {
|
try {
|
||||||
// 1. 参数验证和初始化
|
// 1. 参数验证和初始化
|
||||||
$params = $this->validateAndInitParams();
|
$params = $this->validateAndInitParams();
|
||||||
|
|
||||||
if ($params === false) {
|
if ($params === false) {
|
||||||
return ResponseHelper::error('参数验证失败');
|
return ResponseHelper::error('参数验证失败');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 并发控制:检查并处理同一用户的重复请求
|
||||||
|
$this->requestKey = "aichat_{$params['friendId']}_{$params['wechatAccountId']}";
|
||||||
|
$this->requestId = uniqid('req_', true);
|
||||||
|
|
||||||
|
$concurrentCheck = $this->handleConcurrentRequest($params);
|
||||||
|
if ($concurrentCheck !== true) {
|
||||||
|
return $concurrentCheck; // 返回错误响应
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->currentStep = 1;
|
||||||
|
|
||||||
// 2. 验证Tokens余额
|
// 2. 验证Tokens余额
|
||||||
if (!$this->checkTokensBalance($params['companyId'])) {
|
$this->updateRequestStep(2);
|
||||||
|
if ($this->isRequestCanceled()) {
|
||||||
|
return ResponseHelper::error('该好友有新的AI对话请求正在处理中,当前请求已被取消');
|
||||||
|
}
|
||||||
|
$hasBalance = $this->checkTokensBalance($params['companyId']);
|
||||||
|
|
||||||
|
if (!$hasBalance) {
|
||||||
|
$this->clearRequestCache();
|
||||||
return ResponseHelper::error('Tokens余额不足,请充值后再试');
|
return ResponseHelper::error('Tokens余额不足,请充值后再试');
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. 获取AI配置
|
// 3. 获取AI配置
|
||||||
|
$this->updateRequestStep(3);
|
||||||
|
if ($this->isRequestCanceled()) {
|
||||||
|
return ResponseHelper::error('该好友有新的AI对话请求正在处理中,当前请求已被取消');
|
||||||
|
}
|
||||||
$setting = $this->getAiSettings($params['companyId']);
|
$setting = $this->getAiSettings($params['companyId']);
|
||||||
|
|
||||||
if (!$setting) {
|
if (!$setting) {
|
||||||
|
$this->clearRequestCache();
|
||||||
return ResponseHelper::error('未找到AI配置信息,请先配置AI策略');
|
return ResponseHelper::error('未找到AI配置信息,请先配置AI策略');
|
||||||
}
|
}
|
||||||
|
|
||||||
// 4. 获取好友AI设置
|
// 4. 获取好友AI设置
|
||||||
|
$this->updateRequestStep(4);
|
||||||
|
if ($this->isRequestCanceled()) {
|
||||||
|
return ResponseHelper::error('该好友有新的AI对话请求正在处理中,当前请求已被取消');
|
||||||
|
}
|
||||||
$friendSettings = $this->getFriendSettings($params['companyId'], $params['friendId']);
|
$friendSettings = $this->getFriendSettings($params['companyId'], $params['friendId']);
|
||||||
|
|
||||||
if (!$friendSettings) {
|
if (!$friendSettings) {
|
||||||
|
$this->clearRequestCache();
|
||||||
return ResponseHelper::error('该好友未配置或未开启AI功能');
|
return ResponseHelper::error('该好友未配置或未开启AI功能');
|
||||||
}
|
}
|
||||||
|
|
||||||
// 5. 确保会话存在
|
// 5. 确保会话存在
|
||||||
|
$this->updateRequestStep(5);
|
||||||
|
if ($this->isRequestCanceled()) {
|
||||||
|
return ResponseHelper::error('该好友有新的AI对话请求正在处理中,当前请求已被取消');
|
||||||
|
}
|
||||||
$conversationId = $this->ensureConversation($friendSettings, $setting, $params);
|
$conversationId = $this->ensureConversation($friendSettings, $setting, $params);
|
||||||
|
|
||||||
if (!$conversationId) {
|
if (!$conversationId) {
|
||||||
|
$this->clearRequestCache();
|
||||||
return ResponseHelper::error('创建会话失败');
|
return ResponseHelper::error('创建会话失败');
|
||||||
}
|
}
|
||||||
|
|
||||||
// 6. 获取历史消息
|
// 6. 获取历史消息
|
||||||
|
$this->updateRequestStep(6);
|
||||||
|
if ($this->isRequestCanceled()) {
|
||||||
|
return ResponseHelper::error('该好友有新的AI对话请求正在处理中,当前请求已被取消');
|
||||||
|
}
|
||||||
$msgData = $this->getHistoryMessages($params['friendId'], $friendSettings);
|
$msgData = $this->getHistoryMessages($params['friendId'], $friendSettings);
|
||||||
|
|
||||||
// 7. 创建AI对话
|
// 7. 创建AI对话(从这步开始需要保存对话ID以便取消)
|
||||||
|
$this->updateRequestStep(7);
|
||||||
|
if ($this->isRequestCanceled($conversationId, null)) {
|
||||||
|
return ResponseHelper::error('该好友有新的AI对话请求正在处理中,当前请求已被取消');
|
||||||
|
}
|
||||||
$chatId = $this->createAiChat($setting, $friendSettings, $msgData);
|
$chatId = $this->createAiChat($setting, $friendSettings, $msgData);
|
||||||
|
|
||||||
if (!$chatId) {
|
if (!$chatId) {
|
||||||
|
$this->clearRequestCache();
|
||||||
return ResponseHelper::error('创建对话失败');
|
return ResponseHelper::error('创建对话失败');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 保存对话ID到缓存,以便新请求可以取消
|
||||||
|
$this->updateRequestStep(7, $conversationId, $chatId);
|
||||||
|
|
||||||
// 8. 等待AI处理完成(轮询)
|
// 8. 等待AI处理完成(轮询)
|
||||||
$chatResult = $this->waitForChatCompletion($conversationId, $chatId);
|
$this->updateRequestStep(8, $conversationId, $chatId);
|
||||||
if (!$chatResult) {
|
if ($this->isRequestCanceled($conversationId, $chatId)) {
|
||||||
return ResponseHelper::error('AI处理超时或失败');
|
return ResponseHelper::error('该好友有新的AI对话请求正在处理中,当前请求已被取消');
|
||||||
}
|
}
|
||||||
|
$chatResult = $this->waitForChatCompletion($conversationId, $chatId);
|
||||||
|
|
||||||
|
if (!$chatResult['success']) {
|
||||||
|
$this->clearRequestCache();
|
||||||
|
return ResponseHelper::error($chatResult['error']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$chatResult = $chatResult['data'];
|
||||||
|
|
||||||
// 9. 扣除Tokens
|
// 9. 扣除Tokens
|
||||||
|
$this->updateRequestStep(9, $conversationId, $chatId);
|
||||||
|
if ($this->isRequestCanceled($conversationId, $chatId)) {
|
||||||
|
return ResponseHelper::error('该好友有新的AI对话请求正在处理中,当前请求已被取消');
|
||||||
|
}
|
||||||
$this->consumeTokens($chatResult, $params, $friendSettings);
|
$this->consumeTokens($chatResult, $params, $friendSettings);
|
||||||
|
|
||||||
// 10. 获取对话消息
|
// 10. 获取对话消息
|
||||||
|
$this->updateRequestStep(10, $conversationId, $chatId);
|
||||||
|
if ($this->isRequestCanceled($conversationId, $chatId)) {
|
||||||
|
return ResponseHelper::error('该好友有新的AI对话请求正在处理中,当前请求已被取消');
|
||||||
|
}
|
||||||
$messages = $this->getChatMessages($conversationId, $chatId);
|
$messages = $this->getChatMessages($conversationId, $chatId);
|
||||||
|
|
||||||
if (!$messages) {
|
if (!$messages) {
|
||||||
return ResponseHelper::error('获取对话消息失败');
|
return ResponseHelper::error('获取对话消息失败');
|
||||||
}
|
}
|
||||||
return ResponseHelper::success($messages[1]['content'], '对话成功');
|
|
||||||
|
// 筛选type为answer的消息(AI回复的内容)
|
||||||
|
$answerContent = '';
|
||||||
|
foreach ($messages as $msg) {
|
||||||
|
if (isset($msg['type']) && $msg['type'] === 'answer') {
|
||||||
|
$answerContent = $msg['content'] ?? '';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty($answerContent)) {
|
||||||
|
Log::warning('未找到AI回复内容,messages: ' . json_encode($messages));
|
||||||
|
return ResponseHelper::error('未获取到AI回复内容');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 清理请求缓存
|
||||||
|
$this->clearRequestCache();
|
||||||
|
|
||||||
|
// 返回结果
|
||||||
|
return ResponseHelper::success(['content' => $answerContent], '对话成功');
|
||||||
|
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
\think\facade\Log::error('AI聊天异常:' . $e->getMessage());
|
Log::error('AI聊天异常:' . $e->getMessage());
|
||||||
|
|
||||||
|
// 清理请求缓存
|
||||||
|
$this->clearRequestCache();
|
||||||
|
|
||||||
|
return ResponseHelper::error('系统异常:' . $e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 取消AI对话
|
||||||
|
* 取消当前正在进行的AI对话请求
|
||||||
|
*
|
||||||
|
* @return \think\response\Json
|
||||||
|
*/
|
||||||
|
public function cancel()
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
// 获取参数
|
||||||
|
$friendId = $this->request->param('friendId', '');
|
||||||
|
$wechatAccountId = $this->request->param('wechatAccountId', '');
|
||||||
|
|
||||||
|
if (empty($wechatAccountId) || empty($friendId)) {
|
||||||
|
return ResponseHelper::error('参数缺失');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 生成缓存键
|
||||||
|
$requestKey = "aichat_{$friendId}_{$wechatAccountId}";
|
||||||
|
|
||||||
|
// 获取缓存数据
|
||||||
|
$cacheData = Cache::get($requestKey);
|
||||||
|
|
||||||
|
if (!$cacheData) {
|
||||||
|
return ResponseHelper::error('当前没有正在进行的AI对话');
|
||||||
|
}
|
||||||
|
|
||||||
|
$requestId = $cacheData['request_id'] ?? '';
|
||||||
|
$step = $cacheData['step'] ?? 0;
|
||||||
|
$conversationId = $cacheData['conversation_id'] ?? '';
|
||||||
|
$chatId = $cacheData['chat_id'] ?? '';
|
||||||
|
|
||||||
|
Log::info("手动取消AI对话 - 请求ID: {$requestId}, 步骤: {$step}");
|
||||||
|
|
||||||
|
// 如果已经到达步骤7或之后,需要调用取消API
|
||||||
|
if ($step >= 7 && !empty($conversationId) && !empty($chatId)) {
|
||||||
|
try {
|
||||||
|
$cozeAI = new CozeAI();
|
||||||
|
$cancelResult = $cozeAI->cancelConversationChat([
|
||||||
|
'conversation_id' => $conversationId,
|
||||||
|
'chat_id' => $chatId,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$result = json_decode($cancelResult, true);
|
||||||
|
if ($result['code'] != 200) {
|
||||||
|
Log::error("调用取消API失败 - conversation_id: {$conversationId}, chat_id: {$chatId}, 错误: " . ($result['msg'] ?? '未知错误'));
|
||||||
|
} else {
|
||||||
|
Log::info("成功调用取消API - conversation_id: {$conversationId}, chat_id: {$chatId}");
|
||||||
|
}
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Log::error("调用取消API异常:" . $e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 清理缓存
|
||||||
|
Cache::rm($requestKey);
|
||||||
|
Log::info("已清理AI对话缓存 - 请求ID: {$requestId}");
|
||||||
|
|
||||||
|
return ResponseHelper::success([
|
||||||
|
'canceled_request_id' => $requestId,
|
||||||
|
'step' => $step
|
||||||
|
], 'AI对话已取消');
|
||||||
|
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Log::error('取消AI对话异常:' . $e->getMessage());
|
||||||
return ResponseHelper::error('系统异常:' . $e->getMessage());
|
return ResponseHelper::error('系统异常:' . $e->getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -194,7 +365,7 @@ class AiChatController extends BaseController
|
|||||||
$res = json_decode($res, true);
|
$res = json_decode($res, true);
|
||||||
|
|
||||||
if ($res['code'] != 200) {
|
if ($res['code'] != 200) {
|
||||||
\think\facade\Log::error('创建会话失败:' . ($res['msg'] ?? '未知错误'));
|
Log::error('创建会话失败:' . ($res['msg'] ?? '未知错误'));
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -292,7 +463,7 @@ class AiChatController extends BaseController
|
|||||||
$res = json_decode($res, true);
|
$res = json_decode($res, true);
|
||||||
|
|
||||||
if ($res['code'] != 200) {
|
if ($res['code'] != 200) {
|
||||||
\think\facade\Log::error('创建对话失败:' . ($res['msg'] ?? '未知错误'));
|
Log::error('创建对话失败:' . ($res['msg'] ?? '未知错误'));
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -304,7 +475,7 @@ class AiChatController extends BaseController
|
|||||||
*
|
*
|
||||||
* @param string $conversationId 会话ID
|
* @param string $conversationId 会话ID
|
||||||
* @param string $chatId 对话ID
|
* @param string $chatId 对话ID
|
||||||
* @return array|null
|
* @return array ['success' => bool, 'data' => array|null, 'error' => string]
|
||||||
*/
|
*/
|
||||||
private function waitForChatCompletion($conversationId, $chatId)
|
private function waitForChatCompletion($conversationId, $chatId)
|
||||||
{
|
{
|
||||||
@@ -320,8 +491,9 @@ class AiChatController extends BaseController
|
|||||||
$res = json_decode($res, true);
|
$res = json_decode($res, true);
|
||||||
|
|
||||||
if ($res['code'] != 200) {
|
if ($res['code'] != 200) {
|
||||||
\think\facade\Log::error('获取对话状态失败:' . ($res['msg'] ?? '未知错误'));
|
$errorMsg = 'AI接口调用失败:' . ($res['msg'] ?? '未知错误');
|
||||||
return null;
|
Log::error($errorMsg);
|
||||||
|
return ['success' => false, 'data' => null, 'error' => $errorMsg];
|
||||||
}
|
}
|
||||||
|
|
||||||
$status = $res['data']['status'] ?? '';
|
$status = $res['data']['status'] ?? '';
|
||||||
@@ -330,36 +502,41 @@ class AiChatController extends BaseController
|
|||||||
switch ($status) {
|
switch ($status) {
|
||||||
case self::STATUS_COMPLETED:
|
case self::STATUS_COMPLETED:
|
||||||
// 对话完成,返回结果
|
// 对话完成,返回结果
|
||||||
return $res['data'];
|
return ['success' => true, 'data' => $res['data'], 'error' => ''];
|
||||||
|
|
||||||
case self::STATUS_IN_PROGRESS:
|
case self::STATUS_IN_PROGRESS:
|
||||||
case self::STATUS_CREATED:
|
case self::STATUS_CREATED:
|
||||||
// 继续等待
|
// 继续等待
|
||||||
$retryCount++;
|
$retryCount++;
|
||||||
sleep(self::RETRY_INTERVAL);
|
usleep(self::RETRY_INTERVAL);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case self::STATUS_FAILED:
|
case self::STATUS_FAILED:
|
||||||
\think\facade\Log::error('对话失败,chat_id: ' . $chatId);
|
$errorMsg = 'AI对话处理失败';
|
||||||
return null;
|
Log::error($errorMsg . ',chat_id: ' . $chatId);
|
||||||
|
return ['success' => false, 'data' => null, 'error' => $errorMsg];
|
||||||
|
|
||||||
case self::STATUS_CANCELED:
|
case self::STATUS_CANCELED:
|
||||||
\think\facade\Log::error('对话已取消,chat_id: ' . $chatId);
|
$errorMsg = 'AI对话已被取消';
|
||||||
return null;
|
Log::error($errorMsg . ',chat_id: ' . $chatId);
|
||||||
|
return ['success' => false, 'data' => null, 'error' => $errorMsg];
|
||||||
|
|
||||||
case self::STATUS_REQUIRES_ACTION:
|
case self::STATUS_REQUIRES_ACTION:
|
||||||
\think\facade\Log::warning('对话需要进一步处理,chat_id: ' . $chatId);
|
$errorMsg = 'AI对话需要进一步处理';
|
||||||
return null;
|
Log::warning($errorMsg . ',chat_id: ' . $chatId);
|
||||||
|
return ['success' => false, 'data' => null, 'error' => $errorMsg];
|
||||||
|
|
||||||
default:
|
default:
|
||||||
\think\facade\Log::error('未知状态:' . $status);
|
$errorMsg = 'AI返回未知状态:' . $status;
|
||||||
return null;
|
Log::error($errorMsg);
|
||||||
|
return ['success' => false, 'data' => null, 'error' => $errorMsg];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 超时
|
// 超时
|
||||||
\think\facade\Log::error('对话处理超时,chat_id: ' . $chatId);
|
$errorMsg = 'AI对话处理超时,已等待' . (self::MAX_RETRY_TIMES * self::RETRY_INTERVAL / 1000000) . '秒';
|
||||||
return null;
|
Log::error($errorMsg . ',chat_id: ' . $chatId);
|
||||||
|
return ['success' => false, 'data' => null, 'error' => $errorMsg];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -412,13 +589,154 @@ class AiChatController extends BaseController
|
|||||||
$res = json_decode($res, true);
|
$res = json_decode($res, true);
|
||||||
|
|
||||||
if ($res['code'] != 200) {
|
if ($res['code'] != 200) {
|
||||||
\think\facade\Log::error('获取对话消息失败:' . ($res['msg'] ?? '未知错误'));
|
Log::error('获取对话消息失败:' . ($res['msg'] ?? '未知错误'));
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $res['data'] ?? [];
|
return $res['data'] ?? [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理并发请求
|
||||||
|
* 检查是否有同一用户的旧请求正在处理,如果有则取消旧请求
|
||||||
|
*
|
||||||
|
* @param array $params 请求参数
|
||||||
|
* @return true|\think\response\Json true表示可以继续,否则返回错误响应
|
||||||
|
*/
|
||||||
|
private function handleConcurrentRequest($params)
|
||||||
|
{
|
||||||
|
$cacheData = Cache::get($this->requestKey);
|
||||||
|
|
||||||
|
if ($cacheData) {
|
||||||
|
// 有旧请求正在处理
|
||||||
|
$oldRequestId = $cacheData['request_id'] ?? '';
|
||||||
|
$oldStep = $cacheData['step'] ?? 0;
|
||||||
|
$oldConversationId = $cacheData['conversation_id'] ?? '';
|
||||||
|
$oldChatId = $cacheData['chat_id'] ?? '';
|
||||||
|
|
||||||
|
Log::info("检测到并发请求 - 旧请求: {$oldRequestId} (步骤{$oldStep}), 新请求: {$this->requestId}");
|
||||||
|
|
||||||
|
// 如果旧请求已经到达步骤7或之后,需要调用取消API
|
||||||
|
if ($oldStep >= 7 && !empty($oldConversationId) && !empty($oldChatId)) {
|
||||||
|
try {
|
||||||
|
$cozeAI = new CozeAI();
|
||||||
|
$cancelResult = $cozeAI->cancelConversationChat([
|
||||||
|
'conversation_id' => $oldConversationId,
|
||||||
|
'chat_id' => $oldChatId,
|
||||||
|
]);
|
||||||
|
Log::info("已调用取消API取消旧请求的对话 - conversation_id: {$oldConversationId}, chat_id: {$oldChatId}");
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Log::error("取消旧请求对话失败:" . $e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 标记旧请求为已取消(通过更新缓存的 canceled 标志)
|
||||||
|
$cacheData['canceled'] = true;
|
||||||
|
$cacheData['canceled_by'] = $this->requestId;
|
||||||
|
Cache::set($this->requestKey, $cacheData, self::CACHE_EXPIRE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置当前请求为活动请求
|
||||||
|
$newCacheData = [
|
||||||
|
'request_id' => $this->requestId,
|
||||||
|
'step' => 1,
|
||||||
|
'start_time' => time(),
|
||||||
|
'canceled' => false,
|
||||||
|
'conversation_id' => '',
|
||||||
|
'chat_id' => '',
|
||||||
|
];
|
||||||
|
Cache::set($this->requestKey, $newCacheData, self::CACHE_EXPIRE);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查当前请求是否被新请求取消
|
||||||
|
*
|
||||||
|
* @param string $conversationId 会话ID(可选,用于取消对话)
|
||||||
|
* @param string $chatId 对话ID(可选,用于取消对话)
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
private function isRequestCanceled($conversationId = '', $chatId = '')
|
||||||
|
{
|
||||||
|
$cacheData = Cache::get($this->requestKey);
|
||||||
|
|
||||||
|
if (!$cacheData) {
|
||||||
|
// 缓存不存在,说明被清理或过期,视为被取消
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
$currentRequestId = $cacheData['request_id'] ?? '';
|
||||||
|
$isCanceled = $cacheData['canceled'] ?? false;
|
||||||
|
|
||||||
|
// 如果缓存中的请求ID与当前请求ID不一致,或者被标记为取消
|
||||||
|
if ($currentRequestId !== $this->requestId || $isCanceled) {
|
||||||
|
Log::info("当前请求已被取消 - 请求ID: {$this->requestId}, 缓存请求ID: {$currentRequestId}, 取消标志: " . ($isCanceled ? 'true' : 'false'));
|
||||||
|
|
||||||
|
// 如果提供了对话ID,尝试取消对话
|
||||||
|
if (!empty($conversationId) && !empty($chatId) && $this->currentStep >= 7) {
|
||||||
|
try {
|
||||||
|
$cozeAI = new CozeAI();
|
||||||
|
$cancelResult = $cozeAI->cancelConversationChat([
|
||||||
|
'conversation_id' => $conversationId,
|
||||||
|
'chat_id' => $chatId,
|
||||||
|
]);
|
||||||
|
Log::info("已取消当前请求的对话 - conversation_id: {$conversationId}, chat_id: {$chatId}");
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Log::error("取消当前请求对话失败:" . $e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新请求步骤
|
||||||
|
*
|
||||||
|
* @param int $step 当前步骤
|
||||||
|
* @param string $conversationId 会话ID(可选)
|
||||||
|
* @param string $chatId 对话ID(可选)
|
||||||
|
*/
|
||||||
|
private function updateRequestStep($step, $conversationId = '', $chatId = '')
|
||||||
|
{
|
||||||
|
$this->currentStep = $step;
|
||||||
|
|
||||||
|
$cacheData = Cache::get($this->requestKey);
|
||||||
|
|
||||||
|
if ($cacheData && $cacheData['request_id'] === $this->requestId) {
|
||||||
|
$cacheData['step'] = $step;
|
||||||
|
$cacheData['update_time'] = time();
|
||||||
|
|
||||||
|
if (!empty($conversationId)) {
|
||||||
|
$cacheData['conversation_id'] = $conversationId;
|
||||||
|
}
|
||||||
|
if (!empty($chatId)) {
|
||||||
|
$cacheData['chat_id'] = $chatId;
|
||||||
|
}
|
||||||
|
|
||||||
|
Cache::set($this->requestKey, $cacheData, self::CACHE_EXPIRE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 清理请求缓存
|
||||||
|
*/
|
||||||
|
private function clearRequestCache()
|
||||||
|
{
|
||||||
|
if (!empty($this->requestKey)) {
|
||||||
|
$cacheData = Cache::get($this->requestKey);
|
||||||
|
|
||||||
|
// 只有当前请求才能清理自己的缓存
|
||||||
|
if ($cacheData && isset($cacheData['request_id']) && $cacheData['request_id'] === $this->requestId) {
|
||||||
|
Cache::rm($this->requestKey);
|
||||||
|
Log::info("已清理请求缓存 - 请求ID: {$this->requestId}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public function index2222()
|
public function index2222()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ class MessageController extends BaseController
|
|||||||
|
|
||||||
// 优化后的查询:使用MySQL兼容的查询方式
|
// 优化后的查询:使用MySQL兼容的查询方式
|
||||||
$unionQuery = "
|
$unionQuery = "
|
||||||
(SELECT m.id, m.content, m.wechatFriendId, m.wechatChatroomId, m.createTime, m.wechatTime, 2 as msgType, wc.nickname, wc.chatroomAvatar as avatar, wc.chatroomId
|
(SELECT m.id, m.content, m.wechatFriendId, m.wechatChatroomId, m.createTime, m.wechatTime,m.wechatAccountId, 2 as msgType, wc.nickname, wc.chatroomAvatar as avatar, wc.chatroomId
|
||||||
FROM s2_wechat_chatroom wc
|
FROM s2_wechat_chatroom wc
|
||||||
INNER JOIN s2_wechat_message m ON wc.id = m.wechatChatroomId AND m.type = 2
|
INNER JOIN s2_wechat_message m ON wc.id = m.wechatChatroomId AND m.type = 2
|
||||||
INNER JOIN (
|
INNER JOIN (
|
||||||
@@ -42,7 +42,7 @@ class MessageController extends BaseController
|
|||||||
WHERE wc.accountId = {$accountId} AND wc.isDeleted = 0
|
WHERE wc.accountId = {$accountId} AND wc.isDeleted = 0
|
||||||
)
|
)
|
||||||
UNION ALL
|
UNION ALL
|
||||||
(SELECT m.id, m.content, m.wechatFriendId, m.wechatChatroomId, m.createTime, m.wechatTime, 1 as msgType, 1 as nickname, 1 as avatar, 1 as chatroomId
|
(SELECT m.id, m.content, m.wechatFriendId, m.wechatChatroomId, m.createTime, m.wechatTime, 1 as msgType, 1 as nickname, 1 as avatar, 1 as chatroomId, 1 as wechatAccountId
|
||||||
FROM s2_wechat_message m
|
FROM s2_wechat_message m
|
||||||
INNER JOIN (
|
INNER JOIN (
|
||||||
SELECT wechatFriendId, MAX(wechatTime) as maxTime, MAX(id) as maxId
|
SELECT wechatFriendId, MAX(wechatTime) as maxTime, MAX(id) as maxId
|
||||||
|
|||||||
@@ -83,7 +83,51 @@ class WechatChatroomController extends BaseController
|
|||||||
return ResponseHelper::success(['list'=>$list,'total'=>$total]);
|
return ResponseHelper::success(['list'=>$list,'total'=>$total]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getDetail(){
|
||||||
|
$id = input('id', 0);
|
||||||
|
|
||||||
|
if (!$id) {
|
||||||
|
return ResponseHelper::error('聊天室ID不能为空');
|
||||||
|
}
|
||||||
|
|
||||||
|
$accountId = $this->getUserInfo('s2_accountId');
|
||||||
|
if (empty($accountId)){
|
||||||
|
return ResponseHelper::error('请先登录');
|
||||||
|
}
|
||||||
|
|
||||||
|
$detail = Db::table('s2_wechat_chatroom')
|
||||||
|
->where(['accountId' => $accountId, 'id' => $id, 'isDeleted' => 0])
|
||||||
|
->find();
|
||||||
|
|
||||||
|
if (!$detail) {
|
||||||
|
return ResponseHelper::error('聊天室不存在或无权限访问');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理时间格式
|
||||||
|
$detail['createTime'] = !empty($detail['createTime']) ? date('Y-m-d H:i:s', $detail['createTime']) : '';
|
||||||
|
$detail['updateTime'] = !empty($detail['updateTime']) ? date('Y-m-d H:i:s', $detail['updateTime']) : '';
|
||||||
|
|
||||||
|
// 查询未读消息数量
|
||||||
|
$unreadCount = Db::table('s2_wechat_message')
|
||||||
|
->where('wechatChatroomId', $id)
|
||||||
|
->where('isRead', 0)
|
||||||
|
->count();
|
||||||
|
|
||||||
|
// 查询最新消息
|
||||||
|
$latestMessage = Db::table('s2_wechat_message')
|
||||||
|
->where('wechatChatroomId', $id)
|
||||||
|
->order('id desc')
|
||||||
|
->find();
|
||||||
|
|
||||||
|
$config = [
|
||||||
|
'unreadCount' => $unreadCount,
|
||||||
|
'chat' => !empty($latestMessage),
|
||||||
|
'msgTime' => isset($latestMessage['wechatTime']) ? $latestMessage['wechatTime'] : 0
|
||||||
|
];
|
||||||
|
$detail['config'] = $config;
|
||||||
|
|
||||||
|
return ResponseHelper::success($detail);
|
||||||
|
}
|
||||||
|
|
||||||
public function aiAnnouncement()
|
public function aiAnnouncement()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -101,4 +101,44 @@ class WechatFriendController extends BaseController
|
|||||||
|
|
||||||
return ResponseHelper::success(['list' => $list, 'total' => $total]);
|
return ResponseHelper::success(['list' => $list, 'total' => $total]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取单个好友详情
|
||||||
|
* @return \think\response\Json
|
||||||
|
*/
|
||||||
|
public function getDetail()
|
||||||
|
{
|
||||||
|
$friendId = $this->request->param('id');
|
||||||
|
$accountId = $this->getUserInfo('s2_accountId');
|
||||||
|
|
||||||
|
if (empty($accountId)) {
|
||||||
|
return ResponseHelper::error('请先登录');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty($friendId)) {
|
||||||
|
return ResponseHelper::error('好友ID不能为空');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询好友详情
|
||||||
|
$friend = Db::table('s2_wechat_friend')
|
||||||
|
->where(['id' => $friendId, 'isDeleted' => 0])
|
||||||
|
->find();
|
||||||
|
|
||||||
|
if (empty($friend)) {
|
||||||
|
return ResponseHelper::error('好友不存在');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理好友数据
|
||||||
|
$friend['labels'] = json_decode($friend['labels'], true);
|
||||||
|
$friend['siteLabels'] = json_decode($friend['siteLabels'], true);
|
||||||
|
$friend['createTime'] = !empty($friend['createTime']) ? date('Y-m-d H:i:s', $friend['createTime']) : '';
|
||||||
|
$friend['updateTime'] = !empty($friend['updateTime']) ? date('Y-m-d H:i:s', $friend['updateTime']) : '';
|
||||||
|
$friend['passTime'] = !empty($friend['passTime']) ? date('Y-m-d H:i:s', $friend['passTime']) : '';
|
||||||
|
|
||||||
|
// 获取AI类型设置
|
||||||
|
$aiTypeSetting = FriendSettings::where('friendId', $friendId)->find();
|
||||||
|
$friend['aiType'] = $aiTypeSetting ? $aiTypeSetting['type'] : 0;
|
||||||
|
|
||||||
|
return ResponseHelper::success(['detail' => $friend]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user