feat: 实现完整的人工审核功能与子图模块
- 新增三个核心子图:人工审核、意图理解、格式化输出 - 实现完整的审核 API 端点(/api/review/*) - 前端添加审核确认界面(右下角固定框) - 为每个子图创建分步测试代码 - 添加功能实现文档
This commit is contained in:
@@ -22,6 +22,9 @@ def render_chat_area():
|
||||
# 渲染历史消息
|
||||
_render_chat_history()
|
||||
|
||||
# 检查并渲染审核确认界面
|
||||
_render_review_confirmation()
|
||||
|
||||
# 输入框和流式响应处理
|
||||
_render_input_and_response()
|
||||
|
||||
@@ -344,3 +347,201 @@ def _show_completion_stats(event: dict):
|
||||
if token_usage:
|
||||
total_tokens = token_usage.get("total_tokens", 0)
|
||||
st.caption(f"📊 消耗 {total_tokens} tokens | ⏱️ {elapsed:.2f}s")
|
||||
|
||||
|
||||
def _render_review_confirmation():
|
||||
"""渲染审核确认界面 - 类似编程工具的右下角确认交互"""
|
||||
# 获取当前线程的待审核内容
|
||||
thread_id = AppState.get_current_thread_id()
|
||||
user_id = AppState.get_user_id()
|
||||
|
||||
# 初始化会话状态
|
||||
if 'pending_review' not in st.session_state:
|
||||
st.session_state.pending_review = None
|
||||
if 'show_review_modify' not in st.session_state:
|
||||
st.session_state.show_review_modify = False
|
||||
if 'review_error' not in st.session_state:
|
||||
st.session_state.review_error = None
|
||||
|
||||
# 如果有待审核内容,先尝试从后端获取最新状态
|
||||
if st.session_state.pending_review:
|
||||
review_id = st.session_state.pending_review.get("review_id")
|
||||
if review_id:
|
||||
try:
|
||||
latest_review = api_client.get_review(review_id)
|
||||
if latest_review and latest_review.get("status") != "PENDING":
|
||||
# 审核已处理,清除待审核状态
|
||||
st.session_state.pending_review = None
|
||||
st.session_state.show_review_modify = False
|
||||
except Exception as e:
|
||||
pass
|
||||
|
||||
# 如果没有待审核内容,检查是否有新的待审核内容
|
||||
if not st.session_state.pending_review:
|
||||
try:
|
||||
pending_reviews = api_client.get_pending_reviews(limit=10)
|
||||
# 查找当前线程的待审核内容
|
||||
for review in pending_reviews:
|
||||
if review.get("thread_id") == thread_id and review.get("status") == "PENDING":
|
||||
st.session_state.pending_review = {
|
||||
"review_id": review.get("review_id"),
|
||||
"content_to_review": review.get("content_to_review"),
|
||||
"created_at": review.get("created_at"),
|
||||
"user_id": review.get("user_id")
|
||||
}
|
||||
break
|
||||
except Exception as e:
|
||||
st.session_state.review_error = str(e)
|
||||
|
||||
# 测试按钮 - 用于演示审核功能
|
||||
with st.container():
|
||||
st.markdown("<div style='height: 20px;'></div>", unsafe_allow_html=True)
|
||||
col_test, col_info = st.columns([1, 3])
|
||||
with col_test:
|
||||
if st.button("🔧 测试审核", key="test_review_chat"):
|
||||
# 创建一个测试审核请求
|
||||
test_content = "这是一条待审核的测试内容。\n\n您可以选择:\n✅ 确定 - 批准此内容\n✏️ 修改 - 修改后批准\n❌ 拒绝 - 拒绝此内容"
|
||||
review_id = api_client.request_review(thread_id, user_id, test_content)
|
||||
if review_id:
|
||||
st.session_state.pending_review = {
|
||||
"review_id": review_id,
|
||||
"content_to_review": test_content,
|
||||
"created_at": "2024-01-01T12:00:00",
|
||||
"user_id": user_id
|
||||
}
|
||||
st.success("✅ 已创建测试审核")
|
||||
st.rerun()
|
||||
else:
|
||||
st.error("❌ 创建测试审核失败")
|
||||
with col_info:
|
||||
if st.session_state.get("review_error"):
|
||||
st.warning(f"⚠️ {st.session_state.review_error}")
|
||||
elif st.session_state.pending_review:
|
||||
st.info("📋 有待审核内容")
|
||||
|
||||
# 显示审核确认界面
|
||||
if st.session_state.pending_review:
|
||||
review = st.session_state.pending_review
|
||||
|
||||
# 使用右下角的固定样式显示(通过CSS实现)
|
||||
st.markdown("""
|
||||
<style>
|
||||
.review-container {
|
||||
position: fixed;
|
||||
bottom: 20px;
|
||||
right: 20px;
|
||||
width: 400px;
|
||||
background: white;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 4px 20px rgba(0,0,0,0.15);
|
||||
z-index: 1000;
|
||||
padding: 20px;
|
||||
border: 1px solid #e0e0e0;
|
||||
}
|
||||
.review-header {
|
||||
font-weight: 600;
|
||||
font-size: 16px;
|
||||
margin-bottom: 12px;
|
||||
color: #333;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
.review-content {
|
||||
background: #f8f9fa;
|
||||
padding: 12px;
|
||||
border-radius: 8px;
|
||||
margin-bottom: 16px;
|
||||
max-height: 150px;
|
||||
overflow-y: auto;
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
.review-buttons {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
</style>
|
||||
""", unsafe_allow_html=True)
|
||||
|
||||
# 渲染审核确认框
|
||||
with st.container():
|
||||
st.markdown('<div class="review-container">', unsafe_allow_html=True)
|
||||
|
||||
# 标题和关闭按钮
|
||||
col_title, col_close = st.columns([4, 1])
|
||||
with col_title:
|
||||
st.markdown('<div class="review-header">📋 待审核内容</div>', unsafe_allow_html=True)
|
||||
with col_close:
|
||||
if st.button("✕", key="close_review"):
|
||||
st.session_state.pending_review = None
|
||||
st.rerun()
|
||||
|
||||
# 内容区域 - 转义 HTML
|
||||
safe_content = review["content_to_review"].replace("<", "<").replace(">", ">")
|
||||
st.markdown(f'<div class="review-content">{safe_content}</div>', unsafe_allow_html=True)
|
||||
|
||||
# 如果是修改模式,显示文本编辑框
|
||||
if st.session_state.show_review_modify:
|
||||
modified_content = st.text_area(
|
||||
"修改内容",
|
||||
value=review["content_to_review"],
|
||||
key="modify_text_area",
|
||||
height=100
|
||||
)
|
||||
col_cancel, col_submit = st.columns([1, 1])
|
||||
with col_cancel:
|
||||
if st.button("取消", key="cancel_modify", use_container_width=True):
|
||||
st.session_state.show_review_modify = False
|
||||
st.rerun()
|
||||
with col_submit:
|
||||
if st.button("提交修改", key="submit_modify", type="primary", use_container_width=True):
|
||||
# 调用API提交修改
|
||||
reviewer = user_id
|
||||
success = api_client.modify_review(
|
||||
review["review_id"],
|
||||
reviewer,
|
||||
modified_content
|
||||
)
|
||||
if success:
|
||||
st.success("✅ 修改已提交")
|
||||
st.session_state.pending_review = None
|
||||
st.session_state.show_review_modify = False
|
||||
st.rerun()
|
||||
else:
|
||||
st.error("❌ 提交失败")
|
||||
else:
|
||||
# 按钮区域
|
||||
col_approve, col_modify, col_reject = st.columns([1, 1, 1])
|
||||
with col_approve:
|
||||
if st.button("✅ 确定", key="approve_btn", use_container_width=True, type="primary"):
|
||||
# 调用审核通过API
|
||||
reviewer = user_id
|
||||
success = api_client.approve_review(review["review_id"], reviewer, "已批准")
|
||||
if success:
|
||||
st.success("✅ 已批准")
|
||||
st.session_state.pending_review = None
|
||||
st.rerun()
|
||||
else:
|
||||
st.error("❌ 操作失败")
|
||||
|
||||
with col_modify:
|
||||
if st.button("✏️ 修改", key="modify_btn", use_container_width=True):
|
||||
st.session_state.show_review_modify = True
|
||||
st.rerun()
|
||||
|
||||
with col_reject:
|
||||
if st.button("❌ 拒绝", key="reject_btn", use_container_width=True):
|
||||
# 调用审核拒绝API
|
||||
reviewer = user_id
|
||||
success = api_client.reject_review(review["review_id"], reviewer, "已拒绝")
|
||||
if success:
|
||||
st.success("✅ 已拒绝")
|
||||
st.session_state.pending_review = None
|
||||
st.rerun()
|
||||
else:
|
||||
st.error("❌ 操作失败")
|
||||
|
||||
st.markdown('</div>', unsafe_allow_html=True)
|
||||
|
||||
Reference in New Issue
Block a user