返回提交历史
Modified
g4f/api/__init__.py
+32
-0
XFEstudio/gpt4free
fix(api): detect client disconnection to cancel streaming requests promptly
fcc7566c
代码差异
1 个文件
+32
-0
@@ -807,6 +807,7 @@ class Api:
807
807
)
808
808
async def chat_completions(
809
809
config: ChatCompletionsConfig,
810
request: Request = None,
810
811
credentials: Annotated[
811
812
HTTPAuthorizationCredentials, Depends(Api.security)
812
813
] = None,
@@ -918,6 +919,9 @@ class Api:
918
919
yield f"data: {first_chunk.model_dump_json() if hasattr(first_chunk, 'model_dump_json') else first_chunk.json()}\n\n"
919
920
try:
920
921
async for chunk in response:
922
if request is not None and await request.is_disconnected():
923
debug.log("Client disconnected, aborting streaming response.")
924
return
921
925
if isinstance(chunk, BaseConversation):
922
926
if (
923
927
config.conversation_id is not None
@@ -938,6 +942,12 @@ class Api:
938
942
except Exception as e:
939
943
logger.exception(e)
940
944
yield f"data: {format_exception(e, config)}\n\n"
945
finally:
946
if hasattr(response, "aclose"):
947
try:
948
await response.aclose()
949
except Exception:
950
pass
941
951
yield "data: [DONE]\n\n"
942
952
943
953
headers = (
@@ -978,6 +988,7 @@ class Api:
978
988
@self.app.post("/api/{provider:path}/responses", responses=responses)
979
989
async def create_response(
980
990
config: ResponsesConfig,
991
request: Request = None,
981
992
credentials: Annotated[
982
993
HTTPAuthorizationCredentials, Depends(Api.security)
983
994
] | None = None,
@@ -1066,6 +1077,9 @@ class Api:
1066
1077
yield f"data: {first_chunk.model_dump_json() if hasattr(first_chunk, 'model_dump_json') else first_chunk.json()}\n\n"
1067
1078
try:
1068
1079
async for chunk in response:
1080
if request is not None and await request.is_disconnected():
1081
debug.log("Client disconnected, aborting responses stream.")
1082
return
1069
1083
if isinstance(chunk, BaseConversation):
1070
1084
pass
1071
1085
else:
@@ -1078,6 +1092,12 @@ class Api:
1078
1092
except Exception as e:
1079
1093
logger.exception(e)
1080
1094
yield f"data: {format_exception(e, config)}\n\n"
1095
finally:
1096
if hasattr(response, "aclose"):
1097
try:
1098
await response.aclose()
1099
except Exception:
1100
pass
1081
1101
yield "data: [DONE]\n\n"
1082
1102
1083
1103
headers = (
@@ -1120,6 +1140,7 @@ class Api:
1120
1140
@self.app.post("/api/{provider:path}/messages", responses=responses)
1121
1141
async def create_message(
1122
1142
config: MessagesConfig,
1143
request: Request = None,
1123
1144
credentials: Annotated[
1124
1145
HTTPAuthorizationCredentials, Depends(Api.security)
1125
1146
] = None,
@@ -1210,6 +1231,9 @@ class Api:
1210
1231
yield f"data: {first_chunk.model_dump_json() if hasattr(first_chunk, 'model_dump_json') else first_chunk.json()}\n\n"
1211
1232
try:
1212
1233
async for chunk in response:
1234
if request is not None and await request.is_disconnected():
1235
debug.log("Client disconnected, aborting messages stream.")
1236
return
1213
1237
if isinstance(chunk, BaseConversation):
1214
1238
pass
1215
1239
else:
@@ -1222,6 +1246,12 @@ class Api:
1222
1246
except Exception as e:
1223
1247
logger.exception(e)
1224
1248
yield f"data: {format_exception(e, config)}\n\n"
1249
finally:
1250
if hasattr(response, "aclose"):
1251
try:
1252
await response.aclose()
1253
except Exception:
1254
pass
1225
1255
yield "data: [DONE]\n\n"
1226
1256
1227
1257
headers = (
@@ -2233,6 +2263,8 @@ class Api:
2233
2263
async def stream():
2234
2264
with open(result, "rb") as file:
2235
2265
while True:
2266
if request is not None and await request.is_disconnected():
2267
break
2236
2268
chunk = file.read(65536)
2237
2269
if not chunk:
2238
2270
break