Retry Transcrição
Reprocessa uma nota que falhou na transcrição ou que você deseja transcrever novamente
Descrição
Inicia uma nova tentativa de processamento para uma nota que falhou na transcrição ou que você deseja reprocessar. Útil para casos onde:- A transcrição falhou devido a problemas temporários
- Você deseja reprocessar uma nota com melhorias na IA
- Houve problemas na qualidade da primeira transcrição
Compatibilidade: Este endpoint permite retry para notas com status
failed, completed ou pending. Não é possível fazer retry de uma nota que já está com status processing.Parâmetros da Requisição
Headers
| Header | Obrigatório | Valor |
|---|---|---|
X-API-KEY | ✅ Sim | Sua chave de API |
Content-Type | ✅ Sim | application/json |
Body (JSON)
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
note_id | UUID | ✅ Sim | ID da nota que será reprocessada |
Exemplos de Requisição
cURL
curl -X POST https://api.connectvets.com/transcripts/retry \
-H "X-API-KEY: cvn_live_abc123def456..." \
-H "Content-Type: application/json" \
-d '{
"note_id": "6a4fe1de-52c4-4b2b-a30f-4b3fa9d7d8b3"
}'
JavaScript/TypeScript
async function retryTranscription(noteId) {
const response = await fetch('https://api.connectvets.com/transcripts/retry', {
method: 'POST',
headers: {
'X-API-KEY': 'cvn_live_abc123def456...',
'Content-Type': 'application/json'
},
body: JSON.stringify({
note_id: noteId
})
});
if (!response.ok) {
throw new Error(`Erro no retry: ${response.status}`);
}
const result = await response.json();
return result;
}
// Uso
try {
const result = await retryTranscription('6a4fe1de-52c4-4b2b-a30f-4b3fa9d7d8b3');
console.log('Retry iniciado:', result.status);
console.log('URL da transcrição:', result.transcription);
} catch (error) {
console.error('Erro:', error.message);
}
Python
import requests
import json
def retry_transcription(api_key, note_id):
url = "https://api.connectvets.com/transcripts/retry"
headers = {
"X-API-KEY": api_key,
"Content-Type": "application/json"
}
data = {
"note_id": note_id
}
response = requests.post(url, headers=headers, json=data)
if response.status_code == 200:
result = response.json()
print(f"Retry iniciado para nota {note_id}")
print(f"Status: {result['status']}")
print(f"Transcrição: {result['transcription']}")
return result
else:
print(f"Erro: {response.status_code}")
print(response.text)
return None
# Uso
api_key = "cvn_live_abc123def456..."
note_id = "6a4fe1de-52c4-4b2b-a30f-4b3fa9d7d8b3"
result = retry_transcription(api_key, note_id)
Go
package main
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
)
type RetryRequest struct {
NoteID string `json:"note_id"`
}
type RetryResponse struct {
NoteID string `json:"note_id"`
Status string `json:"status"`
Message string `json:"message"`
Transcription string `json:"transcription"`
}
func retryTranscription(apiKey, noteID string) (*RetryResponse, error) {
url := "https://api.connectvets.com/transcripts/retry"
requestBody := RetryRequest{
NoteID: noteID,
}
jsonData, err := json.Marshal(requestBody)
if err != nil {
return nil, err
}
req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonData))
if err != nil {
return nil, err
}
req.Header.Set("X-API-KEY", apiKey)
req.Header.Set("Content-Type", "application/json")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
if resp.StatusCode != 200 {
return nil, fmt.Errorf("erro %d: %s", resp.StatusCode, resp.Status)
}
var result RetryResponse
err = json.NewDecoder(resp.Body).Decode(&result)
return &result, err
}
// Uso
result, err := retryTranscription("cvn_live_abc123def456...", "6a4fe1de-52c4-4b2b-a30f-4b3fa9d7d8b3")
if err != nil {
log.Fatal(err)
}
fmt.Printf("Status: %s\n", result.Status)
fmt.Printf("Mensagem: %s\n", result.Message)
Resposta de Sucesso (200 OK)
{
"note_id": "6a4fe1de-52c4-4b2b-a30f-4b3fa9d7d8b3",
"status": "processing",
"message": "Transcription retry initiated successfully",
"transcription": "https://cdn.connectvets.com/notes/6a4fe1de.txt"
}
| Campo | Tipo | Descrição |
|---|---|---|
note_id | UUID | ID da nota que está sendo reprocessada |
status | String | Novo status da nota (sempre “processing”) |
message | String | Mensagem de confirmação |
transcription | String | URL onde a nova transcrição ficará disponível |
Tratamento de Erros
400 Bad Request
{
"error": "bad_request",
"message": "Invalid note_id format",
"code": "INVALID_NOTE_ID"
}
note_idausente no corpo da requisiçãonote_idcom formato inválido (não é UUID)- Corpo da requisição malformado
400 Bad Request - Já em Processamento
{
"error": "bad_request",
"message": "transcription is already being processed",
"code": "TRANSCRIPTION_IN_PROGRESS"
}
processing e não pode ser reprocessada novamente até a conclusão.
403 Forbidden
{
"error": "forbidden",
"message": "Note does not belong to current tenant",
"code": "NOTE_ACCESS_DENIED"
}
404 Not Found
{
"error": "not_found",
"message": "Note not found",
"code": "NOTE_NOT_FOUND"
}
Casos de Uso
Retry Automático para Notas Falhadas
async function retryFailedNotes() {
// Buscar notas com status failed
const failedNotes = await listNotes({
transcription_status: 'failed'
});
console.log(`Encontradas ${failedNotes.notes.length} notas falhadas`);
const retryResults = [];
for (const note of failedNotes.notes) {
try {
const result = await retryTranscription(note.id);
retryResults.push({
noteId: note.id,
status: 'success',
newStatus: result.status
});
console.log(`✅ Retry iniciado para nota ${note.id}`);
// Aguardar um pouco entre retries
await new Promise(resolve => setTimeout(resolve, 1000));
} catch (error) {
retryResults.push({
noteId: note.id,
status: 'error',
error: error.message
});
console.error(`❌ Erro no retry da nota ${note.id}:`, error.message);
}
}
return retryResults;
}
Retry com Monitoramento
async function retryAndMonitor(noteId) {
try {
// Iniciar retry
const retryResult = await retryTranscription(noteId);
console.log(`🔄 Retry iniciado para nota ${noteId}`);
// Monitorar progresso
let status = 'processing';
let attempts = 0;
const maxAttempts = 60; // 5 minutos máximo
while (status === 'processing' && attempts < maxAttempts) {
await new Promise(resolve => setTimeout(resolve, 5000)); // 5s
const statusResult = await getNoteStatus(noteId);
status = statusResult.status;
attempts++;
console.log(`📊 Tentativa ${attempts}: Status ${status}`);
if (status === 'completed') {
console.log('✅ Retry concluído com sucesso!');
return { success: true, status };
} else if (status === 'failed') {
console.log('❌ Retry falhou novamente');
return { success: false, status };
}
}
if (attempts >= maxAttempts) {
console.log('⏰ Timeout: Retry demorou muito');
return { success: false, status: 'timeout' };
}
} catch (error) {
console.error('❌ Erro no retry:', error.message);
return { success: false, error: error.message };
}
}
Retry Inteligente com Backoff
async function intelligentRetry(noteId, maxRetries = 3) {
let attempt = 0;
while (attempt < maxRetries) {
try {
// Verificar status atual
const status = await getNoteStatus(noteId);
if (status.status === 'processing') {
console.log('⏳ Nota ainda em processamento, aguardando...');
await new Promise(resolve => setTimeout(resolve, 30000));
continue;
}
if (status.status === 'completed') {
console.log('✅ Nota já processada com sucesso');
return { success: true, alreadyCompleted: true };
}
// Iniciar retry
await retryTranscription(noteId);
console.log(`🔄 Retry ${attempt + 1}/${maxRetries} iniciado`);
// Aguardar processamento
const result = await waitForCompletion(noteId);
if (result.status === 'completed') {
console.log('✅ Retry bem-sucedido!');
return { success: true, attempt: attempt + 1 };
}
attempt++;
if (attempt < maxRetries) {
// Backoff exponencial: 2^attempt minutos
const delayMinutes = Math.pow(2, attempt);
console.log(`⏰ Aguardando ${delayMinutes} minutos antes do próximo retry...`);
await new Promise(resolve => setTimeout(resolve, delayMinutes * 60 * 1000));
}
} catch (error) {
console.error(`❌ Erro no retry ${attempt + 1}:`, error.message);
attempt++;
if (attempt < maxRetries) {
await new Promise(resolve => setTimeout(resolve, 60000)); // 1 minuto
}
}
}
console.log(`❌ Falha após ${maxRetries} tentativas`);
return { success: false, attempts: maxRetries };
}
Monitoramento após Retry
Verificação de Status
Após iniciar um retry, use o endpoint/notes/{id}/status para monitorar o progresso:
async function monitorRetry(noteId) {
console.log('📊 Monitorando retry...');
let status = 'processing';
let checkCount = 0;
while (status === 'processing') {
await new Promise(resolve => setTimeout(resolve, 10000)); // 10s
const result = await getNoteStatus(noteId);
status = result.status;
checkCount++;
console.log(`Verificação ${checkCount}: ${status}`);
if (status === 'completed') {
console.log('🎉 Retry concluído!');
break;
} else if (status === 'failed') {
console.log('💥 Retry falhou');
break;
}
// Timeout após 10 minutos
if (checkCount > 60) {
console.log('⏰ Timeout do monitoramento');
break;
}
}
return status;
}
Boas Práticas
🔄 Gestão de Retries
- Limite tentativas: Não faça retry infinitamente
- Use backoff: Aguarde entre tentativas com delay crescente
- Monitore status: Verifique se a nota já está em processamento
- Log adequadamente: Registre tentativas e resultados
⏰ Timing
- Aguarde falhas: Não faça retry imediatamente após falha
- Respeite processamento: Não tente retry em notas
processing - Use polling inteligente: Interval de 5-10s para verificar status
🚨 Tratamento de Erros
function shouldRetry(error) {
// Não retry em casos irrecuperáveis
const nonRetryableErrors = [
'NOTE_NOT_FOUND',
'NOTE_ACCESS_DENIED',
'INVALID_NOTE_ID'
];
return !nonRetryableErrors.includes(error.code);
}
async function safeRetry(noteId) {
try {
return await retryTranscription(noteId);
} catch (error) {
if (shouldRetry(error)) {
console.log('Erro temporário, pode tentar novamente');
} else {
console.log('Erro permanente, não tentar novamente');
}
throw error;
}
}
📈 Métricas
Monitore métricas importantes:- Taxa de sucesso dos retries
- Tempo médio de processamento
- Notas que falharam múltiplas vezes
- Patterns de falhas para feedback à equipe
OpenAPI
POST /transcripts/retry
openapi: 3.0.3
info:
title: ConnectVets Notes API
description: API para transcrição e análise de consultas veterinárias
version: 1.0.0
contact:
name: ConnectVets Support
email: [email protected]
url: https://connectvets.com.br
license:
name: Proprietary
url: https://connectvets.com.br/terms
servers:
- url: https://api-sandbox.connectvets.com.br/notes/v1
description: Homologação
security:
- ApiKeyAuth: []
paths:
/transcripts/retry:
post:
tags:
- Notes
summary: Reprocessar nota falhada
description: >
Reinicia o processamento de transcrição para uma nota que falhou.
**Requisito**: O retry só está disponível para notas com
`transcription_status: "failed"`.
**Rate Limiting**: Este endpoint está sujeito aos limites da sua API Key
(padrão: 100 req/min, 1000 req/hora).
operationId: retryNote
parameters:
- name: noteId
in: path
required: true
schema:
type: string
format: uuid
description: ID único da nota para reprocessar
example: 550e8400-e29b-41d4-a716-446655440000
requestBody:
required: false
content:
application/json:
schema:
type: object
description: Body vazio para reprocessamento
example: {}
responses:
'200':
description: Reprocessamento iniciado com sucesso
content:
application/json:
schema:
type: object
properties:
data:
$ref: '#/components/schemas/Note'
message:
type: string
description: Mensagem de confirmação
example: Note reprocessing started successfully
example:
data:
id: 550e8400-e29b-41d4-a716-446655440000
name: Rex
transcription_status: pending
created_at: '2024-02-14T18:25:43Z'
updated_at: '2024-02-14T19:15:30Z'
message: Note reprocessing started successfully
'400':
description: Parâmetros inválidos
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
example:
error: bad_request
message: Invalid note id format
code: INVALID_NOTE_ID
'401':
$ref: '#/components/responses/Unauthorized'
'403':
description: Permissões insuficientes
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
example:
error: forbidden
message: Note does not belong to tenant
code: NOTE_ACCESS_DENIED
'404':
$ref: '#/components/responses/NotFound'
'422':
description: Nota não pode ser reprocessada
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
examples:
not_failed:
summary: Status não é 'failed'
value:
error: unprocessable_entity
message: Note can only be retried when status is 'failed'
code: INVALID_RETRY_STATUS
details:
current_status: completed
required_status: failed
already_processing:
summary: Já está sendo processado
value:
error: unprocessable_entity
message: Note is already being processed
code: NOTE_ALREADY_PROCESSING
details:
current_status: processing
components:
schemas:
Note:
type: object
properties:
id:
type: string
format: uuid
description: ID único da nota
example: 6a4fe1de-52c4-4b2b-a30f-4b3fa9d7d8b3
name:
type: string
description: Nome do paciente
example: Rex
gender:
type: string
enum:
- male
- female
- unidentified
description: Sexo do paciente
example: male
audio_name:
type: string
description: Nome do arquivo de áudio
example: consulta_rex_20240214.wav
audio_url:
type: string
format: uri
description: URL do arquivo de áudio
example: https://cdn.connectvets.com/audio/6a4fe1de.wav
transcription_status:
type: string
enum:
- pending
- processing
- completed
- failed
description: Status da transcrição
example: completed
transcription_url:
type: string
format: uri
nullable: true
description: URL da transcrição
example: https://cdn.connectvets.com/transcriptions/6a4fe1de.txt
external_id:
type: string
nullable: true
description: ID externo do seu sistema
example: CLIENTE_123
metadata:
type: array
items:
$ref: '#/components/schemas/Metadata'
description: Metadados adicionais
created_at:
type: string
format: date-time
description: Data de criação
example: '2024-02-14T18:25:43Z'
updated_at:
type: string
format: date-time
description: Data de atualização
example: '2024-02-14T18:30:23Z'
Error:
type: object
properties:
error:
type: string
description: Código do erro
example: bad_request
message:
type: string
description: Mensagem de erro
example: Invalid audio format
code:
type: string
description: Código específico
example: INVALID_AUDIO_FORMAT
details:
type: object
description: Detalhes adicionais do erro
Metadata:
type: object
properties:
key:
type: string
description: Chave do metadado
example: procedimento
value:
type: string
description: Valor do metadado
example: vacina
responses:
Unauthorized:
description: Não autorizado
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
example:
error: unauthorized
message: API Key missing or invalid
code: INVALID_API_KEY
NotFound:
description: Recurso não encontrado
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
example:
error: not_found
message: Note not found
code: NOTE_NOT_FOUND
securitySchemes:
ApiKeyAuth:
type: apiKey
in: header
name: X-API-KEY
description: API Key para autenticação

