malavikapradeep2001 commited on
Commit
c5a7e19
·
1 Parent(s): bf6bb9b
frontend/src/components/ResultsPanel.tsx CHANGED
@@ -1,5 +1,5 @@
1
  import { useState } from "react";
2
- import { FileTextIcon, Loader2Icon } from "lucide-react";
3
  import { ImageWithFallback } from "./ImageWithFallback";
4
  import { ReportModal } from "./ReportModal";
5
  import axios from "axios";
@@ -55,6 +55,18 @@ export function ResultsPanel({ uploadedImage, result, loading }: ResultsPanelPro
55
  confidence,
56
  } = (result || {}) as any;
57
 
 
 
 
 
 
 
 
 
 
 
 
 
58
 
59
 
60
  return (
@@ -88,22 +100,92 @@ export function ResultsPanel({ uploadedImage, result, loading }: ResultsPanelPro
88
  </div>
89
  )}
90
 
91
- {/* Summary Section */}
92
- {summary && (
93
- <div className="bg-gray-50 p-4 rounded-lg mb-6">
94
- <h3 className="text-lg font-semibold text-gray-800 mb-2">
95
- AI Summary
96
- </h3>
97
- <p className="text-gray-700 text-sm leading-relaxed">
98
- <strong>Abnormal Cells:</strong> {summary.abnormal_cells} <br />
99
- <strong>Normal Cells:</strong> {summary.normal_cells} <br />
100
- <strong>Average Confidence:</strong> {summary.avg_confidence?.toFixed(2)}% <br />
101
- </p>
102
- <div className="mt-3 text-gray-800 text-sm italic border-t pt-2">
103
- {summary.ai_interpretation || "No AI interpretation available."}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
104
  </div>
105
- </div>
106
- )}
107
 
108
  {/* Detection list */}
