Skip to main content

Integration Examples

Real-world examples of integrating Perf into your application stack.

Table of Contents

Next.js Integration

API Route Handler

// 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

// 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

# 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

# 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

// 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

// 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

# 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

// 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

# 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

# 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()

Next Steps