Przeglądaj źródła

优化素材上传逻辑

lh 1 miesiąc temu
rodzic
commit
a039ff9cc5
1 zmienionych plików z 111 dodań i 72 usunięć
  1. 111 72
      app/Services/AIGeneration/AIVideoGenerationService.php

+ 111 - 72
app/Services/AIGeneration/AIVideoGenerationService.php

@@ -1237,15 +1237,23 @@ class AIVideoGenerationService
                 // 上传素材(已存在则直接复用,不重复上传)
                 // 上传素材(已存在则直接复用,不重复上传)
                 $createResult = $this->createSeedance20Asset($imageUrl, "参考图片_{$imageIndex}_" . time());
                 $createResult = $this->createSeedance20Asset($imageUrl, "参考图片_{$imageIndex}_" . time());
 
 
+                // 网关素材异步处理为间歇性故障,失败后间隔重试,避免因网关临时故障误判
+                for ($retry = 1; $retry <= 5 && $createResult['code'] !== 0; $retry++) {
+                    sleep($retry <= 3 ? 10 : 30);
+                    dLog('generate')->warning("图片 {$imageIndex} Seedance 2.0素材第 {$retry} 次重试上传");
+                    $createResult = $this->createSeedance20Asset($imageUrl, "参考图片_{$imageIndex}_" . time());
+                }
+
                 if ($createResult['code'] !== 0) {
                 if ($createResult['code'] !== 0) {
-                    dLog('generate')->warning("图片 {$imageIndex} 创建Seedance 2.0素材失败: " . $createResult['msg']);
-                    logDB('generate', 'warning', 'Seedance2.0创建素材失败', [
+                    $errorMessage = (string)($createResult['msg'] ?? '素材创建失败');
+                    dLog('generate')->error("图片 {$imageIndex} 创建Seedance 2.0素材失败: " . $errorMessage);
+                    logDB('generate', 'error', 'Seedance2.0创建素材失败', [
                         'image_url' => $imageUrl,
                         'image_url' => $imageUrl,
                         'index' => $imageIndex,
                         'index' => $imageIndex,
-                        'error' => $createResult['msg']
+                        'error' => $errorMessage
                     ]);
                     ]);
-                    $failedIndexes[] = $imageIndex;
-                    continue;
+                    // 素材不可用会直接影响视频效果,且任务会扣费,失败直接中断任务创建
+                    Utils::throwError('20003:参考图片' . $imageIndex . '上传素材失败:' . $errorMessage);
                 }
                 }
 
 
                 $assetIds[] = $createResult['data']['asset_id'];
                 $assetIds[] = $createResult['data']['asset_id'];
@@ -1290,10 +1298,6 @@ class AIVideoGenerationService
 
 
             if ($needAdjust) {
             if ($needAdjust) {
                 dLog('generate')->info('Seedance 2.0提示词图片序号调整完成');
                 dLog('generate')->info('Seedance 2.0提示词图片序号调整完成');
-                logDB('generate', 'info', 'Seedance2.0提示词调整', [
-                    'failed_indexes' => $failedIndexes,
-                    'adjusted_prompt' => $fullPrompt
-                ]);
             }
             }
         }
         }
 
 
@@ -1358,16 +1362,24 @@ class AIVideoGenerationService
                 // 上传素材(已存在则直接复用,不重复上传)
                 // 上传素材(已存在则直接复用,不重复上传)
                 $createResult = $this->createSeedance20Asset($url, "{$label}_{$mediaIndex}_" . time(), $assetType);
                 $createResult = $this->createSeedance20Asset($url, "{$label}_{$mediaIndex}_" . time(), $assetType);
 
 
