Skip to main content

File Management

Visão Geral

O File Management oferece funcionalidades simplificadas para upload e gerenciamento de arquivos dentro das actions. O módulo automaticamente gerencia as informações de contexto (client_slug, session_id) e retorna IDs únicos para posterior acesso aos arquivos.

Objetivo Principal

  • Upload flexível: Aceita URL ou bytes de arquivos e retorna ID único
  • Dupla modalidade: Upload via URL (externo) ou bytes (gerado/processado)
  • Integração nativa: Funciona com ResponseToUser e ResponseToAgent
  • Suporte a webhooks: Retorno estruturado na API v2
  • Compatibilidade: Funciona também na v1 usando apenas o ID

📤 Método Principal

upload_file(file_url=None, file_bytes=None, filename=None)

Faz upload de um arquivo a partir de uma URL ou bytes e retorna um ID único para acesso posterior.

Parâmetros:

  • file_url (str, opcional): URL do arquivo a ser baixado e salvo
  • file_bytes (bytes, opcional): Conteúdo do arquivo em bytes
  • filename (str, opcional): Nome do arquivo (necessário quando usando file_bytes)

Validação:

  • Pelo menos file_url OU file_bytes deve ser fornecido
  • Quando usar file_bytes, é recomendado fornecer filename

Quando utilizar:

  • Com URL: Processar arquivos de APIs externas, links públicos
  • Com bytes: Arquivos gerados dinamicamente, conteúdo processado, uploads diretos
  • Armazenar comprovantes ou anexos
  • Preparar arquivos para download posterior

Resultado esperado:

  • UUID: ID único do arquivo salvo
  • Arquivo fica disponível para download usando esse ID
  • Contexto automaticamente extraído da action (client_slug, session_id)

Exemplos básicos:

# Opção 1: Upload a partir de URL (método original)
file_url = "https://example.com/documents/contrato.pdf"
file_id = actions_sdk.upload_file(file_url=file_url)

# Opção 2: Upload a partir de bytes
file_bytes = generate_pdf_content() # Seus bytes do arquivo
filename = "contrato_gerado.pdf"
file_id = actions_sdk.upload_file(file_bytes=file_bytes, filename=filename)

print(f"Arquivo salvo com ID: {file_id}")

🔗 Integração com Respostas Estruturadas

Classe FileContent

Representa metadados de um arquivo para uso em respostas.

Parâmetros:

  • fileId (str): Obrigatório - ID único retornado pelo upload_file()
  • fileName (str): Nome do arquivo para exibição (opcional)
  • fileType (str): Tipo do arquivo ("document", "image", etc.) (opcional)
  • fileSize (int): Tamanho em bytes (opcional)

Fluxo Completo: Upload → Resposta

Exemplo 1: Upload via URL (Método Original)

# 1. URL do arquivo recebida
file_url = "https://teste.net/temp/cnh/teste.pdf"

# 2. Upload do arquivo usando actions_sdk
file_id = actions_sdk.upload_file(file_url=file_url)

# 3. Criar objeto FileContent com metadados
file_content = actions_sdk.FileContent(
fileId=str(file_id),
fileName="proposta.pdf",
fileType="document",
fileSize=None # Opcional se não souber o tamanho
)

# 4. Retornar resposta estruturada com arquivo anexado
response = actions_sdk.ResponseToUser(
status=actions_sdk.ResponseStatus.SUCCESS,
message="Documento processado e salvo com sucesso!",
files=[file_content], # Lista de arquivos
instruction="Documento salvo no sistema para posterior consulta"
)

return response

Exemplo 2: Upload via Bytes

# 1. Gerar ou obter conteúdo do arquivo em bytes
file_bytes = generate_digital_card_content() # Seus bytes do arquivo
filename = "cartao_digital.pdf"

try:
# 2. Upload do arquivo usando file_bytes
file_id = actions_sdk.upload_file(file_bytes=file_bytes, filename=filename)

# 3. Criar objeto FileContent com metadados completos
file_content = actions_sdk.FileContent(
fileId=str(file_id),
fileName=filename,
fileType="document",
fileSize=len(file_bytes) # Tamanho conhecido dos bytes
)

