simplify copilot response, adjust error responses, other minor changes
This commit is contained in:
parent
72640ae35f
commit
0d52be41db
|
@ -35,7 +35,7 @@ I included a sample Systemd service (`matrixgpt.service`).
|
|||
## Use
|
||||
|
||||
First, invite your bot to a room. Then you can start a chat by prefixing your message with your trigger (for
|
||||
example, `!c hello!`). The bot will create a thread when it replies. You don't need to use the trigger in the thread.
|
||||
example, `!c hello`). The bot will create a thread when it replies. You don't need to use the trigger in the thread.
|
||||
|
||||
Use `!matrixgpt` to view the bot's help. The bot also responds to `!bots`.
|
||||
|
||||
|
|
|
@ -50,7 +50,7 @@ async def generate_ai_response(
|
|||
context = [{'role': api_client.HUMAN_NAME, 'content': context}]
|
||||
|
||||
# Build the context and do the things that need to be done for our specific API type.
|
||||
api_client.assemble_context(context, system_prompt=command_info.system_prompt, injected_system_prompt=command_info.injected_system_prompt)
|
||||
api_client.prepare_context(context, system_prompt=command_info.system_prompt, injected_system_prompt=command_info.injected_system_prompt)
|
||||
|
||||
if api_client.check_ignore_request():
|
||||
logger.debug(f'Reply to {event.event_id} was ignored by the model "{command_info.model}".')
|
||||
|
@ -82,7 +82,7 @@ async def generate_ai_response(
|
|||
room.room_id,
|
||||
event.event_id,
|
||||
'❌',
|
||||
extra_error='Exception' if global_config['send_extra_messages'] else None
|
||||
extra_error='Exception while generating AI response' if global_config['send_extra_messages'] else None
|
||||
)
|
||||
await client.room_typing(room.room_id, typing_state=False, timeout=1000)
|
||||
return
|
||||
|
@ -93,7 +93,7 @@ async def generate_ai_response(
|
|||
room.room_id,
|
||||
event.event_id,
|
||||
'❌',
|
||||
extra_error='Response was null.' if global_config['send_extra_messages'] else None
|
||||
extra_error='AI response was empty' if global_config['send_extra_messages'] else None
|
||||
)
|
||||
await client.room_typing(room.room_id, typing_state=False, timeout=1000)
|
||||
return
|
||||
|
@ -135,7 +135,7 @@ async def generate_ai_response(
|
|||
await client.room_typing(room.room_id, typing_state=False, timeout=1000)
|
||||
if not isinstance(resp, RoomSendResponse):
|
||||
logger.critical(f'Failed to respond to event {event.event_id} in room {room.room_id}:\n{vars(resp)}')
|
||||
await client_helper.react_to_event(room.room_id, event.event_id, '❌', extra_error='Exception' if global_config['send_extra_messages'] else None)
|
||||
except Exception:
|
||||
await client_helper.react_to_event(room.room_id, event.event_id, '❌', extra_error='Exception' if global_config['send_extra_messages'] else None)
|
||||
await client_helper.react_to_event(room.room_id, event.event_id, '❌', extra_error='Exception while responding to event' if global_config['send_extra_messages'] else None)
|
||||
except Exception as e:
|
||||
await client_helper.react_to_event(room.room_id, event.event_id, '❌', extra_error=f'Exception during response process: {e}' if global_config['send_extra_messages'] else None)
|
||||
raise
|
||||
|
|
|
@ -16,7 +16,7 @@ class AnthropicApiClient(ApiClient):
|
|||
api_key=self._api_key
|
||||
)
|
||||
|
||||
def assemble_context(self, context: list, system_prompt: str = None, injected_system_prompt: str = None):
|
||||
def prepare_context(self, context: list, system_prompt: str = None, injected_system_prompt: str = None):
|
||||
assert not len(self._context)
|
||||
self._context = context
|
||||
self.verify_context()
|
||||
|
@ -28,19 +28,19 @@ class AnthropicApiClient(ApiClient):
|
|||
i = 0
|
||||
while i < len(self._context) - 1:
|
||||
if self._context[i]['role'] == self._context[i + 1]['role']:
|
||||
dummy = self.generate_text_msg(f'<{self._BOT_NAME} did not respond>', self._BOT_NAME) if self._context[i]['role'] == self._HUMAN_NAME else self.generate_text_msg(f'<{self._HUMAN_NAME} did not respond>', self._HUMAN_NAME)
|
||||
dummy = self.text_msg(f'<{self._BOT_NAME} did not respond>', self._BOT_NAME) if self._context[i]['role'] == self._HUMAN_NAME else self.text_msg(f'<{self._HUMAN_NAME} did not respond>', self._HUMAN_NAME)
|
||||
self._context.insert(i + 1, dummy)
|
||||
i += 1
|
||||
# if self._context[-1]['role'] == self._HUMAN_NAME:
|
||||
# self._context.append(self.generate_text_msg(f'<{self._BOT_NAME} did not respond>', self._BOT_NAME))
|
||||
|
||||
def generate_text_msg(self, content: str, role: str):
|
||||
def text_msg(self, content: str, role: str):
|
||||
assert role in [self._HUMAN_NAME, self._BOT_NAME]
|
||||
return {"role": role, "content": [{"type": "text", "text": str(content)}]}
|
||||
|
||||
def append_msg(self, content: str, role: str):
|
||||
assert role in [self._HUMAN_NAME, self._BOT_NAME]
|
||||
self._context.append(self.generate_text_msg(content, role))
|
||||
self._context.append(self.text_msg(content, role))
|
||||
|
||||
async def append_img(self, img_event: RoomMessageImage, role: str):
|
||||
assert role in [self._HUMAN_NAME, self._BOT_NAME]
|
||||
|
|
|
@ -20,33 +20,51 @@ class ApiClient:
|
|||
def _create_client(self, base_url: str = None):
|
||||
raise NotImplementedError
|
||||
|
||||
def check_ignore_request(self):
|
||||
def check_ignore_request(self) -> bool:
|
||||
"""
|
||||
If the bot wants to ignore and not respond to a request.
|
||||
"""
|
||||
return False
|
||||
|
||||
def assemble_context(self, context: list, system_prompt: str = None, injected_system_prompt: str = None):
|
||||
def prepare_context(self, context: list, system_prompt: str = None, injected_system_prompt: str = None) -> None:
|
||||
"""
|
||||
Prepare and process the context that has already been loaded.
|
||||
"""
|
||||
assert not len(self._context)
|
||||
raise NotImplementedError
|
||||
|
||||
def generate_text_msg(self, content: str, role: str):
|
||||
def text_msg(self, content: str, role: str) -> None:
|
||||
"""
|
||||
Create a message of the type text with the given content and role.
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def append_msg(self, content: str, role: str):
|
||||
def append_msg(self, content: str, role: str) -> None:
|
||||
"""
|
||||
Add a message of the type text to the context.
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
async def append_img(self, img_event: RoomMessageImage, role: str):
|
||||
async def append_img(self, img_event: RoomMessageImage, role: str) -> None:
|
||||
"""
|
||||
Add a message of the type image to the context.
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
async def generate(self, command_info: CommandInfo, matrix_gpt_data: str = None) -> Tuple[str, dict | None]:
|
||||
"""
|
||||
Generate a response.
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
@property
|
||||
def context(self):
|
||||
def context(self) -> list:
|
||||
return self._context.copy()
|
||||
|
||||
@property
|
||||
def HUMAN_NAME(self):
|
||||
def HUMAN_NAME(self) -> str:
|
||||
return self._HUMAN_NAME
|
||||
|
||||
@property
|
||||
def BOT_NAME(self):
|
||||
def BOT_NAME(self) -> str:
|
||||
return self._BOT_NAME
|
||||
|
|
|
@ -1,12 +1,10 @@
|
|||
import json
|
||||
import re
|
||||
import time
|
||||
from urllib.parse import urlparse
|
||||
|
||||
from cryptography.fernet import Fernet
|
||||
from nio import RoomMessageImage
|
||||
from sydney import SydneyClient
|
||||
from sydney.exceptions import ThrottledRequestException
|
||||
|
||||
from matrix_gpt.config import global_config
|
||||
from matrix_gpt.generate_clients.api_client import ApiClient
|
||||
|
@ -45,12 +43,7 @@ class CopilotClient(ApiClient):
|
|||
async def append_img(self, img_event: RoomMessageImage, role: str):
|
||||
raise NotImplementedError
|
||||
|
||||
# def check_ignore_request(self):
|
||||
# if len(self._context) > 1:
|
||||
# return True
|
||||
# return False
|
||||
|
||||
def assemble_context(self, context: list, system_prompt: str = None, injected_system_prompt: str = None):
|
||||
def prepare_context(self, context: list, system_prompt: str = None, injected_system_prompt: str = None):
|
||||
assert not len(self._context)
|
||||
self._context = context
|
||||
for i in range(len(self._context)):
|
||||
|
@ -60,8 +53,8 @@ class CopilotClient(ApiClient):
|
|||
async def generate(self, command_info: CommandInfo, matrix_gpt_data: str = None):
|
||||
# TODO: config option for style
|
||||
async with SydneyClient(bing_cookies=self._api_key, style='precise') as sydney:
|
||||
# Ignore any exceptions doing this since they will be caught by the caller.
|
||||
if matrix_gpt_data:
|
||||
# Ignore any exceptions doing this since they will be caught by the caller.
|
||||
decrypted_metadata = decrypt_string(matrix_gpt_data)
|
||||
conversation_metadata = json.loads(decrypted_metadata)
|
||||
sydney.conversation_signature = conversation_metadata["conversation_signature"]
|
||||
|
@ -70,26 +63,9 @@ class CopilotClient(ApiClient):
|
|||
sydney.client_id = conversation_metadata["client_id"]
|
||||
sydney.invocation_id = conversation_metadata["invocation_id"]
|
||||
|
||||
response = None
|
||||
for i in range(3):
|
||||
try:
|
||||
response = dict(await sydney.ask(self._context[-1]['content'], citations=True, raw=True))
|
||||
break
|
||||
except ThrottledRequestException:
|
||||
time.sleep(10)
|
||||
if not response:
|
||||
# If this happens you should first try to change your cookies.
|
||||
# Otherwise, you've used all your credits for today.
|
||||
raise ThrottledRequestException
|
||||
|
||||
bot_response = response['item']['messages'][-1]
|
||||
|
||||
text_card = {}
|
||||
for msg in bot_response['adaptiveCards'][0]['body']:
|
||||
if msg.get('type') == 'TextBlock':
|
||||
text_card = msg
|
||||
break
|
||||
response_text = text_card.get('text', '')
|
||||
response_text = await sydney.ask(self._context[-1]['content'], citations=True)
|
||||
if not len(response_text):
|
||||
raise Exception('Copilot response was empty')
|
||||
|
||||
# Parse the attribution links.
|
||||
attributions_strs = []
|
||||
|
@ -135,9 +111,11 @@ class CopilotClient(ApiClient):
|
|||
)
|
||||
|
||||
if len(self._context) == 1:
|
||||
# Add this disclaimer because the owner of the Microsoft account that the bot uses can go and view
|
||||
# his conversation history and view everything the bot has done.
|
||||
response_text += _COPILOT_WARNING_STR
|
||||
|
||||
# Store the conversation metadata in the response. It's encrypted for privacy purposes.
|
||||
# Store the conversation metadata in the response Matrix event. It's encrypted for privacy purposes.
|
||||
custom_data = {
|
||||
'thread_root_event': self._event.event_id,
|
||||
'data': encrypt_string(event_data)
|
||||
|
|
|
@ -41,7 +41,7 @@ class OpenAIClient(ApiClient):
|
|||
}]
|
||||
})
|
||||
|
||||
def assemble_context(self, context: list, system_prompt: str = None, injected_system_prompt: str = None):
|
||||
def prepare_context(self, context: list, system_prompt: str = None, injected_system_prompt: str = None):
|
||||
assert not len(self._context)
|
||||
self._context = context
|
||||
if isinstance(system_prompt, str) and len(system_prompt):
|
||||
|
|
|
@ -25,9 +25,9 @@ async def do_reply_msg(client_helper: MatrixClientHelper, room: MatrixRoom, requ
|
|||
context=msg,
|
||||
command_info=command_info,
|
||||
)
|
||||
except Exception:
|
||||
except Exception as e:
|
||||
logger.critical(traceback.format_exc())
|
||||
await client_helper.react_to_event(room.room_id, requestor_event.event_id, '❌')
|
||||
await client_helper.react_to_event(room.room_id, requestor_event.event_id, '❌', extra_error=f'Exception during response process: {e}' if global_config['send_extra_messages'] else None)
|
||||
raise
|
||||
|
||||
|
||||
|
@ -86,9 +86,9 @@ async def do_reply_threaded_msg(client_helper: MatrixClientHelper, room: MatrixR
|
|||
thread_root_id=thread_content[0].event_id,
|
||||
matrix_gpt_data=matrix_gpt_data
|
||||
)
|
||||
except:
|
||||
except Exception as e:
|
||||
logger.error(traceback.format_exc())
|
||||
await client_helper.react_to_event(room.room_id, event.event_id, '❌')
|
||||
await client_helper.react_to_event(room.room_id, requestor_event.event_id, '❌', extra_error=f'Exception during response process: {e}' if global_config['send_extra_messages'] else None)
|
||||
raise
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue