Update app.py
Browse files
app.py
CHANGED
|
@@ -28,20 +28,40 @@ def extract_questions_handler(guideline_pdf, surgery_type, suggestions):
|
|
| 28 |
return questions, df
|
| 29 |
|
| 30 |
|
| 31 |
-
def
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 32 |
"""
|
| 33 |
Returns a DataFrame: Question | Answer | Rationale
|
|
|
|
| 34 |
"""
|
| 35 |
if patient_pdf is None:
|
| 36 |
raise gr.Error("Please upload a patient chart PDF.")
|
| 37 |
-
if not
|
| 38 |
-
raise gr.Error("No
|
| 39 |
|
| 40 |
pdf_path = patient_pdf.name if hasattr(patient_pdf, "name") else str(patient_pdf)
|
| 41 |
a_engine = AnsweringEngine(pdf_path)
|
| 42 |
|
| 43 |
rows = []
|
| 44 |
-
for q in
|
| 45 |
res: Dict[str, Dict[str, str]] = a_engine.answer_one(q)
|
| 46 |
ans = res.get(q, {})
|
| 47 |
rows.append({
|
|
@@ -57,6 +77,10 @@ def answer_questions_handler(patient_pdf, questions_state):
|
|
| 57 |
with gr.Blocks(title="Guideline β Questions β Chart Answers", theme="soft") as demo:
|
| 58 |
gr.Markdown("# π₯ Guideline Q&A (Yes/No) β with Iterative Feedback")
|
| 59 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 60 |
with gr.Tabs():
|
| 61 |
with gr.Tab("1) Extract Questions"):
|
| 62 |
with gr.Row():
|
|
@@ -68,7 +92,6 @@ with gr.Blocks(title="Guideline β Questions β Chart Answers", theme="soft")
|
|
| 68 |
)
|
| 69 |
extract_btn = gr.Button("Extract Yes/No Questions", variant="primary")
|
| 70 |
|
| 71 |
-
questions_state = gr.State([]) # list[str]
|
| 72 |
questions_df = gr.Dataframe(headers=["#", "Question"], interactive=False, wrap=True)
|
| 73 |
gr.Markdown("If the questions need refinement, update 'Suggestions' and click the button again.")
|
| 74 |
|
|
@@ -83,13 +106,42 @@ with gr.Blocks(title="Guideline β Questions β Chart Answers", theme="soft")
|
|
| 83 |
)
|
| 84 |
|
| 85 |
with gr.Tab("2) Answer from Patient Chart"):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 86 |
patient_pdf = gr.File(label="Upload Patient Chart PDF (e.g., JAY_MORGAN.pdf)", file_count="single")
|
| 87 |
-
answer_btn = gr.Button("Answer All Questions", variant="primary")
|
| 88 |
answers_df = gr.Dataframe(headers=["Question", "Answer", "Rationale"], interactive=False, wrap=True)
|
| 89 |
|
|
|
|
|
|
|
|
|
|
| 90 |
answer_btn.click(
|
| 91 |
-
fn=
|
| 92 |
-
inputs=[patient_pdf,
|
| 93 |
outputs=answers_df,
|
| 94 |
)
|
| 95 |
|
|
@@ -98,6 +150,7 @@ with gr.Blocks(title="Guideline β Questions β Chart Answers", theme="soft")
|
|
| 98 |
"- Embeddings are cached under `./embeddings/<PDF-name>/` to avoid recomputation.\n"
|
| 99 |
"- Set your OpenAI key: `export OPENAI_API_KEY=...` before running.\n"
|
| 100 |
"- If a PDF is scanned/image-only, text extraction may be poor (consider OCR pre-processing).\n"
|
|
|
|
| 101 |
)
|
| 102 |
|
| 103 |
if __name__ == "__main__":
|
|
|
|
| 28 |
return questions, df
|
| 29 |
|
| 30 |
|
| 31 |
+
def preview_questions_handler(qs: List[str]):
|
| 32 |
+
"""Return a read-only preview table for any list of questions."""
|
| 33 |
+
if not qs:
|
| 34 |
+
return pd.DataFrame({"#": [], "Question": []}), "No questions available."
|
| 35 |
+
df = pd.DataFrame({"#": list(range(1, len(qs) + 1)), "Question": qs})
|
| 36 |
+
return df, f"{len(qs)} questions in the list."
|
| 37 |
+
|
| 38 |
+
|
| 39 |
+
def lock_questions_handler(qs: List[str]):
|
| 40 |
+
"""
|
| 41 |
+
Freeze the current questions into a locked snapshot to ensure we ask the 'earlier' ones.
|
| 42 |
+
Returns (locked_list, locked_df, msg)
|
| 43 |
+
"""
|
| 44 |
+
if not qs:
|
| 45 |
+
raise gr.Error("No questions to lock. Extract questions in Tab 1 first.")
|
| 46 |
+
df = pd.DataFrame({"#": list(range(1, len(qs) + 1)), "Question": qs})
|
| 47 |
+
return qs, df, f"π Locked {len(qs)} questions. These will be used for answering until you lock again."
|
| 48 |
+
|
| 49 |
+
|
| 50 |
+
def answer_questions_handler(patient_pdf, locked_qs: List[str]):
|
| 51 |
"""
|
| 52 |
Returns a DataFrame: Question | Answer | Rationale
|
| 53 |
+
(Answers only the LOCKED questions to guarantee earlier list is used.)
|
| 54 |
"""
|
| 55 |
if patient_pdf is None:
|
| 56 |
raise gr.Error("Please upload a patient chart PDF.")
|
| 57 |
+
if not locked_qs:
|
| 58 |
+
raise gr.Error("No locked questions. Click βπ Lock questions for answeringβ first.")
|
| 59 |
|
| 60 |
pdf_path = patient_pdf.name if hasattr(patient_pdf, "name") else str(patient_pdf)
|
| 61 |
a_engine = AnsweringEngine(pdf_path)
|
| 62 |
|
| 63 |
rows = []
|
| 64 |
+
for q in locked_qs:
|
| 65 |
res: Dict[str, Dict[str, str]] = a_engine.answer_one(q)
|
| 66 |
ans = res.get(q, {})
|
| 67 |
rows.append({
|
|
|
|
| 77 |
with gr.Blocks(title="Guideline β Questions β Chart Answers", theme="soft") as demo:
|
| 78 |
gr.Markdown("# π₯ Guideline Q&A (Yes/No) β with Iterative Feedback")
|
| 79 |
|
| 80 |
+
# States:
|
| 81 |
+
questions_state = gr.State([]) # live list (can be regenerated in Tab 1)
|
| 82 |
+
questions_locked = gr.State([]) # frozen snapshot used for answering
|
| 83 |
+
|
| 84 |
with gr.Tabs():
|
| 85 |
with gr.Tab("1) Extract Questions"):
|
| 86 |
with gr.Row():
|
|
|
|
| 92 |
)
|
| 93 |
extract_btn = gr.Button("Extract Yes/No Questions", variant="primary")
|
| 94 |
|
|
|
|
| 95 |
questions_df = gr.Dataframe(headers=["#", "Question"], interactive=False, wrap=True)
|
| 96 |
gr.Markdown("If the questions need refinement, update 'Suggestions' and click the button again.")
|
| 97 |
|
|
|
|
| 106 |
)
|
| 107 |
|
| 108 |
with gr.Tab("2) Answer from Patient Chart"):
|
| 109 |
+
gr.Markdown("#### Step A β Confirm the questions to be asked")
|
| 110 |
+
|
| 111 |
+
# Preview current (live) questions
|
| 112 |
+
preview_btn = gr.Button("Preview current questions from Tab 1")
|
| 113 |
+
preview_df = gr.Dataframe(headers=["#", "Question"], interactive=False, wrap=True)
|
| 114 |
+
preview_msg = gr.Markdown()
|
| 115 |
+
|
| 116 |
+
preview_btn.click(
|
| 117 |
+
fn=preview_questions_handler,
|
| 118 |
+
inputs=[questions_state],
|
| 119 |
+
outputs=[preview_df, preview_msg],
|
| 120 |
+
)
|
| 121 |
+
|
| 122 |
+
# Lock questions (freeze snapshot)
|
| 123 |
+
lock_btn = gr.Button("π Lock questions for answering", variant="secondary")
|
| 124 |
+
locked_df = gr.Dataframe(headers=["#", "Question"], interactive=False, wrap=True)
|
| 125 |
+
locked_msg = gr.Markdown()
|
| 126 |
+
|
| 127 |
+
lock_btn.click(
|
| 128 |
+
fn=lock_questions_handler,
|
| 129 |
+
inputs=[questions_state],
|
| 130 |
+
outputs=[questions_locked, locked_df, locked_msg],
|
| 131 |
+
)
|
| 132 |
+
|
| 133 |
+
gr.Markdown("#### Step B β Answer the locked questions from the patient chart")
|
| 134 |
+
|
| 135 |
patient_pdf = gr.File(label="Upload Patient Chart PDF (e.g., JAY_MORGAN.pdf)", file_count="single")
|
| 136 |
+
answer_btn = gr.Button("Answer All Locked Questions", variant="primary")
|
| 137 |
answers_df = gr.Dataframe(headers=["Question", "Answer", "Rationale"], interactive=False, wrap=True)
|
| 138 |
|
| 139 |
+
def answer_locked_handler(patient_file, locked_qs):
|
| 140 |
+
return answer_questions_handler(patient_file, locked_qs)
|
| 141 |
+
|
| 142 |
answer_btn.click(
|
| 143 |
+
fn=answer_locked_handler,
|
| 144 |
+
inputs=[patient_pdf, questions_locked],
|
| 145 |
outputs=answers_df,
|
| 146 |
)
|
| 147 |
|
|
|
|
| 150 |
"- Embeddings are cached under `./embeddings/<PDF-name>/` to avoid recomputation.\n"
|
| 151 |
"- Set your OpenAI key: `export OPENAI_API_KEY=...` before running.\n"
|
| 152 |
"- If a PDF is scanned/image-only, text extraction may be poor (consider OCR pre-processing).\n"
|
| 153 |
+
"- Use the **lock** step to ensure the earlier questions are exactly the ones being answered.\n"
|
| 154 |
)
|
| 155 |
|
| 156 |
if __name__ == "__main__":
|