-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcompose.yaml
More file actions
199 lines (190 loc) · 8.29 KB
/
Copy pathcompose.yaml
File metadata and controls
199 lines (190 loc) · 8.29 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
name: vocagateway
# Every gateway service takes the same settings; only the accelerator and the
# device wiring differ per profile. Keeping them in one anchor means a variable
# added here reaches all three services instead of two of them.
# The commit each image is built from, reported by /v1/admin/status and the
# WebUI. `just up` exports these from git; a bare `docker compose up --build`
# leaves them empty and the gateway reports `commit: null`. They sit last in the
# Dockerfile, so a new commit only invalidates the final ENV layer.
x-gateway-build-args: &gateway-build-args
VOCAGATEWAY_GIT_COMMIT: ${VOCAGATEWAY_GIT_COMMIT:-}
VOCAGATEWAY_GIT_COMMIT_SUBJECT: ${VOCAGATEWAY_GIT_COMMIT_SUBJECT:-}
VOCAGATEWAY_GIT_COMMIT_DATE: ${VOCAGATEWAY_GIT_COMMIT_DATE:-}
# Extra cmake flags for the whisper.cpp build, appended last so they override
# the Dockerfile's defaults. See "Tuning the whisper.cpp build" in
# docs/deployment.md — the common one is
# VOCAGATEWAY_WHISPER_CMAKE_EXTRA=-DCMAKE_CUDA_ARCHITECTURES=89-real
WHISPER_CMAKE_EXTRA: ${VOCAGATEWAY_WHISPER_CMAKE_EXTRA:-}
# Blank is resolved to the builder's CPU count. Lower it if a build is killed
# for memory — the cuda one is the hungry one.
BUILD_JOBS: ${VOCAGATEWAY_BUILD_JOBS:-}
x-gateway-environment: &gateway-environment
VOCAGATEWAY_TOKEN_FILE: /run/secrets/vocagateway_token
VOCAGATEWAY_DEBUG: ${VOCAGATEWAY_DEBUG:-false}
# Blank means "not set": the gateway ignores an empty override and falls back
# to auto-discovery. On the default bridge network discovery only ever sees
# the container's private bridge IP, so this is how a phone-reachable address
# gets into the pairing QR without switching to host networking.
VOCAGATEWAY_PUBLIC_URL: ${VOCAGATEWAY_PUBLIC_URL:-}
VOCAGATEWAY_PAIRING_URL: ${VOCAGATEWAY_PAIRING_URL:-}
# Listener inside the container. Only worth changing under
# VOCAGATEWAY_NETWORK_MODE=host, where the container binds the host directly
# and the ports mapping below is discarded.
VOCAGATEWAY_BIND_HOST: ${VOCAGATEWAY_BIND_HOST:-0.0.0.0}
VOCAGATEWAY_PORT: ${VOCAGATEWAY_PORT:-8765}
VOCAGATEWAY_ENGINE: ${VOCAGATEWAY_ENGINE:-auto}
# `fast` decodes whisper.cpp greedily instead of with the narrowed beam
# search. Cheaper on a CPU-only host; compare accuracy on your own audio
# before keeping it.
VOCAGATEWAY_WHISPER_DECODER_PRESET: ${VOCAGATEWAY_WHISPER_DECODER_PRESET:-quality}
VOCAGATEWAY_RETENTION_HOURS: ${VOCAGATEWAY_RETENTION_HOURS:-24}
VOCAGATEWAY_DELETE_SUCCESSFUL_AUDIO: ${VOCAGATEWAY_DELETE_SUCCESSFUL_AUDIO:-true}
# Transcript cleanup. Off unless the `cleanup` profile is up: the gateway
# image ships no text model and no llama.cpp runtime, so leaving these blank
# is the same as the feature not existing. Only the address is set here — the
# rest stays under the operator's control in the WebUI.
#
# docker compose --profile cleanup up -d
#
# The address names the sidecar on Compose's own private network. It is never
# published, and the gateway refuses any address that is not loopback, a
# private range, or a bare service name like this one.
VOCAGATEWAY_CLEANUP_ENDPOINT: ${VOCAGATEWAY_CLEANUP_ENDPOINT:-}
VOCAGATEWAY_CLEANUP_API_KEY: ${VOCAGATEWAY_CLEANUP_API_KEY:-}
# Everything the three services share. Each one then names only what actually
# differs: its image tag, its ACCEL build arg, and its device wiring.
x-gateway-service: &gateway-service
restart: unless-stopped
init: true
network_mode: ${VOCAGATEWAY_NETWORK_MODE:-bridge}
ports:
- "${VOCAGATEWAY_PUBLISH_HOST:-127.0.0.1}:${VOCAGATEWAY_PUBLISH_PORT:-8765}:${VOCAGATEWAY_PORT:-8765}"
environment: *gateway-environment
secrets: [vocagateway_token]
volumes: [vocagateway-data:/data]
# The gateway never escalates: it runs as uid 10001 from the first instruction
# of the entrypoint and needs no capability the kernel grants a process by
# default.
security_opt: [no-new-privileges:true]
cap_drop: [ALL]
# whisper-cli writes its transcript to a per-request temporary directory. On
# the default overlay filesystem every one of those is a copy-up; in RAM it is
# free. The cap is well above what a transcript needs — it exists so a runaway
# cannot spend the host's memory.
tmpfs:
- /tmp:size=64m,mode=1777
# json-file keeps every byte forever by default, which on an appliance that is
# meant to run untouched for months eventually fills the disk.
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"
services:
gateway:
<<: *gateway-service
image: ${VOCAGATEWAY_IMAGE:-vocagateway:local}
build:
context: .
dockerfile: Dockerfile
args:
<<: *gateway-build-args
ACCEL: cpu
gateway-cuda:
<<: *gateway-service
profiles: ["cuda"]
image: vocagateway:cuda
build:
context: .
dockerfile: Dockerfile
args:
<<: *gateway-build-args
ACCEL: cuda
# `gpus` is the whole request; NVIDIA_VISIBLE_DEVICES is what the Container
# Toolkit sets from it, so naming it again in the environment adds nothing.
gpus: all
gateway-vulkan:
<<: *gateway-service
profiles: ["vulkan"]
image: vocagateway:vulkan
build:
context: .
dockerfile: Dockerfile
args:
<<: *gateway-build-args
ACCEL: vulkan
devices:
- /dev/dri:/dev/dri
# Passing /dev/dri through is not enough on its own: the render node is
# root:render on the host, and the gateway runs as uid 10001, which is in
# neither group. Without this the open fails with EACCES, Vulkan enumerates
# no physical device, and whisper.cpp falls back to Mesa's software
# rasteriser — slower than the plain CPU image, and silent about it.
# The render GID differs per distribution (993 on Ubuntu, 104 on Debian);
# read the host's with: stat -c '%g' /dev/dri/renderD128
group_add:
- "${VOCAGATEWAY_RENDER_GID:-993}"
- "${VOCAGATEWAY_VIDEO_GID:-44}"
# Optional transcript-cleanup sidecar. Opt-in, pinned by digest, and never
# published: only the gateway can reach it, over Compose's private network.
#
# The model is *not* baked into the image. Mount a GGUF you installed
# yourself, read-only, and point VOCAGATEWAY_CLEANUP_MODEL_FILE at it:
#
# VOCAGATEWAY_CLEANUP_MODEL_FILE=/models/Qwen3-0.6B-Q8_0.gguf \
# VOCAGATEWAY_CLEANUP_MODEL_DIR=$HOME/.local/share/vocagateway/models/cleanup \
# VOCAGATEWAY_CLEANUP_ENDPOINT=cleanup:8080 \
# VOCAGATEWAY_CLEANUP_API_KEY=$(openssl rand -hex 24) \
# docker compose --profile cleanup up -d
cleanup:
profiles: ["cleanup"]
# Pinned by digest, not by tag: a moving tag would change the runtime under
# a gateway that was tested against a specific one. Refresh deliberately.
image: ${VOCAGATEWAY_CLEANUP_IMAGE:-ghcr.io/ggml-org/llama.cpp:server}
restart: unless-stopped
init: true
# Deliberately no `ports:`. The gateway reaches it by service name on the
# project's default network; nothing outside the project can.
expose: ["8080"]
command:
- --model
- ${VOCAGATEWAY_CLEANUP_MODEL_FILE:-/models/model.gguf}
- --host
- 0.0.0.0
- --port
- "8080"
- --ctx-size
- "8192"
- --parallel
- "1"
# Required for the non-thinking chat-template switch the gateway sends.
- --jinja
- --no-webui
# Read from a secret file rather than argv: the key would otherwise be
# visible in `docker inspect` and in the process list. A missing secret
# fails this service at start, and leaves `docker compose config` (which
# validates every profile) working for everyone not using cleanup.
- --api-key-file
- /run/secrets/vocagateway_cleanup_key
secrets: [vocagateway_cleanup_key]
volumes:
- ${VOCAGATEWAY_CLEANUP_MODEL_DIR:-./models}:/models:ro
read_only: true
security_opt: [no-new-privileges:true]
cap_drop: [ALL]
tmpfs:
- /tmp:size=64m,mode=1777
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"
secrets:
vocagateway_token:
environment: VOCAGATEWAY_TOKEN
# Only read by the opt-in `cleanup` profile. The gateway gets the same value
# through VOCAGATEWAY_CLEANUP_API_KEY, which is how the two agree on it.
vocagateway_cleanup_key:
environment: VOCAGATEWAY_CLEANUP_API_KEY
volumes:
vocagateway-data: