作者 刘锟

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

@@ -10,13 +10,23 @@ @@ -10,13 +10,23 @@
10 namespace App\Console\Commands\LyhTest; 10 namespace App\Console\Commands\LyhTest;
11 11
12 use App\Console\Commands\Domain\DomainInfo; 12 use App\Console\Commands\Domain\DomainInfo;
  13 +use App\Http\Logic\Aside\Project\ProjectLogic;
13 use App\Models\Ai\AiBlogAuthor; 14 use App\Models\Ai\AiBlogAuthor;
14 use App\Models\Com\NoticeLog; 15 use App\Models\Com\NoticeLog;
  16 +use App\Models\Com\V6WeeklyReport;
15 use App\Models\Project\AiBlogTask; 17 use App\Models\Project\AiBlogTask;
16 use App\Models\Project\DeployBuild; 18 use App\Models\Project\DeployBuild;
  19 +use App\Models\Project\DeployOptimize;
17 use App\Models\Project\OnlineCheck; 20 use App\Models\Project\OnlineCheck;
18 use App\Models\Project\Project; 21 use App\Models\Project\Project;
  22 +use App\Models\Project\ProjectAiSetting;
  23 +use App\Models\ProjectAssociation\ProjectAssociation;
  24 +use App\Models\RouteMap\RouteMap;
  25 +use App\Models\Visit\Visit;
  26 +use App\Models\WebSetting\WebLanguage;
19 use App\Models\WebSetting\WebSetting; 27 use App\Models\WebSetting\WebSetting;
  28 +use App\Models\Workchat\MessagePush;
  29 +use App\Services\AiBlogService;
