From 1a90350f5eb22beccce5f6d7bc16b28d6c3a4a2b Mon Sep 17 00:00:00 2001 From: yibo Date: Thu, 4 Jun 2026 18:10:13 +0800 Subject: [PATCH] docs(lifelog): 文档同步到 v0.6 — 声纹聚类 / 5-tab / 会话纪要 / 对话 / 本地 LLM 栈 --- CLAUDE.md | 30 ++++++++++++++++++------------ lifelog-recorder/HANDOFF.md | 41 ++++++++++++++++++++++++++++++++++------- 2 files changed, 52 insertions(+), 19 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index bb24955..46627a0 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -10,7 +10,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co |---|---|---|---| | **lemonPCRM** | `server/` + `frontend/` + `packages/` | Node.js + Express 后端 + 静态前端 | 主线 | | **wechat_plain** | `wechat_plain/` | Android Xposed/A11y 模块 + Pixel 部署脚本 | 主线 | -| **lifelog-recorder** | `lifelog-recorder/` | Pixel 原生 Android 应用(Kotlin + Compose) | v0.1 (2026-06) | +| **lifelog-recorder** | `lifelog-recorder/` | Pixel 原生 Android 应用(Kotlin + Compose) | v0.6 (2026-06) | **lemonPCRM** — lemonAI 出品的 Local-First AI 个人人脉管理系统(Personal CRM)。以人为中心、以对话为链接,通过知识图谱管理微信、LinkedIn、X 等多平台社交关系,将每个联系人与其社媒动态、会议纪要、文件、照片全面关联。 @@ -163,7 +163,7 @@ Launcher (ProcessLauncher spawn / NoneLauncher 无操作) 详见 `server/services/wechat/README.md`。 -## lifelog-recorder(Pixel 8 Pro 24/7 录音 + 本地中文 ASR,v0.1) +## lifelog-recorder(Pixel 8 Pro 24/7 录音 + 本地中文 ASR + 本地 LLM,v0.6) > 完整接手地图、踩坑清单、命令速查见 `lifelog-recorder/HANDOFF.md`。本节只勒住整个项目的**架构骨架 + 关键决策来源**,不重复细节。 @@ -179,12 +179,16 @@ Launcher (ProcessLauncher spawn / NoneLauncher 无操作) Foreground Service (foregroundServiceType=microphone, WAKE_LOCK partial) └ AudioRecord 16k mono PCM16 (VOICE_RECOGNITION source, no AGC/NS) └ Silero VAD ONNX (sherpa-onnx 包装,500ms 静音切 / 30s 强切) - └ paraformer-zh int8 ONNX (sherpa-onnx JNI, 4 threads, 25× realtime) - └ Room SQLite (Segment / Transcript / Summary) - └ Compose LazyColumn 时间轴 UI (倒序,按 startTs) - ↓ (待办) hermes gateway 8642 → Kimi → 纪要 Worker + ├ paraformer-zh int8 ONNX (sherpa-onnx JNI, 4 threads, ~20× realtime) + └ 3dspeaker campplus 192-d 嵌入 → SpeakerClusterer 在线聚类(自动「说话人N」,方案B) + └ Room SQLite v3 (Segment/Transcript/Summary/SpeakerProfile/Chat*; addMigrations, 已去 destructive) + └ Compose 5-tab UI (录音 / 对话 / 时间轴 / 声纹 / 纪要) + ├ SummaryWorker:按时间间隔切「会话」→ 本地 llama-swap(8080) Qwen3.5-2B 出纪要 + └ ChatScreen:本地 2B/4B(llama-swap 8080) + Hermes(8642→Kimi) 多端点对话 ``` +**本地 LLM 栈(v0.6,零云端)**:Termux 自编 llama.cpp HEAD + llama-swap v223 监听 `127.0.0.1:8080`,按 model 名(`2b`/`4b`)热切换 Qwen3.5-{2B,4B}-Q4_K_M。纪要 worker + App 对话都打 8080;Magisk `service.d` 开机自启。完整部署/坑见 memory `pixel-local-llm-stack.md` + HANDOFF.md。 + 技术栈:Kotlin 2.1 + Compose BOM 2024.12.01 + Room 2.6.1 + WorkManager 2.10 + OkHttp 4.12,AGP 8.7.3,minSdk 30 / targetSdk 35(Android 14 强制 `foregroundServiceType` 起步),arm64-v8a 单 ABI。 ### 接口 @@ -245,13 +249,15 @@ Foreground Service (foregroundServiceType=microphone, WAKE_LOCK partial) ### 未来计划(按优先级) -完整待办、估时、技术路线见 `lifelog-recorder/HANDOFF.md` §五。摘要: +完整待办、估时、技术路线见 `lifelog-recorder/HANDOFF.md` §五。 + +✅ **v0.2–v0.6 已完成**:Opus 编码 / BOOT 自启 + 电池白名单 / FTS4 中文搜索 / 段播放 / **声纹在线聚类(方案B 自动 diarization)** / **会话级纪要(按时间间隔切会话)** / **5-tab UI** / **App 内对话(本地 2B/4B + Hermes)** / **本地 LLM 栈(llama-swap)** / **Room 迁移(去 destructive)**。 -- 🔥 **Opus 编码**(WAV 24/7 跑 ~3 GB/天,必须) -- 🔥 **自启动 + 电池白名单**(BOOT_COMPLETED + REQUEST_IGNORE_BATTERY_OPTIMIZATIONS,让 v1 真能脱离 dev 环境跑) -- ⭐ **声纹识别 / speaker diarization**(用户语音里提了 3 次,sherpa-onnx `Speaker.kt` 现成可用) -- ⭐ **FTS5 中文搜索**(Room + ICU tokenizer) -- ⭐ **LLM 纪要 Worker**(cron + idle 触发 → hermes gateway → Kimi) +剩余摘要: +- ⭐ **存储 TTL**(删超 N 天 .opus,文字永留) +- ⭐ **设置页**(存储用量 / 模型切换 / 暂停时段) +- ⭐ **多 anchor 平均**(连选多段标同一人提高匹配率) +- ⭐ **回链 lemonPCRM**(Transcript 实体 → GraphStore `MENTIONED_IN`,v2) ### 与 lemonPCRM 的关系 diff --git a/lifelog-recorder/HANDOFF.md b/lifelog-recorder/HANDOFF.md index efafb10..dca67ed 100644 --- a/lifelog-recorder/HANDOFF.md +++ b/lifelog-recorder/HANDOFF.md @@ -19,9 +19,9 @@ ## §一 这是什么 -24/7 后台录音 → VAD 切段 → 本地 paraformer 中文 ASR → 入库 → 时间轴显示 → (未来)LLM 纪要。 +24/7 后台录音 → VAD 切段 → 本地 paraformer 中文 ASR → 在线声纹聚类(自动「说话人N」)→ 入库 → 5-tab UI(录音/对话/时间轴/声纹/纪要)→ 按时间间隔切「会话」→ 本地 Qwen3.5 LLM 出纪要 + App 内对话。 -**完全本地,零云端依赖**(讯飞客户端只作云复核 fallback)。 +**完全本地,零云端依赖**(讯飞客户端只作云复核 fallback;纪要/对话走本机 llama-swap,Hermes→Kimi 仅作对话里一个可选端点)。v0.6(2026-06-04)起接了本地 LLM 栈,详见 §六。 ### 实测性能(Pixel 8 Pro / Tensor G3 / Android 16 BP2A) @@ -40,7 +40,14 @@ APK 大小: 62 MB(含 34 MB sherpa-onnx .so + 0.6 MB silero VAD + 3 MB samp ``` app/src/main/kotlin/com/lemon/lifelog/ ├── LifelogApp.kt — Application,建 NotificationChannel -├── MainActivity.kt — Compose UI,时间轴 + 搜索 + 声纹 enroll dialog +├── MainActivity.kt — Compose 5-tab 壳 + 时间轴/声纹/纪要 tab + 全 CRUD/批量/筛选 +├── ChatScreen.kt — 对话 tab(ChatGPT 式:会话列表 + 流式气泡 + 端点切换) +├── chat/ +│ ├── ChatConfig.kt — 聊天端点配置(本地 8080/2b/4b 存 SharedPreferences;Hermes 走 BuildConfig) +│ └── ChatClient.kt — OpenAI 兼容流式客户端(本地目标传 enable_thinking=false) +├── summary/ +│ ├── SummaryWorker.kt — ★ 会话级纪要:按时间间隔切会话 → 本地 llama-swap 2B +│ └── SummaryScheduler.kt — WorkManager periodic + enqueueUniqueWork(KEEP) 去重 ├── service/ │ ├── RecorderService.kt — 前台服务,pipeline 主体 ←★ 改 ASR 流程改这里 │ ├── RecorderState.kt — StateFlow 把服务状态推到 UI @@ -51,14 +58,16 @@ app/src/main/kotlin/com/lemon/lifelog/ │ └── SegmentPlayer.kt — MediaPlayer 包装,Opus 段原音播放(系统原生支持) ├── asr/ │ ├── ParaformerEngine.kt — sherpa-onnx paraformer 包装 ←★ 主 ASR -│ ├── SpeakerEmbedder.kt — sherpa-onnx 3dspeaker campplus 192-d 嵌入 + cosineSim +│ ├── SpeakerEmbedder.kt — sherpa-onnx 3dspeaker campplus 192-d 嵌入 + cosineSim + l2normalize +│ ├── SpeakerClusterer.kt — ★ 方案B 在线聚类:自动发现「说话人N」+ reclusterAll 离线重算 │ ├── SpeakerMatcher.kt — 回填工具:用当前 profile 集重算所有段的 speakerId +│ ├── HermesClient.kt — OpenAI 兼容(纪要 worker 用,指本地 llama-swap;readTimeout 600s) │ ├── ModelDownloader.kt — 首次启动下模型(paraformer 232 MB + speaker 28 MB) │ └── XfyunIatClient.kt — 讯飞大模型 WS 客户端,仅 fallback / 云复核用 └── data/ - ├── Entities.kt — Segment / Transcript / Summary / SpeakerProfile / TranscriptFts - ├── Daos.kt — observeTimeline + searchTimeline (FTS4) + SpeakerDao - ├── AppDatabase.kt — Room v2,destructive migration(v0.3 schema 大改) + ├── Entities.kt — Segment / Transcript / Summary / SpeakerProfile / TranscriptFts / ChatConversation / ChatMessage + ├── Daos.kt — observeTimeline + searchTimeline(FTS4) + Speaker/Summary/ChatDao + 范围查询 + ├── AppDatabase.kt — Room v3,addMigrations(MIGRATION_2_3),★ 已删 fallbackToDestructiveMigration(改 schema 不写迁移会崩,绝不静默清库) └── Repository.kt ``` @@ -159,6 +168,7 @@ VAD 参数(在 `RecorderService.runPipeline` 里调): - v0.3 (2026-06):声纹识别(3dspeaker campplus)/ FTS4 中文搜索 - v0.4 (2026-06):段播放 (MediaPlayer Opus) / bottom sheet 操作菜单 / enroll 后自动回填老段 - v0.5 (2026-06):hermes api_server 端点 + SummaryWorker + 纪要 UI section +- v0.6 (2026-06-04):**声纹在线聚类**(SpeakerClusterer,自动「说话人N」+ reclusterAll)/ **5-tab UI**(录音/对话/时间轴/声纹/纪要,时间轴全 CRUD + 批量删导出 + 按说话人/时间/未匹配筛选 + 排序)/ **真暂停**(停采集留模型)/ **会话级纪要**(按时间间隔切会话、可调阈值、要点带 [HH:mm:ss] 点击跳回时间轴、折叠头显示说话人名单)/ **App 内对话**(本地 2B/4B + Hermes 多端点流式)/ **本地 LLM 栈**(llama.cpp HEAD + llama-swap 8080,纪要+对话全本地,见 §六)/ **Room v3 迁移**(去 destructive 改 fail-loud) 剩下: @@ -221,6 +231,23 @@ skills: 用 hermes 自己的 config 模块改最稳(`load_config`/`save_config`,保留其他配置)。改完重启 gateway。 **实测:prompt 12,500 → 399 token(-97%),纪要正常生成。** +### §六 本地 LLM 栈(llama-swap,v0.6 — 纪要 + 对话的真后端) + +零云端推理。**完整部署/坑清单见 memory `pixel-local-llm-stack.md`**,这里只列接手要点: + +``` +~/llama.cpp/ — 自编 HEAD(gh-proxy.com clone 绕墙;server-tools 缺 spawn.h → 手写 Bionic 兼容头丢 $PREFIX/include) +~/llama-swap/llama-swap — v223 静态 arm64 binary,监听 127.0.0.1:8080 +~/llama-swap/config.yaml — model "2b"/"4b" → llama-server + Qwen3.5-{2B,4B}-Q4_K_M.gguf,ttl 300 热切换 +~/models/Qwen3.5-{2B,4B}-Q4_K_M.gguf — hf-mirror.com/unsloth 下,2.74GB / 1.28GB +~/start-llama.sh — launcher(起 llama-swap),被 Magisk service.d 调用 +``` + +- **App 接线**:`ChatConfig` 本地默认 `8080`/`2b`/`4b`(SharedPreferences 可改);`keys.properties` = `8642`(对话的 Hermes 选项 → Kimi);`SummaryWorker.LLM_BASE_URL/LLM_MODEL` = `8080`/`2b`(纪要,已解耦 keys.properties)。 +- **Qwen3.5 默认开思考**:纪要 + 本地对话都要传 `chat_template_kwargs:{enable_thinking:false}` 否则 token 被 `` 吞、流式开头吐字面 `"null"`(org.json.optString 坑,ChatClient.parseDelta 已用 `isNull` 防)。 +- **G3 实测**(Q4,热降频):2B ~12 t/s 生成 / 65 prefill(一篇纪要 ~48s);4B ~4 / 24(~2.6min)。 +- 启动器手测:`su -G 3003 10302 -c 'bash ~/start-llama.sh'`,再 `curl 127.0.0.1:8080/v1/models`。 + ### 自启(Magisk service.d) Termux:Boot 未装(且无匹配签名 APK);已 root,用 Magisk service.d 更稳(不需开 Termux app)。 -- libgit2 0.21.4