+                // 网关素材异步处理为间歇性故障,失败后间隔重试,避免因网关临时故障误判
+                for ($retry = 1; $retry <= 5 && $createResult['code'] !== 0; $retry++) {
+                    sleep($retry <= 3 ? 10 : 30);
+                    dLog('generate')->warning("{$label} {$mediaIndex} Seedance 2.0素材第 {$retry} 次重试上传");
+                    $createResult = $this->createSeedance20Asset($url, "{$label}_{$mediaIndex}_" . time(), $assetType);
+                }
+
                 if ($createResult['code'] !== 0) {
                 if ($createResult['code'] !== 0) {
-                    dLog('generate')->warning("{$label} {$mediaIndex} 创建Seedance 2.0素材失败: " . $createResult['msg']);
-                    logDB('generate', 'warning', 'Seedance2.0创建素材失败', [
+                    $errorMessage = (string)($createResult['msg'] ?? '素材创建失败');
+                    dLog('generate')->error("{$label} {$mediaIndex} 创建Seedance 2.0素材失败: " . $errorMessage);
+                    logDB('generate', 'error', 'Seedance2.0创建素材失败', [
                         'url' => $url,
                         'url' => $url,
                         'asset_type' => $assetType,
                         'asset_type' => $assetType,
                         'index' => $mediaIndex,
                         'index' => $mediaIndex,
-                        'error' => $createResult['msg']
+                        'error' => $errorMessage
                     ]);
                     ]);
-                    $failedIndexes[] = $mediaIndex;
-                    continue;
+                    // 素材不可用会直接影响视频效果,且任务会扣费,失败直接中断任务创建
+                    Utils::throwError('20003:' . $label . $mediaIndex . '上传素材失败:' . $errorMessage);
                 }
                 }
 
 
                 $assetIds[] = $createResult['data']['asset_id'];
                 $assetIds[] = $createResult['data']['asset_id'];
@@ -1413,10 +1425,6 @@ class AIVideoGenerationService
 
 
             if ($needAdjust) {
             if ($needAdjust) {
                 dLog('generate')->info('Seedance 2.0提示词' . $label . '序号调整完成');
                 dLog('generate')->info('Seedance 2.0提示词' . $label . '序号调整完成');
-                logDB('generate', 'info', 'Seedance2.0提示词调整', [
-                    'failed_indexes' => $failedIndexes,
-                    'adjusted_prompt' => $fullPrompt
-                ]);
             }
             }
         }
         }
 
 
@@ -1453,15 +1461,22 @@ class AIVideoGenerationService
             $name = 'seedance20_' . time() . '_' . uniqid();
             $name = 'seedance20_' . time() . '_' . uniqid();
             $createResult = $this->createSeedance20Asset($imageUrl, $name);
             $createResult = $this->createSeedance20Asset($imageUrl, $name);
 
 
+            // 网关素材异步处理为间歇性故障,失败后间隔重试,避免因网关临时故障误判
+            for ($retry = 1; $retry <= 5 && $createResult['code'] !== 0; $retry++) {
+                sleep($retry <= 3 ? 10 : 30);
+                dLog('generate')->warning('Seedance 2.0 图片上传素材第 ' . $retry . ' 次重试: ' . $imageUrl);
+                $createResult = $this->createSeedance20Asset($imageUrl, $name);
+            }
+
             if ($createResult['code'] !== 0) {
             if ($createResult['code'] !== 0) {
-                // 上传失败:移除该图片,继续处理其他图片
-                dLog('generate')->warning('Seedance 2.0 图片上传素材失败,已从content中移除: ' . $imageUrl . ',原因: ' . $createResult['msg']);
-                logDB('generate', 'warning', 'Seedance2.0图片转素材失败', [
+                $errorMessage = (string)($createResult['msg'] ?? '素材创建失败');
+                dLog('generate')->error('Seedance 2.0 图片上传素材失败: ' . $imageUrl . ',原因: ' . $errorMessage);
+                logDB('generate', 'error', 'Seedance2.0图片转素材失败', [
                     'image_url' => $imageUrl,
                     'image_url' => $imageUrl,
-                    'error' => $createResult['msg']
+                    'error' => $errorMessage
                 ]);
                 ]);
-                unset($content[$index]);
-                continue;
+                // 素材不可用会直接影响视频效果,且任务会扣费,失败直接中断任务创建
+                Utils::throwError('20003:图片上传素材失败:' . $errorMessage);
             }
             }
 
 
             $item['image_url']['url'] = 'asset://' . $createResult['data']['asset_id'];
             $item['image_url']['url'] = 'asset://' . $createResult['data']['asset_id'];
@@ -1492,18 +1507,29 @@ class AIVideoGenerationService
                 ];
                 ];
             }
             }
 
 
