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="" diff --git a/README.md b/README.md index 45f3889..6210490 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: @@ -190,6 +191,7 @@ conversation.add_message( text="Please write a poem about the moon", ) ``` + ```pycon >>> conversation.send() In the vast expanse where stars do play, @@ -233,9 +235,10 @@ Simplemind uses [logfire](https://logfire.ai) for logging. To enable logging, ca 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: @@ -246,7 +249,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. 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..7cf3e41 --- /dev/null +++ b/simplemind/providers/amazon.py @@ -0,0 +1,87 @@ +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 + +class Amazon(BaseProvider): + NAME = PROVIDER_NAME + DEFAULT_MODEL = DEFAULT_MODEL + + 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.profile_name: + raise ValueError("Profile name is not provided") + + return anthropic.AnthropicBedrock(aws_profile=self.profile_name) + + @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: Type[T], *, llm_model: str | None = None, **kwargs) -> T: + # 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 a8179b2..30efc26 100644 --- a/simplemind/settings.py +++ b/simplemind/settings.py @@ -41,6 +41,7 @@ class LoggingConfig(BaseSettings): class Settings(BaseSettings): """The class that holds all the API keys for the application.""" + AMAZON_PROFILE_NAME: Optional[str] = Field("default", description="AWS Named Profile") ANTHROPIC_API_KEY: Optional[SecretStr] = Field( None, description="API key for Anthropic" ) diff --git a/tests/test_generate_data.py b/tests/test_generate_data.py index 3d8a6e3..dc07300 100644 --- a/tests/test_generate_data.py +++ b/tests/test_generate_data.py @@ -1,7 +1,9 @@ -from pydantic import BaseModel import pytest -from simplemind.providers import Anthropic, Gemini, Groq, Ollama, OpenAI + +from simplemind.providers import Anthropic, Gemini, OpenAI, Groq, Ollama, Amazon + +from pydantic import BaseModel class ResponseModel(BaseModel): @@ -16,6 +18,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 80f062d..0611b1d 100644 --- a/tests/test_generate_text.py +++ b/tests/test_generate_text.py @@ -1,5 +1,6 @@ import pytest -from simplemind.providers import Anthropic, Gemini, Groq, Ollama, OpenAI + +from simplemind.providers import Anthropic, Gemini, OpenAI, Groq, Ollama, Amazon @pytest.mark.parametrize( @@ -10,6 +11,7 @@ from simplemind.providers import Anthropic, Gemini, Groq, Ollama, OpenAI OpenAI, Groq, Ollama, + Amazon, ], ) def test_generate_text(provider_cls):