SPB Git forge

spb/doc-api

Public
2commits 1branches 0releases
15.7 MBsize
maindefault branch
13 days agolast push
Python 88.3% TypeScript 7.6% Shell 4.1%
1.9 KB · 38 lines python
Raw Blame History
1#!/usr/bin/env python32"""Streaming TTS (gemini-3.1-flash-tts-preview only) via streamGenerateContent?alt=sse — raw HTTP through scripts/live.py.34STATUS: LIVE_VERIFIED 2026-09-18: 26 SSE events in 1.0 s for "Say: OK"; each `data:` event carries one inlineData chunk5        (first 1,920 bytes = 40 ms), last event has finishReason STOP + usageMetadata (50 audio tokens). Free tier.6Run:  .venv/bin/python examples/gemini/speech/tts_stream.py "Say: OK"7"""8from __future__ import annotations910import base6411import json12import sys13import wave14from pathlib import Path1516ROOT = Path(__file__).resolve().parents[3]17sys.path.insert(0, str(ROOT))18from scripts import live  # noqa: E4021920text = sys.argv[1] if len(sys.argv) > 1 else "Say: OK"21body = {"contents": [{"parts": [{"text": text}]}],22        "generationConfig": {"responseModalities": ["AUDIO"], "speechConfig": {"voiceConfig": {"prebuiltVoiceConfig": {"voiceName": "Kore"}}}}}23st, lines, _ = live.gemini_request("POST", "/v1beta/models/gemini-3.1-flash-tts-preview:streamGenerateContent?alt=sse", body,24                                   stream=True, est_cost_usd=0.001, note="example tts_stream.py")25print("HTTP", st)26pcm = bytearray(); n = 0; last = None27for line in lines:28    if not line.startswith("data:"):29        continue30    ev = json.loads(line[5:]); n += 1; last = ev31    for p in ev.get("candidates", [{}])[0].get("content", {}).get("parts", []):32        if "inlineData" in p:33            pcm += base64.b64decode(p["inlineData"]["data"])34out = ROOT / "tmp-live" / "gemini-tts-stream.wav"35with wave.open(str(out), "wb") as w:36    w.setnchannels(1); w.setsampwidth(2); w.setframerate(24000); w.writeframes(bytes(pcm))37print(f"{n} events, {len(pcm)} PCM bytes ({len(pcm) / 48000:.2f} s) -> {out}; last finishReason={last['candidates'][0].get('finishReason') if last else None}; usage={last.get('usageMetadata') if last else None}")38