IAMTFRMZA commited on
Commit
6cfdc3b
ยท
verified ยท
1 Parent(s): 29d68fa

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +95 -203
app.py CHANGED
@@ -3,7 +3,6 @@ import os
3
  import time
4
  import re
5
  import requests
6
- import json
7
  from PIL import Image
8
  from io import BytesIO
9
  from urllib.parse import quote
@@ -36,9 +35,9 @@ if not st.session_state.authenticated:
36
  st.stop()
37
 
38
  # ------------------ App Configuration ------------------
39
- st.set_page_config(page_title="Schlager Forrestdale DocAIAssist", layout="wide", initial_sidebar_state="collapsed")
40
- st.title("๐Ÿ“„ Schlager Forrestdale Document Assistant")
41
- st.caption("Explore City of Armadale construction documents using AI + OCR ๐Ÿง")
42
 
43
  # ------------------ Load API Key ------------------
44
  OPENAI_API_KEY = os.environ.get("OPENAI_API_KEY")
@@ -48,227 +47,120 @@ if not OPENAI_API_KEY:
48
 
49
  client = OpenAI(api_key=OPENAI_API_KEY)
50
 
51
- # ------------------ Tabs ------------------
52
- tab1, tab2 = st.tabs(["๐Ÿ“‘ Contract", "๐Ÿ“ Technical"])
53
-
54
- # ------------------ Contract Tab ------------------
55
- with tab1:
56
- ASSISTANT_ID = "asst_KsQRedoJUnEeStzfox1o06lO"
57
-
58
- if "messages" not in st.session_state:
 
 
 
 
 
 
 
 
 
 
 
59
  st.session_state.messages = []
60
- if "thread_id" not in st.session_state:
61
  st.session_state.thread_id = None
62
- if "image_url" not in st.session_state:
63
  st.session_state.image_url = None
64
- if "image_updated" not in st.session_state:
65
  st.session_state.image_updated = False
66
- if "pending_prompt" not in st.session_state:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
67
  st.session_state.pending_prompt = None
68
 
