DriftLedger/plugins/ppocr/app.plugin.js
fengmengqi f6437b83fe feat: 初始化完整应用框架
- 切换到 expo-router 文件路由,删除 App.tsx
- 新增 5 个 Expo 原生插件:ppocr (OCR), accessibility (账单抓取),
  notification-listener, screenshot-monitor, sms-receiver
- 实现核心领域逻辑:billPipeline (账单流水), dedup (去重),
  transferRecognizer (转账识别), ruleEngine + categories (双轨制分类),
  budgets, creditCards, recurring, sync, ocrProcessor
- 增强 ledger.ts:支持 balance assertion, option, pad/note 指令,
  posting 级 metadata, cost/price 解析
- 新增完整 UI:tabs (首页/报表/设置), 交易详情, 预算, 日历热力图,
  分类管理, 信用卡, 定期交易, 规则管理
- 实现 Zustand 状态管理:ledgerStore, importStore, settingsStore,
  metadataStore, automationStore + 持久化
- 新增 AI 功能:chatAssistant, monthlySummary, voiceInput
- 实现多端同步:gitSync, webdavSync, icloudSync
- 新增主题系统 (tokens/presets) 和 i18n (zh/en)
- 添加 30+ 单元测试覆盖核心逻辑
2026-07-15 10:01:31 +08:00

121 lines
4.4 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* PP-OCRv5 (ONNX Runtime) Config Pluginplan.md「决策 4 Expo Config Plugin 方案」+「3.4 Layer 2」
*
* 本插件在 expo prebuild 时:
* 1. 复制 Kotlin 源码OcrModule.kt + OcrPackage.kt到 android/app/src/main/java/...
* 2. 复制 ONNX 模型与字典到 android/app/src/main/assets
* 3. 注册 OcrPackage 到 MainApplicationgetPackages
* 4. 添加 onnxruntime-android 依赖app/build.gradle
*
* 引擎ONNX Runtime跨平台、微软官方、Windows 友好),替代 NCNN 路线。
* 注意SDK 54 的 @expo/config-plugins 暴露的是 withMainApplication / withAppBuildGradle
* (没有 withAndroidMainApplication / withAndroidGradle。文件复制用 withDangerousMod。
*
* 模型文件放 plugins/ppocr/assets/,版权/体积原因不入仓库,需自行下载(见 README.md
*/
const {
withMainApplication,
withAppBuildGradle,
withDangerousMod,
} = require('@expo/config-plugins');
const fs = require('fs');
const path = require('path');
const PACKAGE = 'com.beancount.mobile.ppocr';
/** 递归复制目录prebuild 阶段执行一次。 */
function copyDir(src, dest) {
if (!fs.existsSync(src)) return;
fs.mkdirSync(dest, { recursive: true });
for (const entry of fs.readdirSync(src)) {
const s = path.join(src, entry);
const d = path.join(dest, entry);
if (fs.statSync(s).isDirectory()) copyDir(s, d);
else fs.copyFileSync(s, d);
}
}
function withPpOcr(config) {
// 1+2. 复制 Kotlin 源码与 ONNX 模型/字典到原生工程
config = withDangerousMod(config, [
'android',
async (modConfig) => {
// platformProjectRoot 在 modRequest 里(项目根的 android/ 子目录)
const projectRoot = modConfig.modRequest.platformProjectRoot;
// Kotlin 源码OcrModule.kt + OcrPackage.kt
copyDir(
path.join(__dirname, 'android'),
path.join(projectRoot, 'app/src/main/java/com/beancount/mobile/ppocr'),
);
// ONNX 模型 + 字典(若已下载)
const assetsSrc = path.join(__dirname, 'assets');
if (fs.existsSync(assetsSrc)) {
copyDir(
assetsSrc,
path.join(projectRoot, 'app/src/main/assets'),
);
}
return modConfig;
},
]);
// 3. 注册 OcrPackage 到 MainApplication
config = withMainApplication(config, (modConfig) => {
let content = modConfig.modResults.contents;
// 3a. 注入 import在 package 声明行后插入)
if (!content.includes(`import ${PACKAGE}.OcrPackage`)) {
content = content.replace(
/^(package\s+[\w.]+;?\s*)$/m,
`$1\nimport ${PACKAGE}.OcrPackage`,
);
}
// 3b. 在 getPackages() 的 .apply {} 块里注入 add(OcrPackage())
if (!content.includes('add(OcrPackage())')) {
if (/PackageList\(this\)\.packages\.apply\s*\{/.test(content)) {
// 新架构 KotlinSDK 54 默认):模板已有空 .apply {} 块,在块开头注入
content = content.replace(
/(PackageList\(this\)\.packages\.apply\s*\{)/,
`$1\n // PP-OCRv5 ONNX 原生模块(由 Config Plugin 注入)\n add(OcrPackage())`,
);
} else if (/PackageList\(this\)\.packages\b/.test(content)) {
// 新架构变体:.packages 后没有 .apply包一层
content = content.replace(
/PackageList\(this\)\.packages\b/,
`PackageList(this).packages.apply { add(OcrPackage()) }`,
);
} else if (/\breturn\s+packages\s*;/.test(content)) {
// 老架构 Java在 return packages; 前插入
content = content.replace(
/(\breturn\s+packages\s*;)/,
`packages.add(new OcrPackage());\n $1`,
);
}
}
modConfig.modResults.contents = content;
return modConfig;
});
// 4. 配置 app/build.gradle 依赖ONNX Runtime Android
config = withAppBuildGradle(config, (modConfig) => {
let gradle = modConfig.modResults.contents;
if (!gradle.includes('onnxruntime')) {
// 在 dependencies { ... } 块末尾追加
gradle = gradle.replace(
/dependencies\s*{([\s\S]*?)^\s*}/m,
(m, inner) =>
`dependencies {${inner}\n // PP-OCRv5 ONNX Runtime由 Config Plugin 注入)\n implementation 'com.microsoft.onnxruntime:onnxruntime-android:1.20.0'\n}`,
);
}
modConfig.modResults.contents = gradle;
return modConfig;
});
return config;
}
module.exports = withPpOcr;