sameerbanchhor commited on
Commit
55eb784
Β·
verified Β·
1 Parent(s): 438ec1c

Upload folder using huggingface_hub

Browse files
.gitignore CHANGED
@@ -8,4 +8,6 @@ __pycache__
8
  llm_documentation.md
9
 
10
  # enironment variable
11
- .env
 
 
 
8
  llm_documentation.md
9
 
10
  # enironment variable
11
+ .env
12
+
13
+ uploaded_files
app/main.py CHANGED
@@ -21,6 +21,11 @@ from app.routers.security import password_generator
21
  # ==========================
22
  from app.routers.auth import system as auth_system
23
 
 
 
 
 
 
24
  # ==========================
25
  # πŸ§ͺ Test Utilities
26
  # ==========================
@@ -45,6 +50,7 @@ app.include_router(random_number_generator.router) # Random number tester
45
  app.include_router(help.router) # Helper/test info
46
  app.include_router(calculator.router) # Mini calculator service
47
  app.include_router(auth_system.router) # <-- NEW AUTH SYSTEM
 
48
  app.include_router(server_status.router) # function to check the system
49
 
50
 
 
21
  # ==========================
22
  from app.routers.auth import system as auth_system
23
 
24
+ # ==========================
25
+ # ☁️ Cloud Drive Module (NEW)
26
+ # ==========================
27
+ from app.routers.drive import storage
28
+
29
  # ==========================
30
  # πŸ§ͺ Test Utilities
31
  # ==========================
 
50
  app.include_router(help.router) # Helper/test info
51
  app.include_router(calculator.router) # Mini calculator service
52
  app.include_router(auth_system.router) # <-- NEW AUTH SYSTEM
53
+ app.include_router(storage.router) # new cloud drive support
54
  app.include_router(server_status.router) # function to check the system
55
 
56
 
