build(client): use locked uv environment in launcher and Docker
This commit is contained in:
@@ -10,8 +10,12 @@ the implementation at the recorded date; current operating instructions live in
|
||||
### Changed
|
||||
|
||||
- Added a uv-managed Python 3.12 environment and Ruff, mypy, and pytest quality
|
||||
checks. Split the FastAPI service into configuration, route, provider,
|
||||
checks, all contained in `s2s-client/`. Startup and Docker use the committed
|
||||
lockfile. Split the FastAPI service into configuration, route, provider,
|
||||
context/reasoning, and realtime modules while retaining `server:app` startup.
|
||||
- Added Pydantic response contracts with permissive upstream fields and original
|
||||
payload serialization. Captured HTTP, request-schema, and realtime regression
|
||||
fixtures preserve existing API behavior, including known failures.
|
||||
- Removed the legacy browser site in favor of the React application in
|
||||
`s2s-frontend`. FastAPI now serves only backend and documentation routes.
|
||||
- Retired daily talk-time accounting and the associated Hugging Face account
|
||||
|
||||
+13
-5
@@ -2,16 +2,24 @@
|
||||
# Serve backend APIs, the WebSocket proxy, and shared project documentation.
|
||||
# Run the React/Vite frontend separately; this image contains no browser UI.
|
||||
# HF Spaces (sdk: docker) routes traffic to $PORT, default 7860.
|
||||
FROM python:3.11-slim
|
||||
FROM python:3.12.14-slim
|
||||
|
||||
COPY --from=ghcr.io/astral-sh/uv:0.12.5 /uv /uvx /bin/
|
||||
|
||||
ENV UV_LINK_MODE=copy \
|
||||
UV_PYTHON_DOWNLOADS=never \
|
||||
PATH="/app/s2s-client/.venv/bin:$PATH"
|
||||
|
||||
WORKDIR /app/s2s-client
|
||||
|
||||
COPY s2s-client/requirements.txt .
|
||||
RUN pip install --no-cache-dir -r requirements.txt
|
||||
COPY s2s-client/pyproject.toml s2s-client/uv.lock ./
|
||||
RUN uv sync --locked --no-dev --no-install-project
|
||||
|
||||
COPY s2s-client/ .
|
||||
COPY s2s-client/README.md s2s-client/server.py ./
|
||||
COPY s2s-client/s2s_client/ ./s2s_client/
|
||||
COPY docs/ /app/docs/
|
||||
RUN uv sync --locked --no-dev
|
||||
|
||||
EXPOSE 7860
|
||||
|
||||
CMD ["uvicorn", "server:app", "--host", "0.0.0.0", "--port", "7860"]
|
||||
CMD ["uvicorn", "s2s_client.main:app", "--host", "0.0.0.0", "--port", "7860"]
|
||||
|
||||
+10
-3
@@ -31,17 +31,24 @@ Build from the repository root so the container includes the documentation:
|
||||
docker build -f s2s-client/Dockerfile -t s2s-client .
|
||||
```
|
||||
|
||||
Run the backend regression tests from the repository root after installing
|
||||
`requirements.txt` in `.venv`:
|
||||
The Python project is contained in this directory: `pyproject.toml`, `uv.lock`,
|
||||
`.python-version`, `.venv`, quality tools, and tests. Use uv 0.12.5 and Python
|
||||
3.12 (uv can provision Python). From the repository root:
|
||||
|
||||
```bash
|
||||
.venv/bin/python -m unittest discover -s s2s-client/tests -v
|
||||
make -C s2s-client install
|
||||
make -C s2s-client check
|
||||
```
|
||||
|
||||
Tests isolate environment configuration, use HTTP fixtures for allocation and
|
||||
caller authentication, and start a loopback WebSocket service to verify audio
|
||||
frames, keepalive, and teardown. No deployed services or database are needed.
|
||||
|
||||
See [backend development and compatibility](../docs/client/development.md) for
|
||||
formatting, typing, schema policy, optional Git hooks, and deployment checks.
|
||||
`uvicorn server:app --app-dir s2s-client` remains a supported entry point;
|
||||
the implementation now lives in `s2s_client/`.
|
||||
|
||||
FastAPI's API explorer remains at `/docs`. Project documents are served as files below
|
||||
`/docs/client/`, `/docs/speech/`, `/docs/adr/`, `/docs/examples/`, and
|
||||
`/docs/proposals/`. The historical `/project/` and `/public/docs.html` URLs
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
fastapi==0.115.6
|
||||
uvicorn[standard]==0.34.0
|
||||
httpx==0.28.1
|
||||
python-dotenv==1.2.2
|
||||
@@ -0,0 +1,53 @@
|
||||
#!/usr/bin/env bash
|
||||
# Build the actual runtime and check HTTP behavior without external services.
|
||||
set -euo pipefail
|
||||
|
||||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
||||
IMAGE="s2s-client-smoke:$(date +%s)-$$"
|
||||
container_id=""
|
||||
cleanup() {
|
||||
if [ -n "$container_id" ]; then
|
||||
docker rm --force "$container_id" >/dev/null
|
||||
fi
|
||||
docker image rm "$IMAGE" >/dev/null 2>&1 || true
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
docker build --file "$ROOT_DIR/s2s-client/Dockerfile" --tag "$IMAGE" "$ROOT_DIR"
|
||||
container_id="$(docker run --detach --publish 127.0.0.1::7860 "$IMAGE")"
|
||||
port="$(docker port "$container_id" 7860/tcp)"
|
||||
ready=false
|
||||
for ((attempt = 0; attempt < 60; attempt++)); do
|
||||
if curl --noproxy '*' --silent --fail --max-time 1 "http://$port/api/config" >/dev/null; then
|
||||
ready=true
|
||||
break
|
||||
fi
|
||||
sleep 0.5
|
||||
done
|
||||
if [ "$ready" != true ]; then
|
||||
docker logs "$container_id"
|
||||
exit 1
|
||||
fi
|
||||
docker exec -i "$container_id" python - <<'PY'
|
||||
import json
|
||||
import urllib.error
|
||||
import urllib.request
|
||||
|
||||
base = "http://127.0.0.1:7860"
|
||||
with urllib.request.urlopen(base + "/api/config") as response:
|
||||
assert json.load(response) == {
|
||||
"search": False, "lb": False, "allowDirect": True, "s2sUrl": "",
|
||||
"primaryPrompt": "", "reasoningType": "PROXY", "injectProfile": False,
|
||||
"debugPrompt": False, "startSessionMode": "", "theme": "", "apipilot": False,
|
||||
}
|
||||
for path in ["/docs", "/docs/README.md", "/openapi.json"]:
|
||||
with urllib.request.urlopen(base + path) as response:
|
||||
assert response.status == 200
|
||||
try:
|
||||
urllib.request.urlopen(base + "/")
|
||||
except urllib.error.HTTPError as error:
|
||||
assert error.code == 404
|
||||
else:
|
||||
raise AssertionError("The backend root must remain 404")
|
||||
print("Docker runtime smoke checks passed")
|
||||
PY
|
||||
Reference in New Issue
Block a user