Skip to main content
Glama

Voice Mode

by mbailey
configuration.py•17.5 kB
"""MCP resources for voice mode configuration.""" import os from typing import Dict, Any from pathlib import Path from ..server import mcp from ..config import ( logger, # Core settings BASE_DIR, DEBUG, SAVE_ALL, SAVE_AUDIO, SAVE_TRANSCRIPTIONS, AUDIO_FEEDBACK_ENABLED, PREFER_LOCAL, ALWAYS_TRY_LOCAL, AUTO_START_KOKORO, # Service settings OPENAI_API_KEY, TTS_BASE_URLS, STT_BASE_URLS, TTS_VOICES, TTS_MODELS, # Whisper settings WHISPER_MODEL, WHISPER_PORT, WHISPER_LANGUAGE, WHISPER_MODEL_PATH, # Kokoro settings KOKORO_PORT, KOKORO_MODELS_DIR, KOKORO_CACHE_DIR, KOKORO_DEFAULT_VOICE, # Audio settings AUDIO_FORMAT, TTS_AUDIO_FORMAT, STT_AUDIO_FORMAT, SAMPLE_RATE, CHANNELS, # Silence detection DISABLE_SILENCE_DETECTION, VAD_AGGRESSIVENESS, SILENCE_THRESHOLD_MS, MIN_RECORDING_DURATION, INITIAL_SILENCE_GRACE_PERIOD, DEFAULT_LISTEN_DURATION, # Streaming STREAMING_ENABLED, STREAM_CHUNK_SIZE, STREAM_BUFFER_MS, STREAM_MAX_BUFFER, # Event logging EVENT_LOG_ENABLED, EVENT_LOG_DIR, EVENT_LOG_ROTATION ) def mask_sensitive(value: Any, key: str) -> Any: """Mask sensitive values like API keys.""" if key.lower().endswith('_key') or key.lower().endswith('_secret'): if value and isinstance(value, str): return f"{value[:8]}...{value[-4:]}" if len(value) > 12 else "***" return value @mcp.resource("voice://config/all") async def all_configuration() -> str: """ Complete voice mode configuration. Shows all current configuration settings including: - Core settings (directories, saving options) - Provider settings (TTS/STT endpoints and preferences) - Audio settings (formats, quality) - Service-specific settings (Whisper, Kokoro) - Silence detection parameters - Streaming configuration - Event logging settings Sensitive values like API keys are masked for security. """ lines = [] lines.append("Voice Mode Configuration") lines.append("=" * 80) lines.append("") # Core Settings lines.append("Core Settings:") lines.append(f" Base Directory: {BASE_DIR}") lines.append(f" Debug Mode: {DEBUG}") lines.append(f" Save All: {SAVE_ALL}") lines.append(f" Save Audio: {SAVE_AUDIO}") lines.append(f" Save Transcriptions: {SAVE_TRANSCRIPTIONS}") lines.append(f" Audio Feedback: {AUDIO_FEEDBACK_ENABLED}") lines.append("") # Provider Settings lines.append("Provider Settings:") lines.append(f" Prefer Local: {PREFER_LOCAL}") lines.append(f" Always Try Local: {ALWAYS_TRY_LOCAL}") lines.append(f" Auto-start Kokoro: {AUTO_START_KOKORO}") lines.append(f" TTS Endpoints: {', '.join(TTS_BASE_URLS)}") lines.append(f" STT Endpoints: {', '.join(STT_BASE_URLS)}") lines.append(f" TTS Voices: {', '.join(TTS_VOICES)}") lines.append(f" TTS Models: {', '.join(TTS_MODELS)}") if OPENAI_API_KEY: lines.append(f" OpenAI API Key: {mask_sensitive(OPENAI_API_KEY, 'openai_api_key')}") lines.append("") # Audio Settings lines.append("Audio Settings:") lines.append(f" Format: {AUDIO_FORMAT}") lines.append(f" TTS Format: {TTS_AUDIO_FORMAT}") lines.append(f" STT Format: {STT_AUDIO_FORMAT}") lines.append(f" Sample Rate: {SAMPLE_RATE} Hz") lines.append(f" Channels: {CHANNELS}") lines.append("") # Silence Detection lines.append("Silence Detection:") lines.append(f" Disabled: {DISABLE_SILENCE_DETECTION}") lines.append(f" VAD Aggressiveness: {VAD_AGGRESSIVENESS}") lines.append(f" Silence Threshold: {SILENCE_THRESHOLD_MS} ms") lines.append(f" Min Recording Duration: {MIN_RECORDING_DURATION} s") lines.append(f" Initial Silence Grace: {INITIAL_SILENCE_GRACE_PERIOD} s") lines.append(f" Default Listen Duration: {DEFAULT_LISTEN_DURATION} s") lines.append("") # Streaming lines.append("Streaming:") lines.append(f" Enabled: {STREAMING_ENABLED}") lines.append(f" Chunk Size: {STREAM_CHUNK_SIZE} bytes") lines.append(f" Buffer: {STREAM_BUFFER_MS} ms") lines.append(f" Max Buffer: {STREAM_MAX_BUFFER} s") lines.append("") # Event Logging lines.append("Event Logging:") lines.append(f" Enabled: {EVENT_LOG_ENABLED}") lines.append(f" Directory: {EVENT_LOG_DIR}") lines.append(f" Rotation: {EVENT_LOG_ROTATION}") lines.append("") # Whisper lines.append("Whisper Configuration:") lines.append(f" Model: {WHISPER_MODEL}") lines.append(f" Port: {WHISPER_PORT}") lines.append(f" Language: {WHISPER_LANGUAGE}") lines.append(f" Model Path: {WHISPER_MODEL_PATH}") lines.append(f" Endpoint: http://127.0.0.1:{WHISPER_PORT}/v1") lines.append("") # Kokoro lines.append("Kokoro Configuration:") lines.append(f" Port: {KOKORO_PORT}") lines.append(f" Models Directory: {KOKORO_MODELS_DIR}") lines.append(f" Cache Directory: {KOKORO_CACHE_DIR}") lines.append(f" Default Voice: {KOKORO_DEFAULT_VOICE}") lines.append(f" Endpoint: http://127.0.0.1:{KOKORO_PORT}/v1") return "\n".join(lines) @mcp.resource("voice://config/whisper") async def whisper_configuration() -> str: """ Whisper service configuration. Shows all Whisper-specific settings including: - Model selection - Port configuration - Language settings - Model storage path These settings control how the local Whisper.cpp service operates. """ lines = [] lines.append("Whisper Service Configuration") lines.append("=" * 40) lines.append("") lines.append("Current Settings:") lines.append(f" Model: {WHISPER_MODEL}") lines.append(f" Port: {WHISPER_PORT}") lines.append(f" Language: {WHISPER_LANGUAGE}") lines.append(f" Model Path: {WHISPER_MODEL_PATH}") lines.append(f" Endpoint: http://127.0.0.1:{WHISPER_PORT}/v1") lines.append("") lines.append("Environment Variables:") lines.append(f" VOICEMODE_WHISPER_MODEL: {os.getenv('VOICEMODE_WHISPER_MODEL', '[not set]')}") lines.append(f" VOICEMODE_WHISPER_PORT: {os.getenv('VOICEMODE_WHISPER_PORT', '[not set]')}") lines.append(f" VOICEMODE_WHISPER_LANGUAGE: {os.getenv('VOICEMODE_WHISPER_LANGUAGE', '[not set]')}") lines.append(f" VOICEMODE_WHISPER_MODEL_PATH: {os.getenv('VOICEMODE_WHISPER_MODEL_PATH', '[not set]')}") return "\n".join(lines) @mcp.resource("voice://config/kokoro") async def kokoro_configuration() -> str: """ Kokoro TTS service configuration. Shows all Kokoro-specific settings including: - Port configuration - Models directory - Cache directory - Default voice selection These settings control how the local Kokoro TTS service operates. """ lines = [] lines.append("Kokoro Service Configuration") lines.append("=" * 40) lines.append("") lines.append("Current Settings:") lines.append(f" Port: {KOKORO_PORT}") lines.append(f" Models Directory: {KOKORO_MODELS_DIR}") lines.append(f" Cache Directory: {KOKORO_CACHE_DIR}") lines.append(f" Default Voice: {KOKORO_DEFAULT_VOICE}") lines.append(f" Endpoint: http://127.0.0.1:{KOKORO_PORT}/v1") lines.append("") lines.append("Environment Variables:") lines.append(f" VOICEMODE_KOKORO_PORT: {os.getenv('VOICEMODE_KOKORO_PORT', '[not set]')}") lines.append(f" VOICEMODE_KOKORO_MODELS_DIR: {os.getenv('VOICEMODE_KOKORO_MODELS_DIR', '[not set]')}") lines.append(f" VOICEMODE_KOKORO_CACHE_DIR: {os.getenv('VOICEMODE_KOKORO_CACHE_DIR', '[not set]')}") lines.append(f" VOICEMODE_KOKORO_DEFAULT_VOICE: {os.getenv('VOICEMODE_KOKORO_DEFAULT_VOICE', '[not set]')}") return "\n".join(lines) def parse_env_file(file_path: Path) -> Dict[str, str]: """Parse an environment file and return a dictionary of key-value pairs.""" config = {} if not file_path.exists(): return config try: with open(file_path, 'r') as f: for line in f: line = line.strip() # Skip empty lines and comments if not line or line.startswith('#'): continue # Parse KEY=VALUE format if '=' in line: key, value = line.split('=', 1) key = key.strip() value = value.strip().strip('"').strip("'") config[key] = value except Exception as e: logger.error(f"Error parsing {file_path}: {e}") return config @mcp.resource("voice://config/env-vars") async def environment_variables() -> str: """ All voice mode environment variables with current values. Shows each configuration variable with: - Name: The environment variable name - Environment Value: Current value from environment - Config File Value: Value from ~/.voicemode/voicemode.env (if exists) - Description: What the variable controls This helps identify configuration sources and troubleshoot settings. """ # Parse config file - try new path first, fall back to old user_config_path = Path.home() / ".voicemode" / "voicemode.env" if not user_config_path.exists(): old_path = Path.home() / ".voicemode" / ".voicemode.env" if old_path.exists(): user_config_path = old_path file_config = parse_env_file(user_config_path) # Define all configuration variables with descriptions config_vars = [ # Core Settings ("VOICEMODE_BASE_DIR", "Base directory for all voicemode data"), ("VOICEMODE_MODELS_DIR", "Directory for all models (defaults to $VOICEMODE_BASE_DIR/models)"), ("VOICEMODE_DEBUG", "Enable debug mode (true/false)"), ("VOICEMODE_SAVE_ALL", "Save all audio and transcriptions (true/false)"), ("VOICEMODE_SAVE_AUDIO", "Save audio files (true/false)"), ("VOICEMODE_SAVE_TRANSCRIPTIONS", "Save transcription files (true/false)"), ("VOICEMODE_AUDIO_FEEDBACK", "Enable audio feedback (true/false)"), # Provider Settings ("VOICEMODE_PREFER_LOCAL", "Prefer local providers over cloud (true/false)"), ("VOICEMODE_ALWAYS_TRY_LOCAL", "Always attempt local providers (true/false)"), ("VOICEMODE_AUTO_START_KOKORO", "Auto-start Kokoro service (true/false)"), ("VOICEMODE_TTS_BASE_URLS", "Comma-separated list of TTS endpoints"), ("VOICEMODE_STT_BASE_URLS", "Comma-separated list of STT endpoints"), ("VOICEMODE_VOICES", "Comma-separated list of preferred voices"), ("VOICEMODE_TTS_MODELS", "Comma-separated list of preferred models"), # Audio Settings ("VOICEMODE_AUDIO_FORMAT", "Audio format for recording (pcm/mp3/wav/flac/aac/opus)"), ("VOICEMODE_TTS_AUDIO_FORMAT", "Audio format for TTS output"), ("VOICEMODE_STT_AUDIO_FORMAT", "Audio format for STT input"), # Whisper Configuration ("VOICEMODE_WHISPER_MODEL", "Whisper model to use (e.g., large-v2)"), ("VOICEMODE_WHISPER_PORT", "Whisper server port"), ("VOICEMODE_WHISPER_LANGUAGE", "Language for transcription"), ("VOICEMODE_WHISPER_MODEL_PATH", "Path to Whisper models"), # Kokoro Configuration ("VOICEMODE_KOKORO_PORT", "Kokoro server port"), ("VOICEMODE_KOKORO_MODELS_DIR", "Directory for Kokoro models"), ("VOICEMODE_KOKORO_CACHE_DIR", "Directory for Kokoro cache"), ("VOICEMODE_KOKORO_DEFAULT_VOICE", "Default Kokoro voice"), # Silence Detection ("VOICEMODE_DISABLE_SILENCE_DETECTION", "Disable silence detection (true/false)"), ("VOICEMODE_VAD_AGGRESSIVENESS", "Voice activity detection aggressiveness (0-3)"), ("VOICEMODE_SILENCE_THRESHOLD_MS", "Silence threshold in milliseconds"), ("VOICEMODE_MIN_RECORDING_DURATION", "Minimum recording duration in seconds"), ("VOICEMODE_INITIAL_SILENCE_GRACE_PERIOD", "Initial silence grace period in seconds"), ("VOICEMODE_DEFAULT_LISTEN_DURATION", "Default listen duration in seconds"), # Streaming ("VOICEMODE_STREAMING_ENABLED", "Enable audio streaming (true/false)"), ("VOICEMODE_STREAM_CHUNK_SIZE", "Stream chunk size in bytes"), ("VOICEMODE_STREAM_BUFFER_MS", "Stream buffer in milliseconds"), ("VOICEMODE_STREAM_MAX_BUFFER", "Maximum stream buffer in seconds"), # Event Logging ("VOICEMODE_EVENT_LOG_ENABLED", "Enable event logging (true/false)"), ("VOICEMODE_EVENT_LOG_DIR", "Directory for event logs"), ("VOICEMODE_EVENT_LOG_ROTATION", "Log rotation policy (daily/weekly/monthly)"), # API Keys ("OPENAI_API_KEY", "OpenAI API key for cloud TTS/STT"), ] result = [] result.append("Voice Mode Environment Variables") result.append("=" * 80) result.append("") for var_name, description in config_vars: env_value = os.getenv(var_name) config_value = file_config.get(var_name) # Mask sensitive values if 'KEY' in var_name or 'SECRET' in var_name: if env_value: env_value = mask_sensitive(env_value, var_name) if config_value: config_value = mask_sensitive(config_value, var_name) result.append(f"{var_name}") result.append(f" Environment: {env_value or '[not set]'}") result.append(f" Config File: {config_value or '[not set]'}") result.append(f" Description: {description}") result.append("") return "\n".join(result) @mcp.resource("voice://config/env-template") async def environment_template() -> str: """ Environment variable template for voice mode configuration. Provides a ready-to-use template of all available environment variables with their current values. This can be saved to ~/.voicemode/voicemode.env and customized as needed. Sensitive values like API keys are masked for security. """ template_lines = [ "#!/usr/bin/env bash", "# Voice Mode Environment Configuration", "# Generated from current settings", "", "# Core Settings", f"export VOICEMODE_BASE_DIR=\"{BASE_DIR}\"", f"export VOICEMODE_DEBUG=\"{str(DEBUG).lower()}\"", f"export VOICEMODE_SAVE_ALL=\"{str(SAVE_ALL).lower()}\"", f"export VOICEMODE_SAVE_AUDIO=\"{str(SAVE_AUDIO).lower()}\"", f"export VOICEMODE_SAVE_TRANSCRIPTIONS=\"{str(SAVE_TRANSCRIPTIONS).lower()}\"", f"export VOICEMODE_AUDIO_FEEDBACK=\"{str(AUDIO_FEEDBACK_ENABLED).lower()}\"", "", "# Provider Settings", f"export VOICEMODE_PREFER_LOCAL=\"{str(PREFER_LOCAL).lower()}\"", f"export VOICEMODE_ALWAYS_TRY_LOCAL=\"{str(ALWAYS_TRY_LOCAL).lower()}\"", f"export VOICEMODE_AUTO_START_KOKORO=\"{str(AUTO_START_KOKORO).lower()}\"", f"export VOICEMODE_TTS_BASE_URLS=\"{','.join(TTS_BASE_URLS)}\"", f"export VOICEMODE_STT_BASE_URLS=\"{','.join(STT_BASE_URLS)}\"", f"export VOICEMODE_VOICES=\"{','.join(TTS_VOICES)}\"", f"export VOICEMODE_TTS_MODELS=\"{','.join(TTS_MODELS)}\"", "", "# Audio Settings", f"export VOICEMODE_AUDIO_FORMAT=\"{AUDIO_FORMAT}\"", f"export VOICEMODE_TTS_AUDIO_FORMAT=\"{TTS_AUDIO_FORMAT}\"", f"export VOICEMODE_STT_AUDIO_FORMAT=\"{STT_AUDIO_FORMAT}\"", "", "# Whisper Configuration", f"export VOICEMODE_WHISPER_MODEL=\"{WHISPER_MODEL}\"", f"export VOICEMODE_WHISPER_PORT=\"{WHISPER_PORT}\"", f"export VOICEMODE_WHISPER_LANGUAGE=\"{WHISPER_LANGUAGE}\"", f"export VOICEMODE_WHISPER_MODEL_PATH=\"{WHISPER_MODEL_PATH}\"", "", "# Kokoro Configuration", f"export VOICEMODE_KOKORO_PORT=\"{KOKORO_PORT}\"", f"export VOICEMODE_KOKORO_MODELS_DIR=\"{KOKORO_MODELS_DIR}\"", f"export VOICEMODE_KOKORO_CACHE_DIR=\"{KOKORO_CACHE_DIR}\"", f"export VOICEMODE_KOKORO_DEFAULT_VOICE=\"{KOKORO_DEFAULT_VOICE}\"", "", "# Silence Detection", f"export VOICEMODE_DISABLE_SILENCE_DETECTION=\"{str(DISABLE_SILENCE_DETECTION).lower()}\"", f"export VOICEMODE_VAD_AGGRESSIVENESS=\"{VAD_AGGRESSIVENESS}\"", f"export VOICEMODE_SILENCE_THRESHOLD_MS=\"{SILENCE_THRESHOLD_MS}\"", f"export VOICEMODE_MIN_RECORDING_DURATION=\"{MIN_RECORDING_DURATION}\"", f"export VOICEMODE_INITIAL_SILENCE_GRACE_PERIOD=\"{INITIAL_SILENCE_GRACE_PERIOD}\"", f"export VOICEMODE_DEFAULT_LISTEN_DURATION=\"{DEFAULT_LISTEN_DURATION}\"", "", "# Streaming", f"export VOICEMODE_STREAMING_ENABLED=\"{str(STREAMING_ENABLED).lower()}\"", f"export VOICEMODE_STREAM_CHUNK_SIZE=\"{STREAM_CHUNK_SIZE}\"", f"export VOICEMODE_STREAM_BUFFER_MS=\"{STREAM_BUFFER_MS}\"", f"export VOICEMODE_STREAM_MAX_BUFFER=\"{STREAM_MAX_BUFFER}\"", "", "# Event Logging", f"export VOICEMODE_EVENT_LOG_ENABLED=\"{str(EVENT_LOG_ENABLED).lower()}\"", f"export VOICEMODE_EVENT_LOG_DIR=\"{EVENT_LOG_DIR}\"", f"export VOICEMODE_EVENT_LOG_ROTATION=\"{EVENT_LOG_ROTATION}\"", "", "# API Keys (masked for security)", f"# export OPENAI_API_KEY=\"{mask_sensitive(OPENAI_API_KEY, 'api_key')}\"", ] return "\n".join(template_lines)

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/mbailey/voicemode'

If you have feedback or need assistance with the MCP directory API, please join our Discord server