Spaces:
Paused
Paused
Bound interactive inference backpressure
Browse filesExact source: ttracx/thoxroute@4f71bbe0dea6d8f029c06a66f010928f0f363550
- Dockerfile +2 -1
- README.md +7 -3
- app.py +22 -2
Dockerfile
CHANGED
|
@@ -23,7 +23,8 @@ ENV HF_HOME=/home/mambauser/.cache/huggingface \
|
|
| 23 |
THOX_FAST_MODEL_REPO=Qwen/Qwen2.5-0.5B-Instruct-GGUF \
|
| 24 |
THOX_FAST_MODEL_REVISION=9217f5db79a29953eb74d5343926648285ec7e67 \
|
| 25 |
THOX_FAST_MODEL_FILE=qwen2.5-0.5b-instruct-q4_k_m.gguf \
|
| 26 |
-
THOX_FAST_POOL_SIZE=
|
|
|
|
| 27 |
THOX_MAX_OUTPUT_TOKENS=128
|
| 28 |
|
| 29 |
# Bake the immutable public interactive model into the image. A RUNNING Space
|
|
|
|
| 23 |
THOX_FAST_MODEL_REPO=Qwen/Qwen2.5-0.5B-Instruct-GGUF \
|
| 24 |
THOX_FAST_MODEL_REVISION=9217f5db79a29953eb74d5343926648285ec7e67 \
|
| 25 |
THOX_FAST_MODEL_FILE=qwen2.5-0.5b-instruct-q4_k_m.gguf \
|
| 26 |
+
THOX_FAST_POOL_SIZE=1 \
|
| 27 |
+
THOX_FAST_QUEUE_TIMEOUT_S=6 \
|
| 28 |
THOX_MAX_OUTPUT_TOKENS=128
|
| 29 |
|
| 30 |
# Bake the immutable public interactive model into the image. A RUNNING Space
|
README.md
CHANGED
|
@@ -12,10 +12,14 @@ license: apache-2.0
|
|
| 12 |
|
| 13 |
This Space exposes one OpenAI-compatible endpoint:
|
| 14 |
|
| 15 |
-
- `thox-fast-chat`: eagerly loaded, bounded,
|
|
|
|
| 16 |
- `thox-rust-coder`: lazily loaded 25B/3B-active Rust-specialist target.
|
| 17 |
|
| 18 |
-
`GET /healthz` is ready only after the
|
| 19 |
-
|
|
|
|
|
|
|
|
|
|
| 20 |
The interactive model is pinned to immutable model revision
|
| 21 |
`9217f5db79a29953eb74d5343926648285ec7e67` and baked into the image.
|
|
|
|
| 12 |
|
| 13 |
This Space exposes one OpenAI-compatible endpoint:
|
| 14 |
|
| 15 |
+
- `thox-fast-chat`: eagerly loaded, bounded, full-CPU Qwen2.5 0.5B target with
|
| 16 |
+
a six-second queue ceiling;
|
| 17 |
- `thox-rust-coder`: lazily loaded 25B/3B-active Rust-specialist target.
|
| 18 |
|
| 19 |
+
`GET /healthz` is ready only after the interactive context is loaded and has
|
| 20 |
+
completed a one-token startup warmup. Streaming sends a role chunk before model
|
| 21 |
+
evaluation so upstream time-to-first-byte watchdogs do not abandon healthy CPU
|
| 22 |
+
work. First-party 15-second requests are capped at 16 output tokens by
|
| 23 |
+
ThoxRoute.
|
| 24 |
The interactive model is pinned to immutable model revision
|
| 25 |
`9217f5db79a29953eb74d5343926648285ec7e67` and baked into the image.
|
app.py
CHANGED
|
@@ -43,7 +43,10 @@ CODER_MODEL_FILE = os.environ.get(
|
|
| 43 |
"THOX_CODER_MODEL_FILE", "Qwen3-Coder-REAP-25B-A3B-Rust-Q4_K_M.gguf"
|
| 44 |
)
|
| 45 |
N_CTX = int(os.environ.get("THOX_N_CTX", "4096"))
|
| 46 |
-
FAST_POOL_SIZE = max(1, min(int(os.environ.get("THOX_FAST_POOL_SIZE", "
|
|
|
|
|
|
|
|
|
|
| 47 |
MAX_OUTPUT_TOKENS = max(
|
| 48 |
1, min(int(os.environ.get("THOX_MAX_OUTPUT_TOKENS", "128")), 512)
|
| 49 |
)
|
|
@@ -142,7 +145,7 @@ class Runtime:
|
|
| 142 |
def acquire(self, model_id: str) -> Lease:
|
| 143 |
if model_id == FAST_MODEL_ID:
|
| 144 |
try:
|
| 145 |
-
model = self._fast.
|
| 146 |
except queue.Empty as exc:
|
| 147 |
raise HTTPException(status_code=429, detail="interactive capacity busy") from exc
|
| 148 |
return Lease(model=model, release=lambda: self._fast.put(model))
|
|
@@ -251,6 +254,23 @@ def _stream_completion(req: ChatRequest, lease: Lease) -> Iterator[bytes]:
|
|
| 251 |
completion_id = _completion_id()
|
| 252 |
created = int(time.time())
|
| 253 |
try:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 254 |
chunks = lease.model.create_chat_completion(
|
| 255 |
messages=_messages(req),
|
| 256 |
max_tokens=_max_tokens(req),
|
|
|
|
| 43 |
"THOX_CODER_MODEL_FILE", "Qwen3-Coder-REAP-25B-A3B-Rust-Q4_K_M.gguf"
|
| 44 |
)
|
| 45 |
N_CTX = int(os.environ.get("THOX_N_CTX", "4096"))
|
| 46 |
+
FAST_POOL_SIZE = max(1, min(int(os.environ.get("THOX_FAST_POOL_SIZE", "1")), 2))
|
| 47 |
+
FAST_QUEUE_TIMEOUT_S = max(
|
| 48 |
+
0.1, min(float(os.environ.get("THOX_FAST_QUEUE_TIMEOUT_S", "6")), 10.0)
|
| 49 |
+
)
|
| 50 |
MAX_OUTPUT_TOKENS = max(
|
| 51 |
1, min(int(os.environ.get("THOX_MAX_OUTPUT_TOKENS", "128")), 512)
|
| 52 |
)
|
|
|
|
| 145 |
def acquire(self, model_id: str) -> Lease:
|
| 146 |
if model_id == FAST_MODEL_ID:
|
| 147 |
try:
|
| 148 |
+
model = self._fast.get(timeout=FAST_QUEUE_TIMEOUT_S)
|
| 149 |
except queue.Empty as exc:
|
| 150 |
raise HTTPException(status_code=429, detail="interactive capacity busy") from exc
|
| 151 |
return Lease(model=model, release=lambda: self._fast.put(model))
|
|
|
|
| 254 |
completion_id = _completion_id()
|
| 255 |
created = int(time.time())
|
| 256 |
try:
|
| 257 |
+
# Send a valid role chunk before llama prompt evaluation. This proves
|
| 258 |
+
# the stream is alive inside ThoxRoute's short time-to-first-byte budget
|
| 259 |
+
# and prevents a healthy CPU inference from being abandoned at 12 s.
|
| 260 |
+
initial = {
|
| 261 |
+
"id": completion_id,
|
| 262 |
+
"object": "chat.completion.chunk",
|
| 263 |
+
"created": created,
|
| 264 |
+
"model": req.model,
|
| 265 |
+
"choices": [
|
| 266 |
+
{
|
| 267 |
+
"index": 0,
|
| 268 |
+
"delta": {"role": "assistant", "content": ""},
|
| 269 |
+
"finish_reason": None,
|
| 270 |
+
}
|
| 271 |
+
],
|
| 272 |
+
}
|
| 273 |
+
yield f"data: {json.dumps(initial, separators=(',', ':'))}\n\n".encode()
|
| 274 |
chunks = lease.model.create_chat_completion(
|
| 275 |
messages=_messages(req),
|
| 276 |
max_tokens=_max_tokens(req),
|