Select the types of activity you want to include in your feed.
Refactor screen describe utilities
Centralize segment/suffix parsing in describe and reuse video extension lists across observe and stats. Update category docs/comments to reflect current paths and legacy formatter support.
···66662. For categories with prompts here, a follow-up request extracts detailed content
67673. Results are stored in JSONL under the category name (e.g., `"meeting": {...}`)
68684. `observe/screen.py` formats JSONL to markdown, using custom formatters when available
6969+5. The formatter also supports legacy keys (`meeting_analysis`, `extracted_text`) for older data
+24-16
observe/describe.py
···3838 CATEGORY = "category" # Category-specific follow-up
393940404141+def _segment_and_suffix(media_path: Path) -> tuple[str, str]:
4242+ """Return segment key and descriptive suffix for a media path."""
4343+ from observe.utils import extract_descriptive_suffix
4444+ from think.utils import segment_key
4545+4646+ segment = segment_key(media_path.stem)
4747+ if segment is None:
4848+ raise ValueError(
4949+ f"Invalid video filename: {media_path.stem} (must be HHMMSS_LEN format)"
5050+ )
5151+ try:
5252+ suffix = extract_descriptive_suffix(media_path.stem)
5353+ except ValueError as exc:
5454+ raise ValueError(
5555+ f"Invalid video filename: {media_path.stem} (must be HHMMSS_LEN format)"
5656+ ) from exc
5757+ return segment, suffix
5858+5959+4160def _discover_category_prompts() -> dict[str, dict]:
4261 """
4362 Discover available category prompts from categories/ directory.
···264283265284 def _move_to_segment(self, media_path: Path) -> Path:
266285 """Move media file to its segment and return new path."""
267267- from observe.utils import extract_descriptive_suffix
268268- from think.utils import segment_key
269269-270270- segment = segment_key(media_path.stem)
271271- if segment is None:
272272- raise ValueError(f"Invalid media filename: {media_path.stem}")
273273- suffix = extract_descriptive_suffix(media_path.stem)
286286+ segment, suffix = _segment_and_suffix(media_path)
274287 segment_dir = media_path.parent / segment
275288 try:
276289 segment_dir.mkdir(exist_ok=True)
···696709 suffix = None
697710 if not args.frames_only:
698711 # Extract segment and suffix for output naming
699699- from observe.utils import extract_descriptive_suffix
700700- from think.utils import segment_key
701701-702702- segment = segment_key(video_path.stem)
703703- if segment is None:
704704- parser.error(
705705- f"Invalid video filename: {video_path.stem} (must be HHMMSS_LEN format)"
706706- )
707707- suffix = extract_descriptive_suffix(video_path.stem)
712712+ try:
713713+ segment, suffix = _segment_and_suffix(video_path)
714714+ except ValueError as exc:
715715+ parser.error(str(exc))
708716 segment_dir = video_path.parent / segment
709717 segment_dir.mkdir(exist_ok=True)
710718 # Output JSONL matches input filename pattern (e.g., center_DP-3_screen.jsonl)
+1-1
observe/screen.py
···242425252626def _discover_categories() -> list[str]:
2727- """Discover available categories from observe/describe/ directory.
2727+ """Discover available categories from observe/categories/ directory.
28282929 Categories are defined by .json metadata files in the describe/ package.
3030
+5-6
observe/sense.py
···2020from watchdog.events import FileSystemEventHandler
2121from watchdog.observers import Observer
22222323+from observe.utils import VIDEO_EXTENSIONS
2324from think.callosum import CallosumConnection
2425from think.runner import ManagedProcess as RunnerManagedProcess
2526from think.utils import day_path, setup_cli
···580581 unprocessed = []
581582 unprocessed.extend(sorted(p.name for p in day_dir.glob("*.flac")))
582583 unprocessed.extend(sorted(p.name for p in day_dir.glob("*.m4a")))
583583- unprocessed.extend(sorted(p.name for p in day_dir.glob("*.webm")))
584584- unprocessed.extend(sorted(p.name for p in day_dir.glob("*.mp4")))
585585- unprocessed.extend(sorted(p.name for p in day_dir.glob("*.mov")))
584584+ for ext in VIDEO_EXTENSIONS:
585585+ unprocessed.extend(sorted(p.name for p in day_dir.glob(f"*{ext}")))
586586587587 return {"processed": processed, "unprocessed": unprocessed}
588588···616616 sensor.register("*.m4a", "transcribe", ["observe-transcribe", "{file}"])
617617618618 # Video files: any HHMMSS_*.webm, HHMMSS_*.mp4, HHMMSS_*.mov in day root
619619- sensor.register("*.webm", "describe", ["observe-describe", "{file}"])
620620- sensor.register("*.mp4", "describe", ["observe-describe", "{file}"])
621621- sensor.register("*.mov", "describe", ["observe-describe", "{file}"])
619619+ for ext in VIDEO_EXTENSIONS:
620620+ sensor.register(f"*{ext}", "describe", ["observe-describe", "{file}"])
622621623622 if args.day:
624623 # Batch mode: process specific day