Skip to main content
Uxie integrates with several third-party services to provide its core functionality. This guide covers setup and configuration for each service.

UploadThing (File Storage)

UploadThing handles PDF file uploads and storage for Uxie.

Setup

  1. Go to UploadThing Dashboard
  2. Sign in and create a new app
  3. Copy your API token from the dashboard
  4. Add to .env:
UPLOADTHING_TOKEN=your-uploadthing-token

Configuration

Uxie’s UploadThing configuration in src/server/uploadthing.ts:
Max File Size
8MB
Maximum PDF file size per upload
Max File Count
1
Number of files per upload request
Accepted File Types
pdf
Only PDF files are accepted

Plan Limits

Upload limits are enforced based on user’s subscription plan:
const userPlan = session?.user.plan ?? FREE_PLAN;
const allowedDocsCount = PLANS[userPlan].maxDocs;

if (userFilesCount >= allowedDocsCount) {
  throw new Error(
    "You have reached the maximum number of documents allowed for your plan"
  );
}

Upload Flow

  1. Middleware: Checks authentication and plan limits
  2. Upload: File is uploaded to UploadThing servers
  3. Processing: PDF is loaded and page count extracted
  4. Cover Generation: First page is converted to cover image
  5. Database: Document record is created in Prisma
UploadThing automatically handles CDN distribution and provides optimized file delivery.

Pinecone (Vector Database)

Pinecone stores document embeddings for semantic search and chat functionality.

Setup

  1. Go to Pinecone Console
  2. Sign up and create a new index
  3. Index configuration:
    • Name: uxie
    • Dimensions: 768 (for BAAI/bge-base-en-v1.5 embeddings)
    • Metric: cosine
    • Environment: Choose your region (e.g., us-east-1-aws)
  4. Copy your API key
  5. Add to .env:
PINECONE_API_KEY=your-pinecone-api-key
PINECONE_ENVIRONMENT=us-east-1-aws

Integration

Uxie uses Pinecone through the LangChain integration:
import { Pinecone } from "@pinecone-database/pinecone";
import { PineconeStore } from "langchain/vectorstores/pinecone";

const getPineconeClient = () => {
  return new Pinecone({
    apiKey: env.PINECONE_API_KEY,
  });
};

const pineconeIndex = getPineconeClient().Index("uxie");

Document Vectorization

When a document is uploaded:
  1. PDF is split into chunks using RecursiveCharacterTextSplitter
  2. Text chunks are embedded using Hugging Face embeddings
  3. Vectors are stored in Pinecone with document metadata
  4. Document is marked as isVectorised: true in database
Make sure your Pinecone index dimensions (768) match your embedding model’s output dimensions.

Metadata Structure

{
  documentId: string,
  pageNumber: number,
  text: string,
  // Additional custom metadata
}

Hugging Face (Embeddings)

Hugging Face provides text embeddings for document vectorization.

Setup

  1. Go to Hugging Face
  2. Sign up and go to Settings > Tokens
  3. Create a new token with read access
  4. Add to .env:
HUGGINGFACE_API_KEY=your-huggingface-api-key

Embedding Model

Uxie uses the BAAI/bge-base-en-v1.5 model:
  • Dimensions: 768
  • Max sequence length: 512 tokens
  • Performance: High-quality embeddings for semantic search
  • Use case: Document vectorization and similarity search

Implementation

import { InferenceClient } from "@huggingface/inference";

const createHuggingFaceEmbeddings = () => {
  const hf = new InferenceClient(env.HUGGINGFACE_API_KEY);
  
  return new (class extends Embeddings {
    async embedDocuments(texts: string[]): Promise<number[][]> {
      const embeddings = await Promise.all(
        texts.map(async (text) => {
          const result = await hf.featureExtraction({
            model: "BAAI/bge-base-en-v1.5",
            inputs: text,
          });
          return parseEmbeddingResult(result);
        })
      );
      return embeddings;
    }
  })();
};
Hugging Face Inference API has rate limits on the free tier. For production use, consider upgrading or hosting your own embedding model.

Google Gemini (AI Models)

Google’s Gemini models power chat, summarization, and flashcard generation.

Setup

  1. Go to Google AI Studio
  2. Create a new API key
  3. Add to .env:
GOOGLE_GENERATIVE_AI_API_KEY=your-gemini-api-key

Models Used

Used for:
  • Document chat (/api/chat/route.ts)
  • Document summarization (/lib/summarize.ts)
  • Flashcard generation (/lib/flashcard.ts)
  • Text completion (/api/completion/route.ts)
Characteristics:
  • Fast inference
  • Cost-effective
  • Good for real-time interactions
import { google } from "@ai-sdk/google";

model: google("gemini-2.5-flash")
Used for:
  • Flashcard answer evaluation (/api/evaluate/route.ts)
Characteristics:
  • Higher reasoning capability
  • Better for complex analysis
  • More accurate evaluation
