diff --git a/main.py b/main.py new file mode 100644 index 0000000..c699afc --- /dev/null +++ b/main.py @@ -0,0 +1,86 @@ +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 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...") + + # 1. Start Prometheus metrics server + metrics_port = int(os.getenv("METRICS_PORT", "8000")) + start_metrics_server(metrics_port) + + # 2. Initialize Database schema + await init_db() + logger.info("Database schema initialized.") + + repo = Repository() + llm = LLMClient() + + # 3. Create Services + admin_bot = AdminBotService(repo=repo) + ai_processor = AIProcessor(repo=repo, llm=llm) + + # Wrap AI processor to automatically push reviewed posts to admin review channel + original_process_post = ai_processor.process_post + async def process_and_notify(post_id: int): + post = await original_process_post(post_id) + if post: + await admin_bot.send_review_post(post.id) + return post + ai_processor.process_post = process_and_notify + + collector = CollectorService(repo=repo, ai_processor=ai_processor) + publisher = PublisherService(repo=repo) + + # 4. Start all services + await admin_bot.start() + await collector.start() + 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 # Windows or specific platforms + + 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 close_db_pool() + logger.info("Copykar cleanly shut down.") + +if __name__ == "__main__": + asyncio.run(main())