""" Interactive runner for Agent 1 - Change Detection. Walks you through: 1. Choosing the item type from a list 2. For each required angle, uploading the BASELINE (pickup) photo and the RETURN photo, one pair at a time, via a native file-picker dialog 3. Optionally entering the student's complaint text 4. Running the pipeline and printing a clear summary Run: python run_interactive.py """ import os import json from change_detection import run_agent1, ITEM_TYPE_ANGLES def pick_file(window_title): """Open a native file-picker dialog. Falls back to typed path entry if tkinter isn't available (e.g. headless environments).""" try: import tkinter as tk from tkinter import filedialog root = tk.Tk() root.withdraw() root.attributes("-topmost", True) path = filedialog.askopenfilename( title=window_title, filetypes=[("Image files", "*.jpg *.jpeg *.png *.bmp *.webp"), ("All files", "*.*")], ) root.destroy() if path: return path print(" No file selected, please try again.") return pick_file(window_title) except Exception: # fallback: manual path entry while True: path = input(f"{window_title}\n Enter the full file path: ").strip().strip('"') if os.path.isfile(path): return path print(f" File not found: {path}") def choose_item_type(): """Print a numbered menu of all known item types (from ITEM_TYPE_ANGLES) and return the chosen key.""" types = list(ITEM_TYPE_ANGLES.keys()) print("\nSelect item type:") for i, t in enumerate(types, 1): print(f" {i}. {t}") while True: choice = input("Enter number: ").strip() if choice.isdigit() and 1 <= int(choice) <= len(types): return types[int(choice) - 1] print("Invalid choice, try again.") def main(): """Full interactive flow: item type -> per-angle photo pairs -> optional complaint -> run_agent1() -> print results.""" print("=== Agent 1 - Change Detection ===") item_id = input("Item ID (e.g. item_laptop_014, press Enter for a default): ").strip() or "item_test_001" item_type = choose_item_type() angles = ITEM_TYPE_ANGLES[item_type] print(f"\nItem type '{item_type}' requires {len(angles)} angle(s): {', '.join(angles)}") print("For each angle you'll upload the BASELINE (pickup) photo, then the RETURN photo.\n") baseline_photos = [] return_photos = [] for angle in angles: print(f"--- Angle: {angle} ---") print(f"[{angle}] Select the BASELINE (pickup) photo...") base_path = pick_file(f"Baseline photo - angle: {angle}") print(f" Baseline: {base_path}") print(f"[{angle}] Select the RETURN photo...") return_path = pick_file(f"Return photo - angle: {angle}") print(f" Return: {return_path}\n") baseline_photos.append({"angle": angle, "path": base_path}) return_photos.append({"angle": angle, "path": return_path}) complaint_text = input("Optional: student complaint text (press Enter to skip): ").strip() or None print("\nRunning change detection...\n") result = run_agent1( item_id=item_id, item_type=item_type, baseline_photos=baseline_photos, return_photos=return_photos, complaint_text=complaint_text, crop_output_dir="agent1_crops", ) print("=" * 50) print("RESULT") print("=" * 50) print(f"Overall change detected : {result['overall_change_detected']}") print(f"Overall change score : {result['overall_change_score']}") print(f"Routing hint : {result['routing_hint']}") print() for a in result["angles"]: print(f"- {a['angle']}: score={a['change_score']}, aligned_ok={a['aligned_ok']}, regions={len(a['regions'])}") for r in a["regions"]: print(f" region: bbox={r['bbox']} area={r['area']} crop={r['crop_path']}") print("\nFull JSON output:") print(json.dumps(result, indent=2)) if __name__ == "__main__": main()