File size: 27,482 Bytes
3016cb6
 
 
 
 
 
 
 
9e4f358
 
 
 
 
 
 
 
3016cb6
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9e4f358
 
 
 
3016cb6
9e4f358
 
 
3016cb6
9e4f358
 
 
 
 
 
 
 
3016cb6
9e4f358
 
 
 
 
 
3016cb6
9e4f358
 
 
 
 
 
 
 
 
3016cb6
9e4f358
 
 
 
3016cb6
9e4f358
 
3016cb6
9e4f358
 
3016cb6
 
9e4f358
 
3016cb6
 
9e4f358
 
3016cb6
9e4f358
3016cb6
9e4f358
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3016cb6
 
 
 
 
 
 
 
 
 
 
 
9e4f358
3016cb6
 
5e16a3d
9e4f358
 
 
3016cb6
 
 
9e4f358
3016cb6
 
 
 
 
 
9e4f358
 
3016cb6
 
 
 
 
 
 
 
 
 
 
 
9e4f358
 
3016cb6
9e4f358
 
 
 
 
3016cb6
9e4f358
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3016cb6
 
9e4f358
 
 
 
 
 
 
 
3016cb6
9e4f358
 
 
 
 
 
 
 
3016cb6
 
9e4f358
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3016cb6
9e4f358
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3016cb6
 
 
 
9e4f358
 
 
 
 
 
 
3016cb6
 
 
 
9e4f358
3016cb6
9e4f358
 
5e16a3d
9e4f358
 
 
 
 
 
 
 
 
 
661e901
9e4f358
 
 
 
434f8b8
9e4f358
434f8b8
9e4f358
 
434f8b8
9e4f358
 
 
 
 
3016cb6
9e4f358
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
a5bcd30
 
 
 
 
 
9e4f358
3016cb6
 
 
9e4f358
 
9674c99
3016cb6
9e4f358
3016cb6
 
9e4f358
 
 
3016cb6
 
 
 
 
 
9e4f358
 
 
 
 
 
 
 
3016cb6
9e4f358
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3016cb6
 
 
 
 
 
9e4f358
3016cb6
 
9e4f358
 
 
 
 
3016cb6
9e4f358
3016cb6
 
 
 
 
9e4f358
 
 
 
 
 
 
 
 
 
 
 
 
3016cb6
9e4f358
3016cb6
 
9e4f358
 
3016cb6
9e4f358
 
 
 
 
3016cb6
9e4f358
 
 
 
 
 
45b75f0
a5bcd30
9e4f358
 
 
 
 
 
 
3016cb6
 
 
 
9e4f358
3016cb6
 
 
 
9e4f358
 
 
92f89a4
3016cb6
 
 
9e4f358
3016cb6
95c9bdc
 
 
 
 
 
 
 
 
 
3016cb6
 
 
 
 
 
9e4f358
 
 
 
3016cb6
 
9e4f358
3016cb6
 
 
9e4f358
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
import streamlit as st
from PIL import Image
import os
import base64
import io
from dotenv import load_dotenv
from groq import Groq
from reportlab.lib.pagesizes import letter
from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Image as ReportLabImage
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.units import inch
from datetime import datetime
import re
from reportlab.lib import colors
import random
import streamlit.components.v1 as components

# ======================
# CONFIGURATION SETTINGS
# ======================
PAGE_CONFIG = {
    "page_title": "Radiology Analyzer",
    "page_icon": "๐Ÿฉบ",
    "layout": "wide",
    "initial_sidebar_state": "expanded"
}

ALLOWED_FILE_TYPES = ['png', 'jpg', 'jpeg']

