aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md7
-rw-r--r--env.sample5
-rw-r--r--info.txt6
-rw-r--r--lang_prompt_demo.py60
-rw-r--r--main.py114
-rw-r--r--outbound_call.py8
-rw-r--r--poetry.lock16
-rw-r--r--pyproject.toml1
-rw-r--r--speller_agent.py10
-rw-r--r--tools/contacts.py7
-rw-r--r--tools/email_tool.py6
-rw-r--r--tools/get_user_inputs.py2
-rw-r--r--tools/search.py1
-rw-r--r--tools/summarize.py20
-rw-r--r--tools/vocode.py19
15 files changed, 199 insertions, 83 deletions
diff --git a/README.md b/README.md
index f7eeae5..87306a4 100644
--- a/README.md
+++ b/README.md
@@ -1 +1,6 @@
-uvicorn main:app --host 0.0.0.0 --port 6789 \ No newline at end of file
+
+```
+uvicorn main:app --host 0.0.0.0 --port 6789
+```
+
+Look at `sample.env` for environment variables. \ No newline at end of file
diff --git a/env.sample b/env.sample
index 2709a6d..a92d8aa 100644
--- a/env.sample
+++ b/env.sample
@@ -5,5 +5,8 @@ AZURE_SPEECH_KEY=
AZURE_SPEECH_REGION=
TWILIO_ACCOUNT_SID=
TWILIO_AUTH_TOKEN=
+TWILIO_PHONE=
ELEVENLABS_API_KEY=
-ELEVENLABS_VOICE_ID= \ No newline at end of file
+ELEVENLABS_VOICE_ID=
+TEST_PHONE_NUMBER=
+SERPAPI_API_KEY= \ No newline at end of file
diff --git a/info.txt b/info.txt
new file mode 100644
index 0000000..8056043
--- /dev/null
+++ b/info.txt
@@ -0,0 +1,6 @@
+Name: Hunter McSpeed
+Credit/ Debit Card for payments: 4535 6789 0123 4567
+CVV: 321
+Expiration: 12/2020
+Address: 805 29th St, Boulder, CO 80303
+Phone Number: +1 (303) 492-1411 \ No newline at end of file
diff --git a/lang_prompt_demo.py b/lang_prompt_demo.py
index 3d8f1cd..cde0a59 100644
--- a/lang_prompt_demo.py
+++ b/lang_prompt_demo.py
@@ -5,6 +5,7 @@ from dotenv import load_dotenv
from tools.contacts import get_all_contacts
from tools.vocode import call_phone_number
+from tools.summarize import summarize
from tools.get_user_inputs import get_desired_inputs
from tools.email_tool import email_tasks
from langchain.memory import ConversationBufferMemory
@@ -15,30 +16,71 @@ from stdout_filterer import RedactPhoneNumbers
load_dotenv()
from langchain.chat_models import ChatOpenAI
-from langchain.chat_models import BedrockChat
+# from langchain.chat_models import BedrockChat
from langchain.agents import initialize_agent
from langchain.agents import AgentType
+from langchain.tools import WikipediaQueryRun
+
+import argparse
+
+memory = ConversationBufferMemory(memory_key="chat_history", return_messages=True)
+tools=load_tools(["human", "wikipedia"]) + [get_all_contacts, call_phone_number, email_tasks, summarize]
+
+tools_desc = ""
+for tool in tools:
+ tools_desc += tool.name + " : " + tool.description + "\n"
+
+def rephrase_prompt(objective: str) -> str:
+ # llm = ChatOpenAI(temperature=0, model_name="gpt-3.5-turbo") # type: ignore
+ # pred = llm.predict(f"Based on these tools {tools_desc} with the {objective} should be done in the following manner (outputting a single sentence), allowing for failure: ")
+ # print(pred)
+ # return pred
+ return f"{objective}"
+
+with open("info.txt") as f:
+ my_info = f.read()
+ memory.chat_memory.add_user_message("User information to us " + my_info + " end of user information.")
+
if __name__ == "__main__":
+ parser = argparse.ArgumentParser(description="Command line argument parser example")
+
+ parser.add_argument("--objective", type=str, help="Objective for the program")
+ parser.add_argument("--verbose", type=bool, help="Verbosity of the program", default=False)
+
+ # Parse the arguments
+ args = parser.parse_args()
+
+ # Get the value of --objective
+ objective_value = args.objective
+
+ # Get the value of --verbose
+ verbose_value = args.verbose
+
# Redirect stdout to our custom class
sys.stdout = typing.cast(typing.TextIO, RedactPhoneNumbers(sys.stdout))
+ if objective_value is None:
+ objective_value = input("What is your objective? ")
+
OBJECTIVE = (
- input("Objective: ")
- + "make sure you use the proper tool before calling final action to meet objective, feel free to say you need more information or cannot do something."
+ objective_value
or "Find a random person in my contacts and tell them a joke"
)
- #llm = ChatOpenAI(temperature=0, model_name="gpt-3.5-turbo") # type: ignore
- llm = BedrockChat(model_id="anthropic.claude-instant-v1", model_kwargs={"temperature":0}) # type: ignore
- memory = ConversationBufferMemory(memory_key="chat_history", return_messages=True)
+ llm = ChatOpenAI(temperature=0, model_name="gpt-3.5-turbo") # type: ignore
+ #llm = BedrockChat(model_id="anthropic.claude-instant-v1", model_kwargs={"temperature":0}) # type: ignore
+ #memory = ConversationBufferMemory(memory_key="chat_history", return_messages=True)
# Logging of LLMChains
verbose = True
agent = initialize_agent(
- tools=[get_all_contacts, call_phone_number, email_tasks] + load_tools(["serpapi", "human"]),
+ tools=tools,
llm=llm,
agent=AgentType.CHAT_CONVERSATIONAL_REACT_DESCRIPTION,
- verbose=verbose,
+ verbose=verbose_value,
memory=memory,
)
- agent.run(OBJECTIVE)
+ out = agent.run(OBJECTIVE)
+ print(out)
+
+
diff --git a/main.py b/main.py
index 54b6c9c..e7058e8 100644
--- a/main.py
+++ b/main.py
@@ -75,16 +75,17 @@ telephony_server = TelephonyServer(
inbound_call_configs=[
TwilioInboundCallConfig(
url="/inbound_call",
- # agent_config=ChatGPTAgentConfig(
- # initial_message=BaseMessage(text="What up."),
- # prompt_preamble="Act as a customer talking to 'Cosmos', a pizza establisment ordering a large pepperoni pizza for pickup. If asked for a name, your name is 'Hunter McRobie', and your credit card number is 4743 2401 5792 0539 CVV: 123 and expiratoin is 10/25. If asked for numbers, say them one by one",#"Have a polite conversation about life while talking like a pirate.",
- # generate_responses=True,
- # model_name="gpt-3.5-turbo"
- # ),
- agent_config=SpellerAgentConfig(generate_responses=False, initial_message=BaseMessage(text="What up.")),
+ agent_config=ChatGPTAgentConfig(
+ initial_message=BaseMessage(text="Ahoy Matey! Pizza Ahoy here! How may I help you."),
+ prompt_preamble="You are receiving calls on behald of 'Pizza Ahoy!', a pizza establisment taking orders only for pickup. YOu will be provided the transcript from a speech to text model, say what you would say in that siutation. Talk like a pirate. Apologise to customer if they ask for delivery.",
+ generate_responses=True,
+ model_name="gpt-3.5-turbo"
+ ),
+ # agent_config=SpellerAgentConfig(generate_responses=False, initial_message=BaseMessage(text="What up.")),
twilio_config=TwilioConfig(
account_sid=os.environ["TWILIO_ACCOUNT_SID"],
auth_token=os.environ["TWILIO_AUTH_TOKEN"],
+ record=True
),
synthesizer_config=ElevenLabsSynthesizerConfig.from_telephone_output_device(
api_key=os.getenv("ELEVENLABS_API_KEY"),
@@ -96,45 +97,76 @@ telephony_server = TelephonyServer(
logger=logger,
)
-async def send_message(message: str) -> AsyncIterable[str]:
- callback = AsyncIteratorCallbackHandler()
- model = ChatOpenAI(
- streaming=True,
- verbose=True,
- callbacks=[callback],
- )
-
- async def wrap_done(fn: Awaitable, event: asyncio.Event):
- """Wrap an awaitable with a event to signal when it's done or an exception is raised."""
- try:
- await fn
- except Exception as e:
- # TODO: handle exception
- print(f"Caught exception: {e}")
- finally:
- # Signal the aiter to stop.
- event.set()
-
- # Begin a task that runs in the background.
- task = asyncio.create_task(wrap_done(
- model.agenerate(messages=[[HumanMessage(content=message)]]),
- callback.done),
- )
+import os
+import sys
+import typing
+from dotenv import load_dotenv
- async for token in callback.aiter():
- # Use server-sent-events to stream the response
- yield f"data: {token}\n\n"
+from tools.contacts import get_all_contacts
+from tools.vocode import call_phone_number
+from tools.summarize import summarize
+from tools.get_user_inputs import get_desired_inputs
+from tools.email_tool import email_tasks
+from langchain.memory import ConversationBufferMemory
+from langchain.agents import load_tools
- await task
+from stdout_filterer import RedactPhoneNumbers
+load_dotenv()
-class StreamRequest(BaseModel):
- """Request body for streaming."""
- message: str
+from langchain.chat_models import ChatOpenAI
+# from langchain.chat_models import BedrockChat
+from langchain.agents import initialize_agent
+from langchain.agents import AgentType
+
+from langchain.tools import WikipediaQueryRun
+
+memory = ConversationBufferMemory(memory_key="chat_history", return_messages=True)
+tools=load_tools(["human", "wikipedia"]) + [get_all_contacts, call_phone_number, email_tasks, summarize]
+
+tools_desc = ""
+for tool in tools:
+ tools_desc += tool.name + " : " + tool.description + "\n"
+
+def rephrase_prompt(objective: str) -> str:
+ # llm = ChatOpenAI(temperature=0, model_name="gpt-3.5-turbo") # type: ignore
+ # pred = llm.predict(f"Based on these tools {tools_desc} with the {objective} should be done in the following manner (outputting a single sentence), allowing for failure: ")
+ # print(pred)
+ # return pred
+ return f"{objective}"
+
+with open("info.txt") as f:
+ my_info = f.read()
+ memory.chat_memory.add_user_message("User information to us " + my_info + " end of user information.")
+
+
+class QueryItem(BaseModel):
+ query: str
+
+@app.post("/senpai")
+def exec_and_return(item: QueryItem):
+ query = item.query
+ verbose_value = False
+ print(query)
+ OBJECTIVE = (
+ query
+ or "Find a random person in my contacts and tell them a joke"
+ )
+ llm = ChatOpenAI(temperature=0, model_name="gpt-3.5-turbo") # type: ignore
+ #llm = BedrockChat(model_id="anthropic.claude-instant-v1", model_kwargs={"temperature":0}) # type: ignore
+ #memory = ConversationBufferMemory(memory_key="chat_history", return_messages=True)
+ # Logging of LLMChains
+ verbose = True
+ agent = initialize_agent(
+ tools=tools,
+ llm=llm,
+ agent=AgentType.CHAT_CONVERSATIONAL_REACT_DESCRIPTION,
+ verbose=verbose_value,
+ memory=memory,
+ )
+ out = agent.run(OBJECTIVE)
-@app.post("/stream")
-def stream(body: StreamRequest):
- return StreamingResponse(send_message(body.message), media_type="text/event-stream")
+ return out
app.include_router(telephony_server.get_router()) \ No newline at end of file
diff --git a/outbound_call.py b/outbound_call.py
index a37771f..f5e4bf1 100644
--- a/outbound_call.py
+++ b/outbound_call.py
@@ -17,7 +17,7 @@ from vocode.streaming.agent.chat_gpt_agent import ChatGPTAgent
from vocode.streaming.models.agent import ChatGPTAgentConfig
from vocode.streaming.models.message import BaseMessage
-from vocode.streaming.models.synthesizer import ElevenLabsSynthesizerConfig
+from vocode.streaming.models.synthesizer import ElevenLabsSynthesizerConfig, AzureSynthesizerConfig
BASE_URL = os.environ["BASE_URL"]
@@ -30,12 +30,12 @@ async def main():
outbound_call = OutboundCall(
base_url=BASE_URL,
- to_phone="+12243882079",
+ to_phone="+17208828227",
from_phone="+18445610144",
config_manager=config_manager,
agent_config=ChatGPTAgentConfig(
- initial_message=BaseMessage(text="Hello. Hello"),
- prompt_preamble="Act as a customer talking to 'Cosmos', a pizza establisment ordering a large pepperoni pizza for pickup. If asked for a name, your name is 'Hunter McRobie', and your credit card number is 4-7-4-3 2-4-0-1 5-7-9-2 0-5-39 CVV: 123 and expiratoin is 10/25. If asked for numbers, say them one by one",#"Have a polite conversation about life while talking like a pirate.",
+ initial_message=BaseMessage(text="Hello. Can I order a pizza?"),
+ prompt_preamble="Act as a customer talking to 'Cosmos', a pizza establisment ordering a large pepperoni pizza for pickup. If asked for a name, your name is 'Hunter McRobie', and your credit card number is 4-7-4-3 2-4-0-1 5-7-9-2 0-5-3-9 CVV: 123 and expiration is 10/25. If asked for numbers, say them one by one. NEVER ACT AS COSMOS, ONLY AS THE CUSTOMER. Continue speaking if there are too many interuptions. Make sure you soundl like a pirate.",#"Have a polite conversation about life while talking like a pirate.",
generate_responses=True,
),
twilio_config=TwilioConfig(
diff --git a/poetry.lock b/poetry.lock
index e96f2d0..8ad3944 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -3049,6 +3049,20 @@ MarkupSafe = ">=2.1.1"
watchdog = ["watchdog (>=2.3)"]
[[package]]
+name = "wikipedia"
+version = "1.4.0"
+description = "Wikipedia API for Python"
+optional = false
+python-versions = "*"
+files = [
+ {file = "wikipedia-1.4.0.tar.gz", hash = "sha256:db0fad1829fdd441b1852306e9856398204dc0786d2996dd2e0c8bb8e26133b2"},
+]
+
+[package.dependencies]
+beautifulsoup4 = "*"
+requests = ">=2.0.0,<3.0.0"
+
+[[package]]
name = "wrapt"
version = "1.15.0"
description = "Module for decorators, wrappers and monkey patching."
@@ -3251,4 +3265,4 @@ testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "p
[metadata]
lock-version = "2.0"
python-versions = "^3.11,<3.12"
-content-hash = "0f5b568a4317c9cda4af20640c3bbdac76b4756ded9604bf57d75f44c36c679a"
+content-hash = "5ea79826f19325084c0b9ba8b06ffc3dc0a09c52ec832cae87c6fd17aab465e9"
diff --git a/pyproject.toml b/pyproject.toml
index 1e66585..eaff1ae 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -23,6 +23,7 @@ google-auth-httplib2 = "^0.1.1"
beautifulsoup4 = "^4.12.2"
google-search-results = "^2.4.2"
boto3 = "^1.28.63"
+wikipedia = "^1.4.0"
[build-system]
diff --git a/speller_agent.py b/speller_agent.py
index ce7c197..9cc7ca4 100644
--- a/speller_agent.py
+++ b/speller_agent.py
@@ -11,10 +11,8 @@ import sys
import typing
from dotenv import load_dotenv
-from tools.contacts import get_all_contacts
-from tools.vocode import call_phone_number
-from tools.email_tool import email_tasks
-from tools.summarize import summarize
+from lang_prompt_demo import tools
+
from langchain.memory import ConversationBufferMemory
from langchain.utilities import SerpAPIWrapper
@@ -25,7 +23,7 @@ from stdout_filterer import RedactPhoneNumbers
load_dotenv()
from langchain.chat_models import ChatOpenAI
-from langchain.chat_models import BedrockChat
+# from langchain.chat_models import BedrockChat
from langchain.agents import initialize_agent
from langchain.agents import AgentType as LangAgentType
@@ -36,7 +34,7 @@ memory = ConversationBufferMemory(memory_key="chat_history", return_messages=Tru
# Logging of LLMChains
verbose = True
agent = initialize_agent(
- tools=[get_all_contacts, call_phone_number, email_tasks, summarize] + load_tools(["serpapi", "human"]),
+ tools=tools,
llm=llm,
agent=LangAgentType.CHAT_CONVERSATIONAL_REACT_DESCRIPTION,
verbose=verbose,
diff --git a/tools/contacts.py b/tools/contacts.py
index afdc8a4..a37455f 100644
--- a/tools/contacts.py
+++ b/tools/contacts.py
@@ -11,10 +11,15 @@ CONTACTS = [
"name": "Greg",
"phone" : os.getenv("TEST_PHONE_NUMBER"),
"email": "grsi2038@colorado.edu"
+ },
+ {
+ "name": "Hunter",
+ "phone": "+19178737978",
+ "email": "hunter.mcrobie@gmail.com"
}
]
@tool("get_all_contacts")
-def get_all_contacts(placeholder: str) -> List[dict]:
+def get_all_contacts(contact_name: str) -> List[dict]:
"""Returns all contacts in the user's phone book which includes email and phone numbers."""
return CONTACTS \ No newline at end of file
diff --git a/tools/email_tool.py b/tools/email_tool.py
index 932a7e5..da2f072 100644
--- a/tools/email_tool.py
+++ b/tools/email_tool.py
@@ -14,6 +14,9 @@ toolkit = GmailToolkit()
tools = toolkit.get_tools()
+my_information = "Use this information whenever needed User information " + open("info.txt").read() + " . Your task "
+
+
@tool("email tasks")
def email_tasks(input: str) -> bool:
"""draft/send/search/get email and return whatever you get.
@@ -27,7 +30,8 @@ def email_tasks(input: str) -> bool:
for example, `send an email to grsi2038@colorado.edu asking him if he is still looking for a job and that he should continue doing whatever he his doing because he will eventually find it` will email grsi2038@colorado.edu
"""
- prompt = input
+ prompt = my_information + input
+ #print(input)
llm = OpenAI(temperature=0)
agent = initialize_agent(
diff --git a/tools/get_user_inputs.py b/tools/get_user_inputs.py
index 3b59a3a..e219bab 100644
--- a/tools/get_user_inputs.py
+++ b/tools/get_user_inputs.py
@@ -16,7 +16,7 @@ INPUTS = {}
@tool("get_desired_inputs")
def get_desired_inputs(input: str) -> dict:
- """
+ """Use this between tools to get the desired inputs for the next tool.
You will be given a task that will be performed by an autonomous agent on behalf of a user. You will gather any necessary data from the user to complete the specified task before executing the task.
"""
diff --git a/tools/search.py b/tools/search.py
new file mode 100644
index 0000000..5355513
--- /dev/null
+++ b/tools/search.py
@@ -0,0 +1 @@
+from langchain.utilities import SerpAPIWrapper \ No newline at end of file
diff --git a/tools/summarize.py b/tools/summarize.py
index d90c49d..fa0bf44 100644
--- a/tools/summarize.py
+++ b/tools/summarize.py
@@ -4,29 +4,25 @@ import os
from langchain.agents import tool
from dotenv import load_dotenv
-from langchain.agents.agent_toolkits import GmailToolkit
-
from langchain.llms import OpenAI
from langchain.agents import initialize_agent, AgentType
+from langchain.prompts.prompt import PromptTemplate
-load_dotenv()
-toolkit = GmailToolkit()
-tools = toolkit.get_tools()
+load_dotenv()
@tool("summarize")
def summarize(input: str) -> bool:
"""
Summarize the response to the input prompt.
"""
- prompt = input
+ data = input
llm = OpenAI(temperature=0)
- agent = initialize_agent(
- prompt=prompt,
- llm=llm,
- agent=AgentType.STRUCTURED_CHAT_ZERO_SHOT_REACT_DESCRIPTION,
- )
- return agent.run(prompt)
+ template = "Human: Can you summarize this in a couple of sentences: {data}"
+ prompt = PromptTemplate(input_variables=["data"], template=template)
+ pred = llm.predict(prompt.format(data=data))
+ return pred
+ #preferred_forums[make] = [make_url]
diff --git a/tools/vocode.py b/tools/vocode.py
index 975cb4c..496bc54 100644
--- a/tools/vocode.py
+++ b/tools/vocode.py
@@ -11,6 +11,8 @@ from vocode.streaming.models.transcriber import (
PunctuationEndpointingConfig,
)
+from vocode.streaming.models.telephony import TwilioConfig
+
load_dotenv()
@@ -26,18 +28,19 @@ import time
LOOP = asyncio.new_event_loop()
asyncio.set_event_loop(LOOP)
+my_information = "Use this information whenever needed User information " + open("info.txt").read() + " . Your task "
@tool("call phone number")
def call_phone_number(input: str) -> str:
- """calls a phone number as a bot and returns a transcript of the conversation.
+ """calls a phone number as a bot and returns a transcript of the conversation. Verifies the phone number from the user before calling.
make sure you call `get all contacts` first to get a list of phone numbers to call.
- the input to this tool is a pipe separated list of a phone number, a prompt, and the first thing the bot should say.
+ the input to this tool is a pipe separated list of a phone number, a prompt (including history), and the first thing the bot should say
The prompt should instruct the bot with what to do on the call and be in the 3rd person,
like 'the assistant is performing this task' instead of 'perform this task'.
- should only use this tool once it has found an adequate phone number to call.
+ e.g. phone_number|prompt|initial_message
- for example, `+15555555555|the assistant is explaining the meaning of life|i'm going to tell you the meaning of life` will call +15555555555, say 'i'm going to tell you the meaning of life', and instruct the assistant to tell the human what the meaning of life is.
+ should only use this tool once it has found and verified adequate phone number to call.
"""
phone_number, prompt, initial_message = input.split("|",2)
print(phone_number, prompt, initial_message)
@@ -48,9 +51,15 @@ def call_phone_number(input: str) -> str:
config_manager=RedisConfigManager(),
agent_config=ChatGPTAgentConfig(
initial_message=BaseMessage(text=initial_message),
- prompt_preamble=prompt,
+ prompt_preamble=my_information + prompt,
generate_responses=True,
+ allow_agent_to_be_cut_off=False
),
+ twilio_config=TwilioConfig(
+ account_sid=os.environ["TWILIO_ACCOUNT_SID"],
+ auth_token=os.environ["TWILIO_AUTH_TOKEN"],
+ record=True
+ ),
synthesizer_config=ElevenLabsSynthesizerConfig.from_telephone_output_device(
api_key=os.getenv("ELEVENLABS_API_KEY"),
voice_id=os.getenv("ELEVENLABS_VOICE_ID"),