| |
| """ |
| 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: |
| 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 |
| print(" ✓ python-docx") |
| except ImportError: |
| print(" ✗ python-docx (not installed)") |
| return False |
|
|
| try: |
| from PIL import Image |
| print(" ✓ Pillow") |
| except ImportError: |
| print(" ✗ Pillow (not installed)") |
| return False |
|
|
| try: |
| import openpyxl |
| print(" ✓ openpyxl") |
| except ImportError: |
| print(" ✗ openpyxl (not installed)") |
| return False |
|
|
| try: |
| import xlrd |
| 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() |
| |
| |
| if not check_python_version(): |
| sys.exit(1) |
| |
| |
| setup_directories() |
| |
| |
| 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) |
| |
| |
| exit_code = start_server(args.host, args.port, args.reload) |
| if exit_code != 0: |
| sys.exit(exit_code) |
|
|
| if __name__ == "__main__": |
| main() |
|
|
|
|