diff --git a/.chainlit/config.toml b/.chainlit/config.toml index bb57df8..be10a3b 100644 --- a/.chainlit/config.toml +++ b/.chainlit/config.toml @@ -74,7 +74,7 @@ github = "https://github.com/reactome/reactome_chatbot/issues" # Specify a Javascript file that can be used to customize the user interface. # The Javascript file can be served from the public directory. -# custom_js = "/public/test.js" +custom_js = "/public/custom.js" # Specify a custom meta image url. # custom_meta_image_url = "https://chainlit-cloud.s3.eu-west-3.amazonaws.com/logo/chainlit_banner.png" diff --git a/.dockerignore b/.dockerignore index 57688a2..5b3c643 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,3 +1,4 @@ +data/ embeddings/ embeddings_bak/ csv_files/ diff --git a/bin/chat-fastapi.py b/bin/chat-fastapi.py index 29a74e0..82dda31 100644 --- a/bin/chat-fastapi.py +++ b/bin/chat-fastapi.py @@ -288,7 +288,9 @@ async def landing_page():

Meet the React-to-Me AI Chatbot!

Your new guide to Reactome. Whether you're looking for specific genes and pathways or just browsing, our AI Chatbot is here to assist you!

@@ -296,7 +298,7 @@ async def landing_page():
Guest Access Log In - +

Choose Guest Access to try the chatbot out. Log In will give an increased query allowance and securely stores your chat history so you can save and continue conversations.

diff --git a/chainlit.md b/chainlit.md index 73653c6..908001a 100644 --- a/chainlit.md +++ b/chainlit.md @@ -35,3 +35,10 @@ Explore pathways such as: Happy exploring with React-to-me! +## _Disclaimer_ + +_This chatbot uses large language model (LLM) technology to assist with questions about the Reactome Knowledgebase. Responses are generated automatically and may contain inaccuracies, outdated information or speculative language._ + +_The information you provide may be retained in accordance with Reactome’s AI provider’s retention policy, which is located [here](https://openai.com/enterprise-privacy/). Do not share sensitive, personal or confidential information._ + +_The chatbot does not substitute for expert curation or peer-reviewed sources and is not a suitable resource for clinical decisions. Users are responsible for validating any output before using it for research, publication, or medical decisions. Any use of this chatbot is subject to Reactome’s [disclaimer](https://reactome.org/about/disclaimer)._ diff --git a/config_default.yml b/config_default.yml index 6831216..e53055a 100644 --- a/config_default.yml +++ b/config_default.yml @@ -18,17 +18,11 @@ messages: welcome: message: |- - Welcome to {chat_profile}, your interactive chatbot for exploring Reactome! + Welcome to {chat_profile}, your interactive chatbot for exploring **[Reactome](https://reactome.org/)**! Ask me about biological pathways and processes. trigger: event: on_chat_start - survey_message: - message: |- - We hope you're enjoying your experience with React-to-me! We'd love to hear your feedback to make it even better. Please take a few minutes to fill out our [survey](https://forms.gle/Rvzb8EA73yZs7wd38). - trigger: - after_messages: 3 - demo-message: message: |- Hello! diff --git a/public/custom.js b/public/custom.js new file mode 100644 index 0000000..67abcde --- /dev/null +++ b/public/custom.js @@ -0,0 +1,64 @@ +/* + * Replace the contents of the Chainlit watermark/footer + */ +(function () { + const CUSTOM_FOOTER_HTML = ` +
+ + + Disclaimer: + Our chatbot uses AI to assist you. + Responses are generated automatically and may not always be accurate. + Do not share sensitive, personal or confidential information. + For more information, please click on the “Readme” icon at the top-right of this window. + + +
+ `.trim(); + + const WATERMARK_SELECTOR = 'a.watermark'; + const APPLIED_ATTR = 'data-custom-watermark'; + + function replaceFooterContents(root = document) { + const nodes = root instanceof Element + ? root.querySelectorAll(WATERMARK_SELECTOR) + : document.querySelectorAll(WATERMARK_SELECTOR); + + nodes.forEach((el) => { + if (!(el instanceof HTMLElement)) return; + if (el.getAttribute(APPLIED_ATTR) === '1') return; + + el.innerHTML = CUSTOM_FOOTER_HTML; + + // disable the link behaviour + el.removeAttribute('href'); + el.removeAttribute('target'); + el.style.pointerEvents = 'none'; + + el.setAttribute(APPLIED_ATTR, '1'); + }); + } + + // Initial run (in case the element is already present). + if (document.readyState === 'loading') { + document.addEventListener('DOMContentLoaded', () => replaceFooterContents(document)); + } else { + replaceFooterContents(document); + } + + // Re-apply on future UI updates (SPA re-renders). + const mo = new MutationObserver((mutations) => { + for (const m of mutations) { + for (const node of m.addedNodes) { + if (node instanceof Element) { + // If the watermark itself is added or its parent subtree changes, update. + if (node.matches?.(WATERMARK_SELECTOR) || node.querySelector?.(WATERMARK_SELECTOR)) { + replaceFooterContents(node); + } + } + } + } + }); + + mo.observe(document.documentElement, { childList: true, subtree: true }); +})(); diff --git a/public/elements/SearchResults.jsx b/public/elements/SearchResults.jsx index 1106c59..13de9ab 100644 --- a/public/elements/SearchResults.jsx +++ b/public/elements/SearchResults.jsx @@ -16,6 +16,7 @@ const SearchResults = () => {
diff --git a/public/favicon.ico b/public/favicon.ico deleted file mode 100644 index ee97eb7..0000000 Binary files a/public/favicon.ico and /dev/null differ diff --git a/public/favicon.svg b/public/favicon.svg new file mode 100644 index 0000000..e126568 --- /dev/null +++ b/public/favicon.svg @@ -0,0 +1 @@ +Reactome_Isotype_Positive \ No newline at end of file diff --git a/src/util/embedding_environment.py b/src/util/embedding_environment.py index 7d34048..ab4a43f 100644 --- a/src/util/embedding_environment.py +++ b/src/util/embedding_environment.py @@ -27,8 +27,11 @@ def get_dict(cls) -> dict[str, Path]: return cls._get().embeddings @classmethod - def get_dir(cls, key: str) -> Path: - return EM_ARCHIVE / cls._get().embeddings[key] + def get_dir(cls, key: str) -> Path | None: + if key in cls._get().embeddings: + return EM_ARCHIVE / cls._get().embeddings[key] + else: + return None @classmethod def get_model(cls, key: str) -> str: