# nyora-notes-tt -- contournement direct NVIDIA NIM/OpenRouter pour onedrive_vec **Instance auteur** : hermes-tt (Claude, session nyora-notes-tt) **Date** : 2026-08-05 **Tags** : nyora-notes-tt, bifrost, embeddings, nvidia-nim, openrouter **Statut** : valide, backfill en cours --- ## Probleme Le quota gratuit Google (`embed_content_free_tier_requests`, 1000/j sur `gemini-embedding-001`) etait epuise, cassant a la fois le backfill embeddings et la recherche vectorielle en temps reel de `search_onedrive_archive`. Le fix de rotation multi-cles Bifrost (voir `common/bifrost-google-provider-key-rotation.md`) ne resout rien : les 3 cles Google partagent le meme pool de quota. Tentative de bascule vers NVIDIA NIM et OpenRouter (tous deux gratuits, comptes crees le 05/08) **via Bifrost** : echec dans les deux cas, en 404. Confirme comme bugs Bifrost upstream, pas une erreur de config : - NVIDIA NIM : issue GitHub maximhq/bifrost#2356 (ouverte) -- Bifrost ne transmet pas le header `Authorization` a l'API amont quand le provider est en `custom_provider_config.base_provider_type: openai`. - OpenRouter : erreur cote client HTTP Bifrost ("small read buffer" en lisant les headers de reponse), cause exacte non confirmee dans les issues connues. Les deux providers fonctionnent parfaitement en appel DIRECT (sans Bifrost), verifie avec les memes cles. --- ## Solution validee : contournement direct, scope isole a onedrive_vec `notes_vec` (mail, alimentee par `pipeline_processor.py`) et `onedrive_vec` (OneDrive, alimentee par `embed_onedrive_docs.py`) sont deux tables **separees**, toutes deux 768d/Google avant ce fix. Decision : ne toucher QUE `onedrive_vec` -- `notes_vec` reste sur Google/Bifrost (768d), fonctionne deja, aucune raison de la casser aujourd'hui. **Modele choisi** : `nvidia/llama-nemotron-embed-vl-1b-v2` (2048d), disponible IDENTIQUE (memes poids) sur NVIDIA NIM et sur OpenRouter (OpenRouter route ce modele gratuit directement vers l'infra NVIDIA -- "hosted by one provider"). Consequence utile : les deux sources produisent le MEME espace vectoriel, donc un vrai repli (pas deux embeddings incompatibles a ne jamais mixer). **Code** (`embed_onedrive_docs.py` et nouvelle fonction `generate_onedrive_embedding` dans `mcp_server.py`, strictement separee de `generate_gemini_embedding` qui reste utilisee par `search_mail_memory`) : ```python NVIDIA_NIM_API_KEY = os.getenv("NVIDIA_NIM_API_KEY", "") OPENROUTER_API_KEY = os.getenv("OPENROUTER_API_KEY", "") EMBEDDING_MODEL = "nvidia/llama-nemotron-embed-vl-1b-v2" EMBEDDING_DIMENSIONS = 2048 def get_embedding(text): text = text[:8000] if NVIDIA_NIM_API_KEY: try: resp = httpx.post( "https://integrate.api.nvidia.com/v1/embeddings", headers={"Authorization": f"Bearer {NVIDIA_NIM_API_KEY}"}, json={"model": EMBEDDING_MODEL, "input": [text], "input_type": "passage"}, timeout=30, ) resp.raise_for_status() vec = resp.json()["data"][0]["embedding"] if len(vec) == EMBEDDING_DIMENSIONS: return vec except Exception: pass # repli OpenRouter if OPENROUTER_API_KEY: resp = httpx.post( "https://openrouter.ai/api/v1/embeddings", headers={"Authorization": f"Bearer {OPENROUTER_API_KEY}"}, json={"model": EMBEDDING_MODEL, "input": text}, timeout=30, ) resp.raise_for_status() return resp.json()["data"][0]["embedding"] ``` **Piege NVIDIA NIM specifique** : le parametre `input_type` (`"query"` ou `"passage"`) est requis par leurs modeles NV-Embed*, absent chez OpenRouter -- mis uniquement sur l'appel NVIDIA direct. **Migration schema** : `onedrive_vec` (`vec0`, dimension figee a la creation) recree en 2048d, perte des 1781 vecteurs 768d existants (non recuperables, mauvais espace vectoriel de toute facon) -- backfill relance depuis zero sur 6648 documents processed, rythme observe ~1/s (~2h estimees), aucune erreur constatee sur le premier lot. **Secrets** : cles dans `/volume1/docker/nyora-notes-tt/.env` (`NVIDIA_NIM_API_KEY`, `OPENROUTER_API_KEY`) -- PAS via Bifrost pour cet usage precis, contournement volontaire tant que #2356 n'est pas corrige upstream. --- ## Verification ```bash docker exec nyora-notes-tt python3 -c " import sqlean as sqlite3, sqlite_vec c = sqlite3.connect('/app/nyora-notes-tt.db') c.enable_load_extension(True); sqlite_vec.load(c); c.enable_load_extension(False) print(c.execute('SELECT COUNT(*) FROM onedrive_vec').fetchone()[0]) " ``` --- ## Reste a faire - Laisser le backfill se terminer (~2h, tourne en arriere-plan via `docker exec -d`, resumable si interrompu -- rescanner simplement au redemarrage, la logique "deja embedde" se base sur les rowid presents). - Reevaluer le retour a Bifrost si/quand #2356 est corrige upstream (verifier changelog maximhq/bifrost). - Auto-actualisation OneDrive (point 1) et ingestion mail continue (point 2) : design discute mais pas implemente -- voir prompt de reprise en session suivante. ## References - Issue Bifrost NVIDIA NIM : https://github.com/maximhq/bifrost/issues/2356 - Runbook associe : `common/bifrost-google-provider-key-rotation.md`, `hermes-tt/nyora-notes-tt-3-bugs-05-08-2026.md`