Update src/reasoning_panel.py
Browse files- src/reasoning_panel.py +54 -18
src/reasoning_panel.py
CHANGED
|
@@ -6,62 +6,94 @@ from typing import Dict, List
|
|
| 6 |
import streamlit as st
|
| 7 |
|
| 8 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 9 |
def _bullets_html(items: List[str]) -> str:
|
| 10 |
-
"""
|
| 11 |
-
Render a list of strings as a markdown bullet list.
|
| 12 |
-
Items may include HTML <sup>...</sup> markers for citations.
|
| 13 |
-
"""
|
| 14 |
if not items:
|
| 15 |
return "_(none)_"
|
| 16 |
-
|
| 17 |
-
return "\n".join(lines)
|
| 18 |
|
| 19 |
|
| 20 |
def build_panel_data(result: Dict[str, object]) -> Dict[str, object]:
|
| 21 |
"""
|
| 22 |
-
|
| 23 |
-
suitable for rendering in Streamlit. This function is intentionally light-weight.
|
| 24 |
"""
|
| 25 |
-
soap = result.get("soap", {}) if isinstance(result, dict) else {}
|
| 26 |
meta = result.get("meta", {}) if isinstance(result, dict) else {}
|
| 27 |
-
citations = result.get("citations", []) if isinstance(result, dict) else []
|
| 28 |
-
|
| 29 |
annotated = meta.get("annotated", {}) if isinstance(meta, dict) else {}
|
|
|
|
|
|
|
| 30 |
assess_html = annotated.get("assessment_html", []) if isinstance(annotated, dict) else []
|
| 31 |
plan_html = annotated.get("plan_html", []) if isinstance(annotated, dict) else []
|
| 32 |
|
|
|
|
|
|
|
|
|
|
| 33 |
return {
|
| 34 |
"assessment_html": assess_html,
|
| 35 |
"plan_html": plan_html,
|
| 36 |
-
"
|
|
|
|
|
|
|
| 37 |
"timings": meta.get("timings", {}),
|
|
|
|
|
|
|
| 38 |
}
|
| 39 |
|
| 40 |
|
| 41 |
def render_reasoning_panel(panel_data: Dict[str, object]) -> None:
|
| 42 |
"""
|
| 43 |
-
Render annotated bullets and
|
| 44 |
"""
|
| 45 |
st.subheader("Reasoning & Evidence")
|
| 46 |
|
| 47 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 48 |
col1, col2 = st.columns(2)
|
| 49 |
with col1:
|
| 50 |
st.markdown("**Assessment (annotated)**")
|
| 51 |
st.markdown(_bullets_html(panel_data.get("assessment_html", [])), unsafe_allow_html=True)
|
|
|
|
|
|
|
|
|
|
|
|
|
| 52 |
with col2:
|
| 53 |
st.markdown("**Plan (annotated)**")
|
| 54 |
st.markdown(_bullets_html(panel_data.get("plan_html", [])), unsafe_allow_html=True)
|
|
|
|
|
|
|
|
|
|
| 55 |
|
| 56 |
-
# Evidence registry
|
| 57 |
st.markdown("---")
|
| 58 |
st.markdown("**Evidence Registry** (global refs)")
|
| 59 |
-
|
| 60 |
-
if not
|
| 61 |
st.caption("No evidence available. Build the FAISS index in Step 1 to enable mapping.")
|
| 62 |
return
|
| 63 |
|
| 64 |
-
for r in
|
| 65 |
with st.container(border=True):
|
| 66 |
n = r.get("n", r.get("rank", "?"))
|
| 67 |
doc = r.get("doc_name", "")
|
|
@@ -73,6 +105,10 @@ def render_reasoning_panel(panel_data: Dict[str, object]) -> None:
|
|
| 73 |
if sp:
|
| 74 |
st.caption(sp)
|
| 75 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 76 |
|
| 77 |
|
| 78 |
|
|
|
|
| 6 |
import streamlit as st
|
| 7 |
|
| 8 |
|
| 9 |
+
def _render_popover_for_item(
|
| 10 |
+
label: str,
|
| 11 |
+
ref_nums: List[int],
|
| 12 |
+
registry: List[Dict[str, object]],
|
| 13 |
+
) -> None:
|
| 14 |
+
"""Render an expander with top‑K evidence for a single bullet."""
|
| 15 |
+
if not ref_nums:
|
| 16 |
+
return
|
| 17 |
+
with st.expander(label, expanded=False):
|
| 18 |
+
for n in ref_nums:
|
| 19 |
+
rec = next((r for r in registry if int(r.get("n", r.get("rank", -1))) == int(n)), None)
|
| 20 |
+
if not rec:
|
| 21 |
+
continue
|
| 22 |
+
title = f"[{n}] {rec.get('doc_name','')} — p.{rec.get('page',0)} | score {float(rec.get('score',0.0)):.3f}"
|
| 23 |
+
st.markdown(f"**{title}**")
|
| 24 |
+
st.write(rec.get("text", ""))
|
| 25 |
+
if rec.get("source_path"):
|
| 26 |
+
st.caption(rec["source_path"])
|
| 27 |
+
|
| 28 |
+
|
| 29 |
def _bullets_html(items: List[str]) -> str:
|
|
|
|
|
|
|
|
|
|
|
|
|
| 30 |
if not items:
|
| 31 |
return "_(none)_"
|
| 32 |
+
return "\n".join([f"- {s}" for s in items])
|
|
|
|
| 33 |
|
| 34 |
|
| 35 |
def build_panel_data(result: Dict[str, object]) -> Dict[str, object]:
|
| 36 |
"""
|
| 37 |
+
Extract renderable data from ai_core.GenerationResult->dict.
|
|
|
|
| 38 |
"""
|
|
|
|
| 39 |
meta = result.get("meta", {}) if isinstance(result, dict) else {}
|
|
|
|
|
|
|
| 40 |
annotated = meta.get("annotated", {}) if isinstance(meta, dict) else {}
|
| 41 |
+
claim_mapping = meta.get("claim_mapping", {}) if isinstance(meta, dict) else {}
|
| 42 |
+
|
| 43 |
assess_html = annotated.get("assessment_html", []) if isinstance(annotated, dict) else []
|
| 44 |
plan_html = annotated.get("plan_html", []) if isinstance(annotated, dict) else []
|
| 45 |
|
| 46 |
+
assess_map_items = claim_mapping.get("assessment", {}).get("items", []) if isinstance(claim_mapping, dict) else []
|
| 47 |
+
plan_map_items = claim_mapping.get("plan", {}).get("items", []) if isinstance(claim_mapping, dict) else []
|
| 48 |
+
|
| 49 |
return {
|
| 50 |
"assessment_html": assess_html,
|
| 51 |
"plan_html": plan_html,
|
| 52 |
+
"assessment_map": assess_map_items,
|
| 53 |
+
"plan_map": plan_map_items,
|
| 54 |
+
"citations": result.get("citations", []),
|
| 55 |
"timings": meta.get("timings", {}),
|
| 56 |
+
"map_mode": meta.get("map_mode", "production"),
|
| 57 |
+
"registry_cap": meta.get("registry_cap", None),
|
| 58 |
}
|
| 59 |
|
| 60 |
|
| 61 |
def render_reasoning_panel(panel_data: Dict[str, object]) -> None:
|
| 62 |
"""
|
| 63 |
+
Render annotated bullets with per‑bullet popovers and global evidence registry.
|
| 64 |
"""
|
| 65 |
st.subheader("Reasoning & Evidence")
|
| 66 |
|
| 67 |
+
timings = panel_data.get("timings", {})
|
| 68 |
+
map_mode = panel_data.get("map_mode", "production")
|
| 69 |
+
cap = panel_data.get("registry_cap", None)
|
| 70 |
+
st.caption(f"Evidence mode: **{map_mode}**" + (f" | registry cap: {cap}" if cap else ""))
|
| 71 |
+
|
| 72 |
+
registry = panel_data.get("citations", [])
|
| 73 |
+
|
| 74 |
col1, col2 = st.columns(2)
|
| 75 |
with col1:
|
| 76 |
st.markdown("**Assessment (annotated)**")
|
| 77 |
st.markdown(_bullets_html(panel_data.get("assessment_html", [])), unsafe_allow_html=True)
|
| 78 |
+
# Popovers per assessment bullet
|
| 79 |
+
for i, it in enumerate(panel_data.get("assessment_map", []), start=1):
|
| 80 |
+
_render_popover_for_item(f"[?] Evidence for Assessment #{i}", it.get("ref_nums", []), registry)
|
| 81 |
+
|
| 82 |
with col2:
|
| 83 |
st.markdown("**Plan (annotated)**")
|
| 84 |
st.markdown(_bullets_html(panel_data.get("plan_html", [])), unsafe_allow_html=True)
|
| 85 |
+
# Popovers per plan bullet
|
| 86 |
+
for i, it in enumerate(panel_data.get("plan_map", []), start=1):
|
| 87 |
+
_render_popover_for_item(f"[?] Evidence for Plan #{i}", it.get("ref_nums", []), registry)
|
| 88 |
|
|
|
|
| 89 |
st.markdown("---")
|
| 90 |
st.markdown("**Evidence Registry** (global refs)")
|
| 91 |
+
|
| 92 |
+
if not registry:
|
| 93 |
st.caption("No evidence available. Build the FAISS index in Step 1 to enable mapping.")
|
| 94 |
return
|
| 95 |
|
| 96 |
+
for r in registry:
|
| 97 |
with st.container(border=True):
|
| 98 |
n = r.get("n", r.get("rank", "?"))
|
| 99 |
doc = r.get("doc_name", "")
|
|
|
|
| 105 |
if sp:
|
| 106 |
st.caption(sp)
|
| 107 |
|
| 108 |
+
if isinstance(timings, dict):
|
| 109 |
+
st.caption(f"Timings: {timings}")
|
| 110 |
+
|
| 111 |
+
|
| 112 |
|
| 113 |
|
| 114 |
|