Adding fixes to the pipeline
This commit is contained in:
+44
-64
@@ -34,7 +34,7 @@ Examples:
|
||||
gnommo -p video1 validate Validate only
|
||||
gnommo -p video1 import Generate slides.json from images
|
||||
gnommo -p video1 pre Preprocess videos (chroma key, etc.)
|
||||
gnommo -p video1 stitch --proxy -f Fast stitch with new begin/end values
|
||||
gnommo -p video1 stitch --res tiny -f Fast stitch with new begin/end values
|
||||
gnommo -p video1 all Full pipeline: transcribe → align → render
|
||||
gnommo -p video1 render --dry-run Show FFmpeg command without running
|
||||
gnommo -p video1 description Generate YouTube description file
|
||||
@@ -113,9 +113,9 @@ Examples:
|
||||
parser.add_argument(
|
||||
"--res",
|
||||
type=str,
|
||||
choices=["low", "full"],
|
||||
choices=["full", "low", "tiny"],
|
||||
default="full",
|
||||
help="Resolution: 'low' (490x270) for fast preview, 'full' for project resolution",
|
||||
help="Resolution: 'full' (project res), 'low' (490x270), 'tiny' (320x180 ultrafast)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-w",
|
||||
@@ -124,11 +124,6 @@ Examples:
|
||||
default=1,
|
||||
help="Number of parallel workers for preprocessing (default: 1)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--proxy",
|
||||
action="store_true",
|
||||
help="Use proxy workflow: downsample to 160x90 for fast iteration",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--final",
|
||||
action="store_true",
|
||||
@@ -184,14 +179,14 @@ Examples:
|
||||
args.dry_run,
|
||||
args.force,
|
||||
args.workers,
|
||||
args.proxy,
|
||||
args.res,
|
||||
)
|
||||
elif action in ("stitch"):
|
||||
return cmd_stitch(
|
||||
project_path,
|
||||
args.verbose,
|
||||
args.force,
|
||||
args.proxy,
|
||||
args.res,
|
||||
)
|
||||
elif action == "render":
|
||||
return cmd_render(
|
||||
@@ -201,10 +196,9 @@ Examples:
|
||||
args.slides,
|
||||
args.res,
|
||||
args.force,
|
||||
args.proxy,
|
||||
)
|
||||
elif action == "transcribe":
|
||||
return cmd_transcribe(project_path, args.verbose, args.proxy, args.final)
|
||||
return cmd_transcribe(project_path, args.verbose, args.res, args.final)
|
||||
elif action == "align":
|
||||
return cmd_align(project_path, args.verbose)
|
||||
elif action == "all":
|
||||
@@ -739,17 +733,18 @@ def cmd_preprocess(
|
||||
dry_run: bool,
|
||||
force: bool = False,
|
||||
workers: int = 1,
|
||||
proxy: bool = False,
|
||||
res: str = "full",
|
||||
) -> int:
|
||||
"""Run preprocessing pipeline on narration segments."""
|
||||
from concurrent.futures import ThreadPoolExecutor, as_completed
|
||||
from .parser import parse_project_config, parse_narration
|
||||
from .preprocessor import (
|
||||
preprocess_video,
|
||||
create_proxies_for_videos,
|
||||
create_downscaled_videos,
|
||||
RES_CONFIGS,
|
||||
)
|
||||
|
||||
mode_str = " (PROXY MODE)" if proxy else ""
|
||||
mode_str = f" ({res.upper()})" if res != "full" else ""
|
||||
print(f"Preprocessing narration: {project_path.name}{mode_str}")
|
||||
|
||||
config = parse_project_config(project_path)
|
||||
@@ -760,12 +755,11 @@ def cmd_preprocess(
|
||||
print(" Run 'gnommo -p <project> import' first to populate narration.json")
|
||||
return 1
|
||||
|
||||
# Proxy mode: create low-res copies first, then work from proxy dir
|
||||
if proxy:
|
||||
proxy_dir = create_proxies_for_videos(narration_dir, narration, force, verbose)
|
||||
# Switch to proxy directory for all subsequent operations
|
||||
narration_dir = proxy_dir
|
||||
print(f" Working from proxy dir: {proxy_dir}")
|
||||
# Downscale source files first if a preview res was requested
|
||||
if res != "full":
|
||||
narration_dir = create_downscaled_videos(narration_dir, narration, res, force, verbose)
|
||||
cfg = RES_CONFIGS[res]
|
||||
print(f" Working from {res} dir ({cfg[0]}x{cfg[1]}): {narration_dir}")
|
||||
|
||||
# Resolve intermediate directory
|
||||
gnommo_scratch = None
|
||||
@@ -853,7 +847,7 @@ def cmd_stitch(
|
||||
project_path: Path,
|
||||
verbose: bool,
|
||||
force: bool = False,
|
||||
proxy: bool = False,
|
||||
res: str = "full",
|
||||
) -> int:
|
||||
"""
|
||||
Stitch narration segments from narration.json.
|
||||
@@ -861,15 +855,11 @@ def cmd_stitch(
|
||||
Reads segments from media/narration/narration.json, applies begin/end
|
||||
trimming during concatenation, and writes output to media/videos/narration_combined.mov.
|
||||
Also creates/updates an entry in videos.json with volume property.
|
||||
|
||||
This is useful for quickly iterating on begin/end trim points without
|
||||
waiting for the full preprocessing pipeline. Works especially well
|
||||
with --proxy for fast feedback.
|
||||
"""
|
||||
from .parser import parse_project_config, parse_narration, parse_videos
|
||||
from .preprocessor import stitch_narration_segments, ensure_proxy_files_exist
|
||||
from .preprocessor import stitch_narration_segments, ensure_downscaled_files_exist, RES_CONFIGS
|
||||
|
||||
mode_str = " (PROXY MODE)" if proxy else ""
|
||||
mode_str = f" ({res.upper()})" if res != "full" else ""
|
||||
print(f"Stitching narration: {project_path.name}{mode_str}")
|
||||
|
||||
config = parse_project_config(project_path)
|
||||
@@ -887,15 +877,13 @@ def cmd_stitch(
|
||||
else:
|
||||
videos_dir = project_path / "media" / "videos"
|
||||
|
||||
# Proxy mode: use proxy directory for both input and output
|
||||
# Create proxy files on-the-fly if they don't exist
|
||||
if proxy:
|
||||
proxy_narration_dir = ensure_proxy_files_exist(narration_dir, force=False, verbose=verbose)
|
||||
proxy_videos_dir = videos_dir / "proxy"
|
||||
proxy_videos_dir.mkdir(parents=True, exist_ok=True)
|
||||
narration_dir = proxy_narration_dir
|
||||
videos_dir = proxy_videos_dir
|
||||
print(f" Using proxy dirs: {narration_dir}, {videos_dir}")
|
||||
# Use downscaled dirs for non-full res
|
||||
if res != "full":
|
||||
cfg = RES_CONFIGS[res]
|
||||
narration_dir = ensure_downscaled_files_exist(narration_dir, res, force=False, verbose=verbose)
|
||||
videos_dir = videos_dir / cfg[2]
|
||||
videos_dir.mkdir(parents=True, exist_ok=True)
|
||||
print(f" Using {res} dirs: {narration_dir}, {videos_dir}")
|
||||
|
||||
# Get segment IDs in sorted order
|
||||
segment_ids = sorted(narration.keys())
|
||||
@@ -962,7 +950,7 @@ def cmd_stitch(
|
||||
print("\n" + "=" * 60)
|
||||
print("Auto-running transcribe to sync with new narration...")
|
||||
print("=" * 60 + "\n")
|
||||
return cmd_transcribe(project_path, verbose, proxy=proxy)
|
||||
return cmd_transcribe(project_path, verbose, res=res)
|
||||
|
||||
|
||||
# =============================================================================
|
||||
@@ -1106,7 +1094,6 @@ def cmd_render(
|
||||
slides_arg: str = None,
|
||||
res: str = "full",
|
||||
force: bool = False,
|
||||
proxy: bool = False,
|
||||
) -> int:
|
||||
"""Render final video."""
|
||||
from .parser import (
|
||||
@@ -1121,7 +1108,7 @@ def cmd_render(
|
||||
from .validator import validate_project
|
||||
from .transformer import build_render_plan
|
||||
from .renderer import render, generate_ffmpeg_command_string
|
||||
from .preprocessor import PROXY_WIDTH, PROXY_HEIGHT, ensure_proxy_files_exist
|
||||
from .preprocessor import RES_CONFIGS, ensure_downscaled_files_exist
|
||||
|
||||
# Parse slide range if provided
|
||||
slide_range = None
|
||||
@@ -1132,10 +1119,9 @@ def cmd_render(
|
||||
print(f"Rendering: {project_path.name}")
|
||||
|
||||
# Show resolution mode
|
||||
if proxy:
|
||||
print(f" Resolution: PROXY ({PROXY_WIDTH}x{PROXY_HEIGHT}) - fast preview mode")
|
||||
elif res == "low":
|
||||
print(" Resolution: LOW (490x270) - fast preview mode")
|
||||
if res != "full":
|
||||
cfg = RES_CONFIGS[res]
|
||||
print(f" Resolution: {res.upper()} ({cfg[0]}x{cfg[1]})")
|
||||
|
||||
# Show cache status
|
||||
cache_info = get_cache_info()
|
||||
@@ -1152,22 +1138,19 @@ def cmd_render(
|
||||
save_citations(citations, citations_path)
|
||||
config = parse_project_config(project_path)
|
||||
|
||||
# Override resolution for proxy or low-res preview mode
|
||||
if proxy:
|
||||
config.resolution = (PROXY_WIDTH, PROXY_HEIGHT)
|
||||
elif res == "low":
|
||||
config.resolution = (490, 270)
|
||||
# Override resolution for preview modes
|
||||
if res != "full":
|
||||
cfg = RES_CONFIGS[res]
|
||||
config.resolution = (cfg[0], cfg[1])
|
||||
|
||||
slides = parse_slides(project_path, config)
|
||||
videos, videos_dir = parse_videos(project_path, config)
|
||||
|
||||
# Proxy mode: use videos from proxy directory
|
||||
# Create proxy files on-the-fly if they don't exist
|
||||
if proxy:
|
||||
proxy_dir = ensure_proxy_files_exist(videos_dir, force=False, verbose=verbose)
|
||||
videos_dir = proxy_dir
|
||||
# Non-full res: use downscaled video directory, create on-the-fly if needed
|
||||
if res != "full":
|
||||
videos_dir = ensure_downscaled_files_exist(videos_dir, res, force=False, verbose=verbose)
|
||||
if verbose:
|
||||
print(f" Using proxy dir: {proxy_dir}")
|
||||
print(f" Using {res} dir: {videos_dir}")
|
||||
audio, audio_dir = parse_audio(project_path, config)
|
||||
|
||||
# Load whisper transcription JSON
|
||||
@@ -1280,7 +1263,6 @@ def cmd_render(
|
||||
audio,
|
||||
audio_dir,
|
||||
slide_range=slide_range,
|
||||
proxy=proxy,
|
||||
)
|
||||
if plan.time_offset > 0:
|
||||
print(f" Time offset: {plan.time_offset:.1f}s (partial render)")
|
||||
@@ -1383,18 +1365,18 @@ def _find_narration_video(config, videos: dict) -> Optional[tuple[str, "VideoSou
|
||||
|
||||
|
||||
def cmd_transcribe(
|
||||
project_path: Path, verbose: bool, proxy: bool = False, final: bool = False
|
||||
project_path: Path, verbose: bool, res: str = "full", final: bool = False
|
||||
) -> int:
|
||||
"""Transcribe video audio using Whisper."""
|
||||
from .transcriber import transcribe_video, save_transcript, words_to_srt
|
||||
from .parser import parse_project_config, parse_videos
|
||||
from .preprocessor import ensure_proxy_files_exist
|
||||
from .preprocessor import ensure_downscaled_files_exist
|
||||
|
||||
# Handle --final mode: transcribe the rendered output for YouTube captions
|
||||
if final:
|
||||
return _transcribe_final(project_path, verbose)
|
||||
|
||||
mode_str = " (PROXY)" if proxy else ""
|
||||
mode_str = f" ({res.upper()})" if res != "full" else ""
|
||||
print(f"Transcribing: {project_path.name}{mode_str}")
|
||||
|
||||
config = parse_project_config(project_path)
|
||||
@@ -1403,11 +1385,9 @@ def cmd_transcribe(
|
||||
print("Error: No videos defined in videos.json", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
# Proxy mode: use videos from proxy directory
|
||||
# Create proxy files on-the-fly if they don't exist
|
||||
if proxy:
|
||||
proxy_dir = ensure_proxy_files_exist(videos_dir, force=False, verbose=verbose)
|
||||
videos_dir = proxy_dir
|
||||
# Non-full res: use downscaled video directory
|
||||
if res != "full":
|
||||
videos_dir = ensure_downscaled_files_exist(videos_dir, res, force=False, verbose=verbose)
|
||||
|
||||
# Check for multi-segment narration (concatenated file)
|
||||
if isinstance(config.main_video, list) and len(config.main_video) > 1:
|
||||
|
||||
Reference in New Issue
Block a user