69
- with st.sidebar:
70
- st.header("โ„น๏ธ Contract Tools")
71
- if st.button("๐Ÿงน Clear Chat"):
72
- st.session_state.messages = []
73
- st.session_state.thread_id = None
74
- st.session_state.image_url = None
75
- st.session_state.image_updated = False
76
- st.session_state.pending_prompt = None
77
- st.rerun()
78
-
79
- show_image = st.toggle("๐Ÿ“‘ Show Page Image", value=True)
80
- keyword = st.text_input("Search by Keyword", placeholder="e.g. defects, WHS, delay")
81
- if st.button("๐Ÿ”Ž Search Keyword") and keyword:
82
- st.session_state.pending_prompt = f"Find clauses or references related to: {keyword}"
83
-
84
- section_options = [
85
- "Select a section...",
86
- "1. Formal Instrument of Contract",
87
- "2. Offer and Acceptance",
88
- "3. Key Personnel",
89
- "4. Contract Pricing",
90
- "5. Specifications",
91
- "6. WHS Policies",
92
- "7. Penalties and Delays",
93
- "8. Dispute Resolution",
94
- "9. Principal Obligations"
95
- ]
96
- section = st.selectbox("๐Ÿ“„ Jump to Section", section_options)
97
- if section != section_options[0]:
98
- st.session_state.pending_prompt = f"Summarize or list key points from section: {section}"
99
-
100
- actions = [
101
- "Select an action...",
102
- "List all contractual obligations",
103
- "Summarize payment terms",
104
- "List WHS responsibilities",
105
- "Find delay-related penalties",
106
- "Extract dispute resolution steps"
107
- ]
108
- action = st.selectbox("โš™๏ธ Common Queries", actions)
109
- if action != actions[0]:
110
- st.session_state.pending_prompt = action
111
-
112
- chat_col, image_col = st.columns([2, 1])
113
- with chat_col:
114
- st.markdown("### ๐Ÿง  Ask a Document-Specific Question")
115
- user_input = st.chat_input("Example: What is the defects liability period?")
116
- if user_input:
117
- st.session_state.messages.append({"role": "user", "content": user_input})
118
- elif st.session_state.pending_prompt:
119
- st.session_state.messages.append({"role": "user", "content": st.session_state.pending_prompt})
120
- st.session_state.pending_prompt = None
121
-
122
- if st.session_state.messages and st.session_state.messages[-1]["role"] == "user":
123
- try:
124
- if st.session_state.thread_id is None:
125
- thread = client.beta.threads.create()
126
- st.session_state.thread_id = thread.id
127
-
128
- client.beta.threads.messages.create(
129
- thread_id=st.session_state.thread_id,
130
- role="user",
131
- content=st.session_state.messages[-1]["content"]
132
- )
133
-
134
- run = client.beta.threads.runs.create(
135
- thread_id=st.session_state.thread_id,
136
- assistant_id=ASSISTANT_ID
137
- )
138
-
139
- with st.spinner("๐Ÿค– Thinking..."):
140
- while True:
141
- status = client.beta.threads.runs.retrieve(thread_id=st.session_state.thread_id, run_id=run.id)
142
- if status.status in ("completed", "failed", "cancelled"):
143
- break
144
- time.sleep(1)
145
-
146
- if status.status == "completed":
147
- messages = client.beta.threads.messages.list(thread_id=st.session_state.thread_id)
148
- for m in reversed(messages.data):
149
- if m.role == "assistant":
150
- reply = m.content[0].text.value
151
- st.session_state.messages.append({"role": "assistant", "content": reply})
152
- match = re.search(r'Document Reference:\s*(.*?),\s*Page\s*(\d+)', reply)
153
- if match:
154
- doc, page = match.group(1).strip(), int(match.group(2))
155
- folder = quote(doc)
156
- img_url = f"https://raw.githubusercontent.com/AndrewLORTech/c2ozschlaegerforrestdale/main/{folder}/{folder}_page_{page:04d}.png"
157
- st.session_state.image_url = img_url
158
- st.session_state.image_updated = True
159
- break
160
- else:
161
- st.error("โŒ Assistant failed.")
162
- st.rerun()
163
- except Exception as e:
164
- st.error(f"โŒ Error: {e}")
165
-
166
- for msg in st.session_state.messages:
167
- with st.chat_message(msg["role"]):
168
- st.markdown(msg["content"], unsafe_allow_html=True)
169
-
170
- with image_col:
171
- if show_image and st.session_state.image_url:
172
- try:
173
- r = requests.get(st.session_state.image_url)
174
- r.raise_for_status()
175
- img = Image.open(BytesIO(r.content))
176
- st.image(img, caption="๐Ÿ“„ OCR Page Image", use_container_width=True)
177
- except Exception as e:
178
- st.error(f"๐Ÿ–ผ๏ธ Image failed: {e}")
179
-
180
- # ------------------ Technical Tab ------------------
181
- with tab2:
182
- ASSISTANT_ID = "asst_DjvuWBc7tCvMbAhY7n1em4BZ"
183
- if "tech_messages" not in st.session_state:
184
- st.session_state.tech_messages = []
185
- if "tech_thread_id" not in st.session_state:
186
- st.session_state.tech_thread_id = None
187
- if "tech_results" not in st.session_state:
188
- st.session_state.tech_results = []
189
- st.session_state.tech_lightbox = None
190
-
191
- tech_input = st.chat_input("Ask about plans, drawings or components")
192
- if tech_input:
193
- st.session_state.tech_messages.append({"role": "user", "content": tech_input})
194
-
195
- if st.session_state.tech_messages and st.session_state.tech_messages[-1]["role"] == "user":
196
  try:
197
- if st.session_state.tech_thread_id is None:
198
  thread = client.beta.threads.create()
199
- st.session_state.tech_thread_id = thread.id
200
 
201
  client.beta.threads.messages.create(
202
- thread_id=st.session_state.tech_thread_id,
203
  role="user",
204
- content=st.session_state.tech_messages[-1]["content"]
205
  )
206
 
207
  run = client.beta.threads.runs.create(
208
- thread_id=st.session_state.tech_thread_id,
209
  assistant_id=ASSISTANT_ID
210
  )
211
 
212
- with st.spinner("๐Ÿ” Searching technical drawings..."):
213
  while True:
214
- run_status = client.beta.threads.runs.retrieve(
215
- thread_id=st.session_state.tech_thread_id,
216
- run_id=run.id
217
- )
218
- if run_status.status in ("completed", "failed", "cancelled"):
219
  break
220
  time.sleep(1)
221
 
