Hiren122 commited on
Commit
86aa39c
·
verified ·
1 Parent(s): 36b28c0

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +54 -25
app.py CHANGED
@@ -30,6 +30,11 @@ IDENTITY_CODE = "Hiren2012805964"
30
  TARGET_MODEL = "claude-opus-4.6"
31
  INTERNAL_MODEL = "claude-sonnet-4.6"
32
 
 
 
 
 
 
33
  # Base system prompt as requested
34
  BASE_SYSTEM_PROMPT = (
35
  "You Are Claude Opus-4.6 Made By Anthropic. You Should Not reveal Your Identity "
@@ -111,25 +116,43 @@ async def proxy_request(path: str, request: Request):
111
  try:
112
  print(f"Proxying {method} to {url} using key ending in ...{api_key[-4:]}")
113
 
114
- # Use a fresh client for every request to ensure clean state
115
- async with httpx.AsyncClient(timeout=120.0, follow_redirects=True) as client:
116
- if payload and payload.get("stream", False):
117
- async def stream_generator():
118
  try:
119
  async with client.stream(method, url, headers=up_headers, json=payload) as response:
120
  print(f"Upstream Stream Status: {response.status_code}")
 
 
 
 
 
 
 
121
  async for chunk in response.aiter_lines():
122
  if not chunk: continue
 
 
 
 
 
123
  # Remap model name in stream
124
  if INTERNAL_MODEL in chunk:
125
  chunk = chunk.replace(INTERNAL_MODEL, TARGET_MODEL)
126
- yield f"{chunk}\n"
 
 
 
 
 
127
  except Exception as e:
128
  print(f"Stream Error: {e}")
129
 
130
- return StreamingResponse(stream_generator(), media_type="text/event-stream")
131
-
132
- else:
 
133
  # Use json=payload if we parsed it, otherwise raw body
134
  response = await client.request(
135
  method,
@@ -169,6 +192,8 @@ async def proxy_request(path: str, request: Request):
169
  @app.post("/v1/responses")
170
  @app.post("/v1/messages")
171
  @app.post("/v1/messeges") # user typo support
 
 
172
  async def chat_proxy_handler(request: Request):
173
  # Airforce uses /v1/chat/completions for almost everything
174
  # We strip the path to pass it correctly
@@ -177,24 +202,28 @@ async def chat_proxy_handler(request: Request):
177
 
178
  @app.get("/v1/models")
179
  async def models_proxy(request: Request):
180
- api_key = await get_next_key()
181
- headers = {"Authorization": f"Bearer {api_key}"}
182
- async with httpx.AsyncClient() as client:
183
- response = await client.get(f"{AIRFORCE_API_URL}/v1/models", headers=headers)
 
 
 
 
 
 
 
184
 
185
- try:
186
- data = response.json()
187
- if isinstance(data, dict) and "data" in data:
188
- # Inject our virtual model
189
- data["data"].append({
190
- "id": TARGET_MODEL,
191
- "object": "model",
192
- "owned_by": "anthropic",
193
- "ready": True
194
- })
195
- return data
196
- except:
197
- return response.text
198
 
199
  if __name__ == "__main__":
200
  import uvicorn
 
30
  TARGET_MODEL = "claude-opus-4.6"
31
  INTERNAL_MODEL = "claude-sonnet-4.6"
32
 
33
+ STATIC_TEXT_MODELS = ["claude-sonnet-4.6", "claude-opus-4.6", "sonar"]
34
+ STATIC_IMAGE_MODELS = [
35
+ "imagen-4", "imagen-3", "flux-3-klein-4b", "flux-2-dev", "flux-2-pro", "z-image"
36
+ ]
37
+
38
  # Base system prompt as requested
39
  BASE_SYSTEM_PROMPT = (
40
  "You Are Claude Opus-4.6 Made By Anthropic. You Should Not reveal Your Identity "
 
116
  try:
117
  print(f"Proxying {method} to {url} using key ending in ...{api_key[-4:]}")
118
 
119
+ if payload and payload.get("stream", False):
120
+ async def stream_generator():
121
+ # Use a fresh client inside the generator to keep it open during streaming
122
+ async with httpx.AsyncClient(timeout=120.0, follow_redirects=True) as client:
123
  try:
124
  async with client.stream(method, url, headers=up_headers, json=payload) as response:
125
  print(f"Upstream Stream Status: {response.status_code}")
126
+ if response.status_code != 200:
127
+ error_text = await response.aread()
128
+ print(f"Upstream Stream Error Body: {error_text.decode('utf-8')}")
129
+ yield f"data: {error_text.decode('utf-8')}\n\n"
130
+ return
131
+
132
+ first_chunk = True
133
  async for chunk in response.aiter_lines():
134
  if not chunk: continue
135
+
136
+ if first_chunk:
137
+ print(f"First Chunk: {chunk[:100]}...")
138
+ first_chunk = False
139
+
140
  # Remap model name in stream
141
  if INTERNAL_MODEL in chunk:
142
  chunk = chunk.replace(INTERNAL_MODEL, TARGET_MODEL)
143
+
144
+ # SSE format requires \n\n to separate events
145
+ # Ensure we don't duplicate newlines if chunk has them
146
+ clean_chunk = chunk.strip()
147
+ if clean_chunk:
148
+ yield f"{clean_chunk}\n\n"
149
  except Exception as e:
150
  print(f"Stream Error: {e}")
151
 
152
+ return StreamingResponse(stream_generator(), media_type="text/event-stream")
153
+
154
+ else:
155
+ async with httpx.AsyncClient(timeout=120.0, follow_redirects=True) as client:
156
  # Use json=payload if we parsed it, otherwise raw body
157
  response = await client.request(
158
  method,
 
192
  @app.post("/v1/responses")
193
  @app.post("/v1/messages")
194
  @app.post("/v1/messeges") # user typo support
195
+ @app.post("/v1/image/generations")
196
+ @app.post("/v1/images/generations")
197
  async def chat_proxy_handler(request: Request):
198
  # Airforce uses /v1/chat/completions for almost everything
199
  # We strip the path to pass it correctly
 
202
 
203
  @app.get("/v1/models")
204
  async def models_proxy(request: Request):
205
+ # Return requested static model list
206
+ models_data = []
207
+
208
+ # Text Models
209
+ for model_id in STATIC_TEXT_MODELS:
210
+ models_data.append({
211
+ "id": model_id,
212
+ "object": "model",
213
+ "created": 1677610602,
214
+ "owned_by": "anthropic" if "claude" in model_id else "airforce"
215
+ })
216
 
217
+ # Image Models
218
+ for model_id in STATIC_IMAGE_MODELS:
219
+ models_data.append({
220
+ "id": model_id,
221
+ "object": "model",
222
+ "created": 1677610602,
223
+ "owned_by": "airforce"
224
+ })
225
+
226
+ return {"object": "list", "data": models_data}
 
 
 
227
 
228
  if __name__ == "__main__":
229
  import uvicorn