SPB Git forge

spb/api-ka

Public

API-KA — plateforme centrale : collecte quotidienne des 8 services KA, historisation append-only et API publique sur www.api-ka.com

48commits 1branches 0releases
5.9 MBsize
maindefault branch
19 days agolast push
Python 60.9% HTML 21% TypeScript 7.3% JavaScript 5.2% CSS 4.8% Shell 0.8%
4.1 KB · 122 lines python
Raw Blame History
1# ============================================2# Projet   : API-KA3# Fichier  : src/api/routes/search.py4# Node     : m3u96b5# Author   : Simon-Pierre Boucher6# Contact  : contact@spboucher.ai7# Date     : 2026-08-238# ============================================9"""Routes /api/v1/search et /api/v1/suggest — recherche Trouve·Ka.1011Proxy public du moteur de recherche interne du Groupe KA (www.trouve-ka.com) :12API-KA relaie les requêtes vers le moteur amont et renvoie ses résultats dans13l'enveloppe uniforme ``{success, data, meta}`` de la plateforme.14"""1516from __future__ import annotations1718from typing import Any1920import httpx21from fastapi import APIRouter, HTTPException, Query2223from src.api.routes import envelope24from src.config import get_settings2526router = APIRouter(prefix="/api/v1", tags=["search"])2728# Le moteur Trouve·Ka plafonne `limit` à 50 — même plafond ici.29MAX_LIMIT = 50303132async def _get(url: str, params: dict[str, Any]) -> Any:33    """GET JSON vers le moteur Trouve·Ka (mêmes réglages que le proxy agent)."""34    async with httpx.AsyncClient(timeout=12, follow_redirects=True) as cx:35        r = await cx.get(url, params=params)36        r.raise_for_status()37        return r.json()383940@router.get("/search")41async def search(42    q: str = Query(43        ..., min_length=1, max_length=200, description="Termes de recherche"44    ),45    page: int = Query(1, ge=1, description="Numéro de page (défaut 1)"),46    limit: int = Query(47        10, ge=1, le=MAX_LIMIT, description="Résultats par page (défaut 10, max 50)"48    ),49    language: str | None = Query(50        None, pattern="^(fr|en)$", description="Langue des résultats : fr ou en"51    ),52    site: str | None = Query(53        None,54        max_length=253,55        description="Limiter à un site — domaine, ex. www.lou-ka.com",56    ),57    category: str | None = Query(None, description="Catégorie Trouve·Ka"),58    freshness: str | None = Query(59        None,60        pattern="^(day|week|month|year)$",61        description="Fraîcheur : day, week, month ou year",62    ),63) -> dict[str, Any]:64    """Recherche web québécoise propulsée par le moteur Trouve·Ka.6566    Proxifie ``GET https://www.trouve-ka.com/api/search`` (moteur de recherche67    interne du Groupe KA) : résultats classés (sémantique + rerank), filtrables68    par langue, site, catégorie et fraîcheur. ``data`` contient les résultats69    (``title``, ``url``, ``snippet``, ``domain``, ``quebec_score``…) ; ``meta``70    expose ``total``, ``took_ms`` et les requêtes reliées (``related``).71    """72    params: dict[str, Any] = {"q": q, "page": page, "limit": limit}73    for key, value in (74        ("language", language),75        ("site", site),76        ("category", category),77        ("freshness", freshness),78    ):79        if value:80            params[key] = value81    try:82        data = await _get(get_settings().trouveka_search_url, params)83    except httpx.HTTPError as exc:84        raise HTTPException(85            status_code=502, detail=f"Moteur Trouve·Ka injoignable : {exc}"86        ) from exc87    return envelope(88        data.get("results", []),89        total=data.get("total"),90        page=data.get("page", page),91        limit=data.get("limit", limit),92        extra_meta={93            "query": data.get("query", q),94            "took_ms": data.get("took_ms"),95            "related": data.get("related", []),96            "source": "trouve-ka",97        },98    )99100101@router.get("/suggest")102async def suggest(103    q: str = Query(104        ...,105        min_length=2,106        max_length=200,107        description="Préfixe de recherche (2 caractères minimum)",108    ),109) -> dict[str, Any]:110    """Suggestions de recherche (autocomplétion) du moteur Trouve·Ka.111112    Proxifie ``GET https://www.trouve-ka.com/api/suggest`` : renvoie dans113    ``data`` la liste des suggestions de requêtes pour le préfixe donné.114    """115    try:116        data = await _get(get_settings().trouveka_suggest_url, {"q": q})117    except httpx.HTTPError as exc:118        raise HTTPException(119            status_code=502, detail=f"Moteur Trouve·Ka injoignable : {exc}"120        ) from exc121    return envelope(data.get("suggestions", []), extra_meta={"source": "trouve-ka"})122