作者 lyh

gx ai视频

  1 +<?php
  2 +/**
  3 + * @remark :
  4 + * @name :AiVideoTask.php
  5 + * @author :lyh
  6 + * @method :post
  7 + * @time :2025/4/30 11:18
  8 + */
  9 +
  10 +namespace App\Console\Commands\Ai;
  11 +
  12 +use App\Models\Ai\AiVideo;
  13 +use App\Models\Project\AiVideoTask as AiVideoTaskModel;
  14 +use App\Models\RouteMap\RouteMap;
  15 +use App\Services\AiVideoService;
  16 +use App\Services\DingService;
  17 +use App\Services\ProjectServer;
  18 +use Illuminate\Console\Command;
  19 +use Illuminate\Support\Facades\DB;
  20 +use Illuminate\Support\Facades\Redis;
  21 +
  22 +class AiVideoTask extends Command
  23 +{
  24 + /**
  25 + * The name and signature of the console command.
  26 + *
  27 + * @var string
  28 + */
  29 + protected $signature = 'save_ai_video';
  30 +
  31 + public $updateProject = [];//需更新的列表
  32 + public $routes = [];//需要更新的路由
  33 +
  34 + /**
  35 + * The console command description.
  36 + *
  37 + * @var string
  38 + */
  39 + protected $description = '查询ai_video是否已经生成';
  40 +
  41 + /**
  42 + * @return bool
  43 + * @throws \Exception
  44 + */
  45 + public function handle(){
  46 + while (true){
  47 + //获取任务id
  48 + $task_id = $this->getTaskId();
  49 + if(empty($task_id)){
  50 + sleep(300);
  51 + continue;
  52 + }
  53 + $this->_action($task_id);
  54 + }
  55 + return true;
  56 + }
  57 +
  58 + /**
  59 + * 获取任务id
  60 + * @param int $finish_at
  61 + * @return mixed
  62 + */
  63 + public function getTaskId($finish_at = 2)
  64 + {
  65 + $task_id = Redis::rpop('ai_video_task');
  66 + if (empty($task_id)) {
  67 +// if(!empty($this->updateProject)){
  68 +// $this->updateProject($this->updateProject);
  69 +// $this->updateProject = [];
  70 +// }
  71 +// if(!empty($this->routes)){
  72 +// $this->updateRoutes($this->routes);
  73 +// $this->routes = [];
  74 +// }
  75 + $aiVideoTaskModel = new AiVideoTaskModel();
  76 + $finish_at = date('Y-m-d H:i:s', strtotime('-' . $finish_at . ' hour'));
  77 + $ids = $aiVideoTaskModel->formatQuery(['status'=>$aiVideoTaskModel::STATUS_RUNNING,'updated_at'=>['<=',$finish_at]])->pluck('id');
  78 + if(!empty($ids)){
  79 + foreach ($ids as $id) {
  80 + Redis::lpush('ai_video_task', $id);
  81 + }
  82 + }
  83 + $task_id = Redis::rpop('ai_video_task');
  84 + }
  85 + return $task_id;
  86 + }
  87 +
  88 + /**
  89 + * @remark :请求
  90 + * @name :sendRequest
  91 + * @author :lyh
  92 + * @method :post
  93 + * @time :2025/4/30 11:31
  94 + */
  95 + public function _action($task_id){
  96 + $aiVideoTaskModel = new AiVideoTaskModel();
  97 + $item = $aiVideoTaskModel->read(['id'=>$task_id]);
  98 + $this->output('ai_video->start:project ID: ' . $item['project_id'] . ',task ID: ' . $task_id);
  99 + $aiVideoService = new AiVideoService($item['project_id']);
  100 + $aiVideoService->task_id = $item['task_id'];
  101 + //拉取文章数据
  102 + $result = $aiVideoService->getVideoDetail();
  103 + if(empty($result['status']) || ($result['status'] != 200)){
  104 + if($item['number'] < 5){
  105 + $aiVideoTaskModel->edit(['number'=>$item['number'] + 1],['id'=>$item['id']]);
  106 + }else{
  107 + $aiVideoTaskModel->edit(['status'=>9],['id'=>$item['id']]);
  108 + // 钉钉通知
  109 + $dingService = new DingService();
  110 + $body = [
  111 + 'keyword' => 'AI_VIDEO获取失败',
  112 + 'msg' => '任务ID:' . $item['task_id'] . PHP_EOL . '返回信息:' . json_encode($result,JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES),
  113 + 'isAtAll' => false, // 是否@所有人
  114 + ];
  115 + $dingService->handle($body);
  116 + }
  117 + $this->output('error: 数据获取失败,status:' . $result['status'] . ',message: ' . ($result['message'] ?? 'null'));
  118 + return false;
  119 + }
  120 + //保存当前项目ai_blog数据
  121 + ProjectServer::useProject($item['project_id']);
  122 + $aiVideoModel = new AiVideo();
  123 + $aiVideoInfo = $aiVideoModel->read(['task_id'=>$item['task_id']],['id','route']);
  124 + if($aiVideoInfo === false){
  125 + // 钉钉通知
  126 + $dingService = new DingService();
  127 + $body = [
  128 + 'keyword' => 'AI_VIDEO生成错误',
  129 + 'msg' => '任务ID:' . $item['task_id'] . ', 子库获取数据失败, 检查子库数据是否被删除!',
  130 + 'isAtAll' => false, // 是否@所有人
  131 + ];
  132 + $dingService->handle($body);
  133 + $this->output('error: 子库获取数据失败, task id: ' . $task_id);
  134 + $aiVideoTaskModel->edit(['status'=>9],['id'=>$item['id']]);
  135 + DB::disconnect('custom_mysql');
  136 + return false;
  137 + }
  138 + //拿到返回的路由查看是否重复
  139 + $route = RouteMap::setRoute($result['data']['url'], RouteMap::SOURCE_AI_VIDEO, $aiVideoInfo['id'], $item['project_id']);
  140 + if($route != $result['data']['url']){
  141 + $aiVideoService->updateDetail(['route'=>$route,'task_id'=>$item['task_id']]);
  142 + }
  143 + $saveData = [
  144 + 'title'=>$result['data']['title'],
  145 + 'image'=>$result['data']['thumb'],
  146 + 'video_url'=>$result['data']['video_url'],
  147 + 'route'=>$route,
  148 + 'author_id'=>$result['data']['author_id'],
  149 + 'keyword'=>json_encode($result['data']['keyword'],true),
  150 + 'content'=>$result['data']['content'],
  151 + 'text'=>$result['data']['"section'],
  152 + 'status'=>$aiVideoTaskModel::STATUS_FINISH
  153 + ];
  154 + $aiVideoModel->edit($saveData,['task_id'=>$item['task_id']]);
  155 + DB::disconnect('custom_mysql');
  156 + $aiVideoTaskModel->edit(['status'=>$aiVideoTaskModel::STATUS_FINISH],['id'=>$item['id']]);
  157 + $this->output('success: task id: ' . $task_id);
  158 + return true;
  159 + }
  160 +
  161 + /**
  162 + * 输入日志
  163 + * @param $message
  164 + * @return bool
  165 + */
  166 + public function output($message)
  167 + {
  168 + $message = date('Y-m-d H:i:s') . ' ' . $message . PHP_EOL;
  169 + echo $message;
  170 + file_put_contents(storage_path('logs/AiVideo/') . date('Ymd') . '.log', $message, FILE_APPEND);
  171 + return true;
  172 + }
  173 +}
