#!/usr/bin/env python3 """ GAKR AI Chatbot - Startup Script Handles environment setup and server startup """ import os import sys import subprocess import argparse import socket from pathlib import Path def configure_output_encoding(): """Avoid UnicodeEncodeError on non-UTF terminal encodings.""" try: if hasattr(sys.stdout, "reconfigure"): sys.stdout.reconfigure(encoding="utf-8", errors="replace") if hasattr(sys.stderr, "reconfigure"): sys.stderr.reconfigure(encoding="utf-8", errors="replace") except Exception: pass def print_banner(): """Print startup banner""" print(""" +--------------------------------------------------------------+ | | | GAKR AI Chatbot Platform | | | | Powered by NVIDIA API + Web Search | | | +--------------------------------------------------------------+ """) def check_python_version(): """Check if Python version is compatible""" if sys.version_info < (3, 8): print("❌ Error: Python 3.8 or higher is required") print(f" Current version: {sys.version_info.major}.{sys.version_info.minor}") return False print(f"✅ Python {sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}") return True def check_dependencies(): """Check if required dependencies are installed""" backend_dir = Path(__file__).parent / "backend" req_file = backend_dir / "requirements.txt" if not req_file.exists(): print("⚠️ requirements.txt not found") return False print("📦 Checking dependencies...") # Try to import key modules try: import fastapi print(" ✓ FastAPI") except ImportError: print(" ✗ FastAPI (not installed)") return False try: import httpx print(" ✓ httpx") except ImportError: print(" ✗ httpx (not installed)") return False try: import PyPDF2 print(" ✓ PyPDF2") except ImportError: print(" ✗ PyPDF2 (not installed)") return False try: import docx # noqa: F401 print(" ✓ python-docx") except ImportError: print(" ✗ python-docx (not installed)") return False try: from PIL import Image # noqa: F401 print(" ✓ Pillow") except ImportError: print(" ✗ Pillow (not installed)") return False try: import openpyxl # noqa: F401 print(" ✓ openpyxl") except ImportError: print(" ✗ openpyxl (not installed)") return False try: import xlrd # noqa: F401 print(" ✓ xlrd") except ImportError: print(" ⚠️ xlrd (not installed, legacy .xls parsing disabled)") try: import pytesseract try: pytesseract.get_tesseract_version() print(" ✓ pytesseract + Tesseract OCR") except Exception: print(" ⚠️ pytesseract installed, but Tesseract OCR binary not detected") except ImportError: print(" ⚠️ pytesseract (not installed, image OCR disabled)") except Exception as e: print(f" ⚠️ pytesseract unavailable ({type(e).__name__}: {e})") print(" Image OCR disabled; server will continue without OCR.") return True def setup_directories(): """Create necessary directories""" base_dir = Path(__file__).parent dirs = [ base_dir / "data", base_dir / "data" / "uploads" ] for d in dirs: d.mkdir(parents=True, exist_ok=True) print("✅ Directories initialized") def is_port_available(host, port): """Check whether a TCP port is available for binding""" bind_host = host if host and host != "0.0.0.0" else "0.0.0.0" with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock: sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) try: sock.bind((bind_host, int(port))) return True except OSError: return False def find_available_port(host, start_port, max_tries=50): """Find first available port starting from start_port""" port = int(start_port) for _ in range(max_tries): if is_port_available(host, port): return port port += 1 return None def start_server(host, port, reload): """Start the FastAPI server""" backend_dir = Path(__file__).parent / "backend" requested_port = int(port) selected_port = find_available_port(host, requested_port) if selected_port is None: print(f"\n❌ No available port found from {requested_port} to {requested_port + 49}") print(" Stop existing server processes or pass a different --port value.") return 1 if selected_port != requested_port: print(f"\n⚠️ Port {requested_port} is already in use. Switching to port {selected_port}.") port = selected_port print(f"\n🚀 Starting server on http://{host}:{port}") print(" Press Ctrl+C to stop\n") cmd = [ sys.executable, "-m", "uvicorn", "main:app", "--host", host, "--port", str(port), ] if reload: cmd.append("--reload") try: result = subprocess.run(cmd, cwd=backend_dir) return result.returncode except KeyboardInterrupt: print("\n\n👋 Server stopped") return 0 def main(): configure_output_encoding() parser = argparse.ArgumentParser(description="GAKR AI Chatbot Server") default_port = int(os.getenv("PORT", "7860")) parser.add_argument("--host", default="0.0.0.0", help="Host to bind (default: 0.0.0.0)") parser.add_argument("--port", type=int, default=default_port, help=f"Port to run on (default: {default_port})") parser.add_argument("--reload", action="store_true", help="Enable auto-reload for development") parser.add_argument("--skip-checks", action="store_true", help="Skip dependency checks") args = parser.parse_args() print_banner() # Check Python version if not check_python_version(): sys.exit(1) # Setup directories setup_directories() # Check dependencies if not args.skip_checks: if not check_dependencies(): print("\n❌ Please install dependencies first:") print(" pip install -r backend/requirements.txt") sys.exit(1) # Start server exit_code = start_server(args.host, args.port, args.reload) if exit_code != 0: sys.exit(exit_code) if __name__ == "__main__": main()