fix the cohere transcriber geenrator : use HF quick start

#4
Files changed (3) hide show
  1. crew2.py +12 -30
  2. transcribe_generator.py +50 -11
  3. vllm_inference.py +1 -1
crew2.py CHANGED
@@ -61,37 +61,19 @@ except ImportError:
61
  ###### The agentic app
62
 
63
  # ------ LLM endpoint constants ------
 
64
  _VLLM_MODEL = "openai/google/gemma-4-26B-A4B-it" # LiteLLM prefix — for crewai
65
  _VLLM_SERVED_MODEL = (
66
  "google/gemma-4-26B-A4B-it" # actual vLLM served name — for direct API calls
67
  )
68
- _vllm_base_url = None
69
 
70
-
71
- def _get_vllm_base_url() -> str:
72
- global _vllm_base_url
73
- if _vllm_base_url is None:
74
- import modal as _modal
75
-
76
- _vllm_base_url = (
77
- _modal.Function.from_name("vllm-inference", "serve").web_url + "/v1"
78
- )
79
- return _vllm_base_url
80
-
81
-
82
- _llm = None
83
-
84
-
85
- def _get_llm():
86
- global _llm
87
- if _llm is None:
88
- _llm = LLM(
89
- model=_VLLM_MODEL,
90
- base_url=_get_vllm_base_url(),
91
- api_key="sk-dummy-key-not-needed",
92
- max_tokens=4096,
93
- )
94
- return _llm
95
 
96
  search_tool = SerperDevTool()
97
 
@@ -185,7 +167,7 @@ def run_pipeline(statement: str, session_id: str | None = None) -> dict:
185
  verbose=True,
186
  allow_delegation=False,
187
  tools=[search_tool],
188
- llm=_get_llm(),
189
  max_iter=1,
190
  )
191
 
@@ -215,7 +197,7 @@ def run_pipeline(statement: str, session_id: str | None = None) -> dict:
215
  verbose=True,
216
  allow_delegation=False,
217
  tools=[search_tool],
218
- llm=_get_llm(),
219
  max_iter=1,
220
  )
221
 
@@ -244,7 +226,7 @@ def run_pipeline(statement: str, session_id: str | None = None) -> dict:
244
  backstory="You are a world-class creative director who translates complex, contrasting ideas into powerful visual concepts.",
245
  verbose=True,
246
  allow_delegation=False,
247
- llm=_get_llm(),
248
  max_iter=1,
249
  )
250
 
