nitish-spz commited on
Commit
e93a798
Β·
1 Parent(s): e749f25

build error - fix 1

Browse files
.dockerignore ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Don't include these in Docker build
2
+ __pycache__/
3
+ *.pyc
4
+ *.pyo
5
+ *.pyd
6
+ .Python
7
+ *.so
8
+ *.egg-info/
9
+
10
+ # Development files
11
+ .git/
12
+ .gitignore
13
+ .gitattributes
14
+ .env
15
+ .env.*
16
+
17
+ # Documentation and examples (not needed for runtime)
18
+ API_CLIENT_EXAMPLES.py
19
+ API_CURL_EXAMPLES.sh
20
+ API_JAVASCRIPT_EXAMPLE.js
21
+ API_KEYS_FOR_COLLEAGUE.md
22
+ API_USAGE.md
23
+ API_USAGE_UPDATED.md
24
+ CHANGELOG_API_UPDATE.md
25
+ FRONTEND_README.md
26
+ frontend.html
27
+ index_v2.html
28
+ setup_instructions.md
29
+ SETUP_MODEL_HUB.md
30
+
31
+ # Unused files (pattern detection removed)
32
+ patterbs.json
33
+ confidence_scores.js
34
+ metadata.js
35
+
36
+ # Test files
37
+ test_images/
38
+ *.local.*
39
+
40
+ # IDE files
41
+ .vscode/
42
+ .idea/
43
+ *.swp
44
+ *.swo
45
+ .DS_Store
46
+
.gitattributes CHANGED
@@ -1,35 +1,12 @@
1
- *.7z filter=lfs diff=lfs merge=lfs -text
2
- *.arrow filter=lfs diff=lfs merge=lfs -text
3
  *.bin filter=lfs diff=lfs merge=lfs -text
4
- *.bz2 filter=lfs diff=lfs merge=lfs -text
5
- *.ckpt filter=lfs diff=lfs merge=lfs -text
6
- *.ftz filter=lfs diff=lfs merge=lfs -text
7
- *.gz filter=lfs diff=lfs merge=lfs -text
8
  *.h5 filter=lfs diff=lfs merge=lfs -text
9
- *.joblib filter=lfs diff=lfs merge=lfs -text
10
- *.lfs.* filter=lfs diff=lfs merge=lfs -text
11
- *.mlmodel filter=lfs diff=lfs merge=lfs -text
12
- *.model filter=lfs diff=lfs merge=lfs -text
13
- *.msgpack filter=lfs diff=lfs merge=lfs -text
14
- *.npy filter=lfs diff=lfs merge=lfs -text
15
- *.npz filter=lfs diff=lfs merge=lfs -text
16
- *.onnx filter=lfs diff=lfs merge=lfs -text
17
- *.ot filter=lfs diff=lfs merge=lfs -text
18
- *.parquet filter=lfs diff=lfs merge=lfs -text
19
- *.pb filter=lfs diff=lfs merge=lfs -text
20
- *.pickle filter=lfs diff=lfs merge=lfs -text
21
- *.pkl filter=lfs diff=lfs merge=lfs -text
22
  *.pt filter=lfs diff=lfs merge=lfs -text
23
- *.pth filter=lfs diff=lfs merge=lfs -text
24
- *.rar filter=lfs diff=lfs merge=lfs -text
25
- *.safetensors filter=lfs diff=lfs merge=lfs -text
26
- saved_model/**/* filter=lfs diff=lfs merge=lfs -text
27
- *.tar.* filter=lfs diff=lfs merge=lfs -text
28
- *.tar filter=lfs diff=lfs merge=lfs -text
29
- *.tflite filter=lfs diff=lfs merge=lfs -text
30
- *.tgz filter=lfs diff=lfs merge=lfs -text
31
- *.wasm filter=lfs diff=lfs merge=lfs -text
32
- *.xz 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
 
1
+ *.pth filter=lfs diff=lfs merge=lfs -text
 
2
  *.bin filter=lfs diff=lfs merge=lfs -text
3
+ *.gguf filter=lfs diff=lfs merge=lfs -text
4
+ *.safetensors filter=lfs diff=lfs merge=lfs -text
 
 
5
  *.h5 filter=lfs diff=lfs merge=lfs -text
 
 
 
 
 
 
 
 
 
 
 
 
 
6
  *.pt filter=lfs diff=lfs merge=lfs -text
7
+ *.pb filter=lfs diff=lfs merge=lfs -text
8
+ *.onnx filter=lfs diff=lfs merge=lfs -text
9
+ *.msgpack filter=lfs diff=lfs merge=lfs -text
10
+ *.arrow filter=lfs diff=lfs merge=lfs -text
11
+ *.ftz filter=lfs diff=lfs merge=lfs -text
12
+ *.joblib filter=lfs diff=lfs merge=lfs -text
 
 
 
 
 
 
 
