Deploy the voice service¶
Same shape as Call an LLM → Deploy and RAG → Deploy. The Terraform module composes the E1 baseline and the E2 call-an-llm module; the Helm chart extends the E2 chart's env-var block with STT/TTS keys. Voice does not need its own state store — Azure Speech + Polly are stateless per-call APIs; Transcribe uses S3 for the audio blob.
Official docs verified 2026-08-08
azurerm_cognitive_account(kind = SpeechServices): registry.terraform.io/…/azurerm/latest/docs/resources/cognitive_account- GCP TTS + STT enable via
google_project_service: registry.terraform.io/…/google/latest/docs/resources/google_project_service - AWS Polly + Transcribe require no dedicated Terraform resource — IAM policy on the app role authorizes API calls.
Layout¶
examples/voice/
service/ # composes E2 chat_native + chat_claude
stt.py # provider-picking speech-to-text
tts.py # provider-picking text-to-speech
voice.py # transcribe → E2 chat → synthesize
main.py # FastAPI /voice-turn + /voice-turn-claude
Dockerfile # layers call-an-llm/service alongside voice/service
requirements.txt
chart/ # extends the E2 chart with STT/TTS env
Chart.yaml
values.yaml
templates/
deployment.yaml
service.yaml
serviceaccount.yaml
terraform/
azure/ (module "baseline" + "call_an_llm" + azurerm_cognitive_account speech)
gcp/ (module "baseline" + "call_an_llm" + google_project_service speech+tts)
aws/ (module "baseline" + "call_an_llm" + audio S3 bucket + IAM polly/transcribe policy)
Terraform — compose, don't duplicate¶
module "baseline" {
source = "../../../foundations/azure"
name = var.name
region = var.region
compute = var.compute
}
module "call_an_llm" {
source = "../../../call-an-llm/terraform/azure"
name = var.name
region = var.region
compute = var.compute
azure_openai_base_url = var.azure_openai_base_url
azure_openai_deployment = var.azure_openai_deployment
foundry_claude_deployment = var.foundry_claude_deployment
}
# Azure AI Speech Cognitive account — one resource covers both STT + TTS.
resource "azurerm_cognitive_account" "speech" {
name = "${var.name}-speech"
location = var.region
resource_group_name = module.baseline.resource_group_name
kind = "SpeechServices"
sku_name = "S0"
}
module "baseline" {
source = "../../../foundations/gcp"
project_id = var.project_id
name = var.name
region = var.region
compute = var.compute
}
module "call_an_llm" {
source = "../../../call-an-llm/terraform/gcp"
project_id = var.project_id
name = var.name
region = var.region
compute = var.compute
}
# Enable STT + TTS APIs on the project.
resource "google_project_service" "speech_to_text" {
project = var.project_id
service = "speech.googleapis.com"
}
resource "google_project_service" "text_to_speech" {
project = var.project_id
service = "texttospeech.googleapis.com"
}
module "baseline" {
source = "../../../foundations/aws"
name = var.name
region = var.region
compute = var.compute
}
module "call_an_llm" {
source = "../../../call-an-llm/terraform/aws"
name = var.name
region = var.region
compute = var.compute
eks_oidc_provider_arn = var.eks_oidc_provider_arn
}
# Transcribe needs an S3 bucket for input audio + transcript output.
resource "aws_s3_bucket" "audio" {
bucket = "${var.name}-audio-${data.aws_caller_identity.current.account_id}"
force_destroy = true
}
Helm — env-var extension¶
The E3 chart's env block is bigger; the voice chart re-uses the E2 shape and adds only:
- Azure:
SPEECH_KEY,SPEECH_ENDPOINT,AZURE_TTS_VOICE - GCP:
GCP_TTS_VOICE(STT + TTS use ADC) - AWS:
AWS_POLLY_VOICE,AWS_POLLY_ENGINE,CHIRON_AUDIO_BUCKET
helm upgrade --install voice ./examples/voice/chart \
--set image.repository="…/voice" --set image.tag="v1" \
--set env.CHIRON_PROVIDER="azure" \
--set env.AZURE_TTS_VOICE="en-US-JennyNeural"
Verify (validate-only)¶
for p in azure gcp aws; do
( cd examples/voice/terraform/$p && terraform init -backend=false && terraform validate )
done
helm lint examples/voice/chart
helm template voice examples/voice/chart > /dev/null
python -m compileall examples/voice/service
Live voice needs real STT/TTS credentials; Phase 3 covers billed apply.