DrValera commited on
Commit
9c418dd
·
verified ·
1 Parent(s): 57ccb99

Upload main.py

Browse files
Files changed (1) hide show
  1. main.py +72 -36
main.py CHANGED
@@ -67,10 +67,10 @@ app.add_middleware(
67
  )
68
 
69
  # to ensure we don’t leak hop-by-hop headers
70
- def _filter_resp_headers(h):
71
  # pass through useful headers but strip hop-by-hop
72
  allowed = {"content-disposition"}
73
- return {k: v for k, v in h.items() if k.lower() in allowed}
74
 
75
  def _extract_user_token(req: Request) -> str | None:
76
  """
@@ -120,23 +120,44 @@ async def _forward_stream(path: str, files=None, data=None, user_token: str | No
120
  headers["X-API-Key"] = user_token
121
 
122
  timeout = httpx.Timeout(600.0)
123
- async with httpx.AsyncClient(timeout=timeout) as client:
124
- async with client.stream(method, url, headers=headers, files=files, data=data) as resp:
125
- if resp.status_code >= 400:
126
- text = await resp.aread()
127
- return Response(
128
- content=text,
129
- status_code=resp.status_code,
130
- media_type=resp.headers.get("content-type","text/plain")
131
- )
132
- media_type = resp.headers.get("content-type", "application/octet-stream")
133
- safe_headers = _filter_resp_headers(resp.headers) # Content-Disposition only
134
- return StreamingResponse(
135
- resp.aiter_raw(),
136
- status_code=resp.status_code,
137
- media_type=media_type,
138
- headers=safe_headers,
139
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
140
 
141
  # for demo
142
  async def _forward_demo_stream(path: str, *, files: dict | None, data: dict | None, method: str = "POST"):
@@ -149,26 +170,41 @@ async def _forward_demo_stream(path: str, *, files: dict | None, data: dict | No
149
  "Authorization": f"Bearer {HF_TOKEN}",
150
  # App-level demo token (checked by the private API):
151
  "X-DATFID-Token": DATFID_DEMO_TOKEN,
 
152
  }
153
 
154
  timeout = httpx.Timeout(120.0)
155
- async with httpx.AsyncClient(timeout=timeout) as client:
156
- async with client.stream(method, url, headers=headers, files=files, data=data) as resp:
157
- if resp.status_code >= 400:
158
- text = await resp.aread()
159
- return Response(
160
- content=text,
161
- status_code=resp.status_code,
162
- media_type=resp.headers.get("content-type","text/plain")
163
- )
164
- media_type = resp.headers.get("content-type", "application/octet-stream")
165
- safe_headers = _filter_resp_headers(resp.headers) # Content-Disposition only
166
- return StreamingResponse(
167
- resp.aiter_raw(),
168
- status_code=resp.status_code,
169
- media_type=media_type,
170
- headers=safe_headers,
171
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
172
 
173
  @app.get("/")
174
  async def root(req: Request):
 
67
  )
68
 
69
  # to ensure we don’t leak hop-by-hop headers
70
+ def _filter_resp_headers(headers: dict) -> dict:
71
  # pass through useful headers but strip hop-by-hop
72
  allowed = {"content-disposition"}
73
+ return {k: v for k, v in headers.items() if k.lower() in allowed}
74
 
75
  def _extract_user_token(req: Request) -> str | None:
76
  """
 
120
  headers["X-API-Key"] = user_token
121
 
122
  timeout = httpx.Timeout(600.0)
123
+
124
+ client = httpx.AsyncClient(timeout=timeout, follow_redirects=True)
125
+
126
+ # Don't open the context yet; the iterator must own the context lifetime.
127
+ stream_ctx = client.stream(method, url, headers=headers, files=files, data=data)
128
+
129
+ # Mutable holders we can fill once the stream opens
130
+ status_holder = {"code": 200}
131
+ media_type_holder = {"ct": "application/octet-stream"}
132
+ headers_holder = {}
133
+
134
+ async def body_iter():
135
+ try:
136
+ async with stream_ctx as resp:
137
+ status_holder["code"] = resp.status_code
138
+ media_type_holder["ct"] = resp.headers.get("content-type", "application/octet-stream")
139
+ headers_holder.update(_filter_resp_headers(resp.headers))
140
+
141
+ # If upstream already returned an error, buffer it (short text/json)
142
+ if resp.status_code >= 400:
143
+ # Buffer entire payload and yield once
144
+ chunk = await resp.aread()
145
+ yield chunk
146
+ return
147
+
148
+ async for chunk in resp.aiter_raw():
149
+ yield chunk
150
+ finally:
151
+ await client.aclose()
152
+
153
+ response = StreamingResponse(
154
+ body_iter(),
155
+ status_code=status_holder["code"],
156
+ media_type=media_type_holder["ct"],
157
+ headers=headers_holder,
158
+ )
159
+ return response
160
+
161
 
162
  # for demo
163
  async def _forward_demo_stream(path: str, *, files: dict | None, data: dict | None, method: str = "POST"):
 
170
  "Authorization": f"Bearer {HF_TOKEN}",
171
  # App-level demo token (checked by the private API):
172
  "X-DATFID-Token": DATFID_DEMO_TOKEN,
173
+ "Accept": "*/*",
174
  }
175
 
176
  timeout = httpx.Timeout(120.0)
177
+ client = httpx.AsyncClient(timeout=timeout, follow_redirects=True)
178
+ stream_ctx = client.stream(method, url, headers=headers, files=files, data=data)
179
+
180
+ status_holder = {"code": 200}
181
+ media_type_holder = {"ct": "application/octet-stream"}
182
+ headers_holder = {}
183
+
184
+ async def body_iter():
185
+ try:
186
+ async with stream_ctx as resp:
187
+ status_holder["code"] = resp.status_code
188
+ media_type_holder["ct"] = resp.headers.get("content-type", "application/octet-stream")
189
+ headers_holder.update(_filter_resp_headers(resp.headers))
190
+
191
+ if resp.status_code >= 400:
192
+ chunk = await resp.aread()
193
+ yield chunk
194
+ return
195
+
196
+ async for chunk in resp.aiter_raw():
197
+ yield chunk
198
+ finally:
199
+ await client.aclose()
200
+
201
+ response = StreamingResponse(
202
+ body_iter(),
203
+ status_code=status_holder["code"],
204
+ media_type=media_type_holder["ct"],
205
+ headers=headers_holder,
206
+ )
207
+ return response
208
 
209
  @app.get("/")
210
  async def root(req: Request):