完成请求推送,但组装mes还有问题

This commit is contained in:
2026-05-04 00:33:29 +08:00
parent 7fc9e10c99
commit 2050a30a52
93 changed files with 9499 additions and 2719 deletions

View File

@@ -141,7 +141,14 @@ class CharacterCard(BaseModel):
outputSchema: Optional[List[OutputSchemaField]] = Field(None, description="输出 schema 定义 (结构化输出)")
avatarPath: Optional[str] = Field(None, description="角色头像路径")
alternate_greetings: Optional[List[str]] = Field(None, description="替代问候语数组")
tags: Optional[List[str]] = Field(None, description="标签数组")
# TODO: 拓展提示词设置(插件/拓展系统预留接口)
# - tableMaintenancePrompt: 用于指导 AI 维护动态表格RPG状态、任务追踪等
# - imageGenerationPrompt: 用于指导 AI 生成图片描述提示词
# 当前状态:字段已定义,默认值为 None等待插件系统实现
tableMaintenancePrompt: Optional[str] = Field(None, description="动态表格维护提示词 - 指导 AI 如何更新表格数据")
imageGenerationPrompt: Optional[str] = Field(None, description="生图提示词模板 - 指导 AI 如何生成图片描述")
createdAt: int = Field(default_factory=lambda: int(datetime.now().timestamp()), description="创建时间戳")
updatedAt: int = Field(default_factory=lambda: int(datetime.now().timestamp()), description="最后更新时间戳")
lastChatAt: Optional[int] = Field(None, description="最后聊天时间戳")
@@ -300,3 +307,84 @@ class ChatRAGConfig(BaseModel):
indexConfig: Optional[Dict[str, Any]] = Field(None, description="索引配置")
createdAt: int = Field(default_factory=lambda: int(datetime.now().timestamp()), description="创建时间戳")
updatedAt: int = Field(default_factory=lambda: int(datetime.now().timestamp()), description="最后更新时间戳")
# ==================== Token 统计 ====================
class TokenUsageStatus(str, Enum):
"""Token 使用状态"""
COMPLETED = 'completed' # 成功完成
INTERRUPTED = 'interrupted' # 被用户中断
FAILED = 'failed' # 请求失败API错误等
class TokenUsageRecord(BaseModel):
"""
Token 使用记录
记录每次 LLM 调用的 token 使用情况,支持按时间、角色、聊天维度统计
"""
id: str = Field(..., description="记录唯一标识符 (UUID)")
chatId: str = Field(..., description="聊天ID (role_name/chat_name)")
roleName: str = Field(..., description="角色名称")
chatName: str = Field(..., description="聊天名称")
messageId: Optional[str] = Field(None, description="关联的消息ID")
floor: Optional[int] = Field(None, description="楼层号")
# Token 统计
promptTokens: int = Field(0, description="输入 token 数")
completionTokens: int = Field(0, description="输出 token 数")
totalTokens: int = Field(0, description="总 token 数")
# 状态信息
status: TokenUsageStatus = Field(TokenUsageStatus.COMPLETED, description="请求状态")
errorMessage: Optional[str] = Field(None, description="错误信息(如果失败)")
# 时间信息
timestamp: int = Field(default_factory=lambda: int(datetime.now().timestamp()), description="请求时间戳")
duration: Optional[float] = Field(None, description="请求耗时(秒)")
# API 信息
model: Optional[str] = Field(None, description="使用的模型")
apiProvider: Optional[str] = Field(None, description="API 提供商")
apiUrl: Optional[str] = Field(None, description="API URL地址")
# ==================== 图片元数据 ====================
class ImageMetadata(BaseModel):
"""
图片元数据
记录生成的图片信息,绑定到角色/聊天的特定楼层
"""
id: str = Field(..., description="图片唯一标识符 (UUID)")
chatId: str = Field(..., description="聊天ID (role_name/chat_name)")
roleName: str = Field(..., description="角色名称")
chatName: str = Field(..., description="聊天名称")
floor: int = Field(..., description="楼层号")
# 图片信息
filename: str = Field(..., description="文件名")
filepath: str = Field(..., description="文件相对路径")
width: Optional[int] = Field(None, description="图片宽度")
height: Optional[int] = Field(None, description="图片高度")
fileSize: Optional[int] = Field(None, description="文件大小(字节)")
# Swipe 支持
swipeIndex: int = Field(0, description="Swipe 索引(同一楼层多张图片)")
isCurrentSwipe: bool = Field(True, description="是否为当前显示的 swipe")
# 生成信息
prompt: Optional[str] = Field(None, description="生成使用的提示词")
negativePrompt: Optional[str] = Field(None, description="负面提示词")
seed: Optional[int] = Field(None, description="随机种子")
model: Optional[str] = Field(None, description="使用的模型/checkpoint")
workflowName: Optional[str] = Field(None, description="使用的工作流名称")
# 任务信息
taskId: Optional[str] = Field(None, description="关联的任务ID")
generationTime: Optional[float] = Field(None, description="生成耗时(秒)")
# 时间信息
createdAt: int = Field(default_factory=lambda: int(datetime.now().timestamp()), description="创建时间戳")

