docs(readme): redesenha o README com hero em SVG [skip ci]
This commit is contained in:
1 parent
10cc9c90c0
commit
b18ed657d6
2 files changed
+130
-146
No files matched your search
@@ -1,77 +1,62 @@
|
||||
<div align="center">
|
||||
|
||||
<h1>ForgeLM</h1>
|
||||
<img src="assets/readme/hero.svg" width="100%" alt="ForgeLM: roda modelos .gguf na sua máquina com uma API no estilo OpenAI, em Rust sobre o llama.cpp">
|
||||
|
||||
<p><strong>Inferência local de LLMs <code>.gguf</code> em Rust: API no estilo OpenAI, CLI e app desktop Tauri, tudo na sua máquina.</strong></p>
|
||||

|
||||

|
||||

|
||||

|
||||
|
||||
<a href="#-quickstart">Quickstart</a> ·
|
||||
<a href="#-arquitetura">Arquitetura</a> ·
|
||||
<a href="#-documenta%C3%A7%C3%A3o">Documentação</a> ·
|
||||
<a href="https://git.evandro.dev.br/evandro/ForgeLM/issues">Issues</a>
|
||||
|
||||

|
||||

|
||||

|
||||
[Início rápido](#in%C3%ADcio-r%C3%A1pido) · [Documentação](docs/README.md) · [Issues](https://git.evandro.dev.br/evandro/ForgeLM/issues)
|
||||
|
||||
</div>
|
||||
|
||||
<hr />
|
||||
|
||||
> [!NOTE]
|
||||
> **Este projeto não está concluído.** O que está descrito abaixo é o que existe hoje no código. Segundo [`.planning/ROADMAP.md`](.planning/ROADMAP.md), as fases 1–4 estão concluídas; a fase 5 (validação de fontes de modelo) segue aberta no roadmap e a fase 6 (redesign do chat) consta como planejada.
|
||||
|
||||
## 📌 O problema
|
||||
|
||||
Rodar um modelo `.gguf` na própria máquina exige juntar peças soltas: um runtime do llama.cpp compatível com a sua GPU, uma API que clientes no estilo OpenAI consigam chamar e um lugar para escolher modelos e conversar. O ForgeLM reúne essas peças em um workspace Rust local-first, sem depender de infraestrutura hospedada, e documenta o que ainda não funciona.
|
||||
|
||||
## ✨ O que faz (o que existe hoje)
|
||||
|
||||
- **Serve** `GET /health`, `GET /v1/models` e `POST /v1/chat/completions` em `:8080`, com streaming SSE e `stream_options.include_usage`.
|
||||
- **Carrega** modelos `.gguf` via llama.cpp (carga dinâmica) com os perfis `Turbo4B` (default), `balanced_9b` e `cpu_fallback`, ajustáveis por variáveis de ambiente.
|
||||
- **Baixa e valida** o runtime llama.cpp `b8358` (CPU ou CUDA 12.4, com SHA-256) quando ele não é encontrado.
|
||||
- **Opera** pela CLI `localllm`: `status`, `models`, `auth`, `config`, `bench`, `logs` e `doctor`.
|
||||
- **Gerencia** o runtime no app desktop (modo `local` ou `remote`; estados `stopped`, `starting`, `ready`, `degraded`, `stopping` e `error`).
|
||||
- **Escaneia, importa, busca e baixa** modelos do Hugging Face com progresso e cancelamento (token opcional) e troca o modelo carregado com um clique (*hot-swap*).
|
||||
- **Conversa** com streaming, memória opcional de até 20 mensagens, separação de `<think>…</think>`, contagem de tokens, tokens/s e edição, reenvio e exclusão de mensagens.
|
||||
- **Protege** a API com chave opcional (`LOCALLLM_API_KEY`), CORS configurável e aliases de modelo.
|
||||
|
||||
## 🖼️ Demonstração
|
||||
|
||||
Capturas do shell do app com a API local offline e nenhum modelo selecionado: mostram o layout, não uma inferência em andamento.
|
||||
|
||||
<p align="center">
|
||||
<img src="./loaded-shell.png" alt="Shell do app ForgeLM em desktop: Runtime Manager, lista de conversas e área de chat" width="720" />
|
||||
<img src="loaded-shell.png" width="720" alt="App desktop do ForgeLM: Runtime Manager com a API local parada, lista de conversas vazia e área de chat">
|
||||
</p>
|
||||
<p align="center"><sub>Captura do import inicial (março de 2026), com a API local parada. A interface mudou depois: o seletor de modelo foi para a caixa de mensagem.</sub></p>
|
||||
|
||||
<p align="center">
|
||||
<img src="./loaded-tablet.png" alt="Shell do app ForgeLM em tablet" height="360" />
|
||||
<img src="./loaded-mobile.png" alt="Shell do app ForgeLM em tela estreita" height="360" />
|
||||
</p>
|
||||
## O que é
|
||||
|
||||
## 🚀 Quickstart
|
||||
O ForgeLM roda modelos `.gguf` na sua máquina com o [llama.cpp](https://github.com/ggml-org/llama.cpp) e os expõe numa API HTTP no estilo OpenAI, com streaming SSE. O mesmo workspace Rust traz uma CLI (`localllm`) e um app desktop em Tauri que liga o servidor, busca e baixa modelos do [Hugging Face](https://huggingface.co) e conversa com eles.
|
||||
|
||||
## Por que usar
|
||||
|
||||
- **Uma peça só, local.** Servidor, engine, download do runtime e app vivem num workspace Rust. Na primeira execução o servidor baixa o llama.cpp `b8358` (CPU ou CUDA 12.4) do GitHub e confere o SHA-256, se não achar um runtime já instalado.
|
||||
- **Clientes OpenAI funcionam com poucas mudanças.** `GET /v1/models` e `POST /v1/chat/completions` seguem o formato da OpenAI; basta trocar a URL base.
|
||||
- **Perfis prontos.** `Turbo4B` (padrão), `balanced_9b` e `cpu_fallback` definem camadas na GPU, contexto e threads, e cada valor pode ser sobrescrito por variável de ambiente.
|
||||
|
||||
**Quando não usar:** se você precisa de compatibilidade ampla com a OpenAI (são três endpoints, `n` precisa ser `1`, sem embeddings), de download automático do runtime fora do Windows x64, ou de algo estável. Nesses casos, o servidor do próprio llama.cpp atende melhor.
|
||||
|
||||
## Como funciona
|
||||
|
||||
- `inference-server` (binário `localllm`): API em Axum na porta `8080`. Valida autenticação, CORS e aliases e repassa ao `inference-core`.
|
||||
- `inference-core`: engine, sessão, sampler e perfis, sobre o `llama-sys`, que carrega o `llama.dll` em tempo de execução.
|
||||
- `runtime-deps`: acha ou baixa o runtime descrito em [`vendor/llama-runtime/manifest.json`](vendor/llama-runtime/manifest.json).
|
||||
- `localllm-cli`: cliente HTTP da mesma API, com `status`, `models`, `auth`, `config`, `bench`, `logs` e `doctor`.
|
||||
- `tauri-app`: React 18 + Vite + Tailwind com backend Tauri 2. No modo `local` inicia e para o servidor e consulta `GET /health`; no modo `remote` só fala com a API. A busca de modelos no Hugging Face não passa pela API local.
|
||||
|
||||
Detalhes em [`docs/developer/architecture.md`](docs/developer/architecture.md).
|
||||
|
||||
## Início rápido
|
||||
|
||||
> [!WARNING]
|
||||
> **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 `*`. Fora de uma máquina confiável, defina a chave e restrinja `LOCALLLM_ADDR` e `LOCALLLM_CORS_ORIGINS`.
|
||||
> **A API sobe aberta por padrão.** Sem `LOCALLLM_API_KEY` não há autenticação, o bind padrão é `0.0.0.0:8080` e o CORS libera `*`. Fora de uma máquina confiável, defina a chave e restrinja `LOCALLLM_ADDR` e `LOCALLLM_CORS_ORIGINS`.
|
||||
|
||||
| Ferramenta | Versão mínima |
|
||||
|---|---|
|
||||
| Rust (cargo) | edition 2021; `rust-version` não declarada |
|
||||
| Node.js + npm (só para o app) | não declarada (sem `.nvmrc` nem `engines`) |
|
||||
| Modelo `.gguf` local | obrigatório |
|
||||
| GPU NVIDIA | opcional (variante CUDA 12.4; existe o perfil `cpu_fallback`) |
|
||||
Requisitos: Rust (cargo; o projeto não declara `rust-version`), um modelo `.gguf` local e, só para o app, Node.js com npm (sem versão declarada). GPU NVIDIA é opcional: o perfil `cpu_fallback` roda sem ela.
|
||||
|
||||
**Na primeira execução o servidor baixa o llama.cpp `b8358`** de `github.com/ggml-org/llama.cpp` se não achar o runtime (`LLAMA_DLL_PATH`, binário adjacente ou vendor legado). CUDA 12.4 são dois zips (≈ 227 MB + ≈ 391 MB); CPU, um zip de ≈ 37 MB. O manifesto só lista `windows-x64`.
|
||||
Na primeira execução, o download do runtime tem cerca de 37 MB na variante CPU e cerca de 618 MB na CUDA 12.4 (dois zips). O manifesto só lista `windows-x64`; em outros sistemas, aponte `LLAMA_DLL_PATH` para uma biblioteca já instalada.
|
||||
|
||||
```bash
|
||||
# 1. API local (Windows cmd; em bash use `export`)
|
||||
set LOCALLLM_MODEL=D:\modelos\meu-modelo.gguf
|
||||
# 1. API local (bash; no cmd do Windows, use set no lugar de export)
|
||||
export LOCALLLM_MODEL=/caminho/para/meu-modelo.gguf
|
||||
cargo run -p inference-server
|
||||
|
||||
curl http://127.0.0.1:8080/health
|
||||
curl http://127.0.0.1:8080/v1/models
|
||||
curl -N http://127.0.0.1:8080/v1/chat/completions \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"model":"default","messages":[{"role":"user","content":"Diga ola"}],"stream":true}'
|
||||
-d '{"model":"default","messages":[{"role":"user","content":"Diga olá"}],"stream":true}'
|
||||
|
||||
# 2. CLI
|
||||
cargo run -p localllm-cli -- status
|
||||
@@ -83,117 +68,56 @@ npm install
|
||||
npm run tauri dev
|
||||
```
|
||||
|
||||
### Variáveis de ambiente
|
||||
Testes: `cargo test` (crates do workspace), `cargo test --manifest-path tauri-app/src-tauri/Cargo.toml` (backend Tauri, fora do workspace) e `npm test` em `tauri-app` (Vitest).
|
||||
|
||||
Extraídas do código e de [`docs/api/configuration.md`](docs/api/configuration.md); não há `.env.example`. O prefixo é `LOCALLLM_` (três L).
|
||||
## Configuração
|
||||
|
||||
A API lê tudo de variáveis de ambiente; não há `.env.example`. A pasta de modelos não é variável: na CLI é a flag global `--models-dir` (padrão `./models`), no app é o campo `models_dir` da configuração do runtime. Ao iniciar o servidor local, o app define `LOCALLLM_MODEL`, `LOCALLLM_ADDR`, `LOCALLLM_GPU_LAYERS` e `LOCALLLM_CTX` (contexto padrão do app: 4096).
|
||||
|
||||
<details>
|
||||
<summary>Variáveis de ambiente da API</summary>
|
||||
|
||||
| Variável | Obrigatória | Descrição |
|
||||
|---|---|---|
|
||||
| `LOCALLLM_MODEL` | Sim | Caminho do `.gguf`; sem ele o engine aborta (`model_path is empty`) |
|
||||
| `LOCALLLM_ADDR` | Não | Endereço de bind; default `0.0.0.0:8080` |
|
||||
| `LOCALLLM_MODEL` | Sim | Caminho do `.gguf`; sem ela o engine aborta (`model_path is empty`) |
|
||||
| `LOCALLLM_ADDR` | Não | Endereço de bind; padrão `0.0.0.0:8080` |
|
||||
| `LOCALLLM_MODEL_ALIASES` | Não | Aliases do modelo, separados por vírgula, expostos em `GET /v1/models` |
|
||||
| `LOCALLLM_PROFILE` | Não | `balanced_9b` ou `cpu_fallback`; ausente ou outro valor = `Turbo4B` |
|
||||
| `LOCALLLM_GPU_LAYERS` | Não | Camadas na GPU; default do perfil (999 em `Turbo4B`/`balanced_9b`, 0 em `cpu_fallback`) |
|
||||
| `LOCALLLM_CTX` | Não | Janela de contexto; default do perfil (4096, 2048 e 2048) |
|
||||
| `LOCALLLM_GPU_LAYERS` | Não | Camadas na GPU; padrão do perfil (999 em `Turbo4B` e `balanced_9b`, 0 em `cpu_fallback`) |
|
||||
| `LOCALLLM_CTX` | Não | Janela de contexto; padrão do perfil (131072, 65536 e 16384) |
|
||||
| `LOCALLLM_BATCH` | Não | `n_batch`; sem valor explícito, usa o do perfil limitado a 4096 |
|
||||
| `LOCALLLM_UBATCH` | Não | `n_ubatch`; default do perfil |
|
||||
| `LOCALLLM_THREADS` | Não | Threads de geração; default do perfil |
|
||||
| `LOCALLLM_THREADS_BATCH` | Não | Threads de prefill; default do perfil |
|
||||
| `LOCALLLM_API_KEY` | Não | Habilita autenticação por chave; vazia ou ausente = API aberta |
|
||||
| `LOCALLLM_AUTH_HEADER` | Não | Cabeçalho preferencial da chave; default `authorization` (também aceita `x-api-key`) |
|
||||
| `LOCALLLM_UBATCH` | Não | `n_ubatch`; padrão do perfil |
|
||||
| `LOCALLLM_THREADS` | Não | Threads de geração; padrão do perfil |
|
||||
| `LOCALLLM_THREADS_BATCH` | Não | Threads de prefill; padrão do perfil |
|
||||
| `LOCALLLM_API_KEY` | Não | Liga a autenticação por chave; vazia ou ausente = API aberta |
|
||||
| `LOCALLLM_AUTH_HEADER` | Não | Cabeçalho preferencial da chave; padrão `authorization` (também aceita `x-api-key`) |
|
||||
| `LOCALLLM_AUTH_SCHEME` | Não | Prefixo removido antes da comparação (ex.: `Bearer`) |
|
||||
| `LOCALLLM_CORS_ORIGINS` | Não | Allowlist de origens separadas por vírgula; default `*` |
|
||||
| `LOCALLLM_CORS_ORIGINS` | Não | Origens permitidas, separadas por vírgula; padrão `*` |
|
||||
| `LOCALLLM_SYSTEM_PROMPT` | Não | Prompt de sistema usado quando a request não traz `system` nem `developer` |
|
||||
| `LOCALLLM_ENABLE_TOOL_CALLS` | Não | Liga/desliga tool calling; default ligado |
|
||||
| `LOCALLLM_LOG_FORMAT` | Não | `json` para logs estruturados; default `pretty` |
|
||||
| `LLAMA_DLL_PATH` | Não | Caminho completo do `llama.dll`; sobrepõe a resolução automática do runtime |
|
||||
| `RUST_LOG` | Não | Filtro de logs do `tracing`; default `info` |
|
||||
| `LOCALLLM_ENABLE_TOOL_CALLS` | Não | Liga ou desliga tool calling; padrão ligado |
|
||||
| `LOCALLLM_LOG_FORMAT` | Não | `json` para logs estruturados; padrão `pretty` |
|
||||
| `LLAMA_DLL_PATH` | Não | Caminho completo da biblioteca do llama.cpp; sobrepõe a resolução automática |
|
||||
| `RUST_LOG` | Não | Filtro de logs do `tracing`; padrão `info` |
|
||||
|
||||
A pasta de modelos **não** é variável de ambiente: na CLI é a flag global `--models-dir` (default `./models`); no app é o campo `models_dir` da configuração do runtime. Ao iniciar o servidor local, o app define `LOCALLLM_MODEL`, `LOCALLLM_ADDR`, `LOCALLLM_GPU_LAYERS` e `LOCALLLM_CTX`.
|
||||
</details>
|
||||
|
||||
## 🧱 Arquitetura
|
||||
## Estado do projeto
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
UI["App Tauri (React + Rust)"] -->|"HTTP e SSE"| SRV["inference-server (Axum)"]
|
||||
CLI["localllm-cli"] -->|"HTTP"| SRV
|
||||
SRV --> CORE["inference-core (engine, sessão, perfis)"]
|
||||
CORE --> SYS["llama-sys (llama.dll via libloading)"]
|
||||
SRV --> DEPS["runtime-deps (download + SHA-256)"]
|
||||
DEPS -->|"llama.cpp b8358"| SYS
|
||||
UI -->|"busca e download de .gguf"| HF["Hugging Face"]
|
||||
```
|
||||
Em desenvolvimento. Pelo [`.planning/ROADMAP.md`](.planning/ROADMAP.md), as fases 1 a 4 estão concluídas, a fase 5 (validação de fontes de modelo) segue aberta com os três planos marcados e a fase 6 (redesign do chat e das Configurações) tem 0 de 3 planos.
|
||||
|
||||
- O app (no modo `local`) inicia e para o `inference-server` e usa `GET /health` para saber se está pronto; no modo `remote` apenas fala com a API.
|
||||
- A CLI é um cliente HTTP da mesma API.
|
||||
- O `inference-server` valida a request (auth, CORS, aliases) e delega ao `inference-core`, que mantém o engine, a sessão e o sampler.
|
||||
- O `inference-core` usa o `llama-sys`, que carrega `llama.dll` dinamicamente; o `runtime-deps` resolve ou baixa esse runtime a partir de [`vendor/llama-runtime/manifest.json`](vendor/llama-runtime/manifest.json).
|
||||
- O app busca e baixa modelos direto do Hugging Face, sem passar pela API local.
|
||||
- A compatibilidade com a OpenAI é parcial: `parallel_tool_calls` não é recurso suportado, `content` em partes vira texto e o raciocínio não sai num campo separado (quem separa `<think>…</think>` é o app).
|
||||
- O chat do app usa `sql.js` carregado por CDN e guarda o banco no `localStorage`.
|
||||
- `scripts/build-dev.sh` e `scripts/build-prod.sh` (e as versões `.ps1`) exigem `vendor/llama.cpp`, que não está no repositório.
|
||||
- `inference-server` e `localllm-cli` declaram um binário com o mesmo nome, `localllm`; use `cargo run -p <crate>`.
|
||||
|
||||
## 🗂️ Estrutura
|
||||
Para contribuir, abra uma issue ou um PR e rode os testes da parte que você alterou.
|
||||
|
||||
```text
|
||||
crates/
|
||||
api-contracts/ tipos compartilhados (chat, modelos, health, erros)
|
||||
inference-core/ engine de inferência, sessão, sampler e perfis
|
||||
inference-server/ API HTTP em Axum (binário localllm)
|
||||
llama-sys/ carga dinâmica do llama.cpp (libloading)
|
||||
metrics/ contadores de tokens e throughput
|
||||
runtime-deps/ resolve e baixa o runtime llama.cpp
|
||||
localllm-cli/ CLI (binário localllm)
|
||||
tauri-app/ app desktop: React 18 + Vite + Tailwind, backend Tauri 2
|
||||
ui/ páginas HTML estáticas de desenvolvimento (index.html, chat.html)
|
||||
docs/ documentação detalhada
|
||||
```
|
||||
## Licença
|
||||
|
||||
## 🧪 Scripts
|
||||
Sem licença publicada: todos os direitos reservados. O [`Cargo.toml`](Cargo.toml) declara `license = "MIT"`, mas o repositório não inclui o arquivo `LICENSE`. Os binários do llama.cpp e os modelos do Hugging Face seguem a licença de cada autor.
|
||||
|
||||
| Comando | O que faz |
|
||||
|---|---|
|
||||
| `cargo run -p inference-server` | Sobe a API em `0.0.0.0:8080` (exige `LOCALLLM_MODEL`) |
|
||||
| `cargo run -p localllm-cli -- <comando>` | Executa a CLI |
|
||||
| `cargo test` | Testes dos crates do workspace |
|
||||
| `cargo test --manifest-path tauri-app/src-tauri/Cargo.toml` | Testes do backend Tauri (fora do workspace) |
|
||||
| `npm run dev` (em `tauri-app`) | Só o frontend, Vite na porta 1420 |
|
||||
| `npm run tauri dev` | App desktop completo |
|
||||
| `npm run build` | `tsc && vite build` |
|
||||
| `npm run preview` | `vite preview` |
|
||||
| `npm test` | `vitest run` |
|
||||
| `npm run tauri` | Repassa argumentos ao `tauri` CLI |
|
||||
| `scripts/build-dev.sh` (há `.ps1`) | Compila `vendor/llama.cpp` em Debug com CUDA |
|
||||
| `scripts/build-prod.sh` (há `.ps1`) | Compila `vendor/llama.cpp` em Release com LTO e CUDA (arch 86) |
|
||||
<div align="center">
|
||||
|
||||
## 📚 Documentação
|
||||
<sub>Feito por <a href="https://evandro.dev.br">Evandro Fonseca Junior</a> · <a href="https://git.evandro.dev.br/evandro">git.evandro.dev.br</a></sub>
|
||||
|
||||
| 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, endpoints e configuração |
|
||||
| [`docs/cli/overview.md`](docs/cli/overview.md) · [`commands.md`](docs/cli/commands.md) | CLI: visão geral e 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: visão geral, guia de uso e comandos Tauri |
|
||||
| [`docs/developer/architecture.md`](docs/developer/architecture.md) | Mapa do workspace e fluxos entre módulos |
|
||||
| [`.planning/ROADMAP.md`](.planning/ROADMAP.md) | Fases e estado do desenvolvimento |
|
||||
|
||||
## 🛣️ Limitações e próximos passos
|
||||
|
||||
- A API expõe só três endpoints; a compatibilidade com a OpenAI é parcial: `n` precisa ser `1`, `parallel_tool_calls` não é recurso suportado e `content` em partes vira texto consolidado.
|
||||
- O raciocínio não é um 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 resto da superfície está 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`, e o runtime manager faz polling do snapshot (sem eventos push).
|
||||
- O manifesto do runtime só lista variantes `windows-x64`; em outros alvos o servidor só sobe com um runtime já presente (binário adjacente ou `LLAMA_DLL_PATH`).
|
||||
- `scripts/build-dev.sh` e `scripts/build-prod.sh` exigem o submódulo `vendor/llama.cpp`, 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.
|
||||
- Próximos passos registrados no roadmap: concluir a fase 5 (validação de fontes de modelo, com seus três planos marcados como feitos mas a fase ainda aberta) e a fase 6 (redesign do chat e da página de Configurações, 0/3 planos).
|
||||
|
||||
## 🤝 Contribuindo
|
||||
|
||||
Abra uma issue ou PR descrevendo a mudança. Antes de enviar, rode os testes que cobrem o que você alterou:
|
||||
|
||||
```bash
|
||||
cargo test && (cd tauri-app && npm test)
|
||||
```
|
||||
|
||||
## 📄 Licença
|
||||
|
||||
MIT, declarada em [`Cargo.toml`](Cargo.toml); o repositório não inclui arquivo `LICENSE`. Os binários de inferência vêm do [llama.cpp](https://github.com/ggml-org/llama.cpp) e os modelos do [Hugging Face](https://huggingface.co) seguem a licença de cada autor.
|
||||
</div>
|
||||
@@ -0,0 +1,60 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="1200" height="420" viewBox="0 0 1200 420" role="img" aria-labelledby="title desc">
|
||||
<title id="title">ForgeLM</title>
|
||||
<desc id="desc">ForgeLM: um arquivo .gguf entra no llama.cpp, que divide as camadas entre GPU e CPU, e a resposta sai em streaming pela API local na porta 8080, em /v1/chat/completions.</desc>
|
||||
|
||||
<rect width="1200" height="420" rx="24" fill="#171717"/>
|
||||
|
||||
<g id="title-block" font-family="system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif">
|
||||
<text x="64" y="170" font-size="64" font-weight="700" fill="#F3F4F6">ForgeLM</text>
|
||||
<text x="64" y="226" font-size="28" fill="#F3F4F6">Rode modelos .gguf na sua máquina</text>
|
||||
<text x="64" y="264" font-size="28" fill="#F3F4F6">com uma API no estilo OpenAI.</text>
|
||||
<text x="64" y="322" font-size="20" fill="#9CA3AF" font-family="ui-monospace, 'SF Mono', Consolas, monospace">Rust · llama.cpp · Axum · Tauri 2</text>
|
||||
</g>
|
||||
|
||||
<g id="model-file" font-family="ui-monospace, 'SF Mono', Consolas, monospace">
|
||||
<path d="M584 152 h60 l28 28 v88 h-88 z" fill="#262626" stroke="#313944" stroke-width="2"/>
|
||||
<path d="M644 152 v28 h28" fill="none" stroke="#313944" stroke-width="2"/>
|
||||
<text x="628" y="234" font-size="20" fill="#F3F4F6" text-anchor="middle">.gguf</text>
|
||||
<text x="628" y="304" font-size="18" fill="#9CA3AF" text-anchor="middle" font-family="system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif">modelo</text>
|
||||
</g>
|
||||
|
||||
<g id="arrows" fill="none" stroke="#9CA3AF" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M682 210 h26 M700 202 l8 8 l-8 8"/>
|
||||
<path d="M836 210 h20 M848 202 l8 8 l-8 8"/>
|
||||
</g>
|
||||
|
||||
<g id="layers" font-family="system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif">
|
||||
<text x="772" y="110" font-size="20" font-weight="700" fill="#F3F4F6" text-anchor="middle">llama.cpp</text>
|
||||
<rect x="716" y="126" width="112" height="28" rx="6" fill="#4b86ff"/>
|
||||
<rect x="716" y="162" width="112" height="28" rx="6" fill="#4b86ff"/>
|
||||
<rect x="716" y="198" width="112" height="28" rx="6" fill="#4b86ff"/>
|
||||
<rect x="716" y="234" width="112" height="28" rx="6" fill="#4b86ff"/>
|
||||
<rect x="716" y="270" width="112" height="28" rx="6" fill="#333333"/>
|
||||
<rect x="716" y="306" width="112" height="28" rx="6" fill="#333333"/>
|
||||
<text x="772" y="146" font-size="18" font-weight="700" fill="#0d0d10" text-anchor="middle">GPU</text>
|
||||
<text x="772" y="326" font-size="18" font-weight="700" fill="#F3F4F6" text-anchor="middle">CPU</text>
|
||||
</g>
|
||||
|
||||
<g id="api-stream" font-family="ui-monospace, 'SF Mono', Consolas, monospace">
|
||||
<rect x="864" y="96" width="272" height="244" rx="14" fill="#0d0d10" stroke="#313944" stroke-width="2"/>
|
||||
<circle cx="890" cy="128" r="6" fill="#30d158"/>
|
||||
<text x="906" y="135" font-size="20" fill="#F3F4F6">:8080</text>
|
||||
<text x="1116" y="135" font-size="18" fill="#9CA3AF" text-anchor="end">SSE</text>
|
||||
<path d="M864 154 h272" stroke="#232a33" stroke-width="2"/>
|
||||
<text x="884" y="186" font-size="18" fill="#9CA3AF">/v1/chat/completions</text>
|
||||
<g font-family="system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif" font-size="20" fill="#F3F4F6">
|
||||
<rect x="884" y="204" width="58" height="34" rx="8" fill="#101c2d" stroke="#203451" stroke-width="2"/>
|
||||
<text x="913" y="228" text-anchor="middle">Olá</text>
|
||||
<rect x="950" y="204" width="30" height="34" rx="8" fill="#101c2d" stroke="#203451" stroke-width="2"/>
|
||||
<text x="965" y="228" text-anchor="middle">,</text>
|
||||
<rect x="988" y="204" width="68" height="34" rx="8" fill="#101c2d" stroke="#203451" stroke-width="2"/>
|
||||
<text x="1022" y="228" text-anchor="middle">tudo</text>
|
||||
<rect x="884" y="248" width="62" height="34" rx="8" fill="#101c2d" stroke="#203451" stroke-width="2"/>
|
||||
<text x="915" y="272" text-anchor="middle">bem</text>
|
||||
<rect x="954" y="248" width="30" height="34" rx="8" fill="#101c2d" stroke="#203451" stroke-width="2"/>
|
||||
<text x="969" y="272" text-anchor="middle">?</text>
|
||||
<rect x="994" y="252" width="12" height="26" rx="2" fill="#4b86ff"/>
|
||||
</g>
|
||||
<text x="884" y="318" font-size="18" fill="#9CA3AF">"stream": true</text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.2 KiB |
Reference in new issue
Block a user