Official Python SDK for Freddy AI. Build AI-powered applications with type safety, async support, and comprehensive error handling.
pip install freddy-aiRequirements:
- Python 3.8+
- httpx (automatically installed)
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()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)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)
)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_keystring · Required - Your Freddy API key from Hubbase_urlstring · Optional - API base URL (default:https://freddy-api.aitronos.com)timeoutfloat · Optional - Request timeout in seconds (default:30.0)
Generate AI responses using various models.
# 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."# 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."# Use pre-configured assistant
response = client.responses.create(
model="gpt-4.1",
inputs=[{"role": "user", "texts": [{"text": "Analyze this data"}]}],
assistant_id="asst_abc123"
)# 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
)# 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)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 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)Upload and manage files for use with vector stores and assistants.
# 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-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 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 by filename
files = client.files.list(
organization_id="org_123",
search="report",
purpose="vector_store"
)# 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 a file
result = client.files.delete(
organization_id="org_123",
file_id="file_abc123"
)
print(f"Deleted: {result['deleted']}")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)Create and manage vector stores for semantic search and RAG applications.
# 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}")# 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 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")# 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
store = client.vector_stores.update(
organization_id="org_123",
vector_store_id="vs_abc123",
name="Updated Knowledge Base",
access_mode="department"
)# Delete vector store
result = client.vector_stores.delete(
organization_id="org_123",
vector_store_id="vs_abc123"
)
print(f"Deleted: {result['deleted']}")# 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 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"
)Generate images using AI models.
# 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 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}")# Generate with specific organization
image = client.images.generate(
organization_id="org_123",
prompt="Abstract art with vibrant colors",
model="dall-e-3",
size="1024x1024"
)# 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 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)List and retrieve available AI models.
# Get all available models
models = client.models.list()
for model in models.data:
print(f"{model.id} - {model.created}")# Get specific model details
model = client.models.retrieve("gpt-4.1")
print(f"Model: {model.id}")
print(f"Owner: {model.owned_by}")async with AsyncFreddyClient(api_key="your-api-key") as client:
models = await client.models.list()
model = await client.models.retrieve("gpt-4.1")The SDK provides specific exception types for different error scenarios.
from freddy import (
FreddyError, # Base exception
APIError, # General API errors
AuthenticationError, # 401 auth errors
RateLimitError, # 429 rate limit errors
ValidationError # Request validation errors
)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}")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!"}]}]
)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 NoneThe SDK includes comprehensive type hints for better IDE support.
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"
)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].textfrom 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)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!"))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))Store your API key securely using environment variables.
# .env
FREDDY_API_KEY=your-api-key
FREDDY_BASE_URL=https://freddy-api.aitronos.comimport 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")
)import os
from freddy import FreddyClient
# Reads from FREDDY_API_KEY env var
client = FreddyClient(api_key=os.environ["FREDDY_API_KEY"])# ✅ 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!# ✅ Good - specific error handling
try:
response = client.responses.create(...)
except RateLimitError:
# Implement backoff
time.sleep(1)
except AuthenticationError:
# Refresh credentials
pass# ✅ 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)# ✅ 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(...)# ✅ Good - custom timeout for long operations
client = FreddyClient(
api_key="...",
timeout=60.0 # 60 seconds for complex tasks
)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
MIT License - see LICENSE for details.
Built with ❤️ by Aitronos