View File

@@ -0,0 +1,164 @@
"""
正则替换规则模型
兼容 SillyTavern 的正则系统,支持全局、角色卡、预设三种作用域。
"""
from enum import Enum
from typing import List, Optional, Dict, Any
from pydantic import BaseModel, Field
from datetime import datetime
class RegexPlacement(int, Enum):
"""
正则应用位置(对应 SillyTavern 的 placement 数组)
0: System Prompt - 系统提示词
1: User Input - 用户输入
2: AI Output - AI 输出
3: Quick Reply - 快捷回复
4: World Info - 世界书信息
5: Reasoning/Thinking - 推理/思考内容
"""
SYSTEM_PROMPT = 0
USER_INPUT = 1
AI_OUTPUT = 2
QUICK_REPLY = 3
WORLD_INFO = 4
REASONING = 5
class RegexScope(str, Enum):
"""
正则规则作用域
- GLOBAL: 全局生效,对所有聊天应用
- CHARACTER: 绑定到特定角色卡
- PRESET: 绑定到特定预设
"""
GLOBAL = 'global'
CHARACTER = 'character'
PRESET = 'preset'
class SubstituteMode(int, Enum):
"""
替换模式
对应 SillyTavern 的 substituteRegex 字段
"""
REPLACE_ALL = 0 # 替换所有匹配
REPLACE_FIRST = 1 # 仅替换首次匹配
REPLACE_CAPTURED = 2 # 替换捕获组
class RegexRule(BaseModel):
"""
单条正则替换规则
完全兼容 SillyTavern 的正则规则格式
"""
id: str = Field(..., description="规则唯一标识符 (UUID)")
scriptName: str = Field(..., description="脚本名称(用于显示)")
# 核心正则配置
findRegex: str = Field(..., description="查找正则表达式(如:/<thinking>[\\s\\S]*?<\\/thinking>/gi")
replaceString: str = Field("", description="替换字符串(支持捕获组引用 $1, $2 等)")
trimStrings: List[str] = Field(default_factory=list, description="要额外修剪的字符串数组")
# 应用位置(关键!对应 SillyTavern 的 placement 数组)
placement: List[RegexPlacement] = Field(
default_factory=lambda: [RegexPlacement.AI_OUTPUT],
description="应用位置数组0=系统提示词, 1=用户输入, 2=AI输出, 3=快捷回复, 4=世界书, 5=推理内容"
)
# 替换模式
substituteRegex: SubstituteMode = Field(
SubstituteMode.REPLACE_ALL,
description="替换模式0=全部1=首次2=捕获组"
)
# 作用范围控制
markdownOnly: bool = Field(False, description="是否仅应用于 Markdown 渲染后的内容")
promptOnly: bool = Field(False, description="是否仅应用于发送给 LLM 的提示词")
runOnEdit: bool = Field(True, description="用户编辑消息时是否重新应用")
# 消息深度控制
minDepth: int = Field(0, ge=0, description="最小消息深度(从最新消息开始计数)")
maxDepth: Optional[int] = Field(None, ge=0, description="最大消息深度None 表示无限制)")
# 作用域配置
scope: RegexScope = Field(RegexScope.GLOBAL, description="规则作用域")
characterName: Optional[str] = Field(None, description="绑定的角色卡名称scope=CHARACTER 时使用)")
presetName: Optional[str] = Field(None, description="绑定的预设名称scope=PRESET 时使用)")
# 启用状态
disabled: bool = Field(False, description="是否禁用此规则(与 enabled 相反,为了兼容 ST")
# 执行顺序
order: int = Field(0, description="执行顺序(数值越小越先执行)")
# 元数据
createdAt: int = Field(default_factory=lambda: int(datetime.now().timestamp()), description="创建时间戳")
updatedAt: int = Field(default_factory=lambda: int(datetime.now().timestamp()), description="最后更新时间戳")
description: Optional[str] = Field(None, description="规则描述(可选)")
class RegexRuleset(BaseModel):
"""
正则规则集
一组正则规则的集合,可以整体导入/导出,兼容 SillyTavern 格式
"""
id: str = Field(..., description="规则集唯一标识符 (UUID)")
name: str = Field(..., description="规则集名称")
description: Optional[str] = Field(None, description="规则集描述")
rules: List[RegexRule] = Field(default_factory=list, description="规则列表")
# 元数据
createdAt: int = Field(default_factory=lambda: int(datetime.now().timestamp()), description="创建时间戳")
updatedAt: int = Field(default_factory=lambda: int(datetime.now().timestamp()), description="最后更新时间戳")
version: int = Field(1, description="版本号(用于数据迁移)")
# SillyTavern 兼容性标记
isSillyTavernFormat: bool = Field(False, description="是否为 SillyTavern 导入格式")
# ==================== 使用示例 ====================
if __name__ == '__main__':
import json
# 创建一条规则
rule = RegexRule(
id="example-hide-thinking-001",
scriptName="隐藏思考标签",
findRegex=r"<thinking>[\s\S]*?<\/thinking>",
replaceString="",
trimStrings=[],
placement=[RegexPlacement.AI_OUTPUT],
substituteRegex=SubstituteMode.REPLACE_ALL,
markdownOnly=False,
promptOnly=False,
runOnEdit=True,
minDepth=0,
maxDepth=None,
scope=RegexScope.GLOBAL,
characterName=None,
presetName=None,
disabled=False,
order=1,
description="隐藏 AI 回复中的 <thinking> 标签及其内容"
)
# 创建规则集
ruleset = RegexRuleset(
id="ruleset-001",
name="默认正则规则集",
description="包含常用的文本处理规则",
rules=[rule]
)
# 导出为 JSON兼容 SillyTavern
print(json.dumps(ruleset.dict(), indent=2, ensure_ascii=False))

View File

@@ -0,0 +1,49 @@
"""
系统设置模型
包含全局配置,如思考标签前后缀等。
"""
from typing import Optional
from pydantic import BaseModel, Field
from datetime import datetime
class SystemSettings(BaseModel):
"""
系统全局设置
持久化存储到 data/system_settings.json
"""
# ==================== 思考标签配置 ====================
thinkingTagPrefix: str = Field(
"<thinking>",
description="思考标签前缀(默认:<thinking>"
)
thinkingTagSuffix: str = Field(
"</thinking>",
description="思考标签后缀(默认:</thinking>"
)
# ==================== 当前选中的预设 ====================
currentPresetName: Optional[str] = Field(
None,
description="当前选中的预设名称(用于确定全局正则的作用域)"
)
# ==================== 元数据 ====================
updatedAt: int = Field(
default_factory=lambda: int(datetime.now().timestamp()),
description="最后更新时间戳"
)
version: int = Field(1, description="版本号")
# ==================== 默认设置 ====================
DEFAULT_SYSTEM_SETTINGS = SystemSettings()
if __name__ == '__main__':
import json
print(json.dumps(DEFAULT_SYSTEM_SETTINGS.dict(), indent=2, ensure_ascii=False))