Mirrors the airports runner flow: test, publish to the Gitea registry, then pull APP_IMAGE into the z00 compose stack.
174 lines
5.2 KiB
YAML
174 lines
5.2 KiB
YAML
x-data volumes:
|
||
app-data: &app-data
|
||
- ./database:/app/database
|
||
- ./storage/app:/app/storage/app
|
||
- ./storage/logs:/app/storage/logs
|
||
|
||
x-app-env: &app-env
|
||
APP_NAME: AndyTranscribe
|
||
APP_ENV: ${APP_ENV:-local}
|
||
APP_KEY: ${APP_KEY}
|
||
APP_DEBUG: ${APP_DEBUG:-true}
|
||
APP_URL: ${APP_URL:-http://localhost:8080}
|
||
APP_PORT: ${APP_HOST_PORT:-8080}
|
||
LOG_CHANNEL: stderr
|
||
DB_CONNECTION: sqlite
|
||
DB_DATABASE: /app/database/database.sqlite
|
||
# File drivers avoid SQLite lock storms: Livewire polls + database queue +
|
||
# session/cache all writing the same sqlite file caused "database is locked".
|
||
SESSION_DRIVER: file
|
||
QUEUE_CONNECTION: database
|
||
CACHE_STORE: file
|
||
BROADCAST_CONNECTION: reverb
|
||
FILESYSTEM_DISK: local
|
||
REVERB_APP_ID: ${REVERB_APP_ID:-andytranscribe}
|
||
REVERB_APP_KEY: ${REVERB_APP_KEY:-andytranscribe-key}
|
||
REVERB_APP_SECRET: ${REVERB_APP_SECRET:-andytranscribe-secret}
|
||
# Server-side publish target (Docker DNS)
|
||
REVERB_HOST: reverb
|
||
REVERB_PORT: 8080
|
||
REVERB_SCHEME: http
|
||
REVERB_SERVER_HOST: 0.0.0.0
|
||
REVERB_SERVER_PORT: 8080
|
||
LOCAL_WHISPER_URL: http://whisper:8000/v1
|
||
LOCAL_WHISPER_API_KEY: ${LOCAL_WHISPER_API_KEY:-not-needed}
|
||
LOCAL_WHISPER_MODEL: ${LOCAL_WHISPER_MODEL:-Systran/faster-whisper-base}
|
||
TRANSCRIPTION_TIMEOUT: ${TRANSCRIPTION_TIMEOUT:-600}
|
||
DB_QUEUE_RETRY_AFTER: ${DB_QUEUE_RETRY_AFTER:-660}
|
||
SEED_USER_NAME: ${SEED_USER_NAME:-Demo User}
|
||
SEED_USER_EMAIL: ${SEED_USER_EMAIL:-demo@example.com}
|
||
SEED_USER_PASSWORD: ${SEED_USER_PASSWORD:-password}
|
||
|
||
# Local: omit APP_IMAGE (builds andytranscribe-app:latest).
|
||
# CI/prod: set APP_IMAGE=gitea.z00.nu/ben/andytranscribe:<sha> and pull.
|
||
x-app-image: &app-image
|
||
image: ${APP_IMAGE:-andytranscribe-app:latest}
|
||
|
||
services:
|
||
app:
|
||
<<: *app-image
|
||
build:
|
||
context: .
|
||
dockerfile: Dockerfile
|
||
args:
|
||
VITE_APP_NAME: ${VITE_APP_NAME:-AndyTranscribe}
|
||
VITE_REVERB_APP_KEY: ${REVERB_APP_KEY:-andytranscribe-key}
|
||
VITE_REVERB_HOST: ${VITE_REVERB_HOST:-localhost}
|
||
VITE_REVERB_PORT: ${REVERB_HOST_PORT:-8081}
|
||
VITE_REVERB_SCHEME: ${VITE_REVERB_SCHEME:-http}
|
||
container_name: andytranscribe-app
|
||
ports:
|
||
- "${APP_HOST_PORT:-8080}:80"
|
||
environment:
|
||
<<: *app-env
|
||
volumes: *app-data
|
||
healthcheck:
|
||
test: ["CMD", "curl", "-f", "http://127.0.0.1/up"]
|
||
interval: 15s
|
||
timeout: 5s
|
||
retries: 5
|
||
start_period: 20s
|
||
depends_on:
|
||
whisper:
|
||
condition: service_healthy
|
||
reverb:
|
||
condition: service_started
|
||
queue:
|
||
condition: service_started
|
||
restart: unless-stopped
|
||
|
||
# Shares the app image — do not declare build: here (avoids rebuilding 3×).
|
||
# `docker compose up --build` builds `app` first, then starts these with the tagged image.
|
||
queue:
|
||
<<: *app-image
|
||
container_name: andytranscribe-queue
|
||
command:
|
||
- php
|
||
- artisan
|
||
- queue:work
|
||
- database
|
||
- --sleep=1
|
||
- --tries=1
|
||
- --timeout=${TRANSCRIPTION_TIMEOUT:-600}
|
||
environment:
|
||
<<: *app-env
|
||
volumes: *app-data
|
||
healthcheck:
|
||
test: ["CMD-SHELL", "tr '\\0' ' ' </proc/1/cmdline | grep -q 'queue:work'"]
|
||
interval: 30s
|
||
timeout: 5s
|
||
retries: 3
|
||
start_period: 20s
|
||
depends_on:
|
||
whisper:
|
||
condition: service_healthy
|
||
reverb:
|
||
condition: service_started
|
||
restart: unless-stopped
|
||
|
||
reverb:
|
||
<<: *app-image
|
||
container_name: andytranscribe-reverb
|
||
command:
|
||
- php
|
||
- artisan
|
||
- reverb:start
|
||
- --host=0.0.0.0
|
||
- --port=8080
|
||
ports:
|
||
- "${REVERB_HOST_PORT:-8081}:8080"
|
||
environment:
|
||
<<: *app-env
|
||
# Browser connects to localhost:8081; hostname used in app config for allowed hosts
|
||
REVERB_HOST: localhost
|
||
volumes: *app-data
|
||
healthcheck:
|
||
test: ["CMD-SHELL", "tr '\\0' ' ' </proc/1/cmdline | grep -q 'reverb:start'"]
|
||
interval: 30s
|
||
timeout: 5s
|
||
retries: 3
|
||
start_period: 20s
|
||
restart: unless-stopped
|
||
|
||
whisper:
|
||
image: fedirz/faster-whisper-server:latest-cpu
|
||
container_name: andytranscribe-whisper
|
||
ports:
|
||
# Host 8090 avoids clashing with the FrankenPHP app on 8080
|
||
- "${WHISPER_HOST_PORT:-8090}:8000"
|
||
volumes:
|
||
- whisper-huggingface-cache:/root/.cache/huggingface
|
||
environment:
|
||
WHISPER__MODEL: ${LOCAL_WHISPER_MODEL:-Systran/faster-whisper-base}
|
||
restart: unless-stopped
|
||
healthcheck:
|
||
test: ["CMD", "python3", "-c", "import urllib.request; urllib.request.urlopen('http://127.0.0.1:8000/health')"]
|
||
interval: 15s
|
||
timeout: 5s
|
||
retries: 10
|
||
start_period: 30s
|
||
|
||
# GPU variant (NVIDIA). Start with:
|
||
# docker compose --profile gpu up -d whisper-gpu
|
||
whisper-gpu:
|
||
profiles: ["gpu"]
|
||
image: fedirz/faster-whisper-server:latest-cuda
|
||
container_name: andytranscribe-whisper-gpu
|
||
ports:
|
||
- "${WHISPER_HOST_PORT:-8090}:8000"
|
||
volumes:
|
||
- whisper-huggingface-cache:/root/.cache/huggingface
|
||
environment:
|
||
WHISPER__MODEL: ${LOCAL_WHISPER_MODEL:-Systran/faster-whisper-base}
|
||
restart: unless-stopped
|
||
deploy:
|
||
resources:
|
||
reservations:
|
||
devices:
|
||
- driver: nvidia
|
||
count: 1
|
||
capabilities: [gpu]
|
||
|
||
volumes:
|
||
whisper-huggingface-cache:
|