Completion Page
This commit is contained in:
		
							parent
							
								
									bcb38d991a
								
							
						
					
					
						commit
						c7ed4b07c2
					
				@ -20,11 +20,11 @@
 | 
			
		||||
  "Manage Models": "管理模型",
 | 
			
		||||
  "Model": "模型",
 | 
			
		||||
  "Model Parameters": "模型参数",
 | 
			
		||||
  "Frequency Penalty *": "Frequency Penalty *",
 | 
			
		||||
  "Presence Penalty *": "Presence Penalty *",
 | 
			
		||||
  "Top_P *": "Top_P *",
 | 
			
		||||
  "Temperature *": "Temperature *",
 | 
			
		||||
  "Max Response Token *": "最大响应 Token *",
 | 
			
		||||
  "Frequency Penalty": "Frequency Penalty",
 | 
			
		||||
  "Presence Penalty": "Presence Penalty",
 | 
			
		||||
  "Top_P": "Top_P",
 | 
			
		||||
  "Temperature": "Temperature",
 | 
			
		||||
  "Max Response Token": "最大响应 Token",
 | 
			
		||||
  "API Port": "API 端口",
 | 
			
		||||
  "Hover your mouse over the text to view a detailed description. Settings marked with * will take effect immediately after being saved.": "把鼠标悬停在文本上查看详细描述. 标记了星号 * 的设置在保存后会立即生效.",
 | 
			
		||||
  "Default API Parameters": "默认 API 参数",
 | 
			
		||||
@ -102,5 +102,17 @@
 | 
			
		||||
  "Enabling this option can greatly improve inference speed, but there may be compatibility issues. If it fails to start, please turn off this option.": "开启这个选项能大大提升推理速度,但可能存在兼容性问题,如果启动失败,请关闭此选项",
 | 
			
		||||
  "Supported custom cuda file not found": "没有找到支持的自定义cuda文件",
 | 
			
		||||
  "Failed to copy custom cuda file": "自定义cuda文件复制失败",
 | 
			
		||||
  "Downloading update, please wait. If it is not completed, please manually download the program from GitHub and replace the original program.": "正在下载更新,请等待。如果一直未完成,请从Github手动下载并覆盖原程序"
 | 
			
		||||
  "Downloading update, please wait. If it is not completed, please manually download the program from GitHub and replace the original program.": "正在下载更新,请等待。如果一直未完成,请从Github手动下载并覆盖原程序",
 | 
			
		||||
  "Completion": "补全",
 | 
			
		||||
  "Parameters": "参数",
 | 
			
		||||
  "Stop Sequences": "停止词",
 | 
			
		||||
  "When this content appears in the response result, the generation will end.": "响应结果出现该内容时就结束生成",
 | 
			
		||||
  "Reset": "重置",
 | 
			
		||||
  "Generate": "生成",
 | 
			
		||||
  "Writer": "写作",
 | 
			
		||||
  "Translator": "翻译",
 | 
			
		||||
  "Catgirl": "猫娘",
 | 
			
		||||
  "Explain Code": "代码解释",
 | 
			
		||||
  "Werewolf": "狼人杀",
 | 
			
		||||
  "Blank": "空白"
 | 
			
		||||
}
 | 
			
		||||
@ -3,18 +3,25 @@ import { Label, Tooltip } from '@fluentui/react-components';
 | 
			
		||||
import classnames from 'classnames';
 | 
			
		||||
 | 
			
		||||
