Build one shared container image for the Flask GUI and CLI pipeline, with Playwright, FFmpeg, and spaCy preinstalled so first runs are reliable. Add bootstrap logic for missing runtime files, bind the GUI to 0.0.0.0 in containers, and preserve state through a repo mount. Constraint: Local development needs a single image that supports both entrypoints without introducing extra services or dependencies. Rejected: Separate GUI and CLI images | duplicated maintenance and no runtime benefit for this repo. Confidence: high Scope-risk: moderate Directive: Keep runtime state creation in the container bootstrap layer; do not reintroduce host-specific assumptions into GUI startup. Tested: docker compose build; docker compose run --rm gui python -c '...'; docker compose run --rm cli python -c 'import main'; docker compose up -d gui; curl -I http://localhost:4000 Not-tested: Full end-to-end video generation with live credentials in this environment.pull/2551/head
parent
c2f394f549
commit
4d8c393a94
@ -1,2 +1,20 @@
|
||||
Dockerfile
|
||||
results
|
||||
.git
|
||||
.github
|
||||
.omx
|
||||
.venv
|
||||
venv
|
||||
__pycache__
|
||||
*.pyc
|
||||
*.pyo
|
||||
*.pyd
|
||||
.pytest_cache
|
||||
.mypy_cache
|
||||
.ruff_cache
|
||||
.DS_Store
|
||||
config.toml
|
||||
results
|
||||
assets/temp
|
||||
assets/backgrounds
|
||||
video_creation/data/videos.json
|
||||
video_creation/data/cookie-threads.json
|
||||
out
|
||||
|
||||
@ -1,12 +1,27 @@
|
||||
FROM python:3.10.14-slim
|
||||
FROM python:3.10-slim-bookworm
|
||||
|
||||
RUN apt update
|
||||
RUN apt-get install -y ffmpeg
|
||||
RUN apt install python3-pip -y
|
||||
ENV PYTHONDONTWRITEBYTECODE=1 \
|
||||
PYTHONUNBUFFERED=1 \
|
||||
PIP_NO_CACHE_DIR=1 \
|
||||
PLAYWRIGHT_BROWSERS_PATH=/ms-playwright
|
||||
|
||||
RUN mkdir /app
|
||||
ADD . /app
|
||||
WORKDIR /app
|
||||
RUN pip install -r requirements.txt
|
||||
|
||||
CMD ["python3", "main.py"]
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y --no-install-recommends \
|
||||
ffmpeg \
|
||||
curl \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
COPY requirements.txt ./
|
||||
RUN pip install --upgrade pip \
|
||||
&& pip install -r requirements.txt \
|
||||
&& python -m spacy download en_core_web_sm
|
||||
|
||||
RUN python -m playwright install --with-deps chromium
|
||||
|
||||
COPY . .
|
||||
|
||||
RUN chmod +x /app/docker-entrypoint.sh
|
||||
|
||||
ENTRYPOINT ["/bin/sh", "/app/docker-entrypoint.sh"]
|
||||
|
||||
@ -1,2 +1,3 @@
|
||||
#!/bin/sh
|
||||
docker build -t rvmt .
|
||||
set -eu
|
||||
docker compose build
|
||||
|
||||
@ -0,0 +1,27 @@
|
||||
services:
|
||||
gui:
|
||||
build:
|
||||
context: .
|
||||
image: videomakerbot:latest
|
||||
command: ["python", "GUI.py"]
|
||||
ports:
|
||||
- "4000:4000"
|
||||
environment:
|
||||
GUI_HOST: "0.0.0.0"
|
||||
GUI_PORT: "4000"
|
||||
GUI_OPEN_BROWSER: "0"
|
||||
GUI_BROWSER_URL: "http://localhost:4000"
|
||||
volumes:
|
||||
- ./:/app
|
||||
shm_size: "1gb"
|
||||
|
||||
cli:
|
||||
build:
|
||||
context: .
|
||||
image: videomakerbot:latest
|
||||
command: ["python", "main.py"]
|
||||
environment:
|
||||
PYTHONUNBUFFERED: "1"
|
||||
volumes:
|
||||
- ./:/app
|
||||
shm_size: "1gb"
|
||||
@ -0,0 +1,6 @@
|
||||
#!/bin/sh
|
||||
set -eu
|
||||
|
||||
python -m utils.docker_bootstrap
|
||||
|
||||
exec "$@"
|
||||
@ -1,2 +1,3 @@
|
||||
#!/bin/sh
|
||||
docker run -v $(pwd)/out/:/app/assets -v $(pwd)/.env:/app/.env -it rvmt
|
||||
set -eu
|
||||
docker compose run --rm cli "$@"
|
||||
|
||||
@ -0,0 +1,70 @@
|
||||
"""Container bootstrap helpers for first-run runtime state."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
from typing import Any, Dict
|
||||
|
||||
import tomlkit
|
||||
|
||||
|
||||
ROOT = Path(__file__).resolve().parent.parent
|
||||
|
||||
|
||||
def _default_from_template(node: Dict[str, Any]) -> Dict[str, Any]:
|
||||
defaults: Dict[str, Any] = {}
|
||||
for key, value in node.items():
|
||||
if isinstance(value, dict) and "optional" in value:
|
||||
if "default" in value:
|
||||
defaults[key] = value["default"]
|
||||
else:
|
||||
value_type = value.get("type")
|
||||
if value_type == "bool":
|
||||
defaults[key] = False
|
||||
elif value_type in {"int", "float"}:
|
||||
defaults[key] = 0
|
||||
else:
|
||||
defaults[key] = ""
|
||||
elif isinstance(value, dict):
|
||||
defaults[key] = _default_from_template(value)
|
||||
return defaults
|
||||
|
||||
|
||||
def _ensure_json(path: Path, content: str) -> None:
|
||||
path.parent.mkdir(parents=True, exist_ok=True)
|
||||
if not path.exists():
|
||||
path.write_text(content, encoding="utf-8")
|
||||
|
||||
|
||||
def _ensure_config(path: Path) -> None:
|
||||
if path.exists():
|
||||
return
|
||||
|
||||
template_path = ROOT / "utils/.config.template.toml"
|
||||
template = tomlkit.loads(template_path.read_text(encoding="utf-8"))
|
||||
defaults = _default_from_template(template)
|
||||
path.write_text(tomlkit.dumps(defaults), encoding="utf-8")
|
||||
|
||||
|
||||
def ensure_runtime_state() -> None:
|
||||
"""Create runtime files and directories expected by the app."""
|
||||
for relative in (
|
||||
"assets/temp",
|
||||
"assets/backgrounds/audio",
|
||||
"assets/backgrounds/video",
|
||||
"results",
|
||||
"video_creation/data",
|
||||
):
|
||||
(ROOT / relative).mkdir(parents=True, exist_ok=True)
|
||||
|
||||
_ensure_config(ROOT / "config.toml")
|
||||
_ensure_json(ROOT / "video_creation/data/videos.json", "[]\n")
|
||||
_ensure_json(ROOT / "utils/backgrounds.json", "{}\n")
|
||||
|
||||
|
||||
def main() -> None:
|
||||
ensure_runtime_state()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Loading…
Reference in new issue