1
0
mirror of https://github.com/lencx/ChatGPT.git synced 2024-10-01 01:06:13 -04:00

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 std::fs;
use std::{fs, path::PathBuf};
use tauri::{api, command, AppHandle, Manager};
#[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);
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_confirm,
cmd::form_msg,
cmd::open_file,
])
.setup(setup::init)
.plugin(tauri_plugin_positioner::init())

View File

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

View File

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

View File

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

6
src/utils.ts vendored
View File

@ -8,10 +8,14 @@ export const DISABLE_AUTO_COMPLETE = {
spellCheck: false
};
const chatRoot = async () => {
export const chatRoot = async () => {
return join(await homeDir(), '.chatgpt')
}
export const chatModelPath = async () => {
return join(await chatRoot(), CHAT_MODEL_JSON);
}
export const readJSON = async (path: string, defaultVal = {}) => {
const root = await chatRoot();
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} />
</Form.Item>
<Form.Item label="Tags" name="tags">
<Tags />
<Tags value={record?.tags} />
</Form.Item>
<Form.Item label="Enable" name="enable" valuePropName="checked">
<Switch />

View File

@ -5,7 +5,7 @@ export const modelColumns = () => [
title: '/{cmd}',
dataIndex: 'cmd',
fixed: 'left',
width: 40,
width: 120,
key: 'cmd',
render: (v: string) => <Tag color="#2a2a2a">/{v}</Tag>
},
@ -13,23 +13,29 @@ export const modelColumns = () => [
title: 'Act',
dataIndex: 'act',
key: 'act',
width: 200,
},
{
title: 'Tags',
dataIndex: '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',
dataIndex: 'enable',
key: 'enable',
width: 80,
render: (v: boolean = false) => <Switch checked={v} disabled />,
},
{
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>
),
@ -37,6 +43,8 @@ export const modelColumns = () => [
{
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>

View File

@ -3,10 +3,37 @@
width: 100%;
max-width: 300px;
overflow: hidden;
white-space: nowrap;
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: 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 { Table, Button, Modal } from 'antd';
import { invoke } from '@tauri-apps/api';
import useChatModel from '@/hooks/useChatModel';
import useColumns from '@/hooks/useColumns';
import useData from '@/hooks/useData';
import { chatModelPath } 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();
const { opData, opAdd, opRemove, opReplace, opSafeKey } = useData(modelData);
const { columns, ...opInfo } = useColumns(modelColumns());
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 = () => {
setVisible(false);
opInfo.resetRecord();
@ -34,27 +49,23 @@ export default function LanguageModel() {
})
};
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 handleOpenFile = async () => {
const path = await chatModelPath();
setChatModelPath(path);
invoke('open_file', { path });
};
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={{
hideOnSinglePage: true,