20 use App\Services\ProjectServer; 30 use App\Services\ProjectServer;
21 use Illuminate\Console\Command; 31 use Illuminate\Console\Command;
22 use Illuminate\Support\Facades\Artisan; 32 use Illuminate\Support\Facades\Artisan;
@@ -39,22 +49,168 @@ class lyhDemo extends Command @@ -39,22 +49,168 @@ class lyhDemo extends Command
39 protected $description = '更新路由'; 49 protected $description = '更新路由';
40 50
41 public function handle(){ 51 public function handle(){
  52 + $projectArr = [3257,1835,1834];
  53 + $v6WeekModel = new V6WeeklyReport();
  54 + foreach ($projectArr as $item){
42 $projectModel = new Project(); 55 $projectModel = new Project();
43 - $lists = $projectModel->list(['delete_status' => 0,'extend_type'=>0,'type'=>['in',[1,2,3,4]]], 'id', ['id']);  
44 - foreach ($lists as $val) {  
45 - echo date('Y-m-d H:i:s') . '开始--项目的id:'. $val['id'] . PHP_EOL;  
46 - ProjectServer::useProject($val['id']);  
47 - try {  
48 - $settingModel = new WebSetting();  
49 - $settingModel->edit(['anchor_num'=>10],['id'=>1,'anchor_num'=>3]);  
50 - $settingModel->edit(['anchor_num'=>3],['id'=>1,'anchor_num'=>1]);  
51 - $settingModel->edit(['anchor_num'=>5],['id'=>1,'anchor_num'=>2]);  
52 - }catch (\Exception $e){  
53 - DB::disconnect('custom_mysql');  
54 - }  
55 - DB::disconnect('custom_mysql'); 56 + $latest = $v6WeekModel->formatQuery(['project_id'=>$item])->orderBy('id', 'desc')->first();
  57 + $list = $projectModel->read(['delete_status'=>0,'id'=>$item],['id','title','is_weekly_report','main_lang_id']);
  58 + $latest['main_lang_id'] = $list['main_lang_id'];
  59 + $latest['is_weekly_report'] = $list['is_weekly_report'];
  60 + $latest['title'] = $list['title'];
  61 + $this->workChatMessage($latest,$item);
56 } 62 }
57 return true; 63 return true;
58 } 64 }
59 - 65 + public function workChatMessage($data,$project_id){
  66 + $arr = [];
  67 + //项目是否有绑定群
  68 + $friend_id = ProjectAssociation::where('project_id', $project_id)
  69 + ->where('status', ProjectAssociation::STATUS_NORMAL)
  70 + ->where('binding_app', ProjectAssociation::ENTERPRISE_WECHAT)
  71 + ->value('friend_id');
  72 + if(!$friend_id){
  73 + echo date('Y-m-d H:i:s') . '没有绑定企微群:'.$project_id . PHP_EOL;
  74 + return false;
  75 + }
  76 + $content = '';
  77 + $content1 = '';
  78 + if(!empty($data['inquiry_total'])){
  79 + $content1 .= '项目共计已收到询盘 '.$data['inquiry_total'].'条,';
  80 + if(!empty($data['week_inquiry_total'])){
  81 + $content1 .= '本周新收 '.$data['week_inquiry_total'].' 封询盘。';
  82 + }
  83 + if(!empty($data['inquiry_country'])){
  84 + $data['inquiry_country'] = json_decode($data['inquiry_country'],true);
  85 + arsort($data['inquiry_country']);
  86 + $data['inquiry_country'] = array_slice($data['inquiry_country'], 0, 4, true);
  87 + $country = '';
  88 + foreach ($data['inquiry_country'] as $k => $v){
  89 + $country .= $k.',';
  90 + };
  91 + $country = trim($country,',');
  92 + if(!empty($country)){
  93 + $content1 .= '询盘主要来源于'.$country.'等国家地区。';
  94 + }
  95 + }
  96 + $content1 .= '如有高质量客户,请您密切关注与跟进;';
  97 + }
  98 + if(!empty($content1)){
  99 + $arr[] = $content1;
  100 + }
  101 + $content2 = '';
  102 + if(!empty($data['google_indexed_num']) || !empty($data['google_links_num']) || !empty($data['keyword_home_num']) || !empty($data['keyword_three_num']) || !empty($data['keyword_five_num']) || !empty($data['keyword_ten_num']) || !empty($data['daily_average_num'])){
  103 + $content2 .= '项目截止目前';
  104 + if($data['main_lang_id'] == 8){
  105 + $title = 'Yandex';
  106 + }else{
  107 + $title = '谷歌';
  108 + }
  109 + if(!empty($data['google_indexed_num'])){
  110 + $content2 .= $title.'收录量:'.$data['google_indexed_num'].'条,';
  111 + }
  112 + if(!empty($data['google_links_num'])){
  113 + //获取上一次的外链数
  114 + $latestRecord = V6WeeklyReport::where(['project_id'=>$project_id])->orderBy('id', 'desc')->first();
  115 + if(!empty($latestRecord)){
  116 + if($latestRecord['google_links_num'] != $data['google_links_num']){
  117 + $content2 .= '外链量:'.$data['google_links_num'].'条,';
  118 + }
  119 + }else{
  120 + $content2 .= '外链量:'.$data['google_links_num'].'条,';
  121 + }
  122 + }
  123 + if(!empty($data['keyword_home_num']) || !empty($data['keyword_three_num']) || !empty($data['keyword_five_num']) || !empty($data['keyword_ten_num'])){
  124 + $content2 .= $title.'搜索排名';
  125 + if(!empty($data['keyword_home_num'])){
  126 + $content2 .= '首页关键词数量为:'.$data['keyword_home_num'].'个,';
  127 + }
  128 + if(!empty($data['keyword_three_num'])){
  129 + $content2 .= '前三页关键词数量为:'.$data['keyword_three_num'].'个,';
  130 + }
  131 + if(!empty($data['keyword_five_num'])){
  132 + $content2 .= '前五页关键词数量为:'.$data['keyword_five_num'].'个,';
  133 + }
  134 + if(!empty($data['keyword_ten_num'])){
  135 + $content2 .= '前十页关键词数量为:'.$data['keyword_ten_num'].'个,';
  136 + }
  137 + }
  138 + if(!empty($data['daily_average_num'])){
  139 + $content2 .= '本周日均访客量:'.$data['daily_average_num'].'+。';
  140 + }
  141 + $content2 .= PHP_EOL.'全球搜建议用户持续分析、选择、添加企业、产品、服务等相关关键词进行优化和监控,以覆盖更多相关排名和流量;';
  142 + }
  143 + if(!empty($content2)){
  144 + $arr[] = $content2;
  145 + }
  146 + $content3 = '';
  147 + if(!empty($data['product_num']) || !empty($data['news_num']) || !empty($data['week_product_num']) || !empty($data['week_news_num'])){
  148 + if(!empty($data['product_num']) || !empty($data['news_num'])){
  149 + $content3 .= '项目截止目前';
  150 + if(!empty($data['product_num'])){
  151 + $content3 .= '发布产品:'.$data['product_num'].'条,';
  152 + }
  153 + if(!empty($data['news_num'])){
  154 + $content3 .= '发布新闻:'.$data['news_num'].'条。';
  155 + }
  156 + }
  157 + if(!empty($data['week_product_num']) || !empty($data['week_news_num'])){
  158 + $content3 .= '本周新增';
  159 + if(!empty($data['week_product_num'])){
  160 + $content3 .= '产品:'.$data['week_product_num'].'条,';
  161 + }
  162 + if(!empty($data['week_news_num'])){
  163 + $content3 .= '新闻:'.$data['week_news_num'].'条。';
  164 + }
  165 + }
  166 + $content3 .= PHP_EOL.'全球搜建议用户保持网站内容的持续更新与完善,可参考谷歌关于创建实用、可靠、以用户为中心的内容的相关建议:https://developers.google.com/search/docs/fundamentals/creating-helpful-content?hl=zh-cn;';
  167 + }
  168 + if(!empty($content3)){
  169 + $arr[] = $content3;
  170 + }
  171 + $content4 = '';
  172 + if(!empty($data['main_update_num'])){
  173 + $content4 .= '网站加载速度维护及主站页面更新'.$data['main_update_num'].'次。';
  174 + }
  175 + if(!empty($data['aggregation_update_num'])){
  176 + $content4 .= '聚合页主站页面更新'.$data['aggregation_update_num'].'次。';
  177 + }
  178 + if(!empty($data['minor_update_num'])){
  179 + $content4 .= '小语种站页面更新'.$data['minor_update_num'].'次。';
  180 + }
  181 + if(!empty($data['aggregation_minor_update_num'])){
  182 + $content4 .= '聚合页小语种站页面'.$data['aggregation_minor_update_num'].'次。';
  183 + }
  184 + if(!empty($content4)){
  185 + $content4 = PHP_EOL.'本周主要优化工作包括:TDK、H标签、Img标签等优化设置排查与进一步完善,Sitemap更新与网页收录提交,外链新增与排查。'.$content4;
  186 + }
  187 + if(!empty($content4)){
  188 + $arr[] = $content4;
  189 + }
  190 + if(empty($arr)){
  191 + return true;
  192 + }
  193 + foreach ($arr as $key => $val){
  194 + $content .= ($key+1).','.$val.PHP_EOL.PHP_EOL;
  195 + }
  196 + $tomorrowNineAM = date('Y-m-d 09:00:00', time());
  197 + if(empty($content)){
  198 + return true;
  199 + }
  200 + $tips = 'Tips:'.PHP_EOL.'1、全球搜V6.0系统提供网页TDK、H标签、Img标签等用户自定义编辑接口且辅以AI创作工具,用户可进一步对相关优化设置进行精细化优化与调整;'.PHP_EOL.'2、全球搜V6.0系统提供小语种页面精准校对翻译功能,用户可进一步对已翻译小语种页面进行人工翻译校对;'.PHP_EOL.'3、全球搜V6.0系统支持绑定Facebook、LinkedIn、X(原Twitter)等社媒账号,可一键同步转发网站上发布的产品和新闻至社媒账号动态,建议用户用起来哦;'.PHP_EOL.'4、如用户有较丰富的企业、产品、服务相关视频素材,全球搜建议用户及时创建YouTube主页,并在YouTube和网站相关网页上同步发布视频;';
  201 + $message = "【全球搜V6.0周报】" . PHP_EOL . $content . PHP_EOL . $tips;
  202 + $param = [
  203 + 'project_id'=>$project_id,
  204 + 'friend_id'=>$friend_id,
  205 + 'type'=>MessagePush::TYPE_WEEK,
  206 + 'content'=> $message,
  207 + 'ref_ids'=>'',
  208 + 'send_time'=>$tomorrowNineAM,
  209 + 'status'=>0,
  210 + ];
  211 + //写入一条推送消息 自动消费
  212 + $messagePushModel = new MessagePush();
  213 + $messagePushModel->add($param);
  214 + return true;
  215 + }
