数据模型

Narrator Android · Room 数据库 + 文件持久化双轨 · 5 大实体

Narrator 的数据存储采用 双轨制① 结构化数据Room(剧本 / AI 服务商 / 对话消息三表); ② 大纲 / 章节推演记录使用文件系统(每个剧本一套 outline/{scriptId}/ 目录树)。 数据层位于 com.carrots.narrator.model,由多个 Repository 仓库对外暴露。

1. 整体结构

model/ ├── AppDatabase.java # Room 单例(version 4) ├── Script.java # 剧本 POJO(UI 层使用,scripts.json 持久化) ├── TrashItem.java # 回收站项 ├── ScriptRepository.java # 剧本仓库(文件 scripts.json) ├── TrashRepository.java # 回收站仓库 ├── OutlineRepository.java # 大纲 / 分卷 / 章节仓库(文件) ├── ScriptCharRepository.java # 剧本角色仓库 ├── ScriptSettingsRepository.java # 剧本设置仓库 ├── GroupRepository.java # 分组仓库 ├── DialogueRepository.java # 对话历史仓库(Room + 文件) ├── AIProviderRepository.java # AI 服务商仓库(Room) ├── dao/ │ ├── ScriptDao.java │ ├── DialogueDao.java │ └── AIProviderDao.java └── entity/ ├── ScriptEntity.java # Room scripts 表 ├── DialogueEntity.java # Room dialogues 表 └── AIProviderEntity.java # Room ai_providers 表

2. Room 数据库

2.1 AppDatabase 单例

文件model/AppDatabase.java 数据库carrot_narrator.db 版本:4

@Database( entities = { ScriptEntity.class, AIProviderEntity.class, DialogueEntity.class }, version = 4, exportSchema = false ) public abstract class AppDatabase extends RoomDatabase { public abstract ScriptDao scriptDao(); public abstract AIProviderDao aiProviderDao(); public abstract DialogueDao dialogueDao(); public static synchronized AppDatabase getInstance(Context context) { // fallbackToDestructiveMigration():版本迁移失败时重建库 } }
⚠️ 迁移策略: fallbackToDestructiveMigration()——若 schema 变更未提供迁移路径,将丢弃旧库重建(开发期方便但生产需谨慎)。

2.2 scripts 表 — ScriptEntity

对应:Web types/script.ts ScriptItem

字段类型说明
idString(PK)主键
titleString标题
descriptionString描述
statusString"active" 进行中 / "draft" 草稿
scriptGroupString分组(悬疑 / 科幻 / 奇幻 等)
authorString作者
createdAtlong创建时间戳(毫秒)
📌 双轨说明: ScriptEntity 提供结构与 Room 通路;当前 UI 层(ScriptFragment)主要通过 ScriptRepositoryfilesDir/scripts.json)管理剧本,仓库内含 5 个预置示例剧本 (从 assets/default_scripts.json 加载)。Script POJO 充当 UI 数据载体。

2.3 ai_providers 表 — AIProviderEntity

对应:Web types/ai.ts AIProvider

字段类型说明
idString(PK)"openai" / "deepseek" / "custom_xxx"
nameString显示名称
apiUrlStringAPI 地址(https://api.openai.com/v1 等)
apiKeyStringBearer Token
modelNameString默认模型名(注入 chat/completions 的 model 字段)
timeoutSecondsint超时秒数
isDefaultboolean是否默认选中

2.4 dialogues 表 — DialogueEntity

对应:Web types/dialogue.ts DialogueMsg 索引@Index("scriptId")

字段类型说明
idlong(PK·自增)主键
scriptIdString所属剧本 / 会话标识(无外键约束,对话可独立于剧本存在)
labelString"M_001" / "M_002" ... 序列标签
roleStringdirector 导演 | narrator 旁白 | character 角色 | user 用户
senderString角色名称
contentString消息内容
reasoningContentString?AI 思考过程(如 deepseek-reasoner 的 reasoning_content
directiveString?导演指令 JSON(仅导演角色,其余为 null)
timestamplong消息时间戳(毫秒)

3. Script POJO

model/Script.java —— UI 层剧本载体,含两个构造:6 参(创建时间取 SimpleDateFormat.getDateInstance().format(now))与 7 参(从 JSON 反序列化时保留原始 createdAt)。

public class Script { private String id, title, desc, status, group, author, createdAt; // status: "active" | "draft" }

生成规则ScriptRepository.add(...) 用自增 nextId 生成 S_%05d 格式 ID 并置顶插入;getGrouped() 按 group 分组供 ScriptFragment 渲染。

4. 文件持久化大纲

文件model/OutlineRepository.java —— 基于文件系统分卷 / 章节存储,对应 Web 端大纲目录树。

{filesDir}/ ├── scripts.json ← 剧本列表索引 └── outline/{scriptId}/ ← 每个剧本一套目录 ├── outline.json ← 卷/章目录结构 ├── settings.json ← 设置(arrangement 等) ├── prompts.json ← 角色提示词(worldview 等) └── {volumeId}/ ← 每个分卷一个文件夹(用 ID 命名) └── {chapterId}.json ← 每章推演记录(messages + state)

4.1 outline.json 格式

{ "volumes": [ { "id": "Vol_0001", "name": "第一卷", "chapters": [ { "id": "Ch_0001", "name": "第一章" } ] } ] }

4.2 settings.json / prompts.json

// settings.json { "arrangement": "..." } // prompts.json — 世界观被 DeductionFragment 的 getWorldView() 读取 { "worldview": "..." }

4.3 章节推演记录 {chapterId}.json

每章独立 JSON 文件,保存该章的 messages 数组(对话流)与 state(推演状态),供 DeductionFragment 加载续演。

5. 其它仓库

仓库承载说明
TrashRepository回收站TrashItem 列表;ScriptRepository.remove(id) 会先移入此处(restore(...) 可恢复到列表首位)
ScriptCharRepository剧本角色scriptId 管理 CharData(性格 / 目标 / 关系 / 能力 / temperature / status)
ScriptSettingsRepository剧本设置剧本级配置项(演绎参数等)
GroupRepository分组分组命名 / 重命名(重命名时联动 ScriptRepository.renameGroup
DialogueRepository对话历史聚合跨剧本对话(Room dialogues 表 + 可选文件缓存)
AIProviderRepositoryAI 服务商封装 AIProviderDao,配合 AiService 使用

6. 演绎角色数据 CharData

DeductionFragment 内部角色数据结构(运行期聚合,非 Room 实体):

字段类型说明
id / name / avatarString标识 / 名号 / 头像
playerString"character" AI 角色自动生成 | "system" 人类角色等待输入
personality / goal / relationships / abilitiesString人格 / 目标 / 关系 / 能力(拼入角色 prompt)
temperaturedouble角色级采样温度,传入 AiService.sendChatStream(..., temperature, ...)
statusString在线 / 不在线 / 连线

7. 默认配置体系

util/Defaults.javares/values/defaults.xml 统一取值,模块通过 Defaults 取默认值,避免硬编码散落:

speechMode() // 发言模式 limitUnlimited() // 是否无限发言 customLimit() // 自定义发言上限 autoSave() // 自动保存策略 showNarrator() // 是否显示旁白 msgAction() // 消息动作 engineMode() // 引擎模式 defaultModel() // 默认模型 fontFamily() // 字体族 fontSize() // 字号