-
Notifications
You must be signed in to change notification settings - Fork 10
feat: add stream support for Bedrock #191
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
14 commits
Select commit
Hold shift + click to select a range
b0dc5a8
feat: add stream support for bedrock
miri-bar 6b06c8b
chore: fix error
miri-bar f63df64
chore: fix stream examples
miri-bar b43131a
Merge branch 'main' into bedrock_streaming
miri-bar f778eea
fix: add fix for last chunk on bedrock, add tests
miri-bar b01df9e
test: fix unittests
miri-bar 661c5f5
test: remove comments
miri-bar ae2c38e
test: fix integration test
miri-bar 0c7a7d0
Merge branch 'main' into bedrock_streaming
Josephasafg 85b9137
Merge branch 'main' into bedrock_streaming
miri-bar 2364610
chore: cr comments
miri-bar 8616f4e
refactor: cr comments
miri-bar 4f48869
refactor: async stream example
miri-bar fad2c49
refactor: cr comments
miri-bar File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,92 @@ | ||
| from __future__ import annotations | ||
|
|
||
| import json | ||
| from functools import lru_cache | ||
| from typing import Iterator, AsyncIterator | ||
|
|
||
| import httpx | ||
| from botocore.eventstream import EventStreamMessage, EventStreamBuffer | ||
| from botocore.model import Shape | ||
| from botocore.parsers import EventStreamJSONParser | ||
|
|
||
| from ai21.errors import StreamingDecodeError | ||
| from ai21.stream.stream_commons import _SSEDecoderBase | ||
|
|
||
|
|
||
| _FINISH_REASON_NULL_STR = '"finish_reason":null' | ||
|
|
||
|
|
||
| @lru_cache(maxsize=None) | ||
| def get_response_stream_shape() -> Shape: | ||
| from botocore.model import ServiceModel | ||
| from botocore.loaders import Loader | ||
|
|
||
| loader = Loader() | ||
| bedrock_service_dict = loader.load_service_model("bedrock-runtime", "service-2") | ||
| bedrock_service_model = ServiceModel(bedrock_service_dict) | ||
| return bedrock_service_model.shape_for("ResponseStream") | ||
|
|
||
|
|
||
| class _AWSEventStreamDecoder(_SSEDecoderBase): | ||
| def __init__(self) -> None: | ||
| self._parser = EventStreamJSONParser() | ||
|
|
||
| def iter(self, response: httpx.Response) -> Iterator[str]: | ||
| event_stream_buffer = EventStreamBuffer() | ||
| previous_item = None | ||
| for chunk in response.iter_bytes(): | ||
| try: | ||
| item = next(self._process_chunks(event_stream_buffer, chunk)) | ||
| except StopIteration as e: | ||
| raise StreamingDecodeError(chunk=str(chunk), error_message=str(e)) | ||
| # For Bedrock metering chunk: | ||
| if previous_item is not None: | ||
| item = self._build_last_chunk(last_model_chunk=previous_item, bedrock_metrics_chunk=item) | ||
| if _FINISH_REASON_NULL_STR not in item and previous_item is None: | ||
| previous_item = item | ||
| continue | ||
| yield item | ||
|
|
||
| async def aiter(self, response: httpx.Response) -> AsyncIterator[str]: | ||
| event_stream_buffer = EventStreamBuffer() | ||
| previous_item = None | ||
| async for chunk in response.aiter_bytes(): | ||
| try: | ||
| item = next(self._process_chunks(event_stream_buffer, chunk)) | ||
| except StopIteration as e: | ||
| raise StreamingDecodeError(chunk=str(chunk), error_message=str(e)) | ||
| # For Bedrock metering chunk: | ||
| if previous_item is not None: | ||
| item = self._build_last_chunk(last_model_chunk=previous_item, bedrock_metrics_chunk=item) | ||
| if _FINISH_REASON_NULL_STR not in item and previous_item is None: | ||
| previous_item = item | ||
| continue | ||
| yield item | ||
|
|
||
| def _parse_message_from_event(self, event: EventStreamMessage) -> str | None: | ||
| response_dict = event.to_response_dict() | ||
| parsed_response = self._parser.parse(response_dict, get_response_stream_shape()) | ||
| if response_dict["status_code"] != 200: | ||
| raise ValueError(f"Bad response code, expected 200: {response_dict}") | ||
|
|
||
| chunk = parsed_response.get("chunk") | ||
| if not chunk: | ||
| return None | ||
|
|
||
| return chunk.get("bytes").decode() # type: ignore[no-any-return] | ||
|
|
||
| def _build_last_chunk(self, last_model_chunk: str, bedrock_metrics_chunk: str) -> str: | ||
| chunk_dict = json.loads(last_model_chunk) | ||
| bedrock_metrics_dict = json.loads(bedrock_metrics_chunk) | ||
| chunk_dict = {**chunk_dict, **bedrock_metrics_dict} | ||
| return json.dumps(chunk_dict) | ||
|
|
||
| def _process_chunks(self, event_stream_buffer, chunk) -> Iterator[str]: | ||
| try: | ||
| event_stream_buffer.add_data(chunk) | ||
| for event in event_stream_buffer: | ||
| message = self._parse_message_from_event(event) | ||
| if message: | ||
| yield message | ||
| except Exception as e: | ||
| raise StreamingDecodeError(chunk=str(chunk), error_message=str(e)) | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.