Moteur OpenRouter (google/gemini-3.5-flash-lite), par defaut
Meme consigne, meme encodage, meme repli local que le moteur Gemini direct ; seuls l'adresse, l'authentification (Bearer) et le format de requete (input_audio, compatible OpenAI) changent. Cle : trousseau zonza-openrouter, puis OPENROUTER_API_KEY. Un 200 portant un objet error est traite comme un echec, pas comme une transcription vide. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
+17
-11
@@ -58,8 +58,8 @@ def audio_en_wav(audio, sample_rate):
|
||||
return tampon.getvalue()
|
||||
|
||||
|
||||
def _lire_trousseau():
|
||||
"""Clé rangée par `security add-generic-password -s zonza-gemini ...`.
|
||||
def _lire_trousseau(service=SERVICE_TROUSSEAU):
|
||||
"""Clé rangée par `security add-generic-password -s <service> ...`.
|
||||
|
||||
Le trousseau, et non `~/.zshrc` : Zonza est lancée par le Finder, qui ne
|
||||
lit jamais la configuration du shell — une clé exportée dans `.zshrc`
|
||||
@@ -69,7 +69,7 @@ def _lire_trousseau():
|
||||
return None
|
||||
try:
|
||||
sortie = subprocess.run(
|
||||
["security", "find-generic-password", "-s", SERVICE_TROUSSEAU, "-w"],
|
||||
["security", "find-generic-password", "-s", service, "-w"],
|
||||
capture_output=True, text=True, timeout=5,
|
||||
)
|
||||
except Exception:
|
||||
@@ -79,19 +79,25 @@ def _lire_trousseau():
|
||||
return sortie.stdout.strip() or None
|
||||
|
||||
|
||||
def lire_cle(trousseau=None, environ=None):
|
||||
"""La clé du trousseau, sinon GEMINI_API_KEY, sinon None."""
|
||||
trousseau = trousseau or _lire_trousseau
|
||||
def lire_cle(trousseau=None, environ=None, service=SERVICE_TROUSSEAU,
|
||||
variable="GEMINI_API_KEY"):
|
||||
"""La clé du trousseau, sinon la variable d'environnement, sinon None."""
|
||||
trousseau = trousseau or (lambda: _lire_trousseau(service))
|
||||
environ = os.environ if environ is None else environ
|
||||
return trousseau() or environ.get("GEMINI_API_KEY") or None
|
||||
return trousseau() or environ.get(variable) or None
|
||||
|
||||
|
||||
def _envoyer(url, cle, corps, delai_s):
|
||||
"""POST JSON. La clé part en en-tête, jamais dans l'URL (qui finit en journal)."""
|
||||
"""La clé part en en-tête, jamais dans l'URL (qui finit en journal)."""
|
||||
return poster_json(url, {"x-goog-api-key": cle}, corps, delai_s)
|
||||
|
||||
|
||||
def poster_json(url, entetes, corps, delai_s):
|
||||
"""POST JSON ; toute erreur HTTP ou réseau devient une ErreurGemini."""
|
||||
requete = urllib.request.Request(
|
||||
url,
|
||||
data=json.dumps(corps).encode("utf-8"),
|
||||
headers={"Content-Type": "application/json", "x-goog-api-key": cle},
|
||||
headers={"Content-Type": "application/json", **entetes},
|
||||
method="POST",
|
||||
)
|
||||
try:
|
||||
@@ -179,12 +185,12 @@ class TranscripteurAvecRepli:
|
||||
try:
|
||||
self.principal.warmup()
|
||||
except Exception as e:
|
||||
print(f"[gemini] indisponible ({e}) — moteur local chargé en secours")
|
||||
print(f"[api] indisponible ({e}) — moteur local chargé en secours")
|
||||
self._secours_pret()
|
||||
|
||||
def transcrire(self, audio):
|
||||
try:
|
||||
return self.principal.transcrire(audio)
|
||||
except Exception as e:
|
||||
print(f"[gemini] échec ({e}) — transcription locale")
|
||||
print(f"[api] échec ({e}) — transcription locale")
|
||||
return self._secours_pret().transcrire(audio)
|
||||
|
||||
Reference in New Issue
Block a user