CSS_STYLES = """
<style>
    /* Main background and text colors */
    .main {
        background-color: #0e1117; 
        color: #ffffff;
    }
    .sidebar .sidebar-content {
        background-color: #1a1d24; 
        color: #ffffff;
    }
    
    /* Custom title styling */
    .main-title {
        font-size: 2.8rem; 
        font-weight: 700; 
        color: #ffffff; 
        margin-bottom: 0.2rem;
        text-align: center;
    }
    .sub-title { 
        font-size: 1.5rem; 
        color: #9ca3af; 
        margin-top: 0.2rem; 
        text-align: center;
        margin-bottom: 2rem;
    }
    
    /* Button styling */
    .stButton>button {
        background-color: #21b9e1 !important;
        color: white !important;
        border-radius: 8px !important;
        padding: 0.5rem 1rem !important;
        border: none !important;
        transition: all 0.3s ease !important;
    }
    .stButton>button:hover {
        background-color: #17a2b8 !important;
        transform: translateY(-2px);
        box-shadow: 0 4px 12px rgba(0, 200, 225, 0.3);
    }
    
    /* Report container */
    .report-container {
        background-color: #1a1d24;
        border-radius: 10px;
        padding: 25px;
        margin-top: 20px;
        box-shadow: 0 4px 15px rgba(0, 0, 0, 0.3);
        border-left: 5px solid #21b9e1;
    }
    .report-text {
        font-family: 'Inter', sans-serif;
        font-size: 14px;
        line-height: 1.6;
        color: #e2e8f0;
    }
    
    /* File uploader */
    .uploadedFile {
        background-color: #1a1d24 !important;
        border-radius: 10px !important;
        padding: 10px !important;
        border: 2px dashed #21b9e1 !important;
    }
    
    /* Sidebar items */
    .sidebar-item {
        padding: 10px 0;
        border-bottom: 1px solid #2d3748;
    }
    .sidebar-title {
        font-weight: bold;
        color: #21b9e1;
        margin-bottom: 10px;
    }
    
    /* Logo container */
    .logo-container {
        display: flex;
        justify-content: center;
        margin-bottom: 20px;
    }
    .logo-pulse {
        width: 100px;
        height: 100px;
        border-radius: 50%;
        animation: pulse 2s infinite;
        display: flex;
        justify-content: center;
        align-items: center;
        background-color: rgba(33, 185, 225, 0.1);
    }
    @keyframes pulse {
        0% {
            box-shadow: 0 0 0 0 rgba(33, 185, 225, 0.4);
        }
        70% {
            box-shadow: 0 0 0 20px rgba(33, 185, 225, 0);
        }
        100% {
            box-shadow: 0 0 0 0 rgba(33, 185, 225, 0);
        }
    }
    
    /* Progress bar */
    .stProgress > div > div {
        background-color: #21b9e1 !important;
    }
    
    /* Analysis status indicator */
    .analysis-complete {
        display: inline-flex;
        align-items: center;
        background-color: rgba(33, 225, 185, 0.2);
        color: #21e1b9;
        padding: 8px 16px;
        border-radius: 20px;
        font-weight: 600;
        margin-bottom: 20px;
    }
    .analysis-complete svg {
        margin-right: 8px;
    }
    
    /* Drop zone */
    .drop-zone {
        background-color: #1a1d24;
        border: 2px dashed #21b9e1;
        border-radius: 10px;
        padding: 40px 20px;
        text-align: center;
        transition: all 0.3s ease;
        margin-bottom: 20px;
    }
    .drop-zone:hover {
        border-color: #17a2b8;
        background-color: #242830;
    }
    .drop-icon {
        font-size: 3rem;
        color: #21b9e1;
        margin-bottom: 10px;
    }
    
    /* Markdown adjustments */
    .markdown-text-container p {
        color: #e2e8f0 !important;
    }
    
    /* Image styling */
    .stImage img {
        border-radius: 10px;
        box-shadow: 0 4px 15px rgba(0, 0, 0, 0.3);
        border: 3px solid #1a1d24;
    }
    
    /* Card styles */
    .card {
        background-color: #1a1d24;
        border-radius: 10px;
        padding: 20px;
        margin-bottom: 20px;
        box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
        transition: all 0.3s ease;
    }
    .card:hover {
        transform: translateY(-5px);
        box-shadow: 0 10px 25px rgba(0, 0, 0, 0.3);
    }
    .card-title {
        color: #21b9e1;
        font-size: 1.2rem;
        font-weight: 600;
        margin-bottom: 10px;
    }
    
    /* Tooltip */
    .tooltip {
        position: relative;
        display: inline-block;
        cursor: pointer;
    }
    .tooltip .tooltiptext {
        visibility: hidden;
        width: 200px;
        background-color: #2d3748;
        color: #fff;
        text-align: center;
        border-radius: 6px;
        padding: 10px;
        position: absolute;
        z-index: 1;
        bottom: 125%;
        left: 50%;
        margin-left: -100px;
        opacity: 0;
        transition: opacity 0.3s;
    }
    .tooltip:hover .tooltiptext {
        visibility: visible;
        opacity: 1;
    }
    
    /* API selector styling */
    .api-selector {
        background-color: #1a1d24;
        border-radius: 10px;
        padding: 15px;
        margin-bottom: 20px;
        border-left: 3px solid #21b9e1;
    }
    .api-selector-title {
        color: #21b9e1;
        font-weight: bold;
        margin-bottom: 10px;
    }
</style>
"""

