作者 赵彬吉
正在显示 42 个修改的文件 包含 1055 行增加99 行删除
<?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'];
... ...
<?php
/**
* @remark :
* @name :AiVideoAutoPublish.php
* @author :lyh
* @method :post
* @time :2025/8/1 15:19
*/
namespace App\Console\Commands\Ai;
use App\Models\Ai\AiVideo;
use App\Models\Product\Keyword;
use App\Models\Product\Product;
use App\Models\Project\AiBlogTask as AiBlogTaskModel;
use App\Models\Project\AiVideoAutoLog;
use App\Models\Project\DeployOptimize;
use App\Models\Project\Project;
use App\Services\AiVideoService;
use App\Services\MidJourneyService;
use App\Services\ProjectServer;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use App\Models\Project\AiVideoTask;
use Illuminate\Support\Facades\Redis;
/**
* @remark :ai视频自动发布
* @name :AiVideoAutoPublish
* @author :lyh
* @method :post
* @time :2025/8/1 15:19
*/
class AiVideoAutoPublish extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'ai_video_auto_publish {action}';
/**
* The console command description.
*
* @var string
*/
protected $description = '自动发布AI Video';
public function handle(){
$action = $this->argument('action');
if($action == 'auto_publish'){
$this->auto_publish();
}
}
/**
* @remark :普通项目--自动发布
* @name :auto_six_publish
* @author :lyh
* @method :post
* @time :2025/8/1 15:22
*/
public function auto_publish(){
$this->output('开始自动发布Video文章');
$projectModel = new Project();
$optimizeModel = new DeployOptimize();
$projectList = $projectModel->list(['is_ai_video'=>1,'id'=>1,'project_type'=>0,'delete_status'=>0,'site_status'=>0,'extend_type'=>0],'id',['id']);
foreach ($projectList as $item){
$this->output("项目{$item['id']}开始自动发布");
//获取当前是否开启自动发布aiVideo
$opInfo = $optimizeModel->read(['project_id'=>$item['id']],['is_ai_video_send','send_ai_video_frequency','start_date']);
if($opInfo['is_ai_video_send'] != 1){
$this->output("项目{$item['id']}未开启自动发布" . $opInfo['start_date']);
continue;
}
if(($opInfo['start_date'] > date('Y-m-d')) || empty($opInfo['start_date'])){
$this->output("项目{$item['id']}未到推广时间" . $opInfo['start_date']);
continue;
}
$aiVideoTaskModel = new AiVideoTask();
$next_auto_date = $aiVideoTaskModel->formatQuery(['project_id'=>$item['id'],'next_auto_date'=>['!=',null]])->orderBy('id', 'desc')->value('next_auto_date');
if($next_auto_date && ($next_auto_date > date('Y-m-d'))){
$this->output("项目{$item['id']}未到执行时间" . $next_auto_date);
continue;
}
//获取当前网站的标题
ProjectServer::useProject($item['id']);
$data = $this->getVideoInfo();
if(!empty($data)){
//写入一条零时生成视频记录
$aiVideoAutoLogModel = new AiVideoAutoLog();
$aiVideoAutoLogModel->addReturnId(
['project_id'=>$item['id'],'title'=>$data['title'],'remark'=>$data['remark'],'images'=>json_encode($data['images'],true),'date'=>date('Y-m-d')]
);
}
DB::disconnect('custom_mysql');
}
}
/**
* @remark :获取产品标题+产品描述
* @name :getProduct
* @author :lyh
* @method :post
* @time :2025/8/1 16:09
*/
public function getVideoInfo(){
$data = [];
$random = 2;
if($random == 1){//取产品
$productModel = new Product();
$info = $productModel->formatQuery(['status'=>1,'title'=>['!=',null],'intro'=>['!=',null]])->select(['title','gallery','intro'])->inRandomOrder()->first();
if(empty($info)){
return $data;
}
$data['title'] = $info['title'];
$data['remark'] = strip_tags($info['intro']);
if(empty($data['remark'])){
$data['remark'] = $data['title'];
}
$data['images'] = array_filter(array_map(function ($item) use ($data) {
if (!empty($item['url'])) {
return [
'alt' => $item['title'] ?? $data['title'],
'url' => getImageUrl($item['url']),
];
}
return null;
}, $info['gallery']));
return $data;
}else{
//聚合页获取当前关联产品的图片
$keywordModel = new Keyword();
$keywordInfo = $keywordModel->formatQuery(['keyword_title'=>['!=',null],'keyword_content'=>['!=',null]])->select(['keyword_title','keyword_content'])->inRandomOrder()->first();
if(empty($keywordInfo)){
return $data;
}
$data['title'] = $keywordInfo['keyword_title'];
$data['remark'] = $keywordInfo['keyword_content'];
$data['remark'] = strip_tags($keywordInfo['intro']);
if(empty($data['remark'])){
$data['remark'] = $data['title'];
}
$data['images'] = [];
$productModel = new Product();
$productList = $productModel->list(['keyword_id'=>['like','%,'.$keywordInfo['id'].',%']],'id',['gallery'],'desc',10);
foreach ($productList as $info){
$images = array_filter(array_map(function ($item) use ($data) {
if (!empty($item['url'])) {
return [
'alt' => $item['title'] ?? $data['title'],
'url' => getImageUrl($item['url']),
];
}
return null; // 返回 null 让 array_filter 去除
}, $info['gallery']));
$data['images'] = array_merge($data['images'],$images);
}
return $data;
}
}
/**
* @remark :组装缺少图片数据-推送至发送平台
* @name :send_video
* @author :lyh
* @method :post
* @time :2025/8/2 10:37
*/
public function auto_send_video(){
$number = Redis::get('ai_video_image') ?? 0;
$aiVideoAutoLogModel = new AiVideoAutoLog();
while (true){
if($number > 5){
echo date('Y-m-d H:i:s').':当前生成图片数量已达到最大限度。'.$number.PHP_EOL;
sleep(300);
continue;
}
$item = $aiVideoAutoLogModel->read(['status'=>0]);
if($item === false){
echo date('Y-m-d H:i:s').':无需生成图片的数据。'.PHP_EOL;
sleep(60);
continue;
}
if(count($item['images']) < 6){
echo date('Y-m-d H:i:s').':提交生成图片。'.$item['project_id'].PHP_EOL;
//需要生成图片
$content = "{$item['remark']}{$item['title']}4K,高清 --no logo --ar 16:9";
$midJourneyService = new MidJourneyService();
$result = $midJourneyService->imagine($content);
if($result && !empty($result['trigger_id'])){
echo '提交的数据详情。'.json_encode($result,true).$item['project_id'].PHP_EOL;
Redis::incr('ai_video_image');
$aiVideoAutoLogModel->edit(['trigger_id'=>$result['trigger_id']],['id'=>$item['id']]);
}
}else{
//提交到待执行
$aiVideoAutoLogModel->edit(['status'=>1],['id'=>$item['id']]);
}
}
}
/**
* @remark :状态为1的数据推送至生成视频任务表
* @name :auto_save_video_task
* @author :lyh
* @method :post
* @time :2025/8/4 9:39
*/
public function auto_save_video_task(){
$aiVideoAutoLogModel = new AiVideoAutoLog();
while (true){
//获取任务id
$task_id = $this->getAutoTaskId();
if(empty($task_id)){
sleep(300);
continue;
}
$info = $aiVideoAutoLogModel->read(['id'=>$task_id]);
if($info === false){
echo date('Y-m-d H:i:s').':当前数据不存在或已被删除'.$task_id.PHP_EOL;
continue;
}
try {
$aiVideoTaskModel = new AiVideoTask();
$aiVideoService = new AiVideoService($info['project_id']);
$projectModel = new DeployOptimize();
$video_setting = $projectModel->getValue(['project_id'=>$info['project_id']],'video_setting');
$storage = $aiVideoTaskModel->videoSetting()[$video_setting ?? 1];
$result = $aiVideoService->createTask($info['title'],$info['remark'],$info['images'],[],$storage);
if($result['status'] == 200){
$aiVideoTaskModel->addReturnId(['task_id'=>$result['data']['task_id'],'project_id'=>$info['project_id'],'storage'=>$storage]);
ProjectServer::useProject($info['project_id']);
$aiVideoModel = new AiVideo();
$aiVideoModel->addReturnId(['title'=>$info['title'],'task_id'=>$result['data']['task_id'],'description'=>$info['remark'],'project_id'=>$info['project_id'],'images'=>json_encode($info['images'],true),'anchor'=>json_encode([],true)]);
DB::disconnect('custom_mysql');
}
}catch (\Exception $e){
echo '错误信息:'.$e->getMessage().PHP_EOL;
continue;
}
}
}
/**
* @remark :火锅自动发布任务id
* @name :getAutoTaskId
* @author :lyh
* @method :post
* @time :2025/8/4 9:44
*/
public function getAutoTaskId()
{
$task_id = Redis::rpop('auto_ai_video_task');
if (empty($task_id)) {
$aiVideoAutoLogModel = new AiVideoAutoLog();
$ids = $aiVideoAutoLogModel->formatQuery(['status'=>1])->pluck('id');
if(!empty($ids)){
foreach ($ids as $id) {
Redis::lpush('auto_ai_video_task', $id);
}
}
$task_id = Redis::rpop('auto_ai_video_task');
}
return $task_id;
}
/**
* @remark :
* @name :getAiVideoParam
* @author :lyh
* @method :post
* @time :2025/8/1 16:25
*/
public function getAiVideoParam()
{
$project_id = '1';
$domain = 'www.cs-conveyor.com';
try {
$sitemap_url = 'https://' . $domain . '/sitemap_post_tag.xml';
$sitemap_string = file_get_contents($sitemap_url);
$xml = new \SimpleXMLElement($sitemap_string);
$json = json_encode($xml);
$array = json_decode($json, true);
$urls = array_column($array['url'], 'loc');
$num = 0;
if ($num >= 10) {
return false;
}
AGAIN:
$url = $urls[array_rand($urls)];
$dom = file_get_html($url);
$h1 = $dom->find('.layout .global_section h1', 0);
$title = $h1 ? trim($h1->plaintext) : '';
$p = $dom->find('.layout .global_section p', 0);
$content = $p ? trim($p->plaintext) : '';
$img = $dom->find('.layout .global_section img');
$images = [];
foreach ($img as $item) {
if (empty($item->src) || empty($item->alt))
continue;
array_push($images, ['src' => $item->src, 'alt' => $item->alt]);
}
if (empty($title) || empty($content) || empty($images)) {
$num++;
goto AGAIN;
}
} catch (\Exception $e) {
echo 'project_id: ' . $project_id . ', domain: ' . $domain . ', error: ' . $e->getMessage() . PHP_EOL;
}
}
/**
* @remark :日志
* @name :output
* @author :lyh
* @method :post
* @time :2025/8/1 15:28
*/
public function output($message)
{
Log::channel('ai_video')->info($message);
echo date('Y-m-d H:i:s') . ' ' . $message . PHP_EOL;
}
}
... ...
... ... @@ -127,7 +127,7 @@ class RemainDay extends Command
//按自然日统计
$diff = time() - strtotime($item['uptime']);
$compliance_day = floor($diff / (60 * 60 * 24));
$seo_remain_day = $deploy_build['service_duration'] - $compliance_day;
$seo_remain_day = $deploy_build['seo_service_duration'] - $compliance_day;
}
if($deploy_build['plan'] == 0 && $seo_remain_day < 0 && $deploy_build['seo_service_duration'] != 0){//只有白帽版本的项目且剩余服务时常为0,放入未续费中
// $this->project->edit(['seo_remain_day'=>$seo_remain_day,'finish_remain_day'=>$compliance_day ?? 0,'extend_type'=>Project::TYPE_FIVE],['id'=>$item['id']]);
... ...
... ... @@ -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,
... ...
... ... @@ -9,7 +9,10 @@ use App\Models\Ai\AiCommand;
use App\Models\Domain\DomainInfo;
use App\Models\Industry\ProjectIndustry;
use App\Models\Industry\ProjectIndustryRelated;
use App\Models\WebSetting\WebSetting;
use App\Services\ProjectServer;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
class CheckProjectIndustry extends Command
{
... ... @@ -31,7 +34,13 @@ class CheckProjectIndustry extends Command
{
$ai_command = AiCommand::where('key', 'project_industry')->value('ai');
if (!$ai_command) {
$this->output('AI指令未配置');
$this->output('project_industry指令未配置');
return;
}
$ai_command_new = AiCommand::where('key', 'project_industry2')->value('ai');
if (!$ai_command_new) {
$this->output('project_industry2指令未配置');
return;
}
... ... @@ -55,18 +64,49 @@ class CheckProjectIndustry extends Command
continue;
}
$project_industry = $this->getIndustryByAI($ai_command, $industry_names, $domain);
$is_industry = false;
$project = ProjectServer::useProject($project_id);
if ($project) {
$webSettingModel = new WebSetting();
$web_setting = $webSettingModel->read(['project_id' => $project_id], ['title', 'keyword']);
if (isset($web_setting['title']) && $web_setting['title'] && isset($web_setting['keyword']) && $web_setting['keyword']) {
$project_industry = $this->getIndustryByAINew($ai_command_new, $industry_names, $web_setting['title'], $web_setting['keyword']);
if ($project_industry) {
$project_industry_name = Arr::splitFilterToArray($project_industry);
$project_industry_id = ProjectIndustry::where('status', 1)->whereIn('industry_name', $project_industry_name)->pluck('id')->toArray();
if ($project_industry_id) {
ProjectIndustryRelated::saveRelated($project_id, $project_industry_id);
$is_industry = true;
$this->output('project_id:' . $project_id . ' , domain:' . $domain . ' | success');
}
}
}
DB::disconnect('custom_mysql');
}
if (!$is_industry) {
$project_industry = $this->getIndustryByAI($ai_command, $industry_names, $domain);
if ($project_industry) {
$project_industry_name = Arr::splitFilterToArray($project_industry);
if ($project_industry) {
$project_industry_name = Arr::splitFilterToArray($project_industry);
$project_industry_id = ProjectIndustry::where('status', 1)->whereIn('industry_name', $project_industry_name)->pluck('id')->toArray();
$project_industry_id = ProjectIndustry::where('status', 1)->whereIn('industry_name', $project_industry_name)->pluck('id')->toArray();
ProjectIndustryRelated::saveRelated($project_id, $project_industry_id);
if ($project_industry_id) {
ProjectIndustryRelated::saveRelated($project_id, $project_industry_id);
$this->output('project_id:' . $project_id . ' , domain:' . $domain . ' | success');
} else {
$this->output('project_id:' . $project_id . ' , domain:' . $domain . ' | AI分析行业失败');
$this->output('project_id:' . $project_id . ' , domain:' . $domain . ' | success');
} else {
$this->output('project_id:' . $project_id . ' , domain:' . $domain . ' | AI分析行业失败');
}
} else {
$this->output('project_id:' . $project_id . ' , domain:' . $domain . ' | AI分析行业失败');
}
}
}
}
... ... @@ -90,6 +130,27 @@ class CheckProjectIndustry extends Command
return Common::deal_str($text);
}
/**
* AI分析行业2.0
* @param $ai_command
* @param $industry_names
* @param $title
* @param $keyword
* @return string|string[]
* @author Akun
* @date 2025/08/01 10:10
*/
public function getIndustryByAINew($ai_command, $industry_names, $title, $keyword)
{
$ai_command = str_replace('{industry}', $industry_names, $ai_command);
$ai_command = str_replace('{title}', $title, $ai_command);
$ai_command = str_replace('{keyword}', $keyword, $ai_command);
$text = Gpt::instance()->openai_chat_qqs($ai_command);
return Common::deal_str($text);
}
public function output($msg)
{
echo date('Y-m-d H:i:s') . ' | ' . $msg . PHP_EOL;
... ...
... ... @@ -9,19 +9,24 @@
namespace App\Console\Commands\LyhTest;
use App\Helper\OaGlobalsoApi;
use App\Models\Ai\AiBlog;
use App\Models\News\News;
use App\Models\Product\Category;
use App\Models\Project\AggregateKeywordAffix;
use App\Models\Project\AiBlogTask;
use App\Models\Project\DeployBuild;
use App\Models\Project\KeywordPrefix;
use App\Models\Project\Project;
use App\Models\Project\ProjectAiSetting;
use App\Models\Project\ProjectWhiteHatAffix;
use App\Models\Template\BTemplateMain;
use App\Models\Template\TemplateTypeMain;
use App\Models\WebSetting\WebSetting;
use App\Services\AiBlogService;
use App\Services\CosService;
use App\Services\Geo\GeoService;
use App\Services\MidJourneyService;
use App\Services\ProjectServer;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
... ... @@ -43,7 +48,13 @@ class lyhDemo extends Command
protected $description = '更新路由';
public function handle(){
return $this->_actionRoute();
// $content = "{Introducing the cutting-edge product from Zhejiang Yuexiang Gas Technology Co., Ltd., the Bracket Gas Flowmeter. This innovative gas flowmeter is designed to provide accurate and reliable measurements for a wide range of industrial applications,Equipped with advanced technology and precision components, the Bracket Gas Flowmeter ensures exceptional performance and durability. It offers highly accurate gas flow readings, allowing users to closely monitor and control gas consumption in various processes. The meter's user-friendly interface displays real-time flow rates and totalized flow data, facilitating efficient and convenient data management,With its robust construction and corrosion-resistant materials, the Bracket Gas Flowmeter guarantees long-term reliability, even in harsh operating conditions. It is compatible with various gases such as natural gas, propane, and hydrogen, making it a versatile choice for multiple industries including oil and gas, chemical, and manufacturing,Furthermore, the Bracket Gas Flowmeter is engineered with ease of installation and maintenance in mind. Its compact and space-saving design allows for flexible mounting options, while its modular construction enables quick and hassle-free maintenance. Additionally, it meets international standards for accuracy and safety, ensuring compliance with industry regulations,Choose the Bracket Gas Flowmeter for precise and efficient gas flow measurement, backed by the expertise and commitment of Zhejiang Yuexiang Gas Technology Co., Ltd},{Shop Quality Brackets: Top China Products & Services for Your Needs},4K,高清 --no logo --ar 16:9";
// $midJourneyService = new MidJourneyService();
// $result = $midJourneyService->imagine($content);
$url = 'https://ecdn6-nc.globalso.com/upload/p/1/png/2025-08/688dcebc26a7a59911.png';
$cosService = new CosService();
$data = $cosService->cropAndUploadToCOS($url);
dd($data);
}
/**
... ...
... ... @@ -202,7 +202,9 @@ class SyncProject extends Command
* @param :version:7->v7版本(升级项目默认为v7)
*/
public function sync($param,$is_update = 0){
$version = (($is_update == 1) ? Project::VERSION_SEVEN : ($param['version'] ?? Project::VERSION_ZERO));
//TODO::4月12日 之前的项目都是v6
$version = (($is_update == 1) ? Project::VERSION_SIX : (empty($param['version']) ? Project::VERSION_SEVEN : $param['version']));
$title = date('Ymd') . '-' . $param['company_name'];
$data = [
'project'=>[
... ... @@ -250,6 +252,9 @@ class SyncProject extends Command
}
DB::beginTransaction();
try {
if(isset($data['deploy_build']['plan']) && in_array($data['deploy_build']['plan'],[4,5,15,16,17])){
$data['project']['version'] = 0;
}
if(isset($data['deploy_build']['seo_plan']) && ($data['deploy_build']['seo_plan'] == 1)){
$data['project']['project_type'] = 1;//白帽版本
}
... ...
... ... @@ -54,7 +54,7 @@ class Temp extends Command
*/
public function specialImport()
{
$file_url = 'https://ecdn6.globalso.com/upload/p/3531/file/2025-07/www-cninfo-com-cn_news_v1-1.csv';
$file_url = 'https://ecdn6.globalso.com/upload/p/3531/file/2025-07/www-cninfo-com-cn_news_v1-2.csv';
$domain = 'static.cninfo.com.cn';
$project_id = 3531;
$is_gbk = 0;
... ... @@ -138,11 +138,19 @@ class Temp extends Command
protected function importModule($project_id, $domain, $data)
{
$module_id = 4;
$category_id = 3;
$model = new CustomModuleContent();
$module = $model->read(['module_id' => $module_id, 'name' => $data[0]]);
if (!$module) {
$category_id = '';
if ($data[2] ?? '') {
if ($data['2'] == '最新公告') {
$category_id = ',3,4,';
} elseif ($data['2'] == '定期报告') {
$category_id = ',3,5,';
}
}
$content = '';
if ($data[4] ?? '') {
//处理内容中的pdf文件
... ... @@ -199,7 +207,7 @@ class Temp extends Command
$id = $model->addReturnId(
[
'name' => $data[0],
'category_id' => ',' . $category_id . ',',
'category_id' => $category_id,
'module_id' => $module_id,
'content' => $content,
'seo_title' => $seo_title,
... ... @@ -218,9 +226,20 @@ class Temp extends Command
$model->edit(['route' => $route], ['id' => $id]);
return true;
}
} else {
$category_id = '';
if ($data[2] ?? '') {
if ($data['2'] == '最新公告') {
$category_id = ',3,4,';
} elseif ($data['2'] == '定期报告') {
$category_id = ',3,5,';
}
}
return false;
$model->edit(['category_id' => $category_id], ['id' => $module['id']]);
return false;
}
}
//特殊字符转换
... ...
... ... @@ -215,7 +215,13 @@ class FetchTicketProjects extends Command
$pm_id = ManageHr::where('status', 1)->find($item->deploy_build->manager_mid)->manage_id ?? ManageHr::where('status', 1)->where('name', '李洁玉')->value('manage_id') ?? 0;
// 第一负责人
if ($status == 1)
/**
* 5.0升级6.0的项目,白帽SEO的项目 都划给售后
* 其他:建站中找项目经理,建站完成找杨长远,推广找售后服务经理
*/
if ($item->is_upgrade || $item->project_type == 1)
$engineer_id = $assm_id; // V5升V6,白帽SEO,找售后服务经理
elseif ($status == 1)
$engineer_id = $pm_id; // 建站中找项目经理
elseif ($status == 2)
$engineer_id = Manage::where('status', 1)->where('name', '杨长远')->value('id') ?? 0; // 建站完成找杨长远
... ... @@ -247,7 +253,7 @@ class FetchTicketProjects extends Command
// $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')
$team_ids = ManageHr::whereIn('id', $team_ids_in)->where('status', 1)->pluck('manage_id')
->unique()
->filter(fn($v) => !is_null($v) && $v !== 0)
->values()
... ...
<?php
/**
* @remark :
* @name :AiVideoController.php
* @author :lyh
* @method :post
* @time :2025/8/2 11:18
*/
namespace App\Http\Controllers\Api;
use App\Enums\Common\Code;
use App\Models\Project\AiVideoAutoLog;
use App\Services\CosService;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Redis;
class AiVideoController extends BaseController
{
/**
* @remark :回调方法
* @name :ImageCallBack
* @author :lyh
* @method :post
* @time :2025/8/2 11:19
*/
public function ImageCallBack(){
@file_put_contents(storage_path('logs/lyh_error.log'), var_export($this->param, true) . PHP_EOL, FILE_APPEND);
Log::channel('ai_video')->info('数据详情:'.json_encode($this->param,true));
$count = Redis::decr('ai_video_image');
if ($count < 0) {
Redis::set('ai_video_image', 0);
}
$data = $this->param['attachments'] ?? [];
$aiVideoAutoLogModel = new AiVideoAutoLog();
if(empty($data) || empty($data['url'])){
$aiVideoAutoLogModel->edit(['status'=>9,'result'=>json_encode($this->param,true)],['trigger_id'=>$this->param['id']]);
}
//获取当前数据详情
$info = $aiVideoAutoLogModel->read(['trigger_id'=>$this->param['id']]);
if($info === false){
Log::channel('ai_video')->info('当前数据不存在或已被删除'.$this->param['id']);
}
//上传图片 返回cdn链接
$cosService = new CosService();
$imagePath = $cosService->uploadRemote($info['project_id'],'video',$data['url']);
try {
if($imagePath){
$cos = config('filesystems.disks.cos');
$url = $cos['cdn1'].'/'.$imagePath;
//裁剪图片为4张
$images = [];
$cosService = new CosService();
$data = $cosService->cropAndUploadToCOS($url);
if(!empty($data)){
foreach ($data as $item){
$images[] = ['url'=>$item,'alt'=>''];
}
}
$images = array_merge($images,$info['images']);
Log::channel('ai_video')->info('图片:'.json_encode($images));
$aiVideoAutoLogModel->edit(['images'=>$images,'result'=>json_encode($this->param,true),'status'=>1],['id'=>$info['id']]);
}
}catch (\Exception $e){
Log::channel('ai_video')->info('上传图片失败'.$e->getMessage());
}
$this->response('success');
}
}
... ...
... ... @@ -845,6 +845,7 @@ class ProjectController extends BaseController
"project_manager_name" => $manageHr->getName($item['deploy_build']['manager_mid']), //项目经理
"after_sales_manager_name" => $manageHr->getName($item['deploy_optimize']['manager_mid']), //售后服务经理
"leader_name" => $manageHr->getName($item['deploy_build']['leader_mid']), //组长
'version' => $item['version']
];
if ($item['type'] == Project::TYPE_TWO) {
$param['is_compliance'] = RankData::where('project_id', $item['id'])->where('lang', '')->value('is_compliance') ?: 0;
... ... @@ -1283,4 +1284,5 @@ class ProjectController extends BaseController
NoticeLog::createLog(NoticeLog::TYPE_UPDATE_PROJECT_TDK, ['project_id' => $this->param['project_id'],'url'=>$this->param['url']]);
$this->response('success',Code::SUCCESS,['url'=>$this->param['url']]);
}
}
... ...
... ... @@ -114,17 +114,24 @@ class RenewProjectController extends BaseController
* @time :2023/8/18 14:33
*/
public function notHaveRenewItems(Project $project){
$this->map['extend_type'] = $project::TYPE_FIVE;//未续费网站 if(!empty($param['search']) && !empty($param['search_type'])){
$this->map['extend_type'] = $project::TYPE_FIVE;//未续费网站
if(!empty($this->map['title'])){
$this->map['title'] = ['like', '%'.$this->map['title'].'%'];
}
$domainModel = new DomainInfo();
if(!empty($this->map['domain'])){
$parsedUrl = parse_url($this->map['domain']);
$search_domain = $parsedUrl['host'] ?? $this->map['domain'];
$projectIds = $domainModel->selectField(['domain'=>['like','%'.$search_domain.'%']],'project_id');
$this->map['id'] = ['in',$projectIds];
unset($this->map['domain']);
}
$lists = $project->formatQuery($this->map)->with('payment')->with('deploy_build')
->with('deploy_optimize')->with('online_check')
->with('project_after')->paginate($this->row, ['*'], 'page', $this->page);
if(!empty($lists)){
$lists = $lists->toArray();
$manageModel = new ManageHr();
$domainModel = new DomainInfo();
foreach ($lists['list'] as $k=>$item){
$item = $this->handleParam($item,$manageModel,$domainModel);
$lists['list'][$k] = $item;
... ...
... ... @@ -28,6 +28,7 @@ class AsideTicketController extends BaseController
$lists = Tickets::with([
'logs.engineer',
'project.pm',
'project.projectV6',
])
->when(!empty($validated['engineer_id']), function ($query) use ($validated) {
// 查 gl_tickets 表 submit_user_id 或 gl_ticket_logs 表 engineer_id
... ...
... ... @@ -30,7 +30,7 @@ class AuthorityScoreController extends BaseController
}
/**
* @remark :豹猫数据统计表详情
* @remark :白帽数据统计表详情
* @name :whiteHatReportInfo
* @author :lyh
* @method :post
... ...
... ... @@ -61,11 +61,11 @@ class ComController extends BaseController
$data = [];
$is_ai_blog = $this->getIsAiBlog();
if($is_ai_blog != 1){
$data[] = 57;
$data[] = 6;
}
$is_ai_video = $this->getIsAiVideo();
if($is_ai_video != 1){
$data[] = 74;
$data[] = 27;
}
if($this->user['login_source'] == User::LOGIN_PASSWORD_SOURCE){
$data[] = 19;
... ...
... ... @@ -37,7 +37,7 @@ class GoogleSearchController extends BaseController
//查询详情数据
$searchDetailModel = new GoogleSearchDetail();
$this->map['project_id'] = $this->user['project_id'];
$data = $searchDetailModel->lists($this->map,$this->page,$this->row,'impressions',['keys','click_rate','position','impressions_rate']);
$data = $searchDetailModel->lists($this->map,$this->page,$this->row,'impressions');
if(!empty($data)){
if($this->param['type'] == 'country'){
$codeCountryModel = new GoogleCodeCountry();
... ...
... ... @@ -287,7 +287,6 @@ class InquiryController extends BaseController
throw new \Exception('文件生成失败,请重试');
}
$fileurl = Storage::disk('runtime')->url($file);
// return Storage::disk('runtime')->download($file); //直接下载
$this->response('success',Code::SUCCESS,['url' => $fileurl]);
}
... ...
... ... @@ -40,7 +40,7 @@ class CategoryController extends BaseController
public function index()
{
$this->map = $this->searchParam();
$filed = ['id', 'project_id', 'pid', 'title', 'image', 'route', 'status','created_at','sort'];
$filed = ['id', 'project_id', 'pid', 'title', 'image', 'route', 'status','created_at','sort','is_type'];
$this->map['deleted_at'] = null;
if($this->user['project_id'] == 3283){//分类太多加载失败
$list = $this->get3283Lists($filed);
... ... @@ -260,4 +260,23 @@ class CategoryController extends BaseController
$this->logic->copyCategoryInfo();
$this->response('success');
}
/**
* @remark :更改状态
* @name :editIsType
* @author :lyh
* @method :post
* @time :2025/7/30 14:23
*/
public function editIsType(){
$this->request->validate([
'id'=>['required'],
'is_type'=>['required'],
],[
'id.required' => 'ID不能为空',
'is_type.required' => 'is_type不能为空',
]);
$data = $this->logic->editIsType($this->param['is_type'],$this->param['id']);
$this->response('success',Code::SUCCESS,$data);
}
}
... ...
... ... @@ -80,6 +80,8 @@ class KeywordController extends BaseController
public function searchParam($map){
if(!empty($map['title'])){
$map['title'] = ['like','%'.$map['title'].'%'];
}else{
unset($map['title']);
}
if(!empty($map['keyword_title'])){
$map['keyword_title'] = ['like','%'.$map['keyword_title'].'%'];
... ...
... ... @@ -330,7 +330,7 @@ class TranslateController extends BaseController
$this->pageSixList($data,$count,$v,1,15);
}
$blogInfo = $routeMapModel->read(['route'=>'blog']);
if($blogInfo === false){
if($blogInfo === false && ($this->user['is_show_blog'] == 1)){
$blogModel = new Blog();
$count = $blogModel->formatQuery(['status'=>1])->count();
$v['route'] = 'blog';
... ...
... ... @@ -162,9 +162,6 @@ class DomainInfoLogic extends BaseLogic
if($project_info['type'] == Project::TYPE_CLOSE){
$this->fail('项目已关闭,无法执行此操作');
}
if($project_info['project_type'] == Project::PROJECT_TYPE_SEO){
$this->fail('白帽SEO项目,无法执行此操作');
}
$serverIpModel = new ServersIp();
$serversIpInfo = $serverIpModel->read(['id'=>$project_info['serve_id']],['servers_id','ip','domain']);
if($serversIpInfo === false){
... ... @@ -230,7 +227,13 @@ class DomainInfoLogic extends BaseLogic
}
}
if(isset($this->param['amp_status']) && $this->param['amp_status'] == 1){
//是否开通m站
$amp_status = $this->param['amp_status'] ?? 0;
if($project_info['project_type'] == Project::PROJECT_TYPE_SEO){
$amp_status = 0;
}
if($amp_status){
//需要开通amp站点,判断m域名是否已经解析
$host_array_amp = $host_array;
if (count($host_array_amp) <= 2) {
... ... @@ -264,9 +267,21 @@ class DomainInfoLogic extends BaseLogic
$unique_extend = [];
if(isset($this->param['extend_config']) && $this->param['extend_config']){
foreach ($this->param['extend_config'] as $k=>$v){
if($v['origin'] && (!in_array($v['origin'],$unique_extend))){
$unique_extend[] = $v['origin'];
$extend_config[] = $v;
if(!$v['origin']){
continue;
}
if(!$v['target']){
continue;
}
$origin_array = parse_url($v['origin']);
$origin_url = isset($origin_array['path']) && $origin_array['path'] ? $origin_array['path'] : $origin_array['host'];
$target_array = parse_url($v['target']);
$target_url = isset($target_array['path']) && $target_array['path'] ? $target_array['path'] : $target_array['host'];
if((!in_array($origin_url,$unique_extend))){
$unique_extend[] = $origin_url;
$extend_config[] = ['origin'=>$origin_url,'target'=>$target_url];
}
}
}
... ... @@ -275,9 +290,21 @@ class DomainInfoLogic extends BaseLogic
$amp_unique_extend = [];
if(isset($this->param['amp_extend_config']) && $this->param['amp_extend_config']){
foreach ($this->param['amp_extend_config'] as $ka=>$va){
if($va['origin'] && (!in_array($va['origin'],$amp_unique_extend))){
$amp_unique_extend[] = $va['origin'];
$amp_extend_config[] = $va;
if(!$va['origin']){
continue;
}
if(!$va['target']){
continue;
}
$amp_origin_array = parse_url($va['origin']);
$amp_origin_url = isset($amp_origin_array['path']) && $amp_origin_array['path'] ? $amp_origin_array['path'] : $amp_origin_array['host'];
$amp_target_array = parse_url($va['target']);
$amp_target_url = isset($amp_target_array['path']) && $amp_target_array['path'] ? $amp_target_array['path'] : $amp_target_array['host'];
if((!in_array($amp_origin_url,$amp_unique_extend))){
$amp_unique_extend[] = $amp_origin_url;
$amp_extend_config[] = ['origin'=>$amp_origin_url,'target'=>$amp_target_url];
}
}
}
... ... @@ -298,7 +325,7 @@ class DomainInfoLogic extends BaseLogic
'private_key' => $this->param['key'] ?? '',
'private_cert' => $this->param['cert'] ?? '',
'is_https' => $is_https,
'amp_status' => $this->param['amp_status'] ?? 0,
'amp_status' => $amp_status,
'amp_type' => $this->param['amp_type'] ?? 0,
'amp_extend_config'=>json_encode($amp_extend_config),
'amp_private_key' => $this->param['amp_key'] ?? '',
... ... @@ -310,21 +337,27 @@ class DomainInfoLogic extends BaseLogic
$this->model->edit($data,['id'=>$this->param['id']]);
//新增建站任务
if ($project_info['project_type'] == Project::PROJECT_TYPE_SEO) {
$type = DomainCreateTask::TYPE_BLOG;
} else {
$type = DomainCreateTask::TYPE_MAIN;
}
$task_model = new DomainCreateTask();
$task_info = $task_model->read(['type'=>DomainCreateTask::TYPE_MAIN,'domain_id'=>$this->param['id'],'status'=>['<',DomainCreateTask::STATUS_SUC]]);
$task_info = $task_model->read(['type'=>$type,'domain_id'=>$this->param['id'],'status'=>['<',DomainCreateTask::STATUS_SUC]]);
if(!$task_info){
$task_model->add([
'server_id' => $serversIpInfo['servers_id'],
'project_id' => $info['project_id'],
'domain_id' => $this->param['id'],
'type' => DomainCreateTask::TYPE_MAIN
'type' => $type
]);
}else{
if($task_info['status'] == DomainCreateTask::STATUS_UN){
$task_model->edit(['sort'=>0],['id'=>$task_info['id']]);
//重复提交,提高优先级
$task_model->edit(['sort'=>$task_info['sort'] + 1],['id'=>$task_info['id']]);
}
}
if($data['amp_status']){
if($amp_status){
$task_amp_info = $task_model->read(['type'=>DomainCreateTask::TYPE_AMP,'domain_id'=>$this->param['id'],'status'=>['<',DomainCreateTask::STATUS_SUC]]);
if(!$task_amp_info){
$task_model->add([
... ...
... ... @@ -738,6 +738,24 @@ class ProjectLogic extends BaseLogic
//改为异步
NoticeLog::createLog(NoticeLog::TYPE_INIT_PROJECT, ['project_id' => $param['id']]);
}
//推广续费网站单独处理
if($param['type'] == Project::TYPE_FOUR){
// 提取非 null 的 expire_at 字段
$validDates = array_filter(
array_column($param['payment']['renewal_record'] ?? [], 'expire_at'),
fn($date) => !is_null($date)
);
// 获取最大日期(如果有)
$maxExpireAt = $validDates ? max($validDates) : null;
if(!empty($maxExpireAt)){
$diff = (strtotime($maxExpireAt) - strtotime($param['uptime'] ?? date('Y-m-d'))) / (60 * 60 * 24);
if($param['project_type'] == Project::PROJECT_TYPE_SEO){
$param['deploy_build']['seo_service_duration'] = $diff;
}else{
$param['deploy_build']['service_duration'] = $diff;
}
}
}
return $this->success($param);
}
... ... @@ -944,7 +962,13 @@ class ProjectLogic extends BaseLogic
if($param['zone_id'] != 0){
$map['zone_id'] = $param['zone_id'];
}
return Channel::where($map)->pluck('alias', 'id')->toArray();
$channelData = [];
$chanelModel = new Channel();
$channelList = $chanelModel->list($map,'id',['id','title','alias']);
foreach ($channelList as $item){
$channelData[$item['id']] = $item['title'].'-'.$item['alias'];
}
return $channelData;
case Project::TYPE_THREE:
return User::where('channel_id', $param['channel_id']??0)->pluck('name', 'id')->toArray();
}
... ...
... ... @@ -63,11 +63,12 @@ class AiVideoLogic extends BaseLogic
* @detail :status=1/待执行
*/
public function sendTask(){
$aiVideoTaskModel = new AiVideoTask();
$aiVideoService = new AiVideoService($this->user['project_id']);
$result = $aiVideoService->createTask($this->param['title'],$this->param['description'],$this->param['images'],$this->param['anchor'] ?? []);
$storage = $aiVideoTaskModel->videoSetting()[$this->user['video_setting'] ?? 1];
$result = $aiVideoService->createTask($this->param['title'],$this->param['description'],$this->param['images'],$this->param['anchor'] ?? [],$storage);
if($result['status'] == 200){
$aiVideoTaskModel = new AiVideoTask();
$aiVideoTaskModel->addReturnId(['task_id'=>$result['data']['task_id'],'project_id'=>$this->user['project_id']]);
$aiVideoTaskModel->addReturnId(['task_id'=>$result['data']['task_id'],'project_id'=>$this->user['project_id'],'storage'=>$storage]);
$id = $this->model->addReturnId(['title'=>$this->param['title'],'task_id'=>$result['data']['task_id'],'description'=>$this->param['description'],'project_id'=>$this->user['project_id'],'images'=>json_encode($this->param['images'],true),'anchor'=>json_encode($this->param['anchor'] ?? [],true)]);
return $this->success(['id'=>$id]);
}
... ...
... ... @@ -50,8 +50,8 @@ class AuthorityScoreLogic extends BaseLogic
$endTime = date('Y-m-t 23:59:59', strtotime($this->param['date']));
//当月ai_blog发布数量及链接
$aiBlogModel = new AiBlog();
$data['ai_blog']['count'] = $aiBlogModel->counts(['created_at'=>['between',[$startTime,$endTime]]]);
$aiRouteArr = $aiBlogModel->selectField(['created_at'=>['between',[$startTime,$endTime]]],'route');
$data['ai_blog']['count'] = $aiBlogModel->counts(['created_at'=>['between',[$startTime,$endTime]],'route'=>['!=',null]]);
$aiRouteArr = $aiBlogModel->selectField(['created_at'=>['between',[$startTime,$endTime]],'route'=>['!=',null]],'route');
if(!empty($aiRouteArr)){
foreach ($aiRouteArr as $k => $item){
$aiRouteArr[$k] = $this->user['domain'] . 'blog/' . $item;
... ... @@ -60,8 +60,8 @@ class AuthorityScoreLogic extends BaseLogic
$data['ai_blog']['link'] = $aiRouteArr;
//当月ai_video发布数量及链接
$aiVideoModel = new AiVideo();
$data['ai_video']['count'] =$aiVideoModel->counts(['created_at'=>['between',[$startTime,$endTime]]]);
$aiVideoRouteArr = $aiVideoModel->selectField(['created_at'=>['between',[$startTime,$endTime]]],'route');
$data['ai_video']['count'] =$aiVideoModel->counts(['created_at'=>['between',[$startTime,$endTime]],'route'=>['!=',null]]);
$aiVideoRouteArr = $aiVideoModel->selectField(['created_at'=>['between',[$startTime,$endTime]],'route'=>['!=',null]],'route');
if(!empty($aiVideoRouteArr)){
foreach ($aiVideoRouteArr as $kVideo => $itemVideo){
$aiVideoRouteArr[$kVideo] = $this->user['domain'] . 'video/' . $itemVideo;
... ...
... ... @@ -116,7 +116,7 @@ class BTemplateLogic extends BaseLogic
$bTemplateComModel = new BTemplateCom();
$otherInfo = $bTemplateComModel->read(['source'=>$headComInfo['source'],'common_type'=>BTemplate::COMMON_OTHER,'is_list'=>$headComInfo['is_list'],'is_custom'=>$headComInfo['is_custom'],'template_id'=>$template_id]);
if($otherInfo === false){
$this->fail('获取失败,请联系管理员222');
$otherInfo = $bTemplateComModel->read(['source'=>99,'common_type'=>BTemplate::COMMON_OTHER,'is_list'=>$headComInfo['is_list'],'is_custom'=>$headComInfo['is_custom'],'template_id'=>$template_id]);
}
$footerComInfo = $this->getFooterComHtml($condition,$source,$is_list,$is_custom,$template_id);
$data = ['head_html'=>$headComInfo['html'] ?? '', 'head_style'=>$headComInfo['html_style'] ?? '', 'other'=>$otherInfo['html'] ?? '',
... ...
... ... @@ -151,6 +151,7 @@ class CategoryLogic extends BaseLogic
}else{
$param['describe_image'] = json_encode([]);
}
$this->param['image'] = $this->param['image'] ?? '';
if(isset($param['cate_tak']) && !empty($param['cate_tak'])){
$param['cate_tak'] = json_encode($param['cate_tak']);
}else{
... ... @@ -361,4 +362,16 @@ class CategoryLogic extends BaseLogic
];
return $this->success($param);
}
/**
* @remark :更改分类为聚合页模式
* @name :editIsType
* @author :lyh
* @method :post
* @time :2025/7/30 14:21
*/
public function editIsType($is_type = 0,$id){
$data = $this->model->edit(['is_type'=>$is_type],['id'=>$id]);
return $this->success($data);
}
}
... ...
... ... @@ -61,7 +61,11 @@ class TranslateLogic extends BaseLogic
$param['url'] = $this->param['url'];
$info = $this->model->with('translate_data')->where($param)->first();
//获取当前URl的所有文本内容
$text_array = $this->getUrlRead($url);
try {
$text_array = $this->getUrlRead($url);
}catch (\Exception $e){
$text_array = [];
}
// 原始校对程序
$old_key = [];//key值组成数据
$data_read = json_decode($info && $info['translate_data'] ? $info['translate_data']['data'] : '',JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
... ...
... ... @@ -68,7 +68,7 @@ class WebSettingTextLogic extends BaseLogic
DB::beginTransaction();
try {
$data = [
'anchor_setting'=>$this->param['anchor_setting'] ?? [],
'anchor_setting'=>$this->param['anchor_setting'] ?? ["5","3","4"],
'anchor_is_enable'=>$this->param['anchor_is_enable'],
'anchor_num'=>$this->param['anchor_num'] ?? 0,
'anchor_page_num'=>$this->param['anchor_page_num'] ?? 0,
... ...
... ... @@ -277,6 +277,7 @@ class UserLoginLogic
$info['main_lang_id'] = $project['main_lang_id'];
$info['is_ai_blog'] = $project['is_ai_blog'] ?? 0;
$info['is_ai_video'] = $project['is_ai_video'] ?? 0;
$info['video_setting'] = $project['deploy_optimize']['video_setting'] ?? 1;
$info['image_max'] = $project['image_max'];
$info['is_del_inquiry'] = $project['is_del_inquiry'] ?? 0;
$info['uptime_type'] = $this->getHistory($project);
... ...
... ... @@ -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.
*
... ...
... ... @@ -24,7 +24,6 @@ class ProjectIndustryRelated extends Base
}
//先删除
self::where('project_id', $project_id)->delete();
//批量保存
if (!empty($industry_ids)) {
$data = [];
... ...
<?php
/**
* @remark :
* @name :AiVideoAutoLog.php
* @author :lyh
* @method :post
* @time :2025/8/2 9:59
*/
namespace App\Models\Project;
use App\Helper\Arr;
use App\Models\Base;
class AiVideoAutoLog extends Base
{
protected $table = 'gl_ai_video_auto_log';
/**
* @remark :获取器图片集合
* @name :getImagesAttribute
* @author :lyh
* @method :post
* @time :2025/8/2 10:45
*/
public function getImagesAttribute($value){
if(!empty($value)){
$value = Arr::s2a($value);
}
return $value;
}
}
... ...
... ... @@ -20,4 +20,18 @@ class AiVideoTask extends Base
*/
const STATUS_RUNNING = 1;
const STATUS_FINISH = 2;
/**
* @remark :视频设置
* @name :videoSetting
* @author :lyh
* @method :post
* @time :2025/8/1 17:17
*/
public function videoSetting(){
return [
1 => 'CDN',
2 => 'YOUTUBE'
];
}
}
... ...
... ... @@ -80,7 +80,7 @@ class RouteMap extends Base
if($source == self::SOURCE_PRODUCT){
$suffix = '-product';
}
$route_len = 65;
// $route_len = 65;
}
$length = strlen($sign);
if($length > $route_len){
... ...
... ... @@ -19,7 +19,7 @@ class TicketProject extends Base
public function projectV6()
{
return $this->hasOne(Project::class, 'id', 'table_id')
->where('version', 6);
->select(['id', 'title', 'company', 'is_upgrade', 'project_type']);
}
// 项目经理
... ...
... ... @@ -55,9 +55,9 @@ class AiVideoService
* @method :post
* @time :2025/4/29 17:59
*/
public function createTask($title,$description,$images = [],$anchor = []){
public function createTask($title,$description,$images = [],$anchor = [],$storage = 'CDN'){
$request_url = $this->url.'api/video/create';
$param = ['title'=>$title, 'description'=>$description, 'images'=>$images,'anchor'=>$anchor];
$param = ['title'=>$title, 'description'=>$description, 'images'=>$images,'anchor'=>$anchor,'storage'=>$storage];
$param['mch_id'] = $this->mch_id;
$this->sign = $this->generateSign($param,$this->key);
$param['sign'] = $this->sign;
... ...
... ... @@ -108,7 +108,6 @@ class CosService
{
if(!$key){
$url_arr = parse_url($file_url);
if($same_name){
$path_arr = explode('/',$url_arr['path']);
$filename = end($path_arr);
... ... @@ -131,7 +130,6 @@ class CosService
'secretKey' => $cos['credentials']['secretKey'],
],
]);
if(empty($body_str)){
try {
$body_str = curl_c($file_url,false);
... ... @@ -146,7 +144,6 @@ class CosService
if(!$body_str){
return '';
}
try {
$cosClient->putObject([
'Bucket' => $cos['bucket'],
... ... @@ -378,4 +375,77 @@ class CosService
}
return [];
}
/**
* @remark :ai_video裁剪图片为4张
* @name :cropAndUploadToCOS
* @author :lyh
* @method :post
* @time :2025/8/2 16:52
*/
public function cropAndUploadToCOS($imageUrl)
{
// 1. 下载远程图片内容
$imageData = file_get_contents($imageUrl);
if (!$imageData) {
return false;
}
// 2. 保存原图到临时文件
$tempOriginal = tempnam(sys_get_temp_dir(), 'original_') . '.png';
file_put_contents($tempOriginal, $imageData);
// 3. 使用 GD 加载图像
$src = imagecreatefrompng($tempOriginal);
if (!$src) {
return false;
}
$width = imagesx($src);
$height = imagesy($src);
$halfWidth = intval($width / 2);
$halfHeight = intval($height / 2);
// 4. 从原图 URL 提取路径信息
$parsed = parse_url($imageUrl);
$pathInfo = pathinfo($parsed['path']); // upload/p/1/png/2025-08/688dcebc26a7a59911.png
$cosPath = ltrim($pathInfo['dirname'], '/'); // 相对路径:upload/p/1/png/2025-08
$baseName = $pathInfo['filename']; // 文件名:688dcebc26a7a59911
$ext = $pathInfo['extension'] ?? 'png'; // 扩展名
// 5. 初始化 COS 客户端
$cos = config('filesystems.disks.cos');
$cosClient = new Client([
'region' => $cos['region'],
'credentials' => [
'secretId' => $cos['credentials']['secretId'],
'secretKey' => $cos['credentials']['secretKey'],
],
]);
// 6. 循环裁剪并上传
$resultPaths = [];
$index = 0;
$cos = config('filesystems.disks.cos');
for ($y = 0; $y < 2; $y++) {
for ($x = 0; $x < 2; $x++) {
$crop = imagecreatetruecolor($halfWidth, $halfHeight);
imagecopy($crop, $src, 0, 0, $x * $halfWidth, $y * $halfHeight, $halfWidth, $halfHeight);
$tempCropped = tempnam(sys_get_temp_dir(), 'crop_') . '.png';
imagepng($crop, $tempCropped);
imagedestroy($crop);
// 新文件名,保持路径不变
$filename = $baseName . '_part' . $index++ . '.' . $ext;
$objectKey = $cosPath . '/' . $filename;
// 上传到 COS
$cosClient->putObject([
'Bucket' => $cos['bucket'],
'Key' => $objectKey,
'Body' => fopen($tempCropped, 'rb'),
]);
// 返回相对路径
$resultPaths[] = $cos['cdn1'].'/'.$objectKey;
unlink($tempCropped);
}
}
// 清理资源
imagedestroy($src);
unlink($tempOriginal);
return $resultPaths; // 相对路径数组
}
}
... ...
... ... @@ -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':
... ...
<?php
/**
* @remark :
* @name :MidJourneyService.php
* @author :lyh
* @method :post
* @time :2025/8/2 10:48
*/
namespace App\Services;
use Illuminate\Support\Facades\Http;
class MidJourneyService
{
/**
* 请求域名
* @var string
*/
public $url = 'https://api.cmer.com';
public $header = [
'apikey' => 'UkzZljFv83Z2qBi5YR1o3f2otAVWtug6',
'X-CmerApi-Host' => 'aiccmj.p.cmer.com',
];
/**
* @remark :提交生成图片
* @name :imagine
* @author :lyh
* @method :post
* @time :2025/8/2 10:50
*/
public function imagine($content, string $refer_img = ''){
try {
$data = ['prompt' => $content];
//回调地址
$data['callback_url'] = route('api.ImageCallBack');
$result = Http::withHeaders($this->header)->withoutVerifying()->post($this->url.'/v1/api/trigger/imagine', $data);
$json = $result->json();
}catch (\Throwable $e){
dump($e->getMessage());
$json = [];
}
return $json ?: [];
}
/**
* 扩展图片
* @param $index
* @param $msg_id
* @param $msg_hash
* @param $trigger_id
* @return array|mixed
*/
public function upscale($index, $msg_id, $msg_hash, $trigger_id){
try {
$result = Http::withHeaders($this->header)->withoutVerifying()->post($this->url.'/v1/api/trigger/upscale', [
"index" => $index,
"msg_id" => $msg_id,
"msg_hash" => $msg_hash,
"trigger_id" => $trigger_id
]);
$json = $result->json();
}catch (\Throwable $e){
$json = [];
}
return $json;
}
/**
* 优化图片
* @param $index
* @param $msg_id
* @param $msg_hash
* @param $trigger_id
* @return array|mixed
*/
public function variation($index, $msg_id, $msg_hash, $trigger_id){
try {
$result = Http::withHeaders($this->header)->withoutVerifying()->post($this->url.'/v1/api/trigger/variation', [
"index" => $index,
"msg_id" => $msg_id,
"msg_hash" => $msg_hash,
"trigger_id" => $trigger_id
]);
$json = $result->json();
}catch (\Throwable $e){
$json = [];
}
return $json;
}
}
... ...
... ... @@ -17,6 +17,7 @@ use Illuminate\Support\Facades\Route;
Route::middleware('auth:sanctum')->get('/user', function (Request $request) {
return $request->user();
});
Route::any('ImageCallBack', [\App\Http\Controllers\Api\AiVideoController::class, 'ImageCallBack'])->name('api.ImageCallBack');
Route::any('stripeWebhook', [\App\Http\Controllers\Api\PayStripeController::class, 'handleWebhook'])->name('api.handleWebhook');
Route::any('traffic_visit', [\App\Http\Controllers\Api\NoticeController::class, 'trafficVisit'])->name('api.traffic_visit');
Route::get('optimize_project_list', [\App\Http\Controllers\Api\PrivateController::class, 'optimizeProjectList'])->name('api.optimize_project_list');
... ...
... ... @@ -304,6 +304,7 @@ Route::middleware(['bloginauth'])->group(function () {
Route::post('category/sort', [\App\Http\Controllers\Bside\Product\CategoryController::class, 'sort'])->name('product_category_sort');
Route::any('category/delete', [\App\Http\Controllers\Bside\Product\CategoryController::class, 'delete'])->name('product_category_delete');
Route::any('category/allSort', [\App\Http\Controllers\Bside\Product\CategoryController::class, 'allSort'])->name('product_category_allSort');
Route::any('category/editIsType', [\App\Http\Controllers\Bside\Product\CategoryController::class, 'editIsType'])->name('product_category_editIsType');//列表页聚合页设置
Route::any('category/copyCategory', [\App\Http\Controllers\Bside\Product\CategoryController::class, 'copyCategory'])->name('product_category_copyCategory');
//产品关键词
Route::get('keyword', [\App\Http\Controllers\Bside\Product\KeywordController::class, 'index'])->name('product_keyword');
... ...