|
@@ -1270,4 +1270,155 @@ class AIImageGenerationService
|
|
|
'can_submit_new_task' => $processingCount === 0
|
|
'can_submit_new_task' => $processingCount === 0
|
|
|
];
|
|
];
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 处理智真AI的参考图片转素材
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param array $referenceImages 参考图片URL数组
|
|
|
|
|
+ * @param string &$fullPrompt 完整提示词(引用传递,用于删除失败图片的标记)
|
|
|
|
|
+ * @return array 返回素材ID数组
|
|
|
|
|
+ */
|
|
|
|
|
+ public function processReferenceImagesToAssets(array $referenceImages, string &$fullPrompt): array
|
|
|
|
|
+ {
|
|
|
|
|
+ $assetIds = [];
|
|
|
|
|
+ $failedIndexes = []; // 记录失败的图片序号
|
|
|
|
|
+
|
|
|
|
|
+ foreach ($referenceImages as $index => $imageUrl) {
|
|
|
|
|
+ $imageIndex = $index + 1; // 图片序号从1开始
|
|
|
|
|
+
|
|
|
|
|
+ try {
|
|
|
|
|
+ dLog('generate')->info("开始处理参考图片 {$imageIndex}: {$imageUrl}");
|
|
|
|
|
+
|
|
|
|
|
+ // 1. 创建素材
|
|
|
|
|
+ $createResult = $this->createAsset([
|
|
|
|
|
+ 'url' => $imageUrl,
|
|
|
|
|
+ 'asset_type' => MpAsset::TYPE_IMAGE,
|
|
|
|
|
+ 'name' => "参考图片_{$imageIndex}_" . time(),
|
|
|
|
|
+ ]);
|
|
|
|
|
+
|
|
|
|
|
+ if ($createResult['code'] !== 0) {
|
|
|
|
|
+ dLog('generate')->warning("图片 {$imageIndex} 创建素材失败: " . $createResult['msg']);
|
|
|
|
|
+ logDB('generate', 'warning', '创建素材失败', [
|
|
|
|
|
+ 'image_url' => $imageUrl,
|
|
|
|
|
+ 'index' => $imageIndex,
|
|
|
|
|
+ 'error' => $createResult['msg']
|
|
|
|
|
+ ]);
|
|
|
|
|
+ $failedIndexes[] = $imageIndex;
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ $assetId = $createResult['data']['asset_id'];
|
|
|
|
|
+ dLog('generate')->info("图片 {$imageIndex} 素材创建成功,asset_id: {$assetId},开始轮询查询状态");
|
|
|
|
|
+
|
|
|
|
|
+ // 2. 轮询查询素材状态(每3秒查询一次,最多查询100次即5分钟)
|
|
|
|
|
+ $maxAttempts = 100;
|
|
|
|
|
+ $attempt = 0;
|
|
|
|
|
+ $assetStatus = null;
|
|
|
|
|
+
|
|
|
|
|
+ while ($attempt < $maxAttempts) {
|
|
|
|
|
+ sleep(3); // 等待3秒
|
|
|
|
|
+ $attempt++;
|
|
|
|
|
+
|
|
|
|
|
+ $getResult = $this->getAsset($assetId);
|
|
|
|
|
+
|
|
|
|
|
+ if ($getResult['code'] !== 0) {
|
|
|
|
|
+ dLog('generate')->warning("图片 {$imageIndex} 查询素材状态失败: " . $getResult['msg']);
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ $assetStatus = $getResult['data']['asset']['status'] ?? null;
|
|
|
|
|
+ dLog('generate')->info("图片 {$imageIndex} 素材状态查询第 {$attempt} 次,状态: {$assetStatus}");
|
|
|
|
|
+
|
|
|
|
|
+ if ($assetStatus === 'Active') {
|
|
|
|
|
+ // 素材可用
|
|
|
|
|
+ $assetIds[] = $assetId;
|
|
|
|
|
+ dLog('generate')->info("图片 {$imageIndex} 素材处理成功,asset_id: {$assetId}");
|
|
|
|
|
+ logDB('generate', 'info', '素材转换成功', [
|
|
|
|
|
+ 'image_url' => $imageUrl,
|
|
|
|
|
+ 'index' => $imageIndex,
|
|
|
|
|
+ 'asset_id' => $assetId
|
|
|
|
|
+ ]);
|
|
|
|
|
+ break;
|
|
|
|
|
+ } elseif ($assetStatus === 'Failed') {
|
|
|
|
|
+ // 素材处理失败
|
|
|
|
|
+ dLog('generate')->warning("图片 {$imageIndex} 素材处理失败");
|
|
|
|
|
+ logDB('generate', 'warning', '素材处理失败', [
|
|
|
|
|
+ 'image_url' => $imageUrl,
|
|
|
|
|
+ 'index' => $imageIndex,
|
|
|
|
|
+ 'asset_id' => $assetId
|
|
|
|
|
+ ]);
|
|
|
|
|
+ $failedIndexes[] = $imageIndex;
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+ // 其他状态(Processing等)继续等待
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 如果超时还未成功
|
|
|
|
|
+ if ($attempt >= $maxAttempts && $assetStatus !== 'Active') {
|
|
|
|
|
+ dLog('generate')->warning("图片 {$imageIndex} 素材处理超时");
|
|
|
|
|
+ logDB('generate', 'warning', '素材处理超时', [
|
|
|
|
|
+ 'image_url' => $imageUrl,
|
|
|
|
|
+ 'index' => $imageIndex,
|
|
|
|
|
+ 'asset_id' => $assetId,
|
|
|
|
|
+ 'last_status' => $assetStatus
|
|
|
|
|
+ ]);
|
|
|
|
|
+ $failedIndexes[] = $imageIndex;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ } catch (\Exception $e) {
|
|
|
|
|
+ dLog('generate')->error("图片 {$imageIndex} 处理异常: " . $e->getMessage());
|
|
|
|
|
+ logDB('generate', 'error', '素材转换异常', [
|
|
|
|
|
+ 'image_url' => $imageUrl,
|
|
|
|
|
+ 'index' => $imageIndex,
|
|
|
|
|
+ 'error' => $e->getMessage()
|
|
|
|
|
+ ]);
|
|
|
|
|
+ $failedIndexes[] = $imageIndex;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 处理失败的图片:从 fullPrompt 中删除对应的标记并调整序号
|
|
|
|
|
+ if (!empty($failedIndexes)) {
|
|
|
|
|
+ dLog('generate')->info('开始处理失败图片的提示词调整,失败序号: ' . implode(',', $failedIndexes));
|
|
|
|
|
+
|
|
|
|
|
+ // 按序号从大到小排序,避免删除时影响后续序号
|
|
|
|
|
+ rsort($failedIndexes);
|
|
|
|
|
+
|
|
|
|
|
+ foreach ($failedIndexes as $failedIndex) {
|
|
|
|
|
+ // 删除失败图片的标记,例如 <图片1>、<图片2> 等
|
|
|
|
|
+ $pattern = "/<图片{$failedIndex}>/u";
|
|
|
|
|
+ $fullPrompt = preg_replace($pattern, '', $fullPrompt);
|
|
|
|
|
+ dLog('generate')->info("已从提示词中删除 <图片{$failedIndex}>");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 重新调整剩余图片的序号
|
|
|
|
|
+ // 例如:如果图片2失败,图片3、图片4需要改为图片2、图片3
|
|
|
|
|
+ $needAdjust = false;
|
|
|
|
|
+ foreach ($failedIndexes as $failedIndex) {
|
|
|
|
|
+ $needAdjust = true;
|
|
|
|
|
+ // 将所有大于失败序号的图片标记序号减1
|
|
|
|
|
+ for ($i = $failedIndex + 1; $i <= count($referenceImages); $i++) {
|
|
|
|
|
+ $oldPattern = "/<图片{$i}>/u";
|
|
|
|
|
+ $newTag = "<图片" . ($i - 1) . ">";
|
|
|
|
|
+ $fullPrompt = preg_replace($oldPattern, $newTag, $fullPrompt);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if ($needAdjust) {
|
|
|
|
|
+ dLog('generate')->info('提示词图片序号调整完成');
|
|
|
|
|
+ logDB('generate', 'info', '提示词调整', [
|
|
|
|
|
+ 'failed_indexes' => $failedIndexes,
|
|
|
|
|
+ 'adjusted_prompt' => $fullPrompt
|
|
|
|
|
+ ]);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ dLog('generate')->info('参考图片转素材完成,成功数量: ' . count($assetIds) . ',失败数量: ' . count($failedIndexes));
|
|
|
|
|
+
|
|
|
|
|
+ // 格式化为可直接在API接口中使用的数组
|
|
|
|
|
+ foreach($assetIds as &$assetId) {
|
|
|
|
|
+ $assetId = "asset://{$assetId}";
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return $assetIds;
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|