This commit is contained in:
GH Action - Upstream Sync 2023-10-08 00:19:29 +00:00
commit 5933b3d7eb
15 changed files with 221 additions and 56 deletions

View File

@ -15,7 +15,8 @@ export function AuthPage() {
const access = useAccessStore(); const access = useAccessStore();
const goHome = () => navigate(Path.Home); const goHome = () => navigate(Path.Home);
const resetAccessCode = () => access.updateCode(""); // Reset access code to empty string const goChat = () => navigate(Path.Chat);
const resetAccessCode = () => { access.updateCode(""); access.updateToken(""); }; // Reset access code to empty string
useEffect(() => { useEffect(() => {
if (getClientConfig()?.isApp) { if (getClientConfig()?.isApp) {
@ -42,17 +43,34 @@ export function AuthPage() {
access.updateCode(e.currentTarget.value); access.updateCode(e.currentTarget.value);
}} }}
/> />
{!access.hideUserApiKey ? (
<>
<div className={styles["auth-tips"]}>{Locale.Auth.SubTips}</div>
<input
className={styles["auth-input"]}
type="password"
placeholder={Locale.Settings.Token.Placeholder}
value={access.token}
onChange={(e) => {
access.updateToken(e.currentTarget.value);
}}
/>
</>
) : null}
<div className={styles["auth-actions"]}> <div className={styles["auth-actions"]}>
<IconButton <IconButton
text={Locale.Auth.Confirm} text={Locale.Auth.Confirm}
type="primary" type="primary"
onClick={goHome} onClick={goChat}
/>
<IconButton
text={Locale.Auth.Later}
onClick={() => {
resetAccessCode();
goHome();
}}
/> />
<IconButton text={Locale.Auth.Later} onClick={() => {
resetAccessCode();
goHome();
}} />
</div> </div>
</div> </div>
); );

View File

@ -433,25 +433,55 @@ export function ImagePreviewer(props: {
const isMobile = useMobileScreen(); const isMobile = useMobileScreen();
const download = () => { const download = async () => {
showToast(Locale.Export.Image.Toast); showToast(Locale.Export.Image.Toast);
const dom = previewRef.current; const dom = previewRef.current;
if (!dom) return; if (!dom) return;
toPng(dom)
.then((blob) => { const isApp = getClientConfig()?.isApp;
if (!blob) return;
try {
if (isMobile || getClientConfig()?.isApp) { const blob = await toPng(dom);
showImageModal(blob); if (!blob) return;
if (isMobile || (isApp && window.__TAURI__)) {
if (isApp && window.__TAURI__) {
const result = await window.__TAURI__.dialog.save({
defaultPath: `${props.topic}.png`,
filters: [
{
name: "PNG Files",
extensions: ["png"],
},
{
name: "All Files",
extensions: ["*"],
},
],
});
if (result !== null) {
const response = await fetch(blob);
const buffer = await response.arrayBuffer();
const uint8Array = new Uint8Array(buffer);
await window.__TAURI__.fs.writeBinaryFile(result, uint8Array);
showToast(Locale.Download.Success);
} else {
showToast(Locale.Download.Failed);
}
} else { } else {
const link = document.createElement("a"); showImageModal(blob);
link.download = `${props.topic}.png`;
link.href = blob;
link.click();
refreshPreview();
} }
}) } else {
.catch((e) => console.log("[Export Image] ", e)); const link = document.createElement("a");
link.download = `${props.topic}.png`;
link.href = blob;
link.click();
refreshPreview();
}
} catch (error) {
showToast(Locale.Download.Failed);
}
}; };
const refreshPreview = () => { const refreshPreview = () => {

12
app/global.d.ts vendored
View File

@ -13,5 +13,17 @@ declare module "*.svg";
declare interface Window { declare interface Window {
__TAURI__?: { __TAURI__?: {
writeText(text: string): Promise<void>; writeText(text: string): Promise<void>;
invoke(command: string, payload?: Record<string, unknown>): Promise<any>;
dialog: {
save(options?: Record<string, unknown>): Promise<string | null>;
};
fs: {
writeBinaryFile(path: string, data: Uint8Array): Promise<void>;
};
notification:{
requestPermission(): Promise<Permission>;
isPermissionGranted(): Promise<boolean>;
sendNotification(options: string | Options): void;
};
}; };
} }

View File

@ -10,6 +10,7 @@ const ar: PartialLocaleType = {
Auth: { Auth: {
Title: "تحتاج إلى رمز الوصول", Title: "تحتاج إلى رمز الوصول",
Tips: "يرجى إدخال رمز الوصول أدناه", Tips: "يرجى إدخال رمز الوصول أدناه",
SubTips: "أو أدخل مفتاح واجهة برمجة تطبيقات OpenAI الخاص بك",
Input: "رمز الوصول", Input: "رمز الوصول",
Confirm: "تأكيد", Confirm: "تأكيد",
Later: "لاحقًا", Later: "لاحقًا",

View File

@ -10,6 +10,7 @@ const bn: PartialLocaleType = {
Auth: { Auth: {
Title: "একটি অ্যাক্সেস কোড প্রয়োজন", Title: "একটি অ্যাক্সেস কোড প্রয়োজন",
Tips: "নীচে অ্যাক্সেস কোড ইনপুট করুন", Tips: "নীচে অ্যাক্সেস কোড ইনপুট করুন",
SubTips: "অথবা আপনার OpenAI API কী প্রবেশ করুন",
Input: "অ্যাক্সেস কোড", Input: "অ্যাক্সেস কোড",
Confirm: "নিশ্চিত করুন", Confirm: "নিশ্চিত করুন",
Later: "পরে", Later: "পরে",

View File

@ -13,6 +13,7 @@ const cn = {
Auth: { Auth: {
Title: "需要密码", Title: "需要密码",
Tips: "管理员开启了密码验证,请在下方填入访问码", Tips: "管理员开启了密码验证,请在下方填入访问码",
SubTips: "或者输入你的 OpenAI API 密钥",
Input: "在此处填写访问码", Input: "在此处填写访问码",
Confirm: "确认", Confirm: "确认",
Later: "稍后再说", Later: "稍后再说",
@ -323,6 +324,10 @@ const cn = {
Success: "已写入剪切板", Success: "已写入剪切板",
Failed: "复制失败,请赋予剪切板权限", Failed: "复制失败,请赋予剪切板权限",
}, },
Download: {
Success: "内容已下载到您的目录。",
Failed: "下载失败。",
},
Context: { Context: {
Toast: (x: any) => `包含 ${x} 条预设提示词`, Toast: (x: any) => `包含 ${x} 条预设提示词`,
Edit: "当前对话设置", Edit: "当前对话设置",

View File

@ -15,6 +15,7 @@ const en: LocaleType = {
Auth: { Auth: {
Title: "Need Access Code", Title: "Need Access Code",
Tips: "Please enter access code below", Tips: "Please enter access code below",
SubTips: "Or enter your OpenAI API Key",
Input: "access code", Input: "access code",
Confirm: "Confirm", Confirm: "Confirm",
Later: "Later", Later: "Later",
@ -329,6 +330,10 @@ const en: LocaleType = {
Success: "Copied to clipboard", Success: "Copied to clipboard",
Failed: "Copy failed, please grant permission to access clipboard", Failed: "Copy failed, please grant permission to access clipboard",
}, },
Download: {
Success: "Content downloaded to your directory.",
Failed: "Download failed.",
},
Context: { Context: {
Toast: (x: any) => `With ${x} contextual prompts`, Toast: (x: any) => `With ${x} contextual prompts`,
Edit: "Current Chat Settings", Edit: "Current Chat Settings",

View File

@ -4,12 +4,12 @@ import { PartialLocaleType } from "./index";
const id: PartialLocaleType = { const id: PartialLocaleType = {
WIP: "Coming Soon...", WIP: "Coming Soon...",
Error: { Error: {
Unauthorized: Unauthorized: "Akses tidak diizinkan, silakan masukkan kode akses atau masukkan kunci API OpenAI Anda. di halaman [autentikasi](/#/auth) atau di halaman [Pengaturan](/#/settings).",
"Akses tidak diizinkan. Silakan [otorisasi](/#/auth) dengan memasukkan kode akses.", },
},
Auth: { Auth: {
Title: "Diperlukan Kode Akses", Title: "Diperlukan Kode Akses",
Tips: "Masukkan kode akses di bawah", Tips: "Masukkan kode akses di bawah",
SubTips: "Atau masukkan kunci API OpenAI Anda",
Input: "Kode Akses", Input: "Kode Akses",
Confirm: "Konfirmasi", Confirm: "Konfirmasi",
Later: "Nanti", Later: "Nanti",
@ -301,6 +301,10 @@ const id: PartialLocaleType = {
Failed: Failed:
"Gagal menyalin, mohon berikan izin untuk mengakses clipboard atau Clipboard API tidak didukung (Tauri)", "Gagal menyalin, mohon berikan izin untuk mengakses clipboard atau Clipboard API tidak didukung (Tauri)",
}, },
Download: {
Success: "Konten berhasil diunduh ke direktori Anda.",
Failed: "Unduhan gagal.",
},
Context: { Context: {
Toast: (x: any) => `Dengan ${x} promp kontekstual`, Toast: (x: any) => `Dengan ${x} promp kontekstual`,
Edit: "Pengaturan Obrolan Saat Ini", Edit: "Pengaturan Obrolan Saat Ini",

View File

@ -7,13 +7,13 @@ const tw: PartialLocaleType = {
Unauthorized: "目前您的狀態是未授權,請前往[設定頁面](/#/auth)輸入授權碼。", Unauthorized: "目前您的狀態是未授權,請前往[設定頁面](/#/auth)輸入授權碼。",
}, },
ChatItem: { ChatItem: {
ChatItemCount: (count: number) => `${count} 對話`, ChatItemCount: (count: number) => `${count} 對話`,
}, },
Chat: { Chat: {
SubTitle: (count: number) => `您已經與 ChatGPT 進行了 ${count} 對話`, SubTitle: (count: number) => `您已經與 ChatGPT 進行了 ${count} 對話`,
Actions: { Actions: {
ChatList: "查看訊息列表", ChatList: "檢視訊息列表",
CompressedHistory: "查看壓縮後的歷史 Prompt", CompressedHistory: "檢視壓縮後的歷史 Prompt",
Export: "匯出聊天紀錄", Export: "匯出聊天紀錄",
Copy: "複製", Copy: "複製",
Stop: "停止", Stop: "停止",
@ -23,15 +23,15 @@ const tw: PartialLocaleType = {
Rename: "重新命名對話", Rename: "重新命名對話",
Typing: "正在輸入…", Typing: "正在輸入…",
Input: (submitKey: string) => { Input: (submitKey: string) => {
var inputHints = `輸入訊息後,按下 ${submitKey} 鍵即可`; var inputHints = `輸入訊息後,按下 ${submitKey} 鍵即可`;
if (submitKey === String(SubmitKey.Enter)) { if (submitKey === String(SubmitKey.Enter)) {
inputHints += "Shift + Enter 鍵換行"; inputHints += "Shift + Enter 鍵換行";
} }
return inputHints; return inputHints;
}, },
Send: "送", Send: "送",
Config: { Config: {
Reset: "重置預設", Reset: "重設",
SaveAs: "另存新檔", SaveAs: "另存新檔",
}, },
}, },
@ -46,7 +46,7 @@ const tw: PartialLocaleType = {
Title: "上下文記憶 Prompt", Title: "上下文記憶 Prompt",
EmptyContent: "尚未記憶", EmptyContent: "尚未記憶",
Copy: "複製全部", Copy: "複製全部",
Send: "送記憶", Send: "送記憶",
Reset: "重設對話", Reset: "重設對話",
ResetConfirm: "重設後將清除目前對話記錄以及歷史記憶,確認重設?", ResetConfirm: "重設後將清除目前對話記錄以及歷史記憶,確認重設?",
}, },
@ -71,22 +71,22 @@ const tw: PartialLocaleType = {
}, },
InjectSystemPrompts: { InjectSystemPrompts: {
Title: "匯入系統提示", Title: "匯入系統提示",
SubTitle: "強制在每個請求的訊息列表開頭添加一個模擬 ChatGPT 的系統提示", SubTitle: "強制在每個請求的訊息列表開頭新增一個模擬 ChatGPT 的系統提示",
}, },
Update: { Update: {
Version: (x: string) => `前版本:${x}`, Version: (x: string) => `前版本:${x}`,
IsLatest: "已是最新版本", IsLatest: "已是最新版本",
CheckUpdate: "檢查更新", CheckUpdate: "檢查更新",
IsChecking: "正在檢查更新...", IsChecking: "正在檢查更新...",
FoundUpdate: (x: string) => `發現新版本:${x}`, FoundUpdate: (x: string) => `發現新版本:${x}`,
GoToUpdate: "前往更新", GoToUpdate: "前往更新",
}, },
SendKey: "送鍵", SendKey: "送鍵",
Theme: "主題", Theme: "主題",
TightBorder: "緊湊邊框", TightBorder: "緊湊邊框",
SendPreviewBubble: { SendPreviewBubble: {
Title: "預覽氣泡", Title: "預覽氣泡",
SubTitle: "在預覽氣泡中預覽 Markdown 容", SubTitle: "在預覽氣泡中預覽 Markdown 容",
}, },
Mask: { Mask: {
Splash: { Splash: {
@ -101,7 +101,7 @@ const tw: PartialLocaleType = {
}, },
List: "自定義提示詞列表", List: "自定義提示詞列表",
ListCount: (builtin: number, custom: number) => ListCount: (builtin: number, custom: number) =>
`內建 ${builtin} 條,用戶定義 ${custom}`, `內建 ${builtin} 條,使用者定義 ${custom}`,
Edit: "編輯", Edit: "編輯",
Modal: { Modal: {
Title: "提示詞列表", Title: "提示詞列表",
@ -132,7 +132,7 @@ const tw: PartialLocaleType = {
}, },
IsChecking: "正在檢查…", IsChecking: "正在檢查…",
Check: "重新檢查", Check: "重新檢查",
NoAccess: "輸入API Key查看餘額", NoAccess: "輸入 API Key 檢視餘額",
}, },
AccessCode: { AccessCode: {
Title: "授權碼", Title: "授權碼",
@ -150,7 +150,7 @@ const tw: PartialLocaleType = {
}, },
PresencePenalty: { PresencePenalty: {
Title: "話題新穎度 (presence_penalty)", Title: "話題新穎度 (presence_penalty)",
SubTitle: "值越大,越有可能展到新話題", SubTitle: "值越大,越有可能展到新話題",
}, },
FrequencyPenalty: { FrequencyPenalty: {
Title: "頻率懲罰度 (frequency_penalty)", Title: "頻率懲罰度 (frequency_penalty)",
@ -163,7 +163,7 @@ const tw: PartialLocaleType = {
Error: "出錯了,請稍後再嘗試", Error: "出錯了,請稍後再嘗試",
Prompt: { Prompt: {
History: (content: string) => History: (content: string) =>
"這是 AI 與用戶的歷史聊天總結,作為前情提要:" + content, "這是 AI 與使用者的歷史聊天總結,作為前情提要:" + content,
Topic: Topic:
"Use the language used by the user (e.g. en for english conversation, zh-hant for chinese conversation, etc.) to generate a title (at most 6 words) summarizing our conversation without any lead-in, quotation marks, preamble like 'Title:', direct text copies, single-word replies, quotation marks, translations, or brackets. Remove enclosing quotation marks. The title should make third-party grasp the essence of the conversation in first sight.", "Use the language used by the user (e.g. en for english conversation, zh-hant for chinese conversation, etc.) to generate a title (at most 6 words) summarizing our conversation without any lead-in, quotation marks, preamble like 'Title:', direct text copies, single-word replies, quotation marks, translations, or brackets. Remove enclosing quotation marks. The title should make third-party grasp the essence of the conversation in first sight.",
Summarize: Summarize:
@ -192,16 +192,16 @@ const tw: PartialLocaleType = {
Item: { Item: {
Info: (count: number) => `包含 ${count} 條預設對話`, Info: (count: number) => `包含 ${count} 條預設對話`,
Chat: "對話", Chat: "對話",
View: "查看", View: "檢視",
Edit: "編輯", Edit: "編輯",
Delete: "除", Delete: "除",
DeleteConfirm: "確認除?", DeleteConfirm: "確認除?",
}, },
EditModal: { EditModal: {
Title: (readonly: boolean) => Title: (readonly: boolean) =>
`編輯預設面具 ${readonly ? "(只" : ""}`, `編輯預設面具 ${readonly ? "(只" : ""}`,
Download: "下載預設", Download: "下載預設",
Clone: "克隆預設", Clone: "複製預設",
}, },
Config: { Config: {
Avatar: "角色頭像", Avatar: "角色頭像",
@ -215,7 +215,7 @@ const tw: PartialLocaleType = {
SubTitle: "現在開始,與面具背後的靈魂思維碰撞", SubTitle: "現在開始,與面具背後的靈魂思維碰撞",
More: "搜尋更多", More: "搜尋更多",
NotShow: "不再呈現", NotShow: "不再呈現",
ConfirmNoShow: "確認禁用?禁用後可以随時在設定中重新啟用。", ConfirmNoShow: "確認停用?停用後可以隨時在設定中重新啟用。",
}, },
UI: { UI: {
Confirm: "確認", Confirm: "確認",

View File

@ -1,4 +1,5 @@
import { LLMModel } from "../client/api"; import { LLMModel } from "../client/api";
import { isMacOS } from "../utils";
import { getClientConfig } from "../config/client"; import { getClientConfig } from "../config/client";
import { import {
DEFAULT_INPUT_TEMPLATE, DEFAULT_INPUT_TEMPLATE,
@ -27,7 +28,7 @@ export enum Theme {
export const DEFAULT_CONFIG = { export const DEFAULT_CONFIG = {
lastUpdate: Date.now(), // timestamp, to merge state lastUpdate: Date.now(), // timestamp, to merge state
submitKey: SubmitKey.CtrlEnter as SubmitKey, submitKey: isMacOS() ? SubmitKey.MetaEnter : SubmitKey.CtrlEnter,
avatar: "1f603", avatar: "1f603",
fontSize: 14, fontSize: 14,
theme: Theme.Auto as Theme, theme: Theme.Auto as Theme,

View File

@ -1,3 +1,4 @@
import { getClientConfig } from "../config/client";
import { Updater } from "../typing"; import { Updater } from "../typing";
import { ApiPath, STORAGE_KEY, StoreKey } from "../constant"; import { ApiPath, STORAGE_KEY, StoreKey } from "../constant";
import { createPersistStore } from "../utils/store"; import { createPersistStore } from "../utils/store";
@ -20,6 +21,7 @@ export interface WebDavConfig {
password: string; password: string;
} }
const isApp = !!getClientConfig()?.isApp;
export type SyncStore = GetStoreState<typeof useSyncStore>; export type SyncStore = GetStoreState<typeof useSyncStore>;
const DEFAULT_SYNC_STATE = { const DEFAULT_SYNC_STATE = {
@ -57,7 +59,11 @@ export const useSyncStore = createPersistStore(
export() { export() {
const state = getLocalAppState(); const state = getLocalAppState();
const fileName = `Backup-${new Date().toLocaleString()}.json`; const datePart = isApp
? `${new Date().toLocaleDateString().replace(/\//g, '_')} ${new Date().toLocaleTimeString().replace(/:/g, '_')}`
: new Date().toLocaleString();
const fileName = `Backup-${datePart}.json`;
downloadAs(JSON.stringify(state), fileName); downloadAs(JSON.stringify(state), fileName);
}, },

View File

@ -2,8 +2,11 @@ import { FETCH_COMMIT_URL, FETCH_TAG_URL, StoreKey } from "../constant";
import { api } from "../client/api"; import { api } from "../client/api";
import { getClientConfig } from "../config/client"; import { getClientConfig } from "../config/client";
import { createPersistStore } from "../utils/store"; import { createPersistStore } from "../utils/store";
import ChatGptIcon from "../icons/chatgpt.png";
import Locale from "../locales";
const ONE_MINUTE = 60 * 1000; const ONE_MINUTE = 60 * 1000;
const isApp = !!getClientConfig()?.isApp;
function formatVersionDate(t: string) { function formatVersionDate(t: string) {
const d = new Date(+t); const d = new Date(+t);
@ -80,6 +83,38 @@ export const useUpdateStore = createPersistStore(
set(() => ({ set(() => ({
remoteVersion: remoteId, remoteVersion: remoteId,
})); }));
if (window.__TAURI__?.notification && isApp) {
// Check if notification permission is granted
await window.__TAURI__?.notification.isPermissionGranted().then((granted) => {
if (!granted) {
return;
} else {
// Request permission to show notifications
window.__TAURI__?.notification.requestPermission().then((permission) => {
if (permission === 'granted') {
if (version === remoteId) {
// Show a notification using Tauri
window.__TAURI__?.notification.sendNotification({
title: "ChatGPT Next Web",
body: `${Locale.Settings.Update.IsLatest}`,
icon: `${ChatGptIcon.src}`,
sound: "Default"
});
} else {
const updateMessage = Locale.Settings.Update.FoundUpdate(`${remoteId}`);
// Show a notification for the new version using Tauri
window.__TAURI__?.notification.sendNotification({
title: "ChatGPT Next Web",
body: updateMessage,
icon: `${ChatGptIcon.src}`,
sound: "Default"
});
}
}
});
}
});
}
console.log("[Got Upstream] ", remoteId); console.log("[Got Upstream] ", remoteId);
} catch (error) { } catch (error) {
console.error("[Fetch Upstream Commit Id]", error); console.error("[Fetch Upstream Commit Id]", error);

View File

@ -31,12 +31,41 @@ export async function copyToClipboard(text: string) {
} }
} }
export function downloadAs(text: string, filename: string) { export async function downloadAs(text: string, filename: string) {
const element = document.createElement("a"); if (window.__TAURI__) {
element.setAttribute( const result = await window.__TAURI__.dialog.save({
"href", defaultPath: `${filename}`,
"data:text/plain;charset=utf-8," + encodeURIComponent(text), filters: [
); {
name: `${filename.split('.').pop()} files`,
extensions: [`${filename.split('.').pop()}`],
},
{
name: "All Files",
extensions: ["*"],
},
],
});
if (result !== null) {
try {
await window.__TAURI__.fs.writeBinaryFile(
result,
new Uint8Array([...text].map((c) => c.charCodeAt(0)))
);
showToast(Locale.Download.Success);
} catch (error) {
showToast(Locale.Download.Failed);
}
} else {
showToast(Locale.Download.Failed);
}
} else {
const element = document.createElement("a");
element.setAttribute(
"href",
"data:text/plain;charset=utf-8," + encodeURIComponent(text),
);
element.setAttribute("download", filename); element.setAttribute("download", filename);
element.style.display = "none"; element.style.display = "none";
@ -46,7 +75,7 @@ export function downloadAs(text: string, filename: string) {
document.body.removeChild(element); document.body.removeChild(element);
} }
}
export function readFromFile() { export function readFromFile() {
return new Promise<string>((res, rej) => { return new Promise<string>((res, rej) => {
const fileInput = document.createElement("input"); const fileInput = document.createElement("input");
@ -173,3 +202,15 @@ export function autoGrowTextArea(dom: HTMLTextAreaElement) {
export function getCSSVar(varName: string) { export function getCSSVar(varName: string) {
return getComputedStyle(document.body).getPropertyValue(varName).trim(); return getComputedStyle(document.body).getPropertyValue(varName).trim();
} }
/**
* Detects Macintosh
*/
export function isMacOS(): boolean {
if (typeof window !== "undefined") {
let userAgent = window.navigator.userAgent.toLocaleLowerCase();
const macintosh = /iphone|ipad|ipod|macintosh/.test(userAgent)
return !!macintosh
}
return false
}

View File

@ -17,7 +17,7 @@ tauri-build = { version = "1.3.0", features = [] }
[dependencies] [dependencies]
serde_json = "1.0" serde_json = "1.0"
serde = { version = "1.0", features = ["derive"] } serde = { version = "1.0", features = ["derive"] }
tauri = { version = "1.3.0", features = ["clipboard-all", "dialog-all", "shell-open", "updater", "window-close", "window-hide", "window-maximize", "window-minimize", "window-set-icon", "window-set-ignore-cursor-events", "window-set-resizable", "window-show", "window-start-dragging", "window-unmaximize", "window-unminimize"] } tauri = { version = "1.3.0", features = ["notification-all", "fs-all", "clipboard-all", "dialog-all", "shell-open", "updater", "window-close", "window-hide", "window-maximize", "window-minimize", "window-set-icon", "window-set-ignore-cursor-events", "window-set-resizable", "window-show", "window-start-dragging", "window-unmaximize", "window-unminimize"] }
tauri-plugin-window-state = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "v1" } tauri-plugin-window-state = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "v1" }
[features] [features]

View File

@ -9,7 +9,7 @@
}, },
"package": { "package": {
"productName": "ChatGPT Next Web", "productName": "ChatGPT Next Web",
"version": "2.9.7" "version": "2.9.8"
}, },
"tauri": { "tauri": {
"allowlist": { "allowlist": {
@ -44,6 +44,12 @@
"startDragging": true, "startDragging": true,
"unmaximize": true, "unmaximize": true,
"unminimize": true "unminimize": true
},
"fs": {
"all": true
},
"notification": {
"all": true
} }
}, },
"bundle": { "bundle": {