dalybuilds commited on
Commit
95b97f6
·
verified ·
1 Parent(s): 3948895

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +23 -21
app.py CHANGED
@@ -4,10 +4,12 @@ import requests
4
  import pandas as pd
5
  from io import BytesIO
6
  import re
7
- import ffmpeg # Using the ffmpeg-python wrapper
 
8
 
9
  # --- Tool-specific Imports ---
10
  from pytube import YouTube
 
11
 
12
  # --- LangChain & Dependency Imports ---
13
  from groq import Groq
@@ -22,6 +24,7 @@ DEFAULT_API_URL = "https://agents-course-unit4-scoring.hf.space"
22
  TEMP_DIR = "/tmp"
23
 
24
  # --- Tool Definition: Audio File Transcription ---
 
25
  def transcribe_audio_file(task_id: str) -> str:
26
  """
27
  Downloads an audio file (.mp3) for a given task_id, transcribes it, and returns the text.
@@ -40,31 +43,31 @@ def transcribe_audio_file(task_id: str) -> str:
40
  except Exception as e:
41
  return f"Error during audio file transcription: {e}"
42
 
43
- # --- Tool Definition: Video Transcription (using ffmpeg-python) ---
 
44
  def transcribe_youtube_video(video_url: str) -> str:
45
  """
46
- Downloads a YouTube video from a URL, extracts its audio using FFmpeg, and transcribes it.
47
  Use this tool ONLY when a question provides a youtube.com URL.
48
  """
49
- print(f"Tool 'transcribe_youtube_video' (ffmpeg-python) called with URL: {video_url}")
50
  video_path, audio_path = None, None
51
  try:
 
 
 
 
 
 
 
52
  os.makedirs(TEMP_DIR, exist_ok=True)
53
  yt = YouTube(video_url)
54
  stream = yt.streams.filter(only_audio=True).first()
55
  video_path = stream.download(output_path=TEMP_DIR)
56
  audio_path = os.path.join(TEMP_DIR, "output.mp3")
57
-
58
- # Use ffmpeg-python to convert the downloaded file to mp3
59
- (
60
- ffmpeg
61
- .input(video_path)
62
- .output(audio_path, **{'q:a': 0, 'map': 'a'}) # Set audio quality and select audio stream
63
- .overwrite_output() # Corresponds to the -y flag
64
- .run(quiet=True) # Use quiet=True to avoid printing ffmpeg logs
65
- )
66
-
67
- print(f"Audio extracted to: {audio_path}")
68
  client = Groq(api_key=os.getenv("GROQ_API_KEY"))
69
  with open(audio_path, "rb") as audio_file:
70
  transcription = client.audio.transcriptions.create(file=audio_file, model="whisper-large-v3", response_format="text")
@@ -72,10 +75,8 @@ def transcribe_youtube_video(video_url: str) -> str:
72
  except Exception as e:
73
  return f"Error during YouTube transcription: {e}"
74
  finally:
75
- # Clean up temporary files
76
  if video_path and os.path.exists(video_path): os.remove(video_path)
77
  if audio_path and os.path.exists(audio_path): os.remove(audio_path)
78
- print("Cleaned up temporary files.")
79
 
80
  # --- Agent Definition ---
81
  class LangChainAgent:
@@ -95,9 +96,10 @@ class LangChainAgent:
95
  "2. **Select ONE tool based on the question:**\n"
96
  " - For general knowledge, facts, or current events: use `web_search`.\n"
97
  " - For an audio file, .mp3, or voice memo: use `audio_file_transcriber` with the `task_id`.\n"
98
- " - For a youtube.com URL: use `youtube_video_transcriber` with the URL.\n"
99
  " - For anything else (like images, which you cannot see, or math), you must answer directly without using a tool.\n"
100
- "3. **Execute and Answer:** After using a tool, analyze the result and provide ONLY THE FINAL ANSWER."
 
101
  )),
102
  ("human", "Question: {input}\nTask ID: {task_id}"),
103
  ("placeholder", "{agent_scratchpad}"),
@@ -169,7 +171,7 @@ with gr.Blocks() as demo:
169
 
170
  if __name__ == "__main__":
171
  print("\n" + "-"*30 + " App Starting " + "-"*30)
172
- for key in ["GROQ_API_KEY", "TAVILY_API_KEY"]:
173
  print(f"✅ {key} secret is set." if os.getenv(key) else f"⚠️ WARNING: {key} secret is not set.")
174
  print("-"*(60 + len(" App Starting ")) + "\n")
175
- demo.launch(debug=True, share=False)
 
4
  import pandas as pd
5
  from io import BytesIO
6
  import re
7
+ import ffmpeg
8
+ from tenacity import retry, stop_after_attempt, wait_fixed
9
 
10
  # --- Tool-specific Imports ---
11
  from pytube import YouTube
12
+ from youtube_transcript_api import YouTubeTranscriptApi, NoTranscriptFound
13
 
14
  # --- LangChain & Dependency Imports ---
15
  from groq import Groq
 
24
  TEMP_DIR = "/tmp"
25
 
26
  # --- Tool Definition: Audio File Transcription ---
27
+ @retry(stop=stop_after_attempt(3), wait=wait_fixed(2))
28
  def transcribe_audio_file(task_id: str) -> str:
29
  """
