Spaces:
Running
Running
| """ | |
| F.R.I.D.A.Y — Configuration System | |
| Manages all configuration, API keys, and settings. | |
| """ | |
| import os | |
| import json | |
| import secrets | |
| from pathlib import Path | |
| from typing import Any, Optional, Dict | |
| from dataclasses import dataclass, field, asdict | |
| # Product version (used by updater + mobile app update banner) | |
| FRIDAY_VERSION = "1.0.0" | |
| class APIConfig: | |
| """API configuration - Gemini only as the brain.""" | |
| gemini_api_key: str = "" | |
| gemini_model: str = "gemini-2.5-flash-preview-04-17" | |
| # Telegram configuration | |
| telegram_bot_token: str = "8634344914:AAHX6wkf7SH7mY__OWWvnf8ak9wdrR3aHvo" | |
| telegram_user_id: str = "7954781047" | |
| # Local connection | |
| pc_local_ip: str = "192.168.29.101" | |
| pc_hostname: str = "admin" | |
| class SecurityConfig: | |
| """Security configuration.""" | |
| activation_hotkey_sequence: str = "ctrl+alt+f4" | |
| key_expiry_seconds: int = 60 | |
| max_wrong_attempts: int = 3 | |
| voice_phrase_hash: str = "" | |
| voice_sensitivity: float = 0.7 | |
| disguised_process_name: str = "Windows Security Health Service" | |
| # Secret security layers | |
| enable_layer1_sequence: bool = True | |
| enable_layer2_stealth: bool = True | |
| enable_layer3_silent_fail: bool = True | |
| enable_layer4_expiry: bool = True | |
| enable_layer5_voice: bool = True | |
| enable_layer6_intrusion: bool = True | |
| enable_layer7_disguise: bool = True | |
| enable_layer8_wipe: bool = True | |
| class AudioConfig: | |
| """Audio configuration.""" | |
| voice_gender: str = "female" | |
| voice_speed: float = 1.0 | |
| voice_pitch: float = 1.0 | |
| default_output_device: str = "" | |
| default_input_device: str = "" | |
| enable_voice_cloning: bool = False | |
| class GUIConfig: | |
| """GUI configuration.""" | |
| target_fps: int = 120 | |
| theme: str = "stark" | |
| enable_animations: bool = True | |
| enable_holographic: bool = True | |
| window_opacity: float = 0.9 | |
| panel_inertia: float = 0.3 | |
| enable_sound_effects: bool = True | |
| MODE_COLORS = { | |
| "stark": (0, 200, 180), | |
| "combat": (255, 60, 60), | |
| "stealth": (120, 120, 255), | |
| "analysis": (255, 200, 0) | |
| } | |
| class SystemConfig: | |
| """System configuration.""" | |
| low_ram_mode: bool = False | |
| fast_startup: bool = True | |
| enable_auto_updates: bool = True | |
| enable_self_healing: bool = True | |
| log_level: str = "INFO" | |
| data_directory: str = "data" | |
| copies_directory: str = "copies system" | |
| class NetworkConfig: | |
| """Network configuration.""" | |
| local_port: int = 5000 | |
| connection_timeout: int = 2 | |
| enable_encryption: bool = True | |
| encryption_key: str = "" | |
| ip_broadcast_interval: int = 86400 # 24 hours | |
| wol_mac: str = "" | |
| wol_broadcast_ip: str = "255.255.255.255" | |
| wol_port: int = 9 | |
| class MemoryConfig: | |
| """Memory configuration.""" | |
| max_memory_entries: int = 10000 | |
| enable_context_carry: bool = True | |
| enable_crash_memory: bool = True | |
| memory_retention_days: int = 365 | |
| class Config: | |
| """ | |
| Main configuration class for F.R.I.D.A.Y. | |
| Manages all configuration settings with secure storage | |
| and automatic loading/saving. | |
| """ | |
| def __init__(self, config_path: Optional[str] = None): | |
| """ | |
| Initialize configuration. | |
| Args: | |
| config_path: Optional path to config file. If None, uses default. | |
| """ | |
| self.config_path = config_path or self._get_default_config_path() | |
| self.config_dir = os.path.dirname(self.config_path) | |
| # Configuration sections | |
| self.api = APIConfig() | |
| self.security = SecurityConfig() | |
| self.audio = AudioConfig() | |
| self.gui = GUIConfig() | |
| self.system = SystemConfig() | |
| self.network = NetworkConfig() | |
| self.memory = MemoryConfig() | |
| # Runtime state (not saved) | |
| self._loaded = False | |
| self._modified = False | |
| def _get_default_config_path(self) -> str: | |
| """Get the default configuration file path.""" | |
| base_dir = os.path.dirname(os.path.abspath(__file__)) | |
| return os.path.join(base_dir, "config.json") | |
| def load(self) -> bool: | |
| """ | |
| Load configuration from file. | |
| Returns: | |
| True if loaded successfully, False otherwise. | |
| """ | |
| if not os.path.exists(self.config_path): | |
| self._create_default_config() | |
| return True | |
| try: | |
| with open(self.config_path, 'r', encoding='utf-8') as f: | |
| data = json.load(f) | |
| # Load each section | |
| if 'api' in data: | |
| self._load_section(self.api, data['api']) | |
| if 'security' in data: | |
| self._load_section(self.security, data['security']) | |
| if 'audio' in data: | |
| self._load_section(self.audio, data['audio']) | |
| if 'gui' in data: | |
| self._load_section(self.gui, data['gui']) | |
| if 'system' in data: | |
| self._load_section(self.system, data['system']) | |
| if 'network' in data: | |
| self._load_section(self.network, data['network']) | |
| if 'memory' in data: | |
| self._load_section(self.memory, data['memory']) | |
| self._loaded = True | |
| self._modified = False | |
| return True | |
| except Exception as e: | |
| print(f"Failed to load config: {e}") | |
| return False | |
| def save(self) -> bool: | |
| """ | |
| Save configuration to file. | |
| Returns: | |
| True if saved successfully, False otherwise. | |
| """ | |
| try: | |
| # Ensure config directory exists | |
| os.makedirs(self.config_dir, exist_ok=True) | |
| # Build config data | |
| data = { | |
| 'api': asdict(self.api), | |
| 'security': asdict(self.security), | |
| 'audio': asdict(self.audio), | |
| 'gui': asdict(self.gui), | |
| 'system': asdict(self.system), | |
| 'network': asdict(self.network), | |
| 'memory': asdict(self.memory), | |
| } | |
| # Write to file | |
| with open(self.config_path, 'w', encoding='utf-8') as f: | |
| json.dump(data, f, indent=2) | |
| self._modified = False | |
| return True | |
| except Exception as e: | |
| print(f"Failed to save config: {e}") | |
| return False | |
| def _load_section(self, section: Any, data: Dict[str, Any]): | |
| """Load a configuration section from data.""" | |
| for key, value in data.items(): | |
| if hasattr(section, key): | |
| setattr(section, key, value) | |
| def _create_default_config(self): | |
| """Create default configuration file.""" | |
| print("Creating default configuration...") | |
| self.save() | |
| def get(self, section: str, key: str, default: Any = None) -> Any: | |
| """ | |
| Get a configuration value. | |
| Args: | |
| section: Configuration section name. | |
| key: Configuration key. | |
| default: Default value if not found. | |
| Returns: | |
| Configuration value or default. | |
| """ | |
| section_obj = getattr(self, section, None) | |
| if section_obj is None: | |
| return default | |
| return getattr(section_obj, key, default) | |
| def set(self, section: str, key: str, value: Any): | |
| """ | |
| Set a configuration value. | |
| Args: | |
| section: Configuration section name. | |
| key: Configuration key. | |
| value: Value to set. | |
| """ | |
| section_obj = getattr(self, section, None) | |
| if section_obj is not None and hasattr(section_obj, key): | |
| setattr(section_obj, key, value) | |
| self._modified = True | |
| def is_modified(self) -> bool: | |
| """Check if configuration has been modified.""" | |
| return self._modified | |
| def get_gemini_api_key(self) -> str: | |
| """Get Gemini API key.""" | |
| return self.api.gemini_api_key | |
| def set_gemini_api_key(self, key: str): | |
| """Set Gemini API key.""" | |
| self.api.gemini_api_key = key | |
| self._modified = True | |
| def generate_encryption_key(self) -> str: | |
| """ | |
| Generate a new encryption key. | |
| Returns: | |
| New encryption key as hex string. | |
| """ | |
| key = secrets.token_hex(32) | |
| self.network.encryption_key = key | |
| self._modified = True | |
| return key | |
| def get_data_directory(self) -> str: | |
| """Get the data directory path.""" | |
| return os.path.join(os.path.dirname(self.config_path), self.system.data_directory) | |
| def get_copies_directory(self) -> str: | |
| """Get the copies system directory path.""" | |
| return os.path.join(os.path.dirname(self.config_path), self.system.copies_directory) | |
| def ensure_directories(self): | |
| """Ensure all required directories exist.""" | |
| dirs = [ | |
| self.get_data_directory(), | |
| self.get_copies_directory(), | |
| os.path.join(self.get_copies_directory(), "snapshots"), | |
| os.path.join(self.get_copies_directory(), "configs"), | |
| os.path.join(self.get_copies_directory(), "memory"), | |
| os.path.join(self.get_copies_directory(), "logs"), | |
| os.path.join(self.get_copies_directory(), "repair"), | |
| ] | |
| for directory in dirs: | |
| os.makedirs(directory, exist_ok=True) | |
| def validate(self) -> tuple[bool, list[str]]: | |
| """ | |
| Validate configuration. | |
| Returns: | |
| Tuple of (is_valid, list_of_errors). | |
| """ | |
| errors = [] | |
| # Validate required API keys | |
| if not self.api.gemini_api_key: | |
| errors.append("Gemini API key is required") | |
| # Validate Telegram config | |
| if not self.api.telegram_bot_token: | |
| errors.append("Telegram bot token is required") | |
| if not self.api.telegram_user_id: | |
| errors.append("Telegram user ID is required") | |
| # Validate network config | |
| if not self.network.encryption_key: | |
| errors.append("Encryption key is required") | |
| # Validate directories | |
| try: | |
| self.ensure_directories() | |
| except Exception as e: | |
| errors.append(f"Failed to create directories: {e}") | |
| return len(errors) == 0, errors | |
| def reset_to_defaults(self): | |
| """Reset all configuration to defaults.""" | |
| self.api = APIConfig() | |
| self.security = SecurityConfig() | |
| self.audio = AudioConfig() | |
| self.gui = GUIConfig() | |
| self.system = SystemConfig() | |
| self.network = NetworkConfig() | |
| self.memory = MemoryConfig() | |
| self._modified = True | |
| def export(self) -> str: | |
| """ | |
| Export configuration as JSON string. | |
| Returns: | |
| JSON string of configuration. | |
| """ | |
| data = { | |
| 'api': asdict(self.api), | |
| 'security': asdict(self.security), | |
| 'audio': asdict(self.audio), | |
| 'gui': asdict(self.gui), | |
| 'system': asdict(self.system), | |
| 'network': asdict(self.network), | |
| 'memory': asdict(self.memory), | |
| } | |
| return json.dumps(data, indent=2) | |
| def import_from_string(self, config_string: str) -> bool: | |
| """ | |
| Import configuration from JSON string. | |
| Args: | |
| config_string: JSON string of configuration. | |
| Returns: | |
| True if imported successfully, False otherwise. | |
| """ | |
| try: | |
| data = json.loads(config_string) | |
| if 'api' in data: | |
| self._load_section(self.api, data['api']) | |
| if 'security' in data: | |
| self._load_section(self.security, data['security']) | |
| if 'audio' in data: | |
| self._load_section(self.audio, data['audio']) | |
| if 'gui' in data: | |
| self._load_section(self.gui, data['gui']) | |
| if 'system' in data: | |
| self._load_section(self.system, data['system']) | |
| if 'network' in data: | |
| self._load_section(self.network, data['network']) | |
| if 'memory' in data: | |
| self._load_section(self.memory, data['memory']) | |
| self._modified = True | |
| return True | |
| except Exception as e: | |
| print(f"Failed to import config: {e}") | |
| return False | |
| # ========================================== | |
| # LEGACY CONFIGURATION BRIDGE | |
| # ========================================== | |
| # These variables are required by modules that have not yet been | |
| # refactored to use the new Config() dataclass. | |
| import os | |
| # Base paths | |
| BASE_DIR = os.path.dirname(os.path.abspath(__file__)) | |
| DATA_DIR = os.path.join(BASE_DIR, ".friday_data") | |
| COPIES_DIR = os.path.join(BASE_DIR, "copies") | |
| SNAPSHOTS_DIR = os.path.join(COPIES_DIR, "snapshots") | |
| CONFIGS_DIR = os.path.join(COPIES_DIR, "configs") | |
| MEMORY_DIR = os.path.join(COPIES_DIR, "memory") | |
| LOGS_DIR = os.path.join(COPIES_DIR, "logs") | |
| ANALYTICS_DIR = os.path.join(COPIES_DIR, "analytics") | |
| REPAIR_DIR = os.path.join(COPIES_DIR, "repair") | |
| # API | |
| GEMINI_API_KEY = "" # Set your Gemini API key here | |
| GEMINI_MODEL = "gemini-2.5-flash-preview-04-17" | |
| # Audio / Voice | |
| # FRIDAY OMEGA - Young, Natural Human Voice (20-25 female) | |
| # Young, natural, friendly - not robotic | |
| VOICE = "en-US-JennyNeural" # Clear, young female voice | |
| VOICE_RATE = "+10%" # Clear and natural (slightly slower for clarity) | |
| WHISPER_RATE = "+5%" | |
| VOLUME_UP_WAKE = True | |
| # Intervals | |
| POWER_INTERVAL = 60 | |
| NETWORK_INTERVAL = 30 | |
| USB_INTERVAL = 5 | |
| SECURITY_INTERVAL = 10 | |
| SCREEN_CHECK_INTERVAL = 15 | |
| ANALYTICS_INTERVAL = 300 | |
| COPIES_INTERVAL = 3600 | |
| HEALING_INTERVAL = 600 | |
| # Modes | |
| MODES = ["STARK", "TACTICAL", "CHILL", "GAMING", "MISSION", "GUARDIAN"] | |
| DEFAULT_MODE = "STARK" | |
| MODE_COLORS = { | |
| "STARK": "#00FFFF", | |
| "TACTICAL": "#FF0000", | |
| "CHILL": "#00FF00", | |
| "GAMING": "#FF00FF", | |
| "MISSION": "#FFFF00", | |
| "GUARDIAN": "#FFFFFF" | |
| } | |
| # Security | |
| SUSPICIOUS_CPU_THRESHOLD = 80 | |
| WEBCAM_ALERT = True | |
| USB_AUTORUN_BLOCK = True | |
| # Gaming | |
| GAME_PROCESSES = ["steam.exe", "csgo.exe", "valorant.exe", "dota2.exe", "leagueoflegends.exe"] | |
| # Standby | |
| SILENT_STANDBY = True | |
| VK_F3 = 0x72 | |
| VK_F4 = 0x73 | |
| DOUBLE_PRESS_WINDOW = 0.45 | |
| CINEMATIC_BOOT = True | |
| # Global config instance expected by legacy modules (e.g., core.listen). | |
| try: | |
| CONFIG = Config() | |
| CONFIG.load() | |
| except Exception: | |
| CONFIG = Config() | |