mirror of
https://github.com/lencx/ChatGPT.git
synced 2024-10-01 01:06:13 -04:00
Merge pull request #115 from lencx/dev
This commit is contained in:
commit
74c0d07a76
@ -22,9 +22,9 @@
|
||||
|
||||
**最新版:**
|
||||
|
||||
- `Mac`: [ChatGPT_0.7.3_x64.dmg](https://github.com/lencx/ChatGPT/releases/download/v0.7.3/ChatGPT_0.7.3_x64.dmg)
|
||||
- `Linux`: [chat-gpt_0.7.3_amd64.deb](https://github.com/lencx/ChatGPT/releases/download/v0.7.3/chat-gpt_0.7.3_amd64.deb)
|
||||
- `Windows`: [ChatGPT_0.7.3_x64_en-US.msi](https://github.com/lencx/ChatGPT/releases/download/v0.7.3/ChatGPT_0.7.3_x64_en-US.msi)
|
||||
- `Mac`: [ChatGPT_0.7.4_x64.dmg](https://github.com/lencx/ChatGPT/releases/download/v0.7.4/ChatGPT_0.7.4_x64.dmg)
|
||||
- `Linux`: [chat-gpt_0.7.4_amd64.deb](https://github.com/lencx/ChatGPT/releases/download/v0.7.4/chat-gpt_0.7.4_amd64.deb)
|
||||
- `Windows`: [ChatGPT_0.7.4_x64_en-US.msi](https://github.com/lencx/ChatGPT/releases/download/v0.7.4/ChatGPT_0.7.4_x64_en-US.msi)
|
||||
|
||||
[其他版本...](https://github.com/lencx/ChatGPT/releases)
|
||||
|
||||
@ -74,7 +74,7 @@ cask "popcorn-time", args: { "no-quarantine": true }
|
||||
- 系统托盘悬浮窗
|
||||
- 应用菜单功能强大
|
||||
- 支持斜杠命令及其配置(可手动配置或从文件同步 [#55](https://github.com/lencx/ChatGPT/issues/55))
|
||||
- 进入应用的全局快捷键 (mac: `Command + Shift + O`, windows: `Ctrl + Shift + O`)
|
||||
- 自定义全局快捷键 ([#108](https://github.com/lencx/ChatGPT/issues/108))
|
||||
|
||||
### 菜单项
|
||||
|
||||
|
@ -24,9 +24,9 @@
|
||||
|
||||
**Latest:**
|
||||
|
||||
- `Mac`: [ChatGPT_0.7.3_x64.dmg](https://github.com/lencx/ChatGPT/releases/download/v0.7.3/ChatGPT_0.7.3_x64.dmg)
|
||||
- `Linux`: [chat-gpt_0.7.3_amd64.deb](https://github.com/lencx/ChatGPT/releases/download/v0.7.3/chat-gpt_0.7.3_amd64.deb)
|
||||
- `Windows`: [ChatGPT_0.7.3_x64_en-US.msi](https://github.com/lencx/ChatGPT/releases/download/v0.7.3/ChatGPT_0.7.3_x64_en-US.msi)
|
||||
- `Mac`: [ChatGPT_0.7.4_x64.dmg](https://github.com/lencx/ChatGPT/releases/download/v0.7.4/ChatGPT_0.7.4_x64.dmg)
|
||||
- `Linux`: [chat-gpt_0.7.4_amd64.deb](https://github.com/lencx/ChatGPT/releases/download/v0.7.4/chat-gpt_0.7.4_amd64.deb)
|
||||
- `Windows`: [ChatGPT_0.7.4_x64_en-US.msi](https://github.com/lencx/ChatGPT/releases/download/v0.7.4/ChatGPT_0.7.4_x64_en-US.msi)
|
||||
|
||||
[Other version...](https://github.com/lencx/ChatGPT/releases)
|
||||
|
||||
@ -76,7 +76,7 @@ In the chatgpt text input area, type a character starting with `/` to bring up t
|
||||
- System tray hover window
|
||||
- Powerful menu items
|
||||
- Support for slash commands and their configuration (can be configured manually or synchronized from a file [#55](https://github.com/lencx/ChatGPT/issues/55))
|
||||
- Global shortcuts to the chatgpt app (mac: `Command + Shift + O`, windows: `Ctrl + Shift + O`)
|
||||
- Customize global shortcuts ([#108](https://github.com/lencx/ChatGPT/issues/108))
|
||||
|
||||
### MenuItem
|
||||
|
||||
|
@ -1,5 +1,11 @@
|
||||
# UPDATE LOG
|
||||
|
||||
## v0.7.4
|
||||
|
||||
fix:
|
||||
- trying to resolve linux errors: `error while loading shared libraries`
|
||||
- customize global shortcuts (`Menu -> Preferences -> Control Center -> General -> Global Shortcut`)
|
||||
|
||||
## v0.7.3
|
||||
|
||||
chore:
|
||||
|
@ -25,7 +25,8 @@ thiserror = "1.0.38"
|
||||
walkdir = "2.3.2"
|
||||
regex = "1.7.0"
|
||||
tokio = { version = "1.23.0", features = ["macros"] }
|
||||
# reqwest = "0.11.13"
|
||||
reqwest = "0.11.13"
|
||||
wry = "0.23.4"
|
||||
|
||||
[dependencies.tauri-plugin-log]
|
||||
git = "https://github.com/tauri-apps/tauri-plugin-log"
|
||||
|
@ -1,7 +1,8 @@
|
||||
use crate::{
|
||||
conf::ChatConfJson,
|
||||
conf::{ChatConfJson, GITHUB_PROMPTS_CSV_URL},
|
||||
utils::{self, exists},
|
||||
};
|
||||
use log::info;
|
||||
use std::{collections::HashMap, fs, path::PathBuf};
|
||||
use tauri::{api, command, AppHandle, Manager};
|
||||
|
||||
@ -87,8 +88,17 @@ pub fn parse_prompt(data: String) -> Vec<PromptRecord> {
|
||||
let mut rdr = csv::Reader::from_reader(data.as_bytes());
|
||||
let mut list = vec![];
|
||||
for result in rdr.deserialize() {
|
||||
let record: PromptRecord = result.unwrap();
|
||||
list.push(record);
|
||||
let record: PromptRecord = result.unwrap_or_else(|err| {
|
||||
info!("parse_prompt_error: {}", err);
|
||||
PromptRecord {
|
||||
cmd: None,
|
||||
act: "".to_string(),
|
||||
prompt: "".to_string(),
|
||||
}
|
||||
});
|
||||
if !record.act.is_empty() {
|
||||
list.push(record);
|
||||
}
|
||||
}
|
||||
list
|
||||
}
|
||||
@ -134,75 +144,133 @@ pub fn cmd_list() -> Vec<ModelRecord> {
|
||||
}
|
||||
|
||||
#[command]
|
||||
pub fn sync_prompts(app: AppHandle, data: String, time: u64) {
|
||||
let data = parse_prompt(data)
|
||||
.iter()
|
||||
.map(move |i| ModelRecord {
|
||||
cmd: if i.cmd.is_some() {
|
||||
i.cmd.clone().unwrap()
|
||||
} else {
|
||||
utils::gen_cmd(i.act.clone())
|
||||
},
|
||||
act: i.act.clone(),
|
||||
prompt: i.prompt.clone(),
|
||||
tags: vec!["chatgpt-prompts".to_string()],
|
||||
enable: true,
|
||||
})
|
||||
.collect::<Vec<ModelRecord>>();
|
||||
pub async fn sync_prompts(app: AppHandle, time: u64) -> Option<Vec<ModelRecord>> {
|
||||
let res = utils::get_data(GITHUB_PROMPTS_CSV_URL, Some(&app))
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let model = chat_root().join("chat.model.json");
|
||||
let model_cmd = chat_root().join("chat.model.cmd.json");
|
||||
let chatgpt_prompts = chat_root().join("cache_model").join("chatgpt_prompts.json");
|
||||
|
||||
if !exists(&model) {
|
||||
fs::write(
|
||||
&model,
|
||||
serde_json::json!({
|
||||
"name": "ChatGPT Model",
|
||||
"link": "https://github.com/lencx/ChatGPT"
|
||||
if let Some(v) = res {
|
||||
let data = parse_prompt(v)
|
||||
.iter()
|
||||
.map(move |i| ModelRecord {
|
||||
cmd: if i.cmd.is_some() {
|
||||
i.cmd.clone().unwrap()
|
||||
} else {
|
||||
utils::gen_cmd(i.act.clone())
|
||||
},
|
||||
act: i.act.clone(),
|
||||
prompt: i.prompt.clone(),
|
||||
tags: vec!["chatgpt-prompts".to_string()],
|
||||
enable: true,
|
||||
})
|
||||
.to_string(),
|
||||
.collect::<Vec<ModelRecord>>();
|
||||
|
||||
let data2 = data.clone();
|
||||
|
||||
let model = chat_root().join("chat.model.json");
|
||||
let model_cmd = chat_root().join("chat.model.cmd.json");
|
||||
let chatgpt_prompts = chat_root().join("cache_model").join("chatgpt_prompts.json");
|
||||
|
||||
if !exists(&model) {
|
||||
fs::write(
|
||||
&model,
|
||||
serde_json::json!({
|
||||
"name": "ChatGPT Model",
|
||||
"link": "https://github.com/lencx/ChatGPT"
|
||||
})
|
||||
.to_string(),
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
// chatgpt_prompts.json
|
||||
fs::write(
|
||||
chatgpt_prompts,
|
||||
serde_json::to_string_pretty(&data).unwrap(),
|
||||
)
|
||||
.unwrap();
|
||||
let cmd_data = cmd_list();
|
||||
|
||||
// chat.model.cmd.json
|
||||
fs::write(
|
||||
model_cmd,
|
||||
serde_json::to_string_pretty(&serde_json::json!({
|
||||
"name": "ChatGPT CMD",
|
||||
"last_updated": time,
|
||||
"data": cmd_data,
|
||||
}))
|
||||
.unwrap(),
|
||||
)
|
||||
.unwrap();
|
||||
let mut kv = HashMap::new();
|
||||
kv.insert(
|
||||
"sync_prompts".to_string(),
|
||||
serde_json::json!({ "id": "chatgpt_prompts", "last_updated": time }),
|
||||
);
|
||||
let model_data = utils::merge(
|
||||
&serde_json::from_str(&fs::read_to_string(&model).unwrap()).unwrap(),
|
||||
&kv,
|
||||
);
|
||||
|
||||
// chat.model.json
|
||||
fs::write(model, serde_json::to_string_pretty(&model_data).unwrap()).unwrap();
|
||||
|
||||
// refresh window
|
||||
api::dialog::message(
|
||||
app.get_window("core").as_ref(),
|
||||
"Sync Prompts",
|
||||
"ChatGPT Prompts data has been synchronized!",
|
||||
);
|
||||
window_reload(app, "core");
|
||||
|
||||
return Some(data2);
|
||||
}
|
||||
|
||||
// chatgpt_prompts.json
|
||||
fs::write(
|
||||
chatgpt_prompts,
|
||||
serde_json::to_string_pretty(&data).unwrap(),
|
||||
)
|
||||
.unwrap();
|
||||
let cmd_data = cmd_list();
|
||||
|
||||
// chat.model.cmd.json
|
||||
fs::write(
|
||||
model_cmd,
|
||||
serde_json::to_string_pretty(&serde_json::json!({
|
||||
"name": "ChatGPT CMD",
|
||||
"last_updated": time,
|
||||
"data": cmd_data,
|
||||
}))
|
||||
.unwrap(),
|
||||
)
|
||||
.unwrap();
|
||||
let mut kv = HashMap::new();
|
||||
kv.insert(
|
||||
"sync_prompts".to_string(),
|
||||
serde_json::json!({ "id": "chatgpt_prompts", "last_updated": time }),
|
||||
);
|
||||
let model_data = utils::merge(
|
||||
&serde_json::from_str(&fs::read_to_string(&model).unwrap()).unwrap(),
|
||||
&kv,
|
||||
);
|
||||
|
||||
// chat.model.json
|
||||
fs::write(model, serde_json::to_string_pretty(&model_data).unwrap()).unwrap();
|
||||
|
||||
// refresh window
|
||||
api::dialog::message(
|
||||
app.get_window("core").as_ref(),
|
||||
"Sync Prompts",
|
||||
"ChatGPT Prompts data has been synchronized!",
|
||||
);
|
||||
window_reload(app, "core");
|
||||
None
|
||||
}
|
||||
|
||||
#[command]
|
||||
pub async fn sync_user_prompts(url: String, data_type: String) -> Option<Vec<ModelRecord>> {
|
||||
let res = utils::get_data(&url, None).await.unwrap_or_else(|err| {
|
||||
info!("chatgpt_http_error: {}", err);
|
||||
None
|
||||
});
|
||||
|
||||
info!("chatgpt_http_url: {}", url);
|
||||
|
||||
if let Some(v) = res {
|
||||
let data;
|
||||
if data_type == "csv" {
|
||||
info!("chatgpt_http_csv_parse");
|
||||
data = parse_prompt(v);
|
||||
} else if data_type == "json" {
|
||||
info!("chatgpt_http_json_parse");
|
||||
data = serde_json::from_str(&v).unwrap_or_else(|err| {
|
||||
info!("chatgpt_http_json_parse_error: {}", err);
|
||||
vec![]
|
||||
});
|
||||
} else {
|
||||
info!("chatgpt_http_unknown_type");
|
||||
data = vec![];
|
||||
}
|
||||
|
||||
let data = data
|
||||
.iter()
|
||||
.map(move |i| ModelRecord {
|
||||
cmd: if i.cmd.is_some() {
|
||||
i.cmd.clone().unwrap()
|
||||
} else {
|
||||
utils::gen_cmd(i.act.clone())
|
||||
},
|
||||
act: i.act.clone(),
|
||||
prompt: i.prompt.clone(),
|
||||
tags: vec!["user-sync".to_string()],
|
||||
enable: true,
|
||||
})
|
||||
.collect::<Vec<ModelRecord>>();
|
||||
|
||||
return Some(data);
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
use crate::{app::window, conf::ChatConfJson, utils};
|
||||
use log::info;
|
||||
use tauri::{utils::config::WindowUrl, window::WindowBuilder, App, GlobalShortcutManager, Manager};
|
||||
use wry::application::accelerator::Accelerator;
|
||||
|
||||
pub fn init(app: &mut App) -> std::result::Result<(), Box<dyn std::error::Error>> {
|
||||
info!("stepup");
|
||||
@ -13,30 +14,35 @@ pub fn init(app: &mut App) -> std::result::Result<(), Box<dyn std::error::Error>
|
||||
window::tray_window(&handle);
|
||||
});
|
||||
|
||||
{
|
||||
info!("global_shortcut_start");
|
||||
let handle = app.app_handle();
|
||||
let mut shortcut = app.global_shortcut_manager();
|
||||
let core_shortcut = shortcut.is_registered("CmdOrCtrl+Shift+O");
|
||||
|
||||
info!("is_registered: {}", core_shortcut.is_ok());
|
||||
|
||||
if core_shortcut.is_ok() {
|
||||
shortcut
|
||||
.register("CmdOrCtrl+Shift+O", move || {
|
||||
if let Some(w) = handle.get_window("core") {
|
||||
if w.is_visible().unwrap() {
|
||||
w.hide().unwrap();
|
||||
} else {
|
||||
w.show().unwrap();
|
||||
w.set_focus().unwrap();
|
||||
if let Some(v) = chat_conf.global_shortcut {
|
||||
info!("global_shortcut: `{}`", v);
|
||||
match v.parse::<Accelerator>() {
|
||||
Ok(_) => {
|
||||
info!("global_shortcut_register");
|
||||
let handle = app.app_handle();
|
||||
let mut shortcut = app.global_shortcut_manager();
|
||||
shortcut
|
||||
.register(&v, move || {
|
||||
if let Some(w) = handle.get_window("core") {
|
||||
if w.is_visible().unwrap() {
|
||||
w.hide().unwrap();
|
||||
} else {
|
||||
w.show().unwrap();
|
||||
w.set_focus().unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
.unwrap();
|
||||
};
|
||||
info!("global_shortcut_end");
|
||||
}
|
||||
})
|
||||
.unwrap_or_else(|err| {
|
||||
info!("global_shortcut_register_error: {}", err);
|
||||
});
|
||||
}
|
||||
Err(err) => {
|
||||
info!("global_shortcut_parse_error: {}", err);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
info!("global_shortcut_unregister");
|
||||
};
|
||||
|
||||
if chat_conf.hide_dock_icon {
|
||||
#[cfg(target_os = "macos")]
|
||||
|
@ -30,7 +30,7 @@ pub fn control_window(handle: &tauri::AppHandle) {
|
||||
let app = handle.clone();
|
||||
tokio::spawn(async move {
|
||||
WindowBuilder::new(&app, "main", WindowUrl::App("index.html".into()))
|
||||
.title("ChatGPT")
|
||||
.title("Control Center")
|
||||
.resizable(true)
|
||||
.fullscreen(false)
|
||||
.inner_size(800.0, 600.0)
|
||||
|
16
src-tauri/src/assets/core.js
vendored
16
src-tauri/src/assets/core.js
vendored
@ -88,21 +88,7 @@ async function init() {
|
||||
});
|
||||
|
||||
window.__sync_prompts = async function() {
|
||||
const res = await fetch('https://raw.githubusercontent.com/f/awesome-chatgpt-prompts/main/prompts.csv');
|
||||
if (res.ok) {
|
||||
const data = await res.text();
|
||||
await invoke('sync_prompts', { data, time: Date.now() });
|
||||
} else {
|
||||
invoke('messageDialog', {
|
||||
__tauriModule: 'Dialog',
|
||||
message: {
|
||||
cmd: 'messageDialog',
|
||||
message: 'ChatGPT Prompts data sync failed, please try again!'.toString(),
|
||||
title: 'Sync Prompts'.toString(),
|
||||
type: 'error'
|
||||
}
|
||||
})
|
||||
}
|
||||
await invoke('sync_prompts', { time: Date.now() });
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -14,10 +14,13 @@ use tauri::TitleBarStyle;
|
||||
pub const ISSUES_URL: &str = "https://github.com/lencx/ChatGPT/issues";
|
||||
pub const UPDATE_LOG_URL: &str = "https://github.com/lencx/ChatGPT/blob/main/UPDATE_LOG.md";
|
||||
pub const AWESOME_URL: &str = "https://github.com/lencx/ChatGPT/blob/main/AWESOME.md";
|
||||
pub const GITHUB_PROMPTS_CSV_URL: &str =
|
||||
"https://raw.githubusercontent.com/f/awesome-chatgpt-prompts/main/prompts.csv";
|
||||
pub const DEFAULT_CHAT_CONF: &str = r#"{
|
||||
"stay_on_top": false,
|
||||
"theme": "Light",
|
||||
"titlebar": true,
|
||||
"global_shortcut": "",
|
||||
"hide_dock_icon": false,
|
||||
"default_origin": "https://chat.openai.com",
|
||||
"origin": "https://chat.openai.com",
|
||||
@ -28,6 +31,7 @@ pub const DEFAULT_CHAT_CONF_MAC: &str = r#"{
|
||||
"stay_on_top": false,
|
||||
"theme": "Light",
|
||||
"titlebar": false,
|
||||
"global_shortcut": "",
|
||||
"hide_dock_icon": false,
|
||||
"default_origin": "https://chat.openai.com",
|
||||
"origin": "https://chat.openai.com",
|
||||
@ -61,6 +65,7 @@ pub struct ChatConfJson {
|
||||
pub origin: String,
|
||||
pub ua_window: String,
|
||||
pub ua_tray: String,
|
||||
pub global_shortcut: Option<String>,
|
||||
}
|
||||
|
||||
impl ChatConfJson {
|
||||
|
@ -63,6 +63,7 @@ async fn main() {
|
||||
cmd::get_chat_model_cmd,
|
||||
cmd::parse_prompt,
|
||||
cmd::sync_prompts,
|
||||
cmd::sync_user_prompts,
|
||||
cmd::window_reload,
|
||||
cmd::cmd_list,
|
||||
fs_extra::metadata,
|
||||
|
@ -109,3 +109,22 @@ pub fn gen_cmd(name: String) -> String {
|
||||
let re = Regex::new(r"[^a-zA-Z0-9]").unwrap();
|
||||
re.replace_all(&name, "_").to_lowercase()
|
||||
}
|
||||
|
||||
pub async fn get_data(
|
||||
url: &str,
|
||||
app: Option<&tauri::AppHandle>,
|
||||
) -> Result<Option<String>, reqwest::Error> {
|
||||
let res = reqwest::get(url).await?;
|
||||
let is_ok = res.status() == 200;
|
||||
let body = res.text().await?;
|
||||
|
||||
if is_ok {
|
||||
Ok(Some(body))
|
||||
} else {
|
||||
info!("chatgpt_http_error: {}", body);
|
||||
if let Some(v) = app {
|
||||
tauri::api::dialog::message(v.get_window("core").as_ref(), "ChatGPT HTTP", body);
|
||||
}
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
@ -7,7 +7,7 @@
|
||||
},
|
||||
"package": {
|
||||
"productName": "ChatGPT",
|
||||
"version": "0.7.3"
|
||||
"version": "0.7.4"
|
||||
},
|
||||
"tauri": {
|
||||
"allowlist": {
|
||||
@ -15,13 +15,6 @@
|
||||
"globalShortcut": {
|
||||
"all": true
|
||||
},
|
||||
"http": {
|
||||
"all": true,
|
||||
"scope": [
|
||||
"https://**",
|
||||
"http://**"
|
||||
]
|
||||
},
|
||||
"fs": {
|
||||
"all": true,
|
||||
"scope": [
|
||||
|
120
src/view/General.tsx
vendored
120
src/view/General.tsx
vendored
@ -1,36 +1,54 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { Form, Radio, Switch, Input, Button, Space, message, Tooltip } from 'antd';
|
||||
import { QuestionCircleOutlined } from '@ant-design/icons';
|
||||
import { invoke } from '@tauri-apps/api';
|
||||
import { invoke, shell, path } from '@tauri-apps/api';
|
||||
import { platform } from '@tauri-apps/api/os';
|
||||
import { ask } from '@tauri-apps/api/dialog';
|
||||
import { relaunch } from '@tauri-apps/api/process';
|
||||
import { clone, omit, isEqual } from 'lodash';
|
||||
|
||||
import { DISABLE_AUTO_COMPLETE } from '@/utils';
|
||||
import useInit from '@/hooks/useInit';
|
||||
import { DISABLE_AUTO_COMPLETE, chatRoot } from '@/utils';
|
||||
|
||||
const OriginLabel = ({ url }: { url: string }) => {
|
||||
return (
|
||||
<span>
|
||||
Switch Origin <Tooltip title={`Default: ${url}`}><QuestionCircleOutlined /></Tooltip>
|
||||
Switch Origin <Tooltip title={`Default: ${url}`}><QuestionCircleOutlined style={{ color: '#1677ff' }} /></Tooltip>
|
||||
</span>
|
||||
)
|
||||
}
|
||||
|
||||
const GlobalShortcut = () => {
|
||||
return (
|
||||
<div>
|
||||
Global Shortcut
|
||||
{' '}
|
||||
<Tooltip title={(
|
||||
<div>
|
||||
<div>Shortcut definition, modifiers and key separated by "+" e.g. CmdOrControl+Q</div>
|
||||
<div style={{ margin: '10px 0'}}>If empty, the shortcut is disabled.</div>
|
||||
<a href="https://tauri.app/v1/api/js/globalshortcut" target="_blank">https://tauri.app/v1/api/js/globalshortcut</a>
|
||||
</div>
|
||||
)}>
|
||||
<QuestionCircleOutlined style={{ color: '#1677ff' }} />
|
||||
</Tooltip>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default function General() {
|
||||
const [form] = Form.useForm();
|
||||
const [jsonPath, setJsonPath] = useState('');
|
||||
const [platformInfo, setPlatform] = useState<string>('');
|
||||
const [chatConf, setChatConf] = useState<any>(null);
|
||||
|
||||
const init = async () => {
|
||||
useInit(async () => {
|
||||
setJsonPath(await path.join(await chatRoot(), 'chat.conf.json'));
|
||||
|
||||
setPlatform(await platform());
|
||||
const chatData = await invoke('get_chat_conf');
|
||||
setChatConf(chatData);
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
init();
|
||||
}, [])
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
form.setFieldsValue(clone(chatConf));
|
||||
@ -55,44 +73,54 @@ export default function General() {
|
||||
};
|
||||
|
||||
return (
|
||||
<Form
|
||||
form={form}
|
||||
style={{ maxWidth: 500 }}
|
||||
onFinish={onFinish}
|
||||
labelCol={{ span: 8 }}
|
||||
wrapperCol={{ span: 15, offset: 1 }}
|
||||
>
|
||||
<Form.Item label="Theme" name="theme">
|
||||
<Radio.Group>
|
||||
<Radio value="Light">Light</Radio>
|
||||
<Radio value="Dark">Dark</Radio>
|
||||
</Radio.Group>
|
||||
</Form.Item>
|
||||
<Form.Item label="Stay On Top" name="stay_on_top" valuePropName="checked">
|
||||
<Switch />
|
||||
</Form.Item>
|
||||
{platformInfo === 'darwin' && (
|
||||
<Form.Item label="Titlebar" name="titlebar" valuePropName="checked">
|
||||
<>
|
||||
<div className="chat-table-tip">
|
||||
<div className="chat-sync-path">
|
||||
<div>PATH: <a onClick={() => shell.open(jsonPath)} title={jsonPath}>{jsonPath}</a></div>
|
||||
</div>
|
||||
</div>
|
||||
<Form
|
||||
form={form}
|
||||
style={{ maxWidth: 500 }}
|
||||
onFinish={onFinish}
|
||||
labelCol={{ span: 8 }}
|
||||
wrapperCol={{ span: 15, offset: 1 }}
|
||||
>
|
||||
<Form.Item label="Theme" name="theme">
|
||||
<Radio.Group>
|
||||
<Radio value="Light">Light</Radio>
|
||||
<Radio value="Dark">Dark</Radio>
|
||||
</Radio.Group>
|
||||
</Form.Item>
|
||||
<Form.Item label="Stay On Top" name="stay_on_top" valuePropName="checked">
|
||||
<Switch />
|
||||
</Form.Item>
|
||||
)}
|
||||
<Form.Item label={<OriginLabel url={chatConf?.default_origin} />} name="origin">
|
||||
<Input placeholder="https://chat.openai.com" {...DISABLE_AUTO_COMPLETE} />
|
||||
</Form.Item>
|
||||
<Form.Item label="User Agent (Window)" name="ua_window">
|
||||
<Input.TextArea autoSize={{ minRows: 4, maxRows: 4 }} {...DISABLE_AUTO_COMPLETE} placeholder="Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36" />
|
||||
</Form.Item>
|
||||
<Form.Item label="User Agent (SystemTray)" name="ua_tray">
|
||||
<Input.TextArea autoSize={{ minRows: 4, maxRows: 4 }} {...DISABLE_AUTO_COMPLETE} placeholder="Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36" />
|
||||
</Form.Item>
|
||||
<Form.Item>
|
||||
<Space size={20}>
|
||||
<Button onClick={onCancel}>Cancel</Button>
|
||||
<Button type="primary" htmlType="submit">
|
||||
Submit
|
||||
</Button>
|
||||
</Space>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
<Form.Item label={<GlobalShortcut />} name="global_shortcut">
|
||||
<Input placeholder="CmdOrCtrl+Shift+O" {...DISABLE_AUTO_COMPLETE} />
|
||||
</Form.Item>
|
||||
{platformInfo === 'darwin' && (
|
||||
<Form.Item label="Titlebar" name="titlebar" valuePropName="checked">
|
||||
<Switch />
|
||||
</Form.Item>
|
||||
)}
|
||||
<Form.Item label={<OriginLabel url={chatConf?.default_origin} />} name="origin">
|
||||
<Input placeholder="https://chat.openai.com" {...DISABLE_AUTO_COMPLETE} />
|
||||
</Form.Item>
|
||||
<Form.Item label="User Agent (Window)" name="ua_window">
|
||||
<Input.TextArea autoSize={{ minRows: 4, maxRows: 4 }} {...DISABLE_AUTO_COMPLETE} placeholder="Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36" />
|
||||
</Form.Item>
|
||||
<Form.Item label="User Agent (SystemTray)" name="ua_tray">
|
||||
<Input.TextArea autoSize={{ minRows: 4, maxRows: 4 }} {...DISABLE_AUTO_COMPLETE} placeholder="Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36" />
|
||||
</Form.Item>
|
||||
<Form.Item>
|
||||
<Space size={20}>
|
||||
<Button onClick={onCancel}>Cancel</Button>
|
||||
<Button type="primary" htmlType="submit">
|
||||
Submit
|
||||
</Button>
|
||||
</Space>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</>
|
||||
)
|
||||
}
|
47
src/view/model/SyncCustom/index.tsx
vendored
47
src/view/model/SyncCustom/index.tsx
vendored
@ -1,6 +1,6 @@
|
||||
import { useState, useRef, useEffect } from 'react';
|
||||
import { Table, Modal, Button, message } from 'antd';
|
||||
import { invoke, http, path, fs } from '@tauri-apps/api';
|
||||
import { invoke, path, fs } from '@tauri-apps/api';
|
||||
|
||||
import useData from '@/hooks/useData';
|
||||
import useChatModel, { useCacheModel } from '@/hooks/useChatModel';
|
||||
@ -10,7 +10,7 @@ import { CHAT_MODEL_JSON, chatRoot, readJSON, genCmd } from '@/utils';
|
||||
import { syncColumns, getPath } from './config';
|
||||
import SyncForm from './Form';
|
||||
|
||||
const setTag = (data: Record<string, any>[]) => data.map((i) => ({ ...i, tags: ['user-sync'], enable: true }))
|
||||
const fmtData = (data: Record<string, any>[] = []) => (Array.isArray(data) ? data : []).map((i) => ({ ...i, cmd: i.cmd ? i.cmd : genCmd(i.act), tags: ['user-sync'], enable: true }));
|
||||
|
||||
export default function SyncCustom() {
|
||||
const [isVisible, setVisible] = useState(false);
|
||||
@ -34,7 +34,9 @@ export default function SyncCustom() {
|
||||
if (!opInfo.opType) return;
|
||||
if (opInfo.opType === 'sync') {
|
||||
const filename = `${opInfo?.opRecord?.id}.json`;
|
||||
handleSync(filename).then(() => {
|
||||
handleSync(filename).then((isOk: boolean) => {
|
||||
opInfo.resetRecord();
|
||||
if (!isOk) return;
|
||||
const data = opReplace(opInfo?.opRecord?.[opSafeKey], { ...opInfo?.opRecord, last_updated: Date.now() });
|
||||
modelSet(data);
|
||||
opInfo.resetRecord();
|
||||
@ -44,9 +46,16 @@ export default function SyncCustom() {
|
||||
setVisible(true);
|
||||
}
|
||||
if (['delete'].includes(opInfo.opType)) {
|
||||
const data = opRemove(opInfo?.opRecord?.[opSafeKey]);
|
||||
modelSet(data);
|
||||
opInfo.resetRecord();
|
||||
(async () => {
|
||||
try {
|
||||
const file = await path.join(await chatRoot(), 'cache_model', `${opInfo?.opRecord?.id}.json`);
|
||||
await fs.removeFile(file);
|
||||
} catch(e) {}
|
||||
const data = opRemove(opInfo?.opRecord?.[opSafeKey]);
|
||||
modelSet(data);
|
||||
opInfo.resetRecord();
|
||||
modelCacheCmd();
|
||||
})();
|
||||
}
|
||||
}, [opInfo.opType, formRef]);
|
||||
|
||||
@ -58,40 +67,30 @@ export default function SyncCustom() {
|
||||
|
||||
// https or http
|
||||
if (/^http/.test(record?.protocol)) {
|
||||
const res = await http.fetch(filePath, {
|
||||
method: 'GET',
|
||||
responseType: isJson ? 1 : 2,
|
||||
});
|
||||
if (res.ok) {
|
||||
if (isJson) {
|
||||
// parse json
|
||||
await modelCacheSet(setTag(Array.isArray(res?.data) ? res?.data : []), file);
|
||||
} else {
|
||||
// parse csv
|
||||
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'] }));
|
||||
await modelCacheSet(fmtList, file);
|
||||
}
|
||||
const data = await invoke('sync_user_prompts', { url: filePath, dataType: record?.ext });
|
||||
if (data) {
|
||||
await modelCacheSet(data as [], file);
|
||||
await modelCacheCmd();
|
||||
message.success('ChatGPT Prompts data has been synchronized!');
|
||||
return true;
|
||||
} else {
|
||||
message.error('ChatGPT Prompts data sync failed, please try again!');
|
||||
return false;
|
||||
}
|
||||
return;
|
||||
}
|
||||
// local
|
||||
if (isJson) {
|
||||
// parse json
|
||||
const data = await readJSON(filePath, { isRoot: true });
|
||||
await modelCacheSet(setTag(Array.isArray(data) ? data : []), file);
|
||||
await modelCacheSet(fmtData(data), file);
|
||||
} else {
|
||||
// parse csv
|
||||
const data = await fs.readTextFile(filePath);
|
||||
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'] }));
|
||||
await modelCacheSet(fmtList, file);
|
||||
await modelCacheSet(fmtData(list), file);
|
||||
}
|
||||
await modelCacheCmd();
|
||||
return true;
|
||||
};
|
||||
|
||||
const handleOk = () => {
|
||||
|
23
src/view/model/SyncPrompts/index.tsx
vendored
23
src/view/model/SyncPrompts/index.tsx
vendored
@ -1,13 +1,13 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { Table, Button, message, Popconfirm } from 'antd';
|
||||
import { invoke, http, path, shell } from '@tauri-apps/api';
|
||||
import { Table, Button, Popconfirm } from 'antd';
|
||||
import { invoke, path, shell } from '@tauri-apps/api';
|
||||
|
||||
import useInit from '@/hooks/useInit';
|
||||
import useData from '@/hooks/useData';
|
||||
import useColumns from '@/hooks/useColumns';
|
||||
import useChatModel, { useCacheModel } from '@/hooks/useChatModel';
|
||||
import useTable, { TABLE_PAGINATION } from '@/hooks/useTable';
|
||||
import { fmtDate, chatRoot, GITHUB_PROMPTS_CSV_URL, genCmd } from '@/utils';
|
||||
import { fmtDate, chatRoot } from '@/utils';
|
||||
import { syncColumns } from './config';
|
||||
import './index.scss';
|
||||
|
||||
@ -33,24 +33,13 @@ export default function SyncPrompts() {
|
||||
}, [modelCacheJson.length]);
|
||||
|
||||
const handleSync = 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) {
|
||||
// const content = data.replace(/"(\s+)?,(\s+)?"/g, '","');
|
||||
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: ['chatgpt-prompts'] }));
|
||||
await modelCacheSet(fmtList);
|
||||
opInit(fmtList);
|
||||
const data = await invoke('sync_prompts', { time: Date.now() });
|
||||
if (data) {
|
||||
opInit(data as any[]);
|
||||
modelSet({
|
||||
id: 'chatgpt_prompts',
|
||||
last_updated: Date.now(),
|
||||
});
|
||||
message.success('ChatGPT Prompts data has been synchronized!');
|
||||
} else {
|
||||
message.error('ChatGPT Prompts data sync failed, please try again!');
|
||||
}
|
||||
};
|
||||
|
||||
|
4
src/view/model/SyncRecord/config.tsx
vendored
4
src/view/model/SyncRecord/config.tsx
vendored
@ -24,7 +24,9 @@ export const syncColumns = () => [
|
||||
dataIndex: 'tags',
|
||||
key: 'tags',
|
||||
// width: 150,
|
||||
render: () => <Tag>chatgpt-prompts</Tag>,
|
||||
render: (v: string[]) => (
|
||||
<span className="chat-prompts-tags">{v?.map(i => <Tag key={i}>{i}</Tag>)}</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: 'Enable',
|
||||
|
Loading…
Reference in New Issue
Block a user