Ed-Strak commited on
Commit
105f58a
Β·
verified Β·
1 Parent(s): 8dcfe4d

Added Files

Browse files
Files changed (5) hide show
  1. .env +1 -0
  2. .gitattributes +36 -35
  3. README.md +13 -13
  4. app.py +272 -0
  5. requirements.txt +5 -0
.env ADDED
@@ -0,0 +1 @@
 
 
1
+ GROQ_API_KEY=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
.gitattributes CHANGED
@@ -1,35 +1,36 @@
1
- *.7z filter=lfs diff=lfs merge=lfs -text
2
- *.arrow filter=lfs diff=lfs merge=lfs -text
3
- *.bin filter=lfs diff=lfs merge=lfs -text
4
- *.bz2 filter=lfs diff=lfs merge=lfs -text
5
- *.ckpt filter=lfs diff=lfs merge=lfs -text
6
- *.ftz filter=lfs diff=lfs merge=lfs -text
7
- *.gz filter=lfs diff=lfs merge=lfs -text
8
- *.h5 filter=lfs diff=lfs merge=lfs -text
9
- *.joblib filter=lfs diff=lfs merge=lfs -text
10
- *.lfs.* filter=lfs diff=lfs merge=lfs -text
11
- *.mlmodel filter=lfs diff=lfs merge=lfs -text
12
- *.model filter=lfs diff=lfs merge=lfs -text
13
- *.msgpack filter=lfs diff=lfs merge=lfs -text
14
- *.npy filter=lfs diff=lfs merge=lfs -text
15
- *.npz filter=lfs diff=lfs merge=lfs -text
16
- *.onnx filter=lfs diff=lfs merge=lfs -text
17
- *.ot filter=lfs diff=lfs merge=lfs -text
18
- *.parquet filter=lfs diff=lfs merge=lfs -text
19
- *.pb filter=lfs diff=lfs merge=lfs -text
20
- *.pickle filter=lfs diff=lfs merge=lfs -text
21
- *.pkl filter=lfs diff=lfs merge=lfs -text
22
- *.pt filter=lfs diff=lfs merge=lfs -text
23
- *.pth filter=lfs diff=lfs merge=lfs -text
24
- *.rar filter=lfs diff=lfs merge=lfs -text
25
- *.safetensors filter=lfs diff=lfs merge=lfs -text
26
- saved_model/**/* filter=lfs diff=lfs merge=lfs -text
27
- *.tar.* filter=lfs diff=lfs merge=lfs -text
28
- *.tar filter=lfs diff=lfs merge=lfs -text
29
- *.tflite filter=lfs diff=lfs merge=lfs -text
30
- *.tgz filter=lfs diff=lfs merge=lfs -text
31
- *.wasm filter=lfs diff=lfs merge=lfs -text
32
- *.xz filter=lfs diff=lfs merge=lfs -text
33
- *.zip filter=lfs diff=lfs merge=lfs -text
34
- *.zst filter=lfs diff=lfs merge=lfs -text
35
- *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
1
+ *.7z filter=lfs diff=lfs merge=lfs -text
2
+ *.arrow filter=lfs diff=lfs merge=lfs -text
3
+ *.bin filter=lfs diff=lfs merge=lfs -text
4
+ *.bz2 filter=lfs diff=lfs merge=lfs -text
5
+ *.ckpt filter=lfs diff=lfs merge=lfs -text
6
+ *.ftz filter=lfs diff=lfs merge=lfs -text
7
+ *.gz filter=lfs diff=lfs merge=lfs -text
8
+ *.h5 filter=lfs diff=lfs merge=lfs -text
9
+ *.joblib filter=lfs diff=lfs merge=lfs -text
10
+ *.lfs.* filter=lfs diff=lfs merge=lfs -text
11
+ *.mlmodel filter=lfs diff=lfs merge=lfs -text
12
+ *.model filter=lfs diff=lfs merge=lfs -text
13
+ *.msgpack filter=lfs diff=lfs merge=lfs -text
14
+ *.npy filter=lfs diff=lfs merge=lfs -text
15
+ *.npz filter=lfs diff=lfs merge=lfs -text
16
+ *.onnx filter=lfs diff=lfs merge=lfs -text
17
+ *.ot filter=lfs diff=lfs merge=lfs -text
18
+ *.parquet filter=lfs diff=lfs merge=lfs -text
19
+ *.pb filter=lfs diff=lfs merge=lfs -text
20
+ *.pickle filter=lfs diff=lfs merge=lfs -text
21
+ *.pkl filter=lfs diff=lfs merge=lfs -text
22
+ *.pt filter=lfs diff=lfs merge=lfs -text
23
+ *.pth filter=lfs diff=lfs merge=lfs -text
24
+ *.rar filter=lfs diff=lfs merge=lfs -text
25
+ *.safetensors filter=lfs diff=lfs merge=lfs -text
26
+ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
27
+ *.tar.* filter=lfs diff=lfs merge=lfs -text
28
+ *.tar filter=lfs diff=lfs merge=lfs -text
29
+ *.tflite filter=lfs diff=lfs merge=lfs -text
30
+ *.tgz filter=lfs diff=lfs merge=lfs -text
31
+ *.wasm filter=lfs diff=lfs merge=lfs -text
32
+ *.xz filter=lfs diff=lfs merge=lfs -text
33
+ *.zip filter=lfs diff=lfs merge=lfs -text
34
+ *.zst filter=lfs diff=lfs merge=lfs -text
35
+ *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ src/radiology.png filter=lfs diff=lfs merge=lfs -text
README.md CHANGED
@@ -1,13 +1,13 @@
1
- ---
2
- title: MediSight
3
- emoji: 🌍
4
- colorFrom: indigo
5
- colorTo: red
6
- sdk: streamlit
7
- sdk_version: 1.43.2
8
- app_file: app.py
9
- pinned: false
10
- short_description: AI model for automated report generation from X-rays
11
- ---
12
-
13
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
1
+ ---
2
+ title: Radiology Analyzer
3
+ emoji: πŸ“ˆ
4
+ colorFrom: yellow
5
+ colorTo: blue
6
+ sdk: streamlit
7
+ sdk_version: 1.42.0
8
+ app_file: app.py
9
+ pinned: false
10
+ license: mit
11
+ ---
12
+
13
+ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
app.py ADDED
@@ -0,0 +1,272 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ from PIL import Image
3
+ import os
4
+ import base64
5
+ import io
6
+ from dotenv import load_dotenv
7
+ from groq import Groq
8
+ from reportlab.lib.pagesizes import letter
9
+ from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer
10
+ from reportlab.lib.styles import getSampleStyleSheet
11
+
12
+ # ======================
13
+ # CONFIGURATION SETTINGS
14
+ # ======================
15
+ PAGE_CONFIG = {
16
+ "page_title": "Radiology Analyzer",
17
+ "page_icon": "🩺",
18
+ "layout": "wide",
19
+ "initial_sidebar_state": "expanded"
20
+ }
21
+
22
+ ALLOWED_FILE_TYPES = ['png', 'jpg', 'jpeg']
23
+
24
+ CSS_STYLES = """
25
+ <style>
26
+ .main { background-color: #f4f9f9; color: #000000; }
27
+ .sidebar .sidebar-content { background-color: #d1e7dd; }
28
+ .stTextInput textarea { color: #000000 !important; }
29
+ .stSelectbox div[data-baseweb="select"],
30
+ .stSelectbox option,
31
+ .stSelectbox div[role="listbox"] div {
32
+ color: black !important;
33
+ background-color: #d1e7dd !important;
34
+ }
35
+ .stSelectbox svg { fill: black !important; }
36
+ .main-title {
37
+ font-size: 88px;
38
+ font-weight: bold;
39
+ color: rgb(33, 238, 238);
40
+ }
41
+ .sub-title {
42
+ font-size: 100px;
43
+ color: #6B6B6B;
44
+ margin-top: -1px;
45
+ }
46
+ .stButton>button {
47
+ background-color: rgb(33, 225, 250);
48
+ color: white;
49
+ font-size: 69px;
50
+ }
51
+ .stImage img {
52
+ border-radius: 10px;
53
+ box-shadow: 2px 2px 10px rgba(0,0,0,0.1);
54
+ }
55
+ .logo {
56
+ text-align: center;
57
+ margin-bottom: 20px;
58
+ }
59
+ .report-container {
60
+ background-color: #ffffff;
61
+ border-radius: 15px;
62
+ padding: 25px;
63
+ margin-top: 20px;
64
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
65
+ border-left: 5px solid #21eeef;
66
+ }
67
+ .report-text {
68
+ font-family: 'Courier New', monospace;
69
+ font-size: 16px;
70
+ line-height: 1.6;
71
+ color: #2c3e50;
72
+ }
73
+ .download-btn {
74
+ background-color: #21eeef !important;
75
+ color: white !important;
76
+ border: none !important;
77
+ border-radius: 8px !important;
78
+ padding: 12px 24px !important;
79
+ }
80
+ </style>
81
+ """
82
+
83
+ # ======================
84
+ # CORE FUNCTIONS
85
+ # ======================
86
+ def configure_application():
87
+ """Initialize application settings and styling"""
88
+ st.set_page_config(**PAGE_CONFIG)
89
+ st.markdown(CSS_STYLES, unsafe_allow_html=True)
90
+
91
+ def initialize_api_client():
92
+ """Create and validate Groq API client"""
93
+ load_dotenv()
94
+ api_key = os.getenv("GROQ_API_KEY")
95
+
96
+ if not api_key:
97
+ st.error("API key not found. Please verify .env configuration.")
98
+ st.stop()
99
+
100
+ return Groq(api_key=api_key)
101
+
102
+ def encode_logo(image_path):
103
+ """Encode logo image to base64"""
104
+ try:
105
+ with open(image_path, "rb") as img_file:
106
+ return base64.b64encode(img_file.read()).decode("utf-8")
107
+ except FileNotFoundError:
108
+ st.error("Logo image not found! Using placeholder.")
109
+ return ""
110
+
111
+ def process_image_data(uploaded_file):
112
+ """Convert image to base64 encoded string"""
113
+ try:
114
+ image = Image.open(uploaded_file)
115
+ buffer = io.BytesIO()
116
+ image.save(buffer, format=image.format)
117
+ return base64.b64encode(buffer.getvalue()).decode('utf-8'), image.format
118
+ except Exception as e:
119
+ st.error(f"Image processing error: {str(e)}")
120
+ return None, None
121
+
122
+ def generate_pdf_report(report_text):
123
+ """Generate PDF document from report text"""
124
+ buffer = io.BytesIO()
125
+ doc = SimpleDocTemplate(buffer, pagesize=letter)
126
+ styles = getSampleStyleSheet()
127
+ story = []
128
+
129
+ # Add title
130
+ title = Paragraph("<b>Radiology Report</b>", styles['Title'])
131
+ story.append(title)
132
+ story.append(Spacer(1, 12))
133
+
134
+ # Add report content
135
+ content = Paragraph(report_text.replace('\n', '<br/>'), styles['BodyText'])
136
+ story.append(content)
137
+
138
+ doc.build(story)
139
+ buffer.seek(0)
140
+ return buffer
141
+
142
+ def generate_radiology_report(uploaded_file, client):
143
+ """Generate AI-powered radiology analysis"""
144
+ base64_image, img_format = process_image_data(uploaded_file)
145
+
146
+ if not base64_image:
147
+ return None
148
+
149
+ image_url = f"data:image/{img_format.lower()};base64,{base64_image}"
150
+
151
+ try:
152
+ response = client.chat.completions.create(
153
+ model="llama-3.2-11b-vision-preview",
154
+ messages=[{
155
+ "role": "user",
156
+ "content": [
157
+ {"type": "text", "text": (
158
+ "As an AI radiologist, provide a detailed structured report including: "
159
+ "1. Imaging modality identification\n2. Anatomical structures visualized\n"
160
+ "3. Abnormal findings description\n4. Differential diagnoses\n"
161
+ "5. Clinical correlation recommendations"
162
+ )},
163
+ {"type": "image_url", "image_url": {"url": image_url}},
164
+ ]
165
+ }],
166
+ temperature=0.2,
167
+ max_tokens=400,
168
+ top_p=0.5
169
+ )
170
+ return response.choices[0].message.content
171
+ except Exception as e:
172
+ st.error(f"API communication error: {str(e)}")
173
+ return None
174
+
175
+ # ======================
176
+ # UI COMPONENTS
177
+ # ======================
178
+ def display_main_interface():
179
+ """Render primary application interface"""
180
+ # Encode logo image
181
+ logo_b64 = encode_logo("src/radiology.png")
182
+
183
+ # Center the logo and title using HTML and CSS
184
+ st.markdown(
185
+ f"""
186
+ <div style="text-align: center;">
187
+ <div class="logo">
188
+ <img src="data:image/png;base64,{logo_b64}" width="100">
189
+ </div>
190
+ <p class="main-title"> Radiology Analyzer</p>
191
+ <p class="sub-title">Advanced Medical Imaging Analysis</p>
192
+ </div>
193
+ """,
194
+ unsafe_allow_html=True
195
+ )
196
+
197
+ st.markdown("---")
198
+
199
+ # Action buttons
200
+ col1, col2 = st.columns([1, 1])
201
+ with col1:
202
+ if st.session_state.get('analysis_result'):
203
+ pdf_report = generate_pdf_report(st.session_state.analysis_result)
204
+ st.download_button(
205
+ label="πŸ“„ Download PDF Report",
206
+ data=pdf_report,
207
+ file_name="radiology_report.pdf",
208
+ mime="application/pdf",
209
+ use_container_width=True,
210
+ help="Download formal PDF version of the report",
211
+ key="download_pdf"
212
+ )
213
+
214
+ with col2:
215
+ if st.button("Clear Analysis πŸ—‘οΈ", use_container_width=True, help="Remove current results"):
216
+ st.session_state.pop('analysis_result')
217
+ st.rerun()
218
+
219
+ # Display analysis results
220
+ if st.session_state.get('analysis_result'):
221
+ st.markdown("### 🎯 Radiological Findings Report")
222
+ st.markdown(
223
+ f'<div class="report-container"><div class="report-text">{st.session_state.analysis_result}</div></div>',
224
+ unsafe_allow_html=True
225
+ )
226
+
227
+ def render_sidebar(client):
228
+ """Create sidebar interface elements"""
229
+ with st.sidebar:
230
+ st.divider()
231
+ st.markdown("### Diagnostic Capabilities")
232
+ st.markdown("""
233
+ - **Multi-Modality Analysis**: X-ray, MRI, CT, Ultrasound
234
+ - **Pathology Detection**: Fractures, tumors, infections
235
+ - **Comparative Analysis**: Track disease progression
236
+ - **Structured Reporting**: Standardized output format
237
+ - **Clinical Correlation**: Suggested next steps
238
+ - **Disclaimer: This service does not provide medical advice, consult a doctor for analysis and treatment
239
+ """)
240
+ st.divider()
241
+
242
+ st.subheader("Image Upload Section")
243
+ uploaded_file = st.file_uploader(
244
+ "Select Medical Image",
245
+ type=ALLOWED_FILE_TYPES,
246
+ help="Supported formats: PNG, JPG, JPEG"
247
+ )
248
+
249
+ if uploaded_file:
250
+ st.image(Image.open(uploaded_file),
251
+ caption="Uploaded Medical Image",
252
+ use_container_width=True)
253
+
254
+ if st.button("Initiate Analysis πŸ”", use_container_width=True):
255
+ with st.spinner("Analyzing image. This may take 20-30 seconds..."):
256
+ report = generate_radiology_report(uploaded_file, client)
257
+ st.session_state.analysis_result = report
258
+ st.rerun()
259
+
260
+ # ======================
261
+ # APPLICATION ENTRYPOINT
262
+ # ======================
263
+ def main():
264
+ """Primary application controller"""
265
+ configure_application()
266
+ groq_client = initialize_api_client()
267
+
268
+ display_main_interface()
269
+ render_sidebar(groq_client)
270
+
271
+ if __name__ == "__main__":
272
+ main()
requirements.txt ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ streamlit
2
+ groq
3
+ Pillow
4
+ python-dotenv
5
+ reportlab