-            // 先获取表中是否已有该url(仅限百度网关来源的素材)
-            $asset = DB::table('mp_assets')->where('url', $url)->where('source_type', 'baidu')->first();
+            // 先获取表中是否已有该url(仅限百度网关来源且状态可用的素材)
+            // 只复用百度网关上传成功的素材,避免复用 Failed 记录或其它网关(ark/kuaikuai)的素材 ID
+            $asset = DB::table('mp_assets')
+                ->where('url', $url)
+                ->where('source_type', 'baidu')
+                ->where('status', MpAsset::STATUS_ACTIVE)
+                ->orderBy('id', 'desc')
+                ->first();
             if ($asset) {
             if ($asset) {
-                dLog('generate')->info('Seedance 2.0 素材已存在,直接复用: ' . $url . ' => ' . $asset->asset_id);
-                return [
-                    'code' => 0,
-                    'msg' => '创建成功',
-                    'data' => [
-                        'asset_id' => $asset->asset_id,
-                        'group_id' => $asset->group_id,
-                    ]
-                ];
+                $extraParams = is_array($asset->extra_params) ? $asset->extra_params : json_decode((string)$asset->extra_params, true);
+                $isBaiduGatewayAsset = is_array($extraParams) && isset($extraParams['Result']);
+                if ($isBaiduGatewayAsset) {
+                    dLog('generate')->info('Seedance 2.0 素材已存在,直接复用: ' . $url . ' => ' . $asset->asset_id);
+                    return [
+                        'code' => 0,
+                        'msg' => '创建成功',
+                        'data' => [
+                            'asset_id' => $asset->asset_id,
+                            'group_id' => $asset->group_id,
+                            'status' => 'ready',
+                        ]
+                    ];
+                }
             }
             }
 
 
             $groupId = $this->ensureSeedance20AssetGroup();
             $groupId = $this->ensureSeedance20AssetGroup();
@@ -1573,10 +1599,6 @@ class AIVideoGenerationService
                 dLog('generate')->info("Seedance 2.0 素材 {$assetId} 状态查询第 {$attempt} 次,状态: {$assetStatus}");
                 dLog('generate')->info("Seedance 2.0 素材 {$assetId} 状态查询第 {$attempt} 次,状态: {$assetStatus}");
 
 
                 if ($assetStatus === 'Active') {
                 if ($assetStatus === 'Active') {
-                    logDB('generate', 'info', 'Seedance2.0素材处理成功', [
-                        'asset_id' => $assetId,
-                        'url' => $url
-                    ]);
                     return [
                     return [
                         'code' => 0,
                         'code' => 0,
                         'msg' => '创建成功',
                         'msg' => '创建成功',
@@ -1776,7 +1798,6 @@ class AIVideoGenerationService
             ]);
             ]);
         }
         }
 
 
-        logDB('generate', 'info', 'Seedance2.0素材组创建成功', ['group_id' => $groupId]);
         return $groupId;
         return $groupId;
     }
     }
 
 
@@ -1805,7 +1826,6 @@ class AIVideoGenerationService
 
 
         $responseData = json_decode($response->getBody(), true);
         $responseData = json_decode($response->getBody(), true);
         dLog('generate')->info('Seedance 2.0 网关 ' . $action . ' 响应: ', $responseData);
         dLog('generate')->info('Seedance 2.0 网关 ' . $action . ' 响应: ', $responseData);
-        logDB('generate', 'info', 'Seedance2.0网关' . $action, ['params' => $body, 'response' => $responseData]);
 
 
         return $responseData;
         return $responseData;
     }
     }
@@ -1849,7 +1869,6 @@ class AIVideoGenerationService
         }
         }
 
 
         dLog('generate')->info('快快AI网关 ' . $method . ' ' . $path . ' 响应: ', $responseData);
         dLog('generate')->info('快快AI网关 ' . $method . ' ' . $path . ' 响应: ', $responseData);
-        logDB('generate', 'info', '快快AI素材网关' . $method . $path, ['params' => $body, 'response' => $responseData]);
 
 
         return $responseData;
         return $responseData;
     }
     }
@@ -2050,19 +2069,29 @@ class AIVideoGenerationService
                 return ['code' => 1, 'msg' => '素材URL不能为空', 'data' => null];
                 return ['code' => 1, 'msg' => '素材URL不能为空', 'data' => null];
             }
             }
 
 
