import React, { useState, useMemo, useEffect } from 'react'; import { SparklesIcon, LoaderIcon, PlusIcon, XIcon, MegaphoneIcon, ChevronLeftIcon, ChevronRightIcon, AlertTriangleIcon, ProductIcon, UsersIcon, FamilyIcon, LayersIcon, DetailedViewIcon, PosterIcon, BlueprintIcon } from '@/components/icons'; import { artStyles, professionalThemes } from '@/lib/styles'; import { generateProductConcepts, analyzeAdTrends, generateSlogan, generateDesignConcepts } from '@/services/geminiService'; import type { BrandConcept, MixedStyle, RegionalityData, TextPosition, AdTrendAnalysis, SubtitleOutlineStyle, BrandData, PriceData, PriceTagStyleId, PriceTagPosition, PriceTagColor, GenerateOptions } from '@/types'; import { RateLimitError } from '@/lib/errors'; interface CreationPanelProps { onGenerate: (options: GenerateOptions) => void; isLoading: boolean; cooldownUntil: Date | null; onCooldown: () => void; } const rebalancePercentages = (styles: Omit[]): MixedStyle[] => { const count = styles.length; if (count === 0) return []; const basePercentage = Math.floor(100 / count); let remainder = 100 % count; return styles.map((style, i) => { const percentage = basePercentage + (remainder > 0 ? 1 : 0); if(remainder > 0) remainder--; return { ...style, percentage }; }); }; export const PromptForm = ({ onGenerate, isLoading, cooldownUntil, onCooldown }: CreationPanelProps): React.JSX.Element => { const [basePrompt, setBasePrompt] = useState(''); const [textOverlay, setTextOverlay] = useState(''); const [mixedStyles, setMixedStyles] = useState([]); const [styleToAdd, setStyleToAdd] = useState(artStyles[0]); const [regionality, setRegionality] = useState({ country: '', city: '', neighborhood: '', weight: 25, }); const [brandName, setBrandName] = useState(''); const [brandSlogan, setBrandSlogan] = useState(''); const [brandWeight, setBrandWeight] = useState(25); const [isSloganLoading, setIsSloganLoading] = useState(false); const [sloganError, setSloganError] = useState(null); // Price Tag State const [priceText, setPriceText] = useState(''); const [priceModelText, setPriceModelText] = useState(''); const [priceStyle, setPriceStyle] = useState('circle'); const [pricePosition, setPricePosition] = useState('none'); const [priceColor, setPriceColor] = useState('red'); const [selectedTheme, setSelectedTheme] = useState(professionalThemes[0]); // Ad Trend Analysis State const [adTrendAnalysis, setAdTrendAnalysis] = useState(null); const [isAdTrendLoading, setIsAdTrendLoading] = useState(false); const [adTrendError, setAdTrendError] = useState(null); // New Brand Concept State const [brandConcepts, setBrandConcepts] = useState(null); const [isConceptLoading, setIsConceptLoading] = useState(false); const [conceptError, setConceptError] = useState(null); const [carouselOptionsVisible, setCarouselOptionsVisible] = useState<{ [key: number]: boolean }>({}); // Cooldown state const [countdown, setCountdown] = useState(0); const isInteractionDisabled = isLoading || countdown > 0 || isAdTrendLoading || isSloganLoading || isConceptLoading; const isProductConceptTheme = useMemo(() => ['Nova Marca de:', 'Nova Loja de:'].some(keyword => selectedTheme.startsWith(keyword)), [selectedTheme]); const isDesignConceptTheme = useMemo(() => selectedTheme.startsWith('Design de Interiores'), [selectedTheme]); const isConceptGeneratorVisible = isProductConceptTheme || isDesignConceptTheme; useEffect(() => { if (!cooldownUntil) { setCountdown(0); return; } const intervalId = setInterval(() => { const now = Date.now(); const remaining = Math.ceil((cooldownUntil.getTime() - now) / 1000); if (remaining > 0) { setCountdown(remaining); } else { setCountdown(0); clearInterval(intervalId); } }, 1000); // Set initial value const now = Date.now(); const remaining = Math.ceil((cooldownUntil.getTime() - now) / 1000); setCountdown(remaining > 0 ? remaining : 0); return () => clearInterval(intervalId); }, [cooldownUntil]); const handleAnalyzeTrends = async () => { if (!selectedTheme.trim() || isInteractionDisabled) return; setIsAdTrendLoading(true); setAdTrendError(null); setAdTrendAnalysis(null); try { const currentBrandData: BrandData = { name: brandName, slogan: brandSlogan, weight: brandWeight }; const result = await analyzeAdTrends(selectedTheme, regionality, currentBrandData); setAdTrendAnalysis(result); } catch (e) { if (e instanceof RateLimitError) { onCooldown(); } setAdTrendError((e as Error).message); } finally { setIsAdTrendLoading(false); } }; const handleGenerateSlogan = async () => { if (!brandName.trim() || !selectedTheme.trim() || isInteractionDisabled) { setSloganError("Preencha o nome da marca e selecione um tema profissional."); return; } setIsSloganLoading(true); setSloganError(null); try { const result = await generateSlogan(brandName, selectedTheme); setBrandSlogan(result.slogan); } catch (e) { if (e instanceof RateLimitError) { onCooldown(); } setSloganError((e as Error).message); } finally { setIsSloganLoading(false); } }; const availableStyles = useMemo(() => { const selectedNames = new Set(mixedStyles.map(s => s.name)); return artStyles.filter(s => !selectedNames.has(s)); }, [mixedStyles]); const handleAddStyle = () => { if (styleToAdd && mixedStyles.length < 3 && !mixedStyles.some(s => s.name === styleToAdd)) { const newStyles = [...mixedStyles, { name: styleToAdd, percentage: 0 }]; setMixedStyles(rebalancePercentages(newStyles)); if(availableStyles.length > 1) { const nextStyle = availableStyles.find(s => s !== styleToAdd) || ''; setStyleToAdd(nextStyle); } else { setStyleToAdd(''); } } }; const handleRemoveStyle = (indexToRemove: number) => { const newStyles = mixedStyles.filter((_, i) => i !== indexToRemove); setMixedStyles(rebalancePercentages(newStyles)); }; const handleSliderChange = (indexToUpdate: number, newPercentageValue: number) => { let styles = [...mixedStyles]; if (styles.length <= 1) { setMixedStyles([{...styles[0], percentage: 100}]); return; } const oldValue = styles[indexToUpdate].percentage; styles[indexToUpdate].percentage = newPercentageValue; let otherTotal = 100 - oldValue; let newOtherTotal = 100 - newPercentageValue; if (otherTotal > 0) { for(let i = 0; i < styles.length; i++) { if (i !== indexToUpdate) { styles[i].percentage = styles[i].percentage * (newOtherTotal / otherTotal); } } } else { const share = newOtherTotal / (styles.length - 1); for(let i = 0; i < styles.length; i++) { if (i !== indexToUpdate) { styles[i].percentage = share; } } } let finalStyles = styles.map(s => ({...s, percentage: Math.round(s.percentage)})); let roundedTotal = finalStyles.reduce((sum, s) => sum + s.percentage, 0); let diffToDistribute = 100 - roundedTotal; if(diffToDistribute !== 0 && finalStyles.length > 0) { // Distribute difference to the largest slice that is not the one being updated let targetIndex = -1; let maxPercent = -1; for (let i = 0; i < finalStyles.length; i++) { if (i !== indexToUpdate && finalStyles[i].percentage > maxPercent) { maxPercent = finalStyles[i].percentage; targetIndex = i; } } if(targetIndex !== -1) finalStyles[targetIndex].percentage += diffToDistribute; else finalStyles[0].percentage += diffToDistribute; } setMixedStyles(finalStyles); }; const handleRegionalityChange = (e: React.ChangeEvent) => { const { name, value } = e.target; setRegionality(prev => ({ ...prev, [name]: name === 'weight' ? parseInt(value, 10) : value, })); }; const handleUseAdConcept = (headline: string, primaryText: string) => { const firstLineOfPrimary = primaryText.split('\n')[0] || ''; setTextOverlay(`${headline}\n${firstLineOfPrimary}`); } const handleGenerateConcepts = async () => { if (!basePrompt.trim() || isInteractionDisabled) return; setIsConceptLoading(true); setConceptError(null); setBrandConcepts(null); try { let concepts; if (isProductConceptTheme) { const productType = selectedTheme.split(': ').pop()?.split('(')[0].trim() || 'produto'; concepts = await generateProductConcepts(basePrompt, productType); } else if (isDesignConceptTheme) { const designType = selectedTheme.split(': ').pop() || ''; concepts = await generateDesignConcepts(basePrompt, designType); } else { return; } setBrandConcepts(concepts); setCarouselOptionsVisible({}); } catch (e) { if (e instanceof RateLimitError) { onCooldown(); } setConceptError((e as Error).message); console.error(e); } finally { setIsConceptLoading(false); } }; const handleToggleCarouselOptions = (conceptIndex: number) => { setCarouselOptionsVisible(prev => ({...prev, [conceptIndex]: !prev[conceptIndex]})); }; const handleGenerateFromConcept = (concept: BrandConcept, scenario: 'product' | 'couple' | 'family' | 'isometric_details' | 'poster' | 'executive_project') => { const styleKeywords = mixedStyles.map(s => `${s.name} (${s.percentage}%)`); let finalPrompt = ''; let textForOverlay = `${concept.name}\n${concept.philosophy}`; let negativePrompt = ''; if (isProductConceptTheme) { const productType = selectedTheme.split(': ').pop()?.split('(')[0].trim() || 'produto'; const baseConceptPrompt = `**Conceito do Produto (${productType}):**\n- **Nome:** ${concept.name}\n- **Filosofia:** "${concept.philosophy}"\n- **Design:** ${concept.visualStyle}\n- **Estilos Adicionais:** ${styleKeywords.join(', ')}.`; negativePrompt = "logotipos, logos, marcas comerciais, texto, palavras, imitação, plágio"; switch(scenario) { case 'product': finalPrompt = `Fotografia de produto de alta qualidade para e-commerce. ${baseConceptPrompt}\n**Diretivas Visuais:** Foco absoluto no produto (${productType}) isolado, em um fundo neutro de estúdio (branco ou cinza claro). Iluminação profissional que realça texturas e a forma do produto. Ângulo de 3/4. Imagem limpa e premium para catálogo.`; textForOverlay = `${concept.name}`; break; case 'couple': finalPrompt = `Fotografia de lifestyle com um casal estiloso. ${baseConceptPrompt}\n**Diretivas Visuais:** Um casal jovem interagindo autenticamente em um ambiente urbano. **O produto (${productType}) DEVE estar em evidência**, sendo usado ou interagindo com ele de forma natural. A composição guia o olhar para o produto. Estética natural, momento espontâneo.`; break; case 'family': finalPrompt = `Fotografia de lifestyle com uma família moderna. ${baseConceptPrompt}\n**Diretivas Visuais:** Uma família feliz em um momento de lazer (parque, passeio). **O produto (${productType}) DEVE estar em evidência**, sendo usado por um ou mais membros, mostrando conforto e estilo para o dia a dia. Estética vibrante, clara e cheia de vida. Posicionar o produto como a escolha da família.`; textForOverlay = `${concept.name}\nPara toda a família`; break; case 'isometric_details': finalPrompt = `Criação de arte técnica e de marketing de alta qualidade. ${baseConceptPrompt}\n**Diretivas Visuais:** Gere UMA ÚNICA imagem no formato de um diagrama isométrico que mostra o produto (${productType}) de forma detalhada. A imagem NÃO deve ter texto. Em vez de texto, use 4 SETAS ou LINHAS DE CHAMADA (callouts) que apontam de características importantes do produto para os 4 cantos da imagem (canto superior esquerdo, superior direito, inferior esquerdo, inferior direito), deixando essas áreas livres para anotações posteriores. A estética deve ser limpa, técnica, mas estilizada para se alinhar ao conceito da marca. Fundo branco ou de cor neutra.`; textForOverlay = concept.name; negativePrompt = "pessoas, paisagens, cenários complexos, desordem, texto, palavras, logos, marcas comerciais, plágio"; break; case 'poster': finalPrompt = `Criação de um cartaz de marketing ou mood board de alta qualidade. ${baseConceptPrompt}\n**Diretivas Visuais:** Gere UMA ÚNICA imagem que seja um pôster ou cartaz. O layout deve ser uma composição limpa e moderna com MÚLTIPLAS imagens de lifestyle menores no estilo "photo dump" ou "trend", mostrando o produto (${productType}) em diferentes contextos autênticos. A estética deve ser de revista de design, com espaço negativo para texto.`; textForOverlay = `${concept.name}`; negativePrompt = "imagem única, uma foto só, desordem, texto, palavras, logos"; break; case 'executive_project': finalPrompt = `Criação de uma folha de projeto técnico (blueprint) de alta qualidade. ${baseConceptPrompt}\n**Diretivas Visuais:** Gere UMA ÚNICA imagem que funciona como uma folha de desenho técnico. O layout deve conter as seguintes vistas do produto (${productType}): uma VISTA ISOMÉTRICA grande e proeminente, e quatro vistas ortográficas menores e alinhadas: VISTA DE TOPO, VISTA FRONTAL, VISTA LATERAL e VISTA DE COSTAS. A estética deve ser limpa, minimalista e profissional, como um desenho de engenharia ou patente, com linhas finas e precisas sobre um fundo branco. A imagem deve ser totalmente livre de textos, números ou dimensões.`; textForOverlay = concept.name; negativePrompt = "texto, palavras, números, dimensões, logos, marcas, pessoas, paisagens, cenários complexos, desordem, cores vibrantes, sombras, fotorrealismo"; break; } } else { // Interior Design Theme const designType = selectedTheme.split(': ').pop() || ''; const baseConceptPrompt = `**Conceito de Design para ${designType}:**\n- **Nome:** ${concept.name}\n- **Filosofia:** "${concept.philosophy}"\n- **Estilo Visual e Materiais:** ${concept.visualStyle}\n- **Estilos Adicionais:** ${styleKeywords.join(', ')}.`; negativePrompt = "desordem, bagunça, má qualidade de renderização, deformado, irrealista, feio, desfocado"; switch(scenario) { case 'product': finalPrompt = `Renderização 3D fotorrealista e cinematográfica de um(a) ${designType} com base no conceito a seguir. ${baseConceptPrompt}\n**Diretivas Visuais:** Foco absoluto no móvel/ambiente. Apresentar em um cenário de estúdio minimalista ou com um fundo sutil que complemente o design. Iluminação profissional que destaca materiais, texturas e formas. Qualidade de imagem de revista de arquitetura de luxo.`; textForOverlay = `${concept.name}`; break; case 'couple': finalPrompt = `Fotografia de lifestyle fotorrealista. ${baseConceptPrompt}\n**Diretivas Visuais:** Um casal interagindo de forma autêntica e elegante no ambiente projetado (${designType}). Ex: cozinhando juntos, relaxando na sala. A arquitetura e o design do mobiliário são o pano de fundo aspiracional. A atmosfera é de conforto, sofisticação e felicidade. Luz natural invasora.`; break; case 'family': finalPrompt = `Fotografia de lifestyle fotorrealista e calorosa. ${baseConceptPrompt}\n**Diretivas Visuais:** Uma família interagindo em um momento feliz e descontraído no ambiente projetado (${designType}). Ex: pais e filhos lendo na sala, preparando uma refeição na cozinha. A cena deve transmitir a funcionalidade e a beleza do espaço no dia a dia. O design serve como um lar acolhedor.`; textForOverlay = `${concept.name}\nPara toda a família`; break; case 'isometric_details': finalPrompt = `Renderização 3D fotorrealista técnica de um(a) ${designType}. ${baseConceptPrompt}\n**Diretivas Visuais:** Gere UMA ÚNICA imagem no formato de uma planta isométrica ou vista de corte (cutaway view) do ambiente (${designType}). A imagem NÃO deve ter texto. Em vez de texto, use 4 SETAS ou LINHAS DE CHAMADA (callouts) para destacar 4 áreas ou detalhes de design chave (ex: um móvel, fluxo de layout, um material) para os 4 cantos da imagem. A estética deve ser limpa e informativa, como de uma revista de arquitetura.`; textForOverlay = concept.name; negativePrompt = "desordem, má qualidade de renderização, deformado, irrealista, feio, desfocado, texto, palavras"; break; case 'poster': finalPrompt = `Criação de um cartaz de marketing ou mood board de design de interiores. ${baseConceptPrompt}\n**Diretivas Visuais:** Gere UMA ÚNICA imagem que seja um pôster ou um mood board. O layout deve conter MÚLTIPLAS imagens menores mostrando diferentes ângulos, detalhes e texturas do ambiente (${designType}). A composição deve ser limpa, profissional, como em uma revista de arquitetura, com espaço negativo para texto.`; textForOverlay = `${concept.name}`; negativePrompt = "uma foto só, desordem, texto, palavras"; break; case 'executive_project': finalPrompt = `Criação de uma folha de projeto de arquitetura de alta qualidade. ${baseConceptPrompt}\n**Diretivas Visuais:** Gere UMA ÚNICA imagem que funciona como uma prancha de apresentação de arquitetura. O layout deve conter as seguintes vistas do ambiente (${designType}): uma VISTA ISOMÉTRICA grande e renderizada de forma limpa, e quatro vistas técnicas menores e alinhadas: PLANTA BAIXA, ELEVAÇÃO FRONTAL, ELEVAÇÃO LATERAL e uma VISTA DE CORTE (cross-section) revelando o interior. A estética deve ser de uma revista de arquitetura de ponta: minimalista, profissional, com linhas finas e precisas sobre um fundo branco. A imagem deve ser totalmente livre de textos, cotas ou anotações.`; textForOverlay = concept.name; negativePrompt = "texto, palavras, cotas, números, anotações, logos, pessoas, desordem, bagunça, cores excessivas, renderização de má qualidade"; break; } } const options: GenerateOptions = { basePrompt, imagePrompt: finalPrompt, textOverlay: textForOverlay, compositionId: 'impacto-light', textPosition: scenario === 'isometric_details' ? 'top-right' : 'center', subtitleOutline: 'auto', artStyles: styleKeywords, theme: selectedTheme, brandData: { name: brandName, slogan: brandSlogan, weight: brandWeight }, priceData: { text: priceText, modelText: priceModelText, style: priceStyle, position: pricePosition, color: priceColor }, negativeImagePrompt: negativePrompt, numberOfImages: 1, scenario, concept }; onGenerate(options); }; const handleGenerateCarousel = (concept: BrandConcept, type: 'cta' | 'educational' | 'trend') => { const styleKeywords = mixedStyles.map(s => `${s.name} (${s.percentage}%)`); let finalPrompt = ''; const numberOfImagesToGenerate = 4; // API LIMIT: Max is 4 let negativePrompt = ''; let scenario: GenerateOptions['scenario']; if (isProductConceptTheme) { const productType = selectedTheme.split(': ').pop()?.split('(')[0].trim() || 'produto'; const baseConceptPrompt = `**Conceito Base do Produto (${productType}):**\n- **Nome:** ${concept.name}\n- **Filosofia:** "${concept.philosophy}"\n- **Design:** ${concept.visualStyle}\n- **Estilos Adicionais:** ${styleKeywords.join(', ')}.`; negativePrompt = "logotipos, logos, marcas, texto, palavras, imitação, plágio"; switch (type) { case 'cta': scenario = 'carousel_cta'; finalPrompt = `Gere um carrossel de ${numberOfImagesToGenerate} imagens de anúncio de alta conversão. ${baseConceptPrompt}\n**Diretriz:** Cada imagem deve ser uma variação de um 'hero shot' do produto (${productType}), com foco em criar desejo imediato. Imagem 1: Produto em close-up extremo, mostrando um detalhe de material premium. Imagem 2: Produto em um ângulo de 3/4 dinâmico com iluminação de estúdio dramática. Imagem 3: O produto flutuando em um fundo de cor vibrante. Imagem 4: O produto em movimento ou em uso, com um leve desfoque para indicar ação. O produto é o herói absoluto em todas as ${numberOfImagesToGenerate} imagens.`; break; case 'educational': scenario = 'carousel_educational'; finalPrompt = `Gere um carrossel de ${numberOfImagesToGenerate} imagens educativas. ${baseConceptPrompt}\n**Diretriz:** Cada imagem deve destacar um detalhe técnico ou de design diferente do produto (${productType}). Use um estilo limpo, quase diagramático. Imagem 1: Close na textura de um material inovador. Imagem 2: Close em uma característica tecnológica. Imagem 3: Close em um detalhe de design único. Imagem 4: Uma visão explodida dos componentes chave, mostrando como eles se encaixam.`; break; case 'trend': scenario = 'carousel_trend'; finalPrompt = `Gere um carrossel de ${numberOfImagesToGenerate} imagens de lifestyle no estilo 'photo dump' para redes sociais. ${baseConceptPrompt}\n**Diretriz:** Capture o produto (${productType}) em contextos autênticos e da moda, com estética de filme granulado. Imagem 1: 'Fit check' ou 'setup check' em um espelho, com o look/ambiente completo em foco. Imagem 2: Close no produto em uso, em um local interessante. Imagem 3: 'Unboxing' estético em uma superfície bem composta. Imagem 4: O produto como parte de um 'flat lay' com objetos que complementam seu universo.`; break; } } else { // Interior Design Theme const designType = selectedTheme.split(': ').pop() || ''; const baseConceptPrompt = `**Conceito de Design para ${designType}:**\n- **Nome:** ${concept.name}\n- **Filosofia:** "${concept.philosophy}"\n- **Estilo Visual e Materiais:** ${concept.visualStyle}\n- **Estilos Adicionais:** ${styleKeywords.join(', ')}.`; negativePrompt = "desordem, bagunça, má qualidade de renderização, deformado, irrealista, feio, desfocado, texto, palavras"; switch (type) { case 'cta': scenario = 'carousel_cta'; finalPrompt = `Gere um carrossel fotorrealista de ${numberOfImagesToGenerate} imagens de anúncio para um(a) ${designType}. ${baseConceptPrompt}\n**Diretriz:** Foco em desejo e luxo. Imagem 1: Ângulo amplo mostrando o ambiente completo. Imagem 2: Close-up em um detalhe de material nobre (ex: veio de mármore, textura da madeira). Imagem 3: Close-up em uma solução de design inteligente (ex: gaveta oculta, sistema de iluminação). Imagem 4: O ambiente visto de uma perspectiva humana, como se o espectador estivesse prestes a entrar.`; break; case 'educational': scenario = 'carousel_educational'; finalPrompt = `Gere um carrossel fotorrealista de ${numberOfImagesToGenerate} imagens educativas sobre um(a) ${designType}. ${baseConceptPrompt}\n**Diretriz:** Foco em funcionalidade e inovação. Imagem 1: Visão geral do design. Imagem 2: Detalhe mostrando a durabilidade ou facilidade de limpeza de um material. Imagem 3: Detalhe mostrando a capacidade de armazenamento ou organização. Imagem 4: Detalhe mostrando a ergonomia ou o conforto do design em uso.`; break; case 'trend': scenario = 'carousel_trend'; finalPrompt = `Gere um carrossel de ${numberOfImagesToGenerate} imagens de lifestyle para redes sociais, com estética 'clean' e orgânica, para um(a) ${designType}. ${baseConceptPrompt}\n**Diretriz:** Capture momentos autênticos no espaço. Imagem 1: Mãos preparando um café na bancada da cozinha. Imagem 2: Um livro e uma manta sobre uma poltrona na sala. Imagem 3: Um canto do ambiente com uma planta e luz natural. Imagem 4: Detalhe da organização de um armário ou closet. O ambiente é o protagonista silencioso.`; break; } } const options: GenerateOptions = { basePrompt, imagePrompt: finalPrompt, textOverlay: "", compositionId: 'impacto-light', textPosition: 'center', subtitleOutline: 'auto', artStyles: styleKeywords, theme: selectedTheme, brandData: { name: concept.name, slogan: concept.philosophy, weight: 100 }, priceData: { text: '', modelText: '', style: 'circle', position: 'none', color: 'red' }, negativeImagePrompt: negativePrompt, numberOfImages: numberOfImagesToGenerate, scenario, concept, }; onGenerate(options); }; const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); if (isInteractionDisabled || !basePrompt.trim()) return; const artStyleKeywords = mixedStyles.map(style => `${style.name} (${style.percentage}%)`); let imagePrompt = `${basePrompt}, tema: ${selectedTheme}.`; if (artStyleKeywords.length > 0) { imagePrompt += ` Estilos visuais: ${artStyleKeywords.join(', ')}.`; } const regionalityKeywords = [regionality.country, regionality.city, regionality.neighborhood].filter(Boolean).join(', '); if (regionalityKeywords && regionality.weight > 10) { imagePrompt += ` Influência regional de ${regionalityKeywords} (${regionality.weight}%).`; } if (brandName && brandWeight > 10) { imagePrompt += ` Associado à marca ${brandName} (${brandWeight}%).`; } const options: GenerateOptions = { basePrompt, imagePrompt, textOverlay, compositionId: 'random', textPosition: 'center', subtitleOutline: 'auto', artStyles: artStyleKeywords, theme: selectedTheme, brandData: { name: brandName, slogan: brandSlogan, weight: brandWeight }, priceData: { text: priceText, modelText: priceModelText, style: priceStyle, position: pricePosition, color: priceColor }, numberOfImages: 1 }; onGenerate(options); }; return (

Painel de Criação

{/* --- SEÇÃO 1: IDEIA CENTRAL --- */}