| | """ |
| | 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" |
| | ) |