Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/lib/common/FileGallery.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@
<i class="bx bx-trash" />
</div>
{/if}
{#if needDownload}
{#if needDownload && !!file.file_download_url}
<div
class="gallery-item-icon download-icon clickable"
tabindex="0"
Expand Down
60 changes: 35 additions & 25 deletions src/lib/common/MessageFileGallery.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,11 @@
/** @type {string} */
export let galleryStyles = '';

/** @type {string} */
export let messageId;
/** @type {any} */
export let message;

/** @type {boolean} */
export let appendImage = false;

/** @type {() => Promise<any>} */
export let fetchFiles = () => Promise.resolve([]);
Expand All @@ -25,31 +28,38 @@
/** @type {import('$fileTypes').AudioFileModel[]} */
let audioFiles = [];

onMount(() => {
onMount(async () => {
if (fetchFiles != null && fetchFiles != undefined) {
fetchFiles().then(data => {
// @ts-ignore
const validFiles = data?.filter(item => !!item.file_url) || [];
// @ts-ignore
textFiles = validFiles.filter(item => !isAudio(item.file_extension)).map(item => {
return {
file_name: item.file_name,
file_extension: item.file_extension,
file_data: isExternalUrl(item.file_url) ? item.file_url : `${PUBLIC_SERVICE_URL}${item.file_url}?access_token=${$userStore?.token}`,
file_download_url: isExternalUrl(item.file_download_url) ? item.file_download_url : `${PUBLIC_SERVICE_URL}${item.file_download_url}?access_token=${$userStore?.token}`
};
});
// @ts-ignore
audioFiles = validFiles.filter(item => isAudio(item.file_extension)).map(item => {
return {
name: item.file_name,
cover: AUDIO_ICON,
artist: '',
url: isExternalUrl(item.file_url) ? item.file_url : `${PUBLIC_SERVICE_URL}${item.file_url}?access_token=${$userStore?.token}`
};
});
const res = await fetchFiles();
// @ts-ignore
const validFiles = res?.filter(item => !!item.file_url) || [];
// @ts-ignore
textFiles = validFiles.filter(item => !isAudio(item.file_extension)).map(item => {
return {
file_name: item.file_name,
file_extension: item.file_extension,
file_data: isExternalUrl(item.file_url) ? item.file_url : `${PUBLIC_SERVICE_URL}${item.file_url}?access_token=${$userStore?.token}`,
file_download_url: isExternalUrl(item.file_download_url) ? item.file_download_url : `${PUBLIC_SERVICE_URL}${item.file_download_url}?access_token=${$userStore?.token}`
};
});
// @ts-ignore
audioFiles = validFiles.filter(item => isAudio(item.file_extension)).map(item => {
return {
name: item.file_name,
cover: AUDIO_ICON,
artist: '',
url: isExternalUrl(item.file_url) ? item.file_url : `${PUBLIC_SERVICE_URL}${item.file_url}?access_token=${$userStore?.token}`
};
});
}

if (appendImage && message?.data) {
textFiles = [...textFiles, {
file_name: 'data',
file_extension: '',
file_data: message?.data
}];
}
});

/** @param {number} idx */
Expand All @@ -71,7 +81,7 @@
onDownload={idx => handleDownloadFile(idx)}
/>
<AudioGallery
id={messageId}
id={message?.message_id}
containerClasses={galleryClasses}
containerStyles={galleryStyles}
audios={audioFiles}
Expand Down
3 changes: 2 additions & 1 deletion src/lib/helpers/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -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";
export const DEFAULT_KNOWLEDGE_COLLECTION = "BotSharp";
export const IMAGE_DATA_PREFIX = 'data:image';
103 changes: 85 additions & 18 deletions src/lib/helpers/http.js
Original file line number Diff line number Diff line change
@@ -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);
}
Expand All @@ -25,35 +25,48 @@ 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
return Promise.reject(error);
}
);


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<any>} config */
function skipLoader(config) {
/** @type {RegExp[]} */
const postRegexes = [
new RegExp('http(s*)://(.*?)/conversation/(.*?)/(.*?)', 'g'),
new RegExp('http(s*)://(.*?)/agent', 'g'),
Expand All @@ -64,19 +77,22 @@ 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'),
new RegExp('http(s*)://(.*?)/conversation/(.*?)/update-tags', 'g'),
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'),
Expand Down Expand Up @@ -112,6 +128,56 @@ function skipLoader(config) {
return false;
}

/** @param {import('axios').InternalAxiosRequestConfig<any>} 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
Expand All @@ -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;
Expand Down
11 changes: 11 additions & 0 deletions src/lib/helpers/store.js
Original file line number Diff line number Diff line change
Expand Up @@ -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: () => {
Expand Down
3 changes: 2 additions & 1 deletion src/lib/helpers/types/conversationTypes.js
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*/


Expand Down
33 changes: 26 additions & 7 deletions src/routes/+layout.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,49 @@
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);

init({
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?.();
});
</script>
{#if isLoading}
<Loader size={50}/>
{/if}

<LoadingToComplete isError={hasError} />

<slot />

<style lang="scss">
Expand Down
12 changes: 7 additions & 5 deletions src/routes/chat/[agentId]/[conversationId]/chat-box.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
PUBLIC_LIVECHAT_ENABLE_TRAINING,
PUBLIC_DEBUG_MODE
} from '$env/static/public';
import { BOT_SENDERS, LEARNER_ID, TRAINING_MODE, USER_SENDERS, ADMIN_ROLES } from '$lib/helpers/constants';
import { BOT_SENDERS, LEARNER_ID, TRAINING_MODE, USER_SENDERS, ADMIN_ROLES, IMAGE_DATA_PREFIX } from '$lib/helpers/constants';
import { signalr } from '$lib/services/signalr-service.js';
import { llmRealtime } from '$lib/services/llm-realtime-service.js';
import { newConversation } from '$lib/services/conversation-service';
Expand Down Expand Up @@ -1658,9 +1658,10 @@
{#if !!message.post_action_disclaimer}
<RcDisclaimer content={message.post_action_disclaimer} />
{/if}
{#if !!message.is_chat_message || !!message.has_message_files}
{#if !!message.is_chat_message || !!message.has_message_files || message?.data?.startsWith(IMAGE_DATA_PREFIX)}
<MessageFileGallery
messageId={message?.message_id}
message={message}
appendImage
galleryStyles={'justify-content: flex-end;'}
fetchFiles={() => getConversationFiles(params.conversationId, message.message_id, FileSourceType.User)}
/>
Expand Down Expand Up @@ -1756,9 +1757,10 @@
</div>
</div>
{/if}
{#if !!message.is_chat_message || !!message.has_message_files}
{#if !!message.is_chat_message || !!message.has_message_files || message?.data?.startsWith(IMAGE_DATA_PREFIX)}
<MessageFileGallery
messageId={message?.message_id}
message={message}
appendImage
galleryStyles={'justify-content: flex-start;'}
fetchFiles={() => getConversationFiles(params.conversationId, message.message_id, FileSourceType.Bot)}
/>
Expand Down
Loading