import React, { useState, useEffect } from 'react'; import { motion, AnimatePresence } from 'framer-motion'; import { X, Sparkles, Image as ImageIcon, Loader2, Download, Settings, Wand2, Lightbulb } from 'lucide-react'; import { cn } from '../lib/utils'; import { useAuthStore } from '../store/authStore'; import { api } from '../lib/api'; interface VizAiModalProps { isOpen: boolean; onClose: () => void; baseImage: string | null; } const dataURLtoBlob = (dataurl: string) => { const arr = dataurl.split(','); const mime = arr[0].match(/:(.*?);/)?.[1]; const bstr = atob(arr[1]); let n = bstr.length; const u8arr = new Uint8Array(n); while(n--) { u8arr[n] = bstr.charCodeAt(n); } return new Blob([u8arr], {type:mime}); }; export const VizAiModal: React.FC = ({ isOpen, onClose, baseImage }) => { const { profile, setProfile } = useAuthStore(); // API Keys const [stabilityApiKey, setStabilityApiKey] = useState(''); const [openAiKey, setOpenAiKey] = useState(''); // Prompt Generation State (AI Idea) const [productName, setProductName] = useState(''); const [ingredients, setIngredients] = useState(''); const [imageTone, setImageTone] = useState(''); const [packDesign, setPackDesign] = useState(''); const [isGeneratingPrompt, setIsGeneratingPrompt] = useState(false); // Image Generation State const [prompt, setPrompt] = useState(''); const [strength, setStrength] = useState(0.85); const [isGeneratingImage, setIsGeneratingImage] = useState(false); const [generatedImage, setGeneratedImage] = useState(null); const [error, setError] = useState(null); useEffect(() => { if (isOpen) { setStabilityApiKey(localStorage.getItem('stability_api_key') || ''); setOpenAiKey(localStorage.getItem('openai_api_key') || ''); } }, [isOpen]); const generateAiIdea = async () => { if (!openAiKey) { setError("Please set your OpenAI API key in Tools > API Settings first."); return; } setIsGeneratingPrompt(true); setError(null); try { const response = await fetch('https://api.openai.com/v1/chat/completions', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${openAiKey}` }, body: JSON.stringify({ model: 'gpt-4o-mini', messages: [{ role: 'system', content: 'You are an expert prompt engineer for Stable Diffusion. Your goal is to take product specifications and write a single, highly descriptive prompt for generating a beautiful, professional product mockup scene. Describe the lighting, the background, and the aesthetic vividly.' }, { role: 'user', content: `Create a single, highly descriptive image generation prompt based on these details: Product Name: ${productName || 'Unspecified Product'} Ingredients/Elements: ${ingredients || 'None specified'} Image Tone/Mood: ${imageTone || 'Professional, studio lighting'} Pack Design/Shape: ${packDesign || 'Standard'} Return ONLY the prompt string (under 100 words) without any conversational text or quotes.` }] }) }); const data = await response.json(); if (data.error) throw new Error(data.error.message); const generated = data.choices?.[0]?.message?.content?.trim() || ""; // Strip quotes if they were included setPrompt(generated.replace(/^"|"$/g, '')); } catch (err: any) { console.error(err); setError(err.message || "Failed to generate AI Idea."); } finally { setIsGeneratingPrompt(false); } }; const generateImage = async () => { if (!stabilityApiKey) { setError("Please set your Stability AI API key in Tools > API Settings first."); return; } if (!baseImage) { setError("No base image captured from the scene."); return; } if (!prompt) { setError("Please enter a prompt or use AI Idea."); return; } if (!profile || profile.api_credits <= 0) { setError("Not enough AI Credits. Please contact an administrator."); return; } setIsGeneratingImage(true); setError(null); try { const formData = new FormData(); formData.append('image', dataURLtoBlob(baseImage), 'base.png'); formData.append('prompt', prompt); formData.append('strength', strength.toString()); formData.append('mode', 'image-to-image'); formData.append('model', 'sd3.5-large'); formData.append('output_format', 'png'); const response = await fetch('https://api.stability.ai/v2beta/stable-image/generate/sd3', { method: 'POST', headers: { 'Authorization': `Bearer ${stabilityApiKey}`, 'Accept': 'image/*' }, body: formData }); if (!response.ok) { const errData = await response.json().catch(() => ({})); throw new Error(errData.message || `Stability API error: ${response.status}`); } const blob = await response.blob(); const imageUrl = URL.createObjectURL(blob); setGeneratedImage(imageUrl); // Deduct credit if (profile) { const { api_credits } = await api.deductCredit(); setProfile({ ...profile, api_credits }); } } catch (err: any) { console.error(err); setError(err.message || "Failed to generate image."); } finally { setIsGeneratingImage(false); } }; if (!isOpen) return null; return (
{/* Header */}

Titan3d AI Generator

Generate stunning product mockups directly from your 3D scene

{/* Left Panel: Inputs */}
{/* AI Idea Box */}

AI Idea Generator

setProductName(e.target.value)} className="w-full bg-zinc-900 border border-zinc-800 rounded px-3 py-2 text-xs text-white placeholder-zinc-600 focus:border-yellow-500/50 outline-none" /> setIngredients(e.target.value)} className="w-full bg-zinc-900 border border-zinc-800 rounded px-3 py-2 text-xs text-white placeholder-zinc-600 focus:border-yellow-500/50 outline-none" /> setImageTone(e.target.value)} className="w-full bg-zinc-900 border border-zinc-800 rounded px-3 py-2 text-xs text-white placeholder-zinc-600 focus:border-yellow-500/50 outline-none" /> setPackDesign(e.target.value)} className="w-full bg-zinc-900 border border-zinc-800 rounded px-3 py-2 text-xs text-white placeholder-zinc-600 focus:border-yellow-500/50 outline-none" />
{/* Main Generation Settings */}