coldn00dl3s's picture
Update app.py
df56ffc verified
import streamlit as st
import pandas as pd
import requests
import json
from datetime import datetime
from pdfminer.high_level import extract_text
import regex as re
st.title("FHIR Converter")
# Dropdown for conversion type
conversion_type = st.selectbox(
"Select Conversion Type",
["CSV to FHIR", "CCDA to FHIR", "Clinical Notes to FHIR"]
)
def extract_entries_from_bundles(bundles):
"""
Extracts the 'entry' data from a list of FHIR bundles, including only the first Patient resource encountered.
Parameters:
- bundles: List of JSON strings, each representing a FHIR bundle.
Returns:
- List of all entries from the provided bundles with only the first Patient resource included.
"""
combined_entries = []
patient_included = False # Flag to track if the first Patient has been included
# Iterate through each bundle
for bundle_str in bundles:
try:
# Parse the JSON bundle
bundle = json.loads(bundle_str)
# Ensure the bundle contains the 'entry' key
if 'entry' in bundle:
for entry in bundle['entry']:
resource = entry.get('resource', {})
# Check the resource type
resource_type = resource.get('resourceType')
# Handle Patient resources
if resource_type == 'Patient':
if not patient_included:
# Include the first Patient resource
combined_entries.append(entry)
patient_included = True
continue
# Include all other resource types
combined_entries.append(entry)
else:
print("Warning: Bundle does not contain 'entry' key.")
except json.JSONDecodeError as e:
print(f"Error decoding JSON bundle: {e}")
return combined_entries
def create_combined_bundle(entries):
"""
Creates a new FHIR bundle containing all the entries.
Parameters:
- entries: List of FHIR entries to include in the new bundle.
Returns:
- JSON string representing the new combined FHIR bundle.
"""
combined_bundle = {
"resourceType": "Bundle",
"type": "collection",
"entry": entries
}
return json.dumps(combined_bundle, indent=2)
if conversion_type == "CSV to FHIR":
res_type = st.selectbox(
"Select Resource Type",
["Patient", "CarePlan", "MedicationRequest", "Immunization", "Encounter", "Claim", "Procedure", "Observation"]
)
# File uploader for CSV file
uploaded_file = st.file_uploader("Upload CSV", type=["csv"])
if uploaded_file is not None:
# Display the uploaded CSV file
df = pd.read_csv(uploaded_file)
st.write("Uploaded CSV:")
st.dataframe(df)
# Placeholders for progress bar and time left
progress_bar = st.progress(0)
time_placeholder = st.empty()
items_placeholder = st.empty()
# Variables to store the result and state
result = st.empty()
conversion_successful = False
# Button to trigger conversion
if st.button("Convert"):
# Convert the CSV to FHIR using the FastAPI endpoint
start_time = datetime.now()
total_items = len(df)
try:
files = {"file": uploaded_file.getvalue()}
data = {"res_type": res_type}
response = requests.post("https://fhir-api-9jsn.onrender.com/convert", files=files, data=data, stream=True)
result_text = ""
for chunk in response.iter_lines():
if chunk:
chunk_data = chunk.decode("utf-8")
json_chunk = json.loads(chunk_data)
if "progress" in json_chunk:
progress = json_chunk["progress"]
current_item = json_chunk["current_item"]
total_items = json_chunk["total_items"]
elapsed_time = datetime.now() - start_time
items_per_second = current_item / elapsed_time.total_seconds()
time_left = (total_items - current_item) / items_per_second
progress_bar.progress(int(progress))
time_placeholder.text(f"Time elapsed: {elapsed_time}")
items_placeholder.text(f"Items processed: {current_item}/{total_items}")
elif "output" in json_chunk:
result_text = json_chunk["output"]
elif "error" in json_chunk:
st.error(f"An error occurred: {json_chunk['error']}")
break
if result_text:
result.success("Conversion successful!")
result.text_area("FHIR Output", result_text, height=400)
conversion_successful = True
except Exception as e:
st.error(f"An error occurred: {str(e)}")
# Display validator button
if conversion_successful:
st.markdown("[Go to FHIR Validator](https://validator.fhir.org)", unsafe_allow_html=True)
elif conversion_type == "CCDA to FHIR":
res_type = st.selectbox(
"Select Resource Type",
["Patient", "Encounter", "Observation", "MedicationRequest", "Procedure", "Immunization", "Condition"]
)
cda_content = st.text_area("Enter CCDA Content in XML format")
# Variables to store the result and state
result = st.empty()
conversion_successful = False
# Button to trigger conversion
if st.button("Convert"):
try:
data = {"res_type": res_type, "cda_content": cda_content}
response = requests.post("https://fhir-api-9jsn.onrender.com/convert_ccda", json=data)
if response.status_code == 200:
result_text = response.json().get("output", "")
if result_text:
result.success("Conversion successful!")
result.text_area("FHIR Output", result_text, height=400)
conversion_successful = True
else:
st.error(f"An error occurred: {response.json().get('error', 'Unknown error')}")
except Exception as e:
st.error(f"An error occurred: {str(e)}")
if conversion_successful:
st.markdown("[Go to FHIR Validator](https://validator.fhir.org)", unsafe_allow_html=True)
elif conversion_type == "Clinical Notes to FHIR":
uploaded_pdf = st.file_uploader("Upload PDF with Clinical Notes", type=["pdf"])
# Variables to store the result and state
result = st.empty()
conversion_successful = False
if uploaded_pdf is not None and st.button("Convert"):
try:
# Extract text from PDF
full_text = extract_text(uploaded_pdf)
pattern = r'(?<!\n)\n\n(?![@#\$%\^&\*\(\)\[\]\{\};:,\.])'
paragraphs = re.split(pattern, full_text)
paragraphs.pop(len(paragraphs)-1)
total_paragraphs = len(paragraphs)
if total_paragraphs == 0:
st.warning("No paragraphs found in the PDF.")
start_time = datetime.now()
result_list = []
for i, paragraph in enumerate(paragraphs):
data = {"note_content": paragraph}
response = requests.post("https://fhir-api-9jsn.onrender.com/convert_notes", json=data)
if response.status_code == 200:
result_list.append(response.json().get("output", ""))
else:
st.error(f"An error occurred at paragraph {i + 1}: {response.json().get('error', 'Unknown error')}")
break
entries = extract_entries_from_bundles(result_list)
combined_bundle = create_combined_bundle(entries)
if combined_bundle:
result.success("Conversion successful!")
result.text_area("FHIR Output", combined_bundle, height=400)
conversion_successful = True
except Exception as e:
st.error(f"An error occurred: {str(e)}")
# Display validator button
if conversion_successful:
st.markdown("[Go to FHIR Validator](https://validator.fhir.org)", unsafe_allow_html=True)