# 4. Log do evento para rastreamento
action_span.event("enviar_arquivo", {
"file_id": str(file_id)
})

# 5. Retornar resposta de sucesso
return actions_sdk.ResponseToUser(
status=actions_sdk.ResponseStatus.SUCCESS,
message="Cartão digital processado e salvo com sucesso!",
files=[file_content],
instruction="Cartão digital salvo no sistema para download"
)

except Exception as e:
# 6. Tratamento de erro
return actions_sdk.ResponseToAgent(
instruction="Informe ao cliente que não foi possível obter o cartão digital e peça para ele tentar novamente mais tarde.",
state_updates={
"error_msg": str(e)
},
status=actions_sdk.ResponseStatus.ERROR,
detail=str(e)
)

Resultado na API v2

O exemplo acima gera automaticamente um objeto estruturado no webhook da rota add_message_v2:

{
"content": [
{
"type": "text",
"text": {
"body": "Documento processado e salvo com sucesso!"
}
},
{
"type": "document",
"document": {
"id": "12345678-1234-5678-9012-123456789012"
}
}
]
}

Estrutura do retorno:

  • Mensagem de texto: {"type": "text", "text": {"body": "mensagem"}}
  • Arquivo document: {"type": "document", "document": {"id": "file_id"}}
  • Arquivo audio: {"type": "audio", "audio": {"id": "file_id"}} (para MP3, WAV, MP4)

🔄 Compatibilidade e Métodos de Upload

Métodos de Upload Disponíveis

1. Upload via URL (Método Original)

# Para arquivos disponíveis via URL pública
file_id = actions_sdk.upload_file(file_url="https://example.com/file.pdf")

2. Upload via Bytes

# Para conteúdo gerado dinamicamente ou bytes diretos
file_id = actions_sdk.upload_file(
file_bytes=pdf_bytes,
filename="documento.pdf"
)

3. Upload Híbrido (Flexível)

# O método detecta automaticamente qual parâmetro usar
def upload_flexible(url=None, content=None, name=None):
if url:
return actions_sdk.upload_file(file_url=url)
elif content:
return actions_sdk.upload_file(file_bytes=content, filename=name)
else:
raise ValueError("Forneça URL ou bytes do arquivo")

Compatibilidade da API

API v2 (Recomendada)

  • Retorno nativo: Objeto files estruturado no webhook
  • Metadados completos: fileName, fileType, fileSize disponíveis
  • Suporte completo: Funciona com URL e bytes
  • Tipagem consistente: Sempre retorna estrutura padronizada

API v1 (Compatível)

  • ID disponível: Pode usar o UUID retornado pelo upload_file()
  • Sem retorno nativo: Não há campo files automático no webhook
  • Implementação manual: Precisa gerenciar metadados do arquivo manualmente
  • Funciona com ambos métodos: URL e bytes
# Compatibilidade v1 - usando bytes
file_id = actions_sdk.upload_file(file_bytes=content, filename="arquivo.pdf")

# Retornar ID na resposta (desenvolvimento manual do cliente)
response = actions_sdk.ResponseToAgent(
status=actions_sdk.ResponseStatus.SUCCESS,
instruction="Arquivo salvo com sucesso.",
metadata={"file_id": str(file_id), "filename": "arquivo.pdf"}
)

⚠️ Considerações Importantes

Extração Automática de Contexto

  • client_slug e session_id são automaticamente extraídos do contexto da action
  • Não é necessário passar esses parâmetros manualmente

Limitações

  • URL deve estar acessível publicamente (apenas para file_url)
  • Tamanho do arquivo limitado em 50MB
  • Validação de parâmetros: Pelo menos file_url OU file_bytes deve ser fornecido

Boas Práticas

# ✅ Excelente - Upload com bytes e metadados completos
def upload_generated_file(content: bytes, name: str):
file_id = actions_sdk.upload_file(
file_bytes=content,
filename=name
)

return actions_sdk.FileContent(
fileId=str(file_id),
fileName=name, # Nome descritivo
fileType="document", # Tipo claro
fileSize=len(content) # Tamanho exato conhecido
)

