Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 24 additions & 58 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,27 +1,25 @@
# AutoEngine Core

AutoEngine Core is an asynchronous Rust engine for driving desktop automation pipelines. It executes YAML workflows that combine image recognition, mouse/keyboard control, conditional logic, and optional Tauri event emission. The crate can be embedded in a GUI application or run headlessly, making it a flexible foundation for custom automation tools.
AutoEngine Core is an asynchronous Rust engine centered on workflow orchestration: it describes automation steps with workflow graphs, schedules node capabilities (image recognition, mouse/keyboard, timed waits, WASM plugins, etc.) and condition controls, and emits events to upper-layer UIs when needed. You can embed it in a GUI or run it headless to build automation assistants or script conversion tools.

## Highlights
- Stage-based pipelines expressed in YAML with `Start`, `ImageRecognition`, `MouseMove`, `MouseClick`, `KeyBoard`, and `TimeWait` nodes.
- Built-in context store with `${var:default}` interpolation so later actions can reuse data captured by previous stages.
- OpenCV-powered template matching with configurable resize/imread options plus on-demand screen captures via the `screenshots` crate.
- Mouse and keyboard automation through Enigo, including press/hold, clicks, and text input with retry/backoff controls.
- Optional Tauri integration that emits per-node events (running, skip, done, error, cancel) for UI feedback.
- Tokio-based executor with cancellation tokens, rate limiting, and looped execution for long-running bots.
## Highlights (Orchestration Focus)
- **DAG orchestration**: A workflow consists of a node list and connections. The entry node is usually `Start`; built-in action nodes cover image recognition, mouse move/click, keyboard input, timed waits, and pluggable WASM nodes. Custom capabilities are supported.
- **Context-driven data flow**: The built-in `Context` supports `${var:default}` interpolation. Node outputs are automatically written so later nodes can reuse coordinates, state, or custom fields with zero boilerplate.
- **Runtime controls**: `WorkflowRunner` offers async execution, retries/intervals, looping, minimum timeslice constraints, and cancellation tokens for long-running automation tasks.
- **Observable events**: The optional `tauri` feature emits node-level events (running/skip/done/error/cancel) so UIs can visualize progress and results.
- **Pluggable capabilities**: Image matching is backed by OpenCV and I/O actions use Enigo, but both are injected as “node capabilities” so the orchestration layer stays simple and replaceable.

## How It Works
1. **Pipeline definition** – Pipelines are lists of stages; each stage contains one or more nodes (actions). Pipelines normally live next to their supporting assets (for example, under `pipeline/image/*.png` for template matching).
2. **Context & variables** – Each node can write to the shared `Context`, and later nodes reference those values using `${stage.image.png.x}` style placeholders or default fallbacks (`${value:0}`).
3. **Conditions** – Nodes may specify `exist`, `not_exist`, or boolean expressions (`condition: "${foo} > 10"`) that gate execution.
4. **Runner** – `PipelineRunner` spins up asynchronous tasks, handles retries, enforces minimum loop intervals, and supports cancellation via `tokio_util::sync::CancellationToken`.
5. **Events** – When compiled with the `tauri` feature the engine emits structured node events so host applications can visualize progress.
1. **Workflow definition**: The workflow is a DAG. `nodes` describe actions and metadata (name, retries, intervals, conditions, etc.), and `connections` link `from` to `to`. Resource files are best stored next to the workflow in `files/` (for example `workflow/files/*.png`).
2. **Context and variables**: Nodes write detection results or computed values into `Context`, later read as `${detect-dot.dot.png.x}`. Defaults are supported via `${value:0}`.
3. **Conditions and branching**: Nodes support existence/non-existence checks and expressions (`condition: "${foo} > 10"`), enabling branching and short-circuiting without extra scripts.
4. **Runner**: `WorkflowRunner` handles async scheduling, retries, throttling, cancellation, and looped execution; enable tauri event output when UI feedback is required.

