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

change upload file location

Browse files
Files changed (3) hide show
  1. Dockerfile +6 -3
  2. app.py +283 -49
  3. requirements.txt +2 -1
Dockerfile CHANGED
@@ -27,12 +27,15 @@ RUN mkdir -p static/metadata && \
27
  ENV PYTHONUNBUFFERED=1
28
  ENV HOST=0.0.0.0
29
  ENV PORT=7860
 
 
 
 
 
 
30
 
31
  # Expose port for Hugging Face Spaces (uses port 7860)
32
  EXPOSE 7860
33
 
34
- # Create volume mount points for persistent data
35
- VOLUME ["/app/static/uploads", "/app/static/metadata"]
36
-
37
  # Run the application
38
  CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "7860"]
 
27
  ENV PYTHONUNBUFFERED=1
28
  ENV HOST=0.0.0.0
29
  ENV PORT=7860
30
+ # Set environment variable for production
31
+ ENV ENV=production
32
+ # These should be set in Hugging Face Space settings
33
+ # ENV HF_USERNAME=your-username
34
+ # ENV HF_TOKEN=your-token
35
+ # ENV HF_DATASET_REPO=image-uploader-data
36
 
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"]
app.py CHANGED
@@ -15,6 +15,10 @@ from starlette.middleware.sessions import SessionMiddleware
15
  from fastapi.security import OAuth2PasswordRequestForm
16
  from fastapi.responses import JSONResponse
17
  import json
 
 
 
 
18
 
19
  # Create FastAPI app
20
  app = FastAPI(title="Image Uploader")
@@ -52,6 +56,38 @@ security = HTTPBasic()
52
  USERNAME = "detomo"
53
  PASSWORD = "itweek2025"
54
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
55
  def get_file_extension(filename: str) -> str:
56
  """Get the file extension from a filename."""
57
  return os.path.splitext(filename)[1].lower()
@@ -77,13 +113,44 @@ def verify_auth(request: Request):
77
 
78
  def get_image_metadata():
79
  """Get all image metadata including hashtags."""
80
- if METADATA_FILE.exists():
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
81
  with open(METADATA_FILE, "r") as f:
82
  return json.load(f)
83
  return {}
84
 
85
  def save_image_metadata(metadata):
86
  """Save image metadata to the JSON file."""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
87
  with open(METADATA_FILE, "w") as f:
88
  json.dump(metadata, f)
89
 
@@ -111,6 +178,62 @@ def mark_image_as_viewed(filename):
111
  metadata[filename]["is_new"] = False
112
  save_image_metadata(metadata)
113
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
114
  @app.get("/login", response_class=HTMLResponse)
115
  async def login_page(request: Request):
116
  """Render the login page."""
