Visão geral

Como instalar o Tolky Voice Widget no seu site ou aplicação web. O visitante conversa por voz com o avatar; a integração segue o mesmo espírito do Minichat: poucas linhas no HTML e o canal fica disponível. O namespace público é window.tolkyVoice (distinto de window.tolky do Minichat) para permitir os dois widgets na mesma página.

Objetivo da integração

O Tolky Voice Widget permite que qualquer site ofereça um canal de conversa por voz com um assistente inteligente da Tolky. O visitante fala e recebe uma resposta falada, natural e contextualizada.

  • Conversa por voz bidirecional — o visitante fala e ouve a resposta, sem precisar digitar
  • Contexto do negócio — o assistente busca informações relevantes do cliente via embeddings semânticos
  • Sessão contínua — o histórico da conversa é mantido durante a sessão do visitante
  • Fallback para texto — se houver falha no áudio, a resposta é exibida em texto

Com pipeline: 'backend' (padrão), o histórico e a persistência seguem o backend Tolky (pushToConversation e o fluxo de conversa na infraestrutura Tolky).

Pré-requisitos

RequisitoDescrição
Conta TolkyConta ativa com pelo menos um host e slug configurado
Origem autorizadaO domínio do site deve estar registrado no painel Tolky
HTTPSO site deve ser servido via HTTPS (obrigatório para acesso ao microfone)
Navegador compatívelNavegadores Chromium (Chrome, Edge, Opera, Brave) 90+ — veja Compatibilidade de navegador

Transporte em tempo real (WebSocket)

A comunicação em tempo real entre o widget e o backend Tolky usa WebSocket, via Socket.IO no namespace /tolky-speech. Esse canal transmite atualizações mínimas de contexto dinâmico (por exemplo contextVersion, metadados e referência a snapshot); o texto completo do contexto não trafega no socket.

O visitante da página não configura URL de WebSocket no snippet: o widget negocia a ligação com a infraestrutura Tolky. Quem integra apenas o script precisa garantir que o navegador possa abrir ligações wss: para os hosts Tolky usados pelo widget (podem coincidir com voice.tolky.to ou outro host exposto pelo proxy; veja a seção Boas práticas de segurança nesta página, incluindo CSP).

Código de instalação

O objetivo é o mesmo do guia do Minichat: poucas linhas copiadas para o HTML e o canal já fica disponível no site.

Adicionando estilos

No Minichat, inclui-se um <link> para uma folha de estilos hospedada na Tolky. No widget de voz isso não é necessário para o caso básico: os estilos da interface vêm no próprio widget.js (injetados em tempo de execução). Não é obrigatório adicionar <link rel="stylesheet" …> para o funcionamento padrão.

Adicionando funcionalidades

Coloque o código antes do fechamento da tag </body>.

Recomendado (uma linha): o slug do host vai no atributo data-slug da tag que carrega o script. O widget localiza essa tag (compatível com async) e combina a configuração com window.tolkyVoice, se existir.

<script src="https://voice.tolky.to/widget.js" data-slug="SLUG_DO_AVATAR" async></script>
  • SLUG_DO_AVATAR: apelido do avatar / host, como em https://tolky.to/slug_do_avatar
  • Opcionalmente: ?slug=SLUG_DO_AVATAR na URL do src se preferir query string; se existir data-slug, ele tem prioridade sobre ?slug=

Alternativa em duas linhas (mesmo espírito do Minichat: configuração inline + script externo):

<script>window.tolkyVoice=window.tolkyVoice||{config:{slug:"SLUG_DO_AVATAR"}};</script>
<script src="https://voice.tolky.to/widget.js" async></script>

Observações:

  • O namespace público é window.tolkyVoice (não window.tolky), para coexistir com o Minichat na mesma página
  • async evita bloquear a renderização da página
  • Se definir tanto window.tolkyVoice.config quanto atributos na tag do widget.js, os valores em window.tolkyVoice.config prevalecem (útil para callbacks e sobrescritas pontuais)

Atributos opcionais na tag <script src="…widget.js">

AtributoValoresDescrição
data-slugstringIdentificador do host (obrigatório via tag se não usar window.tolkyVoice.config.slug nem ?slug=)
data-sub-slugstringAvatar específico do host
data-positionbottom-right, bottom-leftPosição do botão
data-pipelinebackend, localMesmo significado da propriedade pipeline na tabela abaixo
data-auto-greetingtrue, falseSaudação em áudio ao abrir o painel

