diff --git a/Cargo.lock b/Cargo.lock index 341d19a..fe14d65 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -133,7 +133,7 @@ dependencies = [ [[package]] name = "air" -version = "0.2.0" +version = "0.3.0" dependencies = [ "app_dirs2", "arboard", diff --git a/Cargo.toml b/Cargo.toml index a6487f0..6a03737 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,12 +7,15 @@ license = "GPL-3.0" name = "air" readme = "README.md" repository = "https://github.com/hack-ink/air" -version = "0.2.0" +version = "0.3.0" [package.metadata.bundle] -icon = ["asset/icon.png"] -identifier = "ink.hack.AiR" -name = "AiR" +icon = ["asset/icon.icns"] +identifier = "ink.hack.AiR" +long_description = "AI with Rust." +name = "AiR" +short_description = "AI with Rust." +version = "0.3.0" [profile.ci-dev] incremental = false diff --git a/README-zh-CN.md b/README-zh-CN.md new file mode 100644 index 0000000..23857eb --- /dev/null +++ b/README-zh-CN.md @@ -0,0 +1,224 @@ +
+ +# AiR +

AI with Rust |

+ +[![License](https://img.shields.io/badge/License-GPLv3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0) +[![Checks](https://github.com/hack-ink/air/actions/workflows/checks.yml/badge.svg?branch=main)](https://github.com/hack-ink/air/actions/workflows/checks.yml) +[![Release](https://github.com/hack-ink/air/actions/workflows/release.yml/badge.svg)](https://github.com/hack-ink/air/actions/workflows/release.yml) +[![GitHub tag (latest by date)](https://img.shields.io/github/v/tag/hack-ink/air)](https://github.com/hack-ink/air/tags) +[![GitHub last commit](https://img.shields.io/github/last-commit/hack-ink/air?color=red&style=plastic)](https://github.com/hack-ink/air) + +这款完全用 Rust 构建的 AiR 提供了惊人的速度和效率! + +AiR 拥有两个主要功能:准确的翻译和无缝的文本重写,旨在极大地提升您的生产力。 + +AiR 是非母语者的绝佳助手,能够自动修正错误并润色语言,使其听起来像母语使用者。 + +更多精彩功能即将推出! + +[English](README.md) | [中文](README-zh-CN.md) + +本章节完全由 AiR 翻译生成,如有错误请提交 issue 或 PR 进行修正。 +
+ + +## 功能亮点 +### 直接重写 +![rewrite-directly](demo/rewrite-directly.gif) + +### 直接翻译 +![translate-directly](demo/translate-directly.gif) + + +## 状态 +- **操作系统** + - [x] **macOS** + - [ ] **Windows** (即将推出) + - [ ] **Unix** +- **功能** + - [x] **重写** + - [x] **直接重写** + - [x] **翻译** + - [x] **直接翻译** + - [ ] **重构代码** (即将推出) + - [ ] **光学字符识别**(计划中) + - [ ] **文字转语音**(已计划) + + +## 用法 +### 安装 +#### 从源代码构建 +```sh +# 安装 Rust。 +curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- --default-toolchain stable + +# 克隆代码库。 +git clone https://github.com/hack-ink/air +cd air + +# 构建项目后,二进制文件将位于 `target/release/air`。 +cargo build --release + +# 如果您是 macOS 用户并且想拥有一个 `AiR.app`,请运行以下命令。 +# 安装 `cargo-bundle` 将二进制文件打包成应用程序。 +cargo install cargo-bundle +# 构建应用程序后,它将位于 `target/release/bundle/osx/AiR.app`。 +cargo bundle --release +``` + +#### 下载预构建二进制文件 +- **macOS** + - 从 [GitHub Releases](https://github.com/hack-ink/air/releases/latest) 下载最新的预构建二进制文件。 +- **Windows** + - 即将推出 +- **Unix** + - 已计划 + +### 配置 +#### 打开来自未识别开发者的 Mac 应用程序(仅限 macOS) +当您第一次打开应用时,您会看到以下消息: + +`“AiR” 无法打开,因为无法验证开发者。` + +由于我不是认证开发者,您需要允许该应用在您的 Mac 上运行。 + +请请我喝杯咖啡,以便我能获得一个 Apple 开发者证书。 😄 + +1. `打开“系统偏好设置” -> “隐私与安全性”。` +2. `请向下滚动到 ‘“AiR” 因不是来自已识别的开发者而被阻止使用’ 部分。` +3. `点击 “仍然打开”。` + +相关资源: +- [打开来自未识别开发者的 Mac 应用程序 (support.apple.com)](https://support.apple.com/en-hk/guide/mac-help/mh40616/mac) +- [如何打开来自未识别开发者的 Mac 应用程序 (macworld.com)](https://www.macworld.com/article/672947/how-to-open-a-mac-app-from-an-unidentified-developer.html) + +#### 获取系统辅助功能权限(仅限 macOS) +要控制键盘并使用系统剪贴板进行数据读写, +AiR 必须获得系统辅助功能权限。 + +1. `打开 “系统设置” -> “隐私与安全” -> “辅助功能”。` +2. `点击 “+” 按钮,然后添加 “AiR.app” 或 “air” 二进制文件。` + +#### 设置 +你可以通过导航到 “设置” 面板来配置设置。 + +- 通用 + - 字体大小 + - 失去焦点时隐藏:当应用程序失去焦点时隐藏它。 + - 激活的功能:使用非直接功能时启用的功能。 +- AI + - API 基础:AI API 的基本 URL。确保不要忘记 `v1` 部分。(例如:https://api.openai.com/v1)。 + - API 密钥:AI API 密钥。 + - 模型:AI 模型。 + - 温度:人工智能的不可预测性。 +- 翻译 + - 语言 A:您希望从/向 B 翻译的语言。 + - 语言 B:您希望从/向 A 翻译的语言。 +- 快捷键 + - 重写​ + - 直接重写​ + - 翻译​ + - 直接翻译 +- 开发 + - 日志级别 + +AiR目前正在进行大量开发,并非所有设置都会在用户界面中始终可用。 + +然而,所有设置始终可以在设置文件中找到。 + +设置文件的位置因操作系统而异。 +- `~/Library/Application\ Support/AiR/setting.toml` (macOS) +- `C:\Users\\AppData\Roaming\AiR\setting.toml` (Windows) +- `~/.config/AiR/setting.toml` (Unix) + +#### 交互 +在输入区域中键入文本,然后在 macOS 上按 `META+ENTER` 或在其他操作系统上按 `CTRL+ENTER` 以触发相应的功能。 + +您还可以选择文本并使用快捷键直接对选定的文本应用相应的功能。 + +### 更新 +正在开发自动更新功能。 + +目前,您可以通过重复安装步骤手动更新应用程序。 + +#### 重新获得系统访问权限(仅适用于macOS) +1. `按照 “获取系统访问权限” 部分找到 “AiR.app” 或 “air” 二进制文件。` +2. `点击 “-” 按钮以移除现有权限,然后点击 “+” 按钮重新添加权限。` + + +## 开发 +### 架构 +
+ +```mermaid +graph TD + A[AiR] + A --> B[组件] + A --> C[操作系统] + A --> D[服务] + A --> E[状态] + A --> F[用户界面] + B --> B1[数据结构] + C --> C1[macOS/Unix/Windows] + D --> D1[后台进程] + E --> E1[同步] + F --> F1[交互] +``` + +**基于 [egui](https://github.com/emilk/egui),这是一个用纯 Rust 编写的快速跨平台 GUI 工具包。** +
+ +- **组件** + - 提供程序其他部分使用的基本数据结构和函数。 + - 组件应该是静态的,不要包含任何可变状态。 +- **操作系统** + - 提供与操作系统交互的封装API。 + - 需要在此处理操作系统之间的差异,并以总结、抽象的方式呈现。 +- **服务** + - 提供后台任务能力,使其可以独立于 UI 运行。 + - 服务有一个或多个对缓存组件的要求,以节省系统资源、执行频繁的检查或更新,以及处理时间敏感的任务。 + - 与 UI 设置相关的服务应提供热重载功能,以便在 UI 上更改设置时,立即应用这些更改。 + - 服务应包含中止功能,以停止服务,并且在程序退出时应调用此功能,以防止其停滞。 +- **状态** + - 提供可变性,可以在整个程序中同步和共享。 + - 状态应该是 `Arc>` 或 `Arc`。 +- **用户界面** + - 为用户提供与其他部分互动的能力。 + + +## 支持我 +如果您觉得这个项目有帮助,并且希望支持其开发,可以请我喝杯咖啡! + +您的支持非常感谢,并激励我不断改进这个项目。 + +- **法币** + - [Ko-fi](https://ko-fi.com/aurevoirxavier) + - [爱发电](https://afdian.net/a/AurevoirXavier) +- **加密货币** + - **Bitcoin** + - `bc1pedlrf67ss52md29qqkzr2avma6ghyrt4jx9ecp9457qsl75x247sqcp43c` + - **Ethereum** + - `0x3e25247CfF03F99a7D83b28F207112234feE73a6` + - **Polkadot** + - `156HGo9setPcU2qhFMVWLkcmtCEGySLwNqa3DaEiYSWtte4Y` + +感谢您的支持! + + +## 感谢 +我们要向以下项目和贡献者表达由衷的感谢: +- [egui](https://github.com/emilk/egui) 为我们的 GUI 提供了基础。 +- Rust 社区对 Rust 生态系统的持续支持和开发。 + + +## 其他鸣谢​ +- 感谢 [OpenAI Translator](https://github.com/openai-translator/openai-translator) 为本工作提供灵感。 +- 通过 [recraft.ai](https://app.recraft.ai) 创建的精彩图标。 + + +
+ +#### 许可证 +根据 [GPL-3.0](LICENSE) 许可进行授权。 +
diff --git a/README.md b/README.md index 9bfc49a..4f447d0 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,6 @@
# AiR -

AI with Rust |

[![License](https://img.shields.io/badge/License-GPLv3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0) @@ -10,26 +9,214 @@ [![GitHub tag (latest by date)](https://img.shields.io/github/v/tag/hack-ink/air)](https://github.com/hack-ink/air/tags) [![GitHub last commit](https://img.shields.io/github/last-commit/hack-ink/air?color=red&style=plastic)](https://github.com/hack-ink/air) +Built entirely in Rust, AiR delivers blazing speed and efficiency! + +AiR boasts two main features: accurate translation and seamless text rewriting, designed to supercharge your productivity. + +AiR is a great assistant for non-native speakers, automatically fixing errors and polishing language to sound like a native speaker. + +More awesome features are on the horizon! + +[English](README.md) | [中文](README-zh-CN.md) +
+ + +## Feature Highlights +### Rewrite Directly +![rewrite-directly](demo/rewrite-directly.gif) + +### Translate Directly +![translate-directly](demo/translate-directly.gif) + + +## Status +- **OS** + - [x] **macOS** + - [ ] **Windows** (Coming Soon) + - [ ] **Unix** +- **Features** + - [x] **Rewrite** + - [x] **Rewrite Directly** + - [x] **Translate** + - [x] **Translate Directly** + - [ ] **Refactor Code** (Coming Soon) + - [ ] **OCR** (Planed) + - [ ] **TTS** (Planed) + + +## Usage +### Installation +#### Build from Source +```sh +# Install Rust. +curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- --default-toolchain stable + +# Clone the repository. +git clone https://github.com/hack-ink/air +cd air + +# Build the project, and the binary will be available at `target/release/air`. +cargo build --release + +# If you are a macOS user and want to have a `AiR.app`, run the following command. +# Install `cargo-bundle` to package the binary into an app. +cargo install cargo-bundle +# Build the app, and the it will be available at `target/release/bundle/osx/AiR.app`. +cargo bundle --release +``` + +#### Download Pre-built Binary +- **macOS** + - Download the latest pre-built binary from [GitHub Releases](https://github.com/hack-ink/air/releases/latest). +- **Windows** + - Coming Soon +- **Unix** + - Planed + +### Configuration +#### Open a Mac app from an unidentified developer (macOS only) +When you open the app for the first time, you'll see the following message: + +`"AiR" cannot be opened because the developer cannot be verified.` + +Since I'm not an identified developer, you need to allow the app to run on your Mac. + +Buy me a coffee so I can get an Apple Developer Certificate. 😄 + +1. `Open "System Preferences" -> "Privacy & Security".` +2. `Scroll down to the '"AiR" was blocked from use because it is not from an identified developer.' section.` +3. `Click "Open Anyway".` + +Relate resources: +- [Open a Mac app from an unidentified developer (support.apple.com)](https://support.apple.com/en-hk/guide/mac-help/mh40616/mac) +- [How to open a Mac app from an unidentified developer (macworld.com)](https://www.macworld.com/article/672947/how-to-open-a-mac-app-from-an-unidentified-developer.html) + +#### Gain System Accessibility Permission (macOS only) +To control the keyboard and use the system clipboard for reading and writing data, +AiR must obtain system accessibility permissions. + +1. `Open "System Settings" -> "Privacy & Security" -> "Accessibility".` +2. `Click the "+" button and add the "AiR.app" or "air" binary.` + +#### Setting +You can configure the settings by navigating to the "Settings" panel. + +- General + - Font Size + - Hide on Lost Focus: Hide the app when it loses focus. + - Active Function: The active function when using non-directly functions. +- AI + - API Base: The base URL of the AI API. It's crucial to ensure you don't forget the `v1` part. (e.g., https://api.openai.com/v1). + - API Key: The AI API key. + - Model: The AI model. + - Temperature: The unpredictability of AI. +- Translation + - Language A: The language you want to translate from/to B. + - Language B: The language you want to translate from/to A. +- Hotkey + - Rewrite + - Rewrite Directly + - Translate + - Translate Directly +- Development + - Log Level + +AiR is currently under heavy development, and not all settings are always available in the user interface. + +However, all settings can always be found in the settings file. + +The location of the settings file varies depending on the OS. +- `~/Library/Application\ Support/AiR/setting.toml` (macOS) +- `C:\Users\\AppData\Roaming\AiR\setting.toml` (Windows) +- `~/.config/AiR/setting.toml` (Unix) + +#### Interaction +Type the text in the input area and press `META+ENTER` on macOS or `CTRL+ENTER` on other OS to trigger the corresponding function. + +You can also select text and use hotkeys to directly apply the corresponding function to the selected text. + +### Update +An automatic update feature is under development. + +For now, you can manually update the app by repeating the installation steps. + +#### Re-gain System Accessibility Permission (macOS only) +1. `Follow the "Gain System Accessibility Permission" section to locate the "AiR.app" or "air" binary.` +2. `Click the "-" button to remove the existing permission, then click the "+" button to re-add it.` + + +## Development +### Architecture +
+ +```mermaid +graph TD + A[AiR] + A --> B[Components] + A --> C[OS] + A --> D[Services] + A --> E[State] + A --> F[UI] + B --> B1[Data Structures] + C --> C1[macOS/Unix/Windows] + D --> D1[Background Processes] + E --> E1[Synchronization] + F --> F1[Interaction] +``` + +**Built upon [egui](https://github.com/emilk/egui), a fast and cross-platform GUI toolkit written in pure Rust.**
-## Architecture -Built upon [egui](https://github.com/emilk/egui), a fast and cross-platform GUI toolkit written in pure Rust. +- **Components** + - Provides the basic data structures and functions used by other parts of the program. + - Component should be static, don't include any mutable state. +- **OS** + - Provides wrapped APIs to interact with the OS. + - Differences between OS should be addressed here and presented in a summarized, abstract manner. +- **Services** + - Provides background tasks ability to run independently of the UI. + - Service has one or more requirements for a cache component to conserve system resources, perform frequent checks or updates, and handle time-sensitive tasks. + - Service related to UI settings should provide a hot reload function so that when a setting is changed on UI, the changes are applied immediately. + - Service should include an abort function to stop the service, and it should be called when exiting the program. to prevent it from stalling. +- **State** + - Provides mutability that can be synchronized and shared throughout the entire program. + - State should be `Arc>` or `Arc`. +- **UI** + - Provides the interaction ability of other parts for users. + -### Components -- **Static**: These items are static and are used by other parts of the application. +## Support Me +If you find this project helpful and would like to support its development, you can buy me a coffee! -### OS -- **Interaction**: Provides wrapped APIs to interact with the operating system. +Your support is greatly appreciated and motivates me to keep improving this project. -### Services -- **Background Processes**: These items are time-sensitive and require frequent checking or updating. They will be spawned as separate threads and run in the background. +- **Fiat** + - [Ko-fi](https://ko-fi.com/aurevoirxavier) + - [爱发电](https://afdian.net/a/AurevoirXavier) +- **Crypto** + - **Bitcoin** + - `bc1pedlrf67ss52md29qqkzr2avma6ghyrt4jx9ecp9457qsl75x247sqcp43c` + - **Ethereum** + - `0x3e25247CfF03F99a7D83b28F207112234feE73a6` + - **Polkadot** + - `156HGo9setPcU2qhFMVWLkcmtCEGySLwNqa3DaEiYSWtte4Y` -### State -- **Synchronization**: Mutable version of the components. Usually, they are `Arc>` in order to sync the state between service and UI. +Thank you for your support! -### UI -- **User Interface**: The user interface components. +## Appreciation +We would like to extend our heartfelt gratitude to the following projects and contributors: +- [egui](https://github.com/emilk/egui) for providing the foundation for our GUI. +- The Rust community for their continuous support and development of the Rust ecosystem. -## License -AiR is licensed under the [GPLv3](https://www.gnu.org/licenses/gpl-3.0) license. + +## Additional Acknowledgements +- [OpenAI Translator](https://github.com/openai-translator/openai-translator) for providing the inspiration for this work. +- The awesome icon created through [recraft.ai](https://app.recraft.ai). + + +
+ +#### License +Licensed under [GPL-3.0](LICENSE). +
diff --git a/asset/icon.icns b/asset/icon.icns new file mode 100644 index 0000000..efd04d5 Binary files /dev/null and b/asset/icon.icns differ diff --git a/demo/demo.txt b/demo/demo.txt new file mode 100644 index 0000000..b3ed39d --- /dev/null +++ b/demo/demo.txt @@ -0,0 +1,59 @@ +default hotkey fOr rewrite-directly is CTRL+Y. +Afer press the hotky, +AiR will triger CTRL+C/META+C (depending on your OS) to geet the selected text. +Than it wil start itss jooob! + + + +The default hotkey for rewrite directly is CTRL+Y. +After pressing the hotkey, +AiR will trigger CTRL+C/META+C (depending on your OS) to get the selected text. +Then it will start its job! + + +默认的直接翻译热键是 CTRL+I。 +按下热键后, +AiR 将触发 CTRL+C/META+C(取决于您的操作系统), +以获取选中的文本,然后它将开始执行其任务! + + + +The default direct translate hotkey is CTRL+I. +Upon pressing the hotkey, +AiR will trigger CTRL+C/META+C (depending on your operating system), +to capture the selected text, then it will begin performing its task! + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/demo/rewrite-directly.gif b/demo/rewrite-directly.gif new file mode 100644 index 0000000..5cdabc6 Binary files /dev/null and b/demo/rewrite-directly.gif differ diff --git a/demo/translate-directly.gif b/demo/translate-directly.gif new file mode 100644 index 0000000..82642ae Binary files /dev/null and b/demo/translate-directly.gif differ diff --git a/src/component.rs b/src/component.rs index 25264dc..5831cec 100644 --- a/src/component.rs +++ b/src/component.rs @@ -13,8 +13,6 @@ pub mod quote; pub mod setting; use setting::Setting; -pub mod util; - // std use std::fmt::{Debug, Formatter, Result as FmtResult}; // crates.io diff --git a/src/component/setting.rs b/src/component/setting.rs index 2fd58e8..2fea6a2 100644 --- a/src/component/setting.rs +++ b/src/component/setting.rs @@ -103,6 +103,7 @@ impl Rewrite { Text is always provided in format `$TEXT`! \ $TEXT can be provided in any style! \ Discard the `` tag! \ + But keep the indentation and line breaks format! \ Extract the $TEXT and return the refined $TEXT only!"; if self.additional_prompt.is_empty() { @@ -130,6 +131,7 @@ impl Translation { Text is always provided in format `$TEXT`! \ $TEXT can be provided in any style! \ Discard the `` tag! \ + But keep the indentation and line breaks format! \ Extract the $TEXT and return the translated $TEXT only!", self.a.as_str(), self.b.as_str(), diff --git a/src/component/util.rs b/src/component/util.rs deleted file mode 100644 index 4cee521..0000000 --- a/src/component/util.rs +++ /dev/null @@ -1,3 +0,0 @@ -pub fn price_rounded(value: f32) -> f32 { - (value * 1_000_000.).round() / 1_000_000. -} diff --git a/src/ui/panel/chat.rs b/src/ui/panel/chat.rs index 9cbdc05..bbc8313 100644 --- a/src/ui/panel/chat.rs +++ b/src/ui/panel/chat.rs @@ -4,11 +4,7 @@ use std::sync::atomic::Ordering; use eframe::egui::*; // self use super::super::UiT; -use crate::{ - air::AiRContext, - component::{openai::Model, util}, - widget, -}; +use crate::{air::AiRContext, component::openai::Model, util, widget}; #[derive(Debug, Default)] pub struct Chat { diff --git a/src/util.rs b/src/util.rs index 62d8def..6778d97 100644 --- a/src/util.rs +++ b/src/util.rs @@ -1,6 +1,10 @@ // crates.io use eframe::egui::*; +pub fn price_rounded(value: f32) -> f32 { + (value * 1_000_000.).round() / 1_000_000. +} + // TODO?: transparent window. #[allow(unused)] pub fn transparent_frame(ctx: &Context) -> Frame {