|
|
@@ -5422,7 +5422,7 @@ class AnimeService
|
|
|
|
|
|
$model = getProp($data, 'model');
|
|
|
if (!$model) {
|
|
|
- $model = 'seed-2';
|
|
|
+ $model = 'baidu-doubao-seedance-2-0-260128';
|
|
|
}
|
|
|
// 验证模型是否在可用模型表中
|
|
|
if (!DB::table('mp_video_models')->where('model', $model)->where('is_enabled', 1)->exists()) {
|
|
|
@@ -5463,7 +5463,7 @@ class AnimeService
|
|
|
}
|
|
|
$reference_videos = array_slice($reference_videos, 0, 3);
|
|
|
|
|
|
- // 参考音频(支持数组或JSON字符串,最多3个)
|
|
|
+ // 参考音频:以传入的 reference_audios 为准,有值即视为启用,无值即关闭
|
|
|
$reference_audios = getProp($data, 'reference_audios', []);
|
|
|
if (is_string($reference_audios)) {
|
|
|
$reference_audios = json_decode($reference_audios, true) ?: [];
|
|
|
@@ -5472,10 +5472,13 @@ class AnimeService
|
|
|
Utils::throwError('20003:参考音频格式不正确');
|
|
|
}
|
|
|
$reference_audios = array_values(array_unique(array_filter($reference_audios)));
|
|
|
- if (count($reference_audios) > 3) {
|
|
|
- Utils::throwError('20003:参考音频最多选择3个');
|
|
|
+ $audioLimits = $this->getActAudioLimits($model);
|
|
|
+ if ($audioLimits) {
|
|
|
+ $reference_audios = $this->filterActReferenceAudios($reference_audios, $audioLimits);
|
|
|
+ } else {
|
|
|
+ // 非多模态参考音频模型:保留原有最多3段的限制
|
|
|
+ $reference_audios = array_slice($reference_audios, 0, 3);
|
|
|
}
|
|
|
- $reference_audios = array_slice($reference_audios, 0, 3);
|
|
|
|
|
|
// 余额预检:按预估时长计算所需积分,不足直接报错
|
|
|
$chargeDuration = (int)ceil((float)$video_duration);
|
|
|
@@ -11830,53 +11833,115 @@ class AnimeService
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- $usedUrls = [];
|
|
|
- $totalDuration = 0;
|
|
|
+ // 收集候选音频(同一音频可能被多个角色复用,只保留首次出现的URL用于筛选)
|
|
|
+ $orderedUrls = [];
|
|
|
+ foreach (array_keys($orderedNames) as $name) {
|
|
|
+ $timbre = $timbreMap[$name] ?? '';
|
|
|
+ if ($timbre !== '' && !in_array($timbre, $orderedUrls, true)) {
|
|
|
+ $orderedUrls[] = $timbre;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (empty($orderedUrls)) {
|
|
|
+ return $result;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 复用统一的筛选逻辑:单个音频时长 → 段数 → 总时长(与通用接口 generateVideo 共用)
|
|
|
+ $filtered = $this->filterActReferenceAudiosWithDetail($orderedUrls, $limits);
|
|
|
+ $result['total_duration'] = $filtered['total_duration'];
|
|
|
+
|
|
|
+ // 按角色在正文中的出现顺序回填结果,保证键顺序与提示词编号顺序一致
|
|
|
foreach (array_keys($orderedNames) as $name) {
|
|
|
$timbre = $timbreMap[$name] ?? '';
|
|
|
if ($timbre === '') {
|
|
|
continue;
|
|
|
}
|
|
|
-
|
|
|
- // 相同音频复用同一段素材,不重复计数
|
|
|
- if (isset($usedUrls[$timbre])) {
|
|
|
+ if (isset($filtered['durations'][$timbre])) {
|
|
|
$result['allowed'][$name] = $timbre;
|
|
|
+ } elseif (isset($filtered['rejected'][$timbre])) {
|
|
|
+ $result['excluded'][$name] = $filtered['rejected'][$timbre];
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!empty($result['excluded'])) {
|
|
|
+ dLog('anime')->info('参考音频超出模型限制,已截断', [
|
|
|
+ 'model' => $model,
|
|
|
+ 'limits' => $limits,
|
|
|
+ 'allowed' => array_keys($result['allowed']),
|
|
|
+ 'excluded' => $result['excluded'],
|
|
|
+ 'total_duration' => $result['total_duration'],
|
|
|
+ ]);
|
|
|
+ }
|
|
|
+
|
|
|
+ return $result;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 按模型限制逐条筛选参考音频(片段转视频与通用文生视频共用的判断逻辑)
|
|
|
+ * 顺序:单个音频时长 → 段数上限 → 总时长上限;相同URL复用同一段素材,不重复计数
|
|
|
+ *
|
|
|
+ * @param array $referenceAudios 参考音频URL数组
|
|
|
+ * @param array $limits 限制,如 ['max_count'=>3,'max_single'=>15,'max_total'=>15]
|
|
|
+ * @return array ['allowed' => [url...], 'durations' => [url=>秒], 'rejected' => [url=>原因], 'total_duration' => 秒]
|
|
|
+ */
|
|
|
+ public function filterActReferenceAudiosWithDetail(array $referenceAudios, array $limits) {
|
|
|
+ $allowed = [];
|
|
|
+ $durations = [];
|
|
|
+ $rejected = [];
|
|
|
+ $totalDuration = 0;
|
|
|
+
|
|
|
+ foreach ($referenceAudios as $url) {
|
|
|
+ if (!is_string($url) || trim($url) === '' || isset($durations[$url]) || isset($rejected[$url])) {
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
- $duration = $this->getRemoteAudioDurationSeconds($timbre);
|
|
|
+ $duration = $this->getRemoteAudioDurationSeconds($url);
|
|
|
|
|
|
if ($duration > 0 && $duration > $limits['max_single']) {
|
|
|
- $result['excluded'][$name] = '单个音频时长超限(' . $duration . 's > ' . $limits['max_single'] . 's)';
|
|
|
+ $rejected[$url] = '单个音频时长超限(' . $duration . 's > ' . $limits['max_single'] . 's)';
|
|
|
continue;
|
|
|
}
|
|
|
- if (count($usedUrls) >= $limits['max_count']) {
|
|
|
- $result['excluded'][$name] = '超过参考音频段数上限(' . $limits['max_count'] . '段)';
|
|
|
+ if (count($allowed) >= $limits['max_count']) {
|
|
|
+ $rejected[$url] = '超过参考音频段数上限(' . $limits['max_count'] . '段)';
|
|
|
continue;
|
|
|
}
|
|
|
if ($duration > 0 && ($totalDuration + $duration) > $limits['max_total']) {
|
|
|
- $result['excluded'][$name] = '超过参考音频总时长上限(' . $limits['max_total'] . 's)';
|
|
|
+ $rejected[$url] = '超过参考音频总时长上限(' . $limits['max_total'] . 's)';
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
- $usedUrls[$timbre] = true;
|
|
|
+ $allowed[] = $url;
|
|
|
+ $durations[$url] = max(0, $duration);
|
|
|
$totalDuration += max(0, $duration);
|
|
|
- $result['allowed'][$name] = $timbre;
|
|
|
}
|
|
|
|
|
|
- $result['total_duration'] = round($totalDuration, 2);
|
|
|
+ return [
|
|
|
+ 'allowed' => $allowed,
|
|
|
+ 'durations' => $durations,
|
|
|
+ 'rejected' => $rejected,
|
|
|
+ 'total_duration' => round($totalDuration, 2),
|
|
|
+ ];
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 按模型限制过滤参考音频(通用接口用,仅返回通过的URL数组)
|
|
|
+ *
|
|
|
+ * @param array $referenceAudios 参考音频URL数组
|
|
|
+ * @param array $limits 限制
|
|
|
+ * @return array 过滤后的音频URL数组
|
|
|
+ */
|
|
|
+ public function filterActReferenceAudios(array $referenceAudios, array $limits) {
|
|
|
+ $filtered = $this->filterActReferenceAudiosWithDetail($referenceAudios, $limits);
|
|
|
|
|
|
- if (!empty($result['excluded'])) {
|
|
|
+ if (!empty($filtered['rejected'])) {
|
|
|
dLog('anime')->info('参考音频超出模型限制,已截断', [
|
|
|
- 'model' => $model,
|
|
|
'limits' => $limits,
|
|
|
- 'allowed' => array_keys($result['allowed']),
|
|
|
- 'excluded' => $result['excluded'],
|
|
|
- 'total_duration' => $result['total_duration'],
|
|
|
+ 'allowed' => $filtered['allowed'],
|
|
|
+ 'rejected' => $filtered['rejected'],
|
|
|
+ 'total_duration' => $filtered['total_duration'],
|
|
|
]);
|
|
|
}
|
|
|
|
|
|
- return $result;
|
|
|
+ return $filtered['allowed'];
|
|
|
}
|
|
|
|
|
|
/**
|