HARISH20205 commited on
Commit
016fc9a
·
1 Parent(s): dfa9d54
Files changed (3) hide show
  1. Dockerfile +13 -5
  2. app.py +355 -148
  3. requirements.txt +3 -1
Dockerfile CHANGED
@@ -6,21 +6,29 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
6
  ffmpeg \
7
  build-essential \
8
  libsndfile1 \
 
 
9
  && apt-get clean \
10
- && rm -rf /var/lib/apt/lists/*
 
11
 
12
  COPY requirements.txt .
13
 
14
- RUN pip install --no-cache-dir -r requirements.txt
 
15
 
16
  COPY . .
17
 
18
- RUN mkdir -p /app/static/audio
 
19
 
20
  EXPOSE 7860
21
 
22
  ENV PYTHONDONTWRITEBYTECODE=1 \
23
  PYTHONUNBUFFERED=1 \
24
- MODEL_NAME="google/pegasus-xsum"
 
 
 
25
 
26
- CMD ["gunicorn", "--bind", "0.0.0.0:7860", "app:app"]
 
6
  ffmpeg \
7
  build-essential \
8
  libsndfile1 \
9
+ ca-certificates \
10
+ openssl \
11
  && apt-get clean \
12
+ && rm -rf /var/lib/apt/lists/* \
13
+ && update-ca-certificates
14
 
15
  COPY requirements.txt .
16
 
17
+ RUN pip install --no-cache-dir -r requirements.txt \
18
+ && pip install --no-cache-dir pytube
19
 
20
  COPY . .
21
 
22
+ RUN mkdir -p /app/static/audio /tmp/yt-dlp
23
+ RUN chmod -R 777 /tmp
24
 
25
  EXPOSE 7860
26
 
27
  ENV PYTHONDONTWRITEBYTECODE=1 \
28
  PYTHONUNBUFFERED=1 \
29
+ MODEL_NAME="google/pegasus-xsum" \
30
+ PYTHONHTTPSVERIFY=0 \
31
+ SSL_CERT_DIR=/etc/ssl/certs \
32
+ REQUESTS_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crt
33
 
34
+ CMD ["gunicorn", "--bind", "0.0.0.0:7860", "--timeout", "300", "--workers", "1", "app:app"]
app.py CHANGED
@@ -16,17 +16,47 @@ import tempfile
16
 
17
  load_dotenv()
18
 
19
- # Create directories with proper permissions
20
- for directory in ["/tmp/transformers_cache", "/tmp/hf_home", "/tmp/cache"]:
21
- os.makedirs(directory, exist_ok=True)
22
- # Ensure the directory is writeable
23
- os.chmod(directory, 0o777)
24
-
25
- # Set environment variables after creating directories
26
- os.environ["TRANSFORMERS_CACHE"] = "/tmp/transformers_cache"
27
- os.environ["HF_HOME"] = "/tmp/hf_home"
28
- os.environ["XDG_CACHE_HOME"] = "/tmp/cache"
29
- os.environ["PYTHONHTTPSVERIFY"] = "0" # Added to help with SSL issues
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
30
 
31
  app = Flask(__name__)
32
 
@@ -61,25 +91,78 @@ def load_pegasus_model():
61
  return tokenizer, model
62
 
63
 
64
- def transcribe_audio_with_whisper(audio_data, timeout=180): # 3 minute timeout
65
  try:
66
  logging.info("Transcribing audio data")
67
  start_time = time.time()
68
  model = load_whisper_model()
69
 
70
- with tempfile.NamedTemporaryFile(suffix=".mp3", delete=True) as temp_file:
71
  if isinstance(audio_data, io.BytesIO):
72
  temp_file.write(audio_data.getvalue())
73
  else:
74
  temp_file.write(audio_data)
75
  temp_file.flush()
 
76
 
77
- # Add timeout monitoring
78
- result = model.transcribe(temp_file.name)
79
- elapsed = time.time() - start_time
80
- logging.info(f"Transcription completed in {elapsed:.2f} seconds")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
81
 
82
  return result["text"]
 
 
 
 
 
83
  except Exception as e:
84
  logging.error(f"Error in audio transcription: {e}")
85
  raise ValueError(f"Error in audio transcription: {e}")
@@ -113,146 +196,209 @@ def summarize_text_with_pegasus(text, tokenizer, model):
113
  raise ValueError(f"Error in text summarization: {e}")
114
 
115
 
116
- def download_audio_from_youtube(url):
117
- buffer = io.BytesIO()
118
-
119
- # Create a temp directory for cookies with correct permissions
120
- cookie_dir = tempfile.mkdtemp()
121
- cookies_path = os.path.join(cookie_dir, "cookies.txt")
122
-
123
- # Create an empty cookies file with appropriate permissions
124
- with open(cookies_path, "w") as f:
125
- f.write("")
126
- os.chmod(cookies_path, 0o666)
127
-
128
- ydl_opts = {
129
- "format": "bestaudio/best",
130
- "postprocessors": [
131
- {
132
- "key": "FFmpegExtractAudio",
133
- "preferredcodec": "mp3",
134
- "preferredquality": "192",
135
- }
136
- ],
137
- "outtmpl": "-",
138
- "logtostderr": True,
139
- "quiet": False,
140
- "no_warnings": False,
141
- "extract_audio": True,
142
- "nocheckcertificate": True,
143
- "ignoreerrors": True,
144
- "no_color": True,
145
- "geo_bypass": True,
146
- "cookies": cookies_path, # Use our temp cookies file
147
- "socket_timeout": 30,
148
- "retries": 3,
149
- }
150
-
151
  try:
152
- logging.info(f"Downloading audio from YouTube: {url}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
153
 
154
- # Handle SSL certificate issues
155
- cert_path = os.path.join(tempfile.gettempdir(), "cacert.pem")
156
- import certifi
157
 
158
- with open(cert_path, "wb") as f:
159
- f.write(open(certifi.where(), "rb").read())
 
160
 
161
- os.environ["SSL_CERT_FILE"] = cert_path
162
- os.environ["REQUESTS_CA_BUNDLE"] = cert_path
163
 
164
- # Create a proper temporary file for the download
165
- with tempfile.NamedTemporaryFile(suffix=".%(ext)s", delete=False) as temp_file:
166
- output_path = temp_file.name
167
- ydl_opts["outtmpl"] = output_path
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
168
 
 
169
  try:
170
- with YoutubeDL(ydl_opts) as ydl:
171
- # Add more info messages for debugging
172
- logging.info(f"Starting YouTube download with options: {ydl_opts}")
173
- info = ydl.extract_info(url, download=True)
174
-
175
- if not info:
176
- raise ValueError("Could not fetch video information")
177
-
178
- # Construct the output filename based on yt-dlp's naming pattern
179
- audio_file_path = ydl.prepare_filename(info)
180
-
181
- # Handle different possible extensions
182
- for ext in [".mp3", ".webm.mp3", ".m4a.mp3"]:
183
- possible_path = audio_file_path.replace(".webm", ext).replace(
184
- ".m4a", ext
185
- )
186
- if os.path.exists(possible_path):
187
- audio_file_path = possible_path
188
- break
189
-
190
- logging.info(f"Audio downloaded to: {audio_file_path}")
191
-
192
- if not os.path.exists(audio_file_path):
193
- raise ValueError(
194
- f"Downloaded file {audio_file_path} does not exist"
195
- )
196
-
197
- # Read the file and clean up
198
- with open(audio_file_path, "rb") as audio_file:
199
- buffer = io.BytesIO(audio_file.read())
200
- buffer.seek(0)
201
-
202
- # Remove the temporary file
203
- try:
204
- os.unlink(audio_file_path)
205
- except Exception as cleanup_err:
206
- logging.warning(f"Could not remove temp file: {cleanup_err}")
207
- except Exception as ydl_err:
208
- logging.error(f"YoutubeDL error: {ydl_err}")
209
- # Try alternative download method - direct URL only, no fancy features
210
- logging.info("Attempting alternative download method...")
211
-
212
- simple_opts = {
213
- "format": "bestaudio",
214
- "outtmpl": output_path,
215
- "nocheckcertificate": True,
216
- "quiet": True,
217
- "no_warnings": True,
218
- "geo_bypass": True,
219
- }
220
 
221
- with YoutubeDL(simple_opts) as ydl:
222
- info = ydl.extract_info(url, download=True)
223
- if not info:
224
- raise ValueError("Could not fetch video information")
225
 
226
- audio_file_path = ydl.prepare_filename(info)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
227
 
228
- if not os.path.exists(audio_file_path):
229
- raise ValueError(
230
- f"Downloaded file {audio_file_path} does not exist"
231
- )
232
 
233
- # Read the file
234
- with open(audio_file_path, "rb") as audio_file:
235
- buffer = io.BytesIO(audio_file.read())
236
- buffer.seek(0)
237
 
238
- # Convert to MP3 if needed
239
- if not audio_file_path.endswith(".mp3"):
240
- buffer = convert_audio_to_mp3(
241
- buffer.getvalue(),
242
- original_format=audio_file_path.split(".")[-1],
243
- )
244
 
245
- # Clean up the temp directory
 
 
 
 
 
 
246
  try:
247
- os.unlink(cookies_path)
248
- os.rmdir(cookie_dir)
249
- except:
250
- pass
251
 
252
  return buffer
 
253
  except Exception as e:
254
- logging.error(f"Unexpected error downloading audio: {e}", exc_info=True)
255
- raise ValueError(f"Error downloading audio from YouTube: {e}")
 
 
 
 
 
 
 
256
 
257
 
258
  def allowed_file(filename):
@@ -281,56 +427,117 @@ def index():
281
 
282
  @app.route("/transcribe", methods=["POST"])
283
  def transcribe():
 
 
 
 
284
  try:
285
  audio_data = None
286
 
287
  if "url" in request.form and request.form["url"]:
288
- youtube_url = request.form["url"]
 
 
 
 
 
 
 
 
 
 
289
  try:
290
  audio_data = download_audio_from_youtube(youtube_url)
291
- except ValueError as e:
292
- if "bot" in str(e).lower() or "sign in" in str(e).lower():
 
 
 
 
 
 
 
 
 
 
 
 
 
293
  return (
294
  jsonify(
295
  {
296
- "error": "YouTube bot protection is preventing download. Please try uploading an audio file directly instead."
297
  }
298
  ),
299
  400,
300
  )
301
  else:
302
  raise e
 
303
  elif "file" in request.files:
304
  audio_file = request.files["file"]
305
  if not audio_file.filename:
306
  return jsonify({"error": "No file selected."}), 400
 
307
  if not allowed_file(audio_file.filename):
308
  return (
309
  jsonify(
310
- {"error": "Invalid file type. Please upload an audio file."}
 
 
311
  ),
312
  400,
313
  )
314
 
315
  audio_bytes = audio_file.read()
316
  file_format = audio_file.filename.rsplit(".", 1)[1].lower()
 
 
 
 
317
  audio_data = convert_audio_to_mp3(audio_bytes, original_format=file_format)
 
 
 
318
  else:
319
  return jsonify({"error": "No audio file or URL provided."}), 400
320
 
 
 
321
  transcription = transcribe_audio_with_whisper(audio_data)
 
 
 
 
322
 
323
  if transcription:
 
 
324
  tokenizer, model = load_pegasus_model()
325
  summary = summarize_text_with_pegasus(transcription, tokenizer, model)
 
 
 
 
 
 
 
 
326
  return jsonify({"transcription": transcription, "summary": summary})
327
  else:
328
- return jsonify({"error": "Transcription failed."}), 500
 
329
  except ValueError as e:
 
330
  return jsonify({"error": str(e)}), 400
331
  except Exception as e:
332
- logging.error(f"An unexpected error occurred: {e}")
333
- return jsonify({"error": "An unexpected error occurred."}), 500
 
 
 
 
 
334
 
335
 
336
  if __name__ == "__main__":
 
16
 
17
  load_dotenv()
18
 
19
+
20
+ def setup_environment():
21
+ """Configure environment for Hugging Face Spaces"""
22
+ # Create directories with proper permissions
23
+ for directory in [
24
+ "/tmp/transformers_cache",
25
+ "/tmp/hf_home",
26
+ "/tmp/cache",
27
+ "/tmp/yt-dlp",
28
+ "/tmp/certs",
29
+ ]:
30
+ os.makedirs(directory, exist_ok=True)
31
+ try:
32
+ # Ensure the directory is writeable
33
+ os.chmod(directory, 0o777)
34
+ except Exception as e:
35
+ logging.warning(f"Could not set permissions on {directory}: {e}")
36
+
37
+ # Set environment variables
38
+ os.environ["TRANSFORMERS_CACHE"] = "/tmp/transformers_cache"
39
+ os.environ["HF_HOME"] = "/tmp/hf_home"
40
+ os.environ["XDG_CACHE_HOME"] = "/tmp/cache"
41
+
42
+ # Certificate handling
43
+ os.environ["PYTHONHTTPSVERIFY"] = "0"
44
+ os.environ["REQUESTS_CA_BUNDLE"] = "/etc/ssl/certs/ca-certificates.crt"
45
+ os.environ["SSL_CERT_DIR"] = "/etc/ssl/certs"
46
+
47
+ # Set this to the temp directory to avoid permission issues
48
+ os.environ["HOME"] = "/tmp"
49
+
50
+ # For yt-dlp
51
+ os.environ["no_proxy"] = "*"
52
+
53
+ # Disable warnings that might flood logs
54
+ import warnings
55
+
56
+ warnings.filterwarnings("ignore", category=UserWarning)
57
+
58
+
59
+ setup_environment()
60
 
61
  app = Flask(__name__)
62
 
 
91
  return tokenizer, model
92
 
93
 
94
+ def transcribe_audio_with_whisper(audio_data, timeout=300): # 5 minute timeout
95
  try:
96
  logging.info("Transcribing audio data")
97
  start_time = time.time()
98
  model = load_whisper_model()
99
 
100
+ with tempfile.NamedTemporaryFile(suffix=".mp3", delete=False) as temp_file:
101
  if isinstance(audio_data, io.BytesIO):
102
  temp_file.write(audio_data.getvalue())
103
  else:
104
  temp_file.write(audio_data)
105
  temp_file.flush()
106
+ temp_file_path = temp_file.name
107
 
108
+ try:
109
+ # Use multiprocessing to implement a timeout
110
+ from multiprocessing import Process, Queue
111
+
112
+ def transcribe_process(file_path, result_queue):
113
+ try:
114
+ model = load_whisper_model()
115
+ result = model.transcribe(file_path)
116
+ result_queue.put(result)
117
+ except Exception as e:
118
+ result_queue.put(e)
119
+
120
+ # Create a queue for the result
121
+ result_queue = Queue()
122
+ # Create and start the process
123
+ process = Process(
124
+ target=transcribe_process, args=(temp_file_path, result_queue)
125
+ )
126
+ process.start()
127
+
128
+ # Wait for the specified timeout
129
+ process.join(timeout)
130
+
131
+ # If process is still running after timeout, terminate it
132
+ if process.is_alive():
133
+ process.terminate()
134
+ process.join()
135
+ os.unlink(temp_file_path) # Clean up
136
+ raise TimeoutError(f"Transcription timed out after {timeout} seconds")
137
+
138
+ # Get the result
139
+ if result_queue.empty():
140
+ os.unlink(temp_file_path) # Clean up
141
+ raise ValueError("Transcription process failed")
142
+
143
+ result_or_error = result_queue.get()
144
+ if isinstance(result_or_error, Exception):
145
+ os.unlink(temp_file_path) # Clean up
146
+ raise result_or_error
147
+
148
+ result = result_or_error
149
+
150
+ finally:
151
+ # Clean up temp file
152
+ try:
153
+ os.unlink(temp_file_path)
154
+ except:
155
+ pass
156
+
157
+ elapsed = time.time() - start_time
158
+ logging.info(f"Transcription completed in {elapsed:.2f} seconds")
159
 
160
  return result["text"]
161
+ except TimeoutError as e:
162
+ logging.error(f"Transcription timeout: {e}")
163
+ raise ValueError(
164
+ "Audio transcription took too long. Please try a shorter audio file."
165
+ )
166
  except Exception as e:
167
  logging.error(f"Error in audio transcription: {e}")
168
  raise ValueError(f"Error in audio transcription: {e}")
 
196
  raise ValueError(f"Error in text summarization: {e}")
197
 
198
 
199
+ def download_youtube_with_cookies(url):
200
+ """Download YouTube audio using the project's cookies file"""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
201
  try:
202
+ logging.info(f"Downloading YouTube with cookies: {url}")
203
+ # Use the cookies.txt from the project directory
204
+ cookies_path = os.path.join(os.getcwd(), "cookies.txt")
205
+
206
+ if not os.path.exists(cookies_path):
207
+ logging.warning("cookies.txt not found in project directory")
208
+ # Create an empty cookies file
209
+ with open(cookies_path, "w") as f:
210
+ f.write("# Netscape HTTP Cookie File\n")
211
+
212
+ logging.info(f"Using cookies from: {cookies_path}")
213
+
214
+ output_dir = "/tmp/yt_downloads"
215
+ os.makedirs(output_dir, exist_ok=True)
216
+ os.chmod(output_dir, 0o777)
217
+
218
+ output_path = os.path.join(output_dir, f"download_{int(time.time())}.%(ext)s")
219
+
220
+ ydl_opts = {
221
+ "format": "bestaudio/best",
222
+ "postprocessors": [
223
+ {
224
+ "key": "FFmpegExtractAudio",
225
+ "preferredcodec": "mp3",
226
+ "preferredquality": "192",
227
+ }
228
+ ],
229
+ "outtmpl": output_path,
230
+ "cookies": cookies_path,
231
+ "nocheckcertificate": True,
232
+ "ignoreerrors": True,
233
+ "geo_bypass": True,
234
+ "logtostderr": True,
235
+ "quiet": False,
236
+ "no_warnings": False,
237
+ "socket_timeout": 30,
238
+ "retries": 5,
239
+ }
240
+
241
+ with YoutubeDL(ydl_opts) as ydl:
242
+ info = ydl.extract_info(url, download=True)
243
+ if not info:
244
+ raise ValueError("Could not fetch video information")
245
+
246
+ filename = ydl.prepare_filename(info)
247
+ # Handle potential mp3 extension
248
+ if not filename.endswith(".mp3"):
249
+ filename = filename.rsplit(".", 1)[0] + ".mp3"
250
+
251
+ if not os.path.exists(filename):
252
+ # Try alternative extensions
253
+ for ext in [".mp3", ".webm.mp3", ".m4a.mp3"]:
254
+ alt_filename = filename.rsplit(".", 1)[0] + ext
255
+ if os.path.exists(alt_filename):
256
+ filename = alt_filename
257
+ break
258
+
259
+ logging.info(f"Downloaded file: {filename}")
260
+
261
+ if not os.path.exists(filename):
262
+ raise FileNotFoundError(f"Could not find downloaded file: {filename}")
263
+
264
+ with open(filename, "rb") as f:
265
+ buffer = io.BytesIO(f.read())
266
+ buffer.seek(0)
267
+
268
+ # Clean up
269
+ try:
270
+ os.unlink(filename)
271
+ except Exception as e:
272
+ logging.warning(f"Could not remove temp file: {e}")
273
 
274
+ return buffer
 
 
275
 
276
+ except Exception as e:
277
+ logging.error(f"Error downloading with cookies: {e}", exc_info=True)
278
+ raise ValueError(f"Error downloading with cookies: {e}")
279
 
 
 
280
 
281
+ def download_youtube_direct(url):
282
+ """Direct YouTube download without cookies, simplified options"""
283
+ try:
284
+ logging.info(f"Attempting direct YouTube download: {url}")
285
+
286
+ output_dir = "/tmp/yt_direct"
287
+ os.makedirs(output_dir, exist_ok=True)
288
+ os.chmod(output_dir, 0o777)
289
+
290
+ output_path = os.path.join(output_dir, f"direct_{int(time.time())}.%(ext)s")
291
+
292
+ ydl_opts = {
293
+ "format": "bestaudio",
294
+ "outtmpl": output_path,
295
+ "nocheckcertificate": True,
296
+ "ignoreerrors": False,
297
+ "geo_bypass": True,
298
+ "no_warnings": True,
299
+ "quiet": True,
300
+ "skip_download": False,
301
+ "noprogress": True,
302
+ "nooverwrites": False,
303
+ "socket_timeout": 30,
304
+ }
305
+
306
+ with YoutubeDL(ydl_opts) as ydl:
307
+ info = ydl.extract_info(url, download=True)
308
+ if not info:
309
+ raise ValueError("Could not fetch video information")
310
+
311
+ filename = ydl.prepare_filename(info)
312
+
313
+ if not os.path.exists(filename):
314
+ raise FileNotFoundError(f"Could not find downloaded file: {filename}")
315
+
316
+ with open(filename, "rb") as f:
317
+ data = f.read()
318
+
319
+ # Convert to mp3 if needed
320
+ if not filename.endswith(".mp3"):
321
+ buffer = convert_audio_to_mp3(
322
+ data, original_format=filename.split(".")[-1]
323
+ )
324
+ else:
325
+ buffer = io.BytesIO(data)
326
+ buffer.seek(0)
327
 
328
+ # Clean up
329
  try:
330
+ os.unlink(filename)
331
+ except Exception as e:
332
+ logging.warning(f"Could not remove temp file: {e}")
333
+
334
+ return buffer
335
+
336
+ except Exception as e:
337
+ logging.error(f"Error in direct download: {e}", exc_info=True)
338
+ raise ValueError(f"Error in direct download: {e}")
339
+
340
+
341
+ def download_audio_from_youtube(url):
342
+ """Main YouTube download function with multiple fallback methods"""
343
+ logging.info(f"Starting YouTube download process for: {url}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
344
 
345
+ errors = []
 
 
 
346
 
347
+ # Method 1: Try with project cookies
348
+ try:
349
+ return download_youtube_with_cookies(url)
350
+ except Exception as e:
351
+ logging.warning(f"Cookie download failed: {e}")
352
+ errors.append(f"Cookie method: {str(e)}")
353
+
354
+ # Method 2: Try direct download
355
+ try:
356
+ return download_youtube_direct(url)
357
+ except Exception as e:
358
+ logging.warning(f"Direct download failed: {e}")
359
+ errors.append(f"Direct method: {str(e)}")
360
+
361
+ # Method 3: Try with pytube as last resort
362
+ try:
363
+ logging.info("Attempting download with pytube")
364
+ from pytube import YouTube
365
+
366
+ yt = YouTube(url)
367
+ stream = yt.streams.filter(only_audio=True).first()
368
 
369
+ if not stream:
370
+ raise ValueError("No audio stream found")
 
 
371
 
372
+ output_dir = "/tmp/pytube_downloads"
373
+ os.makedirs(output_dir, exist_ok=True)
 
 
374
 
375
+ output_path = stream.download(output_path=output_dir)
376
+ logging.info(f"Downloaded to: {output_path}")
 
 
 
 
377
 
378
+ with open(output_path, "rb") as f:
379
+ data = f.read()
380
+
381
+ # Convert to mp3
382
+ buffer = convert_audio_to_mp3(data, original_format=output_path.split(".")[-1])
383
+
384
+ # Clean up
385
  try:
386
+ os.unlink(output_path)
387
+ except Exception as e:
388
+ logging.warning(f"Could not remove pytube temp file: {e}")
 
389
 
390
  return buffer
391
+
392
  except Exception as e:
393
+ logging.error(f"Pytube download failed: {e}")
394
+ errors.append(f"Pytube method: {str(e)}")
395
+
396
+ # All methods failed
397
+ error_message = "All download methods failed:\n" + "\n".join(errors)
398
+ logging.error(error_message)
399
+ raise ValueError(
400
+ "Could not download YouTube audio. Please try uploading an audio file directly or use a different URL."
401
+ )
402
 
403
 
404
  def allowed_file(filename):
 
427
 
428
  @app.route("/transcribe", methods=["POST"])
429
  def transcribe():
430
+ # Record the start time
431
+ start_time = time.time()
432
+ logging.info("Starting new transcription request")
433
+
434
  try:
435
  audio_data = None
436
 
437
  if "url" in request.form and request.form["url"]:
438
+ youtube_url = request.form["url"].strip()
439
+ logging.info(f"Processing YouTube URL: {youtube_url}")
440
+
441
+ if not youtube_url.startswith(("http://", "https://")):
442
+ return (
443
+ jsonify(
444
+ {"error": "Invalid URL format. Please provide a complete URL."}
445
+ ),
446
+ 400,
447
+ )
448
+
449
  try:
450
  audio_data = download_audio_from_youtube(youtube_url)
451
+ logging.info(
452
+ f"YouTube download completed in {time.time() - start_time:.2f} seconds"
453
+ )
454
+ except Exception as e:
455
+ error_msg = str(e).lower()
456
+ if any(
457
+ term in error_msg
458
+ for term in [
459
+ "bot",
460
+ "sign in",
461
+ "cookie",
462
+ "certificate",
463
+ "permission",
464
+ ]
465
+ ):
466
  return (
467
  jsonify(
468
  {
469
+ "error": "YouTube access issue. Please try uploading an audio file directly or use a different YouTube URL."
470
  }
471
  ),
472
  400,
473
  )
474
  else:
475
  raise e
476
+
477
  elif "file" in request.files:
478
  audio_file = request.files["file"]
479
  if not audio_file.filename:
480
  return jsonify({"error": "No file selected."}), 400
481
+
482
  if not allowed_file(audio_file.filename):
483
  return (
484
  jsonify(
485
+ {
486
+ "error": "Invalid file type. Please upload an audio file (mp3, aac, flac, or m4a)."
487
+ }
488
  ),
489
  400,
490
  )
491
 
492
  audio_bytes = audio_file.read()
493
  file_format = audio_file.filename.rsplit(".", 1)[1].lower()
494
+ logging.info(
495
+ f"Processing uploaded file: {audio_file.filename}, format: {file_format}, size: {len(audio_bytes)} bytes"
496
+ )
497
+
498
  audio_data = convert_audio_to_mp3(audio_bytes, original_format=file_format)
499
+ logging.info(
500
+ f"File conversion completed in {time.time() - start_time:.2f} seconds"
501
+ )
502
  else:
503
  return jsonify({"error": "No audio file or URL provided."}), 400
504
 
505
+ # Transcribe the audio
506
+ transcribe_start = time.time()
507
  transcription = transcribe_audio_with_whisper(audio_data)
508
+ transcribe_time = time.time() - transcribe_start
509
+ logging.info(
510
+ f"Transcription completed in {transcribe_time:.2f} seconds. Text length: {len(transcription)}"
511
+ )
512
 
513
  if transcription:
514
+ # Summarize the transcription
515
+ summary_start = time.time()
516
  tokenizer, model = load_pegasus_model()
517
  summary = summarize_text_with_pegasus(transcription, tokenizer, model)
518
+ summary_time = time.time() - summary_start
519
+ logging.info(
520
+ f"Summarization completed in {summary_time:.2f} seconds. Summary length: {len(summary)}"
521
+ )
522
+
523
+ total_time = time.time() - start_time
524
+ logging.info(f"Total request completed in {total_time:.2f} seconds")
525
+
526
  return jsonify({"transcription": transcription, "summary": summary})
527
  else:
528
+ return jsonify({"error": "Transcription failed to produce any text."}), 500
529
+
530
  except ValueError as e:
531
+ logging.error(f"ValueError: {str(e)}")
532
  return jsonify({"error": str(e)}), 400
533
  except Exception as e:
534
+ logging.error(f"An unexpected error occurred: {e}", exc_info=True)
535
+ return (
536
+ jsonify(
537
+ {"error": "An unexpected error occurred while processing your request."}
538
+ ),
539
+ 500,
540
+ )
541
 
542
 
543
  if __name__ == "__main__":
requirements.txt CHANGED
@@ -7,4 +7,6 @@ python-dotenv==1.0.0
7
  torch==2.1.1
8
  gunicorn==21.2.0
9
  numpy==1.24.2
10
- certifi>=2023.7.22
 
 
 
7
  torch==2.1.1
8
  gunicorn==21.2.0
9
  numpy==1.24.2
10
+ certifi>=2023.7.22
11
+ pytube>=12.1.0
12
+ werkzeug>=2.2.3