Serve call audio through c2-core instead of GCS signed URLs
upload_audio() could only sign a URL when GCP_CREDENTIALS_PATH pointed at a service-account key file. The deployed VM runs on Application Default Credentials with no key file, so every upload silently took the fallback branch and returned a bare gs:// URI. That broke two things at once: * Browsers cannot fetch a gs:// URI, so no recording was ever playable. * _public_url_to_gcs_uri() only matched https://storage.googleapis.com/ and returned None for it, so `if gcs_uri:` in the upload path was always false and transcription never ran. Nothing was logged, which is why this looked like an OpenAI credits problem rather than a storage one. The fallback also interpolated the client-supplied filename instead of the call_id-derived safe name, so the URI did not even name the object written. Calls now store only the canonical gs:// location. A short-lived playback link is minted per read as an HMAC over (call_id, expiry) keyed by SERVICE_KEY, and audio is served from the private bucket by the new /media route. An <audio src> cannot carry an Authorization header, so the link has to be the credential; that router is therefore public with the check done inline, as enrollment.py already does. Signing GCS URLs from the VM would have needed a serviceAccountTokenCreator grant on its own service account — this avoids the IAM change entirely and keeps the bucket private. gcs_uri_for_call() reconstructs the object name from call_id, so recordings made before this fix are reachable again without a data migration. Frontend rows come straight from Firestore via onSnapshot and never see a server-minted field, so CallRow fetches the link lazily on expand. Also removes the last long-lived (1 year) signed URL and the log line that printed it.
This commit is contained in:
@@ -12,9 +12,17 @@ MQTT_DYNSEC_ADMIN_PASS={{ vault_mqtt_dynsec_admin_pass }}
|
||||
|
||||
# No GCP_CREDENTIALS_PATH — the VM uses Application Default Credentials
|
||||
# via the GCE metadata server. The Terraform IAM bindings grant the required roles.
|
||||
# NOTE: because there is no service-account key file here, c2-core cannot mint
|
||||
# GCS *signed* URLs. Call audio is therefore served through c2-core's own
|
||||
# /media route (app/routers/media.py) rather than direct-from-bucket links.
|
||||
FIRESTORE_DATABASE={{ vault_firestore_database }}
|
||||
GCS_BUCKET={{ vault_gcs_bucket }}
|
||||
|
||||
# Absolute origin for call-audio playback links. The browser fetches <audio src>
|
||||
# directly, so a relative path would resolve against the frontend origin
|
||||
# (https://{{ domain }}) instead of the API's.
|
||||
PUBLIC_API_URL=https://api.{{ domain }}
|
||||
|
||||
OPENAI_API_KEY={{ vault_openai_api_key }}
|
||||
GOOGLE_MAPS_API_KEY={{ vault_google_maps_api_key }}
|
||||
GEMINI_API_KEY={{ vault_gemini_api_key }}
|
||||
|
||||
Reference in New Issue
Block a user