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

Deploy: Optimize for Hugging Face Spaces - remove AI APIs and unnecessary files

Browse files
API_USAGE.md DELETED
@@ -1,321 +0,0 @@
1
- # A/B Test Predictor API - Integration Guide
2
-
3
- This guide shows you how to integrate the A/B Test Predictor model into your own applications.
4
-
5
- ## 🚀 Quick Start
6
-
7
- Your Hugging Face Space provides a built-in API that you can call from any application!
8
-
9
- **Space URL**: `https://nitish-spz-abtestpredictorv2.hf.space`
10
-
11
- ---
12
-
13
- ## Method 1: Using Gradio Client (Recommended)
14
-
15
- ### Python
16
-
17
- ```python
18
- from gradio_client import Client
19
- from PIL import Image
20
-
21
- # Connect to your Space
22
- client = Client("nitish-spz/ABTestPredictorV2")
23
-
24
- # Option A: Auto-categorization (AI analyzes images automatically)
25
- result = client.predict(
26
- control_image="./path/to/control.jpg", # Local file path
27
- variant_image="./path/to/variant.jpg", # Local file path
28
- api_name="/predict_with_auto_categorization"
29
- )
30
-
31
- print(result)
32
- # Output: Full JSON with prediction, categories, pattern, and confidence scores
33
-
34
- # Option B: Manual categorization (you provide the categories)
35
- result = client.predict(
36
- control_image="./control.jpg",
37
- variant_image="./variant.jpg",
38
- business_model="SaaS",
39
- customer_type="B2B",
40
- conversion_type="High-Intent Lead Gen",
41
- industry="B2B Software & Tech",
42
- page_type="Conversion",
43
- api_name="/predict_single"
44
- )
45
-
46
- print(result)
47
- ```
48
-
49
- ### JavaScript/Node.js
50
-
51
- ```javascript
52
- import { client } from "@gradio/client";
53
-
54
- const app = await client("nitish-spz/ABTestPredictorV2");
55
-
56
- // Upload images and get prediction
57
- const result = await app.predict("/predict_with_auto_categorization", [
58
- "./control.jpg", // Control image path
59
- "./variant.jpg" // Variant image path
60
- ]);
61
-
62
- console.log(result.data);
63
- ```
64
-
65
- ---
66
-
67
- ## Method 2: Direct HTTP API Calls
68
-
69
- ### Python with requests
70
-
71
- ```python
72
- import requests
73
- import base64
74
-
75
- # Function to encode image as base64
76
- def encode_image(image_path):
77
- with open(image_path, "rb") as image_file:
78
- return base64.b64encode(image_file.read()).decode('utf-8')
79
-
80
- # Encode images
81
- control_b64 = encode_image("control.jpg")
82
- variant_b64 = encode_image("variant.jpg")
83
-
84
- # Make API call
85
- response = requests.post(
86
- "https://nitish-spz-abtestpredictorv2.hf.space/api/predict",
87
- json={
88
- "data": [control_b64, variant_b64]
89
- }
90
- )
91
-
92
- result = response.json()
93
- print(result)
94
- ```
95
-
96
- ### JavaScript/Fetch
97
-
98
- ```javascript
99
- async function predictABTest(controlImageFile, variantImageFile) {
100
- // Convert files to base64
101
- const controlBase64 = await fileToBase64(controlImageFile);
102
- const variantBase64 = await fileToBase64(variantImageFile);
103
-
104
- // Make API call
105
- const response = await fetch(
106
- 'https://nitish-spz-abtestpredictorv2.hf.space/api/predict',
107
- {
108
- method: 'POST',
109
- headers: {
110
- 'Content-Type': 'application/json',
111
- },
112
- body: JSON.stringify({
113
- data: [controlBase64, variantBase64]
114
- })
115
- }
116
- );
117
-
118
- const result = await response.json();
119
- return result;
120
- }
121
-
122
- function fileToBase64(file) {
123
- return new Promise((resolve, reject) => {
124
- const reader = new FileReader();
125
- reader.readAsDataURL(file);
126
- reader.onload = () => resolve(reader.result.split(',')[1]);
127
- reader.onerror = error => reject(error);
128
- });
129
- }
130
- ```
131
-
132
- ### cURL
133
-
134
- ```bash
135
- # Using Gradio API
136
- curl -X POST https://nitish-spz-abtestpredictorv2.hf.space/api/predict \
137
- -H "Content-Type: application/json" \
138
- -d '{
139
- "data": [
140
- "data:image/jpeg;base64,/9j/4AAQSkZJRg...",
141
- "data:image/jpeg;base64,/9j/4AAQSkZJRg..."
142
- ]
143
- }'
144
- ```
145
-
146
- ---
147
-
148
- ## Method 3: Embed in Your Website (iframe)
149
-
150
- ```html
151
- <iframe
152
- src="https://nitish-spz-abtestpredictorv2.hf.space"
153
- frameborder="0"
154
- width="100%"
155
- height="800"
156
- ></iframe>
157
- ```
158
-
159
- ---
160
-
161
- ## Method 4: React Integration
162
-
163
- ```jsx
164
- import React, { useState } from 'react';
165
- import { client } from "@gradio/client";
166
-
167
- function ABTestPredictor() {
168
- const [result, setResult] = useState(null);
169
- const [loading, setLoading] = useState(false);
170
-
171
- const handlePredict = async (controlFile, variantFile) => {
172
- setLoading(true);
173
- try {
174
- const app = await client("nitish-spz/ABTestPredictorV2");
175
- const prediction = await app.predict("/predict_with_auto_categorization", [
176
- controlFile,
177
- variantFile
178
- ]);
179
- setResult(prediction.data);
180
- } catch (error) {
181
- console.error("Prediction failed:", error);
182
- } finally {
183
- setLoading(false);
184
- }
185
- };
186
-
187
- return (
188
- <div>
189
- <input
190
- type="file"
191
- onChange={(e) => handlePredict(e.target.files[0], variantFile)}
192
- />
193
- {/* Display result */}
194
- {result && <pre>{JSON.stringify(result, null, 2)}</pre>}
195
- </div>
196
- );
197
- }
198
- ```
199
-
200
- ---
201
-
202
- ## Response Format
203
-
204
- The API returns a JSON object with the following structure:
205
-
206
- ```json
207
- {
208
- "🎯 Prediction Results": {
209
- "🏆 VARIANT WINS": "0.987",
210
- "📊 Model Confidence": "64.7%",
211
- "📈 Training Data": "1656 samples",
212
- "✅ Historical Accuracy": "119/184 correct",
213
- "🎯 Win/Loss Ratio": "71 wins in 184 tests"
214
- },
215
- "🤖 Auto-Detected Categories": {
216
- "Business Model": "SaaS",
217
- "Customer Type": "B2B",
218
- "Conversion Type": "High-Intent Lead Gen",
219
- "Industry": "B2B Software & Tech",
220
- "Page Type": "Conversion"
221
- },
222
- "🎯 Detected A/B Test Pattern": {
223
- "Pattern": "Double Column Form",
224
- "Description": "The variant implements a 'Double Column Form' modification"
225
- },
226
- "📊 Processing Info": {
227
- "Total Processing Time": "29.58s",
228
- "AI Categorization": "✅ Perplexity Sonar Reasoning Pro",
229
- "Pattern Detection": "✅ Gemini Pro Vision",
230
- "Confidence Source": "B2B Software & Tech | Conversion",
231
- "Total Patterns Analyzed": 359
232
- }
233
- }
234
- ```
235
-
236
- ---
237
-
238
- ## Rate Limits & Best Practices
239
-
240
- 1. **Free Tier**: Hugging Face Spaces have rate limits. For high-volume usage, consider upgrading to a paid plan.
241
-
242
- 2. **Image Size**: Keep images under 5MB for faster processing.
243
-
244
- 3. **Caching**: Cache results for identical image pairs to avoid redundant API calls.
245
-
246
- 4. **Error Handling**: Always implement proper error handling for API calls.
247
-
248
- 5. **Async Processing**: For batch processing, use async/await or threading.
249
-
250
- ---
251
-
252
- ## Example: Full Integration in a Web App
253
-
254
- ```python
255
- from flask import Flask, request, jsonify
256
- from gradio_client import Client
257
-
258
- app = Flask(__name__)
259
- predictor = Client("nitish-spz/ABTestPredictorV2")
260
-
261
- @app.route('/predict', methods=['POST'])
262
- def predict():
263
- try:
264
- # Get images from request
265
- control_img = request.files['control_image']
266
- variant_img = request.files['variant_image']
267
-
268
- # Save temporarily
269
- control_path = f"/tmp/{control_img.filename}"
270
- variant_path = f"/tmp/{variant_img.filename}"
271
- control_img.save(control_path)
272
- variant_img.save(variant_path)
273
-
274
- # Run prediction
275
- result = predictor.predict(
276
- control_path,
277
- variant_path,
278
- api_name="/predict_with_auto_categorization"
279
- )
280
-
281
- return jsonify({
282
- "success": True,
283
- "data": result
284
- })
285
- except Exception as e:
286
- return jsonify({
287
- "success": False,
288
- "error": str(e)
289
- }), 500
290
-
291
- if __name__ == '__main__':
292
- app.run(debug=True)
293
- ```
294
-
295
- ---
296
-
297
- ## Need Help?
298
-
299
- - Check the [Gradio Client Documentation](https://www.gradio.app/guides/getting-started-with-the-python-client)
300
- - Visit your Space: https://huggingface.co/spaces/nitish-spz/ABTestPredictorV2
301
- - For issues, check the Space logs
302
-
303
- ---
304
-
305
- ## Authentication (if you make the Space private)
306
-
307
- If you set your Space to private, users will need an authentication token:
308
-
309
- ```python
310
- from gradio_client import Client
311
-
312
- client = Client(
313
- "nitish-spz/ABTestPredictorV2",
314
- hf_token="hf_..." # Your Hugging Face token
315
- )
316
- ```
317
-
318
- ---
319
-
320
- **Happy Integrating! 🚀**
321
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
DEPLOY_NOW.sh ADDED
@@ -0,0 +1,78 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/bin/bash
2
+
3
+ # Quick deployment script for Hugging Face Space
4
+ # This removes unnecessary files and deploys the Space
5
+
6
+ echo "🚀 Preparing to deploy ABTestPredictor Space..."
7
+ echo ""
8
+
9
+ # Step 1: Remove unnecessary files
10
+ echo "🗑️ Removing unnecessary files..."
11
+ rm -f patterbs.json
12
+ rm -f metadata.js
13
+ rm -f confidence_scores.js
14
+ rm -f frontend.html
15
+ rm -f index_v2.html
16
+ rm -f API_USAGE.md
17
+ rm -rf model/
18
+
19
+ echo "✅ Cleanup complete"
20
+ echo ""
21
+
22
+ # Step 2: Check required files
23
+ echo "📋 Checking required files..."
24
+ required_files=("app.py" "requirements.txt" "packages.txt" "README.md" "confidence_scores.json")
25
+ missing_files=()
26
+
27
+ for file in "${required_files[@]}"; do
28
+ if [ ! -f "$file" ]; then
29
+ missing_files+=("$file")
30
+ fi
31
+ done
32
+
33
+ if [ ${#missing_files[@]} -gt 0 ]; then
34
+ echo "❌ Missing required files:"
35
+ printf '%s\n' "${missing_files[@]}"
36
+ exit 1
37
+ fi
38
+
39
+ echo "✅ All required files present"
40
+ echo ""
41
+
42
+ # Step 3: Show what will be committed
43
+ echo "📦 Files to be committed:"
44
+ git add .
45
+ git status --short
46
+ echo ""
47
+
48
+ # Step 4: Confirm before pushing
49
+ read -p "🤔 Do you want to commit and push these changes? (y/n) " -n 1 -r
50
+ echo ""
51
+
52
+ if [[ $REPLY =~ ^[Yy]$ ]]; then
53
+ # Commit
54
+ echo "💾 Committing changes..."
55
+ git commit -m "Deploy: Remove AI APIs, optimize for Hugging Face Spaces
56
+
57
+ - Removed Perplexity and Gemini API integrations
58
+ - Removed unnecessary files (patterbs.json, metadata.js, etc.)
59
+ - Model will download from nitish-spz/ABTestPredictor
60
+ - Added categorical data input API
61
+ - Optimized with .dockerignore"
62
+
63
+ # Push
64
+ echo "🚀 Pushing to Hugging Face Space..."
65
+ git push origin main
66
+
67
+ echo ""
68
+ echo "✅ Deployment complete!"
69
+ echo ""
70
+ echo "🔍 Monitor your Space build at:"
71
+ echo " https://huggingface.co/spaces/SpiralyzeLLC/ABTestPredictor"
72
+ echo ""
73
+ echo "⏱️ Expected build time: 5-10 minutes"
74
+ else
75
+ echo "❌ Deployment cancelled"
76
+ git reset
77
+ fi
78
+
SPACE_SETUP_GUIDE.md ADDED
@@ -0,0 +1,230 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Hugging Face Space Setup Guide
2
+
3
+ ## Understanding Your Repositories
4
+
5
+ You have **TWO** separate repositories:
6
+
7
+ ### 1. Model Repository: `nitish-spz/ABTestPredictor`
8
+ - **Purpose**: Store the model files
9
+ - **Contains**:
10
+ - `multimodal_gated_model_2.7_GGG.pth` (789 MB)
11
+ - `multimodal_cat_mappings_GGG.json`
12
+ - **Access**: Read-only, Space downloads from here
13
+
14
+ ### 2. Space Repository: `SpiralyzeLLC/ABTestPredictor`
15
+ - **Purpose**: Run the Gradio application
16
+ - **Contains**: All application code + downloads model from repo #1
17
+ - **Access**: This is what deploys and runs
18
+
19
+ ## Required Files in Space Repository
20
+
21
+ Your Space needs these files (but NOT the large model file):
22
+
23
+ ```
24
+ ✅ app.py # Main application code
25
+ ✅ requirements.txt # Python dependencies
26
+ ✅ packages.txt # System dependencies (tesseract-ocr)
27
+ ✅ README.md # Project documentation
28
+ ✅ confidence_scores.json # Confidence data (14KB)
29
+ ✅ .gitattributes # Git LFS config
30
+ ✅ .dockerignore # Build optimization
31
+ ❌ model/ folder # NOT needed - downloads from model repo
32
+ ❌ patterbs.json # NOT needed - removed feature
33
+ ❌ metadata.js # NOT needed - removed feature
34
+ ❌ confidence_scores.js # NOT needed - use .json instead
35
+ ```
36
+
37
+ ## How the Model Loading Works
38
+
39
+ Your `app.py` is configured to:
40
+ 1. Check if model exists locally in `model/` folder
41
+ 2. If not, download from `nitish-spz/ABTestPredictor` model repository
42
+ 3. Cache it for future use
43
+
44
+ ```python
45
+ # In app.py lines 707-748
46
+ if os.path.exists(MODEL_SAVE_PATH):
47
+ model_path = MODEL_SAVE_PATH
48
+ print(f"✅ Using local model")
49
+ else:
50
+ print(f"📥 Downloading from Model Hub...")
51
+ model_path = download_model_from_hub()
52
+ ```
53
+
54
+ ## Deployment Steps
55
+
56
+ ### Step 1: Verify Required Files Exist Locally
57
+ ```bash
58
+ cd /Users/nitish/Spiralyze/HuggingFace/Spaces/ABTestPredictor
59
+
60
+ # Check essential files
61
+ ls -lh app.py requirements.txt packages.txt README.md confidence_scores.json
62
+
63
+ # Should all exist
64
+ ```
65
+
66
+ ### Step 2: Remove Large/Unnecessary Files
67
+ ```bash
68
+ # Remove the local model folder (Space will download from model repo)
69
+ rm -rf model/
70
+
71
+ # Remove unused files from old version
72
+ rm -f patterbs.json metadata.js confidence_scores.js frontend.html index_v2.html
73
+ ```
74
+
75
+ ### Step 3: Verify Git Remote Points to Space
76
+ ```bash
77
+ git remote -v
78
+ # Should show: https://huggingface.co/spaces/SpiralyzeLLC/ABTestPredictor
79
+ ```
80
+
81
+ ### Step 4: Commit and Push to Space
82
+ ```bash
83
+ # Add all files
84
+ git add .
85
+
86
+ # Commit
87
+ git commit -m "Deploy: Add all application files, download model from hub"
88
+
89
+ # Push to Space
90
+ git push origin main
91
+ ```
92
+
93
+ ### Step 5: Monitor Build
94
+ 1. Go to https://huggingface.co/spaces/SpiralyzeLLC/ABTestPredictor
95
+ 2. Click "Logs" tab
96
+ 3. Watch the build progress
97
+ 4. First build takes 5-10 minutes (downloading model)
98
+
99
+ ## If Build Fails
100
+
101
+ ### Check These Files Exist in Space Repo:
102
+ ```bash
103
+ # Essential files checklist
104
+ app.py ✅
105
+ requirements.txt ✅
106
+ packages.txt ✅
107
+ README.md ✅
108
+ confidence_scores.json ✅
109
+ .dockerignore ✅
110
+ .gitattributes ✅
111
+ ```
112
+
113
+ ### Verify Model Repo is Accessible
114
+ Your app downloads from `nitish-spz/ABTestPredictor`. Verify:
115
+ 1. Go to https://huggingface.co/nitish-spz/ABTestPredictor
116
+ 2. Check files are visible
117
+ 3. Make sure it's **public** (not private)
118
+
119
+ ### Check requirements.txt
120
+ ```bash
121
+ cat requirements.txt
122
+ ```
123
+ Should contain:
124
+ ```
125
+ torch
126
+ transformers
127
+ pandas
128
+ scikit-learn
129
+ Pillow
130
+ gradio
131
+ pytesseract
132
+ spaces
133
+ huggingface_hub
134
+ python-dotenv
135
+ ```
136
+
137
+ ### Check packages.txt
138
+ ```bash
139
+ cat packages.txt
140
+ ```
141
+ Should contain:
142
+ ```
143
+ tesseract-ocr
144
+ ```
145
+
146
+ ## Common Issues
147
+
148
+ ### Issue 1: "Model file not found"
149
+ **Cause**: Model repo is private or inaccessible
150
+ **Fix**: Make `nitish-spz/ABTestPredictor` public
151
+
152
+ ### Issue 2: "No module named X"
153
+ **Cause**: Missing dependency in requirements.txt
154
+ **Fix**: Add the missing package to requirements.txt
155
+
156
+ ### Issue 3: "Tesseract not found"
157
+ **Cause**: Missing system dependency
158
+ **Fix**: Ensure packages.txt contains `tesseract-ocr`
159
+
160
+ ### Issue 4: Build hangs at "Installing requirements"
161
+ **Cause**: PyTorch is large (~2GB)
162
+ **Fix**: Wait 5-10 minutes, this is normal
163
+
164
+ ## Space Configuration
165
+
166
+ Your Space should have these settings:
167
+ - **SDK**: Gradio
168
+ - **SDK Version**: 4.44.0
169
+ - **Hardware**: GPU (recommended: T4 or better)
170
+ - **Python Version**: 3.10 (default)
171
+ - **Visibility**: Public or Private (your choice)
172
+
173
+ ## File Size Limits
174
+
175
+ - **Space repo**: Each file < 50MB (except LFS)
176
+ - **Model repo**: Files > 10MB should use Git LFS
177
+ - **Total Space size**: No hard limit, but keep it reasonable
178
+
179
+ ## Success Indicators
180
+
181
+ ✅ Build completes without errors
182
+ ✅ Space status shows "Running"
183
+ ✅ Can access the Gradio interface
184
+ ✅ Making predictions returns results
185
+ ✅ Logs show "Successfully loaded model"
186
+
187
+ ## Expected First-Run Behavior
188
+
189
+ ```
190
+ 🚀 Using device: cuda
191
+ 🔥 GPU: Tesla T4
192
+ 📥 Model not found locally, downloading from Model Hub...
193
+ 📥 Downloading model from Hugging Face Model Hub: nitish-spz/ABTestPredictor
194
+ ✅ Model downloaded to: /home/user/.cache/huggingface/...
195
+ ✅ Successfully loaded GGG model weights
196
+ ✅ Model and processors loaded successfully.
197
+ Running on public URL: https://spiralyzellc-abtestpredictor.hf.space
198
+ ```
199
+
200
+ ## Testing After Deployment
201
+
202
+ ### Test 1: Web Interface
203
+ 1. Visit your Space URL
204
+ 2. Upload test images
205
+ 3. Select categories
206
+ 4. Click predict
207
+ 5. Should see results in ~3-5 seconds
208
+
209
+ ### Test 2: API Client
210
+ ```python
211
+ from gradio_client import Client
212
+
213
+ client = Client("SpiralyzeLLC/ABTestPredictor")
214
+ result = client.predict(
215
+ "control.jpg",
216
+ "variant.jpg",
217
+ "SaaS", "B2B", "High-Intent Lead Gen",
218
+ "B2B Software & Tech", "Awareness & Discovery",
219
+ api_name="/predict_with_categorical_data"
220
+ )
221
+ print(result)
222
+ ```
223
+
224
+ ## Need Help?
225
+
226
+ 1. Check Space logs for errors
227
+ 2. Review DEPLOYMENT_FIX.md for detailed troubleshooting
228
+ 3. Verify all required files are in Space repo
229
+ 4. Ensure model repo is public and accessible
230
+
app.py CHANGED
@@ -33,6 +33,7 @@ CAT_MAPPINGS_SAVE_PATH = os.path.join(MODEL_DIR, "multimodal_cat_mappings_GGG.js
33
  # API Configuration - AI API calls removed, using direct categorical inputs
34
 
35
  # Hugging Face Model Hub Configuration
 
36
  HF_MODEL_REPO = "nitish-spz/ABTestPredictor" # Your model repository
37
  HF_MODEL_FILENAME = "multimodal_gated_model_2.7_GGG.pth"
38
  HF_MAPPINGS_FILENAME = "multimodal_cat_mappings_GGG.json"
 
33
  # API Configuration - AI API calls removed, using direct categorical inputs
34
 
35
  # Hugging Face Model Hub Configuration
36
+ # Point to your model repository (not the Space)
37
  HF_MODEL_REPO = "nitish-spz/ABTestPredictor" # Your model repository
38
  HF_MODEL_FILENAME = "multimodal_gated_model_2.7_GGG.pth"
39
  HF_MAPPINGS_FILENAME = "multimodal_cat_mappings_GGG.json"
confidence_scores.js DELETED
@@ -1,583 +0,0 @@
1
- /**
2
- * Confidence scores for Industry + Page Type combinations
3
- * Generated from holdout_set_statistics.csv (grouping_level = 2)
4
- *
5
- * Key format: "Industry|Page Type"
6
- * Much higher sample counts and more reliable than 5-feature combinations
7
- */
8
-
9
- const confidenceMapping = {
10
- "Automotive & Transportation|Awareness & Discovery": {
11
- "accuracy": 0.6,
12
- "count": 15,
13
- "training_data_count": 135,
14
- "correct_predictions": 9,
15
- "actual_wins": 6,
16
- "predicted_wins": 2
17
- },
18
- "Automotive & Transportation|Consideration & Evaluation": {
19
- "accuracy": 0.667,
20
- "count": 6,
21
- "training_data_count": 54,
22
- "correct_predictions": 4,
23
- "actual_wins": 2,
24
- "predicted_wins": 2
25
- },
26
- "Automotive & Transportation|Conversion": {
27
- "accuracy": 1.0,
28
- "count": 3,
29
- "training_data_count": 27,
30
- "correct_predictions": 3,
31
- "actual_wins": 0,
32
- "predicted_wins": 0
33
- },
34
- "Automotive & Transportation|Internal & Navigation": {
35
- "accuracy": 0.571,
36
- "count": 7,
37
- "training_data_count": 63,
38
- "correct_predictions": 4,
39
- "actual_wins": 3,
40
- "predicted_wins": 2
41
- },
42
- "B2B Services|Awareness & Discovery": {
43
- "accuracy": 0.698,
44
- "count": 483,
45
- "training_data_count": 4347,
46
- "correct_predictions": 337,
47
- "actual_wins": 186,
48
- "predicted_wins": 178
49
- },
50
- "B2B Services|Consideration & Evaluation": {
51
- "accuracy": 0.657,
52
- "count": 175,
53
- "training_data_count": 1575,
54
- "correct_predictions": 115,
55
- "actual_wins": 82,
56
- "predicted_wins": 78
57
- },
58
- "B2B Services|Conversion": {
59
- "accuracy": 0.604,
60
- "count": 53,
61
- "training_data_count": 477,
62
- "correct_predictions": 32,
63
- "actual_wins": 26,
64
- "predicted_wins": 23
65
- },
66
- "B2B Services|Internal & Navigation": {
67
- "accuracy": 0.719,
68
- "count": 139,
69
- "training_data_count": 1251,
70
- "correct_predictions": 100,
71
- "actual_wins": 58,
72
- "predicted_wins": 43
73
- },
74
- "B2B Services|Post-Conversion & Other": {
75
- "accuracy": 0.571,
76
- "count": 14,
77
- "training_data_count": 126,
78
- "correct_predictions": 8,
79
- "actual_wins": 4,
80
- "predicted_wins": 8
81
- },
82
- "B2B Software & Tech|Awareness & Discovery": {
83
- "accuracy": 0.661,
84
- "count": 1626,
85
- "training_data_count": 14634,
86
- "correct_predictions": 1074,
87
- "actual_wins": 667,
88
- "predicted_wins": 625
89
- },
90
- "B2B Software & Tech|Consideration & Evaluation": {
91
- "accuracy": 0.617,
92
- "count": 1046,
93
- "training_data_count": 9414,
94
- "correct_predictions": 645,
95
- "actual_wins": 432,
96
- "predicted_wins": 397
97
- },
98
- "B2B Software & Tech|Conversion": {
99
- "accuracy": 0.647,
100
- "count": 184,
101
- "training_data_count": 1656,
102
- "correct_predictions": 119,
103
- "actual_wins": 71,
104
- "predicted_wins": 74
105
- },
106
- "B2B Software & Tech|Internal & Navigation": {
107
- "accuracy": 0.715,
108
- "count": 376,
109
- "training_data_count": 3384,
110
- "correct_predictions": 269,
111
- "actual_wins": 138,
112
- "predicted_wins": 117
113
- },
114
- "B2B Software & Tech|Post-Conversion & Other": {
115
- "accuracy": 0.78,
116
- "count": 41,
117
- "training_data_count": 369,
118
- "correct_predictions": 32,
119
- "actual_wins": 15,
120
- "predicted_wins": 18
121
- },
122
- "Consumer Services|Awareness & Discovery": {
123
- "accuracy": 0.723,
124
- "count": 238,
125
- "training_data_count": 2142,
126
- "correct_predictions": 172,
127
- "actual_wins": 97,
128
- "predicted_wins": 85
129
- },
130
- "Consumer Services|Consideration & Evaluation": {
131
- "accuracy": 0.592,
132
- "count": 103,
133
- "training_data_count": 927,
134
- "correct_predictions": 61,
135
- "actual_wins": 49,
136
- "predicted_wins": 41
137
- },
138
- "Consumer Services|Conversion": {
139
- "accuracy": 0.643,
140
- "count": 42,
141
- "training_data_count": 378,
142
- "correct_predictions": 27,
143
- "actual_wins": 12,
144
- "predicted_wins": 13
145
- },
146
- "Consumer Services|Internal & Navigation": {
147
- "accuracy": 0.607,
148
- "count": 56,
149
- "training_data_count": 504,
150
- "correct_predictions": 34,
151
- "actual_wins": 32,
152
- "predicted_wins": 22
153
- },
154
- "Consumer Services|Post-Conversion & Other": {
155
- "accuracy": 0.5,
156
- "count": 2,
157
- "training_data_count": 18,
158
- "correct_predictions": 1,
159
- "actual_wins": 1,
160
- "predicted_wins": 0
161
- },
162
- "Consumer Software & Apps|Awareness & Discovery": {
163
- "accuracy": 0.682,
164
- "count": 22,
165
- "training_data_count": 198,
166
- "correct_predictions": 15,
167
- "actual_wins": 5,
168
- "predicted_wins": 8
169
- },
170
- "Consumer Software & Apps|Consideration & Evaluation": {
171
- "accuracy": 0.9,
172
- "count": 10,
173
- "training_data_count": 90,
174
- "correct_predictions": 9,
175
- "actual_wins": 6,
176
- "predicted_wins": 5
177
- },
178
- "Consumer Software & Apps|Conversion": {
179
- "accuracy": 0.667,
180
- "count": 15,
181
- "training_data_count": 135,
182
- "correct_predictions": 10,
183
- "actual_wins": 5,
184
- "predicted_wins": 6
185
- },
186
- "Consumer Software & Apps|Internal & Navigation": {
187
- "accuracy": 0.2,
188
- "count": 5,
189
- "training_data_count": 45,
190
- "correct_predictions": 1,
191
- "actual_wins": 3,
192
- "predicted_wins": 3
193
- },
194
- "Consumer Software & Apps|Post-Conversion & Other": {
195
- "accuracy": 0.0,
196
- "count": 1,
197
- "training_data_count": 9,
198
- "correct_predictions": 0,
199
- "actual_wins": 1,
200
- "predicted_wins": 0
201
- },
202
- "Education|Awareness & Discovery": {
203
- "accuracy": 0.589,
204
- "count": 409,
205
- "training_data_count": 3681,
206
- "correct_predictions": 241,
207
- "actual_wins": 180,
208
- "predicted_wins": 170
209
- },
210
- "Education|Consideration & Evaluation": {
211
- "accuracy": 0.645,
212
- "count": 183,
213
- "training_data_count": 1647,
214
- "correct_predictions": 118,
215
- "actual_wins": 72,
216
- "predicted_wins": 77
217
- },
218
- "Education|Conversion": {
219
- "accuracy": 0.605,
220
- "count": 43,
221
- "training_data_count": 387,
222
- "correct_predictions": 26,
223
- "actual_wins": 16,
224
- "predicted_wins": 17
225
- },
226
- "Education|Internal & Navigation": {
227
- "accuracy": 0.661,
228
- "count": 177,
229
- "training_data_count": 1593,
230
- "correct_predictions": 117,
231
- "actual_wins": 70,
232
- "predicted_wins": 62
233
- },
234
- "Education|Post-Conversion & Other": {
235
- "accuracy": 0.308,
236
- "count": 13,
237
- "training_data_count": 117,
238
- "correct_predictions": 4,
239
- "actual_wins": 9,
240
- "predicted_wins": 8
241
- },
242
- "Finance, Insurance & Real Estate|Awareness & Discovery": {
243
- "accuracy": 0.662,
244
- "count": 417,
245
- "training_data_count": 3753,
246
- "correct_predictions": 276,
247
- "actual_wins": 172,
248
- "predicted_wins": 147
249
- },
250
- "Finance, Insurance & Real Estate|Consideration & Evaluation": {
251
- "accuracy": 0.596,
252
- "count": 193,
253
- "training_data_count": 1737,
254
- "correct_predictions": 115,
255
- "actual_wins": 82,
256
- "predicted_wins": 78
257
- },
258
- "Finance, Insurance & Real Estate|Conversion": {
259
- "accuracy": 0.615,
260
- "count": 52,
261
- "training_data_count": 468,
262
- "correct_predictions": 32,
263
- "actual_wins": 26,
264
- "predicted_wins": 22
265
- },
266
- "Finance, Insurance & Real Estate|Internal & Navigation": {
267
- "accuracy": 0.678,
268
- "count": 177,
269
- "training_data_count": 1593,
270
- "correct_predictions": 120,
271
- "actual_wins": 65,
272
- "predicted_wins": 60
273
- },
274
- "Finance, Insurance & Real Estate|Post-Conversion & Other": {
275
- "accuracy": 0.545,
276
- "count": 22,
277
- "training_data_count": 198,
278
- "correct_predictions": 12,
279
- "actual_wins": 13,
280
- "predicted_wins": 7
281
- },
282
- "Food, Hospitality & Travel|Awareness & Discovery": {
283
- "accuracy": 0.676,
284
- "count": 293,
285
- "training_data_count": 2637,
286
- "correct_predictions": 198,
287
- "actual_wins": 141,
288
- "predicted_wins": 136
289
- },
290
- "Food, Hospitality & Travel|Consideration & Evaluation": {
291
- "accuracy": 0.642,
292
- "count": 159,
293
- "training_data_count": 1431,
294
- "correct_predictions": 102,
295
- "actual_wins": 70,
296
- "predicted_wins": 59
297
- },
298
- "Food, Hospitality & Travel|Conversion": {
299
- "accuracy": 0.6,
300
- "count": 60,
301
- "training_data_count": 540,
302
- "correct_predictions": 36,
303
- "actual_wins": 31,
304
- "predicted_wins": 27
305
- },
306
- "Food, Hospitality & Travel|Internal & Navigation": {
307
- "accuracy": 0.63,
308
- "count": 73,
309
- "training_data_count": 657,
310
- "correct_predictions": 46,
311
- "actual_wins": 32,
312
- "predicted_wins": 27
313
- },
314
- "Food, Hospitality & Travel|Post-Conversion & Other": {
315
- "accuracy": 0.286,
316
- "count": 7,
317
- "training_data_count": 63,
318
- "correct_predictions": 2,
319
- "actual_wins": 2,
320
- "predicted_wins": 5
321
- },
322
- "Health & Wellness|Awareness & Discovery": {
323
- "accuracy": 0.631,
324
- "count": 643,
325
- "training_data_count": 5787,
326
- "correct_predictions": 406,
327
- "actual_wins": 262,
328
- "predicted_wins": 249
329
- },
330
- "Health & Wellness|Consideration & Evaluation": {
331
- "accuracy": 0.663,
332
- "count": 389,
333
- "training_data_count": 3501,
334
- "correct_predictions": 258,
335
- "actual_wins": 175,
336
- "predicted_wins": 156
337
- },
338
- "Health & Wellness|Conversion": {
339
- "accuracy": 0.632,
340
- "count": 106,
341
- "training_data_count": 954,
342
- "correct_predictions": 67,
343
- "actual_wins": 42,
344
- "predicted_wins": 53
345
- },
346
- "Health & Wellness|Internal & Navigation": {
347
- "accuracy": 0.654,
348
- "count": 156,
349
- "training_data_count": 1404,
350
- "correct_predictions": 102,
351
- "actual_wins": 72,
352
- "predicted_wins": 58
353
- },
354
- "Health & Wellness|Post-Conversion & Other": {
355
- "accuracy": 0.667,
356
- "count": 12,
357
- "training_data_count": 108,
358
- "correct_predictions": 8,
359
- "actual_wins": 5,
360
- "predicted_wins": 3
361
- },
362
- "Industrial & Manufacturing|Awareness & Discovery": {
363
- "accuracy": 0.573,
364
- "count": 171,
365
- "training_data_count": 1539,
366
- "correct_predictions": 98,
367
- "actual_wins": 75,
368
- "predicted_wins": 82
369
- },
370
- "Industrial & Manufacturing|Consideration & Evaluation": {
371
- "accuracy": 0.677,
372
- "count": 93,
373
- "training_data_count": 837,
374
- "correct_predictions": 63,
375
- "actual_wins": 34,
376
- "predicted_wins": 32
377
- },
378
- "Industrial & Manufacturing|Conversion": {
379
- "accuracy": 0.778,
380
- "count": 18,
381
- "training_data_count": 162,
382
- "correct_predictions": 14,
383
- "actual_wins": 6,
384
- "predicted_wins": 10
385
- },
386
- "Industrial & Manufacturing|Internal & Navigation": {
387
- "accuracy": 0.776,
388
- "count": 67,
389
- "training_data_count": 603,
390
- "correct_predictions": 52,
391
- "actual_wins": 25,
392
- "predicted_wins": 28
393
- },
394
- "Industrial & Manufacturing|Post-Conversion & Other": {
395
- "accuracy": 0.833,
396
- "count": 6,
397
- "training_data_count": 54,
398
- "correct_predictions": 5,
399
- "actual_wins": 4,
400
- "predicted_wins": 5
401
- },
402
- "Media & Entertainment|Awareness & Discovery": {
403
- "accuracy": 0.701,
404
- "count": 251,
405
- "training_data_count": 2259,
406
- "correct_predictions": 176,
407
- "actual_wins": 99,
408
- "predicted_wins": 106
409
- },
410
- "Media & Entertainment|Consideration & Evaluation": {
411
- "accuracy": 0.663,
412
- "count": 95,
413
- "training_data_count": 855,
414
- "correct_predictions": 63,
415
- "actual_wins": 28,
416
- "predicted_wins": 32
417
- },
418
- "Media & Entertainment|Conversion": {
419
- "accuracy": 0.792,
420
- "count": 24,
421
- "training_data_count": 216,
422
- "correct_predictions": 19,
423
- "actual_wins": 10,
424
- "predicted_wins": 11
425
- },
426
- "Media & Entertainment|Internal & Navigation": {
427
- "accuracy": 0.676,
428
- "count": 68,
429
- "training_data_count": 612,
430
- "correct_predictions": 46,
431
- "actual_wins": 24,
432
- "predicted_wins": 18
433
- },
434
- "Media & Entertainment|Post-Conversion & Other": {
435
- "accuracy": 0.6,
436
- "count": 5,
437
- "training_data_count": 45,
438
- "correct_predictions": 3,
439
- "actual_wins": 1,
440
- "predicted_wins": 1
441
- },
442
- "Non-Profit & Government|Awareness & Discovery": {
443
- "accuracy": 0.692,
444
- "count": 107,
445
- "training_data_count": 963,
446
- "correct_predictions": 74,
447
- "actual_wins": 36,
448
- "predicted_wins": 37
449
- },
450
- "Non-Profit & Government|Consideration & Evaluation": {
451
- "accuracy": 0.531,
452
- "count": 32,
453
- "training_data_count": 288,
454
- "correct_predictions": 17,
455
- "actual_wins": 12,
456
- "predicted_wins": 11
457
- },
458
- "Non-Profit & Government|Conversion": {
459
- "accuracy": 0.707,
460
- "count": 92,
461
- "training_data_count": 828,
462
- "correct_predictions": 65,
463
- "actual_wins": 29,
464
- "predicted_wins": 22
465
- },
466
- "Non-Profit & Government|Internal & Navigation": {
467
- "accuracy": 0.64,
468
- "count": 50,
469
- "training_data_count": 450,
470
- "correct_predictions": 32,
471
- "actual_wins": 23,
472
- "predicted_wins": 21
473
- },
474
- "Non-Profit & Government|Post-Conversion & Other": {
475
- "accuracy": 0.909,
476
- "count": 11,
477
- "training_data_count": 99,
478
- "correct_predictions": 10,
479
- "actual_wins": 4,
480
- "predicted_wins": 3
481
- },
482
- "Other|Awareness & Discovery": {
483
- "accuracy": 0.755,
484
- "count": 53,
485
- "training_data_count": 477,
486
- "correct_predictions": 40,
487
- "actual_wins": 24,
488
- "predicted_wins": 21
489
- },
490
- "Other|Consideration & Evaluation": {
491
- "accuracy": 0.385,
492
- "count": 26,
493
- "training_data_count": 234,
494
- "correct_predictions": 10,
495
- "actual_wins": 13,
496
- "predicted_wins": 9
497
- },
498
- "Other|Conversion": {
499
- "accuracy": 0.75,
500
- "count": 4,
501
- "training_data_count": 36,
502
- "correct_predictions": 3,
503
- "actual_wins": 2,
504
- "predicted_wins": 3
505
- },
506
- "Other|Internal & Navigation": {
507
- "accuracy": 0.4,
508
- "count": 10,
509
- "training_data_count": 90,
510
- "correct_predictions": 4,
511
- "actual_wins": 5,
512
- "predicted_wins": 1
513
- },
514
- "Other|Post-Conversion & Other": {
515
- "accuracy": 1.0,
516
- "count": 1,
517
- "training_data_count": 9,
518
- "correct_predictions": 1,
519
- "actual_wins": 1,
520
- "predicted_wins": 1
521
- },
522
- "Retail & E-commerce|Awareness & Discovery": {
523
- "accuracy": 0.645,
524
- "count": 619,
525
- "training_data_count": 5571,
526
- "correct_predictions": 399,
527
- "actual_wins": 309,
528
- "predicted_wins": 239
529
- },
530
- "Retail & E-commerce|Consideration & Evaluation": {
531
- "accuracy": 0.638,
532
- "count": 718,
533
- "training_data_count": 6462,
534
- "correct_predictions": 458,
535
- "actual_wins": 345,
536
- "predicted_wins": 309
537
- },
538
- "Retail & E-commerce|Conversion": {
539
- "accuracy": 0.661,
540
- "count": 112,
541
- "training_data_count": 1008,
542
- "correct_predictions": 74,
543
- "actual_wins": 58,
544
- "predicted_wins": 60
545
- },
546
- "Retail & E-commerce|Internal & Navigation": {
547
- "accuracy": 0.636,
548
- "count": 154,
549
- "training_data_count": 1386,
550
- "correct_predictions": 98,
551
- "actual_wins": 67,
552
- "predicted_wins": 59
553
- },
554
- "Retail & E-commerce|Post-Conversion & Other": {
555
- "accuracy": 1.0,
556
- "count": 5,
557
- "training_data_count": 45,
558
- "correct_predictions": 5,
559
- "actual_wins": 2,
560
- "predicted_wins": 2
561
- }
562
- };
563
-
564
- // Helper function to get confidence data for Industry + Page Type combination
565
- function getConfidenceScore(industry, pageType) {
566
- const key = industry + '|' + pageType;
567
- return confidenceMapping[key] || {
568
- accuracy: 0.5, // Default fallback
569
- count: 0,
570
- training_data_count: 0,
571
- correct_predictions: 0,
572
- actual_wins: 0,
573
- predicted_wins: 0
574
- };
575
- }
576
-
577
- // Export for use in other files
578
- if (typeof module !== 'undefined' && module.exports) {
579
- module.exports = {
580
- confidenceMapping,
581
- getConfidenceScore
582
- };
583
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
frontend.html DELETED
@@ -1,576 +0,0 @@
1
- <!DOCTYPE html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="UTF-8">
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>A/B Test Predictor - Local Frontend</title>
7
- <style>
8
- * {
9
- margin: 0;
10
- padding: 0;
11
- box-sizing: border-box;
12
- }
13
-
14
- body {
15
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
16
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
17
- min-height: 100vh;
18
- padding: 20px;
19
- display: flex;
20
- justify-content: center;
21
- align-items: center;
22
- }
23
-
24
- .container {
25
- background: white;
26
- border-radius: 20px;
27
- box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
28
- max-width: 1200px;
29
- width: 100%;
30
- padding: 40px;
31
- }
32
-
33
- h1 {
34
- text-align: center;
35
- color: #333;
36
- margin-bottom: 10px;
37
- font-size: 2.5em;
38
- }
39
-
40
- .subtitle {
41
- text-align: center;
42
- color: #666;
43
- margin-bottom: 40px;
44
- font-size: 1.1em;
45
- }
46
-
47
- .upload-section {
48
- display: grid;
49
- grid-template-columns: 1fr 1fr;
50
- gap: 30px;
51
- margin-bottom: 30px;
52
- }
53
-
54
- .upload-box {
55
- border: 3px dashed #667eea;
56
- border-radius: 15px;
57
- padding: 30px;
58
- text-align: center;
59
- transition: all 0.3s ease;
60
- background: #f8f9ff;
61
- cursor: pointer;
62
- position: relative;
63
- overflow: hidden;
64
- }
65
-
66
- .upload-box:hover {
67
- border-color: #764ba2;
68
- background: #f0f1ff;
69
- transform: translateY(-5px);
70
- box-shadow: 0 10px 20px rgba(102, 126, 234, 0.2);
71
- }
72
-
73
- .upload-box.has-image {
74
- border-color: #10b981;
75
- background: #f0fdf4;
76
- }
77
-
78
- .upload-box h3 {
79
- color: #667eea;
80
- margin-bottom: 15px;
81
- font-size: 1.5em;
82
- }
83
-
84
- .upload-icon {
85
- font-size: 3em;
86
- margin-bottom: 10px;
87
- color: #667eea;
88
- }
89
-
90
- .upload-text {
91
- color: #666;
92
- font-size: 0.95em;
93
- margin-bottom: 15px;
94
- }
95
-
96
- .file-input {
97
- display: none;
98
- }
99
-
100
- .preview-image {
101
- max-width: 100%;
102
- max-height: 250px;
103
- border-radius: 10px;
104
- margin-top: 15px;
105
- display: none;
106
- box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
107
- }
108
-
109
- .preview-image.show {
110
- display: block;
111
- }
112
-
113
- .file-name {
114
- color: #10b981;
115
- font-weight: 600;
116
- margin-top: 10px;
117
- font-size: 0.9em;
118
- }
119
-
120
- .predict-button {
121
- width: 100%;
122
- padding: 18px;
123
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
124
- color: white;
125
- border: none;
126
- border-radius: 12px;
127
- font-size: 1.2em;
128
- font-weight: 600;
129
- cursor: pointer;
130
- transition: all 0.3s ease;
131
- margin-bottom: 30px;
132
- box-shadow: 0 5px 15px rgba(102, 126, 234, 0.3);
133
- }
134
-
135
- .predict-button:hover:not(:disabled) {
136
- transform: translateY(-2px);
137
- box-shadow: 0 8px 20px rgba(102, 126, 234, 0.4);
138
- }
139
-
140
- .predict-button:disabled {
141
- background: #ccc;
142
- cursor: not-allowed;
143
- box-shadow: none;
144
- }
145
-
146
- .loading {
147
- display: none;
148
- text-align: center;
149
- margin: 30px 0;
150
- }
151
-
152
- .loading.show {
153
- display: block;
154
- }
155
-
156
- .spinner {
157
- border: 4px solid #f3f3f3;
158
- border-top: 4px solid #667eea;
159
- border-radius: 50%;
160
- width: 50px;
161
- height: 50px;
162
- animation: spin 1s linear infinite;
163
- margin: 0 auto 15px;
164
- }
165
-
166
- @keyframes spin {
167
- 0% { transform: rotate(0deg); }
168
- 100% { transform: rotate(360deg); }
169
- }
170
-
171
- .loading-text {
172
- color: #667eea;
173
- font-weight: 600;
174
- margin-bottom: 10px;
175
- }
176
-
177
- .progress {
178
- color: #666;
179
- font-size: 0.9em;
180
- }
181
-
182
- .results {
183
- display: none;
184
- background: #f8f9ff;
185
- border-radius: 15px;
186
- padding: 30px;
187
- margin-top: 30px;
188
- }
189
-
190
- .results.show {
191
- display: block;
192
- animation: fadeIn 0.5s ease;
193
- }
194
-
195
- @keyframes fadeIn {
196
- from { opacity: 0; transform: translateY(20px); }
197
- to { opacity: 1; transform: translateY(0); }
198
- }
199
-
200
- .results h2 {
201
- color: #333;
202
- margin-bottom: 20px;
203
- font-size: 1.8em;
204
- }
205
-
206
- .json-display {
207
- background: #1e293b;
208
- color: #e2e8f0;
209
- padding: 20px;
210
- border-radius: 10px;
211
- font-family: 'Courier New', monospace;
212
- font-size: 0.9em;
213
- overflow-x: auto;
214
- white-space: pre-wrap;
215
- word-wrap: break-word;
216
- line-height: 1.6;
217
- box-shadow: inset 0 2px 10px rgba(0, 0, 0, 0.2);
218
- }
219
-
220
- .error {
221
- background: #fee;
222
- border: 2px solid #fcc;
223
- border-radius: 10px;
224
- padding: 20px;
225
- margin-top: 20px;
226
- color: #c33;
227
- display: none;
228
- }
229
-
230
- .error.show {
231
- display: block;
232
- }
233
-
234
- .error h3 {
235
- margin-bottom: 10px;
236
- }
237
-
238
- @media (max-width: 768px) {
239
- .upload-section {
240
- grid-template-columns: 1fr;
241
- }
242
-
243
- h1 {
244
- font-size: 1.8em;
245
- }
246
-
247
- .container {
248
- padding: 20px;
249
- }
250
- }
251
- </style>
252
- </head>
253
- <body>
254
- <div class="container">
255
- <h1>🚀 A/B Test Predictor</h1>
256
- <p class="subtitle">Upload your control and variant images to get AI-powered predictions</p>
257
-
258
- <div class="upload-section">
259
- <div class="upload-box" id="controlBox" onclick="document.getElementById('controlInput').click()">
260
- <div class="upload-icon">📊</div>
261
- <h3>Control Image</h3>
262
- <p class="upload-text">Click to upload or drag & drop</p>
263
- <input type="file" id="controlInput" class="file-input" accept="image/*">
264
- <img id="controlPreview" class="preview-image" alt="Control preview">
265
- <div id="controlFileName" class="file-name"></div>
266
- </div>
267
-
268
- <div class="upload-box" id="variantBox" onclick="document.getElementById('variantInput').click()">
269
- <div class="upload-icon">📈</div>
270
- <h3>Variant Image</h3>
271
- <p class="upload-text">Click to upload or drag & drop</p>
272
- <input type="file" id="variantInput" class="file-input" accept="image/*">
273
- <img id="variantPreview" class="preview-image" alt="Variant preview">
274
- <div id="variantFileName" class="file-name"></div>
275
- </div>
276
- </div>
277
-
278
- <button id="predictButton" class="predict-button" disabled>
279
- 🤖 Analyze & Predict Winner
280
- </button>
281
-
282
- <div id="loading" class="loading">
283
- <div class="spinner"></div>
284
- <p class="loading-text">🧠 AI is analyzing your images...</p>
285
- <p class="progress" id="progressText">Uploading files...</p>
286
- </div>
287
-
288
- <div id="error" class="error">
289
- <h3>❌ Error</h3>
290
- <p id="errorMessage"></p>
291
- </div>
292
-
293
- <div id="results" class="results">
294
- <h2>📊 Prediction Results</h2>
295
- <div id="jsonDisplay" class="json-display"></div>
296
- </div>
297
- </div>
298
-
299
- <script>
300
- const API_URL = 'https://nitish-spz-abtestpredictorv2.hf.space';
301
-
302
- let controlFile = null;
303
- let variantFile = null;
304
-
305
- // Setup file input handlers
306
- const controlInput = document.getElementById('controlInput');
307
- const variantInput = document.getElementById('variantInput');
308
- const controlBox = document.getElementById('controlBox');
309
- const variantBox = document.getElementById('variantBox');
310
- const controlPreview = document.getElementById('controlPreview');
311
- const variantPreview = document.getElementById('variantPreview');
312
- const controlFileName = document.getElementById('controlFileName');
313
- const variantFileName = document.getElementById('variantFileName');
314
- const predictButton = document.getElementById('predictButton');
315
- const progressText = document.getElementById('progressText');
316
-
317
- // Handle file selection
318
- controlInput.addEventListener('change', (e) => handleFileSelect(e, 'control'));
319
- variantInput.addEventListener('change', (e) => handleFileSelect(e, 'variant'));
320
-
321
- // Drag and drop handlers
322
- [controlBox, variantBox].forEach(box => {
323
- box.addEventListener('dragover', (e) => {
324
- e.preventDefault();
325
- box.style.borderColor = '#764ba2';
326
- });
327
-
328
- box.addEventListener('dragleave', (e) => {
329
- e.preventDefault();
330
- box.style.borderColor = '#667eea';
331
- });
332
-
333
- box.addEventListener('drop', (e) => {
334
- e.preventDefault();
335
- e.stopPropagation();
336
- box.style.borderColor = '#667eea';
337
-
338
- const type = box.id === 'controlBox' ? 'control' : 'variant';
339
- const files = e.dataTransfer.files;
340
-
341
- if (files.length > 0 && files[0].type.startsWith('image/')) {
342
- const input = type === 'control' ? controlInput : variantInput;
343
- input.files = files;
344
- handleFileSelect({ target: input }, type);
345
- }
346
- });
347
- });
348
-
349
- function handleFileSelect(event, type) {
350
- const file = event.target.files[0];
351
- if (!file) return;
352
-
353
- if (type === 'control') {
354
- controlFile = file;
355
- displayPreview(file, controlPreview, controlFileName, controlBox);
356
- } else {
357
- variantFile = file;
358
- displayPreview(file, variantPreview, variantFileName, variantBox);
359
- }
360
-
361
- // Enable predict button if both files are selected
362
- if (controlFile && variantFile) {
363
- predictButton.disabled = false;
364
- }
365
- }
366
-
367
- function displayPreview(file, previewImg, fileNameDiv, box) {
368
- const reader = new FileReader();
369
- reader.onload = (e) => {
370
- previewImg.src = e.target.result;
371
- previewImg.classList.add('show');
372
- fileNameDiv.textContent = `✓ ${file.name}`;
373
- box.classList.add('has-image');
374
- };
375
- reader.readAsDataURL(file);
376
- }
377
-
378
- // Handle prediction
379
- predictButton.addEventListener('click', async () => {
380
- if (!controlFile || !variantFile) {
381
- showError('Please upload both control and variant images');
382
- return;
383
- }
384
-
385
- // Hide previous results/errors
386
- document.getElementById('results').classList.remove('show');
387
- document.getElementById('error').classList.remove('show');
388
-
389
- // Show loading
390
- document.getElementById('loading').classList.add('show');
391
- predictButton.disabled = true;
392
-
393
- try {
394
- console.log('📤 Step 1: Uploading files to Gradio...');
395
- progressText.textContent = 'Uploading files...';
396
-
397
- // Upload files to Gradio
398
- const controlPath = await uploadFileToGradio(controlFile);
399
- const variantPath = await uploadFileToGradio(variantFile);
400
-
401
- console.log(`✅ Files uploaded: ${controlPath}, ${variantPath}`);
402
-
403
- // Create FileData objects
404
- const controlFileData = {
405
- path: controlPath,
406
- url: `${API_URL}/file=${controlPath}`,
407
- orig_name: controlFile.name,
408
- size: controlFile.size,
409
- mime_type: controlFile.type,
410
- meta: { _type: "gradio.FileData" }
411
- };
412
-
413
- const variantFileData = {
414
- path: variantPath,
415
- url: `${API_URL}/file=${variantPath}`,
416
- orig_name: variantFile.name,
417
- size: variantFile.size,
418
- mime_type: variantFile.type,
419
- meta: { _type: "gradio.FileData" }
420
- };
421
-
422
- console.log('📤 Step 2: Sending prediction request...');
423
- progressText.textContent = 'AI is analyzing images (20-40s)...';
424
-
425
- // Make API call
426
- const response = await fetch(`${API_URL}/call/predict_with_auto_categorization`, {
427
- method: 'POST',
428
- headers: { 'Content-Type': 'application/json' },
429
- body: JSON.stringify({
430
- data: [controlFileData, variantFileData]
431
- })
432
- });
433
-
434
- if (!response.ok) {
435
- throw new Error(`API error: ${response.status}`);
436
- }
437
-
438
- const result = await response.json();
439
- console.log('✅ Request queued:', result);
440
-
441
- if (!result.event_id) {
442
- throw new Error('No event_id received');
443
- }
444
-
445
- // Poll for results
446
- progressText.textContent = 'Waiting for AI prediction...';
447
- const finalResult = await pollForResult(result.event_id);
448
-
449
- console.log('✅ Final result:', finalResult);
450
- displayResults(finalResult);
451
-
452
- } catch (error) {
453
- console.error('❌ Error:', error);
454
- showError(`Failed to get prediction: ${error.message}`);
455
- } finally {
456
- document.getElementById('loading').classList.remove('show');
457
- predictButton.disabled = false;
458
- }
459
- });
460
-
461
- async function uploadFileToGradio(file) {
462
- const formData = new FormData();
463
- formData.append('files', file);
464
-
465
- const response = await fetch(`${API_URL}/upload`, {
466
- method: 'POST',
467
- body: formData
468
- });
469
-
470
- if (!response.ok) {
471
- throw new Error(`Upload failed: ${response.status}`);
472
- }
473
-
474
- const result = await response.json();
475
-
476
- if (Array.isArray(result) && result.length > 0) {
477
- return result[0];
478
- }
479
- throw new Error('Upload failed - no path returned');
480
- }
481
-
482
- async function pollForResult(eventId) {
483
- const maxAttempts = 50; // 50 attempts x 2 seconds = 100 seconds max
484
- const pollInterval = 2000;
485
-
486
- for (let attempt = 0; attempt < maxAttempts; attempt++) {
487
- progressText.textContent = `Polling for results (${attempt + 1}/${maxAttempts})...`;
488
- console.log(`📊 Poll attempt ${attempt + 1}/${maxAttempts}`);
489
-
490
- try {
491
- const response = await fetch(`${API_URL}/call/predict_with_auto_categorization/${eventId}`);
492
-
493
- if (!response.ok) {
494
- await sleep(pollInterval);
495
- continue;
496
- }
497
-
498
- const text = await response.text();
499
-
500
- if (!text || text.trim() === '') {
501
- await sleep(pollInterval);
502
- continue;
503
- }
504
-
505
- // Parse SSE format
506
- const lines = text.split('\n');
507
- for (let i = 0; i < lines.length; i++) {
508
- if (lines[i].trim() === 'event: complete') {
509
- // Found complete event, get the data
510
- for (let j = i + 1; j < lines.length; j++) {
511
- const dataLine = lines[j].trim();
512
- if (dataLine.startsWith('data: ')) {
513
- const jsonData = dataLine.substring(6);
514
- const result = JSON.parse(jsonData);
515
- return result;
516
- }
517
- }
518
- }
519
- }
520
-
521
- // Check for any data line that looks like a result
522
- for (const line of lines) {
523
- if (line.startsWith('data: ')) {
524
- try {
525
- const jsonData = line.substring(6);
526
- const parsed = JSON.parse(jsonData);
527
-
528
- if (parsed && typeof parsed === 'object' && !parsed.progress) {
529
- // Looks like a result
530
- if (parsed['🎯 Prediction Results'] || Array.isArray(parsed)) {
531
- return parsed;
532
- }
533
- }
534
- } catch (e) {
535
- // Not valid JSON, continue
536
- }
537
- }
538
- }
539
-
540
- } catch (error) {
541
- console.error('Poll error:', error);
542
- }
543
-
544
- await sleep(pollInterval);
545
- }
546
-
547
- throw new Error('Polling timeout - no result after 100 seconds');
548
- }
549
-
550
- function sleep(ms) {
551
- return new Promise(resolve => setTimeout(resolve, ms));
552
- }
553
-
554
- function displayResults(data) {
555
- const resultsDiv = document.getElementById('results');
556
- const jsonDisplay = document.getElementById('jsonDisplay');
557
-
558
- // Pretty print JSON
559
- jsonDisplay.textContent = JSON.stringify(data, null, 2);
560
-
561
- resultsDiv.classList.add('show');
562
- }
563
-
564
- function showError(message) {
565
- const errorDiv = document.getElementById('error');
566
- const errorMessage = document.getElementById('errorMessage');
567
-
568
- errorMessage.textContent = message;
569
- errorDiv.classList.add('show');
570
- }
571
-
572
- console.log('✅ Frontend loaded and ready!');
573
- </script>
574
- </body>
575
- </html>
576
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
index_v2.html DELETED
@@ -1,437 +0,0 @@
1
- <!DOCTYPE html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="UTF-8">
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>A/B Test Predictor - Simple Version</title>
7
- <style>
8
- * {
9
- margin: 0;
10
- padding: 0;
11
- box-sizing: border-box;
12
- }
13
-
14
- body {
15
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
16
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
17
- min-height: 100vh;
18
- padding: 20px;
19
- display: flex;
20
- justify-content: center;
21
- align-items: center;
22
- }
23
-
24
- .container {
25
- background: white;
26
- border-radius: 20px;
27
- box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
28
- max-width: 1200px;
29
- width: 100%;
30
- padding: 40px;
31
- }
32
-
33
- h1 {
34
- text-align: center;
35
- color: #333;
36
- margin-bottom: 10px;
37
- font-size: 2.5em;
38
- }
39
-
40
- .subtitle {
41
- text-align: center;
42
- color: #666;
43
- margin-bottom: 40px;
44
- font-size: 1.1em;
45
- }
46
-
47
- .upload-section {
48
- display: grid;
49
- grid-template-columns: 1fr 1fr;
50
- gap: 30px;
51
- margin-bottom: 30px;
52
- }
53
-
54
- .upload-box {
55
- border: 3px dashed #667eea;
56
- border-radius: 15px;
57
- padding: 30px;
58
- text-align: center;
59
- transition: all 0.3s ease;
60
- background: #f8f9ff;
61
- cursor: pointer;
62
- position: relative;
63
- overflow: hidden;
64
- }
65
-
66
- .upload-box:hover {
67
- border-color: #764ba2;
68
- background: #f0f1ff;
69
- transform: translateY(-5px);
70
- box-shadow: 0 10px 20px rgba(102, 126, 234, 0.2);
71
- }
72
-
73
- .upload-box.has-image {
74
- border-color: #10b981;
75
- background: #f0fdf4;
76
- }
77
-
78
- .upload-box h3 {
79
- color: #667eea;
80
- margin-bottom: 15px;
81
- font-size: 1.5em;
82
- }
83
-
84
- .upload-icon {
85
- font-size: 3em;
86
- margin-bottom: 10px;
87
- color: #667eea;
88
- }
89
-
90
- .upload-text {
91
- color: #666;
92
- font-size: 0.95em;
93
- margin-bottom: 15px;
94
- }
95
-
96
- .file-input {
97
- display: none;
98
- }
99
-
100
- .preview-image {
101
- max-width: 100%;
102
- max-height: 250px;
103
- border-radius: 10px;
104
- margin-top: 15px;
105
- display: none;
106
- box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
107
- }
108
-
109
- .preview-image.show {
110
- display: block;
111
- }
112
-
113
- .file-name {
114
- color: #10b981;
115
- font-weight: 600;
116
- margin-top: 10px;
117
- font-size: 0.9em;
118
- }
119
-
120
- .predict-button {
121
- width: 100%;
122
- padding: 18px;
123
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
124
- color: white;
125
- border: none;
126
- border-radius: 12px;
127
- font-size: 1.2em;
128
- font-weight: 600;
129
- cursor: pointer;
130
- transition: all 0.3s ease;
131
- margin-bottom: 30px;
132
- box-shadow: 0 5px 15px rgba(102, 126, 234, 0.3);
133
- }
134
-
135
- .predict-button:hover:not(:disabled) {
136
- transform: translateY(-2px);
137
- box-shadow: 0 8px 20px rgba(102, 126, 234, 0.4);
138
- }
139
-
140
- .predict-button:disabled {
141
- background: #ccc;
142
- cursor: not-allowed;
143
- box-shadow: none;
144
- }
145
-
146
- .loading {
147
- display: none;
148
- text-align: center;
149
- margin: 30px 0;
150
- }
151
-
152
- .loading.show {
153
- display: block;
154
- }
155
-
156
- .spinner {
157
- border: 4px solid #f3f3f3;
158
- border-top: 4px solid #667eea;
159
- border-radius: 50%;
160
- width: 50px;
161
- height: 50px;
162
- animation: spin 1s linear infinite;
163
- margin: 0 auto 15px;
164
- }
165
-
166
- @keyframes spin {
167
- 0% { transform: rotate(0deg); }
168
- 100% { transform: rotate(360deg); }
169
- }
170
-
171
- .loading-text {
172
- color: #667eea;
173
- font-weight: 600;
174
- }
175
-
176
- .results {
177
- display: none;
178
- background: #f8f9ff;
179
- border-radius: 15px;
180
- padding: 30px;
181
- margin-top: 30px;
182
- }
183
-
184
- .results.show {
185
- display: block;
186
- animation: fadeIn 0.5s ease;
187
- }
188
-
189
- @keyframes fadeIn {
190
- from { opacity: 0; transform: translateY(20px); }
191
- to { opacity: 1; transform: translateY(0); }
192
- }
193
-
194
- .results h2 {
195
- color: #333;
196
- margin-bottom: 20px;
197
- font-size: 1.8em;
198
- }
199
-
200
- .json-display {
201
- background: #1e293b;
202
- color: #e2e8f0;
203
- padding: 20px;
204
- border-radius: 10px;
205
- font-family: 'Courier New', monospace;
206
- font-size: 0.9em;
207
- overflow-x: auto;
208
- white-space: pre-wrap;
209
- word-wrap: break-word;
210
- line-height: 1.6;
211
- box-shadow: inset 0 2px 10px rgba(0, 0, 0, 0.2);
212
- }
213
-
214
- .error {
215
- background: #fee;
216
- border: 2px solid #fcc;
217
- border-radius: 10px;
218
- padding: 20px;
219
- margin-top: 20px;
220
- color: #c33;
221
- display: none;
222
- }
223
-
224
- .error.show {
225
- display: block;
226
- }
227
-
228
- .error h3 {
229
- margin-bottom: 10px;
230
- }
231
-
232
- @media (max-width: 768px) {
233
- .upload-section {
234
- grid-template-columns: 1fr;
235
- }
236
-
237
- h1 {
238
- font-size: 1.8em;
239
- }
240
-
241
- .container {
242
- padding: 20px;
243
- }
244
- }
245
- </style>
246
- </head>
247
- <body>
248
- <div class="container">
249
- <h1>🚀 A/B Test Predictor</h1>
250
- <p class="subtitle">Upload your control and variant images to get AI-powered predictions</p>
251
-
252
- <div class="upload-section">
253
- <div class="upload-box" id="controlBox" onclick="document.getElementById('controlInput').click()">
254
- <div class="upload-icon">📊</div>
255
- <h3>Control Image</h3>
256
- <p class="upload-text">Click to upload or drag & drop</p>
257
- <input type="file" id="controlInput" class="file-input" accept="image/*">
258
- <img id="controlPreview" class="preview-image" alt="Control preview">
259
- <div id="controlFileName" class="file-name"></div>
260
- </div>
261
-
262
- <div class="upload-box" id="variantBox" onclick="document.getElementById('variantInput').click()">
263
- <div class="upload-icon">📈</div>
264
- <h3>Variant Image</h3>
265
- <p class="upload-text">Click to upload or drag & drop</p>
266
- <input type="file" id="variantInput" class="file-input" accept="image/*">
267
- <img id="variantPreview" class="preview-image" alt="Variant preview">
268
- <div id="variantFileName" class="file-name"></div>
269
- </div>
270
- </div>
271
-
272
- <button id="predictButton" class="predict-button" disabled>
273
- 🤖 Analyze & Predict Winner
274
- </button>
275
-
276
- <div id="loading" class="loading">
277
- <div class="spinner"></div>
278
- <p class="loading-text">🧠 AI is analyzing your images... This may take 20-40 seconds</p>
279
- </div>
280
-
281
- <div id="error" class="error">
282
- <h3>❌ Error</h3>
283
- <p id="errorMessage"></p>
284
- </div>
285
-
286
- <div id="results" class="results">
287
- <h2>📊 Prediction Results</h2>
288
- <div id="jsonDisplay" class="json-display"></div>
289
- </div>
290
- </div>
291
-
292
- <!-- Import Gradio Client Library -->
293
- <script type="module">
294
- import { Client } from "https://cdn.jsdelivr.net/npm/@gradio/client@1.3.0/dist/index.min.js";
295
-
296
- let controlFile = null;
297
- let variantFile = null;
298
-
299
- // Setup file input handlers
300
- const controlInput = document.getElementById('controlInput');
301
- const variantInput = document.getElementById('variantInput');
302
- const controlBox = document.getElementById('controlBox');
303
- const variantBox = document.getElementById('variantBox');
304
- const controlPreview = document.getElementById('controlPreview');
305
- const variantPreview = document.getElementById('variantPreview');
306
- const controlFileName = document.getElementById('controlFileName');
307
- const variantFileName = document.getElementById('variantFileName');
308
- const predictButton = document.getElementById('predictButton');
309
-
310
- // Handle file selection
311
- controlInput.addEventListener('change', (e) => handleFileSelect(e, 'control'));
312
- variantInput.addEventListener('change', (e) => handleFileSelect(e, 'variant'));
313
-
314
- // Drag and drop handlers
315
- [controlBox, variantBox].forEach(box => {
316
- box.addEventListener('dragover', (e) => {
317
- e.preventDefault();
318
- box.style.borderColor = '#764ba2';
319
- });
320
-
321
- box.addEventListener('dragleave', (e) => {
322
- e.preventDefault();
323
- box.style.borderColor = '#667eea';
324
- });
325
-
326
- box.addEventListener('drop', (e) => {
327
- e.preventDefault();
328
- e.stopPropagation();
329
- box.style.borderColor = '#667eea';
330
-
331
- const type = box.id === 'controlBox' ? 'control' : 'variant';
332
- const files = e.dataTransfer.files;
333
-
334
- if (files.length > 0 && files[0].type.startsWith('image/')) {
335
- const input = type === 'control' ? controlInput : variantInput;
336
- input.files = files;
337
- handleFileSelect({ target: input }, type);
338
- }
339
- });
340
- });
341
-
342
- function handleFileSelect(event, type) {
343
- const file = event.target.files[0];
344
- if (!file) return;
345
-
346
- if (type === 'control') {
347
- controlFile = file;
348
- displayPreview(file, controlPreview, controlFileName, controlBox);
349
- } else {
350
- variantFile = file;
351
- displayPreview(file, variantPreview, variantFileName, variantBox);
352
- }
353
-
354
- // Enable predict button if both files are selected
355
- if (controlFile && variantFile) {
356
- predictButton.disabled = false;
357
- }
358
- }
359
-
360
- function displayPreview(file, previewImg, fileNameDiv, box) {
361
- const reader = new FileReader();
362
- reader.onload = (e) => {
363
- previewImg.src = e.target.result;
364
- previewImg.classList.add('show');
365
- fileNameDiv.textContent = `✓ ${file.name}`;
366
- box.classList.add('has-image');
367
- };
368
- reader.readAsDataURL(file);
369
- }
370
-
371
- // Handle prediction using Gradio Client
372
- predictButton.addEventListener('click', async () => {
373
- if (!controlFile || !variantFile) {
374
- showError('Please upload both control and variant images');
375
- return;
376
- }
377
-
378
- // Hide previous results/errors
379
- document.getElementById('results').classList.remove('show');
380
- document.getElementById('error').classList.remove('show');
381
-
382
- // Show loading
383
- document.getElementById('loading').classList.add('show');
384
- predictButton.disabled = true;
385
-
386
- try {
387
- console.log('🔗 Connecting to Gradio client...');
388
-
389
- // Connect to the Hugging Face Space
390
- const client = await Client.connect("nitish-spz/ABTestPredictorV2");
391
-
392
- console.log('✅ Connected! Uploading files and making prediction...');
393
-
394
- // Make prediction using the official Gradio client
395
- // It automatically handles file uploads
396
- const result = await client.predict("/predict_with_auto_categorization", {
397
- control_image: controlFile,
398
- variant_image: variantFile,
399
- });
400
-
401
- console.log('✅ Result received:', result);
402
-
403
- // Display results
404
- displayResults(result.data);
405
-
406
- } catch (error) {
407
- console.error('❌ Error:', error);
408
- showError(`Failed to get prediction: ${error.message}`);
409
- } finally {
410
- document.getElementById('loading').classList.remove('show');
411
- predictButton.disabled = false;
412
- }
413
- });
414
-
415
- function displayResults(data) {
416
- const resultsDiv = document.getElementById('results');
417
- const jsonDisplay = document.getElementById('jsonDisplay');
418
-
419
- // Pretty print JSON
420
- jsonDisplay.textContent = JSON.stringify(data, null, 2);
421
-
422
- resultsDiv.classList.add('show');
423
- }
424
-
425
- function showError(message) {
426
- const errorDiv = document.getElementById('error');
427
- const errorMessage = document.getElementById('errorMessage');
428
-
429
- errorMessage.textContent = message;
430
- errorDiv.classList.add('show');
431
- }
432
-
433
- console.log('✅ Gradio Client loaded and ready!');
434
- </script>
435
- </body>
436
- </html>
437
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
metadata.js DELETED
@@ -1,604 +0,0 @@
1
- /**
2
- * This file contains the metadata used for filtering in the search application.
3
- * It is auto-generated by a Python script. Do not edit this file manually.
4
- */
5
-
6
- const pattern = [
7
- "Access Wall",
8
- "Accordion",
9
- "Add / Change Delay",
10
- "Add / Change Emphasis",
11
- "Add Background Image",
12
- "Add CTA",
13
- "Add Details",
14
- "Amazon A/B Testing",
15
- "Anchoring",
16
- "Animated CTA",
17
- "Animation",
18
- "Annotate UI",
19
- "Attention Director",
20
- "Audio Recording",
21
- "Autofill",
22
- "Autoplay Video",
23
- "Autoplay Video Without Sound",
24
- "Baseline - Other",
25
- "Baseline Hero",
26
- "Before and After",
27
- "Benefit Button",
28
- "Bestseller / Featured Products",
29
- "Big Claim Headline",
30
- "Bigger Product Images",
31
- "Blog / Content Summary",
32
- "Blurred Content",
33
- "Bold-face Copy",
34
- "Bottom Banner to Top Banner",
35
- "Bottom Corner Pop-up",
36
- "Breadcrumbs",
37
- "Bullet Points",
38
- "Bullet Points - Change Inclusions",
39
- "Bullet Points - Emphasize Inclusions",
40
- "Bullet Points - Inclusions",
41
- "Bulletize Copy",
42
- "Button",
43
- "Button Positioning",
44
- "Button to Radio Button",
45
- "Buttonized CTA",
46
- "Buttons - Image",
47
- "CTA Activation",
48
- "CTA Color Change",
49
- "CTA Copy Change",
50
- "CTA Positioning",
51
- "CTA Section",
52
- "CTA Size",
53
- "Calculator",
54
- "Calendar",
55
- "Calendar Flexibility Button",
56
- "Cart Contents Section",
57
- "Case Studies",
58
- "Change / Add Link to Product Pages",
59
- "Change / Add Product/Plan Name",
60
- "Change Advertisements / Ads",
61
- "Change Attention Director",
62
- "Change Background Image",
63
- "Change CTA Link",
64
- "Change CTA Shape",
65
- "Change CTA to Hyperlink",
66
- "Change Checkbox/Tickbox to Buttons/Dropdown",
67
- "Change Copy Order",
68
- "Change Copy on Image / Video Overlay",
69
- "Change Default Currency",
70
- "Change Default Filter/Sort View",
71
- "Change Displayed / Listed Product / Category",
72
- "Change Donation Amount",
73
- "Change Error Message",
74
- "Change FAQs",
75
- "Change Features",
76
- "Change Field Type",
77
- "Change Font",
78
- "Change Font Color",
79
- "Change Form Field Label",
80
- "Change Form Fields",
81
- "Change GIF / Video / Animation",
82
- "Change Hero Image",
83
- "Change How It Works",
84
- "Change Hyperlink Copy",
85
- "Change Icon",
86
- "Change Icon to Copy",
87
- "Change Image",
88
- "Change Image / Video Size",
89
- "Change Image Order",
90
- "Change Inclusions",
91
- "Change Integrations",
92
- "Change Link to Internal Pages",
93
- "Change Listing Cards Layout / Design",
94
- "Change Logo",
95
- "Change Logos in Social Proof",
96
- "Change Matrix Layout / Design",
97
- "Change Menu",
98
- "Change Modal",
99
- "Change Payment Options",
100
- "Change Price",
101
- "Change Pricing Card Layout / Design",
102
- "Change Product Image",
103
- "Change Progress Timeline",
104
- "Change Promotion",
105
- "Change Qualifying Questions",
106
- "Change Real People",
107
- "Change Recommended Tags",
108
- "Change Resources / Articles",
109
- "Change Reviews Summary",
110
- "Change Section",
111
- "Change Section Order",
112
- "Change Selection Buttons to Field",
113
- "Change Statistics",
114
- "Change Subscription / Trial / Promotion Duration",
115
- "Change Tag Design/Copy",
116
- "Change Testimonial",
117
- "Change Trust Badges",
118
- "Change USPs*",
119
- "Change Upsell Product",
120
- "Change Video Thumbnail Image",
121
- "Chatbot",
122
- "Checkbox / Tickbox",
123
- "Clearbit Form",
124
- "Clickable Icon / Image",
125
- "Clickable Section",
126
- "Color Change",
127
- "Company Info",
128
- "Comparison Matrix",
129
- "Competitor Pricing",
130
- "Concise Headline",
131
- "Condensed List",
132
- "Contact Number",
133
- "Contact Us Section",
134
- "Content to Tabs",
135
- "Copy - Add",
136
- "Copy Center-Aligned",
137
- "Copy Change",
138
- "Copy Positioning",
139
- "Countdown Timer",
140
- "Cross Sell",
141
- "Crossed-out Features",
142
- "Currency Font Size",
143
- "Currency to Percentage Savings",
144
- "Database Number",
145
- "Decrease Number of Slides",
146
- "Demo/Trial Duration",
147
- "Disclaimer",
148
- "Double Column Form",
149
- "Download Method",
150
- "Dropdown",
151
- "Dual CTA",
152
- "Dummy Category Name",
153
- "Dummy Form Field",
154
- "Dynamic/Animated Headline",
155
- "Easing Product/Plan Selection",
156
- "Email Plus CTA",
157
- "Email Plus CTA in Nav",
158
- "Email Subscription",
159
- "Emphasize / Highlight Urgency",
160
- "Emphasize Buttons",
161
- "Emphasize CTA",
162
- "Emphasize Cross Sell",
163
- "Emphasize Form",
164
- "Emphasize Guarantee",
165
- "Emphasize Inclusions",
166
- "Emphasize Interface Image",
167
- "Emphasize Options",
168
- "Emphasize Payment Options",
169
- "Emphasize Pricing / Price",
170
- "Emphasize Search Bar",
171
- "Emphasize Social Proof",
172
- "Emphasize Testimonials",
173
- "Exit Modal",
174
- "Explainer Microcopy",
175
- "External Ad",
176
- "FAQs",
177
- "Fear of Missing Out",
178
- "Features",
179
- "Features - Additional",
180
- "Features - Bento-Style",
181
- "Features - Z-Style",
182
- "Features Accordion",
183
- "Features Grid",
184
- "Filters",
185
- "Filters - Change Options Order",
186
- "Filters - Emphasize",
187
- "Filters - Options",
188
- "Filters - Redesign",
189
- "Filters - Show More Options",
190
- "Flourishes / Small Design Details",
191
- "Font Size",
192
- "Footer Navigation",
193
- "Form - Add",
194
- "Form Activation",
195
- "Form Center-Aligned",
196
- "Form Color Change",
197
- "Form Field Border Change",
198
- "Form Field Label",
199
- "Form Help",
200
- "Form Over Partner Logos",
201
- "Form Over Pricing",
202
- "Form Over Resource",
203
- "Form Over UI",
204
- "Form Over UI - Animated",
205
- "Form Over UI - Other",
206
- "Form Over UI With Copy",
207
- "Form Over UI With Integrations",
208
- "Form Over UI With Reviews Summary",
209
- "Form Over UI With Social Proof",
210
- "Form Over UI With Testimonial",
211
- "Form Over UI in Hero",
212
- "Form Positioning",
213
- "Form Redesign",
214
- "Form in Modal",
215
- "Form on the Left",
216
- "Free Shipping",
217
- "Free Shipping - Emphasize",
218
- "Full-width Modal",
219
- "G2/Forrester/Gartner Alignment Chart",
220
- "GDPR Cookie Modal",
221
- "GDPR Cookie Modal - Change",
222
- "Gender Segmentation",
223
- "Geo-specific Personalization",
224
- "Guarantee",
225
- "Hamburger Button",
226
- "Headline",
227
- "Headline Center-Aligned",
228
- "Headline Copy Change",
229
- "Hero Bar Navigation",
230
- "Hero Center-Aligned",
231
- "Hero Layout",
232
- "Hero Redesign",
233
- "Hero Size",
234
- "Hero Tiles",
235
- "Hide Price in Form",
236
- "Highlight Words",
237
- "How It Works",
238
- "How It Works - Emphasize",
239
- "Hyperlink",
240
- "Icon Label",
241
- "Icons",
242
- "Image",
243
- "Image/Video to Background",
244
- "Impact Chart",
245
- "Inclusions",
246
- "Inclusions - Additional",
247
- "Increase Number of Related Articles/Case Studies",
248
- "Increase Trust",
249
- "Industry Types",
250
- "Infinite Scroll",
251
- "Inline Form Field Copy",
252
- "Inline Form Field Copy Change",
253
- "Inline Link Nudge",
254
- "Inline Validation",
255
- "Insertion",
256
- "Insertion Redesign",
257
- "Instant Copy",
258
- "Integrations",
259
- "Interactive Hero",
260
- "Interactive Modal",
261
- "Interactive Product Section",
262
- "Interactive Tour",
263
- "Interest Rates",
264
- "Interface in Background",
265
- "Left Form Over UI",
266
- "Link to External Sites",
267
- "Link to Internal Page",
268
- "Link to Product Listing",
269
- "Live Chat",
270
- "Live Trends",
271
- "Local Languages",
272
- "Localization Option",
273
- "Locked Hero",
274
- "Login Method",
275
- "Login to Signup",
276
- "Logo",
277
- "Logo Positioning",
278
- "Logo Size",
279
- "Long Page",
280
- "Longform Baseline",
281
- "Map",
282
- "Media Mentions Social Proof",
283
- "Meet the People",
284
- "Menu",
285
- "Mini Case Studies",
286
- "Mini Donation",
287
- "Mini Reviews",
288
- "Mini Triage in Nav",
289
- "Minimize Price Font Size",
290
- "Mixed Media",
291
- "Modal",
292
- "Modify Breadcrumbs",
293
- "Modify Search Bar",
294
- "More Detailed Reviews",
295
- "More Expensive First",
296
- "More Product Info",
297
- "Move Bestsellers/Featured Products Up",
298
- "Move Image Up",
299
- "Multi-step Forms",
300
- "Multiple Hero Images",
301
- "Natural Language Forms",
302
- "Navigation Bar",
303
- "Navigation Bar Redesign",
304
- "New Edition",
305
- "Number of Purchases",
306
- "Number of Slots / Stocks Progress Bar",
307
- "Online / Active Now Status",
308
- "Open in a New Tab",
309
- "Optimized Copy",
310
- "Optimized Copy - Form",
311
- "Optimized Copy - Hero",
312
- "Other",
313
- "Out of Stock Products",
314
- "Page Layout",
315
- "Pain Point",
316
- "Partner Logos",
317
- "Payment First",
318
- "Payment Options",
319
- "People Like Me With Problems Like Mine",
320
- "Personal Headline",
321
- "Personalized OS",
322
- "Postcode / Domain / Other Plus CTA",
323
- "Pre-expanded Chatbot",
324
- "Pre-expanded Dropdown",
325
- "Pre-expanded Tooltip",
326
- "Pre-expanded/Condensed FAQs",
327
- "Pre-filled Text Box",
328
- "Pre-selected Options",
329
- "Price Per Month",
330
- "Price Per Unit",
331
- "Pricing Cards",
332
- "Pricing Cards & Features Combined",
333
- "Pricing Cards - Change / Add Emphasized Plan",
334
- "Pricing Cards - Change Inclusions",
335
- "Pricing Cards - Emphasize Inclusions",
336
- "Pricing Cards - Inclusions",
337
- "Pricing Defaulted to Annual",
338
- "Pricing Defaulted to Subscription",
339
- "Pricing Toggle",
340
- "Product Comparison",
341
- "Product Customization",
342
- "Product Image",
343
- "Product Organization",
344
- "Product Subscription",
345
- "Product/Bundle",
346
- "Progress Bar",
347
- "Progress Timeline",
348
- "Promotion",
349
- "Promotion - Discount Offer Banner",
350
- "Promotion - Emphasize",
351
- "Promotions - Trial Offer",
352
- "Pros and Cons",
353
- "Prozac",
354
- "Prozac - Others",
355
- "Prozac Copy Change",
356
- "Purchase History",
357
- "Push Copy Up",
358
- "Push Form Up",
359
- "Push Form Up - Hero",
360
- "Push Guarantee Up",
361
- "Push Pricing Up",
362
- "QR Code",
363
- "Qualifying Questions",
364
- "Quantitative Headline",
365
- "Quantity Selector",
366
- "Quote Slider",
367
- "Radical Redesign",
368
- "Radical Redesign - Basecamp Pricing",
369
- "Real People",
370
- "Rearranged Form Content",
371
- "Recently Viewed / Purchased",
372
- "Recommended (Non-Product)",
373
- "Recommended Tag",
374
- "Redesign Footer",
375
- "Redesign Modal",
376
- "Redesign Review Ribbon",
377
- "Redesign Section",
378
- "Redesign Triage",
379
- "Reduce Choices",
380
- "Reduce Distractors",
381
- "Reduce Form Length / Remove Form Fields",
382
- "Reduce Lower Interest Content",
383
- "Reduce Steps",
384
- "Reduced Spacing",
385
- "Referral Section",
386
- "Related Articles",
387
- "Related Products",
388
- "Remove Advertisements / Ads",
389
- "Remove Detail",
390
- "Remove Escapes",
391
- "Remove Hero",
392
- "Remove Overages",
393
- "Remove Section",
394
- "Remove Slider",
395
- "Remove Terms & Conditions",
396
- "Remove Top Banner",
397
- "Remove Video",
398
- "Replace Animation With Video",
399
- "Replace Icon With Image",
400
- "Replace Image With Animation",
401
- "Replace Image With Interface",
402
- "Replace Image with Video",
403
- "Resource Section",
404
- "Returning Users",
405
- "Review Ribbon",
406
- "Reviewer Name",
407
- "Reviews Section",
408
- "Reviews Summary",
409
- "Reviews Summary Positioning",
410
- "Rewording",
411
- "Savings",
412
- "Savings - Emphasize",
413
- "Scarcity",
414
- "Scroll Down Animation",
415
- "Search Bar / Button",
416
- "Search Section",
417
- "Search to Dropdown",
418
- "Section Banner",
419
- "Shipping Information",
420
- "Shorten FAQs",
421
- "Shorten Product Comparison",
422
- "Shortened Forms",
423
- "Shortform Baseline",
424
- "Show / Change to Required / Mandatory Field",
425
- "Show Annual Price",
426
- "Show Daily Price",
427
- "Show Interface",
428
- "Show Price",
429
- "Show Starting Price",
430
- "Show Weekly Price",
431
- "Side Navigation",
432
- "Signup / Registration Wall",
433
- "Signup to Demo",
434
- "Simplify Design",
435
- "Single Annual-Monthly Toggle in Pricing",
436
- "Single CTA in Pricing",
437
- "Single Select to Multiple Select Option / Choice",
438
- "Single Sign-On (SSO)",
439
- "Slider Positioning",
440
- "Slider Thumbnail",
441
- "Sliding Form",
442
- "Slight Icon Change",
443
- "Social Count",
444
- "Social Media Links",
445
- "Social Proof",
446
- "Social Proof Copy Change",
447
- "Social Proof in Hero",
448
- "Specific Benefit*",
449
- "Specific Contact",
450
- "Specific Guarantee",
451
- "Specific Headline",
452
- "Split Screen",
453
- "Split Screen with Sticky Form",
454
- "Statistics",
455
- "Statistics - Emphasize",
456
- "Step Numbers",
457
- "Sticky - Other",
458
- "Sticky Banner",
459
- "Sticky CTA",
460
- "Sticky Footer",
461
- "Sticky Form",
462
- "Sticky Navigation Bar",
463
- "Sticky Positioning",
464
- "Sticky Redesign",
465
- "Sticky Reviews",
466
- "Sticky Search Bar",
467
- "Sticky Side Navigation",
468
- "Sticky Subnav",
469
- "Store/Service Locations",
470
- "Stories-style Video",
471
- "Strikethrough Pricing",
472
- "Subhead",
473
- "Subhead Copy Change",
474
- "Subscription/Plan Time/Duration",
475
- "Superhead",
476
- "Superhead Copy Change",
477
- "Suppress Promo",
478
- "Suppressed Content",
479
- "Suppressed Copy",
480
- "Table of Contents",
481
- "Tags",
482
- "Tease Pricing",
483
- "Tease Savings",
484
- "Tease Video / Content",
485
- "Terms of Service",
486
- "Testimonial Positioning",
487
- "Testimonials",
488
- "Testimonials With Stars",
489
- "Text Field/Dropdown to Button",
490
- "Text Field/Dropdown to Slider",
491
- "Text on the Left",
492
- "The Science / Method Behind",
493
- "Time to Completion*",
494
- "Time to First Ah-ha / Completion",
495
- "Tooltip",
496
- "Tooltip - Change",
497
- "Tooltip Positioning",
498
- "Top Banner Color Change",
499
- "Top Banner Copy Change",
500
- "Triage",
501
- "Trust Badges",
502
- "Trust Badges - Emphasize",
503
- "Trust Badges in Hero",
504
- "USPs - Logos / Icons / Images",
505
- "Unique Selling Points (USPs)*",
506
- "Upsell Membership",
507
- "Upsell to Demo/Trial",
508
- "Urgency",
509
- "Use Case",
510
- "Video in Hero",
511
- "Wall of Testimonials",
512
- "Warranty",
513
- "Widen Webpage",
514
- ];
515
-
516
- const industries = [
517
- "Automotive & Transportation",
518
- "B2B Services",
519
- "B2B Software & Tech",
520
- "Consumer Services",
521
- "Consumer Software & Apps",
522
- "Education",
523
- "Finance, Insurance & Real Estate",
524
- "Food, Hospitality & Travel",
525
- "Health & Wellness",
526
- "Industrial & Manufacturing",
527
- "Media & Entertainment",
528
- "Non-Profit & Government",
529
- "Other",
530
- "Retail & E-commerce"
531
- ];
532
-
533
- const customerTypes = [
534
- "B2B",
535
- "B2C",
536
- "Both",
537
- "Other*"
538
- ];
539
-
540
- const pageTypes = [
541
- "Awareness & Discovery",
542
- "Consideration & Evaluation",
543
- "Conversion",
544
- "Internal & Navigation",
545
- "Post-Conversion & Other"
546
- ];
547
-
548
- const results = [
549
- "Loser",
550
- "Neutral",
551
- "Winner"
552
- ];
553
-
554
- const businessModels = [
555
- "E-Commerce",
556
- "Lead Generation",
557
- "Other*",
558
- "SaaS"
559
- ];
560
-
561
- const conversionTypes = [
562
- "Direct Purchase",
563
- "High-Intent Lead Gen",
564
- "Info/Content Lead Gen",
565
- "Location Search",
566
- "Non-Profit/Community",
567
- "Other Conversion"
568
- ];
569
-
570
- // Create category mappings in the format expected by app.py
571
- const categoryMappings = {
572
- "Business Model": {
573
- "num_categories": businessModels.length,
574
- "categories": businessModels
575
- },
576
- "Customer Type": {
577
- "num_categories": customerTypes.length,
578
- "categories": customerTypes
579
- },
580
- "grouped_conversion_type": {
581
- "num_categories": conversionTypes.length,
582
- "categories": conversionTypes
583
- },
584
- "grouped_industry": {
585
- "num_categories": industries.length,
586
- "categories": industries
587
- },
588
- "grouped_page_type": {
589
- "num_categories": pageTypes.length,
590
- "categories": pageTypes
591
- }
592
- };
593
-
594
- // Export the arrays and mappings so they can be imported into other files.
595
- module.exports = {
596
- industries,
597
- customerTypes,
598
- pageTypes,
599
- results,
600
- businessModels,
601
- conversionTypes,
602
- pattern,
603
- categoryMappings,
604
- };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
model/multimodal_cat_mappings_GGG.json DELETED
@@ -1,60 +0,0 @@
1
- {
2
- "Business Model": {
3
- "num_categories": 4,
4
- "categories": [
5
- "E-Commerce",
6
- "Lead Generation",
7
- "Other*",
8
- "SaaS"
9
- ]
10
- },
11
- "Customer Type": {
12
- "num_categories": 4,
13
- "categories": [
14
- "B2B",
15
- "B2C",
16
- "Both",
17
- "Other*"
18
- ]
19
- },
20
- "grouped_conversion_type": {
21
- "num_categories": 6,
22
- "categories": [
23
- "Direct Purchase",
24
- "High-Intent Lead Gen",
25
- "Info/Content Lead Gen",
26
- "Location Search",
27
- "Non-Profit/Community",
28
- "Other Conversion"
29
- ]
30
- },
31
- "grouped_industry": {
32
- "num_categories": 14,
33
- "categories": [
34
- "Automotive & Transportation",
35
- "B2B Services",
36
- "B2B Software & Tech",
37
- "Consumer Services",
38
- "Consumer Software & Apps",
39
- "Education",
40
- "Finance, Insurance & Real Estate",
41
- "Food, Hospitality & Travel",
42
- "Health & Wellness",
43
- "Industrial & Manufacturing",
44
- "Media & Entertainment",
45
- "Non-Profit & Government",
46
- "Other",
47
- "Retail & E-commerce"
48
- ]
49
- },
50
- "grouped_page_type": {
51
- "num_categories": 5,
52
- "categories": [
53
- "Awareness & Discovery",
54
- "Consideration & Evaluation",
55
- "Conversion",
56
- "Internal & Navigation",
57
- "Post-Conversion & Other"
58
- ]
59
- }
60
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
model/multimodal_gated_model_2.7_GGG.pth DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:f174db8f8c95eed67deea8e3b3073d41f98699f64f0f10112532ef5a21c0c5d9
3
- size 788806087
 
 
 
 
patterbs.json DELETED
The diff for this file is too large to render. See raw diff