Ziel: Schlanke, performante, zustandslose API für ein einzelnes Modell (Default: Yamemaru/gemma-3-4b-Darija-GRPO-16bit) zur Übersetzung und optionalem Chat. Fokus auf schnelle Startbarkeit, Stabilität und wenig Abhängigkeiten.
- Nicht enthalten: Auth, DB, Multi-Model-Registry, komplexe CI/CD, Docker (nur optionaler Hinweis in README).
- Enthalten: Health, Info, Translate, minimalistisches Chat, Logging, CORS, Timeouts, Semaphore-Rate-Limit, optional INT4.
- Python 3.11+
- FastAPI + Uvicorn
- PyTorch (CUDA), Transformers
- Optional: bitsandbytes (4-bit), Accelerate
- Single-GPU (RTX 5080, 16 GB), FP16 als Standard, optional INT4 via Flag
manouapi/
app/
__init__.py
main.py # FastAPI App, Startup, Middlewares
config.py # ENV (.env) + Defaults
model.py # Model/Tokenizer Load, Worker, Generate/Translate
router.py # Route-Definitionen
schemas.py # Pydantic-Modelle
utils.py # Prompting, Token-Counting, Timing, Logging-Helfer
requirements.txt
README.md
MODEL_NAME(Default:Yamemaru/gemma-3-4b-Darija-GRPO-16bit)USE_INT4(Default:false) → wenntrue, lade bnb-int4MAX_NEW_TOKENS(Default:128)MAX_INPUT_CHARS(Default:4000) → 413 bei ÜberschreitungTEMPERATURE_TRANSLATE(Default:0.2)TEMPERATURE_CHAT(Default:0.7)TIMEOUT_SECONDS(Default:60)BATCH_SIZE(Default:4) undBATCH_TIMEOUT_MS(Default:50) – optional Micro-BatchingHOST(Default:0.0.0.0),PORT(Default:8000)CORS_ORIGINS(Default:http://localhost:3000,http://localhost:5173) – Flutter-Origin eintragen
- Setze
torch.backends.cuda.matmul.allow_tf32 = True. - Tokenizer:
AutoTokenizer.from_pretrained(MODEL_NAME, use_fast=True). - Modell:
- FP16:
AutoModelForCausalLM.from_pretrained(..., torch_dtype=torch.float16, device_map="auto") - INT4:
AutoModelForCausalLM.from_pretrained(..., load_in_4bit=True, bnb_4bit_compute_dtype=torch.float16, device_map="auto")
- FP16:
- Gerät:
cuda:0(Fallback prüfen; wenn kein CUDA → 500 beim Start). - Prüfe
apply_chat_templatedes Tokenizers: falls vorhanden, für Prompts nutzen; sonst Fallback-Template.
- Translate-Systemprompt: „You are a precise translator. Preserve meaning, tone, and idioms. Output only the translation. Source={src}, Target={tgt}.“
- Chat-Systemprompt: „You are a helpful assistant specializing in Darija and Maghrebi Arabic.“
- Für Übersetzen deterministisch:
temperature=0.2,do_sample=false(bevorzugt deterministisch für Übersetzung). Für Chat:temperature=0.7,do_sample=true.
- Singleton-Worker mit
asyncio.Queueundasyncio.Semaphore(1)pro Prozess. - Serielle Abarbeitung standardmäßig; optionales Micro-Batching: sammle bis N=4 Requests oder 50ms Timeout und rufe
generatein einem Batch auf (nur wenn gleiche Parameter; sonst seriell). - Tokenzählung:
prompt_tokens = len(input_ids[0])output_tokens = len(generated_ids[0]) - len(input_ids[0])
- Rückgabe pro Request: Ergebnistext, Token-Usage, Latenz in ms.
-
POST /translate- Body:
{ "text": "<string>", "source_lang": "auto|en|fr|de|ary|aeb|arq", "target_lang": "ary|en|fr|de" } - Validierung:
textnicht leer → 400, Länge ≤MAX_INPUT_CHARS→ sonst 413. - Prompt-Bau: Chat-Template wenn verfügbar, sonst Fallback. Bei
autoSource wird Prompt klar als „Translate from auto-detected ...“ formuliert. - Antwort:
{ "translation": "<string>", "prompt_tokens": <int>, "output_tokens": <int>, "latency_ms": <int> }.
- Body:
-
POST /chat(optional, minimal)- Body:
{ "messages": [{"role":"user|system|assistant", "content":"..." }], "max_new_tokens": 256 } - System-Prompt wird vorn angestellt (siehe oben) falls nicht vorhanden.
- Antwort:
{ "response": "<string>", "usage": { "prompt_tokens": <int>, "output_tokens": <int> } }.
- Body:
-
GET /healthz→{ "ok": true } -
GET /info→{ "model": "<name>", "dtype": "fp16|int4", "device": "cuda:0" }
- 400: leerer Text, ungültige Sprache, ungültige Messages-Struktur
- 413: Eingabe zu lang (
MAX_INPUT_CHARS) - 500: CUDA-/Ladefehler, Generate-Fehler (gekürzte Message, keine Stacks im Body)
- Timeout je Request: 60s (konfigurierbar)
- Rate-Limit:
asyncio.Semaphore(1)pro Prozess (Single-Worker)
- CORS mit konfigurierten Origins (
CORS_ORIGINS). - Keine Auth; keine Secrets im Code. Option
.envfür Konfig.
- Pro Request: Methode, Pfad, Latenz ms, prompt/output Tokens, ggf.
torch.cuda.memory_allocated()/memory_reserved(). - Strukturierte, kurze Logs; keine Inhalte sensible Daten.
fastapi>=0.110uvicorn[standard]>=0.29transformers>=4.42torch>=2.3(CUDA Build)accelerate>=0.30bitsandbytes>=0.43(optional, nur wennUSE_INT4=true)sentencepiece>=0.2(für einige Tokenizer)pydantic>=2.6python-dotenv>=1.0numpy>=1.26
-
app/main.py- Erstellen der FastAPI-App, CORS, Startup-Event →
load_model()ausmodel.py. - Include
router.py. - Health/Info-Routen.
- Erstellen der FastAPI-App, CORS, Startup-Event →
-
app/config.py- ENV-Lesen (os + dotenv), Defaults setzen, Validieren.
-
app/model.py- Globale Referenzen auf
tokenizer,model,device,dtype. load_model()basierend auf Konfig (FP16/INT4) +device_map="auto".- Worker mit
asyncio.Queue;enqueue_request();worker_loop(). generate(inputs, **gen_kwargs);translate(text, src, tgt);chat(messages, max_new_tokens).
- Globale Referenzen auf
-
app/router.py- POST
/translateund/chatHandlers (Validierung viaschemas.py), Timeout-Wrapping, Fehler-Mapping, Logging.
- POST
-
app/schemas.py- Pydantic-Modelle:
TranslateRequest,TranslateResponse,ChatRequest,ChatResponse.
- Pydantic-Modelle:
-
app/utils.py- Prompt-Helper:
build_translate_messages(src, tgt, text); Fallback-Template. - Tokenzählung, Timing (
monotonic_ns), CUDA-Memory-Stats.
- Prompt-Helper:
- Setup: Python, venv,
pip install -r requirements.txt. - Start:
uvicorn app.main:app --host 0.0.0.0 --port 8000. - ENV-Beispiele (
.env). - Smoke-Tests:
curl -s http://localhost:8000/healthz- Translate EN→ARY Beispiel (20 Wörter).
- Chat-Beispiel.
- Optional: Hinweis zu Docker, aber kein Image bereitgestellt.
- Startup < 60s (Cold Load, Netz abhängig vom HF-Cache). Erster Warmstart nach Download.
/translate< 2s bei 20 Wörtern (Warm, FP16) auf RTX 5080 16GB.- Kein VRAM-Overflow bei Einzelrequest; Nutzung überwachen.
/infozeigt korrektes Modell & dtype.- Smoke-Tests laufen wie im README angegeben.
- Bitsandbytes unter Windows problematisch → Flag standardmäßig
false; README verweist auf Linux-Empfehlung für INT4. - HF-Download langsam → README Hinweis, Modell vorab zu cachen (
HF_HOME). - Chat-Template fehlt → robuster Fallback implementiert.
- Grundgerüst
manouapi/anlegen (Struktur wie oben). config.py+.env-Parsing implementieren.model.py: Load (FP16/optional INT4), Worker,generate/translate/chat+ Tokenzählung.schemas.py: Pydantic-Modelle.utils.py: Prompt-Bau, Timing, CUDA-Memory-Stats.router.py: Endpunkte und Fehler-/Timeout-Handling, Logging.main.py: App, CORS, Startup/Shutdown, Routen.requirements.txtundREADME.md(Smoke-Beispiele einfügen).- Manuelle Smoke-Tests lokal.