feat: chatgpt prompts

This commit is contained in:
lencx
2022-12-16 21:23:46 +08:00
parent 3318bfb23f
commit 47c9072f40
10 changed files with 79 additions and 19 deletions

View File

@@ -1,5 +1,5 @@
use crate::{conf::ChatConfJson, utils}; use crate::{conf::ChatConfJson, utils};
use std::fs; use std::{fs, path::PathBuf};
use tauri::{api, command, AppHandle, Manager}; use tauri::{api, command, AppHandle, Manager};
#[command] #[command]
@@ -59,3 +59,8 @@ pub fn form_msg(app: AppHandle, label: &str, title: &str, msg: &str) {
let win = app.app_handle().get_window(label); let win = app.app_handle().get_window(label);
tauri::api::dialog::message(win.as_ref(), title, msg); tauri::api::dialog::message(win.as_ref(), title, msg);
} }
#[command]
pub fn open_file(path: PathBuf) {
utils::open_file(path);
}

View File

@@ -26,6 +26,7 @@ fn main() {
cmd::form_cancel, cmd::form_cancel,
cmd::form_confirm, cmd::form_confirm,
cmd::form_msg, cmd::form_msg,
cmd::open_file,
]) ])
.setup(setup::init) .setup(setup::init)
.plugin(tauri_plugin_positioner::init()) .plugin(tauri_plugin_positioner::init())

View File

