chore: sync

This commit is contained in:
lencx
2022-12-22 08:59:58 +08:00
parent d513a50e27
commit 2d826c90a0
22 changed files with 116 additions and 47 deletions

View File

@@ -32,7 +32,7 @@
"dependencies": { "dependencies": {
"@ant-design/icons": "^4.8.0", "@ant-design/icons": "^4.8.0",
"@tauri-apps/api": "^1.2.0", "@tauri-apps/api": "^1.2.0",
"antd": "^5.0.6", "antd": "^5.1.0",
"dayjs": "^1.11.7", "dayjs": "^1.11.7",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"react": "^18.2.0", "react": "^18.2.0",

View File

@@ -19,9 +19,11 @@ serde_json = "1.0"
serde = { version = "1.0", features = ["derive"] } serde = { version = "1.0", features = ["derive"] }
tauri = { version = "1.2.2", features = ["api-all", "devtools", "system-tray", "updater"] } tauri = { version = "1.2.2", features = ["api-all", "devtools", "system-tray", "updater"] }
tauri-plugin-positioner = { version = "1.0.4", features = ["system-tray"] } tauri-plugin-positioner = { version = "1.0.4", features = ["system-tray"] }
tokio = { version = "1.23.0", features = ["macros"] }
log = "0.4.17" log = "0.4.17"
csv = "1.1.6" csv = "1.1.6"
thiserror = "1.0.38" thiserror = "1.0.38"
reqwest = "0.11.13"
[dependencies.tauri-plugin-log] [dependencies.tauri-plugin-log]
git = "https://github.com/tauri-apps/tauri-plugin-log" git = "https://github.com/tauri-apps/tauri-plugin-log"

View File

@@ -88,3 +88,12 @@ pub fn parse_prompt(data: String) -> Vec<PromptRecord> {
} }
list list
} }
#[command]
pub fn window_reload(app: AppHandle, label: &str) {
app.app_handle()
.get_window(label)
.unwrap()
.eval("window.location.reload()")
.unwrap();
}

View File

@@ -47,6 +47,10 @@ pub fn init() -> Menu {
let preferences_menu = Submenu::new( let preferences_menu = Submenu::new(
"Preferences", "Preferences",
Menu::with_items([ Menu::with_items([
CustomMenuItem::new("control_center".to_string(), "Control Center")
.accelerator("CmdOrCtrl+Shift+P")
.into(),
MenuItem::Separator.into(),
Submenu::new( Submenu::new(
"Theme", "Theme",
Menu::new() Menu::new()
@@ -67,13 +71,11 @@ pub fn init() -> Menu {
titlebar_menu.into(), titlebar_menu.into(),
#[cfg(target_os = "macos")] #[cfg(target_os = "macos")]
CustomMenuItem::new("hide_dock_icon".to_string(), "Hide Dock Icon").into(), CustomMenuItem::new("hide_dock_icon".to_string(), "Hide Dock Icon").into(),
MenuItem::Separator.into(),
CustomMenuItem::new("inject_script".to_string(), "Inject Script") CustomMenuItem::new("inject_script".to_string(), "Inject Script")
.accelerator("CmdOrCtrl+J") .accelerator("CmdOrCtrl+J")
.into(), .into(),
CustomMenuItem::new("control_center".to_string(), "Control Center") MenuItem::Separator.into(),
.accelerator("CmdOrCtrl+Shift+P") CustomMenuItem::new("sync_prompts".to_string(), "Sync Prompts").into(),
.into(),
MenuItem::Separator.into(), MenuItem::Separator.into(),
CustomMenuItem::new("go_conf".to_string(), "Go to Config") CustomMenuItem::new("go_conf".to_string(), "Go to Config")
.accelerator("CmdOrCtrl+Shift+G") .accelerator("CmdOrCtrl+Shift+G")
@@ -178,6 +180,21 @@ pub fn menu_handler(event: WindowMenuEvent<tauri::Wry>) {
"go_conf" => utils::open_file(utils::chat_root()), "go_conf" => utils::open_file(utils::chat_root()),
"clear_conf" => utils::clear_conf(&app), "clear_conf" => utils::clear_conf(&app),
"awesome" => open(&app, conf::AWESOME_URL.to_string()), "awesome" => open(&app, conf::AWESOME_URL.to_string()),
"sync_prompts" => {
tauri::api::dialog::ask(
app.get_window("main").as_ref(),
"Sync Prompts",
"Data sync will enable all prompts, are you sure you want to sync?",
move |is_restart| {
if is_restart {
app.get_window("main")
.unwrap()
.eval("window.__sync_prompts && window.__sync_prompts()")
.unwrap()
}
},
);
}
"hide_dock_icon" => { "hide_dock_icon" => {
ChatConfJson::amend(&serde_json::json!({ "hide_dock_icon": true }), Some(app)).unwrap() ChatConfJson::amend(&serde_json::json!({ "hide_dock_icon": true }), Some(app)).unwrap()
} }

View File

@@ -15,7 +15,8 @@ use tauri_plugin_log::{
LogTarget, LoggerBuilder, LogTarget, LoggerBuilder,
}; };
fn main() { #[tokio::main]
async fn main() {
ChatConfJson::init(); ChatConfJson::init();
let chat_conf = ChatConfJson::get_chat_conf(); let chat_conf = ChatConfJson::get_chat_conf();
let context = tauri::generate_context!(); let context = tauri::generate_context!();
@@ -59,6 +60,7 @@ fn main() {
cmd::open_file, cmd::open_file,
cmd::get_chat_model, cmd::get_chat_model,
cmd::parse_prompt, cmd::parse_prompt,
cmd::window_reload,
fs_extra::metadata, fs_extra::metadata,
]) ])
.setup(setup::init) .setup(setup::init)

View File

@@ -1,5 +1,6 @@
import { useState } from 'react'; import { useState } from 'react';
import { clone } from 'lodash'; import { clone } from 'lodash';
import { invoke } from '@tauri-apps/api';
import { CHAT_MODEL_JSON, readJSON, writeJSON } from '@/utils'; import { CHAT_MODEL_JSON, readJSON, writeJSON } from '@/utils';
import useInit from '@/hooks/useInit'; import useInit from '@/hooks/useInit';
@@ -16,6 +17,7 @@ export default function useChatModel(key: string) {
const oData = clone(modelJson); const oData = clone(modelJson);
oData[key] = data; oData[key] = data;
await writeJSON(CHAT_MODEL_JSON, oData); await writeJSON(CHAT_MODEL_JSON, oData);
await invoke('window_reload', { label: 'core' });
setModelJson(oData); setModelJson(oData);
} }

28
src/hooks/useEvent.ts vendored Normal file
View File

@@ -0,0 +1,28 @@
import { invoke, http, fs, dialog } from '@tauri-apps/api';
import useInit from '@/hooks/useInit';
import useChatModel from '@/hooks/useChatModel';
import { GITHUB_PROMPTS_CSV_URL, chatPromptsPath, genCmd } from '@/utils';
export default function useEvent() {
const { modelSet } = useChatModel('sys_sync_prompts');
// Using `emit` and `listen` will be triggered multiple times in development mode.
// So here we use `eval` to call `__sync_prompt`
useInit(() => {
(window as any).__sync_prompts = async () => {
const res = await http.fetch(GITHUB_PROMPTS_CSV_URL, {
method: 'GET',
responseType: http.ResponseType.Text,
});
const data = (res.data || '') as string;
if (res.ok) {
await fs.writeTextFile(await chatPromptsPath(), data);
const list: Record<string, string>[] = await invoke('parse_prompt', { data });
modelSet(list.map(i => ({ cmd: genCmd(i.act), enable: true, tags: ['chatgpt-prompts'], ...i })));
dialog.message('ChatGPT Prompts data has been synchronized!');
} else {
dialog.message('ChatGPT Prompts data sync failed, please try again!');
}
}
})
}

View File

@@ -39,6 +39,7 @@ const ChatLayout: FC<ChatLayoutProps> = ({ children }) => {
mode="inline" mode="inline"
inlineIndent={12} inlineIndent={12}
items={menuItems} items={menuItems}
defaultOpenKeys={['/model']}
onClick={(i) => go(i.key)} onClick={(i) => go(i.key)}
/> />
</Sider> </Sider>

14
src/main.tsx vendored
View File

@@ -2,15 +2,23 @@ import { StrictMode, Suspense } from 'react';
import { BrowserRouter } from 'react-router-dom'; import { BrowserRouter } from 'react-router-dom';
import ReactDOM from 'react-dom/client'; import ReactDOM from 'react-dom/client';
import useEvent from '@/hooks/useEvent';
import Layout from '@/layout'; import Layout from '@/layout';
import './main.scss'; import './main.scss';
const App = () => {
useEvent();
return (
<BrowserRouter>
<Layout/>
</BrowserRouter>
);
}
ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render( ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
<StrictMode> <StrictMode>
<Suspense fallback={null}> <Suspense fallback={null}>
<BrowserRouter> <App />
<Layout/>
</BrowserRouter>
</Suspense> </Suspense>
</StrictMode> </StrictMode>
); );

10
src/routes.tsx vendored
View File

@@ -9,9 +9,9 @@ import {
import type { MenuProps } from 'antd'; import type { MenuProps } from 'antd';
import General from '@view/General'; import General from '@view/General';
import LanguageModel from '@/view/LanguageModel'; import UserCustom from '@/view/model/UserCustom';
import SyncPrompts from '@/view/SyncPrompts'; import SyncPrompts from '@/view/model/SyncPrompts';
import SyncMore from '@/view/SyncMore'; import SyncMore from '@/view/model/SyncMore';
export type ChatRouteMetaObject = { export type ChatRouteMetaObject = {
label: string; label: string;
@@ -35,7 +35,7 @@ export const routes: Array<ChatRouteObject> = [
}, },
}, },
{ {
path: '/language-model', path: '/model',
meta: { meta: {
label: 'Language Model', label: 'Language Model',
icon: <BulbOutlined />, icon: <BulbOutlined />,
@@ -43,7 +43,7 @@ export const routes: Array<ChatRouteObject> = [
children: [ children: [
{ {
path: 'user-custom', path: 'user-custom',
element: <LanguageModel />, element: <UserCustom />,
meta: { meta: {
label: 'User Custom', label: 'User Custom',
icon: <UserOutlined />, icon: <UserOutlined />,

4
src/utils.ts vendored
View File

@@ -48,4 +48,6 @@ export const writeJSON = async (path: string, data: Record<string, any>) => {
await writeTextFile(file, JSON.stringify(data, null, 2)); await writeTextFile(file, JSON.stringify(data, null, 2));
} }
export const fmtDate = (date: any) => dayjs(date).format('YYYY-MM-DD HH:mm:ss'); export const fmtDate = (date: any) => dayjs(date).format('YYYY-MM-DD HH:mm:ss');
export const genCmd = (act: string) => act.replace(/\s+|\/+/g, '_').replace(/[^\d\w]/g, '').toLocaleLowerCase();

View File

@@ -1,22 +0,0 @@
// import { Switch, Tag, Tooltip } from 'antd';
export const genCmd = (act: string) => act.replace(/\s+|\/+/g, '_').replace(/[^\d\w]/g, '').toLocaleLowerCase();
export const recordColumns = () => [
{
title: 'URL',
dataIndex: 'url',
// fixed: 'left',
// width: 120,
key: 'url',
},
{
title: 'File Type',
dataIndex: 'file_type',
key: 'file_type',
// width: 200,
},
{
title: 'Action',
}
];

15
src/view/model/SyncMore/config.tsx vendored Normal file
View File

@@ -0,0 +1,15 @@
export const recordColumns = () => [
{
title: 'URL',
dataIndex: 'url',
key: 'url',
},
{
title: 'File Type',
dataIndex: 'file_type',
key: 'file_type',
},
{
title: 'Action',
}
];

View File

@@ -9,7 +9,7 @@ export default function SyncMore() {
<Button className="add-btn" type="primary">Add URL</Button> <Button className="add-btn" type="primary">Add URL</Button>
<Table <Table
key="id" key="id"
rowKey="act" rowKey="url"
columns={[]} columns={[]}
scroll={{ x: 'auto' }} scroll={{ x: 'auto' }}
dataSource={[]} dataSource={[]}

View File

@@ -1,6 +1,6 @@
import { Switch, Tag, Tooltip } from 'antd'; import { Switch, Tag, Tooltip } from 'antd';
export const genCmd = (act: string) => act.replace(/\s+|\/+/g, '_').replace(/[^\d\w]/g, '').toLocaleLowerCase(); import { genCmd } from '@/utils';
export const modelColumns = () => [ export const modelColumns = () => [
{ {

View File

@@ -1,5 +1,5 @@
import { useEffect, useState } from 'react'; import { useEffect, useState } from 'react';
import { Table, Button, message } from 'antd'; import { Table, Button, message, Popconfirm } from 'antd';
import { invoke } from '@tauri-apps/api'; import { invoke } from '@tauri-apps/api';
import { fetch, ResponseType } from '@tauri-apps/api/http'; import { fetch, ResponseType } from '@tauri-apps/api/http';
import { writeTextFile } from '@tauri-apps/api/fs'; import { writeTextFile } from '@tauri-apps/api/fs';
@@ -8,15 +8,14 @@ import useColumns from '@/hooks/useColumns';
import useData from '@/hooks/useData'; import useData from '@/hooks/useData';
import useChatModel from '@/hooks/useChatModel'; import useChatModel from '@/hooks/useChatModel';
import useTable, { TABLE_PAGINATION } from '@/hooks/useTable'; import useTable, { TABLE_PAGINATION } from '@/hooks/useTable';
import { fmtDate, chatPromptsPath, GITHUB_PROMPTS_CSV_URL } from '@/utils'; import { fmtDate, chatPromptsPath, GITHUB_PROMPTS_CSV_URL, genCmd } from '@/utils';
import { modelColumns, genCmd } from './config'; import { modelColumns } from './config';
import './index.scss'; import './index.scss';
const promptsURL = 'https://github.com/f/awesome-chatgpt-prompts/blob/main/prompts.csv'; const promptsURL = 'https://github.com/f/awesome-chatgpt-prompts/blob/main/prompts.csv';
export default function LanguageModel() { export default function LanguageModel() {
const { rowSelection, selectedRowIDs } = useTable(); const { rowSelection, selectedRowIDs } = useTable();
const [loading, setLoading] = useState(false);
const [lastUpdated, setLastUpdated] = useState(); const [lastUpdated, setLastUpdated] = useState();
const { modelJson, modelSet } = useChatModel('sys_sync_prompts'); const { modelJson, modelSet } = useChatModel('sys_sync_prompts');
const { opData, opInit, opReplace, opReplaceItems, opSafeKey } = useData([]); const { opData, opInit, opReplace, opReplaceItems, opSafeKey } = useData([]);
@@ -35,7 +34,6 @@ export default function LanguageModel() {
}, [modelJson?.sys_sync_prompts]) }, [modelJson?.sys_sync_prompts])
const handleSync = async () => { const handleSync = async () => {
setLoading(true);
const res = await fetch(GITHUB_PROMPTS_CSV_URL, { const res = await fetch(GITHUB_PROMPTS_CSV_URL, {
method: 'GET', method: 'GET',
responseType: ResponseType.Text, responseType: ResponseType.Text,
@@ -52,7 +50,6 @@ export default function LanguageModel() {
} else { } else {
message.error('ChatGPT Prompts data sync failed, please try again!'); message.error('ChatGPT Prompts data sync failed, please try again!');
} }
setLoading(false);
}; };
useEffect(() => { useEffect(() => {
@@ -79,7 +76,15 @@ export default function LanguageModel() {
</> </>
)} )}
</div> </div>
<Button type="primary" loading={loading} onClick={handleSync}>Sync</Button> <Popconfirm
title={<span>Data sync will enable all prompts,<br/>are you sure you want to sync?</span>}
placement="topLeft"
onConfirm={handleSync}
okText="Yes"
cancelText="No"
>
<Button type="primary">Sync</Button>
</Popconfirm>
</div> </div>
<div className="chat-table-tip"> <div className="chat-table-tip">
<span className="chat-model-path">URL: <a href={promptsURL} target="_blank" title={promptsURL}>f/awesome-chatgpt-prompts/prompts.csv</a></span> <span className="chat-model-path">URL: <a href={promptsURL} target="_blank" title={promptsURL}>f/awesome-chatgpt-prompts/prompts.csv</a></span>

View File

@@ -7,7 +7,7 @@ import useData from '@/hooks/useData';
import useChatModel from '@/hooks/useChatModel'; import useChatModel from '@/hooks/useChatModel';
import useColumns from '@/hooks/useColumns'; import useColumns from '@/hooks/useColumns';
import { TABLE_PAGINATION } from '@/hooks/useTable'; import { TABLE_PAGINATION } from '@/hooks/useTable';
import { chatModelPath } from '@/utils'; import { chatModelPath, genCmd } from '@/utils';
import { modelColumns } from './config'; import { modelColumns } from './config';
import LanguageModelForm from './Form'; import LanguageModelForm from './Form';
import './index.scss'; import './index.scss';