Spaces:
Sleeping
Sleeping
deploy at 2025-05-13 17:11:52.021690
Browse files- .gitattributes +1 -0
- Dockerfile +10 -0
- README.md +8 -9
- bl-pred.png +0 -0
- black.jpg +0 -0
- chocolate.jpg +0 -0
- cl-pred.png +0 -0
- drop.jpg +0 -0
- export.pkl +3 -0
- lab-logo.png +0 -0
- logo-white.png +3 -0
- main.py +280 -0
- requirements.txt +8 -0
- yellow.jpg +0 -0
- yl-pred.png +0 -0
.gitattributes
CHANGED
|
@@ -33,3 +33,4 @@ 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 |
+
logo-white.png filter=lfs diff=lfs merge=lfs -text
|
Dockerfile
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
FROM python:3.10
|
| 2 |
+
WORKDIR /code
|
| 3 |
+
COPY --link --chown=1000 . .
|
| 4 |
+
RUN mkdir -p /tmp/cache/
|
| 5 |
+
RUN chmod a+rwx -R /tmp/cache/
|
| 6 |
+
ENV HF_HUB_CACHE=HF_HOME
|
| 7 |
+
RUN pip install --no-cache-dir -r requirements.txt
|
| 8 |
+
|
| 9 |
+
ENV PYTHONUNBUFFERED=1 PORT=7860
|
| 10 |
+
CMD ["python", "main.py"]
|
README.md
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
|
|
| 1 |
---
|
| 2 |
-
title:
|
| 3 |
-
emoji:
|
| 4 |
-
colorFrom:
|
| 5 |
-
colorTo:
|
| 6 |
-
sdk:
|
|
|
|
| 7 |
pinned: false
|
| 8 |
-
|
| 9 |
-
short_description: A FastHTML AI web app to classify Labrador dogs
|
| 10 |
---
|
| 11 |
-
|
| 12 |
-
Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
|
|
|
|
| 1 |
+
|
| 2 |
---
|
| 3 |
+
title: dgwyer/labrador-classifier
|
| 4 |
+
emoji: 🚀
|
| 5 |
+
colorFrom: purple
|
| 6 |
+
colorTo: red
|
| 7 |
+
sdk: docker
|
| 8 |
+
app_file: app.py
|
| 9 |
pinned: false
|
| 10 |
+
termination_grace_period: 2m
|
|
|
|
| 11 |
---
|
|
|
|
|
|
bl-pred.png
ADDED
|
black.jpg
ADDED
|
chocolate.jpg
ADDED
|
cl-pred.png
ADDED
|
drop.jpg
ADDED
|
export.pkl
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:24d4f52d4bff038df5654354e0343afb3cc55a05f80adb85a3442c2d3bdcbbaa
|
| 3 |
+
size 46979070
|
lab-logo.png
ADDED
|
logo-white.png
ADDED
|
Git LFS Details
|
main.py
ADDED
|
@@ -0,0 +1,280 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from fastai.vision.all import *
|
| 2 |
+
from fasthtml.common import *
|
| 3 |
+
from PIL import Image
|
| 4 |
+
from io import BytesIO
|
| 5 |
+
from starlette.responses import JSONResponse
|
| 6 |
+
from fasthtml_hf import setup_hf_backup
|
| 7 |
+
|
| 8 |
+
app, rt = fast_app(live=True, pico=False, hdrs=(
|
| 9 |
+
Script(src="https://cdn.tailwindcss.com?plugins=forms,typography"),
|
| 10 |
+
# Add custom styles
|
| 11 |
+
Style("""
|
| 12 |
+
body { background-color: #f9fafb; }
|
| 13 |
+
.card-shadow { box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05); }
|
| 14 |
+
.gradient-bg { background: linear-gradient(135deg, #3b82f6 0%, #1e40af 100%); }
|
| 15 |
+
""")
|
| 16 |
+
))
|
| 17 |
+
|
| 18 |
+
# JavaScript remains unchanged
|
| 19 |
+
drag_drop_js = """
|
| 20 |
+
function setupDragAndDrop() {
|
| 21 |
+
const dropZone = document.getElementById('drop-zone');
|
| 22 |
+
const previewImg = document.getElementById('preview-img');
|
| 23 |
+
const filenameInput = document.getElementById('selected-filename');
|
| 24 |
+
|
| 25 |
+
['dragenter', 'dragover', 'dragleave', 'drop'].forEach(e =>
|
| 26 |
+
dropZone.addEventListener(e, e => { e.preventDefault(); e.stopPropagation(); }, false));
|
| 27 |
+
|
| 28 |
+
['dragenter', 'dragover'].forEach(e =>
|
| 29 |
+
dropZone.addEventListener(e, () => dropZone.classList.add('border-blue-500', 'bg-blue-50'), false));
|
| 30 |
+
|
| 31 |
+
['dragleave', 'drop'].forEach(e =>
|
| 32 |
+
dropZone.addEventListener(e, () => dropZone.classList.remove('border-blue-500', 'bg-blue-50'), false));
|
| 33 |
+
|
| 34 |
+
dropZone.addEventListener('drop', e => {
|
| 35 |
+
if (e.dataTransfer.files.length) {
|
| 36 |
+
const file = e.dataTransfer.files[0];
|
| 37 |
+
const formData = new FormData();
|
| 38 |
+
formData.append('file', file);
|
| 39 |
+
|
| 40 |
+
fetch('/upload', { method: 'POST', body: formData })
|
| 41 |
+
.then(response => response.json())
|
| 42 |
+
.then(data => {
|
| 43 |
+
previewImg.src = '/drop.jpg?' + new Date().getTime();
|
| 44 |
+
filenameInput.value = 'drop.jpg';
|
| 45 |
+
})
|
| 46 |
+
.catch(error => console.error('Error:', error));
|
| 47 |
+
}
|
| 48 |
+
}, false);
|
| 49 |
+
}
|
| 50 |
+
document.addEventListener('DOMContentLoaded', setupDragAndDrop);
|
| 51 |
+
"""
|
| 52 |
+
|
| 53 |
+
# Enhanced image item component
|
| 54 |
+
def image_item(filename, color, label):
|
| 55 |
+
return Div(
|
| 56 |
+
Div(
|
| 57 |
+
Img(src=f"/{filename}",
|
| 58 |
+
cls=f"w-full h-auto cursor-pointer rounded-lg border-[5px] border-{color}",
|
| 59 |
+
onclick=f"document.getElementById('preview-img').src='/{filename}'; document.getElementById('selected-filename').value='{filename}';"),
|
| 60 |
+
cls="overflow-hidden"
|
| 61 |
+
),
|
| 62 |
+
P(f"{label} Labrador", cls="text-sm font-medium text-gray-700 mt-2 text-center"),
|
| 63 |
+
cls="w-[180px]" # Increased width from 130px to 180px
|
| 64 |
+
)
|
| 65 |
+
|
| 66 |
+
@rt('/')
|
| 67 |
+
def get():
|
| 68 |
+
return Div(
|
| 69 |
+
# Header with gradient background, logo, and Twitter link
|
| 70 |
+
Div(
|
| 71 |
+
Div(
|
| 72 |
+
# Flex container for all header elements with space-between
|
| 73 |
+
Div(
|
| 74 |
+
# Left side with logo and text
|
| 75 |
+
Div(
|
| 76 |
+
# Logo
|
| 77 |
+
Img(src="/lab-logo.png", alt="Labrador Classifier Logo",
|
| 78 |
+
cls="h-20 w-auto mr-4"),
|
| 79 |
+
|
| 80 |
+
# Text content
|
| 81 |
+
Div(
|
| 82 |
+
H1("Labrador Classifier", cls="text-2xl font-bold text-white m-0"),
|
| 83 |
+
P("Identify the type of Labrador using AI", cls="text-blue-100 m-0"),
|
| 84 |
+
),
|
| 85 |
+
|
| 86 |
+
# Make this a flex container to align logo and text
|
| 87 |
+
cls="flex items-center"
|
| 88 |
+
),
|
| 89 |
+
|
| 90 |
+
# Right side with Twitter link
|
| 91 |
+
A(
|
| 92 |
+
Img(src="/logo-white.png", alt="Twitter",
|
| 93 |
+
cls="h-6 w-auto transition-transform hover:scale-110"),
|
| 94 |
+
href="https://x.com/dgwyer",
|
| 95 |
+
title="Follow me for more AI content!",
|
| 96 |
+
target="_blank",
|
| 97 |
+
rel="noopener noreferrer",
|
| 98 |
+
cls="flex items-center"
|
| 99 |
+
),
|
| 100 |
+
|
| 101 |
+
# Flex container properties to push items to opposite ends
|
| 102 |
+
cls="flex justify-between items-center"
|
| 103 |
+
),
|
| 104 |
+
cls="max-w-6xl mx-auto px-4 py-6"
|
| 105 |
+
),
|
| 106 |
+
cls="gradient-bg w-full mb-8"
|
| 107 |
+
),
|
| 108 |
+
|
| 109 |
+
# Main content container
|
| 110 |
+
Div(
|
| 111 |
+
# Left column
|
| 112 |
+
Div(
|
| 113 |
+
# Selected image section
|
| 114 |
+
Div(
|
| 115 |
+
H2("Image Analysis", cls="text-xl font-semibold text-gray-800 mb-4 pb-2 border-b"),
|
| 116 |
+
|
| 117 |
+
# Drop zone and preview
|
| 118 |
+
Div(
|
| 119 |
+
Div(
|
| 120 |
+
Img(id="preview-img", src="/black.jpg",
|
| 121 |
+
cls="w-full h-auto object-contain rounded-lg mb-4 mx-auto block min-h-[200px] max-h-[200px]"),
|
| 122 |
+
P("Drag & Drop Image Here",
|
| 123 |
+
cls="text-gray-500 text-sm absolute bottom-4 left-0 right-0 text-center bg-white bg-opacity-75 py-2"),
|
| 124 |
+
id="drop-zone",
|
| 125 |
+
cls="relative w-full border-2 border-dashed border-blue-300 p-8 rounded-xl text-center cursor-pointer transition-colors bg-blue-50 bg-opacity-50 mb-4 hover:bg-blue-100 hover:border-blue-400" # Increased padding to p-8
|
| 126 |
+
),
|
| 127 |
+
# Prediction form
|
| 128 |
+
Form(
|
| 129 |
+
Input(type="hidden", id="selected-filename", name="filename", value="black.jpg"),
|
| 130 |
+
Button('Analyze Image', type="submit",
|
| 131 |
+
cls="w-full py-3 px-4 rounded-lg bg-blue-600 text-white font-medium shadow-md hover:bg-blue-700 transition-colors focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-opacity-50"),
|
| 132 |
+
hx_post="/loading", hx_target="#predictions", cls="mt-3"
|
| 133 |
+
),
|
| 134 |
+
cls="w-full max-w-lg mx-auto" # Changed to max-width instead of percentage
|
| 135 |
+
),
|
| 136 |
+
cls="bg-white rounded-xl p-6 mb-6 card-shadow"
|
| 137 |
+
),
|
| 138 |
+
|
| 139 |
+
# Sample images section
|
| 140 |
+
Div(
|
| 141 |
+
H2("Sample Images", cls="text-xl font-semibold text-gray-800 mb-4 pb-2 border-b"),
|
| 142 |
+
P("Click an image to analyze", cls="text-gray-600 mb-4"),
|
| 143 |
+
Div(
|
| 144 |
+
image_item("black.jpg", "gray-800", "Black"),
|
| 145 |
+
image_item("yellow.jpg", "yellow-500", "Yellow"),
|
| 146 |
+
image_item("chocolate.jpg", "amber-700", "Chocolate"),
|
| 147 |
+
cls="flex flex-row justify-center gap-8 mx-auto" # Increased gap from 6 to 8
|
| 148 |
+
),
|
| 149 |
+
cls="bg-white rounded-xl p-6 card-shadow"
|
| 150 |
+
),
|
| 151 |
+
cls="w-full lg:w-2/3 pr-0 lg:pr-8" # Increased right padding
|
| 152 |
+
),
|
| 153 |
+
|
| 154 |
+
# Right column
|
| 155 |
+
Div(
|
| 156 |
+
Div(
|
| 157 |
+
H2('Results', cls="text-xl font-semibold text-gray-800 mb-4 pb-2 border-b"),
|
| 158 |
+
Div(
|
| 159 |
+
Div(
|
| 160 |
+
NotStr('<svg class="w-12 h-12 text-blue-500 mx-auto mb-4" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9.663 17h4.673M12 3v1m6.364 1.636l-.707.707M21 12h-1M4 12H3m3.343-5.657l-.707-.707m2.828 9.9a5 5 0 117.072 0l-.548.547A3.374 3.374 0 0014 18.469V19a2 2 0 11-4 0v-.531c0-.895-.356-1.754-.988-2.386l-.548-.547z"></path></svg>'),
|
| 161 |
+
H3("Ready for Analysis", cls="text-lg font-medium text-gray-700 text-center"),
|
| 162 |
+
P('Click the "Analyze Image" button to identify the type of Labrador.',
|
| 163 |
+
cls="text-gray-600 text-center"),
|
| 164 |
+
cls="py-8"
|
| 165 |
+
),
|
| 166 |
+
id="predictions",
|
| 167 |
+
cls="bg-gray-50 rounded-lg p-4 min-h-[250px] flex items-center"
|
| 168 |
+
),
|
| 169 |
+
cls="bg-white rounded-xl p-6 card-shadow sticky top-6"
|
| 170 |
+
),
|
| 171 |
+
cls="w-full lg:w-1/3 mt-6 lg:mt-0"
|
| 172 |
+
),
|
| 173 |
+
cls="flex flex-col lg:flex-row gap-6 max-w-6xl mx-auto px-4" # Added max-width and padding
|
| 174 |
+
),
|
| 175 |
+
|
| 176 |
+
# Footer
|
| 177 |
+
Div(
|
| 178 |
+
P("© 2025 Labrador Classifier • By David Gwyer • Powered by FastAI and FastHTML",
|
| 179 |
+
cls="text-center text-gray-500 text-sm"),
|
| 180 |
+
cls="mt-12 py-6 border-t max-w-6xl mx-auto px-4" # Added max-width and padding
|
| 181 |
+
),
|
| 182 |
+
|
| 183 |
+
Script(drag_drop_js),
|
| 184 |
+
cls="min-h-screen"
|
| 185 |
+
)
|
| 186 |
+
|
| 187 |
+
@rt('/upload')
|
| 188 |
+
async def post(file: UploadFile):
|
| 189 |
+
img = Image.open(BytesIO(await file.read())).resize((128, 128), Image.LANCZOS)
|
| 190 |
+
img.save("drop.jpg")
|
| 191 |
+
return JSONResponse({"success": True, "filename": "drop.jpg"})
|
| 192 |
+
|
| 193 |
+
@rt('/loading')
|
| 194 |
+
def post(filename: str = "black.jpg"):
|
| 195 |
+
return Div(
|
| 196 |
+
Div(
|
| 197 |
+
Div(
|
| 198 |
+
NotStr('<svg class="w-12 h-12 animate-spin text-blue-600 mx-auto mb-4" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"><circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle><path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path></svg>'),
|
| 199 |
+
H3("Analyzing Image", cls="text-lg font-medium text-gray-700 text-center"),
|
| 200 |
+
P("Please wait while we process your image...", cls="text-gray-600 text-center"),
|
| 201 |
+
cls="py-8"
|
| 202 |
+
),
|
| 203 |
+
cls="flex items-center justify-center"
|
| 204 |
+
),
|
| 205 |
+
cls="bg-gray-50 rounded-lg p-4 min-h-[250px]",
|
| 206 |
+
hx_get=f"/process?filename={filename}",
|
| 207 |
+
hx_trigger="load",
|
| 208 |
+
hx_swap="outerHTML"
|
| 209 |
+
)
|
| 210 |
+
|
| 211 |
+
@rt('/process')
|
| 212 |
+
def get(filename: str = "black.jpg"):
|
| 213 |
+
# Model inference
|
| 214 |
+
labrador_learner = load_learner('export.pkl')
|
| 215 |
+
prediction = labrador_learner.predict(filename)
|
| 216 |
+
|
| 217 |
+
# Extract prediction data
|
| 218 |
+
label, class_idx, probabilities = prediction
|
| 219 |
+
confidence = probabilities[class_idx.item()].item() * 100
|
| 220 |
+
|
| 221 |
+
# Determine which prediction image to show based on the label
|
| 222 |
+
pred_image = ""
|
| 223 |
+
if label == "black":
|
| 224 |
+
pred_image = "bl-pred.png"
|
| 225 |
+
elif label == "yellow":
|
| 226 |
+
pred_image = "yl-pred.png"
|
| 227 |
+
elif label == "chocolate":
|
| 228 |
+
pred_image = "cl-pred.png"
|
| 229 |
+
|
| 230 |
+
return Div(
|
| 231 |
+
Div(
|
| 232 |
+
# Success icon
|
| 233 |
+
NotStr('<svg class="w-12 h-12 text-green-500 mx-auto mb-3" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"></path></svg>'),
|
| 234 |
+
|
| 235 |
+
# Results
|
| 236 |
+
H3('Analysis Complete', cls="text-lg font-medium text-gray-700 text-center mb-3"),
|
| 237 |
+
|
| 238 |
+
# Prediction image
|
| 239 |
+
Div(
|
| 240 |
+
Img(src=f"/{pred_image}", alt=f"{label.capitalize()} Labrador",
|
| 241 |
+
cls="w-32 h-32 mx-auto mb-4 object-contain"),
|
| 242 |
+
cls="text-center"
|
| 243 |
+
),
|
| 244 |
+
|
| 245 |
+
# Prediction card
|
| 246 |
+
Div(
|
| 247 |
+
Div(
|
| 248 |
+
Div(
|
| 249 |
+
P("Prediction", cls="text-xs font-medium text-gray-500 uppercase tracking-wide"),
|
| 250 |
+
P(f'{label.capitalize()} Labrador',
|
| 251 |
+
cls="text-lg font-bold text-blue-600"),
|
| 252 |
+
cls="flex-grow"
|
| 253 |
+
),
|
| 254 |
+
Div(
|
| 255 |
+
P("Confidence", cls="text-xs font-medium text-gray-500 uppercase tracking-wide"),
|
| 256 |
+
P(f'{confidence:.1f}%',
|
| 257 |
+
cls="text-lg font-bold text-gray-800"),
|
| 258 |
+
cls="text-right"
|
| 259 |
+
),
|
| 260 |
+
cls="flex justify-between items-center"
|
| 261 |
+
),
|
| 262 |
+
|
| 263 |
+
# Progress bar for confidence
|
| 264 |
+
Div(
|
| 265 |
+
Div(
|
| 266 |
+
cls=f"h-2 bg-blue-600 rounded-full",
|
| 267 |
+
style=f"width: {confidence}%"
|
| 268 |
+
),
|
| 269 |
+
cls="w-full bg-gray-200 rounded-full h-2 mt-2"
|
| 270 |
+
),
|
| 271 |
+
|
| 272 |
+
cls="bg-white rounded-lg p-4 shadow-sm border border-gray-200"
|
| 273 |
+
)
|
| 274 |
+
),
|
| 275 |
+
cls="bg-gray-50 rounded-lg p-6 min-h-[250px]"
|
| 276 |
+
)
|
| 277 |
+
|
| 278 |
+
setup_hf_backup(app)
|
| 279 |
+
|
| 280 |
+
serve()
|
requirements.txt
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
fasthtml-hf
|
| 2 |
+
fastai
|
| 3 |
+
python-fasthtml
|
| 4 |
+
Pillow
|
| 5 |
+
starlette
|
| 6 |
+
uvicorn>=0.29
|
| 7 |
+
python-multipart
|
| 8 |
+
huggingface-hub>=0.20.0
|
yellow.jpg
ADDED
|
yl-pred.png
ADDED
|