bidmaster-cli/src/bidmaster/nodes/content/interact_user.py
sladro c1292fcacc feat: add validation and toc pipeline upgrades
Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
2025-11-19 10:11:21 +08:00

146 lines
4.5 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.

"""用户交互节点
与用户交互获取章节填写要求和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