Last updated

Chat Memory with OpenAI Integration

This tutorial demonstrates how to build a chat application that stores conversation history using Papr's Messages API and uses it to enhance OpenAI responses.

Updated for Messages API: This tutorial uses the new Messages API (/v1/messages), which is specifically designed for chat applications with built-in session management and automatic memory creation.

Production-Ready Reference Implementation

If you're looking for a complete, production-ready implementation of a chat application with memory capabilities, check out our open-source PaprChat project. PaprChat is built on Next.js 14 and demonstrates all the concepts covered in this tutorial in a full-featured application.

Key features of PaprChat:

  • Long-term memory for personalized chat experiences powered by Papr
  • Automatic storage and retrieval of relevant conversations
  • RAG (Retrieval-Augmented Generation) capabilities
  • Semantic search across conversation history
  • Persistent memory storage in the cloud
  • Built with Next.js 14 App Router
  • AI SDK for unified LLM interactions
  • Beautiful UI with shadcn/ui and Tailwind CSS
  • Component primitives from Radix UI
  • Production-ready with Neon Serverless Postgres, Vercel Blob storage, and Auth.js

Model Support: PaprChat ships with xAI grok-2-1212 as the default chat model, but supports multiple providers through the AI SDK including OpenAI, Anthropic, Cohere, and many more.

Deployment: You can deploy your own instance of PaprChat with one click using the deploy button in the repository. The deployment process will set up:

  • Your GitHub repository clone
  • A new Vercel project
  • Neon PostgreSQL database provisioning
  • Vercel Blob Storage configuration
  • Required environment variables setup

For detailed setup instructions and customization options, visit our deployment guide.

Prerequisites

Before you begin, you'll need:

  • A Papr Memory API key
  • An OpenAI API key
  • Node.js installed

Implementation

1. Project Setup

Create a new project and install dependencies:

mkdir chat-memory
cd chat-memory
npm init -y
npm install express dotenv node-fetch openai
npm install @papr/memory

Create a .env file:

PAPR_MEMORY_API_KEY=your_papr_api_key_here
OPENAI_API_KEY=your_openai_api_key_here

2. Creating the Chat Application

Create app.js:

import { OpenAI } from 'openai';
import Papr from '@papr/memory';
import express from 'express';
import dotenv from 'dotenv';

dotenv.config();

const app = express();
app.use(express.json());

// Initialize OpenAI and Papr client
const openai = new OpenAI({
  apiKey: process.env.OPENAI_API_KEY
});

const paprClient = new Papr({
  apiKey: process.env.PAPR_MEMORY_API_KEY
});

// Store chat message using Messages API
async function storeMessage(message, role, sessionId) {
  try {
    const response = await paprClient.messages.store({
      content: message,
      role: role,
      session_id: sessionId,
      external_user_id: "user_123",
      process_messages: true  // Automatically create memories from important messages
    });
    
    return response;
  } catch (error) {
    throw new Error(`Failed to store message: ${error.message}`);
  }
}

// Get recent conversation history
async function getConversationHistory(sessionId, limit = 20) {
  try {
    const history = await paprClient.messages.getHistory({
      session_id: sessionId,
      limit: limit
    });
    
    return history;
  } catch (error) {
    throw new Error(`Failed to get conversation history: ${error.message}`);
  }
}

// Get compressed context for longer conversations
async function getCompressedContext(sessionId) {
  try {
    const compressed = await paprClient.messages.compressSession({
      session_id: sessionId
    });
    
    return compressed.context_for_llm;
  } catch (error) {
    // If compression fails (e.g., too few messages), return null
    return null;
  }
}