@@ -268,12 +268,13 @@ class ProjectLogic extends BaseLogic @@ -268,12 +268,13 @@ class ProjectLogic extends BaseLogic
268 public function checkAiBlog($param){ 268 public function checkAiBlog($param){
269 $main_lang_id = $param['main_lang_id'] ?? 0; 269 $main_lang_id = $param['main_lang_id'] ?? 0;
270 $is_ai_blog = $param['is_ai_blog'] ?? 0; 270 $is_ai_blog = $param['is_ai_blog'] ?? 0;
  271 + $is_ai_video = $param['is_ai_video'] ?? 0;
271 $company = $param['company'] ?? ''; 272 $company = $param['company'] ?? '';
272 $company_en_name = $param['deploy_optimize']['company_en_name'] ?? ''; 273 $company_en_name = $param['deploy_optimize']['company_en_name'] ?? '';
273 $company_en_description = $param['deploy_optimize']['company_en_description'] ?? ''; 274 $company_en_description = $param['deploy_optimize']['company_en_description'] ?? '';
274 - if($is_ai_blog == 1){ 275 + if($is_ai_blog == 1 || $is_ai_video){
275 if(empty($main_lang_id) || empty($company) || empty($company_en_name) || empty($company_en_description)){ 276 if(empty($main_lang_id) || empty($company) || empty($company_en_name) || empty($company_en_description)){
276 - $this->fail('开启ai_blog--请填写主语种+公司名称+公司英文名称+公司英文介绍'); 277 + $this->fail('开启ai博客/视频功能--请填写主语种+公司名称+公司英文名称+公司英文介绍');
277 } 278 }
278 } 279 }
279 return true; 280 return true;
@@ -63,6 +63,42 @@ class AiVideoService @@ -63,6 +63,42 @@ class AiVideoService
63 } 63 }
64 64
65 /** 65 /**
  66 + * @remark :获取视频详情
  67 + * @name :getVideoDetail
  68 + * @author :lyh
  69 + * @method :post
  70 + * @time :2025/2/14 11:23
  71 + */
  72 + public function getVideoDetail(){
  73 + $request_url = $this->url.'api/video/detail';
  74 + $param = [
  75 + 'mch_id'=>$this->mch_id,
  76 + 'task_id'=>$this->task_id,
  77 + ];
  78 + $this->sign = $this->generateSign($param,$this->key);
  79 + $param['sign'] = $this->sign;
  80 + $result = http_post($request_url,json_encode($param,true));
  81 + return $result;
  82 + }
  83 +
  84 + /**
  85 + * @remark :更新文章
  86 + * @name :updateDetail
  87 + * @author :lyh
  88 + * @method :post
  89 + * @time :2025/2/21 14:38
  90 + * @param :task_id , title , video_url ,thumb , content , author_id , url ,
  91 + */
  92 + public function updateDetail($param){
  93 + $request_url = $this->url.'api/video/save';
  94 + $param['mch_id'] = $this->mch_id;
  95 + $this->sign = $this->generateSign($param,$this->key);
  96 + $param['sign'] = $this->sign;
  97 + $result = http_post($request_url,json_encode($param,true));
  98 + return $result;
  99 + }
  100 +
  101 + /**
66 * @remark :计算签名 102 * @remark :计算签名
67 * @name :generateSign 103 * @name :generateSign
68 * @author :lyh 104 * @author :lyh