abiyyufahri commited on
Commit
f1199d3
·
1 Parent(s): 1c943af

Install error fix attemp 9

Browse files
Files changed (3) hide show
  1. Dockerfile +33 -16
  2. main.py +72 -47
  3. requirements.txt +18 -6
Dockerfile CHANGED
@@ -1,10 +1,12 @@
1
  FROM python:3.10-slim
2
 
 
3
  RUN apt-get update && apt-get install -y --no-install-recommends \
4
  git gcc g++ libglib2.0-0 libsm6 libxext6 libxrender-dev \
5
  build-essential curl && \
6
  rm -rf /var/lib/apt/lists/*
7
 
 
8
  RUN useradd -m -u 1000 user
9
  USER user
10
  ENV PATH="/home/user/.local/bin:$PATH"
@@ -14,35 +16,50 @@ WORKDIR /app
14
  # Copy requirements first for better caching
15
  COPY --chown=user requirements.txt ./
16
 
17
- # Install dependencies step by step
18
  RUN pip install --upgrade pip && \
19
- pip install --no-cache-dir packaging ninja wheel setuptools "numpy<2.0.0"
20
 
21
- # Install PyTorch CPU version
22
- RUN pip install --no-cache-dir torch==2.2.2+cpu torchvision torchaudio --index-url https://download.pytorch.org/whl/cpu
23
 
24
- # Install core dependencies
 
 
 
 
25
  RUN pip install --no-cache-dir \
26
- transformers \
27
  datasets \
28
  Pillow \
29
  accelerate \
30
- scipy \
31
- qwen-vl-utils \
 
 
32
  fastapi \
33
  "uvicorn[standard]"
34
 
35
- # Install GUI-Actor dependencies manually (skip flash-attn)
36
  RUN pip install --no-cache-dir \
37
- pre-commit \
38
- liger-kernel==0.5.2 \
39
- opencv-python-headless \
40
- deepspeed==0.16.0
41
 
42
  # Copy all application files
43
  COPY --chown=user . .
44
 
45
- # Ensure main.py exists and is readable
46
- RUN ls -la /app/ && cat /app/main.py | head -10
 
 
 
 
 
 
 
 
 
47
 
48
- CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "7860"]
 
1
  FROM python:3.10-slim
2
 
3
+ # Install system dependencies
4
  RUN apt-get update && apt-get install -y --no-install-recommends \
5
  git gcc g++ libglib2.0-0 libsm6 libxext6 libxrender-dev \
6
  build-essential curl && \
7
  rm -rf /var/lib/apt/lists/*
8
 
9
+ # Create user
10
  RUN useradd -m -u 1000 user
11
  USER user
12
  ENV PATH="/home/user/.local/bin:$PATH"
 
16
  # Copy requirements first for better caching
17
  COPY --chown=user requirements.txt ./
18
 
19
+ # Install dependencies with proper NumPy version
20
  RUN pip install --upgrade pip && \
21
+ pip install --no-cache-dir packaging ninja wheel setuptools
22
 
23
+ # Install NumPy 1.x to avoid compatibility issues
24
+ RUN pip install --no-cache-dir "numpy>=1.21.0,<2.0.0"
25
 
26
+ # Install PyTorch CPU version (compatible with NumPy 1.x)
27
+ RUN pip install --no-cache-dir torch==2.2.2+cpu torchvision==0.17.2+cpu torchaudio==2.2.2+cpu \
28
+ --index-url https://download.pytorch.org/whl/cpu
29
+
30
+ # Install transformers and related packages
31
  RUN pip install --no-cache-dir \
32
+ "transformers>=4.37.0" \
33
  datasets \
34
  Pillow \
35
  accelerate \
36
+ scipy
37
+
38
+ # Install FastAPI and related packages
39
+ RUN pip install --no-cache-dir \
40
  fastapi \
41
  "uvicorn[standard]"
42
 
43
+ # Install other dependencies (skip problematic ones)
44
  RUN pip install --no-cache-dir \
45
+ opencv-python-headless
46
+
47
+ # Try to install qwen-vl-utils (if it fails, continue)
48
+ RUN pip install --no-cache-dir qwen-vl-utils || echo "qwen-vl-utils installation failed, continuing..."
49
 
50
  # Copy all application files
51
  COPY --chown=user . .
52
 
53
+ # Set environment variables for better compatibility
54
+ ENV TRANSFORMERS_CACHE=/tmp/transformers_cache
55
+ ENV HF_HOME=/tmp/hf_home
56
+ ENV PYTHONUNBUFFERED=1
57
+
58
+ # Expose port
59
+ EXPOSE 7860
60
+
61
+ # Health check
62
+ HEALTHCHECK --interval=30s --timeout=30s --start-period=60s --retries=3 \
63
+ CMD curl -f http://localhost:7860/health || exit 1
64
 
65
+ CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "7860", "--timeout-keep-alive", "120"]
main.py CHANGED
@@ -1,4 +1,4 @@
1
- from fastapi import FastAPI, Form
2
  from fastapi.responses import JSONResponse
3
  from pydantic import BaseModel
4
  from PIL import Image
@@ -6,55 +6,75 @@ from io import BytesIO
6
  import base64
7
  import torch
8
  import re
 
 
 
9
 
10
- app = FastAPI(title="GUI-Actor API", version="1.0.0")
 
 
11
 
12
  # Initialize global variables
13
  model = None
14
  processor = None
15
  tokenizer = None
16
  model_name = "microsoft/GUI-Actor-2B-Qwen2-VL"
 
17
 
18
- def load_model():
19
  """Load model with proper error handling"""
20
- global model, processor, tokenizer
21
 
22
  try:
23
- print("Loading processor...")
24
- # Try different approaches to load the processor
25
- try:
26
- from transformers import Qwen2VLProcessor
27
- processor = Qwen2VLProcessor.from_pretrained(model_name)
28
- print("Successfully loaded Qwen2VLProcessor")
29
- except Exception as e:
30
- print(f"Failed to load Qwen2VLProcessor: {e}")
31
- from transformers import AutoProcessor
32
- processor = AutoProcessor.from_pretrained(model_name, trust_remote_code=True)
33
- print("Successfully loaded AutoProcessor")
34
 
35
- tokenizer = processor.tokenizer
 
36
 
37
- print("Loading model...")
38
- # Use the correct model class for Qwen2VL
39
- from transformers import Qwen2VLForConditionalGeneration
 
 
 
 
40
 
41
- model = Qwen2VLForConditionalGeneration.from_pretrained(
 
 
 
 
42
  model_name,
43
- torch_dtype=torch.float32, # float32 untuk CPU
44
- device_map=None, # CPU only
45
- trust_remote_code=True, # untuk custom model
46
- attn_implementation=None # skip flash attention
47
  ).eval()
48
 
49
- print("Model loaded successfully!")
 
50
  return True
51
 
52
  except Exception as e:
53
- print(f"Error loading model: {e}")
 
54
  return False
55
 
56
- # Load model at startup
57
- model_loaded = load_model()
 
 
 
 
 
 
 
 
 
 
 
 
 
58
 
59
  class Base64Request(BaseModel):
60
  image_base64: str
@@ -136,6 +156,7 @@ def cpu_inference(conversation, model, tokenizer, processor):
136
  }
137
 
138
  except Exception as e:
 
139
  return {
140
  "topk_points": [(0.5, 0.5)],
141
  "response": f"Error during inference: {str(e)}",
@@ -153,20 +174,26 @@ async def root():
153
  @app.post("/click/base64")
154
  async def predict_click_base64(data: Base64Request):
155
  if not model_loaded:
156
- return JSONResponse(
157
- content={
158
- "error": "Model not loaded properly",
159
- "success": False,
160
- "x": 0.5,
161
- "y": 0.5
162
- },
163
- status_code=503
164
  )
165
 
166
  try:
167
  # Decode base64 to image
168
- image_data = base64.b64decode(data.image_base64.split(",")[-1])
169
- pil_image = Image.open(BytesIO(image_data)).convert("RGB")
 
 
 
 
 
 
 
 
 
 
 
170
 
171
  conversation = [
172
  {
@@ -204,21 +231,19 @@ async def predict_click_base64(data: Base64Request):
204
  "success": pred["success"]
205
  })
206
 
 
 
207
  except Exception as e:
208
- return JSONResponse(
209
- content={
210
- "error": str(e),
211
- "success": False,
212
- "x": 0.5,
213
- "y": 0.5
214
- },
215
- status_code=500
216
  )
217
 
218
  @app.get("/health")
219
  async def health_check():
220
  return {
221
- "status": "healthy",
222
  "model": model_name,
223
  "device": "cpu",
224
  "torch_dtype": "float32",
 
1
+ from fastapi import FastAPI, Form, HTTPException
2
  from fastapi.responses import JSONResponse
3
  from pydantic import BaseModel
4
  from PIL import Image
 
6
  import base64
7
  import torch
8
  import re
9
+ import logging
10
+ import asyncio
11
+ from contextlib import asynccontextmanager
12
 
13
+ # Configure logging
14
+ logging.basicConfig(level=logging.INFO)
15
+ logger = logging.getLogger(__name__)
16
 
17
  # Initialize global variables
18
  model = None
19
  processor = None
20
  tokenizer = None
21
  model_name = "microsoft/GUI-Actor-2B-Qwen2-VL"
22
+ model_loaded = False
23
 
24
+ async def load_model():
25
  """Load model with proper error handling"""
26
+ global model, processor, tokenizer, model_loaded
27
 
28
  try:
29
+ logger.info("Starting model loading...")
 
 
 
 
 
 
 
 
 
 
30
 
31
+ # Import required modules
32
+ from transformers import AutoProcessor, AutoModelForCausalLM
33
 
34
+ logger.info("Loading processor...")
35
+ # Use AutoProcessor for better compatibility
36
+ processor = AutoProcessor.from_pretrained(
37
+ model_name,
38
+ trust_remote_code=True
39
+ )
40
+ logger.info("Processor loaded successfully")
41
 
42
+ tokenizer = processor.tokenizer
43
+
44
+ logger.info("Loading model...")
45
+ # Use AutoModelForCausalLM for better compatibility
46
+ model = AutoModelForCausalLM.from_pretrained(
47
  model_name,
48
+ torch_dtype=torch.float32,
49
+ device_map=None, # CPU only
50
+ trust_remote_code=True,
51
+ low_cpu_mem_usage=True # For better memory management
52
  ).eval()
53
 
54
+ logger.info("Model loaded successfully!")
55
+ model_loaded = True
56
  return True
57
 
58
  except Exception as e:
59
+ logger.error(f"Error loading model: {e}")
60
+ model_loaded = False
61
  return False
62
 
63
+ @asynccontextmanager
64
+ async def lifespan(app: FastAPI):
65
+ # Startup
66
+ logger.info("Starting up GUI-Actor API...")
67
+ await load_model()
68
+ yield
69
+ # Shutdown
70
+ logger.info("Shutting down GUI-Actor API...")
71
+
72
+ # Initialize FastAPI app with lifespan
73
+ app = FastAPI(
74
+ title="GUI-Actor API",
75
+ version="1.0.0",
76
+ lifespan=lifespan
77
+ )
78
 
79
  class Base64Request(BaseModel):
80
  image_base64: str
 
156
  }
157
 
158
  except Exception as e:
159
+ logger.error(f"Inference error: {e}")
160
  return {
161
  "topk_points": [(0.5, 0.5)],
162
  "response": f"Error during inference: {str(e)}",
 
174
  @app.post("/click/base64")
175
  async def predict_click_base64(data: Base64Request):
176
  if not model_loaded:
177
+ raise HTTPException(
178
+ status_code=503,
179
+ detail="Model not loaded properly"
 
 
 
 
 
180
  )
181
 
182
  try:
183
  # Decode base64 to image
184
+ try:
185
+ # Handle data URL format
186
+ if "," in data.image_base64:
187
+ image_data = base64.b64decode(data.image_base64.split(",")[-1])
188
+ else:
189
+ image_data = base64.b64decode(data.image_base64)
190
+ except Exception as e:
191
+ raise HTTPException(status_code=400, detail=f"Invalid base64 image: {e}")
192
+
193
+ try:
194
+ pil_image = Image.open(BytesIO(image_data)).convert("RGB")
195
+ except Exception as e:
196
+ raise HTTPException(status_code=400, detail=f"Invalid image format: {e}")
197
 
198
  conversation = [
199
  {
 
231
  "success": pred["success"]
232
  })
233
 
234
+ except HTTPException:
235
+ raise
236
  except Exception as e:
237
+ logger.error(f"Prediction error: {e}")
238
+ raise HTTPException(
239
+ status_code=500,
240
+ detail=f"Internal server error: {str(e)}"
 
 
 
 
241
  )
242
 
243
  @app.get("/health")
244
  async def health_check():
245
  return {
246
+ "status": "healthy" if model_loaded else "unhealthy",
247
  "model": model_name,
248
  "device": "cpu",
249
  "torch_dtype": "float32",
requirements.txt CHANGED
@@ -1,16 +1,28 @@
 
1
  packaging
2
  ninja
 
 
 
 
 
 
 
 
 
 
 
 
3
  fastapi
4
  uvicorn[standard]
 
 
5
  transformers>=4.37.0
6
  datasets
7
  Pillow
8
- # Fix NumPy compatibility issue
9
- numpy<2.0.0
10
- torch==2.2.2+cpu
11
- torchvision
12
- torchaudio
13
- --index-url https://download.pytorch.org/whl/cpu
14
  accelerate
15
  scipy
 
 
 
16
  qwen-vl-utils
 
1
+ # Core dependencies
2
  packaging
3
  ninja
4
+ wheel
5
+ setuptools
6
+
7
+ # NumPy version that's compatible with PyTorch and transformers
8
+ numpy>=1.21.0,<2.0.0
9
+
10
+ # PyTorch CPU version (will be installed via Dockerfile)
11
+ # torch==2.2.2+cpu
12
+ # torchvision==0.17.2+cpu
13
+ # torchaudio==2.2.2+cpu
14
+
15
+ # FastAPI and related
16
  fastapi
17
  uvicorn[standard]
18
+
19
+ # Transformers and ML dependencies
20
  transformers>=4.37.0
21
  datasets
22
  Pillow
 
 
 
 
 
 
23
  accelerate
24
  scipy
25
+
26
+ # Optional dependencies (install if available)
27
+ opencv-python-headless
28
  qwen-vl-utils