2ch commited on
Commit
c88ec8a
·
verified ·
1 Parent(s): e2b570b

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +148 -0
app.py ADDED
@@ -0,0 +1,148 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from datetime import datetime
2
+ from json import dumps, loads
3
+ from re import sub
4
+ from urllib.parse import urlparse, urlunparse
5
+
6
+ from fastapi import FastAPI, Request
7
+ from fastapi.responses import JSONResponse, StreamingResponse, HTMLResponse
8
+ from httpx import AsyncClient, Limits, Timeout
9
+
10
+ app = FastAPI(title='PROXI-API')
11
+
12
+ MODELS = [
13
+ 'deepseek-ai/DeepSeek-R1',
14
+ 'deepseek-ai/DeepSeek-V3',
15
+ 'deepseek-ai/deepseek-llm-67b-chat',
16
+ 'databricks/dbrx-instruct',
17
+ 'Qwen/QwQ-32B-Preview',
18
+ 'NousResearch/Nous-Hermes-2-Mixtral-8x7B-DPO'
19
+ ]
20
+
21
+ MODELS_OBJ = {
22
+ 'object': 'list',
23
+ 'data': [
24
+ {
25
+ 'id': model,
26
+ 'object': 'model',
27
+ 'created': int(datetime.now().timestamp()),
28
+ 'owned_by': 'blackbox.ai'
29
+ }
30
+ for model in MODELS
31
+ ]
32
+ }
33
+
34
+ BLOCKED_HEADERS = [
35
+ 'x-forwarded-for',
36
+ 'x-real-ip',
37
+ 'proxy-authorization'
38
+ ]
39
+
40
+ HTTPX_CLIENT_KWARGS = dict(
41
+ timeout=Timeout(
42
+ connect=15,
43
+ read=60,
44
+ write=30,
45
+ pool=30
46
+ ),
47
+ limits=Limits(
48
+ max_keepalive_connections=10,
49
+ max_connections=100
50
+ ),
51
+ follow_redirects=True,
52
+ http2=True,
53
+ verify=False
54
+ )
55
+
56
+
57
+ def normalize_headers(request: Request, original_url: str) -> dict:
58
+ headers = {
59
+ key: value for (key, value) in request.headers.items()
60
+ if key.lower() not in BLOCKED_HEADERS and key.lower() != 'host'
61
+ }
62
+ parsed_url = urlparse(original_url)
63
+ origin = urlunparse((parsed_url.scheme, parsed_url.netloc, '', '', '', ''))
64
+ normalized = {key.lower(): value for key, value in headers.items()}
65
+ normalized['referer'] = original_url
66
+ normalized['origin'] = origin
67
+ normalized['accept-encoding'] = 'deflate'
68
+ return normalized
69
+
70
+
71
+ def format_chunk(chunk: bytes, model: str) -> bytes | str | dict:
72
+ chunk_id = 'chatcmpl-AQ8Lzxlg8eSCB1lgVmboiXwZiexqE'
73
+ timestamp = int(datetime.now().timestamp())
74
+ data = {
75
+ "id": chunk_id,
76
+ "object": "chat.completion.chunk",
77
+ "created": timestamp,
78
+ "model": model,
79
+ "system_fingerprint": "fp_67802d9a6d",
80
+ "choices": [
81
+ {
82
+ "index": 0,
83
+ "delta": {
84
+ "content": chunk.decode()
85
+ },
86
+ "finish_reason": None
87
+ }
88
+ ]
89
+ }
90
+ json_data = dumps(data, ensure_ascii=False)
91
+ str_data = f'data: {sub(r'\\\\([ntr])', r'\\\1', json_data)}\n\n'
92
+ return str_data
93
+
94
+
95
+ async def generate(request: Request, url: str, headers: dict, body: bytes):
96
+ body_str = body.decode('utf-8')
97
+ body_obj: dict = loads(body_str)
98
+ model = body_obj.get('model')
99
+ if 'max_tokens' not in body_obj:
100
+ body_obj['max_tokens'] = '32000'
101
+ body = dumps(body_obj, ensure_ascii=False).encode()
102
+ headers = dict(headers)
103
+ headers['content-length'] = str(len(body))
104
+ headers['content-type'] = 'application/json'
105
+ async with AsyncClient(**HTTPX_CLIENT_KWARGS) as stream_client:
106
+ async with stream_client.stream(method=request.method, url=url, headers=headers, content=body, cookies=request.cookies) as stream:
107
+ async for chunk in stream.aiter_raw():
108
+ yield format_chunk(chunk, model)
109
+ yield 'data: [DONE]\n\n'.encode()
110
+
111
+
112
+ @app.post('/api/chat/completions')
113
+ @app.post('/api/v1/chat/completions')
114
+ async def proxy(request: Request):
115
+ try:
116
+ url = 'https://api.blackbox.ai/api/chat'
117
+ headers = normalize_headers(request, url)
118
+ body = await request.body()
119
+ async with AsyncClient(**HTTPX_CLIENT_KWARGS) as headers_client:
120
+ async with headers_client.stream(method=request.method, url=url, headers=headers, content=body, cookies=request.cookies) as response:
121
+ excluded_headers = ['content-encoding', 'content-length', 'transfer-encoding', 'connection']
122
+ filtered_headers = {
123
+ name: value for (name, value) in response.headers.items()
124
+ if name.lower() not in excluded_headers
125
+ }
126
+ return StreamingResponse(generate(request, url, headers, body), status_code=response.status_code, headers=filtered_headers)
127
+
128
+ except Exception as exc:
129
+ return JSONResponse({'error': response.status_code, 'body': f'{exc}'}, status_code=500)
130
+
131
+
132
+ @app.get('/')
133
+ @app.get('/api')
134
+ @app.get('/api/v1')
135
+ async def root():
136
+ return HTMLResponse('ну пролапс, ну и что', status_code=200)
137
+
138
+
139
+ @app.get('/api/models')
140
+ @app.get('/api/v1/models')
141
+ async def models():
142
+ return JSONResponse(MODELS_OBJ, status_code=200, media_type='application/json')
143
+
144
+
145
+ if __name__ == '__main__':
146
+ import uvicorn
147
+ port = 7860
148
+ uvicorn.run(app, host='0.0.0.0', port=port)