Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Misc bug fixes #83

Merged
merged 4 commits into from
Oct 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions AudioTranscriber.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ def transcribe_audio_queue(self, audio_queue: queue.Queue):
root_logger.info(AudioTranscriber.transcribe_audio_queue)
while True:
who_spoke, data, time_spoken = audio_queue.get()
root_logger.info(f'Current time: {datetime.datetime.utcnow()} - Time Spoken: '
root_logger.info(f'Transcribe Audio Queue. Current time: {datetime.datetime.utcnow()} - Time Spoken: '
f'{time_spoken} by : {who_spoke}, queue_backlog - '
f'{audio_queue.qsize()}')
self.update_last_sample_and_phrase_status(who_spoke, data, time_spoken)
Expand All @@ -116,8 +116,8 @@ def transcribe_audio_queue(self, audio_queue: queue.Queue):
time_spoken=time_spoken,
file_path=path)

root_logger.info(f'{datetime.datetime.now()} = Transcription text: {text}')
root_logger.info(f'{datetime.datetime.now()} - End transcription')
root_logger.info(f'{datetime.datetime.utcnow()} = Transcription text: {text}')
root_logger.info(f'{datetime.datetime.utcnow()} - End transcription')

except Exception as exception:
print(exception)
Expand Down Expand Up @@ -352,7 +352,7 @@ def get_transcript(self, length: int = 0):
constants.PERSONA_YOU,
constants.PERSONA_SPEAKER
]
convo_object_return_value = self.conversation.get_conversation(sources=sources)
convo_object_return_value = self.conversation.get_conversation(sources=sources, length=length)
return convo_object_return_value

def clear_transcript_data_loop(self, audio_queue: queue.Queue):
Expand Down
53 changes: 31 additions & 22 deletions GPTResponder.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import constants
import configuration
import app_logging as al
import duration


root_logger = al.get_logger()
Expand Down Expand Up @@ -38,26 +39,24 @@ def generate_response_from_transcript_no_check(self) -> str:
try:
root_logger.info(GPTResponder.generate_response_from_transcript_no_check.__name__)
# print(f'{datetime.datetime.now()} - {GPTResponder.generate_response_from_transcript_no_check.__name__}')
multiturn_prompt_content = self.conversation.get_merged_conversation(
length=constants.MAX_TRANSCRIPTION_PHRASES_FOR_LLM)
multiturn_prompt_api_message = prompts.create_multiturn_prompt(multiturn_prompt_content)
# print(f'Multiturn prompt for ChatGPT: {multiturn_prompt_api_message}')
# Multi turn response is only effective when continuous mode is off.
# In continuous mode, there are far too many responses from LLM,
# they confuse the LLM if that many responses are replayed back to LLM.
# print(f'{datetime.datetime.now()} - Request response')
multi_turn_response = openai.ChatCompletion.create(
model=self.model,
messages=multiturn_prompt_api_message,
temperature=0.0
)
# pprint.pprint(multi_turn_response)
# print(f'{datetime.datetime.now()} - Got response')

# print('-------- Multi Turn --------')
# pprint.pprint(f'message={multiturn_prompt_api_message}', width=120)
# pprint.pprint(f'response={multi_turn_response}', width=120)
# print('-------- -------- -------- -------- -------- --------')
with duration.Duration(name='OpenAI Chat Completion', screen=False):
multiturn_prompt_content = self.conversation.get_merged_conversation(
length=constants.MAX_TRANSCRIPTION_PHRASES_FOR_LLM)
multiturn_prompt_api_message = prompts.create_multiturn_prompt(multiturn_prompt_content)
# print(f'Multiturn prompt for ChatGPT: {multiturn_prompt_api_message}')
# Multi turn response is only effective when continuous mode is off.
# In continuous mode, there are far too many responses from LLM,
# they confuse the LLM if that many responses are replayed back to LLM.
# print(f'{datetime.datetime.now()} - Request response')
# self._pretty_print_openai_request(multiturn_prompt_api_message)
multi_turn_response = openai.ChatCompletion.create(
model=self.model,
messages=multiturn_prompt_api_message,
temperature=0.0,
request_timeout=10
)
# pprint.pprint(f'openai response: {multi_turn_response}', width=120)
# print(f'{datetime.datetime.now()} - Got response')

