Merge pull request #169 from lencx/dev

This commit is contained in:
lencx
2023-01-07 15:28:59 +08:00
committed by GitHub
36 changed files with 457 additions and 164 deletions

View File

@@ -2,7 +2,6 @@ name: Release CI
on: on:
push: push:
# Sequence of patterns matched against refs/tags
tags: tags:
- 'v*' # Push events to matching v*, i.e. v1.0, v20.15.10 - 'v*' # Push events to matching v*, i.e. v1.0, v20.15.10
@@ -90,7 +89,7 @@ jobs:
# 📝: Edit the deployment directory # 📝: Edit the deployment directory
publish_dir: ./updater publish_dir: ./updater
force_orphan: true force_orphan: true
publish-winget: publish-winget:
# Action can only be run on windows # Action can only be run on windows
runs-on: windows-latest runs-on: windows-latest
@@ -99,5 +98,5 @@ jobs:
- uses: vedantmgoyal2009/winget-releaser@v1 - uses: vedantmgoyal2009/winget-releaser@v1
with: with:
identifier: lencx.ChatGPT identifier: lencx.ChatGPT
token: ${{ secrets.GITHUB_TOKEN }} token: ${{ secrets.WINGET_TOKEN }}
version: ${{ env.version }} version: ${{ env.version }}

View File

