mirror of
https://github.com/jie65535/JChatGPT.git
synced 2026-09-15 02:56:10 +08:00
chore: ignore local research files
Keep design documents and experiment scripts local while removing their previously tracked files from version control.
This commit is contained in:
@@ -137,3 +137,5 @@ __pycache__/
|
|||||||
*.py[cod]
|
*.py[cod]
|
||||||
/nul
|
/nul
|
||||||
/.playwright-cli/
|
/.playwright-cli/
|
||||||
|
/docs/
|
||||||
|
/scripts/
|
||||||
|
|||||||
@@ -1,65 +0,0 @@
|
|||||||
# 好感度与主观印象系统
|
|
||||||
|
|
||||||
## 功能定位
|
|
||||||
|
|
||||||
好感度系统保存 Bot 对群友的主观认识,与证据驱动的长期用户画像互补:
|
|
||||||
|
|
||||||
- `FavorabilityInfo` 保存好感度、代号、标签、印象和最近调整原因;
|
|
||||||
- `user-profile.sqlite` 保存从历史聊天归纳出的长期画像;
|
|
||||||
- 两套数据独立持久化,在普通对话上下文中按用户合并渲染;
|
|
||||||
- 自动历史画像不会修改主观好感度。
|
|
||||||
|
|
||||||
## 数据结构
|
|
||||||
|
|
||||||
```kotlin
|
|
||||||
@Serializable
|
|
||||||
data class FavorabilityInfo(
|
|
||||||
val userId: Long,
|
|
||||||
val value: Int = 0,
|
|
||||||
val reasons: List<String> = emptyList(),
|
|
||||||
val impression: String = "",
|
|
||||||
val name: String = "",
|
|
||||||
val tags: List<String> = emptyList(),
|
|
||||||
)
|
|
||||||
```
|
|
||||||
|
|
||||||
字段约束:
|
|
||||||
|
|
||||||
- `value`:限制在 -100 到 100;
|
|
||||||
- `reasons`:只在好感度发生变化且提供原因时追加,保留最近 10 条;
|
|
||||||
- `impression`:最多 200 字符;
|
|
||||||
- `name`:最多 20 字符;
|
|
||||||
- `tags`:最多 5 项,每项最多 20 字符。
|
|
||||||
|
|
||||||
数据继续保存在 Mirai `data.yml` 中,已有字段保持兼容。
|
|
||||||
|
|
||||||
## AI 更新工具
|
|
||||||
|
|
||||||
`adjustUserFavorability` 是唯一的好感度和主观印象维护入口。模型可以在一次调用中:
|
|
||||||
|
|
||||||
- 通过 `change` 增减好感度;
|
|
||||||
- 覆盖 `impression` 或 `name`;
|
|
||||||
- 通过 `tags_add`、`tags_remove` 调整标签。
|
|
||||||
|
|
||||||
只更新印象或标签时,`change` 默认为 0。系统不会因为好感度为 0 而删除用户记录。
|
|
||||||
|
|
||||||
## 回复门控
|
|
||||||
|
|
||||||
启用 `enableFavorabilitySystem` 后,负好感度会降低对应用户触发 Bot 回复的概率:
|
|
||||||
|
|
||||||
```text
|
|
||||||
忽略概率 = abs(value) / 100
|
|
||||||
```
|
|
||||||
|
|
||||||
好感度不再随时间自动向 0 偏移,也没有管理员手动修改或清空好感度的命令。它只会在模型明确调用工具时变化。
|
|
||||||
|
|
||||||
## 上下文注入
|
|
||||||
|
|
||||||
普通聊天会把当前相关用户的主观认识和长期画像合并为紧凑文本:
|
|
||||||
|
|
||||||
- 群聊优先选择触发者和最近发言者;
|
|
||||||
- 私聊只注入当前联系人;
|
|
||||||
- 仅有数值、没有代号/标签/印象的空记录不会制造提示词噪声;
|
|
||||||
- 好感度为 0 但仍有代号、标签或印象的记录继续正常注入。
|
|
||||||
|
|
||||||
长期画像的生成、证据校验和自动维护流程参见 `ProfileSystemDesign-v3.md`。
|
|
||||||
@@ -1,72 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
"""
|
|
||||||
恢复 data.yml:把 tokenUsageDailyRecords 抽出成 token_usage.json,
|
|
||||||
顺手清理 tokenUsageRecords,把 data.yml 重写成合法的、yamlkt 能读回的 JSON。
|
|
||||||
|
|
||||||
用法(在 data.yml 所在目录运行):
|
|
||||||
python3 recover_data_yml.py /path/to/top.jie65535.mirai.JChatGPT/
|
|
||||||
|
|
||||||
会做:
|
|
||||||
1. 备份原 data.yml -> data.yml.bak-<timestamp>
|
|
||||||
2. 读 data.yml(按 JSON 解析,目前文件就是 JSON-flow YAML)
|
|
||||||
3. 把 tokenUsageDailyRecords 写到 token_usage.json
|
|
||||||
4. 删除 tokenUsageRecords 和 tokenUsageDailyRecords 字段
|
|
||||||
5. 重写 data.yml(保留 contactMemory / userFavorability 等)
|
|
||||||
"""
|
|
||||||
import json
|
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
import time
|
|
||||||
|
|
||||||
def main(target_dir: str) -> int:
|
|
||||||
data_path = os.path.join(target_dir, "data.yml")
|
|
||||||
if not os.path.exists(data_path):
|
|
||||||
print(f"NOT FOUND: {data_path}", file=sys.stderr)
|
|
||||||
return 1
|
|
||||||
|
|
||||||
with open(data_path, "r", encoding="utf-8") as f:
|
|
||||||
text = f.read()
|
|
||||||
|
|
||||||
try:
|
|
||||||
data = json.loads(text)
|
|
||||||
except json.JSONDecodeError as e:
|
|
||||||
print(f"data.yml 不是合法 JSON:{e}", file=sys.stderr)
|
|
||||||
print("如果文件其实是 block-style YAML,请先用 yq/python yaml 转换", file=sys.stderr)
|
|
||||||
return 2
|
|
||||||
|
|
||||||
if not isinstance(data, dict):
|
|
||||||
print(f"顶层不是 map,是 {type(data).__name__}", file=sys.stderr)
|
|
||||||
return 3
|
|
||||||
|
|
||||||
ts = int(time.time())
|
|
||||||
backup_path = os.path.join(target_dir, f"data.yml.bak-{ts}")
|
|
||||||
with open(backup_path, "w", encoding="utf-8") as f:
|
|
||||||
f.write(text)
|
|
||||||
print(f"已备份 -> {backup_path}")
|
|
||||||
|
|
||||||
daily_records = data.pop("tokenUsageDailyRecords", [])
|
|
||||||
raw_records = data.pop("tokenUsageRecords", [])
|
|
||||||
print(f"提取 tokenUsageDailyRecords: {len(daily_records)} 条")
|
|
||||||
print(f"丢弃 tokenUsageRecords (legacy): {len(raw_records)} 条")
|
|
||||||
|
|
||||||
token_path = os.path.join(target_dir, "token_usage.json")
|
|
||||||
if os.path.exists(token_path):
|
|
||||||
token_backup = os.path.join(target_dir, f"token_usage.json.bak-{ts}")
|
|
||||||
os.rename(token_path, token_backup)
|
|
||||||
print(f"已备份现有 token_usage.json -> {token_backup}")
|
|
||||||
|
|
||||||
with open(token_path, "w", encoding="utf-8") as f:
|
|
||||||
json.dump(daily_records, f, ensure_ascii=False, indent=2)
|
|
||||||
print(f"写入 -> {token_path} ({len(daily_records)} 条)")
|
|
||||||
|
|
||||||
with open(data_path, "w", encoding="utf-8") as f:
|
|
||||||
json.dump(data, f, ensure_ascii=False, indent=4)
|
|
||||||
print(f"重写 -> {data_path}(剩余字段: {list(data.keys())})")
|
|
||||||
return 0
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
if len(sys.argv) != 2:
|
|
||||||
print(__doc__, file=sys.stderr)
|
|
||||||
sys.exit(1)
|
|
||||||
sys.exit(main(sys.argv[1]))
|
|
||||||
Reference in New Issue
Block a user