|
|
@@ -661,6 +661,8 @@ class AnimeService
|
|
|
Utils::throwError("20003:" . $e->getMessage());
|
|
|
}
|
|
|
|
|
|
+ // 创建任务之后先暂停10s等待异步任务完成
|
|
|
+ sleep(10);
|
|
|
$img_url = $this->loopGetPicTaskResult($task_id);
|
|
|
|
|
|
if (!$img_url) Utils::throwError('20003:图片生成中,请稍后刷新');
|
|
|
@@ -1100,6 +1102,11 @@ class AnimeService
|
|
|
Utils::throwError('1002:请选择分镜');
|
|
|
}
|
|
|
|
|
|
+ // 使用文生文模型重新解析segment_content
|
|
|
+ if (!empty($segment_content)) {
|
|
|
+ $segment_content = $this->parseSegmentContentWithAI($segment_content);
|
|
|
+ }
|
|
|
+
|
|
|
// 根据画面比例给宽高赋值
|
|
|
switch ($ratio) {
|
|
|
case '1:1':
|
|
|
@@ -1166,22 +1173,25 @@ class AnimeService
|
|
|
}
|
|
|
|
|
|
$segment_id = $segment->segment_id;
|
|
|
- $segment_content = $segment->segment_content;
|
|
|
+ $original_segment_content = $segment->segment_content;
|
|
|
+
|
|
|
+ // 如果传入了新的segment_content,使用新的内容,否则使用原有内容
|
|
|
+ $final_segment_content = !empty($segment_content) ? $segment_content : $original_segment_content;
|
|
|
|
|
|
- if (empty($segment_content)) {
|
|
|
+ if (empty($final_segment_content)) {
|
|
|
Utils::throwError('20003:分镜内容不存在,请填写内容后重试');
|
|
|
}
|
|
|
|
|
|
try {
|
|
|
// 分镜剧本数组
|
|
|
$update_data = [
|
|
|
- 'segment_content' => $segment_content,
|
|
|
+ 'segment_content' => $final_segment_content,
|
|
|
'pic_task_status' => '生成中',
|
|
|
'updated_at' => date('Y-m-d H:i:s')
|
|
|
];
|
|
|
|
|
|
// 解析分镜内容,提取画面描述作为主要提示词
|
|
|
- $prompt = $segment_content;
|
|
|
+ $prompt = $final_segment_content;
|
|
|
$ref_img_urls = [];
|
|
|
// 分镜场景
|
|
|
$scene = getProp($data, 'scene');
|
|
|
@@ -1204,7 +1214,7 @@ class AnimeService
|
|
|
$characters = explode(',', $characters);
|
|
|
|
|
|
// 从分镜内容中提取涉及的角色
|
|
|
- $segment_characters = $this->extractCharactersFromSegment($segment_content, array_keys($role_map), $characters);
|
|
|
+ $segment_characters = $this->extractCharactersFromSegment($final_segment_content, array_keys($role_map), $characters);
|
|
|
|
|
|
// 获取匹配角色的参考图
|
|
|
foreach ($segment_characters as $character) {
|
|
|
@@ -1244,6 +1254,40 @@ class AnimeService
|
|
|
|
|
|
// 更新分镜剧本信息
|
|
|
$this->handleSegmentContent($update_data);
|
|
|
+
|
|
|
+ // 如果有对话内容,创建视频配音合成任务(有更改分镜内容时创建)
|
|
|
+ if ($segment_content && getProp($update_data, 'dialogue')) {
|
|
|
+ $now = date('Y-m-d H:i:s');
|
|
|
+ $generate_json = [
|
|
|
+ 'text' => getProp($update_data, 'dialogue'),
|
|
|
+ 'role' => getProp($update_data, 'voice_actor'),
|
|
|
+ 'voice_type' => getProp($update_data, 'voice_type'),
|
|
|
+ 'voice_name' => getProp($update_data, 'voice_name'),
|
|
|
+ 'emotion' => getProp($update_data, 'emotion'),
|
|
|
+ 'emotion_type' => getProp($update_data, 'emotion_type'),
|
|
|
+ 'gender' => getProp($update_data, 'gender'),
|
|
|
+ 'speed_ratio' => getProp($update_data, 'speed_ratio', 0),
|
|
|
+ 'loudness_ratio' => getProp($update_data, 'loudness_ratio', 0),
|
|
|
+ 'emotion_scale' => getProp($update_data, 'emotion_scale', 0),
|
|
|
+ 'pitch' => getProp($update_data, 'pitch', 0),
|
|
|
+ ];
|
|
|
+
|
|
|
+ // 插入视频配音合成任务
|
|
|
+ $dubTaskId = DB::table('mp_dub_video_tasks')->insertGetId([
|
|
|
+ 'alias_segment_id' => $segment_id,
|
|
|
+ 'generate_status' => '执行中',
|
|
|
+ 'audio_url' => '',
|
|
|
+ 'generate_json' => json_encode($generate_json, 256),
|
|
|
+ 'created_at' => date('Y-m-d H:i:s'),
|
|
|
+ 'updated_at' => date('Y-m-d H:i:s'),
|
|
|
+ ]);
|
|
|
+
|
|
|
+ if (!$dubTaskId) {
|
|
|
+ Utils::throwError('20003:创建配音任务失败!');
|
|
|
+ }
|
|
|
+ $update_data['audio_url'] = '';
|
|
|
+ }
|
|
|
+
|
|
|
$boolen = DB::table('mp_episode_segments')
|
|
|
->where('segment_id', $segment_id)
|
|
|
->update($update_data);
|
|
|
@@ -1260,6 +1304,8 @@ class AnimeService
|
|
|
];
|
|
|
}
|
|
|
|
|
|
+ // 创建任务之后先暂停10s等待异步任务完成
|
|
|
+ sleep(10);
|
|
|
$img_url = $this->loopGetPicTaskResult($task_id);
|
|
|
if (!$img_url) Utils::throwError('20003:图片生成中,请稍后刷新');
|
|
|
return $img_url;
|
|
|
@@ -1284,6 +1330,11 @@ class AnimeService
|
|
|
Utils::throwError('1002:请选择分镜');
|
|
|
}
|
|
|
|
|
|
+ // 使用文生文模型重新解析segment_content
|
|
|
+ if (!empty($segment_content)) {
|
|
|
+ $segment_content = $this->parseSegmentContentWithAI($segment_content);
|
|
|
+ }
|
|
|
+
|
|
|
// 根据画面比例给宽高赋值
|
|
|
switch ($ratio) {
|
|
|
case '1:1':
|
|
|
@@ -1350,9 +1401,12 @@ class AnimeService
|
|
|
}
|
|
|
|
|
|
$segment_id = $segment->segment_id;
|
|
|
- $segment_content = $segment->segment_content;
|
|
|
+ $original_segment_content = $segment->segment_content;
|
|
|
|
|
|
- if (empty($segment_content)) {
|
|
|
+ // 如果传入了新的segment_content,使用新的内容,否则使用原有内容
|
|
|
+ $final_segment_content = !empty($segment_content) ? $segment_content : $original_segment_content;
|
|
|
+
|
|
|
+ if (empty($final_segment_content)) {
|
|
|
Utils::throwError('20003:分镜内容不存在,请填写内容后重试');
|
|
|
}
|
|
|
|
|
|
@@ -1370,7 +1424,7 @@ class AnimeService
|
|
|
'act_title' => getProp($segment, 'act_title'),
|
|
|
'segment_id' => $segment_id,
|
|
|
'segment_number' => $new_segment_number,
|
|
|
- 'segment_content' => $segment_content,
|
|
|
+ 'segment_content' => $final_segment_content,
|
|
|
'img_url' => $img_url,
|
|
|
'video_url' => $video_url,
|
|
|
'created_at' => date('Y-m-d H:i:s'),
|
|
|
@@ -1380,10 +1434,42 @@ class AnimeService
|
|
|
// 更新分镜剧本信息
|
|
|
$this->handleSegmentContent($insert_data);
|
|
|
|
|
|
+ // 如果有对话内容,创建视频配音合成任务
|
|
|
+ if (getProp($insert_data, 'dialogue')) {
|
|
|
+ $now = date('Y-m-d H:i:s');
|
|
|
+ $generate_json = [
|
|
|
+ 'text' => getProp($insert_data, 'dialogue'),
|
|
|
+ 'role' => getProp($insert_data, 'voice_actor'),
|
|
|
+ 'voice_type' => getProp($insert_data, 'voice_type'),
|
|
|
+ 'voice_name' => getProp($insert_data, 'voice_name'),
|
|
|
+ 'emotion' => getProp($insert_data, 'emotion'),
|
|
|
+ 'emotion_type' => getProp($insert_data, 'emotion_type'),
|
|
|
+ 'gender' => getProp($insert_data, 'gender'),
|
|
|
+ 'speed_ratio' => getProp($insert_data, 'speed_ratio', 0),
|
|
|
+ 'loudness_ratio' => getProp($insert_data, 'loudness_ratio', 0),
|
|
|
+ 'emotion_scale' => getProp($insert_data, 'emotion_scale', 0),
|
|
|
+ 'pitch' => getProp($insert_data, 'pitch', 0),
|
|
|
+ ];
|
|
|
+
|
|
|
+ // 插入视频配音合成任务
|
|
|
+ $dubTaskId = DB::table('mp_dub_video_tasks')->insertGetId([
|
|
|
+ 'alias_segment_id' => $segment_id,
|
|
|
+ 'generate_status' => '执行中',
|
|
|
+ 'audio_url' => '',
|
|
|
+ 'generate_json' => json_encode($generate_json, 256),
|
|
|
+ 'created_at' => $now,
|
|
|
+ 'updated_at' => $now,
|
|
|
+ ]);
|
|
|
+
|
|
|
+ if (!$dubTaskId) {
|
|
|
+ Utils::throwError('20003:创建配音任务失败!');
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
// 如果没有上传图片则使用当前描述进行生成
|
|
|
if (!$img_url) {
|
|
|
// 解析分镜内容,提取画面描述作为主要提示词
|
|
|
- $prompt = $segment_content;
|
|
|
+ $prompt = $final_segment_content;
|
|
|
$ref_img_urls = [];
|
|
|
// 分镜场景
|
|
|
$scene = getProp($insert_data, 'scene');
|
|
|
@@ -1406,7 +1492,7 @@ class AnimeService
|
|
|
$characters = explode(',', $characters);
|
|
|
|
|
|
// 从分镜内容中提取涉及的角色
|
|
|
- $segment_characters = $this->extractCharactersFromSegment($segment_content, array_keys($role_map), $characters);
|
|
|
+ $segment_characters = $this->extractCharactersFromSegment($final_segment_content, array_keys($role_map), $characters);
|
|
|
|
|
|
// 获取匹配角色的参考图
|
|
|
foreach ($segment_characters as $character) {
|
|
|
@@ -1466,6 +1552,8 @@ class AnimeService
|
|
|
|
|
|
DB::commit();
|
|
|
|
|
|
+ // 创建任务之后先暂停10s等待异步任务完成
|
|
|
+ sleep(10);
|
|
|
if (isset($task_id)) $img_url = $this->loopGetPicTaskResult($task_id);
|
|
|
if (!$img_url) Utils::throwError('20003:图片生成中,请稍后刷新');
|
|
|
$segment = DB::table('mp_episode_segments')->where('segment_id', $segment_id)->first();
|
|
|
@@ -2048,7 +2136,7 @@ class AnimeService
|
|
|
private function loopGetPicTaskResult($task_id) {
|
|
|
$start_count = 0;
|
|
|
$img_url = '';
|
|
|
- while ($start_count <= 30) {
|
|
|
+ while ($start_count <= 20) { // 循环20次请求,每3s一次
|
|
|
sleep(3);
|
|
|
|
|
|
$task = MpGeneratePicTask::where('id', $task_id)->first();
|
|
|
@@ -2082,7 +2170,7 @@ class AnimeService
|
|
|
}
|
|
|
break;
|
|
|
}
|
|
|
- $start_count+=3;
|
|
|
+ $start_count++;
|
|
|
}
|
|
|
|
|
|
return $img_url;
|
|
|
@@ -2624,16 +2712,16 @@ class AnimeService
|
|
|
->where('anime_id', $animeId)
|
|
|
->where('episode_id', $episodeId)
|
|
|
->orderBy('segment_number')
|
|
|
- ->select('segment_id', 'segment_number', 'dub_video_url')
|
|
|
+ ->select('segment_id', 'segment_number', 'video_url', 'audio_url')
|
|
|
->get();
|
|
|
|
|
|
if ($segments->isEmpty()) {
|
|
|
Utils::throwError('20003:未找到该剧集的分镜数据');
|
|
|
}
|
|
|
|
|
|
- // 检查是否所有分镜都有配音视频
|
|
|
+ // 检查是否所有分镜都有配音
|
|
|
$missingVideos = $segments->filter(function($segment) {
|
|
|
- return empty($segment->dub_video_url);
|
|
|
+ return empty($segment->audio_url);
|
|
|
});
|
|
|
|
|
|
if ($missingVideos->isNotEmpty()) {
|
|
|
@@ -2646,7 +2734,8 @@ class AnimeService
|
|
|
foreach ($segments as $segment) {
|
|
|
$generateJson[] = [
|
|
|
'sequence' => $sequence++,
|
|
|
- 'dub_video_url' => $segment->dub_video_url,
|
|
|
+ 'video_url' => $segment->video_url,
|
|
|
+ 'audio_url' => $segment->audio_url,
|
|
|
];
|
|
|
}
|
|
|
|
|
|
@@ -2745,4 +2834,18 @@ class AnimeService
|
|
|
Utils::throwError('20003:' . $e->getMessage());
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 使用文生文模型解析分镜内容
|
|
|
+ */
|
|
|
+ private function parseSegmentContentWithAI($segment_content) {
|
|
|
+ try {
|
|
|
+ // 使用DeepSeek服务的公开方法解析分镜内容
|
|
|
+ return $this->DeepSeekService->parseSegmentContent($segment_content);
|
|
|
+ } catch (\Exception $e) {
|
|
|
+ // 如果AI解析失败,记录日志并返回原内容
|
|
|
+ dLog('anime')->error('AI解析分镜内容失败: ' . $e->getMessage());
|
|
|
+ return $segment_content;
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|