feat: add temperature and top-p to ModelSetting and add ChatConfigurationModal and bind backend data to KnowledgeCard (#65)

* feat: bind backend data to KnowledgeCard

* feat: add ChatConfigurationModal

* feat: add temperature and top-p to ModelSetting
This commit is contained in:
balibabu 2024-02-19 19:16:23 +08:00 committed by GitHub
parent f3d0ebd293
commit 452020d33a
19 changed files with 890 additions and 10 deletions

81
web/package-lock.json generated
View File

@ -18,16 +18,19 @@
"lodash": "^4.17.21",
"moment": "^2.30.1",
"rc-tween-one": "^3.0.6",
"react-chat-elements": "^12.0.13",
"react-i18next": "^14.0.0",
"react-infinite-scroll-component": "^6.1.0",
"umi": "^4.0.90",
"umi-request": "^1.4.0"
"umi-request": "^1.4.0",
"uuid": "^9.0.1"
},
"devDependencies": {
"@react-dev-inspector/umi4-plugin": "^2.0.1",
"@types/lodash": "^4.14.202",
"@types/react": "^18.0.33",
"@types/react-dom": "^18.0.11",
"@types/uuid": "^9.0.8",
"@umijs/lint": "^4.1.1",
"@umijs/plugins": "^4.1.0",
"cross-env": "^7.0.3",
@ -2929,6 +2932,12 @@
"integrity": "sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA==",
"dev": true
},
"node_modules/@types/uuid": {
"version": "9.0.8",
"resolved": "https://registry.npmmirror.com/@types/uuid/-/uuid-9.0.8.tgz",
"integrity": "sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA==",
"dev": true
},
"node_modules/@types/yargs": {
"version": "16.0.9",
"resolved": "https://registry.npmmirror.com/@types/yargs/-/yargs-16.0.9.tgz",
@ -10669,6 +10678,11 @@
"node": ">=8.9.0"
}
},
"node_modules/loaders.css": {
"version": "0.1.2",
"resolved": "https://registry.npmmirror.com/loaders.css/-/loaders.css-0.1.2.tgz",
"integrity": "sha512-Rhowlq24ey1VOeor+3wYOt9+MjaxBOJm1u4KlQgNC3+0xJ0LS4wq4iG57D/BPzvuD/7HHDGQOWJ+81oR2EI9bQ=="
},
"node_modules/local-pkg": {
"version": "0.4.3",
"resolved": "https://registry.npmmirror.com/local-pkg/-/local-pkg-0.4.3.tgz",
@ -12666,6 +12680,15 @@
"resolved": "https://registry.npmmirror.com/process-warning/-/process-warning-1.0.0.tgz",
"integrity": "sha512-du4wfLyj4yCZq1VupnVSZmRsPJsNuxoDQFdCFHLaYiEbFBD7QE0a+I4D7hOxrVnh78QE/YipFAj9lXHiXocV+Q=="
},
"node_modules/progressbar.js": {
"version": "1.1.1",
"resolved": "https://registry.npmmirror.com/progressbar.js/-/progressbar.js-1.1.1.tgz",
"integrity": "sha512-FBsw3BKsUbb+hNeYfiP3xzvAAQrPi4DnGDw66bCmfuRCDLcslxyxv2GyYUdBSKFGSIBa73CUP5WMcl6F8AAXlw==",
"dependencies": {
"lodash.merge": "^4.6.2",
"shifty": "^2.8.3"
}
},
"node_modules/prompts": {
"version": "2.4.2",
"resolved": "https://registry.npmmirror.com/prompts/-/prompts-2.4.2.tgz",
@ -13446,6 +13469,22 @@
"node": ">=0.10.0"
}
},
"node_modules/react-chat-elements": {
"version": "12.0.13",
"resolved": "https://registry.npmmirror.com/react-chat-elements/-/react-chat-elements-12.0.13.tgz",
"integrity": "sha512-Vu5x8kW4LPu8onKfz5vsuDwZsDhoQmTBHJdqKAhVsi42PCQ8KOfzHiDp0fPUJlinJZ/MTJTm69UAchpys4iSTQ==",
"dependencies": {
"classnames": "^2.2.5",
"progressbar.js": "^1.1.0",
"react-icons": "^4.3.1",
"react-spinkit": "^3.0.0",
"timeago.js": "^4.0.2"
},
"peerDependencies": {
"react": "^18.2.0",
"react-dom": "18.2.0"
}
},
"node_modules/react-dev-inspector": {
"version": "2.0.1",
"resolved": "https://registry.npmmirror.com/react-dev-inspector/-/react-dev-inspector-2.0.1.tgz",
@ -13784,6 +13823,14 @@
}
}
},
"node_modules/react-icons": {
"version": "4.12.0",
"resolved": "https://registry.npmmirror.com/react-icons/-/react-icons-4.12.0.tgz",
"integrity": "sha512-IBaDuHiShdZqmfc/TwHu6+d6k2ltNCf3AszxNmjJc1KUfXdEeRJOKyNvLmAHaarhzGmTSVygNdyu8/opXv2gaw==",
"peerDependencies": {
"react": "*"
}
},
"node_modules/react-infinite-scroll-component": {
"version": "6.1.0",
"resolved": "https://registry.npmmirror.com/react-infinite-scroll-component/-/react-infinite-scroll-component-6.1.0.tgz",
@ -13924,6 +13971,17 @@
"react": ">=15"
}
},
"node_modules/react-spinkit": {
"version": "3.0.0",
"resolved": "https://registry.npmmirror.com/react-spinkit/-/react-spinkit-3.0.0.tgz",
"integrity": "sha512-RrfGRPjqxHQiy7quPqhjPynTu0zobgQaZu1QYBMpJJ6pCSRRRK16EZMaxdE6fLVYFRJWpX/eGATWLMoVFFT5uQ==",
"dependencies": {
"classnames": "^2.2.3",
"loaders.css": "^0.1.2",
"object-assign": "^4.1.0",
"prop-types": "^15.5.8"
}
},
"node_modules/reactcss": {
"version": "1.2.3",
"resolved": "https://registry.npmmirror.com/reactcss/-/reactcss-1.2.3.tgz",
@ -14633,6 +14691,14 @@
"integrity": "sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==",
"dev": true
},
"node_modules/shifty": {
"version": "2.20.4",
"resolved": "https://registry.npmmirror.com/shifty/-/shifty-2.20.4.tgz",
"integrity": "sha512-4Y0qRkg8ME5XN8yGNAwmFOmsIURGFKT9UQfNL6DDJQErYtN5HsjyoBuJn41ZQfTkuu2rIbRMn9qazjKsDpO2TA==",
"optionalDependencies": {
"fsevents": "^2.3.2"
}
},
"node_modules/side-channel": {
"version": "1.0.4",
"resolved": "https://registry.npmmirror.com/side-channel/-/side-channel-1.0.4.tgz",
@ -15783,6 +15849,11 @@
"node": ">=12.22"
}
},
"node_modules/timeago.js": {
"version": "4.0.2",
"resolved": "https://registry.npmmirror.com/timeago.js/-/timeago.js-4.0.2.tgz",
"integrity": "sha512-a7wPxPdVlQL7lqvitHGGRsofhdwtkoSXPGATFuSOA2i1ZNQEPLrGnj68vOp2sOJTCFAQVXPeNMX/GctBaO9L2w=="
},
"node_modules/timers-browserify": {
"version": "2.0.12",
"resolved": "https://registry.npmmirror.com/timers-browserify/-/timers-browserify-2.0.12.tgz",
@ -16859,6 +16930,14 @@
"resolved": "https://registry.npmmirror.com/utila/-/utila-0.4.0.tgz",
"integrity": "sha512-Z0DbgELS9/L/75wZbro8xAnT50pBVFQZ+hUEueGDU5FN51YSCYM+jdxsfCiHjwNP/4LCDD0i/graKpeBnOXKRA=="
},
"node_modules/uuid": {
"version": "9.0.1",
"resolved": "https://registry.npmmirror.com/uuid/-/uuid-9.0.1.tgz",
"integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==",
"bin": {
"uuid": "dist/bin/uuid"
}
},
"node_modules/v8-compile-cache": {
"version": "2.4.0",
"resolved": "https://registry.npmmirror.com/v8-compile-cache/-/v8-compile-cache-2.4.0.tgz",

View File

@ -22,16 +22,19 @@
"lodash": "^4.17.21",
"moment": "^2.30.1",
"rc-tween-one": "^3.0.6",
"react-chat-elements": "^12.0.13",
"react-i18next": "^14.0.0",
"react-infinite-scroll-component": "^6.1.0",
"umi": "^4.0.90",
"umi-request": "^1.4.0"
"umi-request": "^1.4.0",
"uuid": "^9.0.1"
},
"devDependencies": {
"@react-dev-inspector/umi4-plugin": "^2.0.1",
"@types/lodash": "^4.14.202",
"@types/react": "^18.0.33",
"@types/react-dom": "^18.0.11",
"@types/uuid": "^9.0.8",
"@umijs/lint": "^4.1.1",
"@umijs/plugins": "^4.1.0",
"cross-env": "^7.0.3",

View File

@ -0,0 +1,24 @@
<svg width="52" height="52" viewBox="0 0 52 52" fill="none" xmlns="http://www.w3.org/2000/svg">
<g filter="url(#filter0_d_550_8026)">
<path
d="M2.5 11C2.5 5.75329 6.75329 1.5 12 1.5H40C45.2467 1.5 49.5 5.75329 49.5 11V39C49.5 44.2467 45.2467 48.5 40 48.5H12C6.75329 48.5 2.5 44.2467 2.5 39V11Z"
stroke="#EAECF0" shape-rendering="crispEdges" />
<path
d="M25.9995 24.9997H26.0095M29.535 28.5352C24.8488 33.2215 19.4669 35.4376 17.5142 33.4849C15.5616 31.5323 17.7777 26.1504 22.464 21.4641C27.1503 16.7778 32.5322 14.5618 34.4848 16.5144C36.4374 18.467 34.2213 23.8489 29.535 28.5352ZM29.535 21.4639C34.2213 26.1502 36.4374 31.5321 34.4848 33.4848C32.5321 35.4374 27.1502 33.2213 22.4639 28.535C17.7776 23.8487 15.5616 18.4668 17.5142 16.5142C19.4668 14.5616 24.8487 16.7776 29.535 21.4639ZM26.4995 24.9997C26.4995 25.2758 26.2757 25.4997 25.9995 25.4997C25.7234 25.4997 25.4995 25.2758 25.4995 24.9997C25.4995 24.7235 25.7234 24.4997 25.9995 24.4997C26.2757 24.4997 26.4995 24.7235 26.4995 24.9997Z"
stroke="#344054" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
</g>
<defs>
<filter id="filter0_d_550_8026" x="0" y="0" width="52" height="52" filterUnits="userSpaceOnUse"
color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix" />
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"
result="hardAlpha" />
<feOffset dy="1" />
<feGaussianBlur stdDeviation="1" />
<feComposite in2="hardAlpha" operator="out" />
<feColorMatrix type="matrix" values="0 0 0 0 0.0627451 0 0 0 0 0.0941176 0 0 0 0 0.156863 0 0 0 0.05 0" />
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_550_8026" />
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_550_8026" result="shape" />
</filter>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@ -19,9 +19,9 @@
.appName {
vertical-align: middle;
font-family: Inter;
font-size: 14px;
font-size: 16px;
font-style: normal;
font-weight: 400;
font-weight: 600;
line-height: 20px;
}

View File

@ -68,7 +68,7 @@ const Configuration = () => {
const fileList = values.avatar;
let avatar;
if (Array.isArray(fileList)) {
if (Array.isArray(fileList) && fileList.length > 0) {
avatar = fileList[0].thumbUrl;
}

View File

@ -0,0 +1,35 @@
import { Form, Input } from 'antd';
import classNames from 'classnames';
import { ISegmentedContentProps } from './interface';
import styles from './index.less';
const AssistantSetting = ({ show }: ISegmentedContentProps) => {
return (
<section
className={classNames({
[styles.segmentedHidden]: !show,
})}
>
<Form.Item
name={'name'}
label="Assistant name"
rules={[{ required: true }]}
>
<Input placeholder="e.g. Resume Jarvis" />
</Form.Item>
<Form.Item name={'avatar'} label="Assistant avatar">
<Input />
</Form.Item>
<Form.Item name={'keywords'} label="Keywords">
<Input.TextArea autoSize={{ minRows: 3 }} />
</Form.Item>
<Form.Item name={'opener'} label="Set an opener">
<Input.TextArea autoSize={{ minRows: 5 }} />
</Form.Item>
</section>
);
};
export default AssistantSetting;

View File

@ -0,0 +1,103 @@
import { Form, FormInstance, Input, InputRef } from 'antd';
import React, { useContext, useEffect, useRef, useState } from 'react';
const EditableContext = React.createContext<FormInstance<any> | null>(null);
interface EditableRowProps {
index: number;
}
interface Item {
key: string;
name: string;
age: string;
address: string;
}
export const EditableRow: React.FC<EditableRowProps> = ({
index,
...props
}) => {
const [form] = Form.useForm();
return (
<Form form={form} component={false}>
<EditableContext.Provider value={form}>
<tr {...props} />
</EditableContext.Provider>
</Form>
);
};
interface EditableCellProps {
title: React.ReactNode;
editable: boolean;
children: React.ReactNode;
dataIndex: keyof Item;
record: Item;
handleSave: (record: Item) => void;
}
export const EditableCell: React.FC<EditableCellProps> = ({
title,
editable,
children,
dataIndex,
record,
handleSave,
...restProps
}) => {
const [editing, setEditing] = useState(false);
const inputRef = useRef<InputRef>(null);
const form = useContext(EditableContext)!;
useEffect(() => {
if (editing) {
inputRef.current!.focus();
}
}, [editing]);
const toggleEdit = () => {
setEditing(!editing);
form.setFieldsValue({ [dataIndex]: record[dataIndex] });
};
const save = async () => {
try {
const values = await form.validateFields();
toggleEdit();
handleSave({ ...record, ...values });
} catch (errInfo) {
console.log('Save failed:', errInfo);
}
};
let childNode = children;
if (editable) {
childNode = editing ? (
<Form.Item
style={{ margin: 0 }}
name={dataIndex}
rules={[
{
required: true,
message: `${title} is required.`,
},
]}
>
<Input ref={inputRef} onPressEnter={save} onBlur={save} />
</Form.Item>
) : (
<div
className="editable-cell-value-wrap"
style={{ paddingRight: 24 }}
onClick={toggleEdit}
>
{children}
</div>
);
}
return <td {...restProps}>{childNode}</td>;
};

View File

@ -0,0 +1,43 @@
.chatConfigurationDescription {
font-size: 14px;
}
.variableContainer {
padding-bottom: 20px;
.variableAlign {
text-align: right;
}
.variableLabel {
margin-right: 16px;
}
.variableTable {
margin-top: 14px;
}
.editableRow {
:global(.editable-cell) {
position: relative;
}
:global(.editable-cell-value-wrap) {
padding: 5px 12px;
cursor: pointer;
height: 22px !important;
}
&:hover {
:global(.editable-cell-value-wrap) {
padding: 4px 11px;
border: 1px solid #d9d9d9;
border-radius: 2px;
}
}
}
}
.segmentedHidden {
opacity: 0;
height: 0;
width: 0;
margin: 0;
}

View File

@ -0,0 +1,107 @@
import { ReactComponent as ChatConfigurationAtom } from '@/assets/svg/chat-configuration-atom.svg';
import { IModalManagerChildrenProps } from '@/components/modal-manager';
import { Divider, Flex, Form, Modal, Segmented } from 'antd';
import { SegmentedValue } from 'antd/es/segmented';
import { useState } from 'react';
import AssistantSetting from './assistant-setting';
import ModelSetting from './model-setting';
import PromptEngine from './prompt-engine';
import styles from './index.less';
enum ConfigurationSegmented {
AssistantSetting = 'Assistant Setting',
ModelSetting = 'Model Setting',
PromptEngine = 'Prompt Engine',
}
const segmentedMap = {
[ConfigurationSegmented.AssistantSetting]: AssistantSetting,
[ConfigurationSegmented.ModelSetting]: ModelSetting,
[ConfigurationSegmented.PromptEngine]: PromptEngine,
};
const layout = {
labelCol: { span: 6 },
wrapperCol: { span: 18 },
};
const validateMessages = {
required: '${label} is required!',
types: {
email: '${label} is not a valid email!',
number: '${label} is not a valid number!',
},
number: {
range: '${label} must be between ${min} and ${max}',
},
};
const ChatConfigurationModal = ({
visible,
hideModal,
}: IModalManagerChildrenProps) => {
const [form] = Form.useForm();
const [value, setValue] = useState<ConfigurationSegmented>(
ConfigurationSegmented.AssistantSetting,
);
const handleOk = async () => {
const x = await form.validateFields();
console.info(x);
};
const handleCancel = () => {
hideModal();
};
const handleSegmentedChange = (val: SegmentedValue) => {
setValue(val as ConfigurationSegmented);
};
const title = (
<Flex gap={16}>
<ChatConfigurationAtom></ChatConfigurationAtom>
<div>
<b>Chat Configuration</b>
<div className={styles.chatConfigurationDescription}>
Here, dress up a dedicated assistant for your special knowledge bases!
💕
</div>
</div>
</Flex>
);
return (
<Modal
title={title}
width={688}
open={visible}
onOk={handleOk}
onCancel={handleCancel}
>
<Segmented
size={'large'}
value={value}
onChange={handleSegmentedChange}
options={Object.values(ConfigurationSegmented)}
block
/>
<Divider></Divider>
<Form
{...layout}
name="nest-messages"
form={form}
style={{ maxWidth: 600 }}
validateMessages={validateMessages}
colon={false}
>
{Object.entries(segmentedMap).map(([key, Element]) => (
<Element key={key} show={key === value}></Element>
))}
</Form>
</Modal>
);
};
export default ChatConfigurationModal;

View File

@ -0,0 +1,3 @@
export interface ISegmentedContentProps {
show: boolean;
}

View File

@ -0,0 +1,155 @@
import { Divider, Flex, Form, InputNumber, Select, Slider } from 'antd';
import classNames from 'classnames';
import { ISegmentedContentProps } from './interface';
import styles from './index.less';
const { Option } = Select;
const ModelSetting = ({ show }: ISegmentedContentProps) => {
return (
<section
className={classNames({
[styles.segmentedHidden]: !show,
})}
>
<Form.Item
label="Model"
name="model"
// rules={[{ required: true, message: 'Please input!' }]}
>
<Select />
</Form.Item>
<Divider></Divider>
<Form.Item
label="Parameters"
name="parameters"
// rules={[{ required: true, message: 'Please input!' }]}
>
<Select />
</Form.Item>
<Form.Item label="Temperature">
<Flex gap={20}>
<Flex flex={1}>
<Form.Item
name={['address', 'province']}
noStyle
rules={[{ required: true, message: 'Province is required' }]}
>
<Slider style={{ display: 'inline-block', width: '100%' }} />
</Form.Item>
</Flex>
<Form.Item
name={['address', 'street']}
noStyle
rules={[{ required: true, message: 'Street is required' }]}
>
<InputNumber
style={{
width: 50,
}}
/>
</Form.Item>
</Flex>
</Form.Item>
<Form.Item label="Top P">
<Flex gap={20}>
<Flex flex={1}>
<Form.Item
name={['address', 'province']}
noStyle
rules={[{ required: true, message: 'Province is required' }]}
>
<Slider style={{ display: 'inline-block', width: '100%' }} />
</Form.Item>
</Flex>
<Form.Item
name={['address', 'street']}
noStyle
rules={[{ required: true, message: 'Street is required' }]}
>
<InputNumber
style={{
width: 50,
}}
/>
</Form.Item>
</Flex>
</Form.Item>
<Form.Item label="Presence Penalty">
<Flex gap={20}>
<Flex flex={1}>
<Form.Item
name={['address', 'province']}
noStyle
rules={[{ required: true, message: 'Province is required' }]}
>
<Slider style={{ display: 'inline-block', width: '100%' }} />
</Form.Item>
</Flex>
<Form.Item
name={['address', 'street']}
noStyle
rules={[{ required: true, message: 'Street is required' }]}
>
<InputNumber
style={{
width: 50,
}}
/>
</Form.Item>
</Flex>
</Form.Item>
<Form.Item label="Frequency Penalty">
<Flex gap={20}>
<Flex flex={1}>
<Form.Item
name={['address', 'province']}
noStyle
rules={[{ required: true, message: 'Province is required' }]}
>
<Slider style={{ display: 'inline-block', width: '100%' }} />
</Form.Item>
</Flex>
<Form.Item
name={['address', 'street']}
noStyle
rules={[{ required: true, message: 'Street is required' }]}
>
<InputNumber
style={{
width: 50,
}}
/>
</Form.Item>
</Flex>
</Form.Item>
<Form.Item label="Max Tokens">
<Flex gap={20}>
<Flex flex={1}>
<Form.Item
name={['address', 'province']}
noStyle
rules={[{ required: true, message: 'Province is required' }]}
>
<Slider style={{ display: 'inline-block', width: '100%' }} />
</Form.Item>
</Flex>
<Form.Item
name={['address', 'street']}
noStyle
rules={[{ required: true, message: 'Street is required' }]}
>
<InputNumber
style={{
width: 50,
}}
/>
</Form.Item>
</Flex>
</Form.Item>
</section>
);
};
export default ModelSetting;

View File

@ -0,0 +1,163 @@
import { DeleteOutlined } from '@ant-design/icons';
import {
Button,
Col,
Divider,
Form,
Input,
Row,
Select,
Switch,
Table,
TableProps,
} from 'antd';
import classNames from 'classnames';
import { useState } from 'react';
import { v4 as uuid } from 'uuid';
import { EditableCell, EditableRow } from './editable-cell';
import { ISegmentedContentProps } from './interface';
import styles from './index.less';
interface DataType {
key: string;
optional: boolean;
}
const { Option } = Select;
const PromptEngine = ({ show }: ISegmentedContentProps) => {
const [dataSource, setDataSource] = useState<DataType[]>([]);
const components = {
body: {
row: EditableRow,
cell: EditableCell,
},
};
const handleRemove = (key: string) => () => {
const newData = dataSource.filter((item) => item.key !== key);
setDataSource(newData);
};
const handleSave = (row: DataType) => {
const newData = [...dataSource];
const index = newData.findIndex((item) => row.key === item.key);
const item = newData[index];
newData.splice(index, 1, {
...item,
...row,
});
setDataSource(newData);
};
const columns: TableProps<DataType>['columns'] = [
{
title: 'key',
dataIndex: 'variable',
key: 'variable',
onCell: (record: DataType) => ({
record,
editable: true,
dataIndex: 'variable',
title: 'key',
handleSave,
}),
},
{
title: 'optional',
dataIndex: 'optional',
key: 'optional',
width: 40,
align: 'center',
render() {
return <Switch size="small" />;
},
},
{
title: 'operation',
dataIndex: 'operation',
width: 30,
key: 'operation',
align: 'center',
render(_, record) {
return <DeleteOutlined onClick={handleRemove(record.key)} />;
},
},
];
const handleAdd = () => {
setDataSource((state) => [
...state,
{
key: uuid(),
variable: '',
optional: true,
},
]);
};
return (
<section
className={classNames({
[styles.segmentedHidden]: !show,
})}
>
<Form.Item
label="Orchestrate"
name="orchestrate"
rules={[{ required: true, message: 'Please input!' }]}
>
<Input.TextArea autoSize={{ maxRows: 5, minRows: 5 }} />
</Form.Item>
<Divider></Divider>
<section className={classNames(styles.variableContainer)}>
<Row align={'middle'} justify="end">
<Col span={6} className={styles.variableAlign}>
<label className={styles.variableLabel}>Variables</label>
</Col>
<Col span={18} className={styles.variableAlign}>
<Button size="small" onClick={handleAdd}>
Add
</Button>
</Col>
</Row>
{dataSource.length > 0 && (
<Row>
<Col span={6}></Col>
<Col span={18}>
<Table
dataSource={dataSource}
columns={columns}
rowKey={'key'}
className={styles.variableTable}
components={components}
rowClassName={() => styles.editableRow}
/>
</Col>
</Row>
)}
</section>
<Form.Item
label="Select one context"
name="context"
rules={[
{
required: true,
message: 'Please select your favourite colors!',
type: 'array',
},
]}
>
<Select mode="multiple" placeholder="Please select favourite colors">
<Option value="red">Red</Option>
<Option value="green">Green</Option>
<Option value="blue">Blue</Option>
</Select>
</Form.Item>
</section>
);
};
export default PromptEngine;

View File

@ -0,0 +1,3 @@
.chatContainer {
padding: 0 24px 24px;
}

View File

@ -0,0 +1,36 @@
import { Button, Flex, Input } from 'antd';
import { ChangeEventHandler, useState } from 'react';
import styles from './index.less';
const ChatContainer = () => {
const [value, setValue] = useState('');
const handlePressEnter = () => {
console.info(value);
};
const handleInputChange: ChangeEventHandler<HTMLInputElement> = (e) => {
setValue(e.target.value);
};
return (
<Flex flex={1} className={styles.chatContainer} vertical>
<Flex flex={1}>xx</Flex>
<Input
size="large"
placeholder="Message Resume Assistant..."
value={value}
suffix={
<Button type="primary" onClick={handlePressEnter}>
Send
</Button>
}
onPressEnter={handlePressEnter}
onChange={handleInputChange}
/>
</Flex>
);
};
export default ChatContainer;

View File

@ -0,0 +1,25 @@
.chatWrapper {
height: 100%;
.chatAppWrapper {
width: 288px;
padding: 26px;
}
.chatTitleWrapper {
width: 220px;
padding: 26px 0;
}
.chatTitle {
padding: 5px 15px;
}
.chatTitleContent {
padding: 5px 10px;
}
.divider {
margin: 0;
height: 100%;
}
}

View File

@ -1,8 +1,64 @@
import { FormOutlined } from '@ant-design/icons';
import { Button, Card, Divider, Flex, Space, Tag } from 'antd';
import { useSelector } from 'umi';
import ChatContainer from './chat-container';
import ModalManager from '@/components/modal-manager';
import ChatConfigurationModal from './chat-configuration-modal';
import styles from './index.less';
const Chat = () => {
const { name } = useSelector((state: any) => state.chatModel);
return <div>chat:{name} </div>;
return (
<Flex className={styles.chatWrapper}>
<Flex className={styles.chatAppWrapper}>
<Flex flex={1} vertical>
<ModalManager>
{({ visible, showModal, hideModal }) => {
return (
<>
<Button type="primary" onClick={() => showModal()}>
Create an Assistant
</Button>
<ChatConfigurationModal
visible={visible}
showModal={showModal}
hideModal={hideModal}
></ChatConfigurationModal>
</>
);
}}
</ModalManager>
<Divider></Divider>
<Card>
<p>Card content</p>
</Card>
</Flex>
</Flex>
<Divider type={'vertical'} className={styles.divider}></Divider>
<Flex className={styles.chatTitleWrapper}>
<Flex flex={1} vertical>
<Flex
justify={'space-between'}
align="center"
className={styles.chatTitle}
>
<Space>
<b>Chat</b>
<Tag>25</Tag>
</Space>
<FormOutlined />
</Flex>
<Divider></Divider>
<section className={styles.chatTitleContent}>today</section>
</Flex>
</Flex>
<Divider type={'vertical'} className={styles.divider}></Divider>
<ChatContainer></ChatContainer>
</Flex>
);
};
export default Chat;

View File

@ -0,0 +1,45 @@
// RCE CSS
import { MessageList } from 'react-chat-elements';
import 'react-chat-elements/dist/main.css';
const ChatBox = () => {
return (
<div style={{ width: 600 }}>
{/* <MessageBox
position={'left'}
type={'photo'}
text={'react.svg'}
data={{
uri: 'https://facebook.github.io/react/img/logo.svg',
status: {
click: false,
loading: 0,
},
}}
/> */}
<MessageList
// referance={messageListReferance}
className="message-list"
lockable={true}
toBottomHeight={'100%'}
dataSource={[
{
position: 'right',
type: 'text',
text: 'Lorem ipsum dolor sit amet',
date: new Date(),
},
{
position: 'left',
type: 'text',
text: 'Lorem ipsum dolor sit amet',
date: new Date(),
},
]}
/>
</div>
);
};
export default ChatBox;

View File

@ -26,7 +26,7 @@
border: 1px solid rgba(234, 236, 240, 1);
box-shadow: 0px 1px 2px 0px rgba(16, 24, 40, 0.05);
padding: 24px;
max-width: 300px;
width: 300px;
cursor: pointer;
.titleWrapper {

View File

@ -63,7 +63,7 @@ const KnowledgeCard = ({ item }: IProps) => {
<Card className={styles.card} onClick={handleCardClick}>
<div className={styles.container}>
<div className={styles.content}>
<Avatar size={34} icon={<UserOutlined />} />
<Avatar size={34} icon={<UserOutlined />} src={item.avatar} />
<span className={styles.delete}>
<Dropdown
@ -78,14 +78,14 @@ const KnowledgeCard = ({ item }: IProps) => {
</div>
<div className={styles.titleWrapper}>
<span className={styles.title}>{item.name}</span>
<p>A comprehensive knowledge base for crafting effective resumes.</p>
<p>{item.description}</p>
</div>
<div className={styles.footer}>
<div className={styles.footerTop}>
<div className={styles.bottomLeft}>
<FileTextOutlined className={styles.leftIcon} />
<span className={styles.rightText}>
<Space>{item.doc_num}</Space>
<Space>{item.doc_num}Docs</Space>
</span>
</div>
</div>