diff --git a/poetry.lock b/poetry.lock index 8f188323..30afb360 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.6.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.8.2 and should not be changed by hand. [[package]] name = "aioboto3" @@ -889,6 +889,25 @@ files = [ {file = "distro-1.8.0.tar.gz", hash = "sha256:02e111d1dc6a50abb8eed6bf31c3e48ed8b0830d1ea2a1b78c61765c2513fdd8"}, ] +[[package]] +name = "duckduckgo-search" +version = "6.2.5" +description = "Search for words, documents, images, news, maps and text translation using the DuckDuckGo.com search engine." +optional = false +python-versions = ">=3.8" +files = [ + {file = "duckduckgo_search-6.2.5-py3-none-any.whl", hash = "sha256:a2ae433f812899adf1e4922d3aa306489039ffdbd83b82da3e828625757877bd"}, + {file = "duckduckgo_search-6.2.5.tar.gz", hash = "sha256:177c7993cdd136698884605883984feee39939b2c2d0ac9037fd5bb801f72c3e"}, +] + +[package.dependencies] +click = ">=8.1.7" +primp = ">=0.5.5" + +[package.extras] +dev = ["mypy (>=1.11.0)", "pytest (>=8.3.1)", "pytest-asyncio (>=0.23.8)", "ruff (>=0.5.5)"] +lxml = ["lxml (>=5.2.2)"] + [[package]] name = "exceptiongroup" version = "1.2.0" @@ -1085,6 +1104,17 @@ smb = ["smbprotocol"] ssh = ["paramiko"] tqdm = ["tqdm"] +[[package]] +name = "geojson" +version = "2.5.0" +description = "Python bindings and utilities for GeoJSON" +optional = false +python-versions = "*" +files = [ + {file = "geojson-2.5.0-py2.py3-none-any.whl", hash = "sha256:ccbd13368dd728f4e4f13ffe6aaf725b6e802c692ba0dde628be475040c534ba"}, + {file = "geojson-2.5.0.tar.gz", hash = "sha256:6e4bb7ace4226a45d9c8c8b1348b3fc43540658359f93c3f7e03efa9f15f658a"}, +] + [[package]] name = "google-auth" version = "2.24.0" @@ -2592,6 +2622,26 @@ dev = ["black", "flake8", "flake8-print", "isort", "pre-commit"] sentry = ["django", "sentry-sdk"] test = ["coverage", "flake8", "freezegun (==0.3.15)", "mock (>=2.0.0)", "pylint", "pytest"] +[[package]] +name = "primp" +version = "0.5.5" +description = "HTTP client that can impersonate web browsers, mimicking their headers and `TLS/JA3/JA4/HTTP2` fingerprints" +optional = false +python-versions = ">=3.8" +files = [ + {file = "primp-0.5.5-cp38-abi3-macosx_10_12_x86_64.whl", hash = "sha256:cff9792e8422424528c23574b5364882d68134ee2743f4a2ae6a765746fb3028"}, + {file = "primp-0.5.5-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:78e13fc5d4d90d44a005dbd5dda116981828c803c86cf85816b3bb5363b045c8"}, + {file = "primp-0.5.5-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3714abfda79d3f5c90a5363db58994afbdbacc4b94fe14e9e5f8ab97e7b82577"}, + {file = "primp-0.5.5-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e54765900ee40eceb6bde43676d7e0b2e16ca1f77c0753981fe5e40afc0c2010"}, + {file = "primp-0.5.5-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:66c7eecc5a55225c42cfb99af857df04f994f3dd0d327c016d3af5414c1a2242"}, + {file = "primp-0.5.5-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:df262271cc1a41f4bf80d68396e967a27d7d3d3de355a3d016f953130e7a20be"}, + {file = "primp-0.5.5-cp38-abi3-win_amd64.whl", hash = "sha256:8b424118d6bab6f9d4980d0f35d5ccc1213ab9f1042497c6ee11730f2f94a876"}, + {file = "primp-0.5.5.tar.gz", hash = "sha256:8623e8a25fd686785296b12175f4173250a08db1de9ee4063282e262b94bf3f2"}, +] + +[package.extras] +dev = ["pytest (>=8.1.1)"] + [[package]] name = "prompt-toolkit" version = "3.0.41" @@ -2935,6 +2985,25 @@ files = [ plugins = ["importlib-metadata"] windows-terminal = ["colorama (>=0.4.6)"] +[[package]] +name = "pyowm" +version = "3.3.0" +description = "A Python wrapper around OpenWeatherMap web APIs" +optional = false +python-versions = ">=3.7" +files = [ + {file = "pyowm-3.3.0-py3-none-any.whl", hash = "sha256:86463108e7613171531ba306040b43c972b3fc0b0acf73b12c50910cdd2107ab"}, + {file = "pyowm-3.3.0.tar.gz", hash = "sha256:8196f77c91eac680676ed5ee484aae8a165408055e3e2b28025cbf60b8681e03"}, +] + +[package.dependencies] +geojson = ">=2.3.0,<3" +PySocks = ">=1.7.1,<2" +requests = [ + {version = ">=2.20.0,<3"}, + {version = "*", extras = ["socks"]}, +] + [[package]] name = "pypika" version = "0.48.9" @@ -2956,6 +3025,18 @@ files = [ {file = "pyreadline3-3.4.1.tar.gz", hash = "sha256:6f3d1f7b8a31ba32b73917cefc1f28cc660562f39aea8646d30bd6eff21f7bae"}, ] +[[package]] +name = "pysocks" +version = "1.7.1" +description = "A Python SOCKS client module. See https://github.com/Anorov/PySocks for more information." +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +files = [ + {file = "PySocks-1.7.1-py27-none-any.whl", hash = "sha256:08e69f092cc6dbe92a0fdd16eeb9b9ffbc13cadfe5ca4c7bd92ffb078b293299"}, + {file = "PySocks-1.7.1-py3-none-any.whl", hash = "sha256:2725bd0a9925919b9b51739eea5f9e2bae91e83288108a9ad338b2e3a4435ee5"}, + {file = "PySocks-1.7.1.tar.gz", hash = "sha256:3f8804571ebe159c380ac6de37643bb4685970655d3bba243530d6558b799aa0"}, +] + [[package]] name = "pytest" version = "7.4.3" @@ -3341,6 +3422,7 @@ files = [ certifi = ">=2017.4.17" charset-normalizer = ">=2,<4" idna = ">=2.5,<4" +PySocks = {version = ">=1.5.6,<1.5.7 || >1.5.7", optional = true, markers = "extra == \"socks\""} urllib3 = ">=1.21.1,<3" [package.extras] @@ -4359,4 +4441,4 @@ testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "p [metadata] lock-version = "2.0" python-versions = "^3.8.1" -content-hash = "ad192b6e49b71bdba4bc37db950009dce017c318bd8b1c9072566462d39dd422" +content-hash = "6af872406428e07067d6331cba9099ecb13ed0de335356b29785133c127c6bcb" diff --git a/pyproject.toml b/pyproject.toml index 42acfccb..a30ff61c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -38,6 +38,8 @@ langchain-openai = "0.0.2" tokenizers = "^0.15.2" boto3 = ">=1.33.2,<1.34.35" aioboto3 = "^12.3.0" +duckduckgo-search = "^6.2.5" +pyowm = "^3.3.0" [tool.poetry.group.dev.dependencies] black = "^23.11.0" diff --git a/salesgpt/tools.py b/salesgpt/tools.py index ef738ba4..2d25756f 100644 --- a/salesgpt/tools.py +++ b/salesgpt/tools.py @@ -4,11 +4,14 @@ import boto3 import requests from langchain.agents import Tool +from langchain.agents import load_tools from langchain.chains import RetrievalQA from langchain.text_splitter import CharacterTextSplitter from langchain_community.chat_models import BedrockChat from langchain_community.vectorstores import Chroma from langchain_openai import ChatOpenAI, OpenAIEmbeddings +from langchain_community.tools import DuckDuckGoSearchRun +from langchain_community.utilities import OpenWeatherMapAPIWrapper from litellm import completion import smtplib from email.mime.multipart import MIMEMultipart @@ -244,6 +247,17 @@ def generate_calendly_invitation_link(query): return f"url: {data['resource']['booking_url']}" else: return "Failed to create Calendly link: " + +def search_web(query): + search = DuckDuckGoSearchRun() + return search.invoke(query) + +def weather_search(query): + OPENWEATHERMAP_API_KEY = os.getenv( + "OPENWEATHERMAP_API_KEY") + weather = OpenWeatherMapAPIWrapper() + print("IT worked") + return weather.run(query) def get_tools(product_catalog): # query to get_tools can be used to be embedded and relevant tools found @@ -251,12 +265,19 @@ def get_tools(product_catalog): # we only use four tools for now, but this is highly extensible! knowledge_base = setup_knowledge_base(product_catalog) - tools = [ + + tools = load_tools(["openweathermap-api"]) + tools.extend([ Tool( name="ProductSearch", func=knowledge_base.run, description="useful for when you need to answer questions about product information or services offered, availability and their costs.", ), + Tool( + name="WebSearch", + func=search_web, + description="useful for when you need to search the web for information.", + ), Tool( name="GeneratePaymentLink", func=generate_stripe_payment_link, @@ -273,6 +294,6 @@ def get_tools(product_catalog): description='''Useful for when you need to create invite for a personal meeting in Sleep Heaven shop. Sends a calendly invitation based on the query input.''', ) - ] + ]) return tools diff --git a/website/docs/Tools/Internet_search.md b/website/docs/Tools/Internet_search.md new file mode 100644 index 00000000..cc47f618 --- /dev/null +++ b/website/docs/Tools/Internet_search.md @@ -0,0 +1,43 @@ +--- +sidebar_position: 2 + +--- +# Internet Search + +SalesGPT now has the capability to perform internet searches using DuckDuckGo through a pre-made LangChain tool. This feature allows the AI sales agent to access up-to-date information from the web during conversations, enhancing its ability to provide relevant and timely responses. + +## How to Enable Internet Search + +To enable the DuckDuckGo search functionality in your SalesGPT setup: + +1. Ensure you have the latest version of LangChain installed. + +2. Add the DuckDuckGo search tool to your tools list in the `get_tools` function within the `tools.py` file: + + ```python + from langchain.tools import DuckDuckGoSearchRun + + def get_tools(product_catalog): + # ... other tool configurations ... + + tools.extend([ + # ... other tools ... + Tool( + name="WebSearch", + func=DuckDuckGoSearchRun().run, + description="Useful for when you need to search the web for current information.", + ), + ]) + + return tools + ``` + +3. Make sure the `USE_TOOLS_IN_API` environment variable is set to `True` in your `.env` file: + + ``` + USE_TOOLS_IN_API=True + ``` + +By adding this tool, your SalesGPT agent will be able to perform web searches when it needs to find information that isn't available in its training data or product catalog. This can be particularly useful for answering questions about current events, market trends, or competitor information. + +Remember to use this tool responsibly and in compliance with DuckDuckGo's terms of service. diff --git a/website/docs/Tools/Pre-built_tools copy.md b/website/docs/Tools/Pre-built_tools copy.md new file mode 100644 index 00000000..555be9e1 --- /dev/null +++ b/website/docs/Tools/Pre-built_tools copy.md @@ -0,0 +1,75 @@ +--- +sidebar_position: 2 + +--- +# Pre-built Tools + +SalesGPT is not limited to just custom-built tools. It can also leverage a wide range of pre-built tools available from LangChain. These tools provide additional capabilities and integrations that can enhance your AI sales agent's functionality. + +## Using LangChain's Pre-built Tools + +LangChain offers a variety of pre-made tools that you can easily integrate into SalesGPT. These tools cover a wide range of functionalities, from web searches to mathematical calculations. + +To use these tools: + +1. Set up the desired tools according to the LangChain documentation. +2. Add the configured tools to the "tools" list in your SalesGPT setup. + +You can find the full list of available tools and their setup instructions in the [LangChain Tools documentation](https://python.langchain.com/v0.2/docs/integrations/tools/). + +Some popular pre-built tools include: + +- Search tools (e.g., SerpAPI, Google Search) +- Calculator tools +- Weather tools +- News API tools +- And many more! + +By incorporating these pre-built tools, you can significantly expand the capabilities of your AI sales agent, allowing it to access real-time information, perform calculations, or integrate with various APIs as needed during sales conversations. + +Remember to review the documentation for each tool you want to use, as some may require additional setup steps or API keys. + + +## Example: Weather Search Tool + +One pre-built tool that has been implemented in SalesGPT is the weather search tool. This serves as a good example of how to set up and use a pre-built tool from LangChain. Here's how it's implemented: + +1. First, ensure you have the necessary API key. For the weather tool, you need an OpenWeatherMap API key. You can get a free key that allows 1000 requests per day from [OpenWeatherMap](https://openweathermap.org/api). + +2. Add the API key to your `.env` file: + + ``` + OPENWEATHERMAP_API_KEY=your_api_key_here + ``` + +3. In the `tools.py` file, import the necessary components and set up the tool: + + ```python + from langchain.tools import OpenWeatherMapAPIWrapper + import os + + def weather_search(query): + OPENWEATHERMAP_API_KEY = os.getenv("OPENWEATHERMAP_API_KEY") + weather = OpenWeatherMapAPIWrapper() + return weather.run(query) + ``` + +4. Add the weather tool to your `get_tools` function: + + ```python + def get_tools(product_catalog): + tools = load_tools(["openweathermap-api"]) + tools.extend([ + # ... other tools ... + Tool( + name="WeatherSearch", + func=weather_search, + description="Useful for getting current weather information for a specific location.", + ), + ]) + return tools + ``` + +This example demonstrates how to set up a pre-built tool from LangChain. Each tool may have its own setup requirements, such as API keys or additional configurations. Always refer to the LangChain documentation for specific setup instructions for each tool you want to use. + +