249 lines
7.6 KiB
Python
249 lines
7.6 KiB
Python
"""
|
|
正则规则 API 路由
|
|
|
|
提供正则规则的 CRUD 操作和导入导出功能
|
|
"""
|
|
from fastapi import APIRouter, HTTPException, UploadFile, File
|
|
from pydantic import BaseModel
|
|
from typing import List, Optional
|
|
import json
|
|
import logging
|
|
|
|
from services.regex_service import regex_service
|
|
from models.regex_rules import RegexRule, RegexRuleset, RegexScope
|
|
from services.system_settings_service import system_settings_service
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
router = APIRouter(prefix="/api/regex", tags=["regex"])
|
|
|
|
|
|
# ==================== 数据模型 ====================
|
|
|
|
class RuleUpdateRequest(BaseModel):
|
|
"""规则更新请求"""
|
|
rule: RegexRule
|
|
scope: RegexScope
|
|
name: Optional[str] = None # 角色卡名称或预设名称(scope 为 CHARACTER/PRESET 时需要)
|
|
|
|
|
|
class SystemSettingsUpdate(BaseModel):
|
|
"""系统设置更新请求"""
|
|
thinkingTagPrefix: Optional[str] = None
|
|
thinkingTagSuffix: Optional[str] = None
|
|
currentPresetName: Optional[str] = None
|
|
|
|
|
|
# ==================== 规则查询 ====================
|
|
|
|
@router.get("/rules")
|
|
async def get_rules(
|
|
character_name: Optional[str] = None,
|
|
preset_name: Optional[str] = None
|
|
):
|
|
"""
|
|
获取适用的正则规则列表
|
|
|
|
Args:
|
|
character_name: 当前角色卡名称(可选)
|
|
preset_name: 当前预设名称(可选)
|
|
|
|
Returns:
|
|
规则列表
|
|
"""
|
|
try:
|
|
rules = regex_service.get_rules_for_context(character_name, preset_name)
|
|
return {
|
|
"success": True,
|
|
"rules": [rule.dict() for rule in rules],
|
|
"count": len(rules)
|
|
}
|
|
except Exception as e:
|
|
logger.error(f"获取规则失败: {e}")
|
|
raise HTTPException(status_code=500, detail=str(e))
|
|
|
|
|
|
@router.get("/rulesets/global")
|
|
async def get_global_rulesets():
|
|
"""获取所有全局规则集"""
|
|
try:
|
|
rulesets = list(regex_service.global_rulesets.values())
|
|
return {
|
|
"success": True,
|
|
"rulesets": [rs.dict() for rs in rulesets]
|
|
}
|
|
except Exception as e:
|
|
logger.error(f"获取全局规则集失败: {e}")
|
|
raise HTTPException(status_code=500, detail=str(e))
|
|
|
|
|
|
@router.get("/rulesets/character/{character_name}")
|
|
async def get_character_ruleset(character_name: str):
|
|
"""获取指定角色卡的规则集"""
|
|
try:
|
|
if character_name in regex_service.character_rulesets:
|
|
ruleset = regex_service.character_rulesets[character_name]
|
|
return {
|
|
"success": True,
|
|
"ruleset": ruleset.dict()
|
|
}
|
|
else:
|
|
return {
|
|
"success": True,
|
|
"ruleset": None
|
|
}
|
|
except Exception as e:
|
|
logger.error(f"获取角色规则集失败: {e}")
|
|
raise HTTPException(status_code=500, detail=str(e))
|
|
|
|
|
|
@router.get("/rulesets/preset/{preset_name}")
|
|
async def get_preset_ruleset(preset_name: str):
|
|
"""获取指定预设的规则集"""
|
|
try:
|
|
if preset_name in regex_service.preset_rulesets:
|
|
ruleset = regex_service.preset_rulesets[preset_name]
|
|
return {
|
|
"success": True,
|
|
"ruleset": ruleset.dict()
|
|
}
|
|
else:
|
|
return {
|
|
"success": True,
|
|
"ruleset": None
|
|
}
|
|
except Exception as e:
|
|
logger.error(f"获取预设规则集失败: {e}")
|
|
raise HTTPException(status_code=500, detail=str(e))
|
|
|
|
|
|
# ==================== 规则管理 ====================
|
|
|
|
@router.post("/rules")
|
|
async def add_rule(request: RuleUpdateRequest):
|
|
"""添加新规则"""
|
|
try:
|
|
regex_service.save_ruleset(
|
|
RegexRuleset(
|
|
id=request.rule.id,
|
|
name=request.rule.scriptName,
|
|
rules=[request.rule]
|
|
),
|
|
request.scope,
|
|
request.name
|
|
)
|
|
|
|
# 重新加载规则
|
|
regex_service._load_all_rules()
|
|
|
|
return {
|
|
"success": True,
|
|
"message": "规则添加成功"
|
|
}
|
|
except Exception as e:
|
|
logger.error(f"添加规则失败: {e}")
|
|
raise HTTPException(status_code=500, detail=str(e))
|
|
|
|
|
|
@router.delete("/rules/{rule_id}")
|
|
async def delete_rule(rule_id: str):
|
|
"""删除规则(需要指定作用域和名称)"""
|
|
# TODO: 实现具体的删除逻辑
|
|
return {
|
|
"success": False,
|
|
"message": "暂未实现,请使用规则集级别的删除"
|
|
}
|
|
|
|
|
|
# ==================== 规则导入导出 ====================
|
|
|
|
@router.post("/import")
|
|
async def import_rules(file: UploadFile = File(...)):
|
|
"""
|
|
导入正则规则(支持 SillyTavern 格式)
|
|
|
|
可以导入:
|
|
1. 单个规则文件(JSON 数组)
|
|
2. 规则集文件(JSON 对象)
|
|
"""
|
|
try:
|
|
content = await file.read()
|
|
data = json.loads(content.decode('utf-8'))
|
|
|
|
# 判断格式并导入
|
|
if isinstance(data, list):
|
|
# SillyTavern 格式 - 导入为全局规则
|
|
ruleset = regex_service._convert_sillytavern_format(data, file.filename.replace('.json', ''))
|
|
regex_service.save_ruleset(ruleset, RegexScope.GLOBAL)
|
|
elif isinstance(data, dict):
|
|
if 'rules' in data:
|
|
# 规则集格式
|
|
ruleset = RegexRuleset(**data)
|
|
regex_service.save_ruleset(ruleset, RegexScope.GLOBAL)
|
|
else:
|
|
raise ValueError("未知的文件格式")
|
|
else:
|
|
raise ValueError("无效的文件格式")
|
|
|
|
# 重新加载规则
|
|
regex_service._load_all_rules()
|
|
|
|
return {
|
|
"success": True,
|
|
"message": f"成功导入规则集: {ruleset.name}"
|
|
}
|
|
except Exception as e:
|
|
logger.error(f"导入规则失败: {e}")
|
|
raise HTTPException(status_code=500, detail=str(e))
|
|
|
|
|
|
@router.get("/export/global")
|
|
async def export_global_rules():
|
|
"""导出所有全局规则"""
|
|
try:
|
|
all_rulesets = list(regex_service.global_rulesets.values())
|
|
return {
|
|
"success": True,
|
|
"rulesets": [rs.dict() for rs in all_rulesets]
|
|
}
|
|
except Exception as e:
|
|
logger.error(f"导出规则失败: {e}")
|
|
raise HTTPException(status_code=500, detail=str(e))
|
|
|
|
|
|
# ==================== 系统设置 ====================
|
|
|
|
@router.get("/settings")
|
|
async def get_system_settings():
|
|
"""获取系统设置"""
|
|
try:
|
|
settings = system_settings_service.settings
|
|
return {
|
|
"success": True,
|
|
"settings": settings.dict()
|
|
}
|
|
except Exception as e:
|
|
logger.error(f"获取系统设置失败: {e}")
|
|
raise HTTPException(status_code=500, detail=str(e))
|
|
|
|
|
|
@router.put("/settings")
|
|
async def update_system_settings(request: SystemSettingsUpdate):
|
|
"""更新系统设置"""
|
|
try:
|
|
if request.thinkingTagPrefix is not None or request.thinkingTagSuffix is not None:
|
|
prefix = request.thinkingTagPrefix or system_settings_service.settings.thinkingTagPrefix
|
|
suffix = request.thinkingTagSuffix or system_settings_service.settings.thinkingTagSuffix
|
|
system_settings_service.update_thinking_tags(prefix, suffix)
|
|
|
|
if request.currentPresetName is not None:
|
|
system_settings_service.update_current_preset(request.currentPresetName)
|
|
|
|
return {
|
|
"success": True,
|
|
"message": "系统设置已更新"
|
|
}
|
|
except Exception as e:
|
|
logger.error(f"更新系统设置失败: {e}")
|
|
raise HTTPException(status_code=500, detail=str(e))
|