mirror of
https://github.com/turnstonelabs/turnstone.git
synced 2026-08-25 05:14:47 -06:00
381057e6ed
Speech-to-text against an omni chat model (e.g. Gemma-4 on vLLM) was broken end to end: - The browser records webm/opus, but the omni chat lane only decodes wav/mp3 (it sniffs the bytes), so every clip came back 400 "Invalid or unsupported audio file". Transcode the upload to 16 kHz mono WAV with ffmpeg first, hardened against the untrusted blob: -protocol_whitelist pipe (no file:/http: SSRF), -vn, and a duration cap. - The chat STT path calls the raw client and so bypasses the provider's request shaping. It now forces enable_thinking=false (via the model's thinking_param): leaving reasoning on costs ~11x latency and returns empty content on some clips. The prompt precedes the audio part (the order Gemma documents for transcription) and max_tokens is capped. Add a streaming variant: POST .../speech-to-text/stream returns the transcript as plain-text deltas and the composer fills them in live (~0.3s to first word). The blocking stream is driven from one worker thread that owns and closes the upstream connection. Drop the gemma skip_special_tokens server-compat workaround: the vLLM bug it patched is fixed upstream, and a stale shim can corrupt output. The node image now installs ffmpeg; rebuild to run this live.
72 lines
2.8 KiB
Docker
72 lines
2.8 KiB
Docker
# =============================================================================
|
|
# Turnstone — Docker build with uv for reproducible, locked installs
|
|
# Single image for all services: server, console, channel, eval
|
|
# =============================================================================
|
|
|
|
FROM python:3.14-slim
|
|
|
|
LABEL org.opencontainers.image.title="turnstone" \
|
|
org.opencontainers.image.description="Multi-node AI orchestration platform"
|
|
|
|
COPY --from=ghcr.io/astral-sh/uv:0.11.21 /uv /usr/local/bin/uv
|
|
|
|
# Remove the slim image's man page exclusion so man-db has actual content
|
|
RUN rm -f /etc/dpkg/dpkg.cfg.d/docker
|
|
|
|
# System dependencies: psycopg (libpq5), developer tooling for agent workflows.
|
|
# ripgrep is the preferred backend for the search tool — natively bounds
|
|
# per-line, per-file, and per-filesize so pathological inputs (minified
|
|
# bundles, training-data JSONL with multi-MB single records) can't OOM us.
|
|
# ffmpeg transcodes omni STT uploads (browser webm/opus) to the 16 kHz mono
|
|
# WAV the omni chat-audio lane decodes.
|
|
RUN apt-get update && apt-get upgrade -y && apt-get install -y --no-install-recommends \
|
|
libpq5 git curl jq man-db manpages procps file ripgrep ffmpeg \
|
|
&& rm -rf /var/lib/apt/lists/*
|
|
|
|
# Node.js LTS (for npx-based MCP servers like @modelcontextprotocol/server-github)
|
|
COPY --from=node:24-slim /usr/local/bin/node /usr/local/bin/node
|
|
COPY --from=node:24-slim /usr/local/lib/node_modules /usr/local/lib/node_modules
|
|
RUN ln -s ../lib/node_modules/npm/bin/npm-cli.js /usr/local/bin/npm \
|
|
&& ln -s ../lib/node_modules/npm/bin/npx-cli.js /usr/local/bin/npx
|
|
|
|
# Non-root user
|
|
RUN useradd --create-home --shell /bin/bash turnstone
|
|
|
|
WORKDIR /app
|
|
|
|
# Install dependencies first (cached layer — only re-runs when deps change)
|
|
COPY pyproject.toml uv.lock README.md LICENSE NOTICE THIRD-PARTY-NOTICES ./
|
|
RUN uv sync --frozen --no-install-project --no-dev \
|
|
--no-compile --extra all
|
|
|
|
# Install the project itself
|
|
COPY turnstone/ turnstone/
|
|
RUN uv sync --frozen --no-dev \
|
|
--no-compile --extra all
|
|
|
|
# Compile bytecode in a separate step (avoids fd exhaustion during install)
|
|
RUN python -m compileall -q .venv turnstone/
|
|
|
|
# Add venv to PATH so entry points are found
|
|
ENV PATH="/app/.venv/bin:$PATH"
|
|
|
|
# Health check script (stdlib only, no pip deps needed)
|
|
COPY docker/healthcheck.py /usr/local/bin/healthcheck.py
|
|
|
|
# Entrypoint script — runs migrations before starting
|
|
COPY docker/entrypoint.sh /usr/local/bin/entrypoint.sh
|
|
|
|
# Data directory — SQLite DB is created in CWD
|
|
WORKDIR /data
|
|
RUN chown turnstone:turnstone /data
|
|
|
|
# Workspace mount point — bind-mount a host directory here
|
|
RUN mkdir -p /workspace && chown turnstone:turnstone /workspace
|
|
|
|
USER turnstone
|
|
|
|
ENTRYPOINT ["entrypoint.sh"]
|
|
|
|
# Default command (overridden per service in compose.yaml)
|
|
CMD ["turnstone-server", "--host", "0.0.0.0", "--port", "8080"]
|