Files
Kokorone/prisma/schema.prisma
T
JefferyandClaude Sonnet 5 6125d6e27f feat: 完成 K 群組 — 對話模式:群聊與角色自聊
群聊/自聊子系統(apps/api/src/room/):在場者名冊與共用場景記錄(純記憶體,
同 C-1 工作記憶的設計)、發言權分配(點名/話題相關度/性格基線/情緒/角色間
關係/發言冷卻與冷落累積算衝動值)、群聊矜持(重用 G-3 親密度分層模板、
下修有效親密度而非另建模板庫)、隱私邊界(EpisodicMemory.isPrivate +
KeywordMemoryRetriever.excludePrivate,天然呆為口風不緊例外)、群聊記憶
投影(各角色依自身視角固化,被虧的那位權重較高)、角色自聊(沿用發言權
機制、空轉偵測注入轉折或收尾、輪數硬上限、使用者插話切換群聊)。
新增 CharacterRelationship 表供角色間關係使用。

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-13 15:15:00 +08:00

356 lines
12 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// 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 // 空閒
}
// J-1 委託類型
enum TaskType {
ONE_TIME // 單次提醒
RECURRING // 週期提醒
CONDITIONAL // 條件提醒
QUERY_ORGANIZE // 查詢整理
TODO_TRACKING // 代辦追蹤
}
enum TaskStatus {
PENDING // 尚未觸發
TRIGGERED // 已觸發,等候使用者回應
COMPLETED // 已完成
FAILED // 執行失敗
CANCELLED // 已取消
}
model User {
id String @id @default(cuid())
name String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
relationships Relationship[]
relatedMemories EpisodicMemory[]
tasks Task[]
@@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[]
tasks Task[]
proactiveCareLogs ProactiveCareLog[]
relationshipsToOthers CharacterRelationship[] @relation("RelationshipFrom")
relationshipsFromOthers CharacterRelationship[] @relation("RelationshipTo")
@@map("characters")
}
// K-2/K-4 角色間關係:群聊中「角色間關係上場」與發言權分配的「與發言者的關係」都吃這張表。
// 有向邊(characterId 對 otherCharacterId 的觀感),故同作品兩角色互相的觀感可以不對稱。
model CharacterRelationship {
id String @id @default(cuid())
characterId String
character Character @relation("RelationshipFrom", fields: [characterId], references: [id], onDelete: Cascade)
otherCharacterId String
otherCharacter Character @relation("RelationshipTo", fields: [otherCharacterId], references: [id], onDelete: Cascade)
affinity Int @default(50) // 0~100,越高越要好;50 為中性
dynamic String? // 互動基調描述性標籤,例如 loyal-friend/rival/protective/crush
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@unique([characterId, otherCharacterId])
@@map("character_relationships")
}
// 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)
isPrivate Boolean @default(false) // K-3 隱私邊界:一對一聊過的私密內容,群聊中不主動洩漏(口風不緊原型除外)
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")
}
// J-1 委託:使用者請角色做的事。執行(觸發準時度)是引擎責任,演出(接案/觸發/追擊的台詞)是角色責任。
model Task {
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)
type TaskType
content String // 委託內容(去除時間片語後的純委託描述,例如「開會」)
rawText String // 使用者原始輸入,供回顧/記憶引用
triggerAt DateTime? // 單次提醒的觸發時間;週期提醒改用 cronExpression
cronExpression String? // 週期提醒(node-cron 表達式)
condition String? // 條件提醒的條件描述(MVP 為文字紀錄,不做真實環境條件監測)
status TaskStatus @default(PENDING)
triggeredAt DateTime? // 最近一次實際觸發的時間
triggerMessage String? // 最近一次觸發演出的訊息內容(供前端/測試輪詢)
overdueNudgeCount Int @default(0) // J-4 逾期追擊次數
lastNudgeAt DateTime?
completedAt DateTime?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@map("tasks")
}
// J-6 主動關照:記錄每次主動關心的觸發時間與內容,供稀有度節流與「不重複台詞」判定。
model ProactiveCareLog {
id String @id @default(cuid())
characterId String
character Character @relation(fields: [characterId], references: [id], onDelete: Cascade)
userId String
message String
triggeredAt DateTime @default(now())
@@map("proactive_care_logs")
}