aboutsummaryrefslogtreecommitdiff
path: root/producer.sh
diff options
context:
space:
mode:
Diffstat (limited to 'producer.sh')
-rwxr-xr-xproducer.sh35
1 files changed, 27 insertions, 8 deletions
diff --git a/producer.sh b/producer.sh
index d2a139f..5814abc 100755
--- a/producer.sh
+++ b/producer.sh
@@ -8,7 +8,8 @@
# Trust boundary for downloads: official PyPI (uv, application wheels) and
# Astral's managed CPython distribution. AI setup additionally trusts
# download.pytorch.org, the pinned DeepFilterNet3 model host, and Hugging Face
-# (ClearVoice MossFormer2_SE_48K weights). Host package-manager settings
+# (ClearVoice MossFormer2_SE_48K weights), plus hash-checked Silero VAD
+# weights from its pinned GitHub release. Host package-manager settings
# (extra indexes, targets, constraints, config files) cannot add to or
# redirect these sources.
#
@@ -29,8 +30,10 @@ RUNTIME="$LIB/runtime"
APP="$RUNTIME/app"
PROJECT="$LIB/project"
READY="$RUNTIME/.producer-ready"
-# Bump when the bootstrap recipe changes (python version, install steps...).
-RUNTIME_VERSION="2"
+GUI_READY="$RUNTIME/.producer-gui-ready"
+# Bump when the bootstrap recipe or installed application contract changes.
+# Version 4 adds the optional GUI command; only GUI launches install its extra.
+RUNTIME_VERSION="4"
usage() {
cat <<'USAGE'
@@ -43,6 +46,7 @@ Usage: ./producer.sh COMMAND [options], or simply:
process RECORDING.wav... The same, with the explicit command keyword
preview RECORDING.wav Render loudness-matched profile previews
config Print resolved settings (TOML, or JSON with --json)
+ gui [--root PATH] [--port N] Open the optional local browser GUI (loopback only)
doctor Check FFmpeg, data directory and CUDA driver
setup --device cpu|cuda Install and self-test the AI backend
(--denoiser clearvoice for the MossFormer2 backend)
@@ -76,6 +80,9 @@ if [[ ${#ARGS[@]} -eq 1 && ( "${ARGS[0]}" == "-h" || "${ARGS[0]}" == "--help" )
exit 0
fi
+WANT_GUI=0
+[[ "${ARGS[0]-}" == "gui" ]] && WANT_GUI=1
+
# A config.toml next to this script is loaded automatically for every
# command that accepts --config, unless one is given explicitly. Named CLI
# flags and --set still override values from the file.
@@ -87,7 +94,7 @@ if [[ $HAVE_CONFIG -eq 0 && -f "$ROOT/config.toml" ]]; then
case "${ARGS[0]-}" in
# After the command word: the CLI treats a leading non-command
# argument as the implicit 'process' command and then as an input.
- process|preview|config)
+ process|preview|config|gui)
ARGS=("${ARGS[0]}" "--config=$ROOT/config.toml" "${ARGS[@]:1}")
;;
# These commands take no --config (or no arguments at all).
@@ -127,7 +134,9 @@ marker_current() {
# a failed or interrupted rebuild leaves neither, forcing a repair.
[[ -f "$READY" ]] \
&& [[ "$(cat -- "$READY" 2>/dev/null)" == "$RUNTIME v$RUNTIME_VERSION" ]] \
- && [[ -x "$APP/bin/python" ]]
+ && [[ -x "$APP/bin/python" ]] \
+ && { [[ "$WANT_GUI" -eq 0 ]] || { [[ -f "$GUI_READY" ]] \
+ && [[ "$(cat -- "$GUI_READY" 2>/dev/null)" == "$RUNTIME v$RUNTIME_VERSION" ]]; }; }
}
bootstrap() {
@@ -156,7 +165,7 @@ bootstrap() {
# Invalidate the marker before any destructive work: if this bootstrap
# fails or is interrupted, the next launch repairs instead of trusting
# a half-built environment.
- rm -f -- "$READY" "$READY.tmp"
+ rm -f -- "$READY" "$READY.tmp" "$GUI_READY"
log "Preparing the contained runtime in lib/runtime (first run, or the directory moved)"
local UV=""
@@ -191,18 +200,28 @@ bootstrap() {
|| fail "Creating the managed Python 3.13 environment failed; check network access and free space."
# The bundled FFmpeg wheel is preferred; where it does not exist (for
# example musl systems), fall back to a system FFmpeg at runtime.
+ local bundled="$PROJECT[bundled-ffmpeg]" core="$PROJECT"
+ if [[ "$WANT_GUI" -eq 1 ]]; then
+ bundled="$PROJECT[bundled-ffmpeg,gui]"
+ core="$PROJECT[gui]"
+ fi
if ! err="$("$UV" pip install --python "$APP/bin/python" --index-url https://pypi.org/simple \
- "$PROJECT[bundled-ffmpeg]" 2>&1 >/dev/null)"; then
+ "$bundled" 2>&1 >/dev/null)"; then
log "Bundled FFmpeg wheel unavailable; installing core dependencies (a system FFmpeg is then required)."
if [[ -n "$err" ]]; then
sed 's/^/[producer] /' <<<"$err" >&2
fi
- "$UV" pip install --python "$APP/bin/python" --index-url https://pypi.org/simple "$PROJECT" \
+ "$UV" pip install --python "$APP/bin/python" --index-url https://pypi.org/simple "$core" \
|| fail "Installing the application dependencies failed; check network access and free space."
fi
"$APP/bin/python" -I -c "import producer" >/dev/null 2>&1 \
|| fail "The application environment failed verification."
+ if [[ "$WANT_GUI" -eq 1 ]]; then
+ "$APP/bin/python" -I -c "import fastapi, uvicorn" >/dev/null 2>&1 \
+ || fail "The optional GUI environment failed verification."
+ printf '%s v%s\n' "$RUNTIME" "$RUNTIME_VERSION" > "$GUI_READY"
+ fi
printf '%s v%s\n' "$RUNTIME" "$RUNTIME_VERSION" > "$READY.tmp"
mv -f -- "$READY.tmp" "$READY"
# Downgrade to the shared runtime lock for the application's lifetime.