Recipe Serve - Python Usage
This guide covers how to configure and manage the recipe server programmatically.Starting the Server Programmatically
Basic Server Start
Copy
from praisonai.recipe.serve import serve, create_app
# Start server (blocking)
serve(host="127.0.0.1", port=8765)
With Configuration
Copy
from praisonai.recipe.serve import serve, load_config
# Load config from file
config = load_config("serve.yaml")
# Override with custom settings
config["auth"] = "api-key"
config["api_key"] = "my-secret-key"
# Start server
serve(
host=config.get("host", "127.0.0.1"),
port=config.get("port", 8765),
reload=False,
config=config
)
Creating ASGI App for Custom Deployment
Copy
from praisonai.recipe.serve import create_app
# Create ASGI app
app = create_app(config={
"auth": "api-key",
"api_key": "my-secret-key",
"cors_origins": "*"
})
# Use with uvicorn programmatically
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=8765)
# Or with other ASGI servers (hypercorn, daphne, etc.)
Configuration File Format
serve.yaml
Copy
# Server binding
host: 127.0.0.1
port: 8765
# Authentication
auth: api-key # none, api-key, jwt
api_key: your-secret-key # or use PRAISONAI_API_KEY env var
# Recipe filtering
recipes:
- support-reply-drafter
- meeting-action-items
- code-review
# Performance
preload: true # Preload recipes on startup
# CORS (for web clients)
cors_origins: "https://app.example.com,https://admin.example.com"
# Logging
log_level: info
Using agents.yaml (Unified Config)
You can include serve configuration in your existingagents.yaml:
Copy
# agents.yaml
framework: praisonai
topic: My Application
roles:
assistant:
role: AI Assistant
goal: Help users
tasks:
respond:
description: Respond to {query}
# Server configuration section
serve:
host: 127.0.0.1
port: 8765
auth: api-key
preload: true
Copy
from praisonai.recipe.serve import load_config, serve
# Load unified config
config = load_config("agents.yaml")
# Extract serve section
serve_config = config.get("serve", {})
# Start server
serve(
host=serve_config.get("host", "127.0.0.1"),
port=serve_config.get("port", 8765),
config=serve_config
)
Authentication Middleware
API Key Authentication
Copy
from praisonai.recipe.serve import create_auth_middleware, create_app
# Create auth middleware
auth_middleware = create_auth_middleware(
auth_type="api-key",
api_key="my-secret-key"
)
# Create app with auth
app = create_app(config={
"auth": "api-key",
"api_key": "my-secret-key"
})
Custom Authentication
Copy
from starlette.middleware.base import BaseHTTPMiddleware
from starlette.responses import JSONResponse
class CustomAuthMiddleware(BaseHTTPMiddleware):
async def dispatch(self, request, call_next):
# Skip auth for health endpoint
if request.url.path == "/health":
return await call_next(request)
# Custom auth logic
token = request.headers.get("Authorization")
if not self.validate_token(token):
return JSONResponse(
{"error": "Unauthorized"},
status_code=401
)
return await call_next(request)
def validate_token(self, token):
# Your validation logic
return token == "Bearer valid-token"
Route Handlers
Available Routes
| Route | Method | Description |
|---|---|---|
/health | GET | Health check |
/v1/recipes | GET | List recipes |
/v1/recipes/{name} | GET | Describe recipe |
/v1/recipes/{name}/schema | GET | Get recipe schema |
/v1/recipes/run | POST | Run recipe (sync) |
/v1/recipes/stream | POST | Run recipe (SSE) |
/v1/recipes/validate | POST | Validate recipe |
Custom Route Example
Copy
from starlette.applications import Starlette
from starlette.routing import Route
from starlette.responses import JSONResponse
from praisonai.recipe.serve import create_app
# Get base app
base_app = create_app()
# Add custom route
async def custom_endpoint(request):
return JSONResponse({"custom": "response"})
# Extend routes
custom_routes = [
Route("/custom", custom_endpoint, methods=["GET"]),
]
# Create new app with extended routes
from starlette.routing import Mount
extended_app = Starlette(
routes=list(base_app.routes) + custom_routes
)
Docker Deployment
Dockerfile
Copy
FROM python:3.11-slim
# Install dependencies
RUN pip install praisonai[serve]
# Copy configuration
COPY serve.yaml /app/
WORKDIR /app
# Set environment variables
ENV PRAISONAI_API_KEY=${PRAISONAI_API_KEY}
ENV OPENAI_API_KEY=${OPENAI_API_KEY}
# Expose port
EXPOSE 8765
# Health check
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
CMD curl -f http://localhost:8765/health || exit 1
# Start server
CMD ["praisonai", "recipe", "serve", "--config", "serve.yaml"]
docker-compose.yaml
Copy
version: '3.8'
services:
recipe-server:
build: .
ports:
- "8765:8765"
environment:
- PRAISONAI_API_KEY=${PRAISONAI_API_KEY}
- OPENAI_API_KEY=${OPENAI_API_KEY}
volumes:
- ./recipes:/app/recipes
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8765/health"]
interval: 30s
timeout: 10s
retries: 3
restart: unless-stopped
Kubernetes Deployment
deployment.yaml
Copy
apiVersion: apps/v1
kind: Deployment
metadata:
name: recipe-server
spec:
replicas: 3
selector:
matchLabels:
app: recipe-server
template:
metadata:
labels:
app: recipe-server
spec:
containers:
- name: recipe-server
image: your-registry/recipe-server:latest
ports:
- containerPort: 8765
env:
- name: PRAISONAI_API_KEY
valueFrom:
secretKeyRef:
name: recipe-secrets
key: api-key
- name: OPENAI_API_KEY
valueFrom:
secretKeyRef:
name: recipe-secrets
key: openai-key
livenessProbe:
httpGet:
path: /health
port: 8765
initialDelaySeconds: 10
periodSeconds: 30
readinessProbe:
httpGet:
path: /health
port: 8765
initialDelaySeconds: 5
periodSeconds: 10
resources:
requests:
memory: "256Mi"
cpu: "250m"
limits:
memory: "512Mi"
cpu: "500m"
---
apiVersion: v1
kind: Service
metadata:
name: recipe-server
spec:
selector:
app: recipe-server
ports:
- port: 80
targetPort: 8765
type: ClusterIP
Testing the Server
Unit Test Example
Copy
import pytest
from starlette.testclient import TestClient
from praisonai.recipe.serve import create_app
@pytest.fixture
def client():
app = create_app(config={"auth": "none"})
return TestClient(app)
def test_health(client):
response = client.get("/health")
assert response.status_code == 200
assert response.json()["status"] == "healthy"
def test_list_recipes(client):
response = client.get("/v1/recipes")
assert response.status_code == 200
assert "recipes" in response.json()
def test_auth_required():
app = create_app(config={
"auth": "api-key",
"api_key": "test-key"
})
client = TestClient(app)
# Without key - should fail
response = client.get("/v1/recipes")
assert response.status_code == 401
# With key - should succeed
response = client.get(
"/v1/recipes",
headers={"X-API-Key": "test-key"}
)
assert response.status_code == 200
Best Practices
1. Always Use Auth in Production
Copy
# Development
serve(host="127.0.0.1", port=8765)
# Production
serve(
host="0.0.0.0",
port=8765,
config={
"auth": "api-key",
"api_key": os.environ["PRAISONAI_API_KEY"]
}
)
2. Preload Recipes for Faster First Request
Copy
# serve.yaml
preload: true
recipes:
- frequently-used-recipe
3. Use Health Checks
Copy
# In your monitoring system
import requests
def check_server_health():
try:
response = requests.get("http://localhost:8765/health", timeout=5)
return response.json()["status"] == "healthy"
except:
return False
4. Configure CORS for Web Clients
Copy
# serve.yaml
cors_origins: "https://app.example.com"
Next Steps
- See CLI Usage for command-line options
- Review Integration Models
- Explore Endpoints Code for client usage

