Add youtube-transcript-api as tool (#10772)
Co-authored-by: crazywoola <427733928@qq.com>pull/10799/head
parent
6de1f8c770
commit
90d6ebc879
@ -0,0 +1,11 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg width="800px" height="800px" viewBox="0 -38 256 256" version="1.1" xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:xlink="http://www.w3.org/1999/xlink" preserveAspectRatio="xMidYMid">
|
||||||
|
<g>
|
||||||
|
<path d="M250.346231,28.0746923 C247.358133,17.0320558 238.732098,8.40602109 227.689461,5.41792308 C207.823743,0 127.868333,0 127.868333,0 C127.868333,0 47.9129229,0.164179487 28.0472049,5.58210256 C17.0045684,8.57020058 8.37853373,17.1962353 5.39043571,28.2388718 C-0.618533519,63.5374615 -2.94988224,117.322662 5.5546152,151.209308 C8.54271322,162.251944 17.1687479,170.877979 28.2113844,173.866077 C48.0771024,179.284 128.032513,179.284 128.032513,179.284 C128.032513,179.284 207.987923,179.284 227.853641,173.866077 C238.896277,170.877979 247.522312,162.251944 250.51041,151.209308 C256.847738,115.861464 258.801474,62.1091 250.346231,28.0746923 Z"
|
||||||
|
fill="#FF0000">
|
||||||
|
</path>
|
||||||
|
<polygon fill="#FFFFFF" points="102.420513 128.06 168.749025 89.642 102.420513 51.224">
|
||||||
|
</polygon>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.0 KiB |
@ -0,0 +1,81 @@
|
|||||||
|
from typing import Any, Union
|
||||||
|
from urllib.parse import parse_qs, urlparse
|
||||||
|
|
||||||
|
from youtube_transcript_api import YouTubeTranscriptApi
|
||||||
|
|
||||||
|
from core.tools.entities.tool_entities import ToolInvokeMessage
|
||||||
|
from core.tools.tool.builtin_tool import BuiltinTool
|
||||||
|
|
||||||
|
|
||||||
|
class YouTubeTranscriptTool(BuiltinTool):
|
||||||
|
def _invoke(
|
||||||
|
self, user_id: str, tool_parameters: dict[str, Any]
|
||||||
|
) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
|
||||||
|
"""
|
||||||
|
Invoke the YouTube transcript tool
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
# Extract parameters with defaults
|
||||||
|
video_input = tool_parameters["video_id"]
|
||||||
|
language = tool_parameters.get("language")
|
||||||
|
output_format = tool_parameters.get("format", "text")
|
||||||
|
preserve_formatting = tool_parameters.get("preserve_formatting", False)
|
||||||
|
proxy = tool_parameters.get("proxy")
|
||||||
|
cookies = tool_parameters.get("cookies")
|
||||||
|
|
||||||
|
# Extract video ID from URL if needed
|
||||||
|
video_id = self._extract_video_id(video_input)
|
||||||
|
|
||||||
|
# Common kwargs for API calls
|
||||||
|
kwargs = {"proxies": {"https": proxy} if proxy else None, "cookies": cookies}
|
||||||
|
|
||||||
|
try:
|
||||||
|
if language:
|
||||||
|
transcript_list = YouTubeTranscriptApi.list_transcripts(video_id, **kwargs)
|
||||||
|
try:
|
||||||
|
transcript = transcript_list.find_transcript([language])
|
||||||
|
except:
|
||||||
|
# If requested language not found, try translating from English
|
||||||
|
transcript = transcript_list.find_transcript(["en"]).translate(language)
|
||||||
|
transcript_data = transcript.fetch()
|
||||||
|
else:
|
||||||
|
transcript_data = YouTubeTranscriptApi.get_transcript(
|
||||||
|
video_id, preserve_formatting=preserve_formatting, **kwargs
|
||||||
|
)
|
||||||
|
|
||||||
|
# Format output
|
||||||
|
formatter_class = {
|
||||||
|
"json": "JSONFormatter",
|
||||||
|
"pretty": "PrettyPrintFormatter",
|
||||||
|
"srt": "SRTFormatter",
|
||||||
|
"vtt": "WebVTTFormatter",
|
||||||
|
}.get(output_format)
|
||||||
|
|
||||||
|
if formatter_class:
|
||||||
|
from youtube_transcript_api import formatters
|
||||||
|
|
||||||
|
formatter = getattr(formatters, formatter_class)()
|
||||||
|
formatted_transcript = formatter.format_transcript(transcript_data)
|
||||||
|
else:
|
||||||
|
formatted_transcript = " ".join(entry["text"] for entry in transcript_data)
|
||||||
|
|
||||||
|
return self.create_text_message(text=formatted_transcript)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
return self.create_text_message(text=f"Error getting transcript: {str(e)}")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
return self.create_text_message(text=f"Error processing request: {str(e)}")
|
||||||
|
|
||||||
|
def _extract_video_id(self, video_input: str) -> str:
|
||||||
|
"""
|
||||||
|
Extract video ID from URL or return as-is if already an ID
|
||||||
|
"""
|
||||||
|
if "youtube.com" in video_input or "youtu.be" in video_input:
|
||||||
|
# Parse URL
|
||||||
|
parsed_url = urlparse(video_input)
|
||||||
|
if "youtube.com" in parsed_url.netloc:
|
||||||
|
return parse_qs(parsed_url.query)["v"][0]
|
||||||
|
else: # youtu.be
|
||||||
|
return parsed_url.path[1:]
|
||||||
|
return video_input # Assume it's already a video ID
|
||||||
@ -0,0 +1,11 @@
|
|||||||
|
from typing import Any
|
||||||
|
|
||||||
|
from core.tools.provider.builtin_tool_provider import BuiltinToolProviderController
|
||||||
|
|
||||||
|
|
||||||
|
class YouTubeTranscriptProvider(BuiltinToolProviderController):
|
||||||
|
def _validate_credentials(self, credentials: dict[str, Any]) -> None:
|
||||||
|
"""
|
||||||
|
No credentials needed for YouTube Transcript API
|
||||||
|
"""
|
||||||
|
pass
|
||||||
@ -0,0 +1,13 @@
|
|||||||
|
identity:
|
||||||
|
author: Tao Wang
|
||||||
|
name: transcript
|
||||||
|
label:
|
||||||
|
en_US: Transcript
|
||||||
|
zh_Hans: Transcript
|
||||||
|
description:
|
||||||
|
en_US: Get transcripts from YouTube videos
|
||||||
|
zh_Hans: 获取 YouTube 视频的字幕/转录文本
|
||||||
|
icon: icon.svg
|
||||||
|
tags:
|
||||||
|
- videos
|
||||||
|
credentials_for_provider:
|
||||||
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue