XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet
公开
关注 0 Fork 0 Star 1
返回提交历史

XFEstudio/gpt4free

fix(api): detect client disconnection to cancel streaming requests promptly

fcc7566c
Anand Mall <anand@example.com>
提交于

代码差异

1 个文件 +32 -0
Modified g4f/api/__init__.py +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