@rslsp1/fa-app-tools 1.3.3 → 1.3.5

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.
@@ -131,6 +131,88 @@ async function hfDeleteProject(path, token) {
131
131
  });
132
132
  if (!res.ok) throw new Error(`HF delete failed: ${res.status} ${res.statusText}`);
133
133
  }
134
+ async function hfSaveTags(workspaceTags, token) {
135
+ const content = new Blob([JSON.stringify(workspaceTags, null, 2)], { type: "application/json" });
136
+ const { uploadFile } = await import("@huggingface/hub");
137
+ await uploadFile({
138
+ repo: { type: "dataset", name: HF_REPO },
139
+ credentials: { accessToken: token },
140
+ file: { path: "tags.json", content },
141
+ branch: "main",
142
+ commitTitle: "Auto-sync tags"
143
+ });
144
+ }
145
+ async function hfLoadTags(token) {
146
+ try {
147
+ const res = await fetch(
148
+ `${HF_BASE}/datasets/${HF_REPO}/resolve/main/tags.json?download=true`,
149
+ { headers: { Authorization: `Bearer ${token}` } }
150
+ );
151
+ if (!res.ok) return null;
152
+ return res.json();
153
+ } catch {
154
+ return null;
155
+ }
156
+ }
157
+ async function hfSaveMetadata(entries, token) {
158
+ const content = new Blob([JSON.stringify(entries, null, 2)], { type: "application/json" });
159
+ const { uploadFile } = await import("@huggingface/hub");
160
+ await uploadFile({
161
+ repo: { type: "dataset", name: HF_REPO },
162
+ credentials: { accessToken: token },
163
+ file: { path: "metadata.json", content },
164
+ branch: "main",
165
+ commitTitle: "Auto-sync metadata"
166
+ });
167
+ }
168
+ async function hfLoadMetadata(token) {
169
+ try {
170
+ const res = await fetch(
171
+ `${HF_BASE}/datasets/${HF_REPO}/resolve/main/metadata.json?download=true`,
172
+ { headers: { Authorization: `Bearer ${token}` } }
173
+ );
174
+ if (!res.ok) return [];
175
+ return res.json();
176
+ } catch {
177
+ return [];
178
+ }
179
+ }
180
+ async function hfUploadImage(base64, id, token, mimeType = "image/jpeg") {
181
+ const ext = mimeType === "image/png" ? "png" : "jpg";
182
+ const binary = atob(base64);
183
+ const bytes = new Uint8Array(binary.length);
184
+ for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
185
+ const content = new Blob([bytes], { type: mimeType });
186
+ const { uploadFile } = await import("@huggingface/hub");
187
+ await uploadFile({
188
+ repo: { type: "dataset", name: HF_REPO },
189
+ credentials: { accessToken: token },
190
+ file: { path: `images/${id}.${ext}`, content },
191
+ branch: "main",
192
+ commitTitle: `Add image ${id}`
193
+ });
194
+ }
195
+ async function hfLoadImageAsBase64(id, token) {
196
+ for (const ext of ["jpg", "png"]) {
197
+ try {
198
+ const res = await fetch(
199
+ `${HF_BASE}/datasets/${HF_REPO}/resolve/main/images/${id}.${ext}?download=true`,
200
+ { headers: { Authorization: `Bearer ${token}` } }
201
+ );
202
+ if (!res.ok) continue;
203
+ const blob = await res.blob();
204
+ return new Promise((resolve, reject) => {
205
+ const reader = new FileReader();
206
+ reader.onload = () => resolve(reader.result.split(",")[1]);
207
+ reader.onerror = reject;
208
+ reader.readAsDataURL(blob);
209
+ });
210
+ } catch {
211
+ continue;
212
+ }
213
+ }
214
+ return null;
215
+ }
134
216
 
