Skip to content
Last updated

Official Python SDK for Freddy AI. Build AI-powered applications with type safety, async support, and comprehensive error handling.

Installation

pip install freddy-ai

Requirements:

  • Python 3.8+
  • httpx (automatically installed)

Quick Start

Synchronous Client

from freddy import FreddyClient

# Initialize client
client = FreddyClient(api_key="your-api-key")

# Create a response
response = client.responses.create(
    model="gpt-4.1",
    inputs=[{"role": "user", "texts": [{"text": "Hello!"}]}]
)

print(response.output[0].content[0].text)
client.close()

Asynchronous Client

import asyncio
from freddy import AsyncFreddyClient

async def main():
    async with AsyncFreddyClient(api_key="your-api-key") as client:
        response = await client.responses.create(
            model="gpt-4.1",
            inputs=[{"role": "user", "texts": [{"text": "Hello!"}]}]
        )
        print(response.output[0].content[0].text)

asyncio.run(main())
from freddy import FreddyClient

# Automatically handles cleanup
with FreddyClient(api_key="your-api-key") as client:
    response = client.responses.create(
        model="gpt-4.1",
        inputs=[{"role": "user", "texts": [{"text": "Hello!"}]}]
    )
    print(response.output[0].content[0].text)

Client Configuration

FreddyClient

from freddy import FreddyClient

client = FreddyClient(
    api_key="your-api-key",                    # Required
    base_url="https://freddy-api.aitronos.com", # Optional
    timeout=30.0                                # Optional (seconds)
)

AsyncFreddyClient

from freddy import AsyncFreddyClient

client = AsyncFreddyClient(
    api_key="your-api-key",                    # Required
    base_url="https://freddy-api.aitronos.com", # Optional
    timeout=30.0                                # Optional (seconds)
)