API_CLIENT_EXAMPLES.py ADDED
@@ -0,0 +1,377 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ A/B Test Predictor - API Client Examples
3
+ ==========================================
4
+
5
+ This file shows how to send requests to the A/B Test Predictor API.
6
+ """
7
+
8
+ # ============================================================================
9
+ # Option 1: Gradio Python Client (Recommended)
10
+ # ============================================================================
11
+
12
+ from gradio_client import Client
13
+ from PIL import Image
14
+ import json
15
+
16
+ # Initialize the client
17
+ # For local deployment:
18
+ client = Client("http://localhost:7860")
19
+
20
+ # For Hugging Face Spaces deployment:
21
+ # client = Client("your-username/ABTestPredictor")
22
+
23
+ def predict_with_gradio_client(control_image_path, variant_image_path,
24
+ business_model, customer_type, conversion_type,
25
+ industry, page_type):
26
+ """
27
+ Send prediction request using Gradio Client
28
+
29
+ Args:
30
+ control_image_path: Path to control image file
31
+ variant_image_path: Path to variant image file
32
+ business_model: One of ["E-Commerce", "Lead Generation", "Other*", "SaaS"]
33
+ customer_type: One of ["B2B", "B2C", "Both", "Other*"]
34
+ conversion_type: One of ["Direct Purchase", "High-Intent Lead Gen",
35
+ "Info/Content Lead Gen", "Location Search",
36
+ "Non-Profit/Community", "Other Conversion"]
37
+ industry: One of the 14 industry categories
38
+ page_type: One of ["Awareness & Discovery", "Consideration & Evaluation",
39
+ "Conversion", "Internal & Navigation", "Post-Conversion & Other"]
40
+
41
+ Returns:
42
+ dict: Prediction results with confidence scores
43
+ """
44
+ result = client.predict(
45
+ control_image_path, # Control image file path
46
+ variant_image_path, # Variant image file path
47
+ business_model, # Business Model dropdown
48
+ customer_type, # Customer Type dropdown
49
+ conversion_type, # Conversion Type dropdown
50
+ industry, # Industry dropdown
51
+ page_type, # Page Type dropdown
52
+ api_name="/predict_with_categorical_data" # The function endpoint
53
+ )
54
+
55
+ return result
56
+
57
+
58
+ # Example usage
59
+ if __name__ == "__main__":
60
+ # Example 1: Basic prediction
61
+ result = predict_with_gradio_client(
62
+ control_image_path="path/to/control_image.jpg",
63
+ variant_image_path="path/to/variant_image.jpg",
64
+ business_model="SaaS",
65
+ customer_type="B2B",
66
+ conversion_type="High-Intent Lead Gen",
67
+ industry="B2B Software & Tech",
68
+ page_type="Awareness & Discovery"
69
+ )
70
+
71
+ print("Prediction Results:")
72
+ print(json.dumps(result, indent=2))
73
+
74
+ # Access specific fields
75
+ win_probability = result['predictionResults']['probability']
76
+ confidence = result['predictionResults']['modelConfidence']
77
+
78
+ print(f"\nWin Probability: {win_probability}")
79
+ print(f"Model Confidence: {confidence}%")
80
+
81
+
82
+ # ============================================================================
83
+ # Option 2: Direct HTTP POST Request (cURL equivalent in Python)
84
+ # ============================================================================
85
+
86
+ import requests
87
+ import base64
88
+
89
+ def predict_with_http_request(control_image_path, variant_image_path,
90
+ business_model, customer_type, conversion_type,
91
+ industry, page_type, api_url="http://localhost:7860"):
92
+ """
93
+ Send prediction request using direct HTTP POST
94
+
95
+ Note: This requires converting images to base64 for Gradio's API format
96
+ """
97
+
98
+ # Read and encode images
99
+ with open(control_image_path, "rb") as f:
100
+ control_b64 = base64.b64encode(f.read()).decode()
101
+
102
+ with open(variant_image_path, "rb") as f:
103
+ variant_b64 = base64.b64encode(f.read()).decode()
104
+
105
+ # Prepare the request payload (Gradio format)
106
+ payload = {
107
+ "data": [
108
+ f"data:image/jpeg;base64,{control_b64}", # Control image
109
+ f"data:image/jpeg;base64,{variant_b64}", # Variant image
110
+ business_model,
111
+ customer_type,
112
+ conversion_type,
113
+ industry,
114
+ page_type
115
+ ]
116
+ }
117
+
118
+ # Send POST request to Gradio API
119
+ response = requests.post(
120
+ f"{api_url}/api/predict",
121
+ json=payload,
122
+ headers={"Content-Type": "application/json"}
123
+ )
124
+
125
+ if response.status_code == 200:
126
+ return response.json()['data'][0] # Gradio wraps response in 'data' array
127
+ else:
128
+ raise Exception(f"API request failed: {response.status_code} - {response.text}")
129
+
130
+
131
+ # ============================================================================
132
+ # Option 3: Using PIL Images (in-memory)
133
+ # ============================================================================
134
+
135
+ import numpy as np
136
+ from PIL import Image
137
+
138
+ def predict_with_pil_images(control_img, variant_img,
139
+ business_model, customer_type, conversion_type,
140
+ industry, page_type):
141
+ """
142
+ Send prediction with PIL Image objects (useful for programmatic image generation)
143
+
144
+ Args:
145
+ control_img: PIL Image object
146
+ variant_img: PIL Image object
147
+ """
148
+
149
+ # Convert PIL images to numpy arrays (Gradio expects numpy arrays)
150
+ control_array = np.array(control_img)
151
+ variant_array = np.array(variant_img)
152
+
153
+ # Use the Gradio client
154
+ result = client.predict(
155
+ control_array,
156
+ variant_array,
157
+ business_model,
158
+ customer_type,
159
+ conversion_type,
160
+ industry,
161
+ page_type,
162
+ api_name="/predict_with_categorical_data"
163
+ )
164
+
165
+ return result
166
+
167
+
168
+ # Example with PIL
169
+ if __name__ == "__main__":
170
+ # Load images using PIL
171
+ control_img = Image.open("control.jpg")
172
+ variant_img = Image.open("variant.jpg")
173
+
174
+ result = predict_with_pil_images(
175
+ control_img=control_img,
176
+ variant_img=variant_img,
177
+ business_model="SaaS",
178
+ customer_type="B2B",
179
+ conversion_type="High-Intent Lead Gen",
180
+ industry="B2B Software & Tech",
181
+ page_type="Awareness & Discovery"
182
+ )
183
+
184
+
185
+ # ============================================================================
186
+ # Option 4: Batch Processing Multiple Tests
187
+ # ============================================================================
188
+
189
+ def batch_predict(test_cases, output_file="results.json"):
190
+ """
191
+ Process multiple A/B tests in batch
192
+
193
+ Args:
194
+ test_cases: List of dicts with test parameters
195
+ output_file: Where to save results
196
+
197
+ Example test_cases:
198
+ [
199
+ {
200
+ "control_image": "test1_control.jpg",
201
+ "variant_image": "test1_variant.jpg",
202
+ "business_model": "SaaS",
203
+ "customer_type": "B2B",
204
+ "conversion_type": "High-Intent Lead Gen",
205
+ "industry": "B2B Software & Tech",
206
+ "page_type": "Awareness & Discovery"
207
+ },
208
+ # ... more tests
209
+ ]
210
+ """
211
+
212
+ results = []
213
+
214
+ for i, test in enumerate(test_cases):
215
+ print(f"Processing test {i+1}/{len(test_cases)}...")
216
+
217
+ try:
218
+ result = predict_with_gradio_client(
219
+ control_image_path=test["control_image"],
220
+ variant_image_path=test["variant_image"],
221
+ business_model=test["business_model"],
222
+ customer_type=test["customer_type"],
223
+ conversion_type=test["conversion_type"],
224
+ industry=test["industry"],
225
+ page_type=test["page_type"]
226
+ )
227
+
228
+ results.append({
229
+ "test_id": i + 1,
230
+ "input": test,
231
+ "prediction": result
232
+ })
233
+
234
+ except Exception as e:
235
+ print(f"Error processing test {i+1}: {e}")
236
+ results.append({
237
+ "test_id": i + 1,
238
+ "input": test,
239
+ "error": str(e)
240
+ })
241
+
242
+ # Save results
243
+ with open(output_file, "w") as f:
244
+ json.dump(results, f, indent=2)
245
+
246
+ print(f"\nBatch processing complete! Results saved to {output_file}")
247
+ return results
248
+
249
+
250
+ # ============================================================================
251
+ # Valid Category Values (for reference)
252
+ # ============================================================================
253
+
254
+ VALID_CATEGORIES = {
255
+ "business_model": [
256
+ "E-Commerce",
257
+ "Lead Generation",
258
+ "Other*",
259
+ "SaaS"
260
+ ],
261
+
262
+ "customer_type": [
263
+ "B2B",
264
+ "B2C",
265
+ "Both",
266
+ "Other*"
267
+ ],
268
+
269
+ "conversion_type": [
270
+ "Direct Purchase",
271
+ "High-Intent Lead Gen",
272
+ "Info/Content Lead Gen",
273
+ "Location Search",
274
+ "Non-Profit/Community",
275
+ "Other Conversion"
276
+ ],
277
+
278
+ "industry": [
279
+ "Automotive & Transportation",
280
+ "B2B Services",
281
+ "B2B Software & Tech",
282
+ "Consumer Services",
283
+ "Consumer Software & Apps",
284
+ "Education",
285
+ "Finance, Insurance & Real Estate",
286
+ "Food, Hospitality & Travel",
287
+ "Health & Wellness",
288
+ "Industrial & Manufacturing",
289
+ "Media & Entertainment",
290
+ "Non-Profit & Government",
291
+ "Other",
292
+ "Retail & E-commerce"
293
+ ],
294
+
295
+ "page_type": [
296
+ "Awareness & Discovery",
297
+ "Consideration & Evaluation",
298
+ "Conversion",
299
+ "Internal & Navigation",
300
+ "Post-Conversion & Other"
301
+ ]
302
+ }
303
+
304
+
305
+ def validate_categories(business_model, customer_type, conversion_type,
306
+ industry, page_type):
307
+ """Validate that all categories are valid"""
308
+
309
+ errors = []
310
+
311
+ if business_model not in VALID_CATEGORIES["business_model"]:
312
+ errors.append(f"Invalid business_model: {business_model}")
313
+
314
+ if customer_type not in VALID_CATEGORIES["customer_type"]:
315
+ errors.append(f"Invalid customer_type: {customer_type}")
316
+
317
+ if conversion_type not in VALID_CATEGORIES["conversion_type"]:
318
+ errors.append(f"Invalid conversion_type: {conversion_type}")
319
+
320
+ if industry not in VALID_CATEGORIES["industry"]:
321
+ errors.append(f"Invalid industry: {industry}")
322
+
323
+ if page_type not in VALID_CATEGORIES["page_type"]:
324
+ errors.append(f"Invalid page_type: {page_type}")
325
+
326
+ if errors:
327
+ raise ValueError("Category validation failed:\n" + "\n".join(errors))
328
+
329
+ return True
330
+
331
+
332
+ # ============================================================================
333
+ # Error Handling Example
334
+ # ============================================================================
335
+
336
+ def safe_predict(control_image_path, variant_image_path,
337
+ business_model, customer_type, conversion_type,
338
+ industry, page_type):
339
+ """
340
+ Safe prediction with error handling and validation
341
+ """
342
+
343
+ try:
344
+ # Validate categories first
345
+ validate_categories(business_model, customer_type, conversion_type,
346
+ industry, page_type)
347
+
348
+ # Make prediction
349
+ result = predict_with_gradio_client(
350
+ control_image_path=control_image_path,
351
+ variant_image_path=variant_image_path,
352
+ business_model=business_model,
353
+ customer_type=customer_type,
354
+ conversion_type=conversion_type,
355
+ industry=industry,
356
+ page_type=page_type
357
+ )
358
+
359
+ return {
360
+ "success": True,
361
+ "result": result
362
+ }
363
+
364
+ except ValueError as e:
365
+ return {
366
+ "success": False,
367
+ "error": "Validation Error",
368
+ "message": str(e)
369
+ }
370
+
371
+ except Exception as e:
372
+ return {
373
+ "success": False,
374
+ "error": "API Error",
375
+ "message": str(e)
376
+ }
377
+
API_CURL_EXAMPLES.sh ADDED
@@ -0,0 +1,187 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/bin/bash
2
+
3
+ # ============================================================================
4
+ # A/B Test Predictor - cURL API Examples
5
+ # ============================================================================
6
+
7
+ # Configuration
8
+ API_URL="http://localhost:7860" # Change to your deployment URL
9
+ # For Hugging Face Spaces: API_URL="https://your-username-abtestpredictor.hf.space"
10
+
11
+ # ============================================================================
12
+ # Example 1: Basic Prediction with Image Files
13
+ # ============================================================================
14
+
15
+ # Convert images to base64
16
+ CONTROL_IMAGE_B64=$(base64 -i control_image.jpg)
17
+ VARIANT_IMAGE_B64=$(base64 -i variant_image.jpg)
18
+
19
+ # Send POST request to Gradio API
20
+ curl -X POST "${API_URL}/api/predict" \
21
+ -H "Content-Type: application/json" \
22
+ -d '{
23
+ "data": [
24
+ "data:image/jpeg;base64,'"${CONTROL_IMAGE_B64}"'",
25
+ "data:image/jpeg;base64,'"${VARIANT_IMAGE_B64}"'",
26
+ "SaaS",
27
+ "B2B",
28
+ "High-Intent Lead Gen",
29
+ "B2B Software & Tech",
30
+ "Awareness & Discovery"
31
+ ],
32
+ "fn_index": 0
33
+ }'
34
+
35
+ # ============================================================================
36
+ # Example 2: Using a Function to Send Requests
37
+ # ============================================================================
38
+
39
+ predict_abtest() {
40
+ local CONTROL_IMG=$1
41
+ local VARIANT_IMG=$2
42
+ local BUSINESS_MODEL=$3
43
+ local CUSTOMER_TYPE=$4
44
+ local CONVERSION_TYPE=$5
45
+ local INDUSTRY=$6
46
+ local PAGE_TYPE=$7
47
+
48
+ # Encode images
49
+ local CONTROL_B64=$(base64 -i "$CONTROL_IMG")
50
+ local VARIANT_B64=$(base64 -i "$VARIANT_IMG")
51
+
52
+ # Make API call
53
+ curl -X POST "${API_URL}/api/predict" \
54
+ -H "Content-Type: application/json" \
55
+ -d '{
56
+ "data": [
57
+ "data:image/jpeg;base64,'"${CONTROL_B64}"'",
58
+ "data:image/jpeg;base64,'"${VARIANT_B64}"'",
59
+ "'"${BUSINESS_MODEL}"'",
60
+ "'"${CUSTOMER_TYPE}"'",
61
+ "'"${CONVERSION_TYPE}"'",
62
+ "'"${INDUSTRY}"'",
63
+ "'"${PAGE_TYPE}"'"
64
+ ]
65
+ }' | jq .
66
+ }
67
+
68
+ # Usage
69
+ predict_abtest \
70
+ "control.jpg" \
71
+ "variant.jpg" \
72
+ "SaaS" \
73
+ "B2B" \
74
+ "High-Intent Lead Gen" \
75
+ "B2B Software & Tech" \
76
+ "Awareness & Discovery"
77
+
78
+ # ============================================================================
79
+ # Example 3: Multiple Predictions in a Loop
80
+ # ============================================================================
81
+
82
+ # Read test cases from CSV
83
+ while IFS=',' read -r control variant business customer conversion industry page
84
+ do
85
+ echo "Processing: $control vs $variant"
86
+
87
+ predict_abtest \
88
+ "$control" \
89
+ "$variant" \
90
+ "$business" \
91
+ "$customer" \
92
+ "$conversion" \
93
+ "$industry" \
94
+ "$page"
95
+
96
+ sleep 1 # Rate limiting
97
+ done < test_cases.csv
98
+
99
+ # ============================================================================
100
+ # Example 4: Save Results to File
101
+ # ============================================================================
102
+
103
+ predict_and_save() {
104
+ local OUTPUT_FILE=$1
105
+
106
+ predict_abtest \
107
+ "control.jpg" \
108
+ "variant.jpg" \
109
+ "SaaS" \
110
+ "B2B" \
111
+ "High-Intent Lead Gen" \
112
+ "B2B Software & Tech" \
113
+ "Awareness & Discovery" > "$OUTPUT_FILE"
114
+
115
+ echo "Results saved to $OUTPUT_FILE"
116
+ }
117
+
118
+ predict_and_save "prediction_result.json"
119
+
120
+ # ============================================================================
121
+ # Example 5: Parse and Extract Specific Fields
122
+ # ============================================================================
123
+
124
+ # Get just the win probability
125
+ get_win_probability() {
126
+ predict_abtest "$@" | jq -r '.data[0].predictionResults.probability'
127
+ }
128
+
129
+ # Get model confidence
130
+ get_confidence() {
131
+ predict_abtest "$@" | jq -r '.data[0].predictionResults.modelConfidence'
132
+ }
133
+
134
+ # Usage
135
+ PROB=$(get_win_probability "control.jpg" "variant.jpg" "SaaS" "B2B" "High-Intent Lead Gen" "B2B Software & Tech" "Awareness & Discovery")
136
+ CONF=$(get_confidence "control.jpg" "variant.jpg" "SaaS" "B2B" "High-Intent Lead Gen" "B2B Software & Tech" "Awareness & Discovery")
137
+
138
+ echo "Win Probability: $PROB"
139
+ echo "Model Confidence: $CONF%"
140
+
141
+ # ============================================================================
142
+ # Valid Category Values (for reference)
143
+ # ============================================================================
144
+
145
+ # Business Model options:
146
+ # - "E-Commerce"
147
+ # - "Lead Generation"
148
+ # - "Other*"
149
+ # - "SaaS"
150
+
151
+ # Customer Type options:
152
+ # - "B2B"
153
+ # - "B2C"
154
+ # - "Both"
155
+ # - "Other*"
156
+
157
+ # Conversion Type options:
158
+ # - "Direct Purchase"
159
+ # - "High-Intent Lead Gen"
160
+ # - "Info/Content Lead Gen"
161
+ # - "Location Search"
162
+ # - "Non-Profit/Community"
163
+ # - "Other Conversion"
164
+
165
+ # Industry options:
166
+ # - "Automotive & Transportation"
167
+ # - "B2B Services"
168
+ # - "B2B Software & Tech"
169
+ # - "Consumer Services"
170
+ # - "Consumer Software & Apps"
171
+ # - "Education"
172
+ # - "Finance, Insurance & Real Estate"
173
+ # - "Food, Hospitality & Travel"
174
+ # - "Health & Wellness"
175
+ # - "Industrial & Manufacturing"
176
+ # - "Media & Entertainment"
177
+ # - "Non-Profit & Government"
178
+ # - "Other"
179
+ # - "Retail & E-commerce"
180
+
181
+ # Page Type options:
182
+ # - "Awareness & Discovery"
183
+ # - "Consideration & Evaluation"
184
+ # - "Conversion"
185
+ # - "Internal & Navigation"
186
+ # - "Post-Conversion & Other"
187
+
API_JAVASCRIPT_EXAMPLE.js ADDED
@@ -0,0 +1,381 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * A/B Test Predictor - JavaScript/Node.js API Examples
3
+ */
4
+
5
+ // ============================================================================
6
+ // Option 1: Using Fetch API (Browser/Node.js)
7
+ // ============================================================================
8
+
9
+ async function predictABTest(controlImagePath, variantImagePath, categories) {
10
+ const apiUrl = 'http://localhost:7860/api/predict'; // Change to your deployment URL
11
+
12
+ // Read and encode images to base64
13
+ const fs = require('fs').promises;
14
+
15
+ const controlImage = await fs.readFile(controlImagePath);
16
+ const variantImage = await fs.readFile(variantImagePath);
17
+
18
+ const controlB64 = `data:image/jpeg;base64,${controlImage.toString('base64')}`;
19
+ const variantB64 = `data:image/jpeg;base64,${variantImage.toString('base64')}`;
20
+
21
+ // Prepare request payload
22
+ const payload = {
23
+ data: [
24
+ controlB64,
25
+ variantB64,
26
+ categories.businessModel,
27
+ categories.customerType,
28
+ categories.conversionType,
29
+ categories.industry,
30
+ categories.pageType
31
+ ]
32
+ };
33
+
34
+ // Send POST request
35
+ const response = await fetch(apiUrl, {
36
+ method: 'POST',
37
+ headers: {
38
+ 'Content-Type': 'application/json'
39
+ },
40
+ body: JSON.stringify(payload)
41
+ });
42
+
43
+ if (!response.ok) {
44
+ throw new Error(`API request failed: ${response.status} ${response.statusText}`);
45
+ }
46
+
47
+ const result = await response.json();
48
+ return result.data[0]; // Gradio wraps response in 'data' array
49
+ }
50
+
51
+ // Example usage
52
+ (async () => {
53
+ try {
54
+ const result = await predictABTest(
55
+ 'control.jpg',
56
+ 'variant.jpg',
57
+ {
58
+ businessModel: 'SaaS',
59
+ customerType: 'B2B',
60
+ conversionType: 'High-Intent Lead Gen',
61
+ industry: 'B2B Software & Tech',
62
+ pageType: 'Awareness & Discovery'
63
+ }
64
+ );
65
+
66
+ console.log('Prediction Results:');
67
+ console.log(JSON.stringify(result, null, 2));
68
+
69
+ console.log('\nWin Probability:', result.predictionResults.probability);
70
+ console.log('Model Confidence:', result.predictionResults.modelConfidence + '%');
71
+
72
+ } catch (error) {
73
+ console.error('Error:', error.message);
74
+ }
75
+ })();
76
+
77
+
78
+ // ============================================================================
79
+ // Option 2: Using Axios (More Robust)
80
+ // ============================================================================
81
+
82
+ const axios = require('axios');
83
+ const fs = require('fs').promises;
84
+
85
+ class ABTestPredictorClient {
86
+ constructor(apiUrl = 'http://localhost:7860') {
87
+ this.apiUrl = apiUrl;
88
+ this.endpoint = `${apiUrl}/api/predict`;
89
+ }
90
+
91
+ async encodeImage(imagePath) {
92
+ const imageBuffer = await fs.readFile(imagePath);
93
+ return `data:image/jpeg;base64,${imageBuffer.toString('base64')}`;
94
+ }
95
+
96
+ async predict(controlImagePath, variantImagePath, categories) {
97
+ try {
98
+ // Encode images
99
+ const controlB64 = await this.encodeImage(controlImagePath);
100
+ const variantB64 = await this.encodeImage(variantImagePath);
101
+
102
+ // Validate categories
103
+ this.validateCategories(categories);
104
+
105
+ // Prepare payload
106
+ const payload = {
107
+ data: [
108
+ controlB64,
109
+ variantB64,
110
+ categories.businessModel,
111
+ categories.customerType,
112
+ categories.conversionType,
113
+ categories.industry,
114
+ categories.pageType
115
+ ]
116
+ };
117
+
118
+ // Make API call
119
+ const response = await axios.post(this.endpoint, payload, {
120
+ headers: {
121
+ 'Content-Type': 'application/json'
122
+ },
123
+ timeout: 30000 // 30 second timeout
124
+ });
125
+
126
+ return {
127
+ success: true,
128
+ data: response.data.data[0]
129
+ };
130
+
131
+ } catch (error) {
132
+ return {
133
+ success: false,
134
+ error: error.message,
135
+ details: error.response?.data
136
+ };
137
+ }
138
+ }
139
+
140
+ validateCategories(categories) {
141
+ const validCategories = {
142
+ businessModel: ['E-Commerce', 'Lead Generation', 'Other*', 'SaaS'],
143
+ customerType: ['B2B', 'B2C', 'Both', 'Other*'],
144
+ conversionType: [
145
+ 'Direct Purchase',
146
+ 'High-Intent Lead Gen',
147
+ 'Info/Content Lead Gen',
148
+ 'Location Search',
149
+ 'Non-Profit/Community',
150
+ 'Other Conversion'
151
+ ],
152
+ industry: [
153
+ 'Automotive & Transportation',
154
+ 'B2B Services',
155
+ 'B2B Software & Tech',
156
+ 'Consumer Services',
157
+ 'Consumer Software & Apps',
158
+ 'Education',
159
+ 'Finance, Insurance & Real Estate',
160
+ 'Food, Hospitality & Travel',
161
+ 'Health & Wellness',
162
+ 'Industrial & Manufacturing',
163
+ 'Media & Entertainment',
164
+ 'Non-Profit & Government',
165
+ 'Other',
166
+ 'Retail & E-commerce'
167
+ ],
168
+ pageType: [
169
+ 'Awareness & Discovery',
170
+ 'Consideration & Evaluation',
171
+ 'Conversion',
172
+ 'Internal & Navigation',
173
+ 'Post-Conversion & Other'
174
+ ]
175
+ };
176
+
177
+ // Validate each category
178
+ for (const [key, value] of Object.entries(categories)) {
179
+ if (!validCategories[key]?.includes(value)) {
180
+ throw new Error(`Invalid ${key}: ${value}`);
181
+ }
182
+ }
183
+
184
+ return true;
185
+ }
186
+
187
+ async batchPredict(testCases) {
188
+ const results = [];
189
+
190
+ for (let i = 0; i < testCases.length; i++) {
191
+ console.log(`Processing test ${i + 1}/${testCases.length}...`);
192
+
193
+ const testCase = testCases[i];
194
+ const result = await this.predict(
195
+ testCase.controlImage,
196
+ testCase.variantImage,
197
+ testCase.categories
198
+ );
199
+
200
+ results.push({
201
+ testId: i + 1,
202
+ input: testCase,
203
+ result: result
204
+ });
205
+
206
+ // Rate limiting
207
+ await new Promise(resolve => setTimeout(resolve, 1000));
208
+ }
209
+
210
+ return results;
211
+ }
212
+ }
213
+
214
+ // Example usage
215
+ (async () => {
216
+ const client = new ABTestPredictorClient('http://localhost:7860');
217
+
218
+ // Single prediction
219
+ const result = await client.predict(
220
+ 'control.jpg',
221
+ 'variant.jpg',
222
+ {
223
+ businessModel: 'SaaS',
224
+ customerType: 'B2B',
225
+ conversionType: 'High-Intent Lead Gen',
226
+ industry: 'B2B Software & Tech',
227
+ pageType: 'Awareness & Discovery'
228
+ }
229
+ );
230
+
231
+ if (result.success) {
232
+ console.log('Prediction successful!');
233
+ console.log('Win Probability:', result.data.predictionResults.probability);
234
+ console.log('Confidence:', result.data.predictionResults.modelConfidence + '%');
235
+ } else {
236
+ console.error('Prediction failed:', result.error);
237
+ }
238
+
239
+ // Batch predictions
240
+ const testCases = [
241
+ {
242
+ controlImage: 'test1_control.jpg',
243
+ variantImage: 'test1_variant.jpg',
244
+ categories: {
245
+ businessModel: 'SaaS',
246
+ customerType: 'B2B',
247
+ conversionType: 'High-Intent Lead Gen',
248
+ industry: 'B2B Software & Tech',
249
+ pageType: 'Awareness & Discovery'
250
+ }
251
+ },
252
+ // Add more test cases...
253
+ ];
254
+
255
+ const batchResults = await client.batchPredict(testCases);
256
+ console.log('Batch results:', JSON.stringify(batchResults, null, 2));
257
+ })();
258
+
259
+
260
+ // ============================================================================
261
+ // Option 3: Browser Example (Using File Input)
262
+ // ============================================================================
263
+
264
+ // HTML:
265
+ // <input type="file" id="controlImage" accept="image/*">
266
+ // <input type="file" id="variantImage" accept="image/*">
267
+ // <button onclick="predictFromBrowser()">Predict</button>
268
+ // <div id="results"></div>
269
+
270
+ async function predictFromBrowser() {
271
+ const controlFile = document.getElementById('controlImage').files[0];
272
+ const variantFile = document.getElementById('variantImage').files[0];
273
+
274
+ if (!controlFile || !variantFile) {
275
+ alert('Please select both images');
276
+ return;
277
+ }
278
+
279
+ // Convert files to base64
280
+ const controlB64 = await fileToBase64(controlFile);
281
+ const variantB64 = await fileToBase64(variantFile);
282
+
283
+ // Prepare payload
284
+ const payload = {
285
+ data: [
286
+ controlB64,
287
+ variantB64,
288
+ 'SaaS',
289
+ 'B2B',
290
+ 'High-Intent Lead Gen',
291
+ 'B2B Software & Tech',
292
+ 'Awareness & Discovery'
293
+ ]
294
+ };
295
+
296
+ try {
297
+ const response = await fetch('http://localhost:7860/api/predict', {
298
+ method: 'POST',
299
+ headers: {
300
+ 'Content-Type': 'application/json'
301
+ },
302
+ body: JSON.stringify(payload)
303
+ });
304
+
305
+ const result = await response.json();
306
+ displayResults(result.data[0]);
307
+
308
+ } catch (error) {
309
+ alert('Error: ' + error.message);
310
+ }
311
+ }
312
+
313
+ function fileToBase64(file) {
314
+ return new Promise((resolve, reject) => {
315
+ const reader = new FileReader();
316
+ reader.onload = () => resolve(reader.result);
317
+ reader.onerror = reject;
318
+ reader.readAsDataURL(file);
319
+ });
320
+ }
321
+
322
+ function displayResults(data) {
323
+ const resultsDiv = document.getElementById('results');
324
+ resultsDiv.innerHTML = `
325
+ <h3>Prediction Results</h3>
326
+ <p>Win Probability: ${data.predictionResults.probability}</p>
327
+ <p>Model Confidence: ${data.predictionResults.modelConfidence}%</p>
328
+ <p>Training Samples: ${data.predictionResults.trainingDataSamples}</p>
329
+ <p>Total Predictions: ${data.predictionResults.totalPredictions}</p>
330
+ `;
331
+ }
332
+
333
+
334
+ // ============================================================================
335
+ // Option 4: Express.js Server Example
336
+ // ============================================================================
337
+
338
+ const express = require('express');
339
+ const multer = require('multer');
340
+ const upload = multer({ dest: 'uploads/' });
341
+
342
+ const app = express();
343
+ const client = new ABTestPredictorClient('http://localhost:7860');
344
+
345
+ app.post('/predict', upload.fields([
346
+ { name: 'control', maxCount: 1 },
347
+ { name: 'variant', maxCount: 1 }
348
+ ]), async (req, res) => {
349
+ try {
350
+ const controlPath = req.files['control'][0].path;
351
+ const variantPath = req.files['variant'][0].path;
352
+
353
+ const categories = {
354
+ businessModel: req.body.businessModel,
355
+ customerType: req.body.customerType,
356
+ conversionType: req.body.conversionType,
357
+ industry: req.body.industry,
358
+ pageType: req.body.pageType
359
+ };
360
+
361
+ const result = await client.predict(controlPath, variantPath, categories);
362
+
363
+ // Clean up uploaded files
364
+ const fs = require('fs');
365
+ fs.unlinkSync(controlPath);
366
+ fs.unlinkSync(variantPath);
367
+
368
+ res.json(result);
369
+
370
+ } catch (error) {
371
+ res.status(500).json({
372
+ success: false,
373
+ error: error.message
374
+ });
375
+ }
376
+ });
377
+
378
+ app.listen(3000, () => {
379
+ console.log('Proxy server running on port 3000');
380
+ });
381
+
DEPLOYMENT_FIX.md ADDED
@@ -0,0 +1,164 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Hugging Face Spaces Deployment Fix
2
+
3
+ ## Problem
4
+ Build was failing with exit code 1 due to cache issues and potentially large/unnecessary files being uploaded.
5
+
6
+ ## Solutions Applied
7
+
8
+ ### 1. Created `.dockerignore`
9
+ This file prevents unnecessary files from being included in the Docker build:
10
+ - Documentation files (API examples, setup guides, etc.)
11
+ - Development files (.git, .env, etc.)
12
+ - Unused files from previous version (patterbs.json, metadata.js, confidence_scores.js)
13
+ - IDE and test files
14
+
15
+ ### 2. Created `.gitattributes`
16
+ Ensures large model files are properly tracked with Git LFS:
17
+ - *.pth files (your model)
18
+ - Other common model formats
19
+
20
+ ### 3. Files That Can Be Deleted (No Longer Needed)
21
+
22
+ These files are from the old AI API version and are no longer used:
23
+ ```bash
24
+ # Can be safely deleted
25
+ rm patterbs.json # 269KB - Pattern descriptions (no longer used)
26
+ rm confidence_scores.js # 15KB - JS version of confidence data
27
+ rm metadata.js # 14KB - JS version of metadata
28
+ rm frontend.html # Old frontend (if not using)
29
+ rm index_v2.html # Old frontend (if not using)
30
+ rm API_USAGE.md # Old API docs (replaced by API_USAGE_UPDATED.md)
31
+ ```
32
+
33
+ ### 4. Essential Files for Deployment
34
+
35
+ Keep these files:
36
+ ```
37
+ βœ… app.py # Main application
38
+ βœ… requirements.txt # Python dependencies
39
+ βœ… packages.txt # System dependencies (tesseract-ocr)
40
+ βœ… README.md # Project documentation
41
+ βœ… confidence_scores.json # Confidence data (NEEDED)
42
+ βœ… model/multimodal_gated_model_2.7_GGG.pth # Model weights
43
+ βœ… model/multimodal_cat_mappings_GGG.json # Category mappings
44
+ βœ… .gitattributes # Git LFS configuration
45
+ βœ… .dockerignore # Docker build optimization
46
+ ```
47
+
48
+ ### 5. Deployment Steps
49
+
50
+ 1. **Clean up unnecessary files:**
51
+ ```bash
52
+ cd /Users/nitish/Spiralyze/HuggingFace/Spaces/ABTestPredictor
53
+
54
+ # Optional: Delete unused files
55
+ rm patterbs.json confidence_scores.js metadata.js frontend.html index_v2.html API_USAGE.md
56
+ ```
57
+
58
+ 2. **Verify Git LFS is tracking the model:**
59
+ ```bash
60
+ git lfs ls-files
61
+ # Should show: model/multimodal_gated_model_2.7_GGG.pth
62
+ ```
63
+
64
+ 3. **Commit and push changes:**
65
+ ```bash
66
+ git add .
67
+ git commit -m "Fix: Remove AI API dependencies and optimize for deployment"
68
+ git push
69
+ ```
70
+
71
+ 4. **If model file isn't tracked by LFS:**
72
+ ```bash
73
+ # Track it
74
+ git lfs track "*.pth"
75
+ git add .gitattributes
76
+ git add model/multimodal_gated_model_2.7_GGG.pth
77
+ git commit -m "Track model file with Git LFS"
78
+ git push
79
+ ```
80
+
81
+ ### 6. Hugging Face Spaces Settings
82
+
83
+ Make sure your Space is configured correctly:
84
+ - **SDK**: Gradio
85
+ - **SDK Version**: 4.44.0 (as specified in README.md)
86
+ - **Hardware**: GPU (T4, A10G, or better recommended)
87
+ - **No environment variables needed** (we removed API keys)
88
+
89
+ ### 7. Common Build Issues & Fixes
90
+
91
+ #### Issue: "File too large"
92
+ **Solution**: Use Git LFS for files > 10MB
93
+ ```bash
94
+ git lfs track "*.pth"
95
+ git add .gitattributes
96
+ git commit -m "Add Git LFS tracking"
97
+ ```
98
+
99
+ #### Issue: "Package installation failed"
100
+ **Solution**: Check requirements.txt for conflicts
101
+ ```bash
102
+ # Test locally first
103
+ pip install -r requirements.txt
104
+ ```
105
+
106
+ #### Issue: "Tesseract not found"
107
+ **Solution**: Ensure packages.txt contains `tesseract-ocr`
108
+
109
+ #### Issue: "Model file not found"
110
+ **Solution**: Verify model files are in the correct location:
111
+ - `model/multimodal_gated_model_2.7_GGG.pth`
112
+ - `model/multimodal_cat_mappings_GGG.json`
113
+
114
+ ### 8. Testing Deployment
115
+
116
+ Once deployed, test the API:
117
+
118
+ **Using Gradio Interface:**
119
+ 1. Go to your Space URL
120
+ 2. Upload test images
121
+ 3. Select categories
122
+ 4. Click "Predict"
123
+
124
+ **Using Python Client:**
125
+ ```python
126
+ from gradio_client import Client
127
+
128
+ client = Client("your-username/ABTestPredictor")
129
+ result = client.predict(
130
+ "control.jpg",
131
+ "variant.jpg",
132
+ "SaaS", "B2B", "High-Intent Lead Gen",
133
+ "B2B Software & Tech", "Awareness & Discovery",
134
+ api_name="/predict_with_categorical_data"
135
+ )
136
+ print(result)
137
+ ```
138
+
139
+ ### 9. Monitoring
140
+
141
+ Check build logs in Hugging Face Spaces:
142
+ - Go to your Space
143
+ - Click "Logs" tab
144
+ - Look for any errors during build or runtime
145
+
146
+ ### 10. Rollback Plan
147
+
148
+ If issues persist:
149
+ 1. Check previous working commit: `git log`
150
+ 2. Revert: `git revert <commit-hash>`
151
+ 3. Or reset: `git reset --hard <working-commit-hash>`
152
+ 4. Force push: `git push --force` (⚠️ only if needed)
153
+
154
+ ## Expected Build Time
155
+ - First build: 5-10 minutes (downloading model, installing packages)
156
+ - Subsequent builds: 2-3 minutes (cached layers)
157
+
158
+ ## Success Indicators
159
+ βœ… Build completes without errors
160
+ βœ… Space status shows "Running"
161
+ βœ… Gradio interface loads correctly
162
+ βœ… Can make predictions successfully
163
+ βœ… Response includes confidence scores
164
+
QUICK_FIX_SUMMARY.md ADDED
@@ -0,0 +1,134 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Quick Fix for Build Error - Summary
2
+
3
+ ## What Was the Problem?
4
+ The Hugging Face Spaces build was failing because:
5
+ 1. Node.js dependency for loading metadata.js (no longer needed)
6
+ 2. Unnecessary large files (patterbs.json - 269KB) being uploaded
7
+ 3. No `.dockerignore` to exclude documentation files
8
+ 4. Git LFS might not be properly configured
9
+
10
+ ## What Was Fixed?
11
+
12
+ ### 1. βœ… Simplified Category Mapping Loading
13
+ **Changed**: Removed Node.js dependency for loading metadata.js
14
+ **File**: `app.py` lines 172-184
15
+ **Result**: Now creates default mappings directly in Python
16
+
17
+ ### 2. βœ… Created `.dockerignore`
18
+ **Purpose**: Excludes unnecessary files from Docker build:
19
+ - Documentation files (API examples, guides)
20
+ - Unused files (patterbs.json, metadata.js, confidence_scores.js)
21
+ - Development files (.git, .env, IDEs)
22
+
23
+ ### 3. βœ… Created `.gitattributes`
24
+ **Purpose**: Ensures model files are properly tracked with Git LFS
25
+
26
+ ## Next Steps
27
+
28
+ ### Step 1: Clean Up (Optional but Recommended)
29
+ ```bash
30
+ cd /Users/nitish/Spiralyze/HuggingFace/Spaces/ABTestPredictor
31
+
32
+ # Delete files that are no longer needed
33
+ rm patterbs.json # Pattern descriptions (no longer used)
34
+ rm confidence_scores.js # JS version (not needed, we use .json)
35
+ rm metadata.js # JS version (not needed)
36
+ rm frontend.html # Old frontend (if using Gradio only)
37
+ rm index_v2.html # Old frontend (if using Gradio only)
38
+ ```
39
+
40
+ ### Step 2: Commit and Push
41
+ ```bash
42
+ # Add all changes
43
+ git add .
44
+
45
+ # Commit
46
+ git commit -m "Fix: Remove Node.js dependency and optimize for Hugging Face Spaces deployment"
47
+
48
+ # Push to Hugging Face Spaces
49
+ git push
50
+ ```
51
+
52
+ ### Step 3: Verify Model LFS Tracking
53
+ ```bash
54
+ # Check if model is tracked by Git LFS
55
+ git lfs ls-files
56
+
57
+ # Should show: model/multimodal_gated_model_2.7_GGG.pth
58
+ ```
59
+
60
+ If the model ISN'T shown, track it:
61
+ ```bash
62
+ git lfs track "model/*.pth"
63
+ git add .gitattributes
64
+ git add model/multimodal_gated_model_2.7_GGG.pth
65
+ git commit -m "Add Git LFS tracking for model file"
66
+ git push
67
+ ```
68
+
69
+ ## Files That MUST Exist for Deployment
70
+
71
+ ```
72
+ βœ… app.py # Main application
73
+ βœ… requirements.txt # Python dependencies
74
+ βœ… packages.txt # System dependencies
75
+ βœ… README.md # Documentation
76
+ βœ… confidence_scores.json # Confidence data
77
+ βœ… model/multimodal_gated_model_2.7_GGG.pth # Model (tracked by LFS)
78
+ βœ… model/multimodal_cat_mappings_GGG.json # Category mappings
79
+ βœ… .gitattributes # LFS configuration
80
+ βœ… .dockerignore # Build optimization
81
+ ```
82
+
83
+ ## Expected Result After Fix
84
+
85
+ - βœ… Build should complete successfully in 5-10 minutes
86
+ - βœ… No Node.js errors
87
+ - βœ… Smaller Docker image (excluded unnecessary files)
88
+ - βœ… Space status: "Running"
89
+ - βœ… API accessible and functional
90
+
91
+ ## Test After Deployment
92
+
93
+ ```python
94
+ from gradio_client import Client
95
+
96
+ client = Client("your-username/ABTestPredictor")
97
+ result = client.predict(
98
+ "control.jpg",
99
+ "variant.jpg",
100
+ "SaaS", "B2B", "High-Intent Lead Gen",
101
+ "B2B Software & Tech", "Awareness & Discovery",
102
+ api_name="/predict_with_categorical_data"
103
+ )
104
+ print(result)
105
+ ```
106
+
107
+ ## If Build Still Fails
108
+
109
+ 1. Check logs in Hugging Face Spaces
110
+ 2. Verify all required files are present
111
+ 3. Check that model file is tracked by Git LFS: `git lfs ls-files`
112
+ 4. Ensure packages.txt contains `tesseract-ocr`
113
+ 5. Review DEPLOYMENT_FIX.md for detailed troubleshooting
114
+
115
+ ## Changes Made to Files
116
+
117
+ ### app.py
118
+ - Removed Node.js subprocess calls
119
+ - Simplified category mapping creation
120
+ - No external dependencies
121
+
122
+ ### New Files
123
+ - `.dockerignore` - Excludes unnecessary files from build
124
+ - `.gitattributes` - Ensures proper Git LFS tracking
125
+ - `DEPLOYMENT_FIX.md` - Detailed troubleshooting guide
126
+ - `QUICK_FIX_SUMMARY.md` - This file
127
+
128
+ ## Key Improvements
129
+
130
+ πŸš€ **Faster builds**: Excluded documentation reduces build time
131
+ πŸ”§ **Simpler deployment**: No Node.js dependency
132
+ πŸ“¦ **Smaller images**: Only essential files included
133
+ βœ… **Better reliability**: Standard Python-only approach
134
+
app.py CHANGED
@@ -170,47 +170,18 @@ if not os.path.exists(MODEL_DIR):
170
  os.makedirs(MODEL_DIR)
171
 
172
  if not os.path.exists(CAT_MAPPINGS_SAVE_PATH):
173
- print(f"⚠️ GGG Category mappings not found. Loading from metadata.js...")
174
- # Import the real metadata from metadata.js
175
- import subprocess
176
- import sys
177
-
178
- try:
179
- # Use Node.js to extract the categoryMappings from metadata.js
180
- result = subprocess.run([
181
- 'node', '-e',
182
- 'const meta = require("./metadata.js"); console.log(JSON.stringify(meta.categoryMappings));'
183
- ], capture_output=True, text=True, cwd='.')
184
-
185
- if result.returncode == 0:
186
- category_mappings_from_js = json.loads(result.stdout.strip())
187
- print(f"βœ… Successfully loaded category mappings from metadata.js for GGG model")
188
- with open(CAT_MAPPINGS_SAVE_PATH, 'w') as f:
189
- json.dump(category_mappings_from_js, f, indent=2)
190
- else:
191
- print(f"⚠️ Failed to load from metadata.js: {result.stderr}")
192
- print("Creating GGG-compatible dummy mappings as fallback...")
193
- dummy_mappings = {
194
- "Business Model": {"num_categories": 4, "categories": ["E-Commerce", "Lead Generation", "Other*", "SaaS"]},
195
- "Customer Type": {"num_categories": 4, "categories": ["B2B", "B2C", "Both", "Other*"]},
196
- "grouped_conversion_type": {"num_categories": 6, "categories": ["Direct Purchase", "High-Intent Lead Gen", "Info/Content Lead Gen", "Location Search", "Non-Profit/Community", "Other Conversion"]},
197
- "grouped_industry": {"num_categories": 14, "categories": ["Automotive & Transportation", "B2B Services", "B2B Software & Tech", "Consumer Services", "Consumer Software & Apps", "Education", "Finance, Insurance & Real Estate", "Food, Hospitality & Travel", "Health & Wellness", "Industrial & Manufacturing", "Media & Entertainment", "Non-Profit & Government", "Other", "Retail & E-commerce"]},
198
- "grouped_page_type": {"num_categories": 5, "categories": ["Awareness & Discovery", "Consideration & Evaluation", "Conversion", "Internal & Navigation", "Post-Conversion & Other"]}
199
- }
200
- with open(CAT_MAPPINGS_SAVE_PATH, 'w') as f:
201
- json.dump(dummy_mappings, f, indent=2)
202
- except Exception as e:
203
- print(f"⚠️ Error loading metadata.js: {e}")
204
- print("Creating GGG-compatible dummy mappings as fallback...")
205
- dummy_mappings = {
206
- "Business Model": {"num_categories": 4, "categories": ["E-Commerce", "Lead Generation", "Other*", "SaaS"]},
207
- "Customer Type": {"num_categories": 4, "categories": ["B2B", "B2C", "Both", "Other*"]},
208
- "grouped_conversion_type": {"num_categories": 6, "categories": ["Direct Purchase", "High-Intent Lead Gen", "Info/Content Lead Gen", "Location Search", "Non-Profit/Community", "Other Conversion"]},
209
- "grouped_industry": {"num_categories": 14, "categories": ["Automotive & Transportation", "B2B Services", "B2B Software & Tech", "Consumer Services", "Consumer Software & Apps", "Education", "Finance, Insurance & Real Estate", "Food, Hospitality & Travel", "Health & Wellness", "Industrial & Manufacturing", "Media & Entertainment", "Non-Profit & Government", "Other", "Retail & E-commerce"]},
210
- "grouped_page_type": {"num_categories": 5, "categories": ["Awareness & Discovery", "Consideration & Evaluation", "Conversion", "Internal & Navigation", "Post-Conversion & Other"]}
211
- }
212
- with open(CAT_MAPPINGS_SAVE_PATH, 'w') as f:
213
- json.dump(dummy_mappings, f, indent=2)
214
 
215
  with open(CAT_MAPPINGS_SAVE_PATH, 'r') as f:
216
  category_mappings = json.load(f)
 
170
  os.makedirs(MODEL_DIR)
171
 
172
  if not os.path.exists(CAT_MAPPINGS_SAVE_PATH):
173
+ print(f"⚠️ GGG Category mappings not found. Creating default mappings...")
174
+ # Create the standard category mappings expected by the model
175
+ default_mappings = {
176
+ "Business Model": {"num_categories": 4, "categories": ["E-Commerce", "Lead Generation", "Other*", "SaaS"]},
177
+ "Customer Type": {"num_categories": 4, "categories": ["B2B", "B2C", "Both", "Other*"]},
178
+ "grouped_conversion_type": {"num_categories": 6, "categories": ["Direct Purchase", "High-Intent Lead Gen", "Info/Content Lead Gen", "Location Search", "Non-Profit/Community", "Other Conversion"]},
179
+ "grouped_industry": {"num_categories": 14, "categories": ["Automotive & Transportation", "B2B Services", "B2B Software & Tech", "Consumer Services", "Consumer Software & Apps", "Education", "Finance, Insurance & Real Estate", "Food, Hospitality & Travel", "Health & Wellness", "Industrial & Manufacturing", "Media & Entertainment", "Non-Profit & Government", "Other", "Retail & E-commerce"]},
180
+ "grouped_page_type": {"num_categories": 5, "categories": ["Awareness & Discovery", "Consideration & Evaluation", "Conversion", "Internal & Navigation", "Post-Conversion & Other"]}
181
+ }
182
+ with open(CAT_MAPPINGS_SAVE_PATH, 'w') as f:
183
+ json.dump(default_mappings, f, indent=2)
184
+ print(f"βœ… Created default category mappings at {CAT_MAPPINGS_SAVE_PATH}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
185
 
186
  with open(CAT_MAPPINGS_SAVE_PATH, 'r') as f:
187
  category_mappings = json.load(f)