Z

Zuna AI

Offline-first. Voz, chat, câmera, geração e histórico local.

Chat

Digite, fale no microfone ou abra a chamada. A fala final é enviada automaticamente.

Motor local de produção

O Zuna AI gera respostas, código, briefings visuais, beats simples, vídeos demo e e-books em modo offline. Para APK/AAB, publicação real, Google login e análise visual avançada, conecte serviços externos depois.

Saídas prontas

Exporte conteúdo como texto copiado, imagem PNG, áudio WAV, vídeo WebM e projetos HTML completos sem depender de servidores.

Conta e idioma

Login local estilo Google
Em modo offline é uma conta local simulada com perfil persistente.

Voz, tema e privacidade

Responder por voz
Fala automática após enviar mensagem ou reconhecer voz.
Autoenviar fala final
Envia automaticamente a última palavra detectada no microfone.
Censura / +18
Bloqueio local de conteúdo sensível até validação explícita.
Permissão de mídia
Solicita câmera/microfone ao abrir chamada ou mic.

Adicionar personalidade

Personalidades prontas

\n`,css:`${header}:root{--bg:#0b0f14;--panel:#111823;--text:#edf2ff;--accent:#8a63ff}*{box-sizing:border-box}body{margin:0;font-family:system-ui;background:var(--bg);color:var(--text)}`,javascript:`${header}const app={name:${JSON.stringify(title)},createdAt:new Date().toISOString()};\nfunction init(){console.log('Zuna AI ready',app)}\ninit();`,python:`${header}def main():\n print(${JSON.stringify(`Zuna AI: ${title}`)})\n\nif __name__ == '__main__':\n main()\n`,java:`${header}public class Main {\n public static void main(String[] args) {\n System.out.println("Zuna AI: ${title}");\n }\n}\n`,kotlin:`${header}fun main() {\n println("Zuna AI: ${title}")\n}\n`,dart:`${header}void main() {\n print('Zuna AI: ${title}');\n}\n`,swift:`${header}import Foundation\nprint("Zuna AI: ${title}")\n`,php:`${header}\nint main(){std::cout << "Zuna AI: ${title}" << std::endl;return 0;}\n`,c:`${header}#include \nint main(void){printf("Zuna AI: ${title}\\n");return 0;}\n`,bash:`${header}#!/usr/bin/env bash\necho "Zuna AI: ${title}"\n`};return out[lang]||out.javascript} function blueprint(kind,prompt){const t=titleFrom(prompt);const keywords=[];if(/site|web|landing|p[áa]gina/.test(prompt))keywords.push('web');if(/app|apk|aab|android/.test(prompt))keywords.push('mobile');if(/imagem|poster|logo|cartaz/.test(prompt))keywords.push('image');if(/vídeo|video|reels|shorts/.test(prompt))keywords.push('video');if(/ebook|livro|pdf|epub/.test(prompt))keywords.push('ebook');if(/música|musica|beat|wav|mp3/.test(prompt))keywords.push('audio');const stack=kind==='site'?['HTML','CSS','Vanilla JS']:kind==='app'?['Android','Kotlin/Flutter','Material You']:kind==='image'?['Canvas','Paleta dinâmica','Export PNG']:kind==='video'?['Canvas','MediaRecorder','Timeline']:kind==='audio'?['Web Audio','WAV export','Beat synth']:['Offline engine','HTML único','LocalStorage'];return{title:t,summary:`Blueprint local de ${kind} para "${t}".`,code:[`Projeto: ${t}`,`Tipo: ${kind}`,`Palavras-chave: ${keywords.length?keywords.join(', '):'nenhuma'}`,`Stack: ${stack.join(' | ')}`,'','Estrutura sugerida:','1. Cabeçalho premium','2. Conteúdo principal responsivo','3. Ações rápidas e exportação','4. Persistência local','5. Ganchos para integração futura'].join('\n')}} function wrap(ctx,text,x,y,maxWidth,lineHeight){const words=String(text||'').split(/\s+/);let line='';for(let n=0;nmaxWidth&&n>0){ctx.fillText(line,x,y);line=words[n]+' ';y+=lineHeight}else line=test}ctx.fillText(line,x,y)} function imageCanvas(prompt){const c=document.createElement('canvas');c.width=1280;c.height=720;const ctx=c.getContext('2d');const h=Math.abs(hash(prompt))%360;const g=ctx.createLinearGradient(0,0,c.width,c.height);g.addColorStop(0,`hsl(${h},84%,12%)`);g.addColorStop(1,`hsl(${(h+55)%360},78%,22%)`);ctx.fillStyle=g;ctx.fillRect(0,0,c.width,c.height);for(let i=0;i<16;i++){const x=(i*81+h*7)%c.width,y=(i*52+h*5)%c.height;ctx.fillStyle=`hsla(${(h+i*19)%360},90%,62%,.18)`;ctx.beginPath();ctx.arc(x,y,70+(i%4)*24,0,Math.PI*2);ctx.fill()}ctx.fillStyle='rgba(255,255,255,.92)';ctx.font='700 64px system-ui';ctx.fillText('Zuna AI',72,110);ctx.font='400 36px system-ui';wrap(ctx,prompt||'Imagem local criada pela Zuna AI',72,170,1050,48);ctx.fillStyle='rgba(255,255,255,.78)';ctx.fillRect(72,560,1136,2);ctx.font='500 24px system-ui';ctx.fillText('Exportação PNG local',72,610);return c} function wavBlob(){const sr=44100,secs=10,len=sr*secs,b=new Float32Array(len),bpm=124,step=Math.round(sr*60/bpm/4),notes=[110,110,165,110,196,165,110,82.41];for(let i=0;idone=r);rec.ondataavailable=e=>e.data.size&&chunks.push(e.data);rec.onstop=()=>done(new Blob(chunks,{type:'video/webm'}));rec.start();const h=Math.abs(hash(prompt))%360;const start=performance.now();const draw=ts=>{const p0=Math.min(1,(ts-start)/5000),g=ctx.createLinearGradient(0,0,canvas.width,canvas.height);g.addColorStop(0,`hsl(${(h+p0*140)%360},90%,11%)`);g.addColorStop(1,`hsl(${(h+70)%360},84%,25%)`);ctx.fillStyle=g;ctx.fillRect(0,0,canvas.width,canvas.height);for(let i=0;i<10;i++){ctx.strokeStyle=`hsla(${(h+i*18)%360},95%,64%,${0.08+p0*0.22})`;ctx.lineWidth=3+i*.2;ctx.beginPath();ctx.arc(640+Math.cos(ts/600+i)*90,360+Math.sin(ts/700+i)*70,60+i*18+p0*140,0,Math.PI*2);ctx.stroke()}ctx.fillStyle='rgba(255,255,255,.92)';ctx.font='800 72px system-ui';ctx.fillText('Zuna AI',70,120);ctx.font='500 34px system-ui';wrap(ctx,prompt,70,190,1060,44);ctx.fillStyle='rgba(255,255,255,.7)';ctx.fillText('Video demo local',70,650);if(p0<1)requestAnimationFrame(draw);else setTimeout(()=>rec.stop(),180)};requestAnimationFrame(draw);return p} function generate(text){const c=text.trim(),i=infer(c),lang=langFrom(c);if(!c)return{text:'Escreva algo para eu responder, ou use o microfone/chamada.',meta:{tags:['vazio']}};if(i.greet)return{text:`Olá, ${state.profile.name||'eu sou a Zuna AI'}. Estou pronta para conversar, criar código pronto para copiar, gerar imagens, esboçar vídeos, montar e-books e responder por voz. Perfil atual: ${state.profile.bio||'profissional, claro e rápido'}.`,meta:{tags:['saudação','voz']}};if(i.time)return{text:`Horário local: ${timeFmt()}. Fuso detectado: ${tz()}. Se quiser, eu também posso formatar isso como relógio, agenda ou painel de hora mundial.`,meta:{tags:['tempo']}};if(i.help)return{text:`A Zuna AI local faz o seguinte offline: - conversa por texto e voz - chamada com câmera e microfone - respostas em voz - geração de código com botão de copiar - blueprint de sites, apps, e-books, imagens, vídeos e áudio - histórico persistente e exclusão de mensagens Para recursos reais como Google login, análise visual avançada e publicação, conecte um backend depois.`,meta:{tags:['ajuda']}};if(i.code)return{text:`Criei um arquivo-base em ${lang.toUpperCase()} com foco em ${state.profile.bio||'execução profissional'}.`,meta:{tags:['código',lang],code:[{language:lang,code:codeTpl(lang,c)}]}};if(i.image)return{text:`Gerando um blueprint visual local para "${titleFrom(c)}".`,meta:{tags:['imagem'],imagePrompt:c}};if(i.video)return{text:`Preparando um vídeo demo local para "${titleFrom(c)}".`,meta:{tags:['vídeo'],videoPrompt:c}};if(i.audio)return{text:'Vou gerar um beat local simples em WAV. Se quiser, eu também posso transformar isso em letra, estrutura de música ou trilha.',meta:{tags:['áudio'],audioPrompt:c}};if(i.ebook)return{text:'Monte um livro-base em Markdown, pronto para exportar, com capítulos e estrutura editorial.',meta:{tags:['ebook'],code:[{language:'markdown',code:[`# ${titleFrom(c)}`,'','## Capítulo 1 - Introdução','Explique o objetivo do projeto com clareza.','','## Capítulo 2 - Desenvolvimento','Liste o conteúdo principal, recursos, etapas e implementação.','','## Capítulo 3 - Conclusão','Feche com aprendizados e próximos passos.'].join('\n')}]}};if(i.call)return{text:'A chamada já está pronta no app: voz, vídeo, microfone contínuo, resposta falada e alternância de câmera. Se algo falhar, normalmente é permissão do navegador.',meta:{tags:['chamada']}};return{text:`Entendi. Vou responder no estilo ${state.profile.bio||'profissional, claro e rápido'}. Posso transformar seu pedido em código pronto, blueprint de app/site, conteúdo visual, áudio local ou roteiro. Se você quiser algo mais específico, diga o alvo e eu entrego o template mais direto possível.`,meta:{tags:['geral']}}} async function speak(text){if(!state.settings.speak||!window.speechSynthesis)return;try{speechSynthesis.cancel();const u=new SpeechSynthesisUtterance(strip(text));u.lang=state.profile.lang||'pt-BR';u.rate=.95;u.pitch=1.02;u.volume=1;const voices=speechSynthesis.getVoices();const v=voices.find(x=>x.name===state.settings.voiceName);if(v)u.voice=v;speechSynthesis.speak(u)}catch{}} function toast(text){els.callStatus.textContent=text;clearTimeout(window.__toast);window.__toast=setTimeout(()=>{els.callStatus.textContent=state.call.open?(state.call.mode==='video'?'Chamada de vídeo ativa.':'Chamada de voz ativa.'):'Pronta.'},1800)} function renderMsg(m,cid){const row=document.createElement('div');row.className=`msg ${m.role==='user'?'user':''}`;const av=document.createElement('div');av.className='avatar';av.textContent=m.role==='user'?'EU':'Z';const main=document.createElement('div');main.className='mainMsg';const head=document.createElement('div');head.className='msgHead';const name=document.createElement('div');name.className='msgName';name.textContent=m.role==='user'?(state.profile.name||'Você'):(m.meta?.label||'Zuna AI');const actions=document.createElement('div');actions.className='msgActions';const copy=document.createElement('button');copy.className='tiny';copy.textContent='⧉';copy.title='Copiar';copy.onclick=()=>copyText(strip(m.content));const del=document.createElement('button');del.className='tiny';del.textContent='🗑';del.title='Excluir';del.onclick=()=>deleteMessage(cid,m.id);actions.append(copy,del);head.append(name,actions);const bubble=document.createElement('div');bubble.className='bubble';bubble.innerHTML=renderContent(m);main.append(head,bubble);row.append(av,main);return row} function renderContent(m){let html=esc(m.content||'').replace(/\n/g,'
');if(m.meta?.code){html+=m.meta.code.map((b,idx)=>`
${esc(b.language||'code')} • arquivo ${idx+1}
${esc(b.code)}
`).join('')}if(m.meta?.renderedImage)html+=`
PNG local
Imagem gerada
`;if(m.meta?.renderedAudio)html+=`
Áudio WAV local
`;if(m.meta?.renderedVideo)html+=`
Vídeo WebM local
`;if(m.meta?.tags?.length)html+=`
${m.meta.tags.map(t=>`${esc(t)}`).join('')}
`;return html} function renderConversations(){els.convList.innerHTML='';[...state.conversations].sort((a,b)=>b.updatedAt-a.updatedAt).forEach(c=>{const item=document.createElement('button');item.className=`conv ${c.id===state.activeId?'active':''}`;item.onclick=()=>{state.activeId=c.id;renderAll();save()};const main=document.createElement('div');main.className='convMain';main.innerHTML=`
${esc(c.title||'Nova conversa')}
${c.messages.filter(m=>m.role==='user').length} mensagens • ${dateFmt(c.updatedAt)}
`;const del=document.createElement('button');del.className='tiny';del.textContent='🗑';del.onclick=e=>{e.stopPropagation();deleteConversation(c.id)};item.append(main,del);els.convList.appendChild(item)})} function renderMessages(){const c=conv();els.messages.innerHTML='';if(!c)return;if(!c.messages.length){const empty=document.createElement('div');empty.className='card';empty.innerHTML='

Comece a conversar

Use texto, microfone ou chamada. A Zuna AI responde com voz, gera código com botão de copiar e salva o histórico localmente.

';els.messages.appendChild(empty);return}c.messages.forEach(m=>els.messages.appendChild(renderMsg(m,c.id)));queueMicrotask(()=>{els.messages.scrollTop=els.messages.scrollHeight})} function renderLibrary(){const items=[{title:'Site premium',desc:'Estrutura de landing page, app web ou portfólio com componentes prontos para copiar.',action:()=>sendPrompt('Crie um site completo, premium e responsivo em HTML único.')},{title:'App Android',desc:'Blueprint de APK/AAB com UI moderna, arquitetura e manifesto.',action:()=>sendPrompt('Crie um app Android completo com estrutura profissional.')},{title:'E-book',desc:'Capítulos, capa textual e estrutura pronta para exportar.',action:()=>sendPrompt('Crie um e-book completo em Markdown com capa, capítulos e conclusão.')},{title:'Imagem',desc:'PNG local gerado por canvas com paleta e composição.',action:()=>sendPrompt('Crie um cartaz profissional para empresa em alta qualidade.')},{title:'Vídeo',desc:'Demo animada local exportável via MediaRecorder.',action:()=>sendPrompt('Crie um vídeo promocional local e profissional.')},{title:'Música',desc:'Beat simples local exportado como WAV.',action:()=>sendPrompt('Crie uma música beat instrumental de alta qualidade.')}];els.libraryGrid.innerHTML='';items.forEach(it=>{const card=document.createElement('div');card.className='card';card.innerHTML=`

${esc(it.title)}

${esc(it.desc)}

`;card.querySelector('button').onclick=it.action;els.libraryGrid.appendChild(card)})} function renderPersonas(){els.personaList.innerHTML='';state.personas.forEach(p=>{const node=document.createElement('div');node.className='persona';node.innerHTML=`

${esc(p.name)}

${esc(p.desc)}
`;node.querySelector('button').onclick=()=>{state.profile.bio=p.desc;els.profileBio.value=p.desc;els.modalBio.value=p.desc;save();toast('Personalidade aplicada')};els.personaList.appendChild(node)})} function renderVoices(){const voices=window.speechSynthesis?speechSynthesis.getVoices():[];els.voiceSelect.innerHTML='';const first=document.createElement('option');first.value='';first.textContent=voices.length?'Automática':'Sem voz disponível';els.voiceSelect.appendChild(first);voices.forEach(v=>{const o=document.createElement('option');o.value=v.name;o.textContent=`${v.name}${v.lang?` (${v.lang})`:''}`;els.voiceSelect.appendChild(o);if(!state.settings.voiceName&&/pt|brazil|brasil/i.test(v.lang+' '+v.name))state.settings.voiceName=v.name});els.voiceSelect.value=state.settings.voiceName||''} function setSwitch(el,on){el.classList.toggle('on',!!on)} function syncSettings(){document.documentElement.dataset.theme=state.theme;setSwitch(els.swSpeak,state.settings.speak);setSwitch(els.swAutoSend,state.settings.autoSend);setSwitch(els.swSafety,state.settings.safety);setSwitch(els.swMedia,state.settings.mediaPermission);setSwitch(els.swLocalLogin,state.settings.localLogin);els.qualityRange.value=String(state.quality);els.profileName.value=state.profile.name||'';els.profileBirth.value=state.profile.birth||'';els.profileAge.value=state.profile.age||'';els.profileLang.value=state.profile.lang||'pt-BR';els.profileBio.value=state.profile.bio||'';els.modalName.value=state.profile.name||'';els.modalBirth.value=state.profile.birth||'';els.modalAge.value=state.profile.age||'';els.modalLang.value=state.profile.lang||'pt-BR';els.modalBio.value=state.profile.bio||'';els.brandLine.textContent=`Offline-first. Voz, chat, câmera, geração e histórico local. Timezone: ${tz()}`;els.panelSubtitle.textContent=state.settings.autoSend?'Digite, fale no microfone ou abra a chamada. A fala final é enviada automaticamente.':'Digite, fale no microfone ou abra a chamada.';els.callTitle.textContent=state.call.mode==='video'?'Chamada de vídeo':'Chamada de voz';els.callSubtitle.textContent='Permita microfone e câmera. A fala final vira mensagem automaticamente.';els.cameraLabel.textContent=state.call.facing==='environment'?'Câmera traseira':'Câmera frontal'} function renderContentToTranscript(text){const chunks=[];if(text)chunks.push(`
Transcrição
${esc(text)}
`);const last=[...(conv()?.messages||[])].reverse().find(m=>m.role==='assistant');if(last)chunks.push(`
Última resposta
${esc(strip(last.content))}
`);els.callTranscript.innerHTML=chunks.join('')||'
Nenhuma fala ainda.
'} function appendCall(text){els.callTranscript.insertAdjacentHTML('beforeend',`
${esc(text)}
`);els.callTranscript.scrollTop=els.callTranscript.scrollHeight} function copyText(text){navigator.clipboard?.writeText(String(text)).catch(()=>{const ta=document.createElement('textarea');ta.value=String(text);document.body.appendChild(ta);ta.select();document.execCommand('copy');ta.remove()})} function deleteMessage(cid,id){const c=state.conversations.find(x=>x.id===cid);if(!c)return;if(!confirm('Excluir esta mensagem?'))return;c.messages=c.messages.filter(m=>m.id!==id);if(!c.messages.length)c.title='Nova conversa';c.updatedAt=Date.now();save();renderAll()} function deleteConversation(id){const c=state.conversations.find(x=>x.id===id);if(!c)return;if(!confirm(`Excluir a conversa "${c.title}"?`))return;state.conversations=state.conversations.filter(x=>x.id!==id);if(!state.conversations.length)state.conversations=[newConv('Bem-vindo')];if(!state.conversations.some(x=>x.id===state.activeId))state.activeId=state.conversations[0].id;save();renderAll()} function renderAll(){syncSettings();renderConversations();renderMessages();save()} async function speakReply(text){await speak(text)} function initRecognition(){if(!SpeechRecognition)return null;const r=new SpeechRecognition();r.continuous=false;r.interimResults=true;r.maxAlternatives=1;r.lang=state.profile.lang||'pt-BR';r.onstart=()=>{state.listening=true;toast('Ouvindo...')};r.onerror=()=>{state.listening=false;toast('Microfone indisponível ou permissão negada.')};r.onend=()=>{state.listening=false};r.onresult=async e=>{let final='',interim='';for(let i=e.resultIndex;it.stop())}catch{}state.call.stream=null;els.cameraVideo.srcObject=null;if(state.call.raf)cancelAnimationFrame(state.call.raf);state.call.raf=0} function drawCamera(){const ctx=els.cameraCanvas.getContext('2d');const loop=ts=>{if(!state.call.open||!state.call.stream)return;els.cameraCanvas.width=1280;els.cameraCanvas.height=720;const h=Math.abs(Math.sin(ts/1200))*60+220;const g=ctx.createLinearGradient(0,0,1280,720);g.addColorStop(0,`hsl(${h},80%,10%)`);g.addColorStop(1,`hsl(${h+50},80%,26%)`);ctx.fillStyle=g;ctx.fillRect(0,0,1280,720);ctx.strokeStyle='rgba(255,255,255,.16)';ctx.lineWidth=2;for(let i=0;i<18;i++){ctx.beginPath();ctx.arc(640+Math.cos(ts/1000+i)*120,360+Math.sin(ts/850+i*.7)*85,50+(i%4)*16,0,Math.PI*2);ctx.stroke()}ctx.fillStyle='rgba(255,255,255,.92)';ctx.font='800 70px system-ui';ctx.fillText('Zuna AI',72,112);ctx.font='500 32px system-ui';ctx.fillText(`Modo ${state.call.mode==='video'?'vídeo':'voz'} • ${els.cameraLabel.textContent}`,72,164);ctx.font='400 26px system-ui';wrap(ctx,'Chamada em tempo real. O navegador envia a sua fala final para a IA local.',72,220,1040,38);state.call.raf=requestAnimationFrame(loop)};loop(performance.now())} async function flipCamera(){if(state.call.mode!=='video')return;state.call.facing=state.call.facing==='environment'?'user':'environment';await startCamera()} async function processReply(prompt,opts={}){const r=generate(prompt),c=conv();if(r.imagePrompt){const canvas=imageCanvas(r.imagePrompt);const blob=await new Promise(res=>canvas.toBlob(res,'image/png'));const url=URL.createObjectURL(blob);c.messages.push({id:uid(),role:'assistant',content:r.text,ts:Date.now(),meta:{...r.meta,renderedImage:url}});c.updatedAt=Date.now();save();renderAll();if(state.settings.speak)await speakReply(r.text);return}if(r.videoPrompt){const blob=await videoBlob(r.videoPrompt);const url=blob?URL.createObjectURL(blob):'';c.messages.push({id:uid(),role:'assistant',content:r.text+(blob?'':'\n\nSeu navegador não oferece MediaRecorder para exportar vídeo local; a prévia continua disponível no canvas interno.'),ts:Date.now(),meta:{...r.meta,renderedVideo:url}});c.updatedAt=Date.now();save();renderAll();if(state.settings.speak)await speakReply(r.text);return}if(r.audioPrompt){const blob=wavBlob();const url=URL.createObjectURL(blob);c.messages.push({id:uid(),role:'assistant',content:r.text,ts:Date.now(),meta:{...r.meta,renderedAudio:url}});c.updatedAt=Date.now();save();renderAll();if(state.settings.speak)await speakReply(r.text);return}c.messages.push({id:uid(),role:'assistant',content:r.text,ts:Date.now(),meta:r.meta});if(r.meta?.code)c.messages[c.messages.length-1].meta.code=r.meta.code;c.updatedAt=Date.now();save();renderAll();if(state.settings.speak&&!opts.skipSpeak)await speakReply(r.text)} async function sendCurrent(){const text=els.input.value.trim();if(!text)return;els.input.value='';autosize();addMsg('user',text,{label:state.profile.name||'Você',tags:['texto']});await processReply(text)} function sendPrompt(text){els.input.value=text;autosize();sendCurrent()} function autosize(){els.input.style.height='auto';els.input.style.height=Math.min(140,els.input.scrollHeight)+'px'} function openProfile(){syncSettings();els.profileOverlay.classList.add('show');els.profileOverlay.setAttribute('aria-hidden','false')} function closeProfile(){els.profileOverlay.classList.remove('show');els.profileOverlay.setAttribute('aria-hidden','true')} function syncDraft(){state.profile.name=els.profileName.value.trim();state.profile.birth=els.profileBirth.value;state.profile.age=els.profileAge.value;state.profile.lang=els.profileLang.value;state.profile.bio=els.profileBio.value.trim();els.modalName.value=state.profile.name;els.modalBirth.value=state.profile.birth;els.modalAge.value=state.profile.age;els.modalLang.value=state.profile.lang;els.modalBio.value=state.profile.bio;save()} function newChat(){const c=newConv('Nova conversa');state.conversations.unshift(c);state.activeId=c.id;save();renderAll();els.input.focus()} function updateTranscript(text=''){state.call.transcript=text;const chunks=[];if(text)chunks.push(`
Transcrição
${esc(text)}
`);const last=[...(conv()?.messages||[])].reverse().find(m=>m.role==='assistant');if(last)chunks.push(`
Última resposta
${esc(strip(last.content))}
`);els.callTranscript.innerHTML=chunks.join('')||'
Nenhuma fala ainda.
'} function appendCall(text){els.callTranscript.insertAdjacentHTML('beforeend',`
${esc(text)}
`);els.callTranscript.scrollTop=els.callTranscript.scrollHeight} async function processCallUser(text){appendCall(`Você: ${text}`);const reply=generate(text);const c=conv();c.messages.push({id:uid(),role:'user',content:text,ts:Date.now(),meta:{label:state.profile.name||'Você',tags:['call']}});c.messages.push({id:uid(),role:'assistant',content:reply.text,ts:Date.now(),meta:reply.meta});if(reply.meta?.code)c.messages[c.messages.length-1].meta.code=reply.meta.code;c.updatedAt=Date.now();save();renderAll();updateTranscript(`Você: ${text}\n\nZuna AI: ${strip(reply.text)}`);if(state.settings.speak)await speakReply(reply.text)} function renderAll(){syncSettings();renderConversations();renderMessages();save()} function renderConversations(){els.convList.innerHTML='';[...state.conversations].sort((a,b)=>b.updatedAt-a.updatedAt).forEach(c=>{const item=document.createElement('button');item.className=`conv ${c.id===state.activeId?'active':''}`;item.onclick=()=>{state.activeId=c.id;renderAll();save()};const main=document.createElement('div');main.className='convMain';main.innerHTML=`
${esc(c.title||'Nova conversa')}
${c.messages.filter(m=>m.role==='user').length} mensagens • ${dateFmt(c.updatedAt)}
`;const del=document.createElement('button');del.className='tiny';del.textContent='🗑';del.onclick=e=>{e.stopPropagation();deleteConversation(c.id)};item.append(main,del);els.convList.appendChild(item)})} function renderMessages(){const c=conv();els.messages.innerHTML='';if(!c)return;if(!c.messages.length){const empty=document.createElement('div');empty.className='card';empty.innerHTML='

Comece a conversar

Use texto, microfone ou chamada. A Zuna AI responde com voz, gera código com botão de copiar e salva o histórico localmente.

';els.messages.appendChild(empty);return}c.messages.forEach(m=>els.messages.appendChild(renderMsg(m,c.id)));queueMicrotask(()=>els.messages.scrollTop=els.messages.scrollHeight)} function renderMsg(m,cid){const row=document.createElement('div');row.className=`msg ${m.role==='user'?'user':''}`;const av=document.createElement('div');av.className='avatar';av.textContent=m.role==='user'?'EU':'Z';const main=document.createElement('div');main.className='mainMsg';const head=document.createElement('div');head.className='msgHead';const name=document.createElement('div');name.className='msgName';name.textContent=m.role==='user'?(state.profile.name||'Você'):(m.meta?.label||'Zuna AI');const actions=document.createElement('div');actions.className='msgActions';const copy=document.createElement('button');copy.className='tiny';copy.textContent='⧉';copy.title='Copiar';copy.onclick=()=>copyText(strip(m.content));const del=document.createElement('button');del.className='tiny';del.textContent='🗑';del.title='Excluir';del.onclick=()=>deleteMessage(cid,m.id);actions.append(copy,del);head.append(name,actions);const bubble=document.createElement('div');bubble.className='bubble';bubble.innerHTML=renderContent(m);main.append(head,bubble);row.append(av,main);return row} function renderContent(m){let html=esc(m.content||'').replace(/\n/g,'
');if(m.meta?.code)html+=m.meta.code.map((b,idx)=>`
${esc(b.language||'code')} • arquivo ${idx+1}
${esc(b.code)}
`).join('');if(m.meta?.renderedImage)html+=`
PNG local
Imagem gerada
`;if(m.meta?.renderedAudio)html+=`
Áudio WAV local
`;if(m.meta?.renderedVideo)html+=`
Vídeo WebM local
`;if(m.meta?.tags?.length)html+=`
${m.meta.tags.map(t=>`${esc(t)}`).join('')}
`;return html} function copyCodeByMsg(msgId,idx){const c=conv(),m=c?.messages.find(x=>x.id===msgId),b=m?.meta?.code?.[idx];if(!b)return;copyText(b.code);toast('Código copiado')} function exportAsset(msgId,key,ext){const c=conv(),m=c?.messages.find(x=>x.id===msgId),src=m?.meta?.[key];if(!src)return;const a=document.createElement('a');a.href=src;a.download=`zuna-${ext}-${msgId}`;a.click()} function deleteMessage(cid,id){const c=state.conversations.find(x=>x.id===cid);if(!c)return;if(!confirm('Excluir esta mensagem?'))return;c.messages=c.messages.filter(m=>m.id!==id);if(!c.messages.length)c.title='Nova conversa';c.updatedAt=Date.now();save();renderAll()} function deleteConversation(id){const c=state.conversations.find(x=>x.id===id);if(!c)return;if(!confirm(`Excluir a conversa "${c.title}"?`))return;state.conversations=state.conversations.filter(x=>x.id!==id);if(!state.conversations.length)state.conversations=[newConv('Bem-vindo')];if(!state.conversations.some(x=>x.id===state.activeId))state.activeId=state.conversations[0].id;save();renderAll()} function renderLibrary(){const items=[{title:'Site premium',desc:'Estrutura de landing page, app web ou portfólio com componentes prontos para copiar.',q:'Crie um site completo, premium e responsivo em HTML único.'},{title:'App Android',desc:'Blueprint de APK/AAB com UI moderna, arquitetura e manifesto.',q:'Crie um app Android completo com estrutura profissional.'},{title:'E-book',desc:'Capítulos, capa textual e estrutura pronta para exportar.',q:'Crie um e-book completo em Markdown com capa, capítulos e conclusão.'},{title:'Imagem',desc:'PNG local gerado por canvas com paleta e composição.',q:'Crie um cartaz profissional para empresa em alta qualidade.'},{title:'Vídeo',desc:'Demo animada local exportável via MediaRecorder.',q:'Crie um vídeo promocional local e profissional.'},{title:'Música',desc:'Beat simples local exportado como WAV.',q:'Crie uma música beat instrumental de alta qualidade.'}];els.libraryGrid.innerHTML='';items.forEach(it=>{const card=document.createElement('div');card.className='card';card.innerHTML=`

${esc(it.title)}

${esc(it.desc)}

`;card.querySelector('button').onclick=()=>sendPrompt(it.q);els.libraryGrid.appendChild(card)})} function renderPersonas(){els.personaList.innerHTML='';state.personas.forEach(p=>{const node=document.createElement('div');node.className='persona';node.innerHTML=`

${esc(p.name)}

${esc(p.desc)}
`;node.querySelector('button').onclick=()=>{state.profile.bio=p.desc;els.profileBio.value=p.desc;els.modalBio.value=p.desc;save();toast('Personalidade aplicada')};els.personaList.appendChild(node)})} function renderVoices(){const voices=window.speechSynthesis?speechSynthesis.getVoices():[];els.voiceSelect.innerHTML='';const first=document.createElement('option');first.value='';first.textContent=voices.length?'Automática':'Sem voz disponível';els.voiceSelect.appendChild(first);voices.forEach(v=>{const o=document.createElement('option');o.value=v.name;o.textContent=`${v.name}${v.lang?` (${v.lang})`:''}`;els.voiceSelect.appendChild(o);if(!state.settings.voiceName&&/pt|brazil|brasil/i.test(v.lang+' '+v.name))state.settings.voiceName=v.name});els.voiceSelect.value=state.settings.voiceName||''} function syncSettings(){document.documentElement.dataset.theme=state.theme;setSwitch(els.swSpeak,state.settings.speak);setSwitch(els.swAutoSend,state.settings.autoSend);setSwitch(els.swSafety,state.settings.safety);setSwitch(els.swMedia,state.settings.mediaPermission);setSwitch(els.swLocalLogin,state.settings.localLogin);els.qualityRange.value=String(state.quality);els.profileName.value=state.profile.name||'';els.profileBirth.value=state.profile.birth||'';els.profileAge.value=state.profile.age||'';els.profileLang.value=state.profile.lang||'pt-BR';els.profileBio.value=state.profile.bio||'';els.modalName.value=state.profile.name||'';els.modalBirth.value=state.profile.birth||'';els.modalAge.value=state.profile.age||'';els.modalLang.value=state.profile.lang||'pt-BR';els.modalBio.value=state.profile.bio||'';els.brandLine.textContent=`Offline-first. Voz, chat, câmera, geração e histórico local. Timezone: ${tz()}`;els.panelSubtitle.textContent=state.settings.autoSend?'Digite, fale no microfone ou abra a chamada. A fala final é enviada automaticamente.':'Digite, fale no microfone ou abra a chamada.';els.callTitle.textContent=state.call.mode==='video'?'Chamada de vídeo':'Chamada de voz';els.callSubtitle.textContent='Permita microfone e câmera. A fala final vira mensagem automaticamente.';els.cameraLabel.textContent=state.call.facing==='environment'?'Câmera traseira':'Câmera frontal'} function openProfile(){syncSettings();els.profileOverlay.classList.add('show');els.profileOverlay.setAttribute('aria-hidden','false')} function closeProfile(){els.profileOverlay.classList.remove('show');els.profileOverlay.setAttribute('aria-hidden','true')} function newChat(){const c=newConv('Nova conversa');state.conversations.unshift(c);state.activeId=c.id;save();renderAll();els.input.focus()} function sendPrompt(text){els.input.value=text;autosize();sendCurrent()} function autosize(){els.input.style.height='auto';els.input.style.height=Math.min(140,els.input.scrollHeight)+'px'} async function startMic(mode='chat'){if(!state.settings.mediaPermission){toast('Permissão de mídia desativada.');return}if(!state.recognition)state.recognition=initRecognition();if(!state.recognition){alert('Este navegador não suporta reconhecimento de fala.');return}stopRecognition();state.listeningMode=mode;try{state.recognition.lang=state.profile.lang||'pt-BR';state.recognition.start()}catch{toast('Não foi possível iniciar o microfone.')}} function stopRecognition(){if(!state.recognition)return;try{state.recognition.onresult=null;state.recognition.stop()}catch{}state.listening=false} function initRecognition(){if(!SpeechRecognition)return null;const r=new SpeechRecognition();r.continuous=false;r.interimResults=true;r.maxAlternatives=1;r.lang=state.profile.lang||'pt-BR';r.onstart=()=>{state.listening=true;toast('Ouvindo...')};r.onerror=()=>{state.listening=false;toast('Microfone indisponível ou permissão negada.')};r.onend=()=>{state.listening=false};r.onresult=async e=>{let final='',interim='';for(let i=e.resultIndex;im.role==='assistant'))addMsg('assistant','Se quiser, eu posso criar agora um site, um app, um e-book, uma imagem, um vídeo demo ou um código pronto para copiar.',{label:'Zuna AI',tags:['início']})} boot(); })();