Files
ai-novel-studio/shared/types/index.ts
T
jocay 3c9b65d982 AI 小说工坊:主编 + 作家多模型协作写作应用
- Nuxt 4 + Nuxt UI 4 + AI SDK 7 + Drizzle/SQLite
- 主编规划大纲与章节简报、选派作家;作家流式写入章节文件并实时推送前端
- 逐章确认模式(默认)与自动模式;摘要与故事记忆
- 酒馆角色卡(PNG/JSON,V1-V3)与世界书导入
- 自定义最高优先级系统提示词、审稿/修改/多版本、任务日志与提示词检视
- 模拟 LLM 服务与端到端测试脚本

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 02:04:40 +08:00

169 lines
4.5 KiB
TypeScript

export type ProviderType = 'openai-compatible' | 'anthropic' | 'google'
export type AgentRole = 'editor' | 'writer' | 'summarizer'
/**
* 章节状态流转:
* planned(大纲已规划)→ briefed(主编已写简报)→ writing(作家写作中)
* → written(等待用户确认)→ approved(已确认,摘要已入库)
*/
export type ChapterStatus = 'planned' | 'briefed' | 'writing' | 'written' | 'approved'
export type VersionStatus = 'writing' | 'done' | 'error' | 'cancelled'
export type JobType = 'outline' | 'brief' | 'write' | 'summarize' | 'review' | 'pipeline'
export type JobStatus = 'running' | 'done' | 'error' | 'cancelled'
export type LoreEntrySource = 'user' | 'card'
export interface ProjectRequirements {
/** 文风,如:细腻、冷峻、轻松幽默 */
style: string
/** 输出语言 */
language: string
/** 叙事视角:第一人称 / 第三人称有限 / 全知 */
pov: string
/** 叙述方式补充:时态、节奏、对白比例等 */
narration: string
/** 每章目标字数 */
wordsPerChapter: number
/** 其他要求(禁用词、尺度等) */
extra: string
}
export interface ProjectSettings {
/** 自动模式:章节写完后自动确认并继续下一章 */
autoMode: boolean
/** 主编写完简报后暂停,等用户确认简报 */
pauseAfterBrief: boolean
/** 允许主编自行创建作家 */
allowEditorCreateWriters: boolean
/** 注入给作家的上一章结尾字数 */
prevTailChars: number
/** 注入的最近章节摘要数量 */
recentSummaryCount: number
/** 输出被截断时自动续写的最大次数 */
maxContinuations: number
/** 自动模式下最多连续写作的章节数(防止失控) */
autoChapterLimit: number
}
export interface CharacterState {
name: string
state: string
}
export interface Foreshadowing {
text: string
status: 'open' | 'resolved'
chapter: number
resolvedChapter?: number
}
export interface ProjectMemory {
characterStates: CharacterState[]
foreshadowing: Foreshadowing[]
timeline: { chapter: number, event: string }[]
}
export const DEFAULT_REQUIREMENTS: ProjectRequirements = {
style: '',
language: '简体中文',
pov: '第三人称有限视角',
narration: '',
wordsPerChapter: 3000,
extra: ''
}
export const DEFAULT_SETTINGS: ProjectSettings = {
autoMode: false,
pauseAfterBrief: false,
allowEditorCreateWriters: true,
prevTailChars: 1500,
recentSummaryCount: 5,
maxContinuations: 2,
autoChapterLimit: 10
}
export const EMPTY_MEMORY: ProjectMemory = {
characterStates: [],
foreshadowing: [],
timeline: []
}
export const CHAPTER_STATUS_LABEL: Record<ChapterStatus, string> = {
planned: '已规划',
briefed: '已出简报',
writing: '写作中',
written: '待确认',
approved: '已确认'
}
export const CHAPTER_STATUS_COLOR: Record<ChapterStatus, 'neutral' | 'info' | 'warning' | 'primary' | 'success'> = {
planned: 'neutral',
briefed: 'info',
writing: 'warning',
written: 'primary',
approved: 'success'
}
export const ROLE_LABEL: Record<AgentRole, string> = {
editor: '主编',
writer: '作家',
summarizer: '摘要员'
}
export const JOB_TYPE_LABEL: Record<JobType, string> = {
outline: '规划大纲',
brief: '章节简报',
write: '写作',
summarize: '摘要',
review: '审稿',
pipeline: '流水线'
}
/** 解析后的酒馆角色卡(统一为内部结构) */
export interface ParsedCard {
spec: 'v1' | 'v2' | 'v3'
name: string
description: string
personality: string
scenario: string
firstMes: string
mesExample: string
systemPrompt: string
postHistoryInstructions: string
creatorNotes: string
alternateGreetings: string[]
tags: string[]
world: string
lore: { title: string, keys: string[], content: string, constant: boolean, enabled: boolean, order: number }[]
raw: Record<string, unknown>
}
/** 服务端推送给前端的事件 */
export type ProjectEvent =
| { type: 'job', job: JobInfo }
| { type: 'delta', chapterId: string, versionId: string, text: string }
| { type: 'chapter', chapterId: string }
| { type: 'chapters' }
| { type: 'agents' }
| { type: 'pipeline', running: boolean, message?: string }
| { type: 'log', level: 'info' | 'warn' | 'error', message: string }
export interface JobInfo {
id: string
type: JobType
status: JobStatus
chapterId: string | null
agentName: string
modelLabel: string
inputTokens: number
outputTokens: number
error: string
log: string
createdAt: string | number | Date
finishedAt: string | number | Date | null
}