@@ -152,7 +275,40 @@ async def home(request: Request, search: Optional[str] = None, tag: Optional[str
152
  uploaded_images = []
153
  metadata = get_image_metadata()
154
 
155
- if UPLOAD_DIR.exists():
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
156
  for file in UPLOAD_DIR.iterdir():
157
  if is_valid_image(get_file_extension(file.name)):
158
  image_url = f"/static/uploads/{file.name}"
@@ -226,7 +382,18 @@ async def upload_image(
226
  # First, check for duplicate filenames
227
  metadata = get_image_metadata()
228
  all_files = {}
229
- if UPLOAD_DIR.exists():
 
 
 
 
 
 
 
 
 
 
 
230
  for file in UPLOAD_DIR.iterdir():
231
  if is_valid_image(get_file_extension(file.name)):
232
  # Get original filename from metadata if available
@@ -267,19 +434,31 @@ async def upload_image(
267
 
268
  # Generate a unique filename to prevent overwrites
269
  unique_filename = f"{uuid.uuid4()}{extension}"
270
- file_path = UPLOAD_DIR / unique_filename
271
 
272
- # Save the file
273
- with file_path.open("wb") as buffer:
274
- shutil.copyfileobj(file.file, buffer)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
275
 
276
  # Save hashtags and original filename
277
  add_hashtags_to_image(unique_filename, hashtag_list, original_filename)
278
 
279
  # For base64 encoding
280
- file.file.seek(0) # Reset file pointer to beginning
281
- contents = await file.read()
282
- base64_encoded = base64.b64encode(contents).decode("utf-8")
283
 
284
  # Determine MIME type
285
  mime_type = {
@@ -291,13 +470,21 @@ async def upload_image(
291
  '.webp': 'image/webp'
292
  }.get(extension, 'application/octet-stream')
293
 
 
 
 
 
 
 
 
 
294
  results.append({
295
  "success": True,
296
  "file_name": unique_filename,
297
  "original_filename": original_filename,
298
- "file_url": f"/static/uploads/{unique_filename}",
299
- "full_url": f"{request.base_url}static/uploads/{unique_filename}",
300
- "embed_html": f'<img src="{request.base_url}static/uploads/{unique_filename}" alt="{original_filename}" />',
301
  "base64_data": f"data:{mime_type};base64,{base64_encoded[:20]}...{base64_encoded[-20:]}",
302
  "base64_embed": f'<img src="data:{mime_type};base64,{base64_encoded}" alt="{original_filename}" />',
303
  "hashtags": hashtag_list
@@ -352,34 +539,55 @@ async def upload_with_replace(
352
  original_filename = file.filename
353
  file_lower = original_filename.lower()
354
 
 
 
 
 
355
  # Check if this file should replace an existing one
356
  if file_lower in replace_map:
357
  # Delete the old file
358
- old_file = UPLOAD_DIR / replace_map[file_lower]
359
- if old_file.exists():
360
- os.remove(old_file)
 
 
 
 
 
 
 
 
 
361
 
362
- # Remove from metadata
363
- metadata = get_image_metadata()
364
- if replace_map[file_lower] in metadata:
365
- del metadata[replace_map[file_lower]]
366
- save_image_metadata(metadata)
367
 
368
  # Generate a unique filename to prevent overwrites
369
  unique_filename = f"{uuid.uuid4()}{extension}"
370
- file_path = UPLOAD_DIR / unique_filename
371
 
372
- # Save the file
373
- with file_path.open("wb") as buffer:
374
- shutil.copyfileobj(file.file, buffer)
 
 
 
 
 
 
 
 
 
 
 
375
 
376
  # Save hashtags and original filename
377
  add_hashtags_to_image(unique_filename, hashtag_list, original_filename)
378
 
379
  # For base64 encoding
380
- file.file.seek(0) # Reset file pointer to beginning
381
- contents = await file.read()
382
- base64_encoded = base64.b64encode(contents).decode("utf-8")
383
 
384
  # Determine MIME type
385
  mime_type = {
@@ -391,13 +599,21 @@ async def upload_with_replace(
391
  '.webp': 'image/webp'
392
  }.get(extension, 'application/octet-stream')
393
 
 
 
 
 
 
 
 
 
394
  results.append({
395
  "success": True,
396
  "file_name": unique_filename,
397
  "original_filename": original_filename,
398
- "file_url": f"/static/uploads/{unique_filename}",
399
- "full_url": f"{request.base_url}static/uploads/{unique_filename}",
400
- "embed_html": f'<img src="{request.base_url}static/uploads/{unique_filename}" alt="{original_filename}" />',
401
  "base64_data": f"data:{mime_type};base64,{base64_encoded[:20]}...{base64_encoded[-20:]}",
402
  "base64_embed": f'<img src="data:{mime_type};base64,{base64_encoded}" alt="{original_filename}" />',
403
  "hashtags": hashtag_list
@@ -415,16 +631,25 @@ async def view_image(request: Request, file_name: str):
415
  if not authenticate(request):
416
  return RedirectResponse(url="/login", status_code=status.HTTP_302_FOUND)
417
 
418
- file_path = UPLOAD_DIR / file_name
419
-
420
- if not file_path.exists():
421
- raise HTTPException(status_code=404, detail="Image not found")
422
-
423
  # Mark image as viewed (not new)
424
  mark_image_as_viewed(file_name)
425
 
426
- image_url = f"/static/uploads/{file_name}"
427
- embed_url = f"{request.base_url}static/uploads/{file_name}"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
428
 
429
  # Get metadata
430
  metadata = get_image_metadata()
@@ -457,10 +682,14 @@ async def update_hashtags(request: Request, file_name: str, hashtags: str = Form
457
  content={"detail": "Not authenticated"}
458
  )
459
 
460
- file_path = UPLOAD_DIR / file_name
461
-
462
- if not file_path.exists():
463
- raise HTTPException(status_code=404, detail="Image not found")
 
 
 
 
464
 
465
  # Process hashtags
466
  hashtag_list = []
@@ -483,13 +712,18 @@ async def delete_image(request: Request, file_name: str):
483
  content={"detail": "Not authenticated"}
484
  )
485
 
486
- file_path = UPLOAD_DIR / file_name
487
-
488
- if not file_path.exists():
489
- raise HTTPException(status_code=404, detail="Image not found")
490
-
491
- # Delete the file
492
- os.remove(file_path)
 
 
 
 
 
493
 
494
  # Remove from metadata
495
  metadata = get_image_metadata()
 
15
  from fastapi.security import OAuth2PasswordRequestForm
16
  from fastapi.responses import JSONResponse
17
  import json
18
+ 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")
 
56
  USERNAME = "detomo"
57
  PASSWORD = "itweek2025"
58
 
59
+ # Hugging Face Dataset configuration
60
+ HF_USERNAME = os.environ.get("HF_USERNAME", "") # Set this in Hugging Face Space settings
61
+ HF_TOKEN = os.environ.get("HF_TOKEN", "") # Set this in Hugging Face Space settings
62
+ 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
+
69
+ # Create or ensure repository exists
70
+ 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."""
93
  return os.path.splitext(filename)[1].lower()
 
113
 
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:
128
+ print(f"Error fetching metadata from Hugging Face: {e}")
129
+ # Return empty dict if failed
130
+ return {}
131
+ # Local development fallback
132
+ elif METADATA_FILE.exists():
133
  with open(METADATA_FILE, "r") as f:
134
  return json.load(f)
135
  return {}
136
 
137
  def save_image_metadata(metadata):
138
  """Save image metadata to the JSON file."""
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()),
145
+ path_in_repo=f"{METADATA_PATH}/image_metadata.json",
146
+ repo_id=f"{HF_USERNAME}/{DATASET_REPO}",
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
 
 
178
  metadata[filename]["is_new"] = False
179
  save_image_metadata(metadata)
180
 
181
+ 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}",
188
+ repo_id=f"{HF_USERNAME}/{DATASET_REPO}",
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}")
195
+ return False
196
+ return False
197
+
198
+ 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}")
211
+ return False
212
+ return False
213
+
214
+ def get_hf_image_url(filename):
215
+ """Get the URL for an image in the Hugging Face repo."""
216
+ if HF_USERNAME:
217
+ return f"https://huggingface.co/datasets/{HF_USERNAME}/{DATASET_REPO}/resolve/main/{IMAGES_PATH}/{filename}"
218
+ return None
219
+
220
+ 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",
227
+ token=HF_TOKEN
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 []
235
+ return []
236
+
237
  @app.get("/login", response_class=HTMLResponse)
238
  async def login_page(request: Request):
239
  """Render the login page."""
 
275
  uploaded_images = []
276
  metadata = get_image_metadata()
277
 
278
+ # In production environment, get images from Hugging Face
279
+ if os.environ.get("ENV", "development") == "production" and HF_USERNAME:
280
+ hf_images = list_hf_images()
281
+
282
+ for file_name in hf_images:
283
+ # Get hashtags from metadata if available
284
+ hashtags = []
285
+ is_new = False
286
+ original_filename = file_name
287
+
288
+ if file_name in metadata:
289
+ hashtags = metadata[file_name].get("hashtags", [])
290
+ is_new = metadata[file_name].get("is_new", False)
291
+ original_filename = metadata[file_name].get("original_filename", file_name)
292
+
293
+ # If searching/filtering, check if this image should be included
294
+ if search and search.lower() not in original_filename.lower() and not any(search.lower() in tag.lower() for tag in hashtags):
295
+ continue
296
+
297
+ if tag and tag not in hashtags:
298
+ continue
299
+
300
+ image_url = get_hf_image_url(file_name)
301
+
302
+ uploaded_images.append({
303
+ "name": file_name,
304
+ "url": image_url,
305
+ "embed_url": image_url,
306
+ "hashtags": hashtags,
307
+ "is_new": is_new,
308
+ "original_filename": original_filename
309
+ })
310
+ # Local development fallback
311
+ elif UPLOAD_DIR.exists():
312
  for file in UPLOAD_DIR.iterdir():
313
  if is_valid_image(get_file_extension(file.name)):
314
  image_url = f"/static/uploads/{file.name}"
 
382
  # First, check for duplicate filenames
383
  metadata = get_image_metadata()
384
  all_files = {}
385
+
386
+ # In production, check for duplicates in Hugging Face repo
387
+ if os.environ.get("ENV", "development") == "production" and HF_USERNAME:
388
+ hf_images = list_hf_images()
389
+ for filename in hf_images:
390
+ # Get original filename from metadata if available
391
+ original_name = filename
392
+ if filename in metadata and "original_filename" in metadata[filename]:
393
+ original_name = metadata[filename]["original_filename"]
394
+ all_files[original_name.lower()] = filename
395
+ # Local development fallback
396
+ elif UPLOAD_DIR.exists():
397
  for file in UPLOAD_DIR.iterdir():
398
  if is_valid_image(get_file_extension(file.name)):
399
  # Get original filename from metadata if available
 
434
 
435
  # Generate a unique filename to prevent overwrites
436
  unique_filename = f"{uuid.uuid4()}{extension}"
 
437
 
438
+ # Read file content for upload
439
+ file.file.seek(0)
440
+ file_content = await file.read()
441
+
442
+ # Save file based on environment
443
+ if os.environ.get("ENV", "development") == "production" and HF_USERNAME and HF_TOKEN:
444
+ # Upload to Hugging Face
445
+ upload_success = upload_to_hf(file_content, unique_filename)
446
+ if not upload_success:
447
+ # Fallback to local storage if HF upload fails
448
+ file_path = UPLOAD_DIR / unique_filename
449
+ with file_path.open("wb") as buffer:
450
+ buffer.write(file_content)
451
+ else:
452
+ # Local development storage
453
+ file_path = UPLOAD_DIR / unique_filename
454
+ with file_path.open("wb") as buffer:
455
+ buffer.write(file_content)
456
 
457
  # Save hashtags and original filename
458
  add_hashtags_to_image(unique_filename, hashtag_list, original_filename)
459
 
460
  # For base64 encoding
461
+ base64_encoded = base64.b64encode(file_content).decode("utf-8")
 
 
462
 
463
  # Determine MIME type
464
  mime_type = {
 
470
  '.webp': 'image/webp'
471
  }.get(extension, 'application/octet-stream')
472
 
473
+ # Get appropriate image URL based on environment
474
+ if os.environ.get("ENV", "development") == "production" and HF_USERNAME:
475
+ image_url = get_hf_image_url(unique_filename)
476
+ full_url = image_url
477
+ else:
478
+ image_url = f"/static/uploads/{unique_filename}"
479
+ full_url = f"{request.base_url}static/uploads/{unique_filename}"
480
+
481
  results.append({
482
  "success": True,
483
  "file_name": unique_filename,
484
  "original_filename": original_filename,
485
+ "file_url": image_url,
486
+ "full_url": full_url,
487
+ "embed_html": f'<img src="{full_url}" alt="{original_filename}" />',
488
  "base64_data": f"data:{mime_type};base64,{base64_encoded[:20]}...{base64_encoded[-20:]}",
489
  "base64_embed": f'<img src="data:{mime_type};base64,{base64_encoded}" alt="{original_filename}" />',
490
  "hashtags": hashtag_list
 
539
  original_filename = file.filename
540
  file_lower = original_filename.lower()
541
 
542
+ # Read file content
543
+ file.file.seek(0)
544
+ file_content = await file.read()
545
+
546
  # Check if this file should replace an existing one
547
  if file_lower in replace_map:
548
  # Delete the old file
549
+ old_filename = replace_map[file_lower]
550
+
551
+ if os.environ.get("ENV", "development") == "production" and HF_USERNAME and HF_TOKEN:
552
+ # Delete from Hugging Face
553
+ delete_success = delete_from_hf(old_filename)
554
+ if not delete_success:
555
+ raise HTTPException(status_code=404, detail="Image not found or could not be deleted")
556
+ else:
557
+ # Delete from local storage
558
+ old_file = UPLOAD_DIR / old_filename
559
+ if old_file.exists():
560
+ os.remove(old_file)
561
 
562
+ # Remove from metadata
563
+ metadata = get_image_metadata()
564
+ if old_filename in metadata:
565
+ del metadata[old_filename]
566
+ save_image_metadata(metadata)
567
 
568
  # Generate a unique filename to prevent overwrites
569
  unique_filename = f"{uuid.uuid4()}{extension}"
 
570
 
571
+ # Save file based on environment
572
+ if os.environ.get("ENV", "development") == "production" and HF_USERNAME and HF_TOKEN:
573
+ # Upload to Hugging Face
574
+ upload_success = upload_to_hf(file_content, unique_filename)
575
+ if not upload_success:
576
+ # Fallback to local storage if HF upload fails
577
+ file_path = UPLOAD_DIR / unique_filename
578
+ with file_path.open("wb") as buffer:
579
+ buffer.write(file_content)
580
+ else:
581
+ # Local development storage
582
+ file_path = UPLOAD_DIR / unique_filename
583
+ with file_path.open("wb") as buffer:
584
+ buffer.write(file_content)
585
 
586
  # Save hashtags and original filename
587
  add_hashtags_to_image(unique_filename, hashtag_list, original_filename)
588
 
589
  # For base64 encoding
590
+ base64_encoded = base64.b64encode(file_content).decode("utf-8")
 
 
591
 
592
  # Determine MIME type
593
  mime_type = {
 
599
  '.webp': 'image/webp'
600
  }.get(extension, 'application/octet-stream')
601
 
602
+ # Get appropriate image URL based on environment
603
+ if os.environ.get("ENV", "development") == "production" and HF_USERNAME:
604
+ image_url = get_hf_image_url(unique_filename)
605
+ full_url = image_url
606
+ else:
607
+ image_url = f"/static/uploads/{unique_filename}"
608
+ full_url = f"{request.base_url}static/uploads/{unique_filename}"
609
+
610
  results.append({
611
  "success": True,
612
  "file_name": unique_filename,
613
  "original_filename": original_filename,
614
+ "file_url": image_url,
615
+ "full_url": full_url,
616
+ "embed_html": f'<img src="{full_url}" alt="{original_filename}" />',
617
  "base64_data": f"data:{mime_type};base64,{base64_encoded[:20]}...{base64_encoded[-20:]}",
618
  "base64_embed": f'<img src="data:{mime_type};base64,{base64_encoded}" alt="{original_filename}" />',
619
  "hashtags": hashtag_list
 
631
  if not authenticate(request):
632
  return RedirectResponse(url="/login", status_code=status.HTTP_302_FOUND)
633
 
 
 
 
 
 
634
  # Mark image as viewed (not new)
635
  mark_image_as_viewed(file_name)
636
 
637
+ # Determine image URL based on environment
638
+ if os.environ.get("ENV", "development") == "production" and HF_USERNAME:
639
+ image_url = get_hf_image_url(file_name)
640
+ embed_url = image_url
641
+
642
+ # Check if file exists in Hugging Face
643
+ if not image_url or file_name not in list_hf_images():
644
+ raise HTTPException(status_code=404, detail="Image not found")
645
+ else:
646
+ # Check local file
647
+ file_path = UPLOAD_DIR / file_name
648
+ if not file_path.exists():
649
+ raise HTTPException(status_code=404, detail="Image not found")
650
+
651
+ image_url = f"/static/uploads/{file_name}"
652
+ embed_url = f"{request.base_url}static/uploads/{file_name}"
653
 
654
  # Get metadata
655
  metadata = get_image_metadata()
 
682
  content={"detail": "Not authenticated"}
683
  )
684
 
685
+ # Check if file exists
686
+ if os.environ.get("ENV", "development") == "production" and HF_USERNAME:
687
+ if file_name not in list_hf_images():
688
+ raise HTTPException(status_code=404, detail="Image not found")
689
+ else:
690
+ file_path = UPLOAD_DIR / file_name
691
+ if not file_path.exists():
692
+ raise HTTPException(status_code=404, detail="Image not found")
693
 
694
  # Process hashtags
695
  hashtag_list = []
 
712
  content={"detail": "Not authenticated"}
713
  )
714
 
715
+ # Delete file based on environment
716
+ if os.environ.get("ENV", "development") == "production" and HF_USERNAME and HF_TOKEN:
717
+ # Delete from Hugging Face
718
+ delete_success = delete_from_hf(file_name)
719
+ if not delete_success:
720
+ raise HTTPException(status_code=404, detail="Image not found or could not be deleted")
721
+ else:
722
+ # Delete from local storage
723
+ file_path = UPLOAD_DIR / file_name
724
+ if not file_path.exists():
725
+ raise HTTPException(status_code=404, detail="Image not found")
726
+ os.remove(file_path)
727
 
728
  # Remove from metadata
729
  metadata = get_image_metadata()
requirements.txt CHANGED
@@ -4,4 +4,5 @@ python-multipart
4
  jinja2
5
  aiofiles
6
  itsdangerous
7
- python-jose
 
 
4
  jinja2
5
  aiofiles
6
  itsdangerous
7
+ python-jose
8
+ huggingface_hub