后端预设、世界书部分补充
This commit is contained in:
15
backend/core/models/PromptComponent.py
Normal file
15
backend/core/models/PromptComponent.py
Normal file
@@ -0,0 +1,15 @@
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
|
||||
class PromptComponent(BaseModel):
|
||||
"""预设组件类,代表一个独立的提示词模块"""
|
||||
|
||||
identifier: str = Field(..., description="唯一标识符,用于引用和定位组件")
|
||||
name: str = Field(..., description="组件显示名称")
|
||||
content: str = Field("", description="组件内容文本")
|
||||
# 0:System,1:User,2:Assistant
|
||||
role: int = Field(0, description="角色身份(0:System,1:User,2:Assistant)")
|
||||
system_prompt: bool = Field(False, description="是否强制作为系统提示词处理")
|
||||
marker: bool = Field(False, description="是否为动态插入点占位符")
|
||||
|
||||
|
||||
52
backend/core/models/PromptList.py
Normal file
52
backend/core/models/PromptList.py
Normal file
@@ -0,0 +1,52 @@
|
||||
from pydantic import BaseModel, Field
|
||||
import PromptComponent
|
||||
from typing import List, Dict, Any
|
||||
|
||||
|
||||
class AIDesignSpec(BaseModel):
|
||||
"""AI设计规范类,包含模型生成的核心参数和动态结构配置"""
|
||||
|
||||
# [Base] 基础核心参数
|
||||
temperature: float = Field(1.0, description="生成温度,控制随机性(0-2)")
|
||||
frequency_penalty: float = Field(0.0, description="频率惩罚,降低重复token概率")
|
||||
presence_penalty: float = Field(0.0, description="存在惩罚,鼓励谈论新话题")
|
||||
top_p: float = Field(1.0, description="核采样,控制词汇选择范围")
|
||||
top_k: int = Field(0, description="随机采样范围,从概率最高的K个词中选择")
|
||||
top_a: float = Field(0.0, description="基于平方概率分布的采样")
|
||||
min_p: float = Field(0.0, description="最小概率阈值")
|
||||
repetition_penalty: float = Field(1.0, description="重复惩罚系数(1.0-1.2)")
|
||||
openai_max_context: int = Field(2048, description="上下文窗口大小(Token上限)")
|
||||
openai_max_tokens: int = Field(250, description="单次回复的最大长度")
|
||||
max_context_unlocked: bool = Field(False, description="是否允许超出限制的上下文")
|
||||
names_behavior: int = Field(0, description="名字处理行为(0=默认,1=始终包含,2=仅角色)")
|
||||
send_if_empty: str = Field("", description="用户发送空消息时自动填充的内容")
|
||||
impersonation_prompt: str = Field("", description="模仿模式下使用的提示词")
|
||||
new_chat_prompt: str = Field("", description="开启新聊天时自动发送的系统提示")
|
||||
new_group_chat_prompt: str = Field("", description="开启新群组聊天时的提示")
|
||||
new_example_chat_prompt: str = Field("", description="新示例聊天的提示")
|
||||
continue_nudge_prompt: str = Field("", description="续写功能触发的提示词")
|
||||
bias_preset_selected: str = Field("", description="选用的偏见预设")
|
||||
wi_format: str = Field("{0}", description="世界书条目的格式化字符串")
|
||||
scenario_format: str = Field("{{scenario}}", description="场景描述的格式化字符串")
|
||||
personality_format: str = Field("", description="角色性格的格式化字符串")
|
||||
group_nudge_prompt: str = Field("", description="群组聊天中提示AI仅以特定角色回复的提示词")
|
||||
stream_openai: bool = Field(True, description="是否使用流式输出")
|
||||
assistant_prefill: str = Field("", description="强制AI回复的开头内容")
|
||||
assistant_impersonation: str = Field("", description="模仿模式下强制AI回复的开头内容")
|
||||
use_sysprompt: bool = Field(True, description="是否强制将提示词注入系统层")
|
||||
squash_system_messages: bool = Field(False, description="是否压缩系统消息")
|
||||
media_inlining: bool = Field(False, description="是否内联媒体描述")
|
||||
continue_prefill: bool = Field(True, description="续写时是否预填充内容")
|
||||
continue_postfix: str = Field(" ", description="续写时添加的后缀")
|
||||
seed: int = Field(-1, description="随机种子(-1为随机)")
|
||||
n: int = Field(1, description="生成回复的数量")
|
||||
|
||||
# [Dynamic] 动态结构
|
||||
prompts: List[PromptComponent] = Field(
|
||||
default_factory=list,
|
||||
description="组件库,定义所有可用的积木块"
|
||||
)
|
||||
prompt_order: List[str] = Field(
|
||||
default_factory=list,
|
||||
description="组装说明书,定义构建最终提示词的顺序"
|
||||
)
|
||||
231
backend/nodes/PresetAssemblyNode.py
Normal file
231
backend/nodes/PresetAssemblyNode.py
Normal file
@@ -0,0 +1,231 @@
|
||||
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"
|
||||
}
|
||||
|
||||
0
frontend-react/src/Store/Slices/LeftTabsSlice.jsx
Normal file
0
frontend-react/src/Store/Slices/LeftTabsSlice.jsx
Normal file
@@ -3,6 +3,10 @@ import React from 'react';
|
||||
import './SideBarLeft.css';
|
||||
import { useSideBarLeftStore } from '../../Store/indexStore';
|
||||
import useSideBarRightStore from '../../Store/Slices/SideBarLeftSlice';
|
||||
import Gallery from './tab/Gallery';
|
||||
import ApiConfig from './tab/ApiConfig';
|
||||
import Presets from './tab/Presets';
|
||||
import WorldBook from './tab/WorldBook';
|
||||
|
||||
const SideBarLeft = () => {
|
||||
const { activeTab, tabs, setActiveTab } = useSideBarLeftStore();
|
||||
@@ -22,10 +26,10 @@ const SideBarLeft = () => {
|
||||
</div>
|
||||
|
||||
<div className="sidebar-content">
|
||||
{activeTab === 'gallery' && <div className="tab-content">画廊内容</div>}
|
||||
{activeTab === 'api' && <div className="tab-content">API配置内容</div>}
|
||||
{activeTab === 'presets' && <div className="tab-content">预设配置内容</div>}
|
||||
{activeTab === 'worldbook' && <div className="tab-content">世界书内容</div>}
|
||||
{activeTab === 'gallery' && <Gallery />}
|
||||
{activeTab === 'api' && <ApiConfig />}
|
||||
{activeTab === 'presets' && <Presets />}
|
||||
{activeTab === 'worldbook' && <WorldBook />}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
13
frontend-react/src/components/SideBarLeft/tab/ApiConfig.jsx
Normal file
13
frontend-react/src/components/SideBarLeft/tab/ApiConfig.jsx
Normal file
@@ -0,0 +1,13 @@
|
||||
import React from 'react';
|
||||
import '../tabcss/ApiConfig.css';
|
||||
|
||||
const ApiConfig = () => {
|
||||
return (
|
||||
<div className="api-config-content">
|
||||
<h2>API配置</h2>
|
||||
{/* 在这里实现API配置的具体内容 */}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ApiConfig;
|
||||
13
frontend-react/src/components/SideBarLeft/tab/Gallery.jsx
Normal file
13
frontend-react/src/components/SideBarLeft/tab/Gallery.jsx
Normal file
@@ -0,0 +1,13 @@
|
||||
import React from 'react';
|
||||
import '../tabcss/Gallery.css';
|
||||
|
||||
const Gallery = () => {
|
||||
return (
|
||||
<div className="gallery-content">
|
||||
<h2>画廊</h2>
|
||||
{/* 在这里实现画廊的具体内容 */}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Gallery;
|
||||
13
frontend-react/src/components/SideBarLeft/tab/Presets.jsx
Normal file
13
frontend-react/src/components/SideBarLeft/tab/Presets.jsx
Normal file
@@ -0,0 +1,13 @@
|
||||
import React from 'react';
|
||||
import '../tabcss/Presets.css';
|
||||
|
||||
const Presets = () => {
|
||||
return (
|
||||
<div className="presets-content">
|
||||
<h2>预设配置</h2>
|
||||
{/* 在这里实现预设配置的具体内容 */}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Presets;
|
||||
13
frontend-react/src/components/SideBarLeft/tab/WorldBook.jsx
Normal file
13
frontend-react/src/components/SideBarLeft/tab/WorldBook.jsx
Normal file
@@ -0,0 +1,13 @@
|
||||
import React from 'react';
|
||||
import '../tabcss/WorldBook.css';
|
||||
|
||||
const WorldBook = () => {
|
||||
return (
|
||||
<div className="worldbook-content">
|
||||
<h2>世界书</h2>
|
||||
{/* 在这里实现世界书的具体内容 */}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default WorldBook;
|
||||
@@ -0,0 +1 @@
|
||||
WorldBook.css
|
||||
Reference in New Issue
Block a user