Spaces:
Sleeping
Sleeping
commit
Browse files- .gitattributes +1 -0
- Dockerfile +51 -0
- README.md +31 -10
- app.py +106 -0
- check_dims.py +13 -0
- check_env.py +21 -0
- classifier.py +103 -0
- dataset_prep.py +45 -0
- debug_mp.py +19 -0
- detect.py +37 -0
- face_shape_means.pkl +3 -0
- geometry.py +52 -0
- hf_upload.py +31 -0
- landmarks.py +66 -0
- lbfmodel.yaml +3 -0
- recommend.py +51 -0
- requirements.txt +12 -0
- server.log +284 -0
- server_mock.log +2 -0
- server_mock_2.log +590 -0
- start.sh +2 -0
- start_and_setup.sh +15 -0
- test_accuracy.py +83 -0
- test_accuracy_simple.py +43 -0
- test_api.py +48 -0
- test_results.txt +12 -0
- train.py +120 -0
- train_means.py +62 -0
- train_model.py +88 -0
- verify_simple.py +27 -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 |
+
lbfmodel.yaml filter=lfs diff=lfs merge=lfs -text
|
Dockerfile
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Use Python 3.10 slim image for compatibility with AI libraries
|
| 2 |
+
FROM python:3.10-slim-bullseye
|
| 3 |
+
|
| 4 |
+
# Set environment variables
|
| 5 |
+
ENV PYTHONDONTWRITEBYTECODE=1
|
| 6 |
+
ENV PYTHONUNBUFFERED=1
|
| 7 |
+
ENV DEBIAN_FRONTEND=noninteractive
|
| 8 |
+
|
| 9 |
+
# Set working directory
|
| 10 |
+
WORKDIR /app
|
| 11 |
+
|
| 12 |
+
# Install system dependencies required for OpenCV
|
| 13 |
+
RUN apt-get update && apt-get install -y --no-install-recommends \
|
| 14 |
+
libgl1-mesa-glx \
|
| 15 |
+
libglib2.0-0 \
|
| 16 |
+
libsm6 \
|
| 17 |
+
libxext6 \
|
| 18 |
+
libxrender-dev \
|
| 19 |
+
wget \
|
| 20 |
+
&& rm -rf /var/lib/apt/lists/*
|
| 21 |
+
|
| 22 |
+
|
| 23 |
+
|
| 24 |
+
# Copy requirements and install Python dependencies
|
| 25 |
+
COPY requirements.txt .
|
| 26 |
+
RUN pip install --no-cache-dir -r requirements.txt
|
| 27 |
+
|
| 28 |
+
# Copy the rest of the application code
|
| 29 |
+
COPY . .
|
| 30 |
+
|
| 31 |
+
# Ensure the LBF model is present (download if missing during build)
|
| 32 |
+
# We can run a small python script to check/download it
|
| 33 |
+
RUN python3 -c "import landmarks; landmarks.ensure_model()"
|
| 34 |
+
|
| 35 |
+
# Train the model during build (if dataset is provided in the context)
|
| 36 |
+
RUN if [ -d "dataset" ]; then \
|
| 37 |
+
echo "Dataset found. Training face shape model..." && \
|
| 38 |
+
python3 train_means.py; \
|
| 39 |
+
else \
|
| 40 |
+
echo "No dataset found. Using pre-trained face_shape_means.pkl if available."; \
|
| 41 |
+
fi
|
| 42 |
+
|
| 43 |
+
|
| 44 |
+
# Expose port (HF Spaces uses 7860 by default)
|
| 45 |
+
EXPOSE 7860
|
| 46 |
+
|
| 47 |
+
# Start the server (Railway/Spaces provide PORT env var)
|
| 48 |
+
# We default to 7860 for HF Spaces
|
| 49 |
+
CMD ["sh", "-c", "uvicorn app:app --host 0.0.0.0 --port ${PORT:-7860}"]
|
| 50 |
+
|
| 51 |
+
|
README.md
CHANGED
|
@@ -1,10 +1,31 @@
|
|
| 1 |
-
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
-
|
| 9 |
-
|
| 10 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# AI Frame Recommendation Service
|
| 2 |
+
|
| 3 |
+
This service analyzes facial features to recommend eyewear frames.
|
| 4 |
+
|
| 5 |
+
## Tech Stack
|
| 6 |
+
- Python 3.10+
|
| 7 |
+
- FastAPI
|
| 8 |
+
- OpenCV (Contrib)
|
| 9 |
+
- Scikit-learn
|
| 10 |
+
|
| 11 |
+
## Run with Docker (Recommended)
|
| 12 |
+
Docker handles all dependencies and ensures the AI models run correctly, avoiding Python version incompatibilities.
|
| 13 |
+
|
| 14 |
+
1. **Build the Image**
|
| 15 |
+
```bash
|
| 16 |
+
docker build -t ai_service .
|
| 17 |
+
```
|
| 18 |
+
|
| 19 |
+
2. **Run the Container**
|
| 20 |
+
```bash
|
| 21 |
+
docker run -p 8000:8000 ai_service
|
| 22 |
+
```
|
| 23 |
+
|
| 24 |
+
The API will be available at `http://localhost:8000`.
|
| 25 |
+
|
| 26 |
+
## Local Setup (Dev Only)
|
| 27 |
+
If you cannot use Docker, you can run locally, but some AI features might be mocked if your Python version is incompatible (e.g., Python 3.14).
|
| 28 |
+
|
| 29 |
+
```bash
|
| 30 |
+
./start_and_setup.sh
|
| 31 |
+
```
|
app.py
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from fastapi import FastAPI, UploadFile, File, HTTPException
|
| 2 |
+
from fastapi.middleware.cors import CORSMiddleware
|
| 3 |
+
from fastapi.responses import JSONResponse
|
| 4 |
+
import uvicorn
|
| 5 |
+
import shutil
|
| 6 |
+
import os
|
| 7 |
+
import uuid
|
| 8 |
+
from pathlib import Path
|
| 9 |
+
import logging
|
| 10 |
+
|
| 11 |
+
from detect import detect_face_shape
|
| 12 |
+
from recommend import get_recommendations
|
| 13 |
+
|
| 14 |
+
# Configure logging
|
| 15 |
+
logging.basicConfig(level=logging.INFO)
|
| 16 |
+
logger = logging.getLogger(__name__)
|
| 17 |
+
|
| 18 |
+
app = FastAPI(title="AI Frame Recommendation Service")
|
| 19 |
+
|
| 20 |
+
# Configure CORS
|
| 21 |
+
# For Hugging Face Spaces, we allow all origins or you can add specific patterns later
|
| 22 |
+
app.add_middleware(
|
| 23 |
+
CORSMiddleware,
|
| 24 |
+
allow_origins=["*"],
|
| 25 |
+
allow_credentials=True,
|
| 26 |
+
allow_methods=["*"],
|
| 27 |
+
allow_headers=["*"],
|
| 28 |
+
)
|
| 29 |
+
|
| 30 |
+
|
| 31 |
+
|
| 32 |
+
UPLOAD_DIR = Path("uploads")
|
| 33 |
+
UPLOAD_DIR.mkdir(exist_ok=True)
|
| 34 |
+
|
| 35 |
+
@app.post("/recommend")
|
| 36 |
+
async def recommend(file: UploadFile = File(...), source: str = "upload", consent: bool = False):
|
| 37 |
+
try:
|
| 38 |
+
# Save uploaded file temporarily
|
| 39 |
+
file_ext = file.filename.split(".")[-1] if file.filename else "jpg"
|
| 40 |
+
filename = f"{uuid.uuid4()}.{file_ext}"
|
| 41 |
+
file_path = UPLOAD_DIR / filename
|
| 42 |
+
|
| 43 |
+
with open(file_path, "wb") as buffer:
|
| 44 |
+
shutil.copyfileobj(file.file, buffer)
|
| 45 |
+
|
| 46 |
+
logger.info(f"Processing image: {file_path}")
|
| 47 |
+
|
| 48 |
+
# Analyze face shape
|
| 49 |
+
try:
|
| 50 |
+
# Returns dict: {'Oval': 0.6, 'Square': 0.4, ...}
|
| 51 |
+
face_shape_probs = detect_face_shape(str(file_path))
|
| 52 |
+
|
| 53 |
+
# Get top result (keys are sorted descending in detect.py)
|
| 54 |
+
top_shape = list(face_shape_probs.keys())[0]
|
| 55 |
+
top_confidence = face_shape_probs[top_shape]
|
| 56 |
+
|
| 57 |
+
logger.info(f"Detected face shape: {top_shape} ({top_confidence})")
|
| 58 |
+
except Exception as e:
|
| 59 |
+
logger.error(f"Error analyzing face: {str(e)}")
|
| 60 |
+
# Clean up file if analysis fails
|
| 61 |
+
if not consent:
|
| 62 |
+
try:
|
| 63 |
+
os.remove(file_path)
|
| 64 |
+
except: pass
|
| 65 |
+
raise HTTPException(status_code=400, detail=f"Could not analyze face: {str(e)}")
|
| 66 |
+
|
| 67 |
+
# Get recommendations using top shape
|
| 68 |
+
recommendations = get_recommendations(top_shape)
|
| 69 |
+
|
| 70 |
+
# Format response
|
| 71 |
+
response = {
|
| 72 |
+
"face_shape": top_shape,
|
| 73 |
+
"confidence": top_confidence,
|
| 74 |
+
"shape_confidence": top_confidence,
|
| 75 |
+
"shape_probabilities": face_shape_probs,
|
| 76 |
+
"frame_types": [
|
| 77 |
+
{"label": rec, "confidence": 0.9} for rec in recommendations.get("glasses", [])
|
| 78 |
+
],
|
| 79 |
+
"frame_size": {"label": "Medium", "confidence": 0.8}, # Placeholder
|
| 80 |
+
"bridge_type": {"label": "Regular", "confidence": 0.8}, # Placeholder
|
| 81 |
+
"materials": [{"label": "Acetate", "confidence": 0.7}], # Placeholder
|
| 82 |
+
"measurements": {
|
| 83 |
+
"face_width": 140, # Placeholder
|
| 84 |
+
"temple_length": 145 # Placeholder
|
| 85 |
+
},
|
| 86 |
+
"ml_predicted_frame": recommendations.get("glasses", [])[0] if recommendations.get("glasses") else None,
|
| 87 |
+
"ml_confidence": 0.85,
|
| 88 |
+
"image_id": str(filename) if consent else None
|
| 89 |
+
}
|
| 90 |
+
|
| 91 |
+
# Clean up if no consent to save
|
| 92 |
+
if not consent:
|
| 93 |
+
os.remove(file_path)
|
| 94 |
+
|
| 95 |
+
return JSONResponse(content=response)
|
| 96 |
+
|
| 97 |
+
except Exception as e:
|
| 98 |
+
logger.error(f"Server error: {str(e)}")
|
| 99 |
+
raise HTTPException(status_code=500, detail=str(e))
|
| 100 |
+
|
| 101 |
+
@app.get("/health")
|
| 102 |
+
def health_check():
|
| 103 |
+
return {"status": "ok"}
|
| 104 |
+
|
| 105 |
+
if __name__ == "__main__":
|
| 106 |
+
uvicorn.run("app:app", host="0.0.0.0", port=8000, reload=True)
|
check_dims.py
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from PIL import Image
|
| 2 |
+
import os
|
| 3 |
+
|
| 4 |
+
folder = "../dataset/test/Heart"
|
| 5 |
+
if os.path.exists(folder):
|
| 6 |
+
files = os.listdir(folder)[:5]
|
| 7 |
+
for f in files:
|
| 8 |
+
path = os.path.join(folder, f)
|
| 9 |
+
try:
|
| 10 |
+
with Image.open(path) as img:
|
| 11 |
+
print(f"{f}: {img.size}")
|
| 12 |
+
except:
|
| 13 |
+
pass
|
check_env.py
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import sys
|
| 2 |
+
print("Starting import check...")
|
| 3 |
+
try:
|
| 4 |
+
import cv2
|
| 5 |
+
print(f"CV2 imported: {cv2.__version__}")
|
| 6 |
+
except Exception as e:
|
| 7 |
+
print(f"CV2 import failed: {e}")
|
| 8 |
+
|
| 9 |
+
try:
|
| 10 |
+
import numpy
|
| 11 |
+
print(f"Numpy imported: {numpy.__version__}")
|
| 12 |
+
except Exception as e:
|
| 13 |
+
print(f"Numpy import failed: {e}")
|
| 14 |
+
|
| 15 |
+
try:
|
| 16 |
+
import sklearn
|
| 17 |
+
print(f"Sklearn imported: {sklearn.__version__}")
|
| 18 |
+
except Exception as e:
|
| 19 |
+
print(f"Sklearn import failed: {e}")
|
| 20 |
+
|
| 21 |
+
print("Import check complete.")
|
classifier.py
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import pickle
|
| 3 |
+
import numpy as np
|
| 4 |
+
from PIL import Image
|
| 5 |
+
from huggingface_hub import hf_hub_download
|
| 6 |
+
|
| 7 |
+
REPO_ID = "codernotme/kataria_optical"
|
| 8 |
+
MODEL_PATH = "face_shape_means.pkl"
|
| 9 |
+
IMG_SIZE = (64, 64)
|
| 10 |
+
|
| 11 |
+
# Global model cache (dictionary of mean vectors)
|
| 12 |
+
_means = None
|
| 13 |
+
|
| 14 |
+
def load_model():
|
| 15 |
+
global _means
|
| 16 |
+
if _means is None:
|
| 17 |
+
# Check local first
|
| 18 |
+
local_path = MODEL_PATH
|
| 19 |
+
if not os.path.exists(local_path):
|
| 20 |
+
try:
|
| 21 |
+
print(f"Downloading {MODEL_PATH} from HF Hub...")
|
| 22 |
+
local_path = hf_hub_download(repo_id=REPO_ID, filename=MODEL_PATH)
|
| 23 |
+
except Exception as e:
|
| 24 |
+
print(f"Could not download from HF Hub: {e}")
|
| 25 |
+
return None
|
| 26 |
+
|
| 27 |
+
try:
|
| 28 |
+
with open(local_path, "rb") as f:
|
| 29 |
+
_means = pickle.load(f)
|
| 30 |
+
print("Loaded Mean Face vectors.")
|
| 31 |
+
except Exception as e:
|
| 32 |
+
print(f"Failed to load model: {e}")
|
| 33 |
+
return _means
|
| 34 |
+
|
| 35 |
+
|
| 36 |
+
def classify_face_shape(image_input):
|
| 37 |
+
"""
|
| 38 |
+
Classifies face shape using Mean Face (Centroid) classification.
|
| 39 |
+
|
| 40 |
+
Args:
|
| 41 |
+
image_input: PIL Image or numpy array.
|
| 42 |
+
|
| 43 |
+
Returns:
|
| 44 |
+
dict: Sorted dictionary of probabilities.
|
| 45 |
+
"""
|
| 46 |
+
means = load_model()
|
| 47 |
+
|
| 48 |
+
if means is None or image_input is None:
|
| 49 |
+
return {"Unknown": 1.0}
|
| 50 |
+
|
| 51 |
+
try:
|
| 52 |
+
# Preprocess: Resize to 64x64, Grayscale, Flatten
|
| 53 |
+
if isinstance(image_input, np.ndarray):
|
| 54 |
+
# Helper to convert numpy (if passed from somewhere else) to PIL for consistent resize
|
| 55 |
+
img = Image.fromarray(image_input)
|
| 56 |
+
else:
|
| 57 |
+
img = image_input
|
| 58 |
+
|
| 59 |
+
# Ensuring grayscale and resize
|
| 60 |
+
img = img.convert("L").resize(IMG_SIZE)
|
| 61 |
+
input_vector = np.array(img).flatten()
|
| 62 |
+
|
| 63 |
+
# Calculate Cosine Similarity to each class mean
|
| 64 |
+
# Cosine Sim = (A . B) / (||A|| * ||B||)
|
| 65 |
+
scores = {}
|
| 66 |
+
input_norm = np.linalg.norm(input_vector)
|
| 67 |
+
if input_norm == 0:
|
| 68 |
+
return {"Unknown": 1.0}
|
| 69 |
+
|
| 70 |
+
for label, mean_vector in means.items():
|
| 71 |
+
mean_norm = np.linalg.norm(mean_vector)
|
| 72 |
+
if mean_norm == 0:
|
| 73 |
+
similarity = 0
|
| 74 |
+
else:
|
| 75 |
+
similarity = np.dot(input_vector, mean_vector) / (input_norm * mean_norm)
|
| 76 |
+
|
| 77 |
+
scores[label] = similarity
|
| 78 |
+
|
| 79 |
+
# Softmax directly on similarity scores?
|
| 80 |
+
# Similarity is between -1 and 1 (usually 0 to 1 for images).
|
| 81 |
+
# We can treat similarity as a logit or just normalize.
|
| 82 |
+
# Let's use simple normalization if all are positive.
|
| 83 |
+
|
| 84 |
+
min_score = min(scores.values())
|
| 85 |
+
if min_score < 0:
|
| 86 |
+
# Shift to positive
|
| 87 |
+
scores = {k: v - min_score for k, v in scores.items()}
|
| 88 |
+
|
| 89 |
+
total_score = sum(scores.values())
|
| 90 |
+
if total_score == 0:
|
| 91 |
+
total_score = 1
|
| 92 |
+
|
| 93 |
+
probabilities = {k: round(float(v / total_score), 4) for k, v in scores.items()}
|
| 94 |
+
|
| 95 |
+
# Sort by probability descending
|
| 96 |
+
return dict(sorted(probabilities.items(), key=lambda item: item[1], reverse=True))
|
| 97 |
+
|
| 98 |
+
|
| 99 |
+
except Exception as e:
|
| 100 |
+
print(f"Prediction error: {e}")
|
| 101 |
+
return {"Error": 1.0}
|
| 102 |
+
|
| 103 |
+
|
dataset_prep.py
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import shutil
|
| 3 |
+
|
| 4 |
+
dataset_path = "/home/codernotme/Projects/Github/katariaoptics/dataset"
|
| 5 |
+
standard_shapes = ["heart", "oblong", "oval", "round", "square"]
|
| 6 |
+
|
| 7 |
+
def normalize_dataset():
|
| 8 |
+
if not os.path.exists(dataset_path):
|
| 9 |
+
print(f"Dataset path {dataset_path} does not exist.")
|
| 10 |
+
return
|
| 11 |
+
|
| 12 |
+
# Create standard folders if they don't exist
|
| 13 |
+
for shape in standard_shapes:
|
| 14 |
+
target_dir = os.path.join(dataset_path, shape)
|
| 15 |
+
os.makedirs(target_dir, exist_ok=True)
|
| 16 |
+
|
| 17 |
+
# Walk through the dataset directory
|
| 18 |
+
for item in os.listdir(dataset_path):
|
| 19 |
+
item_path = os.path.join(dataset_path, item)
|
| 20 |
+
|
| 21 |
+
if os.path.isdir(item_path):
|
| 22 |
+
lower_name = item.lower()
|
| 23 |
+
|
| 24 |
+
# If it matches a standard shape but has different case (e.g., "Heart")
|
| 25 |
+
if lower_name in standard_shapes and item != lower_name:
|
| 26 |
+
target_dir = os.path.join(dataset_path, lower_name)
|
| 27 |
+
print(f"Merging {item} into {lower_name}...")
|
| 28 |
+
|
| 29 |
+
for file_name in os.listdir(item_path):
|
| 30 |
+
src_file = os.path.join(item_path, file_name)
|
| 31 |
+
dst_file = os.path.join(target_dir, file_name)
|
| 32 |
+
|
| 33 |
+
# Handle duplicates by renaming
|
| 34 |
+
if os.path.exists(dst_file):
|
| 35 |
+
base, ext = os.path.splitext(file_name)
|
| 36 |
+
dst_file = os.path.join(target_dir, f"{base}_1{ext}")
|
| 37 |
+
|
| 38 |
+
shutil.move(src_file, dst_file)
|
| 39 |
+
|
| 40 |
+
# Remove the empty directory
|
| 41 |
+
os.rmdir(item_path)
|
| 42 |
+
print(f"Removed {item}")
|
| 43 |
+
|
| 44 |
+
if __name__ == "__main__":
|
| 45 |
+
normalize_dataset()
|
debug_mp.py
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import mediapipe
|
| 2 |
+
import sys
|
| 3 |
+
|
| 4 |
+
print(f"Python version: {sys.version}")
|
| 5 |
+
print(f"MediaPipe location: {mediapipe.__file__}")
|
| 6 |
+
print("dir(mediapipe):")
|
| 7 |
+
print(dir(mediapipe))
|
| 8 |
+
|
| 9 |
+
try:
|
| 10 |
+
import mediapipe.python.solutions
|
| 11 |
+
print("Imported mediapipe.python.solutions successfully")
|
| 12 |
+
except ImportError as e:
|
| 13 |
+
print(f"Failed to import mediapipe.python.solutions: {e}")
|
| 14 |
+
|
| 15 |
+
try:
|
| 16 |
+
import mediapipe.solutions
|
| 17 |
+
print("Imported mediapipe.solutions successfully")
|
| 18 |
+
except ImportError as e:
|
| 19 |
+
print(f"Failed to import mediapipe.solutions: {e}")
|
detect.py
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import logging
|
| 2 |
+
import random
|
| 3 |
+
|
| 4 |
+
logger = logging.getLogger(__name__)
|
| 5 |
+
|
| 6 |
+
def detect_face_shape(image_path):
|
| 7 |
+
"""
|
| 8 |
+
Detects face shape using PIL and trained Mean Face model.
|
| 9 |
+
"""
|
| 10 |
+
from PIL import Image
|
| 11 |
+
import numpy as np
|
| 12 |
+
from classifier import classify_face_shape
|
| 13 |
+
|
| 14 |
+
try:
|
| 15 |
+
# Load image with PIL
|
| 16 |
+
if isinstance(image_path, str):
|
| 17 |
+
img = Image.open(image_path)
|
| 18 |
+
else:
|
| 19 |
+
# Assume it's already a PIL image or numpy array
|
| 20 |
+
img = image_path
|
| 21 |
+
|
| 22 |
+
if img is None:
|
| 23 |
+
raise ValueError("Could not load image")
|
| 24 |
+
|
| 25 |
+
# Classify directly (classifier handles resizing/grayscale)
|
| 26 |
+
shape_probs = classify_face_shape(img)
|
| 27 |
+
|
| 28 |
+
# Get the top shape
|
| 29 |
+
best_shape = list(shape_probs.keys())[0]
|
| 30 |
+
logger.info(f"Detected face shape: {best_shape} for {image_path}")
|
| 31 |
+
|
| 32 |
+
return shape_probs
|
| 33 |
+
|
| 34 |
+
except Exception as e:
|
| 35 |
+
logger.error(f"Detection failed: {e}")
|
| 36 |
+
return {"Error": 1.0}
|
| 37 |
+
|
face_shape_means.pkl
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:36b3f552e1eaf32c2abc3b3ef1fee9cb272b9a6e37ab85ba1d50d49f678eb93a
|
| 3 |
+
size 164135
|
geometry.py
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import numpy as np
|
| 2 |
+
from scipy.spatial import distance as dist
|
| 3 |
+
|
| 4 |
+
def euclidean_dist(p1, p2):
|
| 5 |
+
return dist.euclidean(p1, p2)
|
| 6 |
+
|
| 7 |
+
def extract_features(landmarks):
|
| 8 |
+
"""
|
| 9 |
+
Extracts geometric features from 68-point facial landmarks.
|
| 10 |
+
Indices based on dlib/OpenCV LBF standard.
|
| 11 |
+
|
| 12 |
+
Key Points:
|
| 13 |
+
- Jaw: 0-16 (8 is chin)
|
| 14 |
+
- Eyebrows: 17-21 (left), 22-26 (right)
|
| 15 |
+
- Nose: 27-35 (27 is bridge top)
|
| 16 |
+
- Eyes: 36-41 (left), 42-47 (right)
|
| 17 |
+
"""
|
| 18 |
+
landmarks = np.array(landmarks)
|
| 19 |
+
|
| 20 |
+
# defined points
|
| 21 |
+
jaw_left = landmarks[4]
|
| 22 |
+
jaw_right = landmarks[12]
|
| 23 |
+
chin = landmarks[8]
|
| 24 |
+
|
| 25 |
+
temple_left = landmarks[0]
|
| 26 |
+
temple_right = landmarks[16]
|
| 27 |
+
|
| 28 |
+
nose_top = landmarks[27] # Bridge of nose
|
| 29 |
+
|
| 30 |
+
# Measurements
|
| 31 |
+
jaw_width = euclidean_dist(jaw_left, jaw_right)
|
| 32 |
+
face_width = euclidean_dist(temple_left, temple_right) # Cheekbone/Temple width
|
| 33 |
+
|
| 34 |
+
# Estimate Face Length: distance from chin to nose bridge * 2.2 (heuristic)
|
| 35 |
+
# or chin to mid-eyebrow?
|
| 36 |
+
# Let's use chin to nose_top distance as a reliable segment
|
| 37 |
+
nose_to_chin = euclidean_dist(chin, nose_top)
|
| 38 |
+
face_length = nose_to_chin * 2.2
|
| 39 |
+
|
| 40 |
+
# Approximations
|
| 41 |
+
forehead_width = face_width * 0.9 # Hard to measure with 68 points, assume slightly narrower than temples
|
| 42 |
+
|
| 43 |
+
# Ratios
|
| 44 |
+
lw_ratio = face_length / face_width if face_width > 0 else 0
|
| 45 |
+
jaw_ratio = jaw_width / face_width if face_width > 0 else 0
|
| 46 |
+
forehead_ratio = forehead_width / face_width if face_width > 0 else 0 # Will be constant-ish with this heuristic
|
| 47 |
+
|
| 48 |
+
return {
|
| 49 |
+
"lw_ratio": lw_ratio,
|
| 50 |
+
"jaw_ratio": jaw_ratio,
|
| 51 |
+
"forehead_ratio": forehead_ratio
|
| 52 |
+
}
|
hf_upload.py
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
from huggingface_hub import HfApi, login
|
| 3 |
+
|
| 4 |
+
# 1. Login to Hugging Face
|
| 5 |
+
print("Please provide your Hugging Face WRITE token.")
|
| 6 |
+
login()
|
| 7 |
+
|
| 8 |
+
api = HfApi()
|
| 9 |
+
repo_id = "codernotme/kataria_optical"
|
| 10 |
+
|
| 11 |
+
# 2. Upload only the necessary model files
|
| 12 |
+
files_to_upload = {
|
| 13 |
+
"face_shape_means.pkl": "face_shape_means.pkl",
|
| 14 |
+
"lbfmodel.yaml": "lbfmodel.yaml"
|
| 15 |
+
}
|
| 16 |
+
|
| 17 |
+
print(f"Uploading model files to https://huggingface.co/{repo_id}...")
|
| 18 |
+
|
| 19 |
+
for local_file, repo_path in files_to_upload.items():
|
| 20 |
+
if os.path.exists(local_file):
|
| 21 |
+
print(f"Uploading {local_file}...")
|
| 22 |
+
api.upload_file(
|
| 23 |
+
path_or_fileobj=local_file,
|
| 24 |
+
path_in_repo=repo_path,
|
| 25 |
+
repo_id=repo_id,
|
| 26 |
+
repo_type="model"
|
| 27 |
+
)
|
| 28 |
+
else:
|
| 29 |
+
print(f"Error: {local_file} not found in ai_service directory!")
|
| 30 |
+
|
| 31 |
+
print("\nDone! Now your code can pull the model from Hugging Face.")
|
landmarks.py
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import cv2
|
| 2 |
+
import numpy as np
|
| 3 |
+
import os
|
| 4 |
+
import urllib.request
|
| 5 |
+
from huggingface_hub import hf_hub_download
|
| 6 |
+
|
| 7 |
+
REPO_ID = "codernotme/kataria_optical"
|
| 8 |
+
MODEL_FILE = "lbfmodel.yaml"
|
| 9 |
+
|
| 10 |
+
def ensure_model():
|
| 11 |
+
global MODEL_FILE
|
| 12 |
+
if not os.path.exists(MODEL_FILE):
|
| 13 |
+
print(f"Attempting to download {MODEL_FILE} from HF Hub...")
|
| 14 |
+
try:
|
| 15 |
+
downloaded_path = hf_hub_download(repo_id=REPO_ID, filename=MODEL_FILE)
|
| 16 |
+
MODEL_FILE = downloaded_path
|
| 17 |
+
print("Download from HF Hub complete.")
|
| 18 |
+
except Exception as e:
|
| 19 |
+
print(f"HF Hub download failed ({e}), falling back to GitHub...")
|
| 20 |
+
MODEL_URL = "https://raw.githubusercontent.com/kurnianggoro/GSOC2017/master/data/lbfmodel.yaml"
|
| 21 |
+
try:
|
| 22 |
+
urllib.request.urlretrieve(MODEL_URL, MODEL_FILE)
|
| 23 |
+
print("Download from GitHub complete.")
|
| 24 |
+
except Exception as e2:
|
| 25 |
+
raise RuntimeError(f"Failed to download LBF model from all sources: {e2}")
|
| 26 |
+
|
| 27 |
+
|
| 28 |
+
def get_landmarks(image_path):
|
| 29 |
+
"""
|
| 30 |
+
Extracts 68 face landmarks using OpenCV FacemarkLBF.
|
| 31 |
+
Returns a list/array of (x, y) coordinates.
|
| 32 |
+
"""
|
| 33 |
+
ensure_model()
|
| 34 |
+
|
| 35 |
+
facemark = cv2.face.createFacemarkLBF()
|
| 36 |
+
try:
|
| 37 |
+
facemark.loadModel(MODEL_FILE)
|
| 38 |
+
except Exception as e:
|
| 39 |
+
raise RuntimeError(f"Could not load LBF model: {e}")
|
| 40 |
+
|
| 41 |
+
image = cv2.imread(image_path)
|
| 42 |
+
if image is None:
|
| 43 |
+
raise ValueError(f"Could not read image: {image_path}")
|
| 44 |
+
|
| 45 |
+
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
|
| 46 |
+
|
| 47 |
+
# Detect faces using Haar Cascade (included in cv2)
|
| 48 |
+
face_cascade_path = cv2.data.haarcascades + "haarcascade_frontalface_alt2.xml"
|
| 49 |
+
if not os.path.exists(face_cascade_path):
|
| 50 |
+
# Fallback to default if alt2 not found
|
| 51 |
+
face_cascade_path = cv2.data.haarcascades + "haarcascade_frontalface_default.xml"
|
| 52 |
+
|
| 53 |
+
face_cascade = cv2.CascadeClassifier(face_cascade_path)
|
| 54 |
+
faces = face_cascade.detectMultiScale(gray, 1.3, 5)
|
| 55 |
+
|
| 56 |
+
if len(faces) == 0:
|
| 57 |
+
raise ValueError("No face detected.")
|
| 58 |
+
|
| 59 |
+
# Find landmarks
|
| 60 |
+
ok, landmarks = facemark.fit(gray, faces)
|
| 61 |
+
if not ok:
|
| 62 |
+
raise ValueError("Could not detect landmarks.")
|
| 63 |
+
|
| 64 |
+
# landmarks comes as a list of numpy arrays, we extract the first face's landmarks
|
| 65 |
+
# landmarks[0] is shape (1, 68, 2)
|
| 66 |
+
return landmarks[0][0]
|
lbfmodel.yaml
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:70dd8b1657c42d1595d6bd13d97d932877b3bed54a95d3c4733a0f740d1fd66b
|
| 3 |
+
size 56375857
|
recommend.py
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from landmarks import get_landmarks
|
| 2 |
+
from geometry import extract_features
|
| 3 |
+
from classifier import classify_face_shape
|
| 4 |
+
import logging
|
| 5 |
+
|
| 6 |
+
logger = logging.getLogger(__name__)
|
| 7 |
+
|
| 8 |
+
RECOMMENDATIONS = {
|
| 9 |
+
# Keys must match frame-metadata.ts:
|
| 10 |
+
# Wayfarer, Aviator, Round, Square, Rectangle, Cat-eye, Clubmaster, Geometric, Oversized
|
| 11 |
+
"Oval": {
|
| 12 |
+
"glasses": ["Square", "Rectangle", "Wayfarer", "Aviator"],
|
| 13 |
+
"hair": ["Quiff", "Side Part", "Buzz Fade", "Pompadour"],
|
| 14 |
+
"beard": ["Light Stubble", "Short Boxed", "Verdi"],
|
| 15 |
+
"description": "Balanced proportions. Most frame styles work well."
|
| 16 |
+
},
|
| 17 |
+
"Round": {
|
| 18 |
+
"glasses": ["Rectangle", "Square", "Wayfarer", "Geometric"],
|
| 19 |
+
"hair": ["Pompadour", "High Fade", "Faux Hawk", "Side Part"],
|
| 20 |
+
"beard": ["Goatee", "Van Dyke", "Extended Chin Curtain"],
|
| 21 |
+
"description": "Soft angles with similar width and height. Angular frames add definition."
|
| 22 |
+
},
|
| 23 |
+
"Square": {
|
| 24 |
+
"glasses": ["Round", "Aviator", "Cat-eye", "Clubmaster"],
|
| 25 |
+
"hair": ["Textured Crop", "Side Fade", "Buzz Cut", "Crew Cut"],
|
| 26 |
+
"beard": ["Light Stubble", "Circle Beard", "Royale"],
|
| 27 |
+
"description": "Strong jawline and broad forehead. Round frames soften features."
|
| 28 |
+
},
|
| 29 |
+
"Oblong": {
|
| 30 |
+
"glasses": ["Oversized", "Aviator", "Square", "Wayfarer"],
|
| 31 |
+
"hair": ["Side Part", "Buzz Cut", "Fringe", "Caesar Cut"],
|
| 32 |
+
"beard": ["Mutton Chops", "Chin Strap", "Short Stubble"],
|
| 33 |
+
"description": "Face is longer than it is wide. Oversized frames balance length."
|
| 34 |
+
},
|
| 35 |
+
"Heart": {
|
| 36 |
+
"glasses": ["Round", "Wayfarer", "Cat-eye", "Geometric"],
|
| 37 |
+
"hair": ["Long Fringe", "Side Part", "Textured Quiff", "Swept Back"],
|
| 38 |
+
"beard": ["Full Beard", "Garibaldi", "Extended Goatee"],
|
| 39 |
+
"description": "Wider forehead and narrower chin. Bottom-heavy frames help balance."
|
| 40 |
+
},
|
| 41 |
+
"Diamond": {
|
| 42 |
+
"glasses": ["Round", "Cat-eye", "Clubmaster", "Oval"], # Oval frame type not in metadata, but maybe acceptable as fallback or mapped later. Kept for logic.
|
| 43 |
+
"hair": ["Faux Hawk", "Textured Crop", "Quiff", "Fringe"],
|
| 44 |
+
"beard": ["Full Beard", "Goatee", "Balbo"],
|
| 45 |
+
"description": "Cheekbones are the widest part. Curves soften the cheekbones."
|
| 46 |
+
}
|
| 47 |
+
}
|
| 48 |
+
|
| 49 |
+
def get_recommendations(face_shape):
|
| 50 |
+
"""Returns style recommendations based on face shape."""
|
| 51 |
+
return RECOMMENDATIONS.get(face_shape, RECOMMENDATIONS["Oval"])
|
requirements.txt
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
opencv-contrib-python-headless
|
| 2 |
+
numpy
|
| 3 |
+
fastapi
|
| 4 |
+
uvicorn
|
| 5 |
+
python-multipart
|
| 6 |
+
pydantic
|
| 7 |
+
requests
|
| 8 |
+
Pillow
|
| 9 |
+
scipy
|
| 10 |
+
huggingface_hub
|
| 11 |
+
|
| 12 |
+
huggingface_hub
|
server.log
ADDED
|
@@ -0,0 +1,284 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
INFO: Will watch for changes in these directories: ['/home/codernotme/Projects/Github/katariaoptics/ai_service']
|
| 2 |
+
INFO: Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit)
|
| 3 |
+
INFO: Started reloader process [433406] using StatReload
|
| 4 |
+
Process SpawnProcess-1:
|
| 5 |
+
Traceback (most recent call last):
|
| 6 |
+
File "/usr/lib64/python3.14/multiprocessing/process.py", line 320, in _bootstrap
|
| 7 |
+
self.run()
|
| 8 |
+
~~~~~~~~^^
|
| 9 |
+
File "/usr/lib64/python3.14/multiprocessing/process.py", line 108, in run
|
| 10 |
+
self._target(*self._args, **self._kwargs)
|
| 11 |
+
~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| 12 |
+
File "/home/codernotme/.local/lib/python3.14/site-packages/uvicorn/_subprocess.py", line 80, in subprocess_started
|
| 13 |
+
target(sockets=sockets)
|
| 14 |
+
~~~~~~^^^^^^^^^^^^^^^^^
|
| 15 |
+
File "/home/codernotme/.local/lib/python3.14/site-packages/uvicorn/server.py", line 67, in run
|
| 16 |
+
return asyncio_run(self.serve(sockets=sockets), loop_factory=self.config.get_loop_factory())
|
| 17 |
+
File "/usr/lib64/python3.14/asyncio/runners.py", line 204, in run
|
| 18 |
+
return runner.run(main)
|
| 19 |
+
~~~~~~~~~~^^^^^^
|
| 20 |
+
File "/usr/lib64/python3.14/asyncio/runners.py", line 127, in run
|
| 21 |
+
return self._loop.run_until_complete(task)
|
| 22 |
+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^
|
| 23 |
+
File "/usr/lib64/python3.14/asyncio/base_events.py", line 719, in run_until_complete
|
| 24 |
+
return future.result()
|
| 25 |
+
~~~~~~~~~~~~~^^
|
| 26 |
+
File "/home/codernotme/.local/lib/python3.14/site-packages/uvicorn/server.py", line 71, in serve
|
| 27 |
+
await self._serve(sockets)
|
| 28 |
+
File "/home/codernotme/.local/lib/python3.14/site-packages/uvicorn/server.py", line 78, in _serve
|
| 29 |
+
config.load()
|
| 30 |
+
~~~~~~~~~~~^^
|
| 31 |
+
File "/home/codernotme/.local/lib/python3.14/site-packages/uvicorn/config.py", line 439, in load
|
| 32 |
+
self.loaded_app = import_from_string(self.app)
|
| 33 |
+
~~~~~~~~~~~~~~~~~~^^^^^^^^^^
|
| 34 |
+
File "/home/codernotme/.local/lib/python3.14/site-packages/uvicorn/importer.py", line 19, in import_from_string
|
| 35 |
+
module = importlib.import_module(module_str)
|
| 36 |
+
File "/usr/lib64/python3.14/importlib/__init__.py", line 88, in import_module
|
| 37 |
+
return _bootstrap._gcd_import(name[level:], package, level)
|
| 38 |
+
~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| 39 |
+
File "<frozen importlib._bootstrap>", line 1398, in _gcd_import
|
| 40 |
+
File "<frozen importlib._bootstrap>", line 1371, in _find_and_load
|
| 41 |
+
File "<frozen importlib._bootstrap>", line 1342, in _find_and_load_unlocked
|
| 42 |
+
File "<frozen importlib._bootstrap>", line 938, in _load_unlocked
|
| 43 |
+
File "<frozen importlib._bootstrap_external>", line 759, in exec_module
|
| 44 |
+
File "<frozen importlib._bootstrap>", line 491, in _call_with_frames_removed
|
| 45 |
+
File "/home/codernotme/Projects/Github/katariaoptics/ai_service/app.py", line 11, in <module>
|
| 46 |
+
from detect import detect_face_shape
|
| 47 |
+
File "/home/codernotme/Projects/Github/katariaoptics/ai_service/detect.py", line 1, in <module>
|
| 48 |
+
from landmarks import get_landmarks
|
| 49 |
+
File "/home/codernotme/Projects/Github/katariaoptics/ai_service/landmarks.py", line 5, in <module>
|
| 50 |
+
mp_face_mesh = mp.solutions.face_mesh
|
| 51 |
+
^^^^^^^^^^^^
|
| 52 |
+
AttributeError: module 'mediapipe' has no attribute 'solutions'
|
| 53 |
+
WARNING: StatReload detected changes in 'detect.py'. Reloading...
|
| 54 |
+
WARNING: StatReload detected changes in 'landmarks.py'. Reloading...
|
| 55 |
+
Process SpawnProcess-2:
|
| 56 |
+
Traceback (most recent call last):
|
| 57 |
+
File "/usr/lib64/python3.14/multiprocessing/process.py", line 320, in _bootstrap
|
| 58 |
+
self.run()
|
| 59 |
+
~~~~~~~~^^
|
| 60 |
+
File "/usr/lib64/python3.14/multiprocessing/process.py", line 108, in run
|
| 61 |
+
self._target(*self._args, **self._kwargs)
|
| 62 |
+
~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| 63 |
+
File "/home/codernotme/.local/lib/python3.14/site-packages/uvicorn/_subprocess.py", line 80, in subprocess_started
|
| 64 |
+
target(sockets=sockets)
|
| 65 |
+
~~~~~~^^^^^^^^^^^^^^^^^
|
| 66 |
+
File "/home/codernotme/.local/lib/python3.14/site-packages/uvicorn/server.py", line 67, in run
|
| 67 |
+
return asyncio_run(self.serve(sockets=sockets), loop_factory=self.config.get_loop_factory())
|
| 68 |
+
File "/usr/lib64/python3.14/asyncio/runners.py", line 204, in run
|
| 69 |
+
return runner.run(main)
|
| 70 |
+
~~~~~~~~~~^^^^^^
|
| 71 |
+
File "/usr/lib64/python3.14/asyncio/runners.py", line 127, in run
|
| 72 |
+
return self._loop.run_until_complete(task)
|
| 73 |
+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^
|
| 74 |
+
File "/usr/lib64/python3.14/asyncio/base_events.py", line 719, in run_until_complete
|
| 75 |
+
return future.result()
|
| 76 |
+
~~~~~~~~~~~~~^^
|
| 77 |
+
File "/home/codernotme/.local/lib/python3.14/site-packages/uvicorn/server.py", line 71, in serve
|
| 78 |
+
await self._serve(sockets)
|
| 79 |
+
File "/home/codernotme/.local/lib/python3.14/site-packages/uvicorn/server.py", line 78, in _serve
|
| 80 |
+
config.load()
|
| 81 |
+
~~~~~~~~~~~^^
|
| 82 |
+
File "/home/codernotme/.local/lib/python3.14/site-packages/uvicorn/config.py", line 439, in load
|
| 83 |
+
self.loaded_app = import_from_string(self.app)
|
| 84 |
+
~~~~~~~~~~~~~~~~~~^^^^^^^^^^
|
| 85 |
+
File "/home/codernotme/.local/lib/python3.14/site-packages/uvicorn/importer.py", line 19, in import_from_string
|
| 86 |
+
module = importlib.import_module(module_str)
|
| 87 |
+
File "/usr/lib64/python3.14/importlib/__init__.py", line 88, in import_module
|
| 88 |
+
return _bootstrap._gcd_import(name[level:], package, level)
|
| 89 |
+
~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| 90 |
+
File "<frozen importlib._bootstrap>", line 1398, in _gcd_import
|
| 91 |
+
File "<frozen importlib._bootstrap>", line 1371, in _find_and_load
|
| 92 |
+
File "<frozen importlib._bootstrap>", line 1342, in _find_and_load_unlocked
|
| 93 |
+
File "<frozen importlib._bootstrap>", line 938, in _load_unlocked
|
| 94 |
+
File "<frozen importlib._bootstrap_external>", line 759, in exec_module
|
| 95 |
+
File "<frozen importlib._bootstrap>", line 491, in _call_with_frames_removed
|
| 96 |
+
File "/home/codernotme/Projects/Github/katariaoptics/ai_service/app.py", line 11, in <module>
|
| 97 |
+
from detect import detect_face_shape
|
| 98 |
+
File "/home/codernotme/Projects/Github/katariaoptics/ai_service/detect.py", line 1, in <module>
|
| 99 |
+
from landmarks import get_landmarks
|
| 100 |
+
File "/home/codernotme/Projects/Github/katariaoptics/ai_service/landmarks.py", line 5, in <module>
|
| 101 |
+
# Try to handle potential import issues with mp.solutions
|
| 102 |
+
AttributeError: module 'mediapipe' has no attribute 'solutions'
|
| 103 |
+
Process SpawnProcess-3:
|
| 104 |
+
Traceback (most recent call last):
|
| 105 |
+
File "/usr/lib64/python3.14/multiprocessing/process.py", line 320, in _bootstrap
|
| 106 |
+
self.run()
|
| 107 |
+
~~~~~~~~^^
|
| 108 |
+
File "/usr/lib64/python3.14/multiprocessing/process.py", line 108, in run
|
| 109 |
+
self._target(*self._args, **self._kwargs)
|
| 110 |
+
~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| 111 |
+
File "/home/codernotme/.local/lib/python3.14/site-packages/uvicorn/_subprocess.py", line 80, in subprocess_started
|
| 112 |
+
target(sockets=sockets)
|
| 113 |
+
~~~~~~^^^^^^^^^^^^^^^^^
|
| 114 |
+
File "/home/codernotme/.local/lib/python3.14/site-packages/uvicorn/server.py", line 67, in run
|
| 115 |
+
return asyncio_run(self.serve(sockets=sockets), loop_factory=self.config.get_loop_factory())
|
| 116 |
+
File "/usr/lib64/python3.14/asyncio/runners.py", line 204, in run
|
| 117 |
+
return runner.run(main)
|
| 118 |
+
~~~~~~~~~~^^^^^^
|
| 119 |
+
File "/usr/lib64/python3.14/asyncio/runners.py", line 127, in run
|
| 120 |
+
return self._loop.run_until_complete(task)
|
| 121 |
+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^
|
| 122 |
+
File "/usr/lib64/python3.14/asyncio/base_events.py", line 719, in run_until_complete
|
| 123 |
+
return future.result()
|
| 124 |
+
~~~~~~~~~~~~~^^
|
| 125 |
+
File "/home/codernotme/.local/lib/python3.14/site-packages/uvicorn/server.py", line 71, in serve
|
| 126 |
+
await self._serve(sockets)
|
| 127 |
+
File "/home/codernotme/.local/lib/python3.14/site-packages/uvicorn/server.py", line 78, in _serve
|
| 128 |
+
config.load()
|
| 129 |
+
~~~~~~~~~~~^^
|
| 130 |
+
File "/home/codernotme/.local/lib/python3.14/site-packages/uvicorn/config.py", line 439, in load
|
| 131 |
+
self.loaded_app = import_from_string(self.app)
|
| 132 |
+
~~~~~~~~~~~~~~~~~~^^^^^^^^^^
|
| 133 |
+
File "/home/codernotme/.local/lib/python3.14/site-packages/uvicorn/importer.py", line 22, in import_from_string
|
| 134 |
+
raise exc from None
|
| 135 |
+
File "/home/codernotme/.local/lib/python3.14/site-packages/uvicorn/importer.py", line 19, in import_from_string
|
| 136 |
+
module = importlib.import_module(module_str)
|
| 137 |
+
File "/usr/lib64/python3.14/importlib/__init__.py", line 88, in import_module
|
| 138 |
+
return _bootstrap._gcd_import(name[level:], package, level)
|
| 139 |
+
~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| 140 |
+
File "<frozen importlib._bootstrap>", line 1398, in _gcd_import
|
| 141 |
+
File "<frozen importlib._bootstrap>", line 1371, in _find_and_load
|
| 142 |
+
File "<frozen importlib._bootstrap>", line 1342, in _find_and_load_unlocked
|
| 143 |
+
File "<frozen importlib._bootstrap>", line 938, in _load_unlocked
|
| 144 |
+
File "<frozen importlib._bootstrap_external>", line 759, in exec_module
|
| 145 |
+
File "<frozen importlib._bootstrap>", line 491, in _call_with_frames_removed
|
| 146 |
+
File "/home/codernotme/Projects/Github/katariaoptics/ai_service/app.py", line 11, in <module>
|
| 147 |
+
from detect import detect_face_shape
|
| 148 |
+
File "/home/codernotme/Projects/Github/katariaoptics/ai_service/detect.py", line 1, in <module>
|
| 149 |
+
from landmarks import get_landmarks
|
| 150 |
+
File "/home/codernotme/Projects/Github/katariaoptics/ai_service/landmarks.py", line 10, in <module>
|
| 151 |
+
import mediapipe.python.solutions.face_mesh as mp_face_mesh
|
| 152 |
+
ModuleNotFoundError: No module named 'mediapipe.python'
|
| 153 |
+
WARNING: StatReload detected changes in 'classifier.py'. Reloading...
|
| 154 |
+
Process SpawnProcess-4:
|
| 155 |
+
Traceback (most recent call last):
|
| 156 |
+
File "/usr/lib64/python3.14/multiprocessing/process.py", line 320, in _bootstrap
|
| 157 |
+
self.run()
|
| 158 |
+
~~~~~~~~^^
|
| 159 |
+
File "/usr/lib64/python3.14/multiprocessing/process.py", line 108, in run
|
| 160 |
+
self._target(*self._args, **self._kwargs)
|
| 161 |
+
~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| 162 |
+
File "/home/codernotme/.local/lib/python3.14/site-packages/uvicorn/_subprocess.py", line 80, in subprocess_started
|
| 163 |
+
target(sockets=sockets)
|
| 164 |
+
~~~~~~^^^^^^^^^^^^^^^^^
|
| 165 |
+
File "/home/codernotme/.local/lib/python3.14/site-packages/uvicorn/server.py", line 67, in run
|
| 166 |
+
return asyncio_run(self.serve(sockets=sockets), loop_factory=self.config.get_loop_factory())
|
| 167 |
+
File "/usr/lib64/python3.14/asyncio/runners.py", line 204, in run
|
| 168 |
+
return runner.run(main)
|
| 169 |
+
~~~~~~~~~~^^^^^^
|
| 170 |
+
File "/usr/lib64/python3.14/asyncio/runners.py", line 127, in run
|
| 171 |
+
return self._loop.run_until_complete(task)
|
| 172 |
+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^
|
| 173 |
+
File "/usr/lib64/python3.14/asyncio/base_events.py", line 719, in run_until_complete
|
| 174 |
+
return future.result()
|
| 175 |
+
~~~~~~~~~~~~~^^
|
| 176 |
+
File "/home/codernotme/.local/lib/python3.14/site-packages/uvicorn/server.py", line 71, in serve
|
| 177 |
+
await self._serve(sockets)
|
| 178 |
+
File "/home/codernotme/.local/lib/python3.14/site-packages/uvicorn/server.py", line 78, in _serve
|
| 179 |
+
config.load()
|
| 180 |
+
~~~~~~~~~~~^^
|
| 181 |
+
File "/home/codernotme/.local/lib/python3.14/site-packages/uvicorn/config.py", line 439, in load
|
| 182 |
+
self.loaded_app = import_from_string(self.app)
|
| 183 |
+
~~~~~~~~~~~~~~~~~~^^^^^^^^^^
|
| 184 |
+
File "/home/codernotme/.local/lib/python3.14/site-packages/uvicorn/importer.py", line 22, in import_from_string
|
| 185 |
+
raise exc from None
|
| 186 |
+
File "/home/codernotme/.local/lib/python3.14/site-packages/uvicorn/importer.py", line 19, in import_from_string
|
| 187 |
+
module = importlib.import_module(module_str)
|
| 188 |
+
File "/usr/lib64/python3.14/importlib/__init__.py", line 88, in import_module
|
| 189 |
+
return _bootstrap._gcd_import(name[level:], package, level)
|
| 190 |
+
~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| 191 |
+
File "<frozen importlib._bootstrap>", line 1398, in _gcd_import
|
| 192 |
+
File "<frozen importlib._bootstrap>", line 1371, in _find_and_load
|
| 193 |
+
File "<frozen importlib._bootstrap>", line 1342, in _find_and_load_unlocked
|
| 194 |
+
File "<frozen importlib._bootstrap>", line 938, in _load_unlocked
|
| 195 |
+
File "<frozen importlib._bootstrap_external>", line 759, in exec_module
|
| 196 |
+
File "<frozen importlib._bootstrap>", line 491, in _call_with_frames_removed
|
| 197 |
+
File "/home/codernotme/Projects/Github/katariaoptics/ai_service/app.py", line 11, in <module>
|
| 198 |
+
from detect import detect_face_shape
|
| 199 |
+
File "/home/codernotme/Projects/Github/katariaoptics/ai_service/detect.py", line 1, in <module>
|
| 200 |
+
from landmarks import get_landmarks
|
| 201 |
+
File "/home/codernotme/Projects/Github/katariaoptics/ai_service/landmarks.py", line 10, in <module>
|
| 202 |
+
import mediapipe.python.solutions.face_mesh as mp_face_mesh
|
| 203 |
+
ModuleNotFoundError: No module named 'mediapipe.python'
|
| 204 |
+
WARNING: StatReload detected changes in 'train_model.py'. Reloading...
|
| 205 |
+
Process SpawnProcess-5:
|
| 206 |
+
Traceback (most recent call last):
|
| 207 |
+
File "/usr/lib64/python3.14/multiprocessing/process.py", line 320, in _bootstrap
|
| 208 |
+
self.run()
|
| 209 |
+
~~~~~~~~^^
|
| 210 |
+
File "/usr/lib64/python3.14/multiprocessing/process.py", line 108, in run
|
| 211 |
+
self._target(*self._args, **self._kwargs)
|
| 212 |
+
~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| 213 |
+
File "/home/codernotme/.local/lib/python3.14/site-packages/uvicorn/_subprocess.py", line 80, in subprocess_started
|
| 214 |
+
target(sockets=sockets)
|
| 215 |
+
~~~~~~^^^^^^^^^^^^^^^^^
|
| 216 |
+
File "/home/codernotme/.local/lib/python3.14/site-packages/uvicorn/server.py", line 67, in run
|
| 217 |
+
return asyncio_run(self.serve(sockets=sockets), loop_factory=self.config.get_loop_factory())
|
| 218 |
+
File "/usr/lib64/python3.14/asyncio/runners.py", line 204, in run
|
| 219 |
+
return runner.run(main)
|
| 220 |
+
~~~~~~~~~~^^^^^^
|
| 221 |
+
File "/usr/lib64/python3.14/asyncio/runners.py", line 127, in run
|
| 222 |
+
return self._loop.run_until_complete(task)
|
| 223 |
+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^
|
| 224 |
+
File "/usr/lib64/python3.14/asyncio/base_events.py", line 719, in run_until_complete
|
| 225 |
+
return future.result()
|
| 226 |
+
~~~~~~~~~~~~~^^
|
| 227 |
+
File "/home/codernotme/.local/lib/python3.14/site-packages/uvicorn/server.py", line 71, in serve
|
| 228 |
+
await self._serve(sockets)
|
| 229 |
+
File "/home/codernotme/.local/lib/python3.14/site-packages/uvicorn/server.py", line 78, in _serve
|
| 230 |
+
config.load()
|
| 231 |
+
~~~~~~~~~~~^^
|
| 232 |
+
File "/home/codernotme/.local/lib/python3.14/site-packages/uvicorn/config.py", line 439, in load
|
| 233 |
+
self.loaded_app = import_from_string(self.app)
|
| 234 |
+
~~~~~~~~~~~~~~~~~~^^^^^^^^^^
|
| 235 |
+
File "/home/codernotme/.local/lib/python3.14/site-packages/uvicorn/importer.py", line 22, in import_from_string
|
| 236 |
+
raise exc from None
|
| 237 |
+
File "/home/codernotme/.local/lib/python3.14/site-packages/uvicorn/importer.py", line 19, in import_from_string
|
| 238 |
+
module = importlib.import_module(module_str)
|
| 239 |
+
File "/usr/lib64/python3.14/importlib/__init__.py", line 88, in import_module
|
| 240 |
+
return _bootstrap._gcd_import(name[level:], package, level)
|
| 241 |
+
~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| 242 |
+
File "<frozen importlib._bootstrap>", line 1398, in _gcd_import
|
| 243 |
+
File "<frozen importlib._bootstrap>", line 1371, in _find_and_load
|
| 244 |
+
File "<frozen importlib._bootstrap>", line 1342, in _find_and_load_unlocked
|
| 245 |
+
File "<frozen importlib._bootstrap>", line 938, in _load_unlocked
|
| 246 |
+
File "<frozen importlib._bootstrap_external>", line 759, in exec_module
|
| 247 |
+
File "<frozen importlib._bootstrap>", line 491, in _call_with_frames_removed
|
| 248 |
+
File "/home/codernotme/Projects/Github/katariaoptics/ai_service/app.py", line 11, in <module>
|
| 249 |
+
from detect import detect_face_shape
|
| 250 |
+
File "/home/codernotme/Projects/Github/katariaoptics/ai_service/detect.py", line 1, in <module>
|
| 251 |
+
from landmarks import get_landmarks
|
| 252 |
+
File "/home/codernotme/Projects/Github/katariaoptics/ai_service/landmarks.py", line 10, in <module>
|
| 253 |
+
import mediapipe.python.solutions.face_mesh as mp_face_mesh
|
| 254 |
+
ModuleNotFoundError: No module named 'mediapipe.python'
|
| 255 |
+
WARNING: StatReload detected changes in 'landmarks.py'. Reloading...
|
| 256 |
+
INFO: Started server process [434936]
|
| 257 |
+
INFO: Waiting for application startup.
|
| 258 |
+
INFO: Application startup complete.
|
| 259 |
+
WARNING: StatReload detected changes in 'geometry.py'. Reloading...
|
| 260 |
+
INFO: Shutting down
|
| 261 |
+
INFO: Waiting for application shutdown.
|
| 262 |
+
INFO: Application shutdown complete.
|
| 263 |
+
INFO: Finished server process [434936]
|
| 264 |
+
INFO: Started server process [434970]
|
| 265 |
+
INFO: Waiting for application startup.
|
| 266 |
+
INFO: Application startup complete.
|
| 267 |
+
WARNING: StatReload detected changes in 'detect.py'. Reloading...
|
| 268 |
+
INFO: Shutting down
|
| 269 |
+
INFO: Waiting for application shutdown.
|
| 270 |
+
INFO: Application shutdown complete.
|
| 271 |
+
INFO: Finished server process [434970]
|
| 272 |
+
INFO: Started server process [440285]
|
| 273 |
+
INFO: Waiting for application startup.
|
| 274 |
+
INFO: Application startup complete.
|
| 275 |
+
WARNING: StatReload detected changes in 'detect.py'. Reloading...
|
| 276 |
+
INFO: Shutting down
|
| 277 |
+
INFO: Waiting for application shutdown.
|
| 278 |
+
INFO: Application shutdown complete.
|
| 279 |
+
INFO: Finished server process [440285]
|
| 280 |
+
INFO: Started server process [440403]
|
| 281 |
+
INFO: Waiting for application startup.
|
| 282 |
+
INFO: Application startup complete.
|
| 283 |
+
INFO: 127.0.0.1:38906 - "GET /health HTTP/1.1" 200 OK
|
| 284 |
+
./start.sh: line 2: 433406 Killed uvicorn app:app --host 0.0.0.0 --port 8000 --reload
|
server_mock.log
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
|
|
|
| 1 |
+
INFO: Will watch for changes in these directories: ['/home/codernotme/Projects/Github/katariaoptics/ai_service']
|
| 2 |
+
ERROR: [Errno 98] Address already in use
|
server_mock_2.log
ADDED
|
@@ -0,0 +1,590 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
INFO: Will watch for changes in these directories: ['/home/codernotme/Projects/Github/katariaoptics/ai_service']
|
| 2 |
+
INFO: Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit)
|
| 3 |
+
INFO: Started reloader process [449427] using StatReload
|
| 4 |
+
INFO: Started server process [449444]
|
| 5 |
+
INFO: Waiting for application startup.
|
| 6 |
+
INFO: Application startup complete.
|
| 7 |
+
INFO: 127.0.0.1:53460 - "GET /health HTTP/1.1" 200 OK
|
| 8 |
+
INFO:app:Processing image: uploads/d00563f7-942a-41dd-9406-e968cbf3de51.jpg
|
| 9 |
+
ERROR:detect:Detection failed (using mock): Enforced MOCK mode due to Python 3.14 incompatibility
|
| 10 |
+
INFO:app:Detected face shape: Square
|
| 11 |
+
WARNING: Using mock face shape 'Square' due to library failure.
|
| 12 |
+
INFO: 127.0.0.1:38648 - "POST /recommend HTTP/1.1" 200 OK
|
| 13 |
+
INFO:app:Processing image: uploads/9683e6b9-5f86-4131-8b2b-830044b8a701.jpeg
|
| 14 |
+
ERROR:detect:Detection failed (using mock): Enforced MOCK mode due to Python 3.14 incompatibility
|
| 15 |
+
INFO:app:Detected face shape: Round
|
| 16 |
+
WARNING: Using mock face shape 'Round' due to library failure.
|
| 17 |
+
INFO: 127.0.0.1:35840 - "POST /recommend HTTP/1.1" 200 OK
|
| 18 |
+
WARNING: StatReload detected changes in 'detect.py'. Reloading...
|
| 19 |
+
INFO: Shutting down
|
| 20 |
+
INFO: Waiting for application shutdown.
|
| 21 |
+
INFO: Application shutdown complete.
|
| 22 |
+
INFO: Finished server process [449444]
|
| 23 |
+
INFO: Started server process [453875]
|
| 24 |
+
INFO: Waiting for application startup.
|
| 25 |
+
INFO: Application startup complete.
|
| 26 |
+
INFO:app:Processing image: uploads/45e6ba74-1f38-4589-866d-20ec3449e93f.webp
|
| 27 |
+
INFO:detect:Detected face shape: Oblong
|
| 28 |
+
INFO:app:Detected face shape: Oblong
|
| 29 |
+
INFO: 127.0.0.1:35992 - "POST /recommend HTTP/1.1" 200 OK
|
| 30 |
+
INFO:app:Processing image: uploads/e88a7c7f-f25e-4e3b-aec1-4d7b10ab2ae3.jpg
|
| 31 |
+
INFO:detect:Detected face shape: Oblong
|
| 32 |
+
INFO:app:Detected face shape: Oblong
|
| 33 |
+
INFO: 127.0.0.1:47182 - "POST /recommend HTTP/1.1" 200 OK
|
| 34 |
+
WARNING: StatReload detected changes in 'classifier.py'. Reloading...
|
| 35 |
+
INFO: Shutting down
|
| 36 |
+
INFO: Waiting for application shutdown.
|
| 37 |
+
INFO: Application shutdown complete.
|
| 38 |
+
INFO: Finished server process [453875]
|
| 39 |
+
INFO: Started server process [466007]
|
| 40 |
+
INFO: Waiting for application startup.
|
| 41 |
+
INFO: Application startup complete.
|
| 42 |
+
WARNING: StatReload detected changes in 'detect.py'. Reloading...
|
| 43 |
+
INFO: Shutting down
|
| 44 |
+
INFO: Waiting for application shutdown.
|
| 45 |
+
INFO: Application shutdown complete.
|
| 46 |
+
INFO: Finished server process [466007]
|
| 47 |
+
INFO: Started server process [466157]
|
| 48 |
+
INFO: Waiting for application startup.
|
| 49 |
+
INFO: Application startup complete.
|
| 50 |
+
WARNING: StatReload detected changes in 'app.py'. Reloading...
|
| 51 |
+
INFO: Shutting down
|
| 52 |
+
INFO: Waiting for application shutdown.
|
| 53 |
+
INFO: Application shutdown complete.
|
| 54 |
+
INFO: Finished server process [466157]
|
| 55 |
+
INFO: Started server process [466442]
|
| 56 |
+
INFO: Waiting for application startup.
|
| 57 |
+
INFO: Application startup complete.
|
| 58 |
+
INFO:app:Processing image: uploads/3b37116f-c5bd-459b-8d18-8834b219bf77.jpg
|
| 59 |
+
INFO:detect:Detected face shape: Oblong with probabilities: {'Oblong': np.float64(0.4518), 'Oval': np.float64(0.1806), 'Heart': np.float64(0.121), 'Diamond': np.float64(0.1095), 'Square': np.float64(0.0754), 'Round': np.float64(0.0617)}
|
| 60 |
+
INFO:app:Detected face shape: Oblong (0.4518)
|
| 61 |
+
INFO: 127.0.0.1:58160 - "POST /recommend HTTP/1.1" 200 OK
|
| 62 |
+
INFO:app:Processing image: uploads/385a3c1a-c307-476a-ba59-33ee63ad238c.webp
|
| 63 |
+
INFO:detect:Detected face shape: Oblong with probabilities: {'Oblong': np.float64(0.5095), 'Oval': np.float64(0.1535), 'Heart': np.float64(0.1029), 'Diamond': np.float64(0.0931), 'Square': np.float64(0.0846), 'Round': np.float64(0.0565)}
|
| 64 |
+
INFO:app:Detected face shape: Oblong (0.5095)
|
| 65 |
+
INFO: 127.0.0.1:41656 - "POST /recommend HTTP/1.1" 200 OK
|
| 66 |
+
INFO:app:Processing image: uploads/55292f82-0aac-496d-bcb8-481e5b0eca6e.jpg
|
| 67 |
+
INFO:detect:Detected face shape: Oblong with probabilities: {'Oblong': np.float64(0.4619), 'Oval': np.float64(0.1754), 'Heart': np.float64(0.1175), 'Diamond': np.float64(0.1064), 'Square': np.float64(0.0763), 'Round': np.float64(0.0625)}
|
| 68 |
+
INFO:app:Detected face shape: Oblong (0.4619)
|
| 69 |
+
INFO: 127.0.0.1:41672 - "POST /recommend HTTP/1.1" 200 OK
|
| 70 |
+
INFO:app:Processing image: uploads/5be790fc-d900-423d-b174-929dff668401.jpeg
|
| 71 |
+
INFO:detect:Detected face shape: Oblong with probabilities: {'Oblong': np.float64(0.4638), 'Oval': np.float64(0.1743), 'Heart': np.float64(0.1168), 'Diamond': np.float64(0.1057), 'Square': np.float64(0.0767), 'Round': np.float64(0.0628)}
|
| 72 |
+
INFO:app:Detected face shape: Oblong (0.4638)
|
| 73 |
+
INFO: 127.0.0.1:56742 - "POST /recommend HTTP/1.1" 200 OK
|
| 74 |
+
WARNING: StatReload detected changes in 'train.py'. Reloading...
|
| 75 |
+
INFO: Shutting down
|
| 76 |
+
INFO: Waiting for application shutdown.
|
| 77 |
+
INFO: Application shutdown complete.
|
| 78 |
+
INFO: Finished server process [466442]
|
| 79 |
+
INFO: Started server process [470871]
|
| 80 |
+
INFO: Waiting for application startup.
|
| 81 |
+
INFO: Application startup complete.
|
| 82 |
+
WARNING: StatReload detected changes in 'classifier.py'. Reloading...
|
| 83 |
+
INFO: Shutting down
|
| 84 |
+
INFO: Waiting for application shutdown.
|
| 85 |
+
INFO: Application shutdown complete.
|
| 86 |
+
INFO: Finished server process [470871]
|
| 87 |
+
INFO: Started server process [471707]
|
| 88 |
+
INFO: Waiting for application startup.
|
| 89 |
+
INFO: Application startup complete.
|
| 90 |
+
WARNING: StatReload detected changes in 'detect.py'. Reloading...
|
| 91 |
+
INFO: Shutting down
|
| 92 |
+
INFO: Waiting for application shutdown.
|
| 93 |
+
INFO: Application shutdown complete.
|
| 94 |
+
INFO: Finished server process [471707]
|
| 95 |
+
INFO: Started server process [472251]
|
| 96 |
+
INFO: Waiting for application startup.
|
| 97 |
+
INFO: Application startup complete.
|
| 98 |
+
WARNING: StatReload detected changes in 'train.py'. Reloading...
|
| 99 |
+
INFO: Shutting down
|
| 100 |
+
INFO: Waiting for application shutdown.
|
| 101 |
+
INFO: Application shutdown complete.
|
| 102 |
+
INFO: Finished server process [472251]
|
| 103 |
+
INFO: Started server process [473164]
|
| 104 |
+
INFO: Waiting for application startup.
|
| 105 |
+
INFO: Application startup complete.
|
| 106 |
+
WARNING: StatReload detected changes in 'classifier.py'. Reloading...
|
| 107 |
+
INFO: Shutting down
|
| 108 |
+
INFO: Waiting for application shutdown.
|
| 109 |
+
INFO: Application shutdown complete.
|
| 110 |
+
INFO: Finished server process [473164]
|
| 111 |
+
INFO: Started server process [475917]
|
| 112 |
+
INFO: Waiting for application startup.
|
| 113 |
+
INFO: Application startup complete.
|
| 114 |
+
WARNING: StatReload detected changes in 'detect.py'. Reloading...
|
| 115 |
+
INFO: Shutting down
|
| 116 |
+
INFO: Waiting for application shutdown.
|
| 117 |
+
INFO: Application shutdown complete.
|
| 118 |
+
INFO: Finished server process [475917]
|
| 119 |
+
INFO: Started server process [476076]
|
| 120 |
+
INFO: Waiting for application startup.
|
| 121 |
+
INFO: Application startup complete.
|
| 122 |
+
INFO:app:Processing image: uploads/8901022d-62a1-4c33-b7c6-17c8f2007adc.jpg
|
| 123 |
+
INFO:detect:Detected face shape: oblong for uploads/8901022d-62a1-4c33-b7c6-17c8f2007adc.jpg
|
| 124 |
+
INFO:app:Detected face shape: oblong (0.2111)
|
| 125 |
+
Loaded Mean Face vectors.
|
| 126 |
+
INFO: 127.0.0.1:55444 - "POST /recommend HTTP/1.1" 200 OK
|
| 127 |
+
INFO:app:Processing image: uploads/58318108-6d07-46b4-a93b-8a4183b46ccb.webp
|
| 128 |
+
INFO:detect:Detected face shape: round for uploads/58318108-6d07-46b4-a93b-8a4183b46ccb.webp
|
| 129 |
+
INFO:app:Detected face shape: round (0.2082)
|
| 130 |
+
INFO: 127.0.0.1:55444 - "POST /recommend HTTP/1.1" 200 OK
|
| 131 |
+
INFO:app:Processing image: uploads/3c160486-9fe6-40bc-bc98-f56b6dde3e8e.jpg
|
| 132 |
+
INFO:detect:Detected face shape: heart for uploads/3c160486-9fe6-40bc-bc98-f56b6dde3e8e.jpg
|
| 133 |
+
INFO:app:Detected face shape: heart (0.2041)
|
| 134 |
+
INFO: 127.0.0.1:51692 - "POST /recommend HTTP/1.1" 200 OK
|
| 135 |
+
INFO:app:Processing image: uploads/529b4f8d-dc6c-4195-880e-7644a1a34637.jpeg
|
| 136 |
+
INFO:detect:Detected face shape: oblong for uploads/529b4f8d-dc6c-4195-880e-7644a1a34637.jpeg
|
| 137 |
+
INFO:app:Detected face shape: oblong (0.2076)
|
| 138 |
+
INFO: 127.0.0.1:51700 - "POST /recommend HTTP/1.1" 200 OK
|
| 139 |
+
WARNING: StatReload detected changes in 'test_accuracy_simple.py'. Reloading...
|
| 140 |
+
INFO: Shutting down
|
| 141 |
+
INFO: Waiting for application shutdown.
|
| 142 |
+
INFO: Application shutdown complete.
|
| 143 |
+
INFO: Finished server process [476076]
|
| 144 |
+
INFO: Started server process [493208]
|
| 145 |
+
INFO: Waiting for application startup.
|
| 146 |
+
INFO: Application startup complete.
|
| 147 |
+
WARNING: StatReload detected changes in 'classifier.py'. Reloading...
|
| 148 |
+
INFO: Shutting down
|
| 149 |
+
INFO: Waiting for application shutdown.
|
| 150 |
+
INFO: Application shutdown complete.
|
| 151 |
+
INFO: Finished server process [493208]
|
| 152 |
+
INFO: Started server process [493836]
|
| 153 |
+
INFO: Waiting for application startup.
|
| 154 |
+
INFO: Application startup complete.
|
| 155 |
+
WARNING: StatReload detected changes in 'app.py'. Reloading...
|
| 156 |
+
INFO: Shutting down
|
| 157 |
+
INFO: Waiting for application shutdown.
|
| 158 |
+
INFO: Application shutdown complete.
|
| 159 |
+
INFO: Finished server process [493836]
|
| 160 |
+
INFO: Started server process [519286]
|
| 161 |
+
INFO: Waiting for application startup.
|
| 162 |
+
INFO: Application startup complete.
|
| 163 |
+
WARNING: StatReload detected changes in 'train_means.py'. Reloading...
|
| 164 |
+
INFO: Shutting down
|
| 165 |
+
INFO: Waiting for application shutdown.
|
| 166 |
+
INFO: Application shutdown complete.
|
| 167 |
+
INFO: Finished server process [519286]
|
| 168 |
+
INFO: Started server process [520894]
|
| 169 |
+
INFO: Waiting for application startup.
|
| 170 |
+
INFO: Application startup complete.
|
| 171 |
+
WARNING: StatReload detected changes in 'classifier.py'. Reloading...
|
| 172 |
+
INFO: Shutting down
|
| 173 |
+
INFO: Waiting for application shutdown.
|
| 174 |
+
INFO: Application shutdown complete.
|
| 175 |
+
INFO: Finished server process [520894]
|
| 176 |
+
Process SpawnProcess-16:
|
| 177 |
+
Traceback (most recent call last):
|
| 178 |
+
File "/usr/lib64/python3.14/multiprocessing/process.py", line 320, in _bootstrap
|
| 179 |
+
self.run()
|
| 180 |
+
~~~~~~~~^^
|
| 181 |
+
File "/usr/lib64/python3.14/multiprocessing/process.py", line 108, in run
|
| 182 |
+
self._target(*self._args, **self._kwargs)
|
| 183 |
+
~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| 184 |
+
File "/home/codernotme/.local/lib/python3.14/site-packages/uvicorn/_subprocess.py", line 80, in subprocess_started
|
| 185 |
+
target(sockets=sockets)
|
| 186 |
+
~~~~~~^^^^^^^^^^^^^^^^^
|
| 187 |
+
File "/home/codernotme/.local/lib/python3.14/site-packages/uvicorn/server.py", line 67, in run
|
| 188 |
+
return asyncio_run(self.serve(sockets=sockets), loop_factory=self.config.get_loop_factory())
|
| 189 |
+
File "/usr/lib64/python3.14/asyncio/runners.py", line 204, in run
|
| 190 |
+
return runner.run(main)
|
| 191 |
+
~~~~~~~~~~^^^^^^
|
| 192 |
+
File "/usr/lib64/python3.14/asyncio/runners.py", line 127, in run
|
| 193 |
+
return self._loop.run_until_complete(task)
|
| 194 |
+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^
|
| 195 |
+
File "/usr/lib64/python3.14/asyncio/base_events.py", line 719, in run_until_complete
|
| 196 |
+
return future.result()
|
| 197 |
+
~~~~~~~~~~~~~^^
|
| 198 |
+
File "/home/codernotme/.local/lib/python3.14/site-packages/uvicorn/server.py", line 71, in serve
|
| 199 |
+
await self._serve(sockets)
|
| 200 |
+
File "/home/codernotme/.local/lib/python3.14/site-packages/uvicorn/server.py", line 78, in _serve
|
| 201 |
+
config.load()
|
| 202 |
+
~~~~~~~~~~~^^
|
| 203 |
+
File "/home/codernotme/.local/lib/python3.14/site-packages/uvicorn/config.py", line 439, in load
|
| 204 |
+
self.loaded_app = import_from_string(self.app)
|
| 205 |
+
~~~~~~~~~~~~~~~~~~^^^^^^^^^^
|
| 206 |
+
File "/home/codernotme/.local/lib/python3.14/site-packages/uvicorn/importer.py", line 22, in import_from_string
|
| 207 |
+
raise exc from None
|
| 208 |
+
File "/home/codernotme/.local/lib/python3.14/site-packages/uvicorn/importer.py", line 19, in import_from_string
|
| 209 |
+
module = importlib.import_module(module_str)
|
| 210 |
+
File "/usr/lib64/python3.14/importlib/__init__.py", line 88, in import_module
|
| 211 |
+
return _bootstrap._gcd_import(name[level:], package, level)
|
| 212 |
+
~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| 213 |
+
File "<frozen importlib._bootstrap>", line 1398, in _gcd_import
|
| 214 |
+
File "<frozen importlib._bootstrap>", line 1371, in _find_and_load
|
| 215 |
+
File "<frozen importlib._bootstrap>", line 1342, in _find_and_load_unlocked
|
| 216 |
+
File "<frozen importlib._bootstrap>", line 938, in _load_unlocked
|
| 217 |
+
File "<frozen importlib._bootstrap_external>", line 759, in exec_module
|
| 218 |
+
File "<frozen importlib._bootstrap>", line 491, in _call_with_frames_removed
|
| 219 |
+
File "/home/codernotme/Projects/Github/katariaoptics/ai_service/app.py", line 12, in <module>
|
| 220 |
+
from recommend import get_recommendations
|
| 221 |
+
File "/home/codernotme/Projects/Github/katariaoptics/ai_service/recommend.py", line 3, in <module>
|
| 222 |
+
from classifier import classify_face_shape
|
| 223 |
+
File "/home/codernotme/Projects/Github/katariaoptics/ai_service/classifier.py", line 1, in <module>
|
| 224 |
+
from huggingface_hub import hf_hub_download
|
| 225 |
+
ModuleNotFoundError: No module named 'huggingface_hub'
|
| 226 |
+
WARNING: StatReload detected changes in 'landmarks.py'. Reloading...
|
| 227 |
+
Process SpawnProcess-17:
|
| 228 |
+
Traceback (most recent call last):
|
| 229 |
+
File "/usr/lib64/python3.14/multiprocessing/process.py", line 320, in _bootstrap
|
| 230 |
+
self.run()
|
| 231 |
+
~~~~~~~~^^
|
| 232 |
+
File "/usr/lib64/python3.14/multiprocessing/process.py", line 108, in run
|
| 233 |
+
self._target(*self._args, **self._kwargs)
|
| 234 |
+
~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| 235 |
+
File "/home/codernotme/.local/lib/python3.14/site-packages/uvicorn/_subprocess.py", line 80, in subprocess_started
|
| 236 |
+
target(sockets=sockets)
|
| 237 |
+
~~~~~~^^^^^^^^^^^^^^^^^
|
| 238 |
+
File "/home/codernotme/.local/lib/python3.14/site-packages/uvicorn/server.py", line 67, in run
|
| 239 |
+
return asyncio_run(self.serve(sockets=sockets), loop_factory=self.config.get_loop_factory())
|
| 240 |
+
File "/usr/lib64/python3.14/asyncio/runners.py", line 204, in run
|
| 241 |
+
return runner.run(main)
|
| 242 |
+
~~~~~~~~~~^^^^^^
|
| 243 |
+
File "/usr/lib64/python3.14/asyncio/runners.py", line 127, in run
|
| 244 |
+
return self._loop.run_until_complete(task)
|
| 245 |
+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^
|
| 246 |
+
File "/usr/lib64/python3.14/asyncio/base_events.py", line 719, in run_until_complete
|
| 247 |
+
return future.result()
|
| 248 |
+
~~~~~~~~~~~~~^^
|
| 249 |
+
File "/home/codernotme/.local/lib/python3.14/site-packages/uvicorn/server.py", line 71, in serve
|
| 250 |
+
await self._serve(sockets)
|
| 251 |
+
File "/home/codernotme/.local/lib/python3.14/site-packages/uvicorn/server.py", line 78, in _serve
|
| 252 |
+
config.load()
|
| 253 |
+
~~~~~~~~~~~^^
|
| 254 |
+
File "/home/codernotme/.local/lib/python3.14/site-packages/uvicorn/config.py", line 439, in load
|
| 255 |
+
self.loaded_app = import_from_string(self.app)
|
| 256 |
+
~~~~~~~~~~~~~~~~~~^^^^^^^^^^
|
| 257 |
+
File "/home/codernotme/.local/lib/python3.14/site-packages/uvicorn/importer.py", line 22, in import_from_string
|
| 258 |
+
raise exc from None
|
| 259 |
+
File "/home/codernotme/.local/lib/python3.14/site-packages/uvicorn/importer.py", line 19, in import_from_string
|
| 260 |
+
module = importlib.import_module(module_str)
|
| 261 |
+
File "/usr/lib64/python3.14/importlib/__init__.py", line 88, in import_module
|
| 262 |
+
return _bootstrap._gcd_import(name[level:], package, level)
|
| 263 |
+
~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| 264 |
+
File "<frozen importlib._bootstrap>", line 1398, in _gcd_import
|
| 265 |
+
File "<frozen importlib._bootstrap>", line 1371, in _find_and_load
|
| 266 |
+
File "<frozen importlib._bootstrap>", line 1342, in _find_and_load_unlocked
|
| 267 |
+
File "<frozen importlib._bootstrap>", line 938, in _load_unlocked
|
| 268 |
+
File "<frozen importlib._bootstrap_external>", line 759, in exec_module
|
| 269 |
+
File "<frozen importlib._bootstrap>", line 491, in _call_with_frames_removed
|
| 270 |
+
File "/home/codernotme/Projects/Github/katariaoptics/ai_service/app.py", line 12, in <module>
|
| 271 |
+
from recommend import get_recommendations
|
| 272 |
+
File "/home/codernotme/Projects/Github/katariaoptics/ai_service/recommend.py", line 1, in <module>
|
| 273 |
+
from landmarks import get_landmarks
|
| 274 |
+
File "/home/codernotme/Projects/Github/katariaoptics/ai_service/landmarks.py", line 6, in <module>
|
| 275 |
+
from huggingface_hub import hf_hub_download
|
| 276 |
+
ModuleNotFoundError: No module named 'huggingface_hub'
|
| 277 |
+
WARNING: StatReload detected changes in 'classifier.py'. Reloading...
|
| 278 |
+
Process SpawnProcess-18:
|
| 279 |
+
Traceback (most recent call last):
|
| 280 |
+
File "/usr/lib64/python3.14/multiprocessing/process.py", line 320, in _bootstrap
|
| 281 |
+
self.run()
|
| 282 |
+
~~~~~~~~^^
|
| 283 |
+
File "/usr/lib64/python3.14/multiprocessing/process.py", line 108, in run
|
| 284 |
+
self._target(*self._args, **self._kwargs)
|
| 285 |
+
~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| 286 |
+
File "/home/codernotme/.local/lib/python3.14/site-packages/uvicorn/_subprocess.py", line 80, in subprocess_started
|
| 287 |
+
target(sockets=sockets)
|
| 288 |
+
~~~~~~^^^^^^^^^^^^^^^^^
|
| 289 |
+
File "/home/codernotme/.local/lib/python3.14/site-packages/uvicorn/server.py", line 67, in run
|
| 290 |
+
return asyncio_run(self.serve(sockets=sockets), loop_factory=self.config.get_loop_factory())
|
| 291 |
+
File "/usr/lib64/python3.14/asyncio/runners.py", line 204, in run
|
| 292 |
+
return runner.run(main)
|
| 293 |
+
~~~~~~~~~~^^^^^^
|
| 294 |
+
File "/usr/lib64/python3.14/asyncio/runners.py", line 127, in run
|
| 295 |
+
return self._loop.run_until_complete(task)
|
| 296 |
+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^
|
| 297 |
+
File "/usr/lib64/python3.14/asyncio/base_events.py", line 719, in run_until_complete
|
| 298 |
+
return future.result()
|
| 299 |
+
~~~~~~~~~~~~~^^
|
| 300 |
+
File "/home/codernotme/.local/lib/python3.14/site-packages/uvicorn/server.py", line 71, in serve
|
| 301 |
+
await self._serve(sockets)
|
| 302 |
+
File "/home/codernotme/.local/lib/python3.14/site-packages/uvicorn/server.py", line 78, in _serve
|
| 303 |
+
config.load()
|
| 304 |
+
~~~~~~~~~~~^^
|
| 305 |
+
File "/home/codernotme/.local/lib/python3.14/site-packages/uvicorn/config.py", line 439, in load
|
| 306 |
+
self.loaded_app = import_from_string(self.app)
|
| 307 |
+
~~~~~~~~~~~~~~~~~~^^^^^^^^^^
|
| 308 |
+
File "/home/codernotme/.local/lib/python3.14/site-packages/uvicorn/importer.py", line 22, in import_from_string
|
| 309 |
+
raise exc from None
|
| 310 |
+
File "/home/codernotme/.local/lib/python3.14/site-packages/uvicorn/importer.py", line 19, in import_from_string
|
| 311 |
+
module = importlib.import_module(module_str)
|
| 312 |
+
File "/usr/lib64/python3.14/importlib/__init__.py", line 88, in import_module
|
| 313 |
+
return _bootstrap._gcd_import(name[level:], package, level)
|
| 314 |
+
~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| 315 |
+
File "<frozen importlib._bootstrap>", line 1398, in _gcd_import
|
| 316 |
+
File "<frozen importlib._bootstrap>", line 1371, in _find_and_load
|
| 317 |
+
File "<frozen importlib._bootstrap>", line 1342, in _find_and_load_unlocked
|
| 318 |
+
File "<frozen importlib._bootstrap>", line 938, in _load_unlocked
|
| 319 |
+
File "<frozen importlib._bootstrap_external>", line 759, in exec_module
|
| 320 |
+
File "<frozen importlib._bootstrap>", line 491, in _call_with_frames_removed
|
| 321 |
+
File "/home/codernotme/Projects/Github/katariaoptics/ai_service/app.py", line 12, in <module>
|
| 322 |
+
from recommend import get_recommendations
|
| 323 |
+
File "/home/codernotme/Projects/Github/katariaoptics/ai_service/recommend.py", line 1, in <module>
|
| 324 |
+
from landmarks import get_landmarks
|
| 325 |
+
File "/home/codernotme/Projects/Github/katariaoptics/ai_service/landmarks.py", line 6, in <module>
|
| 326 |
+
from huggingface_hub import hf_hub_download
|
| 327 |
+
ModuleNotFoundError: No module named 'huggingface_hub'
|
| 328 |
+
WARNING: StatReload detected changes in 'app.py'. Reloading...
|
| 329 |
+
Process SpawnProcess-19:
|
| 330 |
+
Traceback (most recent call last):
|
| 331 |
+
File "/usr/lib64/python3.14/multiprocessing/process.py", line 320, in _bootstrap
|
| 332 |
+
self.run()
|
| 333 |
+
~~~~~~~~^^
|
| 334 |
+
File "/usr/lib64/python3.14/multiprocessing/process.py", line 108, in run
|
| 335 |
+
self._target(*self._args, **self._kwargs)
|
| 336 |
+
~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| 337 |
+
File "/home/codernotme/.local/lib/python3.14/site-packages/uvicorn/_subprocess.py", line 80, in subprocess_started
|
| 338 |
+
target(sockets=sockets)
|
| 339 |
+
~~~~~~^^^^^^^^^^^^^^^^^
|
| 340 |
+
File "/home/codernotme/.local/lib/python3.14/site-packages/uvicorn/server.py", line 67, in run
|
| 341 |
+
return asyncio_run(self.serve(sockets=sockets), loop_factory=self.config.get_loop_factory())
|
| 342 |
+
File "/usr/lib64/python3.14/asyncio/runners.py", line 204, in run
|
| 343 |
+
return runner.run(main)
|
| 344 |
+
~~~~~~~~~~^^^^^^
|
| 345 |
+
File "/usr/lib64/python3.14/asyncio/runners.py", line 127, in run
|
| 346 |
+
return self._loop.run_until_complete(task)
|
| 347 |
+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^
|
| 348 |
+
File "/usr/lib64/python3.14/asyncio/base_events.py", line 719, in run_until_complete
|
| 349 |
+
return future.result()
|
| 350 |
+
~~~~~~~~~~~~~^^
|
| 351 |
+
File "/home/codernotme/.local/lib/python3.14/site-packages/uvicorn/server.py", line 71, in serve
|
| 352 |
+
await self._serve(sockets)
|
| 353 |
+
File "/home/codernotme/.local/lib/python3.14/site-packages/uvicorn/server.py", line 78, in _serve
|
| 354 |
+
config.load()
|
| 355 |
+
~~~~~~~~~~~^^
|
| 356 |
+
File "/home/codernotme/.local/lib/python3.14/site-packages/uvicorn/config.py", line 439, in load
|
| 357 |
+
self.loaded_app = import_from_string(self.app)
|
| 358 |
+
~~~~~~~~~~~~~~~~~~^^^^^^^^^^
|
| 359 |
+
File "/home/codernotme/.local/lib/python3.14/site-packages/uvicorn/importer.py", line 22, in import_from_string
|
| 360 |
+
raise exc from None
|
| 361 |
+
File "/home/codernotme/.local/lib/python3.14/site-packages/uvicorn/importer.py", line 19, in import_from_string
|
| 362 |
+
module = importlib.import_module(module_str)
|
| 363 |
+
File "/usr/lib64/python3.14/importlib/__init__.py", line 88, in import_module
|
| 364 |
+
return _bootstrap._gcd_import(name[level:], package, level)
|
| 365 |
+
~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| 366 |
+
File "<frozen importlib._bootstrap>", line 1398, in _gcd_import
|
| 367 |
+
File "<frozen importlib._bootstrap>", line 1371, in _find_and_load
|
| 368 |
+
File "<frozen importlib._bootstrap>", line 1342, in _find_and_load_unlocked
|
| 369 |
+
File "<frozen importlib._bootstrap>", line 938, in _load_unlocked
|
| 370 |
+
File "<frozen importlib._bootstrap_external>", line 759, in exec_module
|
| 371 |
+
File "<frozen importlib._bootstrap>", line 491, in _call_with_frames_removed
|
| 372 |
+
File "/home/codernotme/Projects/Github/katariaoptics/ai_service/app.py", line 12, in <module>
|
| 373 |
+
from recommend import get_recommendations
|
| 374 |
+
File "/home/codernotme/Projects/Github/katariaoptics/ai_service/recommend.py", line 1, in <module>
|
| 375 |
+
from landmarks import get_landmarks
|
| 376 |
+
File "/home/codernotme/Projects/Github/katariaoptics/ai_service/landmarks.py", line 6, in <module>
|
| 377 |
+
from huggingface_hub import hf_hub_download
|
| 378 |
+
ModuleNotFoundError: No module named 'huggingface_hub'
|
| 379 |
+
WARNING: StatReload detected changes in 'app.py'. Reloading...
|
| 380 |
+
INFO: Started server process [525740]
|
| 381 |
+
INFO: Waiting for application startup.
|
| 382 |
+
INFO: Application startup complete.
|
| 383 |
+
WARNING: StatReload detected changes in 'hf_upload.py'. Reloading...
|
| 384 |
+
INFO: Shutting down
|
| 385 |
+
INFO: Waiting for application shutdown.
|
| 386 |
+
INFO: Application shutdown complete.
|
| 387 |
+
INFO: Finished server process [525740]
|
| 388 |
+
WARNING: StatReload detected changes in 'classifier.py'. Reloading...
|
| 389 |
+
Process SpawnProcess-21:
|
| 390 |
+
Traceback (most recent call last):
|
| 391 |
+
File "/usr/lib64/python3.14/multiprocessing/process.py", line 320, in _bootstrap
|
| 392 |
+
self.run()
|
| 393 |
+
~~~~~~~~^^
|
| 394 |
+
File "/usr/lib64/python3.14/multiprocessing/process.py", line 108, in run
|
| 395 |
+
self._target(*self._args, **self._kwargs)
|
| 396 |
+
~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| 397 |
+
File "/home/codernotme/.local/lib/python3.14/site-packages/uvicorn/_subprocess.py", line 80, in subprocess_started
|
| 398 |
+
target(sockets=sockets)
|
| 399 |
+
~~~~~~^^^^^^^^^^^^^^^^^
|
| 400 |
+
File "/home/codernotme/.local/lib/python3.14/site-packages/uvicorn/server.py", line 67, in run
|
| 401 |
+
return asyncio_run(self.serve(sockets=sockets), loop_factory=self.config.get_loop_factory())
|
| 402 |
+
File "/usr/lib64/python3.14/asyncio/runners.py", line 204, in run
|
| 403 |
+
return runner.run(main)
|
| 404 |
+
~~~~~~~~~~^^^^^^
|
| 405 |
+
File "/usr/lib64/python3.14/asyncio/runners.py", line 127, in run
|
| 406 |
+
return self._loop.run_until_complete(task)
|
| 407 |
+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^
|
| 408 |
+
File "/usr/lib64/python3.14/asyncio/base_events.py", line 719, in run_until_complete
|
| 409 |
+
return future.result()
|
| 410 |
+
~~~~~~~~~~~~~^^
|
| 411 |
+
File "/home/codernotme/.local/lib/python3.14/site-packages/uvicorn/server.py", line 71, in serve
|
| 412 |
+
await self._serve(sockets)
|
| 413 |
+
File "/home/codernotme/.local/lib/python3.14/site-packages/uvicorn/server.py", line 78, in _serve
|
| 414 |
+
config.load()
|
| 415 |
+
~~~~~~~~~~~^^
|
| 416 |
+
File "/home/codernotme/.local/lib/python3.14/site-packages/uvicorn/config.py", line 439, in load
|
| 417 |
+
self.loaded_app = import_from_string(self.app)
|
| 418 |
+
~~~~~~~~~~~~~~~~~~^^^^^^^^^^
|
| 419 |
+
File "/home/codernotme/.local/lib/python3.14/site-packages/uvicorn/importer.py", line 22, in import_from_string
|
| 420 |
+
raise exc from None
|
| 421 |
+
File "/home/codernotme/.local/lib/python3.14/site-packages/uvicorn/importer.py", line 19, in import_from_string
|
| 422 |
+
module = importlib.import_module(module_str)
|
| 423 |
+
File "/usr/lib64/python3.14/importlib/__init__.py", line 88, in import_module
|
| 424 |
+
return _bootstrap._gcd_import(name[level:], package, level)
|
| 425 |
+
~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| 426 |
+
File "<frozen importlib._bootstrap>", line 1398, in _gcd_import
|
| 427 |
+
File "<frozen importlib._bootstrap>", line 1371, in _find_and_load
|
| 428 |
+
File "<frozen importlib._bootstrap>", line 1342, in _find_and_load_unlocked
|
| 429 |
+
File "<frozen importlib._bootstrap>", line 938, in _load_unlocked
|
| 430 |
+
File "<frozen importlib._bootstrap_external>", line 759, in exec_module
|
| 431 |
+
File "<frozen importlib._bootstrap>", line 491, in _call_with_frames_removed
|
| 432 |
+
File "/home/codernotme/Projects/Github/katariaoptics/ai_service/app.py", line 12, in <module>
|
| 433 |
+
from recommend import get_recommendations
|
| 434 |
+
File "/home/codernotme/Projects/Github/katariaoptics/ai_service/recommend.py", line 3, in <module>
|
| 435 |
+
from classifier import classify_face_shape
|
| 436 |
+
File "/home/codernotme/Projects/Github/katariaoptics/ai_service/classifier.py", line 5, in <module>
|
| 437 |
+
from huggingface_hub import hf_hub_download
|
| 438 |
+
ModuleNotFoundError: No module named 'huggingface_hub'
|
| 439 |
+
Process SpawnProcess-22:
|
| 440 |
+
Traceback (most recent call last):
|
| 441 |
+
File "/usr/lib64/python3.14/multiprocessing/process.py", line 320, in _bootstrap
|
| 442 |
+
self.run()
|
| 443 |
+
~~~~~~~~^^
|
| 444 |
+
File "/usr/lib64/python3.14/multiprocessing/process.py", line 108, in run
|
| 445 |
+
self._target(*self._args, **self._kwargs)
|
| 446 |
+
~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| 447 |
+
File "/home/codernotme/.local/lib/python3.14/site-packages/uvicorn/_subprocess.py", line 80, in subprocess_started
|
| 448 |
+
target(sockets=sockets)
|
| 449 |
+
~~~~~~^^^^^^^^^^^^^^^^^
|
| 450 |
+
File "/home/codernotme/.local/lib/python3.14/site-packages/uvicorn/server.py", line 67, in run
|
| 451 |
+
return asyncio_run(self.serve(sockets=sockets), loop_factory=self.config.get_loop_factory())
|
| 452 |
+
File "/usr/lib64/python3.14/asyncio/runners.py", line 204, in run
|
| 453 |
+
return runner.run(main)
|
| 454 |
+
~~~~~~~~~~^^^^^^
|
| 455 |
+
File "/usr/lib64/python3.14/asyncio/runners.py", line 127, in run
|
| 456 |
+
return self._loop.run_until_complete(task)
|
| 457 |
+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^
|
| 458 |
+
File "/usr/lib64/python3.14/asyncio/base_events.py", line 719, in run_until_complete
|
| 459 |
+
return future.result()
|
| 460 |
+
~~~~~~~~~~~~~^^
|
| 461 |
+
File "/home/codernotme/.local/lib/python3.14/site-packages/uvicorn/server.py", line 71, in serve
|
| 462 |
+
await self._serve(sockets)
|
| 463 |
+
File "/home/codernotme/.local/lib/python3.14/site-packages/uvicorn/server.py", line 78, in _serve
|
| 464 |
+
config.load()
|
| 465 |
+
~~~~~~~~~~~^^
|
| 466 |
+
File "/home/codernotme/.local/lib/python3.14/site-packages/uvicorn/config.py", line 439, in load
|
| 467 |
+
self.loaded_app = import_from_string(self.app)
|
| 468 |
+
~~~~~~~~~~~~~~~~~~^^^^^^^^^^
|
| 469 |
+
File "/home/codernotme/.local/lib/python3.14/site-packages/uvicorn/importer.py", line 22, in import_from_string
|
| 470 |
+
raise exc from None
|
| 471 |
+
File "/home/codernotme/.local/lib/python3.14/site-packages/uvicorn/importer.py", line 19, in import_from_string
|
| 472 |
+
module = importlib.import_module(module_str)
|
| 473 |
+
File "/usr/lib64/python3.14/importlib/__init__.py", line 88, in import_module
|
| 474 |
+
return _bootstrap._gcd_import(name[level:], package, level)
|
| 475 |
+
~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| 476 |
+
File "<frozen importlib._bootstrap>", line 1398, in _gcd_import
|
| 477 |
+
File "<frozen importlib._bootstrap>", line 1371, in _find_and_load
|
| 478 |
+
File "<frozen importlib._bootstrap>", line 1342, in _find_and_load_unlocked
|
| 479 |
+
File "<frozen importlib._bootstrap>", line 938, in _load_unlocked
|
| 480 |
+
File "<frozen importlib._bootstrap_external>", line 759, in exec_module
|
| 481 |
+
File "<frozen importlib._bootstrap>", line 491, in _call_with_frames_removed
|
| 482 |
+
File "/home/codernotme/Projects/Github/katariaoptics/ai_service/app.py", line 12, in <module>
|
| 483 |
+
from recommend import get_recommendations
|
| 484 |
+
File "/home/codernotme/Projects/Github/katariaoptics/ai_service/recommend.py", line 3, in <module>
|
| 485 |
+
from classifier import classify_face_shape
|
| 486 |
+
File "/home/codernotme/Projects/Github/katariaoptics/ai_service/classifier.py", line 5, in <module>
|
| 487 |
+
from huggingface_hub import hf_hub_download
|
| 488 |
+
ModuleNotFoundError: No module named 'huggingface_hub'
|
| 489 |
+
WARNING: StatReload detected changes in 'landmarks.py'. Reloading...
|
| 490 |
+
Process SpawnProcess-23:
|
| 491 |
+
Traceback (most recent call last):
|
| 492 |
+
File "/usr/lib64/python3.14/multiprocessing/process.py", line 320, in _bootstrap
|
| 493 |
+
self.run()
|
| 494 |
+
~~~~~~~~^^
|
| 495 |
+
File "/usr/lib64/python3.14/multiprocessing/process.py", line 108, in run
|
| 496 |
+
self._target(*self._args, **self._kwargs)
|
| 497 |
+
~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| 498 |
+
File "/home/codernotme/.local/lib/python3.14/site-packages/uvicorn/_subprocess.py", line 80, in subprocess_started
|
| 499 |
+
target(sockets=sockets)
|
| 500 |
+
~~~~~~^^^^^^^^^^^^^^^^^
|
| 501 |
+
File "/home/codernotme/.local/lib/python3.14/site-packages/uvicorn/server.py", line 67, in run
|
| 502 |
+
return asyncio_run(self.serve(sockets=sockets), loop_factory=self.config.get_loop_factory())
|
| 503 |
+
File "/usr/lib64/python3.14/asyncio/runners.py", line 204, in run
|
| 504 |
+
return runner.run(main)
|
| 505 |
+
~~~~~~~~~~^^^^^^
|
| 506 |
+
File "/usr/lib64/python3.14/asyncio/runners.py", line 127, in run
|
| 507 |
+
return self._loop.run_until_complete(task)
|
| 508 |
+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^
|
| 509 |
+
File "/usr/lib64/python3.14/asyncio/base_events.py", line 719, in run_until_complete
|
| 510 |
+
return future.result()
|
| 511 |
+
~~~~~~~~~~~~~^^
|
| 512 |
+
File "/home/codernotme/.local/lib/python3.14/site-packages/uvicorn/server.py", line 71, in serve
|
| 513 |
+
await self._serve(sockets)
|
| 514 |
+
File "/home/codernotme/.local/lib/python3.14/site-packages/uvicorn/server.py", line 78, in _serve
|
| 515 |
+
config.load()
|
| 516 |
+
~~~~~~~~~~~^^
|
| 517 |
+
File "/home/codernotme/.local/lib/python3.14/site-packages/uvicorn/config.py", line 439, in load
|
| 518 |
+
self.loaded_app = import_from_string(self.app)
|
| 519 |
+
~~~~~~~~~~~~~~~~~~^^^^^^^^^^
|
| 520 |
+
File "/home/codernotme/.local/lib/python3.14/site-packages/uvicorn/importer.py", line 22, in import_from_string
|
| 521 |
+
raise exc from None
|
| 522 |
+
File "/home/codernotme/.local/lib/python3.14/site-packages/uvicorn/importer.py", line 19, in import_from_string
|
| 523 |
+
module = importlib.import_module(module_str)
|
| 524 |
+
File "/usr/lib64/python3.14/importlib/__init__.py", line 88, in import_module
|
| 525 |
+
return _bootstrap._gcd_import(name[level:], package, level)
|
| 526 |
+
~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| 527 |
+
File "<frozen importlib._bootstrap>", line 1398, in _gcd_import
|
| 528 |
+
File "<frozen importlib._bootstrap>", line 1371, in _find_and_load
|
| 529 |
+
File "<frozen importlib._bootstrap>", line 1342, in _find_and_load_unlocked
|
| 530 |
+
File "<frozen importlib._bootstrap>", line 938, in _load_unlocked
|
| 531 |
+
File "<frozen importlib._bootstrap_external>", line 759, in exec_module
|
| 532 |
+
File "<frozen importlib._bootstrap>", line 491, in _call_with_frames_removed
|
| 533 |
+
File "/home/codernotme/Projects/Github/katariaoptics/ai_service/app.py", line 12, in <module>
|
| 534 |
+
from recommend import get_recommendations
|
| 535 |
+
File "/home/codernotme/Projects/Github/katariaoptics/ai_service/recommend.py", line 1, in <module>
|
| 536 |
+
from landmarks import get_landmarks
|
| 537 |
+
File "/home/codernotme/Projects/Github/katariaoptics/ai_service/landmarks.py", line 5, in <module>
|
| 538 |
+
from huggingface_hub import hf_hub_download
|
| 539 |
+
ModuleNotFoundError: No module named 'huggingface_hub'
|
| 540 |
+
WARNING: StatReload detected changes in 'app.py'. Reloading...
|
| 541 |
+
Process SpawnProcess-24:
|
| 542 |
+
Traceback (most recent call last):
|
| 543 |
+
File "/usr/lib64/python3.14/multiprocessing/process.py", line 320, in _bootstrap
|
| 544 |
+
self.run()
|
| 545 |
+
~~~~~~~~^^
|
| 546 |
+
File "/usr/lib64/python3.14/multiprocessing/process.py", line 108, in run
|
| 547 |
+
self._target(*self._args, **self._kwargs)
|
| 548 |
+
~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| 549 |
+
File "/home/codernotme/.local/lib/python3.14/site-packages/uvicorn/_subprocess.py", line 80, in subprocess_started
|
| 550 |
+
target(sockets=sockets)
|
| 551 |
+
~~~~~~^^^^^^^^^^^^^^^^^
|
| 552 |
+
File "/home/codernotme/.local/lib/python3.14/site-packages/uvicorn/server.py", line 67, in run
|
| 553 |
+
return asyncio_run(self.serve(sockets=sockets), loop_factory=self.config.get_loop_factory())
|
| 554 |
+
File "/usr/lib64/python3.14/asyncio/runners.py", line 204, in run
|
| 555 |
+
return runner.run(main)
|
| 556 |
+
~~~~~~~~~~^^^^^^
|
| 557 |
+
File "/usr/lib64/python3.14/asyncio/runners.py", line 127, in run
|
| 558 |
+
return self._loop.run_until_complete(task)
|
| 559 |
+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^
|
| 560 |
+
File "/usr/lib64/python3.14/asyncio/base_events.py", line 719, in run_until_complete
|
| 561 |
+
return future.result()
|
| 562 |
+
~~~~~~~~~~~~~^^
|
| 563 |
+
File "/home/codernotme/.local/lib/python3.14/site-packages/uvicorn/server.py", line 71, in serve
|
| 564 |
+
await self._serve(sockets)
|
| 565 |
+
File "/home/codernotme/.local/lib/python3.14/site-packages/uvicorn/server.py", line 78, in _serve
|
| 566 |
+
config.load()
|
| 567 |
+
~~~~~~~~~~~^^
|
| 568 |
+
File "/home/codernotme/.local/lib/python3.14/site-packages/uvicorn/config.py", line 439, in load
|
| 569 |
+
self.loaded_app = import_from_string(self.app)
|
| 570 |
+
~~~~~~~~~~~~~~~~~~^^^^^^^^^^
|
| 571 |
+
File "/home/codernotme/.local/lib/python3.14/site-packages/uvicorn/importer.py", line 22, in import_from_string
|
| 572 |
+
raise exc from None
|
| 573 |
+
File "/home/codernotme/.local/lib/python3.14/site-packages/uvicorn/importer.py", line 19, in import_from_string
|
| 574 |
+
module = importlib.import_module(module_str)
|
| 575 |
+
File "/usr/lib64/python3.14/importlib/__init__.py", line 88, in import_module
|
| 576 |
+
return _bootstrap._gcd_import(name[level:], package, level)
|
| 577 |
+
~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| 578 |
+
File "<frozen importlib._bootstrap>", line 1398, in _gcd_import
|
| 579 |
+
File "<frozen importlib._bootstrap>", line 1371, in _find_and_load
|
| 580 |
+
File "<frozen importlib._bootstrap>", line 1342, in _find_and_load_unlocked
|
| 581 |
+
File "<frozen importlib._bootstrap>", line 938, in _load_unlocked
|
| 582 |
+
File "<frozen importlib._bootstrap_external>", line 759, in exec_module
|
| 583 |
+
File "<frozen importlib._bootstrap>", line 491, in _call_with_frames_removed
|
| 584 |
+
File "/home/codernotme/Projects/Github/katariaoptics/ai_service/app.py", line 12, in <module>
|
| 585 |
+
from recommend import get_recommendations
|
| 586 |
+
File "/home/codernotme/Projects/Github/katariaoptics/ai_service/recommend.py", line 1, in <module>
|
| 587 |
+
from landmarks import get_landmarks
|
| 588 |
+
File "/home/codernotme/Projects/Github/katariaoptics/ai_service/landmarks.py", line 5, in <module>
|
| 589 |
+
from huggingface_hub import hf_hub_download
|
| 590 |
+
ModuleNotFoundError: No module named 'huggingface_hub'
|
start.sh
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/bin/bash
|
| 2 |
+
uvicorn app:app --host 0.0.0.0 --port 8000 --reload
|
start_and_setup.sh
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/bin/bash
|
| 2 |
+
echo "Installing dependencies..."
|
| 3 |
+
pip install -r requirements.txt
|
| 4 |
+
if [ $? -eq 0 ]; then
|
| 5 |
+
echo "Dependencies installed successfully."
|
| 6 |
+
|
| 7 |
+
echo "Training model on dataset..."
|
| 8 |
+
python3 train_model.py
|
| 9 |
+
|
| 10 |
+
echo "Starting server..."
|
| 11 |
+
./start.sh
|
| 12 |
+
else
|
| 13 |
+
echo "Failed to install dependencies."
|
| 14 |
+
exit 1
|
| 15 |
+
fi
|
test_accuracy.py
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import sys
|
| 3 |
+
from detect import detect_face_shape
|
| 4 |
+
|
| 5 |
+
# Configuration
|
| 6 |
+
TEST_DATASET_DIR = "/home/codernotme/Projects/Github/katariaoptics/dataset/test"
|
| 7 |
+
|
| 8 |
+
def test_accuracy():
|
| 9 |
+
print(f"Testing accuracy using dataset at: {TEST_DATASET_DIR}")
|
| 10 |
+
|
| 11 |
+
if not os.path.exists(TEST_DATASET_DIR):
|
| 12 |
+
print("Test dataset directory not found.")
|
| 13 |
+
return
|
| 14 |
+
|
| 15 |
+
total_images = 0
|
| 16 |
+
correct_predictions = 0
|
| 17 |
+
class_stats = {}
|
| 18 |
+
|
| 19 |
+
# Get list of classes (subdirectories)
|
| 20 |
+
classes = [d for d in os.listdir(TEST_DATASET_DIR) if os.path.isdir(os.path.join(TEST_DATASET_DIR, d))]
|
| 21 |
+
|
| 22 |
+
for label in classes:
|
| 23 |
+
folder_path = os.path.join(TEST_DATASET_DIR, label)
|
| 24 |
+
files = os.listdir(folder_path)
|
| 25 |
+
|
| 26 |
+
# Ground truth label (normalize to lowercase to match model classes if needed,
|
| 27 |
+
# though detect.py returns capitalized keys usually? Let's check model keys.)
|
| 28 |
+
# The model uses "heart", "oblong" etc. (lowercase) as keys in the pickle from train_means.py
|
| 29 |
+
# BUT detect.py / classifier.py capitalizes the keys in the return dict.
|
| 30 |
+
# Let's verify what classifier.py returns.
|
| 31 |
+
# classifier.py: return dict(sorted(probabilities.items()...)) where keys are labels.
|
| 32 |
+
# In train_means.py, keys are "heart", "oblong"... (lowercase).
|
| 33 |
+
# In classifier.py, it constructs the dict from the `means` keys.
|
| 34 |
+
# So classifier.py returns lowercase keys like "heart", "oblong".
|
| 35 |
+
# Wait, let me double check classifier.py content.
|
| 36 |
+
|
| 37 |
+
ground_truth = label.lower()
|
| 38 |
+
|
| 39 |
+
class_stats[ground_truth] = {"total": 0, "correct": 0}
|
| 40 |
+
|
| 41 |
+
print(f"Processing class {label} (Ground Truth: {ground_truth})...")
|
| 42 |
+
|
| 43 |
+
for filename in files:
|
| 44 |
+
img_path = os.path.join(folder_path, filename)
|
| 45 |
+
try:
|
| 46 |
+
# Run detection
|
| 47 |
+
result = detect_face_shape(img_path)
|
| 48 |
+
|
| 49 |
+
# Get predicted label (highest probability)
|
| 50 |
+
# detect.py returns dict like {'heart': 0.8, 'oval': 0.2}
|
| 51 |
+
if not result or "Error" in result or "Unknown" in result:
|
| 52 |
+
continue
|
| 53 |
+
|
| 54 |
+
predicted_label = list(result.keys())[0].lower()
|
| 55 |
+
|
| 56 |
+
total_images += 1
|
| 57 |
+
class_stats[ground_truth]["total"] += 1
|
| 58 |
+
|
| 59 |
+
if predicted_label == ground_truth:
|
| 60 |
+
correct_predictions += 1
|
| 61 |
+
class_stats[ground_truth]["correct"] += 1
|
| 62 |
+
|
| 63 |
+
except Exception as e:
|
| 64 |
+
# print(f"Error processing {filename}: {e}")
|
| 65 |
+
pass
|
| 66 |
+
|
| 67 |
+
if total_images == 0:
|
| 68 |
+
print("No images found or processed.")
|
| 69 |
+
return
|
| 70 |
+
|
| 71 |
+
print("\n--- Results ---")
|
| 72 |
+
print(f"Overall Accuracy: {correct_predictions}/{total_images} ({correct_predictions/total_images*100:.2f}%)")
|
| 73 |
+
|
| 74 |
+
print("\nPer Class Accuracy:")
|
| 75 |
+
for cls, stats in class_stats.items():
|
| 76 |
+
if stats["total"] > 0:
|
| 77 |
+
acc = stats["correct"] / stats["total"] * 100
|
| 78 |
+
print(f" {cls}: {stats['correct']}/{stats['total']} ({acc:.2f}%)")
|
| 79 |
+
else:
|
| 80 |
+
print(f" {cls}: No images")
|
| 81 |
+
|
| 82 |
+
if __name__ == "__main__":
|
| 83 |
+
test_accuracy()
|
test_accuracy_simple.py
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import sys
|
| 3 |
+
|
| 4 |
+
# Ensure we can import from current directory
|
| 5 |
+
sys.path.append(os.getcwd())
|
| 6 |
+
|
| 7 |
+
from detect import detect_face_shape
|
| 8 |
+
|
| 9 |
+
TEST_DATASET_DIR = "../dataset/test"
|
| 10 |
+
|
| 11 |
+
def test():
|
| 12 |
+
with open("test_results.txt", "w") as f:
|
| 13 |
+
f.write("Starting simple accuracy test...\n")
|
| 14 |
+
if not os.path.exists(TEST_DATASET_DIR):
|
| 15 |
+
f.write(f"Dataset not found at {TEST_DATASET_DIR}\n")
|
| 16 |
+
return
|
| 17 |
+
|
| 18 |
+
classes = os.listdir(TEST_DATASET_DIR)
|
| 19 |
+
f.write(f"Classes found: {classes}\n")
|
| 20 |
+
|
| 21 |
+
for label in classes:
|
| 22 |
+
folder = os.path.join(TEST_DATASET_DIR, label)
|
| 23 |
+
if not os.path.isdir(folder):
|
| 24 |
+
continue
|
| 25 |
+
|
| 26 |
+
files = os.listdir(folder)
|
| 27 |
+
if not files:
|
| 28 |
+
f.write(f"No files in {label}\n")
|
| 29 |
+
continue
|
| 30 |
+
|
| 31 |
+
# Test just one image per class to verify pipeline
|
| 32 |
+
img_path = os.path.join(folder, files[0])
|
| 33 |
+
f.write(f"Testing {label} with {img_path}\n")
|
| 34 |
+
|
| 35 |
+
try:
|
| 36 |
+
result = detect_face_shape(img_path)
|
| 37 |
+
f.write(f"Result for {label}: {result}\n")
|
| 38 |
+
except Exception as e:
|
| 39 |
+
f.write(f"Error for {label}: {e}\n")
|
| 40 |
+
f.flush()
|
| 41 |
+
|
| 42 |
+
if __name__ == "__main__":
|
| 43 |
+
test()
|
test_api.py
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import requests
|
| 2 |
+
import time
|
| 3 |
+
import sys
|
| 4 |
+
import os
|
| 5 |
+
|
| 6 |
+
API_URL = "http://localhost:8000"
|
| 7 |
+
IMAGE_PATH = "/home/codernotme/.gemini/antigravity/brain/fd9634fe-740d-41a0-9d95-4bd5df08a975/test_face_1770615920629.png" # Updated path
|
| 8 |
+
|
| 9 |
+
def wait_for_server():
|
| 10 |
+
print("Waiting for server...")
|
| 11 |
+
for i in range(30):
|
| 12 |
+
try:
|
| 13 |
+
response = requests.get(f"{API_URL}/health")
|
| 14 |
+
if response.status_code == 200:
|
| 15 |
+
print("Server is ready!")
|
| 16 |
+
return True
|
| 17 |
+
except requests.exceptions.ConnectionError:
|
| 18 |
+
pass
|
| 19 |
+
time.sleep(2)
|
| 20 |
+
print(".", end="", flush=True)
|
| 21 |
+
print("\nServer timed out.")
|
| 22 |
+
return False
|
| 23 |
+
|
| 24 |
+
def test_recommendation():
|
| 25 |
+
if not os.path.exists(IMAGE_PATH):
|
| 26 |
+
print(f"Test image not found at {IMAGE_PATH}")
|
| 27 |
+
return
|
| 28 |
+
|
| 29 |
+
print(f"Testing recommendation with {IMAGE_PATH}...")
|
| 30 |
+
try:
|
| 31 |
+
with open(IMAGE_PATH, "rb") as f:
|
| 32 |
+
files = {"file": f}
|
| 33 |
+
response = requests.post(f"{API_URL}/recommend", files=files)
|
| 34 |
+
|
| 35 |
+
if response.status_code == 200:
|
| 36 |
+
print("Success!")
|
| 37 |
+
print(response.json())
|
| 38 |
+
else:
|
| 39 |
+
print(f"Failed: {response.status_code}")
|
| 40 |
+
print(response.text)
|
| 41 |
+
except Exception as e:
|
| 42 |
+
print(f"Error: {e}")
|
| 43 |
+
|
| 44 |
+
if __name__ == "__main__":
|
| 45 |
+
if wait_for_server():
|
| 46 |
+
test_recommendation()
|
| 47 |
+
else:
|
| 48 |
+
sys.exit(1)
|
test_results.txt
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Starting simple accuracy test...
|
| 2 |
+
Classes found: ['Heart', 'Oblong', 'Oval', 'Round', 'Square']
|
| 3 |
+
Testing Heart with ../dataset/test/Heart/Heart(0).jpg
|
| 4 |
+
Result for Heart: {'oblong': 0.2003, 'heart': 0.2001, 'square': 0.2001, 'oval': 0.2, 'round': 0.1995}
|
| 5 |
+
Testing Oblong with ../dataset/test/Oblong/Oblong(0).jpg
|
| 6 |
+
Result for Oblong: {'square': 0.2005, 'heart': 0.2001, 'oval': 0.2001, 'oblong': 0.2, 'round': 0.1992}
|
| 7 |
+
Testing Oval with ../dataset/test/Oval/Oval(0).jpg
|
| 8 |
+
Result for Oval: {'square': 0.2013, 'oblong': 0.2005, 'heart': 0.2002, 'oval': 0.2001, 'round': 0.1979}
|
| 9 |
+
Testing Round with ../dataset/test/Round/Round(0).jpg
|
| 10 |
+
Result for Round: {'square': 0.2005, 'oblong': 0.2002, 'oval': 0.2002, 'round': 0.1996, 'heart': 0.1995}
|
| 11 |
+
Testing Square with ../dataset/test/Square/Square(0).jpg
|
| 12 |
+
Result for Square: {'heart': 0.2005, 'oval': 0.2003, 'round': 0.1999, 'square': 0.1998, 'oblong': 0.1995}
|
train.py
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import cv2
|
| 3 |
+
import numpy as np
|
| 4 |
+
import pickle
|
| 5 |
+
from sklearn.ensemble import RandomForestClassifier
|
| 6 |
+
from sklearn.model_selection import train_test_split
|
| 7 |
+
from sklearn.metrics import accuracy_score, classification_report
|
| 8 |
+
from sklearn.preprocessing import LabelEncoder
|
| 9 |
+
|
| 10 |
+
# Configuration
|
| 11 |
+
DATASET_DIR = "/home/codernotme/Projects/Github/katariaoptics/dataset"
|
| 12 |
+
MODEL_PATH = "/home/codernotme/Projects/Github/katariaoptics/ai_service/face_shape_model.pkl"
|
| 13 |
+
IMG_SIZE = (64, 64) # Resize detected faces to this size
|
| 14 |
+
|
| 15 |
+
# Load Haar Cascade for face detection
|
| 16 |
+
cascade_path = cv2.data.haarcascades + 'haarcascade_frontalface_default.xml'
|
| 17 |
+
face_cascade = cv2.CascadeClassifier(cascade_path)
|
| 18 |
+
|
| 19 |
+
def load_dataset():
|
| 20 |
+
images = []
|
| 21 |
+
labels = []
|
| 22 |
+
|
| 23 |
+
# Expected classes
|
| 24 |
+
classes = ["heart", "oblong", "oval", "round", "square"]
|
| 25 |
+
|
| 26 |
+
print(f"Loading dataset from {DATASET_DIR}...")
|
| 27 |
+
|
| 28 |
+
for label in classes:
|
| 29 |
+
folder_path = os.path.join(DATASET_DIR, label)
|
| 30 |
+
if not os.path.isdir(folder_path):
|
| 31 |
+
print(f"Warning: Folder {folder_path} not found.")
|
| 32 |
+
continue
|
| 33 |
+
|
| 34 |
+
print(f"Processing class: {label}")
|
| 35 |
+
count = 0
|
| 36 |
+
total_files = len(os.listdir(folder_path))
|
| 37 |
+
|
| 38 |
+
for i, filename in enumerate(os.listdir(folder_path)):
|
| 39 |
+
if i % 50 == 0:
|
| 40 |
+
print(f" Processed {i}/{total_files} images...")
|
| 41 |
+
|
| 42 |
+
img_path = os.path.join(folder_path, filename)
|
| 43 |
+
try:
|
| 44 |
+
# Read image
|
| 45 |
+
img = cv2.imread(img_path)
|
| 46 |
+
if img is None:
|
| 47 |
+
continue
|
| 48 |
+
|
| 49 |
+
# Resize if huge to speed up detection
|
| 50 |
+
h, w = img.shape[:2]
|
| 51 |
+
if w > 1000:
|
| 52 |
+
scale = 1000 / w
|
| 53 |
+
img = cv2.resize(img, (1000, int(h * scale)))
|
| 54 |
+
|
| 55 |
+
# Convert to grayscale
|
| 56 |
+
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
|
| 57 |
+
|
| 58 |
+
# Detect faces
|
| 59 |
+
faces = face_cascade.detectMultiScale(gray, 1.1, 4)
|
| 60 |
+
|
| 61 |
+
# If face detected, crop and use it
|
| 62 |
+
if len(faces) > 0:
|
| 63 |
+
# Use the largest face
|
| 64 |
+
(x, y, w, h) = max(faces, key=lambda f: f[2] * f[3])
|
| 65 |
+
face_roi = gray[y:y+h, x:x+w]
|
| 66 |
+
|
| 67 |
+
# Resize and flatten
|
| 68 |
+
resized = cv2.resize(face_roi, IMG_SIZE)
|
| 69 |
+
flat_features = resized.flatten()
|
| 70 |
+
|
| 71 |
+
images.append(flat_features)
|
| 72 |
+
labels.append(label)
|
| 73 |
+
count += 1
|
| 74 |
+
except Exception as e:
|
| 75 |
+
print(f"Error processing {img_path}: {e}")
|
| 76 |
+
|
| 77 |
+
print(f" Loaded {count} images for {label}")
|
| 78 |
+
|
| 79 |
+
return np.array(images), np.array(labels)
|
| 80 |
+
|
| 81 |
+
def train_model():
|
| 82 |
+
X, y = load_dataset()
|
| 83 |
+
|
| 84 |
+
if len(X) == 0:
|
| 85 |
+
print("Error: No images loaded. Dataset might be empty or paths incorrect.")
|
| 86 |
+
return
|
| 87 |
+
|
| 88 |
+
print(f"Total dataset size: {len(X)} samples")
|
| 89 |
+
|
| 90 |
+
# Encode labels
|
| 91 |
+
le = LabelEncoder()
|
| 92 |
+
y_encoded = le.fit_transform(y)
|
| 93 |
+
|
| 94 |
+
# Save label encoder classes for inference
|
| 95 |
+
with open(MODEL_PATH.replace(".pkl", "_classes.pkl"), "wb") as f:
|
| 96 |
+
pickle.dump(le.classes_, f)
|
| 97 |
+
print(f"Saved class labels: {le.classes_}")
|
| 98 |
+
|
| 99 |
+
# Split dataset
|
| 100 |
+
X_train, X_test, y_train, y_test = train_test_split(X, y_encoded, test_size=0.2, random_state=42)
|
| 101 |
+
|
| 102 |
+
# Train Random Forest
|
| 103 |
+
print("Training Random Forest Classifier...")
|
| 104 |
+
clf = RandomForestClassifier(n_estimators=100, random_state=42)
|
| 105 |
+
clf.fit(X_train, y_train)
|
| 106 |
+
|
| 107 |
+
# Evaluate
|
| 108 |
+
y_pred = clf.predict(X_test)
|
| 109 |
+
accuracy = accuracy_score(y_test, y_pred)
|
| 110 |
+
print(f"Model Accuracy: {accuracy * 100:.2f}%")
|
| 111 |
+
print("\nClassification Report:")
|
| 112 |
+
print(classification_report(y_test, y_pred, target_names=le.classes_))
|
| 113 |
+
|
| 114 |
+
# Save model
|
| 115 |
+
with open(MODEL_PATH, "wb") as f:
|
| 116 |
+
pickle.dump(clf, f)
|
| 117 |
+
print(f"Model saved to {MODEL_PATH}")
|
| 118 |
+
|
| 119 |
+
if __name__ == "__main__":
|
| 120 |
+
train_model()
|
train_means.py
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import pickle
|
| 3 |
+
import numpy as np
|
| 4 |
+
from PIL import Image
|
| 5 |
+
|
| 6 |
+
# Configuration
|
| 7 |
+
# Use local paths relative to the script location
|
| 8 |
+
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
|
| 9 |
+
DATASET_DIR = os.environ.get("DATASET_DIR", os.path.join(BASE_DIR, "dataset"))
|
| 10 |
+
MODEL_PATH = os.environ.get("MODEL_PATH", os.path.join(BASE_DIR, "face_shape_means.pkl"))
|
| 11 |
+
IMG_SIZE = (64, 64)
|
| 12 |
+
|
| 13 |
+
|
| 14 |
+
def load_and_compute_means():
|
| 15 |
+
classes = ["heart", "oblong", "oval", "round", "square"]
|
| 16 |
+
class_means = {}
|
| 17 |
+
|
| 18 |
+
print(f"Dataset Dir: {DATASET_DIR}")
|
| 19 |
+
|
| 20 |
+
for label in classes:
|
| 21 |
+
folder_path = os.path.join(DATASET_DIR, label)
|
| 22 |
+
if not os.path.isdir(folder_path):
|
| 23 |
+
print(f"Warning: Folder {folder_path} not found")
|
| 24 |
+
continue
|
| 25 |
+
|
| 26 |
+
print(f"Processing {label}...")
|
| 27 |
+
vectors = []
|
| 28 |
+
|
| 29 |
+
files = os.listdir(folder_path)
|
| 30 |
+
total = len(files)
|
| 31 |
+
|
| 32 |
+
for i, filename in enumerate(files):
|
| 33 |
+
if i % 100 == 0:
|
| 34 |
+
print(f" {i}/{total}")
|
| 35 |
+
|
| 36 |
+
try:
|
| 37 |
+
img_path = os.path.join(folder_path, filename)
|
| 38 |
+
with Image.open(img_path) as img:
|
| 39 |
+
# Convert to grayscale and resize
|
| 40 |
+
img = img.convert("L").resize(IMG_SIZE)
|
| 41 |
+
# Flatten
|
| 42 |
+
arr = np.array(img).flatten()
|
| 43 |
+
vectors.append(arr)
|
| 44 |
+
except Exception as e:
|
| 45 |
+
# print(f"Error {filename}: {e}")
|
| 46 |
+
pass
|
| 47 |
+
|
| 48 |
+
if vectors:
|
| 49 |
+
# Compute mean vector for this class
|
| 50 |
+
mean_vector = np.mean(vectors, axis=0)
|
| 51 |
+
class_means[label] = mean_vector
|
| 52 |
+
print(f"Computed mean for {label} from {len(vectors)} images.")
|
| 53 |
+
else:
|
| 54 |
+
print(f"No valid images for {label}!")
|
| 55 |
+
|
| 56 |
+
# Save means
|
| 57 |
+
with open(MODEL_PATH, "wb") as f:
|
| 58 |
+
pickle.dump(class_means, f)
|
| 59 |
+
print(f"Saved mean vectors to {MODEL_PATH}")
|
| 60 |
+
|
| 61 |
+
if __name__ == "__main__":
|
| 62 |
+
load_and_compute_means()
|
train_model.py
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import cv2
|
| 3 |
+
import glob
|
| 4 |
+
import numpy as np
|
| 5 |
+
import joblib
|
| 6 |
+
from sklearn.model_selection import train_test_split
|
| 7 |
+
from sklearn.svm import SVC
|
| 8 |
+
from sklearn.preprocessing import LabelEncoder, StandardScaler
|
| 9 |
+
from sklearn.pipeline import make_pipeline
|
| 10 |
+
from sklearn.metrics import classification_report
|
| 11 |
+
|
| 12 |
+
from landmarks import get_landmarks
|
| 13 |
+
from geometry import extract_features
|
| 14 |
+
|
| 15 |
+
DATASET_DIR = "../dataset"
|
| 16 |
+
MODEL_PATH = "face_shape_model.pkl"
|
| 17 |
+
|
| 18 |
+
def get_feature_vector(features):
|
| 19 |
+
"""Converts feature dictionary to a list for the model."""
|
| 20 |
+
return [
|
| 21 |
+
features["lw_ratio"],
|
| 22 |
+
features["jaw_ratio"],
|
| 23 |
+
features["forehead_ratio"],
|
| 24 |
+
# Add more if geometry.py calculates them
|
| 25 |
+
]
|
| 26 |
+
|
| 27 |
+
def train():
|
| 28 |
+
print("Starting training...")
|
| 29 |
+
X = []
|
| 30 |
+
y = []
|
| 31 |
+
|
| 32 |
+
# Iterate through each subdirectory in the dataset
|
| 33 |
+
# Assumes structure: dataset/ShapeName/image.jpg
|
| 34 |
+
if not os.path.exists(DATASET_DIR):
|
| 35 |
+
print(f"Dataset directory not found: {DATASET_DIR}")
|
| 36 |
+
return
|
| 37 |
+
|
| 38 |
+
classes = [d for d in os.listdir(DATASET_DIR) if os.path.isdir(os.path.join(DATASET_DIR, d))]
|
| 39 |
+
print(f"Found classes: {classes}")
|
| 40 |
+
|
| 41 |
+
for label in classes:
|
| 42 |
+
class_dir = os.path.join(DATASET_DIR, label)
|
| 43 |
+
image_files = glob.glob(os.path.join(class_dir, "*"))
|
| 44 |
+
|
| 45 |
+
# Normalize label to capitalized format (e.g., "oval" -> "Oval") to match recommendation engine keys
|
| 46 |
+
normalized_label = label.capitalize()
|
| 47 |
+
|
| 48 |
+
print(f"Processing {label} (normalized to {normalized_label}): {len(image_files)} images")
|
| 49 |
+
|
| 50 |
+
for img_path in image_files:
|
| 51 |
+
try:
|
| 52 |
+
landmarks = get_landmarks(img_path)
|
| 53 |
+
feats = extract_features(landmarks)
|
| 54 |
+
vector = get_feature_vector(feats)
|
| 55 |
+
|
| 56 |
+
X.append(vector)
|
| 57 |
+
y.append(normalized_label)
|
| 58 |
+
except Exception as e:
|
| 59 |
+
# print(f"Skipping {img_path}: {e}")
|
| 60 |
+
pass
|
| 61 |
+
|
| 62 |
+
if len(X) == 0:
|
| 63 |
+
print("No valid data found. Check dataset and landmarks extraction.")
|
| 64 |
+
return
|
| 65 |
+
|
| 66 |
+
X = np.array(X)
|
| 67 |
+
y = np.array(y)
|
| 68 |
+
|
| 69 |
+
print(f"Training on {len(X)} samples...")
|
| 70 |
+
|
| 71 |
+
# Train/Test split
|
| 72 |
+
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
|
| 73 |
+
|
| 74 |
+
# Pipeline: Scale features -> SVM Classifier
|
| 75 |
+
model = make_pipeline(StandardScaler(), SVC(kernel='rbf', probability=True))
|
| 76 |
+
model.fit(X_train, y_train)
|
| 77 |
+
|
| 78 |
+
# Evaluate
|
| 79 |
+
print("Evaluating model...")
|
| 80 |
+
predictions = model.predict(X_test)
|
| 81 |
+
print(classification_report(y_test, predictions))
|
| 82 |
+
|
| 83 |
+
# Save
|
| 84 |
+
joblib.dump(model, MODEL_PATH)
|
| 85 |
+
print(f"Model saved to {MODEL_PATH}")
|
| 86 |
+
|
| 87 |
+
if __name__ == "__main__":
|
| 88 |
+
train()
|
verify_simple.py
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import sys
|
| 3 |
+
from detect import detect_face_shape
|
| 4 |
+
|
| 5 |
+
# Add current dir to path logic if needed, but running from ai_service should be fine
|
| 6 |
+
print("Starting simple verification...")
|
| 7 |
+
|
| 8 |
+
DATASET_DIR = "../dataset"
|
| 9 |
+
# Pick a file
|
| 10 |
+
if os.path.exists(DATASET_DIR):
|
| 11 |
+
heart_dir = os.path.join(DATASET_DIR, "heart")
|
| 12 |
+
if os.path.exists(heart_dir):
|
| 13 |
+
files = os.listdir(heart_dir)
|
| 14 |
+
if files:
|
| 15 |
+
img_path = os.path.join(heart_dir, files[0])
|
| 16 |
+
print(f"Testing {img_path}")
|
| 17 |
+
try:
|
| 18 |
+
result = detect_face_shape(img_path)
|
| 19 |
+
print(f"Result: {result}")
|
| 20 |
+
except Exception as e:
|
| 21 |
+
print(f"Error: {e}")
|
| 22 |
+
else:
|
| 23 |
+
print("No files in heart dir")
|
| 24 |
+
else:
|
| 25 |
+
print("No heart dir")
|
| 26 |
+
else:
|
| 27 |
+
print("No dataset dir")
|