mirror of
https://github.com/lencx/ChatGPT.git
synced 2024-10-01 01:06:13 -04:00
chore: sync
This commit is contained in:
parent
2be560e69a
commit
389e00a5e0
@ -19,11 +19,12 @@ 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"
|
walkdir = "2.3.2"
|
||||||
|
# tokio = { version = "1.23.0", features = ["macros"] }
|
||||||
|
# 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"
|
||||||
|
@ -66,8 +66,8 @@ pub fn open_file(path: PathBuf) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[command]
|
#[command]
|
||||||
pub fn get_chat_model() -> serde_json::Value {
|
pub fn get_chat_model_cmd() -> serde_json::Value {
|
||||||
let path = utils::chat_root().join("chat.model.json");
|
let path = utils::chat_root().join("chat.model.cmd.json");
|
||||||
let content = fs::read_to_string(path).unwrap_or_else(|_| r#"{"data":[]}"#.to_string());
|
let content = fs::read_to_string(path).unwrap_or_else(|_| r#"{"data":[]}"#.to_string());
|
||||||
serde_json::from_str(&content).unwrap()
|
serde_json::from_str(&content).unwrap()
|
||||||
}
|
}
|
||||||
@ -98,3 +98,33 @@ pub fn window_reload(app: AppHandle, label: &str) {
|
|||||||
.eval("window.location.reload()")
|
.eval("window.location.reload()")
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
use walkdir::WalkDir;
|
||||||
|
use utils::chat_root;
|
||||||
|
|
||||||
|
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
|
||||||
|
pub struct ModelRecord {
|
||||||
|
pub cmd: String,
|
||||||
|
pub act: String,
|
||||||
|
pub prompt: String,
|
||||||
|
pub tags: Vec<String>,
|
||||||
|
pub enable: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[command]
|
||||||
|
pub fn cmd_list() -> Vec<ModelRecord> {
|
||||||
|
let mut list = vec![];
|
||||||
|
for entry in WalkDir::new(chat_root().join("cache_model")).into_iter().filter_map(|e| e.ok()) {
|
||||||
|
let file = fs::read_to_string(entry.path().display().to_string());
|
||||||
|
if let Ok(v) = file {
|
||||||
|
let data: Vec<ModelRecord> = serde_json::from_str(&v).unwrap_or_else(|_| vec![]);
|
||||||
|
let enable_list = data.into_iter()
|
||||||
|
.filter(|v| v.enable);
|
||||||
|
list.extend(enable_list)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// dbg!(&list);
|
||||||
|
list.sort_by(|a, b| a.cmd.len().cmp(&b.cmd.len()));
|
||||||
|
list
|
||||||
|
}
|
||||||
|
51
src-tauri/src/assets/cmd.js
vendored
51
src-tauri/src/assets/cmd.js
vendored
@ -61,10 +61,8 @@ function init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function cmdTip() {
|
async function cmdTip() {
|
||||||
const chatModelJson = await invoke('get_chat_model') || {};
|
const chatModelJson = await invoke('get_chat_model_cmd') || {};
|
||||||
const user_custom = chatModelJson.user_custom || [];
|
const data = chatModelJson.data;
|
||||||
const sys_sync_prompts = chatModelJson.sys_sync_prompts || [];
|
|
||||||
const data = [...user_custom, ...sys_sync_prompts];
|
|
||||||
if (data.length <= 0) return;
|
if (data.length <= 0) return;
|
||||||
|
|
||||||
const modelDom = document.createElement('div');
|
const modelDom = document.createElement('div');
|
||||||
@ -82,18 +80,43 @@ async function cmdTip() {
|
|||||||
// Enter a command starting with `/` and press a space to automatically fill `chatgpt prompt`.
|
// Enter a command starting with `/` and press a space to automatically fill `chatgpt prompt`.
|
||||||
// If more than one command appears in the search results, the first one will be used by default.
|
// If more than one command appears in the search results, the first one will be used by default.
|
||||||
searchInput.addEventListener('keydown', (event) => {
|
searchInput.addEventListener('keydown', (event) => {
|
||||||
if (!window.__CHAT_MODEL_CMD__) {
|
if (!window.__CHAT_MODEL_CMD_PROMPT__) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event.keyCode === 13 && window.__CHAT_MODEL_CMD__) {
|
// feat: https://github.com/lencx/ChatGPT/issues/54
|
||||||
searchInput.value = window.__CHAT_MODEL_CMD__;
|
if (event.keyCode === 9) {
|
||||||
|
const strGroup = window.__CHAT_MODEL_CMD_PROMPT__.match(/\{([^{}]*)\}/) || [];
|
||||||
|
|
||||||
|
if (strGroup[1]) {
|
||||||
|
searchInput.value = `/${window.__CHAT_MODEL_CMD__}` + `{${strGroup[1]}}` + ' |-> ';
|
||||||
|
window.__CHAT_MODEL_VAR__ = true;
|
||||||
|
}
|
||||||
|
event.preventDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (window.__CHAT_MODEL_VAR__ && event.keyCode === 9) {
|
||||||
|
const data = searchInput.value.split('|->');
|
||||||
|
if (data[1]) {
|
||||||
|
window.__CHAT_MODEL_CMD_PROMPT__ = window.__CHAT_MODEL_CMD_PROMPT__?.replace(/\{([^{}]*)\}/, `{${data[1]?.trim()}}`);
|
||||||
|
// searchInput.value = window.__CHAT_MODEL_CMD_PROMPT__;
|
||||||
|
}
|
||||||
|
// event.preventDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
// send
|
||||||
|
if (event.keyCode === 13 && window.__CHAT_MODEL_CMD_PROMPT__) {
|
||||||
|
searchInput.value = window.__CHAT_MODEL_CMD_PROMPT__;
|
||||||
modelDom.innerHTML = '';
|
modelDom.innerHTML = '';
|
||||||
|
delete window.__CHAT_MODEL_CMD_PROMPT__;
|
||||||
delete window.__CHAT_MODEL_CMD__;
|
delete window.__CHAT_MODEL_CMD__;
|
||||||
|
delete window.__CHAT_MODEL_VAR__;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
searchInput.addEventListener('input', (event) => {
|
searchInput.addEventListener('input', (event) => {
|
||||||
|
if (window.__CHAT_MODEL_VAR__) return;
|
||||||
|
|
||||||
const query = searchInput.value;
|
const query = searchInput.value;
|
||||||
if (!query || !/^\//.test(query)) {
|
if (!query || !/^\//.test(query)) {
|
||||||
modelDom.innerHTML = '';
|
modelDom.innerHTML = '';
|
||||||
@ -102,18 +125,20 @@ async function cmdTip() {
|
|||||||
|
|
||||||
// all cmd result
|
// all cmd result
|
||||||
if (query === '/') {
|
if (query === '/') {
|
||||||
const result = data.filter(i => i.enable);
|
modelDom.innerHTML = `<div>${data.map(itemDom).join('')}</div>`;
|
||||||
modelDom.innerHTML = `<div>${result.map(itemDom).join('')}</div>`;
|
window.__CHAT_MODEL_CMD_PROMPT__ = data[0]?.prompt.trim();
|
||||||
window.__CHAT_MODEL_CMD__ = result[0]?.prompt.trim();
|
window.__CHAT_MODEL_CMD__ = data[0]?.cmd.trim();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = data.filter(i => i.enable && new RegExp(query.substring(1)).test(i.cmd));
|
const result = data.filter(i => new RegExp(query.substring(1)).test(i.cmd));
|
||||||
if (result.length > 0) {
|
if (result.length > 0) {
|
||||||
modelDom.innerHTML = `<div>${result.map(itemDom).join('')}</div>`;
|
modelDom.innerHTML = `<div>${result.map(itemDom).join('')}</div>`;
|
||||||
window.__CHAT_MODEL_CMD__ = result[0]?.prompt.trim();
|
window.__CHAT_MODEL_CMD_PROMPT__ = result[0]?.prompt.trim();
|
||||||
|
window.__CHAT_MODEL_CMD__ = result[0]?.cmd.trim();
|
||||||
} else {
|
} else {
|
||||||
modelDom.innerHTML = '';
|
modelDom.innerHTML = '';
|
||||||
|
delete window.__CHAT_MODEL_CMD_PROMPT__;
|
||||||
delete window.__CHAT_MODEL_CMD__;
|
delete window.__CHAT_MODEL_CMD__;
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
@ -136,7 +161,7 @@ async function cmdTip() {
|
|||||||
const val = decodeURIComponent(item.getAttribute('data-prompt'));
|
const val = decodeURIComponent(item.getAttribute('data-prompt'));
|
||||||
searchInput.value = val;
|
searchInput.value = val;
|
||||||
document.querySelector('form textarea').focus();
|
document.querySelector('form textarea').focus();
|
||||||
window.__CHAT_MODEL_CMD__ = val;
|
window.__CHAT_MODEL_CMD_PROMPT__ = val;
|
||||||
modelDom.innerHTML = '';
|
modelDom.innerHTML = '';
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
|
@ -15,8 +15,7 @@ use tauri_plugin_log::{
|
|||||||
LogTarget, LoggerBuilder,
|
LogTarget, LoggerBuilder,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[tokio::main]
|
fn 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!();
|
||||||
@ -58,9 +57,10 @@ async fn main() {
|
|||||||
cmd::form_confirm,
|
cmd::form_confirm,
|
||||||
cmd::form_msg,
|
cmd::form_msg,
|
||||||
cmd::open_file,
|
cmd::open_file,
|
||||||
cmd::get_chat_model,
|
cmd::get_chat_model_cmd,
|
||||||
cmd::parse_prompt,
|
cmd::parse_prompt,
|
||||||
cmd::window_reload,
|
cmd::window_reload,
|
||||||
|
cmd::cmd_list,
|
||||||
fs_extra::metadata,
|
fs_extra::metadata,
|
||||||
])
|
])
|
||||||
.setup(setup::init)
|
.setup(setup::init)
|
||||||
|
34
src/hooks/useChatModel.ts
vendored
34
src/hooks/useChatModel.ts
vendored
@ -2,46 +2,52 @@ import { useState, useEffect } from 'react';
|
|||||||
import { clone } from 'lodash';
|
import { clone } from 'lodash';
|
||||||
import { invoke } from '@tauri-apps/api';
|
import { invoke } from '@tauri-apps/api';
|
||||||
|
|
||||||
import { CHAT_MODEL_JSON, readJSON, writeJSON } from '@/utils';
|
import { CHAT_MODEL_JSON, CHAT_MODEL_CMD_JSON, readJSON, writeJSON } from '@/utils';
|
||||||
import useInit from '@/hooks/useInit';
|
import useInit from '@/hooks/useInit';
|
||||||
|
|
||||||
export default function useChatModel(key: string, file = CHAT_MODEL_JSON) {
|
export default function useChatModel(key: string, file = CHAT_MODEL_JSON) {
|
||||||
const [modelJson, setModelJson] = useState<Record<string, any>>([]);
|
const [modelJson, setModelJson] = useState<Record<string, any>>({});
|
||||||
|
|
||||||
useInit(async () => {
|
useInit(async () => {
|
||||||
const data = await readJSON(file, {
|
const data = await readJSON(file, {
|
||||||
defaultVal: { name: 'ChatGPT Model', [key]: [] },
|
defaultVal: { name: 'ChatGPT Model', [key]: null },
|
||||||
});
|
});
|
||||||
setModelJson(data);
|
setModelJson(data);
|
||||||
});
|
});
|
||||||
|
|
||||||
const modelSet = async (data: Record<string, any>[]) => {
|
const modelSet = async (data: Record<string, any>[]|Record<string, any>) => {
|
||||||
const oData = clone(modelJson);
|
const oData = clone(modelJson);
|
||||||
oData[key] = data;
|
oData[key] = data;
|
||||||
await writeJSON(file, oData);
|
await writeJSON(file, oData);
|
||||||
await invoke('window_reload', { label: 'core' });
|
|
||||||
setModelJson(oData);
|
setModelJson(oData);
|
||||||
}
|
}
|
||||||
|
|
||||||
return { modelJson, modelSet, modelData: modelJson?.[key] || [] };
|
return { modelJson, modelSet, modelData: modelJson?.[key] || [] };
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useCacheModel(file: string) {
|
export function useCacheModel(file = '') {
|
||||||
const [modelJson, setModelJson] = useState<Record<string, any>[]>([]);
|
const [modelCacheJson, setModelCacheJson] = useState<Record<string, any>[]>([]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!file) return;
|
if (!file) return;
|
||||||
(async () => {
|
(async () => {
|
||||||
const data = await readJSON(file, { isRoot: true });
|
const data = await readJSON(file, { isRoot: true, isList: true });
|
||||||
setModelJson(data);
|
setModelCacheJson(data);
|
||||||
})();
|
})();
|
||||||
}, [file]);
|
}, [file]);
|
||||||
|
|
||||||
const modelSet = async (data: Record<string, any>[]) => {
|
const modelCacheSet = async (data: Record<string, any>[], newFile = '') => {
|
||||||
await writeJSON(file, data, { isRoot: true });
|
await writeJSON(newFile ? newFile : file, data, { isRoot: true });
|
||||||
await invoke('window_reload', { label: 'core' });
|
setModelCacheJson(data);
|
||||||
setModelJson(data);
|
await modelCacheCmd();
|
||||||
}
|
}
|
||||||
|
|
||||||
return { modelJson, modelSet };
|
const modelCacheCmd = async () => {
|
||||||
|
// Generate the `chat.model.cmd.json` file and refresh the page for the slash command to take effect.
|
||||||
|
const list = await invoke('cmd_list');
|
||||||
|
await writeJSON(CHAT_MODEL_CMD_JSON, { name: 'ChatGPT CMD', last_updated: Date.now(), data: list });
|
||||||
|
await invoke('window_reload', { label: 'core' });
|
||||||
|
};
|
||||||
|
|
||||||
|
return { modelCacheJson, modelCacheSet, modelCacheCmd };
|
||||||
}
|
}
|
3
src/hooks/useData.ts
vendored
3
src/hooks/useData.ts
vendored
@ -17,6 +17,9 @@ export default function useData(oData: any[]) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const opInit = (val: any[] = []) => {
|
const opInit = (val: any[] = []) => {
|
||||||
|
if (!val || !Array.isArray(val)) return;
|
||||||
|
console.log('«20» /src/hooks/useData.ts ~> ', val);
|
||||||
|
|
||||||
const nData = val.map(i => ({ [safeKey]: v4(), ...i }));
|
const nData = val.map(i => ({ [safeKey]: v4(), ...i }));
|
||||||
setData(nData);
|
setData(nData);
|
||||||
};
|
};
|
||||||
|
2
src/hooks/useEvent.ts
vendored
2
src/hooks/useEvent.ts
vendored
@ -5,7 +5,7 @@ import useChatModel from '@/hooks/useChatModel';
|
|||||||
import { GITHUB_PROMPTS_CSV_URL, chatPromptsPath, genCmd } from '@/utils';
|
import { GITHUB_PROMPTS_CSV_URL, chatPromptsPath, genCmd } from '@/utils';
|
||||||
|
|
||||||
export default function useEvent() {
|
export default function useEvent() {
|
||||||
const { modelSet } = useChatModel('sys_sync_prompts');
|
const { modelSet } = useChatModel('sync_prompts');
|
||||||
// Using `emit` and `listen` will be triggered multiple times in development mode.
|
// Using `emit` and `listen` will be triggered multiple times in development mode.
|
||||||
// So here we use `eval` to call `__sync_prompt`
|
// So here we use `eval` to call `__sync_prompt`
|
||||||
useInit(() => {
|
useInit(() => {
|
||||||
|
41
src/main.scss
vendored
41
src/main.scss
vendored
@ -23,3 +23,44 @@ html, body {
|
|||||||
width: 50px !important;
|
width: 50px !important;
|
||||||
min-width: 50px !important;
|
min-width: 50px !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.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-add-btn {
|
||||||
|
margin-bottom: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat-prompts-tags {
|
||||||
|
.ant-tag {
|
||||||
|
margin: 2px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat-sync-path {
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #888;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
line-height: 16px;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
15
src/utils.ts
vendored
15
src/utils.ts
vendored
@ -3,7 +3,7 @@ import { homeDir, join, dirname } from '@tauri-apps/api/path';
|
|||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
|
|
||||||
export const CHAT_MODEL_JSON = 'chat.model.json';
|
export const CHAT_MODEL_JSON = 'chat.model.json';
|
||||||
export const CHAT_MODEL_SYNC_JSON = 'chat.model.sync.json';
|
export const CHAT_MODEL_CMD_JSON = 'chat.model.cmd.json';
|
||||||
export const CHAT_PROMPTS_CSV = 'chat.prompts.csv';
|
export const CHAT_PROMPTS_CSV = 'chat.prompts.csv';
|
||||||
export const GITHUB_PROMPTS_CSV_URL = 'https://raw.githubusercontent.com/f/awesome-chatgpt-prompts/main/prompts.csv';
|
export const GITHUB_PROMPTS_CSV_URL = 'https://raw.githubusercontent.com/f/awesome-chatgpt-prompts/main/prompts.csv';
|
||||||
export const DISABLE_AUTO_COMPLETE = {
|
export const DISABLE_AUTO_COMPLETE = {
|
||||||
@ -20,22 +20,23 @@ export const chatModelPath = async (): Promise<string> => {
|
|||||||
return join(await chatRoot(), CHAT_MODEL_JSON);
|
return join(await chatRoot(), CHAT_MODEL_JSON);
|
||||||
}
|
}
|
||||||
|
|
||||||
export const chatModelSyncPath = async (): Promise<string> => {
|
// export const chatModelSyncPath = async (): Promise<string> => {
|
||||||
return join(await chatRoot(), CHAT_MODEL_SYNC_JSON);
|
// return join(await chatRoot(), CHAT_MODEL_SYNC_JSON);
|
||||||
}
|
// }
|
||||||
|
|
||||||
export const chatPromptsPath = async (): Promise<string> => {
|
export const chatPromptsPath = async (): Promise<string> => {
|
||||||
return join(await chatRoot(), CHAT_PROMPTS_CSV);
|
return join(await chatRoot(), CHAT_PROMPTS_CSV);
|
||||||
}
|
}
|
||||||
|
|
||||||
type readJSONOpts = { defaultVal?: Record<string, any>, isRoot?: boolean };
|
type readJSONOpts = { defaultVal?: Record<string, any>, isRoot?: boolean, isList?: boolean };
|
||||||
export const readJSON = async (path: string, opts: readJSONOpts = {}) => {
|
export const readJSON = async (path: string, opts: readJSONOpts = {}) => {
|
||||||
const { defaultVal = {}, isRoot = false } = opts;
|
const { defaultVal = {}, isRoot = false, isList = false } = opts;
|
||||||
const root = await chatRoot();
|
const root = await chatRoot();
|
||||||
const file = await join(isRoot ? '' : root, path);
|
const file = await join(isRoot ? '' : root, path);
|
||||||
|
|
||||||
if (!await exists(file)) {
|
if (!await exists(file)) {
|
||||||
writeTextFile(file, JSON.stringify({
|
await createDir(await dirname(file), { recursive: true });
|
||||||
|
await writeTextFile(file, isList ? '[]' : JSON.stringify({
|
||||||
name: 'ChatGPT',
|
name: 'ChatGPT',
|
||||||
link: 'https://github.com/lencx/ChatGPT',
|
link: 'https://github.com/lencx/ChatGPT',
|
||||||
...defaultVal,
|
...defaultVal,
|
||||||
|
28
src/view/model/SyncCustom/index.scss
vendored
28
src/view/model/SyncCustom/index.scss
vendored
@ -1,28 +0,0 @@
|
|||||||
.chat-prompts-tags {
|
|
||||||
.ant-tag {
|
|
||||||
margin: 2px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.add-btn {
|
|
||||||
margin-bottom: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.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;
|
|
||||||
}
|
|
||||||
}
|
|
22
src/view/model/SyncCustom/index.tsx
vendored
22
src/view/model/SyncCustom/index.tsx
vendored
@ -3,19 +3,19 @@ import { Table, Modal, Button, message } from 'antd';
|
|||||||
import { invoke, http, path, fs } from '@tauri-apps/api';
|
import { invoke, http, path, fs } from '@tauri-apps/api';
|
||||||
|
|
||||||
import useData from '@/hooks/useData';
|
import useData from '@/hooks/useData';
|
||||||
import useChatModel from '@/hooks/useChatModel';
|
import useChatModel, { useCacheModel } 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 { CHAT_MODEL_SYNC_JSON, chatRoot, writeJSON, readJSON, genCmd } from '@/utils';
|
import { CHAT_MODEL_JSON, chatRoot, readJSON, genCmd } from '@/utils';
|
||||||
import { syncColumns, getPath } from './config';
|
import { syncColumns, getPath } from './config';
|
||||||
import SyncForm from './Form';
|
import SyncForm from './Form';
|
||||||
import './index.scss';
|
|
||||||
|
|
||||||
const setTag = (data: Record<string, any>[]) => data.map((i) => ({ ...i, tags: ['user-sync'], enable: true }))
|
const setTag = (data: Record<string, any>[]) => data.map((i) => ({ ...i, tags: ['user-sync'], enable: true }))
|
||||||
|
|
||||||
export default function SyncCustom() {
|
export default function SyncCustom() {
|
||||||
const [isVisible, setVisible] = useState(false);
|
const [isVisible, setVisible] = useState(false);
|
||||||
const { modelData, modelSet } = useChatModel('sync_url', CHAT_MODEL_SYNC_JSON);
|
const { modelData, modelSet } = useChatModel('sync_custom', CHAT_MODEL_JSON);
|
||||||
|
const { modelCacheCmd, modelCacheSet } = useCacheModel();
|
||||||
const { opData, opInit, opAdd, opRemove, opReplace, opSafeKey } = useData([]);
|
const { opData, opInit, opAdd, opRemove, opReplace, opSafeKey } = useData([]);
|
||||||
const { columns, ...opInfo } = useColumns(syncColumns());
|
const { columns, ...opInfo } = useColumns(syncColumns());
|
||||||
const formRef = useRef<any>(null);
|
const formRef = useRef<any>(null);
|
||||||
@ -53,7 +53,7 @@ export default function SyncCustom() {
|
|||||||
const handleSync = async (filename: string) => {
|
const handleSync = async (filename: string) => {
|
||||||
const record = opInfo?.opRecord;
|
const record = opInfo?.opRecord;
|
||||||
const isJson = /json$/.test(record?.ext);
|
const isJson = /json$/.test(record?.ext);
|
||||||
const file = await path.join(await chatRoot(), 'cache_sync', filename);
|
const file = await path.join(await chatRoot(), 'cache_model', filename);
|
||||||
const filePath = await getPath(record);
|
const filePath = await getPath(record);
|
||||||
|
|
||||||
// https or http
|
// https or http
|
||||||
@ -65,13 +65,14 @@ export default function SyncCustom() {
|
|||||||
if (res.ok) {
|
if (res.ok) {
|
||||||
if (isJson) {
|
if (isJson) {
|
||||||
// parse json
|
// parse json
|
||||||
writeJSON(file, setTag(Array.isArray(res?.data) ? res?.data : []), { isRoot: true, dir: 'cache_sync' });
|
await modelCacheSet(setTag(Array.isArray(res?.data) ? res?.data : []), file);
|
||||||
} else {
|
} else {
|
||||||
// parse csv
|
// parse csv
|
||||||
const list: Record<string, string>[] = await invoke('parse_prompt', { data: res?.data });
|
const list: Record<string, string>[] = await invoke('parse_prompt', { data: res?.data });
|
||||||
const fmtList = list.map(i => ({ ...i, cmd: i.cmd ? i.cmd : genCmd(i.act), enable: true, tags: ['user-sync'] }));
|
const fmtList = list.map(i => ({ ...i, cmd: i.cmd ? i.cmd : genCmd(i.act), enable: true, tags: ['user-sync'] }));
|
||||||
await writeJSON(file, fmtList, { isRoot: true, dir: 'cache_sync' });
|
await modelCacheSet(fmtList, file);
|
||||||
}
|
}
|
||||||
|
await modelCacheCmd();
|
||||||
message.success('ChatGPT Prompts data has been synchronized!');
|
message.success('ChatGPT Prompts data has been synchronized!');
|
||||||
} else {
|
} else {
|
||||||
message.error('ChatGPT Prompts data sync failed, please try again!');
|
message.error('ChatGPT Prompts data sync failed, please try again!');
|
||||||
@ -82,14 +83,15 @@ export default function SyncCustom() {
|
|||||||
if (isJson) {
|
if (isJson) {
|
||||||
// parse json
|
// parse json
|
||||||
const data = await readJSON(filePath, { isRoot: true });
|
const data = await readJSON(filePath, { isRoot: true });
|
||||||
await writeJSON(file, setTag(Array.isArray(data) ? data : []), { isRoot: true, dir: 'cache_sync' });
|
await modelCacheSet(setTag(Array.isArray(data) ? data : []), file);
|
||||||
} else {
|
} else {
|
||||||
// parse csv
|
// parse csv
|
||||||
const data = await fs.readTextFile(filePath);
|
const data = await fs.readTextFile(filePath);
|
||||||
const list: Record<string, string>[] = await invoke('parse_prompt', { data });
|
const list: Record<string, string>[] = await invoke('parse_prompt', { data });
|
||||||
const fmtList = list.map(i => ({ ...i, cmd: i.cmd ? i.cmd : genCmd(i.act), enable: true, tags: ['user-sync'] }));
|
const fmtList = list.map(i => ({ ...i, cmd: i.cmd ? i.cmd : genCmd(i.act), enable: true, tags: ['user-sync'] }));
|
||||||
await writeJSON(file, fmtList, { isRoot: true, dir: 'cache_sync' });
|
await modelCacheSet(fmtList, file);
|
||||||
}
|
}
|
||||||
|
await modelCacheCmd();
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleOk = () => {
|
const handleOk = () => {
|
||||||
@ -109,7 +111,7 @@ export default function SyncCustom() {
|
|||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<Button
|
<Button
|
||||||
className="add-btn"
|
className="chat-add-btn"
|
||||||
type="primary"
|
type="primary"
|
||||||
onClick={opInfo.opNew}
|
onClick={opInfo.opNew}
|
||||||
>
|
>
|
||||||
|
29
src/view/model/SyncPrompts/index.scss
vendored
29
src/view/model/SyncPrompts/index.scss
vendored
@ -1,13 +1,3 @@
|
|||||||
.chat-prompts-tags {
|
|
||||||
.ant-tag {
|
|
||||||
margin: 2px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.add-btn {
|
|
||||||
margin-bottom: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.chat-table-tip, .chat-table-btns {
|
.chat-table-tip, .chat-table-btns {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
@ -20,22 +10,3 @@
|
|||||||
margin-left: 10px;
|
margin-left: 10px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.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;
|
|
||||||
}
|
|
||||||
}
|
|
57
src/view/model/SyncPrompts/index.tsx
vendored
57
src/view/model/SyncPrompts/index.tsx
vendored
@ -1,14 +1,13 @@
|
|||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { Table, Button, message, Popconfirm } from 'antd';
|
import { Table, Button, message, Popconfirm } from 'antd';
|
||||||
import { invoke } from '@tauri-apps/api';
|
import { invoke, http, path, shell } from '@tauri-apps/api';
|
||||||
import { fetch, ResponseType } from '@tauri-apps/api/http';
|
|
||||||
import { writeTextFile } from '@tauri-apps/api/fs';
|
|
||||||
|
|
||||||
import useColumns from '@/hooks/useColumns';
|
import useInit from '@/hooks/useInit';
|
||||||
import useData from '@/hooks/useData';
|
import useData from '@/hooks/useData';
|
||||||
import useChatModel from '@/hooks/useChatModel';
|
import useColumns from '@/hooks/useColumns';
|
||||||
|
import useChatModel, { useCacheModel } from '@/hooks/useChatModel';
|
||||||
import useTable, { TABLE_PAGINATION } from '@/hooks/useTable';
|
import useTable, { TABLE_PAGINATION } from '@/hooks/useTable';
|
||||||
import { fmtDate, chatPromptsPath, GITHUB_PROMPTS_CSV_URL, genCmd } from '@/utils';
|
import { fmtDate, chatRoot, GITHUB_PROMPTS_CSV_URL, genCmd } from '@/utils';
|
||||||
import { syncColumns } from './config';
|
import { syncColumns } from './config';
|
||||||
import './index.scss';
|
import './index.scss';
|
||||||
|
|
||||||
@ -16,36 +15,39 @@ const promptsURL = 'https://github.com/f/awesome-chatgpt-prompts/blob/main/promp
|
|||||||
|
|
||||||
export default function SyncPrompts() {
|
export default function SyncPrompts() {
|
||||||
const { rowSelection, selectedRowIDs } = useTable();
|
const { rowSelection, selectedRowIDs } = useTable();
|
||||||
const [lastUpdated, setLastUpdated] = useState();
|
const [jsonPath, setJsonPath] = useState('');
|
||||||
const { modelJson, modelSet } = useChatModel('sys_sync_prompts');
|
const { modelJson, modelSet } = useChatModel('sync_prompts');
|
||||||
|
const { modelCacheJson, modelCacheSet } = useCacheModel(jsonPath);
|
||||||
const { opData, opInit, opReplace, opReplaceItems, opSafeKey } = useData([]);
|
const { opData, opInit, opReplace, opReplaceItems, opSafeKey } = useData([]);
|
||||||
const { columns, ...opInfo } = useColumns(syncColumns());
|
const { columns, ...opInfo } = useColumns(syncColumns());
|
||||||
|
const lastUpdated = modelJson?.sync_prompts?.last_updated;
|
||||||
const selectedItems = rowSelection.selectedRowKeys || [];
|
const selectedItems = rowSelection.selectedRowKeys || [];
|
||||||
|
|
||||||
|
useInit(async () => {
|
||||||
|
setJsonPath(await path.join(await chatRoot(), 'cache_model', 'chatgpt_prompts.json'));
|
||||||
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!modelJson?.sys_sync_prompts) return;
|
if (modelCacheJson.length <= 0) return;
|
||||||
opInit(modelJson?.sys_sync_prompts);
|
opInit(modelCacheJson);
|
||||||
if (lastUpdated) return;
|
}, [modelCacheJson.length]);
|
||||||
(async () => {
|
|
||||||
const fileData: Record<string, any> = await invoke('metadata', { path: await chatPromptsPath() });
|
|
||||||
setLastUpdated(fileData.accessedAtMs);
|
|
||||||
})();
|
|
||||||
}, [modelJson?.sys_sync_prompts])
|
|
||||||
|
|
||||||
const handleSync = async () => {
|
const handleSync = async () => {
|
||||||
const res = await fetch(GITHUB_PROMPTS_CSV_URL, {
|
const res = await http.fetch(GITHUB_PROMPTS_CSV_URL, {
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
responseType: ResponseType.Text,
|
responseType: http.ResponseType.Text,
|
||||||
});
|
});
|
||||||
const data = (res.data || '') as string;
|
const data = (res.data || '') as string;
|
||||||
if (res.ok) {
|
if (res.ok) {
|
||||||
// const content = data.replace(/"(\s+)?,(\s+)?"/g, '","');
|
// const content = data.replace(/"(\s+)?,(\s+)?"/g, '","');
|
||||||
await writeTextFile(await chatPromptsPath(), data);
|
|
||||||
const list: Record<string, string>[] = await invoke('parse_prompt', { data });
|
const list: Record<string, string>[] = await invoke('parse_prompt', { data });
|
||||||
opInit(list);
|
const fmtList = list.map(i => ({ ...i, cmd: i.cmd ? i.cmd : genCmd(i.act), enable: true, tags: ['chatgpt-prompts'] }));
|
||||||
modelSet(list.map(i => ({ ...i, cmd: i.cmd ? i.cmd : genCmd(i.act), enable: true, tags: ['chatgpt-prompts'] })));
|
await modelCacheSet(fmtList);
|
||||||
setLastUpdated(fmtDate(Date.now()) as any);
|
opInit(fmtList);
|
||||||
|
modelSet({
|
||||||
|
id: 'chatgpt_prompts',
|
||||||
|
last_updated: Date.now(),
|
||||||
|
});
|
||||||
message.success('ChatGPT Prompts data has been synchronized!');
|
message.success('ChatGPT Prompts data has been synchronized!');
|
||||||
} else {
|
} else {
|
||||||
message.error('ChatGPT Prompts data sync failed, please try again!');
|
message.error('ChatGPT Prompts data sync failed, please try again!');
|
||||||
@ -55,13 +57,13 @@ export default function SyncPrompts() {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (opInfo.opType === 'enable') {
|
if (opInfo.opType === 'enable') {
|
||||||
const data = opReplace(opInfo?.opRecord?.[opSafeKey], opInfo?.opRecord);
|
const data = opReplace(opInfo?.opRecord?.[opSafeKey], opInfo?.opRecord);
|
||||||
modelSet(data);
|
modelCacheSet(data);
|
||||||
}
|
}
|
||||||
}, [opInfo.opTime]);
|
}, [opInfo.opTime]);
|
||||||
|
|
||||||
const handleEnable = (isEnable: boolean) => {
|
const handleEnable = (isEnable: boolean) => {
|
||||||
const data = opReplaceItems(selectedRowIDs, { enable: isEnable })
|
const data = opReplaceItems(selectedRowIDs, { enable: isEnable })
|
||||||
modelSet(data);
|
modelCacheSet(data);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -87,7 +89,10 @@ export default function SyncPrompts() {
|
|||||||
</Popconfirm>
|
</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>
|
<div className="chat-sync-path">
|
||||||
|
<div>PATH: <a onClick={() => shell.open(promptsURL)} target="_blank" title={promptsURL}>f/awesome-chatgpt-prompts/prompts.csv</a></div>
|
||||||
|
<div>CACHE: <a onClick={() => shell.open(jsonPath)} target="_blank" title={jsonPath}>{jsonPath}</a></div>
|
||||||
|
</div>
|
||||||
{lastUpdated && <span style={{ marginLeft: 10, color: '#888', fontSize: 12 }}>Last updated on {fmtDate(lastUpdated)}</span>}
|
{lastUpdated && <span style={{ marginLeft: 10, color: '#888', fontSize: 12 }}>Last updated on {fmtDate(lastUpdated)}</span>}
|
||||||
</div>
|
</div>
|
||||||
<Table
|
<Table
|
||||||
|
42
src/view/model/SyncRecord/index.scss
vendored
42
src/view/model/SyncRecord/index.scss
vendored
@ -1,42 +0,0 @@
|
|||||||
// .chat-prompts-tags {
|
|
||||||
// .ant-tag {
|
|
||||||
// margin: 2px;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// .add-btn {
|
|
||||||
// margin-bottom: 5px;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// .chat-table-tip, .chat-table-btns {
|
|
||||||
// display: flex;
|
|
||||||
// justify-content: space-between;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// .chat-table-btns {
|
|
||||||
// margin-bottom: 5px;
|
|
||||||
|
|
||||||
// .num {
|
|
||||||
// margin-left: 10px;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
.chat-sync-path {
|
|
||||||
font-size: 12px;
|
|
||||||
font-weight: 500;
|
|
||||||
color: #888;
|
|
||||||
margin-bottom: 5px;
|
|
||||||
line-height: 16px;
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
15
src/view/model/SyncRecord/index.tsx
vendored
15
src/view/model/SyncRecord/index.tsx
vendored
@ -12,7 +12,6 @@ import { fmtDate, chatRoot } from '@/utils';
|
|||||||
import { getPath } from '@/view/model/SyncCustom/config';
|
import { getPath } from '@/view/model/SyncCustom/config';
|
||||||
import { syncColumns } from './config';
|
import { syncColumns } from './config';
|
||||||
import useInit from '@/hooks/useInit';
|
import useInit from '@/hooks/useInit';
|
||||||
import './index.scss';
|
|
||||||
|
|
||||||
export default function SyncRecord() {
|
export default function SyncRecord() {
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
@ -21,7 +20,7 @@ export default function SyncRecord() {
|
|||||||
const state = location?.state;
|
const state = location?.state;
|
||||||
|
|
||||||
const { rowSelection, selectedRowIDs } = useTable();
|
const { rowSelection, selectedRowIDs } = useTable();
|
||||||
const { modelJson, modelSet } = useCacheModel(jsonPath);
|
const { modelCacheJson, modelCacheSet } = useCacheModel(jsonPath);
|
||||||
const { opData, opInit, opReplace, opReplaceItems, opSafeKey } = useData([]);
|
const { opData, opInit, opReplace, opReplaceItems, opSafeKey } = useData([]);
|
||||||
const { columns, ...opInfo } = useColumns(syncColumns());
|
const { columns, ...opInfo } = useColumns(syncColumns());
|
||||||
|
|
||||||
@ -29,24 +28,24 @@ export default function SyncRecord() {
|
|||||||
|
|
||||||
useInit(async () => {
|
useInit(async () => {
|
||||||
setFilePath(await getPath(state));
|
setFilePath(await getPath(state));
|
||||||
setJsonPath(await path.join(await chatRoot(), 'cache_sync', `${state?.id}.json`));
|
setJsonPath(await path.join(await chatRoot(), 'cache_model', `${state?.id}.json`));
|
||||||
})
|
})
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (modelJson.length <= 0) return;
|
if (modelCacheJson.length <= 0) return;
|
||||||
opInit(modelJson);
|
opInit(modelCacheJson);
|
||||||
}, [modelJson.length]);
|
}, [modelCacheJson.length]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (opInfo.opType === 'enable') {
|
if (opInfo.opType === 'enable') {
|
||||||
const data = opReplace(opInfo?.opRecord?.[opSafeKey], opInfo?.opRecord);
|
const data = opReplace(opInfo?.opRecord?.[opSafeKey], opInfo?.opRecord);
|
||||||
modelSet(data);
|
modelCacheSet(data);
|
||||||
}
|
}
|
||||||
}, [opInfo.opTime]);
|
}, [opInfo.opTime]);
|
||||||
|
|
||||||
const handleEnable = (isEnable: boolean) => {
|
const handleEnable = (isEnable: boolean) => {
|
||||||
const data = opReplaceItems(selectedRowIDs, { enable: isEnable })
|
const data = opReplaceItems(selectedRowIDs, { enable: isEnable })
|
||||||
modelSet(data);
|
modelCacheSet(data);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
39
src/view/model/UserCustom/index.scss
vendored
39
src/view/model/UserCustom/index.scss
vendored
@ -1,39 +0,0 @@
|
|||||||
.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;
|
|
||||||
}
|
|
||||||
}
|
|
89
src/view/model/UserCustom/index.tsx
vendored
89
src/view/model/UserCustom/index.tsx
vendored
@ -1,29 +1,36 @@
|
|||||||
import { useState, useRef, useEffect } from 'react';
|
import { useState, useRef, useEffect } from 'react';
|
||||||
import { Table, Button, Modal, message } from 'antd';
|
import { Table, Button, Modal, message } from 'antd';
|
||||||
import { invoke } from '@tauri-apps/api';
|
import { shell, path } from '@tauri-apps/api';
|
||||||
|
|
||||||
import useInit from '@/hooks/useInit';
|
import useInit from '@/hooks/useInit';
|
||||||
import useData from '@/hooks/useData';
|
import useData from '@/hooks/useData';
|
||||||
import useChatModel from '@/hooks/useChatModel';
|
import useChatModel, { useCacheModel } from '@/hooks/useChatModel';
|
||||||
import useColumns from '@/hooks/useColumns';
|
import useColumns from '@/hooks/useColumns';
|
||||||
import { TABLE_PAGINATION } from '@/hooks/useTable';
|
import useTable, { TABLE_PAGINATION } from '@/hooks/useTable';
|
||||||
import { chatModelPath } from '@/utils';
|
import { chatRoot, fmtDate } from '@/utils';
|
||||||
import { modelColumns } from './config';
|
import { modelColumns } from './config';
|
||||||
import UserCustomForm from './Form';
|
import UserCustomForm from './Form';
|
||||||
import './index.scss';
|
|
||||||
|
|
||||||
export default function LanguageModel() {
|
export default function LanguageModel() {
|
||||||
|
const { rowSelection, selectedRowIDs } = useTable();
|
||||||
const [isVisible, setVisible] = useState(false);
|
const [isVisible, setVisible] = useState(false);
|
||||||
const [modelPath, setChatModelPath] = useState('');
|
const [jsonPath, setJsonPath] = useState('');
|
||||||
const { modelData, modelSet } = useChatModel('user_custom');
|
const { modelJson, modelSet } = useChatModel('user_custom');
|
||||||
const { opData, opInit, opAdd, opRemove, opReplace, opSafeKey } = useData([]);
|
const { modelCacheJson, modelCacheSet } = useCacheModel(jsonPath);
|
||||||
|
const { opData, opInit, opReplaceItems, opAdd, opRemove, opReplace, opSafeKey } = useData([]);
|
||||||
const { columns, ...opInfo } = useColumns(modelColumns());
|
const { columns, ...opInfo } = useColumns(modelColumns());
|
||||||
|
const lastUpdated = modelJson?.user_custom?.last_updated;
|
||||||
|
const selectedItems = rowSelection.selectedRowKeys || [];
|
||||||
const formRef = useRef<any>(null);
|
const formRef = useRef<any>(null);
|
||||||
|
|
||||||
|
useInit(async () => {
|
||||||
|
setJsonPath(await path.join(await chatRoot(), 'cache_model', 'user_custom.json'));
|
||||||
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (modelData.length <= 0) return;
|
if (modelCacheJson.length <= 0) return;
|
||||||
opInit(modelData);
|
opInit(modelCacheJson);
|
||||||
}, [modelData]);
|
}, [modelCacheJson.length]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!opInfo.opType) return;
|
if (!opInfo.opType) return;
|
||||||
@ -32,7 +39,7 @@ export default function LanguageModel() {
|
|||||||
}
|
}
|
||||||
if (['delete'].includes(opInfo.opType)) {
|
if (['delete'].includes(opInfo.opType)) {
|
||||||
const data = opRemove(opInfo?.opRecord?.[opSafeKey]);
|
const data = opRemove(opInfo?.opRecord?.[opSafeKey]);
|
||||||
modelSet(data);
|
modelCacheSet(data);
|
||||||
opInfo.resetRecord();
|
opInfo.resetRecord();
|
||||||
}
|
}
|
||||||
}, [opInfo.opType, formRef]);
|
}, [opInfo.opType, formRef]);
|
||||||
@ -40,14 +47,22 @@ export default function LanguageModel() {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (opInfo.opType === 'enable') {
|
if (opInfo.opType === 'enable') {
|
||||||
const data = opReplace(opInfo?.opRecord?.[opSafeKey], opInfo?.opRecord);
|
const data = opReplace(opInfo?.opRecord?.[opSafeKey], opInfo?.opRecord);
|
||||||
modelSet(data);
|
modelCacheSet(data);
|
||||||
}
|
}
|
||||||
}, [opInfo.opTime])
|
}, [opInfo.opTime])
|
||||||
|
|
||||||
useInit(async () => {
|
|
||||||
const path = await chatModelPath();
|
useEffect(() => {
|
||||||
setChatModelPath(path);
|
if (opInfo.opType === 'enable') {
|
||||||
})
|
const data = opReplace(opInfo?.opRecord?.[opSafeKey], opInfo?.opRecord);
|
||||||
|
modelCacheSet(data);
|
||||||
|
}
|
||||||
|
}, [opInfo.opTime]);
|
||||||
|
|
||||||
|
const handleEnable = (isEnable: boolean) => {
|
||||||
|
const data = opReplaceItems(selectedRowIDs, { enable: isEnable })
|
||||||
|
modelCacheSet(data);
|
||||||
|
};
|
||||||
|
|
||||||
const hide = () => {
|
const hide = () => {
|
||||||
setVisible(false);
|
setVisible(false);
|
||||||
@ -56,8 +71,8 @@ export default function LanguageModel() {
|
|||||||
|
|
||||||
const handleOk = () => {
|
const handleOk = () => {
|
||||||
formRef.current?.form?.validateFields()
|
formRef.current?.form?.validateFields()
|
||||||
.then((vals: Record<string, any>) => {
|
.then(async (vals: Record<string, any>) => {
|
||||||
if (modelData.map((i: any) => i.cmd).includes(vals.cmd) && opInfo?.opRecord?.cmd !== vals.cmd) {
|
if (modelCacheJson.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.`);
|
message.warning(`"cmd: /${vals.cmd}" already exists, please change the "${vals.cmd}" name and resubmit.`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -67,28 +82,46 @@ export default function LanguageModel() {
|
|||||||
case 'edit': data = opReplace(opInfo?.opRecord?.[opSafeKey], vals); break;
|
case 'edit': data = opReplace(opInfo?.opRecord?.[opSafeKey], vals); break;
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
modelSet(data);
|
await modelCacheSet(data);
|
||||||
opInfo.setExtra(Date.now());
|
opInit(data);
|
||||||
|
modelSet({
|
||||||
|
id: 'user_custom',
|
||||||
|
last_updated: Date.now(),
|
||||||
|
});
|
||||||
hide();
|
hide();
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleOpenFile = () => {
|
|
||||||
invoke('open_file', { path: modelPath });
|
|
||||||
};
|
|
||||||
|
|
||||||
const modalTitle = `${({ new: 'Create', edit: 'Edit' })[opInfo.opType]} Model`;
|
const modalTitle = `${({ new: 'Create', edit: 'Edit' })[opInfo.opType]} Model`;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<Button className="add-btn" type="primary" onClick={opInfo.opNew}>Add Model</Button>
|
<div className="chat-table-btns">
|
||||||
<div className="chat-model-path">PATH: <span onClick={handleOpenFile}>{modelPath}</span></div>
|
<Button className="chat-add-btn" type="primary" onClick={opInfo.opNew}>Add Model</Button>
|
||||||
|
<div>
|
||||||
|
{selectedItems.length > 0 && (
|
||||||
|
<>
|
||||||
|
<Button type="primary" onClick={() => handleEnable(true)}>Enable</Button>
|
||||||
|
<Button onClick={() => handleEnable(false)}>Disable</Button>
|
||||||
|
<span className="num">Selected {selectedItems.length} items</span>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/* <div className="chat-model-path">PATH: <span onClick={handleOpenFile}>{modelPath}</span></div> */}
|
||||||
|
<div className="chat-table-tip">
|
||||||
|
<div className="chat-sync-path">
|
||||||
|
<div>CACHE: <a onClick={() => shell.open(jsonPath)} title={jsonPath}>{jsonPath}</a></div>
|
||||||
|
</div>
|
||||||
|
{lastUpdated && <span style={{ marginLeft: 10, color: '#888', fontSize: 12 }}>Last updated on {fmtDate(lastUpdated)}</span>}
|
||||||
|
</div>
|
||||||
<Table
|
<Table
|
||||||
key={opInfo.opExtra}
|
key={lastUpdated}
|
||||||
rowKey="cmd"
|
rowKey="cmd"
|
||||||
columns={columns}
|
columns={columns}
|
||||||
scroll={{ x: 'auto' }}
|
scroll={{ x: 'auto' }}
|
||||||
dataSource={opData}
|
dataSource={opData}
|
||||||
|
rowSelection={rowSelection}
|
||||||
pagination={TABLE_PAGINATION}
|
pagination={TABLE_PAGINATION}
|
||||||
/>
|
/>
|
||||||
<Modal
|
<Modal
|
||||||
|
Loading…
Reference in New Issue
Block a user