记账这件事,难的不是算,而是记。市面上的记账 App 大多要求用户在多个输入框之间跳转——选分类、填金额、挑日期,一套流程下来至少七八次点击。真实生活里,一笔「打车 28 块」的消费发生在关上车门的那一秒,等用户打开 App 找到入口,这笔账大概率就丢了。
奇记 QiNote 把记账压缩成一句话:在聊天框里输入「昨天打车 28.5」,App 自动解析出类型、分类、金额、日期并落库;拿到一张小票,直接拍照发过去,多模态模型读图提取金额与消费时间。交互模式向"和助手对话"靠拢,而不是"填表单"。
数据全部存在本地 Room,无账号、无云端同步。
- 💬 对话式记账 — 自然语言一句话成账;携带最近 10 条聊天上下文,支持"也是 35 块"这类指代补全
- 🧾 小票识别 — 拍照/选图走视觉模型,自动提取金额与消费时间(精确到秒),并正确拆分日期与时间字段
- 🖐 手动模式 — 聊不清楚时切回传统表单,双入口互为兜底
- 📊 数据可视化 — 首页 Bento 统计卡(月支出/月收入/账单数/结余)+ 统计页环形分类占比图与趋势折线图,全部 Compose
Canvas手绘,不引图表库 - 🏝 HyperOS 超级岛 — 记账解析中/成功/失败以焦点通知实时呈现;无权限时经 Shizuku 通道或降级为 Live Updates / 常驻通知
- 🔁 重复检测 — 落库前按「标题+金额+类型+日期+时间」五元组查重,避免重复记账
- 🔐 本地优先与密钥安全 — Room 三实体存储;AI API Key 经 AndroidKeyStore + AES/GCM 加密后写入 DataStore
- 🌙 深色模式 — 自建设计令牌体系(色彩/间距/圆角/缓动/字体),深浅色全覆盖
| 分类 | 技术 |
|---|---|
| 语言 | Kotlin 2.1.21(JDK 11 target,core library desugaring) |
| UI | Jetpack Compose(BOM 2025.05.01)+ Material 3 |
| 架构 | MVVM + Clean Architecture 分层(UI / UseCase / Repository) |
| 依赖注入 | Hilt 2.56.2 |
| 数据 | Room 2.7.1(账单 / 分类 / 聊天记录)+ DataStore 1.1.6 |
| 导航 | Navigation Compose 2.9.0 |
| 网络 | OkHttp 4.12 + kotlinx.serialization 1.8.1 |
| 图片 | Coil 2.7 |
| 特系能力 | Shizuku 13.1.5(特权通道)+ HyperNotification 1.4(超级岛) |
| 安全 | androidx.security-crypto(EncryptedSharedPreferences / AndroidKeyStore) |
两条通道互为降级,能用确定性规则解决的绝不交给概率模型:
用户输入(文字 / 小票图片)
│
├── 带图片 ──────────────► 视觉模型识别小票
│
└── 纯文字
├─ LocalBillParser 本地正则(60+ 分类关键词)
│ └─ 高置信度(命中金额 + 明确分类)→ 直接落账(零成本、离线可用)
├─ AI 可用 → LLM 抽取 JSON(System Prompt 注入当前日期、封闭分类枚举、14 组 few-shot)
│ └─ 失败/超时 → 自动回退本地正则
└─ 都失败 → 引导补充描述
│
▼
JSON 容错解析(剥离 ``` 围栏 + 括号配平扫描 + 字段校验)
▼
日期/时间规范化("昨天"→T-1;"下午3点"→15:00:00)
▼
五元组幂等去重 → Room 落库 → 通知(超级岛 / Live Updates / 常驻)
关键工程决策:
- 金额全程以「分」为单位的 Long 存储,规避浮点累加误差;
- 重试指数退避 + 随机抖动(1s→2s→4s),错误按 401/402/429/超时翻译成人话;
- 模型输出按不可信输入处理:括号配平扫描提取 JSON,未知分类 ID 回退
daily,金额 ≤ 0 直接拒绝。
- Android Studio Hedgehog 或更高版本
- JDK 11+(项目开启 core library desugaring,可直接使用
java.time) - Android SDK 24 (minSdk) — 35 (targetSdk) / compileSdk 36
git clone https://github.com/Fq77/QiNoteAPP.git
cd QiNoteAPP
./gradlew installDebug # 或直接用 Android Studio Run- 进入「设置 → AI 配置」,填入任意 OpenAI Chat Completions 兼容端点、API Key 与模型名(文本 / 视觉可分别指定);
- Key 会以 AndroidKeyStore 硬件密钥 + AES/GCM 加密存储,不落明文;
- 不配置也能用:本地正则覆盖"午餐 35""打车 28.5"这类高频表达。
app/src/main/java/com/qinoteapp/qinoteapp/
├── components/ # 可复用 UI(QiButton / QiSheet / QiToast / 环形统计卡等)
├── data/
│ ├── dao/ # Room DAO(账单 / 分类 / 聊天记录)
│ ├── database/ # 数据库与迁移
│ ├── entity/ # 实体与分类图标映射
│ ├── local/ # PreferencesManager / SecureKeyStore(Key 加密)
│ └── repository/ # 仓库层
├── di/ # Hilt 模块(OkHttp、数据库、偏好)
├── navigation/ # 路由与底部导航
├── network/ # AiApiService / LocalBillParser(本地正则)
├── notification/ # 超级岛、Live Updates、能力探测、Shizuku 通道
│ └── shizuku/ # 特权通知与白名单绕过
├── service/ # 前台服务
├── ui/
│ ├── entry/ # 记账入口(聊天模式 / 手动模式)
│ ├── home/ # 首页(Bento 统计、账单分组)
│ ├── stats/ # 统计(环形图 / 趋势图)
│ ├── settings/ # 设置(AI 配置、分类管理、数据管理、主题)
│ └── theme/ # 设计令牌
├── usecase/ # AiBookkeepingUseCase(双通道决策链)
└── util/ # 金额 / 日期工具
当前 v1.0.1(versionCode 2):API Key 加密存储 + ProGuard 混淆 + 打包修复。
- 核心框架:Jetpack Compose · Kotlin · Hilt · Room
- 功能库:OkHttp · Coil · Kotlinx Serialization · DataStore
- 特系能力:Shizuku · HyperNotification
MIT © Fq77
Made with ❤️ using Android & Jetpack Compose

