kamau1 commited on
Commit
e1f32ed
·
verified ·
1 Parent(s): 71f7767

update: api usage tab design

Browse files
app/__pycache__/__init__.cpython-313.pyc ADDED
Binary file (395 Bytes). View file
 
app/core/__pycache__/__init__.cpython-313.pyc ADDED
Binary file (147 Bytes). View file
 
app/core/__pycache__/config.cpython-313.pyc ADDED
Binary file (2.32 kB). View file
 
static/css/dashboard-simple.css CHANGED
@@ -520,13 +520,13 @@
520
  .api-documentation-section {
521
  margin-top: 60px;
522
  padding: 40px 0;
523
- background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%);
524
- border-top: 1px solid #e2e8f0;
525
  }
526
 
527
  .api-docs-header {
528
  text-align: center;
529
- margin-bottom: 50px;
530
  max-width: 800px;
531
  margin-left: auto;
532
  margin-right: auto;
@@ -534,151 +534,201 @@
534
  }
535
 
536
  .api-docs-header h2 {
537
- font-size: 2.5rem;
538
- font-weight: 700;
539
- color: #1e293b;
540
- margin-bottom: 16px;
541
- background: linear-gradient(135deg, #2563eb, #1d4ed8);
542
- -webkit-background-clip: text;
543
- -webkit-text-fill-color: transparent;
544
- background-clip: text;
545
  }
546
 
547
  .api-docs-header p {
548
- font-size: 1.25rem;
549
- color: #64748b;
550
- line-height: 1.6;
551
  }
552
 
553
- .api-docs-grid {
554
- display: grid;
555
- grid-template-columns: repeat(auto-fit, minmax(400px, 1fr));
556
- gap: 24px;
557
- max-width: 1400px;
558
  margin: 0 auto;
559
  padding: 0 20px;
560
  }
561
 
562
- .api-docs-card {
 
563
  background: white;
564
- border-radius: 12px;
565
- box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
566
- overflow: hidden;
567
- transition: all 0.3s ease;
568
- border: 1px solid #e2e8f0;
569
  }
570
 
571
- .api-docs-card:hover {
572
- box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
573
- transform: translateY(-2px);
 
 
 
 
 
 
 
574
  }
575
 
576
- .api-docs-card-header {
577
- display: flex;
578
- justify-content: space-between;
579
- align-items: center;
580
- padding: 20px 24px;
581
- background: linear-gradient(135deg, #f8fafc, #f1f5f9);
582
- border-bottom: 1px solid #e2e8f0;
583
  }
584
 
585
- .api-docs-card-header h3 {
586
- margin: 0;
587
- font-size: 1.25rem;
588
- font-weight: 600;
589
- color: #1e293b;
590
  }
591
 
592
- .copy-btn {
593
- background: #2563eb;
594
- color: white;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
595
  border: none;
596
- padding: 8px 16px;
597
- border-radius: 6px;
598
  font-size: 0.875rem;
599
  font-weight: 500;
 
600
  cursor: pointer;
 
601
  transition: all 0.2s ease;
 
602
  }
603
 
604
- .copy-btn:hover {
605
- background: #1d4ed8;
606
- transform: scale(1.05);
607
  }
608
 
609
- .api-docs-card-content {
610
- padding: 24px;
 
 
611
  }
612
 
613
- .api-endpoint {
 
 
 
 
 
 
 
 
 
 
 
 
614
  display: flex;
 
615
  align-items: center;
616
- gap: 12px;
617
- margin-bottom: 16px;
618
- padding: 12px 16px;
619
- background: #f1f5f9;
620
- border-radius: 8px;
621
- border-left: 4px solid #2563eb;
622
  }
623
 
624
- .endpoint-method {
625
- background: #2563eb;
 
 
 
 
 
 
626
  color: white;
627
- padding: 4px 8px;
 
628
  border-radius: 4px;
629
  font-size: 0.75rem;
630
- font-weight: 600;
631
- letter-spacing: 0.05em;
 
632
  }
633
 
634
- .endpoint-url {
635
- font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
636
- font-size: 0.875rem;
637
- color: #1e293b;
638
- word-break: break-all;
639
  }
640
 
641
  .code-block {
642
- background: #1e293b;
643
- color: #e2e8f0;
644
  padding: 20px;
645
- border-radius: 8px;
646
- font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
647
- font-size: 0.875rem;
648
- line-height: 1.6;
649
- overflow-x: auto;
650
  margin: 0;
651
- white-space: pre-wrap;
652
- word-wrap: break-word;
653
- }
654
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
655
  .api-docs-footer {
656
- margin-top: 50px;
657
- max-width: 1400px;
658
- margin-left: auto;
659
- margin-right: auto;
660
- padding: 0 20px;
661
  }
662
 
663
  .api-docs-info-grid {
664
  display: grid;
665
- grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
666
- gap: 24px;
667
  }
668
 
669
  .api-info-card {
670
  background: white;
671
- padding: 24px;
672
- border-radius: 12px;
673
- box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
674
- border: 1px solid #e2e8f0;
675
  }
676
 
677
  .api-info-card h4 {
678
  margin: 0 0 16px 0;
679
- font-size: 1.125rem;
680
  font-weight: 600;
681
- color: #1e293b;
682
  }
683
 
684
  .api-info-card ul {
@@ -688,10 +738,11 @@
688
  }
689
 
690
  .api-info-card li {
691
- padding: 8px 0;
692
- border-bottom: 1px solid #f1f5f9;
693
- color: #475569;
694
  line-height: 1.5;
 
695
  }
696
 
697
  .api-info-card li:last-child {
@@ -699,47 +750,52 @@
699
  }
700
 
701
  .api-info-card strong {
702
- color: #1e293b;
703
  font-weight: 600;
704
  }
705
 
706
- /* Responsive Design for API Docs */
707
  @media (max-width: 768px) {
708
  .api-docs-header h2 {
709
- font-size: 2rem;
710
  }
711
 
712
- .api-docs-header p {
713
- font-size: 1.125rem;
714
  }
715
 
716
- .api-docs-grid {
717
- grid-template-columns: 1fr;
718
- padding: 0 16px;
719
  }
720
 
721
- .api-docs-card-header {
722
- padding: 16px 20px;
723
- flex-direction: column;
724
- align-items: flex-start;
725
- gap: 12px;
726
  }
727
 
728
- .api-docs-card-content {
729
- padding: 20px;
 
730
  }
731
 
732
- .code-block {
 
733
  font-size: 0.8rem;
734
- padding: 16px;
735
  }
736
 
737
- .endpoint-url {
738
- font-size: 0.8rem;
 
 
 
 
 
 
 
 
739
  }
740
 
741
  .api-docs-info-grid {
742
  grid-template-columns: 1fr;
743
- padding: 0 16px;
744
  }
745
  }
 
520
  .api-documentation-section {
521
  margin-top: 60px;
522
  padding: 40px 0;
523
+ background: #fafbfc;
524
+ border-top: 1px solid #e1e5e9;
525
  }
526
 
527
  .api-docs-header {
528
  text-align: center;
529
+ margin-bottom: 40px;
530
  max-width: 800px;
531
  margin-left: auto;
532
  margin-right: auto;
 
534
  }
535
 
536
  .api-docs-header h2 {
537
+ font-size: 2rem;
538
+ font-weight: 600;
539
+ color: #1a1a1a;
540
+ margin-bottom: 12px;
 
 
 
 
541
  }
542
 
543
  .api-docs-header p {
544
+ font-size: 1rem;
545
+ color: #666;
546
+ line-height: 1.5;
547
  }
548
 
549
+ .api-docs-container {
550
+ max-width: 1200px;
 
 
 
551
  margin: 0 auto;
552
  padding: 0 20px;
553
  }
554
 
555
+ /* API Endpoint Info */
556
+ .api-endpoint-info {
557
  background: white;
558
+ border: 1px solid #e1e5e9;
559
+ border-radius: 8px;
560
+ padding: 24px;
561
+ margin-bottom: 32px;
 
562
  }
563
 
564
+ .endpoint-method {
565
+ display: inline-block;
566
+ background: #0969da;
567
+ color: white;
568
+ padding: 4px 8px;
569
+ border-radius: 4px;
570
+ font-size: 0.75rem;
571
+ font-weight: 600;
572
+ letter-spacing: 0.5px;
573
+ margin-right: 12px;
574
  }
575
 
576
+ .endpoint-url {
577
+ font-family: 'SF Mono', 'Monaco', 'Inconsolata', 'Roboto Mono', monospace;
578
+ font-size: 0.9rem;
579
+ color: #1a1a1a;
580
+ background: #f6f8fa;
581
+ padding: 2px 6px;
582
+ border-radius: 3px;
583
  }
584
 
585
+ .endpoint-description {
586
+ margin: 16px 0 0 0;
587
+ color: #656d76;
588
+ font-size: 0.9rem;
589
+ line-height: 1.5;
590
  }
591
 
592
+ /* Tabbed Interface */
593
+ .api-tabs-container {
594
+ background: white;
595
+ border: 1px solid #e1e5e9;
596
+ border-radius: 8px;
597
+ overflow: hidden;
598
+ margin-bottom: 32px;
599
+ }
600
+
601
+ .api-tabs {
602
+ display: flex;
603
+ background: #f6f8fa;
604
+ border-bottom: 1px solid #e1e5e9;
605
+ overflow-x: auto;
606
+ }
607
+
608
+ .api-tab {
609
+ background: none;
610
  border: none;
611
+ padding: 12px 20px;
 
612
  font-size: 0.875rem;
613
  font-weight: 500;
614
+ color: #656d76;
615
  cursor: pointer;
616
+ border-bottom: 2px solid transparent;
617
  transition: all 0.2s ease;
618
+ white-space: nowrap;
619
  }
620
 
621
+ .api-tab:hover {
622
+ color: #0969da;
623
+ background: #ffffff;
624
  }
625
 
626
+ .api-tab.active {
627
+ color: #0969da;
628
+ background: white;
629
+ border-bottom-color: #0969da;
630
  }
631
 
632
+ .api-tab-content {
633
+ position: relative;
634
+ }
635
+
636
+ .tab-pane {
637
+ display: none;
638
+ }
639
+
640
+ .tab-pane.active {
641
+ display: block;
642
+ }
643
+
644
+ .code-header {
645
  display: flex;
646
+ justify-content: space-between;
647
  align-items: center;
648
+ padding: 16px 20px;
649
+ background: #f6f8fa;
650
+ border-bottom: 1px solid #e1e5e9;
 
 
 
651
  }
652
 
653
+ .code-title {
654
+ font-size: 0.875rem;
655
+ font-weight: 500;
656
+ color: #1a1a1a;
657
+ }
658
+
659
+ .copy-btn {
660
+ background: #0969da;
661
  color: white;
662
+ border: none;
663
+ padding: 6px 12px;
664
  border-radius: 4px;
665
  font-size: 0.75rem;
666
+ font-weight: 500;
667
+ cursor: pointer;
668
+ transition: background-color 0.2s ease;
669
  }
670
 
671
+ .copy-btn:hover {
672
+ background: #0860ca;
 
 
 
673
  }
674
 
675
  .code-block {
676
+ background: #0d1117;
677
+ color: #e6edf3;
678
  padding: 20px;
 
 
 
 
 
679
  margin: 0;
680
+ font-family: 'SF Mono', 'Monaco', 'Inconsolata', 'Roboto Mono', monospace;
681
+ font-size: 0.8rem;
682
+ line-height: 1.45;
683
+ overflow-x: auto;
684
+ white-space: pre;
685
+ }
686
+
687
+ /* Syntax Highlighting */
688
+ .code-block .keyword { color: #ff7b72; }
689
+ .code-block .string { color: #a5d6ff; }
690
+ .code-block .number { color: #79c0ff; }
691
+ .code-block .comment { color: #8b949e; font-style: italic; }
692
+ .code-block .function { color: #d2a8ff; }
693
+ .code-block .variable { color: #ffa657; }
694
+ .code-block .operator { color: #ff7b72; }
695
+ .code-block .property { color: #79c0ff; }
696
+ .code-block .class { color: #7ee787; }
697
+ .code-block .module { color: #7ee787; }
698
+ .code-block .namespace { color: #7ee787; }
699
+ .code-block .method { color: #d2a8ff; }
700
+ .code-block .flag { color: #ff7b72; }
701
+ .code-block .cmd { color: #7ee787; }
702
+
703
+ /* JSON Syntax Highlighting */
704
+ .code-block .json-key { color: #79c0ff; }
705
+ .code-block .json-string { color: #a5d6ff; }
706
+ .code-block .json-number { color: #79c0ff; }
707
+ .code-block .json-boolean { color: #ff7b72; }
708
+
709
+ /* Additional Information */
710
  .api-docs-footer {
711
+ margin-top: 32px;
 
 
 
 
712
  }
713
 
714
  .api-docs-info-grid {
715
  display: grid;
716
+ grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
717
+ gap: 20px;
718
  }
719
 
720
  .api-info-card {
721
  background: white;
722
+ padding: 20px;
723
+ border-radius: 8px;
724
+ border: 1px solid #e1e5e9;
 
725
  }
726
 
727
  .api-info-card h4 {
728
  margin: 0 0 16px 0;
729
+ font-size: 1rem;
730
  font-weight: 600;
731
+ color: #1a1a1a;
732
  }
733
 
734
  .api-info-card ul {
 
738
  }
739
 
740
  .api-info-card li {
741
+ padding: 6px 0;
742
+ color: #656d76;
743
+ font-size: 0.875rem;
744
  line-height: 1.5;
745
+ border-bottom: 1px solid #f6f8fa;
746
  }
747
 
748
  .api-info-card li:last-child {
 
750
  }
751
 
752
  .api-info-card strong {
753
+ color: #1a1a1a;
754
  font-weight: 600;
755
  }
756
 
757
+ /* Responsive Design */
758
  @media (max-width: 768px) {
759
  .api-docs-header h2 {
760
+ font-size: 1.75rem;
761
  }
762
 
763
+ .api-docs-container {
764
+ padding: 0 16px;
765
  }
766
 
767
+ .api-endpoint-info {
768
+ padding: 20px;
 
769
  }
770
 
771
+ .endpoint-url {
772
+ font-size: 0.8rem;
773
+ word-break: break-all;
 
 
774
  }
775
 
776
+ .api-tabs {
777
+ flex-wrap: nowrap;
778
+ overflow-x: auto;
779
  }
780
 
781
+ .api-tab {
782
+ padding: 10px 16px;
783
  font-size: 0.8rem;
 
784
  }
785
 
786
+ .code-header {
787
+ padding: 12px 16px;
788
+ flex-direction: column;
789
+ align-items: flex-start;
790
+ gap: 8px;
791
+ }
792
+
793
+ .code-block {
794
+ font-size: 0.75rem;
795
+ padding: 16px;
796
  }
797
 
798
  .api-docs-info-grid {
799
  grid-template-columns: 1fr;
 
800
  }
801
  }
static/js/dashboard.js CHANGED
@@ -396,6 +396,31 @@ function fallbackCopyTextToClipboard(text) {
396
  document.body.removeChild(textArea);
397
  }
398
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
399
  // Make dashboard instance globally available for sample image clicks
400
  let dashboard;
401
 
 
396
  document.body.removeChild(textArea);
397
  }
398
 
399
+ // API Documentation Tabs
400
+ document.addEventListener('DOMContentLoaded', function() {
401
+ const apiTabs = document.querySelectorAll('.api-tab');
402
+ const tabPanes = document.querySelectorAll('.tab-pane');
403
+
404
+ apiTabs.forEach(tab => {
405
+ tab.addEventListener('click', function() {
406
+ const targetTab = this.getAttribute('data-tab');
407
+
408
+ // Remove active class from all tabs and panes
409
+ apiTabs.forEach(t => t.classList.remove('active'));
410
+ tabPanes.forEach(p => p.classList.remove('active'));
411
+
412
+ // Add active class to clicked tab
413
+ this.classList.add('active');
414
+
415
+ // Show corresponding tab pane
416
+ const targetPane = document.getElementById(targetTab + '-tab');
417
+ if (targetPane) {
418
+ targetPane.classList.add('active');
419
+ }
420
+ });
421
+ });
422
+ });
423
+
424
  // Make dashboard instance globally available for sample image clicks
425
  let dashboard;
426
 
templates/dashboard.html CHANGED
@@ -173,183 +173,209 @@
173
  <p>Integrate marine species identification into your applications with our REST API</p>
174
  </div>
175
 
176
- <div class="api-docs-grid">
177
- <!-- Quick Start -->
178
- <div class="api-docs-card">
179
- <div class="api-docs-card-header">
180
- <h3>🚀 Quick Start</h3>
181
- </div>
182
- <div class="api-docs-card-content">
183
- <div class="api-endpoint">
184
- <div class="endpoint-method">POST</div>
185
- <div class="endpoint-url">https://seamo-ai-fishapi.hf.space/api/v1/identify</div>
186
- </div>
187
- <p>Upload an image and get species identification results with bounding boxes and confidence scores.</p>
188
- </div>
189
  </div>
190
 
191
- <!-- cURL Example -->
192
- <div class="api-docs-card">
193
- <div class="api-docs-card-header">
194
- <h3>📡 cURL</h3>
195
- <button class="copy-btn" onclick="copyToClipboard('curl-code')">Copy</button>
 
 
 
196
  </div>
197
- <div class="api-docs-card-content">
198
- <pre class="code-block" id="curl-code">curl -X POST "https://seamo-ai-fishapi.hf.space/api/v1/identify" \
199
- -H "Content-Type: multipart/form-data" \
200
- -F "file=@your_image.jpg" \
201
- -F "confidence_threshold=0.25" \
202
- -F "iou_threshold=0.45"</pre>
203
- </div>
204
- </div>
205
 
206
- <!-- Python Example -->
207
- <div class="api-docs-card">
208
- <div class="api-docs-card-header">
209
- <h3>🐍 Python</h3>
210
- <button class="copy-btn" onclick="copyToClipboard('python-code')">Copy</button>
211
- </div>
212
- <div class="api-docs-card-content">
213
- <pre class="code-block" id="python-code">import requests
 
 
 
 
 
 
 
 
 
214
 
215
- url = "https://seamo-ai-fishapi.hf.space/api/v1/identify"
 
 
 
 
 
 
 
216
 
217
- with open("your_image.jpg", "rb") as f:
218
- files = {"file": f}
219
- data = {
220
- "confidence_threshold": 0.25,
221
- "iou_threshold": 0.45
222
- }
223
 
224
- response = requests.post(url, files=files, data=data)
225
- result = response.json()
 
226
 
227
- print(f"Found {len(result['detections'])} species")
228
- for detection in result['detections']:
229
- print(f"- {detection['class_name']}: {detection['confidence']:.2%}")</pre>
230
- </div>
231
- </div>
 
232
 
233
- <!-- JavaScript Example -->
234
- <div class="api-docs-card">
235
- <div class="api-docs-card-header">
236
- <h3>🟨 JavaScript</h3>
237
- <button class="copy-btn" onclick="copyToClipboard('js-code')">Copy</button>
238
- </div>
239
- <div class="api-docs-card-content">
240
- <pre class="code-block" id="js-code">const formData = new FormData();
241
- formData.append('file', fileInput.files[0]);
242
- formData.append('confidence_threshold', '0.25');
243
- formData.append('iou_threshold', '0.45');
244
-
245
- fetch('https://seamo-ai-fishapi.hf.space/api/v1/identify', {
246
- method: 'POST',
247
- body: formData
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
248
  })
249
- .then(response => response.json())
250
- .then(data => {
251
- console.log(`Found ${data.detections.length} species`);
252
- data.detections.forEach(detection => {
253
- console.log(`${detection.class_name}: ${(detection.confidence * 100).toFixed(1)}%`);
254
  });
255
  })
256
- .catch(error => console.error('Error:', error));</pre>
257
- </div>
258
- </div>
259
 
260
- <!-- .NET C# Example -->
261
- <div class="api-docs-card">
262
- <div class="api-docs-card-header">
263
- <h3>🔷 C# (.NET)</h3>
264
- <button class="copy-btn" onclick="copyToClipboard('dotnet-code')">Copy</button>
265
- </div>
266
- <div class="api-docs-card-content">
267
- <pre class="code-block" id="dotnet-code">using System;
268
- using System.IO;
269
- using System.Net.Http;
270
- using System.Threading.Tasks;
271
-
272
- var client = new HttpClient();
273
- var form = new MultipartFormDataContent();
274
-
275
- // Add image file
276
- var fileContent = new ByteArrayContent(File.ReadAllBytes("your_image.jpg"));
277
- fileContent.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("image/jpeg");
278
- form.Add(fileContent, "file", "your_image.jpg");
279
-
280
- // Add parameters
281
- form.Add(new StringContent("0.25"), "confidence_threshold");
282
- form.Add(new StringContent("0.45"), "iou_threshold");
283
-
284
- var response = await client.PostAsync(
285
- "https://seamo-ai-fishapi.hf.space/api/v1/identify",
286
- form
 
 
 
 
 
287
  );
288
 
289
- var result = await response.Content.ReadAsStringAsync();
290
- Console.WriteLine(result);</pre>
291
- </div>
292
- </div>
293
 
294
- <!-- Response Format -->
295
- <div class="api-docs-card">
296
- <div class="api-docs-card-header">
297
- <h3>📋 Response Format</h3>
298
- <button class="copy-btn" onclick="copyToClipboard('response-code')">Copy</button>
299
- </div>
300
- <div class="api-docs-card-content">
301
- <pre class="code-block" id="response-code">{
302
- "success": true,
303
- "detections": [
304
  {
305
- "class_name": "Red Snapper",
306
- "confidence": 0.89,
307
- "bbox": [120, 80, 340, 280],
308
- "class_id": 42
309
  }
310
  ],
311
- "processing_time": 1.23,
312
- "image_info": {
313
- "width": 800,
314
- "height": 600,
315
- "format": "JPEG"
316
  },
317
- "model_info": {
318
- "name": "marina-benthic-33k",
319
- "version": "v1.0",
320
- "total_classes": 691
321
  }
322
  }</pre>
 
323
  </div>
324
  </div>
325
- </div>
326
 
327
- <!-- Additional Information -->
328
- <div class="api-docs-footer">
329
- <div class="api-docs-info-grid">
330
- <div class="api-info-card">
331
- <h4>📊 Parameters</h4>
332
- <ul>
333
- <li><strong>file</strong> (required): Image file (JPG, PNG, WebP)</li>
334
- <li><strong>confidence_threshold</strong>: Min confidence (0.0-1.0, default: 0.25)</li>
335
- <li><strong>iou_threshold</strong>: IoU threshold (0.0-1.0, default: 0.45)</li>
336
- </ul>
337
- </div>
338
- <div class="api-info-card">
339
- <h4>🔗 Additional Endpoints</h4>
340
- <ul>
341
- <li><strong>GET /health</strong>: API health status</li>
342
- <li><strong>GET /api/v1/species</strong>: List all supported species</li>
343
- <li><strong>GET /docs</strong>: Interactive Swagger documentation</li>
344
- </ul>
345
- </div>
346
- <div class="api-info-card">
347
- <h4>⚡ Rate Limits</h4>
348
- <ul>
349
- <li><strong>Free tier</strong>: 100 requests/hour</li>
350
- <li><strong>Max file size</strong>: 10MB</li>
351
- <li><strong>Supported formats</strong>: JPEG, PNG, WebP</li>
352
- </ul>
 
353
  </div>
354
  </div>
355
  </div>
 
173
  <p>Integrate marine species identification into your applications with our REST API</p>
174
  </div>
175
 
176
+ <div class="api-docs-container">
177
+ <!-- API Endpoint Info -->
178
+ <div class="api-endpoint-info">
179
+ <div class="endpoint-method">POST</div>
180
+ <div class="endpoint-url">https://seamo-ai-fishapi.hf.space/api/v1/detect</div>
181
+ <p class="endpoint-description">Upload an image and get species identification results with bounding boxes and confidence scores.</p>
 
 
 
 
 
 
 
182
  </div>
183
 
184
+ <!-- Tabbed Interface -->
185
+ <div class="api-tabs-container">
186
+ <div class="api-tabs">
187
+ <button class="api-tab active" data-tab="curl">cURL</button>
188
+ <button class="api-tab" data-tab="python">Python</button>
189
+ <button class="api-tab" data-tab="javascript">JavaScript</button>
190
+ <button class="api-tab" data-tab="csharp">C#</button>
191
+ <button class="api-tab" data-tab="response">Response</button>
192
  </div>
 
 
 
 
 
 
 
 
193
 
194
+ <div class="api-tab-content">
195
+ <!-- cURL Tab -->
196
+ <div class="tab-pane active" id="curl-tab">
197
+ <div class="code-header">
198
+ <span class="code-title">cURL Request</span>
199
+ <button class="copy-btn" onclick="copyToClipboard('curl-code')">Copy</button>
200
+ </div>
201
+ <pre class="code-block" id="curl-code"><span class="comment"># Easy one-liner with automatic base64 conversion</span>
202
+ <span class="cmd">curl</span> <span class="flag">-X</span> <span class="method">POST</span> <span class="string">"https://seamo-ai-fishapi.hf.space/api/v1/detect"</span> <span class="operator">\</span>
203
+ <span class="flag">-H</span> <span class="string">"Content-Type: application/json"</span> <span class="operator">\</span>
204
+ <span class="flag">-d</span> <span class="string">"{
205
+ \"image\": \"$(base64 -i your_image.jpg | tr -d '\n')\",
206
+ \"confidence_threshold\": 0.25,
207
+ \"iou_threshold\": 0.45,
208
+ \"return_annotated_image\": true
209
+ }"</span></pre>
210
+ </div>
211
 
212
+ <!-- Python Tab -->
213
+ <div class="tab-pane" id="python-tab">
214
+ <div class="code-header">
215
+ <span class="code-title">Python Request</span>
216
+ <button class="copy-btn" onclick="copyToClipboard('python-code')">Copy</button>
217
+ </div>
218
+ <pre class="code-block" id="python-code"><span class="keyword">import</span> <span class="module">requests</span>
219
+ <span class="keyword">import</span> <span class="module">base64</span>
220
 
221
+ <span class="variable">url</span> <span class="operator">=</span> <span class="string">"https://seamo-ai-fishapi.hf.space/api/v1/detect"</span>
 
 
 
 
 
222
 
223
+ <span class="comment"># Read and encode image</span>
224
+ <span class="keyword">with</span> <span class="function">open</span>(<span class="string">"your_image.jpg"</span>, <span class="string">"rb"</span>) <span class="keyword">as</span> <span class="variable">f</span>:
225
+ <span class="variable">image_data</span> <span class="operator">=</span> <span class="variable">base64</span>.<span class="function">b64encode</span>(<span class="variable">f</span>.<span class="function">read</span>()).<span class="function">decode</span>()
226
 
227
+ <span class="variable">payload</span> <span class="operator">=</span> {
228
+ <span class="string">"image"</span>: <span class="variable">image_data</span>,
229
+ <span class="string">"confidence_threshold"</span>: <span class="number">0.25</span>,
230
+ <span class="string">"iou_threshold"</span>: <span class="number">0.45</span>,
231
+ <span class="string">"return_annotated_image"</span>: <span class="keyword">True</span>
232
+ }
233
 
234
+ <span class="variable">response</span> <span class="operator">=</span> <span class="variable">requests</span>.<span class="function">post</span>(<span class="variable">url</span>, <span class="variable">json</span>=<span class="variable">payload</span>)
235
+ <span class="variable">result</span> <span class="operator">=</span> <span class="variable">response</span>.<span class="function">json</span>()
236
+
237
+ <span class="function">print</span>(<span class="string">f"Found </span>{<span class="function">len</span>(<span class="variable">result</span>[<span class="string">'detections'</span>])}<span class="string"> species"</span>)
238
+ <span class="keyword">for</span> <span class="variable">detection</span> <span class="keyword">in</span> <span class="variable">result</span>[<span class="string">'detections'</span>]:
239
+ <span class="function">print</span>(<span class="string">f"- </span>{<span class="variable">detection</span>[<span class="string">'class_name'</span>]}<span class="string">: </span>{<span class="variable">detection</span>[<span class="string">'confidence'</span>]:<span class="string">.2%</span>}<span class="string">"</span>)</pre>
240
+ </div>
241
+
242
+ <!-- JavaScript Tab -->
243
+ <div class="tab-pane" id="javascript-tab">
244
+ <div class="code-header">
245
+ <span class="code-title">JavaScript Request</span>
246
+ <button class="copy-btn" onclick="copyToClipboard('js-code')">Copy</button>
247
+ </div>
248
+ <pre class="code-block" id="js-code"><span class="comment">// Convert file to base64</span>
249
+ <span class="keyword">function</span> <span class="function">fileToBase64</span>(<span class="variable">file</span>) {
250
+ <span class="keyword">return</span> <span class="keyword">new</span> <span class="function">Promise</span>((<span class="variable">resolve</span>, <span class="variable">reject</span>) <span class="operator">=></span> {
251
+ <span class="keyword">const</span> <span class="variable">reader</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="function">FileReader</span>();
252
+ <span class="variable">reader</span>.<span class="property">onload</span> <span class="operator">=</span> () <span class="operator">=></span> <span class="function">resolve</span>(<span class="variable">reader</span>.<span class="property">result</span>.<span class="function">split</span>(<span class="string">','</span>)[<span class="number">1</span>]);
253
+ <span class="variable">reader</span>.<span class="property">onerror</span> <span class="operator">=</span> <span class="variable">reject</span>;
254
+ <span class="variable">reader</span>.<span class="function">readAsDataURL</span>(<span class="variable">file</span>);
255
+ });
256
+ }
257
+
258
+ <span class="keyword">const</span> <span class="variable">imageBase64</span> <span class="operator">=</span> <span class="keyword">await</span> <span class="function">fileToBase64</span>(<span class="variable">fileInput</span>.<span class="property">files</span>[<span class="number">0</span>]);
259
+
260
+ <span class="keyword">const</span> <span class="variable">payload</span> <span class="operator">=</span> {
261
+ <span class="property">image</span>: <span class="variable">imageBase64</span>,
262
+ <span class="property">confidence_threshold</span>: <span class="number">0.25</span>,
263
+ <span class="property">iou_threshold</span>: <span class="number">0.45</span>,
264
+ <span class="property">return_annotated_image</span>: <span class="keyword">true</span>
265
+ };
266
+
267
+ <span class="function">fetch</span>(<span class="string">'https://seamo-ai-fishapi.hf.space/api/v1/detect'</span>, {
268
+ <span class="property">method</span>: <span class="string">'POST'</span>,
269
+ <span class="property">headers</span>: { <span class="string">'Content-Type'</span>: <span class="string">'application/json'</span> },
270
+ <span class="property">body</span>: <span class="function">JSON</span>.<span class="function">stringify</span>(<span class="variable">payload</span>)
271
  })
272
+ .<span class="function">then</span>(<span class="variable">response</span> <span class="operator">=></span> <span class="variable">response</span>.<span class="function">json</span>())
273
+ .<span class="function">then</span>(<span class="variable">data</span> <span class="operator">=></span> {
274
+ <span class="variable">console</span>.<span class="function">log</span>(<span class="string">`Found </span>${<span class="variable">data</span>.<span class="property">detections</span>.<span class="property">length</span>}<span class="string"> species`</span>);
275
+ <span class="variable">data</span>.<span class="property">detections</span>.<span class="function">forEach</span>(<span class="variable">detection</span> <span class="operator">=></span> {
276
+ <span class="variable">console</span>.<span class="function">log</span>(<span class="string">`</span>${<span class="variable">detection</span>.<span class="property">class_name</span>}<span class="string">: </span>${(<span class="variable">detection</span>.<span class="property">confidence</span> <span class="operator">*</span> <span class="number">100</span>).<span class="function">toFixed</span>(<span class="number">1</span>)}<span class="string">%`</span>);
277
  });
278
  })
279
+ .<span class="function">catch</span>(<span class="variable">error</span> <span class="operator">=></span> <span class="variable">console</span>.<span class="function">error</span>(<span class="string">'Error:'</span>, <span class="variable">error</span>));</pre>
280
+ </div>
 
281
 
282
+ <!-- C# Tab -->
283
+ <div class="tab-pane" id="csharp-tab">
284
+ <div class="code-header">
285
+ <span class="code-title">C# Request</span>
286
+ <button class="copy-btn" onclick="copyToClipboard('csharp-code')">Copy</button>
287
+ </div>
288
+ <pre class="code-block" id="csharp-code"><span class="keyword">using</span> <span class="namespace">System</span>;
289
+ <span class="keyword">using</span> <span class="namespace">System.IO</span>;
290
+ <span class="keyword">using</span> <span class="namespace">System.Net.Http</span>;
291
+ <span class="keyword">using</span> <span class="namespace">System.Text</span>;
292
+ <span class="keyword">using</span> <span class="namespace">System.Threading.Tasks</span>;
293
+ <span class="keyword">using</span> <span class="namespace">Newtonsoft.Json</span>;
294
+
295
+ <span class="keyword">var</span> <span class="variable">client</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="function">HttpClient</span>();
296
+
297
+ <span class="comment">// Read and encode image</span>
298
+ <span class="keyword">var</span> <span class="variable">imageBytes</span> <span class="operator">=</span> <span class="class">File</span>.<span class="function">ReadAllBytes</span>(<span class="string">"your_image.jpg"</span>);
299
+ <span class="keyword">var</span> <span class="variable">imageBase64</span> <span class="operator">=</span> <span class="class">Convert</span>.<span class="function">ToBase64String</span>(<span class="variable">imageBytes</span>);
300
+
301
+ <span class="keyword">var</span> <span class="variable">payload</span> <span class="operator">=</span> <span class="keyword">new</span> {
302
+ <span class="property">image</span> = <span class="variable">imageBase64</span>,
303
+ <span class="property">confidence_threshold</span> = <span class="number">0.25</span>,
304
+ <span class="property">iou_threshold</span> = <span class="number">0.45</span>,
305
+ <span class="property">return_annotated_image</span> = <span class="keyword">true</span>
306
+ };
307
+
308
+ <span class="keyword">var</span> <span class="variable">json</span> <span class="operator">=</span> <span class="class">JsonConvert</span>.<span class="function">SerializeObject</span>(<span class="variable">payload</span>);
309
+ <span class="keyword">var</span> <span class="variable">content</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="function">StringContent</span>(<span class="variable">json</span>, <span class="class">Encoding</span>.<span class="property">UTF8</span>, <span class="string">"application/json"</span>);
310
+
311
+ <span class="keyword">var</span> <span class="variable">response</span> <span class="operator">=</span> <span class="keyword">await</span> <span class="variable">client</span>.<span class="function">PostAsync</span>(
312
+ <span class="string">"https://seamo-ai-fishapi.hf.space/api/v1/detect"</span>,
313
+ <span class="variable">content</span>
314
  );
315
 
316
+ <span class="keyword">var</span> <span class="variable">result</span> <span class="operator">=</span> <span class="keyword">await</span> <span class="variable">response</span>.<span class="property">Content</span>.<span class="function">ReadAsStringAsync</span>();
317
+ <span class="class">Console</span>.<span class="function">WriteLine</span>(<span class="variable">result</span>);</pre>
318
+ </div>
 
319
 
320
+ <!-- Response Tab -->
321
+ <div class="tab-pane" id="response-tab">
322
+ <div class="code-header">
323
+ <span class="code-title">JSON Response</span>
324
+ <button class="copy-btn" onclick="copyToClipboard('response-code')">Copy</button>
325
+ </div>
326
+ <pre class="code-block" id="response-code">{
327
+ <span class="json-key">"success"</span>: <span class="json-boolean">true</span>,
328
+ <span class="json-key">"detections"</span>: [
 
329
  {
330
+ <span class="json-key">"class_name"</span>: <span class="json-string">"Red Snapper"</span>,
331
+ <span class="json-key">"confidence"</span>: <span class="json-number">0.89</span>,
332
+ <span class="json-key">"bbox"</span>: [<span class="json-number">120</span>, <span class="json-number">80</span>, <span class="json-number">340</span>, <span class="json-number">280</span>],
333
+ <span class="json-key">"class_id"</span>: <span class="json-number">42</span>
334
  }
335
  ],
336
+ <span class="json-key">"processing_time"</span>: <span class="json-number">1.23</span>,
337
+ <span class="json-key">"image_info"</span>: {
338
+ <span class="json-key">"width"</span>: <span class="json-number">800</span>,
339
+ <span class="json-key">"height"</span>: <span class="json-number">600</span>,
340
+ <span class="json-key">"format"</span>: <span class="json-string">"JPEG"</span>
341
  },
342
+ <span class="json-key">"model_info"</span>: {
343
+ <span class="json-key">"name"</span>: <span class="json-string">"marina-benthic-33k"</span>,
344
+ <span class="json-key">"version"</span>: <span class="json-string">"v1.0"</span>,
345
+ <span class="json-key">"total_classes"</span>: <span class="json-number">691</span>
346
  }
347
  }</pre>
348
+ </div>
349
  </div>
350
  </div>
 
351
 
352
+ <!-- Additional Information -->
353
+ <div class="api-docs-footer">
354
+ <div class="api-docs-info-grid">
355
+ <div class="api-info-card">
356
+ <h4>Parameters</h4>
357
+ <ul>
358
+ <li><strong>file</strong> (required): Image file (JPG, PNG, WebP)</li>
359
+ <li><strong>confidence_threshold</strong>: Min confidence (0.0-1.0, default: 0.25)</li>
360
+ <li><strong>iou_threshold</strong>: IoU threshold (0.0-1.0, default: 0.45)</li>
361
+ </ul>
362
+ </div>
363
+ <div class="api-info-card">
364
+ <h4>Additional Endpoints</h4>
365
+ <ul>
366
+ <li><strong>GET /health</strong>: API health status</li>
367
+ <li><strong>GET /api/v1/species</strong>: List all supported species</li>
368
+ <li><strong>GET /docs</strong>: Interactive Swagger documentation</li>
369
+ </ul>
370
+ </div>
371
+ <div class="api-info-card">
372
+ <h4>Rate Limits</h4>
373
+ <ul>
374
+ <li><strong>Free tier</strong>: 100 requests/hour</li>
375
+ <li><strong>Max file size</strong>: 10MB</li>
376
+ <li><strong>Supported formats</strong>: JPEG, PNG, WebP</li>
377
+ </ul>
378
+ </div>
379
  </div>
380
  </div>
381
  </div>