""" 正则替换规则模型 兼容 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="查找正则表达式(如:/[\\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: Optional[int] = Field(None, ge=0, description="最小消息深度(从最新消息开始计数,None 表示无限制)") 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"[\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 回复中的 标签及其内容" ) # 创建规则集 ruleset = RegexRuleset( id="ruleset-001", name="默认正则规则集", description="包含常用的文本处理规则", rules=[rule] ) # 导出为 JSON(兼容 SillyTavern) print(json.dumps(ruleset.dict(), indent=2, ensure_ascii=False))