# ======================
# CORE FUNCTIONS
# ======================
def configure_application():
    """Initialize application settings and styling"""
    st.set_page_config(**PAGE_CONFIG)
    st.markdown(CSS_STYLES, unsafe_allow_html=True)

def initialize_groq_client():
    """Create and validate Groq API client"""
    load_dotenv()
    api_key = os.getenv("GROQ_API_KEY")        
    if not api_key:
        st.error("Groq API key not found. Please provide an API key.")
        return None
    
    return Groq(api_key=api_key)


def encode_logo(image_path):
    """Encode logo image to base64"""
    try:
        with open(image_path, "rb") as img_file:
            return base64.b64encode(img_file.read()).decode("utf-8")
    except FileNotFoundError:
        # Return a placeholder image (blue medical technology icon) encoded as base64
        return "iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAYAAABw4pVUAAAACXBIWXMAAAsTAAALEwEAmpwYAAAFLUlEQVR4nO2cfYhUVRTGf+uqlWmpZX6kaZpppX1YWpllEQVFEQVBEVFUpBVF0QdFRlEUVERBRNAfkRVZ9GVFpaXlRwpqlGlqpmZqaZa67q7r6qrr9kf30dxh9u7MnTvz5t6Z+8DLMDvv3nPOuWfOPe++e+6CEEIIIYQQ1cCVwBpgl8/2AnCa7UBjZDjwIbDXR4FUsjbg99zV7AZGpBJoZlwDfK+EeOAHYJTNIPuVkMAca2PghBs/AEcZMpdKSGD20IKJQCuvQSoYLSWjpJRiYzLCHgCeB5YDzTZicYGrgF+V7T10AG+kGcRLwPGWYnGFicA/SmgfeoAZaQ6yFhjmMxzXGAV8q6T24WdggB/DTcDFluJxhYHAFiW1DyuDGG9OIIyrgJ+U2N+4z69xNzxcXZ1L3FdDqoVoXucjgdXkQSz6nKzw5BkFbK/xAV3jUsBpoUEJKYmNQD0Pnw+xtgRCeNdg6WO7wvVuVEkMtiWE8K5SrZ1L+pwPAusV+n7Zk8ZHv35FaWiUEOPcC3xRo8JbV41i+3K8RgVX8aysMbGVnWHVKLYvR2tEcE9Wq9iaiMYaEdzjNSq2JqK+RgR3by2KrQYmdG0MCu6yahdbja16wDe1KLYaW/XA6BoUWxPRWWWCuxw4XKNiq5NVD1QjP/oVW5PCrFbmVrW27Krpz8AVZZrWrBaRvQcsAb4CfitKbEtpgbWxAzg3zKSSEyLBjXIVtzf3vLZYqaUQhRQGRWoTmCcHjvDpX41UKcVGZLqPQPdoYkqTxQEW+DTWC7yfVBDWspmQkFHmlWXMfkwRInoMeKyAn+F6Zw2E4e1c9F7KPsMxdxdwfJQVNTfwU9U7bGBfcYLXmlKp5xUL4WUt/Jvgxp5QUaMd3MbA58XMRlqgBxiYVAw3Ay8m8PFNQC+EQVWXlD8XVVIQVwCtZQgiHwaYMpwwiFuThpn+ZFFBzA7gIzCVnLRNAjodF87GIhdPDzArJmxsJxxicYZvFrnwfUBnwrDG5ApjH5cQHnVFhYsB1gEdMWGjtwwXeZnWZJ1fZtjtucHSUuSY/WWGpXLREcWQeBjYFHGRzeUI4nKgiPWAKbmw0NJC2Hhc6Fx6G3SLe76Wc7s17j7BTOA94IKIY7g8I+PrDfZvZWX/gojj/QtMB74vOcwW/qPQnUZ23FHGZNlX5KLFQgMjciOH+W9nngG25MQwLpXvxcDCnO97YubXDGqLEUZTbsvKA8BDwNWGPvuNsTKKKXEzdKNwbg6mxMnlGcZ7iu1BYOmJy4U1phZpgEJhw4tEGZq8DQR2W57QdUPnTIrA1nZaGLEdJLt3p/uD2aCHo+5GFKt4zYWnxs2Qgej1cVZrJJIcYnoX+MiXdW/ywOYtztEp+Jhjd//5YMaGJ5iHrq0GVtB7X5ZY88p2gTBIlRDjiQ3AAVH2K0oIZTG5hP7ESCWkTzUoFJ3AEVlHYotJWQx0TYwNSoj5w2chKP3DibadnWk7SMepVkKMJ9qBWPocB2QdgG1eL0r7gQxwmBJSXvOeRJaXUcY/sMWExm4lxHhiPtBWRuhryjXeRQkJ1MWfVsb2HVZfpjrFbZ1aAMzJNaMLn3+35LbXwXJZR0IIIYQQQgghhBBCCCGEEEIIIYQQQgghhBBCCCGEEEIIIYQQQgghhBBCCCGEEEIIIYQQQgghhBBCCCGEEEIIIYQQQgghhBBCCCGEEEIIIYQQQgghhBBCCCGEEEIIIYQQQgghhBBCCCGEEEIIIYRD/A9AH1PHpL17/AAAAABJRU5ErkJggg=="

def process_image_data(uploaded_file):
    """Convert image to base64 encoded string"""
    try:
        image = Image.open(uploaded_file)
        buffer = io.BytesIO()
        image.save(buffer, format=image.format)
        return base64.b64encode(buffer.getvalue()).decode('utf-8'), image.format
    except Exception as e:
        st.error(f"Image processing error: {str(e)}")
        return None, None

def generate_pdf_report(report_text, uploaded_file):
    """Generate professionally formatted PDF report with bold headers."""
    buffer = io.BytesIO()
    doc = SimpleDocTemplate(buffer, pagesize=letter, 
                           rightMargin=72, leftMargin=72,
                           topMargin=72, bottomMargin=72)
    
    # Create custom styles for different parts of the report
    styles = getSampleStyleSheet()
    
    # Custom styles for better formatting
    title_style = ParagraphStyle(
        'ReportTitle',
        parent=styles['Title'],
        fontSize=16,
        alignment=1,  # Center aligned
        spaceAfter=12
    )
    
    header_style = ParagraphStyle(
        'SectionHeader',
        parent=styles['Heading2'],
        fontSize=12,
        fontName='Helvetica-Bold',
        textColor=colors.black,
        spaceBefore=12,
        spaceAfter=6
    )
    
    normal_style = ParagraphStyle(
        'NormalText',
        parent=styles['BodyText'],
        fontSize=11,
        leading=14,
        spaceAfter=8
    )
    
    abnormal_style = ParagraphStyle(
        'AbnormalText',
        parent=styles['BodyText'],
        fontSize=11,
        leading=14,
        textColor=colors.red,
        backColor=colors.lightgrey,
        borderPadding=5,
        spaceAfter=8
    )
    
    footer_style = ParagraphStyle(
        'FooterText',
        parent=styles['Italic'],
        fontSize=9,
        alignment=1  # Center aligned
    )
    
    # Begin building the report
    story = []
    
    # Hospital/Institution Header
    header_text = "RADIOLOGY DEPARTMENT"
    header = Paragraph(header_text, title_style)
    story.append(header)
    
    # Report Title
    report_title = "RADIOLOGICAL EXAMINATION REPORT"
    title = Paragraph(report_title, title_style)
    story.append(title)
    
    # Add date and report ID
    date_text = f"Date: {datetime.now().strftime('%B %d, %Y')}"
    report_id = f"Report ID: RAD-{datetime.now().strftime('%Y%m%d')}-{random.randint(1000, 9999)}"
    date_para = Paragraph(date_text, normal_style)
    id_para = Paragraph(report_id, normal_style)
    story.append(date_para)
    story.append(id_para)
    story.append(Spacer(1, 12))
    
    # Add the image to the PDF
    if uploaded_file:
        try:
            uploaded_file.seek(0)  # Reset file pointer to beginning
            pil_image = Image.open(uploaded_file)
            img_width = 5 * inch
            aspect = float(pil_image.height) / float(pil_image.width)
            img_height = img_width * aspect
            
            img_temp = io.BytesIO()
            pil_image.save(img_temp, format=pil_image.format if pil_image.format else 'JPEG')
            img_temp.seek(0)
            
            img = ReportLabImage(img_temp, width=img_width, height=img_height)
            story.append(img)
            story.append(Spacer(1, 12))
            
            # Add image caption
            caption = Paragraph("Figure 1: Radiological Image for Analysis", normal_style)
            story.append(caption)
            story.append(Spacer(1, 12))
            
        except Exception as e:
            error_text = Paragraph(f"Image processing error: {str(e)}", normal_style)
            story.append(error_text)
            story.append(Spacer(1, 12))
    
    # Clean the report text (remove markdown-style formatting and unwanted characters)
    cleaned_text = report_text.replace('**', '').replace('##', '').replace('*', '-')
    
    # Define section headers to identify
    section_headers = [
        "DIAGNOSIS",
        "ETIOLOGY",
        "RISK FACTORS",
        "PATHOPHYSIOLOGY",
        "CLINICAL FEATURES",
        "SIGNS AND SYMPTOMS",
        "INVESTIGATIONS",
        "MANAGEMENT",
        "INITIAL STABILIZATION",
        "MEDICAL MANAGEMENT",
        "SURGICAL MANAGEMENT",
        "PROGNOSIS"
    ]
    
    # Split into lines for more precise processing
    lines = cleaned_text.split('\n')
    current_section = ""
    section_content = ""
    
    for i, line in enumerate(lines):
        line = line.strip()
        if not line:
            continue
            
        # Remove any "Step X:" prefixes
        line = re.sub(r'^Step \d+:\s*', '', line)
        
        # Check if this is a section header
        is_header = False
        for header in section_headers:
            if line.upper().startswith(header) or line.upper() == header + ":":
                is_header = True
                break
                
        # Also check if it's a short line ending with a colon (likely a header)
        if not is_header and len(line) < 60 and line.endswith(':'):
            is_header = True
        
        # If we found a header 
        if is_header:
            # First add any accumulated content from previous section
            if section_content.strip():
                # Check for severe abnormalities to highlight
                severe_abnormal_keywords = [
                    'severe', 'critical', 'urgent', 'emergency', 'life-threatening',
                    'malignant', 'neoplasm', 'carcinoma', 'metastasis', 'hemorrhage',
                    'fracture', 'rupture', 'perforation',
                ]
                
                has_severe_issue = any(keyword in section_content.lower() for keyword in severe_abnormal_keywords)
                
                if current_section.upper().startswith("DIAGNOSIS") or current_section.upper().startswith("ABNORMAL"):
                    # This is a diagnosis section - highlight abnormalities
                    p = Paragraph(section_content, abnormal_style if has_severe_issue else normal_style)
                else:
                    p = Paragraph(section_content, normal_style)
                    
                story.append(p)
                story.append(Spacer(1, 6))
                section_content = ""
            
            # Add the new section header - remove any trailing colon for cleaner look
            clean_header = line.strip()
            if clean_header.endswith(':'):
                clean_header = clean_header[:-1]
                
            current_section = clean_header
            p = Paragraph(f"<b>{clean_header}</b>", header_style)  # Bold the header
            story.append(p)
            
        else:
            # This is content - append to the current section content
            if section_content:
                section_content += "<br/>" + line
            else:
                section_content = line
    
    # Add any remaining content
    if section_content.strip():
        p = Paragraph(section_content, normal_style)
        story.append(p)
    
    # Add conclusion if not present
    if not any("PROGNOSIS" in line.upper() for line in lines):
        conclusion_header = Paragraph("<b>PROGNOSIS</b>", header_style)
        story.append(conclusion_header)
        story.append(Spacer(1, 6))
        
        conclusion_text = "Prognosis varies based on the extent and location of findings. Clinical correlation with the patient's symptoms and medical history is recommended."
        conclusion_para = Paragraph(conclusion_text, normal_style)
        story.append(conclusion_para)
    
    # Add footer with disclaimer
    story.append(Spacer(1, 24))
    disclaimer = "This report was generated with AI assistance and should be reviewed by a qualified healthcare professional."
    footer = Paragraph(disclaimer, footer_style)
    story.append(footer)
    
    # Build PDF
    doc.build(story)
    buffer.seek(0)
    return buffer



        


