divython commited on
Commit
a509a5a
·
verified ·
1 Parent(s): 3009fd5

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +132 -82
app.py CHANGED
@@ -6,40 +6,80 @@ import subprocess
6
  from transformers import pipeline
7
 
8
  # --- Configuration ---
9
- # Choose a smaller Whisper model for Hugging Face Spaces to avoid out-of-memory errors.
10
- # 'base' or 'small' are good starting points. 'medium' or 'large' might require more resources.
11
  WHISPER_MODEL_SIZE = "base"
12
 
13
  # Choose a summarization model. 'sshleifer/distilbart-cnn-12-6' is a good balance
14
  # of performance and size for summarization.
15
  SUMMARIZATION_MODEL = "sshleifer/distilbart-cnn-12-6"
16
 
17
- # Define the path to the cookies file. Make sure you have uploaded 'cookies.txt'
18
- # to the root directory of your Hugging Face Space.
 
19
  COOKIES_FILE_PATH = "cookies.txt"
20
 
21
- # --- Load Models (once at startup) ---
22
- # Load the Whisper ASR model
23
- print(f"Loading Whisper model: {WHISPER_MODEL_SIZE}...")
24
- whisper_model = whisper.load_model(WHISPER_MODEL_SIZE)
25
- print("Whisper model loaded.")
26
-
27
- # Load the summarization pipeline
28
- print(f"Loading summarization model: {SUMMARIZATION_MODEL}...")
29
- summarizer = pipeline("summarization", model=SUMMARIZATION_MODEL)
30
- print("Summarization model loaded.")
31
-
32
- # --- Core Functions ---
33
-
34
- def download_and_extract_audio(youtube_url):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
35
  """
36
- Downloads a YouTube video and extracts its audio.
37
- Returns a tuple: (path to extracted audio file or None, error message or None).
38
  """
39
- video_id = youtube_url.split("v=")[-1].split("&")[0] # Extract video ID
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
40
  audio_path = f"/tmp/{video_id}.mp3"
41
 
