Criou uma tarefa de provisionamento e recebeu, em milissegundos, um ID de tarefa pjb_ e um ID de motor eng_. O motor já está pronto a usar, mas ainda está a ser preenchido: um agente de IA está a analisar as suas fontes e a escrever vozes da marca, itens de glossário e instruções. Enquanto isso acontece, quer mostrar esse progresso — uma linha do tipo "A analisar o seu guia de estilo… a configurar o motor… concluído", como num assistente de instalação, em vez de um spinner que nada explica.
O WebSocket dá-lhe exatamente esse feed. Ligue-se à tarefa e o servidor envia um snapshot do estado atual, seguido de um evento provisioning.progress sempre que o workflow avança para uma nova etapa. E, como o servidor envia o estado atual no momento da ligação e fecha logo a seguir uma tarefa terminada, pode ligar-se em qualquer altura, mesmo depois de ela terminar — não há nenhuma janela específica que tenha de apanhar.
GET /jobs/provisioning/:jobId/wsO jobId é o valor pjb_ devolvido na chamada create. Ainda está a dar os primeiros passos no provisionamento assíncrono? Comece pela Visão geral para perceber o modelo mental.
Nesta página
- Tipos de mensagem
- Snapshot ao ligar
- Eventos de progresso
- Ligar depois de a tarefa terminar
- Integrar isto na sua UI
- Mantenha a sua chave de API no servidor
Tipos de mensagem#
Há dois tipos de mensagem a circular no socket. A primeira chega uma única vez, ao ligar; a segunda chega repetidamente, à medida que a tarefa avança.
| Tipo | Quando | Campos principais |
|---|---|---|
provisioning.snapshot | Na ligação inicial | jobId, status, errorMessage |
provisioning.progress | À medida que cada etapa do workflow começa ou termina | jobId, step, detail |
Isto é um feed de atividade, não um feed de resultados: diz-lhe em que ponto está a tarefa e se falhou, não que registos a IA criou. O resumo de tudo o que foi provisionado — os IDs de voz da marca, glossário e instrução — chega em separado, no webhook de conclusão ou ao consultar a tarefa quando estiver concluída. Use o socket para a barra de progresso; use o webhook para a payload.
Snapshot ao ligar#
No instante em que estabelece ligação, o servidor lê o estado atual da tarefa na base de dados e envia-o. Não é preciso que exista primeiro um evento de progresso — o snapshot basta por si só.
{
"type": "provisioning.snapshot",
"jobId": "pjb_A1b2C3d4E5f6G7h8",
"status": "in_progress",
"errorMessage": null
}| Campo | Descrição |
|---|---|
status | in_progress, completed ou failed. |
errorMessage | A descrição da falha quando status é failed; caso contrário, null. |
O snapshot é a única mensagem que tem garantia de receber. Se a tarefa ainda estiver em execução, receberá eventos de progresso a seguir; se a tarefa já tiver terminado, receberá o snapshot e nada mais (ver abaixo).
Eventos de progresso#
À medida que o workflow decorre, o servidor difunde um evento provisioning.progress sempre que entra numa nova etapa. Cada evento indica a step e inclui uma detail legível por humanos.
{
"type": "provisioning.progress",
"jobId": "pjb_A1b2C3d4E5f6G7h8",
"step": "crawling",
"detail": "Crawling source URLs..."
}step | Quando | Exemplo de detail |
|---|---|---|
crawling | Os URLs de origem estão a ser obtidos | "Crawling source URLs..." ou "Retrying crawl (attempt 2)..." |
configuring | O agente de IA está a analisar o conteúdo e a escrever a configuração do motor | "AI agent analyzing content and configuring engine..." ou "Retrying configuration (attempt 2)..." |
completed | A tarefa terminou com sucesso | "Provisioning complete" |
failed | A tarefa falhou | Uma mensagem de erro que descreve a falha |
Uma repetição não é uma falha
As etapas crawling e configuring podem ocorrer mais do que uma vez — um erro transitório na obtenção ou análise gera uma nova tentativa, e essa tentativa surge como um evento de progresso com uma detail como "Retrying crawl (attempt 2)...". Isso significa que a tarefa está a recuperar, não que falhou. Trate apenas a etapa failed como terminal; a respetiva detail traz o motivo real.
Prepare-se para etapas que não reconhece
Podem ser acrescentados novos valores de step ao longo do tempo. Faça switch sobre as etapas que conhece, trate completed e failed como as duas que fecham o socket e ignore tudo o resto como informativo — um cliente compatível com versões futuras continua a funcionar sem precisar de atualização.
Ligar depois de a tarefa terminar#
A grande questão com qualquer socket de progresso é o que acontece se ligar tarde — depois de o crawling terminar, depois de um deploy voltar a ligar o separador, depois de a tarefa já ter falhado. Aqui, a resposta está embutida na forma como o snapshot funciona.
Se a tarefa já tiver chegado a completed ou failed, o servidor envia o snapshot com esse status final (e errorMessage, se tiver falhado) e fecha a ligação de imediato. Não há eventos de progresso para reproduzir, porque o estado final já está no snapshot. Uma tarefa ainda em curso mantém a ligação aberta e transmite progresso; uma tarefa terminada entrega-lhe o resultado e encerra.
Em qualquer dos casos, a primeira mensagem diz-lhe em que ponto está. Ligue-se em qualquer altura, mesmo depois de ela terminar — não pode ligar-se demasiado cedo nem demasiado tarde.
Integrar isto na sua UI#
Abra o socket com o ID de tarefa pjb_, leia o snapshot para definir o estado inicial e, depois, atualize-o com cada evento de progresso, fechando quando a tarefa chegar a completed ou failed:
import WebSocket from "ws";
const jobId = "pjb_A1b2C3d4E5f6G7h8";
const ws = new WebSocket(
`wss://api.lingo.dev/jobs/provisioning/${jobId}/ws`,
{ headers: { "X-API-Key": process.env.LINGO_API_KEY } }
);
ws.on("message", (raw) => {
const event = JSON.parse(raw);
switch (event.type) {
case "provisioning.snapshot":
console.log(`status: ${event.status}`);
break;
case "provisioning.progress":
console.log(`${event.step}: ${event.detail}`);
if (event.step === "completed" || event.step === "failed") {
ws.close();
}
break;
}
});Experimente com uma tarefa em que o crawling corre sem problemas e em que a configuração vai sendo mostrada passo a passo:
status: in_progress
crawling: Crawling source URLs...
configuring: AI agent analyzing content and configuring engine...
completed: Provisioning completeEsse é o fluxo completo no ecrã: a tarefa abre em in_progress, acompanha o crawling e depois a configuração, e completed diz-lhe que o motor está totalmente provisionado. O mesmo ciclo funciona numa ligação tardia — uma tarefa terminada envia um único snapshot com o status final e o socket fecha, por isso o código que trata a execução em direto também trata a repetição sem precisar de um caso especial.
Mantenha a sua chave de API no servidor#
O socket autentica-se com a sua chave de API — a mesma chave com âmbito de organização usada pelos endpoints REST. Essa chave dá acesso a todos os motores da sua organização, por isso o browser é o pior sítio para abrir a ligação: qualquer pessoa que visse o código-fonte conseguiria encontrá-la.
Ligue a partir do backend, não do browser
Abra o WebSocket a partir do seu servidor, onde a chave já está, e depois reencaminhe o progresso para o browser através de um canal seu — um WebSocket ou um stream de server-sent events sob o seu controlo. O frontend mostra o motor a configurar-se; a sua chave nunca sai da sua infraestrutura.
Isto segue a mesma lógica do modelo de webhook: a ligação que comunica com Lingo.dev corre no servidor, e o que chega ao utilizador é apenas aquilo que a sua aplicação decidir reencaminhar.
Onde isto se enquadra#
O WebSocket é a vista em direto — está associado a uma única tarefa e fecha quando essa tarefa termina. Para ter um registo duradouro, de servidor para servidor, do resultado, que sobreviva ao fecho de um separador ou a um deploy, combine-o com o webhook de conclusão: o socket alimenta a barra de progresso enquanto a tarefa está no ecrã, e o webhook entrega o resumo de tudo o que a IA criou no momento em que fica disponível. Ligue ambos a partir da mesma chamada create.