30
  Downloads an audio file (.mp3) for a given task_id, transcribes it, and returns the text.
 
43
  except Exception as e:
44
  return f"Error during audio file transcription: {e}"
45
 
46
+ # --- Tool Definition: Video Transcription (prioritizing transcripts) ---
47
+ @retry(stop=stop_after_attempt(3), wait=wait_fixed(2))
48
  def transcribe_youtube_video(video_url: str) -> str:
49
  """
50
+ Fetches a transcript for a YouTube video from a URL, falling back to download and transcription if needed.
51
  Use this tool ONLY when a question provides a youtube.com URL.
52
  """
53
+ print(f"Tool 'transcribe_youtube_video' called with URL: {video_url}")
54
  video_path, audio_path = None, None
55
  try:
56
+ # Extract video ID and try to fetch official transcript
57
+ video_id = re.search(r"(?:v=|\/)([0-9A-Za-z_-]{11}).*", video_url).group(1)
58
+ transcript = YouTubeTranscriptApi.get_transcript(video_id)
59
+ return ' '.join([entry['text'] for entry in transcript])
60
+ except NoTranscriptFound:
61
+ print("No transcript found; falling back to download and transcribe.")
62
+ # Fallback to original download logic
63
  os.makedirs(TEMP_DIR, exist_ok=True)
64
  yt = YouTube(video_url)
65
  stream = yt.streams.filter(only_audio=True).first()
66
  video_path = stream.download(output_path=TEMP_DIR)
67
  audio_path = os.path.join(TEMP_DIR, "output.mp3")
68
+ stream = ffmpeg.input(video_path)
69
+ stream = ffmpeg.output(stream, audio_path, q=0, map='a', y='y')
70
+ ffmpeg.run(stream)
 
 
 
 
 
 
 
 
71
  client = Groq(api_key=os.getenv("GROQ_API_KEY"))
72
  with open(audio_path, "rb") as audio_file:
73
  transcription = client.audio.transcriptions.create(file=audio_file, model="whisper-large-v3", response_format="text")
 
75
  except Exception as e:
76
  return f"Error during YouTube transcription: {e}"
77
  finally:
 
78
  if video_path and os.path.exists(video_path): os.remove(video_path)
79
  if audio_path and os.path.exists(audio_path): os.remove(audio_path)
 
80
 
81
  # --- Agent Definition ---
82
  class LangChainAgent:
 
96
  "2. **Select ONE tool based on the question:**\n"
97
  " - For general knowledge, facts, or current events: use `web_search`.\n"
98
  " - For an audio file, .mp3, or voice memo: use `audio_file_transcriber` with the `task_id`.\n"
99
+ " - For a youtube.com URL: use `youtube_video_transcriber` with the URL. If transcription fails, fall back to web_search for video transcripts or summaries.\n"
100
  " - For anything else (like images, which you cannot see, or math), you must answer directly without using a tool.\n"
101
+ "3. **Handle Errors:** If a tool fails (e.g., download error), retry once or use web_search to find alternatives.\n"
102
+ "4. **Execute and Answer:** After using a tool, analyze the result and provide ONLY THE FINAL ANSWER without extra text like 'FINAL ANSWER'."
103
  )),
104
  ("human", "Question: {input}\nTask ID: {task_id}"),
105
  ("placeholder", "{agent_scratchpad}"),
 
171
 
172
  if __name__ == "__main__":
173
  print("\n" + "-"*30 + " App Starting " + "-"*30)
174
+ for key in ["GROQ_API_KEY", "TAVILY_API_KEY", "SPACE_ID"]:
175
  print(f"✅ {key} secret is set." if os.getenv(key) else f"⚠️ WARNING: {key} secret is not set.")
176
  print("-"*(60 + len(" App Starting ")) + "\n")
177
+ demo.launch(debug=True, share=False)