Spaces:
Runtime error
Runtime error
Commit History
22 days ago
-
feat(embeddings): voyage-4-large remplace EmbeddingGemma (API Voyage, halfvec 1024)
Mesure sur tout le corpus (32 303 morceaux) et le jeu relu de 102 questions : en recherche dense, MRR@20 0,758 contre 0,537 pour EmbeddingGemma en francais, 0,680 contre 0,537 en anglais. Par le chemin du chat lui-meme (mots-cles en plein texte, question entiere vectorisee, 8 extraits envoyes au modele), l'article attendu figure parmi les extraits 92 % du temps en francais contre 61 % avec Gemma (MRR@8 0,504 contre 0,336), et 87 % en anglais contre 56 % (0,538 contre 0,282). Vectoriser la question entiere plutot que ses mots-cles gagne a lui seul +0,087 de MRR@8 en francais [IC 95 % +0,035 ; +0,143] et +0,127 en anglais [+0,067 ; +0,191]. - embedding_service.py : VoyageProvider (httpx, connexion gardee : 0,42 s par question contre 1,14 s avec une connexion neuve). Son corps de requete reproduit les vecteurs deja calcules du corpus : un test voyage_live le prouve, cosinus >= 0,999 sur deux questions et deux documents. Lots de 900 textes et 90 000 jetons estimes, refus definit…57c8117
27 days ago
-
fix(journal): les journaux de l'application sortent, sans le jeton du WebSocket
- Aucun gestionnaire n'etait pose sur les loggers de l'application : uvicorn ne configure que les siens, et Python ne garde que WARNING. Le journal de chaque appel Mistral ou Groq (fin, jetons, duree) n'apparaissait nulle part, ni en developpement ni dans docker compose logs. - uvicorn journalise chaque WebSocket avec son URL entiere, par son journal d'erreurs que --no-access-log ne coupe pas : le jeton d'administration (?token=...) y passait en clair. Il est masque. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>b229001
-
fix(deploiement): corrections de la revue avant le premier deploiement
Issus d'une revue adversariale des fichiers de deploiement : - deployer.sh passait la fin du deploiement a `ssh ... bash -s` sur l'entree standard : le premier `docker compose exec` (qui garde l'entree ouverte) avalait la suite du script. Rien apres l'attente de la base ne s'executait — ni restauration, ni build, ni demarrage — et le script finissait sans erreur. La fin vit dans demarrer.sh, un fichier lance sur la VM ; chaque exec sans entree recoit </dev/null. - La restauration initiale ne regardait que l'existence de la table laws : un seul demarrage de l'API (qui cree le schema) la faisait sauter pour toujours, sans un mot. Elle se fait si la base n'a AUCUNE loi, dans une base recreee, avec --exit-on-error. - Le dump embarquait les comptes de developpement (et leurs mots de passe d'essai), conversations, jetons et caches : joignables depuis internet. Il n'en garde que le schema ; demarrer.sh cree l'administrateur de production (ADMIN_EMAIL, ADMIN_PASSWORD). -…2afa5a5 -
fix(imports): un seul choix du fournisseur, et chaque fichier importe ce qu'il utilise
La comparaison et l'explication d'article lisaient settings.LLM_PROVIDER sans importer settings. Rien n'echouait a l'import : le nom n'etait resolu qu'a la construction du service, donc chaque /compare et chaque /explain-article repondait 500 des qu'aucune doublure n'etait injectee — en production, jamais dans les tests. Le choix du fournisseur, recopie trois fois, vit desormais dans app/services/llm.py : get_llm_service() rend Mistral ou Gemini selon LLM_PROVIDER, et les erreurs sont regroupees par nature (ERREURS_QUOTA, ERREURS_SATURATION, ERREURS_LLM), quel que soit le fournisseur. Les messages « Please set up Gemini API » deviennent neutres. ruff rendait 18 signalements (2 noms inconnus, 14 imports inutiles, 2 blocs mal ordonnes) ; il en rend zero. Les __import__("sqlalchemy") et __import__("datetime") deviennent de vrais imports. Garde permanente, tests/test_qualite/test_imports.py : ruff doit sortir a zero sur app, scripts, tests et alembic, et chaque module de app doit s'impo…e77f0a8
-
feat(embeddings): EmbeddingGemma par defaut, et une panne qui se voit
EMBEDDING_PROVIDER vaut desormais gemma : les embeddings sont calcules en local, gratuitement, et Gemini ne sert plus qu'au chat. `gemini` reste disponible, a 768 dimensions lui aussi. LA PANNE LA PLUS PROBABLE DU SEMANTIQUE ETAIT LA SEULE INVISIBLE. Modele absent, fichier tronque, vecteurs d'un autre modele : dans chacun de ces cas, la recherche hybride avalait l'erreur et repondait en plein texte seul, pendant que GET /search/health disait « healthy ». Trois filets : - le modele est charge AU DEMARRAGE, et une question est reellement encodee. Un echec n'empeche pas l'API de demarrer — plein texte, chat et comptes s'en passent — mais il est journalise, et le service est ECARTE : garde, il retenterait de charger 300 Mo a chaque question ; - la sante passe en « degraded » si le service manque, si des vecteurs d'un AUTRE fournisseur sont en base (leurs cosinus ne veulent rien dire), ou si aucun vecteur n'est exploitable alors qu'il y a des articles a vectoriser. Ce dernier …7a1d560
-
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
-
Etape 4 : harnais de tests sur PostgreSQL reel
Le conftest utilisait SQLite en memoire. C'etait intenable : le coeur du produit est du SQL PostgreSQL brut (websearch_to_tsquery, ts_rank_cd, DISTINCT ON, = ANY(), similarity(), extension vector) et les objets dont il depend (search_vector, index GIN, triggers, query_cache, embedding_cache) n'existent QUE dans les migrations, jamais dans Base.metadata. create_all ne pouvait pas produire un schema utilisable — une suite verte sur SQLite aurait certifie du code qui renvoie 500 en production. - conftest reecrit : moteur de session construit par `alembic upgrade head` sur une vraie base, isolation par TRUNCATE ... RESTART IDENTITY CASCADE. L'isolation transactionnelle a ete essayee et documentee comme ecartee : les SAVEPOINT du dialecte asyncpg refusent de s'executer dans une transaction ouverte manuellement, et rollback_only casse les tests qui relisent leurs propres ecritures. - Marquage `integration` automatique selon les fixtures demandees, plutot que declare dans 21 fich…0fdac35
-
chore: initial standalone backend for JuriX API (Render)
9cf9a2a