# Python SDK Official Python SDK for Freddy AI. Build AI-powered applications with type safety, async support, and comprehensive error handling. ## Installation ```bash pip install freddy-ai ``` **Requirements:** - Python 3.8+ - httpx (automatically installed) ## Quick Start ### Synchronous Client ```python 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 ```python 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()) ``` ### Context Manager (Recommended) ```python 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 ```python 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 ```python 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](https://freddy-hub.aitronos.com/freddy/api) - **`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 ```python # 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 ```python # 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 ```python # 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) ```python # 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) ```python # 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 ```python 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 ```python 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 ```python # 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 ```python # 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 ```python # 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 ```python # Search by filename files = client.files.list( organization_id="org_123", search="report", purpose="vector_store" ) ``` ### Retrieve File ```python # 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 ```python # Delete a file result = client.files.delete( organization_id="org_123", file_id="file_abc123" ) print(f"Deleted: {result['deleted']}") ``` ### Async File Operations ```python 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 ```python # 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 ```python # 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 ```python # 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 ```python # 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 ```python # 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 ```python # 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 ```python # 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 ```python 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 ```python # 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 ```python # 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 ```python # 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 ```python # 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 ```python 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 ```python # Get all available models models = client.models.list() for model in models.data: print(f"{model.id} - {model.created}") ``` ### Retrieve Model ```python # 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 ```python 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 ```python 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 ```python 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 ```python 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 ```python 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 ```python 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 ```python 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 ```python 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 ```python 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 ```python 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 ```bash # .env FREDDY_API_KEY=your-api-key FREDDY_BASE_URL=https://freddy-api.aitronos.com ``` ```python 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 ```python 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 ```python # ✅ 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 ```python # ✅ 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 ```python # ✅ 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 ```python # ✅ 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 ```python # ✅ 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 - 📖 **[API Reference](/docs/api-reference/introduction)** - 💬 **[Community Forum](https://community.aitronos.com)** - 🐛 **[GitHub Issues](https://github.com/aitronos/freddy-python/issues)** - 📧 **[Email Support](mailto:support@aitronos.com)** ## License MIT License - see [LICENSE](https://github.com/aitronos/freddy-python/blob/main/LICENSE) for details. *Built with ❤️ by Aitronos*