Skip to content

Commit 6575d1f

Browse files
committed
fix: Correctly handle error tokens in chat and deepnews streams
1 parent ef2d03b commit 6575d1f

File tree

4 files changed

+97
-5
lines changed

4 files changed

+97
-5
lines changed

asknews_sdk/api/chat.py

Lines changed: 69 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
CreateChatCompletionRequest,
1010
CreateChatCompletionResponse,
1111
CreateChatCompletionResponseStream,
12+
CreateChatCompletionResponseStreamError,
1213
FilterParamsResponse,
1314
ForecastResponse,
1415
HeadlineQuestionsResponse,
@@ -21,8 +22,10 @@
2122
CreateDeepNewsResponse,
2223
CreateDeepNewsResponseStream,
2324
CreateDeepNewsResponseStreamChunk,
25+
CreateDeepNewsResponseStreamError,
2426
CreateDeepNewsResponseStreamSource,
2527
)
28+
from asknews_sdk.errors import APIError
2629
from asknews_sdk.response import EventSource
2730

2831

@@ -120,7 +123,23 @@ def _stream():
120123
for event in EventSource.from_api_response(response):
121124
if event.content == "[DONE]":
122125
break
123-
yield CreateChatCompletionResponseStream.model_validate_json(event.content)
126+
127+
token = (
128+
TypeAdapter(Union[
129+
CreateChatCompletionResponseStreamError,
130+
CreateChatCompletionResponseStream
131+
])
132+
.validate_json(event.content)
133+
)
134+
135+
if isinstance(token, CreateChatCompletionResponseStreamError):
136+
raise APIError(
137+
response=response,
138+
detail=token.error.message,
139+
code=token.error.code,
140+
)
141+
142+
yield token
124143

125144
return _stream()
126145
else:
@@ -524,7 +543,22 @@ def _stream():
524543
if event.content == "[DONE]":
525544
break
526545

527-
yield TypeAdapter(CreateDeepNewsResponseStream).validate_json(event.content)
546+
token = (
547+
TypeAdapter(Union[
548+
CreateDeepNewsResponseStreamError,
549+
CreateDeepNewsResponseStream
550+
])
551+
.validate_json(event.content)
552+
)
553+
554+
if isinstance(token, CreateDeepNewsResponseStreamError):
555+
raise APIError(
556+
response=response,
557+
detail=token.error.message,
558+
code=token.error.code,
559+
)
560+
561+
yield token
528562

529563
return _stream()
530564
else:
@@ -625,7 +659,23 @@ async def _stream():
625659
async for event in EventSource.from_api_response(response):
626660
if event.content == "[DONE]":
627661
break
628-
yield CreateChatCompletionResponseStream.model_validate_json(event.content)
662+
663+
token = (
664+
TypeAdapter(Union[
665+
CreateChatCompletionResponseStreamError,
666+
CreateChatCompletionResponseStream
667+
])
668+
.validate_json(event.content)
669+
)
670+
671+
if isinstance(token, CreateChatCompletionResponseStreamError):
672+
raise APIError(
673+
response=response,
674+
detail=token.error.message,
675+
code=token.error.code,
676+
)
677+
678+
yield token
629679

630680
return _stream()
631681
else:
@@ -1022,13 +1072,27 @@ async def get_deep_news(
10221072
)
10231073

10241074
if stream:
1025-
10261075
async def _stream():
10271076
async for event in EventSource.from_api_response(response):
10281077
if event.content == "[DONE]":
10291078
break
10301079

1031-
yield TypeAdapter(CreateDeepNewsResponseStream).validate_json(event.content)
1080+
token = (
1081+
TypeAdapter(Union[
1082+
CreateDeepNewsResponseStreamError,
1083+
CreateDeepNewsResponseStream
1084+
])
1085+
.validate_json(event.content)
1086+
)
1087+
1088+
if isinstance(token, CreateDeepNewsResponseStreamError):
1089+
raise APIError(
1090+
response=response,
1091+
detail=token.error.message,
1092+
code=token.error.code,
1093+
)
1094+
1095+
yield token
10321096

10331097
return _stream()
10341098
else:

asknews_sdk/dto/chat.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,17 @@ class CreateChatCompletionResponseStream(BaseSchema):
9797
choices: Annotated[List[CreateChatCompletionResponseStreamChoice], Field(title="Choices")]
9898

9999

100+
class CreateChatCompletionResponseStreamErrorDetails(BaseModel):
101+
message: Annotated[str, Field(title="Message")]
102+
code: Annotated[int, Field(title="Code")]
103+
104+
105+
class CreateChatCompletionResponseStreamError(BaseSchema):
106+
__content_type__ = "text/event-stream"
107+
108+
error: Annotated[CreateChatCompletionResponseStreamErrorDetails, Field(title="Error")]
109+
110+
100111
class ModelItem(BaseModel):
101112
id: Annotated[str, Field(title="Id")]
102113
object: Annotated[Optional[str], Field("model", title="Object")]

asknews_sdk/dto/deepnews.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,17 @@ class CreateDeepNewsResponseStreamSource(BaseSchema):
194194
]
195195

196196

197+
class CreateDeepNewsResponseStreamErrorDetails(BaseModel):
198+
code: Annotated[int, Field(title="Code")]
199+
message: Annotated[str, Field(title="Message")]
200+
201+
202+
class CreateDeepNewsResponseStreamError(BaseSchema):
203+
__content_type__ = "text/event-stream"
204+
205+
error: Annotated[CreateDeepNewsResponseStreamErrorDetails, Field(title="Error")]
206+
207+
197208
CreateDeepNewsResponseStream: TypeAlias = Annotated[
198209
Union[
199210
Annotated[CreateDeepNewsResponseStreamChunk, Tag("chat.completion.chunk")],

asknews_sdk/errors.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,11 @@ class MethodNotAllowed(APIError):
4949
detail = "Method Not Allowed"
5050

5151

52+
class RequestTimeoutError(APIError):
53+
code = 408000
54+
detail = "Request Timeout"
55+
56+
5257
class RateLimitExceededError(APIError):
5358
code = 429000
5459
detail = "Rate Limit Exceeded"
@@ -87,6 +92,7 @@ class ServiceUnavailableError(APIError):
8792
403011: ForbiddenError,
8893
404000: ResourceNotFoundError,
8994
405000: MethodNotAllowed,
95+
408000: RequestTimeoutError,
9096
422000: ValidationError,
9197
429000: RateLimitExceededError,
9298
429001: ConcurrencyLimitExceededError,

0 commit comments

Comments
 (0)