search.py 3.07 KB
"""
Search API routes.
"""

from fastapi import APIRouter, HTTPException, Query
from typing import Optional

from ..models import (
    SearchRequest,
    ImageSearchRequest,
    SearchResponse,
    DocumentResponse,
    ErrorResponse
)

router = APIRouter(prefix="/search", tags=["search"])


@router.post("/", response_model=SearchResponse)
async def search(request: SearchRequest):
    """
    Execute text search query.

    Supports:
    - Multi-language query processing
    - Boolean operators (AND, OR, RANK, ANDNOT)
    - Semantic search with embeddings
    - Custom ranking functions
    - Filters and aggregations
    """
    from fastapi import Request as FastAPIRequest
    req: FastAPIRequest = None

    try:
        # Get searcher from app state
        from main import get_searcher
        searcher = get_searcher()

        # Execute search
        result = searcher.search(
            query=request.query,
            size=request.size,
            from_=request.from_,
            filters=request.filters,
            enable_translation=request.enable_translation,
            enable_embedding=request.enable_embedding,
            enable_rerank=request.enable_rerank,
            min_score=request.min_score
        )

        # Convert to response model
        return SearchResponse(
            hits=result.hits,
            total=result.total,
            max_score=result.max_score,
            took_ms=result.took_ms,
            aggregations=result.aggregations,
            query_info=result.query_info
        )

    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))


@router.post("/image", response_model=SearchResponse)
async def search_by_image(request: ImageSearchRequest):
    """
    Search by image similarity.

    Uses image embeddings to find visually similar products.
    """
    try:
        from main import get_searcher
        searcher = get_searcher()

        # Execute image search
        result = searcher.search_by_image(
            image_url=request.image_url,
            size=request.size,
            filters=request.filters
        )

        return SearchResponse(
            hits=result.hits,
            total=result.total,
            max_score=result.max_score,
            took_ms=result.took_ms,
            aggregations=result.aggregations,
            query_info=result.query_info
        )

    except ValueError as e:
        raise HTTPException(status_code=400, detail=str(e))
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))


@router.get("/{doc_id}", response_model=DocumentResponse)
async def get_document(doc_id: str):
    """
    Get a single document by ID.
    """
    try:
        from main import get_searcher
        searcher = get_searcher()

        doc = searcher.get_document(doc_id)

        if doc is None:
            raise HTTPException(status_code=404, detail=f"Document {doc_id} not found")

        return DocumentResponse(id=doc_id, source=doc)

    except HTTPException:
        raise
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))