Skip to main content
Glama
start_bot.py9.41 kB
#!/usr/bin/env python3 """ IRIS Bot Startup Script Performs all necessary checks and starts the bot properly """ import sys import os import time import signal import subprocess from pathlib import Path from typing import Optional, Tuple # Add project root to path PROJECT_ROOT = Path(__file__).parent.parent sys.path.insert(0, str(PROJECT_ROOT)) try: import redis.asyncio as redis import asyncio from dotenv import load_dotenv except ImportError: print("❌ Missing dependencies. Installing...") subprocess.run([sys.executable, "-m", "pip", "install", "-q", "redis", "python-dotenv"]) import redis.asyncio as redis import asyncio from dotenv import load_dotenv # Colors class Colors: RED = '\033[0;31m' GREEN = '\033[0;32m' YELLOW = '\033[1;33m' BLUE = '\033[0;34m' BOLD = '\033[1m' NC = '\033[0m' def print_header(text: str): print("━" * 60) print(f"{Colors.BOLD}{text}{Colors.NC}") print("━" * 60) print() def print_step(step: int, total: int, text: str): print(f"{Colors.BLUE}[{step}/{total}]{Colors.NC} {text}") def print_success(text: str): print(f"{Colors.GREEN}✓ {text}{Colors.NC}") def print_warning(text: str): print(f"{Colors.YELLOW}⚠️ {text}{Colors.NC}") def print_error(text: str): print(f"{Colors.RED}✗ {text}{Colors.NC}") def get_pid_file() -> Path: return PROJECT_ROOT / ".bot.pid" def get_log_file() -> Path: return PROJECT_ROOT / "bot.log" def check_existing_process() -> Optional[int]: """Check if bot is already running""" pid_file = get_pid_file() if not pid_file.exists(): return None try: pid = int(pid_file.read_text().strip()) # Check if process exists os.kill(pid, 0) return pid except (ProcessLookupError, ValueError): # Process doesn't exist or invalid PID pid_file.unlink(missing_ok=True) return None def stop_process(pid: int, timeout: int = 10) -> bool: """Stop a process gracefully, force kill if needed""" try: # Send SIGTERM os.kill(pid, signal.SIGTERM) # Wait for graceful shutdown for _ in range(timeout): try: os.kill(pid, 0) # Check if still alive time.sleep(1) except ProcessLookupError: return True # Force kill if still running try: os.kill(pid, signal.SIGKILL) return True except ProcessLookupError: return True except ProcessLookupError: return True except Exception as e: print_error(f"Failed to stop process: {e}") return False def check_env_file() -> Tuple[bool, dict]: """Check if .env file exists and load variables""" env_file = PROJECT_ROOT / ".env" if not env_file.exists(): return False, {} load_dotenv(env_file) env_vars = { 'TELEGRAM_BOT_TOKEN': os.getenv('TELEGRAM_BOT_TOKEN'), 'ANTHROPIC_API_KEY': os.getenv('ANTHROPIC_API_KEY'), 'OPENAI_API_KEY': os.getenv('OPENAI_API_KEY'), 'REDIS_HOST': os.getenv('REDIS_HOST', 'localhost'), 'REDIS_PORT': os.getenv('REDIS_PORT', '6379'), 'REDIS_DB': os.getenv('REDIS_DB', '0'), } return True, env_vars async def check_redis_connection(host: str, port: int, db: int) -> bool: """Check if Redis is accessible""" try: client = redis.Redis( host=host, port=port, db=db, socket_connect_timeout=3, decode_responses=True ) await client.ping() await client.aclose() return True except Exception: return False def check_dependencies() -> bool: """Check if required Python packages are installed""" try: import telegram import anthropic import openai return True except ImportError: return False def rotate_log_file(max_size_mb: int = 10): """Rotate log file if too large""" log_file = get_log_file() if not log_file.exists(): return size_mb = log_file.stat().st_size / (1024 * 1024) if size_mb > max_size_mb: print_warning(f"Log file is {size_mb:.1f}MB, rotating...") log_file.rename(log_file.with_suffix('.log.old')) def start_bot() -> Optional[int]: """Start the bot process""" log_file = get_log_file() # Start bot in background cmd = [sys.executable, "-m", "src.telegram_bot.bot"] with open(log_file, 'a') as log: process = subprocess.Popen( cmd, stdout=log, stderr=log, cwd=PROJECT_ROOT, start_new_session=True # Detach from parent ) # Save PID pid_file = get_pid_file() pid_file.write_text(str(process.pid)) return process.pid def main(): print_header("🚀 IRIS BOT - STARTUP SCRIPT") # Step 1: Check existing process print_step(1, 6, "Checking for existing bot process...") existing_pid = check_existing_process() if existing_pid: print_warning(f"Bot is already running (PID: {existing_pid})") response = input("\nDo you want to restart it? (y/n): ").strip().lower() if response == 'y': print_warning("Stopping old bot process...") if stop_process(existing_pid): print_success("Old process stopped") get_pid_file().unlink(missing_ok=True) else: print_error("Failed to stop old process") return 1 else: print_warning("Keeping existing bot process") return 0 else: print_success("No existing bot process") print() # Step 2: Check environment file print_step(2, 6, "Checking environment configuration...") env_exists, env_vars = check_env_file() if not env_exists: print_error(".env file not found!") print("Please create .env file with required variables") return 1 print_success(".env file found") # Check required variables missing_vars = [k for k, v in env_vars.items() if not v] if missing_vars: print_error("Missing required environment variables:") for var in missing_vars: print(f" - {var}") return 1 print_success("All required environment variables set") print() # Step 3: Check Redis connection print_step(3, 6, "Checking Redis connection...") redis_host = env_vars['REDIS_HOST'] redis_port = int(env_vars['REDIS_PORT']) redis_db = int(env_vars['REDIS_DB']) if asyncio.run(check_redis_connection(redis_host, redis_port, redis_db)): print_success(f"Redis connected at {redis_host}:{redis_port}/{redis_db}") else: print_error(f"Cannot connect to Redis at {redis_host}:{redis_port}") print("Please ensure Redis is running and accessible") return 1 print() # Step 4: Check dependencies print_step(4, 6, "Checking Python dependencies...") if check_dependencies(): print_success("Dependencies OK") else: print_warning("Some dependencies might be missing") print("Installing dependencies...") result = subprocess.run( [sys.executable, "-m", "pip", "install", "-q", "-r", str(PROJECT_ROOT / "requirements.txt")], capture_output=True ) if result.returncode == 0: print_success("Dependencies installed") else: print_warning("Some dependencies might be missing, but continuing...") print() # Step 5: Prepare log file print_step(5, 6, "Preparing log file...") rotate_log_file() print_success(f"Log file: {get_log_file()}") print() # Step 6: Start the bot print_step(6, 6, "Starting IRIS bot...") bot_pid = start_bot() if not bot_pid: print_error("Failed to start bot!") return 1 # Wait and verify time.sleep(3) try: os.kill(bot_pid, 0) # Check if process is alive print_success("Bot started successfully!") except ProcessLookupError: print_error("Bot failed to start!") print(f"Check logs: tail -n 50 {get_log_file()}") get_pid_file().unlink(missing_ok=True) return 1 # Print summary print() print_header("✅ IRIS BOT IS RUNNING") print() print("📊 Bot Information:") print(f" • PID: {bot_pid}") print(f" • Redis: {redis_host}:{redis_port}/{redis_db}") print(f" • Log: {get_log_file()}") print(f" • Provider: {os.getenv('LLM_PROVIDER', 'anthropic')}") print() print("🛠️ Useful Commands:") print(" • View logs: python scripts/logs_bot.py") print(" • Check status: python scripts/status_bot.py") print(" • Stop bot: python scripts/stop_bot.py") print() print("━" * 60) return 0 if __name__ == "__main__": try: sys.exit(main()) except KeyboardInterrupt: print("\n\n❌ Interrupted by user") sys.exit(1) except Exception as e: print_error(f"Unexpected error: {e}") import traceback traceback.print_exc() sys.exit(1)

Latest Blog Posts

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/ilvolodel/iris-legacy'

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