## Getting Started
Prerequisites:
- Rust 1.80+ (edition 2024 workspace).
- A working OpenCV toolchain (the [`opencv` crate](https://docs.rs/opencv) expects the native libraries to be installed, e.g., `brew install opencv` on macOS or `apt install libopencv-dev` on Debian/Ubuntu).
- (Optional) Tauri 2.x if you plan to embed the crate in a Tauri application.
- OpenCV runtime (the [`opencv` crate](https://docs.rs/opencv) needs system libraries such as `brew install opencv` or `apt install libopencv-dev`).
- Optional: Tauri 2.x when you need event emission or main-thread keyboard handling.

Build and test the workspace:

Expand All @@ -30,59 +28,27 @@ cargo build -p auto-engine-core
cargo test -p auto-engine-core
```

### Example Pipeline
```yaml
- stage:
- action_type: Start
name: "main"
conditions: ""
- stage:
- action_type: ImageRecognition
name: "find-dot"
retry: -1
interval: 0
params:
images:
- "dot.png"
sub_pipeline: ""
- stage:
- action_type: MouseMove
name: "Move cursor to dot"
retry: 2
params:
x: "${find-dot.dot.png.x}"
y: "${find-dot.dot.png.y}"
conditions:
exist: "find-dot.dot.png"
```

Key ideas demonstrated above:
- Image recognition nodes can look for multiple templates; their results (coordinates, scores) are stored automatically in the context.
- Mouse/keyboard nodes can reference those coordinates through `${...}` expressions and gate execution using conditions.
- `retry` and `interval` allow each action to handle flaky inputs without bringing down the entire pipeline.

### Feature Flags
The crate exposes several opt-in modules. By default all of them are enabled:
Workflow orchestration is core; the following feature flags trim capabilities (all enabled by default):

| Feature | Description |
|------------|-------------|
| `types` | Data structures for nodes, stages, and pipelines. |
| `context` | Shared context store and helpers. |
| `event` | Node event payloads. |
| `pipeline` | Pipeline runner orchestration. |
| `runner` | Mouse, keyboard, and image recognition executors. |
| `utils` | Variable parsing utilities and helpers. |
| `tauri` | Enables Tauri-specific integrations such as main-thread keyboard handling and event emission. |
| `types` | Workflow/node data structures. |
| `context` | Shared context and variable resolution. |
| `event` | Node event definitions. |
| `runner` | Node capability executors (mouse, keyboard, image recognition, etc.). |
| `utils` | Helper utilities such as variable parsing. |
| `tauri` | Main-thread keyboard handling and event emission. |

Disable features in `Cargo.toml` as needed, e.g. `default-features = false` for a minimal build.
Disable features in `Cargo.toml` as needed, e.g. set `default-features = false` for a minimal build.

## Contributing
1. Ensure `cargo fmt` and `cargo clippy` pass locally.
2. Add tests (`cargo test`) whenever you introduce new node types, conditions, or utilities.
3. Document new pipeline actions or DSL additions in this README.
3. Document new workflow actions or DSL additions in this README.

## Miantainer
This project is miantained by CeerDecy(Yuan Haonan), email: [email protected]
## Maintainer
This project is maintained by CeerDecy (Yuan Haonan), email: [email protected].

## License
This project is licensed under the [Apache License 2.0](LICENSE).
95 changes: 32 additions & 63 deletions README_CN.md
Original file line number Diff line number Diff line change
@@ -1,27 +1,25 @@
# AutoEngine Core

AutoEngine Core 是一个基于异步 Rust 的桌面自动化引擎,用于执行由 YAML 描述的工作流。它能够把图像识别、鼠标/键盘控制、条件逻辑以及可选的 Tauri 事件推送组合在一起,既可以嵌入到 GUI 应用中,也能在无界面环境下运行,为自定义自动化工具提供了灵活的内核。

## 核心特性
- 以 Stage 为单位的管线模型,内置 `Start`、`ImageRecognition`、`MouseMove`、`MouseClick`、`KeyBoard`、`TimeWait` 等节点类型。
- 自带上下文存储和 `${var:default}` 插值语法,方便在后续节点中复用上一阶段生成的数据。
- 基于 OpenCV 的模板匹配,支持自定义缩放与 imread 选项,并通过 `screenshots` crate 实时截屏。
- 依托 Enigo 实现鼠标和键盘操作,覆盖点击、按下/松开、文本输入,同时可配置重试与间隔。
- 可选的 Tauri 集成,在每个节点开始/跳过/完成/出错/取消时发送事件,便于 UI 展示执行状态。
- 基于 Tokio 的执行器,内置取消令牌、速率控制与循环执行能力,适合长期运行的自动化脚本。

## 工作原理
1. **定义管线**:管线由若干 Stage 组成,每个 Stage 含有一个或多个节点(动作)。通常会把模板图片等资源放在 `pipeline/image/*.png` 等目录下。
2. **上下文与变量**:节点可向共享 `Context` 写入数据,后续节点通过 `${stage.image.png.x}` 或 `${value:0}`(带默认值)读取。
3. **条件判断**:节点可指定 `exist`、`not_exist` 或布尔表达式(如 `condition: "${foo} > 10"`)来决定是否执行。
4. **运行器**:`PipelineRunner` 使用异步任务驱动执行,处理重试、最小循环间隔,并通过 `tokio_util::sync::CancellationToken` 接收取消信号。
5. **事件通知**:启用 `tauri` 功能后,会向宿主应用发送结构化节点事件,便于可视化进度。

## 快速开始
AutoEngine Core 是一个以“工作流编排”为中心的异步 Rust 引擎:通过节点图(workflow)描述自动化步骤,统一调度节点能力(图像识别、鼠标/键盘、定时等待、WASM 插件等)与条件控制,并在需要时向上层 UI 发出事件。你可以将其嵌入 GUI,也可以无头运行,用以构建自动化助手或脚本转换工具。

## Highlights(聚焦编排)
- **DAG 编排**:Workflow 由节点列表与连接关系构成,入口节点通常为 `Start`,内置动作节点覆盖图像识别、鼠标移动/点击、键盘输入、定时等待,以及可插拔的 WASM 节点;支持自定义能力扩展。
- **上下文驱动的数据流**:内置 `Context` 支持 `${var:default}` 插值,节点输出自动写入,后续节点零样板复用坐标、状态或自定义字段。
- **运行时控制**:`WorkflowRunner` 提供异步执行、重试/间隔、循环运行、最小时间片约束与取消令牌,适合长时间运行的自动化任务。
- **可观察性事件**:可选 `tauri` 特性输出节点级事件(running/skip/done/error/cancel),方便 UI 可视化进度与结果。
- **能力插件化**:图像匹配基于 OpenCV,输入输出动作通过 Enigo,但都作为“节点能力”注入,编排层保持简单和可替换。

## How It Works
1. **Workflow 定义**:workflow 是有向无环图(DAG),`nodes` 描述动作与元数据(名称、重试、间隔、条件等),`connections` 负责连接 `from` 与 `to`。资源文件建议存放在 workflow 旁的 `files/` 目录(如 `workflow/files/*.png`)。
2. **上下文与变量**:节点将检测结果或计算值写入 Context,后续以 `${detect-dot.dot.png.x}` 方式读取,支持默认值 `${value:0}`。
3. **条件与分支**:节点支持存在/不存在判定与表达式(`condition: "${foo} > 10"`),无须额外脚本即可控制分支与短路。
4. **执行器**:`WorkflowRunner` 负责异步调度、重试、节流、取消与循环执行;当需要 UI 反馈时,可开启 tauri 事件输出。

## Getting Started
前置条件:
- Rust 1.80+(工作区使用 2024 edition)。
- 可用的 OpenCV 编译环境(`opencv` crate 依赖本地库,可通过 `brew install opencv``apt install libopencv-dev` 等方式安装)。
- (可选)Tauri 2.x,如果需要将本 crate 嵌入 Tauri 应用
- OpenCV 运行时([`opencv` crate](https://docs.rs/opencv) 需要系统级库,可通过 `brew install opencv``apt install libopencv-dev` 安装)。
- (可选)Tauri 2.x:需要事件上报或主线程键盘处理时开启

构建与测试:

Expand All @@ -30,56 +28,27 @@ cargo build -p auto-engine-core
cargo test -p auto-engine-core
```

### 示例管线
```yaml
- stage:
- action_type: Start
name: "main"
conditions: ""
- stage:
- action_type: ImageRecognition
name: "find-dot"
retry: -1
interval: 0
params:
images:
- "dot.png"
sub_pipeline: ""
- stage:
- action_type: MouseMove
name: "Move cursor to dot"
retry: 2
params:
x: "${find-dot.dot.png.x}"
y: "${find-dot.dot.png.y}"
conditions:
exist: "find-dot.dot.png"
```
### Feature Flags
Workflow 编排为核心能力;下列 feature flags 用于裁剪能力(默认全部启用):

要点说明:
- 图像识别节点可以同时匹配多张模板,坐标与得分会自动写入上下文。
- 鼠标 / 键盘节点可通过 `${...}` 语法引用这些坐标,并结合条件控制执行。
- `retry` 与 `interval` 允许为每个动作配置容错策略,避免单点失败导致整个管线终止。

### 功能开关
该 crate 暴露多个可选模块,默认全部启用:

| Feature | 说明 |
|-----------|------|
| `types` | 节点、Stage、Pipeline 等数据结构。 |
| `context` | 共享上下文及相关工具。 |
| `event` | 节点事件负载定义。 |
| `pipeline`| 管线调度与执行逻辑。 |
| `runner` | 鼠标、键盘、图像识别执行器。 |
| `utils` | 变量解析等辅助工具。 |
| `tauri` | Tauri 集成(主线程键盘调用、事件推送等)。 |
| Feature | Description |
|------------|-------------|
| `types` | Workflow/node 数据结构。 |
| `context` | 共享上下文及变量解析。 |
| `event` | 节点事件定义。 |
| `runner` | 节点能力执行器(鼠标、键盘、图像识别等)。 |
| `utils` | 变量解析等辅助工具。 |
| `tauri` | 主线程键盘处理与事件上报。 |

可在 `Cargo.toml` 中按需关闭,例如设置 `default-features = false` 以获得最小构建。

## 贡献指南
1. 在提交前确保 `cargo fmt` 与 `cargo clippy` 通过。
2. 新增节点、条件或工具函数时记得补充测试(`cargo test`)。
3. 若扩展了管线 DSL,请同步更新本文档。
3. 若扩展了 workflow 动作或 DSL,请同步更新本文档。

## 维护者
项目由 CeerDecy(袁浩楠)维护,邮箱:[email protected]

## 许可证
项目基于 [Apache License 2.0](LICENSE) 发布。
26 changes: 26 additions & 0 deletions auto-engine-core/src/context.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use crate::utils;
use serde::Serialize;
use std::collections::HashMap;
use std::path::PathBuf;
Expand Down Expand Up @@ -53,6 +54,31 @@ impl Context {
);
Ok(())
}
pub async fn get_value(&self, key: &str) -> Option<serde_json::Value> {
let map = self.string_value.read().await;
map.get(key).cloned()
}

pub async fn get_value_parse(&self, key: &str) -> Option<serde_json::Value> {
let mut default_value = None;
let mut key = key.to_string();
for caps in utils::REGEX_PARSE_VARIABLES.captures_iter(&key) {
let var_name = (&caps[1]).to_string();
let default = caps.get(2).map(|m| m.as_str()).unwrap_or("");
if default != "" {
default_value = Some(serde_json::Value::String(default.to_string()));
}
key = var_name;
break;
}

let value = self.get_value(&key).await;
if value.is_some() {
return value;
}

default_value
}

pub fn load_image_path(&self, image: &str) -> Result<PathBuf, String> {
let image_path = self.workflow_path.join("images").join(image);
Expand Down
3 changes: 3 additions & 0 deletions auto-engine-core/src/event/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ impl NodeEventPayload {
pub fn running(name: String) -> NodeEventPayload {
NodeEventPayload::new::<String>("running".to_string(), name, None)
}
pub fn waiting(name: String) -> NodeEventPayload {
NodeEventPayload::new::<String>("waiting".to_string(), name, None)
}

pub fn skip<D: Serialize>(name: String, result: Option<D>) -> NodeEventPayload {
NodeEventPayload::new("skip".to_string(), name, result)
Expand Down
1 change: 1 addition & 0 deletions auto-engine-core/src/node.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
pub mod data_aggregator;
pub mod image_match;
pub mod keyboard;
pub mod mouse_click;
Expand Down
2 changes: 2 additions & 0 deletions auto-engine-core/src/node/data_aggregator.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
pub mod node;
pub mod runner;
Loading
Loading