Some checks failed
Architecture Lint / Linter Tests (pull_request) Successful in 21s
Smoke Test / smoke (pull_request) Failing after 15s
Validate Config / YAML Lint (pull_request) Failing after 18s
Validate Config / JSON Validate (pull_request) Successful in 21s
Validate Config / Python Syntax & Import Check (pull_request) Failing after 1m3s
Validate Config / Python Test Suite (pull_request) Has been skipped
Validate Config / Shell Script Lint (pull_request) Failing after 1m11s
Validate Config / Cron Syntax Check (pull_request) Successful in 15s
Validate Config / Deploy Script Dry Run (pull_request) Successful in 14s
Validate Config / Playbook Schema Validation (pull_request) Successful in 27s
PR Checklist / pr-checklist (pull_request) Failing after 12m35s
Architecture Lint / Lint Repository (pull_request) Failing after 22s
scripts/generate_scenes_from_media.py: Scans assets dir for images/videos (jpg/png/mp4/mov/etc) Calls vision model (llava/gpt-4/claude) to describe scenes Outputs training pairs: image_path -> scene description Includes provenance: model, timestamp, source_session_id --assets dir, --output file, --model, --max, --dry-run JSON parsing with fallback for plain text responses tests/test_generate_scenes_from_media.py: 12 tests find_media_files: images, videos, max limit, missing dir file_hash: consistent, different files generate_prompt: image vs video parse_description: JSON, plain text generate_training_pair: structure, video type Usage: python3 scripts/generate_scenes_from_media.py --assets ~/assets/ python3 scripts/generate_scenes_from_media.py --assets ~/assets/ --model gpt-4 python3 scripts/generate_scenes_from_media.py --assets ~/assets/ --dry-run
116 lines
3.8 KiB
Python
116 lines
3.8 KiB
Python
"""
|
|
Tests for scripts/generate_scenes_from_media.py — Media scene description generator.
|
|
"""
|
|
|
|
import json
|
|
import os
|
|
import tempfile
|
|
import unittest
|
|
from pathlib import Path
|
|
|
|
import sys
|
|
sys.path.insert(0, str(Path(__file__).parent.parent / "scripts"))
|
|
from generate_scenes_from_media import (
|
|
find_media_files,
|
|
file_hash,
|
|
generate_description_prompt,
|
|
parse_description,
|
|
generate_training_pair,
|
|
IMAGE_EXTENSIONS,
|
|
VIDEO_EXTENSIONS,
|
|
)
|
|
|
|
|
|
class TestFindMediaFiles(unittest.TestCase):
|
|
def test_finds_images(self):
|
|
with tempfile.TemporaryDirectory() as tmpdir:
|
|
Path(tmpdir, "test.jpg").touch()
|
|
Path(tmpdir, "test.png").touch()
|
|
Path(tmpdir, "test.txt").touch() # not media
|
|
|
|
files = find_media_files(tmpdir)
|
|
self.assertEqual(len(files), 2)
|
|
|
|
def test_finds_videos(self):
|
|
with tempfile.TemporaryDirectory() as tmpdir:
|
|
Path(tmpdir, "video.mp4").touch()
|
|
Path(tmpdir, "video.mov").touch()
|
|
|
|
files = find_media_files(tmpdir)
|
|
self.assertEqual(len(files), 2)
|
|
|
|
def test_max_limits_results(self):
|
|
with tempfile.TemporaryDirectory() as tmpdir:
|
|
for i in range(10):
|
|
Path(tmpdir, f"img{i}.jpg").touch()
|
|
|
|
files = find_media_files(tmpdir, max_files=3)
|
|
self.assertEqual(len(files), 3)
|
|
|
|
def test_missing_dir_returns_empty(self):
|
|
files = find_media_files("/nonexistent/path")
|
|
self.assertEqual(files, [])
|
|
|
|
|
|
class TestFileHash(unittest.TestCase):
|
|
def test_consistent_hash(self):
|
|
path = Path("/test/file.jpg")
|
|
h1 = file_hash(path)
|
|
h2 = file_hash(path)
|
|
self.assertEqual(h1, h2)
|
|
|
|
def test_different_files_different_hash(self):
|
|
h1 = file_hash(Path("/test/a.jpg"))
|
|
h2 = file_hash(Path("/test/b.jpg"))
|
|
self.assertNotEqual(h1, h2)
|
|
|
|
|
|
class TestGenerateDescriptionPrompt(unittest.TestCase):
|
|
def test_image_prompt(self):
|
|
prompt = generate_description_prompt(Path("test.jpg"))
|
|
self.assertIn("image", prompt.lower())
|
|
self.assertIn("mood", prompt.lower())
|
|
self.assertIn("colors", prompt.lower())
|
|
|
|
def test_video_prompt(self):
|
|
prompt = generate_description_prompt(Path("test.mp4"))
|
|
self.assertIn("video", prompt.lower())
|
|
self.assertIn("camera movement", prompt.lower())
|
|
|
|
|
|
class TestParseDescription(unittest.TestCase):
|
|
def test_parses_json(self):
|
|
text = '{"mood": "calm", "colors": ["blue", "white"], "composition": "wide shot", "camera": "static", "description": "A serene lake"}'
|
|
result = parse_description(text)
|
|
self.assertEqual(result["mood"], "calm")
|
|
self.assertEqual(result["colors"], ["blue", "white"])
|
|
|
|
def test_handles_plain_text(self):
|
|
text = "This is a description of a scene with mood calm and colors blue, white."
|
|
result = parse_description(text)
|
|
self.assertIn("description", result)
|
|
|
|
|
|
class TestGenerateTrainingPair(unittest.TestCase):
|
|
def test_pair_structure(self):
|
|
filepath = Path("/test/photo.jpg")
|
|
description = {"mood": "happy", "colors": ["gold"], "composition": "close-up", "camera": "static", "description": "Smiling face"}
|
|
pair = generate_training_pair(filepath, description, "llava")
|
|
|
|
self.assertEqual(pair["source_file"], str(filepath))
|
|
self.assertEqual(pair["media_type"], "image")
|
|
self.assertEqual(pair["model"], "llava")
|
|
self.assertIn("source_session_id", pair)
|
|
self.assertIn("timestamp", pair)
|
|
self.assertEqual(pair["scene"]["mood"], "happy")
|
|
|
|
def test_video_pair(self):
|
|
filepath = Path("/test/video.mp4")
|
|
description = {"mood": "energetic"}
|
|
pair = generate_training_pair(filepath, description, "gpt-4")
|
|
self.assertEqual(pair["media_type"], "video")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|