mirror of
https://github.com/kennethreitz/simplemind.git
synced 2026-06-05 14:50:16 +00:00
Compare commits
47 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d4cfce01ba | |||
| da9958ef46 | |||
| 918705e2d5 | |||
| eae68d1ee1 | |||
| 3dccac85ff | |||
| 4f3fcac02d | |||
| 593d6c8e07 | |||
| dd2b08b4cf | |||
| 0fa4b60412 | |||
| c1115ccf47 | |||
| 0100ad0163 | |||
| 3090ade9e3 | |||
| 3e2801a1ac | |||
| d9f0d21e53 | |||
| 5bf4fc81e7 | |||
| ca0246a3bb | |||
| 30885beda7 | |||
| a1dfe65084 | |||
| 641de59138 | |||
| 3c4ed48786 | |||
| 467f67d283 | |||
| b109964340 | |||
| b04c68f57d | |||
| 8ed065836a | |||
| abdac66fee | |||
| 1ce2759564 | |||
| d0a76d7532 | |||
| 846efb4190 | |||
| 24b8aa1868 | |||
| eab6730372 | |||
| 2a8b0f07f9 | |||
| 225c187b19 | |||
| a7bc7cee1d | |||
| 031b154648 | |||
| 52f0084ac8 | |||
| 62a68aafc6 | |||
| 462e45612d | |||
| 9a5ad78a3f | |||
| 42da9bcc87 | |||
| dcb9c14d30 | |||
| 87d636ca55 | |||
| 83d430a310 | |||
| b23f732d55 | |||
| 4c8cb49a58 | |||
| fb2460f907 | |||
| cb6d5540cb | |||
| 23389c3a62 |
+2
-1
@@ -1,4 +1,5 @@
|
||||
export OPENAI_API_KEY=""
|
||||
export ANTHROPIC_API_KEY=""
|
||||
export XAI_API_KEY=""
|
||||
export GROQ_API_KEY=""
|
||||
export OLLAMA_HOST_URL=""
|
||||
export GROQ_API_KEY=""
|
||||
|
||||
@@ -166,3 +166,4 @@ cython_debug/
|
||||
.env
|
||||
|
||||
src/**
|
||||
requirements.txt
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
Release History
|
||||
===============
|
||||
|
||||
## 0.1.2 (2024-10-29)
|
||||
|
||||
- Add ollama provider.
|
||||
|
||||
## 0.1.1 (2024-10-29)
|
||||
|
||||
- Fix Groq provider.
|
||||
|
||||
## 0.1.0 (2024-10-29)
|
||||
|
||||
- Initial release.
|
||||
-12
@@ -1,12 +0,0 @@
|
||||
FROM python:3.12.0
|
||||
|
||||
RUN apt-get update -y && apt-get upgrade -y
|
||||
RUN pip install --upgrade pip
|
||||
|
||||
COPY requirements.txt /src/requirements.txt
|
||||
|
||||
WORKDIR /src
|
||||
|
||||
RUN pip install -r requirements.txt
|
||||
|
||||
ENTRYPOINT ["python", "build.py"]
|
||||
@@ -4,6 +4,10 @@
|
||||
|
||||
SimpleMind is an AI library designed to simplify your experience with AI APIs in Python. Inspired by a "for humans" philosophy, it abstracts away complexity, giving developers an intuitive and human-friendly way to interact with powerful AI capabilities. With SimpleMind, tapping into AI is as easy as a friendly conversation.
|
||||
|
||||
```bash
|
||||
$ pip install simplemind
|
||||
```
|
||||
|
||||
## Features
|
||||
- **Easy-to-use AI tools**: SimpleMind provides simple interfaces to popular AI services.
|
||||
- **Human-centered design**: The library prioritizes readability and usability—no need to be an expert to start experimenting.
|
||||
@@ -11,44 +15,39 @@ SimpleMind is an AI library designed to simplify your experience with AI APIs in
|
||||
|
||||
## Supported APIs
|
||||
|
||||
- **OpenAI's GPT**
|
||||
- **Anthropic's Claude**
|
||||
- **xAI's Grok**
|
||||
- **Groq's Groq**
|
||||
- **Ollama's Ollama**
|
||||
|
||||
To specify a specific provider or model, you can use the `llm_provider` and `llm_model` parameters when calling: `generate_text`, `generate_data`, or `create_conversation`.
|
||||
|
||||
- **[OpenAI's GPT](https://openai.com/gpt)**
|
||||
- **[Anthropic's Claude](https://www.anthropic.com/claude)**
|
||||
- **[xAI's Grok](https://x.ai/)**
|
||||
- **[Groq's Groq](https://groq.com/)**
|
||||
- **[Ollama](https://ollama.com)**
|
||||
|
||||
If you'd like 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!
|
||||
|
||||
## Installation
|
||||
|
||||
Coming soon!
|
||||
|
||||
```bash
|
||||
$ pip install simplemind
|
||||
```
|
||||
|
||||
## Quickstart
|
||||
|
||||
SimpleMind takes care of the complex API calls so you can focus on what matters—building, experimenting, and creating.
|
||||
|
||||
```python
|
||||
import simplemind as sm
|
||||
```
|
||||
|
||||
Authenticate your API keys by setting them in the environment variables:
|
||||
First, authenticate your API keys by setting them in the environment variables:
|
||||
|
||||
```bash
|
||||
$ export OPENAI_API_KEY="sk-..."
|
||||
```
|
||||
|
||||
Other supported environment variables: `ANTHROPIC_API_KEY`, `GROK_API_KEY`, `XAI_API_KEY`, and `GROQ_API_KEY`.
|
||||
This pattern allows you to keep your API keys private and out of your codebase. Other supported environment variables: `ANTHROPIC_API_KEY`, `GROK_API_KEY`, `XAI_API_KEY`, and `GROQ_API_KEY`.
|
||||
|
||||
Next, import SimpleMind and start using it:
|
||||
|
||||
```python
|
||||
import simplemind as sm
|
||||
```
|
||||
|
||||
|
||||
## Examples
|
||||
@@ -64,7 +63,7 @@ Generate a response from an AI model based on a given prompt:
|
||||
"The meaning of life is a profound philosophical question that has been explored by cultures, religions, and philosophers for centuries. Different people and belief systems offer varying interpretations:\n\n1. **Religious Perspectives:** Many religions propose that the meaning of life is to fulfill a divine purpose, serve God, or reach an afterlife. For example, Christianity often emphasizes love, faith, and service to God and others as central to life’s meaning.\n\n2. **Philosophical Views:** Philosophers offer diverse answers. Existentialists like Jean-Paul Sartre argue that life has no inherent meaning, and it is up to individuals to create their own purpose. Others, like Aristotle, suggest that achieving eudaimonia (flourishing or happiness) through virtuous living is the key to a meaningful life.\n\n3. **Scientific and Secular Approaches:** Some people find meaning through understanding the natural world, contributing to human knowledge, or through personal accomplishments and happiness. They may view life's meaning as a product of connection, legacy, or the pursuit of knowledge and creativity.\n\n4. **Personal Perspective:** For many, the meaning of life is deeply personal, involving their relationships, passions, and goals. These individuals define life's purpose through experiences, connections, and the impact they have on others and the world.\n\nUltimately, the meaning of life is a subjective question, with each person finding their own answers based on their beliefs, experiences, and reflections."
|
||||
```
|
||||
|
||||
### Structured Response
|
||||
### Structured Data with Pydantic
|
||||
|
||||
You can use Pydantic models to structure the response from the LLM, if the LLM supports it.
|
||||
|
||||
@@ -135,7 +134,7 @@ conversation.add_plugin(SimpleMemoryPlugin())
|
||||
|
||||
conversation.add_message(
|
||||
role="user",
|
||||
text="Write a poem about the moon",
|
||||
text="Please write a poem about the moon",
|
||||
)
|
||||
```
|
||||
```pycon
|
||||
@@ -183,11 +182,6 @@ To get started:
|
||||
3. Make your changes.
|
||||
4. Submit a pull request.
|
||||
|
||||
## Building
|
||||
1. Clone the repository.
|
||||
2. `cd` to the root directory.
|
||||
3. Run `docker-compose up --build`
|
||||
|
||||
## License
|
||||
SimpleMind is licensed under the Apache 2.0 License.
|
||||
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
services:
|
||||
simplemind:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
volumes:
|
||||
- ./simplemind:/src/simplemind
|
||||
- ./build.py:/src/build.py
|
||||
env_file:
|
||||
- .env
|
||||
@@ -1,4 +1,4 @@
|
||||
from typing import List
|
||||
from typing import List, Iterator
|
||||
|
||||
from pydantic import BaseModel
|
||||
|
||||
@@ -9,21 +9,36 @@ class Movie(BaseModel):
|
||||
title: str
|
||||
year: int
|
||||
|
||||
|
||||
class MovieCharecter(BaseModel):
|
||||
name: str
|
||||
actor: str
|
||||
|
||||
|
||||
class MovieQuote(BaseModel):
|
||||
quote: str
|
||||
movie: Movie
|
||||
charecter: MovieCharecter
|
||||
|
||||
|
||||
class QuotesList(BaseModel):
|
||||
quotes: List[MovieQuote]
|
||||
theme: str
|
||||
|
||||
|
||||
quotes = sm.generate_data(llm_provider="openai", llm_model="gpt-4o-mini", prompt="Generate 20 quotes from famous movies", response_model=QuotesList)
|
||||
def gen_quotes(n=10) -> Iterator[MovieQuote]:
|
||||
"""Generate a list of quotes from famous movies."""
|
||||
|
||||
for quote in quotes.quotes:
|
||||
print(f"{quote.charecter.name} from {quote.movie.title} ({quote.movie.year}): {quote.quote!r}")
|
||||
for q in sm.generate_data(
|
||||
llm_provider="openai",
|
||||
llm_model="gpt-4o-mini",
|
||||
prompt=f"Generate {n} quotes from famous movies",
|
||||
response_model=QuotesList,
|
||||
).quotes:
|
||||
yield q
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
for quote in gen_quotes(n=20):
|
||||
print(
|
||||
f"{quote.charecter.name} from {quote.movie.title} ({quote.movie.year}): {quote.quote!r}"
|
||||
)
|
||||
|
||||
@@ -21,7 +21,7 @@ conversation.add_plugin(SimpleMemoryPlugin())
|
||||
|
||||
conversation.add_message(
|
||||
role="user",
|
||||
text="Write a poem about the moon",
|
||||
text="Please write a poem about the moon",
|
||||
)
|
||||
|
||||
r = conversation.send()
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
from _context import sm
|
||||
|
||||
conversation = sm.create_conversation(llm_model="gpt-4o", llm_provider="openai")
|
||||
|
||||
conversation.add_message(
|
||||
"user", "Translate the following text to French: 'Hello, world!'"
|
||||
)
|
||||
def translate_to_french(text: str) -> str:
|
||||
conversation = sm.create_conversation(llm_model="gpt-4o", llm_provider="openai")
|
||||
|
||||
print(conversation.send().text)
|
||||
conversation.add_message(
|
||||
"user", f"Translate the following text to French: {text!r}"
|
||||
)
|
||||
return conversation.send().text
|
||||
|
||||
|
||||
print(translate_to_french("an omlette with cheese"))
|
||||
|
||||
+2
-2
@@ -1,10 +1,10 @@
|
||||
[project]
|
||||
name = "simplemind"
|
||||
version = "0.1.0"
|
||||
version = "0.1.2"
|
||||
description = "An experimental client for AI providers that intends to replace LangChain and LangGraph for most common use cases."
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.11"
|
||||
dependencies = ["pydantic", "pydantic-settings", "instructor", "openai", "anthropic", "groq"]
|
||||
dependencies = ["pydantic", "pydantic-settings", "instructor", "openai", "anthropic", "ollama", "groq"]
|
||||
|
||||
[build-system]
|
||||
requires = ["hatchling"]
|
||||
|
||||
@@ -60,6 +60,9 @@ class Conversation(SMBaseModel):
|
||||
def __str__(self):
|
||||
return f"<Conversation id={self.id!r}>"
|
||||
|
||||
def prepend_system_message(self, role: str, text: str, meta: Optional[Dict[str, Any]] = None):
|
||||
self.messages = [Message(role=role, text=text, meta=meta or {})] + self.messages
|
||||
|
||||
def add_message(
|
||||
self, role: MESSAGE_ROLE, text: str, meta: Optional[Dict[str, Any]] = None
|
||||
):
|
||||
|
||||
@@ -4,6 +4,7 @@ from simplemind.providers._base import BaseProvider
|
||||
from simplemind.providers.anthropic import Anthropic
|
||||
from simplemind.providers.groq import Groq
|
||||
from simplemind.providers.openai import OpenAI
|
||||
from simplemind.providers.ollama import Ollama
|
||||
from simplemind.providers.xai import XAI
|
||||
|
||||
providers: List[Type[BaseProvider]] = [Anthropic, Groq, OpenAI, XAI]
|
||||
providers: List[Type[BaseProvider]] = [Anthropic, Groq, OpenAI, Ollama, XAI]
|
||||
|
||||
@@ -83,7 +83,7 @@ class Groq(BaseProvider):
|
||||
{"role": "user", "content": prompt},
|
||||
]
|
||||
|
||||
response = self.structured_client.chat.completions.create(
|
||||
response = self.client.chat.completions.create(
|
||||
messages=messages,
|
||||
model=llm_model,
|
||||
**kwargs,
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
import ollama as ol
|
||||
import instructor
|
||||
from openai import OpenAI
|
||||
|
||||
from ._base import BaseProvider
|
||||
from ..settings import settings
|
||||
|
||||
PROVIDER_NAME = "ollama"
|
||||
DEFAULT_MODEL = "llama3.2"
|
||||
DEFAULT_TIMEOUT = 60
|
||||
|
||||
|
||||
class Ollama(BaseProvider):
|
||||
NAME = PROVIDER_NAME
|
||||
DEFAULT_MODEL = DEFAULT_MODEL
|
||||
TIMEOUT = DEFAULT_TIMEOUT
|
||||
|
||||
def __init__(self, host_url: str = None):
|
||||
self.host_url = host_url or settings.OLLAMA_HOST_URL
|
||||
|
||||
@property
|
||||
def client(self):
|
||||
"""The raw Ollama client."""
|
||||
if not self.host_url:
|
||||
raise ValueError("No ollama host url provided")
|
||||
return ol.Client(timeout=self.TIMEOUT, host=self.host_url)
|
||||
|
||||
@property
|
||||
def structured_client(self):
|
||||
"""A client patched with Instructor."""
|
||||
return instructor.from_openai(
|
||||
OpenAI(
|
||||
base_url=f"{self.host_url}/v1",
|
||||
api_key="ollama",
|
||||
),
|
||||
mode=instructor.Mode.JSON,
|
||||
)
|
||||
|
||||
def send_conversation(self, conversation: "Conversation"):
|
||||
"""Send a conversation to the Ollama API."""
|
||||
from ..models import Message
|
||||
|
||||
messages = [
|
||||
{"role": msg.role, "content": msg.text} for msg in conversation.messages
|
||||
]
|
||||
response = self.client.chat(
|
||||
model=conversation.llm_model or DEFAULT_MODEL, messages=messages
|
||||
)
|
||||
assistant_message = response.get("message")
|
||||
|
||||
# Create and return a properly formatted Message instance
|
||||
return Message(
|
||||
role="assistant",
|
||||
text=assistant_message.get("content"),
|
||||
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):
|
||||
messages = [
|
||||
{"role": "user", "content": prompt},
|
||||
]
|
||||
|
||||
response = self.structured_client.chat.completions.create(
|
||||
messages=messages, model=llm_model, response_model=response_model, **kwargs
|
||||
)
|
||||
return response
|
||||
|
||||
def generate_text(self, prompt, *, llm_model):
|
||||
messages = [
|
||||
{"role": "user", "content": prompt},
|
||||
]
|
||||
|
||||
response = self.client.chat(messages=messages, model=llm_model)
|
||||
|
||||
return response.get("message").get("content")
|
||||
@@ -12,6 +12,9 @@ class Settings(BaseSettings):
|
||||
)
|
||||
GROQ_API_KEY: Optional[SecretStr] = Field(None, description="API key for Groq")
|
||||
OPENAI_API_KEY: Optional[SecretStr] = Field(None, description="API key for OpenAI")
|
||||
OLLAMA_HOST_URL: Optional[str] = Field(
|
||||
"http://127.0.0.1:11434", description="Fully qualified host URL for Ollama"
|
||||
)
|
||||
XAI_API_KEY: Optional[SecretStr] = Field(None, description="API key for xAI")
|
||||
DEFAULT_LLM_PROVIDER: str = Field("openai", description="The default LLM provider")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user