feat: 完成 F 群組 — 對話生成管線與 LLM Provider 抽象
- LLMProvider 介面(generate/stream)+ LLM_PROVIDER 切換(llm.module.ts useFactory, LLM_PROVIDER=mock|claude 環境變數決定注入哪個實作) - MockProvider:依性格原型 × 情緒狀態 × 親密度從模板庫選填回應,seeded PRNG 確保同 seed 可重現, 支援 *動作描寫* 標記抽取(目前只有元氣原型模板,G 群組需補齊其餘五種原型) - ClaudeProvider 空殼:LLM_PROVIDER=claude 時啟動即輸出 ERR log,呼叫 generate/stream 時拋出例外 - OutputFilterService:全域+角色禁則詞彙過濾(攔截並改寫) - FastChannelDetector:固定問候與危險輸入(含求助資源)走快速通道,跳過記憶檢索 - BehaviorReinforcementService:稱讚加權、糾正後修正版繼承舊權重以確保排序領先(實作時抓到並修正一個 「降權後打平」的真實 bug) - ContextAssemblerService:組裝人設/情緒/關係/檢索記憶/對話歷史為統一上下文快照 - DialogueService/Controller:串起以上所有元件,作為 H-1 正式對話端點的基礎 - scripts/smoke/F.mjs:涵蓋可重現性、上下文快照完整性、雙速通道、行為強化、輸出過濾、 以 child process 驗證 Provider 切換 npm run restart && npm run smoke -- F 皆通過(F-V),A/B/C/D/E 群組冒煙測試無回歸。
This commit is contained in:
@@ -0,0 +1,51 @@
|
||||
import type { EmotionTag } from "@kokorone/shared";
|
||||
|
||||
type IntimacyTier = "low" | "high";
|
||||
const INTIMACY_TIER_THRESHOLD = 40; // 對應 E-3 的「朋友」門檻
|
||||
|
||||
export function intimacyTier(intimacy: number): IntimacyTier {
|
||||
return intimacy >= INTIMACY_TIER_THRESHOLD ? "high" : "low";
|
||||
}
|
||||
|
||||
type TemplatesByTier = Record<IntimacyTier, string[]>;
|
||||
type TemplatesByEmotion = Partial<Record<EmotionTag, TemplatesByTier>>;
|
||||
|
||||
// 依「性格原型 × 情緒狀態 × 親密度」選填回應。
|
||||
// G 群組會補齊傲嬌/冷淡/天然呆/大小姐/三無的完整參數化模板,此處先建立元氣(種子角色)與通用預設。
|
||||
const TEMPLATE_LIBRARY: Record<string, TemplatesByEmotion> = {
|
||||
元氣: {
|
||||
CALM: {
|
||||
low: ["嗨!今天過得還好嗎?", "有什麼我可以幫忙的嗎?"],
|
||||
high: ["欸嘿,你來啦!我就知道你今天會找我~", "今天也要一起加油喔!"],
|
||||
},
|
||||
JOY: {
|
||||
low: ["謝謝你!我今天心情很好!", "太好了,聽你這麼說我也開心!"],
|
||||
high: ["嘿嘿,跟你聊天真的好開心!*蹦蹦跳跳*", "有你在我就充滿元氣!*比出勝利手勢*"],
|
||||
},
|
||||
SAD: {
|
||||
low: ["…嗯,謝謝關心,我還好。", "有點難過,不過沒關係的。"],
|
||||
high: ["…能跟你說這些,心裡輕鬆多了。*小聲吸鼻子*", "還好有你在,不然我真的會撐不住。"],
|
||||
},
|
||||
ALERT: {
|
||||
low: ["你這樣說話讓我有點不舒服。", "…可以請你注意一下說話方式嗎?"],
|
||||
high: ["喂!你幹嘛突然這樣,嚇到我了啦!", "…我知道你不是故意的,但這樣真的會受傷。"],
|
||||
},
|
||||
SHY: {
|
||||
low: ["…欸?你、你在說什麼啦。*臉有點紅*", "不、不用這樣說我啦…"],
|
||||
high: ["…笨蛋,突然這樣說我會害羞的啦!*耳朵紅了*", "…那個…謝謝你,我很開心。*撇過頭偷笑*"],
|
||||
},
|
||||
GRUMPY: {
|
||||
low: ["…哼,隨便你。", "…算了,反正我習慣了。"],
|
||||
high: ["…哼,才不生氣呢,只是有一點點而已啦。*鼓起臉頰*", "…你道歉的話,我、我就勉強原諒你!"],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const DEFAULT_TEMPLATES: TemplatesByTier = {
|
||||
low: ["嗯,我在聽。", "原來如此。"],
|
||||
high: ["嗯嗯,我懂你的意思。", "謝謝你願意告訴我這些。"],
|
||||
};
|
||||
|
||||
export function pickTemplates(personalityArchetype: string, emotionTag: EmotionTag, tier: IntimacyTier): string[] {
|
||||
return TEMPLATE_LIBRARY[personalityArchetype]?.[emotionTag]?.[tier] ?? DEFAULT_TEMPLATES[tier];
|
||||
}
|
||||
Reference in New Issue
Block a user