From beddf76198cdb5254f6e56ff6e58f3b18c280b1a Mon Sep 17 00:00:00 2001 From: lencx Date: Fri, 30 Dec 2022 23:46:30 +0800 Subject: [PATCH 1/8] fix: customize global shortcuts (#108) --- UPDATE_LOG.md | 5 +++++ src-tauri/src/app/setup.rs | 39 +++++++++++++++++--------------------- src-tauri/src/conf.rs | 3 +++ src/view/General.tsx | 21 ++++++++++++++++++++ 4 files changed, 46 insertions(+), 22 deletions(-) diff --git a/UPDATE_LOG.md b/UPDATE_LOG.md index 31259e6..c457bc7 100644 --- a/UPDATE_LOG.md +++ b/UPDATE_LOG.md @@ -1,5 +1,10 @@ # UPDATE LOG +## v0.7.4 + +fix: +- customize global shortcuts (`Menu -> Preferences -> Control Center -> General -> Global Shortcut`) + ## v0.7.3 chore: diff --git a/src-tauri/src/app/setup.rs b/src-tauri/src/app/setup.rs index 5a77aaf..f9105d2 100644 --- a/src-tauri/src/app/setup.rs +++ b/src-tauri/src/app/setup.rs @@ -13,30 +13,25 @@ pub fn init(app: &mut App) -> std::result::Result<(), Box window::tray_window(&handle); }); - { - info!("global_shortcut_start"); + if let Some(v) = chat_conf.global_shortcut { + info!("global_shortcut"); 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(); - } - } - }) - .unwrap(); - }; - info!("global_shortcut_end"); - } + 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_or_else(|err| { + info!("global_shortcut_register_error: {}", err); + }); + } else { + info!("global_shortcut_unregister"); + }; if chat_conf.hide_dock_icon { #[cfg(target_os = "macos")] diff --git a/src-tauri/src/conf.rs b/src-tauri/src/conf.rs index a72a5da..cf2e1f5 100644 --- a/src-tauri/src/conf.rs +++ b/src-tauri/src/conf.rs @@ -18,6 +18,7 @@ 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 +29,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 +63,7 @@ pub struct ChatConfJson { pub origin: String, pub ua_window: String, pub ua_tray: String, + pub global_shortcut: Option, } impl ChatConfJson { diff --git a/src/view/General.tsx b/src/view/General.tsx index 5e7dbbe..20f29b9 100644 --- a/src/view/General.tsx +++ b/src/view/General.tsx @@ -17,6 +17,24 @@ const OriginLabel = ({ url }: { url: string }) => { ) } +const GlobalShortcut = () => { + return ( +
+ Global Shortcut + {' '} + +
Shortcut definition, modifiers and key separated by "+" e.g. CmdOrControl+Q
+
If empty, the shortcut is disabled.
+ https://tauri.app/v1/api/js/globalshortcut +
+ )}> + + + + ) +} + export default function General() { const [form] = Form.useForm(); const [platformInfo, setPlatform] = useState(''); @@ -71,6 +89,9 @@ export default function General() { + } name="global_shortcut"> + + {platformInfo === 'darwin' && ( From 4c7907c10621e314e71cd57b0232ce71ca60049e Mon Sep 17 00:00:00 2001 From: lencx Date: Sat, 31 Dec 2022 12:43:47 +0800 Subject: [PATCH 2/8] chore: conf path --- src/view/General.tsx | 107 +++++++++++++++++++++++-------------------- 1 file changed, 57 insertions(+), 50 deletions(-) diff --git a/src/view/General.tsx b/src/view/General.tsx index 20f29b9..96ea35c 100644 --- a/src/view/General.tsx +++ b/src/view/General.tsx @@ -1,18 +1,19 @@ 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 ( - Switch Origin + Switch Origin ) } @@ -29,7 +30,7 @@ const GlobalShortcut = () => { https://tauri.app/v1/api/js/globalshortcut )}> - + ) @@ -37,18 +38,17 @@ const GlobalShortcut = () => { export default function General() { const [form] = Form.useForm(); + const [jsonPath, setJsonPath] = useState(''); const [platformInfo, setPlatform] = useState(''); const [chatConf, setChatConf] = useState(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)); @@ -73,47 +73,54 @@ export default function General() { }; return ( -
- - - Light - Dark - - - - - - } name="global_shortcut"> - - - {platformInfo === 'darwin' && ( - + <> + + + + + Light + Dark + + + - )} - } name="origin"> - - - - - - - - - - - - - - - + } name="global_shortcut"> + + + {platformInfo === 'darwin' && ( + + + + )} + } name="origin"> + + + + + + + + + + + + + + + + ) } \ No newline at end of file From 5ebda4105dc8eb58959af80cb5b7d93db66233c1 Mon Sep 17 00:00:00 2001 From: lencx Date: Sat, 31 Dec 2022 17:59:55 +0800 Subject: [PATCH 3/8] refactor: prompts sync --- src-tauri/Cargo.toml | 2 +- src-tauri/src/app/cmd.rs | 188 +++++++++++++++++---------- src-tauri/src/app/setup.rs | 24 ++-- src-tauri/src/assets/core.js | 16 +-- src-tauri/src/conf.rs | 2 + src-tauri/src/main.rs | 1 + src-tauri/src/utils.rs | 19 +++ src-tauri/tauri.conf.json | 7 - src/view/model/SyncCustom/index.tsx | 39 +++--- src/view/model/SyncPrompts/index.tsx | 23 +--- src/view/model/SyncRecord/config.tsx | 4 +- 11 files changed, 185 insertions(+), 140 deletions(-) diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 824bcdc..a421bf3 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -25,7 +25,7 @@ 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" [dependencies.tauri-plugin-log] git = "https://github.com/tauri-apps/tauri-plugin-log" diff --git a/src-tauri/src/app/cmd.rs b/src-tauri/src/app/cmd.rs index 45d077a..c2cefe2 100644 --- a/src-tauri/src/app/cmd.rs +++ b/src-tauri/src/app/cmd.rs @@ -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}; @@ -134,75 +135,130 @@ pub fn cmd_list() -> Vec { } #[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::>(); +pub async fn sync_prompts(app: AppHandle, time: u64) -> Option> { + 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::>(); + + 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> { + let res = utils::get_data(&url, None).await.unwrap(); + + info!("chatgpt_http_url: {}", url); + + if let Some(v) = res { + let data; + if data_type == "csv" { + info!("chatgpt_http_csv_parser"); + data = parse_prompt(v); + } else if data_type == "json" { + info!("chatgpt_http_json_parser"); + data = serde_json::from_str(&v).unwrap_or_else(|err| { + info!("chatgpt_http_json_parser_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::>(); + + return Some(data); + } + + None } diff --git a/src-tauri/src/app/setup.rs b/src-tauri/src/app/setup.rs index f9105d2..7a1dbf1 100644 --- a/src-tauri/src/app/setup.rs +++ b/src-tauri/src/app/setup.rs @@ -17,18 +17,20 @@ pub fn init(app: &mut App) -> std::result::Result<(), Box info!("global_shortcut"); 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(); + 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_or_else(|err| { - info!("global_shortcut_register_error: {}", err); - }); + }) + .unwrap_or_else(|err| { + info!("global_shortcut_register_error: {}", err); + }); } else { info!("global_shortcut_unregister"); }; diff --git a/src-tauri/src/assets/core.js b/src-tauri/src/assets/core.js index a3b5d72..8f50323 100644 --- a/src-tauri/src/assets/core.js +++ b/src-tauri/src/assets/core.js @@ -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() }); } } diff --git a/src-tauri/src/conf.rs b/src-tauri/src/conf.rs index cf2e1f5..116267e 100644 --- a/src-tauri/src/conf.rs +++ b/src-tauri/src/conf.rs @@ -14,6 +14,8 @@ 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", diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index 7c6d3f3..8a2fc58 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -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, diff --git a/src-tauri/src/utils.rs b/src-tauri/src/utils.rs index 79920cd..61a153d 100644 --- a/src-tauri/src/utils.rs +++ b/src-tauri/src/utils.rs @@ -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, 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) + } +} diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index d471aaf..474b062 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -15,13 +15,6 @@ "globalShortcut": { "all": true }, - "http": { - "all": true, - "scope": [ - "https://**", - "http://**" - ] - }, "fs": { "all": true, "scope": [ diff --git a/src/view/model/SyncCustom/index.tsx b/src/view/model/SyncCustom/index.tsx index 0e2dceb..4d41b68 100644 --- a/src/view/model/SyncCustom/index.tsx +++ b/src/view/model/SyncCustom/index.tsx @@ -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[]) => data.map((i) => ({ ...i, tags: ['user-sync'], enable: true })) +const fmtData = (data: Record[] = []) => (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); @@ -44,9 +44,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,20 +65,9 @@ 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[] = 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!'); } else { @@ -83,13 +79,12 @@ export default function SyncCustom() { 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[] = 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(); }; diff --git a/src/view/model/SyncPrompts/index.tsx b/src/view/model/SyncPrompts/index.tsx index e6d5f3b..d5a359e 100644 --- a/src/view/model/SyncPrompts/index.tsx +++ b/src/view/model/SyncPrompts/index.tsx @@ -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[] = 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!'); } }; diff --git a/src/view/model/SyncRecord/config.tsx b/src/view/model/SyncRecord/config.tsx index c040ebc..ebd2609 100644 --- a/src/view/model/SyncRecord/config.tsx +++ b/src/view/model/SyncRecord/config.tsx @@ -24,7 +24,9 @@ export const syncColumns = () => [ dataIndex: 'tags', key: 'tags', // width: 150, - render: () => chatgpt-prompts, + render: (v: string[]) => ( + {v?.map(i => {i})} + ), }, { title: 'Enable', From 85fbd4a10432a2f5e7f268bebc72f59694ff90f5 Mon Sep 17 00:00:00 2001 From: lencx Date: Sat, 31 Dec 2022 20:07:09 +0800 Subject: [PATCH 4/8] refactor: global shortcut --- UPDATE_LOG.md | 1 + src-tauri/Cargo.toml | 1 + src-tauri/src/app/cmd.rs | 24 ++++++++++++---- src-tauri/src/app/setup.rs | 43 +++++++++++++++++------------ src-tauri/src/app/window.rs | 2 +- src/view/model/SyncCustom/index.tsx | 8 ++++-- 6 files changed, 53 insertions(+), 26 deletions(-) diff --git a/UPDATE_LOG.md b/UPDATE_LOG.md index c457bc7..8a6b166 100644 --- a/UPDATE_LOG.md +++ b/UPDATE_LOG.md @@ -3,6 +3,7 @@ ## 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 diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index a421bf3..2bb7c08 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -26,6 +26,7 @@ walkdir = "2.3.2" regex = "1.7.0" tokio = { version = "1.23.0", features = ["macros"] } reqwest = "0.11.13" +wry = "0.23.4" [dependencies.tauri-plugin-log] git = "https://github.com/tauri-apps/tauri-plugin-log" diff --git a/src-tauri/src/app/cmd.rs b/src-tauri/src/app/cmd.rs index c2cefe2..6d29a89 100644 --- a/src-tauri/src/app/cmd.rs +++ b/src-tauri/src/app/cmd.rs @@ -88,8 +88,17 @@ pub fn parse_prompt(data: String) -> Vec { 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 } @@ -222,19 +231,22 @@ pub async fn sync_prompts(app: AppHandle, time: u64) -> Option> #[command] pub async fn sync_user_prompts(url: String, data_type: String) -> Option> { - let res = utils::get_data(&url, None).await.unwrap(); + 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_parser"); + info!("chatgpt_http_csv_parse"); data = parse_prompt(v); } else if data_type == "json" { - info!("chatgpt_http_json_parser"); + info!("chatgpt_http_json_parse"); data = serde_json::from_str(&v).unwrap_or_else(|err| { - info!("chatgpt_http_json_parser_error: {}", err); + info!("chatgpt_http_json_parse_error: {}", err); vec![] }); } else { diff --git a/src-tauri/src/app/setup.rs b/src-tauri/src/app/setup.rs index 7a1dbf1..91f812d 100644 --- a/src-tauri/src/app/setup.rs +++ b/src-tauri/src/app/setup.rs @@ -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> { info!("stepup"); @@ -14,23 +15,31 @@ pub fn init(app: &mut App) -> std::result::Result<(), Box }); if let Some(v) = chat_conf.global_shortcut { - info!("global_shortcut"); - 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_or_else(|err| { - info!("global_shortcut_register_error: {}", err); - }); + info!("global_shortcut: `{}`", v); + match v.parse::() { + 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_or_else(|err| { + info!("global_shortcut_register_error: {}", err); + }); + } + Err(err) => { + info!("global_shortcut_parse_error: {}", err); + } + } } else { info!("global_shortcut_unregister"); }; diff --git a/src-tauri/src/app/window.rs b/src-tauri/src/app/window.rs index 55c171e..546be04 100644 --- a/src-tauri/src/app/window.rs +++ b/src-tauri/src/app/window.rs @@ -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) diff --git a/src/view/model/SyncCustom/index.tsx b/src/view/model/SyncCustom/index.tsx index 4d41b68..936283c 100644 --- a/src/view/model/SyncCustom/index.tsx +++ b/src/view/model/SyncCustom/index.tsx @@ -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(); @@ -70,10 +72,11 @@ export default function SyncCustom() { 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) { @@ -87,6 +90,7 @@ export default function SyncCustom() { await modelCacheSet(fmtData(list), file); } await modelCacheCmd(); + return true; }; const handleOk = () => { From fd62c2a8c40c54e03da6862808f3fd1178c3a576 Mon Sep 17 00:00:00 2001 From: lencx Date: Sat, 31 Dec 2022 20:08:11 +0800 Subject: [PATCH 5/8] readme --- README-ZH_CN.md | 6 +++--- README.md | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/README-ZH_CN.md b/README-ZH_CN.md index db42252..4ee952e 100644 --- a/README-ZH_CN.md +++ b/README-ZH_CN.md @@ -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) diff --git a/README.md b/README.md index 3f804fb..ddfca37 100644 --- a/README.md +++ b/README.md @@ -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) From 10993667abc8cf6a510e64911a64e9e02e9c3c66 Mon Sep 17 00:00:00 2001 From: lencx Date: Sat, 31 Dec 2022 20:11:15 +0800 Subject: [PATCH 6/8] readme --- README-ZH_CN.md | 2 +- README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README-ZH_CN.md b/README-ZH_CN.md index 4ee952e..89246ea 100644 --- a/README-ZH_CN.md +++ b/README-ZH_CN.md @@ -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)) ### 菜单项 diff --git a/README.md b/README.md index ddfca37..3e6ca73 100644 --- a/README.md +++ b/README.md @@ -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 From 51891e8a8a3d29a8b65640b434b9000e0aeeacd1 Mon Sep 17 00:00:00 2001 From: lencx Date: Sat, 31 Dec 2022 20:11:21 +0800 Subject: [PATCH 7/8] v0.7.4 --- src-tauri/tauri.conf.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index 474b062..4ed2837 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -7,7 +7,7 @@ }, "package": { "productName": "ChatGPT", - "version": "0.7.3" + "version": "0.7.4" }, "tauri": { "allowlist": { From 5e1295677c29adb0f2494299a443553a37e14812 Mon Sep 17 00:00:00 2001 From: Vinchan Date: Sat, 31 Dec 2022 21:10:12 +0800 Subject: [PATCH 8/8] doc: readme zh-cn --- README-ZH_CN.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README-ZH_CN.md b/README-ZH_CN.md index 89246ea..6ecf21b 100644 --- a/README-ZH_CN.md +++ b/README-ZH_CN.md @@ -32,14 +32,14 @@ ### brew 安装 -Easily install with _[Homebrew](https://brew.sh) ([Cask](https://docs.brew.sh/Cask-Cookbook)):_ +_[Homebrew快捷安装](https://brew.sh) ([Cask](https://docs.brew.sh/Cask-Cookbook)):_ ```sh brew tap lencx/chatgpt https://github.com/lencx/ChatGPT.git brew install --cask chatgpt --no-quarantine ``` -Also, if you keep a _[Brewfile](https://github.com/Homebrew/homebrew-bundle#usage)_, you can add something like this: +如果你坚持使用 _[Brewfile](https://github.com/Homebrew/homebrew-bundle#usage)_ ,你需要添加以下配置: ```rb repo = "lencx/chatgpt" @@ -122,7 +122,7 @@ cask "popcorn-time", args: { "no-quarantine": true } - `4f695d3cfbf8491e9b1f3fab6d85715c.json` - 随机生成的文件名,缓存 `sync_custom` 数据 - `bd1b96f15a1644f7bd647cc53073ff8f.json` - 随机生成的文件名,缓存 `sync_custom` 数据 -### Sync Custom +### 客户端信息同步 目前同步自定文件仅支持 json 和 csv,且需要满足以下格式,否则会导致应用异常: @@ -175,7 +175,7 @@ cask "popcorn-time", args: { "no-quarantine": true } 它是安全的,仅仅只是对 [OpenAI ChatGPT](https://chat.openai.com) 网站的包装,注入了一些额外功能(均在本地,未发起网络请求),如果存疑,可以检查源代码。 -### Developer cannot be verified? +### 开发者未验证? Mac 上无法安装,提示开发者未验证,具体可以查看下面给出的解决方案(它是开源的,很安全)。