import { useState, useRef, useCallback } from "react"; const API_URL = "https://api.anthropic.com/v1/messages"; const STYLES = [ { id: "luxury", label: "🏙️ Luxury Modern", desc: "Blau-grau, LED, Marmor" }, { id: "nordic", label: "🪵 Nordic Minimal", desc: "Hell, Holz, clean" }, { id: "industrial", label: "🏭 Industrial", desc: "Beton, Stahl, roh" }, { id: "warm", label: "🕯️ Warm Cozy", desc: "Erdtöne, weich" }, { id: "futuristic", label: "🚀 Futuristic", desc: "Dunkel, Neon, High-Tech" }, ]; const OUTPUTS = [ { id: "chatgpt", label: "ChatGPT / DALL·E 3" }, { id: "midjourney", label: "Midjourney v6.1" }, { id: "firefly", label: "Adobe Firefly" }, { id: "stablediffusion", label: "Stable Diffusion" }, { id: "gemini", label: "Gemini" }, { id: "all", label: "🔄 Alle" }, ]; const FORMAT_LABELS = { chatgpt: "ChatGPT / DALL·E 3", midjourney: "Midjourney v6.1", firefly: "Adobe Firefly", stablediffusion: "Stable Diffusion XL", gemini: "Google Gemini", }; const FORMAT_COLORS = { chatgpt: "#10a37f", midjourney: "#7c5cfc", firefly: "#ff4444", stablediffusion: "#f5a623", gemini: "#4285f4", }; // Where each AI can be opened with prefilled text const AI_URLS = { chatgpt: (prompt) => `https://chatgpt.com/?q=${encodeURIComponent(prompt)}`, gemini: (prompt) => `https://gemini.google.com/app?q=${encodeURIComponent(prompt)}`, firefly: (_) => `https://firefly.adobe.com/generate/images`, midjourney: (_) => `https://www.midjourney.com/imagine`, stablediffusion: (_) => `https://stablediffusionweb.com/`, }; const AI_OPEN_NOTES = { chatgpt: "Prompt wird vorausgefüllt — Grundriss noch anhängen", gemini: "Prompt wird vorausgefüllt — Grundriss noch anhängen", firefly: "Firefly öffnen — Prompt kopieren & Grundriss hochladen", midjourney: "Midjourney öffnen — Prompt ins /imagine Feld einfügen", stablediffusion: "Stable Diffusion öffnen — Prompt einfügen", }; const STYLE_PROMPTS = { luxury: "elegant blue-grey color palette, cinematic ambient lighting, softly glowing LED accents, high-end modern furniture, marble and glass surfaces", nordic: "bright airy Scandinavian palette, natural wood textures, minimalist clean lines, warm white lighting, linen and oak materials", industrial: "exposed concrete walls, raw steel elements, Edison bulb lighting, dark matte finishes, urban loft atmosphere", warm: "warm earth tones, terracotta and cream palette, soft candlelike lighting, plush textiles, hygge atmosphere", futuristic: "dark high-tech interior, neon accent lighting, glossy surfaces, smart home elements, cyberpunk-inspired palette", }; export default function FloorplanPromptGen() { const [image, setImage] = useState(null); const [selectedStyle, setSelectedStyle] = useState("luxury"); const [selectedOutput, setSelectedOutput] = useState("chatgpt"); const [loading, setLoading] = useState(false); const [results, setResults] = useState(null); const [error, setError] = useState(null); const [dragging, setDragging] = useState(false); const [copied, setCopied] = useState(null); const fileInputRef = useRef(); const handleFile = useCallback(async (file) => { if (!file || !file.type.startsWith("image/")) return; const dataUrl = await new Promise(res => { const r = new FileReader(); r.onload = () => res(r.result); r.readAsDataURL(file); }); setImage({ file, dataUrl, base64: dataUrl.split(",")[1], mediaType: file.type }); setResults(null); setError(null); }, []); const onDrop = (e) => { e.preventDefault(); setDragging(false); if (e.dataTransfer.files[0]) handleFile(e.dataTransfer.files[0]); }; const generate = async () => { if (!image) return; setLoading(true); setError(null); setResults(null); const targets = selectedOutput === "all" ? ["chatgpt", "gemini", "midjourney", "firefly", "stablediffusion"] : [selectedOutput]; const styleDesc = STYLE_PROMPTS[selectedStyle]; const styleName = STYLES.find(s => s.id === selectedStyle)?.label || selectedStyle; const system = `Du bist ein Experte für 3D-Architektur-Visualisierung und Prompt-Engineering. Analysiere Grundrisse und generiere präzise Bildgenerierungs-Prompts. Antworte NUR mit einem JSON-Objekt, ohne Markdown-Backticks oder anderen Text.`; const user = `Analysiere diesen Grundriss und erstelle optimierte Prompts für ein ultra-detailliertes 3D-Architektur-Floorplan-Rendering. Gewählter Stil: ${styleName} Stil-Eigenschaften: ${styleDesc} Erkenne aus dem Grundriss alle Räume, Größen und besondere Merkmale. Generiere folgendes JSON: { "rooms_detected": ["Liste der erkannten Räume mit m²"], "layout_notes": "kurze Beschreibung des Layouts", "prompts": { ${targets.map(t => `"${t}": "vollständiger Prompt für ${FORMAT_LABELS[t]}"`).join(",\n ")} } } Prompt-Anforderungen: - Enthält "ultra-detailed 3D architectural floor plan rendering" - Isometrische Draufsicht von oben - Alle erkannten Räume mit korrekter Möblierung erwähnen - Stil: ${styleDesc} - Fotorealistisch, hochdetailliert Format-spezifisch: - chatgpt: Natürliche Sprache, sehr detailliert, alle Räume aufgelistet - gemini: Natürliche Sprache, strukturiert, präzise - midjourney: Englisch, Tags-Stil, endet mit --ar 9:16 --v 6.1 --stylize 300 - firefly: Englisch, Satzform, Firefly-optimiert - stablediffusion: Englisch, (tag:1.2) Gewichtung, nach ### negative prompt`; try { const resp = await fetch(API_URL, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ model: "claude-sonnet-4-20250514", max_tokens: 4000, system, messages: [{ role: "user", content: [ { type: "image", source: { type: "base64", media_type: image.mediaType, data: image.base64 } }, { type: "text", text: user } ] }] }) }); if (!resp.ok) throw new Error(`API Fehler ${resp.status}`); const data = await resp.json(); const text = data.content.map(i => i.text || "").join(""); const clean = text.replace(/```json|```/g, "").trim(); const parsed = JSON.parse(clean); setResults({ ...parsed, targets }); } catch (e) { setError(e.message); } finally { setLoading(false); } }; const copy = (text, id) => { navigator.clipboard.writeText(text).then(() => { setCopied(id); setTimeout(() => setCopied(null), 2000); }); }; const openInAI = (target, prompt) => { const urlFn = AI_URLS[target]; if (urlFn) window.open(urlFn(prompt), "_blank"); }; return (
{loading && (
GRUNDRISS WIRD ANALYSIERT
)}
{/* Header */}
3D ARCHITEKTUR

