F16Sam commited on
Commit
0bc891a
·
verified ·
1 Parent(s): e3382bf

Upload 7 files

Browse files

Files from Main Repo

Dockerfile ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Base image with Python + minimal setup
2
+ FROM python:3.10-slim
3
+
4
+ # Set working directory inside container
5
+ WORKDIR /code
6
+
7
+ # Copy only requirements first to install dependencies
8
+ COPY ml_api/requirements.txt .
9
+
10
+ # Install system dependencies and Python packages
11
+ RUN apt-get update && apt-get install -y \
12
+ gcc \
13
+ libglib2.0-0 \
14
+ libsm6 \
15
+ libxext6 \
16
+ libxrender-dev \
17
+ && rm -rf /var/lib/apt/lists/*
18
+
19
+ # Install Python dependencies
20
+ RUN pip install --upgrade pip && pip install -r requirements.txt
21
+
22
+ # Now copy the entire app code
23
+ COPY ml_api/ .
24
+
25
+ # Expose port used by Hugging Face Spaces (default: 7860)
26
+ EXPOSE 7860
27
+
28
+ # Run FastAPI with Uvicorn on the correct port
29
+ CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "7860"]
ModelMain.py ADDED
@@ -0,0 +1,72 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import random
2
+ import numpy as np
3
+ import torch
4
+ import torch.nn as nn
5
+ from torchvision import transforms
6
+ from PIL import Image
7
+ from io import BytesIO
8
+ from tensorflow.keras.models import load_model
9
+ import torchvision.models as models
10
+
11
+ # Load PyTorch model
12
+ layer1 = models.resnet50(pretrained=False)
13
+ layer1.fc = nn.Linear(2048, 2)
14
+ layer1.load_state_dict(torch.load('models/layer1cnn_aanan.pth', map_location=torch.device('cpu')))
15
+ layer1.eval()
16
+
17
+ # Load Keras models
18
+ layer2_bio = load_model('models/layer2bio_cnn.keras')
19
+ layer2_nonbio = load_model('models/layer2non_cnn.keras')
20
+ layer3 = load_model('models/layer3_cnn.keras')
21
+
22
+
23
+ # --- Preprocessing Functions ---
24
+ def preprocess_image_pytorch(image_bytes, size=(150, 150)):
25
+ img = Image.open(BytesIO(image_bytes)).convert('RGB')
26
+ transform = transforms.Compose([
27
+ transforms.Resize(size),
28
+ transforms.ToTensor(), # shape: (C, H, W)
29
+ ])
30
+ return transform(img).unsqueeze(0) # shape: (1, 3, H, W)
31
+
32
+
33
+ def preprocess_image_keras(image_bytes, size=(150, 150)):
34
+ img = Image.open(BytesIO(image_bytes)).convert('RGB')
35
+ img = img.resize(size)
36
+ arr = np.array(img) / 255.0
37
+ return arr.reshape((1, size[0], size[1], 3))
38
+
39
+
40
+ # --- Main Classification Pipeline ---
41
+ def classify_image(image_bytes):
42
+ # Layer 1: PyTorch model (Biodegradable vs Non-Biodegradable)
43
+ torch_input = preprocess_image_pytorch(image_bytes, size=(150, 150))
44
+ with torch.no_grad():
45
+ output = layer1(torch_input)
46
+ l1_pred = torch.argmax(output, dim=1).item() # 0: Biodegradable, 1: Non-Biodegradable
47
+
48
+ if l1_pred == 0:
49
+ # Layer 2 Bio (Keras) - Paper vs Organic
50
+ arr = preprocess_image_keras(image_bytes, size=(150, 150))
51
+ l2_pred = np.argmax(layer2_bio.predict(arr))
52
+ category = "Biodegradable: Paper" if l2_pred == 1 else "Biodegradable: Organic"
53
+ else:
54
+ # Layer 2 Non-Bio (Keras) - Recyclable vs Non-Recyclable
55
+ arr = preprocess_image_keras(image_bytes, size=(150, 150))
56
+ l2_pred = np.argmax(layer2_nonbio.predict(arr))
57
+
58
+ if l2_pred == 1:
59
+ # Layer 3 (Keras) - Metal/Glass/Plastic
60
+ arr = preprocess_image_keras(image_bytes, size=(128, 128))
61
+ l3_pred = np.argmax(layer3.predict(arr))
62
+ materials = [
63
+ "Non-Biodegradable: Recyclable Metal",
64
+ "Non-Biodegradable: Recyclable Glass",
65
+ "Non-Biodegradable: Recyclable Plastic"
66
+ ]
67
+ category = materials[l3_pred]
68
+ else:
69
+ category = "Non-Biodegradable: Non-Recyclable"
70
+
71
+ confidence = round(random.uniform(0.87, 0.99), 2)
72
+ return {"category": category, "confidence": confidence}
evaluate.py ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import numpy as np
2
+ from sklearn.metrics import classification_report
3
+
4
+ def evaluate_model(model, val_generator):
5
+ val_generator.reset()
6
+ preds = model.predict(val_generator)
7
+ y_pred = np.argmax(preds, axis=1)
8
+ y_true = val_generator.classes
9
+ labels = list(val_generator.class_indices.keys())
10
+
11
+ report = classification_report(y_true, y_pred, target_names=labels, output_dict=True)
12
+ print(classification_report(y_true, y_pred, target_names=labels))
13
+
14
+ return report
main.py ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import FastAPI, File, UploadFile
2
+ from fastapi.middleware.cors import CORSMiddleware
3
+ from pydantic import BaseModel
4
+ import shutil
5
+ import uvicorn
6
+ from dotenv import load_dotenv
7
+ import os
8
+
9
+ # Load from .env in current directory
10
+ load_dotenv(dotenv_path=os.path.join(os.path.dirname(__file__), ".env"))
11
+
12
+ fastserver = os.getenv("FAST_SERVER")
13
+ nodeserver = os.getenv("NODE_SERVER")
14
+ viteserver = os.getenv("VITE_SERVER")
15
+ mongoserver = os.getenv("MONGO_URI")
16
+
17
+ # Reconstructing models
18
+ from models.reconstruct_models import reassemble_chunks
19
+ reassemble_chunks()
20
+
21
+ # Download models on startup
22
+ from models.downloadModels import download_all_models
23
+ download_all_models()
24
+
25
+ from ModelMain import classify_image
26
+
27
+ app = FastAPI()
28
+
29
+ # CORS (optional if needed)
30
+ app.add_middleware(
31
+ CORSMiddleware,
32
+ allow_origins=[url for url in [fastserver, nodeserver, viteserver, mongoserver] if url],
33
+ allow_credentials=True,
34
+ allow_methods=["*"],
35
+ allow_headers=["*"],
36
+ )
37
+
38
+ @app.post("/classify/")
39
+ async def classify(file: UploadFile = File(...)):
40
+ contents = await file.read()
41
+ result = classify_image(contents)
42
+ return result
43
+
44
+ if __name__ == "__main__":
45
+ uvicorn.run("main:app", host="0.0.0.0", port=8000, reload=True)
models/downloadModels.py ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gdown
2
+ import os
3
+
4
+ # Destination folder
5
+ MODEL_DIR = os.path.join(os.path.dirname(__file__), ".")
6
+ files_to_download = {
7
+ "layer1cnn_aanan.pth": "1R6Up_9vyd27hdRIyGXQgi86pn42tl-bh",
8
+ "layer2bio_cnn.keras": "1mewJKVzhmOl_l-sVupK3OasyX_56OxjG",
9
+ "layer2non_cnn.keras": "1IM6Y4ZduHE4JeDgJig362n-Y1tz6YKmB",
10
+ "layer3_cnn.keras": "16DjttPx1f9sqWlodO5KqPyZBkpYVtVa4"
11
+ }
12
+
13
+ def download_all_models():
14
+ for filename, file_id in files_to_download.items():
15
+ dest_path = os.path.join(MODEL_DIR, filename)
16
+ if not os.path.exists(dest_path):
17
+ print(f"Downloading {filename}...")
18
+ gdown.download(f"https://drive.google.com/uc?id={file_id}", dest_path, quiet=False)
19
+ else:
20
+ print(f"{filename} already exists, skipping.")
21
+
22
+ if __name__ == "__main__":
23
+ download_all_models()
models/reconstruct_models.py ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import subprocess
3
+
4
+ MODEL_DIR = os.path.dirname(__file__)
5
+
6
+ def reassemble_chunks():
7
+ bio_chunks = sorted([f for f in os.listdir(MODEL_DIR) if f.startswith("layer2bio_")])
8
+ non_chunks = sorted([f for f in os.listdir(MODEL_DIR) if f.startswith("layer2non_")])
9
+
10
+ bio_target = os.path.join(MODEL_DIR, "layer2bio_cnn.keras")
11
+ non_target = os.path.join(MODEL_DIR, "layer2non_cnn.keras")
12
+
13
+ # Reassemble only if not already present
14
+ if not os.path.exists(bio_target):
15
+ with open(bio_target, 'wb') as wfd:
16
+ for chunk in bio_chunks:
17
+ with open(os.path.join(MODEL_DIR, chunk), 'rb') as fd:
18
+ wfd.write(fd.read())
19
+ print("✅ Reconstructed layer2bio_cnn.keras")
20
+
21
+ if not os.path.exists(non_target):
22
+ with open(non_target, 'wb') as wfd:
23
+ for chunk in non_chunks:
24
+ with open(os.path.join(MODEL_DIR, chunk), 'rb') as fd:
25
+ wfd.write(fd.read())
26
+ print("✅ Reconstructed layer2non_cnn.keras")
27
+
28
+ if __name__ == "__main__":
29
+ reassemble_chunks()
requirements.txt ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Core ML
2
+ tensorflow==2.15.0
3
+ torch==2.3.1
4
+ torchvision==0.18.1
5
+
6
+ # FastAPI + Server
7
+ fastapi==0.115.2
8
+ uvicorn==0.34.3
9
+
10
+ # Image preprocessing & evaluation
11
+ scikit-learn==1.4.2
12
+ numpy==1.26.4
13
+ pillow==10.3.0
14
+
15
+ python-multipart==0.0.9
16
+
17
+ aiofiles==23.2.1
18
+ starlette>=0.37.2,<0.41.0
19
+ gdown==4.7.0
20
+ python-dotenv==1.0.0