aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--call_transcript_utils.py32
-rw-r--r--lang_prompt_demo.py37
-rw-r--r--stdout_filterer.py15
-rw-r--r--tools/contacts.py19
-rw-r--r--tools/vocode.py64
5 files changed, 167 insertions, 0 deletions
diff --git a/call_transcript_utils.py b/call_transcript_utils.py
new file mode 100644
index 0000000..ce0764c
--- /dev/null
+++ b/call_transcript_utils.py
@@ -0,0 +1,32 @@
+import os
+from typing import Optional
+
+CALL_TRANSCRIPTS_DIR = os.path.join(os.path.dirname(__file__), "call_transcripts")
+
+
+def add_transcript(conversation_id: str, transcript: str) -> None:
+ transcript_path = os.path.join(
+ CALL_TRANSCRIPTS_DIR, "{}.txt".format(conversation_id)
+ )
+ with open(transcript_path, "a") as f:
+ f.write(transcript)
+
+
+def get_transcript(conversation_id: str) -> Optional[str]:
+ transcript_path = os.path.join(
+ CALL_TRANSCRIPTS_DIR, "{}.txt".format(conversation_id)
+ )
+ if os.path.exists(transcript_path):
+ with open(transcript_path, "r") as f:
+ return f.read()
+ return None
+
+
+def delete_transcript(conversation_id: str) -> bool:
+ transcript_path = os.path.join(
+ CALL_TRANSCRIPTS_DIR, "{}.txt".format(conversation_id)
+ )
+ if os.path.exists(transcript_path):
+ os.remove(transcript_path)
+ return True
+ return False
diff --git a/lang_prompt_demo.py b/lang_prompt_demo.py
new file mode 100644
index 0000000..d63aea3
--- /dev/null
+++ b/lang_prompt_demo.py
@@ -0,0 +1,37 @@
+import os
+import sys
+import typing
+from dotenv import load_dotenv
+
+from tools.contacts import get_all_contacts
+from tools.vocode import call_phone_number
+from langchain.memory import ConversationBufferMemory
+
+from stdout_filterer import RedactPhoneNumbers
+
+load_dotenv()
+
+from langchain.chat_models import ChatOpenAI
+from langchain.agents import initialize_agent
+from langchain.agents import AgentType
+
+if __name__ == "__main__":
+ # Redirect stdout to our custom class
+ sys.stdout = typing.cast(typing.TextIO, RedactPhoneNumbers(sys.stdout))
+
+ OBJECTIVE = (
+ input("Objective: ")
+ or "Find a random person in my contacts and tell them a joke"
+ )
+ llm = ChatOpenAI(temperature=0, model_name="gpt-4") # 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],
+ llm=llm,
+ agent=AgentType.CHAT_CONVERSATIONAL_REACT_DESCRIPTION,
+ verbose=verbose,
+ memory=memory,
+ )
+ agent.run(OBJECTIVE)
diff --git a/stdout_filterer.py b/stdout_filterer.py
new file mode 100644
index 0000000..c4cf845
--- /dev/null
+++ b/stdout_filterer.py
@@ -0,0 +1,15 @@
+import re
+
+
+class RedactPhoneNumbers:
+ def __init__(self, stream):
+ self.stream = stream
+
+ def write(self, text):
+ # Regular expression to match phone numbers
+ phone_regex = r"(\+\d{1,2}\s?)?1?\-?\.?\s?\(?\d{3}\)?[\s.-]?\d{3}[\s.-]?\d{4}"
+ redacted_text = re.sub(phone_regex, "****", text)
+ self.stream.write(redacted_text)
+
+ def flush(self):
+ self.stream.flush()
diff --git a/tools/contacts.py b/tools/contacts.py
new file mode 100644
index 0000000..4f4a3be
--- /dev/null
+++ b/tools/contacts.py
@@ -0,0 +1,19 @@
+from typing import List
+from langchain.agents import tool
+
+from dotenv import load_dotenv
+load_dotenv()
+
+import os
+
+CONTACTS = [
+ {
+ "name": "Greg",
+ "phone" : os.getenv("TEST_PHONE_NUMBER")
+ }
+]
+
+@tool("get_all_contacts")
+def get_all_contacts(placeholder: str) -> List[dict]:
+ """Returns all contacts in the user's phone book."""
+ return CONTACTS \ No newline at end of file
diff --git a/tools/vocode.py b/tools/vocode.py
new file mode 100644
index 0000000..f752eff
--- /dev/null
+++ b/tools/vocode.py
@@ -0,0 +1,64 @@
+import logging
+import asyncio
+import os
+from langchain.agents import tool
+from dotenv import load_dotenv
+
+from vocode.streaming.models.message import BaseMessage
+from vocode.streaming.models.synthesizer import ElevenLabsSynthesizerConfig
+from vocode.streaming.models.transcriber import DeepgramTranscriberConfig, PunctuationEndpointingConfig
+
+
+load_dotenv()
+
+from call_transcript_utils import delete_transcript, get_transcript
+
+from vocode.streaming.telephony.conversation.outbound_call import OutboundCall
+from vocode.streaming.telephony.config_manager.redis_config_manager import (
+ RedisConfigManager,
+)
+from vocode.streaming.models.agent import ChatGPTAgentConfig
+import time
+
+LOOP = asyncio.new_event_loop()
+asyncio.set_event_loop(LOOP)
+
+@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.
+ 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 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.
+
+ 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.
+ """
+ phone_number, prompt, initial_message = input.split("|",2)
+ call = OutboundCall(
+ base_url=os.environ["BASE_URL"],
+ to_phone=phone_number,
+ from_phone=os.environ['TWILIO_PHONE'],
+ config_manager=RedisConfigManager(),
+ agent_config=ChatGPTAgentConfig(
+ initial_message=BaseMessage(text=initial_message),
+ prompt_preamble=prompt,
+ generate_responses=True,
+ ),
+ synthesizer_config=ElevenLabsSynthesizerConfig.from_telephone_output_device(
+ api_key=os.getenv("ELEVENLABS_API_KEY"),
+ voice_id=os.getenv("ELEVENLABS_VOICE_ID")
+ ),
+ transcriber_config=DeepgramTranscriberConfig.from_telephone_input_device(
+ endpointing_config=PunctuationEndpointingConfig()
+ ),
+ logger=logging.Logger("OutboundCall")
+ )
+ LOOP.run_until_complete(call.start())
+ while True:
+ maybe_transcript = get_transcript(call.conversation_id)
+ if maybe_transcript:
+ delete_transcript(call.conversation_id)
+ return maybe_transcript
+ else:
+ time.sleep(1) \ No newline at end of file