app/routers/drive/storage.py ADDED
@@ -0,0 +1,177 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import shutil
2
+ import os
3
+ import asyncio
4
+ from fastapi import (
5
+ APIRouter,
6
+ UploadFile,
7
+ File,
8
+ HTTPException,
9
+ Header,
10
+ status,
11
+ Depends,
12
+ WebSocket,
13
+ WebSocketDisconnect
14
+ )
15
+
16
+ # Import Auth System
17
+ from app.routers.auth.system import get_current_user
18
+
19
+ # Router Configuration
20
+ router = APIRouter(
21
+ prefix="/drive",
22
+ tags=["Cloud Drive"]
23
+ )
24
+
25
+ # Settings
26
+ UPLOAD_DIR = "uploaded_files"
27
+ MAX_FILE_SIZE = 1 * 1024 * 1024 * 1024 # 1GB Limit
28
+
29
+ # πŸ” Auth Toggle
30
+ AUTH_ENABLED = False # <<< set False to disable authentication
31
+
32
+ # Auth Wrapper (returns dependency or None)
33
+ def auth_dependency():
34
+ return Depends(get_current_user) if AUTH_ENABLED else None
35
+
36
+ # Ensure the upload directory exists
37
+ os.makedirs(UPLOAD_DIR, exist_ok=True)
38
+
39
+ # ==========================================
40
+ # πŸ› οΈ Helper: Safe Username Extraction
41
+ # ==========================================
42
+ def get_safe_username(user_obj):
43
+ if not user_obj:
44
+ return "anonymous"
45
+ if hasattr(user_obj, "username"):
46
+ return user_obj.username
47
+ return user_obj.get("username", "anonymous")
48
+
49
+
50
+ # ==========================================
51
+ # πŸ“€ Standard File Upload
52
+ # ==========================================
53
+ @router.post("/upload/")
54
+ async def upload_file(
55
+ file: UploadFile = File(...),
56
+ content_length: int = Header(None),
57
+ current_user: object = auth_dependency()
58
+ ):
59
+ if content_length and content_length > MAX_FILE_SIZE:
60
+ raise HTTPException(
61
+ status_code=status.HTTP_413_REQUEST_ENTITY_TOO_LARGE,
62
+ detail="File is too large. Maximum limit is 1GB."
63
+ )
64
+
65
+ username = get_safe_username(current_user)
66
+ file_path = os.path.join(UPLOAD_DIR, file.filename)
67
+
68
+ try:
69
+ with open(file_path, "wb") as buffer:
70
+ shutil.copyfileobj(file.file, buffer)
71
+ except Exception as e:
72
+ raise HTTPException(status_code=500, detail=f"Internal Server Error: {str(e)}")
73
+ finally:
74
+ file.file.close()
75
+
76
+ return {
77
+ "user": username,
78
+ "filename": file.filename,
79
+ "path": file_path,
80
+ "message": "File uploaded successfully"
81
+ }
82
+
83
+
84
+ # ==========================================
85
+ # πŸš€ Remote Upload (Aria2)
86
+ # ==========================================
87
+ @router.post("/remote-upload/")
88
+ async def remote_url_upload(
89
+ url: str,
90
+ custom_filename: str = None,
91
+ current_user: object = auth_dependency()
92
+ ):
93
+ username = get_safe_username(current_user)
94
+
95
+ command = ["aria2c", "-x", "6", "-s", "6", "-d", UPLOAD_DIR, url]
96
+ if custom_filename:
97
+ command.extend(["-o", custom_filename])
98
+
99
+ try:
100
+ process = await asyncio.create_subprocess_exec(
101
+ *command,
102
+ stdout=asyncio.subprocess.PIPE,
103
+ stderr=asyncio.subprocess.PIPE
104
+ )
105
+ stdout, stderr = await process.communicate()
106
+
107
+ if process.returncode != 0:
108
+ raise HTTPException(status_code=500, detail=f"Aria2 Error: {stderr.decode()}")
109
+
110
+ except Exception as e:
111
+ raise HTTPException(status_code=500, detail=f"System Error: {str(e)}")
112
+
113
+ return {
114
+ "user": username,
115
+ "source": url,
116
+ "filename": custom_filename or "Auto-detected",
117
+ "message": "Download completed via Aria2"
118
+ }
119
+
120
+
121
+ # ==========================================
122
+ # πŸ“‘ WebSocket Remote Upload (No Auth Applied)
123
+ # ==========================================
124
+ @router.websocket("/ws/remote-upload/")
125
+ async def websocket_remote_upload(websocket: WebSocket):
126
+ await websocket.accept()
127
+
128
+ try:
129
+ data = await websocket.receive_json()
130
+ target_url = data.get("url")
131
+ custom_filename = data.get("filename")
132
+
133
+ if not target_url:
134
+ await websocket.send_text("❌ Error: No URL provided.")
135
+ await websocket.close()
136
+ return
137
+
138
+ command = ["aria2c", "-x", "6", "-s", "6", "-d", UPLOAD_DIR, target_url]
139
+ if custom_filename:
140
+ command.extend(["-o", custom_filename])
141
+
142
+ await websocket.send_text(f"πŸš€ Starting download: {target_url}")
143
+
144
+ process = await asyncio.create_subprocess_exec(
145
+ *command,
146
+ stdout=asyncio.subprocess.PIPE,
147
+ stderr=asyncio.subprocess.PIPE
148
+ )
149
+
150
+ while True:
151
+ line = await process.stdout.readline()
152
+ if not line:
153
+ if process.returncode is not None:
154
+ break
155
+ await asyncio.sleep(0.1)
156
+ continue
157
+
158
+ decoded_line = line.decode().strip()
159
+ if decoded_line:
160
+ await websocket.send_text(decoded_line)
161
+
162
+ await process.wait()
163
+ if process.returncode == 0:
164
+ await websocket.send_text("βœ… Download Complete.")
165
+ else:
166
+ await websocket.send_text("❌ Download Failed.")
167
+
168
+ await websocket.close()
169
+
170
+ except WebSocketDisconnect:
171
+ print("WS: Client disconnected")
172
+ except Exception as e:
173
+ try:
174
+ await websocket.send_text(f"πŸ”₯ Critical Error: {str(e)}")
175
+ await websocket.close()
176
+ except:
177
+ pass
app/routers/image/jpgcompressor.py CHANGED
@@ -3,7 +3,6 @@ from fastapi.responses import StreamingResponse
3
  from PIL import Image
