File size: 7,521 Bytes
11b1420
fd1ef54
 
c9131d2
fd1ef54
 
 
 
11b1420
 
 
fd1ef54
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
010a1cb
fd1ef54
 
 
010a1cb
fd1ef54
a45b603
 
 
fd1ef54
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
---
title: "Coffee Cup Points Estimator"
emoji: "☕️"
colorFrom: "gray"
colorTo: "green"
sdk: "gradio"
sdk_version: "5.49.1"
app_file: "app.py"
pinned: false
---



# Module3Project

# Overview 
Predict coffee quality scores based on sensory attributes using a RandomForest model and an MLOps pipeline. 
This project demonstrates an end-to-end MLOps pipeline: data ingestion, preprocessing, model training, containerization, cloud deployment, and front-end integration.

# Data
For this project, we are using data on coffee quality found here:
https://www.kaggle.com/datasets/volpatto/coffee-quality-database-from-cqi

The cleaned coffee dataset is publicly hosted on Google Cloud Storage for reproducibility.
The preprocessing pipeline automatically downloads it via the data.url field in config.yaml.

Cleaned data is hosted in Google Cloud Storage:
https://storage.googleapis.com/coffee-quality-data/preprocessed_data.csv

# Architecture 
Data → Cloud (GCS) → Preprocess (ColumnTransformer) → Train (RandomForest) → FastAPI → Gradio frontend

## Frontend Architecture 
```
┌───────────────┐       ┌─────────────┐       ┌───────────────┐       ┌──────────────┐
│  Kaggle Data  │  →    │  GCS Bucket │  →    │  FastAPI (API)│  →    │ Gradio UI    │
└───────────────┘       └─────────────┘       └───────────────┘       └──────────────┘
```
# Frontend 
The Gradio-based frontend is deployed at: https://huggingface.co/spaces/averye-duke/Module3

Hugging face was used to deploy the app. 

# Cloud Deployment: 
The FastAPI container is deployed on Google Cloud Run at:
Base URL:
https://coffee-api-354131048216.us-central1.run.app

Endpoints:

- /health – Health check
- /predict_named – POST endpoint for predictions
- /docs - API documentation (Swagger) 
	
Example cURL:
```
curl -X POST "https://coffee-api-354131048216.us-central1.run.app/predict_named" \
  -H "Content-Type: application/json" \
  -d '{"rows":[{"Aroma":7.5,"Flavor":6.0,"Body":5.5,"Acidity":8.0,"Sweetness":9.0,"Balance":7.0,"Aftertaste":6.5,"Clean.Cup":9.0}]}'
```

# Setup:
```
python -m venv venv
source venv/bin/activate        # Windows: venv\Scripts\activate
pip install --upgrade pip
pip install -r requirements.txt
```
# Testing/running scripts
To test preprocess.py: 
```
python scripts/preprocess.py
```
Confirm all output files exist by running: 
```
ls -l data/cleaned/X_train.csv data/cleaned/X_test.csv data/cleaned/y_train.csv data/cleaned/y_test.csv artifacts/preprocessor.joblib
```
We wrote a unit test script tests/test_preprocessor.py, to run it: 
```
pip install pytest
pytest -q
```

To run the server, do health check use sample predict payload: 
```
uvicorn app.server:app --reload --port 8000 
curl http://127.0.0.1:8000/health
curl -X POST "http://127.0.0.1:8000/predict_named" \
  -H "Content-Type: application/json" \
  -d '{"rows":[ {"Aroma":7.5,"Flavor":6.0,"Number.of.Bags":1,"Category.One.Defects":0} ] }'
```

To train the model:
```
python scripts/train.py
```
Ensure artifacts/model.joblib was built

To run the UI app start the server and type in CLI: 
```
python app/frontend.py
Enter 3 when prompted:
  wandb: (1) Create a W&B account
  wandb: (2) Use an existing W&B account
  wandb: (3) Don't visualize my results
  My personal login is needed to sign in here to update to wandb website

```
Open link in browser

