feat(web): gender-differentiated 4:5 covers + per-card styleGuide prebake

- Regenerate 60 covers (30 male + 30 female) via FLUX with story-specific
  prompts, replacing the prior gender-shared set
- Crop covers to 4:5 (960×1200) via sharp attention cover; matches new
  homepage card aspectRatio
- Persist all 60 prompts to public/home/prompts.json so the prebake step
  can reuse the cover's exact visual anchor (per-card styleGuide) and the
  first-act scene visually carries over from the poster the player clicked
- Restore /play?card= prebaked instant-play path on homepage card click
- Add OpenAI-compatible image route in ai-client for non-Runware endpoints
- Hide Next.js dev indicators globally; tweak F-key fullscreen label

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
DESKTOP-I1T6TF3\Q
2026-06-03 02:20:20 +08:00
parent 820a5f7e87
commit bed4dc5a8f
135 changed files with 826 additions and 476 deletions
+43
View File
@@ -71,6 +71,49 @@ export async function generateImage(
): Promise<GenerateImageResult> {
const url = config.baseUrl.replace(/\/$/, "");
// 1. OpenAI-compatible route (GPTGod, DALL-E, etc.)
const isOpenAi = !url.includes("runware.ai") || config.model === "image-2-vip";
if (isOpenAi) {
const endpoint = url.endsWith("/images/generations") ? url : `${url}/images/generations`;
console.log(`[ai-client] Calling OpenAI-compatible image generations at: ${endpoint} with model: ${config.model}`);
const res = await fetchWithRetry(endpoint, {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${config.apiKey}`,
},
body: JSON.stringify({
model: config.model,
prompt: prompt,
n: 1,
size: "1792x1024", // Use horizontal size (16:9)
}),
});
const text = await res.text();
let json: any;
try {
json = JSON.parse(text);
} catch {
throw new Error(`OpenAI Image API error ${res.status}: ${text.slice(0, 500)}`);
}
if (json.error) {
throw new Error(`OpenAI Image API error: ${json.error.message || JSON.stringify(json.error)}`);
}
const data = json.data?.[0];
const imageUrl = data?.url;
if (!imageUrl) {
throw new Error(`No image URL in OpenAI response: ${text.slice(0, 300)}`);
}
// Generate a mock UUID since OpenAI compatible endpoint doesn't have UUIDs
const imageUuid = crypto.randomUUID();
return { imageUrl, imageUuid };
}
// 2. Runware task-array route
const task: Record<string, unknown> = {
taskType: "imageInference",
taskUUID: crypto.randomUUID(),