セッション開始:2026/06/09 07:18
3D間取りの生成(ChatGPT)で、
モデルが画像を返さなかった場合の挙動を整理する。
従来は画像が得られないと throw new Error("image not generated") していたため、
生成ルートが 500 を返し、レコードは generationStartedAt だけが立った
「生成中」状態のまま残り、60秒後に自動で再試行され続ける(画面側も GenerationLoading が
35秒ごとに自動リロードを繰り返す)。これを終端化し、失敗を記録できるようにするのが本セッションの目的。
outputImageUri に
入力画像(間取り図)をセットし、一般ユーザーには通常の結果として表示する(=失敗を表に出さない)。
エラー文言(generationError)はシステム管理者のみが詳細画面で閲覧できる。generationEndedAt を立てて終端化する。
これにより無限ローディング/自動リロードループを止め、生成ルートの再実行条件
(generationEndedAt: null)にも合致しなくなる。response.output_text が空文字だと
generationError も空になり、システム管理者にも「生成エラー」アコーディオンが表示されない場合があるが、
現時点では許容する。GenerationLog は成功時のみ作成する。今回の変更で失敗の扱いが2系統に分かれた。両者は終端化されるか否かが異なるため区別して理解する。
① ソフト失敗(画像が返らない)
image_generation_call の結果が無いケース。{ success: false, error: output_text } を返す。generationEndedAt + generationError を保存し、
outputImageUri に入力画像をセット。終端(再試行されない)。200 を返す。② ハード失敗(例外)
try/catch で捕捉される例外。generateImageWithChatGpt は従来どおり re-throw。500 を返す。generationEndedAt は立たず、
60秒後に自動再試行される(一過性エラーのリトライ)。この非対称(ソフト=終端 / ハード=リトライ)は意図的。モデルが「生成できない」と判断したコンテンツ起因の失敗はリトライしても結果が変わりにくいため終端化し、 一過性の通信・基盤エラーはリトライに委ねる。
変更
apps/user/actions/solid-floor-plan/generate-image/lib/chatgpt/index.ts
戻り値を判別可能ユニオン Result
(success: true | false)へ変更。画像が得られない場合は throw せず
{ success: false, error: response.output_text, instructions } を返す。
デバッグ用 console.log(response) を削除。
例外(ハード失敗)の catch は従来どおり re-throw。
変更
apps/user/actions/solid-floor-plan/generate-image/index.ts
戻り値型を同じ Result ユニオンへ変更し、
generateImageWithChatGpt の結果をそのまま中継。
変更
apps/user/app/api/solid-floor-plans/[solidFloorPlanId]/generate/route.ts
!generateImageResult.success の分岐を追加。失敗時は
instructions / outputImageUri = 入力画像 /
generationEndedAt / generationError を保存し、
GenerationLog は作成せず 200 を返す。デバッグ用 console.log を削除。
変更
apps/user/app/(vertical)/v/solid-floor-plans/[solidFloorPlanId]/page.tsx
authUser.isSystemManager && solidFloorPlan.generationError のとき
「生成エラー」アコーディオン(読み取り専用 Textarea)を追加。一般ユーザーには表示されない。
スキーマ / マイグレーション
prisma/schema/solid-floor-plan.prisma / prisma/migrations/20260609062420_solid_floor_plans/
SolidFloorPlan に
generationError String? @map("generation_error") を追加
(ALTER TABLE ... ADD COLUMN "generation_error" TEXT)。prisma client 再生成済み。
🟡 仕様確認:
失敗時に outputImageUri へ入力画像を入れることで、
一般ユーザーには「入力と同じ画像が結果として出る/共有・ダウンロード・ホームステージング作成ボタンが出る」状態になる点を確認。
「失敗は一般ユーザーに見せない」方針として意図的と合意。
🟡 既知の限界(許容):
response.output_text が空のとき generationError も空となり、
システム管理者にも「生成エラー」が表示されない。当面許容。将来、空のときはデフォルト文言を入れる余地あり。
🔵 軽微(未対応):
Result 型が generate-image/index.ts と
lib/chatgpt/index.ts に重複定義されている。構造的に互換なので動作上は問題ないが、共通化の余地。
🔵 既存(本セッション対象外):
生成ルートのレスポンスキーが refinement のまま(別機能からの流用と思われる)。今回は変更せず。
apps/user で tsc --noEmit を実行し、型エラー無し(EXIT=0)を確認。
成功分岐後の generateImageResult.imageUri 参照も判別可能ユニオンのナローイングで安全。