parthraninga commited on
Commit
95efa57
·
verified ·
1 Parent(s): b15ab84

Upload 10 files

Browse files
Files changed (10) hide show
  1. .dockerignore +69 -0
  2. .gitignore +134 -0
  3. Dockerfile +47 -0
  4. README.md +295 -10
  5. app.py +285 -0
  6. hf_client.py +197 -0
  7. main.py +221 -0
  8. requirements.txt +10 -0
  9. start_server.py +47 -0
  10. test_client.py +170 -0
.dockerignore ADDED
@@ -0,0 +1,69 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Git
2
+ .git
3
+ .gitignore
4
+
5
+ # Python
6
+ __pycache__/
7
+ *.py[cod]
8
+ *$py.class
9
+ *.so
10
+ .Python
11
+ build/
12
+ develop-eggs/
13
+ dist/
14
+ downloads/
15
+ eggs/
16
+ .eggs/
17
+ lib/
18
+ lib64/
19
+ parts/
20
+ sdist/
21
+ var/
22
+ wheels/
23
+ *.egg-info/
24
+ .installed.cfg
25
+ *.egg
26
+ MANIFEST
27
+
28
+ # Virtual environments
29
+ .env
30
+ .venv
31
+ env/
32
+ venv/
33
+ ENV/
34
+ env.bak/
35
+ venv.bak/
36
+
37
+ # IDE
38
+ .vscode/
39
+ .idea/
40
+ *.swp
41
+ *.swo
42
+ *~
43
+
44
+ # OS
45
+ .DS_Store
46
+ .DS_Store?
47
+ ._*
48
+ .Spotlight-V100
49
+ .Trashes
50
+ ehthumbs.db
51
+ Thumbs.db
52
+
53
+ # Test files
54
+ test_client.py
55
+ hf_client.py
56
+ start_server.py
57
+ test_image.jpg
58
+ sample_images/
59
+
60
+ # Logs
61
+ *.log
62
+ logs/
63
+
64
+ # Temporary files
65
+ tmp/
66
+ temp/
67
+
68
+ # Documentation
69
+ README.md
.gitignore ADDED
@@ -0,0 +1,134 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+ *.so
6
+ .Python
7
+ build/
8
+ develop-eggs/
9
+ dist/
10
+ downloads/
11
+ eggs/
12
+ .eggs/
13
+ lib/
14
+ lib64/
15
+ parts/
16
+ sdist/
17
+ var/
18
+ wheels/
19
+ *.egg-info/
20
+ .installed.cfg
21
+ *.egg
22
+ MANIFEST
23
+
24
+ # PyInstaller
25
+ *.manifest
26
+ *.spec
27
+
28
+ # Installer logs
29
+ pip-log.txt
30
+ pip-delete-this-directory.txt
31
+
32
+ # Unit test / coverage reports
33
+ htmlcov/
34
+ .tox/
35
+ .coverage
36
+ .coverage.*
37
+ .cache
38
+ nosetests.xml
39
+ coverage.xml
40
+ *.cover
41
+ .hypothesis/
42
+ .pytest_cache/
43
+
44
+ # Translations
45
+ *.mo
46
+ *.pot
47
+
48
+ # Django stuff:
49
+ *.log
50
+ local_settings.py
51
+ db.sqlite3
52
+
53
+ # Flask stuff:
54
+ instance/
55
+ .webassets-cache
56
+
57
+ # Scrapy stuff:
58
+ .scrapy
59
+
60
+ # Sphinx documentation
61
+ docs/_build/
62
+
63
+ # PyBuilder
64
+ target/
65
+
66
+ # Jupyter Notebook
67
+ .ipynb_checkpoints
68
+
69
+ # pyenv
70
+ .python-version
71
+
72
+ # celery beat schedule file
73
+ celerybeat-schedule
74
+
75
+ # SageMath parsed files
76
+ *.sage.py
77
+
78
+ # Environments
79
+ .env
80
+ .venv
81
+ env/
82
+ venv/
83
+ ENV/
84
+ env.bak/
85
+ venv.bak/
86
+
87
+ # Spyder project settings
88
+ .spyderproject
89
+ .spyproject
90
+
91
+ # Rope project settings
92
+ .ropeproject
93
+
94
+ # mkdocs documentation
95
+ /site
96
+
97
+ # mypy
98
+ .mypy_cache/
99
+ .dmypy.json
100
+ dmypy.json
101
+
102
+ # IDE
103
+ .vscode/
104
+ .idea/
105
+ *.swp
106
+ *.swo
107
+ *~
108
+
109
+ # OS
110
+ .DS_Store
111
+ .DS_Store?
112
+ ._*
113
+ .Spotlight-V100
114
+ .Trashes
115
+ ehthumbs.db
116
+ Thumbs.db
117
+
118
+ # Model files (if you have local models)
119
+ *.safetensors
120
+ *.bin
121
+ *.pt
122
+ *.pth
123
+
124
+ # Test images
125
+ test_image.jpg
126
+ sample_images/
127
+
128
+ # Logs
129
+ *.log
130
+ logs/
131
+
132
+ # Temporary files
133
+ tmp/
134
+ temp/
Dockerfile ADDED
@@ -0,0 +1,47 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Use Python 3.9 slim image as base
2
+ FROM python:3.9-slim
3
+
4
+ # Set working directory
5
+ WORKDIR /app
6
+
7
+ # Install system dependencies
8
+ RUN apt-get update && apt-get install -y \
9
+ gcc \
10
+ g++ \
11
+ libgl1-mesa-glx \
12
+ libglib2.0-0 \
13
+ libsm6 \
14
+ libxext6 \
15
+ libxrender-dev \
16
+ libgomp1 \
17
+ curl \
18
+ && rm -rf /var/lib/apt/lists/*
19
+
20
+ # Copy requirements first for better caching
21
+ COPY requirements.txt .
22
+
23
+ # Install Python dependencies
24
+ RUN pip install --no-cache-dir -r requirements.txt
25
+
26
+ # Create models directory
27
+ RUN mkdir -p /app/models
28
+
29
+ # Copy model files
30
+ COPY *.safetensors /app/models/
31
+
32
+ # Copy application code
33
+ COPY app.py .
34
+
35
+ # Create a non-root user for security
36
+ RUN useradd -m -u 1000 appuser && chown -R appuser:appuser /app
37
+ USER appuser
38
+
39
+ # Expose port (Hugging Face Spaces uses port 7860)
40
+ EXPOSE 7860
41
+
42
+ # Health check
43
+ HEALTHCHECK --interval=30s --timeout=30s --start-period=5s --retries=3 \
44
+ CMD curl -f http://localhost:7860/health || exit 1
45
+
46
+ # Run the application
47
+ CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "7860"]
README.md CHANGED
@@ -1,10 +1,295 @@
1
- ---
2
- title: Chatgpt Oasis
3
- emoji: 🐨
4
- colorFrom: gray
5
- colorTo: indigo
6
- sdk: docker
7
- pinned: false
8
- ---
9
-
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # ChatGPT Oasis Model Inference API - Hugging Face Spaces (Docker)
2
+
3
+ A FastAPI-based inference server for vision models (Oasis 500M and ViT-L-20) deployed on Hugging Face Spaces using Docker SDK with local model files.
4
+
5
+ ## 🚀 Live Demo
6
+
7
+ This API is deployed on Hugging Face Spaces and can be accessed at:
8
+ ```
9
+ https://your-username-chatgpt-oasis.hf.space
10
+ ```
11
+
12
+ ## 📋 API Endpoints
13
+
14
+ ### Base URL
15
+ ```
16
+ https://your-username-chatgpt-oasis.hf.space
17
+ ```
18
+
19
+ ### Available Endpoints
20
+
21
+ #### 1. API Information
22
+ - **GET** `/`
23
+ - Returns API information and usage instructions
24
+
25
+ #### 2. Health Check
26
+ - **GET** `/health`
27
+ - Returns server health status, model loading status, and model file presence
28
+
29
+ #### 3. List Models
30
+ - **GET** `/models`
31
+ - Returns information about available models and their file status
32
+
33
+ #### 4. Inference (Base64)
34
+ - **POST** `/inference`
35
+ - Accepts base64 encoded images
36
+ - Request body:
37
+ ```json
38
+ {
39
+ "image": "base64_encoded_image_string",
40
+ "model_name": "oasis500m" // or "vit-l-20"
41
+ }
42
+ ```
43
+
44
+ #### 5. Inference (File Upload)
45
+ - **POST** `/upload_inference`
46
+ - Accepts image file uploads
47
+ - Form data:
48
+ - `file`: Image file
49
+ - `model_name`: Model to use (optional, defaults to "oasis500m")
50
+
51
+ #### 6. Simple Prediction (Gradio Compatible)
52
+ - **POST** `/predict`
53
+ - Simple file upload endpoint for easy integration
54
+
55
+ ## 🔧 Usage Examples
56
+
57
+ ### Using Python Requests
58
+
59
+ ```python
60
+ import requests
61
+ import base64
62
+ from PIL import Image
63
+ import io
64
+
65
+ # Your Hugging Face Spaces URL
66
+ SPACE_URL = "https://your-username-chatgpt-oasis.hf.space"
67
+
68
+ # Method 1: File Upload
69
+ def predict_with_file_upload(image_path, model_name="oasis500m"):
70
+ with open(image_path, 'rb') as f:
71
+ files = {'file': f}
72
+ data = {'model_name': model_name}
73
+
74
+ response = requests.post(
75
+ f"{SPACE_URL}/upload_inference",
76
+ files=files,
77
+ data=data,
78
+ timeout=120
79
+ )
80
+ return response.json()
81
+
82
+ # Method 2: Base64 Encoding
83
+ def predict_with_base64(image_path, model_name="oasis500m"):
84
+ # Load and encode image
85
+ image = Image.open(image_path)
86
+ buffer = io.BytesIO()
87
+ image.save(buffer, format="JPEG")
88
+ image_base64 = base64.b64encode(buffer.getvalue()).decode()
89
+
90
+ # Make request
91
+ response = requests.post(
92
+ f"{SPACE_URL}/inference",
93
+ json={
94
+ "image": image_base64,
95
+ "model_name": model_name
96
+ },
97
+ timeout=120
98
+ )
99
+ return response.json()
100
+
101
+ # Example usage
102
+ result = predict_with_file_upload("your_image.jpg", "oasis500m")
103
+ print(result)
104
+ ```
105
+
106
+ ### Using cURL
107
+
108
+ ```bash
109
+ # File upload inference
110
+ curl -X POST "https://your-username-chatgpt-oasis.hf.space/upload_inference" \
111
+ -H "accept: application/json" \
112
+ -F "file=@your_image.jpg" \
113
+ -F "model_name=oasis500m"
114
+
115
+ # Health check
116
+ curl "https://your-username-chatgpt-oasis.hf.space/health"
117
+
118
+ # API documentation
119
+ curl "https://your-username-chatgpt-oasis.hf.space/docs"
120
+ ```
121
+
122
+ ### Using JavaScript/Fetch
123
+
124
+ ```javascript
125
+ // File upload inference
126
+ async function predictImage(file, modelName = 'oasis500m') {
127
+ const formData = new FormData();
128
+ formData.append('file', file);
129
+ formData.append('model_name', modelName);
130
+
131
+ const response = await fetch('https://your-username-chatgpt-oasis.hf.space/upload_inference', {
132
+ method: 'POST',
133
+ body: formData
134
+ });
135
+
136
+ return await response.json();
137
+ }
138
+
139
+ // Base64 inference
140
+ async function predictImageBase64(imageBase64, modelName = 'oasis500m') {
141
+ const response = await fetch('https://your-username-chatgpt-oasis.hf.space/inference', {
142
+ method: 'POST',
143
+ headers: {
144
+ 'Content-Type': 'application/json',
145
+ },
146
+ body: JSON.stringify({
147
+ image: imageBase64,
148
+ model_name: modelName
149
+ })
150
+ });
151
+
152
+ return await response.json();
153
+ }
154
+ ```
155
+
156
+ ## 📊 Response Format
157
+
158
+ All inference endpoints return the same response format:
159
+
160
+ ```json
161
+ {
162
+ "predictions": [
163
+ {
164
+ "label": "predicted_class_name",
165
+ "confidence": 0.95
166
+ },
167
+ {
168
+ "label": "second_predicted_class",
169
+ "confidence": 0.03
170
+ }
171
+ ],
172
+ "model_used": "oasis500m",
173
+ "confidence_scores": [0.95, 0.03, 0.01, 0.005, 0.005]
174
+ }
175
+ ```
176
+
177
+ ## 🤖 Available Models
178
+
179
+ ### Oasis 500M
180
+ - **Type**: Vision Transformer
181
+ - **Size**: ~500M parameters
182
+ - **File**: `oasis500m.safetensors`
183
+ - **Use Case**: General image classification
184
+ - **Performance**: High accuracy on ImageNet
185
+
186
+ ### ViT-L-20
187
+ - **Type**: Vision Transformer Large
188
+ - **Size**: ~300M parameters
189
+ - **File**: `vit-l-20.safetensors`
190
+ - **Use Case**: High-performance image classification
191
+ - **Performance**: State-of-the-art on many benchmarks
192
+
193
+ ## 🔍 API Documentation
194
+
195
+ Once deployed, you can access:
196
+ - **Interactive API Docs**: `https://your-username-chatgpt-oasis.hf.space/docs`
197
+ - **Alternative API Docs**: `https://your-username-chatgpt-oasis.hf.space/redoc`
198
+
199
+ ## 🚀 Deployment on Hugging Face Spaces (Docker SDK)
200
+
201
+ ### Prerequisites
202
+ 1. Hugging Face account
203
+ 2. Local model files (`.safetensors`)
204
+ 3. Git repository with your code
205
+
206
+ ### Steps to Deploy
207
+
208
+ 1. **Create a new Space on Hugging Face**
209
+ - Go to [Hugging Face Spaces](https://huggingface.co/spaces)
210
+ - Click "Create new Space"
211
+ - Choose **"Docker"** as the SDK
212
+ - Set visibility (public/private)
213
+
214
+ 2. **Prepare your files**
215
+ - `Dockerfile` - Container configuration
216
+ - `app.py` - Main FastAPI application
217
+ - `requirements.txt` - Python dependencies
218
+ - `README.md` - This documentation
219
+ - `oasis500m.safetensors` - Oasis model weights
220
+ - `vit-l-20.safetensors` - ViT model weights
221
+
222
+ 3. **Upload files to your Space**
223
+ - Upload all files to the Space repository
224
+ - The Dockerfile will copy the model files into the container
225
+
226
+ 4. **Configure the Space**
227
+ - Set appropriate hardware requirements (CPU/GPU)
228
+ - Ensure sufficient memory for model loading
229
+
230
+ 5. **Deploy**
231
+ - Push your code to the Space repository
232
+ - Hugging Face will automatically build the Docker image and deploy
233
+
234
+ ### Space Configuration
235
+
236
+ Your Space will need:
237
+ - **Hardware**: CPU (or GPU for faster inference)
238
+ - **Memory**: At least 8GB RAM (for both models)
239
+ - **Storage**: Sufficient space for model files (~3GB)
240
+
241
+ ## 📁 File Structure
242
+
243
+ ```
244
+ your-space/
245
+ ├── Dockerfile # Container configuration
246
+ ├── app.py # FastAPI application
247
+ ├── requirements.txt # Python dependencies
248
+ ├── README.md # Documentation
249
+ ├── .dockerignore # Docker ignore file
250
+ ├── oasis500m.safetensors # Oasis model weights
251
+ └── vit-l-20.safetensors # ViT model weights
252
+ ```
253
+
254
+ ## ⚡ Performance Tips
255
+
256
+ - **Model Loading**: Models are loaded once when the container starts
257
+ - **Local Files**: Using local `.safetensors` files avoids download time
258
+ - **Caching**: Consider implementing response caching for repeated requests
259
+ - **Batch Processing**: For multiple images, send them sequentially
260
+ - **Image Size**: Optimize image size before sending (models expect specific dimensions)
261
+
262
+ ## 🔧 Troubleshooting
263
+
264
+ ### Common Issues
265
+
266
+ 1. **Model Loading Time**
267
+ - First request may take longer as models load from local files
268
+ - Check `/health` endpoint for model status
269
+
270
+ 2. **Memory Issues**
271
+ - Use smaller images
272
+ - Process one image at a time
273
+ - Consider using only one model at a time
274
+
275
+ 3. **Model File Issues**
276
+ - Ensure `.safetensors` files are uploaded to the Space
277
+ - Check `/health` endpoint for file presence status
278
+
279
+ 4. **Timeout Errors**
280
+ - Increase timeout settings in your client
281
+ - Check Space logs for errors
282
+
283
+ ### Getting Help
284
+
285
+ - Check the Space logs in Hugging Face dashboard
286
+ - Use the `/health` endpoint to verify model and file status
287
+ - Test with the `/docs` interactive interface
288
+
289
+ ## 📝 License
290
+
291
+ This project is for inference purposes. Please respect the licenses of the underlying models (Oasis and ViT).
292
+
293
+ ## 🤝 Contributing
294
+
295
+ Feel free to submit issues and enhancement requests!
app.py ADDED
@@ -0,0 +1,285 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import FastAPI, File, UploadFile, HTTPException
2
+ from fastapi.responses import JSONResponse
3
+ from pydantic import BaseModel
4
+ import torch
5
+ import torch.nn.functional as F
6
+ from transformers import AutoImageProcessor, AutoModelForImageClassification
7
+ from PIL import Image
8
+ import io
9
+ import numpy as np
10
+ from typing import List, Dict, Any
11
+ import logging
12
+ import os
13
+
14
+ # Configure logging
15
+ logging.basicConfig(level=logging.INFO)
16
+ logger = logging.getLogger(__name__)
17
+
18
+ app = FastAPI(
19
+ title="ChatGPT Oasis Model Inference API",
20
+ description="FastAPI inference server for Oasis and ViT models deployed on Hugging Face Spaces with Docker",
21
+ version="1.0.0"
22
+ )
23
+
24
+ # Global variables to store loaded models
25
+ oasis_model = None
26
+ oasis_processor = None
27
+ vit_model = None
28
+ vit_processor = None
29
+
30
+ class InferenceRequest(BaseModel):
31
+ image: str # Base64 encoded image
32
+ model_name: str = "oasis500m" # Default to oasis model
33
+
34
+ class InferenceResponse(BaseModel):
35
+ predictions: List[Dict[str, Any]]
36
+ model_used: str
37
+ confidence_scores: List[float]
38
+
39
+ def load_models():
40
+ """Load both models from local files"""
41
+ global oasis_model, oasis_processor, vit_model, vit_processor
42
+
43
+ try:
44
+ logger.info("Loading Oasis 500M model from local files...")
45
+ # Load Oasis model from local files
46
+ oasis_processor = AutoImageProcessor.from_pretrained("microsoft/oasis-500m")
47
+ oasis_model = AutoModelForImageClassification.from_pretrained(
48
+ "microsoft/oasis-500m",
49
+ local_files_only=False # Will download config but use local weights
50
+ )
51
+
52
+ # Load local weights if available
53
+ oasis_model_path = "/app/models/oasis500m.safetensors"
54
+ if os.path.exists(oasis_model_path):
55
+ logger.info("Loading Oasis weights from local file...")
56
+ from safetensors.torch import load_file
57
+ state_dict = load_file(oasis_model_path)
58
+ oasis_model.load_state_dict(state_dict, strict=False)
59
+
60
+ oasis_model.eval()
61
+
62
+ logger.info("Loading ViT-L-20 model from local files...")
63
+ # Load ViT model from local files
64
+ vit_processor = AutoImageProcessor.from_pretrained("google/vit-large-patch16-224")
65
+ vit_model = AutoModelForImageClassification.from_pretrained(
66
+ "google/vit-large-patch16-224",
67
+ local_files_only=False # Will download config but use local weights
68
+ )
69
+
70
+ # Load local weights if available
71
+ vit_model_path = "/app/models/vit-l-20.safetensors"
72
+ if os.path.exists(vit_model_path):
73
+ logger.info("Loading ViT weights from local file...")
74
+ from safetensors.torch import load_file
75
+ state_dict = load_file(vit_model_path)
76
+ vit_model.load_state_dict(state_dict, strict=False)
77
+
78
+ vit_model.eval()
79
+
80
+ logger.info("All models loaded successfully!")
81
+
82
+ except Exception as e:
83
+ logger.error(f"Error loading models: {e}")
84
+ raise e
85
+
86
+ @app.on_event("startup")
87
+ async def startup_event():
88
+ """Load models when the application starts"""
89
+ load_models()
90
+
91
+ @app.get("/")
92
+ async def root():
93
+ """Root endpoint with API information"""
94
+ return {
95
+ "message": "ChatGPT Oasis Model Inference API",
96
+ "version": "1.0.0",
97
+ "deployed_on": "Hugging Face Spaces (Docker)",
98
+ "available_models": ["oasis500m", "vit-l-20"],
99
+ "endpoints": {
100
+ "health": "/health",
101
+ "inference": "/inference",
102
+ "upload_inference": "/upload_inference",
103
+ "predict": "/predict"
104
+ },
105
+ "usage": {
106
+ "base64_inference": "POST /inference with JSON body containing 'image' (base64) and 'model_name'",
107
+ "file_upload": "POST /upload_inference with multipart form containing 'file' and optional 'model_name'",
108
+ "simple_predict": "POST /predict with file upload for quick inference"
109
+ }
110
+ }
111
+
112
+ @app.get("/health")
113
+ async def health_check():
114
+ """Health check endpoint"""
115
+ models_status = {
116
+ "oasis500m": oasis_model is not None,
117
+ "vit-l-20": vit_model is not None
118
+ }
119
+
120
+ # Check if model files exist
121
+ model_files = {
122
+ "oasis500m": os.path.exists("/app/models/oasis500m.safetensors"),
123
+ "vit-l-20": os.path.exists("/app/models/vit-l-20.safetensors")
124
+ }
125
+
126
+ return {
127
+ "status": "healthy",
128
+ "models_loaded": models_status,
129
+ "model_files_present": model_files,
130
+ "deployment": "huggingface-spaces-docker"
131
+ }
132
+
133
+ def process_image_with_model(image: Image.Image, model_name: str):
134
+ """Process image with the specified model"""
135
+ if model_name == "oasis500m":
136
+ if oasis_model is None or oasis_processor is None:
137
+ raise HTTPException(status_code=500, detail="Oasis model not loaded")
138
+
139
+ inputs = oasis_processor(images=image, return_tensors="pt")
140
+ with torch.no_grad():
141
+ outputs = oasis_model(**inputs)
142
+ logits = outputs.logits
143
+ probabilities = F.softmax(logits, dim=-1)
144
+
145
+ # Get top predictions
146
+ top_probs, top_indices = torch.topk(probabilities, 5)
147
+
148
+ predictions = []
149
+ for i in range(top_indices.shape[1]):
150
+ pred = {
151
+ "label": oasis_model.config.id2label[top_indices[0][i].item()],
152
+ "confidence": top_probs[0][i].item()
153
+ }
154
+ predictions.append(pred)
155
+
156
+ return predictions
157
+
158
+ elif model_name == "vit-l-20":
159
+ if vit_model is None or vit_processor is None:
160
+ raise HTTPException(status_code=500, detail="ViT model not loaded")
161
+
162
+ inputs = vit_processor(images=image, return_tensors="pt")
163
+ with torch.no_grad():
164
+ outputs = vit_model(**inputs)
165
+ logits = outputs.logits
166
+ probabilities = F.softmax(logits, dim=-1)
167
+
168
+ # Get top predictions
169
+ top_probs, top_indices = torch.topk(probabilities, 5)
170
+
171
+ predictions = []
172
+ for i in range(top_indices.shape[1]):
173
+ pred = {
174
+ "label": vit_model.config.id2label[top_indices[0][i].item()],
175
+ "confidence": top_probs[0][i].item()
176
+ }
177
+ predictions.append(pred)
178
+
179
+ return predictions
180
+
181
+ else:
182
+ raise HTTPException(status_code=400, detail=f"Unknown model: {model_name}")
183
+
184
+ @app.post("/inference", response_model=InferenceResponse)
185
+ async def inference(request: InferenceRequest):
186
+ """Inference endpoint using base64 encoded image"""
187
+ try:
188
+ import base64
189
+
190
+ # Decode base64 image
191
+ image_data = base64.b64decode(request.image)
192
+ image = Image.open(io.BytesIO(image_data)).convert('RGB')
193
+
194
+ # Process with model
195
+ predictions = process_image_with_model(image, request.model_name)
196
+
197
+ # Extract confidence scores
198
+ confidence_scores = [pred["confidence"] for pred in predictions]
199
+
200
+ return InferenceResponse(
201
+ predictions=predictions,
202
+ model_used=request.model_name,
203
+ confidence_scores=confidence_scores
204
+ )
205
+
206
+ except Exception as e:
207
+ logger.error(f"Inference error: {e}")
208
+ raise HTTPException(status_code=500, detail=str(e))
209
+
210
+ @app.post("/upload_inference", response_model=InferenceResponse)
211
+ async def upload_inference(
212
+ file: UploadFile = File(...),
213
+ model_name: str = "oasis500m"
214
+ ):
215
+ """Inference endpoint using file upload"""
216
+ try:
217
+ # Validate file type
218
+ if not file.content_type.startswith('image/'):
219
+ raise HTTPException(status_code=400, detail="File must be an image")
220
+
221
+ # Read and process image
222
+ image_data = await file.read()
223
+ image = Image.open(io.BytesIO(image_data)).convert('RGB')
224
+
225
+ # Process with model
226
+ predictions = process_image_with_model(image, model_name)
227
+
228
+ # Extract confidence scores
229
+ confidence_scores = [pred["confidence"] for pred in predictions]
230
+
231
+ return InferenceResponse(
232
+ predictions=predictions,
233
+ model_used=model_name,
234
+ confidence_scores=confidence_scores
235
+ )
236
+
237
+ except Exception as e:
238
+ logger.error(f"Upload inference error: {e}")
239
+ raise HTTPException(status_code=500, detail=str(e))
240
+
241
+ @app.get("/models")
242
+ async def list_models():
243
+ """List available models and their status"""
244
+ return {
245
+ "available_models": [
246
+ {
247
+ "name": "oasis500m",
248
+ "description": "Oasis 500M vision model",
249
+ "loaded": oasis_model is not None,
250
+ "file_present": os.path.exists("/app/models/oasis500m.safetensors")
251
+ },
252
+ {
253
+ "name": "vit-l-20",
254
+ "description": "Vision Transformer Large model",
255
+ "loaded": vit_model is not None,
256
+ "file_present": os.path.exists("/app/models/vit-l-20.safetensors")
257
+ }
258
+ ]
259
+ }
260
+
261
+ # Hugging Face Spaces specific endpoint for Gradio compatibility
262
+ @app.post("/predict")
263
+ async def predict(file: UploadFile = File(...)):
264
+ """Simple prediction endpoint for Hugging Face Spaces integration"""
265
+ try:
266
+ # Validate file type
267
+ if not file.content_type.startswith('image/'):
268
+ raise HTTPException(status_code=400, detail="File must be an image")
269
+
270
+ # Read and process image
271
+ image_data = await file.read()
272
+ image = Image.open(io.BytesIO(image_data)).convert('RGB')
273
+
274
+ # Process with default model (oasis500m)
275
+ predictions = process_image_with_model(image, "oasis500m")
276
+
277
+ # Return simplified format for Gradio
278
+ return {
279
+ "predictions": predictions[:3], # Top 3 predictions
280
+ "model_used": "oasis500m"
281
+ }
282
+
283
+ except Exception as e:
284
+ logger.error(f"Predict error: {e}")
285
+ raise HTTPException(status_code=500, detail=str(e))
hf_client.py ADDED
@@ -0,0 +1,197 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """
3
+ Client for testing the ChatGPT Oasis Model Inference API deployed on Hugging Face Spaces
4
+ """
5
+
6
+ import requests
7
+ import base64
8
+ import json
9
+ from PIL import Image
10
+ import io
11
+ import os
12
+ import time
13
+
14
+ class HuggingFaceSpacesClient:
15
+ def __init__(self, space_url):
16
+ """
17
+ Initialize the client with your Hugging Face Space URL
18
+
19
+ Args:
20
+ space_url (str): Your Space URL (e.g., "https://your-username-chatgpt-oasis.hf.space")
21
+ """
22
+ self.base_url = space_url.rstrip('/')
23
+
24
+ def health_check(self):
25
+ """Check if the API is healthy and models are loaded"""
26
+ try:
27
+ response = requests.get(f"{self.base_url}/health", timeout=30)
28
+ print(f"Health Check Status: {response.status_code}")
29
+ print(f"Response: {json.dumps(response.json(), indent=2)}")
30
+ return response.status_code == 200
31
+ except Exception as e:
32
+ print(f"Health check error: {e}")
33
+ return False
34
+
35
+ def list_models(self):
36
+ """Get information about available models"""
37
+ try:
38
+ response = requests.get(f"{self.base_url}/models", timeout=30)
39
+ print(f"Models Status: {response.status_code}")
40
+ print(f"Available Models: {json.dumps(response.json(), indent=2)}")
41
+ return response.json()
42
+ except Exception as e:
43
+ print(f"Models list error: {e}")
44
+ return None
45
+
46
+ def predict_file_upload(self, image_path, model_name="oasis500m"):
47
+ """
48
+ Predict using file upload
49
+
50
+ Args:
51
+ image_path (str): Path to the image file
52
+ model_name (str): Model to use ("oasis500m" or "vit-l-20")
53
+ """
54
+ if not os.path.exists(image_path):
55
+ print(f"Image file not found: {image_path}")
56
+ return None
57
+
58
+ try:
59
+ with open(image_path, 'rb') as f:
60
+ files = {'file': (os.path.basename(image_path), f, 'image/jpeg')}
61
+ data = {'model_name': model_name}
62
+
63
+ print(f"Uploading {image_path} to {model_name}...")
64
+ response = requests.post(
65
+ f"{self.base_url}/upload_inference",
66
+ files=files,
67
+ data=data,
68
+ timeout=120
69
+ )
70
+
71
+ print(f"Status: {response.status_code}")
72
+ if response.status_code == 200:
73
+ result = response.json()
74
+ print(f"Model used: {result['model_used']}")
75
+ print("Top 3 predictions:")
76
+ for i, pred in enumerate(result['predictions'][:3]):
77
+ print(f" {i+1}. {pred['label']} ({pred['confidence']:.3f})")
78
+ return result
79
+ else:
80
+ print(f"Error: {response.text}")
81
+ return None
82
+
83
+ except Exception as e:
84
+ print(f"File upload prediction error: {e}")
85
+ return None
86
+
87
+ def predict_base64(self, image_path, model_name="oasis500m"):
88
+ """
89
+ Predict using base64 encoded image
90
+
91
+ Args:
92
+ image_path (str): Path to the image file
93
+ model_name (str): Model to use ("oasis500m" or "vit-l-20")
94
+ """
95
+ if not os.path.exists(image_path):
96
+ print(f"Image file not found: {image_path}")
97
+ return None
98
+
99
+ try:
100
+ # Load and encode image
101
+ image = Image.open(image_path)
102
+ buffer = io.BytesIO()
103
+ image.save(buffer, format="JPEG")
104
+ image_base64 = base64.b64encode(buffer.getvalue()).decode()
105
+
106
+ print(f"Encoding {image_path} and sending to {model_name}...")
107
+ response = requests.post(
108
+ f"{self.base_url}/inference",
109
+ json={
110
+ "image": image_base64,
111
+ "model_name": model_name
112
+ },
113
+ headers={"Content-Type": "application/json"},
114
+ timeout=120
115
+ )
116
+
117
+ print(f"Status: {response.status_code}")
118
+ if response.status_code == 200:
119
+ result = response.json()
120
+ print(f"Model used: {result['model_used']}")
121
+ print("Top 3 predictions:")
122
+ for i, pred in enumerate(result['predictions'][:3]):
123
+ print(f" {i+1}. {pred['label']} ({pred['confidence']:.3f})")
124
+ return result
125
+ else:
126
+ print(f"Error: {response.text}")
127
+ return None
128
+
129
+ except Exception as e:
130
+ print(f"Base64 prediction error: {e}")
131
+ return None
132
+
133
+ def create_test_image(self, output_path="test_image.jpg"):
134
+ """Create a simple test image for testing"""
135
+ # Create a simple colored rectangle
136
+ img = Image.new('RGB', (224, 224), color='red')
137
+ img.save(output_path, format='JPEG')
138
+ print(f"Test image created: {output_path}")
139
+ return output_path
140
+
141
+ def test_all_endpoints(self, image_path=None):
142
+ """Test all endpoints with a given image or create a test image"""
143
+ print("=" * 60)
144
+ print("ChatGPT Oasis Model Inference API - Hugging Face Spaces Test")
145
+ print("=" * 60)
146
+
147
+ # Test health check
148
+ print("\n1. Testing health check...")
149
+ if not self.health_check():
150
+ print("❌ Health check failed. Make sure your Space is running!")
151
+ return
152
+
153
+ # Test models list
154
+ print("\n2. Testing models list...")
155
+ self.list_models()
156
+
157
+ # Use provided image or create test image
158
+ if image_path is None:
159
+ print("\n3. Creating test image...")
160
+ image_path = self.create_test_image()
161
+ else:
162
+ print(f"\n3. Using provided image: {image_path}")
163
+
164
+ # Test both models with file upload
165
+ print("\n4. Testing file upload inference...")
166
+ for model_name in ["oasis500m", "vit-l-20"]:
167
+ print(f"\n--- Testing {model_name} with file upload ---")
168
+ self.predict_file_upload(image_path, model_name)
169
+ time.sleep(2) # Small delay between requests
170
+
171
+ # Test both models with base64
172
+ print("\n5. Testing base64 inference...")
173
+ for model_name in ["oasis500m", "vit-l-20"]:
174
+ print(f"\n--- Testing {model_name} with base64 ---")
175
+ self.predict_base64(image_path, model_name)
176
+ time.sleep(2) # Small delay between requests
177
+
178
+ print("\n" + "=" * 60)
179
+ print("✅ Test completed!")
180
+
181
+ def main():
182
+ """Main function to run the test client"""
183
+
184
+ # Replace with your actual Hugging Face Space URL
185
+ SPACE_URL = "https://your-username-chatgpt-oasis.hf.space"
186
+
187
+ # Initialize client
188
+ client = HuggingFaceSpacesClient(SPACE_URL)
189
+
190
+ # Test with a specific image if provided
191
+ test_image = None # Change this to a path like "your_image.jpg" if you have one
192
+
193
+ # Run all tests
194
+ client.test_all_endpoints(test_image)
195
+
196
+ if __name__ == "__main__":
197
+ main()
main.py ADDED
@@ -0,0 +1,221 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import FastAPI, File, UploadFile, HTTPException
2
+ from fastapi.responses import JSONResponse
3
+ from pydantic import BaseModel
4
+ import torch
5
+ import torch.nn.functional as F
6
+ from transformers import AutoImageProcessor, AutoModelForImageClassification
7
+ from PIL import Image
8
+ import io
9
+ import numpy as np
10
+ from typing import List, Dict, Any
11
+ import logging
12
+
13
+ # Configure logging
14
+ logging.basicConfig(level=logging.INFO)
15
+ logger = logging.getLogger(__name__)
16
+
17
+ app = FastAPI(
18
+ title="ChatGPT Oasis Model Inference API",
19
+ description="FastAPI inference server for Oasis and ViT models",
20
+ version="1.0.0"
21
+ )
22
+
23
+ # Global variables to store loaded models
24
+ oasis_model = None
25
+ oasis_processor = None
26
+ vit_model = None
27
+ vit_processor = None
28
+
29
+ class InferenceRequest(BaseModel):
30
+ image: str # Base64 encoded image
31
+ model_name: str = "oasis500m" # Default to oasis model
32
+
33
+ class InferenceResponse(BaseModel):
34
+ predictions: List[Dict[str, Any]]
35
+ model_used: str
36
+ confidence_scores: List[float]
37
+
38
+ def load_models():
39
+ """Load both models into memory"""
40
+ global oasis_model, oasis_processor, vit_model, vit_processor
41
+
42
+ try:
43
+ logger.info("Loading Oasis 500M model...")
44
+ # Load Oasis model
45
+ oasis_processor = AutoImageProcessor.from_pretrained("microsoft/oasis-500m")
46
+ oasis_model = AutoModelForImageClassification.from_pretrained("microsoft/oasis-500m")
47
+ oasis_model.eval()
48
+
49
+ logger.info("Loading ViT-L-20 model...")
50
+ # Load ViT model
51
+ vit_processor = AutoImageProcessor.from_pretrained("google/vit-large-patch16-224")
52
+ vit_model = AutoModelForImageClassification.from_pretrained("google/vit-large-patch16-224")
53
+ vit_model.eval()
54
+
55
+ logger.info("All models loaded successfully!")
56
+
57
+ except Exception as e:
58
+ logger.error(f"Error loading models: {e}")
59
+ raise e
60
+
61
+ @app.on_event("startup")
62
+ async def startup_event():
63
+ """Load models when the application starts"""
64
+ load_models()
65
+
66
+ @app.get("/")
67
+ async def root():
68
+ """Root endpoint with API information"""
69
+ return {
70
+ "message": "ChatGPT Oasis Model Inference API",
71
+ "version": "1.0.0",
72
+ "available_models": ["oasis500m", "vit-l-20"],
73
+ "endpoints": {
74
+ "health": "/health",
75
+ "inference": "/inference",
76
+ "upload_inference": "/upload_inference"
77
+ }
78
+ }
79
+
80
+ @app.get("/health")
81
+ async def health_check():
82
+ """Health check endpoint"""
83
+ models_status = {
84
+ "oasis500m": oasis_model is not None,
85
+ "vit-l-20": vit_model is not None
86
+ }
87
+
88
+ return {
89
+ "status": "healthy",
90
+ "models_loaded": models_status
91
+ }
92
+
93
+ def process_image_with_model(image: Image.Image, model_name: str):
94
+ """Process image with the specified model"""
95
+ if model_name == "oasis500m":
96
+ if oasis_model is None or oasis_processor is None:
97
+ raise HTTPException(status_code=500, detail="Oasis model not loaded")
98
+
99
+ inputs = oasis_processor(images=image, return_tensors="pt")
100
+ with torch.no_grad():
101
+ outputs = oasis_model(**inputs)
102
+ logits = outputs.logits
103
+ probabilities = F.softmax(logits, dim=-1)
104
+
105
+ # Get top predictions
106
+ top_probs, top_indices = torch.topk(probabilities, 5)
107
+
108
+ predictions = []
109
+ for i in range(top_indices.shape[1]):
110
+ pred = {
111
+ "label": oasis_model.config.id2label[top_indices[0][i].item()],
112
+ "confidence": top_probs[0][i].item()
113
+ }
114
+ predictions.append(pred)
115
+
116
+ return predictions
117
+
118
+ elif model_name == "vit-l-20":
119
+ if vit_model is None or vit_processor is None:
120
+ raise HTTPException(status_code=500, detail="ViT model not loaded")
121
+
122
+ inputs = vit_processor(images=image, return_tensors="pt")
123
+ with torch.no_grad():
124
+ outputs = vit_model(**inputs)
125
+ logits = outputs.logits
126
+ probabilities = F.softmax(logits, dim=-1)
127
+
128
+ # Get top predictions
129
+ top_probs, top_indices = torch.topk(probabilities, 5)
130
+
131
+ predictions = []
132
+ for i in range(top_indices.shape[1]):
133
+ pred = {
134
+ "label": vit_model.config.id2label[top_indices[0][i].item()],
135
+ "confidence": top_probs[0][i].item()
136
+ }
137
+ predictions.append(pred)
138
+
139
+ return predictions
140
+
141
+ else:
142
+ raise HTTPException(status_code=400, detail=f"Unknown model: {model_name}")
143
+
144
+ @app.post("/inference", response_model=InferenceResponse)
145
+ async def inference(request: InferenceRequest):
146
+ """Inference endpoint using base64 encoded image"""
147
+ try:
148
+ import base64
149
+
150
+ # Decode base64 image
151
+ image_data = base64.b64decode(request.image)
152
+ image = Image.open(io.BytesIO(image_data)).convert('RGB')
153
+
154
+ # Process with model
155
+ predictions = process_image_with_model(image, request.model_name)
156
+
157
+ # Extract confidence scores
158
+ confidence_scores = [pred["confidence"] for pred in predictions]
159
+
160
+ return InferenceResponse(
161
+ predictions=predictions,
162
+ model_used=request.model_name,
163
+ confidence_scores=confidence_scores
164
+ )
165
+
166
+ except Exception as e:
167
+ logger.error(f"Inference error: {e}")
168
+ raise HTTPException(status_code=500, detail=str(e))
169
+
170
+ @app.post("/upload_inference", response_model=InferenceResponse)
171
+ async def upload_inference(
172
+ file: UploadFile = File(...),
173
+ model_name: str = "oasis500m"
174
+ ):
175
+ """Inference endpoint using file upload"""
176
+ try:
177
+ # Validate file type
178
+ if not file.content_type.startswith('image/'):
179
+ raise HTTPException(status_code=400, detail="File must be an image")
180
+
181
+ # Read and process image
182
+ image_data = await file.read()
183
+ image = Image.open(io.BytesIO(image_data)).convert('RGB')
184
+
185
+ # Process with model
186
+ predictions = process_image_with_model(image, model_name)
187
+
188
+ # Extract confidence scores
189
+ confidence_scores = [pred["confidence"] for pred in predictions]
190
+
191
+ return InferenceResponse(
192
+ predictions=predictions,
193
+ model_used=model_name,
194
+ confidence_scores=confidence_scores
195
+ )
196
+
197
+ except Exception as e:
198
+ logger.error(f"Upload inference error: {e}")
199
+ raise HTTPException(status_code=500, detail=str(e))
200
+
201
+ @app.get("/models")
202
+ async def list_models():
203
+ """List available models and their status"""
204
+ return {
205
+ "available_models": [
206
+ {
207
+ "name": "oasis500m",
208
+ "description": "Oasis 500M vision model",
209
+ "loaded": oasis_model is not None
210
+ },
211
+ {
212
+ "name": "vit-l-20",
213
+ "description": "Vision Transformer Large model",
214
+ "loaded": vit_model is not None
215
+ }
216
+ ]
217
+ }
218
+
219
+ if __name__ == "__main__":
220
+ import uvicorn
221
+ uvicorn.run(app, host="0.0.0.0", port=8000)
requirements.txt ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ fastapi==0.104.1
2
+ uvicorn[standard]==0.24.0
3
+ torch==2.1.0
4
+ torchvision==0.16.0
5
+ transformers==4.35.0
6
+ safetensors==0.4.0
7
+ Pillow==10.0.1
8
+ python-multipart==0.0.6
9
+ numpy==1.24.3
10
+ pydantic==2.5.0
start_server.py ADDED
@@ -0,0 +1,47 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """
3
+ Startup script for the ChatGPT Oasis Model Inference API
4
+ """
5
+
6
+ import uvicorn
7
+ import argparse
8
+ import os
9
+ import sys
10
+
11
+ def main():
12
+ parser = argparse.ArgumentParser(description="Start the ChatGPT Oasis Model Inference API")
13
+ parser.add_argument("--host", default="0.0.0.0", help="Host to bind to (default: 0.0.0.0)")
14
+ parser.add_argument("--port", type=int, default=8000, help="Port to bind to (default: 8000)")
15
+ parser.add_argument("--reload", action="store_true", help="Enable auto-reload for development")
16
+ parser.add_argument("--workers", type=int, default=1, help="Number of worker processes (default: 1)")
17
+ parser.add_argument("--log-level", default="info", choices=["debug", "info", "warning", "error"],
18
+ help="Log level (default: info)")
19
+
20
+ args = parser.parse_args()
21
+
22
+ print("Starting ChatGPT Oasis Model Inference API...")
23
+ print(f"Host: {args.host}")
24
+ print(f"Port: {args.port}")
25
+ print(f"Workers: {args.workers}")
26
+ print(f"Log Level: {args.log_level}")
27
+ print(f"Auto-reload: {args.reload}")
28
+ print("-" * 50)
29
+
30
+ # Check if main.py exists
31
+ if not os.path.exists("main.py"):
32
+ print("Error: main.py not found in current directory!")
33
+ sys.exit(1)
34
+
35
+ # Start the server
36
+ uvicorn.run(
37
+ "main:app",
38
+ host=args.host,
39
+ port=args.port,
40
+ reload=args.reload,
41
+ workers=args.workers,
42
+ log_level=args.log_level,
43
+ access_log=True
44
+ )
45
+
46
+ if __name__ == "__main__":
47
+ main()
test_client.py ADDED
@@ -0,0 +1,170 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """
3
+ Test client for the ChatGPT Oasis Model Inference API
4
+ """
5
+
6
+ import requests
7
+ import base64
8
+ import json
9
+ from PIL import Image
10
+ import io
11
+ import os
12
+
13
+ # API base URL
14
+ BASE_URL = "http://localhost:8000"
15
+
16
+ def test_health_check():
17
+ """Test the health check endpoint"""
18
+ print("Testing health check...")
19
+ try:
20
+ response = requests.get(f"{BASE_URL}/health")
21
+ print(f"Status: {response.status_code}")
22
+ print(f"Response: {json.dumps(response.json(), indent=2)}")
23
+ return response.status_code == 200
24
+ except Exception as e:
25
+ print(f"Error: {e}")
26
+ return False
27
+
28
+ def test_list_models():
29
+ """Test the models list endpoint"""
30
+ print("\nTesting models list...")
31
+ try:
32
+ response = requests.get(f"{BASE_URL}/models")
33
+ print(f"Status: {response.status_code}")
34
+ print(f"Response: {json.dumps(response.json(), indent=2)}")
35
+ return response.status_code == 200
36
+ except Exception as e:
37
+ print(f"Error: {e}")
38
+ return False
39
+
40
+ def create_test_image():
41
+ """Create a simple test image"""
42
+ # Create a simple colored rectangle
43
+ img = Image.new('RGB', (224, 224), color='red')
44
+
45
+ # Save to bytes
46
+ buffer = io.BytesIO()
47
+ img.save(buffer, format='JPEG')
48
+ buffer.seek(0)
49
+
50
+ return buffer.getvalue()
51
+
52
+ def test_base64_inference():
53
+ """Test inference with base64 encoded image"""
54
+ print("\nTesting base64 inference...")
55
+
56
+ # Create test image
57
+ image_data = create_test_image()
58
+ image_base64 = base64.b64encode(image_data).decode()
59
+
60
+ # Test both models
61
+ for model_name in ["oasis500m", "vit-l-20"]:
62
+ print(f"\nTesting {model_name}...")
63
+ try:
64
+ response = requests.post(
65
+ f"{BASE_URL}/inference",
66
+ json={
67
+ "image": image_base64,
68
+ "model_name": model_name
69
+ },
70
+ headers={"Content-Type": "application/json"}
71
+ )
72
+ print(f"Status: {response.status_code}")
73
+ if response.status_code == 200:
74
+ result = response.json()
75
+ print(f"Model used: {result['model_used']}")
76
+ print(f"Top prediction: {result['predictions'][0]}")
77
+ else:
78
+ print(f"Error: {response.text}")
79
+ except Exception as e:
80
+ print(f"Error: {e}")
81
+
82
+ def test_file_upload_inference():
83
+ """Test inference with file upload"""
84
+ print("\nTesting file upload inference...")
85
+
86
+ # Create test image
87
+ image_data = create_test_image()
88
+
89
+ # Test both models
90
+ for model_name in ["oasis500m", "vit-l-20"]:
91
+ print(f"\nTesting {model_name} with file upload...")
92
+ try:
93
+ files = {'file': ('test_image.jpg', image_data, 'image/jpeg')}
94
+ data = {'model_name': model_name}
95
+
96
+ response = requests.post(
97
+ f"{BASE_URL}/upload_inference",
98
+ files=files,
99
+ data=data
100
+ )
101
+ print(f"Status: {response.status_code}")
102
+ if response.status_code == 200:
103
+ result = response.json()
104
+ print(f"Model used: {result['model_used']}")
105
+ print(f"Top prediction: {result['predictions'][0]}")
106
+ else:
107
+ print(f"Error: {response.text}")
108
+ except Exception as e:
109
+ print(f"Error: {e}")
110
+
111
+ def test_with_real_image(image_path):
112
+ """Test with a real image file"""
113
+ if not os.path.exists(image_path):
114
+ print(f"Image file not found: {image_path}")
115
+ return
116
+
117
+ print(f"\nTesting with real image: {image_path}")
118
+
119
+ # Test file upload
120
+ try:
121
+ with open(image_path, 'rb') as f:
122
+ files = {'file': (os.path.basename(image_path), f, 'image/jpeg')}
123
+ data = {'model_name': 'oasis500m'}
124
+
125
+ response = requests.post(
126
+ f"{BASE_URL}/upload_inference",
127
+ files=files,
128
+ data=data
129
+ )
130
+ print(f"Status: {response.status_code}")
131
+ if response.status_code == 200:
132
+ result = response.json()
133
+ print(f"Model used: {result['model_used']}")
134
+ print("Top 3 predictions:")
135
+ for i, pred in enumerate(result['predictions'][:3]):
136
+ print(f" {i+1}. {pred['label']} ({pred['confidence']:.3f})")
137
+ else:
138
+ print(f"Error: {response.text}")
139
+ except Exception as e:
140
+ print(f"Error: {e}")
141
+
142
+ def main():
143
+ """Run all tests"""
144
+ print("ChatGPT Oasis Model Inference API - Test Client")
145
+ print("=" * 50)
146
+
147
+ # Test basic endpoints
148
+ health_ok = test_health_check()
149
+ models_ok = test_list_models()
150
+
151
+ if not health_ok:
152
+ print("Health check failed. Make sure the server is running!")
153
+ return
154
+
155
+ # Test inference endpoints
156
+ test_base64_inference()
157
+ test_file_upload_inference()
158
+
159
+ # Test with real image if available
160
+ test_images = ["test.jpg", "sample.jpg", "image.jpg"]
161
+ for img in test_images:
162
+ if os.path.exists(img):
163
+ test_with_real_image(img)
164
+ break
165
+
166
+ print("\n" + "=" * 50)
167
+ print("Test completed!")
168
+
169
+ if __name__ == "__main__":
170
+ main()