#!/usr/bin/env python3 # [Script] : claude_voice.py # [Apps] : MRDEVS TOOLS # [Description]: Convierte instrucciones de voz a texto para Claude Code # [Author] : Cortana Rosero One # [Generated] : Created by Claude Code (claude-3-7-sonnet-20250219) # [Created] : 2025/03/30 16:45:00 # [Modified] : 2025/03/30 16:45:00 # [Version] : 1.3.0 # [Use Notes] : Instalar dependencias: pip install speechrecognition pydub pyaudio import os import sys import subprocess import argparse import time import speech_recognition as sr from pydub import AudioSegment from pydub.playback import play # Colores para la salida class Colors: PURPLE = '\033[95m' BLUE = '\033[94m' CYAN = '\033[96m' GREEN = '\033[92m' YELLOW = '\033[93m' RED = '\033[91m' BOLD = '\033[1m' UNDERLINE = '\033[4m' END = '\033[0m' def play_sound(sound_type): """Reproduce un sonido para indicar estados""" sounds_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "sounds") if not os.path.exists(sounds_dir): os.makedirs(sounds_dir, exist_ok=True) # Usar sonidos predeterminados si existen, o crearlos sound_files = { "start": os.path.join(sounds_dir, "start.mp3"), "stop": os.path.join(sounds_dir, "stop.mp3"), "error": os.path.join(sounds_dir, "error.mp3") } # Si no hay archivo de sonido, usar un beep básico try: if os.path.exists(sound_files[sound_type]): sound = AudioSegment.from_file(sound_files[sound_type]) play(sound) else: # Frecuencias para diferentes tipos de sonidos if sound_type == "start": print("\a") # Beep básico del sistema elif sound_type == "stop": print("\a") time.sleep(0.1) print("\a") elif sound_type == "error": print("\a") time.sleep(0.1) print("\a") time.sleep(0.1) print("\a") except Exception: # Si hay algún error reproduciendo el sonido, simplemente continuamos pass def recognize_speech(language="es-ES"): """Captura audio del micrófono y lo convierte a texto""" recognizer = sr.Recognizer() with sr.Microphone() as source: print(f"{Colors.BLUE}[Claude Voice]{Colors.END} {Colors.YELLOW}Escuchando...{Colors.END} (Presiona Ctrl+C para detener)") play_sound("start") # Ajustar para ruido ambiental recognizer.adjust_for_ambient_noise(source, duration=0.5) try: audio = recognizer.listen(source, timeout=10, phrase_time_limit=15) print(f"{Colors.BLUE}[Claude Voice]{Colors.END} {Colors.GREEN}Procesando audio...{Colors.END}") # Intentar reconocer usando Google Speech Recognition text = recognizer.recognize_google(audio, language=language) play_sound("stop") return text except sr.UnknownValueError: play_sound("error") print(f"{Colors.RED}No se pudo entender el audio{Colors.END}") return None except sr.RequestError as e: play_sound("error") print(f"{Colors.RED}Error en el servicio de reconocimiento: {e}{Colors.END}") return None except Exception as e: play_sound("error") print(f"{Colors.RED}Error: {e}{Colors.END}") return None def send_to_claude(text, silent=False): """Envía el texto reconocido a Claude Code""" if not text: return False if not silent: print(f"{Colors.BLUE}[Claude Voice]{Colors.END} Enviando a Claude Code: {Colors.BOLD}{text}{Colors.END}") try: # Usar la ruta de instalación de Claude Code claude_cmd = "claude" if os.system("which claude > /dev/null 2>&1") == 0 else "/usr/local/bin/claude" # Enviar el texto como entrada a Claude result = subprocess.run([claude_cmd, text], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, check=False) if result.returncode != 0: print(f"{Colors.RED}Error al ejecutar Claude Code: {result.stderr}{Colors.END}") return False return True except Exception as e: print(f"{Colors.RED}Error al ejecutar Claude Code: {e}{Colors.END}") return False def interactive_mode(language="es-ES", continuous=False): """Modo interactivo que escucha continuamente comandos de voz""" print(f"{Colors.BLUE}[Claude Voice]{Colors.END} {Colors.GREEN}Modo interactivo iniciado. Di tus instrucciones para Claude Code.{Colors.END}") print(f"{Colors.BLUE}[Claude Voice]{Colors.END} {Colors.YELLOW}Di 'salir' o 'terminar' para finalizar{Colors.END}") try: while True: text = recognize_speech(language) if text: text = text.strip() print(f"{Colors.BLUE}[Claude Voice]{Colors.END} {Colors.GREEN}Reconocido: {Colors.BOLD}{text}{Colors.END}") # Verificar comandos de salida if text.lower() in ["salir", "terminar", "exit", "quit", "goodbye", "bye"]: print(f"{Colors.BLUE}[Claude Voice]{Colors.END} {Colors.YELLOW}Saliendo del modo de voz...{Colors.END}") break # Enviar a Claude Code success = send_to_claude(text) # Si no es modo continuo, salir después del primer comando exitoso if not continuous and success: break # Pausa breve entre reconocimientos if continuous: time.sleep(1) except KeyboardInterrupt: print(f"\n{Colors.BLUE}[Claude Voice]{Colors.END} {Colors.YELLOW}Modo de voz interrumpido por el usuario{Colors.END}") print(f"{Colors.BLUE}[Claude Voice]{Colors.END} {Colors.GREEN}¡Hasta pronto!{Colors.END}") def main(): parser = argparse.ArgumentParser(description='Claude Code Voice - Convierte voz a texto para Claude Code') parser.add_argument('-l', '--language', default='es-ES', help='Idioma para reconocimiento (ej. es-ES, en-US)') parser.add_argument('-c', '--continuous', action='store_true', help='Modo continuo - escucha constantemente hasta que digas "salir"') parser.add_argument('-t', '--text', help='Texto a enviar directamente (sin reconocimiento de voz)') parser.add_argument('-s', '--silent', action='store_true', help='Modo silencioso - no muestra mensajes extra') args = parser.parse_args() if args.text: # Modo de texto directo send_to_claude(args.text, args.silent) else: # Modo interactivo con reconocimiento de voz interactive_mode(args.language, args.continuous) if __name__ == "__main__": main()