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 {