@rslsp1/fa-app-tools 7.2.0 → 7.4.0
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-5QA6DTJ6.mjs → chunk-HUGUH4VB.mjs} +597 -46
- package/dist/index.d.mts +26 -4
- package/dist/index.d.ts +26 -4
- package/dist/index.js +548 -47
- package/dist/index.mjs +2 -2
- package/dist/szenen.d.mts +485 -2
- package/dist/szenen.d.ts +485 -2
- package/dist/szenen.js +760 -68
- package/dist/szenen.mjs +142 -1
- package/package.json +6 -2
package/dist/index.js
CHANGED
|
@@ -132,7 +132,7 @@ __export(index_exports, {
|
|
|
132
132
|
module.exports = __toCommonJS(index_exports);
|
|
133
133
|
|
|
134
134
|
// package.json
|
|
135
|
-
var version = "7.
|
|
135
|
+
var version = "7.4.0";
|
|
136
136
|
|
|
137
137
|
// src/hooks/useOnClickOutside.ts
|
|
138
138
|
var import_react = require("react");
|
|
@@ -2495,9 +2495,9 @@ function mergeSnapshotAndPending(snapshot, pending, bereitsImSnapshot = 0) {
|
|
|
2495
2495
|
}
|
|
2496
2496
|
|
|
2497
2497
|
// src/lib/hfEventLog.ts
|
|
2498
|
-
function treeUrl(namespace, subdir = "") {
|
|
2498
|
+
function treeUrl(namespace, subdir = "", revision = "main") {
|
|
2499
2499
|
const parts = [namespace.replace(/\/$/, ""), subdir].filter(Boolean).join("/");
|
|
2500
|
-
return `${HF_BASE}/api/datasets/${HF_REPO}/tree
|
|
2500
|
+
return `${HF_BASE}/api/datasets/${HF_REPO}/tree/${encodeURIComponent(revision)}${parts ? "/" + parts : ""}`;
|
|
2501
2501
|
}
|
|
2502
2502
|
var DROSSEL_VERSUCHE = 4;
|
|
2503
2503
|
var DROSSEL_BASIS_MS = 400;
|
|
@@ -2530,8 +2530,8 @@ async function mitGeduld(anfrage) {
|
|
|
2530
2530
|
}
|
|
2531
2531
|
return letzte;
|
|
2532
2532
|
}
|
|
2533
|
-
async function hfListDir(namespace, subdir, token) {
|
|
2534
|
-
const res = await mitGeduld(() => holeMitZeitlimit(treeUrl(namespace, subdir), {
|
|
2533
|
+
async function hfListDir(namespace, subdir, token, revision = "main") {
|
|
2534
|
+
const res = await mitGeduld(() => holeMitZeitlimit(treeUrl(namespace, subdir, revision), {
|
|
2535
2535
|
headers: { Authorization: `Bearer ${token}` }
|
|
2536
2536
|
}));
|
|
2537
2537
|
if (res.status === 404) return [];
|
|
@@ -2560,17 +2560,46 @@ function toBase64(text) {
|
|
|
2560
2560
|
bytes.forEach((b) => binary += String.fromCharCode(b));
|
|
2561
2561
|
return btoa(binary);
|
|
2562
2562
|
}
|
|
2563
|
-
|
|
2563
|
+
var HfPreconditionFailedError = class extends Error {
|
|
2564
|
+
constructor(message) {
|
|
2565
|
+
super(message);
|
|
2566
|
+
this.name = "HfPreconditionFailed";
|
|
2567
|
+
}
|
|
2568
|
+
};
|
|
2569
|
+
async function hfRepoHead(token, revision = "main") {
|
|
2570
|
+
const res = await mitGeduld(() => holeMitZeitlimit(
|
|
2571
|
+
`${HF_BASE}/api/datasets/${HF_REPO}/revision/${encodeURIComponent(revision)}`,
|
|
2572
|
+
{ headers: { Authorization: `Bearer ${token}` } }
|
|
2573
|
+
));
|
|
2574
|
+
if (!res.ok) {
|
|
2575
|
+
throw new Error(`HF revision failed: ${res.status} ${res.statusText} (${revision})`);
|
|
2576
|
+
}
|
|
2577
|
+
const daten = await res.json();
|
|
2578
|
+
if (typeof daten.sha !== "string" || daten.sha.length === 0) {
|
|
2579
|
+
throw new Error(
|
|
2580
|
+
`HF revision ${revision}: die Antwort traegt kein "sha". Erhaltene Felder: ${Object.keys(daten || {}).join(", ") || "(keine)"}.`
|
|
2581
|
+
);
|
|
2582
|
+
}
|
|
2583
|
+
return daten.sha;
|
|
2584
|
+
}
|
|
2585
|
+
async function hfUploadSmallFile(repoPath, content, token, summary = `Update ${repoPath}`, options) {
|
|
2586
|
+
const kopf = { summary, description: "" };
|
|
2587
|
+
if (options?.parentCommit) kopf.parentCommit = options.parentCommit;
|
|
2564
2588
|
const res = await fetch(`${HF_BASE}/api/datasets/${HF_REPO}/commit/main`, {
|
|
2565
2589
|
method: "POST",
|
|
2566
2590
|
headers: { Authorization: `Bearer ${token}`, "Content-Type": "application/x-ndjson" },
|
|
2567
2591
|
body: [
|
|
2568
|
-
JSON.stringify({ key: "header", value:
|
|
2592
|
+
JSON.stringify({ key: "header", value: kopf }),
|
|
2569
2593
|
JSON.stringify({ key: "file", value: { path: repoPath, encoding: "base64", content: toBase64(content) } })
|
|
2570
2594
|
].join("\n")
|
|
2571
2595
|
});
|
|
2572
2596
|
if (!res.ok) {
|
|
2573
2597
|
const err = await res.text().catch(() => "");
|
|
2598
|
+
if (options?.parentCommit && (res.status === 412 || res.status === 409)) {
|
|
2599
|
+
throw new HfPreconditionFailedError(
|
|
2600
|
+
`HF commit abgelehnt: Der Branch hat sich seit ${options.parentCommit} bewegt (${res.status}). Es wurde nichts geschrieben.`
|
|
2601
|
+
);
|
|
2602
|
+
}
|
|
2574
2603
|
throw new Error(`HF upload failed: ${res.status} \u2014 ${err.slice(0, 200)}`);
|
|
2575
2604
|
}
|
|
2576
2605
|
}
|
|
@@ -2620,8 +2649,8 @@ async function mitBegrenzterParallelitaet(count, limit, task) {
|
|
|
2620
2649
|
await Promise.all(Array.from({ length: Math.min(limit, count) }, worker));
|
|
2621
2650
|
if (fehlerAufgetreten) throw ersterFehler;
|
|
2622
2651
|
}
|
|
2623
|
-
async function loadPendingEvents(namespace, token, sinceTs, knownPaths) {
|
|
2624
|
-
const files = await hfListDir(namespace, "events", token);
|
|
2652
|
+
async function loadPendingEvents(namespace, token, sinceTs, knownPaths, revision = "main") {
|
|
2653
|
+
const files = await hfListDir(namespace, "events", token, revision);
|
|
2625
2654
|
const pending = files.filter((f) => f.type === "file" && tsFromEventPath(f.path) > sinceTs && !knownPaths?.has(f.path)).sort((a, b) => a.path.localeCompare(b.path));
|
|
2626
2655
|
if (!pending.length) return [];
|
|
2627
2656
|
const raw = new Array(pending.length);
|
|
@@ -2666,7 +2695,13 @@ async function writeHFEvent(namespace, token, type, payload, prevTs, options) {
|
|
|
2666
2695
|
const suffix = options?.ordered ? `${String(++writeSeq % 1e6).padStart(6, "0")}${uuid}` : uuid;
|
|
2667
2696
|
const filename = `${tsToFilename(ts)}_${suffix}.json`;
|
|
2668
2697
|
const repoPath = `${namespace}events/${filename}`;
|
|
2669
|
-
await hfUploadSmallFile(
|
|
2698
|
+
await hfUploadSmallFile(
|
|
2699
|
+
repoPath,
|
|
2700
|
+
JSON.stringify(event, null, 2),
|
|
2701
|
+
token,
|
|
2702
|
+
`Event: ${type}`,
|
|
2703
|
+
options?.parentCommit ? { parentCommit: options.parentCommit } : void 0
|
|
2704
|
+
);
|
|
2670
2705
|
return event;
|
|
2671
2706
|
}
|
|
2672
2707
|
|
|
@@ -6018,7 +6053,8 @@ function capabilitiesOf(port) {
|
|
|
6018
6053
|
imageBatchHistory: typeof port.imageBatchHistory?.listBatchesForPromptRun === "function",
|
|
6019
6054
|
imageOrderHistory: typeof port.imageBatchHistory?.listOrdersForPromptRun === "function",
|
|
6020
6055
|
imageBatchWrite: typeof port.imageBatchWrite?.importBatch === "function",
|
|
6021
|
-
imageGeneration: typeof port.imageGeneration?.startFromPromptRun === "function"
|
|
6056
|
+
imageGeneration: typeof port.imageGeneration?.startFromPromptRun === "function",
|
|
6057
|
+
imageJobs: typeof port.imageJobs?.claimAndRun === "function"
|
|
6022
6058
|
};
|
|
6023
6059
|
}
|
|
6024
6060
|
async function callOptional(capability, operation) {
|
|
@@ -9165,13 +9201,13 @@ function noticeFor(ergebnis, was) {
|
|
|
9165
9201
|
};
|
|
9166
9202
|
}
|
|
9167
9203
|
case "rejected": {
|
|
9168
|
-
const
|
|
9204
|
+
const fehler5 = ergebnis.errors ?? [];
|
|
9169
9205
|
const ungeprueft = ergebnis.unchecked ?? [];
|
|
9170
9206
|
return {
|
|
9171
9207
|
tone: "rejected",
|
|
9172
|
-
text: `${was}: abgelehnt \u2014 ${
|
|
9208
|
+
text: `${was}: abgelehnt \u2014 ${fehler5.length} Befund${fehler5.length === 1 ? "" : "e"}.`,
|
|
9173
9209
|
details: [
|
|
9174
|
-
...
|
|
9210
|
+
...fehler5.map((f) => `${f.path ?? "(ohne Pfad)"}: ${f.message ?? "ohne Meldung"}`),
|
|
9175
9211
|
// Nicht verschweigen: was nicht geprüft wurde, ist nicht in Ordnung,
|
|
9176
9212
|
// sondern ungeprüft.
|
|
9177
9213
|
...ungeprueft.map((u) => `ungepr\xFCft: ${u}`)
|
|
@@ -12671,7 +12707,7 @@ var ERKLAERUNG = {
|
|
|
12671
12707
|
};
|
|
12672
12708
|
var CapabilityPanel = ({ port, elementId, setupPayload }) => {
|
|
12673
12709
|
const [bericht, setBericht] = (0, import_react37.useState)(null);
|
|
12674
|
-
const [
|
|
12710
|
+
const [fehler5, setFehler] = (0, import_react37.useState)(null);
|
|
12675
12711
|
(0, import_react37.useEffect)(() => {
|
|
12676
12712
|
let abgemeldet = false;
|
|
12677
12713
|
setBericht(null);
|
|
@@ -12693,10 +12729,10 @@ var CapabilityPanel = ({ port, elementId, setupPayload }) => {
|
|
|
12693
12729
|
abgemeldet = true;
|
|
12694
12730
|
};
|
|
12695
12731
|
}, [port, elementId, setupPayload]);
|
|
12696
|
-
if (
|
|
12732
|
+
if (fehler5) {
|
|
12697
12733
|
return /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("p", { "data-testid": "capability-fehler", role: "alert", children: [
|
|
12698
12734
|
"F\xE4higkeitsbericht nicht erstellbar: ",
|
|
12699
|
-
|
|
12735
|
+
fehler5
|
|
12700
12736
|
] });
|
|
12701
12737
|
}
|
|
12702
12738
|
if (!bericht) return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("p", { "data-testid": "capability-laden", children: "F\xE4higkeitsbericht wird erstellt \u2026" });
|
|
@@ -13063,7 +13099,60 @@ var SZENEN_EVENT_TYPES = {
|
|
|
13063
13099
|
* Der Elementreducer ignoriert auch diesen Typ (`default:`-Zweig); gelesen
|
|
13064
13100
|
* wird mit `collectImageBatches` (`imageBatchStore.ts`).
|
|
13065
13101
|
*/
|
|
13066
|
-
imageBatchPersisted: "szenen.image_batch_persisted"
|
|
13102
|
+
imageBatchPersisted: "szenen.image_batch_persisted",
|
|
13103
|
+
/**
|
|
13104
|
+
* Ein vorbereiteter Promptvorgang — der Durchstich „Szene → ChatGPT → Lauf".
|
|
13105
|
+
*
|
|
13106
|
+
* Der bestehende Promptpfad ruft das Modell selbst
|
|
13107
|
+
* (`runPromptDerivation()`); ein aufrufendes Chatmodell formuliert dagegen
|
|
13108
|
+
* **zwischen** zwei Werkzeugaufrufen. Damit zerfaellt der eine Vorgang in
|
|
13109
|
+
* zwei, und der zweite braucht genau den Stand, den der erste eingefroren
|
|
13110
|
+
* hat — sonst loeste der Abschluss die inzwischen geaenderte Szene neu auf
|
|
13111
|
+
* und der Lauf behauptete eine Herkunft, die er nicht hat (D-22).
|
|
13112
|
+
*
|
|
13113
|
+
* Deshalb ein eigenes Ereignis und **kein** fluechtiger Prozesszustand: Der
|
|
13114
|
+
* Snapshot ueberlebt Neustart, Hostwechsel und Sitzungsende, weil er im
|
|
13115
|
+
* selben autoritativen Log liegt wie der Lauf, der daraus entsteht.
|
|
13116
|
+
*
|
|
13117
|
+
* Der Elementreducer ignoriert diesen Typ (`default:`-Zweig); gelesen wird
|
|
13118
|
+
* mit `collectPromptOperations` (`scenePromptOperation.ts`).
|
|
13119
|
+
*/
|
|
13120
|
+
promptOperationPrepared: "szenen.prompt_operation_prepared",
|
|
13121
|
+
/**
|
|
13122
|
+
* Ein Bildauftrag wartet auf einen ausfuehrenden Flow-Host.
|
|
13123
|
+
*
|
|
13124
|
+
* Die vorhandene Auftragshistorie (`imageGenerationStarted`) beginnt
|
|
13125
|
+
* **unmittelbar vor** dem Provideraufruf und kennt deshalb keinen wartenden
|
|
13126
|
+
* Auftrag. Genau der entsteht hier: Ein Chatmodell beauftragt ueber MCP ein
|
|
13127
|
+
* Bild, der Auftrag wird dauerhaft abgelegt, und der Werkzeugaufruf endet
|
|
13128
|
+
* sofort mit seiner Kennung — er haelt keine Antwort minutenlang offen.
|
|
13129
|
+
*
|
|
13130
|
+
* Traegt **keinen** Prompt: Der steht im referenzierten Lauf, und ihn hier
|
|
13131
|
+
* zu kopieren waere eine zweite Wahrheit ueber denselben eingefrorenen Text
|
|
13132
|
+
* (D-103).
|
|
13133
|
+
*/
|
|
13134
|
+
imageJobRequested: "szenen.image_job_requested",
|
|
13135
|
+
/**
|
|
13136
|
+
* Ein Flow-Host beansprucht einen wartenden Bildauftrag.
|
|
13137
|
+
*
|
|
13138
|
+
* Ein append-only Log kennt kein Lock: Zwei Tabs koennen beide anhaengen.
|
|
13139
|
+
* Deshalb ist die Uebernahme **nicht** der Append, sondern das Ergebnis
|
|
13140
|
+
* einer deterministischen Schiedsregel darueber (`winningClaimOf`) — der
|
|
13141
|
+
* erste Anspruch in Logreihenfolge gewinnt, und jeder Host liest nach
|
|
13142
|
+
* seinem Append erneut, bevor er einen bezahlten Provideraufruf startet.
|
|
13143
|
+
* Ein unterlegener Anspruch bleibt sichtbar stehen; er wird nicht geloescht,
|
|
13144
|
+
* weil das Log das nicht kann und weil der Versuch ein Beleg ist.
|
|
13145
|
+
*/
|
|
13146
|
+
imageJobClaimed: "szenen.image_job_claimed",
|
|
13147
|
+
/**
|
|
13148
|
+
* Der Bildauftrag ist erledigt — mit dem Ausgang, den der Host gesehen hat.
|
|
13149
|
+
*
|
|
13150
|
+
* Getrennt von `imageGenerationFinished`: Jenes gehoert zum bezahlten
|
|
13151
|
+
* Provideraufruf, dieses zur Zustellung. Ein Auftrag kann fehlschlagen,
|
|
13152
|
+
* **bevor** ein Provider gerufen wurde (abgelehntes Profil), und dann gibt
|
|
13153
|
+
* es kein `imageGenerationFinished`, das den Wartenden erloesen wuerde.
|
|
13154
|
+
*/
|
|
13155
|
+
imageJobSettled: "szenen.image_job_settled"
|
|
13067
13156
|
};
|
|
13068
13157
|
function sortForReplay(events) {
|
|
13069
13158
|
return [...events].sort((a, b) => {
|
|
@@ -13416,9 +13505,9 @@ async function leseBilderAusZip(datei) {
|
|
|
13416
13505
|
);
|
|
13417
13506
|
}
|
|
13418
13507
|
const { default: JSZip3 } = await import("jszip");
|
|
13419
|
-
const archiv = await JSZip3.loadAsync(datei).catch((
|
|
13508
|
+
const archiv = await JSZip3.loadAsync(datei).catch((fehler5) => {
|
|
13420
13509
|
throw new Error(
|
|
13421
|
-
`${name} konnte nicht als ZIP gelesen werden: ${
|
|
13510
|
+
`${name} konnte nicht als ZIP gelesen werden: ${fehler5 instanceof Error ? fehler5.message : String(fehler5)}`
|
|
13422
13511
|
);
|
|
13423
13512
|
});
|
|
13424
13513
|
const pfade = [];
|
|
@@ -13615,6 +13704,7 @@ var RunImagesPanel = ({ port, lauf }) => {
|
|
|
13615
13704
|
const neuLesen = () => setNachladen((n) => n + 1);
|
|
13616
13705
|
const [erzeugenOffen, setErzeugenOffen] = (0, import_react40.useState)(null);
|
|
13617
13706
|
const [zuordnenOffen, setZuordnenOffen] = (0, import_react40.useState)(null);
|
|
13707
|
+
const [chatAuftraegeOffen, setChatAuftraegeOffen] = (0, import_react40.useState)(null);
|
|
13618
13708
|
const quelle = sourceOf(lauf);
|
|
13619
13709
|
const [wahlPhase] = usePortQuery(
|
|
13620
13710
|
() => port.imageGeneration ? port.imageGeneration.imageModelChoiceForRun(lauf.run_id) : Promise.resolve({ kind: "ok", value: null }),
|
|
@@ -13629,10 +13719,17 @@ var RunImagesPanel = ({ port, lauf }) => {
|
|
|
13629
13719
|
() => port.imageBatchHistory ? port.imageBatchHistory.listBatchesForPromptRun(lauf.run_id) : Promise.resolve({ kind: "ok", value: [] }),
|
|
13630
13720
|
[port, lauf.run_id, nachladen]
|
|
13631
13721
|
);
|
|
13722
|
+
const [chatAuftraegePhase] = usePortQuery(
|
|
13723
|
+
() => port.imageJobs ? port.imageJobs.listJobs(lauf.run_id) : Promise.resolve({ kind: "ok", value: [] }),
|
|
13724
|
+
[port, lauf.run_id, nachladen]
|
|
13725
|
+
);
|
|
13632
13726
|
const auftraege = auftraegePhase.status === "ready" ? auftraegePhase.value : [];
|
|
13633
13727
|
const batches = batchesPhase.status === "ready" ? batchesPhase.value : [];
|
|
13728
|
+
const chatAuftraege = chatAuftraegePhase.status === "ready" ? chatAuftraegePhase.value : [];
|
|
13729
|
+
const offeneChatAuftraege = chatAuftraege.filter((a) => a.status === "pending").length;
|
|
13634
13730
|
const auffaellige = auftraege.filter((a) => a.status !== "succeeded");
|
|
13635
13731
|
const erzeugenAuf = erzeugenOffen ?? batches.length === 0;
|
|
13732
|
+
const chatAuftraegeAuf = chatAuftraegeOffen ?? offeneChatAuftraege > 0;
|
|
13636
13733
|
return /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("div", { className: "szenen-bilder", "data-testid": `bilder-${lauf.run_id}`, children: [
|
|
13637
13734
|
/* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("section", { className: "szenen-bilder__eingang", "data-testid": `eingang-${lauf.run_id}`, children: [
|
|
13638
13735
|
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)("h5", { children: "Eingang \u2014 woraus dieser Prompt entstand" }),
|
|
@@ -13753,6 +13850,43 @@ var RunImagesPanel = ({ port, lauf }) => {
|
|
|
13753
13850
|
}
|
|
13754
13851
|
)
|
|
13755
13852
|
] }),
|
|
13853
|
+
faehig.imageJobs && /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(
|
|
13854
|
+
"details",
|
|
13855
|
+
{
|
|
13856
|
+
className: "szenen-bilder__aktion",
|
|
13857
|
+
"data-testid": `auftraege-chat-bereich-${lauf.run_id}`,
|
|
13858
|
+
open: chatAuftraegeAuf,
|
|
13859
|
+
children: [
|
|
13860
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(
|
|
13861
|
+
"summary",
|
|
13862
|
+
{
|
|
13863
|
+
onClick: (e) => {
|
|
13864
|
+
e.preventDefault();
|
|
13865
|
+
setChatAuftraegeOffen(!chatAuftraegeAuf);
|
|
13866
|
+
},
|
|
13867
|
+
children: [
|
|
13868
|
+
"Bildauftraege aus dem Chat",
|
|
13869
|
+
offeneChatAuftraege > 0 ? ` (${offeneChatAuftraege} wartend)` : ""
|
|
13870
|
+
]
|
|
13871
|
+
}
|
|
13872
|
+
),
|
|
13873
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
13874
|
+
ChatAuftraegeAktion,
|
|
13875
|
+
{
|
|
13876
|
+
port,
|
|
13877
|
+
lauf,
|
|
13878
|
+
auftraege: chatAuftraege,
|
|
13879
|
+
fehler: chatAuftraegePhase.status === "error" ? chatAuftraegePhase.message : null,
|
|
13880
|
+
laedt: chatAuftraegePhase.status === "loading",
|
|
13881
|
+
onFertig: () => {
|
|
13882
|
+
setChatAuftraegeOffen(true);
|
|
13883
|
+
neuLesen();
|
|
13884
|
+
}
|
|
13885
|
+
}
|
|
13886
|
+
)
|
|
13887
|
+
]
|
|
13888
|
+
}
|
|
13889
|
+
),
|
|
13756
13890
|
/* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(
|
|
13757
13891
|
"details",
|
|
13758
13892
|
{
|
|
@@ -13936,7 +14070,7 @@ function useBildQuellen(port, bilder) {
|
|
|
13936
14070
|
erneutVersuchen: () => setVersuch((n) => n + 1)
|
|
13937
14071
|
};
|
|
13938
14072
|
}
|
|
13939
|
-
var BildDetails = ({ bild, fehler:
|
|
14073
|
+
var BildDetails = ({ bild, fehler: fehler5, aufloesbar }) => /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("span", { className: "szenen-bilder__meta", "data-testid": `batchbild-${bild.media_ref}`, children: [
|
|
13940
14074
|
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)("code", { children: bild.media_ref }),
|
|
13941
14075
|
/* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("span", { children: [
|
|
13942
14076
|
"Position ",
|
|
@@ -13949,7 +14083,7 @@ var BildDetails = ({ bild, fehler: fehler4, aufloesbar }) => /* @__PURE__ */ (0,
|
|
|
13949
14083
|
"\xD7",
|
|
13950
14084
|
bild.height
|
|
13951
14085
|
] }) : null,
|
|
13952
|
-
|
|
14086
|
+
fehler5 && /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("em", { "data-testid": `batchbild-fehler-${bild.media_ref}`, children: fehler5 }),
|
|
13953
14087
|
!aufloesbar && // Capability-Grenze, kein Fehler: Dieser Host kann Batches lesen,
|
|
13954
14088
|
// aber keine Bilder auflösen (E). Kein erfundener Fallback auf eine
|
|
13955
14089
|
// Serverroute (A6).
|
|
@@ -13965,18 +14099,18 @@ var HERKUNFT_KURZ = {
|
|
|
13965
14099
|
external_import: "extern importiert"
|
|
13966
14100
|
};
|
|
13967
14101
|
var BatchKachel = ({ port, batch }) => {
|
|
13968
|
-
const { quellen, fehler:
|
|
14102
|
+
const { quellen, fehler: fehler5, wiederholbar, erneutVersuchen } = useBildQuellen(port, batch.images);
|
|
13969
14103
|
const aufloesbar = Boolean(port.imageLibrary);
|
|
13970
14104
|
const bilder = batch.images.map((bild) => ({
|
|
13971
14105
|
id: bild.media_ref,
|
|
13972
14106
|
quelle: quellen.get(bild.media_ref) ?? null,
|
|
13973
14107
|
titel: `Bild ${bild.position + 1}`,
|
|
13974
|
-
...
|
|
14108
|
+
...fehler5.get(bild.media_ref) ? { leerText: "Nicht ladbar" } : {},
|
|
13975
14109
|
details: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
13976
14110
|
BildDetails,
|
|
13977
14111
|
{
|
|
13978
14112
|
bild,
|
|
13979
|
-
fehler:
|
|
14113
|
+
fehler: fehler5.get(bild.media_ref) ?? null,
|
|
13980
14114
|
aufloesbar
|
|
13981
14115
|
}
|
|
13982
14116
|
)
|
|
@@ -14036,7 +14170,7 @@ var BatchKachel = ({ port, batch }) => {
|
|
|
14036
14170
|
BildDetails,
|
|
14037
14171
|
{
|
|
14038
14172
|
bild,
|
|
14039
|
-
fehler:
|
|
14173
|
+
fehler: fehler5.get(bild.media_ref) ?? null,
|
|
14040
14174
|
aufloesbar
|
|
14041
14175
|
}
|
|
14042
14176
|
) }, bild.media_ref)) })
|
|
@@ -14305,11 +14439,11 @@ var ZuordnenAktion = ({ port, lauf, onFertig }) => {
|
|
|
14305
14439
|
setSeedListe(DEFAULT_SEED_VORLAGE.seeds);
|
|
14306
14440
|
setVorlageKey(DEFAULT_VORLAGE_KEY);
|
|
14307
14441
|
}
|
|
14308
|
-
} catch (
|
|
14442
|
+
} catch (fehler5) {
|
|
14309
14443
|
if (veraltet()) return;
|
|
14310
14444
|
setNotiz({
|
|
14311
14445
|
tone: "error",
|
|
14312
|
-
text:
|
|
14446
|
+
text: fehler5 instanceof Error ? fehler5.message : String(fehler5)
|
|
14313
14447
|
});
|
|
14314
14448
|
}
|
|
14315
14449
|
if (veraltet()) return;
|
|
@@ -14328,10 +14462,10 @@ var ZuordnenAktion = ({ port, lauf, onFertig }) => {
|
|
|
14328
14462
|
setNotiz(
|
|
14329
14463
|
ergebnis.kind === "ok" ? { tone: "ok", text: `Importiert als Item ${ergebnis.value.item_id} mit ${bilder.length} Bild(ern).` } : noticeFor(ergebnis, "Externe Bilder importieren")
|
|
14330
14464
|
);
|
|
14331
|
-
} catch (
|
|
14465
|
+
} catch (fehler5) {
|
|
14332
14466
|
setNotiz({
|
|
14333
14467
|
tone: "error",
|
|
14334
|
-
text: `Externe Bilder importieren: ${
|
|
14468
|
+
text: `Externe Bilder importieren: ${fehler5 instanceof Error ? fehler5.message : String(fehler5)}`
|
|
14335
14469
|
});
|
|
14336
14470
|
}
|
|
14337
14471
|
setLaeuft(false);
|
|
@@ -14353,10 +14487,10 @@ var ZuordnenAktion = ({ port, lauf, onFertig }) => {
|
|
|
14353
14487
|
...seed !== void 0 ? { seed } : {}
|
|
14354
14488
|
});
|
|
14355
14489
|
}
|
|
14356
|
-
} catch (
|
|
14490
|
+
} catch (fehler5) {
|
|
14357
14491
|
setNotiz({
|
|
14358
14492
|
tone: "error",
|
|
14359
|
-
text: `Externe Bilder importieren: ${
|
|
14493
|
+
text: `Externe Bilder importieren: ${fehler5 instanceof Error ? fehler5.message : String(fehler5)}`
|
|
14360
14494
|
});
|
|
14361
14495
|
return;
|
|
14362
14496
|
}
|
|
@@ -14692,6 +14826,101 @@ function readAsBase64(datei) {
|
|
|
14692
14826
|
leser.readAsDataURL(datei);
|
|
14693
14827
|
});
|
|
14694
14828
|
}
|
|
14829
|
+
var CHAT_AUFTRAG_TEXT = {
|
|
14830
|
+
pending: "wartet auf \xDCbernahme",
|
|
14831
|
+
// Wie bei `started` (D-119): laufend und abgebrochen sind aus dem Log
|
|
14832
|
+
// nicht unterscheidbar, und es gibt keinen automatischen Retry, der die
|
|
14833
|
+
// Unterscheidung bräuchte.
|
|
14834
|
+
claimed: "\xFCbernommen (l\xE4uft oder unterbrochen)",
|
|
14835
|
+
succeeded: "erfolgreich",
|
|
14836
|
+
partial: "teilweise",
|
|
14837
|
+
failed: "fehlgeschlagen",
|
|
14838
|
+
rejected: "abgelehnt \u2014 es wurde nichts ausgef\xFChrt"
|
|
14839
|
+
};
|
|
14840
|
+
var ChatAuftraegeAktion = ({
|
|
14841
|
+
port,
|
|
14842
|
+
lauf,
|
|
14843
|
+
auftraege,
|
|
14844
|
+
fehler: fehler5,
|
|
14845
|
+
laedt,
|
|
14846
|
+
onFertig
|
|
14847
|
+
}) => {
|
|
14848
|
+
const [laufend, setLaufend] = (0, import_react40.useState)(null);
|
|
14849
|
+
const [notiz, setNotiz] = (0, import_react40.useState)(null);
|
|
14850
|
+
async function uebernehmen(jobId) {
|
|
14851
|
+
if (!port.imageJobs) return;
|
|
14852
|
+
setLaufend(jobId);
|
|
14853
|
+
setNotiz(null);
|
|
14854
|
+
try {
|
|
14855
|
+
const ergebnis = await port.imageJobs.claimAndRun(jobId);
|
|
14856
|
+
if (ergebnis.kind === "ok") {
|
|
14857
|
+
setNotiz({
|
|
14858
|
+
tone: ergebnis.job.status === "succeeded" ? "ok" : "rejected",
|
|
14859
|
+
text: `Auftrag ${jobId}: ${CHAT_AUFTRAG_TEXT[ergebnis.job.status]}.` + (ergebnis.job.diagnostic ? ` ${ergebnis.job.diagnostic}` : "")
|
|
14860
|
+
});
|
|
14861
|
+
} else if (ergebnis.kind === "lost") {
|
|
14862
|
+
setNotiz({ tone: "rejected", text: ergebnis.message });
|
|
14863
|
+
} else {
|
|
14864
|
+
setNotiz({ tone: "error", text: ergebnis.message });
|
|
14865
|
+
}
|
|
14866
|
+
} catch (e) {
|
|
14867
|
+
setNotiz({
|
|
14868
|
+
tone: "error",
|
|
14869
|
+
text: `Die \xDCbernahme von Auftrag ${jobId} ist technisch gescheitert: ` + (e instanceof Error ? e.message : String(e))
|
|
14870
|
+
});
|
|
14871
|
+
} finally {
|
|
14872
|
+
setLaufend(null);
|
|
14873
|
+
onFertig();
|
|
14874
|
+
}
|
|
14875
|
+
}
|
|
14876
|
+
return /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("div", { className: "szenen-bilder__aktion-inhalt", "data-testid": `chat-auftraege-${lauf.run_id}`, children: [
|
|
14877
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)("p", { className: "szenen-area__lead", children: "Auftr\xE4ge, die \xFCber den MCP aus dem Chat kamen. Der Prompt wird nicht kopiert \u2014 ausgef\xFChrt wird der eingefrorene Prompt dieses Laufs." }),
|
|
14878
|
+
fehler5 && /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("p", { role: "alert", "data-testid": `chat-auftraege-fehler-${lauf.run_id}`, children: [
|
|
14879
|
+
"Bildauftr\xE4ge aus dem Chat konnten nicht gelesen werden: ",
|
|
14880
|
+
fehler5
|
|
14881
|
+
] }),
|
|
14882
|
+
!fehler5 && !laedt && auftraege.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("p", { "data-testid": `chat-auftraege-leer-${lauf.run_id}`, children: "F\xFCr diesen Lauf liegt kein Auftrag aus dem Chat vor." }),
|
|
14883
|
+
notiz && /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
14884
|
+
"p",
|
|
14885
|
+
{
|
|
14886
|
+
role: notiz.tone === "error" ? "alert" : void 0,
|
|
14887
|
+
"data-testid": `chat-auftraege-notiz-${lauf.run_id}`,
|
|
14888
|
+
children: notiz.text
|
|
14889
|
+
}
|
|
14890
|
+
),
|
|
14891
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)("ul", { className: "szenen-bilder__auftraege", children: auftraege.map((auftrag) => /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("li", { "data-testid": `chat-auftrag-${auftrag.job_id}`, children: [
|
|
14892
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)("span", { children: CHAT_AUFTRAG_TEXT[auftrag.status] }),
|
|
14893
|
+
" \u2014 ",
|
|
14894
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("span", { children: [
|
|
14895
|
+
auftrag.image_count,
|
|
14896
|
+
" ",
|
|
14897
|
+
auftrag.image_count === 1 ? "Bild" : "Bilder",
|
|
14898
|
+
" mit",
|
|
14899
|
+
" ",
|
|
14900
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)("code", { children: auftrag.execution_target_model_key }),
|
|
14901
|
+
" / ",
|
|
14902
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)("code", { children: auftrag.execution_profile_id }),
|
|
14903
|
+
auftrag.aspect_ratio ? ` im Format ${auftrag.aspect_ratio}` : ""
|
|
14904
|
+
] }),
|
|
14905
|
+
auftrag.diagnostic && /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("span", { children: [
|
|
14906
|
+
" ",
|
|
14907
|
+
auftrag.diagnostic
|
|
14908
|
+
] }),
|
|
14909
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)("br", {}),
|
|
14910
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)("code", { className: "szenen-bilder__auftragskennung", children: auftrag.job_id }),
|
|
14911
|
+
auftrag.status === "pending" && /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
14912
|
+
"button",
|
|
14913
|
+
{
|
|
14914
|
+
type: "button",
|
|
14915
|
+
disabled: laufend !== null,
|
|
14916
|
+
onClick: () => void uebernehmen(auftrag.job_id),
|
|
14917
|
+
"data-testid": `chat-auftrag-uebernehmen-${auftrag.job_id}`,
|
|
14918
|
+
children: laufend === auftrag.job_id ? "\xDCbernahme l\xE4uft\u2026" : "\xDCbernehmen und ausf\xFChren (kostet einen Bildaufruf)"
|
|
14919
|
+
}
|
|
14920
|
+
)
|
|
14921
|
+
] }, auftrag.job_id)) })
|
|
14922
|
+
] });
|
|
14923
|
+
};
|
|
14695
14924
|
|
|
14696
14925
|
// src/features/szenen/areas/RunsPanel.tsx
|
|
14697
14926
|
var import_jsx_runtime37 = require("react/jsx-runtime");
|
|
@@ -19253,7 +19482,7 @@ function createHfEventChannel(options) {
|
|
|
19253
19482
|
let syncInFlight = null;
|
|
19254
19483
|
let snapshot = null;
|
|
19255
19484
|
let snapshotGeladen = ohneSnapshot;
|
|
19256
|
-
const refresh = async () => {
|
|
19485
|
+
const refresh = async (revision = "main") => {
|
|
19257
19486
|
if (!snapshotGeladen) {
|
|
19258
19487
|
snapshot = await loadLatestSzenenSnapshot(namespace, token);
|
|
19259
19488
|
snapshotGeladen = true;
|
|
@@ -19261,7 +19490,7 @@ function createHfEventChannel(options) {
|
|
|
19261
19490
|
knownPaths.add(`${namespace}events/${name}`);
|
|
19262
19491
|
}
|
|
19263
19492
|
}
|
|
19264
|
-
const neue = await loadPendingEvents(namespace, token, sinceTs, knownPaths);
|
|
19493
|
+
const neue = await loadPendingEvents(namespace, token, sinceTs, knownPaths, revision);
|
|
19265
19494
|
if (neue.length) cachedRawEvents = [...cachedRawEvents, ...neue];
|
|
19266
19495
|
};
|
|
19267
19496
|
const sync = () => {
|
|
@@ -19272,16 +19501,34 @@ function createHfEventChannel(options) {
|
|
|
19272
19501
|
}
|
|
19273
19502
|
return syncInFlight;
|
|
19274
19503
|
};
|
|
19504
|
+
const sicht = () => {
|
|
19505
|
+
const pending = cachedRawEvents.filter((event) => typeof event.type === "string" && event.type.startsWith(SZENEN_EVENT_PREFIX)).map((event) => ({
|
|
19506
|
+
type: event.type,
|
|
19507
|
+
payload: event.payload,
|
|
19508
|
+
clientId: event.clientId,
|
|
19509
|
+
ts: event.ts
|
|
19510
|
+
}));
|
|
19511
|
+
return mergeSnapshotAndPending(snapshot, pending).events;
|
|
19512
|
+
};
|
|
19275
19513
|
return {
|
|
19276
19514
|
async readEvents() {
|
|
19277
19515
|
await sync();
|
|
19278
|
-
|
|
19279
|
-
|
|
19280
|
-
|
|
19281
|
-
|
|
19282
|
-
|
|
19283
|
-
|
|
19284
|
-
|
|
19516
|
+
return sicht();
|
|
19517
|
+
},
|
|
19518
|
+
async readHead() {
|
|
19519
|
+
return hfRepoHead(token);
|
|
19520
|
+
},
|
|
19521
|
+
async readEventsAt(revision) {
|
|
19522
|
+
await refresh(revision);
|
|
19523
|
+
return sicht();
|
|
19524
|
+
},
|
|
19525
|
+
async appendEventAt(type, payload, parentCommit) {
|
|
19526
|
+
if (!type.startsWith(SZENEN_EVENT_PREFIX)) {
|
|
19527
|
+
throw new Error(
|
|
19528
|
+
`Event-Typ "${type}" gehoert nicht zur Domain szenen. Der geteilte Kanal wird ueber das Praefix "${SZENEN_EVENT_PREFIX}" getrennt.`
|
|
19529
|
+
);
|
|
19530
|
+
}
|
|
19531
|
+
await writeHFEvent(namespace, token, type, payload, [], { ordered: true, parentCommit });
|
|
19285
19532
|
},
|
|
19286
19533
|
async appendEvent(type, payload) {
|
|
19287
19534
|
if (!type.startsWith(SZENEN_EVENT_PREFIX)) {
|
|
@@ -19465,11 +19712,11 @@ async function resolveShotPayload(input) {
|
|
|
19465
19712
|
};
|
|
19466
19713
|
}
|
|
19467
19714
|
const shot = shotPayload;
|
|
19468
|
-
for (const
|
|
19715
|
+
for (const fehler5 of ohneKettenReferenz(
|
|
19469
19716
|
validatePayload("shot", shotPayload).errors,
|
|
19470
19717
|
chain ? "scene_setup_ref" : null
|
|
19471
19718
|
)) {
|
|
19472
|
-
diagnostics.push(diagnosticOfSchemaError(
|
|
19719
|
+
diagnostics.push(diagnosticOfSchemaError(fehler5, `Shot ${shotElementId}`));
|
|
19473
19720
|
}
|
|
19474
19721
|
let setup = null;
|
|
19475
19722
|
let report = null;
|
|
@@ -19581,8 +19828,8 @@ async function resolveScenePayload(input) {
|
|
|
19581
19828
|
"Kein Scene Setup, kein Shot: Der Lauf entsteht aus der Szene allein. Bildaufbau, Kamera und Zielmodell wurden nicht ergaenzt, sondern sind nicht vorhanden (D-135)."
|
|
19582
19829
|
];
|
|
19583
19830
|
const diagnostics = [];
|
|
19584
|
-
for (const
|
|
19585
|
-
diagnostics.push(diagnosticOfSchemaError(
|
|
19831
|
+
for (const fehler5 of validatePayload("scene", scenePayload).errors) {
|
|
19832
|
+
diagnostics.push(diagnosticOfSchemaError(fehler5, `Szene ${sceneElementId}`));
|
|
19586
19833
|
}
|
|
19587
19834
|
const faehig = sceneOnlyCapabilities(scenePayload);
|
|
19588
19835
|
return komponiere({
|
|
@@ -21131,8 +21378,8 @@ function createFlowImageProvider(generateImage) {
|
|
|
21131
21378
|
// Kein Seed: weder als Eingabe dokumentiert noch als Ausgabe
|
|
21132
21379
|
// geliefert — nichts wird erfunden (D-107).
|
|
21133
21380
|
});
|
|
21134
|
-
} catch (
|
|
21135
|
-
ersterFehler =
|
|
21381
|
+
} catch (fehler5) {
|
|
21382
|
+
ersterFehler = fehler5 instanceof Error ? fehler5.message : String(fehler5);
|
|
21136
21383
|
break;
|
|
21137
21384
|
}
|
|
21138
21385
|
}
|
|
@@ -21658,6 +21905,249 @@ function createImageGenerationPort(options) {
|
|
|
21658
21905
|
};
|
|
21659
21906
|
}
|
|
21660
21907
|
|
|
21908
|
+
// src/lib/szenen/imageJobStore.ts
|
|
21909
|
+
var istText6 = (wert) => typeof wert === "string" && wert.trim().length > 0;
|
|
21910
|
+
var SETTLED_STATUS = ["succeeded", "partial", "failed", "rejected"];
|
|
21911
|
+
function collectImageJobs(events) {
|
|
21912
|
+
const nachId = /* @__PURE__ */ new Map();
|
|
21913
|
+
for (const event of events) {
|
|
21914
|
+
if (event.type !== SZENEN_EVENT_TYPES.imageJobRequested) continue;
|
|
21915
|
+
const payload = event.payload;
|
|
21916
|
+
if (!payload || !istText6(payload.job_id) || !istText6(payload.prompt_run_id)) continue;
|
|
21917
|
+
if (nachId.has(payload.job_id)) continue;
|
|
21918
|
+
nachId.set(payload.job_id, {
|
|
21919
|
+
job_id: payload.job_id,
|
|
21920
|
+
prompt_run_id: payload.prompt_run_id,
|
|
21921
|
+
execution_target_model_key: payload.execution_target_model_key ?? "",
|
|
21922
|
+
execution_profile_id: payload.execution_profile_id ?? "",
|
|
21923
|
+
image_count: typeof payload.image_count === "number" ? payload.image_count : 0,
|
|
21924
|
+
...payload.aspect_ratio ? { aspect_ratio: payload.aspect_ratio } : {},
|
|
21925
|
+
requested_by: payload.requested_by ?? "",
|
|
21926
|
+
store_id: payload.store_id ?? "",
|
|
21927
|
+
created_at: payload.created_at ?? "",
|
|
21928
|
+
status: "pending",
|
|
21929
|
+
claim_attempts: []
|
|
21930
|
+
});
|
|
21931
|
+
}
|
|
21932
|
+
for (const event of events) {
|
|
21933
|
+
if (event.type !== SZENEN_EVENT_TYPES.imageJobClaimed) continue;
|
|
21934
|
+
const payload = event.payload;
|
|
21935
|
+
if (!payload || !istText6(payload.job_id) || !istText6(payload.claim_id)) continue;
|
|
21936
|
+
const auftrag = nachId.get(payload.job_id);
|
|
21937
|
+
if (!auftrag) continue;
|
|
21938
|
+
const anspruch = {
|
|
21939
|
+
job_id: payload.job_id,
|
|
21940
|
+
claim_id: payload.claim_id,
|
|
21941
|
+
client_id: payload.client_id ?? "",
|
|
21942
|
+
claimed_at: payload.claimed_at ?? ""
|
|
21943
|
+
};
|
|
21944
|
+
nachId.set(payload.job_id, {
|
|
21945
|
+
...auftrag,
|
|
21946
|
+
claim: auftrag.claim ?? anspruch,
|
|
21947
|
+
claim_attempts: [...auftrag.claim_attempts, anspruch],
|
|
21948
|
+
status: auftrag.status === "pending" ? "claimed" : auftrag.status
|
|
21949
|
+
});
|
|
21950
|
+
}
|
|
21951
|
+
for (const event of events) {
|
|
21952
|
+
if (event.type !== SZENEN_EVENT_TYPES.imageJobSettled) continue;
|
|
21953
|
+
const payload = event.payload;
|
|
21954
|
+
if (!payload || !istText6(payload.job_id)) continue;
|
|
21955
|
+
const auftrag = nachId.get(payload.job_id);
|
|
21956
|
+
if (!auftrag) continue;
|
|
21957
|
+
if (!auftrag.claim || auftrag.claim.claim_id !== payload.claim_id) continue;
|
|
21958
|
+
if (auftrag.status !== "claimed") continue;
|
|
21959
|
+
if (!SETTLED_STATUS.includes(payload.status)) continue;
|
|
21960
|
+
nachId.set(payload.job_id, {
|
|
21961
|
+
...auftrag,
|
|
21962
|
+
status: payload.status,
|
|
21963
|
+
...payload.generation_batch_id ? { generation_batch_id: payload.generation_batch_id } : {},
|
|
21964
|
+
...payload.item_id ? { item_id: payload.item_id } : {},
|
|
21965
|
+
...typeof payload.produced_count === "number" ? { produced_count: payload.produced_count } : {},
|
|
21966
|
+
...payload.diagnostic ? { diagnostic: payload.diagnostic } : {},
|
|
21967
|
+
settled_at: payload.settled_at ?? ""
|
|
21968
|
+
});
|
|
21969
|
+
}
|
|
21970
|
+
return [...nachId.values()];
|
|
21971
|
+
}
|
|
21972
|
+
function jobsForPromptRun(events, runId) {
|
|
21973
|
+
return collectImageJobs(events).filter((j) => j.prompt_run_id === runId);
|
|
21974
|
+
}
|
|
21975
|
+
function findImageJob(events, jobId) {
|
|
21976
|
+
return collectImageJobs(events).find((j) => j.job_id === jobId) ?? null;
|
|
21977
|
+
}
|
|
21978
|
+
function generationBatchIdOf(jobId) {
|
|
21979
|
+
return `job-${jobId}`;
|
|
21980
|
+
}
|
|
21981
|
+
|
|
21982
|
+
// src/lib/szenen/imageJobPort.ts
|
|
21983
|
+
var ANSPRUCH_VERSUCHE = 4;
|
|
21984
|
+
function fehler4(error, aktion) {
|
|
21985
|
+
return {
|
|
21986
|
+
message: `${aktion}: ${error instanceof Error ? error.message : String(error)}`
|
|
21987
|
+
};
|
|
21988
|
+
}
|
|
21989
|
+
function createImageJobPort(options) {
|
|
21990
|
+
const { channel, imageGeneration, storeId, clientId } = options;
|
|
21991
|
+
const newClaimId = options.newClaimId ?? (() => crypto.randomUUID());
|
|
21992
|
+
const now = options.now ?? (() => /* @__PURE__ */ new Date());
|
|
21993
|
+
return {
|
|
21994
|
+
async listJobs(runId) {
|
|
21995
|
+
try {
|
|
21996
|
+
return { kind: "ok", value: jobsForPromptRun(await channel.readEvents(), runId) };
|
|
21997
|
+
} catch (error) {
|
|
21998
|
+
return {
|
|
21999
|
+
kind: "error",
|
|
22000
|
+
...fehler4(error, `Die Bildauftraege des Laufs ${runId} konnten nicht gelesen werden`),
|
|
22001
|
+
retryable: true
|
|
22002
|
+
};
|
|
22003
|
+
}
|
|
22004
|
+
},
|
|
22005
|
+
async claimAndRun(jobId) {
|
|
22006
|
+
let letzterGrund = "";
|
|
22007
|
+
for (let versuch = 1; versuch <= ANSPRUCH_VERSUCHE; versuch += 1) {
|
|
22008
|
+
let kopf;
|
|
22009
|
+
try {
|
|
22010
|
+
kopf = await channel.readHead();
|
|
22011
|
+
} catch (error) {
|
|
22012
|
+
return {
|
|
22013
|
+
kind: "error",
|
|
22014
|
+
...fehler4(error, `Der Kopf-Commit des Bestands war nicht lesbar; Bildauftrag ${jobId} wurde nicht uebernommen`),
|
|
22015
|
+
retryable: true
|
|
22016
|
+
};
|
|
22017
|
+
}
|
|
22018
|
+
let auftrag;
|
|
22019
|
+
try {
|
|
22020
|
+
auftrag = findImageJob(await channel.readEventsAt(kopf), jobId);
|
|
22021
|
+
} catch (error) {
|
|
22022
|
+
return {
|
|
22023
|
+
kind: "error",
|
|
22024
|
+
...fehler4(error, `Der Bildauftrag ${jobId} konnte nicht gelesen werden`),
|
|
22025
|
+
retryable: true
|
|
22026
|
+
};
|
|
22027
|
+
}
|
|
22028
|
+
if (!auftrag) {
|
|
22029
|
+
return {
|
|
22030
|
+
kind: "rejected",
|
|
22031
|
+
message: `Der Bildauftrag ${jobId} steht nicht im autoritativen Log dieses Bestands.`
|
|
22032
|
+
};
|
|
22033
|
+
}
|
|
22034
|
+
if (auftrag.store_id !== storeId) {
|
|
22035
|
+
return {
|
|
22036
|
+
kind: "rejected",
|
|
22037
|
+
message: `Der Bildauftrag ${jobId} gilt fuer den Bestand "${auftrag.store_id}", dieser Host arbeitet auf "${storeId}". Nutzer, Umgebung und Bestand muessen zusammenpassen.`
|
|
22038
|
+
};
|
|
22039
|
+
}
|
|
22040
|
+
if (auftrag.status !== "pending") {
|
|
22041
|
+
return {
|
|
22042
|
+
kind: "lost",
|
|
22043
|
+
job: auftrag,
|
|
22044
|
+
message: `Der Bildauftrag ${jobId} ist bereits "${auftrag.status}"` + (auftrag.claim ? ` (Client ${auftrag.claim.client_id})` : "") + ". Er wird nicht erneut ausgefuehrt \u2014 ein zweiter Lauf waere ein zweites Mal bezahlte Rechenzeit."
|
|
22045
|
+
};
|
|
22046
|
+
}
|
|
22047
|
+
const anspruch = {
|
|
22048
|
+
job_id: jobId,
|
|
22049
|
+
claim_id: newClaimId(),
|
|
22050
|
+
client_id: clientId,
|
|
22051
|
+
claimed_at: now().toISOString()
|
|
22052
|
+
};
|
|
22053
|
+
try {
|
|
22054
|
+
await channel.appendEventAt(
|
|
22055
|
+
SZENEN_EVENT_TYPES.imageJobClaimed,
|
|
22056
|
+
anspruch,
|
|
22057
|
+
kopf
|
|
22058
|
+
);
|
|
22059
|
+
} catch (error) {
|
|
22060
|
+
if (istPreconditionFehler(error)) {
|
|
22061
|
+
letzterGrund = error instanceof Error ? error.message : String(error);
|
|
22062
|
+
continue;
|
|
22063
|
+
}
|
|
22064
|
+
return {
|
|
22065
|
+
kind: "error",
|
|
22066
|
+
...fehler4(error, `Der Anspruch auf Bildauftrag ${jobId} konnte nicht angehaengt werden`),
|
|
22067
|
+
retryable: true
|
|
22068
|
+
};
|
|
22069
|
+
}
|
|
22070
|
+
const gewonnen = {
|
|
22071
|
+
...auftrag,
|
|
22072
|
+
status: "claimed",
|
|
22073
|
+
claim: anspruch,
|
|
22074
|
+
claim_attempts: [...auftrag.claim_attempts, anspruch]
|
|
22075
|
+
};
|
|
22076
|
+
return await fuehreAus(gewonnen, anspruch, jobId);
|
|
22077
|
+
}
|
|
22078
|
+
return {
|
|
22079
|
+
kind: "error",
|
|
22080
|
+
message: `Der Bildauftrag ${jobId} liess sich in ${ANSPRUCH_VERSUCHE} Versuchen nicht exklusiv uebernehmen \u2014 der Bestand wird gerade von anderer Seite beschrieben (${letzterGrund}). Es wurde nichts ausgefuehrt und nichts bezahlt; ein neuer Versuch ist gefahrlos.`,
|
|
22081
|
+
retryable: true
|
|
22082
|
+
};
|
|
22083
|
+
}
|
|
22084
|
+
};
|
|
22085
|
+
async function fuehreAus(gewonnen, anspruch, jobId) {
|
|
22086
|
+
const ergebnis = await imageGeneration.startFromPromptRun({
|
|
22087
|
+
runId: gewonnen.prompt_run_id,
|
|
22088
|
+
generationBatchId: generationBatchIdOf(jobId),
|
|
22089
|
+
executionTargetModelKey: gewonnen.execution_target_model_key,
|
|
22090
|
+
executionProfileId: gewonnen.execution_profile_id,
|
|
22091
|
+
imageCount: gewonnen.image_count,
|
|
22092
|
+
...gewonnen.aspect_ratio ? { aspectRatio: gewonnen.aspect_ratio } : {}
|
|
22093
|
+
});
|
|
22094
|
+
const abschluss = {
|
|
22095
|
+
job_id: jobId,
|
|
22096
|
+
claim_id: anspruch.claim_id,
|
|
22097
|
+
...abschlussFelder(ergebnis, jobId),
|
|
22098
|
+
settled_at: now().toISOString()
|
|
22099
|
+
};
|
|
22100
|
+
try {
|
|
22101
|
+
await channel.appendEvent(SZENEN_EVENT_TYPES.imageJobSettled, abschluss);
|
|
22102
|
+
} catch {
|
|
22103
|
+
}
|
|
22104
|
+
const gelesen = await channel.readEvents().catch(() => null);
|
|
22105
|
+
return {
|
|
22106
|
+
kind: "ok",
|
|
22107
|
+
job: (gelesen && findImageJob(gelesen, jobId)) ?? {
|
|
22108
|
+
...gewonnen,
|
|
22109
|
+
status: abschluss.status,
|
|
22110
|
+
...abschluss.generation_batch_id ? { generation_batch_id: abschluss.generation_batch_id } : {},
|
|
22111
|
+
...abschluss.diagnostic ? { diagnostic: abschluss.diagnostic } : {},
|
|
22112
|
+
settled_at: abschluss.settled_at
|
|
22113
|
+
}
|
|
22114
|
+
};
|
|
22115
|
+
}
|
|
22116
|
+
}
|
|
22117
|
+
function istPreconditionFehler(error) {
|
|
22118
|
+
return Boolean(error && typeof error === "object" && error.name === "HfPreconditionFailed");
|
|
22119
|
+
}
|
|
22120
|
+
function abschlussFelder(ergebnis, jobId) {
|
|
22121
|
+
const batchId = generationBatchIdOf(jobId);
|
|
22122
|
+
switch (ergebnis.kind) {
|
|
22123
|
+
case "succeeded":
|
|
22124
|
+
return {
|
|
22125
|
+
status: "succeeded",
|
|
22126
|
+
generation_batch_id: batchId,
|
|
22127
|
+
item_id: ergebnis.batch.item_id,
|
|
22128
|
+
produced_count: ergebnis.batch.images.length
|
|
22129
|
+
};
|
|
22130
|
+
case "partial":
|
|
22131
|
+
return {
|
|
22132
|
+
status: "partial",
|
|
22133
|
+
generation_batch_id: batchId,
|
|
22134
|
+
item_id: ergebnis.batch.item_id,
|
|
22135
|
+
produced_count: ergebnis.produced,
|
|
22136
|
+
diagnostic: `Angefordert ${ergebnis.requested}, geliefert ${ergebnis.produced}.`
|
|
22137
|
+
};
|
|
22138
|
+
case "failed":
|
|
22139
|
+
return { status: "failed", produced_count: 0, diagnostic: ergebnis.message };
|
|
22140
|
+
case "unsupported":
|
|
22141
|
+
return {
|
|
22142
|
+
status: "rejected",
|
|
22143
|
+
produced_count: 0,
|
|
22144
|
+
diagnostic: `Zielmodell "${ergebnis.targetModelKey}" ist in dieser Umgebung nicht ausfuehrbar: ${ergebnis.reason}`
|
|
22145
|
+
};
|
|
22146
|
+
default:
|
|
22147
|
+
return { status: "rejected", produced_count: 0, diagnostic: ergebnis.message };
|
|
22148
|
+
}
|
|
22149
|
+
}
|
|
22150
|
+
|
|
21661
22151
|
// src/lib/szenen/flowViewPort.ts
|
|
21662
22152
|
var defaultContext = {
|
|
21663
22153
|
async chainFor(contextId) {
|
|
@@ -21756,10 +22246,21 @@ function createFlowSzenenViewPort(options) {
|
|
|
21756
22246
|
},
|
|
21757
22247
|
...options.now ? { now: options.now } : {}
|
|
21758
22248
|
}) : void 0;
|
|
22249
|
+
const kanalMitRevision = typeof channel.readHead === "function" && typeof channel.readEventsAt === "function" && typeof channel.appendEventAt === "function";
|
|
22250
|
+
const imageJobs = imageGeneration && hatHfZugangsdaten && kanalMitRevision ? createImageJobPort({
|
|
22251
|
+
channel,
|
|
22252
|
+
imageGeneration,
|
|
22253
|
+
// Dieselbe Form, in der der Server seinen Bestand kennt (`storeId`).
|
|
22254
|
+
storeId: `hf:${options.namespace}`,
|
|
22255
|
+
clientId: options.imageJobClientId ?? crypto.randomUUID(),
|
|
22256
|
+
...options.newImageJobClaimId ? { newClaimId: options.newImageJobClaimId } : {},
|
|
22257
|
+
...options.now ? { now: options.now } : {}
|
|
22258
|
+
}) : void 0;
|
|
21759
22259
|
const port = { elements, context, runs, derivation, imageBatchHistory };
|
|
21760
22260
|
if (imageLibrary) port.imageLibrary = imageLibrary;
|
|
21761
22261
|
if (imageBatchWrite) port.imageBatchWrite = imageBatchWrite;
|
|
21762
22262
|
if (imageGeneration) port.imageGeneration = imageGeneration;
|
|
22263
|
+
if (imageJobs) port.imageJobs = imageJobs;
|
|
21763
22264
|
return port;
|
|
21764
22265
|
}
|
|
21765
22266
|
|