Floorplan Prompt Generator

Grundriss hochladen → Stil wählen → direkt in deiner KI öffnen

{/* Upload */}
fileInputRef.current.click()} onDragOver={e => { e.preventDefault(); setDragging(true); }} onDragLeave={() => setDragging(false)} onDrop={onDrop} style={{ border: `2px dashed ${dragging ? "#64b5f6" : "#2a2a40"}`, borderRadius: 4, background: dragging ? "rgba(100,181,246,0.05)" : "rgba(255,255,255,0.02)", padding: image ? "20px" : "52px 20px", textAlign: "center", cursor: "pointer", transition: "all 0.2s", }} > e.target.files[0] && handleFile(e.target.files[0])} /> {image ? (
Grundriss
✓ Grundriss geladen
{image.file.name}
{(image.file.size / 1024).toFixed(0)} KB
anderen wählen
) : ( <>
📐
Grundriss hier ablegen
Handgezeichnet oder digital · PNG / JPG
)}
{/* Style selector */}
INNENRAUM-STIL
{STYLES.map(s => ( ))}
{/* Output format */}
ZIEL-KI
{OUTPUTS.map(o => ( ))}
{/* Generate */} {error && (
⚠ {error}
)} {/* Results */} {results && (
{results.rooms_detected && (
ERKANNTE RÄUME
{results.rooms_detected.map((r, i) => ( {r} ))}
{results.layout_notes && (
{results.layout_notes}
)}
)}
GENERIERTE PROMPTS
{results.targets.map(target => { const prompt = results.prompts?.[target]; if (!prompt) return null; const color = FORMAT_COLORS[target] || "#64b5f6"; const note = AI_OPEN_NOTES[target]; return (
{FORMAT_LABELS[target]}
{note && (
ℹ️ {note}
)}
{prompt}
); })}
)}
); }