Scripts-deploy-VMs-models

#1
by RCaz - opened
Files changed (1) hide show
  1. crew2.py +91 -41
crew2.py CHANGED
@@ -1,7 +1,7 @@
1
  import concurrent.futures
2
  import sys
3
  import uuid
4
- from contextlib import contextmanager
5
  from dotenv import load_dotenv
6
 
7
  from crewai import Agent, Crew, LLM, Process, Task
@@ -14,15 +14,19 @@ load_dotenv()
14
  try:
15
  from openinference.instrumentation import using_session as _using_session
16
  except ImportError:
 
17
  @contextmanager
18
  def _using_session(session_id): # noqa: F811
19
  yield
20
 
 
21
  try:
22
  from openinference.semconv.trace import SpanAttributes
23
  except ImportError:
 
24
  class _SpanAttributes:
25
  SESSION_ID = "session_id"
 
26
  SpanAttributes = _SpanAttributes() # type: ignore
27
 
28
  # ------ Phoenix / OpenTelemetry tracing ------
@@ -46,9 +50,11 @@ try:
46
  endpoint="https://RCaz-phoenix-arize-observability.hf.space/v1/traces",
47
  headers=build_hf_headers(),
48
  )
 
49
  CrewAIInstrumentor().instrument(tracer_provider=tracer_provider)
 
50
  except ImportError:
51
- pass
52
 
53
 
54
  ###### The agentic app
@@ -232,7 +238,7 @@ Two research crews investigated it. Here are their findings:
232
  {result_opposite}
233
 
234
  Your job:
235
- Create a highly detailed visual scene description that captures the dialogue, contrast, or tension between these two perspectives. Describe the composition, colors, lighting, mood, subjects, setting, and visual metaphor in vivid detail — as if instructing an artist or image generation model.
236
 
237
  Output exactly in this format:
238
 
@@ -281,21 +287,26 @@ def generate_image(prompt: str) -> bytes:
281
 
282
  import httpx as _httpx
283
 
284
- url = _get_flux_url()
285
- resp = _httpx.post(
286
- url,
287
- json={"prompt": prompt, "steps": 30},
288
- timeout=600,
289
- follow_redirects=True,
290
- )
291
- resp.raise_for_status()
292
- return resp.content
 
 
 
293
 
294
 
295
  # ------ Caption Generation (direct LLM call with image prompt context) ------
296
 
297
 
298
- def generate_caption(corroborate: str, opposite: str, image_prompt: str, session_id: str | None = None) -> dict:
 
 
299
  """
300
  Send the research + image prompt to Gemma 4 and get a 30-second
301
  spoken caption + voice style back.
@@ -343,15 +354,34 @@ VOICE_STYLE: <voice style description>""",
343
  }
344
 
345
  with _using_session(session_id):
346
- resp = _httpx.post(
347
- f"{_VLLM_BASE_URL}/chat/completions",
348
- json=payload,
349
- headers={"Authorization": "Bearer sk-dummy-key-not-needed"},
350
- timeout=300,
351
  )
352
- resp.raise_for_status()
353
- body = resp.json()
354
- text = body["choices"][0]["message"]["content"]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
355
 
356
  print(f"Gemma response:\n{text}\n")
357
 
