Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ jobs:
- name: Check code style with ruff
run: uv run ruff format --check --diff

- name: Check type hints with ty
run: uv run ty check think/

- name: Test with pytest
run: uv run pytest --cov=think --cov-report=lcov
timeout-minutes: 5
Expand Down
9 changes: 9 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,15 @@ repos:
args: [--fix]
# Run the formatter.
- id: ruff-format
- repo: local
hooks:
- id: ty
name: ty check
stages: [pre-commit]
types: [python]
entry: uv run ty check think/
language: python
pass_filenames: false
- repo: local
hooks:
# Run the tests
Expand Down
28 changes: 28 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,54 +14,64 @@ LLM API provider.
Ask a question:

```python
# example: ask.py
from asyncio import run

from think import LLM, ask

llm = LLM.from_url("anthropic:///claude-3-haiku-20240307")


async def haiku(topic):
return await ask(llm, "Write a haiku about {{ topic }}", topic=topic)


print(run(haiku("computers")))
```

Get answers as structured data:

```python
# example: structured.py
from asyncio import run

from think import LLM, LLMQuery

llm = LLM.from_url("openai:///gpt-4o-mini")


class CityInfo(LLMQuery):
"""
Give me basic information about {{ city }}.
"""

name: str
country: str
population: int
latitude: float
longitude: float


async def city_info(city):
return await CityInfo.run(llm, city=city)


info = run(city_info("Paris"))
print(f"{info.name} is a city in {info.country} with {info.population} inhabitants.")
```

Integrate AI with custom tools:

```python
# example: tools.py
from asyncio import run
from datetime import date

from think import LLM, Chat

llm = LLM.from_url("openai:///gpt-4o-mini")


def current_date() -> str:
"""
Get the current date.
Expand All @@ -70,50 +80,59 @@ def current_date() -> str:
"""
return date.today().isoformat()


async def days_to_xmas() -> str:
chat = Chat("How many days are left until Christmas?")
return await llm(chat, tools=[current_date])


print(run(days_to_xmas()))
```

Use vision (with models that support it):

```python
# example: vision.py
from asyncio import run

from think import LLM, Chat

llm = LLM.from_url("openai:///gpt-4o-mini")


async def describe_image(path):
image_data = open(path, "rb").read()
chat = Chat().user("Describe the image in detail", images=[image_data])
return await llm(chat)


print(run(describe_image("path/to/image.jpg")))
```

This also works with PDF documents (with models that support PDFs):

```python
# example: pdf.py
from asyncio import run

from think import LLM, Chat

llm = LLM.from_url("google:///gemini-2.0-flash")


async def read_pdf(path):
pdf_data = open(path, "rb").read()
chat = Chat().user("Read the document", documents=[pdf_data])
return await llm(chat)


print(run(read_pdf("path/to/document.pdf")))
```

Use Pydantic or custom parsers for structured data:

```python
# example: parsing.py
from asyncio import run
from ast import parse

Expand All @@ -123,6 +142,7 @@ from think.prompt import JinjaStringTemplate

llm = LLM.from_url("openai:///gpt-4o-mini")


def parse_python(text):
# extract code block from the text
block_parser = CodeBlockParser()
Expand All @@ -134,13 +154,15 @@ def parse_python(text):
except SyntaxError as err:
raise ValueError(f"Invalid Python code: {err}") from err


async def generate_python_script(task):
system = "You always output the requested code in a single Markdown code block"
prompt = "Write a Python script for the following task: {{ task }}"
tpl = JinjaStringTemplate()
chat = Chat(system).user(tpl(prompt, task=task))
return await llm(chat, parser=parse_python)


print(run(generate_python_script("sort a list of numbers")))
```

Expand All @@ -155,6 +177,7 @@ provides scaffolding to integrate other RAG providers.
Example usage:

```python
# example: rag.py
from asyncio import run

from think import LLM
Expand All @@ -163,6 +186,7 @@ from think.rag.base import RAG, RagDocument
llm = LLM.from_url("openai:///gpt-4o-mini")
rag = RAG.for_provider("txtai")(llm)


async def index_documents():
data = [
RagDocument(id="a", text="Titanic: A sweeping romantic epic"),
Expand All @@ -171,6 +195,7 @@ async def index_documents():
]
await rag.add_documents(data)


run(index_documents())
query = "A movie about a ship that sinks"
result = run(rag(query))
Expand All @@ -191,6 +216,7 @@ use tools, and integrate with RAG.
Example:

```python
# example: agent.py
from asyncio import run
from datetime import datetime

Expand All @@ -199,6 +225,7 @@ from think.agent import BaseAgent, tool

llm = LLM.from_url("openai:///gpt-4o-mini")


class Chatbot(BaseAgent):
"""You are a helpful assistant. Today is {{today}}."""

Expand All @@ -211,6 +238,7 @@ class Chatbot(BaseAgent):
print(response)
return input("> ").strip()


agent = Chatbot(llm, today=datetime.today())
run(agent.run())
```
Expand Down
25 changes: 25 additions & 0 deletions examples/agent.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# example: agent.py
from asyncio import run
from datetime import datetime

from think import LLM
from think.agent import BaseAgent, tool

llm = LLM.from_url("openai:///gpt-4o-mini")


class Chatbot(BaseAgent):
"""You are a helpful assistant. Today is {{today}}."""

@tool
def get_time(self) -> str:
"""Get the current time."""
return datetime.now().strftime("%H:%M")

async def interact(self, response: str) -> str:
print(response)
return input("> ").strip()


agent = Chatbot(llm, today=datetime.today())
run(agent.run())
31 changes: 0 additions & 31 deletions examples/ai_functions.py

This file was deleted.

13 changes: 13 additions & 0 deletions examples/ask.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# example: ask.py
from asyncio import run

from think import LLM, ask

llm = LLM.from_url("anthropic:///claude-3-haiku-20240307")


async def haiku(topic):
return await ask(llm, "Write a haiku about {{ topic }}", topic=topic)


print(run(haiku("computers")))
85 changes: 0 additions & 85 deletions examples/chatbot.py

This file was deleted.

Loading