fix async issues

This commit is contained in:
Cyberes 2023-04-19 17:01:07 -06:00
parent d68262bfee
commit c4ffd82698
4 changed files with 101 additions and 82 deletions

View File

@ -63,6 +63,8 @@ check_config_value_exists(config_data['openai'], 'api_key')
command_prefixes = {} command_prefixes = {}
for k, v in config_data['command'].items(): for k, v in config_data['command'].items():
check_config_value_exists(v, 'model')
check_config_value_exists(v, 'mode', default='default')
if 'allowed_to_chat' not in v.keys(): if 'allowed_to_chat' not in v.keys():
# Set default value # Set default value
v['allowed_to_chat'] = 'all' v['allowed_to_chat'] = 'all'

View File

@ -161,6 +161,7 @@ async def process_chat(
log_full_response: bool = False, log_full_response: bool = False,
injected_system_prompt: str = False injected_system_prompt: str = False
): ):
try:
if not store.check_seen_event(event.event_id): if not store.check_seen_event(event.event_id):
await client.room_typing(room.room_id, typing_state=True, timeout=90000) await client.room_typing(room.room_id, typing_state=True, timeout=90000)
# if self.reply_in_thread: # if self.reply_in_thread:
@ -191,10 +192,14 @@ async def process_chat(
# I don't think the OpenAI py api has a built-in timeout # I don't think the OpenAI py api has a built-in timeout
@stopit.threading_timeoutable(default=(None, None)) @stopit.threading_timeoutable(default=(None, None))
async def generate(): async def generate():
if openai_model in ['gpt-3', 'gpt-4']: if openai_model.startswith('gpt-3') or openai_model.startswith('gpt-4'):
return await loop.run_in_executor(None, functools.partial(openai_obj.ChatCompletion.create, model=openai_model, messages=messages, temperature=openai_temperature, timeout=20)) r = await loop.run_in_executor(None, functools.partial(openai_obj.ChatCompletion.create, model=openai_model, messages=messages, temperature=openai_temperature, timeout=20))
return r.choices[0].message.content
elif openai_model in ['text-davinci-003', 'davinci-instruct-beta', 'text-davinci-001', 'text-davinci-002', 'text-curie-001', 'text-babbage-001']: elif openai_model in ['text-davinci-003', 'davinci-instruct-beta', 'text-davinci-001', 'text-davinci-002', 'text-curie-001', 'text-babbage-001']:
return await loop.run_in_executor(None, functools.partial(openai_obj.Completion.create, model=openai_model, temperature=openai_temperature, timeout=20)) r = await loop.run_in_executor(None, functools.partial(openai_obj.Completion.create, model=openai_model, temperature=openai_temperature, timeout=20, max_tokens=4096))
return r.choices[0].text
else:
raise Exception(f'Model {openai_model} not found!')
response = None response = None
for i in range(openai_retries): for i in range(openai_retries):
@ -204,6 +209,9 @@ async def process_chat(
response = await task response = await task
if response is not None: if response is not None:
break break
else:
logger.warning(f'Response to event {event.event_id} was null, retrying.')
time.sleep(2)
except Exception as e: # (stopit.utils.TimeoutException, openai.error.APIConnectionError) except Exception as e: # (stopit.utils.TimeoutException, openai.error.APIConnectionError)
logger.warning(f'Got exception when generating response to event {event.event_id}, retrying: {e}') logger.warning(f'Got exception when generating response to event {event.event_id}, retrying: {e}')
await client.room_typing(room.room_id, typing_state=True, timeout=15000) await client.room_typing(room.room_id, typing_state=True, timeout=15000)
@ -211,14 +219,11 @@ async def process_chat(
continue continue
if response is None: if response is None:
logger.critical(f'Could not generate response to event {event.event_id} in room {room.room_id}.') logger.critical(f'Response to event {event.event_id} in room {room.room_id} was null.')
await client.room_typing(room.room_id, typing_state=False, timeout=15000) await client.room_typing(room.room_id, typing_state=False, timeout=15000)
await react_to_event(client, room.room_id, event.event_id, '') await react_to_event(client, room.room_id, event.event_id, '')
return return
if openai_model in ['gpt-3', 'gpt-4']: text_response = response.strip().strip('\n')
text_response = response["choices"][0]["message"]["content"].strip().strip('\n')
elif openai_model in ['text-davinci-003', 'davinci-instruct-beta', 'text-davinci-001', 'text-davinci-002', 'text-curie-001', 'text-babbage-001']:
text_response = response["choices"][0]["text"].strip().strip('\n')
# Logging stuff # Logging stuff
if log_full_response: if log_full_response:
@ -241,7 +246,9 @@ async def process_chat(
await react_to_event(client, room.room_id, event.event_id, '') await react_to_event(client, room.room_id, event.event_id, '')
else: else:
store.add_event_id(resp.event_id) store.add_event_id(resp.event_id)
except Exception:
await react_to_event(client, room.room_id, event.event_id, '')
raise
def check_authorized(string, to_check): def check_authorized(string, to_check):
def check_str(s, c): def check_str(s, c):

View File

@ -1,7 +1,10 @@
import sys import sys
def check_config_value_exists(config_part, key, check_type=None, allow_empty=False) -> bool: def check_config_value_exists(config_part, key, check_type=None, allow_empty=False, choices: list = None, default=None) -> bool:
if default and key not in config_part.keys():
return default
else:
if key not in config_part.keys(): if key not in config_part.keys():
print(f'Config key not found: "{key}"') print(f'Config key not found: "{key}"')
sys.exit(1) sys.exit(1)
@ -11,4 +14,7 @@ def check_config_value_exists(config_part, key, check_type=None, allow_empty=Fal
if check_type and not isinstance(config_part[key], check_type): if check_type and not isinstance(config_part[key], check_type):
print(f'Config key "{key}" must be type "{check_type}", not "{type(config_part[key])}".') print(f'Config key "{key}" must be type "{check_type}", not "{type(config_part[key])}".')
sys.exit(1) sys.exit(1)
if choices and config_part[key] not in choices:
print(f'Invalid choice for config key "{key}". Choices: {choices}')
sys.exit(1)
return True return True

View File

@ -1,4 +1,5 @@
import json import json
import logging
import os import os
from pathlib import Path from pathlib import Path
from typing import Union from typing import Union
@ -6,6 +7,7 @@ from typing import Union
from nio import AsyncClient, AsyncClientConfig, LoginError from nio import AsyncClient, AsyncClientConfig, LoginError
from nio import LoginResponse from nio import LoginResponse
logger = logging.getLogger('MatrixGPT')
class MatrixNioGPTHelper: class MatrixNioGPTHelper:
""" """
@ -34,6 +36,7 @@ class MatrixNioGPTHelper:
try: try:
# If there are no previously-saved credentials, we'll use the password # If there are no previously-saved credentials, we'll use the password
if not os.path.exists(self.auth_file): if not os.path.exists(self.auth_file):
logger.info('Using username/password.')
resp = await self.client.login(self.passwd, device_name=self.device_name) resp = await self.client.login(self.passwd, device_name=self.device_name)
# check that we logged in succesfully # check that we logged in succesfully
@ -44,6 +47,7 @@ class MatrixNioGPTHelper:
return False, resp return False, resp
else: else:
# Otherwise the config file exists, so we'll use the stored credentials # Otherwise the config file exists, so we'll use the stored credentials
logger.info('Using cached credentials.')
with open(self.auth_file, "r") as f: with open(self.auth_file, "r") as f:
config = json.load(f) config = json.load(f)
client = AsyncClient(config["homeserver"]) client = AsyncClient(config["homeserver"])