@rslsp1/fa-app-tools 1.1.1 → 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 +15 -4
- package/dist/index.d.ts +15 -4
- package/dist/index.js +68 -5
- package/dist/index.mjs +68 -5
- package/package.json +1 -1
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?:
|
|
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
|
|
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.
|
|
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?:
|
|
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
|
|
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.
|
|
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, {
|
|
@@ -1717,6 +1734,9 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
1717
1734
|
return false;
|
|
1718
1735
|
}
|
|
1719
1736
|
});
|
|
1737
|
+
const [activeReferenceId, setActiveReferenceId] = (0, import_react14.useState)(null);
|
|
1738
|
+
const [activeReferenceThumbnail, setActiveReferenceThumbnail] = (0, import_react14.useState)(null);
|
|
1739
|
+
const [isScanningImage, setIsScanningImage] = (0, import_react14.useState)(false);
|
|
1720
1740
|
const [touchStartX, setTouchStartX] = (0, import_react14.useState)(null);
|
|
1721
1741
|
const [isFullscreen, setIsFullscreen] = (0, import_react14.useState)(false);
|
|
1722
1742
|
const [zoomScale, setZoomScale] = (0, import_react14.useState)(1);
|
|
@@ -1773,6 +1793,36 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
1773
1793
|
} catch {
|
|
1774
1794
|
}
|
|
1775
1795
|
};
|
|
1796
|
+
const handleSelectReference = async () => {
|
|
1797
|
+
const media = await onSelectMedia();
|
|
1798
|
+
if (!media?.length) return;
|
|
1799
|
+
const first = media[0];
|
|
1800
|
+
if (first.mediaId) {
|
|
1801
|
+
setActiveReferenceId(first.mediaId);
|
|
1802
|
+
setActiveReferenceThumbnail(`data:${first.mimeType};base64,${first.base64}`);
|
|
1803
|
+
}
|
|
1804
|
+
};
|
|
1805
|
+
const clearReference = () => {
|
|
1806
|
+
setActiveReferenceId(null);
|
|
1807
|
+
setActiveReferenceThumbnail(null);
|
|
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
|
+
};
|
|
1776
1826
|
const currentIndex = (0, import_react14.useMemo)(() => history.findIndex((h) => h.id === currentResult?.id), [history, currentResult]);
|
|
1777
1827
|
const goToPrev = (0, import_react14.useCallback)(() => {
|
|
1778
1828
|
if (currentIndex > 0) setCurrentResult(history[currentIndex - 1]);
|
|
@@ -1814,7 +1864,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
1814
1864
|
if (!options.silent) setCurrentResult(newGen);
|
|
1815
1865
|
if (seedMode === "random") setSeed(activeSeed);
|
|
1816
1866
|
try {
|
|
1817
|
-
const { base64, mediaId } = await onGenerateImage(buildImageGenerationOptions(promptToUse, aspectRatio, selectedModel, useReferenceId));
|
|
1867
|
+
const { base64, mediaId } = await onGenerateImage(buildImageGenerationOptions(promptToUse, aspectRatio, selectedModel, useReferenceId ?? activeReferenceId ?? void 0));
|
|
1818
1868
|
const finishedGen = { ...newGen, status: "done", base64: `data:image/png;base64,${base64}`, mediaId };
|
|
1819
1869
|
setHistory((prev) => prev.map((g) => g.id === genId ? finishedGen : g));
|
|
1820
1870
|
setGalleryItems((prev) => [finishedGen, ...prev]);
|
|
@@ -2205,6 +2255,11 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
2205
2255
|
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(CompactDropdown, { value: aspectRatio, onChange: setAspectRatio, options: [{ label: "1:1", value: "1:1" }, { label: "16:9", value: "16:9" }, { label: "9:16", value: "9:16" }] }),
|
|
2206
2256
|
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(CompactDropdown, { value: selectedModel, onChange: setSelectedModel, options: [{ value: "\u{1F34C} Nano Banana Pro", label: "\u{1F34C} Nano Banana Pro" }, { value: "\u{1F34C} Nano Banana 2", label: "\u{1F34C} Nano Banana 2" }, { value: "Imagen 4", label: "Imagen 4" }] }),
|
|
2207
2257
|
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "flex-1" }),
|
|
2258
|
+
activeReferenceThumbnail ? /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex items-center gap-1 rounded-lg border border-white/20 bg-white/5 overflow-hidden mr-2", style: { height: 28 }, children: [
|
|
2259
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("img", { src: activeReferenceThumbnail, className: "h-full aspect-square object-cover" }),
|
|
2260
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "text-[10px] text-white/60 font-bold uppercase tracking-wide px-1", children: "Ref" }),
|
|
2261
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("button", { onClick: clearReference, className: "w-6 h-full flex items-center justify-center text-white/30 active:text-white/80 transition-colors", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "material-symbols-outlined text-[14px]", children: "close" }) })
|
|
2262
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("button", { onClick: handleSelectReference, className: "text-white/20 active:text-white/60 transition-colors mr-2", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "material-symbols-outlined text-[20px]", children: "add_photo_alternate" }) }),
|
|
2208
2263
|
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("button", { onClick: toggleContrast, className: "text-white/20 active:text-white/60 transition-colors mr-2", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "material-symbols-outlined text-[20px]", children: highContrast ? "light_mode" : "dark_mode" }) }),
|
|
2209
2264
|
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("button", { onClick: () => setShowStart(true), className: "text-white/20 active:text-white/60 transition-colors mr-1", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "material-symbols-outlined text-[20px]", children: "desktop_windows" }) })
|
|
2210
2265
|
] }),
|
|
@@ -2387,7 +2442,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
2387
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) => {
|
|
2388
2443
|
handleGenerateImage(prompt);
|
|
2389
2444
|
setMobileTab("stage");
|
|
2390
|
-
}, onTagCreate: handleTagCreate, onTagUpdate: handleTagUpdate, onTagDelete: handleTagDelete }),
|
|
2445
|
+
}, onTagCreate: handleTagCreate, onTagUpdate: handleTagUpdate, onTagDelete: handleTagDelete, onScanImage: handleScanImage, isScanning: isScanningImage }),
|
|
2391
2446
|
activeTab === "setup" && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(SetupPanel, { onWorkspaceImport: handleWorkspaceImport, buildInfo }),
|
|
2392
2447
|
activeTab === "sync" && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
2393
2448
|
ProjectSyncTab,
|
|
@@ -2563,7 +2618,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
2563
2618
|
isGeneratingNodeId: (id) => isSynthesizing && focusedNodeId === id
|
|
2564
2619
|
}
|
|
2565
2620
|
) }),
|
|
2566
|
-
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 })
|
|
2567
2622
|
] })
|
|
2568
2623
|
] }),
|
|
2569
2624
|
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex-1 flex flex-col bg-[#0b0b0b] overflow-hidden", children: [
|
|
@@ -2573,6 +2628,14 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
2573
2628
|
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(CompactDropdown, { value: selectedModel, onChange: setSelectedModel, options: [{ value: "\u{1F34C} Nano Banana Pro", label: "\u{1F34C} Nano Banana Pro" }, { value: "\u{1F34C} Nano Banana 2", label: "\u{1F34C} Nano Banana 2" }, { value: "Imagen 4", label: "Imagen 4" }] })
|
|
2574
2629
|
] }),
|
|
2575
2630
|
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
2631
|
+
activeReferenceThumbnail ? /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex items-center gap-1 rounded-lg border border-white/20 bg-white/5 overflow-hidden", style: { height: 28 }, children: [
|
|
2632
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("img", { src: activeReferenceThumbnail, className: "h-full aspect-square object-cover" }),
|
|
2633
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "text-[10px] text-white/60 font-bold uppercase tracking-wide px-1", children: "Ref" }),
|
|
2634
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("button", { onClick: clearReference, className: "w-6 h-full flex items-center justify-center text-white/30 hover:text-white/80 transition-colors", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "material-symbols-outlined text-[14px]", children: "close" }) })
|
|
2635
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("button", { onClick: handleSelectReference, className: "flex items-center gap-1 h-7 px-2 rounded-lg border border-white/10 text-white/30 hover:text-white/60 hover:border-white/20 transition-colors text-[10px] font-bold uppercase tracking-wide", children: [
|
|
2636
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "material-symbols-outlined text-[14px]", children: "add_photo_alternate" }),
|
|
2637
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { children: "Ref" })
|
|
2638
|
+
] }),
|
|
2576
2639
|
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("button", { onClick: () => setIsPromptCollapsed(!isPromptCollapsed), className: "text-white/40 hover:text-white transition-colors", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "material-symbols-outlined", children: isPromptCollapsed ? "expand_more" : "expand_less" }) }),
|
|
2577
2640
|
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(PillButton, { variant: "solid", icon: "bolt", loading: isGenerating, disabled: !activePrompt.trim(), onClick: () => handleGenerateImage(), children: "Generieren" })
|
|
2578
2641
|
] })
|
|
@@ -2659,7 +2722,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
2659
2722
|
}
|
|
2660
2723
|
|
|
2661
2724
|
// src/index.ts
|
|
2662
|
-
var LIB_VERSION = "1.1.
|
|
2725
|
+
var LIB_VERSION = "1.1.3";
|
|
2663
2726
|
// Annotate the CommonJS export names for ESM import in node:
|
|
2664
2727
|
0 && (module.exports = {
|
|
2665
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, {
|
|
@@ -1651,6 +1668,9 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
1651
1668
|
return false;
|
|
1652
1669
|
}
|
|
1653
1670
|
});
|
|
1671
|
+
const [activeReferenceId, setActiveReferenceId] = useState6(null);
|
|
1672
|
+
const [activeReferenceThumbnail, setActiveReferenceThumbnail] = useState6(null);
|
|
1673
|
+
const [isScanningImage, setIsScanningImage] = useState6(false);
|
|
1654
1674
|
const [touchStartX, setTouchStartX] = useState6(null);
|
|
1655
1675
|
const [isFullscreen, setIsFullscreen] = useState6(false);
|
|
1656
1676
|
const [zoomScale, setZoomScale] = useState6(1);
|
|
@@ -1707,6 +1727,36 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
1707
1727
|
} catch {
|
|
1708
1728
|
}
|
|
1709
1729
|
};
|
|
1730
|
+
const handleSelectReference = async () => {
|
|
1731
|
+
const media = await onSelectMedia();
|
|
1732
|
+
if (!media?.length) return;
|
|
1733
|
+
const first = media[0];
|
|
1734
|
+
if (first.mediaId) {
|
|
1735
|
+
setActiveReferenceId(first.mediaId);
|
|
1736
|
+
setActiveReferenceThumbnail(`data:${first.mimeType};base64,${first.base64}`);
|
|
1737
|
+
}
|
|
1738
|
+
};
|
|
1739
|
+
const clearReference = () => {
|
|
1740
|
+
setActiveReferenceId(null);
|
|
1741
|
+
setActiveReferenceThumbnail(null);
|
|
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
|
+
};
|
|
1710
1760
|
const currentIndex = useMemo2(() => history.findIndex((h) => h.id === currentResult?.id), [history, currentResult]);
|
|
1711
1761
|
const goToPrev = useCallback(() => {
|
|
1712
1762
|
if (currentIndex > 0) setCurrentResult(history[currentIndex - 1]);
|
|
@@ -1748,7 +1798,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
1748
1798
|
if (!options.silent) setCurrentResult(newGen);
|
|
1749
1799
|
if (seedMode === "random") setSeed(activeSeed);
|
|
1750
1800
|
try {
|
|
1751
|
-
const { base64, mediaId } = await onGenerateImage(buildImageGenerationOptions(promptToUse, aspectRatio, selectedModel, useReferenceId));
|
|
1801
|
+
const { base64, mediaId } = await onGenerateImage(buildImageGenerationOptions(promptToUse, aspectRatio, selectedModel, useReferenceId ?? activeReferenceId ?? void 0));
|
|
1752
1802
|
const finishedGen = { ...newGen, status: "done", base64: `data:image/png;base64,${base64}`, mediaId };
|
|
1753
1803
|
setHistory((prev) => prev.map((g) => g.id === genId ? finishedGen : g));
|
|
1754
1804
|
setGalleryItems((prev) => [finishedGen, ...prev]);
|
|
@@ -2139,6 +2189,11 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
2139
2189
|
/* @__PURE__ */ jsx13(CompactDropdown, { value: aspectRatio, onChange: setAspectRatio, options: [{ label: "1:1", value: "1:1" }, { label: "16:9", value: "16:9" }, { label: "9:16", value: "9:16" }] }),
|
|
2140
2190
|
/* @__PURE__ */ jsx13(CompactDropdown, { value: selectedModel, onChange: setSelectedModel, options: [{ value: "\u{1F34C} Nano Banana Pro", label: "\u{1F34C} Nano Banana Pro" }, { value: "\u{1F34C} Nano Banana 2", label: "\u{1F34C} Nano Banana 2" }, { value: "Imagen 4", label: "Imagen 4" }] }),
|
|
2141
2191
|
/* @__PURE__ */ jsx13("div", { className: "flex-1" }),
|
|
2192
|
+
activeReferenceThumbnail ? /* @__PURE__ */ jsxs11("div", { className: "flex items-center gap-1 rounded-lg border border-white/20 bg-white/5 overflow-hidden mr-2", style: { height: 28 }, children: [
|
|
2193
|
+
/* @__PURE__ */ jsx13("img", { src: activeReferenceThumbnail, className: "h-full aspect-square object-cover" }),
|
|
2194
|
+
/* @__PURE__ */ jsx13("span", { className: "text-[10px] text-white/60 font-bold uppercase tracking-wide px-1", children: "Ref" }),
|
|
2195
|
+
/* @__PURE__ */ jsx13("button", { onClick: clearReference, className: "w-6 h-full flex items-center justify-center text-white/30 active:text-white/80 transition-colors", children: /* @__PURE__ */ jsx13("span", { className: "material-symbols-outlined text-[14px]", children: "close" }) })
|
|
2196
|
+
] }) : /* @__PURE__ */ jsx13("button", { onClick: handleSelectReference, className: "text-white/20 active:text-white/60 transition-colors mr-2", children: /* @__PURE__ */ jsx13("span", { className: "material-symbols-outlined text-[20px]", children: "add_photo_alternate" }) }),
|
|
2142
2197
|
/* @__PURE__ */ jsx13("button", { onClick: toggleContrast, className: "text-white/20 active:text-white/60 transition-colors mr-2", children: /* @__PURE__ */ jsx13("span", { className: "material-symbols-outlined text-[20px]", children: highContrast ? "light_mode" : "dark_mode" }) }),
|
|
2143
2198
|
/* @__PURE__ */ jsx13("button", { onClick: () => setShowStart(true), className: "text-white/20 active:text-white/60 transition-colors mr-1", children: /* @__PURE__ */ jsx13("span", { className: "material-symbols-outlined text-[20px]", children: "desktop_windows" }) })
|
|
2144
2199
|
] }),
|
|
@@ -2321,7 +2376,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
2321
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) => {
|
|
2322
2377
|
handleGenerateImage(prompt);
|
|
2323
2378
|
setMobileTab("stage");
|
|
2324
|
-
}, onTagCreate: handleTagCreate, onTagUpdate: handleTagUpdate, onTagDelete: handleTagDelete }),
|
|
2379
|
+
}, onTagCreate: handleTagCreate, onTagUpdate: handleTagUpdate, onTagDelete: handleTagDelete, onScanImage: handleScanImage, isScanning: isScanningImage }),
|
|
2325
2380
|
activeTab === "setup" && /* @__PURE__ */ jsx13(SetupPanel, { onWorkspaceImport: handleWorkspaceImport, buildInfo }),
|
|
2326
2381
|
activeTab === "sync" && /* @__PURE__ */ jsx13(
|
|
2327
2382
|
ProjectSyncTab,
|
|
@@ -2497,7 +2552,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
2497
2552
|
isGeneratingNodeId: (id) => isSynthesizing && focusedNodeId === id
|
|
2498
2553
|
}
|
|
2499
2554
|
) }),
|
|
2500
|
-
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 })
|
|
2501
2556
|
] })
|
|
2502
2557
|
] }),
|
|
2503
2558
|
/* @__PURE__ */ jsxs11("div", { className: "flex-1 flex flex-col bg-[#0b0b0b] overflow-hidden", children: [
|
|
@@ -2507,6 +2562,14 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
2507
2562
|
/* @__PURE__ */ jsx13(CompactDropdown, { value: selectedModel, onChange: setSelectedModel, options: [{ value: "\u{1F34C} Nano Banana Pro", label: "\u{1F34C} Nano Banana Pro" }, { value: "\u{1F34C} Nano Banana 2", label: "\u{1F34C} Nano Banana 2" }, { value: "Imagen 4", label: "Imagen 4" }] })
|
|
2508
2563
|
] }),
|
|
2509
2564
|
/* @__PURE__ */ jsxs11("div", { className: "flex items-center gap-2", children: [
|
|
2565
|
+
activeReferenceThumbnail ? /* @__PURE__ */ jsxs11("div", { className: "flex items-center gap-1 rounded-lg border border-white/20 bg-white/5 overflow-hidden", style: { height: 28 }, children: [
|
|
2566
|
+
/* @__PURE__ */ jsx13("img", { src: activeReferenceThumbnail, className: "h-full aspect-square object-cover" }),
|
|
2567
|
+
/* @__PURE__ */ jsx13("span", { className: "text-[10px] text-white/60 font-bold uppercase tracking-wide px-1", children: "Ref" }),
|
|
2568
|
+
/* @__PURE__ */ jsx13("button", { onClick: clearReference, className: "w-6 h-full flex items-center justify-center text-white/30 hover:text-white/80 transition-colors", children: /* @__PURE__ */ jsx13("span", { className: "material-symbols-outlined text-[14px]", children: "close" }) })
|
|
2569
|
+
] }) : /* @__PURE__ */ jsxs11("button", { onClick: handleSelectReference, className: "flex items-center gap-1 h-7 px-2 rounded-lg border border-white/10 text-white/30 hover:text-white/60 hover:border-white/20 transition-colors text-[10px] font-bold uppercase tracking-wide", children: [
|
|
2570
|
+
/* @__PURE__ */ jsx13("span", { className: "material-symbols-outlined text-[14px]", children: "add_photo_alternate" }),
|
|
2571
|
+
/* @__PURE__ */ jsx13("span", { children: "Ref" })
|
|
2572
|
+
] }),
|
|
2510
2573
|
/* @__PURE__ */ jsx13("button", { onClick: () => setIsPromptCollapsed(!isPromptCollapsed), className: "text-white/40 hover:text-white transition-colors", children: /* @__PURE__ */ jsx13("span", { className: "material-symbols-outlined", children: isPromptCollapsed ? "expand_more" : "expand_less" }) }),
|
|
2511
2574
|
/* @__PURE__ */ jsx13(PillButton, { variant: "solid", icon: "bolt", loading: isGenerating, disabled: !activePrompt.trim(), onClick: () => handleGenerateImage(), children: "Generieren" })
|
|
2512
2575
|
] })
|
|
@@ -2593,7 +2656,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
2593
2656
|
}
|
|
2594
2657
|
|
|
2595
2658
|
// src/index.ts
|
|
2596
|
-
var LIB_VERSION = "1.1.
|
|
2659
|
+
var LIB_VERSION = "1.1.3";
|
|
2597
2660
|
export {
|
|
2598
2661
|
AvatarArchitectApp,
|
|
2599
2662
|
CollapsibleCard,
|