Skip to content

Latest commit

 

History

History
307 lines (253 loc) · 8.27 KB

cloudflare-d1-setup.md

File metadata and controls

307 lines (253 loc) · 8.27 KB

Setting Up Mem0 with Cloudflare D1

This guide outlines the steps to deploy Mem0 with Cloudflare D1 for persistent storage, making your memories accessible from any device.

Architecture Overview

graph TD
    A[Client Devices] --> B[Cloudflare DNS]
    B --> C[Cloudflare Pages]
    C --> D[Cloudflare Workers]
    D --> E[Cloudflare D1]
    
    subgraph "Memory Storage"
        E --> F[SQLite Database]
        F --> G[Automatic Backups]
    end
Loading

Prerequisites

  1. Cloudflare account
  2. Domain name configured with Cloudflare DNS
  3. Node.js installed locally
  4. Wrangler CLI (npm install -g wrangler)
  5. OpenAI API key

Implementation Steps

1. Initial Setup

  1. Login to Wrangler:
wrangler login
  1. Create a new D1 database:
wrangler d1 create mem0-db
  1. Create the database schema:
CREATE TABLE memories (
    id TEXT PRIMARY KEY,
    user_id TEXT NOT NULL,
    content TEXT NOT NULL,
    embedding JSON,
    metadata JSON,
    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
);

CREATE INDEX idx_user_id ON memories(user_id);
CREATE INDEX idx_created_at ON memories(created_at);

2. Configure Wrangler

Create or update wrangler.toml:

name = "mem0-api"
main = "src/worker.js"
compatibility_date = "2024-03-09"

[vars]
OPENAI_API_KEY = "your-openai-api-key"

[[d1_databases]]
binding = "DB"
database_name = "mem0-db"
database_id = "your-database-id"

3. API Implementation

Create src/worker.js:

export default {
  async fetch(request, env, ctx) {
    const url = new URL(request.url);
    
    // CORS headers for cross-origin access
    const corsHeaders = {
      'Access-Control-Allow-Origin': '*',
      'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
      'Access-Control-Allow-Headers': 'Content-Type',
    };

    // Handle CORS preflight
    if (request.method === 'OPTIONS') {
      return new Response(null, { headers: corsHeaders });
    }

    if (url.pathname === '/memories' && request.method === 'POST') {
      const { text, user_id } = await request.json();
      
      // Store memory
      await env.DB.prepare(
        'INSERT INTO memories (id, user_id, content) VALUES (?, ?, ?)'
      ).bind(crypto.randomUUID(), user_id, text)
        .run();
      
      return new Response(JSON.stringify({ success: true }), {
        headers: { 'Content-Type': 'application/json', ...corsHeaders },
      });
    }

    if (url.pathname === '/memories/search' && request.method === 'POST') {
      const { query, user_id } = await request.json();
      
      // Search memories
      const memories = await env.DB.prepare(
        'SELECT content FROM memories WHERE user_id = ? AND content LIKE ?'
      ).bind(user_id, `%${query}%`)
        .all();
      
      return new Response(JSON.stringify(memories.results), {
        headers: { 'Content-Type': 'application/json', ...corsHeaders },
      });
    }

    return new Response('Not Found', { status: 404 });
  },
};

4. Frontend Implementation

Create index.html:

<!DOCTYPE html>
<html>
<head>
    <title>Mem0</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link href="https://cdn.jsdelivr.net/npm/tailwindcss@2/dist/tailwind.min.css" rel="stylesheet">
