ssurui
687e0ca9e2
feat: 拍照提问接入本地知识库检索;修复摄像头 deviceId 失效导致打不开
...
架构调整(按 docs/feature-pic-design.md §11):拍照提问从"图+文直接
问视觉模型"改成三段式——① 用固定提示词让视觉模型快一句话描述图片
(describeImage,非流式,实测 6.7s / 45 tokens)② 描述+用户问题拼接
去检索本地知识库 ③ 用户原始问题+检索到的上下文做纯文字生成。②③ 完全
复用文字问答的 embedOne/search/streamGenerate,图片不再传给最终生成。
前端补 vision-query:stage / :caption / :context 三个事件,识别结果以
"识别到:xxx"常驻显示。
同时修一个真机暴露的 bug:CameraCapture 用配置里持久化的 deviceId 做
exact 约束打开摄像头,但 deviceId 在 Web 标准里不保证跨会话稳定,重启
后旧 id 失效直接抛 OverconstrainedError,整个拍照功能不可用(真机截图
确认弹层报错、预览全黑)。改为失效时自动回退默认摄像头,并把实际拿到的
设备 id 回写,让"切到后置摄像头"的逻辑在回退场景下同样生效。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QeoAy5KmkHuKWHAktpEsaN
2026-09-03 20:47:33 +08:00
ssurui
b918a0c53f
fix: 拍照默认摄像头按标签精确匹配后置,不再依赖枚举顺序
...
之前默认摄像头是"设备列表第一个",依赖操作系统 enumerateDevices()
返回顺序,不可靠。真机测出后置摄像头(朝外拍摄那颗)的 label 是
"Hy-8M(8079)-Camera",改成按标签里的型号数字串精确匹配。
摄像头 label 在 getUserMedia 拿到权限前是空的(浏览器隐私限制),
没法一开始就按标签选,所以流程改成:先用默认设备开流拿到权限,
权限到手后 label 才是真的,这时候如果不是用户/配置显式指定的摄像头,
再检查当前是不是已经是后置、不是就切过去。
真机验证:清空之前手动切换保留下来的摄像头偏好后重新打开,稳定落在
后置摄像头(桌面/Mac mini 视角),不再随机。
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-03 16:06:28 +08:00
ssurui
0d19be58c3
fix: 拍照提问摄像头画面倒置、下拉菜单换成前后切换按钮
...
真机拍照实测画面上下颠倒(Mac mini 的苹果标志倒着)。CameraCapture.vue
的 <video> 加 transform: rotate(180deg) 转正预览;capture() 画到 canvas
时同步做相同的 180° 旋转(translate 到右下角再 rotate(Math.PI)),
不然预览是正的、实际拍下来的照片还是倒的。
摄像头选择从下拉菜单换成一个悬浮在预览右上角的圆形切换按钮
(switchCamera(),在设备列表里循环切换,只有 >1 个摄像头时才显示)。
默认摄像头沿用之前"取设备列表第一个"的逻辑不变——真机实测这个正好是
朝外拍摄的那颗(另一颗是朝向操作者的),语义上更接近用户要的默认
"后置摄像头",暂不改动。
真机验证:预览转正、切换按钮能真实切到另一颗摄像头且画面同样是正的、
拍照后的照片方向跟预览一致(不会出现预览正但存图倒的情况)。
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-03 16:02:31 +08:00
ssurui
8054fcdad1
fix: 语音输出恢复"开始播报"、消除加粗文本重复朗读;输入框真正对齐
...
真机复测又发现三个问题,逐一定位修复:
1. 流式播报接上后"开始播报"提示语丢了。TtsPlayer 新增 announceStart(),
只入队播放不碰流式缓冲区状态,beginQuery() 里 stop()+配置同步之后
调用。真机验证:连续问答里从第2轮开始稳定播报"开始播报"(第1轮偶发
缺失,是启动时批量测试自动开始跟语音配置同步的时序竞争,非本次改动
引入的逻辑问题)。
2. 加粗文本(**xxx**)被朗读两遍。根因:markdownToPlain 每次都从头
重新解析整段 rawText,** 闭合符号到达前后同一段文字的纯文本渲染
结果不一样(未闭合时星号当普通字符、闭合后星号被去掉),提前把这段
不稳定文字提交为 lastSpokenPlain 会在闭合符号到达后被重新判定成
"待朗读"造成重复。新增 findStableBoundary(),只处理到最后一个已闭合
的 ** 为止,未闭合的尾部留到下次 append 再处理;flush() 收尾时因为
生成已结束,不再有这个顾虑,直接处理全部剩余内容。真机验证:连续
3 轮问答,每轮都有加粗小标题,全部按顺序推进朗读新内容,无重复。
3. 输入框和按钮行的对不齐问题:之前一直在改 .q-input(文本框本身)的
高度,但真实 DOM 测量显示文本框本身一直是精确的 96px,真正超高的
是它的父容器 .q-input-wrap(渲染成 102.4px,比 96px 多 6.4px),
文本框贴容器顶部导致整体被顶高。给 .q-input-wrap 也显式定死
height:96px。真机像素测量确认对齐。
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-03 15:54:34 +08:00
ssurui
48a9fb0f6d
fix: TTS append() 高频小增量下丢字、输入框 max-height 兜底
...
真机复测发现两个问题:
1. 语音输出改成流式后实测只播一个孤零零的句号,正文完全没读出来。
根因:TtsPlayer.append() 每次调用都用 this.buffer = pending 直接
覆盖缓冲区,而不是累加。LLM 流式返回的增量通常很小(经常几个字一
个 chunk),大部分时候 processBuffer() 没能凑出完整句子就被下一次
append() 覆盖掉,只有 flush() 时残留的最后一小段才被朗读。改成
this.buffer += pending,累加未处理完的内容,不再丢字。真机验证:
同一次问答里生成过程中(回复结束前)已经出现 4 条完整正文的 speak
调用,不再是只有收尾的空句号。
2. 输入框 rows="1" + min-height:0 没能完全消除跟按钮行的高度差
(真机截图像素测量仍有约10px gap),补充 max-height:96px 硬性封顶,
重启(不是 HMR 热更)后截图确认对齐。
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-03 15:34:01 +08:00
ssurui
a78c88c86a
fix: 输入框与旁边的按钮行高度对不齐
...
<textarea class="q-input"> 没设 rows 属性,浏览器按默认 2 行的最小
内容高度处理,字体度量四舍五入后比显式 height:96px 略高几像素,
把整个输入框撑高,导致跟同高度的语音/拍照按钮顶边对不齐(底边因为
input-bar 是 align-items:flex-end 对齐所以没发现,只有顶边露馅)。
加 rows="1" 让最小内容高度不再跟显式高度打架,同时加 min-height:0
防御 UA 默认样式。
用像素网格量过真机截图确认:这是 textarea 本来就有的问题,不是这次
加拍照按钮引入的,只是三个按钮排一起后更显眼。
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-03 15:14:04 +08:00
ssurui
ec634c4133
fix: 语音输出改为边生成边播报,不再等整段答案完成
...
TtsPlayer 本来就实现了完整的流式播报能力(append() 按句子边界切分
入队、flush() 收尾剩余文本),只是 ChatPanel 一直没接上,只在
querying 结束后调用一次 speakWithAnnouncement(全文)。
改为在 onDelta 里实时 append(delta),onDone/onError 里 flush()
收尾。删除了原来 querying 结束时整段朗读的 watch(不删会导致
整段答案被朗读两遍)。效果:不用等生成完,第一句话生成出来就
开始播,播放速度跟不上文字输出时 TtsPlayer 自带的自适应语速会
自动降速跟上。
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-03 15:07:01 +08:00
ssurui
21f9c7e453
feat: 实现拍照提问模式 MVP(阶段1+2)
...
按 docs/feature-pic-design.md 的方案实现:
- AppConfig 新增 vision 字段(enabled 总开关、cameraDeviceId 记住上次
选用的摄像头),主进程/渲染层类型两处同步
- generator.ts 抽出共享的 streamChatCompletion(),新增
streamGenerateVision() 支持 OpenAI 视觉 API 的 image_url content-part,
文字问答路径不受影响
- 新增 visionHandler.ts(vision-query IPC,跳过向量检索,直接转发
图片+问题给 er_backend 代理),注册进 ipc/index.ts
- 新增 CameraCapture.vue:getUserMedia 取景/拍照/重拍/多摄像头切换,
纯交互组件不掺业务逻辑
- ChatPanel.vue 接入拍照入口(仅 vision.enabled 时显示)、待发送图片
缩略图、问题气泡里的图片展示;抽出 beginQuery() 复用文字/拍照两条
路径共同的状态重置逻辑
- SettingsModal.vue 加拍照提问开关
- index.ts 权限处理器注释说明 getUserMedia 摄像头请求也走 'media'
不做检索、不做照片持久化、不做多摄像头预配置界面(MVP 范围见设计文档 §3)。
本地未跑 vue-tsc,接下来在真机上验证类型检查 + 构建 + 端到端联调。
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-03 14:50:52 +08:00
ssurui
d512ad41f9
perf: 精简打包体积,砍掉从未被使用的 Piper 引擎和渲染层专用依赖
...
排查确认两处真实浪费:
1. resources/tts/piper/ 里除 espeak-ng-data 外的所有文件(Piper 神经
语音模型、二进制、自带 onnxruntime、phonemize 库、tashkeel 阿拉伯语
音标模型,合计 ~113M)从未被实际调用——detectBackend() 第一优先级
永远命中 VITS(小雅),Piper 引擎分支代码走不到,只有它 bundle 里的
espeak-ng-data 目录被 VITS 借用当 sherpa-onnx 校验的 dataDir。
systemTts.ts 新增 findPiperEspeakDataDir(),VITS 分支改为只依赖这一
个子目录,不再要求 Piper 引擎的 bin/model/config 存在。
2. electron-builder.config.ts 的 files 补充排除 onnxruntime-web(
@huggingface/transformers 的硬依赖但项目强制走 onnxruntime-node,
完全未用)、naive-ui/date-fns/highlight.js/lodash 系(只在
src/renderer/ 被引用,electron-vite build 时已被 Vite 打包进
out/renderer/*.js,主进程不需要原始 node_modules),约省 227M。
两项合计预计单包体积从 ~789M 降到 ~560M 左右,待真机重新打包安装、
实际听一次语音播报确认功能未受影响。
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-23 00:19:14 +08:00
ssurui
0ae330c4ca
feat: 替换应用图标为新版"电子手册"图标
...
同时替换 main 进程窗口图标源(resources/icon.png,也是打包脚本里
桌面快捷方式图标的来源)和渲染层内嵌 logo 源(src/renderer/public/icon.png)。
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-22 10:35:32 +08:00
surui
836d25cad2
refactor: 推理请求统一走 er_backend 代理(127.0.0.1:17700)
...
- 嵌入/生成服务地址不再由前端按 cardType 推导端口,改为经 er_backend
的 /v1/* 代理转发,服务端口以后端配置为唯一真相来源
- config.ts: 新增 ER_BACKEND_URL 统一常量,删除端口推导逻辑
- generator/statusHandler/queryHandler/erBackendHandler 跟随改造
- fix: package-kylin-arm64-deb.sh 从 .app-version 读版本号时剥离 v 前缀,
修复无 git 环境下 dpkg-deb 报"版本号没有以数字开头"
2026-08-16 21:16:01 +08:00
ssurui
71dce3b37b
docs: 新增批量测试问题示例文件 batch_questions.txt
...
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-08-15 19:56:22 +08:00
ssurui
6f93912c86
feat: 初始提交——elec_rag_ui 独立前端工程
...
基于 Electron + Vue3 + TypeScript + LanceDB 的本地化 RAG 问答桌面应用。
仅支持 Linux(Kylin V10 / Ubuntu),适配 ER160(揽月 M50 NPU)和 ER25(芯动力 RPP)计算卡。
服务进程管理委托给 er_backend(HTTP 17700),前端专注 RAG 逻辑与用户交互。
包含:
- src/elec_rag_ui 前端工程(Electron + Vue3)
- models/ 本地嵌入模型(bge-small/base/large,ASR,标点恢复,onnx 文件由 Git LFS 管理)
- docs/ 示例文档(用于测试索引与问答)
2026-08-15 19:25:28 +08:00