def generate_radiology_report_groq(uploaded_file, client):
    """Generate AI-powered radiology analysis using Groq API"""
    base64_image, img_format = process_image_data(uploaded_file)
    
    if not base64_image:
        return None
    
    image_url = f"data:image/{img_format.lower()};base64,{base64_image}"
    
    try:
        with st.spinner("Analyzing image..."):
            # Add progress bar for visual feedback
            progress_bar = st.progress(0)
            for i in range(100):
                # Update progress bar
                progress_bar.progress(i + 1)
                import time
                time.sleep(0.025)  # Simulate processing time
                
            # Updated prompt to request the detailed, structured format
            response = client.chat.completions.create(
                model="meta-llama/llama-4-maverick-17b-128e-instruct",  # Use Groq's model
                messages=[{
                    "role": "user",
                    "content": [
                        {"type": "text", "text": (
                            """As a radiologist, analyze the following Medical report and provide a comprehensive report structured as follows:

1. **DIAGNOSIS**: Clearly state the primary diagnosis, including dimensions in mmIf where applicable (e.g., if a tumor is present). Use specific anatomical terms relevant to the body part being examined.If it is chest xray also mention if pneumonia is present or not.

2. **FINDINGS**: 
   - Provide detailed observations from the Medical report, including:
     - The size, shape, and location of any lesions or abnormalities if applicable.
     - Description of the surrounding tissues and structures if applicable.
     - Any noted changes in signal intensity on various sequences (e.g., T1W, T2W, FLAIR) if applicable.
     - Mention of any associated findings, such as edema, mass effect, or midline shift if applicble.
     - Specific comments on vascular structures, if applicable.

3. **PATHOPHYSIOLOGY**: Briefly explain the disease mechanism related to the diagnosis, focusing on how it affects the specific body part.

4. **CLINICAL FEATURES**: Provide an overview of typical clinical presentations associated with this diagnosis, emphasizing symptoms that may arise from abnormalities in the specified anatomical area.

5. **SIGNS AND SYMPTOMS**: List common signs and symptoms relevant to the findings in the MRI report. Tailor this section to align with the specific anatomy being assessed.

6. **INVESTIGATIONS**: Mention diagnostic tests typically used for confirmation of the diagnosis, including imaging studies or laboratory tests pertinent to the body part.

7. **MANAGEMENT**: Outline the management plans in three parts:
   - Initial Stabilization: Describe immediate steps for patient care.
   - Medical Management: Outline pharmacological treatments and monitoring.
   - Surgical Management (if applicable): Discuss any surgical interventions specific to the diagnosis and body part.

8. **PROGNOSIS**: Describe expected outcomes and factors that may affect prognosis based on the diagnosis. Include considerations specific to the anatomical region and associated complications.

Please ensure to focus on the following findings from the report:
- Mention specific abnormalities based on the region (e.g., "T2/FLAIR hyperintensities in the right fronto-parietal region" for brain MRI).
- Highlight any significant lesions or deviations from the norm.
- Include any other abnormal findings noted in the report that are relevant to the specific anatomy.

Format each section with appropriate headings and use bullet points for lists. Base your analysis on the provided MRI report details."""
                        )},
                        {"type": "image_url", "image_url": {"url": image_url}},
                    ]
                }],
                temperature=0.1,
                max_tokens=3000,  # Increased token limit for more detailed response
                top_p=0.3
            )
            return response.choices[0].message.content
    except Exception as e:
        st.error(f"Groq API error: {str(e)}")
        return None

