Spaces:
Sleeping
Sleeping
deploy thoxfast 058d0e08b664
Browse filesDeploy the production-validated provider payload from ThoxRoute main 058d0e08b66487267a9f9389e6d0679f1b2361a7 (PR #69). Preserves existing .gitattributes.
- Dockerfile +1 -0
- README.md +25 -1
- THOXROUTE_GITHUB_SHA +1 -0
- app.py +22 -0
Dockerfile
CHANGED
|
@@ -35,6 +35,7 @@ RUN python -c "from huggingface_hub import hf_hub_download; hf_hub_download('Qwe
|
|
| 35 |
|
| 36 |
WORKDIR /app
|
| 37 |
COPY --chown=$MAMBA_USER:$MAMBA_USER app.py /app/app.py
|
|
|
|
| 38 |
|
| 39 |
EXPOSE 7860
|
| 40 |
CMD ["python", "/app/app.py"]
|
|
|
|
| 35 |
|
| 36 |
WORKDIR /app
|
| 37 |
COPY --chown=$MAMBA_USER:$MAMBA_USER app.py /app/app.py
|
| 38 |
+
COPY --chown=$MAMBA_USER:$MAMBA_USER THOXROUTE_GITHUB_SHA /app/THOXROUTE_GITHUB_SHA
|
| 39 |
|
| 40 |
EXPOSE 7860
|
| 41 |
CMD ["python", "/app/app.py"]
|
README.md
CHANGED
|
@@ -22,7 +22,10 @@ that request the full measured container CPU quota. A bounded six-second queue
|
|
| 22 |
absorbs overlap; operators can still opt into at most two contexts with
|
| 23 |
`THOX_FAST_POOL_SIZE` when throughput is more important than the 15-second cold
|
| 24 |
turn contract. CPU allocation comes from the cgroup quota, so it does not repeat
|
| 25 |
-
the historical host-count oversubscription regression.
|
|
|
|
|
|
|
|
|
|
| 26 |
evaluation so upstream time-to-first-byte watchdogs do not abandon healthy CPU
|
| 27 |
work; two-second SSE comments keep the stream live during synchronous prompt
|
| 28 |
evaluation. The interactive provider itself caps every request at 16 output
|
|
@@ -34,3 +37,24 @@ across otherwise unrelated personas without replacing caller instructions; the
|
|
| 34 |
provider does not add this fast-chat prefix to specialist requests.
|
| 35 |
The interactive model is pinned to immutable model revision
|
| 36 |
`9217f5db79a29953eb74d5343926648285ec7e67` and baked into the image.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 22 |
absorbs overlap; operators can still opt into at most two contexts with
|
| 23 |
`THOX_FAST_POOL_SIZE` when throughput is more important than the 15-second cold
|
| 24 |
turn contract. CPU allocation comes from the cgroup quota, so it does not repeat
|
| 25 |
+
the historical host-count oversubscription regression. The same quota is passed
|
| 26 |
+
to llama.cpp's generation and prompt-evaluation thread pools; the batch pool is
|
| 27 |
+
never allowed to infer a larger host CPU count and oversubscribe the constrained
|
| 28 |
+
Space during a cold persona prefix. Streaming sends a role chunk before model
|
| 29 |
evaluation so upstream time-to-first-byte watchdogs do not abandon healthy CPU
|
| 30 |
work; two-second SSE comments keep the stream live during synchronous prompt
|
| 31 |
evaluation. The interactive provider itself caps every request at 16 output
|
|
|
|
| 37 |
provider does not add this fast-chat prefix to specialist requests.
|
| 38 |
The interactive model is pinned to immutable model revision
|
| 39 |
`9217f5db79a29953eb74d5343926648285ec7e67` and baked into the image.
|
| 40 |
+
The health response also reports the exact 40-character ThoxRoute Git revision
|
| 41 |
+
baked into the Space image. Production acceptance must match this value rather
|
| 42 |
+
than inferring deployment identity from a RUNNING stage alone.
|
| 43 |
+
|
| 44 |
+
## Atomic production release
|
| 45 |
+
|
| 46 |
+
From a clean checkout at the exact validated commit, supply a newly issued
|
| 47 |
+
fine-grained token scoped to write only `Thox-ai/thoxrustcoder`:
|
| 48 |
+
|
| 49 |
+
```bash
|
| 50 |
+
export THOX_FAST_HF_DEPLOY_TOKEN='set-in-protected-shell-environment'
|
| 51 |
+
python ops/deploy_thoxfast_space.py \
|
| 52 |
+
--expected-source "$(git rev-parse HEAD)" \
|
| 53 |
+
--expected-parent 45b26461379624b63430c7c3477eff63868cfaac
|
| 54 |
+
```
|
| 55 |
+
|
| 56 |
+
The helper ignores generic cached credentials, validates token metadata,
|
| 57 |
+
rejects the known compromised token name, stages only the runtime allowlist,
|
| 58 |
+
injects the owning Git SHA, and refuses to upload if either source cleanliness
|
| 59 |
+
or the exact Space parent has changed. Never place the token in the repository,
|
| 60 |
+
command arguments, logs, or a generic `HF_TOKEN` variable.
|
THOXROUTE_GITHUB_SHA
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
058d0e08b66487267a9f9389e6d0679f1b2361a7
|
app.py
CHANGED
|
@@ -17,6 +17,7 @@ import uuid
|
|
| 17 |
from contextlib import asynccontextmanager
|
| 18 |
from collections.abc import Iterator
|
| 19 |
from dataclasses import dataclass
|
|
|
|
| 20 |
from typing import Any
|
| 21 |
|
| 22 |
from fastapi import FastAPI, HTTPException
|
|
@@ -71,6 +72,20 @@ DEFAULT_SYSTEM = (
|
|
| 71 |
"ran locally or on-device."
|
| 72 |
)
|
| 73 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 74 |
|
| 75 |
def _usable_cpus() -> int:
|
| 76 |
"""Return the container CPU quota instead of the misleading host count."""
|
|
@@ -114,6 +129,11 @@ def _new_llama(path: str, *, threads: int):
|
|
| 114 |
model_path=path,
|
| 115 |
n_ctx=N_CTX,
|
| 116 |
n_threads=threads,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 117 |
n_gpu_layers=int(os.environ.get("THOX_GPU_LAYERS", "-1")),
|
| 118 |
verbose=False,
|
| 119 |
)
|
|
@@ -275,6 +295,8 @@ def healthz() -> dict[str, Any]:
|
|
| 275 |
"max_output_tokens": MAX_OUTPUT_TOKENS,
|
| 276 |
"n_ctx": N_CTX,
|
| 277 |
"threads": _usable_cpus(),
|
|
|
|
|
|
|
| 278 |
}
|
| 279 |
|
| 280 |
|
|
|
|
| 17 |
from contextlib import asynccontextmanager
|
| 18 |
from collections.abc import Iterator
|
| 19 |
from dataclasses import dataclass
|
| 20 |
+
from pathlib import Path
|
| 21 |
from typing import Any
|
| 22 |
|
| 23 |
from fastapi import FastAPI, HTTPException
|
|
|
|
| 72 |
"ran locally or on-device."
|
| 73 |
)
|
| 74 |
|
| 75 |
+
SOURCE_REVISION_FILE = Path(
|
| 76 |
+
os.environ.get("THOX_SOURCE_REVISION_FILE", "/app/THOXROUTE_GITHUB_SHA")
|
| 77 |
+
)
|
| 78 |
+
|
| 79 |
+
|
| 80 |
+
def _source_revision() -> str:
|
| 81 |
+
"""Return the exact owning Git revision baked into the Space image."""
|
| 82 |
+
|
| 83 |
+
try:
|
| 84 |
+
revision = SOURCE_REVISION_FILE.read_text(encoding="utf-8").strip()
|
| 85 |
+
except OSError:
|
| 86 |
+
return "unknown"
|
| 87 |
+
return revision if len(revision) == 40 and all(c in "0123456789abcdef" for c in revision) else "unknown"
|
| 88 |
+
|
| 89 |
|
| 90 |
def _usable_cpus() -> int:
|
| 91 |
"""Return the container CPU quota instead of the misleading host count."""
|
|
|
|
| 129 |
model_path=path,
|
| 130 |
n_ctx=N_CTX,
|
| 131 |
n_threads=threads,
|
| 132 |
+
# llama.cpp uses the batch pool for prompt evaluation and may derive
|
| 133 |
+
# its default from the host CPU count. Spaces expose more host CPUs
|
| 134 |
+
# than the container quota, so leaving this unset oversubscribes the
|
| 135 |
+
# exact cold-prefix phase that owns the interactive latency budget.
|
| 136 |
+
n_threads_batch=threads,
|
| 137 |
n_gpu_layers=int(os.environ.get("THOX_GPU_LAYERS", "-1")),
|
| 138 |
verbose=False,
|
| 139 |
)
|
|
|
|
| 295 |
"max_output_tokens": MAX_OUTPUT_TOKENS,
|
| 296 |
"n_ctx": N_CTX,
|
| 297 |
"threads": _usable_cpus(),
|
| 298 |
+
"prompt_threads": _usable_cpus(),
|
| 299 |
+
"source_revision": _source_revision(),
|
| 300 |
}
|
| 301 |
|
| 302 |
|