FastAPI & Caddy Integration


In diesem Projekt demonstriere ich die Integration eines Python-basierten FastAPI-Backends mit dem Caddy Webserver. Ziel war es, eine leichtgewichtige API bereitzustellen, die über einen Reverse Proxy sicher und effizient erreichbar ist.

Das Backend: FastAPI (Text-Analyse & KI)

Als Backend-Framework kommt FastAPI zum Einsatz. In diesem erweiterten Beispiel haben wir zwei Endpunkte:

  1. /generate: Eine klassische Text-Analyse (CPU-bound).
  2. /ask-ai: Eine Schnittstelle zu einem LLM über OpenRouter (I/O-bound).

Setup: Installieren Sie openai (pip install openai) und setzen Sie Ihren OpenRouter API Key als Umgebungsvariable.

Das vollständige Skript (main.py):

import os
import requests # Neu: Für die Modell-Liste
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel, Field
from openai import OpenAI

app = FastAPI()

# --- Teil 1: Text-Analyse ---

class TextRequest(BaseModel):
    text: str = Field(..., max_length=500, description="Der zu analysierende Text")

@app.post("/generate")
async def analyze_text(data: TextRequest):
    text = data.text
    stats = {
        "uppercase": text.upper(),
        "reversed": text[::-1],
        "char_count": len(text),
        "word_count": len(text.split()),
        "is_palindrome": text.replace(" ", "").lower() == text.replace(" ", "").lower()[::-1]
    }
    return {"result": stats}

# --- Teil 2: KI-Integration (OpenRouter) ---

# API-Key sicher aus Umgebungsvariablen laden
# Setzen Sie in Linux/Bash: export OPENROUTER_API_KEY="sk-or-..."
API_KEY = os.getenv("OPENROUTER_API_KEY")
client = OpenAI(base_url="https://openrouter.ai/api/v1", api_key=API_KEY)

class AIRequestData(BaseModel):
    prompt: str = Field(..., max_length=2000, description="Code oder Frage")
    model: str = Field("google/gemini-2.0-flash-exp:free", description="Das gewählte Modell") # Neu

@app.get("/models") # Neu: Endpunkt für Modelle
def get_free_models():
    try:
        # Wir holen die Liste direkt von OpenRouter
        response = requests.get("https://openrouter.ai/api/v1/models")
        if response.status_code == 200:
            data = response.json()["data"]
            # Filter: Nur Modelle, die auf ":free" enden
            free_models = [m["id"] for m in data if m["id"].endswith(":free")]
            return {"models": sorted(free_models)}
    except:
        pass
    # Fallback, falls API nicht erreichbar
    return {"models": ["google/gemini-2.0-flash-exp:free", "meta-llama/llama-3-8b-instruct:free"]}

@app.post("/ask-ai")
async def ask_ai(data: AIRequestData):
    if not API_KEY:
        raise HTTPException(status_code=500, detail="Server-Konfiguration fehlt (API Key)")
        
    try:
        completion = client.chat.completions.create(
            model=data.model, # Hier nutzen wir das vom User gewählte Modell
            messages=[
                {"role": "system", "content": "Du bist ein Code-Erklärer. Erkläre den Code kurz, prägnant und auf Deutsch."},
                {"role": "user", "content": data.prompt}
            ]
        )
        return {"result": completion.choices[0].message.content}
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

Der Webserver: Caddy

Um die API unter der gleichen Domain wie das Frontend verfügbar zu machen, verwende ich Caddy. Wir nutzen handle_path, um das /api Präfix zu entfernen, bevor die Anfrage an FastAPI weitergeleitet wird.

Auszug aus der Caddy-Konfiguration:

handle_path /api/* {
    reverse_proxy 127.0.0.1:8000
}

Live-Demo: Text-Analyzer

Geben Sie einen Text ein, um ihn vom Python-Backend analysieren zu lassen. (Stellen Sie sicher, dass das aktualisierte Skript lokal läuft).

Text Analyse API

Ergebnisse erscheinen hier...

Erweiterung: KI Code-Erklärer

Dieses zweite Beispiel nutzt den neuen /ask-ai Endpunkt. Geben Sie einen Code-Schnipsel ein, und das Backend leitet ihn sicher an ein LLM (via OpenRouter) weiter.

Der System-Prompt: Ein großer Vorteil dieser Architektur ist, dass wir dem Modell eine feste Rolle zuweisen können, die der Nutzer nicht ändern kann. Im Python-Backend wird jeder Anfrage dieser System-Prompt vorangestellt:

“Du bist ein Code-Erklärer. Erkläre den Code kurz, prägnant und auf Deutsch.”

Das garantiert, dass die KI immer hilfreich und fokussiert antwortet, egal was der Nutzer eingibt. Ihr API-Key bleibt dabei sicher auf dem Server.

KI Code-Erklärer

Die Erklärung der KI erscheint hier...