llmproxy/README.md
Oliver Hofmann cfa874a4c3 Fix medium/low priority review items; update README
Medium:
- Frontend: Error-Handling in fetchUsers/fetchApiKeys (try/catch)
- Frontend: Loading-Race behoben (Promise.all + .finally)
- Frontend: API-Keys maskiert (nur letzte 4 Zeichen sichtbar)
- Tests: Setup-Code aus test_auth.py in conftest.py konsolidiert
- Tests: Fixture-Scope vereinheitlicht (function statt session)

Low:
- bare except in database.py → except Exception
- datetime.utcnow → datetime.now(timezone.utc) durchgängig
- DateTime(timezone=True) in allen Modell-Spalten
- .gitignore hinzugefügt (.env, *.db, __pycache__, .idea, node_modules)

Docs:
- README aktualisiert (Sicherheit, Konfiguration, Projektstruktur, Tests)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-27 21:48:26 +02:00

157 lines
4.3 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.

# Ollama Proxy mit API-Keys und Quotas
Ein Reverse-Proxy für Ollama mit API-Key-Authentifizierung und Quota-Management.
## Features
- API-Key-Authentifizierung (Bearer Token oder `sk-`-Prefix)
- Quota-Management mit getrennten Tages- und Monatslimits (Tokens & Requests)
- Token-Zählung via tiktoken (cl100k_base)
- Usage-Tracking mit automatischem täglichem/monatlichem Reset
- Web-Admin-Oberfläche für User- und Quota-Verwaltung
- OpenAI-kompatibler `/v1/chat/completions`-Endpunkt
## Sicherheit
- Passwörter mit bcrypt gehasht
- API-Keys als SHA-256-Hash in der DB Plaintext wird nur einmalig bei Erstellung zurückgegeben
- Admin-Zugriff über `is_admin`-Flag in der DB, nicht über Hardcoded-Namen
- CORS-Origins konfigurierbar via `ALLOWED_ORIGINS`
- Quota-Check atomar mit `SELECT FOR UPDATE` (kein TOCTOU-Race)
## Installation & Start
### Voraussetzungen
- Python 3.12+
- PostgreSQL 16+ (oder SQLite für Entwicklung)
- Node.js 18+ (für Frontend)
### Lokal mit SQLite (Entwicklung)
```bash
# Backend
cd backend
pip install -r requirements.txt
python init_db.py
python setup_admin.py
uvicorn main:app --reload --port 8000
# Admin-API (in neuem Terminal)
uvicorn admin:app --reload --port 8001
# Frontend (in neuem Terminal)
cd frontend
npm install
npm run dev
```
### Mit PostgreSQL & Docker (Produktion)
```bash
docker compose up -d
docker compose exec backend python init_db.py
docker compose exec backend python setup_admin.py
```
## Konfiguration
`.env`-Datei im `backend/`-Verzeichnis anlegen:
```env
DATABASE_URL=postgresql://user:pass@host:5432/db
OLLAMA_URL=http://ollama:11434
ALLOWED_ORIGINS=https://admin.example.com
```
| Variable | Standard | Beschreibung |
|----------|----------|--------------|
| `DATABASE_URL` | PostgreSQL lokal | DB-Verbindungsstring; `sqlite:///` für SQLite |
| `OLLAMA_URL` | `http://localhost:11434` | Adresse der Ollama-Instanz |
| `ALLOWED_ORIGINS` | `http://localhost:5173` | Kommagetrennte CORS-Origins für die Admin-UI |
## Proxy-Endpunkte
Alle Endpunkte erfordern einen gültigen API-Key im `Authorization`-Header.
```bash
curl -X POST http://localhost:8000/api/generate \
-H "Authorization: Bearer sk-xxxxxx" \
-H "Content-Type: application/json" \
-d '{"model":"llama3","prompt":"Say hello"}'
```
| Endpunkt | Beschreibung |
|----------|--------------|
| `POST /api/generate` | Ollama generate |
| `POST /api/chat` | Ollama chat |
| `GET /api/tags` | Verfügbare Modelle |
| `GET /v1/models` | Modelle (OpenAI-Format) |
| `POST /v1/chat/completions` | Chat (OpenAI-Format) |
## Admin-API (Port 8001)
Alle Endpunkte erfordern einen API-Key eines Nutzers mit `is_admin=true`.
| Endpunkt | Methode | Beschreibung |
|----------|---------|--------------|
| `/api/users` | GET | Alle User auflisten |
| `/api/users` | POST | Neuen User anlegen |
| `/api/api-keys` | GET | Alle API-Keys auflisten |
| `/api/api-keys` | POST | Neuen API-Key erstellen (Plaintext einmalig in Response) |
| `/api/api-keys/{id}/deactivate` | PUT | API-Key deaktivieren |
| `/api/quotas/{user_id}` | PUT | Quota für User setzen |
### Quota setzen
```bash
curl -X PUT http://localhost:8001/api/quotas/1 \
-H "Authorization: Bearer sk-admin-key" \
-H "Content-Type: application/json" \
-d '{
"daily_tokens": 1000000,
"monthly_tokens": 10000000,
"daily_requests": 1000,
"monthly_requests": 10000
}'
```
`null` für ein Limit bedeutet unbegrenzt.
## Tests
```bash
cd backend
python -m pytest tests/ -v
```
## Projektstruktur
```
llm_quota/
├── backend/
│ ├── main.py # Proxy-Server
│ ├── admin.py # Admin-API
│ ├── database.py # DB-Verbindung & Session
│ ├── models.py # SQLAlchemy-Modelle
│ ├── schemas.py # Pydantic-Schemas
│ ├── crud.py # DB-Operationen & Token-Zählung
│ ├── init_db.py # Tabellen anlegen
│ ├── setup_admin.py # Admin-User & API-Key erstellen
│ ├── requirements.txt
│ ├── Dockerfile
│ └── tests/
│ ├── conftest.py # Fixtures
│ ├── test_auth.py # Authentifizierungs-Tests
│ └── test_quota.py # Quota- & Token-Tests
├── frontend/
│ └── src/
│ ├── main.jsx
│ └── styles.css
├── .gitignore
└── docker-compose.yml
```
## Lizenz
MIT