except Exception as exception:
print(exception)
Expand Down Expand Up @@ -112,7 +111,7 @@ def update_conversation(self, response, persona):
self.response = response
self.conversation.update_conversation(persona=persona,
text=response,
time_spoken=datetime.datetime.now())
time_spoken=datetime.datetime.utcnow())

def respond_to_transcriber(self, transcriber):
"""Thread method to continously update the transcript
Expand All @@ -123,7 +122,6 @@ def respond_to_transcriber(self, transcriber):
start_time = time.time()

transcriber.transcript_changed_event.clear()
response = ''

# Do processing only if LLM transcription is enabled
if not self.gl_vars.freeze_state[0]:
Expand All @@ -146,6 +144,17 @@ def update_response_interval(self, interval):
root_logger.info(GPTResponder.update_response_interval.__name__)
self.response_interval = interval

def _pretty_print_openai_request(self, message: str):
"""Format the openAI request in a nice print format"""
print('[')
for item in message:
print(' {')
print(f' Role: {item["role"]}')
print(f' Content: {item["content"]}')
print(' }')

print(']')


if __name__ == "__main__":
print('GPTResponder')
59 changes: 36 additions & 23 deletions conversation.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
from heapq import merge
import datetime
# import pprint
import constants
import configuration

Expand All @@ -15,21 +14,22 @@ def __init__(self):
constants.PERSONA_YOU: [],
constants.PERSONA_SPEAKER: [],
constants.PERSONA_ASSISTANT: []}
self.last_update: datetime.datetime = None
self.initialize_conversation()

def initialize_conversation(self):
config = configuration.Config().data
prompt = config["OpenAI"]["system_prompt"]
self.update_conversation(persona=constants.PERSONA_SYSTEM, text=prompt,
time_spoken=datetime.datetime.now())
time_spoken=datetime.datetime.utcnow())
initial_convo: dict = config["OpenAI"]["initial_convo"]
# Read the initial conversation from parameters.yaml file and add to the convo
for _, value in initial_convo.items():
role = value['role']
content = value['content']
self.update_conversation(persona=role, text=content,
time_spoken=datetime.datetime.now())
self.last_update: datetime.datetime = datetime.datetime.now()
time_spoken=datetime.datetime.utcnow())
self.last_update: datetime.datetime = datetime.datetime.utcnow()

def clear_conversation_data(self):
"""Clear all conversation data
Expand All @@ -48,15 +48,23 @@ def update_conversation(self, persona: str, text: str, time_spoken, pop: bool =
time_spoken: Time at which conversation happened, this is typically reported in local time
"""
transcript = self.transcript_data[persona]
if pop and len(transcript) > 0:

# For persona you, we populate one item from parameters.yaml.
# Hence do not delete the first item for persona == You
if (pop
and (
(persona.lower() == 'you' and len(transcript) > 1)
or (persona.lower() != 'you' and len(transcript) > 0)
)
):
transcript.pop()

transcript.append((f"{persona}: [{text}]\n\n", time_spoken))
self.last_update = datetime.datetime.now()
self.last_update = datetime.datetime.utcnow()

def get_conversation(self,
sources: list = None,
length: int = 0,
reverse: bool = False) -> list:
length: int = 0) -> list:
"""Get the transcript based on specified sources
Args:
sources: Get data from which sources (You, Speaker, Assistant, System)
Expand All @@ -75,28 +83,33 @@ def get_conversation(self,
self.transcript_data[constants.PERSONA_SPEAKER][-length:] if constants.PERSONA_SPEAKER in sources else [],
self.transcript_data[constants.PERSONA_ASSISTANT][-length:] if constants.PERSONA_ASSISTANT in sources else [],
self.transcript_data[constants.PERSONA_SYSTEM][-length:] if constants.PERSONA_SYSTEM in sources else [],
key=lambda x: x[1], reverse=reverse))
key=lambda x: x[1]))
combined_transcript = combined_transcript[-length:]
return "".join([t[0] for t in combined_transcript])

