@rslsp1/fa-app-tools 2.0.85 → 2.0.87
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-LFPOXNOZ.mjs → chunk-NBUS7AWR.mjs} +10 -2
- package/dist/{chunk-MILMVOK7.mjs → chunk-ZVHEHQ7A.mjs} +232 -60
- package/dist/hfEventTypes-C_PX6RFR.d.ts +241 -0
- package/dist/hfEventTypes-Dkfrcd_t.d.mts +241 -0
- package/dist/{hfStateService-PZH2IDKF.mjs → hfStateService-W7KO2FOH.mjs} +1 -1
- package/dist/index.d.mts +4 -172
- package/dist/index.d.ts +4 -172
- package/dist/index.js +170 -68
- package/dist/index.mjs +6 -74
- package/dist/szenen.d.mts +99 -5
- package/dist/szenen.d.ts +99 -5
- package/dist/szenen.js +241 -63
- package/dist/szenen.mjs +8 -2
- package/package.json +1 -1
- package/dist/flowTextGenerationPort-CeDUFutP.d.mts +0 -73
- package/dist/flowTextGenerationPort-KHjCGt_S.d.ts +0 -73
|
@@ -6,6 +6,12 @@ import { uploadFile } from "@huggingface/hub";
|
|
|
6
6
|
var HF_BASE = "https://huggingface.co";
|
|
7
7
|
var HF_REPO = "RolandSch/fa-app-state";
|
|
8
8
|
var CURRENT_EVENT_VERSION = { major: 1, minor: 0 };
|
|
9
|
+
var SPEICHERBARE_BILDTYPEN = ["image/png", "image/jpeg", "image/webp"];
|
|
10
|
+
function bildEndungFuer(mimeType) {
|
|
11
|
+
if (mimeType === "image/png") return "png";
|
|
12
|
+
if (mimeType === "image/webp") return "webp";
|
|
13
|
+
return "jpg";
|
|
14
|
+
}
|
|
9
15
|
|
|
10
16
|
// src/lib/hfEventLog.ts
|
|
11
17
|
function treeUrl(namespace, subdir = "") {
|
|
@@ -333,7 +339,7 @@ async function hfLoadMetadata(token) {
|
|
|
333
339
|
}
|
|
334
340
|
}
|
|
335
341
|
async function hfUploadImage(base64, id, token, mimeType = "image/jpeg") {
|
|
336
|
-
const ext = mimeType
|
|
342
|
+
const ext = bildEndungFuer(mimeType);
|
|
337
343
|
const binary = atob(base64);
|
|
338
344
|
const bytes = new Uint8Array(binary.length);
|
|
339
345
|
for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
|
|
@@ -375,12 +381,14 @@ async function hfLoadImageAsBase64(id, token, namespace, filename, on404, mimeTy
|
|
|
375
381
|
const result2 = await fetchBase64(`images/${filename}`);
|
|
376
382
|
return result2 === "ABORT" ? null : result2;
|
|
377
383
|
}
|
|
378
|
-
const ext = mimeType
|
|
384
|
+
const ext = bildEndungFuer(mimeType);
|
|
379
385
|
const result = await fetchBase64(`images/${id}.${ext}`);
|
|
380
386
|
return result === "ABORT" ? null : result;
|
|
381
387
|
}
|
|
382
388
|
|
|
383
389
|
export {
|
|
390
|
+
SPEICHERBARE_BILDTYPEN,
|
|
391
|
+
bildEndungFuer,
|
|
384
392
|
hfListDir,
|
|
385
393
|
hfDownloadJsonByPath,
|
|
386
394
|
hfDownloadBinaryByPath,
|
|
@@ -5,12 +5,14 @@ import {
|
|
|
5
5
|
resolvePreferredHead
|
|
6
6
|
} from "./chunk-FUY2OCVC.mjs";
|
|
7
7
|
import {
|
|
8
|
+
SPEICHERBARE_BILDTYPEN,
|
|
9
|
+
bildEndungFuer,
|
|
8
10
|
hfLoadImageAsBase64,
|
|
9
11
|
hfUploadImage,
|
|
10
12
|
loadHFState,
|
|
11
13
|
loadPendingEvents,
|
|
12
14
|
writeHFEvent
|
|
13
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-NBUS7AWR.mjs";
|
|
14
16
|
|
|
15
17
|
// src/lib/szenen/viewPort.ts
|
|
16
18
|
function capabilitiesOf(port) {
|
|
@@ -6468,8 +6470,8 @@ var BestandsBild = ({ port, mediaRef }) => {
|
|
|
6468
6470
|
};
|
|
6469
6471
|
var BatchBild = ({ port, bild }) => {
|
|
6470
6472
|
const [phase] = usePortQuery(
|
|
6471
|
-
() => port.imageLibrary ? port.imageLibrary.resolveImage(bild.media_ref) : Promise.resolve({ kind: "ok", value: null }),
|
|
6472
|
-
[port, bild.media_ref]
|
|
6473
|
+
() => port.imageLibrary ? port.imageLibrary.resolveImage(bild.media_ref, bild.mime_type ?? null) : Promise.resolve({ kind: "ok", value: null }),
|
|
6474
|
+
[port, bild.media_ref, bild.mime_type]
|
|
6473
6475
|
);
|
|
6474
6476
|
return /* @__PURE__ */ jsxs5("li", { "data-testid": `batchbild-${bild.media_ref}`, children: [
|
|
6475
6477
|
phase.status === "ready" && phase.value && /* @__PURE__ */ jsx5(
|
|
@@ -11067,6 +11069,182 @@ function createClientRunPort(options) {
|
|
|
11067
11069
|
};
|
|
11068
11070
|
}
|
|
11069
11071
|
|
|
11072
|
+
// src/lib/hfReducer.ts
|
|
11073
|
+
function applyEvent(state, event) {
|
|
11074
|
+
if (event.v.major > 1) return state;
|
|
11075
|
+
switch (event.type) {
|
|
11076
|
+
// SPEZ: image_added (state/spez/hf-state.spez.yaml)
|
|
11077
|
+
case "image_added": {
|
|
11078
|
+
const p = event.payload;
|
|
11079
|
+
if (state.metadata.some((m) => m.id === p.id)) return state;
|
|
11080
|
+
return { ...state, metadata: [...state.metadata, p] };
|
|
11081
|
+
}
|
|
11082
|
+
// SPEZ: task_requested (global/spez/task-queue.spez.yaml)
|
|
11083
|
+
case "task_requested": {
|
|
11084
|
+
const p = event.payload;
|
|
11085
|
+
if (p.expiresAt && p.expiresAt < event.ts) return state;
|
|
11086
|
+
const openTasks = { ...state.openTasks || {} };
|
|
11087
|
+
openTasks[p.taskId] = p;
|
|
11088
|
+
return { ...state, openTasks };
|
|
11089
|
+
}
|
|
11090
|
+
// SPEZ: task_completed (global/spez/task-queue.spez.yaml)
|
|
11091
|
+
case "task_completed": {
|
|
11092
|
+
const p = event.payload;
|
|
11093
|
+
if (!state.openTasks || !state.openTasks[p.taskId]) return state;
|
|
11094
|
+
const openTasks = { ...state.openTasks };
|
|
11095
|
+
delete openTasks[p.taskId];
|
|
11096
|
+
return { ...state, openTasks };
|
|
11097
|
+
}
|
|
11098
|
+
// SPEZ: tag_upserted (state/spez/hf-state.spez.yaml) — Legacy, wird nicht mehr erzeugt
|
|
11099
|
+
case "tag_upserted": {
|
|
11100
|
+
const p = event.payload;
|
|
11101
|
+
const tags = state.tags;
|
|
11102
|
+
const cat = tags.by_category[p.category] || [];
|
|
11103
|
+
const existing = cat.find((t) => t.value === p.value);
|
|
11104
|
+
const updated = { label: p.label, value: p.value, is_user_created: p.is_user_created, is_deleted: p.is_deleted };
|
|
11105
|
+
const newCat = existing ? cat.map((t) => t.value === p.value ? { ...t, ...updated } : t) : [...cat, updated];
|
|
11106
|
+
const newAll = tags.all.some((t) => t.value === p.value && t.category === p.category) ? tags.all.map((t) => t.value === p.value && t.category === p.category ? { ...t, ...updated, category: p.category } : t) : [...tags.all, { ...updated, category: p.category }];
|
|
11107
|
+
return { ...state, tags: { by_category: { ...tags.by_category, [p.category]: newCat }, all: newAll } };
|
|
11108
|
+
}
|
|
11109
|
+
// SPEZ: thumb_added (state/spez/hf-state.spez.yaml)
|
|
11110
|
+
case "thumb_added": {
|
|
11111
|
+
const p = event.payload;
|
|
11112
|
+
return {
|
|
11113
|
+
...state,
|
|
11114
|
+
metadata: state.metadata.map((m) => m.id === p.id ? { ...m, hasThumb: true } : m)
|
|
11115
|
+
};
|
|
11116
|
+
}
|
|
11117
|
+
// SPEZ: metadata_updated (state/spez/hf-state.spez.yaml)
|
|
11118
|
+
case "metadata_updated": {
|
|
11119
|
+
const p = event.payload;
|
|
11120
|
+
return {
|
|
11121
|
+
...state,
|
|
11122
|
+
metadata: state.metadata.map((m) => m.id === p.id ? { ...m, ...p.delta } : m)
|
|
11123
|
+
};
|
|
11124
|
+
}
|
|
11125
|
+
// SPEZ: title_set (state/spez/hf-state.spez.yaml)
|
|
11126
|
+
case "title_set": {
|
|
11127
|
+
const p = event.payload;
|
|
11128
|
+
return {
|
|
11129
|
+
...state,
|
|
11130
|
+
metadata: state.metadata.map((m) => m.id === p.id ? { ...m, titleTs: event.ts } : m)
|
|
11131
|
+
};
|
|
11132
|
+
}
|
|
11133
|
+
default:
|
|
11134
|
+
return state;
|
|
11135
|
+
}
|
|
11136
|
+
}
|
|
11137
|
+
function applyEvents(state, events) {
|
|
11138
|
+
return events.reduce(applyEvent, state);
|
|
11139
|
+
}
|
|
11140
|
+
|
|
11141
|
+
// src/lib/szenen/hfImageStore.ts
|
|
11142
|
+
var LEERER_BESTAND = {
|
|
11143
|
+
metadata: [],
|
|
11144
|
+
tags: { by_category: {}, all: [] },
|
|
11145
|
+
meta: { consolidatedAt: 0, version: 1 }
|
|
11146
|
+
};
|
|
11147
|
+
var endungFuer = bildEndungFuer;
|
|
11148
|
+
function bildPfad(id, mimeType) {
|
|
11149
|
+
return `images/${id}.${endungFuer(mimeType)}`;
|
|
11150
|
+
}
|
|
11151
|
+
function typAusBytes(base64, vorgabe = "image/png") {
|
|
11152
|
+
const kopf = base64.slice(0, 16);
|
|
11153
|
+
if (kopf.startsWith("iVBORw0KGgo")) return "image/png";
|
|
11154
|
+
if (kopf.startsWith("/9j/")) return "image/jpeg";
|
|
11155
|
+
if (kopf.startsWith("UklGR")) return "image/webp";
|
|
11156
|
+
if (kopf.startsWith("R0lGOD")) return "image/gif";
|
|
11157
|
+
return vorgabe;
|
|
11158
|
+
}
|
|
11159
|
+
var warten = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
11160
|
+
function createHfImageStore(options) {
|
|
11161
|
+
const { namespace, token } = options;
|
|
11162
|
+
const now = options.now ?? (() => Date.now());
|
|
11163
|
+
const versuche = options.leseVersuche ?? 4;
|
|
11164
|
+
const basisMs = options.leseBasisMs ?? 400;
|
|
11165
|
+
const schlafen = options.schlafen ?? warten;
|
|
11166
|
+
const abgelegt = /* @__PURE__ */ new Map();
|
|
11167
|
+
const bekanntePfade = /* @__PURE__ */ new Set();
|
|
11168
|
+
let gefalteterBestand = null;
|
|
11169
|
+
let laufenderAbgleich = null;
|
|
11170
|
+
async function bestandLesen() {
|
|
11171
|
+
const grundlage = gefalteterBestand ?? await loadHFState(namespace, token) ?? LEERER_BESTAND;
|
|
11172
|
+
const neue = await loadPendingEvents(
|
|
11173
|
+
namespace,
|
|
11174
|
+
token,
|
|
11175
|
+
grundlage.meta.consolidatedAt,
|
|
11176
|
+
bekanntePfade
|
|
11177
|
+
);
|
|
11178
|
+
const danach = neue.filter((e) => e.ts > grundlage.meta.consolidatedAt);
|
|
11179
|
+
gefalteterBestand = danach.length ? applyEvents(grundlage, danach) : grundlage;
|
|
11180
|
+
return gefalteterBestand;
|
|
11181
|
+
}
|
|
11182
|
+
function bestandAbgleichen() {
|
|
11183
|
+
if (!laufenderAbgleich) {
|
|
11184
|
+
laufenderAbgleich = bestandLesen().finally(() => {
|
|
11185
|
+
laufenderAbgleich = null;
|
|
11186
|
+
});
|
|
11187
|
+
}
|
|
11188
|
+
return laufenderAbgleich;
|
|
11189
|
+
}
|
|
11190
|
+
return {
|
|
11191
|
+
bestand: bestandAbgleichen,
|
|
11192
|
+
async putWithId(id, base64, mimeType, titel) {
|
|
11193
|
+
const echterTyp = typAusBytes(base64, mimeType);
|
|
11194
|
+
if (!SPEICHERBARE_BILDTYPEN.includes(echterTyp)) {
|
|
11195
|
+
throw new Error(
|
|
11196
|
+
`Das Bild ${id} ist ${echterTyp}; der Bildbestand kann nur ${SPEICHERBARE_BILDTYPEN.join(", ")} wahrheitsgemaess ablegen. Es wurde nichts geschrieben.`
|
|
11197
|
+
);
|
|
11198
|
+
}
|
|
11199
|
+
await hfUploadImage(base64, id, token, echterTyp);
|
|
11200
|
+
await writeHFEvent(namespace, token, "image_added", {
|
|
11201
|
+
id,
|
|
11202
|
+
prompt: titel ?? id,
|
|
11203
|
+
tags: [],
|
|
11204
|
+
timestamp: now(),
|
|
11205
|
+
mimeType: echterTyp
|
|
11206
|
+
}, []);
|
|
11207
|
+
abgelegt.set(id, { data: base64, mimeType: echterTyp });
|
|
11208
|
+
},
|
|
11209
|
+
async resolve(id, mimeType) {
|
|
11210
|
+
const eben = abgelegt.get(id);
|
|
11211
|
+
if (eben) return eben;
|
|
11212
|
+
const zustand = await bestandAbgleichen();
|
|
11213
|
+
const eintrag = zustand.metadata.find((e) => e.id === id);
|
|
11214
|
+
const typ = eintrag?.mimeType || mimeType || null;
|
|
11215
|
+
if (eintrag) {
|
|
11216
|
+
const base64 = await hfLoadImageAsBase64(
|
|
11217
|
+
id,
|
|
11218
|
+
token,
|
|
11219
|
+
void 0,
|
|
11220
|
+
eintrag.filename,
|
|
11221
|
+
void 0,
|
|
11222
|
+
eintrag.mimeType,
|
|
11223
|
+
false
|
|
11224
|
+
);
|
|
11225
|
+
if (base64) return { data: base64, mimeType: eintrag.mimeType || "image/jpeg" };
|
|
11226
|
+
}
|
|
11227
|
+
const pfadTyp = typ ?? "image/png";
|
|
11228
|
+
for (let versuch = 0; versuch < versuche; versuch += 1) {
|
|
11229
|
+
if (versuch > 0) await schlafen(basisMs * 2 ** (versuch - 1));
|
|
11230
|
+
const base64 = await hfLoadImageAsBase64(
|
|
11231
|
+
id,
|
|
11232
|
+
token,
|
|
11233
|
+
void 0,
|
|
11234
|
+
void 0,
|
|
11235
|
+
void 0,
|
|
11236
|
+
pfadTyp,
|
|
11237
|
+
false
|
|
11238
|
+
);
|
|
11239
|
+
if (base64) return { data: base64, mimeType: pfadTyp };
|
|
11240
|
+
}
|
|
11241
|
+
throw new Error(
|
|
11242
|
+
`Das Bild ${id} ist auf HF nicht auffindbar. Geprueft: ${bildPfad(id, pfadTyp)} in ${versuche} Versuchen` + (eintrag ? " (im Bestand verzeichnet, aber nicht ladbar)." : " (nicht im Bestand verzeichnet).")
|
|
11243
|
+
);
|
|
11244
|
+
}
|
|
11245
|
+
};
|
|
11246
|
+
}
|
|
11247
|
+
|
|
11070
11248
|
// src/lib/szenen/hfImageLibrary.ts
|
|
11071
11249
|
function fehler2(nachricht, retryable = false) {
|
|
11072
11250
|
return { kind: "error", message: nachricht, retryable };
|
|
@@ -11082,14 +11260,16 @@ function alsBild(eintrag) {
|
|
|
11082
11260
|
};
|
|
11083
11261
|
}
|
|
11084
11262
|
function createHfImageLibrary(options) {
|
|
11085
|
-
const { namespace, token } = options;
|
|
11086
11263
|
const newImageId = options.newImageId ?? (() => crypto.randomUUID());
|
|
11087
|
-
const
|
|
11088
|
-
|
|
11264
|
+
const store = options.store ?? createHfImageStore({
|
|
11265
|
+
namespace: options.namespace,
|
|
11266
|
+
token: options.token,
|
|
11267
|
+
...options.now ? { now: options.now } : {}
|
|
11268
|
+
});
|
|
11089
11269
|
return {
|
|
11090
11270
|
async listImages(query) {
|
|
11091
11271
|
try {
|
|
11092
|
-
const zustand = await
|
|
11272
|
+
const zustand = await store.bestand();
|
|
11093
11273
|
const eintraege = zustand?.metadata ?? [];
|
|
11094
11274
|
const gesucht = query?.search?.trim().toLowerCase();
|
|
11095
11275
|
const gefiltert = gesucht ? eintraege.filter((e) => (e.prompt ?? "").toLowerCase().includes(gesucht) || e.id.toLowerCase().includes(gesucht)) : eintraege;
|
|
@@ -11103,54 +11283,18 @@ function createHfImageLibrary(options) {
|
|
|
11103
11283
|
);
|
|
11104
11284
|
}
|
|
11105
11285
|
},
|
|
11106
|
-
async resolveImage(mediaRef) {
|
|
11107
|
-
const eben = frisch.get(mediaRef);
|
|
11108
|
-
if (eben) return { kind: "ok", value: { data: eben.data, mime_type: eben.mimeType } };
|
|
11286
|
+
async resolveImage(mediaRef, mimeTypeHinweis) {
|
|
11109
11287
|
try {
|
|
11110
|
-
const
|
|
11111
|
-
|
|
11112
|
-
if (eintrag) {
|
|
11113
|
-
const base64 = await hfLoadImageAsBase64(
|
|
11114
|
-
mediaRef,
|
|
11115
|
-
token,
|
|
11116
|
-
void 0,
|
|
11117
|
-
eintrag.filename,
|
|
11118
|
-
void 0,
|
|
11119
|
-
eintrag.mimeType,
|
|
11120
|
-
false
|
|
11121
|
-
);
|
|
11122
|
-
if (!base64) {
|
|
11123
|
-
return fehler2(`Das Bild ${mediaRef} ist im Bestand verzeichnet, aber nicht ladbar.`, true);
|
|
11124
|
-
}
|
|
11125
|
-
return { kind: "ok", value: { data: base64, mime_type: eintrag.mimeType || "image/jpeg" } };
|
|
11126
|
-
}
|
|
11127
|
-
for (const mimeType of ["image/png", "image/jpeg"]) {
|
|
11128
|
-
const base64 = await hfLoadImageAsBase64(mediaRef, token, void 0, void 0, void 0, mimeType, false);
|
|
11129
|
-
if (base64) return { kind: "ok", value: { data: base64, mime_type: mimeType } };
|
|
11130
|
-
}
|
|
11131
|
-
return fehler2(
|
|
11132
|
-
`Das Bild ${mediaRef} steht nicht im Bestand. Moeglicherweise hat der Abgleich es noch nicht uebertragen.`,
|
|
11133
|
-
true
|
|
11134
|
-
);
|
|
11288
|
+
const bild = await store.resolve(mediaRef, mimeTypeHinweis);
|
|
11289
|
+
return { kind: "ok", value: { data: bild.data, mime_type: bild.mimeType } };
|
|
11135
11290
|
} catch (error) {
|
|
11136
|
-
return fehler2(
|
|
11137
|
-
`Das Bild ${mediaRef} konnte nicht geladen werden: ${error instanceof Error ? error.message : String(error)}`,
|
|
11138
|
-
true
|
|
11139
|
-
);
|
|
11291
|
+
return fehler2(error instanceof Error ? error.message : String(error), true);
|
|
11140
11292
|
}
|
|
11141
11293
|
},
|
|
11142
11294
|
async putImage(input) {
|
|
11143
11295
|
const id = newImageId();
|
|
11144
11296
|
try {
|
|
11145
|
-
await
|
|
11146
|
-
await writeHFEvent(namespace, token, "image_added", {
|
|
11147
|
-
id,
|
|
11148
|
-
prompt: input.title,
|
|
11149
|
-
tags: [],
|
|
11150
|
-
timestamp: now(),
|
|
11151
|
-
mimeType: input.mime_type
|
|
11152
|
-
}, []);
|
|
11153
|
-
frisch.set(id, { mimeType: input.mime_type, data: input.data });
|
|
11297
|
+
await store.putWithId(id, input.data, input.mime_type, input.title);
|
|
11154
11298
|
return {
|
|
11155
11299
|
kind: "ok",
|
|
11156
11300
|
value: { mediaRef: id, title: input.title, mimeType: input.mime_type, thumbUrl: null }
|
|
@@ -11280,6 +11424,11 @@ function alsBilder(rohe) {
|
|
|
11280
11424
|
media_ref: b.media_ref,
|
|
11281
11425
|
position: b.position,
|
|
11282
11426
|
...istText4(b.asset_id) ? { asset_id: b.asset_id } : {},
|
|
11427
|
+
// Der bestätigte MIME-Typ (Review 2026-08-18 §5 P2) muss durch das
|
|
11428
|
+
// Rücklesen hindurch: Genau hier braucht ihn der Lesepfad, um den
|
|
11429
|
+
// Dateipfad `images/<id>.<ext>` zu bilden, statt ihn zu erraten. Nur
|
|
11430
|
+
// gesetzt, wenn er im Ereignis steht — ältere Batches tragen ihn nicht.
|
|
11431
|
+
...istText4(b.mime_type) ? { mime_type: b.mime_type } : {},
|
|
11283
11432
|
model: b.model ?? null,
|
|
11284
11433
|
seed: b.seed ?? null,
|
|
11285
11434
|
width: b.width ?? null,
|
|
@@ -11368,6 +11517,7 @@ async function legeBatchAb(options, input) {
|
|
|
11368
11517
|
const { namespace, token, channel } = options;
|
|
11369
11518
|
const newImageId = options.newImageId ?? ((batchId, position) => `${batchId}-${position}`);
|
|
11370
11519
|
const now = options.now ?? (() => /* @__PURE__ */ new Date());
|
|
11520
|
+
const store = options.store ?? createHfImageStore({ namespace, token });
|
|
11371
11521
|
const itemId = itemIdForRun(input.runId);
|
|
11372
11522
|
let vorhandeneEvents;
|
|
11373
11523
|
try {
|
|
@@ -11386,15 +11536,14 @@ async function legeBatchAb(options, input) {
|
|
|
11386
11536
|
for (let offset = 0; offset < input.images.length; offset++) {
|
|
11387
11537
|
const bild = input.images[offset];
|
|
11388
11538
|
const id = newImageId(input.generationBatchId, startPosition + offset);
|
|
11539
|
+
const echterTyp = typAusBytes(bild.imageBase64, bild.mimeType);
|
|
11389
11540
|
try {
|
|
11390
|
-
await
|
|
11391
|
-
await writeHFEvent(namespace, token, "image_added", {
|
|
11541
|
+
await store.putWithId(
|
|
11392
11542
|
id,
|
|
11393
|
-
|
|
11394
|
-
|
|
11395
|
-
|
|
11396
|
-
|
|
11397
|
-
}, []);
|
|
11543
|
+
bild.imageBase64,
|
|
11544
|
+
echterTyp,
|
|
11545
|
+
input.title ?? `Batch ${input.generationBatchId}`
|
|
11546
|
+
);
|
|
11398
11547
|
} catch (error) {
|
|
11399
11548
|
return fehler3(
|
|
11400
11549
|
`Bild ${offset + 1}/${input.images.length} des Batches ${input.generationBatchId} konnte nicht im Bildbestand abgelegt werden: ${error instanceof Error ? error.message : String(error)}. Bereits abgelegte Bilder dieses Versuchs (${abgelegt.length}) bleiben im Bestand, geh\xF6ren aber zu keinem Batch, solange das Batch-Ereignis nicht geschrieben ist.`
|
|
@@ -11404,6 +11553,7 @@ async function legeBatchAb(options, input) {
|
|
|
11404
11553
|
position: startPosition + offset,
|
|
11405
11554
|
media_ref: id,
|
|
11406
11555
|
asset_id: id,
|
|
11556
|
+
mime_type: echterTyp,
|
|
11407
11557
|
model: bild.model ?? null,
|
|
11408
11558
|
seed: bild.seed ?? null,
|
|
11409
11559
|
width: bild.width ?? null,
|
|
@@ -11447,8 +11597,11 @@ function createHfImageGenerationBatchPersistence(options) {
|
|
|
11447
11597
|
images: input.images.map((bild) => ({
|
|
11448
11598
|
imageBase64: bild.imageBase64,
|
|
11449
11599
|
// Flow liefert PNG-Base64 (bestehende Konvention, s. AvatarArchitectApp.tsx
|
|
11450
|
-
// `data:image/png;base64,${base64}`)
|
|
11451
|
-
// keinen MIME-Typ je Bild.
|
|
11600
|
+
// `data:image/png;base64,${base64}`), und der gemeinsame Vertrag führt
|
|
11601
|
+
// keinen MIME-Typ je Bild. Das ist deshalb nur die **Vorgabe**:
|
|
11602
|
+
// Entschieden wird nach den echten Bytes (Review §5 P2) — ein künftig
|
|
11603
|
+
// anders kodiertes Bild läge sonst unter einer Endung, unter der es
|
|
11604
|
+
// niemand sucht.
|
|
11452
11605
|
mimeType: "image/png",
|
|
11453
11606
|
model: bild.model ?? null,
|
|
11454
11607
|
seed: bild.seed ?? null,
|
|
@@ -11469,6 +11622,8 @@ function createHfImageBatchWrite(options) {
|
|
|
11469
11622
|
title: input.title,
|
|
11470
11623
|
images: input.images.map((bild) => ({
|
|
11471
11624
|
imageBase64: bild.imageBase64,
|
|
11625
|
+
// Vorgabe, kein Urteil — der Import bringt beliebig kodierte Bilder
|
|
11626
|
+
// mit, und der Typ wird aus den Bytes bestimmt (Review §5 P2).
|
|
11472
11627
|
mimeType: "image/png",
|
|
11473
11628
|
model: bild.model ?? null,
|
|
11474
11629
|
seed: bild.seed ?? null,
|
|
@@ -11757,7 +11912,17 @@ function createFlowSzenenViewPort(options) {
|
|
|
11757
11912
|
...options.newRunId ? { newRunId: options.newRunId } : {},
|
|
11758
11913
|
...options.now ? { now: options.now } : {}
|
|
11759
11914
|
});
|
|
11760
|
-
const
|
|
11915
|
+
const hatHfZugangsdaten = Boolean(options.namespace?.trim() && options.token?.trim());
|
|
11916
|
+
const bildSpeicher = hatHfZugangsdaten ? createHfImageStore({
|
|
11917
|
+
namespace: options.namespace,
|
|
11918
|
+
token: options.token,
|
|
11919
|
+
...options.now ? { now: () => options.now().getTime() } : {}
|
|
11920
|
+
}) : void 0;
|
|
11921
|
+
const imageLibrary = options.imageLibrary ?? (bildSpeicher ? createHfImageLibrary({
|
|
11922
|
+
namespace: options.namespace,
|
|
11923
|
+
token: options.token,
|
|
11924
|
+
store: bildSpeicher
|
|
11925
|
+
}) : void 0);
|
|
11761
11926
|
const derivation = createClientDerivationPort({
|
|
11762
11927
|
store: elements,
|
|
11763
11928
|
derivations: createEventLogDerivationPersistence(channel),
|
|
@@ -11767,11 +11932,11 @@ function createFlowSzenenViewPort(options) {
|
|
|
11767
11932
|
...options.now ? { now: options.now } : {}
|
|
11768
11933
|
});
|
|
11769
11934
|
const imageBatchHistory = createHfImageBatchHistory({ channel });
|
|
11770
|
-
const
|
|
11771
|
-
const imageBatchWrite = hatHfZugangsdaten ? createHfImageBatchWrite({
|
|
11935
|
+
const imageBatchWrite = bildSpeicher ? createHfImageBatchWrite({
|
|
11772
11936
|
namespace: options.namespace,
|
|
11773
11937
|
token: options.token,
|
|
11774
11938
|
channel,
|
|
11939
|
+
store: bildSpeicher,
|
|
11775
11940
|
...options.newBatchImageId ? { newImageId: options.newBatchImageId } : {},
|
|
11776
11941
|
...options.now ? { now: options.now } : {}
|
|
11777
11942
|
}) : void 0;
|
|
@@ -11785,6 +11950,9 @@ function createFlowSzenenViewPort(options) {
|
|
|
11785
11950
|
namespace: options.namespace,
|
|
11786
11951
|
token: options.token,
|
|
11787
11952
|
channel,
|
|
11953
|
+
// Dieselbe Instanz wie der Bildbestand — sonst wäre das gerade
|
|
11954
|
+
// erzeugte Bild in der Laufansicht wieder unauffindbar (R1).
|
|
11955
|
+
store: bildSpeicher,
|
|
11788
11956
|
...options.newBatchImageId ? { newImageId: options.newBatchImageId } : {},
|
|
11789
11957
|
...options.now ? { now: options.now } : {}
|
|
11790
11958
|
}),
|
|
@@ -11800,6 +11968,7 @@ function createFlowSzenenViewPort(options) {
|
|
|
11800
11968
|
}
|
|
11801
11969
|
|
|
11802
11970
|
export {
|
|
11971
|
+
applyEvents,
|
|
11803
11972
|
capabilitiesOf,
|
|
11804
11973
|
unsupportedReason,
|
|
11805
11974
|
callOptional,
|
|
@@ -11914,6 +12083,9 @@ export {
|
|
|
11914
12083
|
runPromptDerivation,
|
|
11915
12084
|
createEventLogRunPersistence,
|
|
11916
12085
|
createClientRunPort,
|
|
12086
|
+
bildPfad,
|
|
12087
|
+
typAusBytes,
|
|
12088
|
+
createHfImageStore,
|
|
11917
12089
|
createHfImageLibrary,
|
|
11918
12090
|
FLOW_MODEL_DISPLAY_NAMES,
|
|
11919
12091
|
flowImageProviderHasAccess,
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
import { T as TextGenerationPort } from './contracts-DdYOMBl9.js';
|
|
2
|
+
|
|
3
|
+
interface TagOption {
|
|
4
|
+
label: string;
|
|
5
|
+
value: string;
|
|
6
|
+
is_user_created?: boolean;
|
|
7
|
+
is_deleted?: boolean;
|
|
8
|
+
}
|
|
9
|
+
interface WorkspaceTags {
|
|
10
|
+
by_category: Record<string, TagOption[]>;
|
|
11
|
+
all: Array<TagOption & {
|
|
12
|
+
category: string;
|
|
13
|
+
}>;
|
|
14
|
+
}
|
|
15
|
+
interface Generation {
|
|
16
|
+
id: string;
|
|
17
|
+
nodeId: string;
|
|
18
|
+
base64?: string;
|
|
19
|
+
fullBase64?: string;
|
|
20
|
+
mediaId?: string;
|
|
21
|
+
prompt?: string;
|
|
22
|
+
hierarchy?: string;
|
|
23
|
+
seed?: number;
|
|
24
|
+
model?: string;
|
|
25
|
+
timestamp: number;
|
|
26
|
+
status: 'processing' | 'done' | 'error';
|
|
27
|
+
step?: string;
|
|
28
|
+
tags: string[];
|
|
29
|
+
type?: 'generation' | 'import';
|
|
30
|
+
error?: {
|
|
31
|
+
message: string;
|
|
32
|
+
details?: string;
|
|
33
|
+
};
|
|
34
|
+
selectedForExport?: boolean;
|
|
35
|
+
filename?: string;
|
|
36
|
+
hasThumb?: boolean;
|
|
37
|
+
mimeType?: string;
|
|
38
|
+
titleTs?: number;
|
|
39
|
+
}
|
|
40
|
+
interface ProjectSettings {
|
|
41
|
+
aspectRatio: string;
|
|
42
|
+
selectedModel: string;
|
|
43
|
+
seed: number;
|
|
44
|
+
seedMode: 'random' | 'fixed';
|
|
45
|
+
}
|
|
46
|
+
interface ProjectMeta {
|
|
47
|
+
id: string;
|
|
48
|
+
name: string;
|
|
49
|
+
saved_at: string;
|
|
50
|
+
size: number;
|
|
51
|
+
}
|
|
52
|
+
interface SyncDiff {
|
|
53
|
+
localOnly: Generation[];
|
|
54
|
+
serverOnly: Generation[];
|
|
55
|
+
}
|
|
56
|
+
interface LabFrame {
|
|
57
|
+
id: string;
|
|
58
|
+
base64: string;
|
|
59
|
+
mediaId?: string;
|
|
60
|
+
seed?: number;
|
|
61
|
+
model?: string;
|
|
62
|
+
aspectRatio?: string;
|
|
63
|
+
width?: number;
|
|
64
|
+
height?: number;
|
|
65
|
+
source?: 'generated' | 'flow-gallery' | 'zip-import' | 'db-library';
|
|
66
|
+
}
|
|
67
|
+
interface LabItem {
|
|
68
|
+
id: string;
|
|
69
|
+
prompt: string;
|
|
70
|
+
label?: string;
|
|
71
|
+
tags?: string[];
|
|
72
|
+
frames: LabFrame[];
|
|
73
|
+
}
|
|
74
|
+
interface SelectedLabImage {
|
|
75
|
+
item: LabItem;
|
|
76
|
+
frame: LabFrame;
|
|
77
|
+
label: string;
|
|
78
|
+
roleForPrompt?: string;
|
|
79
|
+
roleForImage?: string;
|
|
80
|
+
sendToPromptAI: boolean;
|
|
81
|
+
sendToImageGen: boolean;
|
|
82
|
+
}
|
|
83
|
+
interface LabServices {
|
|
84
|
+
availableItems: LabItem[];
|
|
85
|
+
recentItems: LabItem[];
|
|
86
|
+
onItemUsed: (item: LabItem) => void;
|
|
87
|
+
generateText: (text: string, options?: {
|
|
88
|
+
images?: {
|
|
89
|
+
base64: string;
|
|
90
|
+
mimeType: string;
|
|
91
|
+
}[];
|
|
92
|
+
systemInstruction?: string;
|
|
93
|
+
}) => Promise<string>;
|
|
94
|
+
generateImage: (options: Record<string, any>) => Promise<{
|
|
95
|
+
base64: string;
|
|
96
|
+
mediaId?: string;
|
|
97
|
+
}>;
|
|
98
|
+
saveResult?: (item: LabItem) => Promise<void>;
|
|
99
|
+
workspaceTags?: WorkspaceTags;
|
|
100
|
+
}
|
|
101
|
+
interface HFMetadataEntry {
|
|
102
|
+
id: string;
|
|
103
|
+
prompt?: string;
|
|
104
|
+
seed?: number;
|
|
105
|
+
model?: string;
|
|
106
|
+
tags: string[];
|
|
107
|
+
timestamp: number;
|
|
108
|
+
mimeType: string;
|
|
109
|
+
size?: number;
|
|
110
|
+
filename?: string;
|
|
111
|
+
hasThumb?: boolean;
|
|
112
|
+
titleTs?: number;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
declare function buildGenerationPrompt(hierarchyText: string, mode?: 'literal' | 'creative'): string;
|
|
116
|
+
declare function buildFallbackPrompt(hierarchyText: string): string;
|
|
117
|
+
declare function cleanAiResponse(text: string): string;
|
|
118
|
+
declare function buildImageGenerationOptions(prompt: string, aspectRatio: string, model: string, referenceMediaId?: string): Record<string, any>;
|
|
119
|
+
interface SelectedTag {
|
|
120
|
+
label: string;
|
|
121
|
+
value: string;
|
|
122
|
+
category: string;
|
|
123
|
+
}
|
|
124
|
+
declare function buildPromptTabPayload(selectedTags: SelectedTag[], instructions: string, rules: string, treeText?: string): string;
|
|
125
|
+
declare function parsePromptResponse(raw: string): {
|
|
126
|
+
prompt: string;
|
|
127
|
+
feedback: string | null;
|
|
128
|
+
};
|
|
129
|
+
interface FlowSdkImage {
|
|
130
|
+
base64: string;
|
|
131
|
+
mimeType: string;
|
|
132
|
+
}
|
|
133
|
+
interface FlowTextGenerationOptions {
|
|
134
|
+
images?: FlowSdkImage[];
|
|
135
|
+
systemInstruction?: string;
|
|
136
|
+
responseFormat?: 'text' | 'json';
|
|
137
|
+
thinkingLevel?: 'low' | 'medium' | 'high';
|
|
138
|
+
}
|
|
139
|
+
interface FlowSdk {
|
|
140
|
+
generate: {
|
|
141
|
+
image: (options: Record<string, any>) => Promise<{
|
|
142
|
+
base64: string;
|
|
143
|
+
mediaId: string;
|
|
144
|
+
}>;
|
|
145
|
+
text: (prompt: string, options?: {
|
|
146
|
+
systemInstruction?: string;
|
|
147
|
+
thinkingLevel?: string;
|
|
148
|
+
images?: FlowSdkImage[];
|
|
149
|
+
}) => Promise<{
|
|
150
|
+
text: string;
|
|
151
|
+
}>;
|
|
152
|
+
};
|
|
153
|
+
download: (args: {
|
|
154
|
+
base64: string;
|
|
155
|
+
mimeType: string;
|
|
156
|
+
filename: string;
|
|
157
|
+
}) => Promise<void>;
|
|
158
|
+
media: {
|
|
159
|
+
selectMultiple: (args: {
|
|
160
|
+
filter: string;
|
|
161
|
+
}) => Promise<any[]>;
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
declare function createFlowServices(Flow: FlowSdk): {
|
|
165
|
+
generateImage: (options: Record<string, any>) => Promise<{
|
|
166
|
+
base64: string;
|
|
167
|
+
mediaId: string;
|
|
168
|
+
}>;
|
|
169
|
+
generateText: (text: string, options?: FlowTextGenerationOptions) => Promise<string>;
|
|
170
|
+
};
|
|
171
|
+
declare function interpretSdkError(err: any): Error;
|
|
172
|
+
|
|
173
|
+
type FlowGenerateText = (prompt: string, options?: FlowTextGenerationOptions) => Promise<string>;
|
|
174
|
+
interface CreateFlowTextGenerationPortOptions {
|
|
175
|
+
provider?: string;
|
|
176
|
+
modelId?: string;
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Adapts the existing Flow SDK service to the host-neutral Szenen contract.
|
|
180
|
+
* It deliberately does not parse or validate the response: that happens once
|
|
181
|
+
* in `runPromptDerivation`, identically for every host.
|
|
182
|
+
*/
|
|
183
|
+
declare function createFlowTextGenerationPort(generateText: FlowGenerateText, options?: CreateFlowTextGenerationPortOptions): TextGenerationPort;
|
|
184
|
+
|
|
185
|
+
interface HFEventVersion {
|
|
186
|
+
major: number;
|
|
187
|
+
minor: number;
|
|
188
|
+
}
|
|
189
|
+
interface HFEvent<P = unknown> {
|
|
190
|
+
v: HFEventVersion;
|
|
191
|
+
type: string;
|
|
192
|
+
ts: number;
|
|
193
|
+
prevTs: number[];
|
|
194
|
+
clientId: string;
|
|
195
|
+
payload: P;
|
|
196
|
+
}
|
|
197
|
+
interface HFStateMeta {
|
|
198
|
+
consolidatedAt: number;
|
|
199
|
+
version: number;
|
|
200
|
+
}
|
|
201
|
+
interface HFStateSnapshot {
|
|
202
|
+
metadata: HFMetadataEntry[];
|
|
203
|
+
tags: WorkspaceTags;
|
|
204
|
+
meta: HFStateMeta;
|
|
205
|
+
openTasks?: Record<string, TaskRequestedPayload>;
|
|
206
|
+
}
|
|
207
|
+
interface HFFileInfo {
|
|
208
|
+
type: 'file' | 'directory';
|
|
209
|
+
path: string;
|
|
210
|
+
size: number;
|
|
211
|
+
}
|
|
212
|
+
interface ImageAddedPayload extends HFMetadataEntry {
|
|
213
|
+
taskId?: string;
|
|
214
|
+
}
|
|
215
|
+
interface TagUpsertedPayload {
|
|
216
|
+
category: string;
|
|
217
|
+
label: string;
|
|
218
|
+
value: string;
|
|
219
|
+
is_user_created?: boolean;
|
|
220
|
+
is_deleted?: boolean;
|
|
221
|
+
}
|
|
222
|
+
interface MetadataUpdatedPayload {
|
|
223
|
+
id: string;
|
|
224
|
+
delta: Partial<HFMetadataEntry>;
|
|
225
|
+
}
|
|
226
|
+
interface TaskRequestedPayload {
|
|
227
|
+
taskId: string;
|
|
228
|
+
taskType: string;
|
|
229
|
+
params: {
|
|
230
|
+
prompt: string;
|
|
231
|
+
tags?: string[];
|
|
232
|
+
book?: string;
|
|
233
|
+
kapitel?: string;
|
|
234
|
+
ankerId?: string;
|
|
235
|
+
promptVersion?: number;
|
|
236
|
+
[key: string]: any;
|
|
237
|
+
};
|
|
238
|
+
expiresAt?: number;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
export { type CreateFlowTextGenerationPortOptions as C, type FlowGenerateText as F, type Generation as G, type HFEvent as H, type ImageAddedPayload as I, type LabFrame as L, type MetadataUpdatedPayload as M, type ProjectMeta as P, type SelectedLabImage as S, type TagOption as T, type WorkspaceTags as W, type FlowSdk as a, type FlowTextGenerationOptions as b, type HFEventVersion as c, type HFFileInfo as d, type HFMetadataEntry as e, type HFStateMeta as f, type HFStateSnapshot as g, type LabItem as h, type LabServices as i, type ProjectSettings as j, type SelectedTag as k, type SyncDiff as l, type TagUpsertedPayload as m, buildFallbackPrompt as n, buildGenerationPrompt as o, buildImageGenerationOptions as p, buildPromptTabPayload as q, cleanAiResponse as r, createFlowServices as s, createFlowTextGenerationPort as t, interpretSdkError as u, parsePromptResponse as v };
|