60 } 216 }
@@ -4,6 +4,7 @@ namespace App\Http\Controllers\Aside\Com; @@ -4,6 +4,7 @@ namespace App\Http\Controllers\Aside\Com;
4 4
5 use App\Enums\Common\Code; 5 use App\Enums\Common\Code;
6 use App\Enums\Common\Common; 6 use App\Enums\Common\Common;
  7 +use App\Helper\Translate;
7 use App\Http\Controllers\Aside\BaseController; 8 use App\Http\Controllers\Aside\BaseController;
8 use App\Http\Logic\Aside\Manage\MenuLogic; 9 use App\Http\Logic\Aside\Manage\MenuLogic;
9 use App\Http\Logic\Bside\User\UserLoginLogic; 10 use App\Http\Logic\Bside\User\UserLoginLogic;
@@ -11,6 +12,7 @@ use App\Models\Inquiry\InquiryData; @@ -11,6 +12,7 @@ use App\Models\Inquiry\InquiryData;
11 use App\Models\Manage\Manage; 12 use App\Models\Manage\Manage;
12 use App\Models\User\User; 13 use App\Models\User\User;
13 use App\Models\WebSetting\WebLanguage; 14 use App\Models\WebSetting\WebLanguage;
  15 +use App\Services\HumanizeAiTextService;
