ethix commited on
Commit
b29bd8c
·
1 Parent(s): 77f3a53

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

Files changed (1) hide show
  1. app.py +216 -114
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-danger'
203
  elif label == 'REAL':
204
- return 'bg-success'
205
  elif label == 'UNCERTAIN':
206
- return 'bg-warning'
207
  elif label == 'MAINTENANCE':
208
- return 'bg-info'
209
  else:
210
- return 'bg-secondary'
211
- print(results)
212
  html_content = f"""
213
- <link href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" rel="stylesheet">
214
- <div class="container">
215
- <div class="row mt-4 px-2">
216
- <div class="col">
217
- <h5>SwinV2/detect <span class="badge badge-secondary ml-1">M1</span></h5>
218
- <p>{results[0][3]}</p>
219
- </div>
220
- <div class="col">
221
- <h5>ViT/AI-vs-Real <span class="badge badge-secondary ml-1">M2</span></h5>
222
- <p>{results[1][3]}</p>
223
- </div>
224
- <div class="col">
225
- <h5>Swin/SDXL <span class="badge badge-secondary ml-1">M3</span></h5>
226
- <p>{results[2][3]}</p>
227
- </div>
228
- <div class="col">
229
- <h5>Swin/SDXL-FLUX <span class="badge badge-secondary ml-1">M4</span></h5>
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 class="card">
258
- <div class="card-header {get_header_color(results[0][-1])}" style="height:120px;">
259
- <span class="text-center font-weight-bolder">{results[0][-1]}</span>
260
- </div>
261
- <div class="card-body">
262
- <h5 class="card-title">SwinV2/detect <span class="badge badge-secondary ml-1">M1</span></h5>
263
-
264
- <div class="progress">
265
- <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>
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
- </div>
271
- <div class="card-footer">
272
- <small class="text-muted">model by @haywoodsloan / more info</small>
 
 
 
 
 
273
  </div>
274
  </div>
275
- <div class="card">
276
- <div class="card-header {get_header_color(results[0][-1])}" style="height:120px;">
277
- <span class="text-center font-weight-bolder">{results[0][-1]}</span>
278
- </div>
279
- <div class="card-body">
280
- <h5 class="card-title">SwinV2/detect <span class="badge badge-secondary ml-1">M1</span></h5>
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
- <div class="card">
294
- <div class="card-header {get_header_color(results[0][-1])}" style="height:120px;">
295
- <span class="text-center font-weight-bolder">{results[0][-1]}</span>
296
- </div>
297
- <div class="card-body">
298
- <h5 class="card-title">SwinV2/detect <span class="badge badge-secondary ml-1">M1</span></h5>
299
-
300
- <div class="progress">
301
- <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>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
302
  </div>
303
- <div class="progress">
304
- <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>
 
 
 
 
 
 
305
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
306
  </div>
307
- <div class="card-footer">
308
- <small class="text-muted">model by @haywoodsloan / more info</small>
 
 
 
 
 
 
309
  </div>
310
  </div>
311
- <div class="card">
312
- <div class="card-header {get_header_color(results[0][-1])}" style="height:120px;">
313
- <span class="text-center font-weight-bolder">{results[0][-1]}</span>
314
- </div>
315
- <div class="card-body">
316
- <h5 class="card-title">SwinV2/detect <span class="badge badge-secondary ml-1">M1</span></h5>
317
-
318
- <div class="progress">
319
- <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>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
320
  </div>
321
- <div class="progress">
322
- <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>
 
 
 
 
 
 
323
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
324
  </div>
325
- <div class="card-footer">
326
- <small class="text-muted">model by @haywoodsloan / more info</small>
 
 
 
 
 
 
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=2):
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=3):
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")