Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
146 lines
4.5 KiB
Python
146 lines
4.5 KiB
Python
"""用户交互节点
|
||
|
||
与用户交互获取章节填写要求和RAG配置。
|
||
"""
|
||
|
||
import logging
|
||
from typing import Any, Dict
|
||
|
||
from ..base import BaseNode, NodeContext
|
||
|
||
logger = logging.getLogger(__name__)
|
||
|
||
|
||
class InteractWithUserNode(BaseNode):
|
||
"""用户交互节点
|
||
|
||
职责:
|
||
1. 询问用户该章节需要强调的内容
|
||
2. 询问是否使用RAG知识库
|
||
3. 如果使用RAG,选择具体的知识库
|
||
4. 保存配置供后续子章节继承
|
||
"""
|
||
|
||
@property
|
||
def name(self) -> str:
|
||
return "interact_user"
|
||
|
||
@property
|
||
def description(self) -> str:
|
||
return "与用户交互获取章节配置"
|
||
|
||
def execute(self, state: Dict[str, Any], context: NodeContext) -> Dict[str, Any]:
|
||
"""执行用户交互
|
||
|
||
Args:
|
||
state: 当前状态
|
||
context: 执行上下文
|
||
|
||
Returns:
|
||
更新后的状态
|
||
"""
|
||
chapter = state.get("current_chapter", {})
|
||
chapter_id = chapter.get("id")
|
||
chapter_title = chapter.get("title")
|
||
|
||
if not chapter_id:
|
||
raise ValueError("当前章节信息缺失")
|
||
|
||
# 检查是否需要交互
|
||
needs_interaction = state.get("needs_interaction", False)
|
||
if not needs_interaction:
|
||
# 不需要交互,直接返回
|
||
return state
|
||
|
||
# 获取交互处理器
|
||
interaction_handler = state.get("interaction_handler")
|
||
|
||
if not interaction_handler:
|
||
# 无交互处理器时立即失败,暴露配置问题
|
||
raise ValueError("交互处理器未配置,无法获取章节配置")
|
||
|
||
logger.info(f"开始与用户交互,获取章节配置: {chapter_id} - {chapter_title}")
|
||
|
||
# 1. 询问需要强调的内容
|
||
emphasis = interaction_handler(
|
||
interaction_type="text",
|
||
prompt=f"📝 正在处理章节:{chapter_id}. {chapter_title}\n"
|
||
f" 是否有需要特别强调的内容?(直接回车跳过)",
|
||
default="",
|
||
key=f"emphasis_{chapter_id}",
|
||
)
|
||
|
||
# 2. 询问是否使用RAG
|
||
use_rag_response = interaction_handler(
|
||
interaction_type="choice",
|
||
prompt="是否使用RAG知识库辅助生成内容",
|
||
options=["是", "否"],
|
||
default="否",
|
||
key=f"use_rag_{chapter_id}",
|
||
)
|
||
|
||
use_rag = use_rag_response == "是"
|
||
rag_store = None
|
||
|
||
# 3. 如果使用RAG,选择知识库
|
||
if use_rag:
|
||
rag_store = self._select_rag_store(interaction_handler, chapter_id, state)
|
||
|
||
# 保存章节配置
|
||
config = {
|
||
"emphasis": emphasis.strip() if emphasis else "",
|
||
"rag_enabled": use_rag,
|
||
"rag_store": rag_store,
|
||
}
|
||
|
||
state.setdefault("chapter_configs", {})[chapter_id] = config
|
||
|
||
logger.info(
|
||
f"章节配置已保存: 强调内容={'有' if config['emphasis'] else '无'}, "
|
||
f"RAG={'启用' if use_rag else '禁用'}"
|
||
)
|
||
|
||
return state
|
||
|
||
def _select_rag_store(self, interaction_handler, chapter_id: str, state: Dict[str, Any]) -> str:
|
||
"""选择RAG知识库
|
||
|
||
Args:
|
||
interaction_handler: 交互处理器
|
||
chapter_id: 章节ID
|
||
state: 当前状态
|
||
|
||
Returns:
|
||
知识库标识
|
||
"""
|
||
# 从state获取RAGTool实例(由InitConfigNode统一初始化)
|
||
rag_tool = state.get("rag_tool")
|
||
if not rag_tool:
|
||
raise ValueError("RAGTool未初始化,请检查InitConfigNode配置")
|
||
|
||
try:
|
||
stats = rag_tool.get_stats()
|
||
total_chunks = stats.get("total_chunks", 0)
|
||
total_files = stats.get("total_files", 0)
|
||
|
||
# 显示知识库统计信息
|
||
store_info = f"默认知识库 ({total_files}个文档, {total_chunks}个文档块)"
|
||
|
||
choice = interaction_handler(
|
||
interaction_type="choice",
|
||
prompt="选择知识库",
|
||
options=[
|
||
("default", store_info),
|
||
("none", "不使用RAG")
|
||
],
|
||
default="default",
|
||
key=f"rag_store_{chapter_id}",
|
||
)
|
||
|
||
if choice == "default":
|
||
return "default"
|
||
return None
|
||
|
||
except Exception as e:
|
||
logger.error(f"获取知识库信息失败: {e}", exc_info=True)
|
||
raise ValueError("获取知识库信息失败,无法选择RAG存储") from e |