112 lines
3.1 KiB
JavaScript
112 lines
3.1 KiB
JavaScript
export const STORAGE_KEY = "image-prompt-studio:simple-prompt:v1";
|
|
|
|
export const GENERATION_DEFAULTS = {
|
|
size: "1024x1024",
|
|
quality: "high",
|
|
outputFormat: "png",
|
|
background: "auto",
|
|
count: 1,
|
|
moderation: "auto",
|
|
outputCompression: 90,
|
|
};
|
|
|
|
export const EXAMPLE_PROMPTS = [
|
|
"一只白色陶瓷杯放在浅灰色窗边桌面上,晨光柔和,极简产品摄影,干净背景,苹果官网质感。",
|
|
"未来感电动车停在雾气很轻的海边公路,银色车身,阴天柔光,电影级写实海报。",
|
|
"一间现代风格客厅,浅木地板,奶油白沙发,大面积自然光,室内设计杂志封面感。",
|
|
"一款无线耳机悬浮在纯白背景中,蓝色柔和反射光,商业广告风,细节锐利。",
|
|
];
|
|
|
|
export const PROCESSING_STAGES = [
|
|
{
|
|
title: "整理 Prompt",
|
|
detail: "检查内容并准备发送到服务端。",
|
|
thresholdMs: 1400,
|
|
},
|
|
{
|
|
title: "连接 gpt-image-2",
|
|
detail: "向 OpenAI Images API 发起图片生成请求。",
|
|
thresholdMs: 5200,
|
|
},
|
|
{
|
|
title: "等待渲染",
|
|
detail: "模型正在生成高质量图片,这一步通常最耗时。",
|
|
thresholdMs: 15000,
|
|
},
|
|
{
|
|
title: "准备下载",
|
|
detail: "接收 base64 图片并整理成浏览器可下载文件。",
|
|
thresholdMs: 24000,
|
|
},
|
|
];
|
|
|
|
export function sanitizePrompt(input) {
|
|
return String(input ?? "")
|
|
.replace(/\r/g, "")
|
|
.replace(/[ \t]+\n/g, "\n")
|
|
.replace(/\n{3,}/g, "\n\n")
|
|
.split("\n")
|
|
.map((line) => line.trim())
|
|
.join("\n")
|
|
.trim();
|
|
}
|
|
|
|
export function buildPromptStats(prompt) {
|
|
const cleanPrompt = sanitizePrompt(prompt);
|
|
|
|
if (!cleanPrompt) {
|
|
return "输入一句清晰的画面描述即可开始。";
|
|
}
|
|
|
|
const lineCount = cleanPrompt.split("\n").length;
|
|
const charCount = cleanPrompt.length;
|
|
|
|
return `${charCount} 个字符 · ${lineCount} 行`;
|
|
}
|
|
|
|
export function buildDownloadStem(prompt) {
|
|
const normalized = sanitizePrompt(prompt)
|
|
.toLowerCase()
|
|
.replace(/[^a-z0-9\u4e00-\u9fa5\s-]/g, "")
|
|
.trim()
|
|
.replace(/\s+/g, "-")
|
|
.slice(0, 48);
|
|
|
|
return normalized || "generated-image";
|
|
}
|
|
|
|
export function createProcessingSnapshot(elapsedMs, isComplete = false) {
|
|
if (isComplete) {
|
|
return {
|
|
progress: 1,
|
|
activeStageIndex: PROCESSING_STAGES.length - 1,
|
|
lead: "图片已生成完成,可以预览和下载。",
|
|
};
|
|
}
|
|
|
|
const safeElapsed = Math.max(0, elapsedMs);
|
|
const finalThreshold =
|
|
PROCESSING_STAGES[PROCESSING_STAGES.length - 1]?.thresholdMs ?? 24000;
|
|
const progress = Math.min(0.92, safeElapsed / finalThreshold);
|
|
const activeStageIndex = resolveActiveStageIndex(safeElapsed);
|
|
const activeStage = PROCESSING_STAGES[activeStageIndex];
|
|
|
|
return {
|
|
progress,
|
|
activeStageIndex,
|
|
lead: activeStage
|
|
? `${activeStage.title}中... ${activeStage.detail}`
|
|
: "正在处理,请稍候。",
|
|
};
|
|
}
|
|
|
|
function resolveActiveStageIndex(elapsedMs) {
|
|
for (let index = PROCESSING_STAGES.length - 1; index >= 0; index -= 1) {
|
|
if (elapsedMs >= PROCESSING_STAGES[index].thresholdMs) {
|
|
return index;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|