---
title: "Google Cloud TTS vs AI Studio TTS — Separate Services, Different Quotas"
aliases: [google-tts-migration, cloud-tts-ai-studio, gemini-tts-quota]
tags: [gcp, tts, google-cloud, ai-studio, iam, python, video-accessibility]
sources:
  - "daily/2026-05-08.md"
created: 2026-05-08
updated: 2026-05-08
---

# Google Cloud TTS vs AI Studio TTS — Separate Services, Different Quotas

Gemini TTS on AI Studio API (`generativelanguage.googleapis.com`, `GEMINI_API_KEY`) has a 10 RPM preview quota regardless of payment tier. The production quota lives on the **Google Cloud TTS API** (`texttospeech.googleapis.com`, service account). They are completely separate services — migrating requires switching client library and IAM, not just upgrading the key tier.

## The Core Separation

| | AI Studio TTS | Google Cloud TTS |
|---|---|---|
| Endpoint | `generativelanguage.googleapis.com` | `texttospeech.googleapis.com` |
| Auth | `GEMINI_API_KEY` | Service account (JSON key) |
| Quota | 10 RPM preview (fixed) | Production-grade, scalable |
| Client lib | `google-generativeai` | `google-cloud-texttospeech` |
| Model | Gemini TTS via genai | `gemini-2.5-pro-tts` in VoiceSelectionParams |

## Migration Pattern

```python
# OLD — AI Studio (10 RPM preview quota)
from google import generativeai as genai
genai.configure(api_key=os.getenv("GEMINI_API_KEY"))
# ... genai TTS calls

# NEW — Google Cloud TTS (production quota)
from google.cloud import texttospeech

client = texttospeech.TextToSpeechClient()
# auth via GOOGLE_APPLICATION_CREDENTIALS env var → service account JSON

voice = texttospeech.VoiceSelectionParams(
    language_code="en-US",
    model_name="gemini-2.5-pro-tts"  # requires >= 2.36.0 — see below
)
audio_config = texttospeech.AudioConfig(
    audio_encoding=texttospeech.AudioEncoding.MP3
)
synthesis_input = texttospeech.SynthesisInput(text=text)

response = client.synthesize_speech(
    input=synthesis_input,
    voice=voice,
    audio_config=audio_config
)
audio_bytes = response.audio_content
```

## `model_name` Silent Ignore in Old Versions

`google-cloud-texttospeech < 2.28` accepts `model_name` in `VoiceSelectionParams` without raising an error — it silently ignores the field and falls back to the default voice.

```bash
# Check installed version
pip show google-cloud-texttospeech
# Version: 2.27.0  ← silent ignore territory

# Fix: bump in pyproject.toml
# google-cloud-texttospeech = ">=2.36.0"

# Regenerate lock file without updating other packages
poetry lock --no-update

# Rebuild Docker container (not just restart)
docker compose build backend && docker compose up -d backend
```

Diagnostic: TTS audio plays but with a generic default voice, not the Gemini model. No error in logs.

## IAM Requirement — `roles/aiplatform.user`

Even though Cloud TTS is not Vertex AI, accessing Gemini models through Cloud TTS requires the `roles/aiplatform.user` IAM role on the GCP project.

**Error signal:**
```
403 PermissionDenied: aiplatform.endpoints.predict
```

**Fix:** Grant the role in GCP IAM console → IAM & Admin → Grant access → add `roles/aiplatform.user` to the service account.

## Environment Variable Setup

```bash
# Service account JSON key path
GOOGLE_APPLICATION_CREDENTIALS=/app/service-account.json

# Or inline for Docker compose
volumes:
  - ./service-account.json:/app/service-account.json:ro
environment:
  - GOOGLE_APPLICATION_CREDENTIALS=/app/service-account.json
```

## Related Concepts

- [[wiki/concepts/pydub-ffmpeg-silent-dependency]] — another audio pipeline silent dependency issue
- [[wiki/concepts/lameenc-bytearray-gcs-upload]] — GCS audio upload gotcha

## Sources

- [[daily/2026-05-08.md]] — Discovered during video-accessibility TTS migration from AI Studio to Cloud TTS; 5 concurrent bugs fixed in the same session
