[IMPROVED] Mejorar interacción con Claude Code en claude_voice.py

- Añadido indicador de progreso animado durante la espera de respuestas
- Implementación de timeout configurable para evitar esperas indefinidas
- Nuevo comando de voz 'versión' para verificar la versión de Claude Code
- Nueva opción --version para consultar directamente la versión instalada
- Información más clara sobre el estado de las respuestas
- Sugerencias de solución para problemas comunes
- Actualizado README con las nuevas características

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Mauro Rosero P. 2025-03-30 23:13:04 -05:00
parent ccdfa68813
commit c35f705537
Signed by: mrosero
GPG key ID: 83BD2A5F674B7E26
2 changed files with 118 additions and 15 deletions

View file

@ -180,6 +180,12 @@ bin/claude_voice.py --list-devices
# Especificar dispositivo de audio por ID
bin/claude_voice.py --device 1
# Ver la versión de Claude Code instalada
bin/claude_voice.py --version
# Modificar tiempo máximo de espera para respuestas (en segundos)
bin/claude_voice.py --timeout 30
# Enviar texto directamente (sin voz)
bin/claude_voice.py --text "Cómo puedo crear un archivo en Python"
```

View file

@ -243,7 +243,7 @@ def recognize_speech(language="es-ES"):
return final_result
def send_to_claude(text, silent=False):
def send_to_claude(text, silent=False, timeout=60):
"""Envía el texto reconocido a Claude Code"""
if not text:
return False
@ -255,25 +255,76 @@ def send_to_claude(text, silent=False):
# 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)
# Mostrar que estamos esperando respuesta
print(f"{Colors.BLUE}[Claude Voice]{Colors.END} {Colors.YELLOW}Esperando respuesta de Claude Code...{Colors.END}")
if result.returncode != 0:
print(f"{Colors.RED}Error al ejecutar Claude Code: {result.stderr}{Colors.END}")
# Usar un timer para mostrar actividad
start_time = time.time()
progress_chars = ['', '', '', '', '', '', '', '']
progress_thread_active = True
def show_progress():
i = 0
while progress_thread_active:
sys.stdout.write(f"\r{Colors.BLUE}[Claude Voice]{Colors.END} {Colors.YELLOW}Esperando {progress_chars[i]} {int(time.time() - start_time)}s{Colors.END}")
sys.stdout.flush()
i = (i + 1) % len(progress_chars)
time.sleep(0.1)
# Limpiar la línea cuando terminamos
sys.stdout.write("\r" + " " * 60 + "\r")
sys.stdout.flush()
# Iniciar hilo de progreso
progress_thread = threading.Thread(target=show_progress)
progress_thread.daemon = True
progress_thread.start()
try:
# Enviar el texto como entrada a Claude
result = subprocess.run([claude_cmd, text],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True,
timeout=timeout,
check=False)
# Detener el hilo de progreso
progress_thread_active = False
progress_thread.join(1.0) # Esperar a que termine, pero con timeout
# Verificar resultado
if result.returncode != 0:
print(f"\n{Colors.RED}Error al ejecutar Claude Code: {result.stderr}{Colors.END}")
return False
# Mostrar información sobre la respuesta
print(f"\n{Colors.GREEN}Claude Code ha respondido exitosamente.{Colors.END}")
return True
except subprocess.TimeoutExpired:
# Detener el hilo de progreso
progress_thread_active = False
progress_thread.join(1.0)
print(f"\n{Colors.RED}Tiempo de espera agotado. Claude Code está tardando demasiado en responder.{Colors.END}")
print(f"{Colors.YELLOW}La consulta fue enviada, pero puedes verificar la terminal de Claude Code para ver la respuesta.{Colors.END}")
return False
return True
except Exception as e:
print(f"{Colors.RED}Error al ejecutar Claude Code: {e}{Colors.END}")
print(f"\n{Colors.RED}Error al ejecutar Claude Code: {e}{Colors.END}")
# Sugerir soluciones comunes
if "No such file or directory" in str(e):
print(f"{Colors.YELLOW}No se encontró el comando 'claude'. Asegúrate de tener Claude Code instalado correctamente.{Colors.END}")
print(f"{Colors.YELLOW}Prueba instalarlo con: bin/claude_install.sh{Colors.END}")
return False
def interactive_mode(language="es-ES", continuous=False):
def interactive_mode(language="es-ES", continuous=False, timeout=60, device=None):
"""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}")
print(f"{Colors.BLUE}[Claude Voice]{Colors.END} {Colors.YELLOW}Di 'versión' para conocer la versión de Claude Code{Colors.END}")
try:
while True:
@ -288,8 +339,30 @@ def interactive_mode(language="es-ES", continuous=False):
print(f"{Colors.BLUE}[Claude Voice]{Colors.END} {Colors.YELLOW}Saliendo del modo de voz...{Colors.END}")
break
# Verificar comandos especiales
if text.lower() in ["versión", "version"]:
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"
# Obtener versión
result = subprocess.run([claude_cmd, "--version"],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True,
check=False)
if result.returncode == 0:
version = result.stdout.strip() or "Desconocida"
print(f"{Colors.BLUE}[Claude Voice]{Colors.END} {Colors.GREEN}Versión de Claude Code: {Colors.BOLD}{version}{Colors.END}")
else:
print(f"{Colors.RED}Error al obtener versión: {result.stderr}{Colors.END}")
except Exception as e:
print(f"{Colors.RED}Error al ejecutar Claude Code: {e}{Colors.END}")
continue
# Enviar a Claude Code
success = send_to_claude(text)
success = send_to_claude(text, timeout=timeout)
# Si no es modo continuo, salir después del primer comando exitoso
if not continuous and success:
@ -361,8 +434,10 @@ def main():
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')
parser.add_argument('-d', '--device', type=int, help='ID del dispositivo de audio a utilizar')
parser.add_argument('--timeout', type=int, default=60, help='Tiempo máximo de espera para respuesta de Claude Code (segundos)')
parser.add_argument('--list-devices', action='store_true', help='Listar dispositivos de audio disponibles')
parser.add_argument('--list-languages', action='store_true', help='Listar idiomas soportados')
parser.add_argument('--version', action='store_true', help='Mostrar versión de Claude Code')
parser.add_argument('--install-deps', action='store_true', help='Instalar dependencias')
args = parser.parse_args()
@ -405,14 +480,36 @@ def main():
if args.list_languages:
list_languages()
return
# Mostrar versión de Claude Code si se solicita
if args.version:
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"
# Obtener versión
result = subprocess.run([claude_cmd, "--version"],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True,
check=False)
if result.returncode == 0:
version = result.stdout.strip() or "Desconocida"
print(f"{Colors.BLUE}[Claude Voice]{Colors.END} {Colors.GREEN}Versión de Claude Code: {Colors.BOLD}{version}{Colors.END}")
else:
print(f"{Colors.RED}Error al obtener versión: {result.stderr}{Colors.END}")
except Exception as e:
print(f"{Colors.RED}Error al ejecutar Claude Code: {e}{Colors.END}")
return
# Enviar texto directo si se proporciona
if args.text:
send_to_claude(args.text, args.silent)
send_to_claude(args.text, args.silent, args.timeout)
return
# Modo interactivo con reconocimiento de voz
interactive_mode(args.language, args.continuous)
interactive_mode(args.language, args.continuous, args.timeout, args.device)
if __name__ == "__main__":
main()