Spaces:
Running
Running
Upload folder using huggingface_hub
Browse files- README.md +11 -1
- src/ml/modal_train.py +6 -6
README.md
CHANGED
|
@@ -160,8 +160,10 @@ graph TD
|
|
| 160 |
| Model | Algorithm | Task | Tracked on |
|
| 161 |
|:------|:----------|:-----|:-----------|
|
| 162 |
| **Churn Classifier** | Random Forest, Logistic Regression, Gradient Boosting | Predict customer churn probability from account features | [DagsHub MLflow](https://dagshub.com/saibalajinamburi/CustomerCore.mlflow) |
|
|
|
|
| 163 |
|
| 164 |
-
The training pipeline (`src/ml/train_churn.py`) trains all 3 models, compares F1 scores, and **auto-promotes the best one to "Production"** in the DagsHub Model Registry. Logged artifacts include ROC curves, confusion matrices, and feature importance plots.
|
|
|
|
| 165 |
|
| 166 |
### Models We Call via API (LLM)
|
| 167 |
|
|
@@ -690,6 +692,11 @@ doppler run -- python -X utf8 src/ml/train_churn.py
|
|
| 690 |
pytest tests/ -v
|
| 691 |
```
|
| 692 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 693 |
---
|
| 694 |
|
| 695 |
## ⚠️ Challenges Faced & How We Solved Them
|
|
@@ -708,6 +715,9 @@ pytest tests/ -v
|
|
| 708 |
| **Ollama unavailable in cloud containers** | HF Spaces don't ship with Ollama — local model calls time out after several seconds | `LLMClient` detects `SPACE_ID` / `APP_ENV=production` at startup and transparently redirects local tier calls to `openrouter/google/gemini-2.5-flash` |
|
| 709 |
| **Stale HITL data persists after role switch** | Switching from `manager` to `support_agent` in the demo left previously fetched review rows visible | Added an immediate role guard in `generateToken()` that clears the HITL table and shows an "Access Denied" banner the instant the role changes to `support_agent` |
|
| 710 |
| **Misleading DB timeout error messages** | When Supabase was unreachable, the UI catch block printed "Ensure role is manager" — wrong root cause | Updated catch blocks to distinguish `NetworkError` / `ENOTFOUND` from auth errors and display an accurate "Database unreachable" message with guidance |
|
|
|
|
|
|
|
|
|
|
| 711 |
|
| 712 |
---
|
| 713 |
|
|
|
|
| 160 |
| Model | Algorithm | Task | Tracked on |
|
| 161 |
|:------|:----------|:-----|:-----------|
|
| 162 |
| **Churn Classifier** | Random Forest, Logistic Regression, Gradient Boosting | Predict customer churn probability from account features | [DagsHub MLflow](https://dagshub.com/saibalajinamburi/CustomerCore.mlflow) |
|
| 163 |
+
| **Support LLM (QLoRA)** | Llama 3 8B Instruct (PEFT / QLoRA) | Predict professional, tenant-specific ticket resolutions | Hugging Face Adapter Registry |
|
| 164 |
|
| 165 |
+
* **Churn Classifier**: The training pipeline (`src/ml/train_churn.py`) trains all 3 models, compares F1 scores, and **auto-promotes the best one to "Production"** in the DagsHub Model Registry. Logged artifacts include ROC curves, confusion matrices, and feature importance plots.
|
| 166 |
+
* **Support LLM (QLoRA)**: The serverless training pipeline (`src/ml/modal_train.py`) executes on-demand on an Nvidia A10G GPU using **Modal**, pulls historical resolved support tickets (`raw_text` and `suggested_resolution`) from Supabase, performs QLoRA fine-tuning in 4-bit NF4 double-quantization, and publishes the resulting LoRA adapter (`customercore-llama3-adapter`) to the Hugging Face Hub.
|
| 167 |
|
| 168 |
### Models We Call via API (LLM)
|
| 169 |
|
|
|
|
| 692 |
pytest tests/ -v
|
| 693 |
```
|
| 694 |
|
| 695 |
+
### 9. (Optional) Run Serverless GPU LLM Fine-Tuning
|
| 696 |
+
```bash
|
| 697 |
+
doppler run -- modal run src/ml/modal_train.py
|
| 698 |
+
```
|
| 699 |
+
|
| 700 |
---
|
| 701 |
|
| 702 |
## ⚠️ Challenges Faced & How We Solved Them
|
|
|
|
| 715 |
| **Ollama unavailable in cloud containers** | HF Spaces don't ship with Ollama — local model calls time out after several seconds | `LLMClient` detects `SPACE_ID` / `APP_ENV=production` at startup and transparently redirects local tier calls to `openrouter/google/gemini-2.5-flash` |
|
| 716 |
| **Stale HITL data persists after role switch** | Switching from `manager` to `support_agent` in the demo left previously fetched review rows visible | Added an immediate role guard in `generateToken()` that clears the HITL table and shows an "Access Denied" banner the instant the role changes to `support_agent` |
|
| 717 |
| **Misleading DB timeout error messages** | When Supabase was unreachable, the UI catch block printed "Ensure role is manager" — wrong root cause | Updated catch blocks to distinguish `NetworkError` / `ENOTFOUND` from auth errors and display an accurate "Database unreachable" message with guidance |
|
| 718 |
+
| **Gated base model downloads on HF** | Hugging Face gated models (like `meta-llama/Meta-Llama-3-8B-Instruct`) returned a `403 Forbidden` error on serverless containers without user authorization | Switched base model to `NousResearch/Meta-Llama-3-8B-Instruct`, a public non-gated clone with identical architecture and weights |
|
| 719 |
+
| **Missing dependency in Python 3.12 container** | The remote training process crashed with `ModuleNotFoundError: No module named 'setuptools'` | Added `setuptools` to the container `pip_install` settings in `modal_train.py` for Python 3.12 compatibility |
|
| 720 |
+
| **Schema mapping & status issues in training script** | Direct queries failed due to non-existent columns (`text`) and incorrect status mapping (`completed` vs check constraints) | Replaced the column selection with `raw_text` and changed the status filter criteria to `'complete'` |
|
| 721 |
|
| 722 |
---
|
| 723 |
|
src/ml/modal_train.py
CHANGED
|
@@ -18,6 +18,7 @@ image = (
|
|
| 18 |
modal.Image.debian_slim()
|
| 19 |
.apt_install("git")
|
| 20 |
.pip_install(
|
|
|
|
| 21 |
"numpy<2",
|
| 22 |
"torch==2.2.0",
|
| 23 |
"transformers==4.38.1",
|
|
@@ -25,8 +26,7 @@ image = (
|
|
| 25 |
"bitsandbytes==0.42.0",
|
| 26 |
"accelerate==0.27.2",
|
| 27 |
"datasets==2.17.1",
|
| 28 |
-
"supabase==2.
|
| 29 |
-
"gotrue==2.8.1",
|
| 30 |
)
|
| 31 |
)
|
| 32 |
|
|
@@ -75,8 +75,8 @@ def train_llm():
|
|
| 75 |
# Fetch completed triage tickets to use as training ground-truth
|
| 76 |
response = (
|
| 77 |
supabase.table("tickets")
|
| 78 |
-
.select("
|
| 79 |
-
.eq("status", "
|
| 80 |
.limit(1000) # Limit for demonstration, can be raised to fetch full dataset
|
| 81 |
.execute()
|
| 82 |
)
|
|
@@ -92,7 +92,7 @@ def train_llm():
|
|
| 92 |
# Standard prompt template matching Llama 3 style
|
| 93 |
def format_prompt(row):
|
| 94 |
system_prompt = "You are a CustomerCore B2B support agent. Respond to the support ticket professionally."
|
| 95 |
-
user_input = row["
|
| 96 |
response = row["suggested_resolution"]
|
| 97 |
|
| 98 |
prompt = (
|
|
@@ -107,7 +107,7 @@ def train_llm():
|
|
| 107 |
print("🧹 Data formatted into instruction training prompt template.")
|
| 108 |
|
| 109 |
# 3. Configure 4-bit quantization (QLoRA)
|
| 110 |
-
base_model_name = "
|
| 111 |
print(f"📥 Loading base model on GPU: {base_model_name}")
|
| 112 |
|
| 113 |
bnb_config = BitsAndBytesConfig(
|
|
|
|
| 18 |
modal.Image.debian_slim()
|
| 19 |
.apt_install("git")
|
| 20 |
.pip_install(
|
| 21 |
+
"setuptools",
|
| 22 |
"numpy<2",
|
| 23 |
"torch==2.2.0",
|
| 24 |
"transformers==4.38.1",
|
|
|
|
| 26 |
"bitsandbytes==0.42.0",
|
| 27 |
"accelerate==0.27.2",
|
| 28 |
"datasets==2.17.1",
|
| 29 |
+
"supabase==2.30.0",
|
|
|
|
| 30 |
)
|
| 31 |
)
|
| 32 |
|
|
|
|
| 75 |
# Fetch completed triage tickets to use as training ground-truth
|
| 76 |
response = (
|
| 77 |
supabase.table("tickets")
|
| 78 |
+
.select("raw_text, suggested_resolution")
|
| 79 |
+
.eq("status", "complete")
|
| 80 |
.limit(1000) # Limit for demonstration, can be raised to fetch full dataset
|
| 81 |
.execute()
|
| 82 |
)
|
|
|
|
| 92 |
# Standard prompt template matching Llama 3 style
|
| 93 |
def format_prompt(row):
|
| 94 |
system_prompt = "You are a CustomerCore B2B support agent. Respond to the support ticket professionally."
|
| 95 |
+
user_input = row["raw_text"]
|
| 96 |
response = row["suggested_resolution"]
|
| 97 |
|
| 98 |
prompt = (
|
|
|
|
| 107 |
print("🧹 Data formatted into instruction training prompt template.")
|
| 108 |
|
| 109 |
# 3. Configure 4-bit quantization (QLoRA)
|
| 110 |
+
base_model_name = "NousResearch/Meta-Llama-3-8B-Instruct"
|
| 111 |
print(f"📥 Loading base model on GPU: {base_model_name}")
|
| 112 |
|
| 113 |
bnb_config = BitsAndBytesConfig(
|