瀏覽代碼

1新增全能模式模型参数接口2.对快快AI下的seed模型进行传参适配

lh 1 月之前
父節點
當前提交
ea9abafaab

+ 72 - 0
app/Http/Controllers/Anime/AnimeController.php

@@ -121,6 +121,78 @@ class AnimeController extends BaseController
         return $this->success($models);
     }
 
+    /**
+     * 快快AI Seedance 系列模型的生成参数选项(时长/宽高比/分辨率)
+     * 可选值统一为 key-value 结构:key 为前端展示文案(中文友好),value 为接口接收值
+     *
+     * @return \Illuminate\Http\JsonResponse
+     */
+    public function seedanceModelOptions()
+    {
+        $commonRatios = [
+            ['key' => '16:9', 'value' => '16:9'],
+            ['key' => '4:3', 'value' => '4:3'],
+            ['key' => '1:1', 'value' => '1:1'],
+            ['key' => '3:4', 'value' => '3:4'],
+            ['key' => '9:16', 'value' => '9:16'],
+            ['key' => '21:9', 'value' => '21:9'],
+            ['key' => '智能适配', 'value' => 'adaptive'],
+        ];
+
+        $duration = function (int $min, int $max, int $default = -1) {
+            return [
+                'default' => $default,
+                'min' => $min,
+                'max' => $max,
+                'options' => [
+                    ['key' => '智能选择', 'value' => -1],
+                ],
+            ];
+        };
+
+        $resolutions = function (array $values, string $default = '720p') {
+            $options = [];
+            foreach ($values as $value) {
+                $options[] = ['key' => $value, 'value' => $value];
+            }
+            return [
+                'default' => $default,
+                'options' => $options,
+            ];
+        };
+
+        return $this->success([
+            [
+                'model' => 'seed-2.5',
+                'name' => 'Seedance 2.5',
+                'duration' => $duration(4, 30, -1),
+                'ratios' => $commonRatios,
+                'resolutions' => $resolutions(['480p', '720p', '1080p']),
+            ],
+            [
+                'model' => 'seed-2',
+                'name' => 'Seedance 2.0',
+                'duration' => $duration(4, 15),
+                'ratios' => $commonRatios,
+                'resolutions' => $resolutions(['480p', '720p', '1080p', '4k']),
+            ],
+            [
+                'model' => 'seed-2-fast',
+                'name' => 'Seedance 2.0 Fast',
+                'duration' => $duration(4, 15),
+                'ratios' => $commonRatios,
+                'resolutions' => $resolutions(['480p', '720p']),
+            ],
+            [
+                'model' => 'seed-2-mini',
+                'name' => 'Seedance 2.0 Mini',
+                'duration' => $duration(4, 15),
+                'ratios' => $commonRatios,
+                'resolutions' => $resolutions(['480p', '720p']),
+            ],
+        ]);
+    }
+
     public function artStyleList()
     {
         $result = [

+ 78 - 6
app/Services/AIGeneration/AIVideoGenerationService.php

@@ -66,6 +66,9 @@ class AIVideoGenerationService
             ? (bool)$params['generate_audio']
             : (isset($params['parameters']['generate_audio']) ? (bool)$params['parameters']['generate_audio'] : false);
 
+        // 带参考视频时按 video_to_video 定价(无该定价时积分引擎自动回退 video_generation)
+        $hasReferenceVideo = !empty($params['reference_video_assets']) || !empty($params['reference_videos']);
+
         return [
             'user_id' => $uid,
             'model' => $model,
@@ -73,6 +76,7 @@ class AIVideoGenerationService
             'video_duration' => $params['video_duration'] ?? -1,
             'ratio' => $ratio,
             'generate_audio' => $generateAudio,
+            'mode' => $hasReferenceVideo ? 'video_to_video' : 'video_generation',
             'api_type' => $apiType,
             'source' => !empty($params['alias_segment_id']) ? 'segment' : (!empty($params['alias_act_id']) ? 'act' : ''),
             'alias_segment_id' => $params['alias_segment_id'] ?? '',
@@ -1029,6 +1033,10 @@ class AIVideoGenerationService
         $firstFrame = $params['first_frame_url'] ?? '';
         $tailFrame = $params['tail_frame_url'] ?? '';
 
+        // 请求接口model按 参考视频/分辨率 适配(如 seed-2 -> seed-2-vision-1080)
+        // 系统内记录保持原模型不变,仅外部接口调用时转换
+        $model = $this->kuaikuaiRequestModel($model, $resolution, !empty($referenceVideos));
+
         // 多模态/参考图场景(API地址一致,仅入参兼容)
         if ($referenceImages || $referenceVideos || $referenceAudios) {
             // 有参考素材且存在首帧时,首帧并入参考图首位(文档多模态示例以图片1作为首帧)
@@ -1093,6 +1101,45 @@ class AIVideoGenerationService
     }
 
     /**
+     * 快快AI请求接口模型名适配(仅外部接口调用传参,系统记录保持原模型名)
+     * 规则:
+     * - seed-2:480p/720p -> seed-2;1080p -> seed-2-1080;4k -> seed-2-4k
+     *           带参考视频时分别对应 seed-2-vision / seed-2-vision-1080 / seed-2-vision-4k
+     * - seed-2-fast / seed-2-mini / seed-2.5:仅支持 -vision(不带分辨率变体)
+     *
+     * @param string $model 系统内模型名
+     * @param string $resolution 归一化分辨率(480p/720p/1080p/4k)
+     * @param bool $hasReferenceVideo 是否带参考视频
+     * @return string
+     */
+    private function kuaikuaiRequestModel(string $model, string $resolution, bool $hasReferenceVideo): string
+    {
+        // seed-2 支持 1080p / 4k 分辨率变体
+        if ($model === 'seed-2') {
+            $base = 'seed-2' . ($hasReferenceVideo ? '-vision' : '');
+            if ($resolution === '1080p') {
+                return $base . '-1080';
+            }
+            if ($resolution === '4k') {
+                return $base . '-4k';
+            }
+            return $base;
+        }
+
+        // seed-2-fast / seed-2-mini / seed-2.5 仅适配 -vision,不带分辨率
+        if ($hasReferenceVideo) {
+            $map = [
+                'seed-2-fast' => 'seed-2-fast-vision',
+                'seed-2-mini' => 'seed-2-mini-vision',
+                'seed-2.5' => 'seed-2.5-vision',
+            ];
+            return $map[$model] ?? $model;
+        }
+
+        return $model;
+    }
+
+    /**
      * 将 Seedance 2.0 参考图上传为百度AI网关素材
      * 失败处理与智帧AI的processReferenceImagesToAssets一致:删除参考图的同时清理提示词中的<图片N>标记
      *
@@ -2704,12 +2751,37 @@ class AIVideoGenerationService
             // 构建查询 URL
             $url = $gatewayBaseUrl . '/v1/video/generations/' . $task->task_id;
 
-            $response = $client->get($url, [
-                'headers' => [
-                    'Authorization' => 'Bearer ' . $apiKey,
-                    'Content-Type' => 'application/json',
-                ]
-            ]);
+            try {
+                $response = $client->get($url, [
+                    'headers' => [
+                        'Authorization' => 'Bearer ' . $apiKey,
+                        'Content-Type' => 'application/json',
+                    ]
+                ]);
+            } catch (\GuzzleHttp\Exception\ClientException $e) {
+                // 网关查询接口要求通用令牌(模型专用Key查询时返回403 no access to model)
+                // 回退使用Seedance-common令牌重试一次
+                $statusCode = $e->getResponse() ? $e->getResponse()->getStatusCode() : 0;
+                $errorBody = $e->getResponse() ? (string)$e->getResponse()->getBody() : '';
+                if ($statusCode !== 403 || strpos($errorBody, 'no access to model') === false) {
+                    throw $e;
+                }
+
+                $commonKey = env('KUAIKUAI_SEEDANCE_COMMON_AK');
+                if (empty($commonKey) || $commonKey === $apiKey) {
+                    throw $e;
+                }
+                dLog('generate')->warning('快快AI任务状态查询使用模型Key被拒(403),回退Seedance-common令牌重试', [
+                    'id' => $task->id,
+                    'api_key_env' => $apiKeyEnv,
+                ]);
+                $response = $client->get($url, [
+                    'headers' => [
+                        'Authorization' => 'Bearer ' . $commonKey,
+                        'Content-Type' => 'application/json',
+                    ]
+                ]);
+            }
 
             $responseData = json_decode($response->getBody(), true);
             dLog('generate')->info('快快AI任务状态查询响应: ', $responseData);

+ 4 - 0
app/Services/Anime/AnimeService.php

@@ -5467,6 +5467,10 @@ class AnimeService
 
         // 视频计费场景(video_generation/video_to_video),默认视频生成
         $scene = (string)getProp($data, 'scene', 'video_generation');
+        // 未显式传scene且带参考视频时,自动按video_to_video定价
+        if ($mode === 'video' && !array_key_exists('scene', $data) && !empty(getProp($data, 'reference_videos', []))) {
+            $scene = 'video_to_video';
+        }
         $items = [];
         $model = '';
         $resolution = '';

+ 1 - 0
routes/api.php

@@ -178,6 +178,7 @@ Route::group(['middleware' => ['bindToken', 'bindExportToken', 'checkLogin']], f
             Route::get('textModel', [AnimeController::class, 'textModel']);                         // 文字模型
             Route::get('imageModel', [AnimeController::class, 'imageModel']);                       // 图片模型
             Route::get('videoModel', [AnimeController::class, 'videoModel']);                       // 视频模型
+            Route::get('seedanceModelOptions', [AnimeController::class, 'seedanceModelOptions']);   // Seedance模型生成参数选项
             Route::get('artStyleList', [AnimeController::class, 'artStyleList']);                   // 艺术风格列表
             Route::post('create', [AnimeController::class, 'createAnime']);                         // 创建动漫
             Route::post('edit', [AnimeController::class, 'editAnime']);                             // 编辑动漫