222
- if run_status.status == "completed":
223
- messages = client.beta.threads.messages.list(thread_id=st.session_state.tech_thread_id)
224
- for msg in reversed(messages.data):
225
- if msg.role == "assistant":
226
- content = msg.content[0].text.value
227
- st.session_state.tech_messages.append({"role": "assistant", "content": content})
228
- try:
229
- st.session_state.tech_results = json.loads(content.strip("`json "))
230
- except:
231
- st.session_state.tech_results = []
 
 
 
232
  break
 
 
 
233
  except Exception as e:
234
- st.error(f"โŒ Technical Assistant Error: {e}")
235
-
236
- with st.expander("๐Ÿ”ง Options (Filter + Pagination)", expanded=False):
237
- disciplines = sorted(set(d.get("discipline", "") for d in st.session_state.tech_results))
238
- selected = st.selectbox("๐ŸŒ Filter by discipline", ["All"] + disciplines)
239
- page_size = 8
240
- page = st.number_input("Page", min_value=1, step=1, value=1)
241
-
242
- if st.session_state.tech_results:
243
- st.subheader("๐Ÿ“‚ Results")
244
- results = [r for r in st.session_state.tech_results if selected == "All" or r.get("discipline") == selected]
245
- paged = results[(page - 1) * page_size : page * page_size]
246
- cols = st.columns(4)
247
- for i, item in enumerate(paged):
248
- with cols[i % 4]:
249
- st.markdown(f"**๐Ÿ“ {item['drawing_number']} ({item['discipline']})**")
250
- st.caption(item.get("summary", ""))
251
 
252
- image_urls = item.get("images", [])
253
- if not image_urls:
254
- st.warning("โš ๏ธ No image available.")
255
- else:
256
- url = image_urls[0]
257
- st.caption(f"๐Ÿ”— Image URL: {url}")
258
- try:
259
- st.image(url, caption=f"{item['drawing_number']} - Page 1", use_container_width=True)
260
- except Exception as e:
261
- st.error(f"โŒ Could not load image: {e}")
262
 
263
- if st.button("๐Ÿ–ผ๏ธ View Drawing Details", key=f"thumb_{i}"):
264
- st.session_state.tech_lightbox = url
265
-
266
- if st.session_state.tech_lightbox:
267
- st.image(st.session_state.tech_lightbox, caption="๐Ÿ” Enlarged Drawing Preview", use_container_width=True)
268
- if st.button("โŒ Close Preview"):
269
- st.session_state.tech_lightbox = None
270
- st.rerun()
271
- else:
272
- for msg in st.session_state.tech_messages:
273
- with st.chat_message(msg["role"]):
274
- st.markdown(msg["content"], unsafe_allow_html=True)
 
3
  import time
4
  import re
5
  import requests
 
6
  from PIL import Image
7
  from io import BytesIO
8
  from urllib.parse import quote
 
35
  st.stop()
36
 
37
  # ------------------ App Configuration ------------------
38
+ st.set_page_config(page_title="Pathology Assistant", layout="wide", initial_sidebar_state="collapsed")
39
+ st.title("๐Ÿงฌ AI Pathology Assistant")
40
+ st.caption("Explore histology, anatomy, and pathology documents using AI + OCR")
41
 
42
  # ------------------ Load API Key ------------------
43
  OPENAI_API_KEY = os.environ.get("OPENAI_API_KEY")
 
47
 
48
  client = OpenAI(api_key=OPENAI_API_KEY)
49
 
50
+ # ------------------ Assistant Configuration ------------------
51
+ ASSISTANT_ID = "your_pathology_assistant_id_here" # Replace with actual ID
52
+
53
+ # ------------------ Session State ------------------
54
+ if "messages" not in st.session_state:
55
+ st.session_state.messages = []
56
+ if "thread_id" not in st.session_state:
57
+ st.session_state.thread_id = None
58
+ if "image_url" not in st.session_state:
59
+ st.session_state.image_url = None
60
+ if "image_updated" not in st.session_state:
61
+ st.session_state.image_updated = False
62
+ if "pending_prompt" not in st.session_state:
63
+ st.session_state.pending_prompt = None
64
+
65
+ # ------------------ Sidebar ------------------
66
+ with st.sidebar:
67
+ st.header("๐Ÿ” Pathology Tools")
68
+ if st.button("๐Ÿงน Clear Chat"):
69
  st.session_state.messages = []
 
70
  st.session_state.thread_id = None
 
71
  st.session_state.image_url = None
 
72
  st.session_state.image_updated = False
