Fernando Moreno commited on
Commit
4ebcec2
·
1 Parent(s): 2d2d2d9

Enhanced progression analysis with automatic timepoint organization

Browse files
Files changed (1) hide show
  1. app.py +96 -41
app.py CHANGED
@@ -8,6 +8,7 @@ import io
8
  from datetime import datetime
9
  import pandas as pd
10
  from collections import defaultdict
 
11
 
12
  # Page configuration
13
  st.set_page_config(
@@ -195,6 +196,44 @@ def analyze_progression(timepoints_data):
195
  response = model.generate_content(content)
196
  return response.text
197
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
198
  def main():
199
  # Header
200
  st.markdown("""
@@ -227,7 +266,7 @@ def main():
227
 
228
  # Scan Analysis Section
229
  st.markdown("### Pentacam Scan Analysis")
230
- analysis_type = st.radio("Select Analysis Type", ["Single Timepoint", "Multiple Timepoint Progression"])
231
 
232
  if analysis_type == "Single Timepoint":
233
  st.markdown('<div class="upload-section">', unsafe_allow_html=True)
@@ -261,54 +300,70 @@ def main():
261
 
262
  st.markdown('</div>', unsafe_allow_html=True)
263
 
264
- else: # Multiple Timepoint Progression
265
  st.markdown('<div class="upload-section">', unsafe_allow_html=True)
266
- st.info("Upload scans from multiple timepoints to analyze progression")
 
267
 
268
- # Create a dynamic form for multiple timepoints
269
- timepoints_data = defaultdict(list)
270
- num_timepoints = st.number_input("Number of Timepoints", min_value=2, max_value=10, value=3)
 
 
271
 
272
- st.markdown('<div class="timeline-container">', unsafe_allow_html=True)
273
- for i in range(num_timepoints):
274
- st.markdown(f'<div class="timepoint-card">', unsafe_allow_html=True)
275
- col1, col2 = st.columns([1, 3])
276
-
277
- with col1:
278
- date = st.date_input(f"Date - Timepoint {i+1}", key=f"date_{i}")
279
 
280
- with col2:
281
- files = st.file_uploader(
282
- f"Upload Scans - Timepoint {i+1}",
283
- type=['png', 'jpg', 'jpeg'],
284
- accept_multiple_files=True,
285
- key=f"files_{i}"
286
- )
287
 
288
- if files:
 
 
 
 
289
  images = []
290
- for file in files:
291
- image = Image.open(file)
292
- images.append(image)
293
- timepoints_data[date.strftime("%Y-%m-%d")].extend(images)
294
 
295
- if images:
296
- cols = st.columns(len(images))
297
- for idx, (col, img) in enumerate(zip(cols, images)):
298
- with col:
299
- st.image(img, caption=f"Scan {idx + 1}", use_column_width=True)
300
-
301
- st.markdown('</div>', unsafe_allow_html=True)
302
- st.markdown('</div>', unsafe_allow_html=True)
303
-
304
- if timepoints_data and len(timepoints_data) >= 2:
305
- if st.button("Analyze Progression"):
306
- with st.spinner("Analyzing progression across timepoints..."):
307
- progression_analysis = analyze_progression(timepoints_data)
308
- st.markdown("### Progression Analysis Results")
309
- st.markdown('<div class="analysis-container">', unsafe_allow_html=True)
310
- st.markdown(progression_analysis)
311
  st.markdown('</div>', unsafe_allow_html=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
312
 
313
  st.markdown('</div>', unsafe_allow_html=True)
314
 
 
8
  from datetime import datetime
9
  import pandas as pd
10
  from collections import defaultdict
11
+ import re
12
 
13
  # Page configuration
14
  st.set_page_config(
 
196
  response = model.generate_content(content)
197
  return response.text
198
 
199
+ def extract_date_from_filename(filename):
200
+ """Extract date from filename using common patterns"""
201
+ # Common date patterns (add more patterns if needed)
202
+ patterns = [
203
+ r'(\d{4}[-_/]\d{2}[-_/]\d{2})', # YYYY-MM-DD, YYYY_MM_DD
204
+ r'(\d{2}[-_/]\d{2}[-_/]\d{4})', # DD-MM-YYYY, DD_MM_YYYY
205
+ r'(\d{8})', # YYYYMMDD
206
+ ]
207
+
208
+ for pattern in patterns:
209
+ match = re.search(pattern, filename)
210
+ if match:
211
+ date_str = match.group(1)
212
+ try:
213
+ # Try different date formats
214
+ for fmt in ['%Y-%m-%d', '%Y_%m_%d', '%d-%m-%Y', '%d_%m_%Y', '%Y%m%d']:
215
+ try:
216
+ return datetime.strptime(date_str.replace('/', '-'), fmt).strftime('%Y-%m-%d')
217
+ except ValueError:
218
+ continue
219
+ except ValueError:
220
+ continue
221
+ return None
222
+
223
+ def organize_scans_by_date(files):
224
+ """Organize uploaded files by their dates"""
225
+ organized_files = defaultdict(list)
226
+ unorganized_files = []
227
+
228
+ for file in files:
229
+ date = extract_date_from_filename(file.name)
230
+ if date:
231
+ organized_files[date].append(file)
232
+ else:
233
+ unorganized_files.append(file)
234
+
235
+ return organized_files, unorganized_files
236
+
237
  def main():
238
  # Header
239
  st.markdown("""
 
266
 
267
  # Scan Analysis Section
268
  st.markdown("### Pentacam Scan Analysis")
269
+ analysis_type = st.radio("Select Analysis Type", ["Single Timepoint", "Progression Analysis"])
270
 
271
  if analysis_type == "Single Timepoint":
272
  st.markdown('<div class="upload-section">', unsafe_allow_html=True)
 
300
 
301
  st.markdown('</div>', unsafe_allow_html=True)
302
 
303
+ else: # Progression Analysis
304
  st.markdown('<div class="upload-section">', unsafe_allow_html=True)
305
+ st.info("""Upload all your Pentacam scans at once. The system will automatically organize them by date and analyze progression.
306
+ For best results, ensure your scan filenames include dates (e.g., 'scan_2023-01-15.jpg' or 'pentacam_20230115.png')""")
307
 
308
+ uploaded_files = st.file_uploader(
309
+ "Upload All Pentacam Scans",
310
+ type=['png', 'jpg', 'jpeg'],
311
+ accept_multiple_files=True
312
+ )
313
 
314
+ if uploaded_files:
315
+ organized_files, unorganized_files = organize_scans_by_date(uploaded_files)
 
 
 
 
 
316
 
317
+ if organized_files:
318
+ st.markdown("### Organized Scans by Date")
319
+ st.markdown('<div class="timeline-container">', unsafe_allow_html=True)
320
+
321
+ timepoints_data = defaultdict(list)
322
+ dates = sorted(organized_files.keys())
 
323
 
324
+ for date in dates:
325
+ st.markdown(f'<div class="timepoint-card">', unsafe_allow_html=True)
326
+ st.markdown(f"#### Timepoint: {date}")
327
+
328
+ files = organized_files[date]
329
  images = []
330
+ cols = st.columns(len(files))
 
 
 
331
 
332
+ for idx, (file, col) in enumerate(zip(files, cols)):
333
+ with col:
334
+ image = Image.open(file)
335
+ images.append(image)
336
+ st.image(image, caption=f"Scan {idx + 1}", use_column_width=True)
337
+
338
+ timepoints_data[date].extend(images)
 
 
 
 
 
 
 
 
 
339
  st.markdown('</div>', unsafe_allow_html=True)
340
+
341
+ if unorganized_files:
342
+ st.warning(f"{len(unorganized_files)} files couldn't be automatically dated. Please ensure filenames include dates.")
343
+ with st.expander("Manually Assign Dates"):
344
+ for file in unorganized_files:
345
+ col1, col2 = st.columns([2, 1])
346
+ with col1:
347
+ st.text(file.name)
348
+ with col2:
349
+ date = st.date_input(f"Date for {file.name}", key=f"manual_{file.name}")
350
+ image = Image.open(file)
351
+ timepoints_data[date.strftime("%Y-%m-%d")].append(image)
352
+
353
+ if len(timepoints_data) >= 2:
354
+ if st.button("Analyze Progression"):
355
+ with st.spinner("Analyzing progression across timepoints..."):
356
+ progression_analysis = analyze_progression(timepoints_data)
357
+ st.markdown("### Progression Analysis Results")
358
+ st.markdown('<div class="analysis-container">', unsafe_allow_html=True)
359
+ st.markdown(progression_analysis)
360
+ st.markdown('</div>', unsafe_allow_html=True)
361
+ else:
362
+ st.warning("Please upload scans from at least 2 different timepoints for progression analysis.")
363
+
364
+ st.markdown('</div>', unsafe_allow_html=True)
365
+ else:
366
+ st.error("No dated scans found. Please ensure your filenames include dates (e.g., 'scan_2023-01-15.jpg').")
367
 
368
  st.markdown('</div>', unsafe_allow_html=True)
369