sequenceDiagram
autonumber
participant C as Client
participant API as FastAPI Router
participant SS as ImageSearchService
participant Cache as Semantic Cache<br/>(In-Memory Qdrant)
participant EP as EmbeddingProvider<br/>(CLIP / Infinity)
participant VDP as VectorDBProvider<br/>(QdrantClientWrapper)
participant Embed as CLIP / Infinity
participant VDB as Qdrant
C->>+API: GET /search/images?q=red circle&limit=10
Note over API: Parse query params,<br/>create providers via factories
API->>API: create_embedding_provider(config)
API->>API: create_vector_db_provider(config)
API->>+SS: search_images_async(collection, query, limit)
SS->>SS: Validate query (non-empty, limit 1-100)
Note over SS: Step 1: Generate Query Embedding
SS->>+EP: embed_text(query="red circle")
EP->>+Embed: POST /embed {"inputs": ["red circle"]}
Embed-->>-EP: {"embeddings": [[0.123, -0.456, ...]]}
EP-->>-SS: vector[512]
Note over SS: Step 2: Check Semantic Cache
SS->>+Cache: lookup(collection, query_vector, limit)
alt Cache Hit (similarity >= 0.95)
Cache-->>SS: SearchResults (cached)
Note over SS: Return cached results
else Cache Miss
Cache-->>-SS: None
Note over SS: Step 3: Vector Similarity Search
SS->>+VDP: search_async(collection, query_vector, limit=10)
VDP->>+VDB: POST /collections/{name}/points/search
VDB-->>-VDP: [{id, score, payload}, ...]
VDP-->>-SS: SearchResults(items)
Note over SS: Step 4: Store in Cache
SS->>Cache: store(collection, query_vector, query_text, results, limit)
end
SS-->>-API: SearchResults
API->>API: Convert to ImageSearchResponse
API-->>-C: 200 OK<br/>{"query": "red circle",<br/>"results": [...], "total": 10}