@@ -369,7 +399,9 @@ VOICE_STYLE: <voice style description>""",
369
  # ------ Voice Generation (VoxCPM on Modal) ------
370
 
371
 
372
- def generate_voice(voice_style: str, voice_script: str, session_id: str | None = None) -> bytes:
 
 
373
  """Send script to VoxCPM on Modal T4, return WAV bytes."""
374
  if session_id is None:
375
  session_id = str(uuid.uuid4())
@@ -381,15 +413,20 @@ def generate_voice(voice_style: str, voice_script: str, session_id: str | None =
381
  import httpx as _httpx
382
 
383
  with _using_session(session_id):
384
- url = _get_vox_url()
385
- resp = _httpx.post(
386
- url,
387
- json={"text": voice_script, "voice_style": voice_style},
388
- timeout=600,
389
- follow_redirects=True,
390
- )
391
- resp.raise_for_status()
392
- return resp.content
 
 
 
 
 
393
 
394
 
395
  # ------ Audio Transcription (Cohere Transcribe on Modal) ------
@@ -405,14 +442,19 @@ def transcribe_audio(audio_path: str, session_id: str | None = None) -> str:
405
  url = _get_transcribe_url()
406
 
407
  with _using_session(session_id):
408
- with open(audio_path, "rb") as f:
409
- audio_b64 = base64.b64encode(f.read()).decode()
 
 
 
 
 
410
 
411
- resp = _httpx.post(url, json={"audio": audio_b64}, timeout=600)
412
- resp.raise_for_status()
413
- text = resp.json()["transcription"]
414
- print(f'Transcribed: "{text}"\n')
415
- return text
416
 
417
 
418
  # ------ CLI Entry Point ------
@@ -461,7 +503,9 @@ if __name__ == "__main__":
461
  caption_result = None
462
  if prompt and corroborate and opposite:
463
  try:
464
- caption_result = generate_caption(corroborate, opposite, prompt, session_id=session_id)
 
 
465
  if caption_result["caption"]:
466
  print(f"\n✓ Caption: {caption_result['caption']}")
467
  if caption_result["voice_style"]:
@@ -472,10 +516,16 @@ if __name__ == "__main__":
472
  print("(Skipping caption generation — missing prompt or research)")
473
 
474
  # Generate voice
475
- if caption_result and caption_result["voice_style"] and caption_result["caption"]:
 
 
 
 
476
  try:
477
  audio_bytes = generate_voice(
478
- caption_result["voice_style"], caption_result["caption"], session_id=session_id
 
 
479
  )
480
  filename = "crew_voice_output.wav"
481
  with open(filename, "wb") as f:
 
1
  import concurrent.futures
2
  import sys
3
  import uuid
4
+ from contextlib import contextmanager, nullcontext
5
  from dotenv import load_dotenv
6
 
7
  from crewai import Agent, Crew, LLM, Process, Task
 
14
  try:
15
  from openinference.instrumentation import using_session as _using_session
16
  except ImportError:
17
+
18
  @contextmanager
19
  def _using_session(session_id): # noqa: F811
20
  yield
21
 
22
+
23
  try:
24
  from openinference.semconv.trace import SpanAttributes
25
  except ImportError:
26
+
27
  class _SpanAttributes:
28
  SESSION_ID = "session_id"
29
+
30
  SpanAttributes = _SpanAttributes() # type: ignore
31
 
32
  # ------ Phoenix / OpenTelemetry tracing ------
 
50
  endpoint="https://RCaz-phoenix-arize-observability.hf.space/v1/traces",
51
  headers=build_hf_headers(),
52
  )
53
+ OpenAIInstrumentor().instrument(tracer_provider=tracer_provider)
54
  CrewAIInstrumentor().instrument(tracer_provider=tracer_provider)
55
+ tracer = trace.get_tracer("crewai")
56
  except ImportError:
57
+ tracer = None
58
 
59
 
60
  ###### The agentic app
 
238
  {result_opposite}
239
 
240
  Your job:
241
+ Create a highly detailed visual scene description that captures and merges the dialogue, contrast, or tension between these two perspectives. Describe the composition, colors, lighting, mood, subjects, setting, and visual metaphor in vivid detail — as if instructing an artist or image generation model.
242
 
243
  Output exactly in this format:
244
 
 
287
 
288
  import httpx as _httpx
289
 
290
+ with (
291
+ tracer.start_as_current_span("flux.generate_image") if tracer else nullcontext()
292
+ ):
293
+ url = _get_flux_url()
294
+ resp = _httpx.post(
295
+ url,
296
+ json={"prompt": prompt, "steps": 30},
297
+ timeout=600,
298
+ follow_redirects=True,
299
+ )
300
+ resp.raise_for_status()
301
+ return resp.content
302
 
303
 
304
  # ------ Caption Generation (direct LLM call with image prompt context) ------
305
 
306
 
307
+ def generate_caption(
308
+ corroborate: str, opposite: str, image_prompt: str, session_id: str | None = None
309
+ ) -> dict:
310
  """