def get_merged_conversation(self, length: int = 0, reverse: bool = False) -> list:
def get_merged_conversation(self, length: int = 0) -> list:
"""Creates a prompt to be sent to LLM (OpenAI by default)
length: Get the last length elements from the audio transcript.
Initial system prompt is always part of the return value
Default value = 0, gives the complete transcript
"""
# print(f'You: Length: {len(self.transcript_data[constants.PERSONA_YOU])}')
# print(f'Speaker: Length: {len(self.transcript_data[constants.PERSONA_SPEAKER])}')
# print(f'Assistant: Length: {len(self.transcript_data[constants.PERSONA_ASSISTANT])}')
# print(f'System: Length: {len(self.transcript_data[constants.PERSONA_SYSTEM])}')

combined_transcript = self.transcript_data[constants.PERSONA_SYSTEM]
combined_transcript = list(merge(
combined_transcript,
self.transcript_data[constants.PERSONA_YOU][-length:],
self.transcript_data[constants.PERSONA_SPEAKER][-length:],
self.transcript_data[constants.PERSONA_ASSISTANT][-length:],
key=lambda x: x[1], reverse=reverse))
combined_transcript = combined_transcript[-length:]
combined_transcript = self.transcript_data[constants.PERSONA_YOU][-length:] + self.transcript_data[constants.PERSONA_SPEAKER][-length:] + self.transcript_data[constants.PERSONA_ASSISTANT][-length:]
sorted_transcript = sorted(combined_transcript, key=lambda x: x[1])
sorted_transcript = sorted_transcript[-length:]
sorted_transcript.insert(0, self.transcript_data[constants.PERSONA_YOU][0])
sorted_transcript.insert(0, self.transcript_data[constants.PERSONA_SYSTEM][0])
# self._pretty_print_transcript(sorted_transcript)

return sorted_transcript

def _pretty_print_transcript(self, message: list):
"""Format the openAI request in a nice print format"""
print('[')
for item in message:
print(' {')
print(f' {item[0].strip()}')
print(f' {item[1]}')
print(' }')

return combined_transcript
print(']')
16 changes: 14 additions & 2 deletions interactions.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import os
import platform
import argparse
import pprint
import subprocess
Expand All @@ -12,6 +14,7 @@