-            // 先获取表中是否已有该url(仅限快快AI来源的素材)
-            $asset = DB::table('mp_assets')->where('url', $url)->where('source_type', 'kuaikuai')->first();
+            // 先获取表中是否已有该url(仅限快快AI来源且状态可用的素材)
+            // 只复用网关上传成功的素材,避免复用 Failed 记录或其它网关(ark)的素材 ID
+            $asset = DB::table('mp_assets')
+                ->where('url', $url)
+                ->where('source_type', 'kuaikuai')
+                ->where('status', MpAsset::STATUS_ACTIVE)
+                ->orderBy('id', 'desc')
+                ->first();
             if ($asset) {
             if ($asset) {
-                dLog('generate')->info('快快AI素材已存在,直接复用: ' . $url . ' => ' . $asset->asset_id);
-                return [
-                    'code' => 0,
-                    'msg' => '创建成功',
-                    'data' => [
-                        'asset_id' => $asset->asset_id,
-                        'group_id' => $asset->group_id,
-                        'status' => $asset->status === MpAsset::STATUS_ACTIVE ? 'ready' : ($asset->status === MpAsset::STATUS_FAILED ? 'failed' : 'pending'),
-                    ],
-                ];
+                $extraParams = is_array($asset->extra_params) ? $asset->extra_params : json_decode((string)$asset->extra_params, true);
+                $isKuaikuaiGatewayAsset = is_array($extraParams) && isset($extraParams['success']);
+                if ($isKuaikuaiGatewayAsset) {
+                    dLog('generate')->info('快快AI素材已存在,直接复用: ' . $url . ' => ' . $asset->asset_id);
+                    return [
+                        'code' => 0,
+                        'msg' => '创建成功',
+                        'data' => [
+                            'asset_id' => $asset->asset_id,
+                            'group_id' => $asset->group_id,
+                            'status' => 'ready',
+                        ],
+                    ];
+                }
             }
             }
 
 
             $groupId = $this->ensureKuaikuaiAssetGroup();
             $groupId = $this->ensureKuaikuaiAssetGroup();
