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
ResponseToUsereResponseToAgent - 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 salvofile_bytes(bytes, opcional): Conteúdo do arquivo em bytesfilename(str, opcional): Nome do arquivo (necessário quando usandofile_bytes)
Validação:
- Pelo menos
file_urlOUfile_bytesdeve ser fornecido - Quando usar
file_bytes, é recomendado fornecerfilename
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 peloupload_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
filesestruturado 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
filesautomá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_urlOUfile_bytesdeve 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)
)
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
O File Management extrai automaticamente client_slug e session_id do contexto da action, não sendo necessário gerenciar esses parâmetros manualmente.
- 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_urlOUfile_bytesdeve ser fornecido - Filename recomendado: Ao usar
file_bytes, forneçafilenamepara 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:
- Upload via API: Arquivo é enviado através do endpoint
/admin/v2/files/upload - Mensagem Document: Arquivo é adicionado ao state através de mensagem tipo
document - 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
- O método interno
extract_files_from_requestidentifica o arquivo pelo ID no campodocument.id - Busca os dados completos do arquivo na tabela
uploaded_files - Adiciona os dados completos à chave
filesno 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 arquivofile_name: Nome original do arquivofile_size: Tamanho em bytesfile_type: Tipo detectado do arquivo (document,image,audio,video)file_extension: Extensão do arquivocaption: Legenda opcional fornecida no enviouploaded_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
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