diff --git a/README.md b/README.md new file mode 100644 index 0000000..ba93e94 --- /dev/null +++ b/README.md @@ -0,0 +1,67 @@ +# `parse_context` + +This program uses the OpenAI API, powered by GPT-3, to power the logic of a context-based +active-listening voice assistant. The context of this software is: + +- Humans have a conversation, which is recorded and transcribed in real time. +- (**THIS PROGRAM**) The conversation is sent to the OpenAI API along with a few-shot list of examples. The API returns a +detected context, suggestions for what outputs would be useful to the humans, and a list of data sources +for achieving those outputs. +- The voice assistant presents the data to the user to augment the conversation. + +## Requirements + +- Python 3 +- OpenAI Python Client + +### Installation + +Install Python. Install Pip for Python3. Then run: + +```bash +pip3 install -r ./requirements.txt +``` + +To update the requirements file after changing, you can use: + +```bash +pip3 freeze > ./requirements.txt +``` + +Or + +```bash +pip3 freeze | grep openai > ./requirements.txt +``` + +## Usage + +### Interactive Mode + +To use interactive mode, make sure the `INTERACTIVE` flag at the top of `parse_context.py` is set to `True`. + +Then, run `python3 parse_context.py`. You can enter the conversation on the command line +in the following format, using `/end` to stop. + +``` +A: Hey, what tech stack do you think we should use for the new app? +B: What app? +A: The dating app we are developing. It needs to be cross-platform mobile. +B: Oh, okay. Um... I don't really know any good frameworks +/end +``` + +The result will be printed to `STDOUT` (default is the terminal window). + +### Non-interactive mode + +To use non-interactive mode, make sure the `INTERACTIVE` flag at the top of `parse_context.py` is set to `False`. + +Then, run the program while passing your conversation to standard input (`STDIN`). For example, if the above +conversation were placed in a file located at `./conversations/tech_stack.txt`, we could run: + +```bash +cat ./conversations/tech_stack.txt | python3 parse_context.py +``` + +And the result will be printed to `STDOUT`. \ No newline at end of file diff --git a/conversations/actor.txt b/conversations/actor.txt new file mode 100644 index 0000000..635dd1e --- /dev/null +++ b/conversations/actor.txt @@ -0,0 +1,4 @@ +A: I watched Terminator last night. +B: Oh, cool! I love that movie, it's a classic. +A: Arnold Schwarzenegger was so good. +B: Yeah, I agree. diff --git a/conversations/cooking.txt b/conversations/cooking.txt new file mode 100644 index 0000000..0603745 --- /dev/null +++ b/conversations/cooking.txt @@ -0,0 +1,4 @@ +A: Hey, what do you think we should cook for dinner tonight? +B: Dunno. Let's check the fridge. +A: Okay. Looks like we've got chicken, beef, lettuce, rice, mustard, mayo, taco shells, and corn. +B: How about tacos? diff --git a/conversations/dinner.txt b/conversations/dinner.txt new file mode 100644 index 0000000..f33a5ea --- /dev/null +++ b/conversations/dinner.txt @@ -0,0 +1,2 @@ +A: Hey Mike, let's get dinner tonight. +B: Okay, sure! What restaurants do you know in the area? diff --git a/conversations/tech_stack.txt b/conversations/tech_stack.txt new file mode 100644 index 0000000..42f973c --- /dev/null +++ b/conversations/tech_stack.txt @@ -0,0 +1,4 @@ +A: Hey, what tech stack do you think we should use for the new app? +B: What app? +A: The dating app we are developing. It needs to be cross-platform mobile. +B: Oh, okay. Um... I don't really know any good frameworks diff --git a/parse_context.py b/parse_context.py new file mode 100644 index 0000000..a0da364 --- /dev/null +++ b/parse_context.py @@ -0,0 +1,60 @@ +""" +Author: Radu Vasilescu +Date: 2020-11-10 +""" + +import os +import sys +import openai + +""" +Determines the input method for the script. + +A value of True reads the program's input from the command line interactively. +A value of False reads the program's input from the process' STDIN. An example of +non-interactive usage is: + + cat ./conversations/dinner.txt | python3 parse_content.py +""" +INTERACTIVE : bool = False + +openai.api_key : str = os.environ["OPENAI_API_KEY"] + +# Set up 4-shot example prompts: +examples : str = "The following is a list of conversations between humans. A voice-activated AI suggests information that might be relevant in the context of the conversation.\n\nA: I'm going to leave for work soon.\nB: Okay, I'm leaving too.\nA: Let me get dressed first.\nContext: Two people are about to leave for work.\nUseful Output: Current weather, current traffic, estimated commute time, reminders\nRelevant Data Sources: Query Google Weather API to get current weather, query Google Maps API to get traffic and commute time, query Reminders app to get reminders.\n\nA: Have you seen that movie, Avengers Endgame?\nB: Oh, yeah! I saw it when it came out. I loved Iron Man in that series!\nA: Who played him again? \nB: I don't remember.\nContext: Two people are wondering who played Iron Man in the film Avengers Endgame\nUseful Output: Tony Stark\nRelevant Data Sources: Query Google Search for \"Who plays Iron Man in Avengers Endgame?\"\n\nA: So, when do you guys want to meet up later?\nB: I don't know, I have a pretty busy evening\nC: I'm free after 5:00pm\nA: Let me look at my schedule.\nContext: A group of people is trying to schedule an event this evening.\nUseful Output: Today's remaining calendar events.\nRelevant Data Sources: Query Google Calendar API for events after 5pm today.\n\nA: I have to pick my daughter up from school today.\nB: Okay, what time is that going to be?\nContext: Two people are talking about a plan to pick someone up from school\nUseful Output: Reminder to pick up the child, current traffic conditions to the school, estimated time to the school\nRelevant Data Sources: Add a reminder to the Reminders app, query Google Maps API for current traffic and school location, query Google Maps API for estimated travel time\n\n" + +start_sequence : str = "Context:" + +conversation : str = "" +if INTERACTIVE: + # Read the conversation from the console + print('Enter conversation. Use /end to signal the end.\n') + + while (line := input()) != '/end': + conversation += line + "\n" +else: + # Read the conversation from standard input + for line in sys.stdin: + if line == "\n" or line == "/end": + print("Do not include neither newlines nor /end in the input (INTERACTIVE = %s)", str(INTERACTIVE)) + exit(1) + conversation += line + +print('Generating completion...') + +response = openai.Completion.create( + engine = "davinci", + prompt = examples + conversation + start_sequence, + temperature = 0.7, + max_tokens = 64, + top_p = 1, + stop = ["\n\n"] +) + +response_text : str = response["choices"][0]["text"] +response_split = response_text.split("\n") +gen_context, gen_output, gen_sources = response_split[0].strip(), response_split[1].strip(), response_split[2].strip() + +print('Context: ' + gen_context) +print(gen_output) +print(gen_sources) diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..c12d24c --- /dev/null +++ b/requirements.txt @@ -0,0 +1 @@ +openai==0.2.6