Adds docs
This commit is contained in:
294
docs/api.md
Normal file
294
docs/api.md
Normal file
@@ -0,0 +1,294 @@
|
|||||||
|
# Documentação da API
|
||||||
|
|
||||||
|
## Base URL
|
||||||
|
|
||||||
|
```
|
||||||
|
http://<host>:8000
|
||||||
|
```
|
||||||
|
|
||||||
|
## Autenticação
|
||||||
|
|
||||||
|
Todos os endpoints protegidos requerem o header:
|
||||||
|
|
||||||
|
```
|
||||||
|
X-API-Key: <sua-chave-de-api>
|
||||||
|
```
|
||||||
|
|
||||||
|
Respostas de erro de autenticação:
|
||||||
|
|
||||||
|
```json
|
||||||
|
HTTP 403 Forbidden
|
||||||
|
{ "detail": "Invalid API key" }
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Endpoints
|
||||||
|
|
||||||
|
### `GET /health`
|
||||||
|
|
||||||
|
Verifica se o serviço está ativo.
|
||||||
|
|
||||||
|
**Autenticação:** Não requerida
|
||||||
|
|
||||||
|
**Resposta:**
|
||||||
|
```json
|
||||||
|
HTTP 200 OK
|
||||||
|
{ "status": "healthy" }
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `GET /rules`
|
||||||
|
|
||||||
|
Lista os códigos de procedimento que possuem regras de autorização configuradas.
|
||||||
|
|
||||||
|
**Autenticação:** Não requerida
|
||||||
|
|
||||||
|
**Resposta:**
|
||||||
|
```json
|
||||||
|
HTTP 200 OK
|
||||||
|
{
|
||||||
|
"codes": [
|
||||||
|
"40808130",
|
||||||
|
"40808122",
|
||||||
|
"31303293",
|
||||||
|
"31005470",
|
||||||
|
"41501012",
|
||||||
|
"40901254",
|
||||||
|
"40901262",
|
||||||
|
"..."
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `POST /process`
|
||||||
|
|
||||||
|
Processa uma lista de guias de autorização médica. Para cada guia, extrai texto dos documentos anexados e avalia cada serviço solicitado usando o agente de IA.
|
||||||
|
|
||||||
|
**Autenticação:** Requerida (`X-API-Key`)
|
||||||
|
|
||||||
|
**Content-Type:** `application/json`
|
||||||
|
|
||||||
|
#### Corpo da Requisição
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"operadora": {
|
||||||
|
"organizacaoId": "string",
|
||||||
|
"processId": "string"
|
||||||
|
},
|
||||||
|
"guias": [ <lista de objetos guia> ]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Estrutura de uma Guia
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"atendimento": {
|
||||||
|
"codigoGuia": "GUIA-2025-0001",
|
||||||
|
"nomeAtendente": "Maria da Silva",
|
||||||
|
"codigoContratante": "UNIMED-SP",
|
||||||
|
"nomeContratante": "Unimed São Paulo",
|
||||||
|
"codigoPlanoContratado": "PLANO-OURO",
|
||||||
|
"planoRegulamentado": "true",
|
||||||
|
"carteirinhaBeneficiario": "1234567890",
|
||||||
|
"nomeBeneficiario": "João Pereira",
|
||||||
|
"dataNascimentoBeneficiario": "1980-05-20",
|
||||||
|
"idadeBeneficiario": 45,
|
||||||
|
"generoBeneficiario": "M"
|
||||||
|
},
|
||||||
|
"guia": {
|
||||||
|
"codigoGuiaLocal": "GUIA-2025-0001",
|
||||||
|
"tipoGuia": "SP/SADT",
|
||||||
|
"nomePrestadorSolicitante": "Dr. Fulano",
|
||||||
|
"nomePrestadorExecutante": "Hospital X",
|
||||||
|
"caraterAtendimento": "eletivo",
|
||||||
|
"tipoAtendimento": "ambulatorial",
|
||||||
|
"codigoCid": "S72.0",
|
||||||
|
"indicacaoClinica": "Paciente com fratura de fêmur."
|
||||||
|
},
|
||||||
|
"servicos": [
|
||||||
|
{
|
||||||
|
"sequenciaServico": 1,
|
||||||
|
"codigoServico": "40808130",
|
||||||
|
"descricaoServico": "Densitometria óssea",
|
||||||
|
"tipoServico": "EXAME",
|
||||||
|
"quantidadeSolicitada": 1,
|
||||||
|
"servicoCobertoPlano": "true",
|
||||||
|
"dataSolicitacao": "2025-11-17T10:15:00"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"historico": {
|
||||||
|
"quantidadeHistoricoProcedimento365dias": 1,
|
||||||
|
"quantidadeHistoricoProcedimentoTotal": 1
|
||||||
|
},
|
||||||
|
"anexos": [
|
||||||
|
{
|
||||||
|
"codigoGuia": "GUIA-2025-0001",
|
||||||
|
"tipoAnexo": "LAUDO",
|
||||||
|
"descricao": "Laudo do exame.",
|
||||||
|
"nomeArquivo": "laudo.pdf",
|
||||||
|
"idAnexo": "IMG-000001",
|
||||||
|
"mimeType": "application/pdf",
|
||||||
|
"URLAnexo": "s3://meu-bucket/documentos/laudo.pdf"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Campos Importantes
|
||||||
|
|
||||||
|
| Campo | Tipo | Descrição |
|
||||||
|
|--------------------------------|--------|------------------------------------------------------------|
|
||||||
|
| `atendimento.nomeBeneficiario` | string | Nome do paciente (verificado nos documentos pelo agente) |
|
||||||
|
| `servicos[].codigoServico` | string | Código TUSS do procedimento solicitado |
|
||||||
|
| `anexos[].URLAnexo` | string | URI S3 do documento (`s3://bucket/chave`) |
|
||||||
|
| `guia.indicacaoClinica` | string | Indicação clínica usada pelo agente na decisão |
|
||||||
|
|
||||||
|
#### Resposta de Sucesso
|
||||||
|
|
||||||
|
```json
|
||||||
|
HTTP 200 OK
|
||||||
|
{
|
||||||
|
"status": "success",
|
||||||
|
"operadora": {
|
||||||
|
"organizacaoId": "asasasabb-1234-5678-aabb-123456abcdef",
|
||||||
|
"processId": "ihjas1212rjaklpastash"
|
||||||
|
},
|
||||||
|
"guias": [
|
||||||
|
{
|
||||||
|
"atendimento": { ... },
|
||||||
|
"guia": { ... },
|
||||||
|
"servicos": [ ... ],
|
||||||
|
"historico": { ... },
|
||||||
|
"anexos": [
|
||||||
|
{
|
||||||
|
"nomeArquivo": "laudo.pdf",
|
||||||
|
"URLAnexo": "s3://meu-bucket/documentos/laudo.pdf",
|
||||||
|
"textoExtraido": "João Pereira\nDensitometria Óssea\nResultado: ...",
|
||||||
|
"pageCount": 2,
|
||||||
|
"tempoExtracaoSegundos": 3.14
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"avaliacaoAgente": [
|
||||||
|
{
|
||||||
|
"codigoServico": "40808130",
|
||||||
|
"resultado": "Aprovado",
|
||||||
|
"agentOutput": "{\"status\": \"Aprovado\", \"criterio\": \"Mulher acima de 45 anos\", \"documentos\": [{\"nome\": \"laudo.pdf\", \"pertence_ao_paciente\": true}]}",
|
||||||
|
"input_tokens": 1523,
|
||||||
|
"output_tokens": 87,
|
||||||
|
"tempoAgentSegundos": 4.32
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"tempoProcessamento": {
|
||||||
|
"extracaoSegundos": 3.14,
|
||||||
|
"agentSegundos": 4.32,
|
||||||
|
"totalSegundos": 7.86
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Campos da Avaliação (`avaliacaoAgente`)
|
||||||
|
|
||||||
|
| Campo | Tipo | Valores possíveis | Descrição |
|
||||||
|
|------------------------|--------|------------------------------------------|---------------------------------------------------|
|
||||||
|
| `codigoServico` | string | — | Código original conforme enviado na requisição |
|
||||||
|
| `resultado` | string | `"Aprovado"`, `"Reprovado"`, `"SKIPPED"` | Decisão final do agente |
|
||||||
|
| `agentOutput` | string | JSON string | Resposta completa do agente (status + critério + documentos) |
|
||||||
|
| `input_tokens` | int | — | Total de tokens de entrada consumidos |
|
||||||
|
| `output_tokens` | int | — | Total de tokens de saída gerados |
|
||||||
|
| `tempoAgentSegundos` | float | — | Tempo de execução do agente em segundos |
|
||||||
|
|
||||||
|
#### Resultado `"SKIPPED"`
|
||||||
|
|
||||||
|
Retornado quando o código de procedimento não possui regras configuradas no `rules.yaml`:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"codigoServico": "99999999",
|
||||||
|
"resultado": "SKIPPED",
|
||||||
|
"motivo": "Codigo '99999999' nao encontrado nas regras",
|
||||||
|
"agentOutput": "",
|
||||||
|
"tempoAgentSegundos": 0
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Erro em Guia Individual
|
||||||
|
|
||||||
|
Se uma guia falhar completamente, ela é substituída por um objeto de erro na lista (as demais guias continuam sendo processadas):
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"error": "mensagem de erro",
|
||||||
|
"guia": "GUIA-2025-0001"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Exemplo Completo
|
||||||
|
|
||||||
|
### Requisição
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -X POST http://localhost:8000/process \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-H "X-API-Key: sua-chave-aqui" \
|
||||||
|
-d '{
|
||||||
|
"operadora": {
|
||||||
|
"organizacaoId": "org-123",
|
||||||
|
"processId": "proc-456"
|
||||||
|
},
|
||||||
|
"guias": [
|
||||||
|
{
|
||||||
|
"atendimento": {
|
||||||
|
"nomeBeneficiario": "Ana Paula Costa",
|
||||||
|
"idadeBeneficiario": 52,
|
||||||
|
"generoBeneficiario": "F",
|
||||||
|
"carteirinhaBeneficiario": "9876543210"
|
||||||
|
},
|
||||||
|
"guia": {
|
||||||
|
"codigoGuiaLocal": "GUIA-2025-0042",
|
||||||
|
"indicacaoClinica": "Rastreamento de osteoporose pós-menopausa.",
|
||||||
|
"codigoCid": "M81.0"
|
||||||
|
},
|
||||||
|
"servicos": [
|
||||||
|
{
|
||||||
|
"codigoServico": "40808130",
|
||||||
|
"descricaoServico": "Densitometria óssea",
|
||||||
|
"quantidadeSolicitada": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"historico": {},
|
||||||
|
"anexos": [
|
||||||
|
{
|
||||||
|
"nomeArquivo": "pedido_medico.pdf",
|
||||||
|
"URLAnexo": "s3://meu-bucket/guias/pedido_medico.pdf"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}'
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## Formato de Saída no S3
|
||||||
|
|
||||||
|
Após cada chamada ao `/process`, os resultados são salvos automaticamente:
|
||||||
|
|
||||||
|
```
|
||||||
|
s3://<OUTPUT_BUCKET>/<API_VERSION>/<codigoGuiaLocal>_<YYYYMMDD_HHMMSS>.json
|
||||||
|
```
|
||||||
|
|
||||||
|
Exemplo:
|
||||||
|
```
|
||||||
|
s3://upflux-doc-analyzer/v1/GUIA-2025-0042_20251117_143022.json
|
||||||
|
```
|
||||||
|
|
||||||
|
O conteúdo é o mesmo objeto da guia processada (JSON completo, incluindo texto extraído e avaliações).
|
||||||
170
docs/langfuse.md
Normal file
170
docs/langfuse.md
Normal file
@@ -0,0 +1,170 @@
|
|||||||
|
# Observabilidade com Langfuse
|
||||||
|
|
||||||
|
## O que é o Langfuse
|
||||||
|
|
||||||
|
O [Langfuse](https://langfuse.com) é uma plataforma de observabilidade para aplicações LLM. No doc-processor ele é usado para rastrear cada chamada ao agente de IA, permitindo:
|
||||||
|
|
||||||
|
- Visualizar o histórico completo de mensagens de cada execução (System, Human, AI, Tool calls).
|
||||||
|
- Monitorar consumo de tokens (entrada e saída) por execução e por procedimento.
|
||||||
|
- Medir latência das chamadas ao modelo.
|
||||||
|
- Inspecionar as respostas brutas do agente para depuração.
|
||||||
|
- Auditar decisões do sistema ao longo do tempo.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Como está integrado no código
|
||||||
|
|
||||||
|
### Inicialização (`utils/langgraph_agent.py`)
|
||||||
|
|
||||||
|
O cliente Langfuse é criado **uma única vez** na importação do módulo, usando as credenciais do Secrets Manager:
|
||||||
|
|
||||||
|
```python
|
||||||
|
from langfuse import Langfuse
|
||||||
|
from langfuse.langchain import CallbackHandler
|
||||||
|
|
||||||
|
langfuse = Langfuse(
|
||||||
|
secret_key=SECRETS["LANGFUSE-SECRET-KEY"],
|
||||||
|
public_key=SECRETS["LANGFUSE-PUBLIC-KEY"],
|
||||||
|
host=LANGFUSE_HOST, # padrão: https://cloud.langfuse.com
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Rastreamento de execuções (`run_agent`)
|
||||||
|
|
||||||
|
Para cada chamada ao agente, um `CallbackHandler` do Langfuse é instanciado e passado como callback ao LangGraph. Isso faz com que todas as mensagens trocadas durante a execução sejam enviadas automaticamente ao Langfuse:
|
||||||
|
|
||||||
|
```python
|
||||||
|
langfuse_handler = CallbackHandler()
|
||||||
|
config = {"callbacks": [langfuse_handler]}
|
||||||
|
final_state = await agent.ainvoke(initial_state, config=config)
|
||||||
|
```
|
||||||
|
|
||||||
|
O `CallbackHandler` captura automaticamente:
|
||||||
|
- O conteúdo do System Prompt e da mensagem Human enviados ao modelo.
|
||||||
|
- Cada resposta do LLM (incluindo tool calls intermediárias).
|
||||||
|
- As respostas das ferramentas (`ToolMessage`).
|
||||||
|
- Tokens usados em cada step.
|
||||||
|
|
||||||
|
### Flush assíncrono
|
||||||
|
|
||||||
|
Após cada execução do agente, o buffer do Langfuse é enviado ao servidor de forma assíncrona para garantir que nenhum trace seja perdido mesmo que o processo seja encerrado logo após:
|
||||||
|
|
||||||
|
```python
|
||||||
|
await asyncio.to_thread(langfuse.flush)
|
||||||
|
```
|
||||||
|
|
||||||
|
> **Por que `to_thread`?** O método `flush()` do Langfuse é bloqueante. Executá-lo em uma thread separada evita que ele bloqueie o event loop do FastAPI enquanto aguarda a resposta da rede.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Contagem de Tokens
|
||||||
|
|
||||||
|
Além do rastreamento automático pelo Langfuse, o código também acumula os tokens manualmente a partir dos metadados das mensagens AI para retorná-los na resposta da API:
|
||||||
|
|
||||||
|
```python
|
||||||
|
input_tokens = 0
|
||||||
|
output_tokens = 0
|
||||||
|
for msg in final_state["messages"]:
|
||||||
|
usage = getattr(msg, "usage_metadata", None)
|
||||||
|
if usage:
|
||||||
|
input_tokens += usage.get("input_tokens", 0)
|
||||||
|
output_tokens += usage.get("output_tokens", 0)
|
||||||
|
```
|
||||||
|
|
||||||
|
Os tokens são somados de **todas** as mensagens AI geradas durante a execução, incluindo chamadas intermediárias quando o agente usa a ferramenta `check`. Esses valores são retornados em cada `avaliacaoAgente`:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"codigoServico": "40808130",
|
||||||
|
"resultado": "Aprovado",
|
||||||
|
"input_tokens": 1523,
|
||||||
|
"output_tokens": 87
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Criando uma Organização e um Projeto no Langfuse
|
||||||
|
|
||||||
|
### 1. Criar conta e organização
|
||||||
|
|
||||||
|
1. Acesse o ip do Ec2 via http na porta 3000, após liberar no security group para o ip desejado, e clique em **Sign Up**.
|
||||||
|
2. Após o login, o Langfuse pede para criar ou entrar em uma **organização**. A organização agrupa todos os projetos e membros da equipe.
|
||||||
|
- Clique em **Create new organization**, preencha o nome e confirme.
|
||||||
|
|
||||||
|
### 2. Criar um projeto
|
||||||
|
|
||||||
|
Dentro da organização:
|
||||||
|
|
||||||
|
1. Crie um novo projeto.
|
||||||
|
2. Nos passos iniciais tem um botão para criar as Api keys, copie os valores de Secret e Public.
|
||||||
|
|
||||||
|
### 3. Apontar o sistema para o novo projeto
|
||||||
|
|
||||||
|
Atualize os segredos no AWS Secrets Manager (`doc-analyzer`) com os novos valores:
|
||||||
|
|
||||||
|
Basta ir no Secrets manager, escolher o segredo doc-analyzer, ir em retrieve secret value e edit. Atualize com os novos valores.
|
||||||
|
|
||||||
|
Após atualizar, talvez seja nescessário reiniciar o container/serviço para que ele carregue as novas credenciais:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# ECS — forçar novo deploy
|
||||||
|
aws ecs update-service \
|
||||||
|
--cluster <nome-do-cluster> \
|
||||||
|
--service <nome-do-servico> \
|
||||||
|
--force-new-deployment
|
||||||
|
```
|
||||||
|
|
||||||
|
Nas próximas execuções, os traces aparecerão no novo projeto dentro da nova organização.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Configuração
|
||||||
|
|
||||||
|
### Variável de Ambiente
|
||||||
|
|
||||||
|
| Variável | Padrão | Descrição |
|
||||||
|
|------------------|------------------------------|------------------------------------|
|
||||||
|
| `LANGFUSE_HOST` | `http://13.59.214.47:3000/` | Endereço do servidor Langfuse. Pode ser uma instância self-hosted. |
|
||||||
|
|
||||||
|
### Segredos (AWS Secrets Manager — `doc-analyzer`)
|
||||||
|
|
||||||
|
| Chave | Descrição |
|
||||||
|
|-----------------------|------------------------------------|
|
||||||
|
| `LANGFUSE-SECRET-KEY` | Chave secreta do projeto Langfuse |
|
||||||
|
| `LANGFUSE-PUBLIC-KEY` | Chave pública do projeto Langfuse |
|
||||||
|
|
||||||
|
As chaves são obtidas no painel do Langfuse em **Settings → API Keys**.
|
||||||
|
|
||||||
|
### Self-hosted
|
||||||
|
|
||||||
|
Para usar uma instância própria do Langfuse (ex: rodando internamente), basta configurar (variável de ambiente do ecs):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
LANGFUSE_HOST=http://13.59.214.47:3000/
|
||||||
|
```
|
||||||
|
|
||||||
|
E atualizar as chaves correspondentes no Secrets Manager.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## O que visualizar no painel
|
||||||
|
|
||||||
|
Cada chamada ao `POST /process` gera uma ou mais **traces** no Langfuse (uma por serviço avaliado). Em cada trace é possível ver:
|
||||||
|
|
||||||
|
1. **Input**: JSON da guia + conteúdo OCR dos documentos enviados ao agente.
|
||||||
|
2. **System Prompt**: Critérios de auto-aprovação e documentação mínima do procedimento avaliado.
|
||||||
|
3. **Steps intermediários**: Se o agente chamou a ferramenta `check`, aparece como um step separado com o conteúdo retornado.
|
||||||
|
4. **Output**: JSON final com `status`, `criterio` e lista de `documentos`.
|
||||||
|
5. **Tokens e latência**: Custo estimado e tempo de resposta do modelo.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Depuração
|
||||||
|
|
||||||
|
Se as traces não aparecerem no painel:
|
||||||
|
|
||||||
|
1. Verifique se `LANGFUSE-SECRET-KEY` e `LANGFUSE-PUBLIC-KEY` estão corretos no Secrets Manager.
|
||||||
|
2. Confirme que `LANGFUSE_HOST` aponta para o servidor correto.
|
||||||
|
3. Verifique os logs do container — erros de conexão com o Langfuse são silenciosos por padrão (o `flush` falha sem derrubar o serviço).
|
||||||
|
4. Confirme que o container tem acesso de rede ao host do Langfuse.
|
||||||
342
docs/modulos.md
Normal file
342
docs/modulos.md
Normal file
@@ -0,0 +1,342 @@
|
|||||||
|
# Documentação dos Módulos
|
||||||
|
|
||||||
|
## 1. `app.py` — Aplicação Principal
|
||||||
|
|
||||||
|
Ponto de entrada da API REST. Define os endpoints FastAPI, autentica as requisições e orquestra o processamento das guias.
|
||||||
|
|
||||||
|
### Autenticação
|
||||||
|
|
||||||
|
Toda requisição ao endpoint `/process` deve incluir o header:
|
||||||
|
|
||||||
|
```
|
||||||
|
X-API-Key: <chave configurada no Secrets Manager>
|
||||||
|
```
|
||||||
|
|
||||||
|
Se a chave estiver ausente ou incorreta, a API retorna `HTTP 403 Forbidden`.
|
||||||
|
|
||||||
|
### Função `process_guia(guia: dict) → dict`
|
||||||
|
|
||||||
|
Processa uma única guia de autorização do início ao fim.
|
||||||
|
|
||||||
|
**Etapas:**
|
||||||
|
|
||||||
|
1. Itera sobre todos os anexos da guia (`guia.anexos`).
|
||||||
|
2. Para cada anexo, extrai o texto via OCR (em paralelo, usando `asyncio.gather`).
|
||||||
|
3. Concatena todos os textos extraídos em uma única string (`file_content`).
|
||||||
|
4. Avalia cada serviço médico (`guia.servicos`) em paralelo, chamando o agente de IA.
|
||||||
|
5. Adiciona os tempos de processamento ao objeto da guia.
|
||||||
|
|
||||||
|
**Campos adicionados à guia:**
|
||||||
|
|
||||||
|
| Campo | Tipo | Descrição |
|
||||||
|
|------------------------------------------|---------|---------------------------------------------------|
|
||||||
|
| `anexo.textoExtraido` | string | Texto extraído via OCR do arquivo |
|
||||||
|
| `anexo.pageCount` | int | Número de páginas extraídas |
|
||||||
|
| `anexo.tempoExtracaoSegundos` | float | Tempo de extração do anexo em segundos |
|
||||||
|
| `anexo.error` | string | Mensagem de erro (apenas se falhou) |
|
||||||
|
| `guia.avaliacaoAgente` | list | Lista de avaliações dos serviços |
|
||||||
|
| `guia.tempoProcessamento.extracaoSegundos` | float | Tempo total de extração de todos os anexos |
|
||||||
|
| `guia.tempoProcessamento.agentSegundos` | float | Tempo total do agente para todos os serviços |
|
||||||
|
| `guia.tempoProcessamento.totalSegundos` | float | Tempo total de processamento da guia |
|
||||||
|
|
||||||
|
### Função `_extract_anexo(anexo_idx, anexo)`
|
||||||
|
|
||||||
|
Função interna de `process_guia`. Processa um único anexo:
|
||||||
|
|
||||||
|
- Lê o campo `urlAnexo` ou `URLAnexo` para obter a URI S3.
|
||||||
|
- Se a URI for inválida ou não começar com `s3://`, define `textoExtraido = ""` e retorna `None`.
|
||||||
|
- Chama `extract_text_from_s3_document` para baixar e executar OCR.
|
||||||
|
- Em caso de erro, armazena a mensagem em `anexo.error` e retorna texto vazio.
|
||||||
|
- Retorna a string formatada `"--- <nomeArquivo> ---\n<texto>"`.
|
||||||
|
|
||||||
|
### Modelo de Requisição `ProcessRequest`
|
||||||
|
|
||||||
|
```python
|
||||||
|
class ProcessRequest(BaseModel):
|
||||||
|
operadora: dict # Metadados da operadora (passado diretamente na resposta)
|
||||||
|
guias: list[dict] # Lista de guias a serem avaliadas
|
||||||
|
```
|
||||||
|
|
||||||
|
### Endpoints
|
||||||
|
|
||||||
|
| Método | Rota | Autenticação | Descrição |
|
||||||
|
|--------|------------|--------------|---------------------------------------------------|
|
||||||
|
| POST | `/process` | X-API-Key | Processa todas as guias da requisição |
|
||||||
|
| GET | `/health` | Não | Verifica se o serviço está ativo |
|
||||||
|
| GET | `/rules` | Não | Lista os códigos de procedimento com regras ativas|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. `services/document_extractor.py` — Extração de Documentos
|
||||||
|
|
||||||
|
Responsável por baixar arquivos do S3 e extrair texto via AWS Textract.
|
||||||
|
|
||||||
|
### Clientes AWS
|
||||||
|
|
||||||
|
Dois clientes boto3 são criados no início do módulo:
|
||||||
|
|
||||||
|
- `_s3_input`: cliente S3 autenticado com as credenciais do Secrets Manager (para acesso ao bucket de entrada de documentos).
|
||||||
|
- `_textract`: cliente Textract usando as credenciais de ambiente padrão.
|
||||||
|
|
||||||
|
### Função `parse_s3_uri(s3_uri: str) → tuple[str, str]`
|
||||||
|
|
||||||
|
Converte uma URI S3 no formato `s3://bucket/chave` em uma tupla `(bucket, chave)`.
|
||||||
|
|
||||||
|
**Erros:**
|
||||||
|
- Lança `ValueError` se o scheme não for `s3://`.
|
||||||
|
- Lança `ValueError` se o bucket ou a chave estiverem ausentes.
|
||||||
|
|
||||||
|
**Exemplos:**
|
||||||
|
```python
|
||||||
|
parse_s3_uri("s3://meu-bucket/pasta/arquivo.pdf")
|
||||||
|
# → ("meu-bucket", "pasta/arquivo.pdf")
|
||||||
|
```
|
||||||
|
|
||||||
|
### Função `extract_text_from_s3_document(bucket: str, key: str) → tuple[str, int]`
|
||||||
|
|
||||||
|
Função assíncrona principal do módulo. Baixa o arquivo e extrai o texto conforme o tipo:
|
||||||
|
|
||||||
|
| Extensão | Comportamento |
|
||||||
|
|-----------------------|-------------------------------------------------------------------|
|
||||||
|
| `.png`, `.jpg`, `.jpeg` | Envia os bytes diretamente ao Textract. Retorna `(texto, 1)`. |
|
||||||
|
| `.pdf` | Separa o PDF em páginas individuais. Cada página é enviada ao Textract separadamente (em paralelo). Retorna `(texto_completo, num_paginas)`. |
|
||||||
|
| Outros | Retorna `("", 0)` sem processar. |
|
||||||
|
|
||||||
|
> **Nota:** Operações bloqueantes do boto3 são executadas em threads separadas via `asyncio.to_thread` para não bloquear o event loop.
|
||||||
|
|
||||||
|
### Funções Auxiliares
|
||||||
|
|
||||||
|
#### `_split_pdf_pages(pdf_bytes: bytes) → list[bytes]`
|
||||||
|
|
||||||
|
Usa PyPDF2 para ler o PDF e separar cada página em um arquivo PDF individual (em bytes). Necessário porque o Textract aceita no máximo uma página por chamada via bytes.
|
||||||
|
|
||||||
|
#### `_textract_detect_bytes(file_bytes: bytes) → str`
|
||||||
|
|
||||||
|
Chama `textract.detect_document_text` com os bytes do arquivo e retorna o texto extraído.
|
||||||
|
|
||||||
|
#### `_extract_text_from_textract_response(response: dict) → str`
|
||||||
|
|
||||||
|
Filtra os blocos da resposta do Textract, mantendo apenas blocos do tipo `LINE`, e os concatena em uma string com quebras de linha.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. `services/authorization.py` — Avaliação de Serviços
|
||||||
|
|
||||||
|
Avalia se um serviço médico deve ser aprovado ou reprovado, consultando o agente de IA.
|
||||||
|
|
||||||
|
### Função `evaluate_servico(servico, guia, file_content) → dict`
|
||||||
|
|
||||||
|
**Parâmetros:**
|
||||||
|
|
||||||
|
| Parâmetro | Tipo | Descrição |
|
||||||
|
|----------------|--------|--------------------------------------------------------|
|
||||||
|
| `servico` | dict | Objeto do serviço médico com `codigoServico` e outros campos |
|
||||||
|
| `guia` | dict | Guia completa (atendimento, guia, histórico) |
|
||||||
|
| `file_content` | str | Texto OCR concatenado de todos os anexos |
|
||||||
|
|
||||||
|
**Fluxo:**
|
||||||
|
|
||||||
|
1. Extrai o `codigoServico` e mantém apenas os dígitos numéricos.
|
||||||
|
2. Verifica se o código está presente no dicionário `RULES` (carregado do `rules.yaml`).
|
||||||
|
- Se não estiver: retorna `resultado = "SKIPPED"` imediatamente.
|
||||||
|
3. Monta um payload JSON com `atendimento`, `guia`, `servico` e `historico`.
|
||||||
|
4. Chama `run_agent(query, code, file_content)` de forma assíncrona.
|
||||||
|
5. Tenta parsear a resposta JSON do agente para extrair o campo `status`.
|
||||||
|
6. Suporta respostas encapsuladas em blocos de código markdown (` ```json ... ``` `).
|
||||||
|
|
||||||
|
**Resposta:**
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"codigoServico": "40808130",
|
||||||
|
"resultado": "Aprovado",
|
||||||
|
"agentOutput": "{ \"status\": \"Aprovado\", ... }",
|
||||||
|
"input_tokens": 1523,
|
||||||
|
"output_tokens": 87,
|
||||||
|
"tempoAgentSegundos": 4.32
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Resultado possível:**
|
||||||
|
|
||||||
|
| Valor | Condição |
|
||||||
|
|-------------|-------------------------------------------------------|
|
||||||
|
| `"Aprovado"` | Agente retornou `status: Aprovado` |
|
||||||
|
| `"Reprovado"` | Agente retornou `status: Reprovado` ou erro no parse |
|
||||||
|
| `"SKIPPED"` | Código de serviço não possui regras configuradas |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. `services/result_store.py` — Persistência de Resultados
|
||||||
|
|
||||||
|
Salva os resultados do processamento no S3 de saída.
|
||||||
|
|
||||||
|
### Função `save_results(results: list[dict]) → None`
|
||||||
|
|
||||||
|
Persiste cada guia processada como um arquivo JSON separado no S3.
|
||||||
|
|
||||||
|
**Localização no S3:**
|
||||||
|
|
||||||
|
```
|
||||||
|
s3://<OUTPUT_BUCKET>/<API_VERSION>/<codigoGuiaLocal>_<YYYYMMDD_HHMMSS>.json
|
||||||
|
```
|
||||||
|
|
||||||
|
Exemplo:
|
||||||
|
```
|
||||||
|
s3://upflux-doc-analyzer/v1/GUIA-2025-0001_20251117_103000.json
|
||||||
|
```
|
||||||
|
|
||||||
|
**Comportamento:**
|
||||||
|
- Todas as guias são salvas em paralelo com `asyncio.gather`.
|
||||||
|
- Erros são silenciados (`except Exception: pass`) para não impedir a resposta da API.
|
||||||
|
- Usa o cliente S3 padrão de ambiente (sem credenciais explícitas).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. `utils/langgraph_agent.py` — Agente de IA (LangGraph)
|
||||||
|
|
||||||
|
Núcleo de decisão do sistema. Define o fluxo do agente ReAct usando LangGraph e executa a avaliação via AWS Bedrock (Claude).
|
||||||
|
|
||||||
|
### Carregamento das Regras
|
||||||
|
|
||||||
|
Ao importar o módulo, o arquivo `rules.yaml` é lido e dois dicionários são populados:
|
||||||
|
|
||||||
|
- `RULES`: mapeamento de código de procedimento → critérios de auto-aprovação (texto livre).
|
||||||
|
- `MIN_DOC`: mapeamento de código de procedimento → documentação mínima exigida (texto livre).
|
||||||
|
|
||||||
|
### `AgentState` (TypedDict)
|
||||||
|
|
||||||
|
Estado compartilhado entre os nós do grafo LangGraph:
|
||||||
|
|
||||||
|
```python
|
||||||
|
class AgentState(TypedDict):
|
||||||
|
messages: Annotated[list, add_messages]
|
||||||
|
```
|
||||||
|
|
||||||
|
O campo `messages` acumula todas as mensagens trocadas (System, Human, AI, Tool) ao longo da execução.
|
||||||
|
|
||||||
|
### Função `create_agent(file_content: str) → CompiledGraph`
|
||||||
|
|
||||||
|
Cria e compila o grafo LangGraph para uma execução específica.
|
||||||
|
|
||||||
|
**Ferramenta disponível:**
|
||||||
|
|
||||||
|
- `check(expression: str) → str`: Retorna o conteúdo OCR dos documentos. O agente pode chamar essa ferramenta quando o JSON da guia não for suficiente para a decisão.
|
||||||
|
|
||||||
|
**Nós do grafo:**
|
||||||
|
|
||||||
|
| Nó | Função |
|
||||||
|
|-----------|------------------------------------------------------------------|
|
||||||
|
| `agent` | Chama o LLM (Bedrock Claude) com o estado atual das mensagens |
|
||||||
|
| `tools` | Executa as ferramentas solicitadas pelo LLM |
|
||||||
|
|
||||||
|
**Fluxo condicional:**
|
||||||
|
|
||||||
|
```
|
||||||
|
[entrada] → agent → (tem tool_calls?) → Sim → tools → agent → ...
|
||||||
|
→ Não → END
|
||||||
|
```
|
||||||
|
|
||||||
|
### Função `run_agent(query, code, file_content) → dict`
|
||||||
|
|
||||||
|
Executa o agente para um serviço específico.
|
||||||
|
|
||||||
|
**System Prompt:** Instruções em inglês que descrevem:
|
||||||
|
- O papel do agente (aprovador/reprovador de procedimentos médicos).
|
||||||
|
- Os critérios de auto-aprovação do código (extraídos de `RULES[code]`).
|
||||||
|
- A documentação mínima exigida (extraída de `MIN_DOC[code]`).
|
||||||
|
- A lógica de decisão (auto-aprovação tem prioridade sobre documentação mínima).
|
||||||
|
- O formato obrigatório de resposta (JSON puro, sem markdown):
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"status": "Aprovado" ou "Reprovado",
|
||||||
|
"criterio": "descrição breve do critério atendido ou motivo da negação",
|
||||||
|
"documentos": [
|
||||||
|
{ "nome": "nome do documento", "pertence_ao_paciente": true }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Human Message:** JSON da guia + conteúdo OCR dos documentos dentro da tag `<documentos_anexados>`.
|
||||||
|
|
||||||
|
**Observabilidade:** Cada execução é rastreada no Langfuse via `CallbackHandler`.
|
||||||
|
|
||||||
|
**Retorno:**
|
||||||
|
|
||||||
|
```python
|
||||||
|
{
|
||||||
|
"response": "<JSON string da resposta do agente>",
|
||||||
|
"input_tokens": 1523,
|
||||||
|
"output_tokens": 87
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Os tokens são somados de todas as mensagens AI geradas durante a execução (incluindo chamadas intermediárias de ferramentas).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. `utils/config.py` — Configurações
|
||||||
|
|
||||||
|
Carrega variáveis de ambiente com valores padrão:
|
||||||
|
|
||||||
|
```python
|
||||||
|
AWS_REGION = os.environ.get("AWS_REGION", "us-east-2")
|
||||||
|
BEDROCK_MODEL_ARN = os.environ["BEDROCK_MODEL_ARN"] # obrigatória
|
||||||
|
OUTPUT_BUCKET = os.environ.get("OUTPUT_BUCKET", "upflux-doc-analyzer")
|
||||||
|
API_VERSION = os.environ.get("API_VERSION", "v1")
|
||||||
|
LANGFUSE_HOST = os.environ.get("LANGFUSE_HOST", "https://cloud.langfuse.com")
|
||||||
|
```
|
||||||
|
|
||||||
|
`BEDROCK_MODEL_ARN` é obrigatória; se ausente, o serviço falha na inicialização com `KeyError`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. `utils/secrets_manager.py` — Gerenciamento de Segredos
|
||||||
|
|
||||||
|
Carrega os segredos do AWS Secrets Manager uma única vez na inicialização:
|
||||||
|
|
||||||
|
```python
|
||||||
|
_client = boto3.client("secretsmanager", region_name="us-east-2")
|
||||||
|
_response = _client.get_secret_value(SecretId="doc-analyzer")
|
||||||
|
SECRETS: dict = json.loads(_response["SecretString"])
|
||||||
|
```
|
||||||
|
|
||||||
|
O dicionário `SECRETS` é importado pelos módulos que precisam de credenciais (`app.py`, `document_extractor.py`, `langgraph_agent.py`).
|
||||||
|
|
||||||
|
**Chaves esperadas em `SECRETS`:**
|
||||||
|
|
||||||
|
| Chave | Usado em |
|
||||||
|
|------------------------|-----------------------------------|
|
||||||
|
| `API-KEY` | `app.py` (autenticação da API) |
|
||||||
|
| `AWS_ACCESS_KEY` | `document_extractor.py` (S3) |
|
||||||
|
| `AWS_SECRET_KEY` | `document_extractor.py` (S3) |
|
||||||
|
| `LANGFUSE-SECRET-KEY` | `langgraph_agent.py` (Langfuse) |
|
||||||
|
| `LANGFUSE-PUBLIC-KEY` | `langgraph_agent.py` (Langfuse) |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 8. `utils/rules.yaml` — Regras de Autorização
|
||||||
|
|
||||||
|
Arquivo YAML com dois blocos principais:
|
||||||
|
|
||||||
|
### `rules` — Critérios de Auto-Aprovação
|
||||||
|
|
||||||
|
Cada entrada é um código de procedimento TUSS mapeado para um texto descrevendo as condições que, se atendidas, permitem aprovação imediata sem auditoria médica.
|
||||||
|
|
||||||
|
**Exemplos de códigos:**
|
||||||
|
|
||||||
|
| Código | Procedimento |
|
||||||
|
|--------------|-------------------------------------------|
|
||||||
|
| `40808130` | Densitometria óssea (osteoporose) |
|
||||||
|
| `31303293` | DIU Hormonal (Mirena/Kyleena) |
|
||||||
|
| `31005470` | Colecistectomia (cálculo biliar/colelitíase) |
|
||||||
|
| `40901254` | Ultrassom obstétrico 1º trimestre |
|
||||||
|
| `40901262` | Ultrassom obstétrico morfológico |
|
||||||
|
| `41501012` | Cirurgia de catarata |
|
||||||
|
| `20103190` | Reabilitação do assoalho pélvico |
|
||||||
|
| `40304906` | Eco-doppler venoso |
|
||||||
|
|
||||||
|
### `min_doc` — Documentação Mínima
|
||||||
|
|
||||||
|
Para cada código, descreve quais documentos são necessários quando os critérios de auto-aprovação não são atendidos. O agente verifica a presença dessas informações nos anexos OCR.
|
||||||
115
docs/visao-geral.md
Normal file
115
docs/visao-geral.md
Normal file
@@ -0,0 +1,115 @@
|
|||||||
|
# Doc-Processor — Visão Geral do Sistema
|
||||||
|
|
||||||
|
## O que é
|
||||||
|
|
||||||
|
O **Doc-Processor** é um serviço de análise automatizada de guias de autorização médica. Ele recebe solicitações de procedimentos médicos (guias), extrai o texto dos documentos anexados via OCR, e utiliza um agente de inteligência artificial (LLM) para decidir se cada serviço solicitado deve ser **Aprovado** ou **Reprovado**, com base em regras de negócio configuradas para cada código de procedimento.
|
||||||
|
|
||||||
|
O sistema foi desenvolvido para operar no contexto de operadoras de saúde (ex: Unimed), reduzindo o trabalho manual dos auditores médicos.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Fluxo de Processamento
|
||||||
|
|
||||||
|
```
|
||||||
|
POST /process
|
||||||
|
│
|
||||||
|
├─► Para cada guia (em paralelo):
|
||||||
|
│ │
|
||||||
|
│ ├─► Para cada anexo (em paralelo):
|
||||||
|
│ │ ├─► Baixa o arquivo do S3
|
||||||
|
│ │ ├─► OCR via AWS Textract
|
||||||
|
│ │ └─► Armazena texto extraído na guia
|
||||||
|
│ │
|
||||||
|
│ └─► Para cada serviço (em paralelo):
|
||||||
|
│ ├─► Verifica se o código existe nas regras
|
||||||
|
│ ├─► Monta o payload JSON (atendimento + guia + serviço + histórico)
|
||||||
|
│ ├─► Chama o agente LangGraph com o texto dos documentos
|
||||||
|
│ └─► Retorna Aprovado / Reprovado / SKIPPED
|
||||||
|
│
|
||||||
|
├─► Salva todos os resultados no S3 (bucket de saída)
|
||||||
|
└─► Retorna resposta HTTP com as avaliações
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Decisão do Agente
|
||||||
|
|
||||||
|
O agente segue a seguinte lógica de decisão para cada serviço:
|
||||||
|
|
||||||
|
1. **Critérios de auto-aprovação** (`rules.yaml › rules`): Se qualquer um desses critérios estiver presente na guia ou nos documentos, o procedimento é aprovado imediatamente.
|
||||||
|
2. **Documentação mínima** (`rules.yaml › min_doc`): Se nenhum critério de auto-aprovação for atendido, o agente verifica se a documentação mínima exigida está presente. Se estiver (mesmo que em tipo diferente de documento), o procedimento é aprovado.
|
||||||
|
3. **Reprovação**: Se nem os critérios de auto-aprovação nem a documentação mínima estiverem presentes, o procedimento é reprovado.
|
||||||
|
|
||||||
|
O agente também verifica, em cada documento, se o nome do beneficiário da guia está presente.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Tecnologias Utilizadas
|
||||||
|
|
||||||
|
| Tecnologia | Função |
|
||||||
|
|-------------------|-----------------------------------------------------|
|
||||||
|
| FastAPI | Framework web / API REST |
|
||||||
|
| LangGraph | Orquestração do agente de IA (fluxo ReAct) |
|
||||||
|
| LangChain AWS | Integração com AWS Bedrock (LLM Claude/Anthropic) |
|
||||||
|
| AWS Bedrock | Modelo de linguagem (LLM) para decisão |
|
||||||
|
| AWS Textract | OCR de PDFs e imagens |
|
||||||
|
| AWS S3 | Armazenamento de documentos de entrada e resultados |
|
||||||
|
| AWS Secrets Manager | Gerenciamento seguro de credenciais |
|
||||||
|
| Langfuse | Observabilidade e rastreamento de chamadas ao LLM |
|
||||||
|
| PyPDF2 | Separação de páginas de PDFs para OCR por página |
|
||||||
|
| Pydantic | Validação do corpo da requisição |
|
||||||
|
| Docker | Containerização do serviço |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Estrutura de Diretórios
|
||||||
|
|
||||||
|
```
|
||||||
|
code/
|
||||||
|
├── app.py # Ponto de entrada da API FastAPI
|
||||||
|
├── dockerfile # Imagem Docker da aplicação
|
||||||
|
├── Makefile # Automação de build e deploy
|
||||||
|
├── requirements.txt # Dependências Python
|
||||||
|
│
|
||||||
|
├── services/
|
||||||
|
│ ├── authorization.py # Avalia cada serviço via agente de IA
|
||||||
|
│ ├── document_extractor.py # Extrai texto de documentos no S3 via Textract
|
||||||
|
│ └── result_store.py # Persiste resultados no S3
|
||||||
|
│
|
||||||
|
├── utils/
|
||||||
|
│ ├── config.py # Variáveis de ambiente / configurações
|
||||||
|
│ ├── langgraph_agent.py # Definição e execução do agente LangGraph
|
||||||
|
│ ├── rules.yaml # Regras de autorização por código de procedimento
|
||||||
|
│ └── secrets_manager.py # Carrega segredos do AWS Secrets Manager
|
||||||
|
│
|
||||||
|
└── document/ # Documentação do sistema (esta pasta)
|
||||||
|
├── visao-geral.md
|
||||||
|
├── modulos.md
|
||||||
|
└── api.md
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Configuração
|
||||||
|
|
||||||
|
### Variáveis de Ambiente
|
||||||
|
|
||||||
|
| Variável | Obrigatória | Padrão | Descrição |
|
||||||
|
|----------------------|-------------|-------------------------------|----------------------------------------------|
|
||||||
|
| `AWS_REGION` | Não | `us-east-2` | Região AWS usada para todos os serviços |
|
||||||
|
| `BEDROCK_MODEL_ARN` | **Sim** | — | ARN do modelo Claude no AWS Bedrock |
|
||||||
|
| `OUTPUT_BUCKET` | Não | `upflux-doc-analyzer` | Bucket S3 onde os resultados são salvos |
|
||||||
|
| `API_VERSION` | Não | `v1` | Prefixo de versão usado na chave do S3 |
|
||||||
|
| `LANGFUSE_HOST` | Não | `https://cloud.langfuse.com` | Host do servidor Langfuse (observabilidade) |
|
||||||
|
|
||||||
|
### Segredos (AWS Secrets Manager — Secret ID: `doc-analyzer`)
|
||||||
|
|
||||||
|
| Chave | Descrição |
|
||||||
|
|------------------------|----------------------------------------------------|
|
||||||
|
| `API-KEY` | Chave de autenticação da API (`X-API-Key`) |
|
||||||
|
| `AWS_ACCESS_KEY` | Access Key para acesso ao S3 de entrada |
|
||||||
|
| `AWS_SECRET_KEY` | Secret Key para acesso ao S3 de entrada |
|
||||||
|
| `LANGFUSE-SECRET-KEY` | Chave secreta do Langfuse |
|
||||||
|
| `LANGFUSE-PUBLIC-KEY` | Chave pública do Langfuse |
|
||||||
|
|
||||||
|
---
|
||||||
Reference in New Issue
Block a user