|
|
|
<?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;
|
|
|
|
}
|
|
|
|
} |
...
|
...
|
|