Pynkaro

A conversa que criou o Pynkaro

O Pynkaro inteiro — app, avatar, site — foi construído numa conversa entre o Ricardo e o Claude (a IA da Anthropic), no modo Cowork do app para macOS. Esta página é o registro completo dessa conversa: as mensagens do Ricardo estão na íntegra, como foram escritas; as respostas do Claude estão condensadas ao essencial (as originais incluíam páginas de código, que estão no GitHub). Que sirva de guia e inspiração: é assim que se resolve um problema conversando.

Pré-história — 2 de fevereiro (trechos literais do histórico)

Ricardo Claude, você fala portugues?
Claude Sim! Eu falo português fluentemente. 😊 Posso te ajudar em português sem problema nenhum.
Ricardo Como eu obtenho a chave para sua API
Claude Através do Console da Anthropic: console.anthropic.com → API Keys → Create Key.

Dia 1 — Da ideia ao protótipo falante

Ricardo Quero criar um aplicativo para MacOS que seja um assistente virtual. Ele ficará ouvindo o microfone do meu MacOS e, quando eu o chamar pelo nome, digamos "Cláudio", ele passa a prestar atenção na pergunta que vou fazer, transcreve para texto, daí encaminha essa pergunta para uma inteligencia artificial, digamos o Claude, depois recebe a resposta e converte para voz. Como você planejaria tal projeto?
Claude É um pipeline de voz em 5 componentes: wake word local → captura com detecção de silêncio → transcrição (Speech framework da Apple, on-device em pt-BR) → Claude via API → texto-para-fala. Duas perguntas definem o caminho: tudo local/privado ou aceita nuvem? Swift ou Python?
Ricardo Prefiro em swift, prefiro local/privado (apenas a inteligencia articial acessada via api). Poderia montar um protótipo local? Como te dou acesso a meu diretório?
Claude [pede acesso à pasta e cria o projeto] Protótipo pronto em Swift: máquina de estados (aguardando → capturando → pensando → falando), SFSpeechRecognizer pt-BR on-device para wake word e transcrição, detecção de fim de pergunta por silêncio, e voz do sistema na resposta. Só o texto da pergunta sai do Mac.
Ricardo Funcionou muito bem. Mas a voz final achei muito mecanica, como podemos ter o resultado em uma forma mais natural?
Claude Três caminhos: baixar as vozes premium da Apple (grátis, 2 minutos), TTS neural local (Piper), ou TTS em nuvem (ElevenLabs — o mais natural). Já ajustei o código para escolher automaticamente a melhor voz instalada.
Ricardo Vamos fazer a opção 3 para soar mais natural, via ElevenLabs
Claude Integrado: o app envia o texto à ElevenLabs (modelo multilingual) e toca o áudio; se a API falhar, cai na voz do sistema. Seu áudio de microfone continua nunca saindo do Mac.
Ricardo Um outro problema é que a IA do Claude não tem acesso a internet. Isso pode ser util dependendo do que eu for perguntar. Tem como permitir tal acesso?
Claude Tem, e é simples: a API da Anthropic tem busca na web nativa, executada nos servidores deles — o Claude decide quando pesquisar. Liguei com limite de 3 buscas por pergunta.
Ricardo Por favor, configure, como default, uma voz masculina para a resposta, tanto no eleven labs quanto no default do sistema, por favor
Claude Feito: Daniel na ElevenLabs e, no sistema, filtro automático pela melhor voz masculina pt-BR instalada.

A saga da wake word

Ricardo Quero mais duas alterações na palavra de ativação. Mude de "Claudio" para "Claudiovski", porque tem menos risco de ser confundida, segundo retire o aviso sonoro de que reconheceu a palavra chave. Basta a indicação no output.
Claude Feito — com um alerta: palavra inventada pode sair transcrita de formas imprevisíveis.
Ricardo Claudiovski não ficou legal, por favor tente Clauidobot que pode ser duas palavras também "claudio bot"
Ricardo Ainda não gostei do resultado. Estou pensando em trocar para uma palavra que existe na lingua portuguesa para não ter problemas. Por favor, substitua por "Píncaro", vamos testar assim
Claude Escolha certa: palavra do dicionário (o reconhecedor a conhece), trissílaba, rara na fala cotidiana. E deixei a wake word configurável sem recompilar — três trocas já mostravam o padrão.
Ricardo Pincaro ficou bom. Um outro problema que estou tendo é que quando pergunto as horas ele diz que não tem acesso a um relógio. Mas ele tem acesso a internet. É só perguntar que horas são na internet. Tem como corrigir isso?
Claude Para hora local nem precisa de internet: o Mac já sabe. Injetei data, hora e fuso no prompt de sistema a cada pergunta — horas de outros lugares ele calcula pela diferença de fuso.