Parâmetros de query no src (além de slug e subSlug): podem complementar; data-* na mesma tag tem precedência sobre a query quando ambos definem o mesmo campo.

Configurações

Propriedades de configuração

PropriedadeTipoObrigatórioPadrãoDescrição
slugstringSimIdentificador do host no ecossistema Tolky
subSlugstringNãonullSeleciona um avatar específico do host
languagestringNão"pt-BR"Idioma preferencial (v1 suporta apenas pt-BR)
positionstringNão"bottom-right"Posição do botão: "bottom-right" ou "bottom-left"
pipelinestringNão"backend""backend": sessão e raciocínio Tolky via infraestrutura (produção). "local": apenas conversa e TTS neste serviço (demo/desenvolvimento sem backend-service)
autoGreetingbooleanNãofalseSe true, reproduz saudação em áudio ao abrir o painel do widget
greetingTextstringNão(texto fixo pt-BR)Texto da saudação quando autoGreeting é true
apiBaseUrlstringNãoorigem do scriptBase URL HTTP do BFF (ex.: https://voice.tolky.to). Normalmente inferida a partir da tag <script>; só precisa definir para apontar a um deployment custom/staging
socketBaseUrlstringNãoheurística sobre apiBaseUrlURL do Socket.IO (ex.: wss://api.tolky.to). Se omitida, é derivada de apiBaseUrl

Callbacks

CallbackAssinatura (TypeScript)Descrição
onReady() => voidWidget carregado e pronto para uso
onListening() => voidWidget começou a capturar áudio do usuário
onTranscript(data) => void com data.textTranscrição da fala do usuário disponível
onResponse(data) => void com data.text e data.audioResposta do assistente recebida
onError(data) => void com data.code e data.messageErro ocorrido
onSessionStart(data) => void com data.sessionIdSessão iniciada
onSessionEnd() => voidSessão encerrada

Exemplo com callbacks

<script>
  window.tolkyVoice = window.tolkyVoice || {
    config: {
      slug: 'meu-slug',
      position: 'bottom-right',
      onReady: function () {
        console.log('Widget de voz pronto');
      },
      onTranscript: function (data) {
        console.log('Usuário disse:', data.text);
      },
      onResponse: function (data) {
        console.log('Assistente respondeu:', data.text);
      },
      onError: function (err) {
        console.error('[TolkyVoice]', err.code, err.message);
      }
    }
  };
</script>
<script src="https://voice.tolky.to/widget.js" async></script>

Inicialização

Fluxo de carregamento

1. Página carrega o script widget.js
2. Script resolve o slug: window.tolkyVoice.config, depois atributos/query na tag do widget.js
   └── Se não houver slug → widget não é renderizado
3. Widget cria uma sessão no backend
4. Widget estabelece a ligação em tempo real via WebSocket (Socket.IO /tolky-speech) quando aplicável
5. Widget busca a configuração do host (avatar, voz, contexto)
6. Botão de voz é renderizado na posição configurada
7. Callback onReady é disparado

Métodos públicos

Após a inicialização, os seguintes métodos ficam disponíveis em window.tolkyVoice:

// Abre o painel do widget
window.tolkyVoice.open();

// Fecha o painel do widget (botão permanece visível)
window.tolkyVoice.close();

// Inicia captura de voz manualmente
window.tolkyVoice.start();

// Para captura de voz
window.tolkyVoice.stop();

// Remove o widget completamente do DOM
window.tolkyVoice.destroy();

Eventos principais

Os eventos são recebidos via callbacks definidos no objeto de configuração.

Ciclo de vida de uma interação por voz

onReady
  └── Usuário clica no botão
        └── onListening
              └── Usuário fala
                    └── onTranscript (texto: "Quais são os planos disponíveis?")
                          └── Assistente processa
                                └── onResponse (texto + áudio)

Ciclo de vida de uma sessão

onSessionStart (sessionId: abc-123)
  └── (interações de voz)
        └── onSessionEnd

Tratamento de erros

window.tolkyVoice = {
  config: {
    slug: 'meu-slug',
    onError: function (err) {
      switch (err.code) {
        case 'MIC_PERMISSION_DENIED':
          alert('Por favor, permita o acesso ao microfone.');
          break;
        case 'NETWORK_ERROR':
          alert('Verifique sua conexão com a internet.');
          break;
        default:
          console.error('[TolkyVoice]', err.code, err.message);
      }
    }
  }
};

Boas práticas de segurança

  1. Registre a origem do site no painel Tolky antes de publicar. Requisições de domínios não autorizados serão bloqueadas com erro ORIGIN_DENIED.

  2. Nunca exponha tokens ou credenciais no código frontend. O widget se autentica automaticamente pela origem do domínio — nenhum token é necessário no snippet de integração.

  3. Sirva o site via HTTPS. O acesso ao microfone (getUserMedia) exige contexto seguro. Em HTTP, o navegador bloqueia o acesso ao áudio.

  4. Não armazene dados sensíveis em localStorage ou cookies criados pelo widget. O widget gerencia sua própria sessão internamente.

  5. Content Security Policy (CSP). Se o site utiliza CSP, adicione as seguintes diretivas (incluindo wss: para o canal WebSocket do widget):

script-src 'self' https://voice.tolky.to;
connect-src 'self' https://voice.tolky.to wss://voice.tolky.to;
media-src 'self' https://voice.tolky.to;

Se o ambiente Tolky apontar o Socket.IO para outro domínio, inclua também https:// e wss:// desse domínio em connect-src.

Mensagens de erro comuns

CódigoMensagemCausa provávelSolução
SLUG_NOT_FOUNDSlug não encontradoSlug inválido ou não configurado no painelVerificar o slug no painel Tolky
ORIGIN_DENIEDOrigem não autorizadaDomínio do site não registradoAdicionar o domínio nas origens autorizadas no painel
MIC_PERMISSION_DENIEDPermissão de microfone negadaUsuário negou o acesso ao microfoneOrientar o visitante a permitir o microfone nas configurações do navegador
MIC_NOT_AVAILABLEMicrofone não disponívelDispositivo sem microfone ou hardware em usoVerificar se o dispositivo possui microfone funcional
NETWORK_ERRORErro de conexãoFalha de rede entre o navegador e o backendVerificar a conexão do visitante
TTS_UNAVAILABLEServiço de voz indisponívelEngine de síntese de voz temporariamente foraTentar novamente em alguns instantes
SESSION_EXPIREDSessão expiradaSessão inativa por tempo prolongadoNo pipeline backend, o widget renova a sessão automaticamente e repete o pedido de raciocínio uma vez antes de propagar o erro para onError
TEXT_TOO_LONGTexto excede limiteResposta do assistente acima de 5 000 caracteresContatar o suporte Tolky

Compatibilidade de navegador

A primeira versão do widget de voz usa a Web Speech API nativa do Chromium para speech-to-text (STT), detectada via window.SpeechRecognition || window.webkitSpeechRecognition.

NavegadorMotorSTT suportado
Google Chrome (desktop / Android)ChromiumSim
Microsoft EdgeChromiumSim
OperaChromiumSim
BraveChromiumSim
Safari (macOS / iOS)WebKitNão
FirefoxGeckoNão

iOS: todos os navegadores no iOS utilizam o motor WebKit. Chrome, Edge e Opera no iOS não suportam a Web Speech API para STT.

Quando o navegador não suporta a Web Speech API, o botão de microfone fica desabilitado e um aviso é exibido; o ciclo completo de conversa por voz não fica disponível nesse ambiente.

O STT do Chromium pode enviar áudio para infraestrutura do Google. Exige conexão com a internet e está sujeito aos termos do serviço do provedor.

Limitações da primeira versão

A versão inicial cobre o ciclo completo de conversa por voz. Os itens abaixo estão previstos para versões futuras e não fazem parte da v1:

  • Idioma: apenas português brasileiro (pt-BR)
  • Personalização visual: sem suporte a temas, cores ou posicionamento customizado além de bottom-right / bottom-left
  • Modo offline: requer conexão com a internet
  • Avatar animado: sem representação visual animada durante a conversa
  • Interrupção de fala (barge-in): não é possível interromper a resposta do assistente no meio
  • Ativação por voz (wake word): ativação apenas por clique no botão
  • Multimodal: sem alternância entre voz e texto na mesma sessão
  • Analytics embarcados: métricas de uso não são expostas no widget