Update app.py
Browse files
app.py
CHANGED
|
@@ -1,12 +1,6 @@
|
|
| 1 |
# app.py β Spine Coder (Chatbot + Feedback + Session Logs) β Gradio 4.x
|
| 2 |
# ------------------------------------------------------------------------------
|
| 3 |
-
#
|
| 4 |
-
# - Two-column layout: Inputs | Results
|
| 5 |
-
# - Examples use gr.Examples (click-to-fill works in Gradio 4.x)
|
| 6 |
-
# - Suggestions render as a pandas DataFrame (no UI "Error" chips)
|
| 7 |
-
# - Robust result-shape normalization (levels can be dict/list, flags list/dict)
|
| 8 |
-
# - JSON output + warnings panel (+ optional DEBUG tracebacks)
|
| 9 |
-
# - Feedback logger + one-click session export to /logs
|
| 10 |
# ------------------------------------------------------------------------------
|
| 11 |
|
| 12 |
import os
|
|
@@ -66,22 +60,19 @@ def _coalesce_suggestions(result: Dict[str, Any]) -> Tuple[List[Dict[str, Any]],
|
|
| 66 |
if not isinstance(result, dict):
|
| 67 |
return [], {}
|
| 68 |
|
| 69 |
-
# rows
|
| 70 |
sugg = result.get("suggestions") or []
|
| 71 |
rows: List[Dict[str, Any]] = []
|
| 72 |
for s in sugg:
|
| 73 |
if not isinstance(s, dict):
|
| 74 |
continue
|
| 75 |
conf_val = s.get("confidence")
|
| 76 |
-
if isinstance(conf_val, (int, float))
|
| 77 |
-
conf_out = round(float(conf_val), 2)
|
| 78 |
-
else:
|
| 79 |
-
conf_out = conf_val or ""
|
| 80 |
-
|
| 81 |
rows.append({
|
| 82 |
"CPT": s.get("cpt", ""),
|
| 83 |
"Modifier": s.get("modifier") or "",
|
| 84 |
-
"Modifiers": ", ".join(s.get("modifiers", [])) if isinstance(s.get("modifiers"), list)
|
|
|
|
| 85 |
"Description": s.get("desc", ""),
|
| 86 |
"Rationale": s.get("rationale", ""),
|
| 87 |
"Confidence": conf_out,
|
|
@@ -91,9 +82,12 @@ def _coalesce_suggestions(result: Dict[str, Any]) -> Tuple[List[Dict[str, Any]],
|
|
| 91 |
"Units": s.get("units", 1),
|
| 92 |
})
|
| 93 |
|
| 94 |
-
# normalize levels
|
|
|
|
|
|
|
|
|
|
|
|
|
| 95 |
levels_obj = result.get("levels")
|
| 96 |
-
segs: List[str], inters: List[str], lvl_lat = [], [], ""
|
| 97 |
if isinstance(levels_obj, dict):
|
| 98 |
segs = list(levels_obj.get("segments") or [])
|
| 99 |
inters = list(levels_obj.get("interspaces") or [])
|
|
@@ -101,7 +95,7 @@ def _coalesce_suggestions(result: Dict[str, Any]) -> Tuple[List[Dict[str, Any]],
|
|
| 101 |
elif isinstance(levels_obj, list):
|
| 102 |
segs = [str(x) for x in levels_obj]
|
| 103 |
|
| 104 |
-
# normalize flags
|
| 105 |
flags_obj = result.get("flags")
|
| 106 |
if isinstance(flags_obj, list):
|
| 107 |
flags_list = [str(x) for x in flags_obj]
|
|
@@ -110,6 +104,7 @@ def _coalesce_suggestions(result: Dict[str, Any]) -> Tuple[List[Dict[str, Any]],
|
|
| 110 |
else:
|
| 111 |
flags_list = []
|
| 112 |
|
|
|
|
| 113 |
meta = {
|
| 114 |
"payer": result.get("payer", ""),
|
| 115 |
"region": result.get("region", ""),
|
|
@@ -214,7 +209,6 @@ CUSTOM_CSS = """
|
|
| 214 |
with gr.Blocks(theme=THEME, css=CUSTOM_CSS, title="Spine Coder β CPT Billing") as demo:
|
| 215 |
session_id = gr.State(new_session())
|
| 216 |
|
| 217 |
-
# Header
|
| 218 |
with gr.Row():
|
| 219 |
with gr.Column():
|
| 220 |
gr.Markdown("### 𦴠Spine Coder β CPT Billing & Operative Note NLP")
|
|
@@ -224,7 +218,6 @@ with gr.Blocks(theme=THEME, css=CUSTOM_CSS, title="Spine Coder β CPT Billing")
|
|
| 224 |
'<span class="footer-note">No PHI is stored; inputs are session-scoped and ephemeral.</span></div>'
|
| 225 |
)
|
| 226 |
|
| 227 |
-
# Body
|
| 228 |
with gr.Row():
|
| 229 |
# Inputs
|
| 230 |
with gr.Column(scale=5):
|
|
@@ -275,7 +268,6 @@ with gr.Blocks(theme=THEME, css=CUSTOM_CSS, title="Spine Coder β CPT Billing")
|
|
| 275 |
json_out = gr.Code(language="json", value="", interactive=False)
|
| 276 |
warn_md = gr.Markdown("")
|
| 277 |
|
| 278 |
-
# Events
|
| 279 |
def _on_load():
|
| 280 |
sid = new_session()
|
| 281 |
return sid, sid
|
|
@@ -294,5 +286,4 @@ with gr.Blocks(theme=THEME, css=CUSTOM_CSS, title="Spine Coder β CPT Billing")
|
|
| 294 |
export_btn.click(do_export, inputs=[session_id], outputs=[export_file])
|
| 295 |
|
| 296 |
if __name__ == "__main__":
|
| 297 |
-
# Set share=True if you want a public link while testing locally.
|
| 298 |
demo.launch()
|
|
|
|
| 1 |
# app.py β Spine Coder (Chatbot + Feedback + Session Logs) β Gradio 4.x
|
| 2 |
# ------------------------------------------------------------------------------
|
| 3 |
+
# Stable build: fixed annotations, robust normalization, error-safe, aesthetic UI
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 4 |
# ------------------------------------------------------------------------------
|
| 5 |
|
| 6 |
import os
|
|
|
|
| 60 |
if not isinstance(result, dict):
|
| 61 |
return [], {}
|
| 62 |
|
| 63 |
+
# ---------- rows ----------
|
| 64 |
sugg = result.get("suggestions") or []
|
| 65 |
rows: List[Dict[str, Any]] = []
|
| 66 |
for s in sugg:
|
| 67 |
if not isinstance(s, dict):
|
| 68 |
continue
|
| 69 |
conf_val = s.get("confidence")
|
| 70 |
+
conf_out = round(float(conf_val), 2) if isinstance(conf_val, (int, float)) else (conf_val or "")
|
|
|
|
|
|
|
|
|
|
|
|
|
| 71 |
rows.append({
|
| 72 |
"CPT": s.get("cpt", ""),
|
| 73 |
"Modifier": s.get("modifier") or "",
|
| 74 |
+
"Modifiers": ", ".join(s.get("modifiers", [])) if isinstance(s.get("modifiers"), list)
|
| 75 |
+
else (s.get("modifiers") or ""),
|
| 76 |
"Description": s.get("desc", ""),
|
| 77 |
"Rationale": s.get("rationale", ""),
|
| 78 |
"Confidence": conf_out,
|
|
|
|
| 82 |
"Units": s.get("units", 1),
|
| 83 |
})
|
| 84 |
|
| 85 |
+
# ---------- normalize levels ----------
|
| 86 |
+
segs: List[str] = []
|
| 87 |
+
inters: List[str] = []
|
| 88 |
+
lvl_lat: str = ""
|
| 89 |
+
|
| 90 |
levels_obj = result.get("levels")
|
|
|
|
| 91 |
if isinstance(levels_obj, dict):
|
| 92 |
segs = list(levels_obj.get("segments") or [])
|
| 93 |
inters = list(levels_obj.get("interspaces") or [])
|
|
|
|
| 95 |
elif isinstance(levels_obj, list):
|
| 96 |
segs = [str(x) for x in levels_obj]
|
| 97 |
|
| 98 |
+
# ---------- normalize flags ----------
|
| 99 |
flags_obj = result.get("flags")
|
| 100 |
if isinstance(flags_obj, list):
|
| 101 |
flags_list = [str(x) for x in flags_obj]
|
|
|
|
| 104 |
else:
|
| 105 |
flags_list = []
|
| 106 |
|
| 107 |
+
# ---------- meta ----------
|
| 108 |
meta = {
|
| 109 |
"payer": result.get("payer", ""),
|
| 110 |
"region": result.get("region", ""),
|
|
|
|
| 209 |
with gr.Blocks(theme=THEME, css=CUSTOM_CSS, title="Spine Coder β CPT Billing") as demo:
|
| 210 |
session_id = gr.State(new_session())
|
| 211 |
|
|
|
|
| 212 |
with gr.Row():
|
| 213 |
with gr.Column():
|
| 214 |
gr.Markdown("### 𦴠Spine Coder β CPT Billing & Operative Note NLP")
|
|
|
|
| 218 |
'<span class="footer-note">No PHI is stored; inputs are session-scoped and ephemeral.</span></div>'
|
| 219 |
)
|
| 220 |
|
|
|
|
| 221 |
with gr.Row():
|
| 222 |
# Inputs
|
| 223 |
with gr.Column(scale=5):
|
|
|
|
| 268 |
json_out = gr.Code(language="json", value="", interactive=False)
|
| 269 |
warn_md = gr.Markdown("")
|
| 270 |
|
|
|
|
| 271 |
def _on_load():
|
| 272 |
sid = new_session()
|
| 273 |
return sid, sid
|
|
|
|
| 286 |
export_btn.click(do_export, inputs=[session_id], outputs=[export_file])
|
| 287 |
|
| 288 |
if __name__ == "__main__":
|
|
|
|
| 289 |
demo.launch()
|