自扩展桌面文件阅读器 —— 不认识的文件格式,现场学会它。
A self-extending desktop file reader: feed it an unknown format, and it learns to parse it on the spot.
Pi Reader 是一个具备「自我扩展能力」的桌面文件阅读器。它基于 Tauri v2(Rust 后端 + React 前端)构建,内部集成了一个 Pi Agent 智能体。当你把任意格式的文件拖进窗口时,Pi Agent 会调用本地 LLM 动态生成一段 Rhai 解析脚本,现场学会这个新格式,并持久化到磁盘——以后再遇到同类文件直接复用,不再调用 LLM。
核心思想:把「格式解析」从硬编码变成运行时学习,让阅读器自己学会读任何文本文件。
| 功能 | 说明 |
|---|---|
| 🔵 内置格式解析 | 开箱支持 JSON、YAML、纯文本(TXT / LOG / MD) |
| 🟢 自我扩展 | 未知格式自动调用 Pi Agent 生成 Rhai 解析脚本 |
| 🟣 持久化学习 | 学会的格式保存在磁盘,重启不丢失 |
| 🟠 在线修复 | 解析不满意?写反馈,Agent 重新生成改进版 |
| 🔵 文件树浏览 | 原生文件夹浏览 + 拖拽打开 |
| 🟢 JSON 树查看器 | 可折叠/展开的结构化 JSON 视图 |
| 🔴 Agent 日志 | 实时查看 Pi Agent 的推理与生成过程 |
痛点: 日常工作中我们经常遇到小众格式、公司内部日志格式、或一次性数据文件——为它们写解析器太重,用通用工具又读不出结构化内容。每遇到一个新格式就得写脚本、装工具、学新语法,效率低下。
Pi Reader 的解法:
- 零编码:遇到不认识的文件,拖进去就行,LLM 自动生成解析器。
- 越用越强:学会的格式永久保留,数量越多,阅读器越「聪明」。
- 离线可用:已学会的格式不需要网络,内置格式更是完全离线。
- 安全沙箱:所有解析脚本在 Rhai 沙箱中运行,无文件/网络能力。
┌──────────────────────────────────────────────────────────────────┐
│ Pi Reader 自我扩展循环 │
│ │
│ 打开文件 ──→ 嗅探(扩展名+魔数) ──→ 匹配 handler? │
│ │ │
│ 命中 ◄──── 已学会? │
│ │ │
│ 未命中 │
│ │ │
│ ▼ │
│ Pi Agent 调用 LLM │
│ │ │
│ ▼ │
│ 生成 Rhai 解析脚本 │
│ │ │
│ ▼ │
│ 沙箱校验 + 试运行 ──┬── 通过 │
│ │ │ │
│ 失败 ▼ │
│ │ 注册 + 持久化 │
│ 重试一次 │ │
│ │ ▼ │
│ └──→ 直接解析 ──→ 展示结果 │
└──────────────────────────────────────────────────────────────────┘
| 依赖 | 版本 | 说明 |
|---|---|---|
| Rust 工具链 | ≥ 1.77 | rustup 安装 |
| Node.js | ≥ 18 | 前端构建 |
| WebView2 | Windows 内置 | Tauri GUI 必需 |
| Pi Coding Agent | 最新 | LLM 后端(可选,离线可用) |
# 1. 克隆项目
git clone https://github.com/your-username/pi-reader.git
cd pi-reader
# 2. 安装前端依赖
npm install
# 3. 启动开发模式(会拉起 Rust 后端 + 桌面窗口)
npm run tauri dev
# 4. (可选)安装 Pi Coding Agent,获得 AI 扩展能力
npm install -g @earendil-works/pi-coding-agent
# 然后配置 DeepSeek provider(详见 Pi 文档)- 🖱️ 打开文件:点击「打开文件」或直接把文件拖进窗口
- 🤖 自动学习:如果是 JSON/YAML/TXT 等内置格式→直接显示;如果是未知格式→Pi Agent 自动生成解析器
- 📖 浏览结果:结构化 JSON 以可折叠树形展示,右侧面板显示 Agent 生成日志
- 🔄 反馈修复:对解析结果不满意,在查看器下方写反馈,Agent 会重新生成改进版
- 🧠 持久记忆:学会的格式显示在左侧「已学会的格式」列表中,下次直接复用
| 区域 | 功能 |
|---|---|
| 📁 左侧面板 | 文件树浏览 + Pi Agent 状态 + 已学会格式列表 |
| 📄 中央查看器 | JSON 树视图、解析脚本展示、反馈/修复面板 |
| 📋 右侧面板 | Pi Agent 推理日志(实时流式显示) |
通过原生对话框选择文件夹,左侧文件树支持文件夹展开/收起,点击文件即可在中央区域查看解析结果。
左侧底部显示当前所有 handler 状态:
- ✅ 已连接的 Pi Agent — LLM 状态指示灯
- 📚 已学会的格式 — 列出所有持久化的能力,支持「遗忘」操作
- ⚙️ 内置格式 — JSON / YAML / 文本
当解析器运行失败时,界面会切换到「修复模式」:
- 显示原始运行错误
- 你描述期望的解析行为
- Agent 基于错误 + 反馈 + 上一次脚本重新生成
核心引擎 pi-core 是一个纯 Rust 库,无需 Tauri 或网络即可独立运行和测试。它包含三个模块:
- reader:
Engine入口,嗅探文件(扩展名 + 魔数 + 前 4096 字符),遍历注册的FormatHandler,找到匹配则解析,否则委托给 PiAgent。 - agent:
PiAgent+ 可插拔LlmProvidertrait +ScriptHandler+ Rhai 脚本沙箱。内置PiSdkProvider(Node.js bridge)、PiCliProvider(pi CLI 子进程)、StaticProvider(测试用)三种实现。 - registry:能力持久化。学会的脚本以 JSON 格式存储在
<config_dir>/pi-reader/capabilities/。
// LlmProvider — 可插拔 trait,只需实现一个方法
pub trait LlmProvider: Send + Sync {
fn name(&self) -> &str;
fn generate_parser(&self, req: ParserRequest) -> BoxFuture<'static, Result<String>>;
}已内置实现:
- PiSdkProvider — 通过 Node.js bridge 调用 Pi Coding Agent SDK(默认)
- PiCliProvider — 通过
pi --mode jsonCLI 子进程调用 - OpenAiProvider — 兼容 OpenAI 协议的通用 HTTP 客户端(DeepSeek / 通义 / Ollama 等)
- StaticProvider — 固定脚本返回(离线测试)
所有自动生成的解析器均在 Rhai 嵌入式脚本语言的沙箱中执行:
- 安全:无文件系统、无网络访问、无 FFI
- 零编译:脚本即时编译执行,没有编译步骤
- 丰富的内置辅助函数:
split、lines、trim、parseInt、parseFloat、json_stringify等 20+ 字符串处理函数
// LLM 为 CSV 格式自动生成的解析器示例
fn parse(raw) {
let lines = raw.split("\n");
let headers = [];
let rows = [];
let first = true;
for line in lines {
let t = line.trim();
if t == "" { continue; }
let cells = t.split(",");
if first {
headers = cells;
first = false;
} else {
let row = #{};
let i = 0;
while i < cells.len() {
let key = if i < headers.len() { headers[i] } else { "col" + i };
row[key] = cells[i].trim();
i = i + 1;
}
rows.push(row);
}
}
return #{ "headers": headers, "rows": rows, "row_count": rows.len() };
}
当自动生成的解析器不符合预期时,无需手动修改代码:
- 在查看器下方的文本框中描述问题(如「这个字段请用 parseInt 转换」「不要忽略空行」)
- Pi Agent 收到反馈 + 上一次生成的脚本 + 原始运行错误
- Agent 综合分析后生成改进版脚本
- 新脚本通过沙箱校验后自动替换旧的,持久化保存
右侧面板实时显示 Pi Agent 的每一步动作:
- 格式嗅探结果(扩展名、魔数)
- LLM 调用状态(生成中、成功/失败)
- 脚本校验结果(字段数、错误信息)
- 持久化状态(已学会、已遗忘)
| 阶段 | 内容 | 状态 |
|---|---|---|
| Phase 1 | MVP:核心引擎 + Tauri 桌面壳 + 基本前端 | ✅ 已完成 |
| Phase 2 | 基于内容魔数的格式匹配(不止依赖扩展名) | 📋 计划中 |
| Phase 3 | 二进制格式支持(通过 Hex 转文本预处理) | 📋 计划中 |
| Phase 4 | 多 LLM Provider 切换 UI + 自定义 Provider 热加载 | 📋 计划中 |
| Phase 5 | 解析脚本导出/共享/社区仓库 | 💭 规划中 |
- Frontend: React 18 + TypeScript + Vite 5 + Tauri API v2
- Backend: Rust (Tauri v2) —
src-tauri/桌面壳 - Core Engine: Rust (纯库) —
pi-core/可独立测试 - Scripting: Rhai 1.x — 嵌入式脚本语言,安全沙箱执行
- LLM Integration: Pi Coding Agent SDK / CLI / OpenAI 兼容协议
- Storage: JSON 文件系统 —
<config>/pi-reader/capabilities/*.json - Build: Cargo workspace + npm + Tauri CLI
pi-reader/
├── Cargo.toml # workspace: pi-core + src-tauri
├── pi-core/ # 纯 Rust 核心引擎
│ ├── src/
│ │ ├── reader/ # Engine + FormatHandler trait + 内置 handler
│ │ ├── agent/ # PiAgent + LlmProvider + Rhai 沙箱 + prompt
│ │ ├── registry.rs # 能力持久化存储
│ │ ├── error.rs # 错误类型定义
│ │ └── lib.rs # 公开 API
│ ├── tests/ # 集成测试
│ └── examples/cli.rs # 无 GUI 命令行入口
├── src-tauri/ # Tauri 桌面应用
│ ├── src/
│ │ ├── lib.rs # 应用启动 + 状态管理 + 依赖注入
│ │ ├── commands.rs # 8 个 Tauri 命令
│ │ └── main.rs # 入口
│ ├── tauri.conf.json
│ └── resources/ # pi-bridge.cjs(Node.js bridge)
├── src/ # React 前端
│ ├── App.tsx # 主布局 + 拖拽 + 状态管理
│ ├── api.ts # Tauri invoke 封装
│ ├── components/ # 5 个 UI 组件
│ └── styles.css # 全部样式
├── index.html
├── package.json
└── tsconfig.json
核心引擎可脱离 GUI 与网络进行测试:
# 运行所有 pi-core 测试
cargo test -p pi-core
# 运行单个测试(CSV 学习 + 持久化 + 复用流程)
cargo test -p pi-core --test learn_flow learns_csv_and_persists
# 离线 CLI 演示(使用内置兜底脚本)
cargo run -p pi-core --example cli -- path/to/file
# TypeScript 类型检查 + Vite 构建
npm run build测试覆盖以下核心场景:
- ✅ CSV 格式的学习流程 + 持久化验证
- ✅ 第二次读取同类文件直接复用(不调 LLM)
- ✅ JSON 内置格式不触发学习
- ✅ 未配置 Agent 时返回友好错误
- ✅ YAML 知识图谱自定义解析器(带注释剥离)
MIT License
Pi Reader — 自扩展文件阅读器 · A self-extending file reader
基于 Tauri v2 + React + Rust,由 Pi Coding Agent 驱动 AI 扩展能力