@@ -1,10 +1,9 @@
<p align="center"> <p align="center">
<img width="180" src="./public/logo.png" alt="ChatGPT"> <img width="180" src="./public/logo.png" alt="ChatGPT">
<h1 align="center">ChatGPT</h1> <h1 align="center">ChatGPT</h1>
<p align="center">ChatGPT 桌面应用Mac, Windows and Linux</p>
</p> </p>
> ChatGPT 桌面应用
[![English badge](https://img.shields.io/badge/%E8%8B%B1%E6%96%87-English-blue)](./README.md) [![English badge](https://img.shields.io/badge/%E8%8B%B1%E6%96%87-English-blue)](./README.md)
[![简体中文 badge](https://img.shields.io/badge/%E7%AE%80%E4%BD%93%E4%B8%AD%E6%96%87-Simplified%20Chinese-blue)](./README-ZH_CN.md)\ [![简体中文 badge](https://img.shields.io/badge/%E7%AE%80%E4%BD%93%E4%B8%AD%E6%96%87-Simplified%20Chinese-blue)](./README-ZH_CN.md)\
![License](https://img.shields.io/badge/License-Apache%202-green.svg) ![License](https://img.shields.io/badge/License-Apache%202-green.svg)
@@ -23,24 +22,29 @@
### Windows ### 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://learn.microsoft.com/en-us/windows/package-manager/winget/): - 使用 [winget](https://winstall.app/apps/lencx.ChatGPT):
- `winget install --id=lencx.ChatGPT -e` ```bash
- `winget install --id=lencx.ChatGPT -e --version 0.7.4` # install the latest version
winget install --id=lencx.ChatGPT -e
**注意:如果安装路径和应用名称相同,会导致冲突 ([#142](https://github.com/lencx/ChatGPT/issues/142#issuecomment-1371166972))** # install the specified version
winget install --id=lencx.ChatGPT -e --version 0.7.4
```
**注意:如果安装路径和应用名称相同,会导致冲突 ([#142](https://github.com/lencx/ChatGPT/issues/142#issuecomment-0.8.0))**
### Mac ### Mac
- [ChatGPT_0.7.4_x64.dmg](https://github.com/lencx/ChatGPT/releases/download/v0.7.4/ChatGPT_0.7.4_x64.dmg) - [ChatGPT_0.8.0_x64.dmg](https://github.com/lencx/ChatGPT/releases/download/v0.8.0/ChatGPT_0.8.0_x64.dmg)
- 如果你偏爱 `.app` 的安装包,你同样可以在我们的 github releases 里找到 [ChatGPT.app.tar.gz](https://github.com/lencx/ChatGPT/releases/download/v0.7.4/ChatGPT.app.tar.gz) - [ChatGPT.app.tar.gz](https://github.com/lencx/ChatGPT/releases/download/v0.8.0/ChatGPT.app.tar.gz)
- Homebrew \ - Homebrew \
_[Homebrew 快捷安装](https://brew.sh) ([Cask](https://docs.brew.sh/Cask-Cookbook)):_ _[Homebrew 快捷安装](https://brew.sh) ([Cask](https://docs.brew.sh/Cask-Cookbook)):_
```sh ```sh
brew tap lencx/chatgpt https://github.com/lencx/ChatGPT.git brew tap lencx/chatgpt https://github.com/lencx/ChatGPT.git
brew install --cask chatgpt --no-quarantine brew install --cask chatgpt --no-quarantine
``` ```
如果你坚持使用 _[Brewfile](https://github.com/Homebrew/homebrew-bundle#usage)_ 需要添加以下配置: 如果你坚持使用 _[Brewfile](https://github.com/Homebrew/homebrew-bundle#usage)_ 需要添加以下配置:
```rb ```rb
repo = "lencx/chatgpt" repo = "lencx/chatgpt"
tap repo, "https://github.com/#{repo}.git" tap repo, "https://github.com/#{repo}.git"
@@ -49,24 +53,25 @@
### Linux ### 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) - [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.7.4_amd64.AppImage](https://github.com/lencx/ChatGPT/releases/download/v0.7.4/chat-gpt_0.7.4_amd64.AppImage): **工作可靠,`.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` 运行失败时可以尝试它**
- [chatgpt-desktop-bin](https://aur.archlinux.org/packages/chatgpt-desktop-bin): 使用 AUR 来安装 - 使用 [AUR](https://aur.archlinux.org/packages/chatgpt-desktop-bin):
```bash
yay -S chatgpt-desktop-bin
```
<!-- download end --> <!-- download end -->
---
## 📢 公告 ## 📢 公告
这是一个令人兴奋的重大更新。像 `Telegram 机器人指令` 那样工作,帮助你快速填充自定模型,来让 ChatGPT 按照你想要的方式去工作。这个项目倾注了我大量业余时间,如果它对你有所帮助,宣传转发,或者 star 都是对我的巨大鼓励。我希望我可以持续更新下去,加入更多有趣的功能。 这是一个令人兴奋的重大更新。像 `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`,来一键同步所有,如果你不想让某些提示出现在你的斜杠命令,你可以禁用它们。
![chat cmd](./assets/chat-cmd-1.png) ![chatgpt menu](./assets/chatgpt-menu.png)
![chat cmd](./assets/chat-cmd-2.png) ![chatgpt sync prompts](./assets/chatgpt-sync-prompts.png)
<!-- 数据导入完成后,可以重新启动应用来使配置生效(`Menu -> Preferences -> Restart ChatGPT`)。 --> <!-- 数据导入完成后,可以重新启动应用来使配置生效(`Menu -> Preferences -> Restart ChatGPT`)。 -->
@@ -85,11 +90,12 @@
- 应用菜单功能强大 - 应用菜单功能强大
- 支持斜杠命令及其配置(可手动配置或从文件同步 [#55](https://github.com/lencx/ChatGPT/issues/55) - 支持斜杠命令及其配置(可手动配置或从文件同步 [#55](https://github.com/lencx/ChatGPT/issues/55)
- 自定义全局快捷键 ([#108](https://github.com/lencx/ChatGPT/issues/108)) - 自定义全局快捷键 ([#108](https://github.com/lencx/ChatGPT/issues/108))
- 划词搜索 ([#122](https://github.com/lencx/ChatGPT/issues/122) 鼠标选中文本,不超过 400 个字符):应用使用 Tauri 构建,因其安全限制,会导致部分操作按钮无效,建议前往浏览器操作。
### 菜单项 ### #️⃣ 菜单项
- **Preferences (喜好)** - **Preferences (喜好)**
- `Theme` - `Light`, `Dark` (仅支持 macOS 和 Windows) - `Theme` - `Light`, `Dark`, `System` (仅支持 macOS 和 Windows)
- `Stay On Top`: 窗口置顶 - `Stay On Top`: 窗口置顶
- `Titlebar`: 是否显示 `Titlebar`,仅 macOS 支持 - `Titlebar`: 是否显示 `Titlebar`,仅 macOS 支持
- `Inject Script`: 用于修改网站的用户自定义脚本 - `Inject Script`: 用于修改网站的用户自定义脚本
@@ -110,7 +116,7 @@
- `Report Bug`: 报告 BUG 或反馈建议 - `Report Bug`: 报告 BUG 或反馈建议
- `Toggle Developer Tools`: 网站调试工具,调试页面或脚本可能需要 - `Toggle Developer Tools`: 网站调试工具,调试页面或脚本可能需要
## 应用配置 ## ⚙️ 应用配置
| 平台 | 路径 | | 平台 | 路径 |
| ------- | ------------------------- | | ------- | ------------------------- |
@@ -163,9 +169,9 @@
## 👀 预览 ## 👀 预览
<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/install.png" alt="install"> <img width="320" src="./assets/chatgpt-control-center-general.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/chatgpt-export.png" alt="export"> <img width="320" src="./assets/chatgpt-dalle2-tray.png" alt="dalle2 tray">
<img width="320" src="./assets/tray-login.png" alt="tray login"> <img width="320" src="./assets/auto-update.png" alt="auto update"> <img width="320" src="./assets/auto-update.png" alt="auto update">
## ❓ 常见问题 ## ❓ 常见问题
@@ -187,6 +193,8 @@ Mac 上无法安装,提示开发者未验证,具体可以查看下面给出
- [Open a Mac app from an unidentified developer](https://support.apple.com/en-sg/guide/mac-help/mh40616/mac) - [Open a Mac app from an unidentified developer](https://support.apple.com/en-sg/guide/mac-help/mh40616/mac)
---
### 我想自己构建它? ### 我想自己构建它?
#### 预安装 #### 预安装

View File

@@ -1,11 +1,9 @@
<p align="center"> <p align="center">
<img width="180" src="./public/logo.png" alt="ChatGPT"> <img width="180" src="./public/logo.png" alt="ChatGPT">
<h1 align="center">ChatGPT</h1> <h1 align="center">ChatGPT</h1>
<p align="center">ChatGPT Desktop Application (Mac, Windows and Linux)</p>
</p> </p>
<div align="center"><h2>ChatGPT Desktop Application</h2></div>
<br>
[![English badge](https://img.shields.io/badge/%E8%8B%B1%E6%96%87-English-blue)](./README.md) [![English badge](https://img.shields.io/badge/%E8%8B%B1%E6%96%87-English-blue)](./README.md)
[![简体中文 badge](https://img.shields.io/badge/%E7%AE%80%E4%BD%93%E4%B8%AD%E6%96%87-Simplified%20Chinese-blue)](./README-ZH_CN.md)\ [![简体中文 badge](https://img.shields.io/badge/%E7%AE%80%E4%BD%93%E4%B8%AD%E6%96%87-Simplified%20Chinese-blue)](./README-ZH_CN.md)\
![License](https://img.shields.io/badge/License-Apache%202-green.svg) ![License](https://img.shields.io/badge/License-Apache%202-green.svg)
@@ -26,17 +24,22 @@
### Windows ### Windows
- From our github releases: [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
- Or install with [winget](https://learn.microsoft.com/en-us/windows/package-manager/winget/): - Use [winget](https://winstall.app/apps/lencx.ChatGPT):
- `winget install --id=lencx.ChatGPT -e` ```bash
- `winget install --id=lencx.ChatGPT -e --version 0.7.4` # install the latest version
winget install --id=lencx.ChatGPT -e
**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-1371166972))** # install the specified version
winget install --id=lencx.ChatGPT -e --version 0.7.4
```
**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 ### Mac
- From our github releases: [ChatGPT_0.7.4_x64.dmg](https://github.com/lencx/ChatGPT/releases/download/v0.7.4/ChatGPT_0.7.4_x64.dmg) - [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
- If you prefer `.app` installation, you can also download it from our github releases: [ChatGPT.app.tar.gz](https://github.com/lencx/ChatGPT/releases/download/v0.7.4/ChatGPT.app.tar.gz) - [ChatGPT.app.tar.gz](https://github.com/lencx/ChatGPT/releases/download/v0.8.0/ChatGPT.app.tar.gz): Download the `.app` installer
- Homebrew \ - Homebrew \
Or you can install with _[Homebrew](https://brew.sh) ([Cask](https://docs.brew.sh/Cask-Cookbook)):_ Or you can install with _[Homebrew](https://brew.sh) ([Cask](https://docs.brew.sh/Cask-Cookbook)):_
```sh ```sh
@@ -52,14 +55,12 @@
### Linux ### 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) - [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.7.4_amd64.AppImage](https://github.com/lencx/ChatGPT/releases/download/v0.7.4/chat-gpt_0.7.4_amd64.AppImage): **works reliably, you can try it if `.deb` fails to run** - [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. - 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 --> <!-- download end -->
---
## 📢 Announcement ## 📢 Announcement
### ChatGPT Prompts! ### ChatGPT Prompts!
@@ -68,22 +69,18 @@ This is a major and exciting update. It works like a `Telegram bot command` and
### How does it work? ### 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.
![chat cmd](./assets/chat-cmd-1.png) ![chatgpt menu](./assets/chatgpt-menu.png)
![chatgpt sync prompts](./assets/chatgpt-sync-prompts.png)
![chat cmd](./assets/chat-cmd-2.png)
<!-- After the data import is done, you can restart the app to make the configuration take effect (`Menu -> Preferences -> Restart ChatGPT`). --> <!-- After the data import is done, you can restart the app to make the configuration take effect (`Menu -> Preferences -> Restart ChatGPT`). -->
<br>
- 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. - 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. - 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. - 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.
<br>
![chatgpt](assets/chatgpt.gif) ![chatgpt](assets/chatgpt.gif)
![chatgpt-cmd](assets/chatgpt-cmd.gif) ![chatgpt-cmd](assets/chatgpt-cmd.gif)
## ✨ Features ## ✨ Features
@@ -96,11 +93,12 @@ You can look at **[awesome-chatgpt-prompts](https://github.com/f/awesome-chatgpt
- Powerful menu items - 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)) - 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)) - 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** - **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. - `Stay On Top`: The window is stay on top of other windows.
- `Titlebar`: Whether to display the titlebar, supported by macOS only. - `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). - `Hide Dock Icon` ([#35](https://github.com/lencx/ChatGPT/issues/35)): Hide application icons from the Dock(support macOS only).
@@ -121,7 +119,7 @@ You can look at **[awesome-chatgpt-prompts](https://github.com/f/awesome-chatgpt
- `Report Bug`: Report a bug or give feedback. - `Report Bug`: Report a bug or give feedback.
- `Toggle Developer Tools`: Developer debugging tools. - `Toggle Developer Tools`: Developer debugging tools.
## Application Configuration ## ⚙️ Application Configuration
| Platform | Path | | Platform | Path |
| -------- | ------------------------- | | -------- | ------------------------- |
@@ -172,18 +170,18 @@ Currently, only json and csv are supported for synchronizing custom files, and t
"b","bb","bbb bbb bbb" "b","bb","bbb bbb bbb"
``` ```
## TODO ## 📌 TODO
<!-- - Web access capability ([#20](https://github.com/lencx/ChatGPT/issues/20)) --> <!-- - Web access capability ([#20](https://github.com/lencx/ChatGPT/issues/20)) -->
- `Control Center` - Feature Enhancements - `Control Center` enhancement
- Integration with [DALL·E 2](https://openai.com/dall-e-2/) ([#122](https://github.com/lencx/ChatGPT/issues/122)) - `Pop-up Search` enhancement
- ... - ...
## 👀 Preview ## 👀 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/install.png" alt="install"> <img width="320" src="./assets/chatgpt-popup-search.png" alt="popup search">
<img width="320" src="./assets/export.png" alt="export"> <img width="320" src="./assets/tray.png" alt="tray"> <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/tray-login.png" alt="tray login"> <img width="320" src="./assets/auto-update.png" alt="auto update"> <img width="320" src="./assets/chatgpt-dalle2-tray.png" alt="dalle2 tray"> <img width="320" src="./assets/auto-update.png" alt="auto update">
## ❓FAQ ## ❓FAQ
@@ -203,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) - [Open a Mac app from an unidentified developer](https://support.apple.com/en-sg/guide/mac-help/mh40616/mac)
---
### How do i build it? ### How do i build it?
#### PreInstall #### PreInstall
@@ -231,7 +231,6 @@ yarn dev
# bundle path: src-tauri/target/release/bundle # bundle path: src-tauri/target/release/bundle
yarn build yarn build
``` ```
---
## ❤️ Thanks ## ❤️ Thanks

View File

@@ -1,5 +1,15 @@
# UPDATE LOG # 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 ## v0.7.4
fix: fix:

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 426 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 808 KiB

BIN
assets/chatgpt-export.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 241 KiB

BIN
assets/chatgpt-menu.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 742 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 580 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 406 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 500 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 226 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 989 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 543 KiB

View File

@@ -29,9 +29,12 @@ reqwest = "0.11.13"
wry = "0.23.4" wry = "0.23.4"
dark-light = "1.0.0" dark-light = "1.0.0"
[dependencies.tauri-plugin-log] [dependencies.tauri-plugin-log]
git = "https://github.com/tauri-apps/tauri-plugin-log" git = "https://github.com/lencx/tauri-plugin-log"
branch = "dev" branch = "dev"
features = ["colored"] features = ["colored"]
[dependencies.tauri-plugin-autostart]
git = "https://github.com/lencx/tauri-plugin-autostart"
branch = "dev"
[features] [features]
# by default Tauri runs in production mode # by default Tauri runs in production mode

View File

@@ -1,16 +1,28 @@
use crate::{ use crate::{
app::window,
conf::{ChatConfJson, GITHUB_PROMPTS_CSV_URL}, conf::{ChatConfJson, GITHUB_PROMPTS_CSV_URL},
utils::{self, exists}, utils,
}; };
use log::info; use log::info;
use std::{collections::HashMap, fs, path::PathBuf}; use std::{collections::HashMap, fs, path::PathBuf};
use tauri::{api, command, AppHandle, Manager, Theme}; use tauri::{api, command, AppHandle, Manager, Theme};
use walkdir::WalkDir;
#[command] #[command]
pub fn drag_window(app: AppHandle) { pub fn drag_window(app: AppHandle) {
app.get_window("core").unwrap().start_dragging().unwrap(); 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] #[command]
pub fn fullscreen(app: AppHandle) { pub fn fullscreen(app: AppHandle) {
let win = app.get_window("core").unwrap(); let win = app.get_window("core").unwrap();
@@ -49,8 +61,8 @@ pub fn reset_chat_conf() -> ChatConfJson {
} }
#[command] #[command]
pub fn run_check_update(app: AppHandle, silent: bool) { pub fn run_check_update(app: AppHandle, silent: bool, has_msg: Option<bool>) {
utils::run_check_update(app, silent).unwrap(); utils::run_check_update(app, silent, has_msg);
} }
#[command] #[command]
@@ -127,9 +139,6 @@ pub fn window_reload(app: AppHandle, label: &str) {
.unwrap(); .unwrap();
} }
use utils::chat_root;
use walkdir::WalkDir;
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] #[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
pub struct ModelRecord { pub struct ModelRecord {
pub cmd: String, pub cmd: String,
@@ -142,7 +151,7 @@ pub struct ModelRecord {
#[command] #[command]
pub fn cmd_list() -> Vec<ModelRecord> { pub fn cmd_list() -> Vec<ModelRecord> {
let mut list = vec![]; 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() .into_iter()
.filter_map(|e| e.ok()) .filter_map(|e| e.ok())
{ {
@@ -182,11 +191,13 @@ pub async fn sync_prompts(app: AppHandle, time: u64) -> Option<Vec<ModelRecord>>
let data2 = data.clone(); let data2 = data.clone();
let model = chat_root().join("chat.model.json"); let model = utils::chat_root().join("chat.model.json");
let model_cmd = chat_root().join("chat.model.cmd.json"); let model_cmd = utils::chat_root().join("chat.model.cmd.json");
let chatgpt_prompts = chat_root().join("cache_model").join("chatgpt_prompts.json"); let chatgpt_prompts = utils::chat_root()
.join("cache_model")
.join("chatgpt_prompts.json");
if !exists(&model) { if !utils::exists(&model) {
fs::write( fs::write(
&model, &model,
serde_json::json!({ serde_json::json!({
@@ -236,7 +247,8 @@ pub async fn sync_prompts(app: AppHandle, time: u64) -> Option<Vec<ModelRecord>>
"Sync Prompts", "Sync Prompts",
"ChatGPT Prompts data has been synchronized!", "ChatGPT Prompts data has been synchronized!",
); );
window_reload(app, "core"); window_reload(app.clone(), "core");
window_reload(app, "tray");
return Some(data2); return Some(data2);
} }

View File

@@ -1,4 +1,5 @@
use crate::{ use crate::{
app::{cmd, window},
conf::{self, ChatConfJson}, conf::{self, ChatConfJson},
utils, utils,
}; };
@@ -11,8 +12,6 @@ use tauri_plugin_positioner::{on_tray_event, Position, WindowExt};
#[cfg(target_os = "macos")] #[cfg(target_os = "macos")]
use tauri::AboutMetadata; use tauri::AboutMetadata;
use super::window;
// --- Menu // --- Menu
pub fn init() -> Menu { pub fn init() -> Menu {
let chat_conf = ChatConfJson::get_chat_conf(); let chat_conf = ChatConfJson::get_chat_conf();
@@ -36,6 +35,11 @@ pub fn init() -> Menu {
let stay_on_top = let stay_on_top =
CustomMenuItem::new("stay_on_top".to_string(), "Stay On Top").accelerator("CmdOrCtrl+T"); CustomMenuItem::new("stay_on_top".to_string(), "Stay On Top").accelerator("CmdOrCtrl+T");
let stay_on_top_menu = if chat_conf.stay_on_top {
stay_on_top.selected()
} else {
stay_on_top
};
#[cfg(target_os = "macos")] #[cfg(target_os = "macos")]
let titlebar = let titlebar =
@@ -51,10 +55,11 @@ pub fn init() -> Menu {
let update_silent = CustomMenuItem::new("update_silent".to_string(), "Silent"); let update_silent = CustomMenuItem::new("update_silent".to_string(), "Silent");
let _update_disable = CustomMenuItem::new("update_disable".to_string(), "Disable"); let _update_disable = CustomMenuItem::new("update_disable".to_string(), "Disable");
let stay_on_top_menu = if chat_conf.stay_on_top { let popup_search = CustomMenuItem::new("popup_search".to_string(), "Pop-up Search");
stay_on_top.selected() let popup_search_menu = if chat_conf.popup_search {
popup_search.selected()
} else { } else {
stay_on_top popup_search
}; };
#[cfg(target_os = "macos")] #[cfg(target_os = "macos")]
@@ -71,6 +76,15 @@ pub fn init() -> Menu {
.accelerator("CmdOrCtrl+Shift+P") .accelerator("CmdOrCtrl+Shift+P")
.into(), .into(),
MenuItem::Separator.into(), MenuItem::Separator.into(),
stay_on_top_menu.into(),
#[cfg(target_os = "macos")]
titlebar_menu.into(),
#[cfg(target_os = "macos")]
CustomMenuItem::new("hide_dock_icon".to_string(), "Hide Dock Icon").into(),
CustomMenuItem::new("inject_script".to_string(), "Inject Script")
.accelerator("CmdOrCtrl+J")
.into(),
MenuItem::Separator.into(),
Submenu::new( Submenu::new(
"Theme", "Theme",
Menu::new() Menu::new()
@@ -110,15 +124,8 @@ pub fn init() -> Menu {
// }) // })
) )
.into(), .into(),
stay_on_top_menu.into(),
#[cfg(target_os = "macos")]
titlebar_menu.into(),
#[cfg(target_os = "macos")]
CustomMenuItem::new("hide_dock_icon".to_string(), "Hide Dock Icon").into(),
CustomMenuItem::new("inject_script".to_string(), "Inject Script")
.accelerator("CmdOrCtrl+J")
.into(),
MenuItem::Separator.into(), MenuItem::Separator.into(),
popup_search_menu.into(),
CustomMenuItem::new("sync_prompts".to_string(), "Sync Prompts").into(), CustomMenuItem::new("sync_prompts".to_string(), "Sync Prompts").into(),
MenuItem::Separator.into(), MenuItem::Separator.into(),
CustomMenuItem::new("go_conf".to_string(), "Go to Config") CustomMenuItem::new("go_conf".to_string(), "Go to Config")
@@ -177,6 +184,8 @@ pub fn init() -> Menu {
let window_menu = Submenu::new( let window_menu = Submenu::new(
"Window", "Window",
Menu::new() 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::Minimize)
.add_native_item(MenuItem::Zoom), .add_native_item(MenuItem::Zoom),
); );
@@ -199,9 +208,9 @@ pub fn init() -> Menu {
Menu::new() Menu::new()
.add_submenu(app_menu) .add_submenu(app_menu)
.add_submenu(preferences_menu) .add_submenu(preferences_menu)
.add_submenu(window_menu)
.add_submenu(edit_menu) .add_submenu(edit_menu)
.add_submenu(view_menu) .add_submenu(view_menu)
.add_submenu(window_menu)
.add_submenu(help_menu) .add_submenu(help_menu)
} }
@@ -209,12 +218,9 @@ pub fn init() -> Menu {
pub fn menu_handler(event: WindowMenuEvent<tauri::Wry>) { pub fn menu_handler(event: WindowMenuEvent<tauri::Wry>) {
let win = Some(event.window()).unwrap(); let win = Some(event.window()).unwrap();
let app = win.app_handle(); 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 script_path = utils::script_path().to_string_lossy().to_string();
let menu_id = event.menu_item_id(); let menu_id = event.menu_item_id();
let menu_handle = win.menu_handle();
let core_window = app.get_window("core").unwrap();
let menu_handle = core_window.menu_handle();
match menu_id { match menu_id {
// App // App
@@ -227,7 +233,7 @@ pub fn menu_handler(event: WindowMenuEvent<tauri::Wry>) {
); );
} }
"check_update" => { "check_update" => {
utils::run_check_update(app, false).unwrap(); utils::run_check_update(app, false, None);
} }
// Preferences // Preferences
"control_center" => window::control_window(&app), "control_center" => window::control_window(&app),
@@ -236,6 +242,18 @@ pub fn menu_handler(event: WindowMenuEvent<tauri::Wry>) {
"go_conf" => utils::open_file(utils::chat_root()), "go_conf" => utils::open_file(utils::chat_root()),
"clear_conf" => utils::clear_conf(&app), "clear_conf" => utils::clear_conf(&app),
"awesome" => open(&app, conf::AWESOME_URL.to_string()), "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" => { "sync_prompts" => {
tauri::api::dialog::ask( tauri::api::dialog::ask(
app.get_window("core").as_ref(), app.get_window("core").as_ref(),
@@ -272,7 +290,8 @@ pub fn menu_handler(event: WindowMenuEvent<tauri::Wry>) {
ChatConfJson::amend(&serde_json::json!({ "theme": theme }), Some(app)).unwrap(); ChatConfJson::amend(&serde_json::json!({ "theme": theme }), Some(app)).unwrap();
} }
"update_prompt" | "update_silent" | "update_disable" => { "update_prompt" | "update_silent" | "update_disable" => {
for id in ["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(); menu_handle.get_item(id).set_selected(false).unwrap();
} }
let auto_update = match menu_id { let auto_update = match menu_id {
@@ -301,19 +320,22 @@ pub fn menu_handler(event: WindowMenuEvent<tauri::Wry>) {
ChatConfJson::amend(&serde_json::json!({ "auto_update": auto_update }), None).unwrap(); ChatConfJson::amend(&serde_json::json!({ "auto_update": auto_update }), None).unwrap();
} }
"stay_on_top" => { "stay_on_top" => {
let mut stay_on_top = state.stay_on_top.lock().unwrap(); let chat_conf = conf::ChatConfJson::get_chat_conf();
*stay_on_top = !*stay_on_top; let stay_on_top = !chat_conf.stay_on_top;
menu_handle menu_handle
.get_item(menu_id) .get_item(menu_id)
.set_selected(*stay_on_top) .set_selected(stay_on_top)
.unwrap(); .unwrap();
win.set_always_on_top(*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(); ChatConfJson::amend(&serde_json::json!({ "stay_on_top": stay_on_top }), None).unwrap();
} }
// Window
"dalle2" => window::dalle2_window(&app, None, None, Some(false)),
// View // View
"reload" => win.eval("window.location.reload()").unwrap(), "reload" => win.eval("window.location.reload()").unwrap(),
"go_back" => win.eval("window.history.go(-1)").unwrap(), "go_back" => win.eval("window.history.go(-1)").unwrap(),
"go_forward" => 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 "scroll_top" => win
.eval( .eval(
r#"window.scroll({ r#"window.scroll({
@@ -346,12 +368,13 @@ pub fn menu_handler(event: WindowMenuEvent<tauri::Wry>) {
// --- SystemTray Menu // --- SystemTray Menu
pub fn tray_menu() -> SystemTray { pub fn tray_menu() -> SystemTray {
if cfg!(target_os = "macos") { if cfg!(target_os = "macos") {
return SystemTray::new().with_menu( SystemTray::new().with_menu(
SystemTrayMenu::new() SystemTrayMenu::new()
.add_item(CustomMenuItem::new( .add_item(CustomMenuItem::new(
"control_center".to_string(), "control_center".to_string(),
"Control Center", "Control Center",
)) ))
.add_native_item(SystemTrayMenuItem::Separator)
.add_item(CustomMenuItem::new( .add_item(CustomMenuItem::new(
"show_dock_icon".to_string(), "show_dock_icon".to_string(),
"Show Dock Icon", "Show Dock Icon",
@@ -360,20 +383,22 @@ pub fn tray_menu() -> SystemTray {
"hide_dock_icon".to_string(), "hide_dock_icon".to_string(),
"Hide Dock Icon", "Hide Dock Icon",
)) ))
.add_item(CustomMenuItem::new("show_core".to_string(), "Show ChatGPT"))
.add_native_item(SystemTrayMenuItem::Separator) .add_native_item(SystemTrayMenuItem::Separator)
.add_item(CustomMenuItem::new("quit".to_string(), "Quit ChatGPT")), .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 // --- SystemTray Event
@@ -414,6 +439,15 @@ pub fn tray_handler(handle: &AppHandle, event: SystemTrayEvent) {
.unwrap(); .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), "quit" => std::process::exit(0),
_ => (), _ => (),
}, },

View File

@@ -10,7 +10,7 @@ pub fn init(app: &mut App) -> std::result::Result<(), Box<dyn std::error::Error>
let theme = ChatConfJson::theme(); let theme = ChatConfJson::theme();
let handle = app.app_handle(); let handle = app.app_handle();
tokio::spawn(async move { tauri::async_runtime::spawn(async move {
window::tray_window(&handle); 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); app.set_activation_policy(tauri::ActivationPolicy::Accessory);
} else { } else {
let app = app.handle(); let app = app.handle();
tokio::spawn(async move { tauri::async_runtime::spawn(async move {
#[cfg(target_os = "macos")] #[cfg(target_os = "macos")]
WindowBuilder::new(&app, "core", WindowUrl::App(url.into())) WindowBuilder::new(&app, "core", WindowUrl::App(url.into()))
.title("ChatGPT") .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) .always_on_top(chat_conf.stay_on_top)
.title_bar_style(ChatConfJson::titlebar()) .title_bar_style(ChatConfJson::titlebar())
.initialization_script(&utils::user_script()) .initialization_script(&utils::user_script())
.initialization_script(include_str!("../assets/html2canvas.js")) .initialization_script(include_str!("../vendors/floating-ui-core.js"))
.initialization_script(include_str!("../assets/jspdf.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/core.js"))
.initialization_script(include_str!("../assets/popup.core.js"))
.initialization_script(include_str!("../assets/export.js")) .initialization_script(include_str!("../assets/export.js"))
.initialization_script(include_str!("../assets/cmd.js")) .initialization_script(include_str!("../assets/cmd.js"))
.user_agent(&chat_conf.ua_window) .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) .theme(theme)
.always_on_top(chat_conf.stay_on_top) .always_on_top(chat_conf.stay_on_top)
.initialization_script(&utils::user_script()) .initialization_script(&utils::user_script())
.initialization_script(include_str!("../assets/html2canvas.js")) .initialization_script(include_str!("../vendors/floating-ui-core.js"))
.initialization_script(include_str!("../assets/jspdf.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/core.js"))
.initialization_script(include_str!("../assets/popup.core.js"))
.initialization_script(include_str!("../assets/export.js")) .initialization_script(include_str!("../assets/export.js"))
.initialization_script(include_str!("../assets/cmd.js")) .initialization_script(include_str!("../assets/cmd.js"))
.user_agent(&chat_conf.ua_window) .user_agent(&chat_conf.ua_window)
@@ -89,10 +95,12 @@ pub fn init(app: &mut App) -> std::result::Result<(), Box<dyn std::error::Error>
.unwrap(); .unwrap();
}); });
} }
// auto_update // auto_update
if chat_conf.auto_update != "Disable" { if chat_conf.auto_update != "Disable" {
info!("stepup::run_check_update");
let app = app.handle(); let app = app.handle();
utils::run_check_update(app, chat_conf.auto_update == "Silent").unwrap(); utils::run_check_update(app, chat_conf.auto_update == "Silent", None);
} }
Ok(()) Ok(())

View File

@@ -1,12 +1,14 @@
use crate::{conf, utils}; 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) { pub fn tray_window(handle: &tauri::AppHandle) {
let chat_conf = conf::ChatConfJson::get_chat_conf(); let chat_conf = conf::ChatConfJson::get_chat_conf();
let theme = conf::ChatConfJson::theme(); let theme = conf::ChatConfJson::theme();
let app = handle.clone(); let app = handle.clone();
tokio::spawn(async move { tauri::async_runtime::spawn(async move {
WindowBuilder::new(&app, "tray", WindowUrl::App(chat_conf.origin.into())) WindowBuilder::new(&app, "tray", WindowUrl::App(chat_conf.origin.into()))
.title("ChatGPT") .title("ChatGPT")
.resizable(false) .resizable(false)
@@ -16,8 +18,11 @@ pub fn tray_window(handle: &tauri::AppHandle) {
.always_on_top(true) .always_on_top(true)
.theme(theme) .theme(theme)
.initialization_script(&utils::user_script()) .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/core.js"))
.initialization_script(include_str!("../assets/cmd.js")) .initialization_script(include_str!("../assets/cmd.js"))
.initialization_script(include_str!("../assets/popup.core.js"))
.user_agent(&chat_conf.ua_tray) .user_agent(&chat_conf.ua_tray)
.build() .build()
.unwrap() .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(); let app = handle.clone();
tokio::spawn(async move {
WindowBuilder::new(&app, "main", WindowUrl::App("index.html".into())) let query = if query.is_some() {
.title("Control Center") 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) .resizable(true)
.fullscreen(false) .fullscreen(false)
.inner_size(800.0, 600.0) .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() .build()
.unwrap(); .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();
}
}); });
} }

View File

@@ -75,6 +75,11 @@ function init() {
width: 24px; width: 24px;
height: 24px; height: 24px;
} }
@media screen and (max-width: 767px) {
#download-png-button, #download-pdf-button, #download-html-button {
display: none;
}
}
`; `;
document.head.append(styleDom); document.head.append(styleDom);

View File

@@ -71,6 +71,7 @@ async function init() {
document.addEventListener("click", (e) => { document.addEventListener("click", (e) => {
const origin = e.target.closest("a"); const origin = e.target.closest("a");
if (!origin.target) return;
if (origin && origin.href && origin.target !== '_self') { if (origin && origin.href && origin.target !== '_self') {
invoke('open_link', { url: origin.href }); invoke('open_link', { url: origin.href });
} }

40
src-tauri/src/assets/dalle2.js vendored Normal file
View 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
View 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);
}

View File

@@ -2,7 +2,7 @@ use crate::utils::{chat_root, create_file, exists};
use anyhow::Result; use anyhow::Result;
use log::info; use log::info;
use serde_json::Value; use serde_json::Value;
use std::{collections::BTreeMap, fs, path::PathBuf, sync::Mutex}; use std::{collections::BTreeMap, fs, path::PathBuf};
use tauri::{Manager, Theme}; use tauri::{Manager, Theme};
#[cfg(target_os = "macos")] #[cfg(target_os = "macos")]
@@ -21,6 +21,7 @@ pub const DEFAULT_CHAT_CONF: &str = r#"{
"auto_update": "Prompt", "auto_update": "Prompt",
"theme": "Light", "theme": "Light",
"titlebar": true, "titlebar": true,
"popup_search": true,
"global_shortcut": "", "global_shortcut": "",
"hide_dock_icon": false, "hide_dock_icon": false,
"default_origin": "https://chat.openai.com", "default_origin": "https://chat.openai.com",
@@ -33,6 +34,7 @@ pub const DEFAULT_CHAT_CONF_MAC: &str = r#"{
"auto_update": "Prompt", "auto_update": "Prompt",
"theme": "Light", "theme": "Light",
"titlebar": false, "titlebar": false,
"popup_search": true,
"global_shortcut": "", "global_shortcut": "",
"hide_dock_icon": false, "hide_dock_icon": false,
"default_origin": "https://chat.openai.com", "default_origin": "https://chat.openai.com",
@@ -41,18 +43,6 @@ pub const DEFAULT_CHAT_CONF_MAC: &str = r#"{
"ua_tray": "" "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)] #[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
pub struct ChatConfJson { pub struct ChatConfJson {
// support macOS only // support macOS only
@@ -63,6 +53,7 @@ pub struct ChatConfJson {
pub theme: String, pub theme: String,
// auto update policy, Prompt/Silent/Disable // auto update policy, Prompt/Silent/Disable
pub auto_update: String, pub auto_update: String,
pub popup_search: bool,
pub stay_on_top: bool, pub stay_on_top: bool,
pub default_origin: String, pub default_origin: String,
pub origin: String, pub origin: String,

View File

@@ -8,8 +8,9 @@ mod conf;
mod utils; mod utils;
use app::{cmd, fs_extra, menu, setup}; use app::{cmd, fs_extra, menu, setup};
use conf::{ChatConfJson, ChatState}; use conf::ChatConfJson;
use tauri::api::path; use tauri::api::path;
use tauri_plugin_autostart::MacosLauncher;
use tauri_plugin_log::{ use tauri_plugin_log::{
fern::colors::{Color, ColoredLevelConfig}, fern::colors::{Color, ColoredLevelConfig},
LogTarget, LoggerBuilder, LogTarget, LoggerBuilder,
@@ -20,7 +21,6 @@ async fn main() {
ChatConfJson::init(); ChatConfJson::init();
// If the file does not exist, creating the file will block menu synchronization // If the file does not exist, creating the file will block menu synchronization
utils::create_chatgpt_prompts(); utils::create_chatgpt_prompts();
let chat_conf = ChatConfJson::get_chat_conf();
let context = tauri::generate_context!(); let context = tauri::generate_context!();
let colors = ColoredLevelConfig { let colors = ColoredLevelConfig {
error: Color::Red, error: Color::Red,
@@ -34,11 +34,7 @@ async fn main() {
// https://github.com/tauri-apps/tauri/pull/2736 // https://github.com/tauri-apps/tauri/pull/2736
.plugin( .plugin(
LoggerBuilder::new() LoggerBuilder::new()
.level(if cfg!(debug_assertions) { .level(log::LevelFilter::Debug)
log::LevelFilter::Debug
} else {
log::LevelFilter::Trace
})
.with_colors(colors) .with_colors(colors)
.targets([ .targets([
// LogTarget::LogDir, // LogTarget::LogDir,
@@ -49,7 +45,6 @@ async fn main() {
]) ])
.build(), .build(),
) )
.manage(ChatState::default(chat_conf))
.invoke_handler(tauri::generate_handler![ .invoke_handler(tauri::generate_handler![
cmd::drag_window, cmd::drag_window,
cmd::fullscreen, cmd::fullscreen,
@@ -68,11 +63,16 @@ async fn main() {
cmd::sync_prompts, cmd::sync_prompts,
cmd::sync_user_prompts, cmd::sync_user_prompts,
cmd::window_reload, cmd::window_reload,
cmd::dalle2_window,
cmd::cmd_list, cmd::cmd_list,
fs_extra::metadata, fs_extra::metadata,
]) ])
.setup(setup::init) .setup(setup::init)
.plugin(tauri_plugin_positioner::init()) .plugin(tauri_plugin_positioner::init())
.plugin(tauri_plugin_autostart::init(
MacosLauncher::LaunchAgent,
None,
))
.menu(menu::init()) .menu(menu::init())
.system_tray(menu::tray_menu()) .system_tray(menu::tray_menu())
.on_menu_event(menu::menu_handler) .on_menu_event(menu::menu_handler)
@@ -81,13 +81,18 @@ async fn main() {
// https://github.com/tauri-apps/tauri/discussions/2684 // https://github.com/tauri-apps/tauri/discussions/2684
if let tauri::WindowEvent::CloseRequested { api, .. } = event.event() { if let tauri::WindowEvent::CloseRequested { api, .. } = event.event() {
let win = event.window(); let win = event.window();
if win.label() == "main" { if win.label() == "core" {
win.close().unwrap();
} else {
// TODO: https://github.com/tauri-apps/tauri/issues/3084 // TODO: https://github.com/tauri-apps/tauri/issues/3084
// event.window().hide().unwrap(); // event.window().hide().unwrap();
// https://github.com/tauri-apps/tao/pull/517 // https://github.com/tauri-apps/tao/pull/517
#[cfg(target_os = "macos")]
event.window().minimize().unwrap(); 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(); api.prevent_close();
} }

View File

@@ -130,7 +130,8 @@ pub async fn get_data(
} }
} }
pub fn run_check_update(app: AppHandle<Wry>, silent: bool) -> Result<()> { 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 { tauri::async_runtime::spawn(async move {
let result = app.updater().check().await; let result = app.updater().check().await;
let update_resp = result.unwrap(); let update_resp = result.unwrap();
@@ -144,15 +145,23 @@ pub fn run_check_update(app: AppHandle<Wry>, silent: bool) -> Result<()> {
prompt_for_install(app, update_resp).await.unwrap(); 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",
);
}
} }
}); });
Ok(())
} }
// Copy private api in tauri/updater/mod.rs. TODO: refactor to public api // 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 // 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. // 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<()> { pub async fn prompt_for_install(app: AppHandle<Wry>, update: UpdateResponse<Wry>) -> Result<()> {
info!("prompt_for_install");
let windows = app.windows(); let windows = app.windows();
let parent_window = windows.values().next(); let parent_window = windows.values().next();
let package_info = app.package_info().clone(); let package_info = app.package_info().clone();
@@ -199,6 +208,7 @@ Release Notes:
} }
pub async fn silent_install(app: AppHandle<Wry>, update: UpdateResponse<Wry>) -> Result<()> { pub async fn silent_install(app: AppHandle<Wry>, update: UpdateResponse<Wry>) -> Result<()> {
info!("silent_install");
let windows = app.windows(); let windows = app.windows();
let parent_window = windows.values().next(); let parent_window = windows.values().next();

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -7,7 +7,7 @@
}, },
"package": { "package": {
"productName": "ChatGPT", "productName": "ChatGPT",
"version": "0.7.4" "version": "0.8.1"
}, },
"tauri": { "tauri": {
"allowlist": { "allowlist": {
@@ -75,4 +75,4 @@
"pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IEIxMjY4OUI5MTVFNjBEMDUKUldRRkRlWVZ1WWttc1NGWEE0RFNSb0RqdnhsekRJZTkwK2hVLzhBZTZnaHExSEZ1ZEdzWkpXTHkK" "pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IEIxMjY4OUI5MTVFNjBEMDUKUldRRkRlWVZ1WWttc1NGWEE0RFNSb0RqdnhsekRJZTkwK2hVLzhBZTZnaHExSEZ1ZEdzWkpXTHkK"
} }
} }
} }

View File

@@ -47,6 +47,7 @@ export function useCacheModel(file = '') {
const list = await invoke('cmd_list'); const list = await invoke('cmd_list');
await writeJSON(CHAT_MODEL_CMD_JSON, { name: 'ChatGPT CMD', last_updated: Date.now(), data: 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: 'core' });
await invoke('window_reload', { label: 'tray' });
}; };
return { modelCacheJson, modelCacheSet, modelCacheCmd }; return { modelCacheJson, modelCacheSet, modelCacheCmd };

View File

@@ -26,7 +26,7 @@ export default function ChatLayout() {
}) })
const checkAppUpdate = async () => { const checkAppUpdate = async () => {
await invoke('run_check_update', { silent: false }); await invoke('run_check_update', { silent: false, hasMsg: true });
} }
return ( return (

41
src/view/General.tsx vendored
View File

@@ -14,12 +14,12 @@ const AutoUpdateLabel = () => {
return ( return (
<span> <span>
Auto Update <Tooltip title={( Auto Update <Tooltip title={(
<div> <div>
<div>Auto Update Policy</div> <div>Auto Update Policy</div>
<span><strong>Prompt</strong>: prompt to install</span><br/> <span><strong>Prompt</strong>: prompt to install</span><br/>
<span><strong>Silent</strong>: install silently</span><br/> <span><strong>Silent</strong>: install silently</span><br/>
{/*<span><strong>Disable</strong>: disable auto update</span><br/>*/} {/*<span><strong>Disable</strong>: disable auto update</span><br/>*/}
</div> </div>
)}><QuestionCircleOutlined style={{ color: '#1677ff' }} /></Tooltip> )}><QuestionCircleOutlined style={{ color: '#1677ff' }} /></Tooltip>
</span> </span>
) )
@@ -33,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 ( return (
<div> <div>
Global Shortcut Global Shortcut
@@ -122,6 +137,9 @@ export default function General() {
<Switch /> <Switch />
</Form.Item> </Form.Item>
)} )}
<Form.Item label={<PopupSearchLabel />} name="popup_search" valuePropName="checked">
<Switch />
</Form.Item>
<Form.Item label="Theme" name="theme"> <Form.Item label="Theme" name="theme">
<Radio.Group> <Radio.Group>
<Radio value="Light">Light</Radio> <Radio value="Light">Light</Radio>
@@ -138,7 +156,7 @@ export default function General() {
{/*<Radio value="Disable">Disable</Radio>*/} {/*<Radio value="Disable">Disable</Radio>*/}
</Radio.Group> </Radio.Group>
</Form.Item> </Form.Item>
<Form.Item label={<GlobalShortcut />} name="global_shortcut"> <Form.Item label={<GlobalShortcutLabel />} name="global_shortcut">
<Input placeholder="CmdOrCtrl+Shift+O" {...DISABLE_AUTO_COMPLETE} /> <Input placeholder="CmdOrCtrl+Shift+O" {...DISABLE_AUTO_COMPLETE} />
</Form.Item> </Form.Item>
<Form.Item label={<OriginLabel url={chatConf?.default_origin} />} name="origin"> <Form.Item label={<OriginLabel url={chatConf?.default_origin} />} name="origin">
@@ -153,11 +171,8 @@ export default function General() {
<Form.Item> <Form.Item>
<Space size={20}> <Space size={20}>
<Button onClick={onCancel}>Cancel</Button> <Button onClick={onCancel}>Cancel</Button>
<Button type="primary" htmlType="submit">Submit</Button>
<Button type="primary" htmlType="submit"> <Button type="dashed" onClick={onReset}>Reset to defaults</Button>
Submit
</Button>
<a onClick={onReset}>Reset to defaults</a>
</Space> </Space>
</Form.Item> </Form.Item>