|
Documentação
Marcar uma demonstraçãoPlataforma
PlataformaMCPCLIAPI
Workflows
GuiasChangelog

Boas-vindas

  • Visão geral
  • Autenticação
  • Erros e códigos de estado
  • Assinaturas de webhook

Localização

  • Visão geral
  • Criar jobs
  • Bloquear chaves não traduzíveis
  • Acompanhar um grupo de jobs
  • Obter um trabalho
  • Listar tarefas
  • Entrega de webhooks
  • Progresso em tempo real (WebSocket)

Pipeline

  • Visão geral
  • Edição por IA pré-localização
  • Revisão humana
  • avaliação por IA (post-edit)
  • Reformular para soar natural
  • Verificação por retrotradução
  • Configurar o pipeline
  • Observar execuções do pipeline

Provisionamento

  • Visão geral
  • Criar uma tarefa de aprovisionamento
  • Tipos de fonte
  • O que a IA extrai
  • Entrega de webhook
  • Progresso em tempo real (WebSocket)

Síncrono

  • Localize
  • Recognize

Gestão do motor

  • Sugestões do motor

Progresso em tempo real via WebSocket

Criou um grupo de tarefas. Algures, um utilizador está a olhar para um spinner e "a traduzir para 14 idiomas…" é verdade, mas inútil — nunca avança. O que quer é ver a contagem subir à frente dele: 3 prontos, depois 4, depois um idioma com falha, e no fim concluído.

Fazer polling ao grupo de tarefas leva-o até lá, mas é ruidoso, e cada pedido devolve-lhe um novo snapshot que tem de comparar com o anterior para perceber o que realmente mudou. O WebSocket inverte isso. Liga-se uma vez e o servidor envia um evento sempre que um idioma fica resolvido — e cada mensagem inclui o estado completo do grupo, por isso apresenta o snapshot e nunca precisa de reconciliar um delta. Se perder um frame, voltar a ligar-se ou reiniciar o separador, a mensagem seguinte volta a trazer a verdade completa.

text
GET /jobs/localization/groups/:groupId/ws

Ainda não conhece a localização assíncrona? Comece pela Visão geral. O groupId aqui é o que recebeu quando criou as tarefas.

Nesta página

  • Tipos de mensagem
  • Payloads das mensagens
  • Como integrá-lo na sua interface
  • Mantenha a sua chave de API no servidor

Tipos de mensagem#

Há quatro tipos de mensagem a circular no socket. Cada um indica o que acabou de acontecer e, ao mesmo tempo, entrega o estado atual do grupo inteiro.

TipoQuandoCampos principais
snapshotNa ligação inicialEstado completo do grupo
job.completedUm idioma termina com sucessojobId, locale, mais o estado completo do grupo
job.failedUm idioma falhajobId, locale, error, mais o estado completo do grupo
group.completedTodas as tarefas foram resolvidasgroupId, status, mais o estado completo do grupo. O servidor fecha a ligação após esta mensagem.

Cada mensagem contém um objeto snapshot com o estado atual do grupo: totalJobs, completedJobs, completedWithWarningsJobs, failedJobs e um mapa jobs indexado pelo ID da tarefa, cada um com o respetivo locale e status. Estas contagens são as mesmas que o endpoint do grupo de tarefas devolve — por isso, um snapshot vindo do socket e um poll ao endpoint REST concordam sobre até onde o grupo já avançou.

apresente o snapshot, nunca reconcilie

Nunca precisa de controlar que eventos já viu, reproduzir mensagens em falta ou fundir uma atualização parcial no estado local. Leia snapshot em cada mensagem e desenhe a sua interface a partir daí. Ao voltar a ligar-se, snapshot é reenviado primeiro, por isso um cliente que acabou de entrar e outro que esteve a ouvir o tempo todo convergem para o mesmo estado.

Payloads das mensagens#

Estes são os frames exatos que o servidor envia. Os IDs têm formatos reais (ljg_ para o grupo, ljb_ para cada tarefa); o snapshot aparece abreviado com "..." apenas onde repete a estrutura já mostrada.

Ao ligar-se, o servidor envia o estado atual:

json
{
  "type": "snapshot",
  "snapshot": {
    "groupId": "ljg_A1b2C3d4E5f6G7h8",
    "totalJobs": 3,
    "completedJobs": 1,
    "completedWithWarningsJobs": 0,
    "failedJobs": 0,
    "jobs": {
      "ljb_A1b2C3d4E5f6G7h8": { "locale": "de", "status": "completed" },
      "ljb_B2c3D4e5F6g7H8i9": { "locale": "fr", "status": "processing" },
      "ljb_C3d4E5f6G7h8I9j0": { "locale": "ja", "status": "queued" }
    }
  }
}

À medida que cada idioma termina, o evento identifica o idioma que mudou e inclui o snapshot atualizado:

json
{
  "type": "job.completed",
  "jobId": "ljb_B2c3D4e5F6g7H8i9",
  "locale": "fr",
  "snapshot": {
    "groupId": "ljg_A1b2C3d4E5f6G7h8",
    "totalJobs": 3,
    "completedJobs": 2,
    "completedWithWarningsJobs": 0,
    "failedJobs": 0,
    "jobs": {
      "ljb_A1b2C3d4E5f6G7h8": { "locale": "de", "status": "completed" },
      "ljb_B2c3D4e5F6g7H8i9": { "locale": "fr", "status": "completed" },
      "ljb_C3d4E5f6G7h8I9j0": { "locale": "ja", "status": "processing" }
    }
  }
}

