kamau1 commited on
Commit
1ccc4ec
Β·
verified Β·
1 Parent(s): 8b3f6c2

Add professional, light-themed dashboard

Browse files
.gitattributes CHANGED
@@ -33,3 +33,5 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
 
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ docs/gradio/images/red_fish_2.png filter=lfs diff=lfs merge=lfs -text
37
+ docs/gradio/images/red_fish.png filter=lfs diff=lfs merge=lfs -text
Dockerfile CHANGED
@@ -67,6 +67,10 @@ COPY --chown=user --from=model-builder /models $HOME/app/models
67
  # Copy the application code
68
  COPY --chown=user ./app app
69
 
 
 
 
 
70
  # Create necessary directories
71
  RUN mkdir -p $HOME/.cache/huggingface $HOME/.cache/torch
72
 
 
67
  # Copy the application code
68
  COPY --chown=user ./app app
69
 
70
+ # Copy templates and static files for dashboard
71
+ COPY --chown=user ./templates templates
72
+ COPY --chown=user ./static static
73
+
74
  # Create necessary directories
75
  RUN mkdir -p $HOME/.cache/huggingface $HOME/.cache/torch
76
 
app/.DS_Store ADDED
Binary file (6.15 kB). View file
 
app/main.py CHANGED
@@ -8,7 +8,9 @@ import asyncio
8
  from contextlib import asynccontextmanager
9
  from fastapi import FastAPI, HTTPException, Request
10
  from fastapi.middleware.cors import CORSMiddleware
11
- from fastapi.responses import JSONResponse
 
 
12
  import uvicorn
13
 
14
  from app.core.config import settings
@@ -57,6 +59,10 @@ app = FastAPI(
57
  lifespan=lifespan
58
  )
59
 
 
 
 
 
60
  # Add CORS middleware
61
  app.add_middleware(
62
  CORSMiddleware,
@@ -86,18 +92,31 @@ async def global_exception_handler(request: Request, exc: Exception):
86
  app.include_router(api_router, prefix=settings.API_V1_STR)
87
 
88
 
89
- # Root endpoint
90
- @app.get("/", tags=["Root"])
91
- async def root():
 
 
 
 
 
 
 
 
 
 
 
 
92
  """
93
- Root endpoint providing basic API information.
94
  """
95
  return {
96
  "message": "Marine Species Identification API",
97
  "version": settings.VERSION,
98
  "docs": "/docs",
99
  "health": f"{settings.API_V1_STR}/health",
100
- "api_info": f"{settings.API_V1_STR}/info"
 
101
  }
102
 
103
 
 
8
  from contextlib import asynccontextmanager
9
  from fastapi import FastAPI, HTTPException, Request
10
  from fastapi.middleware.cors import CORSMiddleware
11
+ from fastapi.responses import JSONResponse, HTMLResponse
12
+ from fastapi.staticfiles import StaticFiles
13
+ from fastapi.templating import Jinja2Templates
14
  import uvicorn
15
 
16
  from app.core.config import settings
 
59
  lifespan=lifespan
60
  )
61
 
62
+ # Mount static files and templates (for dashboard)
63
+ app.mount("/static", StaticFiles(directory="static"), name="static")
64
+ templates = Jinja2Templates(directory="templates")
65
+
66
  # Add CORS middleware
