From 4f207604bdc7ca57622d0dc180f92d512e463aaf Mon Sep 17 00:00:00 2001 From: Jicheng Lu <103353@smsassist.com> Date: Fri, 14 Feb 2025 11:25:43 -0600 Subject: [PATCH 1/4] rename --- src/lib/helpers/types/conversationTypes.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/lib/helpers/types/conversationTypes.js b/src/lib/helpers/types/conversationTypes.js index 6bce4176..070b7b2a 100644 --- a/src/lib/helpers/types/conversationTypes.js +++ b/src/lib/helpers/types/conversationTypes.js @@ -41,7 +41,8 @@ * @typedef {Object} StateSearchQuery * @property {string} query - The search query. * @property {number?} [keyLimit] - The key limit. - * @property {boolean?} [preLoad] - Whether it is preloading or not. + * @property {number?} [convLimit] - The conversation limit. + * @property {boolean?} [preload] - Whether it is preloading or not. */ From 8a6ff6c4110b7a5efd838dbf7dc2c4a9bad115e5 Mon Sep 17 00:00:00 2001 From: Jicheng Lu <103353@smsassist.com> Date: Mon, 17 Feb 2025 11:50:04 -0600 Subject: [PATCH 2/4] append image --- src/lib/common/FileGallery.svelte | 2 +- src/lib/common/MessageFileGallery.svelte | 60 +++++++++++-------- .../[conversationId]/chat-box.svelte | 10 ++-- 3 files changed, 42 insertions(+), 30 deletions(-) diff --git a/src/lib/common/FileGallery.svelte b/src/lib/common/FileGallery.svelte index cc081daa..a800baaa 100644 --- a/src/lib/common/FileGallery.svelte +++ b/src/lib/common/FileGallery.svelte @@ -103,7 +103,7 @@ {/if} - {#if needDownload} + {#if needDownload && !!file.file_download_url} {/if} - {#if !!message.is_chat_message || !!message.has_message_files} + {#if !!message.is_chat_message || !!message.has_message_files || message?.data?.startsWith("data:image")} getConversationFiles(params.conversationId, message.message_id, FileSourceType.Bot)} /> From 87dd06dd229ac5a027f26240e98e059b533cde87 Mon Sep 17 00:00:00 2001 From: Jicheng Lu <103353@smsassist.com> Date: Mon, 17 Feb 2025 11:58:49 -0600 Subject: [PATCH 3/4] minor change --- src/routes/chat/[agentId]/[conversationId]/chat-box.svelte | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/routes/chat/[agentId]/[conversationId]/chat-box.svelte b/src/routes/chat/[agentId]/[conversationId]/chat-box.svelte index af309236..fcbf834d 100644 --- a/src/routes/chat/[agentId]/[conversationId]/chat-box.svelte +++ b/src/routes/chat/[agentId]/[conversationId]/chat-box.svelte @@ -92,6 +92,7 @@ const maxTextLength = 64000; const duration = 2000; const MESSAGE_STORAGE_KEY = 'message_draft_'; + const IMAGE_DATA_PREFIX = 'data:image'; /** @type {import('$agentTypes').AgentModel} */ export let agent; @@ -1658,7 +1659,7 @@ {#if !!message.post_action_disclaimer} {/if} - {#if !!message.is_chat_message || !!message.has_message_files || message?.data?.startsWith("data:image")} + {#if !!message.is_chat_message || !!message.has_message_files || message?.data?.startsWith(IMAGE_DATA_PREFIX)} {/if} - {#if !!message.is_chat_message || !!message.has_message_files || message?.data?.startsWith("data:image")} + {#if !!message.is_chat_message || !!message.has_message_files || message?.data?.startsWith(IMAGE_DATA_PREFIX)} Date: Mon, 17 Feb 2025 14:14:35 -0600 Subject: [PATCH 4/4] add global error --- src/lib/helpers/constants.js | 3 +- src/lib/helpers/http.js | 103 +++++++++++++++--- src/lib/helpers/store.js | 11 ++ src/routes/+layout.svelte | 33 ++++-- .../[conversationId]/chat-box.svelte | 3 +- src/routes/page/agent/[agentId]/+page.svelte | 7 +- src/routes/page/conversation/+page.svelte | 7 +- .../[conversationId]/conv-dialogs.svelte | 15 +-- 8 files changed, 132 insertions(+), 50 deletions(-) diff --git a/src/lib/helpers/constants.js b/src/lib/helpers/constants.js index 142d881a..ddb7d4a5 100644 --- a/src/lib/helpers/constants.js +++ b/src/lib/helpers/constants.js @@ -35,4 +35,5 @@ export const LEARNER_ID = "01acc3e5-0af7-49e6-ad7a-a760bd12dc40"; export const EVALUATOR_ID = "2cd4b805-7078-4405-87e9-2ec9aadf8a11"; export const TRAINING_MODE = "training"; -export const DEFAULT_KNOWLEDGE_COLLECTION = "BotSharp"; \ No newline at end of file +export const DEFAULT_KNOWLEDGE_COLLECTION = "BotSharp"; +export const IMAGE_DATA_PREFIX = 'data:image'; \ No newline at end of file diff --git a/src/lib/helpers/http.js b/src/lib/helpers/http.js index 4a239f00..ec388ff5 100644 --- a/src/lib/helpers/http.js +++ b/src/lib/helpers/http.js @@ -1,11 +1,11 @@ import axios from 'axios'; -import { getUserStore, loaderStore } from '$lib/helpers/store.js'; +import { getUserStore, globalErrorStore, loaderStore } from '$lib/helpers/store.js'; // Add a request interceptor to attach authentication tokens or headers axios.interceptors.request.use( (config) => { // Add your authentication logic here - let user = getUserStore(); + const user = getUserStore(); if (!skipLoader(config)) { loaderStore.set(true); } @@ -25,26 +25,28 @@ axios.interceptors.response.use( (response) => { // If the request was successful, return the response loaderStore.set(false); + const user = getUserStore(); + + const isExpired = Date.now() / 1000 > user.expires; + if (isExpired) { + redirectToLogin(); + return Promise.reject('user token expired!'); + } return response; }, (error) => { loaderStore.set(false); - let user = getUserStore(); - - if (Date.now() / 1000 > user.expires) { - error.response = {status: 401}; - } - - // If the error status is 401, handle it here - if (error.response && error.response.status === 401) { - // Perform actions like redirecting to the login page or refreshing tokens - // Example: redirect to the login page - const curUrl = window.location.pathname + window.location.search; - let loginUrl = 'login'; - if (curUrl) { - loginUrl += `?redirect=${encodeURIComponent(curUrl)}`; - } - window.location.href = loginUrl; + const user = getUserStore(); + console.log('error', error); + const isExpired = Date.now() / 1000 > user.expires; + if (isExpired || (error.response && error.response.status === 401)) { + redirectToLogin(); + return Promise.reject(error); + } else if (!skipGlobalError(error.config)) { + globalErrorStore.set(true); + setTimeout(() => { + globalErrorStore.set(false); + }, 2500); } // Return the error to the calling function @@ -52,8 +54,19 @@ axios.interceptors.response.use( } ); + +function redirectToLogin() { + const curUrl = window.location.pathname + window.location.search; + let loginUrl = 'login'; + if (curUrl) { + loginUrl += `?redirect=${encodeURIComponent(curUrl)}`; + } + window.location.href = loginUrl; +} + /** @param {import('axios').InternalAxiosRequestConfig} config */ function skipLoader(config) { + /** @type {RegExp[]} */ const postRegexes = [ new RegExp('http(s*)://(.*?)/conversation/(.*?)/(.*?)', 'g'), new RegExp('http(s*)://(.*?)/agent', 'g'), @@ -64,6 +77,7 @@ function skipLoader(config) { new RegExp('http(s*)://(.*?)/users', 'g') ]; + /** @type {RegExp[]} */ const putRegexes = [ new RegExp('http(s*)://(.*?)/knowledge/vector/(.*?)/update', 'g'), new RegExp('http(s*)://(.*?)/conversation/(.*?)/update-message', 'g'), @@ -71,12 +85,14 @@ function skipLoader(config) { new RegExp('http(s*)://(.*?)/users', 'g'), ]; + /** @type {RegExp[]} */ const deleteRegexes = [ new RegExp('http(s*)://(.*?)/knowledge/vector/(.*?)/delete-collection', 'g'), new RegExp('http(s*)://(.*?)/knowledge/vector/(.*?)/data/(.*?)', 'g'), new RegExp('http(s*)://(.*?)/knowledge/vector/(.*?)/data', 'g'), ]; + /** @type {RegExp[]} */ const getRegexes = [ new RegExp('http(s*)://(.*?)/setting/(.*?)', 'g'), new RegExp('http(s*)://(.*?)/user/me', 'g'), @@ -112,6 +128,56 @@ function skipLoader(config) { return false; } +/** @param {import('axios').InternalAxiosRequestConfig} config */ +function skipGlobalError(config) { + /** @type {RegExp[]} */ + const postRegexes = [ + new RegExp('http(s*)://(.*?)/knowledge/vector/(.*?)/page', 'g'), + new RegExp('http(s*)://(.*?)/knowledge/(.*?)/search', 'g'), + new RegExp('http(s*)://(.*?)/knowledge/vector/(.*?)/create', 'g'), + new RegExp('http(s*)://(.*?)/knowledge/document/(.*?)/page', 'g'), + new RegExp('http(s*)://(.*?)/knowledge/vector/create-collection', 'g'), + new RegExp('http(s*)://(.*?)/refresh-agents', 'g') + ]; + + /** @type {RegExp[]} */ + const putRegexes = [ + new RegExp('http(s*)://(.*?)/knowledge/vector/(.*?)/update', 'g'), + new RegExp('http(s*)://(.*?)/role', 'g'), + new RegExp('http(s*)://(.*?)/user', 'g'), + new RegExp('http(s*)://(.*?)/conversation/(.*?)/update-message', 'g'), + new RegExp('http(s*)://(.*?)/conversation/(.*?)/update-tags', 'g') + ]; + + /** @type {RegExp[]} */ + const deleteRegexes = [ + new RegExp('http(s*)://(.*?)/knowledge/vector/(.*?)/delete-collection', 'g'), + new RegExp('http(s*)://(.*?)/knowledge/vector/(.*?)/data/(.*?)', 'g'), + new RegExp('http(s*)://(.*?)/knowledge/vector/(.*?)/data', 'g'), + ]; + + /** @type {RegExp[]} */ + const getRegexes = []; + + if (config.method === 'post' && postRegexes.some(regex => regex.test(config.url || ''))) { + return true; + } + + if (config.method === 'put' && putRegexes.some(regex => regex.test(config.url || ''))) { + return true; + } + + if (config.method === 'delete' && deleteRegexes.some(regex => regex.test(config.url || ''))) { + return true; + } + + if (config.method === 'get' && getRegexes.some(regex => regex.test(config.url || ''))) { + return true; + } + + return false; +} + /** * @param {String} url * @param {Object} args @@ -120,6 +186,7 @@ function skipLoader(config) { export function replaceUrl(url, args) { const keys = Object.keys(args); keys.forEach(key => { + // @ts-ignore url = url.replace("{" + key + "}", args[key]); }); return url; diff --git a/src/lib/helpers/store.js b/src/lib/helpers/store.js index 328cbb49..4d886565 100644 --- a/src/lib/helpers/store.js +++ b/src/lib/helpers/store.js @@ -90,6 +90,17 @@ const createLoaderStore = () => { export const loaderStore = createLoaderStore(); +const createGlobalErrorStore = () => { + const { subscribe, set } = writable(false); + return { + subscribe, + set + }; +} + +export const globalErrorStore = createGlobalErrorStore(); + + const createConversationUserStateStore = () => { return { resetAll: () => { diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte index 678b4039..13c71ce3 100644 --- a/src/routes/+layout.svelte +++ b/src/routes/+layout.svelte @@ -2,9 +2,10 @@ import { addMessages, init, getLocaleFromNavigator } from 'svelte-i18n'; import en from '$lib/langs/en.json'; import '$lib/helpers/http'; - import { onMount } from 'svelte'; - import { loaderStore } from '$lib/helpers/store'; + import { onDestroy, onMount } from 'svelte'; + import { globalErrorStore, loaderStore } from '$lib/helpers/store'; import Loader from '$lib/common/Loader.svelte'; + import LoadingToComplete from '$lib/common/LoadingToComplete.svelte'; addMessages('en', en); @@ -12,20 +13,38 @@ fallbackLocale: 'en', initialLocale: getLocaleFromNavigator() }); - /** - * @type {boolean} - */ - let isLoading; + + /** @type {boolean} */ + let isLoading = false; + let hasError = false; + + /** @type {any} */ + let loaderUnsubscriber; + /** @type {any} */ + let errorUnsubscriber; + onMount(() => { window?.speechSynthesis?.cancel(); - const subscribe = loaderStore.subscribe(value => { + loaderUnsubscriber = loaderStore.subscribe(value => { isLoading = value; }); + + errorUnsubscriber = globalErrorStore.subscribe(value => { + hasError = value; + }); }) + + onDestroy(() => { + loaderUnsubscriber?.(); + errorUnsubscriber?.(); + }); {#if isLoading} {/if} + + +