- ScheduleService:I-1 平日/週末/假期時段表(可為角色寫入高中生預設作息)、 I-3 時間感知(Asia/Taipei 當地時間,不受伺服器時區影響)、剛醒/睡前偵測 - constants.ts:I-2 時段狀態 → 回應可用度對照(FREE/SEMI_BUSY/BUSY/SLEEP → NORMAL/BRIEF/DELAYED/NO_REPLY),沒有作息表的角色一律視為 NORMAL(相容既有角色) - ScheduleExceptionService:I-4 三種破例(深夜還陪你聊/上課偷回訊息/為你調整行程), 各自獨立冷卻期,觸發時記入關係帳本 - ScheduleEmotionBaselineService:I-5 作息驅動情緒基線(社團剛結束的疲憊、假日偏高心情), 只在本輪沒有明確情緒訊號時介入,串接進 EmotionService.processInput 的新增選項 - OfflineEventService:I-6 離線事件生成,依「今天已發生的固定行程」挑選對應模板, 一天只生成一次,寫入低權重情節記憶 - DialogueService 整合以上機制:離線事件生成 → 情緒基線標記 → 累積親密度 → 作息可用度判定 → 不符合則嘗試破例 → 依可用度決定回覆內容 - 修正真實 bug:G-5 角色建立流程誤用 source=OFFLINE_GENERATED 標記背景故事, 與 I-6「今天是否已生成離線事件」的判斷共用同一標記,已改為 SOURCE_EXTRACTION - ChatView.tsx 補上 NO_REPLY/context 為 null 的防呆(作息可用度整合後的必要調整) - scripts/smoke/I.mjs:以獨立測試角色(避免污染種子角色的排程狀態)驗證全部六項 npm run restart && npm run smoke -- I 皆通過(I-V),A~H 群組冒煙測試無回歸。
273 lines
8.4 KiB
Plaintext
273 lines
8.4 KiB
Plaintext
// Kokorone 資料模型
|
||
// R-2 會將 provider 由 sqlite 切換為 postgresql,並為 MemoryRetriever 加上 pgvector 語意檢索。
|
||
|
||
generator client {
|
||
provider = "prisma-client"
|
||
output = "../packages/db/generated"
|
||
}
|
||
|
||
datasource db {
|
||
provider = "sqlite"
|
||
}
|
||
|
||
enum CharacterSource {
|
||
ORIGINAL // 原創
|
||
EXISTING_WORK // 既有作品
|
||
}
|
||
|
||
enum CharacterBuildStatus {
|
||
CANDIDATE // 候補
|
||
BUILT // 已建置
|
||
}
|
||
|
||
enum MemorySource {
|
||
INTERACTION // 互動
|
||
OFFLINE_GENERATED // 離線生成
|
||
SOURCE_EXTRACTION // 原作萃取
|
||
}
|
||
|
||
// 情緒標籤類型:對應情緒子系統六種狀態(見 D 群組)
|
||
enum EmotionTag {
|
||
CALM // 平靜
|
||
JOY // 愉悅
|
||
SAD // 低落
|
||
ALERT // 警戒
|
||
SHY // 害羞
|
||
GRUMPY // 彆扭
|
||
}
|
||
|
||
enum RelationshipStage {
|
||
STRANGER // 陌生 0-19
|
||
ACQUAINTANCE // 認識 20-39
|
||
FRIEND // 朋友 40-59
|
||
CLOSE_AMBIGUOUS // 摯友-曖昧 60-79
|
||
BONDED // 羈絆 80-100
|
||
}
|
||
|
||
// I-1 週期表:平日/週末/假期各一份時段表
|
||
enum ScheduleDayType {
|
||
WEEKDAY // 平日
|
||
WEEKEND // 週末
|
||
HOLIDAY // 假期/特殊日
|
||
}
|
||
|
||
enum ScheduleSlotStatus {
|
||
SLEEP // 睡眠
|
||
BUSY // 忙碌
|
||
SEMI_BUSY // 半忙碌
|
||
FREE // 空閒
|
||
}
|
||
|
||
model User {
|
||
id String @id @default(cuid())
|
||
name String
|
||
createdAt DateTime @default(now())
|
||
updatedAt DateTime @updatedAt
|
||
|
||
relationships Relationship[]
|
||
relatedMemories EpisodicMemory[]
|
||
|
||
@@map("users")
|
||
}
|
||
|
||
model Work {
|
||
id String @id @default(cuid())
|
||
title String
|
||
volumeProgress String? // 卷數進度
|
||
worldview String? // 世界觀
|
||
progressAnchor String? // 作品進度錨定點(M-9/N 群組使用;描述作品實際描寫過的時期)
|
||
createdAt DateTime @default(now())
|
||
updatedAt DateTime @updatedAt
|
||
|
||
characters Character[]
|
||
|
||
@@map("works")
|
||
}
|
||
|
||
model Character {
|
||
id String @id @default(cuid())
|
||
workId String?
|
||
work Work? @relation(fields: [workId], references: [id], onDelete: SetNull)
|
||
|
||
source CharacterSource
|
||
buildStatus CharacterBuildStatus @default(CANDIDATE)
|
||
|
||
// 角色設定表七欄位
|
||
basicInfo String // 基本資料:名字、年齡、外型、出身
|
||
backgroundStory String // 背景故事:成長經歷、重大事件
|
||
personalityArchetype String // 性格原型:傲嬌/冷淡/天然呆/元氣/大小姐/三無
|
||
likesDislikes String // 喜好/厭惡
|
||
goalsObsessions String // 目標/執念
|
||
speechStyle String // 說話方式:口癖、語尾詞、第一/第二人稱
|
||
initialRelationValue String? // 人際初始值:對誰親近、對誰有心結
|
||
|
||
createdAt DateTime @default(now())
|
||
updatedAt DateTime @updatedAt
|
||
|
||
aliases CharacterAlias[]
|
||
episodicMemories EpisodicMemory[]
|
||
semanticMemories SemanticMemory[]
|
||
proceduralRules ProceduralRule[]
|
||
emotionState EmotionState?
|
||
relationships Relationship[]
|
||
contrastTriggerLogs ContrastTriggerLog[]
|
||
scheduleSlots ScheduleSlot[]
|
||
specialDays SpecialDay[]
|
||
scheduleExceptions ScheduleExceptionLog[]
|
||
|
||
@@map("characters")
|
||
}
|
||
|
||
// G-4 反差萌稀有度控制:記錄每次反差行為觸發的時間,供冷卻期判定。
|
||
model ContrastTriggerLog {
|
||
id String @id @default(cuid())
|
||
characterId String
|
||
character Character @relation(fields: [characterId], references: [id], onDelete: Cascade)
|
||
triggeredAt DateTime @default(now())
|
||
|
||
@@map("contrast_trigger_logs")
|
||
}
|
||
|
||
// I-1 作息表:平日/週末/假期各一份時段表,每個時段一列。
|
||
model ScheduleSlot {
|
||
id String @id @default(cuid())
|
||
characterId String
|
||
character Character @relation(fields: [characterId], references: [id], onDelete: Cascade)
|
||
dayType ScheduleDayType
|
||
startMinute Int // 當天 00:00 起算的分鐘數(0~1440),跨午夜的時段請拆成兩列
|
||
endMinute Int
|
||
status ScheduleSlotStatus
|
||
label String? // 固定行程名稱,例如「社團活動」
|
||
|
||
@@map("schedule_slots")
|
||
}
|
||
|
||
// I-1 特殊日:考試週、生日、原作紀念日——當天整天視為 HOLIDAY 作息。
|
||
model SpecialDay {
|
||
id String @id @default(cuid())
|
||
characterId String
|
||
character Character @relation(fields: [characterId], references: [id], onDelete: Cascade)
|
||
date DateTime // 只使用日期部分(比對年/月/日)
|
||
label String
|
||
|
||
@@map("special_days")
|
||
}
|
||
|
||
// I-4 破例規則:記錄每種破例最後一次觸發的時間,供稀有度冷卻判定。
|
||
model ScheduleExceptionLog {
|
||
id String @id @default(cuid())
|
||
characterId String
|
||
character Character @relation(fields: [characterId], references: [id], onDelete: Cascade)
|
||
exceptionType String // LATE_NIGHT_CHAT/SNEAK_REPLY_IN_CLASS/ADJUST_SCHEDULE
|
||
triggeredAt DateTime @default(now())
|
||
|
||
@@map("schedule_exception_logs")
|
||
}
|
||
|
||
model CharacterAlias {
|
||
id String @id @default(cuid())
|
||
characterId String
|
||
character Character @relation(fields: [characterId], references: [id], onDelete: Cascade)
|
||
formalName String // 正式名
|
||
nickname String? // 暱稱
|
||
calledByOthers String? // 他人稱呼(作品中其他角色如何稱呼)
|
||
createdAt DateTime @default(now())
|
||
|
||
@@map("character_aliases")
|
||
}
|
||
|
||
model EpisodicMemory {
|
||
id String @id @default(cuid())
|
||
characterId String
|
||
character Character @relation(fields: [characterId], references: [id], onDelete: Cascade)
|
||
content String
|
||
occurredAt DateTime // 發生時間
|
||
emotionTag EmotionTag
|
||
emotionIntensity Float // 情緒強度
|
||
retrievalCount Int @default(0) // 提取次數
|
||
lastRetrievedAt DateTime?
|
||
source MemorySource
|
||
weight Float @default(1) // 權重(供遺忘/檢索排序使用)
|
||
relatedUserId String? // 這段記憶與哪位使用者相關(E-5 關係加權檢索用)
|
||
relatedUser User? @relation(fields: [relatedUserId], references: [id], onDelete: SetNull)
|
||
createdAt DateTime @default(now())
|
||
|
||
@@map("episodic_memories")
|
||
}
|
||
|
||
model SemanticMemory {
|
||
id String @id @default(cuid())
|
||
characterId String
|
||
character Character @relation(fields: [characterId], references: [id], onDelete: Cascade)
|
||
fact String // 去情境化事實
|
||
about String // 對象(關於誰/什麼)
|
||
createdAt DateTime @default(now())
|
||
|
||
@@map("semantic_memories")
|
||
}
|
||
|
||
model ProceduralRule {
|
||
id String @id @default(cuid())
|
||
characterId String
|
||
character Character @relation(fields: [characterId], references: [id], onDelete: Cascade)
|
||
situation String // 情境
|
||
responsePattern String // 回應模式
|
||
weight Float @default(1)
|
||
createdAt DateTime @default(now())
|
||
updatedAt DateTime @updatedAt
|
||
|
||
@@map("procedural_rules")
|
||
}
|
||
|
||
model EmotionState {
|
||
id String @id @default(cuid())
|
||
characterId String @unique
|
||
character Character @relation(fields: [characterId], references: [id], onDelete: Cascade)
|
||
|
||
calm Float @default(100) // 平靜
|
||
joy Float @default(0) // 愉悅
|
||
sad Float @default(0) // 低落
|
||
alert Float @default(0) // 警戒
|
||
shy Float @default(0) // 害羞
|
||
grumpy Float @default(0) // 彆扭
|
||
|
||
updatedAt DateTime @updatedAt
|
||
|
||
@@map("emotion_states")
|
||
}
|
||
|
||
model Relationship {
|
||
id String @id @default(cuid())
|
||
characterId String
|
||
character Character @relation(fields: [characterId], references: [id], onDelete: Cascade)
|
||
userId String
|
||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||
|
||
intimacy Int @default(0) // 親密度 0~100
|
||
trust Int @default(0) // 信任度 0~100
|
||
firstMet DateTime?
|
||
lastInteraction DateTime?
|
||
interactionCount Int @default(0)
|
||
stage RelationshipStage @default(STRANGER)
|
||
|
||
ledgerEntries SentimentLedgerEntry[]
|
||
|
||
createdAt DateTime @default(now())
|
||
updatedAt DateTime @updatedAt
|
||
|
||
@@unique([characterId, userId])
|
||
@@map("relationships")
|
||
}
|
||
|
||
model SentimentLedgerEntry {
|
||
id String @id @default(cuid())
|
||
relationshipId String
|
||
relationship Relationship @relation(fields: [relationshipId], references: [id], onDelete: Cascade)
|
||
date DateTime
|
||
event String
|
||
weight Float // 允許正負:正向事件為正值,負向事件為負值
|
||
createdAt DateTime @default(now())
|
||
|
||
@@map("sentiment_ledger_entries")
|
||
}
|