@@ -383,7 +365,7 @@ VOICE_STYLE: <voice style description>""",
383
  )
384
  with _span_cm as _span:
385
  resp = _httpx.post(
386
- f"{_get_vllm_base_url()}/chat/completions",
387
  json=payload,
388
  headers={"Authorization": "Bearer sk-dummy-key-not-needed"},
389
  timeout=300,
 
61
  ###### The agentic app
62
 
63
  # ------ LLM endpoint constants ------
64
+ _VLLM_BASE_URL = "https://rcaz33--example-vllm-inference-serve.modal.run/v1"
65
  _VLLM_MODEL = "openai/google/gemma-4-26B-A4B-it" # LiteLLM prefix — for crewai
66
  _VLLM_SERVED_MODEL = (
67
  "google/gemma-4-26B-A4B-it" # actual vLLM served name — for direct API calls
68
  )
 
69
 
70
+ # Define our LLM using the Modal-deployed Gemma 4 26B model via vLLM (OpenAI-compatible API)
71
+ llm = LLM(
72
+ model=_VLLM_MODEL,
73
+ base_url=_VLLM_BASE_URL,
74
+ api_key="sk-dummy-key-not-needed",
75
+ max_tokens=4096,
76
+ )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
77
 
78
  search_tool = SerperDevTool()
79
 
 
167
  verbose=True,
168
  allow_delegation=False,
169
  tools=[search_tool],
170
+ llm=llm,
171
  max_iter=1,
172
  )
173
 
 
197
  verbose=True,
198
  allow_delegation=False,
199
  tools=[search_tool],
200
+ llm=llm,
201
  max_iter=1,
202
  )
203
 
 
226
  backstory="You are a world-class creative director who translates complex, contrasting ideas into powerful visual concepts.",
227
  verbose=True,
228
  allow_delegation=False,
229
+ llm=llm,
230
  max_iter=1,
231
  )
232
 
 
365
  )
366
  with _span_cm as _span:
367
  resp = _httpx.post(
368
+ f"{_VLLM_BASE_URL}/chat/completions",
369
  json=payload,
370
  headers={"Authorization": "Bearer sk-dummy-key-not-needed"},
371
  timeout=300,
transcribe_generator.py CHANGED
@@ -11,8 +11,11 @@ transcribe_image = modal.Image.debian_slim(python_version="3.12").pip_install(
11
  "torch>=2.5.0",
12
  "transformers>=5.4.0",
13
  "huggingface_hub",
 
 
14
  "fastapi[standard]",
15
  "requests",
 
16
  )
17
 
18
  hf_cache_vol = modal.Volume.from_name("huggingface-cache", create_if_missing=True)
@@ -31,17 +34,45 @@ SAMPLE_RATE = 16000
31
  )
32
  class CohereTranscriber:
33
  def __init__(self):
34
- from transformers import AutoProcessor, CohereAsrForConditionalGeneration
35
-
36
- self.processor = AutoProcessor.from_pretrained(MODEL_NAME)
37
- self.model = CohereAsrForConditionalGeneration.from_pretrained(
38
- MODEL_NAME, device_map="auto"
 
 
 
 
 
 
 
 
39
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
40
 
41
  @modal.fastapi_endpoint(method="POST")
42
  def transcribe(self, body: dict) -> JSONResponse:
43
- from transformers.audio_utils import load_audio
 
44
  import requests as _requests
 
45
 
46
  audio_bytes = None
47
 
@@ -57,15 +88,23 @@ class CohereTranscriber:
57
  status_code=400,
58
  )
59
 
60
- audio = load_audio(io.BytesIO(audio_bytes), sampling_rate=SAMPLE_RATE)
 
 
 
 
61
 
62
  inputs = self.processor(
63
- audio, sampling_rate=SAMPLE_RATE, return_tensors="pt", language="en"
64
  )
65
- inputs.to(self.model.device, dtype=self.model.dtype)
 
 
 
66
 
67
- outputs = self.model.generate(**inputs, max_new_tokens=256)
68
- transcription = self.processor.decode(outputs, skip_special_tokens=True)
 
69
 
70
  return JSONResponse({"transcription": transcription})
71
 
 
11
  "torch>=2.5.0",
12
  "transformers>=5.4.0",
13
  "huggingface_hub",
14
+ "soundfile",
15
+ "librosa",
16
  "fastapi[standard]",
17
  "requests",
18
+ "sentencepiece",
19
  )
20
 
21
  hf_cache_vol = modal.Volume.from_name("huggingface-cache", create_if_missing=True)
 
34
  )
35
  class CohereTranscriber:
36
  def __init__(self):
37
+ import torch
38
+ from transformers import AutoProcessor
39
+
40
+ self.device = "cuda"
41
+ from transformers import AutoModelForSpeechSeq2Seq, AutoConfig
42
+ # Config: preprocessor.features=128, window_size=0.025s (400 @16kHz), window_stride=0.01s (160 @16kHz)
43
+ self.processor = AutoProcessor.from_pretrained(
44
+ MODEL_NAME,
45
+ trust_remote_code=True,
46
+ feature_size=128,
47
+ n_window_size=400,
48
+ n_window_stride=160,
49
+ n_fft=512,
50
  )
51
+ # Load config, get model class from pattern matching, patch list→set for transformers 5.12 compat
52
+ config = AutoConfig.from_pretrained(MODEL_NAME, trust_remote_code=True)
53
+ # Try loading; if it fails due to list|set, patch and retry
54
+ import transformers.modeling_utils as _mu
55
+ orig_fn = _mu.PreTrainedModel._adjust_missing_and_unexpected_keys
56
+ def patched_fn(self, *a, **kw):
57
+ if hasattr(self, '_keys_to_ignore_on_load_unexpected') and isinstance(self._keys_to_ignore_on_load_unexpected, list):
58
+ self._keys_to_ignore_on_load_unexpected = set(self._keys_to_ignore_on_load_unexpected)
59
+ return orig_fn(self, *a, **kw)
60
+ _mu.PreTrainedModel._adjust_missing_and_unexpected_keys = patched_fn
61
+ try:
62
+ self.model = AutoModelForSpeechSeq2Seq.from_pretrained(
63
+ MODEL_NAME,
64
+ dtype=torch.bfloat16,
65
+ trust_remote_code=True,
66
+ ).to(self.device)
67
+ finally:
68
+ _mu.PreTrainedModel._adjust_missing_and_unexpected_keys = orig_fn
69
 
70
  @modal.fastapi_endpoint(method="POST")
71
  def transcribe(self, body: dict) -> JSONResponse:
72
+ import librosa
73
+ import soundfile as sf
74
  import requests as _requests
75
+ import torch
76
 
77
  audio_bytes = None
78
 
 
88
  status_code=400,
89
  )
90
 
91
+ audio, sr = sf.read(io.BytesIO(audio_bytes))
92
+ if sr != SAMPLE_RATE:
93
+ audio = librosa.resample(audio, orig_sr=sr, target_sr=SAMPLE_RATE)
94
+ if audio.ndim > 1:
95
+ audio = audio.mean(axis=1)
96
 
97
  inputs = self.processor(
98
+ audio, sampling_rate=SAMPLE_RATE, return_tensors="pt"
99
  )
100
+ input_features = inputs.input_features.to(self.device, dtype=torch.bfloat16)
101
+
102
+ with torch.no_grad():
103
+ generated_ids = self.model.generate(input_features)
104
 
105
+ transcription = self.processor.batch_decode(
106
+ generated_ids, skip_special_tokens=True
107
+ )[0]
108
 
109
  return JSONResponse({"transcription": transcription})
110
 
vllm_inference.py CHANGED
@@ -27,7 +27,7 @@ FAST_BOOT = False
27
  SPECULATIVE_MODEL_NAME = "google/gemma-4-26B-A4B-it-assistant"
28
  SPECULATIVE_MODEL_REVISION = "f188f476dc11dd5bb3014dc861529d316bce49d3"
29
 
30
- app = modal.App("vllm-inference")
31
 
32
  N_GPU = 1
33
  MINUTES = 60
 
27
  SPECULATIVE_MODEL_NAME = "google/gemma-4-26B-A4B-it-assistant"
28
  SPECULATIVE_MODEL_REVISION = "f188f476dc11dd5bb3014dc861529d316bce49d3"
29
 
30
+ app = modal.App("example-vllm-inference")
31
 
32
  N_GPU = 1
33
  MINUTES = 60