朋友圈采集优化

This commit is contained in:
wong
2025-07-29 09:43:32 +08:00
parent d78ff1e376
commit 28778a9566
5 changed files with 306 additions and 292 deletions

View File

@@ -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)) {

View File

@@ -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()
];

View File

@@ -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');
});
// 好友相关

View File

@@ -1,30 +0,0 @@
<?php
namespace app\cunkebao\controller;
use think\Controller;
use think\Queue;
use app\job\ContentCollectJob;
class ContentCollectController extends Controller
{
/**
* 添加内容采集任务到队列
* @return \think\response\Json
*/
public function addCollectTask()
{
try {
$data = [
'libraryId' => 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()]);
}
}
}

View File

@@ -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;
/**
* 内容库控制器
@@ -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, // 排除的关键词
@@ -118,16 +119,15 @@ class ContentLibraryController extends Controller
$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')
@@ -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,49 +226,49 @@ 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']);
}
if (!empty($library['timeEnd'])) {
$library['timeEnd'] = date('Y-m-d', $library['timeEnd']);
}
// 将好友信息添加到返回数据中
$library['selectedFriends'] = $friendsInfo;
}
// 获取好友详细信息
if (!empty($library['sourceFriends'])) {
$friendIds = $library['sourceFriends'];
$friendsInfo = [];
// 获取群组详细信息
if (!empty($library['sourceGroups'])) {
$groupIds = $library['sourceGroups'];
$groupsInfo = [];
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($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['selectedFriends'] = $friendsInfo;
}
// 将群组信息添加到返回数据中
$library['selectedGroups'] = $groupsInfo;
}
// 获取群组详细信息
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;
}
return json([
'code' => 200,
@@ -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([]);
// 更新内容库基本信息
@@ -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'])
@@ -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();
@@ -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' => '内容项目不存在或无权限操作']);
@@ -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()]);
}
}
/************************************
* 数据采集相关功能
************************************/
@@ -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');
}
@@ -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,11 +973,10 @@ class ContentLibraryController extends Controller
])
->order('createTime', 'desc')
//->where('create_time', '>=', time() - 86400)
->page(1,20)
->page(1, 20)
->select();
if (empty($moments)) {
continue;
}
@@ -995,13 +1032,13 @@ class ContentLibraryController extends Controller
}
// 如果启用了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表
@@ -1023,7 +1060,6 @@ class ContentLibraryController extends Controller
}
if (empty($collectedData)) {
return [
'status' => 'warning',
@@ -1183,11 +1219,11 @@ class ContentLibraryController extends Controller
// 如果启用了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'] = '';
}
}
@@ -1433,52 +1469,61 @@ class ContentLibraryController extends Controller
}
// 判断内容类型 (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;
}
@@ -1788,9 +1833,7 @@ class ContentLibraryController extends Controller
}
/**
/**
* 解析URL获取网页信息内部调用
* @param string $url 要解析的URL
* @return array 包含title、icon的数组失败返回空数组
@@ -1879,9 +1922,6 @@ class ContentLibraryController extends Controller
}
/**
* 将相对URL转换为绝对URL
* @param string $relativeUrl 相对URL
@@ -1908,8 +1948,8 @@ class ContentLibraryController extends Controller
// 处理以/开头的绝对路径
if (strpos($relativeUrl, '/') === 0) {
return $baseParts['scheme'] . '://' . $baseParts['host'] .
(isset($baseParts['port']) ? ':' . $baseParts['port'] : '') .
$relativeUrl;
(isset($baseParts['port']) ? ':' . $baseParts['port'] : '') .
$relativeUrl;
}
// 处理相对路径
@@ -1919,8 +1959,8 @@ class ContentLibraryController extends Controller
}
return $baseParts['scheme'] . '://' . $baseParts['host'] .
(isset($baseParts['port']) ? ':' . $baseParts['port'] : '') .
$basePath . '/' . $relativeUrl;
(isset($baseParts['port']) ? ':' . $baseParts['port'] : '') .
$basePath . '/' . $relativeUrl;
}
/**
@@ -1947,9 +1987,9 @@ class ContentLibraryController extends Controller
}
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;
}
}