|
|
@@ -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,
|
|
|
+ ];
|
|
|
+ }
|
|
|
}
|