def create_params(args: argparse.Namespace) -> dict:
"""Create Ping Parameters"""
try:
root_logger.info(create_params.__name__)
git_version = subprocess.check_output(
Expand All @@ -28,21 +31,30 @@ def create_params(args: argparse.Namespace) -> dict:

hostname = socket.gethostname()
host_ip = socket.gethostbyname(hostname)
user = os.getlogin()
cwd = os.getcwd()
os_name = f'{os.name} {platform.system()} {platform.release()}'

arg_dict = {
'version': git_version,
'hostname': hostname,
'ip': host_ip,
'user': user,
'dir': cwd,
'os': os_name,
'args': args
}
return arg_dict


def params(args: argparse.Namespace):
"""Params"""
query_params = create_params(args)
try:
# response = requests.get("http://127.0.0.1:5000/ping", params=query_params, timeout=10)
response = requests.get("http://34.74.220.77:5000/ping", params=query_params, timeout=10)
if response.status_code != 200:
root_logger.info(f'Error received: {response}')
except ConnectionError as ce:
pprint.pprint(ce)
except ConnectionError:
# pprint.pprint(ce)
print('[INFO] Operating in Desktop mode')
6 changes: 5 additions & 1 deletion parameters.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,10 @@ OpenAI:
system_prompt: "You are a casual pal, genuinely interested in the conversation at hand. Please respond, in detail, to the conversation. Confidently give a straightforward response to the speaker, even if you don't understand them. Give your response in square brackets. DO NOT ask to repeat, and DO NOT ask for clarification. Just answer the speaker directly."
# system_prompt: "You are an expert at Basketball and helping others learn about basketball. Please respond, in detail, to the conversation. Confidently give a straightforward response to the speaker, even if you don't understand them. Give your response in square brackets. DO NOT ask to repeat, and DO NOT ask for clarification. Just answer the speaker directly."
# system_prompt: "You are an expert at Fantasy Football and helping others learn about Fantasy football. Please respond, in detail, to the conversation. Confidently give a straightforward response to the speaker, even if you don't understand them. Give your response in square brackets. DO NOT ask to repeat, and DO NOT ask for clarification. Just answer the speaker directly."
# system_prompt: “You are an expert Agile Coach and are interviewing for a position. Respond in detail to the conversation. Confidently give a straightforward response to the speaker, even if you don't understand them. Give your response in square brackets. DO NOT ask to repeat, and DO NOT ask for clarification. Just answer the speaker directly."

# When we anticipate to talk about a specific topic, seed the content with some conversation
# Application expects role "You" to have 1 entry
# If the conversation is generic, replace this text with something like this.
# role: You
# content: I am V, I want to have a casual friendly conversation
Expand All @@ -36,11 +38,13 @@ OpenAI:
role: "You"
# content: "I am V, I want to learn about Fantasy Football"
# content: "I am V, I want to learn about Basketball"
# content: "Hey assistant, how are you doing today, I want to talk about Agile coaching today."
content: Hey assistant, how are you doing today, I am in mood of a casual conversation.
second:
role: "assistant"
# content: "Hello, V. That's awesome! What do you want to know about basketball"
# content: "Hello, V. That's awesome! What do you want to know about Fantasy Football"
# content: "Hello, V. You are awesome. I am doing very well and looking forward to discussion about Agile coaching."
content: Hello, V. You are awesome. I am doing very well and looking forward to some light hearted banter with you.

General:
Expand All @@ -55,4 +59,4 @@ General:
# Setting clear_transcript_periodically: yes will clear transcript data at a regular interval
# clear_transcript_interval_seconds is applicable when clear_transcript_periodically is set to Yes
clear_transcript_periodically: No # Possible values are Yes, No
clear_transcript_interval_seconds: 30
clear_transcript_interval_seconds: 60
5 changes: 3 additions & 2 deletions prompts.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ def create_single_turn_prompt_message(transcript: str) -> list:
return prompt_api_message


def create_multiturn_prompt(convo: list) -> list:
def create_multiturn_prompt(convo: list[tuple]) -> list[dict[str, str]]:
"""Create message list to be sent to LLM.
Creates multiple items in the list in the format
[
Expand All @@ -57,8 +57,9 @@ def create_multiturn_prompt(convo: list) -> list:
The single message contains everything including system prompt and user input
"""
ret_value = []

# Each convo item is a tuple
for convo_item in convo:
# print(convo_item)
# Get Persona, text
convo_persona = convo_item[0][0:convo_item[0].find(':')]
# print(convo_persona)
Expand Down
4 changes: 2 additions & 2 deletions ui.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

root_logger = al.get_logger()
UI_FONT_SIZE = 20
last_transcript_ui_update_time: datetime.datetime = datetime.datetime.now()
last_transcript_ui_update_time: datetime.datetime = datetime.datetime.utcnow()
global_vars_module: GlobalVars.TranscriptionGlobals = None


Expand Down Expand Up @@ -120,7 +120,7 @@ def update_transcript_ui(transcriber: AudioTranscriber, textbox: ctk.CTkTextbox)
transcript_string = transcriber.get_transcript()
write_in_textbox(textbox, transcript_string)
textbox.see("end")
last_transcript_ui_update_time = datetime.datetime.now()
last_transcript_ui_update_time = datetime.datetime.utcnow()

textbox.after(constants.TRANSCRIPT_UI_UPDATE_DELAY_DURATION_MS,
update_transcript_ui, transcriber, textbox)
Expand Down
Loading