saibalajiomg commited on
Commit
f47b400
·
verified ·
1 Parent(s): 2e206ee

Upload folder using huggingface_hub

Browse files
Files changed (2) hide show
  1. README.md +11 -1
  2. 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.9.0",
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("text, suggested_resolution")
79
- .eq("status", "completed")
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["text"]
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 = "meta-llama/Meta-Llama-3-8B-Instruct"
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(