# Model
We used a RandomForestRegression for the model. Test size is 20% of dataset. Model has accuracy of 94.2% with 100 estimators.

W and B tracks model performance. Data can be found in wandb/run.../files/wandb-summary.json. Data is presented like this:
```
{
  "_timestamp":1.763876781125257e+09,
  "_wandb":{"runtime":2},
  "_runtime":2,
  "_step":0,
  "R2":0.9424069488737763,
  "RMSE":0.5528660703704987,
  "MAE":0.31615526315789416,
  "MAPE":0.39006294567905464
}
```
These perfomance metrics are also stored in artifacts.metrics.json like this:
```
{
    "R2": 0.9424069488737761,
    "RMSE": 0.5528660703704994,
    "MAE": 0.31615526315789455,
    "MAPE": 0.39006294567905514
}
```
The 94.2% R2 value shows very good fit and a cup score that correlates strongly with the other columns. The RMSE 0f 0.55 shows a small predicition error and therefore reinforces the model's high preformance.  The MAE of 0.314 also shows a small error to the actual cup points. MAPE shows average percentage error of 39% which shows medium accuracy. This could be due to the small size dataset the model was trained on.

# 🐳 Docker and Testing 
## Build the image 
```
# from the project root
docker build -t coffee-api:dev .
docker run --rm -e WANDB_MODE=offline -p 8000:8000 coffee-api:dev
```
Note: Use WANDB_MODE=offline (as shown above) when running inside Docker or CI to prevent login prompts from Weights & Biases. If you have a W&B API key, set it via WANDB_API_KEY=your_key to enable cloud logging.

## Run the container 
```
docker run --rm -p 8000:8000 \
  -v "$(pwd)/artifacts":/app/artifacts \
  -v "$(pwd)/config.yaml":/app/config.yaml \
  -v "$(pwd)/data":/app/data \
  coffee-api:dev
```
Then open:
	•	Health check: http://127.0.0.1:8000/health
	•	Interactive docs: http://127.0.0.1:8000/docs

If artifacts are missing, the container automatically runs scripts/preprocess.py to generate them.

## Run tests inside the container 

To verify reproducibility of preprocessing and data pipeline:
```
docker run --rm -v "$(pwd)":/app -w /app coffee-api:dev python -m pytest -q
```
Expect output: 
```
...
3 passed in ~0.9s
```

## Docker-related notes: 
- Ports: container exposes 8000 (mapped to host port 8000)
- Artifacts (preprocessor.joblib, model.joblib) are mounted from the host for faster iteration

# Limitations & Ethics
Predictions depend on sensory ratings, which are subjective.
The model is not suitable for real-world evaluation of coffee quality without expert calibration.
The dataset may contain sampling bias by country or producer, and model predictions should not be used for commercial grading without calibration against expert cuppers.

# Notes / Gotchas
- config.yaml may include data.input_columns — if present the server will require/expect those columns and reindex incoming payloads automatically. 
- The server will try to load artifacts/preprocessor.joblib and artifacts/model.joblib. If those are missing the server returns deterministic dummy predictions (development mode).

# ☁️ Cloud Services Used
- **Google Cloud Storage (GCS):** Stores the cleaned dataset (`preprocessed_data.csv`) publicly.
- **Google Cloud Run:** Hosts and serves the FastAPI model API container.
- **Weights & Biases (W&B):** Tracks model training metrics and performance.

# 🧠 Authors
- Eugenia Tate
- Avery Estopinal

# References: 
- OpenAI. (2025). ChatGPT (Version 5.1) [Large language model]. https://chat.openai.com We used ChatGPT (OpenAI GPT-5.1) to assist with code snippets. 
Portions of the preprocessing, frontend, train and most of server code were assisted by ChatGPT (OpenAI GPT-5.1). Authors verified and adapted the generated code. 
Authors fully understand what the code does and how to apply the knowledge in the future.
- Kaggle Coffee Quality Data (Volpatto, 2020) https://www.kaggle.com/datasets/volpatto/coffee-quality-database-from-cqi