Skip to content

Commit f0e0464

Browse files
committed
Fixes
1 parent 4686f52 commit f0e0464

File tree

3 files changed

+83
-2
lines changed

3 files changed

+83
-2
lines changed

.github/workflows/tests.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ jobs:
113113
if: ${{ matrix.skip_pytests != 'true' }}
114114
env:
115115
ML_BACKEND: ${{ matrix.backend_dir_name }}
116+
TEST_ENV: "true"
116117
run: |
117118
docker compose -f label_studio_ml/examples/${{ matrix.backend_dir_name }}/docker-compose.yml exec -T ${{ matrix.backend_dir_name }} pytest -vvv --cov --cov-report=xml:/tmp/coverage.xml
118119

label_studio_ml/examples/deepgram/model.py

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import os
22
import sys
33
import pathlib
4+
from types import SimpleNamespace
45
from typing import List, Dict, Optional
56
from label_studio_ml.model import LabelStudioMLBase
67
from label_studio_ml.response import ModelResponse
@@ -20,6 +21,11 @@ class DeepgramModel(LabelStudioMLBase):
2021

2122
def setup(self):
2223
"""Initialize the Deepgram client with API key from environment"""
24+
self.test_mode = self._is_test_mode_enabled()
25+
if self.test_mode:
26+
self._setup_test_clients()
27+
return
28+
2329
api_key = os.getenv('DEEPGRAM_API_KEY')
2430
if not api_key:
2531
raise ValueError("DEEPGRAM_API_KEY environment variable is not set")
@@ -78,13 +84,46 @@ def predict(self, tasks: List[Dict], context: Optional[Dict] = None, **kwargs) -
7884
print(f"Uploaded audio to S3: {s3_url}")
7985

8086
# Update task with S3 URL
81-
ls.tasks.update(id=task_id, data={"text": text, "audio": s3_url})
87+
if self.test_mode:
88+
print(f"[TEST MODE] Would update task {task_id} with audio {s3_url}")
89+
else:
90+
ls.tasks.update(id=task_id, data={"text": text, "audio": s3_url})
8291
except Exception as e:
8392
print(f"Error uploading to S3: {e}")
8493
raise
8594
finally:
8695
# Clean up local file
8796
if os.path.exists(local_audio_path):
8897
os.remove(local_audio_path)
89-
98+
99+
def _is_test_mode_enabled(self) -> bool:
100+
"""Check environment variables to decide if the model should use local stubs."""
101+
truthy = {'1', 'true', 'TRUE', 'True', 'yes', 'on'}
102+
explicit_flag = os.getenv('DEEPGRAM_TEST_MODE')
103+
test_env_flag = os.getenv('TEST_ENV')
104+
return (explicit_flag in truthy) or (test_env_flag in truthy)
105+
106+
def _setup_test_clients(self):
107+
"""Configure lightweight stub clients so docker/CI runs do not need real secrets."""
108+
print("[TEST MODE] DeepgramModel using stubbed Deepgram/S3 clients.")
109+
110+
def fake_generate(text: str):
111+
# Produce deterministic fake audio bytes for predictable tests.
112+
preview = text[:10] if text else ''
113+
return [f"fake-audio-{preview}".encode('utf-8')]
114+
115+
fake_audio = SimpleNamespace(generate=fake_generate)
116+
fake_speak = SimpleNamespace(v1=SimpleNamespace(audio=fake_audio))
117+
self.deepgram_client = SimpleNamespace(speak=fake_speak)
118+
119+
class _StubS3Client:
120+
"""Minimal S3 client replacement for test environments."""
121+
def upload_file(self, filename, bucket, key, ExtraArgs=None):
122+
print(f"[TEST MODE] Pretend upload of {filename} to s3://{bucket}/{key}")
123+
124+
self.s3_client = _StubS3Client()
125+
# Provide sensible defaults so downstream URL building still works.
126+
self.s3_region = os.getenv('AWS_DEFAULT_REGION', 'us-east-1')
127+
self.s3_bucket = os.getenv('S3_BUCKET', 'test-bucket')
128+
self.s3_folder = os.getenv('S3_FOLDER', 'tts')
90129

label_studio_ml/examples/deepgram/test_model.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,3 +178,44 @@ def test_predict_s3_failure_raises_and_cleans_up_temp_file(env_settings, patched
178178
assert not os.path.exists(local_path)
179179
patched_clients['ls'].tasks.update.assert_not_called()
180180

181+
182+
def test_setup_in_test_mode_uses_stub_clients(monkeypatch):
183+
"""
184+
Scenario: TEST_ENV is enabled to activate internal stubs.
185+
Steps : set TEST_ENV, instantiate the model, and inspect configured clients.
186+
Checks : ensure real Deepgram constructor is not called and stub clients exist with defaults.
187+
"""
188+
monkeypatch.setenv('TEST_ENV', '1')
189+
ctor = MagicMock()
190+
monkeypatch.setattr(deepgram_model, 'DeepgramClient', ctor)
191+
192+
model = deepgram_model.DeepgramModel()
193+
194+
assert model.test_mode is True
195+
ctor.assert_not_called()
196+
assert callable(model.deepgram_client.speak.v1.audio.generate)
197+
assert model.s3_bucket == 'test-bucket'
198+
assert model.s3_folder == 'tts'
199+
200+
201+
def test_predict_test_mode_skips_label_studio_update(monkeypatch):
202+
"""
203+
Scenario: predict runs in test mode so external Label Studio updates should be skipped.
204+
Steps : enable TEST_ENV, patch ls.tasks.update, run predict with valid context.
205+
Checks : confirm stub S3 upload runs without raising and Label Studio update is not invoked.
206+
"""
207+
monkeypatch.setenv('TEST_ENV', '1')
208+
model = deepgram_model.DeepgramModel()
209+
mocked_update = MagicMock()
210+
monkeypatch.setattr(deepgram_model.ls.tasks, 'update', mocked_update)
211+
212+
tasks = [{'id': 321}]
213+
context = {
214+
'user_id': 'tester',
215+
'result': [{'value': {'text': ['Hello from test mode']}}],
216+
}
217+
218+
model.predict(tasks=tasks, context=context)
219+
220+
mocked_update.assert_not_called()
221+

0 commit comments

Comments
 (0)