Yao211 commited on
Commit
c1d2e01
·
verified ·
1 Parent(s): 8b4dcb9

Delete app.py

Browse files
Files changed (1) hide show
  1. app.py +0 -743
app.py DELETED
@@ -1,743 +0,0 @@
1
- import gradio as gr
2
- import os
3
- import requests
4
- from PIL import Image
5
- import json
6
-
7
- # Configuration
8
- API_BASE_URL = os.getenv("API_BASE_URL")
9
-
10
- def face_compare(frame1, frame2, request: gr.Request = None):
11
- """Face comparison with enhanced result display"""
12
- try:
13
- url = f"{API_BASE_URL}/api/face_match"
14
-
15
- # Prepare files
16
- files = {}
17
- if frame1:
18
- files['image1'] = open(frame1, 'rb')
19
- if frame2:
20
- files['image2'] = open(frame2, 'rb')
21
-
22
- if not files:
23
- return "<div class='error-message'>Please upload both images</div>"
24
-
25
- # Make API request
26
- response = requests.post(url=url, files=files)
27
- result = response.json()
28
-
29
- # Close files
30
- for file in files.values():
31
- file.close()
32
-
33
- # Enhanced result processing
34
- return format_face_comparison_result(result, frame1, frame2)
35
-
36
- except Exception as e:
37
- return f"<div class='error-message'>Error processing request: {str(e)}</div>"
38
-
39
- def format_face_comparison_result(result, img1_path, img2_path):
40
- """Format face comparison results with professional styling"""
41
-
42
- detections = result.get("detections", [])
43
- matches = result.get("match", [])
44
-
45
- # Create result HTML
46
- html = "<div class='result-content'>"
47
-
48
- # Detection results - show all detected faces
49
- if detections:
50
- for i, detection in enumerate(detections):
51
- face_image = detection.get("face", "")
52
- first_face_index = detection.get("firstFaceIndex")
53
- second_face_index = detection.get("secondFaceIndex")
54
-
55
- # Matching results in the new table format
56
- if matches:
57
- html += """
58
- <div class="matching-section">
59
- <div class="matches-table">
60
- <table>
61
- <thead>
62
- <tr>
63
- <th>First Image Face</th>
64
- <th>Second Image Face</th>
65
- <th>Similarity Score</th>
66
- <th>Result</th>
67
- </tr>
68
- </thead>
69
- <tbody>
70
- """
71
-
72
- # Group matches by first image face index for better organization
73
- match_groups = {}
74
- for match in matches:
75
- first_face_index = match.get("firstFaceIndex", "N/A")
76
- if first_face_index not in match_groups:
77
- match_groups[first_face_index] = []
78
- match_groups[first_face_index].append(match)
79
-
80
- row_number = 1
81
- for first_face_index in sorted(match_groups.keys()):
82
- for match in match_groups[first_face_index]:
83
- first_face_index = match.get("firstFaceIndex", "N/A")
84
- second_face_index = match.get("secondFaceIndex", "N/A")
85
- similarity = match.get("similarity", 0)
86
-
87
- # Get face images for display
88
- first_face_img = ""
89
- second_face_img = ""
90
-
91
- for detection in detections:
92
- if detection.get("firstFaceIndex") == first_face_index:
93
- first_face_img = detection.get("face", "")
94
- if detection.get("secondFaceIndex") == second_face_index:
95
- second_face_img = detection.get("face", "")
96
-
97
- # Determine result and color
98
- if similarity >= 0.6: # Threshold for same person
99
- result_text = "same person"
100
- result_class = "result-same"
101
- else:
102
- result_text = "different person"
103
- result_class = "result-different"
104
-
105
- first_face_display = f"<img src='data:image/png;base64,{first_face_img}' class='table-face-thumbnail' />" if first_face_img else f"Face {first_face_index}"
106
- second_face_display = f"<img src='data:image/png;base64,{second_face_img}' class='table-face-thumbnail' />" if second_face_img else f"Face {second_face_index}"
107
-
108
- html += f"""
109
- <tr>
110
- <td class="face-cell">
111
- <div class="face-display">
112
- {first_face_display}
113
- <div class="face-label">Face {first_face_index}</div>
114
- </div>
115
- </td>
116
- <td class="face-cell">
117
- <div class="face-display">
118
- {second_face_display}
119
- <div class="face-label">Face {second_face_index}</div>
120
- </div>
121
- </td>
122
- <td class="similarity-score">{similarity:.4f}</td>
123
- <td><span class="result-text {result_class}">{result_text}</span></td>
124
- </tr>
125
- """
126
- row_number += 1
127
-
128
- html += """
129
- </tbody>
130
- </table>
131
- </div>
132
- </div>
133
- """
134
- else:
135
- html += "<div class='no-results'>No face matches found.</div>"
136
-
137
- html += "</div>"
138
- return html
139
-
140
- def create_footer():
141
- """Create simple footer"""
142
- return """
143
- <div class="footer">
144
- <p>© 2024 MiniAiLive. All rights reserved.</p>
145
- <p>
146
- <a href="https://www.miniai.live" target="_blank">Website</a> |
147
- <a href="mailto:info@miniai.live">Contact Us</a> |
148
- <a href="https://www.miniai.live/privacy-policy" target="_blank">Privacy Policy</a>
149
- </p>
150
- </div>
151
- """
152
-
153
- def get_custom_css():
154
- """Return simplified CSS styling that works for both light and dark themes"""
155
- return """
156
- footer {visibility: hidden}
157
-
158
- /* Full width container */
159
- .gradio-container {
160
- max-width: 95% !important;
161
- width: 95% !important;
162
- margin: 0 auto !important;
163
- }
164
-
165
- /* Center everything */
166
- .container {
167
- display: flex;
168
- flex-direction: column;
169
- align-items: center;
170
- justify-content: center;
171
- width: 100%;
172
- }
173
-
174
- /* Header styling - logo and text in same line */
175
- .company-header {
176
- background: var(--background-fill-primary);
177
- padding: 20px;
178
- margin-bottom: 20px;
179
- text-align: center;
180
- width: 100%;
181
- display: flex;
182
- align-items: center;
183
- justify-content: center;
184
- gap: 20px;
185
- flex-wrap: wrap;
186
- }
187
-
188
- .header-logo {
189
- flex-shrink: 0;
190
- }
191
-
192
- .header-logo img {
193
- width: 120px;
194
- height: auto;
195
- }
196
-
197
- .header-text {
198
- text-align: center;
199
- }
200
-
201
- .header-text h1 {
202
- font-size: 2em;
203
- margin-bottom: 8px;
204
- font-weight: 600;
205
- margin-top: 0;
206
- color: var(--body-text-color);
207
- }
208
-
209
- .header-text p {
210
- font-size: 1.1em;
211
- margin-bottom: 0;
212
- color: var(--body-text-color);
213
- opacity: 0.8;
214
- }
215
-
216
- /* About section layout */
217
- .about-section {
218
- width: 100%;
219
- margin-bottom: 20px;
220
- }
221
-
222
- .about-content {
223
- display: flex;
224
- gap: 20px;
225
- width: 100%;
226
- }
227
-
228
- .features-section {
229
- flex: 0.6;
230
- padding: 20px;
231
- background: var(--background-fill-secondary);
232
- border-radius: 8px;
233
- }
234
-
235
- .demo-items-section {
236
- flex: 0.4;
237
- padding: 20px;
238
- background: var(--background-fill-secondary);
239
- border-radius: 8px;
240
- }
241
-
242
- .demo-items-grid {
243
- display: grid;
244
- grid-template-columns: repeat(2, 1fr);
245
- gap: 10px;
246
- }
247
-
248
- .demo-item {
249
- background: var(--background-fill-primary);
250
- padding: 15px;
251
- border-radius: 6px;
252
- text-align: center;
253
- transition: background-color 0.2s ease;
254
- display: flex;
255
- flex-direction: column;
256
- align-items: center;
257
- justify-content: center;
258
- text-decoration: none;
259
- color: var(--body-text-color);
260
- }
261
-
262
- .demo-item:hover {
263
- background: var(--button-secondary-background-fill-hover);
264
- }
265
-
266
- .demo-item img {
267
- height: 25px;
268
- margin-bottom: 8px;
269
- }
270
-
271
- .demo-item span {
272
- font-size: 0.85em;
273
- font-weight: 500;
274
- }
275
-
276
- /* Main content layout */
277
- .main-content-row {
278
- display: flex;
279
- gap: 20px;
280
- width: 100%;
281
- margin-bottom: 20px;
282
- }
283
-
284
- .upload-section {
285
- flex: 2;
286
- display: flex;
287
- flex-direction: column;
288
- gap: 15px;
289
- }
290
-
291
- .result-section {
292
- flex: 1.2;
293
- }
294
-
295
- .upload-images-row {
296
- display: flex;
297
- gap: 15px;
298
- width: 100%;
299
- }
300
-
301
- .upload-image-col {
302
- flex: 1;
303
- }
304
-
305
- /* Button styling */
306
- .button-primary {
307
- background: var(--button-primary-background-fill) !important;
308
- border: none !important;
309
- padding: 12px 24px !important;
310
- font-size: 16px !important;
311
- font-weight: 600 !important;
312
- color: var(--button-primary-text-color) !important;
313
- border-radius: 6px !important;
314
- cursor: pointer !important;
315
- transition: background-color 0.2s ease !important;
316
- margin: 15px 0 !important;
317
- width: 100% !important;
318
- }
319
-
320
- .button-primary:hover {
321
- background: var(--button-primary-background-fill-hover) !important;
322
- }
323
-
324
- /* Result container styling */
325
- .result-container {
326
- background: var(--background-fill-primary);
327
- padding: 4px;
328
- border-radius: 8px;
329
- margin-top: 0;
330
- width: 100%;
331
- text-align: center;
332
- height: fit-content;
333
- }
334
-
335
- .result-content {
336
- width: 100%;
337
- }
338
-
339
- /* Detection cards */
340
- .detections-grid {
341
- display: grid;
342
- grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
343
- gap: 12px;
344
- margin-top: 15px;
345
- justify-content: center;
346
- }
347
-
348
- .detection-card {
349
- background: var(--background-fill-secondary);
350
- padding: 12px;
351
- border-radius: 6px;
352
- text-align: center;
353
- display: flex;
354
- flex-direction: column;
355
- align-items: center;
356
- }
357
-
358
- .face-thumbnail {
359
- width: 50px;
360
- height: 50px;
361
- border-radius: 50%;
362
- object-fit: cover;
363
- margin-bottom: 8px;
364
- }
365
-
366
- .no-face {
367
- width: 50px;
368
- height: 50px;
369
- background: var(--background-fill-primary);
370
- border-radius: 50%;
371
- display: flex;
372
- align-items: center;
373
- justify-content: center;
374
- margin: 0 auto 8px;
375
- color: var(--body-text-color);
376
- font-size: 0.7em;
377
- opacity: 0.7;
378
- }
379
-
380
- .face-source {
381
- font-size: 0.8em;
382
- color: var(--body-text-color);
383
- opacity: 0.8;
384
- margin-top: 5px;
385
- }
386
-
387
- /* Matching table - NEW STYLING */
388
- .matches-table {
389
- display: flex;
390
- justify-content: center;
391
- width: 100%;
392
- overflow-x: auto;
393
- }
394
-
395
- .matches-table table {
396
- width: 100%;
397
- border-collapse: collapse;
398
- margin-top: 4px;
399
- font-size: 0.9em;
400
- min-width: 500px;
401
- }
402
-
403
- .matches-table th {
404
- background: var(--background-fill-secondary);
405
- color: var(--body-text-color);
406
- padding: 4px 2px;
407
- text-align: center;
408
- font-size: 0.85em;
409
- font-weight: 600;
410
- border-bottom: 2px solid var(--border-color-primary);
411
- }
412
-
413
- .matches-table td {
414
- padding: 4px 2px;
415
- border-bottom: 1px solid var(--border-color-primary);
416
- text-align: center;
417
- font-size: 0.8em;
418
- color: var(--body-text-color);
419
- }
420
-
421
- .row-number {
422
- font-weight: 600;
423
- color: var(--body-text-color);
424
- }
425
-
426
- .face-cell {
427
- vertical-align: middle;
428
- }
429
-
430
- .face-display {
431
- display: flex;
432
- flex-direction: column;
433
- align-items: center;
434
- gap: 1px;
435
- }
436
-
437
- .table-face-thumbnail {
438
- width: 60px;
439
- height: 60px;
440
- border-radius: 50%;
441
- object-fit: cover;
442
- border: 2px solid var(--border-color-primary);
443
- }
444
-
445
- .face-label {
446
- font-size: 0.75em;
447
- color: var(--body-text-color);
448
- opacity: 1;
449
- }
450
-
451
- .similarity-score {
452
- font-weight: 600;
453
- color: var(--body-text-color);
454
- }
455
-
456
- .result-text {
457
- padding: 4px 2px;
458
- border-radius: 10px;
459
- font-size: 1.25em;
460
- font-weight: 600;
461
- text-transform: capitalize;
462
- }
463
-
464
- .result-same {
465
- background: #d4edda;
466
- color: #155724;
467
- }
468
-
469
- .result-different {
470
- background: #f8d7da;
471
- color: #721c24;
472
- }
473
-
474
- .no-results {
475
- text-align: center;
476
- padding: 30px;
477
- color: var(--body-text-color);
478
- opacity: 0.7;
479
- font-style: italic;
480
- }
481
-
482
- /* Error messages */
483
- .error-message {
484
- background: var(--background-fill-secondary);
485
- color: var(--body-text-color);
486
- padding: 15px;
487
- border-radius: 6px;
488
- text-align: center;
489
- width: 100%;
490
- opacity: 0.9;
491
- }
492
-
493
- /* Input images styling */
494
- .gradio-image {
495
- display: flex !important;
496
- justify-content: center !important;
497
- align-items: center !important;
498
- height: 350px !important;
499
- }
500
-
501
- .gradio-image .wrap {
502
- display: flex !important;
503
- justify-content: center !important;
504
- align-items: center !important;
505
- width: 100% !important;
506
- height: 100% !important;
507
- }
508
-
509
- /* Examples styling */
510
- .examples-container {
511
- background: var(--background-fill-secondary);
512
- padding: 12px;
513
- border-radius: 6px;
514
- margin-top: 12px;
515
- width: 100%;
516
- text-align: center;
517
- }
518
-
519
- /* Footer */
520
- .footer {
521
- text-align: center;
522
- margin-top: 20px;
523
- padding: 15px;
524
- border-radius: 6px;
525
- background: var(--background-fill-secondary);
526
- }
527
-
528
- .footer p {
529
- margin: 5px 0;
530
- color: var(--body-text-color);
531
- }
532
-
533
- .footer a {
534
- color: var(--body-text-color);
535
- text-decoration: none;
536
- opacity: 0.8;
537
- }
538
-
539
- .footer a:hover {
540
- opacity: 1;
541
- text-decoration: underline;
542
- }
543
-
544
- /* Section titles */
545
- .section-title {
546
- margin-bottom: 12px !important;
547
- text-align: center;
548
- color: var(--body-text-color);
549
- font-weight: 600;
550
- }
551
-
552
- /* Ensure proper text visibility in dark mode */
553
- .gradio-markdown {
554
- color: var(--body-text-color) !important;
555
- }
556
-
557
- .gradio-markdown h3 {
558
- color: var(--body-text-color) !important;
559
- }
560
-
561
- .gradio-markdown p {
562
- color: var(--body-text-color) !important;
563
- }
564
-
565
- .gradio-markdown li {
566
- color: var(--body-text-color) !important;
567
- }
568
- """
569
-
570
- # Create Gradio interface
571
- with gr.Blocks(
572
- title="MiniAiLive - Face Recognition WebAPI Playground",
573
- theme=gr.themes.Soft(),
574
- css=get_custom_css()
575
- ) as demo:
576
-
577
- with gr.Column(elem_classes="container"):
578
- # Header Section - Logo and text in same line, centered
579
- gr.HTML("""
580
- <div class="company-header">
581
- <div class="header-logo">
582
- <img src="https://miniai.live/wp-content/uploads/2024/02/logo_name-1-768x426-1.png" alt="MiniAiLive Logo">
583
- </div>
584
- <div class="header-text">
585
- <h1>MiniAiLive Face Recognition WebAPI Playground</h1>
586
- <p>Experience our NIST FRVT Top Ranked 1:1 & 1:N Face Matching Technology</p>
587
- </div>
588
- </div>
589
- """)
590
-
591
- # About Section with Features and Demo Items
592
- with gr.Column(elem_classes="about-section"):
593
- with gr.Row(elem_classes="about-content"):
594
- # Features Section (60%)
595
- with gr.Column(scale=0.6, elem_classes="features-section"):
596
- gr.Markdown("""
597
- **MiniAiLive** is a leading provider of cutting-edge face recognition and liveness detection solutions.
598
- Our technology is **NIST FRVT Top Ranked** for Face Recognition.
599
-
600
- ### 🏆 Key Features:
601
- - **NIST FRVT Top Ranked** Top Accuracy in both 1:1 & 1:N Face Matching Technology
602
- - **Real-time** Face Matching & Verification
603
- - **On-Premise** Offers complete data control and privacy
604
- - **On-Device, Offline** Runs on machine. No internet connection is required.
605
- - **Cross-Platform Support** Supports Windows, Linux, Android & iOS
606
- - **Free Service** Completely free to use, Free technical support & update
607
-
608
- [Visit our website](https://miniai.live) to explore our complete suite of AI solutions!
609
- """)
610
-
611
- # Demo Items Section (40%)
612
- with gr.Column(scale=0.4, elem_classes="demo-items-section"):
613
- with gr.Column(elem_classes="demo-items-grid"):
614
- gr.HTML("""
615
- <a href="https://github.com/MiniAiLive" target="_blank" class="demo-item">
616
- <img src="https://miniai.live/wp-content/uploads/2024/10/new_git-1-300x67.png" alt="GitHub">
617
- <span>GitHub</span>
618
- </a>
619
- """)
620
-
621
- gr.HTML("""
622
- <a href="https://huggingface.co/MiniAiLive" target="_blank" class="demo-item">
623
- <img src="https://miniai.live/wp-content/uploads/2024/10/new_hugging-1-300x67.png" alt="HuggingFace">
624
- <span>HuggingFace</span>
625
- </a>
626
- """)
627
-
628
- gr.HTML("""
629
- <a href="https://demo.miniai.live" target="_blank" class="demo-item">
630
- <img src="https://miniai.live/wp-content/uploads/2024/10/new_gradio-300x67.png" alt="Gradio">
631
- <span>Live Demo</span>
632
- </a>
633
- """)
634
-
635
- gr.HTML("""
636
- <a href="https://docs.miniai.live/" target="_blank" class="demo-item">
637
- <img src="https://miniai.live/wp-content/uploads/2024/10/a-300x70.png" alt="Documentation">
638
- <span>Documentation</span>
639
- </a>
640
- """)
641
-
642
- gr.HTML("""
643
- <a href="https://www.youtube.com/@miniailive" target="_blank" class="demo-item">
644
- <img src="https://miniai.live/wp-content/uploads/2024/10/Untitled-1-300x70.png" alt="YouTube">
645
- <span>YouTube</span>
646
- </a>
647
- """)
648
-
649
- gr.HTML("""
650
- <a href="https://play.google.com/store/apps/dev?id=5831076207730531667" target="_blank" class="demo-item">
651
- <img src="https://miniai.live/wp-content/uploads/2024/10/googleplay-300x62.png" alt="Google Play">
652
- <span>Google Play</span>
653
- </a>
654
- """)
655
-
656
- # Main Content - Upload and Results
657
- with gr.Row(elem_classes="main-content-row"):
658
- # Upload Section
659
- with gr.Column(scale=0.6, elem_classes="upload-section"):
660
- gr.Markdown("### Upload Images for Comparison", elem_classes="section-title")
661
-
662
- with gr.Row(elem_classes="upload-images-row"):
663
- # First Image
664
- with gr.Column(scale=1, elem_classes="upload-image-col"):
665
- im_match_in1 = gr.Image(
666
- type='filepath',
667
- height=350,
668
- label="First Image",
669
- show_download_button=False
670
- )
671
-
672
- # Second Image
673
- with gr.Column(scale=1, elem_classes="upload-image-col"):
674
- im_match_in2 = gr.Image(
675
- type='filepath',
676
- height=350,
677
- label="Second Image",
678
- show_download_button=False
679
- )
680
-
681
- # Examples and Button
682
- with gr.Accordion("Try Example Images", open=True):
683
- with gr.Row():
684
- gr.Examples(
685
- examples=[
686
- "assets/1.jpg",
687
- "assets/2.jpg",
688
- "assets/3.jpg",
689
- "assets/4.jpg",
690
- ],
691
- inputs=im_match_in1,
692
- label="First Image Examples"
693
- )
694
- gr.Examples(
695
- examples=[
696
- "assets/1-1.jpg",
697
- "assets/2-1.jpg",
698
- "assets/3-1.jpg",
699
- "assets/4-1.jpg",
700
- ],
701
- inputs=im_match_in2,
702
- label="Second Image Examples"
703
- )
704
-
705
- btn_f_match = gr.Button(
706
- "Compare Faces 🚀",
707
- variant='primary',
708
- elem_classes="button-primary"
709
- )
710
-
711
- # Results Section
712
- with gr.Column(scale=0.4, elem_classes="result-section"):
713
- gr.Markdown("### Comparison Results", elem_classes="section-title")
714
- txt_compare_out = gr.HTML(
715
- value="<div style='text-align: center; padding: 40px;'>Results will appear here after comparison</div>"
716
- )
717
-
718
- # Connect the function
719
- btn_f_match.click(
720
- face_compare,
721
- inputs=[im_match_in1, im_match_in2],
722
- outputs=txt_compare_out
723
- )
724
-
725
- # Visitor Counter
726
- gr.HTML("""
727
- <div style="text-align: center; margin: 20px 0;">
728
- <a href="https://visitorbadge.io/status?path=https%3A%2F%2Fhuggingface.co%2Fspaces%2FMiniAiLive%2FFaceRecognition-LivenessDetection-Demo">
729
- <img src="https://api.visitorbadge.io/api/combined?path=https%3A%2F%2Fhuggingface.co%2Fspaces%2FMiniAiLive%2FFaceRecognition-LivenessDetection-Demo&label=VISITORS&labelColor=%2337d67a&countColor=%23ff8a65&style=plastic&labelStyle=none" />
730
- </a>
731
- </div>
732
- """)
733
-
734
- # Footer
735
- gr.HTML(create_footer())
736
-
737
- if __name__ == "__main__":
738
- demo.launch(
739
- share=False,
740
- show_error=True,
741
- server_name="0.0.0.0",
742
- server_port=7860
743
- )