@rslsp1/fa-app-tools 1.3.16 → 2.0.12
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-WCFXXLKN.mjs +409 -0
- package/dist/hfStateService-6YYT6ATO.mjs +54 -0
- package/dist/index.d.mts +103 -9
- package/dist/index.d.ts +103 -9
- package/dist/index.js +811 -298
- package/dist/index.mjs +574 -252
- package/package.json +5 -4
- package/dist/chunk-X6S5BP36.mjs +0 -232
- package/dist/hfStateService-B62RV5K3.mjs +0 -32
package/dist/index.js
CHANGED
|
@@ -259,13 +259,28 @@ var init_project = __esm({
|
|
|
259
259
|
}
|
|
260
260
|
});
|
|
261
261
|
|
|
262
|
+
// src/lib/hfEventTypes.ts
|
|
263
|
+
var CURRENT_EVENT_VERSION;
|
|
264
|
+
var init_hfEventTypes = __esm({
|
|
265
|
+
"src/lib/hfEventTypes.ts"() {
|
|
266
|
+
"use strict";
|
|
267
|
+
CURRENT_EVENT_VERSION = { major: 1, minor: 0 };
|
|
268
|
+
}
|
|
269
|
+
});
|
|
270
|
+
|
|
262
271
|
// src/lib/hfStateService.ts
|
|
263
272
|
var hfStateService_exports = {};
|
|
264
273
|
__export(hfStateService_exports, {
|
|
265
274
|
HF_TOKEN_KEY: () => HF_TOKEN_KEY,
|
|
266
275
|
getHFToken: () => getHFToken,
|
|
276
|
+
getSessionClientId: () => getSessionClientId,
|
|
277
|
+
hfBatchArchive: () => hfBatchArchive,
|
|
278
|
+
hfBootstrapFromLegacy: () => hfBootstrapFromLegacy,
|
|
267
279
|
hfDeleteProject: () => hfDeleteProject,
|
|
280
|
+
hfDownloadBinaryByPath: () => hfDownloadBinaryByPath,
|
|
281
|
+
hfDownloadJsonByPath: () => hfDownloadJsonByPath,
|
|
268
282
|
hfDownloadProject: () => hfDownloadProject,
|
|
283
|
+
hfListDir: () => hfListDir,
|
|
269
284
|
hfListProjects: () => hfListProjects,
|
|
270
285
|
hfLoadImageAsBase64: () => hfLoadImageAsBase64,
|
|
271
286
|
hfLoadMetadata: () => hfLoadMetadata,
|
|
@@ -275,7 +290,12 @@ __export(hfStateService_exports, {
|
|
|
275
290
|
hfUploadImage: () => hfUploadImage,
|
|
276
291
|
hfUploadProject: () => hfUploadProject,
|
|
277
292
|
hfUploadProjectForm: () => hfUploadProjectForm,
|
|
278
|
-
|
|
293
|
+
hfUploadSmallFile: () => hfUploadSmallFile,
|
|
294
|
+
loadHFState: () => loadHFState,
|
|
295
|
+
loadPendingEvents: () => loadPendingEvents,
|
|
296
|
+
setHFToken: () => setHFToken,
|
|
297
|
+
tsFromEventPath: () => tsFromEventPath,
|
|
298
|
+
writeHFEvent: () => writeHFEvent
|
|
279
299
|
});
|
|
280
300
|
function getHFToken() {
|
|
281
301
|
try {
|
|
@@ -290,6 +310,177 @@ function setHFToken(token) {
|
|
|
290
310
|
} catch {
|
|
291
311
|
}
|
|
292
312
|
}
|
|
313
|
+
function treeUrl(namespace, subdir = "") {
|
|
314
|
+
const parts = [namespace.replace(/\/$/, ""), subdir].filter(Boolean).join("/");
|
|
315
|
+
return `${HF_BASE}/api/datasets/${HF_REPO}/tree/main${parts ? "/" + parts : ""}`;
|
|
316
|
+
}
|
|
317
|
+
async function hfListDir(namespace, subdir, token) {
|
|
318
|
+
const res = await fetch(treeUrl(namespace, subdir), {
|
|
319
|
+
headers: { Authorization: `Bearer ${token}` }
|
|
320
|
+
});
|
|
321
|
+
if (res.status === 404) return [];
|
|
322
|
+
if (!res.ok) throw new Error(`HF list failed: ${res.status} ${res.statusText}`);
|
|
323
|
+
return res.json();
|
|
324
|
+
}
|
|
325
|
+
async function hfDownloadJsonByPath(repoPath, token) {
|
|
326
|
+
const res = await fetch(
|
|
327
|
+
`${HF_BASE}/datasets/${HF_REPO}/resolve/main/${repoPath}?download=true`,
|
|
328
|
+
{ headers: { Authorization: `Bearer ${token}` } }
|
|
329
|
+
);
|
|
330
|
+
if (!res.ok) throw new Error(`HF download failed: ${res.status}`);
|
|
331
|
+
return res.json();
|
|
332
|
+
}
|
|
333
|
+
async function hfDownloadBinaryByPath(repoPath, token) {
|
|
334
|
+
const res = await fetch(
|
|
335
|
+
`${HF_BASE}/datasets/${HF_REPO}/resolve/main/${repoPath}?download=true`,
|
|
336
|
+
{ headers: { Authorization: `Bearer ${token}` } }
|
|
337
|
+
);
|
|
338
|
+
if (!res.ok) throw new Error(`HF download binary failed: ${res.status}`);
|
|
339
|
+
return new Uint8Array(await res.arrayBuffer());
|
|
340
|
+
}
|
|
341
|
+
async function hfUploadSmallFile(repoPath, content, token, summary = `Update ${repoPath}`) {
|
|
342
|
+
const bytes = new TextEncoder().encode(content);
|
|
343
|
+
let binary = "";
|
|
344
|
+
bytes.forEach((b) => binary += String.fromCharCode(b));
|
|
345
|
+
const b64 = btoa(binary);
|
|
346
|
+
const res = await fetch(`${HF_BASE}/api/datasets/${HF_REPO}/commit/main`, {
|
|
347
|
+
method: "POST",
|
|
348
|
+
headers: { Authorization: `Bearer ${token}`, "Content-Type": "application/x-ndjson" },
|
|
349
|
+
body: [
|
|
350
|
+
JSON.stringify({ key: "header", value: { summary, description: "" } }),
|
|
351
|
+
JSON.stringify({ key: "file", value: { path: repoPath, encoding: "base64", content: b64 } })
|
|
352
|
+
].join("\n")
|
|
353
|
+
});
|
|
354
|
+
if (!res.ok) {
|
|
355
|
+
const err = await res.text().catch(() => "");
|
|
356
|
+
throw new Error(`HF upload failed: ${res.status} \u2014 ${err.slice(0, 200)}`);
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
async function hfBatchArchive(moves, token, summary) {
|
|
360
|
+
const lines = [
|
|
361
|
+
JSON.stringify({ key: "header", value: { summary, description: "" } }),
|
|
362
|
+
...moves.flatMap(({ from, to, content }) => {
|
|
363
|
+
const bytes = new TextEncoder().encode(content);
|
|
364
|
+
let binary = "";
|
|
365
|
+
bytes.forEach((b) => binary += String.fromCharCode(b));
|
|
366
|
+
return [
|
|
367
|
+
JSON.stringify({ key: "file", value: { path: to, encoding: "base64", content: btoa(binary) } }),
|
|
368
|
+
JSON.stringify({ key: "deletedFile", value: { path: from } })
|
|
369
|
+
];
|
|
370
|
+
})
|
|
371
|
+
];
|
|
372
|
+
const res = await fetch(`${HF_BASE}/api/datasets/${HF_REPO}/commit/main`, {
|
|
373
|
+
method: "POST",
|
|
374
|
+
headers: { Authorization: `Bearer ${token}`, "Content-Type": "application/x-ndjson" },
|
|
375
|
+
body: lines.join("\n")
|
|
376
|
+
});
|
|
377
|
+
if (!res.ok) {
|
|
378
|
+
const err = await res.text().catch(() => "");
|
|
379
|
+
throw new Error(`HF batch archive failed: ${res.status} \u2014 ${err.slice(0, 200)}`);
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
function tsFromEventPath(repoPath) {
|
|
383
|
+
const filename = repoPath.split("/").pop() || "";
|
|
384
|
+
const iso = filename.replace(/_[^_]+\.json$/, "").replace(/-/g, (m, i) => i > 7 ? ":" : m);
|
|
385
|
+
const ts = Date.parse(iso.replace(/T(\d{2}):(\d{2}):(\d{2})\.(\d{3})Z/, "T$1:$2:$3.$4Z"));
|
|
386
|
+
return isNaN(ts) ? 0 : ts;
|
|
387
|
+
}
|
|
388
|
+
async function loadHFState(namespace, token) {
|
|
389
|
+
const files = await hfListDir(namespace, "", token);
|
|
390
|
+
const stateFiles = files.filter((f) => f.type === "file" && /state-[\dT\-]+Z\.zip$/.test(f.path.split("/").pop() || "")).sort((a, b) => b.path.localeCompare(a.path));
|
|
391
|
+
if (!stateFiles.length) return null;
|
|
392
|
+
const zipBytes = await hfDownloadBinaryByPath(stateFiles[0].path, token);
|
|
393
|
+
const zip = await import_jszip2.default.loadAsync(zipBytes);
|
|
394
|
+
const [metadataStr, tagsStr, metaStr] = await Promise.all([
|
|
395
|
+
zip.file("metadata.json")?.async("string"),
|
|
396
|
+
zip.file("tags.json")?.async("string"),
|
|
397
|
+
zip.file("state_meta.json")?.async("string")
|
|
398
|
+
]);
|
|
399
|
+
if (!metadataStr || !tagsStr || !metaStr) throw new Error("state.zip: fehlende Pflicht-Dateien");
|
|
400
|
+
return {
|
|
401
|
+
metadata: JSON.parse(metadataStr),
|
|
402
|
+
tags: JSON.parse(tagsStr),
|
|
403
|
+
meta: JSON.parse(metaStr)
|
|
404
|
+
};
|
|
405
|
+
}
|
|
406
|
+
async function loadPendingEvents(namespace, token, sinceTs) {
|
|
407
|
+
const files = await hfListDir(namespace, "events", token);
|
|
408
|
+
const pending = files.filter((f) => f.type === "file" && tsFromEventPath(f.path) > sinceTs).sort((a, b) => a.path.localeCompare(b.path));
|
|
409
|
+
const events = await Promise.all(
|
|
410
|
+
pending.map((f) => hfDownloadJsonByPath(f.path, token))
|
|
411
|
+
);
|
|
412
|
+
return events;
|
|
413
|
+
}
|
|
414
|
+
function getSessionClientId() {
|
|
415
|
+
return SESSION_CLIENT_ID;
|
|
416
|
+
}
|
|
417
|
+
function tsToFilename(ts) {
|
|
418
|
+
return new Date(ts).toISOString().replace(/:/g, "-").replace(".", "-");
|
|
419
|
+
}
|
|
420
|
+
async function writeHFEvent(namespace, token, type, payload, prevTs) {
|
|
421
|
+
const ts = Date.now();
|
|
422
|
+
const uuid = crypto.randomUUID().slice(0, 8);
|
|
423
|
+
const event = {
|
|
424
|
+
v: CURRENT_EVENT_VERSION,
|
|
425
|
+
type,
|
|
426
|
+
ts,
|
|
427
|
+
prevTs,
|
|
428
|
+
clientId: SESSION_CLIENT_ID,
|
|
429
|
+
payload
|
|
430
|
+
};
|
|
431
|
+
const filename = `${tsToFilename(ts)}_${uuid}.json`;
|
|
432
|
+
const repoPath = `${namespace}events/${filename}`;
|
|
433
|
+
await hfUploadSmallFile(repoPath, JSON.stringify(event, null, 2), token, `Event: ${type}`);
|
|
434
|
+
return event;
|
|
435
|
+
}
|
|
436
|
+
async function hfBootstrapFromLegacy(namespace, token, onProgress) {
|
|
437
|
+
const log = (msg) => {
|
|
438
|
+
if (onProgress) onProgress(msg);
|
|
439
|
+
};
|
|
440
|
+
log("Lese tags.json \u2026");
|
|
441
|
+
const tags = await fetch(
|
|
442
|
+
`${HF_BASE}/datasets/${HF_REPO}/resolve/main/tags.json?download=true`,
|
|
443
|
+
{ headers: { Authorization: `Bearer ${token}` } }
|
|
444
|
+
).then((r) => r.ok ? r.json() : null).catch(() => null);
|
|
445
|
+
log("Lese metadata.json \u2026");
|
|
446
|
+
const metadata = await fetch(
|
|
447
|
+
`${HF_BASE}/datasets/${HF_REPO}/resolve/main/metadata.json?download=true`,
|
|
448
|
+
{ headers: { Authorization: `Bearer ${token}` } }
|
|
449
|
+
).then((r) => r.ok ? r.json() : []).catch(() => []);
|
|
450
|
+
const snapshot = {
|
|
451
|
+
metadata: Array.isArray(metadata) ? metadata : [],
|
|
452
|
+
tags: tags?.by_category ? tags : { by_category: {}, all: [] },
|
|
453
|
+
meta: { consolidatedAt: Date.now(), version: 1 }
|
|
454
|
+
};
|
|
455
|
+
log(`Erstelle state.zip (${snapshot.metadata.length} Bilder, ${snapshot.tags.all?.length ?? 0} Tags) \u2026`);
|
|
456
|
+
const zip = new import_jszip2.default();
|
|
457
|
+
zip.file("metadata.json", JSON.stringify(snapshot.metadata, null, 2));
|
|
458
|
+
zip.file("tags.json", JSON.stringify(snapshot.tags, null, 2));
|
|
459
|
+
zip.file("state_meta.json", JSON.stringify(snapshot.meta, null, 2));
|
|
460
|
+
const zipBytes = await zip.generateAsync({ type: "uint8array", compression: "DEFLATE" });
|
|
461
|
+
const ts = snapshot.meta.consolidatedAt;
|
|
462
|
+
const stateFilename = `state-${new Date(ts).toISOString().replace(/:/g, "-").replace(".", "-")}.zip`;
|
|
463
|
+
const repoPath = `${namespace}${stateFilename}`;
|
|
464
|
+
let binary = "";
|
|
465
|
+
zipBytes.forEach((b) => {
|
|
466
|
+
binary += String.fromCharCode(b);
|
|
467
|
+
});
|
|
468
|
+
const b64 = btoa(binary);
|
|
469
|
+
log("Lade state.zip hoch \u2026");
|
|
470
|
+
const commitRes = await fetch(`${HF_BASE}/api/datasets/${HF_REPO}/commit/main`, {
|
|
471
|
+
method: "POST",
|
|
472
|
+
headers: { Authorization: `Bearer ${token}`, "Content-Type": "application/x-ndjson" },
|
|
473
|
+
body: [
|
|
474
|
+
JSON.stringify({ key: "header", value: { summary: `Bootstrap: initialer State aus Legacy-Daten`, description: "" } }),
|
|
475
|
+
JSON.stringify({ key: "file", value: { path: repoPath, encoding: "base64", content: b64 } })
|
|
476
|
+
].join("\n")
|
|
477
|
+
});
|
|
478
|
+
if (!commitRes.ok) {
|
|
479
|
+
const err = await commitRes.text().catch(() => "");
|
|
480
|
+
throw new Error(`HF commit failed: ${commitRes.status} \u2014 ${err.slice(0, 300)}`);
|
|
481
|
+
}
|
|
482
|
+
log(`Fertig \u2014 ${stateFilename}`);
|
|
483
|
+
}
|
|
293
484
|
async function hfListProjects(token) {
|
|
294
485
|
const res = await fetch(`${HF_BASE}/api/datasets/${HF_REPO}/tree/main`, {
|
|
295
486
|
headers: { Authorization: `Bearer ${token}` }
|
|
@@ -333,7 +524,6 @@ async function hfUploadProject(zipBase64, name, token) {
|
|
|
333
524
|
if (!preRes.ok) throw new Error(`HF preupload failed: ${preRes.status} ${preRes.statusText}`);
|
|
334
525
|
const preData = await preRes.json();
|
|
335
526
|
const fileInfo = preData.files?.[0];
|
|
336
|
-
const debugInfo = JSON.stringify({ uploadMode: fileInfo?.uploadMode, hasUploadUrl: !!fileInfo?.uploadUrl, hasVerifyUrl: !!fileInfo?.verifyUrl, headerKeys: Object.keys(fileInfo?.header || {}), verifyHeaderKeys: Object.keys(fileInfo?.verifyHeader || {}) });
|
|
337
527
|
if (!fileInfo?.uploadMode) throw new Error(`HF preupload kein fileInfo: ${JSON.stringify(preData)}`);
|
|
338
528
|
if (fileInfo.uploadMode === "lfs" && fileInfo.uploadUrl) {
|
|
339
529
|
let uploadStatus = 0;
|
|
@@ -379,21 +569,8 @@ async function hfUploadProject(zipBase64, name, token) {
|
|
|
379
569
|
}
|
|
380
570
|
return { id: filename.replace(/\.zip$/, ""), name: filename.replace(/\.zip$/, ""), path: filename, size, isLfs: true };
|
|
381
571
|
}
|
|
382
|
-
async function hfUploadProjectForm(
|
|
383
|
-
|
|
384
|
-
const binary = atob(zipBase64);
|
|
385
|
-
const bytes = new Uint8Array(binary.length);
|
|
386
|
-
for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
|
|
387
|
-
const blob = new Blob([bytes], { type: "application/zip" });
|
|
388
|
-
const { uploadFile } = await import("@huggingface/hub");
|
|
389
|
-
await uploadFile({
|
|
390
|
-
repo: { type: "dataset", name: HF_REPO },
|
|
391
|
-
credentials: { accessToken: token },
|
|
392
|
-
file: { path: filename, content: blob },
|
|
393
|
-
branch: "main",
|
|
394
|
-
commitTitle: `Upload ${filename}`
|
|
395
|
-
});
|
|
396
|
-
return { id: filename.replace(/\.zip$/, ""), name: filename.replace(/\.zip$/, ""), path: filename, size: bytes.length, isLfs: true };
|
|
572
|
+
async function hfUploadProjectForm(_zipBase64, _name, _token) {
|
|
573
|
+
throw new Error("hfUploadProjectForm is deprecated. Use hfUploadProject instead.");
|
|
397
574
|
}
|
|
398
575
|
async function hfDeleteProject(path, token) {
|
|
399
576
|
const res = await fetch(`${HF_BASE}/api/datasets/${HF_REPO}/commit/main`, {
|
|
@@ -406,16 +583,8 @@ async function hfDeleteProject(path, token) {
|
|
|
406
583
|
});
|
|
407
584
|
if (!res.ok) throw new Error(`HF delete failed: ${res.status} ${res.statusText}`);
|
|
408
585
|
}
|
|
409
|
-
async function hfSaveTags(
|
|
410
|
-
|
|
411
|
-
const { uploadFile } = await import("@huggingface/hub");
|
|
412
|
-
await uploadFile({
|
|
413
|
-
repo: { type: "dataset", name: HF_REPO },
|
|
414
|
-
credentials: { accessToken: token },
|
|
415
|
-
file: { path: "tags.json", content },
|
|
416
|
-
branch: "main",
|
|
417
|
-
commitTitle: "Auto-sync tags"
|
|
418
|
-
});
|
|
586
|
+
async function hfSaveTags(_workspaceTags, _token) {
|
|
587
|
+
throw new Error("hfSaveTags is deprecated. Use writeHFEvent instead.");
|
|
419
588
|
}
|
|
420
589
|
async function hfLoadTags(token) {
|
|
421
590
|
try {
|
|
@@ -429,16 +598,8 @@ async function hfLoadTags(token) {
|
|
|
429
598
|
return null;
|
|
430
599
|
}
|
|
431
600
|
}
|
|
432
|
-
async function hfSaveMetadata(
|
|
433
|
-
|
|
434
|
-
const { uploadFile } = await import("@huggingface/hub");
|
|
435
|
-
await uploadFile({
|
|
436
|
-
repo: { type: "dataset", name: HF_REPO },
|
|
437
|
-
credentials: { accessToken: token },
|
|
438
|
-
file: { path: "metadata.json", content },
|
|
439
|
-
branch: "main",
|
|
440
|
-
commitTitle: "Auto-sync metadata"
|
|
441
|
-
});
|
|
601
|
+
async function hfSaveMetadata(_entries, _token) {
|
|
602
|
+
throw new Error("hfSaveMetadata is deprecated. Use writeHFEvent instead.");
|
|
442
603
|
}
|
|
443
604
|
async function hfLoadMetadata(token) {
|
|
444
605
|
try {
|
|
@@ -457,14 +618,32 @@ async function hfUploadImage(base64, id, token, mimeType = "image/jpeg") {
|
|
|
457
618
|
const binary = atob(base64);
|
|
458
619
|
const bytes = new Uint8Array(binary.length);
|
|
459
620
|
for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
|
|
460
|
-
const
|
|
461
|
-
const
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
621
|
+
const hashBuffer = await crypto.subtle.digest("SHA-256", bytes);
|
|
622
|
+
const oid = Array.from(new Uint8Array(hashBuffer)).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
623
|
+
const size = bytes.length;
|
|
624
|
+
const filename = `images/${id}.${ext}`;
|
|
625
|
+
const preRes = await fetch(`${HF_BASE}/api/datasets/${HF_REPO}/preupload/main`, {
|
|
626
|
+
method: "POST",
|
|
627
|
+
headers: { Authorization: `Bearer ${token}`, "Content-Type": "application/json" },
|
|
628
|
+
body: JSON.stringify({ files: [{ path: filename, size }] })
|
|
629
|
+
});
|
|
630
|
+
if (!preRes.ok) throw new Error(`HF preupload failed: ${preRes.status}`);
|
|
631
|
+
const preData = await preRes.json();
|
|
632
|
+
const fileInfo = preData.files?.[0];
|
|
633
|
+
if (fileInfo?.uploadUrl) {
|
|
634
|
+
await fetch(fileInfo.uploadUrl, {
|
|
635
|
+
method: "PUT",
|
|
636
|
+
headers: { "Content-Type": mimeType, ...fileInfo.header || {} },
|
|
637
|
+
body: bytes
|
|
638
|
+
});
|
|
639
|
+
}
|
|
640
|
+
await fetch(`${HF_BASE}/api/datasets/${HF_REPO}/commit/main`, {
|
|
641
|
+
method: "POST",
|
|
642
|
+
headers: { Authorization: `Bearer ${token}`, "Content-Type": "application/x-ndjson" },
|
|
643
|
+
body: [
|
|
644
|
+
JSON.stringify({ key: "header", value: { summary: `Add image ${id}`, description: "" } }),
|
|
645
|
+
JSON.stringify({ key: "lfsFile", value: { path: filename, algo: "sha256", oid, size } })
|
|
646
|
+
].join("\n")
|
|
468
647
|
});
|
|
469
648
|
}
|
|
470
649
|
async function hfLoadImageAsBase64(id, token) {
|
|
@@ -488,13 +667,16 @@ async function hfLoadImageAsBase64(id, token) {
|
|
|
488
667
|
}
|
|
489
668
|
return null;
|
|
490
669
|
}
|
|
491
|
-
var HF_BASE, HF_REPO, HF_TOKEN_KEY;
|
|
670
|
+
var import_jszip2, HF_BASE, HF_REPO, HF_TOKEN_KEY, SESSION_CLIENT_ID;
|
|
492
671
|
var init_hfStateService = __esm({
|
|
493
672
|
"src/lib/hfStateService.ts"() {
|
|
494
673
|
"use strict";
|
|
674
|
+
import_jszip2 = __toESM(require("jszip"));
|
|
675
|
+
init_hfEventTypes();
|
|
495
676
|
HF_BASE = "https://huggingface.co";
|
|
496
677
|
HF_REPO = "RolandSch/fa-app-state";
|
|
497
678
|
HF_TOKEN_KEY = "hf-token";
|
|
679
|
+
SESSION_CLIENT_ID = `client-${crypto.randomUUID().slice(0, 8)}`;
|
|
498
680
|
}
|
|
499
681
|
});
|
|
500
682
|
|
|
@@ -524,9 +706,12 @@ __export(index_exports, {
|
|
|
524
706
|
SectionLabel: () => SectionLabel,
|
|
525
707
|
SetupPanel: () => SetupPanel,
|
|
526
708
|
TagManagerPanel: () => TagManagerPanel,
|
|
709
|
+
applyEvent: () => applyEvent,
|
|
710
|
+
applyEvents: () => applyEvents,
|
|
527
711
|
autoLabel: () => autoLabel,
|
|
528
712
|
buildBlendInstruction: () => buildBlendInstruction,
|
|
529
713
|
buildCompareInstruction: () => buildCompareInstruction,
|
|
714
|
+
buildDag: () => buildDag,
|
|
530
715
|
buildFallbackPrompt: () => buildFallbackPrompt,
|
|
531
716
|
buildGenerationPrompt: () => buildGenerationPrompt,
|
|
532
717
|
buildImageGenerationOptions: () => buildImageGenerationOptions,
|
|
@@ -538,29 +723,38 @@ __export(index_exports, {
|
|
|
538
723
|
cleanAiResponse: () => cleanAiResponse,
|
|
539
724
|
createFlowServices: () => createFlowServices,
|
|
540
725
|
exportProjectToZip: () => exportProjectToZip,
|
|
726
|
+
findForks: () => findForks,
|
|
727
|
+
findTips: () => findTips,
|
|
541
728
|
formatTreeToMarkdown: () => formatTreeToMarkdown,
|
|
542
729
|
frameToGeneration: () => frameToGeneration,
|
|
543
730
|
getFormattedTimestamp: () => getFormattedTimestamp,
|
|
544
731
|
getHFToken: () => getHFToken,
|
|
732
|
+
getSessionClientId: () => getSessionClientId,
|
|
545
733
|
groupGenerationsToLabItems: () => groupGenerationsToLabItems,
|
|
734
|
+
hfBatchArchive: () => hfBatchArchive,
|
|
735
|
+
hfBootstrapFromLegacy: () => hfBootstrapFromLegacy,
|
|
546
736
|
hfDeleteProject: () => hfDeleteProject,
|
|
547
737
|
hfDownloadProject: () => hfDownloadProject,
|
|
738
|
+
hfListDir: () => hfListDir,
|
|
548
739
|
hfListProjects: () => hfListProjects,
|
|
549
740
|
hfLoadImageAsBase64: () => hfLoadImageAsBase64,
|
|
550
|
-
hfLoadMetadata: () => hfLoadMetadata,
|
|
551
|
-
hfLoadTags: () => hfLoadTags,
|
|
552
|
-
hfSaveMetadata: () => hfSaveMetadata,
|
|
553
|
-
hfSaveTags: () => hfSaveTags,
|
|
554
741
|
hfUploadImage: () => hfUploadImage,
|
|
555
742
|
hfUploadProjectForm: () => hfUploadProjectForm,
|
|
743
|
+
hfUploadSmallFile: () => hfUploadSmallFile,
|
|
556
744
|
importProjectFromZip: () => importProjectFromZip,
|
|
557
745
|
injectXMPMetadata: () => injectXMPMetadata,
|
|
558
746
|
interpretSdkError: () => interpretSdkError,
|
|
747
|
+
loadHFState: () => loadHFState,
|
|
748
|
+
loadPendingEvents: () => loadPendingEvents,
|
|
559
749
|
parsePromptFile: () => parsePromptFile,
|
|
560
750
|
parsePromptResponse: () => parsePromptResponse,
|
|
561
751
|
setHFToken: () => setHFToken,
|
|
752
|
+
topoSort: () => topoSort,
|
|
753
|
+
tsFromEventPath: () => tsFromEventPath,
|
|
754
|
+
useHFState: () => useHFState,
|
|
562
755
|
useKeyboardNavigation: () => useKeyboardNavigation,
|
|
563
|
-
useOnClickOutside: () => useOnClickOutside
|
|
756
|
+
useOnClickOutside: () => useOnClickOutside,
|
|
757
|
+
writeHFEvent: () => writeHFEvent
|
|
564
758
|
});
|
|
565
759
|
module.exports = __toCommonJS(index_exports);
|
|
566
760
|
|
|
@@ -1343,7 +1537,7 @@ function ListView({ nodes, edges, onNodeChange, onAddChild, onDeleteNode, onMove
|
|
|
1343
1537
|
}
|
|
1344
1538
|
|
|
1345
1539
|
// src/components/AvatarArchitectApp.tsx
|
|
1346
|
-
var
|
|
1540
|
+
var import_react22 = require("react");
|
|
1347
1541
|
|
|
1348
1542
|
// src/components/PromptTab.tsx
|
|
1349
1543
|
var import_react12 = require("react");
|
|
@@ -1871,6 +2065,7 @@ var import_react13 = require("react");
|
|
|
1871
2065
|
init_hfStateService();
|
|
1872
2066
|
var import_jsx_runtime12 = require("react/jsx-runtime");
|
|
1873
2067
|
var ProjectSyncTab = ({
|
|
2068
|
+
topSlot,
|
|
1874
2069
|
onProjectExport,
|
|
1875
2070
|
onProjectImport,
|
|
1876
2071
|
onWorkspaceImport,
|
|
@@ -1962,6 +2157,7 @@ var ProjectSyncTab = ({
|
|
|
1962
2157
|
if (hfToken) loadHfProjects(hfToken);
|
|
1963
2158
|
}, [hfToken]);
|
|
1964
2159
|
return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "absolute inset-0 overflow-y-auto dark-scrollbar", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "p-6 flex flex-col gap-8", children: [
|
|
2160
|
+
topSlot && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { children: topSlot }),
|
|
1965
2161
|
(onProjectExport || onProjectImport || onWorkspaceImport) && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "flex flex-col gap-4", children: [
|
|
1966
2162
|
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(SectionLabel, { children: "Projekt-ZIP" }),
|
|
1967
2163
|
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "flex flex-col gap-2", children: [
|
|
@@ -2370,14 +2566,255 @@ function toPromptImages(images) {
|
|
|
2370
2566
|
// src/components/AvatarArchitectApp.tsx
|
|
2371
2567
|
init_hfStateService();
|
|
2372
2568
|
|
|
2569
|
+
// src/hooks/useHFState.ts
|
|
2570
|
+
var import_react14 = require("react");
|
|
2571
|
+
init_hfStateService();
|
|
2572
|
+
|
|
2573
|
+
// src/lib/hfReducer.ts
|
|
2574
|
+
function applyEvent(state, event) {
|
|
2575
|
+
if (event.v.major > 1) return state;
|
|
2576
|
+
switch (event.type) {
|
|
2577
|
+
case "image_added": {
|
|
2578
|
+
const p = event.payload;
|
|
2579
|
+
if (state.metadata.some((m) => m.id === p.id)) return state;
|
|
2580
|
+
return { ...state, metadata: [...state.metadata, p] };
|
|
2581
|
+
}
|
|
2582
|
+
case "tag_upserted": {
|
|
2583
|
+
const p = event.payload;
|
|
2584
|
+
const tags = state.tags;
|
|
2585
|
+
const cat = tags.by_category[p.category] || [];
|
|
2586
|
+
const existing = cat.find((t) => t.value === p.value);
|
|
2587
|
+
const updated = { label: p.label, value: p.value, is_user_created: p.is_user_created, is_deleted: p.is_deleted };
|
|
2588
|
+
const newCat = existing ? cat.map((t) => t.value === p.value ? { ...t, ...updated } : t) : [...cat, updated];
|
|
2589
|
+
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 }];
|
|
2590
|
+
return { ...state, tags: { by_category: { ...tags.by_category, [p.category]: newCat }, all: newAll } };
|
|
2591
|
+
}
|
|
2592
|
+
case "metadata_updated": {
|
|
2593
|
+
const p = event.payload;
|
|
2594
|
+
return {
|
|
2595
|
+
...state,
|
|
2596
|
+
metadata: state.metadata.map((m) => m.id === p.id ? { ...m, ...p.delta } : m)
|
|
2597
|
+
};
|
|
2598
|
+
}
|
|
2599
|
+
default:
|
|
2600
|
+
return state;
|
|
2601
|
+
}
|
|
2602
|
+
}
|
|
2603
|
+
function applyEvents(state, events) {
|
|
2604
|
+
return events.reduce(applyEvent, state);
|
|
2605
|
+
}
|
|
2606
|
+
|
|
2607
|
+
// src/lib/hfDag.ts
|
|
2608
|
+
function buildDag(events) {
|
|
2609
|
+
const dag = /* @__PURE__ */ new Map();
|
|
2610
|
+
for (const event of events) {
|
|
2611
|
+
dag.set(event.ts, { event, children: [] });
|
|
2612
|
+
}
|
|
2613
|
+
for (const event of events) {
|
|
2614
|
+
for (const parent of event.prevTs) {
|
|
2615
|
+
const node = dag.get(parent);
|
|
2616
|
+
if (node && !node.children.includes(event.ts)) {
|
|
2617
|
+
node.children.push(event.ts);
|
|
2618
|
+
}
|
|
2619
|
+
}
|
|
2620
|
+
}
|
|
2621
|
+
return dag;
|
|
2622
|
+
}
|
|
2623
|
+
function findTips(dag) {
|
|
2624
|
+
return [...dag.values()].filter((n) => n.children.length === 0).map((n) => n.event.ts);
|
|
2625
|
+
}
|
|
2626
|
+
function findForks(dag) {
|
|
2627
|
+
const forks = [];
|
|
2628
|
+
for (const [ts, node] of dag) {
|
|
2629
|
+
if (node.children.length > 1) {
|
|
2630
|
+
forks.push({ parentTs: ts, childTs: node.children });
|
|
2631
|
+
}
|
|
2632
|
+
}
|
|
2633
|
+
return forks;
|
|
2634
|
+
}
|
|
2635
|
+
function topoSort(events) {
|
|
2636
|
+
if (!events.length) return [];
|
|
2637
|
+
const inDegree = /* @__PURE__ */ new Map();
|
|
2638
|
+
const children = /* @__PURE__ */ new Map();
|
|
2639
|
+
const tsSet = new Set(events.map((e) => e.ts));
|
|
2640
|
+
for (const e of events) {
|
|
2641
|
+
inDegree.set(e.ts, 0);
|
|
2642
|
+
children.set(e.ts, []);
|
|
2643
|
+
}
|
|
2644
|
+
for (const e of events) {
|
|
2645
|
+
for (const p of e.prevTs) {
|
|
2646
|
+
if (tsSet.has(p)) {
|
|
2647
|
+
children.get(p).push(e.ts);
|
|
2648
|
+
inDegree.set(e.ts, (inDegree.get(e.ts) || 0) + 1);
|
|
2649
|
+
}
|
|
2650
|
+
}
|
|
2651
|
+
}
|
|
2652
|
+
const queue = events.filter((e) => (inDegree.get(e.ts) || 0) === 0).sort((a, b) => a.ts - b.ts);
|
|
2653
|
+
const result = [];
|
|
2654
|
+
const byTs = new Map(events.map((e) => [e.ts, e]));
|
|
2655
|
+
while (queue.length) {
|
|
2656
|
+
const node = queue.shift();
|
|
2657
|
+
result.push(node);
|
|
2658
|
+
for (const childTs of children.get(node.ts) || []) {
|
|
2659
|
+
const newDeg = (inDegree.get(childTs) || 0) - 1;
|
|
2660
|
+
inDegree.set(childTs, newDeg);
|
|
2661
|
+
if (newDeg === 0) {
|
|
2662
|
+
const child = byTs.get(childTs);
|
|
2663
|
+
const insertAt = queue.findIndex((q) => q.ts > child.ts);
|
|
2664
|
+
if (insertAt === -1) queue.push(child);
|
|
2665
|
+
else queue.splice(insertAt, 0, child);
|
|
2666
|
+
}
|
|
2667
|
+
}
|
|
2668
|
+
}
|
|
2669
|
+
return result;
|
|
2670
|
+
}
|
|
2671
|
+
|
|
2672
|
+
// src/hooks/useHFState.ts
|
|
2673
|
+
var OFFLINE_BUFFER_KEY = "hf-offline-buffer";
|
|
2674
|
+
var POLL_INTERVAL_MS = 3e4;
|
|
2675
|
+
function readOfflineBuffer() {
|
|
2676
|
+
try {
|
|
2677
|
+
return JSON.parse(localStorage.getItem(OFFLINE_BUFFER_KEY) || "[]");
|
|
2678
|
+
} catch {
|
|
2679
|
+
return [];
|
|
2680
|
+
}
|
|
2681
|
+
}
|
|
2682
|
+
function writeOfflineBuffer(events) {
|
|
2683
|
+
try {
|
|
2684
|
+
localStorage.setItem(OFFLINE_BUFFER_KEY, JSON.stringify(events));
|
|
2685
|
+
} catch {
|
|
2686
|
+
}
|
|
2687
|
+
}
|
|
2688
|
+
function useHFState(token, namespace) {
|
|
2689
|
+
const [state, setState] = (0, import_react14.useState)(null);
|
|
2690
|
+
const [isLoading, setIsLoading] = (0, import_react14.useState)(false);
|
|
2691
|
+
const [error, setError] = (0, import_react14.useState)(null);
|
|
2692
|
+
const [eventCount, setEventCount] = (0, import_react14.useState)(0);
|
|
2693
|
+
const [forks, setForks] = (0, import_react14.useState)([]);
|
|
2694
|
+
const [pendingBufferCount, setPendingBufferCount] = (0, import_react14.useState)(readOfflineBuffer().length);
|
|
2695
|
+
const [lastEventTs, setLastEventTs] = (0, import_react14.useState)(0);
|
|
2696
|
+
const [hasStateZip, setHasStateZip] = (0, import_react14.useState)(false);
|
|
2697
|
+
const knownEventPaths = (0, import_react14.useRef)(/* @__PURE__ */ new Set());
|
|
2698
|
+
const allEventsRef = (0, import_react14.useRef)([]);
|
|
2699
|
+
const applyNewEvents = (0, import_react14.useCallback)((snapshot, newEvents) => {
|
|
2700
|
+
if (!newEvents.length && allEventsRef.current.length === 0) {
|
|
2701
|
+
setEventCount(0);
|
|
2702
|
+
return snapshot;
|
|
2703
|
+
}
|
|
2704
|
+
const sorted = topoSort([...allEventsRef.current, ...newEvents]);
|
|
2705
|
+
allEventsRef.current = sorted;
|
|
2706
|
+
const afterConsolidation = sorted.filter((e) => e.ts > snapshot.meta.consolidatedAt);
|
|
2707
|
+
const dag = buildDag(afterConsolidation);
|
|
2708
|
+
setForks(findForks(dag));
|
|
2709
|
+
setEventCount(afterConsolidation.length);
|
|
2710
|
+
if (afterConsolidation.length) setLastEventTs(Math.max(...afterConsolidation.map((e) => e.ts)));
|
|
2711
|
+
return applyEvents(snapshot, afterConsolidation);
|
|
2712
|
+
}, []);
|
|
2713
|
+
const loadFull = (0, import_react14.useCallback)(async () => {
|
|
2714
|
+
if (!token || !namespace) return;
|
|
2715
|
+
setIsLoading(true);
|
|
2716
|
+
setError(null);
|
|
2717
|
+
try {
|
|
2718
|
+
const snapshot = await loadHFState(namespace, token);
|
|
2719
|
+
setHasStateZip(snapshot !== null);
|
|
2720
|
+
const base = snapshot ?? {
|
|
2721
|
+
metadata: [],
|
|
2722
|
+
tags: { by_category: {}, all: [] },
|
|
2723
|
+
meta: { consolidatedAt: 0, version: 1 }
|
|
2724
|
+
};
|
|
2725
|
+
const events = await loadPendingEvents(namespace, token, base.meta.consolidatedAt);
|
|
2726
|
+
events.forEach((e) => knownEventPaths.current.add(`${e.ts}_${e.clientId}`));
|
|
2727
|
+
allEventsRef.current = [];
|
|
2728
|
+
const finalState = applyNewEvents(base, events);
|
|
2729
|
+
setState(finalState);
|
|
2730
|
+
const buffer = readOfflineBuffer();
|
|
2731
|
+
if (buffer.length) {
|
|
2732
|
+
for (const evt of buffer) {
|
|
2733
|
+
await writeHFEvent(namespace, token, evt.type, evt.payload, evt.prevTs).catch(() => {
|
|
2734
|
+
});
|
|
2735
|
+
}
|
|
2736
|
+
writeOfflineBuffer([]);
|
|
2737
|
+
setPendingBufferCount(0);
|
|
2738
|
+
const freshEvents = await loadPendingEvents(namespace, token, base.meta.consolidatedAt);
|
|
2739
|
+
freshEvents.forEach((e) => knownEventPaths.current.add(`${e.ts}_${e.clientId}`));
|
|
2740
|
+
setState((prev) => prev ? applyNewEvents(base, freshEvents) : prev);
|
|
2741
|
+
}
|
|
2742
|
+
} catch (e) {
|
|
2743
|
+
setError(e.message);
|
|
2744
|
+
} finally {
|
|
2745
|
+
setIsLoading(false);
|
|
2746
|
+
}
|
|
2747
|
+
}, [token, namespace, applyNewEvents]);
|
|
2748
|
+
const pollNew = (0, import_react14.useCallback)(async () => {
|
|
2749
|
+
if (!token || !namespace || !state) return;
|
|
2750
|
+
try {
|
|
2751
|
+
const events = await loadPendingEvents(namespace, token, state.meta.consolidatedAt);
|
|
2752
|
+
const newEvents = events.filter((e) => !knownEventPaths.current.has(`${e.ts}_${e.clientId}`));
|
|
2753
|
+
if (!newEvents.length) return;
|
|
2754
|
+
newEvents.forEach((e) => knownEventPaths.current.add(`${e.ts}_${e.clientId}`));
|
|
2755
|
+
setState((prev) => prev ? applyNewEvents(prev, newEvents) : prev);
|
|
2756
|
+
} catch {
|
|
2757
|
+
}
|
|
2758
|
+
}, [token, namespace, state, applyNewEvents]);
|
|
2759
|
+
(0, import_react14.useEffect)(() => {
|
|
2760
|
+
if (token && namespace) loadFull();
|
|
2761
|
+
}, [token, namespace]);
|
|
2762
|
+
(0, import_react14.useEffect)(() => {
|
|
2763
|
+
if (!token || !namespace) return;
|
|
2764
|
+
const id = setInterval(pollNew, POLL_INTERVAL_MS);
|
|
2765
|
+
return () => clearInterval(id);
|
|
2766
|
+
}, [token, namespace, pollNew]);
|
|
2767
|
+
const writeEvent = (0, import_react14.useCallback)(async (type, payload) => {
|
|
2768
|
+
const prevTs = lastEventTs ? [lastEventTs] : [state?.meta.consolidatedAt ?? 0];
|
|
2769
|
+
console.log("[HF] writeEvent called:", { type, namespace, tokenOk: !!token, prevTs });
|
|
2770
|
+
await pollNew();
|
|
2771
|
+
try {
|
|
2772
|
+
console.log("[HF] writeHFEvent start, path will be:", `${namespace}events/...`);
|
|
2773
|
+
const event = await writeHFEvent(namespace, token, type, payload, prevTs);
|
|
2774
|
+
console.log("[HF] writeHFEvent success:", event.ts);
|
|
2775
|
+
knownEventPaths.current.add(`${event.ts}_${event.clientId}`);
|
|
2776
|
+
setState((prev) => prev ? applyNewEvents(prev, [event]) : prev);
|
|
2777
|
+
setLastEventTs(event.ts);
|
|
2778
|
+
await pollNew();
|
|
2779
|
+
} catch (e) {
|
|
2780
|
+
console.error("[HF] writeHFEvent FAILED, going to offline buffer:", e);
|
|
2781
|
+
const buffer = readOfflineBuffer();
|
|
2782
|
+
const offline = {
|
|
2783
|
+
v: { major: 1, minor: 0 },
|
|
2784
|
+
type,
|
|
2785
|
+
ts: Date.now(),
|
|
2786
|
+
prevTs,
|
|
2787
|
+
clientId: getSessionClientId(),
|
|
2788
|
+
payload
|
|
2789
|
+
};
|
|
2790
|
+
writeOfflineBuffer([...buffer, offline]);
|
|
2791
|
+
setPendingBufferCount(buffer.length + 1);
|
|
2792
|
+
setState((prev) => prev ? applyNewEvents(prev, [offline]) : prev);
|
|
2793
|
+
}
|
|
2794
|
+
}, [namespace, token, lastEventTs, state, pollNew, applyNewEvents]);
|
|
2795
|
+
return {
|
|
2796
|
+
state,
|
|
2797
|
+
isLoading,
|
|
2798
|
+
error,
|
|
2799
|
+
pendingBufferCount,
|
|
2800
|
+
eventCount,
|
|
2801
|
+
forks,
|
|
2802
|
+
writeEvent,
|
|
2803
|
+
refresh: loadFull,
|
|
2804
|
+
lastEventTs,
|
|
2805
|
+
allEvents: allEventsRef.current,
|
|
2806
|
+
hasStateZip
|
|
2807
|
+
};
|
|
2808
|
+
}
|
|
2809
|
+
|
|
2373
2810
|
// src/components/labs/LabsTab.tsx
|
|
2374
|
-
var
|
|
2811
|
+
var import_react20 = require("react");
|
|
2375
2812
|
|
|
2376
2813
|
// src/components/labs/LabRemix.tsx
|
|
2377
|
-
var
|
|
2814
|
+
var import_react16 = require("react");
|
|
2378
2815
|
|
|
2379
2816
|
// src/components/labs/LabImagePicker.tsx
|
|
2380
|
-
var
|
|
2817
|
+
var import_react15 = require("react");
|
|
2381
2818
|
var import_jsx_runtime13 = require("react/jsx-runtime");
|
|
2382
2819
|
var LabImagePicker = ({
|
|
2383
2820
|
availableItems,
|
|
@@ -2386,8 +2823,8 @@ var LabImagePicker = ({
|
|
|
2386
2823
|
onClose,
|
|
2387
2824
|
title = "Bild w\xE4hlen"
|
|
2388
2825
|
}) => {
|
|
2389
|
-
const [search, setSearch] = (0,
|
|
2390
|
-
const [drillItem, setDrillItem] = (0,
|
|
2826
|
+
const [search, setSearch] = (0, import_react15.useState)("");
|
|
2827
|
+
const [drillItem, setDrillItem] = (0, import_react15.useState)(null);
|
|
2391
2828
|
const filtered = availableItems.filter(
|
|
2392
2829
|
(item) => !search || item.prompt.toLowerCase().includes(search.toLowerCase())
|
|
2393
2830
|
);
|
|
@@ -2489,13 +2926,13 @@ var LabImagePicker = ({
|
|
|
2489
2926
|
// src/components/labs/LabRemix.tsx
|
|
2490
2927
|
var import_jsx_runtime14 = require("react/jsx-runtime");
|
|
2491
2928
|
var LabRemix = ({ services, onResult }) => {
|
|
2492
|
-
const [showPicker, setShowPicker] = (0,
|
|
2493
|
-
const [selected, setSelected] = (0,
|
|
2494
|
-
const [instruction, setInstruction] = (0,
|
|
2495
|
-
const [generatedPrompt, setGeneratedPrompt] = (0,
|
|
2496
|
-
const [resultImage, setResultImage] = (0,
|
|
2497
|
-
const [isGeneratingPrompt, setIsGeneratingPrompt] = (0,
|
|
2498
|
-
const [isGeneratingImage, setIsGeneratingImage] = (0,
|
|
2929
|
+
const [showPicker, setShowPicker] = (0, import_react16.useState)(false);
|
|
2930
|
+
const [selected, setSelected] = (0, import_react16.useState)(null);
|
|
2931
|
+
const [instruction, setInstruction] = (0, import_react16.useState)("");
|
|
2932
|
+
const [generatedPrompt, setGeneratedPrompt] = (0, import_react16.useState)("");
|
|
2933
|
+
const [resultImage, setResultImage] = (0, import_react16.useState)(null);
|
|
2934
|
+
const [isGeneratingPrompt, setIsGeneratingPrompt] = (0, import_react16.useState)(false);
|
|
2935
|
+
const [isGeneratingImage, setIsGeneratingImage] = (0, import_react16.useState)(false);
|
|
2499
2936
|
const handleSelectImage = (item, frame) => {
|
|
2500
2937
|
services.onItemUsed(item);
|
|
2501
2938
|
setSelected({
|
|
@@ -2678,16 +3115,16 @@ var LabRemix = ({ services, onResult }) => {
|
|
|
2678
3115
|
};
|
|
2679
3116
|
|
|
2680
3117
|
// src/components/labs/LabBlend.tsx
|
|
2681
|
-
var
|
|
3118
|
+
var import_react17 = require("react");
|
|
2682
3119
|
var import_jsx_runtime15 = require("react/jsx-runtime");
|
|
2683
3120
|
var LabBlend = ({ services, onResult }) => {
|
|
2684
|
-
const [showPickerFor, setShowPickerFor] = (0,
|
|
2685
|
-
const [selectedImages, setSelectedImages] = (0,
|
|
2686
|
-
const [instruction, setInstruction] = (0,
|
|
2687
|
-
const [generatedPrompt, setGeneratedPrompt] = (0,
|
|
2688
|
-
const [resultImage, setResultImage] = (0,
|
|
2689
|
-
const [isGeneratingPrompt, setIsGeneratingPrompt] = (0,
|
|
2690
|
-
const [isGeneratingImage, setIsGeneratingImage] = (0,
|
|
3121
|
+
const [showPickerFor, setShowPickerFor] = (0, import_react17.useState)(null);
|
|
3122
|
+
const [selectedImages, setSelectedImages] = (0, import_react17.useState)([]);
|
|
3123
|
+
const [instruction, setInstruction] = (0, import_react17.useState)("");
|
|
3124
|
+
const [generatedPrompt, setGeneratedPrompt] = (0, import_react17.useState)("");
|
|
3125
|
+
const [resultImage, setResultImage] = (0, import_react17.useState)(null);
|
|
3126
|
+
const [isGeneratingPrompt, setIsGeneratingPrompt] = (0, import_react17.useState)(false);
|
|
3127
|
+
const [isGeneratingImage, setIsGeneratingImage] = (0, import_react17.useState)(false);
|
|
2691
3128
|
const handleSelectImage = (index, item, frame) => {
|
|
2692
3129
|
services.onItemUsed(item);
|
|
2693
3130
|
const newImg = {
|
|
@@ -2874,17 +3311,17 @@ var LabBlend = ({ services, onResult }) => {
|
|
|
2874
3311
|
};
|
|
2875
3312
|
|
|
2876
3313
|
// src/components/labs/LabCompare.tsx
|
|
2877
|
-
var
|
|
3314
|
+
var import_react18 = require("react");
|
|
2878
3315
|
var import_jsx_runtime16 = require("react/jsx-runtime");
|
|
2879
3316
|
var LabCompare = ({ services, onResult }) => {
|
|
2880
|
-
const [showPickerFor, setShowPickerFor] = (0,
|
|
2881
|
-
const [selectedImages, setSelectedImages] = (0,
|
|
2882
|
-
const [instruction, setInstruction] = (0,
|
|
2883
|
-
const [analysis, setAnalysis] = (0,
|
|
2884
|
-
const [generatedPrompt, setGeneratedPrompt] = (0,
|
|
2885
|
-
const [resultImage, setResultImage] = (0,
|
|
2886
|
-
const [isAnalyzing, setIsAnalyzing] = (0,
|
|
2887
|
-
const [isGeneratingImage, setIsGeneratingImage] = (0,
|
|
3317
|
+
const [showPickerFor, setShowPickerFor] = (0, import_react18.useState)(null);
|
|
3318
|
+
const [selectedImages, setSelectedImages] = (0, import_react18.useState)([]);
|
|
3319
|
+
const [instruction, setInstruction] = (0, import_react18.useState)("");
|
|
3320
|
+
const [analysis, setAnalysis] = (0, import_react18.useState)("");
|
|
3321
|
+
const [generatedPrompt, setGeneratedPrompt] = (0, import_react18.useState)("");
|
|
3322
|
+
const [resultImage, setResultImage] = (0, import_react18.useState)(null);
|
|
3323
|
+
const [isAnalyzing, setIsAnalyzing] = (0, import_react18.useState)(false);
|
|
3324
|
+
const [isGeneratingImage, setIsGeneratingImage] = (0, import_react18.useState)(false);
|
|
2888
3325
|
const handleSelectImage = (index, item, frame) => {
|
|
2889
3326
|
services.onItemUsed(item);
|
|
2890
3327
|
const newImg = {
|
|
@@ -3047,14 +3484,14 @@ var LabCompare = ({ services, onResult }) => {
|
|
|
3047
3484
|
};
|
|
3048
3485
|
|
|
3049
3486
|
// src/components/labs/LabLoop.tsx
|
|
3050
|
-
var
|
|
3487
|
+
var import_react19 = require("react");
|
|
3051
3488
|
var import_jsx_runtime17 = require("react/jsx-runtime");
|
|
3052
3489
|
var LabLoop = ({ services, onResult }) => {
|
|
3053
|
-
const [rounds, setRounds] = (0,
|
|
3054
|
-
const [currentInstruction, setCurrentInstruction] = (0,
|
|
3055
|
-
const [showPickerForRound, setShowPickerForRound] = (0,
|
|
3056
|
-
const [pendingImages, setPendingImages] = (0,
|
|
3057
|
-
const [isGenerating, setIsGenerating] = (0,
|
|
3490
|
+
const [rounds, setRounds] = (0, import_react19.useState)([]);
|
|
3491
|
+
const [currentInstruction, setCurrentInstruction] = (0, import_react19.useState)("");
|
|
3492
|
+
const [showPickerForRound, setShowPickerForRound] = (0, import_react19.useState)(null);
|
|
3493
|
+
const [pendingImages, setPendingImages] = (0, import_react19.useState)([]);
|
|
3494
|
+
const [isGenerating, setIsGenerating] = (0, import_react19.useState)(false);
|
|
3058
3495
|
const currentPrompt = rounds.length > 0 ? rounds[rounds.length - 1].prompt : "";
|
|
3059
3496
|
const handleAddImage = (item, frame) => {
|
|
3060
3497
|
services.onItemUsed(item);
|
|
@@ -3218,7 +3655,7 @@ var TABS = [
|
|
|
3218
3655
|
{ key: "loop", label: "Loop", icon: "loop" }
|
|
3219
3656
|
];
|
|
3220
3657
|
var LabsTab = ({ services, onResult }) => {
|
|
3221
|
-
const [activeTab, setActiveTab] = (0,
|
|
3658
|
+
const [activeTab, setActiveTab] = (0, import_react20.useState)("remix");
|
|
3222
3659
|
return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "flex flex-col h-full overflow-hidden", children: [
|
|
3223
3660
|
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "flex border-b border-white/5 shrink-0", children: TABS.map((tab) => /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
|
|
3224
3661
|
"button",
|
|
@@ -3242,19 +3679,19 @@ var LabsTab = ({ services, onResult }) => {
|
|
|
3242
3679
|
};
|
|
3243
3680
|
|
|
3244
3681
|
// src/components/TagManagerPanel.tsx
|
|
3245
|
-
var
|
|
3682
|
+
var import_react21 = require("react");
|
|
3246
3683
|
var import_jsx_runtime19 = require("react/jsx-runtime");
|
|
3247
3684
|
function TagManagerPanel({ workspaceTags, onTagCreate, onTagUpdate, onTagDelete, onTagReorder, onTagMove }) {
|
|
3248
3685
|
const categories = Object.keys(workspaceTags.by_category).filter(
|
|
3249
3686
|
(cat) => (workspaceTags.by_category[cat] || []).some((t) => !t.is_deleted)
|
|
3250
3687
|
);
|
|
3251
|
-
const [selectedCategory, setSelectedCategory] = (0,
|
|
3688
|
+
const [selectedCategory, setSelectedCategory] = (0, import_react21.useState)(categories[0] || "");
|
|
3252
3689
|
const effectiveCategory = categories.includes(selectedCategory) ? selectedCategory : categories[0] || "";
|
|
3253
|
-
const [editingLabel, setEditingLabel] = (0,
|
|
3254
|
-
const [editState, setEditState] = (0,
|
|
3255
|
-
const [newTag, setNewTag] = (0,
|
|
3256
|
-
const [movingLabel, setMovingLabel] = (0,
|
|
3257
|
-
const [moveTarget, setMoveTarget] = (0,
|
|
3690
|
+
const [editingLabel, setEditingLabel] = (0, import_react21.useState)(null);
|
|
3691
|
+
const [editState, setEditState] = (0, import_react21.useState)({ label: "", value: "" });
|
|
3692
|
+
const [newTag, setNewTag] = (0, import_react21.useState)({ label: "", value: "" });
|
|
3693
|
+
const [movingLabel, setMovingLabel] = (0, import_react21.useState)(null);
|
|
3694
|
+
const [moveTarget, setMoveTarget] = (0, import_react21.useState)("");
|
|
3258
3695
|
const tags = (workspaceTags.by_category[effectiveCategory] || []).filter((t) => !t.is_deleted);
|
|
3259
3696
|
const otherCategories = categories.filter((c) => c !== effectiveCategory);
|
|
3260
3697
|
const startEdit = (tag) => {
|
|
@@ -3451,8 +3888,8 @@ function TagManagerPanel({ workspaceTags, onTagCreate, onTagUpdate, onTagDelete,
|
|
|
3451
3888
|
|
|
3452
3889
|
// src/components/AvatarArchitectApp.tsx
|
|
3453
3890
|
var import_jsx_runtime20 = require("react/jsx-runtime");
|
|
3454
|
-
function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onSelectMedia, buildInfo, initialHfToken, onFetchServerProjects, onServerSave, onServerLoad, onServerDelete }) {
|
|
3455
|
-
(0,
|
|
3891
|
+
function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onSelectMedia, buildInfo, initialHfToken, hfNamespace, allowDevNamespace, onFetchServerProjects, onServerSave, onServerLoad, onServerDelete }) {
|
|
3892
|
+
(0, import_react22.useEffect)(() => {
|
|
3456
3893
|
const id = "flow-styles";
|
|
3457
3894
|
if (!document.getElementById(id)) {
|
|
3458
3895
|
const style = document.createElement("style");
|
|
@@ -3461,22 +3898,92 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
3461
3898
|
document.head.appendChild(style);
|
|
3462
3899
|
}
|
|
3463
3900
|
}, []);
|
|
3464
|
-
const [showStart, setShowStart] = (0,
|
|
3465
|
-
const [layoutChoice, setLayoutChoice] = (0,
|
|
3901
|
+
const [showStart, setShowStart] = (0, import_react22.useState)(true);
|
|
3902
|
+
const [layoutChoice, setLayoutChoice] = (0, import_react22.useState)(() => {
|
|
3466
3903
|
try {
|
|
3467
3904
|
return localStorage.getItem("aa-layout") || null;
|
|
3468
3905
|
} catch {
|
|
3469
3906
|
return null;
|
|
3470
3907
|
}
|
|
3471
3908
|
});
|
|
3472
|
-
const [projectLoaded, setProjectLoaded] = (0,
|
|
3473
|
-
const [hfToken, setHfToken] = (0,
|
|
3474
|
-
const [hfTokenInput, setHfTokenInput] = (0,
|
|
3475
|
-
const [isLoadingFromHF, setIsLoadingFromHF] = (0,
|
|
3476
|
-
const [
|
|
3477
|
-
|
|
3478
|
-
|
|
3479
|
-
|
|
3909
|
+
const [projectLoaded, setProjectLoaded] = (0, import_react22.useState)(false);
|
|
3910
|
+
const [hfToken, setHfToken] = (0, import_react22.useState)(initialHfToken || "");
|
|
3911
|
+
const [hfTokenInput, setHfTokenInput] = (0, import_react22.useState)(initialHfToken || "");
|
|
3912
|
+
const [isLoadingFromHF, setIsLoadingFromHF] = (0, import_react22.useState)(false);
|
|
3913
|
+
const [hfNamespaceLocal, setHfNamespaceLocal] = (0, import_react22.useState)(() => {
|
|
3914
|
+
try {
|
|
3915
|
+
const stored = localStorage.getItem("aa-hf-namespace");
|
|
3916
|
+
if (stored !== null) return stored;
|
|
3917
|
+
return allowDevNamespace ? "app.art-by-rolands.de/" : "";
|
|
3918
|
+
} catch {
|
|
3919
|
+
return "";
|
|
3920
|
+
}
|
|
3921
|
+
});
|
|
3922
|
+
const [hfNamespaceFromServer, setHfNamespaceFromServer] = (0, import_react22.useState)(null);
|
|
3923
|
+
(0, import_react22.useEffect)(() => {
|
|
3924
|
+
if (hfNamespace !== void 0) return;
|
|
3925
|
+
const backendUrl = typeof window !== "undefined" ? window.BACKEND_URL || window.location.origin : null;
|
|
3926
|
+
if (!backendUrl) return;
|
|
3927
|
+
fetch(`${backendUrl}/api/status`).then((r) => r.json()).then((d) => {
|
|
3928
|
+
if (typeof d.hfNamespace === "string" && d.hfNamespace) setHfNamespaceFromServer(d.hfNamespace);
|
|
3929
|
+
}).catch(() => {
|
|
3930
|
+
});
|
|
3931
|
+
}, [hfNamespace]);
|
|
3932
|
+
const effectiveNamespace = hfNamespace ?? hfNamespaceFromServer ?? hfNamespaceLocal;
|
|
3933
|
+
const {
|
|
3934
|
+
state: hfState,
|
|
3935
|
+
isLoading: isHfRefreshing,
|
|
3936
|
+
pendingBufferCount,
|
|
3937
|
+
eventCount,
|
|
3938
|
+
writeEvent: hfWriteEvent,
|
|
3939
|
+
refresh: refreshHF,
|
|
3940
|
+
hasStateZip
|
|
3941
|
+
} = useHFState(hfToken, effectiveNamespace);
|
|
3942
|
+
const [bootstrapLog, setBootstrapLog] = (0, import_react22.useState)([]);
|
|
3943
|
+
const [isBootstrapping, setIsBootstrapping] = (0, import_react22.useState)(false);
|
|
3944
|
+
const syncTopSlot = /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_jsx_runtime20.Fragment, { children: [
|
|
3945
|
+
pendingBufferCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { style: { background: "linear-gradient(90deg,#f59e0b,#ef4444)", padding: "4px 10px", fontSize: 11, color: "#fff", borderRadius: 4, marginBottom: 4 }, children: [
|
|
3946
|
+
pendingBufferCount,
|
|
3947
|
+
" \xC4nderung",
|
|
3948
|
+
pendingBufferCount > 1 ? "en" : "",
|
|
3949
|
+
" lokal \u2014 bei Flow-Reload verloren wenn nicht synchronisiert"
|
|
3950
|
+
] }),
|
|
3951
|
+
eventCount > 100 && /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { style: { background: "#dc2626", color: "#fff", padding: "5px 10px", borderRadius: 4, marginBottom: 4, fontWeight: 600, fontSize: 11 }, children: [
|
|
3952
|
+
"\u26A0 ",
|
|
3953
|
+
eventCount,
|
|
3954
|
+
" Events nicht konsolidiert \u2014 Konsolidierung dringend empfohlen"
|
|
3955
|
+
] }),
|
|
3956
|
+
eventCount > 50 && eventCount <= 100 && /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { style: { background: "#44403c", color: "#a8a29e", padding: "4px 10px", borderRadius: 4, marginBottom: 4, fontSize: 11 }, children: [
|
|
3957
|
+
eventCount,
|
|
3958
|
+
" Events seit letzter Konsolidierung \u2014 Konsolidierung empfohlen"
|
|
3959
|
+
] }),
|
|
3960
|
+
hfToken && !hasStateZip && !isHfRefreshing && /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { style: { background: "#1c1917", border: "1px solid #44403c", borderRadius: 6, padding: "10px 12px" }, children: [
|
|
3961
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { style: { fontSize: 12, color: "#a8a29e", marginBottom: 6 }, children: effectiveNamespace ? `Kein State-Snapshot in HF (${effectiveNamespace}) \u2014 aus Legacy-Daten (tags.json + metadata.json) migrieren?` : "Namespace wird geladen\u2026" }),
|
|
3962
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
3963
|
+
"button",
|
|
3964
|
+
{
|
|
3965
|
+
disabled: isBootstrapping || !effectiveNamespace,
|
|
3966
|
+
onClick: async () => {
|
|
3967
|
+
setIsBootstrapping(true);
|
|
3968
|
+
setBootstrapLog([]);
|
|
3969
|
+
try {
|
|
3970
|
+
await hfBootstrapFromLegacy(effectiveNamespace, hfToken, (msg) => setBootstrapLog((prev) => [...prev, msg]));
|
|
3971
|
+
setBootstrapLog((prev) => [...prev, "\u2713 Fertig"]);
|
|
3972
|
+
setTimeout(() => refreshHF(), 1500);
|
|
3973
|
+
} catch (e) {
|
|
3974
|
+
setBootstrapLog((prev) => [...prev, `Fehler: ${e.message}`]);
|
|
3975
|
+
} finally {
|
|
3976
|
+
setIsBootstrapping(false);
|
|
3977
|
+
}
|
|
3978
|
+
},
|
|
3979
|
+
style: { padding: "5px 12px", background: "#0ea5e9", color: "#fff", border: "none", borderRadius: 4, cursor: isBootstrapping || !effectiveNamespace ? "not-allowed" : "pointer", fontSize: 11, fontWeight: 600, opacity: isBootstrapping || !effectiveNamespace ? 0.6 : 1 },
|
|
3980
|
+
children: isBootstrapping ? "Migriere\u2026" : "Legacy-Migration starten"
|
|
3981
|
+
}
|
|
3982
|
+
),
|
|
3983
|
+
bootstrapLog.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { style: { marginTop: 6, fontFamily: "monospace", fontSize: 10, color: "#78716c", lineHeight: 1.6 }, children: bootstrapLog.map((l, i) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { children: l }, i)) })
|
|
3984
|
+
] })
|
|
3985
|
+
] });
|
|
3986
|
+
const wsInputRef = (0, import_react22.useRef)(null);
|
|
3480
3987
|
const startApp = (choice) => {
|
|
3481
3988
|
try {
|
|
3482
3989
|
localStorage.setItem("aa-layout", choice);
|
|
@@ -3485,70 +3992,110 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
3485
3992
|
setLayoutChoice(choice);
|
|
3486
3993
|
setShowStart(false);
|
|
3487
3994
|
};
|
|
3488
|
-
const [nodes, setNodes] = (0,
|
|
3489
|
-
const [edges, setEdges] = (0,
|
|
3490
|
-
const [history, setHistory] = (0,
|
|
3491
|
-
const [galleryItems, setGalleryItems] = (0,
|
|
3492
|
-
const galleryItemsRef = (0,
|
|
3493
|
-
(0,
|
|
3995
|
+
const [nodes, setNodes] = (0, import_react22.useState)([{ id: "1", type: "custom", position: { x: 0, y: 0 }, data: { label: "Fine Art Project", placeholder: "Name..." } }]);
|
|
3996
|
+
const [edges, setEdges] = (0, import_react22.useState)([]);
|
|
3997
|
+
const [history, setHistory] = (0, import_react22.useState)([]);
|
|
3998
|
+
const [galleryItems, setGalleryItems] = (0, import_react22.useState)([]);
|
|
3999
|
+
const galleryItemsRef = (0, import_react22.useRef)([]);
|
|
4000
|
+
(0, import_react22.useEffect)(() => {
|
|
3494
4001
|
galleryItemsRef.current = galleryItems;
|
|
3495
4002
|
}, [galleryItems]);
|
|
3496
|
-
const
|
|
3497
|
-
|
|
3498
|
-
|
|
3499
|
-
|
|
3500
|
-
|
|
3501
|
-
|
|
3502
|
-
|
|
3503
|
-
|
|
3504
|
-
|
|
3505
|
-
|
|
3506
|
-
|
|
3507
|
-
|
|
3508
|
-
|
|
3509
|
-
|
|
3510
|
-
|
|
3511
|
-
|
|
3512
|
-
|
|
3513
|
-
|
|
3514
|
-
|
|
3515
|
-
|
|
4003
|
+
const hfImageNotFoundRef = (0, import_react22.useRef)(/* @__PURE__ */ new Set());
|
|
4004
|
+
(0, import_react22.useEffect)(() => {
|
|
4005
|
+
if (!hfState) return;
|
|
4006
|
+
if (hfState.tags?.by_category) setWorkspaceTags(hfState.tags);
|
|
4007
|
+
const hfIds = new Set(hfState.metadata.map((m) => m.id));
|
|
4008
|
+
const skeletons = hfState.metadata.map((m) => ({
|
|
4009
|
+
id: m.id,
|
|
4010
|
+
nodeId: m.id,
|
|
4011
|
+
prompt: m.prompt,
|
|
4012
|
+
seed: m.seed,
|
|
4013
|
+
model: m.model,
|
|
4014
|
+
tags: m.tags || [],
|
|
4015
|
+
timestamp: m.timestamp,
|
|
4016
|
+
status: "done"
|
|
4017
|
+
}));
|
|
4018
|
+
setGalleryItems((prev) => {
|
|
4019
|
+
const localOnly = prev.filter((g) => !hfIds.has(g.id));
|
|
4020
|
+
const merged = skeletons.map((s) => prev.find((g) => g.id === s.id) ?? s);
|
|
4021
|
+
return [...localOnly, ...merged];
|
|
4022
|
+
});
|
|
4023
|
+
setHistory((prev) => {
|
|
4024
|
+
const localOnly = prev.filter((g) => !hfIds.has(g.id));
|
|
4025
|
+
const merged = skeletons.map((s) => prev.find((g) => g.id === s.id) ?? s);
|
|
4026
|
+
return [...localOnly, ...merged];
|
|
4027
|
+
});
|
|
4028
|
+
for (const entry of hfState.metadata) {
|
|
4029
|
+
if (hfImageNotFoundRef.current.has(entry.id)) continue;
|
|
4030
|
+
hfLoadImageAsBase64(entry.id, hfToken).then((b64) => {
|
|
4031
|
+
if (!b64) {
|
|
4032
|
+
hfImageNotFoundRef.current.add(entry.id);
|
|
4033
|
+
return;
|
|
4034
|
+
}
|
|
4035
|
+
const prefix = `data:${entry.mimeType || "image/jpeg"};base64,`;
|
|
4036
|
+
setGalleryItems((prev) => prev.map((g) => g.id === entry.id && !g.base64 ? { ...g, base64: prefix + b64 } : g));
|
|
4037
|
+
setHistory((prev) => prev.map((g) => g.id === entry.id && !g.base64 ? { ...g, base64: prefix + b64 } : g));
|
|
4038
|
+
}).catch(() => {
|
|
4039
|
+
hfImageNotFoundRef.current.add(entry.id);
|
|
4040
|
+
});
|
|
4041
|
+
}
|
|
4042
|
+
}, [hfState]);
|
|
4043
|
+
const [activePrompt, setActivePrompt] = (0, import_react22.useState)("");
|
|
4044
|
+
const [isSynthesizing, setIsSynthesizing] = (0, import_react22.useState)(false);
|
|
4045
|
+
const [activeGenerationsCount, setActiveGenerationsCount] = (0, import_react22.useState)(0);
|
|
4046
|
+
const [currentResult, setCurrentResult] = (0, import_react22.useState)(null);
|
|
4047
|
+
const [focusedNodeId, setFocusedNodeId] = (0, import_react22.useState)(null);
|
|
4048
|
+
const [leftTab, setLeftTab] = (0, import_react22.useState)("prompt");
|
|
4049
|
+
const [promptFeedback, setPromptFeedback] = (0, import_react22.useState)(null);
|
|
4050
|
+
const [lastPromptPayload, setLastPromptPayload] = (0, import_react22.useState)(null);
|
|
4051
|
+
const [isPromptTabGenerating, setIsPromptTabGenerating] = (0, import_react22.useState)(false);
|
|
4052
|
+
const [activeTab, setActiveTab] = (0, import_react22.useState)("history");
|
|
4053
|
+
const [mobileTab, setMobileTab] = (0, import_react22.useState)("stage");
|
|
4054
|
+
const [middlePanel, setMiddlePanel] = (0, import_react22.useState)("stage");
|
|
4055
|
+
const [recentLabItems, setRecentLabItems] = (0, import_react22.useState)([]);
|
|
4056
|
+
const [aspectRatio, setAspectRatio] = (0, import_react22.useState)("1:1");
|
|
4057
|
+
const [selectedModel, setSelectedModel] = (0, import_react22.useState)("\u{1F34C} Nano Banana Pro");
|
|
4058
|
+
const [seed, setSeed] = (0, import_react22.useState)(Math.floor(Math.random() * 1e6));
|
|
4059
|
+
const [seedMode, setSeedMode] = (0, import_react22.useState)("random");
|
|
4060
|
+
const [isLeftCollapsed, setIsLeftCollapsed] = (0, import_react22.useState)(false);
|
|
4061
|
+
const [isRightCollapsed, setIsRightCollapsed] = (0, import_react22.useState)(false);
|
|
4062
|
+
const [leftPanelWidth, setLeftPanelWidth] = (0, import_react22.useState)(() => {
|
|
3516
4063
|
try {
|
|
3517
4064
|
return parseInt(localStorage.getItem("aa-left-width") || "260", 10);
|
|
3518
4065
|
} catch {
|
|
3519
4066
|
return 260;
|
|
3520
4067
|
}
|
|
3521
4068
|
});
|
|
3522
|
-
const [rightPanelWidth, setRightPanelWidth] = (0,
|
|
4069
|
+
const [rightPanelWidth, setRightPanelWidth] = (0, import_react22.useState)(() => {
|
|
3523
4070
|
try {
|
|
3524
4071
|
return parseInt(localStorage.getItem("aa-right-width") || "320", 10);
|
|
3525
4072
|
} catch {
|
|
3526
4073
|
return 320;
|
|
3527
4074
|
}
|
|
3528
4075
|
});
|
|
3529
|
-
const [isPromptCollapsed, setIsPromptCollapsed] = (0,
|
|
3530
|
-
const [projectActionState, setProjectActionState] = (0,
|
|
3531
|
-
const syncServerDataRef = (0,
|
|
3532
|
-
const [workspaceTags, setWorkspaceTags] = (0,
|
|
3533
|
-
const [serverProjects, setServerProjects] = (0,
|
|
3534
|
-
const [isLoadingFromServer, setIsLoadingFromServer] = (0,
|
|
3535
|
-
const [highContrast, setHighContrast] = (0,
|
|
4076
|
+
const [isPromptCollapsed, setIsPromptCollapsed] = (0, import_react22.useState)(false);
|
|
4077
|
+
const [projectActionState, setProjectActionState] = (0, import_react22.useState)("idle");
|
|
4078
|
+
const syncServerDataRef = (0, import_react22.useRef)(null);
|
|
4079
|
+
const [workspaceTags, setWorkspaceTags] = (0, import_react22.useState)(null);
|
|
4080
|
+
const [serverProjects, setServerProjects] = (0, import_react22.useState)([]);
|
|
4081
|
+
const [isLoadingFromServer, setIsLoadingFromServer] = (0, import_react22.useState)(false);
|
|
4082
|
+
const [highContrast, setHighContrast] = (0, import_react22.useState)(() => {
|
|
3536
4083
|
try {
|
|
3537
4084
|
return localStorage.getItem("aa-contrast") === "high";
|
|
3538
4085
|
} catch {
|
|
3539
4086
|
return false;
|
|
3540
4087
|
}
|
|
3541
4088
|
});
|
|
3542
|
-
const [activeReferenceId, setActiveReferenceId] = (0,
|
|
3543
|
-
const [activeReferenceThumbnail, setActiveReferenceThumbnail] = (0,
|
|
3544
|
-
const [isScanningImage, setIsScanningImage] = (0,
|
|
3545
|
-
const [touchStartX, setTouchStartX] = (0,
|
|
3546
|
-
const [isFullscreen, setIsFullscreen] = (0,
|
|
3547
|
-
const [zoomScale, setZoomScale] = (0,
|
|
3548
|
-
const [zoomOffset, setZoomOffset] = (0,
|
|
3549
|
-
const lastPinchDist = (0,
|
|
3550
|
-
const lastTapTime = (0,
|
|
3551
|
-
const dragStart = (0,
|
|
4089
|
+
const [activeReferenceId, setActiveReferenceId] = (0, import_react22.useState)(null);
|
|
4090
|
+
const [activeReferenceThumbnail, setActiveReferenceThumbnail] = (0, import_react22.useState)(null);
|
|
4091
|
+
const [isScanningImage, setIsScanningImage] = (0, import_react22.useState)(false);
|
|
4092
|
+
const [touchStartX, setTouchStartX] = (0, import_react22.useState)(null);
|
|
4093
|
+
const [isFullscreen, setIsFullscreen] = (0, import_react22.useState)(false);
|
|
4094
|
+
const [zoomScale, setZoomScale] = (0, import_react22.useState)(1);
|
|
4095
|
+
const [zoomOffset, setZoomOffset] = (0, import_react22.useState)({ x: 0, y: 0 });
|
|
4096
|
+
const lastPinchDist = (0, import_react22.useRef)(null);
|
|
4097
|
+
const lastTapTime = (0, import_react22.useRef)(0);
|
|
4098
|
+
const dragStart = (0, import_react22.useRef)(null);
|
|
3552
4099
|
const openFullscreen = () => {
|
|
3553
4100
|
setIsFullscreen(true);
|
|
3554
4101
|
setZoomScale(1);
|
|
@@ -3611,7 +4158,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
3611
4158
|
setActiveReferenceId(null);
|
|
3612
4159
|
setActiveReferenceThumbnail(null);
|
|
3613
4160
|
};
|
|
3614
|
-
const labServices = (0,
|
|
4161
|
+
const labServices = (0, import_react22.useMemo)(() => {
|
|
3615
4162
|
const available = groupGenerationsToLabItems([...galleryItems, ...history]);
|
|
3616
4163
|
return {
|
|
3617
4164
|
availableItems: available,
|
|
@@ -3691,17 +4238,17 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
3691
4238
|
setIsScanningImage(false);
|
|
3692
4239
|
}
|
|
3693
4240
|
};
|
|
3694
|
-
const currentIndex = (0,
|
|
3695
|
-
const goToPrev = (0,
|
|
4241
|
+
const currentIndex = (0, import_react22.useMemo)(() => history.findIndex((h) => h.id === currentResult?.id), [history, currentResult]);
|
|
4242
|
+
const goToPrev = (0, import_react22.useCallback)(() => {
|
|
3696
4243
|
if (currentIndex > 0) setCurrentResult(history[currentIndex - 1]);
|
|
3697
4244
|
}, [currentIndex, history]);
|
|
3698
|
-
const goToNext = (0,
|
|
4245
|
+
const goToNext = (0, import_react22.useCallback)(() => {
|
|
3699
4246
|
if (currentIndex < history.length - 1) setCurrentResult(history[currentIndex + 1]);
|
|
3700
4247
|
}, [currentIndex, history]);
|
|
3701
4248
|
const hcStyle = highContrast ? { filter: "brightness(1.6) contrast(1.05)" } : void 0;
|
|
3702
4249
|
const isGenerating = activeGenerationsCount > 0;
|
|
3703
4250
|
useKeyboardNavigation(history, currentResult, setCurrentResult);
|
|
3704
|
-
const getSubtreeFormat = (0,
|
|
4251
|
+
const getSubtreeFormat = (0, import_react22.useCallback)((nodeId, depth = 0) => {
|
|
3705
4252
|
const node = nodes.find((n) => n.id === nodeId);
|
|
3706
4253
|
if (!node) return "";
|
|
3707
4254
|
const childrenIds = edges.filter((e) => e.source === nodeId).map((e) => e.target);
|
|
@@ -3709,7 +4256,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
3709
4256
|
return `${indent}- ${node.data.label || "(unbenannt)"}
|
|
3710
4257
|
` + childrenIds.map((id) => getSubtreeFormat(id, depth + 1)).join("");
|
|
3711
4258
|
}, [nodes, edges]);
|
|
3712
|
-
const activePath = (0,
|
|
4259
|
+
const activePath = (0, import_react22.useMemo)(() => {
|
|
3713
4260
|
if (!focusedNodeId) return /* @__PURE__ */ new Set();
|
|
3714
4261
|
const path = /* @__PURE__ */ new Set([focusedNodeId]);
|
|
3715
4262
|
let currId = focusedNodeId;
|
|
@@ -3741,7 +4288,11 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
3741
4288
|
if (prev.id === genId || !options.silent) return finishedGen;
|
|
3742
4289
|
return prev;
|
|
3743
4290
|
});
|
|
3744
|
-
|
|
4291
|
+
console.log("[HF] handleGenerateImage \u2014 condition check:", { hfToken: !!hfToken, base64: !!base64, effectiveNamespace });
|
|
4292
|
+
if (hfToken && base64 && effectiveNamespace) {
|
|
4293
|
+
hfUploadImage(base64, genId, hfToken).catch((e) => {
|
|
4294
|
+
console.error("[HF] hfUploadImage failed:", e);
|
|
4295
|
+
});
|
|
3745
4296
|
const entry = {
|
|
3746
4297
|
id: genId,
|
|
3747
4298
|
prompt: promptToUse || void 0,
|
|
@@ -3751,20 +4302,9 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
3751
4302
|
timestamp: Date.now(),
|
|
3752
4303
|
mimeType: "image/jpeg"
|
|
3753
4304
|
};
|
|
3754
|
-
|
|
3755
|
-
|
|
3756
|
-
|
|
3757
|
-
hfMetaSaveQueue.current = hfMetaSaveQueue.current.then(async () => {
|
|
3758
|
-
try {
|
|
3759
|
-
const existing = await hfLoadMetadata(token);
|
|
3760
|
-
const ids = new Set((existing || []).map((e) => e.id));
|
|
3761
|
-
if (!ids.has(genId)) {
|
|
3762
|
-
const next = [...existing || [], entry];
|
|
3763
|
-
await hfSaveMetadata(next, token);
|
|
3764
|
-
setHfMetadata(next);
|
|
3765
|
-
}
|
|
3766
|
-
} catch {
|
|
3767
|
-
}
|
|
4305
|
+
console.log("[HF] calling hfWriteEvent, namespace:", effectiveNamespace);
|
|
4306
|
+
hfWriteEvent("image_added", entry).catch((e) => {
|
|
4307
|
+
console.error("[HF] hfWriteEvent outer catch:", e);
|
|
3768
4308
|
});
|
|
3769
4309
|
}
|
|
3770
4310
|
} catch (err) {
|
|
@@ -3800,6 +4340,11 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
3800
4340
|
all: [...prev.all, { ...newTagOption, category: tag.category }]
|
|
3801
4341
|
};
|
|
3802
4342
|
});
|
|
4343
|
+
if (hfToken && effectiveNamespace) {
|
|
4344
|
+
const p = { category: tag.category, label: tag.label, value: tag.value, is_user_created: true };
|
|
4345
|
+
hfWriteEvent("tag_upserted", p).catch(() => {
|
|
4346
|
+
});
|
|
4347
|
+
}
|
|
3803
4348
|
};
|
|
3804
4349
|
const handleTagUpdate = (originalLabel, originalCategory, updates) => {
|
|
3805
4350
|
setWorkspaceTags((prev) => {
|
|
@@ -3812,8 +4357,14 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
3812
4357
|
);
|
|
3813
4358
|
return { by_category: { ...prev.by_category, [originalCategory]: updatedCat }, all: updatedAll };
|
|
3814
4359
|
});
|
|
4360
|
+
if (hfToken && effectiveNamespace) {
|
|
4361
|
+
const p = { category: originalCategory, label: updates.label, value: updates.value, is_user_created: true };
|
|
4362
|
+
hfWriteEvent("tag_upserted", p).catch(() => {
|
|
4363
|
+
});
|
|
4364
|
+
}
|
|
3815
4365
|
};
|
|
3816
4366
|
const handleTagDelete = (label, category) => {
|
|
4367
|
+
const tagValue = workspaceTags?.by_category[category]?.find((t) => t.label === label)?.value;
|
|
3817
4368
|
setWorkspaceTags((prev) => {
|
|
3818
4369
|
if (!prev) return prev;
|
|
3819
4370
|
const updatedCat = (prev.by_category[category] || []).map(
|
|
@@ -3824,6 +4375,11 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
3824
4375
|
);
|
|
3825
4376
|
return { by_category: { ...prev.by_category, [category]: updatedCat }, all: updatedAll };
|
|
3826
4377
|
});
|
|
4378
|
+
if (hfToken && effectiveNamespace && tagValue) {
|
|
4379
|
+
const p = { category, label, value: tagValue, is_deleted: true };
|
|
4380
|
+
hfWriteEvent("tag_upserted", p).catch(() => {
|
|
4381
|
+
});
|
|
4382
|
+
}
|
|
3827
4383
|
};
|
|
3828
4384
|
const handleTagReorder = (category, reorderedTags) => {
|
|
3829
4385
|
setWorkspaceTags((prev) => {
|
|
@@ -3973,38 +4529,39 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
3973
4529
|
await fetchServerProjects();
|
|
3974
4530
|
};
|
|
3975
4531
|
const handleHfInitialSync = async (onProgress) => {
|
|
3976
|
-
if (!hfToken) return;
|
|
3977
|
-
const
|
|
4532
|
+
if (!hfToken || !effectiveNamespace) return;
|
|
4533
|
+
const existingIds = new Set((hfState?.metadata || []).map((m) => m.id));
|
|
4534
|
+
const gens = galleryItems.filter((g) => g.base64 && g.status === "done" && !existingIds.has(g.id));
|
|
3978
4535
|
const total = gens.length;
|
|
3979
4536
|
onProgress(0, total);
|
|
3980
4537
|
let done = 0;
|
|
3981
4538
|
for (const gen of gens) {
|
|
3982
4539
|
const raw = gen.base64.includes(",") ? gen.base64.split(",")[1] : gen.base64;
|
|
3983
4540
|
const mimeType = gen.base64.startsWith("data:image/png") ? "image/png" : "image/jpeg";
|
|
3984
|
-
await hfUploadImage(raw, gen.id, hfToken, mimeType)
|
|
4541
|
+
await hfUploadImage(raw, gen.id, hfToken, mimeType).catch(() => {
|
|
4542
|
+
});
|
|
4543
|
+
const entry = {
|
|
4544
|
+
id: gen.id,
|
|
4545
|
+
prompt: gen.prompt || void 0,
|
|
4546
|
+
seed: gen.seed,
|
|
4547
|
+
model: gen.model,
|
|
4548
|
+
tags: gen.tags || [],
|
|
4549
|
+
timestamp: gen.timestamp,
|
|
4550
|
+
mimeType
|
|
4551
|
+
};
|
|
4552
|
+
await hfWriteEvent("image_added", entry).catch(() => {
|
|
4553
|
+
});
|
|
3985
4554
|
done++;
|
|
3986
4555
|
onProgress(done, total);
|
|
3987
4556
|
}
|
|
3988
|
-
const localEntries = gens.map((g) => ({
|
|
3989
|
-
id: g.id,
|
|
3990
|
-
prompt: g.prompt || void 0,
|
|
3991
|
-
seed: g.seed,
|
|
3992
|
-
model: g.model,
|
|
3993
|
-
tags: g.tags || [],
|
|
3994
|
-
timestamp: g.timestamp,
|
|
3995
|
-
mimeType: g.base64.startsWith("data:image/png") ? "image/png" : "image/jpeg"
|
|
3996
|
-
}));
|
|
3997
|
-
const existingMeta = await hfLoadMetadata(hfToken);
|
|
3998
|
-
const existingIds = new Set((existingMeta || []).map((e) => e.id));
|
|
3999
|
-
const newEntries = localEntries.filter((e) => !existingIds.has(e.id));
|
|
4000
|
-
const mergedMeta = [...existingMeta || [], ...newEntries];
|
|
4001
|
-
await hfSaveMetadata(mergedMeta, hfToken);
|
|
4002
|
-
setHfMetadata(mergedMeta);
|
|
4003
4557
|
if (workspaceTags) {
|
|
4004
|
-
const
|
|
4005
|
-
|
|
4006
|
-
|
|
4007
|
-
|
|
4558
|
+
for (const [category, tags] of Object.entries(workspaceTags.by_category)) {
|
|
4559
|
+
for (const tag of tags) {
|
|
4560
|
+
const p = { category, label: tag.label, value: tag.value, is_user_created: tag.is_user_created, is_deleted: tag.is_deleted };
|
|
4561
|
+
await hfWriteEvent("tag_upserted", p).catch(() => {
|
|
4562
|
+
});
|
|
4563
|
+
}
|
|
4564
|
+
}
|
|
4008
4565
|
}
|
|
4009
4566
|
};
|
|
4010
4567
|
const handleComputeSyncDiff = async () => {
|
|
@@ -4043,87 +4600,9 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
4043
4600
|
setTimeout(() => setProjectActionState("idle"), 4e3);
|
|
4044
4601
|
}
|
|
4045
4602
|
};
|
|
4046
|
-
(0,
|
|
4603
|
+
(0, import_react22.useEffect)(() => {
|
|
4047
4604
|
if (activeTab === "setup" || activeTab === "sync") fetchServerProjects();
|
|
4048
4605
|
}, [activeTab]);
|
|
4049
|
-
const [isHfRefreshing, setIsHfRefreshing] = (0, import_react21.useState)(false);
|
|
4050
|
-
const loadFromHF = (0, import_react21.useCallback)(async (token) => {
|
|
4051
|
-
setIsHfRefreshing(true);
|
|
4052
|
-
try {
|
|
4053
|
-
hfLoadTags(token).then((tags) => {
|
|
4054
|
-
if (tags?.by_category) setWorkspaceTags(tags);
|
|
4055
|
-
}).catch(() => {
|
|
4056
|
-
});
|
|
4057
|
-
const entries = await hfLoadMetadata(token);
|
|
4058
|
-
if (!Array.isArray(entries) || entries.length === 0) return;
|
|
4059
|
-
setHfMetadata(entries);
|
|
4060
|
-
const hfIds = new Set(entries.map((e) => e.id));
|
|
4061
|
-
const hfSkeletons = entries.map((e) => ({
|
|
4062
|
-
id: e.id,
|
|
4063
|
-
nodeId: e.id,
|
|
4064
|
-
prompt: e.prompt,
|
|
4065
|
-
seed: e.seed,
|
|
4066
|
-
model: e.model,
|
|
4067
|
-
tags: e.tags || [],
|
|
4068
|
-
timestamp: e.timestamp,
|
|
4069
|
-
status: "done"
|
|
4070
|
-
}));
|
|
4071
|
-
setGalleryItems((prev) => {
|
|
4072
|
-
const localOnly = prev.filter((g) => !hfIds.has(g.id));
|
|
4073
|
-
const merged = hfSkeletons.map((s) => prev.find((g) => g.id === s.id) ?? s);
|
|
4074
|
-
return [...localOnly, ...merged];
|
|
4075
|
-
});
|
|
4076
|
-
setHistory((prev) => {
|
|
4077
|
-
const localOnly = prev.filter((g) => !hfIds.has(g.id));
|
|
4078
|
-
const merged = hfSkeletons.map((s) => prev.find((g) => g.id === s.id) ?? s);
|
|
4079
|
-
return [...localOnly, ...merged];
|
|
4080
|
-
});
|
|
4081
|
-
for (const entry of entries) {
|
|
4082
|
-
hfLoadImageAsBase64(entry.id, token).then((b64) => {
|
|
4083
|
-
if (!b64) return;
|
|
4084
|
-
const prefix = `data:${entry.mimeType || "image/jpeg"};base64,`;
|
|
4085
|
-
setGalleryItems((prev) => prev.map((g) => g.id === entry.id && !g.base64 ? { ...g, base64: prefix + b64 } : g));
|
|
4086
|
-
setHistory((prev) => prev.map((g) => g.id === entry.id && !g.base64 ? { ...g, base64: prefix + b64 } : g));
|
|
4087
|
-
}).catch(() => {
|
|
4088
|
-
});
|
|
4089
|
-
}
|
|
4090
|
-
const localOnlyItems = galleryItemsRef.current.filter((g) => !hfIds.has(g.id) && g.base64 && g.status === "done");
|
|
4091
|
-
if (localOnlyItems.length > 0) {
|
|
4092
|
-
hfMetaSaveQueue.current = hfMetaSaveQueue.current.then(async () => {
|
|
4093
|
-
try {
|
|
4094
|
-
let currentMeta = await hfLoadMetadata(token);
|
|
4095
|
-
const existingIds = new Set((currentMeta || []).map((e) => e.id));
|
|
4096
|
-
for (const gen of localOnlyItems) {
|
|
4097
|
-
if (existingIds.has(gen.id)) continue;
|
|
4098
|
-
const raw = gen.base64.includes(",") ? gen.base64.split(",")[1] : gen.base64;
|
|
4099
|
-
const mimeType = gen.base64.startsWith("data:image/png") ? "image/png" : "image/jpeg";
|
|
4100
|
-
await hfUploadImage(raw, gen.id, token, mimeType).catch(() => {
|
|
4101
|
-
});
|
|
4102
|
-
const entry = {
|
|
4103
|
-
id: gen.id,
|
|
4104
|
-
prompt: gen.prompt || void 0,
|
|
4105
|
-
seed: gen.seed,
|
|
4106
|
-
model: gen.model,
|
|
4107
|
-
tags: gen.tags || [],
|
|
4108
|
-
timestamp: gen.timestamp,
|
|
4109
|
-
mimeType
|
|
4110
|
-
};
|
|
4111
|
-
currentMeta = [...currentMeta || [], entry];
|
|
4112
|
-
existingIds.add(gen.id);
|
|
4113
|
-
}
|
|
4114
|
-
await hfSaveMetadata(currentMeta, token);
|
|
4115
|
-
setHfMetadata(currentMeta);
|
|
4116
|
-
} catch {
|
|
4117
|
-
}
|
|
4118
|
-
});
|
|
4119
|
-
}
|
|
4120
|
-
} finally {
|
|
4121
|
-
setIsHfRefreshing(false);
|
|
4122
|
-
}
|
|
4123
|
-
}, []);
|
|
4124
|
-
(0, import_react21.useEffect)(() => {
|
|
4125
|
-
if (hfToken) loadFromHF(hfToken);
|
|
4126
|
-
}, [hfToken]);
|
|
4127
4606
|
const mergeWorkspaceTags = (local, remote) => {
|
|
4128
4607
|
if (!remote?.by_category) return local;
|
|
4129
4608
|
const merged = {};
|
|
@@ -4143,22 +4622,6 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
4143
4622
|
const all = Object.entries(merged).flatMap(([cat, tags]) => tags.map((t) => ({ ...t, category: cat })));
|
|
4144
4623
|
return { by_category: merged, all };
|
|
4145
4624
|
};
|
|
4146
|
-
(0, import_react21.useEffect)(() => {
|
|
4147
|
-
if (!hfToken || !workspaceTags) return;
|
|
4148
|
-
if (hfTagSaveTimer.current) clearTimeout(hfTagSaveTimer.current);
|
|
4149
|
-
hfTagSaveTimer.current = setTimeout(async () => {
|
|
4150
|
-
const remote = await hfLoadTags(hfToken).catch(() => null);
|
|
4151
|
-
const merged = mergeWorkspaceTags(workspaceTags, remote);
|
|
4152
|
-
await hfSaveTags(merged, hfToken).catch(() => {
|
|
4153
|
-
});
|
|
4154
|
-
if (Object.values(merged.by_category).some(
|
|
4155
|
-
(tags, i) => tags.length !== Object.values(workspaceTags.by_category)[i]?.length
|
|
4156
|
-
)) setWorkspaceTags(merged);
|
|
4157
|
-
}, 1500);
|
|
4158
|
-
return () => {
|
|
4159
|
-
if (hfTagSaveTimer.current) clearTimeout(hfTagSaveTimer.current);
|
|
4160
|
-
};
|
|
4161
|
-
}, [workspaceTags, hfToken]);
|
|
4162
4625
|
if (isFullscreen && currentResult?.base64) {
|
|
4163
4626
|
const fsBase64 = currentResult.base64.startsWith("data:") ? currentResult.base64 : `data:image/png;base64,${currentResult.base64}`;
|
|
4164
4627
|
return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
|
|
@@ -4363,6 +4826,28 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
4363
4826
|
)) }),
|
|
4364
4827
|
layoutChoice === "mobile-desktop" && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "text-white/20 text-[9px] text-center", children: "Mobil-Layout skaliert f\xFCr Desktop-Modus" }),
|
|
4365
4828
|
layoutChoice === "tablet-landscape" && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "text-white/20 text-[9px] text-center", children: "2-Spalten-Layout f\xFCr Landscape-Tablet im Desktop-Mode" })
|
|
4829
|
+
] }),
|
|
4830
|
+
!hfNamespace && !hfNamespaceFromServer && /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "flex items-center gap-3 w-full max-w-[280px]", children: [
|
|
4831
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "text-white/25 text-[10px] uppercase tracking-widest font-bold", children: "State:" }),
|
|
4832
|
+
["app.art-by-rolands.de/", "dev-app.art-by-rolands.de/"].map((ns, i) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
4833
|
+
"button",
|
|
4834
|
+
{
|
|
4835
|
+
onClick: () => {
|
|
4836
|
+
setHfNamespaceLocal(ns);
|
|
4837
|
+
try {
|
|
4838
|
+
localStorage.setItem("aa-hf-namespace", ns);
|
|
4839
|
+
} catch {
|
|
4840
|
+
}
|
|
4841
|
+
},
|
|
4842
|
+
className: "px-3 py-1 rounded-lg text-[11px] font-bold transition-colors",
|
|
4843
|
+
style: {
|
|
4844
|
+
background: hfNamespaceLocal === ns ? "#e7e5e4" : "#44403c",
|
|
4845
|
+
color: hfNamespaceLocal === ns ? "#1c1917" : "#e7e5e4"
|
|
4846
|
+
},
|
|
4847
|
+
children: i === 0 ? "PROD" : "DEV"
|
|
4848
|
+
},
|
|
4849
|
+
ns
|
|
4850
|
+
))
|
|
4366
4851
|
] })
|
|
4367
4852
|
] });
|
|
4368
4853
|
}
|
|
@@ -4499,7 +4984,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
4499
4984
|
mobileTab === "browse" && /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "flex flex-col flex-1 min-h-0", children: [
|
|
4500
4985
|
/* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "flex border-b border-white/5 shrink-0", style: { height: 52 }, children: [
|
|
4501
4986
|
["history", "gallery", "inspect"].map((tab) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { onClick: () => setActiveTab(tab), className: `flex-1 flex items-center justify-center gap-1.5 transition-colors text-[11px] font-bold uppercase tracking-wide ${activeTab === tab ? "text-white border-b-2 border-white" : "text-white/30"}`, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "material-symbols-outlined text-[20px]", children: tab === "history" ? "history" : tab === "gallery" ? "photo_library" : "info" }) }, tab)),
|
|
4502
|
-
hfToken && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { onClick: () =>
|
|
4987
|
+
hfToken && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { onClick: () => refreshHF(), disabled: isHfRefreshing, className: "w-12 flex items-center justify-center text-white/20 active:text-white transition-colors disabled:opacity-30", children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: `material-symbols-outlined text-[20px]${isHfRefreshing ? " animate-spin" : ""}`, children: "sync" }) })
|
|
4503
4988
|
] }),
|
|
4504
4989
|
/* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "flex-1 overflow-hidden relative", children: [
|
|
4505
4990
|
activeTab === "history" && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(HistoryPanel, { history, currentResultId: currentResult?.id || null, onSelect: (g) => {
|
|
@@ -4597,6 +5082,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
4597
5082
|
activeTab === "sync" && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
4598
5083
|
ProjectSyncTab,
|
|
4599
5084
|
{
|
|
5085
|
+
topSlot: syncTopSlot,
|
|
4600
5086
|
onProjectExport: handleProjectExport,
|
|
4601
5087
|
onProjectImport: (f) => handleProjectImport(f),
|
|
4602
5088
|
onWorkspaceImport: handleWorkspaceImport,
|
|
@@ -4889,7 +5375,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
4889
5375
|
setActiveTab(tab);
|
|
4890
5376
|
setIsRightCollapsed(false);
|
|
4891
5377
|
}, className: `flex-1 flex items-center justify-center relative transition-colors ${activeTab === tab ? "text-white" : "text-white/20"}`, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "material-symbols-outlined text-[20px]", children: tab === "history" ? "history" : tab === "gallery" ? "photo_library" : tab === "inspect" ? "info" : tab === "setup" ? "settings" : tab === "sync" ? "cloud_sync" : "label" }) }, tab)) }),
|
|
4892
|
-
hfToken && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { onClick: () =>
|
|
5378
|
+
hfToken && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { onClick: () => refreshHF(), disabled: isHfRefreshing, className: "w-10 flex items-center justify-center text-white/20 hover:text-white/60 transition-colors disabled:opacity-30", children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: `material-symbols-outlined text-[18px]${isHfRefreshing ? " animate-spin" : ""}`, children: "sync" }) }),
|
|
4893
5379
|
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { onClick: () => setIsRightCollapsed(!isRightCollapsed), className: "w-10 flex items-center justify-center text-white/20 hover:text-white", children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "material-symbols-outlined text-[18px]", children: isRightCollapsed ? "chevron_left" : "chevron_right" }) })
|
|
4894
5380
|
] }),
|
|
4895
5381
|
!isRightCollapsed && /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "flex-1 overflow-hidden relative", children: [
|
|
@@ -4928,6 +5414,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
4928
5414
|
activeTab === "sync" && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
4929
5415
|
ProjectSyncTab,
|
|
4930
5416
|
{
|
|
5417
|
+
topSlot: syncTopSlot,
|
|
4931
5418
|
onProjectExport: handleProjectExport,
|
|
4932
5419
|
onProjectImport: (f) => handleProjectImport(f),
|
|
4933
5420
|
onWorkspaceImport: handleWorkspaceImport,
|
|
@@ -4954,6 +5441,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
4954
5441
|
}
|
|
4955
5442
|
|
|
4956
5443
|
// src/components/FaApp.tsx
|
|
5444
|
+
var import_react23 = require("react");
|
|
4957
5445
|
var import_jsx_runtime21 = require("react/jsx-runtime");
|
|
4958
5446
|
function FaApp({
|
|
4959
5447
|
onGenerateImage,
|
|
@@ -4965,12 +5453,22 @@ function FaApp({
|
|
|
4965
5453
|
onFlowUpload: _onFlowUpload,
|
|
4966
5454
|
onFlowMediaUpload: _onFlowMediaUpload,
|
|
4967
5455
|
libToken,
|
|
5456
|
+
allowDevNamespace,
|
|
5457
|
+
serverBaseUrl,
|
|
4968
5458
|
onFetchServerProjects,
|
|
4969
5459
|
onServerSave,
|
|
4970
5460
|
onServerLoad,
|
|
4971
5461
|
onServerDelete,
|
|
4972
5462
|
buildInfo
|
|
4973
5463
|
}) {
|
|
5464
|
+
const [hfNamespace, setHfNamespace] = (0, import_react23.useState)(void 0);
|
|
5465
|
+
(0, import_react23.useEffect)(() => {
|
|
5466
|
+
if (!serverBaseUrl) return;
|
|
5467
|
+
fetch(`${serverBaseUrl}/api/status`).then((r) => r.json()).then((d) => {
|
|
5468
|
+
if (typeof d.hfNamespace === "string") setHfNamespace(d.hfNamespace);
|
|
5469
|
+
}).catch(() => {
|
|
5470
|
+
});
|
|
5471
|
+
}, [serverBaseUrl]);
|
|
4974
5472
|
const wrappedPrompt = async (text, options) => {
|
|
4975
5473
|
const result = await onGeneratePrompt(text, options);
|
|
4976
5474
|
return result.text;
|
|
@@ -4982,7 +5480,9 @@ function FaApp({
|
|
|
4982
5480
|
onGeneratePrompt: wrappedPrompt,
|
|
4983
5481
|
onDownload,
|
|
4984
5482
|
onSelectMedia,
|
|
4985
|
-
initialHfToken: libToken,
|
|
5483
|
+
initialHfToken: libToken ? libToken.startsWith("hf_") ? libToken : `hf_${libToken}` : void 0,
|
|
5484
|
+
hfNamespace,
|
|
5485
|
+
allowDevNamespace: !hfNamespace && allowDevNamespace,
|
|
4986
5486
|
onFetchServerProjects,
|
|
4987
5487
|
onServerSave,
|
|
4988
5488
|
onServerLoad,
|
|
@@ -4994,7 +5494,8 @@ function FaApp({
|
|
|
4994
5494
|
|
|
4995
5495
|
// src/index.ts
|
|
4996
5496
|
init_hfStateService();
|
|
4997
|
-
|
|
5497
|
+
init_hfStateService();
|
|
5498
|
+
var LIB_VERSION = "2.0.12";
|
|
4998
5499
|
// Annotate the CommonJS export names for ESM import in node:
|
|
4999
5500
|
0 && (module.exports = {
|
|
5000
5501
|
AvatarArchitectApp,
|
|
@@ -5020,9 +5521,12 @@ var LIB_VERSION = "1.3.16";
|
|
|
5020
5521
|
SectionLabel,
|
|
5021
5522
|
SetupPanel,
|
|
5022
5523
|
TagManagerPanel,
|
|
5524
|
+
applyEvent,
|
|
5525
|
+
applyEvents,
|
|
5023
5526
|
autoLabel,
|
|
5024
5527
|
buildBlendInstruction,
|
|
5025
5528
|
buildCompareInstruction,
|
|
5529
|
+
buildDag,
|
|
5026
5530
|
buildFallbackPrompt,
|
|
5027
5531
|
buildGenerationPrompt,
|
|
5028
5532
|
buildImageGenerationOptions,
|
|
@@ -5034,27 +5538,36 @@ var LIB_VERSION = "1.3.16";
|
|
|
5034
5538
|
cleanAiResponse,
|
|
5035
5539
|
createFlowServices,
|
|
5036
5540
|
exportProjectToZip,
|
|
5541
|
+
findForks,
|
|
5542
|
+
findTips,
|
|
5037
5543
|
formatTreeToMarkdown,
|
|
5038
5544
|
frameToGeneration,
|
|
5039
5545
|
getFormattedTimestamp,
|
|
5040
5546
|
getHFToken,
|
|
5547
|
+
getSessionClientId,
|
|
5041
5548
|
groupGenerationsToLabItems,
|
|
5549
|
+
hfBatchArchive,
|
|
5550
|
+
hfBootstrapFromLegacy,
|
|
5042
5551
|
hfDeleteProject,
|
|
5043
5552
|
hfDownloadProject,
|
|
5553
|
+
hfListDir,
|
|
5044
5554
|
hfListProjects,
|
|
5045
5555
|
hfLoadImageAsBase64,
|
|
5046
|
-
hfLoadMetadata,
|
|
5047
|
-
hfLoadTags,
|
|
5048
|
-
hfSaveMetadata,
|
|
5049
|
-
hfSaveTags,
|
|
5050
5556
|
hfUploadImage,
|
|
5051
5557
|
hfUploadProjectForm,
|
|
5558
|
+
hfUploadSmallFile,
|
|
5052
5559
|
importProjectFromZip,
|
|
5053
5560
|
injectXMPMetadata,
|
|
5054
5561
|
interpretSdkError,
|
|
5562
|
+
loadHFState,
|
|
5563
|
+
loadPendingEvents,
|
|
5055
5564
|
parsePromptFile,
|
|
5056
5565
|
parsePromptResponse,
|
|
5057
5566
|
setHFToken,
|
|
5567
|
+
topoSort,
|
|
5568
|
+
tsFromEventPath,
|
|
5569
|
+
useHFState,
|
|
5058
5570
|
useKeyboardNavigation,
|
|
5059
|
-
useOnClickOutside
|
|
5571
|
+
useOnClickOutside,
|
|
5572
|
+
writeHFEvent
|
|
5060
5573
|
});
|