lbb123 commited on
Commit
7ca7fc2
·
verified ·
1 Parent(s): e46b0e4

Upload 2 files

Browse files
Files changed (2) hide show
  1. app.py +93 -0
  2. requirements.txt +3 -0
app.py ADDED
@@ -0,0 +1,93 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import asyncio
3
+ import aiohttp
4
+ import json
5
+ from fastapi import FastAPI, Request, Response
6
+ from fastapi.responses import StreamingResponse, JSONResponse
7
+
8
+ TARGET_BASE_URL = "https://api.deepinfra.com/v1/openai"
9
+ REAL_API_KEY = os.environ["REAL_API_KEY"] # 从 Space secrets 读取
10
+ FAKE_KEY = os.environ.get("FAKE_KEY", "123456") # 本地访问时的鉴权
11
+
12
+ @asynccontextmanager
13
+ async def lifespan(app: FastAPI):
14
+ app.state.session = aiohttp.ClientSession()
15
+ yield
16
+ await app.state.session.close()
17
+
18
+ app = FastAPI(lifespan=lifespan)
19
+
20
+ @app.api_route("/v1/{path:path}", methods=["GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"])
21
+ async def proxy_endpoint(path: str = "", request: Request = None):
22
+ if request.method == "OPTIONS":
23
+ return Response(status_code=200, headers={
24
+ "Access-Control-Allow-Origin": "*",
25
+ "Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, OPTIONS",
26
+ "Access-Control-Allow-Headers": "Authorization, Content-Type"
27
+ })
28
+
29
+ # 鉴权:只允许携带正确 FAKE_KEY 的请求
30
+ auth_header = request.headers.get("authorization", "")
31
+ if auth_header.lower() != f"bearer {FAKE_KEY}":
32
+ return JSONResponse(status_code=401, content={"error": "Invalid fake key"})
33
+
34
+ target_url = f"{TARGET_BASE_URL.rstrip('/')}/{path}" if path else TARGET_BASE_URL.rstrip('/')
35
+
36
+ headers = {}
37
+ for key, value in request.headers.items():
38
+ if key.lower() in ["host", "content-length", "connection", "authorization", "transfer-encoding"]:
39
+ continue
40
+ headers[key] = value
41
+ headers["Authorization"] = f"Bearer {REAL_API_KEY}"
42
+
43
+ body = await request.body()
44
+ query_params = dict(request.query_params)
45
+
46
+ is_stream = False
47
+ if body:
48
+ try:
49
+ is_stream = json.loads(body).get("stream", False)
50
+ except:
51
+ pass
52
+
53
+ session = request.app.state.session
54
+ timeout = aiohttp.ClientTimeout(total=None, connect=10, sock_read=60)
55
+
56
+ resp = await session.request(
57
+ method=request.method,
58
+ url=target_url,
59
+ headers=headers,
60
+ data=body,
61
+ params=query_params,
62
+ timeout=timeout
63
+ )
64
+
65
+ if is_stream or "text/event-stream" in resp.headers.get("content-type", ""):
66
+ async def stream_generator():
67
+ try:
68
+ async for chunk in resp.content.iter_any():
69
+ yield chunk
70
+ except:
71
+ pass
72
+ finally:
73
+ resp.close()
74
+ return StreamingResponse(
75
+ stream_generator(),
76
+ media_type=resp.headers.get("content-type", "text/event-stream"),
77
+ headers={
78
+ "cache-control": "no-cache",
79
+ "connection": "keep-alive",
80
+ "access-control-allow-origin": "*"
81
+ }
82
+ )
83
+ else:
84
+ content = await resp.read()
85
+ resp.close()
86
+ return Response(
87
+ content=content,
88
+ status_code=resp.status,
89
+ headers={
90
+ "content-type": resp.headers.get("content-type", "application/json"),
91
+ "access-control-allow-origin": "*"
92
+ }
93
+ )
requirements.txt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ fastapi
2
+ uvicorn
3
+ aiohttp