</head>
<body class="bg-gray-100 p-4">
    <div class="max-w-lg mx-auto space-y-4">
        <div class="bg-white p-4 rounded shadow">
            <input type="text" id="memory" placeholder="Enter memory" 
                   class="w-full p-2 border rounded mb-2">
            <button onclick="addMemory()" 
                    class="w-full bg-blue-500 text-white p-2 rounded">
                Add Memory
            </button>
        </div>
        
        <div class="bg-white p-4 rounded shadow">
            <input type="text" id="search" placeholder="Search memories" 
                   class="w-full p-2 border rounded mb-2">
            <button onclick="searchMemories()" 
                    class="w-full bg-green-500 text-white p-2 rounded">
                Search
            </button>
        </div>

        <div id="results" class="bg-white p-4 rounded shadow"></div>
    </div>

    <script>
        const API_URL = 'https://api.yourdomain.com';
        const USER_ID = localStorage.getItem('user_id') || 
                       crypto.randomUUID();
        
        // Store user_id for consistent access
        localStorage.setItem('user_id', USER_ID);

        async function addMemory() {
            const memory = document.getElementById('memory').value;
            try {
                const response = await fetch(`${API_URL}/memories`, {
                    method: 'POST',
                    headers: {'Content-Type': 'application/json'},
                    body: JSON.stringify({
                        text: memory,
                        user_id: USER_ID
                    })
                });
                const result = await response.json();
                if (result.success) {
                    alert('Memory added successfully!');
                    document.getElementById('memory').value = '';
                }
            } catch (error) {
                console.error('Error:', error);
                alert('Failed to add memory');
            }
        }

        async function searchMemories() {
            const query = document.getElementById('search').value;
            try {
                const response = await fetch(`${API_URL}/memories/search`, {
                    method: 'POST',
                    headers: {'Content-Type': 'application/json'},
                    body: JSON.stringify({
                        query: query,
                        user_id: USER_ID
                    })
                });
                const results = await response.json();
                document.getElementById('results').innerHTML = results
                    .map(r => `<div class="border-b p-2">${r.content}</div>`)
                    .join('');
            } catch (error) {
                console.error('Error:', error);
                alert('Failed to search memories');
            }
        }
    </script>
</body>
</html>

5. Deployment Steps

  1. Deploy the Worker:
wrangler deploy
  1. Deploy the frontend to Cloudflare Pages:

    • Connect your GitHub repository
    • Configure build settings (none needed for static site)
    • Set environment variables:
  2. Configure DNS:

    • Add A record for api.yourdomain.com pointing to your Worker
    • Add CNAME record for www pointing to your Pages deployment

6. Testing

  1. Visit your deployed frontend (https://yourdomain.com)
  2. Add a test memory
  3. Search for the memory
  4. Try accessing from different devices

7. Maintenance

  1. Monitor usage in Cloudflare dashboard
  2. Check D1 storage limits
  3. Review Workers usage metrics
  4. Backup database regularly (automatic with D1)

Security Considerations

  1. Add authentication if needed:
// Add to worker.js
async function authenticate(request) {
    const authHeader = request.headers.get('Authorization');
    if (!authHeader) {
        throw new Error('No authorization header');
    }
    // Implement your authentication logic
}
  1. Rate limiting:
// Add to worker.js
const RATE_LIMIT = 100; // requests per minute
const rateLimiter = new Map();

function checkRateLimit(ip) {
    const now = Date.now();
    const userRequests = rateLimiter.get(ip) || [];
    const recentRequests = userRequests.filter(time => now - time < 60000);
    
    if (recentRequests.length >= RATE_LIMIT) {
        throw new Error('Rate limit exceeded');
    }
    
    recentRequests.push(now);
    rateLimiter.set(ip, recentRequests);
}
  1. Enable security headers:
// Add to response headers
'Strict-Transport-Security': 'max-age=31536000; includeSubDomains',
'X-Content-Type-Options': 'nosniff',
'X-Frame-Options': 'DENY',
'X-XSS-Protection': '1; mode=block'

Next Steps

  1. Implement additional features:

    • Full-text search
    • Memory categorization
    • Media attachments
    • Sharing capabilities
  2. Add monitoring:

    • Set up Cloudflare Analytics
    • Configure error tracking
    • Monitor API usage
  3. Enhance security:

    • Add user authentication
    • Implement API key rotation
    • Set up backup strategy