Update llama runtime and isolate background reviews
This commit is contained in:
@@ -1,6 +1,10 @@
|
|||||||
# Generated as /etc/mike-ai/stack.env by install.sh. Never commit real values.
|
# Generated as /etc/mike-ai/stack.env by install.sh. Never commit real values.
|
||||||
AI_BIND_ADDRESS=10.77.0.2
|
AI_BIND_ADDRESS=10.77.0.2
|
||||||
MODEL_DIR=/data/models
|
MODEL_DIR=/data/models
|
||||||
|
REVIEW_MODEL_FILE=qwen3-4b-review/Qwen3-4B-Instruct-2507-Q4_K_M.gguf
|
||||||
|
REVIEW_CONTEXT=32768
|
||||||
|
REVIEW_GPU_DEVICE=1
|
||||||
|
REVIEW_GPU_LAYERS=0
|
||||||
ROUTER_API_KEY=GENERATED_BY_INSTALLER
|
ROUTER_API_KEY=GENERATED_BY_INSTALLER
|
||||||
CONTROLLER_TOKEN=GENERATED_BY_INSTALLER
|
CONTROLLER_TOKEN=GENERATED_BY_INSTALLER
|
||||||
FLUX_MODEL_DIR=/data/models/FLUX.2-klein-4B
|
FLUX_MODEL_DIR=/data/models/FLUX.2-klein-4B
|
||||||
|
|||||||
+76
-8
@@ -32,6 +32,76 @@ x-llama-common: &llama-common
|
|||||||
start_period: 30s
|
start_period: 30s
|
||||||
|
|
||||||
services:
|
services:
|
||||||
|
# Kleines, dauerhaft geladenes Hilfsmodell fuer Hermes-Hintergrundaufgaben
|
||||||
|
# (Memory-/Skill-Review). Es laeuft unabhaengig vom wechselnden Hauptmodell
|
||||||
|
# und kann dessen Prompt-Cache daher nicht mehr
|
||||||
|
# verdraengen. Athena reserviert die 3060 bereits fuer Qwen und XTTS; der
|
||||||
|
# robuste Standard ist deshalb CPU/RAM. GPU-Layer koennen spaeter per Env
|
||||||
|
# zugeschaltet werden, sobald dort garantiert Speicher frei ist.
|
||||||
|
llama-review:
|
||||||
|
image: ${LLAMA_IMAGE:-mike-ai/llama.cpp:local}
|
||||||
|
container_name: mike-ai-llama-review
|
||||||
|
restart: unless-stopped
|
||||||
|
gpus: all
|
||||||
|
ipc: host
|
||||||
|
read_only: true
|
||||||
|
tmpfs:
|
||||||
|
- /tmp:size=512m,mode=1777
|
||||||
|
volumes:
|
||||||
|
- "${MODEL_DIR:-/srv/mike-ai/models}:/models:ro"
|
||||||
|
environment:
|
||||||
|
NVIDIA_VISIBLE_DEVICES: ${REVIEW_GPU_DEVICE:-1}
|
||||||
|
NVIDIA_DRIVER_CAPABILITIES: compute,utility
|
||||||
|
command:
|
||||||
|
- --model
|
||||||
|
- "/models/${REVIEW_MODEL_FILE:-qwen3-4b-review/Qwen3-4B-Instruct-2507-Q4_K_M.gguf}"
|
||||||
|
- --alias
|
||||||
|
- qwen-review
|
||||||
|
- --ctx-size
|
||||||
|
- "${REVIEW_CONTEXT:-32768}"
|
||||||
|
- --flash-attn
|
||||||
|
- "on"
|
||||||
|
- --cache-type-k
|
||||||
|
- q4_0
|
||||||
|
- --cache-type-v
|
||||||
|
- q4_0
|
||||||
|
- --cache-prompt
|
||||||
|
- --threads
|
||||||
|
- "${LLAMA_THREADS:-6}"
|
||||||
|
- --threads-batch
|
||||||
|
- "${LLAMA_THREADS_BATCH:-6}"
|
||||||
|
- --batch-size
|
||||||
|
- "${REVIEW_BATCH_SIZE:-512}"
|
||||||
|
- --ubatch-size
|
||||||
|
- "${REVIEW_UBATCH_SIZE:-64}"
|
||||||
|
- --parallel
|
||||||
|
- "1"
|
||||||
|
- --kv-unified
|
||||||
|
- --jinja
|
||||||
|
- --host
|
||||||
|
- 0.0.0.0
|
||||||
|
- --port
|
||||||
|
- "8080"
|
||||||
|
- --metrics
|
||||||
|
- --fit
|
||||||
|
- "off"
|
||||||
|
- --n-gpu-layers
|
||||||
|
- "${REVIEW_GPU_LAYERS:-0}"
|
||||||
|
- --no-kv-offload
|
||||||
|
- --no-mmap
|
||||||
|
- --no-ui
|
||||||
|
- --temperature
|
||||||
|
- "0.2"
|
||||||
|
networks: [inference]
|
||||||
|
security_opt: ["no-new-privileges:true"]
|
||||||
|
cap_drop: [ALL]
|
||||||
|
healthcheck:
|
||||||
|
test: [CMD, curl, -fsS, "http://127.0.0.1:8080/health"]
|
||||||
|
interval: 10s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 60
|
||||||
|
start_period: 30s
|
||||||
|
|
||||||
wireguard-gateway:
|
wireguard-gateway:
|
||||||
build: ./platform/docker/wireguard-gateway
|
build: ./platform/docker/wireguard-gateway
|
||||||
image: mike-ai/wireguard-gateway:local
|
image: mike-ai/wireguard-gateway:local
|
||||||
@@ -153,17 +223,12 @@ services:
|
|||||||
environment:
|
environment:
|
||||||
NVIDIA_VISIBLE_DEVICES: ${MEDIUM_GPU_DEVICES:-0,1}
|
NVIDIA_VISIBLE_DEVICES: ${MEDIUM_GPU_DEVICES:-0,1}
|
||||||
NVIDIA_DRIVER_CAPABILITIES: compute,utility
|
NVIDIA_DRIVER_CAPABILITIES: compute,utility
|
||||||
# Keep the language model split unchanged while placing the complete
|
# Temporary llama.cpp cache workaround: keep Medium text-only. Current
|
||||||
# multimodal projector on the secondary RTX 3060.
|
# multimodal builds can discard the complete KV state on a later turn.
|
||||||
MTMD_BACKEND_DEVICE: CUDA1
|
# The model split, context and MTP settings remain unchanged.
|
||||||
command:
|
command:
|
||||||
- --model
|
- --model
|
||||||
- "/models/${MEDIUM_MODEL_FILE:?MEDIUM_MODEL_FILE is required}"
|
- "/models/${MEDIUM_MODEL_FILE:?MEDIUM_MODEL_FILE is required}"
|
||||||
- --mmproj
|
|
||||||
- "/models/${VISION_PROJECTOR_FILE:?VISION_PROJECTOR_FILE is required}"
|
|
||||||
- --mmproj-offload
|
|
||||||
- --mmproj-device
|
|
||||||
- CUDA1
|
|
||||||
- --alias
|
- --alias
|
||||||
- qwen-medium
|
- qwen-medium
|
||||||
- --ctx-size
|
- --ctx-size
|
||||||
@@ -568,6 +633,9 @@ services:
|
|||||||
ROUTER_STATE_FILE: /var/lib/mike-ai-profile-router/state.json
|
ROUTER_STATE_FILE: /var/lib/mike-ai-profile-router/state.json
|
||||||
ROUTER_MAX_CONCURRENT_REQUESTS: "16"
|
ROUTER_MAX_CONCURRENT_REQUESTS: "16"
|
||||||
UPSTREAM_URL: http://llama-upstream:8080
|
UPSTREAM_URL: http://llama-upstream:8080
|
||||||
|
REVIEW_UPSTREAM_URL: http://llama-review:8080
|
||||||
|
REVIEW_MODEL_NAME: qwen-review
|
||||||
|
REVIEW_CONTEXT_LENGTH: "${REVIEW_CONTEXT:-32768}"
|
||||||
PROFILE_CONTROL_URL: http://profile-controller:8090
|
PROFILE_CONTROL_URL: http://profile-controller:8090
|
||||||
PROFILE_CONTROL_TOKEN: "${CONTROLLER_TOKEN:?CONTROLLER_TOKEN is required}"
|
PROFILE_CONTROL_TOKEN: "${CONTROLLER_TOKEN:?CONTROLLER_TOKEN is required}"
|
||||||
SWITCH_TIMEOUT: "600"
|
SWITCH_TIMEOUT: "600"
|
||||||
|
|||||||
@@ -4,6 +4,11 @@
|
|||||||
AI_HOSTNAME=ki-host
|
AI_HOSTNAME=ki-host
|
||||||
ADMIN_USER=mike
|
ADMIN_USER=mike
|
||||||
MODEL_DIR=/data/models
|
MODEL_DIR=/data/models
|
||||||
|
REVIEW_MODEL_FILE=qwen3-4b-review/Qwen3-4B-Instruct-2507-Q4_K_M.gguf
|
||||||
|
REVIEW_CONTEXT=32768
|
||||||
|
# Eine einzelne GPU-ID oder stabile NVIDIA-GPU-UUID; auf Athena die RTX 3060.
|
||||||
|
REVIEW_GPU_DEVICE=1
|
||||||
|
REVIEW_GPU_LAYERS=0
|
||||||
|
|
||||||
# Installing a new NVIDIA driver can require one reboot. In that case this
|
# Installing a new NVIDIA driver can require one reboot. In that case this
|
||||||
# installer exits with code 20 (NVIDIA) or 21 (stable NIC rename); rerun the
|
# installer exits with code 20 (NVIDIA) or 21 (stable NIC rename); rerun the
|
||||||
|
|||||||
@@ -0,0 +1,53 @@
|
|||||||
|
# Aktueller temporärer Laufzustand
|
||||||
|
|
||||||
|
Stand: 31. August 2026
|
||||||
|
|
||||||
|
## Produktive llama.cpp-Runtime
|
||||||
|
|
||||||
|
Alle Textprofile und das Review-Modell verwenden llama.cpp Build 10718,
|
||||||
|
Commit `41ef91f7c8046087cdfbb276b79bff311ecf1c6d`. Der vorherige Build 10587
|
||||||
|
wurde nach einem kontrollierten A/B-Test ersetzt. Der Wechsel verbessert den
|
||||||
|
Durchsatz bei großen Werkzeuglisten, ohne im 70K-/120K-Kontext- und Cachetest
|
||||||
|
eine Regression zu zeigen.
|
||||||
|
|
||||||
|
## Qwen Medium: vorübergehend ohne Vision-Projektor
|
||||||
|
|
||||||
|
`qwen-medium` läuft aktuell als reines Textprofil **ohne `--mmproj`**. Das ist
|
||||||
|
ein vorläufiger Workaround für einen llama.cpp-Fehler, bei dem ein geladener
|
||||||
|
Multimodal-/Vision-Projektor die Wiederverwendung des Prompt-/KV-Caches
|
||||||
|
verhindern und dadurch eine vollständige erneute Prompt-Verarbeitung auslösen
|
||||||
|
kann.
|
||||||
|
|
||||||
|
Dabei gilt ausdrücklich:
|
||||||
|
|
||||||
|
- Der Gesamtkontext bleibt bei **160.000 Tokens**.
|
||||||
|
- **MTP / Speculative Decoding bleibt aktiviert**; MTP wurde nicht entfernt.
|
||||||
|
- Modell, Quantisierung, GPU-Aufteilung und KV-Cache-Quantisierung bleiben
|
||||||
|
unverändert.
|
||||||
|
- Nur die Bildanalyse über den Qwen-Vision-Projektor ist im Medium-Profil
|
||||||
|
vorübergehend nicht verfügbar.
|
||||||
|
- Der Workaround ist noch nicht durch einen vollständig kontrollierten lokalen
|
||||||
|
A/B-Test mit identischen Anfragen bestätigt. Er entspricht jedoch dem in
|
||||||
|
llama.cpp Issue #19858 und verwandten Meldungen beschriebenen Workaround.
|
||||||
|
|
||||||
|
Referenz:
|
||||||
|
|
||||||
|
- https://github.com/ggml-org/llama.cpp/issues/19858
|
||||||
|
- https://github.com/ggml-org/llama.cpp/issues/21133
|
||||||
|
|
||||||
|
## Separates bekanntes Problem
|
||||||
|
|
||||||
|
Automatische Hermes-Hintergrundanfragen können weiterhin den einzigen aktiven
|
||||||
|
llama.cpp-Slot belegen und damit den Cache eines großen Chats verdrängen. Dieses
|
||||||
|
Slot-Eviction-Problem ist unabhängig vom MMProj-Workaround und muss separat in
|
||||||
|
der Hermes-Auxiliary-/Hintergrundverarbeitung geklärt werden.
|
||||||
|
|
||||||
|
## Nächster Entscheidungspunkt
|
||||||
|
|
||||||
|
Vor einer dauerhaften Übernahme kontrolliert vergleichen:
|
||||||
|
|
||||||
|
1. identischer Mehrturn-Textchat mit MMProj,
|
||||||
|
2. identischer Mehrturn-Textchat ohne MMProj,
|
||||||
|
3. jeweils keine parallelen Hermes-Hintergrundanfragen,
|
||||||
|
4. gelesene beziehungsweise erneut verarbeitete Prompt-Tokens und Prefill-Zeit
|
||||||
|
vergleichen.
|
||||||
@@ -1 +1 @@
|
|||||||
3f545beccee69d9975f466ec7e45fd9aacd8ba90
|
41ef91f7c8046087cdfbb276b79bff311ecf1c6d
|
||||||
|
|||||||
@@ -21,11 +21,13 @@ nach Standardbenchmark, Tool-Calling-Test und Kontexttest übernommen.
|
|||||||
- Fast, Medium, Large und Uncensored: integrierte Vision; der jeweilige
|
- Fast, Medium, Large und Uncensored: integrierte Vision; der jeweilige
|
||||||
Projektor liegt vollständig auf der RTX 3060
|
Projektor liegt vollständig auf der RTX 3060
|
||||||
|
|
||||||
Die produktive Runtime ist auf Commit
|
Die produktive Runtime ist auf llama.cpp Build 10718, Commit
|
||||||
`3f545beccee69d9975f466ec7e45fd9aacd8ba90` festgeschrieben. Gegen den
|
`41ef91f7c8046087cdfbb276b79bff311ecf1c6d`, festgeschrieben. Im lokalen
|
||||||
vorherigen Commit waren Antworten und Geschwindigkeit praktisch identisch;
|
A/B-Test blieben normaler Durchsatz, 70K-/120K-Kontext und Prompt-Cache
|
||||||
übernommen wurde er wegen der Qwen-/MTP-/Multimodal-Korrekturen und des
|
unverändert. Mit 100 angebotenen Werkzeugen stieg der Ausgabedurchsatz von
|
||||||
expliziten `--mmproj-device`.
|
56,03 auf 60,67 Tokens/s. Der Build begrenzt insbesondere einen teuren
|
||||||
|
Qwen3-Coder-Workaround wieder auf die betroffenen Modellfamilien, statt ihn
|
||||||
|
auch auf Qwen3.8 anzuwenden.
|
||||||
|
|
||||||
Die Dateien selbst sind nicht Bestandteil des Repositories. Pfade und Hashes
|
Die Dateien selbst sind nicht Bestandteil des Repositories. Pfade und Hashes
|
||||||
werden im lokalen Modellmanifest verwaltet.
|
werden im lokalen Modellmanifest verwaltet.
|
||||||
|
|||||||
@@ -94,6 +94,9 @@ from router_support import (
|
|||||||
HOST = os.environ.get("ROUTER_HOST", "0.0.0.0")
|
HOST = os.environ.get("ROUTER_HOST", "0.0.0.0")
|
||||||
PORT = int(os.environ.get("ROUTER_PORT", "8081"))
|
PORT = int(os.environ.get("ROUTER_PORT", "8081"))
|
||||||
UPSTREAM_URL = os.environ.get("UPSTREAM_URL", "http://127.0.0.1:8080").rstrip("/")
|
UPSTREAM_URL = os.environ.get("UPSTREAM_URL", "http://127.0.0.1:8080").rstrip("/")
|
||||||
|
REVIEW_UPSTREAM_URL = os.environ.get("REVIEW_UPSTREAM_URL", "").rstrip("/")
|
||||||
|
REVIEW_MODEL_NAME = os.environ.get("REVIEW_MODEL_NAME", "qwen-review").strip()
|
||||||
|
REVIEW_CONTEXT_LENGTH = int(os.environ.get("REVIEW_CONTEXT_LENGTH", "32768"))
|
||||||
PROFILE_SCRIPT = os.environ.get("PROFILE_SCRIPT", "/usr/local/bin/llama-profile")
|
PROFILE_SCRIPT = os.environ.get("PROFILE_SCRIPT", "/usr/local/bin/llama-profile")
|
||||||
PROFILE_DIR = os.environ.get(
|
PROFILE_DIR = os.environ.get(
|
||||||
"PROFILE_DIR", "/etc/systemd/system/mike-ai-llama-ui.service.d")
|
"PROFILE_DIR", "/etc/systemd/system/mike-ai-llama-ui.service.d")
|
||||||
@@ -225,6 +228,11 @@ def _parse_upstream(url: str) -> tuple[str, int]:
|
|||||||
|
|
||||||
|
|
||||||
UPSTREAM_HOST, UPSTREAM_PORT = _parse_upstream(UPSTREAM_URL)
|
UPSTREAM_HOST, UPSTREAM_PORT = _parse_upstream(UPSTREAM_URL)
|
||||||
|
if REVIEW_UPSTREAM_URL:
|
||||||
|
REVIEW_UPSTREAM_HOST, REVIEW_UPSTREAM_PORT = _parse_upstream(
|
||||||
|
REVIEW_UPSTREAM_URL)
|
||||||
|
else:
|
||||||
|
REVIEW_UPSTREAM_HOST, REVIEW_UPSTREAM_PORT = "", 0
|
||||||
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
@@ -1590,9 +1598,7 @@ class Handler(BaseHTTPRequestHandler):
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _models_payload() -> dict:
|
def _models_payload() -> dict:
|
||||||
return {
|
models = [
|
||||||
"object": "list",
|
|
||||||
"data": [
|
|
||||||
{
|
{
|
||||||
"id": f"qwen-{name}",
|
"id": f"qwen-{name}",
|
||||||
"object": "model",
|
"object": "model",
|
||||||
@@ -1602,7 +1608,19 @@ class Handler(BaseHTTPRequestHandler):
|
|||||||
"context_window": ctx,
|
"context_window": ctx,
|
||||||
}
|
}
|
||||||
for name, ctx in PROFILES.items()
|
for name, ctx in PROFILES.items()
|
||||||
],
|
]
|
||||||
|
if REVIEW_UPSTREAM_URL:
|
||||||
|
models.append({
|
||||||
|
"id": REVIEW_MODEL_NAME,
|
||||||
|
"object": "model",
|
||||||
|
"created": 0,
|
||||||
|
"owned_by": "ai-profile-router",
|
||||||
|
"context_length": REVIEW_CONTEXT_LENGTH,
|
||||||
|
"context_window": REVIEW_CONTEXT_LENGTH,
|
||||||
|
})
|
||||||
|
return {
|
||||||
|
"object": "list",
|
||||||
|
"data": models,
|
||||||
}
|
}
|
||||||
|
|
||||||
def _status_payload(self) -> dict:
|
def _status_payload(self) -> dict:
|
||||||
@@ -2165,6 +2183,7 @@ class Handler(BaseHTTPRequestHandler):
|
|||||||
|
|
||||||
data = None
|
data = None
|
||||||
requested_profile: str | None = None
|
requested_profile: str | None = None
|
||||||
|
requested_review = False
|
||||||
# Virtuelles Modell erkennen. Umschalten und Chat-Lease werden weiter
|
# Virtuelles Modell erkennen. Umschalten und Chat-Lease werden weiter
|
||||||
# unten atomar unter dem zentralen Orchestrierungs-Lock ausgeführt.
|
# unten atomar unter dem zentralen Orchestrierungs-Lock ausgeführt.
|
||||||
if body is not None and self.path.startswith("/v1/"):
|
if body is not None and self.path.startswith("/v1/"):
|
||||||
@@ -2173,7 +2192,10 @@ class Handler(BaseHTTPRequestHandler):
|
|||||||
except ValueError:
|
except ValueError:
|
||||||
data = None
|
data = None
|
||||||
model = data.get("model") if isinstance(data, dict) else None
|
model = data.get("model") if isinstance(data, dict) else None
|
||||||
if isinstance(model, str) and model in VIRTUAL_MODELS:
|
if (isinstance(model, str) and REVIEW_UPSTREAM_URL
|
||||||
|
and model == REVIEW_MODEL_NAME):
|
||||||
|
requested_review = True
|
||||||
|
elif isinstance(model, str) and model in VIRTUAL_MODELS:
|
||||||
requested_profile = VIRTUAL_MODELS[model]
|
requested_profile = VIRTUAL_MODELS[model]
|
||||||
elif isinstance(model, str) and model.startswith("qwen-"):
|
elif isinstance(model, str) and model.startswith("qwen-"):
|
||||||
# qwen-* ist der Namensraum des Routers
|
# qwen-* ist der Namensraum des Routers
|
||||||
@@ -2185,6 +2207,9 @@ class Handler(BaseHTTPRequestHandler):
|
|||||||
# kann kein zweiter Client zwischen Profilwahl und Upstream-Request das
|
# kann kein zweiter Client zwischen Profilwahl und Upstream-Request das
|
||||||
# Modell austauschen. Vision-Vorbereitung gehört zur selben Transaktion.
|
# Modell austauschen. Vision-Vorbereitung gehört zur selben Transaktion.
|
||||||
if isinstance(data, dict) and path == "/v1/chat/completions":
|
if isinstance(data, dict) and path == "/v1/chat/completions":
|
||||||
|
if requested_review:
|
||||||
|
self._review_chat_proxy(data)
|
||||||
|
return
|
||||||
self._chat_proxy(body, data, requested_profile)
|
self._chat_proxy(body, data, requested_profile)
|
||||||
return
|
return
|
||||||
if requested_profile is not None:
|
if requested_profile is not None:
|
||||||
@@ -2262,6 +2287,28 @@ class Handler(BaseHTTPRequestHandler):
|
|||||||
if lease_acquired:
|
if lease_acquired:
|
||||||
self._release_model_lease()
|
self._release_model_lease()
|
||||||
|
|
||||||
|
def _review_chat_proxy(self, data: dict) -> None:
|
||||||
|
"""Leitet kompakte Hermes-Hintergrundreviews an das Hilfsmodell.
|
||||||
|
|
||||||
|
Absichtlich ohne Hauptmodell-Lease und Profilwechsel: Der Review darf
|
||||||
|
den aktiven Qwen-Chat weder anhalten noch dessen Prompt-Cache ersetzen.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
data = _normalize_llamacpp_reasoning(data)
|
||||||
|
data = _cap_chat_generation(data)
|
||||||
|
if _request_has_image(data):
|
||||||
|
raise ValueError("qwen-review unterstützt keine Bilder")
|
||||||
|
data["model"] = REVIEW_MODEL_NAME
|
||||||
|
self._proxy_to(
|
||||||
|
json.dumps(data).encode(),
|
||||||
|
REVIEW_UPSTREAM_HOST,
|
||||||
|
REVIEW_UPSTREAM_PORT,
|
||||||
|
"Review-Modell",
|
||||||
|
)
|
||||||
|
except ValueError as exc:
|
||||||
|
self._send_error(400, str(exc), "invalid_request_error",
|
||||||
|
"invalid_review_request")
|
||||||
|
|
||||||
def _proxy_with_wait(self, body: bytes | None) -> None:
|
def _proxy_with_wait(self, body: bytes | None) -> None:
|
||||||
"""Leitet an llama.cpp weiter, wartet aber erst, bis Qwen verfügbar ist.
|
"""Leitet an llama.cpp weiter, wartet aber erst, bis Qwen verfügbar ist.
|
||||||
|
|
||||||
@@ -2295,9 +2342,13 @@ class Handler(BaseHTTPRequestHandler):
|
|||||||
STATE.active_chats -= 1
|
STATE.active_chats -= 1
|
||||||
|
|
||||||
def _proxy(self, body: bytes | None) -> None:
|
def _proxy(self, body: bytes | None) -> None:
|
||||||
|
self._proxy_to(body, UPSTREAM_HOST, UPSTREAM_PORT, "llama.cpp")
|
||||||
|
|
||||||
|
def _proxy_to(self, body: bytes | None, host: str, port: int,
|
||||||
|
upstream_name: str) -> None:
|
||||||
# An llama.cpp weiterleiten (Streaming bleibt erhalten).
|
# An llama.cpp weiterleiten (Streaming bleibt erhalten).
|
||||||
try:
|
try:
|
||||||
conn = http.client.HTTPConnection(UPSTREAM_HOST, UPSTREAM_PORT,
|
conn = http.client.HTTPConnection(host, port,
|
||||||
timeout=CONNECT_TIMEOUT)
|
timeout=CONNECT_TIMEOUT)
|
||||||
conn.connect()
|
conn.connect()
|
||||||
conn.sock.settimeout(REQUEST_TIMEOUT)
|
conn.sock.settimeout(REQUEST_TIMEOUT)
|
||||||
@@ -2306,7 +2357,7 @@ class Handler(BaseHTTPRequestHandler):
|
|||||||
conn.request(self.command, self.path, body=body, headers=headers)
|
conn.request(self.command, self.path, body=body, headers=headers)
|
||||||
resp = conn.getresponse()
|
resp = conn.getresponse()
|
||||||
except (OSError, http.client.HTTPException) as e:
|
except (OSError, http.client.HTTPException) as e:
|
||||||
self._send_error(502, f"llama.cpp nicht erreichbar: {e}",
|
self._send_error(502, f"{upstream_name} nicht erreichbar: {e}",
|
||||||
"server_error", "upstream_unavailable")
|
"server_error", "upstream_unavailable")
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user