diff --git a/web/package.json b/web/package.json index fe9a26ac71..07c13a84ca 100644 --- a/web/package.json +++ b/web/package.json @@ -44,6 +44,7 @@ "i18next-resources-to-backend": "^1.1.3", "immer": "^9.0.19", "js-cookie": "^3.0.1", + "katex": "^0.16.7", "lodash-es": "^4.17.21", "negotiator": "^0.6.3", "next": "13.2.4", diff --git a/web/service/base.ts b/web/service/base.ts index c6e841e5ac..bbc9261ac2 100644 --- a/web/service/base.ts +++ b/web/service/base.ts @@ -1,4 +1,5 @@ -import { API_PREFIX, PUBLIC_API_PREFIX, IS_CE_EDITION } from '@/config' +/* eslint-disable no-new, prefer-promise-reject-errors */ +import { API_PREFIX, IS_CE_EDITION, PUBLIC_API_PREFIX } from '@/config' import Toast from '@/app/components/base/toast' const TIME_OUT = 100000 @@ -46,12 +47,11 @@ function unicodeToChar(text: string) { }) } - export function format(text: string) { let res = text.trim() - if (res.startsWith('\n')) { + if (res.startsWith('\n')) res = res.replace('\n', '') - } + return res.replaceAll('\n', '
').replaceAll('```', '') } @@ -77,12 +77,22 @@ const handleStream = (response: any, onData: IOnData, onCompleted?: IOnCompleted lines.forEach((message) => { if (message.startsWith('data: ')) { // check if it starts with data: // console.log(message); - bufferObj = JSON.parse(message.substring(6)) // remove data: and parse as json + try { + bufferObj = JSON.parse(message.substring(6)) // remove data: and parse as json + } + catch (e) { + // mute handle message cut off + onData('', isFirstMessage, { + conversationId: bufferObj?.conversation_id, + messageId: bufferObj?.id, + }) + return + } if (bufferObj.status === 400 || !bufferObj.event) { onData('', false, { conversationId: undefined, messageId: '', - errorMessage: bufferObj.message + errorMessage: bufferObj.message, }) hasError = true onCompleted && onCompleted(true) @@ -97,19 +107,19 @@ const handleStream = (response: any, onData: IOnData, onCompleted?: IOnCompleted } }) buffer = lines[lines.length - 1] - } catch (e) { + } + catch (e) { onData('', false, { conversationId: undefined, messageId: '', - errorMessage: e + '' + errorMessage: `${e}`, }) hasError = true onCompleted && onCompleted(true) return } - if (!hasError) { + if (!hasError) read() - } }) } read() @@ -120,8 +130,8 @@ const baseFetch = ( fetchOptions: any, { isPublicAPI = false, - needAllResponseContent - }: IOtherOptions + needAllResponseContent, + }: IOtherOptions, ) => { const options = Object.assign({}, baseOptions, fetchOptions) if (isPublicAPI) { @@ -129,7 +139,7 @@ const baseFetch = ( options.headers.set('Authorization', `bearer ${sharedToken}`) } - let urlPrefix = isPublicAPI ? PUBLIC_API_PREFIX : API_PREFIX + const urlPrefix = isPublicAPI ? PUBLIC_API_PREFIX : API_PREFIX let urlWithPrefix = `${urlPrefix}${url.startsWith('/') ? url : `/${url}`}` const { method, params, body } = options @@ -176,12 +186,14 @@ const baseFetch = ( bodyJson.then((data: any) => { if (data.code === 'not_setup') { globalThis.location.href = `${globalThis.location.origin}/install` - } else { + } + else { if (location.pathname === '/signin') { bodyJson.then((data: any) => { Toast.notify({ type: 'error', message: data.message }) }) - } else { + } + else { globalThis.location.href = loginUrl } } @@ -195,15 +207,13 @@ const baseFetch = ( new Promise(() => { bodyJson.then((data: any) => { Toast.notify({ type: 'error', message: data.message }) - if (data.code === 'already_setup') { + if (data.code === 'already_setup') globalThis.location.href = `${globalThis.location.origin}/signin` - } }) }) break // fall through default: - // eslint-disable-next-line no-new new Promise(() => { bodyJson.then((data: any) => { Toast.notify({ type: 'error', message: data.message }) @@ -215,7 +225,7 @@ const baseFetch = ( // handle delete api. Delete api not return content. if (res.status === 204) { - resolve({ result: "success" }) + resolve({ result: 'success' }) return } @@ -243,22 +253,21 @@ export const upload = (options: any): Promise => { ...defaultOptions, ...options, headers: { ...defaultOptions.headers, ...options.headers }, - }; - return new Promise(function (resolve, reject) { + } + return new Promise((resolve, reject) => { const xhr = options.xhr - xhr.open(options.method, options.url); - for (const key in options.headers) { - xhr.setRequestHeader(key, options.headers[key]); - } + xhr.open(options.method, options.url) + for (const key in options.headers) + xhr.setRequestHeader(key, options.headers[key]) + xhr.withCredentials = true xhr.responseType = 'json' xhr.onreadystatechange = function () { if (xhr.readyState === 4) { - if (xhr.status === 201) { + if (xhr.status === 201) resolve(xhr.response) - } else { + else reject(xhr) - } } } xhr.upload.onprogress = options.onprogress @@ -287,7 +296,6 @@ export const ssePost = (url: string, fetchOptions: any, { isPublicAPI = false, o .then((res: any) => { // debugger if (!/^(2|3)\d{2}$/.test(res.status)) { - // eslint-disable-next-line no-new new Promise(() => { res.json().then((data: any) => { Toast.notify({ type: 'error', message: data.message || 'Server Error' })