4
  from io import BytesIO
5
 
6
-
7
  # ==========================
8
  # πŸ–ΌοΈ Image Processing Router
9
  # ==========================
@@ -12,54 +11,126 @@ router = APIRouter(
12
  tags=["Image Processing"]
13
  )
14
 
15
-
16
  # ==========================
17
- # πŸ“¦ JPG Compression Endpoint
18
  # ==========================
19
- @router.post("/compress_jpg")
20
- async def compress_jpg(
21
  file: UploadFile = File(..., description="The JPG image file to compress."),
22
- quality: int = Form(75, description="JPEG compression quality (1 to 100). Default is 75.")
23
  ):
24
  """
25
- πŸ”§ Compresses a JPEG image at a specified quality and returns the optimized file.
 
26
  """
27
 
28
  # --------------------------
29
  # πŸ›‘ Validation Checks
30
  # --------------------------
31
- if file.content_type != "image/jpeg":
32
  raise HTTPException(
33
  status_code=400,
34
- detail="Invalid file type. Only JPEG files are supported for this endpoint."
35
  )
36
 
37
- if not 1 <= quality <= 100:
38
  raise HTTPException(
39
  status_code=400,
40
- detail="Quality must be an integer between 1 and 100."
41
  )
42
 
 
 
 
43
  # --------------------------
44
  # πŸ“₯ Read Image Bytes
45
  # --------------------------
46
  content = await file.read()
47
- input_buffer = BytesIO(content)
48
- output_buffer = BytesIO()
 
 
 
 
 
 
49
 
 
 
50
  try:
 
 
 
 
 
 
 
 
51
  # --------------------------
52
- # πŸ§ͺ Pillow Compression
53
  # --------------------------
54
- img = Image.open(input_buffer)
55
- img.save(output_buffer, "JPEG", quality=quality)
56
- output_buffer.seek(0)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
57
 
58
  # --------------------------
59
  # πŸ“€ Return as Stream
60
  # --------------------------
