|
|
@@ -216,6 +216,158 @@ class AIImageGenerationService
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
+ * 提交任务到GPT-Image2 API
|
|
|
+ *
|
|
|
+ * @param MpGeneratePicTask $task
|
|
|
+ * @return void
|
|
|
+ */
|
|
|
+ public function submitTaskToGptImage2Api(MpGeneratePicTask $task): void
|
|
|
+ {
|
|
|
+ try {
|
|
|
+ // 验证环境变量配置
|
|
|
+ $apiKey = env('GPT_IMAGE2_API_KEY');
|
|
|
+
|
|
|
+ if (empty($apiKey)) {
|
|
|
+ $task->updateStatus(MpGeneratePicTask::STATUS_FAILED, [
|
|
|
+ 'error_message' => 'GPT-Image2 API KEY未配置,请检查环境变量GPT_IMAGE2_API_KEY'
|
|
|
+ ]);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 更新状态为处理中
|
|
|
+ $task->updateStatus(MpGeneratePicTask::STATUS_PROCESSING);
|
|
|
+
|
|
|
+ // 构建GPT-Image2 API请求参数
|
|
|
+ $apiParams = [
|
|
|
+ 'model' => 'gpt-image-2',
|
|
|
+ 'prompt' => $task->prompt,
|
|
|
+ ];
|
|
|
+
|
|
|
+ // 尺寸参数
|
|
|
+ if ($task->width && $task->height) {
|
|
|
+ $apiParams['size'] = $task->width . 'x' . $task->height;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 参考图片
|
|
|
+ if ($task->ref_img_url) {
|
|
|
+ $imageUrl = is_array($task->ref_img_url) ? $task->ref_img_url[0] : $task->ref_img_url;
|
|
|
+ $apiParams['image_url'] = [
|
|
|
+ 'url' => $imageUrl
|
|
|
+ ];
|
|
|
+ }
|
|
|
+
|
|
|
+ dLog('generate')->info('GPT-Image2 API参数: ', $apiParams);
|
|
|
+ logDB('generate', 'info', 'GPT-Image2任务提交', ['task_id' => $task->task_id, 'params' => $apiParams]);
|
|
|
+
|
|
|
+ // 调用GPT-Image2 API
|
|
|
+ $response = $this->httpClient->post('https://token.ithinkai.cn/v1/images/generations', [
|
|
|
+ 'headers' => [
|
|
|
+ 'Authorization' => 'Bearer ' . $apiKey,
|
|
|
+ 'Content-Type' => 'application/json',
|
|
|
+ ],
|
|
|
+ 'json' => $apiParams,
|
|
|
+ ]);
|
|
|
+
|
|
|
+ $responseData = json_decode($response->getBody()->getContents(), true);
|
|
|
+ dLog('generate')->info('GPT-Image2 API响应: ', $responseData);
|
|
|
+ logDB('generate', 'info', 'GPT-Image2 API响应', ['task_id' => $task->task_id, 'response' => $responseData]);
|
|
|
+
|
|
|
+ if (isset($responseData['error'])) {
|
|
|
+ // API返回错误
|
|
|
+ logDB('generate', 'error', 'GPT-Image2任务失败', ['task_id' => $task->task_id, 'error' => $responseData['error']['message'] ?? 'API Error']);
|
|
|
+ $task->updateStatus(MpGeneratePicTask::STATUS_FAILED, [
|
|
|
+ 'error_message' => $responseData['error']['message'] ?? 'API Error',
|
|
|
+ 'result_json' => $responseData
|
|
|
+ ]);
|
|
|
+ } else {
|
|
|
+ // 任务提交成功,直接处理结果
|
|
|
+ $this->processGptImage2ApiResponse($task, $responseData);
|
|
|
+ }
|
|
|
+ } catch (\Exception $e) {
|
|
|
+ // 记录错误
|
|
|
+ dLog('generate')->error('GPT-Image2 API请求失败: ' . $e->getMessage());
|
|
|
+ logDB('generate', 'error', 'GPT-Image2任务异常', ['task_id' => $task->task_id, 'error' => $e->getMessage()]);
|
|
|
+ $task->updateStatus(MpGeneratePicTask::STATUS_FAILED, [
|
|
|
+ 'error_message' => 'API请求失败: ' . $e->getMessage()
|
|
|
+ ]);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 处理GPT-Image2 API响应结果
|
|
|
+ *
|
|
|
+ * @param MpGeneratePicTask $task
|
|
|
+ * @param array $responseData
|
|
|
+ * @return void
|
|
|
+ */
|
|
|
+ private function processGptImage2ApiResponse(MpGeneratePicTask $task, array $responseData): void
|
|
|
+ {
|
|
|
+ try {
|
|
|
+ if (!isset($responseData['data']) || empty($responseData['data'])) {
|
|
|
+ $task->updateStatus(MpGeneratePicTask::STATUS_FAILED, [
|
|
|
+ 'error_message' => '未返回图片数据',
|
|
|
+ 'result_json' => $responseData
|
|
|
+ ]);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ $result_urls = [];
|
|
|
+ foreach ($responseData['data'] as $imageData) {
|
|
|
+ if (isset($imageData['url'])) {
|
|
|
+ $url = $imageData['url'];
|
|
|
+ $pic_name = 'ai_generation_gpt_' . time() . '_' . uniqid();
|
|
|
+ $pic_ext = getImgExtFromUrl($url);
|
|
|
+ $pic_name = $pic_name . $pic_ext;
|
|
|
+
|
|
|
+ if ($pic_ext === '.png') {
|
|
|
+ $comporessed_data = compressRemoteImageUrlToSize($url);
|
|
|
+ $url = uploadStreamByTos('image', $comporessed_data, $pic_name);
|
|
|
+ } else {
|
|
|
+ // 将图片另存到tos
|
|
|
+ $url = uploadStreamByTos('image', file_get_contents($url), $pic_name);
|
|
|
+ }
|
|
|
+
|
|
|
+ $result_urls[] = $url;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (empty($result_urls)) {
|
|
|
+ $task->updateStatus(MpGeneratePicTask::STATUS_FAILED, [
|
|
|
+ 'error_message' => '所有图片生成失败',
|
|
|
+ 'result_json' => $responseData
|
|
|
+ ]);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 更新任务状态为成功
|
|
|
+ $task->updateStatus(MpGeneratePicTask::STATUS_SUCCESS, [
|
|
|
+ 'result_url' => $result_urls,
|
|
|
+ 'result_json' => $responseData
|
|
|
+ ]);
|
|
|
+
|
|
|
+ // 同步调整分镜图片状态和结果
|
|
|
+ $segment_id = getProp($task, 'alias_segment_id');
|
|
|
+ if ($segment_id) {
|
|
|
+ DB::table('mp_episode_segments')->where('segment_id', $segment_id)->update([
|
|
|
+ 'img_url' => $result_urls[0],
|
|
|
+ 'pic_task_status' => '已完成',
|
|
|
+ ]);
|
|
|
+
|
|
|
+ // 如果是首帧图ID则更新anime表
|
|
|
+ if (Redis::sismember('anime_first_frame_urls', $segment_id)) {
|
|
|
+ $anime_id = DB::table('mp_episode_segments')->where('segment_id', $segment_id)->value('anime_id');
|
|
|
+ DB::table('mp_animes')->where('id', $anime_id)->update(['first_frame_url' => $result_urls[0], 'updated_at' => date('Y-m-d H:i:s')]);
|
|
|
+ Redis::srem('anime_first_frame_urls', $segment_id);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } catch (\Exception $e) {
|
|
|
+ $task->updateStatus(MpGeneratePicTask::STATUS_FAILED, [
|
|
|
+ 'error_message' => '处理响应失败: ' . $e->getMessage()
|
|
|
+ ]);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
* 提交任务到火山图片生成API
|
|
|
*
|
|
|
* @param MpGeneratePicTask $task
|
|
|
@@ -553,7 +705,21 @@ class AIImageGenerationService
|
|
|
\App\Jobs\ProcessVolcImageGenerationJob::dispatch($task->id)->onConnection('redis');
|
|
|
}
|
|
|
|
|
|
- // 2. 获取所有处理中的任务(仅即梦AI需要查询状态)
|
|
|
+ // 2. 处理GPT-Image2的pending任务(批量提交到队列)
|
|
|
+ $gptImage2PendingTasks = MpGeneratePicTask::where('status', MpGeneratePicTask::STATUS_PENDING)
|
|
|
+ ->whereIn('model', BaseConst::GPT_IMAGE2_MODELS)
|
|
|
+ ->orderBy('created_at', 'asc')
|
|
|
+ ->limit(50) // 每次最多处理50个任务,避免超时
|
|
|
+ ->get();
|
|
|
+
|
|
|
+ foreach ($gptImage2PendingTasks as $task) {
|
|
|
+ dLog('generate')->info('开始分发GPT-Image2任务到队列: ' . $task->task_id);
|
|
|
+
|
|
|
+ // 分发到队列
|
|
|
+ \App\Jobs\ProcessGptImage2GenerationJob::dispatch($task->id)->onConnection('redis');
|
|
|
+ }
|
|
|
+
|
|
|
+ // 3. 获取所有处理中的任务(仅即梦AI需要查询状态)
|
|
|
$processingTasks = MpGeneratePicTask::where('status', MpGeneratePicTask::STATUS_PROCESSING)
|
|
|
->where('model', self::MODEL_JIMENG_4)
|
|
|
->get();
|
|
|
@@ -608,7 +774,7 @@ class AIImageGenerationService
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- // 3. 检查是否有任务完成,如果有则处理下一个排队任务(仅即梦AI)
|
|
|
+ // 4. 检查是否有任务完成,如果有则处理下一个排队任务(仅即梦AI)
|
|
|
$this->processNextQueuedTask();
|
|
|
}
|
|
|
|