auto-save 2026-05-18 10:53 (+2, ~2)
This commit is contained in:
2
.env.local.example
Normal file
2
.env.local.example
Normal file
@@ -0,0 +1,2 @@
|
||||
# 生图 API Key。没填则自动走 mock 模式(SVG 占位图)
|
||||
POE_API_KEY=
|
||||
@@ -20,6 +20,13 @@
|
||||
"message": "auto-save 2026-05-18 10:39 (+1, ~1)",
|
||||
"hash": "0accb73",
|
||||
"files_changed": 4
|
||||
},
|
||||
{
|
||||
"ts": "2026-05-18T10:46:21+08:00",
|
||||
"type": "commit",
|
||||
"message": "auto-save 2026-05-18 10:44 (+6, ~2)",
|
||||
"hash": "494779d",
|
||||
"files_changed": 20
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
2076
package-lock.json
generated
Normal file
2076
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -38,11 +38,19 @@ export async function listSessions(): Promise<GenSession[]> {
|
||||
return all.sort((a, b) => b.createdAt - a.createdAt);
|
||||
}
|
||||
|
||||
function extFromMime(mime: string): string {
|
||||
if (mime.includes('jpeg')) return 'jpg';
|
||||
if (mime.includes('svg')) return 'svg';
|
||||
if (mime.includes('png')) return 'png';
|
||||
if (mime.includes('webp')) return 'webp';
|
||||
return 'bin';
|
||||
}
|
||||
|
||||
export async function saveGeneratedImage(sessionId: string, imageId: string, dataUrl: string): Promise<string> {
|
||||
await ensureDirs();
|
||||
const m = dataUrl.match(/^data:image\/(\w+);base64,(.+)$/);
|
||||
const m = dataUrl.match(/^data:([^;]+);base64,(.+)$/);
|
||||
if (!m) throw new Error('Invalid data URL');
|
||||
const ext = m[1] === 'jpeg' ? 'jpg' : m[1];
|
||||
const ext = extFromMime(m[1]);
|
||||
const file = path.join(GEN_DIR, `${sessionId}_${imageId}.${ext}`);
|
||||
await fs.writeFile(file, Buffer.from(m[2], 'base64'));
|
||||
return `/api/img/generated/${sessionId}_${imageId}.${ext}`;
|
||||
@@ -65,7 +73,9 @@ export async function readImageFile(bucket: 'generated' | 'selected' | 'refs', f
|
||||
const dir = bucket === 'generated' ? GEN_DIR : bucket === 'selected' ? SEL_DIR : REF_DIR;
|
||||
const buf = await fs.readFile(path.join(dir, filename));
|
||||
const ext = path.extname(filename).slice(1).toLowerCase();
|
||||
const type = ext === 'jpg' ? 'image/jpeg' : `image/${ext}`;
|
||||
const type = ext === 'jpg' ? 'image/jpeg'
|
||||
: ext === 'svg' ? 'image/svg+xml'
|
||||
: `image/${ext}`;
|
||||
return { buf, type };
|
||||
} catch {
|
||||
return null;
|
||||
@@ -74,9 +84,9 @@ export async function readImageFile(bucket: 'generated' | 'selected' | 'refs', f
|
||||
|
||||
export async function saveRefImage(sessionId: string, idx: number, dataUrl: string): Promise<string> {
|
||||
await ensureDirs();
|
||||
const m = dataUrl.match(/^data:image\/(\w+);base64,(.+)$/);
|
||||
const m = dataUrl.match(/^data:([^;]+);base64,(.+)$/);
|
||||
if (!m) throw new Error('Invalid ref data URL');
|
||||
const ext = m[1] === 'jpeg' ? 'jpg' : m[1];
|
||||
const ext = extFromMime(m[1]);
|
||||
const file = path.join(REF_DIR, `${sessionId}_ref${idx}.${ext}`);
|
||||
await fs.writeFile(file, Buffer.from(m[2], 'base64'));
|
||||
return `/api/img/refs/${sessionId}_ref${idx}.${ext}`;
|
||||
|
||||
Reference in New Issue
Block a user