Compare commits
98 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3e4a4a3031 | ||
|
|
8863e4575c | ||
|
|
94a8112d45 | ||
|
|
7ee9b0c716 | ||
|
|
b97d3a55f2 | ||
|
|
a3b40f7f40 | ||
|
|
de5533d942 | ||
|
|
8022594ace | ||
|
|
ec20d03c50 | ||
|
|
bb6e431bd9 | ||
|
|
8c2303dec9 | ||
|
|
d0df8df108 | ||
|
|
a7cff0df66 | ||
|
|
cd2b7832d4 | ||
|
|
3919b24df8 | ||
|
|
fc25746c2d | ||
|
|
ab0999d7d7 | ||
|
|
c2b0e02b75 | ||
|
|
a6e746d27e | ||
|
|
a0896c9799 | ||
|
|
a87654e427 | ||
|
|
8ad7a8a9b0 | ||
|
|
9f3c72ec6d | ||
|
|
13acb1d56e | ||
|
|
d982a09870 | ||
|
|
1dee42dc79 | ||
|
|
e3c9b16de3 | ||
|
|
d657a6e262 | ||
|
|
e0c4584529 | ||
|
|
f812d5ab04 | ||
|
|
c1cec366fb | ||
|
|
3e300c66c3 | ||
|
|
f7335d9162 | ||
|
|
e7ed106a01 | ||
|
|
cf09dbe429 | ||
|
|
73a91df77e | ||
|
|
fc6912eb59 | ||
|
|
f646684f4d | ||
|
|
2f0e617b1a | ||
|
|
3e9c2f8e94 | ||
|
|
8689082c7b | ||
|
|
aa98d7dd2a | ||
|
|
a361ce52b5 | ||
|
|
594260ce5d | ||
|
|
53a240953f | ||
|
|
4c86477d6f | ||
|
|
e2235e7060 | ||
|
|
3dd49cd5d3 | ||
|
|
65bb811f15 | ||
|
|
ce60c0566f | ||
|
|
0ab4832349 | ||
|
|
5286de2f1e | ||
|
|
197d458c78 | ||
|
|
845229d629 | ||
|
|
30099f730f | ||
|
|
f26dace129 | ||
|
|
0a434f1add | ||
|
|
883f36b26d | ||
|
|
a7cd73b314 | ||
|
|
c19698bc41 | ||
|
|
0197d12119 | ||
|
|
038b13dd31 | ||
|
|
c7a6cfc897 | ||
|
|
a6912deb9f | ||
|
|
709029a6c6 | ||
|
|
060f3b5915 | ||
|
|
139afa2943 | ||
|
|
cef8ffc1a7 | ||
|
|
693b83e0c6 | ||
|
|
b35b035c09 | ||
|
|
b8614e73ff | ||
|
|
6bd52fe961 | ||
|
|
b370fd187c | ||
|
|
9333800002 | ||
|
|
b76d141dbc | ||
|
|
b66fbd617d | ||
|
|
802a201d82 | ||
|
|
508752691c | ||
|
|
484f1d6921 | ||
|
|
a27876b7a9 | ||
|
|
7c4f0bf67f | ||
|
|
41cc76d557 | ||
|
|
a6bac89a87 | ||
|
|
b7591c0b41 | ||
|
|
ffa8ff1d03 | ||
|
|
bac33c4689 | ||
|
|
bce27c1e39 | ||
|
|
5e1295677c | ||
|
|
51891e8a8a | ||
|
|
10993667ab | ||
|
|
fd62c2a8c4 | ||
|
|
85fbd4a104 | ||
|
|
5ebda4105d | ||
|
|
4c7907c106 | ||
|
|
beddf76198 | ||
|
|
d450d35935 | ||
|
|
11492fef24 | ||
|
|
74c0d07a76 |
43
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
name: "🕷️ Bug report"
|
||||
description: "report bugs"
|
||||
title: "[Bug]"
|
||||
labels:
|
||||
- "bug"
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: "Please make sure to [search for existing issues](https://github.com/lencx/ChatGPT/issues) before filing a new one!"
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
## Bug report
|
||||
Please fill in the following information to help us reproduce the bug:
|
||||
- type: input
|
||||
id: version
|
||||
attributes:
|
||||
label: Version
|
||||
description: "Please specify the version of ChatGPT you are using, a newer version may have fixed the bug you encountered.Check the [UPDATE_LOG](https://github.com/lencx/ChatGPT/blob/main/UPDATE_LOG.md) for more information."
|
||||
placeholder: "e.g. v0.1.0"
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: bug
|
||||
attributes:
|
||||
label: Bug description
|
||||
description: |
|
||||
Please describe the bug here,if possible, please provide a minimal example to reproduce the bug.The content of `~/.chatgpt/chatgpt.log` may be helpful if you encounter a crash.
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: OS
|
||||
attributes:
|
||||
label: OS
|
||||
description: "Please specify the OS you are using."
|
||||
placeholder: "e.g. Ubuntu 22.04"
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: environment
|
||||
attributes:
|
||||
label: Environment
|
||||
description: "If you think your environment may be related to the problem, please describe it here."
|
||||
37
.github/ISSUE_TEMPLATE/build_error_report.yml
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
name: "❌ Build error report"
|
||||
description: "report errors when building by yourself"
|
||||
title: "[Build Error]"
|
||||
labels:
|
||||
- "build error"
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: "Please make sure to [search for existing issues](https://github.com/lencx/ChatGPT/issues) before filing a new one!"
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: "Please make sure to build from the source code with the latest version of ChatGPT."
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
## Build error report
|
||||
Please fill in the following information to help us reproduce the bug:
|
||||
- type: textarea
|
||||
id: error
|
||||
attributes:
|
||||
label: Error message
|
||||
description: "Please paste the error message here."
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: OS
|
||||
attributes:
|
||||
label: OS
|
||||
description: "Please specify the OS you are using."
|
||||
placeholder: "e.g. Ubuntu 22.04"
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: environment
|
||||
attributes:
|
||||
label: Environment
|
||||
description: "If you think your environment may be related to the problem, please describe it here."
|
||||
1
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
@@ -0,0 +1 @@
|
||||
blank_issues_enabled: false
|
||||
19
.github/ISSUE_TEMPLATE/docmentation_issue.yml
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
name: "📚 Documentation Issue"
|
||||
description: "report documentation issues, typos welcome!"
|
||||
title: "[Doc]"
|
||||
labels:
|
||||
- "documentation"
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: "Please make sure to [search for existing issues](https://github.com/lencx/ChatGPT/issues) before creating a new one."
|
||||
- type: textarea
|
||||
id: doc-description
|
||||
attributes:
|
||||
label: "Provide a description of requested docs changes"
|
||||
description: "Briefly describe the requested docs changes."
|
||||
validations:
|
||||
required: true
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: Please limit one request per issue.
|
||||
34
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
name: "⭐ Feature or enhancement request"
|
||||
description: "suggest new features or enhancements"
|
||||
title: "[Feature]"
|
||||
labels:
|
||||
- "enhancement"
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: "Please make sure to [search for existing issues](https://github.com/lencx/ChatGPT/issues) before creating a new one."
|
||||
- type: textarea
|
||||
id: feature-description
|
||||
attributes:
|
||||
label: "Feature description"
|
||||
description: "Describe the feature or enhancements you'd like to see."
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: motivation
|
||||
attributes:
|
||||
label: "Motivation"
|
||||
description: "Describe the motivation for this feature or enhancement."
|
||||
- type: textarea
|
||||
id: alternatives
|
||||
attributes:
|
||||
label: "Alternatives"
|
||||
description: "Describe any alternatives you've considered."
|
||||
- type: textarea
|
||||
id: additional-context
|
||||
attributes:
|
||||
label: "Additional context"
|
||||
description: "Add any other context or screenshots about the feature request here."
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: Please limit one request per issue.
|
||||
34
.github/ISSUE_TEMPLATE/security.yml
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
name: "⚠️ Security&Privacy issue"
|
||||
description: "Report security or privacy issues"
|
||||
title: "[Security]"
|
||||
labels:
|
||||
- "security"
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: "Please make sure to [search for existing issues](https://github.com/lencx/ChatGPT/issues) before creating a new one."
|
||||
- type: textarea
|
||||
id: security-description
|
||||
attributes:
|
||||
label: "Description"
|
||||
description: "Describe the security or privacy issue."
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: motivation
|
||||
attributes:
|
||||
label: "Motivation"
|
||||
description: "Describe the motivation for this security or privacy issue."
|
||||
- type: textarea
|
||||
id: alternatives
|
||||
attributes:
|
||||
label: "Alternatives"
|
||||
description: "Describe any alternatives you've considered."
|
||||
- type: textarea
|
||||
id: additional-context
|
||||
attributes:
|
||||
label: "Additional context"
|
||||
description: "Add any other context or screenshots about the security or privacy issue here."
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: Please limit one request per issue.
|
||||
14
.github/workflows/release.yml
vendored
@@ -57,6 +57,9 @@ jobs:
|
||||
- name: Install app dependencies and build it
|
||||
run: yarn && yarn build:fe
|
||||
|
||||
# - name: Rewrite tauri.conf.json
|
||||
# run: yarn fix:conf
|
||||
|
||||
- name: fix tray icon
|
||||
if: matrix.platform != 'macos-latest'
|
||||
run: |
|
||||
@@ -87,3 +90,14 @@ jobs:
|
||||
# 📝: Edit the deployment directory
|
||||
publish_dir: ./updater
|
||||
force_orphan: true
|
||||
|
||||
publish-winget:
|
||||
# Action can only be run on windows
|
||||
runs-on: windows-latest
|
||||
needs: [create-release, build-tauri]
|
||||
steps:
|
||||
- uses: vedantmgoyal2009/winget-releaser@v1
|
||||
with:
|
||||
identifier: lencx.ChatGPT
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
version: ${{ env.version }}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Awesome ChatGPT
|
||||
|
||||
- [Awesome ChatGPT Prompts](https://github.com/f/awesome-chatgpt-prompts) - This repo includes ChatGPT promt curation to use ChatGPT better.
|
||||
- [Awesome ChatGPT Prompts](https://github.com/f/awesome-chatgpt-prompts) - This repo includes ChatGPT prompt curation to use ChatGPT better.
|
||||
- [Awesome ChatGPT](https://github.com/humanloop/awesome-chatgpt) - Curated list of awesome tools, demos, docs for ChatGPT and GPT-3
|
||||
|
||||
## Extension
|
||||
|
||||
108
README-ZH_CN.md
@@ -1,62 +1,77 @@
|
||||
<p align="center">
|
||||
<img width="180" src="./public/logo.png" alt="ChatGPT">
|
||||
<h1 align="center">ChatGPT</h1>
|
||||
<p align="center">ChatGPT 桌面应用(Mac, Windows and Linux)</p>
|
||||
</p>
|
||||
|
||||
> ChatGPT 桌面应用
|
||||
|
||||
[](./README.md)
|
||||
[](./README-ZH_CN.md)
|
||||
|
||||
[](./README-ZH_CN.md)\
|
||||

|
||||
[](https://github.com/lencx/ChatGPT/releases)
|
||||
[](https://discord.gg/aPhCRf4zZr)
|
||||
[](https://twitter.com/lencx_)
|
||||
|
||||
[Awesome ChatGPT](./AWESOME.md)
|
||||
<a href="https://www.buymeacoffee.com/lencx" target="_blank"><img src="https://cdn.buymeacoffee.com/buttons/v2/default-blue.png" alt="Buy Me A Coffee" style="height: 40px !important;width: 145px !important;" ></a>
|
||||
|
||||
## 📦 下载
|
||||
## 📦 安装
|
||||
|
||||
[📝 更新日志](./UPDATE_LOG.md)
|
||||
- [📝 更新日志](./UPDATE_LOG.md)
|
||||
- [🕒 历史版本...](https://github.com/lencx/ChatGPT/releases)
|
||||
|
||||
<!-- download start -->
|
||||
|
||||
**最新版:**
|
||||
### Windows
|
||||
|
||||
- `Mac`: [ChatGPT_0.7.4_x64.dmg](https://github.com/lencx/ChatGPT/releases/download/v0.7.4/ChatGPT_0.7.4_x64.dmg)
|
||||
- `Linux`: [chat-gpt_0.7.4_amd64.deb](https://github.com/lencx/ChatGPT/releases/download/v0.7.4/chat-gpt_0.7.4_amd64.deb)
|
||||
- `Windows`: [ChatGPT_0.7.4_x64_en-US.msi](https://github.com/lencx/ChatGPT/releases/download/v0.7.4/ChatGPT_0.7.4_x64_en-US.msi)
|
||||
- [ChatGPT_0.8.0_x64_en-US.msi](https://github.com/lencx/ChatGPT/releases/download/v0.8.0/ChatGPT_0.8.0_x64_en-US.msi):
|
||||
- 使用 [winget](https://winstall.app/apps/lencx.ChatGPT):
|
||||
```bash
|
||||
# install the latest version
|
||||
winget install --id=lencx.ChatGPT -e
|
||||
|
||||
[其他版本...](https://github.com/lencx/ChatGPT/releases)
|
||||
# install the specified version
|
||||
winget install --id=lencx.ChatGPT -e --version 0.8.0
|
||||
```
|
||||
|
||||
**注意:如果安装路径和应用名称相同,会导致冲突 ([#142](https://github.com/lencx/ChatGPT/issues/142#issuecomment-0.8.0))**
|
||||
|
||||
### Mac
|
||||
|
||||
- [ChatGPT_0.8.0_x64.dmg](https://github.com/lencx/ChatGPT/releases/download/v0.8.0/ChatGPT_0.8.0_x64.dmg)
|
||||
- [ChatGPT.app.tar.gz](https://github.com/lencx/ChatGPT/releases/download/v0.8.0/ChatGPT.app.tar.gz)
|
||||
- Homebrew \
|
||||
_[Homebrew 快捷安装](https://brew.sh) ([Cask](https://docs.brew.sh/Cask-Cookbook)):_
|
||||
```sh
|
||||
brew tap lencx/chatgpt https://github.com/lencx/ChatGPT.git
|
||||
brew install --cask chatgpt --no-quarantine
|
||||
```
|
||||
如果你坚持使用 _[Brewfile](https://github.com/Homebrew/homebrew-bundle#usage)_ ,则需要添加以下配置:
|
||||
```rb
|
||||
repo = "lencx/chatgpt"
|
||||
tap repo, "https://github.com/#{repo}.git"
|
||||
cask "chatgpt", args: { "no-quarantine": true }
|
||||
```
|
||||
|
||||
### Linux
|
||||
|
||||
- [chat-gpt_0.8.0_amd64.deb](https://github.com/lencx/ChatGPT/releases/download/v0.8.0/chat-gpt_0.8.0_amd64.deb)
|
||||
- [chat-gpt_0.8.0_amd64.AppImage](https://github.com/lencx/ChatGPT/releases/download/v0.8.0/chat-gpt_0.8.0_amd64.AppImage): **工作可靠,`.deb` 运行失败时可以尝试它**
|
||||
- 使用 [AUR](https://aur.archlinux.org/packages/chatgpt-desktop-bin):
|
||||
```bash
|
||||
yay -S chatgpt-desktop-bin
|
||||
```
|
||||
|
||||
<!-- download end -->
|
||||
|
||||
### brew 安装
|
||||
|
||||
Easily install with _[Homebrew](https://brew.sh) ([Cask](https://docs.brew.sh/Cask-Cookbook)):_
|
||||
|
||||
```sh
|
||||
brew tap lencx/chatgpt https://github.com/lencx/ChatGPT.git
|
||||
brew install --cask chatgpt --no-quarantine
|
||||
```
|
||||
|
||||
Also, if you keep a _[Brewfile](https://github.com/Homebrew/homebrew-bundle#usage)_, you can add something like this:
|
||||
|
||||
```rb
|
||||
repo = "lencx/chatgpt"
|
||||
tap repo, "https://github.com/#{repo}.git"
|
||||
cask "popcorn-time", args: { "no-quarantine": true }
|
||||
```
|
||||
|
||||
## 📢 公告
|
||||
|
||||
这是一个令人兴奋的重大更新。像 `Telegram 机器人指令` 那样工作,帮助你快速填充自定模型,来让 ChatGPT 按照你想要的方式去工作。这个项目倾注了我大量业余时间,如果它对你有所帮助,宣传转发,或者 star 都是对我的巨大鼓励。我希望我可以持续更新下去,加入更多有趣的功能。
|
||||
|
||||
### 如何使用指令?
|
||||
|
||||
你可以从 [awesome-chatgpt-prompts](https://github.com/f/awesome-chatgpt-prompts) 来寻找有趣的功能来导入到应用。
|
||||
你可以从 [awesome-chatgpt-prompts](https://github.com/f/awesome-chatgpt-prompts) 来寻找有趣的功能来导入到应用。也可以使用 `Sync Prompts`,来一键同步所有,如果你不想让某些提示出现在你的斜杠命令,你可以禁用它们。
|
||||
|
||||

|
||||

|
||||

|
||||

|
||||
|
||||
<!-- 数据导入完成后,可以重新启动应用来使配置生效(`Menu -> Preferences -> Restart ChatGPT`)。 -->
|
||||
|
||||
@@ -75,11 +90,12 @@ cask "popcorn-time", args: { "no-quarantine": true }
|
||||
- 应用菜单功能强大
|
||||
- 支持斜杠命令及其配置(可手动配置或从文件同步 [#55](https://github.com/lencx/ChatGPT/issues/55))
|
||||
- 自定义全局快捷键 ([#108](https://github.com/lencx/ChatGPT/issues/108))
|
||||
- 划词搜索 ([#122](https://github.com/lencx/ChatGPT/issues/122) 鼠标选中文本,不超过 400 个字符):应用使用 Tauri 构建,因其安全限制,会导致部分操作按钮无效,建议前往浏览器操作。
|
||||
|
||||
### 菜单项
|
||||
### #️⃣ 菜单项
|
||||
|
||||
- **Preferences (喜好)**
|
||||
- `Theme` - `Light`, `Dark` (仅支持 macOS 和 Windows)
|
||||
- `Theme` - `Light`, `Dark`, `System` (仅支持 macOS 和 Windows)
|
||||
- `Stay On Top`: 窗口置顶
|
||||
- `Titlebar`: 是否显示 `Titlebar`,仅 macOS 支持
|
||||
- `Inject Script`: 用于修改网站的用户自定义脚本
|
||||
@@ -100,7 +116,7 @@ cask "popcorn-time", args: { "no-quarantine": true }
|
||||
- `Report Bug`: 报告 BUG 或反馈建议
|
||||
- `Toggle Developer Tools`: 网站调试工具,调试页面或脚本可能需要
|
||||
|
||||
## 应用配置
|
||||
## ⚙️ 应用配置
|
||||
|
||||
| 平台 | 路径 |
|
||||
| ------- | ------------------------- |
|
||||
@@ -122,11 +138,11 @@ cask "popcorn-time", args: { "no-quarantine": true }
|
||||
- `4f695d3cfbf8491e9b1f3fab6d85715c.json` - 随机生成的文件名,缓存 `sync_custom` 数据
|
||||
- `bd1b96f15a1644f7bd647cc53073ff8f.json` - 随机生成的文件名,缓存 `sync_custom` 数据
|
||||
|
||||
### Sync Custom
|
||||
### 客户端信息同步
|
||||
|
||||
目前同步自定文件仅支持 json 和 csv,且需要满足以下格式,否则会导致应用异常:
|
||||
|
||||
> JSON 格式
|
||||
`JSON 格式`
|
||||
|
||||
```json
|
||||
[
|
||||
@@ -143,7 +159,7 @@ cask "popcorn-time", args: { "no-quarantine": true }
|
||||
]
|
||||
```
|
||||
|
||||
> CSV 格式
|
||||
`CSV 格式`
|
||||
|
||||
```csv
|
||||
"cmd","act","prompt"
|
||||
@@ -153,13 +169,9 @@ cask "popcorn-time", args: { "no-quarantine": true }
|
||||
|
||||
## 👀 预览
|
||||
|
||||
<img width="320" src="./assets/install.png" alt="install"> <img width="320" src="./assets/control-center.png" alt="control center">
|
||||
<img width="320" src="./assets/export.png" alt="export"> <img width="320" src="./assets/tray.png" alt="tray">
|
||||
<img width="320" src="./assets/tray-login.png" alt="tray login"> <img width="320" src="./assets/auto-update.png" alt="auto update">
|
||||
|
||||
---
|
||||
|
||||
<a href="https://www.buymeacoffee.com/lencx" target="_blank"><img src="https://cdn.buymeacoffee.com/buttons/v2/default-blue.png" alt="Buy Me A Coffee" style="height: 60px !important;width: 217px !important;" ></a>
|
||||
<img width="320" src="./assets/install.png" alt="install"> <img width="320" src="./assets/chatgpt-control-center-general.png" alt="control center">
|
||||
<img width="320" src="./assets/chatgpt-export.png" alt="export"> <img width="320" src="./assets/chatgpt-dalle2-tray.png" alt="dalle2 tray">
|
||||
<img width="320" src="./assets/auto-update.png" alt="auto update">
|
||||
|
||||
## ❓ 常见问题
|
||||
|
||||
@@ -175,12 +187,14 @@ cask "popcorn-time", args: { "no-quarantine": true }
|
||||
|
||||
它是安全的,仅仅只是对 [OpenAI ChatGPT](https://chat.openai.com) 网站的包装,注入了一些额外功能(均在本地,未发起网络请求),如果存疑,可以检查源代码。
|
||||
|
||||
### Developer cannot be verified?
|
||||
### 开发者未验证?
|
||||
|
||||
Mac 上无法安装,提示开发者未验证,具体可以查看下面给出的解决方案(它是开源的,很安全)。
|
||||
|
||||
- [Open a Mac app from an unidentified developer](https://support.apple.com/en-sg/guide/mac-help/mh40616/mac)
|
||||
|
||||
---
|
||||
|
||||
### 我想自己构建它?
|
||||
|
||||
#### 预安装
|
||||
@@ -217,7 +231,7 @@ yarn build
|
||||
|
||||
---
|
||||
|
||||
[](https://star-history.com/#lencx/chatgpt&Date)
|
||||
[](https://star-history.com/#lencx/chatgpt&Timeline)
|
||||
|
||||
## 中国用户
|
||||
|
||||
|
||||
112
README.md
@@ -1,68 +1,84 @@
|
||||
<p align="center">
|
||||
<img width="180" src="./public/logo.png" alt="ChatGPT">
|
||||
<h1 align="center">ChatGPT</h1>
|
||||
<p align="center">ChatGPT Desktop Application (Mac, Windows and Linux)</p>
|
||||
</p>
|
||||
|
||||
> ChatGPT Desktop Application
|
||||
|
||||
[](./README.md)
|
||||
[](./README-ZH_CN.md)
|
||||
|
||||
[](./README-ZH_CN.md)\
|
||||

|
||||
[](https://github.com/lencx/ChatGPT/releases)
|
||||
[](https://discord.gg/aPhCRf4zZr)
|
||||
[](https://twitter.com/lencx_)
|
||||
|
||||
<!-- [](./README-ZH.md) -->
|
||||
|
||||
[Awesome ChatGPT](./AWESOME.md)
|
||||
<a href="https://www.buymeacoffee.com/lencx" target="_blank"><img src="https://cdn.buymeacoffee.com/buttons/v2/default-blue.png" alt="Buy Me A Coffee" style="height: 40px !important;width: 145px !important;" ></a>
|
||||
|
||||
## 📦 Downloads
|
||||
## 📦 Install
|
||||
|
||||
[📝 Update Log](./UPDATE_LOG.md)
|
||||
- [📝 Update Log](./UPDATE_LOG.md)
|
||||
- [🕒 History versions...](https://github.com/lencx/ChatGPT/releases)
|
||||
|
||||
<!-- download start -->
|
||||
|
||||
**Latest:**
|
||||
### Windows
|
||||
|
||||
- `Mac`: [ChatGPT_0.7.4_x64.dmg](https://github.com/lencx/ChatGPT/releases/download/v0.7.4/ChatGPT_0.7.4_x64.dmg)
|
||||
- `Linux`: [chat-gpt_0.7.4_amd64.deb](https://github.com/lencx/ChatGPT/releases/download/v0.7.4/chat-gpt_0.7.4_amd64.deb)
|
||||
- `Windows`: [ChatGPT_0.7.4_x64_en-US.msi](https://github.com/lencx/ChatGPT/releases/download/v0.7.4/ChatGPT_0.7.4_x64_en-US.msi)
|
||||
- [ChatGPT_0.8.0_x64_en-US.msi](https://github.com/lencx/ChatGPT/releases/download/v0.8.0/ChatGPT_0.8.0_x64_en-US.msi): Direct download installer
|
||||
- Use [winget](https://winstall.app/apps/lencx.ChatGPT):
|
||||
```bash
|
||||
# install the latest version
|
||||
winget install --id=lencx.ChatGPT -e
|
||||
|
||||
[Other version...](https://github.com/lencx/ChatGPT/releases)
|
||||
# install the specified version
|
||||
winget install --id=lencx.ChatGPT -e --version 0.8.0
|
||||
```
|
||||
|
||||
**Note: If the installation path and application name are the same, it will lead to conflict ([#142](https://github.com/lencx/ChatGPT/issues/142#issuecomment-0.8.0))**
|
||||
|
||||
### Mac
|
||||
|
||||
- [ChatGPT_0.8.0_x64.dmg](https://github.com/lencx/ChatGPT/releases/download/v0.8.0/ChatGPT_0.8.0_x64.dmg): Direct download installer
|
||||
- [ChatGPT.app.tar.gz](https://github.com/lencx/ChatGPT/releases/download/v0.8.0/ChatGPT.app.tar.gz): Download the `.app` installer
|
||||
- Homebrew \
|
||||
Or you can install with _[Homebrew](https://brew.sh) ([Cask](https://docs.brew.sh/Cask-Cookbook)):_
|
||||
```sh
|
||||
brew tap lencx/chatgpt https://github.com/lencx/ChatGPT.git
|
||||
brew install --cask chatgpt --no-quarantine
|
||||
```
|
||||
Also, if you keep a _[Brewfile](https://github.com/Homebrew/homebrew-bundle#usage)_, you can add something like this:
|
||||
```rb
|
||||
repo = "lencx/chatgpt"
|
||||
tap repo, "https://github.com/#{repo}.git"
|
||||
cask "chatgpt", args: { "no-quarantine": true }
|
||||
```
|
||||
|
||||
### Linux
|
||||
|
||||
- [chat-gpt_0.8.0_amd64.deb](https://github.com/lencx/ChatGPT/releases/download/v0.8.0/chat-gpt_0.8.0_amd64.deb): Download `.deb` installer, advantage small size, disadvantage poor compatibility
|
||||
- [chat-gpt_0.8.0_amd64.AppImage](https://github.com/lencx/ChatGPT/releases/download/v0.8.0/chat-gpt_0.8.0_amd64.AppImage): Works reliably, you can try it if `.deb` fails to run
|
||||
- Available on [AUR](https://aur.archlinux.org/packages/chatgpt-desktop-bin) with the package name `chatgpt-desktop-bin`, and you can use your favourite AUR package manager to install it.
|
||||
|
||||
<!-- download end -->
|
||||
|
||||
### Install
|
||||
|
||||
Easily install with _[Homebrew](https://brew.sh) ([Cask](https://docs.brew.sh/Cask-Cookbook)):_
|
||||
|
||||
```sh
|
||||
brew tap lencx/chatgpt https://github.com/lencx/ChatGPT.git
|
||||
brew install --cask chatgpt --no-quarantine
|
||||
```
|
||||
|
||||
Also, if you keep a _[Brewfile](https://github.com/Homebrew/homebrew-bundle#usage)_, you can add something like this:
|
||||
|
||||
```rb
|
||||
repo = "lencx/chatgpt"
|
||||
tap repo, "https://github.com/#{repo}.git"
|
||||
cask "chatgpt", args: { "no-quarantine": true }
|
||||
```
|
||||
|
||||
## 📢 Announcement
|
||||
|
||||
### ChatGPT Prompts!
|
||||
|
||||
This is a major and exciting update. It works like a `Telegram bot command` and helps you quickly populate custom models to make chatgpt work the way you want it to. This project has taken a lot of my spare time, so if it helps you, please help spread the word or star it would be a great encouragement to me. I hope I can keep updating it and adding more interesting features.
|
||||
|
||||
### How does it work?
|
||||
|
||||
You can look at [awesome-chatgpt-prompts](https://github.com/f/awesome-chatgpt-prompts) to find interesting features to import into the app.
|
||||
You can look at **[awesome-chatgpt-prompts](https://github.com/f/awesome-chatgpt-prompts)** to find interesting features to import into the app. You can also use `Sync Prompts` to sync all in one click, and if you don't want certain prompts to appear in your slash commands, you can disable them.
|
||||
|
||||

|
||||

|
||||

|
||||

|
||||
|
||||
<!-- After the data import is done, you can restart the app to make the configuration take effect (`Menu -> Preferences -> Restart ChatGPT`). -->
|
||||
|
||||
In the chatgpt text input area, type a character starting with `/` to bring up the command prompt, press the spacebar, and it will fill the input area with the text associated with the command by default (note: if it contains multiple command prompts, it will only select the first one as the fill, you can keep typing until the first prompted command is the one you want, then press the spacebar. Or use the mouse to click on one of the multiple commands). When the fill is complete, you simply press the Enter key. Under the slash command, use the tab key to modify the contents of the `{q}` tag (only single changes are supported [#54](https://github.com/lencx/ChatGPT/issues/54)). Use the keyboard `⇧` (arrow up) and `⇩` (arrow down) keys to select the slash command.
|
||||
- In the chatgpt text input area, type a character starting with `/` to bring up the command prompt, press the spacebar, and it will fill the input area with the text associated with the command by default (note: if it contains multiple command prompts, it will only select the first one as the fill, you can keep typing until the first prompted command is the one you want, then press the spacebar.
|
||||
- Or use the mouse to click on one of the multiple commands). When the fill is complete, you simply press the Enter key.
|
||||
- Under the slash command, use the tab key to modify the contents of the `{q}` tag (only single changes are supported [#54](https://github.com/lencx/ChatGPT/issues/54)). Use the keyboard `⇧` (arrow up) and `⇩` (arrow down) keys to select the slash command.
|
||||
|
||||

|
||||

|
||||
@@ -77,11 +93,12 @@ In the chatgpt text input area, type a character starting with `/` to bring up t
|
||||
- Powerful menu items
|
||||
- Support for slash commands and their configuration (can be configured manually or synchronized from a file [#55](https://github.com/lencx/ChatGPT/issues/55))
|
||||
- Customize global shortcuts ([#108](https://github.com/lencx/ChatGPT/issues/108))
|
||||
- Pop-up Search ([#122](https://github.com/lencx/ChatGPT/issues/122) mouse selected content, no more than 400 characters): The application is built using Tauri, and due to its security restrictions, some of the action buttons will not work, so we recommend going to your browser.
|
||||
|
||||
### MenuItem
|
||||
## #️⃣ MenuItem
|
||||
|
||||
- **Preferences**
|
||||
- `Theme` - `Light`, `Dark` (Only macOS and Windows are supported).
|
||||
- `Theme` - `Light`, `Dark`, `System` (Only macOS and Windows are supported).
|
||||
- `Stay On Top`: The window is stay on top of other windows.
|
||||
- `Titlebar`: Whether to display the titlebar, supported by macOS only.
|
||||
- `Hide Dock Icon` ([#35](https://github.com/lencx/ChatGPT/issues/35)): Hide application icons from the Dock(support macOS only).
|
||||
@@ -102,7 +119,7 @@ In the chatgpt text input area, type a character starting with `/` to bring up t
|
||||
- `Report Bug`: Report a bug or give feedback.
|
||||
- `Toggle Developer Tools`: Developer debugging tools.
|
||||
|
||||
## Application Configuration
|
||||
## ⚙️ Application Configuration
|
||||
|
||||
| Platform | Path |
|
||||
| -------- | ------------------------- |
|
||||
@@ -128,7 +145,7 @@ In the chatgpt text input area, type a character starting with `/` to bring up t
|
||||
|
||||
Currently, only json and csv are supported for synchronizing custom files, and the following formats need to be met, otherwise the application will be abnormal:
|
||||
|
||||
> JSON format:
|
||||
`JSON format:`
|
||||
|
||||
```json
|
||||
[
|
||||
@@ -145,7 +162,7 @@ Currently, only json and csv are supported for synchronizing custom files, and t
|
||||
]
|
||||
```
|
||||
|
||||
> CSV format
|
||||
`CSV format`
|
||||
|
||||
```csv
|
||||
"cmd","act","prompt"
|
||||
@@ -153,21 +170,18 @@ Currently, only json and csv are supported for synchronizing custom files, and t
|
||||
"b","bb","bbb bbb bbb"
|
||||
```
|
||||
|
||||
## TODO
|
||||
## 📌 TODO
|
||||
|
||||
<!-- - Web access capability ([#20](https://github.com/lencx/ChatGPT/issues/20)) -->
|
||||
- `Control Center` - Feature Enhancements
|
||||
- `Control Center` enhancement
|
||||
- `Pop-up Search` enhancement
|
||||
- ...
|
||||
|
||||
## 👀 Preview
|
||||
|
||||
<img width="320" src="./assets/install.png" alt="install"> <img width="320" src="./assets/control-center.png" alt="control center">
|
||||
<img width="320" src="./assets/export.png" alt="export"> <img width="320" src="./assets/tray.png" alt="tray">
|
||||
<img width="320" src="./assets/tray-login.png" alt="tray login"> <img width="320" src="./assets/auto-update.png" alt="auto update">
|
||||
|
||||
---
|
||||
|
||||
<a href="https://www.buymeacoffee.com/lencx" target="_blank"><img src="https://cdn.buymeacoffee.com/buttons/v2/default-blue.png" alt="Buy Me A Coffee" style="height: 60px !important;width: 217px !important;" ></a>
|
||||
<img width="320" src="./assets/install.png" alt="install"> <img width="320" src="./assets/chatgpt-popup-search.png" alt="popup search">
|
||||
<img width="320" src="./assets/chatgpt-control-center-general.png" alt="control center"> <img width="320" src="./assets/chatgpt-export.png" alt="export">
|
||||
<img width="320" src="./assets/chatgpt-dalle2-tray.png" alt="dalle2 tray"> <img width="320" src="./assets/auto-update.png" alt="auto update">
|
||||
|
||||
## ❓FAQ
|
||||
|
||||
@@ -187,6 +201,8 @@ It's safe, just a wrapper for [OpenAI ChatGPT](https://chat.openai.com) website,
|
||||
|
||||
- [Open a Mac app from an unidentified developer](https://support.apple.com/en-sg/guide/mac-help/mh40616/mac)
|
||||
|
||||
---
|
||||
|
||||
### How do i build it?
|
||||
|
||||
#### PreInstall
|
||||
@@ -223,7 +239,7 @@ yarn build
|
||||
|
||||
---
|
||||
|
||||
[](https://star-history.com/#lencx/chatgpt&Date)
|
||||
[](https://star-history.com/#lencx/chatgpt&Timeline)
|
||||
|
||||
## 中国用户
|
||||
|
||||
|
||||
@@ -1,5 +1,15 @@
|
||||
# UPDATE LOG
|
||||
|
||||
## v0.8.0
|
||||
|
||||
feat:
|
||||
- theme enhancement (Light, Dark, System)
|
||||
- automatic updates support `silent` settings
|
||||
- pop-up search: select the ChatGPT content with the mouse, the `DALL·E 2` button appears, and click to jump (note: because the search content filled by the script cannot trigger the event directly, you need to enter a space in the input box to make the button clickable).
|
||||
|
||||
fix:
|
||||
- close the main window and hide it in the tray (windows systems)
|
||||
|
||||
## v0.7.4
|
||||
|
||||
fix:
|
||||
|
||||
|
Before Width: | Height: | Size: 1.9 MiB |
|
Before Width: | Height: | Size: 1.1 MiB |
BIN
assets/chatgpt-control-center-general.png
Normal file
|
After Width: | Height: | Size: 426 KiB |
BIN
assets/chatgpt-dalle2-tray.png
Normal file
|
After Width: | Height: | Size: 808 KiB |
BIN
assets/chatgpt-export.png
Normal file
|
After Width: | Height: | Size: 241 KiB |
BIN
assets/chatgpt-menu.png
Normal file
|
After Width: | Height: | Size: 742 KiB |
BIN
assets/chatgpt-popup-search.png
Normal file
|
After Width: | Height: | Size: 580 KiB |
BIN
assets/chatgpt-sync-prompts.png
Normal file
|
After Width: | Height: | Size: 406 KiB |
|
Before Width: | Height: | Size: 500 KiB |
|
Before Width: | Height: | Size: 226 KiB |
|
Before Width: | Height: | Size: 989 KiB |
BIN
assets/tray.png
|
Before Width: | Height: | Size: 543 KiB |
@@ -8,6 +8,7 @@
|
||||
"build": "yarn tauri build",
|
||||
"updater": "tr updater",
|
||||
"release": "tr release --git",
|
||||
"fix:conf": "tr override --json.tauri_updater_active=false",
|
||||
"fix:tray": "tr override --json.tauri_systemTray_iconPath=\"icons/tray-icon-light.png\" --json.tauri_systemTray_iconAsTemplate=false",
|
||||
"fix:tray:mac": "tr override --json.tauri_systemTray_iconPath=\"icons/tray-icon.png\" --json.tauri_systemTray_iconAsTemplate=true",
|
||||
"download": "node ./scripts/download.js",
|
||||
|
||||
@@ -27,11 +27,14 @@ regex = "1.7.0"
|
||||
tokio = { version = "1.23.0", features = ["macros"] }
|
||||
reqwest = "0.11.13"
|
||||
wry = "0.23.4"
|
||||
|
||||
dark-light = "1.0.0"
|
||||
[dependencies.tauri-plugin-log]
|
||||
git = "https://github.com/tauri-apps/tauri-plugin-log"
|
||||
git = "https://github.com/lencx/tauri-plugin-log"
|
||||
branch = "dev"
|
||||
features = ["colored"]
|
||||
[dependencies.tauri-plugin-autostart]
|
||||
git = "https://github.com/lencx/tauri-plugin-autostart"
|
||||
branch = "dev"
|
||||
|
||||
[features]
|
||||
# by default Tauri runs in production mode
|
||||
|
||||
@@ -1,16 +1,28 @@
|
||||
use crate::{
|
||||
app::window,
|
||||
conf::{ChatConfJson, GITHUB_PROMPTS_CSV_URL},
|
||||
utils::{self, exists},
|
||||
utils,
|
||||
};
|
||||
use log::info;
|
||||
use std::{collections::HashMap, fs, path::PathBuf};
|
||||
use tauri::{api, command, AppHandle, Manager};
|
||||
use tauri::{api, command, AppHandle, Manager, Theme};
|
||||
use walkdir::WalkDir;
|
||||
|
||||
#[command]
|
||||
pub fn drag_window(app: AppHandle) {
|
||||
app.get_window("core").unwrap().start_dragging().unwrap();
|
||||
}
|
||||
|
||||
#[command]
|
||||
pub fn dalle2_window(app: AppHandle, query: String) {
|
||||
window::dalle2_window(
|
||||
&app.app_handle(),
|
||||
Some(query),
|
||||
Some("ChatGPT & DALL·E 2".to_string()),
|
||||
None,
|
||||
);
|
||||
}
|
||||
|
||||
#[command]
|
||||
pub fn fullscreen(app: AppHandle) {
|
||||
let win = app.get_window("core").unwrap();
|
||||
@@ -38,6 +50,21 @@ pub fn get_chat_conf() -> ChatConfJson {
|
||||
ChatConfJson::get_chat_conf()
|
||||
}
|
||||
|
||||
#[command]
|
||||
pub fn get_theme() -> String {
|
||||
ChatConfJson::theme().unwrap_or(Theme::Light).to_string()
|
||||
}
|
||||
|
||||
#[command]
|
||||
pub fn reset_chat_conf() -> ChatConfJson {
|
||||
ChatConfJson::reset_chat_conf()
|
||||
}
|
||||
|
||||
#[command]
|
||||
pub fn run_check_update(app: AppHandle, silent: bool, has_msg: Option<bool>) {
|
||||
utils::run_check_update(app, silent, has_msg);
|
||||
}
|
||||
|
||||
#[command]
|
||||
pub fn form_confirm(_app: AppHandle, data: serde_json::Value) {
|
||||
ChatConfJson::amend(&serde_json::json!(data), None).unwrap();
|
||||
@@ -112,9 +139,6 @@ pub fn window_reload(app: AppHandle, label: &str) {
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
use utils::chat_root;
|
||||
use walkdir::WalkDir;
|
||||
|
||||
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
|
||||
pub struct ModelRecord {
|
||||
pub cmd: String,
|
||||
@@ -127,7 +151,7 @@ pub struct ModelRecord {
|
||||
#[command]
|
||||
pub fn cmd_list() -> Vec<ModelRecord> {
|
||||
let mut list = vec![];
|
||||
for entry in WalkDir::new(chat_root().join("cache_model"))
|
||||
for entry in WalkDir::new(utils::chat_root().join("cache_model"))
|
||||
.into_iter()
|
||||
.filter_map(|e| e.ok())
|
||||
{
|
||||
@@ -167,11 +191,13 @@ pub async fn sync_prompts(app: AppHandle, time: u64) -> Option<Vec<ModelRecord>>
|
||||
|
||||
let data2 = data.clone();
|
||||
|
||||
let model = chat_root().join("chat.model.json");
|
||||
let model_cmd = chat_root().join("chat.model.cmd.json");
|
||||
let chatgpt_prompts = chat_root().join("cache_model").join("chatgpt_prompts.json");
|
||||
let model = utils::chat_root().join("chat.model.json");
|
||||
let model_cmd = utils::chat_root().join("chat.model.cmd.json");
|
||||
let chatgpt_prompts = utils::chat_root()
|
||||
.join("cache_model")
|
||||
.join("chatgpt_prompts.json");
|
||||
|
||||
if !exists(&model) {
|
||||
if !utils::exists(&model) {
|
||||
fs::write(
|
||||
&model,
|
||||
serde_json::json!({
|
||||
@@ -221,7 +247,8 @@ pub async fn sync_prompts(app: AppHandle, time: u64) -> Option<Vec<ModelRecord>>
|
||||
"Sync Prompts",
|
||||
"ChatGPT Prompts data has been synchronized!",
|
||||
);
|
||||
window_reload(app, "core");
|
||||
window_reload(app.clone(), "core");
|
||||
window_reload(app, "tray");
|
||||
|
||||
return Some(data2);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use crate::{
|
||||
app::{cmd, window},
|
||||
conf::{self, ChatConfJson},
|
||||
utils,
|
||||
};
|
||||
@@ -11,8 +12,6 @@ use tauri_plugin_positioner::{on_tray_event, Position, WindowExt};
|
||||
#[cfg(target_os = "macos")]
|
||||
use tauri::AboutMetadata;
|
||||
|
||||
use super::window;
|
||||
|
||||
// --- Menu
|
||||
pub fn init() -> Menu {
|
||||
let chat_conf = ChatConfJson::get_chat_conf();
|
||||
@@ -24,6 +23,7 @@ pub fn init() -> Menu {
|
||||
MenuItem::About(name.into(), AboutMetadata::default()).into(),
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
CustomMenuItem::new("about".to_string(), "About ChatGPT").into(),
|
||||
CustomMenuItem::new("check_update".to_string(), "Check for Updates").into(),
|
||||
MenuItem::Services.into(),
|
||||
MenuItem::Hide.into(),
|
||||
MenuItem::HideOthers.into(),
|
||||
@@ -35,18 +35,33 @@ pub fn init() -> Menu {
|
||||
|
||||
let stay_on_top =
|
||||
CustomMenuItem::new("stay_on_top".to_string(), "Stay On Top").accelerator("CmdOrCtrl+T");
|
||||
#[cfg(target_os = "macos")]
|
||||
let titlebar =
|
||||
CustomMenuItem::new("titlebar".to_string(), "Titlebar").accelerator("CmdOrCtrl+B");
|
||||
let theme_light = CustomMenuItem::new("theme_light".to_string(), "Light");
|
||||
let theme_dark = CustomMenuItem::new("theme_dark".to_string(), "Dark");
|
||||
let is_dark = chat_conf.theme == "Dark";
|
||||
|
||||
let stay_on_top_menu = if chat_conf.stay_on_top {
|
||||
stay_on_top.selected()
|
||||
} else {
|
||||
stay_on_top
|
||||
};
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
let titlebar =
|
||||
CustomMenuItem::new("titlebar".to_string(), "Titlebar").accelerator("CmdOrCtrl+B");
|
||||
|
||||
let theme_light = CustomMenuItem::new("theme_light".to_string(), "Light");
|
||||
let theme_dark = CustomMenuItem::new("theme_dark".to_string(), "Dark");
|
||||
let theme_system = CustomMenuItem::new("theme_system".to_string(), "System");
|
||||
let is_dark = chat_conf.theme == "Dark";
|
||||
let is_system = chat_conf.theme == "System";
|
||||
|
||||
let update_prompt = CustomMenuItem::new("update_prompt".to_string(), "Prompt");
|
||||
let update_silent = CustomMenuItem::new("update_silent".to_string(), "Silent");
|
||||
let _update_disable = CustomMenuItem::new("update_disable".to_string(), "Disable");
|
||||
|
||||
let popup_search = CustomMenuItem::new("popup_search".to_string(), "Pop-up Search");
|
||||
let popup_search_menu = if chat_conf.popup_search {
|
||||
popup_search.selected()
|
||||
} else {
|
||||
popup_search
|
||||
};
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
let titlebar_menu = if chat_conf.titlebar {
|
||||
titlebar.selected()
|
||||
@@ -61,21 +76,6 @@ pub fn init() -> Menu {
|
||||
.accelerator("CmdOrCtrl+Shift+P")
|
||||
.into(),
|
||||
MenuItem::Separator.into(),
|
||||
Submenu::new(
|
||||
"Theme",
|
||||
Menu::new()
|
||||
.add_item(if is_dark {
|
||||
theme_light
|
||||
} else {
|
||||
theme_light.selected()
|
||||
})
|
||||
.add_item(if is_dark {
|
||||
theme_dark.selected()
|
||||
} else {
|
||||
theme_dark
|
||||
}),
|
||||
)
|
||||
.into(),
|
||||
stay_on_top_menu.into(),
|
||||
#[cfg(target_os = "macos")]
|
||||
titlebar_menu.into(),
|
||||
@@ -85,6 +85,47 @@ pub fn init() -> Menu {
|
||||
.accelerator("CmdOrCtrl+J")
|
||||
.into(),
|
||||
MenuItem::Separator.into(),
|
||||
Submenu::new(
|
||||
"Theme",
|
||||
Menu::new()
|
||||
.add_item(if is_dark || is_system {
|
||||
theme_light
|
||||
} else {
|
||||
theme_light.selected()
|
||||
})
|
||||
.add_item(if is_dark {
|
||||
theme_dark.selected()
|
||||
} else {
|
||||
theme_dark
|
||||
})
|
||||
.add_item(if is_system {
|
||||
theme_system.selected()
|
||||
} else {
|
||||
theme_system
|
||||
}),
|
||||
)
|
||||
.into(),
|
||||
Submenu::new(
|
||||
"Auto Update",
|
||||
Menu::new()
|
||||
.add_item(if chat_conf.auto_update == "Prompt" {
|
||||
update_prompt.selected()
|
||||
} else {
|
||||
update_prompt
|
||||
})
|
||||
.add_item(if chat_conf.auto_update == "Silent" {
|
||||
update_silent.selected()
|
||||
} else {
|
||||
update_silent
|
||||
}), // .add_item(if chat_conf.auto_update == "Disable" {
|
||||
// update_disable.selected()
|
||||
// } else {
|
||||
// update_disable
|
||||
// })
|
||||
)
|
||||
.into(),
|
||||
MenuItem::Separator.into(),
|
||||
popup_search_menu.into(),
|
||||
CustomMenuItem::new("sync_prompts".to_string(), "Sync Prompts").into(),
|
||||
MenuItem::Separator.into(),
|
||||
CustomMenuItem::new("go_conf".to_string(), "Go to Config")
|
||||
@@ -143,6 +184,8 @@ pub fn init() -> Menu {
|
||||
let window_menu = Submenu::new(
|
||||
"Window",
|
||||
Menu::new()
|
||||
.add_item(CustomMenuItem::new("dalle2".to_string(), "DALL·E 2"))
|
||||
.add_native_item(MenuItem::Separator)
|
||||
.add_native_item(MenuItem::Minimize)
|
||||
.add_native_item(MenuItem::Zoom),
|
||||
);
|
||||
@@ -165,9 +208,9 @@ pub fn init() -> Menu {
|
||||
Menu::new()
|
||||
.add_submenu(app_menu)
|
||||
.add_submenu(preferences_menu)
|
||||
.add_submenu(window_menu)
|
||||
.add_submenu(edit_menu)
|
||||
.add_submenu(view_menu)
|
||||
.add_submenu(window_menu)
|
||||
.add_submenu(help_menu)
|
||||
}
|
||||
|
||||
@@ -175,12 +218,9 @@ pub fn init() -> Menu {
|
||||
pub fn menu_handler(event: WindowMenuEvent<tauri::Wry>) {
|
||||
let win = Some(event.window()).unwrap();
|
||||
let app = win.app_handle();
|
||||
let state: tauri::State<conf::ChatState> = app.state();
|
||||
let script_path = utils::script_path().to_string_lossy().to_string();
|
||||
let menu_id = event.menu_item_id();
|
||||
|
||||
let core_window = app.get_window("core").unwrap();
|
||||
let menu_handle = core_window.menu_handle();
|
||||
let menu_handle = win.menu_handle();
|
||||
|
||||
match menu_id {
|
||||
// App
|
||||
@@ -192,6 +232,9 @@ pub fn menu_handler(event: WindowMenuEvent<tauri::Wry>) {
|
||||
format!("Version {}", tauri_conf.package.version.unwrap()),
|
||||
);
|
||||
}
|
||||
"check_update" => {
|
||||
utils::run_check_update(app, false, None);
|
||||
}
|
||||
// Preferences
|
||||
"control_center" => window::control_window(&app),
|
||||
"restart" => tauri::api::process::restart(&app.env()),
|
||||
@@ -199,6 +242,18 @@ pub fn menu_handler(event: WindowMenuEvent<tauri::Wry>) {
|
||||
"go_conf" => utils::open_file(utils::chat_root()),
|
||||
"clear_conf" => utils::clear_conf(&app),
|
||||
"awesome" => open(&app, conf::AWESOME_URL.to_string()),
|
||||
"popup_search" => {
|
||||
let chat_conf = conf::ChatConfJson::get_chat_conf();
|
||||
let popup_search = !chat_conf.popup_search;
|
||||
menu_handle
|
||||
.get_item(menu_id)
|
||||
.set_selected(popup_search)
|
||||
.unwrap();
|
||||
ChatConfJson::amend(&serde_json::json!({ "popup_search": popup_search }), None)
|
||||
.unwrap();
|
||||
cmd::window_reload(app.clone(), "core");
|
||||
cmd::window_reload(app, "tray");
|
||||
}
|
||||
"sync_prompts" => {
|
||||
tauri::api::dialog::ask(
|
||||
app.get_window("core").as_ref(),
|
||||
@@ -226,28 +281,61 @@ pub fn menu_handler(event: WindowMenuEvent<tauri::Wry>) {
|
||||
.unwrap();
|
||||
tauri::api::process::restart(&app.env());
|
||||
}
|
||||
"theme_light" | "theme_dark" => {
|
||||
let theme = if menu_id == "theme_dark" {
|
||||
"Dark"
|
||||
} else {
|
||||
"Light"
|
||||
"theme_light" | "theme_dark" | "theme_system" => {
|
||||
let theme = match menu_id {
|
||||
"theme_dark" => "Dark",
|
||||
"theme_system" => "System",
|
||||
_ => "Light",
|
||||
};
|
||||
ChatConfJson::amend(&serde_json::json!({ "theme": theme }), Some(app)).unwrap();
|
||||
}
|
||||
"update_prompt" | "update_silent" | "update_disable" => {
|
||||
// for id in ["update_prompt", "update_silent", "update_disable"] {
|
||||
for id in ["update_prompt", "update_silent"] {
|
||||
menu_handle.get_item(id).set_selected(false).unwrap();
|
||||
}
|
||||
let auto_update = match menu_id {
|
||||
"update_silent" => {
|
||||
menu_handle
|
||||
.get_item("update_silent")
|
||||
.set_selected(true)
|
||||
.unwrap();
|
||||
"Silent"
|
||||
}
|
||||
"update_disable" => {
|
||||
menu_handle
|
||||
.get_item("update_disable")
|
||||
.set_selected(true)
|
||||
.unwrap();
|
||||
"Disable"
|
||||
}
|
||||
_ => {
|
||||
menu_handle
|
||||
.get_item("update_prompt")
|
||||
.set_selected(true)
|
||||
.unwrap();
|
||||
"Prompt"
|
||||
}
|
||||
};
|
||||
ChatConfJson::amend(&serde_json::json!({ "auto_update": auto_update }), None).unwrap();
|
||||
}
|
||||
"stay_on_top" => {
|
||||
let mut stay_on_top = state.stay_on_top.lock().unwrap();
|
||||
*stay_on_top = !*stay_on_top;
|
||||
let chat_conf = conf::ChatConfJson::get_chat_conf();
|
||||
let stay_on_top = !chat_conf.stay_on_top;
|
||||
menu_handle
|
||||
.get_item(menu_id)
|
||||
.set_selected(*stay_on_top)
|
||||
.set_selected(stay_on_top)
|
||||
.unwrap();
|
||||
win.set_always_on_top(*stay_on_top).unwrap();
|
||||
ChatConfJson::amend(&serde_json::json!({ "stay_on_top": *stay_on_top }), None).unwrap();
|
||||
win.set_always_on_top(stay_on_top).unwrap();
|
||||
ChatConfJson::amend(&serde_json::json!({ "stay_on_top": stay_on_top }), None).unwrap();
|
||||
}
|
||||
// Window
|
||||
"dalle2" => window::dalle2_window(&app, None, None, Some(false)),
|
||||
// View
|
||||
"reload" => win.eval("window.location.reload()").unwrap(),
|
||||
"go_back" => win.eval("window.history.go(-1)").unwrap(),
|
||||
"go_forward" => win.eval("window.history.go(1)").unwrap(),
|
||||
// core: document.querySelector('main .overflow-y-auto')
|
||||
"scroll_top" => win
|
||||
.eval(
|
||||
r#"window.scroll({
|
||||
@@ -280,12 +368,13 @@ pub fn menu_handler(event: WindowMenuEvent<tauri::Wry>) {
|
||||
// --- SystemTray Menu
|
||||
pub fn tray_menu() -> SystemTray {
|
||||
if cfg!(target_os = "macos") {
|
||||
return SystemTray::new().with_menu(
|
||||
SystemTray::new().with_menu(
|
||||
SystemTrayMenu::new()
|
||||
.add_item(CustomMenuItem::new(
|
||||
"control_center".to_string(),
|
||||
"Control Center",
|
||||
))
|
||||
.add_native_item(SystemTrayMenuItem::Separator)
|
||||
.add_item(CustomMenuItem::new(
|
||||
"show_dock_icon".to_string(),
|
||||
"Show Dock Icon",
|
||||
@@ -294,20 +383,22 @@ pub fn tray_menu() -> SystemTray {
|
||||
"hide_dock_icon".to_string(),
|
||||
"Hide Dock Icon",
|
||||
))
|
||||
.add_item(CustomMenuItem::new("show_core".to_string(), "Show ChatGPT"))
|
||||
.add_native_item(SystemTrayMenuItem::Separator)
|
||||
.add_item(CustomMenuItem::new("quit".to_string(), "Quit ChatGPT")),
|
||||
);
|
||||
)
|
||||
} else {
|
||||
SystemTray::new().with_menu(
|
||||
SystemTrayMenu::new()
|
||||
.add_item(CustomMenuItem::new(
|
||||
"control_center".to_string(),
|
||||
"Control Center",
|
||||
))
|
||||
.add_item(CustomMenuItem::new("show_core".to_string(), "Show ChatGPT"))
|
||||
.add_native_item(SystemTrayMenuItem::Separator)
|
||||
.add_item(CustomMenuItem::new("quit".to_string(), "Quit ChatGPT")),
|
||||
)
|
||||
}
|
||||
|
||||
SystemTray::new().with_menu(
|
||||
SystemTrayMenu::new()
|
||||
.add_item(CustomMenuItem::new(
|
||||
"control_center".to_string(),
|
||||
"Control Center",
|
||||
))
|
||||
.add_native_item(SystemTrayMenuItem::Separator)
|
||||
.add_item(CustomMenuItem::new("quit".to_string(), "Quit ChatGPT")),
|
||||
)
|
||||
}
|
||||
|
||||
// --- SystemTray Event
|
||||
@@ -348,6 +439,15 @@ pub fn tray_handler(handle: &AppHandle, event: SystemTrayEvent) {
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
"show_core" => {
|
||||
let core_win = app.get_window("core").unwrap();
|
||||
let tray_win = app.get_window("tray").unwrap();
|
||||
if !core_win.is_visible().unwrap() {
|
||||
core_win.show().unwrap();
|
||||
core_win.set_focus().unwrap();
|
||||
tray_win.hide().unwrap();
|
||||
}
|
||||
}
|
||||
"quit" => std::process::exit(0),
|
||||
_ => (),
|
||||
},
|
||||
|
||||
@@ -10,7 +10,7 @@ pub fn init(app: &mut App) -> std::result::Result<(), Box<dyn std::error::Error>
|
||||
let theme = ChatConfJson::theme();
|
||||
let handle = app.app_handle();
|
||||
|
||||
tokio::spawn(async move {
|
||||
tauri::async_runtime::spawn(async move {
|
||||
window::tray_window(&handle);
|
||||
});
|
||||
|
||||
@@ -49,7 +49,7 @@ pub fn init(app: &mut App) -> std::result::Result<(), Box<dyn std::error::Error>
|
||||
app.set_activation_policy(tauri::ActivationPolicy::Accessory);
|
||||
} else {
|
||||
let app = app.handle();
|
||||
tokio::spawn(async move {
|
||||
tauri::async_runtime::spawn(async move {
|
||||
#[cfg(target_os = "macos")]
|
||||
WindowBuilder::new(&app, "core", WindowUrl::App(url.into()))
|
||||
.title("ChatGPT")
|
||||
@@ -61,9 +61,12 @@ pub fn init(app: &mut App) -> std::result::Result<(), Box<dyn std::error::Error>
|
||||
.always_on_top(chat_conf.stay_on_top)
|
||||
.title_bar_style(ChatConfJson::titlebar())
|
||||
.initialization_script(&utils::user_script())
|
||||
.initialization_script(include_str!("../assets/html2canvas.js"))
|
||||
.initialization_script(include_str!("../assets/jspdf.js"))
|
||||
.initialization_script(include_str!("../vendors/floating-ui-core.js"))
|
||||
.initialization_script(include_str!("../vendors/floating-ui-dom.js"))
|
||||
.initialization_script(include_str!("../vendors/html2canvas.js"))
|
||||
.initialization_script(include_str!("../vendors/jspdf.js"))
|
||||
.initialization_script(include_str!("../assets/core.js"))
|
||||
.initialization_script(include_str!("../assets/popup.core.js"))
|
||||
.initialization_script(include_str!("../assets/export.js"))
|
||||
.initialization_script(include_str!("../assets/cmd.js"))
|
||||
.user_agent(&chat_conf.ua_window)
|
||||
@@ -79,9 +82,12 @@ pub fn init(app: &mut App) -> std::result::Result<(), Box<dyn std::error::Error>
|
||||
.theme(theme)
|
||||
.always_on_top(chat_conf.stay_on_top)
|
||||
.initialization_script(&utils::user_script())
|
||||
.initialization_script(include_str!("../assets/html2canvas.js"))
|
||||
.initialization_script(include_str!("../assets/jspdf.js"))
|
||||
.initialization_script(include_str!("../vendors/floating-ui-core.js"))
|
||||
.initialization_script(include_str!("../vendors/floating-ui-dom.js"))
|
||||
.initialization_script(include_str!("../vendors/html2canvas.js"))
|
||||
.initialization_script(include_str!("../vendors/jspdf.js"))
|
||||
.initialization_script(include_str!("../assets/core.js"))
|
||||
.initialization_script(include_str!("../assets/popup.core.js"))
|
||||
.initialization_script(include_str!("../assets/export.js"))
|
||||
.initialization_script(include_str!("../assets/cmd.js"))
|
||||
.user_agent(&chat_conf.ua_window)
|
||||
@@ -90,5 +96,12 @@ pub fn init(app: &mut App) -> std::result::Result<(), Box<dyn std::error::Error>
|
||||
});
|
||||
}
|
||||
|
||||
// auto_update
|
||||
if chat_conf.auto_update != "Disable" {
|
||||
info!("stepup::run_check_update");
|
||||
let app = app.handle();
|
||||
utils::run_check_update(app, chat_conf.auto_update == "Silent", None);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
use crate::{conf, utils};
|
||||
use tauri::{utils::config::WindowUrl, window::WindowBuilder};
|
||||
use log::info;
|
||||
use std::time::SystemTime;
|
||||
use tauri::{utils::config::WindowUrl, window::WindowBuilder, Manager};
|
||||
|
||||
pub fn tray_window(handle: &tauri::AppHandle) {
|
||||
let chat_conf = conf::ChatConfJson::get_chat_conf();
|
||||
let theme = conf::ChatConfJson::theme();
|
||||
let app = handle.clone();
|
||||
|
||||
tokio::spawn(async move {
|
||||
tauri::async_runtime::spawn(async move {
|
||||
WindowBuilder::new(&app, "tray", WindowUrl::App(chat_conf.origin.into()))
|
||||
.title("ChatGPT")
|
||||
.resizable(false)
|
||||
@@ -16,8 +18,11 @@ pub fn tray_window(handle: &tauri::AppHandle) {
|
||||
.always_on_top(true)
|
||||
.theme(theme)
|
||||
.initialization_script(&utils::user_script())
|
||||
.initialization_script(include_str!("../vendors/floating-ui-core.js"))
|
||||
.initialization_script(include_str!("../vendors/floating-ui-dom.js"))
|
||||
.initialization_script(include_str!("../assets/core.js"))
|
||||
.initialization_script(include_str!("../assets/cmd.js"))
|
||||
.initialization_script(include_str!("../assets/popup.core.js"))
|
||||
.user_agent(&chat_conf.ua_tray)
|
||||
.build()
|
||||
.unwrap()
|
||||
@@ -26,16 +31,77 @@ pub fn tray_window(handle: &tauri::AppHandle) {
|
||||
});
|
||||
}
|
||||
|
||||
pub fn control_window(handle: &tauri::AppHandle) {
|
||||
pub fn dalle2_window(
|
||||
handle: &tauri::AppHandle,
|
||||
query: Option<String>,
|
||||
title: Option<String>,
|
||||
is_new: Option<bool>,
|
||||
) {
|
||||
info!("dalle2_query: {:?}", query);
|
||||
let theme = conf::ChatConfJson::theme();
|
||||
let app = handle.clone();
|
||||
tokio::spawn(async move {
|
||||
WindowBuilder::new(&app, "main", WindowUrl::App("index.html".into()))
|
||||
.title("Control Center")
|
||||
|
||||
let query = if query.is_some() {
|
||||
format!(
|
||||
"window.addEventListener('DOMContentLoaded', function() {{\nwindow.__CHATGPT_QUERY__='{}';\n}})",
|
||||
query.unwrap()
|
||||
)
|
||||
} else {
|
||||
"".to_string()
|
||||
};
|
||||
|
||||
let label = if is_new.unwrap_or(true) {
|
||||
let timestamp = SystemTime::now()
|
||||
.duration_since(SystemTime::UNIX_EPOCH)
|
||||
.unwrap()
|
||||
.as_secs();
|
||||
format!("dalle2_{}", timestamp)
|
||||
} else {
|
||||
"dalle2".to_string()
|
||||
};
|
||||
|
||||
if app.get_window("dalle2").is_none() {
|
||||
tauri::async_runtime::spawn(async move {
|
||||
WindowBuilder::new(
|
||||
&app,
|
||||
label,
|
||||
WindowUrl::App("https://labs.openai.com".into()),
|
||||
)
|
||||
.title(title.unwrap_or_else(|| "DALL·E 2".to_string()))
|
||||
.resizable(true)
|
||||
.fullscreen(false)
|
||||
.inner_size(800.0, 600.0)
|
||||
.min_inner_size(800.0, 600.0)
|
||||
.always_on_top(false)
|
||||
.theme(theme)
|
||||
.initialization_script(include_str!("../assets/core.js"))
|
||||
.initialization_script(&query)
|
||||
.initialization_script(include_str!("../assets/dalle2.js"))
|
||||
.build()
|
||||
.unwrap();
|
||||
});
|
||||
} else {
|
||||
let dalle2_win = app.get_window("dalle2").unwrap();
|
||||
dalle2_win.show().unwrap();
|
||||
dalle2_win.set_focus().unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn control_window(handle: &tauri::AppHandle) {
|
||||
let app = handle.clone();
|
||||
tauri::async_runtime::spawn(async move {
|
||||
if app.app_handle().get_window("main").is_none() {
|
||||
WindowBuilder::new(&app, "main", WindowUrl::App("index.html".into()))
|
||||
.title("Control Center")
|
||||
.resizable(true)
|
||||
.fullscreen(false)
|
||||
.inner_size(800.0, 600.0)
|
||||
.min_inner_size(800.0, 600.0)
|
||||
.build()
|
||||
.unwrap();
|
||||
} else {
|
||||
let main_win = app.app_handle().get_window("main").unwrap();
|
||||
main_win.show().unwrap();
|
||||
main_win.set_focus().unwrap();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
5
src-tauri/src/assets/cmd.js
vendored
@@ -75,6 +75,11 @@ function init() {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
}
|
||||
@media screen and (max-width: 767px) {
|
||||
#download-png-button, #download-pdf-button, #download-html-button {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
`;
|
||||
document.head.append(styleDom);
|
||||
|
||||
|
||||
1
src-tauri/src/assets/core.js
vendored
@@ -71,6 +71,7 @@ async function init() {
|
||||
|
||||
document.addEventListener("click", (e) => {
|
||||
const origin = e.target.closest("a");
|
||||
if (!origin.target) return;
|
||||
if (origin && origin.href && origin.target !== '_self') {
|
||||
invoke('open_link', { url: origin.href });
|
||||
}
|
||||
|
||||
40
src-tauri/src/assets/dalle2.js
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
// *** Core Script - DALL·E 2 ***
|
||||
|
||||
async function init() {
|
||||
document.addEventListener("click", (e) => {
|
||||
const origin = e.target.closest("a");
|
||||
if (!origin.target) return;
|
||||
if (origin && origin.href && origin.target !== '_self') {
|
||||
if (/\/(login|signup)$/.test(window.location.href)) {
|
||||
origin.target = '_self';
|
||||
} else {
|
||||
invoke('open_link', { url: origin.href });
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (window.searchInterval) {
|
||||
clearInterval(window.searchInterval);
|
||||
}
|
||||
|
||||
window.searchInterval = setInterval(() => {
|
||||
const searchInput = document.querySelector('.image-prompt-form-wrapper form>.text-input');
|
||||
if (searchInput) {
|
||||
clearInterval(window.searchInterval);
|
||||
|
||||
if (!window.__CHATGPT_QUERY__) return;
|
||||
const query = decodeURIComponent(window.__CHATGPT_QUERY__);
|
||||
searchInput.focus();
|
||||
searchInput.value = query;
|
||||
}
|
||||
}, 200)
|
||||
}
|
||||
|
||||
if (
|
||||
document.readyState === "complete" ||
|
||||
document.readyState === "interactive"
|
||||
) {
|
||||
init();
|
||||
} else {
|
||||
document.addEventListener("DOMContentLoaded", init);
|
||||
}
|
||||
84
src-tauri/src/assets/popup.core.js
vendored
Normal file
@@ -0,0 +1,84 @@
|
||||
// *** Core Script - DALL·E 2 Core ***
|
||||
|
||||
async function init() {
|
||||
const chatConf = await invoke('get_chat_conf') || {};
|
||||
if (!chatConf.popup_search) return;
|
||||
if (!window.FloatingUIDOM) return;
|
||||
|
||||
const styleDom = document.createElement('style');
|
||||
styleDom.innerHTML = `
|
||||
#chagpt-selection-menu {
|
||||
display: none;
|
||||
width: max-content;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
background: #4a4a4a;
|
||||
color: white;
|
||||
font-weight: bold;
|
||||
padding: 5px 8px;
|
||||
border-radius: 4px;
|
||||
font-size: 12px;
|
||||
cursor: pointer;
|
||||
}
|
||||
`;
|
||||
document.head.append(styleDom);
|
||||
|
||||
const selectionMenu = document.createElement('div');
|
||||
selectionMenu.id = 'chagpt-selection-menu';
|
||||
selectionMenu.innerHTML = 'DALL·E 2';
|
||||
document.body.appendChild(selectionMenu);
|
||||
const { computePosition, flip, offset, shift } = window.FloatingUIDOM;
|
||||
|
||||
document.body.addEventListener('mousedown', async (e) => {
|
||||
if (e.target.id === 'chagpt-selection-menu') {
|
||||
await invoke('dalle2_window', { query: encodeURIComponent(window.__DALLE2_CONTENT__) });
|
||||
} else {
|
||||
delete window.__DALLE2_CONTENT__;
|
||||
}
|
||||
});
|
||||
|
||||
document.body.addEventListener("mouseup", async (e) => {
|
||||
selectionMenu.style.display = 'none';
|
||||
const selection = window.getSelection();
|
||||
window.__DALLE2_CONTENT__ = selection.toString().trim();
|
||||
|
||||
if (!window.__DALLE2_CONTENT__) return;
|
||||
|
||||
if (selection.rangeCount > 0) {
|
||||
const range = selection.getRangeAt(0);
|
||||
const rect = range.getClientRects()[0];
|
||||
|
||||
const rootEl = document.createElement('div');
|
||||
rootEl.style.top = `${rect.top}px`;
|
||||
rootEl.style.position = 'fixed';
|
||||
rootEl.style.left = `${rect.left}px`;
|
||||
document.body.appendChild(rootEl);
|
||||
|
||||
selectionMenu.style.display = 'block';
|
||||
computePosition(rootEl, selectionMenu, {
|
||||
placement: 'top',
|
||||
middleware: [
|
||||
flip(),
|
||||
offset(5),
|
||||
shift({ padding: 5 })
|
||||
]
|
||||
}).then(({x, y}) => {
|
||||
Object.assign(selectionMenu.style, {
|
||||
left: `${x}px`,
|
||||
top: `${y}px`,
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
if (
|
||||
document.readyState === "complete" ||
|
||||
document.readyState === "interactive"
|
||||
) {
|
||||
init();
|
||||
} else {
|
||||
document.addEventListener("DOMContentLoaded", init);
|
||||
}
|
||||
@@ -2,7 +2,7 @@ use crate::utils::{chat_root, create_file, exists};
|
||||
use anyhow::Result;
|
||||
use log::info;
|
||||
use serde_json::Value;
|
||||
use std::{collections::BTreeMap, fs, path::PathBuf, sync::Mutex};
|
||||
use std::{collections::BTreeMap, fs, path::PathBuf};
|
||||
use tauri::{Manager, Theme};
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
@@ -18,8 +18,10 @@ pub const GITHUB_PROMPTS_CSV_URL: &str =
|
||||
"https://raw.githubusercontent.com/f/awesome-chatgpt-prompts/main/prompts.csv";
|
||||
pub const DEFAULT_CHAT_CONF: &str = r#"{
|
||||
"stay_on_top": false,
|
||||
"auto_update": "Prompt",
|
||||
"theme": "Light",
|
||||
"titlebar": true,
|
||||
"popup_search": true,
|
||||
"global_shortcut": "",
|
||||
"hide_dock_icon": false,
|
||||
"default_origin": "https://chat.openai.com",
|
||||
@@ -29,8 +31,10 @@ pub const DEFAULT_CHAT_CONF: &str = r#"{
|
||||
}"#;
|
||||
pub const DEFAULT_CHAT_CONF_MAC: &str = r#"{
|
||||
"stay_on_top": false,
|
||||
"auto_update": "Prompt",
|
||||
"theme": "Light",
|
||||
"titlebar": false,
|
||||
"popup_search": true,
|
||||
"global_shortcut": "",
|
||||
"hide_dock_icon": false,
|
||||
"default_origin": "https://chat.openai.com",
|
||||
@@ -39,27 +43,17 @@ pub const DEFAULT_CHAT_CONF_MAC: &str = r#"{
|
||||
"ua_tray": ""
|
||||
}"#;
|
||||
|
||||
pub struct ChatState {
|
||||
pub stay_on_top: Mutex<bool>,
|
||||
}
|
||||
|
||||
impl ChatState {
|
||||
pub fn default(chat_conf: ChatConfJson) -> Self {
|
||||
ChatState {
|
||||
stay_on_top: Mutex::new(chat_conf.stay_on_top),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
|
||||
pub struct ChatConfJson {
|
||||
// support macOS only
|
||||
pub titlebar: bool,
|
||||
pub hide_dock_icon: bool,
|
||||
|
||||
// macOS and Windows
|
||||
// macOS and Windows, Light/Dark/System
|
||||
pub theme: String,
|
||||
|
||||
// auto update policy, Prompt/Silent/Disable
|
||||
pub auto_update: String,
|
||||
pub popup_search: bool,
|
||||
pub stay_on_top: bool,
|
||||
pub default_origin: String,
|
||||
pub origin: String,
|
||||
@@ -129,6 +123,17 @@ impl ChatConfJson {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn reset_chat_conf() -> Self {
|
||||
let conf_file = ChatConfJson::conf_path();
|
||||
let content = if cfg!(target_os = "macos") {
|
||||
DEFAULT_CHAT_CONF_MAC
|
||||
} else {
|
||||
DEFAULT_CHAT_CONF
|
||||
};
|
||||
fs::write(&conf_file, content).unwrap();
|
||||
serde_json::from_str(content).unwrap()
|
||||
}
|
||||
|
||||
// https://users.rust-lang.org/t/updating-object-fields-given-dynamic-json/39049/3
|
||||
pub fn amend(new_rules: &Value, app: Option<tauri::AppHandle>) -> Result<()> {
|
||||
let config = ChatConfJson::get_chat_conf();
|
||||
@@ -163,11 +168,20 @@ impl ChatConfJson {
|
||||
|
||||
pub fn theme() -> Option<Theme> {
|
||||
let conf = ChatConfJson::get_chat_conf();
|
||||
if conf.theme == "Dark" {
|
||||
Some(Theme::Dark)
|
||||
} else {
|
||||
Some(Theme::Light)
|
||||
}
|
||||
let theme = match conf.theme.as_str() {
|
||||
"System" => match dark_light::detect() {
|
||||
// Dark mode
|
||||
dark_light::Mode::Dark => Theme::Dark,
|
||||
// Light mode
|
||||
dark_light::Mode::Light => Theme::Light,
|
||||
// Unspecified
|
||||
dark_light::Mode::Default => Theme::Light,
|
||||
},
|
||||
"Dark" => Theme::Dark,
|
||||
_ => Theme::Light,
|
||||
};
|
||||
|
||||
Some(theme)
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
|
||||
@@ -8,8 +8,9 @@ mod conf;
|
||||
mod utils;
|
||||
|
||||
use app::{cmd, fs_extra, menu, setup};
|
||||
use conf::{ChatConfJson, ChatState};
|
||||
use conf::ChatConfJson;
|
||||
use tauri::api::path;
|
||||
use tauri_plugin_autostart::MacosLauncher;
|
||||
use tauri_plugin_log::{
|
||||
fern::colors::{Color, ColoredLevelConfig},
|
||||
LogTarget, LoggerBuilder,
|
||||
@@ -20,7 +21,6 @@ async fn main() {
|
||||
ChatConfJson::init();
|
||||
// If the file does not exist, creating the file will block menu synchronization
|
||||
utils::create_chatgpt_prompts();
|
||||
let chat_conf = ChatConfJson::get_chat_conf();
|
||||
let context = tauri::generate_context!();
|
||||
let colors = ColoredLevelConfig {
|
||||
error: Color::Red,
|
||||
@@ -34,11 +34,7 @@ async fn main() {
|
||||
// https://github.com/tauri-apps/tauri/pull/2736
|
||||
.plugin(
|
||||
LoggerBuilder::new()
|
||||
.level(if cfg!(debug_assertions) {
|
||||
log::LevelFilter::Debug
|
||||
} else {
|
||||
log::LevelFilter::Trace
|
||||
})
|
||||
.level(log::LevelFilter::Debug)
|
||||
.with_colors(colors)
|
||||
.targets([
|
||||
// LogTarget::LogDir,
|
||||
@@ -49,13 +45,15 @@ async fn main() {
|
||||
])
|
||||
.build(),
|
||||
)
|
||||
.manage(ChatState::default(chat_conf))
|
||||
.invoke_handler(tauri::generate_handler![
|
||||
cmd::drag_window,
|
||||
cmd::fullscreen,
|
||||
cmd::download,
|
||||
cmd::open_link,
|
||||
cmd::get_chat_conf,
|
||||
cmd::get_theme,
|
||||
cmd::reset_chat_conf,
|
||||
cmd::run_check_update,
|
||||
cmd::form_cancel,
|
||||
cmd::form_confirm,
|
||||
cmd::form_msg,
|
||||
@@ -65,11 +63,16 @@ async fn main() {
|
||||
cmd::sync_prompts,
|
||||
cmd::sync_user_prompts,
|
||||
cmd::window_reload,
|
||||
cmd::dalle2_window,
|
||||
cmd::cmd_list,
|
||||
fs_extra::metadata,
|
||||
])
|
||||
.setup(setup::init)
|
||||
.plugin(tauri_plugin_positioner::init())
|
||||
.plugin(tauri_plugin_autostart::init(
|
||||
MacosLauncher::LaunchAgent,
|
||||
None,
|
||||
))
|
||||
.menu(menu::init())
|
||||
.system_tray(menu::tray_menu())
|
||||
.on_menu_event(menu::menu_handler)
|
||||
@@ -78,13 +81,18 @@ async fn main() {
|
||||
// https://github.com/tauri-apps/tauri/discussions/2684
|
||||
if let tauri::WindowEvent::CloseRequested { api, .. } = event.event() {
|
||||
let win = event.window();
|
||||
if win.label() == "main" {
|
||||
win.close().unwrap();
|
||||
} else {
|
||||
if win.label() == "core" {
|
||||
// TODO: https://github.com/tauri-apps/tauri/issues/3084
|
||||
// event.window().hide().unwrap();
|
||||
// https://github.com/tauri-apps/tao/pull/517
|
||||
#[cfg(target_os = "macos")]
|
||||
event.window().minimize().unwrap();
|
||||
|
||||
// fix: https://github.com/lencx/ChatGPT/issues/93
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
event.window().hide().unwrap();
|
||||
} else {
|
||||
win.close().unwrap();
|
||||
}
|
||||
api.prevent_close();
|
||||
}
|
||||
|
||||
@@ -8,7 +8,8 @@ use std::{
|
||||
path::{Path, PathBuf},
|
||||
process::Command,
|
||||
};
|
||||
use tauri::{utils::config::Config, Manager};
|
||||
use tauri::updater::UpdateResponse;
|
||||
use tauri::{utils::config::Config, AppHandle, Manager, Wry};
|
||||
|
||||
pub fn chat_root() -> PathBuf {
|
||||
tauri::api::path::home_dir().unwrap().join(".chatgpt")
|
||||
@@ -128,3 +129,104 @@ pub async fn get_data(
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn run_check_update(app: AppHandle<Wry>, silent: bool, has_msg: Option<bool>) {
|
||||
info!("run_check_update: silent={} has_msg={:?}", silent, has_msg);
|
||||
tauri::async_runtime::spawn(async move {
|
||||
let result = app.updater().check().await;
|
||||
let update_resp = result.unwrap();
|
||||
if update_resp.is_update_available() {
|
||||
if silent {
|
||||
tauri::async_runtime::spawn(async move {
|
||||
silent_install(app, update_resp).await.unwrap();
|
||||
});
|
||||
} else {
|
||||
tauri::async_runtime::spawn(async move {
|
||||
prompt_for_install(app, update_resp).await.unwrap();
|
||||
});
|
||||
}
|
||||
} else if let Some(v) = has_msg {
|
||||
if v {
|
||||
tauri::api::dialog::message(
|
||||
app.app_handle().get_window("core").as_ref(),
|
||||
"ChatGPT",
|
||||
"Your ChatGPT is up to date",
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Copy private api in tauri/updater/mod.rs. TODO: refactor to public api
|
||||
// Prompt a dialog asking if the user want to install the new version
|
||||
// Maybe we should add an option to customize it in future versions.
|
||||
pub async fn prompt_for_install(app: AppHandle<Wry>, update: UpdateResponse<Wry>) -> Result<()> {
|
||||
info!("prompt_for_install");
|
||||
let windows = app.windows();
|
||||
let parent_window = windows.values().next();
|
||||
let package_info = app.package_info().clone();
|
||||
|
||||
let body = update.body().unwrap();
|
||||
// todo(lemarier): We should review this and make sure we have
|
||||
// something more conventional.
|
||||
let should_install = tauri::api::dialog::blocking::ask(
|
||||
parent_window,
|
||||
format!(r#"A new version of {} is available! "#, package_info.name),
|
||||
format!(
|
||||
r#"{} {} is now available -- you have {}.
|
||||
|
||||
Would you like to install it now?
|
||||
|
||||
Release Notes:
|
||||
{}"#,
|
||||
package_info.name,
|
||||
update.latest_version(),
|
||||
package_info.version,
|
||||
body
|
||||
),
|
||||
);
|
||||
|
||||
if should_install {
|
||||
// Launch updater download process
|
||||
// macOS we display the `Ready to restart dialog` asking to restart
|
||||
// Windows is closing the current App and launch the downloaded MSI when ready (the process stop here)
|
||||
// Linux we replace the AppImage by launching a new install, it start a new AppImage instance, so we're closing the previous. (the process stop here)
|
||||
update.download_and_install().await?;
|
||||
|
||||
// Ask user if we need to restart the application
|
||||
let should_exit = tauri::api::dialog::blocking::ask(
|
||||
parent_window,
|
||||
"Ready to Restart",
|
||||
"The installation was successful, do you want to restart the application now?",
|
||||
);
|
||||
if should_exit {
|
||||
app.restart();
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn silent_install(app: AppHandle<Wry>, update: UpdateResponse<Wry>) -> Result<()> {
|
||||
info!("silent_install");
|
||||
let windows = app.windows();
|
||||
let parent_window = windows.values().next();
|
||||
|
||||
// Launch updater download process
|
||||
// macOS we display the `Ready to restart dialog` asking to restart
|
||||
// Windows is closing the current App and launch the downloaded MSI when ready (the process stop here)
|
||||
// Linux we replace the AppImage by launching a new install, it start a new AppImage instance, so we're closing the previous. (the process stop here)
|
||||
update.download_and_install().await?;
|
||||
|
||||
// Ask user if we need to restart the application
|
||||
let should_exit = tauri::api::dialog::blocking::ask(
|
||||
parent_window,
|
||||
"Ready to Restart",
|
||||
"The silent installation was successful, do you want to restart the application now?",
|
||||
);
|
||||
if should_exit {
|
||||
app.restart();
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
1
src-tauri/src/vendors/floating-ui-core.js
vendored
Normal file
1
src-tauri/src/vendors/floating-ui-dom.js
vendored
Normal file
@@ -7,7 +7,7 @@
|
||||
},
|
||||
"package": {
|
||||
"productName": "ChatGPT",
|
||||
"version": "0.7.4"
|
||||
"version": "0.8.0"
|
||||
},
|
||||
"tauri": {
|
||||
"allowlist": {
|
||||
@@ -68,7 +68,7 @@
|
||||
},
|
||||
"updater": {
|
||||
"active": true,
|
||||
"dialog": true,
|
||||
"dialog": false,
|
||||
"endpoints": [
|
||||
"https://lencx.github.io/ChatGPT/install.json"
|
||||
],
|
||||
|
||||
1
src/hooks/useChatModel.ts
vendored
@@ -47,6 +47,7 @@ export function useCacheModel(file = '') {
|
||||
const list = await invoke('cmd_list');
|
||||
await writeJSON(CHAT_MODEL_CMD_JSON, { name: 'ChatGPT CMD', last_updated: Date.now(), data: list });
|
||||
await invoke('window_reload', { label: 'core' });
|
||||
await invoke('window_reload', { label: 'tray' });
|
||||
};
|
||||
|
||||
return { modelCacheJson, modelCacheSet, modelCacheCmd };
|
||||
|
||||
19
src/layout/index.scss
vendored
@@ -1,10 +1,20 @@
|
||||
.chat-logo {
|
||||
text-align: center;
|
||||
padding: 5px 0;
|
||||
height: 48px;
|
||||
|
||||
img {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
margin-top: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
.chat-info {
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
|
||||
.ant-tag {
|
||||
margin: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,9 +31,6 @@
|
||||
.ant-menu {
|
||||
user-select: none;
|
||||
-webkit-user-select: none;
|
||||
.ant-menu-item {
|
||||
background-color: #f8f8f8;
|
||||
}
|
||||
}
|
||||
|
||||
.ant-layout-footer {
|
||||
|
||||
46
src/layout/index.tsx
vendored
@@ -1,25 +1,39 @@
|
||||
import { FC, useState } from 'react';
|
||||
import { Layout, Menu } from 'antd';
|
||||
import { useState } from 'react';
|
||||
import {Layout, Menu, Tooltip, ConfigProvider, theme, Tag } from 'antd';
|
||||
import { SyncOutlined } from '@ant-design/icons';
|
||||
import { useNavigate, useLocation } from 'react-router-dom';
|
||||
import { getName, getVersion } from '@tauri-apps/api/app';
|
||||
import { invoke } from '@tauri-apps/api';
|
||||
|
||||
import useInit from '@/hooks/useInit';
|
||||
import Routes, { menuItems } from '@/routes';
|
||||
import './index.scss';
|
||||
|
||||
const { Content, Footer, Sider } = Layout;
|
||||
|
||||
interface ChatLayoutProps {
|
||||
children?: React.ReactNode;
|
||||
}
|
||||
|
||||
const ChatLayout: FC<ChatLayoutProps> = ({ children }) => {
|
||||
export default function ChatLayout() {
|
||||
const [collapsed, setCollapsed] = useState(false);
|
||||
const [appInfo, setAppInfo] = useState<Record<string, any>>({});
|
||||
const location = useLocation();
|
||||
const go = useNavigate();
|
||||
|
||||
useInit(async () => {
|
||||
setAppInfo({
|
||||
appName: await getName(),
|
||||
appVersion: await getVersion(),
|
||||
appTheme: await invoke("get_theme"),
|
||||
});
|
||||
})
|
||||
|
||||
const checkAppUpdate = async () => {
|
||||
await invoke('run_check_update', { silent: false, hasMsg: true });
|
||||
}
|
||||
|
||||
return (
|
||||
<ConfigProvider theme={{algorithm: appInfo.appTheme === "dark" ? theme.darkAlgorithm : theme.defaultAlgorithm}}>
|
||||
<Layout style={{ minHeight: '100vh' }} hasSider>
|
||||
<Sider
|
||||
theme="light"
|
||||
theme={appInfo.appTheme === "dark" ? "dark" : "light"}
|
||||
collapsible
|
||||
collapsed={collapsed}
|
||||
onCollapse={(value) => setCollapsed(value)}
|
||||
@@ -34,9 +48,20 @@ const ChatLayout: FC<ChatLayoutProps> = ({ children }) => {
|
||||
}}
|
||||
>
|
||||
<div className="chat-logo"><img src="/logo.png" /></div>
|
||||
<div className="chat-info">
|
||||
<Tag>{appInfo.appName}</Tag>
|
||||
<Tag>
|
||||
<span style={{ marginRight: 5 }}>{appInfo.appVersion}</span>
|
||||
<Tooltip title="click to check update">
|
||||
<a onClick={checkAppUpdate}><SyncOutlined /></a>
|
||||
</Tooltip>
|
||||
</Tag>
|
||||
</div>
|
||||
|
||||
<Menu
|
||||
defaultSelectedKeys={[location.pathname]}
|
||||
mode="inline"
|
||||
theme={ appInfo.appTheme === "dark" ? "dark" : "light" }
|
||||
inlineIndent={12}
|
||||
items={menuItems}
|
||||
defaultOpenKeys={['/model']}
|
||||
@@ -56,7 +81,6 @@ const ChatLayout: FC<ChatLayoutProps> = ({ children }) => {
|
||||
<a href="https://github.com/lencx/chatgpt" target="_blank">ChatGPT Desktop Application</a> ©2022 Created by lencx</Footer>
|
||||
</Layout>
|
||||
</Layout>
|
||||
</ConfigProvider>
|
||||
);
|
||||
};
|
||||
|
||||
export default ChatLayout;
|
||||
};
|
||||
2
src/main.scss
vendored
@@ -63,7 +63,7 @@ html, body {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
color: #2a2a2a;
|
||||
// color: #2a2a2a;
|
||||
}
|
||||
|
||||
span {
|
||||
|
||||
82
src/view/General.tsx
vendored
@@ -10,6 +10,21 @@ import { clone, omit, isEqual } from 'lodash';
|
||||
import useInit from '@/hooks/useInit';
|
||||
import { DISABLE_AUTO_COMPLETE, chatRoot } from '@/utils';
|
||||
|
||||
const AutoUpdateLabel = () => {
|
||||
return (
|
||||
<span>
|
||||
Auto Update <Tooltip title={(
|
||||
<div>
|
||||
<div>Auto Update Policy</div>
|
||||
<span><strong>Prompt</strong>: prompt to install</span><br/>
|
||||
<span><strong>Silent</strong>: install silently</span><br/>
|
||||
{/*<span><strong>Disable</strong>: disable auto update</span><br/>*/}
|
||||
</div>
|
||||
)}><QuestionCircleOutlined style={{ color: '#1677ff' }} /></Tooltip>
|
||||
</span>
|
||||
)
|
||||
}
|
||||
|
||||
const OriginLabel = ({ url }: { url: string }) => {
|
||||
return (
|
||||
<span>
|
||||
@@ -18,7 +33,22 @@ const OriginLabel = ({ url }: { url: string }) => {
|
||||
)
|
||||
}
|
||||
|
||||
const GlobalShortcut = () => {
|
||||
const PopupSearchLabel = () => {
|
||||
return (
|
||||
<span>
|
||||
Pop-up Search
|
||||
{' '}
|
||||
<Tooltip title={(
|
||||
<div>
|
||||
<div style={{ marginBottom: 10 }}>Generate images according to the content: Select the ChatGPT content with the mouse, no more than 400 characters. the <b>DALL·E 2</b> button appears, and click to jump (Note: because the search content filled by the script cannot trigger the event directly, you need to enter a space in the input box to make the button clickable).</div>
|
||||
<div>The application is built using Tauri, and due to its security restrictions, some of the action buttons will not work, so we recommend going to your browser.</div>
|
||||
</div>
|
||||
)}><QuestionCircleOutlined style={{ color: '#1677ff' }} /></Tooltip>
|
||||
</span>
|
||||
)
|
||||
}
|
||||
|
||||
const GlobalShortcutLabel = () => {
|
||||
return (
|
||||
<div>
|
||||
Global Shortcut
|
||||
@@ -58,6 +88,19 @@ export default function General() {
|
||||
form.setFieldsValue(chatConf);
|
||||
};
|
||||
|
||||
const onReset = async () => {
|
||||
const chatData = await invoke('reset_chat_conf');
|
||||
setChatConf(chatData);
|
||||
const isOk = await ask(`Configuration reset successfully, whether to restart?`, {
|
||||
title: 'ChatGPT Preferences'
|
||||
});
|
||||
if (isOk) {
|
||||
relaunch();
|
||||
return;
|
||||
}
|
||||
message.success('Configuration reset successfully');
|
||||
};
|
||||
|
||||
const onFinish = async (values: any) => {
|
||||
if (!isEqual(omit(chatConf, ['default_origin']), values)) {
|
||||
await invoke('form_confirm', { data: values, label: 'main' });
|
||||
@@ -86,23 +129,36 @@ export default function General() {
|
||||
labelCol={{ span: 8 }}
|
||||
wrapperCol={{ span: 15, offset: 1 }}
|
||||
>
|
||||
<Form.Item label="Theme" name="theme">
|
||||
<Radio.Group>
|
||||
<Radio value="Light">Light</Radio>
|
||||
<Radio value="Dark">Dark</Radio>
|
||||
</Radio.Group>
|
||||
</Form.Item>
|
||||
<Form.Item label="Stay On Top" name="stay_on_top" valuePropName="checked">
|
||||
<Switch />
|
||||
</Form.Item>
|
||||
<Form.Item label={<GlobalShortcut />} name="global_shortcut">
|
||||
<Input placeholder="CmdOrCtrl+Shift+O" {...DISABLE_AUTO_COMPLETE} />
|
||||
</Form.Item>
|
||||
{platformInfo === 'darwin' && (
|
||||
<Form.Item label="Titlebar" name="titlebar" valuePropName="checked">
|
||||
<Switch />
|
||||
</Form.Item>
|
||||
)}
|
||||
<Form.Item label={<PopupSearchLabel />} name="popup_search" valuePropName="checked">
|
||||
<Switch />
|
||||
</Form.Item>
|
||||
<Form.Item label="Theme" name="theme">
|
||||
<Radio.Group>
|
||||
<Radio value="Light">Light</Radio>
|
||||
<Radio value="Dark">Dark</Radio>
|
||||
{["darwin", "windows"].includes(platformInfo) && (
|
||||
<Radio value="System">System</Radio>
|
||||
)}
|
||||
</Radio.Group>
|
||||
</Form.Item>
|
||||
<Form.Item label={<AutoUpdateLabel />} name="auto_update">
|
||||
<Radio.Group>
|
||||
<Radio value="Prompt">Prompt</Radio>
|
||||
<Radio value="Silent">Silent</Radio>
|
||||
{/*<Radio value="Disable">Disable</Radio>*/}
|
||||
</Radio.Group>
|
||||
</Form.Item>
|
||||
<Form.Item label={<GlobalShortcutLabel />} name="global_shortcut">
|
||||
<Input placeholder="CmdOrCtrl+Shift+O" {...DISABLE_AUTO_COMPLETE} />
|
||||
</Form.Item>
|
||||
<Form.Item label={<OriginLabel url={chatConf?.default_origin} />} name="origin">
|
||||
<Input placeholder="https://chat.openai.com" {...DISABLE_AUTO_COMPLETE} />
|
||||
</Form.Item>
|
||||
@@ -115,10 +171,10 @@ export default function General() {
|
||||
<Form.Item>
|
||||
<Space size={20}>
|
||||
<Button onClick={onCancel}>Cancel</Button>
|
||||
<Button type="primary" htmlType="submit">
|
||||
Submit
|
||||
</Button>
|
||||
<Button type="primary" htmlType="submit">Submit</Button>
|
||||
<Button type="dashed" onClick={onReset}>Reset to defaults</Button>
|
||||
</Space>
|
||||
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</>
|
||||
|
||||