14 use Illuminate\Support\Facades\Cache; 16 use Illuminate\Support\Facades\Cache;
15 use Illuminate\Support\Facades\Hash; 17 use Illuminate\Support\Facades\Hash;
16 18
@@ -160,5 +162,35 @@ class IndexController extends BaseController @@ -160,5 +162,35 @@ class IndexController extends BaseController
160 $this->response('success',Code::SUCCESS,['dynamic_password'=>$dynamic_password]); 162 $this->response('success',Code::SUCCESS,['dynamic_password'=>$dynamic_password]);
161 } 163 }
162 164
  165 + /**
  166 + * @remark :去ai痕迹
  167 + * @name :notAiHumanizer
  168 + * @author :lyh
  169 + * @method :post
  170 + * @time :2025/5/21 9:08
  171 + */
  172 + public function notAiHumanizer(){
  173 + $this->request->validate([
  174 + 'text'=>'required',
  175 + 'lang'=>'required'
  176 + ],[
  177 + 'text.required' => '文本text不能为空',
  178 + 'lang.required' => '语种不能为空',
  179 + ]);
  180 + $service = new HumanizeAiTextService();
  181 + $data = $service->humanizer($this->param['text'],$this->param['lang']);
  182 + $this->response('success', Code::SUCCESS, $data);
  183 + }
163 184
  185 + /**
  186 + * @remark :翻译
  187 + * @name :stringTranslation
  188 + * @author :lyh
  189 + * @method :post
  190 + * @time :2025/5/21 9:31
  191 + */
  192 + public function stringTranslation(){
  193 + $data = Translate::translateSl($this->param['text']);
  194 + $this->response('success', Code::SUCCESS, $data);
  195 + }
164 } 196 }
@@ -1214,4 +1214,5 @@ class ProjectController extends BaseController @@ -1214,4 +1214,5 @@ class ProjectController extends BaseController
1214 $lists = $model->list(['status' => 1], 'id', ['id', 'industry_name'], 'asc'); 1214 $lists = $model->list(['status' => 1], 'id', ['id', 'industry_name'], 'asc');
1215 $this->response('success', Code::SUCCESS, $lists); 1215 $this->response('success', Code::SUCCESS, $lists);
1216 } 1216 }
  1217 +
1217 } 1218 }
  1 +<?php
  2 +/**
  3 + * Created by PhpStorm.
  4 + * User: zhl
  5 + * Date: 2025/5/20
  6 + * Time: 14:49
  7 + */
  8 +namespace App\Services;
  9 +
  10 +use Illuminate\Support\Facades\Http;
  11 +
  12 +/**
  13 + * AI去痕迹
  14 + * Class HumanizeAiTextService
  15 + * @package App\Services
  16 + */
  17 +class HumanizeAiTextService
  18 +{
  19 + /**
  20 + * 封装接口地址
  21 + */
  22 + const CMER_API = 'https://api.cmer.com/';
  23 +
  24 +
  25 + const DRIVER_HUMANIZE = 'humanize'; //3.9号停用 https://rapidapi.com/firdavscoder1/api/humanize1/playground/apiendpoint_4bdba3d9-c66a-4e3d-b1e9-ff307da08e96
  26 + const DRIVER_HUMANIZE_AI_TEXT = 'humanize-ai-text';
  27 +
  28 +
  29 +#=======================================================================================================================
  30 +#== AI生成内容 去除AI痕迹 ==
  31 +#== https://rapidapi.com/bilgisamapi-bilgisamapi-default/api/ai-content-detection-ai-detector-humanize-ai-text ==
  32 +#== https://rapidapi.com/firdavscoder1/api/humanize1/playground/apiendpoint_4bdba3d9-c66a-4e3d-b1e9-ff307da08e96 ==
  33 +#=======================================================================================================================
  34 +
  35 + /**
  36 + * 去AI痕迹 header
  37 + * @param $driver
  38 + * @return array
  39 + */
  40 + public function humanizeHeader($driver)
  41 + {
  42 + return [
  43 + 'apikey' => 'kWd7wQbEPUF0fr17dnt5NQLazfv44O9T',
  44 + 'X-CmerApi-Host' => $driver . '.p.cmer.com',
  45 + 'Content-Type' => 'application/json',
  46 + ];
  47 + }
  48 +
  49 + /**
  50 + * 去AI痕迹提交
  51 + * FIXME humanize:返回请求ID:request_id, 需要异步获取结果
  52 + * @param string $text
  53 + * @param string $lang
  54 + * @return array|mixed
  55 + */
  56 + public function humanizer($text, $lang)
  57 + {
  58 + $driver = self::DRIVER_HUMANIZE_AI_TEXT;
  59 + switch ($driver){
  60 + case self::DRIVER_HUMANIZE:
  61 + $action = 'humainzer/';
  62 + $readilibty = 'Marketing';
  63 + $mode = 'ENHANCED';
  64 + $params = compact('text', 'readilibty', 'mode');
  65 + $result = Http::withoutVerifying()->withHeaders($this->humanizeHeader($driver))->asForm()->post(self::CMER_API . $action, $params)->json();
  66 + break;
  67 + case self::DRIVER_HUMANIZE_AI_TEXT:
  68 + $action = 'humanizeContent?noqueue=1&language=' . $lang;
  69 + $params = compact('text');
  70 + $result = Http::withoutVerifying()->withHeaders($this->humanizeHeader($driver))->post(self::CMER_API . $action, $params)->json();
  71 + break;
  72 + default:
  73 + $result = [];
  74 + break;
  75 +
  76 + }
  77 + return $result;
  78 + }
  79 +
  80 + /**
  81 + * 去AI痕迹结果
  82 + * FIXME humanize:异步获取结果
  83 + * @param $request_id
  84 + * @return \Illuminate\Http\Client\Response
  85 + */
  86 + public function humanizerResult($request_id)
  87 + {
  88 + $action = 'result/';
  89 + $params = compact('request_id');
  90 + return Http::withoutVerifying()->withHeaders($this->humanizeHeader(self::DRIVER_HUMANIZE))->asForm()->post(self::CMER_API . $action, $params);
  91 + }
  92 +}