135
217
  export {
136
218
  HF_TOKEN_KEY,
@@ -140,5 +222,11 @@ export {
140
222
  hfDownloadProject,
141
223
  hfUploadProject,
142
224
  hfUploadProjectForm,
143
- hfDeleteProject
225
+ hfDeleteProject,
226
+ hfSaveTags,
227
+ hfLoadTags,
228
+ hfSaveMetadata,
229
+ hfLoadMetadata,
230
+ hfUploadImage,
231
+ hfLoadImageAsBase64
144
232
  };
@@ -4,16 +4,28 @@ import {
4
4
  hfDeleteProject,
5
5
  hfDownloadProject,
6
6
  hfListProjects,
7
+ hfLoadImageAsBase64,
8
+ hfLoadMetadata,
9
+ hfLoadTags,
10
+ hfSaveMetadata,
11
+ hfSaveTags,
12
+ hfUploadImage,
7
13
  hfUploadProject,
8
14
  hfUploadProjectForm,
9
15
  setHFToken
10
- } from "./chunk-JW5O3URT.mjs";
16
+ } from "./chunk-X6S5BP36.mjs";
11
17
  export {
12
18
  HF_TOKEN_KEY,
13
19
  getHFToken,
14
20
  hfDeleteProject,
15
21
  hfDownloadProject,
16
22
  hfListProjects,
23
+ hfLoadImageAsBase64,
24
+ hfLoadMetadata,
25
+ hfLoadTags,
26
+ hfSaveMetadata,
27
+ hfSaveTags,
28
+ hfUploadImage,
17
29
  hfUploadProject,
18
30
  hfUploadProjectForm,
19
31
  setHFToken
package/dist/index.d.mts CHANGED
@@ -97,6 +97,16 @@ interface LabServices {
97
97
  saveResult?: (item: LabItem) => Promise<void>;
98
98
  workspaceTags?: WorkspaceTags;
99
99
  }
100
+ interface HFMetadataEntry {
101
+ id: string;
102
+ prompt?: string;
103
+ seed?: number;
104
+ model?: string;
105
+ tags: string[];
106
+ timestamp: number;
107
+ mimeType: string;
108
+ size?: number;
109
+ }
100
110
 
101
111
  /**
102
112
  * Hook für die Tastaturnavigation im Detailview.
@@ -448,6 +458,26 @@ declare function buildLoopInstruction(rounds: Array<{
448
458
  declare function autoLabel(index: number): string;
449
459
  declare function buildReferenceImageMediaIds(images: SelectedLabImage[]): string[];
450
460
 
451
- declare const LIB_VERSION = "1.3.3";
461
+ declare function getHFToken(): string | null;
462
+ declare function setHFToken(token: string): void;
463
+ interface HFProjectMeta {
464
+ id: string;
465
+ name: string;
466
+ path: string;
467
+ size: number;
468
+ isLfs: boolean;
469
+ }
470
+ declare function hfListProjects(token: string): Promise<HFProjectMeta[]>;
471
+ declare function hfDownloadProject(path: string, token: string): Promise<File>;
472
+ declare function hfUploadProjectForm(zipBase64: string, name: string, token: string): Promise<HFProjectMeta>;
473
+ declare function hfDeleteProject(path: string, token: string): Promise<void>;
474
+ declare function hfSaveTags(workspaceTags: any, token: string): Promise<void>;
475
+ declare function hfLoadTags(token: string): Promise<any | null>;
476
+ declare function hfSaveMetadata(entries: any[], token: string): Promise<void>;
477
+ declare function hfLoadMetadata(token: string): Promise<any[]>;
478
+ declare function hfUploadImage(base64: string, id: string, token: string, mimeType?: string): Promise<void>;
479
+ declare function hfLoadImageAsBase64(id: string, token: string): Promise<string | null>;
480
+
481
+ declare const LIB_VERSION = "1.3.5";
452
482
 
453
- export { AvatarArchitectApp, type AvatarArchitectAppProps, CollapsibleCard, CompactDropdown, type ExtractedCharacter, FaToolsBadge, type FlowSdk, GLOBAL_STYLES, type Generation, HistoryPanel, InspectPanel, LIB_VERSION, LabBlend, LabCompare, type LabFrame, LabImagePicker, type LabItem, LabLoop, LabRemix, type LabServices, LabsTab, ListView, type MediaItem, MediaLibrary, PillButton, type ProjectMeta, type ProjectSettings, ProjectSyncTab, PromptTab, SectionLabel, type SelectedLabImage, type SelectedTag, SetupPanel, type SyncDiff, TagManagerPanel, type TagOption, type WorkspaceTags, autoLabel, buildBlendInstruction, buildCompareInstruction, buildFallbackPrompt, buildGenerationPrompt, buildImageGenerationOptions, buildLoopInstruction, buildPromptTabPayload, buildReferenceImageMediaIds, buildRemixInstruction, buildScanInstruction, cleanAiResponse, createFlowServices, exportProjectToZip, formatTreeToMarkdown, frameToGeneration, getFormattedTimestamp, groupGenerationsToLabItems, importProjectFromZip, injectXMPMetadata, interpretSdkError, parsePromptFile, parsePromptResponse, useKeyboardNavigation, useOnClickOutside };
483
+ export { AvatarArchitectApp, type AvatarArchitectAppProps, CollapsibleCard, CompactDropdown, type ExtractedCharacter, FaToolsBadge, type FlowSdk, GLOBAL_STYLES, type Generation, type HFMetadataEntry, HistoryPanel, InspectPanel, LIB_VERSION, LabBlend, LabCompare, type LabFrame, LabImagePicker, type LabItem, LabLoop, LabRemix, type LabServices, LabsTab, ListView, type MediaItem, MediaLibrary, PillButton, type ProjectMeta, type ProjectSettings, ProjectSyncTab, PromptTab, SectionLabel, type SelectedLabImage, type SelectedTag, SetupPanel, type SyncDiff, TagManagerPanel, type TagOption, type WorkspaceTags, autoLabel, buildBlendInstruction, buildCompareInstruction, buildFallbackPrompt, buildGenerationPrompt, buildImageGenerationOptions, buildLoopInstruction, buildPromptTabPayload, buildReferenceImageMediaIds, buildRemixInstruction, buildScanInstruction, cleanAiResponse, createFlowServices, exportProjectToZip, formatTreeToMarkdown, frameToGeneration, getFormattedTimestamp, getHFToken, groupGenerationsToLabItems, hfDeleteProject, hfDownloadProject, hfListProjects, hfLoadImageAsBase64, hfLoadMetadata, hfLoadTags, hfSaveMetadata, hfSaveTags, hfUploadImage, hfUploadProjectForm, importProjectFromZip, injectXMPMetadata, interpretSdkError, parsePromptFile, parsePromptResponse, setHFToken, useKeyboardNavigation, useOnClickOutside };
package/dist/index.d.ts CHANGED
@@ -97,6 +97,16 @@ interface LabServices {
97
97
  saveResult?: (item: LabItem) => Promise<void>;
98
98
  workspaceTags?: WorkspaceTags;
99
99
  }
100
+ interface HFMetadataEntry {
101
+ id: string;
102
+ prompt?: string;
103
+ seed?: number;
104
+ model?: string;
105
+ tags: string[];
106
+ timestamp: number;
107
+ mimeType: string;
108
+ size?: number;
109
+ }
100
110
 
101
111
  /**
102
112
  * Hook für die Tastaturnavigation im Detailview.
@@ -448,6 +458,26 @@ declare function buildLoopInstruction(rounds: Array<{
448
458
  declare function autoLabel(index: number): string;
449
459
  declare function buildReferenceImageMediaIds(images: SelectedLabImage[]): string[];
450
460
 
451
- declare const LIB_VERSION = "1.3.3";
461
+ declare function getHFToken(): string | null;
462
+ declare function setHFToken(token: string): void;
463
+ interface HFProjectMeta {
464
+ id: string;
465
+ name: string;
466
+ path: string;
467
+ size: number;
468
+ isLfs: boolean;
469
+ }
470
+ declare function hfListProjects(token: string): Promise<HFProjectMeta[]>;
471
+ declare function hfDownloadProject(path: string, token: string): Promise<File>;
472
+ declare function hfUploadProjectForm(zipBase64: string, name: string, token: string): Promise<HFProjectMeta>;
473
+ declare function hfDeleteProject(path: string, token: string): Promise<void>;
474
+ declare function hfSaveTags(workspaceTags: any, token: string): Promise<void>;
475
+ declare function hfLoadTags(token: string): Promise<any | null>;
476
+ declare function hfSaveMetadata(entries: any[], token: string): Promise<void>;
477
+ declare function hfLoadMetadata(token: string): Promise<any[]>;
478
+ declare function hfUploadImage(base64: string, id: string, token: string, mimeType?: string): Promise<void>;
479
+ declare function hfLoadImageAsBase64(id: string, token: string): Promise<string | null>;
480
+
481
+ declare const LIB_VERSION = "1.3.5";
452
482
 
453
- export { AvatarArchitectApp, type AvatarArchitectAppProps, CollapsibleCard, CompactDropdown, type ExtractedCharacter, FaToolsBadge, type FlowSdk, GLOBAL_STYLES, type Generation, HistoryPanel, InspectPanel, LIB_VERSION, LabBlend, LabCompare, type LabFrame, LabImagePicker, type LabItem, LabLoop, LabRemix, type LabServices, LabsTab, ListView, type MediaItem, MediaLibrary, PillButton, type ProjectMeta, type ProjectSettings, ProjectSyncTab, PromptTab, SectionLabel, type SelectedLabImage, type SelectedTag, SetupPanel, type SyncDiff, TagManagerPanel, type TagOption, type WorkspaceTags, autoLabel, buildBlendInstruction, buildCompareInstruction, buildFallbackPrompt, buildGenerationPrompt, buildImageGenerationOptions, buildLoopInstruction, buildPromptTabPayload, buildReferenceImageMediaIds, buildRemixInstruction, buildScanInstruction, cleanAiResponse, createFlowServices, exportProjectToZip, formatTreeToMarkdown, frameToGeneration, getFormattedTimestamp, groupGenerationsToLabItems, importProjectFromZip, injectXMPMetadata, interpretSdkError, parsePromptFile, parsePromptResponse, useKeyboardNavigation, useOnClickOutside };
483
+ export { AvatarArchitectApp, type AvatarArchitectAppProps, CollapsibleCard, CompactDropdown, type ExtractedCharacter, FaToolsBadge, type FlowSdk, GLOBAL_STYLES, type Generation, type HFMetadataEntry, HistoryPanel, InspectPanel, LIB_VERSION, LabBlend, LabCompare, type LabFrame, LabImagePicker, type LabItem, LabLoop, LabRemix, type LabServices, LabsTab, ListView, type MediaItem, MediaLibrary, PillButton, type ProjectMeta, type ProjectSettings, ProjectSyncTab, PromptTab, SectionLabel, type SelectedLabImage, type SelectedTag, SetupPanel, type SyncDiff, TagManagerPanel, type TagOption, type WorkspaceTags, autoLabel, buildBlendInstruction, buildCompareInstruction, buildFallbackPrompt, buildGenerationPrompt, buildImageGenerationOptions, buildLoopInstruction, buildPromptTabPayload, buildReferenceImageMediaIds, buildRemixInstruction, buildScanInstruction, cleanAiResponse, createFlowServices, exportProjectToZip, formatTreeToMarkdown, frameToGeneration, getFormattedTimestamp, getHFToken, groupGenerationsToLabItems, hfDeleteProject, hfDownloadProject, hfListProjects, hfLoadImageAsBase64, hfLoadMetadata, hfLoadTags, hfSaveMetadata, hfSaveTags, hfUploadImage, hfUploadProjectForm, importProjectFromZip, injectXMPMetadata, interpretSdkError, parsePromptFile, parsePromptResponse, setHFToken, useKeyboardNavigation, useOnClickOutside };
package/dist/index.js CHANGED
@@ -267,6 +267,12 @@ __export(hfStateService_exports, {
267
267
  hfDeleteProject: () => hfDeleteProject,
268
268
  hfDownloadProject: () => hfDownloadProject,
269
269
  hfListProjects: () => hfListProjects,
270
+ hfLoadImageAsBase64: () => hfLoadImageAsBase64,
271
+ hfLoadMetadata: () => hfLoadMetadata,
272
+ hfLoadTags: () => hfLoadTags,
273
+ hfSaveMetadata: () => hfSaveMetadata,
274
+ hfSaveTags: () => hfSaveTags,
275
+ hfUploadImage: () => hfUploadImage,
270
276
  hfUploadProject: () => hfUploadProject,
271
277
  hfUploadProjectForm: () => hfUploadProjectForm,
272
278
  setHFToken: () => setHFToken
@@ -400,6 +406,88 @@ async function hfDeleteProject(path, token) {
400
406
  });
401
407
  if (!res.ok) throw new Error(`HF delete failed: ${res.status} ${res.statusText}`);
402
408
  }
409
+ async function hfSaveTags(workspaceTags, token) {
410
+ const content = new Blob([JSON.stringify(workspaceTags, null, 2)], { type: "application/json" });
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
+ });
419
+ }
420
+ async function hfLoadTags(token) {
421
+ try {
422
+ const res = await fetch(
423
+ `${HF_BASE}/datasets/${HF_REPO}/resolve/main/tags.json?download=true`,
424
+ { headers: { Authorization: `Bearer ${token}` } }
425
+ );
426
+ if (!res.ok) return null;
427
+ return res.json();
428
+ } catch {
429
+ return null;
430
+ }
431
+ }
432
+ async function hfSaveMetadata(entries, token) {
433
+ const content = new Blob([JSON.stringify(entries, null, 2)], { type: "application/json" });
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
+ });
442
+ }
443
+ async function hfLoadMetadata(token) {
444
+ try {
445
+ const res = await fetch(
446
+ `${HF_BASE}/datasets/${HF_REPO}/resolve/main/metadata.json?download=true`,
447
+ { headers: { Authorization: `Bearer ${token}` } }
448
+ );
449
+ if (!res.ok) return [];
450
+ return res.json();
451
+ } catch {
452
+ return [];
453
+ }
454
+ }
455
+ async function hfUploadImage(base64, id, token, mimeType = "image/jpeg") {
456
+ const ext = mimeType === "image/png" ? "png" : "jpg";
457
+ const binary = atob(base64);
458
+ const bytes = new Uint8Array(binary.length);
459
+ for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
460
+ const content = new Blob([bytes], { type: mimeType });
461
+ const { uploadFile } = await import("@huggingface/hub");
462
+ await uploadFile({
463
+ repo: { type: "dataset", name: HF_REPO },
464
+ credentials: { accessToken: token },
465
+ file: { path: `images/${id}.${ext}`, content },
466
+ branch: "main",
467
+ commitTitle: `Add image ${id}`
468
+ });
469
+ }
470
+ async function hfLoadImageAsBase64(id, token) {
471
+ for (const ext of ["jpg", "png"]) {
472
+ try {
473
+ const res = await fetch(
474
+ `${HF_BASE}/datasets/${HF_REPO}/resolve/main/images/${id}.${ext}?download=true`,
475
+ { headers: { Authorization: `Bearer ${token}` } }
476
+ );
477
+ if (!res.ok) continue;
478
+ const blob = await res.blob();
479
+ return new Promise((resolve, reject) => {
480
+ const reader = new FileReader();
481
+ reader.onload = () => resolve(reader.result.split(",")[1]);
482
+ reader.onerror = reject;
483
+ reader.readAsDataURL(blob);
484
+ });
485
+ } catch {
486
+ continue;
487
+ }
488
+ }
489
+ return null;
490
+ }
403
491
  var HF_BASE, HF_REPO, HF_TOKEN_KEY;
404
492
  var init_hfStateService = __esm({
405
493
  "src/lib/hfStateService.ts"() {
@@ -452,12 +540,24 @@ __export(index_exports, {
452
540
  formatTreeToMarkdown: () => formatTreeToMarkdown,
453
541
  frameToGeneration: () => frameToGeneration,
454
542
  getFormattedTimestamp: () => getFormattedTimestamp,
543
+ getHFToken: () => getHFToken,
455
544
  groupGenerationsToLabItems: () => groupGenerationsToLabItems,
545
+ hfDeleteProject: () => hfDeleteProject,
546
+ hfDownloadProject: () => hfDownloadProject,
547
+ hfListProjects: () => hfListProjects,
548
+ hfLoadImageAsBase64: () => hfLoadImageAsBase64,
549
+ hfLoadMetadata: () => hfLoadMetadata,
550
+ hfLoadTags: () => hfLoadTags,
551
+ hfSaveMetadata: () => hfSaveMetadata,
552
+ hfSaveTags: () => hfSaveTags,
553
+ hfUploadImage: () => hfUploadImage,
554
+ hfUploadProjectForm: () => hfUploadProjectForm,
456
555
  importProjectFromZip: () => importProjectFromZip,
457
556
  injectXMPMetadata: () => injectXMPMetadata,
458
557
  interpretSdkError: () => interpretSdkError,
459
558
  parsePromptFile: () => parsePromptFile,
460
559
  parsePromptResponse: () => parsePromptResponse,
560
+ setHFToken: () => setHFToken,
461
561
  useKeyboardNavigation: () => useKeyboardNavigation,
462
562
  useOnClickOutside: () => useOnClickOutside
463
563
  });
@@ -2223,6 +2323,16 @@ function autoLabel(index) {
2223
2323
  function buildReferenceImageMediaIds(images) {
2224
2324
  return images.filter((i) => i.sendToImageGen && i.frame.mediaId).map((i) => i.frame.mediaId);
2225
2325
  }
2326
+ function toPromptImages(images) {
2327
+ return images.filter((i) => i.sendToPromptAI && i.frame.base64).map((i) => {
2328
+ const raw = i.frame.base64.includes(",") ? i.frame.base64.split(",")[1] : i.frame.base64;
2329
+ const mimeType = i.frame.base64.startsWith("data:image/png") ? "image/png" : "image/jpeg";
2330
+ return { base64: raw, mimeType };
2331
+ });
2332
+ }
2333
+
2334
+ // src/components/AvatarArchitectApp.tsx
2335
+ init_hfStateService();
2226
2336
 
2227
2337
  // src/components/labs/LabsTab.tsx
2228
2338
  var import_react19 = require("react");
@@ -2373,7 +2483,8 @@ var LabRemix = ({ services, onResult }) => {
2373
2483
  instruction,
2374
2484
  selected.item.prompt
2375
2485
  );
2376
- const images = selected.sendToPromptAI ? [{ base64: selected.frame.base64, mimeType: "image/png" }] : void 0;
2486
+ const imgs = toPromptImages([selected]);
2487
+ const images = imgs.length ? imgs : void 0;
2377
2488
  const result = await services.generateText(text, { systemInstruction, images });
2378
2489
  setGeneratedPrompt(result);
2379
2490
  } finally {
@@ -2766,7 +2877,7 @@ var LabCompare = ({ services, onResult }) => {
2766
2877
  setIsAnalyzing(true);
2767
2878
  try {
2768
2879
  const { text, systemInstruction } = buildCompareInstruction(filled, instruction);
2769
- const images = filled.filter((i) => i.sendToPromptAI).map((i) => ({ base64: i.frame.base64, mimeType: "image/png" }));
2880
+ const images = toPromptImages(filled);
2770
2881
  const result = await services.generateText(text, { systemInstruction, images: images.length ? images : void 0 });
2771
2882
  setAnalysis(result);
2772
2883
  setGeneratedPrompt("");
@@ -2934,7 +3045,7 @@ var LabLoop = ({ services, onResult }) => {
2934
3045
  images: r.images
2935
3046
  }));
2936
3047
  const { text, systemInstruction } = buildLoopInstruction(historyForBuilder, currentInstruction);
2937
- const allImages = [...rounds.flatMap((r) => r.images), ...pendingImages].filter((i) => i.sendToPromptAI).map((i) => ({ base64: i.frame.base64, mimeType: "image/png" }));
3048
+ const allImages = toPromptImages([...rounds.flatMap((r) => r.images), ...pendingImages]);
2938
3049
  const newPrompt = await services.generateText(text, {
2939
3050
  systemInstruction,
2940
3051
  images: allImages.length ? allImages : void 0
@@ -3326,6 +3437,8 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
3326
3437
  const [hfToken, setHfToken] = (0, import_react21.useState)("");
3327
3438
  const [hfTokenInput, setHfTokenInput] = (0, import_react21.useState)("");
3328
3439
  const [isLoadingFromHF, setIsLoadingFromHF] = (0, import_react21.useState)(false);
3440
+ const [hfMetadata, setHfMetadata] = (0, import_react21.useState)([]);
3441
+ const hfTagSaveTimer = (0, import_react21.useRef)(null);
3329
3442
  const wsInputRef = (0, import_react21.useRef)(null);
3330
3443
  const startApp = (choice) => {
3331
3444
  try {
@@ -3587,6 +3700,25 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
3587
3700
  if (prev.id === genId || !options.silent) return finishedGen;
3588
3701
  return prev;
3589
3702
  });
3703
+ if (hfToken && base64) {
3704
+ const entry = {
3705
+ id: genId,
3706
+ prompt: promptToUse || void 0,
3707
+ seed: seedMode === "fixed" ? seed : activeSeed,
3708
+ model: selectedModel,
3709
+ tags: [],
3710
+ timestamp: Date.now(),
3711
+ mimeType: "image/jpeg"
3712
+ };
3713
+ hfUploadImage(base64, genId, hfToken).catch(() => {
3714
+ });
3715
+ setHfMetadata((prev) => {
3716
+ const next = [...prev, entry];
3717
+ hfSaveMetadata(next, hfToken).catch(() => {
3718
+ });
3719
+ return next;
3720
+ });
3721
+ }
3590
3722
  } catch (err) {
3591
3723
  const errorGen = { ...newGen, status: "error", error: { message: err.message || "Unbekannter Fehler", details: err.toString() } };
3592
3724
  setHistory((prev) => prev.map((g) => g.id === genId ? errorGen : g));
@@ -3831,6 +3963,28 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
3831
3963
  (0, import_react21.useEffect)(() => {
3832
3964
  if (activeTab === "setup" || activeTab === "sync") fetchServerProjects();
3833
3965
  }, [activeTab]);
3966
+ (0, import_react21.useEffect)(() => {
3967
+ if (!hfToken) return;
3968
+ hfLoadTags(hfToken).then((tags) => {
3969
+ if (tags?.by_category) setWorkspaceTags(tags);
3970
+ }).catch(() => {
3971
+ });
3972
+ hfLoadMetadata(hfToken).then((entries) => {
3973
+ if (Array.isArray(entries)) setHfMetadata(entries);
3974
+ }).catch(() => {
3975
+ });
3976
+ }, [hfToken]);
3977
+ (0, import_react21.useEffect)(() => {
3978
+ if (!hfToken || !workspaceTags) return;
3979
+ if (hfTagSaveTimer.current) clearTimeout(hfTagSaveTimer.current);
3980
+ hfTagSaveTimer.current = setTimeout(() => {
3981
+ hfSaveTags(workspaceTags, hfToken).catch(() => {
3982
+ });
3983
+ }, 1500);
3984
+ return () => {
3985
+ if (hfTagSaveTimer.current) clearTimeout(hfTagSaveTimer.current);
3986
+ };
3987
+ }, [workspaceTags, hfToken]);
3834
3988
  if (isFullscreen && currentResult?.base64) {
3835
3989
  const fsBase64 = currentResult.base64.startsWith("data:") ? currentResult.base64 : `data:image/png;base64,${currentResult.base64}`;
3836
3990
  return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
@@ -3932,6 +4086,8 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
3932
4086
  "input",
3933
4087
  {
3934
4088
  type: "password",
4089
+ autoComplete: "current-password",
4090
+ id: "hf-token-input",
3935
4091
  value: hfTokenInput,
3936
4092
  onChange: (e) => setHfTokenInput(e.target.value),
3937
4093
  onKeyDown: (e) => {
@@ -4618,7 +4774,8 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
4618
4774
  }
4619
4775
 
4620
4776
  // src/index.ts
4621
- var LIB_VERSION = "1.3.3";
4777
+ init_hfStateService();
4778
+ var LIB_VERSION = "1.3.5";
4622
4779
  // Annotate the CommonJS export names for ESM import in node:
4623
4780
  0 && (module.exports = {
4624
4781
  AvatarArchitectApp,
@@ -4660,12 +4817,24 @@ var LIB_VERSION = "1.3.3";
4660
4817
  formatTreeToMarkdown,
4661
4818
  frameToGeneration,
4662
4819
  getFormattedTimestamp,
4820
+ getHFToken,
4663
4821
  groupGenerationsToLabItems,
4822
+ hfDeleteProject,
4823
+ hfDownloadProject,
4824
+ hfListProjects,
4825
+ hfLoadImageAsBase64,
4826
+ hfLoadMetadata,
4827
+ hfLoadTags,
4828
+ hfSaveMetadata,
4829
+ hfSaveTags,
4830
+ hfUploadImage,
4831
+ hfUploadProjectForm,
4664
4832
  importProjectFromZip,
4665
4833
  injectXMPMetadata,
4666
4834
  interpretSdkError,
4667
4835
  parsePromptFile,
4668
4836
  parsePromptResponse,
4837
+ setHFToken,
4669
4838
  useKeyboardNavigation,
4670
4839
  useOnClickOutside
4671
4840
  });
package/dist/index.mjs CHANGED
@@ -4,10 +4,19 @@ import {
4
4
  injectXMPMetadata
5
5
  } from "./chunk-UFXDXENC.mjs";
6
6
  import {
7
+ getHFToken,
7
8
  hfDeleteProject,
9
+ hfDownloadProject,
8
10
  hfListProjects,
9
- hfUploadProjectForm
10
- } from "./chunk-JW5O3URT.mjs";
11
+ hfLoadImageAsBase64,
12
+ hfLoadMetadata,
13
+ hfLoadTags,
14
+ hfSaveMetadata,
15
+ hfSaveTags,
16
+ hfUploadImage,
17
+ hfUploadProjectForm,
18
+ setHFToken
19
+ } from "./chunk-X6S5BP36.mjs";
11
20
 
12
21
  // src/hooks/useOnClickOutside.ts
13
22
  import { useEffect } from "react";
@@ -1547,8 +1556,8 @@ var ProjectSyncTab = ({
1547
1556
  {
1548
1557
  onClick: async () => {
1549
1558
  try {
1550
- const { hfDownloadProject } = await import("./hfStateService-UUDYKEMD.mjs");
1551
- const file = await hfDownloadProject(p.path, hfToken);
1559
+ const { hfDownloadProject: hfDownloadProject2 } = await import("./hfStateService-B62RV5K3.mjs");
1560
+ const file = await hfDownloadProject2(p.path, hfToken);
1552
1561
  onHfLoad(file);
1553
1562
  } catch (e) {
1554
1563
  setHfError(e.message);
@@ -1760,6 +1769,13 @@ function autoLabel(index) {
1760
1769
  function buildReferenceImageMediaIds(images) {
1761
1770
  return images.filter((i) => i.sendToImageGen && i.frame.mediaId).map((i) => i.frame.mediaId);
1762
1771
  }
1772
+ function toPromptImages(images) {
1773
+ return images.filter((i) => i.sendToPromptAI && i.frame.base64).map((i) => {
1774
+ const raw = i.frame.base64.includes(",") ? i.frame.base64.split(",")[1] : i.frame.base64;
1775
+ const mimeType = i.frame.base64.startsWith("data:image/png") ? "image/png" : "image/jpeg";
1776
+ return { base64: raw, mimeType };
1777
+ });
1778
+ }
1763
1779
 
1764
1780
  // src/components/labs/LabsTab.tsx
1765
1781
  import { useState as useState12 } from "react";
@@ -1910,7 +1926,8 @@ var LabRemix = ({ services, onResult }) => {
1910
1926
  instruction,
1911
1927
  selected.item.prompt
1912
1928
  );
1913
- const images = selected.sendToPromptAI ? [{ base64: selected.frame.base64, mimeType: "image/png" }] : void 0;
1929
+ const imgs = toPromptImages([selected]);
1930
+ const images = imgs.length ? imgs : void 0;
1914
1931
  const result = await services.generateText(text, { systemInstruction, images });
1915
1932
  setGeneratedPrompt(result);
1916
1933
  } finally {
@@ -2303,7 +2320,7 @@ var LabCompare = ({ services, onResult }) => {
2303
2320
  setIsAnalyzing(true);
2304
2321
  try {
2305
2322
  const { text, systemInstruction } = buildCompareInstruction(filled, instruction);
2306
- const images = filled.filter((i) => i.sendToPromptAI).map((i) => ({ base64: i.frame.base64, mimeType: "image/png" }));
2323
+ const images = toPromptImages(filled);
2307
2324
  const result = await services.generateText(text, { systemInstruction, images: images.length ? images : void 0 });
2308
2325
  setAnalysis(result);
2309
2326
  setGeneratedPrompt("");
@@ -2471,7 +2488,7 @@ var LabLoop = ({ services, onResult }) => {
2471
2488
  images: r.images
2472
2489
  }));
2473
2490
  const { text, systemInstruction } = buildLoopInstruction(historyForBuilder, currentInstruction);
2474
- const allImages = [...rounds.flatMap((r) => r.images), ...pendingImages].filter((i) => i.sendToPromptAI).map((i) => ({ base64: i.frame.base64, mimeType: "image/png" }));
2491
+ const allImages = toPromptImages([...rounds.flatMap((r) => r.images), ...pendingImages]);
2475
2492
  const newPrompt = await services.generateText(text, {
2476
2493
  systemInstruction,
2477
2494
  images: allImages.length ? allImages : void 0
@@ -2863,6 +2880,8 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
2863
2880
  const [hfToken, setHfToken] = useState14("");
2864
2881
  const [hfTokenInput, setHfTokenInput] = useState14("");
2865
2882
  const [isLoadingFromHF, setIsLoadingFromHF] = useState14(false);
2883
+ const [hfMetadata, setHfMetadata] = useState14([]);
2884
+ const hfTagSaveTimer = useRef6(null);
2866
2885
  const wsInputRef = useRef6(null);
2867
2886
  const startApp = (choice) => {
2868
2887
  try {
@@ -3124,6 +3143,25 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
3124
3143
  if (prev.id === genId || !options.silent) return finishedGen;
3125
3144
  return prev;
3126
3145
  });
3146
+ if (hfToken && base64) {
3147
+ const entry = {
3148
+ id: genId,
3149
+ prompt: promptToUse || void 0,
3150
+ seed: seedMode === "fixed" ? seed : activeSeed,
3151
+ model: selectedModel,
3152
+ tags: [],
3153
+ timestamp: Date.now(),
3154
+ mimeType: "image/jpeg"
3155
+ };
3156
+ hfUploadImage(base64, genId, hfToken).catch(() => {
3157
+ });
3158
+ setHfMetadata((prev) => {
3159
+ const next = [...prev, entry];
3160
+ hfSaveMetadata(next, hfToken).catch(() => {
3161
+ });
3162
+ return next;
3163
+ });
3164
+ }
3127
3165
  } catch (err) {
3128
3166
  const errorGen = { ...newGen, status: "error", error: { message: err.message || "Unbekannter Fehler", details: err.toString() } };
3129
3167
  setHistory((prev) => prev.map((g) => g.id === genId ? errorGen : g));
@@ -3368,6 +3406,28 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
3368
3406
  useEffect5(() => {
3369
3407
  if (activeTab === "setup" || activeTab === "sync") fetchServerProjects();
3370
3408
  }, [activeTab]);
3409
+ useEffect5(() => {
3410
+ if (!hfToken) return;
3411
+ hfLoadTags(hfToken).then((tags) => {
3412
+ if (tags?.by_category) setWorkspaceTags(tags);
3413
+ }).catch(() => {
3414
+ });
3415
+ hfLoadMetadata(hfToken).then((entries) => {
3416
+ if (Array.isArray(entries)) setHfMetadata(entries);
3417
+ }).catch(() => {
3418
+ });
3419
+ }, [hfToken]);
3420
+ useEffect5(() => {
3421
+ if (!hfToken || !workspaceTags) return;
3422
+ if (hfTagSaveTimer.current) clearTimeout(hfTagSaveTimer.current);
3423
+ hfTagSaveTimer.current = setTimeout(() => {
3424
+ hfSaveTags(workspaceTags, hfToken).catch(() => {
3425
+ });
3426
+ }, 1500);
3427
+ return () => {
3428
+ if (hfTagSaveTimer.current) clearTimeout(hfTagSaveTimer.current);
3429
+ };
3430
+ }, [workspaceTags, hfToken]);
3371
3431
  if (isFullscreen && currentResult?.base64) {
3372
3432
  const fsBase64 = currentResult.base64.startsWith("data:") ? currentResult.base64 : `data:image/png;base64,${currentResult.base64}`;
3373
3433
  return /* @__PURE__ */ jsxs18(
@@ -3469,6 +3529,8 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
3469
3529
  "input",
3470
3530
  {
3471
3531
  type: "password",
3532
+ autoComplete: "current-password",
3533
+ id: "hf-token-input",
3472
3534
  value: hfTokenInput,
3473
3535
  onChange: (e) => setHfTokenInput(e.target.value),
3474
3536
  onKeyDown: (e) => {
@@ -3497,10 +3559,10 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
3497
3559
  onClick: async () => {
3498
3560
  setIsLoadingFromHF(true);
3499
3561
  try {
3500
- const { hfListProjects: hfListProjects2, hfDownloadProject } = await import("./hfStateService-UUDYKEMD.mjs");
3562
+ const { hfListProjects: hfListProjects2, hfDownloadProject: hfDownloadProject2 } = await import("./hfStateService-B62RV5K3.mjs");
3501
3563
  const projects = await hfListProjects2(hfToken);
3502
3564
  if (projects.length > 0) {
3503
- const file = await hfDownloadProject(projects[0].path, hfToken);
3565
+ const file = await hfDownloadProject2(projects[0].path, hfToken);
3504
3566
  await handleProjectImport(file);
3505
3567
  }
3506
3568
  } catch (e) {
@@ -4155,7 +4217,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
4155
4217
  }
4156
4218
 
4157
4219
  // src/index.ts
4158
- var LIB_VERSION = "1.3.3";
4220
+ var LIB_VERSION = "1.3.5";
4159
4221
  export {
4160
4222
  AvatarArchitectApp,
4161
4223
  CollapsibleCard,
@@ -4196,12 +4258,24 @@ export {
4196
4258
  formatTreeToMarkdown,
4197
4259
  frameToGeneration,
4198
4260
  getFormattedTimestamp,
4261
+ getHFToken,
4199
4262
  groupGenerationsToLabItems,
4263
+ hfDeleteProject,
4264
+ hfDownloadProject,
4265
+ hfListProjects,
4266
+ hfLoadImageAsBase64,
4267
+ hfLoadMetadata,
4268
+ hfLoadTags,
4269
+ hfSaveMetadata,
4270
+ hfSaveTags,
4271
+ hfUploadImage,
4272
+ hfUploadProjectForm,
4200
4273
  importProjectFromZip,
4201
4274
  injectXMPMetadata,
4202
4275
  interpretSdkError,
4203
4276
  parsePromptFile,
4204
4277
  parsePromptResponse,
4278
+ setHFToken,
4205
4279
  useKeyboardNavigation,
4206
4280
  useOnClickOutside
4207
4281
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rslsp1/fa-app-tools",
3
- "version": "1.3.3",
3
+ "version": "1.3.5",
4
4
  "description": "Shared tools and hooks for Fine Art flow apps",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",