import logging from typing import Any, Dict from reachy_mini_conversation_app.tools.core_tools import Tool, ToolDependencies logger = logging.getLogger(__name__) # Initialize dance library try: from reachy_mini_dances_library.collection.dance import AVAILABLE_MOVES from reachy_mini_conversation_app.dance_emotion_moves import DanceQueueMove DANCE_AVAILABLE = True except ImportError as e: logger.warning(f"Dance library not available: {e}") AVAILABLE_MOVES = {} DANCE_AVAILABLE = False class Dance(Tool): """Play a named or random dance move once (or repeat). Non-blocking.""" name = "dance" description = "Play a named or random dance move once (or repeat). Non-blocking." parameters_schema = { "type": "object", "properties": { "move": { "type": "string", "description": """Name of the move; use 'random' or omit for random. Here is a list of the available moves: simple_nod: A simple, continuous up-and-down nodding motion. head_tilt_roll: A continuous side-to-side head roll (ear to shoulder). side_to_side_sway: A smooth, side-to-side sway of the entire head. dizzy_spin: A circular 'dizzy' head motion combining roll and pitch. stumble_and_recover: A simulated stumble and recovery with multiple axis movements. Good vibes interwoven_spirals: A complex spiral motion using three axes at different frequencies. sharp_side_tilt: A sharp, quick side-to-side tilt using a triangle waveform. side_peekaboo: A multi-stage peekaboo performance, hiding and peeking to each side. yeah_nod: An emphatic two-part yeah nod using transient motions. uh_huh_tilt: A combined roll-and-pitch uh-huh gesture of agreement. neck_recoil: A quick, transient backward recoil of the neck. chin_lead: A forward motion led by the chin, combining translation and pitch. groovy_sway_and_roll: A side-to-side sway combined with a corresponding roll for a groovy effect. chicken_peck: A sharp, forward, chicken-like pecking motion. side_glance_flick: A quick glance to the side that holds, then returns. polyrhythm_combo: A 3-beat sway and a 2-beat nod create a polyrhythmic feel. grid_snap: A robotic, grid-snapping motion using square waveforms. pendulum_swing: A simple, smooth pendulum-like swing using a roll motion. jackson_square: Traces a rectangle via a 5-point path, with sharp twitches on arrival at each checkpoint. """, }, "repeat": { "type": "integer", "description": "How many times to repeat the move (default 1).", }, }, "required": [], } async def __call__(self, deps: ToolDependencies, **kwargs: Any) -> Dict[str, Any]: """Play a named or random dance move once (or repeat). Non-blocking.""" if not DANCE_AVAILABLE: return {"error": "Dance system not available"} move_name = kwargs.get("move") repeat = int(kwargs.get("repeat", 1)) logger.info("Tool call: dance move=%s repeat=%d", move_name, repeat) if not move_name or move_name == "random": import random move_name = random.choice(list(AVAILABLE_MOVES.keys())) if move_name not in AVAILABLE_MOVES: return {"error": f"Unknown dance move '{move_name}'. Available: {list(AVAILABLE_MOVES.keys())}"} # Add dance moves to queue movement_manager = deps.movement_manager for _ in range(repeat): dance_move = DanceQueueMove(move_name) movement_manager.queue_move(dance_move) return {"status": "queued", "move": move_name, "repeat": repeat}