All checks were successful
Deploy Noval to K3s / deploy (push) Successful in 47s
- **文件管理**: - 支持文件上传、解析和删除。 - 限制支持格式(txt, md, docx, pdf),最大 10MB。 - 提供前端上传区、文件列表及后端解析服务。 - **技能管理**: - 新增技能的创建、更新及删除功能。 - 支持分配自定义提示词和工具权限。 - 提供技能列表及分组工具选择交互界面。 同时调整相关 API 和前端组件,优化协作体验。
263 lines
5.6 KiB
Python
263 lines
5.6 KiB
Python
from __future__ import annotations
|
||
|
||
from datetime import datetime
|
||
|
||
from pydantic import BaseModel, Field
|
||
|
||
|
||
class NovelCreate(BaseModel):
|
||
title: str = Field(min_length=1, max_length=200)
|
||
description: str = Field(default="", max_length=2000)
|
||
|
||
|
||
class NovelUpdate(BaseModel):
|
||
title: str | None = Field(default=None, min_length=1, max_length=200)
|
||
description: str | None = Field(default=None, max_length=2000)
|
||
|
||
|
||
class NovelRead(BaseModel):
|
||
id: int
|
||
title: str
|
||
description: str
|
||
created_at: datetime
|
||
updated_at: datetime
|
||
|
||
|
||
class NovelList(BaseModel):
|
||
items: list[NovelRead]
|
||
total: int
|
||
|
||
|
||
# ── 大纲 ──
|
||
|
||
|
||
class OutlineCreate(BaseModel):
|
||
summary: str = Field(min_length=1, max_length=200)
|
||
detail: str = Field(default="", max_length=1000)
|
||
parent_id: int | None = None
|
||
|
||
|
||
class OutlineUpdate(BaseModel):
|
||
summary: str | None = Field(default=None, min_length=1, max_length=200)
|
||
detail: str | None = Field(default=None, max_length=1000)
|
||
sort_order: int | None = None
|
||
|
||
|
||
class OutlineRead(BaseModel):
|
||
id: int
|
||
novel_id: int
|
||
parent_id: int | None = None
|
||
sort_order: int
|
||
summary: str
|
||
detail: str
|
||
children: list[OutlineRead] = []
|
||
created_at: datetime
|
||
updated_at: datetime
|
||
|
||
|
||
class OutlineList(BaseModel):
|
||
items: list[OutlineRead]
|
||
total: int
|
||
|
||
|
||
class OutlineReorder(BaseModel):
|
||
"""排序请求:按顺序传入大纲id列表"""
|
||
ordered_ids: list[int]
|
||
|
||
|
||
# ── 角色 ──
|
||
|
||
|
||
class CharacterCreate(BaseModel):
|
||
name: str = Field(min_length=1, max_length=100)
|
||
description: str = Field(default="", max_length=1000)
|
||
|
||
|
||
class CharacterUpdate(BaseModel):
|
||
name: str | None = Field(default=None, min_length=1, max_length=100)
|
||
description: str | None = Field(default=None, max_length=1000)
|
||
|
||
|
||
class CharacterRead(BaseModel):
|
||
id: int
|
||
novel_id: int
|
||
name: str
|
||
description: str
|
||
created_at: datetime
|
||
updated_at: datetime
|
||
|
||
|
||
class CharacterList(BaseModel):
|
||
items: list[CharacterRead]
|
||
total: int
|
||
|
||
|
||
# ── 章节 ──
|
||
|
||
|
||
class ChapterCreate(BaseModel):
|
||
title: str = Field(min_length=1, max_length=200)
|
||
content: str = Field(default="", max_length=5000)
|
||
|
||
|
||
class ChapterUpdate(BaseModel):
|
||
title: str | None = Field(default=None, min_length=1, max_length=200)
|
||
content: str | None = Field(default=None, max_length=5000)
|
||
sort_order: int | None = None
|
||
|
||
|
||
class ChapterRead(BaseModel):
|
||
id: int
|
||
novel_id: int
|
||
sort_order: int
|
||
title: str
|
||
content: str
|
||
created_at: datetime
|
||
updated_at: datetime
|
||
|
||
|
||
class ChapterList(BaseModel):
|
||
items: list[ChapterRead]
|
||
total: int
|
||
|
||
|
||
class ChapterReorder(BaseModel):
|
||
"""排序请求:按顺序传入章节id列表"""
|
||
ordered_ids: list[int]
|
||
|
||
|
||
# ── 世界观 ──
|
||
|
||
|
||
class WorldSettingUpdate(BaseModel):
|
||
content: str = Field(default="", max_length=5000)
|
||
|
||
|
||
class WorldSettingRead(BaseModel):
|
||
id: int
|
||
novel_id: int
|
||
content: str
|
||
created_at: datetime
|
||
updated_at: datetime
|
||
|
||
|
||
# ── 文件 ──
|
||
|
||
|
||
class FileRead(BaseModel):
|
||
id: int
|
||
novel_id: int
|
||
filename: str
|
||
file_size: int
|
||
mime_type: str
|
||
text_length: int
|
||
created_at: datetime
|
||
|
||
|
||
class FileList(BaseModel):
|
||
items: list[FileRead]
|
||
total: int
|
||
|
||
|
||
# ── Skill ──
|
||
|
||
|
||
class SkillCreate(BaseModel):
|
||
name: str = Field(min_length=1, max_length=100)
|
||
description: str = Field(default="", max_length=500)
|
||
system_prompt: str = Field(default="", max_length=10000)
|
||
allowed_tools: list[str] = Field(default_factory=list)
|
||
novel_id: int | None = None
|
||
|
||
|
||
class SkillUpdate(BaseModel):
|
||
name: str | None = Field(default=None, min_length=1, max_length=100)
|
||
description: str | None = Field(default=None, max_length=500)
|
||
system_prompt: str | None = Field(default=None, max_length=10000)
|
||
allowed_tools: list[str] | None = None
|
||
|
||
|
||
class SkillRead(BaseModel):
|
||
id: int
|
||
name: str
|
||
description: str
|
||
system_prompt: str
|
||
allowed_tools: list[str]
|
||
is_builtin: bool
|
||
novel_id: int | None
|
||
created_at: datetime
|
||
updated_at: datetime
|
||
|
||
|
||
class SkillList(BaseModel):
|
||
items: list[SkillRead]
|
||
total: int
|
||
|
||
|
||
class ToolInfo(BaseModel):
|
||
name: str
|
||
description: str
|
||
|
||
|
||
# ── AI配置 ──
|
||
|
||
|
||
class AIConfigSave(BaseModel):
|
||
provider: str = Field(default="openai")
|
||
base_url: str = Field(default="https://api.openai.com/v1")
|
||
api_key: str = Field(min_length=1)
|
||
model: str = Field(default="gpt-4o")
|
||
|
||
|
||
class AIConfigRead(BaseModel):
|
||
id: int
|
||
provider: str
|
||
base_url: str
|
||
api_key_masked: str # 脱敏后的key
|
||
model: str
|
||
updated_at: datetime
|
||
|
||
|
||
# ── 聊天 ──
|
||
|
||
|
||
class ChatMessageInput(BaseModel):
|
||
role: str
|
||
content: str
|
||
|
||
|
||
class PendingToolCall(BaseModel):
|
||
"""待审批的工具调用"""
|
||
id: str
|
||
name: str
|
||
arguments: dict
|
||
|
||
|
||
class ChatRequest(BaseModel):
|
||
messages: list[ChatMessageInput]
|
||
novel_id: int | None = None
|
||
page_context: str | None = None # 用户当前所在页面,如 "大纲页" "世界观页"
|
||
tools_enabled: bool = True # 是否启用工具调用
|
||
auto_approve_tools: bool = False # 是否自动执行工具(无需人工审批)
|
||
skill_id: int | None = None # 激活的 Skill ID
|
||
# 工具审批续传
|
||
pending_tool_calls: list[PendingToolCall] | None = None
|
||
assistant_text: str | None = None # LLM 在工具调用前输出的文本
|
||
|
||
|
||
class ChatMessageRead(BaseModel):
|
||
id: int
|
||
novel_id: int | None
|
||
role: str
|
||
content: str
|
||
created_at: datetime
|
||
|
||
|
||
class ChatMessageList(BaseModel):
|
||
items: list[ChatMessageRead]
|
||
total: int
|
||
|
||
|
||
# 解决 OutlineRead 自引用
|
||
OutlineRead.model_rebuild()
|