Files
ForgeLM/README.md
T

163 lines
9.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<div align="center">
# ForgeLM
**Inferência local de LLMs `.gguf` em Rust: API HTTP no estilo OpenAI, CLI e app
desktop Tauri com chat persistente e gerenciador de modelos — tudo rodando na sua máquina.**
![Linguagem](https://img.shields.io/badge/Rust-edition_2021-informational)
![Desktop](https://img.shields.io/badge/Tauri-v2-informational)
![Licença](https://img.shields.io/badge/licen%C3%A7a-MIT-informational)
[Início rápido](#in%C3%ADcio-r%C3%A1pido) · [Recursos](#o-que-existe-hoje) · [Como funciona](#como-funciona) · [Limitações](#limita%C3%A7%C3%B5es-conhecidas) · [Documentação](#documenta%C3%A7%C3%A3o)
</div>
> [!NOTE]
> **Estado do projeto:** em desenvolvimento (último commit em abril/2026). Segundo
> [`.planning/ROADMAP.md`](.planning/ROADMAP.md), as fases 1–4 (estado de rascunho do
> runtime, segurança dos comandos de ciclo de vida, workspace unificado e download de
> modelos do Hugging Face) estão concluídas e a fase 5 (validação de fontes de modelo)
> segue aberta. O histórico também registra os planos 06-01 a 06-03 (redesign do chat
> e da página de Configurações).
> [!IMPORTANT]
> **A API sobe aberta por padrão.** Sem `LOCALLLM_API_KEY` não há autenticação, o
> bind default é `0.0.0.0:8080` e o CORS libera `*`. Para uso fora de uma máquina
> confiável, defina a chave e restrinja `LOCALLLM_ADDR` e `LOCALLLM_CORS_ORIGINS`
> (veja [`docs/api/configuration.md`](docs/api/configuration.md)).
## O que existe hoje
| Superfície | Onde | O que entrega |
|---|---|---|
| **API HTTP local** | [`crates/inference-server`](crates/inference-server) | `GET /health`, `GET /v1/models` e `POST /v1/chat/completions` (com streaming SSE e `stream_options.include_usage`) |
| **CLI `localllm`** | [`crates/localllm-cli`](crates/localllm-cli) | Comandos `status`, `models`, `auth`, `config`, `bench`, `logs` e `doctor`; flags globais `--server`, `--api-key`, `--models-dir`, `--format text\|json` e `--dry-run` |
| **App desktop** | [`tauri-app`](tauri-app) | Runtime manager (modo `local` ou `remote`), chat persistente e página de Configurações com gerenciador de modelos |
| **Perfis de runtime** | [`crates/inference-core`](crates/inference-core) | `Turbo4B` (default), `balanced_9b` e `cpu_fallback`, ajustáveis por `LOCALLLM_GPU_LAYERS`, `LOCALLLM_CTX`, `LOCALLLM_BATCH`, etc. |
| **Runtime llama.cpp gerenciado** | [`crates/runtime-deps`](crates/runtime-deps) | Baixa o llama.cpp `b8358` (variantes CPU e CUDA 12.4), valida SHA-256 e guarda em cache local |
No app desktop:
- **Runtime manager** com estados `stopped`, `starting`, `ready`, `degraded`, `stopping` e `error`; o modo local inicia/para o processo e usa `GET /health` para saber se está pronto.
- **Gerenciador de modelos:** escaneia/importa `.gguf`, busca modelos no Hugging Face, baixa em streaming com progresso e cancelamento (token do Hugging Face opcional), troca o modelo carregado com um clique (*hot-swap*: para, grava o novo `model_path` e reinicia), apaga arquivos e abre a pasta no explorador.
- **Chat:** streaming, memória opcional de até 20 mensagens recentes, separação visual do raciocínio (`<think>…</think>`) da resposta final, contagem de tokens (por mensagem e por chat) e tokens/s, edição, reenvio e exclusão de mensagens.
## Início rápido
> [!WARNING]
> **Na primeira execução o servidor baixa o runtime do llama.cpp.** Se o runtime não
> for encontrado (`LLAMA_DLL_PATH`, ao lado do binário ou vendor legado), o `runtime-deps` baixa o
> pacote de `github.com/ggml-org/llama.cpp` (`b8358`). A variante CUDA 12.4 são dois
> zips (≈ 227 MB + ≈ 391 MB conforme o manifesto); a CPU, um zip de ≈ 37 MB. O
> servidor escolhe CUDA quando as camadas em GPU são `> 0` e cai para CPU caso não
> exista variante de GPU para o alvo.
**1. Subir a API local** (Windows `cmd`; em bash use `export`):
```bash
set LOCALLLM_MODEL=D:\caminho\modelo.gguf
cargo run -p inference-server
curl http://127.0.0.1:8080/health
curl http://127.0.0.1:8080/v1/models
```
**2. Usar a CLI:**
```bash
cargo run -p localllm-cli -- status
cargo run -p localllm-cli -- models list
```
**3. Abrir o app desktop:**
```bash
cd tauri-app
npm install
npm run tauri dev
```
No app, abra o Runtime Manager, escolha modo `local` ou `remote` e depois use o chat.
**Requisitos:** toolchain Rust atual, Node.js/NPM (app Tauri) e um modelo `.gguf` local.
GPU NVIDIA é opcional — existe o perfil `cpu_fallback`.
## Como funciona
```mermaid
flowchart LR
UI["App Tauri<br/>React + Rust"] -->|"HTTP /v1/chat/completions"| S
UI -->|"inicia / para / health"| S["inference-server<br/>Axum · binário localllm"]
CLI["localllm-cli"] -->|HTTP| S
S --> C["inference-core<br/>engine · sessão · sampler · perfis"]
C --> L["llama-sys<br/>carga dinâmica (libloading)"]
L --> R["llama.dll<br/>llama.cpp b8358"]
D["runtime-deps<br/>download + SHA-256"] --> R
S --> D
UI -->|"busca e download"| HF["Hugging Face"]
S -.-> M["metrics<br/>tokens e throughput"]
```
<details>
<summary>Crates e módulos</summary>
| Módulo | Responsabilidade |
|---|---|
| `crates/api-contracts` | Tipos compartilhados: chat completions, lista de modelos, health e erros |
| `crates/inference-core` | Engine de inferência local: carga do modelo, sessão, sampler e perfis de runtime |
| `crates/inference-server` | Camada HTTP em Axum: variáveis de ambiente, auth, CORS e aliases de modelo |
| `crates/localllm-cli` | CLI de operação e automação (clap) |
| `crates/metrics` | Contadores de uso de tokens e throughput |
| `crates/llama-sys` | Integração de baixo nível: carrega `llama.dll` dinamicamente via `libloading` |
| `crates/runtime-deps` | Resolve o runtime (override por env, binário adjacente, vendor legado ou cache gerenciado) e instala a partir de [`vendor/llama-runtime/manifest.json`](vendor/llama-runtime/manifest.json) |
| `tauri-app/` | App desktop: frontend React 18 + Vite + Tailwind, backend Tauri 2 em Rust |
Variáveis de ambiente do servidor (principais): `LOCALLLM_MODEL`, `LOCALLLM_ADDR`,
`LOCALLLM_MODEL_ALIASES`, `LOCALLLM_PROFILE`, `LOCALLLM_API_KEY`,
`LOCALLLM_AUTH_HEADER`, `LOCALLLM_AUTH_SCHEME`, `LOCALLLM_CORS_ORIGINS`,
`LOCALLLM_SYSTEM_PROMPT` e `LOCALLLM_ENABLE_TOOL_CALLS`. Detalhes em
[`docs/api/configuration.md`](docs/api/configuration.md).
</details>
## Limitações conhecidas
- A API expõe só três endpoints; a compatibilidade com a OpenAI é parcial e focada no fluxo de chat (`n` precisa ser `1`, `parallel_tool_calls` não é tratado como recurso suportado, `content` em partes vira texto consolidado).
- O raciocínio não aparece como campo separado na API; quem separa `<think>…</think>` é o frontend do app.
- Na CLI, a execução ao vivo está mais consolidada em `status`, `models list` e `bench throughput`; o restante da superfície é mais avançado no parser do que nas capacidades HTTP públicas.
- O chat usa `sql.js` carregado por CDN e persiste o banco exportado em `localStorage` — não é um banco nativo do sistema.
- No modo local o app precisa encontrar o binário `localllm`; o runtime manager faz polling periódico do snapshot (sem fluxo de eventos push).
- O manifesto do runtime ([`vendor/llama-runtime/manifest.json`](vendor/llama-runtime/manifest.json)) só lista variantes `windows-x64` (CPU e CUDA 12.4). Em outros alvos o servidor só sobe com um runtime já presente (binário adjacente ou `LLAMA_DLL_PATH`).
- Os scripts [`scripts/build-dev.sh`](scripts/build-dev.sh) e [`scripts/build-prod.sh`](scripts/build-prod.sh) compilam `vendor/llama.cpp` e exigem esse submódulo, que não está declarado no repositório (não há `.gitmodules`).
- `inference-server` e `localllm-cli` declaram ambos um binário chamado `localllm`; use `cargo run -p <crate>` para escolher qual executar.
## Execução local
```bash
cargo run -p inference-server # API em 0.0.0.0:8080 (precisa de LOCALLLM_MODEL)
cargo run -p localllm-cli -- status # CLI
cd tauri-app
npm install
npm run dev # só o frontend (Vite, porta 1420)
npm run tauri dev # app desktop completo
npm run build # tsc + vite build
npm test # vitest run
```
## Documentação
| Documento | Conteúdo |
|---|---|
| [`docs/README.md`](docs/README.md) | Índice da documentação |
| [`docs/api/overview.md`](docs/api/overview.md) · [`endpoints.md`](docs/api/endpoints.md) · [`configuration.md`](docs/api/configuration.md) | API: visão geral, referência HTTP e configuração |
| [`docs/cli/overview.md`](docs/cli/overview.md) · [`commands.md`](docs/cli/commands.md) | CLI: visão geral e referência de comandos |
| [`docs/app/overview.md`](docs/app/overview.md) · [`user-guide.md`](docs/app/user-guide.md) · [`backend-commands.md`](docs/app/backend-commands.md) | App desktop: visão geral, guia de uso e comandos Tauri |
| [`docs/developer/architecture.md`](docs/developer/architecture.md) | Arquitetura do workspace e fluxos entre módulos |
## Avisos
- Os binários de inferência vêm do [llama.cpp](https://github.com/ggml-org/llama.cpp) (releases oficiais baixadas e verificadas por SHA-256); modelos são buscados no [Hugging Face](https://huggingface.co) e seguem a licença de cada autor.
- Licença do workspace: MIT (declarada em [`Cargo.toml`](Cargo.toml); o repositório não inclui arquivo `LICENSE`).