siddhartharyaai commited on
Commit
388741c
·
verified ·
1 Parent(s): 555c75b

Update utils.py

Browse files
Files changed (1) hide show
  1. utils.py +233 -1
utils.py CHANGED
@@ -259,4 +259,236 @@ def transcribe_youtube_video(video_url: str) -> str:
259
  raise ValueError(f"RapidAPI transcription error: {response.status_code}, {response.text}")
260
 
261
  data = response.json()
262
- if not isinstance(data, list) or not data:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
259
  raise ValueError(f"RapidAPI transcription error: {response.status_code}, {response.text}")
260
 
261
  data = response.json()
262
+ if not isinstance(data, list) or not data:
263
+ raise ValueError(f"Unexpected transcript format or empty transcript: {data}")
264
+
265
+ transcript_as_text = data[0].get('transcriptionAsText', '').strip()
266
+ if not transcript_as_text:
267
+ raise ValueError("transcriptionAsText field is missing or empty.")
268
+
269
+ print("[LOG] Transcript retrieval successful.")
270
+ print(f"[DEBUG] Transcript Length: {len(transcript_as_text)} characters.")
271
+ snippet = transcript_as_text[:200] + "..." if len(transcript_as_text) > 200 else transcript_as_text
272
+ print(f"[DEBUG] Transcript Snippet: {snippet}")
273
+
274
+ return transcript_as_text
275
+ except Exception as e:
276
+ print("[ERROR] RapidAPI transcription error:", e)
277
+ raise ValueError(f"Error transcribing YouTube video via RapidAPI: {str(e)}")
278
+
279
+ def generate_audio_mp3(text: str, speaker: str) -> str:
280
+ try:
281
+ import streamlit as st
282
+ print(f"[LOG] Generating audio for speaker: {speaker}")
283
+ language_selection = st.session_state.get("language_selection", "English (American)")
284
+ if language_selection == "English (American)":
285
+ print(f"[LOG] Using Deepgram for English (American)")
286
+ if speaker in ["John", "Jane"]:
287
+ processed_text = text
288
+ else:
289
+ processed_text = _preprocess_text_for_tts(text, speaker)
290
+ deepgram_api_url = "https://api.deepgram.com/v1/speak"
291
+ params = {"model": "aura-asteria-en"}
292
+ if speaker == "John":
293
+ params["model"] = "aura-zeus-en"
294
+ headers = {
295
+ "Accept": "audio/mpeg",
296
+ "Content-Type": "application/json",
297
+ "Authorization": f"Token {os.environ.get('DEEPGRAM_API_KEY')}"
298
+ }
299
+ body = {"text": processed_text}
300
+ response = requests.post(deepgram_api_url, params=params, headers=headers, json=body, stream=True)
301
+ if response.status_code != 200:
302
+ raise ValueError(f"Deepgram TTS error: {response.status_code}, {response.text}")
303
+ content_type = response.headers.get('Content-Type', '')
304
+ if 'audio/mpeg' not in content_type:
305
+ raise ValueError("Unexpected Content-Type from Deepgram.")
306
+ with tempfile.NamedTemporaryFile(delete=False, suffix=".mp3") as mp3_file:
307
+ for chunk in response.iter_content(chunk_size=8192):
308
+ if chunk:
309
+ mp3_file.write(chunk)
310
+ mp3_path = mp3_file.name
311
+ audio_seg = AudioSegment.from_file(mp3_path, format="mp3")
312
+ audio_seg = effects.normalize(audio_seg)
313
+ final_mp3_path = tempfile.NamedTemporaryFile(delete=False, suffix=".mp3").name
314
+ audio_seg.export(final_mp3_path, format="mp3")
315
+ if os.path.exists(mp3_path):
316
+ os.remove(mp3_path)
317
+ return final_mp3_path
318
+ else:
319
+ print(f"[LOG] Using Murf API for language: {language_selection}")
320
+ if language_selection == "Hinglish":
321
+ from indic_transliteration.sanscript import transliterate, DEVANAGARI, IAST
322
+ text = transliterate(text, DEVANAGARI, IAST)
323
+ api_key = os.environ.get("MURF_API_KEY")
324
+ headers = {
325
+ "Content-Type": "application/json",
326
+ "Accept": "application/json",
327
+ "api-key": api_key
328
+ }
329
+ multi_native_locale = "hi-IN" if language_selection in ["Hinglish", "Hindi"] else "en-IN"
330
+ if language_selection == "English (Indian)":
331
+ voice_id = "en-IN-aarav" if speaker == "John" else "en-IN-isha"
332
+ elif language_selection == "Hindi":
333
+ voice_id = "hi-IN-kabir" if speaker == "John" else "hi-IN-shweta"
334
+ elif language_selection == "Hinglish":
335
+ voice_id = "hi-IN-kabir" if speaker == "John" else "hi-IN-shweta"
336
+ else:
337
+ voice_id = "en-IN-aarav" if speaker == "John" else "en-IN-isha"
338
+ payload = {
339
+ "audioDuration": 0,
340
+ "channelType": "MONO",
341
+ "encodeAsBase64": False,
342
+ "format": "WAV",
343
+ "modelVersion": "GEN2",
344
+ "multiNativeLocale": multi_native_locale,
345
+ "pitch": 0,
346
+ "pronunciationDictionary": {},
347
+ "rate": 0,
348
+ "sampleRate": 48000,
349
+ "style": "Conversational",
350
+ "text": text,
351
+ "variation": 1,
352
+ "voiceId": voice_id
353
+ }
354
+ response = requests.post("https://api.murf.ai/v1/speech/generate", headers=headers, json=payload)
355
+ if response.status_code != 200:
356
+ raise ValueError(f"Murf API error: {response.status_code}, {response.text}")
357
+ json_resp = response.json()
358
+ audio_url = json_resp.get("audioFile")
359
+ if not audio_url:
360
+ raise ValueError("No audio file URL returned by Murf API")
361
+ audio_response = requests.get(audio_url)
362
+ if audio_response.status_code != 200:
363
+ raise ValueError(f"Error fetching audio from {audio_url}")
364
+ with tempfile.NamedTemporaryFile(delete=False, suffix=".wav") as wav_file:
365
+ wav_file.write(audio_response.content)
366
+ wav_path = wav_file.name
367
+ audio_seg = AudioSegment.from_file(wav_path, format="wav")
368
+ audio_seg = effects.normalize(audio_seg)
369
+ final_mp3_path = tempfile.NamedTemporaryFile(delete=False, suffix=".mp3").name
370
+ audio_seg.export(final_mp3_path, format="mp3")
371
+ os.remove(wav_path)
372
+ return final_mp3_path
373
+ except Exception as e:
374
+ print("[ERROR] Error generating audio:", e)
375
+ raise ValueError(f"Error generating audio: {str(e)}")
376
+
377
+ def transcribe_youtube_video_OLD_YTDLP(video_url: str) -> str:
378
+ pass
379
+
380
+ def _preprocess_text_for_tts(text: str, speaker: str) -> str:
381
+ text = re.sub(r"\bNo\.\b", "Number", text)
382
+ text = re.sub(r"\b(?i)SaaS\b", "sass", text)
383
+ abbreviations_as_words = {"NASA", "NATO", "UNESCO"}
384
+ def insert_periods_for_abbrev(m):
385
+ abbr = m.group(0)
386
+ if abbr in abbreviations_as_words:
387
+ return abbr
388
+ return ".".join(list(abbr)) + "."
389
+ text = re.sub(r"\b([A-Z]{2,})\b", insert_periods_for_abbrev, text)
390
+ text = re.sub(r"\.\.", ".", text)
391
+ def remove_periods_for_tts(m):
392
+ return m.group().replace(".", " ").strip()
393
+ text = re.sub(r"[A-Z]\.[A-Z](?:\.[A-Z])*\.", remove_periods_for_tts, text)
394
+ text = re.sub(r"-", " ", text)
395
+ text = re.sub(r"\b(ha(ha)?|heh|lol)\b", "(* laughs *)", text, flags=re.IGNORECASE)
396
+ text = re.sub(r"\bsigh\b", "(* sighs *)", text, flags=re.IGNORECASE)
397
+ text = re.sub(r"\b(groan|moan)\b", "(* groans *)", text, flags=re.IGNORECASE)
398
+ if speaker != "Jane":
399
+ def insert_thinking_pause(m):
400
+ word = m.group(1)
401
+ if random.random() < 0.3:
402
+ filler = random.choice(['hmm,', 'well,', 'let me see,'])
403
+ return f"{word}..., {filler}"
404
+ else:
405
+ return f"{word}...,"
406
+ keywords_pattern = r"\b(important|significant|crucial|point|topic)\b"
407
+ text = re.sub(keywords_pattern, insert_thinking_pause, text, flags=re.IGNORECASE)
408
+ conj_pattern = r"\b(and|but|so|because|however)\b"
409
+ text = re.sub(conj_pattern, lambda m: f"{m.group()}...", text, flags=re.IGNORECASE)
410
+ text = re.sub(r"\b(uh|um|ah)\b", "", text, flags=re.IGNORECASE)
411
+ def capitalize_match(m):
412
+ return m.group().upper()
413
+ text = re.sub(r'(^\s*\w)|([.!?]\s*\w)', capitalize_match, text)
414
+ return text.strip()
415
+
416
+ def _spell_digits(d: str) -> str:
417
+ digit_map = {
418
+ '0': 'zero', '1': 'one', '2': 'two', '3': 'three',
419
+ '4': 'four', '5': 'five', '6': 'six', '7': 'seven',
420
+ '8': 'eight', '9': 'nine'
421
+ }
422
+ return " ".join(digit_map[ch] for ch in d if ch in digit_map)
423
+
424
+ def mix_with_bg_music(spoken: AudioSegment, custom_music_path=None) -> AudioSegment:
425
+ if custom_music_path:
426
+ music_path = custom_music_path
427
+ else:
428
+ music_path = "bg_music.mp3"
429
+
430
+ try:
431
+ bg_music = AudioSegment.from_file(music_path, format="mp3")
432
+ except Exception as e:
433
+ print("[ERROR] Failed to load background music:", e)
434
+ return spoken
435
+
436
+ bg_music = bg_music - 18.0
437
+ total_length_ms = len(spoken) + 2000
438
+ looped_music = AudioSegment.empty()
439
+ while len(looped_music) < total_length_ms:
440
+ looped_music += bg_music
441
+ looped_music = looped_music[:total_length_ms]
442
+ final_mix = looped_music.overlay(spoken, position=2000)
443
+ return final_mix
444
+
445
+ def call_groq_api_for_qa(system_prompt: str) -> str:
446
+ #Kept for use, Changed model
447
+ try:
448
+ headers = {
449
+ "Authorization": f"Bearer {os.environ.get('GROQ_API_KEY')}", # Use GROQ API KEY
450
+ "Content-Type": "application/json",
451
+ "Accept": "application/json"
452
+ }
453
+ data = {
454
+ "model": "deepseek-r1-distill-llama-70b", #Using Deepseek
455
+ "messages": [{"role": "user", "content": system_prompt}],
456
+ "max_tokens": 512,
457
+ "temperature": 0.7
458
+ }
459
+ response = requests.post("https://api.groq.com/openai/v1/chat/completions", #Using groq endpoint
460
+ headers=headers, data=json.dumps(data))
461
+ response.raise_for_status()
462
+ return response.json()["choices"][0]["message"]["content"].strip()
463
+ except Exception as e:
464
+ print("[ERROR] Groq API error:", e)
465
+ fallback = {"speaker": "John", "text": "I'm sorry, I'm having trouble answering right now."}
466
+ return json.dumps(fallback)
467
+
468
+ # --- Agent and Tavily Integration ---
469
+
470
+ def run_research_agent(topic: str, report_type: str = "research_report", max_results: int = 20) -> str:
471
+ """
472
+ Runs the Open Deep Research agent to generate a research report.
473
+
474
+ Args:
475
+ topic: The research topic.
476
+ report_type: The type of report to generate (currently only supports "research_report").
477
+ max_results: The maximum number of search results to use.
478
+
479
+ Returns:
480
+ A string containing the generated research report. Or, in case of error,
481
+ an error message.
482
+ """
483
+ print(f"[LOG] Starting research agent for topic: {topic}")
484
+ try:
485
+ agent = OpenDeepResearcher(topic, report_type=report_type, max_results=max_results, tavily_api_key=os.environ.get("TAVILY_API_KEY"))
486
+ report_content = agent.run()
487
+ print("[LOG] Research agent completed successfully.")
488
+
489
+ # Now, use the report_structure module to generate the structured report.
490
+ structured_report = generate_report(report_content)
491
+ return structured_report
492
+ except Exception as e:
493
+ print(f"[ERROR] Error in research agent: {e}")
494
+ return f"Sorry, I encountered an error during research: {e}"