| """ |
| Image Similarity Search API with FastAPI and Qdrant - Fixed Access |
| This application provides endpoints for uploading images and searching for similar images |
| using vector embeddings from the CLIP model. Implemented using OOP principles. |
| """ |
|
|
| import uvicorn |
| from fastapi import FastAPI |
| from contextlib import asynccontextmanager |
| import os |
| import ssl |
| from fastapi.middleware.cors import CORSMiddleware |
|
|
| from config import Config |
| from services.embedding_service import ImageEmbeddingModel |
| from services.vector_db_service import VectorDatabaseClient |
| from api.routes import register_routes |
|
|
|
|
| @asynccontextmanager |
| async def lifespan(app: FastAPI): |
| """Lifespan context manager for FastAPI application startup and shutdown events""" |
| |
| vector_db = app.state.vector_db |
| vector_db.ensure_collection_exists() |
| |
| yield |
| |
| |
| |
|
|
|
|
| class ImageSimilarityAPI: |
| """Main application class that orchestrates all components""" |
| |
| def __init__(self): |
| |
| self.config = Config() |
| |
| |
| self.embedding_model = ImageEmbeddingModel(self.config.model_name) |
| self.vector_db = VectorDatabaseClient( |
| self.config.qdrant_url, |
| self.config.qdrant_api_key, |
| self.config.collection_name, |
| self.config.embedding_size |
| ) |
| |
| |
| self.app = FastAPI( |
| title="Image Similarity Search API", |
| description="API for uploading images and searching for similar images using CLIP embeddings", |
| version="1.0.0", |
| lifespan=lifespan |
| ) |
| |
| |
| self.app.add_middleware( |
| CORSMiddleware, |
| allow_origins=["*"], |
| allow_credentials=True, |
| allow_methods=["*"], |
| allow_headers=["*"], |
| ) |
| |
| self.app.state.vector_db = self.vector_db |
| |
| |
| register_routes(self.app, self.embedding_model, self.vector_db) |
| |
| def run(self, use_https=False, cert_file="./certs/cert.pem", key_file="./certs/key.pem"): |
| """Run the FastAPI application with optional HTTPS support |
| |
| Args: |
| use_https: Whether to use HTTPS or plain HTTP |
| cert_file: Path to SSL certificate file |
| key_file: Path to SSL private key file |
| """ |
| host = "0.0.0.0" |
| port = 8000 if not use_https else 8443 |
| |
| ssl_context = None |
| if use_https: |
| |
| if not os.path.exists(cert_file) or not os.path.exists(key_file): |
| print(f"ERROR: SSL certificate files not found at {cert_file} and/or {key_file}") |
| print("Falling back to HTTP. To use HTTPS, please provide valid certificate files.") |
| use_https = False |
| else: |
| |
| ssl_context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH) |
| ssl_context.load_cert_chain(cert_file, key_file) |
| |
| |
| protocol = "https" if use_https else "http" |
| print(f"\n{'='*50}") |
| print(f"Access the API at: {protocol}://{host}:{port}") |
| print(f"Swagger UI available at: {protocol}://{host}:{port}/docs") |
| print(f"ReDoc UI available at: {protocol}://{host}:{port}/redoc") |
| print(f"{'='*50}\n") |
| |
| uvicorn.run( |
| self.app, |
| host=host, |
| port=port, |
| reload=self.config.environment == "development", |
| ssl_certfile=cert_file if use_https else None, |
| ssl_keyfile=key_file if use_https else None |
| ) |
|
|
|
|
| def create_app() -> FastAPI: |
| """Create and return the FastAPI application""" |
| api = ImageSimilarityAPI() |
| return api.app |
|
|
|
|
| if __name__ == "__main__": |
| api = ImageSimilarityAPI() |
| |
| api.run( |
| use_https=False, |
| cert_file="./certs/cert.pem", |
| key_file="./certs/key.pem" |
| ) |