# ✅ Bom - Upload com URL e metadados completos
file_content = actions_sdk.FileContent(
fileId=str(file_id),
fileName="Contrato_Assinado.pdf", # Nome descritivo
fileType="document", # Tipo claro
fileSize=1024000 # Tamanho se conhecido
)

# ❌ Evitar - Apenas ID mínimo (funciona, mas menos informativo)
file_content = actions_sdk.FileContent(fileId=str(file_id))

# ✅ Excelente - Validação robusta para ambos métodos
def safe_upload_flexible(file_url=None, file_bytes=None, filename=None):
try:
if file_bytes and filename:
return actions_sdk.upload_file(
file_bytes=file_bytes,
filename=filename
)
elif file_url:
return actions_sdk.upload_file(file_url=file_url)
else:
raise ValueError("Forneça file_url OU (file_bytes + filename)")

except Exception as e:
logger.error(f"Erro no upload: {e}")
return None

# ✅ Bom - Tratamento de erro com ResponseToAgent
def handle_upload_with_error_handling(file_bytes: bytes, filename: str):
try:
file_id = actions_sdk.upload_file(
file_bytes=file_bytes,
filename=filename
)

file_content = actions_sdk.FileContent(
fileId=str(file_id),
fileName=filename,
fileType="document",
fileSize=len(file_bytes)
)

return actions_sdk.ResponseToUser(
status=actions_sdk.ResponseStatus.SUCCESS,
message="Arquivo processado com sucesso!",
files=[file_content],
instruction="Arquivo salvo no sistema"
)

except Exception as e:
return actions_sdk.ResponseToAgent(
instruction="Informe que houve erro no upload e peça para tentar novamente.",
status=actions_sdk.ResponseStatus.ERROR,
detail=str(e)
)
Novos Recursos

Upload via Bytes: Agora você pode fazer upload direto de conteúdo em bytes, ideal para:

  • Arquivos gerados dinamicamente (PDFs, imagens, documentos)
  • Conteúdo processado em memória
  • Integração com APIs que retornam bytes
  • Upload direto sem necessidade de URLs públicas
Integração Automática

O File Management extrai automaticamente client_slug e session_id do contexto da action, não sendo necessário gerenciar esses parâmetros manualmente.

Limitações Importantes
  • URLs devem estar publicamente acessíveis (apenas para file_url)
  • Tamanho máximo de 50MB por arquivo
  • Pelo menos um parâmetro obrigatório: file_url OU file_bytes deve ser fornecido
  • Filename recomendado: Ao usar file_bytes, forneça filename para melhor identificação

📥 Fluxo de Upload Externo e Acesso em Actions

Este fluxo documenta como arquivos enviados via API v2 ficam disponíveis para serem acessados e manipulados dentro de actions.

Visão Geral do Fluxo

O processo completo envolve três etapas principais:

  1. Upload via API: Arquivo é enviado através do endpoint /admin/v2/files/upload
  2. Mensagem Document: Arquivo é adicionado ao state através de mensagem tipo document
  3. Acesso na Action: Action lê os dados do arquivo do state e pode gerar URLs de download

1️⃣ Upload do Arquivo via API

Endpoint

POST /admin/v2/files/upload

Exemplo de Request

curl --request POST \
--url https://api.tech4.ai/admin/v2/files/upload \
--header 'Content-Type: application/json' \
--header 'x-client-key: YOUR_API_KEY' \
--data '{
"session_id": "c599ba4e-3805-4a37-8a71-8a8008ca0a47",
"file_url": "https://storage.example.com/temp/document.pdf"
}'

Response

{
"file_id": "6c4f8a50-8c1c-4809-bfb8-a1d8e6318896",
"detail": "File uploaded successfully"
}

2️⃣ Envio da Mensagem com Documento

Após o upload, para que o arquivo seja adicionado ao state da sessão, é necessário enviar uma mensagem do tipo document:

Endpoint

POST /admin/v2/conversation/{session_id}/message

Exemplo de Request

