Просмотр исходного кода

优化动漫全局和剧集中主体和场景图片生成任务的检查脚本

lh 2 дней назад
Родитель
Сommit
52c7cffcf5
2 измененных файлов с 250 добавлено и 5 удалено
  1. 247 4
      app/Console/Anime/AnimeCheckImgUrlCommand.php
  2. 3 1
      app/Services/Anime/AnimeService.php

+ 247 - 4
app/Console/Anime/AnimeCheckImgUrlCommand.php

@@ -3,6 +3,7 @@
 namespace App\Console\Anime;
 use Illuminate\Console\Command;
 use Illuminate\Support\Facades\DB;
+use App\Services\AIGeneration\AIImageGenerationService;
 
 class AnimeCheckImgUrlCommand extends Command
 {
@@ -20,6 +21,14 @@ class AnimeCheckImgUrlCommand extends Command
      */
     protected $description = '检查动漫对话角色和场景图片生成状态';
 
+    protected $aiImageGenerationService;
+
+    public function __construct(AIImageGenerationService $aiImageGenerationService)
+    {
+        parent::__construct();
+        $this->aiImageGenerationService = $aiImageGenerationService;
+    }
+
     /**
      * Execute the console command.
      *
@@ -28,12 +37,72 @@ class AnimeCheckImgUrlCommand extends Command
     public function handle()
     {
         dLog('generate')->info('====================开始检查动漫对话角色和场景图片生成状态====================');
+        $time_start = microtime(true);
+        $timeout = 50; // 超时时间50秒
+        $check_interval = 3; // 每3秒检查一次
+        
+        while (true) {
+            // 检查是否超时
+            $elapsed_time = microtime(true) - $time_start;
+            if ($elapsed_time >= $timeout) {
+                dLog('generate')->info('检查超时,退出循环');
+                break;
+            }
+
+            // 检查是否有需要处理的数据
+            $has_pending_animes = $this->hasPendingAnimes();
+            $has_pending_episodes = $this->hasPendingEpisodes();
+
+            // 如果没有需要检查的内容,直接跳出循环
+            if (!$has_pending_animes && !$has_pending_episodes) {
+                dLog('generate')->info('没有需要检查的内容,退出循环');
+                break;
+            }
+
+            // 检查动漫全局角色和场景
+            if ($has_pending_animes) {
+                $this->checkAnimes();
+            }
+
+            // 检查剧集角色和场景
+            if ($has_pending_episodes) {
+                $this->checkEpisodes();
+            }
+
+            // 等待3秒后继续下一次检查
+            sleep($check_interval);
+        }
+
+        $time_end = microtime(true);
+        dLog('generate')->info('脚本执行时间: '.round($time_end-$time_start, 2).'秒');
+        dLog('generate')->info('====================结束检查动漫对话角色和场景图片生成状态====================');
+    }
+
+    // 检查动漫全局执行中的任务
+    private function hasPendingAnimes() {
         $time_expire_datetime = date('Y-m-d H:i:s', strtotime('-12 hours'));
         DB::table('mp_animes')->where('generate_status', '执行中')->where('generate_at', '<', $time_expire_datetime)->update([
             'generate_status' => '失败',
             'updated_at'=>date('Y-m-d H:i:s'),
         ]);
-        $time_start = microtime(true);
+
+        return DB::table('mp_animes')->where('generate_status', '执行中')->exists();
+    }
+
+    // 检查剧集执行中的任务
+    private function hasPendingEpisodes() {
+        $time_expire_datetime = date('Y-m-d H:i:s', strtotime('-12 hours'));
+        DB::table('mp_anime_episodes')->where('generate_status', '执行中')->where('generate_at', '<', $time_expire_datetime)->update([
+            'generate_status' => '失败',
+            'updated_at'=>date('Y-m-d H:i:s'),
+        ]);
+
+        return DB::table('mp_anime_episodes')->where('generate_status', '执行中')->exists();
+    }
+
+    // 检查全局
+    private function checkAnimes() {
+        dLog('generate')->info('====================开始检查动漫全局====================');
 
         // 获取待执行的动漫对话数据
         $data = DB::table('mp_animes')->where('generate_status', '执行中')->select('id', 'roles', 'scenes')->get();
@@ -62,11 +131,11 @@ class AnimeCheckImgUrlCommand extends Command
             }
         }
 
-        $time_end = microtime(true);
-        dLog('generate')->info('脚本执行时间: '.round($time_end-$time_start, 2).'秒');
-        dLog('generate')->info('====================结束检查动漫对话角色和场景图片生成状态====================');
+        dLog('generate')->info('====================结束检查动漫全局====================');
     }
 
+
+    // 检查全局角色
     private function checkRoles($id, $roles) {
         $role_success_count = 0;
         foreach ($roles as &$role) {
@@ -99,6 +168,7 @@ class AnimeCheckImgUrlCommand extends Command
         ];
     }
 
+    // 检查全局场景
     private function checkScenes($id, $scenes) {
         $scene_success_count = 0;
         foreach ($scenes as &$scene) {
@@ -130,6 +200,7 @@ class AnimeCheckImgUrlCommand extends Command
         ];
     }
 
+    // 剧集中同步继承全局角色和场景
     private function syncRolesAndScenes($id, $roles, $scenes) {
         // 获取该动漫对话对应的所有剧集
         $episodes = DB::table('mp_anime_episodes')->where('anime_id', $id)->get();
@@ -152,6 +223,14 @@ class AnimeCheckImgUrlCommand extends Command
                 $episode_role_name = getProp($episode_role, 'role');
                 $episode_description = getProp($episode_role, 'description');
                 $episode_url = getProp($episode_role, 'url');
+                $episode_task_id = getProp($episode_role, 'task_id');
+
+                // 如果已有URL或已有任务ID,跳过
+                if (!empty($episode_url) || !empty($episode_task_id)) {
+                    continue;
+                }
+
+                $url_inherited = false;
 
                 // 遍历方法中的角色数据
                 foreach ($roles as $role) {
@@ -166,10 +245,40 @@ class AnimeCheckImgUrlCommand extends Command
                         && !empty($role_url)) {
                         $episode_role['url'] = $role_url;
                         $roles_updated = true;
+                        $url_inherited = true;
                         dLog('generate')->info("剧集ID:{$episode_id} 角色:{$role_name} URL已更新");
                         break;
                     }
                 }
+
+                // 如果无法继承URL,则创建图片生成任务
+                if (!$url_inherited && $episode_role_name != '旁白') {
+                    try {
+                        // 获取剧集的美术风格
+                        $art_style = getProp($episode, 'art_style');
+                        $description = $episode_description;
+                        if ($art_style) {
+                            $description = "美术风格:\n$art_style\n主体描述:$description";
+                        }
+
+                        $params = [
+                            'prompt' => $description,
+                            'ref_img_urls' => []
+                        ];
+                        
+                        $task = $this->aiImageGenerationService->createImageGenerationTask($params);
+                        $task_id = $task->id;
+                        
+                        if ($task_id) {
+                            $episode_role['task_id'] = $task_id;
+                            $episode_role['task_status'] = 'processing';
+                            $roles_updated = true;
+                            dLog('generate')->info("剧集ID:{$episode_id} 角色:{$episode_role_name} 创建图片生成任务,任务ID:{$task_id}");
+                        }
+                    } catch (\Exception $e) {
+                        dLog('generate')->error("剧集ID:{$episode_id} 角色:{$episode_role_name} 创建图片生成任务失败: " . $e->getMessage());
+                    }
+                }
             }
 
             // 更新剧集中的场景URL
@@ -177,6 +286,14 @@ class AnimeCheckImgUrlCommand extends Command
                 $episode_scene_name = getProp($episode_scene, 'scene');
                 $episode_description = getProp($episode_scene, 'description');
                 $episode_url = getProp($episode_scene, 'url');
+                $episode_task_id = getProp($episode_scene, 'task_id');
+
+                // 如果已有URL或已有任务ID,跳过
+                if (!empty($episode_url) || !empty($episode_task_id)) {
+                    continue;
+                }
+
+                $url_inherited = false;
 
                 // 遍历方法中的场景数据
                 foreach ($scenes as $scene) {
@@ -191,10 +308,40 @@ class AnimeCheckImgUrlCommand extends Command
                         && !empty($scene_url)) {
                         $episode_scene['url'] = $scene_url;
                         $scenes_updated = true;
+                        $url_inherited = true;
                         dLog('generate')->info("剧集ID:{$episode_id} 场景:{$scene_name} URL已更新");
                         break;
                     }
                 }
+
+                // 如果无法继承URL,则创建图片生成任务
+                if (!$url_inherited) {
+                    try {
+                        // 获取剧集的美术风格
+                        $art_style = getProp($episode, 'art_style');
+                        $description = $episode_description;
+                        if ($art_style) {
+                            $description = "美术风格:\n$art_style\n场景描述:$description";
+                        }
+
+                        $params = [
+                            'prompt' => $description,
+                            'ref_img_urls' => []
+                        ];
+                        
+                        $task = $this->aiImageGenerationService->createImageGenerationTask($params);
+                        $task_id = $task->id;
+                        
+                        if ($task_id) {
+                            $episode_scene['task_id'] = $task_id;
+                            $episode_scene['task_status'] = 'processing';
+                            $scenes_updated = true;
+                            dLog('generate')->info("剧集ID:{$episode_id} 场景:{$episode_scene_name} 创建图片生成任务,任务ID:{$task_id}");
+                        }
+                    } catch (\Exception $e) {
+                        dLog('generate')->error("剧集ID:{$episode_id} 场景:{$episode_scene_name} 创建图片生成任务失败: " . $e->getMessage());
+                    }
+                }
             }
 
             // 如果有更新,则保存到数据库
@@ -214,4 +361,100 @@ class AnimeCheckImgUrlCommand extends Command
             }
         }
     }
+
+
+    // 检查剧集
+    private function checkEpisodes() {
+        dLog('generate')->info('====================开始检查剧集====================');
+
+        // 获取待执行的剧集数据
+        $data = DB::table('mp_anime_episodes')->where('generate_status', '执行中')->select('id', 'roles', 'scenes')->get();
+        
+        foreach ($data as $item) {
+            $id = getProp($item, 'id');
+            $roles = json_decode(getProp($item, 'roles'), true);
+            $scenes = json_decode(getProp($item, 'scenes'), true);
+            $role_count = count($roles);
+            $scene_count = count($scenes);
+
+            // 处理角色图片状态
+            $role_result = $this->checkEpisodeRoles($id, $roles);
+
+            // 处理场景图片状态
+            $scene_result = $this->checkEpisodeScenes($id, $scenes);
+
+            if ($role_result['success_count'] == $role_count && $scene_result['success_count'] == $scene_count) {
+                // 更新状态为已完成
+                DB::table('mp_anime_episodes')->where('id', $id)->update(['generate_status' => '已完成', 'updated_at'=>date('Y-m-d H:i:s')]);
+                dLog('generate')->info("剧集ID:{$id} 图片已全部生成完毕");
+            }
+        }
+
+        dLog('generate')->info('====================结束检查剧集====================');
+    }
+
+    // 检查剧集角色
+    private function checkEpisodeRoles($id, $roles) {
+        $role_success_count = 0;
+        foreach ($roles as &$role) {
+            $task_id = getProp($role, 'task_id');
+            $task_status = getProp($role, 'task_status');
+            if (!$task_id || $task_status == 'success') {
+                $role_success_count++;
+                continue;
+            }
+            $task = DB::table('mp_generate_pic_tasks')->where('id', $task_id)->select('result_url', 'status')->first();
+            if (in_array(getProp($task, 'status'), ['success', 'failed'])) {
+                $role['task_status'] = 'success';
+                $role['url'] = '';
+                $result_url = getProp($task, 'result_url');
+                if ($result_url && is_json($result_url)) {
+                    $role['url'] = json_decode($result_url, true)[0];
+                }
+
+                $role_success_count++;
+            }
+        }
+
+        if ($role_success_count > 0) {
+            DB::table('mp_anime_episodes')->where('id', $id)->update(['roles' => json_encode($roles, 256)]);
+        }
+
+        return [
+            'roles'         => $roles,
+            'success_count' => $role_success_count,
+        ];
+    }
+
+    // 检查剧集场景
+    private function checkEpisodeScenes($id, $scenes) {
+        $scene_success_count = 0;
+        foreach ($scenes as &$scene) {
+            $task_id = getProp($scene, 'task_id');
+            $task_status = getProp($scene, 'task_status');
+            if (!$task_id || $task_status == 'success') {
+                $scene_success_count++;
+                continue;
+            }
+            $task = DB::table('mp_generate_pic_tasks')->where('id', $task_id)->select('result_url', 'status')->first();
+            if (in_array(getProp($task, 'status'), ['success', 'failed'])) {
+                $scene['task_status'] = 'success';
+                $scene['url'] = '';
+                $result_url = getProp($task, 'result_url');
+                if ($result_url && is_json($result_url)) {
+                    $scene['url'] = json_decode($result_url, true)[0];
+                }
+
+                $scene_success_count++;
+            }
+        }
+
+        if ($scene_success_count > 0) {
+            DB::table('mp_anime_episodes')->where('id', $id)->update(['scenes' => json_encode($scenes, 256)]);
+        }
+        return [
+            'scenes'        => $scenes,
+            'success_count' => $scene_success_count,
+        ];
+    }
 }

+ 3 - 1
app/Services/Anime/AnimeService.php

@@ -80,6 +80,7 @@ class AnimeService
             if ($art_style) $description = "美术风格:\n$art_style\n主体描述:$description";
             // 参考图地址
             $ref_img_url = getProp($role, 'url');
+            if ($ref_img_url) continue;     // 已有图片则跳过
             
             // 此处调用AIImageGenerationService的生成图片任务接口: createImageGenerationTask(注意使用默认参数,prompt使用角色描述),并返回任务id
             try {
@@ -132,6 +133,7 @@ class AnimeService
             if ($art_style) $description = "美术风格:\n$art_style\n\n场景描述:$description";
             // 参考图地址
             $ref_img_url = getProp($scene, 'url');
+            if ($ref_img_url) continue;     // 已有图片则跳过
             
             // 此处调用AIImageGenerationService的生成图片任务接口: createImageGenerationTask(注意使用默认参数,prompt使用角色描述),并返回任务id
             try {
@@ -154,7 +156,7 @@ class AnimeService
             }
         }
         
-        // 保存角色信息
+        // 保存场景信息
         $boolen = DB::table('mp_anime_episodes')->where('id', $episode_id)->update([
             'scenes'             => json_encode($scenes, 256),
             'generate_status'   => '执行中',