parthraninga commited on
Commit
2afd81c
Β·
verified Β·
1 Parent(s): dbd2bf5

Upload 9 files

Browse files
Files changed (9) hide show
  1. .gitattributes +1 -35
  2. .gitignore +25 -0
  3. DEPLOY.md +122 -0
  4. Dockerfile +34 -0
  5. README.md +132 -10
  6. app.py +270 -0
  7. contextClassifier.onnx +3 -0
  8. requirements.txt +6 -0
  9. test_api.py +139 -0
.gitattributes CHANGED
@@ -1,35 +1 @@
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
+ *.onnx filter=lfs diff=lfs merge=lfs -text
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
.gitignore ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ venv/
2
+ __pycache__/
3
+ *.pyc
4
+ *.pyo
5
+ *.pyd
6
+ .Python
7
+ env/
8
+ pip-log.txt
9
+ pip-delete-this-directory.txt
10
+ .tox/
11
+ .coverage
12
+ .coverage.*
13
+ .pytest_cache/
14
+ .DS_Store
15
+ .vscode/settings.json
16
+ *.egg-info/
17
+ dist/
18
+ build/
19
+ .idea/
20
+ .env
21
+ .env.local
22
+ .env.*.local
23
+ npm-debug.log*
24
+ yarn-debug.log*
25
+ yarn-error.log*
DEPLOY.md ADDED
@@ -0,0 +1,122 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # πŸš€ Hugging Face Spaces Deployment Guide
2
+
3
+ ## Quick Deploy Steps
4
+
5
+ ### 1. Create Your Space
6
+ 1. Go to [huggingface.co/new-space](https://huggingface.co/new-space)
7
+ 2. Name: `content-classifier` (or your preferred name)
8
+ 3. SDK: **Docker**
9
+ 4. Visibility: Public/Private (your choice)
10
+ 5. Click **Create Space**
11
+
12
+ ### 2. Upload Files
13
+ Upload these files to your Space:
14
+
15
+ **Required Files:**
16
+ - `contextClassifier.onnx` (your model file)
17
+ - `app.py`
18
+ - `requirements.txt`
19
+ - `Dockerfile`
20
+ - `README.md`
21
+
22
+ **Optional Files:**
23
+ - `test_api.py` (for testing)
24
+
25
+ ### 3. Model File
26
+ ⚠️ **Important**: Make sure your `contextClassifier.onnx` file is in the same directory as these files before uploading.
27
+
28
+ ### 4. Git Method (Recommended)
29
+
30
+ ```bash
31
+ # Clone your space
32
+ git clone https://huggingface.co/spaces/YOUR_USERNAME/YOUR_SPACE_NAME
33
+ cd YOUR_SPACE_NAME
34
+
35
+ # Copy your model file
36
+ copy path\to\your\contextClassifier.onnx .
37
+
38
+ # Copy all project files
39
+ copy app.py .
40
+ copy requirements.txt .
41
+ copy Dockerfile .
42
+ copy README.md .
43
+
44
+ # Add and commit
45
+ git add .
46
+ git commit -m "πŸ” Add content classifier ONNX model"
47
+ git push
48
+ ```
49
+
50
+ ### 5. Monitor Deployment
51
+
52
+ 1. **Check Build Logs**: Go to your Space > Logs tab
53
+ 2. **Wait for Build**: Usually takes 2-3 minutes
54
+ 3. **Check Status**: Space will show "Building" β†’ "Running"
55
+
56
+ ### 6. Test Your Space
57
+
58
+ Once deployed, your API will be available at:
59
+ ```
60
+ https://YOUR_USERNAME-YOUR_SPACE_NAME.hf.space
61
+ ```
62
+
63
+ **API Endpoints:**
64
+ - `/docs` - Interactive documentation
65
+ - `/predict` - Main prediction endpoint
66
+ - `/health` - Health check
67
+ - `/model-info` - Model information
68
+
69
+ ### 7. Example Usage
70
+
71
+ ```python
72
+ import requests
73
+
74
+ # Replace with your actual Space URL
75
+ api_url = "https://YOUR_USERNAME-YOUR_SPACE_NAME.hf.space"
76
+
77
+ response = requests.post(
78
+ f"{api_url}/predict",
79
+ json={"text": "This is a test message for classification"}
80
+ )
81
+
82
+ print(response.json())
83
+ ```
84
+
85
+ ## Troubleshooting
86
+
87
+ ### Common Issues:
88
+
89
+ **Build Fails:**
90
+ - Check Logs tab for error details
91
+ - Verify all required files are uploaded
92
+ - Ensure `contextClassifier.onnx` is present
93
+
94
+ **Model Not Found:**
95
+ - Verify `contextClassifier.onnx` is in root directory
96
+ - Check file name matches exactly (case-sensitive)
97
+
98
+ **API Not Responding:**
99
+ - Check if Space is "Running" (not "Building")
100
+ - Try accessing `/health` endpoint first
101
+ - Check Logs for runtime errors
102
+
103
+ **Memory Issues:**
104
+ - ONNX model might be too large
105
+ - Consider model optimization
106
+ - Check Space hardware limits
107
+
108
+ ### Success Indicators:
109
+
110
+ βœ… Space shows "Running" status
111
+ βœ… `/health` endpoint returns `{"status": "healthy"}`
112
+ βœ… `/docs` shows interactive API documentation
113
+ βœ… `/predict` accepts POST requests and returns expected format
114
+
115
+ ## Next Steps
116
+
117
+ 1. **Test thoroughly** with various text inputs
118
+ 2. **Share your Space** with the community
119
+ 3. **Monitor usage** in Space analytics
120
+ 4. **Update model** by pushing new `contextClassifier.onnx`
121
+
122
+ Your Content Classifier is now live and ready to use! πŸŽ‰
Dockerfile ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM python:3.9-slim
2
+
3
+ # Set working directory
4
+ WORKDIR /app
5
+
6
+ # Install system dependencies
7
+ RUN apt-get update && apt-get install -y \
8
+ gcc \
9
+ && rm -rf /var/lib/apt/lists/*
10
+
11
+ # Copy requirements first for better caching
12
+ COPY requirements.txt .
13
+
14
+ # Install Python dependencies
15
+ RUN pip install --no-cache-dir --upgrade pip && \
16
+ pip install --no-cache-dir -r requirements.txt
17
+
18
+ # Copy application files
19
+ COPY . .
20
+
21
+ # Create non-root user for security
22
+ RUN useradd --create-home --shell /bin/bash app && \
23
+ chown -R app:app /app
24
+ USER app
25
+
26
+ # Expose port
27
+ EXPOSE 7860
28
+
29
+ # Health check
30
+ HEALTHCHECK --interval=30s --timeout=30s --start-period=5s --retries=3 \
31
+ CMD python -c "import requests; requests.get('http://localhost:7860/health')"
32
+
33
+ # Run the application
34
+ CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "7860"]
README.md CHANGED
@@ -1,10 +1,132 @@
1
- ---
2
- title: Context Classifier2
3
- emoji: 🐒
4
- colorFrom: indigo
5
- colorTo: pink
6
- sdk: docker
7
- pinned: false
8
- ---
9
-
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ title: Content Classifier
3
+ emoji: πŸ”
4
+ colorFrom: blue
5
+ colorTo: purple
6
+ sdk: docker
7
+ pinned: false
8
+ license: mit
9
+ app_port: 7860
10
+ ---
11
+
12
+ # πŸ” Content Classifier
13
+
14
+ A powerful FastAPI-based content classification service using ONNX for threat detection and sentiment analysis.
15
+
16
+ ## πŸš€ Features
17
+
18
+ - **Threat Detection**: Classify content for potential threats
19
+ - **Sentiment Analysis**: Analyze text sentiment (positive/negative)
20
+ - **ONNX Runtime**: High-performance model inference
21
+ - **REST API**: Easy-to-use HTTP endpoints
22
+ - **Auto Documentation**: Interactive Swagger UI at `/docs`
23
+ - **Health Monitoring**: Built-in health checks
24
+
25
+ ## πŸ“‘ API Endpoints
26
+
27
+ | Endpoint | Method | Description |
28
+ |----------|--------|-------------|
29
+ | `/predict` | POST | Classify text content |
30
+ | `/health` | GET | Check API health status |
31
+ | `/model-info` | GET | Get model information |
32
+ | `/docs` | GET | Interactive API documentation |
33
+
34
+ ## πŸ”§ Usage
35
+
36
+ ### Example Request
37
+
38
+ ```bash
39
+ curl -X POST "https://YOUR-SPACE-NAME.hf.space/predict" \
40
+ -H "Content-Type: application/json" \
41
+ -d '{"text": "This is a sample text to classify"}'
42
+ ```
43
+
44
+ ### Example Response
45
+
46
+ ```json
47
+ {
48
+ "is_threat": false,
49
+ "final_confidence": 0.75,
50
+ "threat_prediction": 0.25,
51
+ "sentiment_analysis": {
52
+ "label": "POSITIVE",
53
+ "score": 0.5
54
+ },
55
+ "onnx_prediction": {
56
+ "threat_probability": 0.25,
57
+ "raw_output": [[0.75, 0.25]],
58
+ "output_shape": [1, 2]
59
+ },
60
+ "models_used": ["contextClassifier.onnx"],
61
+ "raw_predictions": {
62
+ "onnx": {
63
+ "threat_probability": 0.25,
64
+ "raw_output": [[0.75, 0.25]]
65
+ },
66
+ "sentiment": {
67
+ "label": "POSITIVE",
68
+ "score": 0.5
69
+ }
70
+ }
71
+ }
72
+ ```
73
+
74
+ ## πŸ“Š Response Format
75
+
76
+ The API returns a structured response with:
77
+
78
+ - **`is_threat`**: Boolean indicating if content is threatening
79
+ - **`final_confidence`**: Confidence score (0.0 to 1.0)
80
+ - **`threat_prediction`**: Raw threat probability
81
+ - **`sentiment_analysis`**: Sentiment classification and score
82
+ - **`onnx_prediction`**: Raw ONNX model output
83
+ - **`models_used`**: List of models used for prediction
84
+ - **`raw_predictions`**: Complete prediction data
85
+
86
+ ## πŸ› οΈ Local Development
87
+
88
+ 1. **Install dependencies:**
89
+ ```bash
90
+ pip install -r requirements.txt
91
+ ```
92
+
93
+ 2. **Place your model:**
94
+ Ensure `contextClassifier.onnx` is in the project root
95
+
96
+ 3. **Run the API:**
97
+ ```bash
98
+ python app.py
99
+ ```
100
+
101
+ 4. **Visit:** `http://localhost:7860/docs`
102
+
103
+ ## 🐳 Docker
104
+
105
+ ```bash
106
+ # Build
107
+ docker build -t content-classifier .
108
+
109
+ # Run
110
+ docker run -p 7860:7860 content-classifier
111
+ ```
112
+
113
+ ## πŸ“ Model Requirements
114
+
115
+ Your `contextClassifier.onnx` model should:
116
+ - Accept text-based inputs
117
+ - Return classification predictions
118
+ - Be compatible with ONNX Runtime
119
+
120
+ ## βš™οΈ Configuration
121
+
122
+ Customize the preprocessing and postprocessing functions in `app.py` based on your specific model requirements.
123
+
124
+ ## πŸ” Monitoring
125
+
126
+ - **Health Check**: `/health` - Monitor API status
127
+ - **Model Info**: `/model-info` - View model details
128
+ - **Logs**: Check application logs for debugging
129
+
130
+ ## πŸ“œ License
131
+
132
+ MIT License - feel free to use and modify!
app.py ADDED
@@ -0,0 +1,270 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import numpy as np
3
+ import onnxruntime as ort
4
+ from fastapi import FastAPI, HTTPException
5
+ from pydantic import BaseModel
6
+ import uvicorn
7
+ import json
8
+ from typing import Dict, Any, List, Optional
9
+
10
+ app = FastAPI(
11
+ title="Content Classifier API",
12
+ description="ONNX-based content classification for threat detection and sentiment analysis",
13
+ version="1.0.0"
14
+ )
15
+
16
+ # Model configuration
17
+ MODEL_PATH = "contextClassifier.onnx"
18
+ session = None
19
+
20
+ class TextInput(BaseModel):
21
+ text: str
22
+ max_length: Optional[int] = 512
23
+
24
+ class PredictionResponse(BaseModel):
25
+ is_threat: bool
26
+ final_confidence: float
27
+ threat_prediction: float
28
+ sentiment_analysis: Optional[Dict[str, Any]]
29
+ onnx_prediction: Optional[Dict[str, Any]]
30
+ models_used: List[str]
31
+ raw_predictions: Dict[str, Any]
32
+
33
+ def load_model():
34
+ """Load the ONNX model"""
35
+ global session
36
+ try:
37
+ if not os.path.exists(MODEL_PATH):
38
+ raise FileNotFoundError(f"Model file not found: {MODEL_PATH}")
39
+
40
+ session = ort.InferenceSession(MODEL_PATH)
41
+ print(f"βœ… Model loaded successfully from {MODEL_PATH}")
42
+
43
+ # Print model info
44
+ inputs = [input.name for input in session.get_inputs()]
45
+ outputs = [output.name for output in session.get_outputs()]
46
+ print(f"πŸ“₯ Model inputs: {inputs}")
47
+ print(f"πŸ“€ Model outputs: {outputs}")
48
+
49
+ except Exception as e:
50
+ print(f"❌ Error loading model: {e}")
51
+ raise e
52
+
53
+ def preprocess_text(text: str, max_length: int = 512) -> Dict[str, np.ndarray]:
54
+ """
55
+ Preprocess text for the ONNX model
56
+ NOTE: Adjust this function based on your model's specific requirements
57
+ """
58
+ try:
59
+ # Basic text preprocessing (customize based on your model)
60
+ text = text.strip().lower()
61
+
62
+ # Simple tokenization (replace with actual tokenizer if needed)
63
+ tokens = text.split()[:max_length]
64
+
65
+ # Pad or truncate to fixed length
66
+ if len(tokens) < max_length:
67
+ tokens.extend(['[PAD]'] * (max_length - len(tokens)))
68
+
69
+ # Convert to numerical representation
70
+ # NOTE: This is a placeholder - replace with your actual preprocessing
71
+ input_ids = np.array([hash(token) % 30000 for token in tokens], dtype=np.int64).reshape(1, -1)
72
+ attention_mask = np.array([1 if token != '[PAD]' else 0 for token in tokens], dtype=np.int64).reshape(1, -1)
73
+
74
+ return {
75
+ "input_ids": input_ids,
76
+ "attention_mask": attention_mask
77
+ }
78
+
79
+ except Exception as e:
80
+ print(f"❌ Preprocessing error: {e}")
81
+ raise HTTPException(status_code=500, detail=f"Text preprocessing failed: {str(e)}")
82
+
83
+ def postprocess_predictions(outputs: List[np.ndarray]) -> Dict[str, Any]:
84
+ """
85
+ Process ONNX model outputs into the required format
86
+ """
87
+ try:
88
+ predictions = {}
89
+
90
+ if not outputs or len(outputs) == 0:
91
+ raise ValueError("No outputs received from model")
92
+
93
+ # Get the main output (adjust index based on your model)
94
+ main_output = outputs[0]
95
+
96
+ # Extract threat prediction
97
+ if len(main_output.shape) == 2 and main_output.shape[1] >= 2:
98
+ # Binary classification: [non_threat_prob, threat_prob]
99
+ threat_prediction = float(main_output[0][1])
100
+ elif len(main_output.shape) == 2 and main_output.shape[1] == 1:
101
+ # Single output probability
102
+ threat_prediction = float(main_output[0][0])
103
+ else:
104
+ # Fallback for other output shapes
105
+ threat_prediction = float(main_output.flatten()[0])
106
+
107
+ # Calculate confidence and threat classification
108
+ final_confidence = abs(threat_prediction - 0.5) * 2 # Scale to 0-1
109
+ is_threat = threat_prediction > 0.5
110
+
111
+ # Store ONNX predictions
112
+ predictions["onnx"] = {
113
+ "threat_probability": threat_prediction,
114
+ "raw_output": main_output.tolist(),
115
+ "output_shape": main_output.shape
116
+ }
117
+
118
+ # Generate sentiment analysis (inverse relationship with threat)
119
+ sentiment_score = (0.5 - threat_prediction) * 2 # Convert to sentiment scale
120
+ predictions["sentiment"] = {
121
+ "label": "POSITIVE" if sentiment_score > 0 else "NEGATIVE",
122
+ "score": abs(sentiment_score)
123
+ }
124
+
125
+ models_used = ["contextClassifier.onnx"]
126
+
127
+ # Return the exact format specified
128
+ return {
129
+ "is_threat": is_threat,
130
+ "final_confidence": final_confidence,
131
+ "threat_prediction": threat_prediction,
132
+ "sentiment_analysis": predictions.get("sentiment"),
133
+ "onnx_prediction": predictions.get("onnx"),
134
+ "models_used": models_used,
135
+ "raw_predictions": predictions
136
+ }
137
+
138
+ except Exception as e:
139
+ print(f"❌ Postprocessing error: {e}")
140
+ # Return safe fallback response
141
+ return {
142
+ "is_threat": False,
143
+ "final_confidence": 0.0,
144
+ "threat_prediction": 0.0,
145
+ "sentiment_analysis": {"label": "NEUTRAL", "score": 0.0},
146
+ "onnx_prediction": {"error": str(e)},
147
+ "models_used": ["contextClassifier.onnx"],
148
+ "raw_predictions": {"error": str(e)}
149
+ }
150
+
151
+ @app.on_event("startup")
152
+ async def startup_event():
153
+ """Load model on application startup"""
154
+ load_model()
155
+
156
+ @app.get("/")
157
+ async def root():
158
+ """Root endpoint with API information"""
159
+ return {
160
+ "message": "πŸ” Content Classifier API",
161
+ "description": "ONNX-based content classification for threat detection and sentiment analysis",
162
+ "model": MODEL_PATH,
163
+ "status": "running",
164
+ "endpoints": {
165
+ "predict": "/predict",
166
+ "health": "/health",
167
+ "model_info": "/model-info",
168
+ "docs": "/docs"
169
+ }
170
+ }
171
+
172
+ @app.post("/predict", response_model=PredictionResponse)
173
+ async def predict(input_data: TextInput):
174
+ """
175
+ Classify content for threat detection and sentiment analysis
176
+
177
+ Returns the exact format:
178
+ {
179
+ "is_threat": bool,
180
+ "final_confidence": float,
181
+ "threat_prediction": float,
182
+ "sentiment_analysis": dict,
183
+ "onnx_prediction": dict,
184
+ "models_used": list,
185
+ "raw_predictions": dict
186
+ }
187
+ """
188
+ if session is None:
189
+ raise HTTPException(status_code=500, detail="Model not loaded. Please check server logs.")
190
+
191
+ if not input_data.text.strip():
192
+ raise HTTPException(status_code=400, detail="Text input cannot be empty")
193
+
194
+ try:
195
+ # Preprocess the input text
196
+ model_inputs = preprocess_text(input_data.text, input_data.max_length)
197
+
198
+ # Prepare inputs for ONNX Runtime
199
+ input_names = [input.name for input in session.get_inputs()]
200
+ ort_inputs = {}
201
+
202
+ for name in input_names:
203
+ if name in model_inputs:
204
+ ort_inputs[name] = model_inputs[name]
205
+ else:
206
+ print(f"⚠️ Warning: Expected input '{name}' not found in processed inputs")
207
+
208
+ if not ort_inputs:
209
+ raise HTTPException(status_code=500, detail="No valid inputs prepared for model")
210
+
211
+ # Run inference
212
+ outputs = session.run(None, ort_inputs)
213
+
214
+ # Process and return results
215
+ result = postprocess_predictions(outputs)
216
+ return result
217
+
218
+ except Exception as e:
219
+ print(f"❌ Prediction error: {e}")
220
+ raise HTTPException(status_code=500, detail=f"Prediction failed: {str(e)}")
221
+
222
+ @app.get("/health")
223
+ async def health_check():
224
+ """Health check endpoint"""
225
+ return {
226
+ "status": "healthy" if session is not None else "unhealthy",
227
+ "model_loaded": session is not None,
228
+ "model_path": MODEL_PATH,
229
+ "model_exists": os.path.exists(MODEL_PATH)
230
+ }
231
+
232
+ @app.get("/model-info")
233
+ async def model_info():
234
+ """Get detailed model information"""
235
+ if session is None:
236
+ raise HTTPException(status_code=500, detail="Model not loaded")
237
+
238
+ try:
239
+ inputs = []
240
+ for input_meta in session.get_inputs():
241
+ inputs.append({
242
+ "name": input_meta.name,
243
+ "type": str(input_meta.type),
244
+ "shape": list(input_meta.shape) if input_meta.shape else None
245
+ })
246
+
247
+ outputs = []
248
+ for output_meta in session.get_outputs():
249
+ outputs.append({
250
+ "name": output_meta.name,
251
+ "type": str(output_meta.type),
252
+ "shape": list(output_meta.shape) if output_meta.shape else None
253
+ })
254
+
255
+ return {
256
+ "model_path": MODEL_PATH,
257
+ "model_size": f"{os.path.getsize(MODEL_PATH) / (1024*1024):.2f} MB",
258
+ "inputs": inputs,
259
+ "outputs": outputs,
260
+ "runtime_info": {
261
+ "providers": session.get_providers(),
262
+ "device": "CPU"
263
+ }
264
+ }
265
+
266
+ except Exception as e:
267
+ raise HTTPException(status_code=500, detail=f"Failed to get model info: {str(e)}")
268
+
269
+ if __name__ == "__main__":
270
+ uvicorn.run(app, host="0.0.0.0", port=7860)
contextClassifier.onnx ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:11e8c5314dfcec3f5c06b74655961b3211a4f4509ff8e7026e066ac14251d979
3
+ size 267958108
requirements.txt ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ fastapi==0.104.1
2
+ uvicorn[standard]==0.24.0
3
+ onnxruntime==1.16.3
4
+ numpy==1.24.3
5
+ pydantic==2.5.0
6
+ python-multipart==0.0.6
test_api.py ADDED
@@ -0,0 +1,139 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import requests
2
+ import json
3
+ import time
4
+
5
+ # Configuration
6
+ BASE_URL = "http://localhost:7860"
7
+
8
+ def test_api():
9
+ """Test all API endpoints"""
10
+ print("πŸ§ͺ Testing Content Classifier API")
11
+ print("=" * 50)
12
+
13
+ # Test 1: Root endpoint
14
+ print("\nπŸ“ Testing root endpoint...")
15
+ try:
16
+ response = requests.get(f"{BASE_URL}/")
17
+ print(f"βœ… Status: {response.status_code}")
18
+ print(f"πŸ“„ Response: {json.dumps(response.json(), indent=2)}")
19
+ except Exception as e:
20
+ print(f"❌ Error: {e}")
21
+
22
+ # Test 2: Health check
23
+ print("\nπŸ₯ Testing health endpoint...")
24
+ try:
25
+ response = requests.get(f"{BASE_URL}/health")
26
+ print(f"βœ… Status: {response.status_code}")
27
+ print(f"πŸ“„ Response: {json.dumps(response.json(), indent=2)}")
28
+ except Exception as e:
29
+ print(f"❌ Error: {e}")
30
+
31
+ # Test 3: Model info
32
+ print("\nπŸ€– Testing model info endpoint...")
33
+ try:
34
+ response = requests.get(f"{BASE_URL}/model-info")
35
+ print(f"βœ… Status: {response.status_code}")
36
+ if response.status_code == 200:
37
+ print(f"πŸ“„ Response: {json.dumps(response.json(), indent=2)}")
38
+ else:
39
+ print(f"πŸ“„ Response: {response.text}")
40
+ except Exception as e:
41
+ print(f"❌ Error: {e}")
42
+
43
+ # Test 4: Prediction endpoint
44
+ print("\nπŸ” Testing prediction endpoint...")
45
+
46
+ test_cases = [
47
+ {
48
+ "text": "Hello, how are you today? I hope you're doing well!",
49
+ "expected": "positive sentiment"
50
+ },
51
+ {
52
+ "text": "I will destroy everything and cause harm!",
53
+ "expected": "threat detection"
54
+ },
55
+ {
56
+ "text": "This product is amazing, I love it so much!",
57
+ "expected": "positive sentiment"
58
+ },
59
+ {
60
+ "text": "I hate this, it's terrible and awful!",
61
+ "expected": "negative sentiment"
62
+ },
63
+ {
64
+ "text": "Neutral statement about weather conditions today.",
65
+ "expected": "neutral/low confidence"
66
+ }
67
+ ]
68
+
69
+ for i, case in enumerate(test_cases, 1):
70
+ print(f"\nπŸ“ Test Case {i}: {case['expected']}")
71
+ print(f"πŸ’¬ Text: '{case['text'][:50]}{'...' if len(case['text']) > 50 else ''}'")
72
+
73
+ try:
74
+ payload = {
75
+ "text": case["text"],
76
+ "max_length": 512
77
+ }
78
+
79
+ response = requests.post(f"{BASE_URL}/predict", json=payload)
80
+
81
+ if response.status_code == 200:
82
+ result = response.json()
83
+ print(f"βœ… Status: {response.status_code}")
84
+ print(f"🎯 Is Threat: {result['is_threat']}")
85
+ print(f"πŸ“Š Confidence: {result['final_confidence']:.3f}")
86
+ print(f"⚠️ Threat Prediction: {result['threat_prediction']:.3f}")
87
+ print(f"😊 Sentiment: {result['sentiment_analysis']['label']} ({result['sentiment_analysis']['score']:.3f})")
88
+ print(f"πŸ”§ Models Used: {result['models_used']}")
89
+ else:
90
+ print(f"❌ Status: {response.status_code}")
91
+ print(f"πŸ“„ Response: {response.text}")
92
+
93
+ except Exception as e:
94
+ print(f"❌ Error: {e}")
95
+
96
+ print("\n" + "=" * 50)
97
+ print("🏁 API Testing Complete!")
98
+
99
+ def test_edge_cases():
100
+ """Test edge cases and error conditions"""
101
+ print("\n🚨 Testing Edge Cases")
102
+ print("=" * 30)
103
+
104
+ edge_cases = [
105
+ {"text": "", "description": "Empty string"},
106
+ {"text": " ", "description": "Whitespace only"},
107
+ {"text": "A" * 1000, "description": "Very long text"},
108
+ {"text": "πŸ”₯πŸ’―πŸš€", "description": "Emoji only"},
109
+ {"text": "12345 67890", "description": "Numbers only"}
110
+ ]
111
+
112
+ for case in edge_cases:
113
+ print(f"\nπŸ“ Testing: {case['description']}")
114
+ try:
115
+ payload = {"text": case["text"]}
116
+ response = requests.post(f"{BASE_URL}/predict", json=payload)
117
+
118
+ if response.status_code == 200:
119
+ result = response.json()
120
+ print(f"βœ… Success: Threat={result['is_threat']}, Confidence={result['final_confidence']:.3f}")
121
+ else:
122
+ print(f"⚠️ Status {response.status_code}: {response.json().get('detail', 'Unknown error')}")
123
+
124
+ except Exception as e:
125
+ print(f"❌ Error: {e}")
126
+
127
+ if __name__ == "__main__":
128
+ print("πŸ” Content Classifier API Test Suite")
129
+ print(f"🌐 Base URL: {BASE_URL}")
130
+
131
+ # Wait a moment for server to be ready
132
+ print("\n⏱️ Waiting for server to be ready...")
133
+ time.sleep(2)
134
+
135
+ # Run tests
136
+ test_api()
137
+ test_edge_cases()
138
+
139
+ print(f"\nπŸ“š Visit {BASE_URL}/docs for interactive API documentation")