Personalidade

Ricardo É possível pedir também uma resposta mais informal, coloquial e talvez até com algum humor?
Ricardo Ótimo, agora altere a voz padrão do elevenlabs para Lutz - Chuckling, Giggly and Cheerful
Ricardo Alterei a voz default diretamente no código, para uma criada por mim lá no ElevenLabs. Gostaria agora que você limitasse a resposta da inteligencia artificial a uma frase apenas de, no máximo 60 palavras. Respostas muito grandes atrapalham o fluxo do vídeo.
Ricardo Quero uma outra alteração: Geralmente minhas perguntas são objetivas. Quando eu começar minha pergunta com "Na sua opinião, ..." entenda que não quero nenhuma grande pesquisa nem opinião fundamentada, quero apenas uma opinião engraçada. Seja exagerado, escolha um lado aleatoriamente e, se for o caso, coloque um argumento maluco.
Claude Tudo no prompt de sistema: tom de amigo brasileiro com humor como tempero, regra estrita de uma frase (máx. 60 palavras), e o "modo opinião" — lado aleatório, convicção total, argumento absurdo. A voz Lutz (risonha) combinou com a persona.

Vira projeto de verdade: Pynkaro

Ricardo Eu gostaria de mudar o nome do nosso projeto de "Claudio" para "Pynkaro" e movê-lo para um diretório de um novo repositório que criei no github
Ricardo Gostaria que as chaves da Anthropic e da ElevenLabs fossem colocadas em um arquivo de configuração a parte para não serem enviadas em commit para o github, não quero ter que usar variaveis de ambiente para isso
Claude Projeto renomeado e migrado (pacote, persona, variáveis), e as chaves foram para um config.json no .gitignore, com um config.example.json como modelo para quem clonar.

O avatar ganha vida

Ricardo [envia a imagem do fennec] Eu quero agora que o assistente tem uma imagem visual, um avatar na tela do meu mac, não precisa, num primeiro momento, sincronizar a voz, mas ele deve aparecer quando for chamado e depois sumir. Como poderiamos fazer isso? Segue sugestão de como seria o avatar
Claude Janela flutuante sem borda e transparente no canto da tela, que ignora cliques: aparece com fade na wake word e some quando a resposta termina.
Ricardo Ficou bom, mas gostaria que ficasse maior, 2.5x o tamanho atual
Ricardo Agora como poderiamos fazer para ele mover os lábios ao ler a resposta? Imagino que teriamos que usar alguma api para renderização de vídeo... não quero que faça nada ainda, apenas me aponte como poderia ser feito
Claude Nada de vídeo! Quatro opções, da mais simples à mais cara: (1) "boca de muppet" — o volume do áudio troca 3 sprites de boca; (2) visemas por timestamps da ElevenLabs; (3) rig 2D (Live2D/Rive); (4) vídeo gerado por IA — inviável em tempo real.
Ricardo Ok, pode começar com o 1
Ricardo Quero que o avatar apareça subindo de baixo para cima, quando chamado. Na hora de ir embora pode ficar como esta.
Ricardo Alguma coisa não funcionou... ele apenas apareceu como estava antes
Claude Culpa minha: animar o frame de uma janela via animator ignora o NSAnimationContext do macOS. Refiz do jeito confiável — a janela fica fixa e quem sobe é a view da imagem dentro dela, com recorte. Lição de AppKit registrada no projeto.
Ricardo Vamos tentar o item 2 de visemas por timestamp?
Claude O endpoint with-timestamps da ElevenLabs devolve o instante de cada caractere falado. Cada letra vira boca: A aberta, O/U arredondada, M/B/P fechada, F/V nos dentes; pausas fecham a boca. Um timer a 60 fps segue o relógio do áudio — e se algo faltar, degrada para o modo por volume, depois para a voz do sistema.

O programa de notícias

