From cc64544d50f7511a707997516183d6fed0a0c2ef Mon Sep 17 00:00:00 2001 From: Mariano Gabriel Date: Sun, 28 Jun 2026 21:12:13 -0300 Subject: [PATCH] refactor (untested) --- INDEX.md | 84 +++++++ README.md | 99 +++----- .../cht/interleave_cht_frames.py | 2 +- .../summarize/compile_meeting.py | 2 +- .../summarize/summarize_meeting.py | 2 +- .../summarize/summarize_simple.py | 2 +- .../transcribe_oneoff.sh | 2 +- meetus/deprecated/__init__.py | 11 + meetus/{ => deprecated}/hybrid_processor.py | 4 + meetus/{ => deprecated}/ocr_processor.py | 4 + meetus/{ => deprecated}/prompts/code.txt | 0 meetus/{ => deprecated}/prompts/console.txt | 0 meetus/{ => deprecated}/prompts/dashboard.txt | 0 meetus/{ => deprecated}/prompts/meeting.txt | 0 meetus/{ => deprecated}/vision_processor.py | 4 + meetus/output_manager.py | 3 +- meetus/utils/__init__.py | 0 meetus/workflow.py | 220 ++---------------- process_meeting.py | 66 +----- tests/__init__.py | 29 +++ tests/_stubs/cv2.py | 2 + tests/test_batch.py | 109 +++++++++ tests/test_config.py | 77 ++++++ tests/test_makefile.py | 55 +++++ tests/test_smoke.py | 57 +++++ tests/test_summarize.py | 46 ++++ 26 files changed, 540 insertions(+), 340 deletions(-) create mode 100644 INDEX.md rename interleave_cht_frames.py => ctrl/cht/interleave_cht_frames.py (98%) rename compile_meeting.py => ctrl/summarize/compile_meeting.py (99%) rename summarize_meeting.py => ctrl/summarize/summarize_meeting.py (99%) rename summarize_simple.py => ctrl/summarize/summarize_simple.py (98%) rename transcribe_oneoff.sh => ctrl/transcribe_oneoff.sh (98%) create mode 100644 meetus/deprecated/__init__.py rename meetus/{ => deprecated}/hybrid_processor.py (97%) rename meetus/{ => deprecated}/ocr_processor.py (96%) rename meetus/{ => deprecated}/prompts/code.txt (100%) rename meetus/{ => deprecated}/prompts/console.txt (100%) rename meetus/{ => deprecated}/prompts/dashboard.txt (100%) rename meetus/{ => deprecated}/prompts/meeting.txt (100%) rename meetus/{ => deprecated}/vision_processor.py (96%) delete mode 100644 meetus/utils/__init__.py create mode 100644 tests/__init__.py create mode 100644 tests/_stubs/cv2.py create mode 100644 tests/test_batch.py create mode 100644 tests/test_config.py create mode 100644 tests/test_makefile.py create mode 100644 tests/test_smoke.py create mode 100644 tests/test_summarize.py diff --git a/INDEX.md b/INDEX.md new file mode 100644 index 0000000..7d7e7d0 --- /dev/null +++ b/INDEX.md @@ -0,0 +1,84 @@ +# meetus — repo index + +A standalone, local-first **command-line tool**: turn screen-share meeting/training +recordings into a rich, AI-summarizable transcript. The extraction pipeline is +deterministic and offline; the summarization step is the only LLM-facing part. + +meetus stands on its own. The separate **`cht`** project does the same thing in +realtime; meetus may or may not feed it, so the two are kept formally apart (the +cht-facing bits here live under `ctrl/cht/`). + +> This file maps the whole repo. [`README.md`](README.md) is the detailed manual for +> the main `process_meeting.py` CLI. + +## Data flow + +``` +video / audio + │ process_meeting.py (deterministic, offline) + ▼ +output// run folder: YYYYMMDD-NNN-/ + ├── .json Whisper/WhisperX transcript (base) + ├── .srt / .vtt / ... extra transcript formats (optional) + ├── frames/ extracted scene/interval frames + ├── _enhanced.txt transcript + frame refs ◀── the product + └── manifest.json + │ ctrl/summarize/*.py (local LLM — WIP, on hold) + ▼ +_summary_simple.md / _reference.md +``` + +`make batch` (→ `ctrl/batch.sh`) runs the pipeline over a whole directory tree, +mirroring the input folder structure into the output. + +## Status legend + +✅ active · 🚧 WIP, on hold · 🗄️ deprecated (kept for reference) · 🧰 one-off / niche · 📄 docs + +## Layout + +``` +process_meeting.py ✅ the CLI tool — entry point (stays at root) +Makefile ✅ batch convenience wrapper +meetus/ ✅ core package + ├─ workflow.py orchestrator (whisper → frames → merge) + ├─ frame_extractor.py FFmpeg scene-detection / interval frames + ├─ transcript_merger.py interleave transcript + frame refs → enhanced.txt + ├─ output_manager.py run-folder naming + manifest.json + ├─ cache_manager.py per-step caching (skip done work on rerun) + └─ deprecated/ 🗄️ old screen-text idea (OCR/vision/hybrid) — unwired, reference only + ├─ ocr_processor.py (was --ocr-engine) + ├─ vision_processor.py (was --use-vision) + ├─ hybrid_processor.py (was --use-hybrid) + └─ prompts/ vision context prompts +ctrl/ control plane / operational scripts + ├─ batch.sh ✅ recursive batch runner (mirrors tree, continues past failures) + ├─ transcribe_oneoff.sh 🧰 high-quality re-transcription over an existing run + ├─ summarize/ 🚧 last step — local-LLM summarization (WIP, on hold) + │ ├─ summarize_simple.py minimal map-and-append; reads every referenced frame + │ ├─ compile_meeting.py REFINE-pattern technical reference; on-demand frames + │ └─ summarize_meeting.py map→extract(validated facts)→reduce + └─ cht/ 🧰 bridge to the separate realtime `cht` project + └─ interleave_cht_frames.py whisperx JSON + cht frames/index.json → enhanced.txt +def/ 📄 design/decision notes, in order (the feature history) +README.md 📄 manual for process_meeting.py +INDEX.md 📄 this file +MARIAN.md 📄 genesis brainstorm (explains why the deprecated OCR path exists) +local-run.sh 📄 personal scratch invocations (gitignored) +``` + +## Notes + +- **Default flow** uses `--embed-images` (frames referenced for the LLM to read) + + `--scene-detection --scene-threshold 10 --diarize`. `make batch` adds + `--transcript-formats srt` and writes outputs next to the sources. See `README.md`. +- **`meetus/deprecated/`** is no longer imported or reachable from the CLI (its flags + were removed and `workflow.py` no longer imports it). Kept for reference only; the + realtime continuation of the idea is the separate `cht` project. +- **`ctrl/summarize/`** scripts are standalone; run them under an env with the `openai` + client (e.g. `~/wdir/llm/.venv`) against a local OpenAI-compatible server. + +## Loose ends + +- `README.md`'s "Output Files" example still shows the old run-folder format + `YYYYMMDD_HHMMSS-video` (actual: `YYYYMMDD-NNN-`). Minor; worth a tidy. diff --git a/README.md b/README.md index 6a57483..720cca5 100644 --- a/README.md +++ b/README.md @@ -104,7 +104,7 @@ python process_meeting.py samples/meeting.mkv --embed-images --interval 3 --diar python process_meeting.py samples/meeting.mkv --embed-images --scene-detection --scene-threshold 10 --diarize # Iterate on scene threshold (reuse whisper transcript) -python process_meeting.py samples/meeting.mkv --embed-images --scene-detection --scene-threshold 5 --skip-cache-frames --skip-cache-analysis +python process_meeting.py samples/meeting.mkv --embed-images --scene-detection --scene-threshold 5 --skip-cache-frames # Re-run whisper only python process_meeting.py samples/meeting.mkv --embed-images --skip-cache-whisper @@ -150,7 +150,6 @@ The tool automatically reuses the most recent output directory for the same vide - `--no-cache`: Force complete reprocessing - `--skip-cache-frames`: Re-extract frames only - `--skip-cache-whisper`: Re-run transcription only -- `--skip-cache-analysis`: Re-run analysis only This allows you to iterate on scene detection thresholds without re-running Whisper! @@ -169,7 +168,7 @@ python process_meeting.py samples/meeting.mkv --embed-images --scene-detection - python process_meeting.py samples/meeting.mkv --embed-images --scene-detection --scene-threshold 10 --diarize # Adjust scene threshold (keeps cached whisper transcript) -python process_meeting.py samples/meeting.mkv --embed-images --scene-detection --scene-threshold 5 --skip-cache-frames --skip-cache-analysis +python process_meeting.py samples/meeting.mkv --embed-images --scene-detection --scene-threshold 5 --skip-cache-frames ``` ### Example Prompt for Claude @@ -186,42 +185,17 @@ Please summarize this meeting transcript. Pay special attention to: ## Command Reference -``` -usage: process_meeting.py [-h] [--transcript TRANSCRIPT] [--run-whisper] - [--whisper-model {tiny,base,small,medium,large}] - [--diarize] [--output OUTPUT] [--output-dir OUTPUT_DIR] - [--interval INTERVAL] [--scene-detection] - [--scene-threshold SCENE_THRESHOLD] - [--embed-images] [--embed-quality EMBED_QUALITY] - [--no-cache] [--skip-cache-frames] [--skip-cache-whisper] - [--skip-cache-analysis] [--no-deduplicate] - [--extract-only] [--format {detailed,compact}] - [--verbose] video +`process_meeting.py --help` is the source of truth for flags — run it rather than +relying on a copy here. The essentials: -Main Options: - video Path to video file - --diarize Use WhisperX with speaker diarization - --embed-images Add frame file references to transcript (recommended) +- `--diarize` — WhisperX with speaker diarization (needs a HuggingFace token) +- `--embed-images` — reference frames in the transcript for the LLM (default behavior) +- `--scene-detection` / `--scene-threshold N` — frame extraction (lower = more frames) +- `--interval N` — fixed-interval extraction instead of scene detection +- `--transcript-formats srt,vtt,…` — extra transcript formats alongside JSON +- `--no-cache` / `--skip-cache-frames` / `--skip-cache-whisper` — cache control -Frame Extraction: - --scene-detection Use FFmpeg scene detection (recommended) - --scene-threshold Detection sensitivity 0-100 (default: 15, lower=more sensitive) - --interval Extract frame every N seconds (alternative to scene detection) - -Caching: - --no-cache Force complete reprocessing - --skip-cache-frames Re-extract frames only - --skip-cache-whisper Re-run transcription only - --skip-cache-analysis Re-run analysis only - -Other: - --run-whisper Run Whisper (without diarization) - --whisper-model Whisper model: tiny, base, small, medium, large (default: medium) - --transcript, -t Path to existing Whisper transcript (JSON or TXT) - --output, -o Output file for enhanced transcript - --output-dir Directory for output files (default: output/) - --verbose, -v Enable verbose logging -``` +For batches, prefer `make batch IN=` (see [`INDEX.md`](INDEX.md)). ## Tips for Best Results @@ -238,10 +212,6 @@ Other: - **Whisper** (`--run-whisper`): Standard transcription, fast - **WhisperX** (`--run-whisper --diarize`): Adds speaker identification, requires HuggingFace token -### Deduplication -- Enabled by default - removes similar consecutive frames -- Disable with `--no-deduplicate` if slides/screens change subtly - ## Troubleshooting ### Frame Extraction Issues @@ -274,44 +244,37 @@ Other: **Want to re-run specific steps** - `--skip-cache-frames`: Re-extract frames - `--skip-cache-whisper`: Re-run transcription -- `--skip-cache-analysis`: Re-run analysis - `--no-cache`: Force complete reprocessing -## Experimental Features +## Deprecated Features (kept for reference) ### OCR and Vision Analysis -OCR (`--ocr-engine`) and Vision analysis (`--use-vision`) options are available but experimental. The recommended approach is to use `--embed-images` which embeds frame references directly in the transcript, letting your LLM analyze the images. - -```bash -# Experimental: OCR extraction -python process_meeting.py samples/meeting.mkv --run-whisper --ocr-engine tesseract - -# Experimental: Vision model analysis -python process_meeting.py samples/meeting.mkv --run-whisper --use-vision --vision-model llava:13b - -# Experimental: Hybrid OpenCV + OCR -python process_meeting.py samples/meeting.mkv --run-whisper --use-hybrid -``` +OCR, Vision and Hybrid screen-text analysis were the original approach but went nowhere. They have been **removed from the CLI** (the `--ocr-engine` / `--use-vision` / `--use-hybrid` flags no longer exist) and now live, unwired, in `meetus/deprecated/` for reference only. The tool always references frames (`--embed-images`) so your LLM reads them directly. The realtime continuation of the idea is the separate `cht` project. See [`INDEX.md`](INDEX.md). ## Project Structure +See [`INDEX.md`](INDEX.md) for the full repo map. In brief: + ``` meetus/ -├── meetus/ # Main package -│ ├── __init__.py +├── process_meeting.py # Main CLI script (entry point) +├── Makefile # `make batch` convenience wrapper +├── meetus/ # Core package │ ├── workflow.py # Processing orchestrator -│ ├── output_manager.py # Output directory & manifest management -│ ├── cache_manager.py # Caching logic -│ ├── frame_extractor.py # Video frame extraction (FFmpeg scene detection) -│ ├── vision_processor.py # Vision model analysis (experimental) -│ ├── ocr_processor.py # OCR processing (experimental) -│ └── transcript_merger.py # Transcript merging -├── process_meeting.py # Main CLI script -├── requirements.txt # Python dependencies -├── output/ # Timestamped output directories -│ └── YYYYMMDD_HHMMSS-video/ # Auto-generated per video -├── samples/ # Sample videos (gitignored) +│ ├── frame_extractor.py # Frame extraction (FFmpeg scene detection) +│ ├── transcript_merger.py # Transcript + frame-ref merging +│ ├── output_manager.py # Run dirs (YYYYMMDD-NNN-) & manifest +│ ├── cache_manager.py # Per-step caching +│ └── deprecated/ # Old OCR/vision/hybrid analysis (reference only) +├── ctrl/ # Control plane / operational scripts +│ ├── batch.sh # Recursive batch runner +│ ├── transcribe_oneoff.sh # High-quality re-transcription +│ ├── summarize/ # Local-LLM summarization (WIP, on hold) +│ └── cht/ # Bridge to the realtime `cht` project +├── def/ # Design/decision notes +├── output/ # Run directories (gitignored) +├── samples/ # Sample inputs (gitignored) └── README.md # This file ``` diff --git a/interleave_cht_frames.py b/ctrl/cht/interleave_cht_frames.py similarity index 98% rename from interleave_cht_frames.py rename to ctrl/cht/interleave_cht_frames.py index d750d66..1de7c35 100644 --- a/interleave_cht_frames.py +++ b/ctrl/cht/interleave_cht_frames.py @@ -6,7 +6,7 @@ frames/index.json. Frames are placed at their real timestamps rather than appended at the end. Usage: - python interleave_cht_frames.py \\ + python ctrl/cht/interleave_cht_frames.py \\ [output.txt] """ import json diff --git a/compile_meeting.py b/ctrl/summarize/compile_meeting.py similarity index 99% rename from compile_meeting.py rename to ctrl/summarize/compile_meeting.py index 3d082ca..8a6ca2b 100755 --- a/compile_meeting.py +++ b/ctrl/summarize/compile_meeting.py @@ -18,7 +18,7 @@ OpenAI-compatible server (vLLM or llama.cpp — see ~/wdir/llm/serve.sh); --base swaps it. Usage (start `~/wdir/llm/serve.sh qwen-vl` first, then): - ~/wdir/llm/.venv/bin/python compile_meeting.py \\ + ~/wdir/llm/.venv/bin/python ctrl/summarize/compile_meeting.py \\ output//_enhanced.txt \\ "compile every deployment/data-flow workflow and the system architecture \\ as a technical reference; note the [mm:ss] each was shown on screen" \\ diff --git a/summarize_meeting.py b/ctrl/summarize/summarize_meeting.py similarity index 99% rename from summarize_meeting.py rename to ctrl/summarize/summarize_meeting.py index e8040cd..cfff28b 100755 --- a/summarize_meeting.py +++ b/ctrl/summarize/summarize_meeting.py @@ -22,7 +22,7 @@ summarization failure mode — hallucinated names/facts + long-input drift): Usage: # start the local server first (`~/wdir/llm/serve.sh qwen7b`), then: - python summarize_meeting.py output//_enhanced.txt \\ + python ctrl/summarize/summarize_meeting.py output//_enhanced.txt \\ "focus on the names mentioned and their roles, output in English" \\ -o output//summary_en.md diff --git a/summarize_simple.py b/ctrl/summarize/summarize_simple.py similarity index 98% rename from summarize_simple.py rename to ctrl/summarize/summarize_simple.py index a807ec0..3a93efd 100755 --- a/summarize_simple.py +++ b/ctrl/summarize/summarize_simple.py @@ -8,7 +8,7 @@ Edit SYS below to change the steer. Talks to a local OpenAI-compatible endpoint (ollama / vLLM / llama.cpp). Usage: - ~/wdir/llm/.venv/bin/python summarize_simple.py _enhanced.txt \\ + ~/wdir/llm/.venv/bin/python ctrl/summarize/summarize_simple.py _enhanced.txt \\ --base-url http://localhost:11434/v1 --model gemma3-27b-16k """ import argparse, base64, io, re, sys diff --git a/transcribe_oneoff.sh b/ctrl/transcribe_oneoff.sh similarity index 98% rename from transcribe_oneoff.sh rename to ctrl/transcribe_oneoff.sh index ad17eae..54371f0 100755 --- a/transcribe_oneoff.sh +++ b/ctrl/transcribe_oneoff.sh @@ -4,7 +4,7 @@ # merger so the enhanced transcript is regenerated using the existing frames. # # Usage: -# ./transcribe_oneoff.sh