runner: pass per-tool args from coderai-docker; video editor --session on by default

* coderai-docker (run_oci.sh): new --tool-arg TOOL VAL (one token) and
  --tool-args TOOL STR (whitespace string), repeatable, for video-editor |
  videogen | township | parler. They accumulate into CODERAI_<TOOL>_ARGS env vars
  that supervisord appends to each tool's command line. Documented in --help
  (plus the --map dir-or-file note and bring-your-config examples), and shown on
  the startup banner (tool-args:).
* entrypoint: default+export the four CODERAI_*_ARGS (empty) so supervisord's
  %(ENV_...)s never fails on an undefined var; pre-create /cache/video_editor/sessions.
* supervisord: append %(ENV_CODERAI_*_ARGS)s to all four tool launchers; the video
  editor now runs with --session --session-dir /cache/video_editor/sessions so
  editor-state recovery is ON by default and persists on the cache volume.
* video_editor.py: new --session-dir to place session state/assets at a
  persistent/mapped path (defaults to ~/.cache/... when omitted).

Bump version to 0.1.6.
Co-Authored-By: 's avatarClaude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RdMufYvtTbtGDWsiZVoXce
parent f160c1f0
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
# Canonical product version for CoderAI — single source of truth. Both the API # Canonical product version for CoderAI — single source of truth. Both the API
# metadata and the admin web UI read from here. # metadata and the admin web UI read from here.
__version__ = "0.1.5" __version__ = "0.1.6"
# Configure the CUDA caching allocator BEFORE torch is imported anywhere. # Configure the CUDA caching allocator BEFORE torch is imported anywhere.
# expandable_segments lets the allocator return freed pages to the driver even # expandable_segments lets the allocator return freed pages to the driver even
......
...@@ -26,6 +26,14 @@ export PYTHONDONTWRITEBYTECODE=1 ...@@ -26,6 +26,14 @@ export PYTHONDONTWRITEBYTECODE=1
: "${CODERAI_TOOL_TOWNSHIP:=true}" : "${CODERAI_TOOL_TOWNSHIP:=true}"
: "${CODERAI_TOOL_PARLER:=false}" : "${CODERAI_TOOL_PARLER:=false}"
export CODERAI_TOOL_VIDEO_EDITOR CODERAI_TOOL_VIDEOGEN CODERAI_TOOL_TOWNSHIP CODERAI_TOOL_PARLER export CODERAI_TOOL_VIDEO_EDITOR CODERAI_TOOL_VIDEOGEN CODERAI_TOOL_TOWNSHIP CODERAI_TOOL_PARLER
# Per-tool extra CLI args appended by supervisord (%(ENV_CODERAI_*_ARGS)s). The run
# script sets these via --tool-arg/--tool-args; default empty. supervisord fails to
# start if a referenced ENV var is undefined, so always export them.
: "${CODERAI_VIDEO_EDITOR_ARGS:=}"
: "${CODERAI_VIDEOGEN_ARGS:=}"
: "${CODERAI_TOWNSHIP_ARGS:=}"
: "${CODERAI_PARLER_ARGS:=}"
export CODERAI_VIDEO_EDITOR_ARGS CODERAI_VIDEOGEN_ARGS CODERAI_TOWNSHIP_ARGS CODERAI_PARLER_ARGS
export CODERAI_CONFIG_DIR CODERAI_MODELS_DIR CODERAI_CACHE_DIR CODERAI_PARLER_MODEL CODERAI_TMP export CODERAI_CONFIG_DIR CODERAI_MODELS_DIR CODERAI_CACHE_DIR CODERAI_PARLER_MODEL CODERAI_TMP
mkdir -p \ mkdir -p \
...@@ -35,6 +43,7 @@ mkdir -p \ ...@@ -35,6 +43,7 @@ mkdir -p \
"$CODERAI_CACHE_DIR/township_output" \ "$CODERAI_CACHE_DIR/township_output" \
"$CODERAI_CACHE_DIR/videogen_output" \ "$CODERAI_CACHE_DIR/videogen_output" \
"$CODERAI_CACHE_DIR/video_editor" \ "$CODERAI_CACHE_DIR/video_editor" \
"$CODERAI_CACHE_DIR/video_editor/sessions" \
"$CODERAI_TMP" \ "$CODERAI_TMP" \
/tmp/nginx-client-body /tmp/nginx-proxy /tmp/nginx-fastcgi \ /tmp/nginx-client-body /tmp/nginx-proxy /tmp/nginx-fastcgi \
/tmp/nginx-uwsgi /tmp/nginx-scgi /tmp/nginx-uwsgi /tmp/nginx-scgi
......
...@@ -70,6 +70,8 @@ LOG_FILE_CONT="" ...@@ -70,6 +70,8 @@ LOG_FILE_CONT=""
# default (the three UIs on, parler off). Keyed by CODERAI_TOOL_* env var. # default (the three UIs on, parler off). Keyed by CODERAI_TOOL_* env var.
declare -A TOOL_STATE=() declare -A TOOL_STATE=()
DISABLE_ALL_TOOLS=0 DISABLE_ALL_TOOLS=0
# Extra CLI args appended to a tool's command line, keyed by CODERAI_*_ARGS env var.
declare -A TOOL_ARGS=()
# Map a friendly tool name to its CODERAI_TOOL_* env var (or fail). # Map a friendly tool name to its CODERAI_TOOL_* env var (or fail).
tool_env_var() { tool_env_var() {
...@@ -82,6 +84,18 @@ tool_env_var() { ...@@ -82,6 +84,18 @@ tool_env_var() {
esac esac
} }
# Map a friendly tool name to the env var holding EXTRA args for that tool's
# command (supervisord appends %(ENV_CODERAI_*_ARGS)s to each tool launcher).
tool_args_var() {
case "$1" in
video-editor|video_editor|editor) echo CODERAI_VIDEO_EDITOR_ARGS ;;
videogen|video-gen) echo CODERAI_VIDEOGEN_ARGS ;;
township|fighters) echo CODERAI_TOWNSHIP_ARGS ;;
parler|tts) echo CODERAI_PARLER_ARGS ;;
*) return 1 ;;
esac
}
usage() { usage() {
cat <<'EOF' cat <<'EOF'
Usage: Usage:
...@@ -151,12 +165,27 @@ Options: ...@@ -151,12 +165,27 @@ Options:
(parler TTS is off by default; this turns it on.) (parler TTS is off by default; this turns it on.)
--disable-tool NAME Disable a single demo tool. Repeatable. Same NAMEs as above. --disable-tool NAME Disable a single demo tool. Repeatable. Same NAMEs as above.
Explicit --enable/--disable-tool overrides --no-tools. Explicit --enable/--disable-tool overrides --no-tools.
--tool-arg TOOL VAL Append ONE extra CLI arg to a bundled tool's command line.
Repeatable. TOOL is one of video-editor|videogen|township|
parler. e.g. --tool-arg township --web-port --tool-arg township 9000
--tool-args TOOL STR
Like --tool-arg but appends a whole whitespace-separated
string at once, e.g. --tool-args video-editor "--voice masculine".
Repeatable; combine with --tool-arg. (The video editor already
runs with --session on by default, persisting to
/cache/video_editor/sessions.)
-- ARGS Extra args passed to the container engine before the image name. -- ARGS Extra args passed to the container engine before the image name.
-h, --help Show this help. -h, --help Show this help.
Test against your live config + data (no rebuild): Bring your bare-metal config + data into the container with --map (dir OR file):
# Server config/models/caches (paths in models.json resolve 1:1):
packaging/linux/run_oci.sh --nvidia --local \ packaging/linux/run_oci.sh --nvidia --local \
--map /AI/guffcache --map /AI/huggingface --map /AI/offloads --map /AI/guffcache --map /AI/huggingface --map /AI/offloads
# Township tool (one tree holds its config + all artifacts):
... --map /storage/coderai/township_output:/cache/township_output
# Video editor (config file + the media_dir/output_dir it points at):
... --map /host/video_editor.config.json:/cache/video_editor/video_editor.config.json \
--map /host/coderai_media --map /host/video_editor_output
EOF EOF
} }
...@@ -229,6 +258,18 @@ while [[ $# -gt 0 ]]; do ...@@ -229,6 +258,18 @@ while [[ $# -gt 0 ]]; do
[[ $# -ge 2 ]] || { echo "Error: --disable-tool requires a tool name" >&2; exit 2; } [[ $# -ge 2 ]] || { echo "Error: --disable-tool requires a tool name" >&2; exit 2; }
_v="$(tool_env_var "$2")" || { echo "Error: unknown tool '$2' (video-editor|videogen|township|parler)" >&2; exit 2; } _v="$(tool_env_var "$2")" || { echo "Error: unknown tool '$2' (video-editor|videogen|township|parler)" >&2; exit 2; }
TOOL_STATE["$_v"]=false; shift 2 ;; TOOL_STATE["$_v"]=false; shift 2 ;;
# Append extra CLI args to a bundled tool's command. --tool-arg adds ONE token;
# --tool-args adds a whitespace-separated string. Repeatable. e.g.
# --tool-arg township --web-port --tool-arg township 9000
# --tool-args video-editor "--voice masculine"
--tool-arg)
[[ $# -ge 3 ]] || { echo "Error: --tool-arg requires TOOL and a value" >&2; exit 2; }
_v="$(tool_args_var "$2")" || { echo "Error: unknown tool '$2' (video-editor|videogen|township|parler)" >&2; exit 2; }
TOOL_ARGS["$_v"]="${TOOL_ARGS[$_v]:+${TOOL_ARGS[$_v]} }$3"; shift 3 ;;
--tool-args)
[[ $# -ge 3 ]] || { echo "Error: --tool-args requires TOOL and a string" >&2; exit 2; }
_v="$(tool_args_var "$2")" || { echo "Error: unknown tool '$2' (video-editor|videogen|township|parler)" >&2; exit 2; }
TOOL_ARGS["$_v"]="${TOOL_ARGS[$_v]:+${TOOL_ARGS[$_v]} }$3"; shift 3 ;;
-d|--detach) DETACH=1; shift ;; -d|--detach) DETACH=1; shift ;;
--) --)
shift shift
...@@ -448,6 +489,16 @@ if [[ "${#TOOL_STATE[@]}" -gt 0 ]]; then ...@@ -448,6 +489,16 @@ if [[ "${#TOOL_STATE[@]}" -gt 0 ]]; then
done done
TOOLS_NOTE="${TOOLS_NOTE% }" TOOLS_NOTE="${TOOLS_NOTE% }"
fi fi
# Per-tool extra CLI args (CODERAI_*_ARGS) → supervisord appends them to the tool.
TOOLARGS_NOTE="(none)"
if [[ "${#TOOL_ARGS[@]}" -gt 0 ]]; then
TOOLARGS_NOTE=""
for _v in "${!TOOL_ARGS[@]}"; do
args+=(-e "$_v=${TOOL_ARGS[$_v]}")
TOOLARGS_NOTE+="${_v}='${TOOL_ARGS[$_v]}' "
done
TOOLARGS_NOTE="${TOOLARGS_NOTE% }"
fi
args+=("${EXTRA_ARGS[@]}" "$IMAGE_TAG") args+=("${EXTRA_ARGS[@]}" "$IMAGE_TAG")
...@@ -463,6 +514,7 @@ Starting CoderAI OCI container ...@@ -463,6 +514,7 @@ Starting CoderAI OCI container
debug: ${DEBUG_SPEC:-off} debug: ${DEBUG_SPEC:-off}
log: $LOG_HOST_NOTE log: $LOG_HOST_NOTE
tools: $TOOLS_NOTE tools: $TOOLS_NOTE
tool-args:$([[ "$TOOLARGS_NOTE" == "(none)" ]] && echo " (none)" || echo " $TOOLARGS_NOTE")
user: ${USER_SPEC:-container default (root)} user: ${USER_SPEC:-container default (root)}
cdr-args:${CODERAI_EXTRA_ARGS:+ $CODERAI_EXTRA_ARGS} cdr-args:${CODERAI_EXTRA_ARGS:+ $CODERAI_EXTRA_ARGS}
EOF EOF
......
...@@ -54,6 +54,8 @@ command=/usr/local/bin/with-env /opt/coderai/python/bin/python3 /opt/coderai/app ...@@ -54,6 +54,8 @@ command=/usr/local/bin/with-env /opt/coderai/python/bin/python3 /opt/coderai/app
--no-browser --host 127.0.0.1 --port 8420 --no-browser --host 127.0.0.1 --port 8420
--base-url http://127.0.0.1:8776 --base-url http://127.0.0.1:8776
--config /cache/video_editor/video_editor.config.json --config /cache/video_editor/video_editor.config.json
--session --session-dir /cache/video_editor/sessions
%(ENV_CODERAI_VIDEO_EDITOR_ARGS)s
directory=/opt/coderai/app directory=/opt/coderai/app
autostart=%(ENV_CODERAI_TOOL_VIDEO_EDITOR)s autostart=%(ENV_CODERAI_TOOL_VIDEO_EDITOR)s
autorestart=true autorestart=true
...@@ -69,6 +71,7 @@ command=/usr/local/bin/with-env /opt/coderai/python/bin/python3 /opt/coderai/app ...@@ -69,6 +71,7 @@ command=/usr/local/bin/with-env /opt/coderai/python/bin/python3 /opt/coderai/app
--host 127.0.0.1 --web-port 7790 --host 127.0.0.1 --web-port 7790
--base-url http://127.0.0.1:8776 --base-url http://127.0.0.1:8776
--out-dir /cache/videogen_output --out-dir /cache/videogen_output
%(ENV_CODERAI_VIDEOGEN_ARGS)s
directory=/opt/coderai/app directory=/opt/coderai/app
autostart=%(ENV_CODERAI_TOOL_VIDEOGEN)s autostart=%(ENV_CODERAI_TOOL_VIDEOGEN)s
autorestart=true autorestart=true
...@@ -85,6 +88,7 @@ command=/usr/local/bin/with-env /opt/coderai/python/bin/python3 /opt/coderai/app ...@@ -85,6 +88,7 @@ command=/usr/local/bin/with-env /opt/coderai/python/bin/python3 /opt/coderai/app
--base-url http://127.0.0.1:8776 --base-url http://127.0.0.1:8776
--out-dir /cache/township_output --out-dir /cache/township_output
--config /cache/township_output/township_config.json --config /cache/township_output/township_config.json
%(ENV_CODERAI_TOWNSHIP_ARGS)s
directory=/opt/coderai/app directory=/opt/coderai/app
autostart=%(ENV_CODERAI_TOOL_TOWNSHIP)s autostart=%(ENV_CODERAI_TOOL_TOWNSHIP)s
autorestart=true autorestart=true
...@@ -106,6 +110,7 @@ redirect_stderr=true ...@@ -106,6 +110,7 @@ redirect_stderr=true
[program:parler] [program:parler]
command=/usr/local/bin/with-env /opt/coderai/python/bin/python3 /opt/coderai/app/tools/parler_tts_service.py command=/usr/local/bin/with-env /opt/coderai/python/bin/python3 /opt/coderai/app/tools/parler_tts_service.py
--model %(ENV_CODERAI_PARLER_MODEL)s --port 8123 --model %(ENV_CODERAI_PARLER_MODEL)s --port 8123
%(ENV_CODERAI_PARLER_ARGS)s
environment=PYTHONPATH="/opt/coderai/parler-venv/site-packages" environment=PYTHONPATH="/opt/coderai/parler-venv/site-packages"
directory=/opt/coderai/app directory=/opt/coderai/app
autostart=%(ENV_CODERAI_TOOL_PARLER)s autostart=%(ENV_CODERAI_TOOL_PARLER)s
......
...@@ -1034,13 +1034,17 @@ class Config: ...@@ -1034,13 +1034,17 @@ class Config:
back to a config file.""" back to a config file."""
def __init__(self, settings: dict, config_path: str | None = None, def __init__(self, settings: dict, config_path: str | None = None,
session_name: str | None = None): session_name: str | None = None, session_dir: str | None = None):
self.tts_dir = Path(tempfile.mkdtemp(prefix="vedit_tts_")) self.tts_dir = Path(tempfile.mkdtemp(prefix="vedit_tts_"))
self.upload_dir = Path(tempfile.mkdtemp(prefix="vedit_up_")) self.upload_dir = Path(tempfile.mkdtemp(prefix="vedit_up_"))
self.config_path = Path(config_path).expanduser().resolve() if config_path else None self.config_path = Path(config_path).expanduser().resolve() if config_path else None
self.session_name = safe_session_name(session_name) if session_name else None self.session_name = safe_session_name(session_name) if session_name else None
self.session_path = (Path.home() / ".cache" / "coderai" / "video_editor" / # Sessions live under --session-dir when given (e.g. a persistent/mapped path
"sessions" / f"{self.session_name}.json") if self.session_name else None # in a container), else the per-user cache dir.
_sessions_base = (Path(session_dir).expanduser() if session_dir
else Path.home() / ".cache" / "coderai" / "video_editor" / "sessions")
self.session_path = (_sessions_base / f"{self.session_name}.json"
if self.session_name else None)
self.session_asset_dir = (self.session_path.with_suffix("") if self.session_path else None) self.session_asset_dir = (self.session_path.with_suffix("") if self.session_path else None)
self.media_dir = Path(settings["media_dir"]).expanduser().resolve() self.media_dir = Path(settings["media_dir"]).expanduser().resolve()
self.output_dir = Path(settings["output_dir"]).expanduser().resolve() self.output_dir = Path(settings["output_dir"]).expanduser().resolve()
...@@ -4012,6 +4016,10 @@ def main(): ...@@ -4012,6 +4016,10 @@ def main():
help="Do not auto-open a browser tab") help="Do not auto-open a browser tab")
parser.add_argument("--session", nargs="?", const="default", default=None, parser.add_argument("--session", nargs="?", const="default", default=None,
help="Enable realtime editor-state recovery, optionally named") help="Enable realtime editor-state recovery, optionally named")
parser.add_argument("--session-dir", default=None,
help="Directory for session state/assets (default: "
"~/.cache/coderai/video_editor/sessions). Point this at "
"a persistent/mapped path when running in a container.")
args = parser.parse_args() args = parser.parse_args()
# When -c is omitted, auto-load (and later save back to) a default config in # When -c is omitted, auto-load (and later save back to) a default config in
...@@ -4094,7 +4102,8 @@ def main(): ...@@ -4094,7 +4102,8 @@ def main():
"until you set one (--audio-model, config file, or Settings panel).", "until you set one (--audio-model, config file, or Settings panel).",
file=sys.stderr) file=sys.stderr)
cfg = Config(settings, config_path=args.config, session_name=args.session) cfg = Config(settings, config_path=args.config, session_name=args.session,
session_dir=args.session_dir)
tts_model, stt_model, audio_model = cfg.tts_model, cfg.stt_model, cfg.audio_model tts_model, stt_model, audio_model = cfg.tts_model, cfg.stt_model, cfg.audio_model
editor = Editor(cfg) editor = Editor(cfg)
handler = make_handler(editor) handler = make_handler(editor)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment