feat: model selection+visibility, better filenames, picdrop direct upload + configurable gallery

- studio: quality/model selector (friendly names from active models); library shows model used
- seed 2 models (Schnell/Beste Qualitaet); GET /api/models for studio+library
- filename: YYYY-MM-DD_motif_format.png (was redundant slug, no date)
- picdrop: direct upload to final name (fix .tmp- leftover from failed rename on picdrop); cleanupTmp helper
- configurable default gallery (migration 003, settings + admin field); base_path=SFTP root, gallery=subfolder
This commit is contained in:
2026-07-23 18:54:37 +00:00
parent b047f55687
commit 6d58c6c8fd
12 changed files with 120 additions and 28 deletions
+4 -5
View File
@@ -3,7 +3,7 @@ import { getObject, putObject, resultKey } from './storage';
import { generateImage } from './openrouter';
import { buildPrompt, type Task } from './prompts';
import { resolveDimensions, aspectRatio, type Orientation } from './format';
import { finalizeToFormat, stickerContour, slugFilename, type CropMode } from './pipeline';
import { finalizeToFormat, stickerContour, buildResultFilename, formatToken, type CropMode } from './pipeline';
import sharp from 'sharp';
const DEFAULT_MODEL = 'google/gemini-3.1-flash-image';
@@ -46,8 +46,8 @@ export interface ProcessResult { ok: boolean; cost: number; error?: string; }
/** Verarbeitet eine Position vollständig und aktualisiert ihren Datensatz. */
export async function processItem(itemId: string): Promise<ProcessResult> {
const item = await one<{ id: string; job_id: string; source_path: string }>(
'SELECT id, job_id, source_path FROM items WHERE id=$1', [itemId]);
const item = await one<{ id: string; job_id: string; source_path: string; filename: string | null }>(
'SELECT id, job_id, source_path, filename FROM items WHERE id=$1', [itemId]);
if (!item) return { ok: false, cost: 0, error: 'Position nicht gefunden' };
const job = await one<{ recipe_snapshot: RecipeSnapshot }>(
@@ -105,8 +105,7 @@ export async function processItem(itemId: string): Promise<ProcessResult> {
const key = resultKey(item.id);
await putObject(key, outBuf, 'image/png');
const label = target?.label || 'original';
const filename = slugFilename(label.replace(/\s+/g, '-'), target?.label || '');
const filename = buildResultFilename(item.filename, formatToken(r.output_format), 'png');
const outputPx = `${fin.width}x${fin.height}`;
const deliveryStatus = (r.delivery === 'picdrop' || r.delivery === 'both') ? 'pending' : 'none';