Pārlūkot izejas kodu

片段确认分镜接口新增对图片生成状态的兜底判断

lh 2 nedēļas atpakaļ
vecāks
revīzija
8d3a4d2c9f
1 mainītis faili ar 109 papildinājumiem un 0 dzēšanām
  1. 109 0
      app/Services/Anime/AnimeService.php

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

@@ -9906,6 +9906,9 @@ class AnimeService
         $scenes = json_decode(getProp($episode, 'scenes'), true) ?: [];
         $props = json_decode(getProp($episode, 'props'), true) ?: [];
 
+        // 确认前校验并等待角色、场景、道具图片全部生成(参照 episodePicsInfo 更新与监控逻辑),未全部生成不得继续后续逻辑
+        $this->waitForEpisodeAssetsImagesReady($episode_id, $roles, $scenes, $props);
+
         // 获取所有片段数据
         $acts = DB::table('mp_episode_segments')->where('episode_id', $episode_id)->orderBy('act_number')->get();
         
@@ -10116,6 +10119,112 @@ class AnimeService
     }
 
     /**
+     * 参照 episodePicsInfo 的更新与监控逻辑:
+     * 每5秒查询一次角色/场景/道具的图片任务状态,任务成功后将图片URL回填到对应资产并写回分集表。
+     * 所有需要图片的资产均已生成(url 非空)才返回;最多等待1分钟,仍有图片未生成则直接报错。
+     */
+    private function waitForEpisodeAssetsImagesReady($episode_id, &$roles, &$scenes, &$props) {
+        $pollInterval = 5;      // 每5秒查询一次
+        $maxWaitSeconds = 60;   // 最多持续1分钟
+        $startTime = time();
+
+        while (true) {
+            // 从数据库读取最新数据,兼容后台 Anime:checkImgUrl 等任务对角色/场景/道具图片URL的更新
+            $episode = DB::table('mp_anime_episodes')->where('id', $episode_id)->first();
+            if (!$episode) {
+                Utils::throwError('20003:分集不存在');
+            }
+            $roles = json_decode(getProp($episode, 'roles'), true) ?: [];
+            $scenes = json_decode(getProp($episode, 'scenes'), true) ?: [];
+            $props = json_decode(getProp($episode, 'props'), true) ?: [];
+
+            $updated = false;
+            $pendingAssets = [];
+
+            $this->refreshEpisodeAssetsImageTasks($roles, 'role', '旁白', $pendingAssets, $updated);
+            $this->refreshEpisodeAssetsImageTasks($scenes, 'scene', '', $pendingAssets, $updated);
+            $this->refreshEpisodeAssetsImageTasks($props, 'prop', '', $pendingAssets, $updated);
+
+            // 有图片任务结果更新时写回分集表
+            if ($updated) {
+                DB::table('mp_anime_episodes')->where('id', $episode_id)->update([
+                    'roles'      => json_encode($roles, JSON_UNESCAPED_UNICODE),
+                    'scenes'     => json_encode($scenes, JSON_UNESCAPED_UNICODE),
+                    'props'      => json_encode($props, JSON_UNESCAPED_UNICODE),
+                    'updated_at' => date('Y-m-d H:i:s')
+                ]);
+            }
+
+            // 所有需要图片的资产都已生成,允许继续 confirmActs 后续逻辑
+            if (empty($pendingAssets)) {
+                return;
+            }
+
+            // 超过1分钟仍未生成完毕,阻止 confirmActs 后续逻辑
+            if (time() - $startTime >= $maxWaitSeconds) {
+                Utils::throwError('20003:还有主体、场景或道具图片未生成,请等待图片生成后重试');
+            }
+
+            sleep($pollInterval);
+        }
+    }
+
+    /**
+     * 参照 episodePicsInfo:遍历单个资产列表,对有图片任务但还没有图片URL的资产查询图片任务结果并回填。
+     * 任务成功但没有可用的结果URL、或任务不存在/生成失败时,直接阻止继续(抛出图片未生成的错误)。
+     */
+    private function refreshEpisodeAssetsImageTasks(&$assets, $nameKey, $skipName, &$pendingAssets, &$updated) {
+        foreach ($assets as &$asset) {
+            $assetName = getProp($asset, $nameKey);
+            if ($assetName === '' || ($skipName !== '' && $assetName === $skipName)) {
+                continue;
+            }
+
+            // 已有图片URL的资产视为已生成
+            if (getProp($asset, 'url')) {
+                continue;
+            }
+
+            $task_id = getProp($asset, 'task_id');
+            // 没有图片任务且没有图片URL,说明图片尚未生成
+            if (!$task_id) {
+                $pendingAssets[] = $assetName;
+                continue;
+            }
+
+            $task = DB::table('mp_generate_pic_tasks')
+                ->where('id', $task_id)
+                ->select('status', 'result_url')
+                ->first();
+
+            if (!$task) {
+                Utils::throwError('20003:还有主体、场景或道具图片未生成,请等待图片生成后重试');
+            }
+
+            if ($task->status === 'success') {
+                $result_url = getProp($task, 'result_url');
+                if ($result_url) {
+                    $result_urls = is_json($result_url) ? json_decode($result_url, true) : [$result_url];
+                    if (is_array($result_urls) && !empty($result_urls[0])) {
+                        $asset['url'] = $result_urls[0];
+                        $asset['task_status'] = 'success';
+                        $updated = true;
+                        continue;
+                    }
+                }
+                // 任务成功但没有可用的结果URL,仍视为未生成
+                $pendingAssets[] = $assetName;
+            } elseif ($task->status === 'failed') {
+                Utils::throwError('20003:还有主体、场景或道具图片未生成,请等待图片生成后重试');
+            } else {
+                // 任务仍在生成中,等待下一次轮询
+                $pendingAssets[] = $assetName;
+            }
+        }
+        unset($asset);
+    }
+
+    /**
      * 导出动漫剧本为PDF(参照示例PDF版式)
      * @param int $animeId 动漫ID
      * @param int $episodeCount 导出集数,默认8,传-1表示全部