Skip to content
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

Add support for AWS Bedrock (Nova & Claude) #160

Merged
merged 6 commits into from
Jan 10, 2025

Conversation

Smiley73
Copy link
Contributor

@Smiley73 Smiley73 commented Jan 4, 2025

No description provided.

@valentinfrlch
Copy link
Owner

Hi, thanks for the PR! Have you tested this yet?

@Smiley73
Copy link
Contributor Author

Smiley73 commented Jan 5, 2025

Yes I have switched my HA to use this version and it's working great. I'm feeding it 15-30 jpegs extracted from Blue Iris, using nova-pro.
I ran a quick automation to capture the debug output for reference:

2025-01-05 16:21:51.878 DEBUG (MainThread) [custom_components.llmvision.providers] Found model type `us.amazon.nova-pro-v1:0` for AWS Bedrock call.
2025-01-05 16:21:51.879 DEBUG (MainThread) [custom_components.llmvision.providers] AWS Bedrock request data: {'messages': [{'role': 'user', 'content': [{'text': 'Image 1:'}, {'image': {'format': 'jpeg', 'source': {'bytes': '<long_string>'}}}, {'text': 'Image 2:'}, {'image': {'format': 'jpeg', 'source': {'bytes': '<long_string>'}}}, {'text': 'Image 3:'}, {'image': {'format': 'jpeg', 'source': {'bytes': '<long_string>'}}}, {'text': 'Image 4:'}, {'image': {'format': 'jpeg', 'source': {'bytes': '<long_string>'}}}, {'text': 'Image 5:'}, {'image': {'format': 'jpeg', 'source': {'bytes': '<long_string>'}}}, {'text': 'Image 6:'}, {'image': {'format': 'jpeg', 'source': {'bytes': '<long_string>'}}}, {'text': 'Image 7:'}, {'image': {'format': 'jpeg', 'source': {'bytes': '<long_string>'}}}, {'text': 'Image 8:'}, {'image': {'format': 'jpeg', 'source': {'bytes': '<long_string>'}}}, {'text': 'Image 9:'}, {'image': {'format': 'jpeg', 'source': {'bytes': '<long_string>'}}}, {'text': 'Image 10:'}, {'image': {'format': 'jpeg', 'source': {'bytes': '<long_string>'}}}, {'text': 'Image 11:'}, {'image': {'format': 'jpeg', 'source': {'bytes': '<long_string>'}}}, {'text': 'Image 12:'}, {'image': {'format': 'jpeg', 'source': {'bytes': '<long_string>'}}}, {'text': 'Image 13:'}, {'image': {'format': 'jpeg', 'source': {'bytes': '<long_string>'}}}, {'text': 'Image 14:'}, {'image': {'format': 'jpeg', 'source': {'bytes': '<long_string>'}}}, {'text': 'Image 15:'}, {'image': {'format': 'jpeg', 'source': {'bytes': '<long_string>'}}}, {'text': 'Image 16:'}, {'image': {'format': 'jpeg', 'source': {'bytes': '<long_string>'}}}, {'text': 'Image 17:'}, {'image': {'format': 'jpeg', 'source': {'bytes': '<long_string>'}}}, {'text': 'Image 18:'}, {'image': {'format': 'jpeg', 'source': {'bytes': '<long_string>'}}}, {'text': 'Image 19:'}, {'image': {'format': 'jpeg', 'source': {'bytes': '<long_string>'}}}, {'text': 'Image 20:'}, {'image': {'format': 'jpeg', 'source': {'bytes': '<long_string>'}}}, {'text': 'Image 21:'}, {'image': {'format': 'jpeg', 'source': {'bytes': '<long_string>'}}}, {'text': 'Image 22:'}, {'image': {'format': 'jpeg', 'source': {'bytes': '<long_string>'}}}, {'text': 'Image 23:'}, {'image': {'format': 'jpeg', 'source': {'bytes': '<long_string>'}}}, {'text': 'Image 24:'}, {'image': {'format': 'jpeg', 'source': {'bytes': '<long_string>'}}}, {'text': 'Image 25:'}, {'image': {'format': 'jpeg', 'source': {'bytes': '<long_string>'}}}, {'text': 'Image 26:'}, {'image': {'format': 'jpeg', 'source': {'bytes': '<long_string>'}}}, {'text': 'Image 27:'}, {'image': {'format': 'jpeg', 'source': {'bytes': '<long_string>'}}}, {'text': 'Image 28:'}, {'image': {'format': 'jpeg', 'source': {'bytes': '<long_string>'}}}, {'text': ''<long_string>'}]}], 'inferenceConfig': {'max_new_tokens': 1000, 'temperature': 0.1}}
2025-01-05 16:21:51.879 INFO (MainThread) [custom_components.llmvision.providers] Invoking Bedrock model us.amazon.nova-pro-v1:0 in us-east-1
2025-01-05 16:21:57.885 DEBUG (MainThread) [custom_components.llmvision.providers] AWS Bedrock call Response: {'ResponseMetadata': {'RequestId': 'f0556879-5c18-4e94-a810-f4daa6054a00', 'HTTPStatusCode': 200, 'HTTPHeaders': {'date': 'Sun, 05 Jan 2025 22:21:57 GMT', 'content-type': 'application/json', 'content-length': '468', 'connection': 'keep-alive', 'x-amzn-requestid': 'f0556879-5c18-4e94-a810-f4daa6054a00', 'x-amzn-bedrock-invocation-latency': '5696', 'x-amzn-bedrock-output-token-count': '62', 'x-amzn-bedrock-input-token-count': '19817'}, 'RetryAttempts': 0}, 'contentType': 'application/json', 'body': <botocore.response.StreamingBody object at 0x7f3e71e2b6d0>}
2025-01-05 16:21:57.885 INFO (MainThread) [custom_components.llmvision.providers] AWS Bedrock call latency: 5696 tokens_in: 19817 tokens_out: 62
2025-01-05 16:21:57.885 DEBUG (MainThread) [custom_components.llmvision.providers] AWS Bedrock call response data: {'output': {'message': {'content': [{'text': '{\n  "report": "A person was delivering mail at the front door.",\n  "explanation": "The camera named \'Front Door\' captured a person delivering mail. The person was seen interacting with the mailbox, indicating mail delivery. No other activities, vehicles, or persons were detected in the footage."\n}'}], 'role': 'assistant'}}, 'stopReason': 'end_turn', 'usage': {'inputTokens': 19817, 'outputTokens': 62, 'totalTokens': 19879}}


return response_text

async def _post(self, model, data) -> dict:
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Provider implementations shouldn't overwrite the _post method. If AWS requires special error handling those errors should be handled directly in Provider.

_LOGGER.error(f"Found unknown model type `{call.model}` for AWS Bedrock call.")
raise ServiceValidationError("Unknown model type specified. Only Nova and Claude are currently supported.")

def _prepare_vision_data_nova(self, call) -> list:
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This needs to handled in _prepare_vision_data as well as the superclass (Provider) looks like this:

async def vision_request(self, call) -> str:
        data = self._prepare_vision_data(call)
        return await self._make_request(data)

Therefore _prepare_vision_data_nova would never be called.

else:
_LOGGER.warning(f"Found unknown model type `{call.model}` for AWS Bedrock call. Will attempt `Nova`")

def _prepare_text_data_nova(self, call) -> list:
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also needs to be handled in _prepare_text_data for the same reason as vision above.

Copy link
Owner

@valentinfrlch valentinfrlch left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Amazing work so far! Just a couple of issues (see my comments). Does AWS really have different API guidelines for different models?

Also boto3 would need to be added to requirements in manifest.json see the HA dev docs here.

Thanks again for your work!

@Smiley73
Copy link
Contributor Author

Smiley73 commented Jan 6, 2025

I'll get it tackled. It'll be a couple days.
Yes Bedrock uses the native formatting for each model. Makes it easier for them to integrate I guess, but more of a pain for anybody wanting flexibility. In that case I guess it would be easier to use something like a lite-llm proxy. I'll dig through their code a bit, to see if I missed anything.

@Smiley73
Copy link
Contributor Author

Smiley73 commented Jan 7, 2025

@valentinfrlch I made the changes requested. Let me know if I misunderstood anything, my coding skills are quite rusty.
I also checked into the API format. According to their documentation, each model on Bedrock uses its native API format.

@youkorr
Copy link

youkorr commented Jan 7, 2025

Hello, your work is great, but I can't integrate DeepSeek.

@Smiley73
Copy link
Contributor Author

Smiley73 commented Jan 7, 2025

Hello, your work is great, but I can't integrate DeepSeek.

Can you be a bit more specific? DeepSeek seems to be available through the Marketplace only and you have to provision an instance?
My focus was on Nova and Anthropic through Bedrock directly. Each model has a slightly different API and needs coding.
You might be better of leveraging something like litellm-proxy and then add a custom openai endpoint to llm-vision.

@valentinfrlch
Copy link
Owner

Hello, your work is great, but I can't integrate DeepSeek.

Please create a feature request. This is a pull request for something completely unrelated.

Repository owner deleted a comment from youkorr Jan 7, 2025
Repository owner deleted a comment from youkorr Jan 7, 2025
Copy link
Owner

@valentinfrlch valentinfrlch left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code looks good to me. Thanks again for your contribution! Somehow I don't have access to any models on AWS so I can't really test this... Will check again tomorrow.

@Smiley73
Copy link
Contributor Author

Smiley73 commented Jan 8, 2025

Code looks good to me. Thanks again for your contribution! Somehow I don't have access to any models on AWS so I can't really test this... Will check again tomorrow.

You need to turn the model access on.
Go to the AWS console -> Bedrock -> Bedrock Configurations (all the way down) -> Model Access
Just turn all of them on. Give some explanation.
If they come out with new versions of the models or new ones, you'll have to do this for anything new.

Repository owner deleted a comment from youkorr Jan 9, 2025
@valentinfrlch
Copy link
Owner

During validate there is a call to _post. I think it is supposed to go to invoke_bedrock. Sorry, I missed that when reviewing.

https://github.com/Smiley73/ha-llmvision/blob/be80641b7aa2e5b7520b35c54b9b3f7448324706/custom_components/llmvision/providers.py#L892C1-L892C62

@Smiley73
Copy link
Contributor Author

Smiley73 commented Jan 9, 2025

During validate there is a call to _post. I think it is supposed to go to invoke_bedrock. Sorry, I missed that when reviewing.

https://github.com/Smiley73/ha-llmvision/blob/be80641b7aa2e5b7520b35c54b9b3f7448324706/custom_components/llmvision/providers.py#L892C1-L892C62

Of course the one thing I didn't test! Good catch. I'll fix it tonight.

@Smiley73
Copy link
Contributor Author

Should be fixed now. Sorry about that.

@valentinfrlch
Copy link
Owner

Thank you! Everything works now. The models seem to be very accurate too, so a great addition!

@valentinfrlch valentinfrlch merged commit 0f6763f into valentinfrlch:main Jan 10, 2025
4 checks passed
@Smiley73 Smiley73 deleted the aws2 branch January 10, 2025 12:00
@Smiley73
Copy link
Contributor Author

@valentinfrlch I'm going to refactor this. I must have had tunnel vision and missed a different way of invoking the models on Bedrock. Using the converse api it's a single API spec and we'll be able to support the majority of models available in AWS.
https://docs.aws.amazon.com/bedrock/latest/userguide/conversation-inference-call.html#conversation-inference-call-request

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants