Update app.py
Browse files
app.py
CHANGED
|
@@ -152,7 +152,19 @@ async def get_status(task_id: str):
|
|
| 152 |
async def download(task_id: str):
|
| 153 |
if task_id not in tasks or tasks[task_id]["status"] != "completed":
|
| 154 |
return {"error": "File not ready"}
|
| 155 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 156 |
|
| 157 |
@app.get("/stream/{task_id}")
|
| 158 |
async def stream(task_id: str, request: Request):
|
|
@@ -163,6 +175,17 @@ async def stream(task_id: str, request: Request):
|
|
| 163 |
file_size = os.path.getsize(file_path)
|
| 164 |
range_header = request.headers.get("Range")
|
| 165 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 166 |
if range_header:
|
| 167 |
byte1, byte2 = 0, None
|
| 168 |
match = range_header.replace("bytes=", "").split("-")
|
|
@@ -175,28 +198,38 @@ async def stream(task_id: str, request: Request):
|
|
| 175 |
if byte2 is not None:
|
| 176 |
length = byte2 + 1 - byte1
|
| 177 |
|
| 178 |
-
def file_iterator(start,
|
| 179 |
with open(file_path, "rb") as f:
|
| 180 |
f.seek(start)
|
| 181 |
-
|
| 182 |
-
|
| 183 |
-
read_size = min(chunk_size, length)
|
| 184 |
data = f.read(read_size)
|
| 185 |
if not data:
|
| 186 |
break
|
| 187 |
yield data
|
| 188 |
-
|
| 189 |
del data
|
| 190 |
-
gc.collect()
|
| 191 |
|
| 192 |
-
|
| 193 |
"Content-Range": f"bytes {byte1}-{byte1+length-1}/{file_size}",
|
| 194 |
-
"Accept-Ranges": "bytes",
|
| 195 |
"Content-Length": str(length),
|
| 196 |
-
}
|
| 197 |
-
return StreamingResponse(file_iterator(byte1, length), status_code=206, headers=
|
| 198 |
else:
|
| 199 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 200 |
|
| 201 |
@app.get("/storage")
|
| 202 |
async def get_storage():
|
|
|
|
| 152 |
async def download(task_id: str):
|
| 153 |
if task_id not in tasks or tasks[task_id]["status"] != "completed":
|
| 154 |
return {"error": "File not ready"}
|
| 155 |
+
|
| 156 |
+
# Hugging Face reverse proxy buffering ko explicit bypass karne ke liye headers
|
| 157 |
+
headers = {
|
| 158 |
+
"X-Accel-Buffering": "no",
|
| 159 |
+
"Cache-Control": "no-cache, no-store, must-revalidate",
|
| 160 |
+
"Pragma": "no-cache",
|
| 161 |
+
"Expires": "0"
|
| 162 |
+
}
|
| 163 |
+
return FileResponse(
|
| 164 |
+
tasks[task_id]["file_path"],
|
| 165 |
+
filename=tasks[task_id].get("original_filename"),
|
| 166 |
+
headers=headers
|
| 167 |
+
)
|
| 168 |
|
| 169 |
@app.get("/stream/{task_id}")
|
| 170 |
async def stream(task_id: str, request: Request):
|
|
|
|
| 175 |
file_size = os.path.getsize(file_path)
|
| 176 |
range_header = request.headers.get("Range")
|
| 177 |
|
| 178 |
+
# Fast output transfer ke liye chunk size 1MB se 4MB ke beech hona chahiye (Overhead kam karne ke liye)
|
| 179 |
+
STREAM_CHUNK_SIZE = 2 * 1024 * 1024
|
| 180 |
+
|
| 181 |
+
# Common performance headers jo proxy networks ko instantaneous routing ke liye force karte hain
|
| 182 |
+
base_headers = {
|
| 183 |
+
"X-Accel-Buffering": "no",
|
| 184 |
+
"Cache-Control": "no-cache, no-store, must-revalidate",
|
| 185 |
+
"Pragma": "no-cache",
|
| 186 |
+
"Accept-Ranges": "bytes"
|
| 187 |
+
}
|
| 188 |
+
|
| 189 |
if range_header:
|
| 190 |
byte1, byte2 = 0, None
|
| 191 |
match = range_header.replace("bytes=", "").split("-")
|
|
|
|
| 198 |
if byte2 is not None:
|
| 199 |
length = byte2 + 1 - byte1
|
| 200 |
|
| 201 |
+
def file_iterator(start, length_left):
|
| 202 |
with open(file_path, "rb") as f:
|
| 203 |
f.seek(start)
|
| 204 |
+
while length_left > 0:
|
| 205 |
+
read_size = min(STREAM_CHUNK_SIZE, length_left)
|
|
|
|
| 206 |
data = f.read(read_size)
|
| 207 |
if not data:
|
| 208 |
break
|
| 209 |
yield data
|
| 210 |
+
length_left -= len(data)
|
| 211 |
del data
|
|
|
|
| 212 |
|
| 213 |
+
base_headers.update({
|
| 214 |
"Content-Range": f"bytes {byte1}-{byte1+length-1}/{file_size}",
|
|
|
|
| 215 |
"Content-Length": str(length),
|
| 216 |
+
})
|
| 217 |
+
return StreamingResponse(file_iterator(byte1, length), status_code=206, headers=base_headers)
|
| 218 |
else:
|
| 219 |
+
def full_file_iterator():
|
| 220 |
+
with open(file_path, "rb") as f:
|
| 221 |
+
while True:
|
| 222 |
+
data = f.read(STREAM_CHUNK_SIZE)
|
| 223 |
+
if not data:
|
| 224 |
+
break
|
| 225 |
+
yield data
|
| 226 |
+
del data
|
| 227 |
+
|
| 228 |
+
base_headers.update({
|
| 229 |
+
"Content-Length": str(file_size),
|
| 230 |
+
"Content-Disposition": f'attachment; filename="{tasks[task_id].get("original_filename")}"'
|
| 231 |
+
})
|
| 232 |
+
return StreamingResponse(full_file_iterator(), media_type="application/octet-stream", headers=base_headers)
|
| 233 |
|
| 234 |
@app.get("/storage")
|
| 235 |
async def get_storage():
|