export const Labeled: FC<{
 | 
			
		||||
  label: string; desc?: string | null, content: ReactElement, flex?: boolean, spaceBetween?: boolean
 | 
			
		||||
  label: string;
 | 
			
		||||
  desc?: string | null,
 | 
			
		||||
  content: ReactElement,
 | 
			
		||||
  flex?: boolean,
 | 
			
		||||
  spaceBetween?: boolean,
 | 
			
		||||
  breakline?: boolean
 | 
			
		||||
}> = ({
 | 
			
		||||
  label,
 | 
			
		||||
  desc,
 | 
			
		||||
  content,
 | 
			
		||||
  flex,
 | 
			
		||||
  spaceBetween
 | 
			
		||||
  spaceBetween,
 | 
			
		||||
  breakline
 | 
			
		||||
}) => {
 | 
			
		||||
  return (
 | 
			
		||||
    <div className={classnames(
 | 
			
		||||
      'items-center',
 | 
			
		||||
      !breakline ? 'items-center' : '',
 | 
			
		||||
      flex ? 'flex' : 'grid grid-cols-2',
 | 
			
		||||
      breakline ? 'flex-col' : '',
 | 
			
		||||
      spaceBetween && 'justify-between')
 | 
			
		||||
    }>
 | 
			
		||||
      {desc ?
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										46
									
								
								frontend/src/components/WorkHeader.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								frontend/src/components/WorkHeader.tsx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,46 @@
 | 
			
		||||
import React, { FC } from 'react';
 | 
			
		||||
import { observer } from 'mobx-react-lite';
 | 
			
		||||
import { Divider, PresenceBadge, Text } from '@fluentui/react-components';
 | 
			
		||||
import commonStore, { ModelStatus } from '../stores/commonStore';
 | 
			
		||||
import { ConfigSelector } from './ConfigSelector';
 | 
			
		||||
import { RunButton } from './RunButton';
 | 
			
		||||
import { PresenceBadgeStatus } from '@fluentui/react-badge';
 | 
			
		||||
import { useTranslation } from 'react-i18next';
 | 
			
		||||
 | 
			
		||||
const statusText = {
 | 
			
		||||
  [ModelStatus.Offline]: 'Offline',
 | 
			
		||||
  [ModelStatus.Starting]: 'Starting',
 | 
			
		||||
  [ModelStatus.Loading]: 'Loading',
 | 
			
		||||
  [ModelStatus.Working]: 'Working'
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const badgeStatus: { [modelStatus: number]: PresenceBadgeStatus } = {
 | 
			
		||||
  [ModelStatus.Offline]: 'unknown',
 | 
			
		||||
  [ModelStatus.Starting]: 'away',
 | 
			
		||||
  [ModelStatus.Loading]: 'away',
 | 
			
		||||
  [ModelStatus.Working]: 'available'
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const WorkHeader: FC = observer(() => {
 | 
			
		||||
  const { t } = useTranslation();
 | 
			
		||||
  const port = commonStore.getCurrentModelConfig().apiParameters.apiPort;
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <div className="flex flex-col gap-1">
 | 
			
		||||
      <div className="flex justify-between items-center">
 | 
			
		||||
        <div className="flex items-center gap-2">
 | 
			
		||||
          <PresenceBadge status={badgeStatus[commonStore.status.modelStatus]} />
 | 
			
		||||
          <Text size={100}>{t('Model Status') + ': ' + t(statusText[commonStore.status.modelStatus])}</Text>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div className="flex items-center gap-2">
 | 
			
		||||
          <ConfigSelector size="small" />
 | 
			
		||||
          <RunButton iconMode />
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
      <Text size={100}>
 | 
			
		||||
        {t('This tool\'s API is compatible with OpenAI API. It can be used with any ChatGPT tool you like. Go to the settings of some ChatGPT tool, replace the \'https://api.openai.com\' part in the API address with \'') + `http://127.0.0.1:${port}` + '\'.'}
 | 
			
		||||
      </Text>
 | 
			
		||||
      <Divider style={{ flexGrow: 0 }} />
 | 
			
		||||
    </div>
 | 
			
		||||
  );
 | 
			
		||||
});
 | 
			
		||||
@ -1,11 +1,8 @@
 | 
			
		||||
import React, { FC, useEffect, useRef, useState } from 'react';
 | 
			
		||||
import { useTranslation } from 'react-i18next';
 | 
			
		||||
import { RunButton } from '../components/RunButton';
 | 
			
		||||
import { Avatar, Divider, PresenceBadge, Text, Textarea } from '@fluentui/react-components';
 | 
			
		||||
import { Avatar, PresenceBadge, Textarea } from '@fluentui/react-components';
 | 
			
		||||
import commonStore, { ModelStatus } from '../stores/commonStore';
 | 
			
		||||
import { observer } from 'mobx-react-lite';
 | 
			
		||||
import { PresenceBadgeStatus } from '@fluentui/react-badge';
 | 
			
		||||
import { ConfigSelector } from '../components/ConfigSelector';
 | 
			
		||||
import { v4 as uuid } from 'uuid';
 | 
			
		||||
import classnames from 'classnames';
 | 
			
		||||
import { fetchEventSource } from '@microsoft/fetch-event-source';
 | 
			
		||||
@ -17,6 +14,7 @@ import { ArrowCircleUp28Regular, Delete28Regular, RecordStop28Regular } from '@f
 | 
			
		||||
import { CopyButton } from '../components/CopyButton';
 | 
			
		||||
import { ReadButton } from '../components/ReadButton';
 | 
			
		||||
import { toast } from 'react-toastify';
 | 
			
		||||
import { WorkHeader } from '../components/WorkHeader';
 | 
			
		||||
 | 
			
		||||
export const userName = 'M E';
 | 
			
		||||
export const botName = 'A I';
 | 
			
		||||
@ -293,40 +291,10 @@ const ChatPanel: FC = observer(() => {
 | 
			
		||||
  );
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const statusText = {
 | 
			
		||||
  [ModelStatus.Offline]: 'Offline',
 | 
			
		||||
  [ModelStatus.Starting]: 'Starting',
 | 
			
		||||
  [ModelStatus.Loading]: 'Loading',
 | 
			
		||||
  [ModelStatus.Working]: 'Working'
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const badgeStatus: { [modelStatus: number]: PresenceBadgeStatus } = {
 | 
			
		||||
  [ModelStatus.Offline]: 'unknown',
 | 
			
		||||
  [ModelStatus.Starting]: 'away',
 | 
			
		||||
  [ModelStatus.Loading]: 'away',
 | 
			
		||||
  [ModelStatus.Working]: 'available'
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const Chat: FC = observer(() => {
 | 
			
		||||
  const { t } = useTranslation();
 | 
			
		||||
  const port = commonStore.getCurrentModelConfig().apiParameters.apiPort;
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <div className="flex flex-col gap-1 p-2 h-full overflow-hidden">
 | 
			
		||||
      <div className="flex justify-between items-center">
 | 
			
		||||
        <div className="flex items-center gap-2">
 | 
			
		||||
          <PresenceBadge status={badgeStatus[commonStore.status.modelStatus]} />
 | 
			
		||||
          <Text size={100}>{t('Model Status') + ': ' + t(statusText[commonStore.status.modelStatus])}</Text>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div className="flex items-center gap-2">
 | 
			
		||||
          <ConfigSelector size="small" />
 | 
			
		||||
          <RunButton iconMode />
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
      <Text size={100}>
 | 
			
		||||
        {t('This tool\'s API is compatible with OpenAI API. It can be used with any ChatGPT tool you like. Go to the settings of some ChatGPT tool, replace the \'https://api.openai.com\' part in the API address with \'') + `http://127.0.0.1:${port}` + '\'.'}
 | 
			
		||||
      </Text>
 | 
			
		||||
      <Divider style={{ flexGrow: 0 }} />
 | 
			
		||||
      <WorkHeader />
 | 
			
		||||
      <ChatPanel />
 | 
			
		||||
    </div>
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										302
									
								
								frontend/src/pages/Completion.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										302
									
								
								frontend/src/pages/Completion.tsx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,302 @@
 | 
			
		||||
import React, { FC, useEffect, useRef } from 'react';
 | 
			
		||||
import { observer } from 'mobx-react-lite';
 | 
			
		||||
import { WorkHeader } from '../components/WorkHeader';
 | 
			
		||||
import { Button, Dropdown, Input, Option, Textarea } from '@fluentui/react-components';
 | 
			
		||||
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';
 | 
			
		||||
 | 
			
		||||
export type CompletionParams = Omit<ApiParameters, 'apiPort'> & { stop: string }
 | 
			
		||||
 | 
			
		||||
export type CompletionPreset = {
 | 
			
		||||
  name: string,
 | 
			
		||||
  prompt: string,
 | 
			
		||||
  params: CompletionParams
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const defaultPresets: CompletionPreset[] = [{
 | 
			
		||||
  name: 'Writer',
 | 
			
		||||
  prompt: '以下是不朽的科幻史诗巨著,描写细腻,刻画了宏大的星际文明战争。\n第一章\n',
 | 
			
		||||
  params: {
 | 
			
		||||
    maxResponseToken: 4100,
 | 
			
		||||
    temperature: 1,
 | 
			
		||||
    topP: 0.5,
 | 
			
		||||
    presencePenalty: 0.4,
 | 
			
		||||
    frequencyPenalty: 0.4,
 | 
			
		||||
    stop: ''
 | 
			
		||||
  }
 | 
			
		||||
}, {
 | 
			
		||||
  name: 'Translator',
 | 
			
		||||
  prompt: '',
 | 
			
		||||
  params: {
 | 
			
		||||
    maxResponseToken: 4100,
 | 
			
		||||
    temperature: 1,
 | 
			
		||||
    topP: 0.5,
 | 
			
		||||
    presencePenalty: 0.4,
 | 
			
		||||
    frequencyPenalty: 0.4,
 | 
			
		||||
    stop: ''
 | 
			
		||||
  }
 | 
			
		||||
}, {
 | 
			
		||||
  name: 'Catgirl',
 | 
			
		||||
  prompt: '',
 | 
			
		||||
  params: {
 | 
			
		||||
    maxResponseToken: 4100,
 | 
			
		||||
    temperature: 1,
 | 
			
		||||
    topP: 0.5,
 | 
			
		||||
    presencePenalty: 0.4,
 | 
			
		||||
    frequencyPenalty: 0.4,
 | 
			
		||||
    stop: ''
 | 
			
		||||
  }
 | 
			
		||||
}, {
 | 
			
		||||
  name: 'Explain Code',
 | 
			
		||||
  prompt: '',
 | 
			
		||||
  params: {
 | 
			
		||||
    maxResponseToken: 4100,
 | 
			
		||||
    temperature: 1,
 | 
			
		||||
    topP: 0.5,
 | 
			
		||||
    presencePenalty: 0.4,
 | 
			
		||||
    frequencyPenalty: 0.4,
 | 
			
		||||
    stop: ''
 | 
			
		||||
  }
 | 
			
		||||
}, {
 | 
			
		||||
  name: 'Werewolf',
 | 
			
		||||
  prompt: '',
 | 
			
		||||
  params: {
 | 
			
		||||
    maxResponseToken: 4100,
 | 
			
		||||
    temperature: 1,
 | 
			
		||||
    topP: 0.5,
 | 
			
		||||
    presencePenalty: 0.4,
 | 
			
		||||
    frequencyPenalty: 0.4,
 | 
			
		||||
    stop: ''
 | 
			
		||||
  }
 | 
			
		||||
}, {
 | 
			
		||||
  name: 'Blank',
 | 
			
		||||
  prompt: '',
 | 
			
		||||
  params: {
 | 
			
		||||
    maxResponseToken: 4100,
 | 
			
		||||
    temperature: 1,
 | 
			
		||||
    topP: 0.5,
 | 
			
		||||
    presencePenalty: 0.4,
 | 
			
		||||
    frequencyPenalty: 0.4,
 | 
			
		||||
    stop: ''
 | 
			
		||||
  }
 | 
			
		||||
}];
 | 
			
		||||
 | 
			
		||||
const CompletionPanel: FC = observer(() => {
 | 
			
		||||
  const { t } = useTranslation();
 | 
			
		||||
  const inputRef = useRef<HTMLTextAreaElement>(null);
 | 
			
		||||
  const port = commonStore.getCurrentModelConfig().apiParameters.apiPort;
 | 
			
		||||
  const sseControllerRef = useRef<AbortController | null>(null);
 | 
			
		||||
 | 
			
		||||
  const scrollToBottom = () => {
 | 
			
		||||
    if (inputRef.current)
 | 
			
		||||
      inputRef.current.scrollTop = inputRef.current.scrollHeight;
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  useEffect(() => {
 | 
			
		||||
    if (inputRef.current)
 | 
			
		||||
      inputRef.current.style.height = '100%';
 | 
			
		||||
    scrollToBottom();
 | 
			
		||||
  }, []);
 | 
			
		||||
 | 
			
		||||
  if (!commonStore.completionPreset)
 | 
			
		||||
    commonStore.setCompletionPreset(defaultPresets[0]);
 | 
			
		||||
 | 
			
		||||
  const name = commonStore.completionPreset!.name;
 | 
			
		||||
 | 
			
		||||
  const prompt = commonStore.completionPreset!.prompt;
 | 
			
		||||
  const setPrompt = (prompt: string) => {
 | 
			
		||||
    commonStore.setCompletionPreset({
 | 
			
		||||
      ...commonStore.completionPreset!,
 | 
			
		||||
      prompt
 | 
			
		||||
    });
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  const params = commonStore.completionPreset!.params;
 | 
			
		||||
  const setParams = (newParams: Partial<CompletionParams>) => {
 | 
			
		||||
    commonStore.setCompletionPreset({
 | 
			
		||||
      ...commonStore.completionPreset!,
 | 
			
		||||
      params: {
 | 
			
		||||
        ...commonStore.completionPreset!.params,
 | 
			
		||||
        ...newParams
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  const onSubmit = (prompt: string) => {
 | 
			
		||||
    if (commonStore.status.modelStatus === ModelStatus.Offline) {
 | 
			
		||||
      toast(t('Please click the button in the top right corner to start the model'), { type: 'warning' });
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    let answer = '';
 | 
			
		||||
    sseControllerRef.current = new AbortController();
 | 
			
		||||
    fetchEventSource(`http://127.0.0.1:${port}/completions`, // https://api.openai.com/v1/completions || http://127.0.0.1:${port}/completions
 | 
			
		||||
      {
 | 
			
		||||
        method: 'POST',
 | 
			
		||||
        headers: {
 | 
			
		||||
          'Content-Type': 'application/json',
 | 
			
		||||
          Authorization: `Bearer sk-`
 | 
			
		||||
        },
 | 
			
		||||
        body: JSON.stringify({
 | 
			
		||||
          prompt,
 | 
			
		||||
          stream: true,
 | 
			
		||||
          model: 'text-davinci-003',
 | 
			
		||||
          max_tokens: params.maxResponseToken,
 | 
			
		||||
          temperature: params.temperature,
 | 
			
		||||
          top_p: params.topP,
 | 
			
		||||
          presence_penalty: params.presencePenalty,
 | 
			
		||||
          frequency_penalty: params.frequencyPenalty,
 | 
			
		||||
          stop: params.stop || undefined
 | 
			
		||||
        }),
 | 
			
		||||
        signal: sseControllerRef.current?.signal,
 | 
			
		||||
        onmessage(e) {
 | 
			
		||||
          console.log('sse message', e);
 | 
			
		||||
          scrollToBottom();
 | 
			
		||||
          if (e.data === '[DONE]') {
 | 
			
		||||
            commonStore.setCompletionGenerating(false);
 | 
			
		||||
            return;
 | 
			
		||||
          }
 | 
			
		||||
          let data;
 | 
			
		||||
          try {
 | 
			
		||||
            data = JSON.parse(e.data);
 | 
			
		||||
          } catch (error) {
 | 
			
		||||
            console.debug('json error', error);
 | 
			
		||||
            return;
 | 
			
		||||
          }
 | 
			
		||||
          if (data.choices && Array.isArray(data.choices) && data.choices.length > 0) {
 | 
			
		||||
            answer += data.choices[0].text;
 | 
			
		||||
            setPrompt(prompt + answer);
 | 
			
		||||
          }
 | 
			
		||||
        },
 | 
			
		||||
        onclose() {
 | 
			
		||||
          console.log('Connection closed');
 | 
			
		||||
        },
 | 
			
		||||
        onerror(err) {
 | 
			
		||||
          commonStore.setCompletionGenerating(false);
 | 
			
		||||
          throw err;
 | 
			
		||||
        }
 | 
			
		||||
      });
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <div className="flex flex-col sm:flex-row gap-2 overflow-hidden grow">
 | 
			
		||||
      <Textarea
 | 
			
		||||
        ref={inputRef}
 | 
			
		||||
        className="grow"
 | 
			
		||||
        value={prompt}
 | 
			
		||||
        onChange={(e) => setPrompt(e.target.value)}
 | 
			
		||||
      />
 | 
			
		||||
      <div className="flex flex-col gap-1 max-h-48 sm:max-w-sm sm:max-h-full">
 | 
			
		||||
        <Dropdown style={{ minWidth: 0 }}
 | 
			
		||||
          value={t(commonStore.completionPreset!.name)!}
 | 
			
		||||
          selectedOptions={[commonStore.completionPreset!.name]}
 | 
			
		||||
          onOptionSelect={(_, data) => {
 | 
			
		||||
            if (data.optionValue) {
 | 
			
		||||
              commonStore.setCompletionPreset(defaultPresets.find((preset) => preset.name === data.optionValue)!);
 | 
			
		||||
            }
 | 
			
		||||
          }}>
 | 
			
		||||
          {
 | 
			
		||||
            defaultPresets.map((preset) =>
 | 
			
		||||
              <Option key={preset.name} value={preset.name}>{t(preset.name)!}</Option>)
 | 
			
		||||
          }
 | 
			
		||||
        </Dropdown>
 | 
			
		||||
        <div className="flex flex-col gap-1 overflow-x-hidden overflow-y-auto">
 | 
			
		||||
          <Labeled flex breakline label={t('Max Response Token')}
 | 
			
		||||
            desc={t('By default, the maximum number of tokens that can be answered in a single response, it can be changed by the user by specifying API parameters.')}
 | 
			
		||||
            content={
 | 
			
		||||
              <ValuedSlider value={params.maxResponseToken} min={100} max={8100}
 | 
			
		||||
                step={400}
 | 
			
		||||
                input
 | 
			
		||||
                onChange={(e, data) => {
 | 
			
		||||
                  setParams({
 | 
			
		||||
                    maxResponseToken: data.value
 | 
			
		||||
                  });
 | 
			
		||||
                }} />
 | 
			
		||||
            } />
 | 
			
		||||
          <Labeled flex breakline label={t('Temperature')}
 | 
			
		||||
            desc={t('Sampling temperature, the higher the stronger the randomness and creativity, while the lower, the more focused and deterministic it will be.')}
 | 
			
		||||
            content={
 | 
			
		||||
              <ValuedSlider value={params.temperature} min={0} max={2} step={0.1}
 | 
			
		||||
                input
 | 
			
		||||
                onChange={(e, data) => {
 | 
			
		||||
                  setParams({
 | 
			
		||||
                    temperature: data.value
 | 
			
		||||
                  });
 | 
			
		||||
                }} />
 | 
			
		||||
            } />
 | 
			
		||||
          <Labeled flex breakline label={t('Top_P')}
 | 
			
		||||
            desc={t('Consider the results of the top n% probability mass, 0.1 considers the top 10%, with higher quality but more conservative, 1 considers all results, with lower quality but more diverse.')}
 | 
			
		||||
            content={
 | 
			
		||||
              <ValuedSlider value={params.topP} min={0} max={1} step={0.1} input
 | 
			
		||||
                onChange={(e, data) => {
 | 
			
		||||
                  setParams({
 | 
			
		||||
                    topP: data.value
 | 
			
		||||
                  });
 | 
			
		||||
                }} />
 | 
			
		||||
            } />
 | 
			
		||||
          <Labeled flex breakline label={t('Presence Penalty')}
 | 
			
		||||
            desc={t('Positive values penalize new tokens based on whether they appear in the text so far, increasing the model\'s likelihood to talk about new topics.')}
 | 
			
		||||
            content={
 | 
			
		||||
              <ValuedSlider value={params.presencePenalty} min={-2} max={2}
 | 
			
		||||
                step={0.1} input
 | 
			
		||||
                onChange={(e, data) => {
 | 
			
		||||
                  setParams({
 | 
			
		||||
                    presencePenalty: data.value
 | 
			
		||||
                  });
 | 
			
		||||
                }} />
 | 
			
		||||
            } />
 | 
			
		||||
          <Labeled flex breakline label={t('Frequency Penalty')}
 | 
			
		||||
            desc={t('Positive values penalize new tokens based on their existing frequency in the text so far, decreasing the model\'s likelihood to repeat the same line verbatim.')}
 | 
			
		||||
            content={
 | 
			
		||||
              <ValuedSlider value={params.frequencyPenalty} min={-2} max={2}
 | 
			
		||||
                step={0.1} input
 | 
			
		||||
                onChange={(e, data) => {
 | 
			
		||||
                  setParams({
 | 
			
		||||
                    frequencyPenalty: data.value
 | 
			
		||||
                  });
 | 
			
		||||
                }} />
 | 
			
		||||
            } />
 | 
			
		||||
          <Labeled flex breakline label={t('Stop Sequences')}
 | 
			
		||||
            desc={t('When this content appears in the response result, the generation will end.')}
 | 
			
		||||
            content={
 | 
			
		||||
              <Input value={params.stop}
 | 
			
		||||
                onChange={(e, data) => {
 | 
			
		||||
                  setParams({
 | 
			
		||||
                    stop: data.value
 | 
			
		||||
                  });
 | 
			
		||||
                }} />
 | 
			
		||||
            } />
 | 
			
		||||
        </div>
 | 
			
		||||
        <div className="grow" />
 | 
			
		||||
        <div className="flex justify-between gap-2">
 | 
			
		||||
          <Button className="grow" onClick={() => {
 | 
			
		||||
            commonStore.setCompletionPreset(defaultPresets.find((preset) => preset.name === name)!);
 | 
			
		||||
          }}>{t('Reset')}</Button>
 | 
			
		||||
          <Button className="grow" appearance="primary" onClick={() => {
 | 
			
		||||
            if (commonStore.completionGenerating) {
 | 
			
		||||
              sseControllerRef.current?.abort();
 | 
			
		||||
              commonStore.setCompletionGenerating(false);
 | 
			
		||||
            } else {
 | 
			
		||||
              commonStore.setCompletionGenerating(true);
 | 
			
		||||
              onSubmit(prompt);
 | 
			
		||||
            }
 | 
			
		||||
          }}>{!commonStore.completionGenerating ? t('Generate') : t('Stop')}</Button>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
  );
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
export const Completion: FC = observer(() => {
 | 
			
		||||
  return (
 | 
			
		||||
    <div className="flex flex-col gap-1 p-2 h-full overflow-hidden">
 | 
			
		||||
      <WorkHeader />
 | 
			
		||||
      <CompletionPanel />
 | 
			
		||||
    </div>
 | 
			
		||||
  );
 | 
			
		||||
});
 | 
			
		||||
@ -643,7 +643,7 @@ export const Configs: FC = observer(() => {
 | 
			
		||||
                        });
 | 
			
		||||
                      }} />
 | 
			
		||||
                  } />
 | 
			
		||||
                <Labeled label={t('Max Response Token *')}
 | 
			
		||||
                <Labeled label={t('Max Response Token') + ' *'}
 | 
			
		||||
                  desc={t('By default, the maximum number of tokens that can be answered in a single response, it can be changed by the user by specifying API parameters.')}
 | 
			
		||||
                  content={
 | 
			
		||||
                    <ValuedSlider value={selectedConfig.apiParameters.maxResponseToken} min={100} max={8100}
 | 
			
		||||
@ -655,7 +655,7 @@ export const Configs: FC = observer(() => {
 | 
			
		||||
                        });
 | 
			
		||||
                      }} />
 | 
			
		||||
                  } />
 | 
			
		||||
                <Labeled label={t('Temperature *')}
 | 
			
		||||
                <Labeled label={t('Temperature') + ' *'}
 | 
			
		||||
                  desc={t('Sampling temperature, the higher the stronger the randomness and creativity, while the lower, the more focused and deterministic it will be.')}
 | 
			
		||||
                  content={
 | 
			
		||||
                    <ValuedSlider value={selectedConfig.apiParameters.temperature} min={0} max={2} step={0.1}
 | 
			
		||||
@ -666,7 +666,7 @@ export const Configs: FC = observer(() => {
 | 
			
		||||
                        });
 | 
			
		||||
                      }} />
 | 
			
		||||
                  } />
 | 
			
		||||
                <Labeled label={t('Top_P *')}
 | 
			
		||||
                <Labeled label={t('Top_P') + ' *'}
 | 
			
		||||
                  desc={t('Consider the results of the top n% probability mass, 0.1 considers the top 10%, with higher quality but more conservative, 1 considers all results, with lower quality but more diverse.')}
 | 
			
		||||
                  content={
 | 
			
		||||
                    <ValuedSlider value={selectedConfig.apiParameters.topP} min={0} max={1} step={0.1} input
 | 
			
		||||
@ -676,7 +676,7 @@ export const Configs: FC = observer(() => {
 | 
			
		||||
                        });
 | 
			
		||||
                      }} />
 | 
			
		||||
                  } />
 | 
			
		||||
                <Labeled label={t('Presence Penalty *')}
 | 
			
		||||
                <Labeled label={t('Presence Penalty') + ' *'}
 | 
			
		||||
                  desc={t('Positive values penalize new tokens based on whether they appear in the text so far, increasing the model\'s likelihood to talk about new topics.')}
 | 
			
		||||
                  content={
 | 
			
		||||
                    <ValuedSlider value={selectedConfig.apiParameters.presencePenalty} min={-2} max={2}
 | 
			
		||||
@ -687,7 +687,7 @@ export const Configs: FC = observer(() => {
 | 
			
		||||
                        });
 | 
			
		||||
                      }} />
 | 
			
		||||
                  } />
 | 
			
		||||
                <Labeled label={t('Frequency Penalty *')}
 | 
			
		||||
                <Labeled label={t('Frequency Penalty') + ' *'}
 | 
			
		||||
                  desc={t('Positive values penalize new tokens based on their existing frequency in the text so far, decreasing the model\'s likelihood to repeat the same line verbatim.')}
 | 
			
		||||
                  content={
 | 
			
		||||
                    <ValuedSlider value={selectedConfig.apiParameters.frequencyPenalty} min={-2} max={2}
 | 
			
		||||
 | 
			
		||||
@ -3,6 +3,7 @@ import { Configs } from './Configs';
 | 
			
		||||
import {
 | 
			
		||||
  ArrowDownload20Regular,
 | 
			
		||||
  Chat20Regular,
 | 
			
		||||
  ClipboardEdit20Regular,
 | 
			
		||||
  DataUsageSettings20Regular,
 | 
			
		||||
  DocumentSettings20Regular,
 | 
			
		||||
  Home20Regular,
 | 
			
		||||
@ -17,6 +18,7 @@ import { Train } from './Train';
 | 
			
		||||
import { Settings } from './Settings';
 | 
			
		||||
import { About } from './About';
 | 
			
		||||
import { Downloads } from './Downloads';
 | 
			
		||||
import { Completion } from './Completion';
 | 
			
		||||
 | 
			
		||||
type NavigationItem = {
 | 
			
		||||
  label: string;
 | 
			
		||||
@ -41,6 +43,13 @@ export const pages: NavigationItem[] = [
 | 
			
		||||
    element: <Chat />,
 | 
			
		||||
    top: true
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    label: 'Completion',
 | 
			
		||||
    path: '/completion',
 | 
			
		||||
    icon: <ClipboardEdit20Regular />,
 | 
			
		||||
    element: <Completion />,
 | 
			
		||||
    top: true
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    label: 'Configs',
 | 
			
		||||
    path: '/configs',
 | 
			
		||||
 | 
			
		||||
@ -10,6 +10,7 @@ import { SettingsType } from '../pages/Settings';
 | 
			
		||||
import { IntroductionContent } from '../pages/Home';
 | 
			
		||||
import { AboutContent } from '../pages/About';
 | 
			
		||||
import i18n from 'i18next';
 | 
			
		||||
import { CompletionPreset } from '../pages/Completion';
 | 
			
		||||
 | 
			
		||||
export enum ModelStatus {
 | 
			
		||||
  Offline,
 | 
			
		||||
@ -37,6 +38,9 @@ class CommonStore {
 | 
			
		||||
  // chat
 | 
			
		||||
  conversations: Conversations = {};
 | 
			
		||||
  conversationsOrder: string[] = [];
 | 
			
		||||
  // completion
 | 
			
		||||
  completionPreset: CompletionPreset | null = null;
 | 
			
		||||
  completionGenerating: boolean = false;
 | 
			
		||||
  // configs
 | 
			
		||||
  currentModelConfigIndex: number = 0;
 | 
			
		||||
  modelConfigs: ModelConfig[] = [];
 | 
			
		||||
@ -155,6 +159,14 @@ class CommonStore {
 | 
			
		||||
  setConversationsOrder = (value: string[]) => {
 | 
			
		||||
    this.conversationsOrder = value;
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  setCompletionPreset(value: CompletionPreset) {
 | 
			
		||||
    this.completionPreset = value;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  setCompletionGenerating(value: boolean) {
 | 
			
		||||
    this.completionGenerating = value;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default new CommonStore();
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user