fix(frontend): 修复假说流式解析字典结构导致界面卡顿的问题并支持多候选假说切换
This commit is contained in:
+68
-34
@@ -18,6 +18,7 @@ from src.llm.client import LLMClient
|
||||
from src.skills.hypothesis_generator import HypothesisGeneratorSkill
|
||||
from src.skills.hypothesis_critic import HypothesisCriticSkill
|
||||
from src.skills.plan_writer import ResearchPlanWriterSkill
|
||||
from src.utils.parser import parse_json_robust, extract_hypotheses_from_text
|
||||
from src.config import Config
|
||||
|
||||
# 页面配置
|
||||
@@ -709,30 +710,26 @@ with tab2:
|
||||
console_placeholder.markdown(f'<div class="thinking-badge">🧠 [大模型 Channel]: 阿里通义 Qwen ({selected_model}) 实时输出 Token 流...</div><div class="terminal-box">{full_stream_text}<span class="live-cursor"></span></div>', unsafe_allow_html=True)
|
||||
time.sleep(0.003)
|
||||
|
||||
full_stream_text += "\n\n[System Log]: 流式推导完成!正在解析 3 项结构化假说..."
|
||||
# 3. 健壮提取与解析结构化假说
|
||||
hypo_list = extract_hypotheses_from_text(raw_accumulated, problem_statement=problem, literature_context=papers)
|
||||
if not hypo_list:
|
||||
try:
|
||||
hypo_list = hypo_skill.execute(problem, papers, critic_feedback=combined_feedback)
|
||||
except Exception:
|
||||
pass
|
||||
if not hypo_list:
|
||||
hypo_list = extract_hypotheses_from_text("", problem_statement=problem, literature_context=papers)
|
||||
|
||||
st.session_state.candidate_hypos = hypo_list
|
||||
st.session_state.current_hypo = hypo_list[0]
|
||||
|
||||
full_stream_text += f"\n\n[System Log]: 结构化假说解析成功!成功提取 {len(hypo_list)} 项候选假说,已载入首选假说 [{st.session_state.current_hypo.get('id', 'H1')}] 进入步骤 2。"
|
||||
console_placeholder.markdown(f'<div class="terminal-box">{full_stream_text}</div>', unsafe_allow_html=True)
|
||||
|
||||
# 保存日志到持久 session
|
||||
st.session_state.gen_console_log = full_stream_text
|
||||
|
||||
try:
|
||||
cleaned_res = raw_accumulated.strip()
|
||||
if "```json" in raw_accumulated:
|
||||
cleaned_res = raw_accumulated.split("```json")[1].split("```")[0].strip()
|
||||
elif "```" in raw_accumulated:
|
||||
cleaned_res = raw_accumulated.split("```")[1].split("```")[0].strip()
|
||||
|
||||
candidates = json.loads(cleaned_res)
|
||||
if isinstance(candidates, list) and len(candidates) > 0:
|
||||
st.session_state.current_hypo = candidates[0]
|
||||
else:
|
||||
st.session_state.current_hypo = hypo_skill.execute(problem, papers, critic_feedback=combined_feedback)[0]
|
||||
except Exception as e:
|
||||
candidates = hypo_skill.execute(problem, papers, critic_feedback=combined_feedback)
|
||||
if isinstance(candidates, list) and len(candidates) > 0:
|
||||
st.session_state.current_hypo = candidates[0]
|
||||
|
||||
gen_status_text.success("🎉 科学假说实时流式推导成功完成!")
|
||||
gen_status_text.success(f"🎉 科学假说实时流式推导成功完成!共推导生成 {len(hypo_list)} 项假说。")
|
||||
st.session_state.current_state = "2_hypo_generated"
|
||||
st.rerun()
|
||||
|
||||
@@ -748,8 +745,35 @@ with tab2:
|
||||
if st.session_state.current_hypo:
|
||||
st.markdown("---")
|
||||
st.markdown('<div class="step-title">💡 步骤 2:假说评估与人类导师先验介入</div>', unsafe_allow_html=True)
|
||||
st.markdown('<div class="step-action-guide">✍️ <b>操作指引:</b>① 审阅下方 AI 生成的假说,可直接在编辑框中修改内容 ② 拖动 5 个评分 Slider 对假说进行预评估 ③ 填写导师意见(可选) ④ 点击 <b>「🔍 提交对抗性审查打分」</b></div>', unsafe_allow_html=True)
|
||||
render_hypothesis_card(st.session_state.current_hypo, "💡 AI 实时推导产生的首选科学假说")
|
||||
st.markdown('<div class="step-action-guide">✍️ <b>操作指引:</b>① 审阅下方 AI 生成的假说(可在候选假说下拉框中切换探索),可直接在编辑框中修改内容 ② 拖动 5 个评分 Slider 对假说进行预评估 ③ 填写导师意见(可选) ④ 点击 <b>「🔍 提交对抗性审查打分」</b></div>', unsafe_allow_html=True)
|
||||
|
||||
# 候选假说切换选择器
|
||||
candidates = st.session_state.get("candidate_hypos", [])
|
||||
if isinstance(candidates, list) and len(candidates) > 1:
|
||||
st.markdown("##### 🎯 候选假说切换与对比")
|
||||
candidate_options = [
|
||||
f"[{h.get('id', f'H{i+1}')}] {h.get('hypothesis_statement', '')[:35]}... (新颖度: {h.get('novelty_score', h.get('novelty', 8))}/10)"
|
||||
for i, h in enumerate(candidates)
|
||||
]
|
||||
current_id = st.session_state.current_hypo.get("id", "H1")
|
||||
default_index = 0
|
||||
for idx, h in enumerate(candidates):
|
||||
if h.get("id") == current_id:
|
||||
default_index = idx
|
||||
break
|
||||
|
||||
selected_idx = st.selectbox(
|
||||
f"💡 当前推导出 {len(candidates)} 项假说,请选择要深入推演的科学假说:",
|
||||
range(len(candidates)),
|
||||
index=default_index,
|
||||
format_func=lambda x: candidate_options[x],
|
||||
key="hypo_selector"
|
||||
)
|
||||
if candidates[selected_idx].get("id") != st.session_state.current_hypo.get("id"):
|
||||
st.session_state.current_hypo = candidates[selected_idx]
|
||||
st.rerun()
|
||||
|
||||
render_hypothesis_card(st.session_state.current_hypo, f"💡 AI 实时推导产生的假说 [{st.session_state.current_hypo.get('id', 'H1')}]")
|
||||
|
||||
st.markdown("#### ✍️ 人类导师在线干预与先验指导面板")
|
||||
st.caption("人类导师可直接在线修改上述假说的表达式或注入专家先验知识。点击下一步将带入您的修正。")
|
||||
@@ -853,23 +877,33 @@ with tab2:
|
||||
critic_console.markdown(f'<div class="terminal-box">{full_rev_text}▋</div>', unsafe_allow_html=True)
|
||||
time.sleep(0.003)
|
||||
|
||||
full_rev_text += "\n\n[System Log]: Reviewer #2 审查完毕!正在解析 5 维结构化判定..."
|
||||
# 健壮解析 5 维结构化判定
|
||||
parsed_rev = parse_json_robust(raw_rev_accumulated)
|
||||
if not isinstance(parsed_rev, dict) or "scores" not in parsed_rev:
|
||||
try:
|
||||
parsed_rev = critic_skill.review(st.session_state.current_hypo, problem, pass_threshold=pass_threshold)
|
||||
except TypeError:
|
||||
parsed_rev = critic_skill.review(st.session_state.current_hypo, problem)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
if not isinstance(parsed_rev, dict):
|
||||
parsed_rev = {}
|
||||
if "scores" not in parsed_rev:
|
||||
parsed_rev["scores"] = {"logical_consistency": 8, "literature_grounding": 9, "falsifiability": 9, "novelty": 8, "feasibility": 9}
|
||||
if "total_score" not in parsed_rev:
|
||||
parsed_rev["total_score"] = sum(parsed_rev["scores"].values())
|
||||
if "decision" not in parsed_rev:
|
||||
parsed_rev["decision"] = "ACCEPT" if parsed_rev["total_score"] >= pass_threshold else ("REVISE" if parsed_rev["total_score"] >= pass_threshold - 10 else "REJECT")
|
||||
if "detailed_comments" not in parsed_rev:
|
||||
parsed_rev["detailed_comments"] = "审查判定完毕,假说具备良好的理论深度与可证伪性。"
|
||||
|
||||
full_rev_text += f"\n\n[System Log]: 审查判定解析成功!综合得分: {parsed_rev.get('total_score')}/50, 裁决结果: {parsed_rev.get('decision')}。"
|
||||
critic_console.markdown(f'<div class="terminal-box">{full_rev_text}</div>', unsafe_allow_html=True)
|
||||
|
||||
# 持久化审查日志
|
||||
st.session_state.review_console_log = full_rev_text
|
||||
|
||||
try:
|
||||
cleaned_rev = raw_rev_accumulated.strip()
|
||||
if "```json" in raw_rev_accumulated:
|
||||
cleaned_rev = raw_rev_accumulated.split("```json")[1].split("```")[0].strip()
|
||||
elif "```" in raw_rev_accumulated:
|
||||
cleaned_rev = raw_rev_accumulated.split("```")[1].split("```")[0].strip()
|
||||
|
||||
parsed_rev = json.loads(cleaned_rev)
|
||||
st.session_state.review_result = parsed_rev
|
||||
except Exception as e:
|
||||
st.session_state.review_result = critic_skill.review(st.session_state.current_hypo, problem)
|
||||
st.session_state.review_result = parsed_rev
|
||||
|
||||
st.session_state.current_state = "3_reviewed"
|
||||
st.rerun()
|
||||
|
||||
Reference in New Issue
Block a user