311
  Send the research + image prompt to Gemma 4 and get a 30-second
312
  spoken caption + voice style back.
 
354
  }
355
 
356
  with _using_session(session_id):
357
+ _span_cm = (
358
+ tracer.start_as_current_span("llm.generate_caption")
359
+ if tracer
360
+ else nullcontext()
 
361
  )
362
+ with _span_cm as _span:
363
+ resp = _httpx.post(
364
+ f"{_VLLM_BASE_URL}/chat/completions",
365
+ json=payload,
366
+ headers={"Authorization": "Bearer sk-dummy-key-not-needed"},
367
+ timeout=300,
368
+ )
369
+ resp.raise_for_status()
370
+ body = resp.json()
371
+ text = body["choices"][0]["message"]["content"]
372
+
373
+ if tracer and "usage" in body:
374
+ usage = body["usage"]
375
+ _span.set_attribute(
376
+ "llm.token_count.prompt", usage.get("prompt_tokens", 0)
377
+ )
378
+ _span.set_attribute(
379
+ "llm.token_count.completion", usage.get("completion_tokens", 0)
380
+ )
381
+ _span.set_attribute(
382
+ "llm.token_count.total", usage.get("total_tokens", 0)
383
+ )
384
+ _span.set_attribute("llm.model_name", _VLLM_SERVED_MODEL)
385
 
386
  print(f"Gemma response:\n{text}\n")
387
 
 
399
  # ------ Voice Generation (VoxCPM on Modal) ------
400
 
401
 
402
+ def generate_voice(
403
+ voice_style: str, voice_script: str, session_id: str | None = None
404
+ ) -> bytes:
405
  """Send script to VoxCPM on Modal T4, return WAV bytes."""
406
  if session_id is None:
407
  session_id = str(uuid.uuid4())
 
413
  import httpx as _httpx
414
 
415
  with _using_session(session_id):
416
+ with (
417
+ tracer.start_as_current_span("voxcpm.generate_voice")
418
+ if tracer
419
+ else nullcontext()
420
+ ):
421
+ url = _get_vox_url()
422
+ resp = _httpx.post(
423
+ url,
424
+ json={"text": voice_script, "voice_style": voice_style},
425
+ timeout=600,
426
+ follow_redirects=True,
427
+ )
428
+ resp.raise_for_status()
429
+ return resp.content
430
 
431
 
432
  # ------ Audio Transcription (Cohere Transcribe on Modal) ------
 
442
  url = _get_transcribe_url()
443
 
444
  with _using_session(session_id):
445
+ with (
446
+ tracer.start_as_current_span("cohere.transcribe_audio")
447
+ if tracer
448
+ else nullcontext()
449
+ ):
450
+ with open(audio_path, "rb") as f:
451
+ audio_b64 = base64.b64encode(f.read()).decode()
452
 
453
+ resp = _httpx.post(url, json={"audio": audio_b64}, timeout=600)
454
+ resp.raise_for_status()
455
+ text = resp.json()["transcription"]
456
+ print(f'Transcribed: "{text}"\n')
457
+ return text
458
 
459
 
460
  # ------ CLI Entry Point ------
 
503
  caption_result = None
504
  if prompt and corroborate and opposite:
505
  try:
506
+ caption_result = generate_caption(
507
+ corroborate, opposite, prompt, session_id=session_id
508
+ )
509
  if caption_result["caption"]:
510
  print(f"\n✓ Caption: {caption_result['caption']}")
511
  if caption_result["voice_style"]:
 
516
  print("(Skipping caption generation — missing prompt or research)")
517
 
518
  # Generate voice
519
+ if (
520
+ caption_result
521
+ and caption_result["voice_style"]
522
+ and caption_result["caption"]
523
+ ):
524
  try:
525
  audio_bytes = generate_voice(
526
+ caption_result["voice_style"],
527
+ caption_result["caption"],
528
+ session_id=session_id,
529
  )
530
  filename = "crew_voice_output.wav"
531
  with open(filename, "wb") as f: