UNPKG

@revenium/perplexity

Version:
867 lines (648 loc) 22.5 kB
# Revenium Middleware for Perplexity A lightweight, production-ready middleware that adds **Revenium metering and tracking** to Perplexity AI API calls. [![npm version](https://img.shields.io/npm/v/@revenium/perplexity.svg)](https://www.npmjs.com/package/@revenium/perplexity) [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT) ## Features - ✅ **Zero Configuration** - Works out of the box with environment variables - ✅ **Automatic Metering** - Tracks all API calls with detailed usage metrics - ✅ **Streaming Support** - Full support for streaming responses - ✅ **TypeScript First** - Built with TypeScript, includes full type definitions - ✅ **Multi-Format** - Supports both ESM and CommonJS - ✅ **Custom Metadata** - Add custom tracking metadata to any request - ✅ **Production Ready** - Battle-tested and optimized for production use ## Package Migration This package has been renamed from `revenium-middleware-perplexity-node` to `@revenium/perplexity` for better organization and simpler naming. ### Migration Steps If you're upgrading from the old package: ```bash # Uninstall the old package npm uninstall revenium-middleware-perplexity-node # Install the new package npm install @revenium/perplexity ``` **Update your imports:** ```typescript // Old import import "revenium-middleware-perplexity-node"; // New import import "@revenium/perplexity"; ``` All functionality remains exactly the same - only the package name has changed. ## Table of Contents - [Installation](https://github.com/revenium/revenium-middleware-perplexity-node#-installation) - [Three Ways to Use This Middleware](https://github.com/revenium/revenium-middleware-perplexity-node#-three-ways-to-use-this-middleware) - [Option 1: New Project with npm Package](https://github.com/revenium/revenium-middleware-perplexity-node#option-1-new-project-with-npm-package-recommended) - [Option 2: Clone and Use Locally](https://github.com/revenium/revenium-middleware-perplexity-node#option-2-clone-and-use-locally) - [Option 3: Add to Existing Project](https://github.com/revenium/revenium-middleware-perplexity-node#option-3-add-to-existing-project) - [Quick Start](https://github.com/revenium/revenium-middleware-perplexity-node#-quick-start) - [API Reference](https://github.com/revenium/revenium-middleware-perplexity-node#-api-reference) - [Examples](https://github.com/revenium/revenium-middleware-perplexity-node#-examples) - [Environment Variables](https://github.com/revenium/revenium-middleware-perplexity-node#-environment-variables) ## Installation ```bash npm install @revenium/perplexity ``` ## Three Ways to Use This Middleware ### Option 1: New Project with npm Package (Recommended) **Best for:** Starting a new project or adding Perplexity with Revenium to an existing project. #### Step 1: Create a new project ```bash mkdir my-perplexity-project cd my-perplexity-project npm init -y ``` #### Step 2: Install the middleware ```bash npm install @revenium/perplexity dotenv ``` #### Step 3: Create `.env` file ```env # Perplexity API Configuration PERPLEXITY_API_KEY=your_perplexity_api_key # Revenium Metering Configuration REVENIUM_METERING_API_KEY=your_revenium_api_key REVENIUM_METERING_BASE_URL=https://api.revenium.io/meter ``` #### Step 4: Create `index.js` ```javascript const { initializeReveniumFromEnv, initializePerplexityFromEnv, createChatCompletion, PERPLEXITY_MODELS, } = require("@revenium/perplexity"); async function main() { // Initialize configurations initializeReveniumFromEnv(); initializePerplexityFromEnv(); // Create a chat completion const result = await createChatCompletion({ messages: [{ role: "user", content: "What is the capital of France?" }], model: PERPLEXITY_MODELS.SONAR_PRO, }); console.log("Response:", result.content); console.log("Tokens used:", result.usage.totalTokens); } main().catch(console.error); ``` #### Step 5: Run your project ```bash node index.js ``` --- ### Option 2: Clone and Use Locally **Best for:** Development, testing, or contributing to the middleware. #### Step 1: Clone the repository ```bash git clone https://github.com/revenium/revenium-middleware-perplexity-node.git cd revenium-middleware-perplexity-node ``` #### Step 2: Install dependencies ```bash npm install ``` #### Step 3: Create `.env` file ```env # Perplexity API Configuration PERPLEXITY_API_KEY=your_perplexity_api_key # Revenium Metering Configuration REVENIUM_METERING_API_KEY=your_revenium_api_key REVENIUM_METERING_BASE_URL=https://api.revenium.io/meter ``` #### Step 4: Build the project ```bash npm run build ``` #### Step 5: Run examples **TypeScript Examples:** ```bash npm run example:basic # Basic chat completion npm run example:streaming # Streaming response npm run example:chat # Multi-turn conversation npm run example:metadata # Custom metadata ``` **JavaScript Playground:** ```bash npm run playground:basic # Basic chat completion npm run playground:streaming # Streaming response npm run playground:chat # Multi-turn conversation npm run playground:metadata # Custom metadata ``` #### Step 6: Use in your own code After building, you can import from the local build: ```javascript const { initializeReveniumFromEnv, initializePerplexityFromEnv, createChatCompletion, } = require("./dist/cjs"); // Your code here... ``` --- ### Option 3: Add to Existing Project **Best for:** Integrating Perplexity with Revenium into an existing Node.js project. #### Step 1: Install the middleware ```bash npm install @revenium/perplexity ``` #### Step 2: Add environment variables Add to your existing `.env` file: ```env # Perplexity API Configuration PERPLEXITY_API_KEY=your_perplexity_api_key # Revenium Metering Configuration REVENIUM_METERING_API_KEY=your_revenium_api_key REVENIUM_METERING_BASE_URL=https://api.revenium.io/meter ``` #### Step 3: Initialize in your application **For CommonJS projects:** ```javascript require("dotenv").config(); const { initializeReveniumFromEnv, initializePerplexityFromEnv, createChatCompletion, PERPLEXITY_MODELS, } = require("@revenium/perplexity"); // Initialize once at app startup initializeReveniumFromEnv(); initializePerplexityFromEnv(); // Use anywhere in your app async function askPerplexity(question) { const result = await createChatCompletion({ messages: [{ role: "user", content: question }], model: PERPLEXITY_MODELS.SONAR_PRO, }); return result.content; } ``` **For ES Modules projects:** ```javascript import "dotenv/config"; import { initializeReveniumFromEnv, initializePerplexityFromEnv, createChatCompletion, PERPLEXITY_MODELS, } from "@revenium/perplexity"; // Initialize once at app startup initializeReveniumFromEnv(); initializePerplexityFromEnv(); // Use anywhere in your app export async function askPerplexity(question) { const result = await createChatCompletion({ messages: [{ role: "user", content: question }], model: PERPLEXITY_MODELS.SONAR_PRO, }); return result.content; } ``` **For TypeScript projects:** ```typescript import "dotenv/config"; import { initializeReveniumFromEnv, initializePerplexityFromEnv, createChatCompletion, PERPLEXITY_MODELS, type ChatCompletionResult, } from "@revenium/perplexity"; // Initialize once at app startup initializeReveniumFromEnv(); initializePerplexityFromEnv(); // Use anywhere in your app export async function askPerplexity(question: string): Promise<string> { const result: ChatCompletionResult = await createChatCompletion({ messages: [{ role: "user", content: question }], model: PERPLEXITY_MODELS.SONAR_PRO, }); return result.content; } ``` --- ## Quick Start ### 1. Set up environment variables Create a `.env` file in your project root: ```env # Perplexity API Configuration PERPLEXITY_API_KEY=your_perplexity_api_key # Revenium Metering Configuration REVENIUM_METERING_API_KEY=your_revenium_api_key REVENIUM_METERING_BASE_URL=https://api.revenium.io/meter ``` ### 2. Initialize and use ```typescript import { initializeReveniumFromEnv, initializePerplexityFromEnv, createChatCompletion, PERPLEXITY_MODELS, } from "@revenium/perplexity"; // Initialize configurations initializeReveniumFromEnv(); initializePerplexityFromEnv(); // Create a chat completion const result = await createChatCompletion({ messages: [{ role: "user", content: "What is the capital of France?" }], model: PERPLEXITY_MODELS.SONAR_PRO, }); console.log(result.content); // Output: "The capital of France is Paris." ``` ## API Reference ### Configuration #### `initializeReveniumFromEnv()` Initialize Revenium configuration from environment variables. ```typescript const config = initializeReveniumFromEnv(); ``` #### `initializePerplexityFromEnv()` Initialize Perplexity configuration from environment variables. ```typescript const config = initializePerplexityFromEnv(); ``` #### `initializeRevenium(config)` Initialize Revenium with custom configuration. ```typescript initializeRevenium({ meteringApiKey: "your_api_key", meteringBaseUrl: "https://api.revenium.io/meter", teamId: "your_team_id", // Optional }); ``` #### `initializePerplexity(config)` Initialize Perplexity with custom configuration. ```typescript initializePerplexity({ apiKey: "your_perplexity_api_key", baseUrl: "https://api.perplexity.ai", // Optional }); ``` ### Chat Completions #### `createChatCompletion(params)` Create a chat completion with automatic metering. ```typescript const result = await createChatCompletion({ messages: [ { role: "system", content: "You are a helpful assistant." }, { role: "user", content: "Hello!" }, ], model: PERPLEXITY_MODELS.SONAR_PRO, maxTokens: 100, temperature: 0.7, usageMetadata: { // Optional subscriber: { id: "user-123" }, organizationId: "org-456", productId: "product-789", }, }); console.log(result.content); console.log(result.usage); console.log(result.transactionId); ``` **Parameters:** - `messages` - Array of message objects with `role` and `content` - `model` - Perplexity model to use (see [Available Models](https://github.com/revenium/revenium-middleware-perplexity-node#available-models)) - `maxTokens` - Maximum tokens to generate (optional) - `temperature` - Sampling temperature 0-2 (optional) - `topP` - Nucleus sampling parameter (optional) - `presencePenalty` - Presence penalty -2 to 2 (optional) - `frequencyPenalty` - Frequency penalty -2 to 2 (optional) - `usageMetadata` - Custom metadata for tracking (optional) **Returns:** ```typescript { content: string; role: string; finishReason: string | null; usage: { promptTokens: number; completionTokens: number; totalTokens: number; } model: string; transactionId: string; rawResponse: PerplexityResponse; } ``` #### `createStreamingChatCompletion(params)` Create a streaming chat completion. ```typescript const result = await createStreamingChatCompletion({ messages: [{ role: "user", content: "Count from 1 to 5" }], model: PERPLEXITY_MODELS.SONAR_PRO, }); for await (const chunk of result.stream) { const content = chunk.choices[0]?.delta?.content || ""; process.stdout.write(content); } ``` **Returns:** ```typescript { stream: AsyncGenerator<PerplexityStreamChunk>; transactionId: string; model: string; } ``` ### Available Models ```typescript import { PERPLEXITY_MODELS } from "@revenium/perplexity"; // Online Models (with internet access) PERPLEXITY_MODELS.SONAR; // "sonar" PERPLEXITY_MODELS.SONAR_PRO; // "sonar-pro" PERPLEXITY_MODELS.SONAR_REASONING; // "sonar-reasoning" // Chat Models (offline) PERPLEXITY_MODELS.LLAMA_3_1_SONAR_SMALL_128K_CHAT; // "llama-3.1-sonar-small-128k-chat" PERPLEXITY_MODELS.LLAMA_3_1_SONAR_LARGE_128K_CHAT; // "llama-3.1-sonar-large-128k-chat" PERPLEXITY_MODELS.LLAMA_3_1_SONAR_HUGE_128K_CHAT; // "llama-3.1-sonar-huge-128k-chat" ``` ### Utility Functions #### `disableRevenium()` / `enableRevenium()` Temporarily disable or enable Revenium metering. ```typescript import { disableRevenium, enableRevenium } from "@revenium/perplexity"; disableRevenium(); // Stop sending metering data // ... make API calls ... enableRevenium(); // Resume sending metering data ``` #### `generateTransactionId()` Generate a unique transaction ID. ```typescript import { generateTransactionId } from "@revenium/perplexity"; const txnId = generateTransactionId(); ``` ## Examples ### Basic Chat Completion ```typescript import { initializeReveniumFromEnv, initializePerplexityFromEnv, createChatCompletion, PERPLEXITY_MODELS, } from "@revenium/perplexity"; initializeReveniumFromEnv(); initializePerplexityFromEnv(); const result = await createChatCompletion({ messages: [{ role: "user", content: "What is the capital of France?" }], model: PERPLEXITY_MODELS.SONAR_PRO, }); console.log(result.content); ``` ### Streaming Response ```typescript const result = await createStreamingChatCompletion({ messages: [{ role: "user", content: "Write a short poem about AI" }], model: PERPLEXITY_MODELS.SONAR_PRO, }); for await (const chunk of result.stream) { const content = chunk.choices[0]?.delta?.content || ""; process.stdout.write(content); } ``` ### Multi-turn Conversation ```typescript const messages = [ { role: "system", content: "You are a helpful assistant." }, { role: "user", content: "What is the capital of France?" }, ]; const response1 = await createChatCompletion({ messages, model: PERPLEXITY_MODELS.SONAR_PRO, }); messages.push({ role: "assistant", content: response1.content }); messages.push({ role: "user", content: "What is its population?" }); const response2 = await createChatCompletion({ messages, model: PERPLEXITY_MODELS.SONAR_PRO, }); ``` ### Custom Metadata ```typescript const result = await createChatCompletion({ messages: [{ role: "user", content: "Hello!" }], model: PERPLEXITY_MODELS.SONAR_PRO, usageMetadata: { subscriber: { id: "user-123", email: "user@example.com", }, organizationId: "org-456", productId: "premium-plan", traceId: "trace-abc-123", }, }); ``` ## What Gets Tracked The middleware automatically captures: - **Token Usage**: Prompt and completion tokens for accurate billing - **Request Duration**: Total time for each API call - **Model Information**: Which Perplexity model was used - **Operation Type**: Chat completion, streaming, etc. - **Error Tracking**: Failed requests and error details - **Streaming Metrics**: Time to first token for streaming responses - **Custom Metadata**: Business context you provide ## Advanced Usage ### Streaming Responses ```typescript import { initializeReveniumFromEnv, initializePerplexityFromEnv, createStreamingChatCompletion, PERPLEXITY_MODELS, } from "@revenium/perplexity"; initializeReveniumFromEnv(); initializePerplexityFromEnv(); const result = await createStreamingChatCompletion({ messages: [{ role: "user", content: "Count from 1 to 5" }], model: PERPLEXITY_MODELS.SONAR_PRO, usageMetadata: { subscriber: { id: "user-123" }, taskType: "counting-demo", }, }); for await (const chunk of result.stream) { const content = chunk.choices[0]?.delta?.content || ""; process.stdout.write(content); } ``` ### Custom Metadata Tracking Add business context to your AI usage: ```typescript const customMetadata = { subscriber: { id: "user-789", email: "user@company.com", credential: { name: "premium-user", value: "tier-1", }, }, organizationId: "org-456", productId: "premium-plan", taskType: "RESEARCH", agent: "ResearchBot", traceId: "session-123", responseQualityScore: 9.2, }; const result = await createChatCompletion({ messages: [{ role: "user", content: "Research AI trends" }], model: PERPLEXITY_MODELS.SONAR_PRO, usageMetadata: customMetadata, }); ``` ### Usage Metadata Interface All metadata fields are optional: ```typescript interface UsageMetadata { traceId?: string; // Session or conversation ID taskType?: string; // Type of AI task organizationId?: string; // Organization/company ID subscriptionId?: string; // Billing plan ID productId?: string; // Your product/feature ID agent?: string; // AI agent identifier responseQualityScore?: number; // Quality score (0-1) subscriber?: { id?: string; // User ID from your system email?: string; // User's email address credential?: { name?: string; // Credential name value?: string; // Credential value }; }; } ``` ## Configuration Options ### Environment Variables | Variable | Required | Default | Description | | ---------------------------- | -------- | ------------------------------- | --------------------------------- | | `PERPLEXITY_API_KEY` | Yes | - | Your Perplexity API key | | `REVENIUM_METERING_API_KEY` | Yes | - | Your Revenium API key | | `REVENIUM_METERING_BASE_URL` | Yes | - | Revenium metering API base URL | | `PERPLEXITY_API_BASE_URL` | No | `https://api.perplexity.ai` | Perplexity API base URL | | `DEBUG` | No | `false` | Enable debug logging | ### Manual Configuration ```typescript import { initializeRevenium, initializePerplexity, createChatCompletion, } from "@revenium/perplexity"; // Manual configuration initializeRevenium({ meteringApiKey: "hak_your_revenium_key", meteringBaseUrl: "https://api.revenium.io/meter/v2", }); initializePerplexity({ apiKey: "pplx_your_perplexity_key", baseUrl: "https://api.perplexity.ai", }); ``` ## Troubleshooting ### Common Issues #### "Missing API Key" Error ```bash # Make sure you've set the API keys export PERPLEXITY_API_KEY="pplx_your_actual_api_key" export REVENIUM_METERING_API_KEY="hak_your_actual_revenium_key" # Verify they're set echo $PERPLEXITY_API_KEY echo $REVENIUM_METERING_API_KEY ``` #### "Requests not being tracked" ```bash # Verify Revenium configuration export REVENIUM_METERING_API_KEY="hak_your_actual_revenium_key" export REVENIUM_METERING_BASE_URL="https://api.revenium.io/meter/v2" # Enable debug logging to see what's happening export DEBUG="true" ``` #### TypeScript errors with usageMetadata - Ensure you're importing from `@revenium/perplexity` - Check that your TypeScript version is 5.0+ - Verify you're using the latest version: `npm update @revenium/perplexity` #### Build/Import Errors ```bash # Clean and reinstall rm -rf node_modules npm install # For TypeScript projects npm run build ``` ### Debug Mode Enable debug logging to troubleshoot issues: ```bash export DEBUG="true" node your-script.js ``` This will show: - Initialization details - Configuration loading - API call information - Error details ## Project Structure ``` revenium-middleware-perplexity-node/ ├── src/ │ ├── core/ │ │ ├── config/ # Configuration management │ │ ├── tracking/ # Metering and tracking │ │ └── wrapper/ # Perplexity API wrapper │ ├── types/ # TypeScript type definitions │ ├── utils/ # Utility functions │ └── index.ts # Main entry point ├── examples/ # TypeScript examples ├── playground/ # JavaScript examples └── dist/ ├── cjs/ # CommonJS build ├── esm/ # ES Modules build └── types/ # TypeScript definitions ``` ## Running Examples ### TypeScript Examples ```bash npm run example:basic # Basic chat completion npm run example:streaming # Streaming response npm run example:chat # Multi-turn conversation npm run example:metadata # Custom metadata ``` ### JavaScript Playground ```bash npm run playground:basic # Basic chat completion npm run playground:streaming # Streaming response npm run playground:chat # Multi-turn conversation npm run playground:metadata # Custom metadata ``` ## How It Works 1. **Initialization**: When you call `initializePerplexityFromEnv()` and `initializeReveniumFromEnv()`, the middleware sets up configurations 2. **Request Wrapping**: All Perplexity API calls go through the middleware wrapper 3. **Usage Extraction**: Token counts, model info, and timing data are captured from responses 4. **Async Tracking**: Usage data is sent to Revenium in the background (fire-and-forget) 5. **Transparent Response**: Original Perplexity responses are returned unchanged The middleware never blocks your application - if Revenium tracking fails, your Perplexity requests continue normally. ## Requirements - Node.js 16+ - TypeScript 5.0+ (for TypeScript projects) - Revenium API key - Perplexity API key ## Documentation For detailed documentation, visit [docs.revenium.io](https://docs.revenium.io) ## Contributing See [CONTRIBUTING.md](https://github.com/revenium/revenium-middleware-perplexity-node/blob/HEAD/CONTRIBUTING.md) ## Code of Conduct See [CODE_OF_CONDUCT.md](https://github.com/revenium/revenium-middleware-perplexity-node/blob/HEAD/CODE_OF_CONDUCT.md) ## Security See [SECURITY.md](https://github.com/revenium/revenium-middleware-perplexity-node/blob/HEAD/SECURITY.md) ## License This project is licensed under the MIT License - see the [LICENSE](https://github.com/revenium/revenium-middleware-perplexity-node/blob/HEAD/LICENSE) file for details. ## Support For issues, feature requests, or contributions: - **GitHub Repository**: [revenium/revenium-middleware-perplexity-node](https://github.com/revenium/revenium-middleware-perplexity-node) - **Issues**: [Report bugs or request features](https://github.com/revenium/revenium-middleware-perplexity-node/issues) - **Documentation**: [docs.revenium.io](https://docs.revenium.io) - **Contact**: Reach out to the Revenium team for additional support ## Development For development and testing instructions, see [DEVELOPMENT.md](https://github.com/revenium/revenium-middleware-perplexity-node/blob/HEAD/DEVELOPMENT.md). --- **Built by Revenium**