spb/trouve-ka Public
Trouve-KA — moteur de recherche web indépendant, Québec-first. Crawler distribué, index OpenSearch, ranking bilingue, galerie d'images. En prod : www.trouve-ka.com
Python 76.8%
TypeScript 15.7%
SQL 3.9%
Shell 1.4%
CSS 1.3%
Dockerfile 0.7%
1# Trouve-KA — client OpenSearch2# Author: Simon-Pierre Boucher3# Contact: contact@spboucher.ai45"""Client OpenSearch async : création d'index, indexation immédiate, recherche, statut."""67import hashlib8from typing import Any910from opensearchpy import AsyncOpenSearch11from opensearchpy.exceptions import NotFoundError1213from .mapping import INDEX_SETTINGS141516def doc_id_for_url(url: str) -> str:17 """ID de document stable dérivé de l'URL canonique."""18 return hashlib.sha256(url.encode("utf-8")).hexdigest()[:32]192021class SearchCore:22 def __init__(self, search_url: str, index: str):23 self.index = index24 self.client = AsyncOpenSearch(hosts=[search_url], timeout=15, max_retries=2, retry_on_timeout=True)2526 async def close(self) -> None:27 await self.client.close()2829 async def ensure_index(self) -> None:30 if not await self.client.indices.exists(index=self.index):31 await self.client.indices.create(index=self.index, body=INDEX_SETTINGS)3233 async def index_document(self, doc: dict[str, Any]) -> str:34 """Indexation immédiate d'un document (cherchable au prochain refresh, ~1 s)."""35 _id = doc_id_for_url(doc["canonical_url"] or doc["url"])36 await self.client.index(index=self.index, id=_id, body=doc)37 return _id3839 async def update_document(self, url: str, partial: dict[str, Any]) -> None:40 """Mise à jour partielle (enrichissement asynchrone, étapes 2-3)."""41 try:42 await self.client.update(index=self.index, id=doc_id_for_url(url), body={"doc": partial})43 except NotFoundError:44 pass4546 async def delete_document(self, url: str) -> None:47 try:48 await self.client.delete(index=self.index, id=doc_id_for_url(url))49 except NotFoundError:50 pass5152 async def search(self, body: dict[str, Any]) -> dict[str, Any]:53 return await self.client.search(index=self.index, body=body)5455 async def count(self) -> int:56 try:57 res = await self.client.count(index=self.index)58 return res["count"]59 except NotFoundError:60 return 06162 async def ping(self) -> bool:63 try:64 return await self.client.ping()65 except Exception:66 return False67