def generate_radiology_report(uploaded_file, api_choice='groq'):
    client = initialize_groq_client()
    if client:
        return generate_radiology_report_groq(uploaded_file, client)
    else:
        st.error("Failed to initialize Groq client. Please check your API key.")
        return None

# ======================
# UI COMPONENTS
# ======================
def display_animated_logo():
    """Display an animated medical logo"""
    logo_b64 = encode_logo("src/Round_image_depicting_a_futuristic_medical_image_a-1742282117033-photoaidcom-cropped.png")
    
    # If logo file doesn't exist, use the placeholder from encode_logo
    st.markdown(
        f"""
        <div class="logo-container">
            <div class="logo-pulse">
                <img src="data:image/png;base64,{logo_b64}" width="200">
            </div>
        </div>
        """, 
        unsafe_allow_html=True
    )

def display_main_interface():
    """Render primary application interface"""
    # Display animated logo and titles
    display_animated_logo()
    
    st.markdown('<h1 class="main-title">Radiology Analyzer</h1>', unsafe_allow_html=True)
    st.markdown('<p class="sub-title">Advanced Medical Imaging Analysis</p>', unsafe_allow_html=True)
    
    # Action buttons
    if st.session_state.get('analysis_result'):
        st.markdown(
            """
            <div class="analysis-complete">
                <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16">
                    <path d="M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0zm-3.97-3.03a.75.75 0 0 0-1.08.022L7.477 9.417 5.384 7.323a.75.75 0 0 0-1.06 1.06L6.97 11.03a.75.75 0 0 0 1.079-.02l3.992-4.99a.75.75 0 0 0-.01-1.05z"/>
                </svg>
                Analysis Complete
            </div>
            """,
            unsafe_allow_html=True
        )
        
        col1, col2 = st.columns([1, 1])
        with col1:
            pdf_report = generate_pdf_report(st.session_state.analysis_result, st.session_state.uploaded_file)
            st.download_button(
                label="๐Ÿ“„ Download PDF Report",
                data=pdf_report,
                file_name="radiology_report.pdf",
                mime="application/pdf",
                use_container_width=True,
                help="Download formal PDF version of the report"
            )

        with col2:
            if st.button("Clear Analysis ๐Ÿ—‘๏ธ", use_container_width=True, help="Remove current results"):
                st.session_state.pop('analysis_result', None)
                st.session_state.pop('uploaded_file', None)
                st.rerun()

        # Display analysis results in a styled container
        st.markdown("### ๐ŸŽฏ Radiological Findings Report")
        st.markdown(
            f'<div class="report-container"><div class="report-text">{st.session_state.analysis_result}</div></div>', 
            unsafe_allow_html=True
        )
    else:
        # Show a centered placeholder message
        st.markdown(
            """
            <div style="text-align: center; margin-top: 50px; color: #9ca3af; padding: 100px 0;">
                <svg xmlns="http://www.w3.org/2000/svg" width="64" height="64" fill="currentColor" viewBox="0 0 16 16" style="margin-bottom: 20px;">
                    <path d="M8 0a8 8 0 1 0 0 16A8 8 0 0 0 8 0ZM1.5 8a6.5 6.5 0 1 1 13 0 6.5 6.5 0 0 1-13 0Zm4.879-2.773 4.264 2.559a.25.25 0 0 1 0 .428l-4.264 2.559A.25.25 0 0 1 6 10.559V5.442a.25.25 0 0 1 .379-.215Z"/>
                </svg>
                <p style="font-size: 1.2rem;">Upload a medical image to begin analysis</p>
            </div>
            """,
            unsafe_allow_html=True
        )

