Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion backend/app/core/batch/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from google import genai
from sqlmodel import Session

from app.core.exception_handlers import HTTPException
from fastapi import HTTPException
from app.crud.credentials import get_provider_credential

logger = logging.getLogger(__name__)
Expand Down
4 changes: 3 additions & 1 deletion backend/app/crud/tts_evaluations/result.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,9 @@ def get_results_by_run_id(
results = []
for result in rows:
signed_url = (
storage.get_signed_url(result.object_store_url) if storage else None
storage.get_signed_url(result.object_store_url)
if storage and result.object_store_url
else None
)
results.append(TTSResultPublic.from_model(result, signed_url=signed_url))

Expand Down
65 changes: 65 additions & 0 deletions backend/app/tests/api/routes/test_tts_evaluation.py
Original file line number Diff line number Diff line change
Expand Up @@ -1006,6 +1006,71 @@ def test_get_run_with_results(
assert "Hello world" in texts
assert "Good morning" in texts

@patch("app.api.routes.tts_evaluations.evaluation.get_cloud_storage")
def test_get_run_with_signed_urls_and_null_object_store_url(
self,
mock_get_cloud_storage: MagicMock,
client: TestClient,
user_api_key_header: dict[str, str],
db: Session,
user_api_key: TestAuthContext,
test_dataset_with_samples: EvaluationDataset,
) -> None:
"""Test that signed URL generation handles results with null object_store_url."""
dataset = test_dataset_with_samples

mock_storage = MagicMock()
mock_storage.get_signed_url.return_value = (
"https://signed-url.example.com/audio.wav"
)
mock_get_cloud_storage.return_value = mock_storage

run = create_tts_run(
session=db,
run_name="signed_url_null_test",
dataset_id=dataset.id,
dataset_name=dataset.name,
org_id=user_api_key.organization_id,
project_id=user_api_key.project_id,
models=["gemini-2.5-pro-preview-tts"],
total_items=2,
)

# Result with valid S3 URL
create_test_tts_result(
db=db,
evaluation_run_id=run.id,
organization_id=user_api_key.organization_id,
project_id=user_api_key.project_id,
sample_text="Completed result",
status=JobStatus.SUCCESS.value,
object_store_url="s3://bucket/audio/test.wav",
)
# Result with null object_store_url (failed)
create_test_tts_result(
db=db,
evaluation_run_id=run.id,
organization_id=user_api_key.organization_id,
project_id=user_api_key.project_id,
sample_text="Failed result",
status=JobStatus.FAILED.value,
object_store_url=None,
)

response = client.get(
f"/api/v1/evaluations/tts/runs/{run.id}",
params={"include_results": True, "include_signed_url": True},
headers=user_api_key_header,
)

assert response.status_code == 200, response.text
data = response.json()["data"]
assert data["results_total"] == 2

results_by_text = {r["sample_text"]: r for r in data["results"]}
assert results_by_text["Completed result"]["signed_url"] is not None
assert results_by_text["Failed result"]["signed_url"] is None

def test_get_run_without_results(
self,
client: TestClient,
Expand Down
Loading