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>
@@ -66,3 +66,16 @@
|
|||||||
opacity: 0;
|
opacity: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Hide Next.js dev compiler indicators and static overlays completely */
|
||||||
|
next-route-announcer,
|
||||||
|
nextjs-portal,
|
||||||
|
#nextjs-dev-indicator,
|
||||||
|
.nextjs-static-indicator,
|
||||||
|
div[data-nextjs-toast-wrapper],
|
||||||
|
div[data-nextjs-toast] {
|
||||||
|
display: none !important;
|
||||||
|
visibility: hidden !important;
|
||||||
|
opacity: 0 !important;
|
||||||
|
pointer-events: none !important;
|
||||||
|
}
|
||||||
|
|||||||
@@ -962,7 +962,7 @@ function PlayInner() {
|
|||||||
title="全屏 (F)"
|
title="全屏 (F)"
|
||||||
>
|
>
|
||||||
<i className="fa-solid fa-expand text-[10px]" />
|
<i className="fa-solid fa-expand text-[10px]" />
|
||||||
F · 全 · 屏
|
F · 键 · 全 · 屏
|
||||||
</button>
|
</button>
|
||||||
}
|
}
|
||||||
aboveCanvasLeft={
|
aboveCanvasLeft={
|
||||||
|
|||||||
@@ -71,6 +71,49 @@ export async function generateImage(
|
|||||||
): Promise<GenerateImageResult> {
|
): Promise<GenerateImageResult> {
|
||||||
const url = config.baseUrl.replace(/\/$/, "");
|
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> = {
|
const task: Record<string, unknown> = {
|
||||||
taskType: "imageInference",
|
taskType: "imageInference",
|
||||||
taskUUID: crypto.randomUUID(),
|
taskUUID: crypto.randomUUID(),
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 100 KiB After Width: | Height: | Size: 142 KiB |
|
Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 129 KiB |
|
Before Width: | Height: | Size: 39 KiB After Width: | Height: | Size: 142 KiB |
|
Before Width: | Height: | Size: 72 KiB After Width: | Height: | Size: 60 KiB |
|
Before Width: | Height: | Size: 112 KiB After Width: | Height: | Size: 76 KiB |
|
Before Width: | Height: | Size: 122 KiB After Width: | Height: | Size: 166 KiB |
|
Before Width: | Height: | Size: 76 KiB After Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 66 KiB After Width: | Height: | Size: 76 KiB |
|
Before Width: | Height: | Size: 160 KiB After Width: | Height: | Size: 77 KiB |
|
Before Width: | Height: | Size: 73 KiB After Width: | Height: | Size: 200 KiB |
|
Before Width: | Height: | Size: 62 KiB After Width: | Height: | Size: 170 KiB |
|
Before Width: | Height: | Size: 108 KiB After Width: | Height: | Size: 40 KiB |
|
Before Width: | Height: | Size: 225 KiB After Width: | Height: | Size: 251 KiB |
|
Before Width: | Height: | Size: 69 KiB After Width: | Height: | Size: 96 KiB |
|
Before Width: | Height: | Size: 104 KiB After Width: | Height: | Size: 145 KiB |
|
Before Width: | Height: | Size: 87 KiB After Width: | Height: | Size: 96 KiB |
|
Before Width: | Height: | Size: 157 KiB After Width: | Height: | Size: 116 KiB |
|
Before Width: | Height: | Size: 95 KiB After Width: | Height: | Size: 125 KiB |
|
Before Width: | Height: | Size: 65 KiB After Width: | Height: | Size: 69 KiB |
|
Before Width: | Height: | Size: 82 KiB After Width: | Height: | Size: 99 KiB |
|
Before Width: | Height: | Size: 149 KiB After Width: | Height: | Size: 148 KiB |
|
Before Width: | Height: | Size: 52 KiB After Width: | Height: | Size: 124 KiB |
|
Before Width: | Height: | Size: 45 KiB After Width: | Height: | Size: 34 KiB |
|
Before Width: | Height: | Size: 183 KiB After Width: | Height: | Size: 226 KiB |
|
Before Width: | Height: | Size: 109 KiB |
|
Before Width: | Height: | Size: 130 KiB |
|
Before Width: | Height: | Size: 253 KiB After Width: | Height: | Size: 296 KiB |
|
Before Width: | Height: | Size: 97 KiB After Width: | Height: | Size: 312 KiB |
|
Before Width: | Height: | Size: 143 KiB After Width: | Height: | Size: 178 KiB |
|
Before Width: | Height: | Size: 95 KiB After Width: | Height: | Size: 168 KiB |
|
Before Width: | Height: | Size: 186 KiB After Width: | Height: | Size: 90 KiB |
|
Before Width: | Height: | Size: 185 KiB After Width: | Height: | Size: 172 KiB |
|
Before Width: | Height: | Size: 107 KiB After Width: | Height: | Size: 143 KiB |
|
Before Width: | Height: | Size: 67 KiB After Width: | Height: | Size: 75 KiB |