Ricardo Ficou bom sim! Quero uma outra alteração agora, quando o programa iniciar ele deve perguntar o nome de quem sugeriu a notícia (que será a notícia que ele vai me ajudar a comentar), eu vou digitar dois nomes, um por linha. Quando eu perguntar "Pinkaro, quem sugeriu essas notícias?" ele deve responder "Essas notícias foram sugeridas por ..." e dai os dois nomes que eu informei no início e depois complementar com " e várias outras pessoas"
Ricardo Preciso de mais uma interação específica. Quando eu perguntar para o Pincaro o que ele acha do pessoal que sugeriu a notícia hoje, ele deve responder fazendo uma pequena crítica bem humorada dos nomes das pessoas que sugeriram as notícias
Claude Regras no prompt: "quem sugeriu?" tem resposta fixa com os nomes + "e várias outras pessoas"; "o que você acha deles?" gera zoeira leve e afetuosa, improvisada a cada vez. Os nomes depois viraram uma janelinha no app, e o histórico passou a reiniciar quando eles mudam — o modelo insistia nos nomes antigos que ele mesmo já tinha falado.

De protótipo a aplicativo (e um site no caminho)

Ricardo Acho que nossa prova de conceito está concluida. O próximo passo é transformar isso num aplicativo real, com um icone, uma janela bonitinha. Como podemos fazer isso? Não faça ainda, apenas me indique o que pretende fazer.
Ricardo Talvez fosse melhor começar por um outro lado. Quero fazer um site para o Pynkaro com uma landing page bacana, baseada na imagem dele. Já até reservei o site pynkaro.com para isso.
Claude Repositório separado, site estático sem framework, GitHub Pages com domínio próprio — é esta página que você está lendo.
Ricardo Voltando ao projeto original do assistente, vamos implementar as duas primeiras etapas da transformação em um aplicativo de verdade
Claude O terminal deu lugar a um app de menu bar: a orelha no topo da tela muda conforme o estado (ouvindo/pensando/falando), com menu de pausa e configurações, e um script que monta o Pynkaro.app com permissões e assinatura.
Ricardo Ele não dá nenhum erro. Chega a criar o Pynkaro.app mas quando mando o open simplesmente nada acontece. Ele deveria abrir uma janela ou algo assim, certo?
Claude Não — app de menu bar não abre janela; o sinal de vida é o ícone perto do relógio. Mas o ícone realmente não aparecia: o MenuBarExtra do SwiftUI falhou em silêncio. Troquei pelo NSStatusItem clássico do AppKit e funcionou de primeira.
Ricardo Eu tenho 2 monitores. O avatar está aparecendo no monitor errado. Como posso fazer para configurar isso?
Claude Menu novo: "Tela do avatar", com a lista dos seus monitores e um ✓ no escolhido.

O melhor bug da história

Ricardo Algo aconteceu com o Pynkaro... ele não está recebendo a pergunta... o que pode estar acontecendo?
Claude Diagnóstico em etapas: permissões ok, wake word ok... adicionei um print do que o reconhecedor ouve. E o log entregou: "📝 Ouvido: Píncaro" e depois "📝 Ouvido: Qual" — após uma pausa, o reconhecedor finaliza a frase da wake word e recomeça a transcrição do zero. A wake word sumia do texto e a pergunta era descartada. Por isso o comportamento parecia aleatório: dependia de você fazer pausa ou não. Corrigido: sem wake word no texto durante a captura, o texto inteiro é a pergunta.
Ricardo Testei aqui e ficou ótimo! Inclusive as legendas

Últimos retoques

Ricardo Acho que seria interessante que a minha pergunta e a resposta do pincaro aparecessem na tela no caso do aplicativo. Talvez como uma "legenda" debaixo do avatar.
Ricardo Algumas vezes eu falo a palavra Pynkaro ativando ele só que falei sem querer. Será que poderia haver uma segunda palavra chave tipo "esquece" ou "deixa pra lá" para fazer ele sumir sem responder a pergunta alguma?
Ricardo Outro ponto é menos importante... há uma distância entre o avatar e o fundo da tela, tem como zerar essa distância?
Claude Legenda ao vivo em pílula translúcida (mostra sua fala sendo transcrita e depois a resposta), frases de cancelamento ("esquece", "deixa pra lá", "cancela") que fazem o avatar sumir em silêncio, e o fennec colado na borda física da tela. E, por fim, esta página — a conversa completa, para inspirar quem quiser construir algo assim. 🦊