Spaces:
Runtime error
Runtime error
Commit History
19 days ago
-
feat(deploy): configurer le deploiement sur Hugging Face Spaces (Gradio/FastAPI)
8272a44
-
feat: deployment on free tiers, object-storage documents, and email
Enables the project to run on a free hosting tier — ephemeral disk, managed Postgres behind a connection pooler, no outbound SMTP — and adds the password reset flow that was previously a dead end. Two blocking deployment bugs, both reproduced rather than deduced: DATABASE_URL with ?sslmode=require TypeError: connect() got an unexpected keyword argument 'sslmode' SQLAlchemy's asyncpg dialect forwards unknown query parameters straight to asyncpg.connect(), whose signature accepts neither sslmode nor channel_binding and has no **kwargs. The failure surfaces only on the first database access, long after an apparently successful start — and that is exactly the URL the "copy" buttons of managed Postgres providers hand out, and what .env.example recommended. Settings now refuse such a URL at load time, naming PGSSLMODE as the remedy. alembic/env.py, swapping asyncpg for psycopg2 but keeping the query string ProgrammingError: invalid dsn: invalid URI query parameter prepared_s…6429ad3
-
fix(qualite): ruff devient une vraie barriere, et trouve un schema mort et casse
Ruff tournait sans jeu de regles declare : 1332 signalements, dont 98 faux positifs sur le motif `Depends()` de FastAPI et 615 modernisations de style. Un controle que personne ne peut passer n'est pas un controle. Le jeu retenu ne garde que ce qui signale un defaut reel (F, E4, E7, E9, I, RUF100), avec des exceptions nommees la ou l'ordre des imports EST la protection : env.py doit poser sys.path avant d'importer les modeles, conftest doit surcharger DATABASE_URL avant d'importer l'application. Ce que le controle a alors trouve : - UN SCHEMA MORT ET CASSE. `LawDetailResponse` existait deja, exposant `List[ArticleResponse]`. Il n'etait branche sur aucune route, et il etait doublement inutilisable : ArticleResponse porte le CONTENU integral de chaque article — pour le Code Minier, 166 Ko servis deux fois — et son `number` etait plafonne a 20 caracteres alors que la colonne en fait 64 depuis qu'elle accueille « QUATRE-VINGT-DIX-SEPTIEME ». Le plafond du schema est corrige, et…7435134 -
refactor: retirer 165 Mo de dependances mortes et dix scripts a usage unique
DEPENDANCES scikit-learn et joblib : ZERO occurrence dans tout le depot depuis la suppression du classifieur ML. Avec scipy qu'ils entrainent, ils pesaient 165 Mo dans l'image pour rien. Le classement de domaine est fait par des regles depuis legal_domain_classifier.py. SCRIPTS Sept scripts a usage unique, sans argparse, avec `law_id = 1` code en dur et aucun garde `__main__` — donc executables au simple import. Quatre d'entre eux etaient DESTRUCTIFS sans confirmation : force_clean_extract, reextract_ constitution, reextract_pdfplumber effacaient les articles de la loi 1. reprocess_law.py portait en plus un file_id code en dur ; il figurait dans un plan de suppression precedent et n'avait pas ete supprime. Trois scripts de maintenance des categories (add_category_icons, update_category_icons, cleanup_categories) sont perimes par la migration 007, qui possede desormais les 14 domaines avec leurs icones et le verifie par assertion. Les executer se battrait contre elle. reset_databas…d41abd1 -
fix(chat): la sonde mentait, le 503 n'etait pas rattrape, la reflexion fuyait
`GET /api/v1/rag/health` annoncait `llm: unhealthy` en permanence. Quatre causes distinctes, toutes mesurees. 1. LA SONDE ETAIT FAUSSE. Elle interrogeait le modele avec `max_output_tokens=10`. Les modeles a raisonnement consomment ce budget en reflexion interne : `response.text` revenait vide et la sonde concluait « en panne ». Mesure sur gemini-3-flash-preview, gemini-3.5-flash et gemini-flash-latest : les trois echouaient a 10 jetons, les trois repondaient a 512. La sonde lit desormais `finish_reason` et distingue « budget epuise » de « service injoignable ». 2. LE 503 N'ETAIT PAS RATTRAPE. « This model is currently experiencing high demand » revient par salves de quelques secondes sur le palier gratuit. `GeminiServiceError` etait levee en trois endroits et attrapee NULLE PART — l'import cense la traiter dormait, inutilise, en tete de rag_service. Trois tentatives a delai croissant absorbent la salve ; au-dela, un 503 HTTP avec Retry-After remplace …092315b
-
feat(search): retrieval au niveau chunk, embeddings 1536 indexables
La recherche travaillait au niveau document et ne pouvait pas etre indexee. 1. Niveau chunk. postgres_search_service appliquait un SELECT DISTINCT ON (law_id) ... ORDER BY law_id : les articles etaient ecrases a un par loi, et l'ordre transmis a la fusion RRF n'etait plus celui de la pertinence mais celui des identifiants. Cote semantique, la distance etait calculee par article puis passee a func.max() + GROUP BY Law.* : l'article gagnant etait jete, le resultat sortait avec matched_articles vide, highlights vide et content nul — soit aucun texte pour le prompt. Nouveau schema ChunkResult, une ligne par article, avec son numero, son titre, sa section, sa page et son contenu integral. SearchResult est inchangee champ pour champ et desormais DERIVEE des chunks : le front n'a rien a changer et recoit enfin des matched_articles remplis. SearchResponse.chunks est additif, avec un defaut, donc les reponses deja en cache se deserialisent encore. 2. Filtre…72be68d
-
Etape 2 : bugs independants du reste (auth et schema non touches)
Corriges avant l'auth pour que le commit d'authentification ne porte que sur l'authentification. Toujours casses, desormais reparés : - database.py : health_check_db executait la chaine brute "SELECT 1", refusee par SQLAlchemy 2. L'exception etait avalee -> GET /admin/system declarait la base en panne EN PERMANENCE. - rag_service.py : SYSTEM_PROMPTS est indexe par langue, pas par persona. SYSTEM_PROMPTS["citoyen"] levait KeyError a chaque appel -> /rag/ask/stream n'a jamais rien renvoye d'autre qu'une erreur. Remplace par get_system_prompt(persona, language), deja utilise en non-streaming. - rag_service.py + rag.py : joinedload sur une collection sans .unique() -> InvalidRequestError. Toute requete portant un session_id existant echouait, et GET /rag/conversations/{id} renvoyait toujours 500. - 4 endpoints inatteignables, masques par une route parametree declaree avant (FastAPI resout dans l'ordre) : /upload/health (404), /categories/health (422), /personas/health (4…016376a
-
chore: initial standalone backend for JuriX API (Render)
9cf9a2a