model: google("gemini-1.5-pro")

Usage Example

import { streamText } from "ai";
import { google } from "@ai-sdk/google";

const result = await streamText({
  model: google("gemini-2.5-flash"),
  messages: [
    {
      role: "system",
      content: "You are a helpful document assistant."
    },
    {
      role: "user",
      content: "Summarize this document..."
    }
  ],
});
Gemini API has usage quotas. Monitor your usage in Google AI Studio and upgrade if needed.

Liveblocks (Real-time Collaboration)

Liveblocks enables real-time collaboration features for document annotations and sharing.

Setup

  1. Go to Liveblocks Dashboard
  2. Create a new project
  3. Copy your public API key (not secret key)
  4. Add to .env:
NEXT_PUBLIC_LIVEBLOCKS_PUBLIC_API_KEY=your-liveblocks-public-key
Use the public key (prefixed with NEXT_PUBLIC_) since it will be exposed to the client. Never use the secret key in client-side code.

Configuration

Liveblocks is configured in liveblocks.config.ts:
import { createClient } from "@liveblocks/client";
import { createRoomContext } from "@liveblocks/react";

const client = createClient({
  publicApiKey: env.NEXT_PUBLIC_LIVEBLOCKS_PUBLIC_API_KEY,
});

export const {
  RoomProvider,
  useMyPresence,
  useOthers,
  // ... other hooks
} = createRoomContext(client);

Features Enabled

  • Presence: See who else is viewing the document
  • Live cursors: Track user positions in real-time
  • Collaboration: Multiple users editing annotations
  • Comments: Real-time commenting on documents

Usage

import { RoomProvider } from "@/liveblocks.config";

function DocumentViewer({ documentId }) {
  return (
    <RoomProvider id={documentId}>
      {/* Your collaborative features */}
    </RoomProvider>
  );
}
Liveblocks automatically handles connection management, reconnection, and conflict resolution.

Service Comparison

ServicePurposePricing TierRate Limits
UploadThingFile storageFree: 2GB storage100 uploads/month (free)
PineconeVector databaseFree: 1 index100K vectors (free)
Hugging FaceEmbeddingsFree APIRate limited
Google GeminiAI modelsPay per tokenGenerous free quota
LiveblocksReal-time syncFree: 100 MAUUnlimited rooms (free)
MAU = Monthly Active Users. Liveblocks counts users who connect to a room in a given month.

Cost Optimization Tips

UploadThing

  • Compress PDFs before upload when possible
  • Delete unused documents to free up storage
  • Consider upgrading for production use

Pinecone

  • Use namespace filtering to reduce vector count
  • Delete old document vectors when documents are removed
  • Monitor index size in Pinecone dashboard

Hugging Face

  • Cache embeddings for frequently accessed documents
  • Batch embedding requests when possible
  • Consider self-hosting for high-volume use

Google Gemini

  • Use Gemini 2.5 Flash for most operations (cheaper)
  • Reserve Gemini 1.5 Pro for complex tasks
  • Implement token limits on user inputs
  • Cache common responses when appropriate

Liveblocks

  • Clean up inactive rooms periodically
  • Use presence awareness to optimize updates
  • Monitor MAU usage in dashboard

Environment Variables Summary

.env
# UploadThing
UPLOADTHING_TOKEN=your-uploadthing-token

# Pinecone
PINECONE_API_KEY=your-pinecone-api-key
PINECONE_ENVIRONMENT=us-east-1-aws

# Hugging Face
HUGGINGFACE_API_KEY=your-huggingface-api-key

# Google Gemini
GOOGLE_GENERATIVE_AI_API_KEY=your-gemini-api-key

# Liveblocks
NEXT_PUBLIC_LIVEBLOCKS_PUBLIC_API_KEY=your-liveblocks-public-key

Testing Your Configuration

Verify each service is configured correctly:

UploadThing

# Try uploading a test PDF through the UI
# Check UploadThing dashboard for successful uploads

Pinecone

import { getPineconeClient } from "@/lib/pinecone";

const client = getPineconeClient();
const indexes = await client.listIndexes();
console.log(indexes); // Should include "uxie"

Hugging Face

import { InferenceClient } from "@huggingface/inference";

const hf = new InferenceClient(process.env.HUGGINGFACE_API_KEY);
const result = await hf.featureExtraction({
  model: "sentence-transformers/all-MiniLM-L6-v2",
  inputs: "test",
});
console.log(result); // Should return array of numbers

Google Gemini

import { google } from "@ai-sdk/google";
import { generateText } from "ai";

const result = await generateText({
  model: google("gemini-2.5-flash"),
  prompt: "Say hello",
});
console.log(result.text); // Should return a greeting

Liveblocks

// Check browser console for successful connection
// Should see: "Liveblocks: Connected to room"

Build docs developers (and LLMs) love