@rslsp1/fa-app-tools 0.1.14 → 1.0.1
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 +20 -5
- package/dist/index.d.ts +20 -5
- package/dist/index.js +301 -100
- package/dist/index.mjs +296 -98
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -4,11 +4,13 @@ import { Node, Edge } from '@xyflow/react';
|
|
|
4
4
|
|
|
5
5
|
declare function useOnClickOutside(ref: RefObject<HTMLElement | null>, handler: (e: MouseEvent | TouchEvent) => void): void;
|
|
6
6
|
|
|
7
|
+
interface TagOption {
|
|
8
|
+
label: string;
|
|
9
|
+
value: string;
|
|
10
|
+
}
|
|
7
11
|
interface WorkspaceTags {
|
|
8
|
-
by_category: Record<string,
|
|
9
|
-
all: Array<{
|
|
10
|
-
label: string;
|
|
11
|
-
value: string;
|
|
12
|
+
by_category: Record<string, TagOption[]>;
|
|
13
|
+
all: Array<TagOption & {
|
|
12
14
|
category: string;
|
|
13
15
|
}>;
|
|
14
16
|
}
|
|
@@ -69,6 +71,11 @@ declare function buildGenerationPrompt(hierarchyText: string, mode?: 'literal' |
|
|
|
69
71
|
declare function buildFallbackPrompt(hierarchyText: string): string;
|
|
70
72
|
declare function cleanAiResponse(text: string): string;
|
|
71
73
|
declare function buildImageGenerationOptions(prompt: string, aspectRatio: string, model: string, referenceMediaId?: string): Record<string, any>;
|
|
74
|
+
declare function buildPromptTabPayload(selectedValues: string[], instructions: string, treeText?: string): string;
|
|
75
|
+
declare function parsePromptResponse(raw: string): {
|
|
76
|
+
prompt: string;
|
|
77
|
+
feedback: string | null;
|
|
78
|
+
};
|
|
72
79
|
declare function interpretSdkError(err: any): Error;
|
|
73
80
|
|
|
74
81
|
interface ExtractedCharacter {
|
|
@@ -189,4 +196,12 @@ interface AvatarArchitectAppProps {
|
|
|
189
196
|
}
|
|
190
197
|
declare function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onSelectMedia }: AvatarArchitectAppProps): react_jsx_runtime.JSX.Element;
|
|
191
198
|
|
|
192
|
-
|
|
199
|
+
interface PromptTabProps {
|
|
200
|
+
workspaceTags: WorkspaceTags;
|
|
201
|
+
onGenerate: (selectedValues: string[], instructions: string) => Promise<void>;
|
|
202
|
+
isGenerating: boolean;
|
|
203
|
+
feedback: string | null;
|
|
204
|
+
}
|
|
205
|
+
declare const PromptTab: React.FC<PromptTabProps>;
|
|
206
|
+
|
|
207
|
+
export { AvatarArchitectApp, type AvatarArchitectAppProps, CompactDropdown, type ExtractedCharacter, FaToolsBadge, GLOBAL_STYLES, type Generation, HistoryPanel, InspectPanel, ListView, type MediaItem, MediaLibrary, PillButton, type ProjectSettings, PromptTab, SectionLabel, SetupPanel, type TagOption, type WorkspaceTags, buildFallbackPrompt, buildGenerationPrompt, buildImageGenerationOptions, buildPromptTabPayload, cleanAiResponse, exportProjectToZip, formatTreeToMarkdown, getFormattedTimestamp, importProjectFromZip, injectXMPMetadata, interpretSdkError, parsePromptFile, parsePromptResponse, useKeyboardNavigation, useOnClickOutside };
|
package/dist/index.d.ts
CHANGED
|
@@ -4,11 +4,13 @@ import { Node, Edge } from '@xyflow/react';
|
|
|
4
4
|
|
|
5
5
|
declare function useOnClickOutside(ref: RefObject<HTMLElement | null>, handler: (e: MouseEvent | TouchEvent) => void): void;
|
|
6
6
|
|
|
7
|
+
interface TagOption {
|
|
8
|
+
label: string;
|
|
9
|
+
value: string;
|
|
10
|
+
}
|
|
7
11
|
interface WorkspaceTags {
|
|
8
|
-
by_category: Record<string,
|
|
9
|
-
all: Array<{
|
|
10
|
-
label: string;
|
|
11
|
-
value: string;
|
|
12
|
+
by_category: Record<string, TagOption[]>;
|
|
13
|
+
all: Array<TagOption & {
|
|
12
14
|
category: string;
|
|
13
15
|
}>;
|
|
14
16
|
}
|
|
@@ -69,6 +71,11 @@ declare function buildGenerationPrompt(hierarchyText: string, mode?: 'literal' |
|
|
|
69
71
|
declare function buildFallbackPrompt(hierarchyText: string): string;
|
|
70
72
|
declare function cleanAiResponse(text: string): string;
|
|
71
73
|
declare function buildImageGenerationOptions(prompt: string, aspectRatio: string, model: string, referenceMediaId?: string): Record<string, any>;
|
|
74
|
+
declare function buildPromptTabPayload(selectedValues: string[], instructions: string, treeText?: string): string;
|
|
75
|
+
declare function parsePromptResponse(raw: string): {
|
|
76
|
+
prompt: string;
|
|
77
|
+
feedback: string | null;
|
|
78
|
+
};
|
|
72
79
|
declare function interpretSdkError(err: any): Error;
|
|
73
80
|
|
|
74
81
|
interface ExtractedCharacter {
|
|
@@ -189,4 +196,12 @@ interface AvatarArchitectAppProps {
|
|
|
189
196
|
}
|
|
190
197
|
declare function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onSelectMedia }: AvatarArchitectAppProps): react_jsx_runtime.JSX.Element;
|
|
191
198
|
|
|
192
|
-
|
|
199
|
+
interface PromptTabProps {
|
|
200
|
+
workspaceTags: WorkspaceTags;
|
|
201
|
+
onGenerate: (selectedValues: string[], instructions: string) => Promise<void>;
|
|
202
|
+
isGenerating: boolean;
|
|
203
|
+
feedback: string | null;
|
|
204
|
+
}
|
|
205
|
+
declare const PromptTab: React.FC<PromptTabProps>;
|
|
206
|
+
|
|
207
|
+
export { AvatarArchitectApp, type AvatarArchitectAppProps, CompactDropdown, type ExtractedCharacter, FaToolsBadge, GLOBAL_STYLES, type Generation, HistoryPanel, InspectPanel, ListView, type MediaItem, MediaLibrary, PillButton, type ProjectSettings, PromptTab, SectionLabel, SetupPanel, type TagOption, type WorkspaceTags, buildFallbackPrompt, buildGenerationPrompt, buildImageGenerationOptions, buildPromptTabPayload, cleanAiResponse, exportProjectToZip, formatTreeToMarkdown, getFormattedTimestamp, importProjectFromZip, injectXMPMetadata, interpretSdkError, parsePromptFile, parsePromptResponse, useKeyboardNavigation, useOnClickOutside };
|
package/dist/index.js
CHANGED
|
@@ -39,11 +39,13 @@ __export(index_exports, {
|
|
|
39
39
|
ListView: () => ListView,
|
|
40
40
|
MediaLibrary: () => MediaLibrary,
|
|
41
41
|
PillButton: () => PillButton,
|
|
42
|
+
PromptTab: () => PromptTab,
|
|
42
43
|
SectionLabel: () => SectionLabel,
|
|
43
44
|
SetupPanel: () => SetupPanel,
|
|
44
45
|
buildFallbackPrompt: () => buildFallbackPrompt,
|
|
45
46
|
buildGenerationPrompt: () => buildGenerationPrompt,
|
|
46
47
|
buildImageGenerationOptions: () => buildImageGenerationOptions,
|
|
48
|
+
buildPromptTabPayload: () => buildPromptTabPayload,
|
|
47
49
|
cleanAiResponse: () => cleanAiResponse,
|
|
48
50
|
exportProjectToZip: () => exportProjectToZip,
|
|
49
51
|
formatTreeToMarkdown: () => formatTreeToMarkdown,
|
|
@@ -52,6 +54,7 @@ __export(index_exports, {
|
|
|
52
54
|
injectXMPMetadata: () => injectXMPMetadata,
|
|
53
55
|
interpretSdkError: () => interpretSdkError,
|
|
54
56
|
parsePromptFile: () => parsePromptFile,
|
|
57
|
+
parsePromptResponse: () => parsePromptResponse,
|
|
55
58
|
useKeyboardNavigation: () => useKeyboardNavigation,
|
|
56
59
|
useOnClickOutside: () => useOnClickOutside
|
|
57
60
|
});
|
|
@@ -352,6 +355,33 @@ function buildImageGenerationOptions(prompt, aspectRatio, model, referenceMediaI
|
|
|
352
355
|
}
|
|
353
356
|
return options;
|
|
354
357
|
}
|
|
358
|
+
function buildPromptTabPayload(selectedValues, instructions, treeText) {
|
|
359
|
+
const parts = [];
|
|
360
|
+
if (treeText) parts.push(`HIERARCHY:
|
|
361
|
+
${treeText}`);
|
|
362
|
+
if (selectedValues.length > 0) parts.push(`SELECTED TAGS:
|
|
363
|
+
${selectedValues.join(", ")}`);
|
|
364
|
+
if (instructions.trim()) parts.push(`ADDITIONAL INSTRUCTIONS:
|
|
365
|
+
${instructions.trim()}`);
|
|
366
|
+
return [
|
|
367
|
+
"Create a high-quality image generation prompt based on the following inputs. Translate everything to English.",
|
|
368
|
+
`Return a JSON object with exactly two keys: "prompt" (the prompt string) and "feedback" (a short note on your choices in the user's language, or null).`,
|
|
369
|
+
"Output ONLY the JSON object, no markdown, no wrapping.",
|
|
370
|
+
"",
|
|
371
|
+
...parts
|
|
372
|
+
].join("\n");
|
|
373
|
+
}
|
|
374
|
+
function parsePromptResponse(raw) {
|
|
375
|
+
const cleaned = raw.replace(/^```json\s*/i, "").replace(/^```\s*/i, "").replace(/```$/i, "").trim();
|
|
376
|
+
try {
|
|
377
|
+
const parsed = JSON.parse(cleaned);
|
|
378
|
+
if (typeof parsed?.prompt === "string") {
|
|
379
|
+
return { prompt: parsed.prompt.trim(), feedback: parsed.feedback ?? null };
|
|
380
|
+
}
|
|
381
|
+
} catch {
|
|
382
|
+
}
|
|
383
|
+
return { prompt: cleaned, feedback: null };
|
|
384
|
+
}
|
|
355
385
|
function interpretSdkError(err) {
|
|
356
386
|
const msg = err?.message || "Generierung fehlgeschlagen";
|
|
357
387
|
if (msg.includes("PUBLIC_ERROR_SOMETHING_WENT_WRONG")) {
|
|
@@ -603,8 +633,8 @@ var InspectPanel = ({ currentResult, history, onSelect, workspaceTags, onTagTogg
|
|
|
603
633
|
Object.entries(workspaceTags.by_category).map(([cat, tags]) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "flex flex-col gap-2", children: [
|
|
604
634
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "text-[8px] font-bold text-white/30 uppercase tracking-widest px-1", children: cat }),
|
|
605
635
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "flex flex-wrap gap-1.5", children: tags.map((t) => {
|
|
606
|
-
const isActive = (currentResult.tags || []).includes(t);
|
|
607
|
-
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { onClick: () => onTagToggle?.(t), className: `px-2.5 py-1 rounded-lg text-[8px] font-bold uppercase transition-all border ${isActive ? "bg-blue-500 border-blue-400 text-white shadow-[0_0_10px_rgba(59,130,246,0.3)]" : "bg-white/5 border-white/5 text-white/20 hover:text-white/50 hover:bg-white/10"}`, children: t }, t);
|
|
636
|
+
const isActive = (currentResult.tags || []).includes(t.label);
|
|
637
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { onClick: () => onTagToggle?.(t.label), className: `px-2.5 py-1 rounded-lg text-[8px] font-bold uppercase transition-all border ${isActive ? "bg-blue-500 border-blue-400 text-white shadow-[0_0_10px_rgba(59,130,246,0.3)]" : "bg-white/5 border-white/5 text-white/20 hover:text-white/50 hover:bg-white/10"}`, children: t.label }, t.label);
|
|
608
638
|
}) })
|
|
609
639
|
] }, cat))
|
|
610
640
|
] })
|
|
@@ -816,11 +846,117 @@ function ListView({ nodes, edges, onNodeChange, onAddChild, onDeleteNode, onMove
|
|
|
816
846
|
}
|
|
817
847
|
|
|
818
848
|
// src/components/AvatarArchitectApp.tsx
|
|
849
|
+
var import_react12 = require("react");
|
|
850
|
+
var import_react13 = require("motion/react");
|
|
851
|
+
|
|
852
|
+
// src/components/PromptTab.tsx
|
|
819
853
|
var import_react10 = require("react");
|
|
820
854
|
var import_react11 = require("motion/react");
|
|
821
855
|
var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
856
|
+
var PromptTab = ({ workspaceTags, onGenerate, isGenerating, feedback }) => {
|
|
857
|
+
const [selectedLabels, setSelectedLabels] = (0, import_react10.useState)(/* @__PURE__ */ new Set());
|
|
858
|
+
const [instructions, setInstructions] = (0, import_react10.useState)("");
|
|
859
|
+
const [showFeedback, setShowFeedback] = (0, import_react10.useState)(true);
|
|
860
|
+
const toggleTag = (label) => {
|
|
861
|
+
setSelectedLabels((prev) => {
|
|
862
|
+
const next = new Set(prev);
|
|
863
|
+
if (next.has(label)) next.delete(label);
|
|
864
|
+
else next.add(label);
|
|
865
|
+
return next;
|
|
866
|
+
});
|
|
867
|
+
};
|
|
868
|
+
const handleGenerate = () => {
|
|
869
|
+
const selectedValues = workspaceTags.all.filter((t) => selectedLabels.has(t.label)).map((t) => t.value);
|
|
870
|
+
onGenerate(selectedValues, instructions);
|
|
871
|
+
};
|
|
872
|
+
const categories = Object.entries(workspaceTags.by_category).filter(([, tags]) => tags.length > 0);
|
|
873
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "absolute inset-0 flex flex-col overflow-hidden", children: [
|
|
874
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex-1 overflow-y-auto dark-scrollbar px-3 py-3 flex flex-col gap-4", children: [
|
|
875
|
+
categories.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex flex-col items-center justify-center py-16 gap-3 opacity-20", children: [
|
|
876
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "material-symbols-outlined text-[48px]", children: "label_off" }),
|
|
877
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("p", { className: "text-[9px] font-bold uppercase tracking-widest text-center", children: [
|
|
878
|
+
"Keine Tags geladen.",
|
|
879
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("br", {}),
|
|
880
|
+
"Importiere ein Workspace-JSON im Setup-Tab."
|
|
881
|
+
] })
|
|
882
|
+
] }) : categories.map(([cat, tags]) => /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex flex-col gap-2", children: [
|
|
883
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(SectionLabel, { children: cat }),
|
|
884
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "flex flex-wrap gap-1", children: tags.map((t) => {
|
|
885
|
+
const active = selectedLabels.has(t.label);
|
|
886
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
887
|
+
"button",
|
|
888
|
+
{
|
|
889
|
+
onClick: () => toggleTag(t.label),
|
|
890
|
+
className: `px-2 py-1 rounded-lg text-[8px] font-bold uppercase tracking-wide transition-all border ${active ? "bg-blue-500 border-blue-400 text-white shadow-[0_0_8px_rgba(59,130,246,0.3)]" : "bg-white/5 border-white/5 text-white/30 hover:text-white/60 hover:bg-white/10"}`,
|
|
891
|
+
children: t.label
|
|
892
|
+
},
|
|
893
|
+
t.label
|
|
894
|
+
);
|
|
895
|
+
}) })
|
|
896
|
+
] }, cat)),
|
|
897
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex flex-col gap-2 mt-2", children: [
|
|
898
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(SectionLabel, { children: "Zus\xE4tzliche Anweisungen" }),
|
|
899
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
900
|
+
"textarea",
|
|
901
|
+
{
|
|
902
|
+
value: instructions,
|
|
903
|
+
onChange: (e) => setInstructions(e.target.value),
|
|
904
|
+
placeholder: "Weitere Vorgaben f\xFCr den AI-Prompt...",
|
|
905
|
+
className: "w-full bg-white/5 border border-white/10 rounded-xl p-3 text-[10px] text-white/70 placeholder-white/20 resize-none h-20 outline-none focus:border-white/20 dark-scrollbar"
|
|
906
|
+
}
|
|
907
|
+
)
|
|
908
|
+
] })
|
|
909
|
+
] }),
|
|
910
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "shrink-0 border-t border-white/5 p-3 flex flex-col gap-2", children: [
|
|
911
|
+
feedback && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex flex-col", children: [
|
|
912
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
|
|
913
|
+
"button",
|
|
914
|
+
{
|
|
915
|
+
onClick: () => setShowFeedback((p) => !p),
|
|
916
|
+
className: "flex items-center gap-1.5 text-[8px] font-bold uppercase text-amber-400/60 hover:text-amber-400 transition-colors mb-1",
|
|
917
|
+
children: [
|
|
918
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "material-symbols-outlined text-[12px]", children: "psychology" }),
|
|
919
|
+
"KI-Analyse",
|
|
920
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "material-symbols-outlined text-[12px] ml-auto", children: showFeedback ? "expand_less" : "expand_more" })
|
|
921
|
+
]
|
|
922
|
+
}
|
|
923
|
+
),
|
|
924
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react11.AnimatePresence, { children: showFeedback && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
925
|
+
import_react11.motion.div,
|
|
926
|
+
{
|
|
927
|
+
initial: { height: 0, opacity: 0 },
|
|
928
|
+
animate: { height: "auto", opacity: 1 },
|
|
929
|
+
exit: { height: 0, opacity: 0 },
|
|
930
|
+
className: "overflow-hidden",
|
|
931
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { className: "text-[9px] text-amber-400/50 leading-relaxed bg-amber-500/5 border border-amber-500/10 rounded-xl p-2 italic", children: feedback })
|
|
932
|
+
}
|
|
933
|
+
) })
|
|
934
|
+
] }),
|
|
935
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex items-center justify-between", children: [
|
|
936
|
+
selectedLabels.size > 0 ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { className: "text-[8px] text-white/30 font-bold uppercase", children: [
|
|
937
|
+
selectedLabels.size,
|
|
938
|
+
" Tags gew\xE4hlt"
|
|
939
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "text-[8px] text-white/20 italic", children: "Keine Tags gew\xE4hlt" }),
|
|
940
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
941
|
+
PillButton,
|
|
942
|
+
{
|
|
943
|
+
variant: "solid",
|
|
944
|
+
icon: "auto_fix_high",
|
|
945
|
+
loading: isGenerating,
|
|
946
|
+
disabled: selectedLabels.size === 0 && !instructions.trim(),
|
|
947
|
+
onClick: handleGenerate,
|
|
948
|
+
children: "Prompt bauen"
|
|
949
|
+
}
|
|
950
|
+
)
|
|
951
|
+
] })
|
|
952
|
+
] })
|
|
953
|
+
] });
|
|
954
|
+
};
|
|
955
|
+
|
|
956
|
+
// src/components/AvatarArchitectApp.tsx
|
|
957
|
+
var import_jsx_runtime11 = require("react/jsx-runtime");
|
|
822
958
|
function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onSelectMedia }) {
|
|
823
|
-
(0,
|
|
959
|
+
(0, import_react12.useEffect)(() => {
|
|
824
960
|
const id = "flow-styles";
|
|
825
961
|
if (!document.getElementById(id)) {
|
|
826
962
|
const style = document.createElement("style");
|
|
@@ -829,27 +965,31 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
829
965
|
document.head.appendChild(style);
|
|
830
966
|
}
|
|
831
967
|
}, []);
|
|
832
|
-
const [nodes, setNodes] = (0,
|
|
833
|
-
const [edges, setEdges] = (0,
|
|
834
|
-
const [history, setHistory] = (0,
|
|
835
|
-
const [galleryItems, setGalleryItems] = (0,
|
|
836
|
-
const [activePrompt, setActivePrompt] = (0,
|
|
837
|
-
const [isSynthesizing, setIsSynthesizing] = (0,
|
|
838
|
-
const [activeGenerationsCount, setActiveGenerationsCount] = (0,
|
|
839
|
-
const [currentResult, setCurrentResult] = (0,
|
|
840
|
-
const [focusedNodeId, setFocusedNodeId] = (0,
|
|
841
|
-
const [
|
|
842
|
-
const [
|
|
843
|
-
const [
|
|
844
|
-
const [
|
|
845
|
-
const [
|
|
846
|
-
const [
|
|
847
|
-
const [
|
|
848
|
-
const [
|
|
849
|
-
const [
|
|
968
|
+
const [nodes, setNodes] = (0, import_react12.useState)([{ id: "1", type: "custom", position: { x: 0, y: 0 }, data: { label: "Fine Art Project", placeholder: "Name..." } }]);
|
|
969
|
+
const [edges, setEdges] = (0, import_react12.useState)([]);
|
|
970
|
+
const [history, setHistory] = (0, import_react12.useState)([]);
|
|
971
|
+
const [galleryItems, setGalleryItems] = (0, import_react12.useState)([]);
|
|
972
|
+
const [activePrompt, setActivePrompt] = (0, import_react12.useState)("");
|
|
973
|
+
const [isSynthesizing, setIsSynthesizing] = (0, import_react12.useState)(false);
|
|
974
|
+
const [activeGenerationsCount, setActiveGenerationsCount] = (0, import_react12.useState)(0);
|
|
975
|
+
const [currentResult, setCurrentResult] = (0, import_react12.useState)(null);
|
|
976
|
+
const [focusedNodeId, setFocusedNodeId] = (0, import_react12.useState)(null);
|
|
977
|
+
const [leftTab, setLeftTab] = (0, import_react12.useState)("hierarchy");
|
|
978
|
+
const [promptFeedback, setPromptFeedback] = (0, import_react12.useState)(null);
|
|
979
|
+
const [isPromptTabGenerating, setIsPromptTabGenerating] = (0, import_react12.useState)(false);
|
|
980
|
+
const [activeTab, setActiveTab] = (0, import_react12.useState)("history");
|
|
981
|
+
const [aspectRatio, setAspectRatio] = (0, import_react12.useState)("1:1");
|
|
982
|
+
const [selectedModel, setSelectedModel] = (0, import_react12.useState)("\u{1F34C} Nano Banana Pro");
|
|
983
|
+
const [seed, setSeed] = (0, import_react12.useState)(Math.floor(Math.random() * 1e6));
|
|
984
|
+
const [seedMode, setSeedMode] = (0, import_react12.useState)("random");
|
|
985
|
+
const [isLeftCollapsed, setIsLeftCollapsed] = (0, import_react12.useState)(false);
|
|
986
|
+
const [isRightCollapsed, setIsRightCollapsed] = (0, import_react12.useState)(false);
|
|
987
|
+
const [isPromptCollapsed, setIsPromptCollapsed] = (0, import_react12.useState)(false);
|
|
988
|
+
const [projectActionState, setProjectActionState] = (0, import_react12.useState)("idle");
|
|
989
|
+
const [workspaceTags, setWorkspaceTags] = (0, import_react12.useState)(null);
|
|
850
990
|
const isGenerating = activeGenerationsCount > 0;
|
|
851
991
|
useKeyboardNavigation(history, currentResult, setCurrentResult);
|
|
852
|
-
const getSubtreeFormat = (0,
|
|
992
|
+
const getSubtreeFormat = (0, import_react12.useCallback)((nodeId, depth = 0) => {
|
|
853
993
|
const node = nodes.find((n) => n.id === nodeId);
|
|
854
994
|
if (!node) return "";
|
|
855
995
|
const childrenIds = edges.filter((e) => e.source === nodeId).map((e) => e.target);
|
|
@@ -857,7 +997,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
857
997
|
return `${indent}- ${node.data.label || "(unbenannt)"}
|
|
858
998
|
` + childrenIds.map((id) => getSubtreeFormat(id, depth + 1)).join("");
|
|
859
999
|
}, [nodes, edges]);
|
|
860
|
-
const activePath = (0,
|
|
1000
|
+
const activePath = (0, import_react12.useMemo)(() => {
|
|
861
1001
|
if (!focusedNodeId) return /* @__PURE__ */ new Set();
|
|
862
1002
|
const path = /* @__PURE__ */ new Set([focusedNodeId]);
|
|
863
1003
|
let currId = focusedNodeId;
|
|
@@ -910,16 +1050,32 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
910
1050
|
const handleSynthesizePrompt = async (nodeId, autoGenerate = false) => {
|
|
911
1051
|
setIsSynthesizing(true);
|
|
912
1052
|
try {
|
|
913
|
-
const
|
|
914
|
-
setActivePrompt(
|
|
1053
|
+
const raw = await onGeneratePrompt(getSubtreeFormat(nodeId));
|
|
1054
|
+
setActivePrompt(raw);
|
|
915
1055
|
setFocusedNodeId(nodeId);
|
|
916
|
-
if (autoGenerate) handleGenerateImage(
|
|
1056
|
+
if (autoGenerate) handleGenerateImage(raw, void 0, nodeId);
|
|
917
1057
|
} catch {
|
|
918
1058
|
setActivePrompt("Synthese-Fehler");
|
|
919
1059
|
} finally {
|
|
920
1060
|
setIsSynthesizing(false);
|
|
921
1061
|
}
|
|
922
1062
|
};
|
|
1063
|
+
const handlePromptTabGenerate = async (selectedValues, instructions) => {
|
|
1064
|
+
setIsPromptTabGenerating(true);
|
|
1065
|
+
setPromptFeedback(null);
|
|
1066
|
+
try {
|
|
1067
|
+
const treeText = focusedNodeId ? getSubtreeFormat(focusedNodeId) : void 0;
|
|
1068
|
+
const payload = buildPromptTabPayload(selectedValues, instructions, treeText);
|
|
1069
|
+
const raw = await onGeneratePrompt(payload);
|
|
1070
|
+
const { prompt, feedback } = parsePromptResponse(raw);
|
|
1071
|
+
setActivePrompt(prompt);
|
|
1072
|
+
setPromptFeedback(feedback);
|
|
1073
|
+
} catch {
|
|
1074
|
+
setActivePrompt("Synthese-Fehler");
|
|
1075
|
+
} finally {
|
|
1076
|
+
setIsPromptTabGenerating(false);
|
|
1077
|
+
}
|
|
1078
|
+
};
|
|
923
1079
|
const handleDownloadSingle = async () => {
|
|
924
1080
|
if (!currentResult?.base64) return;
|
|
925
1081
|
try {
|
|
@@ -975,58 +1131,100 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
975
1131
|
const root = JSON.parse(ev.target?.result);
|
|
976
1132
|
const rawTags = root.tags || root;
|
|
977
1133
|
if (!rawTags?.by_category) return;
|
|
1134
|
+
const filtered = {};
|
|
1135
|
+
const EXCLUDED = ["pdf-export", "book.micro-edit-rules"];
|
|
1136
|
+
Object.entries(rawTags.by_category).forEach(([cat, items]) => {
|
|
1137
|
+
if (EXCLUDED.includes(cat) || !Array.isArray(items)) return;
|
|
1138
|
+
filtered[cat] = items.filter((t) => t && typeof t === "object" && t.label && t.value);
|
|
1139
|
+
});
|
|
1140
|
+
const filteredAll = (rawTags.all || []).filter((t) => t && !EXCLUDED.includes(t.category));
|
|
1141
|
+
setWorkspaceTags({ by_category: filtered, all: filteredAll });
|
|
978
1142
|
} catch (err) {
|
|
979
1143
|
console.error("Workspace Load failed", err);
|
|
980
1144
|
}
|
|
981
1145
|
};
|
|
982
1146
|
reader.readAsText(file);
|
|
983
1147
|
};
|
|
984
|
-
return /* @__PURE__ */ (0,
|
|
985
|
-
/* @__PURE__ */ (0,
|
|
986
|
-
/* @__PURE__ */ (0,
|
|
987
|
-
!isLeftCollapsed && /* @__PURE__ */ (0,
|
|
988
|
-
|
|
1148
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex h-screen w-screen bg-[#0e0e0e] text-white overflow-hidden", children: [
|
|
1149
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_react13.motion.div, { animate: { width: isLeftCollapsed ? 48 : 260 }, className: "flex flex-col border-r border-white/5 overflow-hidden relative bg-black/10 shrink-0", children: [
|
|
1150
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "h-14 border-b border-white/5 flex items-center justify-between shrink-0 px-1", children: [
|
|
1151
|
+
!isLeftCollapsed && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex flex-1 gap-1", children: [
|
|
1152
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
|
|
1153
|
+
"button",
|
|
1154
|
+
{
|
|
1155
|
+
onClick: () => setLeftTab("hierarchy"),
|
|
1156
|
+
className: `flex-1 flex items-center justify-center gap-1 h-8 rounded-lg text-[8px] font-bold uppercase tracking-wide transition-colors ${leftTab === "hierarchy" ? "bg-white/10 text-white" : "text-white/30 hover:text-white/60"}`,
|
|
1157
|
+
children: [
|
|
1158
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "material-symbols-outlined text-[14px]", children: "account_tree" }),
|
|
1159
|
+
"Hierarchie"
|
|
1160
|
+
]
|
|
1161
|
+
}
|
|
1162
|
+
),
|
|
1163
|
+
workspaceTags && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
|
|
1164
|
+
"button",
|
|
1165
|
+
{
|
|
1166
|
+
onClick: () => setLeftTab("prompt"),
|
|
1167
|
+
className: `flex-1 flex items-center justify-center gap-1 h-8 rounded-lg text-[8px] font-bold uppercase tracking-wide transition-colors ${leftTab === "prompt" ? "bg-white/10 text-white" : "text-white/30 hover:text-white/60"}`,
|
|
1168
|
+
children: [
|
|
1169
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "material-symbols-outlined text-[14px]", children: "auto_fix_high" }),
|
|
1170
|
+
"Prompt"
|
|
1171
|
+
]
|
|
1172
|
+
}
|
|
1173
|
+
)
|
|
1174
|
+
] }),
|
|
1175
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { onClick: () => setIsLeftCollapsed(!isLeftCollapsed), className: "material-symbols-outlined text-[18px] text-white/40 hover:text-white transition-all w-10 flex items-center justify-center", children: isLeftCollapsed ? "chevron_right" : "chevron_left" })
|
|
989
1176
|
] }),
|
|
990
|
-
!isLeftCollapsed && /* @__PURE__ */ (0,
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1177
|
+
!isLeftCollapsed && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "flex-1 overflow-hidden relative", children: /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_react13.AnimatePresence, { mode: "wait", children: [
|
|
1178
|
+
leftTab === "hierarchy" && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react13.motion.div, { className: "absolute inset-0", initial: { opacity: 0 }, animate: { opacity: 1 }, exit: { opacity: 0 }, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
1179
|
+
ListView,
|
|
1180
|
+
{
|
|
1181
|
+
nodes,
|
|
1182
|
+
edges,
|
|
1183
|
+
onNodeChange: (id, l) => setNodes((nds) => nds.map((n) => n.id === id ? { ...n, data: { ...n.data, label: l } } : n)),
|
|
1184
|
+
onAddChild: (pId) => {
|
|
1185
|
+
const newId = crypto.randomUUID();
|
|
1186
|
+
setNodes((nds) => [...nds, { id: newId, type: "custom", position: { x: 0, y: 0 }, data: { label: "", placeholder: "Konzept..." } }]);
|
|
1187
|
+
setEdges((eds) => [...eds, { id: `e-${pId}-${newId}`, source: pId, target: newId }]);
|
|
1188
|
+
setFocusedNodeId(newId);
|
|
1189
|
+
return newId;
|
|
1190
|
+
},
|
|
1191
|
+
onDeleteNode: (id) => {
|
|
1192
|
+
setNodes((nds) => nds.filter((n) => n.id !== id));
|
|
1193
|
+
setEdges((eds) => eds.filter((e) => e.source !== id && e.target !== id));
|
|
1194
|
+
},
|
|
1195
|
+
onFocus: setFocusedNodeId,
|
|
1196
|
+
focusedNodeId,
|
|
1197
|
+
activePath,
|
|
1198
|
+
onGenerate: handleSynthesizePrompt,
|
|
1199
|
+
onGenerateBranch: (id) => handleSynthesizePrompt(id, true),
|
|
1200
|
+
isGeneratingNodeId: (id) => isSynthesizing && focusedNodeId === id
|
|
1201
|
+
}
|
|
1202
|
+
) }, "hierarchy"),
|
|
1203
|
+
leftTab === "prompt" && workspaceTags && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react13.motion.div, { className: "absolute inset-0", initial: { opacity: 0 }, animate: { opacity: 1 }, exit: { opacity: 0 }, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
1204
|
+
PromptTab,
|
|
1205
|
+
{
|
|
1206
|
+
workspaceTags,
|
|
1207
|
+
onGenerate: handlePromptTabGenerate,
|
|
1208
|
+
isGenerating: isPromptTabGenerating,
|
|
1209
|
+
feedback: promptFeedback
|
|
1210
|
+
}
|
|
1211
|
+
) }, "prompt")
|
|
1212
|
+
] }) })
|
|
1015
1213
|
] }),
|
|
1016
|
-
/* @__PURE__ */ (0,
|
|
1017
|
-
/* @__PURE__ */ (0,
|
|
1018
|
-
/* @__PURE__ */ (0,
|
|
1019
|
-
/* @__PURE__ */ (0,
|
|
1020
|
-
/* @__PURE__ */ (0,
|
|
1214
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex-1 flex flex-col bg-[#0b0b0b] overflow-hidden", children: [
|
|
1215
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "h-14 border-b border-white/5 flex items-center px-4 gap-2 justify-between shrink-0 bg-black/20", children: [
|
|
1216
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex items-center gap-1.5", children: [
|
|
1217
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.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" }] }),
|
|
1218
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.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" }] })
|
|
1021
1219
|
] }),
|
|
1022
|
-
/* @__PURE__ */ (0,
|
|
1023
|
-
/* @__PURE__ */ (0,
|
|
1024
|
-
/* @__PURE__ */ (0,
|
|
1220
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
1221
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { onClick: () => setIsPromptCollapsed(!isPromptCollapsed), className: "text-white/40 hover:text-white transition-colors", children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "material-symbols-outlined", children: isPromptCollapsed ? "expand_more" : "expand_less" }) }),
|
|
1222
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(PillButton, { variant: "solid", icon: "bolt", loading: isGenerating, disabled: !activePrompt.trim(), onClick: () => handleGenerateImage(), children: "Generieren" })
|
|
1025
1223
|
] })
|
|
1026
1224
|
] }),
|
|
1027
|
-
/* @__PURE__ */ (0,
|
|
1028
|
-
/* @__PURE__ */ (0,
|
|
1029
|
-
/* @__PURE__ */ (0,
|
|
1225
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex-1 flex flex-col overflow-hidden relative", children: [
|
|
1226
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react13.AnimatePresence, { children: !isPromptCollapsed && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react13.motion.div, { initial: { height: 0 }, animate: { height: "auto" }, exit: { height: 0 }, className: "px-6 py-4 border-b border-white/5 bg-black/10 overflow-hidden shrink-0", children: /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: `relative min-h-[60px] p-4 rounded-2xl border transition-all ${isSynthesizing ? "prompt-loading" : "bg-white/5 border-white/10"}`, children: [
|
|
1227
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
1030
1228
|
"textarea",
|
|
1031
1229
|
{
|
|
1032
1230
|
value: activePrompt,
|
|
@@ -1035,48 +1233,48 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
1035
1233
|
placeholder: "W\xE4hle einen Knoten oder tippe einen Prompt..."
|
|
1036
1234
|
}
|
|
1037
1235
|
),
|
|
1038
|
-
activePrompt && !isSynthesizing && /* @__PURE__ */ (0,
|
|
1236
|
+
activePrompt && !isSynthesizing && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { onClick: () => setActivePrompt(""), className: "absolute top-2 right-2 w-6 h-6 rounded-full bg-white/5 hover:bg-white/10 flex items-center justify-center transition-colors text-white/20 hover:text-white", children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "material-symbols-outlined text-[14px]", children: "close" }) })
|
|
1039
1237
|
] }) }) }),
|
|
1040
|
-
/* @__PURE__ */ (0,
|
|
1041
|
-
isGenerating && currentResult?.status === "done" && /* @__PURE__ */ (0,
|
|
1042
|
-
/* @__PURE__ */ (0,
|
|
1043
|
-
/* @__PURE__ */ (0,
|
|
1238
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "flex-1 p-6 overflow-hidden flex items-center justify-center", children: /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "h-full w-full max-w-4xl aspect-square rounded-3xl border border-white/5 bg-black/40 relative overflow-hidden flex items-center justify-center group shadow-2xl", children: [
|
|
1239
|
+
isGenerating && currentResult?.status === "done" && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "absolute top-6 right-6 z-30 bg-black/60 backdrop-blur-md px-4 py-2 rounded-full border border-white/10 flex items-center gap-3", children: [
|
|
1240
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "w-3 h-3 border-t-2 border-white rounded-full animate-spin" }),
|
|
1241
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "text-[10px] text-white/60 uppercase font-bold tracking-widest", children: "Neue Referenz..." })
|
|
1044
1242
|
] }),
|
|
1045
|
-
currentResult ? currentResult.status === "processing" ? /* @__PURE__ */ (0,
|
|
1046
|
-
/* @__PURE__ */ (0,
|
|
1047
|
-
/* @__PURE__ */ (0,
|
|
1048
|
-
] }) : currentResult.status === "error" ? /* @__PURE__ */ (0,
|
|
1049
|
-
/* @__PURE__ */ (0,
|
|
1050
|
-
/* @__PURE__ */ (0,
|
|
1051
|
-
/* @__PURE__ */ (0,
|
|
1052
|
-
/* @__PURE__ */ (0,
|
|
1243
|
+
currentResult ? currentResult.status === "processing" ? /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex flex-col items-center gap-4", children: [
|
|
1244
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "w-10 h-10 border-t-2 border-white rounded-full animate-spin" }),
|
|
1245
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "text-[10px] text-white/40 uppercase font-bold tracking-widest", children: "Erstelle Bild..." })
|
|
1246
|
+
] }) : currentResult.status === "error" ? /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "p-10 text-center flex flex-col items-center gap-5 max-w-md", children: [
|
|
1247
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "w-16 h-16 rounded-full bg-red-500/10 flex items-center justify-center", children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "material-symbols-outlined text-red-500 text-[32px]", children: "warning" }) }),
|
|
1248
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex flex-col gap-2", children: [
|
|
1249
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("h3", { className: "text-[11px] font-bold uppercase tracking-widest text-red-400", children: "Generierungsfehler" }),
|
|
1250
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { className: "text-white/60 text-[12px] leading-relaxed", children: currentResult.error?.message })
|
|
1053
1251
|
] }),
|
|
1054
|
-
/* @__PURE__ */ (0,
|
|
1055
|
-
] }) : /* @__PURE__ */ (0,
|
|
1056
|
-
/* @__PURE__ */ (0,
|
|
1057
|
-
/* @__PURE__ */ (0,
|
|
1058
|
-
/* @__PURE__ */ (0,
|
|
1059
|
-
/* @__PURE__ */ (0,
|
|
1060
|
-
/* @__PURE__ */ (0,
|
|
1252
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(PillButton, { variant: "outline", icon: "refresh", onClick: () => handleGenerateImage(currentResult.prompt), children: "Erneut versuchen" })
|
|
1253
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "h-full w-full relative flex items-center justify-center", children: [
|
|
1254
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("img", { src: currentResult.base64, className: "max-h-full max-w-full object-contain rounded-xl shadow-2xl" }),
|
|
1255
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "absolute bottom-6 flex gap-2 opacity-0 group-hover:opacity-100 transition-all translate-y-4 group-hover:translate-y-0 z-20", children: [
|
|
1256
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(PillButton, { variant: "outline", icon: "replay", onClick: () => setActivePrompt(currentResult.prompt || ""), children: "Prompt" }),
|
|
1257
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(PillButton, { variant: "solid", icon: "auto_fix_high", onClick: () => handleGenerateImage(currentResult.prompt || activePrompt, currentResult.mediaId, void 0, { silent: true }), children: "Referenz" }),
|
|
1258
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(PillButton, { variant: "outline", icon: "download", onClick: handleDownloadSingle, children: "Speichern" })
|
|
1061
1259
|
] })
|
|
1062
|
-
] }) : /* @__PURE__ */ (0,
|
|
1063
|
-
/* @__PURE__ */ (0,
|
|
1064
|
-
/* @__PURE__ */ (0,
|
|
1260
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex flex-col items-center gap-2 opacity-10", children: [
|
|
1261
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "material-symbols-outlined text-[100px]", children: "palette" }),
|
|
1262
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "text-[12px] font-bold uppercase tracking-[0.2em]", children: "Avatar Architect" })
|
|
1065
1263
|
] })
|
|
1066
1264
|
] }) })
|
|
1067
1265
|
] })
|
|
1068
1266
|
] }),
|
|
1069
|
-
/* @__PURE__ */ (0,
|
|
1070
|
-
/* @__PURE__ */ (0,
|
|
1071
|
-
/* @__PURE__ */ (0,
|
|
1267
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_react13.motion.div, { animate: { width: isRightCollapsed ? 60 : 320 }, className: "flex flex-col border-l border-white/5 bg-[#0e0e0e] shrink-0", children: [
|
|
1268
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex border-b border-white/5 h-14 shrink-0 overflow-hidden", children: [
|
|
1269
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "flex flex-1", children: ["history", "gallery", "inspect", "setup"].map((tab) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { onClick: () => {
|
|
1072
1270
|
setActiveTab(tab);
|
|
1073
1271
|
setIsRightCollapsed(false);
|
|
1074
|
-
}, className: `flex-1 flex items-center justify-center relative transition-colors ${activeTab === tab ? "text-white" : "text-white/20"}`, children: /* @__PURE__ */ (0,
|
|
1075
|
-
/* @__PURE__ */ (0,
|
|
1272
|
+
}, className: `flex-1 flex items-center justify-center relative transition-colors ${activeTab === tab ? "text-white" : "text-white/20"}`, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "material-symbols-outlined text-[20px]", children: tab === "history" ? "history" : tab === "gallery" ? "photo_library" : tab === "inspect" ? "info" : "settings" }) }, tab)) }),
|
|
1273
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { onClick: () => setIsRightCollapsed(!isRightCollapsed), className: "w-10 flex items-center justify-center text-white/20 hover:text-white", children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "material-symbols-outlined text-[18px]", children: isRightCollapsed ? "chevron_left" : "chevron_right" }) })
|
|
1076
1274
|
] }),
|
|
1077
|
-
!isRightCollapsed && /* @__PURE__ */ (0,
|
|
1078
|
-
activeTab === "history" && /* @__PURE__ */ (0,
|
|
1079
|
-
activeTab === "gallery" && /* @__PURE__ */ (0,
|
|
1275
|
+
!isRightCollapsed && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "flex-1 overflow-hidden relative", children: /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_react13.AnimatePresence, { mode: "wait", children: [
|
|
1276
|
+
activeTab === "history" && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(HistoryPanel, { history, currentResultId: currentResult?.id || null, onSelect: setCurrentResult, onDelete: (id) => setHistory((h) => h.filter((x) => x.id !== id)) }, "history"),
|
|
1277
|
+
activeTab === "gallery" && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
1080
1278
|
MediaLibrary,
|
|
1081
1279
|
{
|
|
1082
1280
|
items: galleryItems,
|
|
@@ -1102,8 +1300,8 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
1102
1300
|
},
|
|
1103
1301
|
"gallery"
|
|
1104
1302
|
),
|
|
1105
|
-
activeTab === "inspect" && /* @__PURE__ */ (0,
|
|
1106
|
-
activeTab === "setup" && /* @__PURE__ */ (0,
|
|
1303
|
+
activeTab === "inspect" && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(InspectPanel, { currentResult, history, onSelect: setCurrentResult }, "inspect"),
|
|
1304
|
+
activeTab === "setup" && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
1107
1305
|
SetupPanel,
|
|
1108
1306
|
{
|
|
1109
1307
|
onProjectExport: handleProjectExport,
|
|
@@ -1128,11 +1326,13 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
1128
1326
|
ListView,
|
|
1129
1327
|
MediaLibrary,
|
|
1130
1328
|
PillButton,
|
|
1329
|
+
PromptTab,
|
|
1131
1330
|
SectionLabel,
|
|
1132
1331
|
SetupPanel,
|
|
1133
1332
|
buildFallbackPrompt,
|
|
1134
1333
|
buildGenerationPrompt,
|
|
1135
1334
|
buildImageGenerationOptions,
|
|
1335
|
+
buildPromptTabPayload,
|
|
1136
1336
|
cleanAiResponse,
|
|
1137
1337
|
exportProjectToZip,
|
|
1138
1338
|
formatTreeToMarkdown,
|
|
@@ -1141,6 +1341,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
1141
1341
|
injectXMPMetadata,
|
|
1142
1342
|
interpretSdkError,
|
|
1143
1343
|
parsePromptFile,
|
|
1344
|
+
parsePromptResponse,
|
|
1144
1345
|
useKeyboardNavigation,
|
|
1145
1346
|
useOnClickOutside
|
|
1146
1347
|
});
|
package/dist/index.mjs
CHANGED
|
@@ -293,6 +293,33 @@ function buildImageGenerationOptions(prompt, aspectRatio, model, referenceMediaI
|
|
|
293
293
|
}
|
|
294
294
|
return options;
|
|
295
295
|
}
|
|
296
|
+
function buildPromptTabPayload(selectedValues, instructions, treeText) {
|
|
297
|
+
const parts = [];
|
|
298
|
+
if (treeText) parts.push(`HIERARCHY:
|
|
299
|
+
${treeText}`);
|
|
300
|
+
if (selectedValues.length > 0) parts.push(`SELECTED TAGS:
|
|
301
|
+
${selectedValues.join(", ")}`);
|
|
302
|
+
if (instructions.trim()) parts.push(`ADDITIONAL INSTRUCTIONS:
|
|
303
|
+
${instructions.trim()}`);
|
|
304
|
+
return [
|
|
305
|
+
"Create a high-quality image generation prompt based on the following inputs. Translate everything to English.",
|
|
306
|
+
`Return a JSON object with exactly two keys: "prompt" (the prompt string) and "feedback" (a short note on your choices in the user's language, or null).`,
|
|
307
|
+
"Output ONLY the JSON object, no markdown, no wrapping.",
|
|
308
|
+
"",
|
|
309
|
+
...parts
|
|
310
|
+
].join("\n");
|
|
311
|
+
}
|
|
312
|
+
function parsePromptResponse(raw) {
|
|
313
|
+
const cleaned = raw.replace(/^```json\s*/i, "").replace(/^```\s*/i, "").replace(/```$/i, "").trim();
|
|
314
|
+
try {
|
|
315
|
+
const parsed = JSON.parse(cleaned);
|
|
316
|
+
if (typeof parsed?.prompt === "string") {
|
|
317
|
+
return { prompt: parsed.prompt.trim(), feedback: parsed.feedback ?? null };
|
|
318
|
+
}
|
|
319
|
+
} catch {
|
|
320
|
+
}
|
|
321
|
+
return { prompt: cleaned, feedback: null };
|
|
322
|
+
}
|
|
296
323
|
function interpretSdkError(err) {
|
|
297
324
|
const msg = err?.message || "Generierung fehlgeschlagen";
|
|
298
325
|
if (msg.includes("PUBLIC_ERROR_SOMETHING_WENT_WRONG")) {
|
|
@@ -544,8 +571,8 @@ var InspectPanel = ({ currentResult, history, onSelect, workspaceTags, onTagTogg
|
|
|
544
571
|
Object.entries(workspaceTags.by_category).map(([cat, tags]) => /* @__PURE__ */ jsxs4("div", { className: "flex flex-col gap-2", children: [
|
|
545
572
|
/* @__PURE__ */ jsx6("span", { className: "text-[8px] font-bold text-white/30 uppercase tracking-widest px-1", children: cat }),
|
|
546
573
|
/* @__PURE__ */ jsx6("div", { className: "flex flex-wrap gap-1.5", children: tags.map((t) => {
|
|
547
|
-
const isActive = (currentResult.tags || []).includes(t);
|
|
548
|
-
return /* @__PURE__ */ jsx6("button", { onClick: () => onTagToggle?.(t), className: `px-2.5 py-1 rounded-lg text-[8px] font-bold uppercase transition-all border ${isActive ? "bg-blue-500 border-blue-400 text-white shadow-[0_0_10px_rgba(59,130,246,0.3)]" : "bg-white/5 border-white/5 text-white/20 hover:text-white/50 hover:bg-white/10"}`, children: t }, t);
|
|
574
|
+
const isActive = (currentResult.tags || []).includes(t.label);
|
|
575
|
+
return /* @__PURE__ */ jsx6("button", { onClick: () => onTagToggle?.(t.label), className: `px-2.5 py-1 rounded-lg text-[8px] font-bold uppercase transition-all border ${isActive ? "bg-blue-500 border-blue-400 text-white shadow-[0_0_10px_rgba(59,130,246,0.3)]" : "bg-white/5 border-white/5 text-white/20 hover:text-white/50 hover:bg-white/10"}`, children: t.label }, t.label);
|
|
549
576
|
}) })
|
|
550
577
|
] }, cat))
|
|
551
578
|
] })
|
|
@@ -757,9 +784,115 @@ function ListView({ nodes, edges, onNodeChange, onAddChild, onDeleteNode, onMove
|
|
|
757
784
|
}
|
|
758
785
|
|
|
759
786
|
// src/components/AvatarArchitectApp.tsx
|
|
760
|
-
import { useState as
|
|
787
|
+
import { useState as useState4, useCallback, useMemo, useEffect as useEffect4 } from "react";
|
|
788
|
+
import { motion as motion6, AnimatePresence as AnimatePresence2 } from "motion/react";
|
|
789
|
+
|
|
790
|
+
// src/components/PromptTab.tsx
|
|
791
|
+
import { useState as useState3 } from "react";
|
|
761
792
|
import { motion as motion5, AnimatePresence } from "motion/react";
|
|
762
793
|
import { jsx as jsx10, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
794
|
+
var PromptTab = ({ workspaceTags, onGenerate, isGenerating, feedback }) => {
|
|
795
|
+
const [selectedLabels, setSelectedLabels] = useState3(/* @__PURE__ */ new Set());
|
|
796
|
+
const [instructions, setInstructions] = useState3("");
|
|
797
|
+
const [showFeedback, setShowFeedback] = useState3(true);
|
|
798
|
+
const toggleTag = (label) => {
|
|
799
|
+
setSelectedLabels((prev) => {
|
|
800
|
+
const next = new Set(prev);
|
|
801
|
+
if (next.has(label)) next.delete(label);
|
|
802
|
+
else next.add(label);
|
|
803
|
+
return next;
|
|
804
|
+
});
|
|
805
|
+
};
|
|
806
|
+
const handleGenerate = () => {
|
|
807
|
+
const selectedValues = workspaceTags.all.filter((t) => selectedLabels.has(t.label)).map((t) => t.value);
|
|
808
|
+
onGenerate(selectedValues, instructions);
|
|
809
|
+
};
|
|
810
|
+
const categories = Object.entries(workspaceTags.by_category).filter(([, tags]) => tags.length > 0);
|
|
811
|
+
return /* @__PURE__ */ jsxs8("div", { className: "absolute inset-0 flex flex-col overflow-hidden", children: [
|
|
812
|
+
/* @__PURE__ */ jsxs8("div", { className: "flex-1 overflow-y-auto dark-scrollbar px-3 py-3 flex flex-col gap-4", children: [
|
|
813
|
+
categories.length === 0 ? /* @__PURE__ */ jsxs8("div", { className: "flex flex-col items-center justify-center py-16 gap-3 opacity-20", children: [
|
|
814
|
+
/* @__PURE__ */ jsx10("span", { className: "material-symbols-outlined text-[48px]", children: "label_off" }),
|
|
815
|
+
/* @__PURE__ */ jsxs8("p", { className: "text-[9px] font-bold uppercase tracking-widest text-center", children: [
|
|
816
|
+
"Keine Tags geladen.",
|
|
817
|
+
/* @__PURE__ */ jsx10("br", {}),
|
|
818
|
+
"Importiere ein Workspace-JSON im Setup-Tab."
|
|
819
|
+
] })
|
|
820
|
+
] }) : categories.map(([cat, tags]) => /* @__PURE__ */ jsxs8("div", { className: "flex flex-col gap-2", children: [
|
|
821
|
+
/* @__PURE__ */ jsx10(SectionLabel, { children: cat }),
|
|
822
|
+
/* @__PURE__ */ jsx10("div", { className: "flex flex-wrap gap-1", children: tags.map((t) => {
|
|
823
|
+
const active = selectedLabels.has(t.label);
|
|
824
|
+
return /* @__PURE__ */ jsx10(
|
|
825
|
+
"button",
|
|
826
|
+
{
|
|
827
|
+
onClick: () => toggleTag(t.label),
|
|
828
|
+
className: `px-2 py-1 rounded-lg text-[8px] font-bold uppercase tracking-wide transition-all border ${active ? "bg-blue-500 border-blue-400 text-white shadow-[0_0_8px_rgba(59,130,246,0.3)]" : "bg-white/5 border-white/5 text-white/30 hover:text-white/60 hover:bg-white/10"}`,
|
|
829
|
+
children: t.label
|
|
830
|
+
},
|
|
831
|
+
t.label
|
|
832
|
+
);
|
|
833
|
+
}) })
|
|
834
|
+
] }, cat)),
|
|
835
|
+
/* @__PURE__ */ jsxs8("div", { className: "flex flex-col gap-2 mt-2", children: [
|
|
836
|
+
/* @__PURE__ */ jsx10(SectionLabel, { children: "Zus\xE4tzliche Anweisungen" }),
|
|
837
|
+
/* @__PURE__ */ jsx10(
|
|
838
|
+
"textarea",
|
|
839
|
+
{
|
|
840
|
+
value: instructions,
|
|
841
|
+
onChange: (e) => setInstructions(e.target.value),
|
|
842
|
+
placeholder: "Weitere Vorgaben f\xFCr den AI-Prompt...",
|
|
843
|
+
className: "w-full bg-white/5 border border-white/10 rounded-xl p-3 text-[10px] text-white/70 placeholder-white/20 resize-none h-20 outline-none focus:border-white/20 dark-scrollbar"
|
|
844
|
+
}
|
|
845
|
+
)
|
|
846
|
+
] })
|
|
847
|
+
] }),
|
|
848
|
+
/* @__PURE__ */ jsxs8("div", { className: "shrink-0 border-t border-white/5 p-3 flex flex-col gap-2", children: [
|
|
849
|
+
feedback && /* @__PURE__ */ jsxs8("div", { className: "flex flex-col", children: [
|
|
850
|
+
/* @__PURE__ */ jsxs8(
|
|
851
|
+
"button",
|
|
852
|
+
{
|
|
853
|
+
onClick: () => setShowFeedback((p) => !p),
|
|
854
|
+
className: "flex items-center gap-1.5 text-[8px] font-bold uppercase text-amber-400/60 hover:text-amber-400 transition-colors mb-1",
|
|
855
|
+
children: [
|
|
856
|
+
/* @__PURE__ */ jsx10("span", { className: "material-symbols-outlined text-[12px]", children: "psychology" }),
|
|
857
|
+
"KI-Analyse",
|
|
858
|
+
/* @__PURE__ */ jsx10("span", { className: "material-symbols-outlined text-[12px] ml-auto", children: showFeedback ? "expand_less" : "expand_more" })
|
|
859
|
+
]
|
|
860
|
+
}
|
|
861
|
+
),
|
|
862
|
+
/* @__PURE__ */ jsx10(AnimatePresence, { children: showFeedback && /* @__PURE__ */ jsx10(
|
|
863
|
+
motion5.div,
|
|
864
|
+
{
|
|
865
|
+
initial: { height: 0, opacity: 0 },
|
|
866
|
+
animate: { height: "auto", opacity: 1 },
|
|
867
|
+
exit: { height: 0, opacity: 0 },
|
|
868
|
+
className: "overflow-hidden",
|
|
869
|
+
children: /* @__PURE__ */ jsx10("p", { className: "text-[9px] text-amber-400/50 leading-relaxed bg-amber-500/5 border border-amber-500/10 rounded-xl p-2 italic", children: feedback })
|
|
870
|
+
}
|
|
871
|
+
) })
|
|
872
|
+
] }),
|
|
873
|
+
/* @__PURE__ */ jsxs8("div", { className: "flex items-center justify-between", children: [
|
|
874
|
+
selectedLabels.size > 0 ? /* @__PURE__ */ jsxs8("span", { className: "text-[8px] text-white/30 font-bold uppercase", children: [
|
|
875
|
+
selectedLabels.size,
|
|
876
|
+
" Tags gew\xE4hlt"
|
|
877
|
+
] }) : /* @__PURE__ */ jsx10("span", { className: "text-[8px] text-white/20 italic", children: "Keine Tags gew\xE4hlt" }),
|
|
878
|
+
/* @__PURE__ */ jsx10(
|
|
879
|
+
PillButton,
|
|
880
|
+
{
|
|
881
|
+
variant: "solid",
|
|
882
|
+
icon: "auto_fix_high",
|
|
883
|
+
loading: isGenerating,
|
|
884
|
+
disabled: selectedLabels.size === 0 && !instructions.trim(),
|
|
885
|
+
onClick: handleGenerate,
|
|
886
|
+
children: "Prompt bauen"
|
|
887
|
+
}
|
|
888
|
+
)
|
|
889
|
+
] })
|
|
890
|
+
] })
|
|
891
|
+
] });
|
|
892
|
+
};
|
|
893
|
+
|
|
894
|
+
// src/components/AvatarArchitectApp.tsx
|
|
895
|
+
import { jsx as jsx11, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
763
896
|
function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onSelectMedia }) {
|
|
764
897
|
useEffect4(() => {
|
|
765
898
|
const id = "flow-styles";
|
|
@@ -770,24 +903,28 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
770
903
|
document.head.appendChild(style);
|
|
771
904
|
}
|
|
772
905
|
}, []);
|
|
773
|
-
const [nodes, setNodes] =
|
|
774
|
-
const [edges, setEdges] =
|
|
775
|
-
const [history, setHistory] =
|
|
776
|
-
const [galleryItems, setGalleryItems] =
|
|
777
|
-
const [activePrompt, setActivePrompt] =
|
|
778
|
-
const [isSynthesizing, setIsSynthesizing] =
|
|
779
|
-
const [activeGenerationsCount, setActiveGenerationsCount] =
|
|
780
|
-
const [currentResult, setCurrentResult] =
|
|
781
|
-
const [focusedNodeId, setFocusedNodeId] =
|
|
782
|
-
const [
|
|
783
|
-
const [
|
|
784
|
-
const [
|
|
785
|
-
const [
|
|
786
|
-
const [
|
|
787
|
-
const [
|
|
788
|
-
const [
|
|
789
|
-
const [
|
|
790
|
-
const [
|
|
906
|
+
const [nodes, setNodes] = useState4([{ id: "1", type: "custom", position: { x: 0, y: 0 }, data: { label: "Fine Art Project", placeholder: "Name..." } }]);
|
|
907
|
+
const [edges, setEdges] = useState4([]);
|
|
908
|
+
const [history, setHistory] = useState4([]);
|
|
909
|
+
const [galleryItems, setGalleryItems] = useState4([]);
|
|
910
|
+
const [activePrompt, setActivePrompt] = useState4("");
|
|
911
|
+
const [isSynthesizing, setIsSynthesizing] = useState4(false);
|
|
912
|
+
const [activeGenerationsCount, setActiveGenerationsCount] = useState4(0);
|
|
913
|
+
const [currentResult, setCurrentResult] = useState4(null);
|
|
914
|
+
const [focusedNodeId, setFocusedNodeId] = useState4(null);
|
|
915
|
+
const [leftTab, setLeftTab] = useState4("hierarchy");
|
|
916
|
+
const [promptFeedback, setPromptFeedback] = useState4(null);
|
|
917
|
+
const [isPromptTabGenerating, setIsPromptTabGenerating] = useState4(false);
|
|
918
|
+
const [activeTab, setActiveTab] = useState4("history");
|
|
919
|
+
const [aspectRatio, setAspectRatio] = useState4("1:1");
|
|
920
|
+
const [selectedModel, setSelectedModel] = useState4("\u{1F34C} Nano Banana Pro");
|
|
921
|
+
const [seed, setSeed] = useState4(Math.floor(Math.random() * 1e6));
|
|
922
|
+
const [seedMode, setSeedMode] = useState4("random");
|
|
923
|
+
const [isLeftCollapsed, setIsLeftCollapsed] = useState4(false);
|
|
924
|
+
const [isRightCollapsed, setIsRightCollapsed] = useState4(false);
|
|
925
|
+
const [isPromptCollapsed, setIsPromptCollapsed] = useState4(false);
|
|
926
|
+
const [projectActionState, setProjectActionState] = useState4("idle");
|
|
927
|
+
const [workspaceTags, setWorkspaceTags] = useState4(null);
|
|
791
928
|
const isGenerating = activeGenerationsCount > 0;
|
|
792
929
|
useKeyboardNavigation(history, currentResult, setCurrentResult);
|
|
793
930
|
const getSubtreeFormat = useCallback((nodeId, depth = 0) => {
|
|
@@ -851,16 +988,32 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
851
988
|
const handleSynthesizePrompt = async (nodeId, autoGenerate = false) => {
|
|
852
989
|
setIsSynthesizing(true);
|
|
853
990
|
try {
|
|
854
|
-
const
|
|
855
|
-
setActivePrompt(
|
|
991
|
+
const raw = await onGeneratePrompt(getSubtreeFormat(nodeId));
|
|
992
|
+
setActivePrompt(raw);
|
|
856
993
|
setFocusedNodeId(nodeId);
|
|
857
|
-
if (autoGenerate) handleGenerateImage(
|
|
994
|
+
if (autoGenerate) handleGenerateImage(raw, void 0, nodeId);
|
|
858
995
|
} catch {
|
|
859
996
|
setActivePrompt("Synthese-Fehler");
|
|
860
997
|
} finally {
|
|
861
998
|
setIsSynthesizing(false);
|
|
862
999
|
}
|
|
863
1000
|
};
|
|
1001
|
+
const handlePromptTabGenerate = async (selectedValues, instructions) => {
|
|
1002
|
+
setIsPromptTabGenerating(true);
|
|
1003
|
+
setPromptFeedback(null);
|
|
1004
|
+
try {
|
|
1005
|
+
const treeText = focusedNodeId ? getSubtreeFormat(focusedNodeId) : void 0;
|
|
1006
|
+
const payload = buildPromptTabPayload(selectedValues, instructions, treeText);
|
|
1007
|
+
const raw = await onGeneratePrompt(payload);
|
|
1008
|
+
const { prompt, feedback } = parsePromptResponse(raw);
|
|
1009
|
+
setActivePrompt(prompt);
|
|
1010
|
+
setPromptFeedback(feedback);
|
|
1011
|
+
} catch {
|
|
1012
|
+
setActivePrompt("Synthese-Fehler");
|
|
1013
|
+
} finally {
|
|
1014
|
+
setIsPromptTabGenerating(false);
|
|
1015
|
+
}
|
|
1016
|
+
};
|
|
864
1017
|
const handleDownloadSingle = async () => {
|
|
865
1018
|
if (!currentResult?.base64) return;
|
|
866
1019
|
try {
|
|
@@ -916,58 +1069,100 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
916
1069
|
const root = JSON.parse(ev.target?.result);
|
|
917
1070
|
const rawTags = root.tags || root;
|
|
918
1071
|
if (!rawTags?.by_category) return;
|
|
1072
|
+
const filtered = {};
|
|
1073
|
+
const EXCLUDED = ["pdf-export", "book.micro-edit-rules"];
|
|
1074
|
+
Object.entries(rawTags.by_category).forEach(([cat, items]) => {
|
|
1075
|
+
if (EXCLUDED.includes(cat) || !Array.isArray(items)) return;
|
|
1076
|
+
filtered[cat] = items.filter((t) => t && typeof t === "object" && t.label && t.value);
|
|
1077
|
+
});
|
|
1078
|
+
const filteredAll = (rawTags.all || []).filter((t) => t && !EXCLUDED.includes(t.category));
|
|
1079
|
+
setWorkspaceTags({ by_category: filtered, all: filteredAll });
|
|
919
1080
|
} catch (err) {
|
|
920
1081
|
console.error("Workspace Load failed", err);
|
|
921
1082
|
}
|
|
922
1083
|
};
|
|
923
1084
|
reader.readAsText(file);
|
|
924
1085
|
};
|
|
925
|
-
return /* @__PURE__ */
|
|
926
|
-
/* @__PURE__ */
|
|
927
|
-
/* @__PURE__ */
|
|
928
|
-
!isLeftCollapsed && /* @__PURE__ */
|
|
929
|
-
|
|
1086
|
+
return /* @__PURE__ */ jsxs9("div", { className: "flex h-screen w-screen bg-[#0e0e0e] text-white overflow-hidden", children: [
|
|
1087
|
+
/* @__PURE__ */ jsxs9(motion6.div, { animate: { width: isLeftCollapsed ? 48 : 260 }, className: "flex flex-col border-r border-white/5 overflow-hidden relative bg-black/10 shrink-0", children: [
|
|
1088
|
+
/* @__PURE__ */ jsxs9("div", { className: "h-14 border-b border-white/5 flex items-center justify-between shrink-0 px-1", children: [
|
|
1089
|
+
!isLeftCollapsed && /* @__PURE__ */ jsxs9("div", { className: "flex flex-1 gap-1", children: [
|
|
1090
|
+
/* @__PURE__ */ jsxs9(
|
|
1091
|
+
"button",
|
|
1092
|
+
{
|
|
1093
|
+
onClick: () => setLeftTab("hierarchy"),
|
|
1094
|
+
className: `flex-1 flex items-center justify-center gap-1 h-8 rounded-lg text-[8px] font-bold uppercase tracking-wide transition-colors ${leftTab === "hierarchy" ? "bg-white/10 text-white" : "text-white/30 hover:text-white/60"}`,
|
|
1095
|
+
children: [
|
|
1096
|
+
/* @__PURE__ */ jsx11("span", { className: "material-symbols-outlined text-[14px]", children: "account_tree" }),
|
|
1097
|
+
"Hierarchie"
|
|
1098
|
+
]
|
|
1099
|
+
}
|
|
1100
|
+
),
|
|
1101
|
+
workspaceTags && /* @__PURE__ */ jsxs9(
|
|
1102
|
+
"button",
|
|
1103
|
+
{
|
|
1104
|
+
onClick: () => setLeftTab("prompt"),
|
|
1105
|
+
className: `flex-1 flex items-center justify-center gap-1 h-8 rounded-lg text-[8px] font-bold uppercase tracking-wide transition-colors ${leftTab === "prompt" ? "bg-white/10 text-white" : "text-white/30 hover:text-white/60"}`,
|
|
1106
|
+
children: [
|
|
1107
|
+
/* @__PURE__ */ jsx11("span", { className: "material-symbols-outlined text-[14px]", children: "auto_fix_high" }),
|
|
1108
|
+
"Prompt"
|
|
1109
|
+
]
|
|
1110
|
+
}
|
|
1111
|
+
)
|
|
1112
|
+
] }),
|
|
1113
|
+
/* @__PURE__ */ jsx11("button", { onClick: () => setIsLeftCollapsed(!isLeftCollapsed), className: "material-symbols-outlined text-[18px] text-white/40 hover:text-white transition-all w-10 flex items-center justify-center", children: isLeftCollapsed ? "chevron_right" : "chevron_left" })
|
|
930
1114
|
] }),
|
|
931
|
-
!isLeftCollapsed && /* @__PURE__ */
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
1115
|
+
!isLeftCollapsed && /* @__PURE__ */ jsx11("div", { className: "flex-1 overflow-hidden relative", children: /* @__PURE__ */ jsxs9(AnimatePresence2, { mode: "wait", children: [
|
|
1116
|
+
leftTab === "hierarchy" && /* @__PURE__ */ jsx11(motion6.div, { className: "absolute inset-0", initial: { opacity: 0 }, animate: { opacity: 1 }, exit: { opacity: 0 }, children: /* @__PURE__ */ jsx11(
|
|
1117
|
+
ListView,
|
|
1118
|
+
{
|
|
1119
|
+
nodes,
|
|
1120
|
+
edges,
|
|
1121
|
+
onNodeChange: (id, l) => setNodes((nds) => nds.map((n) => n.id === id ? { ...n, data: { ...n.data, label: l } } : n)),
|
|
1122
|
+
onAddChild: (pId) => {
|
|
1123
|
+
const newId = crypto.randomUUID();
|
|
1124
|
+
setNodes((nds) => [...nds, { id: newId, type: "custom", position: { x: 0, y: 0 }, data: { label: "", placeholder: "Konzept..." } }]);
|
|
1125
|
+
setEdges((eds) => [...eds, { id: `e-${pId}-${newId}`, source: pId, target: newId }]);
|
|
1126
|
+
setFocusedNodeId(newId);
|
|
1127
|
+
return newId;
|
|
1128
|
+
},
|
|
1129
|
+
onDeleteNode: (id) => {
|
|
1130
|
+
setNodes((nds) => nds.filter((n) => n.id !== id));
|
|
1131
|
+
setEdges((eds) => eds.filter((e) => e.source !== id && e.target !== id));
|
|
1132
|
+
},
|
|
1133
|
+
onFocus: setFocusedNodeId,
|
|
1134
|
+
focusedNodeId,
|
|
1135
|
+
activePath,
|
|
1136
|
+
onGenerate: handleSynthesizePrompt,
|
|
1137
|
+
onGenerateBranch: (id) => handleSynthesizePrompt(id, true),
|
|
1138
|
+
isGeneratingNodeId: (id) => isSynthesizing && focusedNodeId === id
|
|
1139
|
+
}
|
|
1140
|
+
) }, "hierarchy"),
|
|
1141
|
+
leftTab === "prompt" && workspaceTags && /* @__PURE__ */ jsx11(motion6.div, { className: "absolute inset-0", initial: { opacity: 0 }, animate: { opacity: 1 }, exit: { opacity: 0 }, children: /* @__PURE__ */ jsx11(
|
|
1142
|
+
PromptTab,
|
|
1143
|
+
{
|
|
1144
|
+
workspaceTags,
|
|
1145
|
+
onGenerate: handlePromptTabGenerate,
|
|
1146
|
+
isGenerating: isPromptTabGenerating,
|
|
1147
|
+
feedback: promptFeedback
|
|
1148
|
+
}
|
|
1149
|
+
) }, "prompt")
|
|
1150
|
+
] }) })
|
|
956
1151
|
] }),
|
|
957
|
-
/* @__PURE__ */
|
|
958
|
-
/* @__PURE__ */
|
|
959
|
-
/* @__PURE__ */
|
|
960
|
-
/* @__PURE__ */
|
|
961
|
-
/* @__PURE__ */
|
|
1152
|
+
/* @__PURE__ */ jsxs9("div", { className: "flex-1 flex flex-col bg-[#0b0b0b] overflow-hidden", children: [
|
|
1153
|
+
/* @__PURE__ */ jsxs9("div", { className: "h-14 border-b border-white/5 flex items-center px-4 gap-2 justify-between shrink-0 bg-black/20", children: [
|
|
1154
|
+
/* @__PURE__ */ jsxs9("div", { className: "flex items-center gap-1.5", children: [
|
|
1155
|
+
/* @__PURE__ */ jsx11(CompactDropdown, { value: aspectRatio, onChange: setAspectRatio, options: [{ label: "1:1", value: "1:1" }, { label: "16:9", value: "16:9" }, { label: "9:16", value: "9:16" }] }),
|
|
1156
|
+
/* @__PURE__ */ jsx11(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" }] })
|
|
962
1157
|
] }),
|
|
963
|
-
/* @__PURE__ */
|
|
964
|
-
/* @__PURE__ */
|
|
965
|
-
/* @__PURE__ */
|
|
1158
|
+
/* @__PURE__ */ jsxs9("div", { className: "flex items-center gap-2", children: [
|
|
1159
|
+
/* @__PURE__ */ jsx11("button", { onClick: () => setIsPromptCollapsed(!isPromptCollapsed), className: "text-white/40 hover:text-white transition-colors", children: /* @__PURE__ */ jsx11("span", { className: "material-symbols-outlined", children: isPromptCollapsed ? "expand_more" : "expand_less" }) }),
|
|
1160
|
+
/* @__PURE__ */ jsx11(PillButton, { variant: "solid", icon: "bolt", loading: isGenerating, disabled: !activePrompt.trim(), onClick: () => handleGenerateImage(), children: "Generieren" })
|
|
966
1161
|
] })
|
|
967
1162
|
] }),
|
|
968
|
-
/* @__PURE__ */
|
|
969
|
-
/* @__PURE__ */
|
|
970
|
-
/* @__PURE__ */
|
|
1163
|
+
/* @__PURE__ */ jsxs9("div", { className: "flex-1 flex flex-col overflow-hidden relative", children: [
|
|
1164
|
+
/* @__PURE__ */ jsx11(AnimatePresence2, { children: !isPromptCollapsed && /* @__PURE__ */ jsx11(motion6.div, { initial: { height: 0 }, animate: { height: "auto" }, exit: { height: 0 }, className: "px-6 py-4 border-b border-white/5 bg-black/10 overflow-hidden shrink-0", children: /* @__PURE__ */ jsxs9("div", { className: `relative min-h-[60px] p-4 rounded-2xl border transition-all ${isSynthesizing ? "prompt-loading" : "bg-white/5 border-white/10"}`, children: [
|
|
1165
|
+
/* @__PURE__ */ jsx11(
|
|
971
1166
|
"textarea",
|
|
972
1167
|
{
|
|
973
1168
|
value: activePrompt,
|
|
@@ -976,48 +1171,48 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
976
1171
|
placeholder: "W\xE4hle einen Knoten oder tippe einen Prompt..."
|
|
977
1172
|
}
|
|
978
1173
|
),
|
|
979
|
-
activePrompt && !isSynthesizing && /* @__PURE__ */
|
|
1174
|
+
activePrompt && !isSynthesizing && /* @__PURE__ */ jsx11("button", { onClick: () => setActivePrompt(""), className: "absolute top-2 right-2 w-6 h-6 rounded-full bg-white/5 hover:bg-white/10 flex items-center justify-center transition-colors text-white/20 hover:text-white", children: /* @__PURE__ */ jsx11("span", { className: "material-symbols-outlined text-[14px]", children: "close" }) })
|
|
980
1175
|
] }) }) }),
|
|
981
|
-
/* @__PURE__ */
|
|
982
|
-
isGenerating && currentResult?.status === "done" && /* @__PURE__ */
|
|
983
|
-
/* @__PURE__ */
|
|
984
|
-
/* @__PURE__ */
|
|
1176
|
+
/* @__PURE__ */ jsx11("div", { className: "flex-1 p-6 overflow-hidden flex items-center justify-center", children: /* @__PURE__ */ jsxs9("div", { className: "h-full w-full max-w-4xl aspect-square rounded-3xl border border-white/5 bg-black/40 relative overflow-hidden flex items-center justify-center group shadow-2xl", children: [
|
|
1177
|
+
isGenerating && currentResult?.status === "done" && /* @__PURE__ */ jsxs9("div", { className: "absolute top-6 right-6 z-30 bg-black/60 backdrop-blur-md px-4 py-2 rounded-full border border-white/10 flex items-center gap-3", children: [
|
|
1178
|
+
/* @__PURE__ */ jsx11("div", { className: "w-3 h-3 border-t-2 border-white rounded-full animate-spin" }),
|
|
1179
|
+
/* @__PURE__ */ jsx11("span", { className: "text-[10px] text-white/60 uppercase font-bold tracking-widest", children: "Neue Referenz..." })
|
|
985
1180
|
] }),
|
|
986
|
-
currentResult ? currentResult.status === "processing" ? /* @__PURE__ */
|
|
987
|
-
/* @__PURE__ */
|
|
988
|
-
/* @__PURE__ */
|
|
989
|
-
] }) : currentResult.status === "error" ? /* @__PURE__ */
|
|
990
|
-
/* @__PURE__ */
|
|
991
|
-
/* @__PURE__ */
|
|
992
|
-
/* @__PURE__ */
|
|
993
|
-
/* @__PURE__ */
|
|
1181
|
+
currentResult ? currentResult.status === "processing" ? /* @__PURE__ */ jsxs9("div", { className: "flex flex-col items-center gap-4", children: [
|
|
1182
|
+
/* @__PURE__ */ jsx11("div", { className: "w-10 h-10 border-t-2 border-white rounded-full animate-spin" }),
|
|
1183
|
+
/* @__PURE__ */ jsx11("span", { className: "text-[10px] text-white/40 uppercase font-bold tracking-widest", children: "Erstelle Bild..." })
|
|
1184
|
+
] }) : currentResult.status === "error" ? /* @__PURE__ */ jsxs9("div", { className: "p-10 text-center flex flex-col items-center gap-5 max-w-md", children: [
|
|
1185
|
+
/* @__PURE__ */ jsx11("div", { className: "w-16 h-16 rounded-full bg-red-500/10 flex items-center justify-center", children: /* @__PURE__ */ jsx11("span", { className: "material-symbols-outlined text-red-500 text-[32px]", children: "warning" }) }),
|
|
1186
|
+
/* @__PURE__ */ jsxs9("div", { className: "flex flex-col gap-2", children: [
|
|
1187
|
+
/* @__PURE__ */ jsx11("h3", { className: "text-[11px] font-bold uppercase tracking-widest text-red-400", children: "Generierungsfehler" }),
|
|
1188
|
+
/* @__PURE__ */ jsx11("p", { className: "text-white/60 text-[12px] leading-relaxed", children: currentResult.error?.message })
|
|
994
1189
|
] }),
|
|
995
|
-
/* @__PURE__ */
|
|
996
|
-
] }) : /* @__PURE__ */
|
|
997
|
-
/* @__PURE__ */
|
|
998
|
-
/* @__PURE__ */
|
|
999
|
-
/* @__PURE__ */
|
|
1000
|
-
/* @__PURE__ */
|
|
1001
|
-
/* @__PURE__ */
|
|
1190
|
+
/* @__PURE__ */ jsx11(PillButton, { variant: "outline", icon: "refresh", onClick: () => handleGenerateImage(currentResult.prompt), children: "Erneut versuchen" })
|
|
1191
|
+
] }) : /* @__PURE__ */ jsxs9("div", { className: "h-full w-full relative flex items-center justify-center", children: [
|
|
1192
|
+
/* @__PURE__ */ jsx11("img", { src: currentResult.base64, className: "max-h-full max-w-full object-contain rounded-xl shadow-2xl" }),
|
|
1193
|
+
/* @__PURE__ */ jsxs9("div", { className: "absolute bottom-6 flex gap-2 opacity-0 group-hover:opacity-100 transition-all translate-y-4 group-hover:translate-y-0 z-20", children: [
|
|
1194
|
+
/* @__PURE__ */ jsx11(PillButton, { variant: "outline", icon: "replay", onClick: () => setActivePrompt(currentResult.prompt || ""), children: "Prompt" }),
|
|
1195
|
+
/* @__PURE__ */ jsx11(PillButton, { variant: "solid", icon: "auto_fix_high", onClick: () => handleGenerateImage(currentResult.prompt || activePrompt, currentResult.mediaId, void 0, { silent: true }), children: "Referenz" }),
|
|
1196
|
+
/* @__PURE__ */ jsx11(PillButton, { variant: "outline", icon: "download", onClick: handleDownloadSingle, children: "Speichern" })
|
|
1002
1197
|
] })
|
|
1003
|
-
] }) : /* @__PURE__ */
|
|
1004
|
-
/* @__PURE__ */
|
|
1005
|
-
/* @__PURE__ */
|
|
1198
|
+
] }) : /* @__PURE__ */ jsxs9("div", { className: "flex flex-col items-center gap-2 opacity-10", children: [
|
|
1199
|
+
/* @__PURE__ */ jsx11("span", { className: "material-symbols-outlined text-[100px]", children: "palette" }),
|
|
1200
|
+
/* @__PURE__ */ jsx11("span", { className: "text-[12px] font-bold uppercase tracking-[0.2em]", children: "Avatar Architect" })
|
|
1006
1201
|
] })
|
|
1007
1202
|
] }) })
|
|
1008
1203
|
] })
|
|
1009
1204
|
] }),
|
|
1010
|
-
/* @__PURE__ */
|
|
1011
|
-
/* @__PURE__ */
|
|
1012
|
-
/* @__PURE__ */
|
|
1205
|
+
/* @__PURE__ */ jsxs9(motion6.div, { animate: { width: isRightCollapsed ? 60 : 320 }, className: "flex flex-col border-l border-white/5 bg-[#0e0e0e] shrink-0", children: [
|
|
1206
|
+
/* @__PURE__ */ jsxs9("div", { className: "flex border-b border-white/5 h-14 shrink-0 overflow-hidden", children: [
|
|
1207
|
+
/* @__PURE__ */ jsx11("div", { className: "flex flex-1", children: ["history", "gallery", "inspect", "setup"].map((tab) => /* @__PURE__ */ jsx11("button", { onClick: () => {
|
|
1013
1208
|
setActiveTab(tab);
|
|
1014
1209
|
setIsRightCollapsed(false);
|
|
1015
|
-
}, className: `flex-1 flex items-center justify-center relative transition-colors ${activeTab === tab ? "text-white" : "text-white/20"}`, children: /* @__PURE__ */
|
|
1016
|
-
/* @__PURE__ */
|
|
1210
|
+
}, className: `flex-1 flex items-center justify-center relative transition-colors ${activeTab === tab ? "text-white" : "text-white/20"}`, children: /* @__PURE__ */ jsx11("span", { className: "material-symbols-outlined text-[20px]", children: tab === "history" ? "history" : tab === "gallery" ? "photo_library" : tab === "inspect" ? "info" : "settings" }) }, tab)) }),
|
|
1211
|
+
/* @__PURE__ */ jsx11("button", { onClick: () => setIsRightCollapsed(!isRightCollapsed), className: "w-10 flex items-center justify-center text-white/20 hover:text-white", children: /* @__PURE__ */ jsx11("span", { className: "material-symbols-outlined text-[18px]", children: isRightCollapsed ? "chevron_left" : "chevron_right" }) })
|
|
1017
1212
|
] }),
|
|
1018
|
-
!isRightCollapsed && /* @__PURE__ */
|
|
1019
|
-
activeTab === "history" && /* @__PURE__ */
|
|
1020
|
-
activeTab === "gallery" && /* @__PURE__ */
|
|
1213
|
+
!isRightCollapsed && /* @__PURE__ */ jsx11("div", { className: "flex-1 overflow-hidden relative", children: /* @__PURE__ */ jsxs9(AnimatePresence2, { mode: "wait", children: [
|
|
1214
|
+
activeTab === "history" && /* @__PURE__ */ jsx11(HistoryPanel, { history, currentResultId: currentResult?.id || null, onSelect: setCurrentResult, onDelete: (id) => setHistory((h) => h.filter((x) => x.id !== id)) }, "history"),
|
|
1215
|
+
activeTab === "gallery" && /* @__PURE__ */ jsx11(
|
|
1021
1216
|
MediaLibrary,
|
|
1022
1217
|
{
|
|
1023
1218
|
items: galleryItems,
|
|
@@ -1043,8 +1238,8 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
1043
1238
|
},
|
|
1044
1239
|
"gallery"
|
|
1045
1240
|
),
|
|
1046
|
-
activeTab === "inspect" && /* @__PURE__ */
|
|
1047
|
-
activeTab === "setup" && /* @__PURE__ */
|
|
1241
|
+
activeTab === "inspect" && /* @__PURE__ */ jsx11(InspectPanel, { currentResult, history, onSelect: setCurrentResult }, "inspect"),
|
|
1242
|
+
activeTab === "setup" && /* @__PURE__ */ jsx11(
|
|
1048
1243
|
SetupPanel,
|
|
1049
1244
|
{
|
|
1050
1245
|
onProjectExport: handleProjectExport,
|
|
@@ -1068,11 +1263,13 @@ export {
|
|
|
1068
1263
|
ListView,
|
|
1069
1264
|
MediaLibrary,
|
|
1070
1265
|
PillButton,
|
|
1266
|
+
PromptTab,
|
|
1071
1267
|
SectionLabel,
|
|
1072
1268
|
SetupPanel,
|
|
1073
1269
|
buildFallbackPrompt,
|
|
1074
1270
|
buildGenerationPrompt,
|
|
1075
1271
|
buildImageGenerationOptions,
|
|
1272
|
+
buildPromptTabPayload,
|
|
1076
1273
|
cleanAiResponse,
|
|
1077
1274
|
exportProjectToZip,
|
|
1078
1275
|
formatTreeToMarkdown,
|
|
@@ -1081,6 +1278,7 @@ export {
|
|
|
1081
1278
|
injectXMPMetadata,
|
|
1082
1279
|
interpretSdkError,
|
|
1083
1280
|
parsePromptFile,
|
|
1281
|
+
parsePromptResponse,
|
|
1084
1282
|
useKeyboardNavigation,
|
|
1085
1283
|
useOnClickOutside
|
|
1086
1284
|
};
|