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',