| """ |
| Climate-Resilient Agriculture Platform - Unified Entry Point |
| Optimized for Hugging Face Spaces and single-container deployment |
| |
| Starts ALL services: |
| 1. Pest Prediction API (Port 8000) |
| 2. Weather Intelligence API (Port 8001) |
| 3. Water Management API (Port 8002) |
| 4. Master API Server (Port 7860/8003) |
| 5. Telegram Bot (Background Task) |
| """ |
|
|
| import os |
| import sys |
| import asyncio |
| import logging |
| import threading |
| import time |
| from pathlib import Path |
| from dotenv import load_dotenv |
| import uvicorn |
|
|
| |
| load_dotenv() |
|
|
| |
| logging.basicConfig( |
| level=logging.INFO, |
| format="%(asctime)s | %(levelname)s | %(name)s | %(message)s", |
| handlers=[logging.StreamHandler(sys.stdout)] |
| ) |
| logger = logging.getLogger("MasterApp") |
|
|
| |
| Path("data").mkdir(exist_ok=True) |
|
|
| |
| |
| SERVICES = [ |
| ("pest:app", 8000), |
| ("weather:app", 8001), |
| ("water:app", 8002) |
| ] |
|
|
| def run_service(app_path: str, port: int): |
| """Run a sub-service in its own thread""" |
| try: |
| logger.info(f"[STARTUP] Launching {app_path} on port {port}...") |
| uvicorn.run( |
| app_path, |
| host="127.0.0.1", |
| port=port, |
| log_level="error", |
| access_log=False |
| ) |
| except Exception as e: |
| logger.error(f"[ERROR] Service {app_path} failed: {e}") |
|
|
| def run_telegram_bot(): |
| """Runs Telegram bot in its own event loop""" |
| try: |
| logger.info("[BOT] Initializing Telegram bot thread...") |
| |
| |
| time.sleep(5) |
|
|
| loop = asyncio.new_event_loop() |
| asyncio.set_event_loop(loop) |
|
|
| from telegram_bot import main as bot_main |
| |
| |
| if asyncio.iscoroutinefunction(bot_main): |
| loop.run_until_complete(bot_main()) |
| else: |
| bot_main() |
|
|
| except Exception as e: |
| logger.warning(f"[BOT WARNING] Telegram bot failed to initialize: {type(e).__name__}") |
| logger.info(f"[BOT INFO] This is normal if there's no internet/network access") |
| logger.info(f"[BOT INFO] REST APIs will continue working without the bot") |
| |
|
|
| def run_app(): |
| """Starts the full platform""" |
| logger.info("=" * 80) |
| logger.info("🌾 FarmSense MASTER STARTUP") |
| logger.info("=" * 80) |
|
|
| |
| for app_path, port in SERVICES: |
| t = threading.Thread(target=run_service, args=(app_path, port), daemon=True) |
| t.start() |
| logger.info(f"[STARTUP] {app_path} started in background") |
|
|
| |
| time.sleep(2) |
|
|
| |
| bot_thread = threading.Thread( |
| target=run_telegram_bot, |
| name="TelegramBotThread", |
| daemon=True |
| ) |
| bot_thread.start() |
| logger.info("[STARTUP] Telegram Bot started in background") |
|
|
| |
| |
| main_port = int(os.getenv("PORT", 7860)) |
| logger.info(f"[STARTUP] Master API starting on port {main_port}...") |
| |
| uvicorn.run( |
| "api_server:app", |
| host="0.0.0.0", |
| port=main_port, |
| log_level="info", |
| access_log=True, |
| reload=False |
| ) |
|
|
| if __name__ == "__main__": |
| try: |
| run_app() |
| except KeyboardInterrupt: |
| logger.info("[SHUTDOWN] Graceful shutdown initiated") |
| except Exception as e: |
| logger.exception(f"[FATAL ERROR] {e}") |
| sys.exit(1) |
| finally: |
| logger.info("[EXIT] Application stopped") |