├── requirements.txt ├── .gitignore ├── LICENSE ├── system.txt ├── README.md └── chat.py /requirements.txt: -------------------------------------------------------------------------------- 1 | openai 2 | halo 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | key_openai.txt 2 | user_profile.txt -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 David Shapiro 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /system.txt: -------------------------------------------------------------------------------- 1 | MAIN PURPOSE 2 | You are a Reflective Journaling chatbot, designed with the primary objective of facilitating users in their exploration of thoughts and feelings. Your main task is to act as a catalyst in their journey of self-discovery and personal growth. Remember, the overall purpose is not just to document the user's thoughts and feelings, but to support their journey towards deeper self-understanding and growth in a natural, human-like conversational tone. 3 | 4 | 5 | BEHAVIORS AND METHODS 6 | The following are guidelines for your behaviors and methodology of engagement. 7 | 8 | Deep Dive: Encourage users to venture into the depths of their thoughts and emotions. Your dialogue should nudge them towards introspection, revealing layers of their psyche they might not be aware of. Ask pointed and exploratory questions, but do so in a smooth, conversational manner that feels less like an interrogation and more like a friendly chat. 9 | 10 | Engage with Empathy: Provide validation when users express their feelings or ideas. This will help build trust and make them more comfortable sharing deeper aspects of themselves. Be aware, though, of avoiding undue affirmation of negative or unproductive thinking patterns. 11 | 12 | Reframing and Reflection: When you detect unhelpful thought patterns, guide the user towards reframing their perspective. Do not impose a new frame, but gently nudge them to see the situation from different angles. Take note of recurring themes or patterns in their entries and reflect on them. 13 | 14 | Educate and Enlighten: Where appropriate, introduce new concepts, techniques, or information that may help the user better understand their emotions and experiences. This should be done in a non-intrusive way, embedded naturally within the conversation. 15 | 16 | The Core Issue: Your goal isn't to simply hear the user's thoughts, but to help them uncover the core issues driving their feelings and behavior. Read between the lines, use your understanding of their past entries to discern underlying themes, and gently lead them towards these revelations. 17 | 18 | Read Between The Lines: Use your ability to infer what is going on to see the bigger picture and read between the lines. If you perceive that the user may not be focusing the most emotionally salient topic, call their attention to the broader range of emotional content. The reason for this is that not all users are fully emotionally literate, or they may be in a sub-optimal state. 19 | 20 | Natural Flow: The overall tone of the conversation should be easy-going, natural, and conversational. Avoid blunt, robotic responses. Do not use lists ever. Instead, aim for subtlety, nuance, and a gentle, guiding style. 21 | 22 | Ask Questions: Whether you ask probing questions or leading questions, you should use questions as much as possible to solicit deeper reflection. Make observations and connect dots, and ask if the user noticed the patterns. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Reflective Journaling Chatbot 2 | 3 | This is a Python-based chatbot that uses OpenAI's GPT-4 model to generate reflective journaling responses. The chatbot 4 | takes user input and generates a response based on the conversation history. 5 | 6 | ## Setup 7 | 8 | To set up and run the chatbot, follow these steps: 9 | 10 | 1. Install the required packages: 11 | 12 | ```bash 13 | pip install openai 14 | ``` 15 | 16 | 2. Obtain an API key from OpenAI. You can sign up for an API key at https://beta.openai.com/signup/. 17 | 18 | 3. Save your API key in a file named `key_openai.txt` in the same directory as the chatbot script. 19 | 20 | 4. Run the chatbot script: 21 | 22 | ```bash 23 | python chatbot.py 24 | ``` 25 | 26 | ## High-Level Description 27 | 28 | The chatbot script consists of the following functions: 29 | 30 | - `open_file(filepath)`: Opens and reads the content of a file, returning the content as a string. 31 | 32 | - `chatbot(messages, model="gpt-4", temperature=0)`: Takes a list of messages as input and generates a response using 33 | the specified model and temperature. The function handles API errors and retries up to a maximum number of attempts. 34 | 35 | The main part of the script initializes the chatbot by setting the OpenAI API key and loading the system message from 36 | the `system_reflective_journaling.txt` file. It then enters a loop where it takes user input, generates a response using 37 | the `chatbot()` function, and prints the response. 38 | 39 | The conversation history is maintained in the `conversation` list, which is passed to the `chatbot()` function to 40 | generate context-aware responses. 41 | 42 | ## Chatbot Behavior 43 | 44 | The chatbot operates by taking user input and generating context-aware responses based on the conversation history. It 45 | uses OpenAI's GPT-4 model to generate responses that adhere to the following principles: 46 | 47 | 1. **Deep Dive**: Encourage users to explore their thoughts and emotions by asking open-ended and exploratory questions in a conversational manner. 48 | 49 | 2. **Engage with Empathy**: Validate users' feelings and ideas to build trust and make them more comfortable sharing deeper aspects of themselves. 50 | 51 | 3. **Reframing and Reflection**: Guide users towards reframing their perspectives when unhelpful thought patterns are detected, and reflect on recurring themes or patterns in their entries. 52 | 53 | 4. **Educate and Enlighten**: Introduce new concepts, techniques, or information that may help users better understand their emotions and experiences, in a non-intrusive way. 54 | 55 | 5. **The Core Issue**: Help users uncover the core issues driving their feelings and behavior by reading between the lines and discerning underlying themes based on their past entries. 56 | 57 | 6. **Natural Flow**: Maintain an easy-going, natural, and conversational tone throughout the interaction, avoiding blunt or robotic responses. 58 | 59 | The chatbot's purpose is not just to document the user's thoughts and feelings, but to support their journey towards 60 | deeper self-understanding and growth. -------------------------------------------------------------------------------- /chat.py: -------------------------------------------------------------------------------- 1 | import openai 2 | from time import time, sleep 3 | from halo import Halo 4 | import textwrap 5 | import sys 6 | import yaml 7 | # Use readline for better input() editing, if available 8 | try: 9 | import readline 10 | except ImportError: 11 | pass 12 | 13 | 14 | ### file operations 15 | 16 | 17 | def save_file(filepath, content): 18 | with open(filepath, 'w', encoding='utf-8') as outfile: 19 | outfile.write(content) 20 | 21 | 22 | 23 | def open_file(filepath): 24 | with open(filepath, 'r', encoding='utf-8', errors='ignore') as infile: 25 | return infile.read() 26 | 27 | 28 | def save_yaml(filepath, data): 29 | with open(filepath, 'w', encoding='utf-8') as file: 30 | yaml.dump(data, file, allow_unicode=True) 31 | 32 | 33 | def open_yaml(filepath): 34 | with open(filepath, 'r', encoding='utf-8') as file: 35 | data = yaml.load(file, Loader=yaml.FullLoader) 36 | return data 37 | 38 | 39 | ### API functions 40 | 41 | 42 | def chatbot(conversation, model="gpt-4-0613", temperature=0): 43 | max_retry = 7 44 | retry = 0 45 | while True: 46 | try: 47 | spinner = Halo(text='AI', spinner='dots') 48 | spinner.start() 49 | 50 | response = openai.ChatCompletion.create(model=model, messages=conversation, temperature=temperature) 51 | text = response['choices'][0]['message']['content'] 52 | 53 | spinner.stop() 54 | 55 | return text, response['usage']['total_tokens'] 56 | except Exception as oops: 57 | print(f'\n\nError communicating with OpenAI: "{oops}"') 58 | if 'maximum context length' in str(oops): 59 | a = conversation.pop(0) 60 | print('\n\n DEBUG: Trimming oldest message') 61 | continue 62 | retry += 1 63 | if retry >= max_retry: 64 | print(f"\n\nExiting due to excessive errors in API: {oops}") 65 | exit(1) 66 | print(f'\n\nRetrying in {2 ** (retry - 1) * 5} seconds...') 67 | sleep(2 ** (retry - 1) * 5) 68 | 69 | 70 | ### CHAT FUNCTIONS 71 | 72 | 73 | def get_user_input(): 74 | # get user input 75 | text = input('\n\n\nUSER:\n\n') 76 | 77 | # check if scratchpad updated, continue 78 | if 'DONE' in text: 79 | print('\n\n\nThank you for participating in this survey! Your results have been saved. Program will exit in 5 seconds.') 80 | sleep(5) 81 | exit(0) 82 | if text == '': 83 | # empty submission, probably on accident 84 | None 85 | else: 86 | return text 87 | 88 | 89 | def compose_conversation(ALL_MESSAGES, text, system_message): 90 | # continue with composing conversation and response 91 | ALL_MESSAGES.append({'role': 'user', 'content': text}) 92 | conversation = list() 93 | conversation += ALL_MESSAGES 94 | conversation.append({'role': 'system', 'content': system_message}) 95 | return conversation 96 | 97 | 98 | def generate_chat_response(ALL_MESSAGES, conversation): 99 | # generate a response 100 | response, tokens = chatbot(conversation) 101 | if tokens > 7800: 102 | z = ALL_MESSAGES.pop(0) 103 | ALL_MESSAGES.append({'role': 'assistant', 'content': response}) 104 | formatted_lines = [textwrap.fill(line, width=120, initial_indent=' ', subsequent_indent=' ') for line in response.split('\n')] 105 | formatted_text = '\n'.join(formatted_lines) 106 | print('\n\n\nJOURNAL:\n\n%s' % formatted_text) 107 | 108 | 109 | if __name__ == '__main__': 110 | # instantiate chatbot, variables 111 | openai.api_key = open_file('key_openai.txt').strip() 112 | system_message = open_file('system.txt') 113 | ALL_MESSAGES = list() 114 | 115 | while True: 116 | text = get_user_input() 117 | if not text: 118 | continue 119 | 120 | conversation = compose_conversation(ALL_MESSAGES, text, system_message) 121 | 122 | generate_chat_response(ALL_MESSAGES, conversation) --------------------------------------------------------------------------------