@@ -2109,7 +2138,6 @@ class AIVideoGenerationService
 
 
             // 网关已就绪/失败,直接返回
             // 网关已就绪/失败,直接返回
             if (in_array($status, ['ready', 'success'], true)) {
             if (in_array($status, ['ready', 'success'], true)) {
-                logDB('generate', 'info', '快快AI素材上传成功', ['asset_id' => $assetId, 'url' => $url]);
                 return [
                 return [
                     'code' => 0,
                     'code' => 0,
                     'msg' => '创建成功',
                     'msg' => '创建成功',
@@ -2142,7 +2170,6 @@ class AIVideoGenerationService
                 dLog('generate')->info("快快AI素材 {$assetId} 状态查询第 {$attempt} 次,状态: {$lastStatus}");
                 dLog('generate')->info("快快AI素材 {$assetId} 状态查询第 {$attempt} 次,状态: {$lastStatus}");
 
 
                 if (in_array($lastStatus, ['ready', 'success'], true)) {
                 if (in_array($lastStatus, ['ready', 'success'], true)) {
-                    logDB('generate', 'info', '快快AI素材处理成功', ['asset_id' => $assetId, 'url' => $url]);
                     return [
                     return [
                         'code' => 0,
                         'code' => 0,
                         'msg' => '创建成功',
                         'msg' => '创建成功',
@@ -2301,14 +2328,22 @@ class AIVideoGenerationService
             $name = 'kuaikuai_' . time() . '_' . uniqid();
             $name = 'kuaikuai_' . time() . '_' . uniqid();
             $createResult = $this->createKuaikuaiAsset($imageUrl, $name, MpAsset::TYPE_IMAGE, '视频内容图片');
             $createResult = $this->createKuaikuaiAsset($imageUrl, $name, MpAsset::TYPE_IMAGE, '视频内容图片');
 
 
-            if ($createResult['code'] !== 0) {
-                dLog('generate')->warning('快快AI图片上传素材失败,已从content中移除: ' . $imageUrl . ',原因: ' . $createResult['msg']);
-                logDB('generate', 'warning', '快快AI图片转素材失败', [
+            // 网关素材异步处理为间歇性故障,失败后间隔重试,避免因网关临时故障误判
+            for ($retry = 1; $retry <= 5 && ($createResult['code'] !== 0 || ($createResult['data']['status'] ?? '') !== 'ready'); $retry++) {
+                sleep($retry <= 3 ? 10 : 30);
+                dLog('generate')->warning('快快AI图片上传素材第 ' . $retry . ' 次重试: ' . $imageUrl);
+                $createResult = $this->createKuaikuaiAsset($imageUrl, $name, MpAsset::TYPE_IMAGE, '视频内容图片');
+            }
+
+            if ($createResult['code'] !== 0 || ($createResult['data']['status'] ?? '') !== 'ready') {
+                $errorMessage = (string)($createResult['msg'] ?? '素材创建失败');
+                dLog('generate')->error('快快AI图片上传素材失败: ' . $imageUrl . ',原因: ' . $errorMessage);
+                logDB('generate', 'error', '快快AI图片转素材失败', [
                     'image_url' => $imageUrl,
                     'image_url' => $imageUrl,
-                    'error' => $createResult['msg'],
+                    'error' => $errorMessage,
                 ]);
                 ]);
-                unset($content[$index]);
-                continue;
+                // 素材不可用会直接影响视频效果,且任务会扣费,失败直接中断任务创建
+                Utils::throwError('20003:图片上传素材失败:' . $errorMessage);
             }
             }
 
 
             $item['image_url']['url'] = 'asset://' . $createResult['data']['asset_id'];
             $item['image_url']['url'] = 'asset://' . $createResult['data']['asset_id'];
@@ -2380,16 +2415,24 @@ class AIVideoGenerationService
                 // 上传素材(已存在则直接复用,不重复上传)
                 // 上传素材(已存在则直接复用,不重复上传)
                 $createResult = $this->createKuaikuaiAsset($url, "{$label}_{$mediaIndex}_" . time(), $assetType, $label);
                 $createResult = $this->createKuaikuaiAsset($url, "{$label}_{$mediaIndex}_" . time(), $assetType, $label);
 
 
-                if ($createResult['code'] !== 0) {
-                    dLog('generate')->warning("{$label} {$mediaIndex} 创建快快AI素材失败: " . $createResult['msg']);
-                    logDB('generate', 'warning', '快快AI创建素材失败', [
+                // 网关素材异步处理为间歇性故障,失败后间隔重试,避免因网关临时故障误判
+                for ($retry = 1; $retry <= 5 && ($createResult['code'] !== 0 || ($createResult['data']['status'] ?? '') !== 'ready'); $retry++) {
+                    sleep($retry <= 3 ? 10 : 30);
+                    dLog('generate')->warning("{$label} {$mediaIndex} 快快AI素材第 {$retry} 次重试上传");
+                    $createResult = $this->createKuaikuaiAsset($url, "{$label}_{$mediaIndex}_" . time(), $assetType, $label);
+                }
+
+                if ($createResult['code'] !== 0 || ($createResult['data']['status'] ?? '') !== 'ready') {
+                    $errorMessage = (string)($createResult['msg'] ?? '素材创建失败');
+                    dLog('generate')->error("{$label} {$mediaIndex} 创建快快AI素材失败: " . $errorMessage);
+                    logDB('generate', 'error', '快快AI创建素材失败', [
                         'url' => $url,
                         'url' => $url,
                         'asset_type' => $assetType,
                         'asset_type' => $assetType,
                         'index' => $mediaIndex,
                         'index' => $mediaIndex,
-                        'error' => $createResult['msg'],
+                        'error' => $errorMessage,
                     ]);
                     ]);
-                    $failedIndexes[] = $mediaIndex;
-                    continue;
+                    // 素材不可用会直接影响视频效果,且任务会扣费,失败直接中断任务创建
+                    Utils::throwError('20003:' . $label . $mediaIndex . '上传素材失败:' . $errorMessage);
                 }
                 }
 
 
                 $assetIds[] = $createResult['data']['asset_id'];
                 $assetIds[] = $createResult['data']['asset_id'];
@@ -2434,10 +2477,6 @@ class AIVideoGenerationService
 
 
             if ($needAdjust) {
             if ($needAdjust) {
                 dLog('generate')->info('快快AI提示词' . $label . '序号调整完成');
                 dLog('generate')->info('快快AI提示词' . $label . '序号调整完成');
-                logDB('generate', 'info', '快快AI提示词调整', [
-                    'failed_indexes' => $failedIndexes,
-                    'adjusted_prompt' => $fullPrompt,
-                ]);
             }
             }
         }
         }