Apiarist Dev commited on
Commit Β·
686d2ed
1
Parent(s): 87f44ca
polish: seed sample hives, polished CSS theme, rich About + README, dataset live on Hub
Browse files- README.md +48 -8
- app.py +97 -11
- scripts/push_yolo_to_hub.py +179 -0
README.md
CHANGED
|
@@ -7,19 +7,59 @@ sdk: gradio
|
|
| 7 |
sdk_version: 6.16.0
|
| 8 |
python_version: '3.12'
|
| 9 |
app_file: app.py
|
| 10 |
-
pinned:
|
| 11 |
-
license:
|
| 12 |
short_description: Offline AI inspector for honeybee hive frames
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 13 |
---
|
| 14 |
|
| 15 |
# π Apiarist
|
| 16 |
|
| 17 |
-
|
|
|
|
| 18 |
|
| 19 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 20 |
|
| 21 |
## Stack
|
| 22 |
-
|
| 23 |
-
-
|
| 24 |
-
-
|
| 25 |
-
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 7 |
sdk_version: 6.16.0
|
| 8 |
python_version: '3.12'
|
| 9 |
app_file: app.py
|
| 10 |
+
pinned: true
|
| 11 |
+
license: apache-2.0
|
| 12 |
short_description: Offline AI inspector for honeybee hive frames
|
| 13 |
+
tags:
|
| 14 |
+
- beekeeping
|
| 15 |
+
- object-detection
|
| 16 |
+
- vision-language-model
|
| 17 |
+
- small-models
|
| 18 |
+
- zerogpu
|
| 19 |
+
models:
|
| 20 |
+
- Qwen/Qwen2.5-VL-3B-Instruct
|
| 21 |
+
- maryammeda/apiarist-honey-bee-detector
|
| 22 |
+
datasets:
|
| 23 |
+
- maryammeda/apiarist-inaturalist-bees
|
| 24 |
---
|
| 25 |
|
| 26 |
# π Apiarist
|
| 27 |
|
| 28 |
+
A fully-offline AI hive frame inspector for backyard beekeepers. Built
|
| 29 |
+
in 10 days for the [Build Small Hackathon](https://huggingface.co/build-small-hackathon).
|
| 30 |
|
| 31 |
+
## What it does
|
| 32 |
+
|
| 33 |
+
Point a phone at any honeycomb frame, get back:
|
| 34 |
+
|
| 35 |
+
- bee / drone / queen / varroa-mite detections with bounding boxes
|
| 36 |
+
- a narrative inspection report
|
| 37 |
+
- auto-saved to a per-hive registry
|
| 38 |
+
- weekly PDF report on demand
|
| 39 |
+
|
| 40 |
+
All local. No cloud APIs at inference.
|
| 41 |
+
|
| 42 |
+
## Architecture
|
| 43 |
+
|
| 44 |
+
| Layer | Model | Job |
|
| 45 |
+
|---|---|---|
|
| 46 |
+
| Specialist | [Custom YOLOv8s](https://huggingface.co/maryammeda/apiarist-honey-bee-detector) (22 MB) | Detects + counts bees, drones, queens, varroa mites |
|
| 47 |
+
| Generalist | [Qwen2.5-VL-3B-Instruct](https://huggingface.co/Qwen/Qwen2.5-VL-3B-Instruct) | Writes the narrative inspection report |
|
| 48 |
+
| Persistence | SQLite | Hive registry + inspection history |
|
| 49 |
+
| Reports | ReportLab | Weekly PDF generation |
|
| 50 |
|
| 51 |
## Stack
|
| 52 |
+
|
| 53 |
+
- π€ [Hugging Face Spaces](https://huggingface.co/spaces) on ZeroGPU
|
| 54 |
+
- π¨ [Gradio](https://gradio.app) with a custom field-tool theme
|
| 55 |
+
- β‘ [Modal](https://modal.com) for fine-tuning the YOLO (1Γ T4, 60 epochs)
|
| 56 |
+
- π Training data: [Hendricks Ricky bee-project](https://universe.roboflow.com/hendricks_ricky-hotmail-de/bee-project) (3,308 imgs, 892 queens)
|
| 57 |
+
- πΏ Context imagery: [Apiarist iNaturalist bees dataset](https://huggingface.co/datasets/maryammeda/apiarist-inaturalist-bees)
|
| 58 |
+
|
| 59 |
+
## Badges chased
|
| 60 |
+
|
| 61 |
+
π Off the Grid Β· π― Well-Tuned Β· π¨ Off-Brand Β· π‘ Sharing is Caring Β· π Field Notes
|
| 62 |
+
|
| 63 |
+
## License
|
| 64 |
+
|
| 65 |
+
Apache 2.0
|
app.py
CHANGED
|
@@ -410,23 +410,72 @@ def view_hive_history(hive_name):
|
|
| 410 |
|
| 411 |
custom_css = """
|
| 412 |
.gradio-container {
|
| 413 |
-
background: #1a1410 !important;
|
| 414 |
color: #f4e4bc !important;
|
| 415 |
-
font-family: 'Courier New', monospace !important;
|
|
|
|
|
|
|
| 416 |
}
|
| 417 |
-
h1
|
| 418 |
-
|
| 419 |
-
|
|
|
|
|
|
|
|
|
|
| 420 |
color: #1a1410 !important;
|
| 421 |
font-weight: bold !important;
|
| 422 |
border: none !important;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 423 |
}
|
| 424 |
-
.gr-box, .block { border-color: #f4a300 !important; }
|
| 425 |
"""
|
| 426 |
|
| 427 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 428 |
def build_ui() -> gr.Blocks:
|
| 429 |
db.init_db()
|
|
|
|
| 430 |
|
| 431 |
with gr.Blocks(title="Apiarist - Hive Frame Inspector") as app:
|
| 432 |
gr.Markdown("# π APIARIST")
|
|
@@ -557,13 +606,50 @@ def build_ui() -> gr.Blocks:
|
|
| 557 |
with gr.Tab("βΉοΈ About"):
|
| 558 |
gr.Markdown(
|
| 559 |
"""
|
| 560 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 561 |
|
| 562 |
-
|
| 563 |
-
- π― Custom-trained on labeled bee imagery
|
| 564 |
-
- π Built in 10 days for the [Build Small Hackathon](https://huggingface.co/build-small-hackathon)
|
| 565 |
|
| 566 |
-
|
| 567 |
"""
|
| 568 |
)
|
| 569 |
|
|
|
|
| 410 |
|
| 411 |
custom_css = """
|
| 412 |
.gradio-container {
|
| 413 |
+
background: linear-gradient(180deg, #1a1410 0%, #2a1f15 100%) !important;
|
| 414 |
color: #f4e4bc !important;
|
| 415 |
+
font-family: 'JetBrains Mono', 'Courier New', monospace !important;
|
| 416 |
+
max-width: 1400px !important;
|
| 417 |
+
margin: 0 auto !important;
|
| 418 |
}
|
| 419 |
+
h1 { color: #f4a300 !important; letter-spacing: 0.05em; }
|
| 420 |
+
h2, h3 { color: #f4a300 !important; }
|
| 421 |
+
h4 { color: #ffd066 !important; }
|
| 422 |
+
button.primary,
|
| 423 |
+
button[variant="primary"] {
|
| 424 |
+
background: linear-gradient(180deg, #ffb733 0%, #f4a300 100%) !important;
|
| 425 |
color: #1a1410 !important;
|
| 426 |
font-weight: bold !important;
|
| 427 |
border: none !important;
|
| 428 |
+
box-shadow: 0 2px 8px rgba(244, 163, 0, 0.25) !important;
|
| 429 |
+
transition: transform 80ms ease, box-shadow 200ms ease !important;
|
| 430 |
+
}
|
| 431 |
+
button.primary:hover {
|
| 432 |
+
transform: translateY(-1px);
|
| 433 |
+
box-shadow: 0 4px 14px rgba(244, 163, 0, 0.40) !important;
|
| 434 |
+
}
|
| 435 |
+
.gr-box, .block, .gradio-container .block {
|
| 436 |
+
border-color: rgba(244, 163, 0, 0.35) !important;
|
| 437 |
+
background: rgba(42, 31, 21, 0.4) !important;
|
| 438 |
+
}
|
| 439 |
+
.tabs > .tab-nav > button.selected {
|
| 440 |
+
color: #f4a300 !important;
|
| 441 |
+
border-bottom: 2px solid #f4a300 !important;
|
| 442 |
+
}
|
| 443 |
+
.gradio-container a {
|
| 444 |
+
color: #ffd066 !important;
|
| 445 |
+
}
|
| 446 |
+
.gradio-container a:hover {
|
| 447 |
+
color: #ffe599 !important;
|
| 448 |
+
text-decoration: underline;
|
| 449 |
+
}
|
| 450 |
+
table {
|
| 451 |
+
border-color: rgba(244, 163, 0, 0.25) !important;
|
| 452 |
}
|
|
|
|
| 453 |
"""
|
| 454 |
|
| 455 |
|
| 456 |
+
def _seed_sample_data():
|
| 457 |
+
"""Drop a handful of plausible hives into the DB on first boot
|
| 458 |
+
so the Hives tab isn't empty for first-visit judges."""
|
| 459 |
+
if db.list_hives():
|
| 460 |
+
return # someone already has data
|
| 461 |
+
samples = [
|
| 462 |
+
("Hive #1 β Apricot tree", "South corner of yard", "yellow",
|
| 463 |
+
"Italian queen, marked yellow"),
|
| 464 |
+
("Hive #2 β Cedar fence", "East side, near cedar", "red",
|
| 465 |
+
"2024 queen, watch for supersedure cells"),
|
| 466 |
+
("Hive #3 β Vegetable garden", "By the tomato beds", "white",
|
| 467 |
+
"Newly split from Hive #1 in May"),
|
| 468 |
+
]
|
| 469 |
+
for name, loc, marker, notes in samples:
|
| 470 |
+
try:
|
| 471 |
+
db.add_hive(name, loc, marker, notes)
|
| 472 |
+
except Exception:
|
| 473 |
+
pass
|
| 474 |
+
|
| 475 |
+
|
| 476 |
def build_ui() -> gr.Blocks:
|
| 477 |
db.init_db()
|
| 478 |
+
_seed_sample_data()
|
| 479 |
|
| 480 |
with gr.Blocks(title="Apiarist - Hive Frame Inspector") as app:
|
| 481 |
gr.Markdown("# π APIARIST")
|
|
|
|
| 606 |
with gr.Tab("βΉοΈ About"):
|
| 607 |
gr.Markdown(
|
| 608 |
"""
|
| 609 |
+
## π Apiarist
|
| 610 |
+
|
| 611 |
+
An offline AI hive frame inspector for backyard beekeepers. Built in
|
| 612 |
+
10 days for the [Build Small Hackathon](https://huggingface.co/build-small-hackathon).
|
| 613 |
+
|
| 614 |
+
### The problem
|
| 615 |
+
|
| 616 |
+
Frank β a beekeeper down the road β keeps 14 hives and inspects each
|
| 617 |
+
weekend by hand. Last summer he lost four colonies to queen failures
|
| 618 |
+
he didn't spot in time. Apiarist is the assistant he should have had:
|
| 619 |
+
fast, focused, runs on a laptop in a field, never sends his hive data
|
| 620 |
+
anywhere.
|
| 621 |
+
|
| 622 |
+
### How it works
|
| 623 |
+
|
| 624 |
+
Two models, two jobs:
|
| 625 |
+
|
| 626 |
+
- **YOLOv8s, custom-trained** (22 MB) β finds bees, drones, queens, and
|
| 627 |
+
varroa mites with bounding boxes. CPU-fast.
|
| 628 |
+
- **Qwen2.5-VL-3B-Instruct** β takes the image + YOLO detection counts
|
| 629 |
+
and writes a narrative inspection report. Runs on ZeroGPU.
|
| 630 |
+
|
| 631 |
+
Together: structured detection + narrative report in ~5 seconds, no
|
| 632 |
+
internet required.
|
| 633 |
+
|
| 634 |
+
### What's in the box
|
| 635 |
+
|
| 636 |
+
- π **Inspect** β upload a frame, get an annotated image + report
|
| 637 |
+
- π **Hives** β registry, per-hive inspection history, weekly PDF reports
|
| 638 |
+
- βοΈ **Compare** β Apiarist vs raw generalist VLM, side-by-side
|
| 639 |
+
- π SQLite persistence for the whole apiary
|
| 640 |
+
|
| 641 |
+
### Stack
|
| 642 |
+
|
| 643 |
+
- Vision-language model: [Qwen2.5-VL-3B-Instruct](https://huggingface.co/Qwen/Qwen2.5-VL-3B-Instruct)
|
| 644 |
+
- Specialist detector: [Apiarist Honey-Bee Detector (custom YOLOv8s)](https://huggingface.co/maryammeda/apiarist-honey-bee-detector)
|
| 645 |
+
- Training data: [Hendricks Ricky bee-project](https://universe.roboflow.com/hendricks_ricky-hotmail-de/bee-project) on Roboflow Universe (3,308 labeled images, 892 queens)
|
| 646 |
+
- Bee imagery: [Apiarist iNaturalist bees dataset](https://huggingface.co/datasets/maryammeda/apiarist-inaturalist-bees)
|
| 647 |
+
- Compute: Modal (training), Hugging Face ZeroGPU (inference)
|
| 648 |
+
- Frontend: Gradio with custom field-tool theme
|
| 649 |
|
| 650 |
+
### Badges chased
|
|
|
|
|
|
|
| 651 |
|
| 652 |
+
π Off the Grid Β· π― Well-Tuned Β· π¨ Off-Brand Β· π‘ Sharing is Caring Β· π Field Notes
|
| 653 |
"""
|
| 654 |
)
|
| 655 |
|
scripts/push_yolo_to_hub.py
ADDED
|
@@ -0,0 +1,179 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Push the trained YOLOv8s honey-bee detector to a Hugging Face model repo.
|
| 3 |
+
|
| 4 |
+
Earns the "Sharing is Caring" badge. Re-run any time the local
|
| 5 |
+
weights/honey_bee_detector.pt is updated.
|
| 6 |
+
|
| 7 |
+
Usage:
|
| 8 |
+
py scripts/push_yolo_to_hub.py --repo-id maryammeda/apiarist-honey-bee-detector
|
| 9 |
+
"""
|
| 10 |
+
|
| 11 |
+
from __future__ import annotations
|
| 12 |
+
|
| 13 |
+
import argparse
|
| 14 |
+
import os
|
| 15 |
+
from pathlib import Path
|
| 16 |
+
|
| 17 |
+
from dotenv import load_dotenv
|
| 18 |
+
from huggingface_hub import HfApi
|
| 19 |
+
|
| 20 |
+
|
| 21 |
+
WEIGHTS_PATH = Path(__file__).parent.parent / "weights" / "honey_bee_detector.pt"
|
| 22 |
+
|
| 23 |
+
|
| 24 |
+
README_TEMPLATE = """---
|
| 25 |
+
license: apache-2.0
|
| 26 |
+
library_name: ultralytics
|
| 27 |
+
tags:
|
| 28 |
+
- yolo
|
| 29 |
+
- yolov8
|
| 30 |
+
- object-detection
|
| 31 |
+
- bees
|
| 32 |
+
- beekeeping
|
| 33 |
+
- computer-vision
|
| 34 |
+
pipeline_tag: object-detection
|
| 35 |
+
---
|
| 36 |
+
|
| 37 |
+
# Apiarist Honey-Bee Detector (YOLOv8s)
|
| 38 |
+
|
| 39 |
+
A custom-trained **YOLOv8s** specialist detector for honeycomb frame
|
| 40 |
+
inspection. Built as part of [Apiarist](https://huggingface.co/spaces/build-small-hackathon/Apiarist) β a fully-offline AI hive inspector for
|
| 41 |
+
backyard beekeepers, made for the
|
| 42 |
+
[Build Small Hackathon](https://huggingface.co/build-small-hackathon).
|
| 43 |
+
|
| 44 |
+
## Classes
|
| 45 |
+
|
| 46 |
+
Trained on the [hendricks_ricky bee-project](https://universe.roboflow.com/hendricks_ricky-hotmail-de/bee-project) dataset
|
| 47 |
+
(3,308 labeled images, including 892 queen-bee examples). Four classes:
|
| 48 |
+
|
| 49 |
+
- `Queen` β queen bee (larger, elongated abdomen)
|
| 50 |
+
- `Worker` β worker / forager bees (the majority class)
|
| 51 |
+
- `Drone` β male / drone bees
|
| 52 |
+
- `Varroa` β varroa destructor mites visible on bees or comb
|
| 53 |
+
|
| 54 |
+
## Usage
|
| 55 |
+
|
| 56 |
+
```python
|
| 57 |
+
from ultralytics import YOLO
|
| 58 |
+
from PIL import Image
|
| 59 |
+
|
| 60 |
+
model = YOLO("honey_bee_detector.pt")
|
| 61 |
+
results = model(Image.open("hive_frame.jpg"), conf=0.10, device="cpu")
|
| 62 |
+
for box in results[0].boxes:
|
| 63 |
+
cls = model.names[int(box.cls.item())]
|
| 64 |
+
conf = float(box.conf.item())
|
| 65 |
+
print(f"{cls}: {conf:.0%}")
|
| 66 |
+
```
|
| 67 |
+
|
| 68 |
+
Recommended per-class confidence thresholds (tuned empirically on real
|
| 69 |
+
frame photos):
|
| 70 |
+
|
| 71 |
+
```python
|
| 72 |
+
PER_CLASS_CONF = {
|
| 73 |
+
"Worker": 0.25,
|
| 74 |
+
"Drone": 0.55, # higher β drones false-positive on fingers, shadows
|
| 75 |
+
"Varroa": 0.30, # mites are small
|
| 76 |
+
"Queen": 0.15, # lower β try harder to find her
|
| 77 |
+
}
|
| 78 |
+
```
|
| 79 |
+
|
| 80 |
+
## Training
|
| 81 |
+
|
| 82 |
+
- Base weights: `yolov8s.pt`
|
| 83 |
+
- Epochs: 60
|
| 84 |
+
- Image size: 640Γ640
|
| 85 |
+
- Batch size: 32
|
| 86 |
+
- Hardware: 1Γ NVIDIA T4 (Modal)
|
| 87 |
+
- Cost: ~$0.40 of free hackathon credit
|
| 88 |
+
|
| 89 |
+
## Limitations
|
| 90 |
+
|
| 91 |
+
The training set includes ~892 queen images, which is far more than the
|
| 92 |
+
typical bee-detection dataset but still limited compared to the
|
| 93 |
+
millions of bees in worker class. Queen detection precision is
|
| 94 |
+
moderate β when the model labels a queen, verify visually. Use as a
|
| 95 |
+
**candidate flag**, not as ground truth.
|
| 96 |
+
|
| 97 |
+
Varroa mite detection works on close-up frames where mites are visible
|
| 98 |
+
on the dorsal side of bees or in cells, but will miss mites hidden
|
| 99 |
+
under abdomens.
|
| 100 |
+
|
| 101 |
+
## License
|
| 102 |
+
|
| 103 |
+
Apache 2.0. Trained on data released under CC BY 4.0 by the original
|
| 104 |
+
dataset authors.
|
| 105 |
+
|
| 106 |
+
## Citation
|
| 107 |
+
|
| 108 |
+
If you use this model, please credit:
|
| 109 |
+
- This work: Apiarist (Build Small Hackathon entry, 2026)
|
| 110 |
+
- Training data: hendricks_ricky/bee-project, Roboflow Universe
|
| 111 |
+
"""
|
| 112 |
+
|
| 113 |
+
|
| 114 |
+
def main() -> None:
|
| 115 |
+
parser = argparse.ArgumentParser()
|
| 116 |
+
parser.add_argument(
|
| 117 |
+
"--repo-id",
|
| 118 |
+
required=True,
|
| 119 |
+
help="Target HF repo, e.g. 'maryammeda/apiarist-honey-bee-detector'",
|
| 120 |
+
)
|
| 121 |
+
parser.add_argument(
|
| 122 |
+
"--private",
|
| 123 |
+
action="store_true",
|
| 124 |
+
help="Create repo as private (default public)",
|
| 125 |
+
)
|
| 126 |
+
args = parser.parse_args()
|
| 127 |
+
|
| 128 |
+
load_dotenv()
|
| 129 |
+
token = (
|
| 130 |
+
os.environ.get("HF_TOKEN")
|
| 131 |
+
or os.environ.get("HUGGING_FACE_HUB_TOKEN")
|
| 132 |
+
)
|
| 133 |
+
if not token:
|
| 134 |
+
raise SystemExit(
|
| 135 |
+
"Need HF_TOKEN in .env. Get one at "
|
| 136 |
+
"https://huggingface.co/settings/tokens (write scope)."
|
| 137 |
+
)
|
| 138 |
+
|
| 139 |
+
if not WEIGHTS_PATH.exists():
|
| 140 |
+
raise SystemExit(f"Weights not found at {WEIGHTS_PATH}")
|
| 141 |
+
|
| 142 |
+
print(f"Weights: {WEIGHTS_PATH} ({WEIGHTS_PATH.stat().st_size / 1024 / 1024:.1f} MB)")
|
| 143 |
+
|
| 144 |
+
api = HfApi(token=token)
|
| 145 |
+
print(f"Creating model repo {args.repo_id} ...")
|
| 146 |
+
api.create_repo(
|
| 147 |
+
repo_id=args.repo_id,
|
| 148 |
+
repo_type="model",
|
| 149 |
+
private=args.private,
|
| 150 |
+
exist_ok=True,
|
| 151 |
+
)
|
| 152 |
+
|
| 153 |
+
# Write a model card README
|
| 154 |
+
print("Uploading README ...")
|
| 155 |
+
api.upload_file(
|
| 156 |
+
path_or_fileobj=README_TEMPLATE.encode("utf-8"),
|
| 157 |
+
path_in_repo="README.md",
|
| 158 |
+
repo_id=args.repo_id,
|
| 159 |
+
repo_type="model",
|
| 160 |
+
commit_message="Add model card",
|
| 161 |
+
)
|
| 162 |
+
|
| 163 |
+
print(f"Uploading {WEIGHTS_PATH.name} ...")
|
| 164 |
+
api.upload_file(
|
| 165 |
+
path_or_fileobj=str(WEIGHTS_PATH),
|
| 166 |
+
path_in_repo="honey_bee_detector.pt",
|
| 167 |
+
repo_id=args.repo_id,
|
| 168 |
+
repo_type="model",
|
| 169 |
+
commit_message="Upload YOLOv8s honey-bee detector weights",
|
| 170 |
+
)
|
| 171 |
+
|
| 172 |
+
print(
|
| 173 |
+
f"\n[OK] Model live at: "
|
| 174 |
+
f"https://huggingface.co/{args.repo_id}"
|
| 175 |
+
)
|
| 176 |
+
|
| 177 |
+
|
| 178 |
+
if __name__ == "__main__":
|
| 179 |
+
main()
|