Integration Examples
Real-world examples of integrating Perf into your application stack.Table of Contents
- Next.js Integration
- Python FastAPI
- Express.js Backend
- React Frontend (with Streaming)
- LangChain Integration
- Vercel AI SDK
- Background Jobs
- Slack Bot
Next.js Integration
API Route Handler
Copy
// app/api/chat/route.ts
import { NextRequest, NextResponse } from 'next/server';
const PERF_API_KEY = process.env.PERF_API_KEY!;
const PERF_API_URL = 'https://api.withperf.pro/v1/chat';
export async function POST(request: NextRequest) {
try {
const { messages } = await request.json();
// Call Perf API
const response = await fetch(PERF_API_URL, {
method: 'POST',
headers: {
'Authorization': `Bearer ${PERF_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
messages,
max_cost_per_call: 0.01,
}),
});
if (!response.ok) {
const error = await response.json();
return NextResponse.json(
{ error: error.message },
{ status: response.status }
);
}
const data = await response.json();
return NextResponse.json(data);
} catch (error) {
console.error('Chat API error:', error);
return NextResponse.json(
{ error: 'Internal server error' },
{ status: 500 }
);
}
}
Client Component
Copy
// components/ChatInterface.tsx
'use client';
import { useState } from 'react';
interface Message {
role: 'user' | 'assistant';
content: string;
}
export default function ChatInterface() {
const [messages, setMessages] = useState<Message[]>([]);
const [input, setInput] = useState('');
const [loading, setLoading] = useState(false);
const sendMessage = async () => {
if (!input.trim()) return;
const userMessage: Message = { role: 'user', content: input };
setMessages(prev => [...prev, userMessage]);
setInput('');
setLoading(true);
try {
const response = await fetch('/api/chat', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
messages: [...messages, userMessage],
}),
});
const data = await response.json();
if (data.error) {
throw new Error(data.error);
}
const assistantMessage: Message = {
role: 'assistant',
content: data.output,
};
setMessages(prev => [...prev, assistantMessage]);
} catch (error) {
console.error('Error:', error);
alert('Failed to send message');
} finally {
setLoading(false);
}
};
return (
<div className="flex flex-col h-screen">
<div className="flex-1 overflow-y-auto p-4 space-y-4">
{messages.map((msg, idx) => (
<div
key={idx}
className={`p-3 rounded-lg ${
msg.role === 'user'
? 'bg-blue-100 ml-12'
: 'bg-gray-100 mr-12'
}`}
>
{msg.content}
</div>
))}
{loading && <div className="text-gray-500">Thinking...</div>}
</div>
<div className="border-t p-4">
<div className="flex gap-2">
<input
type="text"
value={input}
onChange={(e) => setInput(e.target.value)}
onKeyPress={(e) => e.key === 'Enter' && sendMessage()}
className="flex-1 border rounded px-3 py-2"
placeholder="Type a message..."
disabled={loading}
/>
<button
onClick={sendMessage}
disabled={loading}
className="bg-blue-500 text-white px-6 py-2 rounded disabled:opacity-50"
>
Send
</button>
</div>
</div>
</div>
);
}
Python FastAPI
Main Application
Copy
# main.py
from fastapi import FastAPI, HTTPException, Depends
from fastapi.security import HTTPBearer, HTTPAuthCredentials
from pydantic import BaseModel
from typing import List, Optional
import httpx
import os
app = FastAPI()
security = HTTPBearer()
PERF_API_KEY = os.environ.get("PERF_API_KEY")
PERF_API_URL = "https://api.withperf.pro/v1/chat"
class Message(BaseModel):
role: str
content: str
class ChatRequest(BaseModel):
messages: List[Message]
max_cost_per_call: Optional[float] = 0.01
class ChatResponse(BaseModel):
output: str
model_used: str
billing: dict
tokens: dict
@app.post("/chat", response_model=ChatResponse)
async def chat(
request: ChatRequest,
credentials: HTTPAuthCredentials = Depends(security)
):
"""
Chat endpoint that proxies to Perf API
"""
# Validate user token (your own auth logic)
if not await validate_user_token(credentials.credentials):
raise HTTPException(status_code=401, detail="Invalid token")
# Call Perf API
async with httpx.AsyncClient() as client:
try:
response = await client.post(
PERF_API_URL,
json=request.dict(),
headers={
"Authorization": f"Bearer {PERF_API_KEY}",
"Content-Type": "application/json"
},
timeout=30.0
)
response.raise_for_status()
return response.json()
except httpx.HTTPStatusError as e:
raise HTTPException(
status_code=e.response.status_code,
detail=e.response.json().get("error", "Unknown error")
)
except httpx.TimeoutException:
raise HTTPException(status_code=504, detail="Request timeout")
async def validate_user_token(token: str) -> bool:
# Implement your user authentication logic
return True
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=8000)
Background Task Processing
Copy
# background_tasks.py
from celery import Celery
import httpx
import os
celery = Celery('tasks', broker='redis://localhost:6379/0')
PERF_API_KEY = os.environ.get("PERF_API_KEY")
@celery.task
def process_document_async(document_text: str, user_id: str):
"""
Process documents in background using Perf
"""
with httpx.Client() as client:
response = client.post(
"https://api.withperf.pro/v1/chat",
json={
"messages": [
{
"role": "user",
"content": f"Summarize this document:\n\n{document_text}"
}
],
"max_cost_per_call": 0.02
},
headers={
"Authorization": f"Bearer {PERF_API_KEY}",
"Content-Type": "application/json"
}
)
result = response.json()
# Store result in database
save_summary(user_id, result['output'], result['billing']['cost_usd'])
return result
Express.js Backend
Copy
// server.js
const express = require('express');
const fetch = require('node-fetch');
require('dotenv').config();
const app = express();
app.use(express.json());
const PERF_API_KEY = process.env.PERF_API_KEY;
const PERF_API_URL = 'https://api.withperf.pro/v1/chat';
// Rate limiting per user
const userRateLimits = new Map();
function checkUserRateLimit(userId) {
const now = Date.now();
const userLimit = userRateLimits.get(userId) || { count: 0, resetAt: now + 60000 };
if (now > userLimit.resetAt) {
userLimit.count = 0;
userLimit.resetAt = now + 60000;
}
if (userLimit.count >= 20) {
return false;
}
userLimit.count++;
userRateLimits.set(userId, userLimit);
return true;
}
app.post('/api/chat', async (req, res) => {
try {
// Validate user session
const userId = req.session?.userId;
if (!userId) {
return res.status(401).json({ error: 'Unauthorized' });
}
// Check rate limit
if (!checkUserRateLimit(userId)) {
return res.status(429).json({
error: 'Too many requests',
retryAfter: 60
});
}
// Call Perf API
const response = await fetch(PERF_API_URL, {
method: 'POST',
headers: {
'Authorization': `Bearer ${PERF_API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
messages: req.body.messages,
max_cost_per_call: 0.01
})
});
const data = await response.json();
if (!response.ok) {
return res.status(response.status).json(data);
}
// Log usage for billing
await logUsage(userId, data.billing.cost_usd, data.tokens);
res.json(data);
} catch (error) {
console.error('Chat error:', error);
res.status(500).json({ error: 'Internal server error' });
}
});
app.listen(3000, () => {
console.log('Server running on port 3000');
});
React Frontend with Streaming
Copy
// hooks/useChat.ts
import { useState, useCallback } from 'react';
interface Message {
role: 'user' | 'assistant';
content: string;
}
export function useChat() {
const [messages, setMessages] = useState<Message[]>([]);
const [isLoading, setIsLoading] = useState(false);
const [streamingContent, setStreamingContent] = useState('');
const sendMessage = useCallback(async (content: string) => {
const userMessage: Message = { role: 'user', content };
setMessages(prev => [...prev, userMessage]);
setIsLoading(true);
setStreamingContent('');
try {
const response = await fetch('/api/chat/stream', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
messages: [...messages, userMessage],
}),
});
const reader = response.body?.getReader();
const decoder = new TextDecoder();
let fullContent = '';
while (true) {
const { done, value } = await reader!.read();
if (done) break;
const chunk = decoder.decode(value);
const lines = chunk.split('\n');
for (const line of lines) {
if (line.startsWith('data: ')) {
const data = JSON.parse(line.slice(6));
if (!data.done) {
fullContent += data.chunk;
setStreamingContent(fullContent);
} else {
// Streaming complete
setMessages(prev => [
...prev,
{ role: 'assistant', content: fullContent }
]);
setStreamingContent('');
}
}
}
}
} catch (error) {
console.error('Streaming error:', error);
alert('Failed to send message');
} finally {
setIsLoading(false);
}
}, [messages]);
return {
messages,
isLoading,
streamingContent,
sendMessage,
};
}
LangChain Integration
Copy
# perf_langchain.py
from langchain.llms.base import LLM
from typing import Any, List, Optional
import httpx
import os
class PerfLLM(LLM):
"""
LangChain wrapper for Perf API
"""
max_cost_per_call: float = 0.01
perf_api_key: str = os.environ.get("PERF_API_KEY", "")
@property
def _llm_type(self) -> str:
return "perf"
def _call(
self,
prompt: str,
stop: Optional[List[str]] = None
) -> str:
with httpx.Client() as client:
response = client.post(
"https://api.withperf.pro/v1/chat",
json={
"messages": [{"role": "user", "content": prompt}],
"max_cost_per_call": self.max_cost_per_call
},
headers={
"Authorization": f"Bearer {self.perf_api_key}",
"Content-Type": "application/json"
}
)
response.raise_for_status()
data = response.json()
return data["output"]
# Usage
from langchain.chains import LLMChain
from langchain.prompts import PromptTemplate
llm = PerfLLM(max_cost_per_call=0.005)
template = """
Extract the key information from this text:
{text}
Return JSON with: name, email, phone
"""
prompt = PromptTemplate(template=template, input_variables=["text"])
chain = LLMChain(llm=llm, prompt=prompt)
result = chain.run(text="Contact John Doe at [email protected] or 555-1234")
print(result)
Vercel AI SDK
Copy
// app/api/chat/route.ts
import { OpenAIStream, StreamingTextResponse } from 'ai';
export const runtime = 'edge';
export async function POST(req: Request) {
const { messages } = await req.json();
// Call Perf streaming endpoint
const response = await fetch('https://api.withperf.pro/v1/chat/stream', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.PERF_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ messages }),
});
// Convert to Vercel AI SDK format
const stream = new ReadableStream({
async start(controller) {
const reader = response.body?.getReader();
const decoder = new TextDecoder();
while (true) {
const { done, value } = await reader!.read();
if (done) break;
const chunk = decoder.decode(value);
const lines = chunk.split('\n');
for (const line of lines) {
if (line.startsWith('data: ')) {
const data = JSON.parse(line.slice(6));
if (!data.done) {
controller.enqueue(new TextEncoder().encode(data.chunk));
}
}
}
}
controller.close();
},
});
return new StreamingTextResponse(stream);
}
Background Jobs
Copy
# batch_processor.py
import asyncio
import httpx
from typing import List, Dict
import os
PERF_API_KEY = os.environ.get("PERF_API_KEY")
async def process_batch(items: List[str]) -> List[Dict]:
"""
Process a batch of items using Perf API with concurrency control
"""
async with httpx.AsyncClient() as client:
semaphore = asyncio.Semaphore(10) # Max 10 concurrent requests
async def process_item(item: str):
async with semaphore:
response = await client.post(
"https://api.withperf.pro/v1/chat",
json={
"messages": [
{"role": "user", "content": f"Analyze: {item}"}
],
"max_cost_per_call": 0.005
},
headers={
"Authorization": f"Bearer {PERF_API_KEY}",
"Content-Type": "application/json"
},
timeout=30.0
)
return response.json()
results = await asyncio.gather(
*[process_item(item) for item in items],
return_exceptions=True
)
return results
# Usage
if __name__ == "__main__":
items = ["item1", "item2", "item3", ...]
results = asyncio.run(process_batch(items))
total_cost = sum(r.get('billing', {}).get('cost_usd', 0) for r in results)
print(f"Processed {len(results)} items for ${total_cost:.4f}")
Slack Bot
Copy
# slack_bot.py
from slack_bolt import App
from slack_bolt.adapter.socket_mode import SocketModeHandler
import httpx
import os
app = App(token=os.environ.get("SLACK_BOT_TOKEN"))
PERF_API_KEY = os.environ.get("PERF_API_KEY")
@app.event("app_mention")
def handle_mention(event, say):
"""
Respond to @mentions using Perf API
"""
user_message = event['text']
# Call Perf
with httpx.Client() as client:
response = client.post(
"https://api.withperf.pro/v1/chat",
json={
"messages": [{"role": "user", "content": user_message}],
"max_cost_per_call": 0.01
},
headers={
"Authorization": f"Bearer {PERF_API_KEY}",
"Content-Type": "application/json"
}
)
data = response.json()
say(
text=data['output'],
thread_ts=event['ts'],
blocks=[
{
"type": "section",
"text": {"type": "mrkdwn", "text": data['output']}
},
{
"type": "context",
"elements": [
{
"type": "mrkdwn",
"text": f"_Model: {data['model_used']} • Cost: ${data['billing']['cost_usd']:.5f}_"
}
]
}
]
)
if __name__ == "__main__":
handler = SocketModeHandler(app, os.environ["SLACK_APP_TOKEN"])
handler.start()