diff --git a/README.md b/README.md index caddf2d..fe01289 100644 --- a/README.md +++ b/README.md @@ -43,6 +43,7 @@ CHATBOT_LANGUAGES = { "en": "en-US", "de": "de-DE" } +CHATBOT_ASSISTANT_NAME = "Assistant" ``` In addition, the chatbot endpoint needs to be added to the `config/urls.py` @@ -263,4 +264,4 @@ Acknowledgement We would like to thank the Federal Government and the Heads of Government of the Länder, as well as the Joint Science Conference (GWK), for their funding and support within the framework of the NFDI4ING consortium. -Funded by the German Research Foundation (DFG) - project number 442146713." +Funded by the German Research Foundation (DFG) - project number 442146713. diff --git a/rdmo_chatbot/chatbot/adapter.py b/rdmo_chatbot/chatbot/adapter.py index 227106c..440392e 100644 --- a/rdmo_chatbot/chatbot/adapter.py +++ b/rdmo_chatbot/chatbot/adapter.py @@ -11,11 +11,13 @@ class BaseAdapter: - async def call_copilot(self, name, args={}, default=None): - return_value = default - if cl.context.session.client_type == "copilot": - return_value = await cl.CopilotFunction(name=name, args=args).acall() - return return_value + async def call_copilot(self, name: str, default=None, **kwargs): + if cl.context.session.client_type != "copilot": + return default + + result = await cl.CopilotFunction(name=name, args=kwargs).acall() + + return default if result is None else result async def on_chat_start(self): pass @@ -67,19 +69,11 @@ async def on_chat_start(self): # check if we have a history, yet if store.has_history(user.identifier, project_id): - content = getattr(config, f"CONTINUATION_{lang_code.upper()}", "") - await cl.Message(content=content).send() + await self.send_continuation(lang_code) + await self.send_history(user, project_id) else: # if the history is empty, display the confirmation message - content = getattr(config, f"CONFIRMATION_{lang_code.upper()}", "") - message = cl.AskActionMessage(content=content, actions=[ - cl.Action(name="confirmation", icon="check", label="", payload={"value": "confirmation"}), - cl.Action(name="leave", icon="x", label="", payload={"value": "leave"}), - ]) - response = await message.send() - await message.remove() - - if response and response.get("payload").get("value") == "confirmation": + if await self.send_confirmation(lang_code): content = getattr(config, f"START_{lang_code.upper()}", "").strip() store.set_history(user.identifier, project_id, [ AIMessage(content=content) @@ -93,7 +87,8 @@ async def on_user_message(self, message): user = cl.user_session.get("user") # get the full project from the copilot - project = await self.call_copilot("getProject", default={}) + project = await self.call_copilot("getProject") + project = project if isinstance(project, dict) else {} project_id = project.get("id") # get the history from the store @@ -153,7 +148,7 @@ async def on_system_message(self, message): store.reset_history(user.identifier, project_id) async def on_transfer(self, action): - await self.call_copilot("handleTransfer", args=action.payload) + await self.call_copilot("handleTransfer", **action.payload) async def on_contact(self, action): # get user and project_id from the session @@ -163,10 +158,37 @@ async def on_contact(self, action): # get the history from the store history = store.get_history(user.identifier, project_id) - await self.call_copilot("openContactModal", args={ - "history": messages_to_dicts(history) - }) + await self.call_copilot("openContactModal", history=messages_to_dicts(history)) + + async def send_continuation(self, lang_code): + content = getattr(config, f"CONTINUATION_{lang_code.upper()}", "") + await cl.Message(content=content).send() + + async def send_history(self, user, project_id): + history = store.get_history(user.identifier, project_id) + + for message in history: + if isinstance(message, HumanMessage): + message_author = user.display_name or "You" + message_type = "user_message" + elif isinstance(message, AIMessage): + message_author = config.ASSISTANT_NAME + message_type = "assistant_message" + else: + continue + + await cl.Message(content=message.content, author=message_author, type=message_type).send() + + async def send_confirmation(self, lang_code): + content = getattr(config, f"CONFIRMATION_{lang_code.upper()}", "") + message = cl.AskActionMessage(content=content, actions=[ + cl.Action(name="confirmation", icon="check", label="", payload={"value": "confirmation"}), + cl.Action(name="leave", icon="x", label="", payload={"value": "leave"}), + ]) + response = await message.send() + await message.remove() + return response and response.get("payload").get("value") == "confirmation" class OpenAILangChainAdapter(LangChainAdapter): diff --git a/rdmo_chatbot/plugin/utils.py b/rdmo_chatbot/plugin/utils.py index bbdeed3..26b46c2 100644 --- a/rdmo_chatbot/plugin/utils.py +++ b/rdmo_chatbot/plugin/utils.py @@ -1,4 +1,4 @@ -from datetime import UTC, datetime, timedelta +from datetime import datetime, timedelta, timezone from django import template from django.conf import settings @@ -15,7 +15,7 @@ def get_chatbot_token(user): "identifier": user.username, "display_name": get_full_name(user), "metadata": {}, - "exp": datetime.now(UTC) + timedelta(minutes=60 * 24), + "exp": datetime.now(timezone.utc) + timedelta(minutes=60 * 24), } return jwt.encode(token_data, settings.CHATBOT_AUTH_SECRET, algorithm="HS256")