From e9ed9d7810dfd47c18a9202b7d65bfa700122ebb Mon Sep 17 00:00:00 2001 From: Maksim Novikov Date: Mon, 22 Jan 2024 21:31:50 +0500 Subject: [PATCH] Update to latest versions of langchain, openai --- README.md | 2 +- examples/sales_agent_with_context.ipynb | 93 +++++++++++++------------ examples/streaming_generator_example.py | 2 +- poetry.lock | 89 +++++++++++++++++------ pyproject.toml | 5 +- run.py | 5 +- salesgpt/agents.py | 72 +++++++++---------- salesgpt/chains.py | 5 +- salesgpt/salesgptapi.py | 2 +- salesgpt/tools.py | 11 +-- tests/test_salesgpt.py | 10 +-- 11 files changed, 170 insertions(+), 126 deletions(-) diff --git a/README.md b/README.md index ab32865a..7348ea9f 100644 --- a/README.md +++ b/README.md @@ -92,7 +92,7 @@ We are building SalesGPT to power your best AI Sales Agents. Hence, we would lov ```python import os from salesgpt.agents import SalesGPT -from langchain.chat_models import ChatLiteLLM +from langchain_community.chat_models import ChatLiteLLM from dotenv import load_dotenv load_dotenv() # make sure you have .env file with your API keys, eg., OPENAI_API_KEY=sk-xxx diff --git a/examples/sales_agent_with_context.ipynb b/examples/sales_agent_with_context.ipynb index d1a2e3a9..918757eb 100644 --- a/examples/sales_agent_with_context.ipynb +++ b/examples/sales_agent_with_context.ipynb @@ -51,18 +51,17 @@ "from langchain.llms import BaseLLM\n", "from pydantic import BaseModel, Field\n", "from langchain.chains.base import Chain\n", - "from langchain.chat_models import ChatOpenAI, ChatLiteLLM\n", + "from langchain.chat_models import ChatLiteLLM\n", "from langchain.agents import Tool, LLMSingleActionAgent, AgentExecutor\n", "from langchain.text_splitter import CharacterTextSplitter\n", - "from langchain.embeddings.openai import OpenAIEmbeddings\n", "from langchain.chains import RetrievalQA\n", "from langchain.vectorstores import Chroma\n", - "from langchain.llms import OpenAI\n", "from langchain.prompts.base import StringPromptTemplate\n", "from typing import Callable\n", "from langchain.agents.agent import AgentOutputParser\n", "from langchain.agents.conversational.prompt import FORMAT_INSTRUCTIONS\n", - "from langchain.schema import AgentAction, AgentFinish \n", + "from langchain.schema import AgentAction, AgentFinish\n", + "from langchain_openai import ChatOpenAI, OpenAIEmbeddings\n", "from typing import Union\n" ] }, @@ -299,7 +298,7 @@ { "data": { "text/plain": [ - "'1'" + "{'conversation_history': '', 'text': '1'}" ] }, "execution_count": 6, @@ -308,7 +307,7 @@ } ], "source": [ - "stage_analyzer_chain.run(conversation_history='')" + "stage_analyzer_chain.invoke({'conversation_history': ''})" ] }, { @@ -355,7 +354,16 @@ { "data": { "text/plain": [ - "\"I'm doing great, thank you for asking! I'm reaching out to you today because I wanted to discuss how Sleep Haven can help you achieve a better night's sleep. Our premium mattresses are designed to provide the most comfortable and supportive sleeping experience possible. Are you interested in improving your sleep with a high-quality mattress? \"" + "{'salesperson_name': 'Ted Lasso',\n", + " 'salesperson_role': 'Business Development Representative',\n", + " 'company_name': 'Sleep Haven',\n", + " 'company_business': 'Sleep Haven is a premium mattress company that provides customers with the most comfortable and supportive sleeping experience possible. We offer a range of high-quality mattresses, pillows, and bedding accessories that are designed to meet the unique needs of our customers.',\n", + " 'company_values': \"Our mission at Sleep Haven is to help people achieve a better night's sleep by providing them with the best possible sleep solutions. We believe that quality sleep is essential to overall health and well-being, and we are committed to helping our customers achieve optimal sleep by offering exceptional products and customer service.\",\n", + " 'conversation_purpose': 'find out whether they are looking to achieve better sleep via buying a premier mattress.',\n", + " 'conversation_history': 'Hello, this is Ted Lasso from Sleep Haven. How are you doing today? \\nUser: I am well, howe are you?',\n", + " 'conversation_type': 'call',\n", + " 'conversation_stage': 'Introduction: Start the conversation by introducing yourself and your company. Be polite and respectful while keeping the tone of the conversation professional. Your greeting should be welcoming. Always clarify in your greeting the reason why you are contacting the prospect.',\n", + " 'text': \"I'm doing great, thank you for asking! I'm reaching out today to see if you're interested in improving your sleep experience with a premium mattress from Sleep Haven. We offer a range of high-quality mattresses designed to provide the most comfortable and supportive sleep possible. Would you like to learn more about our products? \"}" ] }, "execution_count": 7, @@ -364,17 +372,17 @@ } ], "source": [ - "sales_conversation_utterance_chain.run(\n", - " salesperson_name = \"Ted Lasso\",\n", - " salesperson_role= \"Business Development Representative\",\n", - " company_name=\"Sleep Haven\",\n", - " company_business=\"Sleep Haven is a premium mattress company that provides customers with the most comfortable and supportive sleeping experience possible. We offer a range of high-quality mattresses, pillows, and bedding accessories that are designed to meet the unique needs of our customers.\",\n", - " company_values = \"Our mission at Sleep Haven is to help people achieve a better night's sleep by providing them with the best possible sleep solutions. We believe that quality sleep is essential to overall health and well-being, and we are committed to helping our customers achieve optimal sleep by offering exceptional products and customer service.\",\n", - " conversation_purpose = \"find out whether they are looking to achieve better sleep via buying a premier mattress.\",\n", - " conversation_history='Hello, this is Ted Lasso from Sleep Haven. How are you doing today? \\nUser: I am well, howe are you?',\n", - " conversation_type=\"call\",\n", - " conversation_stage = conversation_stages.get('1', \"Introduction: Start the conversation by introducing yourself and your company. Be polite and respectful while keeping the tone of the conversation professional.\")\n", - ")" + "sales_conversation_utterance_chain.invoke({\n", + " 'salesperson_name': \"Ted Lasso\",\n", + " 'salesperson_role': \"Business Development Representative\",\n", + " 'company_name': \"Sleep Haven\",\n", + " 'company_business': \"Sleep Haven is a premium mattress company that provides customers with the most comfortable and supportive sleeping experience possible. We offer a range of high-quality mattresses, pillows, and bedding accessories that are designed to meet the unique needs of our customers.\",\n", + " 'company_values': \"Our mission at Sleep Haven is to help people achieve a better night's sleep by providing them with the best possible sleep solutions. We believe that quality sleep is essential to overall health and well-being, and we are committed to helping our customers achieve optimal sleep by offering exceptional products and customer service.\",\n", + " 'conversation_purpose': \"find out whether they are looking to achieve better sleep via buying a premier mattress.\",\n", + " 'conversation_history': 'Hello, this is Ted Lasso from Sleep Haven. How are you doing today? \\nUser: I am well, howe are you?',\n", + " 'conversation_type': \"call\",\n", + " 'conversation_stage': conversation_stages.get('1', \"Introduction: Start the conversation by introducing yourself and your company. Be polite and respectful while keeping the tone of the conversation professional.\")\n", + "})" ] }, { @@ -447,7 +455,7 @@ " text_splitter = CharacterTextSplitter(chunk_size=10, chunk_overlap=0)\n", " texts = text_splitter.split_text(product_catalog)\n", "\n", - " llm = OpenAI(temperature=0)\n", + " llm = ChatOpenAI(temperature=0)\n", " embeddings = OpenAIEmbeddings()\n", " docsearch = Chroma.from_texts(\n", " texts, embeddings, collection_name=\"product-knowledge-base\"\n", @@ -487,13 +495,15 @@ "text": [ "Created a chunk of size 940, which is longer than the specified 10\n", "Created a chunk of size 844, which is longer than the specified 10\n", - "Created a chunk of size 837, which is longer than the specified 10\n" + "Created a chunk of size 837, which is longer than the specified 10\n", + "/Users/test/Documents/extra/ml/github/salesgptvenv/lib/python3.10/site-packages/langchain_core/_api/deprecation.py:117: LangChainDeprecationWarning: The function `run` was deprecated in LangChain 0.1.0 and will be removed in 0.2.0. Use invoke instead.\n", + " warn_deprecated(\n" ] }, { "data": { "text/plain": [ - "' We have four products available: the Classic Harmony Spring Mattress, the Plush Serenity Bamboo Mattress, the Luxury Cloud-Comfort Memory Foam Mattress, and the EcoGreen Hybrid Latex Mattress. Each product is available in different sizes, with the Classic Harmony Spring Mattress available in Queen and King sizes, the Plush Serenity Bamboo Mattress available in King size, the Luxury Cloud-Comfort Memory Foam Mattress available in Twin, Queen, and King sizes, and the EcoGreen Hybrid Latex Mattress available in Twin and Full sizes.'" + "'We have four products available:\\n\\n1. Luxury Cloud-Comfort Memory Foam Mattress\\n2. Classic Harmony Spring Mattress\\n3. EcoGreen Hybrid Latex Mattress\\n4. Plush Serenity Bamboo Mattress'" ] }, "execution_count": 10, @@ -898,7 +908,9 @@ "text": [ "Created a chunk of size 940, which is longer than the specified 10\n", "Created a chunk of size 844, which is longer than the specified 10\n", - "Created a chunk of size 837, which is longer than the specified 10\n" + "Created a chunk of size 837, which is longer than the specified 10\n", + "/Users/test/Documents/extra/ml/github/salesgptvenv/lib/python3.10/site-packages/langchain_core/_api/deprecation.py:117: LangChainDeprecationWarning: The class `langchain.agents.agent.LLMSingleActionAgent` was deprecated in langchain 0.1.0 and will be removed in 0.2.0. Use Use new agent constructor methods like create_react_agent, create_json_agent, create_structured_chat_agent, etc. instead.\n", + " warn_deprecated(\n" ] } ], @@ -925,7 +937,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "Conversation Stage: Introduction: Start the conversation by introducing yourself and your company. Be polite and respectful while keeping the tone of the conversation professional. Your greeting should be welcoming. Always clarify in your greeting the reason why you are contacting the prospect.\n" + "Conversation Stage: 1\n" ] } ], @@ -942,7 +954,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "Ted Lasso: Hello there! This is Ted Lasso from Sleep Haven. How are you doing today?\n" + "Ted Lasso: Hello! This is Ted Lasso from Sleep Haven. How are you doing today?\n" ] } ], @@ -985,7 +997,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "Ted Lasso: I'm doing great, thank you! I'd be happy to tell you more about our mattresses. Our mattresses at Sleep Haven are designed to provide the most comfortable and supportive sleeping experience possible. They are made with high-quality materials and are tailored to meet your unique needs. Is there anything specific you'd like to know about our mattresses?\n" + "Ted Lasso: I apologize, I was unable to find the answer to your question. Is there anything else I can help with?\n" ] } ], @@ -1011,7 +1023,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "Conversation Stage: Needs analysis: Ask open-ended questions to uncover the prospect's needs and pain points. Listen carefully to their responses and take notes.\n" + "Conversation Stage: Solution presentation: Based on the prospect's needs, present your product/service as the solution that can address their pain points.\n" ] } ], @@ -1028,7 +1040,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "Ted Lasso: Our Sleep Haven mattresses are made from a variety of materials, including memory foam, high-density foam, cooling gel-infused particles, bamboo, adaptive foam, inner springs, plush padding, natural cotton, and natural latex. These materials are carefully selected to provide the utmost comfort and support for a better night's sleep. Is there anything else I can assist you with?\n" + "Ted Lasso: Our mattresses at Sleep Haven are made from high-quality materials that prioritize comfort and support. We have the EcoGreen Hybrid Latex Mattress, which is made from 100% natural latex harvested from eco-friendly plantations. We also have the Plush Serenity Bamboo Mattress, which features a bamboo-infused top layer known for its breathability and moisture-wicking properties. These materials provide a luxurious and comfortable sleeping experience. Is there anything else I can assist you with?\n" ] } ], @@ -1054,7 +1066,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "Conversation Stage: Needs analysis: Ask open-ended questions to uncover the prospect's needs and pain points. Listen carefully to their responses and take notes.\n" + "Conversation Stage: Solution presentation: Based on the prospect's needs, present your product/service as the solution that can address their pain points.\n" ] } ], @@ -1071,7 +1083,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "Ted Lasso: Absolutely! We have two fantastic mattresses available in a queen size. The first option is our Luxury Cloud-Comfort Memory Foam Mattress, which provides unparalleled comfort and support. The second option is our Classic Harmony Spring Mattress, which combines the support of inner springs with the plush padding for a truly restful sleep. Both mattresses are designed to meet the unique needs of our customers. Which one would you like to learn more about? \n" + "Ted Lasso: Absolutely! We have queen-sized mattresses available at Sleep Haven. Our mattresses come in various sizes, including queen size, to accommodate different preferences and needs. We understand the importance of finding the right mattress size for a comfortable sleep. Is there anything else I can assist you with?\n" ] } ], @@ -1114,15 +1126,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "Ted Lasso: Of course! Let me compare and contrast our Luxury Cloud-Comfort Memory Foam Mattress and our Classic Harmony Spring Mattress for you. \n", - "\n", - "The Luxury Cloud-Comfort Memory Foam Mattress is made with multiple layers of memory foam, including our premium cloud-comfort foam. This foam is designed to contour to your body, providing personalized support and pressure relief. It also has cooling gel-infused particles that help regulate temperature and keep you cool throughout the night. The memory foam construction also helps reduce motion transfer, so you won't be disturbed by your partner's movements.\n", - "\n", - "On the other hand, the Classic Harmony Spring Mattress combines the support of inner springs with the plush padding for a balanced and comfortable sleep surface. The individually wrapped coils provide targeted support for your body, while the plush padding adds an extra layer of cushioning. It also has a quilted cover made with natural cotton for a soft and breathable feel. \n", - "\n", - "Both mattresses offer great comfort and support, but the main difference lies in the construction. The Luxury Cloud-Comfort Memory Foam Mattress provides a more personalized and contouring feel, while the Classic Harmony Spring Mattress offers a combination of support and cushioning.\n", - "\n", - "Is there anything specific you would like to know about these mattresses?\n" + "Ted Lasso: The EcoGreen Hybrid Latex Mattress is made from 100% natural latex, which provides excellent support and pressure relief. It is also eco-friendly, as the latex is harvested from sustainable plantations. On the other hand, the Plush Serenity Bamboo Mattress has a bamboo-infused top layer, which offers breathability and moisture-wicking properties. Both mattresses are designed for a comfortable and supportive sleeping experience, but the choice ultimately depends on your personal preferences and needs. Is there anything else I can help you with?\n" ] } ], @@ -1165,7 +1169,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "Ted Lasso: The Luxury Cloud-Comfort Memory Foam Mattress is priced at $999. As for the Classic Harmony Spring Mattress, let me check the price for you. \n" + "Ted Lasso: The price of the EcoGreen Hybrid Latex Mattress is $1,599. Is there anything else I can assist you with?\n" ] } ], @@ -1208,7 +1212,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "Ted Lasso: I have the price for the Classic Harmony Spring Mattress. It is priced at $1,299. Both the Luxury Cloud-Comfort Memory Foam Mattress and the Classic Harmony Spring Mattress offer excellent comfort and support. Is there anything else I can help you with?\n" + "Ted Lasso: Thank you for considering Sleep Haven! If you have any further questions or if there's anything else I can assist you with, please don't hesitate to reach out. Have a great day! =1.0.2)"] [[package]] name = "langchain" -version = "0.0.345" +version = "0.1.0" description = "Building applications with LLMs through composability" optional = false python-versions = ">=3.8.1,<4.0" files = [ - {file = "langchain-0.0.345-py3-none-any.whl", hash = "sha256:461a126ec182834c714589ceec47354401d80b903262efab8d669fe941a0a4df"}, - {file = "langchain-0.0.345.tar.gz", hash = "sha256:2d366513a46e4620d8fe6fc956b9185c2a252e60e2fc0476113482455aaaa9f0"}, + {file = "langchain-0.1.0-py3-none-any.whl", hash = "sha256:8652e74b039333a55c79faff4400b077ba1bd0ddce5255574e42d301c05c1733"}, + {file = "langchain-0.1.0.tar.gz", hash = "sha256:d43119f8d3fda2c8ddf8c3a19bd5b94b347e27d1867ff14a921b90bdbed0668a"}, ] [package.dependencies] aiohttp = ">=3.8.3,<4.0.0" -anyio = "<4.0" async-timeout = {version = ">=4.0.0,<5.0.0", markers = "python_version < \"3.11\""} dataclasses-json = ">=0.5.7,<0.7" jsonpatch = ">=1.33,<2.0" -langchain-core = ">=0.0.9,<0.1" -langsmith = ">=0.0.63,<0.1.0" +langchain-community = ">=0.0.9,<0.1" +langchain-core = ">=0.1.7,<0.2" +langsmith = ">=0.0.77,<0.1.0" numpy = ">=1,<2" pydantic = ">=1,<3" PyYAML = ">=5.3" @@ -1633,46 +1633,95 @@ SQLAlchemy = ">=1.4,<3" tenacity = ">=8.1.0,<9.0.0" [package.extras] -all = ["O365 (>=2.0.26,<3.0.0)", "aleph-alpha-client (>=2.15.0,<3.0.0)", "amadeus (>=8.1.0)", "arxiv (>=1.4,<2.0)", "atlassian-python-api (>=3.36.0,<4.0.0)", "awadb (>=0.3.9,<0.4.0)", "azure-ai-formrecognizer (>=3.2.1,<4.0.0)", "azure-ai-textanalytics (>=5.3.0,<6.0.0)", "azure-ai-vision (>=0.11.1b1,<0.12.0)", "azure-cognitiveservices-speech (>=1.28.0,<2.0.0)", "azure-cosmos (>=4.4.0b1,<5.0.0)", "azure-identity (>=1.12.0,<2.0.0)", "beautifulsoup4 (>=4,<5)", "clarifai (>=9.1.0)", "clickhouse-connect (>=0.5.14,<0.6.0)", "cohere (>=4,<5)", "deeplake (>=3.8.3,<4.0.0)", "dgml-utils (>=0.3.0,<0.4.0)", "docarray[hnswlib] (>=0.32.0,<0.33.0)", "duckduckgo-search (>=3.8.3,<4.0.0)", "elasticsearch (>=8,<9)", "esprima (>=4.0.1,<5.0.0)", "faiss-cpu (>=1,<2)", "google-api-python-client (==2.70.0)", "google-auth (>=2.18.1,<3.0.0)", "google-search-results (>=2,<3)", "gptcache (>=0.1.7)", "html2text (>=2020.1.16,<2021.0.0)", "huggingface_hub (>=0,<1)", "jinja2 (>=3,<4)", "jq (>=1.4.1,<2.0.0)", "lancedb (>=0.1,<0.2)", "langkit (>=0.0.6,<0.1.0)", "lark (>=1.1.5,<2.0.0)", "librosa (>=0.10.0.post2,<0.11.0)", "lxml (>=4.9.2,<5.0.0)", "manifest-ml (>=0.0.1,<0.0.2)", "marqo (>=1.2.4,<2.0.0)", "momento (>=1.13.0,<2.0.0)", "nebula3-python (>=3.4.0,<4.0.0)", "neo4j (>=5.8.1,<6.0.0)", "networkx (>=2.6.3,<4)", "nlpcloud (>=1,<2)", "nltk (>=3,<4)", "nomic (>=1.0.43,<2.0.0)", "openai (<2)", "openlm (>=0.0.5,<0.0.6)", "opensearch-py (>=2.0.0,<3.0.0)", "pdfminer-six (>=20221105,<20221106)", "pexpect (>=4.8.0,<5.0.0)", "pgvector (>=0.1.6,<0.2.0)", "pinecone-client (>=2,<3)", "pinecone-text (>=0.4.2,<0.5.0)", "psycopg2-binary (>=2.9.5,<3.0.0)", "pymongo (>=4.3.3,<5.0.0)", "pyowm (>=3.3.0,<4.0.0)", "pypdf (>=3.4.0,<4.0.0)", "pytesseract (>=0.3.10,<0.4.0)", "python-arango (>=7.5.9,<8.0.0)", "pyvespa (>=0.33.0,<0.34.0)", "qdrant-client (>=1.3.1,<2.0.0)", "rdflib (>=6.3.2,<7.0.0)", "redis (>=4,<5)", "requests-toolbelt (>=1.0.0,<2.0.0)", "sentence-transformers (>=2,<3)", "singlestoredb (>=0.7.1,<0.8.0)", "tensorflow-text (>=2.11.0,<3.0.0)", "tigrisdb (>=1.0.0b6,<2.0.0)", "tiktoken (>=0.3.2,<0.6.0)", "torch (>=1,<3)", "transformers (>=4,<5)", "weaviate-client (>=3,<4)", "wikipedia (>=1,<2)", "wolframalpha (==5.0.0)"] azure = ["azure-ai-formrecognizer (>=3.2.1,<4.0.0)", "azure-ai-textanalytics (>=5.3.0,<6.0.0)", "azure-ai-vision (>=0.11.1b1,<0.12.0)", "azure-cognitiveservices-speech (>=1.28.0,<2.0.0)", "azure-core (>=1.26.4,<2.0.0)", "azure-cosmos (>=4.4.0b1,<5.0.0)", "azure-identity (>=1.12.0,<2.0.0)", "azure-search-documents (==11.4.0b8)", "openai (<2)"] clarifai = ["clarifai (>=9.1.0)"] cli = ["typer (>=0.9.0,<0.10.0)"] cohere = ["cohere (>=4,<5)"] docarray = ["docarray[hnswlib] (>=0.32.0,<0.33.0)"] embeddings = ["sentence-transformers (>=2,<3)"] -extended-testing = ["aiosqlite (>=0.19.0,<0.20.0)", "aleph-alpha-client (>=2.15.0,<3.0.0)", "anthropic (>=0.3.11,<0.4.0)", "arxiv (>=1.4,<2.0)", "assemblyai (>=0.17.0,<0.18.0)", "atlassian-python-api (>=3.36.0,<4.0.0)", "beautifulsoup4 (>=4,<5)", "bibtexparser (>=1.4.0,<2.0.0)", "cassio (>=0.1.0,<0.2.0)", "chardet (>=5.1.0,<6.0.0)", "cohere (>=4,<5)", "dashvector (>=1.0.1,<2.0.0)", "databricks-vectorsearch (>=0.21,<0.22)", "datasets (>=2.15.0,<3.0.0)", "dgml-utils (>=0.3.0,<0.4.0)", "esprima (>=4.0.1,<5.0.0)", "faiss-cpu (>=1,<2)", "feedparser (>=6.0.10,<7.0.0)", "fireworks-ai (>=0.6.0,<0.7.0)", "geopandas (>=0.13.1,<0.14.0)", "gitpython (>=3.1.32,<4.0.0)", "google-cloud-documentai (>=2.20.1,<3.0.0)", "gql (>=3.4.1,<4.0.0)", "html2text (>=2020.1.16,<2021.0.0)", "javelin-sdk (>=0.1.8,<0.2.0)", "jinja2 (>=3,<4)", "jq (>=1.4.1,<2.0.0)", "jsonschema (>1)", "lxml (>=4.9.2,<5.0.0)", "markdownify (>=0.11.6,<0.12.0)", "motor (>=3.3.1,<4.0.0)", "msal (>=1.25.0,<2.0.0)", "mwparserfromhell (>=0.6.4,<0.7.0)", "mwxml (>=0.3.3,<0.4.0)", "newspaper3k (>=0.2.8,<0.3.0)", "numexpr (>=2.8.6,<3.0.0)", "openai (<2)", "openapi-pydantic (>=0.3.2,<0.4.0)", "pandas (>=2.0.1,<3.0.0)", "pdfminer-six (>=20221105,<20221106)", "pgvector (>=0.1.6,<0.2.0)", "praw (>=7.7.1,<8.0.0)", "psychicapi (>=0.8.0,<0.9.0)", "py-trello (>=0.19.0,<0.20.0)", "pymupdf (>=1.22.3,<2.0.0)", "pypdf (>=3.4.0,<4.0.0)", "pypdfium2 (>=4.10.0,<5.0.0)", "pyspark (>=3.4.0,<4.0.0)", "rank-bm25 (>=0.2.2,<0.3.0)", "rapidfuzz (>=3.1.1,<4.0.0)", "rapidocr-onnxruntime (>=1.3.2,<2.0.0)", "requests-toolbelt (>=1.0.0,<2.0.0)", "rspace_client (>=2.5.0,<3.0.0)", "scikit-learn (>=1.2.2,<2.0.0)", "sqlite-vss (>=0.1.2,<0.2.0)", "streamlit (>=1.18.0,<2.0.0)", "sympy (>=1.12,<2.0)", "telethon (>=1.28.5,<2.0.0)", "timescale-vector (>=0.0.1,<0.0.2)", "tqdm (>=4.48.0)", "upstash-redis (>=0.15.0,<0.16.0)", "xata (>=1.0.0a7,<2.0.0)", "xmltodict (>=0.13.0,<0.14.0)"] +extended-testing = ["aiosqlite (>=0.19.0,<0.20.0)", "aleph-alpha-client (>=2.15.0,<3.0.0)", "anthropic (>=0.3.11,<0.4.0)", "arxiv (>=1.4,<2.0)", "assemblyai (>=0.17.0,<0.18.0)", "atlassian-python-api (>=3.36.0,<4.0.0)", "beautifulsoup4 (>=4,<5)", "bibtexparser (>=1.4.0,<2.0.0)", "cassio (>=0.1.0,<0.2.0)", "chardet (>=5.1.0,<6.0.0)", "cohere (>=4,<5)", "couchbase (>=4.1.9,<5.0.0)", "dashvector (>=1.0.1,<2.0.0)", "databricks-vectorsearch (>=0.21,<0.22)", "datasets (>=2.15.0,<3.0.0)", "dgml-utils (>=0.3.0,<0.4.0)", "esprima (>=4.0.1,<5.0.0)", "faiss-cpu (>=1,<2)", "feedparser (>=6.0.10,<7.0.0)", "fireworks-ai (>=0.9.0,<0.10.0)", "geopandas (>=0.13.1,<0.14.0)", "gitpython (>=3.1.32,<4.0.0)", "google-cloud-documentai (>=2.20.1,<3.0.0)", "gql (>=3.4.1,<4.0.0)", "hologres-vector (>=0.0.6,<0.0.7)", "html2text (>=2020.1.16,<2021.0.0)", "javelin-sdk (>=0.1.8,<0.2.0)", "jinja2 (>=3,<4)", "jq (>=1.4.1,<2.0.0)", "jsonschema (>1)", "langchain-openai (>=0.0.2,<0.1)", "lxml (>=4.9.2,<5.0.0)", "markdownify (>=0.11.6,<0.12.0)", "motor (>=3.3.1,<4.0.0)", "msal (>=1.25.0,<2.0.0)", "mwparserfromhell (>=0.6.4,<0.7.0)", "mwxml (>=0.3.3,<0.4.0)", "newspaper3k (>=0.2.8,<0.3.0)", "numexpr (>=2.8.6,<3.0.0)", "openai (<2)", "openapi-pydantic (>=0.3.2,<0.4.0)", "pandas (>=2.0.1,<3.0.0)", "pdfminer-six (>=20221105,<20221106)", "pgvector (>=0.1.6,<0.2.0)", "praw (>=7.7.1,<8.0.0)", "psychicapi (>=0.8.0,<0.9.0)", "py-trello (>=0.19.0,<0.20.0)", "pymupdf (>=1.22.3,<2.0.0)", "pypdf (>=3.4.0,<4.0.0)", "pypdfium2 (>=4.10.0,<5.0.0)", "pyspark (>=3.4.0,<4.0.0)", "rank-bm25 (>=0.2.2,<0.3.0)", "rapidfuzz (>=3.1.1,<4.0.0)", "rapidocr-onnxruntime (>=1.3.2,<2.0.0)", "requests-toolbelt (>=1.0.0,<2.0.0)", "rspace_client (>=2.5.0,<3.0.0)", "scikit-learn (>=1.2.2,<2.0.0)", "sqlite-vss (>=0.1.2,<0.2.0)", "streamlit (>=1.18.0,<2.0.0)", "sympy (>=1.12,<2.0)", "telethon (>=1.28.5,<2.0.0)", "timescale-vector (>=0.0.1,<0.0.2)", "tqdm (>=4.48.0)", "upstash-redis (>=0.15.0,<0.16.0)", "xata (>=1.0.0a7,<2.0.0)", "xmltodict (>=0.13.0,<0.14.0)"] javascript = ["esprima (>=4.0.1,<5.0.0)"] llms = ["clarifai (>=9.1.0)", "cohere (>=4,<5)", "huggingface_hub (>=0,<1)", "manifest-ml (>=0.0.1,<0.0.2)", "nlpcloud (>=1,<2)", "openai (<2)", "openlm (>=0.0.5,<0.0.6)", "torch (>=1,<3)", "transformers (>=4,<5)"] openai = ["openai (<2)", "tiktoken (>=0.3.2,<0.6.0)"] qdrant = ["qdrant-client (>=1.3.1,<2.0.0)"] text-helpers = ["chardet (>=5.1.0,<6.0.0)"] +[[package]] +name = "langchain-community" +version = "0.0.11" +description = "Community contributed LangChain integrations." +optional = false +python-versions = ">=3.8.1,<4.0" +files = [ + {file = "langchain_community-0.0.11-py3-none-any.whl", hash = "sha256:30ab1d7dbf35d0ebe684d8a1e8964e8dedd3d31a3703790436b39674cfa06f41"}, + {file = "langchain_community-0.0.11.tar.gz", hash = "sha256:eaeaa8d63427ecf0cb32fe2f1ba4d05ad6d5ef9f7019baf21dc2dde5b1403002"}, +] + +[package.dependencies] +aiohttp = ">=3.8.3,<4.0.0" +dataclasses-json = ">=0.5.7,<0.7" +langchain-core = ">=0.1.8,<0.2" +langsmith = ">=0.0.63,<0.1.0" +numpy = ">=1,<2" +PyYAML = ">=5.3" +requests = ">=2,<3" +SQLAlchemy = ">=1.4,<3" +tenacity = ">=8.1.0,<9.0.0" + +[package.extras] +cli = ["typer (>=0.9.0,<0.10.0)"] +extended-testing = ["aiosqlite (>=0.19.0,<0.20.0)", "aleph-alpha-client (>=2.15.0,<3.0.0)", "anthropic (>=0.3.11,<0.4.0)", "arxiv (>=1.4,<2.0)", "assemblyai (>=0.17.0,<0.18.0)", "atlassian-python-api (>=3.36.0,<4.0.0)", "azure-ai-documentintelligence (>=1.0.0b1,<2.0.0)", "beautifulsoup4 (>=4,<5)", "bibtexparser (>=1.4.0,<2.0.0)", "cassio (>=0.1.0,<0.2.0)", "chardet (>=5.1.0,<6.0.0)", "cohere (>=4,<5)", "dashvector (>=1.0.1,<2.0.0)", "databricks-vectorsearch (>=0.21,<0.22)", "datasets (>=2.15.0,<3.0.0)", "dgml-utils (>=0.3.0,<0.4.0)", "esprima (>=4.0.1,<5.0.0)", "faiss-cpu (>=1,<2)", "feedparser (>=6.0.10,<7.0.0)", "fireworks-ai (>=0.9.0,<0.10.0)", "geopandas (>=0.13.1,<0.14.0)", "gitpython (>=3.1.32,<4.0.0)", "google-cloud-documentai (>=2.20.1,<3.0.0)", "gql (>=3.4.1,<4.0.0)", "gradientai (>=1.4.0,<2.0.0)", "hologres-vector (>=0.0.6,<0.0.7)", "html2text (>=2020.1.16,<2021.0.0)", "javelin-sdk (>=0.1.8,<0.2.0)", "jinja2 (>=3,<4)", "jq (>=1.4.1,<2.0.0)", "jsonschema (>1)", "lxml (>=4.9.2,<5.0.0)", "markdownify (>=0.11.6,<0.12.0)", "motor (>=3.3.1,<4.0.0)", "msal (>=1.25.0,<2.0.0)", "mwparserfromhell (>=0.6.4,<0.7.0)", "mwxml (>=0.3.3,<0.4.0)", "newspaper3k (>=0.2.8,<0.3.0)", "numexpr (>=2.8.6,<3.0.0)", "openai (<2)", "openapi-pydantic (>=0.3.2,<0.4.0)", "oracle-ads (>=2.9.1,<3.0.0)", "pandas (>=2.0.1,<3.0.0)", "pdfminer-six (>=20221105,<20221106)", "pgvector (>=0.1.6,<0.2.0)", "praw (>=7.7.1,<8.0.0)", "psychicapi (>=0.8.0,<0.9.0)", "py-trello (>=0.19.0,<0.20.0)", "pymupdf (>=1.22.3,<2.0.0)", "pypdf (>=3.4.0,<4.0.0)", "pypdfium2 (>=4.10.0,<5.0.0)", "pyspark (>=3.4.0,<4.0.0)", "rank-bm25 (>=0.2.2,<0.3.0)", "rapidfuzz (>=3.1.1,<4.0.0)", "rapidocr-onnxruntime (>=1.3.2,<2.0.0)", "requests-toolbelt (>=1.0.0,<2.0.0)", "rspace_client (>=2.5.0,<3.0.0)", "scikit-learn (>=1.2.2,<2.0.0)", "sqlite-vss (>=0.1.2,<0.2.0)", "streamlit (>=1.18.0,<2.0.0)", "sympy (>=1.12,<2.0)", "telethon (>=1.28.5,<2.0.0)", "timescale-vector (>=0.0.1,<0.0.2)", "tqdm (>=4.48.0)", "upstash-redis (>=0.15.0,<0.16.0)", "xata (>=1.0.0a7,<2.0.0)", "xmltodict (>=0.13.0,<0.14.0)", "zhipuai (>=1.0.7,<2.0.0)"] + [[package]] name = "langchain-core" -version = "0.0.9" +version = "0.1.10" description = "Building applications with LLMs through composability" optional = false python-versions = ">=3.8.1,<4.0" files = [ - {file = "langchain_core-0.0.9-py3-none-any.whl", hash = "sha256:ce5dcf05804cdc4edf0b06d6691cb3dd4ed0014ed9cc08d02bd2b1691344c137"}, - {file = "langchain_core-0.0.9.tar.gz", hash = "sha256:d3ba6e30ed57ba2a3cbe227daad81fc4edf29cd3d3e24b418782ba69b07cb07d"}, + {file = "langchain_core-0.1.10-py3-none-any.whl", hash = "sha256:d89952f6d0766cfc88d9f1e25b84d56f8d7bd63a45ad8ec1a9a038c9b49df16d"}, + {file = "langchain_core-0.1.10.tar.gz", hash = "sha256:3c9e1383264c102fcc6f865700dbb9416c4931a25d0ac2195f6311c6b867aa17"}, ] [package.dependencies] +anyio = ">=3,<5" jsonpatch = ">=1.33,<2.0" langsmith = ">=0.0.63,<0.1.0" +packaging = ">=23.2,<24.0" pydantic = ">=1,<3" +PyYAML = ">=5.3" +requests = ">=2,<3" tenacity = ">=8.1.0,<9.0.0" +[package.extras] +extended-testing = ["jinja2 (>=3,<4)"] + +[[package]] +name = "langchain-openai" +version = "0.0.2" +description = "An integration package connecting OpenAI and LangChain" +optional = false +python-versions = ">=3.8.1,<4.0" +files = [ + {file = "langchain_openai-0.0.2-py3-none-any.whl", hash = "sha256:0a46067be13ce95a029fdca339cd1034a61be1a727786178fbad702668a060f9"}, + {file = "langchain_openai-0.0.2.tar.gz", hash = "sha256:713af4a638f65b3af2f741a9d61991011c31939b070d81ede5b2e3cba625e01a"}, +] + +[package.dependencies] +langchain-core = ">=0.1.7,<0.2" +numpy = ">=1,<2" +openai = ">=1.6.1,<2.0.0" +tiktoken = ">=0.5.2,<0.6.0" + [[package]] name = "langsmith" -version = "0.0.69" +version = "0.0.80" description = "Client library to connect to the LangSmith LLM Tracing and Evaluation Platform." optional = false python-versions = ">=3.8.1,<4.0" files = [ - {file = "langsmith-0.0.69-py3-none-any.whl", hash = "sha256:49a2546bb83eedb0552673cf81a068bb08078d6d48471f4f1018e1d5c6aa46b1"}, - {file = "langsmith-0.0.69.tar.gz", hash = "sha256:8fb5297f274db0576ec650d9bab0319acfbb6622d62bc5bb9fe31c6235dc0358"}, + {file = "langsmith-0.0.80-py3-none-any.whl", hash = "sha256:dee1c6ef9e8241b82a8851926624269954d0ff8e22d82e32e73455f387f4e245"}, + {file = "langsmith-0.0.80.tar.gz", hash = "sha256:6d22ee07eb41c65b3f5166b20041a026714952497d9e80d5be6879d3a5c14d84"}, ] [package.dependencies] @@ -2124,23 +2173,23 @@ sympy = "*" [[package]] name = "openai" -version = "1.3.7" +version = "1.7.0" description = "The official Python library for the openai API" optional = false python-versions = ">=3.7.1" files = [ - {file = "openai-1.3.7-py3-none-any.whl", hash = "sha256:e5c51367a910297e4d1cd33d2298fb87d7edf681edbe012873925ac16f95bee0"}, - {file = "openai-1.3.7.tar.gz", hash = "sha256:18074a0f51f9b49d1ae268c7abc36f7f33212a0c0d08ce11b7053ab2d17798de"}, + {file = "openai-1.7.0-py3-none-any.whl", hash = "sha256:2282e8e15acb05df79cccba330c025b8e84284c7ec1f3fa31f167a8479066333"}, + {file = "openai-1.7.0.tar.gz", hash = "sha256:f2a8dcb739e8620c9318a2c6304ea72aebb572ba02fa1d586344405e80d567d3"}, ] [package.dependencies] -anyio = ">=3.5.0,<4" +anyio = ">=3.5.0,<5" distro = ">=1.7.0,<2" httpx = ">=0.23.0,<1" pydantic = ">=1.9.0,<3" sniffio = "*" tqdm = ">4" -typing-extensions = ">=4.5,<5" +typing-extensions = ">=4.7,<5" [package.extras] datalib = ["numpy (>=1)", "pandas (>=1.2.3)", "pandas-stubs (>=1.1.0.11)"] @@ -4175,4 +4224,4 @@ testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "p [metadata] lock-version = "2.0" python-versions = "^3.8.1" -content-hash = "7087f3632b0ac2946ef1ef89f04fcb9c015efc92f1548c1e38a2799cd473c380" +content-hash = "bed4abef919c343d925c158f47699247b0c8ffa5cc375a2e78c654a9353407fe" diff --git a/pyproject.toml b/pyproject.toml index 475eb5be..0f06c7bd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -24,8 +24,8 @@ keywords = ["openai", "sales", "gpt", "autonomous", "agi"] [tool.poetry.dependencies] python = "^3.8.1" -langchain = "^0.0.345" -openai = "^1.3.7" +langchain = "0.1.0" +openai = "1.7.0" chromadb = "^0.4.18" tiktoken = "^0.5.2" pydantic = "^2.5.2" @@ -34,6 +34,7 @@ ipykernel = "^6.27.1" pytest = "^7.4.3" pytest-cov = "^4.1.0" pytest-asyncio = "^0.23.1" +langchain-openai = "0.0.2" [tool.poetry.group.dev.dependencies] black = "^23.11.0" diff --git a/run.py b/run.py index bc97cea2..4ce37ba7 100644 --- a/run.py +++ b/run.py @@ -3,7 +3,7 @@ import os from dotenv import load_dotenv -from langchain.chat_models import ChatLiteLLM +from langchain_community.chat_models import ChatLiteLLM from salesgpt.agents import SalesGPT @@ -24,8 +24,7 @@ parser.add_argument( "--config", type=str, help="Path to agent config file", default="" ) - parser.add_argument("--verbose", type=bool, help="Verbosity", - default=False) + parser.add_argument("--verbose", type=bool, help="Verbosity", default=False) parser.add_argument( "--max_num_turns", type=int, diff --git a/salesgpt/agents.py b/salesgpt/agents.py index dd42c559..f5e88096 100644 --- a/salesgpt/agents.py +++ b/salesgpt/agents.py @@ -1,11 +1,12 @@ from copy import deepcopy from typing import Any, Callable, Dict, List, Union -from langchain.agents import AgentExecutor, LLMSingleActionAgent +from langchain.agents import (AgentExecutor, LLMSingleActionAgent, + create_openai_tools_agent) from langchain.chains import LLMChain, RetrievalQA from langchain.chains.base import Chain -from langchain.chat_models import ChatLiteLLM -from langchain.llms.base import create_base_retry_decorator +from langchain_community.chat_models import ChatLiteLLM +from langchain_core.language_models.llms import create_base_retry_decorator from litellm import acompletion from pydantic import Field @@ -222,57 +223,46 @@ async def _astreaming_generator(self): model=self.model_name, ) - def _call(self, inputs: Dict[str, Any]) -> None: + def _call(self, inputs: Dict[str, Any]) -> Dict[str, Any]: """Run one step of the sales agent.""" + # override inputs temporarily + inputs = { + "input": "", + "conversation_stage": self.current_conversation_stage, + "conversation_history": "\n".join(self.conversation_history), + "salesperson_name": self.salesperson_name, + "salesperson_role": self.salesperson_role, + "company_name": self.company_name, + "company_business": self.company_business, + "company_values": self.company_values, + "conversation_purpose": self.conversation_purpose, + "conversation_type": self.conversation_type, + } + # Generate agent's utterance - # if use tools if self.use_tools: - ai_message = self.sales_agent_executor.run( - input="", - conversation_stage=self.current_conversation_stage, - conversation_history="\n".join(self.conversation_history), - salesperson_name=self.salesperson_name, - salesperson_role=self.salesperson_role, - company_name=self.company_name, - company_business=self.company_business, - company_values=self.company_values, - conversation_purpose=self.conversation_purpose, - conversation_type=self.conversation_type, - ) - + ai_message = self.sales_agent_executor.invoke(inputs) + output = ai_message["output"] else: - # else - ai_message = self.sales_conversation_utterance_chain.run( - conversation_stage=self.current_conversation_stage, - conversation_history="\n".join(self.conversation_history), - salesperson_name=self.salesperson_name, - salesperson_role=self.salesperson_role, - company_name=self.company_name, - company_business=self.company_business, - company_values=self.company_values, - conversation_purpose=self.conversation_purpose, - conversation_type=self.conversation_type, - ) + ai_message = self.sales_conversation_utterance_chain.invoke(inputs) + output = ai_message["text"] # Add agent's response to conversation history agent_name = self.salesperson_name - ai_message = agent_name + ": " + ai_message - if "" not in ai_message: - ai_message += " " - self.conversation_history.append(ai_message) - print(ai_message.replace("", "")) - return {} + output = agent_name + ": " + output + if "" not in output: + output += " " + self.conversation_history.append(output) + print(output.replace("", "")) + return ai_message @classmethod @time_logger def from_llm(cls, llm: ChatLiteLLM, verbose: bool = False, **kwargs) -> "SalesGPT": """Initialize the SalesGPT Controller.""" stage_analyzer_chain = StageAnalyzerChain.from_llm(llm, verbose=verbose) - if ( - "use_custom_prompt" in kwargs.keys() - and kwargs["use_custom_prompt"] == "True" - ): + if "use_custom_prompt" in kwargs.keys() and kwargs["use_custom_prompt"] is True: use_custom_prompt = deepcopy(kwargs["use_custom_prompt"]) custom_prompt = deepcopy(kwargs["custom_prompt"]) @@ -293,7 +283,7 @@ def from_llm(cls, llm: ChatLiteLLM, verbose: bool = False, **kwargs) -> "SalesGP ) if "use_tools" in kwargs.keys() and ( - kwargs["use_tools"] == "True" or kwargs["use_tools"] == True + kwargs["use_tools"] == "True" or kwargs["use_tools"] is True ): # set up agent with tools product_catalog = kwargs["product_catalog"] diff --git a/salesgpt/chains.py b/salesgpt/chains.py index 7b8c62fc..0c5e238a 100644 --- a/salesgpt/chains.py +++ b/salesgpt/chains.py @@ -1,5 +1,6 @@ -from langchain import LLMChain, PromptTemplate -from langchain.chat_models import ChatLiteLLM +from langchain.chains import LLMChain +from langchain.prompts import PromptTemplate +from langchain_community.chat_models import ChatLiteLLM from salesgpt.logger import time_logger from salesgpt.prompts import (SALES_AGENT_INCEPTION_PROMPT, diff --git a/salesgpt/salesgptapi.py b/salesgpt/salesgptapi.py index d5f6b82d..9af960c1 100644 --- a/salesgpt/salesgptapi.py +++ b/salesgpt/salesgptapi.py @@ -1,6 +1,6 @@ import json -from langchain.chat_models import ChatLiteLLM +from langchain_community.chat_models import ChatLiteLLM from salesgpt.agents import SalesGPT diff --git a/salesgpt/tools.py b/salesgpt/tools.py index 3a4c4b30..42f596ea 100644 --- a/salesgpt/tools.py +++ b/salesgpt/tools.py @@ -1,12 +1,13 @@ from langchain.agents import Tool from langchain.chains import RetrievalQA -from langchain.embeddings.openai import OpenAIEmbeddings -from langchain.llms import OpenAI from langchain.text_splitter import CharacterTextSplitter -from langchain.vectorstores import Chroma +from langchain_community.vectorstores import Chroma +from langchain_openai import ChatOpenAI, OpenAIEmbeddings -def setup_knowledge_base(product_catalog: str = None): +def setup_knowledge_base( + product_catalog: str = None, model_name: str = "gpt-3.5-turbo" +): """ We assume that the product catalog is simply a text string. """ @@ -17,7 +18,7 @@ def setup_knowledge_base(product_catalog: str = None): text_splitter = CharacterTextSplitter(chunk_size=10, chunk_overlap=0) texts = text_splitter.split_text(product_catalog) - llm = OpenAI(temperature=0) + llm = ChatOpenAI(model_name=model_name, temperature=0) embeddings = OpenAIEmbeddings() docsearch = Chroma.from_texts( texts, embeddings, collection_name="product-knowledge-base" diff --git a/tests/test_salesgpt.py b/tests/test_salesgpt.py index 76607671..e98c37aa 100644 --- a/tests/test_salesgpt.py +++ b/tests/test_salesgpt.py @@ -2,21 +2,21 @@ import os import pytest -from langchain.chat_models import ChatLiteLLM +from dotenv import load_dotenv +from langchain_community.chat_models import ChatLiteLLM from salesgpt.agents import SalesGPT -import openai -from dotenv import load_dotenv -dotenv_path = os.path.join(os.path.dirname(__file__), '..', '.env') +dotenv_path = os.path.join(os.path.dirname(__file__), "..", ".env") load_dotenv(dotenv_path) # Now, try to load the API key -api_key = os.getenv('OPENAI_API_KEY') +api_key = os.getenv("OPENAI_API_KEY") if not api_key: raise Exception("OPENAI_API_KEY not found") #openai.api_key = os.getenv('OPENAI_API_KEY') + class TestSalesGPT: def test_valid_inference_no_tools(self, load_env): """Test that the agent will start and generate the first utterance."""