""" modules/ar_objects.py — FRIDAY AR Object Creator Creates and places 3D objects in AR via voice commands. Smart interpretation - FRIDAY understands intent! """ import os import json import time import random from typing import Optional, List from config import DATA_DIR OBJECTS_FILE = os.path.join(DATA_DIR, "ar_objects.json") # === Smart Object Mapping - FRIDAY understands what you want! === SMART_OBJECTS = { # Vehicles "car": "sphere", "bike": "cylinder", "plane": "cone", "rocket": "cone", "ship": "cylinder", "boat": "cylinder", "train": "cylinder", # Buildings "house": "pyramid", "tower": "cylinder", "building": "pyramid", "castle": "pyramid", "skyscraper": "cylinder", # Nature "tree": "cone", "flower": "cone", "mountain": "pyramid", "rock": "sphere", "sun": "sphere", "moon": "sphere", "planet": "sphere", "star": "star", # Fun "roller coaster": "grid", "coaster": "grid", "ferris wheel": "torus", "wheel": "torus", "ring": "torus", # Characters "iron man": "mark_1", "captain": "shield", "shield": "shield", "arc reactor": "arc_reactor", " repulsor": "repulsor", # Tech vibes "laser": "pyramid", "beam": "pyramid", "portal": "sphere", "wormhole": "sphere", # Weapons "gun": "pyramid", "sword": "pyramid", "blade": "pyramid", # Misc "heart": "heart", "diamond": "diamond", "skull": "skull", "crystal": "diamond", "orb": "sphere", "box": "cube", } def _load() -> dict: if not os.path.exists(OBJECTS_FILE): return {"objects": [], "placed": []} try: with open(OBJECTS_FILE, "r") as f: return json.load(f) except: return {"objects": [], "placed": []} def _save(data: dict) -> None: try: os.makedirs(DATA_DIR, exist_ok=True) with open(OBJECTS_FILE, "w") as f: json.dump(data, f) except: pass # === Pre-defined AR Objects === AR_OBJECTS = { # Basic Shapes "cube": {"type": "box", "color": "#00FFFF", "size": 0.5}, "sphere": {"type": "sphere", "color": "#FF00FF", "size": 0.5}, "cylinder": {"type": "cylinder", "color": "#00FF00", "size": 0.5}, "pyramid": {"type": "cone", "color": "#FFFF00", "size": 0.5}, "torus": {"type": "torus", "color": "#FF6600", "size": 0.5}, # Tech Objects "arc_reactor": {"type": "glow_ring", "color": "#00FFFF", "size": 0.3}, "mark_1": {"type": "helmet", "color": "#FF0000", "size": 1.0}, "shield": {"type": "disk", "color": "#0066FF", "size": 0.8}, " repulsor": {"type": "glow_orb", "color": "#FF3300", "size": 0.2}, # UI Elements "hologram": {"type": "plane", "color": "#00FF88", "size": 1.0}, "grid": {"type": "wire_grid", "color": "#00FF88", "size": 2.0}, "target": {"type": "crosshair", "color": "#FF0000", "size": 0.3}, "radar": {"type": "circle_scan", "color": "#00FF00", "size": 1.0}, # Decorative "star": {"type": "star", "color": "#FFFF00", "size": 0.5}, "heart": {"type": "heart", "color": "#FF0066", "size": 0.3}, "diamond": {"type": "diamond", "color": "#00FFFF", "size": 0.4}, "skull": {"type": "skull", "color": "#FFFFFF", "size": 0.3}, } def list_available_objects() -> List[str]: """List all available object types.""" return list(AR_OBJECTS.keys()) def create_object(name: str, custom_size: float = 0.5, custom_color: str = "") -> str: """ Create a new AR object. Args: name: Object type (cube, sphere, etc) custom_size: Optional custom size custom_color: Optional custom color Returns: Confirmation message """ name = name.lower().strip() if name in AR_OBJECTS: obj = AR_OBJECTS[name].copy() else: # Custom object obj = {"type": "custom", "color": custom_color or "#00FFFF", "size": custom_size} if custom_size > 0: obj["size"] = custom_size if custom_color: obj["color"] = custom_color # Add to objects list data = _load() obj_id = f"{name}_{int(time.time())}" obj["id"] = obj_id obj["created_at"] = time.time() data["objects"].append(obj) _save(data) return f"Created {name}." def place_object(name: str, x: float = 0, y: float = 0, z: float = -2) -> str: """ Place an object in AR space. Args: name: Object name/type x, y, z: Position in AR space Returns: Confirmation message """ name = name.lower().strip() # Get or create object data = _load() obj = None # Look for existing object for o in data.get("objects", []): if name in o.get("id", ""): obj = o break if not obj: # Create new if name in AR_OBJECTS: obj = AR_OBJECTS[name].copy() else: obj = {"type": "box", "color": "#00FFFF", "size": 0.5} # Set position obj["position"] = {"x": x, "y": y, "z": z} obj["id"] = f"{name}_{int(time.time())}" obj["placed_at"] = time.time() # Add to placed if "placed" not in data: data["placed"] = [] data["placed"].append(obj) _save(data) return f"Placed {name} at position." def remove_object(name: str) -> str: """Remove a placed object.""" data = _load() name = name.lower() placed = data.get("placed", []) data["placed"] = [o for o in placed if name not in o.get("id", "")] _save(data) return f"Removed {name}." def clear_all_objects() -> str: """Clear all placed objects.""" data = _load() data["placed"] = [] _save(data) return "All objects cleared." def get_placed_objects() -> List[dict]: """Get all placed objects for AR renderer.""" data = _load() return data.get("placed", []) def get_object_state_for_ar() -> dict: """Get object state for AR scene.""" data = _load() return { "objects": data.get("placed", []), "available": list(AR_OBJECTS.keys()), } # === AR Scene Integration === def update_ar_scene() -> None: """Update AR scene with current objects.""" try: from modules.ar_scene import apply_patch state = get_object_state_for_ar() apply_patch({"ar_objects": state["objects"]}) except: pass # === Smart Voice Command Handler === def handle_command(command: str, speak) -> bool: c = command.lower() # Check for SMART objects first (natural language) for natural_name, ar_obj in SMART_OBJECTS.items(): if natural_name in c: # "make a roller coaster" → creates grid # "place a car" → places sphere if "create" in c or "make" in c or "build" in c: create_result = create_object(ar_obj) msg = create_result.replace("Created", "Its") speak(f"Making {natural_name}! {msg}") return True if "place" in c or "put" in c: place_result = place_object(ar_obj) msg = place_result.replace("Placed", "Done") speak(f"Placing {natural_name}! {msg}") return True # Create object (direct) if "create" in c or "make" in c or "build" in c: for obj in list_available_objects(): if obj in c: result = create_object(obj) speak(result) return True # Ask what to make speak("What should I make? I can do roller coaster, car, plane, house, tree, arc reactor, and more!") return True # Also check for smart objects in basic commands if "place" in c or "put" in c: for obj in list_available_objects(): if obj in c: result = place_object(obj) speak(result) return True speak("Place what?") return True # Remove object if "remove" in c or "delete" in c: for obj in list_available_objects(): if obj in c: result = remove_object(obj) speak(result) return True # Clear all if "clear all" in c or "remove all" in c: result = clear_all_objects() speak(result) return True # List objects if "what objects" in c or "list objects" in c or "show objects" in c: objects = get_placed_objects() if objects: names = [o.get("id", "unknown")[:20] for o in objects] speak(f"Placed: {', '.join(names)}") else: speak("No objects placed. Say 'make a roller coaster' or 'place a car'!") return True # Ask what to make (smart suggestion) if "what can you make" in c or "what do you know" in c: speak("I can make: roller coaster, car, plane, house, tree, arc reactor, heart, star, and much more! Just say 'make a [whatever]'!") return True return False # === Quick Place Functions === def quick_place(obj_type: str) -> str: """Quick place a common object.""" placements = { "reactor": "arc_reactor", "mark": "mark_1", "shield": "shield", "hologram": "hologram", "radar": "radar", "target": "target", "grid": "grid", } target = placements.get(obj_type.lower(), obj_type) return place_object(target)