@rslsp1/fa-app-tools 1.1.2 → 1.1.3

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/index.d.mts CHANGED
@@ -93,13 +93,21 @@ declare function parsePromptResponse(raw: string): {
93
93
  prompt: string;
94
94
  feedback: string | null;
95
95
  };
96
+ interface FlowSdkImage {
97
+ base64: string;
98
+ mimeType: string;
99
+ }
96
100
  interface FlowSdk {
97
101
  generate: {
98
102
  image: (options: Record<string, any>) => Promise<{
99
103
  base64: string;
100
104
  mediaId: string;
101
105
  }>;
102
- text: (prompt: string, options?: Record<string, any>) => Promise<{
106
+ text: (prompt: string, options?: {
107
+ systemInstruction?: string;
108
+ thinkingLevel?: string;
109
+ images?: FlowSdkImage[];
110
+ }) => Promise<{
103
111
  text: string;
104
112
  }>;
105
113
  };
@@ -119,7 +127,7 @@ declare function createFlowServices(Flow: FlowSdk): {
119
127
  base64: string;
120
128
  mediaId: string;
121
129
  }>;
122
- generateText: (hierarchyText: string, mode?: "literal" | "creative") => Promise<string>;
130
+ generateText: (hierarchyText: string, mode?: "literal" | "creative" | "scan", images?: FlowSdkImage[]) => Promise<string>;
123
131
  };
124
132
  declare function interpretSdkError(err: any): Error;
125
133
 
@@ -233,7 +241,10 @@ interface AvatarArchitectAppProps {
233
241
  base64: string;
234
242
  mediaId?: string;
235
243
  }>;
236
- onGeneratePrompt: (text: string) => Promise<string>;
244
+ onGeneratePrompt: (text: string, mode?: string, images?: {
245
+ base64: string;
246
+ mimeType: string;
247
+ }[]) => Promise<string>;
237
248
  onDownload: (base64: string, mimeType: string, filename: string) => Promise<void>;
238
249
  onSelectMedia: () => Promise<MediaItem[]>;
239
250
  buildInfo?: string;
@@ -297,6 +308,6 @@ interface ProjectSyncTabProps {
297
308
  }
298
309
  declare const ProjectSyncTab: React.FC<ProjectSyncTabProps>;
299
310
 
300
- declare const LIB_VERSION = "1.1.2";
311
+ declare const LIB_VERSION = "1.1.3";
301
312
 
302
313
  export { AvatarArchitectApp, type AvatarArchitectAppProps, CollapsibleCard, CompactDropdown, type ExtractedCharacter, FaToolsBadge, type FlowSdk, GLOBAL_STYLES, type Generation, HistoryPanel, InspectPanel, LIB_VERSION, ListView, type MediaItem, MediaLibrary, PillButton, type ProjectMeta, type ProjectSettings, ProjectSyncTab, PromptTab, SectionLabel, type SelectedTag, SetupPanel, type SyncDiff, type TagOption, type WorkspaceTags, buildFallbackPrompt, buildGenerationPrompt, buildImageGenerationOptions, buildPromptTabPayload, cleanAiResponse, createFlowServices, exportProjectToZip, formatTreeToMarkdown, getFormattedTimestamp, importProjectFromZip, injectXMPMetadata, interpretSdkError, parsePromptFile, parsePromptResponse, useKeyboardNavigation, useOnClickOutside };
package/dist/index.d.ts CHANGED
@@ -93,13 +93,21 @@ declare function parsePromptResponse(raw: string): {
93
93
  prompt: string;
94
94
  feedback: string | null;
95
95
  };
96
+ interface FlowSdkImage {
97
+ base64: string;
98
+ mimeType: string;
99
+ }
96
100
  interface FlowSdk {
97
101
  generate: {
98
102
  image: (options: Record<string, any>) => Promise<{
99
103
  base64: string;
100
104
  mediaId: string;
101
105
  }>;
102
- text: (prompt: string, options?: Record<string, any>) => Promise<{
106
+ text: (prompt: string, options?: {
107
+ systemInstruction?: string;
108
+ thinkingLevel?: string;
109
+ images?: FlowSdkImage[];
110
+ }) => Promise<{
103
111
  text: string;
104
112
  }>;
105
113
  };
@@ -119,7 +127,7 @@ declare function createFlowServices(Flow: FlowSdk): {
119
127
  base64: string;
120
128
  mediaId: string;
121
129
  }>;
122
- generateText: (hierarchyText: string, mode?: "literal" | "creative") => Promise<string>;
130
+ generateText: (hierarchyText: string, mode?: "literal" | "creative" | "scan", images?: FlowSdkImage[]) => Promise<string>;
123
131
  };
124
132
  declare function interpretSdkError(err: any): Error;
125
133
 
@@ -233,7 +241,10 @@ interface AvatarArchitectAppProps {
233
241
  base64: string;
234
242
  mediaId?: string;
235
243
  }>;
236
- onGeneratePrompt: (text: string) => Promise<string>;
244
+ onGeneratePrompt: (text: string, mode?: string, images?: {
245
+ base64: string;
246
+ mimeType: string;
247
+ }[]) => Promise<string>;
237
248
  onDownload: (base64: string, mimeType: string, filename: string) => Promise<void>;
238
249
  onSelectMedia: () => Promise<MediaItem[]>;
239
250
  buildInfo?: string;
@@ -297,6 +308,6 @@ interface ProjectSyncTabProps {
297
308
  }
298
309
  declare const ProjectSyncTab: React.FC<ProjectSyncTabProps>;
299
310
 
300
- declare const LIB_VERSION = "1.1.2";
311
+ declare const LIB_VERSION = "1.1.3";
301
312
 
302
313
  export { AvatarArchitectApp, type AvatarArchitectAppProps, CollapsibleCard, CompactDropdown, type ExtractedCharacter, FaToolsBadge, type FlowSdk, GLOBAL_STYLES, type Generation, HistoryPanel, InspectPanel, LIB_VERSION, ListView, type MediaItem, MediaLibrary, PillButton, type ProjectMeta, type ProjectSettings, ProjectSyncTab, PromptTab, SectionLabel, type SelectedTag, SetupPanel, type SyncDiff, type TagOption, type WorkspaceTags, buildFallbackPrompt, buildGenerationPrompt, buildImageGenerationOptions, buildPromptTabPayload, cleanAiResponse, createFlowServices, exportProjectToZip, formatTreeToMarkdown, getFormattedTimestamp, importProjectFromZip, injectXMPMetadata, interpretSdkError, parsePromptFile, parsePromptResponse, useKeyboardNavigation, useOnClickOutside };
package/dist/index.js CHANGED
@@ -428,7 +428,24 @@ function createFlowServices(Flow) {
428
428
  throw interpretSdkError(err);
429
429
  }
430
430
  },
431
- generateText: async (hierarchyText, mode = "creative") => {
431
+ generateText: async (hierarchyText, mode = "creative", images) => {
432
+ if (mode === "scan" && images?.length) {
433
+ try {
434
+ const response = await Flow.generate.text(
435
+ "Analyze this image and create a detailed image generation prompt that would recreate it. Focus on: subject, style, lighting, composition, color palette, mood, and technical quality. Output ONLY the prompt string, no explanations.",
436
+ {
437
+ thinkingLevel: "low",
438
+ systemInstruction: "You are an expert image analyst and prompt engineer. Always return ONLY the generation prompt, no headers, no quotes, no conversational filler.",
439
+ images
440
+ }
441
+ );
442
+ const result = response?.text?.trim() || "";
443
+ if (!result) throw new Error("Empty AI response");
444
+ return cleanAiResponse(result);
445
+ } catch (err) {
446
+ throw interpretSdkError(err);
447
+ }
448
+ }
432
449
  const prompt = buildGenerationPrompt(hierarchyText, mode);
433
450
  try {
434
451
  const response = await Flow.generate.text(prompt, {
@@ -1719,6 +1736,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
1719
1736
  });
1720
1737
  const [activeReferenceId, setActiveReferenceId] = (0, import_react14.useState)(null);
1721
1738
  const [activeReferenceThumbnail, setActiveReferenceThumbnail] = (0, import_react14.useState)(null);
1739
+ const [isScanningImage, setIsScanningImage] = (0, import_react14.useState)(false);
1722
1740
  const [touchStartX, setTouchStartX] = (0, import_react14.useState)(null);
1723
1741
  const [isFullscreen, setIsFullscreen] = (0, import_react14.useState)(false);
1724
1742
  const [zoomScale, setZoomScale] = (0, import_react14.useState)(1);
@@ -1788,6 +1806,23 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
1788
1806
  setActiveReferenceId(null);
1789
1807
  setActiveReferenceThumbnail(null);
1790
1808
  };
1809
+ const handleScanImage = async (file) => {
1810
+ setIsScanningImage(true);
1811
+ try {
1812
+ const base64 = await new Promise((resolve, reject) => {
1813
+ const reader = new FileReader();
1814
+ reader.onloadend = () => resolve(reader.result.split(",")[1]);
1815
+ reader.onerror = reject;
1816
+ reader.readAsDataURL(file);
1817
+ });
1818
+ const prompt = await onGeneratePrompt("", "scan", [{ base64, mimeType: file.type || "image/png" }]);
1819
+ setActivePrompt(prompt);
1820
+ } catch (err) {
1821
+ console.error("Scan fehlgeschlagen:", err);
1822
+ } finally {
1823
+ setIsScanningImage(false);
1824
+ }
1825
+ };
1791
1826
  const currentIndex = (0, import_react14.useMemo)(() => history.findIndex((h) => h.id === currentResult?.id), [history, currentResult]);
1792
1827
  const goToPrev = (0, import_react14.useCallback)(() => {
1793
1828
  if (currentIndex > 0) setCurrentResult(history[currentIndex - 1]);
@@ -2407,7 +2442,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
2407
2442
  leftTab === "prompt" && workspaceTags && activeTab !== "setup" && activeTab !== "sync" && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(PromptTab, { workspaceTags, onGenerate: handlePromptTabGenerate, isGenerating: isPromptTabGenerating, feedback: promptFeedback, promptResult: activePrompt || null, lastPayload: lastPromptPayload, onGenerateImage: (prompt) => {
2408
2443
  handleGenerateImage(prompt);
2409
2444
  setMobileTab("stage");
2410
- }, onTagCreate: handleTagCreate, onTagUpdate: handleTagUpdate, onTagDelete: handleTagDelete }),
2445
+ }, onTagCreate: handleTagCreate, onTagUpdate: handleTagUpdate, onTagDelete: handleTagDelete, onScanImage: handleScanImage, isScanning: isScanningImage }),
2411
2446
  activeTab === "setup" && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(SetupPanel, { onWorkspaceImport: handleWorkspaceImport, buildInfo }),
2412
2447
  activeTab === "sync" && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2413
2448
  ProjectSyncTab,
@@ -2583,7 +2618,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
2583
2618
  isGeneratingNodeId: (id) => isSynthesizing && focusedNodeId === id
2584
2619
  }
2585
2620
  ) }),