73
+ st.session_state.pending_prompt = None
74
+ st.rerun()
75
+
76
+ show_image = st.toggle("๐Ÿ–ผ๏ธ Show Slide Image", value=True)
77
+ keyword = st.text_input("Keyword Search (e.g. mitosis, infarct, carcinoma)")
78
+ if st.button("๐Ÿ”Ž Search Keyword") and keyword:
79
+ st.session_state.pending_prompt = f"Find clauses or references related to: {keyword}"
80
+
81
+ section = st.text_input("๐Ÿง  Section Lookup (e.g. Connective Tissue, Inflammation)")
82
+ if section:
83
+ st.session_state.pending_prompt = f"Summarize or list key points from section: {section}"
84
+
85
+ actions = [
86
+ "Select an action...",
87
+ "List histological features of inflammation",
88
+ "Summarize features of carcinoma",
89
+ "List muscle types and features",
90
+ "Extract diagnostic markers",
91
+ "Summarize embryology stages"
92
+ ]
93
+ action = st.selectbox("โš™๏ธ Common Queries", actions)
94
+ if action != actions[0]:
95
+ st.session_state.pending_prompt = action
96
+
97
+ # ------------------ Main Chat Layout ------------------
98
+ chat_col, image_col = st.columns([2, 1])
99
+
100
+ with chat_col:
101
+ st.markdown("### ๐Ÿ’ฌ Ask a Pathology-Specific Question")
102
+ user_input = st.chat_input("Example: What are features of squamous cell carcinoma?")
103
+ if user_input:
104
+ st.session_state.messages.append({"role": "user", "content": user_input})
105
+ elif st.session_state.pending_prompt:
106
+ st.session_state.messages.append({"role": "user", "content": st.session_state.pending_prompt})
107
  st.session_state.pending_prompt = None
108
 
109
+ if st.session_state.messages and st.session_state.messages[-1]["role"] == "user":
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
110
  try:
111
+ if st.session_state.thread_id is None:
112
  thread = client.beta.threads.create()
113
+ st.session_state.thread_id = thread.id
114
 
115
  client.beta.threads.messages.create(
116
+ thread_id=st.session_state.thread_id,
117
  role="user",
118
+ content=st.session_state.messages[-1]["content"]
119
  )
120
 
121
  run = client.beta.threads.runs.create(
122
+ thread_id=st.session_state.thread_id,
123
  assistant_id=ASSISTANT_ID
124
  )
125
 
126
+ with st.spinner("๐Ÿ”ฌ Analyzing pathology data..."):
127
  while True:
128
+ status = client.beta.threads.runs.retrieve(thread_id=st.session_state.thread_id, run_id=run.id)
129
+ if status.status in ("completed", "failed", "cancelled"):
 
 
 
130
  break
131
  time.sleep(1)
132
 
133
+ if status.status == "completed":
134
+ messages = client.beta.threads.messages.list(thread_id=st.session_state.thread_id)
135
+ for m in reversed(messages.data):
136
+ if m.role == "assistant":
137
+ reply = m.content[0].text.value
138
+ st.session_state.messages.append({"role": "assistant", "content": reply})
139
+ match = re.search(r'Document Reference:\s*(.*?),\s*Page\s*(\d+)', reply)
140
+ if match:
141
+ doc, page = match.group(1).strip(), int(match.group(2))
142
+ folder = quote(doc)
143
+ img_url = f"https://raw.githubusercontent.com/AndrewLORTech/c2ozschlaegerforrestdale/main/{folder}/{folder}_page_{page:04d}.png"
144
+ st.session_state.image_url = img_url
145
+ st.session_state.image_updated = True
146
  break
147
+ else:
148
+ st.error("โŒ Assistant failed.")
149
+ st.rerun()
150
  except Exception as e:
151
+ st.error(f"โŒ Error: {e}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
152
 
153
+ for msg in st.session_state.messages:
154
+ with st.chat_message(msg["role"]):
155
+ st.markdown(msg["content"], unsafe_allow_html=True)
 
 
 
 
 
 
 
156
 
157
+ # ------------------ Image Viewer ------------------
158
+ with image_col:
159
+ if show_image and st.session_state.image_url:
160
+ try:
161
+ r = requests.get(st.session_state.image_url)
162
+ r.raise_for_status()
163
+ img = Image.open(BytesIO(r.content))
164
+ st.image(img, caption="๐Ÿงพ OCR Page Image", use_container_width=True)
165
+ except Exception as e:
166
+ st.error(f"๐Ÿ–ผ๏ธ Image failed: {e}")