9f42ee2460
Private, offline speech-to-text that runs Whisper on the user's own device — free, no account, no per-minute fees. Replaces Otter.ai / Rev. - Pure, tested engine: chunking, overlap timestamp-stitching, exports (SRT/VTT/TXT/MD/JSON), WAV codec, resampler, job queue, model catalog (142 tests). - Platform-abstracted TranscriptionEngine: transformers.js on web (loaded from CDN at runtime to dodge Metro's onnxruntime-web bundling limits), whisper.rn on native. Shared pipeline orchestrates decode -> chunk -> transcribe -> stitch. - Cross-platform StorageRepo (Dexie web / expo-sqlite native), Zod-validated. - UI: library + search, import, live-progress transcription, synced click-to-seek editor, multi-format export; model picker + privacy in settings. - Web ships as a single-page PWA with COOP/COEP isolation for threaded WASM; Docker (nginx) image + Traefik compose for wisp.briggen.dev. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
73 lines
3.4 KiB
Docker
73 lines
3.4 KiB
Docker
# syntax=docker/dockerfile:1
|
|
#
|
|
# docker/web.Dockerfile
|
|
# ---------------------------------------------------------------------------
|
|
# Multi-stage build for the Wisp web app.
|
|
#
|
|
# Stage 1 (builder): Uses the official Bun image to install dependencies and
|
|
# run the Expo/Metro static web export. The output is a
|
|
# fully static SPA in /app/dist.
|
|
#
|
|
# Stage 2 (runtime): A tiny nginx:alpine image that serves the exported
|
|
# static files. nginx is configured (docker/nginx.conf)
|
|
# to send the cross-origin isolation headers that the
|
|
# multi-threaded WASM Whisper backend requires, namely:
|
|
# Cross-Origin-Opener-Policy: same-origin
|
|
# Cross-Origin-Embedder-Policy: require-corp
|
|
#
|
|
# Build: docker build -f docker/web.Dockerfile -t wisp-web:latest .
|
|
# Run: docker run --rm -p 8080:8080 wisp-web:latest
|
|
#
|
|
# NOTE: build context must be the repository root (so the whole repo + lockfile
|
|
# are available to the builder).
|
|
# ---------------------------------------------------------------------------
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Stage 1: build the static site with Bun + Expo export
|
|
# ---------------------------------------------------------------------------
|
|
# Pin to the Bun 1.x line. `oven/bun:1` tracks the latest 1.x patch release;
|
|
# pin to an exact digest/tag in production if you want fully reproducible builds.
|
|
FROM oven/bun:1 AS builder
|
|
|
|
WORKDIR /app
|
|
|
|
# Copy manifest + lockfile first so Docker can cache the (slow) dependency
|
|
# install layer independently of source changes. `bun.lock` is Bun's lockfile.
|
|
COPY package.json bun.lock ./
|
|
|
|
# Install EXACTLY what the lockfile specifies. --frozen-lockfile fails the build
|
|
# if package.json and bun.lock have drifted, which keeps CI deterministic.
|
|
RUN bun install --frozen-lockfile
|
|
|
|
# Now copy the rest of the repository (app code, assets, config, etc.).
|
|
# Anything matched by .dockerignore (node_modules, dist, .git ...) is skipped.
|
|
COPY . .
|
|
|
|
# Produce the static web bundle. `bun run export:web` maps to
|
|
# `expo export --platform web`, which writes the static site to ./dist
|
|
# (Expo's default --output-dir). app.json sets web.output = "static", so this
|
|
# emits prerendered HTML + the JS/WASM assets for the SPA.
|
|
RUN bun run export:web
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Stage 2: serve the static site with nginx
|
|
# ---------------------------------------------------------------------------
|
|
FROM nginx:alpine AS runtime
|
|
|
|
# Drop the stock nginx site config and install ours. Our config:
|
|
# - listens on 8080 (non-privileged port; matches docker-compose + reverse proxy)
|
|
# - SPA fallback (try_files ... /index.html)
|
|
# - COOP/COEP/CORP cross-origin isolation headers (for threaded WASM)
|
|
# - gzip + long-lived caching for hashed static assets
|
|
# - serves /wisp.apk if an APK has been dropped into the web root
|
|
COPY docker/nginx.conf /etc/nginx/conf.d/default.conf
|
|
|
|
# Copy the exported static site from the builder stage into nginx's web root.
|
|
COPY --from=builder /app/dist /usr/share/nginx/html
|
|
|
|
# Document the port the container listens on (informational; publish with -p).
|
|
EXPOSE 8080
|
|
|
|
# nginx:alpine's default entrypoint already runs nginx in the foreground
|
|
# ("daemon off") via /docker-entrypoint.sh, so no CMD override is needed.
|