2586
- leftTab === "prompt" && workspaceTags && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(PromptTab, { workspaceTags, onGenerate: handlePromptTabGenerate, isGenerating: isPromptTabGenerating, feedback: promptFeedback, promptResult: activePrompt || null, lastPayload: lastPromptPayload, onGenerateImage: (prompt) => handleGenerateImage(prompt), onTagCreate: handleTagCreate, onTagUpdate: handleTagUpdate, onTagDelete: handleTagDelete })
2621
+ leftTab === "prompt" && workspaceTags && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(PromptTab, { workspaceTags, onGenerate: handlePromptTabGenerate, isGenerating: isPromptTabGenerating, feedback: promptFeedback, promptResult: activePrompt || null, lastPayload: lastPromptPayload, onGenerateImage: (prompt) => handleGenerateImage(prompt), onTagCreate: handleTagCreate, onTagUpdate: handleTagUpdate, onTagDelete: handleTagDelete, onScanImage: handleScanImage, isScanning: isScanningImage })
2587
2622
  ] })
2588
2623
  ] }),
2589
2624
  /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex-1 flex flex-col bg-[#0b0b0b] overflow-hidden", children: [
@@ -2687,7 +2722,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
2687
2722
  }
2688
2723
 
2689
2724
  // src/index.ts
