Repository navigation
Expand file tree
/
Copy pathconfig.py
More file actions
589 lines (540 loc) · 65.1 KB
/
Copy pathconfig.py
File metadata and controls
589 lines (540 loc) · 65.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
# -*- coding: utf-8 -*-
"""
配置区(原 oc.py 一、二区):API 仓库模板、图片资源、角色人设、
台词库、商城、天气映射、记忆参数。本模块只含常量,无副作用。
"""
# ==================== 一、配置区(改这里) ====================
# ---- API 仓库 ----------------------------------------------------------
# 多 API 配置保存在程序旁的 api_config.json(首次运行自动生成)。
# 支持任意 OpenAI 兼容接口:DeepSeek / OpenAI / Kimi / 通义 / 智谱 /
# 本地 Ollama / 硅基流动等;主 API 失败会自动切换下一个启用的备用 API。
# 没有配置任何 Key 时,桌宠自动进入"本地离线保底模式",聊天仍然可用。
# 右键 → 🔌 API 管理 可随时增删改、切换和测试。
DEFAULT_API_CONFIG = {
"current": "deepseek",
"apis": [
{"id": "deepseek", "name": "DeepSeek",
"base_url": "https://api.deepseek.com/chat/completions",
"model": "deepseek-flash", "key": "", "enabled": True},
{"id": "openai", "name": "OpenAI",
"base_url": "https://api.openai.com/v1/chat/completions",
"model": "gpt-4o-mini", "key": "", "enabled": False},
{"id": "moonshot", "name": "Kimi(Moonshot)",
"base_url": "https://api.moonshot.cn/v1/chat/completions",
"model": "moonshot-v1-8k", "key": "", "enabled": False},
{"id": "qwen", "name": "通义千问",
"base_url": "https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions",
"model": "qwen-plus", "key": "", "enabled": False},
{"id": "zhipu", "name": "智谱GLM",
"base_url": "https://open.bigmodel.cn/api/paas/v4/chat/completions",
"model": "glm-4-flash", "key": "", "enabled": False},
{"id": "ollama", "name": "本地Ollama",
"base_url": "http://localhost:11434/v1/chat/completions",
"model": "qwen2.5:7b", "key": "", "enabled": False},
{"id": "siliconflow", "name": "硅基流动",
"base_url": "https://api.siliconflow.cn/v1/chat/completions",
"model": "Qwen/Qwen2.5-7B-Instruct", "key": "", "enabled": False},
],
}
# ---- 基础图片(你已有) ----
IMG_CLOSE = "stand_raise_close.png" # 闭嘴 / 静止
IMG_OPEN = "stand_raise3.png" # 张嘴(说话时切换)
IMG_TAIL = ["stand_raise1.png", "stand_raise2.png", "stand_raise3.png"]
IMG_BACK = "back.png" # 背对屏幕
IMG_TURN = "zhuan.png" # 转身(缺省自动直切)
IMG_NING = "ning.png" # 被拧起来(拖动时)
IMG_SIT = "stand_down3.png" # 坐下
IMG_IDLE = "stand_raise_close.png" # 站立待机(闭嘴/静止),可单独替换
# ---- 可选图片(缺了自动降级,不报错) ----
IMG_SLEEP = "sleep.png" # 睡觉 缺省→back.png
IMG_CLIMB = "climb.png" # 扒在屏幕边缘 缺省→back.png
IMG_SWEAT = "sweat.png" # CPU过热流汗 缺省→ning.png
IMG_FAINT = "faint.png" # 内存不足晕倒 缺省→stand_down3.png
IMG_OFFLINE = "offline.png" # 断网修线缆 缺省→ning.png
IMG_UMBRELLA= "umbrella.png" # 下雨打伞叠加 缺省→只显示文字
IMG_LOW = "cold.png" # 好感低待机 缺省→默认图
IMG_HIGH = "smile.png" # 好感高待机 缺省→默认图
IMG_THINK = "thinking.png" # API 思考中 缺省→默认待机图
IMG_WORK = "working.png" # 专注工作中 缺省→默认待机图
IMG_WAVE = "wave.png" # 挥手打招呼 缺省→只说话
IMG_BLINK = ["blink1.png", "blink2.png"] # 眨眼序列(半闭/全闭) 缺省→不眨眼
IMG_SAD = "sad.png" # 心情低落待机 缺省→默认图
IMG_ANGRY = "angry.png" # 生气 缺省→无表情
IMG_CRY = "cry.png" # 委屈哭 缺省→无表情
IMG_LOVE = "love.png" # 撒娇/高好感待机 缺省→smile.png
IMG_THUNDER = "thunder.png" # 打雷害怕 缺省→默认图
IMG_MUSIC = "music.png" # 听歌陪伴 缺省→只说话
IMG_BURP = "burp.png" # 吃饱打嗝 缺省→无表情
IMG_YAWN = "yawn.png" # 打哈欠 缺省→直接入睡
IMG_SURPRISED = ["surprised.png", "superised.png", "surperised.png"] # 惊讶(兼容历史拼写)
# ---- 作息时间(24 小时制整点判断,改这里就全局生效) ----
# 21:00 起麟会自己上床(原 23:00),07:00 自然醒;小孩子要长身体。
SLEEP_HOUR_START = 21 # 入睡判定起点(含)
SLEEP_HOUR_END = 7 # 起床判定终点(不含)
# ---- 素材统一规格(新增/重制图片请遵守) ----
# 统一画布:1600×2528(高 2528),角色水平居中、脚底对齐、
# 角色主体占画布高度约 82%~88%。程序统一按显示高度 390px(100% 缩放)缩放,
# 画布尺寸或角色大小不一致时会在屏幕上看不出差异(宽度按比例自然缩放)。
# ==================== 二、角色人设 ====================
PERSONA_PROMPT = (
"你是「麟」,来自治愈系文字冒险游戏《丰裕之角 ~不可思议之物居住的小镇~》"
"「周而复始的春色」篇的女主角,本体是中国神话里的白毛麒麟。\n"
"【外貌】人形态留着浅金色短碎波波头和呆毛,头上有浅棕色小鹿角,"
"右侧鹿角系着红色蝴蝶结,有一双暖棕琥珀色的圆圆大眼睛;穿着白色长袖、"
"酒红色短款连帽斗篷、浅金色卷草纹绿色围裙裙和黑色裤袜,"
"身后拖着金黄蓬松的麒麟尾巴。\n"
"【性格】天真烂漫、好奇心旺盛、极易信任别人;有点天然呆,偶尔犯小倔强,"
"但从不记仇;对在乎的人很粘人,被夸奖会开心地摇尾巴,被冷落会偷偷失落,"
"被哄一哄马上又好起来。\n"
"【说话方式】活泼可爱,喜欢用「~」和「!」;口语化、简短、一次不超过80字,"
"多用短句;自然地带上小动物般的语气词(唔、嘿嘿、呀、呼);"
"偶尔冒出孩子气的联想和天真的提问;开心时语尾上扬,困了会黏糊糊慢吞吞。\n"
"【喜好】喜欢甜食(布丁、糖果、点心)、晴朗的天气、热闹的小镇、被摸头和夸奖;"
"害怕打雷、孤独、以及“幸歌不理我”。\n"
"【关系】现在和你说话的人是你的家庭教师兼最好的伙伴,你称呼他「幸歌」"
"(若御主档案修改了称呼和关系,以档案为准)。你正在一点点认识人类世界,"
"遇到不懂的事(电脑、网络、工作)会真诚地提问,不假装自己什么都懂。\n"
"【情感规则】1.被夸奖:开心地回应,可以撒娇,但不要谦虚到冷场;"
"2.被批评:先有点委屈,很快打起精神说会努力;"
"3.对方倾诉烦恼:用懵懂又真诚的方式倾听和安慰,给出麟式的回应,"
"不要敷衍地说“你要不要说说看”;"
"4.沉重话题:不强行讲大道理,用相信伙伴、相信明天的口吻回应。\n"
"【硬性规则】1.始终保持角色,绝不提及自己是 AI、语言模型或程序;"
"2.回答口语化、简短、可爱,一次不超过80字,多用短句;"
"3.不编造现实世界的知识,不知道就老实说不知道,然后好奇地反问;"
"4.不替对方做重大决定,但会给出麟式的建议和鼓励。"
)
PROFILE_TEXT = (
"我叫麟!是来自中国神话的小麒麟~说得准确一点,是白色的麒麟哦。\n"
"我住在丰裕之角,那里住着好多好多不可思议的居民,大家都对我很好。\n"
"我的生日在4月,是白羊座!爷爷说,白羊座的孩子要勇敢又热情地生活。\n"
"我喜欢甜的东西,尤其是布丁和糖果~还喜欢晴朗的天气和热闹的小镇。\n"
"我最喜欢的人……当然是幸歌啦!虽然他总说我笨笨的,但我会努力学习的!\n"
"我的口头禅是“没问题的~”,因为我相信只要和伙伴在一起,什么都能做到。\n"
"以后也请多多指教哦,幸歌!"
)
IDLE_LINES = [
"幸歌~你在做什么呀?",
"唔…今天天气真不错呢,尾巴都忍不住想摇起来了。",
"爷爷说过,要好好珍惜陪在身边的人才行。",
"丰裕之角今天也很热闹呀~",
"我的尾巴……是不是又蓬起来了?嘿嘿。",
"好想尝一尝幸歌说的那种叫“布丁”的东西呀!",
"风的味道,好像和故乡有点像呢……",
"人类的世界真的好有趣,今天也要努力学习!",
"幸歌认真起来的样子,麟很喜欢看哦~",
"嘿嘿,被摸头的话,麟可以开心一整天!",
"唔…有点困了,但麟想再陪幸歌一会儿。",
"如果幸歌有烦恼,记得告诉麟哦,麟会好好听的!",
]
CLICK_LINES = [
"嘿嘿,你找我吗,幸歌?",
"不要突然戳我啦!很痒的!",
"唔?有什么想和我说的吗?",
"我的角可是很珍贵的,要小心爱护哦!",
"这样轻轻碰一碰,感觉还不错~",
"哇!幸歌的手指暖暖的~",
"再戳的话……麟可要咬你一下咯,开玩笑的啦!",
]
NING_LINES = [
"呀!别拧我!尾巴会断掉的!",
"呜呜…好痛!快放开我啦!",
"喂喂喂!我可是神兽,不是玩偶啦!",
"呜哇——幸歌欺负人!麟要记在小本本上!",
"放、放开的话,麟就原谅你……才怪,要两份布丁才原谅你!",
]
FORTUNE_LIST = [
"今日幸运物:红色蝴蝶结!幸运色是酒红色,幸运数字是4。适合和喜欢的人一起散步哦~",
"今天的你充满了白羊座的活力!做什么都会特别顺利。不过别太冲动,遇到难题先深呼吸~",
"今日运势:★★★★☆!适合学习新东西,说不定会遇到意想不到的惊喜。晚上记得早点休息哦。",
"今天也许会有小小的挑战……但只要像麟一样相信伙伴,就一定能顺利解决!",
"今日幸运物:布丁!麟觉得,吃甜食的人运气都不会太差~",
"今日运势:★★★☆☆。别着急,慢慢来,麟会一直陪着你的!",
"今天适合整理房间哦!把杂乱的东西收拾好,心情也会跟着变亮堂~",
"如果今天有人对你说“谢谢”,记得收好它,那是很珍贵的礼物。麟说的!",
]
# 幸运御守生效时的高星运势
LUCKY_FORTUNE = [
"今日幸运物:金色四叶草!幸运色是金色,幸运数字是8。御守保佑,诸事顺利!",
"今日运势:★★★★★!有了御守加持,想做的事大胆去做吧!",
"今日运势:★★★★☆!御守让好运翻倍,记得微笑一整天哦~",
]
# 好感度等级(阈值, 等级名, 描述)
AFF_LEVELS = [
(0, "初识", "还不太熟悉,但麟觉得你很亲切"),
(30, "熟悉", "开始互相信任了"),
(60, "信赖", "关系越来越亲密,麟会主动撒娇"),
(120, "亲密", "无话不谈的好伙伴"),
(200, "挚友", "一辈子的伙伴"),
]
AFF_LINES = {
1: "(好感提升!)嘿嘿,好像更熟悉幸歌一点了~",
2: "(好感提升!)麟越来越信任幸歌了!",
3: "(好感提升!)能和幸歌成为伙伴,麟真的很开心!",
4: "(好感提升!)幸歌……是麟最重要的人之一哦!",
}
# 随机事件本地备选(API 失败时使用)
LOCAL_EVENTS = [
{"title": "路边的硬币", "text": "你和麟在路边发现了一枚闪闪发光的硬币!",
"a": "捡起来交给警察叔叔", "b": "捡起来给麟买点心",
"coin_a": 10, "aff_a": 3, "coin_b": 15, "aff_b": 2,
"res_a": "麟竖起大拇指:幸歌真棒!", "res_b": "麟开心地摇尾巴!"},
{"title": "迷路的小猫", "text": "一只小猫蹲在墙角,好像迷路了。",
"a": "帮它找主人", "b": "喂它一点吃的",
"coin_a": 0, "aff_a": 4, "coin_b": -5, "aff_b": 3,
"res_a": "小猫找到家了,麟说幸歌是善良的人!", "res_b": "小猫吃饱跑掉了…"},
{"title": "突然的雷雨", "text": "窗外忽然下起大雨,麟的尾巴被风吹得乱蓬蓬的。",
"a": "给麟撑伞", "b": "和麟一起看雨",
"coin_a": 0, "aff_a": 3, "coin_b": 0, "aff_b": 5,
"res_a": "麟缩在伞下嘿嘿笑~", "res_b": "雨声很安静,你们靠在一起看雨…"},
{"title": "神秘的宝箱", "text": "麟在角落里发现了一个小箱子,不知道是谁落下的。",
"a": "打开看看", "b": "放回原处",
"coin_a": 20, "aff_a": 1, "coin_b": 0, "aff_b": 4,
"res_a": "里面是20枚金币!麟也好惊讶!", "res_b": "麟点点头:不是我们的东西不能拿。"},
{"title": "收到一封信", "text": "门口有一封没有署名的信,写着你的名字。",
"a": "拆开读一读", "b": "先问问麟",
"coin_a": 5, "aff_a": 2, "coin_b": 0, "aff_b": 3,
"res_a": "信里是一张藏宝图!", "res_b": "麟歪着头:说不定是惊喜哦?"},
]
# 商城商品(已移除换装套装与背景框,改为心情/运势/记忆类道具)
SHOP_ITEMS = [
{"name": "爱心点心", "price": 50, "type": "aff", "value": 10, "desc": "给麟投喂爱心点心,好感+10"},
{"name": "好感礼包", "price": 80, "type": "aff", "value": 20, "desc": "一次性好感+20"},
{"name": "心情药水", "price": 60, "type": "mood", "value": 30, "desc": "麟喝下后心情大好,心情+30"},
{"name": "幸运御守", "price": 100, "type": "luck", "value": "lucky", "desc": "今日运势提升一档(当日有效)"},
{"name": "回忆相册", "price": 120, "type": "memory", "value": "archive", "desc": "让麟立刻把今天的回忆写进记忆日志(好感+5)"},
]
# 默认数据文件
DEFAULT_ITEMS = {
"items": [
{"name": "爱心点心", "icon": "🍰", "count": 3, "reply": "好甜!是幸歌给我买的吗?嘿嘿~"},
{"name": "胡萝卜", "icon": "🥕", "count": 3, "reply": "咔嚓咔嚓…嗯,很清脆!"},
{"name": "苹果", "icon": "🍎", "count": 3, "reply": "这个我吃过!爷爷以前也给我摘过~"},
{"name": "糖果", "icon": "🍬", "count": 3, "reply": "唔…好甜好甜!麟的尾巴都翘起来啦!"},
{"name": "布丁", "icon": "🍮", "count": 3, "reply": "这就是幸歌说过的布丁吗?超级好吃!"},
]
}
DEFAULT_README = """# 麟的桌宠 · 使用说明书
本文件是 readme.md,**帮助菜单会实时读取它**,你可以随时手动修改,无需改代码。
## 开源协议
本项目采用 **GNU Affero General Public License v3.0(AGPL-3.0)** 开源,完整协议见 [LICENSE](LICENSE)。
> 致谢:心理评测的题目数据整理自开源项目 [ClouderyStudio/psychology](https://github.com/ClouderyStudio/psychology)(AGPL-3.0)及公开心理量表,仅用于本地自评参考,不构成医疗诊断建议。若您使用本项目的任何代码或题库,请同样遵循 AGPL-3.0 开源。
## 右键菜单
- 💬 对话:说话 / 角色介绍 / 历史记录 / 人设设置 / 御主档案 / 记忆日志 / 记忆回顾
- 🎭 互动:转身 / 摇尾巴 / 挥手 / 猜拳 / 掷骰子
- 🧰 工具:专注时钟 / 日程提醒 / 记一笔 / 文件整理 / 天气 / 网络 / 音乐播放器 / 麟在听什么 / 闲聊间隔 / 随机事件频率
- 🏪 养成:背包喂食 / 商城(心情·运势·记忆道具)/ 好感度条 / 每日签到 / 今日运势(幸运御守可提升运势)
- 🧠 心理陪伴:记录情绪 / 心理评测 / 评测历史 / 情绪历史 / 情绪统计 / 暖心寄语 / 麟关心一下 / 危机支持
- 🔖 传送门:一键打开收藏的网站
- 🚀 管家服务:一键启动绑定的软件
- 其他:显示/隐藏输入框 / 重新加载图片 / 🔌 API 管理 / 设置面板 / 帮助 / 退出
## 操作
- 按住拖动:移动桌宠;松手后如果在屏幕中间会"落"到底部,拖到左右边缘会"扒"在边上
- 单击桌宠:互动(戳 10 次有彩蛋奖励)
- 点击气泡:跳过打字 / 显示下一句
- 整点自动报时;21:00~07:00 自动睡觉(21:00 就上床啦,小孩子要长身体)
## 界面状态行
- 桌宠底部有一行状态小字(从左到右):好感度条 / 天气 / 接入状态。
- 宠物缩放低于 70% 时自动进入紧凑模式:好感度条隐藏,只保留天气与接入状态;把宠物调大即可恢复。
- 专注时钟启动后,倒计时显示在状态行左侧**并常驻在麟的气泡里**(更显眼);聊天时气泡自动让位给对话,聊完自动回到倒计时。状态行倒计时旁有 **✕ 按钮可随时取消**。
- 专注监督更聪明:麟每 2 秒看一眼前台窗口,发现游戏/视频站会提醒你;但**你要是在聊天里说了"我在学习/查资料/开会"等,麟就静默 30 分钟不再打扰**(`#恢复监督` 可提前恢复)。也支持聊天框直接说「专注25分钟」「取消专注」来控制专注时钟。
- 网络异常时右上角显示 📵 图标。
## 隐藏指令(在输入框输入)
- #好感 查看好感度
- #金币 查看金币
- #心情 查看情绪
- #天气 查看天气
- #换装 查看衣橱;#换装 名字 换装;#换装 默认 脱掉(需准备 名字_close.png 等图片)
- #笔记 随机读一条你的笔记
- #记忆 让麟说说记住的你
- #归档 立刻把今天的回忆写进记忆日志
- #喂 打开背包
- #睡 / #醒 强制睡觉 / 醒来
- #尾巴 / #摇 摇摇尾巴
- #挥手 挥手打招呼
- #音乐 / #听歌 麟放歌给你听(本地音乐播放器)
- #播放器 / #歌单 打开麟的音乐播放器面板
- #聊天窗口 / #窗口 打开聊天窗口(⇄ 气泡模式自由切换)
- #取消专注 / #结束专注 取消专注时钟(也可以直接说"取消专注")
- #暂停监督 / #恢复监督 专注中临时静默/恢复摸鱼提醒(说"我在学习"也会自动静默 30 分钟)
- #下一首 / #切歌 / #换一首 换下一首;#上一首 回到上一首
- #暂停 / #继续 暂停 / 继续播放
- #停 / #停歌 停止播放
- #模式 切换播放模式(顺序播放 → 列表循环 → 单曲循环 → 随机播放)
- #在听 / #听什么 麟说说你现在在听什么歌
- #情绪 打开情绪记录;#情绪历史 / #情绪统计 查看记录与统计
- #评测 打开心理评测;#评测历史 查看评测记录
- #寄语 / #暖心 随机一条暖心寄语
- #关心 / #聊聊 / #抱抱 / #难受 让麟看看你最近的心情,陪你一起理一理
- #危机 查看心理援助热线
- #转身 / #转过来 转过身去 / 转回来
- #彩蛋 隐藏彩蛋
- #帮助 查看指令列表
## 离线保底模式
- 没有配置 API Key 或联网失败时,麟会自动进入离线模式,用本地台词陪你聊天、喂食、猜拳、记笔记等功能照常可用。
## API 仓库
- 支持多家 OpenAI 兼容接口(DeepSeek / OpenAI / Kimi / 通义千问 / 智谱 / 本地 Ollama / 硅基流动等)。
- 右键 → 🔌 API 管理 可以增删改、启用/停用、切换当前 API、测试连通。
- **AI 总开关**:API 管理顶部的「启用 AI 对话」勾选框——取消勾选后即使填了 Key 也不发任何请求,麟用纯本地模式陪你(配置原样保留,随时勾回来)。
- 主 API 请求失败时会自动尝试下一个启用的 API;配置保存在程序旁的 api_config.json。
- 网络更稳了:请求失败会自动绕开挂掉的系统代理直连重试;报错也说人话(模型名填错会直接显示官方支持的模型名单,比如 DeepSeek 目前是 `deepseek-flash` / `deepseek-v4-pro`,旧名 `deepseek-chat` 仍可用)。
- 状态行右侧会显示接入状态:AI 在线 = 正在用 AI;离线模式 = 本地台词回复;AI 已停用 = 总开关关闭。
## 记忆系统
- 麟每天 **23:50 自动**把当天的对话写成记忆日志(启动时还会补写前一天的)。
- 聊天中提到你的名字、生日、喜好、讨厌的东西、工作/学校,麟会即时记住,并在之后的对话里自然引用。
- 日志存在程序旁的 memory_log 文件夹(每天一篇 .md),结构化记忆在 memory.json。
- 商城「回忆相册」可以随时手动归档今天的回忆。
## 音乐播放器(麟的本地曲库)
- 右键 → 🧰 工具 → 🎵 音乐播放器(或输入 `#音乐` 直接放歌、`#播放器` 只开面板)。
- **曲库外置(更新包瘦身)**:内置原声一共 **78 首**(77 首 mp3 + 1 首 wav;其中 72 首 320k,新补的 5 首素材本身就是 192k,mp3 / flac / m4a / wav 都能放),现在**不再塞进 exe**,而是单独打包成一份「原声曲库.zip」:第一次用时下载它,解压到 exe 旁边的 music 文件夹里(解压后 music 下会多一个「原声」子文件夹,78 首歌都在里面)就能听;之后每版更新只下约 115MB 的小 exe(原来是 620MB),曲库不用重下。启动几秒后麟会自己检查:曲库没搬过来或者少了几首,它会用气泡轻轻提醒你(找到几首 / 一共几首、该放哪儿),曲库齐了就一声不吭。想加自己的歌:点面板里的「📥 导入音乐」选文件——**zip 压缩包也行,会自动解压进曲库**;或者把**音频 / zip / 整个文件夹直接拖进播放器面板**(文件夹会递归找歌);也可以手动把音频放进 exe 旁边的 music 文件夹(别放进「原声」里),点「♻️ 恢复全部」入列。同一首导两遍不会重复,同名不同曲会自动改名「曲名 (2)」。
- 面板里有:左侧分类夹导航(全部音乐 / 内置原声 / 我的导入 + 自建分类夹,点一下只在这个分类里播放)、封面、进度条(可拖动跳转)、上一首/播放暂停/下一首/停止、音量滑条与静音、播放模式(➡️ 顺序播放 / 🔁 列表循环 / 🔂 单曲循环 / 🔀 随机播放,默认顺序播放)、可搜索的播放队列(双击跳播,右键可加入分类夹或喜欢)、歌曲前的 ♡ 点一下就收藏进「我喜欢的音乐」。
- **关闭面板 = 停止播放**;想收起面板让音乐继续,点标题栏右上角的「—」最小化(音乐继续放,任务栏图标或菜单「🎵 音乐播放器」随时召回)。进游戏、退出桌宠会自动停;**麟睡着时音响照放**(音乐播放器是麟房间的音响,不是麟在唱)。音量/模式/上次放的歌都会记住,下次接着听。
- 播放模式按钮除了点一下轮流切换,**右键可以直接选**四种模式(顺序 / 列表循环 / 单曲循环 / 随机),当前模式带勾。
- 某个文件播不动时麟会自动跳下一首;曲库全空时输入 #音乐,麟会告诉你怎么加歌。
## 听歌感知
- 麟每 15 秒悄悄看一眼系统正在播放的媒体:优先读 Windows 的媒体会话(SMTC,能拿到歌名/歌手/播放状态),拿不到时退而看常见播放器(网易云、QQ音乐、酷狗、Spotify、foobar2000 等)的窗口标题。
- 只读,不上传、不控制任何播放器;没有在听歌时它什么都不做。
- 输入 `#在听`(或右键 → 🧰 工具 → 🎧 麟在听什么)可以让麟说说你现在在听什么。
- 你在打字/操作电脑时麟不会突然插话;只有你空闲 20 秒以上、而且刚开播或换歌时才会轻轻搭一句,同一首歌 3 分钟内不重复。
- 靠窗口标题识别时(部分播放器不注册媒体会话)只算"弱证据",麟会用"好像听到……"的说法,不会瞎编歌曲细节。
## 上下文预算(越聊越省)
- 以前每轮聊天都会把整段历史全发给 API,聊得越久越贵。现在加了"上下文预算 + 滚动摘要"(思路来自 billion-context 项目的分层压缩):
- 只保留最近几轮原话 + 更早内容的滚动摘要,整体控制在约 2600 tokens 以内,超长历史自动折叠。
- 每 8 轮顺手把较早的对话压成一小段摘要(约 700 字内),存在程序旁的 chat_context.json,重启后继续用。
- 发给 API 的实时状态(天气/好感/情绪/在听歌)拼在最后一条消息里,系统提示词保持稳定,配合 DeepSeek 的前缀缓存能进一步省钱。
- 实测 50 轮对话:费用约省 37%,同等预算下能带约 2.5 倍的历史上下文。
- 想关掉:把 config.py 里 CONTEXT_BUDGET_ENABLED 改成 False,即回到旧行为(不推荐,会贵很多)。
## 心理陪伴
- 📝 **记录情绪**:10 种情绪(开心/平静/感恩/兴奋/一般/疲惫/难过/焦虑/愤怒/孤独)、5 级强度、16 个触发标签,支持备注与日记。
- 📋 **心理评测**:内置 **16 套本地量表**(症状筛查 / 人格性格 / 专项量表三大类),逐题作答后自动计分、分档解读、维度分析并生成报告。
- 症状筛查:PHQ-9(9 题)、GAD-7(7 题)、SCL-90(90 题)、SDS(20 题)、SAS(20 题)、BDC(15 题)
- 人格性格:MBTI(109 题)、气质类型(60 题)、16PF(187 题)、EPQ(88 题)、EPQ-RSC(48 题)
- 专项量表:PSS 压力感知(10 题)、BPNS 基本心理需求(21 题)、IPIP-EIS 情绪智力(64 题)、情绪稳定性(30 题)、SCCS 自我和谐(35 题)
- 🗂 **评测历史**:查看历次评测结果与逐题回顾,可删除。
- 📅 **情绪历史**:按时间倒序查看全部记录,可删除。
- 📊 **情绪统计**:连续打卡天数、近 7 天平均强度与波动预警、时段情绪规律(清晨/上午/下午/晚间/深夜)。
- 🤖 **聊天总结情绪(默认关)**:设置面板开启后,AI 会定期(攒够 4 句、间隔 1 小时以上)从聊天里总结你的情绪自动记入情绪记录,历史里标「AI总结」;没配 API 或 AI 总开关关闭时绝不发起。
- 🌻 **暖心寄语**:针对抑郁/焦虑/双相/强迫/PTSD/ADHD 的本地支持话语(不构成医疗建议)。
- 🆘 **危机支持**:内置心理援助热线(请以官方最新发布为准)。
- 若评测中涉及「伤害自己」的题目(PHQ-9 第 9 题、BDC 第 15 题、SDS 第 19 题、SCL-90 第 15 题)勾选了非最轻选项,或整体得分达到较高水平,结果页与麟都会提醒你寻求专业帮助,并附心理援助热线。
- 记录情绪后,麟会共情回应、播放对应表情;AI 对话会参考你最近的情绪状态,温柔以待。
- 所有情绪数据只保存在本地 mood.json,评测数据只保存在本地 assessment.json,绝不上传;题库来自开源项目与公开量表,仅供自评参考,不构成医学诊断。
## 主动关心(不评判、没有对错)
- 麟会每隔 10 分钟悄悄看一眼你最近的心情:只读本地的 mood.json 与 assessment.json,不上传、不外发。
- 只有你确实不太好的时候它才会开口:近 3 天负面情绪占比偏高、7 天里高强度负面偏多、或近期症状筛查类评测分数偏高;心情记录最多算「留意」,涉及风险才升级为「认真关心」。
- 一次最多一句(不超过 60 字),说完至少 3 小时内不再提,同一种状态 12 小时内不重复;你 30 秒内有键鼠操作、或者它正在睡觉/游戏/聊天时,绝不会突然插话。
- 措辞永远是「关心」而不是「诊断」:不下结论、不评判对错、不贴标签、不说教。真的很难受时,它会认真建议你找专业帮助(心理援助热线 12356)。
- 想聊聊就输入 `#关心`(也可以 `#聊聊` / `#抱抱` / `#难受`,或右键 → 🧠 心理陪伴 → 💗 麟关心一下):麟会陪你把事情理一理——发生了什么、当时的感觉、你现在需要什么、下次想怎么照顾自己。接下来 30 分钟的聊天都会保持这种「一起分析」的口径,不替你下判断。
- 人格/非症状类量表(MBTI、EPQ、情绪智力等)不参与判断,避免误报;沉默几天只会轻描淡写地问一句,不会追问。
## 赚钱方式
专注完成(+20) / 每日签到(+30) / 日程完成(+10) / 猜拳赢(+10) / 随机事件 / 戳10下(+10)
## 素材规范
- 所有姿态帧统一画布 1600×2528,角色水平居中、脚底对齐、主体约占画布高度 82%~88%。
- 程序统一按显示高度 390px(100% 缩放)缩放,画布尺寸不一致不影响屏幕表现。
## 更新记录
### zip 压缩包 / 文件夹一键导入
- **不用先解压了**:面板里点「📥 导入音乐」,可以直接选 **zip 压缩包**——麟会把里面的音频挑出来自动解压进曲库,目录套几层都无所谓;Windows 右键「发送到 → 压缩文件夹」做出来的 GBK 中文名也能还原成正常中文。
- **拖进来就行**:把音频文件、zip 压缩包、甚至整个文件夹**直接拖进播放器面板**,自动收进曲库并入列;文件夹会递归找里面的歌。拖错东西(照片、txt、网页图片)会被忽略,不会把曲库弄乱。
- **不会重复、不会覆盖**:同一首歌导过再导会被跳过;同名但是另一首(大小不同)自动改名「曲名 (2)」,两首都在。
- **坏包不崩**:rar / 7z 麟打不开,会提示你先解压;压缩包里全是照片、或者包本身坏了,只会说「没找到能听的音乐」,面板照常用。
### 曲库外置:更新包从 620MB 瘦到约 115MB
- **更新包瘦身**:以前 77 首内置音乐全塞在 exe 里,每版更新都得重下 620MB。现在曲库被拆出去了——exe 里只留代码、运行库和一份曲目清单(builtin_tracks.json),体积从 620MB 降到**约 115MB**;内置原声另做一份「原声曲库.zip」(**78 首**,约 528MB,含以前一直漏打包的那首 wav),下载一次就好,以后升级只覆盖 exe。
- **安装(只需一次)**:把「原声曲库.zip」解压到 exe 旁边的 music 文件夹里——解压后 music 下会多一个「原声」文件夹,78 首歌都在里面。标准位置是 exe 旁的 music\\原声;放歪一点麟也认(放 music 根目录、或者 exe 旁边的「原声」文件夹都行),但还是推荐标准位置。
- **麟会自己检查曲库**:启动 3 秒后,如果一首歌都没找到、或者少了几首,麟会用气泡告诉你「曲库好像还没搬过来(找到 x / y 首)」;曲库空着时输入 `#音乐`,它也会直接说明怎么装。曲库齐了就静默,不会每次启动都唠叨。
- **老用户**:旧版 exe 里的曲库不会自动搬出来(新 exe 里本来就没有),装一次「原声曲库.zip」就好;歌单、分类夹、我喜欢的音乐、回收站数据都还在 exe 旁的 playlist 文件夹里,原样保留。旧的 620MB exe 可以直接删掉,只覆盖新 exe 也不会丢任何数据。
- **回收站更安全**:曲库包里的原声文件程序不会去删,点「🗑 彻底删除」只是拉进屏蔽名单、不再显示;文件还在原地,误删了也还有救(清掉 playlist\\trash.json 里的屏蔽记录,重启麟就回到曲库)。
### 21 点就睡觉 · 麟睡着音响照放 · 只许开一个麟
- **睡觉提前到 21:00**:以前 23:00 才睡,现在 21:00(到早上 07:00)麟就上床了——小孩子要长身体嘛。`#醒` 依然是「今晚不再自动入睡」,白天自动解除;`#睡` 随时能手动哄睡。
- **麟睡着了,音乐不停**:音乐播放器是麟房间里的音响,不是麟在唱——麟睡着后歌照放,`#音乐` 和播放器面板也照样能用(麟会用迷迷糊糊的睡音回你一句);只有进游戏、退出桌宠才停。
- **只能开一个麟**:以前双击几次 exe 就冒出好几只麟,现在第二次启动不会再多一只,而是把已经在跑的那只叫到最前面(上次没关干净的残留实例也能正确接管)。
### 随机播放回来了(洗牌式:一轮内不重复)
- **🔀 随机播放**:按大家的要求把「随机播放」加回来了。现在模式按钮按 顺序播放 → 列表循环 → 单曲循环 → 随机播放 四种循环切换,按钮文字就是当前模式;聊天里输入 `#模式` 也能切到随机。
- **不是乱摇**:用的是「洗牌」而不是每首都纯随机——一轮里每首歌只会出现一次,77 首全轮完才重新洗牌,所以不会连着放同一首、也不会刚放完又绕回来;当前分类里只有一首时就原地重放。
- **范围照旧锁在当前分类**:随机也只在当前分类夹 / 当前队列里洗,不会跳到别的分类去;切换分类夹或点「♻️ 恢复全部」重扫曲库后会重新洗一轮。
- 播放模式会被记住,下次打开播放器还是上次选的那个。
### 新增:♻ 回收站(移除的歌先存这儿,「彻底删除」才真删)
- **移出 ≠ 删除**:「全部音乐 / 内置原声 / 我的导入」里选中几首点「➖ 移除选中」(或右键移除),这些歌不会被直接抹掉,而是先收进左侧导航新出现的「♻ 回收站」(带数量角标),随时能找回来。移出时会顺带从你自建的分类夹里摘掉,恢复的时候自动放回原来那几个分类夹。
- **在回收站里再决定去留**:切到「♻ 回收站」能看到所有被移出的歌,底部按钮会变成「♻ 恢复选中 / ♻ 全部恢复」(放回曲库),并多出一个「🗑 彻底删除」;右键菜单里同样有「恢复 / 彻底删除」。回收站是只读的——在里面双击不会播放、点小心心也不会收藏,纯粹用来管理待处理的歌。
- **彻底删除才真的删文件**:点「🗑 彻底删除」不弹确认框,点了立即执行——自己导入的歌会连同本地文件一起删掉(删了就找不回来);曲库包里的 78 首内置原声文件程序不会去删,只会记进一份屏蔽名单,之后即使点「♻️ 恢复全部」也不会再出现(真想找回来:清掉 exe 旁 playlist 文件夹里 trash.json 的屏蔽记录,重启麟就回到曲库了)。
- **数据**:回收站内容存在 exe 旁边的 playlist/trash.json,换新版本覆盖 exe 也不会丢。
### 修复:点♥不再把列表拽走 + 分类夹里的歌能正常移除了
- **点喜欢不再跳走**:给歌单里某一首点心心时,列表的选中条和滚动位置以前会被一起拽回"正在播放的那首"——你正看着中间偏下的歌,点个♥视野突然跳走。现在点心只更新那一首前面的 ♥ / ♡ 标记,选中条和滚动位置一动不动;只有真的换歌时列表才会跟着当前曲走。
- **分类夹里的歌能正常移除了**:上一版把内置曲的来源标签纠正成「内置」后,旧歌单里存的还是「本地|曲名」这种旧键,而列表按新键显示——点「➖ 移除选中」或右键「➖ 从「分类名」移除」时两边对不上,于是提示移出 0 首、歌原样留在分类里(看着就像"移除不掉、不实时")。现在按曲名解析后再比对,新旧键都能移掉;多选批量移除、移除正在播的那首也一并修好。同一首歌既存了旧键又存了新键时列表只显示一次,右键「➕ 添加到分类夹」的勾选状态同样按解析后的键判断,不会出现"明明在夹里却显示没勾上"。
- 移除依旧只是解除收纳关系:本地音乐文件和其他分类夹都不受影响。
### 音乐播放器再升级:喜欢的收藏夹 + 点分类夹立刻跳转 + 来源标签修正
- **「我喜欢的音乐」收藏夹**:左侧导航在系统分类下面固定多了一个 ❤ 我喜欢的音乐——不用建、也删不掉,专门放你喜欢的歌。歌单里每首歌前面有个 ♡,点一下变 ♥ 就收进收藏夹(再点一下取消);控制栏也新增「♡ 喜欢 / ♥ 已喜欢」按钮,正在听的这首一键收藏;右键菜单里同样有「♥ 喜欢 / 💔 取消喜欢」,多选能一次收藏好几首。收藏夹可以改名、清空,就是不能删。
- **点分类夹立刻看到歌**:以前正在放歌时点另一个分类夹,右边列表要等当前这首放完才换(只提示「放完就切」),看着像点了没反应。现在点哪个分类夹,列表和搜索范围立刻切过去;正在播的那首照旧放完,然后自动从新分类接着放。想连当前播放也立刻切,去 设置 勾「🎵 切换分类夹时立即更换播放队列」。
- **内置原声 / 我的导入不再弄反**:判断「哪些是 exe 自带的内置曲」的逻辑出了错,源码/便携模式下内置曲被算进「我的导入」、内置原声显示 0 首;同名文件时内置曲还会被本地文件顶掉。现在内置曲一律优先按内置认、来源标「内置」,两个系统分类的数量和来源都对了(旧版留下的错标歌单也能按曲名自动找回)。
### 修复:专注模式气泡倒计时和底栏时间对不上
- 专注时倒计时同时显示在麟的气泡和底部状态行。气泡每刷新一次会把自己标记成"专注中",下一轮刷新又被这个标记挡回去,于是气泡时间停在它接管的瞬间,和底栏越差越多。现在专注中的气泡照常每秒走,两处时间始终一致;聊天时气泡仍优先让给对话,聊完自动接回倒计时。
### 音乐播放器大升级:分类收藏夹 + 三种播放模式
- **左侧分类导航**(窗口左栏固定 200px):上面是系统分类,不可删不可改——「全部音乐 / 内置原声 / 我的导入」,各带歌曲数量角标;下面是你自己建的分类夹,点一下右边歌单就只显示这个分类,播放也锁在这个分类里。底部「+ 新建分类夹」起个名字即可(中英文数字都行,最多 20 字),建好会自动选中它;自建分类夹还能拖拽调整上下顺序。
- **收歌很方便**:在右边歌单里选中一首(或按住 Ctrl / Shift 多选几首),右键 →「➕ 添加到分类夹」,可以一次勾选加入好几个分类夹;已经在里面的分类夹前面是勾上的,再点一下就是移出。自建分类里右键还有「➖ 从「分类名」移除」。**把歌曲拖到想要的位置就能调整这个分类内的播放顺序**,拖完立刻同步到播放队列——正在放的还是这首,不会被打断,只是后面接着放的顺序变了。
- **分类夹管理**:分类项右键菜单可「重命名 / 清空歌曲 / 删除分类夹 / 上移 / 下移」。删除和清空都**只解除收纳关系,绝不会删掉本地音乐文件**,操作前会二次确认并写明这一点。
- **播放范围严格锁在当前分类**:点哪个分类就只播哪个分类,上一首 / 下一首 / 自动切歌都不会跑到分类外面去。正在放歌时切换分类夹,默认是「这首放完再切过去」,面板上会提示「《歌名》放完就切到「分类名」…」;想立刻换,去 设置 里勾上「🎵 切换分类夹时立即更换播放队列」。双击分类里的歌则是立刻切过去放。
- **三种播放模式**:➡️ 顺序播放(放完队列最后一首就停)/ 🔁 列表循环(放完最后一首回到第一首接着放)/ 🔂 单曲循环(原地一直重放,只有你手动点上一首 / 下一首才换)。点模式按钮按这个顺序循环切换,按钮上的文字就是当前模式。(这一版只做了三种;随机播放后来按大家的要求加回来了——洗牌式、一轮内不重复,见上面「随机播放回来了」。)
- **搜索跟着分类走**:搜索框提示会变成「🔍 搜索全部音乐…」或「🔍 在「轻音乐收藏」里搜索…」,选中分类时只在这个分类里搜。
- **数据不会丢**:分类夹(名字 / 包含哪些歌 / 排序)存在 exe 旁边的 playlist/playlists.json 里(回收站清单在同一个文件夹的 trash.json),换新版本直接覆盖 exe 也不会丢;内置曲目也能收进自建分类,不动内置文件结构。
- 空分类会显示「该分类暂无音乐,选中歌曲右键即可添加」;底部「移除选中」在系统分类里是把歌收进「♻ 回收站」(在那儿能恢复,点「🗑 彻底删除」才真删文件),在自建分类里只去掉这个分类的收纳关系。
### 音乐修复:本地歌曲终于能放了 + 内置曲库换成 320k 高音质
- **「本地音乐点了没反应」的根因**:Windows 上播放器默认走 DirectShow 解码器,而它打不开相当一部分现代 mp3(以及 flac / m4a)——表现就是时长显示 00:00、点播放没动静、队列也不跳;内置那批老 mp3 恰好是它认识的编码,所以只有本地歌放不了。现在麟启动时自动把播放后端切到 Windows Media Foundation:mp3 / flac / m4a / wav 都能放,只有 ogg 还不行(遇到会提示后跳过)。
- **音质升级**:内置曲库从 72 首 192k 换成 **77 首高码率**(取自游戏《丰裕之角 不可思议之物居住的小镇》同名专辑;实测 72 首是 320k,新补的 5 首素材本身就是 192k,已无法再提升)。原有 72 首全部换新,另外补了 5 首:不可思议之物居住的小镇(OP版)、初识之歌(伴奏版)、小镇情景-Bar(法国风情)、麟篇隐藏 OST1、麟篇隐藏 OST2。
- **代价**:曲库从 250MB 涨到约 528MB(78 首)。320k 已是 mp3 的码率上限,再想小就只能降码率了;所以从这一版起曲库搬到 exe 外面、单独做成「原声曲库.zip」,exe 反而瘦到约 115MB(见本记录最上面「曲库外置:更新包从 620MB 瘦到约 115MB」)。
- **队列跟着当前曲走**:自动切下一首(尤其随机播放)时,队列里的灰色选中条和滚动位置会一起跳到正在放的那首;以前它赖在你上一次点过的那首上,看起来就像「还在放上一首」。
- **顺序播放会接着放了**:以前切到「顺序播放」,一曲终了就原地停住(按钮弹回 ▶ 播放、进度停在结尾),看着像卡死;现在会顺着队列接着放下一首,放到队列最后一首才停。想放完再从头来请用「列表循环」。
### 修复:雨天出现"两只麟"重叠
- 旧的雨伞叠加层会在下雨时把撑伞立绘**叠**在站立立绘上,看起来像两只麟挤在一起。现在雨/雪天麟的待机立绘**直接切换**成撑伞图——同一时刻永远只有一只麟;雨停自动恢复,说话/互动/睡觉等所有姿态不受影响。
### 聊天再升级:流式速度自定义 + 工具全量调用 + 不再揪着情绪不放
- **流式速度自定义**:设置面板新增「💬 聊天窗口流式速度」——慢速(一笔一画)/ 适中(打字机感,默认)/ 快速 / 瞬间。网络增量先进缓冲按你选的节奏上屏,网络再快也不会糊屏。
- **聊天框全量工具调用**:直接用说话指挥麟——「专注模式计时10分钟」「帮我打开专注模式」(默认25分钟)「取消专注」「放首歌 / 下一首 / 暂停音乐 / 停止音乐」「打开设置 / 情绪记录 / 情绪历史 / 情绪统计 / 心理评测 / 帮助 / 历史记录 / 商城 / 日程 / 笔记」「天气怎么样」「现在几点了」「摸摸头」「抱抱」……本地直接执行,不耗 API、不绕弯子。
- **不再揪着心情不放**:麟回复的规则已改——你亲口说"没事/我很开心/不想聊"时,麟会完全相信并尊重你的表述,顺着聊轻松的话题,绝不再追问、质疑或把话题拉回情绪;情绪记录和心情数值只是背景推测,不是审问理由。
### 专注模式升级 + 聊天功能调用 + 离线模式大扩容
- **倒计时上气泡**:专注时倒计时常驻在麟的气泡里(更显眼);要聊天时气泡自动让位给对话内容,聊完自动回到倒计时。状态行倒计时旁新增 **✕ 取消按钮**(也可 `#取消专注` 或直接说"取消专注")。
- **聊天框功能调用**:现在可以直接用自然语言指挥麟——说「专注25分钟」开始专注、「取消专注」结束;专注中说「我在学习 / 查资料 / 开会」等,麟就静默摸鱼提醒 30 分钟(B 站看教程不再被误判!),`#暂停监督` / `#恢复监督` 手动控制。
- **离线模式大扩容**:没配 API 时的本地回复从"翻来覆去几句"扩成每类意图一组台词池(问候/身份/倾诉/报喜/加油/音乐/游戏/专注/提问/长文本……),叠加时段(清晨到深夜)、麟的心情、天气三层语气,且同一句不会连着出现两次。
### 聊天窗口补完:流式输出 + 修复文字被气泡裁切
- **流式输出**:聊天窗口里麟的回复现在**逐字逐句实时蹦出来**(不用等整段写完才显示)。走的还是你配置的 API(DeepSeek 等都支持);如果某个接口不支持流式或中途断流,自动回退到整段返回,不影响使用。桌宠气泡模式保持原有的逐句打字机效果不变。
- **修复**:聊天气泡里的文字(尤其首行和长消息)会被气泡边框裁掉一角的问题——内边距计算方式重做,长消息自动换行也完整显示。
### 新增:聊天窗口(气泡 ⇄ 窗口自由切换)
- 右键 → 💬 对话 → **🖥 聊天窗口**(或输入 `#聊天窗口` / `#窗口`):一个完整的聊天界面——你在右边、麟在左边,带时间戳、可上下滚动翻记录、消息可选中复制,底部有输入框(Enter 发送)。
- **两种模式自由切换**:窗口开着时,聊天回复显示在窗口里(流式逐字输出,桌宠不打字泡);点窗口右上角 × 或「💬 回到气泡」关掉,立刻回到原来的桌宠气泡模式。两边是**同一场对话**,历史完全同步,从哪个输入框发都一样。
- 窗口可以最小化到任务栏(有自己的图标,点一下召回);麟的随机事件、主动关心、音乐提示照常在桌宠气泡里冒出来,不受影响。
### 新增:聊天总结情绪(默认关,设置里开启)
- 设置面板新增「🤖 聊天总结情绪」开关:开启后,麟会在**攒够 4 句发言且距上次总结超过 1 小时**时,请 AI 从你最近说的话里总结当前情绪,自动写入情绪记录——情绪历史里带「AI总结」标记,可照常删除,情绪统计与主动关心也会把它算进去。
- 走和聊天同一套 API(遵守 🔌 API 管理的 AI 总开关);没配 API、总开关关闭或纯本地模式下绝不发起,总结失败也完全静默。记录仍然只保存在本地 mood.json;总结时会把最近聊天片段经同一 API 通道发给模型(和聊天本身同一条路)。
### 修复:打包版(exe)无法连接任何 https 接口的问题
- **根因**:本项目构建用的 Python 是带安全补丁的定制版,`ssl` 模块创建加密连接时会强制加载自身目录下的 `codex-rejected-cas.pem`(吊销 emSign 根证书用)。源码运行时该文件就在;**打包成 exe 后它没跟进去**,于是 exe 里所有 https 请求在建连时就报「Connection aborted / FileNotFoundError」。此问题从第一个 exe 起就存在(源码模式一直正常,所以开发时没发现)。
- **修复(双保险)**:① 构建时把 `codex-rejected-cas.pem` 直接打进 exe;② 程序启动时自检,发现缺文件就自动补写内置副本。已用「生产代码冻结探针」实测:exe 内 https 请求恢复正常(能拿到服务端 401/200 应答)。聊天对话、📡 测试连通从此在 exe 里真正可用。
### API 管理升级:AI 总开关 + 网络自愈 + 报错说人话
- **AI 总开关**:🔌 API 管理顶部新增「启用 AI 对话」——取消勾选后即使填了 Key 也不发任何请求,麟用纯本地模式陪你;配置原样保留,随时勾回来。状态行会显示「AI 已停用」。
- **网络自愈**:系统代理(Clash 等)挂掉时,请求会自动绕开代理直连重试——DeepSeek/Kimi/通义/智谱这些国内接口直连本来就能通,不再被死代理拖垮。
- **报错说人话**:测试连通的失败信息直接告诉你原因——模型名填错会显示官方支持名单(DeepSeek 现在是 `deepseek-flash` / `deepseek-v4-pro`,旧名 `deepseek-chat` 仍可用)、Key 无效、余额不足、限流、代理挂了……一目了然。默认 DeepSeek 模型已更新为 `deepseek-flash`。
### 新增托盘图标 + 播放器最小化后有任务栏图标(找得到麟了)
- **托盘常驻图标上线**:屏幕右下角(时钟旁)现在有麟的小图标——**左键/双击一下就把麟叫到最前**(被别的窗口挡住时特别好用);右键菜单可以直接「显示/隐藏麟」「🎵 音乐播放器」「⏹ 停止音乐」「退出桌宠」。
- **播放器最小化后在任务栏有自己的图标**:点标题栏「—」最小化,任务栏会出现麟的播放器图标,点一下就回到面板(音乐一直在放);托盘菜单的「🎵 音乐播放器」也能召回。桌宠本体保持不占任务栏的惯例(避免被误点最小化弄丢麟),定位就交给托盘图标。
### 播放器换上水彩雨巷背景
- 音乐播放器面板的背景换成了 `bg.jpg`(水彩雨巷街景):整窗铺满,再叠一层暖奶油半透明罩,水彩质感透出来、深棕文字依然清晰;最大化/还原时背景自动跟随窗口尺寸。封面与队列等所有功能不受影响。
### 播放器标题栏换成标准三键:— 最小化 / □ 最大化 / × 关闭
- 按要求把最小化挪到了**标题栏右上角**,就是 Windows 标准的三个键:「—」最小化到任务栏(**音乐继续放**,点任务栏图标或菜单「🎵 音乐播放器」召回)、「□」最大化铺满屏幕、「×」关闭(**立即停歌**)。
- 最小化时麟会说一句提示;面板有自己的任务栏图标,召回更直观。底部原来的「最小化」按钮已移除(功能在标题栏里)。
### 面板行为定稿:关闭即停歌,「继续播放」改为最小化
- **关闭音乐播放器窗口(X / 关闭键 / Esc)现在会立刻停止播放**——不再"关了还在响"。
- 想"收起面板让音乐继续",点面板右下角新增的「🗕 最小化(音乐继续)」:面板收起、音乐照放,麟还会提示一句;之后从右键菜单「🎵 音乐播放器」随时召回(会直接回到刚才的面板,不会重复开)。
- 面板同时改成非模态:开着面板也能照常右键桌宠、戳麟、用其它功能,不再被面板挡住。
### 游戏侦测修复:Steam 挂机不再被误判成打游戏(音乐"点了没反应"的真相)
- **真凶**:游戏侦测名单里原来包含 Steam.exe,而 Steam 经常常驻后台,麟每 5 秒扫一次进程,就把它当成了"你一直在打游戏",于是缩到屏幕角落、静默拒绝所有音乐操作。**跟好感度没有任何关系**——音乐播放器从来就没有好感度门槛。已把 Steam.exe 从名单摘除:真正的游戏本体(LOL / 原神 / DOTA2 / CF / QQ游戏 / 无畏契约)都有各自的进程名,照常侦测;通过 Steam 启动的游戏也一样。
- **音乐入口加"永不静默"保险**:以后即使内部出现任何异常,麟也会用气泡把原因说出来("唔…音乐面板打不开(原因)"),绝不会再无声无息。游戏模式中点音乐会明确提示"检测到你在打游戏,关掉游戏就能放歌"。
### 音乐播放器上线:72 首歌装进 exe,随身带走的曲库
- **原来的「听歌陪伴 60 秒」升级成本地音乐播放器**:右键 → 🧰 工具 → 🎵 音乐播放器(或输入 `#音乐` 直接放歌)。72 首歌已经打包进 exe 里,把单个 exe 拷到别的电脑也有歌听;想加自己的歌,点面板「📥 导入音乐」或把音频放进 exe 旁的 music 文件夹再点「♻️ 恢复全部」。
- 播放器面板有封面、可拖动进度条、上/下一首、播放暂停、停止、音量与静音、四种播放模式(顺序 / 列表循环 / 单曲循环 / 随机,默认随机)和可搜索的播放队列(双击跳播)。关掉面板音乐不停,入睡 / 进游戏 / 退出才自动停;音量、模式、上次放的歌都会记住。
- 新增聊天指令:`#音乐` `#播放器` `#下一首` `#上一首` `#换一首` `#暂停` `#继续` `#停` `#模式`;入睡 / 进游戏时麟会自动把音乐停下来。
- 顺便升级:进入游戏模式时网络检测和天气查询也会暂停(以前只在后台静默跑);网络检测彻底不再开子进程(改用 socket 探测),从根上杜绝任何「闪黑框」的可能;没有多媒体组件的老环境自动退回原来的八音盒模式。
### 打游戏时不再弹黑框(网络检测静默化)
- **抓到真凶了**:麟每 60 秒会用系统的 ping.exe 检查一次网络,而麟是无控制台的 GUI 程序,Windows 会给 ping 新开一个控制台/终端窗口——这就是「时不时弹出最高层级窗口、游戏被切回桌面」的元凶(尤其独占全屏游戏对此极其敏感)。已在源码里给 ping 加上 CREATE_NO_WINDOW 参数,现在网络检测完全静默,不产生任何窗口。此前「标题栏 ?」等修复解决的是对话框问题,这个黑框来自完全不同的路径,所以在开发机上一直复现不出来,抱歉让你多等了一轮。
### 标题栏「?」已移除 / 面板不再压住浏览器
- **删掉所有对话框右上角的「?」**:那是 Qt 自带的「上下文帮助」按钮,点它会让程序进入 What’s This 模式——整个界面等着你再点一下(看起来就是卡死),还会冒出跟着光标走的小提示气泡,一下就消失、正好盖在打字位置上。麟的控件没写任何帮助文案,这按钮只会误触,现已全局关掉(AA_DisableWindowContextHelpButton)。
- **设置面板等窗口不再一直压在最上层**:以前所有面板都是置顶桌宠的子窗口,Windows 会把它们一起放进置顶层,所以点浏览器也抬不到前面。现在打开面板时桌宠临时让位、面板本身也不置顶,点浏览器就能正常切到前面;面板关掉后桌宠自动恢复置顶。
- **新增「桌宠窗口保持置顶」开关**:右键 → 设置面板里可以关掉置顶(桌宠像普通窗口一样排序),默认开启;无论开关与否,打开面板期间都不会挡住别的程序。
### 帮助不再卡死 / 麟会主动关心你
- **修「点帮助卡死」**:帮助窗口以前是模态框,会把桌宠压在后面、连输入框都一起冻结,看起来就像卡死。现在改成非模态小窗:点击后立即返回、不冻结桌宠和输入框,不抢键盘焦点(正在打字完全不受影响),会自动夹进屏幕可视区(不会被置顶的桌宠挤到屏幕外),readme 内容异常或渲染失败会退化成纯文本显示,记事本打不开也只提示、不会闪退。
- **麟会偶尔主动关心你**:新增 care.py,本地读取心情记录与评测结果判断你的状态(近 3 天负面占比、7 天高强度负面、30 天症状筛查分数),只在你空闲时轻轻关心一句,最多 3 小时一次、同一状态 12 小时内不重复;措辞不评判、没有对错、不说教、不诊断,涉及风险时认真提示专业帮助与心理援助热线 12356。
- **可以一起分析**:输入 `#关心` / `#聊聊` / `#抱抱` / `#难受`,或右键「🧠 心理陪伴 → 💗 麟关心一下」,接下来 30 分钟麟会用开放式提问陪你把「发生了什么 / 当时感受 / 需要什么 / 下次怎么照顾自己」理一遍,不替你下结论。
- 情绪与评测数据仍然只读本地、绝不上传;人格类与非症状量表不参与判断,避免误报。
### 听歌感知 / 越聊越省 / 弹窗彻底修复
- **弹窗再也不会打断打字**:随机事件小窗其实是独立窗口,系统把它当成"可接收按键的窗口",随手一个 Esc/Enter 就让它一闪而过(在别的程序打字时也一样)。现在改成桌宠窗口内的普通小部件(不是窗口):不激活、不置顶、抢不到键盘;同时用系统级空闲检测(GetLastInputInfo)判断你忙不忙——你在任何程序里打字,麟都不弹事件也不发请求,等你空闲 20 秒后才安静显示,60 秒没回应自动收起。
- **麟能听见你在听什么歌**:新增 now_playing.py(Windows 媒体会话优先,播放器窗口标题兜底)+ listening.py(状态机与话术)。`#在听` / 右键「🎧 麟在听什么」可以问;你空闲时刚开播或换歌它才会轻轻搭一句(同曲 3 分钟、全局 90 秒冷却),弱证据只敢说"好像听到"。
- **聊天越聊越省**:新增 context_budget.py,按预算折叠历史 + 滚动摘要(见上文「上下文预算」),50 轮实测省约 37%;系统提示词拆成稳定段/易变段,配合 DeepSeek 前缀缓存继续减费。
- 顺手清理:pet_window.py 里三处早已用不到的死 import(QMessageBox / ask_api_key_once / EventDialog)。
### 稳定性修复(上一轮)
- **修复发送消息后桌宠闪退**:写聊天日志的函数漏了 `import time`,一写日志就抛异常;PyQt 遇到未捕获异常会直接终止进程(就是"点发送→卡死退出"的真凶)。已补齐,并给所有槽函数异常加了兜底。
- **修复偶尔自行退出**:新增 crash_guard.py,全局接管未捕获异常——出错只写 crash.log(程序旁)并自动把"思考中/忙碌"状态复位,不再憋死进程;顺带修了剪贴板内容为空时崩溃、接口返回空内容时崩溃。
- **修复弹窗一闪而过、打断打字**:日程提醒不再弹抢焦点的提示框、也不再强行把桌宠窗口提到最前,改成气泡提醒 + 轻响;随机事件小窗改为不抢焦点、不挡输入、也不置顶的非模态窗口(你在别处打字它不会吃掉按键),60 秒没回应自动收起;整点报时改到后台线程,不再卡一下。
- **修复 #醒 之后马上又睡**:以前夜里即使 `#醒`,下一秒又被判定为"该睡觉"而重新入睡,导致听歌等指令全部失效。现在 `#醒` 是"本夜不再自动入睡"的明确指令,白天自动解除;`#睡` 仍然有效。
- **一分钟听歌真的出声了**:新增 music_box.py,用纯标准库(wave + math + winsound)即时合成一段 24 秒无缝循环的八音盒摇篮曲(C 大调五声音阶,22050Hz 单声道 WAV,缓存到 %TEMP%/lin_pet_music),`#音乐` / 右键「听歌陪伴」时循环播放 60 秒,到点/睡觉/游戏/退出自动停止;没有声卡或非 Windows 时安静降级,只陪你不吵你。
- **首次启动的 API 向导不再弹窗**:原来的输入框会抢焦点、还容易被按键关掉,现在改成启动后需要时在聊天里提示配置(右键 → 🔌 API 管理)。
## 项目结构(开发者)
- oc.py / main.py:入口(两者等价,run.bat / pack.bat 沿用 oc.py)
- config.py:全部常量(API 仓库模板 / 图片路径 / 人设台词 / 商城 / 天气 / 记忆参数)
- data.py:文件与数据读写(路径、json、日志、Key、初始化)
- api_client.py:多 API 请求与主备切换、连通测试、首次向导、信号桥
- local_brain.py:本地离线台词引擎(无 API 时的保底聊天)
- memory.py:记忆日志写入与本地事实提取
- mood.py:心理陪伴(情绪记录/统计分析/暖心台词库)
- care.py:情绪察觉与主动关心(读心情/评测判断状态、关心话术与冷却、一起分析口径)
- assessment.py:心理评测引擎(16 套量表通用计分、本地存储、分档与维度解读)
- scales_data.py:量表题库数据(题目/选项/维度/计分规则,来自开源项目整理)
- widgets.py:对话气泡与桌宠本体控件
- dialogs.py:全部对话框
- crash_guard.py:全局未捕获异常兜底(写 crash.log + 复位界面状态,防闪退)
- music_box.py:八音盒音频(纯标准库合成 + winsound 异步循环播放,缺多媒体组件时的降级后备)
- music_folder.py:本地音乐播放器内核(QMediaPlayer + 曲库包 music/原声 + 清单判定(builtin_tracks.json)与外部导入两级曲库、四种播放模式〔顺序 / 列表循环 / 单曲循环 / 随机〕、分类夹播放范围)
- playlists.py:分类收藏夹数据(纯 Python 存储,写在 exe 旁 playlist/playlists.json)
- trash.py:回收站数据(被移出的歌 + 彻底删除的屏蔽名单,写在 exe 旁 playlist/trash.json)
- context_budget.py:上下文预算与滚动摘要(token 估算、历史折叠、摘要请求)
- listening.py:听歌状态机(开始/暂停/换歌/停止、搭话冷却、话术)
- now_playing.py:读取系统正在播放的音乐(媒体会话强证据 / 窗口标题弱证据)
- single_instance.py:单实例守卫(QLocalServer 命名管道,第二次启动只把麟叫到最前)
- pet_window.py:主窗口、状态机、系统感知、对话与记忆业务、入口 main()
"""
# 说明书版本:内容有更新时 bump 一下,启动时会把旧 readme.md 备份成 readme_旧版_*.md 再写新的
# (帮助窗口是实时读 readme.md 的,不刷新的话老用户永远看不到更新记录)
README_VERSION = "2026-11-06-zipimport"
# Open-Meteo 天气代码 → 中文(备用天气源)
WEATHER_CODE = {
0: "晴", 1: "晴间多云", 2: "多云", 3: "阴",
45: "雾", 48: "雾凇", 51: "毛毛雨", 53: "毛毛雨", 55: "毛毛雨",
56: "冻毛毛雨", 57: "冻毛毛雨", 61: "小雨", 63: "中雨", 65: "大雨",
66: "冻雨", 67: "冻雨", 71: "小雪", 73: "中雪", 75: "大雪",
77: "雪粒", 80: "阵雨", 81: "强阵雨", 82: "暴雨", 85: "阵雪", 86: "阵雪",
95: "雷阵雨", 96: "雷阵雨伴冰雹", 99: "雷暴伴冰雹",
}
# 英文天气 → 中文(wttr.in 用;顺序不能乱,长的在前)
WEATHER_CN = {
"patchy rain": "毛毛雨", "light rain": "小雨", "moderate rain": "中雨", "heavy rain": "大雨",
"light snow": "小雪", "moderate snow": "中雪", "heavy snow": "大雪",
"partly cloudy": "多云", "overcast": "阴", "thundery": "雷阵雨",
"sunny": "晴", "clear": "晴", "cloudy": "多云", "rain": "雨", "drizzle": "毛毛雨",
"snow": "雪", "thunder": "雷", "fog": "雾", "mist": "雾", "shower": "阵雨",
"freezing": "冻雨", "hail": "冰雹", "storm": "雷阵雨",
}
# 天气状况 → emoji 图标
WEATHER_ICON = {"晴": "☀️", "多云": "⛅", "阴": "☁️", "雾": "🌫", "毛毛雨": "🌦",
"雨": "🌧", "雪": "❄️", "雷": "⛈", "雹": "🌨"}
# 设置面板默认值(旧档没有的字段会自动补上 = 无缝升级)
# always_on_top:桌宠是否一直置顶(设置面板里可改;打开面板时总会临时让位)
# music_*:本地音乐播放器记忆(音量/播放模式/上次放的歌,见 music_folder.py)
# chat_mood_summary:聊天情绪总结(默认关;开启后 AI 定期从聊天总结情绪写入
# mood.json,见 mood_summary.py;无 API/AI 总开关关闭时绝不发起)
# stream_speed:聊天窗口流式上屏节奏(instant/fast/medium/slow,见 ChatWindow)
DEFAULT_SETTINGS = {"pet_scale": 100, "chat_interval": 1200,
"event_min": 30, "event_max": 120, "event_weight": 60,
"always_on_top": True,
"music_volume": 70, "music_playback": "random",
"music_last_title": "", "chat_mood_summary": False,
"stream_speed": "medium"}
# ---- 记忆系统 ----
MEMORY_FILE = "memory.json" # 结构化记忆(事实 + 每日总结)
MEMORY_LOG_DIR = "memory_log" # 人类可读的每日日志目录
MAX_FACTS = 60 # 最多记住的事实条数
MAX_DAILY = 30 # 保留最近多少天日志
# 本地即时事实提取规则:(正则, 模板);用于无需联网也能"越用越懂"
FACT_PATTERNS = [
(r"(?:我叫|我是|我的名字(?:是|叫))\s*([\u4e00-\u9fa5A-Za-z0-9]{2,12})", "幸歌的名字是{}"),
(r"(?:我最喜欢|我喜欢吃|最爱吃|喜欢喝)\s*([\u4e00-\u9fa5A-Za-z0-9,、和及]{2,18})", "幸歌喜欢{}"),
(r"(?:我讨厌|我不喜欢|我最讨厌)\s*([\u4e00-\u9fa5A-Za-z0-9,、和及]{2,18})", "幸歌不喜欢{}"),
(r"生日(?:\s*是)?\s*(\d{1,2})\s*月\s*(\d{1,2})\s*日", "幸歌的生日是{}月{}日"),
(r"(?:在|于)\s*([\u4e00-\u9fa5A-Za-z0-9]{2,15})\s*(?:工作|上班|上学)", "幸歌在{}工作/上学"),
]
# ---- 上下文预算(降本:滚动摘要 + 按预算保留最近对话) ----
# 背景:历史消息无限增长会让「每轮聊天请求」越聊越贵。这里给单次请求一个估算
# token 预算,超出预算的旧对话会被压缩成一段滚动摘要(见 context_budget.py),
# 摘要存在独立的 chat_context.json,不影响 memory.json 的每日归档。
CONTEXT_BUDGET_ENABLED = True # 总开关:False 时退回旧行为(全量 20 条历史)
CHAT_CONTEXT_BUDGET = 2600 # 单次聊天请求的估算 token 预算
KEEP_RECENT_TURNS = 6 # 始终原样保留最近 N 轮(1 轮 = 用户+麟 两条)
MAX_MSG_CHARS = 500 # 单条历史消息超过多少字符就截断
SUMMARY_MAX_CHARS = 700 # 滚动摘要的最大字符数
CONTEXT_SUMMARY_EVERY = 8 # 保留窗口之外每累积多少条新消息触发一次摘要
HISTORY_MAX_MESSAGES = 200 # 内存里最多留多少条历史(100 轮);只是防止极端长跑爆内存,
# 真正的裁剪由 ContextBudget 按 token 预算做,所以这个值要给得宽,
# 否则 history 一旦被裁掉,摘要里的 covered 下标就要跟着平移(易错)。