vumichien commited on
Commit
d60f370
·
1 Parent(s): 30e908e

add permission

Browse files
Files changed (2) hide show
  1. Dockerfile +10 -6
  2. app.py +57 -18
Dockerfile CHANGED
@@ -8,6 +8,11 @@ RUN apt-get update && \
8
  build-essential \
9
  && rm -rf /var/lib/apt/lists/*
10
 
 
 
 
 
 
11
  # Copy requirements first to leverage Docker cache
12
  COPY requirements.txt .
13
  RUN pip install --no-cache-dir -r requirements.txt
@@ -16,12 +21,8 @@ RUN pip install --no-cache-dir -r requirements.txt
16
  COPY . .
17
 
18
  # Create upload directory with proper permissions
19
- RUN mkdir -p static/uploads && \
20
- chmod -R 777 static/uploads
21
-
22
- # Create metadata directory with proper permissions
23
- RUN mkdir -p static/metadata && \
24
- chmod -R 777 static/metadata
25
 
26
  # Set environment variables for Hugging Face
27
  ENV PYTHONUNBUFFERED=1
@@ -37,5 +38,8 @@ ENV ENV=production
37
  # Expose port for Hugging Face Spaces (uses port 7860)
38
  EXPOSE 7860
39
 
 
 
 
40
  # Run the application
41
  CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "7860"]
 
8
  build-essential \
9
  && rm -rf /var/lib/apt/lists/*
10
 
11
+ # Create a non-root user to run the application
12
+ RUN useradd -m appuser && \
13
+ mkdir -p /home/appuser/app /home/appuser/.cache && \
14
+ chown -R appuser:appuser /home/appuser
15
+
16
  # Copy requirements first to leverage Docker cache
17
  COPY requirements.txt .
18
  RUN pip install --no-cache-dir -r requirements.txt
 
21
  COPY . .
22
 
23
  # Create upload directory with proper permissions
24
+ RUN mkdir -p static/uploads static/metadata && \
25
+ chmod -R 777 static
 
 
 
 
26
 
27
  # Set environment variables for Hugging Face
28
  ENV PYTHONUNBUFFERED=1
 
38
  # Expose port for Hugging Face Spaces (uses port 7860)
39
  EXPOSE 7860
40
 
41
+ # Switch to the non-root user
42
+ # USER appuser
43
+
44
  # Run the application
45
  CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "7860"]
app.py CHANGED
@@ -19,6 +19,7 @@ import io
19
  from huggingface_hub import HfApi, HfFolder, create_repo
20
  from huggingface_hub.utils import RepositoryNotFoundError
21
  from huggingface_hub.hf_api import RepoFile
 
22
 
23
  # Create FastAPI app
24
  app = FastAPI(title="Image Uploader")
@@ -63,6 +64,13 @@ DATASET_REPO = os.environ.get("HF_DATASET_REPO", "image-uploader-data")
63
  IMAGES_PATH = "images"
64
  METADATA_PATH = "metadata"
65
 
 
 
 
 
 
 
 
66
  # Initialize HfApi
67
  hf_api = HfApi(token=HF_TOKEN)
68
 
@@ -71,22 +79,38 @@ def ensure_repo_exists():
71
  try:
72
  # Check if repo exists
73
  hf_api.repo_info(repo_id=f"{HF_USERNAME}/{DATASET_REPO}", repo_type="dataset")
 
74
  except RepositoryNotFoundError:
75
  # Create repo if it doesn't exist
76
- create_repo(f"{HF_USERNAME}/{DATASET_REPO}", repo_type="dataset", token=HF_TOKEN)
77
- # Initialize metadata
78
- metadata = json.dumps({})
79
- hf_api.upload_file(
80
- path_or_fileobj=io.BytesIO(metadata.encode()),
81
- path_in_repo=f"{METADATA_PATH}/image_metadata.json",
82
- repo_id=f"{HF_USERNAME}/{DATASET_REPO}",
83
- repo_type="dataset",
84
- token=HF_TOKEN
85
- )
 
 
 
 
 
 
 
86
 
87
  # Initialize repository if in production
88
  if os.environ.get("ENV", "development") == "production":
89
- ensure_repo_exists()
 
 
 
 
 
 
 
 
90
 
91
  def get_file_extension(filename: str) -> str:
92
  """Get the file extension from a filename."""
@@ -114,14 +138,17 @@ def verify_auth(request: Request):
114
  def get_image_metadata():
115
  """Get all image metadata including hashtags."""
116
  # In production, get metadata from Hugging Face
117
- if os.environ.get("ENV", "development") == "production" and HF_USERNAME:
118
  try:
 
119
  metadata_file = hf_api.hf_hub_download(
120
  repo_id=f"{HF_USERNAME}/{DATASET_REPO}",
121
  filename=f"{METADATA_PATH}/image_metadata.json",
122
  repo_type="dataset",
123
- token=HF_TOKEN
 
124
  )
 
125
  with open(metadata_file, "r") as f:
126
  return json.load(f)
127
  except Exception as e:
@@ -139,6 +166,7 @@ def save_image_metadata(metadata):
139
  # In production, save to Hugging Face
140
  if os.environ.get("ENV", "development") == "production" and HF_USERNAME and HF_TOKEN:
141
  try:
 
142
  metadata_str = json.dumps(metadata)
143
  hf_api.upload_file(
144
  path_or_fileobj=io.BytesIO(metadata_str.encode()),
@@ -147,12 +175,16 @@ def save_image_metadata(metadata):
147
  repo_type="dataset",
148
  token=HF_TOKEN
149
  )
 
150
  except Exception as e:
151
  print(f"Error saving metadata to Hugging Face: {e}")
152
-
153
- # Local development or fallback
154
- with open(METADATA_FILE, "w") as f:
155
- json.dump(metadata, f)
 
 
 
156
 
157
  def add_hashtags_to_image(filename, hashtags, original_filename=None):
158
  """Add hashtags to an image."""
@@ -182,6 +214,7 @@ def upload_to_hf(file_content, filename):
182
  """Upload a file to Hugging Face Dataset Repository."""
183
  if os.environ.get("ENV", "development") == "production" and HF_USERNAME and HF_TOKEN:
184
  try:
 
185
  hf_api.upload_file(
186
  path_or_fileobj=io.BytesIO(file_content),
187
  path_in_repo=f"{IMAGES_PATH}/{filename}",
@@ -189,6 +222,7 @@ def upload_to_hf(file_content, filename):
189
  repo_type="dataset",
190
  token=HF_TOKEN
191
  )
 
192
  return True
193
  except Exception as e:
194
  print(f"Error uploading to Hugging Face: {e}")
@@ -199,12 +233,14 @@ def delete_from_hf(filename):
199
  """Delete a file from Hugging Face Dataset Repository."""
200
  if os.environ.get("ENV", "development") == "production" and HF_USERNAME and HF_TOKEN:
201
  try:
 
202
  hf_api.delete_file(
203
  path_in_repo=f"{IMAGES_PATH}/{filename}",
204
  repo_id=f"{HF_USERNAME}/{DATASET_REPO}",
205
  repo_type="dataset",
206
  token=HF_TOKEN
207
  )
 
208
  return True
209
  except Exception as e:
210
  print(f"Error deleting from Hugging Face: {e}")
@@ -221,6 +257,7 @@ def list_hf_images():
221
  """List all images in the Hugging Face repo."""
222
  if os.environ.get("ENV", "development") == "production" and HF_USERNAME and HF_TOKEN:
223
  try:
 
224
  files = hf_api.list_repo_files(
225
  repo_id=f"{HF_USERNAME}/{DATASET_REPO}",
226
  repo_type="dataset",
@@ -228,7 +265,9 @@ def list_hf_images():
228
  )
229
  # Filter only image files in the images directory
230
  image_files = [f for f in files if f.startswith(f"{IMAGES_PATH}/")]
231
- return [os.path.basename(f) for f in image_files]
 
 
232
  except Exception as e:
233
  print(f"Error listing files from Hugging Face: {e}")
234
  return []
 
19
  from huggingface_hub import HfApi, HfFolder, create_repo
20
  from huggingface_hub.utils import RepositoryNotFoundError
21
  from huggingface_hub.hf_api import RepoFile
22
+ import tempfile
23
 
24
  # Create FastAPI app
25
  app = FastAPI(title="Image Uploader")
 
64
  IMAGES_PATH = "images"
65
  METADATA_PATH = "metadata"
66
 
67
+ # Set HF cache directory to a writable location
68
+ # This is necessary for Hugging Face Spaces which has permission issues with the default cache location
69
+ os.environ["HF_HOME"] = os.path.join(tempfile.gettempdir(), "huggingface")
70
+ os.environ["HUGGINGFACE_HUB_CACHE"] = os.path.join(tempfile.gettempdir(), "huggingface", "hub")
71
+ os.makedirs(os.environ["HF_HOME"], exist_ok=True)
72
+ os.makedirs(os.environ["HUGGINGFACE_HUB_CACHE"], exist_ok=True)
73
+
74
  # Initialize HfApi
75
  hf_api = HfApi(token=HF_TOKEN)
76
 
 
79
  try:
80
  # Check if repo exists
81
  hf_api.repo_info(repo_id=f"{HF_USERNAME}/{DATASET_REPO}", repo_type="dataset")
82
+ print(f"Repository {HF_USERNAME}/{DATASET_REPO} exists")
83
  except RepositoryNotFoundError:
84
  # Create repo if it doesn't exist
85
+ try:
86
+ print(f"Creating repository {HF_USERNAME}/{DATASET_REPO}")
87
+ create_repo(f"{HF_USERNAME}/{DATASET_REPO}", repo_type="dataset", token=HF_TOKEN)
88
+ # Initialize metadata
89
+ metadata = json.dumps({})
90
+ hf_api.upload_file(
91
+ path_or_fileobj=io.BytesIO(metadata.encode()),
92
+ path_in_repo=f"{METADATA_PATH}/image_metadata.json",
93
+ repo_id=f"{HF_USERNAME}/{DATASET_REPO}",
94
+ repo_type="dataset",
95
+ token=HF_TOKEN
96
+ )
97
+ print(f"Repository created and initialized")
98
+ except Exception as e:
99
+ print(f"Error creating repository: {e}")
100
+ except Exception as e:
101
+ print(f"Error checking repository: {e}")
102
 
103
  # Initialize repository if in production
104
  if os.environ.get("ENV", "development") == "production":
105
+ print("Running in production mode, checking Hugging Face repository...")
106
+ if HF_USERNAME and HF_TOKEN:
107
+ print(f"Using Hugging Face credentials for user: {HF_USERNAME}")
108
+ try:
109
+ ensure_repo_exists()
110
+ except Exception as e:
111
+ print(f"Error ensuring repository exists: {e}")
112
+ else:
113
+ print("Warning: HF_USERNAME or HF_TOKEN not set. Running without Hugging Face integration.")
114
 
115
  def get_file_extension(filename: str) -> str:
116
  """Get the file extension from a filename."""
 
138
  def get_image_metadata():
139
  """Get all image metadata including hashtags."""
140
  # In production, get metadata from Hugging Face
141
+ if os.environ.get("ENV", "development") == "production" and HF_USERNAME and HF_TOKEN:
142
  try:
143
+ print(f"Fetching metadata from Hugging Face repository {HF_USERNAME}/{DATASET_REPO}")
144
  metadata_file = hf_api.hf_hub_download(
145
  repo_id=f"{HF_USERNAME}/{DATASET_REPO}",
146
  filename=f"{METADATA_PATH}/image_metadata.json",
147
  repo_type="dataset",
148
+ token=HF_TOKEN,
149
+ local_dir=os.path.join(tempfile.gettempdir(), "hf_downloads")
150
  )
151
+ print(f"Metadata downloaded to {metadata_file}")
152
  with open(metadata_file, "r") as f:
153
  return json.load(f)
154
  except Exception as e:
 
166
  # In production, save to Hugging Face
167
  if os.environ.get("ENV", "development") == "production" and HF_USERNAME and HF_TOKEN:
168
  try:
169
+ print(f"Saving metadata to Hugging Face repository {HF_USERNAME}/{DATASET_REPO}")
170
  metadata_str = json.dumps(metadata)
171
  hf_api.upload_file(
172
  path_or_fileobj=io.BytesIO(metadata_str.encode()),
 
175
  repo_type="dataset",
176
  token=HF_TOKEN
177
  )
178
+ print(f"Metadata saved successfully")
179
  except Exception as e:
180
  print(f"Error saving metadata to Hugging Face: {e}")
181
+ # Still save locally as fallback
182
+ with open(METADATA_FILE, "w") as f:
183
+ json.dump(metadata, f)
184
+ else:
185
+ # Local development or fallback
186
+ with open(METADATA_FILE, "w") as f:
187
+ json.dump(metadata, f)
188
 
189
  def add_hashtags_to_image(filename, hashtags, original_filename=None):
190
  """Add hashtags to an image."""
 
214
  """Upload a file to Hugging Face Dataset Repository."""
215
  if os.environ.get("ENV", "development") == "production" and HF_USERNAME and HF_TOKEN:
216
  try:
217
+ print(f"Uploading file {filename} to Hugging Face repository {HF_USERNAME}/{DATASET_REPO}")
218
  hf_api.upload_file(
219
  path_or_fileobj=io.BytesIO(file_content),
220
  path_in_repo=f"{IMAGES_PATH}/{filename}",
 
222
  repo_type="dataset",
223
  token=HF_TOKEN
224
  )
225
+ print(f"File {filename} uploaded successfully")
226
  return True
227
  except Exception as e:
228
  print(f"Error uploading to Hugging Face: {e}")
 
233
  """Delete a file from Hugging Face Dataset Repository."""
234
  if os.environ.get("ENV", "development") == "production" and HF_USERNAME and HF_TOKEN:
235
  try:
236
+ print(f"Deleting file {filename} from Hugging Face repository {HF_USERNAME}/{DATASET_REPO}")
237
  hf_api.delete_file(
238
  path_in_repo=f"{IMAGES_PATH}/{filename}",
239
  repo_id=f"{HF_USERNAME}/{DATASET_REPO}",
240
  repo_type="dataset",
241
  token=HF_TOKEN
242
  )
243
+ print(f"File {filename} deleted successfully")
244
  return True
245
  except Exception as e:
246
  print(f"Error deleting from Hugging Face: {e}")
 
257
  """List all images in the Hugging Face repo."""
258
  if os.environ.get("ENV", "development") == "production" and HF_USERNAME and HF_TOKEN:
259
  try:
260
+ print(f"Listing files from Hugging Face repository {HF_USERNAME}/{DATASET_REPO}")
261
  files = hf_api.list_repo_files(
262
  repo_id=f"{HF_USERNAME}/{DATASET_REPO}",
263
  repo_type="dataset",
 
265
  )
266
  # Filter only image files in the images directory
267
  image_files = [f for f in files if f.startswith(f"{IMAGES_PATH}/")]
268
+ image_basenames = [os.path.basename(f) for f in image_files]
269
+ print(f"Found {len(image_basenames)} images")
270
+ return image_basenames
271
  except Exception as e:
272
  print(f"Error listing files from Hugging Face: {e}")
273
  return []