作者 刘锟

Merge remote-tracking branch 'origin/master' into akun

<?php
/**
* @remark :
* @name :AiBlogTask.php
* @author :lyh
* @method :post
* @time :2025/2/14 11:14
*/
namespace App\Console\Commands\Ai;
use App\Models\Ai\AiBlog;
use App\Models\Ai\AiBlogAuthor;
use App\Models\Ai\AiBlogList;
use App\Models\Domain\DomainInfo;
use App\Models\Project\Project;
use App\Models\Project\ProjectAiSetting;
use App\Models\RouteMap\RouteMap;
use App\Services\AiBlogService;
use App\Services\ProjectServer;
use Illuminate\Console\Command;
use App\Models\Project\AiBlogTask as AiBlogTaskModel;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\DB;
use function Symfony\Component\String\s;
/***
* @remark :根据项目更新blog列表
* @name :AiBlogListTask
* @author :lyh
* @method :post
* @time :2025/3/6 9:45
*/
class AiBlogListAllTask extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'save_all_ai_blog_list';
/**
* The console command description.
*
* @var string
*/
protected $description = '生成blog列表';
public function handle(){
$projectModel = new Project();
$lists = $projectModel->list(['delete_status' => 0,'project_type'=>0,'extend_type'=>0,'type'=>['in',[2,3,4,6]]], 'id', ['id']);
foreach ($lists as $item){
echo '执行的项目的id'.$item['id'].PHP_EOL;
$project_id = $item['id'];
ProjectServer::useProject($project_id);
$projectAiSettingModel = new ProjectAiSetting();
$aiSettingInfo = $projectAiSettingModel->read(['project_id'=>$project_id]);
if($aiSettingInfo === false){
echo '未加载到配置。'.PHP_EOL;
continue;
}
$this->updateBlogList($aiSettingInfo);
$this->curlDelRoute($project_id);
DB::disconnect('custom_mysql');
}
return true;
}
/**
* @remark :更新列表页数据
* @name :updateBlogList
* @author :lyh
* @method :post
* @time :2025/3/5 11:07
*/
public function updateBlogList($aiSettingInfo){
$aiBlogService = new AiBlogService();
$aiBlogService->mch_id = $aiSettingInfo['mch_id'];
$aiBlogService->key = $aiSettingInfo['key'];
$page = 1;
$saveData = [];
$result = $aiBlogService->getAiBlogList($page,15);
if(!isset($result['status']) || $result['status'] != 200){
return true;
}
$total_page = $result['data']['total_page'];
//组装数据保存
$saveData[] = [
'route'=>$page,
'text'=>$result['data']['section'],
];
while ($total_page > $page){
$page++;
$result = $aiBlogService->getAiBlogList($page,15);
if(isset($result['status']) && $result['status'] == 200){
$saveData[] = [
'route'=>$page,
'text'=>$result['data']['section'],
];
}
}
$aiBlogListModel = new AiBlogList();
if(!empty($saveData)){
//写一条路由信息
$aiBlogListModel->truncate();
$aiBlogListModel->insertAll($saveData);
}
return true;
}
/**
* @remark :通知C端生成界面
* @name :sendNotice
* @author :lyh
* @method :post
* @time :2025/3/6 11:51
*/
public function curlDelRoute($project_id){
$domainModel = new DomainInfo();
//获取项目域名
$domain = $domainModel->getProjectIdDomain($project_id);
if(!empty($domain)){
$c_url = $domain.'api/update_page/';
$param = [
'project_id' => $project_id,
'type' => 1,
'route' => 3,
'url' => ['top-blog'],
'language'=> [],
'is_sitemap' => 0
];
http_post($c_url, json_encode($param));
}
return true;
}
}
... ...
... ... @@ -72,7 +72,7 @@ class AiBlogListTask extends Command
$page = 1;
$saveData = [];
$result = $aiBlogService->getAiBlogList($page,15);
if(!isset($result['status']) && $result['status'] != 200){
if(!isset($result['status']) || $result['status'] != 200){
return true;
}
$total_page = $result['data']['total_page'];
... ...
... ... @@ -47,7 +47,7 @@ class GeoQuestionRes extends Command
sleep(300);
continue;
}
echo date('Y-m-d H:i:s').'执行的任务id:'.$task_id.PHP_EOL;
$this->output('执行的任务ID:' . $task_id);
$geoQuestionModel = new GeoQuestion();
$taskInfo = $geoQuestionModel->read(['id'=>$task_id]);
if ($taskInfo === false) {
... ... @@ -85,23 +85,20 @@ class GeoQuestionRes extends Command
GET_RESULT:
$error_num++;
try {
if ($error_num >= 3) {
if ($error_num > 3) {
$this->output('任务ID:' . $task_id . ', 项目ID:' . $taskInfo['project_id'] . ', 平台:' . $platform . ', 问题:' . $question . ', 获取失败.');
continue;
}
$this->output('执行平台:' . $platform . '执行次数:' . $error_num);
$this->output('平台:' . $platform . ', 执行次数:' . $error_num);
switch ($platform){
case 'google_ai_overview':
// overview 数据结构不确定, 需要单独处理数据
$data = $geo_service->getGooglePlatformResult($question);
$result = $this->dealGoogleData($data);
break;
case 'deep_seek':
$data = $geo_service->getDeepSeekResult($question);
$result = $this->dealDeepSeek($data);
break;
case 'openai-not-network':
$data = $geo_service->getDeepSeekResult($question,'gpt-4o-mini');
$result = $this->dealDeepSeek($data,'gpt-4o-mini');
$data = $geo_service->getChatResult($question, 'gpt-4o-mini');
$result = $this->dealChatData($data, 'gpt-4o-mini');
break;
default:
$result = $geo_service->getAiPlatformResult($question, $platform);
... ... @@ -158,7 +155,7 @@ class GeoQuestionRes extends Command
}
$save_data['text'] = json_encode(!empty($data) ? $data : $result,true);
$geoLogModel->addReturnId($save_data);
echo '执行结束:'.$platform.PHP_EOL;
$this->output('平台:' . $platform . ' 完成');
}
}
$next_time = date('Y-m-d', strtotime('+' . ($projectInfo['geo_frequency'] ?? 3) . ' days'));
... ... @@ -168,13 +165,12 @@ class GeoQuestionRes extends Command
}
/**
* @remark :获取命中的url
* @name :getUrl
* @author :lyh
* @method :post
* @time :2025/7/3 16:38
* 获取命中的url
* @param array $urlArr
* @param array $result_annotations
* @return array
*/
public function getUrl($urlArr = [],$result_annotations = []){
public function getUrl($urlArr = [], $result_annotations = []){
$url = [];
$url_num = [];
if(!empty($urlArr)){
... ... @@ -187,17 +183,16 @@ class GeoQuestionRes extends Command
}
}
}
return ['url'=>$url,'url_num'=>$url_num];
return ['url' => $url, 'url_num' => $url_num];
}
/**
* @remark :获取命中的关键词
* @name :getKeywords
* @author :lyh
* @method :post
* @time :2025/7/3 16:26
* 获取命中的关键词
* @param array $keywordArr
* @param array $result_text
* @return array
*/
public function getKeywords($keywordArr = [],$result_text = []){
public function getKeywords($keywordArr = [], $result_text = []){
$keywords = [];
$keywords_num = [];
if(!empty($keywordArr) && !empty($result_text)){
... ... @@ -210,17 +205,16 @@ class GeoQuestionRes extends Command
}
}
}
return ['keywords'=>$keywords,'keywords_num'=>$keywords_num];
return ['keywords' => $keywords, 'keywords_num' => $keywords_num];
}
/**
* @remark :整合deepSeek
* @name :requestDeepSeek
* @author :lyh
* @method :post
* @time :2025/7/15 10:58
* 处理 会话 返回数据
* @param $data
* @param string $model
* @return array
*/
public function dealDeepSeek($data,$model = 'DeepSeek'){
public function dealChatData($data, $model){
$result = [
'code' => 200,
'model' => $model,
... ...
... ... @@ -3,6 +3,7 @@
namespace App\Console\Commands\WebTraffic;
use App\Helper\Arr;
use App\Models\Ai\AiBlog;
use App\Models\Product\Category;
use App\Models\Product\Product;
use App\Models\Project\OnlineCheck;
... ... @@ -361,8 +362,32 @@ class WebTraffic extends Command
$data['urls_details'] = DB::connection('custom_mysql')->table('gl_product')
->where('project_id', $project_id)->where('status', Product::STATUS_ON)
->whereNull('deleted_at')
->inRandomOrder()
->limit(100)
->pluck('route', 'id')->toArray();
//已发布AI博客
$ai_blog_urls = DB::connection('custom_mysql')->table('gl_ai_blog')
->where('project_id', $project_id)->where('status', AiBlog::STATUS_FINISH)
->inRandomOrder()
->limit(20)
->pluck('route', 'id')->toArray();
foreach ($ai_blog_urls as &$ai_blog_url){
$ai_blog_url = 'blog/' . $ai_blog_url;
}
//已发布AI视频
$ai_video_urls = DB::connection('custom_mysql')->table('gl_ai_video')
->where('project_id', $project_id)->where('status', 2)
->inRandomOrder()
->limit(20)
->pluck('route', 'id')->toArray();
foreach ($ai_video_urls as &$ai_video_url){
$ai_video_url = 'video/' . $ai_video_url;
}
$data['urls_details'] = array_merge($data['urls_details'], $ai_blog_urls, $ai_video_urls);
$data['urls_cats'] = array_merge($data['urls_cats'], $data['urls_page']);
if(empty($data['urls_cats'])){
$data['urls_cats'] = $data['urls_details'];
... ...
... ... @@ -3,6 +3,7 @@
namespace App\Console\Commands\WebTraffic;
use App\Helper\Arr;
use App\Models\Ai\AiBlog;
use App\Models\HomeCount\Count;
use App\Models\Product\Category;
use App\Models\Product\Product;
... ... @@ -320,6 +321,7 @@ class WebTrafficFix extends Command
* 获取产品分类、单页和详情链接
*/
protected function getProductUrls($project_id){
ProjectServer::useProject($project_id);
//已发布产品分类页面
$data['urls_cats'] = DB::connection('custom_mysql')->table('gl_product_category')
->where('project_id', $project_id)->where('status', Category::STATUS_ACTIVE)
... ... @@ -335,8 +337,31 @@ class WebTrafficFix extends Command
$data['urls_details'] = DB::connection('custom_mysql')->table('gl_product')
->where('project_id', $project_id)->where('status', Product::STATUS_ON)
->whereNull('deleted_at')
->inRandomOrder()
->limit(100)
->pluck('route', 'id')->toArray();
//已发布AI博客
$ai_blog_urls = DB::connection('custom_mysql')->table('gl_ai_blog')
->where('project_id', $project_id)->where('status', AiBlog::STATUS_FINISH)
->inRandomOrder()
->limit(20)
->pluck('route', 'id')->toArray();
foreach ($ai_blog_urls as &$ai_blog_url){
$ai_blog_url = 'blog/' . $ai_blog_url;
}
//已发布AI视频
$ai_video_urls = DB::connection('custom_mysql')->table('gl_ai_video')
->where('project_id', $project_id)->where('status', 2)
->inRandomOrder()
->limit(20)
->pluck('route', 'id')->toArray();
foreach ($ai_video_urls as &$ai_video_url){
$ai_video_url = 'video/' . $ai_video_url;
}
$data['urls_details'] = array_merge($data['urls_details'], $ai_blog_urls, $ai_video_urls);
$data['urls_cats'] = array_merge($data['urls_cats'], $data['urls_page']);
if(empty($data['urls_cats'])){
$data['urls_cats'] = $data['urls_details'];
... ...
... ... @@ -3,6 +3,7 @@
namespace App\Console\Commands\WebTraffic;
use App\Helper\Arr;
use App\Models\Ai\AiBlog;
use App\Models\Product\Category;
use App\Models\Product\Product;
use App\Models\Project\OnlineCheck;
... ... @@ -391,8 +392,31 @@ class WebTrafficRussia extends Command
$data['urls_details'] = DB::connection('custom_mysql')->table('gl_product')
->where('project_id', $project_id)->where('status', Product::STATUS_ON)
->whereNull('deleted_at')
->inRandomOrder()
->limit(100)
->pluck('route', 'id')->toArray();
//已发布AI博客
$ai_blog_urls = DB::connection('custom_mysql')->table('gl_ai_blog')
->where('project_id', $project_id)->where('status', AiBlog::STATUS_FINISH)
->inRandomOrder()
->limit(20)
->pluck('route', 'id')->toArray();
foreach ($ai_blog_urls as &$ai_blog_url){
$ai_blog_url = 'blog/' . $ai_blog_url;
}
//已发布AI视频
$ai_video_urls = DB::connection('custom_mysql')->table('gl_ai_video')
->where('project_id', $project_id)->where('status', 2)
->inRandomOrder()
->limit(20)
->pluck('route', 'id')->toArray();
foreach ($ai_video_urls as &$ai_video_url){
$ai_video_url = 'video/' . $ai_video_url;
}
$data['urls_details'] = array_merge($data['urls_details'], $ai_blog_urls, $ai_video_urls);
$data['urls_cats'] = array_merge($data['urls_cats'], $data['urls_page']);
if(empty($data['urls_cats'])){
$data['urls_cats'] = $data['urls_details'];
... ...
... ... @@ -3,6 +3,7 @@
namespace App\Console\Commands\WebTraffic;
use App\Helper\Arr;
use App\Models\Ai\AiBlog;
use App\Models\Product\Category;
use App\Models\Product\Product;
use App\Models\Project\OnlineCheck;
... ... @@ -382,8 +383,31 @@ class WebTrafficRussiaSpecial extends Command
$data['urls_details'] = DB::connection('custom_mysql')->table('gl_product')
->where('project_id', $project_id)->where('status', Product::STATUS_ON)
->whereNull('deleted_at')
->inRandomOrder()
->limit(100)
->pluck('route', 'id')->toArray();
//已发布AI博客
$ai_blog_urls = DB::connection('custom_mysql')->table('gl_ai_blog')
->where('project_id', $project_id)->where('status', AiBlog::STATUS_FINISH)
->inRandomOrder()
->limit(20)
->pluck('route', 'id')->toArray();
foreach ($ai_blog_urls as &$ai_blog_url){
$ai_blog_url = 'blog/' . $ai_blog_url;
}
//已发布AI视频
$ai_video_urls = DB::connection('custom_mysql')->table('gl_ai_video')
->where('project_id', $project_id)->where('status', 2)
->inRandomOrder()
->limit(20)
->pluck('route', 'id')->toArray();
foreach ($ai_video_urls as &$ai_video_url){
$ai_video_url = 'video/' . $ai_video_url;
}
$data['urls_details'] = array_merge($data['urls_details'], $ai_blog_urls, $ai_video_urls);
$data['urls_cats'] = array_merge($data['urls_cats'], $data['urls_page']);
if(empty($data['urls_cats'])){
$data['urls_cats'] = $data['urls_details'];
... ...
... ... @@ -3,6 +3,7 @@
namespace App\Console\Commands\WebTraffic;
use App\Helper\Arr;
use App\Models\Ai\AiBlog;
use App\Models\Product\Category;
use App\Models\Product\Product;
use App\Models\Project\OnlineCheck;
... ... @@ -348,8 +349,31 @@ class WebTrafficSpecial extends Command
$data['urls_details'] = DB::connection('custom_mysql')->table('gl_product')
->where('project_id', $project_id)->where('status', Product::STATUS_ON)
->whereNull('deleted_at')
->inRandomOrder()
->limit(100)
->pluck('route', 'id')->toArray();
//已发布AI博客
$ai_blog_urls = DB::connection('custom_mysql')->table('gl_ai_blog')
->where('project_id', $project_id)->where('status', AiBlog::STATUS_FINISH)
->inRandomOrder()
->limit(20)
->pluck('route', 'id')->toArray();
foreach ($ai_blog_urls as &$ai_blog_url){
$ai_blog_url = 'blog/' . $ai_blog_url;
}
//已发布AI视频
$ai_video_urls = DB::connection('custom_mysql')->table('gl_ai_video')
->where('project_id', $project_id)->where('status', 2)
->inRandomOrder()
->limit(20)
->pluck('route', 'id')->toArray();
foreach ($ai_video_urls as &$ai_video_url){
$ai_video_url = 'video/' . $ai_video_url;
}
$data['urls_details'] = array_merge($data['urls_details'], $ai_blog_urls, $ai_video_urls);
$data['urls_cats'] = array_merge($data['urls_cats'], $data['urls_page']);
if(empty($data['urls_cats'])){
$data['urls_cats'] = $data['urls_details'];
... ...
... ... @@ -229,7 +229,7 @@ class FetchTicketProjects extends Command
|| $item->site_status == 1
) ? 1 : 0;
$team_ids = [
$team_ids_in = [
$item->deploy_build->leader_mid,
$item->deploy_build->manager_mid,
$item->deploy_build->designer_mid,
... ... @@ -240,11 +240,18 @@ class FetchTicketProjects extends Command
$item->deploy_optimize->tech_mid,
$item->deploy_optimize->tech_leader,
];
// $team_ids 去重复
$team_ids = array_unique($team_ids);
$team_ids = array_filter($team_ids);
$team_ids_in = array_unique($team_ids_in);
$team_ids_in = array_filter($team_ids_in);
// $team_ids 去掉下标
$team_ids = array_values($team_ids);
$team_ids_in = array_values($team_ids_in);
$team_ids = ManageHr::whereIn('manage_id', $team_ids_in)->where('status', 1)->pluck('manage_id')
->unique()
->filter(fn($v) => !is_null($v) && $v !== 0)
->values()
->toArray();
$fields = [
'company_name' => $item->company,
... ...
... ... @@ -210,7 +210,7 @@ class CNoticeController extends BaseController
* 更新通知C端
* @param Request $request
* @return \Illuminate\Http\JsonResponse
* @param : type : 1->主站更新 4->聚合页更新 7->ai博客
* @param : route : 1->主站更新 4->聚合页更新 7->ai博客
*/
public function sendNotify(Request $request)
{
... ... @@ -223,7 +223,7 @@ class CNoticeController extends BaseController
$url = $request->input('url', []);
$language = $request->input('language', []);
$is_sitemap = intval($request->input('is_sitemap', 0));
if($type == 4){//代表聚合页更新
if($route == 4){//代表聚合页更新
$keywordModel = new Keyword();
$keywordInfo = $keywordModel->whereNull('seo_title')->orWhereNull('seo_keywords')->orWhereNull('seo_description')->first();
if(!empty($keywordInfo)){
... ... @@ -302,7 +302,7 @@ class CNoticeController extends BaseController
'is_sitemap' => $is_sitemap
];
try {
http_post($c_url, json_encode($c_param));
http_post($c_url, json_encode($c_param,true));
}catch (\Exception $e){
NoticeLog::createLog(NoticeLog::GENERATE_PAGE, ['c_url'=>$c_url,'c_params'=>$c_param]);
}
... ...
... ... @@ -37,6 +37,9 @@ class GeoLinkLogic extends BaseLogic
*/
public function getLinkList($map = [],$page = 1,$row = 20,$order = 'id'){
$filed = ['*'];
if(isset($map['url']) && !empty($map['url'])){
$map['url'] = ['like','%'.$map['url'].'%'];
}
$lists = $this->model->lists($map,$page,$row,$order,$filed);
return $this->success($lists);
}
... ... @@ -64,13 +67,6 @@ class GeoLinkLogic extends BaseLogic
* @time :2025/7/14 16:50
*/
public function saveLink(){
$data = [
'project_id' => 1,
'data' => [
['da'=>'ce_shi1', 'url'=>'www.baidu.com', 'send_time'=>'2021-07-09 11:12:12'],
['da'=>'ce_shi2', 'url'=>'www.baidu1.com', 'send_time'=>'2021-07-10 11:13:12'],
],
];
try {
if(!empty($this->param['data'])){
$data = [];
... ...
... ... @@ -88,19 +88,17 @@ class GeoQuestionResLogic extends BaseLogic
$questionModel = new GeoQuestion();
$list = $questionModel->list(['project_id'=>$this->user['project_id']],['question','keywords','url']);
$questionTotalCount = $urlTotalCount = $keywordsTotalCount = $keywordUrlCount = 0;
$keywordArr = [];
$questionLogModel = new GeoQuestionLog();
$keywordUrlCount = $questionLogModel->counts(['project_id'=>$this->user['project_id'],'hit'=>['!=',0]]);
foreach ($list as $item){
$questionTotalCount += count($item['question'] ?? []);
$keywordsTotalCount += count($item['keywords'] ?? []);
$urlTotalCount += count($item['url'] ?? []);
foreach ($item['keywords'] as $keyWordItem){
if (!array_key_exists($keyWordItem, $keywordArr)) {
$keywordArr[$keyWordItem] = $questionLogModel->counts(['project_id'=>$this->user['project_id'],'keywords'=>['like','%"'.$keyWordItem.'"%']]);
}
$keywordArr = [];
$questionResModel = new GeoQuestionLog();
$resList = $questionResModel->list(['project_id'=>$this->user['project_id']],['keywords','url','keywords_num','url_num']);
foreach ($resList as $resItem){
$keywordUrlCount += count($resItem['keywords']);
$keywordUrlCount += count($resItem['url']);
foreach ($resItem['keywords_num'] as $key => $value) {
$keywordArr[$key] = ($keywordArr[$key] ?? 0) + (($value != 0) ? 1 : 0);
}
}
$data = [
... ... @@ -124,7 +122,7 @@ class GeoQuestionResLogic extends BaseLogic
$data = [];
$platformModel = new GeoPlatform();
$list = $platformModel->list(['status'=>1],'id',['name','en_name']);
$questionResModel = new GeoQuestionResult();
$questionResModel = new GeoQuestionLog();
foreach ($list as $item){
$data[$item['name']] = $questionResModel->counts(['project_id'=>$this->user['project_id'],'hit'=>['!=',0],'platform'=>$item['en_name']]);
}
... ... @@ -139,7 +137,7 @@ class GeoQuestionResLogic extends BaseLogic
* @time :2025/7/21 16:36
*/
public function getSearchDate(){
$dates = $this->model->select(DB::raw('DATE(created_at) as date_only'))->distinct()->pluck('date_only');
$dates = $this->model->where('project_id',$this->user['project_id'])->select(DB::raw('DATE(created_at) as date_only'))->distinct()->pluck('date_only');
return $this->success($dates);
}
... ...
... ... @@ -16,6 +16,16 @@ class AsideTicketStoreRequest extends FormRequest
return true;
}
protected function prepareForValidation()
{
if ($this->has('close_wechat')) {
$this->merge([
// 将 "true", "1", "on", "yes" 等转换为 true,其他转换为 false
'close_wechat' => filter_var($this->close_wechat, FILTER_VALIDATE_BOOLEAN),
]);
}
}
/**
* Get the validation rules that apply to the request.
*
... ...
... ... @@ -70,13 +70,12 @@ class GeoService
}
/**
* @remark :请求deepSeek数据
* @name :getDeepSeek
* @author :lyh
* @method :post
* @time :2025/7/15 10:59
* 请求chat会话, 自定义模型
* @param $content
* @param string $model
* @return mixed|string
*/
public function getDeepSeekResult($content,$model = 'deepseek-r1'){
public function getChatResult($content, $model = 'deepseek-r1'){
$url = $this->api_url . 'v1/chat';
switch ($model){
case 'deepseek-r1':
... ...