curl --request POST \
--url https://api.tech4.ai/admin/v2/conversation/c599ba4e-3805-4a37-8a71-8a8008ca0a47/message \
--header 'Content-Type: application/json' \
--header 'x-client-key: YOUR_API_KEY' \
--data '{
"type": "document",
"text": null,
"document": {
"id": "6c4f8a50-8c1c-4809-bfb8-a1d8e6318896",
"url": null,
"caption": "Documento para análise"
}
}'

Processo Interno

  1. O método interno extract_files_from_request identifica o arquivo pelo ID no campo document.id
  2. Busca os dados completos do arquivo na tabela uploaded_files
  3. Adiciona os dados completos à chave files no state da sessão

3️⃣ Estrutura dos Dados no State

Após o envio da mensagem do tipo document, os dados do arquivo ficam disponíveis no state da sessão na chave files:

{
"files": [
{
"caption": "Documento para análise",
"file_id": "6c4f8a50-8c1c-4809-bfb8-a1d8e6318896",
"file_name": "document.pdf",
"file_size": 2048576,
"file_type": "document",
"uploaded_at": "2025-11-03T22:06:35.241038+00:00",
"file_extension": ".pdf"
}
]
}

Campos disponíveis:

  • file_id: UUID único do arquivo
  • file_name: Nome original do arquivo
  • file_size: Tamanho em bytes
  • file_type: Tipo detectado do arquivo (document, image, audio, video)
  • file_extension: Extensão do arquivo
  • caption: Legenda opcional fornecida no envio
  • uploaded_at: Timestamp do upload em formato ISO 8601

4️⃣ Acesso aos Arquivos em Actions

Método download_file(file_id)

Gera uma URL temporária de download para um arquivo específico.

Parâmetros:

  • file_id (str): UUID do arquivo obtido do state

Retorno:

  • str: URL temporária válida por 10 minutos

Exemplo de uso completo:

def processar_documento_enviado():
"""
Action que processa documentos enviados via API externa
"""
try:
# 1. Acessar lista de arquivos do state (somente leitura)
files = state_manager.get("files")

if not files:
return actions_sdk.ResponseToUser(
status=actions_sdk.ResponseStatus.ERROR,
message="Nenhum documento foi enviado ainda. Por favor, envie um documento primeiro."
)

# 2. Pegar o último arquivo enviado
last_file = files[-1]
file_id = last_file.get("file_id")
file_name = last_file.get("file_name", "arquivo")
file_size = last_file.get("file_size", 0)
file_type = last_file.get("file_type", "document")

# 3. Log do processamento
action_span.event("processar_documento", {
"file_id": file_id,
"file_name": file_name,
"file_size": file_size
})

# 4. Gerar URL temporária para download
download_url = actions_sdk.download_file(file_id=file_id)

# 5. Criar objeto FileContent para resposta
file_content = actions_sdk.FileContent(
fileId=file_id,
fileName=file_name,
fileUrl=download_url,
fileSize=file_size
)

# 6. Retornar arquivo processado ao usuário
return actions_sdk.ResponseToUser(
status=actions_sdk.ResponseStatus.SUCCESS,
message=f"Documento '{file_name}' processado com sucesso! Você pode baixá-lo usando o link abaixo.",
files=[file_content]
)

except Exception as e:
action_span.event("erro_processar_documento", {
"error": str(e)
})

return actions_sdk.ResponseToAgent(
instruction="Informe ao usuário que ocorreu um erro ao processar o documento e peça para tentar novamente.",
status=actions_sdk.ResponseStatus.ERROR,
detail=str(e)
)

5️⃣ Proteção da Chave files

A chave files no state é protegida contra modificação pelas actions para garantir integridade dos dados:

✅ Operações Permitidas

# Leitura dos arquivos
files = state_manager.get("files")

# Modificação de outras chaves
state_manager.update("custom_key", "valor")

❌ Operações Bloqueadas

# Tentativa de modificar diretamente a chave files
state_manager.update("files", nova_lista) # → ERRO

Proteção Importante

A chave files é somente leitura dentro das actions. Isso garante que:

  • Apenas a API v2 pode adicionar/remover arquivos via mensagens do tipo document
  • Actions não podem corromper acidentalmente os dados de arquivos
  • O histórico de arquivos da sessão permanece consistente