Commit
·
ad8bdfe
1
Parent(s):
0309978
Update interface.py
Browse files- interface.py +62 -54
interface.py
CHANGED
@@ -1,8 +1,9 @@
|
|
1 |
import re, uuid
|
2 |
import base64
|
3 |
-
|
4 |
import bcrypt
|
5 |
import gradio as gr
|
|
|
6 |
from gradio_pdf import PDF
|
7 |
from pathlib import Path
|
8 |
import time
|
@@ -14,6 +15,8 @@ from fpdf import FPDF
|
|
14 |
REPORT_DIR = Path("reports")
|
15 |
REPORT_DIR.mkdir(exist_ok=True)
|
16 |
SALT = b'$2b$12$MC7djiqmIR7154Syul5Wme'
|
|
|
|
|
17 |
|
18 |
USERS = {
|
19 |
'test_user': b'$2b$12$MC7djiqmIR7154Syul5WmeQwebwsNOK5svMX08zMYhvpF9P9IVXe6',
|
@@ -100,7 +103,7 @@ class ChatInterface:
|
|
100 |
return history, gr.Textbox(value=message, interactive=False)
|
101 |
|
102 |
async def process_message(
|
103 |
-
self, message: str, display_image: Optional[str], chat_history: List[ChatMessage]
|
104 |
) -> AsyncGenerator[Tuple[List[ChatMessage], Optional[str], str], None]:
|
105 |
"""
|
106 |
Process a message and generate responses.
|
@@ -197,6 +200,55 @@ class ChatInterface:
|
|
197 |
)
|
198 |
yield chat_history, self.display_file_path
|
199 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
200 |
|
201 |
def create_demo(agent, tools_dict):
|
202 |
"""
|
@@ -210,6 +262,7 @@ def create_demo(agent, tools_dict):
|
|
210 |
gr.Blocks: Gradio Blocks interface
|
211 |
"""
|
212 |
interface = ChatInterface(agent, tools_dict)
|
|
|
213 |
|
214 |
with gr.Blocks(theme=gr.themes.Soft()) as demo:
|
215 |
auth_state = gr.State(False)
|
@@ -257,15 +310,6 @@ def create_demo(agent, tools_dict):
|
|
257 |
image_display = gr.Image(
|
258 |
label="Image", type="filepath", height=685, container=True
|
259 |
)
|
260 |
-
# with gr.Row():
|
261 |
-
# upload_button = gr.UploadButton(
|
262 |
-
# "📎 Upload X-Ray",
|
263 |
-
# file_types=["image"],
|
264 |
-
# )
|
265 |
-
# dicom_upload = gr.UploadButton(
|
266 |
-
# "📄 Upload DICOM",
|
267 |
-
# file_types=["file"],
|
268 |
-
# )
|
269 |
with gr.Row():
|
270 |
analyze_btn = gr.Button("Analyze 1")
|
271 |
analyze2_btn = gr.Button("Analyze 2")
|
@@ -276,39 +320,26 @@ def create_demo(agent, tools_dict):
|
|
276 |
|
277 |
with gr.Tab(label="Report section"):
|
278 |
generate_report_btn = gr.Button("Generate Report")
|
279 |
-
# diseases_df = gr.Dataframe(
|
280 |
-
# headers=["Disease", "Info"],
|
281 |
-
# datatype=["str", "str"],
|
282 |
-
# interactive=False, visible=False, max_height=220)
|
283 |
conclusion_tb = gr.Textbox(label="Conclusion", interactive=False)
|
284 |
with gr.Row():
|
285 |
approve_btn = gr.Button("Approve", visible=False)
|
286 |
-
# reject_btn = gr.Button("Reject", visible=False)
|
287 |
download_pdf_btn = gr.DownloadButton(label="📥 Download PDF", visible=False)
|
288 |
-
# pdf_preview = gr.HTML(visible=False)
|
289 |
-
# pdf_preview = gr.File(visible=False)
|
290 |
pdf_preview = PDF(visible=False)
|
291 |
-
# rejection_text = gr.Textbox(
|
292 |
-
# show_label=False,
|
293 |
-
# visible=False,
|
294 |
-
# placeholder="Tell us what is wrong with the report",
|
295 |
-
# container=False,
|
296 |
-
# interactive=True
|
297 |
-
# )
|
298 |
-
# with gr.Row():
|
299 |
-
# submit_reject_btn = gr.Button("Submit", visible=False)
|
300 |
-
# cancel_reject_btn = gr.Button("Cancel", visible=False)
|
301 |
|
302 |
# Event handlers
|
303 |
def authenticate(username, password):
|
304 |
hashed = USERS.get(username)
|
305 |
if hashed and bcrypt.checkpw(password.encode(), hashed):
|
|
|
|
|
|
|
306 |
return (
|
307 |
gr.update(visible=False), # hide login
|
308 |
gr.update(visible=True), # show main
|
309 |
gr.update(visible=False), # hide error
|
310 |
True # set state
|
311 |
)
|
|
|
312 |
return None, None, gr.update(value="❌ Incorrect username or password", visible=True), False
|
313 |
|
314 |
def clear_chat():
|
@@ -336,10 +367,8 @@ def create_demo(agent, tools_dict):
|
|
336 |
return (
|
337 |
gr.update(value=result["Conclusion"], lines=4, interactive=True),
|
338 |
gr.update(visible=True),
|
339 |
-
|
340 |
-
|
341 |
-
|
342 |
-
# def records_to_pdf(table, conclusion) -> Path:
|
343 |
def records_to_pdf(conclusion) -> Path:
|
344 |
"""
|
345 |
Writes a PDF report under ./reports/ and returns the Path.
|
@@ -351,28 +380,14 @@ def create_demo(agent, tools_dict):
|
|
351 |
|
352 |
pdf.cell(0, 10, "Chest-X-ray Report", ln=1, align="C")
|
353 |
pdf.ln(4)
|
354 |
-
|
355 |
-
# pdf.set_font(family="Helvetica", style="B")
|
356 |
-
# pdf.cell(60, 8, "Disease")
|
357 |
-
# pdf.cell(0, 8, "Information", ln=1)
|
358 |
-
# pdf.set_font(family="Helvetica", style="")
|
359 |
-
|
360 |
-
# for idx, row in table.iterrows():
|
361 |
-
# pdf.multi_cell(0, 8, f"{row['Disease']}: {row['Info']}")
|
362 |
-
|
363 |
-
# pdf.ln(4)
|
364 |
-
# pdf.set_font(family="Helvetica", style="B")
|
365 |
-
# pdf.cell(0, 8, "Conclusion", ln=1)
|
366 |
pdf.set_font(family="Helvetica", style="")
|
367 |
pdf.multi_cell(0, 8, conclusion)
|
368 |
|
369 |
pdf_path = REPORT_DIR / f"report_{uuid.uuid4().hex}.pdf"
|
370 |
pdf.output(str(pdf_path))
|
371 |
return pdf_path
|
372 |
-
|
373 |
-
# def build_pdf_and_preview(table, conclusion):
|
374 |
def build_pdf_and_preview(conclusion):
|
375 |
-
# pdf_path = records_to_pdf(table, conclusion)
|
376 |
pdf_path = records_to_pdf(conclusion)
|
377 |
|
378 |
iframe_html = (
|
@@ -433,13 +448,8 @@ def create_demo(agent, tools_dict):
|
|
433 |
outputs=[chatbot, image_display, txt],
|
434 |
).then(lambda: gr.Textbox(interactive=True), None, [txt])
|
435 |
|
436 |
-
# upload_button.upload(handle_file_upload, inputs=upload_button, outputs=[image_display])
|
437 |
-
|
438 |
-
# dicom_upload.upload(handle_file_upload, inputs=dicom_upload, outputs=[image_display])
|
439 |
-
|
440 |
clear_btn.click(clear_chat, outputs=[chatbot, image_display])
|
441 |
new_thread_btn.click(new_thread, outputs=[chatbot, image_display, conclusion_tb, approve_btn, download_pdf_btn, pdf_preview])
|
442 |
-
# generate_report_btn.click(generate_report, outputs=[diseases_df, conclusion_tb, approve_btn, reject_btn])
|
443 |
generate_report_btn.click(generate_report, outputs=[conclusion_tb, approve_btn])
|
444 |
approve_btn.click(
|
445 |
build_pdf_and_preview,
|
@@ -447,7 +457,5 @@ def create_demo(agent, tools_dict):
|
|
447 |
inputs=[conclusion_tb],
|
448 |
outputs=[download_pdf_btn, pdf_preview],
|
449 |
)
|
450 |
-
# reject_btn.click(show_reject_ui, outputs=[rejection_text, submit_reject_btn, cancel_reject_btn])
|
451 |
-
# cancel_reject_btn.click(hide_reject_ui, outputs=[rejection_text, submit_reject_btn, cancel_reject_btn])
|
452 |
|
453 |
return demo
|
|
|
1 |
import re, uuid
|
2 |
import base64
|
3 |
+
import os
|
4 |
import bcrypt
|
5 |
import gradio as gr
|
6 |
+
import boto3
|
7 |
from gradio_pdf import PDF
|
8 |
from pathlib import Path
|
9 |
import time
|
|
|
15 |
REPORT_DIR = Path("reports")
|
16 |
REPORT_DIR.mkdir(exist_ok=True)
|
17 |
SALT = b'$2b$12$MC7djiqmIR7154Syul5Wme'
|
18 |
+
s3_client = boto3.client("s3", region_name="ca-central-1", aws_access_key_id=os.getenv("AWS_ACCESS_KEY"), aws_secret_access_key=os.getenv("AWS_SECRET_KEY"))
|
19 |
+
BUCKET_NAME = "molx-data-storage"
|
20 |
|
21 |
USERS = {
|
22 |
'test_user': b'$2b$12$MC7djiqmIR7154Syul5WmeQwebwsNOK5svMX08zMYhvpF9P9IVXe6',
|
|
|
103 |
return history, gr.Textbox(value=message, interactive=False)
|
104 |
|
105 |
async def process_message(
|
106 |
+
self, message: str, display_image: Optional[str], chat_history: List[ChatMessage], session_details: dict
|
107 |
) -> AsyncGenerator[Tuple[List[ChatMessage], Optional[str], str], None]:
|
108 |
"""
|
109 |
Process a message and generate responses.
|
|
|
200 |
)
|
201 |
yield chat_history, self.display_file_path
|
202 |
|
203 |
+
finally:
|
204 |
+
store_chat_history(session_details['username'], session_details['session_id'], chat_history)
|
205 |
+
|
206 |
+
def store_chat_history(username, session_id, chat_history):
|
207 |
+
"""
|
208 |
+
Store the chat history (Agent responses) in S3 as a text file with a unique name.
|
209 |
+
|
210 |
+
Args:
|
211 |
+
username (str): The username of the user.
|
212 |
+
session_id (str): A unique session identifier.
|
213 |
+
chat_history (list): A list of agent responses to be saved in the text file.
|
214 |
+
|
215 |
+
Returns:
|
216 |
+
str: The URL of the uploaded chat history in S3.
|
217 |
+
"""
|
218 |
+
chat_history_text = "\n".join(chat_history)
|
219 |
+
timestamp = str(int(time.time())) # Get current timestamp for unique name
|
220 |
+
chat_history_path = f"/tmp/{session_id}_chat_history_{timestamp}.txt"
|
221 |
+
|
222 |
+
with open(chat_history_path, "w") as f:
|
223 |
+
f.write(chat_history_text)
|
224 |
+
|
225 |
+
# Upload chat history to S3 with the timestamp
|
226 |
+
return upload_to_s3(chat_history_path, username, session_id)
|
227 |
+
|
228 |
+
|
229 |
+
def upload_to_s3(file_path, username, session_id):
|
230 |
+
"""
|
231 |
+
Upload a file to S3 under the user's folder and session ID.
|
232 |
+
|
233 |
+
Args:
|
234 |
+
file_path (str): The path to the file to upload.
|
235 |
+
username (str): The username of the user.
|
236 |
+
session_id (str): A unique session identifier.
|
237 |
+
file_type (str): The type of file being uploaded (image, report, etc.).
|
238 |
+
|
239 |
+
Returns:
|
240 |
+
str: The URL of the uploaded file in S3.
|
241 |
+
"""
|
242 |
+
# Define the S3 object key
|
243 |
+
file_name = Path(file_path).name
|
244 |
+
s3_key = f"{username}/{session_id}/{file_name}"
|
245 |
+
|
246 |
+
# Upload the file to S3
|
247 |
+
s3_client.upload_file(file_path, BUCKET_NAME, s3_key)
|
248 |
+
|
249 |
+
# Generate the file URL
|
250 |
+
file_url = f"https://{BUCKET_NAME}.s3.amazonaws.com/{s3_key}"
|
251 |
+
return file_url
|
252 |
|
253 |
def create_demo(agent, tools_dict):
|
254 |
"""
|
|
|
262 |
gr.Blocks: Gradio Blocks interface
|
263 |
"""
|
264 |
interface = ChatInterface(agent, tools_dict)
|
265 |
+
session_details = {}
|
266 |
|
267 |
with gr.Blocks(theme=gr.themes.Soft()) as demo:
|
268 |
auth_state = gr.State(False)
|
|
|
310 |
image_display = gr.Image(
|
311 |
label="Image", type="filepath", height=685, container=True
|
312 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
313 |
with gr.Row():
|
314 |
analyze_btn = gr.Button("Analyze 1")
|
315 |
analyze2_btn = gr.Button("Analyze 2")
|
|
|
320 |
|
321 |
with gr.Tab(label="Report section"):
|
322 |
generate_report_btn = gr.Button("Generate Report")
|
|
|
|
|
|
|
|
|
323 |
conclusion_tb = gr.Textbox(label="Conclusion", interactive=False)
|
324 |
with gr.Row():
|
325 |
approve_btn = gr.Button("Approve", visible=False)
|
|
|
326 |
download_pdf_btn = gr.DownloadButton(label="📥 Download PDF", visible=False)
|
|
|
|
|
327 |
pdf_preview = PDF(visible=False)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
328 |
|
329 |
# Event handlers
|
330 |
def authenticate(username, password):
|
331 |
hashed = USERS.get(username)
|
332 |
if hashed and bcrypt.checkpw(password.encode(), hashed):
|
333 |
+
session_details["username"] = username
|
334 |
+
session_details["session_id"] = str(uuid.uuid4()) + str(time.time())
|
335 |
+
|
336 |
return (
|
337 |
gr.update(visible=False), # hide login
|
338 |
gr.update(visible=True), # show main
|
339 |
gr.update(visible=False), # hide error
|
340 |
True # set state
|
341 |
)
|
342 |
+
|
343 |
return None, None, gr.update(value="❌ Incorrect username or password", visible=True), False
|
344 |
|
345 |
def clear_chat():
|
|
|
367 |
return (
|
368 |
gr.update(value=result["Conclusion"], lines=4, interactive=True),
|
369 |
gr.update(visible=True),
|
370 |
+
)
|
371 |
+
|
|
|
|
|
372 |
def records_to_pdf(conclusion) -> Path:
|
373 |
"""
|
374 |
Writes a PDF report under ./reports/ and returns the Path.
|
|
|
380 |
|
381 |
pdf.cell(0, 10, "Chest-X-ray Report", ln=1, align="C")
|
382 |
pdf.ln(4)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
383 |
pdf.set_font(family="Helvetica", style="")
|
384 |
pdf.multi_cell(0, 8, conclusion)
|
385 |
|
386 |
pdf_path = REPORT_DIR / f"report_{uuid.uuid4().hex}.pdf"
|
387 |
pdf.output(str(pdf_path))
|
388 |
return pdf_path
|
389 |
+
|
|
|
390 |
def build_pdf_and_preview(conclusion):
|
|
|
391 |
pdf_path = records_to_pdf(conclusion)
|
392 |
|
393 |
iframe_html = (
|
|
|
448 |
outputs=[chatbot, image_display, txt],
|
449 |
).then(lambda: gr.Textbox(interactive=True), None, [txt])
|
450 |
|
|
|
|
|
|
|
|
|
451 |
clear_btn.click(clear_chat, outputs=[chatbot, image_display])
|
452 |
new_thread_btn.click(new_thread, outputs=[chatbot, image_display, conclusion_tb, approve_btn, download_pdf_btn, pdf_preview])
|
|
|
453 |
generate_report_btn.click(generate_report, outputs=[conclusion_tb, approve_btn])
|
454 |
approve_btn.click(
|
455 |
build_pdf_and_preview,
|
|
|
457 |
inputs=[conclusion_tb],
|
458 |
outputs=[download_pdf_btn, pdf_preview],
|
459 |
)
|
|
|
|
|
460 |
|
461 |
return demo
|