doniramdani820 commited on
Commit
a891b12
·
verified ·
1 Parent(s): 603a5b3

Upload 6 files

Browse files
Files changed (4) hide show
  1. Dockerfile +7 -2
  2. SPACE_CONFIG.md +188 -0
  3. app.py +57 -9
  4. requirements.txt +5 -5
Dockerfile CHANGED
@@ -3,14 +3,17 @@
3
 
4
  FROM python:3.11-slim as base
5
 
6
- # Install system dependencies yang diperlukan (minimal)
7
  RUN apt-get update && apt-get install -y \
 
8
  libglib2.0-0 \
9
  libsm6 \
10
  libxext6 \
11
  libxrender-dev \
12
  libgomp1 \
13
  libglib2.0-0 \
 
 
14
  && rm -rf /var/lib/apt/lists/* \
15
  && apt-get clean
16
 
@@ -28,13 +31,15 @@ RUN pip install --no-cache-dir --upgrade pip && \
28
  # Copy aplikasi
29
  COPY . .
30
 
31
- # Set environment variables untuk optimasi
32
  ENV PYTHONUNBUFFERED=1
33
  ENV PYTHONDONTWRITEBYTECODE=1
34
  ENV OMP_NUM_THREADS=2
35
  ENV MKL_NUM_THREADS=2
36
  ENV OPENBLAS_NUM_THREADS=2
37
  ENV NUMEXPR_NUM_THREADS=2
 
 
38
 
39
  # Expose port
40
  EXPOSE 7860
 
3
 
4
  FROM python:3.11-slim as base
5
 
6
+ # Install system dependencies yang diperlukan (minimal) + fix untuk ONNX Runtime
7
  RUN apt-get update && apt-get install -y \
8
+ curl \
9
  libglib2.0-0 \
10
  libsm6 \
11
  libxext6 \
12
  libxrender-dev \
13
  libgomp1 \
14
  libglib2.0-0 \
15
+ libgl1-mesa-glx \
16
+ libgthread-2.0-0 \
17
  && rm -rf /var/lib/apt/lists/* \
18
  && apt-get clean
19
 
 
31
  # Copy aplikasi
32
  COPY . .
33
 
34
+ # Set environment variables untuk optimasi + ONNX Runtime fix
35
  ENV PYTHONUNBUFFERED=1
36
  ENV PYTHONDONTWRITEBYTECODE=1
37
  ENV OMP_NUM_THREADS=2
38
  ENV MKL_NUM_THREADS=2
39
  ENV OPENBLAS_NUM_THREADS=2
40
  ENV NUMEXPR_NUM_THREADS=2
41
+ ENV ORT_DISABLE_ALL_OPTIMIZATION=1
42
+ ENV ONNXRUNTIME_LOG_SEVERITY_LEVEL=3
43
 
44
  # Expose port
45
  EXPOSE 7860
SPACE_CONFIG.md ADDED
@@ -0,0 +1,188 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # 🔧 Hugging Face Spaces Configuration
2
+
3
+ ## YAML Front Matter Configuration
4
+
5
+ File `README.md` harus dimulai dengan YAML front matter configuration:
6
+
7
+ ```yaml
8
+ ---
9
+ title: FunCaptcha Solver API
10
+ emoji: 🧩
11
+ colorFrom: blue
12
+ colorTo: purple
13
+ sdk: docker
14
+ pinned: false
15
+ suggested_hardware: cpu-basic
16
+ app_file: app.py
17
+ ---
18
+ ```
19
+
20
+ ## 📋 Configuration Options
21
+
22
+ ### **Required Fields**
23
+
24
+ | Field | Value | Description |
25
+ |---|---|---|
26
+ | `sdk` | `docker` | **CRITICAL**: Must be "docker" for Docker-based spaces |
27
+ | `title` | `FunCaptcha Solver API` | Display name di HF Spaces |
28
+
29
+ ### **Optional Fields**
30
+
31
+ | Field | Default Value | Description | Options |
32
+ |---|---|---|---|
33
+ | `emoji` | `🧩` | Icon untuk space | Any emoji |
34
+ | `colorFrom` | `blue` | Gradient start color | blue, red, green, yellow, etc. |
35
+ | `colorTo` | `purple` | Gradient end color | purple, pink, orange, etc. |
36
+ | `pinned` | `false` | Pin space di profile | `true` / `false` |
37
+ | `app_file` | `app.py` | Main application file | Any Python file |
38
+ | `suggested_hardware` | `cpu-basic` | Hardware suggestion | See below |
39
+
40
+ ### **Hardware Options**
41
+
42
+ | Hardware | Description | Use Case |
43
+ |---|---|---|
44
+ | `cpu-basic` | **2 vCPU, 16GB RAM** | ✅ **Recommended untuk FunCaptcha** |
45
+ | `cpu-upgrade` | 8 vCPU, 32GB RAM | Heavy ML workloads |
46
+ | `t4-small` | GPU T4, 15GB VRAM | GPU-accelerated inference |
47
+ | `t4-medium` | GPU T4, 60GB RAM | Large GPU models |
48
+
49
+ > 💡 **Tip**: `cpu-basic` sudah cukup untuk FunCaptcha solver dengan optimasi yang sudah diterapkan.
50
+
51
+ ## 🚨 Common Configuration Errors
52
+
53
+ ### **Error: "Missing configuration in README"**
54
+
55
+ **Cause**: README.md tidak dimulai dengan YAML front matter
56
+
57
+ **Solution**:
58
+ ```yaml
59
+ # ❌ WRONG - Missing YAML front matter
60
+ # FunCaptcha Solver API
61
+
62
+ # ✅ CORRECT - With YAML front matter
63
+ ---
64
+ title: FunCaptcha Solver API
65
+ emoji: 🧩
66
+ sdk: docker
67
+ ---
68
+
69
+ # FunCaptcha Solver API
70
+ ```
71
+
72
+ ### **Error: "Invalid SDK configuration"**
73
+
74
+ **Cause**: `sdk` field salah atau missing
75
+
76
+ **Solution**:
77
+ ```yaml
78
+ # ❌ WRONG
79
+ sdk: python
80
+ # or missing sdk field
81
+
82
+ # ✅ CORRECT
83
+ sdk: docker
84
+ ```
85
+
86
+ ### **Error: "Space fails to start"**
87
+
88
+ **Possible causes & solutions**:
89
+
90
+ 1. **Dockerfile issues**
91
+ - Check Dockerfile syntax
92
+ - Verify all dependencies installed
93
+ - Check port 7860 exposed
94
+
95
+ 2. **Missing model files**
96
+ - Upload `best.onnx` dan `data.yaml`
97
+ - Check file paths in app.py
98
+
99
+ 3. **Missing API key**
100
+ - Set `FUNCAPTCHA_API_KEY` di space secrets
101
+ - Verify secret name exactly matches
102
+
103
+ ## 🛠️ Customization Options
104
+
105
+ ### **Custom Title & Branding**
106
+
107
+ ```yaml
108
+ ---
109
+ title: Your Custom FunCaptcha API
110
+ emoji: 🤖
111
+ colorFrom: green
112
+ colorTo: blue
113
+ ---
114
+ ```
115
+
116
+ ### **Private Space**
117
+
118
+ Set space visibility to **Private** during creation (tidak bisa diubah via YAML).
119
+
120
+ ### **Custom App File**
121
+
122
+ Jika rename `app.py`:
123
+
124
+ ```yaml
125
+ ---
126
+ sdk: docker
127
+ app_file: main.py # Your custom filename
128
+ ---
129
+ ```
130
+
131
+ ### **Hardware Upgrade**
132
+
133
+ Untuk performa lebih tinggi:
134
+
135
+ ```yaml
136
+ ---
137
+ sdk: docker
138
+ suggested_hardware: cpu-upgrade # More powerful CPU
139
+ ---
140
+ ```
141
+
142
+ ## 🔍 Validation Checklist
143
+
144
+ Sebelum deploy, pastikan:
145
+
146
+ - [ ] README.md dimulai dengan `---`
147
+ - [ ] `sdk: docker` field present
148
+ - [ ] `title` field specified
149
+ - [ ] YAML format valid (no tabs, proper indentation)
150
+ - [ ] File ends dengan `---` dan newline
151
+ - [ ] No syntax errors dalam YAML
152
+
153
+ ## 🧪 Testing Configuration
154
+
155
+ ```bash
156
+ # Test YAML syntax locally
157
+ python -c "import yaml; yaml.safe_load(open('README.md').read().split('---')[1])"
158
+
159
+ # Check for required fields
160
+ grep -E "^(sdk|title):" README.md
161
+ ```
162
+
163
+ ## 📝 Template untuk Custom Spaces
164
+
165
+ ```yaml
166
+ ---
167
+ title: "Your App Name"
168
+ emoji: 🚀
169
+ colorFrom: blue
170
+ colorTo: purple
171
+ sdk: docker
172
+ pinned: false
173
+ suggested_hardware: cpu-basic
174
+ app_file: app.py
175
+ license: mit
176
+ short_description: "Brief description of your space"
177
+ ---
178
+
179
+ # Your App Name
180
+
181
+ Your app description here...
182
+ ```
183
+
184
+ ---
185
+
186
+ **⚠️ CRITICAL**: Tanpa proper YAML front matter, HF Spaces tidak akan recognize space sebagai Docker-based application dan akan fail untuk start!
187
+
188
+ **✅ Quick Fix**: Copy exact YAML header dari `README.md` yang sudah disediakan dalam deployment package.
app.py CHANGED
@@ -22,11 +22,21 @@ import logging
22
 
23
  import cv2
24
  import numpy as np
25
- import onnxruntime as ort
26
  from PIL import Image
27
  import yaml
28
  import difflib
29
 
 
 
 
 
 
 
 
 
 
 
 
30
  from fastapi import FastAPI, HTTPException, Depends, status
31
  from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
32
  from fastapi.middleware.cors import CORSMiddleware
@@ -124,6 +134,11 @@ class ModelManager:
124
  @staticmethod
125
  async def get_model(config_key: str) -> Optional[Dict[str, Any]]:
126
  """Load model dengan caching untuk efficiency"""
 
 
 
 
 
127
  if config_key not in LOADED_MODELS:
128
  logger.info(f"Loading model: {config_key}")
129
 
@@ -301,7 +316,17 @@ async def handle_pick_the_challenge(data: dict) -> dict:
301
 
302
  model_data = await ModelManager.get_model(config_key)
303
  if not model_data:
304
- return {'status': 'error', 'message': f'Model {config_key} tidak ditemukan'}
 
 
 
 
 
 
 
 
 
 
305
 
306
  try:
307
  # Decode image
@@ -418,7 +443,17 @@ async def handle_upright_challenge(data: dict) -> dict:
418
  model_data = await ModelManager.get_model('upright')
419
 
420
  if not model_data:
421
- return {'status': 'error', 'message': 'Model upright tidak ditemukan'}
 
 
 
 
 
 
 
 
 
 
422
 
423
  image_bytes = base64.b64decode(image_b64.split(',')[1])
424
  reconstructed_image_pil = Image.open(io.BytesIO(image_bytes))
@@ -505,11 +540,13 @@ async def root():
505
  async def health_check():
506
  """Health check endpoint"""
507
  return {
508
- "status": "healthy",
509
  "service": "FunCaptcha Solver",
 
510
  "models_loaded": len(LOADED_MODELS),
511
  "available_models": list(CONFIGS.keys()),
512
- "cache_entries": len(RESPONSE_CACHE)
 
513
  }
514
 
515
  @app.post("/solve", response_model=FunCaptchaResponse)
@@ -574,12 +611,23 @@ async def startup_event():
574
  logger.error(f"❌ API key error: {e}")
575
  raise e
576
 
577
- # Preload default model jika ada
578
- if os.path.exists('best.onnx') and os.path.exists('data.yaml'):
579
  logger.info("Preloading default model...")
580
- await ModelManager.get_model('default')
 
 
 
 
 
 
 
 
581
 
582
- logger.info("✅ FunCaptcha Solver API started successfully")
 
 
 
583
 
584
  @app.on_event("shutdown")
585
  async def shutdown_event():
 
22
 
23
  import cv2
24
  import numpy as np
 
25
  from PIL import Image
26
  import yaml
27
  import difflib
28
 
29
+ # Try to import ONNX Runtime with fallback handling
30
+ try:
31
+ import onnxruntime as ort
32
+ ONNX_AVAILABLE = True
33
+ print("✅ ONNX Runtime imported successfully")
34
+ except ImportError as e:
35
+ print(f"❌ ONNX Runtime import failed: {e}")
36
+ print("⚠️ Running without ONNX Runtime - model inference will be disabled")
37
+ ONNX_AVAILABLE = False
38
+ ort = None
39
+
40
  from fastapi import FastAPI, HTTPException, Depends, status
41
  from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
42
  from fastapi.middleware.cors import CORSMiddleware
 
134
  @staticmethod
135
  async def get_model(config_key: str) -> Optional[Dict[str, Any]]:
136
  """Load model dengan caching untuk efficiency"""
137
+ # Check if ONNX Runtime is available
138
+ if not ONNX_AVAILABLE:
139
+ logger.error("❌ ONNX Runtime not available - cannot load models")
140
+ return None
141
+
142
  if config_key not in LOADED_MODELS:
143
  logger.info(f"Loading model: {config_key}")
144
 
 
316
 
317
  model_data = await ModelManager.get_model(config_key)
318
  if not model_data:
319
+ if not ONNX_AVAILABLE:
320
+ return {
321
+ 'status': 'error',
322
+ 'message': 'ONNX Runtime not available - model inference disabled',
323
+ 'processing_time': (datetime.now() - start_time).total_seconds()
324
+ }
325
+ return {
326
+ 'status': 'error',
327
+ 'message': f'Model {config_key} tidak ditemukan',
328
+ 'processing_time': (datetime.now() - start_time).total_seconds()
329
+ }
330
 
331
  try:
332
  # Decode image
 
443
  model_data = await ModelManager.get_model('upright')
444
 
445
  if not model_data:
446
+ if not ONNX_AVAILABLE:
447
+ return {
448
+ 'status': 'error',
449
+ 'message': 'ONNX Runtime not available - model inference disabled',
450
+ 'processing_time': (datetime.now() - start_time).total_seconds()
451
+ }
452
+ return {
453
+ 'status': 'error',
454
+ 'message': 'Model upright tidak ditemukan',
455
+ 'processing_time': (datetime.now() - start_time).total_seconds()
456
+ }
457
 
458
  image_bytes = base64.b64decode(image_b64.split(',')[1])
459
  reconstructed_image_pil = Image.open(io.BytesIO(image_bytes))
 
540
  async def health_check():
541
  """Health check endpoint"""
542
  return {
543
+ "status": "healthy" if ONNX_AVAILABLE else "degraded",
544
  "service": "FunCaptcha Solver",
545
+ "onnx_runtime_available": ONNX_AVAILABLE,
546
  "models_loaded": len(LOADED_MODELS),
547
  "available_models": list(CONFIGS.keys()),
548
+ "cache_entries": len(RESPONSE_CACHE),
549
+ "warnings": [] if ONNX_AVAILABLE else ["ONNX Runtime not available - model inference disabled"]
550
  }
551
 
552
  @app.post("/solve", response_model=FunCaptchaResponse)
 
611
  logger.error(f"❌ API key error: {e}")
612
  raise e
613
 
614
+ # Preload default model jika ada dan ONNX Runtime available
615
+ if ONNX_AVAILABLE and os.path.exists('best.onnx') and os.path.exists('data.yaml'):
616
  logger.info("Preloading default model...")
617
+ try:
618
+ await ModelManager.get_model('default')
619
+ logger.info("✅ Default model preloaded successfully")
620
+ except Exception as e:
621
+ logger.warning(f"⚠️ Failed to preload default model: {e}")
622
+ elif not ONNX_AVAILABLE:
623
+ logger.warning("⚠️ ONNX Runtime not available - skipping model preload")
624
+ else:
625
+ logger.warning("⚠️ Model files (best.onnx, data.yaml) not found - upload them to enable solving")
626
 
627
+ if ONNX_AVAILABLE:
628
+ logger.info("✅ FunCaptcha Solver API started successfully with full functionality")
629
+ else:
630
+ logger.warning("⚠️ FunCaptcha Solver API started with limited functionality (ONNX Runtime unavailable)")
631
 
632
  @app.on_event("shutdown")
633
  async def shutdown_event():
requirements.txt CHANGED
@@ -5,11 +5,11 @@
5
  fastapi==0.104.1
6
  uvicorn[standard]==0.24.0
7
 
8
- # ML/AI dependencies - Versi stabil dan ringan
9
- onnxruntime==1.16.3
10
- opencv-python-headless==4.8.1.78
11
- numpy==1.24.4
12
- pillow==10.1.0
13
 
14
  # Utility libraries - Minimal yang diperlukan
15
  pyyaml==6.0.1
 
5
  fastapi==0.104.1
6
  uvicorn[standard]==0.24.0
7
 
8
+ # ML/AI dependencies - HF Spaces compatible versions (fixed executable stack issue)
9
+ onnxruntime==1.15.1
10
+ opencv-python-headless==4.8.0.76
11
+ numpy==1.24.3
12
+ pillow==10.0.1
13
 
14
  # Utility libraries - Minimal yang diperlukan
15
  pyyaml==6.0.1