mirror of
https://github.com/lencx/ChatGPT.git
synced 2024-10-01 01:06:13 -04:00
refactor: conf
This commit is contained in:
parent
60b7e3148a
commit
d9612d3bed
1479
Cargo.lock
generated
1479
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@ -58,7 +58,7 @@
|
|||||||
"uuid": "^9.0.0"
|
"uuid": "^9.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@tauri-apps/cli": "^1.2.2",
|
"@tauri-apps/cli": "^1.3.1",
|
||||||
"@tauri-release/cli": "^0.2.5",
|
"@tauri-release/cli": "^0.2.5",
|
||||||
"@types/lodash": "^4.14.191",
|
"@types/lodash": "^4.14.191",
|
||||||
"@types/node": "^18.7.10",
|
"@types/node": "^18.7.10",
|
||||||
|
@ -4,7 +4,7 @@ specifiers:
|
|||||||
'@ant-design/icons': ^4.8.0
|
'@ant-design/icons': ^4.8.0
|
||||||
'@monaco-editor/react': ^4.4.6
|
'@monaco-editor/react': ^4.4.6
|
||||||
'@tauri-apps/api': ^1.2.0
|
'@tauri-apps/api': ^1.2.0
|
||||||
'@tauri-apps/cli': ^1.2.2
|
'@tauri-apps/cli': ^1.3.1
|
||||||
'@tauri-release/cli': ^0.2.5
|
'@tauri-release/cli': ^0.2.5
|
||||||
'@types/lodash': ^4.14.191
|
'@types/lodash': ^4.14.191
|
||||||
'@types/node': ^18.7.10
|
'@types/node': ^18.7.10
|
||||||
@ -59,7 +59,7 @@ dependencies:
|
|||||||
uuid: 9.0.0
|
uuid: 9.0.0
|
||||||
|
|
||||||
devDependencies:
|
devDependencies:
|
||||||
'@tauri-apps/cli': 1.2.3
|
'@tauri-apps/cli': 1.3.1
|
||||||
'@tauri-release/cli': 0.2.5
|
'@tauri-release/cli': 0.2.5
|
||||||
'@types/lodash': 4.14.191
|
'@types/lodash': 4.14.191
|
||||||
'@types/node': 18.11.19
|
'@types/node': 18.11.19
|
||||||
@ -1094,10 +1094,10 @@ packages:
|
|||||||
engines: { node: '>= 14.6.0', npm: '>= 6.6.0', yarn: '>= 1.19.1' }
|
engines: { node: '>= 14.6.0', npm: '>= 6.6.0', yarn: '>= 1.19.1' }
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/@tauri-apps/cli-darwin-arm64/1.2.3:
|
/@tauri-apps/cli-darwin-arm64/1.3.1:
|
||||||
resolution:
|
resolution:
|
||||||
{
|
{
|
||||||
integrity: sha512-phJN3fN8FtZZwqXg08bcxfq1+X1JSDglLvRxOxB7VWPq+O5SuB8uLyssjJsu+PIhyZZnIhTGdjhzLSFhSXfLsw==,
|
integrity: sha512-QlepYVPgOgspcwA/u4kGG4ZUijlXfdRtno00zEy+LxinN/IRXtk+6ErVtsmoLi1ZC9WbuMwzAcsRvqsD+RtNAg==,
|
||||||
}
|
}
|
||||||
engines: { node: '>= 10' }
|
engines: { node: '>= 10' }
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
@ -1106,10 +1106,10 @@ packages:
|
|||||||
dev: true
|
dev: true
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
/@tauri-apps/cli-darwin-x64/1.2.3:
|
/@tauri-apps/cli-darwin-x64/1.3.1:
|
||||||
resolution:
|
resolution:
|
||||||
{
|
{
|
||||||
integrity: sha512-jFZ/y6z8z6v4yliIbXKBXA7BJgtZVMsITmEXSuD6s5+eCOpDhQxbRkr6CA+FFfr+/r96rWSDSgDenDQuSvPAKw==,
|
integrity: sha512-fKcAUPVFO3jfDKXCSDGY0MhZFF/wDtx3rgFnogWYu4knk38o9RaqRkvMvqJhLYPuWaEM5h6/z1dRrr9KKCbrVg==,
|
||||||
}
|
}
|
||||||
engines: { node: '>= 10' }
|
engines: { node: '>= 10' }
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
@ -1118,10 +1118,10 @@ packages:
|
|||||||
dev: true
|
dev: true
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
/@tauri-apps/cli-linux-arm-gnueabihf/1.2.3:
|
/@tauri-apps/cli-linux-arm-gnueabihf/1.3.1:
|
||||||
resolution:
|
resolution:
|
||||||
{
|
{
|
||||||
integrity: sha512-C7h5vqAwXzY0kRGSU00Fj8PudiDWFCiQqqUNI1N+fhCILrzWZB9TPBwdx33ZfXKt/U4+emdIoo/N34v3TiAOmQ==,
|
integrity: sha512-+4H0dv8ltJHYu/Ma1h9ixUPUWka9EjaYa8nJfiMsdCI4LJLNE6cPveE7RmhZ59v9GW1XB108/k083JUC/OtGvA==,
|
||||||
}
|
}
|
||||||
engines: { node: '>= 10' }
|
engines: { node: '>= 10' }
|
||||||
cpu: [arm]
|
cpu: [arm]
|
||||||
@ -1130,10 +1130,10 @@ packages:
|
|||||||
dev: true
|
dev: true
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
/@tauri-apps/cli-linux-arm64-gnu/1.2.3:
|
/@tauri-apps/cli-linux-arm64-gnu/1.3.1:
|
||||||
resolution:
|
resolution:
|
||||||
{
|
{
|
||||||
integrity: sha512-buf1c8sdkuUzVDkGPQpyUdAIIdn5r0UgXU6+H5fGPq/Xzt5K69JzXaeo6fHsZEZghbV0hOK+taKV4J0m30UUMQ==,
|
integrity: sha512-Pj3odVO1JAxLjYmoXKxcrpj/tPxcA8UP8N06finhNtBtBaxAjrjjxKjO4968KB0BUH7AASIss9EL4Tr0FGnDuw==,
|
||||||
}
|
}
|
||||||
engines: { node: '>= 10' }
|
engines: { node: '>= 10' }
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
@ -1142,10 +1142,10 @@ packages:
|
|||||||
dev: true
|
dev: true
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
/@tauri-apps/cli-linux-arm64-musl/1.2.3:
|
/@tauri-apps/cli-linux-arm64-musl/1.3.1:
|
||||||
resolution:
|
resolution:
|
||||||
{
|
{
|
||||||
integrity: sha512-x88wPS9W5xAyk392vc4uNHcKBBvCp0wf4H9JFMF9OBwB7vfd59LbQCFcPSu8f0BI7bPrOsyHqspWHuFL8ojQEA==,
|
integrity: sha512-tA0JdDLPFaj42UDIVcF2t8V0tSha40rppcmAR/MfQpTCxih6399iMjwihz9kZE1n4b5O4KTq9GliYo50a8zYlQ==,
|
||||||
}
|
}
|
||||||
engines: { node: '>= 10' }
|
engines: { node: '>= 10' }
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
@ -1154,10 +1154,10 @@ packages:
|
|||||||
dev: true
|
dev: true
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
/@tauri-apps/cli-linux-x64-gnu/1.2.3:
|
/@tauri-apps/cli-linux-x64-gnu/1.3.1:
|
||||||
resolution:
|
resolution:
|
||||||
{
|
{
|
||||||
integrity: sha512-ZMz1jxEVe0B4/7NJnlPHmwmSIuwiD6ViXKs8F+OWWz2Y4jn5TGxWKFg7DLx5OwQTRvEIZxxT7lXHi5CuTNAxKg==,
|
integrity: sha512-FDU+Mnvk6NLkqQimcNojdKpMN4Y3W51+SQl+NqG9AFCWprCcSg62yRb84751ujZuf2MGT8HQOfmd0i77F4Q3tQ==,
|
||||||
}
|
}
|
||||||
engines: { node: '>= 10' }
|
engines: { node: '>= 10' }
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
@ -1166,10 +1166,10 @@ packages:
|
|||||||
dev: true
|
dev: true
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
/@tauri-apps/cli-linux-x64-musl/1.2.3:
|
/@tauri-apps/cli-linux-x64-musl/1.3.1:
|
||||||
resolution:
|
resolution:
|
||||||
{
|
{
|
||||||
integrity: sha512-B/az59EjJhdbZDzawEVox0LQu2ZHCZlk8rJf85AMIktIUoAZPFbwyiUv7/zjzA/sY6Nb58OSJgaPL2/IBy7E0A==,
|
integrity: sha512-MpO3akXFmK8lZYEbyQRDfhdxz1JkTBhonVuz5rRqxwA7gnGWHa1aF1+/2zsy7ahjB2tQ9x8DDFDMdVE20o9HrA==,
|
||||||
}
|
}
|
||||||
engines: { node: '>= 10' }
|
engines: { node: '>= 10' }
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
@ -1178,10 +1178,10 @@ packages:
|
|||||||
dev: true
|
dev: true
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
/@tauri-apps/cli-win32-ia32-msvc/1.2.3:
|
/@tauri-apps/cli-win32-ia32-msvc/1.3.1:
|
||||||
resolution:
|
resolution:
|
||||||
{
|
{
|
||||||
integrity: sha512-ypdO1OdC5ugNJAKO2m3sb1nsd+0TSvMS9Tr5qN/ZSMvtSduaNwrcZ3D7G/iOIanrqu/Nl8t3LYlgPZGBKlw7Ng==,
|
integrity: sha512-9Boeo3K5sOrSBAZBuYyGkpV2RfnGQz3ZhGJt4hE6P+HxRd62lS6+qDKAiw1GmkZ0l1drc2INWrNeT50gwOKwIQ==,
|
||||||
}
|
}
|
||||||
engines: { node: '>= 10' }
|
engines: { node: '>= 10' }
|
||||||
cpu: [ia32]
|
cpu: [ia32]
|
||||||
@ -1190,10 +1190,10 @@ packages:
|
|||||||
dev: true
|
dev: true
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
/@tauri-apps/cli-win32-x64-msvc/1.2.3:
|
/@tauri-apps/cli-win32-x64-msvc/1.3.1:
|
||||||
resolution:
|
resolution:
|
||||||
{
|
{
|
||||||
integrity: sha512-CsbHQ+XhnV/2csOBBDVfH16cdK00gNyNYUW68isedmqcn8j+s0e9cQ1xXIqi+Hue3awp8g3ImYN5KPepf3UExw==,
|
integrity: sha512-wMrTo91hUu5CdpbElrOmcZEoJR4aooTG+fbtcc87SMyPGQy1Ux62b+ZdwLvL1sVTxnIm//7v6QLRIWGiUjCPwA==,
|
||||||
}
|
}
|
||||||
engines: { node: '>= 10' }
|
engines: { node: '>= 10' }
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
@ -1202,23 +1202,23 @@ packages:
|
|||||||
dev: true
|
dev: true
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
/@tauri-apps/cli/1.2.3:
|
/@tauri-apps/cli/1.3.1:
|
||||||
resolution:
|
resolution:
|
||||||
{
|
{
|
||||||
integrity: sha512-erxtXuPhMEGJPBtnhPILD4AjuT81GZsraqpFvXAmEJZ2p8P6t7MVBifCL8LznRknznM3jn90D3M8RNBP3wcXTw==,
|
integrity: sha512-o4I0JujdITsVRm3/0spfJX7FcKYrYV1DXJqzlWIn6IY25/RltjU6qbC1TPgVww3RsRX63jyVUTcWpj5wwFl+EQ==,
|
||||||
}
|
}
|
||||||
engines: { node: '>= 10' }
|
engines: { node: '>= 10' }
|
||||||
hasBin: true
|
hasBin: true
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
'@tauri-apps/cli-darwin-arm64': 1.2.3
|
'@tauri-apps/cli-darwin-arm64': 1.3.1
|
||||||
'@tauri-apps/cli-darwin-x64': 1.2.3
|
'@tauri-apps/cli-darwin-x64': 1.3.1
|
||||||
'@tauri-apps/cli-linux-arm-gnueabihf': 1.2.3
|
'@tauri-apps/cli-linux-arm-gnueabihf': 1.3.1
|
||||||
'@tauri-apps/cli-linux-arm64-gnu': 1.2.3
|
'@tauri-apps/cli-linux-arm64-gnu': 1.3.1
|
||||||
'@tauri-apps/cli-linux-arm64-musl': 1.2.3
|
'@tauri-apps/cli-linux-arm64-musl': 1.3.1
|
||||||
'@tauri-apps/cli-linux-x64-gnu': 1.2.3
|
'@tauri-apps/cli-linux-x64-gnu': 1.3.1
|
||||||
'@tauri-apps/cli-linux-x64-musl': 1.2.3
|
'@tauri-apps/cli-linux-x64-musl': 1.3.1
|
||||||
'@tauri-apps/cli-win32-ia32-msvc': 1.2.3
|
'@tauri-apps/cli-win32-ia32-msvc': 1.3.1
|
||||||
'@tauri-apps/cli-win32-x64-msvc': 1.2.3
|
'@tauri-apps/cli-win32-x64-msvc': 1.3.1
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/@tauri-release/cli/0.2.5:
|
/@tauri-release/cli/0.2.5:
|
||||||
|
BIN
public/bmc.png
Normal file
BIN
public/bmc.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.6 KiB |
BIN
public/wxp.png
Normal file
BIN
public/wxp.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 248 KiB |
92
src-tauri/src/scripts/chat.js → scripts/chat.js
vendored
92
src-tauri/src/scripts/chat.js → scripts/chat.js
vendored
@ -1,7 +1,13 @@
|
|||||||
|
/**
|
||||||
|
* @name chat.js
|
||||||
|
* @version 0.1.0
|
||||||
|
* @url https://github.com/lencx/ChatGPT/tree/main/scripts/chat.js
|
||||||
|
*/
|
||||||
|
|
||||||
async function init() {
|
async function init() {
|
||||||
new MutationObserver(function (mutationsList) {
|
new MutationObserver(function (mutationsList) {
|
||||||
for (const mutation of mutationsList) {
|
for (const mutation of mutationsList) {
|
||||||
if (mutation.target.closest("form")) {
|
if (mutation.target.closest('form')) {
|
||||||
chatBtns();
|
chatBtns();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -10,28 +16,29 @@ async function init() {
|
|||||||
subtree: true,
|
subtree: true,
|
||||||
});
|
});
|
||||||
document.addEventListener('visibilitychange', () =>
|
document.addEventListener('visibilitychange', () =>
|
||||||
document.getElementsByTagName('textarea')[0]?.focus()
|
document.getElementsByTagName('textarea')[0]?.focus(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function chatBtns() {
|
async function chatBtns() {
|
||||||
const chatConf = await invoke('get_app_conf') || {};
|
const chatConf = (await invoke('get_app_conf')) || {};
|
||||||
const synth = window.speechSynthesis;
|
const synth = window.speechSynthesis;
|
||||||
let currentUtterance = null;
|
let currentUtterance = null;
|
||||||
let currentIndex = -1;
|
let currentIndex = -1;
|
||||||
const list = Array.from(document.querySelectorAll("main >div>div>div>div>div"));
|
const list = Array.from(document.querySelectorAll('main >div>div>div>div>div'));
|
||||||
list.forEach((i, idx) => {
|
list.forEach((i, idx) => {
|
||||||
if (i.querySelector('.chat-item-copy')) return;
|
// if (i.querySelector('.chat-item-copy')) return;
|
||||||
|
if (i.querySelector('.chat-item-voice')) return;
|
||||||
if (!i.querySelector('button.rounded-md')) return;
|
if (!i.querySelector('button.rounded-md')) return;
|
||||||
if (!i.querySelector('.self-end')) return;
|
if (!i.querySelector('.self-end')) return;
|
||||||
const cpbtn = i.querySelector('button.rounded-md').cloneNode(true);
|
// const cpbtn = i.querySelector('button.rounded-md').cloneNode(true);
|
||||||
cpbtn.classList.add('chat-item-copy');
|
// cpbtn.classList.add('chat-item-copy');
|
||||||
cpbtn.title = 'Copy to clipboard';
|
// cpbtn.title = 'Copy to clipboard';
|
||||||
cpbtn.innerHTML = setIcon('copy');
|
// cpbtn.innerHTML = setIcon('copy');
|
||||||
i.querySelector('.self-end').appendChild(cpbtn);
|
// i.querySelector('.self-end').appendChild(cpbtn);
|
||||||
cpbtn.onclick = () => {
|
// cpbtn.onclick = () => {
|
||||||
copyToClipboard(i?.innerText?.trim() || '', cpbtn);
|
// copyToClipboard(i?.innerText?.trim() || '', cpbtn);
|
||||||
}
|
// }
|
||||||
|
|
||||||
const saybtn = i.querySelector('button.rounded-md').cloneNode(true);
|
const saybtn = i.querySelector('button.rounded-md').cloneNode(true);
|
||||||
saybtn.classList.add('chat-item-voice');
|
saybtn.classList.add('chat-item-voice');
|
||||||
@ -55,9 +62,9 @@ async function chatBtns() {
|
|||||||
if (!txt) return;
|
if (!txt) return;
|
||||||
const utterance = new SpeechSynthesisUtterance(txt);
|
const utterance = new SpeechSynthesisUtterance(txt);
|
||||||
const voices = speechSynthesis.getVoices();
|
const voices = speechSynthesis.getVoices();
|
||||||
let voice = voices.find(voice => voice.voiceURI === chatConf.speech_lang);
|
let voice = voices.find((voice) => voice.voiceURI === chatConf.speech_lang);
|
||||||
if (!voice) {
|
if (!voice) {
|
||||||
voice = voices.find(voice => voice.lang === 'en-US');
|
voice = voices.find((voice) => voice.lang === 'en-US');
|
||||||
}
|
}
|
||||||
utterance.voice = voice;
|
utterance.voice = voice;
|
||||||
currentIndex = idx;
|
currentIndex = idx;
|
||||||
@ -74,35 +81,35 @@ async function chatBtns() {
|
|||||||
saybtn.innerHTML = setIcon('voice');
|
saybtn.innerHTML = setIcon('voice');
|
||||||
currentUtterance = null;
|
currentUtterance = null;
|
||||||
currentIndex = -1;
|
currentIndex = -1;
|
||||||
}
|
};
|
||||||
}
|
};
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function copyToClipboard(text, btn) {
|
// function copyToClipboard(text, btn) {
|
||||||
window.clearTimeout(window.__cpTimeout);
|
// window.clearTimeout(window.__cpTimeout);
|
||||||
btn.innerHTML = setIcon('cpok');
|
// btn.innerHTML = setIcon('cpok');
|
||||||
if (navigator.clipboard) {
|
// if (navigator.clipboard) {
|
||||||
navigator.clipboard.writeText(text);
|
// navigator.clipboard.writeText(text);
|
||||||
} else {
|
// } else {
|
||||||
var textarea = document.createElement('textarea');
|
// var textarea = document.createElement('textarea');
|
||||||
document.body.appendChild(textarea);
|
// document.body.appendChild(textarea);
|
||||||
textarea.style.position = 'fixed';
|
// textarea.style.position = 'fixed';
|
||||||
textarea.style.clip = 'rect(0 0 0 0)';
|
// textarea.style.clip = 'rect(0 0 0 0)';
|
||||||
textarea.style.top = '10px';
|
// textarea.style.top = '10px';
|
||||||
textarea.value = text;
|
// textarea.value = text;
|
||||||
textarea.select();
|
// textarea.select();
|
||||||
document.execCommand('copy', true);
|
// document.execCommand('copy', true);
|
||||||
document.body.removeChild(textarea);
|
// document.body.removeChild(textarea);
|
||||||
}
|
// }
|
||||||
window.__cpTimeout = setTimeout(() => {
|
// window.__cpTimeout = setTimeout(() => {
|
||||||
btn.innerHTML = setIcon('copy');
|
// btn.innerHTML = setIcon('copy');
|
||||||
}, 1000);
|
// }, 1000);
|
||||||
}
|
// }
|
||||||
|
|
||||||
function focusOnInput() {
|
function focusOnInput() {
|
||||||
// This currently works because there is only a single `<textarea>` element on the ChatGPT UI page.
|
// This currently works because there is only a single `<textarea>` element on the ChatGPT UI page.
|
||||||
document.getElementsByTagName("textarea")[0].focus();
|
document.getElementsByTagName('textarea')[0].focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
function setIcon(type) {
|
function setIcon(type) {
|
||||||
@ -114,11 +121,8 @@ function setIcon(type) {
|
|||||||
}[type];
|
}[type];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (document.readyState === 'complete' || document.readyState === 'interactive') {
|
||||||
document.readyState === "complete" ||
|
|
||||||
document.readyState === "interactive"
|
|
||||||
) {
|
|
||||||
init();
|
init();
|
||||||
} else {
|
} else {
|
||||||
document.addEventListener("DOMContentLoaded", init);
|
document.addEventListener('DOMContentLoaded', init);
|
||||||
}
|
}
|
66
src-tauri/src/scripts/cmd.js → scripts/cmd.js
vendored
66
src-tauri/src/scripts/cmd.js → scripts/cmd.js
vendored
@ -1,4 +1,8 @@
|
|||||||
// *** Core Script - CMD ***
|
/**
|
||||||
|
* @name cmd.js
|
||||||
|
* @version 0.1.0
|
||||||
|
* @url https://github.com/lencx/ChatGPT/tree/main/scripts/cmd.js
|
||||||
|
*/
|
||||||
|
|
||||||
function init() {
|
function init() {
|
||||||
const styleDom = document.createElement('style');
|
const styleDom = document.createElement('style');
|
||||||
@ -105,7 +109,7 @@ function init() {
|
|||||||
clearInterval(window.formInterval);
|
clearInterval(window.formInterval);
|
||||||
}
|
}
|
||||||
window.formInterval = setInterval(() => {
|
window.formInterval = setInterval(() => {
|
||||||
const form = document.querySelector("form textarea");
|
const form = document.querySelector('form textarea');
|
||||||
if (!form) return;
|
if (!form) return;
|
||||||
clearInterval(window.formInterval);
|
clearInterval(window.formInterval);
|
||||||
cmdTip();
|
cmdTip();
|
||||||
@ -117,11 +121,11 @@ function init() {
|
|||||||
}
|
}
|
||||||
if (mutation.target.getAttribute('class') === 'chat-model-cmd-list') {
|
if (mutation.target.getAttribute('class') === 'chat-model-cmd-list') {
|
||||||
// The `chatgpt prompt` fill can be done by clicking on the event.
|
// The `chatgpt prompt` fill can be done by clicking on the event.
|
||||||
const searchDom = document.querySelector("form .chat-model-cmd-list>div");
|
const searchDom = document.querySelector('form .chat-model-cmd-list>div');
|
||||||
const searchInput = document.querySelector('form textarea');
|
const searchInput = document.querySelector('form textarea');
|
||||||
if (!searchDom) return;
|
if (!searchDom) return;
|
||||||
searchDom.addEventListener('click', (event) => {
|
searchDom.addEventListener('click', (event) => {
|
||||||
const item = event.target.closest("div");
|
const item = event.target.closest('div');
|
||||||
if (item) {
|
if (item) {
|
||||||
const val = decodeURIComponent(item.getAttribute('data-prompt'));
|
const val = decodeURIComponent(item.getAttribute('data-prompt'));
|
||||||
searchInput.value = val;
|
searchInput.value = val;
|
||||||
@ -140,7 +144,7 @@ function init() {
|
|||||||
|
|
||||||
async function cmdTip() {
|
async function cmdTip() {
|
||||||
initDom();
|
initDom();
|
||||||
const chatModelJson = await invoke('get_chat_model_cmd') || {};
|
const chatModelJson = (await invoke('get_chat_model_cmd')) || {};
|
||||||
const data = chatModelJson.data;
|
const data = chatModelJson.data;
|
||||||
if (data.length <= 0) return;
|
if (data.length <= 0) return;
|
||||||
|
|
||||||
@ -156,7 +160,12 @@ async function cmdTip() {
|
|||||||
modelDom.style.bottom = '54px';
|
modelDom.style.bottom = '54px';
|
||||||
}
|
}
|
||||||
|
|
||||||
const itemDom = (v) => `<div class="cmd-item" title="${v.prompt}" data-cmd="${v.cmd}" data-prompt="${encodeURIComponent(v.prompt)}"><b title="${v.cmd}">/${v.cmd}</b><i>${v.act}</i></div>`;
|
const itemDom = (v) =>
|
||||||
|
`<div class="cmd-item" title="${v.prompt}" data-cmd="${
|
||||||
|
v.cmd
|
||||||
|
}" data-prompt="${encodeURIComponent(v.prompt)}"><b title="${v.cmd}">/${v.cmd}</b><i>${
|
||||||
|
v.act
|
||||||
|
}</i></div>`;
|
||||||
const renderList = (v) => {
|
const renderList = (v) => {
|
||||||
initDom();
|
initDom();
|
||||||
modelDom.innerHTML = `<div>${v.map(itemDom).join('')}</div>`;
|
modelDom.innerHTML = `<div>${v.map(itemDom).join('')}</div>`;
|
||||||
@ -168,16 +177,23 @@ async function cmdTip() {
|
|||||||
};
|
};
|
||||||
const setPrompt = (v = '') => {
|
const setPrompt = (v = '') => {
|
||||||
if (v.trim()) {
|
if (v.trim()) {
|
||||||
window.__CHAT_MODEL_CMD_PROMPT__ = window.__CHAT_MODEL_CMD_PROMPT__?.replace(/\{([^{}]*)\}/, `{${v.trim()}}`);
|
window.__CHAT_MODEL_CMD_PROMPT__ = window.__CHAT_MODEL_CMD_PROMPT__?.replace(
|
||||||
}
|
/\{([^{}]*)\}/,
|
||||||
|
`{${v.trim()}}`,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
};
|
||||||
const searchInput = document.querySelector('form textarea');
|
const searchInput = document.querySelector('form textarea');
|
||||||
|
|
||||||
// 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.
|
||||||
function cmdKeydown(event) {
|
function cmdKeydown(event) {
|
||||||
if (!window.__CHAT_MODEL_CMD_PROMPT__) {
|
if (!window.__CHAT_MODEL_CMD_PROMPT__) {
|
||||||
if (!event.shiftKey && event.keyCode === 13 && __TAURI_METADATA__.__currentWindow.label === 'tray') {
|
if (
|
||||||
|
!event.shiftKey &&
|
||||||
|
event.keyCode === 13 &&
|
||||||
|
__TAURI_METADATA__.__currentWindow.label === 'tray'
|
||||||
|
) {
|
||||||
const btn = document.querySelector('form button');
|
const btn = document.querySelector('form button');
|
||||||
if (btn) btn.click();
|
if (btn) btn.click();
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
@ -186,20 +202,26 @@ async function cmdTip() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ------------------ Keyboard scrolling (ArrowUp | ArrowDown) --------------------------
|
// ------------------ Keyboard scrolling (ArrowUp | ArrowDown) --------------------------
|
||||||
if (event.keyCode === 38 && window.__cmd_index > 0) { // ArrowUp
|
if (event.keyCode === 38 && window.__cmd_index > 0) {
|
||||||
|
// ArrowUp
|
||||||
window.__cmd_list[window.__cmd_index].classList.remove('selected');
|
window.__cmd_list[window.__cmd_index].classList.remove('selected');
|
||||||
window.__cmd_index = window.__cmd_index - 1;
|
window.__cmd_index = window.__cmd_index - 1;
|
||||||
window.__cmd_list[window.__cmd_index].classList.add('selected');
|
window.__cmd_list[window.__cmd_index].classList.add('selected');
|
||||||
window.__CHAT_MODEL_CMD_PROMPT__ = decodeURIComponent(window.__cmd_list[window.__cmd_index].getAttribute('data-prompt'));
|
window.__CHAT_MODEL_CMD_PROMPT__ = decodeURIComponent(
|
||||||
|
window.__cmd_list[window.__cmd_index].getAttribute('data-prompt'),
|
||||||
|
);
|
||||||
searchInput.value = `/${window.__cmd_list[window.__cmd_index].getAttribute('data-cmd')}`;
|
searchInput.value = `/${window.__cmd_list[window.__cmd_index].getAttribute('data-cmd')}`;
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event.keyCode === 40 && window.__cmd_index < window.__cmd_list.length - 1) { // ArrowDown
|
if (event.keyCode === 40 && window.__cmd_index < window.__cmd_list.length - 1) {
|
||||||
|
// ArrowDown
|
||||||
window.__cmd_list[window.__cmd_index].classList.remove('selected');
|
window.__cmd_list[window.__cmd_index].classList.remove('selected');
|
||||||
window.__cmd_index = window.__cmd_index + 1;
|
window.__cmd_index = window.__cmd_index + 1;
|
||||||
window.__cmd_list[window.__cmd_index].classList.add('selected');
|
window.__cmd_list[window.__cmd_index].classList.add('selected');
|
||||||
window.__CHAT_MODEL_CMD_PROMPT__ = decodeURIComponent(window.__cmd_list[window.__cmd_index].getAttribute('data-prompt'));
|
window.__CHAT_MODEL_CMD_PROMPT__ = decodeURIComponent(
|
||||||
|
window.__cmd_list[window.__cmd_index].getAttribute('data-prompt'),
|
||||||
|
);
|
||||||
searchInput.value = `/${window.__cmd_list[window.__cmd_index].getAttribute('data-cmd')}`;
|
searchInput.value = `/${window.__cmd_list[window.__cmd_index].getAttribute('data-cmd')}`;
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
}
|
}
|
||||||
@ -228,7 +250,8 @@ async function cmdTip() {
|
|||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (window.__CHAT_MODEL_STATUS__ === 1 && event.keyCode === 9) { // TAB
|
if (window.__CHAT_MODEL_STATUS__ === 1 && event.keyCode === 9) {
|
||||||
|
// TAB
|
||||||
const data = searchInput.value.split('|->');
|
const data = searchInput.value.split('|->');
|
||||||
if (data[1]?.trim()) {
|
if (data[1]?.trim()) {
|
||||||
setPrompt(data[1]);
|
setPrompt(data[1]);
|
||||||
@ -238,7 +261,8 @@ async function cmdTip() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// input text
|
// input text
|
||||||
if (window.__CHAT_MODEL_STATUS__ === 2 && event.keyCode === 9) { // TAB
|
if (window.__CHAT_MODEL_STATUS__ === 2 && event.keyCode === 9) {
|
||||||
|
// TAB
|
||||||
searchInput.value = window.__CHAT_MODEL_CMD_PROMPT__;
|
searchInput.value = window.__CHAT_MODEL_CMD_PROMPT__;
|
||||||
modelDom.innerHTML = '';
|
modelDom.innerHTML = '';
|
||||||
delete window.__CHAT_MODEL_STATUS__;
|
delete window.__CHAT_MODEL_STATUS__;
|
||||||
@ -253,7 +277,8 @@ async function cmdTip() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ------------------ send --------------------------------------------------------------------
|
// ------------------ send --------------------------------------------------------------------
|
||||||
if (event.keyCode === 13 && window.__CHAT_MODEL_CMD_PROMPT__) { // Enter
|
if (event.keyCode === 13 && window.__CHAT_MODEL_CMD_PROMPT__) {
|
||||||
|
// Enter
|
||||||
const data = searchInput.value.split('|->');
|
const data = searchInput.value.split('|->');
|
||||||
setPrompt(data[1]);
|
setPrompt(data[1]);
|
||||||
|
|
||||||
@ -286,7 +311,7 @@ async function cmdTip() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = data.filter(i => 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) {
|
||||||
renderList(result);
|
renderList(result);
|
||||||
} else {
|
} else {
|
||||||
@ -310,11 +335,8 @@ function initDom() {
|
|||||||
delete window.__cmd_index;
|
delete window.__cmd_index;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (document.readyState === 'complete' || document.readyState === 'interactive') {
|
||||||
document.readyState === "complete" ||
|
|
||||||
document.readyState === "interactive"
|
|
||||||
) {
|
|
||||||
init();
|
init();
|
||||||
} else {
|
} else {
|
||||||
document.addEventListener("DOMContentLoaded", init);
|
document.addEventListener('DOMContentLoaded', init);
|
||||||
}
|
}
|
88
src-tauri/src/scripts/core.js → scripts/core.js
vendored
88
src-tauri/src/scripts/core.js → scripts/core.js
vendored
@ -1,4 +1,8 @@
|
|||||||
// *** Core Script - IPC ***
|
/**
|
||||||
|
* @name core.js
|
||||||
|
* @version 0.1.0
|
||||||
|
* @url https://github.com/lencx/ChatGPT/tree/main/scripts/core.js
|
||||||
|
*/
|
||||||
|
|
||||||
const uid = () => window.crypto.getRandomValues(new Uint32Array(1))[0];
|
const uid = () => window.crypto.getRandomValues(new Uint32Array(1))[0];
|
||||||
function transformCallback(callback = () => {}, once = false) {
|
function transformCallback(callback = () => {}, once = false) {
|
||||||
@ -9,11 +13,11 @@ function transformCallback(callback = () => {}, once = false) {
|
|||||||
if (once) {
|
if (once) {
|
||||||
Reflect.deleteProperty(window, prop);
|
Reflect.deleteProperty(window, prop);
|
||||||
}
|
}
|
||||||
return callback(result)
|
return callback(result);
|
||||||
},
|
},
|
||||||
writable: false,
|
writable: false,
|
||||||
configurable: true,
|
configurable: true,
|
||||||
})
|
});
|
||||||
return identifier;
|
return identifier;
|
||||||
}
|
}
|
||||||
async function invoke(cmd, args) {
|
async function invoke(cmd, args) {
|
||||||
@ -22,16 +26,16 @@ async function invoke(cmd, args) {
|
|||||||
const callback = transformCallback((e) => {
|
const callback = transformCallback((e) => {
|
||||||
resolve(e);
|
resolve(e);
|
||||||
Reflect.deleteProperty(window, `_${error}`);
|
Reflect.deleteProperty(window, `_${error}`);
|
||||||
}, true)
|
}, true);
|
||||||
const error = transformCallback((e) => {
|
const error = transformCallback((e) => {
|
||||||
reject(e);
|
reject(e);
|
||||||
Reflect.deleteProperty(window, `_${callback}`);
|
Reflect.deleteProperty(window, `_${callback}`);
|
||||||
}, true)
|
}, true);
|
||||||
window.__TAURI_POST_MESSAGE__({
|
window.__TAURI_POST_MESSAGE__({
|
||||||
cmd,
|
cmd,
|
||||||
callback,
|
callback,
|
||||||
error,
|
error,
|
||||||
...args
|
...args,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -44,8 +48,8 @@ async function message(message) {
|
|||||||
message: message.toString(),
|
message: message.toString(),
|
||||||
title: null,
|
title: null,
|
||||||
type: null,
|
type: null,
|
||||||
buttonLabel: null
|
buttonLabel: null,
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -62,39 +66,47 @@ async function init() {
|
|||||||
async function platform() {
|
async function platform() {
|
||||||
return invoke('platform', {
|
return invoke('platform', {
|
||||||
__tauriModule: 'Os',
|
__tauriModule: 'Os',
|
||||||
message: { cmd: 'platform' }
|
message: { cmd: 'platform' },
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (__TAURI_METADATA__.__currentWindow.label !== 'tray') {
|
if (__TAURI_METADATA__.__currentWindow.label !== 'tray') {
|
||||||
const _platform = await platform();
|
const _platform = await platform();
|
||||||
const chatConf = await invoke('get_app_conf') || {};
|
const chatConf = (await invoke('get_app_conf')) || {};
|
||||||
if (/darwin/.test(_platform) && !chatConf.titlebar) {
|
if (/darwin/.test(_platform) && !chatConf.titlebar) {
|
||||||
const topStyleDom = document.createElement("style");
|
const topStyleDom = document.createElement('style');
|
||||||
topStyleDom.innerHTML = `#chatgpt-app-window-top{position:fixed;top:0;z-index:999999999;width:100%;height:24px;background:transparent;cursor:grab;cursor:-webkit-grab;user-select:none;-webkit-user-select:none;}#chatgpt-app-window-top:active {cursor:grabbing;cursor:-webkit-grabbing;}`;
|
topStyleDom.innerHTML = `#chatgpt-app-window-top{position:fixed;top:0;z-index:999999999;width:100%;height:24px;background:transparent;cursor:grab;cursor:-webkit-grab;user-select:none;-webkit-user-select:none;}#chatgpt-app-window-top:active {cursor:grabbing;cursor:-webkit-grabbing;}`;
|
||||||
document.head.appendChild(topStyleDom);
|
document.head.appendChild(topStyleDom);
|
||||||
const topDom = document.createElement("div");
|
const topDom = document.createElement('div');
|
||||||
topDom.id = "chatgpt-app-window-top";
|
topDom.id = 'chatgpt-app-window-top';
|
||||||
document.body.appendChild(topDom);
|
document.body.appendChild(topDom);
|
||||||
|
|
||||||
if (window.location.host === 'chat.openai.com') {
|
if (window.location.host === 'chat.openai.com') {
|
||||||
const nav = document.body.querySelector('nav');
|
const nav = document.body.querySelector('nav');
|
||||||
if (nav) {
|
if (nav) {
|
||||||
const currentPaddingTop = parseInt(window.getComputedStyle(document.querySelector('nav'), null).getPropertyValue('padding-top').replace('px', ''), 10);
|
const currentPaddingTop = parseInt(
|
||||||
const navStyleDom = document.createElement("style");
|
window
|
||||||
navStyleDom.innerHTML = `nav{padding-top:${currentPaddingTop + topDom.clientHeight}px !important}`;
|
.getComputedStyle(document.querySelector('nav'), null)
|
||||||
|
.getPropertyValue('padding-top')
|
||||||
|
.replace('px', ''),
|
||||||
|
10,
|
||||||
|
);
|
||||||
|
const navStyleDom = document.createElement('style');
|
||||||
|
navStyleDom.innerHTML = `nav{padding-top:${
|
||||||
|
currentPaddingTop + topDom.clientHeight
|
||||||
|
}px !important}`;
|
||||||
document.head.appendChild(navStyleDom);
|
document.head.appendChild(navStyleDom);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
topDom.addEventListener("mousedown", () => invoke("drag_window"));
|
topDom.addEventListener('mousedown', () => invoke('drag_window'));
|
||||||
topDom.addEventListener("touchstart", () => invoke("drag_window"));
|
topDom.addEventListener('touchstart', () => invoke('drag_window'));
|
||||||
topDom.addEventListener("dblclick", () => invoke("fullscreen"));
|
topDom.addEventListener('dblclick', () => invoke('fullscreen'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
document.addEventListener("click", (e) => {
|
document.addEventListener('click', (e) => {
|
||||||
const origin = e.target.closest("a");
|
const origin = e.target.closest('a');
|
||||||
if (!origin || !origin.target) return;
|
if (!origin || !origin.target) return;
|
||||||
if (origin && origin.href && origin.target !== '_self') {
|
if (origin && origin.href && origin.target !== '_self') {
|
||||||
invoke('open_link', { url: origin.href });
|
invoke('open_link', { url: origin.href });
|
||||||
@ -102,14 +114,18 @@ async function init() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Fix Chinese input method "Enter" on Safari
|
// Fix Chinese input method "Enter" on Safari
|
||||||
document.addEventListener("keydown", (e) => {
|
document.addEventListener(
|
||||||
|
'keydown',
|
||||||
|
(e) => {
|
||||||
if (e.keyCode == 229) e.stopPropagation();
|
if (e.keyCode == 229) e.stopPropagation();
|
||||||
}, true)
|
},
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
|
||||||
if (window.location.host === 'chat.openai.com') {
|
if (window.location.host === 'chat.openai.com') {
|
||||||
window.__sync_prompts = async function () {
|
window.__sync_prompts = async function () {
|
||||||
await invoke('sync_prompts', { time: Date.now() });
|
await invoke('sync_prompts', { time: Date.now() });
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
coreZoom();
|
coreZoom();
|
||||||
@ -145,11 +161,11 @@ function coreZoom() {
|
|||||||
document.body.appendChild(zoomTipDom);
|
document.body.appendChild(zoomTipDom);
|
||||||
function zoom(callback) {
|
function zoom(callback) {
|
||||||
if (window.zoomSetTimeout) clearTimeout(window.zoomSetTimeout);
|
if (window.zoomSetTimeout) clearTimeout(window.zoomSetTimeout);
|
||||||
const htmlZoom = window.localStorage.getItem("htmlZoom") || "100%";
|
const htmlZoom = window.localStorage.getItem('htmlZoom') || '100%';
|
||||||
const html = document.getElementsByTagName("html")[0];
|
const html = document.getElementsByTagName('html')[0];
|
||||||
const zoom = callback(htmlZoom);
|
const zoom = callback(htmlZoom);
|
||||||
html.style.zoom = zoom;
|
html.style.zoom = zoom;
|
||||||
window.localStorage.setItem("htmlZoom", zoom);
|
window.localStorage.setItem('htmlZoom', zoom);
|
||||||
zoomTipDom.innerHTML = zoom;
|
zoomTipDom.innerHTML = zoom;
|
||||||
zoomTipDom.style.display = 'block';
|
zoomTipDom.style.display = 'block';
|
||||||
zoomTipDom.classList.remove('ZoomTopTipAni');
|
zoomTipDom.classList.remove('ZoomTopTipAni');
|
||||||
@ -158,9 +174,9 @@ function coreZoom() {
|
|||||||
}, 2500);
|
}, 2500);
|
||||||
}
|
}
|
||||||
function zoomDefault() {
|
function zoomDefault() {
|
||||||
const htmlZoom = window.localStorage.getItem("htmlZoom");
|
const htmlZoom = window.localStorage.getItem('htmlZoom');
|
||||||
if (htmlZoom) {
|
if (htmlZoom) {
|
||||||
document.getElementsByTagName("html")[0].style.zoom = htmlZoom;
|
document.getElementsByTagName('html')[0].style.zoom = htmlZoom;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function zoomIn() {
|
function zoomIn() {
|
||||||
@ -176,20 +192,10 @@ function coreZoom() {
|
|||||||
window.__zoomIn = zoomIn;
|
window.__zoomIn = zoomIn;
|
||||||
window.__zoomOut = zoomOut;
|
window.__zoomOut = zoomOut;
|
||||||
window.__zoom0 = zoom0;
|
window.__zoom0 = zoom0;
|
||||||
|
|
||||||
window.__clearCache = () => {
|
|
||||||
window.localStorage.clear();
|
|
||||||
window.sessionStorage.clear();
|
|
||||||
window.applicationCache && window.applicationCache.update();
|
|
||||||
window.location.reload();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (document.readyState === 'complete' || document.readyState === 'interactive') {
|
||||||
document.readyState === "complete" ||
|
|
||||||
document.readyState === "interactive"
|
|
||||||
) {
|
|
||||||
init();
|
init();
|
||||||
} else {
|
} else {
|
||||||
document.addEventListener("DOMContentLoaded", init);
|
document.addEventListener('DOMContentLoaded', init);
|
||||||
}
|
}
|
@ -1,8 +1,12 @@
|
|||||||
// *** Core Script - DALL·E 2 ***
|
/**
|
||||||
|
* @name dalle2.js
|
||||||
|
* @version 0.1.0
|
||||||
|
* @url https://github.com/lencx/ChatGPT/tree/main/scripts/dalle2.js
|
||||||
|
*/
|
||||||
|
|
||||||
function init() {
|
function init() {
|
||||||
document.addEventListener("click", (e) => {
|
document.addEventListener('click', (e) => {
|
||||||
const origin = e.target.closest("a");
|
const origin = e.target.closest('a');
|
||||||
if (!origin || !origin.target) return;
|
if (!origin || !origin.target) return;
|
||||||
if (origin && origin.href && origin.target !== '_self') {
|
if (origin && origin.href && origin.target !== '_self') {
|
||||||
if (/\/(login|signup)$/.test(window.location.href)) {
|
if (/\/(login|signup)$/.test(window.location.href)) {
|
||||||
@ -27,14 +31,11 @@ function init() {
|
|||||||
searchInput.focus();
|
searchInput.focus();
|
||||||
searchInput.value = query;
|
searchInput.value = query;
|
||||||
}
|
}
|
||||||
}, 200)
|
}, 200);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (document.readyState === 'complete' || document.readyState === 'interactive') {
|
||||||
document.readyState === "complete" ||
|
|
||||||
document.readyState === "interactive"
|
|
||||||
) {
|
|
||||||
init();
|
init();
|
||||||
} else {
|
} else {
|
||||||
document.addEventListener("DOMContentLoaded", init);
|
document.addEventListener('DOMContentLoaded', init);
|
||||||
}
|
}
|
180
src-tauri/src/scripts/export.js → scripts/export.js
vendored
180
src-tauri/src/scripts/export.js → scripts/export.js
vendored
@ -1,27 +1,32 @@
|
|||||||
// *** Core Script - Export ***
|
/**
|
||||||
|
* @name export.js
|
||||||
|
* @version 0.1.0
|
||||||
|
* @url https://github.com/lencx/ChatGPT/tree/main/scripts/export.js
|
||||||
|
*/
|
||||||
|
|
||||||
async function init() {
|
async function init() {
|
||||||
if (window.location.pathname === '/auth/login') return;
|
if (window.location.pathname === '/auth/login') return;
|
||||||
const buttonOuterHTMLFallback = `<button class="btn flex justify-center gap-2 btn-neutral" id="download-png-button">Try Again</button>`;
|
const buttonOuterHTMLFallback = `<button class="btn flex justify-center gap-2 btn-neutral">Try Again</button>`;
|
||||||
removeButtons();
|
removeButtons();
|
||||||
if (window.buttonsInterval) {
|
if (window.buttonsInterval) {
|
||||||
clearInterval(window.buttonsInterval);
|
clearInterval(window.buttonsInterval);
|
||||||
}
|
}
|
||||||
if (window.innerWidth < 767) return;
|
if (window.innerWidth < 767) return;
|
||||||
|
|
||||||
const chatConf = await invoke('get_app_conf') || {};
|
const chatConf = (await invoke('get_app_conf')) || {};
|
||||||
window.buttonsInterval = setInterval(() => {
|
window.buttonsInterval = setInterval(() => {
|
||||||
const actionsArea = document.querySelector("form>div>div");
|
const actionsArea = document.querySelector('form>div>div>div');
|
||||||
if (!actionsArea) {
|
const hasBtn = document.querySelector('form>div>div>div button');
|
||||||
|
if (!actionsArea || !hasBtn) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (shouldAddButtons(actionsArea)) {
|
if (shouldAddButtons(actionsArea)) {
|
||||||
let TryAgainButton = actionsArea.querySelector("button");
|
let TryAgainButton = actionsArea.querySelector('button');
|
||||||
if (!TryAgainButton) {
|
if (!TryAgainButton) {
|
||||||
const parentNode = document.createElement("div");
|
const parentNode = document.createElement('div');
|
||||||
parentNode.innerHTML = buttonOuterHTMLFallback;
|
parentNode.innerHTML = buttonOuterHTMLFallback;
|
||||||
TryAgainButton = parentNode.querySelector("button");
|
TryAgainButton = parentNode.querySelector('button');
|
||||||
}
|
}
|
||||||
addActionsButtons(actionsArea, TryAgainButton, chatConf);
|
addActionsButtons(actionsArea, TryAgainButton, chatConf);
|
||||||
} else if (shouldRemoveButtons()) {
|
} else if (shouldRemoveButtons()) {
|
||||||
@ -30,12 +35,12 @@ async function init() {
|
|||||||
}, 1000);
|
}, 1000);
|
||||||
|
|
||||||
const Format = {
|
const Format = {
|
||||||
PNG: "png",
|
PNG: 'png',
|
||||||
PDF: "pdf",
|
PDF: 'pdf',
|
||||||
};
|
};
|
||||||
|
|
||||||
function shouldRemoveButtons() {
|
function shouldRemoveButtons() {
|
||||||
if (document.querySelector("form .text-2xl")) {
|
if (document.querySelector('form .text-2xl')) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@ -43,7 +48,7 @@ async function init() {
|
|||||||
|
|
||||||
function shouldAddButtons(actionsArea) {
|
function shouldAddButtons(actionsArea) {
|
||||||
// first, check if there's a "Try Again" button and no other buttons
|
// first, check if there's a "Try Again" button and no other buttons
|
||||||
const buttons = actionsArea.querySelectorAll("button");
|
const buttons = actionsArea.querySelectorAll('button');
|
||||||
|
|
||||||
const hasTryAgainButton = Array.from(buttons).some((button) => {
|
const hasTryAgainButton = Array.from(buttons).some((button) => {
|
||||||
return !/download-/.test(button.id);
|
return !/download-/.test(button.id);
|
||||||
@ -51,11 +56,14 @@ async function init() {
|
|||||||
|
|
||||||
const stopBtn = buttons?.[0]?.innerText;
|
const stopBtn = buttons?.[0]?.innerText;
|
||||||
|
|
||||||
if (/Stop generating/ig.test(stopBtn)) {
|
if (/Stop generating/gi.test(stopBtn)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (buttons.length === 2 && (/Regenerate response/ig.test(stopBtn) || buttons[1].innerText === '')) {
|
if (
|
||||||
|
buttons.length === 2 &&
|
||||||
|
(/Regenerate response/gi.test(stopBtn) || buttons[1].innerText === '')
|
||||||
|
) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -64,14 +72,14 @@ async function init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// otherwise, check if open screen is not visible
|
// otherwise, check if open screen is not visible
|
||||||
const isOpenScreen = document.querySelector("h1.text-4xl");
|
const isOpenScreen = document.querySelector('h1.text-4xl');
|
||||||
if (isOpenScreen) {
|
if (isOpenScreen) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if the conversation is finished and there are no share buttons
|
// check if the conversation is finished and there are no share buttons
|
||||||
const finishedConversation = document.querySelector("form button>svg");
|
const finishedConversation = document.querySelector('form button>svg');
|
||||||
const hasShareButtons = actionsArea.querySelectorAll("button[share-ext]");
|
const hasShareButtons = actionsArea.querySelectorAll('button[share-ext]');
|
||||||
if (finishedConversation && !hasShareButtons.length) {
|
if (finishedConversation && !hasShareButtons.length) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -80,10 +88,10 @@ async function init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function removeButtons() {
|
function removeButtons() {
|
||||||
const downloadPngButton = document.getElementById("download-png-button");
|
const downloadPngButton = document.getElementById('download-png-button');
|
||||||
const downloadPdfButton = document.getElementById("download-pdf-button");
|
const downloadPdfButton = document.getElementById('download-pdf-button');
|
||||||
const downloadMdButton = document.getElementById("download-markdown-button");
|
const downloadMdButton = document.getElementById('download-markdown-button');
|
||||||
const refreshButton = document.getElementById("refresh-page-button");
|
const refreshButton = document.getElementById('refresh-page-button');
|
||||||
if (downloadPngButton) {
|
if (downloadPngButton) {
|
||||||
downloadPngButton.remove();
|
downloadPngButton.remove();
|
||||||
}
|
}
|
||||||
@ -101,9 +109,9 @@ async function init() {
|
|||||||
function addActionsButtons(actionsArea, TryAgainButton) {
|
function addActionsButtons(actionsArea, TryAgainButton) {
|
||||||
// Export markdown
|
// Export markdown
|
||||||
const exportMd = TryAgainButton.cloneNode(true);
|
const exportMd = TryAgainButton.cloneNode(true);
|
||||||
exportMd.id = "download-markdown-button";
|
exportMd.id = 'download-markdown-button';
|
||||||
exportMd.setAttribute("share-ext", "true");
|
exportMd.setAttribute('share-ext', 'true');
|
||||||
exportMd.title = "Export Markdown";
|
exportMd.title = 'Export Markdown';
|
||||||
|
|
||||||
exportMd.innerHTML = setIcon('md');
|
exportMd.innerHTML = setIcon('md');
|
||||||
exportMd.onclick = () => {
|
exportMd.onclick = () => {
|
||||||
@ -113,9 +121,9 @@ async function init() {
|
|||||||
|
|
||||||
// Generate PNG
|
// Generate PNG
|
||||||
const downloadPngButton = TryAgainButton.cloneNode(true);
|
const downloadPngButton = TryAgainButton.cloneNode(true);
|
||||||
downloadPngButton.id = "download-png-button";
|
downloadPngButton.id = 'download-png-button';
|
||||||
downloadPngButton.setAttribute("share-ext", "true");
|
downloadPngButton.setAttribute('share-ext', 'true');
|
||||||
downloadPngButton.title = "Generate PNG";
|
downloadPngButton.title = 'Generate PNG';
|
||||||
downloadPngButton.innerHTML = setIcon('png');
|
downloadPngButton.innerHTML = setIcon('png');
|
||||||
downloadPngButton.onclick = () => {
|
downloadPngButton.onclick = () => {
|
||||||
downloadThread();
|
downloadThread();
|
||||||
@ -124,9 +132,9 @@ async function init() {
|
|||||||
|
|
||||||
// Generate PDF
|
// Generate PDF
|
||||||
const downloadPdfButton = TryAgainButton.cloneNode(true);
|
const downloadPdfButton = TryAgainButton.cloneNode(true);
|
||||||
downloadPdfButton.id = "download-pdf-button";
|
downloadPdfButton.id = 'download-pdf-button';
|
||||||
downloadPdfButton.setAttribute("share-ext", "true");
|
downloadPdfButton.setAttribute('share-ext', 'true');
|
||||||
downloadPdfButton.title = "Download PDF";
|
downloadPdfButton.title = 'Download PDF';
|
||||||
downloadPdfButton.innerHTML = setIcon('pdf');
|
downloadPdfButton.innerHTML = setIcon('pdf');
|
||||||
downloadPdfButton.onclick = () => {
|
downloadPdfButton.onclick = () => {
|
||||||
downloadThread({ as: Format.PDF });
|
downloadThread({ as: Format.PDF });
|
||||||
@ -135,8 +143,8 @@ async function init() {
|
|||||||
|
|
||||||
// Refresh
|
// Refresh
|
||||||
const refreshButton = TryAgainButton.cloneNode(true);
|
const refreshButton = TryAgainButton.cloneNode(true);
|
||||||
refreshButton.id = "refresh-page-button";
|
refreshButton.id = 'refresh-page-button';
|
||||||
refreshButton.title = "Refresh the Page";
|
refreshButton.title = 'Refresh the Page';
|
||||||
refreshButton.innerHTML = setIcon('refresh');
|
refreshButton.innerHTML = setIcon('refresh');
|
||||||
refreshButton.onclick = () => {
|
refreshButton.onclick = () => {
|
||||||
window.location.reload();
|
window.location.reload();
|
||||||
@ -145,13 +153,15 @@ async function init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function exportMarkdown() {
|
async function exportMarkdown() {
|
||||||
const content = Array.from(document.querySelectorAll('main .items-center>div')).map(i => {
|
const content = Array.from(document.querySelectorAll('main .items-center>div'))
|
||||||
|
.map((i) => {
|
||||||
let j = i.cloneNode(true);
|
let j = i.cloneNode(true);
|
||||||
if (/dark\:bg-gray-800/.test(i.getAttribute('class'))) {
|
if (/dark\:bg-gray-800/.test(i.getAttribute('class'))) {
|
||||||
j.innerHTML = `<blockquote>${i.innerHTML}</blockquote>`;
|
j.innerHTML = `<blockquote>${i.innerHTML}</blockquote>`;
|
||||||
}
|
}
|
||||||
return j.innerHTML;
|
return j.innerHTML;
|
||||||
}).join('');
|
})
|
||||||
|
.join('');
|
||||||
const data = ExportMD.turndown(content);
|
const data = ExportMD.turndown(content);
|
||||||
const { id, filename } = getName();
|
const { id, filename } = getName();
|
||||||
await invoke('save_file', { name: `notes/${id}.md`, content: data });
|
await invoke('save_file', { name: `notes/${id}.md`, content: data });
|
||||||
@ -170,7 +180,7 @@ async function init() {
|
|||||||
}).then(async function (canvas) {
|
}).then(async function (canvas) {
|
||||||
elements.restoreLocation();
|
elements.restoreLocation();
|
||||||
window.devicePixelRatio = pixelRatio;
|
window.devicePixelRatio = pixelRatio;
|
||||||
const imgData = canvas.toDataURL("image/png");
|
const imgData = canvas.toDataURL('image/png');
|
||||||
requestAnimationFrame(() => {
|
requestAnimationFrame(() => {
|
||||||
if (as === Format.PDF) {
|
if (as === Format.PDF) {
|
||||||
return handlePdf(imgData, canvas, pixelRatio);
|
return handlePdf(imgData, canvas, pixelRatio);
|
||||||
@ -182,36 +192,26 @@ async function init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function handleImg(imgData) {
|
async function handleImg(imgData) {
|
||||||
const binaryData = atob(imgData.split("base64,")[1]);
|
const binaryData = atob(imgData.split('base64,')[1]);
|
||||||
const data = [];
|
const data = [];
|
||||||
for (let i = 0; i < binaryData.length; i++) {
|
for (let i = 0; i < binaryData.length; i++) {
|
||||||
data.push(binaryData.charCodeAt(i));
|
data.push(binaryData.charCodeAt(i));
|
||||||
}
|
}
|
||||||
const { pathname, id, filename } = getName();
|
const name = `ChatGPT_${formatDateTime()}.png`;
|
||||||
await invoke('download', { name: `download/img/${id}.png`, blob: data });
|
await invoke('download_file', { name: name, blob: data });
|
||||||
await invoke('download_list', { pathname, filename, id, dir: 'download' });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function handlePdf(imgData, canvas, pixelRatio) {
|
async function handlePdf(imgData, canvas, pixelRatio) {
|
||||||
const { jsPDF } = window.jspdf;
|
const { jsPDF } = window.jspdf;
|
||||||
const orientation = canvas.width > canvas.height ? "l" : "p";
|
const orientation = canvas.width > canvas.height ? 'l' : 'p';
|
||||||
var pdf = new jsPDF(orientation, "pt", [
|
var pdf = new jsPDF(orientation, 'pt', [canvas.width / pixelRatio, canvas.height / pixelRatio]);
|
||||||
canvas.width / pixelRatio,
|
|
||||||
canvas.height / pixelRatio,
|
|
||||||
]);
|
|
||||||
var pdfWidth = pdf.internal.pageSize.getWidth();
|
var pdfWidth = pdf.internal.pageSize.getWidth();
|
||||||
var pdfHeight = pdf.internal.pageSize.getHeight();
|
var pdfHeight = pdf.internal.pageSize.getHeight();
|
||||||
pdf.addImage(imgData, "PNG", 0, 0, pdfWidth, pdfHeight, '', 'FAST');
|
pdf.addImage(imgData, 'PNG', 0, 0, pdfWidth, pdfHeight, '', 'FAST');
|
||||||
const { pathname, id, filename } = getName();
|
|
||||||
const data = pdf.__private__.getArrayBuffer(pdf.__private__.buildDocument());
|
const data = pdf.__private__.getArrayBuffer(pdf.__private__.buildDocument());
|
||||||
await invoke('download', { name: `download/pdf/${id}.pdf`, blob: Array.from(new Uint8Array(data)) });
|
|
||||||
await invoke('download_list', { pathname, filename, id, dir: 'download' });
|
|
||||||
}
|
|
||||||
|
|
||||||
function getName() {
|
const name = `ChatGPT_${formatDateTime()}.pdf`;
|
||||||
const id = window.crypto.getRandomValues(new Uint32Array(1))[0].toString(36);
|
await invoke('download_file', { name: name, blob: Array.from(new Uint8Array(data)) });
|
||||||
const name = document.querySelector('nav .overflow-y-auto a.hover\\:bg-gray-800')?.innerText?.trim() || '';
|
|
||||||
return { filename: name ? name : id, id, pathname: 'chat.download.json' };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class Elements {
|
class Elements {
|
||||||
@ -222,62 +222,62 @@ async function init() {
|
|||||||
// this.threadWrapper = document.querySelector(".cdfdFe");
|
// this.threadWrapper = document.querySelector(".cdfdFe");
|
||||||
this.spacer = document.querySelector("[class*='h-48'].w-full.flex-shrink-0");
|
this.spacer = document.querySelector("[class*='h-48'].w-full.flex-shrink-0");
|
||||||
this.thread = document.querySelector(
|
this.thread = document.querySelector(
|
||||||
"[class*='react-scroll-to-bottom']>[class*='react-scroll-to-bottom']>div"
|
"[class*='react-scroll-to-bottom']>[class*='react-scroll-to-bottom']>div",
|
||||||
);
|
);
|
||||||
|
|
||||||
// fix: old chat https://github.com/lencx/ChatGPT/issues/185
|
// fix: old chat https://github.com/lencx/ChatGPT/issues/185
|
||||||
if (!this.thread) {
|
if (!this.thread) {
|
||||||
this.thread = document.querySelector("main .overflow-y-auto");
|
this.thread = document.querySelector('main .overflow-y-auto');
|
||||||
}
|
}
|
||||||
|
|
||||||
// h-full overflow-y-auto
|
// h-full overflow-y-auto
|
||||||
this.positionForm = document.querySelector("form").parentNode;
|
this.positionForm = document.querySelector('form').parentNode;
|
||||||
// this.styledThread = document.querySelector("main");
|
// this.styledThread = document.querySelector("main");
|
||||||
// this.threadContent = document.querySelector(".gAnhyd");
|
// this.threadContent = document.querySelector(".gAnhyd");
|
||||||
this.scroller = Array.from(
|
this.scroller = Array.from(document.querySelectorAll('[class*="react-scroll-to"]')).filter(
|
||||||
document.querySelectorAll('[class*="react-scroll-to"]')
|
(el) => el.classList.contains('h-full'),
|
||||||
).filter((el) => el.classList.contains("h-full"))[0];
|
)[0];
|
||||||
|
|
||||||
// fix: old chat
|
// fix: old chat
|
||||||
if (!this.scroller) {
|
if (!this.scroller) {
|
||||||
this.scroller = document.querySelector('main .overflow-y-auto');
|
this.scroller = document.querySelector('main .overflow-y-auto');
|
||||||
}
|
}
|
||||||
|
|
||||||
this.hiddens = Array.from(document.querySelectorAll(".overflow-hidden"));
|
this.hiddens = Array.from(document.querySelectorAll('.overflow-hidden'));
|
||||||
this.images = Array.from(document.querySelectorAll("img[srcset]"));
|
this.images = Array.from(document.querySelectorAll('img[srcset]'));
|
||||||
}
|
}
|
||||||
fixLocation() {
|
fixLocation() {
|
||||||
this.hiddens.forEach((el) => {
|
this.hiddens.forEach((el) => {
|
||||||
el.classList.remove("overflow-hidden");
|
el.classList.remove('overflow-hidden');
|
||||||
});
|
});
|
||||||
this.spacer.style.display = "none";
|
this.spacer.style.display = 'none';
|
||||||
this.thread.style.maxWidth = "960px";
|
this.thread.style.maxWidth = '960px';
|
||||||
this.thread.style.marginInline = "auto";
|
this.thread.style.marginInline = 'auto';
|
||||||
this.positionForm.style.display = "none";
|
this.positionForm.style.display = 'none';
|
||||||
this.scroller.classList.remove("h-full");
|
this.scroller.classList.remove('h-full');
|
||||||
this.scroller.style.minHeight = "100vh";
|
this.scroller.style.minHeight = '100vh';
|
||||||
this.images.forEach((img) => {
|
this.images.forEach((img) => {
|
||||||
const srcset = img.getAttribute("srcset");
|
const srcset = img.getAttribute('srcset');
|
||||||
img.setAttribute("srcset_old", srcset);
|
img.setAttribute('srcset_old', srcset);
|
||||||
img.setAttribute("srcset", "");
|
img.setAttribute('srcset', '');
|
||||||
});
|
});
|
||||||
//Fix to the text shifting down when generating the canvas
|
//Fix to the text shifting down when generating the canvas
|
||||||
document.body.style.lineHeight = "0.5";
|
document.body.style.lineHeight = '0.5';
|
||||||
}
|
}
|
||||||
restoreLocation() {
|
restoreLocation() {
|
||||||
this.hiddens.forEach((el) => {
|
this.hiddens.forEach((el) => {
|
||||||
el.classList.add("overflow-hidden");
|
el.classList.add('overflow-hidden');
|
||||||
});
|
});
|
||||||
this.spacer.style.display = null;
|
this.spacer.style.display = null;
|
||||||
this.thread.style.maxWidth = null;
|
this.thread.style.maxWidth = null;
|
||||||
this.thread.style.marginInline = null;
|
this.thread.style.marginInline = null;
|
||||||
this.positionForm.style.display = null;
|
this.positionForm.style.display = null;
|
||||||
this.scroller.classList.add("h-full");
|
this.scroller.classList.add('h-full');
|
||||||
this.scroller.style.minHeight = null;
|
this.scroller.style.minHeight = null;
|
||||||
this.images.forEach((img) => {
|
this.images.forEach((img) => {
|
||||||
const srcset = img.getAttribute("srcset_old");
|
const srcset = img.getAttribute('srcset_old');
|
||||||
img.setAttribute("srcset", srcset);
|
img.setAttribute('srcset', srcset);
|
||||||
img.setAttribute("srcset_old", "");
|
img.setAttribute('srcset_old', '');
|
||||||
});
|
});
|
||||||
document.body.style.lineHeight = null;
|
document.body.style.lineHeight = null;
|
||||||
}
|
}
|
||||||
@ -292,15 +292,31 @@ async function init() {
|
|||||||
refresh: `<svg class="chatappico refresh" viewBox="0 0 1024 1024"><path d="M512 63.5C264.3 63.5 63.5 264.3 63.5 512S264.3 960.5 512 960.5 960.5 759.7 960.5 512 759.7 63.5 512 63.5zM198 509.6h87.6c0-136.3 102.3-243.4 233.7-238.5 43.8 0 82.8 14.6 121.7 34.1L597.2 349c-24.4-9.8-53.6-19.5-82.8-19.5-92.5 0-170.4 77.9-170.4 180.1h87.6L314.8 631.3 198 509.6z m540.3-0.1c0 131.4-102.2 243.4-228.8 243.4-43.8 0-82.8-19.4-121.7-38.9l43.8-43.8c24.4 9.8 53.6 19.5 82.8 19.5 92.5 0 170.4-77.9 170.4-180.1h-92.5l116.9-121.7L826 509.5h-87.7z" fill="currentColor"></path></svg>`,
|
refresh: `<svg class="chatappico refresh" viewBox="0 0 1024 1024"><path d="M512 63.5C264.3 63.5 63.5 264.3 63.5 512S264.3 960.5 512 960.5 960.5 759.7 960.5 512 759.7 63.5 512 63.5zM198 509.6h87.6c0-136.3 102.3-243.4 233.7-238.5 43.8 0 82.8 14.6 121.7 34.1L597.2 349c-24.4-9.8-53.6-19.5-82.8-19.5-92.5 0-170.4 77.9-170.4 180.1h87.6L314.8 631.3 198 509.6z m540.3-0.1c0 131.4-102.2 243.4-228.8 243.4-43.8 0-82.8-19.4-121.7-38.9l43.8-43.8c24.4 9.8 53.6 19.5 82.8 19.5 92.5 0 170.4-77.9 170.4-180.1h-92.5l116.9-121.7L826 509.5h-87.7z" fill="currentColor"></path></svg>`,
|
||||||
}[type];
|
}[type];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function formatDateTime() {
|
||||||
|
const now = new Date();
|
||||||
|
const year = now.getFullYear();
|
||||||
|
const month = String(now.getMonth() + 1).padStart(2, '0');
|
||||||
|
const day = String(now.getDate()).padStart(2, '0');
|
||||||
|
const hours = String(now.getHours()).padStart(2, '0');
|
||||||
|
const minutes = String(now.getMinutes()).padStart(2, '0');
|
||||||
|
const seconds = String(now.getSeconds()).padStart(2, '0');
|
||||||
|
const formattedDateTime = `${year}_${month}_${day}_${hours}_${minutes}_${seconds}`;
|
||||||
|
return formattedDateTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getName() {
|
||||||
|
const id = window.crypto.getRandomValues(new Uint32Array(1))[0].toString(36);
|
||||||
|
const name =
|
||||||
|
document.querySelector('nav .overflow-y-auto a.hover\\:bg-gray-800')?.innerText?.trim() || '';
|
||||||
|
return { filename: name ? name : id, id, pathname: 'chat.download.json' };
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
window.addEventListener('resize', init);
|
window.addEventListener('resize', init);
|
||||||
|
|
||||||
if (
|
if (document.readyState === 'complete' || document.readyState === 'interactive') {
|
||||||
document.readyState === "complete" ||
|
|
||||||
document.readyState === "interactive"
|
|
||||||
) {
|
|
||||||
init();
|
init();
|
||||||
} else {
|
} else {
|
||||||
document.addEventListener("DOMContentLoaded", init);
|
document.addEventListener('DOMContentLoaded', init);
|
||||||
}
|
}
|
41
scripts/manifest.json
Normal file
41
scripts/manifest.json
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
{
|
||||||
|
"name": "ChatGPT Script",
|
||||||
|
"author": "lencx",
|
||||||
|
"scripts": [
|
||||||
|
{
|
||||||
|
"name": "core.js",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"url": "https://github.com/lencx/ChatGPT/tree/main/scripts/chat.js"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cmd.js",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"url": "https://github.com/lencx/ChatGPT/tree/main/scripts/cmd.js"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "core.js",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"url": "https://github.com/lencx/ChatGPT/tree/main/scripts/core.js"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "dalle2.js",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"url": "https://github.com/lencx/ChatGPT/tree/main/scripts/dalle2.js"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "export.js",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"url": "https://github.com/lencx/ChatGPT/tree/main/scripts/export.js"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "markdown.export.js",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"url": "https://github.com/lencx/ChatGPT/tree/main/scripts/markdown.export.js"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "popup.core.js",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"url": "https://github.com/lencx/ChatGPT/tree/main/scripts/popup.core.js"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -1,18 +1,24 @@
|
|||||||
|
/**
|
||||||
|
* @name markdown.export.js
|
||||||
|
* @version 0.1.0
|
||||||
|
* @url https://github.com/lencx/ChatGPT/tree/main/scripts/markdown.export.js
|
||||||
|
*/
|
||||||
|
|
||||||
var ExportMD = (function () {
|
var ExportMD = (function () {
|
||||||
if (!TurndownService || !turndownPluginGfm) return;
|
if (!TurndownService || !turndownPluginGfm) return;
|
||||||
const hljsREG = /^.*(hljs).*(language-[a-z0-9]+).*$/i;
|
const hljsREG = /^.*(hljs).*(language-[a-z0-9]+).*$/i;
|
||||||
const gfm = turndownPluginGfm.gfm
|
const gfm = turndownPluginGfm.gfm;
|
||||||
const turndownService = new TurndownService({
|
const turndownService = new TurndownService({
|
||||||
hr: '---'
|
hr: '---',
|
||||||
})
|
})
|
||||||
.use(gfm)
|
.use(gfm)
|
||||||
.addRule('code', {
|
.addRule('code', {
|
||||||
filter: (node) => {
|
filter(node) {
|
||||||
if (node.nodeName === 'CODE' && hljsREG.test(node.classList.value)) {
|
if (node.nodeName === 'CODE' && hljsREG.test(node.classList.value)) {
|
||||||
return 'code';
|
return 'code';
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
replacement: (content, node) => {
|
replacement(content, node) {
|
||||||
const classStr = node.getAttribute('class');
|
const classStr = node.getAttribute('class');
|
||||||
if (hljsREG.test(classStr)) {
|
if (hljsREG.test(classStr)) {
|
||||||
const lang = classStr.match(/.*language-(\w+)/)[1];
|
const lang = classStr.match(/.*language-(\w+)/)[1];
|
||||||
@ -21,18 +27,26 @@ var ExportMD = (function () {
|
|||||||
}
|
}
|
||||||
return `\`\`\`\n${content}\n\`\`\``;
|
return `\`\`\`\n${content}\n\`\`\``;
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.addRule('ignore-text', {
|
||||||
|
filter: (node) => {
|
||||||
|
if (node.nodeName === 'DIV' && node.classList.contains('!invisible')) {
|
||||||
|
return 'ignore-text';
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
replacement: () => '',
|
||||||
})
|
})
|
||||||
.addRule('ignore', {
|
.addRule('ignore', {
|
||||||
filter: ['button', 'img'],
|
filter: ['button', 'img', 'svg'],
|
||||||
replacement: () => '',
|
replacement: () => '',
|
||||||
})
|
})
|
||||||
.addRule('table', {
|
.addRule('table', {
|
||||||
filter: 'table',
|
filter: 'table',
|
||||||
replacement: function(content, node) {
|
replacement(content, node) {
|
||||||
return `\`\`\`${content}\n\`\`\``;
|
return `\`\`\`${content}\n\`\`\``;
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
return turndownService;
|
return turndownService;
|
||||||
}({}));
|
})({});
|
@ -1,7 +1,11 @@
|
|||||||
// *** Core Script - DALL·E 2 Core ***
|
/**
|
||||||
|
* @name popup.core.js
|
||||||
|
* @version 0.1.0
|
||||||
|
* @url https://github.com/lencx/ChatGPT/tree/main/scripts/popup.core.js
|
||||||
|
*/
|
||||||
|
|
||||||
async function init() {
|
async function init() {
|
||||||
const chatConf = await invoke('get_app_conf') || {};
|
const chatConf = (await invoke('get_app_conf')) || {};
|
||||||
if (!chatConf.popup_search) return;
|
if (!chatConf.popup_search) return;
|
||||||
if (!window.FloatingUIDOM) return;
|
if (!window.FloatingUIDOM) return;
|
||||||
|
|
||||||
@ -33,13 +37,15 @@ async function init() {
|
|||||||
document.body.addEventListener('mousedown', async (e) => {
|
document.body.addEventListener('mousedown', async (e) => {
|
||||||
selectionMenu.style.display = 'none';
|
selectionMenu.style.display = 'none';
|
||||||
if (e.target.id === 'chagpt-selection-menu') {
|
if (e.target.id === 'chagpt-selection-menu') {
|
||||||
await invoke('dalle2_search_window', { query: encodeURIComponent(window.__DALLE2_CONTENT__) });
|
await invoke('dalle2_search_window', {
|
||||||
|
query: encodeURIComponent(window.__DALLE2_CONTENT__),
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
delete window.__DALLE2_CONTENT__;
|
delete window.__DALLE2_CONTENT__;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
document.body.addEventListener("mouseup", async (e) => {
|
document.body.addEventListener('mouseup', async (e) => {
|
||||||
selectionMenu.style.display = 'none';
|
selectionMenu.style.display = 'none';
|
||||||
const selection = window.getSelection();
|
const selection = window.getSelection();
|
||||||
window.__DALLE2_CONTENT__ = selection.toString().trim();
|
window.__DALLE2_CONTENT__ = selection.toString().trim();
|
||||||
@ -59,11 +65,7 @@ async function init() {
|
|||||||
selectionMenu.style.display = 'block';
|
selectionMenu.style.display = 'block';
|
||||||
computePosition(rootEl, selectionMenu, {
|
computePosition(rootEl, selectionMenu, {
|
||||||
placement: 'top',
|
placement: 'top',
|
||||||
middleware: [
|
middleware: [flip(), offset(5), shift({ padding: 5 })],
|
||||||
flip(),
|
|
||||||
offset(5),
|
|
||||||
shift({ padding: 5 })
|
|
||||||
]
|
|
||||||
}).then(({ x, y }) => {
|
}).then(({ x, y }) => {
|
||||||
Object.assign(selectionMenu.style, {
|
Object.assign(selectionMenu.style, {
|
||||||
left: `${x}px`,
|
left: `${x}px`,
|
||||||
@ -74,11 +76,8 @@ async function init() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (document.readyState === 'complete' || document.readyState === 'interactive') {
|
||||||
document.readyState === "complete" ||
|
|
||||||
document.readyState === "interactive"
|
|
||||||
) {
|
|
||||||
init();
|
init();
|
||||||
} else {
|
} else {
|
||||||
document.addEventListener("DOMContentLoaded", init);
|
document.addEventListener('DOMContentLoaded', init);
|
||||||
}
|
}
|
44
sponsor.html
Normal file
44
sponsor.html
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>ChatGPT</title>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu,
|
||||||
|
Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
|
||||||
|
height: 100vh;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
flex-direction: column;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
p {
|
||||||
|
margin: 0;
|
||||||
|
padding: 5px 10px;
|
||||||
|
font-weight: bold;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 12px;
|
||||||
|
color: #686868;
|
||||||
|
}
|
||||||
|
a {
|
||||||
|
margin: 20px 10px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
img {
|
||||||
|
width: 240px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<p>🙏 Thank you for your support, which can help ChatGPT Free version to develop better!</p>
|
||||||
|
<p>🙏 感谢您的支持,可以让 ChatGPT 免费版更好的发展!</p>
|
||||||
|
<a target="_blank" href="https://www.buymeacoffee.com/lencx">
|
||||||
|
<img style="width: 160px" src="/bmc.png" />
|
||||||
|
</a>
|
||||||
|
<img src="/wxp.png" />
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -22,11 +22,11 @@ thiserror = "1.0.38"
|
|||||||
walkdir = "2.3.2"
|
walkdir = "2.3.2"
|
||||||
regex = "1.7.0"
|
regex = "1.7.0"
|
||||||
reqwest = "0.11.13"
|
reqwest = "0.11.13"
|
||||||
wry = "0.24.1"
|
|
||||||
dark-light = "1.0.0"
|
dark-light = "1.0.0"
|
||||||
|
wry = "0.*"
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
tokio = { version = "1.23.0", features = ["macros"] }
|
tokio = { version = "1.23.0", features = ["macros"] }
|
||||||
tauri = { version = "1.2.4", features = ["devtools", "fs-create-dir", "fs-exists", "fs-read-dir", "fs-read-file", "fs-remove-dir", "fs-remove-file", "fs-write-file", "global-shortcut", "global-shortcut-all", "os-all", "path-all", "process-all", "shell-all", "shell-open-api", "system-tray", "updater"] }
|
tauri = { version = "1.3.0", features = ["devtools", "fs-create-dir", "fs-exists", "fs-read-dir", "fs-read-file", "fs-remove-dir", "fs-remove-file", "fs-write-file", "global-shortcut", "global-shortcut-all", "os-all", "path-all", "process-all", "shell-all", "shell-open-api", "system-tray", "updater"] }
|
||||||
tauri-plugin-positioner = { git = "https://github.com/lencx/tauri-plugins-workspace", features = ["system-tray"] }
|
tauri-plugin-positioner = { git = "https://github.com/lencx/tauri-plugins-workspace", features = ["system-tray"] }
|
||||||
tauri-plugin-log = { git = "https://github.com/lencx/tauri-plugins-workspace", branch = "dev", features = ["colored"] }
|
tauri-plugin-log = { git = "https://github.com/lencx/tauri-plugins-workspace", branch = "dev", features = ["colored"] }
|
||||||
tauri-plugin-autostart = { git = "https://github.com/lencx/tauri-plugins-workspace", branch = "dev" }
|
tauri-plugin-autostart = { git = "https://github.com/lencx/tauri-plugins-workspace", branch = "dev" }
|
||||||
|
@ -18,30 +18,31 @@ pub fn fullscreen(app: AppHandle) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[command]
|
// #[command]
|
||||||
pub fn download(app: AppHandle, name: String, blob: Vec<u8>) {
|
// pub fn download(app: AppHandle, name: String, blob: Vec<u8>) {
|
||||||
let win = app.app_handle().get_window("core");
|
// let win = app.app_handle().get_window("core");
|
||||||
let path = utils::app_root().join(PathBuf::from(name));
|
// let path = utils::app_root().join(PathBuf::from(name));
|
||||||
utils::create_file(&path).unwrap();
|
// utils::create_file(&path).unwrap();
|
||||||
fs::write(&path, blob).unwrap();
|
// fs::write(&path, blob).unwrap();
|
||||||
tauri::api::dialog::message(
|
// tauri::api::dialog::message(
|
||||||
win.as_ref(),
|
// win.as_ref(),
|
||||||
"Save File",
|
// "Save File",
|
||||||
format!("PATH: {}", path.display()),
|
// format!("PATH: {}", path.display()),
|
||||||
);
|
// );
|
||||||
}
|
// }
|
||||||
|
|
||||||
#[command]
|
#[command]
|
||||||
pub fn save_file(app: AppHandle, name: String, content: String) {
|
pub fn save_file(_app: AppHandle, name: String, content: String) {
|
||||||
let win = app.app_handle().get_window("core");
|
// let win = app.app_handle().get_window("core");
|
||||||
let path = utils::app_root().join(PathBuf::from(name));
|
let path = utils::app_root().join(PathBuf::from(name));
|
||||||
utils::create_file(&path).unwrap();
|
utils::create_file(&path).unwrap();
|
||||||
fs::write(&path, content).unwrap();
|
fs::write(&path, content).unwrap();
|
||||||
tauri::api::dialog::message(
|
utils::open_file(path);
|
||||||
win.as_ref(),
|
// tauri::api::dialog::message(
|
||||||
"Save File",
|
// win.as_ref(),
|
||||||
format!("PATH: {}", path.display()),
|
// "Save File",
|
||||||
);
|
// format!("PATH: {}", path.display()),
|
||||||
|
// );
|
||||||
}
|
}
|
||||||
|
|
||||||
#[command]
|
#[command]
|
||||||
@ -59,6 +60,13 @@ pub fn open_file(path: PathBuf) {
|
|||||||
utils::open_file(path);
|
utils::open_file(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[command]
|
||||||
|
pub fn download_file(name: String, blob: Vec<u8>) {
|
||||||
|
let file = tauri::api::path::download_dir().unwrap().join(name);
|
||||||
|
fs::write(&file, blob).unwrap();
|
||||||
|
utils::open_file(file);
|
||||||
|
}
|
||||||
|
|
||||||
#[command]
|
#[command]
|
||||||
pub async fn get_data(app: AppHandle, url: String, is_msg: Option<bool>) -> Option<String> {
|
pub async fn get_data(app: AppHandle, url: String, is_msg: Option<bool>) -> Option<String> {
|
||||||
let is_msg = is_msg.unwrap_or(false);
|
let is_msg = is_msg.unwrap_or(false);
|
||||||
|
@ -140,7 +140,6 @@ pub fn init() -> Menu {
|
|||||||
popup_search_menu.into(),
|
popup_search_menu.into(),
|
||||||
CustomMenuItem::new("sync_prompts", "Sync Prompts").into(),
|
CustomMenuItem::new("sync_prompts", "Sync Prompts").into(),
|
||||||
MenuItem::Separator.into(),
|
MenuItem::Separator.into(),
|
||||||
CustomMenuItem::new("clear_cache", "Clear Cache").into(),
|
|
||||||
CustomMenuItem::new("go_conf", "Go to Config")
|
CustomMenuItem::new("go_conf", "Go to Config")
|
||||||
.accelerator("CmdOrCtrl+Shift+G")
|
.accelerator("CmdOrCtrl+Shift+G")
|
||||||
.into(),
|
.into(),
|
||||||
@ -150,7 +149,7 @@ pub fn init() -> Menu {
|
|||||||
CustomMenuItem::new("clear_conf", "Clear Config").into(),
|
CustomMenuItem::new("clear_conf", "Clear Config").into(),
|
||||||
MenuItem::Separator.into(),
|
MenuItem::Separator.into(),
|
||||||
CustomMenuItem::new("nofwl", "NoFWL Desktop Application").into(),
|
CustomMenuItem::new("nofwl", "NoFWL Desktop Application").into(),
|
||||||
CustomMenuItem::new("buy_coffee", "Buy lencx a coffee").into(),
|
CustomMenuItem::new("sponsor", "Sponsor Author").into(),
|
||||||
]),
|
]),
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -243,20 +242,6 @@ pub fn menu_handler(event: WindowMenuEvent<tauri::Wry>) {
|
|||||||
"inject_script" => open(&app, &script_path),
|
"inject_script" => open(&app, &script_path),
|
||||||
"go_conf" => utils::open_file(utils::app_root()),
|
"go_conf" => utils::open_file(utils::app_root()),
|
||||||
"clear_conf" => utils::clear_conf(&app),
|
"clear_conf" => utils::clear_conf(&app),
|
||||||
"clear_cache" => {
|
|
||||||
let main_win = app.get_window("core");
|
|
||||||
let tray_win = app.get_window("tray");
|
|
||||||
if let Some(main) = main_win {
|
|
||||||
main
|
|
||||||
.eval("window.__clearCache && window.__clearCache()")
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
if let Some(tray) = tray_win {
|
|
||||||
tray
|
|
||||||
.eval("window.__clearCache && window.__clearCache()")
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"app_website" => window::cmd::wa_window(
|
"app_website" => window::cmd::wa_window(
|
||||||
app,
|
app,
|
||||||
"app_website".into(),
|
"app_website".into(),
|
||||||
@ -265,7 +250,7 @@ pub fn menu_handler(event: WindowMenuEvent<tauri::Wry>) {
|
|||||||
None,
|
None,
|
||||||
),
|
),
|
||||||
"nofwl" => open(&app, conf::NOFWL_APP),
|
"nofwl" => open(&app, conf::NOFWL_APP),
|
||||||
"buy_coffee" => open(&app, conf::BUY_COFFEE),
|
"sponsor" => window::sponsor_window(app),
|
||||||
"popup_search" => {
|
"popup_search" => {
|
||||||
let app_conf = AppConf::read();
|
let app_conf = AppConf::read();
|
||||||
let popup_search = !app_conf.popup_search;
|
let popup_search = !app_conf.popup_search;
|
||||||
|
0
src-tauri/src/app/script.rs
Normal file
0
src-tauri/src/app/script.rs
Normal file
@ -52,13 +52,8 @@ pub fn init(app: &mut App) -> std::result::Result<(), Box<dyn std::error::Error>
|
|||||||
} else {
|
} else {
|
||||||
let app = app.handle();
|
let app = app.handle();
|
||||||
tauri::async_runtime::spawn(async move {
|
tauri::async_runtime::spawn(async move {
|
||||||
let link = if app_conf2.main_dashboard {
|
let url2 = &url;
|
||||||
"index.html"
|
let mut main_win = WindowBuilder::new(&app, "core", WindowUrl::App(url2.into()))
|
||||||
} else {
|
|
||||||
&url
|
|
||||||
};
|
|
||||||
info!("main_window: {}", link);
|
|
||||||
let mut main_win = WindowBuilder::new(&app, "core", WindowUrl::App(link.into()))
|
|
||||||
.title("ChatGPT")
|
.title("ChatGPT")
|
||||||
.resizable(true)
|
.resizable(true)
|
||||||
.fullscreen(false)
|
.fullscreen(false)
|
||||||
@ -66,7 +61,7 @@ pub fn init(app: &mut App) -> std::result::Result<(), Box<dyn std::error::Error>
|
|||||||
.theme(Some(theme))
|
.theme(Some(theme))
|
||||||
.always_on_top(app_conf2.stay_on_top)
|
.always_on_top(app_conf2.stay_on_top)
|
||||||
.initialization_script(&utils::user_script())
|
.initialization_script(&utils::user_script())
|
||||||
.initialization_script(include_str!("../scripts/core.js"))
|
.initialization_script(include_str!("../../../scripts/core.js"))
|
||||||
.user_agent(&app_conf2.ua_window);
|
.user_agent(&app_conf2.ua_window);
|
||||||
|
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
@ -76,7 +71,7 @@ pub fn init(app: &mut App) -> std::result::Result<(), Box<dyn std::error::Error>
|
|||||||
.hidden_title(true);
|
.hidden_title(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if url == "https://chat.openai.com" && !app_conf2.main_dashboard {
|
if url == "https://chat.openai.com" {
|
||||||
main_win = main_win
|
main_win = main_win
|
||||||
.initialization_script(include_str!("../vendors/floating-ui-core.js"))
|
.initialization_script(include_str!("../vendors/floating-ui-core.js"))
|
||||||
.initialization_script(include_str!("../vendors/floating-ui-dom.js"))
|
.initialization_script(include_str!("../vendors/floating-ui-dom.js"))
|
||||||
@ -84,11 +79,11 @@ pub fn init(app: &mut App) -> std::result::Result<(), Box<dyn std::error::Error>
|
|||||||
.initialization_script(include_str!("../vendors/jspdf.js"))
|
.initialization_script(include_str!("../vendors/jspdf.js"))
|
||||||
.initialization_script(include_str!("../vendors/turndown.js"))
|
.initialization_script(include_str!("../vendors/turndown.js"))
|
||||||
.initialization_script(include_str!("../vendors/turndown-plugin-gfm.js"))
|
.initialization_script(include_str!("../vendors/turndown-plugin-gfm.js"))
|
||||||
.initialization_script(include_str!("../scripts/popup.core.js"))
|
.initialization_script(include_str!("../../../scripts/popup.core.js"))
|
||||||
.initialization_script(include_str!("../scripts/export.js"))
|
.initialization_script(include_str!("../../../scripts/export.js"))
|
||||||
.initialization_script(include_str!("../scripts/markdown.export.js"))
|
.initialization_script(include_str!("../../../scripts/markdown.export.js"))
|
||||||
.initialization_script(include_str!("../scripts/cmd.js"))
|
.initialization_script(include_str!("../../../scripts/cmd.js"))
|
||||||
.initialization_script(include_str!("../scripts/chat.js"))
|
.initialization_script(include_str!("../../../scripts/chat.js"))
|
||||||
}
|
}
|
||||||
|
|
||||||
main_win.build().unwrap();
|
main_win.build().unwrap();
|
||||||
|
@ -23,16 +23,16 @@ pub fn tray_window(handle: &tauri::AppHandle) {
|
|||||||
.always_on_top(true)
|
.always_on_top(true)
|
||||||
.theme(Some(theme))
|
.theme(Some(theme))
|
||||||
.initialization_script(&utils::user_script())
|
.initialization_script(&utils::user_script())
|
||||||
.initialization_script(include_str!("../scripts/core.js"))
|
.initialization_script(include_str!("../../../scripts/core.js"))
|
||||||
.user_agent(&app_conf.ua_tray);
|
.user_agent(&app_conf.ua_tray);
|
||||||
|
|
||||||
if app_conf.tray_origin == "https://chat.openai.com" && !app_conf.tray_dashboard {
|
if app_conf.tray_origin == "https://chat.openai.com" && !app_conf.tray_dashboard {
|
||||||
tray_win = tray_win
|
tray_win = tray_win
|
||||||
.initialization_script(include_str!("../vendors/floating-ui-core.js"))
|
.initialization_script(include_str!("../vendors/floating-ui-core.js"))
|
||||||
.initialization_script(include_str!("../vendors/floating-ui-dom.js"))
|
.initialization_script(include_str!("../vendors/floating-ui-dom.js"))
|
||||||
.initialization_script(include_str!("../scripts/cmd.js"))
|
.initialization_script(include_str!("../../../scripts/cmd.js"))
|
||||||
.initialization_script(include_str!("../scripts/chat.js"))
|
.initialization_script(include_str!("../../../scripts/chat.js"))
|
||||||
.initialization_script(include_str!("../scripts/popup.core.js"))
|
.initialization_script(include_str!("../../../scripts/popup.core.js"))
|
||||||
}
|
}
|
||||||
|
|
||||||
tray_win.build().unwrap().hide().unwrap();
|
tray_win.build().unwrap().hide().unwrap();
|
||||||
@ -78,9 +78,9 @@ pub fn dalle2_window(
|
|||||||
.inner_size(800.0, 600.0)
|
.inner_size(800.0, 600.0)
|
||||||
.always_on_top(false)
|
.always_on_top(false)
|
||||||
.theme(Some(theme))
|
.theme(Some(theme))
|
||||||
.initialization_script(include_str!("../scripts/core.js"))
|
.initialization_script(include_str!("../../../scripts/core.js"))
|
||||||
.initialization_script(&query)
|
.initialization_script(&query)
|
||||||
.initialization_script(include_str!("../scripts/dalle2.js"))
|
.initialization_script(include_str!("../../../scripts/dalle2.js"))
|
||||||
.build()
|
.build()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
});
|
});
|
||||||
@ -91,6 +91,23 @@ pub fn dalle2_window(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn sponsor_window(handle: tauri::AppHandle) {
|
||||||
|
tauri::async_runtime::spawn(async move {
|
||||||
|
if let Some(win) = handle.get_window("sponsor") {
|
||||||
|
win.show().unwrap()
|
||||||
|
} else {
|
||||||
|
WindowBuilder::new(&handle, "sponsor", WindowUrl::App("sponsor.html".into()))
|
||||||
|
.title("Sponsor")
|
||||||
|
.resizable(true)
|
||||||
|
.fullscreen(false)
|
||||||
|
.inner_size(600.0, 600.0)
|
||||||
|
.min_inner_size(600.0, 600.0)
|
||||||
|
.build()
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
pub mod cmd {
|
pub mod cmd {
|
||||||
use super::*;
|
use super::*;
|
||||||
use log::info;
|
use log::info;
|
||||||
@ -144,7 +161,7 @@ pub mod cmd {
|
|||||||
tauri::async_runtime::spawn(async move {
|
tauri::async_runtime::spawn(async move {
|
||||||
tauri::WindowBuilder::new(&app, label, tauri::WindowUrl::App(url.parse().unwrap()))
|
tauri::WindowBuilder::new(&app, label, tauri::WindowUrl::App(url.parse().unwrap()))
|
||||||
.initialization_script(&script.unwrap_or_default())
|
.initialization_script(&script.unwrap_or_default())
|
||||||
.initialization_script(include_str!("../scripts/core.js"))
|
.initialization_script(include_str!("../../../scripts/core.js"))
|
||||||
.title(title)
|
.title(title)
|
||||||
.inner_size(960.0, 700.0)
|
.inner_size(960.0, 700.0)
|
||||||
.resizable(true)
|
.resizable(true)
|
||||||
|
@ -67,7 +67,7 @@ impl AppConf {
|
|||||||
Self {
|
Self {
|
||||||
titlebar: !cfg!(target_os = "macos"),
|
titlebar: !cfg!(target_os = "macos"),
|
||||||
hide_dock_icon: false,
|
hide_dock_icon: false,
|
||||||
save_window_state: false,
|
save_window_state: true,
|
||||||
theme: "light".into(),
|
theme: "light".into(),
|
||||||
auto_update: "prompt".into(),
|
auto_update: "prompt".into(),
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
|
@ -55,11 +55,11 @@ async fn main() {
|
|||||||
.invoke_handler(tauri::generate_handler![
|
.invoke_handler(tauri::generate_handler![
|
||||||
cmd::drag_window,
|
cmd::drag_window,
|
||||||
cmd::fullscreen,
|
cmd::fullscreen,
|
||||||
cmd::download,
|
|
||||||
cmd::save_file,
|
cmd::save_file,
|
||||||
cmd::open_link,
|
cmd::open_link,
|
||||||
cmd::run_check_update,
|
cmd::run_check_update,
|
||||||
cmd::open_file,
|
cmd::open_file,
|
||||||
|
cmd::download_file,
|
||||||
cmd::get_data,
|
cmd::get_data,
|
||||||
gpt::get_chat_model_cmd,
|
gpt::get_chat_model_cmd,
|
||||||
gpt::parse_prompt,
|
gpt::parse_prompt,
|
||||||
|
@ -87,7 +87,24 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"security": {
|
"security": {
|
||||||
"csp": null
|
"csp": null,
|
||||||
|
"dangerousRemoteDomainIpcAccess": [
|
||||||
|
{
|
||||||
|
"windows": ["core", "main", "tray"],
|
||||||
|
"domain": "chat.openai.com",
|
||||||
|
"enableTauriAPI": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"windows": ["core", "main"],
|
||||||
|
"domain": "labs.openai.com",
|
||||||
|
"enableTauriAPI": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"windows": ["core", "main", "tray"],
|
||||||
|
"domain": "openai.com",
|
||||||
|
"enableTauriAPI": true
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"updater": {
|
"updater": {
|
||||||
"active": true,
|
"active": true,
|
||||||
|
5
src/main.scss
vendored
5
src/main.scss
vendored
@ -73,6 +73,11 @@ body,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.action-btn,
|
||||||
|
.file-path {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
.chat-file-path {
|
.chat-file-path {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
|
38
src/routes.tsx
vendored
38
src/routes.tsx
vendored
@ -5,24 +5,21 @@ import {
|
|||||||
SyncOutlined,
|
SyncOutlined,
|
||||||
FileSyncOutlined,
|
FileSyncOutlined,
|
||||||
UserOutlined,
|
UserOutlined,
|
||||||
DownloadOutlined,
|
|
||||||
FormOutlined,
|
FormOutlined,
|
||||||
GlobalOutlined,
|
|
||||||
InfoCircleOutlined,
|
InfoCircleOutlined,
|
||||||
|
CodeOutlined,
|
||||||
} from '@ant-design/icons';
|
} from '@ant-design/icons';
|
||||||
import type { MenuProps } from 'antd';
|
import type { MenuProps } from 'antd';
|
||||||
|
|
||||||
import Settings from '@/view/settings';
|
import Settings from '@/view/settings';
|
||||||
import About from '@/view/about';
|
import About from '@/view/about';
|
||||||
import Awesome from '@/view/awesome';
|
import Scripts from '@/view/scripts';
|
||||||
import UserCustom from '@/view/model/UserCustom';
|
import UserCustom from '@/view/prompts/UserCustom';
|
||||||
import SyncPrompts from '@/view/model/SyncPrompts';
|
import SyncPrompts from '@/view/prompts/SyncPrompts';
|
||||||
import SyncCustom from '@/view/model/SyncCustom';
|
import SyncCustom from '@/view/prompts/SyncCustom';
|
||||||
import SyncRecord from '@/view/model/SyncRecord';
|
import SyncRecord from '@/view/prompts/SyncRecord';
|
||||||
import Download from '@/view/download';
|
|
||||||
import Notes from '@/view/notes';
|
import Notes from '@/view/notes';
|
||||||
import Markdown from '@/view/markdown';
|
import Markdown from '@/view/markdown';
|
||||||
import Dashboard from '@/view/dashboard';
|
|
||||||
|
|
||||||
export type ChatRouteMetaObject = {
|
export type ChatRouteMetaObject = {
|
||||||
label: string;
|
label: string;
|
||||||
@ -46,14 +43,6 @@ export const routes: Array<ChatRouteObject> = [
|
|||||||
icon: <SettingOutlined />,
|
icon: <SettingOutlined />,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
path: '/awesome',
|
|
||||||
element: <Awesome />,
|
|
||||||
meta: {
|
|
||||||
label: 'Awesome',
|
|
||||||
icon: <GlobalOutlined />,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
path: '/notes',
|
path: '/notes',
|
||||||
element: <Notes />,
|
element: <Notes />,
|
||||||
@ -68,9 +57,9 @@ export const routes: Array<ChatRouteObject> = [
|
|||||||
hideMenu: true,
|
hideMenu: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/model',
|
path: '/prompts',
|
||||||
meta: {
|
meta: {
|
||||||
label: 'Language Model',
|
label: 'Prompts',
|
||||||
icon: <BulbOutlined />,
|
icon: <BulbOutlined />,
|
||||||
},
|
},
|
||||||
children: [
|
children: [
|
||||||
@ -107,11 +96,11 @@ export const routes: Array<ChatRouteObject> = [
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/download',
|
path: '/scripts',
|
||||||
element: <Download />,
|
element: <Scripts />,
|
||||||
meta: {
|
meta: {
|
||||||
label: 'Download',
|
label: 'Scripts',
|
||||||
icon: <DownloadOutlined />,
|
icon: <CodeOutlined />,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -124,8 +113,7 @@ export const routes: Array<ChatRouteObject> = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/',
|
path: '/',
|
||||||
element: <Dashboard />,
|
element: <Settings />,
|
||||||
hideMenu: true,
|
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
4
src/view/about/index.tsx
vendored
4
src/view/about/index.tsx
vendored
@ -69,10 +69,6 @@ const AboutChatGPT = () => {
|
|||||||
src="https://user-images.githubusercontent.com/16164244/207228025-117b5f77-c5d2-48c2-a070-774b7a1596f2.png"
|
src="https://user-images.githubusercontent.com/16164244/207228025-117b5f77-c5d2-48c2-a070-774b7a1596f2.png"
|
||||||
/>
|
/>
|
||||||
</p>
|
</p>
|
||||||
<img
|
|
||||||
width="250"
|
|
||||||
src="https://user-images.githubusercontent.com/16164244/219439614-d5c3710c-e0b3-4df9-9b3c-c150ba0ba5f1.png"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
128
src/view/model/SyncCustom/Form.tsx
vendored
128
src/view/model/SyncCustom/Form.tsx
vendored
@ -1,128 +0,0 @@
|
|||||||
import {
|
|
||||||
useEffect,
|
|
||||||
useState,
|
|
||||||
ForwardRefRenderFunction,
|
|
||||||
useImperativeHandle,
|
|
||||||
forwardRef,
|
|
||||||
} from 'react';
|
|
||||||
import { Form, Input, Select, Tooltip } from 'antd';
|
|
||||||
import { v4 } from 'uuid';
|
|
||||||
import type { FormProps } from 'antd';
|
|
||||||
|
|
||||||
import { DISABLE_AUTO_COMPLETE, chatRoot } from '@/utils';
|
|
||||||
import useInit from '@/hooks/useInit';
|
|
||||||
|
|
||||||
interface SyncFormProps {
|
|
||||||
record?: Record<string | symbol, any> | null;
|
|
||||||
type: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
const initFormValue = {
|
|
||||||
act: '',
|
|
||||||
enable: true,
|
|
||||||
tags: [],
|
|
||||||
prompt: '',
|
|
||||||
};
|
|
||||||
|
|
||||||
const SyncForm: ForwardRefRenderFunction<FormProps, SyncFormProps> = ({ record, type }, ref) => {
|
|
||||||
const isDisabled = type === 'edit';
|
|
||||||
const [form] = Form.useForm();
|
|
||||||
useImperativeHandle(ref, () => ({ form }));
|
|
||||||
const [root, setRoot] = useState('');
|
|
||||||
|
|
||||||
useInit(async () => {
|
|
||||||
setRoot(await chatRoot());
|
|
||||||
});
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (record) {
|
|
||||||
form.setFieldsValue(record);
|
|
||||||
}
|
|
||||||
}, [record]);
|
|
||||||
|
|
||||||
const pathOptions = (
|
|
||||||
<Form.Item noStyle name="protocol" initialValue="https">
|
|
||||||
<Select disabled={isDisabled}>
|
|
||||||
<Select.Option value="local">{root}</Select.Option>
|
|
||||||
<Select.Option value="http">http://</Select.Option>
|
|
||||||
<Select.Option value="https">https://</Select.Option>
|
|
||||||
</Select>
|
|
||||||
</Form.Item>
|
|
||||||
);
|
|
||||||
const extOptions = (
|
|
||||||
<Form.Item noStyle name="ext" initialValue="json">
|
|
||||||
<Select disabled={isDisabled}>
|
|
||||||
<Select.Option value="csv">.csv</Select.Option>
|
|
||||||
<Select.Option value="json">.json</Select.Option>
|
|
||||||
</Select>
|
|
||||||
</Form.Item>
|
|
||||||
);
|
|
||||||
|
|
||||||
const jsonTip = (
|
|
||||||
<Tooltip
|
|
||||||
title={
|
|
||||||
<pre>
|
|
||||||
{JSON.stringify(
|
|
||||||
[
|
|
||||||
{ cmd: '', act: '', prompt: '' },
|
|
||||||
{ cmd: '', act: '', prompt: '' },
|
|
||||||
],
|
|
||||||
null,
|
|
||||||
2,
|
|
||||||
)}
|
|
||||||
</pre>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<a>JSON</a>
|
|
||||||
</Tooltip>
|
|
||||||
);
|
|
||||||
|
|
||||||
const csvTip = (
|
|
||||||
<Tooltip
|
|
||||||
title={
|
|
||||||
<pre>{`"cmd","act","prompt"
|
|
||||||
"cmd","act","prompt"
|
|
||||||
"cmd","act","prompt"
|
|
||||||
"cmd","act","prompt"`}</pre>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<a>CSV</a>
|
|
||||||
</Tooltip>
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<Form form={form} labelCol={{ span: 4 }} initialValues={initFormValue}>
|
|
||||||
<Form.Item
|
|
||||||
label="Name"
|
|
||||||
name="name"
|
|
||||||
rules={[{ required: true, message: 'Please enter a name!' }]}
|
|
||||||
>
|
|
||||||
<Input placeholder="Please enter a name" {...DISABLE_AUTO_COMPLETE} />
|
|
||||||
</Form.Item>
|
|
||||||
<Form.Item
|
|
||||||
label="PATH"
|
|
||||||
name="path"
|
|
||||||
rules={[{ required: true, message: 'Please enter the path!' }]}
|
|
||||||
>
|
|
||||||
<Input
|
|
||||||
placeholder="YOUR_PATH"
|
|
||||||
addonBefore={pathOptions}
|
|
||||||
addonAfter={extOptions}
|
|
||||||
{...DISABLE_AUTO_COMPLETE}
|
|
||||||
/>
|
|
||||||
</Form.Item>
|
|
||||||
<Form.Item style={{ display: 'none' }} name="id" initialValue={v4().replace(/-/g, '')}>
|
|
||||||
<input />
|
|
||||||
</Form.Item>
|
|
||||||
</Form>
|
|
||||||
<div className="tip">
|
|
||||||
<p>
|
|
||||||
The file supports only {csvTip} and {jsonTip} formats.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default forwardRef(SyncForm);
|
|
192
src/view/prompts/SyncCustom/Form.tsx
vendored
Normal file
192
src/view/prompts/SyncCustom/Form.tsx
vendored
Normal file
@ -0,0 +1,192 @@
|
|||||||
|
import {
|
||||||
|
useEffect,
|
||||||
|
useState,
|
||||||
|
ForwardRefRenderFunction,
|
||||||
|
useImperativeHandle,
|
||||||
|
forwardRef,
|
||||||
|
} from 'react';
|
||||||
|
import { Form, Input, Radio, Upload, Tooltip, message } from 'antd';
|
||||||
|
import { v4 } from 'uuid';
|
||||||
|
import { InboxOutlined } from '@ant-design/icons';
|
||||||
|
import type { FormProps, RadioChangeEvent, UploadProps, UploadFile } from 'antd';
|
||||||
|
|
||||||
|
import { DISABLE_AUTO_COMPLETE, chatRoot } from '@/utils';
|
||||||
|
// import useInit from '@/hooks/useInit';
|
||||||
|
|
||||||
|
interface SyncFormProps {
|
||||||
|
record?: Record<string | symbol, any> | null;
|
||||||
|
type: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const initFormValue = {
|
||||||
|
name: '',
|
||||||
|
url: '',
|
||||||
|
file: null,
|
||||||
|
protocol: 'https',
|
||||||
|
};
|
||||||
|
|
||||||
|
const SyncForm: ForwardRefRenderFunction<FormProps, SyncFormProps> = ({ record, type }, ref) => {
|
||||||
|
// const isDisabled = type === 'edit';
|
||||||
|
const [form] = Form.useForm();
|
||||||
|
useImperativeHandle(ref, () => ({ form }));
|
||||||
|
// const [root, setRoot] = useState('');
|
||||||
|
const [protocol, setProtocol] = useState('https');
|
||||||
|
const [fileList, setFileList] = useState<UploadFile[]>([]);
|
||||||
|
|
||||||
|
// useInit(async () => {
|
||||||
|
// setRoot(await chatRoot());
|
||||||
|
// });
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (record) {
|
||||||
|
form.setFieldsValue(record);
|
||||||
|
}
|
||||||
|
}, [record]);
|
||||||
|
|
||||||
|
// const pathOptions = (
|
||||||
|
// <Form.Item noStyle name="protocol" initialValue="https">
|
||||||
|
// <Select disabled={isDisabled}>
|
||||||
|
// <Select.Option value="local">{root}</Select.Option>
|
||||||
|
// <Select.Option value="http">http://</Select.Option>
|
||||||
|
// <Select.Option value="https">https://</Select.Option>
|
||||||
|
// </Select>
|
||||||
|
// </Form.Item>
|
||||||
|
// );
|
||||||
|
|
||||||
|
// const extOptions = (
|
||||||
|
// <Form.Item noStyle name="ext" initialValue="json">
|
||||||
|
// <Select disabled={isDisabled}>
|
||||||
|
// <Select.Option value="csv">.csv</Select.Option>
|
||||||
|
// <Select.Option value="json">.json</Select.Option>
|
||||||
|
// </Select>
|
||||||
|
// </Form.Item>
|
||||||
|
// );
|
||||||
|
|
||||||
|
const jsonTip = (
|
||||||
|
<Tooltip
|
||||||
|
title={
|
||||||
|
<pre>
|
||||||
|
{JSON.stringify(
|
||||||
|
[
|
||||||
|
{ cmd: '', act: '', prompt: '' },
|
||||||
|
{ cmd: '', act: '', prompt: '' },
|
||||||
|
],
|
||||||
|
null,
|
||||||
|
2,
|
||||||
|
)}
|
||||||
|
</pre>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<a>.json</a>
|
||||||
|
</Tooltip>
|
||||||
|
);
|
||||||
|
|
||||||
|
const csvTip = (
|
||||||
|
<Tooltip
|
||||||
|
title={
|
||||||
|
<pre>{`"cmd","act","prompt"
|
||||||
|
"cmd","act","prompt"
|
||||||
|
"cmd","act","prompt"
|
||||||
|
"cmd","act","prompt"`}</pre>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<a>.csv</a>
|
||||||
|
</Tooltip>
|
||||||
|
);
|
||||||
|
|
||||||
|
const handleType = (e: RadioChangeEvent) => {
|
||||||
|
setProtocol(e.target.value);
|
||||||
|
};
|
||||||
|
|
||||||
|
const uploadOptions: UploadProps = {
|
||||||
|
onRemove: () => {
|
||||||
|
setFileList([]);
|
||||||
|
},
|
||||||
|
customRequest: () => {},
|
||||||
|
beforeUpload: (file) => {
|
||||||
|
const isCSV = /.csv$/.test(file.name);
|
||||||
|
const isJSON = /.json$/.test(file.name);
|
||||||
|
const isOk = isCSV || isJSON;
|
||||||
|
if (!isOk) {
|
||||||
|
message.error('You can only upload .json or .csv file!');
|
||||||
|
} else {
|
||||||
|
setFileList([file]);
|
||||||
|
}
|
||||||
|
return isOk || Upload.LIST_IGNORE;
|
||||||
|
},
|
||||||
|
maxCount: 1,
|
||||||
|
fileList,
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Form form={form} labelCol={{ span: 4 }} initialValues={initFormValue}>
|
||||||
|
<Form.Item
|
||||||
|
label="Name"
|
||||||
|
name="name"
|
||||||
|
rules={[{ required: true, message: 'Please enter a name!' }]}
|
||||||
|
>
|
||||||
|
<Input placeholder="Please enter a name" {...DISABLE_AUTO_COMPLETE} />
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item label="Protocol" name="protocol" rules={[{ required: true }]}>
|
||||||
|
<Radio.Group onChange={handleType} value={protocol}>
|
||||||
|
<Radio value="https">https</Radio>
|
||||||
|
<Radio value="http">http</Radio>
|
||||||
|
<Radio value="local">local</Radio>
|
||||||
|
</Radio.Group>
|
||||||
|
</Form.Item>
|
||||||
|
<div style={{ marginLeft: 30, color: '#888' }}>
|
||||||
|
<p>
|
||||||
|
<b>.ext</b>: The file supports only {csvTip} and {jsonTip} formats.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
{['http', 'https'].includes(protocol) && (
|
||||||
|
<Form.Item
|
||||||
|
label="URL"
|
||||||
|
name="url"
|
||||||
|
rules={[
|
||||||
|
{ required: true, message: 'Please enter the URL!' },
|
||||||
|
({ getFieldValue }) => ({
|
||||||
|
validator(_, value) {
|
||||||
|
if (!value || /\.json$|\.csv$/.test(getFieldValue('url'))) {
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
|
return Promise.reject(new Error('The file supports only .csv and .json formats'));
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
]}
|
||||||
|
style={{ height: 200 }}
|
||||||
|
>
|
||||||
|
<Input
|
||||||
|
placeholder="your_path/file_name.ext"
|
||||||
|
addonBefore={`${protocol}://`}
|
||||||
|
// addonAfter={extOptions}
|
||||||
|
{...DISABLE_AUTO_COMPLETE}
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
)}
|
||||||
|
{protocol === 'local' && (
|
||||||
|
<Form.Item
|
||||||
|
name="file"
|
||||||
|
label="File"
|
||||||
|
rules={[{ required: true, message: 'Please select a file!' }]}
|
||||||
|
style={{ height: 200 }}
|
||||||
|
>
|
||||||
|
<Upload.Dragger {...uploadOptions}>
|
||||||
|
<p className="ant-upload-drag-icon">
|
||||||
|
<InboxOutlined />
|
||||||
|
</p>
|
||||||
|
<p className="ant-upload-text">Click or drag file to this area to upload</p>
|
||||||
|
<p className="ant-upload-hint">Only .json or .csv files are supported.</p>
|
||||||
|
</Upload.Dragger>
|
||||||
|
</Form.Item>
|
||||||
|
)}
|
||||||
|
<Form.Item style={{ display: 'none' }} name="id" initialValue={v4().replace(/-/g, '')}>
|
||||||
|
<input />
|
||||||
|
</Form.Item>
|
||||||
|
</Form>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default forwardRef(SyncForm);
|
@ -130,7 +130,7 @@ export default function SyncCustom() {
|
|||||||
type="primary"
|
type="primary"
|
||||||
onClick={opInfo.opNew}
|
onClick={opInfo.opNew}
|
||||||
>
|
>
|
||||||
Add PATH
|
Add Prompt
|
||||||
</Button>
|
</Button>
|
||||||
<Table
|
<Table
|
||||||
key="id"
|
key="id"
|
||||||
@ -143,7 +143,7 @@ export default function SyncCustom() {
|
|||||||
<Modal
|
<Modal
|
||||||
open={isVisible}
|
open={isVisible}
|
||||||
onCancel={hide}
|
onCancel={hide}
|
||||||
title="Sync PATH"
|
title="Add Prompt"
|
||||||
onOk={handleOk}
|
onOk={handleOk}
|
||||||
destroyOnClose
|
destroyOnClose
|
||||||
maskClosable={false}
|
maskClosable={false}
|
@ -9,7 +9,7 @@ import useColumns from '@/hooks/useColumns';
|
|||||||
import FilePath from '@/components/FilePath';
|
import FilePath from '@/components/FilePath';
|
||||||
import { useCacheModel } from '@/hooks/useChatModel';
|
import { useCacheModel } from '@/hooks/useChatModel';
|
||||||
import { useTableRowSelection, TABLE_PAGINATION } from '@/hooks/useTable';
|
import { useTableRowSelection, TABLE_PAGINATION } from '@/hooks/useTable';
|
||||||
import { getPath } from '@/view/model/SyncCustom/config';
|
import { getPath } from '@/view/prompts/SyncCustom/config';
|
||||||
import { fmtDate, chatRoot } from '@/utils';
|
import { fmtDate, chatRoot } from '@/utils';
|
||||||
import { syncColumns } from './config';
|
import { syncColumns } from './config';
|
||||||
import useInit from '@/hooks/useInit';
|
import useInit from '@/hooks/useInit';
|
@ -94,13 +94,13 @@ export default function UserCustom() {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const modalTitle = `${{ new: 'Create', edit: 'Edit' }[opInfo.opType]} Model`;
|
const modalTitle = `${{ new: 'Create', edit: 'Edit' }[opInfo.opType]} Prompt`;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<div className="chat-table-btns">
|
<div className="chat-table-btns">
|
||||||
<Button className="chat-add-btn" type="primary" onClick={opInfo.opNew}>
|
<Button className="chat-add-btn" type="primary" onClick={opInfo.opNew}>
|
||||||
Add Model
|
Add Prompt
|
||||||
</Button>
|
</Button>
|
||||||
<div>
|
<div>
|
||||||
{selectedItems.length > 0 && (
|
{selectedItems.length > 0 && (
|
34
src/view/scripts/Editor.tsx
vendored
Normal file
34
src/view/scripts/Editor.tsx
vendored
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
import { FC, useEffect, useState } from 'react';
|
||||||
|
import Editor from '@monaco-editor/react';
|
||||||
|
|
||||||
|
interface MarkdownEditorProps {
|
||||||
|
value?: string;
|
||||||
|
onChange?: (v: string) => void;
|
||||||
|
mode?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ScriptEditor: FC<MarkdownEditorProps> = ({
|
||||||
|
value = 'console.log',
|
||||||
|
onChange,
|
||||||
|
mode = 'split',
|
||||||
|
}) => {
|
||||||
|
const [content, setContent] = useState(value);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setContent(value);
|
||||||
|
onChange && onChange(value);
|
||||||
|
}, [value]);
|
||||||
|
|
||||||
|
const handleEdit = (e: any) => {
|
||||||
|
setContent(e);
|
||||||
|
onChange && onChange(e);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="script-editor">
|
||||||
|
<Editor language="js" value={content} onChange={handleEdit} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ScriptEditor;
|
97
src/view/scripts/Head.tsx
vendored
Normal file
97
src/view/scripts/Head.tsx
vendored
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
import { useEffect, useState } from 'react';
|
||||||
|
import { Tag, Collapse, Tooltip } from 'antd';
|
||||||
|
import { EditOutlined, FileSyncOutlined } from '@ant-design/icons';
|
||||||
|
import { path, fs, shell } from '@tauri-apps/api';
|
||||||
|
|
||||||
|
import { chatRoot } from '@/utils';
|
||||||
|
import useInit from '@/hooks/useInit';
|
||||||
|
|
||||||
|
export type ScriptInfo = {
|
||||||
|
name: string;
|
||||||
|
filePath: string;
|
||||||
|
file: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
interface ScriptHeadProps {
|
||||||
|
name: string;
|
||||||
|
onEdit?: (data: ScriptInfo) => void;
|
||||||
|
activeKey: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function ScriptHead({ name, onEdit, activeKey }: ScriptHeadProps) {
|
||||||
|
const [file, setFile] = useState('');
|
||||||
|
const [filePath, setFilePath] = useState('');
|
||||||
|
const [editing, setEdit] = useState(false);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (activeKey !== name) {
|
||||||
|
setEdit(false);
|
||||||
|
}
|
||||||
|
}, [activeKey]);
|
||||||
|
|
||||||
|
useInit(async () => {
|
||||||
|
const filePath = await path.join(await chatRoot(), 'scripts', name);
|
||||||
|
setFilePath(filePath);
|
||||||
|
const content = await fs.readTextFile(filePath);
|
||||||
|
setFile(content);
|
||||||
|
});
|
||||||
|
|
||||||
|
const handleGoFile = () => {
|
||||||
|
shell.open(filePath);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleEdit = async () => {
|
||||||
|
setEdit(true);
|
||||||
|
onEdit && onEdit({ name, filePath, file });
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleCancel = async () => {
|
||||||
|
setEdit(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSave = async () => {
|
||||||
|
setEdit(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSync = async () => {};
|
||||||
|
|
||||||
|
const handleURL = async () => {
|
||||||
|
shell.open(`https://github.com/lencx/ChatGPT/blob/main/scripts/${name}`);
|
||||||
|
};
|
||||||
|
|
||||||
|
const version = '0.1.0';
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<span>
|
||||||
|
<Tag color="orange">{version}</Tag>
|
||||||
|
</span>
|
||||||
|
{editing ? (
|
||||||
|
<span>
|
||||||
|
<Tag className="action-btn" onClick={handleCancel} color="default">
|
||||||
|
Cancel
|
||||||
|
</Tag>
|
||||||
|
<Tag className="action-btn" onClick={handleSave} color="geekblue-inverse">
|
||||||
|
Save
|
||||||
|
</Tag>
|
||||||
|
</span>
|
||||||
|
) : (
|
||||||
|
<Tag className="action-btn" title="Script Edit" onClick={handleEdit} color="blue-inverse">
|
||||||
|
<EditOutlined />
|
||||||
|
</Tag>
|
||||||
|
)}
|
||||||
|
<Tag className="action-btn" title="Script Sync" onClick={handleSync} color="orange-inverse">
|
||||||
|
<FileSyncOutlined />
|
||||||
|
</Tag>
|
||||||
|
<span>
|
||||||
|
<Tag className="file-path" color="blue" onClick={handleGoFile}>
|
||||||
|
Path: {filePath}
|
||||||
|
</Tag>
|
||||||
|
</span>
|
||||||
|
<span>
|
||||||
|
<Tag className="file-path" color="green" onClick={handleURL}>
|
||||||
|
URL: lencx/ChatGPT/scripts/{name}
|
||||||
|
</Tag>
|
||||||
|
</span>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
72
src/view/scripts/config.tsx
vendored
Normal file
72
src/view/scripts/config.tsx
vendored
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
import { useState } from 'react';
|
||||||
|
import { Link } from 'react-router-dom';
|
||||||
|
import { Tag, Space, Popconfirm } from 'antd';
|
||||||
|
import { path, shell } from '@tauri-apps/api';
|
||||||
|
|
||||||
|
import useInit from '@/hooks/useInit';
|
||||||
|
import { fmtDate, chatRoot } from '@/utils';
|
||||||
|
|
||||||
|
export const scriptColumns = () => [
|
||||||
|
{
|
||||||
|
title: 'File Name',
|
||||||
|
dataIndex: 'name',
|
||||||
|
key: 'name',
|
||||||
|
width: 120,
|
||||||
|
render: (v: string) => <Tag>{v}</Tag>,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Version',
|
||||||
|
dataIndex: 'version',
|
||||||
|
key: 'version',
|
||||||
|
width: 120,
|
||||||
|
render: (v: string) => <Tag>{v}</Tag>,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Path',
|
||||||
|
dataIndex: 'path',
|
||||||
|
key: 'path',
|
||||||
|
width: 200,
|
||||||
|
render: (_: string, row: any) => <RenderPath row={row} />,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Created',
|
||||||
|
dataIndex: 'created',
|
||||||
|
key: 'created',
|
||||||
|
width: 150,
|
||||||
|
render: fmtDate,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Action',
|
||||||
|
fixed: 'right',
|
||||||
|
width: 160,
|
||||||
|
render: (_: any, row: any, actions: any) => {
|
||||||
|
return (
|
||||||
|
<Space>
|
||||||
|
<Link to={`/md/${row.id}`} state={row}>
|
||||||
|
Edit
|
||||||
|
</Link>
|
||||||
|
<Popconfirm
|
||||||
|
title="Are you sure you want to synchronize? It will overwrite all previous modifications made to this file."
|
||||||
|
onConfirm={() => actions.setRecord(row, 'sync')}
|
||||||
|
okText="Yes"
|
||||||
|
cancelText="No"
|
||||||
|
>
|
||||||
|
<a>Sync</a>
|
||||||
|
</Popconfirm>
|
||||||
|
</Space>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const RenderPath = ({ row }: any) => {
|
||||||
|
const [filePath, setFilePath] = useState('');
|
||||||
|
useInit(async () => {
|
||||||
|
setFilePath(await getPath(row));
|
||||||
|
});
|
||||||
|
return <a onClick={() => shell.open(filePath)}>{filePath}</a>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getPath = async (row: any) => {
|
||||||
|
return (await path.join(await chatRoot(), 'notes', row.id)) + `.${row.ext}`;
|
||||||
|
};
|
10
src/view/scripts/index.scss
vendored
Normal file
10
src/view/scripts/index.scss
vendored
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
.chatgpt-script {
|
||||||
|
.ant-collapse-header {
|
||||||
|
user-select: none;
|
||||||
|
-webkit-user-select: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.script-editor {
|
||||||
|
height: 300px;
|
||||||
|
}
|
72
src/view/scripts/index.tsx
vendored
Normal file
72
src/view/scripts/index.tsx
vendored
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
import { useState } from 'react';
|
||||||
|
import { Table, Tag } from 'antd';
|
||||||
|
|
||||||
|
import useData from '@/hooks/useData';
|
||||||
|
import useColumns from '@/hooks/useColumns';
|
||||||
|
import { useTableRowSelection, TABLE_PAGINATION } from '@/hooks/useTable';
|
||||||
|
import { scriptColumns } from './config';
|
||||||
|
import ScriptHead, { type ScriptInfo } from './Head';
|
||||||
|
import ScriptEditor from './Editor';
|
||||||
|
import './index.scss';
|
||||||
|
|
||||||
|
// const { Panel } = Collapse;
|
||||||
|
|
||||||
|
const SCRIPTS = [
|
||||||
|
'core.js',
|
||||||
|
'chat.js',
|
||||||
|
'cmd.js',
|
||||||
|
'dalle2.js',
|
||||||
|
'export.js',
|
||||||
|
'markdown.export.js',
|
||||||
|
'popup.core.js',
|
||||||
|
];
|
||||||
|
|
||||||
|
export default function Scripts() {
|
||||||
|
const [activeKey, setActiveKey] = useState('core.js');
|
||||||
|
|
||||||
|
const { columns, ...opInfo } = useColumns(scriptColumns());
|
||||||
|
|
||||||
|
const handleActiveKeyChange = (key: any) => {
|
||||||
|
setActiveKey(key);
|
||||||
|
};
|
||||||
|
|
||||||
|
const panelHeadProps = {
|
||||||
|
onEdit(data: ScriptInfo) {
|
||||||
|
setActiveKey(data.name);
|
||||||
|
},
|
||||||
|
activeKey,
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="chatgpt-script">
|
||||||
|
<Table
|
||||||
|
columns={columns}
|
||||||
|
dataSource={SCRIPTS.map((i) => ({ name: i }))}
|
||||||
|
{...TABLE_PAGINATION}
|
||||||
|
/>
|
||||||
|
{/* <Tabs
|
||||||
|
items={SCRIPTS.map((i) => {
|
||||||
|
return {
|
||||||
|
label: <Tag>{i}</Tag>,
|
||||||
|
key: i,
|
||||||
|
children: <ScriptEditor />,
|
||||||
|
}
|
||||||
|
})}
|
||||||
|
/> */}
|
||||||
|
{/* <Collapse
|
||||||
|
accordion
|
||||||
|
collapsible="icon"
|
||||||
|
activeKey={activeKey}
|
||||||
|
onChange={handleActiveKeyChange}
|
||||||
|
>
|
||||||
|
{SCRIPTS.map((i) => {
|
||||||
|
return (
|
||||||
|
<Panel header={<ScriptHead name={i} {...panelHeadProps} />} key={i}>
|
||||||
|
<ScriptEditor />
|
||||||
|
</Panel>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</Collapse> */}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
4
src/view/settings/General.tsx
vendored
4
src/view/settings/General.tsx
vendored
@ -25,9 +25,9 @@ export default function General() {
|
|||||||
<Form.Item label="Stay On Top" name="stay_on_top" valuePropName="checked">
|
<Form.Item label="Stay On Top" name="stay_on_top" valuePropName="checked">
|
||||||
<Switch />
|
<Switch />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item label="Save Window State" name="save_window_state" valuePropName="checked">
|
{/* <Form.Item label="Save Window State" name="save_window_state" valuePropName="checked">
|
||||||
<Switch />
|
<Switch />
|
||||||
</Form.Item>
|
</Form.Item> */}
|
||||||
{platformInfo === 'darwin' && (
|
{platformInfo === 'darwin' && (
|
||||||
<Form.Item label="Titlebar" name="titlebar" valuePropName="checked">
|
<Form.Item label="Titlebar" name="titlebar" valuePropName="checked">
|
||||||
<Switch />
|
<Switch />
|
||||||
|
4
src/view/settings/MainWindow.tsx
vendored
4
src/view/settings/MainWindow.tsx
vendored
@ -1,7 +1,7 @@
|
|||||||
import { Form, Switch, Input, InputNumber, Tooltip } from 'antd';
|
import { Form, Switch, Input, InputNumber, Tooltip } from 'antd';
|
||||||
import { QuestionCircleOutlined } from '@ant-design/icons';
|
import { QuestionCircleOutlined } from '@ant-design/icons';
|
||||||
|
|
||||||
import SwitchOrigin from '@/components/SwitchOrigin';
|
// import SwitchOrigin from '@/components/SwitchOrigin';
|
||||||
import { DISABLE_AUTO_COMPLETE } from '@/utils';
|
import { DISABLE_AUTO_COMPLETE } from '@/utils';
|
||||||
|
|
||||||
const PopupSearchLabel = () => {
|
const PopupSearchLabel = () => {
|
||||||
@ -56,7 +56,7 @@ export default function MainWindow() {
|
|||||||
<Form.Item label="Default Height" name="main_height">
|
<Form.Item label="Default Height" name="main_height">
|
||||||
<InputNumber />
|
<InputNumber />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<SwitchOrigin name="main" />
|
{/* <SwitchOrigin name="main" /> */}
|
||||||
<Form.Item label="User Agent (Main)" name="ua_window">
|
<Form.Item label="User Agent (Main)" name="ua_window">
|
||||||
<Input.TextArea
|
<Input.TextArea
|
||||||
autoSize={{ minRows: 4, maxRows: 4 }}
|
autoSize={{ minRows: 4, maxRows: 4 }}
|
||||||
|
4
src/view/settings/TrayWindow.tsx
vendored
4
src/view/settings/TrayWindow.tsx
vendored
@ -2,7 +2,7 @@ import { Form, Switch, Input, InputNumber, Tooltip } from 'antd';
|
|||||||
import { QuestionCircleOutlined } from '@ant-design/icons';
|
import { QuestionCircleOutlined } from '@ant-design/icons';
|
||||||
|
|
||||||
import { DISABLE_AUTO_COMPLETE } from '@/utils';
|
import { DISABLE_AUTO_COMPLETE } from '@/utils';
|
||||||
import SwitchOrigin from '@/components/SwitchOrigin';
|
// import SwitchOrigin from '@/components/SwitchOrigin';
|
||||||
|
|
||||||
const UALabel = () => {
|
const UALabel = () => {
|
||||||
return (
|
return (
|
||||||
@ -29,7 +29,7 @@ export default function TrayWindow() {
|
|||||||
<Form.Item label="Default Height" name="tray_height">
|
<Form.Item label="Default Height" name="tray_height">
|
||||||
<InputNumber />
|
<InputNumber />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<SwitchOrigin name="tray" />
|
{/* <SwitchOrigin name="tray" /> */}
|
||||||
<Form.Item label={<UALabel />} name="ua_tray">
|
<Form.Item label={<UALabel />} name="ua_tray">
|
||||||
<Input.TextArea
|
<Input.TextArea
|
||||||
autoSize={{ minRows: 4, maxRows: 4 }}
|
autoSize={{ minRows: 4, maxRows: 4 }}
|
||||||
|
Loading…
Reference in New Issue
Block a user