From d179879731796d4071bcaa93ee1dee2c496bb181 Mon Sep 17 00:00:00 2001 From: Jingcheng Yang Date: Fri, 22 Mar 2024 23:58:03 -0400 Subject: [PATCH] Improve the performance. --- docs/publications.md | 19 +++ src/api/req.rs | 6 +- src/model/llm.rs | 8 +- studio/config/config.embed.ts | 8 +- studio/config/config.ts | 13 +- studio/config/routes.ts | 1 + studio/package.json | 3 + studio/src/app.tsx | 26 +++- studio/src/components/ChatBox/index.tsx | 4 +- studio/src/components/ErrorBoundary/index.tsx | 27 ++++ studio/src/components/util.ts | 65 --------- studio/src/components/webllm.ts | 85 ++++++++++++ studio/src/global.tsx | 1 + studio/src/pages/404.tsx | 4 +- studio/src/pages/KnowledgeGraph/index.tsx | 13 +- studio/yarn.lock | 125 +++++++++++++++++- 16 files changed, 322 insertions(+), 86 deletions(-) create mode 100644 docs/publications.md create mode 100644 studio/src/components/ErrorBoundary/index.tsx create mode 100644 studio/src/components/webllm.ts diff --git a/docs/publications.md b/docs/publications.md new file mode 100644 index 0000000..6faf23f --- /dev/null +++ b/docs/publications.md @@ -0,0 +1,19 @@ +### Entity Extraction + +- [Ollama](https://ollama.com/): Get up and running with large language models, locally. +- [Vicuna](https://vicuna.lmsys.org/): An Open-Source Chatbot Impressing GPT-4 with 90%* ChatGPT Quality. +- [Phind-codellama](https://ollama.com/library/phind-codellama): Code generation model based on Code Llama. +- [allenai/OLMo](https://github.com/allenai/OLMo): Modeling, training, eval, and inference code for OLMo. + +### Semantic Search and Reranking + +- [ParadeDB](https://www.paradedb.com/): ParadeDB is a modern Elasticsearch alternative built on Postgres. + +### Similar Projects + +- [Consensus](https://consensus.app/search/): Ask a question, get conclusions from research papers. + +### PDF Parsing + +- [Grobid](https://grobid.readthedocs.io/en/latest/Grobid-service/) +- [pdffigures2](https://github.com/allenai/pdffigures2) \ No newline at end of file diff --git a/src/api/req.rs b/src/api/req.rs index ac3a72d..017e189 100644 --- a/src/api/req.rs +++ b/src/api/req.rs @@ -1,5 +1,5 @@ use anyhow; -use poem_openapi::{types::ToJSON, Object}; +use poem_openapi::Object; use reqwest; use serde::{Deserialize, Serialize}; @@ -37,9 +37,7 @@ pub struct PublicationDetail { } impl Publication { - pub async fn fetch_publication( - id: &str, - ) -> Result { + pub async fn fetch_publication(id: &str) -> Result { let api_token = match std::env::var("GUIDESCOPER_API_TOKEN") { Ok(token) => token, Err(_) => { diff --git a/src/model/llm.rs b/src/model/llm.rs index 7d243e5..9f5e089 100644 --- a/src/model/llm.rs +++ b/src/model/llm.rs @@ -272,7 +272,7 @@ impl LlmContext for SubgraphWithCtx { }; // You need to prepare two fields: 1) subgraph: a json string; 2) context_str: a string, it need to be a disease name, such as "ME/CFS". - prompt_templates.insert("explain_subgraph_mechanism_with_disease_ctx", "Knowledge Subgraph: {{subgraph}}\n\nKnowledge Subgraph Analysis Request:\nI have a set of Subgraph data that includes a collection of genes/proteins and their connections to a specific disease, {{ context_str }}. This Subgraph consists of nodes (representing genes/proteins) and edges (representing interactions or relationships between the genes/proteins). Each node has associated attributes, such as name, description, or known disease associations. Edges may also have attributes, like the type or strength of interaction. My goal is to identify key nodes and paths within this Subgraph that are most relevant to {{ context_str }}. To achieve this, I need your assistance to: 1. Identify and explain the key nodes that are most relevant to {{ context_str }}. Please base your explanation on the nodes and their attributes and their known roles in the disease, explaining which nodes are critical and why these nodes are critical. 2. Determine and describe the main paths connecting these key nodes. Please discuss how these paths might be involved in the onset, progression, or treatment of the disease, considering the type and strength of interactions between nodes. 3. Provide a report summarizing your findings and understanding, including a list of key nodes and paths, along with a rationale for how they are related to {{ context_str }}. Note that, given the complexity and multifactorial nature of diseases, explanations may need to integrate multiple attributes of nodes and their interactions. \n\nGuidance for Response:\n\nPlease address the aforementioned inquiries based on the Knowledge Subgraph and your expertise. For each of the questions related to the Knowledge Subgraph and its implications for {{context_str}}, it is imperative that you provide supporting literature. This literature must exclusively come from PubMed, which is a critical repository for reliable medical research findings. Your responses should not only incorporate insights derived from these studies but also include citations formatted according to standard academic practices. Specifically, citations should detail the authors, title, journal name, year of publication, and the PubMed ID (PMID) to facilitate easy verification and further reading.\n\nFor example, a proper citation format would be: Doe J, Smith A, Jones B. Title of the Article. Journal Name. Year;Volume(Issue):Page numbers. PMID: XXXXXXX."); + prompt_templates.insert("explain_subgraph_mechanism_with_disease_ctx", "Knowledge Subgraph: {{subgraph}}\n\nKnowledge Subgraph Analysis Request:\nI have a set of Subgraph data that includes a collection of genes/proteins and their connections to a specific disease, {{context_str}}. This Subgraph consists of nodes (representing genes/proteins) and edges (representing interactions or relationships between the genes/proteins). Each node has associated attributes, such as name, description, or known disease associations. Edges may also have attributes, like the type or strength of interaction. My goal is to identify key nodes and paths within this Subgraph that are most relevant to {{context_str}}. To achieve this, I need your assistance to: 1. Identify and explain the key nodes that are most relevant to {{context_str}}. Please base your explanation on the nodes and their attributes and their known roles in the disease, explaining which nodes are critical and why these nodes are critical. 2. Determine and describe the main paths connecting these key nodes. Please discuss how these paths might be involved in the onset, progression, or treatment of the disease, considering the type and strength of interactions between nodes. 3. Provide a report summarizing your findings and understanding, including a list of key nodes and paths, along with a rationale for how they are related to {{context_str}}. Note that, given the complexity and multifactorial nature of diseases, explanations may need to integrate multiple attributes of nodes and their interactions. \n\nGuidance for Response:\n\nPlease address the aforementioned inquiries based on the Knowledge Subgraph and your expertise. For each of the questions related to the Knowledge Subgraph and its implications for {{context_str}}, it is imperative that you provide supporting literature. This literature must exclusively come from PubMed, which is a critical repository for reliable medical research findings. Your responses should not only incorporate insights derived from these studies but also include citations formatted according to standard academic practices. Specifically, citations should detail the authors, title, journal name, year of publication, and the PubMed ID (PMID) to facilitate easy verification and further reading.\n\nFor example, a proper citation format would be: Doe J, Smith A, Jones B. Title of the Article. Journal Name. Year;Volume(Issue):Page numbers. PMID: XXXXXXX."); let mut m3 = HashMap::new(); m3.insert("key", "explain_subgraph_importance_with_disease_ctx"); @@ -287,10 +287,10 @@ impl LlmContext for SubgraphWithCtx { }; // JSON version // You need to prepare two fields: 1) subgraph: a json string; 2) context_str: a string, it need to be a disease name, such as "ME/CFS". - // m.insert("explain_subgraph_importance_with_disease_ctx", "Knowledge Subgraph: {{subgraph}}\n\nKnowledge Subgraph Analysis Request:\nI have a set of Subgraph data that includes a collection of genes/proteins and their connections to a specific disease, {{ context_str }}. This Subgraph consists of nodes (representing genes/proteins) and edges (representing interactions or relationships between the genes/proteins). Each node has associated attributes, such as name, description, or known disease associations. Edges may also have attributes, like the type or strength of interaction. My goal is to identify key nodes and paths within this Subgraph that are most relevant to {{ context_str }}. To achieve this, please label these nodes and paths as critical, important, moderate, or less important based on your knowledges and the subgraph, and provide a rationale for your assessment. After labeling the nodes and paths, please output your findings as an array, the format is like```{your_output}```. The array contains a set of objects, each object have as least three columns: id (node or edge), importance, reason."); + // m.insert("explain_subgraph_importance_with_disease_ctx", "Knowledge Subgraph: {{subgraph}}\n\nKnowledge Subgraph Analysis Request:\nI have a set of Subgraph data that includes a collection of genes/proteins and their connections to a specific disease, {{context_str}}. This Subgraph consists of nodes (representing genes/proteins) and edges (representing interactions or relationships between the genes/proteins). Each node has associated attributes, such as name, description, or known disease associations. Edges may also have attributes, like the type or strength of interaction. My goal is to identify key nodes and paths within this Subgraph that are most relevant to {{context_str}}. To achieve this, please label these nodes and paths as critical, important, moderate, or less important based on your knowledges and the subgraph, and provide a rationale for your assessment. After labeling the nodes and paths, please output your findings as an array, the format is like```{your_output}```. The array contains a set of objects, each object have as least three columns: id (node or edge), importance, reason."); // Table version - prompt_templates.insert("explain_subgraph_importance_with_disease_ctx", "Knowledge Subgraph: {{subgraph}}\n\nKnowledge Subgraph Analysis Request:\nI have a set of Subgraph data that includes a collection of genes/proteins and their connections to a specific disease, {{ context_str }}. This Subgraph consists of nodes (representing genes/proteins) and edges (representing interactions or relationships between the genes/proteins). Each node has associated attributes, such as name, description, or known disease associations. Edges may also have attributes, like the type or strength of interaction. My goal is to identify key nodes and edges within this Subgraph that are most relevant to {{ context_str }}. To achieve this, please label these nodes listed in the subgraph as Critical, Important, Moderate, or Less Important based on your knowledges on {{ context_str }} and the subgraph, and provide a rationale for your assessment. After labeling the nodes, please output your results as a table (not a file). The table contains a set of rows, each row have as least six columns: #, ID (node id), Name (node name), Importance, Reliability, Reason. Please note: 1. the subgraph might be incomplete, so you need to use your knowledges to think these nodes step by step, and then assess the importance of the nodes; 2. you need to consider the importance of the node types for specific diseases, for example, symptom might be important for a symptom-defined disease, but it might be less important for a genetic disease; 3. you need to consider the reliability of the relation, for example, if the relation is mentioned more frequent in your knowledgebase, then we can treat it more reliable; 4. the final table you output should ordered by importance and reliability, and the importance should be ordered by Critical, Important, Moderate, and Less Important; 5. you need to tell me why you think the node is important / less important, reliable / less reliable, and the reason should be based on the subgraph and your knowledges (recommendation)."); + prompt_templates.insert("explain_subgraph_importance_with_disease_ctx", "Knowledge Subgraph: {{subgraph}}\n\nKnowledge Subgraph Analysis Request:\nI have a set of Subgraph data that includes a collection of genes/proteins and their connections to a specific disease, {{context_str}}. This Subgraph consists of nodes (representing genes/proteins) and edges (representing interactions or relationships between the genes/proteins). Each node has associated attributes, such as name, description, or known disease associations. Edges may also have attributes, like the type or strength of interaction. My goal is to identify key nodes and edges within this Subgraph that are most relevant to {{context_str}}. To achieve this, please label these nodes listed in the subgraph as Critical, Important, Moderate, or Less Important based on your knowledges on {{context_str}} and the subgraph, and provide a rationale for your assessment. After labeling the nodes, please output your results as a table (not a file). The table contains a set of rows, each row have as least six columns: #, ID (node id), Name (node name), Importance, Reliability, Reason. Please note: 1. the subgraph might be incomplete, so you need to use your knowledges to think these nodes step by step, and then assess the importance of the nodes; 2. you need to consider the importance of the node types for specific diseases, for example, symptom might be important for a symptom-defined disease, but it might be less important for a genetic disease; 3. you need to consider the reliability of the relation, for example, if the relation is mentioned more frequent in your knowledgebase, then we can treat it more reliable; 4. the final table you output should ordered by importance and reliability, and the importance should be ordered by Critical, Important, Moderate, and Less Important; 5. you need to tell me why you think the node is important / less important, reliable / less reliable, and the reason should be based on the subgraph and your knowledges (recommendation)."); let mut m4 = HashMap::new(); m4.insert("key", "explain_path_within_subgraph"); @@ -304,7 +304,7 @@ impl LlmContext for SubgraphWithCtx { prompts.push(m4); }; // Actually, in this case, the context_str is a path name, such as "ME/CFS-[treated_by]->Ibuprofen-[treats]->Headache". - prompt_templates.insert("explain_path_within_subgraph", "Knowledge Subgraph: {{subgraph}}\n\nMy goal is to explain the path {{ context_str }} within the subgraph. Please provide a detailed explanation of the path."); + prompt_templates.insert("explain_path_within_subgraph", "Knowledge Subgraph: {{subgraph}}\n\nMy goal is to explain the path {{context_str}} within the subgraph. Please provide a detailed explanation of the path."); let mut m5 = HashMap::new(); m5.insert("key", "explain_path_with_attention_subgraph"); diff --git a/studio/config/config.embed.ts b/studio/config/config.embed.ts index 6624fc1..4a19614 100644 --- a/studio/config/config.embed.ts +++ b/studio/config/config.embed.ts @@ -1,17 +1,23 @@ // https://umijs.org/config/ import { defineConfig } from 'umi'; +// How to improve the loading performance: https://juejin.cn/post/7207743145998811173 export default defineConfig({ outputPath: '../assets', publicPath: '/assets/', history: { type: 'hash', }, + // https://umijs.org/blog/code-splitting#%E4%BB%A3%E7%A0%81%E6%8B%86%E5%88%86%E6%8C%87%E5%8D%97 (It's similar with dynamicImport in umi 3.x) codeSplitting: { - jsStrategy: 'granularChunks' + jsStrategy: 'depPerChunk' }, esbuildMinifyIIFE: true, favicons: ['/assets/gene.png'], + jsMinifier: 'terser', + jsMinifierOptions: { + + }, proxy: undefined, locale: { default: 'en-US', diff --git a/studio/config/config.ts b/studio/config/config.ts index 5ee1cc1..f09a47a 100644 --- a/studio/config/config.ts +++ b/studio/config/config.ts @@ -2,6 +2,7 @@ import { defineConfig } from 'umi'; import path from 'path'; import proxy from './proxy'; +import CompressionPlugin from 'compression-webpack-plugin'; import { routes as defaultRoutes } from './routes'; // const isDev = process.env.NODE_ENV === 'development'; @@ -24,7 +25,7 @@ export default defineConfig({ request: {}, npmClient: 'yarn', dva: {}, - chainWebpack: (config: any) => { + chainWebpack: (config: any, { env }) => { config.merge({ resolve: { fallback: { @@ -36,6 +37,16 @@ export default defineConfig({ // https://github.com/webpack/webpack/discussions/13585 config.resolve.alias.set('perf_hooks', path.resolve(__dirname, 'perf_hooks.ts')); // console.log("config.resolve.alias", config.resolve.alias); + + if (env === 'production') { + config.plugin('compression-webpack-plugin').use( + new CompressionPlugin({ + test: /.js$|.html$|.css$/, + threshold: 10240, + deleteOriginalAssets: false, + }), + ); + } }, layout: { // https://umijs.org/docs/max/layout-menu diff --git a/studio/config/routes.ts b/studio/config/routes.ts index b80b219..9e93d4e 100644 --- a/studio/config/routes.ts +++ b/studio/config/routes.ts @@ -72,6 +72,7 @@ export const routes = [ redirect: '/knowledge-table', }, { + path: '/*', component: './404', }, ]; diff --git a/studio/package.json b/studio/package.json index 6ab36d9..cf6de4d 100644 --- a/studio/package.json +++ b/studio/package.json @@ -8,6 +8,7 @@ "dev": "max dev", "build": "max build", "build:embed": "cross-env UMI_APP_IS_STATIC=true UMI_ENV=embed UMI_APP_AUTH0_CLIENT_ID=Y08FauV1dAEiocNIZt5LiOifzNgXr6Uo UMI_APP_AUTH0_DOMAIN=biomedgps.jp.auth0.com max build", + "build:analyze": "cross-env ANALYZE=true max build", "format": "prettier --cache --write .", "postinstall": "max setup", "setup": "max setup", @@ -27,6 +28,7 @@ "@fingerprintjs/fingerprintjs": "^3.3.6", "@handsontable/react": "^12.1.3", "@mlc-ai/web-llm": "0.2.15", + "@sentry/react": "^7.108.0", "@textea/json-viewer": "^2.9.0", "@umijs/max": "^4.1.2", "@umijs/route-utils": "^2.0.0", @@ -83,6 +85,7 @@ "@types/react": "^18.0.0", "@types/react-dom": "^18.0.0", "@umijs/plugins": "^4.1.2", + "compression-webpack-plugin": "^11.1.0", "cross-env": "^7.0.3", "husky": "^8.0.3", "lint-staged": "^13.2.0", diff --git a/studio/src/app.tsx b/studio/src/app.tsx index 5e5d5af..b2ca497 100644 --- a/studio/src/app.tsx +++ b/studio/src/app.tsx @@ -1,10 +1,31 @@ import Footer from '@/components/Footer'; import Header from '@/components/Header'; +import ErrorBoundary from '@/components/ErrorBoundary'; import { RequestConfig, history, RuntimeConfig } from 'umi'; import { PageLoading, SettingDrawer } from '@ant-design/pro-components'; import { Auth0Provider } from '@auth0/auth0-react'; import { CustomSettings, AppVersion } from '../config/defaultSettings'; import { getJwtAccessToken } from '@/components/util'; +import * as Sentry from "@sentry/react"; + +// Configure Sentry for error tracking +Sentry.init({ + dsn: "https://6b871a833586050acae9100637b200c6@o143851.ingest.us.sentry.io/4506958288846848", + integrations: [ + Sentry.browserTracingIntegration(), + Sentry.replayIntegration({ + maskAllText: false, + blockAllMedia: false, + }), + ], + // Performance Monitoring + tracesSampleRate: 1.0, // Capture 100% of the transactions + // Set 'tracePropagationTargets' to control for which URLs distributed tracing should be enabled + tracePropagationTargets: ["localhost", /^https:\/\/drugs.3steps\.cn\/api/], + // Session Replay + replaysSessionSampleRate: 0.1, // This sets the sample rate at 10%. You may want to change it to 100% while in development and then sample at a lower rate in production. + replaysOnErrorSampleRate: 1.0, // If you're not already sampling the entire session, change the sample rate to 100% when sampling sessions where errors occur. +}); // 运行时配置 // @ts-ignore @@ -48,6 +69,7 @@ export const request: RequestConfig = { baseURL: apiPrefix, errorConfig: { errorHandler: (resData) => { + console.log("errorHandler: ", resData); return { ...resData, success: false, @@ -189,7 +211,9 @@ export const layout: RuntimeConfig = (initialState: any) => { } else { return ( <> - {children} + + {children} + ); } diff --git a/studio/src/components/ChatBox/index.tsx b/studio/src/components/ChatBox/index.tsx index 31fddad..441ac98 100644 --- a/studio/src/components/ChatBox/index.tsx +++ b/studio/src/components/ChatBox/index.tsx @@ -1,7 +1,7 @@ import { ReactChatPlugin } from 'biominer-components'; import { filter, set } from 'lodash'; import * as webllm from "@mlc-ai/web-llm"; -import { initChat } from '@/components/util'; +import { initChat } from '@/components/webllm'; import { useEffect, useState } from 'react'; import { message as AntdMessage } from 'antd'; import rehypeRaw from 'rehype-raw'; @@ -51,7 +51,9 @@ const ChatBoxWrapper: React.FC = (props) => { useEffect(() => { const initChatBox = async () => { + // @ts-ignore if (window.chat) { + // @ts-ignore setChat(window.chat); } else { const chat = await initChat(); diff --git a/studio/src/components/ErrorBoundary/index.tsx b/studio/src/components/ErrorBoundary/index.tsx new file mode 100644 index 0000000..6205176 --- /dev/null +++ b/studio/src/components/ErrorBoundary/index.tsx @@ -0,0 +1,27 @@ +import React from 'react'; +import { history } from 'umi'; + +class ErrorBoundary extends React.Component { + state = { hasError: false }; + + static getDerivedStateFromError(error: any) { + // Update state so the next render will show the fallback UI. + return { hasError: true }; + } + + componentDidCatch(error: any, errorInfo: any) { + // You can log the error to an error reporting service + console.log(error, errorInfo); + } + + render() { + if (this.state.hasError) { + history.push('/404'); + } + + // @ts-ignore + return this.props.children; + } +}; + +export default ErrorBoundary; \ No newline at end of file diff --git a/studio/src/components/util.ts b/studio/src/components/util.ts index 8146e2a..e0c0acb 100644 --- a/studio/src/components/util.ts +++ b/studio/src/components/util.ts @@ -1,6 +1,3 @@ -import * as webllm from "@mlc-ai/web-llm"; -import { message } from "antd"; - export const getJwtAccessToken = (): string | null => { let jwtToken = null; // Check if the cookie exists @@ -21,65 +18,3 @@ export const getJwtAccessToken = (): string | null => { return null; } } - -export const initChat = async () => { - // const chat = new webllm.ChatWorkerClient(new Worker( - // new URL('./assets/web-llm.worker.js', import.meta.url), - // { type: 'module' } - // )); - const chat = new webllm.ChatModule(); - - const remoteUrl = "https://huggingface.co"; - const genConfig = (url: string) => { - let model_lib_baseurl = "https://raw.githubusercontent.com"; - if (url === window.location.origin) { - model_lib_baseurl = url - } - - const myAppConfig = { - model_list: [ - { - "model_url": `${url}/mlc-ai/Mistral-7B-Instruct-v0.2-q4f16_1-MLC/resolve/main/`, - "local_id": "Mistral-7B-Instruct-v0.2-q4f16_1", - "model_lib_url": `${model_lib_baseurl}/mlc-ai/binary-mlc-llm-libs/main/Mistral-7B-Instruct-v0.2/Mistral-7B-Instruct-v0.2-q4f16_1-sw4k_cs1k-webgpu.wasm`, - "required_features": ["shader-f16"], - }, - ] - } - - return myAppConfig; - } - - message.open({ - key: "loading", - type: 'loading', - content: 'Chat AI is loading...', - }); - - chat.setInitProgressCallback((report: webllm.InitProgressReport) => { - if (report.progress === 1) { - message.open({ - key: "loading", - type: 'success', - content: "Chat AI is loaded.", - duration: 2, - }); - } else { - message.open({ - key: "loading", - type: 'loading', - content: `Chat AI is loading... ${(report.progress * 100).toFixed(2)}%`, - }) - } - }); - - let appConfig = genConfig(remoteUrl); - console.log("Chat AI is loading with remote config:", appConfig); - await chat.reload("Mistral-7B-Instruct-v0.2-q4f16_1", undefined, appConfig); - console.log("Chat AI is loaded."); - - // @ts-ignore - window.chat = chat; - - return chat; -}; diff --git a/studio/src/components/webllm.ts b/studio/src/components/webllm.ts new file mode 100644 index 0000000..1eb684f --- /dev/null +++ b/studio/src/components/webllm.ts @@ -0,0 +1,85 @@ +import { ChatModule, InitProgressReport } from "@mlc-ai/web-llm"; +import { message } from "antd"; + +export const getJwtAccessToken = (): string | null => { + let jwtToken = null; + // Check if the cookie exists + if (document.cookie && document.cookie.includes("jwt_access_token=")) { + // Retrieve the cookie value + // @ts-ignore + jwtToken = document.cookie + .split("; ") + .find((row) => row.startsWith("jwt_access_token=")) + .split("=")[1]; + } + + if (jwtToken) { + console.log("JWT access token found in the cookie."); + return jwtToken; + } else { + console.log("JWT access token not found in the cookie."); + return null; + } +} + +export const initChat = async () => { + // const chat = new webllm.ChatWorkerClient(new Worker( + // new URL('./assets/web-llm.worker.js', import.meta.url), + // { type: 'module' } + // )); + const chat = new ChatModule(); + + const remoteUrl = "https://huggingface.co"; + const genConfig = (url: string) => { + let model_lib_baseurl = "https://raw.githubusercontent.com"; + if (url === window.location.origin) { + model_lib_baseurl = url + } + + const myAppConfig = { + model_list: [ + { + "model_url": `${url}/mlc-ai/Mistral-7B-Instruct-v0.2-q4f16_1-MLC/resolve/main/`, + "local_id": "Mistral-7B-Instruct-v0.2-q4f16_1", + "model_lib_url": `${model_lib_baseurl}/mlc-ai/binary-mlc-llm-libs/main/Mistral-7B-Instruct-v0.2/Mistral-7B-Instruct-v0.2-q4f16_1-sw4k_cs1k-webgpu.wasm`, + "required_features": ["shader-f16"], + }, + ] + } + + return myAppConfig; + } + + message.open({ + key: "loading", + type: 'loading', + content: 'Chat AI is loading...', + }); + + chat.setInitProgressCallback((report: InitProgressReport) => { + if (report.progress === 1) { + message.open({ + key: "loading", + type: 'success', + content: "Chat AI is loaded.", + duration: 2, + }); + } else { + message.open({ + key: "loading", + type: 'loading', + content: `Chat AI is loading... ${(report.progress * 100).toFixed(2)}%`, + }) + } + }); + + let appConfig = genConfig(remoteUrl); + console.log("Chat AI is loading with remote config:", appConfig); + await chat.reload("Mistral-7B-Instruct-v0.2-q4f16_1", undefined, appConfig); + console.log("Chat AI is loaded."); + + // @ts-ignore + window.chat = chat; + + return chat; +}; diff --git a/studio/src/global.tsx b/studio/src/global.tsx index 6b9c1d7..29c3461 100644 --- a/studio/src/global.tsx +++ b/studio/src/global.tsx @@ -1,4 +1,5 @@ import FingerprintJS from '@fingerprintjs/fingerprintjs'; +import { message as AndMessage } from 'antd'; const getIdentity = async () => { let visitorId = localStorage.getItem('rapex-visitor-id') diff --git a/studio/src/pages/404.tsx b/studio/src/pages/404.tsx index 301e173..fac10ad 100644 --- a/studio/src/pages/404.tsx +++ b/studio/src/pages/404.tsx @@ -5,8 +5,8 @@ import { history } from 'umi'; const NoFoundPage: React.FC = () => ( history.push('/')}> Back Home diff --git a/studio/src/pages/KnowledgeGraph/index.tsx b/studio/src/pages/KnowledgeGraph/index.tsx index c78e6fe..b2bcfa2 100644 --- a/studio/src/pages/KnowledgeGraph/index.tsx +++ b/studio/src/pages/KnowledgeGraph/index.tsx @@ -1,10 +1,8 @@ -import ChatBox from '@/components/ChatBox'; import { history } from 'umi'; -import { Row, Col, Button, message as AntMessage } from 'antd'; +import { Row, Col, Button, message as AntMessage, Empty } from 'antd'; import { KnowledgeGraph } from 'biominer-components'; -import React, { useEffect, useState, memo } from 'react'; +import React, { useEffect, useState, memo, Suspense } from 'react'; import { useAuth0 } from "@auth0/auth0-react"; -import { initChat } from '@/components/util'; // TODO: KeepAlive will cause some bugs, so we disable it for now. // import { KeepAlive } from 'umi'; import { MessageFilled, MessageOutlined } from '@ant-design/icons'; @@ -25,6 +23,7 @@ const KnowledgeGraphWithChatBot: React.FC = () => { const [message, setMessage] = useState('') const [chatBoxVisible, setChatBoxVisible] = useState(false) const [span, setSpan] = useState(kgFullSpan) + const ChatBox = React.lazy(() => import('@/components/ChatBox')); useEffect(() => { if (!isAuthenticated) { @@ -48,7 +47,11 @@ const KnowledgeGraphWithChatBot: React.FC = () => { { chatBoxVisible ? ( - + + }> + + ) : null } diff --git a/studio/yarn.lock b/studio/yarn.lock index 337b921..d0ac171 100644 --- a/studio/yarn.lock +++ b/studio/yarn.lock @@ -3086,6 +3086,88 @@ dependencies: "@daybrush/utils" "^1.4.0" +"@sentry-internal/feedback@7.108.0": + version "7.108.0" + resolved "https://registry.yarnpkg.com/@sentry-internal/feedback/-/feedback-7.108.0.tgz#7033352abd304f1383ec47640e056a0dfd5132b7" + integrity sha512-8JcgZEnk1uWrXJhsd3iRvFtEiVeaWOEhN0NZwhwQXHfvODqep6JtrkY1yCIyxbpA37aZmrPc2JhyotRERGfUjg== + dependencies: + "@sentry/core" "7.108.0" + "@sentry/types" "7.108.0" + "@sentry/utils" "7.108.0" + +"@sentry-internal/replay-canvas@7.108.0": + version "7.108.0" + resolved "https://registry.yarnpkg.com/@sentry-internal/replay-canvas/-/replay-canvas-7.108.0.tgz#641133c19c0e1c423617b8d791f53d6cd0b0a862" + integrity sha512-R5tvjGqWUV5vSk0N1eBgVW7wIADinrkfDEBZ9FyKP2mXHBobsyNGt30heJDEqYmVqluRqjU2NuIRapsnnrpGnA== + dependencies: + "@sentry/core" "7.108.0" + "@sentry/replay" "7.108.0" + "@sentry/types" "7.108.0" + "@sentry/utils" "7.108.0" + +"@sentry-internal/tracing@7.108.0": + version "7.108.0" + resolved "https://registry.yarnpkg.com/@sentry-internal/tracing/-/tracing-7.108.0.tgz#d1e660701fb860cfae72b6ebfa8fb267533421fa" + integrity sha512-zuK5XsTsb+U+hgn3SPetYDAogrXsM16U/LLoMW7+TlC6UjlHGYQvmX3o+M2vntejoU1QZS8m1bCAZSMWEypAEw== + dependencies: + "@sentry/core" "7.108.0" + "@sentry/types" "7.108.0" + "@sentry/utils" "7.108.0" + +"@sentry/browser@7.108.0": + version "7.108.0" + resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-7.108.0.tgz#b95810bb6572b63781f253615896f5afb1a3a5c0" + integrity sha512-FNpzsdTvGvdHJMUelqEouUXMZU7jC+dpN7CdT6IoHVVFEkoAgrjMVUhXZoQ/dmCkdKWHmFSQhJ8Fm6V+e9Aq0A== + dependencies: + "@sentry-internal/feedback" "7.108.0" + "@sentry-internal/replay-canvas" "7.108.0" + "@sentry-internal/tracing" "7.108.0" + "@sentry/core" "7.108.0" + "@sentry/replay" "7.108.0" + "@sentry/types" "7.108.0" + "@sentry/utils" "7.108.0" + +"@sentry/core@7.108.0": + version "7.108.0" + resolved "https://registry.yarnpkg.com/@sentry/core/-/core-7.108.0.tgz#a27e8d6f85f59c5730ce86071474f15ac899fde0" + integrity sha512-I/VNZCFgLASxHZaD0EtxZRM34WG9w2gozqgrKGNMzAymwmQ3K9g/1qmBy4e6iS3YRptb7J5UhQkZQHrcwBbjWQ== + dependencies: + "@sentry/types" "7.108.0" + "@sentry/utils" "7.108.0" + +"@sentry/react@^7.108.0": + version "7.108.0" + resolved "https://registry.yarnpkg.com/@sentry/react/-/react-7.108.0.tgz#26a50324f6d7a9576f3753c099e7bcd8def94f3c" + integrity sha512-C60arh5/gtO42eMU9l34aWlKDLZUO+1j1goaEf/XRSwUcyJS9tbJrs+mT4nbKxUsEG714It2gRbfSEvh1eXmCg== + dependencies: + "@sentry/browser" "7.108.0" + "@sentry/core" "7.108.0" + "@sentry/types" "7.108.0" + "@sentry/utils" "7.108.0" + hoist-non-react-statics "^3.3.2" + +"@sentry/replay@7.108.0": + version "7.108.0" + resolved "https://registry.yarnpkg.com/@sentry/replay/-/replay-7.108.0.tgz#baa679bd19b4e3729e607d3f84cff5048aeb3415" + integrity sha512-jo8fDOzcZJclP1+4n9jUtVxTlBFT9hXwxhAMrhrt70FV/nfmCtYQMD3bzIj79nwbhUtFP6pN39JH1o7Xqt1hxQ== + dependencies: + "@sentry-internal/tracing" "7.108.0" + "@sentry/core" "7.108.0" + "@sentry/types" "7.108.0" + "@sentry/utils" "7.108.0" + +"@sentry/types@7.108.0": + version "7.108.0" + resolved "https://registry.yarnpkg.com/@sentry/types/-/types-7.108.0.tgz#5ceb959c4dabe511fc441fec8c2465f2d624900f" + integrity sha512-bKtHITmBN3kqtqE5eVvL8mY8znM05vEodENwRpcm6TSrrBjC2RnwNWVwGstYDdHpNfFuKwC8mLY9bgMJcENo8g== + +"@sentry/utils@7.108.0": + version "7.108.0" + resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-7.108.0.tgz#0231042956aed2ef35809891592238530349dfd9" + integrity sha512-a45yEFD5qtgZaIFRAcFkG8C8lnDzn6t4LfLXuV4OafGAy/3ZAN3XN8wDnrruHkiUezSSANGsLg3bXaLW/JLvJw== + dependencies: + "@sentry/types" "7.108.0" + "@sinclair/typebox@^0.27.8": version "0.27.8" resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.27.8.tgz#6667fac16c436b5434a387a34dedb013198f6e6e" @@ -4539,11 +4621,25 @@ ahooks@^3.0.8: screenfull "^5.0.0" tslib "^2.4.1" +ajv-formats@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ajv-formats/-/ajv-formats-2.1.1.tgz#6e669400659eb74973bbf2e33327180a0996b520" + integrity sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA== + dependencies: + ajv "^8.0.0" + ajv-keywords@^3.4.1, ajv-keywords@^3.5.2: version "3.5.2" resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz#31f29da5ab6e00d1c2d329acf7b5929614d5014d" integrity sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ== +ajv-keywords@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-5.1.0.tgz#69d4d385a4733cdbeab44964a1170a88f87f0e16" + integrity sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw== + dependencies: + fast-deep-equal "^3.1.3" + ajv@^6.10.0, ajv@^6.12.2, ajv@^6.12.3, ajv@^6.12.4, ajv@^6.12.5: version "6.12.6" resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" @@ -4554,7 +4650,7 @@ ajv@^6.10.0, ajv@^6.12.2, ajv@^6.12.3, ajv@^6.12.4, ajv@^6.12.5: json-schema-traverse "^0.4.1" uri-js "^4.2.2" -ajv@^8.0.1: +ajv@^8.0.0, ajv@^8.0.1, ajv@^8.9.0: version "8.12.0" resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.12.0.tgz#d1a0527323e22f53562c567c00991577dfbe19d1" integrity sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA== @@ -6235,6 +6331,14 @@ compressible@~2.0.16: dependencies: mime-db ">= 1.43.0 < 2" +compression-webpack-plugin@^11.1.0: + version "11.1.0" + resolved "https://registry.yarnpkg.com/compression-webpack-plugin/-/compression-webpack-plugin-11.1.0.tgz#ee340d2029cf99ccecdea9ad1410b377d15b48b3" + integrity sha512-zDOQYp10+upzLxW+VRSjEpRRwBXJdsb5lBMlRxx1g8hckIFBpe3DTI0en2w7h+beuq89576RVzfiXrkdPGrHhA== + dependencies: + schema-utils "^4.2.0" + serialize-javascript "^6.0.2" + compression@^1.7.4: version "1.7.4" resolved "https://registry.yarnpkg.com/compression/-/compression-1.7.4.tgz#95523eff170ca57c29a0ca41e6fe131f41e5bb8f" @@ -14815,7 +14919,7 @@ raf@3.4.1, raf@^3.1.0, raf@^3.3.2, raf@^3.4.0, raf@^3.4.1: dependencies: performance-now "^2.1.0" -randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5: +randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5, randombytes@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== @@ -17295,6 +17399,16 @@ schema-utils@^3.0.0, schema-utils@^3.1.1: ajv "^6.12.5" ajv-keywords "^3.5.2" +schema-utils@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-4.2.0.tgz#70d7c93e153a273a805801882ebd3bff20d89c8b" + integrity sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw== + dependencies: + "@types/json-schema" "^7.0.9" + ajv "^8.9.0" + ajv-formats "^2.1.1" + ajv-keywords "^5.1.0" + screenfull@^5.0.0: version "5.2.0" resolved "https://registry.yarnpkg.com/screenfull/-/screenfull-5.2.0.tgz#6533d524d30621fc1283b9692146f3f13a93d1ba" @@ -17383,6 +17497,13 @@ send@0.18.0: range-parser "~1.2.1" statuses "2.0.1" +serialize-javascript@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.2.tgz#defa1e055c83bf6d59ea805d8da862254eb6a6c2" + integrity sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g== + dependencies: + randombytes "^2.1.0" + serve-static@1.15.0, serve-static@^1.15.0: version "1.15.0" resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.15.0.tgz#faaef08cffe0a1a62f60cad0c4e513cff0ac9540"