2690
- var LIB_VERSION = "1.1.2";
2725
+ var LIB_VERSION = "1.1.3";
2691
2726
  // Annotate the CommonJS export names for ESM import in node:
2692
2727
  0 && (module.exports = {
2693
2728
  AvatarArchitectApp,
package/dist/index.mjs CHANGED
@@ -362,7 +362,24 @@ function createFlowServices(Flow) {
362
362
  throw interpretSdkError(err);
363
363
  }
364
364
  },
365
- generateText: async (hierarchyText, mode = "creative") => {
365
+ generateText: async (hierarchyText, mode = "creative", images) => {
366
+ if (mode === "scan" && images?.length) {
367
+ try {
368
+ const response = await Flow.generate.text(
369
+ "Analyze this image and create a detailed image generation prompt that would recreate it. Focus on: subject, style, lighting, composition, color palette, mood, and technical quality. Output ONLY the prompt string, no explanations.",
370
+ {
371
+ thinkingLevel: "low",
372
+ systemInstruction: "You are an expert image analyst and prompt engineer. Always return ONLY the generation prompt, no headers, no quotes, no conversational filler.",
373
+ images
374
+ }
375
+ );
376
+ const result = response?.text?.trim() || "";
377
+ if (!result) throw new Error("Empty AI response");
378
+ return cleanAiResponse(result);
379
+ } catch (err) {
380
+ throw interpretSdkError(err);
381
+ }
382
+ }
366
383
  const prompt = buildGenerationPrompt(hierarchyText, mode);
367
384
  try {
368
385
  const response = await Flow.generate.text(prompt, {
@@ -1653,6 +1670,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
1653
1670
  });
1654
1671
  const [activeReferenceId, setActiveReferenceId] = useState6(null);
1655
1672
  const [activeReferenceThumbnail, setActiveReferenceThumbnail] = useState6(null);
1673
+ const [isScanningImage, setIsScanningImage] = useState6(false);
1656
1674
  const [touchStartX, setTouchStartX] = useState6(null);
1657
1675
  const [isFullscreen, setIsFullscreen] = useState6(false);
1658
1676
  const [zoomScale, setZoomScale] = useState6(1);
@@ -1722,6 +1740,23 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
1722
1740
  setActiveReferenceId(null);
1723
1741
  setActiveReferenceThumbnail(null);
1724
1742
  };
1743
+ const handleScanImage = async (file) => {
1744
+ setIsScanningImage(true);
1745
+ try {
1746
+ const base64 = await new Promise((resolve, reject) => {
1747
+ const reader = new FileReader();
1748
+ reader.onloadend = () => resolve(reader.result.split(",")[1]);
1749
+ reader.onerror = reject;
1750
+ reader.readAsDataURL(file);
1751
+ });
1752
+ const prompt = await onGeneratePrompt("", "scan", [{ base64, mimeType: file.type || "image/png" }]);
1753
+ setActivePrompt(prompt);
1754
+ } catch (err) {
1755
+ console.error("Scan fehlgeschlagen:", err);
1756
+ } finally {
1757
+ setIsScanningImage(false);
1758
+ }
1759
+ };
1725
1760
  const currentIndex = useMemo2(() => history.findIndex((h) => h.id === currentResult?.id), [history, currentResult]);
1726
1761
  const goToPrev = useCallback(() => {
1727
1762
  if (currentIndex > 0) setCurrentResult(history[currentIndex - 1]);
@@ -2341,7 +2376,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
2341
2376
  leftTab === "prompt" && workspaceTags && activeTab !== "setup" && activeTab !== "sync" && /* @__PURE__ */ jsx13(PromptTab, { workspaceTags, onGenerate: handlePromptTabGenerate, isGenerating: isPromptTabGenerating, feedback: promptFeedback, promptResult: activePrompt || null, lastPayload: lastPromptPayload, onGenerateImage: (prompt) => {
2342
2377
  handleGenerateImage(prompt);
2343
2378
  setMobileTab("stage");
2344
- }, onTagCreate: handleTagCreate, onTagUpdate: handleTagUpdate, onTagDelete: handleTagDelete }),
2379
+ }, onTagCreate: handleTagCreate, onTagUpdate: handleTagUpdate, onTagDelete: handleTagDelete, onScanImage: handleScanImage, isScanning: isScanningImage }),
2345
2380
  activeTab === "setup" && /* @__PURE__ */ jsx13(SetupPanel, { onWorkspaceImport: handleWorkspaceImport, buildInfo }),
2346
2381
  activeTab === "sync" && /* @__PURE__ */ jsx13(
2347
2382
  ProjectSyncTab,
@@ -2517,7 +2552,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
2517
2552
  isGeneratingNodeId: (id) => isSynthesizing && focusedNodeId === id
2518
2553
  }
2519
2554
  ) }),
2520
- leftTab === "prompt" && workspaceTags && /* @__PURE__ */ jsx13(PromptTab, { workspaceTags, onGenerate: handlePromptTabGenerate, isGenerating: isPromptTabGenerating, feedback: promptFeedback, promptResult: activePrompt || null, lastPayload: lastPromptPayload, onGenerateImage: (prompt) => handleGenerateImage(prompt), onTagCreate: handleTagCreate, onTagUpdate: handleTagUpdate, onTagDelete: handleTagDelete })
2555
+ leftTab === "prompt" && workspaceTags && /* @__PURE__ */ jsx13(PromptTab, { workspaceTags, onGenerate: handlePromptTabGenerate, isGenerating: isPromptTabGenerating, feedback: promptFeedback, promptResult: activePrompt || null, lastPayload: lastPromptPayload, onGenerateImage: (prompt) => handleGenerateImage(prompt), onTagCreate: handleTagCreate, onTagUpdate: handleTagUpdate, onTagDelete: handleTagDelete, onScanImage: handleScanImage, isScanning: isScanningImage })
2521
2556
  ] })
2522
2557
  ] }),
2523
2558
  /* @__PURE__ */ jsxs11("div", { className: "flex-1 flex flex-col bg-[#0b0b0b] overflow-hidden", children: [
@@ -2621,7 +2656,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
2621
2656
  }
2622
2657
 
2623
2658
  // src/index.ts
2624
- var LIB_VERSION = "1.1.2";
2659
+ var LIB_VERSION = "1.1.3";
2625
2660
  export {
2626
2661
  AvatarArchitectApp,
2627
2662
  CollapsibleCard,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rslsp1/fa-app-tools",
3
- "version": "1.1.2",
3
+ "version": "1.1.3",
4
4
  "description": "Shared tools and hooks for Fine Art flow apps",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",