67
  app.add_middleware(
68
  CORSMiddleware,
 
92
  app.include_router(api_router, prefix=settings.API_V1_STR)
93
 
94
 
95
+ # Dashboard endpoint (new web interface)
96
+ @app.get("/", response_class=HTMLResponse, tags=["Dashboard"])
97
+ async def dashboard(request: Request):
98
+ """
99
+ Main dashboard for marine species identification.
100
+ Provides a web interface for testing the API.
101
+ """
102
+ return templates.TemplateResponse("dashboard.html", {
103
+ "request": request,
104
+ "active_tab": "dashboard"
105
+ })
106
+
107
+ # API root endpoint (moved to /api for clarity)
108
+ @app.get("/api", tags=["Root"])
109
+ async def api_root():
110
  """
111
+ API root endpoint providing basic API information.
112
  """
113
  return {
114
  "message": "Marine Species Identification API",
115
  "version": settings.VERSION,
116
  "docs": "/docs",
117
  "health": f"{settings.API_V1_STR}/health",
118
+ "api_info": f"{settings.API_V1_STR}/info",
119
+ "dashboard": "/"
120
  }
121
 
122
 
docs/.DS_Store ADDED
Binary file (6.15 kB). View file
 
docs/dev/HF-MODELS.md ADDED
@@ -0,0 +1,55 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Here is an example of a dockerfile of a fastapi app that uses my self hosted model
2
+
3
+ # Dockerfile for Sema Translation API on HuggingFace Spaces
4
+ # Multi-stage build to handle model downloading with proper permissions
5
+
6
+ # Stage 1: Download models as root
7
+ FROM python:3.10-slim AS model-builder
8
+
9
+ # Install huggingface_hub for downloading models
10
+ RUN pip install huggingface_hub
11
+
12
+ # Download models from sematech/sema-utils
13
+ RUN python -c "\
14
+ from huggingface_hub import hf_hub_download; \
15
+ hf_hub_download('sematech/sema-utils', 'spm.model'); \
16
+ hf_hub_download('sematech/sema-utils', 'lid218e.bin'); \
17
+ hf_hub_download('sematech/sema-utils', 'translation_models/sematrans-3.3B/model.bin'); \
18
+ hf_hub_download('sematech/sema-utils', 'translation_models/sematrans-3.3B/config.json'); \
19
+ hf_hub_download('sematech/sema-utils', 'translation_models/sematrans-3.3B/shared_vocabulary.txt')"
20
+
21
+ # Stage 2: Build the application
22
+ FROM python:3.10-slim
23
+
24
+ # Set up a new user named "user" with user ID 1000
25
+ RUN useradd -m -u 1000 user
26
+ # Switch to the "user" user
27
+ USER user
28
+ # Set home to the user's home directory
29
+ ENV HOME=/home/user \
30
+ PATH=/home/user/.local/bin:$PATH
31
+
32
+ # Set the working directory to the user's home directory
33
+ WORKDIR $HOME/app
34
+
35
+ # Set environment variables for HuggingFace
36
+ ENV HF_HUB_OFFLINE=1
37
+ ENV TRANSFORMERS_NO_ADVISORY_WARNINGS=1
38
+
39
+ # Copy the requirements file and install dependencies
40
+ COPY --chown=user ./requirements.txt requirements.txt
41
+ RUN pip install --no-cache-dir --upgrade pip
42
+ RUN pip install --no-cache-dir --user -r requirements.txt
43
+
44
+ # Copy the downloaded models from the builder stage
45
+ COPY --chown=user --from=model-builder /root/.cache/huggingface $HOME/.cache/huggingface
46
+
47
+ # Copy the application code
48
+ COPY --chown=user ./app app
49
+
50
+ # Expose port 7860 (HuggingFace Spaces standard)
51
+ EXPOSE 7860
52
+
53
+ # Tell uvicorn to run on port 7860, which is the standard for HF Spaces
54
+ # Use 0.0.0.0 to make it accessible from outside the container
55
+ CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "7860"]
docs/dev/HF-QUICKSTART.md ADDED
@@ -0,0 +1,117 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ 🐳 Get started with your Docker Space!
2
+ Your new Space has been created, follow these steps to get started (or read the full documentation)
3
+
4
+ Start by cloning this repo by using:
5
+
6
+ Use an access token as git password/credential
7
+
8
+
9
+ # When prompted for a password, use an access token with write permissions.
10
+ # Generate one from your settings: https://huggingface.co/settings/tokens
11
+ git clone https://huggingface.co/spaces/seamo-ai/fishapi
12
+
13
+ # Make sure hf CLI is installed: pip install -U "huggingface_hub[cli]"
14
+ hf download seamo-ai/fishapi --repo-type=space
15
+ Let's create a simple Python app using FastAPI:
16
+
17
+ requirements.txt
18
+
19
+
20
+ fastapi
21
+ uvicorn[standard]
22
+ Hint You can also create the requirements file file directly in your browser.
23
+ app.py
24
+
25
+
26
+ from fastapi import FastAPI
27
+
28
+ app = FastAPI()
29
+
30
+ @app.get("/")
31
+ def greet_json():
32
+ return {"Hello": "World!"}
33
+ Hint You can also create the app file file directly in your browser.
34
+ Create your Dockerfile:
35
+
36
+
37
+ # Read the doc: https://huggingface.co/docs/hub/spaces-sdks-docker
38
+ # you will also find guides on how best to write your Dockerfile
39
+
40
+ FROM python:3.9
41
+
42
+ RUN useradd -m -u 1000 user
43
+ USER user
44
+ ENV PATH="/home/user/.local/bin:$PATH"
45
+
46
+ WORKDIR /app
47
+
48
+ COPY --chown=user ./requirements.txt requirements.txt
49
+ RUN pip install --no-cache-dir --upgrade -r requirements.txt
50
+
51
+ COPY --chown=user . /app
52
+ CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "7860"]
53
+ Hint Alternatively, you can create the Dockerfile file directly in your browser.
54
+ Then commit and push:
55
+
56
+
57
+ git add requirements.txt app.py Dockerfile
58
+ git commit -m "Add application file"
59
+ git push
60
+ Finally, your Space should be running on this page after a few moments!
61
+
62
+ App port
63
+
64
+ Your Docker Space needs to listen on port 7860.
65
+
66
+ Personalize your Space
67
+
68
+ Make your Space stand out by customizing its emoji, colors, and description by editing metadata in its README.md file.
69
+
70
+ Documentation
71
+
72
+ Read the full documentation for Docker Spaces [here](https://huggingface.co/docs/hub/spaces-sdks-docker).
73
+
74
+
75
+ Seamo Model card
76
+ seamo-ai/marina-species-v1
77
+
78
+ License:
79
+ apache-2.0
80
+ Model card
81
+ Files and versions
82
+ Community
83
+ Settings
84
+ Getting started with your model
85
+ Complete model information
86
+ Add metadata and complete your model card to make your model more discoverable.
87
+
88
+
89
+ Push your model files
90
+ Upload your model weights to this repository.
91
+
92
+ CLI
93
+ Python
94
+ Git
95
+ HTTPS
96
+ SSH
97
+
98
+
99
+ brew install huggingface-cli
100
+
101
+
102
+ hf auth login
103
+
104
+
105
+ hf upload seamo-ai/marina-species-v1 .
106
+ You can also upload directly from the website using the File Uploader.
107
+
108
+ Preparing a significant release? Consult our guide to improve your model page and extend its impact and reach.
109
+ Downloads last month
110
+ -
111
+
112
+ Downloads are not tracked for this model.
113
+ How to track
114
+ Inference Providers
115
+ NEW
116
+ This model isn't deployed by any Inference Provider.
117
+
docs/dev/SEAMO-GRADIO.md ADDED
File without changes
docs/gradio/.DS_Store ADDED
Binary file (6.15 kB). View file
 
docs/gradio/Dockerfile ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM python:3.7
2
+
3
+ RUN apt-get update \
4
+ && apt-get install ffmpeg libsm6 libxext6 -y
5
+
6
+ RUN pip install yolov5 tator gradio
7
+
8
+ COPY . ./
9
+
10
+ CMD [ "python", "-u", "./tator_inference.py" ]
docs/gradio/README.md ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ title: Seamore
3
+ emoji: 🐟
4
+ colorFrom: blue
5
+ colorTo: indigo
6
+ sdk: gradio
7
+ sdk_version: 3.47.1
8
+ app_file: app.py
9
+ pinned: false
10
+ ---
11
+
12
+ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
13
+
14
+
15
+ This is a gradio app for the yolo 5 model that identifies fish species.
16
+
docs/gradio/app.py ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import glob
2
+ import gradio as gr
3
+ from inference import *
4
+ from PIL import Image
5
+
6
+
7
+ def gradio_app(image_path):
8
+ """A function that send the file to the inference pipeline, and filters
9
+ some predictions before outputting to gradio interface."""
10
+
11
+ predictions = run_inference(image_path)
12
+
13
+ out_img = Image.fromarray(predictions.render()[0])
14
+
15
+ return out_img
16
+
17
+
18
+ Title = "Marine Life Identification"
19
+ description = (
20
+ ""
21
+ )
22
+
23
+ examples = glob.glob("images/*.png")
24
+
25
+ gr.Interface(gradio_app,
26
+ inputs=[gr.inputs.Image(type="filepath")],
27
+ outputs=gr.outputs.Image(type="pil"),
28
+ enable_queue=True,
29
+ title=Title,
30
+ description=description,
31
+ examples=examples).launch()
docs/gradio/images/.DS_Store ADDED
Binary file (6.15 kB). View file
 
docs/gradio/images/red_fish.png ADDED

Git LFS Details

  • SHA256: 82d2d4b63874a4436397b3866733c3e5854b55e792a98ff6ba1780e1158e736e
  • Pointer size: 131 Bytes
  • Size of remote file: 543 kB
docs/gradio/images/red_fish_2.png ADDED

Git LFS Details

  • SHA256: d917b1fb942e49b13fd9202c3e8a50343b80dfcaa2c35258260ed3b912d72895
  • Pointer size: 131 Bytes
  • Size of remote file: 467 kB
docs/gradio/inference.py ADDED
@@ -0,0 +1,69 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import cv2
2
+ import glob
3
+ import numpy as np
4
+ import torch
5
+ import yolov5
6
+ from typing import Dict, Tuple, Union, List, Optional
7
+
8
+
9
+ # -----------------------------------------------------------------------------
10
+ # Configs
11
+ # -----------------------------------------------------------------------------
12
+
13
+ model_path = "models/mbari-mb-benthic-33k.pt"
14
+
15
+
16
+ # -----------------------------------------------------------------------------
17
+ # YOLOv5 class
18
+ # -----------------------------------------------------------------------------
19
+
20
+ class YOLO:
21
+ """Wrapper class for loading and running YOLO model"""
22
+
23
+ def __init__(self, model_path: str, device: Optional[str] = None):
24
+
25
+ # load model
26
+ self.model = yolov5.load(model_path, device=device)
27
+
28
+ def __call__(
29
+ self,
30
+ img: Union[str, np.ndarray],
31
+ conf_threshold: float = 0.25,
32
+ iou_threshold: float = 0.45,
33
+ image_size: int = 720,
34
+ classes: Optional[List[int]] = None) -> torch.Tensor:
35
+ self.model.conf = conf_threshold
36
+ self.model.iou = iou_threshold
37
+
38
+ if classes is not None:
39
+ self.model.classes = classes
40
+
41
+ # pylint: disable=not-callable
42
+ detections = self.model(img, size=image_size)
43
+
44
+ return detections
45
+
46
+
47
+ def run_inference(image_path):
48
+ """Helper function to execute the inference."""
49
+
50
+ predictions = model(image_path)
51
+
52
+ return predictions
53
+
54
+
55
+ # -----------------------------------------------------------------------------
56
+ # Model Creation
57
+ # -----------------------------------------------------------------------------
58
+ model = YOLO(model_path, device='cpu')
59
+
60
+ if __name__ == "__main__":
61
+
62
+ # For demo purposes: run through a couple of test
63
+ # images and then output the predictions in a folder.
64
+ test_images = glob.glob("images/*.png")
65
+
66
+ for test_image in test_images:
67
+ predictions = run_inference(test_image)
68
+
69
+ print("Done.")
docs/gradio/mbari-mb-benthic-33k.names ADDED
@@ -0,0 +1,691 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Anoplopoma fimbria
2
+ Crossaster
3
+ Myxoderma sacculatum
4
+ Sebastolobus
5
+ Neptunea-Buccinum Complex
6
+ Ceriantharia
7
+ Merluccius productus
8
+ Pannychia moseleyi
9
+ Octopus rubescens
10
+ Actiniaria
11
+ Solasteridae
12
+ Antimora microlepis
13
+ Macrouridae
14
+ Heteropolypus ritteri
15
+ Liponema brevicorne
16
+ Ophiuroidea
17
+ Octocorallia
18
+ Porifera
19
+ Brisingida
20
+ Chorilia longipes
21
+ Asteroidea
22
+ equipment
23
+ Metridium farcimen
24
+ Embassichthys bathybius
25
+ Funiculina
26
+ Strongylocentrotus fragilis
27
+ Chionoecetes tanneri
28
+ Actinostoloidea
29
+ Myxoderma platyacanthum
30
+ Gastropoda
31
+ Umbellula
32
+ Psolus squamatus
33
+ Hexactinellida
34
+ Swiftia simplex
35
+ Galatheidae
36
+ Coryphaenoides
37
+ Dosidicus gigas
38
+ Microstomus pacificus
39
+ Sebastolobus alascanus
40
+ Farrea
41
+ Poralia rufescens
42
+ Acanthoptilum
43
+ Isosicyonis
44
+ Paragorgia arborea
45
+ Pannychia sp. 2
46
+ Bothrocara brunneum
47
+ Hormathiidae
48
+ Lycenchelys
49
+ Pteraster
50
+ Paragorgia
51
+ Sebastes
52
+ Bathyraja abyssicola
53
+ Eptatretus
54
+ Lycenchelys crotalinus
55
+ Pennatulacea
56
+ Pandalidae
57
+ Tunicata
58
+ Actinernus
59
+ Asbestopluma rickettsi
60
+ Apostichopus leukothele
61
+ Stylasterias forreri
62
+ Sebastes elongatus
63
+ Sebastomus complex
64
+ Parastenella
65
+ Bathyraja trachura
66
+ Laqueus californicus
67
+ Eutonina indicans
68
+ Keratoisis
69
+ Apristurus
70
+ Mysida
71
+ Tritonia tetraquetra
72
+ Mediaster aequalis
73
+ Anthoptilum grandiflorum
74
+ Virgulariidae
75
+ Vesicomyidae
76
+ Sebastolobus altivelis
77
+ Neptunea
78
+ Rathbunaster californicus
79
+ Bathyraja kincaidii
80
+ Scyliorhinidae
81
+ Lycodapus
82
+ Paralomis
83
+ Isididae
84
+ Crinoidea
85
+ Acanthogorgia
86
+ Swiftia
87
+ Enteroctopus dofleini
88
+ Pagurus tanneri
89
+ Mediaster
90
+ Pyrosoma atlanticum
91
+ Nanomia bijuga
92
+ Lycodes diapterus
93
+ Pectinidae
94
+ Asbestopluma
95
+ Isidella
96
+ Hippasteria
97
+ Osedax
98
+ Corallimorphus
99
+ Florometra serratissima
100
+ Scotoplanes
101
+ Asteronyx
102
+ Swiftia kofoidi
103
+ Pandalus
104
+ Pennatula phosphorea
105
+ Ascidiacea
106
+ Laminariales
107
+ Doryteuthis opalescens
108
+ Sebastidae
109
+ Bathyraja
110
+ Paelopatides confundens
111
+ Suction Sampler
112
+ Lycodes cortezianus
113
+ Pandalus platyceros
114
+ Lumpenus sagitta
115
+ Pandalopsis ampla
116
+ Hydrolagus colliei
117
+ Bathyraja spinosissima
118
+ Solaster hypothrissus
119
+ Hyalonema (Corynonema) populiferum
120
+ Holothuroidea
121
+ Apostichopus
122
+ Synallactidae
123
+ Caridea
124
+ Lithodidae
125
+ Tonrometra
126
+ Stomphia didemon
127
+ Solmissus
128
+ Euphausia
129
+ Lycodapus fierasfer
130
+ Munidopsis depressa
131
+ Cataetyx
132
+ Sebastes diploproa
133
+ Pleurobranchaea californica
134
+ Paguroidea
135
+ Lycodes
136
+ Heterochone calyx
137
+ Isidella tentaculum
138
+ Psathyrometra fragilis
139
+ Sebastes melanostomus
140
+ trash
141
+ Xeneretmus latifrons
142
+ Bathyraja microtrachys
143
+ Bathybembix
144
+ Pyrosoma detritus
145
+ Luidia foliolata
146
+ Lycodes pacificus
147
+ Munida
148
+ Beringraja rhina
149
+ Lophaster
150
+ Gersemia juliepackardae
151
+ Paralomis multispina
152
+ Stomphia
153
+ Primnoidae
154
+ Funiculina-Halipteris complex
155
+ Pleuronectiformes
156
+ Sibogagorgia cauliflora
157
+ Sebastes chlorostictus
158
+ Sebastes zacentrus
159
+ Sebastes babcocki
160
+ Solaster
161
+ Akoya platinum
162
+ Opisthoteuthis sp. A
163
+ Lepidisis
164
+ Branchiocerianthus
165
+ Antedonidae
166
+ Gorgonocephalus eucnemis
167
+ Staurocalyptus
168
+ Glyptocephalus zachirus
169
+ Phyllospadix-Zostera detritus
170
+ Careproctus melanurus
171
+ Amphipoda
172
+ LRJ complex
173
+ Careproctus
174
+ Benthopecten
175
+ Squalus suckleyi
176
+ Eopsetta jordani
177
+ Eusergestes similis
178
+ Sabellida
179
+ Brachyura
180
+ Serpulidae
181
+ Lyopsetta exilis
182
+ Mycale
183
+ Poraniopsis inflata
184
+ Eualus macrophthalmus
185
+ Chonelasma
186
+ Acanthascinae
187
+ Rajiformes
188
+ Corallimorphus pilatus
189
+ Zoarcidae
190
+ Aegina
191
+ medusa carcass
192
+ Neogastropoda
193
+ Pleuronectidae
194
+ Calyptogena
195
+ Pleuronectinae
196
+ Hymenaster
197
+ Munidopsis
198
+ Swiftia sim
199
+ Munnopsidae
200
+ Lobata
201
+ Pannychia
202
+ Lithodes couesi
203
+ Myctophidae
204
+ Thrissacanthias penicillatus
205
+ geology
206
+ Dofleinia
207
+ Asthenactis fisheri
208
+ Cydippida
209
+ Harriotta raleighana
210
+ Metacarcinus magister
211
+ Gobiidae
212
+ Albatrossia pectoralis
213
+ Lampocteis cruentiventer
214
+ Buccinidae
215
+ Alcyonacea
216
+ Ophiacanthidae
217
+ Careproctus kamikawai
218
+ Stylatula
219
+ Paragorgiidae
220
+ Majidae
221
+ Megalodicopia hians
222
+ Moridae
223
+ Ptilosarcus gurneyi
224
+ Isopoda
225
+ Asbestopluma monticola
226
+ Octopoda
227
+ Bivalvia
228
+ Desmophyllum dianthus
229
+ Fungiacyathus (Bathyactis) marenzelleri
230
+ Peniagone
231
+ Elpidia
232
+ Scotoplanes globosa
233
+ Teuthoidea
234
+ Peniagone gracilis
235
+ Oneirophanta mutabilis complex
236
+ Nanomia bijuga nectosome
237
+ fishing-debris
238
+ Peniagone papillata
239
+ Synallactidae gen. et sp. indet.
240
+ Sebastes rufus
241
+ Hydrolagus cf. trolli
242
+ Psychropotes sp. 2
243
+ Tjalfiella
244
+ Poeobius meseres
245
+ Bathochordaeus stygius inner filter
246
+ Bathochordaeus stygius outer filter
247
+ Hydrozoa
248
+ Cnemidocarpa
249
+ Hyalonema
250
+ Malacostraca
251
+ Iosactis vagabunda
252
+ Abyssocucumis abyssorum
253
+ Peniagone vitrea
254
+ Ophiodon elongatus
255
+ Parastichopus leukothele
256
+ Cystechinus loveni
257
+ Ceramaster
258
+ Hexacorallia
259
+ Octopus californicus
260
+ Neolithodes diomedeae
261
+ Benthocodon pedunculata
262
+ Styelidae
263
+ Physiculus rastrelliger
264
+ Laetmogone
265
+ Sebastes saxicola
266
+ Bathochordaeus
267
+ Cladorhizidae
268
+ Peribolaster biserialis
269
+ Muusoctopus robustus
270
+ Hydrolagus melanophasma
271
+ Beroe forskalii
272
+ Sebastes flavidus
273
+ Nemichthyidae
274
+ Poraniopsis
275
+ Sebastes brevispinis
276
+ Sebastes rubrivinctus
277
+ Octopodidae
278
+ Paraliparis sp. 2
279
+ Pythonaster
280
+ Synallactes
281
+ Sebastes ensifer
282
+ Sebastes miniatus
283
+ Hyalonema (Oonema) bianchoratum
284
+ Anomura
285
+ Echinocrepis rostrata
286
+ Prayidae
287
+ Physonectae nectosome
288
+ Physonectae
289
+ Sebastes paucispinis
290
+ Sebastes head
291
+ Hirudinea
292
+ Urticina
293
+ Astropecten
294
+ Leptogorgia
295
+ Galatheoidea
296
+ Beroe cucumis
297
+ Bolocera
298
+ Fariometra parvula
299
+ Neptunea-Buccinum Complex eggcase
300
+ Graneledone boreopacifica
301
+ Polynoidae
302
+ Psamminidae
303
+ Psychrolutes phrictus
304
+ Sergestes similis
305
+ Calycophorae nectosome
306
+ Beroe
307
+ Thenea muricata
308
+ Gonatus
309
+ Henricia
310
+ Nudibranchia
311
+ Sebastes aurora
312
+ Zoantharia
313
+ Clavularia
314
+ Terebratulina complex
315
+ Macrourinae
316
+ Ptychogastria
317
+ Delectopecten
318
+ Phacellophora camtschatica
319
+ Siboglinidae
320
+ Gorgoniidae
321
+ eggcase
322
+ Sibogagorgia
323
+ Comatulida
324
+ Diogenidae
325
+ eggs
326
+ Apolemia
327
+ Midwater Respirometry System
328
+ Pycnogonida
329
+ Calliostoma
330
+ Sebastes aleutianus-melanostictus complex
331
+ Brachiopoda
332
+ Medusae
333
+ Lamellibrachia
334
+ Bathyphellia australis
335
+ Ophiuridae
336
+ Lycodes brevipes
337
+ Atolla
338
+ Plectobranchus evides
339
+ Asteriidae
340
+ Farrea occa
341
+ Agonidae
342
+ Bathymetrinae
343
+ Decapoda
344
+ Corallium
345
+ Halipteris californica
346
+ Dipsacaster
347
+ Chonelasmatinae sp. 2
348
+ shell
349
+ Phyllospadix detritus
350
+ Spectrunculus grandis
351
+ shell fragment
352
+ Paralomis verrilli
353
+ Hydrolagus
354
+ Actinopterygii
355
+ Parmaturus xaniurus
356
+ whale carcass
357
+ Pterasteridae arm
358
+ Annelida
359
+ Lyrocteis
360
+ Echiura
361
+ Vanhoeffenura pulchra
362
+ Bolinopsis infundibulum
363
+ Colossendeidae
364
+ Bathochordaeus stygius
365
+ Sebastes jordani
366
+ Platyctenida
367
+ Saxipendium implicatum
368
+ TorquaratoridaeB sp. 2
369
+ Pachycara bulbiceps
370
+ Hydractiniidae
371
+ Psamminidae sp. 2
372
+ Tjalfiellidae
373
+ Myxoderma
374
+ Hyocrinidae
375
+ Chondrocladia
376
+ Cystocrepis setigera
377
+ Munidopsis kensmithi
378
+ Radiozoa
379
+ Chaetognatha
380
+ Siphonophorae
381
+ Chrysogorgia
382
+ Pseudostichopus mollis
383
+ Benthothuria
384
+ Bolocera kensmithi
385
+ Sebastes semicinctus
386
+ Galiteuthis phyllura
387
+ Octopodinae
388
+ Serrivomer
389
+ Demospongiae
390
+ Latrunculia (Latrunculia) austini
391
+ Dromalia alexandri
392
+ Scleractinia
393
+ Plesionika
394
+ bacterial mat
395
+ Chondrocladia (Symmetrocladia) lyra
396
+ Neoloricata
397
+ asteroid feeding depression
398
+ Bathyalcyon robustum
399
+ Bathypterois
400
+ Distichoptilum
401
+ Paraliparis cephalus
402
+ Sebastes serranoides
403
+ Goniasteridae
404
+ ledge
405
+ Tromikosoma panamense
406
+ Ctenophora
407
+ Docosaccus maculatus
408
+ sinker
409
+ Lophaster furcilliger
410
+ Sebastes cortezi
411
+ Culeolus
412
+ Mysidacea
413
+ Bathydorus laevis pseudospinosus
414
+ Alepocephalus tenebrosus
415
+ Echinoidea
416
+ Heterozonias alternatus
417
+ Smithsonius dorothea
418
+ Heterocarpus sp. 2
419
+ Eucryphycus californicus
420
+ Polychaeta tube
421
+ Cirroteuthis
422
+ Tergivelum baldwinae
423
+ Tiburonia granrojo
424
+ Liparidae
425
+ Riftia pachyptila
426
+ Hydroidolina
427
+ Plexauridae
428
+ Bathylagidae
429
+ Lepidion
430
+ Sclerothamnopsis
431
+ Careproctus ovigerus
432
+ Psychropotes depressa
433
+ Icelinus filamentosus
434
+ Chrysogorgia monticola
435
+ wood
436
+ Bathochordaeus inner filter
437
+ Sebastes entomelas
438
+ Anthozoa
439
+ Bathypterois pectinatus
440
+ Cladorhiza kensmithi
441
+ Aporocidaris milleri
442
+ Ischnomesidae
443
+ Staurocalyptus solidus
444
+ Anthoptilum lithophilum
445
+ Atolla wyvillei
446
+ Erenna richardi
447
+ Hyalonematidae
448
+ Pleurobranchaea
449
+ Sergestidae
450
+ Thermarces cerberus
451
+ Pennatula
452
+ Moloha faxoni
453
+ Munida quadrispina
454
+ Lophiiformes
455
+ Benthoctopus
456
+ Strongylocentrotus
457
+ kelp
458
+ Nanomia nectosome
459
+ Sicyonis
460
+ Chrysogorgia pinnata
461
+ Forskalia formosa
462
+ Sebastes ruberrimus
463
+ Sebastes levis
464
+ Praya dubia nectosome
465
+ Praya dubia
466
+ Pleuronectiformes 3
467
+ Chuniphyes multidentata
468
+ Dictyocalyx
469
+ Zaniolepis frenata
470
+ Octopus
471
+ Forcipulatacea
472
+ Eretmichthys pinnatus
473
+ Dibranchus hystrix
474
+ Coelorinchus spilonotus
475
+ Pseudobathylagus
476
+ Benthodytes
477
+ Alternatipathes
478
+ Lillipathes
479
+ Protoptilum sp. 2
480
+ Hastigerinella digitata
481
+ Bargmannia elongata
482
+ Bargmannia elongata nectosome
483
+ Psychronaetes
484
+ Bathysaurus mollis
485
+ Lycodinae
486
+ Euplectellidae
487
+ Pasiphaea
488
+ Bathysiphon
489
+ Beroe abyssicola
490
+ Tomopteris
491
+ Polychaeta
492
+ Articulata
493
+ Apostichopus californicus
494
+ Kophobelemnon
495
+ Bolinopsis
496
+ Euryalida
497
+ Pennatulidae
498
+ Gastroptychus
499
+ molt
500
+ Corallimorphus denhartogi
501
+ Neptunea eggcase
502
+ Octacnemidae sp. 2
503
+ Xeneretmus
504
+ Dibranchus spinosus
505
+ Epizoanthus stellaris
506
+ Pennatulacea sp. 2
507
+ Sebastes borealis
508
+ Aeolidiidae
509
+ Mitrocoma cellularia
510
+ Tromikosoma
511
+ Icichthys lockingtoni
512
+ Solmissus incisa
513
+ Sebastes pinniger
514
+ Enteropneusta
515
+ Sebastes auriculatus
516
+ Megalodicopia
517
+ Asthenactis papyraceus
518
+ Sebastes miniatus-pinniger complex
519
+ Asthenactis
520
+ test
521
+ Icelinus
522
+ Parantipathes
523
+ Sebastes macdonaldi
524
+ Sebastes mystinus
525
+ Physiculus nematopus-rastrelliger complex
526
+ Sebastes rosenblatti
527
+ Bathochordaeus sinker
528
+ Distichoptilum gracile
529
+ kelp holdfast
530
+ Rhinochimaeridae
531
+ Echinocrepis setigera
532
+ Sebastes caurinus
533
+ Egregia menziesii
534
+ Myriothelidae
535
+ coiled fecal cast
536
+ Cystechinus giganteus
537
+ Bathochordaeus mcnutti inner filter
538
+ Bathochordaeus mcnutti
539
+ Cladorhiza
540
+ Cirripedia
541
+ Swiftia kol
542
+ Phyllochaetopterus gigas
543
+ Hymenaster koehleri
544
+ sinker outer filter
545
+ Allocentrotus fragilis
546
+ Luciobrotula sp. A
547
+ Opisthoteuthis
548
+ Haliscera bigelowi
549
+ Scotoplanes clarki
550
+ Lyssacinosida sp. 2
551
+ larvacean outer filter
552
+ Ophichthus frontalis
553
+ Calyptrophora
554
+ Provannidae
555
+ Marine organism
556
+ Farrea truncata complex
557
+ Actinoscyphia
558
+ Exocoelactis
559
+ Kophobelemnidae
560
+ Lychnagalma nectosome
561
+ Lychnagalma
562
+ Caenogastropoda
563
+ Zoroasteridae
564
+ Bathochordaeus outer filter
565
+ Vanhoeffenura
566
+ Stylasterias
567
+ Calycophorae
568
+ Vitreosalpa gemini
569
+ Anguilliformes
570
+ Calocarides quinqueseriatus
571
+ Fungiacyathus
572
+ Candelabridae sp. 2
573
+ Tergivelum sp. A
574
+ Mesochordaeus erythrocephalus
575
+ Monothalamea
576
+ Paradiopatra
577
+ Munida bapensis
578
+ Sebastes crameri-melanostomus complex
579
+ Asterozoa
580
+ Patiria miniata
581
+ Ophidiiformes
582
+ Salpida
583
+ Coelorinchus scaphopsis
584
+ Tomopteris nisseni
585
+ Camptoplites sp. A
586
+ Psychropotidae
587
+ Paxillosida
588
+ Dendronotus patricki
589
+ Oneirophanta
590
+ Lensia conoidea nectosome
591
+ Lensia conoidea
592
+ Glyphocrangon vicaria
593
+ Dipsacaster eximius
594
+ Bathydorus
595
+ Bathycrinidae
596
+ Sebastolobus head
597
+ Doryteuthis (Amerigo) opalescens eggs
598
+ Sebastes crameri
599
+ Thetys vagina
600
+ Sebastes ovalis
601
+ Lycodapus mandibularis
602
+ Sebastolobus tail
603
+ Sebastes goodei
604
+ Pseudobathylagus milleri
605
+ Narcomedusa
606
+ Chiroteuthis calyx
607
+ Heterobranchia
608
+ Octacnemidae
609
+ inner filter
610
+ Pentametrocrinus paucispinulus
611
+ Beroe gracilis
612
+ Schizopathidae
613
+ Dytaster gilberti
614
+ Physiculus sp. 2
615
+ Octopodidae tentacle
616
+ Mysidae
617
+ Antipatharia
618
+ Lychnagalma utricularia nectosome
619
+ Lychnagalma utricularia
620
+ Ridgeia
621
+ Actinauge verrillii
622
+ Oikopleuridae outer filter
623
+ Fecampiid eggcase
624
+ Chilara taylori
625
+ Acesta
626
+ Caulophacus
627
+ Parophrys vetulus
628
+ Dibranchus sp. A
629
+ Holothuria (Vaneyothuria) zacae
630
+ Prayidae nectosome
631
+ Acanthephyra
632
+ Bathycrinus complanatus
633
+ Munnopsis
634
+ Alcyoniidae
635
+ Microstomus bathybius
636
+ Theudoidea
637
+ Hydromedusae
638
+ Protoptilum
639
+ Bathyphellia
640
+ Euplokamidae
641
+ Microstomus pacificus sole
642
+ Hormiphora californensis
643
+ Leptocephalus-3
644
+ Verum proximum
645
+ Lepidopsetta bilineata
646
+ Corolla spectabilis
647
+ Haliscera conica
648
+ Brisaster
649
+ Oikopleura outer filter
650
+ Paulasterias mcclaini
651
+ Sicyonis careyi
652
+ Iosactis
653
+ Oikopleuridae inner filter
654
+ Chromista
655
+ Mola mola
656
+ Melanostigma pammelas
657
+ Scrippsia pacifica
658
+ larvacean house
659
+ Sebastes phillipsi
660
+ Peinaleopolynoe orphanae
661
+ Cnidaria
662
+ salp detritus
663
+ Atolla vanhoeffeni
664
+ Appendicularia outer filter
665
+ Appendicularia inner filter
666
+ Sebastes simulator
667
+ Acharax
668
+ Plesionika sp. A
669
+ Mediaster tenellus
670
+ Eutonina
671
+ Octopoteuthis deletron
672
+ Crustacea
673
+ Psathyrometra
674
+ Patellogastropoda
675
+ Sebastes cortezi tail
676
+ Yoda sp. A
677
+ Lophiodes caulinaris
678
+ Ptilosarcus
679
+ Gnathophis cinctus
680
+ Munidopsis sp. 2
681
+ salp chain
682
+ Oikopleuridae
683
+ Vogtia
684
+ Rossellidae
685
+ detrital aggregate
686
+ Sebastes maliger
687
+ Tuscaretta
688
+ Chaunacops coloratus
689
+ Pleurobrachiidae
690
+ Tenebrincola cukri
691
+ Amblyraja hyperborea
docs/gradio/mbari-mb-benthic-33k_stats.txt ADDED
@@ -0,0 +1,691 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ 339 Anoplopoma fimbria
2
+ 320 Crossaster
3
+ 27 Myxoderma sacculatum
4
+ 5114 Sebastolobus
5
+ 252 Neptunea-Buccinum Complex
6
+ 264 Ceriantharia
7
+ 6291 Merluccius productus
8
+ 2554 Pannychia moseleyi
9
+ 1751 Octopus rubescens
10
+ 3316 Actiniaria
11
+ 186 Solasteridae
12
+ 479 Antimora microlepis
13
+ 131 Macrouridae
14
+ 1408 Heteropolypus ritteri
15
+ 621 Liponema brevicorne
16
+ 3706 Ophiuroidea
17
+ 289 Octocorallia
18
+ 2575 Porifera
19
+ 413 Brisingida
20
+ 209 Chorilia longipes
21
+ 2803 Asteroidea
22
+ 235 equipment
23
+ 594 Metridium farcimen
24
+ 744 Embassichthys bathybius
25
+ 3848 Funiculina
26
+ 8631 Strongylocentrotus fragilis
27
+ 2790 Chionoecetes tanneri
28
+ 151 Actinostoloidea
29
+ 120 Myxoderma platyacanthum
30
+ 811 Gastropoda
31
+ 1723 Umbellula
32
+ 3965 Psolus squamatus
33
+ 786 Hexactinellida
34
+ 743 Swiftia simplex
35
+ 287 Galatheidae
36
+ 411 Coryphaenoides
37
+ 50 Dosidicus gigas
38
+ 1214 Microstomus pacificus
39
+ 65 Sebastolobus alascanus
40
+ 907 Farrea
41
+ 54 Poralia rufescens
42
+ 757 Acanthoptilum
43
+ 812 Isosicyonis
44
+ 3546 Paragorgia arborea
45
+ 25 Pannychia sp. 2
46
+ 14 Bothrocara brunneum
47
+ 409 Hormathiidae
48
+ 621 Lycenchelys
49
+ 488 Pteraster
50
+ 484 Paragorgia
51
+ 1368 Sebastes
52
+ 199 Bathyraja abyssicola
53
+ 403 Eptatretus
54
+ 86 Lycenchelys crotalinus
55
+ 788 Pennatulacea
56
+ 92 Pandalidae
57
+ 584 Tunicata
58
+ 803 Actinernus
59
+ 293 Asbestopluma rickettsi
60
+ 525 Apostichopus leukothele
61
+ 214 Stylasterias forreri
62
+ 44 Sebastes elongatus
63
+ 74 Sebastomus complex
64
+ 215 Parastenella
65
+ 504 Bathyraja trachura
66
+ 300 Laqueus californicus
67
+ 2 Eutonina indicans
68
+ 3829 Keratoisis
69
+ 8 Apristurus
70
+ 66 Mysida
71
+ 68 Tritonia tetraquetra
72
+ 284 Mediaster aequalis
73
+ 41 Anthoptilum grandiflorum
74
+ 22 Virgulariidae
75
+ 766 Vesicomyidae
76
+ 136 Sebastolobus altivelis
77
+ 246 Neptunea
78
+ 3181 Rathbunaster californicus
79
+ 424 Bathyraja kincaidii
80
+ 6 Scyliorhinidae
81
+ 15 Lycodapus
82
+ 160 Paralomis
83
+ 1426 Isididae
84
+ 160 Crinoidea
85
+ 31 Acanthogorgia
86
+ 301 Swiftia
87
+ 57 Enteroctopus dofleini
88
+ 39 Pagurus tanneri
89
+ 119 Mediaster
90
+ 28 Pyrosoma atlanticum
91
+ 1098 Nanomia bijuga
92
+ 359 Lycodes diapterus
93
+ 31 Pectinidae
94
+ 340 Asbestopluma
95
+ 263 Isidella
96
+ 301 Hippasteria
97
+ 34 Osedax
98
+ 152 Corallimorphus
99
+ 373 Florometra serratissima
100
+ 602 Scotoplanes
101
+ 415 Asteronyx
102
+ 418 Swiftia kofoidi
103
+ 29 Pandalus
104
+ 46 Pennatula phosphorea
105
+ 24 Ascidiacea
106
+ 12 Laminariales
107
+ 117 Doryteuthis opalescens
108
+ 5 Sebastidae
109
+ 43 Bathyraja
110
+ 590 Paelopatides confundens
111
+ 329 Suction Sampler
112
+ 270 Lycodes cortezianus
113
+ 337 Pandalus platyceros
114
+ 6 Lumpenus sagitta
115
+ 570 Pandalopsis ampla
116
+ 167 Hydrolagus colliei
117
+ 207 Bathyraja spinosissima
118
+ 62 Solaster hypothrissus
119
+ 36 Hyalonema (Corynonema) populiferum
120
+ 465 Holothuroidea
121
+ 56 Apostichopus
122
+ 167 Synallactidae
123
+ 209 Caridea
124
+ 72 Lithodidae
125
+ 1 Tonrometra
126
+ 26 Stomphia didemon
127
+ 50 Solmissus
128
+ 54 Euphausia
129
+ 59 Lycodapus fierasfer
130
+ 8 Munidopsis depressa
131
+ 3 Cataetyx
132
+ 520 Sebastes diploproa
133
+ 37 Pleurobranchaea californica
134
+ 80 Paguroidea
135
+ 49 Lycodes
136
+ 418 Heterochone calyx
137
+ 135 Isidella tentaculum
138
+ 500 Psathyrometra fragilis
139
+ 162 Sebastes melanostomus
140
+ 118 trash
141
+ 33 Xeneretmus latifrons
142
+ 157 Bathyraja microtrachys
143
+ 31 Bathybembix
144
+ 253 Pyrosoma detritus
145
+ 107 Luidia foliolata
146
+ 34 Lycodes pacificus
147
+ 55 Munida
148
+ 86 Beringraja rhina
149
+ 153 Lophaster
150
+ 2373 Gersemia juliepackardae
151
+ 128 Paralomis multispina
152
+ 21 Stomphia
153
+ 14 Primnoidae
154
+ 267 Funiculina-Halipteris complex
155
+ 684 Pleuronectiformes
156
+ 63 Sibogagorgia cauliflora
157
+ 17 Sebastes chlorostictus
158
+ 18 Sebastes zacentrus
159
+ 43 Sebastes babcocki
160
+ 67 Solaster
161
+ 50 Akoya platinum
162
+ 11 Opisthoteuthis sp. A
163
+ 50 Lepidisis
164
+ 2 Branchiocerianthus
165
+ 81 Antedonidae
166
+ 31 Gorgonocephalus eucnemis
167
+ 492 Staurocalyptus
168
+ 56 Glyptocephalus zachirus
169
+ 21 Phyllospadix-Zostera detritus
170
+ 53 Careproctus melanurus
171
+ 12 Amphipoda
172
+ 625 LRJ complex
173
+ 26 Careproctus
174
+ 24 Benthopecten
175
+ 7 Squalus suckleyi
176
+ 31 Eopsetta jordani
177
+ 81 Eusergestes similis
178
+ 32 Sabellida
179
+ 6 Brachyura
180
+ 275 Serpulidae
181
+ 22 Lyopsetta exilis
182
+ 107 Mycale
183
+ 33 Poraniopsis inflata
184
+ 23 Eualus macrophthalmus
185
+ 12 Chonelasma
186
+ 163 Acanthascinae
187
+ 21 Rajiformes
188
+ 115 Corallimorphus pilatus
189
+ 19 Zoarcidae
190
+ 41 Aegina
191
+ 1 medusa carcass
192
+ 3 Neogastropoda
193
+ 10 Pleuronectidae
194
+ 7 Calyptogena
195
+ 10 Pleuronectinae
196
+ 296 Hymenaster
197
+ 202 Munidopsis
198
+ 14 Swiftia sim
199
+ 54 Munnopsidae
200
+ 7 Lobata
201
+ 138 Pannychia
202
+ 8 Lithodes couesi
203
+ 4 Myctophidae
204
+ 7 Thrissacanthias penicillatus
205
+ 34 geology
206
+ 8 Dofleinia
207
+ 141 Asthenactis fisheri
208
+ 15 Cydippida
209
+ 4 Harriotta raleighana
210
+ 11 Metacarcinus magister
211
+ 2 Gobiidae
212
+ 5 Albatrossia pectoralis
213
+ 6 Lampocteis cruentiventer
214
+ 21 Buccinidae
215
+ 53 Alcyonacea
216
+ 58 Ophiacanthidae
217
+ 5 Careproctus kamikawai
218
+ 4 Stylatula
219
+ 72 Paragorgiidae
220
+ 12 Majidae
221
+ 21 Megalodicopia hians
222
+ 2 Moridae
223
+ 13 Ptilosarcus gurneyi
224
+ 23 Isopoda
225
+ 214 Asbestopluma monticola
226
+ 9 Octopoda
227
+ 54 Bivalvia
228
+ 17 Desmophyllum dianthus
229
+ 41 Fungiacyathus (Bathyactis) marenzelleri
230
+ 3760 Peniagone
231
+ 822 Elpidia
232
+ 1706 Scotoplanes globosa
233
+ 32 Teuthoidea
234
+ 551 Peniagone gracilis
235
+ 158 Oneirophanta mutabilis complex
236
+ 337 Nanomia bijuga nectosome
237
+ 6 fishing-debris
238
+ 231 Peniagone papillata
239
+ 184 Synallactidae gen. et sp. indet.
240
+ 18 Sebastes rufus
241
+ 109 Hydrolagus cf. trolli
242
+ 96 Psychropotes sp. 2
243
+ 255 Tjalfiella
244
+ 24 Poeobius meseres
245
+ 34 Bathochordaeus stygius inner filter
246
+ 31 Bathochordaeus stygius outer filter
247
+ 17 Hydrozoa
248
+ 57 Cnemidocarpa
249
+ 29 Hyalonema
250
+ 21 Malacostraca
251
+ 17 Iosactis vagabunda
252
+ 499 Abyssocucumis abyssorum
253
+ 811 Peniagone vitrea
254
+ 18 Ophiodon elongatus
255
+ 10 Parastichopus leukothele
256
+ 124 Cystechinus loveni
257
+ 13 Ceramaster
258
+ 51 Hexacorallia
259
+ 163 Octopus californicus
260
+ 17 Neolithodes diomedeae
261
+ 381 Benthocodon pedunculata
262
+ 4 Styelidae
263
+ 9 Physiculus rastrelliger
264
+ 25 Laetmogone
265
+ 40 Sebastes saxicola
266
+ 11 Bathochordaeus
267
+ 62 Cladorhizidae
268
+ 8 Peribolaster biserialis
269
+ 144 Muusoctopus robustus
270
+ 43 Hydrolagus melanophasma
271
+ 8 Beroe forskalii
272
+ 15 Sebastes flavidus
273
+ 3 Nemichthyidae
274
+ 22 Poraniopsis
275
+ 12 Sebastes brevispinis
276
+ 16 Sebastes rubrivinctus
277
+ 32 Octopodidae
278
+ 1 Paraliparis sp. 2
279
+ 33 Pythonaster
280
+ 74 Synallactes
281
+ 6 Sebastes ensifer
282
+ 19 Sebastes miniatus
283
+ 40 Hyalonema (Oonema) bianchoratum
284
+ 2 Anomura
285
+ 92 Echinocrepis rostrata
286
+ 8 Prayidae
287
+ 2 Physonectae nectosome
288
+ 2 Physonectae
289
+ 9 Sebastes paucispinis
290
+ 1 Sebastes head
291
+ 45 Hirudinea
292
+ 2 Urticina
293
+ 2 Astropecten
294
+ 30 Leptogorgia
295
+ 51 Galatheoidea
296
+ 5 Beroe cucumis
297
+ 28 Bolocera
298
+ 14 Fariometra parvula
299
+ 5 Neptunea-Buccinum Complex eggcase
300
+ 51 Graneledone boreopacifica
301
+ 7 Polynoidae
302
+ 55 Psamminidae
303
+ 29 Psychrolutes phrictus
304
+ 2 Sergestes similis
305
+ 2 Calycophorae nectosome
306
+ 40 Beroe
307
+ 37 Thenea muricata
308
+ 17 Gonatus
309
+ 18 Henricia
310
+ 1 Nudibranchia
311
+ 66 Sebastes aurora
312
+ 681 Zoantharia
313
+ 112 Clavularia
314
+ 33 Terebratulina complex
315
+ 4 Macrourinae
316
+ 34 Ptychogastria
317
+ 21 Delectopecten
318
+ 20 Phacellophora camtschatica
319
+ 10 Siboglinidae
320
+ 6 Gorgoniidae
321
+ 132 eggcase
322
+ 60 Sibogagorgia
323
+ 106 Comatulida
324
+ 3 Diogenidae
325
+ 2 eggs
326
+ 12 Apolemia
327
+ 7 Midwater Respirometry System
328
+ 15 Pycnogonida
329
+ 25 Calliostoma
330
+ 14 Sebastes aleutianus-melanostictus complex
331
+ 57 Brachiopoda
332
+ 8 Medusae
333
+ 31 Lamellibrachia
334
+ 28 Bathyphellia australis
335
+ 6 Ophiuridae
336
+ 8 Lycodes brevipes
337
+ 13 Atolla
338
+ 4 Plectobranchus evides
339
+ 3 Asteriidae
340
+ 84 Farrea occa
341
+ 7 Agonidae
342
+ 9 Bathymetrinae
343
+ 7 Decapoda
344
+ 17 Corallium
345
+ 87 Halipteris californica
346
+ 8 Dipsacaster
347
+ 2 Chonelasmatinae sp. 2
348
+ 29 shell
349
+ 3 Phyllospadix detritus
350
+ 1 Spectrunculus grandis
351
+ 18 shell fragment
352
+ 9 Paralomis verrilli
353
+ 5 Hydrolagus
354
+ 21 Actinopterygii
355
+ 26 Parmaturus xaniurus
356
+ 3 whale carcass
357
+ 1 Pterasteridae arm
358
+ 5 Annelida
359
+ 2 Lyrocteis
360
+ 14 Echiura
361
+ 11 Vanhoeffenura pulchra
362
+ 14 Bolinopsis infundibulum
363
+ 31 Colossendeidae
364
+ 18 Bathochordaeus stygius
365
+ 44 Sebastes jordani
366
+ 3 Platyctenida
367
+ 2 Saxipendium implicatum
368
+ 2 TorquaratoridaeB sp. 2
369
+ 28 Pachycara bulbiceps
370
+ 10 Hydractiniidae
371
+ 47 Psamminidae sp. 2
372
+ 1 Tjalfiellidae
373
+ 62 Myxoderma
374
+ 5 Hyocrinidae
375
+ 3 Chondrocladia
376
+ 78 Cystocrepis setigera
377
+ 19 Munidopsis kensmithi
378
+ 2 Radiozoa
379
+ 22 Chaetognatha
380
+ 14 Siphonophorae
381
+ 36 Chrysogorgia
382
+ 13 Pseudostichopus mollis
383
+ 10 Benthothuria
384
+ 21 Bolocera kensmithi
385
+ 11 Sebastes semicinctus
386
+ 1 Galiteuthis phyllura
387
+ 2 Octopodinae
388
+ 2 Serrivomer
389
+ 8 Demospongiae
390
+ 6 Latrunculia (Latrunculia) austini
391
+ 15 Dromalia alexandri
392
+ 82 Scleractinia
393
+ 16 Plesionika
394
+ 27 bacterial mat
395
+ 2 Chondrocladia (Symmetrocladia) lyra
396
+ 13 Neoloricata
397
+ 2 asteroid feeding depression
398
+ 8 Bathyalcyon robustum
399
+ 2 Bathypterois
400
+ 2 Distichoptilum
401
+ 2 Paraliparis cephalus
402
+ 9 Sebastes serranoides
403
+ 12 Goniasteridae
404
+ 3 ledge
405
+ 21 Tromikosoma panamense
406
+ 10 Ctenophora
407
+ 7 Docosaccus maculatus
408
+ 2 sinker
409
+ 20 Lophaster furcilliger
410
+ 46 Sebastes cortezi
411
+ 8 Culeolus
412
+ 4 Mysidacea
413
+ 64 Bathydorus laevis pseudospinosus
414
+ 2 Alepocephalus tenebrosus
415
+ 12 Echinoidea
416
+ 13 Heterozonias alternatus
417
+ 19 Smithsonius dorothea
418
+ 2 Heterocarpus sp. 2
419
+ 2 Eucryphycus californicus
420
+ 104 Polychaeta tube
421
+ 4 Cirroteuthis
422
+ 20 Tergivelum baldwinae
423
+ 2 Tiburonia granrojo
424
+ 7 Liparidae
425
+ 19 Riftia pachyptila
426
+ 2 Hydroidolina
427
+ 9 Plexauridae
428
+ 5 Bathylagidae
429
+ 4 Lepidion
430
+ 7 Sclerothamnopsis
431
+ 1 Careproctus ovigerus
432
+ 3 Psychropotes depressa
433
+ 11 Icelinus filamentosus
434
+ 24 Chrysogorgia monticola
435
+ 3 wood
436
+ 13 Bathochordaeus inner filter
437
+ 15 Sebastes entomelas
438
+ 11 Anthozoa
439
+ 6 Bathypterois pectinatus
440
+ 20 Cladorhiza kensmithi
441
+ 15 Aporocidaris milleri
442
+ 6 Ischnomesidae
443
+ 9 Staurocalyptus solidus
444
+ 18 Anthoptilum lithophilum
445
+ 5 Atolla wyvillei
446
+ 6 Erenna richardi
447
+ 4 Hyalonematidae
448
+ 1 Pleurobranchaea
449
+ 3 Sergestidae
450
+ 6 Thermarces cerberus
451
+ 43 Pennatula
452
+ 3 Moloha faxoni
453
+ 5 Munida quadrispina
454
+ 2 Lophiiformes
455
+ 11 Benthoctopus
456
+ 60 Strongylocentrotus
457
+ 2 kelp
458
+ 5 Nanomia nectosome
459
+ 10 Sicyonis
460
+ 17 Chrysogorgia pinnata
461
+ 4 Forskalia formosa
462
+ 39 Sebastes ruberrimus
463
+ 10 Sebastes levis
464
+ 14 Praya dubia nectosome
465
+ 17 Praya dubia
466
+ 2 Pleuronectiformes 3
467
+ 3 Chuniphyes multidentata
468
+ 1 Dictyocalyx
469
+ 1 Zaniolepis frenata
470
+ 4 Octopus
471
+ 6 Forcipulatacea
472
+ 2 Eretmichthys pinnatus
473
+ 2 Dibranchus hystrix
474
+ 1 Coelorinchus spilonotus
475
+ 2 Pseudobathylagus
476
+ 6 Benthodytes
477
+ 6 Alternatipathes
478
+ 10 Lillipathes
479
+ 46 Protoptilum sp. 2
480
+ 5 Hastigerinella digitata
481
+ 8 Bargmannia elongata
482
+ 7 Bargmannia elongata nectosome
483
+ 8 Psychronaetes
484
+ 6 Bathysaurus mollis
485
+ 12 Lycodinae
486
+ 3 Euplectellidae
487
+ 6 Pasiphaea
488
+ 23 Bathysiphon
489
+ 4 Beroe abyssicola
490
+ 11 Tomopteris
491
+ 8 Polychaeta
492
+ 5 Articulata
493
+ 3 Apostichopus californicus
494
+ 23 Kophobelemnon
495
+ 6 Bolinopsis
496
+ 3 Euryalida
497
+ 2 Pennatulidae
498
+ 2 Gastroptychus
499
+ 3 molt
500
+ 2 Corallimorphus denhartogi
501
+ 8 Neptunea eggcase
502
+ 11 Octacnemidae sp. 2
503
+ 5 Xeneretmus
504
+ 3 Dibranchus spinosus
505
+ 30 Epizoanthus stellaris
506
+ 4 Pennatulacea sp. 2
507
+ 2 Sebastes borealis
508
+ 2 Aeolidiidae
509
+ 43 Mitrocoma cellularia
510
+ 3 Tromikosoma
511
+ 1 Icichthys lockingtoni
512
+ 6 Solmissus incisa
513
+ 13 Sebastes pinniger
514
+ 5 Enteropneusta
515
+ 5 Sebastes auriculatus
516
+ 6 Megalodicopia
517
+ 10 Asthenactis papyraceus
518
+ 4 Sebastes miniatus-pinniger complex
519
+ 8 Asthenactis
520
+ 3 test
521
+ 3 Icelinus
522
+ 1 Parantipathes
523
+ 13 Sebastes macdonaldi
524
+ 4 Sebastes mystinus
525
+ 5 Physiculus nematopus-rastrelliger complex
526
+ 1 Sebastes rosenblatti
527
+ 16 Bathochordaeus sinker
528
+ 3 Distichoptilum gracile
529
+ 1 kelp holdfast
530
+ 1 Rhinochimaeridae
531
+ 3 Echinocrepis setigera
532
+ 9 Sebastes caurinus
533
+ 2 Egregia menziesii
534
+ 1 Myriothelidae
535
+ 5 coiled fecal cast
536
+ 1 Cystechinus giganteus
537
+ 8 Bathochordaeus mcnutti inner filter
538
+ 8 Bathochordaeus mcnutti
539
+ 1 Cladorhiza
540
+ 6 Cirripedia
541
+ 2 Swiftia kol
542
+ 4 Phyllochaetopterus gigas
543
+ 10 Hymenaster koehleri
544
+ 3 sinker outer filter
545
+ 11 Allocentrotus fragilis
546
+ 2 Luciobrotula sp. A
547
+ 1 Opisthoteuthis
548
+ 1 Haliscera bigelowi
549
+ 12 Scotoplanes clarki
550
+ 2 Lyssacinosida sp. 2
551
+ 2 larvacean outer filter
552
+ 1 Ophichthus frontalis
553
+ 3 Calyptrophora
554
+ 6 Provannidae
555
+ 3 Marine organism
556
+ 3 Farrea truncata complex
557
+ 3 Actinoscyphia
558
+ 5 Exocoelactis
559
+ 12 Kophobelemnidae
560
+ 1 Lychnagalma nectosome
561
+ 1 Lychnagalma
562
+ 8 Caenogastropoda
563
+ 5 Zoroasteridae
564
+ 13 Bathochordaeus outer filter
565
+ 3 Vanhoeffenura
566
+ 2 Stylasterias
567
+ 4 Calycophorae
568
+ 4 Vitreosalpa gemini
569
+ 2 Anguilliformes
570
+ 1 Calocarides quinqueseriatus
571
+ 1 Fungiacyathus
572
+ 3 Candelabridae sp. 2
573
+ 2 Tergivelum sp. A
574
+ 1 Mesochordaeus erythrocephalus
575
+ 1 Monothalamea
576
+ 4 Paradiopatra
577
+ 2 Munida bapensis
578
+ 8 Sebastes crameri-melanostomus complex
579
+ 1 Asterozoa
580
+ 6 Patiria miniata
581
+ 1 Ophidiiformes
582
+ 3 Salpida
583
+ 2 Coelorinchus scaphopsis
584
+ 2 Tomopteris nisseni
585
+ 2 Camptoplites sp. A
586
+ 2 Psychropotidae
587
+ 1 Paxillosida
588
+ 2 Dendronotus patricki
589
+ 4 Oneirophanta
590
+ 1 Lensia conoidea nectosome
591
+ 2 Lensia conoidea
592
+ 4 Glyphocrangon vicaria
593
+ 3 Dipsacaster eximius
594
+ 3 Bathydorus
595
+ 4 Bathycrinidae
596
+ 4 Sebastolobus head
597
+ 1 Doryteuthis (Amerigo) opalescens eggs
598
+ 5 Sebastes crameri
599
+ 1 Thetys vagina
600
+ 5 Sebastes ovalis
601
+ 1 Lycodapus mandibularis
602
+ 1 Sebastolobus tail
603
+ 7 Sebastes goodei
604
+ 1 Pseudobathylagus milleri
605
+ 1 Narcomedusa
606
+ 2 Chiroteuthis calyx
607
+ 1 Heterobranchia
608
+ 1 Octacnemidae
609
+ 1 inner filter
610
+ 1 Pentametrocrinus paucispinulus
611
+ 2 Beroe gracilis
612
+ 1 Schizopathidae
613
+ 2 Dytaster gilberti
614
+ 3 Physiculus sp. 2
615
+ 1 Octopodidae tentacle
616
+ 5 Mysidae
617
+ 1 Antipatharia
618
+ 2 Lychnagalma utricularia nectosome
619
+ 2 Lychnagalma utricularia
620
+ 1 Ridgeia
621
+ 1 Actinauge verrillii
622
+ 1 Oikopleuridae outer filter
623
+ 1 Fecampiid eggcase
624
+ 2 Chilara taylori
625
+ 1 Acesta
626
+ 3 Caulophacus
627
+ 2 Parophrys vetulus
628
+ 1 Dibranchus sp. A
629
+ 1 Holothuria (Vaneyothuria) zacae
630
+ 2 Prayidae nectosome
631
+ 1 Acanthephyra
632
+ 1 Bathycrinus complanatus
633
+ 1 Munnopsis
634
+ 1 Alcyoniidae
635
+ 1 Microstomus bathybius
636
+ 1 Theudoidea
637
+ 4 Hydromedusae
638
+ 1 Protoptilum
639
+ 2 Bathyphellia
640
+ 1 Euplokamidae
641
+ 1 Microstomus pacificus sole
642
+ 3 Hormiphora californensis
643
+ 1 Leptocephalus-3
644
+ 2 Verum proximum
645
+ 1 Lepidopsetta bilineata
646
+ 1 Corolla spectabilis
647
+ 1 Haliscera conica
648
+ 18 Brisaster
649
+ 2 Oikopleura outer filter
650
+ 1 Paulasterias mcclaini
651
+ 1 Sicyonis careyi
652
+ 2 Iosactis
653
+ 1 Oikopleuridae inner filter
654
+ 1 Chromista
655
+ 1 Mola mola
656
+ 1 Melanostigma pammelas
657
+ 1 Scrippsia pacifica
658
+ 1 larvacean house
659
+ 4 Sebastes phillipsi
660
+ 1 Peinaleopolynoe orphanae
661
+ 3 Cnidaria
662
+ 1 salp detritus
663
+ 5 Atolla vanhoeffeni
664
+ 1 Appendicularia outer filter
665
+ 1 Appendicularia inner filter
666
+ 2 Sebastes simulator
667
+ 1 Acharax
668
+ 2 Plesionika sp. A
669
+ 1 Mediaster tenellus
670
+ 1 Eutonina
671
+ 2 Octopoteuthis deletron
672
+ 1 Crustacea
673
+ 2 Psathyrometra
674
+ 2 Patellogastropoda
675
+ 1 Sebastes cortezi tail
676
+ 2 Yoda sp. A
677
+ 1 Lophiodes caulinaris
678
+ 1 Ptilosarcus
679
+ 1 Gnathophis cinctus
680
+ 4 Munidopsis sp. 2
681
+ 2 salp chain
682
+ 1 Oikopleuridae
683
+ 1 Vogtia
684
+ 2 Rossellidae
685
+ 3 detrital aggregate
686
+ 1 Sebastes maliger
687
+ 1 Tuscaretta
688
+ 1 Chaunacops coloratus
689
+ 1 Pleurobrachiidae
690
+ 1 Tenebrincola cukri
691
+ 1 Amblyraja hyperborea
docs/gradio/requirements.txt ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ tator
2
+ yolov5==6.2.3
docs/gradio/tator_inference.py ADDED
@@ -0,0 +1,100 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import logging
3
+ from tempfile import TemporaryFile
4
+
5
+ import cv2
6
+ import numpy as np
7
+ from PIL import Image
8
+
9
+ import tator
10
+ import inference
11
+
12
+
13
+ logger = logging.getLogger(__name__)
14
+ logger.setLevel(logging.INFO)
15
+
16
+ # Read environment variables that are provided from TATOR
17
+ host = os.getenv('HOST')
18
+ token = os.getenv('TOKEN')
19
+ project_id = int(os.getenv('PROJECT_ID'))
20
+ media_ids = [int(id_) for id_ in os.getenv('MEDIA_IDS').split(',')]
21
+ frames_per_inference = int(os.getenv('FRAMES_PER_INFERENCE', 30))
22
+
23
+ # Set up the TATOR API.
24
+ api = tator.get_api(host, token)
25
+
26
+ # Iterate through each video.
27
+ for media_id in media_ids:
28
+
29
+ # Download video.
30
+ media = api.get_media(media_id)
31
+ logger.info(f"Downloading {media.name}...")
32
+ out_path = f"/tmp/{media.name}"
33
+ for progress in tator.util.download_media(api, media, out_path):
34
+ logger.info(f"Download progress: {progress}%")
35
+
36
+ # Do inference on each video.
37
+ logger.info(f"Doing inference on {media.name}...")
38
+ localizations = []
39
+ vid = cv2.VideoCapture(out_path)
40
+ frame_number = 0
41
+
42
+ # Read *every* frame from the video, break when at the end.
43
+ while True:
44
+ ret, frame = vid.read()
45
+ if not ret:
46
+ break
47
+
48
+ # Create a temporary file, access the image data, save data to file.
49
+ framefile = TemporaryFile(suffix='.jpg')
50
+ im = Image.fromarray(frame)
51
+ im.save(framefile)
52
+
53
+ # For every N frames, make a prediction; append prediction results
54
+ # to a list, increase the frame count.
55
+ if frame_number % frames_per_inference == 0:
56
+
57
+ spec = {}
58
+
59
+ # Predictions contains all information inside pandas dataframe
60
+ predictions = inference.run_inference(framefile)
61
+
62
+ for i, r in predictions.pandas().xyxy[0].iterrows:
63
+
64
+ spec['media_id'] = media_id
65
+ spec['type'] = None # Unsure, docs not specific
66
+ spec['frame'] = frame_number
67
+
68
+ x, y, x2, y2 = r['xmin'], r['ymin'], r['xmax'], r['ymax']
69
+ w, h = x2 - x, y2 - y
70
+
71
+ spec['x'] = x
72
+ spec['y'] = y
73
+ spec['width'] = w
74
+ spec['height'] = h
75
+ spec['class_category'] = r['name']
76
+ spec['confidence'] = r['confidence']
77
+
78
+ localizations.append(spec)
79
+
80
+ frame_number += 1
81
+
82
+ # End interaction with video properly.
83
+ vid.release()
84
+
85
+ logger.info(f"Uploading object detections on {media.name}...")
86
+
87
+ # Create the localizations in the video.
88
+ num_created = 0
89
+ for response in tator.util.chunked_create(api.create_localization_list,
90
+ project_id,
91
+ localization_spec=localizations):
92
+ num_created += len(response.id)
93
+
94
+ # Output pretty logging information.
95
+ logger.info(f"Successfully created {num_created} localizations on "
96
+ f"{media.name}!")
97
+
98
+ logger.info("-------------------------------------------------")
99
+
100
+ logger.info(f"Completed inference on {len(media_ids)} files.")
requirements.txt CHANGED
@@ -21,6 +21,9 @@ huggingface-hub==0.19.4
21
  python-multipart==0.0.6
22
  aiofiles==23.2.1
23
 
 
 
 
24
  # Performance monitoring and optimization
25
  psutil==5.9.6
26
 
 
21
  python-multipart==0.0.6
22
  aiofiles==23.2.1
23
 
24
+ # Templates and Static Files (for dashboard)
25
+ jinja2==3.1.2
26
+
27
  # Performance monitoring and optimization
28
  psutil==5.9.6
29
 
static/css/dashboard.css ADDED
@@ -0,0 +1,356 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* Dashboard-specific styles */
2
+
3
+ .dashboard {
4
+ max-width: 1400px;
5
+ margin: 0 auto;
6
+ }
7
+
8
+ /* Page Header */
9
+ .page-header {
10
+ text-align: center;
11
+ margin-bottom: var(--spacing-xl);
12
+ }
13
+
14
+ .page-description {
15
+ font-size: 1.125rem;
16
+ color: var(--gray-600);
17
+ max-width: 600px;
18
+ margin: 0 auto;
19
+ line-height: 1.6;
20
+ }
21
+
22
+ /* Status Banner */
23
+ .status-banner {
24
+ background: white;
25
+ border: 1px solid var(--gray-200);
26
+ border-radius: var(--radius-lg);
27
+ padding: var(--spacing-md);
28
+ margin-bottom: var(--spacing-xl);
29
+ display: flex;
30
+ align-items: center;
31
+ justify-content: space-between;
32
+ box-shadow: var(--shadow-sm);
33
+ }
34
+
35
+ .status-indicator {
36
+ display: flex;
37
+ align-items: center;
38
+ gap: var(--spacing-sm);
39
+ }
40
+
41
+ .status-dot {
42
+ width: 12px;
43
+ height: 12px;
44
+ border-radius: 50%;
45
+ background: var(--gray-400);
46
+ animation: pulse 2s infinite;
47
+ }
48
+
49
+ .status-dot.healthy {
50
+ background: var(--success-green);
51
+ }
52
+
53
+ .status-dot.error {
54
+ background: var(--error-red);
55
+ }
56
+
57
+ .status-text {
58
+ font-weight: 500;
59
+ color: var(--gray-700);
60
+ }
61
+
62
+ .model-info {
63
+ font-size: 0.875rem;
64
+ color: var(--gray-500);
65
+ }
66
+
67
+ @keyframes pulse {
68
+ 0%, 100% { opacity: 1; }
69
+ 50% { opacity: 0.5; }
70
+ }
71
+
72
+ /* Dashboard Grid */
73
+ .dashboard-grid {
74
+ display: grid;
75
+ grid-template-columns: 1fr 1fr 1fr;
76
+ gap: var(--spacing-xl);
77
+ margin-bottom: var(--spacing-2xl);
78
+ }
79
+
80
+ .panel {
81
+ min-height: 600px;
82
+ }
83
+
84
+ /* Upload Area */
85
+ .upload-area {
86
+ border: 2px dashed var(--gray-300);
87
+ border-radius: var(--radius-lg);
88
+ padding: var(--spacing-2xl);
89
+ text-align: center;
90
+ cursor: pointer;
91
+ transition: all 0.2s ease;
92
+ margin-bottom: var(--spacing-lg);
93
+ min-height: 200px;
94
+ display: flex;
95
+ align-items: center;
96
+ justify-content: center;
97
+ }
98
+
99
+ .upload-area:hover {
100
+ border-color: var(--primary-blue);
101
+ background-color: var(--gray-50);
102
+ }
103
+
104
+ .upload-area.dragover {
105
+ border-color: var(--primary-blue);
106
+ background-color: #eff6ff;
107
+ transform: scale(1.02);
108
+ }
109
+
110
+ .upload-area.has-image {
111
+ border-style: solid;
112
+ border-color: var(--success-green);
113
+ background-color: var(--gray-50);
114
+ padding: var(--spacing-md);
115
+ }
116
+
117
+ .upload-content {
118
+ display: flex;
119
+ flex-direction: column;
120
+ align-items: center;
121
+ gap: var(--spacing-md);
122
+ }
123
+
124
+ .upload-icon {
125
+ font-size: 3rem;
126
+ color: var(--gray-400);
127
+ }
128
+
129
+ .upload-primary {
130
+ font-size: 1.125rem;
131
+ font-weight: 500;
132
+ color: var(--gray-700);
133
+ margin: 0;
134
+ }
135
+
136
+ .upload-secondary {
137
+ font-size: 0.875rem;
138
+ color: var(--gray-500);
139
+ margin: 0;
140
+ }
141
+
142
+ /* Settings Section */
143
+ .settings-section {
144
+ margin-bottom: var(--spacing-lg);
145
+ padding-top: var(--spacing-lg);
146
+ border-top: 1px solid var(--gray-200);
147
+ }
148
+
149
+ .settings-section h4 {
150
+ margin-bottom: var(--spacing-md);
151
+ color: var(--gray-700);
152
+ }
153
+
154
+ .settings-grid {
155
+ display: grid;
156
+ gap: var(--spacing-md);
157
+ }
158
+
159
+ .setting-item label {
160
+ display: block;
161
+ font-size: 0.875rem;
162
+ font-weight: 500;
163
+ color: var(--gray-700);
164
+ margin-bottom: var(--spacing-xs);
165
+ }
166
+
167
+ .slider-container {
168
+ display: flex;
169
+ align-items: center;
170
+ gap: var(--spacing-md);
171
+ }
172
+
173
+ .slider-container input[type="range"] {
174
+ flex: 1;
175
+ height: 6px;
176
+ border-radius: 3px;
177
+ background: var(--gray-200);
178
+ outline: none;
179
+ -webkit-appearance: none;
180
+ }
181
+
182
+ .slider-container input[type="range"]::-webkit-slider-thumb {
183
+ -webkit-appearance: none;
184
+ width: 20px;
185
+ height: 20px;
186
+ border-radius: 50%;
187
+ background: var(--primary-blue);
188
+ cursor: pointer;
189
+ box-shadow: var(--shadow-sm);
190
+ }
191
+
192
+ .slider-container input[type="range"]::-moz-range-thumb {
193
+ width: 20px;
194
+ height: 20px;
195
+ border-radius: 50%;
196
+ background: var(--primary-blue);
197
+ cursor: pointer;
198
+ border: none;
199
+ box-shadow: var(--shadow-sm);
200
+ }
201
+
202
+ .slider-value {
203
+ font-size: 0.875rem;
204
+ font-weight: 500;
205
+ color: var(--primary-blue);
206
+ min-width: 40px;
207
+ text-align: right;
208
+ }
209
+
210
+ /* Button Styles */
211
+ .btn-full {
212
+ width: 100%;
213
+ }
214
+
215
+ /* Image Containers */
216
+ .image-container {
217
+ border: 1px solid var(--gray-200);
218
+ border-radius: var(--radius-md);
219
+ overflow: hidden;
220
+ min-height: 250px;
221
+ display: flex;
222
+ align-items: center;
223
+ justify-content: center;
224
+ background: var(--gray-50);
225
+ }
226
+
227
+ .image-container img {
228
+ max-width: 100%;
229
+ max-height: 100%;
230
+ object-fit: contain;
231
+ }
232
+
233
+ .image-placeholder {
234
+ text-align: center;
235
+ color: var(--gray-400);
236
+ }
237
+
238
+ .placeholder-icon {
239
+ font-size: 2rem;
240
+ margin-bottom: var(--spacing-sm);
241
+ }
242
+
243
+ /* Results Sections */
244
+ .annotated-section,
245
+ .metadata-section,
246
+ .species-section {
247
+ margin-bottom: var(--spacing-lg);
248
+ }
249
+
250
+ .annotated-section h4,
251
+ .metadata-section h4,
252
+ .species-section h4 {
253
+ margin-bottom: var(--spacing-md);
254
+ color: var(--gray-700);
255
+ font-size: 1rem;
256
+ font-weight: 600;
257
+ }
258
+
259
+ /* Metadata Grid */
260
+ .metadata-grid {
261
+ display: grid;
262
+ gap: var(--spacing-sm);
263
+ }
264
+
265
+ .metadata-item {
266
+ display: flex;
267
+ justify-content: space-between;
268
+ align-items: center;
269
+ padding: var(--spacing-sm);
270
+ background: var(--gray-50);
271
+ border-radius: var(--radius-sm);
272
+ }
273
+
274
+ .metadata-label {
275
+ font-size: 0.875rem;
276
+ color: var(--gray-600);
277
+ }
278
+
279
+ .metadata-value {
280
+ font-size: 0.875rem;
281
+ font-weight: 500;
282
+ color: var(--gray-900);
283
+ }
284
+
285
+ /* Species List */
286
+ .species-list {
287
+ display: grid;
288
+ gap: var(--spacing-sm);
289
+ max-height: 300px;
290
+ overflow-y: auto;
291
+ }
292
+
293
+ .species-item {
294
+ display: flex;
295
+ justify-content: space-between;
296
+ align-items: center;
297
+ padding: var(--spacing-sm);
298
+ background: white;
299
+ border: 1px solid var(--gray-200);
300
+ border-radius: var(--radius-sm);
301
+ transition: all 0.2s ease;
302
+ }
303
+
304
+ .species-item:hover {
305
+ border-color: var(--primary-blue);
306
+ box-shadow: var(--shadow-sm);
307
+ }
308
+
309
+ .species-name {
310
+ font-size: 0.875rem;
311
+ font-weight: 500;
312
+ color: var(--gray-900);
313
+ }
314
+
315
+ .species-confidence {
316
+ font-size: 0.875rem;
317
+ font-weight: 600;
318
+ color: var(--primary-blue);
319
+ }
320
+
321
+ /* Responsive Design */
322
+ @media (max-width: 1024px) {
323
+ .dashboard-grid {
324
+ grid-template-columns: 1fr;
325
+ gap: var(--spacing-lg);
326
+ }
327
+
328
+ .status-banner {
329
+ flex-direction: column;
330
+ gap: var(--spacing-sm);
331
+ text-align: center;
332
+ }
333
+ }
334
+
335
+ @media (max-width: 768px) {
336
+ .upload-area {
337
+ padding: var(--spacing-lg);
338
+ min-height: 150px;
339
+ }
340
+
341
+ .upload-icon {
342
+ font-size: 2rem;
343
+ }
344
+
345
+ .upload-primary {
346
+ font-size: 1rem;
347
+ }
348
+
349
+ .settings-grid {
350
+ gap: var(--spacing-sm);
351
+ }
352
+
353
+ .image-container {
354
+ min-height: 200px;
355
+ }
356
+ }
static/css/main.css ADDED
@@ -0,0 +1,275 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* Marine Species API - Main Stylesheet */
2
+
3
+ :root {
4
+ /* Color Palette */
5
+ --primary-blue: #2563eb;
6
+ --success-green: #059669;
7
+ --error-red: #dc2626;
8
+ --warning-yellow: #d97706;
9
+
10
+ /* Grays */
11
+ --gray-50: #f9fafb;
12
+ --gray-100: #f3f4f6;
13
+ --gray-200: #e5e7eb;
14
+ --gray-300: #d1d5db;
15
+ --gray-400: #9ca3af;
16
+ --gray-500: #6b7280;
17
+ --gray-600: #4b5563;
18
+ --gray-700: #374151;
19
+ --gray-800: #1f2937;
20
+ --gray-900: #111827;
21
+
22
+ /* Spacing */
23
+ --spacing-xs: 0.25rem;
24
+ --spacing-sm: 0.5rem;
25
+ --spacing-md: 1rem;
26
+ --spacing-lg: 1.5rem;
27
+ --spacing-xl: 2rem;
28
+ --spacing-2xl: 3rem;
29
+
30
+ /* Border Radius */
31
+ --radius-sm: 6px;
32
+ --radius-md: 8px;
33
+ --radius-lg: 12px;
34
+ --radius-xl: 16px;
35
+
36
+ /* Shadows */
37
+ --shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
38
+ --shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
39
+ --shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
40
+ }
41
+
42
+ /* Reset and Base Styles */
43
+ * {
44
+ margin: 0;
45
+ padding: 0;
46
+ box-sizing: border-box;
47
+ }
48
+
49
+ body {
50
+ font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
51
+ font-size: 1rem;
52
+ line-height: 1.5;
53
+ color: var(--gray-900);
54
+ background-color: var(--gray-50);
55
+ min-height: 100vh;
56
+ display: flex;
57
+ flex-direction: column;
58
+ }
59
+
60
+ /* Container */
61
+ .container {
62
+ max-width: 1200px;
63
+ margin: 0 auto;
64
+ padding: 0 var(--spacing-md);
65
+ }
66
+
67
+ /* Header */
68
+ .header {
69
+ background: white;
70
+ border-bottom: 1px solid var(--gray-200);
71
+ position: sticky;
72
+ top: 0;
73
+ z-index: 100;
74
+ }
75
+
76
+ .header .container {
77
+ display: flex;
78
+ align-items: center;
79
+ justify-content: space-between;
80
+ padding: var(--spacing-md);
81
+ }
82
+
83
+ .nav-brand {
84
+ display: flex;
85
+ align-items: center;
86
+ gap: var(--spacing-sm);
87
+ }
88
+
89
+ .nav-icon {
90
+ font-size: 1.5rem;
91
+ }
92
+
93
+ .nav-title {
94
+ font-size: 1.25rem;
95
+ font-weight: 600;
96
+ color: var(--gray-900);
97
+ }
98
+
99
+ .nav-tabs {
100
+ display: flex;
101
+ gap: var(--spacing-lg);
102
+ }
103
+
104
+ .nav-tab {
105
+ padding: var(--spacing-sm) var(--spacing-md);
106
+ text-decoration: none;
107
+ color: var(--gray-600);
108
+ font-weight: 500;
109
+ border-radius: var(--radius-md);
110
+ transition: all 0.2s ease;
111
+ }
112
+
113
+ .nav-tab:hover {
114
+ color: var(--primary-blue);
115
+ background-color: var(--gray-100);
116
+ }
117
+
118
+ .nav-tab.active {
119
+ color: var(--primary-blue);
120
+ background-color: var(--gray-100);
121
+ }
122
+
123
+ /* Main Content */
124
+ .main {
125
+ flex: 1;
126
+ padding: var(--spacing-xl) 0;
127
+ }
128
+
129
+ /* Footer */
130
+ .footer {
131
+ background: white;
132
+ border-top: 1px solid var(--gray-200);
133
+ padding: var(--spacing-lg) 0;
134
+ margin-top: auto;
135
+ }
136
+
137
+ .footer p {
138
+ text-align: center;
139
+ color: var(--gray-500);
140
+ font-size: 0.875rem;
141
+ }
142
+
143
+ /* Typography */
144
+ h1 {
145
+ font-size: 2rem;
146
+ font-weight: 600;
147
+ color: var(--gray-900);
148
+ margin-bottom: var(--spacing-lg);
149
+ }
150
+
151
+ h2 {
152
+ font-size: 1.5rem;
153
+ font-weight: 500;
154
+ color: var(--gray-900);
155
+ margin-bottom: var(--spacing-md);
156
+ }
157
+
158
+ h3 {
159
+ font-size: 1.25rem;
160
+ font-weight: 500;
161
+ color: var(--gray-900);
162
+ margin-bottom: var(--spacing-sm);
163
+ }
164
+
165
+ /* Cards */
166
+ .card {
167
+ background: white;
168
+ border: 1px solid var(--gray-200);
169
+ border-radius: var(--radius-lg);
170
+ box-shadow: var(--shadow-sm);
171
+ overflow: hidden;
172
+ }
173
+
174
+ .card-header {
175
+ padding: var(--spacing-lg);
176
+ border-bottom: 1px solid var(--gray-200);
177
+ background: var(--gray-50);
178
+ }
179
+
180
+ .card-body {
181
+ padding: var(--spacing-lg);
182
+ }
183
+
184
+ .card-title {
185
+ font-size: 1.125rem;
186
+ font-weight: 600;
187
+ color: var(--gray-900);
188
+ margin: 0;
189
+ }
190
+
191
+ /* Buttons */
192
+ .btn {
193
+ display: inline-flex;
194
+ align-items: center;
195
+ justify-content: center;
196
+ gap: var(--spacing-sm);
197
+ padding: 12px 24px;
198
+ font-size: 1rem;
199
+ font-weight: 500;
200
+ text-decoration: none;
201
+ border: none;
202
+ border-radius: var(--radius-md);
203
+ cursor: pointer;
204
+ transition: all 0.2s ease;
205
+ min-height: 44px;
206
+ }
207
+
208
+ .btn-primary {
209
+ background: var(--primary-blue);
210
+ color: white;
211
+ }
212
+
213
+ .btn-primary:hover {
214
+ background: #1d4ed8;
215
+ transform: translateY(-1px);
216
+ box-shadow: var(--shadow-md);
217
+ }
218
+
219
+ .btn-primary:disabled {
220
+ background: var(--gray-300);
221
+ cursor: not-allowed;
222
+ transform: none;
223
+ box-shadow: none;
224
+ }
225
+
226
+ .btn-secondary {
227
+ background: white;
228
+ color: var(--gray-700);
229
+ border: 1px solid var(--gray-300);
230
+ }
231
+
232
+ .btn-secondary:hover {
233
+ background: var(--gray-50);
234
+ border-color: var(--gray-400);
235
+ }
236
+
237
+ /* Loading Spinner */
238
+ .spinner {
239
+ width: 20px;
240
+ height: 20px;
241
+ border: 2px solid transparent;
242
+ border-top: 2px solid currentColor;
243
+ border-radius: 50%;
244
+ animation: spin 1s linear infinite;
245
+ }
246
+
247
+ @keyframes spin {
248
+ to {
249
+ transform: rotate(360deg);
250
+ }
251
+ }
252
+
253
+ /* Responsive Design */
254
+ @media (max-width: 768px) {
255
+ .container {
256
+ padding: 0 var(--spacing-sm);
257
+ }
258
+
259
+ .header .container {
260
+ flex-direction: column;
261
+ gap: var(--spacing-md);
262
+ }
263
+
264
+ .nav-tabs {
265
+ gap: var(--spacing-md);
266
+ }
267
+
268
+ h1 {
269
+ font-size: 1.75rem;
270
+ }
271
+
272
+ .main {
273
+ padding: var(--spacing-lg) 0;
274
+ }
275
+ }
static/js/dashboard.js ADDED
@@ -0,0 +1,250 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Dashboard functionality for Marine Species API
2
+
3
+ class MarineDashboard {
4
+ constructor() {
5
+ this.currentImage = null;
6
+ this.currentImageFile = null;
7
+ this.isProcessing = false;
8
+
9
+ this.initializeElements();
10
+ this.bindEvents();
11
+ this.checkAPIStatus();
12
+ }
13
+
14
+ initializeElements() {
15
+ // Upload elements
16
+ this.uploadArea = document.getElementById('uploadArea');
17
+ this.fileInput = document.getElementById('fileInput');
18
+ this.identifyBtn = document.getElementById('identifyBtn');
19
+
20
+ // Settings elements
21
+ this.confidenceSlider = document.getElementById('confidenceSlider');
22
+ this.confidenceValue = document.getElementById('confidenceValue');
23
+ this.iouSlider = document.getElementById('iouSlider');
24
+ this.iouValue = document.getElementById('iouValue');
25
+
26
+ // Display elements
27
+ this.originalImageContainer = document.getElementById('originalImageContainer');
28
+ this.annotatedImageContainer = document.getElementById('annotatedImageContainer');
29
+
30
+ // Results elements
31
+ this.metadataSection = document.getElementById('metadataSection');
32
+ this.speciesSection = document.getElementById('speciesSection');
33
+ this.processingTime = document.getElementById('processingTime');
34
+ this.speciesCount = document.getElementById('speciesCount');
35
+ this.imageSize = document.getElementById('imageSize');
36
+ this.speciesList = document.getElementById('speciesList');
37
+
38
+ // Status elements
39
+ this.statusDot = document.getElementById('statusDot');
40
+ this.statusText = document.getElementById('statusText');
41
+ this.modelInfo = document.getElementById('modelInfo');
42
+ }
43
+
44
+ bindEvents() {
45
+ // Upload area events
46
+ this.uploadArea.addEventListener('click', () => this.fileInput.click());
47
+ this.uploadArea.addEventListener('dragover', this.handleDragOver.bind(this));
48
+ this.uploadArea.addEventListener('dragleave', this.handleDragLeave.bind(this));
49
+ this.uploadArea.addEventListener('drop', this.handleDrop.bind(this));
50
+
51
+ // File input change
52
+ this.fileInput.addEventListener('change', this.handleFileSelect.bind(this));
53
+
54
+ // Settings sliders
55
+ this.confidenceSlider.addEventListener('input', this.updateConfidenceValue.bind(this));
56
+ this.iouSlider.addEventListener('input', this.updateIouValue.bind(this));
57
+
58
+ // Identify button
59
+ this.identifyBtn.addEventListener('click', this.identifySpecies.bind(this));
60
+ }
61
+
62
+ // API Status Check
63
+ async checkAPIStatus() {
64
+ try {
65
+ const response = await fetch('/api/v1/health');
66
+ const data = await response.json();
67
+
68
+ if (data.model_loaded) {
69
+ this.statusDot.className = 'status-dot healthy';
70
+ this.statusText.textContent = 'API Ready';
71
+
72
+ if (data.model_info) {
73
+ this.modelInfo.textContent = `Model: ${data.model_info.model_name} (${data.model_info.total_classes} species)`;
74
+ }
75
+ } else {
76
+ this.statusDot.className = 'status-dot error';
77
+ this.statusText.textContent = 'Model Loading...';
78
+ this.modelInfo.textContent = 'Please wait while the model loads';
79
+ }
80
+ } catch (error) {
81
+ this.statusDot.className = 'status-dot error';
82
+ this.statusText.textContent = 'API Unavailable';
83
+ this.modelInfo.textContent = 'Unable to connect to API';
84
+ console.error('API status check failed:', error);
85
+ }
86
+ }
87
+
88
+ // Drag and Drop Handlers
89
+ handleDragOver(e) {
90
+ e.preventDefault();
91
+ this.uploadArea.classList.add('dragover');
92
+ }
93
+
94
+ handleDragLeave(e) {
95
+ e.preventDefault();
96
+ this.uploadArea.classList.remove('dragover');
97
+ }
98
+
99
+ handleDrop(e) {
100
+ e.preventDefault();
101
+ this.uploadArea.classList.remove('dragover');
102
+
103
+ const files = e.dataTransfer.files;
104
+ if (files.length > 0) {
105
+ this.processFile(files[0]);
106
+ }
107
+ }
108
+
109
+ // File Selection Handler
110
+ handleFileSelect(e) {
111
+ const file = e.target.files[0];
112
+ if (file) {
113
+ this.processFile(file);
114
+ }
115
+ }
116
+
117
+ // Process Selected File
118
+ processFile(file) {
119
+ // Validate file type
120
+ if (!file.type.startsWith('image/')) {
121
+ window.MarineAPI.utils.showNotification('Please select an image file', 'error');
122
+ return;
123
+ }
124
+
125
+ // Validate file size (10MB limit)
126
+ if (file.size > 10 * 1024 * 1024) {
127
+ window.MarineAPI.utils.showNotification('File size must be less than 10MB', 'error');
128
+ return;
129
+ }
130
+
131
+ this.currentImageFile = file;
132
+ this.displayOriginalImage(file);
133
+ this.identifyBtn.disabled = false;
134
+
135
+ // Update upload area
136
+ this.uploadArea.classList.add('has-image');
137
+ this.uploadArea.innerHTML = `
138
+ <div class="upload-content">
139
+ <div class="upload-icon">βœ…</div>
140
+ <div class="upload-text">
141
+ <p class="upload-primary">${file.name}</p>
142
+ <p class="upload-secondary">${window.MarineAPI.utils.formatFileSize(file.size)}</p>
143
+ </div>
144
+ </div>
145
+ `;
146
+ }
147
+
148
+ // Display Original Image
149
+ displayOriginalImage(file) {
150
+ const reader = new FileReader();
151
+ reader.onload = (e) => {
152
+ this.currentImage = e.target.result;
153
+ this.originalImageContainer.innerHTML = `
154
+ <img src="${e.target.result}" alt="Original image" />
155
+ `;
156
+ };
157
+ reader.readAsDataURL(file);
158
+ }
159
+
160
+ // Settings Handlers
161
+ updateConfidenceValue() {
162
+ this.confidenceValue.textContent = `${this.confidenceSlider.value}%`;
163
+ }
164
+
165
+ updateIouValue() {
166
+ this.iouValue.textContent = `${this.iouSlider.value}%`;
167
+ }
168
+
169
+ // Main Identification Function
170
+ async identifySpecies() {
171
+ if (!this.currentImage || this.isProcessing) return;
172
+
173
+ this.isProcessing = true;
174
+ window.MarineAPI.utils.setLoading(this.identifyBtn, true);
175
+
176
+ try {
177
+ // Prepare request data
178
+ const requestData = {
179
+ image: this.currentImage.split(',')[1], // Remove data:image/jpeg;base64, prefix
180
+ confidence_threshold: this.confidenceSlider.value / 100,
181
+ iou_threshold: this.iouSlider.value / 100,
182
+ image_size: 640,
183
+ return_annotated_image: true
184
+ };
185
+
186
+ // Make API request
187
+ const response = await fetch('/api/v1/detect', {
188
+ method: 'POST',
189
+ headers: {
190
+ 'Content-Type': 'application/json',
191
+ },
192
+ body: JSON.stringify(requestData)
193
+ });
194
+
195
+ if (!response.ok) {
196
+ throw new Error(`API request failed: ${response.status}`);
197
+ }
198
+
199
+ const result = await response.json();
200
+ this.displayResults(result);
201
+ window.MarineAPI.utils.showNotification('Species identification completed!', 'success');
202
+
203
+ } catch (error) {
204
+ console.error('Identification failed:', error);
205
+ window.MarineAPI.utils.showNotification('Identification failed. Please try again.', 'error');
206
+ } finally {
207
+ this.isProcessing = false;
208
+ window.MarineAPI.utils.setLoading(this.identifyBtn, false);
209
+ }
210
+ }
211
+
212
+ // Display Results
213
+ displayResults(result) {
214
+ const { detections, annotated_image, processing_time, image_dimensions } = result;
215
+
216
+ // Display annotated image
217
+ if (annotated_image) {
218
+ this.annotatedImageContainer.innerHTML = `
219
+ <img src="data:image/jpeg;base64,${annotated_image}" alt="Annotated results" />
220
+ `;
221
+ }
222
+
223
+ // Update metadata
224
+ this.processingTime.textContent = `${processing_time.toFixed(3)}s`;
225
+ this.speciesCount.textContent = detections.length;
226
+ this.imageSize.textContent = `${image_dimensions.width}Γ—${image_dimensions.height}`;
227
+
228
+ // Show metadata section
229
+ this.metadataSection.style.display = 'block';
230
+
231
+ // Display species list
232
+ if (detections.length > 0) {
233
+ this.speciesList.innerHTML = detections.map(detection => `
234
+ <div class="species-item">
235
+ <span class="species-name">${detection.class_name}</span>
236
+ <span class="species-confidence">${(detection.confidence * 100).toFixed(1)}%</span>
237
+ </div>
238
+ `).join('');
239
+ this.speciesSection.style.display = 'block';
240
+ } else {
241
+ this.speciesList.innerHTML = '<p class="no-detections">No marine species detected. Try adjusting the confidence threshold.</p>';
242
+ this.speciesSection.style.display = 'block';
243
+ }
244
+ }
245
+ }
246
+
247
+ // Initialize dashboard when DOM is loaded
248
+ document.addEventListener('DOMContentLoaded', () => {
249
+ new MarineDashboard();
250
+ });
static/js/main.js ADDED
@@ -0,0 +1,90 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Marine Species API - Main JavaScript
2
+
3
+ // Global state
4
+ window.MarineAPI = {
5
+ baseURL: window.location.origin,
6
+ currentImage: null,
7
+ isProcessing: false
8
+ };
9
+
10
+ // Utility functions
11
+ const utils = {
12
+ // Show/hide loading state
13
+ setLoading: (element, isLoading) => {
14
+ if (isLoading) {
15
+ element.disabled = true;
16
+ element.innerHTML = '<span class="spinner"></span> Processing...';
17
+ } else {
18
+ element.disabled = false;
19
+ element.innerHTML = element.dataset.originalText || 'Identify Marine Life';
20
+ }
21
+ },
22
+
23
+ // Format file size
24
+ formatFileSize: (bytes) => {
25
+ if (bytes === 0) return '0 Bytes';
26
+ const k = 1024;
27
+ const sizes = ['Bytes', 'KB', 'MB', 'GB'];
28
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
29
+ return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
30
+ },
31
+
32
+ // Show notification
33
+ showNotification: (message, type = 'info') => {
34
+ // Simple notification system
35
+ const notification = document.createElement('div');
36
+ notification.className = `notification notification-${type}`;
37
+ notification.textContent = message;
38
+
39
+ // Style the notification
40
+ Object.assign(notification.style, {
41
+ position: 'fixed',
42
+ top: '20px',
43
+ right: '20px',
44
+ padding: '12px 20px',
45
+ borderRadius: '8px',
46
+ color: 'white',
47
+ fontWeight: '500',
48
+ zIndex: '1000',
49
+ transform: 'translateX(100%)',
50
+ transition: 'transform 0.3s ease'
51
+ });
52
+
53
+ // Set background color based on type
54
+ const colors = {
55
+ success: '#059669',
56
+ error: '#dc2626',
57
+ warning: '#d97706',
58
+ info: '#2563eb'
59
+ };
60
+ notification.style.backgroundColor = colors[type] || colors.info;
61
+
62
+ document.body.appendChild(notification);
63
+
64
+ // Animate in
65
+ setTimeout(() => {
66
+ notification.style.transform = 'translateX(0)';
67
+ }, 100);
68
+
69
+ // Remove after 5 seconds
70
+ setTimeout(() => {
71
+ notification.style.transform = 'translateX(100%)';
72
+ setTimeout(() => {
73
+ document.body.removeChild(notification);
74
+ }, 300);
75
+ }, 5000);
76
+ }
77
+ };
78
+
79
+ // Initialize when DOM is loaded
80
+ document.addEventListener('DOMContentLoaded', () => {
81
+ console.log('🐟 Marine Species API Dashboard Loaded');
82
+
83
+ // Store original button text for loading states
84
+ document.querySelectorAll('.btn').forEach(btn => {
85
+ btn.dataset.originalText = btn.textContent;
86
+ });
87
+ });
88
+
89
+ // Export utils for use in other scripts
90
+ window.MarineAPI.utils = utils;
templates/base.html ADDED
@@ -0,0 +1,59 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>{% block title %}Marine Species Identification API{% endblock %}</title>
7
+
8
+ <!-- Inter Font -->
9
+ <link rel="preconnect" href="https://fonts.googleapis.com">
10
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
11
+ <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&display=swap" rel="stylesheet">
12
+
13
+ <!-- Custom CSS -->
14
+ <link rel="stylesheet" href="{{ url_for('static', path='/css/main.css') }}">
15
+
16
+ {% block extra_css %}{% endblock %}
17
+ </head>
18
+ <body>
19
+ <!-- Navigation Header -->
20
+ <header class="header">
21
+ <div class="container">
22
+ <div class="nav-brand">
23
+ <span class="nav-icon">🐟</span>
24
+ <span class="nav-title">Marine Species API</span>
25
+ </div>
26
+
27
+ <nav class="nav-tabs">
28
+ <a href="/" class="nav-tab {% if active_tab == 'dashboard' %}active{% endif %}">
29
+ Dashboard
30
+ </a>
31
+ <a href="/docs" class="nav-tab {% if active_tab == 'docs' %}active{% endif %}">
32
+ API Docs
33
+ </a>
34
+ <a href="/api/v1/info" class="nav-tab" target="_blank">
35
+ API Info
36
+ </a>
37
+ </nav>
38
+ </div>
39
+ </header>
40
+
41
+ <!-- Main Content -->
42
+ <main class="main">
43
+ <div class="container">
44
+ {% block content %}{% endblock %}
45
+ </div>
46
+ </main>
47
+
48
+ <!-- Footer -->
49
+ <footer class="footer">
50
+ <div class="container">
51
+ <p>&copy; 2025 Marine Species Identification API. Powered by YOLOv5.</p>
52
+ </div>
53
+ </footer>
54
+
55
+ <!-- JavaScript -->
56
+ <script src="{{ url_for('static', path='/js/main.js') }}"></script>
57
+ {% block extra_js %}{% endblock %}
58
+ </body>
59
+ </html>
templates/dashboard.html ADDED
@@ -0,0 +1,149 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {% extends "base.html" %}
2
+
3
+ {% block title %}Dashboard - Marine Species Identification API{% endblock %}
4
+
5
+ {% block extra_css %}
6
+ <link rel="stylesheet" href="{{ url_for('static', path='/css/dashboard.css') }}">
7
+ {% endblock %}
8
+
9
+ {% block content %}
10
+ <div class="dashboard">
11
+ <!-- Page Header -->
12
+ <div class="page-header">
13
+ <h1>🌊 Marine Species Identification</h1>
14
+ <p class="page-description">
15
+ Upload an image to identify marine species using our advanced YOLOv5 model.
16
+ Supports 691+ species including fish, corals, sea stars, and more.
17
+ </p>
18
+ </div>
19
+
20
+ <!-- API Status Banner -->
21
+ <div class="status-banner" id="statusBanner">
22
+ <div class="status-indicator">
23
+ <span class="status-dot" id="statusDot"></span>
24
+ <span class="status-text" id="statusText">Checking API status...</span>
25
+ </div>
26
+ <div class="model-info" id="modelInfo"></div>
27
+ </div>
28
+
29
+ <!-- Main Dashboard Grid -->
30
+ <div class="dashboard-grid">
31
+ <!-- Input Panel -->
32
+ <div class="panel input-panel">
33
+ <div class="card">
34
+ <div class="card-header">
35
+ <h3 class="card-title">πŸ“€ Upload Image</h3>
36
+ </div>
37
+ <div class="card-body">
38
+ <!-- Upload Area -->
39
+ <div class="upload-area" id="uploadArea">
40
+ <div class="upload-content">
41
+ <div class="upload-icon">πŸ“·</div>
42
+ <div class="upload-text">
43
+ <p class="upload-primary">Drag image here or click to browse</p>
44
+ <p class="upload-secondary">PNG, JPG, JPEG up to 10MB</p>
45
+ </div>
46
+ </div>
47
+ <input type="file" id="fileInput" accept="image/*" hidden>
48
+ </div>
49
+
50
+ <!-- Settings -->
51
+ <div class="settings-section">
52
+ <h4>βš™οΈ Detection Settings</h4>
53
+ <div class="settings-grid">
54
+ <div class="setting-item">
55
+ <label for="confidenceSlider">Confidence Threshold</label>
56
+ <div class="slider-container">
57
+ <input type="range" id="confidenceSlider" min="0" max="100" value="25">
58
+ <span class="slider-value" id="confidenceValue">25%</span>
59
+ </div>
60
+ </div>
61
+ <div class="setting-item">
62
+ <label for="iouSlider">IoU Threshold</label>
63
+ <div class="slider-container">
64
+ <input type="range" id="iouSlider" min="0" max="100" value="45">
65
+ <span class="slider-value" id="iouValue">45%</span>
66
+ </div>
67
+ </div>
68
+ </div>
69
+ </div>
70
+
71
+ <!-- Action Button -->
72
+ <button class="btn btn-primary btn-full" id="identifyBtn" disabled>
73
+ πŸ” Identify Marine Life
74
+ </button>
75
+ </div>
76
+ </div>
77
+ </div>
78
+
79
+ <!-- Original Image Panel -->
80
+ <div class="panel image-panel">
81
+ <div class="card">
82
+ <div class="card-header">
83
+ <h3 class="card-title">πŸ–ΌοΈ Original Image</h3>
84
+ </div>
85
+ <div class="card-body">
86
+ <div class="image-container" id="originalImageContainer">
87
+ <div class="image-placeholder">
88
+ <div class="placeholder-icon">πŸ–ΌοΈ</div>
89
+ <p>Upload an image to see it here</p>
90
+ </div>
91
+ </div>
92
+ </div>
93
+ </div>
94
+ </div>
95
+
96
+ <!-- Results Panel -->
97
+ <div class="panel results-panel">
98
+ <div class="card">
99
+ <div class="card-header">
100
+ <h3 class="card-title">🎯 Detection Results</h3>
101
+ </div>
102
+ <div class="card-body">
103
+ <!-- Annotated Image -->
104
+ <div class="annotated-section">
105
+ <h4>Annotated Image</h4>
106
+ <div class="image-container" id="annotatedImageContainer">
107
+ <div class="image-placeholder">
108
+ <div class="placeholder-icon">πŸ”</div>
109
+ <p>Annotated results will appear here</p>
110
+ </div>
111
+ </div>
112
+ </div>
113
+
114
+ <!-- Detection Metadata -->
115
+ <div class="metadata-section" id="metadataSection" style="display: none;">
116
+ <h4>Detection Summary</h4>
117
+ <div class="metadata-grid">
118
+ <div class="metadata-item">
119
+ <span class="metadata-label">Processing Time</span>
120
+ <span class="metadata-value" id="processingTime">-</span>
121
+ </div>
122
+ <div class="metadata-item">
123
+ <span class="metadata-label">Species Found</span>
124
+ <span class="metadata-value" id="speciesCount">-</span>
125
+ </div>
126
+ <div class="metadata-item">
127
+ <span class="metadata-label">Image Size</span>
128
+ <span class="metadata-value" id="imageSize">-</span>
129
+ </div>
130
+ </div>
131
+ </div>
132
+
133
+ <!-- Species List -->
134
+ <div class="species-section" id="speciesSection" style="display: none;">
135
+ <h4>Detected Species</h4>
136
+ <div class="species-list" id="speciesList">
137
+ <!-- Species items will be populated here -->
138
+ </div>
139
+ </div>
140
+ </div>
141
+ </div>
142
+ </div>
143
+ </div>
144
+ </div>
145
+ {% endblock %}
146
+
147
+ {% block extra_js %}
148
+ <script src="{{ url_for('static', path='/js/dashboard.js') }}"></script>
149
+ {% endblock %}