109
  {detections && detections.length > 0 && (
@@ -192,6 +274,15 @@ export function ResultsPanel({ uploadedImage, result, loading }: ResultsPanelPro
192
  {/* Show only when not loading and we have analysis data (summary or confidence) */}
193
  {!isLoading && (summary || confidence) && (
194
  <div className="flex items-center justify-end mb-6">
 
 
 
 
 
 
 
 
 
195
  <button
196
  onClick={() => setShowReportModal(true)}
197
  className="flex items-center gap-2 bg-gradient-to-r from-teal-700 via-teal-600 to-teal-700 text-white px-4 py-2 rounded-lg hover:opacity-90 transition-all"
 
1
  import { useState } from "react";
2
+ import { DownloadIcon, FileTextIcon, Loader2Icon } from "lucide-react";
3
  import { ImageWithFallback } from "./ImageWithFallback";
4
  import { ReportModal } from "./ReportModal";
5
  import axios from "axios";
 
55
  confidence,
56
  } = (result || {}) as any;
57
 
58
+ const handleDownload = () => {
59
+ if (annotated_image_url) {
60
+ const link = document.createElement("a");
61
+ link.href = annotated_image_url;
62
+ link.download = "analysis_result.jpg";
63
+ // For Firefox it is necessary to add the link to the DOM
64
+ document.body.appendChild(link);
65
+ link.click();
66
+ link.remove();
67
+ }
68
+ };
69
+
70
 
71
 
72
  return (
 
100
  </div>
101
  )}
102
 
103
+ {/* Summary Section - model-specific rendering (colposcopy, cytology, histopathology) */}
104
+ {summary && (() => {
105
+ const model = (model_used || "").toString();
106
+ const isColpo = /colpo|colposcopy/i.test(model);
107
+ const isCyto = /cyto|cytology/i.test(model);
108
+ const isHistoLike = /mwt|cin|histopath/i.test(model);
109
+
110
+ // helper values
111
+ const abnormalCount = Number(summary.abnormal_cells) || 0;
112
+ const pred = (summary.prediction || summary.result || "").toString().toLowerCase();
113
+ const isAbnormal = abnormalCount > 0 || /abnormal|positive|high-grade|malignant/.test(pred);
114
+
115
+ // Colposcopy: show only Abnormal / Normal (based on abnormal_cells count or prediction)
116
+ if (isColpo) {
117
+ return (
118
+ <div className="bg-gray-50 p-4 rounded-lg mb-6">
119
+ <h3 className="text-lg font-semibold text-gray-800 mb-2">AI Summary</h3>
120
+ <p className="text-gray-700 text-sm">
121
+ <strong>Result:</strong> {isAbnormal ? "Abnormal" : "Normal"}
122
+ </p>
123
+ <div className="mt-3 text-gray-800 text-sm italic border-t pt-2">
124
+ {summary.ai_interpretation || "No AI interpretation available."}
125
+ </div>
126
+ </div>
127
+ );
128
+ }
129
+
130
+ // Cytology: keep existing detailed summary (abnormal/normal counts + avg confidence + interpretation)
131
+ if (isCyto) {
132
+ return (
133
+ <div className="bg-gray-50 p-4 rounded-lg mb-6">
134
+ <h3 className="text-lg font-semibold text-gray-800 mb-2">AI Summary</h3>
135
+ <p className="text-gray-700 text-sm leading-relaxed">
136
+ {typeof summary.abnormal_cells !== 'undefined' && (
137
+ <><strong>Abnormal Cells:</strong> {summary.abnormal_cells} <br /></>
138
+ )}
139
+ {typeof summary.normal_cells !== 'undefined' && (
140
+ <><strong>Normal Cells:</strong> {summary.normal_cells} <br /></>
141
+ )}
142
+ {typeof summary.avg_confidence !== 'undefined' && (
143
+ <><strong>Average Confidence:</strong> {summary.avg_confidence?.toFixed(2)}% <br /></>
144
+ )}
145
+ </p>
146
+ <div className="mt-3 text-gray-800 text-sm italic border-t pt-2">
147
+ {summary.ai_interpretation || "No AI interpretation available."}
148
+ </div>
149
+ </div>
150
+ );
151
+ }
152
+
153
+ // Histopathology / CIN / MWT: show average confidence prominently + interpretation
154
+ if (isHistoLike) {
155
+ return (
156
+ <div className="bg-gray-50 p-4 rounded-lg mb-6">
157
+ <h3 className="text-lg font-semibold text-gray-800 mb-2">AI Summary</h3>
158
+ <p className="text-gray-700 text-sm leading-relaxed">
159
+ <strong>Average Confidence:</strong> {typeof summary.avg_confidence !== 'undefined' ? `${summary.avg_confidence?.toFixed(2)}%` : "-"}
160
+ </p>
161
+ <div className="mt-3 text-gray-800 text-sm italic border-t pt-2">
162
+ {summary.ai_interpretation || "No AI interpretation available."}
163
+ </div>
164
+ </div>
165
+ );
166
+ }
167
+
168
+ // Fallback: render only the fields that exist to avoid empty labels
169
+ return (
170
+ <div className="bg-gray-50 p-4 rounded-lg mb-6">
171
+ <h3 className="text-lg font-semibold text-gray-800 mb-2">AI Summary</h3>
172
+ <p className="text-gray-700 text-sm leading-relaxed">
173
+ {typeof summary.abnormal_cells !== 'undefined' && (
174
+ <><strong>Abnormal Cells:</strong> {summary.abnormal_cells} <br /></>
175
+ )}
176
+ {typeof summary.normal_cells !== 'undefined' && (
177
+ <><strong>Normal Cells:</strong> {summary.normal_cells} <br /></>
178
+ )}
179
+ {typeof summary.avg_confidence !== 'undefined' && (
180
+ <><strong>Average Confidence:</strong> {summary.avg_confidence?.toFixed(2)}% <br /></>
181
+ )}
182
+ </p>
183
+ <div className="mt-3 text-gray-800 text-sm italic border-t pt-2">
184
+ {summary.ai_interpretation || "No AI interpretation available."}
185
+ </div>
186
  </div>
187
+ );
188
+ })()}
189
 
190
  {/* Detection list */}
191
  {detections && detections.length > 0 && (
 
274
  {/* Show only when not loading and we have analysis data (summary or confidence) */}
275
  {!isLoading && (summary || confidence) && (
276
  <div className="flex items-center justify-end mb-6">
277
+ {annotated_image_url && (
278
+ <button
279
+ onClick={handleDownload}
280
+ className="flex items-center gap-2 mr-3 bg-gradient-to-r from-teal-700 via-teal-600 to-teal-700 text-white px-4 py-2 rounded-lg hover:opacity-90 transition-all"
281
+ >
282
+ <DownloadIcon className="w-4 h-4" />
283
+ Download Image
284
+ </button>
285
+ )}
286
  <button
287
  onClick={() => setShowReportModal(true)}
288
  className="flex items-center gap-2 bg-gradient-to-r from-teal-700 via-teal-600 to-teal-700 text-white px-4 py-2 rounded-lg hover:opacity-90 transition-all"