169 lines
6.6 KiB
Python
169 lines
6.6 KiB
Python
import streamlit as st
|
||
import os
|
||
import json
|
||
import shutil
|
||
|
||
# --- 配置 ---
|
||
# 定义文件目录
|
||
SOURCE_DIR = "processed_json_outputs"
|
||
APPROVED_DIR = "reviewed_approved"
|
||
REJECTED_DIR = "reviewed_rejected"
|
||
|
||
# --- 核心功能 ---
|
||
|
||
def get_pending_files():
|
||
"""获取所有待审核的JSON文件列表"""
|
||
if not os.path.exists(SOURCE_DIR):
|
||
return []
|
||
|
||
# 创建目标文件夹(如果不存在)
|
||
os.makedirs(APPROVED_DIR, exist_ok=True)
|
||
os.makedirs(REJECTED_DIR, exist_ok=True)
|
||
|
||
processed_files = set(os.listdir(SOURCE_DIR))
|
||
approved_files = set(os.listdir(APPROVED_DIR))
|
||
rejected_files = set(os.listdir(REJECTED_DIR))
|
||
|
||
# 待审核文件 = 源文件 - (已通过的文件 + 已驳回的文件)
|
||
pending_files = list(processed_files - approved_files - rejected_files)
|
||
return sorted(pending_files)
|
||
|
||
def display_knowledge_card(data, index):
|
||
"""以美观的卡片形式展示单个知识点"""
|
||
with st.expander(f"**知识点 {index+1}: {data.get('summary', '无摘要')}**", expanded=True):
|
||
st.info(f"**摘要:** {data.get('summary', 'N/A')}")
|
||
|
||
st.subheader("核心策略/方法论")
|
||
for step in data.get('core_strategy', []):
|
||
st.markdown(f"**- 第 {step.get('step')} 步: {step.get('title')}**")
|
||
st.markdown(f"> {step.get('content')}")
|
||
|
||
st.subheader("话术示例")
|
||
examples = data.get('script_examples', [])
|
||
if examples:
|
||
for ex in examples:
|
||
st.code(ex, language='text')
|
||
else:
|
||
st.caption("无")
|
||
|
||
st.subheader("常见误区")
|
||
pitfalls = data.get('common_pitfalls', [])
|
||
if pitfalls:
|
||
for pit in pitfalls:
|
||
st.warning(f"- {pit}")
|
||
else:
|
||
st.caption("无")
|
||
|
||
# 案例和来源信息
|
||
col1, col2 = st.columns(2)
|
||
with col1:
|
||
case = data.get('case_study', {})
|
||
st.subheader("相关案例")
|
||
st.caption(f"主播: {case.get('streamer_name', 'N/A')}")
|
||
st.caption(f"描述: {case.get('description', 'N/A')}")
|
||
with col2:
|
||
ref = data.get('source_reference', {})
|
||
st.subheader("来源参考")
|
||
st.caption(f"文件名: {ref.get('video_title', 'N/A')}")
|
||
st.caption(f"时间戳: {ref.get('timestamp', 'N/A')}")
|
||
|
||
def display_editable_card(data, key_prefix):
|
||
"""以可编辑的形式展示单个知识点"""
|
||
edited_data = data.copy() # 创建副本以存储编辑内容
|
||
|
||
edited_data['summary'] = st.text_input("摘要", value=data.get('summary', ''), key=f"{key_prefix}_summary")
|
||
|
||
st.subheader("核心策略/方法论")
|
||
edited_strategies = []
|
||
for i, step in enumerate(data.get('core_strategy', [])):
|
||
with st.container(border=True):
|
||
edited_step = step.copy()
|
||
edited_step['title'] = st.text_input(f"步骤 {i+1} 标题", value=step.get('title', ''), key=f"{key_prefix}_step{i}_title")
|
||
edited_step['content'] = st.text_area(f"步骤 {i+1} 内容", value=step.get('content', ''), key=f"{key_prefix}_step{i}_content")
|
||
edited_strategies.append(edited_step)
|
||
edited_data['core_strategy'] = edited_strategies
|
||
|
||
# 其他字段为了简化,这里只做展示,也可以按需添加编辑功能
|
||
st.subheader("话术示例 (暂不可编辑)")
|
||
st.json(data.get('script_examples', []))
|
||
|
||
st.subheader("常见误区 (暂不可编辑)")
|
||
st.json(data.get('common_pitfalls', []))
|
||
|
||
return edited_data
|
||
|
||
|
||
# --- Streamlit 页面布局 ---
|
||
|
||
st.set_page_config(layout="wide", page_title="直播知识库审核平台")
|
||
|
||
st.title("💡 直播知识库审核平台")
|
||
st.markdown("在这里审核由AI处理生成的知识点。操作后文件会自动归档。")
|
||
|
||
# --- 侧边栏 ---
|
||
pending_files = get_pending_files()
|
||
if not pending_files:
|
||
st.sidebar.success("🎉 恭喜!所有文件都已审核完毕!")
|
||
st.balloons()
|
||
else:
|
||
st.sidebar.header("待审核文件")
|
||
selected_file = st.sidebar.radio("请选择一个文件进行审核:", pending_files, key="file_selector")
|
||
|
||
# --- 主界面 ---
|
||
if selected_file:
|
||
file_path = os.path.join(SOURCE_DIR, selected_file)
|
||
with open(file_path, 'r', encoding='utf-8') as f:
|
||
try:
|
||
content_data = json.load(f)
|
||
except json.JSONDecodeError:
|
||
st.error(f"文件 {selected_file} 格式错误,不是有效的JSON。")
|
||
content_data = None
|
||
|
||
if content_data:
|
||
st.header(f"正在审核: `{selected_file}`")
|
||
|
||
# 使用Session State来控制编辑模式
|
||
if 'edit_mode' not in st.session_state:
|
||
st.session_state.edit_mode = False
|
||
|
||
# --- 操作按钮 ---
|
||
col1, col2, col3, _ = st.columns([1,1,1,3])
|
||
|
||
if col1.button("✅ 通过", use_container_width=True):
|
||
shutil.copy(file_path, os.path.join(APPROVED_DIR, selected_file))
|
||
st.success(f"文件 '{selected_file}' 已通过并归档!")
|
||
st.rerun() # 重新运行脚本以刷新列表
|
||
|
||
if col2.button("❌ 驳回", use_container_width=True):
|
||
shutil.copy(file_path, os.path.join(REJECTED_DIR, selected_file))
|
||
st.warning(f"文件 '{selected_file}' 已驳回并归档。")
|
||
st.rerun()
|
||
|
||
if col3.button("✏️ 编辑", use_container_width=True):
|
||
st.session_state.edit_mode = not st.session_state.edit_mode
|
||
st.rerun()
|
||
|
||
|
||
st.markdown("---")
|
||
|
||
# --- 内容展示 ---
|
||
if st.session_state.edit_mode:
|
||
st.subheader("📝 编辑模式")
|
||
edited_content = []
|
||
for i, item in enumerate(content_data):
|
||
edited_item = display_editable_card(item, key_prefix=f"item_{i}")
|
||
edited_content.append(edited_item)
|
||
|
||
if st.button("💾 保存修改并通过", type="primary"):
|
||
# 将修改后的内容保存到 "approved" 目录
|
||
save_path = os.path.join(APPROVED_DIR, selected_file)
|
||
with open(save_path, 'w', encoding='utf-8') as f:
|
||
json.dump(edited_content, f, ensure_ascii=False, indent=2)
|
||
st.success(f"文件 '{selected_file}' 的修改已保存并通过!")
|
||
st.session_state.edit_mode = False
|
||
st.rerun()
|
||
|
||
else:
|
||
st.subheader("👁️🗨️ 预览模式")
|
||
for i, item in enumerate(content_data):
|
||
display_knowledge_card(item, i) |