@@ -17,6 +17,7 @@ Route::middleware(['aloginauth'])->group(function () { @@ -17,6 +17,7 @@ Route::middleware(['aloginauth'])->group(function () {
17 Route::any('/sendNotify', [Aside\Com\CNoticeController::class, 'sendNotify'])->name('admin.sendNotify'); 17 Route::any('/sendNotify', [Aside\Com\CNoticeController::class, 'sendNotify'])->name('admin.sendNotify');
18 Route::any('/getCountry', [Aside\Com\CNoticeController::class, 'getCountry'])->name('admin.getCountry'); 18 Route::any('/getCountry', [Aside\Com\CNoticeController::class, 'getCountry'])->name('admin.getCountry');
19 Route::any('/getDynamicPassword', [Aside\Com\IndexController::class, 'getDynamicPassword'])->name('admin.getDynamicPassword'); 19 Route::any('/getDynamicPassword', [Aside\Com\IndexController::class, 'getDynamicPassword'])->name('admin.getDynamicPassword');
  20 + Route::any('/notAiHumanizer', [Aside\Com\IndexController::class, 'notAiHumanizer'])->name('admin.notAiHumanizer');
20 //会员相关 21 //会员相关
21 Route::prefix('user')->group(function () { 22 Route::prefix('user')->group(function () {
22 //会员管理 23 //会员管理
@@ -574,6 +575,7 @@ Route::middleware(['aloginauth'])->group(function () { @@ -574,6 +575,7 @@ Route::middleware(['aloginauth'])->group(function () {
574 //无需登录验证的路由组 575 //无需登录验证的路由组
575 Route::group([], function () { 576 Route::group([], function () {
576 Route::any('/login', [Aside\LoginController::class, 'login'])->name('admin.login.white'); 577 Route::any('/login', [Aside\LoginController::class, 'login'])->name('admin.login.white');
  578 + Route::any('/stringTranslation', [Aside\Com\IndexController::class, 'stringTranslation'])->name('admin.stringTranslation');
577 // Route::any('/image/{hash}/{w?}/{h?}', [\App\Http\Controllers\File\ImageController::class, 'index'])->name('admin.image_show'); 579 // Route::any('/image/{hash}/{w?}/{h?}', [\App\Http\Controllers\File\ImageController::class, 'index'])->name('admin.image_show');
578 Route::any('/file/{hash}', [\App\Http\Controllers\File\FileController::class, 'index'])->name('admin.file_show'); 580 Route::any('/file/{hash}', [\App\Http\Controllers\File\FileController::class, 'index'])->name('admin.file_show');
579 Route::any('/download_files', [\App\Http\Controllers\File\FileController::class, 'downLoad'])->name('admin.files_downLoad');//导出文件 581 Route::any('/download_files', [\App\Http\Controllers\File\FileController::class, 'downLoad'])->name('admin.files_downLoad');//导出文件