# Testing Guide: Phase 1-3 Implementation This guide covers all features implemented in Phases 1-3 of the video processing enhancement project. Use this document to validate each feature works correctly before processing your 3,000+ video library. ## Overview of Changes ### Phase 1: Database Schema & Model Versioning - Model version tracking (SigLIP, ArcFace, labels hash) - New database columns for processing metadata - FTS5 to regular table migration for proper score sorting ### Phase 2: Processing Improvements - Category-specific scene detection thresholds - Enhanced hybrid approach (scene + interval fallback) - Face crop size increased to 256x256 pixels ### Phase 3: Settings UI - Scene threshold controls in Settings page - Preset configurations (static, moderate, dynamic) - Minimum thumbnails configuration --- ## Test 1: Backend Settings Module ### 1.1 Verify Presets Load Correctly ```bash cd /home/user/Search-UI/backend python3 -c " import settings print('Presets:') for name, config in settings.PRESET_SETTINGS.items(): print(f' {name}: threshold={config[\"scene_threshold\"]}, interval={config[\"thumbnail_interval\"]}s, min={config[\"min_thumbnails\"]}') print(f'\nDefaults: {settings.get_defaults()}') " ``` **Expected Output:** ``` Presets: static: threshold=0.12, interval=10.0s, min=30 moderate: threshold=0.2, interval=5.0s, min=35 dynamic: threshold=0.35, interval=2.0s, min=50 Defaults: {'scene_threshold': 0.29, 'thumbnail_interval': 3.0, 'min_thumbnails': 30} ``` ### 1.2 Test get_processing_settings() ```bash cd /home/user/Search-UI/backend python3 -c " import settings print(f'Default: {settings.get_processing_settings()}') settings.set_scene_threshold(0.35) print(f'Updated: {settings.get_processing_settings()}') " ``` **Expected Output:** - Default returns `scene_threshold=0.2` - Updated returns `scene_threshold=0.35` --- ## Test 2: Search Images Model Versioning ### 2.1 Verify Version Constants ```bash cd /home/user/Search-UI/backend python3 -c " # Check the source file for constants with open('search_images.py', 'r') as f: content = f.read() import re version_match = re.search(r'SIGLIP_MODEL_VERSION = \"([^\"]+)\"', content) threshold_match = re.search(r'CLASSIFICATION_THRESHOLD = ([0-9.]+)', content) print(f'SIGLIP_MODEL_VERSION: {version_match.group(1) if version_match else \"NOT FOUND\"}') print(f'CLASSIFICATION_THRESHOLD: {threshold_match.group(1) if threshold_match else \"NOT FOUND\"}') print('get_labels_version(): defined' if 'def get_labels_version()' in content else 'get_labels_version(): NOT FOUND') " ``` **Expected Output:** ``` SIGLIP_MODEL_VERSION: siglip2-so400m-patch16-naflex-v1 CLASSIFICATION_THRESHOLD: 0.1 get_labels_version(): defined ``` ### 2.2 Verify Database Schema (processed_videos table) ```bash cd /home/user/Search-UI/backend python3 -c " from database import get_db conn = get_db() cursor = conn.execute('PRAGMA table_info(processed_videos)') columns = [row[1] for row in cursor.fetchall()] required = ['siglip_model_version', 'labels_version', 'classification_threshold', 'resolution_label', 'scene_threshold', 'duration_seconds', 'fps', 'total_frames'] for col in required: status = '✓' if col in columns else '✗' print(f'{status} {col}') " ``` **Expected:** All columns marked with ✓ ### 2.3 Verify image_categories is Regular Table (not FTS5) ```bash cd /home/user/Search-UI/backend python3 -c " from database import get_db conn = get_db() # Check if it's a regular table (not FTS5 virtual table) cursor = conn.execute(\"SELECT sql FROM sqlite_master WHERE name='image_categories'\") row = cursor.fetchone() if row: sql = row[0] if 'VIRTUAL TABLE' in sql.upper(): print('✗ Still FTS5 virtual table') else: print('✓ Regular table') print(f' Schema: {sql[:100]}...') else: print('✗ Table not found') # Check indexes cursor = conn.execute(\"SELECT name FROM sqlite_master WHERE type='index' AND tbl_name='image_categories'\") indexes = [row[0] for row in cursor.fetchall()] print(f' Indexes: {indexes}') " ``` **Expected:** - Regular table (not virtual) - Indexes include: idx_categories_natural_key, idx_categories_category_name, idx_categories_score --- ## Test 3: Face Search Constants ### 3.1 Verify Constants ```bash cd /home/user/Search-UI/backend python3 -c " with open('face_search.py', 'r') as f: content = f.read() import re crop_match = re.search(r'FACE_CROP_SIZE = (\d+)', content) conf_match = re.search(r'MIN_FACE_CONFIDENCE = ([0-9.]+)', content) version_match = re.search(r'ARCFACE_MODEL_VERSION = \"([^\"]+)\"', content) print(f'FACE_CROP_SIZE: {crop_match.group(1) if crop_match else \"NOT FOUND\"} (expected: 256)') print(f'MIN_FACE_CONFIDENCE: {conf_match.group(1) if conf_match else \"NOT FOUND\"}') print(f'ARCFACE_MODEL_VERSION: {version_match.group(1) if version_match else \"NOT FOUND\"}') " ``` **Expected:** ``` FACE_CROP_SIZE: 256 (expected: 256) MIN_FACE_CONFIDENCE: 0.5 ARCFACE_MODEL_VERSION: arcface-mtcnn-v1 ``` --- ## Test 4: Process Video Integration ### 4.1 Verify Scene Threshold Usage ```bash cd /home/user/Search-UI/backend grep -n "scene_threshold = processing_settings" process_video.py grep -n "gt(scene" process_video.py ``` **Expected:** Both patterns found, showing scene_threshold is used dynamically from settings. ### 4.2 Verify FACE_CROP_SIZE Usage ```bash cd /home/user/Search-UI/backend grep -n "face_search.FACE_CROP_SIZE" process_video.py ``` **Expected:** Found in process_video.py (not hardcoded 128) ### 4.3 Verify Enhanced Hybrid Approach ```bash cd /home/user/Search-UI/backend grep -n "fallback_threshold" process_video.py grep -n "int(min_thumbnails \* 0.5)" process_video.py ``` **Expected:** 50% threshold used for fallback decision --- ## Test 5: API Endpoints ### 5.1 Start Backend Server ```bash cd /home/user/Search-UI tmux new -d -s backend "cd backend && source venv/bin/activate && uvicorn main:app --reload --host 0.0.0.0 2>&1 | tee ../backend.log" sleep 3 tail -5 backend.log ``` **Expected:** Server running on http://0.0.0.0:8000 ### 5.2 Test GET /api/settings/series ```bash curl -s "http://localhost:8000/api/settings/series?language=E" | python3 -m json.tool | head -50 ``` **Expected Response Structure:** ```json { "settings": [...], "available_categories": [...], "presets": { "static": {"scene_threshold": 0.12, ...}, "moderate": {...}, "dynamic": {...} }, "defaults": { "scene_threshold": 0.29, "thumbnail_interval": 3.0, "min_thumbnails": 30 } } ``` ### 5.3 Test POST /api/settings/series ```bash # Add a test setting curl -X POST "http://localhost:8000/api/settings/series?category=TestDrama&thumbnail_interval=2.0&scene_threshold=0.35&min_thumbnails=50&preset=dynamic" # Verify it was added curl -s "http://localhost:8000/api/settings/series?language=E" | python3 -c " import sys, json data = json.load(sys.stdin) for s in data.get('settings', []): if s.get('category') == 'TestDrama': print(f'Found: {s}') break else: print('Not found') " # Clean up curl -s "http://localhost:8000/api/settings/series?language=E" | python3 -c " import sys, json data = json.load(sys.stdin) for s in data.get('settings', []): if s.get('category') == 'TestDrama': print(f'Setting ID to delete: {s[\"id\"]}') " # Delete using the ID from above # curl -X DELETE "http://localhost:8000/api/settings/series/{id}" ``` --- ## Test 6: Frontend Settings Page ### 6.1 Start Frontend Server ```bash cd /home/user/Search-UI tmux new -d -s frontend "cd frontend && npm run dev -- --host 0.0.0.0 2>&1 | tee ../frontend.log" sleep 5 tail -5 frontend.log ``` ### 6.2 Visual Testing Checklist Open browser to http://localhost:5173 (or your network IP:5173) Navigate to Settings page and verify: - [ ] **Presets Section** displays all three presets with values: - Static: Threshold 0.12, Interval 10s, Min 30 - Moderate: Threshold 0.20, Interval 5s, Min 35 - Dynamic: Threshold 0.35, Interval 2s, Min 50 - Default: Shows current defaults - [ ] **Add Series Setting Form** has: - Category dropdown (populated from available categories) - Subcategory dropdown (optional) - Preset dropdown (static, moderate, dynamic, or custom) - Scene Threshold input (0.05-0.5, step 0.01) - Fallback Interval input (0.5-60, step 0.5) - Min Thumbnails input (10-200, step 5) - [ ] **Preset Selection** auto-fills values: - Select "Static" preset → threshold=0.12, interval=10, min=30 - Select "Dynamic" preset → threshold=0.35, interval=2, min=50 - Custom settings inputs become disabled when preset selected - [ ] **Current Settings Table** shows columns: - Category | Subcategory | Threshold | Interval | Min | Preset | Actions - [ ] **Add/Delete** works: - Add a test category with dynamic preset - Verify it appears in table with correct values - Delete it and verify it's removed --- ## Test 7: End-to-End Video Processing ### 7.1 Test with Single Video **Prerequisites:** Have a test video in the system with known category. ```bash # Process a single video with explicit settings curl -X POST "http://localhost:8000/api/process-video?natural_key=YOUR_TEST_KEY&label=480p" ``` ### 7.2 Verify Processing Metadata Saved ```bash cd /home/user/Search-UI/backend python3 -c " from database import get_db conn = get_db() cursor = conn.execute(''' SELECT natural_key, resolution_label, scene_threshold, siglip_model_version, labels_version, duration_seconds FROM processed_videos ORDER BY processed_at DESC LIMIT 5 ''') print('Recent processed videos:') for row in cursor.fetchall(): print(f' {row}') " ``` **Expected:** Shows processing metadata including scene_threshold, model versions ### 7.3 Verify Thumbnail Count After processing, check the thumbnails directory: ```bash # Replace with actual natural_key and label ls -la /home/user/Search-UI/backend/videos/{natural_key}/{label}/thumbnails/ | wc -l ``` **Expected:** Number of thumbnails appropriate for the content type and settings --- ## Automated Test Script Run the comprehensive test script: ```bash cd /home/user/Search-UI python3 scratchpad/2025-12-25-1708-test-phase1-3.py ``` **Expected:** All 6 modules pass (6/6) --- ## Known Limitations ### Phase 4 (Deferred) The Unified Person system (combining face + speaker recognition) requires: - ECAPA-TDNN model integration for speaker embeddings - New Person management UI - Cross-reference system for face ↔ speaker associations - This is planned for future implementation ### Phase 5 (Deferred) Validation and performance improvements: - Bulk reprocessing detection - Performance profiling - These will be addressed after Phase 4 --- ## Troubleshooting ### Backend Won't Start ```bash # Check for Python environment issues cd /home/user/Search-UI/backend source venv/bin/activate pip list | grep -E "fastapi|uvicorn|sqlite-vec" ``` ### Database Migration Issues ```bash # Force recreate tables (WARNING: loses data) cd /home/user/Search-UI/backend python3 -c " from database import get_db conn = get_db() # Drop and recreate problematic tables conn.execute('DROP TABLE IF EXISTS image_categories') # Re-run the app to recreate " ``` ### Frontend Build Issues ```bash cd /home/user/Search-UI/frontend npm install npm run build ``` --- ## Summary Checklist Before processing your video library, verify: - [ ] All automated tests pass (6/6) - [ ] Backend API returns presets and defaults correctly - [ ] Frontend Settings page displays and functions correctly - [ ] Test video processes with correct scene threshold - [ ] Processing metadata saved to database - [ ] Thumbnail count appropriate for content type