Download tools/youtube_transcript.py from Realistvik0/First_agent_template: direct link, hf CLI and curl.
- Browser
- Download file 3.77 kB
-
https://huggingface.co/spaces/Realistvik0/First_agent_template/resolve/main/tools/youtube_transcript.py
- Command line
-
hf download hf://spaces/Realistvik0/First_agent_template/tools/youtube_transcript.py
-
curl -L -o youtube_transcript.py https://huggingface.co/spaces/Realistvik0/First_agent_template/resolve/main/tools/youtube_transcript.py
3.77 kB
| import re | |
| from smolagents.tools import Tool | |
| class YouTubeTranscriptTool(Tool): | |
| name = "youtube_transcript" | |
| description = ( | |
| "Fetches the spoken transcript of a YouTube video. " | |
| "Use this for ANY question about the content of a YouTube video — " | |
| "what is said, shown, demonstrated, or described in it. " | |
| "Pass the full YouTube URL or just the video ID." | |
| ) | |
| inputs = { | |
| "url": { | |
| "type": "string", | |
| "description": ( | |
| "The YouTube video URL (e.g. https://www.youtube.com/watch?v=XXXXXXXXXXX) " | |
| "or bare video ID (e.g. XXXXXXXXXXX)." | |
| ), | |
| } | |
| } | |
| output_type = "string" | |
| def __init__(self, *args, **kwargs): | |
| self.is_initialized = False | |
| def forward(self, url: str) -> str: | |
| try: | |
| from youtube_transcript_api import YouTubeTranscriptApi | |
| from youtube_transcript_api._errors import ( | |
| TranscriptsDisabled, | |
| NoTranscriptFound, | |
| VideoUnavailable, | |
| CouldNotRetrieveTranscript, | |
| ) | |
| except ImportError: | |
| return ( | |
| "youtube-transcript-api is not installed. " | |
| "Add 'youtube-transcript-api' to requirements.txt and rebuild." | |
| ) | |
| video_id = self._extract_video_id(url.strip()) | |
| if not video_id: | |
| return f"Could not extract a YouTube video ID from: {url}" | |
| api = YouTubeTranscriptApi() | |
| # Try to fetch English first; fall back to any available language. | |
| # v1.x: api.fetch(video_id, languages=[...]) is the simplest path. | |
| # api.list(video_id).find_transcript([...]).fetch() gives language control. | |
| try: | |
| transcript_list = api.list(video_id) | |
| try: | |
| transcript = transcript_list.find_transcript( | |
| ["en", "en-US", "en-GB"] | |
| ) | |
| except NoTranscriptFound: | |
| # Fall back to whatever is available | |
| transcript = next(iter(transcript_list)) | |
| entries = transcript.fetch() | |
| # v1.x entries are FetchedTranscriptSnippet objects with .text attribute | |
| # but also support dict-style access for backwards compat | |
| try: | |
| text = " ".join(e.text for e in entries) | |
| except AttributeError: | |
| text = " ".join(e["text"] for e in entries) | |
| if len(text) > 12000: | |
| text = text[:12000] + "\n\n[Transcript truncated at 12,000 characters]" | |
| return text | |
| except TranscriptsDisabled: | |
| return ( | |
| f"Transcripts are disabled for video {video_id}. " | |
| "Try searching for the video title or description instead." | |
| ) | |
| except VideoUnavailable: | |
| return f"Video {video_id} is unavailable or does not exist." | |
| except NoTranscriptFound: | |
| return ( | |
| f"No transcript found for video {video_id}. " | |
| "The video may not have captions." | |
| ) | |
| except CouldNotRetrieveTranscript as e: | |
| return f"Could not retrieve transcript for {video_id}: {e}" | |
| except Exception as e: | |
| return f"Could not retrieve transcript for {video_id}: {e}" | |
| def _extract_video_id(url: str) -> str: | |
| """Return the 11-character YouTube video ID from a URL or bare ID.""" | |
| patterns = [ | |
| r"(?:v=|youtu\.be/|embed/|shorts/)([A-Za-z0-9_-]{11})", | |
| r"^([A-Za-z0-9_-]{11})$", | |
| ] | |
| for pattern in patterns: | |
| match = re.search(pattern, url) | |
| if match: | |
| return match.group(1) | |
| return "" |