Files

1317 lines
28 KiB
Markdown

# Documentação Técnica das APIs - OllaHubBackend
## Visão Geral
O **OllaHubBackend** é uma API REST desenvolvida em Rust (Actix Web) que fornece gerenciamento de modelos Ollama, operações criptográficas, gerenciamento de usuários e comunicação em tempo real via WebSocket.
### Base URL
- **Desenvolvimento**: `http://127.0.0.1:8080`
- **Produção**: [A definir]
### Versões da API
- **V1 (Legado)**: Endpoints implementados diretamente no `main.rs`
- **V2 (Modular)**: Endpoints organizados em módulos (`src/api/mod.rs`) - **Recomendado**
- **Usuários V1**: CRUD de usuários em `/api/v1/users`
### Swagger UI
Documentação interativa disponível em: `http://127.0.0.1:8080/docs`
---
## Autenticação
A API utiliza **JWT (JSON Web Tokens)** para autenticação. Endpoints protegidos requerem o header de autorização.
### Como Autenticar
```http
Authorization: Bearer <seu_token_jwt>
```
### Endpoints Protegidos
Os seguintes caminhos requerem autenticação JWT:
- `/api/v1/*` (todos os endpoints de usuários)
- `/v2/api/crypto/*` (todas as operações de criptografia)
- `/v2/api/models/*` (operações de modelos)
### Endpoints Públicos
- `GET /health`
- `GET /v2/health`
- `GET /v2/api/ollama/check`
- `POST /v2/api/ollama/install`
- `WS /v2/ws` (WebSocket)
### Configuração JWT
A chave secreta JWT é configurada via variável de ambiente:
- Variável: `JWT_SECRET`
- Padrão (dev): `changeme-dev-secret`
---
## Endpoints
### Sistema / Health
#### GET /health
Verifica o status básico da API.
**Autenticação**: Não requerida
**Resposta**:
```json
"ok"
```
**Exemplo**:
```bash
curl http://127.0.0.1:8080/health
```
---
#### GET /v2/health
Verifica o status da API V2.
**Autenticação**: Não requerida
**Resposta**:
```json
{
"status": "ok"
}
```
**Exemplo**:
```bash
curl http://127.0.0.1:8080/v2/health
```
---
### Ollama - Instalação e Verificação
#### GET /v2/api/ollama/check
Verifica se o Ollama está instalado e acessível no sistema.
**Autenticação**: Não requerida
**Resposta**:
```json
{
"installed": true,
"in_path": true,
"version": "0.1.15",
"service_running": true,
"api_status": "reachable",
"details": {
"native_version": "ollama version is 0.1.15",
"api_/api/version": "{\"version\":\"0.1.15\"}",
"api_/api/tags": "{\"models\":[...]}",
"security_antivirus_active": "false",
"security_antivirus_instructions": "..."
},
"issues": []
}
```
**Campos da Resposta**:
- `installed` (boolean): Se o Ollama está instalado
- `in_path` (boolean): Se o binário está no PATH
- `version` (string|null): Versão do Ollama
- `service_running` (boolean): Se o serviço está rodando
- `api_status` (string): `"reachable"`, `"unreachable"` ou `"degraded"`
- `details` (object): Detalhes técnicos da instalação
- `issues` (array): Lista de problemas encontrados
**Exemplo**:
```bash
curl http://127.0.0.1:8080/v2/api/ollama/check
```
---
#### POST /v2/api/ollama/install
Inicia o processo de instalação automática do Ollama (se não estiver instalado) e garante que o serviço esteja rodando. O progresso é enviado via WebSocket.
**Autenticação**: Não requerida
**Request Body** (opcional):
```json
{
"method": "auto",
"platform": "auto"
}
```
**Resposta**:
```json
{
"status": "started",
"operation_id": "550e8400-e29b-41d4-a716-446655440000"
}
```
**Campos da Resposta**:
- `status` (string): Status da operação (`"started"`)
- `operation_id` (string): UUID da operação para rastreamento via WebSocket
**Eventos WebSocket**:
- `Log`: Mensagens de log durante a instalação
- `Progress`: Progresso da instalação
- `Done`: Instalação concluída com sucesso
- `Error`: Erro durante a instalação
**Exemplo**:
```bash
curl -X POST http://127.0.0.1:8080/v2/api/ollama/install \
-H "Content-Type: application/json" \
-d '{"method": "auto", "platform": "auto"}'
```
**Notas**:
- A instalação é específica por plataforma (Windows, Linux, macOS)
- O progresso é enviado via WebSocket (`WS /v2/ws`)
- Em caso de falha, eventos `Error` são enviados via WebSocket
- Os endpoints V1 (`GET /ollama/install-check` e `POST /ollama/install`) foram removidos
---
### Modelos (V2)
#### GET /v2/api/models
Lista todos os modelos disponíveis do arquivo `modelList.json`.
**Autenticação**: Requerida (JWT)
**Resposta**:
```json
[
{
"name": "llama2",
"description": "Modelo LLaMA 2"
},
{
"name": "mistral",
"description": "Modelo Mistral"
}
]
```
**Códigos de Status**:
- `200 OK`: Sucesso
- `401 Unauthorized`: Token JWT inválido ou ausente
- `500 Internal Server Error`: Erro ao ler arquivo de modelos
**Exemplo**:
```bash
curl -H "Authorization: Bearer <token>" \
http://127.0.0.1:8080/v2/api/models
```
**JavaScript/TypeScript**:
```typescript
const response = await fetch('http://127.0.0.1:8080/v2/api/models', {
headers: {
'Authorization': `Bearer ${token}`
}
});
const models = await response.json();
```
---
#### POST /v2/api/models/install
Inicia a instalação (download) de um modelo do Ollama. O progresso é enviado via WebSocket.
**Autenticação**: Requerida (JWT)
**Request Body**:
```json
{
"name": "llama2:7b"
}
```
**Resposta**:
```json
{
"status": "started",
"model": "llama2:7b"
}
```
**Códigos de Status**:
- `202 Accepted`: Instalação iniciada
- `400 Bad Request`: Nome do modelo inválido
- `401 Unauthorized`: Token JWT inválido ou ausente
- `500 Internal Server Error`: Erro ao iniciar instalação
**Exemplo**:
```bash
curl -X POST \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{"name":"llama2:7b"}' \
http://127.0.0.1:8080/v2/api/models/install
```
**JavaScript/TypeScript**:
```typescript
const response = await fetch('http://127.0.0.1:8080/v2/api/models/install', {
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({ name: 'llama2:7b' })
});
const result = await response.json();
```
**Notas**:
- O progresso da instalação é enviado via WebSocket (`/v2/ws`)
- Conecte-se ao WebSocket antes de iniciar a instalação para receber eventos
- O formato do nome pode incluir tag: `"modelo:tag"` (ex: `"llama2:7b"`)
---
### Criptografia (V2)
Todas as operações de criptografia usam **AES-256-GCM** com chave de 32 bytes.
#### POST /v2/api/crypto/set-key
Define a chave de criptografia (deve ser chamado antes de usar encrypt/decrypt).
**Autenticação**: Requerida (JWT)
**Request Body**:
```json
{
"hex_key": "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
}
```
**Resposta**:
```json
{
"ok": true
}
```
**Códigos de Status**:
- `200 OK`: Chave definida com sucesso
- `400 Bad Request`: Chave inválida (deve ter 64 caracteres hex = 32 bytes)
- `401 Unauthorized`: Token JWT inválido ou ausente
- `409 Conflict`: Chave já foi definida anteriormente
**Exemplo**:
```bash
curl -X POST \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{"hex_key":"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"}' \
http://127.0.0.1:8080/v2/api/crypto/set-key
```
**Notas**:
- A chave é persistida no disco automaticamente
- Use a mesma chave no frontend para operações de criptografia
- A chave deve ter exatamente 64 caracteres hexadecimais (32 bytes)
---
#### POST /v2/api/crypto/rotate-key
Gera uma nova chave de criptografia aleatória e retorna em hexadecimal.
**Autenticação**: Requerida (JWT)
**Resposta**:
```json
{
"key": "a1b2c3d4e5f6789012345678901234567890abcdef1234567890abcdef123456"
}
```
**Códigos de Status**:
- `200 OK`: Chave rotacionada com sucesso
- `401 Unauthorized`: Token JWT inválido ou ausente
- `500 Internal Server Error`: Erro ao gerar/salvar chave
**Exemplo**:
```bash
curl -X POST \
-H "Authorization: Bearer <token>" \
http://127.0.0.1:8080/v2/api/crypto/rotate-key
```
**Notas**:
- A nova chave substitui a anterior
- Salve a chave retornada para uso no frontend
- A chave é automaticamente persistida no disco
---
#### POST /v2/api/crypto/encrypt
Criptografa dados usando AES-256-GCM.
**Autenticação**: Requerida (JWT)
**Request Body**:
```json
{
"data": "dados sensíveis para criptografar"
}
```
**Resposta**:
```json
{
"ciphertext": "base64_encoded_ciphertext_with_nonce"
}
```
**Códigos de Status**:
- `200 OK`: Criptografia bem-sucedida
- `400 Bad Request`: Chave não definida ou dados inválidos
- `401 Unauthorized`: Token JWT inválido ou ausente
**Exemplo**:
```bash
curl -X POST \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{"data":"minha senha secreta"}' \
http://127.0.0.1:8080/v2/api/crypto/encrypt
```
**Notas**:
- O nonce (12 bytes) é incluído automaticamente no início do ciphertext
- O resultado é retornado em Base64
- O formato do ciphertext: `[nonce 12 bytes][ciphertext]` (tudo em Base64)
---
#### POST /v2/api/crypto/decrypt
Descriptografa dados usando AES-256-GCM.
**Autenticação**: Requerida (JWT)
**Request Body**:
```json
{
"data": "base64_encoded_ciphertext_with_nonce"
}
```
**Resposta**:
```json
{
"plaintext": "dados descriptografados"
}
```
**Códigos de Status**:
- `200 OK`: Descriptografia bem-sucedida
- `400 Bad Request`: Chave não definida, Base64 inválido ou tag de autenticação inválida
- `401 Unauthorized`: Token JWT inválido ou ausente
**Exemplo**:
```bash
curl -X POST \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{"data":"ciphertext_base64_aqui"}' \
http://127.0.0.1:8080/v2/api/crypto/decrypt
```
**Notas**:
- O nonce é extraído automaticamente dos primeiros 12 bytes
- O `data` deve ser o mesmo `ciphertext` retornado por `encrypt`
- A tag de autenticação GCM é verificada automaticamente
---
### Usuários (V1)
#### GET /api/v1/users
Lista todos os usuários cadastrados.
**Autenticação**: Requerida (JWT)
**Resposta**:
```json
[
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "João Silva",
"email": "[email protected]"
},
{
"id": "660e8400-e29b-41d4-a716-446655440001",
"name": "Maria Santos",
"email": "[email protected]"
}
]
```
**Códigos de Status**:
- `200 OK`: Sucesso
- `401 Unauthorized`: Token JWT inválido ou ausente
**Exemplo**:
```bash
curl -H "Authorization: Bearer <token>" \
http://127.0.0.1:8080/api/v1/users
```
---
#### GET /api/v1/users/{id}
Obtém um usuário específico por ID.
**Autenticação**: Requerida (JWT)
**Parâmetros de Path**:
- `id` (string): UUID do usuário
**Resposta**:
```json
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "João Silva",
"email": "[email protected]"
}
```
**Códigos de Status**:
- `200 OK`: Usuário encontrado
- `401 Unauthorized`: Token JWT inválido ou ausente
- `404 Not Found`: Usuário não encontrado
**Exemplo**:
```bash
curl -H "Authorization: Bearer <token>" \
http://127.0.0.1:8080/api/v1/users/550e8400-e29b-41d4-a716-446655440000
```
---
#### POST /api/v1/users
Cria um novo usuário.
**Autenticação**: Requerida (JWT)
**Request Body**:
```json
{
"name": "João Silva",
"email": "[email protected]"
}
```
**Validações**:
- `name`: Mínimo 2 caracteres
- `email`: Formato de email válido
**Resposta**:
```json
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "João Silva",
"email": "[email protected]"
}
```
**Códigos de Status**:
- `201 Created`: Usuário criado com sucesso
- `400 Bad Request`: Erro de validação
- `401 Unauthorized`: Token JWT inválido ou ausente
**Exemplo**:
```bash
curl -X POST \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{"name":"João Silva","email":"[email protected]"}' \
http://127.0.0.1:8080/api/v1/users
```
---
#### PUT /api/v1/users/{id}
Atualiza um usuário existente.
**Autenticação**: Requerida (JWT)
**Parâmetros de Path**:
- `id` (string): UUID do usuário
**Request Body**:
```json
{
"name": "João Silva Atualizado",
"email": "[email protected]"
}
```
**Validações**:
- `name`: Mínimo 2 caracteres (opcional)
- `email`: Formato de email válido (opcional)
**Resposta**:
```json
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "João Silva Atualizado",
"email": "[email protected]"
}
```
**Códigos de Status**:
- `200 OK`: Usuário atualizado
- `400 Bad Request`: Erro de validação
- `401 Unauthorized`: Token JWT inválido ou ausente
- `404 Not Found`: Usuário não encontrado
**Exemplo**:
```bash
curl -X PUT \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{"name":"João Silva Atualizado","email":"[email protected]"}' \
http://127.0.0.1:8080/api/v1/users/550e8400-e29b-41d4-a716-446655440000
```
---
#### DELETE /api/v1/users/{id}
Remove um usuário.
**Autenticação**: Requerida (JWT)
**Parâmetros de Path**:
- `id` (string): UUID do usuário
**Resposta**: Sem corpo (204 No Content)
**Códigos de Status**:
- `204 No Content`: Usuário removido
- `401 Unauthorized`: Token JWT inválido ou ausente
- `404 Not Found`: Usuário não encontrado
**Exemplo**:
```bash
curl -X DELETE \
-H "Authorization: Bearer <token>" \
http://127.0.0.1:8080/api/v1/users/550e8400-e29b-41d4-a716-446655440000
```
---
### WebSocket (V2)
#### WS /v2/ws
Endpoint WebSocket para receber eventos em tempo real, especialmente durante a instalação de modelos.
**Autenticação**: Não requerida (mas pode ser implementada)
**Conexão**:
```
ws://127.0.0.1:8080/v2/ws
```
**Tipos de Eventos**:
1. **Log**: Mensagens de log durante operações
```json
{
"kind": "Log",
"message": "Downloading model llama2:7b..."
}
```
2. **Progress**: Progresso de operações (ex: download de modelo)
```json
{
"kind": "Progress",
"message": "{\"status\":\"downloading\",\"completed\":50,\"total\":100}"
}
```
3. **Done**: Operação concluída
```json
{
"kind": "Done",
"message": "Download do modelo 'llama2:7b' concluído"
}
```
4. **Error**: Erro durante operação
```json
{
"kind": "Error",
"message": "Falha ao conectar com API do Ollama"
}
```
**Exemplo JavaScript**:
```javascript
const ws = new WebSocket('ws://127.0.0.1:8080/v2/ws');
ws.onopen = () => {
console.log('WebSocket conectado');
};
ws.onmessage = (event) => {
const data = JSON.parse(event.data);
console.log('Evento recebido:', data);
switch(data.kind) {
case 'Log':
console.log('Log:', data.message);
break;
case 'Progress':
console.log('Progresso:', data.message);
break;
case 'Done':
console.log('Concluído:', data.message);
break;
case 'Error':
console.error('Erro:', data.message);
break;
}
};
ws.onerror = (error) => {
console.error('Erro WebSocket:', error);
};
ws.onclose = () => {
console.log('WebSocket desconectado');
};
```
**Exemplo TypeScript**:
```typescript
enum WsEventKind {
Log = 'Log',
Progress = 'Progress',
Done = 'Done',
Error = 'Error'
}
interface WsEvent {
kind: WsEventKind;
message: string;
}
const ws = new WebSocket('ws://127.0.0.1:8080/v2/ws');
ws.onmessage = (event: MessageEvent) => {
const data: WsEvent = JSON.parse(event.data);
// Processar evento
};
```
**Fluxo de Instalação de Modelo**:
1. Conecte-se ao WebSocket
2. Chame `POST /v2/api/models/install` com o nome do modelo
3. Receba eventos via WebSocket:
- `Log`: Mensagens de progresso
- `Progress`: Atualizações de progresso (se disponível)
- `Done`: Instalação concluída
- `Error`: Erro durante instalação
**Notas**:
- O WebSocket mantém a conexão aberta para receber múltiplos eventos
---
### WebSocket Chat (`/v2/ws/chat`)
Endpoint WebSocket dedicado para chat com modelos Ollama, oferecendo streaming em tempo real das respostas.
#### Conectar
```javascript
const ws = new WebSocket('ws://127.0.0.1:8080/v2/ws/chat');
ws.onopen = () => {
console.log('Chat WebSocket conectado');
// Enviar mensagem de chat
const chatRequest = {
model: "llama2",
messages: [
{ role: "user", content: "Olá, como você está?" }
],
stream: true,
options: {
temperature: 0.7,
top_p: 0.9
}
};
ws.send(JSON.stringify(chatRequest));
};
ws.onmessage = (event) => {
const response = JSON.parse(event.data);
if (response.done) {
console.log('Chat finalizado');
return;
}
if (response.message) {
// Acumular conteúdo da mensagem
console.log('Chunk recebido:', response.message.content);
}
if (response.error) {
console.error('Erro no chat:', response.error);
}
};
ws.onerror = (error) => {
console.error('Erro WebSocket chat:', error);
};
ws.onclose = () => {
console.log('Chat WebSocket desconectado');
};
```
#### Formato da Requisição
```json
{
"model": "llama2",
"messages": [
{ "role": "user", "content": "Sua mensagem aqui" },
{ "role": "assistant", "content": "Resposta anterior" }
],
"stream": true,
"options": {
"temperature": 0.7,
"top_p": 0.9,
"top_k": 40
}
}
```
**Campos**:
- `model` (string, obrigatório): Nome do modelo a ser usado
- `messages` (array, obrigatório): Array de mensagens no formato `{ role: "user"|"assistant", content: string }`
- `stream` (boolean, opcional): Sempre `true` para streaming (padrão: `true`)
- `options` (object, opcional): Opções do modelo (temperature, top_p, top_k, etc.)
#### Formato da Resposta (Streaming)
Cada chunk recebido é um objeto JSON:
```json
{
"model": "llama2",
"created_at": "2024-01-01T12:00:00Z",
"message": {
"role": "assistant",
"content": "Olá! Estou bem, obrigado por perguntar."
},
"done": false
}
```
**Último chunk** (quando `done: true`):
```json
{
"model": "llama2",
"created_at": "2024-01-01T12:00:05Z",
"message": null,
"done": true,
"total_duration": 5000000000,
"load_duration": 100000000,
"prompt_eval_count": 10,
"prompt_eval_duration": 200000000,
"eval_count": 50,
"eval_duration": 4700000000
}
```
#### Características
- **Streaming em tempo real**: Respostas são enviadas chunk por chunk conforme geradas
- **Baixa latência**: WebSocket mantém conexão persistente
- **Heartbeat**: Ping/pong automático a cada 5 segundos
- **Timeout**: Desconexão automática após 30 segundos de inatividade
- **Múltiplas conversas**: Uma conexão pode enviar múltiplas requisições de chat
#### Exemplo Completo: Conversa com Histórico
```javascript
const ws = new WebSocket('ws://127.0.0.1:8080/v2/ws/chat');
let conversationHistory = [];
ws.onopen = () => {
sendMessage("Olá!");
};
function sendMessage(userMessage) {
// Adicionar mensagem do usuário ao histórico
conversationHistory.push({ role: "user", content: userMessage });
const request = {
model: "llama2",
messages: conversationHistory,
stream: true
};
ws.send(JSON.stringify(request));
}
ws.onmessage = (event) => {
const response = JSON.parse(event.data);
if (response.done) {
// Adicionar resposta completa ao histórico
if (response.message) {
conversationHistory.push(response.message);
}
console.log('Conversa atualizada:', conversationHistory);
return;
}
// Acumular chunks da resposta
if (response.message && response.message.content) {
process.stdout.write(response.message.content);
}
};
// Enviar próxima mensagem após resposta completa
ws.onmessage = (event) => {
const response = JSON.parse(event.data);
if (response.done) {
if (response.message) {
conversationHistory.push(response.message);
}
// Próxima mensagem do usuário
sendMessage("Conte-me uma piada");
} else if (response.message) {
process.stdout.write(response.message.content);
}
};
```
#### Tratamento de Erros
```javascript
ws.onmessage = (event) => {
const response = JSON.parse(event.data);
if (response.error) {
console.error('Erro do Ollama:', response.error);
// Erro pode ocorrer em qualquer chunk
}
if (response.done && response.error) {
// Erro final - conexão pode ser fechada
ws.close();
}
};
```
#### Notas Importantes
- O endpoint requer autenticação JWT (mesmo token usado em outras APIs)
- O WebSocket mantém a conexão aberta para múltiplas requisições
- Cada requisição deve incluir o histórico completo da conversa
- Respostas são enviadas em formato JSON lines (uma linha por chunk)
- Use `done: true` para saber quando a resposta está completa
- Eventos são broadcast para todos os clientes conectados
- Ping/Pong são gerenciados automaticamente
---
## Modelos de Dados
### User
```typescript
interface User {
id: string; // UUID
name: string; // Mínimo 2 caracteres
email: string; // Email válido
}
```
### CreateUserRequest
```typescript
interface CreateUserRequest {
name: string; // Mínimo 2 caracteres
email: string; // Email válido
}
```
### UpdateUserRequest
```typescript
interface UpdateUserRequest {
name?: string; // Mínimo 2 caracteres (opcional)
email?: string; // Email válido (opcional)
}
```
### ModelInfo
```typescript
interface ModelInfo {
name: string;
description?: string;
}
```
### InstallReq
```typescript
interface InstallReq {
name: string; // Nome do modelo (ex: "llama2:7b")
}
```
### SetKeyReq
```typescript
interface SetKeyReq {
hex_key: string; // 64 caracteres hex (32 bytes)
}
```
### CryptReq
```typescript
interface CryptReq {
data: string; // Dados para criptografar/descriptografar
}
```
### ApiErrorBody
```typescript
interface ApiErrorBody {
error: string; // Mensagem de erro
}
```
### WsEvent
```typescript
enum WsEventKind {
Log = 'Log',
Progress = 'Progress',
Done = 'Done',
Error = 'Error'
}
interface WsEvent {
kind: WsEventKind;
message: string;
}
```
---
## Tratamento de Erros
### Códigos de Status HTTP
- `200 OK`: Requisição bem-sucedida
- `201 Created`: Recurso criado com sucesso
- `202 Accepted`: Requisição aceita para processamento assíncrono
- `204 No Content`: Sucesso sem conteúdo de retorno
- `400 Bad Request`: Erro na requisição (validação, formato)
- `401 Unauthorized`: Token JWT ausente ou inválido
- `404 Not Found`: Recurso não encontrado
- `409 Conflict`: Conflito (ex: chave já definida)
- `500 Internal Server Error`: Erro interno do servidor
### Formato de Erro
Todos os erros retornam o seguinte formato:
```json
{
"error": "Mensagem de erro descritiva"
}
```
### Exemplos de Erros
**400 Bad Request**:
```json
{
"error": "validação: email: deve ser um email válido"
}
```
**401 Unauthorized**:
```json
{
"error": "Token JWT inválido ou ausente"
}
```
**404 Not Found**:
```json
{
"error": "Usuário não encontrado"
}
```
**500 Internal Server Error**:
```json
{
"error": "Falha ao ler arquivo de modelos: No such file or directory"
}
```
---
## Variáveis de Ambiente
### OLLAMA_BASE_URL
- **Descrição**: URL base da API do Ollama
- **Padrão**: `http://localhost:11434`
- **Uso**: Usado para comunicação com o Ollama
### MODEL_LIST_PATH
- **Descrição**: Caminho para o arquivo JSON com lista de modelos
- **Padrão**: `modelList.json`
- **Uso**: Arquivo lido para listar modelos disponíveis
### JWT_SECRET
- **Descrição**: Chave secreta para assinatura de tokens JWT
- **Padrão**: `changeme-dev-secret`
- **Uso**: Validação de tokens JWT
- **Importante**:
- Deve ser o **mesmo valor** usado no frontend para gerar tokens
- Altere em produção!
- Pode ser configurado via variável de ambiente ou arquivo `.env`
**Configuração via `.env`** (recomendado):
```env
JWT_SECRET=5741f9da3be6007674a5e10edab7b124
```
**Configuração via variável de ambiente**:
```bash
# Windows (PowerShell)
$env:JWT_SECRET="5741f9da3be6007674a5e10edab7b124"
# Linux/Mac
export JWT_SECRET="5741f9da3be6007674a5e10edab7b124"
```
### SKIP_ANTIVIRUS_WARNINGS
- **Descrição**: Suprime avisos de verificação de antivírus durante inicialização
- **Padrão**: `false`
- **Valores**: `true` ou `false`
- **Uso**: Define como `true` para desabilitar avisos informativos sobre antivírus/segurança
- **Exemplo**: `SKIP_ANTIVIRUS_WARNINGS=true cargo run`
---
## Exemplos de Fluxos Completos
### Fluxo 1: Instalar um Modelo com Acompanhamento via WebSocket
```javascript
// 1. Conectar ao WebSocket
const ws = new WebSocket('ws://127.0.0.1:8080/v2/ws');
ws.onmessage = (event) => {
const data = JSON.parse(event.data);
if (data.kind === 'Done') {
console.log('Modelo instalado!');
}
};
// 2. Aguardar conexão
ws.onopen = async () => {
// 3. Iniciar instalação
const response = await fetch('http://127.0.0.1:8080/v2/api/models/install', {
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({ name: 'llama2:7b' })
});
const result = await response.json();
console.log('Instalação iniciada:', result);
};
```
### Fluxo 2: Configurar Criptografia e Criptografar Dados
```javascript
// 1. Definir chave (ou rotacionar)
const rotateResponse = await fetch('http://127.0.0.1:8080/v2/api/crypto/rotate-key', {
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`
}
});
const { key } = await rotateResponse.json();
console.log('Nova chave:', key);
// 2. Criptografar dados
const encryptResponse = await fetch('http://127.0.0.1:8080/v2/api/crypto/encrypt', {
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({ data: 'dados sensíveis' })
});
const { ciphertext } = await encryptResponse.json();
console.log('Dados criptografados:', ciphertext);
// 3. Descriptografar
const decryptResponse = await fetch('http://127.0.0.1:8080/v2/api/crypto/decrypt', {
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({ data: ciphertext })
});
const { plaintext } = await decryptResponse.json();
console.log('Dados descriptografados:', plaintext);
```
### Fluxo 3: CRUD Completo de Usuários
```javascript
const baseUrl = 'http://127.0.0.1:8080/api/v1/users';
const headers = {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
};
// 1. Criar usuário
const createResponse = await fetch(baseUrl, {
method: 'POST',
headers,
body: JSON.stringify({
name: 'João Silva',
email: '[email protected]'
})
});
const newUser = await createResponse.json();
console.log('Usuário criado:', newUser);
// 2. Listar usuários
const listResponse = await fetch(baseUrl, { headers });
const users = await listResponse.json();
console.log('Usuários:', users);
// 3. Obter usuário específico
const getUserResponse = await fetch(`${baseUrl}/${newUser.id}`, { headers });
const user = await getUserResponse.json();
console.log('Usuário:', user);
// 4. Atualizar usuário
const updateResponse = await fetch(`${baseUrl}/${newUser.id}`, {
method: 'PUT',
headers,
body: JSON.stringify({
name: 'João Silva Atualizado',
email: '[email protected]'
})
});
const updatedUser = await updateResponse.json();
console.log('Usuário atualizado:', updatedUser);
// 5. Deletar usuário
await fetch(`${baseUrl}/${newUser.id}`, {
method: 'DELETE',
headers
});
console.log('Usuário deletado');
```
---
## Notas Importantes
### Segurança
1. **JWT Secret**: Sempre altere o `JWT_SECRET` em produção
2. **HTTPS**: Use HTTPS em produção para proteger tokens e dados
3. **Chave de Criptografia**: Mantenha a chave de criptografia segura e nunca a exponha
4. **Validação**: Todos os inputs são validados no backend
### Performance
1. **WebSocket**: Use WebSocket para operações longas (instalação de modelos)
2. **Assíncrono**: Instalação de modelos é assíncrona (202 Accepted)
3. **Cache**: Considere cachear lista de modelos no frontend
### Compatibilidade
1. **V1 vs V2**: Prefira endpoints V2 quando disponíveis
2. **Swagger**: Use `/docs` para documentação interativa
3. **Versões**: Endpoints V1 podem ser descontinuados no futuro
### Limitações
1. **Armazenamento de Usuários**: Atualmente em memória (perdido ao reiniciar)
2. **Chave de Criptografia**: Uma chave por instância do servidor
3. **WebSocket**: Broadcast para todos os clientes (não filtrado por operação)
---
## Suporte e Recursos
- **Swagger UI**: `http://127.0.0.1:8080/docs`
- **Health Check**: `http://127.0.0.1:8080/health`
- **Código Fonte**: Ver repositório do projeto
---
**Última Atualização**: 2024