@@ -16,6 +16,10 @@ const Tags: FC<TagsProps> = ({ value = [], onChange }) => {
const [inputValue, setInputValue] = useState(''); const [inputValue, setInputValue] = useState('');
const inputRef = useRef<InputRef>(null); const inputRef = useRef<InputRef>(null);
useEffect(() => {
setTags(value);
}, [value])
useEffect(() => { useEffect(() => {
if (inputVisible) { if (inputVisible) {
inputRef.current?.focus(); inputRef.current?.focus();

View File

@@ -10,6 +10,7 @@
.chat-container { .chat-container {
padding: 20px; padding: 20px;
overflow: hidden;
} }
.ant-menu { .ant-menu {

View File

@@ -3,7 +3,6 @@ import { Layout, Menu } from 'antd';
import { useNavigate, useLocation } from 'react-router-dom'; import { useNavigate, useLocation } from 'react-router-dom';
import Routes, { menuItems } from '@/routes'; import Routes, { menuItems } from '@/routes';
import './index.scss'; import './index.scss';
const { Content, Footer, Sider } = Layout; const { Content, Footer, Sider } = Layout;

6
src/utils.ts vendored
View File

@@ -8,10 +8,14 @@ export const DISABLE_AUTO_COMPLETE = {
spellCheck: false spellCheck: false
}; };
const chatRoot = async () => { export const chatRoot = async () => {
return join(await homeDir(), '.chatgpt') return join(await homeDir(), '.chatgpt')
} }
export const chatModelPath = async () => {
return join(await chatRoot(), CHAT_MODEL_JSON);
}
export const readJSON = async (path: string, defaultVal = {}) => { export const readJSON = async (path: string, defaultVal = {}) => {
const root = await chatRoot(); const root = await chatRoot();
const file = await join(root, path); const file = await join(root, path);

View File

@@ -47,7 +47,7 @@ const LanguageModel: ForwardRefRenderFunction<FormProps, LanguageModelProps> = (
<Input placeholder="Please input act" {...DISABLE_AUTO_COMPLETE} /> <Input placeholder="Please input act" {...DISABLE_AUTO_COMPLETE} />
</Form.Item> </Form.Item>
<Form.Item label="Tags" name="tags"> <Form.Item label="Tags" name="tags">
<Tags /> <Tags value={record?.tags} />
</Form.Item> </Form.Item>
<Form.Item label="Enable" name="enable" valuePropName="checked"> <Form.Item label="Enable" name="enable" valuePropName="checked">
<Switch /> <Switch />

View File

@@ -5,7 +5,7 @@ export const modelColumns = () => [
title: '/{cmd}', title: '/{cmd}',
dataIndex: 'cmd', dataIndex: 'cmd',
fixed: 'left', fixed: 'left',
width: 40, width: 120,
key: 'cmd', key: 'cmd',
render: (v: string) => <Tag color="#2a2a2a">/{v}</Tag> render: (v: string) => <Tag color="#2a2a2a">/{v}</Tag>
}, },
@@ -13,23 +13,29 @@ export const modelColumns = () => [
title: 'Act', title: 'Act',
dataIndex: 'act', dataIndex: 'act',
key: 'act', key: 'act',
width: 200,
}, },
{ {
title: 'Tags', title: 'Tags',
dataIndex: 'tags', dataIndex: 'tags',
key: 'tags', key: 'tags',
render: (v: string[]) => v?.map(i => <Tag key={i}>{i}</Tag>), width: 150,
render: (v: string[]) => (
<span className="chat-prompts-tags">{v?.map(i => <Tag key={i}>{i}</Tag>)}</span>
),
}, },
{ {
title: 'Enable', title: 'Enable',
dataIndex: 'enable', dataIndex: 'enable',
key: 'enable', key: 'enable',
width: 80,
render: (v: boolean = false) => <Switch checked={v} disabled />, render: (v: boolean = false) => <Switch checked={v} disabled />,
}, },
{ {
title: 'Prompt', title: 'Prompt',
dataIndex: 'prompt', dataIndex: 'prompt',
key: 'prompt', key: 'prompt',
width: 300,
render: (v: string) => ( render: (v: string) => (
<Tooltip overlayInnerStyle={{ width: 350 }} title={v}><span className="chat-prompts-val">{v}</span></Tooltip> <Tooltip overlayInnerStyle={{ width: 350 }} title={v}><span className="chat-prompts-val">{v}</span></Tooltip>
), ),
@@ -37,6 +43,8 @@ export const modelColumns = () => [
{ {
title: 'Action', title: 'Action',
key: 'action', key: 'action',
fixed: 'right',
width: 120,
render: (_: any, row: any, actions: any) => ( render: (_: any, row: any, actions: any) => (
<Space size="middle"> <Space size="middle">
<a onClick={() => actions.setRecord(row, 'edit')}>Edit</a> <a onClick={() => actions.setRecord(row, 'edit')}>Edit</a>

View File

@@ -3,10 +3,37 @@
width: 100%; width: 100%;
max-width: 300px; max-width: 300px;
overflow: hidden; overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis; text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
}
.chat-prompts-tags {
.ant-tag {
margin: 2px;
}
} }
.add-btn { .add-btn {
margin-bottom: 20px; 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;
}
} }

View File

@@ -1,20 +1,35 @@
import { useState, useRef, useEffect } from 'react'; import { useState, useRef, useEffect } from 'react';
import { Table, Button, Modal } from 'antd'; import { Table, Button, Modal } from 'antd';
import { invoke } from '@tauri-apps/api';
import useChatModel from '@/hooks/useChatModel'; import useChatModel from '@/hooks/useChatModel';
import useColumns from '@/hooks/useColumns'; import useColumns from '@/hooks/useColumns';
import useData from '@/hooks/useData'; import useData from '@/hooks/useData';
import { chatModelPath } from '@/utils';
import { modelColumns } from './config'; import { modelColumns } from './config';
import LanguageModelForm from './Form'; import LanguageModelForm from './Form';
import './index.scss'; import './index.scss';
export default function LanguageModel() { export default function LanguageModel() {
const [isVisible, setVisible] = useState(false); const [isVisible, setVisible] = useState(false);
const [modelPath, setChatModelPath] = useState('');
const { modelData, modelSet } = useChatModel(); const { modelData, modelSet } = useChatModel();
const { opData, opAdd, opRemove, opReplace, opSafeKey } = useData(modelData); const { opData, opAdd, opRemove, opReplace, opSafeKey } = useData(modelData);
const { columns, ...opInfo } = useColumns(modelColumns()); const { columns, ...opInfo } = useColumns(modelColumns());
const formRef = useRef<any>(null); const formRef = useRef<any>(null);
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]);
const hide = () => { const hide = () => {
setVisible(false); setVisible(false);
opInfo.resetRecord(); opInfo.resetRecord();
@@ -34,27 +49,23 @@ export default function LanguageModel() {
}) })
}; };
useEffect(() => { const handleOpenFile = async () => {
if (!opInfo.opType) return; const path = await chatModelPath();
if (['edit', 'new'].includes(opInfo.opType)) { setChatModelPath(path);
setVisible(true); invoke('open_file', { path });
} };
if (['delete'].includes(opInfo.opType)) {
const data = opRemove(opInfo?.opRecord?.[opSafeKey]);
modelSet(data);
opInfo.resetRecord();
}
}, [opInfo.opType, formRef]);
const modalTitle = `${({ new: 'Create', edit: 'Edit' })[opInfo.opType]} Language Model`; const modalTitle = `${({ new: 'Create', edit: 'Edit' })[opInfo.opType]} Language Model`;
return ( return (
<div> <div>
<Button className="add-btn" type="primary" onClick={opInfo.opNew}>Add Model</Button> <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 <Table
key={opInfo.opTime} key={opInfo.opTime}
rowKey="cmd" rowKey="cmd"
columns={columns} columns={columns}
scroll={{ x: 'auto' }}
dataSource={opData} dataSource={opData}
pagination={{ pagination={{
hideOnSinglePage: true, hideOnSinglePage: true,