diff --git a/docs/modules/agents/tools/examples/youtube.ipynb b/docs/modules/agents/tools/examples/youtube.ipynb new file mode 100644 index 00000000..567aa0ef --- /dev/null +++ b/docs/modules/agents/tools/examples/youtube.ipynb @@ -0,0 +1,125 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "acb64858", + "metadata": {}, + "source": [ + "# YouTubeSearchTool\n", + "\n", + "This notebook shows how to use a tool to search YouTube\n", + "\n", + "Adapted from [https://github.com/venuv/langchain_yt_tools](https://github.com/venuv/langchain_yt_tools)" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "9bb15d4a", + "metadata": {}, + "outputs": [], + "source": [ + "#! pip install youtube_search" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "cc1c83e2", + "metadata": {}, + "outputs": [], + "source": [ + "from langchain.tools import YouTubeSearchTool" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "becb262b", + "metadata": {}, + "outputs": [], + "source": [ + "tool = YouTubeSearchTool()" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "6bbc4211", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "\"['/watch?v=VcVfceTsD0A&pp=ygUMbGV4IGZyaWVkbWFu', '/watch?v=gPfriiHBBek&pp=ygUMbGV4IGZyaWVkbWFu']\"" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "tool.run(\"lex friedman\")" + ] + }, + { + "cell_type": "markdown", + "id": "7f772147", + "metadata": {}, + "source": [ + "You can also specify the number of results that are returned" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "682fdb33", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "\"['/watch?v=VcVfceTsD0A&pp=ygUMbGV4IGZyaWVkbWFu', '/watch?v=YVJ8gTnDC4Y&pp=ygUMbGV4IGZyaWVkbWFu', '/watch?v=Udh22kuLebg&pp=ygUMbGV4IGZyaWVkbWFu', '/watch?v=gPfriiHBBek&pp=ygUMbGV4IGZyaWVkbWFu', '/watch?v=L_Guz73e6fw&pp=ygUMbGV4IGZyaWVkbWFu']\"" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "tool.run(\"lex friedman,5\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bb5e1659", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.1" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/langchain/tools/__init__.py b/langchain/tools/__init__.py index 6568c1de..7afee8cc 100644 --- a/langchain/tools/__init__.py +++ b/langchain/tools/__init__.py @@ -35,6 +35,7 @@ from langchain.tools.vectorstore.tool import ( ) from langchain.tools.wikipedia.tool import WikipediaQueryRun from langchain.tools.wolfram_alpha.tool import WolframAlphaQueryRun +from langchain.tools.youtube.search import YouTubeSearchTool from langchain.tools.zapier.tool import ZapierNLAListActions, ZapierNLARunAction __all__ = [ @@ -80,4 +81,5 @@ __all__ = [ "ZapierNLAListActions", "ZapierNLARunAction", "tool", + "YouTubeSearchTool", ] diff --git a/langchain/tools/youtube/__init__.py b/langchain/tools/youtube/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/langchain/tools/youtube/search.py b/langchain/tools/youtube/search.py new file mode 100644 index 00000000..0255434a --- /dev/null +++ b/langchain/tools/youtube/search.py @@ -0,0 +1,59 @@ +""" +Adapted from https://github.com/venuv/langchain_yt_tools + +CustomYTSearchTool searches YouTube videos related to a person +and returns a specified number of video URLs. +Input to this tool should be a comma separated list, + - the first part contains a person name + - and the second(optional) a number that is the + maximum number of video results to return + """ +import json +from typing import Optional + +from langchain.callbacks.manager import ( + AsyncCallbackManagerForToolRun, + CallbackManagerForToolRun, +) +from langchain.tools import BaseTool + + +class YouTubeSearchTool(BaseTool): + name = "YouTubeSearch" + description = ( + "search for youtube videos associated with a person. " + "the input to this tool should be a comma separated list, " + "the first part contains a person name and the second a " + "number that is the maximum number of video results " + "to return aka num_results. the second part is optional" + ) + + def _search(self, person: str, num_results: int) -> str: + from youtube_search import YoutubeSearch + + results = YoutubeSearch(person, num_results).to_json() + data = json.loads(results) + url_suffix_list = [video["url_suffix"] for video in data["videos"]] + return str(url_suffix_list) + + def _run( + self, + query: str, + run_manager: Optional[CallbackManagerForToolRun] = None, + ) -> str: + """Use the tool.""" + values = query.split(",") + person = values[0] + if len(values) > 1: + num_results = int(values[1]) + else: + num_results = 2 + return self._search(person, num_results) + + async def _arun( + self, + query: str, + run_manager: Optional[AsyncCallbackManagerForToolRun] = None, + ) -> str: + """Use the tool asynchronously.""" + raise NotImplementedError("YouTubeSearchTool does not yet support async") diff --git a/tests/unit_tests/tools/test_public_api.py b/tests/unit_tests/tools/test_public_api.py index 6b6deebb..43de10e6 100644 --- a/tests/unit_tests/tools/test_public_api.py +++ b/tests/unit_tests/tools/test_public_api.py @@ -44,10 +44,11 @@ _EXPECTED = [ "ZapierNLAListActions", "ZapierNLARunAction", "tool", + "YouTubeSearchTool", ] def test_public_api() -> None: """Test for regressions or changes in the public API.""" # Check that the public API is as expected - assert public_api == sorted(_EXPECTED) + assert sorted(public_api) == sorted(_EXPECTED)