mirror of
https://github.com/QuantumNous/new-api.git
synced 2026-04-07 05:43:23 +00:00
Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
69f57728b2 | ||
|
|
7cab9d7c8a | ||
|
|
e5dc21d56b | ||
|
|
713de36ecd | ||
|
|
64e085dc4c | ||
|
|
3622c664b6 |
@@ -5,7 +5,7 @@
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"@douyinfe/semi-icons": "^2.63.1",
|
||||
"@douyinfe/semi-ui": "^2.63.1",
|
||||
"@douyinfe/semi-ui": "^2.69.1",
|
||||
"@visactor/react-vchart": "~1.8.8",
|
||||
"@visactor/vchart": "~1.8.8",
|
||||
"@visactor/vchart-semi-theme": "~1.8.8",
|
||||
|
||||
5166
web/pnpm-lock.yaml
generated
5166
web/pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -24,7 +24,7 @@ import { Layout } from '@douyinfe/semi-ui';
|
||||
import Midjourney from './pages/Midjourney';
|
||||
import Pricing from './pages/Pricing/index.js';
|
||||
import Task from "./pages/Task/index.js";
|
||||
import Playground from './components/Playground.js';
|
||||
import Playground from './pages/Playground/Playground.js';
|
||||
import OAuth2Callback from "./components/OAuth2Callback.js";
|
||||
|
||||
const Home = lazy(() => import('./pages/Home'));
|
||||
|
||||
@@ -9,17 +9,19 @@ import '../index.css';
|
||||
import fireworks from 'react-fireworks';
|
||||
|
||||
import {
|
||||
IconClose,
|
||||
IconHelpCircle,
|
||||
IconHome,
|
||||
IconHomeStroked,
|
||||
IconKey,
|
||||
IconHomeStroked, IconIndentLeft,
|
||||
IconKey, IconMenu,
|
||||
IconNoteMoneyStroked,
|
||||
IconPriceTag,
|
||||
IconUser
|
||||
} from '@douyinfe/semi-icons';
|
||||
import { Avatar, Dropdown, Layout, Nav, Switch } from '@douyinfe/semi-ui';
|
||||
import { Avatar, Button, Dropdown, Layout, Nav, Switch } from '@douyinfe/semi-ui';
|
||||
import { stringToColor } from '../helpers/render';
|
||||
import Text from '@douyinfe/semi-ui/lib/es/typography/text';
|
||||
import { StyleContext } from '../context/Style/index.js';
|
||||
|
||||
// HeaderBar Buttons
|
||||
let headerButtons = [
|
||||
@@ -31,21 +33,6 @@ let headerButtons = [
|
||||
},
|
||||
];
|
||||
|
||||
let buttons = [
|
||||
{
|
||||
text: '首页',
|
||||
itemKey: 'home',
|
||||
to: '/',
|
||||
// icon: <IconHomeStroked />,
|
||||
},
|
||||
// {
|
||||
// text: 'Playground',
|
||||
// itemKey: 'playground',
|
||||
// to: '/playground',
|
||||
// // icon: <IconNoteMoneyStroked />,
|
||||
// },
|
||||
];
|
||||
|
||||
if (localStorage.getItem('chat_link')) {
|
||||
headerButtons.splice(1, 0, {
|
||||
name: '聊天',
|
||||
@@ -56,9 +43,9 @@ if (localStorage.getItem('chat_link')) {
|
||||
|
||||
const HeaderBar = () => {
|
||||
const [userState, userDispatch] = useContext(UserContext);
|
||||
const [styleState, styleDispatch] = useContext(StyleContext);
|
||||
let navigate = useNavigate();
|
||||
|
||||
const [showSidebar, setShowSidebar] = useState(false);
|
||||
const systemName = getSystemName();
|
||||
const logo = getLogo();
|
||||
const currentDate = new Date();
|
||||
@@ -69,8 +56,20 @@ const HeaderBar = () => {
|
||||
currentDate.getDate() >= 9 &&
|
||||
currentDate.getDate() <= 24);
|
||||
|
||||
let buttons = [
|
||||
{
|
||||
text: '首页',
|
||||
itemKey: 'home',
|
||||
to: '/',
|
||||
},
|
||||
{
|
||||
text: '控制台',
|
||||
itemKey: 'detail',
|
||||
to: '/',
|
||||
},
|
||||
];
|
||||
|
||||
async function logout() {
|
||||
setShowSidebar(false);
|
||||
await API.get('/api/user/logout');
|
||||
showSuccess('注销成功!');
|
||||
userDispatch({ type: 'logout' });
|
||||
@@ -108,36 +107,54 @@ const HeaderBar = () => {
|
||||
<div style={{ width: '100%' }}>
|
||||
<Nav
|
||||
mode={'horizontal'}
|
||||
// bodyStyle={{ height: 100 }}
|
||||
renderWrapper={({ itemElement, isSubNav, isInSubNav, props }) => {
|
||||
const routerMap = {
|
||||
about: '/about',
|
||||
login: '/login',
|
||||
register: '/register',
|
||||
detail: '/detail',
|
||||
home: '/',
|
||||
};
|
||||
return (
|
||||
<Link
|
||||
style={{ textDecoration: 'none' }}
|
||||
to={routerMap[props.itemKey]}
|
||||
>
|
||||
{itemElement}
|
||||
</Link>
|
||||
<div onClick={(e) => {
|
||||
if (props.itemKey === 'home') {
|
||||
styleDispatch({ type: 'SET_SIDER', payload: true });
|
||||
} else {
|
||||
styleDispatch({ type: 'SET_SIDER', payload: false });
|
||||
}
|
||||
}}>
|
||||
<Link
|
||||
className="header-bar-text"
|
||||
style={{ textDecoration: 'none' }}
|
||||
to={routerMap[props.itemKey]}
|
||||
>
|
||||
{itemElement}
|
||||
</Link>
|
||||
</div>
|
||||
);
|
||||
}}
|
||||
selectedKeys={[]}
|
||||
// items={headerButtons}
|
||||
onSelect={(key) => {}}
|
||||
header={isMobile()?{
|
||||
header={styleState.isMobile?{
|
||||
logo: (
|
||||
<img src={logo} alt='logo' style={{ marginRight: '0.75em' }} />
|
||||
<>
|
||||
{
|
||||
styleState.showSider ?
|
||||
<Button icon={<IconMenu />} theme="light" aria-label="展开侧边栏" onClick={
|
||||
() => styleDispatch({ type: 'SET_SIDER', payload: false })
|
||||
} />:
|
||||
<Button icon={<IconIndentLeft />} theme="light" aria-label="关闭侧边栏" onClick={
|
||||
() => styleDispatch({ type: 'SET_SIDER', payload: true })
|
||||
} />
|
||||
}
|
||||
</>
|
||||
),
|
||||
}:{
|
||||
logo: (
|
||||
<img src={logo} alt='logo' />
|
||||
),
|
||||
text: systemName,
|
||||
|
||||
}}
|
||||
items={buttons}
|
||||
footer={
|
||||
@@ -159,17 +176,15 @@ const HeaderBar = () => {
|
||||
)}
|
||||
<Nav.Item itemKey={'about'} icon={<IconHelpCircle />} />
|
||||
<>
|
||||
{!isMobile() && (
|
||||
<Switch
|
||||
checkedText='🌞'
|
||||
size={'large'}
|
||||
checked={theme === 'dark'}
|
||||
uncheckedText='🌙'
|
||||
onChange={(checked) => {
|
||||
setTheme(checked);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
<Switch
|
||||
checkedText='🌞'
|
||||
size={'large'}
|
||||
checked={theme === 'dark'}
|
||||
uncheckedText='🌙'
|
||||
onChange={(checked) => {
|
||||
setTheme(checked);
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
{userState.user ? (
|
||||
<>
|
||||
|
||||
40
web/src/components/PageLayout.js
Normal file
40
web/src/components/PageLayout.js
Normal file
@@ -0,0 +1,40 @@
|
||||
import HeaderBar from './HeaderBar.js';
|
||||
import { Layout } from '@douyinfe/semi-ui';
|
||||
import SiderBar from './SiderBar.js';
|
||||
import App from '../App.js';
|
||||
import FooterBar from './Footer.js';
|
||||
import { ToastContainer } from 'react-toastify';
|
||||
import React, { useContext } from 'react';
|
||||
import { StyleContext } from '../context/Style/index.js';
|
||||
const { Sider, Content, Header, Footer } = Layout;
|
||||
|
||||
|
||||
const PageLayout = () => {
|
||||
const [styleState, styleDispatch] = useContext(StyleContext);
|
||||
|
||||
return (
|
||||
<Layout style={{ height: '100vh', display: 'flex', flexDirection: 'column' }}>
|
||||
<Header>
|
||||
<HeaderBar />
|
||||
</Header>
|
||||
<Layout style={{ flex: 1, overflow: 'hidden' }}>
|
||||
<Sider>
|
||||
{styleState.showSider ? null : <SiderBar />}
|
||||
</Sider>
|
||||
<Layout>
|
||||
<Content
|
||||
style={{ overflowY: 'auto', padding: '24px' }}
|
||||
>
|
||||
<App />
|
||||
</Content>
|
||||
<Layout.Footer>
|
||||
<FooterBar></FooterBar>
|
||||
</Layout.Footer>
|
||||
</Layout>
|
||||
</Layout>
|
||||
<ToastContainer />
|
||||
</Layout>
|
||||
)
|
||||
}
|
||||
|
||||
export default PageLayout;
|
||||
@@ -31,14 +31,15 @@ import { Avatar, Dropdown, Layout, Nav, Switch } from '@douyinfe/semi-ui';
|
||||
import { setStatusData } from '../helpers/data.js';
|
||||
import { stringToColor } from '../helpers/render.js';
|
||||
import { useSetTheme, useTheme } from '../context/Theme/index.js';
|
||||
import { StyleContext } from '../context/Style/index.js';
|
||||
|
||||
// HeaderBar Buttons
|
||||
|
||||
const SiderBar = () => {
|
||||
const [userState, userDispatch] = useContext(UserContext);
|
||||
const [styleState, styleDispatch] = useContext(StyleContext);
|
||||
const [statusState, statusDispatch] = useContext(StatusContext);
|
||||
const defaultIsCollapsed =
|
||||
isMobile() || localStorage.getItem('default_collapse_sidebar') === 'true';
|
||||
localStorage.getItem('default_collapse_sidebar') === 'true';
|
||||
|
||||
const [selectedKeys, setSelectedKeys] = useState(['home']);
|
||||
const [isCollapsed, setIsCollapsed] = useState(defaultIsCollapsed);
|
||||
@@ -196,7 +197,6 @@ const SiderBar = () => {
|
||||
useEffect(() => {
|
||||
loadStatus().then(() => {
|
||||
setIsCollapsed(
|
||||
isMobile() ||
|
||||
localStorage.getItem('default_collapse_sidebar') === 'true',
|
||||
);
|
||||
});
|
||||
@@ -239,7 +239,6 @@ const SiderBar = () => {
|
||||
<Nav
|
||||
style={{ maxWidth: 220, height: '100%' }}
|
||||
defaultIsCollapsed={
|
||||
isMobile() ||
|
||||
localStorage.getItem('default_collapse_sidebar') === 'true'
|
||||
}
|
||||
isCollapsed={isCollapsed}
|
||||
@@ -284,17 +283,6 @@ const SiderBar = () => {
|
||||
}}
|
||||
footer={
|
||||
<>
|
||||
{isMobile() && (
|
||||
<Switch
|
||||
checkedText='🌞'
|
||||
size={'small'}
|
||||
checked={theme === 'dark'}
|
||||
uncheckedText='🌙'
|
||||
onChange={(checked) => {
|
||||
setTheme(checked);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
}
|
||||
>
|
||||
|
||||
57
web/src/context/Style/index.js
Normal file
57
web/src/context/Style/index.js
Normal file
@@ -0,0 +1,57 @@
|
||||
// contexts/User/index.jsx
|
||||
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { isMobile } from '../../helpers/index.js';
|
||||
|
||||
export const StyleContext = React.createContext({
|
||||
dispatch: () => null,
|
||||
});
|
||||
|
||||
export const StyleProvider = ({ children }) => {
|
||||
const [state, setState] = useState({
|
||||
isMobile: false,
|
||||
showSider: false,
|
||||
});
|
||||
|
||||
const dispatch = (action) => {
|
||||
if ('type' in action) {
|
||||
switch (action.type) {
|
||||
case 'TOGGLE_SIDER':
|
||||
setState(prev => ({ ...prev, showSider: !prev.showSider }));
|
||||
break;
|
||||
case 'SET_SIDER':
|
||||
setState(prev => ({ ...prev, showSider: action.payload }));
|
||||
break;
|
||||
case 'SET_MOBILE':
|
||||
setState(prev => ({ ...prev, isMobile: action.payload }));
|
||||
break;
|
||||
default:
|
||||
setState(prev => ({ ...prev, ...action }));
|
||||
}
|
||||
} else {
|
||||
setState(prev => ({ ...prev, ...action }));
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const updateIsMobile = () => {
|
||||
dispatch({ type: 'SET_MOBILE', payload: isMobile() });
|
||||
};
|
||||
|
||||
updateIsMobile();
|
||||
|
||||
// Optionally, add event listeners to handle window resize
|
||||
window.addEventListener('resize', updateIsMobile);
|
||||
|
||||
// Cleanup event listener on component unmount
|
||||
return () => {
|
||||
window.removeEventListener('resize', updateIsMobile);
|
||||
};
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<StyleContext.Provider value={[state, dispatch]}>
|
||||
{children}
|
||||
</StyleContext.Provider>
|
||||
);
|
||||
};
|
||||
@@ -17,6 +17,10 @@ body {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
#root > section > header > section > div > div > div > div.semi-navigation-header-list-outer > div.semi-navigation-list-wrapper > ul > div > a > li > span{
|
||||
font-weight: 600 !important;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 767px) {
|
||||
.semi-table-tbody,
|
||||
.semi-table-row,
|
||||
@@ -39,6 +43,10 @@ body {
|
||||
row-gap: 3px;
|
||||
column-gap: 10px;
|
||||
}
|
||||
|
||||
.semi-navigation-horizontal .semi-navigation-header {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.semi-table-tbody > .semi-table-row > .semi-table-row-cell {
|
||||
|
||||
@@ -13,6 +13,8 @@ import { Layout } from '@douyinfe/semi-ui';
|
||||
import SiderBar from './components/SiderBar';
|
||||
import { ThemeProvider } from './context/Theme';
|
||||
import FooterBar from './components/Footer';
|
||||
import { StyleProvider } from './context/Style/index.js';
|
||||
import PageLayout from './components/PageLayout.js';
|
||||
|
||||
// initialization
|
||||
|
||||
@@ -24,27 +26,9 @@ root.render(
|
||||
<UserProvider>
|
||||
<BrowserRouter>
|
||||
<ThemeProvider>
|
||||
<Layout style={{ height: '100vh', display: 'flex', flexDirection: 'column' }}>
|
||||
<Header>
|
||||
<HeaderBar />
|
||||
</Header>
|
||||
<Layout style={{ flex: 1, overflow: 'hidden' }}>
|
||||
<Sider>
|
||||
<SiderBar />
|
||||
</Sider>
|
||||
<Layout>
|
||||
<Content
|
||||
style={{ overflowY: 'auto', padding: '24px' }}
|
||||
>
|
||||
<App />
|
||||
</Content>
|
||||
<Layout.Footer>
|
||||
<FooterBar></FooterBar>
|
||||
</Layout.Footer>
|
||||
</Layout>
|
||||
</Layout>
|
||||
<ToastContainer />
|
||||
</Layout>
|
||||
<StyleProvider>
|
||||
<PageLayout/>
|
||||
</StyleProvider>
|
||||
</ThemeProvider>
|
||||
</BrowserRouter>
|
||||
</UserProvider>
|
||||
|
||||
@@ -3,11 +3,13 @@ import { Card, Col, Row } from '@douyinfe/semi-ui';
|
||||
import { API, showError, showNotice, timestamp2string } from '../../helpers';
|
||||
import { StatusContext } from '../../context/Status';
|
||||
import { marked } from 'marked';
|
||||
import { StyleContext } from '../../context/Style/index.js';
|
||||
|
||||
const Home = () => {
|
||||
const [statusState] = useContext(StatusContext);
|
||||
const [homePageContentLoaded, setHomePageContentLoaded] = useState(false);
|
||||
const [homePageContent, setHomePageContent] = useState('');
|
||||
const [styleState, styleDispatch] = useContext(StyleContext);
|
||||
|
||||
const displayNotice = async () => {
|
||||
const res = await API.get('/api/notice');
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import React, { useCallback, useContext, useEffect, useState } from 'react';
|
||||
import { useNavigate, useSearchParams } from 'react-router-dom';
|
||||
import { UserContext } from '../context/User';
|
||||
import { API, getUserIdFromLocalStorage, showError } from '../helpers';
|
||||
import { Card, Chat, Input, Layout, Select, Slider, TextArea, Typography } from '@douyinfe/semi-ui';
|
||||
import { UserContext } from '../../context/User/index.js';
|
||||
import { API, getUserIdFromLocalStorage, showError } from '../../helpers/index.js';
|
||||
import { Card, Chat, Input, Layout, Select, Slider, TextArea, Typography, Button } from '@douyinfe/semi-ui';
|
||||
import { SSE } from 'sse';
|
||||
import { IconSetting } from '@douyinfe/semi-icons';
|
||||
import { StyleContext } from '../../context/Style/index.js';
|
||||
|
||||
const defaultMessage = [
|
||||
{
|
||||
@@ -54,6 +56,8 @@ const Playground = () => {
|
||||
const [message, setMessage] = useState(defaultMessage);
|
||||
const [models, setModels] = useState([]);
|
||||
const [groups, setGroups] = useState([]);
|
||||
const [showSettings, setShowSettings] = useState(true);
|
||||
const [styleState, styleDispatch] = useContext(StyleContext);
|
||||
|
||||
const handleInputChange = (name, value) => {
|
||||
setInputs((inputs) => ({ ...inputs, [name]: value }));
|
||||
@@ -257,95 +261,141 @@ const Playground = () => {
|
||||
})
|
||||
}, []);
|
||||
|
||||
const SettingsToggle = () => {
|
||||
if (!styleState.isMobile) return null;
|
||||
return (
|
||||
<Button
|
||||
icon={<IconSetting />}
|
||||
style={{
|
||||
position: 'absolute',
|
||||
left: showSettings ? -10 : -20,
|
||||
top: '50%',
|
||||
transform: 'translateY(-50%)',
|
||||
zIndex: 1000,
|
||||
width: 40,
|
||||
height: 40,
|
||||
borderRadius: '0 20px 20px 0',
|
||||
padding: 0,
|
||||
boxShadow: '2px 0 8px rgba(0, 0, 0, 0.15)',
|
||||
}}
|
||||
onClick={() => setShowSettings(!showSettings)}
|
||||
theme="solid"
|
||||
type="primary"
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
function CustomInputRender(props) {
|
||||
const { detailProps } = props;
|
||||
const { clearContextNode, uploadNode, inputNode, sendNode, onClick } = detailProps;
|
||||
|
||||
return <div style={{margin: '8px 16px', display: 'flex', flexDirection:'row',
|
||||
alignItems: 'flex-end', borderRadius: 16,padding: 10, border: '1px solid var(--semi-color-border)'}}
|
||||
onClick={onClick}
|
||||
>
|
||||
{/*{uploadNode}*/}
|
||||
{inputNode}
|
||||
{sendNode}
|
||||
</div>
|
||||
}
|
||||
|
||||
const renderInputArea = useCallback((props) => {
|
||||
return (<CustomInputRender {...props} />)
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Layout style={{height: '100%'}}>
|
||||
<Layout.Sider>
|
||||
<Card style={commonOuterStyle}>
|
||||
<div style={{ marginTop: 10 }}>
|
||||
<Typography.Text strong>分组:</Typography.Text>
|
||||
</div>
|
||||
<Select
|
||||
placeholder={'请选择分组'}
|
||||
name='group'
|
||||
required
|
||||
selection
|
||||
onChange={(value) => {
|
||||
handleInputChange('group', value);
|
||||
}}
|
||||
value={inputs.group}
|
||||
autoComplete='new-password'
|
||||
optionList={groups}
|
||||
/>
|
||||
<div style={{ marginTop: 10 }}>
|
||||
<Typography.Text strong>模型:</Typography.Text>
|
||||
</div>
|
||||
<Select
|
||||
placeholder={'请选择模型'}
|
||||
name='model'
|
||||
required
|
||||
selection
|
||||
searchPosition='dropdown'
|
||||
filter
|
||||
onChange={(value) => {
|
||||
handleInputChange('model', value);
|
||||
}}
|
||||
value={inputs.model}
|
||||
autoComplete='new-password'
|
||||
optionList={models}
|
||||
/>
|
||||
<div style={{ marginTop: 10 }}>
|
||||
<Typography.Text strong>Temperature:</Typography.Text>
|
||||
</div>
|
||||
<Slider
|
||||
step={0.1}
|
||||
min={0.1}
|
||||
max={1}
|
||||
value={inputs.temperature}
|
||||
onChange={(value) => {
|
||||
handleInputChange('temperature', value);
|
||||
}}
|
||||
/>
|
||||
<div style={{ marginTop: 10 }}>
|
||||
<Typography.Text strong>MaxTokens:</Typography.Text>
|
||||
</div>
|
||||
<Input
|
||||
placeholder='MaxTokens'
|
||||
name='max_tokens'
|
||||
required
|
||||
autoComplete='new-password'
|
||||
defaultValue={0}
|
||||
value={inputs.max_tokens}
|
||||
onChange={(value) => {
|
||||
handleInputChange('max_tokens', value);
|
||||
}}
|
||||
/>
|
||||
{(showSettings || !styleState.isMobile) && (
|
||||
<Layout.Sider style={{ display: styleState.isMobile ? 'block' : 'initial' }}>
|
||||
<Card style={commonOuterStyle}>
|
||||
<div style={{ marginTop: 10 }}>
|
||||
<Typography.Text strong>分组:</Typography.Text>
|
||||
</div>
|
||||
<Select
|
||||
placeholder={'请选择分组'}
|
||||
name='group'
|
||||
required
|
||||
selection
|
||||
onChange={(value) => {
|
||||
handleInputChange('group', value);
|
||||
}}
|
||||
value={inputs.group}
|
||||
autoComplete='new-password'
|
||||
optionList={groups}
|
||||
/>
|
||||
<div style={{ marginTop: 10 }}>
|
||||
<Typography.Text strong>模型:</Typography.Text>
|
||||
</div>
|
||||
<Select
|
||||
placeholder={'请选择模型'}
|
||||
name='model'
|
||||
required
|
||||
selection
|
||||
searchPosition='dropdown'
|
||||
filter
|
||||
onChange={(value) => {
|
||||
handleInputChange('model', value);
|
||||
}}
|
||||
value={inputs.model}
|
||||
autoComplete='new-password'
|
||||
optionList={models}
|
||||
/>
|
||||
<div style={{ marginTop: 10 }}>
|
||||
<Typography.Text strong>Temperature:</Typography.Text>
|
||||
</div>
|
||||
<Slider
|
||||
step={0.1}
|
||||
min={0.1}
|
||||
max={1}
|
||||
value={inputs.temperature}
|
||||
onChange={(value) => {
|
||||
handleInputChange('temperature', value);
|
||||
}}
|
||||
/>
|
||||
<div style={{ marginTop: 10 }}>
|
||||
<Typography.Text strong>MaxTokens:</Typography.Text>
|
||||
</div>
|
||||
<Input
|
||||
placeholder='MaxTokens'
|
||||
name='max_tokens'
|
||||
required
|
||||
autoComplete='new-password'
|
||||
defaultValue={0}
|
||||
value={inputs.max_tokens}
|
||||
onChange={(value) => {
|
||||
handleInputChange('max_tokens', value);
|
||||
}}
|
||||
/>
|
||||
|
||||
<div style={{ marginTop: 10 }}>
|
||||
<Typography.Text strong>System:</Typography.Text>
|
||||
</div>
|
||||
<TextArea
|
||||
placeholder='System Prompt'
|
||||
name='system'
|
||||
required
|
||||
autoComplete='new-password'
|
||||
autosize
|
||||
defaultValue={systemPrompt}
|
||||
// value={systemPrompt}
|
||||
onChange={(value) => {
|
||||
setSystemPrompt(value);
|
||||
}}
|
||||
/>
|
||||
<div style={{ marginTop: 10 }}>
|
||||
<Typography.Text strong>System:</Typography.Text>
|
||||
</div>
|
||||
<TextArea
|
||||
placeholder='System Prompt'
|
||||
name='system'
|
||||
required
|
||||
autoComplete='new-password'
|
||||
autosize
|
||||
defaultValue={systemPrompt}
|
||||
// value={systemPrompt}
|
||||
onChange={(value) => {
|
||||
setSystemPrompt(value);
|
||||
}}
|
||||
/>
|
||||
|
||||
</Card>
|
||||
</Layout.Sider>
|
||||
</Card>
|
||||
</Layout.Sider>
|
||||
)}
|
||||
<Layout.Content>
|
||||
<div style={{height: '100%'}}>
|
||||
<div style={{height: '100%', position: 'relative'}}>
|
||||
<SettingsToggle />
|
||||
<Chat
|
||||
chatBoxRenderConfig={{
|
||||
renderChatBoxAction: () => {
|
||||
return <div></div>
|
||||
}
|
||||
}}
|
||||
renderInputArea={renderInputArea}
|
||||
roleConfig={roleInfo}
|
||||
style={commonOuterStyle}
|
||||
chats={message}
|
||||
@@ -7,7 +7,7 @@ import {
|
||||
showError,
|
||||
showSuccess,
|
||||
} from '../../helpers';
|
||||
import { renderQuotaWithPrompt } from '../../helpers/render';
|
||||
import { getQuotaPerUnit, renderQuota, renderQuotaWithPrompt } from '../../helpers/render';
|
||||
import {
|
||||
AutoComplete,
|
||||
Button,
|
||||
@@ -66,11 +66,16 @@ const EditRedemption = (props) => {
|
||||
}, [props.editingRedemption.id]);
|
||||
|
||||
const submit = async () => {
|
||||
if (!isEdit && inputs.name === '') return;
|
||||
let name = inputs.name;
|
||||
if (!isEdit && inputs.name === '') {
|
||||
// set default name
|
||||
name = '兑换码-' + renderQuota(quota);
|
||||
}
|
||||
setLoading(true);
|
||||
let localInputs = inputs;
|
||||
localInputs.count = parseInt(localInputs.count);
|
||||
localInputs.quota = parseInt(localInputs.quota);
|
||||
localInputs.name = name;
|
||||
let res;
|
||||
if (isEdit) {
|
||||
res = await API.put(`/api/redemption/`, {
|
||||
|
||||
Reference in New Issue
Block a user