|
@@ -3189,6 +3189,7 @@ class AnimeService
|
|
|
$tail_frame = getProp($data, 'tail_frame');
|
|
$tail_frame = getProp($data, 'tail_frame');
|
|
|
$first_frame_url = getProp($data, 'first_frame_url');
|
|
$first_frame_url = getProp($data, 'first_frame_url');
|
|
|
$tail_frame_url = getProp($data, 'tail_frame_url');
|
|
$tail_frame_url = getProp($data, 'tail_frame_url');
|
|
|
|
|
+ $generate_audio = getProp($data, 'generate_audio', 0);
|
|
|
|
|
|
|
|
if (!$segment_id) {
|
|
if (!$segment_id) {
|
|
|
Utils::throwError('1002:分镜ID不能为空');
|
|
Utils::throwError('1002:分镜ID不能为空');
|
|
@@ -3209,17 +3210,70 @@ class AnimeService
|
|
|
// 获取分镜内容
|
|
// 获取分镜内容
|
|
|
$segmentContent = getProp($segment, 'segment_content', '');
|
|
$segmentContent = getProp($segment, 'segment_content', '');
|
|
|
|
|
|
|
|
- // 如果没有传入尾帧描述,使用分镜表中的尾帧描述
|
|
|
|
|
- if (!$tail_frame) {
|
|
|
|
|
- $tail_frame = getProp($segment, 'tail_frame', '');
|
|
|
|
|
|
|
+ // 检查 $segmentContent 中是否已有尾帧描述
|
|
|
|
|
+ $contentHasTailFrame = preg_match('/(?:尾帧描述|尾帧)[::]\s*([^\n]+)/u', $segmentContent, $contentTailFrameMatch);
|
|
|
|
|
+
|
|
|
|
|
+ // 确定最终使用的尾帧描述(优先级:用户输入 > segmentContent自带 > 分镜表字段)
|
|
|
|
|
+ $finalTailFrame = '';
|
|
|
|
|
+ if ($tail_frame) {
|
|
|
|
|
+ // 用户输入了尾帧描述,优先使用
|
|
|
|
|
+ $finalTailFrame = $tail_frame;
|
|
|
|
|
+
|
|
|
|
|
+ // 如果 segmentContent 中已有尾帧描述,需要替换
|
|
|
|
|
+ if ($contentHasTailFrame) {
|
|
|
|
|
+ $segmentContent = preg_replace('/(?:尾帧描述|尾帧)[::]\s*[^\n]+/u', "尾帧描述:$tail_frame", $segmentContent);
|
|
|
|
|
+ }
|
|
|
|
|
+ } elseif ($contentHasTailFrame) {
|
|
|
|
|
+ // segmentContent 中有尾帧描述,使用它
|
|
|
|
|
+ $finalTailFrame = trim($contentTailFrameMatch[1]);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // 两者都没有,使用分镜表中的尾帧描述
|
|
|
|
|
+ $finalTailFrame = getProp($segment, 'tail_frame', '');
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ // 判断 $segmentContent 是否有台词内容,如果有则确保使用中文左右双引号
|
|
|
|
|
+ $hasDialogue = false;
|
|
|
|
|
+ if (preg_match('/(?:台词内容|台词|对白|对话)[::]\s*([^\n]+)/u', $segmentContent, $dialogueMatch)) {
|
|
|
|
|
+ $dialogue = trim($dialogueMatch[1]);
|
|
|
|
|
+
|
|
|
|
|
+ // 如果台词不为空且不是"无"
|
|
|
|
|
+ if (!empty($dialogue) && $dialogue !== '无') {
|
|
|
|
|
+ // 过滤掉所有符号(引号、标点、空格等),只保留文字内容来判断是否有实际台词
|
|
|
|
|
+ $dialogueFiltered = preg_replace('/[""\'\',。!?、;:…—\-\s\p{P}\p{S}]/u', '', $dialogue);
|
|
|
|
|
+ if (!empty($dialogueFiltered) && $dialogueFiltered !== '无') {
|
|
|
|
|
+ $hasDialogue = true;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ $dialogue = preg_replace('/^["”]/u', '“', $dialogue); // 替换句首英文双引号或中文右双引号
|
|
|
|
|
+ $dialogue = preg_replace('/["“]$/u', '”', $dialogue); // 替换句尾英文双引号或中文左双引号
|
|
|
|
|
+ // 句首或句尾没有中文双引号,则分别添加中文左右双引号
|
|
|
|
|
+ if (!preg_match('/^[“]/', $dialogue)) {
|
|
|
|
|
+ $dialogue = '“' . $dialogue;
|
|
|
|
|
+ }
|
|
|
|
|
+ if (!preg_match('/[”]$/', $dialogue)) {
|
|
|
|
|
+ $dialogue .= '”';
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 将修改后的台词替换回 $segmentContent
|
|
|
|
|
+ $originalDialogue = $dialogueMatch[1];
|
|
|
|
|
+ $segmentContent = str_replace($originalDialogue, $dialogue, $segmentContent);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
// 构建完整的提示词
|
|
// 构建完整的提示词
|
|
|
$fullPrompt = $segmentContent;
|
|
$fullPrompt = $segmentContent;
|
|
|
- if ($tail_frame) {
|
|
|
|
|
- $fullPrompt .= "\n尾帧描述:$tail_frame";
|
|
|
|
|
|
|
+ if ($finalTailFrame && !$contentHasTailFrame) {
|
|
|
|
|
+ // 只有当 segmentContent 中没有尾帧描述时才追加
|
|
|
|
|
+ $fullPrompt .= "\n尾帧描述:$finalTailFrame";
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ // 去除多余的换行符(将连续多个换行符替换为单个换行符)
|
|
|
|
|
+ $fullPrompt = preg_replace('/\n{2,}/', "\n", $fullPrompt);
|
|
|
|
|
+ $fullPrompt = trim($fullPrompt);
|
|
|
|
|
+
|
|
|
|
|
+ // 当前是否启用音效同出(没台词强制关闭音效同出,节省资源收费)
|
|
|
|
|
+ $current_generate_audio = $hasDialogue ? $generate_audio : 0;
|
|
|
|
|
+
|
|
|
// 智能选择视频时长
|
|
// 智能选择视频时长
|
|
|
// $videoDuration = $this->calculateOptimalVideoDuration($segmentContent, $tail_frame);
|
|
// $videoDuration = $this->calculateOptimalVideoDuration($segmentContent, $tail_frame);
|
|
|
$videoDuration = -1;
|
|
$videoDuration = -1;
|
|
@@ -3250,16 +3304,16 @@ class AnimeService
|
|
|
$videoParams = [
|
|
$videoParams = [
|
|
|
'model' => $model,
|
|
'model' => $model,
|
|
|
'alias_segment_id' => $segment_id,
|
|
'alias_segment_id' => $segment_id,
|
|
|
- 'prompt' => $fullPrompt,
|
|
|
|
|
|
|
+ 'prompt' => trim($fullPrompt),
|
|
|
'video_duration' => $videoDuration,
|
|
'video_duration' => $videoDuration,
|
|
|
'video_resolution' => '720P',
|
|
'video_resolution' => '720P',
|
|
|
'seed' => -1,
|
|
'seed' => -1,
|
|
|
'ratio' => $ratio,
|
|
'ratio' => $ratio,
|
|
|
- 'generate_audio' => false,
|
|
|
|
|
|
|
+ 'generate_audio' => (int)$current_generate_audio === 0 ? false : true,
|
|
|
'draft' => false,
|
|
'draft' => false,
|
|
|
'watermark' => false,
|
|
'watermark' => false,
|
|
|
'camera_fixed' => false,
|
|
'camera_fixed' => false,
|
|
|
- 'callback_url' => 'http://mpaudio.yqsd.cn/api/video/seedanceCallback'
|
|
|
|
|
|
|
+ // 'callback_url' => 'http://mpaudio.yqsd.cn/api/video/seedanceCallback'
|
|
|
];
|
|
];
|
|
|
|
|
|
|
|
// 如果分镜有图片,作为首帧
|
|
// 如果分镜有图片,作为首帧
|
|
@@ -3372,6 +3426,7 @@ class AnimeService
|
|
|
DB::table('mp_episode_segments')->where('segment_id', $segment_id)->update([
|
|
DB::table('mp_episode_segments')->where('segment_id', $segment_id)->update([
|
|
|
'video_task_id' => $task->id,
|
|
'video_task_id' => $task->id,
|
|
|
'video_task_status' => '生成中',
|
|
'video_task_status' => '生成中',
|
|
|
|
|
+ 'generate_audio' => $generate_audio,
|
|
|
'updated_at' => date('Y-m-d H:i:s')
|
|
'updated_at' => date('Y-m-d H:i:s')
|
|
|
]);
|
|
]);
|
|
|
|
|
|