def render_sidebar():
    """Create sidebar interface elements"""
    with st.sidebar:
        st.markdown('<div class="sidebar-item">', unsafe_allow_html=True)
        st.markdown('<div class="sidebar-title">Diagnostic Capabilities</div>', unsafe_allow_html=True)
        st.markdown("""
        - **Multi-Modality Analysis:** X-ray, MRI, CT, Ultrasound
        - **Pathology Detection:** Fractures, tumors, infections
        - **Comparative Analysis:** Track disease progression
        - **Structured Reporting:** Standardized output format
        - **Clinical Correlation:** Suggested next steps
        """)
        st.markdown("""
        <div class="tooltip">
            <strong>Disclaimer:</strong> This service does not provide medical advice.
            <span class="tooltiptext">Always consult with a qualified healthcare professional for diagnosis and treatment.</span>
        </div>
        """, unsafe_allow_html=True)
        st.markdown('</div>', unsafe_allow_html=True)        

        
        st.markdown('</div>', unsafe_allow_html=True)
        
        # Image Upload Section
        st.markdown('<div class="sidebar-item">', unsafe_allow_html=True)
        st.markdown('<div class="sidebar-title">Image Upload Section</div>', unsafe_allow_html=True)
        
        
        uploaded_file = st.file_uploader(
            "Select Medical Image", 
            type=ALLOWED_FILE_TYPES,
            label_visibility="collapsed",
            help="Supported formats: PNG, JPG, JPEG"
        )

        if uploaded_file:
            st.session_state.uploaded_file = uploaded_file  # Store uploaded file in session state
            
            # Display image with a styled container
            # st.markdown('<div class="card">', unsafe_allow_html=True)
            st.image(Image.open(uploaded_file), 
                    caption="Uploaded Medical Image",
                    use_container_width=True)
            st.markdown('</div>', unsafe_allow_html=True)

        if st.button("โ–ถ๏ธ Initiate Analysis", use_container_width=True):
                    # Use the selected API provider
                    api_choice = 'groq'
                    report = generate_radiology_report(uploaded_file, api_choice)
                    
                    if report:
                        st.session_state.analysis_result = report
                        st.rerun()
        st.markdown('</div>', unsafe_allow_html=True)


# ======================
# APPLICATION ENTRYPOINT
# ======================
def main():
    """Primary application controller"""
    # Check if dark mode is in session state, default to true
    if 'dark_mode' not in st.session_state:
        st.session_state.dark_mode = True
    
    configure_application()
    
    render_sidebar()
    display_main_interface()

if __name__ == "__main__":
    main()