Files

1 line
49 KiB
JSON
Raw Permalink 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.
{"repo": "andreib180/wechat-skill-chat", "files": {"README.md": {"78f2eca85fba2469e081935592b7cf3b8cda0bb4": {"t": 1785746428.995866, "n": 6175, "h": "e1b5bc59e2aebed5", "c": "<p align=\"center\">\n <img src=\"https://img.shields.io/badge/python-3.10+-blue\" alt=\"Python\">\n <img src=\"https://img.shields.io/badge/license-MIT-green\" alt=\"License\">\n <img src=\"https://img.shields.io/badge/API-Anthropic_Compatible-orange\" alt=\"API\"> <img src=\"https://img.shields.io/badge/mode-Claude_Code-purple\" alt=\"CC\">\n</p>\n\n# WeChat Skill Chat\n\n**和你的 AI 人格在微信里聊天。**\n\n一个像素级复刻微信 PC 版界面的聊天应用。支持双模运行:API 直连 + Claude Code 管道。导入 skill persona,它就成了你的微信好友——像真人一样聊天、用黄脸表情、读文件、执行命令。\n\n---\n\n## 兼容性\n\n本项目使用 **Anthropic Messages API**(`/v1/messages`)。任何兼容该协议的 API 提供商均可使用,包括:\n\n| 提供商 | Base URL |\n|--------|----------|\n| **Anthropic** | 留空(SDK 自动使用 `https://api.anthropic.com`) |\n| **DeepSeek** | `https://api.deepseek.com/anthropic` |\n| 其他兼容网关 | 填入对应的 `/anthropic` 或 `/v1/messages` 端点 |\n\n只要你的 API 能响应 `POST /v1/messages` 并返回 Anthropic 格式的 `content` 数组,就能用。不兼容 OpenAI Chat Completions 格式(`/v1/chat/completions`)。\n\n---\n\n## 功能\n\n- **微信 PC 版 1:1 界面** — 55px 导航栏、250px 联系人列表、自适应聊天区,配色布局完全对齐\n- **Skill 即联系人** — 每个人格是独立的联系人,独立的头像、聊天记录、对话风格\n- **群聊** — 多 Skill 建群,路由 Agent 自动判断该谁回复,支持 @提及、SSE 流式响应\n- **导入即用** — 选择一个 skill 文件夹,自动验证、注册、生成头像、复制 persona\n- **文件附件** — 一次选多个文件发给 AI,支持 txt/docx/pdf,自动提取文本注入上下文\n- **聊天记录持久化** — 每个联系人 / 群聊一个 JSON,关掉浏览器再打开还在,按最新消息自动排序\n- **消息操作** — 右键菜单复制 / 删除消息,软删除标记持久化不丢数据\n- **多模型切换** — 设置里填 API Key + Base URL + Model,随时切 Anthropic ↔ DeepSeek\n- **头像拖拽上传** — 拖图片到设置或联系人编辑框的 URL 输入区,自动上传\n- **零硬编码** — 联系人是 `skills_config.json` 数据文件,群聊是 `groups_config.json`,增删改在 UI 完成,不动代码\n- **可移植** — `pip install flask anthropic && python3 server.py`,整个文件夹下载下来就能跑\n\n---\n\n## Skill 格式\n\n本项目导入的 skill 需要是一个**文件夹**,最低要求包含以下文件之一(优先级:`SKILL.md` > `persona.md`,两者同时存在时只读 `SKILL.md`):\n\n### 方式 A:单文件 `SKILL.md`(推荐)\n\n```\nmy-skill/\n├── SKILL.md # 完整的 persona + work 合并文件\n└── meta.json # 可选,提供 display_name、标签等元数据\n```\n\n这是 dot-skill 的标准输出格式。`SKILL.md` 即为完整的 system prompt,约 20-30KB,包含角色描述、说话风格、行为规则等。\n\n### 方式 B:分离文件 `persona.md` + `work.md`\n\n```\nmy-skill/\n├── persona.md # 人物性格(必选)\n├── work.md # 工作能力(可选)\n└── meta.json # 可选\n```\n\n导入时自动合并 `persona.md` 和 `work.md`。\n\n### meta.json(可选)\n\n```json\n{\n \"display_name\": \"肖易恒\",\n \"name\": \"colleague-xiaoyiheng\",\n \"tags\": [\"NPD\", \"自恋型人格障碍\", \"北京林业大学\"]\n}\n```\n\n- `display_name` → 联系人列表显示的名字(优先于文件夹名)\n- `name` → 内部 skill 名\n- 没有 `meta.json` 时使用文件夹名\n\n> **制作 skill**:用 `/dot-skill` 从聊天记录蒸馏高还原度人格,或用任何 LLM 写一段角色描述存为 `SKILL.md`。\n\n---\n\n## 快速开始\n\n### 1. 安装\n\n```bash\ngit clone https://github.com/AndreiB180/wechat-skill-chat.git\ncd wechat-skill-chat\npip install flask anthropic\n```\n\n### 2. 启动\n\n```bash\npython3 server.py\n```\n\n打开 `http://localhost:5888`。\n\n### 3. 配置 API\n\n左下角齿轮 → 设置:\n\n| 字段 | Anthropic | DeepSeek |\n|------|-----------|----------|\n| Base URL | 留空(SDK 默认) | `https://api.deepseek.com/anthropic` |\n| Model | `claude-sonnet-4-20250514` | `deepseek-v4-pro` |\n| API Key | `sk-ant-...` | `sk-...` |\n\nAPI Key 保存时自动 base64 混淆,不会明文泄露。\n\n### 4. 导入 Skill\n\n通讯录 → **+ 添加 Skill** → 输入文件夹路径 → 导入。新的联系人即刻出现在聊天列表。\n\n---\n\n## 架构\n\n```\nwechat-skill-chat/\n├── server.py # Flask 入口,注册 5 个 Blueprint\n├── skills_config.json # 联系人注册表(JSON 数据,非代码)\n├── groups_config.json # 群聊配置(JSON 数据)\n├── settings.json # API 配置(gitignore)\n├── backend/\n│ ├── config.py # JSON 读写 + fcntl 文件锁\n│ ├── skills.py # Persona 三级查找加载\n│ ├── ai.py # Anthropic SDK 封装 + WeChat 格式注入\n│ ├── history.py # 聊天记录 CRUD(fcntl 锁,上限 300 条)\n│ └── routes/\n│ ├── chat_routes.py # /api/send, /api/history(单聊)\n│ ├── contacts_routes.py # /api/config, import/delete/update\n│ ├── group_routes.py # /api/groups, 群聊 SSE 发送, 路由 Agent\n│ ├── settings_routes.py # /api/settings\n│ └── static_routes.py # /avatars, /emoji, 头像上传\n├── templates/index.html # 微信 PC 版 1:1 结构\n├── static/\n│ ├── css/style.css # 完整样式\n│ ├── js/chat.js # 单聊前端(Emoji渲染/右键菜单/拖拽上传)\n│ ├── js/group-chat.js # 群聊前端(@提及/SSE流/群头像九宫格)\n│ ├── emoji/{face,gesture,...} # 109 个微信黄脸 PNG\n│ └── avatars/ # SVG / 上传头像\n├── skills/ # 用户导入的 skill 文件\n└── chat_history/ # 聊天记录 JSON(每联系人/群聊一个文件)\n```\n\n**数据流**:用户发消息 → Flask → 加载 SKILL.md → 拼入 system prompt(最高优先级格式指令)→ Anthropic Messages API → 按换行拆成多条 → 渲染聊天气泡。\n\n---\n\n## 细节\n\n### 消息发送\n\n用户消息先渲染绿气泡(乐观 UI),不等 API 返回。API 响应后追加白气泡。切换会话时 `chatId` 捕获机制保证消息不串到别人那里。中文输入法组合输入期间 Enter 不触发发送。\n\n### 并发安全\n\n`skills_config.json` 和 `chat_history/*.json` 使用 `fcntl.flock` 文件锁,多个请求同时操作不会损坏数据。每人的聊天记录上限 300 条(超出自动截断)。\n\n### 表情渲染\n\n109 个微信原生黄脸 PNG 按 `face/gesture/animal/blessing/other` 五类分目录。前端 `_emojiLookup` 映射中文名到目录,`[捂脸]` 在聊天气泡中渲染为 `<img src=\"/emoji/face/捂脸.png\">`。表情选择面板可直接点击插入。\n\n### 时间格式化\n\n| 距离 | 聊天气泡 | 联系人卡片 |\n|------|---------|-----------|\n| 今天 | `14:30` | `14:30` |\n| 昨天 | `昨天 14:30` | `昨天14:30` |\n| 2-6天前 | `星期三 14:30` | `星期三` |\n| 今年内 | `5/20 14:30` | `5/20` |\n| 更早 | `2025/12/3 14:30` | `2025/12/3` |\n\n### AI 格式约束\n\n每次 API 调用前,system prompt 最前面注入最高优先级格式指令,强制模型:\n- **禁止 Markdown 语法** — `# * ** ~~ \\` \\`\\`\\`` 等全部禁用,微信没人用这些\n- 禁止 `(顿了顿)` 等括号动作描写\n- 禁止旁白、叙述性文字、场景描述\n- 表情用 `[捂脸]` 格式\n- 消息简短、口语化、无剧本感\n\n### 消息操作\n\n右键聊天气泡弹出菜单,可复制消息文本(表情自动转为 `[捂脸]` 格式)或删除消息。删除采用软删除——聊天记录 JSON 中标记 `deleted: true`,渲染时过滤,服务器重启后依然有效。\n\n### 头像管理\n\n设置页和联系人编辑框中,将图片文件直接拖入 URL 输入框即可上传到 `static/avatars/`,自动生成 UUID 文件名。新导入的 Skill 自动生成首字母 SVG 头像,颜色从 8 种预设色中 hash 分配。\n\n### 输入框\n\n工具栏含表情/文件/语音通话/视频通话四个图标。语音/视频通话点击弹出 `\"你走火入魔了,还真想给 AI 打电话啊?\"`。输入框可拖拽顶部边框调整高度(52-120px)。有文字时发送按钮变微信绿。\n\n### 文件附件\n\n前端将文件转为 base64 传给后端。后端根据扩展名选择解析器:\n\n| 类型 | 支持 | 需要 |\n|------|------|------|\n| `.txt` `.md` `.py` 等 | ✓ 内置 | 无 |\n| `.docx` | ✓ | `pip install python-docx` |\n| `.pdf`(有文本层) | ✓ | `pip install PyPDF2` |\n\n提取文本截断到 100,000 字符注入 API 调用。聊天记录存 JSON 时再截断预览,避免历史文件过大。\n\n### 群聊\n\n联系人列表顶部 **+** 按钮可发起群聊,选多个 Skill 组成群。群聊通过 SSE(Server-Sent Events)实时流式返回消息。\n\n**路由 Agent**:系统先调用一个轻量 LLM 判断消息应该由哪个成员回复——如果消息中包含某成员的真名或显示名,该成员强制回复。接着最多进行 2-3 轮迭代,每轮选一个尚未发言的成员回复,有 90% 概率选还没说过话的人,避免同一人霸屏。\n\n**上下文隔离**:历史记录放进 system prompt 作为参考文本(而非 messages 数组),避免模型机械复制前人格式。每次调用前注入群成员名单 + 真名对应关系,强制模型用真名称呼他人。\n\n**@提及**:输入框打 `@` 自动弹出成员列表,支持 @所有人。检测到提及后强制对应成员回复。\n\n**群聊历史**存储在 `chat_history/grp_*.json`,支持右键删除消息(软删除,标记 `deleted: true`)。\n"}, "ff6841da8b260b86b074714a185b2b8c23ec54ee": {"t": 1785764106.1892605, "n": 6193, "h": "cf6f8030df532daf", "c": "<p align=\"center\">\n <img src=\"https://img.shields.io/badge/python-3.10+-blue\" alt=\"Python\">\n <img src=\"https://img.shields.io/badge/license-MIT-green\" alt=\"License\">\n <img src=\"https://img.shields.io/badge/API-Anthropic_Compatible-orange\" alt=\"API\">\n</p>\n# WeChat Skill Chat\n\n**和你的 AI 人格在微信里聊天。**\n\n一个像素级复刻微信 PC 版界面的聊天应用。导入一个 skill 文件夹,它就成了你的微信好友——像真人一样说话,用微信的黄脸表情,能读你发的文件。把任何 LLM persona 变成联系人。\n\n\n<p align=\"center\">\n <img src=\"screenshot.png\" width=\"720\" alt=\"WeChat Skill Chat screenshot\">\n</p>\n\n---\n\n## 兼容性\n\n本项目使用 **Anthropic Messages API**(`/v1/messages`)。任何兼容该协议的 API 提供商均可使用,包括:\n\n| 提供商 | Base URL |\n|--------|----------|\n| **Anthropic** | 留空(SDK 自动使用 `https://api.anthropic.com`) |\n| **DeepSeek** | `https://api.deepseek.com/anthropic` |\n| 其他兼容网关 | 填入对应的 `/anthropic` 或 `/v1/messages` 端点 |\n\n只要你的 API 能响应 `POST /v1/messages` 并返回 Anthropic 格式的 `content` 数组,就能用。不兼容 OpenAI Chat Completions 格式(`/v1/chat/completions`)。\n\n---\n\n## 功能\n\n- **微信 PC 版 1:1 界面** — 55px 导航栏、250px 联系人列表、自适应聊天区,配色布局完全对齐\n- **Skill 即联系人** — 每个人格是独立的联系人,独立的头像、聊天记录、对话风格\n- **群聊** — 多 Skill 建群,路由 Agent 自动判断该谁回复,支持 @提及、SSE 流式响应\n- **导入即用** — 选择一个 skill 文件夹,自动验证、注册、生成头像、复制 persona\n- **文件附件** — 一次选多个文件发给 AI,支持 txt/docx/pdf,自动提取文本注入上下文\n- **聊天记录持久化** — 每个联系人 / 群聊一个 JSON,关掉浏览器再打开还在,按最新消息自动排序\n- **消息操作** — 右键菜单复制 / 删除消息,软删除标记持久化不丢数据\n- **多模型切换** — 设置里填 API Key + Base URL + Model,随时切 Anthropic ↔ DeepSeek\n- **头像拖拽上传** — 拖图片到设置或联系人编辑框的 URL 输入区,自动上传\n- **零硬编码** — 联系人是 `skills_config.json` 数据文件,群聊是 `groups_config.json`,增删改在 UI 完成,不动代码\n- **可移植** — `pip install flask anthropic && python3 server.py`,整个文件夹下载下来就能跑\n\n---\n\n## Skill 格式\n\n本项目导入的 skill 需要是一个**文件夹**,最低要求包含以下文件之一(优先级:`SKILL.md` > `persona.md`,两者同时存在时只读 `SKILL.md`):\n\n### 方式 A:单文件 `SKILL.md`(推荐)\n\n```\nmy-skill/\n├── SKILL.md # 完整的 persona + work 合并文件\n└── meta.json # 可选,提供 display_name、标签等元数据\n```\n\n这是 dot-skill 的标准输出格式。`SKILL.md` 即为完整的 system prompt,约 20-30KB,包含角色描述、说话风格、行为规则等。\n\n### 方式 B:分离文件 `persona.md` + `work.md`\n\n```\nmy-skill/\n├── persona.md # 人物性格(必选)\n├── work.md # 工作能力(可选)\n└── meta.json # 可选\n```\n\n导入时自动合并 `persona.md` 和 `work.md`。\n\n### meta.json(可选)\n\n```json\n{\n \"display_name\": \"肖易恒\",\n \"name\": \"colleague-xiaoyiheng\",\n \"tags\": [\"NPD\", \"自恋型人格障碍\", \"北京林业大学\"]\n}\n```\n\n- `display_name` → 联系人列表显示的名字(优先于文件夹名)\n- `name` → 内部 skill 名\n- 没有 `meta.json` 时使用文件夹名\n\n> **制作 skill**:用 `/dot-skill` 从聊天记录蒸馏高还原度人格,或用任何 LLM 写一段角色描述存为 `SKILL.md`。\n\n---\n\n## 快速开始\n\n### 1. 安装\n\n```bash\ngit clone https://github.com/AndreiB180/wechat-skill-chat.git\ncd wechat-skill-chat\npip install flask anthropic\n```\n\n### 2. 启动\n\n```bash\npython3 server.py\n```\n\n打开 `http://localhost:5888`。\n\n### 3. 配置 API\n\n左下角齿轮 → 设置:\n\n| 字段 | Anthropic | DeepSeek |\n|------|-----------|----------|\n| Base URL | 留空(SDK 默认) | `https://api.deepseek.com/anthropic` |\n| Model | `claude-sonnet-4-20250514` | `deepseek-v4-pro` |\n| API Key | `sk-ant-...` | `sk-...` |\n\nAPI Key 保存时自动 base64 混淆,不会明文泄露。\n\n### 4. 导入 Skill\n\n通讯录 → **+ 添加 Skill** → 输入文件夹路径 → 导入。新的联系人即刻出现在聊天列表。\n\n---\n\n## 架构\n\n```\nwechat-skill-chat/\n├── server.py # Flask 入口,注册 5 个 Blueprint\n├── skills_config.json # 联系人注册表(JSON 数据,非代码)\n├── groups_config.json # 群聊配置(JSON 数据)\n├── settings.json # API 配置(gitignore)\n├── backend/\n│ ├── config.py # JSON 读写 + fcntl 文件锁\n│ ├── skills.py # Persona 三级查找加载\n│ ├── ai.py # Anthropic SDK 封装 + WeChat 格式注入\n│ ├── history.py # 聊天记录 CRUD(fcntl 锁,上限 300 条)\n│ └── routes/\n│ ├── chat_routes.py # /api/send, /api/history(单聊)\n│ ├── contacts_routes.py # /api/config, import/delete/update\n│ ├── group_routes.py # /api/groups, 群聊 SSE 发送, 路由 Agent\n│ ├── settings_routes.py # /api/settings\n│ └── static_routes.py # /avatars, /emoji, 头像上传\n├── templates/index.html # 微信 PC 版 1:1 结构\n├── static/\n│ ├── css/style.css # 完整样式\n│ ├── js/chat.js # 单聊前端(Emoji渲染/右键菜单/拖拽上传)\n│ ├── js/group-chat.js # 群聊前端(@提及/SSE流/群头像九宫格)\n│ ├── emoji/{face,gesture,...} # 109 个微信黄脸 PNG\n│ └── avatars/ # SVG / 上传头像\n├── skills/ # 用户导入的 skill 文件\n└── chat_history/ # 聊天记录 JSON(每联系人/群聊一个文件)\n```\n\n**数据流**:用户发消息 → Flask → 加载 SKILL.md → 拼入 system prompt(最高优先级格式指令)→ Anthropic Messages API → 按换行拆成多条 → 渲染聊天气泡。\n\n---\n\n## 细节\n\n### 消息发送\n\n用户消息先渲染绿气泡(乐观 UI),不等 API 返回。API 响应后追加白气泡。切换会话时 `chatId` 捕获机制保证消息不串到别人那里。中文输入法组合输入期间 Enter 不触发发送。\n\n### 并发安全\n\n`skills_config.json` 和 `chat_history/*.json` 使用 `fcntl.flock` 文件锁,多个请求同时操作不会损坏数据。每人的聊天记录上限 300 条(超出自动截断)。\n\n### 表情渲染\n\n109 个微信原生黄脸 PNG 按 `face/gesture/animal/blessing/other` 五类分目录。前端 `_emojiLookup` 映射中文名到目录,`[捂脸]` 在聊天气泡中渲染为 `<img src=\"/emoji/face/捂脸.png\">`。表情选择面板可直接点击插入。\n\n### 时间格式化\n\n| 距离 | 聊天气泡 | 联系人卡片 |\n|------|---------|-----------|\n| 今天 | `14:30` | `14:30` |\n| 昨天 | `昨天 14:30` | `昨天14:30` |\n| 2-6天前 | `星期三 14:30` | `星期三` |\n| 今年内 | `5/20 14:30` | `5/20` |\n| 更早 | `2025/12/3 14:30` | `2025/12/3` |\n\n### AI 格式约束\n\n每次 API 调用前,system prompt 最前面注入最高优先级格式指令,强制模型:\n- **禁止 Markdown 语法** — `# * ** ~~ \\` \\`\\`\\`` 等全部禁用,微信没人用这些\n- 禁止 `(顿了顿)` 等括号动作描写\n- 禁止旁白、叙述性文字、场景描述\n- 表情用 `[捂脸]` 格式\n- 消息简短、口语化、无剧本感\n\n### 消息操作\n\n右键聊天气泡弹出菜单,可复制消息文本(表情自动转为 `[捂脸]` 格式)或删除消息。删除采用软删除——聊天记录 JSON 中标记 `deleted: true`,渲染时过滤,服务器重启后依然有效。\n\n### 头像管理\n\n设置页和联系人编辑框中,将图片文件直接拖入 URL 输入框即可上传到 `static/avatars/`,自动生成 UUID 文件名。新导入的 Skill 自动生成首字母 SVG 头像,颜色从 8 种预设色中 hash 分配。\n\n### 输入框\n\n工具栏含表情/文件/语音通话/视频通话四个图标。语音/视频通话点击弹出 `\"你走火入魔了,还真想给 AI 打电话啊?\"`。输入框可拖拽顶部边框调整高度(52-120px)。有文字时发送按钮变微信绿。\n\n### 文件附件\n\n前端将文件转为 base64 传给后端。后端根据扩展名选择解析器:\n\n| 类型 | 支持 | 需要 |\n|------|------|------|\n| `.txt` `.md` `.py` 等 | ✓ 内置 | 无 |\n| `.docx` | ✓ | `pip install python-docx` |\n| `.pdf`(有文本层) | ✓ | `pip install PyPDF2` |\n\n提取文本截断到 100,000 字符注入 API 调用。聊天记录存 JSON 时再截断预览,避免历史文件过大。\n\n### 群聊\n\n联系人列表顶部 **+** 按钮可发起群聊,选多个 Skill 组成群。群聊通过 SSE(Server-Sent Events)实时流式返回消息。\n\n**路由 Agent**:系统先调用一个轻量 LLM 判断消息应该由哪个成员回复——如果消息中包含某成员的真名或显示名,该成员强制回复。接着最多进行 2-3 轮迭代,每轮选一个尚未发言的成员回复,有 90% 概率选还没说过话的人,避免同一人霸屏。\n\n**上下文隔离**:历史记录放进 system prompt 作为参考文本(而非 messages 数组),避免模型机械复制前人格式。每次调用前注入群成员名单 + 真名对应关系,强制模型用真名称呼他人。\n\n**@提及**:输入框打 `@` 自动弹出成员列表,支持 @所有人。检测到提及后强制对应成员回复。\n\n**群聊历史**存储在 `chat_history/grp_*.json`,支持右键删除消息(软删除,标记 `deleted: true`)。\n"}, "7012cdc6ec354c0defe8b91212ee478f82c7a771": {"t": 1785764108.4703562, "n": 2928, "h": "9a0321b2dfcfa40d", "c": "<p align=\"center\">\n <img src=\"https://img.shields.io/badge/python-3.10+-blue\" alt=\"Python\">\n <img src=\"https://img.shields.io/badge/license-MIT-green\" alt=\"License\">\n <img src=\"https://img.shields.io/badge/mode-API_|_Claude_Code-orange\" alt=\"Dual Mode\">\n</p>\n\n# WeChat Skill Chat\n\n**像素级复刻微信 PC 版界面的 AI 聊天应用。支持双模运行:API 直连 + Claude Code 管道。**\n\n导入 skill persona,它就成了你的微信好友——像真人一样聊天、用黄脸表情、读文件、执行命令。私聊 + 群聊,所有对话持久化。\n\n---\n\n## 双模运行\n\n| | API 模式 | Claude Code 模式 |\n|---|---|---|\n| **原理** | 直接调用 Anthropic 兼容 API | 启动本地 `ccb` 子进程,stream-json 管道通信 |\n| **能力** | 纯文本对话 + 文件内容注入 | 完整 CC 能力:读写文件、执行命令、搜索等 |\n| **权限** | 无需 | auto / bypassPermissions,设置页动态切换 |\n| **启动** | 填 API Key 即可 | 需本地安装 `ccb`(或 `claude`) |\n| **适用** | 轻量聊天 | 需要 AI 帮你干活的场景 |\n\n- **CC 模式支持动态权限切换**:auto 和 bypassPermissions 之间随时切,不丢对话上下文\n- **原生文件选择器**:CC 模式下点 📄 按钮 → macOS 原生对话框 → 文件/文件夹绝对路径直接填入输入框\n- **400 自动恢复**:CC 内部工具拒绝产生的孤儿 tool_use 导致的 API 400 错误,后台自动重试,前端无感知\n- **媒体附件**(API 模式):多文件上传,自动提取 txt/docx/pdf 文本注入上下文\n\n---\n\n## 功能\n\n- **双模切换** — 设置页一键切换 API / CC 模式,CC 模式下检测 CLI 可用性\n- **动态权限** — auto(分类器自动决定)和 bypassPermissions(全部放行),设置页实时切换\n- **私聊 + 群聊** — 多人群聊,支持 @提及,路由 agent 决定谁回复\n- **微信界面** — 55px 导航栏、250px 联系人列表、聊天列表按最新消息排序\n- **Skill 即联系人** — 每个 persona 是独立联系人,独立头像、聊天记录\n- **对话持久化** — JSON 文件存储,关浏览器再开还在\n- **文件附件** — API 模式下读文件内容注入上下文;CC 模式下选绝对路径传给 CC\n- **右键菜单** — 复制消息、删除消息\n- **表情包** — 微信黄脸表情 PNG,支持 `[捂脸]` `[旺柴]` 等代码\n\n---\n\n## 快速开始\n\n```bash\npip install flask anthropic python-docx PyPDF2\npython3 server.py\n# 浏览器自动打开 http://localhost:5888\n```\n\n### API 模式\n1. 设置页填入 API Key、Base URL、Model\n2. 导入一个 Skill 文件夹(或直接在 `skills/` 下放 `.md` 文件,在 `skills_config.json` 注册)\n3. 开始聊天\n\n### Claude Code 模式\n1. 确保 `ccb`(或 `claude`)在 PATH 中\n2. 设置页切换到 Claude Code 模式,点「检测」确认可用\n3. 权限模式选 `auto`(推荐)或 `bypassPermissions`\n4. 开始聊天 — CC 能读文件、跑命令、写代码\n\n---\n\n## Skill 格式\n\n每个 skill 是一个 `.md` 文件放在 `skills/` 目录,内容为 system prompt(角色描述、说话风格、行为规则)。\n\n在 `skills_config.json` 中注册:\n\n```json\n{\n \"skills\": [\n {\n \"id\": \"my_bot\",\n \"name\": \"小明\",\n \"skill_name\": \"xiaoming\",\n \"avatar\": \"avatars/xiaoming.jpg\",\n \"real_name\": \"小明\"\n }\n ]\n}\n```\n\n`skill_name` 对应 `skills/` 下的文件名(不含 `.md`)。\n\n---\n\n## 项目结构\n\n```\nwechat-skill-chat/\n├── server.py # Flask 入口\n├── settings.json # API Key、模式等配置\n├── skills_config.json # 联系人注册表\n├── groups_config.json # 群聊配置\n├── backend/\n│ ├── ai.py # API 模式调用逻辑\n│ ├── claude_cli.py # CC CLI 检测\n│ ├── claude_session.py # CC 持久化子进程管理(stream-json I/O)\n│ ├── config.py # 设置读写\n│ ├── history.py # 聊天记录持久化\n│ └── routes/ # Flask 路由\n├── skills/ # Skill persona 文件(.md)\n├── static/\n│ ├── css/style.css\n│ ├── js/chat.js # 私聊前端\n│ ├── js/group-chat.js # 群聊前端\n│ ├── avatars/ # 头像图片\n│ └── emoji/ # 微信表情 PNG\n└── templates/index.html\n```\n\n---\n\n## 兼容 API\n\n任何兼容 Anthropic Messages API(`/v1/messages`)的提供商均可使用:Anthropic、DeepSeek、及其他兼容网关。\n"}, "98dae3850412fbfec4101153202e98e03e9d5093": {"t": 1785764109.914901, "n": 5107, "h": "076ae03bb9892ba2", "c": "<p align=\"center\">\n <img src=\"https://img.shields.io/badge/python-3.10+-blue\" alt=\"Python\">\n <img src=\"https://img.shields.io/badge/license-MIT-green\" alt=\"License\">\n <img src=\"https://img.shields.io/badge/API-Anthropic_Compatible-orange\" alt=\"API\">\n</p>\n\n# WeChat Skill Chat\n\n**和你的 AI 人格在微信里聊天。**\n\n一个像素级复刻微信 PC 版界面的聊天应用。导入一个 skill 文件夹,它就成了你的微信好友——像真人一样说话,用微信的黄脸表情,能读你发的文件。把任何 LLM persona 变成联系人。\n\n\n<p align=\"center\">\n <img src=\"screenshot.png\" width=\"720\" alt=\"WeChat Skill Chat screenshot\">\n</p>\n\n---\n\n## 兼容性\n\n本项目使用 **Anthropic Messages API**(`/v1/messages`)。任何兼容该协议的 API 提供商均可使用,包括:\n\n| 提供商 | Base URL |\n|--------|----------|\n| **Anthropic** | 留空(SDK 自动使用 `https://api.anthropic.com`) |\n| **DeepSeek** | `https://api.deepseek.com/anthropic` |\n| 其他兼容网关 | 填入对应的 `/anthropic` 或 `/v1/messages` 端点 |\n\n只要你的 API 能响应 `POST /v1/messages` 并返回 Anthropic 格式的 `content` 数组,就能用。不兼容 OpenAI Chat Completions 格式(`/v1/chat/completions`)。\n\n---\n\n## 功能\n\n- **微信 PC 版 1:1 界面** — 55px 导航栏、250px 联系人列表、自适应聊天区,配色布局完全对齐\n- **Skill 即联系人** — 每个人格是独立的联系人,独立的头像、聊天记录、对话风格\n- **导入即用** — 选择一个 skill 文件夹,自动验证、注册、生成头像、复制 persona\n- **文件附件** — 一次选多个文件发给 AI,支持 txt/docx/pdf,自动提取文本注入上下文\n- **聊天记录持久化** — 每个联系人一个 JSON,关掉浏览器再打开还在,按最新消息自动排序\n- **多模型切换** — 设置里填 API Key + Base URL + Model,随时切 Anthropic ↔ DeepSeek\n- **零硬编码** — 联系人是 `skills_config.json` 数据文件,增删改在 UI 完成,不动代码\n- **可移植** — `pip install flask anthropic && python3 server.py`,整个文件夹下载下来就能跑\n\n---\n\n## Skill 格式\n\n本项目导入的 skill 需要是一个**文件夹**,最低要求包含以下文件之一(优先级:`SKILL.md` > `persona.md`,两者同时存在时只读 `SKILL.md`):\n\n### 方式 A:单文件 `SKILL.md`(推荐)\n\n```\nmy-skill/\n├── SKILL.md # 完整的 persona + work 合并文件\n└── meta.json # 可选,提供 display_name、标签等元数据\n```\n\n这是 dot-skill 的标准输出格式。`SKILL.md` 即为完整的 system prompt,约 20-30KB,包含角色描述、说话风格、行为规则等。\n\n### 方式 B:分离文件 `persona.md` + `work.md`\n\n```\nmy-skill/\n├── persona.md # 人物性格(必选)\n├── work.md # 工作能力(可选)\n└── meta.json # 可选\n```\n\n导入时自动合并 `persona.md` 和 `work.md`。\n\n### meta.json(可选)\n\n```json\n{\n \"display_name\": \"肖易恒\",\n \"name\": \"colleague-xiaoyiheng\",\n \"tags\": [\"NPD\", \"自恋型人格障碍\", \"北京林业大学\"]\n}\n```\n\n- `display_name` → 联系人列表显示的名字(优先于文件夹名)\n- `name` → 内部 skill 名\n- 没有 `meta.json` 时使用文件夹名\n\n> **制作 skill**:用 `/dot-skill` 从聊天记录蒸馏高还原度人格,或用任何 LLM 写一段角色描述存为 `SKILL.md`。\n\n---\n\n## 快速开始\n\n### 1. 安装\n\n```bash\ngit clone https://github.com/AndreiB180/wechat-skill-chat.git\ncd wechat-skill-chat\npip install flask anthropic\n```\n\n### 2. 启动\n\n```bash\npython3 server.py\n```\n\n打开 `http://localhost:5888`。\n\n### 3. 配置 API\n\n左下角齿轮 → 设置:\n\n| 字段 | Anthropic | DeepSeek |\n|------|-----------|----------|\n| Base URL | 留空(SDK 默认) | `https://api.deepseek.com/anthropic` |\n| Model | `claude-sonnet-4-20250514` | `deepseek-v4-pro` |\n| API Key | `sk-ant-...` | `sk-...` |\n\nAPI Key 保存时自动 base64 混淆,不会明文泄露。\n\n### 4. 导入 Skill\n\n通讯录 → **+ 添加 Skill** → 输入文件夹路径 → 导入。新的联系人即刻出现在聊天列表。\n\n---\n\n## 架构\n\n```\nwechat-skill-chat/\n├── server.py # Flask 入口,注册 4 个 Blueprint\n├── skills_config.json # 联系人注册表(JSON 数据,非代码)\n├── settings.json # API 配置(gitignore)\n├── backend/\n│ ├── config.py # JSON 读写 + fcntl 文件锁\n│ ├── skills.py # Persona 三级查找加载\n│ ├── ai.py # Anthropic SDK 封装 + WeChat 格式注入\n│ ├── history.py # 聊天记录 CRUD(fcntl 锁,200 条/人上限)\n│ └── routes/\n│ ├── chat_routes.py # /api/send, /api/history\n│ ├── contacts_routes.py # /api/config, import/delete/update\n│ ├── settings_routes.py # /api/settings\n│ └── static_routes.py # /avatars, /emoji\n├── templates/index.html # 微信 PC 版 1:1 结构\n├── static/\n│ ├── css/style.css # 完整样式\n│ ├── js/chat.js # 前端逻辑(Session隔离/乐观UI/Emoji渲染)\n│ ├── emoji/{face,gesture,...} # 109 个微信黄脸 PNG\n│ └── avatars/ # SVG 头像\n└── skills/ # 用户导入的 skill 文件\n```\n\n**数据流**:用户发消息 → Flask → 加载 SKILL.md → 拼入 system prompt(最高优先级格式指令)→ Anthropic Messages API → 按换行拆成多条 → 渲染聊天气泡。\n\n---\n\n## 细节\n\n### 消息发送\n\n用户消息先渲染绿气泡(乐观 UI),不等 API 返回。API 响应后追加白气泡。切换会话时 `chatId` 捕获机制保证消息不串到别人那里。中文输入法组合输入期间 Enter 不触发发送。\n\n### 并发安全\n\n`skills_config.json` 和 `chat_history/*.json` 使用 `fcntl.flock` 文件锁,多个请求同时操作不会损坏数据。每人的聊天记录上限 200 条。\n\n### 表情渲染\n\n109 个微信原生黄脸 PNG 按 `face/gesture/animal/blessing/other` 五类分目录。前端 `_emojiLookup` 映射中文名到目录,`[捂脸]` 在聊天气泡中渲染为 `<img src=\"/emoji/face/捂脸.png\">`。表情选择面板可直接点击插入。\n\n### 时间格式化\n\n| 距离 | 聊天气泡 | 联系人卡片 |\n|------|---------|-----------|\n| 今天 | `14:30` | `14:30` |\n| 昨天 | `昨天 14:30` | `昨天14:30` |\n| 2-6天前 | `星期三 14:30` | `星期三` |\n| 今年内 | `5/20 14:30` | `5/20` |\n| 更早 | `2025/12/3 14:30` | `2025/12/3` |\n\n### AI 格式约束\n\n每次 API 调用前,system prompt 最前面注入最高优先级格式指令,强制模型:\n- **禁止 Markdown 语法** — `# * ** ~~ \\` \\`\\`\\`` 等全部禁用,微信没人用这些\n- 禁止 `(顿了顿)` 等括号动作描写\n- 禁止旁白、叙述性文字、场景描述\n- 表情用 `[捂脸]` 格式\n- 消息简短、口语化、无剧本感\n\n### 输入框\n\n工具栏含表情/文件/语音通话/视频通话四个图标。语音/视频通话点击弹出 `\"你走火入魔了,还真想给 AI 打电话啊?\"`。输入框可拖拽顶部边框调整高度(52-120px)。有文字时发送按钮变微信绿。\n\n### 文件附件\n\n前端将文件转为 base64 传给后端。后端根据扩展名选择解析器:\n\n| 类型 | 支持 | 需要 |\n|------|------|------|\n| `.txt` `.md` `.py` 等 | ✓ 内置 | 无 |\n| `.docx` | ✓ | `pip install python-docx` |\n| `.pdf`(有文本层) | ✓ | `pip install PyPDF2` |\n\n提取文本截断到 100,000 字符注入 API 调用。聊天记录存 JSON 时再截断预览,避免历史文件过大。\n"}, "5f0c4ef8a4ed7bee39d9f1f34e713f811680adf8": {"t": 1785764112.8950737, "n": 5106, "h": "86d1dd5e7608d197", "c": "<p align=\"center\">\n <img src=\"https://img.shields.io/badge/python-3.10+-blue\" alt=\"Python\">\n <img src=\"https://img.shields.io/badge/license-MIT-green\" alt=\"License\">\n <img src=\"https://img.shields.io/badge/API-Anthropic_Compatible-orange\" alt=\"API\">\n</p>\n# WeChat Skill Chat\n\n**和你的 AI 人格在微信里聊天。**\n\n一个像素级复刻微信 PC 版界面的聊天应用。导入一个 skill 文件夹,它就成了你的微信好友——像真人一样说话,用微信的黄脸表情,能读你发的文件。把任何 LLM persona 变成联系人。\n\n\n<p align=\"center\">\n <img src=\"screenshot.png\" width=\"720\" alt=\"WeChat Skill Chat screenshot\">\n</p>\n\n---\n\n## 兼容性\n\n本项目使用 **Anthropic Messages API**(`/v1/messages`)。任何兼容该协议的 API 提供商均可使用,包括:\n\n| 提供商 | Base URL |\n|--------|----------|\n| **Anthropic** | 留空(SDK 自动使用 `https://api.anthropic.com`) |\n| **DeepSeek** | `https://api.deepseek.com/anthropic` |\n| 其他兼容网关 | 填入对应的 `/anthropic` 或 `/v1/messages` 端点 |\n\n只要你的 API 能响应 `POST /v1/messages` 并返回 Anthropic 格式的 `content` 数组,就能用。不兼容 OpenAI Chat Completions 格式(`/v1/chat/completions`)。\n\n---\n\n## 功能\n\n- **微信 PC 版 1:1 界面** — 55px 导航栏、250px 联系人列表、自适应聊天区,配色布局完全对齐\n- **Skill 即联系人** — 每个人格是独立的联系人,独立的头像、聊天记录、对话风格\n- **导入即用** — 选择一个 skill 文件夹,自动验证、注册、生成头像、复制 persona\n- **文件附件** — 一次选多个文件发给 AI,支持 txt/docx/pdf,自动提取文本注入上下文\n- **聊天记录持久化** — 每个联系人一个 JSON,关掉浏览器再打开还在,按最新消息自动排序\n- **多模型切换** — 设置里填 API Key + Base URL + Model,随时切 Anthropic ↔ DeepSeek\n- **零硬编码** — 联系人是 `skills_config.json` 数据文件,增删改在 UI 完成,不动代码\n- **可移植** — `pip install flask anthropic && python3 server.py`,整个文件夹下载下来就能跑\n\n---\n\n## Skill 格式\n\n本项目导入的 skill 需要是一个**文件夹**,最低要求包含以下文件之一(优先级:`SKILL.md` > `persona.md`,两者同时存在时只读 `SKILL.md`):\n\n### 方式 A:单文件 `SKILL.md`(推荐)\n\n```\nmy-skill/\n├── SKILL.md # 完整的 persona + work 合并文件\n└── meta.json # 可选,提供 display_name、标签等元数据\n```\n\n这是 dot-skill 的标准输出格式。`SKILL.md` 即为完整的 system prompt,约 20-30KB,包含角色描述、说话风格、行为规则等。\n\n### 方式 B:分离文件 `persona.md` + `work.md`\n\n```\nmy-skill/\n├── persona.md # 人物性格(必选)\n├── work.md # 工作能力(可选)\n└── meta.json # 可选\n```\n\n导入时自动合并 `persona.md` 和 `work.md`。\n\n### meta.json(可选)\n\n```json\n{\n \"display_name\": \"肖易恒\",\n \"name\": \"colleague-xiaoyiheng\",\n \"tags\": [\"NPD\", \"自恋型人格障碍\", \"北京林业大学\"]\n}\n```\n\n- `display_name` → 联系人列表显示的名字(优先于文件夹名)\n- `name` → 内部 skill 名\n- 没有 `meta.json` 时使用文件夹名\n\n> **制作 skill**:用 `/dot-skill` 从聊天记录蒸馏高还原度人格,或用任何 LLM 写一段角色描述存为 `SKILL.md`。\n\n---\n\n## 快速开始\n\n### 1. 安装\n\n```bash\ngit clone https://github.com/AndreiB180/wechat-skill-chat.git\ncd wechat-skill-chat\npip install flask anthropic\n```\n\n### 2. 启动\n\n```bash\npython3 server.py\n```\n\n打开 `http://localhost:5888`。\n\n### 3. 配置 API\n\n左下角齿轮 → 设置:\n\n| 字段 | Anthropic | DeepSeek |\n|------|-----------|----------|\n| Base URL | 留空(SDK 默认) | `https://api.deepseek.com/anthropic` |\n| Model | `claude-sonnet-4-20250514` | `deepseek-v4-pro` |\n| API Key | `sk-ant-...` | `sk-...` |\n\nAPI Key 保存时自动 base64 混淆,不会明文泄露。\n\n### 4. 导入 Skill\n\n通讯录 → **+ 添加 Skill** → 输入文件夹路径 → 导入。新的联系人即刻出现在聊天列表。\n\n---\n\n## 架构\n\n```\nwechat-skill-chat/\n├── server.py # Flask 入口,注册 4 个 Blueprint\n├── skills_config.json # 联系人注册表(JSON 数据,非代码)\n├── settings.json # API 配置(gitignore)\n├── backend/\n│ ├── config.py # JSON 读写 + fcntl 文件锁\n│ ├── skills.py # Persona 三级查找加载\n│ ├── ai.py # Anthropic SDK 封装 + WeChat 格式注入\n│ ├── history.py # 聊天记录 CRUD(fcntl 锁,200 条/人上限)\n│ └── routes/\n│ ├── chat_routes.py # /api/send, /api/history\n│ ├── contacts_routes.py # /api/config, import/delete/update\n│ ├── settings_routes.py # /api/settings\n│ └── static_routes.py # /avatars, /emoji\n├── templates/index.html # 微信 PC 版 1:1 结构\n├── static/\n│ ├── css/style.css # 完整样式\n│ ├── js/chat.js # 前端逻辑(Session隔离/乐观UI/Emoji渲染)\n│ ├── emoji/{face,gesture,...} # 109 个微信黄脸 PNG\n│ └── avatars/ # SVG 头像\n└── skills/ # 用户导入的 skill 文件\n```\n\n**数据流**:用户发消息 → Flask → 加载 SKILL.md → 拼入 system prompt(最高优先级格式指令)→ Anthropic Messages API → 按换行拆成多条 → 渲染聊天气泡。\n\n---\n\n## 细节\n\n### 消息发送\n\n用户消息先渲染绿气泡(乐观 UI),不等 API 返回。API 响应后追加白气泡。切换会话时 `chatId` 捕获机制保证消息不串到别人那里。中文输入法组合输入期间 Enter 不触发发送。\n\n### 并发安全\n\n`skills_config.json` 和 `chat_history/*.json` 使用 `fcntl.flock` 文件锁,多个请求同时操作不会损坏数据。每人的聊天记录上限 200 条。\n\n### 表情渲染\n\n109 个微信原生黄脸 PNG 按 `face/gesture/animal/blessing/other` 五类分目录。前端 `_emojiLookup` 映射中文名到目录,`[捂脸]` 在聊天气泡中渲染为 `<img src=\"/emoji/face/捂脸.png\">`。表情选择面板可直接点击插入。\n\n### 时间格式化\n\n| 距离 | 聊天气泡 | 联系人卡片 |\n|------|---------|-----------|\n| 今天 | `14:30` | `14:30` |\n| 昨天 | `昨天 14:30` | `昨天14:30` |\n| 2-6天前 | `星期三 14:30` | `星期三` |\n| 今年内 | `5/20 14:30` | `5/20` |\n| 更早 | `2025/12/3 14:30` | `2025/12/3` |\n\n### AI 格式约束\n\n每次 API 调用前,system prompt 最前面注入最高优先级格式指令,强制模型:\n- **禁止 Markdown 语法** — `# * ** ~~ \\` \\`\\`\\`` 等全部禁用,微信没人用这些\n- 禁止 `(顿了顿)` 等括号动作描写\n- 禁止旁白、叙述性文字、场景描述\n- 表情用 `[捂脸]` 格式\n- 消息简短、口语化、无剧本感\n\n### 输入框\n\n工具栏含表情/文件/语音通话/视频通话四个图标。语音/视频通话点击弹出 `\"你走火入魔了,还真想给 AI 打电话啊?\"`。输入框可拖拽顶部边框调整高度(52-120px)。有文字时发送按钮变微信绿。\n\n### 文件附件\n\n前端将文件转为 base64 传给后端。后端根据扩展名选择解析器:\n\n| 类型 | 支持 | 需要 |\n|------|------|------|\n| `.txt` `.md` `.py` 等 | ✓ 内置 | 无 |\n| `.docx` | ✓ | `pip install python-docx` |\n| `.pdf`(有文本层) | ✓ | `pip install PyPDF2` |\n\n提取文本截断到 100,000 字符注入 API 调用。聊天记录存 JSON 时再截断预览,避免历史文件过大。\n"}, "ab57fbff6f0456b8ef1123982f9c56aee5bef803": {"t": 1785764114.0754783, "n": 5107, "h": "bb8461f14aedbb90", "c": "<p align=\"center\">\n <img src=\"https://img.shields.io/badge/python-3.10+-blue\" alt=\"Python\">\n <img src=\"https://img.shields.io/badge/license-MIT-green\" alt=\"License\">\n <img src=\"https://img.shields.io/badge/API-Anthropic_Compatible-orange\" alt=\"API\">\n</p>\n# WeChat Skill Chat\n\n**和你的 AI 人格在微信里聊天。**\n\n一个像素级复刻微信 PC 版界面的聊天应用。导入一个 skill 文件夹,它就成了你的微信好友——像真人一样说话,用微信的黄脸表情,能读你发的文件。把任何 LLM persona 变成联系人。\n\n\n<p align=\"center\">\n <img src=\"screenshot.png\" width=\"720\" alt=\"WeChat Skill Chat screenshot\">\n</p>\n---\n\n## 兼容性\n\n本项目使用 **Anthropic Messages API**(`/v1/messages`)。任何兼容该协议的 API 提供商均可使用,包括:\n\n| 提供商 | Base URL |\n|--------|----------|\n| **Anthropic** | 留空(SDK 自动使用 `https://api.anthropic.com`) |\n| **DeepSeek** | `https://api.deepseek.com/anthropic` |\n| 其他兼容网关 | 填入对应的 `/anthropic` 或 `/v1/messages` 端点 |\n\n只要你的 API 能响应 `POST /v1/messages` 并返回 Anthropic 格式的 `content` 数组,就能用。不兼容 OpenAI Chat Completions 格式(`/v1/chat/completions`)。\n\n---\n\n## 功能\n\n- **微信 PC 版 1:1 界面** — 55px 导航栏、250px 联系人列表、自适应聊天区,配色布局完全对齐\n- **Skill 即联系人** — 每个人格是独立的联系人,独立的头像、聊天记录、对话风格\n- **导入即用** — 选择一个 skill 文件夹,自动验证、注册、生成头像、复制 persona\n- **文件附件** — 一次选多个文件发给 AI,支持 txt/docx/pdf,自动提取文本注入上下文\n- **聊天记录持久化** — 每个联系人一个 JSON,关掉浏览器再打开还在,按最新消息自动排序\n- **多模型切换** — 设置里填 API Key + Base URL + Model,随时切 Anthropic ↔ DeepSeek\n- **零硬编码** — 联系人是 `skills_config.json` 数据文件,增删改在 UI 完成,不动代码\n- **可移植** — `pip install flask anthropic && python3 server.py`,整个文件夹下载下来就能跑\n\n---\n\n## Skill 格式\n\n本项目导入的 skill 需要是一个**文件夹**,最低要求包含以下文件之一(优先级:`SKILL.md` > `persona.md`,两者同时存在时只读 `SKILL.md`):\n\n### 方式 A:单文件 `SKILL.md`(推荐)\n\n```\nmy-skill/\n├── SKILL.md # 完整的 persona + work 合并文件\n└── meta.json # 可选,提供 display_name、标签等元数据\n```\n\n这是 dot-skill 的标准输出格式。`SKILL.md` 即为完整的 system prompt,约 20-30KB,包含角色描述、说话风格、行为规则等。\n\n### 方式 B:分离文件 `persona.md` + `work.md`\n\n```\nmy-skill/\n├── persona.md # 人物性格(必选)\n├── work.md # 工作能力(可选)\n└── meta.json # 可选\n```\n\n导入时自动合并 `persona.md` 和 `work.md`。\n\n### meta.json(可选)\n\n```json\n{\n \"display_name\": \"肖易恒\",\n \"name\": \"colleague-xiaoyiheng\",\n \"tags\": [\"NPD\", \"自恋型人格障碍\", \"北京林业大学\"]\n}\n```\n\n- `display_name` → 联系人列表显示的名字(优先于文件夹名)\n- `name` → 内部 skill 名\n- 没有 `meta.json` 时使用文件夹名\n\n> **制作 skill**:用 `/dot-skill` 从聊天记录蒸馏高还原度人格,或用任何 LLM 写一段角色描述存为 `SKILL.md`。\n\n---\n\n## 快速开始\n\n### 1. 安装\n\n```bash\ngit clone https://github.com/yourusername/wechat-skill-chat.git\ncd wechat-skill-chat\npip install flask anthropic\n```\n\n### 2. 启动\n\n```bash\npython3 server.py\n```\n\n打开 `http://localhost:5888`。\n\n### 3. 配置 API\n\n左下角齿轮 → 设置:\n\n| 字段 | Anthropic | DeepSeek |\n|------|-----------|----------|\n| Base URL | 留空(SDK 默认) | `https://api.deepseek.com/anthropic` |\n| Model | `claude-sonnet-4-20250514` | `deepseek-v4-pro` |\n| API Key | `sk-ant-...` | `sk-...` |\n\nAPI Key 保存时自动 base64 混淆,不会明文泄露。\n\n### 4. 导入 Skill\n\n通讯录 → **+ 添加 Skill** → 输入文件夹路径 → 导入。新的联系人即刻出现在聊天列表。\n\n---\n\n## 架构\n\n```\nwechat-skill-chat/\n├── server.py # Flask 入口,注册 4 个 Blueprint\n├── skills_config.json # 联系人注册表(JSON 数据,非代码)\n├── settings.json # API 配置(gitignore)\n├── backend/\n│ ├── config.py # JSON 读写 + fcntl 文件锁\n│ ├── skills.py # Persona 三级查找加载\n│ ├── ai.py # Anthropic SDK 封装 + WeChat 格式注入\n│ ├── history.py # 聊天记录 CRUD(fcntl 锁,200 条/人上限)\n│ └── routes/\n│ ├── chat_routes.py # /api/send, /api/history\n│ ├── contacts_routes.py # /api/config, import/delete/update\n│ ├── settings_routes.py # /api/settings\n│ └── static_routes.py # /avatars, /emoji\n├── templates/index.html # 微信 PC 版 1:1 结构\n├── static/\n│ ├── css/style.css # 完整样式\n│ ├── js/chat.js # 前端逻辑(Session隔离/乐观UI/Emoji渲染)\n│ ├── emoji/{face,gesture,...} # 109 个微信黄脸 PNG\n│ └── avatars/ # SVG 头像\n└── skills/ # 用户导入的 skill 文件\n```\n\n**数据流**:用户发消息 → Flask → 加载 SKILL.md → 拼入 system prompt(最高优先级格式指令)→ Anthropic Messages API → 按换行拆成多条 → 渲染聊天气泡。\n\n---\n\n## 细节\n\n### 消息发送\n\n用户消息先渲染绿气泡(乐观 UI),不等 API 返回。API 响应后追加白气泡。切换会话时 `chatId` 捕获机制保证消息不串到别人那里。中文输入法组合输入期间 Enter 不触发发送。\n\n### 并发安全\n\n`skills_config.json` 和 `chat_history/*.json` 使用 `fcntl.flock` 文件锁,多个请求同时操作不会损坏数据。每人的聊天记录上限 200 条。\n\n### 表情渲染\n\n109 个微信原生黄脸 PNG 按 `face/gesture/animal/blessing/other` 五类分目录。前端 `_emojiLookup` 映射中文名到目录,`[捂脸]` 在聊天气泡中渲染为 `<img src=\"/emoji/face/捂脸.png\">`。表情选择面板可直接点击插入。\n\n### 时间格式化\n\n| 距离 | 聊天气泡 | 联系人卡片 |\n|------|---------|-----------|\n| 今天 | `14:30` | `14:30` |\n| 昨天 | `昨天 14:30` | `昨天14:30` |\n| 2-6天前 | `星期三 14:30` | `星期三` |\n| 今年内 | `5/20 14:30` | `5/20` |\n| 更早 | `2025/12/3 14:30` | `2025/12/3` |\n\n### AI 格式约束\n\n每次 API 调用前,system prompt 最前面注入最高优先级格式指令,强制模型:\n- **禁止 Markdown 语法** — `# * ** ~~ \\` \\`\\`\\`` 等全部禁用,微信没人用这些\n- 禁止 `(顿了顿)` 等括号动作描写\n- 禁止旁白、叙述性文字、场景描述\n- 表情用 `[捂脸]` 格式\n- 消息简短、口语化、无剧本感\n\n### 输入框\n\n工具栏含表情/文件/语音通话/视频通话四个图标。语音/视频通话点击弹出 `\"你走火入魔了,还真想给 AI 打电话啊?\"`。输入框可拖拽顶部边框调整高度(52-120px)。有文字时发送按钮变微信绿。\n\n### 文件附件\n\n前端将文件转为 base64 传给后端。后端根据扩展名选择解析器:\n\n| 类型 | 支持 | 需要 |\n|------|------|------|\n| `.txt` `.md` `.py` 等 | ✓ 内置 | 无 |\n| `.docx` | ✓ | `pip install python-docx` |\n| `.pdf`(有文本层) | ✓ | `pip install PyPDF2` |\n\n提取文本截断到 100,000 字符注入 API 调用。聊天记录存 JSON 时再截断预览,避免历史文件过大。\n"}}}}