diff options
author | Navan Chauhan <navanchauhan@gmail.com> | 2023-10-13 23:50:10 -0600 |
---|---|---|
committer | Navan Chauhan <navanchauhan@gmail.com> | 2023-10-13 23:50:10 -0600 |
commit | 9f914f8d479d58d7ccc045784fe614dfea9a1219 (patch) | |
tree | db5a58ae9bdae7a7aa139c6220e048c359657298 | |
parent | 6edba6384b42fa03785ac5887e91eb310e876ced (diff) |
langchain
-rw-r--r-- | call_transcript_utils.py | 32 | ||||
-rw-r--r-- | lang_prompt_demo.py | 37 | ||||
-rw-r--r-- | stdout_filterer.py | 15 | ||||
-rw-r--r-- | tools/contacts.py | 19 | ||||
-rw-r--r-- | tools/vocode.py | 64 |
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 |