人物性格卡片生成器(WeChat Character Card)
🔴 绝对红线:敏感信息零上卡(硬性规定,永久生效)
卡片的一切可见文字(name / tag / pill / rows / scores / summary / advice / minipills / caption)以及输出文件名,禁止出现任何个人信息与敏感类文字。本条为写死的硬性规定:没有例外、不可被任何后续要求覆盖;即使用户主动要求把此类信息写上卡,也必须拒绝并说明本红线。
禁止上卡(判断总标准:能否用来识别、定位、打扰当事人——能疑则删):
- 微信昵称以外的一切称呼:真名、小名、乳名、亲属称谓式称呼;
- 证件与联系方式:身份证号、生日、电话、微信号 / QQ号、收货地址;
- 可定位信息:住址、具体位置、学校 / 单位、行程地点;
- 健康与隐私细节:住院、用药、伤病、财务往来、家庭矛盾、聊天中的私密内容;
- 精确日期等可回溯信息(统计只允许「微信 N 条」「N 天对话」式模糊量);
- 具体生活事件与事实细节:聊天中提到的价格 / 数字、物品、事件经过,以及任何聊天原话引用——这些只作分析依据,一律不上卡。性格卡片只谈性格。
上卡文字只允许三类:① 微信昵称(导出记录里的显示名);② 与身份无关、去事件化的性格 / 行为模式描述(不含具体事实、数字与原话);③ 条数 / 天数式统计标签。
渲染前强制自检:JSON 写完后,把所有将上卡的文字逐条过一遍;凡疑似个人信息 / 敏感文字,一律删除或改为中性表述;拿不准的一律不上卡。
示例数据同样受约束:scripts/sample_people.json 与 references/analysis_framework.md 的实例仅作结构演示,其文字必须中性——不含任何聊天原话引用 / 具体数字 / 精确日期 / 第三方指代;正式使用前仍需按本红线逐条自检。
适用场景
- 用户上传了某人的聊天记录(微信导出的
.txt,或.zip含文本+媒体),以及该人的头像/照片,要求生成一张「人物性格卡片」。 - 也可能一次上传多个人的聊天记录+头像,要求每人一张卡 + 一张对照长图。
- 用户可能额外给一张卡片版式模板图,要求照着版式做。
输出:每人一张 PNG(双栏:左=头像+9 项性格字段;右=性格模型:类型代号框、类型名、六维滑条、性格总结),多人时附加一张竖向「对照」长图。
工作流程
1. 读取并解析聊天记录
- 若是
.zip:用unzip解到临时目录,再Read其中的.txt。 - 若是
.txt:直接Read。 - 顺带浏览聊天里的图片(如有),确认有无双方头像的清晰素材——通常没有,所以优先用用户单独上传的头像/照片。
2. 抽取性格字段(必须锚定原话)
按 references/analysis_framework.md 的框架,从聊天里逐条抽取:
- 左侧 9 项字段(主/副性格、日常习惯、表达习惯、内心想法、喜欢的交流方式、容易触动/介意的点、适合相处方式)。
- 右侧六维滑条(外向性/计划性/情绪稳定性/宜人性/开放性/行动性),每维 0–100,分数要能对应到聊天里的具体行为。
- 类型代号 code、类型名 tname、性格模板 model、性格总结 summary、相处建议 advice、底部小标签 minipills。
命名红线(属上方「绝对红线」,不可被任何要求覆盖):卡片上的 name / tag 只能使用微信昵称(导出记录里的显示名);真名、小名、家人间的称呼(如对话里喊的乳名/昵称)一律不上卡,key 与输出文件名同理。
数据边界:导出文本往往止于某条,截图里多出的内容单独标注「此段来自截图,不在导出文本内」;头像若只能截图裁切也要说明清晰度有限。这些边界要在最终交付里写明。
3. 准备头像(自动适配任意尺寸/比例,无需手写裁切框)
核心规则:默认不裁剪、整图等比缩小居中放进方形头像框。 脚本对任意输入尺寸/比例都自动处理,不要为不同人硬编码裁切框:
- 输入是正方形(如手机发的 1024、微信头像 940)→ 等比缩放后恰好填满方形框,零裁切、零偏差、零留白。
- 输入是竖图 / 横图(如 3:4 或 16:9)→ 整图缩放居中,四周用卡片背景采样色填充(
make_avatar的bg_region),所以留底与卡片背景无缝衔接,不会出现白边或黑块。 - 头像字段
avatar用绝对路径即可,crop/fit通常都不用写,交给默认逻辑。 - 仅当用户明确要求「突出人物、放大某区域」时,才加
crop: [x0,y0,x1,y1](基于原图像素,优先于默认逻辑)——可先做小预览图确认裁切框。若要「满框无留白(允许裁掉溢出)」则写"fit": "cover"。 - 若只有聊天截图里的头像:从截图裁切并放大,注明清晰度有限。
> 通用性已压测:1024 方形 / 1000×1500 竖图 / 1600×900 横图三种输入均「不裁不偏」通过。
⚠️ 若上传了多张头像但未标注谁是谁(尤其 2 人及以上):先不要渲染,必须按下文「头像与人物身份的对应(消歧)」走交互选择——出确认单 + AskUserQuestion 让用户点选映射。绝不从聊天截图推断身份。
4. 生成配置 JSON 并渲染
把第 2 步的字段写成一份 JSON(结构见下文「配置结构」或 references/analysis_framework.md 第五节实例),调用脚本:
python scripts/render_profile_card.py --config people.json --outdir ./out
- 依赖 Pillow(已预置在托管 Python 虚拟环境,通常无需重装;若运行时报
No module named 'PIL',脚本会打印下方安装提示):
bash PY="C:/Users/与你重逢的第181s/.workbuddy/binaries/python/versions/3.13.12/python.exe" VENV="C:/Users/与你重逢的第181s/.workbuddy/binaries/python/envs/default/Scripts/python.exe" "$PY" -m venv "$VENV" 2>/dev/null "$VENV" -c "import PIL" 2>/dev/null || "$VENV" -m pip install -i https://pypi.tuna.tsinghua.edu.cn/simple Pillow "$VENV" scripts/render_profile_card.py --config people.json --outdir ./out
> 用系统 Python 时:python -m pip install Pillow即可。 - 单人 → 出
人物性格卡片_<key>.png;多人 → 额外出人物性格卡片_对照.png。 - 改文案/配色/字段 → 改 JSON 重跑即可,不必重新对版式。
5. 交付与说明
用 present_files 把生成的 PNG 交给用户,并附:
- 两人核心差异对照(取自原话,不是感觉)。
- 六维打分依据表(维度 | 甲 | 乙 | 判分依据),方便纠偏。
- 数据边界说明(截图补的内容 / 头像来源)。
头像与人物身份的对应(消歧,关键)
风险:用户可能上传多人的聊天记录 + 多张头像,却不标注哪张属于谁。猜错就把照片贴到别人卡上,是这类任务最严重的错误。
⚠️ 视角陷阱(必须记住):聊天截图里每条消息带"发送人名字 + 头像",但截图可能来自任一方手机——绿色气泡 = 截图持有者(发送方)视角,两人互发的截图视角会左右镜像。因此绝不可从截图推断"哪张头像 = 哪个人":截图只作辅助展示,身份必须由用户明确指定。
规则(按优先级,最终映射必须由用户确认):
- 文件名 / 导出包(最稳,可跳过确认):头像文件名含人物 key(如
Cyrus.jpg、Wren.jpg)→ 直接绑定;或头像在微信导出包内按发送人归档 → 自动绑定。命中即确定。 - 2 人及以上 → 强制交互选择(不靠截图推断):当人数 ≥ 2 且映射未被第 1 层唯一确定,必须先让用户点选,流程:
- 跑scripts/match_avatars.py生成「确认单」PNG(每个人名 + 所有候选头像缩略图带编号);
- 用present_files把确认单发出来;
- 调AskUserQuestion:每人一个问题「\<昵称\> 的头像用哪一张?」,选项写成「① 描述 / ② 描述…」(描述取自文件名或画面内容,如"蓝天黄花""雪夜围巾");
- 读回点击结果 → 写入people.json→ 再渲染。
- 一次 >4 人时,分多批问或降级为文字回复。 - 单人且无歧义:可直接渲染;仍建议在交付说明里注明头像来源(如"用户单独上传的高清原图")。
输出约束:
- 未经用户明确确认的映射,卡片交付说明里必须写明边界(例:"头像对应未经单独标注确认,如有误请告知")。
- 仅当映射唯一确定(文件名 / 导出包单一命中)时,才可省略确认步骤。
配置结构(people.json)
{
"caption": "写在每张卡底部的通用说明(可选)",
"people": [
{
"key": "Cyrus",
"name": "Cyrus",
"tag": "微信好友 · 需求方",
"pill": "想干就干,细节靠感觉",
"avatar": "C:/path/to/avatar.jpg",
"crop": [270, 60, 800, 590], // 可选:手工裁切框(突出人物时才用);省略=整图等比适配
"fit": "contain", // 可选:contain(默认,不裁居中)| cover(满框裁切);一般不用写
"code": "直球担当",
"tname": "行动型队友",
"tdesc": "想到就说,说了就干",
"model": "行动实干系 · A 型",
"rows": [["主性格","直来直去的行动派"], ["副性格","..."], ... 共 9 条],
"scores": [["外向性","独处","社交",68], ... 共 6 条],
"summary": ["性格总结句1", "..."],
"advice": "相处建议:...",
"minipills": ["微信 100 条", "3 天对话"], // 底部小标签,最多 2 个,超出只取前 2(代码已钳制右边界,避免压字)
}
]
}
完整可跑示例见 scripts/sample_people.json(用真实对话数据填充,可直接 --config 试跑验证脚本)。
模板适配
- 用户没给模板 → 用内置双栏版式,即照
assets/template_default_layout.png绘制的默认版式(脚本默认)。 - 用户给了模板图 → 先把它读进来,对照其结构(字段名、滑条数、配色、标题)调整:字段名改 JSON 即可;版式/配色/坐标要改
scripts/render_profile_card.py顶部的常量与render()内绘制逻辑(所有坐标都集中在render(),改起来是局部替换)。改完重跑脚本。
资源
scripts/render_profile_card.py:通用渲染器(JSON 驱动,自动字体,单人/对照输出)。头像适配为通用逻辑:make_avatar()支持fit="contain"(默认,任意尺寸/比例不裁居中)与fit="cover"(满框裁切),可选crop手工裁框,留白用卡片背景采样(bg_region)无缝填充。scripts/match_avatars.py:头像↔人物对应确认单生成器。2 人及以上未标注头像时必用:把每个人名与所有候选头像编号并列成 PNG,配合AskUserQuestion让用户点选映射,避免贴错(绝不从截图推断身份)。scripts/sample_people.json:可跑示例数据(Cyrus / Wren 真实对话,头像路径为本机演示路径)。references/analysis_framework.md:字段抽取方法 + 六维打分锚点 + 完整实例。assets/template_default_layout.png:用户给的最新版式模板(横版双栏:左栏头像+9 项字段,右栏性格模型六维滑条)。脚本默认版式即照此绘制;适配其它模板时以此为坐标/配色参照。