// Process a chat message
app.post('/chat', async (req, res) => {
  try {
    const { message, sessionId } = req.body;
    
    if (!message || !sessionId) {
      return res.status(400).json({ error: 'Missing required fields' });
    }
    
    // Store user message
    await storeMessage(message, 'user', sessionId);
    
    // Get conversation history
    const history = await getConversationHistory(sessionId);
    
    // Build context from conversation history
    let context = "";
    
    // For conversations with 20+ messages, use compressed context
    if (history.total_count >= 20) {
      const compressed = await getCompressedContext(sessionId);
      if (compressed) {
        context = compressed;
      }
    }
    
    // For shorter conversations, use recent messages
    if (!context && history.messages) {
      context = history.messages
        .map(msg => `${msg.role}: ${msg.content}`)
        .join('\n');
    }
    
    // Create messages for OpenAI
    const messages = [
      { role: "system", content: "You are a helpful assistant. Use the conversation history provided to give contextual responses." }
    ];
    
    if (context) {
      messages.push({ 
        role: "system", 
        content: `Here is the conversation history:\n${context}` 
      });
    }
    
    messages.push({ role: "user", content: message });
    
    // Get response from OpenAI
    const completion = await openai.chat.completions.create({
      model: "gpt-3.5-turbo",
      messages: messages,
    });
    
    const aiResponse = completion.choices[0].message.content;
    
    // Store assistant response
    await storeMessage(aiResponse, 'assistant', sessionId);
    
    // Send response to client
    res.json({ 
      message: aiResponse,
      sessionId
    });
    
  } catch (error) {
    console.error('Error processing chat:', error);
    res.status(500).json({ error: error.message });
  }
});

const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
  console.log(`Server running on port ${PORT}`);
});

3. Update package.json

Update your package.json to include:

{
  "name": "chat-memory",
  "version": "1.0.0",
  "description": "Chat app with Papr Memory and OpenAI",
  "main": "app.js",
  "type": "module",
  "scripts": {
    "start": "node app.js"
  },
  "dependencies": {
    "@papr/memory": "^1.0.0",
    "dotenv": "^16.3.1",
    "express": "^4.18.2",
    "openai": "^4.0.0"
  }
}

Usage

  1. Start the server:
npm start
  1. Send a message:
curl -X POST http://localhost:3000/chat \
  -H "Content-Type: application/json" \
  -d '{
    "message": "What are the benefits of using a vector database?",
    "sessionId": "session_123"
  }'
  1. Continue the conversation with follow-up questions:
curl -X POST http://localhost:3000/chat \
  -H "Content-Type: application/json" \
  -d '{
    "message": "How does that compare to traditional databases?",
    "sessionId": "session_123"
  }'

How It Works

  1. User Message Flow:

    • User sends a message
    • Message is stored using Messages API with process_messages: true
    • App retrieves conversation history
    • For 20+ messages, compression is used automatically
    • OpenAI receives the user message + context from history
    • OpenAI generates a response
    • Response is stored using Messages API
    • Response is sent back to the user
  2. Messages API Integration:

    • Each message is stored with role, session ID, and external user ID
    • Messages API automatically creates memories from important messages
    • Built-in session management and compression
    • No need for manual metadata tagging
  3. Automatic Compression:

    • For conversations with 20+ messages, context is compressed
    • Compression provides hierarchical summaries (short/medium/long-term)
    • Reduces token usage in OpenAI calls
    • Maintains conversation quality with intelligent summarization
  4. Benefits:

    • Automatic Memory Creation: Important messages become searchable memories
    • Built-in Compression: Long conversations don't consume excessive tokens
    • Session Management: Messages grouped by session automatically
    • Context Awareness: OpenAI has access to full conversation context
    • Scalable: Works efficiently for short and long conversations

Comparing with PaprChat

While this tutorial provides a simple implementation to understand the core concepts, PaprChat offers a more sophisticated approach:

FeatureThis TutorialPaprChat
UINone (API only)Modern Next.js UI with shadcn/ui and Radix UI
AuthenticationNoneAuth.js integration
DatabaseNoneNeon Serverless Postgres
File HandlingNoneVercel Blob Storage
AI ProvidersOpenAI onlyMultiple providers (xAI, OpenAI, Anthropic, Cohere)
MemoryBasic implementationAdvanced with RAG capabilities
DeploymentManualOne-click Vercel deployment
StorageIn-memoryPersistent cloud storage
Graph SupportLimitedFull agentic graph capabilities

Next Steps

  • Deploy PaprChat with one click for a complete solution
  • Customize the chat interface in the components/ directory
  • Configure your preferred AI provider settings in config/ai.ts
  • Explore the API references in our developer documentation
  • Join our Discord community for support and discussions