From 8d83050a64c35a2cb163ffe3799abf9904e2236a Mon Sep 17 00:00:00 2001 From: Stan Zubarev Date: Thu, 31 Oct 2024 19:34:50 -0400 Subject: [PATCH 1/6] add Amazon Bedrock provider --- simplemind/providers/__init__.py | 3 +- simplemind/providers/amazon.py | 85 ++++++++++++++++++++++++++++++++ simplemind/settings.py | 3 ++ 3 files changed, 90 insertions(+), 1 deletion(-) create mode 100644 simplemind/providers/amazon.py diff --git a/simplemind/providers/__init__.py b/simplemind/providers/__init__.py index 201f851..cc6c465 100644 --- a/simplemind/providers/__init__.py +++ b/simplemind/providers/__init__.py @@ -7,5 +7,6 @@ from .groq import Groq from .ollama import Ollama from .openai import OpenAI from .xai import XAI +from .amazon import Amazon -providers: List[Type[BaseProvider]] = [Anthropic, Gemini, Groq, OpenAI, Ollama, XAI] +providers: List[Type[BaseProvider]] = [Anthropic, Gemini, Groq, OpenAI, Ollama, XAI, Amazon] diff --git a/simplemind/providers/amazon.py b/simplemind/providers/amazon.py new file mode 100644 index 0000000..f4a9ede --- /dev/null +++ b/simplemind/providers/amazon.py @@ -0,0 +1,85 @@ +from typing import Union +import json + +import instructor +import anthropic + +from ._base import BaseProvider +from ..settings import settings + +PROVIDER_NAME = "amazon" +DEFAULT_MODEL = "anthropic.claude-3-sonnet-20240229-v1:0" +DEFAULT_MAX_TOKENS = 5000 + +class Amazon(BaseProvider): + NAME = PROVIDER_NAME + DEFAULT_MODEL = DEFAULT_MODEL + + def __init__(self, api_key: Union[str, None] = None): + self.api_key = api_key or settings.get_api_key(PROVIDER_NAME) + + @property + def client(self): + """The AnthropicBedrock client.""" + if not self.api_key: + raise ValueError("Profile name is not provided") + + return anthropic.AnthropicBedrock(aws_profile=self.api_key) + + @property + def structured_client(self): + """A client patched with Instructor.""" + return instructor.from_anthropic(self.client) + + def send_conversation(self, conversation: "Conversation", **kwargs): + """Send a conversation to the OpenAI API.""" + from ..models import Message + + messages = [ + {"role": msg.role, "content": msg.text} for msg in conversation.messages + ] + + response = self.client.chat.completions.create( + model=conversation.llm_model or DEFAULT_MODEL, messages=messages, **kwargs + ) + + # Get the response content from the OpenAI response + assistant_message = response.choices[0].message + + # Create and return a properly formatted Message instance + return Message( + role="assistant", + text=assistant_message.content or "", + raw=response, + llm_model=conversation.llm_model or DEFAULT_MODEL, + llm_provider=PROVIDER_NAME, + ) + + def structured_response(self, prompt, response_model, *, llm_model: str, **kwargs): + # Ensure messages are provided in kwargs + messages = [ + {"role": "user", "content": prompt}, + ] + + response = self.structured_client.chat.completions.create( + messages=messages, + model=llm_model or self.DEFAULT_MODEL, + response_model=response_model, + max_tokens=DEFAULT_MAX_TOKENS, + **kwargs, + ) + return response + + def generate_text(self, prompt, *, llm_model, **kwargs): + messages = [ + {"role": "user", "content": prompt}, + ] + + response = self.client.messages.create( + model=llm_model or self.DEFAULT_MODEL, + messages=messages, + max_tokens=DEFAULT_MAX_TOKENS, + **kwargs, + ) + + return response.content[0].text \ No newline at end of file diff --git a/simplemind/settings.py b/simplemind/settings.py index d561228..d840ae7 100644 --- a/simplemind/settings.py +++ b/simplemind/settings.py @@ -18,6 +18,9 @@ class LoggingConfig(BaseSettings): class Settings(BaseSettings): """The class that holds all the API keys for the application.""" + AMAZON_API_KEY: Optional[SecretStr] = Field( + "default", description="AWS Named Profile" + ) ANTHROPIC_API_KEY: Optional[SecretStr] = Field( None, description="API key for Anthropic" ) From 25b742db1fc445935e162b3fa3572ee351a57281 Mon Sep 17 00:00:00 2001 From: Stan Zubarev Date: Thu, 31 Oct 2024 19:50:51 -0400 Subject: [PATCH 2/6] remove profile --- simplemind/settings.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/simplemind/settings.py b/simplemind/settings.py index d840ae7..ad604a5 100644 --- a/simplemind/settings.py +++ b/simplemind/settings.py @@ -18,9 +18,7 @@ class LoggingConfig(BaseSettings): class Settings(BaseSettings): """The class that holds all the API keys for the application.""" - AMAZON_API_KEY: Optional[SecretStr] = Field( - "default", description="AWS Named Profile" - ) + AMAZON_API_KEY: Optional[SecretStr] = Field(None, description="AWS Named Profile") ANTHROPIC_API_KEY: Optional[SecretStr] = Field( None, description="API key for Anthropic" ) From f19263d309183d7572bc5c8a7a392d6389edee09 Mon Sep 17 00:00:00 2001 From: Stan Zubarev Date: Thu, 31 Oct 2024 20:49:13 -0400 Subject: [PATCH 3/6] update reaadme --- README.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 7728df2..cedcd16 100644 --- a/README.md +++ b/README.md @@ -24,10 +24,12 @@ To specify a specific provider or model, you can use the `llm_provider` and `llm - [**Ollama**](https://ollama.com) - [**OpenAI's GPT**](https://openai.com/gpt) - [**xAI's Grok**](https://x.ai/) +- [**Amazon Bedrock**](https://aws.amazon.com/bedrock/) If you want to see Simplemind support, additional providers or models, please send a pull request! ## Why SimpleMind? + - **Intuitive**: Built with Pythonic simplicity and readability in mind. - **For Humans**: Emphasizes a human-friendly interface, just like `requests` for HTTP. - **Open Source**: Simplemind is open source, and contributions are always welcome! @@ -56,7 +58,6 @@ Next, import Simplemind and start using it: import simplemind as sm ``` - ## Examples Here are some examples of how to use Simplemind: @@ -163,6 +164,7 @@ conversation.add_message( text="Please write a poem about the moon", ) ``` + ```pycon >>> conversation.send() In the vast expanse where stars do play, @@ -200,9 +202,10 @@ Simple, yet effective. Please see the [examples](examples) directory for executable examples. -------------------- +--- ## Contributing + We welcome contributions of all kinds. Feel free to open issues for bug reports or feature requests, and submit pull requests to make SimpleMind even better. To get started: @@ -213,8 +216,9 @@ To get started: 4. Submit a pull request. ## License + Simplemind is licensed under the Apache 2.0 License. ## Acknowledgements -Simplemind is inspired by the philosophy of "code for humans" and aims to make working with AI models accessible to all. Special thanks to the open-source community for their contributions and inspiration. +Simplemind is inspired by the philosophy of "code for humans" and aims to make working with AI models accessible to all. Special thanks to the open-source community for their contributions and inspiration. From 2a5966eb10415cdbe1b09d270e2a0a1e5a272c59 Mon Sep 17 00:00:00 2001 From: Stan Zubarev Date: Thu, 31 Oct 2024 20:50:42 -0400 Subject: [PATCH 4/6] fix tests --- tests/test_generate_data.py | 3 ++- tests/test_generate_text.py | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/test_generate_data.py b/tests/test_generate_data.py index bea35c8..b622cad 100644 --- a/tests/test_generate_data.py +++ b/tests/test_generate_data.py @@ -1,6 +1,6 @@ import pytest -from simplemind.providers import Anthropic, Gemini, OpenAI, Groq, Ollama +from simplemind.providers import Anthropic, Gemini, OpenAI, Groq, Ollama, Amazon from pydantic import BaseModel @@ -16,6 +16,7 @@ class ResponseModel(BaseModel): OpenAI, Groq, Ollama, + Amazon ], ) def test_generate_data(provider_cls): diff --git a/tests/test_generate_text.py b/tests/test_generate_text.py index 55a9a13..0611b1d 100644 --- a/tests/test_generate_text.py +++ b/tests/test_generate_text.py @@ -1,6 +1,6 @@ import pytest -from simplemind.providers import Anthropic, Gemini, OpenAI, Groq, Ollama +from simplemind.providers import Anthropic, Gemini, OpenAI, Groq, Ollama, Amazon @pytest.mark.parametrize( @@ -11,6 +11,7 @@ from simplemind.providers import Anthropic, Gemini, OpenAI, Groq, Ollama OpenAI, Groq, Ollama, + Amazon, ], ) def test_generate_text(provider_cls): From c25f1e1058185d18d855dc4dbad7853100335c87 Mon Sep 17 00:00:00 2001 From: Stan Zubarev Date: Thu, 31 Oct 2024 20:50:57 -0400 Subject: [PATCH 5/6] rename parameter --- simplemind/providers/amazon.py | 18 ++++++++++-------- simplemind/settings.py | 2 +- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/simplemind/providers/amazon.py b/simplemind/providers/amazon.py index f4a9ede..7cf3e41 100644 --- a/simplemind/providers/amazon.py +++ b/simplemind/providers/amazon.py @@ -1,12 +1,14 @@ -from typing import Union -import json +from typing import Type, TypeVar import instructor import anthropic +from pydantic import BaseModel from ._base import BaseProvider from ..settings import settings +T = TypeVar("T", bound=BaseModel) + PROVIDER_NAME = "amazon" DEFAULT_MODEL = "anthropic.claude-3-sonnet-20240229-v1:0" DEFAULT_MAX_TOKENS = 5000 @@ -15,16 +17,16 @@ class Amazon(BaseProvider): NAME = PROVIDER_NAME DEFAULT_MODEL = DEFAULT_MODEL - def __init__(self, api_key: Union[str, None] = None): - self.api_key = api_key or settings.get_api_key(PROVIDER_NAME) + def __init__(self, profile_name: str | None = None): + self.profile_name = profile_name or settings.AMAZON_PROFILE_NAME @property def client(self): """The AnthropicBedrock client.""" - if not self.api_key: + if not self.profile_name: raise ValueError("Profile name is not provided") - return anthropic.AnthropicBedrock(aws_profile=self.api_key) + return anthropic.AnthropicBedrock(aws_profile=self.profile_name) @property def structured_client(self): @@ -55,7 +57,7 @@ class Amazon(BaseProvider): llm_provider=PROVIDER_NAME, ) - def structured_response(self, prompt, response_model, *, llm_model: str, **kwargs): + def structured_response(self, prompt, response_model: Type[T], *, llm_model: str | None = None, **kwargs) -> T: # Ensure messages are provided in kwargs messages = [ {"role": "user", "content": prompt}, @@ -65,7 +67,7 @@ class Amazon(BaseProvider): messages=messages, model=llm_model or self.DEFAULT_MODEL, response_model=response_model, - max_tokens=DEFAULT_MAX_TOKENS, + max_tokens = DEFAULT_MAX_TOKENS, **kwargs, ) return response diff --git a/simplemind/settings.py b/simplemind/settings.py index ad604a5..5e28629 100644 --- a/simplemind/settings.py +++ b/simplemind/settings.py @@ -18,7 +18,7 @@ class LoggingConfig(BaseSettings): class Settings(BaseSettings): """The class that holds all the API keys for the application.""" - AMAZON_API_KEY: Optional[SecretStr] = Field(None, description="AWS Named Profile") + AMAZON_PROFILE_NAME: Optional[str] = Field("default", description="AWS Named Profile") ANTHROPIC_API_KEY: Optional[SecretStr] = Field( None, description="API key for Anthropic" ) From 75c42278a22c4ca705399a1518f6c4500428c6fc Mon Sep 17 00:00:00 2001 From: Stan Zubarev Date: Thu, 31 Oct 2024 20:55:56 -0400 Subject: [PATCH 6/6] add parameter to env template --- .envrc.template | 1 + 1 file changed, 1 insertion(+) diff --git a/.envrc.template b/.envrc.template index 16f0415..f41818c 100644 --- a/.envrc.template +++ b/.envrc.template @@ -4,3 +4,4 @@ export GROQ_API_KEY="" export OLLAMA_HOST_URL="" export OPENAI_API_KEY="" export XAI_API_KEY="" +export AMAZON_PROFILE_NAME=""