From 40c2f8acfa6d8b2568960d1b93d75b89b70b22c9 Mon Sep 17 00:00:00 2001 From: Mathieu B Date: Sat, 25 Mar 2023 15:52:22 +0100 Subject: [PATCH] auto create room, clear chat, chatgpt parsing --- jarvis/api.py | 34 ++++++++------- jarvis/start.py | 2 +- jarvis/utils/chat_utils.py | 6 +-- jarvis/utils/chatgpt_prompt_2_smaller.txt | 7 ++- jarvis/utils/chatgpt_utils.py | 52 ++++++++++++++++++----- 5 files changed, 67 insertions(+), 34 deletions(-) diff --git a/jarvis/api.py b/jarvis/api.py index ac93c94..a0b92d6 100644 --- a/jarvis/api.py +++ b/jarvis/api.py @@ -9,7 +9,7 @@ from flask import Flask, request from flask_socketio import SocketIO, emit, join_room, leave_room, \ rooms -from jarvis.utils import chat_utils, whisper_utils +from jarvis.utils import chat_utils, whisper_utils, chatgpt_utils # Set this variable to "threading", "eventlet" or "gevent" to test the # different async modes, or leave it set to None for the application to choose @@ -36,30 +36,25 @@ def process_message(message): logging.info("New PROCESS request from room " + message['uuid']) logging.info("Message : " + message['data']) + if message['uuid'] not in rooms(): + logging.warning("Room not found, creating it") + join_room(message['uuid']) + # TODO: maybe implement grammar check and correction ? # intent_manager.recognise(message['data'], message['uuid']) - if message['data'] != "": - # response = chatgpt_recognise(message['data']) - response = {'action': 'answer', - 'answer': "Hello! As an AI, I don't have emotions, but I'm always here to help you with your smart home needs. How can I assist you today?"} + # response = chatgpt_recognise(message['data'], message['uuid']) + # text_response = chatgpt_utils.get_answer_from_response(response) + text_response = "Tokens are expensive ya know?" - if response['action'] == 'clarify': - chat_utils.send_jarvis_message_to_room(response['question'], message['uuid']) - elif response['action'] == 'command': - chat_utils.send_jarvis_message_to_room(response['comment'], message['uuid']) - elif response['action'] == 'query': - chat_utils.send_jarvis_message_to_room(response['device_description'], message['uuid']) - elif response['action'] == 'answer': - chat_utils.send_jarvis_message_to_room(response['answer'], message['uuid']) - else: - chat_utils.send_jarvis_message_to_room("I don't know how to respond to that...", message['uuid']) + chat_utils.send_jarvis_message_to_room(text_response, message['uuid']) @socketio.event def join(message): message = json.loads(message) + logging.info("New client joined room " + message['uuid']) join_room(message['uuid']) @@ -67,7 +62,6 @@ def join(message): @socketio.event def leave(message): leave_room(message['uuid']) - emit('my_response', 'In rooms: ' + ', '.join(rooms())) @socketio.event @@ -76,6 +70,14 @@ def connect(): emit('my_response', {'data': 'Connected', 'count': 0}) +@socketio.event +def clear_chat(message): + message = json.loads(message) + + emit('clear_chat', {}, to=message['uuid']) + chatgpt_utils.clear_chat(message['uuid']) + + # .WAV (i.e.) FILE REQUEST @app.route("/get_text_from_audio", methods=['POST']) def get_text_from_audio(): diff --git a/jarvis/start.py b/jarvis/start.py index 7cc0a18..98f73c0 100644 --- a/jarvis/start.py +++ b/jarvis/start.py @@ -8,7 +8,7 @@ from jarvis.skills.intent_services import intent_manager from jarvis.utils import whisper_utils if __name__ == '__main__': - logging.getLogger().setLevel(logging.DEBUG) + logging.getLogger().setLevel(logging.INFO) # Load lingua franca in the memory lingua_franca.load_language(lang="fr") diff --git a/jarvis/utils/chat_utils.py b/jarvis/utils/chat_utils.py index c82524e..f96ea1f 100644 --- a/jarvis/utils/chat_utils.py +++ b/jarvis/utils/chat_utils.py @@ -1,13 +1,13 @@ import logging -from jarvis.api import socketio +from flask_socketio import emit def send_user_message_to_room(text, room_id): logging.debug("Sending message from user to room " + room_id + " : " + text) - socketio.emit('message_from_user', {'data': text, "uuid": room_id}, to=room_id) + emit('message_from_user', {'data': text, "uuid": room_id}, to=room_id) def send_jarvis_message_to_room(text, room_id): logging.debug("Sending message from jarvis to room " + room_id + " : " + text) - socketio.emit('message_from_jarvis', {'data': text, "uuid": room_id}, to=room_id) + emit('message_from_jarvis', {'data': text, "uuid": room_id}, to=room_id) diff --git a/jarvis/utils/chatgpt_prompt_2_smaller.txt b/jarvis/utils/chatgpt_prompt_2_smaller.txt index a99ffe5..da81241 100644 --- a/jarvis/utils/chatgpt_prompt_2_smaller.txt +++ b/jarvis/utils/chatgpt_prompt_2_smaller.txt @@ -3,8 +3,8 @@ Respond to smart home requests in JSON format with HomeAssistant API terminology Requests groups: - command: change the state of an accessory (properties : location, device_class, device_description, value, comment, scheduleTimeStamp) - query: only for retrieving a smart device state (properties : location, device_class, device_description, property) - - answer: for unrelated questions, short wikipedia answers (properties : answer) - - clarify: when not obvious, ask for details (properties : question) + - answer: for any questions (properties : answer) + - clarify: when you don't understand, ask for details (properties : question) NEVER add other properties Response: @@ -21,5 +21,4 @@ For commands property "scheduleTimeStamp" is for scheduling a command in the fut The house located at {{location}} and current time is {{timestamp}}. If questions about you, you are funny smart home AI like Jarvis from Iron Man, be nice and helpful with all topics. -Very important to only respond with only one valid JSON and encapsulate every JSON property with double quotes "". Don't add anything and never excuse yourself. Respond to only one request. - +Very important for you to only respond with a single valid JSON response and encapsulate every JSON property with double quotes "". Don't add anything and never excuse yourself. Respond to only one request at a time. \ No newline at end of file diff --git a/jarvis/utils/chatgpt_utils.py b/jarvis/utils/chatgpt_utils.py index e4c52c3..1a30ee7 100644 --- a/jarvis/utils/chatgpt_utils.py +++ b/jarvis/utils/chatgpt_utils.py @@ -1,36 +1,68 @@ import json +import logging import time import openai -chat_messages = [] +chat_messages = {} -def chatgpt_recognise(text): +def chatgpt_recognise(text, uuid): if len(chat_messages) == 0: - chatgpt_init() + chatgpt_init(uuid) print("START-TIME GPT: " + time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())) - chat_messages.append({"role": "user", "content": text}) + chat_messages[uuid].append({"role": "user", "content": text}) response = openai.ChatCompletion.create( model="gpt-3.5-turbo", - messages=chat_messages + messages=chat_messages[uuid], ) print("END-TIME GPT: " + time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())) - response = json.loads(str(response.choices[0].message.content)) - print(response) + # Check if the response is a "valid" JSON + try: + response = json.loads(str(response.choices[0].message.content)) + if 'action' in response: + chat_messages[uuid].append({"role": "assistant", "content": get_answer_from_response(response)}) + return response - return response + except Exception as e: + logging.error("Error while parsing GPT-3 response, probably not JSON: " + str(response.choices)) + logging.error(str(e)) + return {"action": "answer", "answer": get_answer_from_response(response)} -def chatgpt_init(): +def clear_chat(uuid): + logging.info("Cleared chat for uuid " + uuid) + chat_messages[uuid] = [] + + +def get_answer_from_response(response): + if 'action' not in response: + # Fix for when it responds in plaintext to follow-up questions + # In that case the response is an OpenAIObject not a JSON + return response.choices[0].message.content + else: + if response['action'] == 'clarify': + return response['question'] + elif response['action'] == 'command': + return response['comment'] + elif response['action'] == 'query': + return response['device_description'] + elif response['action'] == 'answer': + return response['answer'] + else: + return "I don't know how to respond to that..." + + +def chatgpt_init(uuid): prompt = open("utils/chatgpt_prompt_2_smaller.txt", "r").read() prompt.replace("{{timestamp}}", time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())) prompt.replace("{{location}}", "Lausanne in the canton Vaud of Switzerland") - chat_messages.append({"role": "system", "content": prompt}) + chat_messages[uuid] = [] + chat_messages[uuid].append({"role": "system", "content": prompt})