Files
SillyTavern_replica/backend/nodes/PresetAssemblyNode.py

232 lines
7.0 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
from typing import List, Dict, Any, Optional
from pydantic import BaseModel, Field
from backend.core.models.PromptList import AIDesignSpec
from backend.core.models.PromptComponent import PromptComponent
from enum import Enum
from enum import Enum
class SpecialIdentifier(str, Enum):
"""
特殊组件标识符枚举
定义所有提示词组件的类型及其在最终 Prompt 中的默认物理流向
顺序大致遵循:系统层 -> 角色层 -> 动态层 -> 历史层 -> 尾部指令
"""
WORLD_INFO_BEFORE = "worldInfoBefore"
"""前置世界书:通常用于全局设定(如物理法则),紧接在 Main Prompt 之后,拥有最高优先级"""
PERSONA_DESCRIPTION = "personaDescription"
"""用户设定:告诉 AI {{user}} 是谁,通常放在场景之后,完成“谁在对谁说话”的闭环"""
ENHANCE_DEFINITIONS = "enhanceDefinitions"
"""增强定义:通常是 "If you have more knowledge...",用于补充 AI 的知识库这里用rag获取"""
WORLD_INFO_AFTER = "worldInfoAfter"
"""后置世界书:通常用于特定场景规则,位于中间层底部,用于覆盖或补充前面的全局设定"""
CHAT_HISTORY = "chatHistory"
"""聊天历史:包含用户与 AI 的过往对话,占据提示词的下半部分"""
JAILBREAK = "jailbreak"
"""后置指令/注释也即d0层通常位于聊天记录之后、AI 生成之前,用于最后时刻的强调(如“不要重复”)"""
class PresetAssemblyNode(BaseModel):
"""预设组装节点类,负责根据组装指令动态组装提示词内容"""
# 输入数据
design_spec: AIDesignSpec = Field(
...,
description="AI设计规范包含组件库和组装顺序"
)
target_character_id: int = Field(
...,
description="目标角色ID用于选择对应的组装指令"
)
# 内部状态(不参与序列化)
_component_map: Dict[str, PromptComponent] = Field(
default_factory=dict,
description="组件标识符到组件对象的映射"
)
def __init__(self, **data):
"""初始化方法,构建组件映射"""
super().__init__(**data)
# 构建组件映射字典,提高查找效率
self._component_map = {
comp.identifier: comp
for comp in self.design_spec.prompts
}
def _process_special_component(self, component: PromptComponent) -> Optional[Dict[str, Any]]:
"""
处理特殊组件marker为True的组件
参数:
component: 要处理的组件
返回:
Optional[Dict[str, Any]]: 处理后的消息如果组件无法处理则返回None
"""
try:
# 尝试将标识符转换为枚举
special_id = SpecialIdentifier(component.identifier)
# 根据不同标识符执行不同处理逻辑
if special_id == SpecialIdentifier.CHAT_HISTORY:
return self._handle_chat_history(component)
elif special_id == SpecialIdentifier.WORLD_INFO_BEFORE:
return self._handle_world_info_before(component)
elif special_id == SpecialIdentifier.WORLD_INFO_AFTER:
return self._handle_world_info_after(component)
elif special_id == SpecialIdentifier.CHAR_DESCRIPTION:
return self._handle_char_description(component)
else:
# 未知特殊组件,使用默认处理
return self._process_regular_component(component)
except ValueError:
# 不是特殊标识符,使用默认处理
return self._process_regular_component(component)
def _process_special_component(self, component: PromptComponent) -> Optional[Dict[str, Any]]:
"""
处理特殊组件marker为True的组件
参数:
component: 要处理的组件
返回:
Optional[Dict[str, Any]]: 处理后的消息如果组件无法处理则返回None
"""
try:
# 尝试将标识符转换为枚举
special_id = SpecialIdentifier(component.identifier)
# 根据不同标识符执行不同处理逻辑
if special_id == SpecialIdentifier.CHAT_HISTORY:
return self._handle_chat_history(component)
elif special_id == SpecialIdentifier.WORLD_INFO_BEFORE:
return self._handle_world_info_before(component)
elif special_id == SpecialIdentifier.WORLD_INFO_AFTER:
return self._handle_world_info_after(component)
elif special_id == SpecialIdentifier.DIALOGUE_EXAMPLES:
return self._handle_dialogue_examples(component)
elif special_id == SpecialIdentifier.CHAR_DESCRIPTION:
return self._handle_char_description(component)
elif special_id == SpecialIdentifier.CHAR_PERSONALITY:
return self._handle_char_personality(component)
elif special_id == SpecialIdentifier.SCENARIO:
return self._handle_scenario(component)
elif special_id == SpecialIdentifier.PERSONA_DESCRIPTION:
return self._handle_persona_description(component)
else:
# 未知特殊组件,使用默认处理
return self._process_regular_component(component)
except ValueError:
# 不是特殊标识符,使用默认处理
return self._process_regular_component(component)
def _process_regular_component(self, component: PromptComponent) -> Dict[str, Any]:
"""
处理普通组件marker为False的组件
参数:
component: 要处理的组件
返回:
Dict[str, Any]: 处理后的消息
"""
# 角色映射表
role_map = {0: "system", 1: "user", 2: "assistant"}
# 构建消息
message = {
"role": role_map.get(component.role, "system"),
"content": component.content
}
# 添加系统提示词标记
if component.system_prompt:
message["system_prompt"] = True
return message
# 以下为特殊组件处理方法
def _handle_chat_history(self, component: PromptComponent) -> Dict[str, Any]:
"""
处理聊天历史组件
参数:
component: 聊天历史组件
返回:
Dict[str, Any]: 处理后的消息
"""
# 这里应该从外部获取实际的聊天历史
# 示例实现,实际需要根据业务逻辑调整
return {
"role": "system",
"content": "聊天历史内容...",
"marker": True,
"type": "chat_history"
}
def _handle_world_info_before(self, component: PromptComponent) -> Dict[str, Any]:
"""
处理前置世界信息组件
参数:
component: 世界信息组件
返回:
Dict[str, Any]: 处理后的消息
"""
# 这里应该从外部获取实际的世界信息
return {
"role": "system",
"content": "前置世界信息...",
"marker": True,
"type": "world_info_before"
}
def _handle_world_info_after(self, component: PromptComponent) -> Dict[str, Any]:
"""
处理后置世界信息组件
参数:
component: 世界信息组件
返回:
Dict[str, Any]: 处理后的消息
"""
# 这里应该从外部获取实际的世界信息
return {
"role": "system",
"content": "后置世界信息...",
"marker": True,
"type": "world_info_after"
}
def _handle_char_description(self, component: PromptComponent) -> Dict[str, Any]:
"""
处理角色描述组件
参数:
component: 角色描述组件
返回:
Dict[str, Any]: 处理后的消息
"""
# 这里应该从外部获取实际的角色描述
return {
"role": "system",
"content": "角色描述内容...",
"marker": True,
"type": "char_description"
}