Spaces:
Running
Running
| """FastAPI serving entry point. | |
| Usage: | |
| python scripts/serve.py | |
| Configuration is read from configs/default.yaml (all config in one place). | |
| Override model paths via CLI flags if needed: | |
| python scripts/serve.py --student-tower outputs/checkpoints/student_tower_best.keras \\ | |
| --scholarship-tower outputs/checkpoints/scholarship_tower_best.keras | |
| Before starting, pulls latest data + model artifacts from HuggingFace (checks both repos). | |
| """ | |
| import os | |
| os.environ["OMP_NUM_THREADS"] = "1" | |
| os.environ["TOKENIZERS_PARALLELISM"] = "false" | |
| import argparse | |
| import signal | |
| import sys | |
| import uvicorn | |
| from scripts.hf_sync import pull_data_artifacts, pull_model_artifacts | |
| from src.serving.inference_engine import InferenceEngine | |
| from src.serving.api import create_app | |
| def parse_args(): | |
| parser = argparse.ArgumentParser(description="Start recommendation serving API") | |
| parser.add_argument( | |
| "--student-tower", | |
| type=str, | |
| default=None, | |
| help="Override student tower checkpoint path (defaults from config)", | |
| ) | |
| parser.add_argument( | |
| "--scholarship-tower", | |
| type=str, | |
| default=None, | |
| help="Override scholarship tower checkpoint path (defaults from config)", | |
| ) | |
| parser.add_argument("--config", type=str, default="configs/default.yaml") | |
| return parser.parse_args() | |
| def main(): | |
| args = parse_args() | |
| # Pull data + model artifacts from HuggingFace before starting server (blocks until done) | |
| print("Pulling data artifacts...") | |
| pull_data_artifacts(config_path=args.config) | |
| print("Pulling model artifacts...") | |
| pull_model_artifacts(config_path=args.config) | |
| # Build and initialize inference engine (loads models, warms up SBERT, caches scholarships) | |
| # Pass None for paths not provided via CLI — InferenceEngine will resolve defaults from config | |
| print(f"Initializing InferenceEngine (config: {args.config}) ...") | |
| engine = InferenceEngine( | |
| student_tower_path=args.student_tower, | |
| scholarship_tower_path=args.scholarship_tower, | |
| config_path=args.config, | |
| ) | |
| engine.initialize() | |
| # Create FastAPI app bound to this engine instance | |
| app = create_app(engine) | |
| # Start uvicorn server with config-driven host/port | |
| print(f"Starting server on {engine.server_config.server_host}:{engine.server_config.server_port}") | |
| def shutdown(signum, frame): | |
| print("\nShutting down gracefully...") | |
| sys.exit(0) | |
| signal.signal(signal.SIGINT, shutdown) | |
| signal.signal(signal.SIGTERM, shutdown) | |
| try: | |
| uvicorn.run( | |
| app, | |
| host=engine.server_config.server_host, | |
| port=engine.server_config.server_port, | |
| ) | |
| except KeyboardInterrupt: | |
| pass | |
| if __name__ == "__main__": | |
| main() | |