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 — types partagés du pipeline2# Author: Simon-Pierre Boucher3# Contact: contact@spboucher.ai45"""Modèles Pydantic partagés entre crawler, parser, classifier, indexer et API."""67from datetime import datetime8from enum import StrEnum910from pydantic import BaseModel, Field111213class ErrorCode(StrEnum):14 DNS = "dns"15 TIMEOUT = "timeout"16 TLS = "tls"17 HTTP_4XX = "http_4xx"18 HTTP_5XX = "http_5xx"19 ROBOTS_DENIED = "robots_denied"20 PARSE_FAILED = "parse_failed"21 UNSUPPORTED_CONTENT = "unsupported_content"22 TOO_LARGE = "too_large"23 DUPLICATE = "duplicate"24 SPAM = "spam"25 NOT_QUEBEC = "not_quebec"26 SSRF_BLOCKED = "ssrf_blocked"27 TOO_MANY_REDIRECTS = "too_many_redirects"28 CONNECTION = "connection"29 OK = "ok"303132class Outcome(StrEnum):33 INDEXED = "indexed"34 DUPLICATE = "duplicate"35 UNCHANGED = "unchanged"36 ERROR = "error"37 NOT_QUEBEC = "not_quebec"38 ROBOTS_BLOCKED = "robots_blocked"39 REDIRECT = "redirect"404142class FetchResult(BaseModel):43 url: str44 final_url: str45 status_code: int | None = None46 error_code: ErrorCode = ErrorCode.OK47 content_type: str | None = None48 charset: str | None = None49 body: bytes | None = None50 etag: str | None = None51 last_modified: str | None = None52 duration_ms: int = 053 redirect_chain: list[str] = Field(default_factory=list)545556class ExtractedLink(BaseModel):57 url: str58 anchor: str = ""59 nofollow: bool = False606162class ParsedPage(BaseModel):63 url: str64 canonical_url: str | None = None65 title: str = ""66 description: str = ""67 body: str = ""68 headings: list[str] = Field(default_factory=list)69 language: str | None = None70 links: list[ExtractedLink] = Field(default_factory=list)71 published_at: datetime | None = None72 modified_at: datetime | None = None73 author: str | None = None74 image_url: str | None = None75 noindex: bool = False76 nofollow_page: bool = False77 structured_hints: list[str] = Field(default_factory=list) # textes JSON-LD/OG utiles au scoring787980class QuebecSignals(BaseModel):81 score: float = 0.082 locations: list[str] = Field(default_factory=list)83 reasons: list[str] = Field(default_factory=list)848586class SearchResult(BaseModel):87 title: str88 url: str89 display_url: str90 snippet: str91 domain: str92 language: str | None = None93 quebec_score: float = 0.094 badges: list[str] = Field(default_factory=list)95 published_at: datetime | None = None969798class SearchResponse(BaseModel):99 query: str100 total: int101 took_ms: int102 page: int103 limit: int104 results: list[SearchResult]105