ztoolx commited on
Commit
346f627
·
verified ·
1 Parent(s): fa29869
Files changed (1) hide show
  1. main.py +31 -14
main.py CHANGED
@@ -1,7 +1,8 @@
1
  from fastapi import FastAPI, HTTPException
2
  from fastapi.middleware.cors import CORSMiddleware
3
- from youtube_transcript_api import YouTubeTranscriptApi, TranscriptsDisabled, NoTranscriptFound, VideoUnavailable
4
  import re
 
5
 
6
  app = FastAPI()
7
 
@@ -14,8 +15,11 @@ app.add_middleware(
14
  allow_headers=["*"],
15
  )
16
 
 
 
 
 
17
  def extract_video_id(url: str) -> str:
18
- # The fix: Changed re.match to re.search so it finds the ID even with https:// in front
19
  pattern = r'(?:youtube\.com\/(?:[^\/]+\/.+\/|(?:v|e(?:mbed)?)\/|.*[?&]v=)|youtu\.be\/)([^"&?\/\s]{11})'
20
  match = re.search(pattern, url)
21
  if match:
@@ -23,16 +27,16 @@ def extract_video_id(url: str) -> str:
23
  return None
24
 
25
  @app.post("/api/transcript")
26
- async def get_transcript(request: dict):
27
- url = request.get("url")
28
- if not url:
29
- raise HTTPException(status_code=400, detail="Missing URL")
30
-
31
  video_id = extract_video_id(url)
32
  if not video_id:
33
  raise HTTPException(status_code=400, detail="Invalid YouTube URL")
34
 
35
  try:
 
 
36
  # Fetch available transcripts
37
  transcript_list = YouTubeTranscriptApi.list_transcripts(video_id)
38
 
@@ -40,14 +44,18 @@ async def get_transcript(request: dict):
40
  transcript = None
41
  try:
42
  transcript = transcript_list.find_manually_created_transcript(['en'])
 
43
  except NoTranscriptFound:
44
  try:
45
  transcript = transcript_list.find_generated_transcript(['en'])
 
46
  except NoTranscriptFound:
47
- # If no English, get the first available language
48
- for t in transcript_list:
49
- transcript = t
50
- break
 
 
51
 
52
  if not transcript:
53
  raise HTTPException(status_code=404, detail="No captions found for this video.")
@@ -55,20 +63,29 @@ async def get_transcript(request: dict):
55
  # Fetch the actual text data
56
  transcript_data = transcript.fetch()
57
 
58
- # Combine all text lines
59
- full_text = " ".join([line['text'] for line in transcript_data])
60
 
61
  # Clean up HTML entities
62
  full_text = full_text.replace("'", "'").replace(""", '"').replace("&", "&").replace("'", "'")
63
 
 
64
  return {"text": full_text}
65
 
 
 
 
 
66
  except TranscriptsDisabled:
67
  raise HTTPException(status_code=403, detail="Captions are disabled for this video.")
68
  except VideoUnavailable:
69
  raise HTTPException(status_code=404, detail="Video is unavailable.")
 
 
70
  except Exception as e:
71
- raise HTTPException(status_code=500, detail=f"Failed to fetch transcript: {str(e)}")
 
 
72
 
73
  # KEEP-ALIVE ENDPOINT
74
  @app.get("/api/health")
 
1
  from fastapi import FastAPI, HTTPException
2
  from fastapi.middleware.cors import CORSMiddleware
3
+ from youtube_transcript_api import YouTubeTranscriptApi, TranscriptsDisabled, NoTranscriptFound, VideoUnavailable, TooManyRequests, NoTranscriptAvailable
4
  import re
5
+ from pydantic import BaseModel
6
 
7
  app = FastAPI()
8
 
 
15
  allow_headers=["*"],
16
  )
17
 
18
+ # Pydantic model to ensure we receive proper JSON data
19
+ class TranscriptRequest(BaseModel):
20
+ url: str
21
+
22
  def extract_video_id(url: str) -> str:
 
23
  pattern = r'(?:youtube\.com\/(?:[^\/]+\/.+\/|(?:v|e(?:mbed)?)\/|.*[?&]v=)|youtu\.be\/)([^"&?\/\s]{11})'
24
  match = re.search(pattern, url)
25
  if match:
 
27
  return None
28
 
29
  @app.post("/api/transcript")
30
+ async def get_transcript(req: TranscriptRequest):
31
+ url = req.url
32
+
 
 
33
  video_id = extract_video_id(url)
34
  if not video_id:
35
  raise HTTPException(status_code=400, detail="Invalid YouTube URL")
36
 
37
  try:
38
+ print(f"Attempting to fetch transcript for video_id: {video_id}")
39
+
40
  # Fetch available transcripts
41
  transcript_list = YouTubeTranscriptApi.list_transcripts(video_id)
42
 
 
44
  transcript = None
45
  try:
46
  transcript = transcript_list.find_manually_created_transcript(['en'])
47
+ print("Found manual English transcript.")
48
  except NoTranscriptFound:
49
  try:
50
  transcript = transcript_list.find_generated_transcript(['en'])
51
+ print("Found auto-generated English transcript.")
52
  except NoTranscriptFound:
53
+ # If no English, get the first available language safely
54
+ try:
55
+ transcript = next(iter(transcript_list))
56
+ print(f"Found fallback transcript: {transcript.language_code}")
57
+ except StopIteration:
58
+ pass
59
 
60
  if not transcript:
61
  raise HTTPException(status_code=404, detail="No captions found for this video.")
 
63
  # Fetch the actual text data
64
  transcript_data = transcript.fetch()
65
 
66
+ # Combine all text lines safely
67
+ full_text = " ".join([line.get('text', '') for line in transcript_data])
68
 
69
  # Clean up HTML entities
70
  full_text = full_text.replace("'", "'").replace(""", '"').replace("&", "&").replace("'", "'")
71
 
72
+ print(f"Successfully fetched transcript. Length: {len(full_text)} chars")
73
  return {"text": full_text}
74
 
75
+ except HTTPException:
76
+ raise # Re-raise our custom HTTP exceptions
77
+ except TooManyRequests:
78
+ raise HTTPException(status_code=429, detail="YouTube is rate-limiting requests from this server. Please try again in a minute.")
79
  except TranscriptsDisabled:
80
  raise HTTPException(status_code=403, detail="Captions are disabled for this video.")
81
  except VideoUnavailable:
82
  raise HTTPException(status_code=404, detail="Video is unavailable.")
83
+ except NoTranscriptAvailable:
84
+ raise HTTPException(status_code=404, detail="No transcript is available for this video.")
85
  except Exception as e:
86
+ # Catch-all: Log the exact error to Hugging Face logs so we can see what went wrong!
87
+ print(f"UNHANDLED ERROR for {video_id}: {type(e).__name__} - {str(e)}")
88
+ raise HTTPException(status_code=500, detail=f"Failed to fetch transcript: {type(e).__name__} - {str(e)}")
89
 
90
  # KEEP-ALIVE ENDPOINT
91
  @app.get("/api/health")