Parameters:

  • api_key string · Required - Your Freddy API key from Hub
  • base_url string · Optional - API base URL (default: https://freddy-api.aitronos.com)
  • timeout float · Optional - Request timeout in seconds (default: 30.0)

Responses API

Generate AI responses using various models.

Create Response

# Basic text generation
response = client.responses.create(
    model="gpt-4.1",
    inputs=[
        {
            "role": "user",
            "texts": [{"text": "What is the capital of France?"}]
        }
    ]
)

print(response.output[0].content[0].text)
# Output: "The capital of France is Paris."

With Thread Context

# Maintain conversation context
response = client.responses.create(
    model="gpt-4.1",
    inputs=[{"role": "user", "texts": [{"text": "Remember my name is Alice"}]}],
    thread_id="thread_abc123"
)

# Continue conversation
response = client.responses.create(
    model="gpt-4.1",
    inputs=[{"role": "user", "texts": [{"text": "What's my name?"}]}],
    thread_id="thread_abc123"
)

print(response.output[0].content[0].text)
# Output: "Your name is Alice."

With Assistant

# Use pre-configured assistant
response = client.responses.create(
    model="gpt-4.1",
    inputs=[{"role": "user", "texts": [{"text": "Analyze this data"}]}],
    assistant_id="asst_abc123"
)

With Tools (Function Calling)

# Define tools
tools = [
    {
        "type": "function",
        "function": {
            "name": "get_weather",
            "description": "Get current weather for a location",
            "parameters": {
                "type": "object",
                "properties": {
                    "location": {
                        "type": "string",
                        "description": "City name"
                    }
                },
                "required": ["location"]
            }
        }
    }
]

response = client.responses.create(
    model="gpt-4.1",
    inputs=[{"role": "user", "texts": [{"text": "What's the weather in London?"}]}],
    tools=tools
)

Structured Output (JSON)

# Force JSON response
response = client.responses.create(
    model="gpt-4.1",
    inputs=[{"role": "user", "texts": [{"text": "List 3 programming languages"}]}],
    response_format={"type": "json_object"}
)

import json
data = json.loads(response.output[0].content[0].text)
print(data)

Advanced Parameters

response = client.responses.create(
    model="gpt-4.1",
    inputs=[{"role": "user", "texts": [{"text": "Write a story"}]}],
    temperature=0.8,           # Creativity (0.0-2.0)
    max_tokens=500,            # Maximum output length
    organization_id="org_123", # Billing organization
    thread_id="thread_456",    # Conversation context
    assistant_id="asst_789"    # Assistant configuration
)

Async Response Creation

async with AsyncFreddyClient(api_key="your-api-key") as client:
    response = await client.responses.create(
        model="gpt-4.1",
        inputs=[{"role": "user", "texts": [{"text": "Hello!"}]}]
    )
    print(response.output[0].content[0].text)

Files API

Upload and manage files for use with vector stores and assistants.

Upload File

# Upload from file path
file = client.files.upload(
    organization_id="org_123",
    file="document.pdf",
    purpose="vector_store"
)

print(f"Uploaded: {file.id}")

Upload from File Object

# Upload from file-like object
with open("document.pdf", "rb") as f:
    file = client.files.upload(
        organization_id="org_123",
        file=f,
        purpose="vector_store",
        filename="my_document.pdf"
    )

List Files

# List all files
files = client.files.list(
    organization_id="org_123",
    page=1,
    page_size=20
)

for file in files.data:
    print(f"{file.name} - {file.size} bytes")

Search Files

# Search by filename
files = client.files.list(
    organization_id="org_123",
    search="report",
    purpose="vector_store"
)

Retrieve File

# Get file details
file = client.files.retrieve(
    organization_id="org_123",
    file_id="file_abc123"
)

print(f"Name: {file.name}")
print(f"Size: {file.size} bytes")
print(f"Created: {file.created_at}")

Delete File

# Delete a file
result = client.files.delete(
    organization_id="org_123",
    file_id="file_abc123"
)

print(f"Deleted: {result['deleted']}")

Async File Operations

async with AsyncFreddyClient(api_key="your-api-key") as client:
    # Upload
    file = await client.files.upload(
        organization_id="org_123",
        file="document.pdf",
        purpose="vector_store"
    )
    
    # List
    files = await client.files.list(organization_id="org_123")
    
    # Delete
    await client.files.delete(organization_id="org_123", file_id=file.id)

Vector Stores API

Create and manage vector stores for semantic search and RAG applications.

Create Vector Store

# Create a new vector store
store = client.vector_stores.create(
    organization_id="org_123",
    name="Company Knowledge Base",
    description="Internal documentation and policies",
    access_mode="organization"
)

print(f"Created: {store.id}")

Add Files to Vector Store

# Upload and add file
file = client.files.upload(
    organization_id="org_123",
    file="policy.pdf",
    purpose="vector_store"
)

# Add to vector store
client.vector_stores.add_file(
    organization_id="org_123",
    vector_store_id=store.id,
    file_id=file.id
)

List Vector Stores

# List all vector stores
stores = client.vector_stores.list(
    organization_id="org_123",
    page=1,
    page_size=20
)

for store in stores.data:
    print(f"{store.name} - {store.file_count} files")

Retrieve Vector Store

# Get vector store details
store = client.vector_stores.retrieve(
    organization_id="org_123",
    vector_store_id="vs_abc123"
)

print(f"Name: {store.name}")
print(f"Files: {store.file_count}")

Update Vector Store

# Update vector store
store = client.vector_stores.update(
    organization_id="org_123",
    vector_store_id="vs_abc123",
    name="Updated Knowledge Base",
    access_mode="department"
)

Delete Vector Store

# Delete vector store
result = client.vector_stores.delete(
    organization_id="org_123",
    vector_store_id="vs_abc123"
)

print(f"Deleted: {result['deleted']}")

Search Vector Store

# Semantic search
results = client.vector_stores.search(
    organization_id="org_123",
    vector_store_id="vs_abc123",
    query="What is our vacation policy?",
    limit=5
)

for result in results:
    print(f"Score: {result.score}")
    print(f"Content: {result.content}")

Async Vector Store Operations

async with AsyncFreddyClient(api_key="your-api-key") as client:
    # Create
    store = await client.vector_stores.create(
        organization_id="org_123",
        name="Knowledge Base"
    )
    
    # Search
    results = await client.vector_stores.search(
        organization_id="org_123",
        vector_store_id=store.id,
        query="search query"
    )

Images API

Generate images using AI models.

Generate Image

# Generate single image
image = client.images.generate(
    prompt="A serene mountain landscape at sunset",
    model="dall-e-3",
    size="1024x1024",
    quality="hd",
    n=1
)

print(f"Image URL: {image.data[0].url}")

Generate Multiple Images

# Generate multiple variations
images = client.images.generate(
    prompt="A futuristic cityscape",
    model="dall-e-3",
    size="1792x1024",
    n=4
)

for i, img in enumerate(images.data):
    print(f"Image {i+1}: {img.url}")

Custom Organization

# Generate with specific organization
image = client.images.generate(
    organization_id="org_123",
    prompt="Abstract art with vibrant colors",
    model="dall-e-3",
    size="1024x1024"
)

Base64 Response

# Get base64-encoded image
image = client.images.generate(
    prompt="A cute robot",
    model="dall-e-3",
    response_format="b64_json"
)

import base64
from PIL import Image
import io

# Decode and save
image_data = base64.b64decode(image.data[0].b64_json)
img = Image.open(io.BytesIO(image_data))
img.save("robot.png")

Async Image Generation

async with AsyncFreddyClient(api_key="your-api-key") as client:
    image = await client.images.generate(
        prompt="A beautiful sunset",
        model="dall-e-3",
        size="1024x1024"
    )
    print(image.data[0].url)

Models API

List and retrieve available AI models.

List Models

# Get all available models
models = client.models.list()

for model in models.data:
    print(f"{model.id} - {model.created}")

Retrieve Model

# Get specific model details
model = client.models.retrieve("gpt-4.1")

print(f"Model: {model.id}")
print(f"Owner: {model.owned_by}")

Async Model Operations

async with AsyncFreddyClient(api_key="your-api-key") as client:
    models = await client.models.list()
    model = await client.models.retrieve("gpt-4.1")

Error Handling

The SDK provides specific exception types for different error scenarios.

Exception Types

from freddy import (
    FreddyError,           # Base exception
    APIError,              # General API errors
    AuthenticationError,   # 401 auth errors
    RateLimitError,        # 429 rate limit errors
    ValidationError        # Request validation errors
)

Basic Error Handling

from freddy import FreddyClient, APIError, AuthenticationError, RateLimitError

client = FreddyClient(api_key="your-api-key")

try:
    response = client.responses.create(
        model="gpt-4.1",
        inputs=[{"role": "user", "texts": [{"text": "Hello!"}]}]
    )
except AuthenticationError as e:
    print(f"Authentication failed: {e.message}")
    print(f"Status: {e.status_code}")
except RateLimitError as e:
    print(f"Rate limit exceeded: {e.message}")
    print(f"Retry after: {e.response.get('retry_after')}")
except APIError as e:
    print(f"API error: {e.message}")
    print(f"Status: {e.status_code}")
    print(f"Response: {e.response}")

Comprehensive Error Handling

import time
from freddy import FreddyClient, RateLimitError, APIError

def create_response_with_retry(client, **kwargs):
    max_retries = 3
    for attempt in range(max_retries):
        try:
            return client.responses.create(**kwargs)
        except RateLimitError as e:
            if attempt < max_retries - 1:
                retry_after = e.response.get('retry_after', 1)
                print(f"Rate limited. Retrying in {retry_after}s...")
                time.sleep(retry_after)
            else:
                raise
        except APIError as e:
            if e.status_code >= 500 and attempt < max_retries - 1:
                print(f"Server error. Retrying...")
                time.sleep(2 ** attempt)
            else:
                raise

# Use with retry logic
client = FreddyClient(api_key="your-api-key")
response = create_response_with_retry(
    client,
    model="gpt-4.1",
    inputs=[{"role": "user", "texts": [{"text": "Hello!"}]}]
)

Async Error Handling

from freddy import AsyncFreddyClient, APIError

async def safe_create_response():
    async with AsyncFreddyClient(api_key="your-api-key") as client:
        try:
            response = await client.responses.create(
                model="gpt-4.1",
                inputs=[{"role": "user", "texts": [{"text": "Hello!"}]}]
            )
            return response
        except APIError as e:
            print(f"Error: {e.message}")
            return None

Type Hints

The SDK includes comprehensive type hints for better IDE support.

Typed Responses

from freddy import FreddyClient
from freddy.models import ModelResponse, FileObject, VectorStoreObject

client: FreddyClient = FreddyClient(api_key="your-api-key")

# Type-safe response handling
response: ModelResponse = client.responses.create(
    model="gpt-4.1",
    inputs=[{"role": "user", "texts": [{"text": "Hello!"}]}]
)

file: FileObject = client.files.upload(
    organization_id="org_123",
    file="document.pdf"
)

Custom Type Definitions

from typing import List, Dict, Any, Optional
from freddy import FreddyClient
from freddy.types import Message, FilePurpose, AccessMode

def create_conversation(
    client: FreddyClient,
    messages: List[Message],
    model: str = "gpt-4.1",
    temperature: Optional[float] = None
) -> str:
    """Create a conversation with type-safe parameters"""
    response = client.responses.create(
        model=model,
        inputs=messages,
        temperature=temperature
    )
    return response.output[0].content[0].text

Advanced Examples

RAG Application

from freddy import FreddyClient

client = FreddyClient(api_key="your-api-key")

# 1. Create vector store
store = client.vector_stores.create(
    organization_id="org_123",
    name="Company Docs"
)

# 2. Upload documents
files = ["policy.pdf", "handbook.pdf", "faq.pdf"]
for file_path in files:
    file = client.files.upload(
        organization_id="org_123",
        file=file_path,
        purpose="vector_store"
    )
    client.vector_stores.add_file(
        organization_id="org_123",
        vector_store_id=store.id,
        file_id=file.id
    )

# 3. Query with context
def ask_question(question: str) -> str:
    # Search relevant context
    results = client.vector_stores.search(
        organization_id="org_123",
        vector_store_id=store.id,
        query=question,
        limit=3
    )
    
    # Build context
    context = "\n\n".join([r.content for r in results])
    
    # Generate answer
    response = client.responses.create(
        model="gpt-4.1",
        inputs=[
            {
                "role": "system",
                "texts": [{"text": f"Context:\n{context}"}]
            },
            {
                "role": "user",
                "texts": [{"text": question}]
            }
        ]
    )
    
    return response.output[0].content[0].text

# Use the RAG system
answer = ask_question("What is our vacation policy?")
print(answer)

Multi-Turn Conversation

from freddy import FreddyClient

client = FreddyClient(api_key="your-api-key")

class Conversation:
    def __init__(self, client: FreddyClient, thread_id: str):
        self.client = client
        self.thread_id = thread_id
    
    def send(self, message: str) -> str:
        response = self.client.responses.create(
            model="gpt-4.1",
            inputs=[{"role": "user", "texts": [{"text": message}]}],
            thread_id=self.thread_id
        )
        return response.output[0].content[0].text

# Use conversation
conv = Conversation(client, "thread_123")
print(conv.send("Hello!"))
print(conv.send("What's the weather?"))
print(conv.send("Thanks!"))

Batch Processing

import asyncio
from freddy import AsyncFreddyClient

async def process_batch(questions: list[str]) -> list[str]:
    async with AsyncFreddyClient(api_key="your-api-key") as client:
        tasks = [
            client.responses.create(
                model="gpt-4.1",
                inputs=[{"role": "user", "texts": [{"text": q}]}]
            )
            for q in questions
        ]
        
        responses = await asyncio.gather(*tasks)
        return [r.output[0].content[0].text for r in responses]

# Process 10 questions in parallel
questions = [f"Question {i}" for i in range(10)]
answers = asyncio.run(process_batch(questions))

Environment Variables

Store your API key securely using environment variables.

Using .env File

# .env
FREDDY_API_KEY=your-api-key
FREDDY_BASE_URL=https://freddy-api.aitronos.com
import os
from dotenv import load_dotenv
from freddy import FreddyClient

load_dotenv()

client = FreddyClient(
    api_key=os.getenv("FREDDY_API_KEY"),
    base_url=os.getenv("FREDDY_BASE_URL")
)

Direct Environment Variable

import os
from freddy import FreddyClient

# Reads from FREDDY_API_KEY env var
client = FreddyClient(api_key=os.environ["FREDDY_API_KEY"])

Best Practices

1. Use Context Managers

# ✅ Good - automatic cleanup
with FreddyClient(api_key="...") as client:
    response = client.responses.create(...)

# ❌ Bad - manual cleanup required
client = FreddyClient(api_key="...")
response = client.responses.create(...)
client.close()  # Easy to forget!

2. Handle Errors Gracefully

# ✅ Good - specific error handling
try:
    response = client.responses.create(...)
except RateLimitError:
    # Implement backoff
    time.sleep(1)
except AuthenticationError:
    # Refresh credentials
    pass

3. Use Async for Concurrency

# ✅ Good - process 100 requests concurrently
async def process_many():
    async with AsyncFreddyClient(api_key="...") as client:
        tasks = [client.responses.create(...) for _ in range(100)]
        return await asyncio.gather(*tasks)

4. Reuse Client Instances

# ✅ Good - reuse client
client = FreddyClient(api_key="...")
for item in items:
    response = client.responses.create(...)

# ❌ Bad - creates new connection each time
for item in items:
    client = FreddyClient(api_key="...")
    response = client.responses.create(...)

5. Set Appropriate Timeouts

# ✅ Good - custom timeout for long operations
client = FreddyClient(
    api_key="...",
    timeout=60.0  # 60 seconds for complex tasks
)

Changelog

v0.1.0 (Current)

Features:

  • ✅ Synchronous and asynchronous clients
  • ✅ Responses API (text generation)
  • ✅ Files API (upload, list, retrieve, delete)
  • ✅ Vector Stores API (create, manage, search)
  • ✅ Images API (generation)
  • ✅ Models API (list, retrieve)
  • ✅ Comprehensive error handling
  • ✅ Type hints and autocompletion
  • ✅ Context manager support

Coming Soon:

  • 🔄 Streaming response support
  • 🔄 Assistants API
  • 🔄 Threads API
  • 🔄 Audio API
  • 🔄 Batch API

Support

License

MIT License - see LICENSE for details.


Built with ❤️ by Aitronos