Easy AI
py_simple.easy_ai
easy_ai wraps common LangChain functionality to make it easier to use.
EasyAIError
Bases: Exception
Raised when a call to an AI model or provider cannot be completed.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
message
|
str
|
Description of what went wrong. |
required |
ai_chat(ai_model)
Runs an interactive chat loop in the terminal against a LangChain chat model, without you having to write the input/print loop, exit handling, or conversation memory yourself.
Prompts for input with "You: ", prints each reply prefixed with
"AI: ", and keeps going until the user types "exit", "quit", "stop",
or "bye" (at which point it prints a goodbye message and returns).
Each turn is appended to an internal history list of HumanMessage/
AIMessage objects, and the full history is sent to the model on
every call, so the model has memory of the whole conversation for
as long as the loop runs. The history is local to this call and is
not preserved once the loop exits. Errors from ask_ai() are
caught and printed instead of raising, so a single bad call
doesn't end the session.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
ai_model
|
BaseChatModel
|
A LangChain chat model instance,
such as one returned by |
required |
Returns:
| Type | Description |
|---|---|
None
|
None. Runs until the user exits the loop. |
Example
from py_simple import get_model, ai_chat
model = get_model("anthropic", "claude-sonnet-4-6")
ai_chat(model)
from langchain_anthropic import ChatAnthropic
from langchain_core.messages import HumanMessage, AIMessage
model = ChatAnthropic(model_name="claude-sonnet-4-6")
history = []
while True:
user_input = input("You: ")
if user_input.lower() in ("exit", "quit", "stop", "bye"):
print("AI: Talk to you later!")
break
history.append(HumanMessage(content=user_input))
response = model.invoke(history).content
history.append(AIMessage(content=response))
print(f"AI: {response}")
analyze_sentiment(ai_model, text)
Sends a request to analyze the sentiment of the provided text using the
given LangChain chat model, returning a brief classification (e.g. Positive,
Negative, or Neutral).
Args:
ai_model (BaseChatModel): A LangChain chat model instance,
such as one returned by `get_model()`.
text (str): The raw text string to analyze.
Returns:
str: The sentiment classification of the text.
Raises:
EasyAIError: If the underlying model call fails.
Example:
=== "The Py_simple Way"
```python
from py_simple import get_model, analyze_sentiment
model = get_model("anthropic", "claude-sonnet-4-6")
sentiment = analyze_sentiment(
model,
"I absolutely love this new tool!",
)
```
=== "The Traditional Way"
```python
from langchain_anthropic import ChatAnthropic
from langchain_core.messages import HumanMessage
model = ChatAnthropic(model_name="claude-sonnet-4-6")
sentiment = model.invoke([
HumanMessage(
content=(
"Analyze the sentiment of the following text and "
"respond with a single word "
"(e.g., Positive, Negative, Neutral):
" "I absolutely love this new tool!" ) ) ]).content ```
ask_ai(ai_model, question)
Sends a question to a LangChain chat model and returns the content of the response, without you having to reach into the returned message object yourself.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
ai_model
|
BaseChatModel
|
A LangChain chat model instance,
such as one returned by |
required |
question
|
str | list
|
Either a single question as plain text, or a list of LangChain message objects (HumanMessage/AIMessage) representing the conversation so far. Pass a list to give the model memory of prior turns; the caller is responsible for building and updating that list. |
required |
Returns:
| Type | Description |
|---|---|
str | list[str | dict[Any, Any]]
|
The model's response content. Usually a plain string, but |
str | list[str | dict[Any, Any]]
|
some providers may return a list of content blocks instead. |
Raises:
| Type | Description |
|---|---|
EasyAIError
|
If the underlying call to the model fails for any reason (e.g. invalid API key, network error, timeout). |
Example
from py_simple import get_model, ask_ai
model = get_model("anthropic", "claude-sonnet-4-6")
answer = ask_ai(model, "hi")
from langchain_anthropic import ChatAnthropic
model = ChatAnthropic(model_name="claude-sonnet-4-6")
answer = model.invoke("hi").content
chunk_text(text, max_chars=500)
Split text into pieces that fit inside a character limit.
Useful before sending a long note to an AI model that only accepts a short prompt. Words stay whole when they fit. A single word longer than the limit is split so nothing is dropped.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
text
|
str
|
The text to split. |
required |
max_chars
|
int
|
Maximum characters in each piece.
Defaults to |
500
|
Returns:
| Type | Description |
|---|---|
list[str]
|
list[str]: The pieces, in order. An empty string returns an empty list. |
Raises:
| Type | Description |
|---|---|
EasyAIError
|
If |
Example
from py_simple import chunk_text
pieces = chunk_text("Pack a lunch and a notebook", max_chars=16)
text = "Pack a lunch and a notebook"
words = text.split()
pieces = []
current = ""
for word in words:
candidate = word if not current else f"{current} {word}"
if len(candidate) <= 16:
current = candidate
else:
pieces.append(current)
current = word
if current:
pieces.append(current)
detect_language(text)
Guesses which language a piece of text is written in, using simple keyword scoring rules, without installing a language-detection library or calling an external API.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
text
|
str
|
The raw text to analyze. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
str |
str
|
The detected language name (e.g., "English"), or |
str
|
"Unknown" if nothing could be confidently identified. |
Raises:
| Type | Description |
|---|---|
EasyAIError
|
If |
Example
from py_simple import detect_language
language = detect_language("Hello, how are you?")
# "English"
get_model(provider, model_name, api_key=None, base_url=None, timeout=30)
Returns a LangChain chat model instance for the given provider, without you having to remember each provider's import path and constructor arguments.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
provider
|
str
|
Name of the LLM provider. One of "openai", "ollama", "anthropic", "google", or "mistral". Case-insensitive. |
required |
model_name
|
str
|
Name of the model to use (e.g., "gpt-4o", "llama3", "claude-sonnet-4-6"). |
required |
api_key
|
str
|
API key for the provider, if required. Not used for "ollama". Defaults to None. |
None
|
base_url
|
str
|
Custom base URL for the provider. Used for "openai" and "ollama" (defaults to "http://localhost:11434" for ollama if not provided). Defaults to None. |
None
|
timeout
|
int
|
Request timeout in seconds. Currently only used for "anthropic". Defaults to 30. |
30
|
Returns:
| Type | Description |
|---|---|
BaseChatModel
|
A LangChain chat model instance corresponding to the given |
BaseChatModel
|
provider. |
Raises:
| Type | Description |
|---|---|
EasyAIError
|
If |
Example
from py_simple import get_model
model = get_model("anthropic", "claude-sonnet-4-6")
from langchain_anthropic import ChatAnthropic
model = ChatAnthropic(
model_name="claude-sonnet-4-6",
timeout=30,
stop=None
)
rewrite_text(ai_model, text, tone='calm')
Sends a request to change the tone of the provided text, without you having to change it manually.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
ai_model
|
BaseChatModel
|
A LangChain chat model instance,
such as one returned by |
required |
text
|
str
|
Text whose tone will be changed. |
required |
tone
|
str
|
Used to decide the tone for the text that the user wants (e.g. calm, angry, nervous, supportive, etc.). Defaults to "calm". |
'calm'
|
Returns:
| Name | Type | Description |
|---|---|---|
str |
str
|
The text with its tone changed. |
Raises:
| Type | Description |
|---|---|
EasyAIError
|
If the underlying model call fails. |
Example
from py_simple import get_model, rewrite_text
model = get_model("anthropic", "claude-sonnet-4-6")
tone = rewrite_text(
model,
"hello py-simple-wrap devs",
"excited",
)
from langchain_anthropic import ChatAnthropic
from langchain_core.messages import HumanMessage
model = ChatAnthropic(model_name="claude-sonnet-4-6")
tone = model.invoke([
HumanMessage(
content="Change tone to excited: hello py-simple-wrap devs"
)
]).content
summarize_text(ai_model, text)
Sends a request to summarize the provided text using the given
LangChain chat model, without you having to format messages manually.
Args:
ai_model (BaseChatModel): A LangChain chat model instance,
such as one returned by `get_model()`.
text (str): The raw text string to be summarized.
Returns:
str: A concise summary of the input text.
Raises:
EasyAIError: If the underlying model call fails.
Example:
=== "The Py_simple Way"
```python
from py_simple import get_model, summarize_text
model = get_model("anthropic", "claude-sonnet-4-6")
summary = summarize_text(model, "Long article text here...")
```
=== "The Traditional Way"
```python
from langchain_anthropic import ChatAnthropic
from langchain_core.messages import HumanMessage
model = ChatAnthropic(model_name="claude-sonnet-4-6")
summary = model.invoke(
[HumanMessage(content="Please summarize:
Long article text here...")] ).content ```
translate_text(ai_model, text, target_lang='English')
Sends a request to translate the provided text into the target language using the given LangChain chat model, without you having to format messages manually.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
ai_model
|
BaseChatModel
|
A LangChain chat model instance,
such as one returned by |
required |
text
|
str
|
The raw text string to be translated. |
required |
target_lang
|
str
|
The name of the language to translate into (e.g. "French", "Spanish", "German"). Defaults to "English". |
'English'
|
Returns:
| Name | Type | Description |
|---|---|---|
str |
str
|
The translated text. |
Raises:
| Type | Description |
|---|---|
EasyAIError
|
If the underlying model call fails. |
Example
from py_simple import get_model, translate_text
model = get_model("anthropic", "claude-sonnet-4-6")
translation = translate_text(
model,
"Hola mundo",
target_lang="English",
)
from langchain_anthropic import ChatAnthropic
from langchain_core.messages import HumanMessage
model = ChatAnthropic(model_name="claude-sonnet-4-6")
translation = model.invoke([
HumanMessage(content="Translate to English: Hola mundo")
]).content