Skip to main content

Vision Client

O VisionClient extrai dados estruturados de documentos (PDFs, imagens, etc.) utilizando layouts configurados na plataforma Tech4.ai. Use quando a action precisa processar documentos e obter campos tipados a partir deles.

Inicialização​

from actions_sdk.core.types.action_context import ActionContext
from actions_sdk.features.vision import VisionClient, VisionClientError

ctx: ActionContext

vision = VisionClient(ctx)

O VisionClient extrai ctx.vision_base_url automaticamente no construtor.

Exceções no construtor:

  • ValueError — se ctx.vision_base_url não estiver definido

Métodos​

extract(layout_id, file_url=None, file_id=None, timeout=45)​

Extrai dados estruturados de um documento com base em um layout configurado.

vision = VisionClient(ctx)
resultado = vision.extract(
layout_id="ff43427f-817c-44cc-96ee-5f85638d6ff7",
file_id="9acbfe76-9b5e-4ed2-936a-aafee99a5315",
)

print(resultado.status) # "ok", "partial" ou "nodata"
print(resultado.extracted_data) # dict com os campos extraídos

Parâmetros:

ParâmetroTipoPadrãoDescrição
layout_idstr—Obrigatório. ID do layout Vision que define os campos a serem extraídos
file_urlstr | NoneNoneURL pública do arquivo a ser analisado. Mutuamente exclusivo com file_id
file_idstr | NoneNoneID de um arquivo já enviado para a plataforma. Mutuamente exclusivo com file_url
timeoutint45Timeout em segundos (máximo: 45)
Atenção

Exatamente um entre file_url e file_id deve ser fornecido. Passar ambos ou nenhum levanta ValueError.

Retorna: VisionExtractResponse


VisionExtractResponse​

Objeto com o resultado da extração:

resultado = vision.extract(layout_id="...", file_id="...")

resultado.status # Literal["ok", "partial", "nodata"]
resultado.extracted_data # dict — campos extraídos conforme o layout

Status de Extração​

StatusSignificado
"ok"Todos os campos do layout foram extraídos com sucesso
"partial"Parte dos campos foi extraída; campos ausentes ficam com valor None ou são omitidos
"nodata"Nenhum campo pôde ser extraído do documento
Boas práticas

Sempre verifique o status antes de usar extracted_data. Com "partial" ou "nodata", trate a ausência de campos antes de prosseguir com a lógica de negócio.

Exemplos de retorno​

Extração bem-sucedida ("ok"):

resultado.status          # "ok"
resultado.extracted_data # {
# "numero_nota": "3524",
# "data_emissao": "2024-03-15",
# "valor_total": 1250.0,
# "cnpj_emitente": "12.345.678/0001-99",
# "razao_social": "Empresa Exemplo LTDA"
# }

Extração parcial ("partial"):

resultado.status          # "partial"
resultado.extracted_data # {
# "numero_nota": "3524",
# "data_emissao": None,
# "valor_total": 1250.0,
# "cnpj_emitente": None,
# "razao_social": "Empresa Exemplo LTDA"
# }

Sem dados ("nodata"):

resultado.status          # "nodata"
resultado.extracted_data # {}

Erros e Exceções​

ExceçãoQuando ocorreComo tratar
VisionClientErrorFalha na chamada à API de extração (4xx/5xx, erros de rede, respostas malformadas)Capture e retorne ResponseToAgent com ERROR
ValueErrorctx.vision_base_url não definido no construtor, ou ambos/nenhum de file_url/file_id fornecidosIndica problema de configuração do motor ou uso incorreto do método
from actions_sdk.features.vision import VisionClient, VisionClientError

try:
resultado = vision.extract(layout_id=layout_id, file_id=file_id)
except VisionClientError as erro:
return ResponseToAgent(
status=ResponseStatus.ERROR,
instruction=f"Falha na extração do documento: {erro}",
)
except ValueError as erro:
return ResponseToAgent(
status=ResponseStatus.ERROR,
instruction=f"VisionClient não disponível neste ambiente: {erro}",
)

Exemplo completo​

Baseado na action vision_extract do agente de homologação:

import traceback

from actions_sdk.core.types.action_context import ActionContext
from actions_sdk.core.types.responses import ResponseStatus, ResponseToAgent
from actions_sdk.features.conversational.state import StateManager
from actions_sdk.features.tracing import ActionSpan
from actions_sdk.features.vision import VisionClient, VisionClientError

ctx: ActionContext

CHAVE_PROGRESSO = "action.vision.progresso"


def vision_extract(file_id: str, layout_id: str):
span = ActionSpan(ctx)
state = StateManager(ctx)

span.event("action.vision.inicio", {"file_id": file_id, "layout_id": layout_id})

try:
vision = VisionClient(ctx)
resultado = vision.extract(
layout_id=layout_id,
file_id=file_id,
)

state.update(CHAVE_PROGRESSO, "SUCESSO ✓")
span.event(
"action.vision.sucesso",
{"status": resultado.status, "campos": len(resultado.extracted_data)},
)

return ResponseToAgent(
status=ResponseStatus.SUCCESS,
instruction=(
f"VisionClient.extract() concluído.\n"
f"File ID: {file_id}\n"
f"Layout ID: {layout_id}\n"
f"Status da extração: {resultado.status}\n"
f"Campos extraídos ({len(resultado.extracted_data)}): {resultado.extracted_data}"
),
state_updates=state.get_full_state(),
)

except VisionClientError as erro:
state.update(CHAVE_PROGRESSO, "FALHA ✗")
span.event("action.vision.erro", {"erro": str(erro)})
return ResponseToAgent(
status=ResponseStatus.ERROR,
instruction=f"Falha na extração do documento: {erro}",
state_updates=state.get_full_state(),
)

except ValueError as erro:
# VisionClient levanta ValueError quando ctx.vision_base_url não está configurado
state.update(CHAVE_PROGRESSO, "FALHA ✗")
span.event("action.vision.nao_configurado", {"erro": str(erro)})
return ResponseToAgent(
status=ResponseStatus.ERROR,
instruction=f"VisionClient não disponível neste ambiente: {erro}",
state_updates=state.get_full_state(),
)

except Exception as erro:
state.update(CHAVE_PROGRESSO, "FALHA ✗")
span.event("action.vision.erro_inesperado", {"erro": str(erro)})
return ResponseToAgent(
status=ResponseStatus.ERROR,
instruction=f"Erro inesperado: {traceback.format_exc()}",
state_updates=state.get_full_state(),
)