Current Server Action

Open the file at lib/actions/resources.ts. This file has one function, createResource, which, as the name implies, allows you to create a resource.
lib/actions/resources.ts
"use server";

import {
  NewResourceParams,
  insertResourceSchema,
  resources,
} from "@/lib/db/schema/resources";
import { db } from "../db";

export const createResource = async (input: NewResourceParams) => {
  try {
    const { content } = insertResourceSchema.parse(input);

    const [resource] = await db
      .insert(resources)
      .values({ content })
      .returning();

    return "Resource successfully created.";
  } catch (e) {
    if (e instanceof Error)
      return e.message.length > 0 ? e.message : "Error, please try again.";
  }
};
This function is a Server Action, as denoted by the "use server"; directive at the top of the file. This means that it can be called anywhere in your Next.js application. This function will take an input, run it through a Zod schema to ensure it adheres to the correct schema, and then creates a new resource in the database. This is the ideal location to generate and store embeddings of the newly created resources.

Updated Server Action

Update the file with the following code:
lib/actions/resources.ts
"use server";

import {
  NewResourceParams,
  insertResourceSchema,
  resources,
} from "@/lib/db/schema/resources";
import { db } from "../db";
import { generateEmbeddings } from "../ai/embedding";
import { embeddings as embeddingsTable } from "../db/schema/embeddings";

export const createResource = async (input: NewResourceParams) => {
  try {
    const { content } = insertResourceSchema.parse(input);

    const [resource] = await db
      .insert(resources)
      .values({ content })
      .returning();

    const embeddings = await generateEmbeddings(content);
    await db.insert(embeddingsTable).values(
      embeddings.map((embedding) => ({
        resourceId: resource.id,
        ...embedding,
      }))
    );

    return "Resource successfully created and embedded.";
  } catch (error) {
    return error instanceof Error && error.message.length > 0
      ? error.message
      : "Error, please try again.";
  }
};

Understanding the Changes

First, you call the generateEmbeddings function created in the previous step, passing in the source material (content). Once you have your embeddings of the source material, you can save them to the database, passing the resourceId alongside each embedding.

Key Changes Made

Import Statements

  • Added import for generateEmbeddings function - Added import for embeddings table schema

Embedding Generation

  • Call generateEmbeddings with content - Process the returned embeddings array

Database Storage

  • Insert embeddings into embeddings table - Map each embedding with resourceId

Success Message

  • Updated return message to indicate embedding creation - Enhanced error handling

Test the Implementation

Let’s create a simple test to verify that your embedding generation is working correctly.

Create a Test Function

Add the following test function to your lib/ai/embedding.ts file:
// Test function - you can remove this after testing
export const testEmbeddingGeneration = async () => {
  const testContent =
    "This is a test document. It contains multiple sentences. Each sentence will become a chunk. The chunks will be converted to embeddings.";

  try {
    console.log("Testing embedding generation...");
    const result = await generateEmbeddings(testContent);

    console.log("✅ Embedding generation successful!");
    console.log(`📊 Generated ${result.length} embeddings`);
    console.log(`📝 First chunk: "${result[0]?.content}"`);
    console.log(
      `🔢 First embedding dimensions: ${result[0]?.embedding.length}`
    );

    return result;
  } catch (error) {
    console.error("❌ Embedding generation failed:", error);
    throw error;
  }
};

Run the Test

To test the embedding generation function, we’ll create a dedicated test file and run it using a script.
1

Create the Test File

Create a new file at /tests/test-embeddings.js:
import "dotenv/config";
import { testEmbeddingGeneration } from "../lib/ai/embedding";

testEmbeddingGeneration()
  .then((result) => console.log("Test completed successfully"))
  .catch((error) => console.error("Test failed:", error));
2

Add Test Script to package.json

Add this line to the scripts section of your package.json:
{
  "scripts": {
    "test:embeddings": "npx tsx tests/test-embeddings.js"
  }
}
3

Update Dependencies

Make sure you have the required dependencies. You may need to update or add:
{
  "dependencies": {
    "zod": "^4.1.3"
  }
}
4

Run the Test

Execute the following command in your terminal:
pnpm run test:embeddings
5

Check for Errors

If the test fails, check the error messages in the terminal output. Common issues include:
  • Missing environment variables
  • Incorrect API keys
  • Network connectivity problems
  • Missing dependencies

Expected Output

If everything is working correctly, you should see output similar to:
Testing embedding generation...
✅ Embedding generation successful!
📊 Generated 4 embeddings
📝 First chunk: "This is a test document"
🔢 First embedding dimensions: 1536
Test completed successfully

What to Check

Function Execution

  • No errors during execution - Console logs appear as expected - Function returns an array of embeddings

Output Format

  • Each embedding has content and embedding properties - Embedding arrays have 1536 dimensions - Content matches the input chunks
Remember: This test function is for development purposes only. Remove it from your production code after testing.