import asyncio import logging import signal import os from dotenv import load_dotenv from db.database import init_db, close_db_pool from db.repository import Repository from core.metrics import start_metrics_server from core.llm import LLMClient from core.queue import RedisQueue from services.ai_processor import AIProcessor from services.collector import CollectorService from services.admin_bot import AdminBotService from services.publisher import PublisherService # Load environment variables load_dotenv() # Configure logging logging.basicConfig( level=logging.INFO, format="%(asctime)s [%(levelname)s] %(name)s: %(message)s" ) logger = logging.getLogger("copykar.main") async def main(): logger.info("Starting Copykar System with Immediate Admin Review & Paced Target Queues...") # 1. Start Prometheus metrics server metrics_port = int(os.getenv("METRICS_PORT", "8000")) start_metrics_server(metrics_port) # 2. Initialize Database schema & Redis Queue await init_db() logger.info("Database schema initialized.") redis_queue = RedisQueue() await redis_queue.connect() repo = Repository() llm = LLMClient() # 3. Create Services ai_processor = AIProcessor(repo=repo, llm=llm) admin_bot = AdminBotService(repo=repo, ai_processor=ai_processor, queue=redis_queue) collector = CollectorService(repo=repo, on_post_received=admin_bot.send_raw_review_post) admin_bot.set_collector(collector) # Publisher handles per-target delivery queues, intervals, and sleep windows publisher = PublisherService(repo=repo, queue=redis_queue, client=collector.client) # 4. Start all services await admin_bot.start() await collector.start(notify_fn=admin_bot.notify_admins) await publisher.start() logger.info("All Copykar services are active and running.") # Graceful shutdown event stop_event = asyncio.Event() loop = asyncio.get_running_loop() for sig in (signal.SIGINT, signal.SIGTERM): try: loop.add_signal_handler(sig, stop_event.set) except NotImplementedError: pass try: await stop_event.wait() except (asyncio.CancelledError, KeyboardInterrupt): pass finally: logger.info("Shutting down Copykar services...") await collector.stop() await publisher.stop() await admin_bot.stop() await redis_queue.close() await close_db_pool() logger.info("Copykar cleanly shut down.") if __name__ == "__main__": asyncio.run(main())