File size: 3,801 Bytes
6a6337e 34c461b 6a6337e | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 | """
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 environment variables
load_dotenv()
# Setup logging
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s | %(levelname)s | %(name)s | %(message)s",
handlers=[logging.StreamHandler(sys.stdout)]
)
logger = logging.getLogger("MasterApp")
# Ensure required directories exist
Path("data").mkdir(exist_ok=True)
# Define services to run
# Format: (module_name, port_number)
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", # Keep logs clean
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...")
# Give services time to start up
time.sleep(5)
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
from telegram_bot import main as bot_main
# If bot_main is async → await it
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")
# Don't crash the app - just continue without the bot
def run_app():
"""Starts the full platform"""
logger.info("=" * 80)
logger.info("🌾 FarmSense MASTER STARTUP")
logger.info("=" * 80)
# 1. Start sub-services in background threads
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")
# 2. Wait a moment for services to bind
time.sleep(2)
# 3. Start Telegram bot in background thread
bot_thread = threading.Thread(
target=run_telegram_bot,
name="TelegramBotThread",
daemon=True
)
bot_thread.start()
logger.info("[STARTUP] Telegram Bot started in background")
# 4. Run Main Master API on port 7860 (Hugging Face Default)
# This remains on the main thread
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") |