|
@@ -2480,6 +2480,9 @@ class AnimeService
|
|
|
$table_name = 'mp_anime_episodes';
|
|
$table_name = 'mp_anime_episodes';
|
|
|
$id_field = 'id';
|
|
$id_field = 'id';
|
|
|
$id_value = $episode_id;
|
|
$id_value = $episode_id;
|
|
|
|
|
+
|
|
|
|
|
+ // 获取剧集的anime_id用于继承全局数据
|
|
|
|
|
+ $anime_id = getProp($source, 'anime_id');
|
|
|
} else {
|
|
} else {
|
|
|
// 从动漫表获取
|
|
// 从动漫表获取
|
|
|
$source = DB::table('mp_animes')->where('id', $anime_id)->where('is_deleted', 0)->first();
|
|
$source = DB::table('mp_animes')->where('id', $anime_id)->where('is_deleted', 0)->first();
|
|
@@ -2492,6 +2495,11 @@ class AnimeService
|
|
|
$source = (array)$source;
|
|
$source = (array)$source;
|
|
|
$roles = json_decode(getProp($source, 'roles', '[]'), true) ?: [];
|
|
$roles = json_decode(getProp($source, 'roles', '[]'), true) ?: [];
|
|
|
$scenes = json_decode(getProp($source, 'scenes', '[]'), true) ?: [];
|
|
$scenes = json_decode(getProp($source, 'scenes', '[]'), true) ?: [];
|
|
|
|
|
+
|
|
|
|
|
+ // 如果是分集数据,需要处理继承和任务创建逻辑
|
|
|
|
|
+ if ($episode_id) {
|
|
|
|
|
+ $this->processEpisodeRolesAndScenes($episode_id, $anime_id, $roles, $scenes, $source);
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
// 返回生成器函数,用于 SSE 流式输出
|
|
// 返回生成器函数,用于 SSE 流式输出
|
|
|
return function() use ($roles, $scenes, $table_name, $id_field, $id_value) {
|
|
return function() use ($roles, $scenes, $table_name, $id_field, $id_value) {
|
|
@@ -3809,6 +3817,175 @@ class AnimeService
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
|
|
+ * 处理分集的角色和场景数据(继承全局数据或创建新任务)
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param int $episode_id 分集ID
|
|
|
|
|
+ * @param int $anime_id 动漫ID
|
|
|
|
|
+ * @param array $roles 分集角色数组(引用传递)
|
|
|
|
|
+ * @param array $scenes 分集场景数组(引用传递)
|
|
|
|
|
+ * @param array $episode 分集数据
|
|
|
|
|
+ */
|
|
|
|
|
+ private function processEpisodeRolesAndScenes($episode_id, $anime_id, &$roles, &$scenes, $episode) {
|
|
|
|
|
+ // 获取全局动漫的角色和场景数据
|
|
|
|
|
+ $anime = DB::table('mp_animes')->where('id', $anime_id)->first();
|
|
|
|
|
+ if (!$anime) return;
|
|
|
|
|
+
|
|
|
|
|
+ $global_roles = json_decode(getProp($anime, 'roles'), true) ?: [];
|
|
|
|
|
+ $global_scenes = json_decode(getProp($anime, 'scenes'), true) ?: [];
|
|
|
|
|
+
|
|
|
|
|
+ $roles_updated = false;
|
|
|
|
|
+ $scenes_updated = false;
|
|
|
|
|
+
|
|
|
|
|
+ // 处理角色
|
|
|
|
|
+ foreach ($roles as &$role) {
|
|
|
|
|
+ $role_name = getProp($role, 'role');
|
|
|
|
|
+ $role_description = getProp($role, 'description');
|
|
|
|
|
+ $role_url = getProp($role, 'url');
|
|
|
|
|
+ $role_task_id = getProp($role, 'task_id');
|
|
|
|
|
+
|
|
|
|
|
+ // 如果已有URL或已有任务ID,跳过
|
|
|
|
|
+ if (!empty($role_url) || !empty($role_task_id) || $role_name === '旁白') {
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ $url_inherited = false;
|
|
|
|
|
+
|
|
|
|
|
+ // 尝试从全局数据中继承
|
|
|
|
|
+ foreach ($global_roles as $global_role) {
|
|
|
|
|
+ $global_role_name = getProp($global_role, 'role');
|
|
|
|
|
+ $global_role_description = getProp($global_role, 'description');
|
|
|
|
|
+ $global_role_url = getProp($global_role, 'url');
|
|
|
|
|
+ $global_role_task_id = getProp($global_role, 'task_id');
|
|
|
|
|
+ $global_role_task_status = getProp($global_role, 'task_status');
|
|
|
|
|
+
|
|
|
|
|
+ // 满足条件:角色名相同、描述相同、全局有URL
|
|
|
|
|
+ if ($role_name === $global_role_name
|
|
|
|
|
+ && $role_description === $global_role_description
|
|
|
|
|
+ && !empty($global_role_url)) {
|
|
|
|
|
+ // 继承 task_id、task_status 和 url
|
|
|
|
|
+ $role['task_id'] = $global_role_task_id;
|
|
|
|
|
+ $role['task_status'] = $global_role_task_status;
|
|
|
|
|
+ $role['url'] = $global_role_url;
|
|
|
|
|
+ $roles_updated = true;
|
|
|
|
|
+ $url_inherited = true;
|
|
|
|
|
+ dLog('anime')->info("分集ID:{$episode_id} 角色:{$role_name} 继承全局数据");
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 如果无法继承且没有任务ID,创建新任务
|
|
|
|
|
+ if (!$url_inherited && empty($role_task_id)) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ $art_style = getProp($episode, 'art_style');
|
|
|
|
|
+ $description = $role_description;
|
|
|
|
|
+ if ($art_style) {
|
|
|
|
|
+ $description = "美术风格:\n{$art_style}\n主体描述:{$description}\n图片要求:图片侧重点在于主体人物信息,需要突出人物形象,不显示场景或背景信息";
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ $params = [
|
|
|
|
|
+ 'prompt' => $description,
|
|
|
|
|
+ 'ref_img_urls' => []
|
|
|
|
|
+ ];
|
|
|
|
|
+
|
|
|
|
|
+ $task = $this->aiImageGenerationService->createImageGenerationTask($params);
|
|
|
|
|
+ $task_id = $task->id;
|
|
|
|
|
+
|
|
|
|
|
+ if ($task_id) {
|
|
|
|
|
+ $role['task_id'] = $task_id;
|
|
|
|
|
+ $role['task_status'] = 'processing';
|
|
|
|
|
+ $roles_updated = true;
|
|
|
|
|
+ dLog('anime')->info("分集ID:{$episode_id} 角色:{$role_name} 创建图片生成任务,任务ID:{$task_id}");
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (\Exception $e) {
|
|
|
|
|
+ dLog('anime')->error("分集ID:{$episode_id} 角色:{$role_name} 创建图片生成任务失败: " . $e->getMessage());
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 处理场景
|
|
|
|
|
+ foreach ($scenes as &$scene) {
|
|
|
|
|
+ $scene_name = getProp($scene, 'scene');
|
|
|
|
|
+ $scene_description = getProp($scene, 'description');
|
|
|
|
|
+ $scene_url = getProp($scene, 'url');
|
|
|
|
|
+ $scene_task_id = getProp($scene, 'task_id');
|
|
|
|
|
+
|
|
|
|
|
+ // 如果已有URL或已有任务ID,跳过
|
|
|
|
|
+ if (!empty($scene_url) || !empty($scene_task_id)) {
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ $url_inherited = false;
|
|
|
|
|
+
|
|
|
|
|
+ // 尝试从全局数据中继承
|
|
|
|
|
+ foreach ($global_scenes as $global_scene) {
|
|
|
|
|
+ $global_scene_name = getProp($global_scene, 'scene');
|
|
|
|
|
+ $global_scene_description = getProp($global_scene, 'description');
|
|
|
|
|
+ $global_scene_url = getProp($global_scene, 'url');
|
|
|
|
|
+ $global_scene_task_id = getProp($global_scene, 'task_id');
|
|
|
|
|
+ $global_scene_task_status = getProp($global_scene, 'task_status');
|
|
|
|
|
+
|
|
|
|
|
+ // 满足条件:场景名相同、描述相同、全局有URL
|
|
|
|
|
+ if ($scene_name === $global_scene_name
|
|
|
|
|
+ && $scene_description === $global_scene_description
|
|
|
|
|
+ && !empty($global_scene_url)) {
|
|
|
|
|
+ // 继承 task_id、task_status 和 url
|
|
|
|
|
+ $scene['task_id'] = $global_scene_task_id;
|
|
|
|
|
+ $scene['task_status'] = $global_scene_task_status;
|
|
|
|
|
+ $scene['url'] = $global_scene_url;
|
|
|
|
|
+ $scenes_updated = true;
|
|
|
|
|
+ $url_inherited = true;
|
|
|
|
|
+ dLog('anime')->info("分集ID:{$episode_id} 场景:{$scene_name} 继承全局数据");
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 如果无法继承且没有任务ID,创建新任务
|
|
|
|
|
+ if (!$url_inherited && empty($scene_task_id)) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ $art_style = getProp($episode, 'art_style');
|
|
|
|
|
+ $description = $scene_description;
|
|
|
|
|
+ if ($art_style) {
|
|
|
|
|
+ $description = "美术风格:\n{$art_style}\n场景描述:{$description}\n图片要求: 图片侧重点是场景,生成的是场景环境图片,不要出现人物";
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ $params = [
|
|
|
|
|
+ 'prompt' => $description,
|
|
|
|
|
+ 'ref_img_urls' => []
|
|
|
|
|
+ ];
|
|
|
|
|
+
|
|
|
|
|
+ $task = $this->aiImageGenerationService->createImageGenerationTask($params);
|
|
|
|
|
+ $task_id = $task->id;
|
|
|
|
|
+
|
|
|
|
|
+ if ($task_id) {
|
|
|
|
|
+ $scene['task_id'] = $task_id;
|
|
|
|
|
+ $scene['task_status'] = 'processing';
|
|
|
|
|
+ $scenes_updated = true;
|
|
|
|
|
+ dLog('anime')->info("分集ID:{$episode_id} 场景:{$scene_name} 创建图片生成任务,任务ID:{$task_id}");
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (\Exception $e) {
|
|
|
|
|
+ dLog('anime')->error("分集ID:{$episode_id} 场景:{$scene_name} 创建图片生成任务失败: " . $e->getMessage());
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 如果有更新,保存到数据库
|
|
|
|
|
+ if ($roles_updated || $scenes_updated) {
|
|
|
|
|
+ $update_data = ['updated_at' => date('Y-m-d H:i:s')];
|
|
|
|
|
+
|
|
|
|
|
+ if ($roles_updated) {
|
|
|
|
|
+ $update_data['roles'] = json_encode($roles, JSON_UNESCAPED_UNICODE);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if ($scenes_updated) {
|
|
|
|
|
+ $update_data['scenes'] = json_encode($scenes, JSON_UNESCAPED_UNICODE);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ DB::table('mp_anime_episodes')->where('id', $episode_id)->update($update_data);
|
|
|
|
|
+ dLog('anime')->info("分集ID:{$episode_id} 角色和场景数据已更新");
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
* 根据图片URL使用AI反推图片提示词
|
|
* 根据图片URL使用AI反推图片提示词
|
|
|
*
|
|
*
|
|
|
* @param string $img_url 图片URL
|
|
* @param string $img_url 图片URL
|