Refactor HTML generation with Tailwind CSS and enhanced model result visualization
Browse files- Replace Bootstrap with Tailwind CSS for more flexible styling
- Implement dynamic color-coding for model result cards
- Add detailed model information and confidence score displays
- Improve layout and responsiveness of results presentation
- Update Gradio interface column scaling for better visual balance
app.py
CHANGED
@@ -67,7 +67,7 @@ def predict_image(img, confidence_threshold):
|
|
67 |
try:
|
68 |
prediction_1 = clf_1(img_pil)
|
69 |
result_1 = {pred['label']: pred['score'] for pred in prediction_1}
|
70 |
-
result_1output = [1, result_1['real'], result_1['artificial']]
|
71 |
print(result_1output)
|
72 |
# Ensure the result dictionary contains all class names
|
73 |
for class_name in class_names_1:
|
@@ -91,7 +91,7 @@ def predict_image(img, confidence_threshold):
|
|
91 |
try:
|
92 |
prediction_2 = clf_2(img_pil)
|
93 |
result_2 = {pred['label']: pred['score'] for pred in prediction_2}
|
94 |
-
result_2output = [2, result_2['Real Image'], result_2['AI Image']]
|
95 |
print(result_2output)
|
96 |
# Ensure the result dictionary contains all class names
|
97 |
for class_name in class_names_2:
|
@@ -121,7 +121,7 @@ def predict_image(img, confidence_threshold):
|
|
121 |
labels_3[1]: float(probabilities_3[1]), # Real
|
122 |
labels_3[0]: float(probabilities_3[0]) # AI
|
123 |
}
|
124 |
-
result_3output = [3, float(probabilities_3[1]), float(probabilities_3[0])]
|
125 |
print(result_3output)
|
126 |
# Ensure the result dictionary contains all class names
|
127 |
for class_name in labels_3:
|
@@ -151,7 +151,7 @@ def predict_image(img, confidence_threshold):
|
|
151 |
labels_4[1]: float(probabilities_4[1]), # Real
|
152 |
labels_4[0]: float(probabilities_4[0]) # AI
|
153 |
}
|
154 |
-
result_4output = [4, float(probabilities_4[1]), float(probabilities_4[0])]
|
155 |
print(result_4)
|
156 |
# Ensure the result dictionary contains all class names
|
157 |
for class_name in labels_4:
|
@@ -171,7 +171,7 @@ def predict_image(img, confidence_threshold):
|
|
171 |
label_4 = f"Error: {str(e)}"
|
172 |
|
173 |
try:
|
174 |
-
result_5output = [5, 0.0, 0.0, 'MAINTENANCE']
|
175 |
img_bytes = convert_pil_to_bytes(img_pil)
|
176 |
# print(img)
|
177 |
# print(img_bytes)
|
@@ -195,137 +195,239 @@ def predict_image(img, confidence_threshold):
|
|
195 |
combined_outputs = [ result_1output, result_2output, result_3output, result_4output, result_5output ]
|
196 |
return img_pil, combined_outputs
|
197 |
|
|
|
198 |
# Define a function to generate the HTML content
|
199 |
def generate_results_html(results):
|
200 |
def get_header_color(label):
|
201 |
if label == 'AI':
|
202 |
-
return 'bg-
|
203 |
elif label == 'REAL':
|
204 |
-
return 'bg-
|
205 |
elif label == 'UNCERTAIN':
|
206 |
-
return 'bg-
|
207 |
elif label == 'MAINTENANCE':
|
208 |
-
return 'bg-
|
209 |
else:
|
210 |
-
return 'bg-
|
211 |
-
|
212 |
html_content = f"""
|
213 |
-
<link href="https://
|
214 |
-
<div class="container">
|
215 |
-
<div class="
|
216 |
-
|
217 |
-
|
218 |
-
|
219 |
-
|
220 |
-
|
221 |
-
|
222 |
-
|
223 |
-
|
224 |
-
|
225 |
-
|
226 |
-
|
227 |
-
|
228 |
-
|
229 |
-
|
230 |
-
<p>{results[3][3]}</p>
|
231 |
-
</div>
|
232 |
-
<div class="col">
|
233 |
-
<h5>GOAT <span class="badge badge-secondary ml-1">M5</span></h5>
|
234 |
-
<p>{results[4][3]}</p>
|
235 |
-
</div>
|
236 |
-
</div>
|
237 |
-
<div class="col">
|
238 |
-
<div class="card-group">
|
239 |
-
<div class="card">
|
240 |
-
<div class="card-header {get_header_color(results[0][-1])}" style="height:120px;">
|
241 |
-
<span class="text-center font-weight-bolder">{results[0][-1]}</span>
|
242 |
-
</div>
|
243 |
-
<div class="card-body">
|
244 |
-
<h5 class="card-title">SwinV2/detect <span class="badge badge-secondary ml-1">M1</span></h5>
|
245 |
-
|
246 |
-
<div class="progress">
|
247 |
-
<div class="progress-bar" role="progressbar" style="width: {results[0][-3] * 100:.2f}%;" aria-valuenow="{results[0][-3] * 100:.2f}" aria-valuemin="0" aria-valuemax="100">{results[0][-3] * 100:.2f}% (Real)</div>
|
248 |
-
</div>
|
249 |
-
<div class="progress">
|
250 |
-
<div class="progress-bar bg-danger" role="progressbar" style="width: {results[0][-4] * 100:.2f}%;" aria-valuenow="{results[0][-4] * 100:.2f}" aria-valuemin="0" aria-valuemax="100">{results[0][-4] * 100:.2f}% (AI)</div>
|
251 |
-
</div>
|
252 |
-
</div>
|
253 |
-
<div class="card-footer">
|
254 |
-
<small class="text-muted">model by @haywoodsloan / more info</small>
|
255 |
-
</div>
|
256 |
</div>
|
257 |
-
<div
|
258 |
-
<div class="
|
259 |
-
|
260 |
-
|
261 |
-
|
262 |
-
|
263 |
-
|
264 |
-
|
265 |
-
|
266 |
-
</div>
|
267 |
-
<div class="progress">
|
268 |
-
<div class="progress-bar bg-danger" role="progressbar" style="width: {results[0][-4] * 100:.2f}%;" aria-valuenow="{results[0][-4] * 100:.2f}" aria-valuemin="0" aria-valuemax="100">{results[0][-4] * 100:.2f}% (AI)</div>
|
269 |
</div>
|
270 |
-
|
271 |
-
|
272 |
-
|
|
|
|
|
|
|
|
|
|
|
273 |
</div>
|
274 |
</div>
|
275 |
-
<div class="
|
276 |
-
<
|
277 |
-
<
|
278 |
-
</div>
|
279 |
-
<
|
280 |
-
<
|
281 |
-
|
282 |
-
<div class="progress">
|
283 |
-
<div class="progress-bar" role="progressbar" style="width: {results[0][-3] * 100:.2f}%;" aria-valuenow="{results[0][-3] * 100:.2f}" aria-valuemin="0" aria-valuemax="100">{results[0][-3] * 100:.2f}% (Real)</div>
|
284 |
-
</div>
|
285 |
-
<div class="progress">
|
286 |
-
<div class="progress-bar bg-danger" role="progressbar" style="width: {results[0][-4] * 100:.2f}%;" aria-valuenow="{results[0][-4] * 100:.2f}" aria-valuemin="0" aria-valuemax="100">{results[0][-4] * 100:.2f}% (AI)</div>
|
287 |
-
</div>
|
288 |
-
</div>
|
289 |
-
<div class="card-footer">
|
290 |
-
<small class="text-muted">model by @haywoodsloan / more info</small>
|
291 |
-
</div>
|
292 |
</div>
|
293 |
-
|
294 |
-
|
295 |
-
|
296 |
-
|
297 |
-
|
298 |
-
|
299 |
-
|
300 |
-
<
|
301 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
302 |
</div>
|
303 |
-
<div class="
|
304 |
-
<div class="
|
|
|
|
|
|
|
|
|
|
|
|
|
305 |
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
306 |
</div>
|
307 |
-
<div class="
|
308 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
309 |
</div>
|
310 |
</div>
|
311 |
-
<div class="
|
312 |
-
<
|
313 |
-
<
|
314 |
-
</div>
|
315 |
-
<
|
316 |
-
<
|
317 |
-
|
318 |
-
|
319 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
320 |
</div>
|
321 |
-
<div class="
|
322 |
-
<div class="
|
|
|
|
|
|
|
|
|
|
|
|
|
323 |
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
324 |
</div>
|
325 |
-
<div class="
|
326 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
327 |
</div>
|
328 |
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
329 |
</div>
|
330 |
</div>
|
331 |
</div>
|
@@ -343,11 +445,11 @@ with gr.Blocks() as iface:
|
|
343 |
gr.Markdown("# AI Generated Image Classification")
|
344 |
|
345 |
with gr.Row():
|
346 |
-
with gr.Column(scale=
|
347 |
image_input = gr.Image(label="Upload Image to Analyze", sources=['upload'], type='pil')
|
348 |
confidence_slider = gr.Slider(0.0, 1.0, value=0.5, step=0.01, label="Confidence Threshold")
|
349 |
inputs = [image_input, confidence_slider]
|
350 |
-
with gr.Column(scale=
|
351 |
image_output = gr.Image(label="Processed Image")
|
352 |
# Custom HTML component to display results in 5 columns
|
353 |
results_html = gr.HTML(label="Model Predictions")
|
|
|
67 |
try:
|
68 |
prediction_1 = clf_1(img_pil)
|
69 |
result_1 = {pred['label']: pred['score'] for pred in prediction_1}
|
70 |
+
result_1output = [1, 'SwinV2-base', result_1['real'], result_1['artificial']]
|
71 |
print(result_1output)
|
72 |
# Ensure the result dictionary contains all class names
|
73 |
for class_name in class_names_1:
|
|
|
91 |
try:
|
92 |
prediction_2 = clf_2(img_pil)
|
93 |
result_2 = {pred['label']: pred['score'] for pred in prediction_2}
|
94 |
+
result_2output = [2, 'ViT-base Classifer', result_2['Real Image'], result_2['AI Image']]
|
95 |
print(result_2output)
|
96 |
# Ensure the result dictionary contains all class names
|
97 |
for class_name in class_names_2:
|
|
|
121 |
labels_3[1]: float(probabilities_3[1]), # Real
|
122 |
labels_3[0]: float(probabilities_3[0]) # AI
|
123 |
}
|
124 |
+
result_3output = [3, 'SDXL-Trained', float(probabilities_3[1]), float(probabilities_3[0])]
|
125 |
print(result_3output)
|
126 |
# Ensure the result dictionary contains all class names
|
127 |
for class_name in labels_3:
|
|
|
151 |
labels_4[1]: float(probabilities_4[1]), # Real
|
152 |
labels_4[0]: float(probabilities_4[0]) # AI
|
153 |
}
|
154 |
+
result_4output = [4, 'SDXL + FLUX', float(probabilities_4[1]), float(probabilities_4[0])]
|
155 |
print(result_4)
|
156 |
# Ensure the result dictionary contains all class names
|
157 |
for class_name in labels_4:
|
|
|
171 |
label_4 = f"Error: {str(e)}"
|
172 |
|
173 |
try:
|
174 |
+
result_5output = [5, 'TBA', 0.0, 0.0, 'MAINTENANCE']
|
175 |
img_bytes = convert_pil_to_bytes(img_pil)
|
176 |
# print(img)
|
177 |
# print(img_bytes)
|
|
|
195 |
combined_outputs = [ result_1output, result_2output, result_3output, result_4output, result_5output ]
|
196 |
return img_pil, combined_outputs
|
197 |
|
198 |
+
# Define a function to generate the HTML content
|
199 |
# Define a function to generate the HTML content
|
200 |
def generate_results_html(results):
|
201 |
def get_header_color(label):
|
202 |
if label == 'AI':
|
203 |
+
return 'bg-red-500 text-red-700 bg-red-100', 'bg-red-400', 'bg-red-100', 'bg-red-700 text-red-700', 'bg-red-200'
|
204 |
elif label == 'REAL':
|
205 |
+
return 'bg-green-500 text-green-700 bg-green-100', 'bg-green-400', 'bg-green-100', 'bg-green-700 text-green-700', 'bg-green-200'
|
206 |
elif label == 'UNCERTAIN':
|
207 |
+
return 'bg-yellow-500 text-yellow-700 bg-yellow-100', 'bg-yellow-400', 'bg-yellow-100', 'bg-yellow-700 text-yellow-700', 'bg-yellow-200'
|
208 |
elif label == 'MAINTENANCE':
|
209 |
+
return 'bg-blue-500 text-blue-700 bg-blue-100', 'bg-blue-400', 'bg-blue-100', 'bg-blue-700 text-blue-700', 'bg-blue-200'
|
210 |
else:
|
211 |
+
return 'bg-gray-300 text-gray-700 bg-gray-100', 'bg-gray-400', 'bg-gray-100', 'bg-gray-700 text-gray-700', 'bg-gray-200'
|
212 |
+
|
213 |
html_content = f"""
|
214 |
+
<link href="https://cdn.jsdelivr.net/npm/tailwindcss@2.2.19/dist/tailwind.min.css" rel="stylesheet">
|
215 |
+
<div class="container mx-auto mt-4">
|
216 |
+
<div class="grid xl:grid-cols-3 md:grid-cols-2 grid-cols-1 gap-4">
|
217 |
+
<!-- Tile 1: SwinV2/detect -->
|
218 |
+
<div
|
219 |
+
class="group flex flex-col bg-neutral-300 rounded-sm p-4 m-1 border border-neutral-800 shadow-xs transition hover:shadow-lg dark:shadow-gray-700/25">
|
220 |
+
<div
|
221 |
+
class="-m-4 h-24 {get_header_color(results[0][-1])[0]} rounded-sm rounded-b-none transition border group-hover:border-gray-100 group-hover:shadow-lg group-hover:{get_header_color(results[0][-1])[4]}">
|
222 |
+
<span class="text-neutral-300 font-mono tracking-widest p-4 pb-3 block text-xs text-center">MODEL 1: {results[0][1]}</span>
|
223 |
+
<span
|
224 |
+
class="flex w-24 mx-auto tracking-wide items-center justify-center rounded-full {get_header_color(results[0][-1])[2]} px-2.5 py-0.5 {get_header_color(results[0][-1])[3]}"
|
225 |
+
>
|
226 |
+
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="3" stroke="currentColor" class="size-5 mr-2 -ml-3 group-hover:animate group-hover:animate-pulse">
|
227 |
+
{'<path stroke-linecap="round" stroke-linejoin="round" d="M9 12.75 11.25 15 15 9.75M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z" />' if results[0][-1] == 'REAL' else '<path stroke-linecap="round" stroke-linejoin="round" d="m9.75 9.75 4.5 4.5m0-4.5-4.5 4.5M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z" />'}
|
228 |
+
</svg>
|
229 |
+
<p class="whitespace-nowrap text-lg leading-normal font-bold text-center self-center align-middle py-px">{results[0][-1]}</p>
|
230 |
+
</span>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
231 |
</div>
|
232 |
+
<div>
|
233 |
+
<div class="mt-4 relative -mx-4 bg-neutral-800">
|
234 |
+
<div class="w-full bg-neutral-400 rounded-none h-8">
|
235 |
+
<div class="bg-green-400 h-full rounded-none" style="width: {results[0][2] * 100:.2f}%;">
|
236 |
+
<p class="p-2 px-4 text-xs self-center align-middle">Conf:
|
237 |
+
<span class="ml-1 font-medium font-mono">{results[0][2]:.2f}</span>
|
238 |
+
</p>
|
239 |
+
</div>
|
240 |
+
</div>
|
|
|
|
|
|
|
241 |
</div>
|
242 |
+
<div class="mt-4 relative -mx-4 bg-neutral-800">
|
243 |
+
<div class="w-full bg-neutral-400 rounded-none h-8">
|
244 |
+
<div class="bg-red-400 h-full rounded-none" style="width: {results[0][3] * 100:.2f}%;">
|
245 |
+
<p class="p-2 px-4 text-xs self-center align-middle">Conf:
|
246 |
+
<span class="ml-1 font-medium font-mono">{results[0][3]:.2f}</span>
|
247 |
+
</p>
|
248 |
+
</div>
|
249 |
+
</div>
|
250 |
</div>
|
251 |
</div>
|
252 |
+
<div class="flex flex-col items-start">
|
253 |
+
<h4 class="mt-4 text-sm font-semibold tracking-wide">SwinV2 Based</h4>
|
254 |
+
<hr class="py-px my-2 w-full bg-neutral-700" />
|
255 |
+
<div class="text-xs font-mono">Real: {results[0][2]:.4f}, AI: {results[0][3]:.4f}</div>
|
256 |
+
<hr class="py-px mt-6 w-full bg-neutral-700" />
|
257 |
+
<a class="mt-2 text-[0.66rem] tracking-wide">@haywoodsloan / more info</a>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
258 |
</div>
|
259 |
+
</div>
|
260 |
+
<!-- Tile 2: ViT/AI-vs-Real -->
|
261 |
+
<div
|
262 |
+
class="group flex flex-col bg-neutral-300 rounded-sm p-4 m-1 border border-neutral-800 shadow-xs transition hover:shadow-lg dark:shadow-gray-700/25">
|
263 |
+
<div
|
264 |
+
class="-m-4 h-24 {get_header_color(results[1][-1])[0]} rounded-sm rounded-b-none transition border group-hover:border-gray-100 group-hover:shadow-lg group-hover:{get_header_color(results[1][-1])[4]}">
|
265 |
+
<span class="text-neutral-300 font-mono tracking-widest p-4 pb-3 block text-xs text-center">MODEL 2: {results[1][1]}</span>
|
266 |
+
<span
|
267 |
+
class="flex w-24 mx-auto tracking-wide items-center justify-center rounded-full {get_header_color(results[1][-1])[2]} px-2.5 py-0.5 {get_header_color(results[1][-1])[3]}"
|
268 |
+
>
|
269 |
+
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="3" stroke="currentColor" class="size-5 mr-2 -ml-3 group-hover:animate group-hover:animate-pulse">
|
270 |
+
{'<path stroke-linecap="round" stroke-linejoin="round" d="M9 12.75 11.25 15 15 9.75M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z" />' if results[1][-1] == 'REAL' else '<path stroke-linecap="round" stroke-linejoin="round" d="m9.75 9.75 4.5 4.5m0-4.5-4.5 4.5M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z" />'}
|
271 |
+
</svg>
|
272 |
+
<p class="whitespace-nowrap text-lg leading-normal font-bold text-center self-center align-middle py-px">{results[1][-1]}</p>
|
273 |
+
</span>
|
274 |
+
</div>
|
275 |
+
<div>
|
276 |
+
<div class="mt-4 relative -mx-4 bg-neutral-800">
|
277 |
+
<div class="w-full bg-neutral-400 rounded-none h-8">
|
278 |
+
<div class="bg-green-400 h-full rounded-none" style="width: {results[1][1] * 100:.2f}%;">
|
279 |
+
<p class="p-2 px-4 text-xs self-center align-middle">Conf:
|
280 |
+
<span class="ml-1 font-medium font-mono">{results[1][1]:.2f}</span>
|
281 |
+
</p>
|
282 |
+
</div>
|
283 |
+
</div>
|
284 |
</div>
|
285 |
+
<div class="mt-4 relative -mx-4 bg-neutral-800">
|
286 |
+
<div class="w-full bg-neutral-400 rounded-none h-8">
|
287 |
+
<div class="bg-red-400 h-full rounded-none" style="width: {results[1][2] * 100:.2f}%;">
|
288 |
+
<p class="p-2 px-4 text-xs self-center align-middle">Conf:
|
289 |
+
<span class="ml-1 font-medium font-mono">{results[1][2]:.2f}</span>
|
290 |
+
</p>
|
291 |
+
</div>
|
292 |
+
</div>
|
293 |
</div>
|
294 |
+
</div>
|
295 |
+
<div class="flex flex-col items-start">
|
296 |
+
<h4 class="mt-4 text-sm font-semibold tracking-wide">ViT Based</h4>
|
297 |
+
<hr class="py-px my-2 w-full bg-neutral-700" />
|
298 |
+
<div class="text-xs font-mono">Real: {results[1][1]:.4f}, AI: {results[1][2]:.4f}</div>
|
299 |
+
<hr class="py-px mt-6 w-full bg-neutral-700" />
|
300 |
+
<a class="mt-2 text-[0.66rem] tracking-wide">@Heem2 / more info</a>
|
301 |
+
</div>
|
302 |
+
</div>
|
303 |
+
<!-- Tile 3: Swin/SDXL -->
|
304 |
+
<div
|
305 |
+
class="group flex flex-col bg-neutral-300 rounded-sm p-4 m-1 border border-neutral-800 shadow-xs transition hover:shadow-lg dark:shadow-gray-700/25">
|
306 |
+
<div
|
307 |
+
class="-m-4 h-24 {get_header_color(results[2][-1])[0]} rounded-sm rounded-b-none transition border group-hover:border-gray-100 group-hover:shadow-lg group-hover:{get_header_color(results[2][-1])[4]}">
|
308 |
+
<span class="text-neutral-300 font-mono tracking-widest p-4 pb-3 block text-xs text-center">MODEL 3: {results[2][1]}</span>
|
309 |
+
<span
|
310 |
+
class="flex w-24 mx-auto tracking-wide items-center justify-center rounded-full {get_header_color(results[2][-1])[2]} px-2.5 py-0.5 {get_header_color(results[2][-1])[3]}"
|
311 |
+
>
|
312 |
+
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="3" stroke="currentColor" class="size-5 mr-2 -ml-3 group-hover:animate group-hover:animate-pulse">
|
313 |
+
{'<path stroke-linecap="round" stroke-linejoin="round" d="M9 12.75 11.25 15 15 9.75M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z" />' if results[2][-1] == 'REAL' else '<path stroke-linecap="round" stroke-linejoin="round" d="m9.75 9.75 4.5 4.5m0-4.5-4.5 4.5M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z" />'}
|
314 |
+
</svg>
|
315 |
+
<p class="whitespace-nowrap text-lg leading-normal font-bold text-center self-center align-middle py-px">{results[2][-1]}</p>
|
316 |
+
</span>
|
317 |
+
</div>
|
318 |
+
<div>
|
319 |
+
<div class="mt-4 relative -mx-4 bg-neutral-800">
|
320 |
+
<div class="w-full bg-neutral-400 rounded-none h-8">
|
321 |
+
<div class="bg-green-400 h-full rounded-none" style="width: {results[2][1] * 100:.2f}%;">
|
322 |
+
<p class="p-2 px-4 text-xs self-center align-middle">Conf:
|
323 |
+
<span class="ml-1 font-medium font-mono">{results[2][1]:.2f}</span>
|
324 |
+
</p>
|
325 |
+
</div>
|
326 |
+
</div>
|
327 |
</div>
|
328 |
+
<div class="mt-4 relative -mx-4 bg-neutral-800">
|
329 |
+
<div class="w-full bg-neutral-400 rounded-none h-8">
|
330 |
+
<div class="bg-red-400 h-full rounded-none" style="width: {results[2][2] * 100:.2f}%;">
|
331 |
+
<p class="p-2 px-4 text-xs self-center align-middle">Conf:
|
332 |
+
<span class="ml-1 font-medium font-mono">{results[2][2]:.2f}</span>
|
333 |
+
</p>
|
334 |
+
</div>
|
335 |
+
</div>
|
336 |
</div>
|
337 |
</div>
|
338 |
+
<div class="flex flex-col items-start">
|
339 |
+
<h4 class="mt-4 text-sm font-semibold tracking-wide">Swin Based</h4>
|
340 |
+
<hr class="py-px my-2 w-full bg-neutral-700" />
|
341 |
+
<div class="text-xs font-mono">Real: {results[2][1]:.4f}, AI: {results[2][2]:.4f}</div>
|
342 |
+
<hr class="py-px mt-6 w-full bg-neutral-700" />
|
343 |
+
<a class="mt-2 text-[0.66rem] tracking-wide">@Organika / more info</a>
|
344 |
+
</div>
|
345 |
+
</div>
|
346 |
+
<!-- Tile 4: Swin/SDXL-FLUX -->
|
347 |
+
<div
|
348 |
+
class="group flex flex-col bg-neutral-300 rounded-sm p-4 m-1 border border-neutral-800 shadow-xs transition hover:shadow-lg dark:shadow-gray-700/25">
|
349 |
+
<div
|
350 |
+
class="-m-4 h-24 {get_header_color(results[3][-1])[0]} rounded-sm rounded-b-none transition border group-hover:border-gray-100 group-hover:shadow-lg group-hover:{get_header_color(results[3][-1])[4]}">
|
351 |
+
<span class="text-neutral-300 font-mono tracking-widest p-4 pb-3 block text-xs text-center">MODEL 4: {results[3][1]}</span>
|
352 |
+
<span
|
353 |
+
class="flex w-24 mx-auto tracking-wide items-center justify-center rounded-full {get_header_color(results[3][-1])[2]} px-2.5 py-0.5 {get_header_color(results[3][-1])[3]}"
|
354 |
+
>
|
355 |
+
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="3" stroke="currentColor" class="size-5 mr-2 -ml-3 group-hover:animate group-hover:animate-pulse">
|
356 |
+
{'<path stroke-linecap="round" stroke-linejoin="round" d="M9 12.75 11.25 15 15 9.75M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z" />' if results[3][-1] == 'REAL' else '<path stroke-linecap="round" stroke-linejoin="round" d="m9.75 9.75 4.5 4.5m0-4.5-4.5 4.5M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z" />'}
|
357 |
+
</svg>
|
358 |
+
<p class="whitespace-nowrap text-lg leading-normal font-bold text-center self-center align-middle py-px">{results[3][-1]}</p>
|
359 |
+
</span>
|
360 |
+
</div>
|
361 |
+
<div>
|
362 |
+
<div class="mt-4 relative -mx-4 bg-neutral-800">
|
363 |
+
<div class="w-full bg-neutral-400 rounded-none h-8">
|
364 |
+
<div class="bg-green-400 h-full rounded-none" style="width: {results[3][1] * 100:.2f}%;">
|
365 |
+
<p class="p-2 px-4 text-xs self-center align-middle">Conf:
|
366 |
+
<span class="ml-1 font-medium font-mono">{results[3][1]:.2f}</span>
|
367 |
+
</p>
|
368 |
+
</div>
|
369 |
+
</div>
|
370 |
</div>
|
371 |
+
<div class="mt-4 relative -mx-4 bg-neutral-800">
|
372 |
+
<div class="w-full bg-neutral-400 rounded-none h-8">
|
373 |
+
<div class="bg-red-400 h-full rounded-none" style="width: {results[3][2] * 100:.2f}%;">
|
374 |
+
<p class="p-2 px-4 text-xs self-center align-middle">Conf:
|
375 |
+
<span class="ml-1 font-medium font-mono">{results[3][2]:.2f}</span>
|
376 |
+
</p>
|
377 |
+
</div>
|
378 |
+
</div>
|
379 |
</div>
|
380 |
+
</div>
|
381 |
+
<div class="flex flex-col items-start">
|
382 |
+
<h4 class="mt-4 text-sm font-semibold tracking-wide">Swin Based</h4>
|
383 |
+
<hr class="py-px my-2 w-full bg-neutral-700" />
|
384 |
+
<div class="text-xs font-mono">Real: {results[3][1]:.4f}, AI: {results[3][2]:.4f}</div>
|
385 |
+
<hr class="py-px mt-6 w-full bg-neutral-700" />
|
386 |
+
<a class="mt-2 text-[0.66rem] tracking-wide">@cmckinle / more info</a>
|
387 |
+
</div>
|
388 |
+
</div>
|
389 |
+
<!-- Tile 5: GOAT -->
|
390 |
+
<div
|
391 |
+
class="group flex flex-col bg-neutral-300 rounded-sm p-4 m-1 border border-neutral-800 shadow-xs transition hover:shadow-lg dark:shadow-gray-700/25">
|
392 |
+
<div
|
393 |
+
class="-m-4 h-24 {get_header_color(results[4][-1])[0]} rounded-sm rounded-b-none transition border group-hover:border-gray-100 group-hover:shadow-lg group-hover:{get_header_color(results[4][-1])[4]}">
|
394 |
+
<span class="text-neutral-300 font-mono tracking-widest p-4 pb-3 block text-xs text-center">MODEL 5: {results[4][1]}</span>
|
395 |
+
<span
|
396 |
+
class="flex w-24 mx-auto tracking-wide items-center justify-center rounded-full {get_header_color(results[4][-1])[2]} px-2.5 py-0.5 {get_header_color(results[4][-1])[3]}"
|
397 |
+
>
|
398 |
+
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="3" stroke="currentColor" class="size-5 mr-2 -ml-3 group-hover:animate group-hover:animate-pulse">
|
399 |
+
{'<path stroke-linecap="round" stroke-linejoin="round" d="M9 12.75 11.25 15 15 9.75M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z" />' if results[4][-1] == 'REAL' else '<path stroke-linecap="round" stroke-linejoin="round" d="m9.75 9.75 4.5 4.5m0-4.5-4.5 4.5M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z" />'}
|
400 |
+
</svg>
|
401 |
+
<p class="whitespace-nowrap text-lg leading-normal font-bold text-center self-center align-middle py-px">{results[4][-1]}</p>
|
402 |
+
</span>
|
403 |
+
</div>
|
404 |
+
<div>
|
405 |
+
<div class="mt-4 relative -mx-4 bg-neutral-800">
|
406 |
+
<div class="w-full bg-neutral-400 rounded-none h-8">
|
407 |
+
<div class="bg-green-400 h-full rounded-none" style="width: 50%;">
|
408 |
+
<p class="p-2 px-4 text-xs self-center align-middle">Conf:
|
409 |
+
<span class="ml-1 font-medium font-mono">50%</span>
|
410 |
+
</p>
|
411 |
+
</div>
|
412 |
+
</div>
|
413 |
</div>
|
414 |
+
<div class="mt-4 relative -mx-4 bg-neutral-800">
|
415 |
+
<div class="w-full bg-neutral-400 rounded-none h-8">
|
416 |
+
<div class="bg-red-400 h-full rounded-none" style="width: 50%;">
|
417 |
+
<p class="p-2 px-4 text-xs self-center align-middle">Conf:
|
418 |
+
<span class="ml-1 font-medium font-mono">50%</span>
|
419 |
+
</p>
|
420 |
+
</div>
|
421 |
+
</div>
|
422 |
</div>
|
423 |
</div>
|
424 |
+
<div class="flex flex-col items-start">
|
425 |
+
<h4 class="mt-4 text-sm font-semibold tracking-wide">GOAT Model</h4>
|
426 |
+
<hr class="py-px my-2 w-full bg-neutral-700" />
|
427 |
+
<div class="text-xs font-mono">Real: 50%, AI: 50%</div>
|
428 |
+
<hr class="py-px mt-6 w-full bg-neutral-700" />
|
429 |
+
<a class="mt-2 text-[0.66rem] tracking-wide">@GOAT / more info</a>
|
430 |
+
</div>
|
431 |
</div>
|
432 |
</div>
|
433 |
</div>
|
|
|
445 |
gr.Markdown("# AI Generated Image Classification")
|
446 |
|
447 |
with gr.Row():
|
448 |
+
with gr.Column(scale=1):
|
449 |
image_input = gr.Image(label="Upload Image to Analyze", sources=['upload'], type='pil')
|
450 |
confidence_slider = gr.Slider(0.0, 1.0, value=0.5, step=0.01, label="Confidence Threshold")
|
451 |
inputs = [image_input, confidence_slider]
|
452 |
+
with gr.Column(scale=2):
|
453 |
image_output = gr.Image(label="Processed Image")
|
454 |
# Custom HTML component to display results in 5 columns
|
455 |
results_html = gr.HTML(label="Model Predictions")
|