42
- # yt-dlp options to download best audio only
43
  ydl_opts = {
44
  'format': 'bestaudio/best',
45
  'postprocessors': [{
@@ -51,46 +91,45 @@ def download_and_extract_audio(youtube_url):
51
  'noplaylist': True,
52
  'quiet': True,
53
  'no_warnings': True,
 
54
  }
55
 
56
- # Add cookies if the file exists
57
  if os.path.exists(COOKIES_FILE_PATH):
58
  ydl_opts['cookiefile'] = COOKIES_FILE_PATH
59
- print(f"Using cookies from {COOKIES_FILE_PATH}")
60
  else:
61
- print(f"Cookies file not found at {COOKIES_FILE_PATH}. Proceeding without cookies.")
 
62
 
63
 
64
  try:
65
- print(f"Downloading audio for {youtube_url} to {audio_path}...")
66
  with yt_dlp.YoutubeDL(ydl_opts) as ydl:
67
  ydl.download([youtube_url])
68
- print("Audio download and extraction complete.")
69
- return audio_path, None
 
 
 
 
 
 
 
 
70
  except yt_dlp.utils.DownloadError as e:
71
- error_message = f"Download Error: {e.exc_info[1].msg if e.exc_info else str(e)}"
72
  print(error_message)
73
  return None, error_message
74
  except Exception as e:
75
- error_message = f"An unexpected error occurred during download: {str(e)}"
76
  print(error_message)
77
  return None, error_message
 
 
 
 
78
 
79
- def transcribe_audio(audio_file_path):
80
- """
81
- Transcribes the given audio file using the loaded Whisper model.
82
- Returns the transcribed text.
83
- """
84
- print(f"Transcribing audio from {audio_file_path} using Whisper...")
85
- try:
86
- # Transcribe using the loaded Whisper model
87
- result = whisper_model.transcribe(audio_file_path, fp16=False) # fp16=False for CPU inference
88
- transcript = result["text"]
89
- print("Transcription complete.")
90
- return transcript
91
- except Exception as e:
92
- print(f"Error during transcription: {e}")
93
- return "Transcription failed."
94
 
95
  def summarize_text(text):
96
  """
@@ -99,64 +138,75 @@ def summarize_text(text):
99
  """
100
  print("Summarizing text...")
101
  try:
102
- # The summarizer pipeline can handle long texts by chunking them internally,
103
- # but for very long videos, it might still struggle or be slow.
104
- # min_length and max_length control the summary length.
105
- summary = summarizer(text, max_length=500, min_length=50, do_sample=False)[0]['summary_text']
106
  print("Summarization complete.")
107
  return summary
108
  except Exception as e:
109
  print(f"Error during summarization: {e}")
110
  return "Summarization failed."
111
 
 
 
112
  def process_youtube_video(youtube_url):
113
  """
114
- Main function to process the YouTube video: download, transcribe, and summarize.
115
  """
116
- # 1. Download and Extract Audio
117
- audio_file_path, download_error = download_and_extract_audio(youtube_url)
118
- if download_error:
119
- return f"Failed to download or extract audio: {download_error}", "N/A"
120
- if not audio_file_path or not os.path.exists(audio_file_path):
121
- return "Failed to download or extract audio due to an unknown reason.", "N/A"
122
-
123
- # 2. Transcribe Audio
124
- transcript = transcribe_audio(audio_file_path)
125
-
126
- # 3. Summarize Transcript
127
- summary = summarize_text(transcript)
 
 
128
 
129
- # 4. Clean up temporary audio file
130
- if os.path.exists(audio_file_path):
131
- os.remove(audio_file_path)
132
- print(f"Cleaned up {audio_file_path}")
133
 
134
- return transcript, summary
135
 
136
  # --- Gradio Interface ---
137
  iface = gr.Interface(
138
  fn=process_youtube_video,
139
  inputs=gr.Textbox(label="Enter YouTube Video URL (e.g., https://www.youtube.com/watch?v=dQw4w9WgXcQ)"),
140
  outputs=[
141
- gr.Textbox(label="Full Transcript", lines=15),
142
- gr.Textbox(label="Summary/Notes", lines=10)
143
  ],
144
- title="Mini NotebookLM: YouTube Video Summarizer",
145
  description=(
146
- "Enter a YouTube video URL, and this tool will download its audio, "
147
- "transcribe it using OpenAI Whisper, and then generate a summary/notes."
148
- "<br><b>Note:</b> If you encounter download issues (e.g., 'Sign in to confirm you’re not a bot'), "
149
- "ensure you have uploaded a `cookies.txt` file (exported from your browser) to the root of this Hugging Face Space. "
150
- "You can typically export cookies using browser extensions like 'Get cookies.txt' or similar."
151
- "<br><b>Performance:</b> Analyzing long videos (e.g., 1 hour+) can take a significant amount of time "
152
- "and consume considerable resources, especially on CPU-only Hugging Face Spaces. "
153
- "For faster processing of long videos, consider upgrading your Hugging Face Space to a GPU instance."
 
 
 
 
 
 
 
154
  ),
155
- allow_flagging="auto", # Allows users to flag results for review
156
  examples=[
157
- ["https://www.youtube.com/watch?v=jNQXAC9IVRw"], # Updated example: A short educational video
 
158
  ]
159
  )
160
 
161
- # Launch the Gradio app
162
- iface.launch()
 
6
  from transformers import pipeline
7
 
8
  # --- Configuration ---
9
+ # Using 'base' Whisper model for significantly reduced resource usage.
10
+ # This is ideal for free Colab tiers or Hugging Face Spaces with limited CPU/GPU.
11
  WHISPER_MODEL_SIZE = "base"
12
 
13
  # Choose a summarization model. 'sshleifer/distilbart-cnn-12-6' is a good balance
14
  # of performance and size for summarization.
15
  SUMMARIZATION_MODEL = "sshleifer/distilbart-cnn-12-6"
16
 
17
+ # Path to your downloaded cookies.txt file.
18
+ # IMPORTANT: You MUST upload 'cookies.txt' (exported from your browser after logging into YouTube)
19
+ # to the root directory of your Colab notebook or Hugging Face Space for this to work.
20
  COOKIES_FILE_PATH = "cookies.txt"
21
 
22
+ # --- Global Variables for Models (loaded once) ---
23
+ whisper_model = None
24
+ summarizer_pipeline = None
25
+
26
+ # --- Setup Function to Install Libraries and Load Models ---
27
+ def setup_environment():
28
+ """Installs necessary libraries and loads AI models."""
29
+ print("Installing required libraries...")
30
+ # Use !pip install for Colab
31
+ !pip install -q gradio yt-dlp openai-whisper transformers ffmpeg-python
32
+
33
+ global whisper_model, summarizer_pipeline
34
+
35
+ if whisper_model is None:
36
+ print(f"Loading Whisper model: {WHISPER_MODEL_SIZE}...")
37
+ try:
38
+ # Check for GPU and set device
39
+ import torch
40
+ device = "cuda" if torch.cuda.is_available() else "cpu"
41
+ print(f"Using device: {device}")
42
+ whisper_model = whisper.load_model(WHISPER_MODEL_SIZE, device=device)
43
+ print("Whisper model loaded.")
44
+ except Exception as e:
45
+ print(f"Error loading Whisper model: {e}. Falling back to CPU.")
46
+ whisper_model = whisper.load_model(WHISPER_MODEL_SIZE, device="cpu")
47
+ print("Whisper model loaded on CPU.")
48
+
49
+ if summarizer_pipeline is None:
50
+ print(f"Loading summarization model: {SUMMARIZATION_MODEL}...")
51
+ summarizer_pipeline = pipeline("summarization", model=SUMMARIZATION_MODEL)
52
+ print("Summarization model loaded.")
53
+
54
+ # Call setup function once at the start of the Colab session
55
+ setup_environment()
56
+
57
+ # --- Audio Download and Transcription ---
58
+
59
+ def download_and_transcribe_audio(youtube_url):
60
  """
61
+ Downloads audio from YouTube and transcribes it using Whisper.
62
+ Returns transcript or error message.
63
  """
64
+ video_id = None
65
+ try:
66
+ from urllib.parse import urlparse, parse_qs
67
+ parsed_url = urlparse(youtube_url)
68
+ if parsed_url.hostname in ['www.youtube.com', 'youtube.com', 'm.youtube.com']:
69
+ video_id = parse_qs(parsed_url.query).get('v')
70
+ if video_id:
71
+ video_id = video_id[0]
72
+ elif parsed_url.hostname == 'youtu.be':
73
+ video_id = parsed_url.path[1:]
74
+
75
+ if not video_id:
76
+ return None, "Invalid YouTube URL provided. Please check the format."
77
+
78
+ except Exception as e:
79
+ return None, f"Error parsing YouTube URL: {e}"
80
+
81
  audio_path = f"/tmp/{video_id}.mp3"
82
 
 
83
  ydl_opts = {
84
  'format': 'bestaudio/best',
85
  'postprocessors': [{
 
91
  'noplaylist': True,
92
  'quiet': True,
93
  'no_warnings': True,
94
+ 'user_agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36',
95
  }
96
 
 
97
  if os.path.exists(COOKIES_FILE_PATH):
98
  ydl_opts['cookiefile'] = COOKIES_FILE_PATH
99
+ print(f"Using cookies from {COOKIES_FILE_PATH} for yt-dlp download.")
100
  else:
101
+ print(f"WARNING: {COOKIES_FILE_PATH} not found. Proceeding without cookies. "
102
+ "Downloads may fail due to bot detection. Please upload a valid cookies.txt.")
103
 
104
 
105
  try:
106
+ print(f"Downloading audio for {youtube_url} to {audio_path} using yt-dlp...")
107
  with yt_dlp.YoutubeDL(ydl_opts) as ydl:
108
  ydl.download([youtube_url])
109
+ print("Audio download complete.")
110
+
111
+ print(f"Transcribing audio from {audio_path} using Whisper ({WHISPER_MODEL_SIZE})...")
112
+ if whisper_model is None:
113
+ setup_environment()
114
+
115
+ result = whisper_model.transcribe(audio_path, fp16=False)
116
+ transcript = result["text"]
117
+ print("Transcription complete.")
118
+ return transcript, None
119
  except yt_dlp.utils.DownloadError as e:
120
+ error_message = f"Download Error (yt-dlp): {e.exc_info[1].msg if e.exc_info else str(e)}"
121
  print(error_message)
122
  return None, error_message
123
  except Exception as e:
124
+ error_message = f"An unexpected error occurred during audio processing: {str(e)}"
125
  print(error_message)
126
  return None, error_message
127
+ finally:
128
+ if os.path.exists(audio_path):
129
+ os.remove(audio_path)
130
+ print(f"Cleaned up {audio_path}")
131
 
132
+ # --- Text Summarization ---
 
 
 
 
 
 
 
 
 
 
 
 
 
 
133
 
134
  def summarize_text(text):
135
  """
 
138
  """
139
  print("Summarizing text...")
140
  try:
141
+ if summarizer_pipeline is None:
142
+ setup_environment()
143
+
144
+ summary = summarizer_pipeline(text, max_length=500, min_length=50, do_sample=False)[0]['summary_text']
145
  print("Summarization complete.")
146
  return summary
147
  except Exception as e:
148
  print(f"Error during summarization: {e}")
149
  return "Summarization failed."
150
 
151
+ # --- Main Processing Function ---
152
+
153
  def process_youtube_video(youtube_url):
154
  """
155
+ Main function to process the YouTube video: download audio, transcribe, and summarize.
156
  """
157
+ full_transcript = "N/A"
158
+ summary_notes = "N/A"
159
+
160
+ if whisper_model is None or summarizer_pipeline is None:
161
+ setup_environment()
162
+ if whisper_model is None or summarizer_pipeline is None:
163
+ return "Error: Failed to load AI models. Please check Colab environment.", "N/A"
164
+
165
+ transcribed_text, audio_error = download_and_transcribe_audio(youtube_url)
166
+ if transcribed_text:
167
+ full_transcript = transcribed_text
168
+ else:
169
+ full_transcript = f"Failed to get transcript: {audio_error}"
170
+ return full_transcript, summary_notes
171
 
172
+ if full_transcript and not full_transcript.startswith("Failed to get transcript"):
173
+ summary_notes = summarize_text(full_transcript)
174
+ else:
175
+ summary_notes = "Cannot summarize due to failed transcription."
176
 
177
+ return full_transcript, summary_notes
178
 
179
  # --- Gradio Interface ---
180
  iface = gr.Interface(
181
  fn=process_youtube_video,
182
  inputs=gr.Textbox(label="Enter YouTube Video URL (e.g., https://www.youtube.com/watch?v=dQw4w9WgXcQ)"),
183
  outputs=[
184
+ gr.Textbox(label="Full Transcript", lines=15, interactive=False),
185
+ gr.Textbox(label="Summary/Notes", lines=10, interactive=False)
186
  ],
187
+ title="Mini-Mini NotebookLM: YouTube Video Summarizer (Colab/Hugging Face)",
188
  description=(
189
+ "This is a smaller, more resource-efficient version of NotebookLM. "
190
+ "Enter a YouTube video URL. This tool will download its audio using `yt-dlp`, "
191
+ "transcribe it using OpenAI Whisper (using the smaller 'base' model), "
192
+ "and then generate a summary/notes."
193
+ "<br><br><b>Important Setup Steps (One-Time in Colab/Hugging Face Spaces):</b>"
194
+ "<ol>"
195
+ "<li><b>Export `cookies.txt` from your browser:</b> Use a browser extension like 'Get cookies.txt' (for Chrome/Firefox) "
196
+ "after logging into YouTube. This file contains your session cookies, which `yt-dlp` needs to bypass YouTube's bot detection.</li>"
197
+ "<li><b>Upload `cookies.txt` to the root directory of your Colab notebook or Hugging Face Space.</b></li>"
198
+ "</ol>"
199
+ "<b>Performance Note:</b> While this version is optimized, analyzing long videos (e.g., 1 hour+) can still take a significant amount of time "
200
+ "and consume considerable resources, especially on free tiers. For faster results, try shorter videos."
201
+ "<br><b>Troubleshooting Downloads:</b> If downloads still fail with 'Sign in to confirm you’re not a bot', "
202
+ "your `cookies.txt` might be invalid or expired, or YouTube's detection has become more aggressive. "
203
+ "There are no other direct, free, and reliable methods to bypass YouTube's restrictions without using their official APIs."
204
  ),
205
+ allow_flagging="auto",
206
  examples=[
207
+ ["https://www.youtube.com/watch?v=jNQXAC9IVRw"], # Short educational video
208
+ ["https://www.youtube.com/watch?v=kfS7W0-JtQo"] # Another example
209
  ]
210
  )
211
 
212
+ iface.launch(debug=True)