# AionsHome **Repository Path**: strange_touchannel/AionsHome ## Basic Information - **Project Name**: AionsHome - **Description**: No description available - **Primary Language**: Unknown - **License**: MIT - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-09-10 - **Last Updated**: 2026-09-16 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # Aion Chat 项目档案 ## 项目定位 局域网 + 外网(Tailscale 组网)多端同步 AI 聊天程序 + 摄像头智能监控系统。PC/手机浏览器同时使用,支持 PWA 安装为独立 App(全屏无地址栏),数据全部存在本地电脑上。 ## 技术栈 - **后端**:Python FastAPI + SQLite (aiosqlite) + WebSocket - **前端**:多页面架构(原生 JS,无框架),暖光主题,手机/PC 自适应。chat.html/css/js 为主聊天页(结构/样式/逻辑分离),独立功能页通过 common.css/common.js 共享样式和工具函数 - **摄像头**:OpenCV (`cv2`) DirectShow 后端后台线程采集 + ESP32-CAM HTTP 远程抓帧(双摄切换 + App 桥接模式) - **语音**:WebRTC VAD 语音检测 + 硬基流动 ASR (SenseVoiceSmall) + TTS (CosyVoice2) + 语音消息(按住录制) - **AI 接口**:硬基流动(OpenAI 兼容)、Google Gemini(REST API)、AiPro 中转站(OpenAI 兼容)、Gemini CLI(本地子进程调用,免费 OAuth 认证)、Codex CLI(本地子进程调用,Connor 专用) - **AI 生图**:Gemini `gemini-3.1-flash-image-preview`(REST API generateContent,responseModalities=["IMAGE"]) - **Embedding**:Gemini `gemini-embedding-001`(3072维),余弦相似度检索 - **Android App**:Java,WebView + 前台推送服务(OkHttp 4.12.0 WebSocket)+ 原生录音桥 + 原生摄像头桥 + 原生视频录制桥(MediaCodec + MediaMuxer),compileSdk 34 / minSdk 24 - **音乐**:pyncm(网易云音乐 API,搜索/歌曲详情/音频URL,支持 MUSIC_U Cookie VIP 登录 + 服务端代理推流) - **EPUB 解析**:ebooklib(EPUB 读取)+ BeautifulSoup4 / lxml(HTML 解析) - **基金监控**:akshare(A股/基金数据拉取)+ chinese-calendar(中国节假日/交易日判断) - **MCP 娱乐室**:mcp(Python MCP SDK,支持 Streamable HTTP / stdio 传输,接入外部服务如 AI 小镇) - **聊天室**:三人群聊(用户 + Aion + Connor-Codex),Connor 代理通过 HTTP 轮询接入 Codex CLI 服务,随机回复顺序,统一时间线上下文(私聊+群聊合并排序,场景切换标记),统一记忆总结(Aion/Connor 各自合并私聊+群聊消息总结,独立锚点,1小时无新消息自动触发),图片收发(用户发图→CLI 管线通过本地绝对路径传递、API 管线通过 base64 内嵌,Codex 回复 `[[image:...]]` 标记→前端渲染,图片存储于 `Connor-Codex/uploads/YYYY-MM-DD/`),TTS 语音合成(Aion/Connor 独立音色配置,硬基流动 CosyVoice2 服务端流式切分+并行合成,通过 SSE 推送音频分段顺序播放,配置持久化 localStorage) - **依赖库**:fastapi, uvicorn, httpx, aiosqlite, opencv-python, Pillow, sounddevice, numpy, webrtcvad-wheels, pyncm, pywin32, psutil, ebooklib, beautifulsoup4, lxml, akshare, chinese-calendar, mcp ## 模块化文件结构 项目已从单文件拆分为 12 个模块化文件: ``` 项目根目录/ ├── 一键启动.bat # 双击启动服务(内含绝对路径,搬迁后需修改) ├── 模型预设.txt # 模型列表参考 ├── public/ # 公共静态资源 │ ├── BackGround.png │ ├── icon.png # 原始图标(1024x941) │ ├── icon-192.png # PWA 图标 192x192(自动生成) │ ├── icon-512.png # PWA 图标 512x512(自动生成) │ ├── AionMonitoralart.mp3 # Core 查看监控前的提示音 │ ├── AIonResponse.mp3 # 语音唤醒回复音频("诶,我在呢") │ ├── UserIcon.png # 用户聊天头像 │ ├── AIIcon.png # AI 聊天头像 │ └── 生图锚点.jpg # SELFIE 参考图(AI 人物一致性锚点) │ └── wallpaper/ # 动态壁纸媒体文件(图片+视频) ├── AionApp/ # Android WebView 原生壳(Java,Android Studio 项目) │ ├── app/src/main/java/com/aion/chat/ │ │ ├── LauncherActivity.java # 启动页:双地址选择(家庭WiFi / Tailscale)+ 记住选择 + 启动推送服务 │ │ ├── WebViewActivity.java # WebView 主页:全屏加载 chat.html,麦克风权限,前后台状态通知推送服务 │ │ ├── AudioBridge.java # 原生录音桥:AudioRecord 16kHz → base64 → JS 回调,录制时同步转发 PCM 给 VideoBridge │ │ ├── CameraBridge.java # 原生摄像头桥:legacy Camera API → NV21 字节旋转 → JPEG → JS 轮询(绕过 WebView HTTPS 限制),录制时转发帧给 VideoBridge │ │ ├── VideoBridge.java # 原生视频录制桥:MediaCodec(H.264) + MediaCodec(AAC) + MediaMuxer → MP4,复用 CameraBridge/AudioBridge 的帧数据 │ │ ├── (AionImageSaver) # 图片保存桥(WebViewActivity 内匿名类):JS base64 → MediaStore 写入相册 │ │ └── AionPushService.java # 前台推送服务:独立 WebSocket 长连接 + 通知弹窗 + 断线重连 + WakeLock/WifiLock 保活 + ESP32-CAM 桥接(拉帧→上传服务器) │ └── build.gradle # compileSdk 34, minSdk 24, Gradle 8.5 + AGP 8.2.2, OkHttp 4.12.0 ├── LittleToy/ # BLE 玩具逆向分析 & 独立 demo │ ├── toy_control_v4.html # 独立 BLE 控制页面(可单独使用) │ └── 逆向分析笔记.md # SOSEXY 设备协议逆向笔记 ├── 启动壁纸.bat # Chrome App 模式无边框全屏启动动态壁纸 └── aion-chat/ ├── main.py # 入口:lifespan、路由注册、静态挂载、WebSocket、PWA 路由、自动记忆总结定时任务(私聊+群聊空闲检测)、Connor自动总结定时任务 ├── config.py # 全局路径、常量、settings/worldbook/chat_status/cam_config 读写 ├── database.py # SQLite 初始化(conversations/messages/memories/schedules/theater 等表 + 性能索引) ├── ws.py # WebSocket ConnectionManager 单例,含 tts_clients 状态追踪 + _tts_fallback HTTP 回落机制 + client_id 注册/定向推送 ├── ai_providers.py # AI 调用:硅基流动/Gemini/AiPro中转站/GeminiCLI 流式 + 非流式 + 多模态消息构建 ├── memory.py # 向量记忆:embedding、综合评分召回、手动/自动总结(合并私聊+群聊消息)、即时哨兵(RAG路由)、原文追溯 ├── camera.py # 摄像头:CameraMonitor 类、Sentinel 分析(注入设备活动摘要)、Core 唤醒、[CAM_CHECK]、ESP32-CAM 双摄切换+App桥接 ├── location.py # 高德地图定位:GPS心跳处理、三级研判、状态机(at_home/outside)、哨兵通知、POI搜索 ├── voice.py # 语音唤醒 + 半双工通话(WebRTC VAD + 硬基流动 ASR),通话中自动携带 TTS 参数 ├── tts.py # 服务端流式 TTS:按句切分(100-200字)+ 异步并行合成 + WebSocket/SSE 推送音频分片 ├── schedule.py # 日程/闹铃/定时监控管理器:ScheduleManager、文本指令解析、闹铃触发Core唤醒、定时监控截图+Core分析(注入设备活动摘要) ├── ghost_forest.py # 奥罗斯幽林 TRPG 引擎:会话管理、AI 对话历史压缩、D20 骰子判定、角色属性/道具系统 ├── gift.py # 礼物系统:AI 判断送礼 + 硅基流动 Kolors 生图 + 礼物数据 CRUD ├── fund.py # 基金持仓监控:akshare数据拉取、盈亏计算、上证指数、历史走势、AI分析prompt生成、每日14:45定时任务(FundScheduler) ├── book.py # EPUB 解析模块:书籍导入、章节拆分、段落标注、图片提取 ├── image_gen.py # AI 生图模块:Gemini 图片生成(SELFIE/DRAW 模式) ├── mcp_client.py # MCP 连接管理器:管理多个 MCP Server 连接(HTTP/stdio)、工具发现、统一 call_tool 接口、转换 OpenAI tools 格式 ├── context_builder.py # 统一上下文构建:fetch_merged_timeline(合并私聊+群聊消息时间线)、render_merged_timeline(场景切换标记渲染)、build_ability_block、build_memory_blocks、strip_tool_commands ├── chatroom.py # 聊天室核心逻辑:Connor-Codex 代理调用(HTTP+taskId轮询+images)、统一时间线上下文构建、统一记忆总结(Connor 1v1+群聊合并,独立锚点 connor_unified)、1h无消息自动总结 ├── routes/ │ ├── __init__.py │ ├── book.py # 阅读功能 API:书籍上传/列表/章节/进度/删除/图片/AI批注(单段+全章SSE) │ ├── theater.py # 小剧场 API:独立对话CRUD、消息CRUD、角色CRUD、SSE流式回复(无记忆/系统能力注入)+ TTS ├── chat.py # 对话/消息 CRUD、send_message(SSE)、regenerate、cam-check-trigger、[MUSIC:xxx]/[ALARM:...]/[REMINDER:...]/[Monitor:...]/[TOY:x]/[查看动态:n]/[视频电话] 检测 │ ├── music.py # 音乐搜索/详情/播放/代理推流 API(pyncm) │ ├── schedule.py # 日程 CRUD API(列表/添加/删除) │ ├── cam.py # 摄像头控制 + 监控日志 API + ESP32-CAM 画面源切换/桥接帧接收 │ ├── location.py # 定位 API:心跳上报、状态查询、POI搜索、配置管理、设置家位置 │ ├── files.py # 上传、聊天记录文件导出/管理 │ ├── settings.py # 设置、世界书、模型列表、TTS 代理、视频通话开关、AI生图开关 │ ├── memories.py # 记忆库 CRUD + 手动总结触发 + 原文查看 + 锚点管理 API │ ├── heart_whispers.py # 心语 API(列表查询 + 删除) │ ├── activity.py # 活动日志 API(上报/查询/清理/状态诊断/10分钟摘要/AI联动开关配置) │ ├── voice.py # 语音唤醒/通话控制 API │ ├── ghost_forest.py # 奥罗斯幽林 TRPG API(16 个端点:人设/会话/剧情生成/选择/骰子/大结局)+ SSE 流式 TTS │ ├── gift.py # 礼物系统 API(pending/receive/list/delete/test) │ ├── fund.py # 基金监控 API:持仓CRUD、配置开关、数据拉取、手动触发AI分析、缓存读取、历史走势 │ ├── playground.py # 娱乐室 API:MCP Server 连接/断开、tool calling 循环、SSE 流式行动日志、经历总结归档 │ └── wallpaper.py # 动态壁纸 API:文件列表/配置读写/上传/删除 │ └── chatroom.py # 聊天室 API:房间 CRUD、发消息(SSE)、AI 互聊(SSE)、记忆 CRUD、配置、Connor 状态、总结记忆、图片上传(/api/chatroom/upload)+ 图片路径重写 + TTS流式合成(Aion/Connor独立音色) ├── activity.py # 设备活动日志:JSONL 存储、自动清理(保留最近 3 小时)、PC 前台窗口采集(win32gui+psutil)、App 包名→中文名映射、10分钟窗口摘要(时长权重+carry-forward状态追溯)、AI联动开关+Prompt摘要生成 ├── music.py # pyncm 封装层(搜索/歌曲详情/音频URL/MUSIC_U Cookie 登录/匿名登录) ├── README.md # 本文件 ├── 监控流程.md # Sentinel/Core 架构设计文档 ├── static/ │ ├── home.html # 手机风格主页 → /(应用图标网格 + Dock 栏) │ ├── chat.html # 主聊天页 → /chat(含语音唤醒/TTS/BLE/音乐/系统日志/debug面板) │ ├── chat.css # 主聊天页样式(从 chat.html 拆分) │ ├── chat.js # 主聊天页逻辑(从 chat.html 拆分) │ ├── common.css # 子页面共享样式(CSS变量/布局/组件/闹铃弹窗/toast) │ ├── common.js # 子页面共享工具(api()/WS连接/闹铃弹窗/系统通知) │ ├── settings.html # 设置页 → /settings(API Key 管理) │ ├── worldbook.html # 世界书页 → /worldbook(AI/用户人设编辑) │ ├── memory.html # 记忆库页 → /memory(CRUD/搜索/总结/锚点/原文追溯) │ ├── schedule.html # 日程管理页 → /schedule(列表/添加/删除) │ ├── camera.html # 摄像头页 → /camera(预览/缩放/监控开关/配置) │ ├── monitor-logs.html # 监控日志页 → /monitor-logs(按日期查看/实时WS推送) │ ├── location.html # 定位页 → /location(状态/POI/配置) │ ├── heart-whispers.html # 心语页 → /heart-whispers(AI秘密日记查看/删除) │ ├── activity-logs.html # 活动日志页 → /activity-logs(双设备活动查看/筛选/清理/10分钟摘要弹窗/AI联动开关) │ ├── reading.html # 阅读页 → /reading(书架+阅读器+AI批注+选文聊天+音乐播放) │ ├── theater.html # 小剧场页 → /theater(独立聊天+多角色管理+TTS,茶色暗色主题) │ ├── ghost-forest.html # 奥罗斯幽林页 → /ghost-forest(TRPG 游戏:D20 骰子+角色扮演+AI DM) │ ├── gift.html # 爱的印记页 → /gift(礼物陈列馆,缩略图网格+详情弹窗) │ ├── fund.html # 奥罗斯财团页 → /fund(基金持仓监控、数据拉取、AI分析、持仓管理) │ ├── playground.html # 娱乐室页 → /playground(MCP 服务连接 + AI 自主探索 + 行动日志 + 历史记录) │ ├── playground.css # 娱乐室样式 │ ├── playground.js # 娱乐室前端逻辑(SSE 实时渲染 + 历史记录加载) │ ├── chatroom.html # 聊天室页 → /chatroom(三人群聊 + Connor 私聊 + 房间管理 + 记忆库悬浮窗 + 图片收发 + TTS设置) │ ├── chatroom.css # 聊天室样式(暖色三人气泡、头像、双换行拆分气泡、图片预览/查看器/内联图片、TTS滑块开关) │ ├── chatroom.js # 聊天室前端逻辑(SSE流式、AI互聊、记忆CRUD、世界书人设继承、图片上传/粘贴/[[image:]]渲染、TTS分段队列播放+音色配置持久化) │ ├── wallpaper.html # 动态壁纸页 → /wallpaper(全屏壁纸轮播+AI气泡,独立显示器使用) │ ├── video-call.js # 视频通话模块:摄像头预览 + 按住录制视频 + ASR转写 + 来电/去电 UI │ ├── manifest.json # PWA Web App Manifest(从 /manifest.json 提供) │ └── sw.js # PWA Service Worker(从 /sw.js 提供) └── data/ # ★ 备份只需复制此文件夹 ├── chat.db # SQLite 数据库 ├── settings.json # API Key 持久化 ├── worldbook.json # 世界书(AI/用户人设+名称) ├── cam_config.json # 摄像头监控配置(active_source/esp32_cam_url/本地摄像头/定时/静默时段) ├── chat_status.json # 聊天状态摘要(供哨兵参考) ├── location_config.json # 定位配置(高德Key、家坐标、开关、安静时段、阈值等) ├── location_status.json # 定位状态缓存(当前坐标、状态、地址、天气、POI等) ├── digest_anchor.json # 总结锚点(记录上次总结到哪条消息的时间戳) ├── uploads/ # 上传的图片/视频 ├── chats/ # 导出的 .md 聊天记录 + _index.json ├── screenshots/ # 摄像头截图(自动清理) ├── monitor_logs/ # Sentinel 监控日志(JSONL,按日期,3天自动清理) ├── activity_logs/ # 设备活动日志(JSONL,按日期,保留最近 3 小时) ├── books/ # EPUB 书籍数据(解析后的章节+图片+批注数据库) ├── theater_personas.json # 小剧场角色预设(多套人设,JSON数组) ├── fund_config.json # 基金监控配置(开关、投资倾向) ├── fund_cache.json # 基金数据缓存(最近一次拉取结果) ├── mcp_servers.json # MCP Server 配置(娱乐室服务地址列表) ├── wallpaper_config.json # 动态壁纸配置(轮换间隔、文件启用状态、气泡锚点坐标) └── ghost_forest/ # 奥罗斯幽林 TRPG 数据 ├── _personas.json # DM/玩家人设预设 └── {uuid}.json # 游戏会话存档(每局一个文件) ``` ## 路由 | 路径 | 说明 | |------|------| | `/` | home.html 手机风格主页(应用图标启动器) | | `/chat` | chat.html 主聊天页 | | `/settings` | settings.html 设置页(API Key 管理) | | `/worldbook` | worldbook.html 世界书页 | | `/memory` | memory.html 记忆库页 | | `/schedule` | schedule.html 日程管理页 | | `/camera` | camera.html 摄像头监控页 | | `/monitor-logs` | monitor-logs.html 监控日志页 | | `/location` | location.html 定位地图页 | | `/heart-whispers` | heart-whispers.html 心语页(AI秘密日记) | | `/activity-logs` | activity-logs.html 活动日志页(双设备活动查看) | | `/reading` | reading.html 阅读页(书架+阅读器+AI批注+选文聊天) | | `/theater` | theater.html 小剧场页(独立聊天+多角色+TTS) | | `/ghost-forest` | ghost-forest.html 奥罗斯幽林页(TRPG 冒险游戏) | | `/gift` | gift.html 爱的印记页(礼物陈列馆) | | `/fund` | fund.html 奥罗斯财团页(基金持仓监控) | | `/playground` | playground.html 娱乐室页(MCP 服务接入 + AI 自主探索) | | `/wallpaper` | wallpaper.html 动态壁纸页(全屏壁纸轮播+AI气泡) | | `/manifest.json` | PWA Web App Manifest | | `/sw.js` | PWA Service Worker(根路径提供,作用域覆盖全站) | | `/public/*` | 公共资源 | | `/static/*` | 静态文件 | | `/uploads/*` | data/uploads/(主聊天上传) | | `/cr-uploads/*` | Connor-Codex/uploads/(聊天室图片,按日期子目录) | | `/api/*` | 后端 API | | `/ws` | WebSocket 多端同步 | ## 支持的模型 ### 硅基流动(api.siliconflow.cn) - GLM-5 → `Pro/zai-org/GLM-5` - GLM-4.7 → `Pro/zai-org/GLM-4.7` - Kimi-K2.5 → `Pro/moonshotai/Kimi-K2.5` ### Gemini(generativelanguage.googleapis.com) - gemini-3.1-flash-lite → `gemini-3.1-flash-lite-preview`(Sentinel / poll_digest 默认模型) - gemini-2.5-pro → `gemini-2.5-pro` - gemini-3-flash → `gemini-3-flash-preview`(聊天默认模型) - gemini-3.1-pro → `gemini-3.1-pro-preview` ### AiPro 中转站(vip.aipro.love) - claude-sonnet-4-6 → `claude-sonnet-4-6` - claude-opus-4-6 → `claude-opus-4-6` ### 哨兵/向量模型(支持独立 Gemini Free Key) - Sentinel 哨兵分析 → `gemini-3.1-flash-lite-preview` - 向量 Embedding → `gemini-embedding-001`(3072维) - 即时哨兵 → `gemini-3.1-flash-lite-preview` - 记忆总结(手动/自动) → 当前聊天对话的核心模型(跟随用户选择) 哨兵和向量模型支持配置独立的 Gemini Free Key,留空则自动复用主 Gemini Key。 ## 已实现功能 ### 聊天核心 1. **对话管理** — 创建/删除/重命名对话,默认日期命名,侧栏显示每个对话的消息条数 2. **消息 CRUD** — 发送/编辑(气泡内 inline)/删除/复制,⋯ 点阵菜单 3. **流式 AI 回复** — SSE 流式输出,逐字显示,等待时显示「思考中」/「正在输入」循环动画 + 弹跳小圆点 4. **重新生成** — AI 消息可一键重新生成 5. **多端实时同步** — WebSocket 广播,PC/手机任一端操作实时同步 6. **上下文长度控制** — 滑块 1-100 条可调,默认 20 7. **世界书(World Book)** — AI/用户人设 + 自定义名称,注入 prompt 前缀 8. **图片/视频上传** — 多模态支持,Gemini 用 inline_data,硅基流动用 URL 9. **语音消息** — 微信风格按住说话录音,松手发送。浏览器使用 MediaRecorder 录制 WebM,Android 使用原生 AudioBridge 录音。录音通过硅基流动 ASR 自动转写为文字,消息以语音气泡形式展示(显示时长 + 播放按钮),转写文本同时保存供记忆/上下文使用 9. **聊天记录文件管理** — 自动导出 .md,文件管理器弹窗查看/下载/删除 10. **API Key 管理** — 界面内设置面板,支持 Gemini + Gemini Free(哨兵+向量)+ 硅基流动 + 中转站 四组 Key 11. **手机适配** — 侧栏抽屉式展开,聊天气泡布局,触屏友好,`@media (max-width: 768px)` 单独优化紧凑间距 62. **聊天头像** — 用户/AI 消息旁显示圆形头像(`public/UserIcon.png` / `public/AIIcon.png`),用户右侧、AI 左侧 63. **多气泡拆分** — AI 回复中 `\n\n` 自动拆分为多个独立消息气泡,像微信连发效果,流式输出实时拆分 64. **时间内联显示** — 消息时间显示在用户/AI 名字旁边,不再独占一行 12. **当前时间注入** — 每次发消息/重新生成时,将准确时间拼接到 prompt 前缀最后一条 assistant 回复中 ### Debug 透明度面板 13. **Token 用量追踪** — Gemini usageMetadata + 硅基流动 usage,在 SSE 流中通过 debug 事件传回前端 14. **记忆召回可视化** — 每次发消息时召回的记忆条目,显示综合分数 + 三维分解(vec_sim / kw_score / importance) 15. **完整 Prompt 查看** — 可展开查看发送给模型的全部 prompt 消息(截断前500字/条) 16. **Debug 条** — 每条 AI 消息下方显示:模型名、输入/输出/总 token、召回记忆数,点击展开详情 ### 向量记忆库(RAG 重构) 17. **记忆总结(手动 + 自动)** — 手动:用户点击「总结新记忆」按钮触发(无最低条数限制)。自动:每 30 分钟检测,若用户已 30 分钟未对话且未总结消息 ≥ 30 条则自动触发。两者共用同一套逻辑和锚点,不会重复总结。从锚点之后的消息开始,每 30 条一组串行处理(余数 <10 合并到最后一组),使用当前聊天的核心模型(而非 flash-lite)提取结构化记忆(含关键词 + 重要度 0-1 + unresolved 判断),Prompt 注入世界书 AI/用户人设使记忆更具个人视角。每组成功后更新锚点。全部总结完成后,带最近 30 条聊天上下文 + 人设再调用一次核心模型,生成一句感慨/吐槽,作为 assistant 消息插入聊天(前置一条「🧠 AI整理了记忆库」系统胶囊) 18. **即时哨兵(instant_digest)** — 每次用户发消息时自动调用 flash-lite 分析最近对话,返回结构化 JSON:`{is_search_needed, keywords, require_detail, status, topic}`,决定是否需要搜索记忆、是否需要追溯原文细节,同时提供 topic 用于背景记忆浮现 19. **向量化存储** — 使用 Gemini `gemini-embedding-001`(3072维)将记忆向量化,存入 SQLite memories 表,每条记忆含 keywords(JSON 关键词数组)、importance(重要度)、source_start_ts/source_end_ts(来源时间范围)、unresolved(是否待办/未完成) 20. **综合评分召回** — `final_score = vec_sim × 0.6 + kw_score × 0.3 + importance × 0.1`,threshold=0.45,Top 5。关键词匹配支持子串模糊命中 21. **原文追溯(fetch_source_details)** — 当 `require_detail=true` 时,在召回记忆的 source 时间范围内按关键词筛选原始对话记录,去重后按时间排序,拼接注入 prompt 22. **总结锚点管理** — 锚点持久化在 `data/digest_anchor.json`,UI 显示当前锚点时间 + 日期选择器可回退 23. **可视化管理** — 侧边栏「🧠 记忆库」按钮,支持搜索/添加/编辑/删除,编辑后自动重新向量化。每条记忆显示关键词标签 + 重要度分数,编辑时可修改关键词和重要度。有 source 时间范围的记忆可点击 📜 查看原文。📌 按钮可切换记忆的“待办/未完成”状态,unresolved 的记忆以橙色高亮显示 ### 语音合成 (TTS) — 服务端流式推送架构 24. **服务端流式 TTS** — AI 流式输出过程中,后端 `tts.py` 的 `TTSStreamer` 实时按句切分文本(100-200 字,按句号/问号/感叹号/换行等断句),每句异步调用硅基流动 CosyVoice2-0.5B 合成 mp3,合成完成后立即通过 WebSocket 或 SSE 推送 `tts_chunk` 事件给前端,前端收到即可开始播放,无需等待全文生成完毕。SSE 模式通过 `sse_queue` 参数支持,用于小剧场和奥罗斯幽林等独立 SSE 流场景 25. **多场景触发** — 用户发消息后的 AI 流式回复、重新生成、Core 主动发言(哨兵唤醒/闹铃/定时监控/[CAM_CHECK] 跟进)均自动创建 TTSStreamer 进行流式合成 26. **音色选择** — 齿轮配置面板内选择硅基流动账号下的自定义音色,通过 WebSocket `tts_state` 消息同步到服务端 27. **前端队列播放** — 前端维护 `ttsQueue`(Map 结构,key 为 msg_id),每条消息的分片按 seq 顺序播放,多条消息按到达顺序排队;播放完最后一片后服务端广播 `tts_done` 事件,前端清理队列并继续下一条 28. **多端 TTS 状态同步** — 前端开启 TTS 后通过 WebSocket 发送 `tts_state` 消息(含 enabled/voice),服务端 `ConnectionManager` 在 `tts_clients` 字典中跟踪各客户端状态;同时 HTTP POST(send_message/regenerate)的 body 中也携带 `tts_enabled`/`tts_voice` 作为 `_tts_fallback` 回落,确保服务端发起的消息(cam_check/闹铃/监控)也能获取 TTS 状态 28b. **TTS 音频缓存** — 合成的音频分片存储在 `data/tts_cache/` 目录,文件名为 `{msg_id}_s{seq}.mp3`,前端可通过 `/api/tts/audio/{chunk_name}` 获取;点击 AI 消息的 🔊 图标可重播已缓存的 TTS 分片 28c. **TTS 重播** — 点击聊天气泡下的喇叭图标,前端通过 HEAD 请求探测 `{msg_id}_s0`、`{msg_id}_s1`... 是否存在,依次播放所有分片;支持 GET 和 HEAD 两种 HTTP 方法 ### 摄像头智能监控(Sentinel/Core 双脑架构) 28. **摄像头集成** — OpenCV DirectShow 后端,支持多摄像头切换,绿屏检测,智能预热验证 28a. **ESP32-CAM 双摄** — 支持 ESP32-CAM 作为备选摄像头源,前端 tab 切换本地/ESP32,地址支持 IP 或 mDNS 名称(如 `espcam.local`) 28b. **自动桥接** — 服务器直连 ESP32 失败时,自动通知 App(AionPushService)启动桥接:App 从热点局域网拉帧→上传服务器。直连恢复时自动关闭桥接 28c. **户外模式** — 手机开热点 + ESP32 连热点,App 前台服务桥接帧数据到家里服务器(~1fps,约 80KB/帧),AI 仍可触发 Sentinel/[CAM_CHECK]/定时监控 28d. **零侵入** — 所有下游(Sentinel、Core、[CAM_CHECK]、定时监控、预览)通过 `get_frame_jpeg()` 取帧,无需感知帧来源。`active_source` 默认 `local`,不配置 ESP32 时行为完全不变 29. **Sentinel 哨兵** — 定时截图后由轻量模型(flash-lite)分析,注入设备活动摘要(近 60 分钟 6 条)作为辅助判断依据,输出结构化 JSON(含概况摘要 summary + 唤醒原因 core_reason) 30. **Core 唤醒** — Sentinel 判断需要时唤醒 Core(当前聊天模型),Core 收到哨兵摘要+唤醒原因+最近5条日志+记忆召回,主动在对话中联系用户 31. **监控日志系统** — 独立于聊天的 JSONL 日志,按日期存储,3 天自动清理 32. **日志查看器** — 侧边栏「📜 监控日志」按钮,按日期浏览,显示概况摘要和唤醒原因,WebSocket 实时推送新日志 33. **聊天状态摘要(chat_status)** — 即时哨兵提取,存储在 `data/chat_status.json`,监控哨兵分析时自动注入 ### Core 主动查看监控([CAM_CHECK]) 34. **[CAM_CHECK] 指令** — 摄像头开启时,prompt 中注入能力提示,Core 可在回复中输出 `[CAM_CHECK]` 指令主动请求查看监控画面 35. **前端实时过滤** — 流式输出时前端实时 strip `[CAM_CHECK]`,用户看不到原始指令 36. **提示音 + 5秒延迟** — 检测到指令后前端播放 `AionMonitoralart.mp3` 提示音,等待 5 秒给用户反应时间,然后再截图 37. **加载指示器** — 等待期间在 AI 消息下方显示「📷 {AI名} 正在查看监控 ● ● ●」弹跳动画,5秒后自动移除(renderMessages 重建后自动恢复) 38. **后台截图+AI分析** — 5秒后前端 POST `/api/cam-check-trigger`,后端截图并调用 Core 模型分析画面,结果作为新 assistant 消息保存并 WebSocket 广播 39. **摄像头离线处理** — 若摄像头未开启,后端发 `cam_offline` SSE 事件,前端显示「📷 摄像头未开启,Core无法查看监控信息」提示 40. **两套系统独立** — 哨兵定时监控和 Core 主动查看是完全独立的两套系统,互不影响。关闭哨兵不影响 Core 主动查看,反之亦然 ### Core 主动查看设备动态([查看动态:n]) 40a. **[查看动态:n] 指令** — AI联动开关开启时,prompt 中注入能力提示,Core 可在回复中输出 `[查看动态:n]`(n=1~12,对应 10~120 分钟)主动查看用户设备使用动态 40b. **n 值安全** — n 自动 clamp 到 1-12 范围,无效值默认为 6(60 分钟),避免异常请求 40c. **前端实时过滤** — 流式输出时前端实时 strip `[查看动态:n]`,用户看不到原始指令 40d. **加载指示器** — 检测到指令后在 AI 消息下方显示「📊 {AI名} 正在查看你的动态 ● ● ●」紫色主题弹跳动画(30 秒安全超时自动移除) 40e. **后台摘要+AI分析** — 后端获取设备活动摘要,组装 Prompt(人设+上下文+摘要)调用 Core 生成关怀/评论回复,结果作为新 assistant 消息保存并 WebSocket 广播 40f. **系统消息** — 查看动态后自动插入 system 消息「{AI名}查看了{用户名}过去N分钟的动态」,纳入上下文关键词匹配 40g. **与摄像头监控独立** — 查看动态仅读取设备活动日志,不依赖摄像头,两套系统完全独立 ### Sentinel/Core 工作流程 ``` 【哨兵定时监控】 定时截图 → 获取设备活动摘要(近 60 分钟 6 条)→ Sentinel(flash-lite) 分析 → 输出 JSON: { "monitoringlog": "观察描述...", "summary": "这段时间的概况摘要...", "call_core": true/false, "core_reason": "唤醒原因(仅call_core=true时)" } ↓ 日志写入 monitor_logs/YYYY-MM-DD.jsonl + WebSocket 广播 ↓ (如果 call_core = true) 组装提示词(含唤醒原因 + 概况摘要 + 最近5条日志 + 世界书 + 聊天上下文 + 记忆召回) → Core(当前模型) 生成回复 → 作为 assistant 消息插入对话 【Core 主动查看监控 [CAM_CHECK]】 Core 回复包含 [CAM_CHECK] → 后端检测并发 SSE 事件 + WebSocket 广播 → 前端播放提示音 → 等待 5 秒 → POST /api/cam-check-trigger → 后端截图 → 带人设+上下文+图片调用 Core → 结果作为新 assistant 消息保存+广播 ``` ### 语音唤醒 + 半双工通话 41. **语音唤醒** — 聊天配置面板开关,支持自定义唤醒词,后台持续监听麦克风 42. **WebRTC VAD** — 使用 Google WebRTC VAD 频谱分析检测人声,不靠音量阈值,嗰杂环境(狗叫/风扇/空调)也能稳定工作 43. **半双工通话模式** — 唤醒后进入通话:用户说话 → ASR 识别 → 发送到聊天 → AI 回复 + TTS 播放 → 轮到用户说话,循环往复 44. **麦克风协调** — AI 说话(TTS 播放 / [CAM_CHECK] 处理)期间暂停录音,服务端 `tts_done` 事件触发前端 `notifyVoiceAiSpeaking(false)` 自动恢复录音;voice.py 发送消息时自动携带 `tts_enabled`/`tts_voice` 参数 45. **语音挂断** — 说“再见/拜拜/挂断”自动挂断通话,继续监听唤醒词;60 秒无人说话自动挂断 46. **唤醒回复音频** — 唤醒成功后播放 `public/AIonResponse.mp3`(“诶,我在呢”) 47. **通话状态指示器** — 前端顶部实时显示:等待唤醒 / 聆听中 / AI 思考中 / 通话结束,含挂断按钮 48. **完整功能集成** — 语音发送的消息与手动发送完全一致:有 debug 信息、记忆召回、[CAM_CHECK] 能力 ### 语音唤醒工作流程 ``` 【监听待命】 WebRTC VAD 持续检测 → 检测到人声 → 录音 → 静音截断 → ASR 识别 → 文本包含唤醒词? → 是 → 进入通话模式 【通话模式(半双工)】 播放唤醒回复音频 → 等待 AI 说完 → 循环: ├ 录音(VAD 检测 + 1.5 秒静音截断) ├ ASR 识别 ├ 检查挂断关键词 → 是 → 发送消息 + 挂断 → 回到监听待命 └ 发送消息到聊天 → AI 回复 + TTS → 暂停麦克风 → TTS 播完 → 继续录音 → 60 秒无人说话 → 自动挂断 → 回到监听待命 【状态同步】 voice.py 通过 WebSocket 广播 voice_state 事件 voice.py 发送消息时携带 tts_enabled/tts_voice 参数 → 服务端创建 TTSStreamer → TTS 分片通过 WebSocket tts_chunk 推送 → 前端按序播放 → 全部合成完毕 → 服务端广播 tts_done → 前端 notifyVoiceAiSpeaking(false) → 恢复录音 [CAM_CHECK] 触发时通知后端保持 AI 说话状态 ``` ### 视频通话([视频电话]) 204. **视频通话模式** — 摄像头预览 + 按住录制视频片段 + ASR 转写 + AI 多模态理解,实现「看到你 + 听到你 + 跟你说话」的完整通话体验。录制的视频片段直接发送给 Gemini(inline_data,最大 20MB),AI 可以看到画面和听到声音 205. **用户主动发起** — 聊天页面 📹 按钮发起视频通话,3 秒等待期间播放铃声动画,用户可取消 206. **AI 主动发起** — AI 回复包含 `[视频电话]` 指令时,后端延迟 10 秒后通过 WebSocket 定向推送给发送者客户端,前端弹出来电 UI(铃声 + 接听/挂断按钮) 207. **来电指示器** — AI 回复触发视频通话时,消息底部显示「📹 AI 正在发起视频通话...」动画指示器,10 秒后自动消失并触发来电 UI 208. **摄像头预览** — 全屏通话界面显示用户摄像头画面(主画面)和 AI 头像(画中画),支持点击切换大小画面位置 209. **按住录制** — 通话界面底部「🎙 按住录制」按钮,按住开始录制视频+音频,松手停止并自动发送。支持上滑取消录制,最长录制 60 秒(自动停止) 210. **浏览器双轨录制** — PC/手机 Chrome 使用双 MediaRecorder:一轨录制视频+音频(WebM),一轨单独录制音频(用于 ASR 转写),确保视频和转写文本同时获得 211. **Android 原生视频录制** — `VideoBridge.java` 使用 MediaCodec(H.264) + MediaCodec(AAC) + MediaMuxer 编码 MP4,复用 CameraBridge 的 NV21 预览帧和 AudioBridge 的 PCM 音频帧,录制期间摄像头预览不中断 212. **视频片段附件** — 录制完成后上传视频文件,ASR 转写音频,构建 `{type: "video_clip", url, duration, transcript}` 附件发送到聊天 213. **Gemini 视频理解** — 当前消息的视频以 inline_data 发送给 Gemini(支持 video/mp4、video/webm),AI 可以同时理解画面和音频内容;历史消息中的视频片段仅保留转写文本 `[视频通话] {transcript}`,不重复发送视频数据 214. **视频气泡** — 聊天记录中视频片段以渐变色气泡展示(📹 图标 + 时长),点击可全屏播放 215. **前后摄像头切换** — 通话界面 🔄 按钮支持前后摄像头切换 216. **不活跃自动挂断** — 120 秒内无任何录制操作自动挂断通话 217. **开关控制** — 聊天配置面板中「视频通话」开关控制 AI 是否具有发起视频通话的能力(`[视频电话]` 指令是否注入 prompt),用户主动发起不受开关影响 218. **前端指令过滤** — 流式输出时前端实时 strip `[视频电话]`,用户看不到原始指令 ### AI 生图([SELFIE:xxx] / [DRAW:xxx]) 400. **AI 自主生图** — AI 在回复中输出 `[SELFIE:prompt]`(自拍/角色一致性生图)或 `[DRAW:prompt]`(自由创作生图)指令,后端自动检测并异步调用 Gemini 生图 API 401. **SELFIE 模式** — 附带 `public/生图锚点.jpg` 作为参考图片(base64 inlineData),Gemini 基于参考图生成角色一致的新图片,适合 AI 发自拍 402. **DRAW 模式** — 纯文本 prompt 自由生图,不附带参考图,适合 AI 画画/创作 403. **异步非阻塞** — 生图任务通过 `asyncio.create_task()` 在后台执行,不阻塞聊天流和页面操作。生图期间用户可继续发消息、切换页面 404. **加载指示器** — 检测到生图指令后在 AI 消息下方显示「🎨 {AI名} 正在发送图片 ● ● ●」橙色主题弹跳动画(renderMessages 重建后自动恢复) 405. **图片消息** — 生图完成后,图片保存到 `data/uploads/img_gen_{timestamp}.{ext}`,创建新 assistant 消息(附带图片附件),通过 WebSocket 广播 `msg_created` + `image_gen_done` 事件 406. **图片查看器** — 聊天中的图片点击后弹出全屏 lightbox,支持保存图片(浏览器用 blob 下载,Android App 通过 `AionImageSaver` 原生桥接写入相册) 407. **前端指令过滤** — 流式输出时前端实时 strip `[SELFIE:xxx]` 和 `[DRAW:xxx]`,用户看不到原始指令 408. **TTS 过滤** — TTS 合成时自动剥除 `[SELFIE:...]` 和 `[DRAW:...]` 内容,不会被语音朗读 409. **开关控制** — 聊天配置面板中「AI 生图」开关控制 AI 是否具有生图能力(指令是否注入 prompt),关闭后 AI 不会尝试生图 410. **Gemini API** — 使用 `gemini-3.1-flash-image-preview` 模型,REST `generateContent` 端点,`responseModalities: ["IMAGE", "TEXT"]`,120 秒超时 411. **三处统一** — send_message、regenerate、Core/语音/定时触发三套 `_bg_generate` 函数均支持生图指令检测和异步生图 ### AI 生图工作流程 ``` 【AI 触发生图(正常聊天 / 语音 / Core 主动发言)】 AI 回复包含 [SELFIE:穿着白裙子在花园里] 或 [DRAW:一只飞翔的龙] → 后端 regex 检测 → 从显示文本和数据库中 strip 掉 → SSE 发 image_gen_start 事件 + WebSocket 广播 → 前端显示「🎨 正在发送图片」橙色指示器 → asyncio.create_task(_do_image_gen(...)) 【异步生图(_do_image_gen)】 ├ SELFIE 模式:读取 public/生图锚点.jpg → base64 编码 → 作为 inlineData 附加到请求 ├ DRAW 模式:仅发送文本 prompt → POST https://generativelanguage.googleapis.com/v1beta/models/gemini-3.1-flash-image-preview:generateContent requestBody: { contents: [{parts: [...]}], generationConfig: {responseModalities: ["IMAGE", "TEXT"]} } → 解析 response → 提取 inlineData(base64 图片数据) → 保存到 data/uploads/img_gen_{timestamp}.{ext} → 创建 assistant 消息(附带图片附件 URL) → WebSocket 广播 msg_created + image_gen_done → 前端移除指示器 + 渲染新消息(含图片) 【生图失败】 → WebSocket 广播 image_gen_failed → 前端移除指示器 【图片保存(全屏查看器)】 点击图片 → 全屏 lightbox ├ 浏览器:fetch → blob → createObjectURL → 模拟点击 └ Android App:fetch → blob → FileReader → base64 → AionImageSaver.save() → MediaStore 写入相册 ``` 215. **消息保存** — 通话中的视频片段正常保存到聊天记录,视频文件上传到 `data/uploads/`,转写文本存入附件数据 216. **Chrome 兼容** — PC/手机 Chrome 浏览器使用标准 `getUserMedia` API 获取摄像头+麦克风,无需原生桥;Android WebView 自动 fallback 到 `CameraBridge` + `AudioBridge` + `VideoBridge` ### 视频通话工作流程 ``` 【用户主动发起】 点击 📹 按钮 → 3 秒等待(播放铃声动画)→ 进入通话界面 → 启动摄像头(getUserMedia 或 AionCamera 原生桥) → 启动音频流(仅预热,不录制) → 底部显示「🎙 按住录制」按钮 + 挂断按钮 【按住录制(核心交互)】 按下录制按钮 → 开始录制: 浏览器:双 MediaRecorder(视频+音频 WebM / 纯音频 WebM) Android:AionVideo.startRecord() → MediaCodec H.264 + AAC + MediaMuxer → 界面显示录制计时 + 红色脉冲动画 → 上滑进入「取消区域」→ 松手取消录制 → 正常松手 → 停止录制: 浏览器:双 Blob → 上传视频 + ASR 转写音频 Android:AionVideo.stopRecord() → base64 MP4 → 上传 + 收集的 PCM 帧构建 WAV → ASR → 构建 {type:"video_clip", url, duration, transcript} → POST 发送消息到聊天(视频 inline_data 发给 Gemini) → AI 回复 + TTS → 录制按钮暂时禁用 → TTS 播完 → 恢复录制按钮 → 等待下次按住 【AI 主动发起】 AI 回复包含 [视频电话] → 后端检测 → 从显示文本 strip → 消息底部显示「📹 正在发起视频通话...」指示器 → 10 秒延迟 → WebSocket 定向推送 video_call_ring 给发送者 → 前端弹出来电 UI(铃声 + 接听/挂断) → 用户接听 → 进入通话界面(同上) → 用户挂断/超时 → 取消 【历史消息处理】 当前消息 → 视频以 inline_data 发送给 Gemini(AI 看到画面+听到音频) 历史消息 → 仅保留转写文本「[视频通话] {transcript}」(不重复发送视频) 记忆总结/哨兵 → 仅使用转写文本 【Android 原生视频录制桥(VideoBridge.java)】 JS 调用 AionVideo.startRecord(width, height) → 创建 MediaCodec 视频编码器(H.264, NV12)+ 音频编码器(AAC, 16kHz mono) → MediaMuxer 准备写入临时 MP4 文件 → CameraBridge.processFrame() 中转发 NV21 帧 → NV21→NV12 转换 → 送入视频编码器 → AudioBridge 录音线程中转发 PCM 帧 → 送入音频编码器 → 编码输出同步写入 MediaMuxer → JS 调用 AionVideo.stopRecord() → flush + stop → 读取 MP4 文件 → base64 返回 【Android 原生摄像头桥(CameraBridge.java)】 JS 调用 AionCamera.start("user"|"environment") → Camera.open() → 设置 640×480 NV21 预览 → setPreviewCallbackWithBuffer(3 个预分配 buffer,零 GC) → 摄像头回调 → 复制数据到 inputBuf → 归还 camera buffer → 后台 ExecutorService 线程: ├ NV21 纯字节数组旋转(rotateNV21_CW90/270/180,~1ms) ├ YuvImage.compressToJpeg(已旋转的竖屏 JPEG) ├ Base64 编码 → 更新 lastFrameB64 └ 录制中?→ 转发旋转后的 NV21 帧给 VideoBridge.onVideoFrame() → JS requestAnimationFrame 轮询 getFrame() → 更新 .src ``` ### 音乐点歌([MUSIC:xxx]) 65. **AI 自主点歌** — AI 在回复中输出 `[MUSIC:歌曲名 歌手名]` 指令,后端自动检测并通过 pyncm 搜索网易云音乐 66. **音乐卡片** — 搜索结果以卡片形式展示:封面、歌名、歌手、专辑 + 最多 3 首候选歌曲 67. **双播放模式** — 每首歌提供「网易云播放」(跳转 `music.163.com` 网页)和「在线播放」(页内 `