Files changed (1) hide show
  1. app.py +88 -30
app.py CHANGED
@@ -1061,16 +1061,22 @@ async def tiers():
1061
  async def websocket_chat(ws: WebSocket):
1062
  ip = ws.client.host
1063
 
 
1064
  await ws.accept()
1065
 
1066
- # rate limit auth attempts
1067
  if not check_ws_auth_rate_limit(ip):
1068
  await ws.close(code=4408)
1069
  return
1070
 
1071
  try:
 
1072
  auth_msg = await ws.receive_text()
1073
- auth_data = json.loads(auth_msg)
 
 
 
 
1074
 
1075
  provided_key = auth_data.get("key")
1076
 
@@ -1078,45 +1084,97 @@ async def websocket_chat(ws: WebSocket):
1078
  await ws.close(code=4403)
1079
  return
1080
 
1081
- # authenticated
1082
- await ws.send_json({"type": "auth", "status": "ok"})
1083
-
1084
- while True:
1085
- msg = await ws.receive_text()
1086
- data = json.loads(msg)
1087
-
1088
- body = data.get("body")
1089
- headers = data.get("headers", {})
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1090
 
1091
- if not body:
1092
- await ws.send_json({"error": "Missing body"})
1093
- continue
 
 
 
 
 
 
1094
 
1095
- url = str(ws.url).replace("ws://", "http://").replace("wss://", "https://")
1096
- url = url.split("/ws/chat")[0] + "/gen/chat/completions"
 
 
 
 
1097
 
1098
- async with httpx.AsyncClient(timeout=None) as client:
1099
- async with client.stream(
1100
- "POST",
1101
- url,
1102
- json=body,
1103
- headers=headers,
1104
- ) as r:
1105
 
1106
- async for line in r.aiter_lines():
1107
- if not line:
1108
- continue
 
1109
 
1110
- await ws.send_text(line)
 
 
 
 
1111
 
1112
  except WebSocketDisconnect:
1113
  return
 
1114
  except Exception as e:
1115
  try:
1116
- await ws.send_json({"error": str(e)})
1117
- except:
 
 
 
 
 
 
 
 
1118
  pass
1119
- await ws.close()
1120
 
1121
  @app.get("/portal")
1122
  @app.post("/portal")
 
1061
  async def websocket_chat(ws: WebSocket):
1062
  ip = ws.client.host
1063
 
1064
+ # Accept connection
1065
  await ws.accept()
1066
 
1067
+ # Basic connection rate limiting
1068
  if not check_ws_auth_rate_limit(ip):
1069
  await ws.close(code=4408)
1070
  return
1071
 
1072
  try:
1073
+ # Expect an auth message first
1074
  auth_msg = await ws.receive_text()
1075
+ try:
1076
+ auth_data = json.loads(auth_msg)
1077
+ except Exception:
1078
+ await ws.close(code=4400)
1079
+ return
1080
 
1081
  provided_key = auth_data.get("key")
1082
 
 
1084
  await ws.close(code=4403)
1085
  return
1086
 
1087
+ # Auth success
1088
+ await ws.send_json({
1089
+ "type": "auth",
1090
+ "status": "ok"
1091
+ })
1092
+
1093
+ # Internal endpoint (avoids Hugging Face proxy redirect)
1094
+ internal_url = "http://127.0.0.1:7860/gen/chat/completions"
1095
+
1096
+ # Persistent HTTP client for streaming
1097
+ async with httpx.AsyncClient(
1098
+ timeout=None,
1099
+ follow_redirects=False
1100
+ ) as client:
1101
+
1102
+ while True:
1103
+ try:
1104
+ msg = await ws.receive_text()
1105
+ except WebSocketDisconnect:
1106
+ break
1107
+
1108
+ try:
1109
+ data = json.loads(msg)
1110
+ except Exception:
1111
+ await ws.send_json({"error": "Invalid JSON"})
1112
+ continue
1113
+
1114
+ body = data.get("body")
1115
+ headers = data.get("headers") or {}
1116
+
1117
+ if not body:
1118
+ await ws.send_json({"error": "Missing body"})
1119
+ continue
1120
+
1121
+ try:
1122
+ async with client.stream(
1123
+ "POST",
1124
+ internal_url,
1125
+ json=body,
1126
+ headers=headers
1127
+ ) as response:
1128
 
1129
+ # Handle upstream errors
1130
+ if response.status_code >= 400:
1131
+ error_text = ""
1132
+ try:
1133
+ error_text = (await response.aread()).decode(
1134
+ "utf-8", errors="replace"
1135
+ )[:500]
1136
+ except Exception:
1137
+ pass
1138
 
1139
+ await ws.send_json({
1140
+ "error": "Upstream request failed",
1141
+ "status": response.status_code,
1142
+ "detail": error_text
1143
+ })
1144
+ continue
1145
 
1146
+ # Stream tokens/lines to the websocket
1147
+ async for line in response.aiter_lines():
1148
+ if not line:
1149
+ continue
 
 
 
1150
 
1151
+ try:
1152
+ await ws.send_text(line)
1153
+ except RuntimeError:
1154
+ break
1155
 
1156
+ except Exception as stream_error:
1157
+ await ws.send_json({
1158
+ "error": "Streaming error",
1159
+ "detail": str(stream_error)
1160
+ })
1161
 
1162
  except WebSocketDisconnect:
1163
  return
1164
+
1165
  except Exception as e:
1166
  try:
1167
+ await ws.send_json({
1168
+ "error": "Server error",
1169
+ "detail": str(e)
1170
+ })
1171
+ except Exception:
1172
+ pass
1173
+
1174
+ try:
1175
+ await ws.close()
1176
+ except Exception:
1177
  pass
 
1178
 
1179
  @app.get("/portal")
1180
  @app.post("/portal")