Uma falha é uma mensagem normal, não uma ligação interrompida. job.failed inclui o idioma e um error, além do mesmo snapshot completo — o idioma com falha mostra status: "failed" no mapa jobs, todos os outros idiomas continuam a chegar, e o socket segue até group.completed:

json
{
  "type": "job.failed",
  "jobId": "ljb_C3d4E5f6G7h8I9j0",
  "locale": "ja",
  "error": "Model timeout after 30 seconds",
  "snapshot": { "...": "..." }
}

Quando todas as tarefas tiverem sido resolvidas, o servidor envia um evento final e fecha a ligação:

json
{
  "type": "group.completed",
  "groupId": "ljg_A1b2C3d4E5f6G7h8",
  "status": "completed",
  "snapshot": { "...": "..." }
}

O status final é completed quando todos os idiomas foram concluídos com sucesso, completed_with_warnings quando todos os idiomas produziram resultado mas uma ou mais etapas opcionais do pipeline falharam em pelo menos um deles, partial quando alguns idiomas tiveram sucesso e outros falharam, e failed quando todos falharam. Para perceber o que cada um destes estados significa para o grupo como um todo, veja Acompanhar um grupo de tarefas.

Apresente a partir do snapshot sempre que encontrar algo que não reconhece

Faça switch sobre os tipos de mensagem que conhece e, para tudo o que não reconhecer, volte a apresentar a partir de snapshot. Cada mensagem inclui um snapshot completo, por isso um cliente que, por defeito, o desenha a partir daí mantém-se correto mesmo num frame para o qual não tem um ramo específico.

Como integrá-lo na sua interface#

O grupo é o seu modelo de progresso. Quando criou as tarefas, o 202 devolveu-lhe um groupId e um array jobs — uma entrada por idioma. Inicialize o seu registo de progresso a partir dessa resposta e terá a estrutura que o socket vai preencher: o total a contabilizar e um contador a começar em zero.

javascript
const { groupId, jobs } = await response.json();

await db.translationProgress.create({
  contentId: content.id,
  groupId,
  totalLanguages: jobs.length,
  completedLanguages: 0,
});

Depois, abra o socket com esse groupId e, em cada mensagem, leia snapshot e volte a desenhar. Veja o contador subir à medida que os idiomas vão ficando concluídos, e pare quando chegar group.completed:

javascript
import WebSocket from "ws";

const groupId = "ljg_A1b2C3d4E5f6G7h8";
const ws = new WebSocket(
  `wss://api.lingo.dev/jobs/localization/groups/${groupId}/ws`,
  { headers: { "X-API-Key": process.env.LINGO_API_KEY } }
);

ws.on("message", (raw) => {
  const event = JSON.parse(raw);
  const { snapshot } = event;

  switch (event.type) {
    case "snapshot":
      console.log(`${snapshot.completedJobs}/${snapshot.totalJobs} complete`);
      break;
    case "job.completed":
      console.log(`${event.locale} ready (${snapshot.completedJobs}/${snapshot.totalJobs})`);
      break;
    case "job.failed":
      console.error(`${event.locale} failed: ${event.error}`);
      break;
    case "group.completed":
      console.log(`All translations done: ${event.status}`);
      ws.close();
      break;
  }
});

Ao executar num grupo de três idiomas, isto imprime a execução à medida que acontece:

text
1/3 complete
fr ready (2/3)
ja failed: Model timeout after 30 seconds
All translations done: partial

O contador avançou sozinho, um idioma falhou sem derrubar o stream, e partial disse-lhe onde a execução terminou — exatamente o que o seu spinner precisa para se transformar numa barra de progresso a sério. Repare que o loop nunca acumula estado: cada ramo lê a partir de snapshot na mensagem em mãos, por isso o mesmo código está correto na primeira ligação, em cada atualização e ao voltar a ligar-se.

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 que os endpoints REST usam. Isto significa que o navegador é o lugar errado para o abrir — uma chave de API em JavaScript do cliente dá acesso a todos os motores da sua organização a qualquer pessoa que veja o código-fonte.

Ligue-se a partir do seu backend, não do navegador

Abra o WebSocket a partir do seu servidor, onde a chave já está, e depois distribua os eventos para o navegador através do seu próprio canal — um WebSocket ou stream de server-sent events que controla. O seu frontend recebe progresso em tempo real; a sua chave nunca sai da sua infraestrutura.

Isto espelha o modelo de webhook: a ligação que toca em Lingo.dev é do lado do servidor, e o que chega ao utilizador é aquilo que a sua própria aplicação decidir encaminhar.

Onde isto se enquadra#

O WebSocket é a vista em tempo real — está associado a um grupo e fecha quando esse grupo termina. Para uma entrega duradoura, de servidor para servidor, que sobreviva ao fecho de um separador ou a um deploy, combine-o com webhooks: o socket alimenta a interface enquanto a execução está no ecrã, o webhook regista cada resultado no momento em que chega. Ligue ambos a partir da mesma chamada de criação e os seus utilizadores veem o progresso à medida que acontece, enquanto o seu backend preserva o resultado independentemente de quem está a ver.

Entrega por webhook
Entrega duradoura, de servidor para servidor, de cada idioma à medida que fica concluído
Criar tarefas
Submeta conteúdo para tradução e obtenha o groupId ao qual se liga aqui
Acompanhar um grupo de tarefas
Estados do grupo e o que a conclusão parcial significa para o grupo

Esta página foi útil?

Max PrilutskiyMax Prilutskiy·Atualizado há 12 dias·6 min de leitura