From 28778a95664b04ce8a3bcbdfd92abb77e4376dda Mon Sep 17 00:00:00 2001 From: wong <106998207@qq.com> Date: Tue, 29 Jul 2025 09:43:32 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9C=8B=E5=8F=8B=E5=9C=88=E9=87=87=E9=9B=86?= =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/controller/WebSocketController.php | 2 + .../controller/WebSocketControllerCopy.php | 2 + Server/application/cunkebao/config/route.php | 2 +- .../controller/ContentCollectController.php | 30 - .../controller/ContentLibraryController.php | 562 ++++++++++-------- 5 files changed, 306 insertions(+), 292 deletions(-) delete mode 100644 Server/application/cunkebao/controller/ContentCollectController.php diff --git a/Server/application/api/controller/WebSocketController.php b/Server/application/api/controller/WebSocketController.php index 8400183d..27fb9c18 100644 --- a/Server/application/api/controller/WebSocketController.php +++ b/Server/application/api/controller/WebSocketController.php @@ -534,6 +534,8 @@ class WebSocketController extends BaseController 'userName' => $momentEntity['userName'] ?? '', 'snsId' => $moment['snsId'] ?? '', 'type' => $moment['type'] ?? 0, + 'title' => $moment['title'] ?? '', + 'coverImage' => $moment['coverImage'] ?? '', 'update_time' => time() ]; if (!empty($momentId)) { diff --git a/Server/application/api/controller/WebSocketControllerCopy.php b/Server/application/api/controller/WebSocketControllerCopy.php index 60bb2fbd..33bf77f3 100644 --- a/Server/application/api/controller/WebSocketControllerCopy.php +++ b/Server/application/api/controller/WebSocketControllerCopy.php @@ -341,6 +341,8 @@ class WebSocketControllerCopy extends BaseController 'userName' => $momentEntity['userName'] ?? '', 'snsId' => $moment['snsId'] ?? '', 'type' => $moment['type'] ?? 0, + 'title' => $moment['title'] ?? '', + 'coverImage' => $moment['coverImage'] ?? '', 'update_time' => time() ]; diff --git a/Server/application/cunkebao/config/route.php b/Server/application/cunkebao/config/route.php index 76b32f5f..c0dfc22e 100644 --- a/Server/application/cunkebao/config/route.php +++ b/Server/application/cunkebao/config/route.php @@ -28,7 +28,6 @@ Route::group('v1/', function () { Route::get(':id/friends', 'app\cunkebao\controller\wechat\GetWechatOnDeviceFriendsV1Controller@index'); Route::get('getWechatInfo', 'app\cunkebao\controller\wechat\GetWechatController@getWechatInfo'); Route::get(':wechatId', 'app\cunkebao\controller\wechat\GetWechatProfileV1Controller@index'); - Route::post('transfer-friends', 'app\cunkebao\controller\wechat\PostTransferFriends@index'); // 微信好友转移 @@ -100,6 +99,7 @@ Route::group('v1/', function () { Route::delete('delete-item', 'app\cunkebao\controller\ContentLibraryController@deleteItem'); // 删除内容库素材 Route::get('get-item-detail', 'app\cunkebao\controller\ContentLibraryController@getItemDetail'); // 获取内容库素材详情 Route::post('update-item', 'app\cunkebao\controller\ContentLibraryController@updateItem'); // 更新内容库素材 + Route::get('aiEditContent', 'app\cunkebao\controller\ContentLibraryController@aiEditContent'); }); // 好友相关 diff --git a/Server/application/cunkebao/controller/ContentCollectController.php b/Server/application/cunkebao/controller/ContentCollectController.php deleted file mode 100644 index 171c57e1..00000000 --- a/Server/application/cunkebao/controller/ContentCollectController.php +++ /dev/null @@ -1,30 +0,0 @@ - input('libraryId/d', 0), // 0表示采集所有内容库 - 'timestamp' => time() - ]; - - Queue::push(ContentCollectJob::class, $data, 'content_collect'); - - return json(['code' => 200, 'msg' => '采集任务已加入队列']); - } catch (\Exception $e) { - return json(['code' => 500, 'msg' => '添加采集任务失败:' . $e->getMessage()]); - } - } -} \ No newline at end of file diff --git a/Server/application/cunkebao/controller/ContentLibraryController.php b/Server/application/cunkebao/controller/ContentLibraryController.php index 86cbf7de..c59d7d0b 100644 --- a/Server/application/cunkebao/controller/ContentLibraryController.php +++ b/Server/application/cunkebao/controller/ContentLibraryController.php @@ -11,6 +11,7 @@ use app\api\controller\WebSocketController; use think\facade\Cache; use think\facade\Env; use app\api\controller\AutomaticAssign; +use think\facade\Request; /** * 内容库控制器 @@ -20,7 +21,7 @@ class ContentLibraryController extends Controller /************************************ * 内容库基础管理功能 ************************************/ - + /** * 创建内容库 * @return \think\response\Json @@ -40,7 +41,7 @@ class ContentLibraryController extends Controller } // 检查内容库名称是否已存在 - $exists = ContentLibrary::where(['name' => $param['name'],'userId' => $this->request->userInfo['id'],'isDel' => 0])->find(); + $exists = ContentLibrary::where(['name' => $param['name'], 'userId' => $this->request->userInfo['id'], 'isDel' => 0])->find(); if ($exists) { return json(['code' => 400, 'msg' => '内容库名称已存在']); } @@ -48,8 +49,8 @@ class ContentLibraryController extends Controller Db::startTrans(); try { - $keywordInclude = isset($param['keywordInclude']) ? json_encode($param['keywordInclude'],256) : json_encode([]); - $keywordExclude = isset($param['keywordExclude']) ? json_encode($param['keywordExclude'],256) : json_encode([]); + $keywordInclude = isset($param['keywordInclude']) ? json_encode($param['keywordInclude'], 256) : json_encode([]); + $keywordExclude = isset($param['keywordExclude']) ? json_encode($param['keywordExclude'], 256) : json_encode([]); $sourceType = isset($param['sourceType']) ? $param['sourceType'] : 1; @@ -59,7 +60,7 @@ class ContentLibraryController extends Controller // 数据来源配置 'sourceFriends' => $sourceType == 1 ? json_encode($param['friends']) : json_encode([]), // 选择的微信好友 'sourceGroups' => $sourceType == 2 ? json_encode($param['groups']) : json_encode([]), // 选择的微信群 - 'groupMembers' => $sourceType == 2 ? json_encode($param['groupMembers']) : json_encode([]), // 群组成员 + 'groupMembers' => $sourceType == 2 ? json_encode($param['groupMembers']) : json_encode([]), // 群组成员 // 关键词配置 'keywordInclude' => $keywordInclude, // 包含的关键词 'keywordExclude' => $keywordExclude, // 排除的关键词 @@ -96,7 +97,7 @@ class ContentLibraryController extends Controller return json(['code' => 500, 'msg' => '创建失败:' . $e->getMessage()]); } } - + /** * 获取内容库列表 * @return \think\response\Json @@ -112,22 +113,21 @@ class ContentLibraryController extends Controller ['userId', '=', $this->request->userInfo['id']], ['isDel', '=', 0] // 只查询未删除的记录 ]; - + // 添加名称模糊搜索 if ($keyword !== '') { $where[] = ['name', 'like', '%' . $keyword . '%']; } - // 添加名称模糊搜索 + // 添加名称模糊搜索 if (!empty($sourceType)) { $where[] = ['sourceType', '=', $sourceType]; } - $list = ContentLibrary::where($where) ->field('id,name,sourceFriends,sourceGroups,keywordInclude,keywordExclude,aiEnabled,aiPrompt,timeEnabled,timeStart,timeEnd,status,sourceType,userId,createTime,updateTime') - ->with(['user' => function($query) { + ->with(['user' => function ($query) { $query->field('id,username'); }]) ->order('id', 'desc') @@ -162,7 +162,7 @@ class ContentLibraryController extends Controller $item['selectedFriends'] = $friendsInfo; } - + if (!empty($item['sourceGroups']) && $item['sourceType'] == 2) { $groupIds = $item['sourceGroups']; $groupsInfo = []; @@ -212,8 +212,8 @@ class ContentLibraryController extends Controller ['userId', '=', $this->request->userInfo['id']], ['isDel', '=', 0] // 只查询未删除的记录 ]) - ->field('id,name,sourceType,sourceFriends,sourceGroups,keywordInclude,keywordExclude,aiEnabled,aiPrompt,timeEnabled,timeStart,timeEnd,status,userId,companyId,createTime,updateTime,groupMembers') - ->find(); + ->field('id,name,sourceType,sourceFriends,sourceGroups,keywordInclude,keywordExclude,aiEnabled,aiPrompt,timeEnabled,timeStart,timeEnd,status,userId,companyId,createTime,updateTime,groupMembers') + ->find(); if (empty($library)) { return json(['code' => 404, 'msg' => '内容库不存在']); @@ -226,53 +226,53 @@ class ContentLibraryController extends Controller $library['keywordExclude'] = json_decode($library['keywordExclude'] ?: '[]', true); $library['groupMembers'] = json_decode($library['groupMembers'] ?: '[]', true); - // 将时间戳转换为日期格式(精确到日) - if (!empty($library['timeStart'])) { - $library['timeStart'] = date('Y-m-d', $library['timeStart']); - } - if (!empty($library['timeEnd'])) { - $library['timeEnd'] = date('Y-m-d', $library['timeEnd']); - } - - // 获取好友详细信息 - if (!empty($library['sourceFriends'])) { - $friendIds = $library['sourceFriends']; - $friendsInfo = []; - - if (!empty($friendIds)) { - // 查询好友信息,使用wechat_friendship表 - $friendsInfo = Db::name('wechat_friendship')->alias('wf') - ->field('wf.id,wf.wechatId, wa.nickname, wa.avatar') - ->join('wechat_account wa', 'wf.wechatId = wa.wechatId') - ->whereIn('wf.id', $friendIds) - ->select(); + // 将时间戳转换为日期格式(精确到日) + if (!empty($library['timeStart'])) { + $library['timeStart'] = date('Y-m-d', $library['timeStart']); } - - // 将好友信息添加到返回数据中 - $library['selectedFriends'] = $friendsInfo; - } - - // 获取群组详细信息 - if (!empty($library['sourceGroups'])) { - $groupIds = $library['sourceGroups']; - $groupsInfo = []; - - if (!empty($groupIds)) { - // 查询群组信息 - $groupsInfo = Db::name('wechat_group')->alias('g') - ->field('g.id, g.chatroomId, g.name, g.avatar, g.ownerWechatId,wa.nickname as ownerNickname,wa.avatar as ownerAvatar,wa.alias as ownerAlias') - ->join('wechat_account wa', 'g.ownerWechatId = wa.wechatId') - ->whereIn('g.id', $groupIds) - ->select(); + if (!empty($library['timeEnd'])) { + $library['timeEnd'] = date('Y-m-d', $library['timeEnd']); + } + + // 获取好友详细信息 + if (!empty($library['sourceFriends'])) { + $friendIds = $library['sourceFriends']; + $friendsInfo = []; + + if (!empty($friendIds)) { + // 查询好友信息,使用wechat_friendship表 + $friendsInfo = Db::name('wechat_friendship')->alias('wf') + ->field('wf.id,wf.wechatId, wa.nickname, wa.avatar') + ->join('wechat_account wa', 'wf.wechatId = wa.wechatId') + ->whereIn('wf.id', $friendIds) + ->select(); + } + + // 将好友信息添加到返回数据中 + $library['selectedFriends'] = $friendsInfo; + } + + // 获取群组详细信息 + if (!empty($library['sourceGroups'])) { + $groupIds = $library['sourceGroups']; + $groupsInfo = []; + + if (!empty($groupIds)) { + // 查询群组信息 + $groupsInfo = Db::name('wechat_group')->alias('g') + ->field('g.id, g.chatroomId, g.name, g.avatar, g.ownerWechatId,wa.nickname as ownerNickname,wa.avatar as ownerAvatar,wa.alias as ownerAlias') + ->join('wechat_account wa', 'g.ownerWechatId = wa.wechatId') + ->whereIn('g.id', $groupIds) + ->select(); + } + + // 将群组信息添加到返回数据中 + $library['selectedGroups'] = $groupsInfo; } - - // 将群组信息添加到返回数据中 - $library['selectedGroups'] = $groupsInfo; - } return json([ - 'code' => 200, - 'msg' => '获取成功', + 'code' => 200, + 'msg' => '获取成功', 'data' => $library ]); } @@ -312,8 +312,8 @@ class ContentLibraryController extends Controller Db::startTrans(); try { - $keywordInclude = isset($param['keywordInclude']) ? json_encode($param['keywordInclude'],256) : json_encode([]); - $keywordExclude = isset($param['keywordExclude']) ? json_encode($param['keywordExclude'],256) : json_encode([]); + $keywordInclude = isset($param['keywordInclude']) ? json_encode($param['keywordInclude'], 256) : json_encode([]); + $keywordExclude = isset($param['keywordExclude']) ? json_encode($param['keywordExclude'], 256) : json_encode([]); // 更新内容库基本信息 @@ -429,7 +429,7 @@ class ContentLibraryController extends Controller // 处理资源URL $item['resUrls'] = json_decode($item['resUrls'] ?: '[]', true); $item['urls'] = json_decode($item['urls'] ?: '[]', true); - + // 格式化时间 //$item['createTime'] = date('Y-m-d H:i:s', $item['createTime']); if ($item['createMomentTime']) { @@ -448,8 +448,8 @@ class ContentLibraryController extends Controller ->field('wa.nickname, wa.avatar') ->find(); $item['senderNickname'] = !empty($friendInfo['nickname']) ? $friendInfo['nickname'] : ''; - $item['senderAvatar'] = !empty( $friendInfo['avatar']) ? $friendInfo['avatar'] : ''; - }else if ($item['type'] == 'group_message' && !empty($item['wechatChatroomId'])) { + $item['senderAvatar'] = !empty($friendInfo['avatar']) ? $friendInfo['avatar'] : ''; + } else if ($item['type'] == 'group_message' && !empty($item['wechatChatroomId'])) { $friendInfo = Db::table('s2_wechat_chatroom_member') ->field('nickname, avatar') ->where('wechatId', $item['wechatId']) @@ -500,14 +500,14 @@ class ContentLibraryController extends Controller if (empty($param['content'])) { return json(['code' => 400, 'msg' => '内容数据不能为空']); } - + // 当类型为群消息时,限制图片只能上传一张 if ($param['type'] == 'group_message') { $images = isset($param['images']) ? $param['images'] : []; if (is_string($images)) { $images = json_decode($images, true); } - + if (count($images) > 1) { return json(['code' => 400, 'msg' => '群消息类型只能上传一张图片']); } @@ -533,8 +533,8 @@ class ContentLibraryController extends Controller $item->content = $param['content']; $item->comment = $param['comment'] ?? ''; $item->sendTime = strtotime($param['sendTime']); - $item->resUrls = json_encode($param['resUrls'] ?? [],256); - $item->urls = json_encode($param['urls'] ?? [],256); + $item->resUrls = json_encode($param['resUrls'] ?? [], 256); + $item->urls = json_encode($param['urls'] ?? [], 256); $item->senderNickname = '系统创建'; $item->coverImage = $param['coverImage'] ?? ''; $item->save(); @@ -615,7 +615,7 @@ class ContentLibraryController extends Controller // 处理资源URL $item['resUrls'] = json_decode($item['resUrls'] ?: '[]', true); $item['urls'] = json_decode($item['urls'] ?: '[]', true); - + // 添加内容类型的文字描述 $contentTypeMap = [ 0 => '未知', @@ -627,7 +627,7 @@ class ContentLibraryController extends Controller 6 => '图文' ]; $item['contentTypeName'] = $contentTypeMap[$item['contentType'] ?? 0] ?? '未知'; - + // 格式化时间 if ($item['createMomentTime']) { $item['createMomentTimeFormatted'] = date('Y-m-d H:i:s', $item['createMomentTime']); @@ -660,8 +660,8 @@ class ContentLibraryController extends Controller } return json([ - 'code' => 200, - 'msg' => '获取成功', + 'code' => 200, + 'msg' => '获取成功', 'data' => $item ]); } @@ -688,7 +688,7 @@ class ContentLibraryController extends Controller $item = ContentItem::where([ ['id', '=', $param['id']], ['isDel', '=', 0] - ]) ->find(); + ])->find(); if (!$item) { return json(['code' => 404, 'msg' => '内容项目不存在或无权限操作']); @@ -699,7 +699,7 @@ class ContentLibraryController extends Controller $item->title = $param['title'] ?? $item->title; $item->content = $param['content'] ?? $item->content; $item->comment = $param['comment'] ?? $item->comment; - + // 处理发送时间 if (!empty($param['sendTime'])) { $item->sendTime = strtotime($param['sendTime']); @@ -714,7 +714,7 @@ class ContentLibraryController extends Controller if (isset($param['resUrls'])) { $resUrls = is_string($param['resUrls']) ? json_decode($param['resUrls'], true) : $param['resUrls']; $item->resUrls = json_encode($resUrls, JSON_UNESCAPED_UNICODE); - + // 设置封面图片 if (!empty($resUrls[0])) { $item->coverImage = $resUrls[0]; @@ -750,6 +750,44 @@ class ContentLibraryController extends Controller } + public function aiEditContent() + { + + $id = Request::param('id', ''); + + // 简单验证 + if (empty($id)) { + return json(['code' => 400, 'msg' => '参数错误']); + } + + // 查询内容项目是否存在并检查权限 + $item = ContentItem::where([ + ['id', '=', $id], + ['isDel', '=', 0] + ])->find(); + + if (empty($item)) { + return json(['code' => 404, 'msg' => '内容项目不存在或无权限操作']); + } + + if (empty($item['content'])) { + return json(['code' => 404, 'msg' => '内容不能为空']); + } + + try { + $contentAi = $this->aiRewrite(['aiEnabled' => true], $item['content']); + if (!empty($contentAi)) { + ContentItem::where(['id' => $item['id']])->update(['contentAi' => $contentAi, 'updateTime' => time()]); + return json(['code' => 200, 'msg' => 'ai编写成功', 'data' => ['editAfter' => $contentAi, 'editFront' => $item['content']]]); + } else { + return json(['code' => 500, 'msg' => 'ai编写失败']); + } + } catch (\Exception $e) { + return json(['code' => 500, 'msg' => 'ai编写失败:' . $e->getMessage()]); + } + } + + /************************************ * 数据采集相关功能 ************************************/ @@ -784,7 +822,7 @@ class ContentLibraryController extends Controller ['isDel', '=', 0], // 未删除 ['status', '=', 1], // 已开启 ]; - + // 查询符合条件的内容库 $libraries = ContentLibrary::where($where) ->field('id,name,sourceType,sourceFriends,sourceGroups,keywordInclude,keywordExclude,aiEnabled,aiPrompt,timeEnabled,timeStart,timeEnd,status,userId,companyId,createTime,updateTime,groupMembers') @@ -794,11 +832,11 @@ class ContentLibraryController extends Controller if (empty($libraries)) { return json(['code' => 200, 'msg' => '没有可用的内容库配置']); } - + $successCount = 0; $failCount = 0; $results = []; - + // 处理每个内容库的采集任务 foreach ($libraries as $library) { try { @@ -808,7 +846,7 @@ class ContentLibraryController extends Controller $library['keywordInclude'] = json_decode($library['keywordInclude'] ?: '[]', true); $library['keywordExclude'] = json_decode($library['keywordExclude'] ?: '[]', true); $library['groupMembers'] = json_decode($library['groupMembers'] ?: '[]', true); - + // 根据数据来源类型执行不同的采集逻辑 $collectResult = []; switch ($library['sourceType']) { @@ -817,26 +855,26 @@ class ContentLibraryController extends Controller $collectResult = $this->collectFromFriends($library); } break; - + case 2: // 群类型 if (!empty($library['sourceGroups'])) { $collectResult = $this->collectFromGroups($library); } break; - + default: $collectResult = [ 'status' => 'failed', 'message' => '不支持的数据来源类型' ]; } - + if ($collectResult['status'] == 'success') { $successCount++; } else { $failCount++; } - + $results[] = [ 'library_id' => $library['id'], 'library_name' => $library['name'], @@ -844,7 +882,7 @@ class ContentLibraryController extends Controller 'message' => $collectResult['message'] ?? '', 'data' => $collectResult['data'] ?? [] ]; - + } catch (\Exception $e) { $failCount++; $results[] = [ @@ -855,7 +893,7 @@ class ContentLibraryController extends Controller ]; } } - + // 返回采集结果 return json_encode([ 'code' => 200, @@ -868,7 +906,7 @@ class ContentLibraryController extends Controller ] ]); } - + /** * 从好友采集朋友圈内容 * @param array $library 内容库配置 @@ -889,7 +927,7 @@ class ContentLibraryController extends Controller $username = Env::get('api.username2', ''); $password = Env::get('api.password2', ''); if (!empty($username) || !empty($password)) { - $toAccountId = Db::name('users')->where('account',$username)->value('s2_accountId'); + $toAccountId = Db::name('users')->where('account', $username)->value('s2_accountId'); } @@ -905,7 +943,7 @@ class ContentLibraryController extends Controller 'message' => '未找到有效的好友信息' ]; } - + // 从朋友圈采集内容 $collectedData = []; $totalMomentsCount = 0; @@ -915,15 +953,15 @@ class ContentLibraryController extends Controller if (!empty($username) && !empty($password)) { //执行切换好友命令 $automaticAssign = new AutomaticAssign(); - $automaticAssign->allotWechatFriend(['wechatFriendId' => $friend['id'],'toAccountId' => $toAccountId],true); + $automaticAssign->allotWechatFriend(['wechatFriendId' => $friend['id'], 'toAccountId' => $toAccountId], true); //存入缓存 $friendData['friendId'] = $friend['id']; artificialAllotWechatFriend($friendData); //执行采集朋友圈命令 - $webSocket = new WebSocketController(['userName' => $username,'password' => $password,'accountId' => $toAccountId]); - $webSocket->getMoments(['wechatFriendId' => $friend['id'],'wechatAccountId' => $friend['wechatAccountId']]); + $webSocket = new WebSocketController(['userName' => $username, 'password' => $password, 'accountId' => $toAccountId]); + $webSocket->getMoments(['wechatFriendId' => $friend['id'], 'wechatAccountId' => $friend['wechatAccountId']]); //采集完毕切换 - $automaticAssign->allotWechatFriend(['wechatFriendId' => $friend['id'],'toAccountId' => $friend['accountId']],true); + $automaticAssign->allotWechatFriend(['wechatFriendId' => $friend['id'], 'toAccountId' => $friend['accountId']], true); } @@ -935,33 +973,32 @@ class ContentLibraryController extends Controller ]) ->order('createTime', 'desc') //->where('create_time', '>=', time() - 86400) - ->page(1,20) + ->page(1, 20) ->select(); - if (empty($moments)) { continue; } - + // 获取好友详细信息 $friendInfo = Db::table('s2_wechat_friend') ->where('wechatId', $friend['wechatId']) ->field('nickname, avatar') ->find(); - + $nickname = $friendInfo['nickname'] ?? '未知好友'; $friendMomentsCount = 0; - + // 处理每条朋友圈数据 foreach ($moments as $moment) { // 处理关键词过滤 $content = $moment['content'] ?? ''; - + // 如果启用了关键词过滤 $includeKeywords = $library['keywordInclude']; $excludeKeywords = $library['keywordExclude']; - + // 检查是否包含必须关键词 $includeMatch = empty($includeKeywords); if (!empty($includeKeywords)) { @@ -972,12 +1009,12 @@ class ContentLibraryController extends Controller } } } - + // 如果不满足包含条件,跳过 if (!$includeMatch) { continue; } - + // 检查是否包含排除关键词 $excludeMatch = false; if (!empty($excludeKeywords)) { @@ -988,28 +1025,28 @@ class ContentLibraryController extends Controller } } } - + // 如果满足排除条件,跳过 if ($excludeMatch) { continue; } // 如果启用了AI处理 - if (!empty($library['aiEnabled']) && !empty($content)) { - $contentAi = $this->aiRewrite($library,$content); - if (!empty($content)){ - $moment['contentAi'] = $contentAi; - }else{ - $moment['contentAi'] = ''; - } + if (!empty($library['aiEnabled']) && !empty($content)) { + $contentAi = $this->aiRewrite($library, $content); + if (!empty($content)) { + $moment['contentAi'] = $contentAi; + } else { + $moment['contentAi'] = ''; + } } // 保存到内容库的content_item表 $this->saveMomentToContentItem($moment, $library['id'], $friend, $nickname); - + $friendMomentsCount++; } - + if ($friendMomentsCount > 0) { // 记录采集结果 $collectedData[$friend['wechatId']] = [ @@ -1017,20 +1054,19 @@ class ContentLibraryController extends Controller 'nickname' => $nickname, 'count' => $friendMomentsCount ]; - + $totalMomentsCount += $friendMomentsCount; } } - - + if (empty($collectedData)) { return [ 'status' => 'warning', 'message' => '未采集到任何朋友圈内容' ]; } - + return [ 'status' => 'success', 'message' => '成功采集到' . count($collectedData) . '位好友的' . $totalMomentsCount . '条朋友圈内容', @@ -1040,7 +1076,7 @@ class ContentLibraryController extends Controller 'details' => $collectedData ] ]; - + } catch (\Exception $e) { return [ 'status' => 'error', @@ -1048,7 +1084,7 @@ class ContentLibraryController extends Controller ]; } } - + /** * 从群组采集消息内容 * @param array $library 内容库配置 @@ -1063,7 +1099,7 @@ class ContentLibraryController extends Controller 'message' => '没有指定要采集的群组' ]; } - + try { // 查询群组信息 $groups = Db::name('wechat_group')->alias('g') @@ -1071,14 +1107,14 @@ class ContentLibraryController extends Controller ->whereIn('g.id', $groupIds) ->where('g.deleteTime', 0) ->select(); - + if (empty($groups)) { return [ 'status' => 'failed', 'message' => '未找到有效的群组信息' ]; } - + // 获取群成员信息 $groupMembers = $library['groupMembers']; if (empty($groupMembers)) { @@ -1088,23 +1124,23 @@ class ContentLibraryController extends Controller 'message' => '未找到有效的群成员信息' ]; } - + // 从群组采集内容 $collectedData = []; $totalMessagesCount = 0; $chatroomIds = array_column($groups, 'id'); - + // 获取群消息 - 支持时间范围过滤 $messageWhere = [ ['wechatChatroomId', 'in', $chatroomIds], ['type', '=', 2] ]; - + // 如果启用时间限制 if ($library['timeEnabled'] && $library['timeStart'] > 0 && $library['timeEnd'] > 0) { $messageWhere[] = ['createTime', 'between', [$library['timeStart'], $library['timeEnd']]]; } - + // 查询群消息 $groupMessages = Db::table('s2_wechat_message') ->where($messageWhere) @@ -1127,14 +1163,14 @@ class ContentLibraryController extends Controller 'messages' => [] ]; } - + // 处理消息内容 $content = $message['content'] ?? ''; - + // 如果启用了关键词过滤 $includeKeywords = $library['keywordInclude']; $excludeKeywords = $library['keywordExclude']; - + // 检查是否包含必须关键词 $includeMatch = empty($includeKeywords); @@ -1146,12 +1182,12 @@ class ContentLibraryController extends Controller } } } - + // 如果不满足包含条件,跳过 if (!$includeMatch) { continue; } - + // 检查是否包含排除关键词 $excludeMatch = false; if (!empty($excludeKeywords)) { @@ -1162,12 +1198,12 @@ class ContentLibraryController extends Controller } } } - + // 如果满足排除条件,跳过 if ($excludeMatch) { continue; } - + // 找到对应的群组信息 $groupInfo = null; foreach ($groups as $group) { @@ -1176,18 +1212,18 @@ class ContentLibraryController extends Controller break; } } - + if (!$groupInfo) { continue; } // 如果启用了AI处理 - if (!empty($library['aiEnabled']) && !empty($content)) { - $contentAi = $this->aiRewrite($library,$content); - if (!empty($content)){ + if (!empty($library['aiEnabled']) && !empty($content)) { + $contentAi = $this->aiRewrite($library, $content); + if (!empty($content)) { $moment['contentAi'] = $contentAi; - }else{ + } else { $moment['contentAi'] = ''; } } @@ -1195,7 +1231,7 @@ class ContentLibraryController extends Controller // 保存消息到内容库 $this->saveMessageToContentItem($message, $library['id'], $groupInfo); - + // 累计计数 $groupedMessages[$chatroomId]['count']++; $groupedMessages[$chatroomId]['messages'][] = [ @@ -1204,10 +1240,10 @@ class ContentLibraryController extends Controller 'sender' => $message['senderNickname'], 'time' => date('Y-m-d H:i:s', $message['createTime']) ]; - + $totalMessagesCount++; } - + // 构建结果数据 foreach ($groups as $group) { $chatroomId = $group['chatroomId']; @@ -1220,14 +1256,14 @@ class ContentLibraryController extends Controller ]; } } - + if (empty($collectedData)) { return [ 'status' => 'warning', 'message' => '未采集到符合条件的群消息内容' ]; } - + return [ 'status' => 'success', 'message' => '成功采集到' . count($collectedData) . '个群的' . $totalMessagesCount . '条消息', @@ -1237,7 +1273,7 @@ class ContentLibraryController extends Controller 'details' => $collectedData ] ]; - + } catch (\Exception $e) { return [ 'status' => 'error', @@ -1245,7 +1281,7 @@ class ContentLibraryController extends Controller ]; } } - + /** * 判断内容类型 * @param string $content 内容文本 @@ -1259,13 +1295,13 @@ class ContentLibraryController extends Controller if (empty($content) && empty($resUrls) && empty($urls)) { return 0; // 未知类型 } - + // 分析内容中可能包含的链接或图片地址 if (!empty($content)) { // 检查内容中是否有链接 $urlPattern = '/https?:\/\/[-A-Za-z0-9+&@#\/%?=~_|!:,.;]+[-A-Za-z0-9+&@#\/%=~_|]/'; preg_match_all($urlPattern, $content, $contentUrlMatches); - + if (!empty($contentUrlMatches[0])) { // 将内容中的链接添加到urls数组中(去重) foreach ($contentUrlMatches[0] as $url) { @@ -1274,25 +1310,25 @@ class ContentLibraryController extends Controller } } } - + // 检查内容中是否包含图片或视频链接 foreach ($contentUrlMatches[0] ?? [] as $url) { // 检查是否为图片文件 - if (stripos($url, '.jpg') !== false || - stripos($url, '.jpeg') !== false || - stripos($url, '.png') !== false || - stripos($url, '.gif') !== false || - stripos($url, '.webp') !== false || + if (stripos($url, '.jpg') !== false || + stripos($url, '.jpeg') !== false || + stripos($url, '.png') !== false || + stripos($url, '.gif') !== false || + stripos($url, '.webp') !== false || stripos($url, '.bmp') !== false || stripos($url, 'image') !== false) { if (!in_array($url, $resUrls)) { $resUrls[] = $url; } } - + // 检查是否为视频文件 - if (stripos($url, '.mp4') !== false || - stripos($url, '.mov') !== false || + if (stripos($url, '.mp4') !== false || + stripos($url, '.mov') !== false || stripos($url, '.avi') !== false || stripos($url, '.wmv') !== false || stripos($url, '.flv') !== false || @@ -1303,21 +1339,21 @@ class ContentLibraryController extends Controller } } } - + // 判断是否有小程序信息 if (strpos($content, '小程序') !== false || strpos($content, 'appid') !== false) { return 5; // 小程序 } - + // 检查资源URL中是否有视频或图片 $hasVideo = false; $hasImage = false; - + if (!empty($resUrls)) { foreach ($resUrls as $url) { // 检查是否为视频文件 - if (stripos($url, '.mp4') !== false || - stripos($url, '.mov') !== false || + if (stripos($url, '.mp4') !== false || + stripos($url, '.mov') !== false || stripos($url, '.avi') !== false || stripos($url, '.wmv') !== false || stripos($url, '.flv') !== false || @@ -1325,13 +1361,13 @@ class ContentLibraryController extends Controller $hasVideo = true; break; // 一旦发现视频文件,立即退出循环 } - + // 检查是否为图片文件 - if (stripos($url, '.jpg') !== false || - stripos($url, '.jpeg') !== false || - stripos($url, '.png') !== false || - stripos($url, '.gif') !== false || - stripos($url, '.webp') !== false || + if (stripos($url, '.jpg') !== false || + stripos($url, '.jpeg') !== false || + stripos($url, '.png') !== false || + stripos($url, '.gif') !== false || + stripos($url, '.webp') !== false || stripos($url, '.bmp') !== false || stripos($url, 'image') !== false) { $hasImage = true; @@ -1339,12 +1375,12 @@ class ContentLibraryController extends Controller } } } - + // 如果发现视频文件,判定为视频类型 if ($hasVideo) { return 3; // 视频 } - + // 判断内容是否纯链接 $isPureLink = false; if (!empty($content) && !empty($urls)) { @@ -1357,12 +1393,12 @@ class ContentLibraryController extends Controller $isPureLink = true; } } - + // 如果内容是纯链接,判定为链接类型 if ($isPureLink) { return 2; // 链接 } - + // 优先判断内容文本 // 如果有文本内容(不仅仅是链接) if (!empty($content) && !$isPureLink) { @@ -1373,17 +1409,17 @@ class ContentLibraryController extends Controller return 4; // 纯文本 } } - + // 判断是否为图片类型 if ($hasImage) { return 1; // 图片 } - + // 判断是否为链接类型 if (!empty($urls)) { return 2; // 链接 } - + // 默认为文本类型 return 4; // 文本 } @@ -1404,81 +1440,90 @@ class ContentLibraryController extends Controller try { - + // 检查朋友圈数据是否已存在于内容项目中 $exists = ContentItem::where('libraryId', $libraryId) ->where('snsId', $moment['snsId'] ?? '') ->find(); - + if ($exists) { return true; } - + // 解析资源URL (可能是JSON字符串) $resUrls = $moment['resUrls']; if (is_string($resUrls)) { $resUrls = json_decode($resUrls, true); } - + // 处理urls字段 $urls = $moment['urls'] ?? []; if (is_string($urls)) { $urls = json_decode($urls, true); } - + // 构建封面图片 $coverImage = ''; if (!empty($resUrls) && is_array($resUrls) && count($resUrls) > 0) { $coverImage = $resUrls[0]; } - + // 判断内容类型 (0=未知, 1=图片, 2=链接, 3=视频, 4=文本, 5=小程序) - if($moment['type'] == 1) { + if ($moment['type'] == 1) { //图文 $contentType = 1; - }elseif ($moment['type'] == 3){ + } elseif ($moment['type'] == 3) { //链接 $contentType = 2; $urls = []; $url = is_string($moment['urls']) ? json_decode($moment['urls'], true) : $moment['urls'] ?? []; $url = $url[0]; - // 检查是否是飞书链接 - if (strpos($url, 'feishu.cn') !== false) { - // 飞书文档需要登录,无法直接获取内容,返回默认信息 + //兼容链接采集不到标题及图标 + if (empty($moment['title']) || empty($moment['coverImage'])) { + // 检查是否是飞书链接 + if (strpos($url, 'feishu.cn') !== false) { + // 飞书文档需要登录,无法直接获取内容,返回默认信息 + $urls[] = [ + 'url' => $url, + 'image' => 'http://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/2025/07/09/3db2a5d7fe49011ab68175a42a5094ce.jpeg', + 'desc' => '飞书文档' + ]; + } else { + $getUrlDetails = $this->getExternalPageDetails($url); + $icon = 'http://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/2025/07/09/ec039d96fad6eab1d960f207d3d9ca9f.jpeg'; + if (!empty($getUrlDetails['title'])) { + $urls[] = [ + 'url' => $url, + 'image' => $icon, + 'desc' => '点击查看详情' + ]; + } else { + $urls[] = [ + 'url' => $url, + 'image' => !empty($getUrlDetails['icon']) ? $getUrlDetails['icon'] : $icon, + 'desc' => $getUrlDetails['title'] + ]; + } + } + }else{ $urls[] = [ 'url' => $url, - 'image' => 'http://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/2025/07/09/3db2a5d7fe49011ab68175a42a5094ce.jpeg', - 'desc' => '飞书文档' + 'image' => $moment['coverImage'], + 'desc' => $moment['title'] ]; - }else{ - $getUrlDetails = $this->getExternalPageDetails($url); - $icon = 'http://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/2025/07/09/ec039d96fad6eab1d960f207d3d9ca9f.jpeg'; - if (!empty($getUrlDetails['title'])) { - $urls[] = [ - 'url' => $url, - 'image' => $icon, - 'desc' => '点击查看详情' - ]; - }else{ - $urls[] = [ - 'url' => $url, - 'image' => !empty($getUrlDetails['icon']) ? $getUrlDetails['icon'] : $icon, - 'desc' => $getUrlDetails['title'] - ]; - } } $moment['urls'] = $urls; - }elseif ($moment['type'] == 15){ + } elseif ($moment['type'] == 15) { //视频 $contentType = 3; - }elseif ($moment['type'] == 2){ + } elseif ($moment['type'] == 2) { //纯文本 $contentType = 4; - }elseif ($moment['type'] == 30){ + } elseif ($moment['type'] == 30) { //小程序 $contentType = 5; - }else{ + } else { $contentType = 1; } @@ -1497,11 +1542,11 @@ class ContentLibraryController extends Controller $item->contentAi = $moment['contentAi'] ?? ''; $item->coverImage = $coverImage; $item->contentType = $contentType; // 设置内容类型 - + // 独立存储resUrls和urls字段 $item->resUrls = is_string($moment['resUrls']) ? $moment['resUrls'] : json_encode($resUrls, JSON_UNESCAPED_UNICODE); $item->urls = is_string($moment['urls']) ? $moment['urls'] : json_encode($urls, JSON_UNESCAPED_UNICODE); - + // 保存地理位置信息 $item->location = $moment['location'] ?? ''; $item->lat = $moment['lat'] ?? 0; @@ -1514,7 +1559,7 @@ class ContentLibraryController extends Controller return false; } } - + /** * 保存群聊消息到内容项目表 * @param array $message 消息数据 @@ -1537,26 +1582,26 @@ class ContentLibraryController extends Controller if ($exists) { return true; } - + // 提取消息内容中的链接 $content = $message['content'] ?? ''; $links = []; $pattern = '/https?:\/\/[-A-Za-z0-9+&@#\/%?=~_|!:,.;]+[-A-Za-z0-9+&@#\/%=~_|]/'; preg_match_all($pattern, $content, $matches); - + if (!empty($matches[0])) { $links = $matches[0]; } - + // 提取可能的图片URL $resUrls = []; if (isset($message['imageUrl']) && !empty($message['imageUrl'])) { $resUrls[] = $message['imageUrl']; } - + // 判断内容类型 (0=未知, 1=图片, 2=链接, 3=视频, 4=文本, 5=小程序, 6=图文) $contentType = $this->determineContentType($content, $resUrls, $links); - + // 创建新的内容项目 $item = new ContentItem(); $item->libraryId = $libraryId; @@ -1567,13 +1612,13 @@ class ContentLibraryController extends Controller $item->createTime = time(); $item->content = $content; $item->contentType = $contentType; // 设置内容类型 - + // 设置发送者信息 $item->wechatId = $message['senderWechatId'] ?? ''; $item->wechatChatroomId = $message['wechatChatroomId'] ?? ''; $item->senderNickname = $message['senderNickname'] ?? ''; $item->createMessageTime = $message['createTime'] ?? 0; - + // 处理资源URL if (!empty($resUrls)) { $item->resUrls = json_encode($resUrls, JSON_UNESCAPED_UNICODE); @@ -1582,15 +1627,15 @@ class ContentLibraryController extends Controller $item->coverImage = $resUrls[0]; } } - + // 处理链接 if (!empty($links)) { $item->urls = json_encode($links, JSON_UNESCAPED_UNICODE); } - + // 设置商品信息(需根据消息内容解析) $this->extractProductInfo($item, $content); - + $item->save(); return true; } catch (\Exception $e) { @@ -1599,7 +1644,7 @@ class ContentLibraryController extends Controller return false; } } - + /** * 从消息内容中提取商品信息 * @param ContentItem $item 内容项目对象 @@ -1614,7 +1659,7 @@ class ContentLibraryController extends Controller '/《(.+?)》/', // 匹配《》中的内容 '/商品名称[::](.+?)[\r\n]/' // 匹配"商品名称:"后的内容 ]; - + foreach ($titlePatterns as $pattern) { preg_match($pattern, $content, $matches); if (!empty($matches[1])) { @@ -1622,7 +1667,7 @@ class ContentLibraryController extends Controller break; } } - + // 如果没有找到商品名称,尝试使用内容的前部分作为标题 if (empty($item->productTitle)) { // 获取第一行非空内容作为标题 @@ -1636,7 +1681,7 @@ class ContentLibraryController extends Controller } } } - + /** * 获取朋友圈数据 * @param string $wechatId 微信ID @@ -1652,7 +1697,7 @@ class ContentLibraryController extends Controller ['id' => 2, 'content' => '分享一个有趣的项目', 'createTime' => time() - 7200], ]; } - + /** * 根据关键词过滤朋友圈内容 * @param array $moments 朋友圈内容 @@ -1665,16 +1710,16 @@ class ContentLibraryController extends Controller if (empty($moments)) { return []; } - + $filtered = []; foreach ($moments as $moment) { $content = $moment['content'] ?? ''; - + // 如果内容为空,跳过 if (empty($content)) { continue; } - + // 检查是否包含必须关键词 $includeMatch = empty($includeKeywords); if (!empty($includeKeywords)) { @@ -1685,12 +1730,12 @@ class ContentLibraryController extends Controller } } } - + // 如果不满足包含条件,跳过 if (!$includeMatch) { continue; } - + // 检查是否包含排除关键词 $excludeMatch = false; if (!empty($excludeKeywords)) { @@ -1701,19 +1746,19 @@ class ContentLibraryController extends Controller } } } - + // 如果满足排除条件,跳过 if ($excludeMatch) { continue; } - + // 通过所有过滤,添加到结果中 $filtered[] = $moment; } - + return $filtered; } - + /** * 使用AI处理采集的数据 * @param array $data 采集的数据 @@ -1726,7 +1771,7 @@ class ContentLibraryController extends Controller // 实际实现需要根据具体的AI API return $data; } - + /** * 保存采集的数据到内容项目 * @param array $data 采集的数据 @@ -1738,7 +1783,7 @@ class ContentLibraryController extends Controller if (empty($data) || empty($libraryId)) { return false; } - + try { foreach ($data as $wechatId => $userData) { foreach ($userData['moments'] as $moment) { @@ -1759,7 +1804,7 @@ class ContentLibraryController extends Controller return false; } } - + /** * 获取所有群成员 * @param array $groupIds 群组ID列表 @@ -1770,7 +1815,7 @@ class ContentLibraryController extends Controller if (empty($groupIds)) { return []; } - + try { // 查询群成员信息 $members = Db::name('wechat_group_member')->alias('gm') @@ -1779,7 +1824,7 @@ class ContentLibraryController extends Controller ->whereIn('gm.groupId', $groupIds) ->where('gm.isDel', 0) ->select(); - + return $members; } catch (\Exception $e) { \think\facade\Log::error('获取群成员失败: ' . $e->getMessage()); @@ -1788,9 +1833,7 @@ class ContentLibraryController extends Controller } - - - /** + /** * 解析URL获取网页信息(内部调用) * @param string $url 要解析的URL * @return array 包含title、icon的数组,失败返回空数组 @@ -1822,7 +1865,7 @@ class ContentLibraryController extends Controller // 获取网页内容 $html = @file_get_contents($url, false, $context); - + if ($html === false) { return []; } @@ -1879,9 +1922,6 @@ class ContentLibraryController extends Controller } - - - /** * 将相对URL转换为绝对URL * @param string $relativeUrl 相对URL @@ -1907,9 +1947,9 @@ class ContentLibraryController extends Controller // 处理以/开头的绝对路径 if (strpos($relativeUrl, '/') === 0) { - return $baseParts['scheme'] . '://' . $baseParts['host'] . - (isset($baseParts['port']) ? ':' . $baseParts['port'] : '') . - $relativeUrl; + return $baseParts['scheme'] . '://' . $baseParts['host'] . + (isset($baseParts['port']) ? ':' . $baseParts['port'] : '') . + $relativeUrl; } // 处理相对路径 @@ -1918,9 +1958,9 @@ class ContentLibraryController extends Controller $basePath = '/'; } - return $baseParts['scheme'] . '://' . $baseParts['host'] . - (isset($baseParts['port']) ? ':' . $baseParts['port'] : '') . - $basePath . '/' . $relativeUrl; + return $baseParts['scheme'] . '://' . $baseParts['host'] . + (isset($baseParts['port']) ? ':' . $baseParts['port'] : '') . + $basePath . '/' . $relativeUrl; } /** @@ -1936,20 +1976,20 @@ class ContentLibraryController extends Controller // 移除HTML实体 $text = html_entity_decode($text, ENT_QUOTES | ENT_HTML5, 'UTF-8'); - + // 移除多余的空白字符 $text = preg_replace('/\s+/', ' ', $text); - + // 移除控制字符 $text = preg_replace('/[\x00-\x1F\x7F]/', '', $text); - + return trim($text); } - public function aiRewrite($library = [],$content = '') + public function aiRewrite($library = [], $content = '') { - if (empty($library['aiEnabled']) && empty($content)){ + if (empty($library['aiEnabled']) && empty($content)) { return false; } @@ -1957,19 +1997,19 @@ class ContentLibraryController extends Controller $utl = Env::get('doubaoAi.api_url', ''); $apiKey = Env::get('doubaoAi.api_key', ''); $model = Env::get('doubaoAi.model', 'doubao-1-5-pro-32k-250115'); - if (empty($apiKey)){ + if (empty($apiKey)) { return false; } if (!empty($library['aiPrompt'])) { $aiPrompt = $library['aiPrompt']; - }else{ + } else { $aiPrompt = '重写这条朋友圈 要求: 1、原本的字数和意思不要修改超过10% 2、出现品牌名或个人名字就去除'; } - $content = $aiPrompt .' ' . $content; + $content = $aiPrompt . ' ' . $content; $headerData = ['Authorization:Bearer ' . $apiKey]; $header = setHeader($headerData); @@ -1977,16 +2017,16 @@ class ContentLibraryController extends Controller $params = [ 'model' => $model, 'messages' => [ - ['role' => 'system','content' => '你是人工智能助手.'], - ['role' => 'user','content' => $content], + ['role' => 'system', 'content' => '你是人工智能助手.'], + ['role' => 'user', 'content' => $content], ] ]; - $result = requestCurl($utl, $params, 'POST', $header,'json'); - $result = json_decode($result,true); - if (!empty($result['choices'])){ + $result = requestCurl($utl, $params, 'POST', $header, 'json'); + $result = json_decode($result, true); + if (!empty($result['choices'])) { $contentAI = $result['choices'][0]['message']['content']; return $contentAI; - }else{ + } else { return false; } }