61
  return StreamingResponse(
62
- output_buffer,
63
  media_type="image/jpeg",
64
  headers={
65
  "Content-Disposition": f"attachment; filename=compressed_{file.filename}"
@@ -67,10 +138,7 @@ async def compress_jpg(
67
  )
68
 
69
  except Exception as e:
70
- # --------------------------
71
- # πŸ’₯ Error Handling
72
- # --------------------------
73
  raise HTTPException(
74
  status_code=500,
75
  detail=f"Image processing error: {e}"
76
- )
 
3
  from PIL import Image
4
  from io import BytesIO
5
 
 
6
  # ==========================
7
  # πŸ–ΌοΈ Image Processing Router
8
  # ==========================
 
11
  tags=["Image Processing"]
12
  )
13
 
 
14
  # ==========================
15
+ # πŸ“¦ JPG Target Size Endpoint
16
  # ==========================
17
+ @router.post("/compress_jpg_to_size")
18
+ async def compress_jpg_to_size(
19
  file: UploadFile = File(..., description="The JPG image file to compress."),
20
+ target_size_kb: int = Form(..., description="Target file size in KB (e.g., 240).")
21
  ):
22
  """
23
+ πŸ”§ Compresses a JPEG image to fit within a specific file size (in KB).
24
+ Uses binary search to find the best quality and, if necessary, resizes dimensions.
25
  """
26
 
27
  # --------------------------
28
  # πŸ›‘ Validation Checks
29
  # --------------------------
30
+ if file.content_type not in ["image/jpeg", "image/jpg"]:
31
  raise HTTPException(
32
  status_code=400,
33
+ detail="Invalid file type. Only JPEG files are supported."
34
  )
35
 
36
+ if target_size_kb <= 0:
37
  raise HTTPException(
38
  status_code=400,
39
+ detail="Target size must be greater than 0 KB."
40
  )
41
 
42
+ # Calculate target bytes
43
+ target_bytes = target_size_kb * 1024
44
+
45
  # --------------------------
46
  # πŸ“₯ Read Image Bytes
47
  # --------------------------
48
  content = await file.read()
49
+
50
+ # ⚑ Optimization: If original is already smaller than target, return original
51
+ if len(content) <= target_bytes:
52
+ return StreamingResponse(
53
+ BytesIO(content),
54
+ media_type="image/jpeg",
55
+ headers={"Content-Disposition": f"attachment; filename=original_{file.filename}"}
56
+ )
57
 
58
+ input_buffer = BytesIO(content)
59
+
60
  try:
61
+ img = Image.open(input_buffer)
62
+
63
+ # Convert to RGB if necessary (e.g., if input was RGBA)
64
+ if img.mode != 'RGB':
65
+ img = img.convert('RGB')
66
+
67
+ output_buffer = BytesIO()
68
+
69
  # --------------------------
70
+ # πŸ“‰ Binary Search Algorithm
71
  # --------------------------
72
+ # We search for the best quality between 1 and 95
73
+ min_quality = 1
74
+ max_quality = 95
75
+ best_buffer = None
76
+
77
+ while min_quality <= max_quality:
78
+ quality = (min_quality + max_quality) // 2
79
+
80
+ # Clear buffer and save with current quality
81
+ output_buffer.seek(0)
82
+ output_buffer.truncate()
83
+ img.save(output_buffer, format="JPEG", quality=quality)
84
+
85
+ size = output_buffer.tell()
86
+
87
+ if size <= target_bytes:
88
+ # This fits! But can we get better quality?
89
+ best_buffer = BytesIO(output_buffer.getvalue()) # Store success
90
+ min_quality = quality + 1 # Try higher quality
91
+ else:
92
+ # Too big, reduce quality
93
+ max_quality = quality - 1
94
+
95
+ # --------------------------
96
+ # ⚠️ Fallback: Resize
97
+ # --------------------------
98
+ # If even quality=1 is too big, we must reduce image dimensions
99
+ if best_buffer is None:
100
+ resize_factor = 0.9
101
+ while True:
102
+ width, height = img.size
103
+ new_width = int(width * resize_factor)
104
+ new_height = int(height * resize_factor)
105
+
106
+ # Stop if image gets too tiny (sanity check)
107
+ if new_width < 10 or new_height < 10:
108
+ break
109
+
110
+ img = img.resize((new_width, new_height), Image.Resampling.LANCZOS)
111
+
112
+ output_buffer.seek(0)
113
+ output_buffer.truncate()
114
+ img.save(output_buffer, format="JPEG", quality=5) # Low quality + resize
115
+
116
+ if output_buffer.tell() <= target_bytes:
117
+ best_buffer = output_buffer
118
+ break
119
+
120
+ resize_factor *= 0.9 # Reduce size by another 10%
121
+
122
+ # If we still failed (extremely rare), just return the last attempt
123
+ if best_buffer is None:
124
+ output_buffer.seek(0)
125
+ best_buffer = output_buffer
126
+
127
+ best_buffer.seek(0)
128
 
129
  # --------------------------
130
  # πŸ“€ Return as Stream
131
  # --------------------------
132
  return StreamingResponse(
133
+ best_buffer,
134
  media_type="image/jpeg",
135
  headers={
136
  "Content-Disposition": f"attachment; filename=compressed_{file.filename}"
 
138
  )
139
 
140
  except Exception as e:
 
 
 
141
  raise HTTPException(
142
  status_code=500,
143
  detail=f"Image processing error: {e}"
144
+ )