|
|
@@ -32,15 +32,12 @@ class AnimeService
|
|
|
];
|
|
|
}
|
|
|
|
|
|
- public function uploadImg($data) {
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
public function batchSetRoleImg($data) {
|
|
|
$anime_id = getProp($data, 'anime_id');
|
|
|
$episode_number = getProp($data, 'episode_number');
|
|
|
if (!$anime_id) Utils::throwError('1002:请选择对话');
|
|
|
- $roles = getProp($data, 'roles');
|
|
|
+ $anime = DB::table('mp_animes')->where('id', $anime_id)->where('is_deleted', 0)->first();
|
|
|
+ $roles = json_decode(getProp($anime, 'roles'), true);
|
|
|
|
|
|
foreach ($roles as &$role) {
|
|
|
$role_name = getProp($role, 'role');
|
|
|
@@ -70,10 +67,11 @@ class AnimeService
|
|
|
}
|
|
|
|
|
|
// 保存角色信息
|
|
|
- $boolen = DB::table('mp_anime_episodes')->where('anime_id', $anime_id)->where('episode_number', $episode_number)->where('is_default', 1)->update([
|
|
|
+ // $boolen = DB::table('mp_animes')->where('anime_id', $anime_id)->where('episode_number', $episode_number)->where('is_default', 1)->update([
|
|
|
+ $boolen = DB::table('mp_animes')->where('id', $anime_id)->update([
|
|
|
'roles' => json_encode($roles, 256),
|
|
|
'generate_status' => '执行中',
|
|
|
- 'generate_status' => date('Y-m-d H:i:s'),
|
|
|
+ 'generate_at' => date('Y-m-d H:i:s'),
|
|
|
'updated_at' => date('Y-m-d H:i:s')
|
|
|
]);
|
|
|
if (!$boolen) {
|
|
|
@@ -88,7 +86,8 @@ class AnimeService
|
|
|
$anime_id = getProp($data, 'anime_id');
|
|
|
if (!$anime_id) Utils::throwError('1002:请选择对话');
|
|
|
$episode_number = getProp($data, 'episode_number');
|
|
|
- $scenes = getProp($data, 'scenes');
|
|
|
+ $anime = DB::table('mp_animes')->where('id', $anime_id)->where('is_deleted', 0)->first();
|
|
|
+ $scenes = json_decode(getProp($anime, 'scenes'), true);
|
|
|
|
|
|
foreach ($scenes as &$scene) {
|
|
|
$scene_name = getProp($scene, 'scene');
|
|
|
@@ -118,10 +117,11 @@ class AnimeService
|
|
|
}
|
|
|
|
|
|
// 保存角色信息
|
|
|
- $boolen = DB::table('mp_anime_episodes')->where('anime_id', $anime_id)->where('episode_number', $episode_number)->where('is_default', 1)->update([
|
|
|
+ // $boolen = DB::table('mp_anime_episodes')->where('anime_id', $anime_id)->where('episode_number', $episode_number)->where('is_default', 1)->update([
|
|
|
+ $boolen = DB::table('mp_animes')->where('id', $anime_id)->update([
|
|
|
'scenes' => json_encode($scenes, 256),
|
|
|
'generate_status' => '执行中',
|
|
|
- 'generate_status' => date('Y-m-d H:i:s'),
|
|
|
+ 'generate_at' => date('Y-m-d H:i:s'),
|
|
|
'updated_at' => date('Y-m-d H:i:s')
|
|
|
]);
|
|
|
if (!$boolen) {
|
|
|
@@ -461,4 +461,230 @@ class AnimeService
|
|
|
return $img_url;
|
|
|
|
|
|
}
|
|
|
+
|
|
|
+ public function batchSetSegmentTasks($data) {
|
|
|
+ $anime_id = getProp($data, 'anime_id');
|
|
|
+ $episode_number = getProp($data, 'episode_number');
|
|
|
+
|
|
|
+ if (!$anime_id || !$episode_number) {
|
|
|
+ Utils::throwError('1002:请选择剧集');
|
|
|
+ }
|
|
|
+
|
|
|
+ // 获取剧集信息
|
|
|
+ $episode = DB::table('mp_anime_episodes')
|
|
|
+ ->where('anime_id', $anime_id)
|
|
|
+ ->where('episode_number', $episode_number)
|
|
|
+ ->where('is_default', 1)
|
|
|
+ ->select('id as episode_id', 'anime_id', 'episode_number')
|
|
|
+ ->first();
|
|
|
+
|
|
|
+ if (!$episode) {
|
|
|
+ Utils::throwError('20003:该剧集不存在');
|
|
|
+ }
|
|
|
+
|
|
|
+ // 获取动漫的角色信息(包含参考图)
|
|
|
+ $anime = DB::table('mp_animes')
|
|
|
+ ->where('id', $anime_id)
|
|
|
+ ->select('roles', 'scenes')
|
|
|
+ ->first();
|
|
|
+
|
|
|
+ if (!$anime || !$anime->roles) {
|
|
|
+ Utils::throwError('20003:未找到角色信息');
|
|
|
+ }
|
|
|
+
|
|
|
+ $roles = json_decode($anime->roles, true);
|
|
|
+ if (!$roles) {
|
|
|
+ Utils::throwError('20003:角色信息格式错误');
|
|
|
+ }
|
|
|
+ // 构建角色名称到参考图的映射
|
|
|
+ $role_map = [];
|
|
|
+ foreach ($roles as $role) {
|
|
|
+ $role_name = getProp($role, 'role');
|
|
|
+ $role_url = getProp($role, 'url');
|
|
|
+ if (!empty($role_name) && !empty($role_url)) {
|
|
|
+ // // 处理角色名称,去除装扮后缀(如:许芸-校服装 -> 许芸)- 修复中文乱码问题(弃用,容易产生重复图片)
|
|
|
+ // $base_name = preg_replace('/[--].*$/u', '', $role_name);
|
|
|
+ // $role_map[$base_name] = $role_url;
|
|
|
+ // 同时保存完整名称的映射
|
|
|
+ $role_map[$role_name] = $role_url;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ $scenes = json_decode($anime->scenes, true);
|
|
|
+ if (!$scenes) {
|
|
|
+ Utils::throwError('20003:角色信息格式错误');
|
|
|
+ }
|
|
|
+ // 构建角色名称到参考图的映射
|
|
|
+ $scene_map = [];
|
|
|
+ foreach ($scenes as $scene) {
|
|
|
+ $scene_name = getProp($scene, 'scene');
|
|
|
+ $scene_url = getProp($scene, 'url');
|
|
|
+ if (!empty($scene_name) && !empty($scene_url)) {
|
|
|
+ $scene_map[$scene_name] = $scene_url;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 获取所有分镜信息
|
|
|
+ $segments = DB::table('mp_episode_segments')
|
|
|
+ ->where('anime_id', $anime_id)
|
|
|
+ ->where('episode_id', $episode->episode_id)
|
|
|
+ ->orderBy('segment_number')
|
|
|
+ ->select('segment_id', 'segment_number', 'segment_content', 'scene', 'characters')
|
|
|
+ ->limit(3)
|
|
|
+ ->get()
|
|
|
+ ->toArray();
|
|
|
+
|
|
|
+ if (empty($segments)) {
|
|
|
+ Utils::throwError('20003:未找到分镜信息');
|
|
|
+ }
|
|
|
+
|
|
|
+ $updated_segments = [];
|
|
|
+ $failed_segments = [];
|
|
|
+
|
|
|
+ // 批量为每个分镜生成图片任务
|
|
|
+ foreach ($segments as $segment) {
|
|
|
+ $segment_id = $segment->segment_id;
|
|
|
+ $segment_content = $segment->segment_content;
|
|
|
+
|
|
|
+ if (empty($segment_content)) {
|
|
|
+ $failed_segments[] = [
|
|
|
+ 'segment_id' => $segment_id,
|
|
|
+ 'error' => '分镜内容为空'
|
|
|
+ ];
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ // 解析分镜内容,提取画面描述作为主要提示词
|
|
|
+ $prompt = $segment_content;
|
|
|
+ $ref_img_urls = [];
|
|
|
+ // 分镜场景
|
|
|
+ $scene = getProp($segment, 'scene');
|
|
|
+ $matched_scene = '';
|
|
|
+ if (isset($scene_map[$scene])) {
|
|
|
+ $img_index = count($ref_img_urls) + 1;
|
|
|
+ $prompt = "场景:$scene(图$img_index)\n$prompt";
|
|
|
+ $ref_img_urls[] = $scene_map[$scene];
|
|
|
+ $matched_scene = $scene;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 分镜角色
|
|
|
+ $characters = getProp($segment, 'characters');
|
|
|
+ $characters = str_replace(['、', ',', ';'], ',', $characters);
|
|
|
+ $roles = explode(',', $characters);
|
|
|
+
|
|
|
+ // 从分镜内容中提取涉及的角色
|
|
|
+ $segment_characters = $this->extractCharactersFromSegment($segment_content, array_keys($role_map), $roles);
|
|
|
+
|
|
|
+ // 获取匹配角色的参考图
|
|
|
+ foreach ($segment_characters as $character) {
|
|
|
+ if (isset($role_map[$character])) {
|
|
|
+ // 将$prompt中出现的角色替换成角色(图1、2、3,序号是$ref_img_urls的个数加1)
|
|
|
+ $img_index = count($ref_img_urls) + 1;
|
|
|
+ $prompt = str_replace($character, $character . '(图' . $img_index . ')', $prompt);
|
|
|
+ $ref_img_urls[] = $role_map[$character];
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 如果没有找到匹配的角色参考图,不使用参考图
|
|
|
+ if (empty($ref_img_urls)) {
|
|
|
+ $ref_img_urls = [];
|
|
|
+ }
|
|
|
+
|
|
|
+ // 准备生成任务参数
|
|
|
+ $params = [
|
|
|
+ 'alias_segment_id' => $segment_id,
|
|
|
+ 'prompt' => $prompt,
|
|
|
+ 'ref_img_urls' => $ref_img_urls
|
|
|
+ ];
|
|
|
+
|
|
|
+ // $task_id = mt_rand(100000, 999999);
|
|
|
+ // 调用AI图片生成服务
|
|
|
+ $task = $this->aiImageGenerationService->createImageGenerationTask($params);
|
|
|
+ $task_id = $task->id;
|
|
|
+
|
|
|
+ if (!$task_id) {
|
|
|
+ $failed_segments[] = [
|
|
|
+ 'segment_id' => $segment_id,
|
|
|
+ 'error' => '创建生成任务失败'
|
|
|
+ ];
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 更新分镜的任务信息
|
|
|
+ $update_result = DB::table('mp_episode_segments')
|
|
|
+ ->where('segment_id', $segment_id)
|
|
|
+ ->update([
|
|
|
+ 'pic_task_id' => $task_id,
|
|
|
+ 'pic_task_status' => '生成中',
|
|
|
+ 'updated_at' => date('Y-m-d H:i:s')
|
|
|
+ ]);
|
|
|
+
|
|
|
+ if ($update_result) {
|
|
|
+ $updated_segments[] = [
|
|
|
+ 'segment_id' => $segment_id,
|
|
|
+ 'task_id' => $task_id,
|
|
|
+ 'status' => '生成中',
|
|
|
+ 'matched_scenes' => $scene,
|
|
|
+ 'matched_roles' => $segment_characters,
|
|
|
+ 'ref_urls_count' => count($ref_img_urls)
|
|
|
+ ];
|
|
|
+ } else {
|
|
|
+ $failed_segments[] = [
|
|
|
+ 'segment_id' => $segment_id,
|
|
|
+ 'error' => '更新分镜任务状态失败'
|
|
|
+ ];
|
|
|
+ }
|
|
|
+
|
|
|
+ } catch (\Exception $e) {
|
|
|
+ $failed_segments[] = [
|
|
|
+ 'segment_id' => $segment_id,
|
|
|
+ 'error' => $e->getMessage()
|
|
|
+ ];
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // // 更新剧集生成状态
|
|
|
+ // if (!empty($updated_segments)) {
|
|
|
+ // DB::table('mp_anime_episodes')
|
|
|
+ // ->where('id', $episode->episode_id)
|
|
|
+ // ->update([
|
|
|
+ // 'generate_status' => '执行中',
|
|
|
+ // 'updated_at' => date('Y-m-d H:i:s')
|
|
|
+ // ]);
|
|
|
+ // }
|
|
|
+
|
|
|
+ return [
|
|
|
+ 'success_count' => count($updated_segments),
|
|
|
+ 'failed_count' => count($failed_segments),
|
|
|
+ 'success_segments' => $updated_segments,
|
|
|
+ 'failed_segments' => $failed_segments,
|
|
|
+ 'total_segments' => count($segments)
|
|
|
+ ];
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 从分镜内容中提取涉及的角色
|
|
|
+ */
|
|
|
+ private function extractCharactersFromSegment($segment_content, $available_characters, $roles) {
|
|
|
+ $found_characters = [];
|
|
|
+
|
|
|
+ foreach ($available_characters as $character) {
|
|
|
+ // 检查角色名称是否在分镜内容中出现
|
|
|
+ if (strpos($segment_content, $character) !== false) {
|
|
|
+ $found_characters[] = $character;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!$found_characters) {
|
|
|
+ foreach ($roles as $character) {
|
|
|
+ // 检查角色名称是否在分镜内容中出现
|
|
|
+ if (strpos($segment_content, $character) !== false) {
|
|
|
+ $found_characters[] = $character;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return array_unique($found_characters);
|
|
|
+ }
|
|
|
}
|