@@ -42,5 +43,5 @@ export const WorkHeader: FC = observer(() => {
- );
+ ;
});
\ No newline at end of file
diff --git a/frontend/src/main.tsx b/frontend/src/main.tsx
index c8a60d6..bbf8af8 100644
--- a/frontend/src/main.tsx
+++ b/frontend/src/main.tsx
@@ -1,3 +1,4 @@
+import './webWails';
import React from 'react';
import { createRoot } from 'react-dom/client';
import './style.scss';
@@ -6,7 +7,6 @@ import App from './App';
import { HashRouter } from 'react-router-dom';
import { startup } from './startup';
import './_locales/i18n-react';
-import 'html-midi-player';
import { WindowShow } from '../wailsjs/runtime';
startup().then(() => {
diff --git a/frontend/src/pages/About.tsx b/frontend/src/pages/About.tsx
index 70bafc5..608dab8 100644
--- a/frontend/src/pages/About.tsx
+++ b/frontend/src/pages/About.tsx
@@ -5,9 +5,7 @@ import MarkdownRender from '../components/MarkdownRender';
import { observer } from 'mobx-react-lite';
import commonStore from '../stores/commonStore';
-export type AboutContent = { [lang: string]: string }
-
-export const About: FC = observer(() => {
+const About: FC = observer(() => {
const { t } = useTranslation();
const lang: string = commonStore.settings.language;
@@ -21,3 +19,5 @@ export const About: FC = observer(() => {
} />
);
});
+
+export default About;
diff --git a/frontend/src/pages/Chat.tsx b/frontend/src/pages/Chat.tsx
index 05d66ce..b4c654f 100644
--- a/frontend/src/pages/Chat.tsx
+++ b/frontend/src/pages/Chat.tsx
@@ -28,46 +28,16 @@ import { OpenFileFolder, OpenOpenFileDialog, OpenSaveFileDialog } from '../../wa
import { absPathAsset, bytesToReadable, toastWithButton } from '../utils';
import { PresetsButton } from './PresetsManager/PresetsButton';
import { useMediaQuery } from 'usehooks-ts';
+import { botName, ConversationMessage, MessageType, userName, welcomeUuid } from '../types/chat';
-export const userName = 'M E';
-export const botName = 'A I';
+let chatSseControllers: {
+ [id: string]: AbortController
+} = {};
-export const welcomeUuid = 'welcome';
-
-export enum MessageType {
- Normal,
- Error
-}
-
-export type Side = 'left' | 'right'
-
-export type Color = 'neutral' | 'brand' | 'colorful'
-
-export type MessageItem = {
- sender: string,
- type: MessageType,
- color: Color,
- avatarImg?: string,
- time: string,
- content: string,
- side: Side,
- done: boolean
-}
-
-export type Conversation = {
- [uuid: string]: MessageItem
-}
-
-export type Role = 'assistant' | 'user' | 'system';
-
-export type ConversationMessage = {
- role: Role;
- content: string;
-}
-
-let chatSseControllers: { [id: string]: AbortController } = {};
-
-const MoreUtilsButton: FC<{ uuid: string, setEditing: (editing: boolean) => void }> = observer(({
+const MoreUtilsButton: FC<{
+ uuid: string,
+ setEditing: (editing: boolean) => void
+}> = observer(({
uuid,
setEditing
}) => {
@@ -98,7 +68,8 @@ const MoreUtilsButton: FC<{ uuid: string, setEditing: (editing: boolean) => void
});
const ChatMessageItem: FC<{
- uuid: string, onSubmit: (message: string | null, answerId: string | null,
+ uuid: string,
+ onSubmit: (message: string | null, answerId: string | null,
startUuid: string | null, endUuid: string | null, includeEndUuid: boolean) => void
}> = observer(({ uuid, onSubmit }) => {
const { t } = useTranslation();
@@ -243,7 +214,7 @@ const ChatPanel: FC = observer(() => {
color: 'colorful',
avatarImg: logo,
time: new Date().toISOString(),
- content: t('Hello! I\'m RWKV, an open-source and commercially usable large language model.'),
+ content: commonStore.platform === 'web' ? t('Hello, what can I do for you?') : t('Hello! I\'m RWKV, an open-source and commercially usable large language model.'),
side: 'left',
done: true
}
@@ -260,7 +231,7 @@ const ChatPanel: FC = observer(() => {
e.stopPropagation();
if (e.type === 'click' || (e.keyCode === 13 && !e.shiftKey)) {
e.preventDefault();
- if (commonStore.status.status === ModelStatus.Offline && !commonStore.settings.apiUrl) {
+ if (commonStore.status.status === ModelStatus.Offline && !commonStore.settings.apiUrl && commonStore.platform !== 'web') {
toast(t('Please click the button in the top right corner to start the model'), { type: 'warning' });
return;
}
@@ -464,7 +435,7 @@ const ChatPanel: FC = observer(() => {
:
}
size="small" shape="circular" appearance="secondary"
onClick={() => {
- if (commonStore.status.status === ModelStatus.Offline && !commonStore.settings.apiUrl) {
+ if (commonStore.status.status === ModelStatus.Offline && !commonStore.settings.apiUrl && commonStore.platform !== 'web') {
toast(t('Please click the button in the top right corner to start the model'), { type: 'warning' });
return;
}
@@ -478,43 +449,62 @@ const ChatPanel: FC = observer(() => {
commonStore.setAttachmentUploading(true);
- // Both are slow. Communication between frontend and backend is slow. Use AssetServer Handler to read the file.
- // const blob = new Blob([atob(info.content as unknown as string)]); // await fetch(`data:application/octet-stream;base64,${info.content}`).then(r => r.blob());
- const blob = await fetch(absPathAsset(filePath)).then(r => r.blob());
- const attachmentName = filePath.split(/[\\/]/).pop();
- const urlPath = `/file-to-text?file_name=${attachmentName}`;
- const bodyForm = new FormData();
- bodyForm.append('file_data', blob, attachmentName);
- fetch(commonStore.settings.apiUrl ?
- commonStore.settings.apiUrl + urlPath :
- `http://127.0.0.1:${port}${urlPath}`, {
- method: 'POST',
- body: bodyForm
- }).then(async r => {
- if (r.status === 200) {
- const pages = (await r.json()).pages as any[];
- let attachmentContent: string;
- if (pages.length === 1)
- attachmentContent = pages[0].page_content;
- else
- attachmentContent = pages.map((p, i) => `Page ${i + 1}:\n${p.page_content}`).join('\n\n');
- commonStore.setCurrentTempAttachment(
- {
- name: attachmentName!,
- size: blob.size,
- content: attachmentContent
- });
- } else {
- toast(r.statusText + '\n' + (await r.text()), {
- type: 'error'
- });
- }
- commonStore.setAttachmentUploading(false);
- }
- ).catch(e => {
+ let blob: Blob;
+ let attachmentName: string | undefined;
+ let attachmentContent: string | undefined;
+ if (commonStore.platform === 'web') {
+ const webReturn = filePath as any;
+ blob = webReturn.blob;
+ attachmentName = blob.name;
+ attachmentContent = webReturn.content;
+ } else {
+ // Both are slow. Communication between frontend and backend is slow. Use AssetServer Handler to read the file.
+ // const blob = new Blob([atob(info.content as unknown as string)]); // await fetch(`data:application/octet-stream;base64,${info.content}`).then(r => r.blob());
+ blob = await fetch(absPathAsset(filePath)).then(r => r.blob());
+ attachmentName = filePath.split(/[\\/]/).pop();
+ }
+ if (attachmentContent) {
+ commonStore.setCurrentTempAttachment(
+ {
+ name: attachmentName!,
+ size: blob.size,
+ content: attachmentContent
+ });
commonStore.setAttachmentUploading(false);
- toast(t('Error') + ' - ' + (e.message || e), { type: 'error', autoClose: 2500 });
- });
+ } else {
+ const urlPath = `/file-to-text?file_name=${attachmentName}`;
+ const bodyForm = new FormData();
+ bodyForm.append('file_data', blob, attachmentName);
+ fetch(commonStore.settings.apiUrl ?
+ commonStore.settings.apiUrl + urlPath :
+ `http://127.0.0.1:${port}${urlPath}`, {
+ method: 'POST',
+ body: bodyForm
+ }).then(async r => {
+ if (r.status === 200) {
+ const pages = (await r.json()).pages as any[];
+ if (pages.length === 1)
+ attachmentContent = pages[0].page_content;
+ else
+ attachmentContent = pages.map((p, i) => `Page ${i + 1}:\n${p.page_content}`).join('\n\n');
+ commonStore.setCurrentTempAttachment(
+ {
+ name: attachmentName!,
+ size: blob.size,
+ content: attachmentContent!
+ });
+ } else {
+ toast(r.statusText + '\n' + (await r.text()), {
+ type: 'error'
+ });
+ }
+ commonStore.setAttachmentUploading(false);
+ }
+ ).catch(e => {
+ commonStore.setAttachmentUploading(false);
+ toast(t('Error') + ' - ' + (e.message || e), { type: 'error', autoClose: 2500 });
+ });
+ }
}).catch(e => {
toast(t('Error') + ' - ' + (e.message || e), { type: 'error', autoClose: 2500 });
});
@@ -586,7 +576,7 @@ const ChatPanel: FC = observer(() => {
);
});
-export const Chat: FC = observer(() => {
+const Chat: FC = observer(() => {
return (
@@ -594,3 +584,5 @@ export const Chat: FC = observer(() => {
);
});
+
+export default Chat;
diff --git a/frontend/src/pages/Completion.tsx b/frontend/src/pages/Completion.tsx
index a1133d4..fe57f35 100644
--- a/frontend/src/pages/Completion.tsx
+++ b/frontend/src/pages/Completion.tsx
@@ -5,7 +5,6 @@ import { Button, Dropdown, Input, Option, Textarea } from '@fluentui/react-compo
import { Labeled } from '../components/Labeled';
import { ValuedSlider } from '../components/ValuedSlider';
import { useTranslation } from 'react-i18next';
-import { ApiParameters } from './Configs';
import commonStore, { ModelStatus } from '../stores/commonStore';
import { fetchEventSource } from '@microsoft/fetch-event-source';
import { toast } from 'react-toastify';
@@ -14,18 +13,7 @@ import { PresetsButton } from './PresetsManager/PresetsButton';
import { ToolTipButton } from '../components/ToolTipButton';
import { ArrowSync20Regular } from '@fluentui/react-icons';
import { defaultPresets } from './defaultConfigs';
-
-export type CompletionParams = Omit
& {
- stop: string,
- injectStart: string,
- injectEnd: string
-};
-
-export type CompletionPreset = {
- name: string,
- prompt: string,
- params: CompletionParams
-}
+import { CompletionParams, CompletionPreset } from '../types/completion';
let completionSseController: AbortController | null = null;
@@ -80,7 +68,7 @@ const CompletionPanel: FC = observer(() => {
const onSubmit = (prompt: string) => {
commonStore.setCompletionSubmittedPrompt(prompt);
- if (commonStore.status.status === ModelStatus.Offline && !commonStore.settings.apiUrl) {
+ if (commonStore.status.status === ModelStatus.Offline && !commonStore.settings.apiUrl && commonStore.platform !== 'web') {
toast(t('Please click the button in the top right corner to start the model'), { type: 'warning' });
commonStore.setCompletionGenerating(false);
return;
@@ -269,7 +257,7 @@ const CompletionPanel: FC = observer(() => {
} />
} />
);
});
+
+export default Settings;
diff --git a/frontend/src/pages/Train.tsx b/frontend/src/pages/Train.tsx
index 2ab38f3..11d56cd 100644
--- a/frontend/src/pages/Train.tsx
+++ b/frontend/src/pages/Train.tsx
@@ -1,4 +1,4 @@
-import React, { FC, ReactElement, useEffect, useRef, useState } from 'react';
+import React, { FC, useEffect, useRef, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { Button, Dropdown, Input, Option, Select, Switch, Tab, TabList } from '@fluentui/react-components';
import {
@@ -24,7 +24,6 @@ import { Labeled } from '../components/Labeled';
import { ToolTipButton } from '../components/ToolTipButton';
import { DataUsageSettings20Regular, Folder20Regular } from '@fluentui/react-icons';
import { useNavigate } from 'react-router';
-import { Precision } from './Configs';
import {
CategoryScale,
Chart as ChartJS,
@@ -40,6 +39,12 @@ import { ChartJSOrUndefined } from 'react-chartjs-2/dist/types';
import { WindowShow } from '../../wailsjs/runtime';
import { t } from 'i18next';
import { DialogButton } from '../components/DialogButton';
+import {
+ DataProcessParameters,
+ LoraFinetuneParameters,
+ LoraFinetunePrecision,
+ TrainNavigationItem
+} from '../types/train';
ChartJS.register(
CategoryScale,
@@ -86,39 +91,6 @@ const addLossDataToChart = (epoch: number, loss: number) => {
commonStore.setChartData(commonStore.chartData);
};
-export type DataProcessParameters = {
- dataPath: string;
- vocabPath: string;
-}
-
-export type LoraFinetunePrecision = 'bf16' | 'fp16' | 'tf32';
-
-export type LoraFinetuneParameters = {
- baseModel: string;
- ctxLen: number;
- epochSteps: number;
- epochCount: number;
- epochBegin: number;
- epochSave: number;
- microBsz: number;
- accumGradBatches: number;
- preFfn: boolean;
- headQk: boolean;
- lrInit: string;
- lrFinal: string;
- warmupSteps: number;
- beta1: number;
- beta2: number;
- adamEps: string;
- devices: number;
- precision: LoraFinetunePrecision;
- gradCp: boolean;
- loraR: number;
- loraAlpha: number;
- loraDropout: number;
- loraLoad: string
-}
-
const loraFinetuneParametersOptions: Array<[key: keyof LoraFinetuneParameters, type: string, name: string]> = [
['devices', 'number', 'Devices'],
['precision', 'LoraFinetunePrecision', 'Precision'],
@@ -568,10 +540,6 @@ const LoraFinetune: FC = observer(() => {
);
});
-type TrainNavigationItem = {
- element: ReactElement;
-};
-
const pages: { [label: string]: TrainNavigationItem } = {
'LoRA Finetune': {
element:
@@ -582,7 +550,7 @@ const pages: { [label: string]: TrainNavigationItem } = {
};
-export const Train: FC = () => {
+const Train: FC = () => {
const { t } = useTranslation();
const [tab, setTab] = useState('LoRA Finetune');
@@ -607,3 +575,5 @@ export const Train: FC = () => {