VideoTask.php 13.6 KB
<?php
/**
 * Created by PhpStorm.
 * User: zhl
 * Date: 2024/02/26
 * Time: 10:13
 */
namespace App\Console\Commands\KeywordInVideo;

use App\Console\Commands\Model;
use App\Console\Commands\TaskSub;
use App\Models\Com\KeywordVideoTask;
use App\Models\Com\KeywordVideoTaskLog;
use App\Models\Domain\DomainInfo;
use App\Models\Product\Keyword;
use App\Models\Product\KeywordRelated;
use App\Models\Product\Product;
use App\Services\ProjectServer;
use Illuminate\Console\Command;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Redis;

class VideoTask extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'video_task';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = '视频推广任务';

    /**
     * Create a new command instance.
     *
     * @return void
     */
    public function __construct()
    {
        parent::__construct();
    }

    /**
     * @var int 最大子任务
     */
    public $max_sub_task = 200;
    public $max_num = 49000;
    /**
     * @return bool
     */
    public function handle()
    {
        Log::info('开始视频推广任务');
        $number = KeywordVideoTaskLog::getMonthVideoNum();
        if($number >= $this->max_num){
            Log::info('当月以达到最大视频生成数,任务执行数:' . $number);
            return true;
        }
        $this->createSubTask($number);
        $this->sendSubTask();
        Log::info('结束视频推广任务');
        return true;
    }

    /**
     * 创建子任务
     * TODO 获取需要生成子任务的项目,获取项目中未生成视频的关键词,通过关键词生成初始化子任务
     * @return bool
     */
    public function createSubTask($number)
    {
        $sub_task_num = $this->max_sub_task;
        while (true) {
            if ($sub_task_num <= 0){
                break;
            }
            if($number >= $this->max_num){
                break;
            }
            $task_project = KeywordVideoTask::where(['status' => KeywordVideoTask::STATUS_OPEN])->orderBy('sort', 'desc')->orderBy('id', 'desc')->first();
            if (empty($task_project)){
                break;
            }
            echo '开始,项目id:'.$task_project->project_id.PHP_EOL;
            $domainModel = new DomainInfo();
            $domainInfo = $domainModel->read(['project_id'=>$task_project->project_id]);
            if($domainInfo === false){
                $task_project->status = KeywordVideoTask::STATUS_CLOSE;
                $task_project->save();
                continue;
            }
            ProjectServer::useProject($task_project->project_id);
            if(!empty($task_project->keywords)){
                $keywords = explode(',',trim(',',$task_project->keywords));
            }
            $keyword = $this->getProjectKeyword($task_project->number,$keywords ?? []);
            // 已经没有需要生成视频的关键词
            if (!$keyword) {
                $task_project->status = KeywordVideoTask::STATUS_CLOSE;
                $task_project->save();
                continue;
            }
            $logo_bg = $this->getImage($domainInfo);
            foreach ($keyword as $val) {
                $log = KeywordVideoTaskLog::where(['project_id' => $task_project->project_id, 'keyword_id' => $val->id , 'result_status'=>'200'])->first();
                if ($log){
                    continue;
                }
                $keywordInfo = $this->getKeywordImage($val->id,$task_project->project_id,$domainInfo['domain']);
                if(!empty($keywordInfo['product_list'])){
                    if(!empty($task_project->logo_img)){
                        $logo_bg['logo'] = $task_project->logo_img;
                    }
                    $array = [
                        'project_id' => $task_project->project_id,
                        'keyword_id' => $val->id,
                        'keyword' => $val->title,
                        'data' => json_encode(['url' => $keywordInfo['url'],'title' => $keywordInfo['title'],
                            'description' => $keywordInfo['keyword_content'], 'images' => $keywordInfo['product_list'],
                            'keywords' => $keywordInfo['keyword_list'], 'logo_bg' => $logo_bg , 'template_data' => $task_project->template_data]),
                        'status' => KeywordVideoTaskLog::STATUS_INIT,
                        'updated_at' => date('Y-m-d H:i:s'),
                        'created_at' => date('Y-m-d H:i:s'),
                    ];
                    $rs = KeywordVideoTaskLog::insert($array);
                    if($rs && ($sub_task_num > 0)){
                        $sub_task_num--;
                    }
                }
            }
            Cache::put('video_keyword_number_month',$number + count($keyword),3600);
            $task_project->status = KeywordVideoTask::STATUS_CLOSE;
            $task_project->save();
        }
        return true;
    }

    /**
     * 发送子任务
     * @return bool
     */
    public function sendSubTask()
    {
        $subTask = KeywordVideoTaskLog::where(['status' => KeywordVideoTaskLog::STATUS_INIT])->orderBy('id', 'asc')->get();
        if ($subTask->isEmpty()){
            return true;
        }
        foreach ($subTask as $val) {
            $valData = json_decode($val->data,true);
            $task_id = 'v6-' . uniqid();
            $data = [
                'project_data' => [
                    'tag_url' => $valData['url'],
                    'title' => $valData['title'],
                    'keywords' => $valData['keywords'],
                    'description' => $valData['description'],
                    'images' => $valData['images'],
                    'logo'=> $valData['logo_bg']['logo'] ?? '',
                    'bg'=> $valData['logo_bg']['bg'] ?? '',
                    'template_id'=> ((array)$valData['template_data'])['template_id'] ?? '',
                ],
                'task_id' => $task_id,
                'callback_url' => env('APP_URL') . '/api/video_task_callback',
                'is_ytb'=>false,
                'other_language_subtitle'=>false
            ];
            $result = Http::post('http://216.250.255.116:7866/create_task', $data);//todo::小天的接口
            $res_json = json_decode($result,true);
            $val->task_id = $task_id;
            $val->status = KeywordVideoTaskLog::STATUS_ERROR;
            if(isset($res_json['code']) && ($res_json['code'] == 200)){
                $val->status = KeywordVideoTaskLog::STATUS_RUNNING;
            }
            $val->result_info = $result;
            $val->save();
        }
        return true;
    }

    /**
     * 获取未生成页面的关键词
     * @param $number
     * @return mixed
     */
    public function getProjectKeyword($number,$keywords = [])
    {

        $keyword_id = Keyword::where('video', null)->whereIn("title", $keywords)->whereNull('deleted_at')
            ->where('route', 'not like', '%-tag')->whereNotNull('keyword_content')->inRandomOrder()->take($number)->pluck('id')->toArray();
        $need = $number - count($keyword_id);
        if ($need > 0) {
            $keyword_arr_id = Keyword::where('video', null)->where('route', 'not like', '%-tag')->whereNull('deleted_at')
                ->whereNotNull('keyword_content')->whereNotIn('id', $keyword_id)->orderBy('id','asc')->inRandomOrder()->take($need)->pluck('id')->toArray();
        }
        $keyword_arr_id = array_merge($keyword_id, $keyword_arr_id);
        $keyword = Keyword::whereIn("id", $keyword_arr_id)->get();
        return $keyword;
    }

    /**
     * 获取需要处理的任务
     * @return int
     */
    public function getTaskProject()
    {
//        $task_project = Model::where(['status' => Model::STATUS_OPEN])->orderBy('sort', 'desc')->first();
        $project_id = 110;
        return $project_id;
    }

    /**
     * 根据关键字获取产品主图
     * @param $keyword_id
     * @param $project_id
     * @param $domain
     * @return array
     */
    public function getKeywordImage($keyword_id,$project_id,$domain){
        $keywordModel = new Keyword();
        $keywordInfo = $keywordModel->read(['id'=>$keyword_id]);
        // TODO 当内容太多时,生成视频过长, 尽量保证生成视频30秒左右, 所以需要控制文案内容长度
        $content = $keywordInfo['keyword_content'];
        $content_array = explode(" ", $content);
        if (count($content_array) > 80) {
            $content_array = preg_split("/[,,。]/u", $content);
            $tmp = '';
            foreach ($content_array as $val) {
                $tmp .= $val . '.';
                $tmp_array = explode(' ', $tmp);
                if (count($tmp_array) > 60) {
                    $content = $tmp;
                    break;
                }
            }
        }
        //TODO::所有产品
        $thumb = $this->getRecommendAndHotProducts($keyword_id);
        $keyword_arr = Keyword::where("project_id",$project_id)->where("status",1)->inRandomOrder()->take(10)->pluck('title')->toArray();
        $data = [
            'url'=> 'https://' . $domain.'/'.$keywordInfo['route'],
            'title'=>$keywordInfo['title'],
            'keyword_title'=>$keywordInfo['keyword_title'],
            'keyword_content'=>$content,
            'product_list'=>$thumb ?? [],
            'keyword_list'=>$keyword_arr ?? []
        ];
        return $data;
    }

    /**
     * 关键词聚合页-推荐&热门产品
     */
    public function getRecommendAndHotProducts($keyword_id): ?array
    {
        $productIds = [];
        $productsQuery = Product::where("status",1)->where("keyword_id","like","%,".$keyword_id.",%")->limit(13)->get();
        if (count($productsQuery) > 0){
            foreach ($productsQuery as $item){
                $productIds[] = $item->id;
            }
            if (count($productIds) < 13){
                $product_all_id = Product::where('thumb','!=',null)->whereNotIn('id', $productIds)->where("status",Product::STATUS_ON)->inRandomOrder()->take(20 - count($productIds))->pluck('id')->toArray();
                if(empty($product_all_id)){
                    $randomData = [];
                }else{
                    $randomData = Product::whereIn("id", $product_all_id)->orderByRaw(DB::raw("FIELD(id, " . implode(',', $product_all_id) . ")"))->get();
                }
                $products = $productsQuery->merge($randomData);
            }else{
                $products = $productsQuery;
            }
        }else{
            $product_all_id = Product::where('thumb','!=',null)->where("status",Product::STATUS_ON)->inRandomOrder()->take(20)->pluck('id')->toArray();
            if(empty($product_all_id)){
                $products = [];
            }else{
                $products = Product::whereIn("id", $product_all_id)->orderByRaw(DB::raw("FIELD(id, " . implode(',', $product_all_id) . ")"))->get();
            }
        }
        $data = [];
        if (!empty($products)){
            foreach ($products as $item){
                if(empty($item->thumb) || ($item->thumb['url'] == "")){
                    continue;
                }
                if(count($data) > 13){
                    break;
                }
                $keyword_ids = implode(',',$item->keyword_id);
                $keyword_video_ids = implode(',',$item->keyword_video_id);
                if (strpos(','.$keyword_ids.',', ','.$keyword_id.',') === false) {
                    if(strpos(','.$keyword_video_ids.',', ','.$keyword_id.',') === false){
                        //不包含
                        $productModel = new Product();
                        $keyword_video_ids = !empty($keyword_video_ids) ? ','.$keyword_video_ids.',' : ',' ;
                        $keyword_video_id_str = $keyword_video_ids . $keyword_id.',';
                        $productModel->edit(['keyword_video_id'=>$keyword_video_id_str],['id'=>$item->id]);
                        KeywordRelated::saveRelated($item->id,$keyword_video_ids,2);
                    }
                }
                $data[] = ['url'=>getImageUrl($item->thumb['url']),'title'=>$item->title];
            }
        }
        return $data;
    }

    /**
     * 获取图片
     * @param $domainInfo
     * @return array
     */
    public function getImage($domainInfo){
        $logo = $bg = '';
        try {
            $dom = file_get_html('https://'.$domainInfo['domain'].'/');
            $logoDom = $dom->find('.logo', 0);
            if ($logoDom) {
                $logoDomImg = $logoDom->find("img",0);
                if($logoDomImg != null){
                    $logo = $logoDomImg->src;
                }
            }
            $elements = $dom->find('.section-banner-wrap-block');
            if (count($elements) >= 2) {
                foreach ($elements as $v){
                    $image = $v->find('img', 0);
                    if($image != null){
                        break;
                    }
                }
            } else {
                $image = $dom->find('.section-banner-wrap-block',0);
                if($image != null){
                    $image = $image->find('img', 0);
                }else{
                    $image = null;
                }
            }
            if($image != null){
                $bg = $image->src;
            }
            $dom->clear();
        } catch (\Exception $e) {
            Log::error('file_get_html: ' . $domainInfo['domain'] . ', error message: ' . $e->getMessage());
        }
        return ['logo' => $logo, 'bg' => $bg];
    }
}