rajsecrets0 commited on
Commit
38ad37e
·
verified ·
1 Parent(s): a1e9f62

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +249 -0
app.py ADDED
@@ -0,0 +1,249 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import base64
3
+ import requests
4
+ from PIL import Image
5
+ from io import BytesIO
6
+ from pdf2image import convert_from_bytes
7
+ import smtplib
8
+ from email.mime.text import MIMEText
9
+ from email.mime.multipart import MIMEMultipart
10
+ import schedule
11
+ import time
12
+ import threading
13
+
14
+ # Configuration - Replace with your API key
15
+ GEMINI_API_KEY = st.secrets["GEMINI_API_KEY"]
16
+ GEMINI_MODEL = "gemini-2.0-flash"
17
+
18
+ DOCUMENT_TYPES = [
19
+ "Insurance Policies", "Explanation of Benefits (EOBs)",
20
+ "Claims (Approved, Denied, or Pending)", "Visit Summaries",
21
+ "Test Results (Lab Reports, Imaging Reports)",
22
+ "Prescriptions (E-Prescriptions, Handwritten)",
23
+ "Discharge Summaries", "Medical Bills", "Payment Statements",
24
+ "Pharmacy Receipts", "Prior Authorization Requests",
25
+ "Consent Forms", "Referral Letters", "Others"
26
+ ]
27
+
28
+ def initialize_session_state():
29
+ """Initialize all session state variables"""
30
+ if "chat_history" not in st.session_state:
31
+ st.session_state.chat_history = []
32
+ if "processed_doc" not in st.session_state:
33
+ st.session_state.processed_doc = None
34
+ if "doc_preview" not in st.session_state:
35
+ st.session_state.doc_preview = None
36
+ if "reminder_set" not in st.session_state:
37
+ st.session_state.reminder_set = False
38
+
39
+ def encode_file(uploaded_file):
40
+ """Safely encode different file types to base64"""
41
+ try:
42
+ file_bytes = uploaded_file.getvalue()
43
+
44
+ if uploaded_file.type == "application/pdf":
45
+ images = convert_from_bytes(file_bytes, first_page=1, last_page=1)
46
+ if not images:
47
+ raise ValueError("Failed to convert PDF to image")
48
+ img_byte_arr = BytesIO()
49
+ images[0].save(img_byte_arr, format='JPEG')
50
+ return base64.b64encode(img_byte_arr.getvalue()).decode('utf-8')
51
+
52
+ return base64.b64encode(file_bytes).decode('utf-8')
53
+ except Exception as e:
54
+ st.error(f"File processing error: {str(e)}")
55
+ return None
56
+
57
+ def query_gemini(prompt, image_b64=None):
58
+ """Handle Gemini API communication"""
59
+ url = f"https://generativelanguage.googleapis.com/v1/models/{GEMINI_MODEL}:generateContent?key={GEMINI_API_KEY}"
60
+
61
+ parts = [{"text": prompt}]
62
+ if image_b64:
63
+ parts.append({
64
+ "inline_data": {
65
+ "mime_type": "image/jpeg",
66
+ "data": image_b64
67
+ }
68
+ })
69
+
70
+ try:
71
+ response = requests.post(
72
+ url,
73
+ json={"contents": [{"parts": parts}]},
74
+ headers={"Content-Type": "application/json"},
75
+ timeout=30
76
+ )
77
+ response.raise_for_status()
78
+ return response.json()["candidates"][0]["content"]["parts"][0]["text"]
79
+ except Exception as e:
80
+ st.error(f"API Error: {str(e)}")
81
+ return None
82
+
83
+ def process_document():
84
+ """Handle document processing pipeline"""
85
+ uploaded_file = st.session_state.uploaded_file
86
+ if not uploaded_file:
87
+ return
88
+
89
+ try:
90
+ with st.spinner("Analyzing document..."):
91
+ # Convert to base64
92
+ image_b64 = encode_file(uploaded_file)
93
+ if not image_b64:
94
+ return
95
+
96
+ # Generate preview
97
+ if uploaded_file.type == "application/pdf":
98
+ images = convert_from_bytes(uploaded_file.getvalue(), first_page=1, last_page=1)
99
+ st.session_state.doc_preview = images[0]
100
+ else:
101
+ st.session_state.doc_preview = Image.open(uploaded_file)
102
+
103
+ # Classify document
104
+ classify_prompt = f"Classify this healthcare document into one of: {DOCUMENT_TYPES}. Respond only with the category name."
105
+ doc_type = query_gemini(classify_prompt, image_b64) or "Others"
106
+
107
+ # Store results
108
+ st.session_state.processed_doc = {
109
+ "type": doc_type,
110
+ "content": image_b64,
111
+ "summary": query_gemini("Create a detailed structured summary of this healthcare document.", image_b64)
112
+ }
113
+
114
+ except Exception as e:
115
+ st.error(f"Processing failed: {str(e)}")
116
+ st.session_state.processed_doc = None
117
+
118
+ def handle_chat_query():
119
+ """Process user chat input"""
120
+ user_input = st.session_state.chat_input
121
+ if not user_input or not st.session_state.processed_doc:
122
+ return
123
+
124
+ prompt = f"""
125
+ Document Context:
126
+ - Type: {st.session_state.processed_doc['type']}
127
+ - Summary: {st.session_state.processed_doc['summary']}
128
+
129
+ Question: {user_input}
130
+
131
+ Answer concisely and factually. If unsure, state "Information not found".
132
+ """
133
+
134
+ with st.spinner("Generating response..."):
135
+ response = query_gemini(prompt, st.session_state.processed_doc['content'])
136
+
137
+ st.session_state.chat_history.append(("user", user_input))
138
+ st.session_state.chat_history.append(("assistant", response or "Could not generate response"))
139
+
140
+ def send_email_reminder(email, message):
141
+ """Send an email reminder using ProtonMail Bridge"""
142
+ try:
143
+ sender_email = st.secrets["PROTONMAIL_USERNAME"]
144
+ sender_password = st.secrets["PROTONMAIL_PASSWORD"]
145
+
146
+ msg = MIMEMultipart()
147
+ msg['From'] = sender_email
148
+ msg['To'] = email
149
+ msg['Subject'] = "Medicine Reminder"
150
+
151
+ msg.attach(MIMEText(message, 'plain'))
152
+
153
+ with smtplib.SMTP('127.0.0.1', 1025) as smtp:
154
+ smtp.starttls()
155
+ smtp.login(sender_email, sender_password)
156
+ smtp.sendmail(sender_email, email, msg.as_string())
157
+
158
+ st.success("Email reminder sent successfully!")
159
+ except Exception as e:
160
+ st.error(f"Failed to send email: {str(e)}")
161
+
162
+ def schedule_reminder(email, time_str, message):
163
+ """Schedule a medicine reminder"""
164
+ try:
165
+ schedule.every().day.at(time_str).do(send_email_reminder, email, message)
166
+
167
+ # Run the scheduler in a separate thread
168
+ def run_scheduler():
169
+ while True:
170
+ schedule.run_pending()
171
+ time.sleep(1)
172
+
173
+ threading.Thread(target=run_scheduler, daemon=True).start()
174
+
175
+ st.session_state.reminder_set = True
176
+ st.success("Reminder set successfully!")
177
+ except Exception as e:
178
+ st.error(f"Failed to set reminder: {str(e)}")
179
+
180
+ # UI Layout
181
+ def main():
182
+ st.set_page_config(page_title="Healthcare Document Assistant", layout="wide")
183
+ initialize_session_state()
184
+
185
+ # Sidebar Section
186
+ with st.sidebar:
187
+ st.header("Document Management")
188
+
189
+ # Preview above upload button
190
+ if st.session_state.doc_preview:
191
+ st.subheader("Preview")
192
+ st.image(st.session_state.doc_preview, use_container_width=True)
193
+
194
+ # Upload button
195
+ st.file_uploader(
196
+ "Upload Document",
197
+ type=["pdf", "png", "jpg", "jpeg"],
198
+ key="uploaded_file",
199
+ on_change=process_document
200
+ )
201
+
202
+ # Document type below upload button
203
+ if st.session_state.processed_doc:
204
+ st.divider()
205
+ st.subheader("Document Type")
206
+ st.markdown(f"**{st.session_state.processed_doc['type']}**")
207
+
208
+ # Medicine Reminder
209
+ st.divider()
210
+ st.subheader("Medicine Reminder")
211
+
212
+ if not st.session_state.reminder_set:
213
+ email = st.text_input("Enter your email")
214
+ time_str = st.text_input("Enter reminder time (24-hour format, e.g., 14:30)")
215
+ message = st.text_area("Enter reminder message")
216
+
217
+ if st.button("Set Reminder"):
218
+ schedule_reminder(email, time_str, message)
219
+ else:
220
+ st.success("Reminder is already set. You will receive an email at the specified time.")
221
+
222
+ # Main Content
223
+ st.title("Healthcare Document Assistant")
224
+
225
+ if st.session_state.processed_doc:
226
+ # Document Summary
227
+ st.subheader("Document Summary")
228
+ st.markdown(st.session_state.processed_doc['summary'])
229
+
230
+ # Chat Interface
231
+ st.divider()
232
+ st.subheader("Document Q&A")
233
+
234
+ # Chat history
235
+ for role, message in st.session_state.chat_history:
236
+ with st.chat_message(role.capitalize()):
237
+ st.markdown(message)
238
+
239
+ # Chat input
240
+ st.chat_input(
241
+ "Ask about the document...",
242
+ key="chat_input",
243
+ on_submit=handle_chat_query
244
+ )
245
+ else:
246
+ st.info("Please upload a document to begin analysis")
247
+
248
+ if __name__ == "__main__":
249
+ main()