mirror of
https://github.com/FranP-code/ChatGPT.git
synced 2025-10-13 00:13:25 +00:00
chore: sync
This commit is contained in:
66
src/view/model/UserCustom/Form.tsx
vendored
Normal file
66
src/view/model/UserCustom/Form.tsx
vendored
Normal file
@@ -0,0 +1,66 @@
|
||||
import { useEffect, ForwardRefRenderFunction, useImperativeHandle, forwardRef } from 'react';
|
||||
import { Form, Input, Switch } from 'antd';
|
||||
import type { FormProps } from 'antd';
|
||||
|
||||
import Tags from '@comps/Tags';
|
||||
import { DISABLE_AUTO_COMPLETE } from '@/utils';
|
||||
|
||||
interface LanguageModelProps {
|
||||
record?: Record<string|symbol, any> | null;
|
||||
}
|
||||
|
||||
const initFormValue = {
|
||||
act: '',
|
||||
enable: true,
|
||||
tags: [],
|
||||
prompt: '',
|
||||
};
|
||||
|
||||
const LanguageModel: ForwardRefRenderFunction<FormProps, LanguageModelProps> = ({ record }, ref) => {
|
||||
const [form] = Form.useForm();
|
||||
useImperativeHandle(ref, () => ({ form }));
|
||||
|
||||
useEffect(() => {
|
||||
if (record) {
|
||||
form.setFieldsValue(record);
|
||||
}
|
||||
}, [record]);
|
||||
|
||||
return (
|
||||
<Form
|
||||
form={form}
|
||||
labelCol={{ span: 4 }}
|
||||
initialValues={initFormValue}
|
||||
>
|
||||
<Form.Item
|
||||
label="/{cmd}"
|
||||
name="cmd"
|
||||
rules={[{ required: true, message: 'Please input {cmd}!' }]}
|
||||
>
|
||||
<Input placeholder="Please input {cmd}" {...DISABLE_AUTO_COMPLETE} />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label="Act"
|
||||
name="act"
|
||||
rules={[{ required: true, message: 'Please input act!' }]}
|
||||
>
|
||||
<Input placeholder="Please input act" {...DISABLE_AUTO_COMPLETE} />
|
||||
</Form.Item>
|
||||
<Form.Item label="Tags" name="tags">
|
||||
<Tags value={record?.tags} />
|
||||
</Form.Item>
|
||||
<Form.Item label="Enable" name="enable" valuePropName="checked">
|
||||
<Switch />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label="Prompt"
|
||||
name="prompt"
|
||||
rules={[{ required: true, message: 'Please input prompt!' }]}
|
||||
>
|
||||
<Input.TextArea rows={4} placeholder="Please input prompt" {...DISABLE_AUTO_COMPLETE} />
|
||||
</Form.Item>
|
||||
</Form>
|
||||
)
|
||||
}
|
||||
|
||||
export default forwardRef(LanguageModel);
|
||||
64
src/view/model/UserCustom/config.tsx
vendored
Normal file
64
src/view/model/UserCustom/config.tsx
vendored
Normal file
@@ -0,0 +1,64 @@
|
||||
import { Tag, Switch, Tooltip, Space, Popconfirm } from 'antd';
|
||||
|
||||
export const modelColumns = () => [
|
||||
{
|
||||
title: '/{cmd}',
|
||||
dataIndex: 'cmd',
|
||||
fixed: 'left',
|
||||
width: 120,
|
||||
key: 'cmd',
|
||||
render: (v: string) => <Tag color="#2a2a2a">/{v}</Tag>
|
||||
},
|
||||
{
|
||||
title: 'Act',
|
||||
dataIndex: 'act',
|
||||
key: 'act',
|
||||
width: 200,
|
||||
},
|
||||
{
|
||||
title: 'Tags',
|
||||
dataIndex: 'tags',
|
||||
key: 'tags',
|
||||
width: 150,
|
||||
render: (v: string[]) => (
|
||||
<span className="chat-prompts-tags">{v?.map(i => <Tag key={i}>{i}</Tag>)}</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: 'Enable',
|
||||
dataIndex: 'enable',
|
||||
key: 'enable',
|
||||
width: 80,
|
||||
render: (v: boolean = false, row: Record<string, any>, action: Record<string, any>) => (
|
||||
<Switch checked={v} onChange={(v) => action.setRecord({ ...row, enable: v }, 'enable')} />
|
||||
),
|
||||
},
|
||||
{
|
||||
title: 'Prompt',
|
||||
dataIndex: 'prompt',
|
||||
key: 'prompt',
|
||||
width: 300,
|
||||
render: (v: string) => (
|
||||
<Tooltip overlayInnerStyle={{ width: 350 }} title={v}><span className="chat-prompts-val">{v}</span></Tooltip>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: 'Action',
|
||||
key: 'action',
|
||||
fixed: 'right',
|
||||
width: 120,
|
||||
render: (_: any, row: any, actions: any) => (
|
||||
<Space size="middle">
|
||||
<a onClick={() => actions.setRecord(row, 'edit')}>Edit</a>
|
||||
<Popconfirm
|
||||
title="Are you sure to delete this model?"
|
||||
onConfirm={() => actions.setRecord(row, 'delete')}
|
||||
okText="Yes"
|
||||
cancelText="No"
|
||||
>
|
||||
<a>Delete</a>
|
||||
</Popconfirm>
|
||||
</Space>
|
||||
),
|
||||
}
|
||||
];
|
||||
39
src/view/model/UserCustom/index.scss
vendored
Normal file
39
src/view/model/UserCustom/index.scss
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
.chat-prompts-val {
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
max-width: 300px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 3;
|
||||
-webkit-box-orient: vertical;
|
||||
}
|
||||
|
||||
.chat-prompts-tags {
|
||||
.ant-tag {
|
||||
margin: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
.add-btn {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.chat-model-path {
|
||||
font-size: 12px;
|
||||
font-weight: bold;
|
||||
color: #888;
|
||||
margin-bottom: 5px;
|
||||
|
||||
span {
|
||||
display: inline-block;
|
||||
// background-color: #d8d8d8;
|
||||
color: #4096ff;
|
||||
padding: 0 8px;
|
||||
height: 20px;
|
||||
line-height: 20px;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
105
src/view/model/UserCustom/index.tsx
vendored
Normal file
105
src/view/model/UserCustom/index.tsx
vendored
Normal file
@@ -0,0 +1,105 @@
|
||||
import { useState, useRef, useEffect } from 'react';
|
||||
import { Table, Button, Modal, message } from 'antd';
|
||||
import { invoke } from '@tauri-apps/api';
|
||||
|
||||
import useInit from '@/hooks/useInit';
|
||||
import useData from '@/hooks/useData';
|
||||
import useChatModel from '@/hooks/useChatModel';
|
||||
import useColumns from '@/hooks/useColumns';
|
||||
import { TABLE_PAGINATION } from '@/hooks/useTable';
|
||||
import { chatModelPath, genCmd } from '@/utils';
|
||||
import { modelColumns } from './config';
|
||||
import LanguageModelForm from './Form';
|
||||
import './index.scss';
|
||||
|
||||
export default function LanguageModel() {
|
||||
const [isVisible, setVisible] = useState(false);
|
||||
const [modelPath, setChatModelPath] = useState('');
|
||||
const { modelData, modelSet } = useChatModel('user_custom');
|
||||
const { opData, opInit, opAdd, opRemove, opReplace, opSafeKey } = useData([]);
|
||||
const { columns, ...opInfo } = useColumns(modelColumns());
|
||||
const formRef = useRef<any>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (modelData.length <= 0) return;
|
||||
opInit(modelData);
|
||||
}, [modelData])
|
||||
|
||||
useEffect(() => {
|
||||
if (!opInfo.opType) return;
|
||||
if (['edit', 'new'].includes(opInfo.opType)) {
|
||||
setVisible(true);
|
||||
}
|
||||
if (['delete'].includes(opInfo.opType)) {
|
||||
const data = opRemove(opInfo?.opRecord?.[opSafeKey]);
|
||||
modelSet(data);
|
||||
opInfo.resetRecord();
|
||||
}
|
||||
}, [opInfo.opType, formRef]);
|
||||
|
||||
useEffect(() => {
|
||||
if (opInfo.opType === 'enable') {
|
||||
const data = opReplace(opInfo?.opRecord?.[opSafeKey], opInfo?.opRecord);
|
||||
modelSet(data);
|
||||
}
|
||||
}, [opInfo.opTime])
|
||||
|
||||
useInit(async () => {
|
||||
const path = await chatModelPath();
|
||||
setChatModelPath(path);
|
||||
})
|
||||
|
||||
const hide = () => {
|
||||
setVisible(false);
|
||||
opInfo.resetRecord();
|
||||
};
|
||||
|
||||
const handleOk = () => {
|
||||
formRef.current?.form?.validateFields()
|
||||
.then((vals: Record<string, any>) => {
|
||||
if (modelData.map((i: any) => i.cmd).includes(vals.cmd) && opInfo?.opRecord?.cmd !== vals.cmd) {
|
||||
message.warning(`"cmd: /${vals.cmd}" already exists, please change the "${vals.cmd}" name and resubmit.`);
|
||||
return;
|
||||
}
|
||||
let data = [];
|
||||
switch (opInfo.opType) {
|
||||
case 'new': data = opAdd(vals); break;
|
||||
case 'edit': data = opReplace(opInfo?.opRecord?.[opSafeKey], vals); break;
|
||||
default: break;
|
||||
}
|
||||
modelSet(data)
|
||||
hide();
|
||||
})
|
||||
};
|
||||
|
||||
const handleOpenFile = () => {
|
||||
invoke('open_file', { path: modelPath });
|
||||
};
|
||||
|
||||
const modalTitle = `${({ new: 'Create', edit: 'Edit' })[opInfo.opType]} Language Model`;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Button className="add-btn" type="primary" onClick={opInfo.opNew}>Add Model</Button>
|
||||
<div className="chat-model-path">PATH: <span onClick={handleOpenFile}>{modelPath}</span></div>
|
||||
<Table
|
||||
key={opInfo.opTime}
|
||||
rowKey="cmd"
|
||||
columns={columns}
|
||||
scroll={{ x: 'auto' }}
|
||||
dataSource={opData}
|
||||
pagination={TABLE_PAGINATION}
|
||||
/>
|
||||
<Modal
|
||||
open={isVisible}
|
||||
onCancel={hide}
|
||||
title={modalTitle}
|
||||
onOk={handleOk}
|
||||
destroyOnClose
|
||||
maskClosable={false}
|
||||
>
|
||||
<LanguageModelForm record={opInfo?.opRecord} ref={formRef} />
|
||||
</Modal>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user