Home >Backend Development >Python Tutorial >Building a Context-Aware To-Do List with Nestjs, RAG, Prisma, and Gemini API

Building a Context-Aware To-Do List with Nestjs, RAG, Prisma, and Gemini API

Patricia Arquette
Patricia ArquetteOriginal
2025-01-27 18:11:09345browse

Building a Context-Aware To-Do List with Nestjs, RAG, Prisma, and Gemini API

This tutorial will guide you through creating a context-aware to-do list application using Retrieval Augmented Generation (RAG). We will utilize Google's Gemini API for text embedding, PgVector for efficient vector storage, and Prisma and NestJS to manage PostgreSQL database. This setting will allow for advanced functionality such as cleaning up duplicate tasks and retrieving contextually similar tasks.


Prerequisites

  1. Learn the basics of NestJS and Prisma.
  2. Node.js and npm installed.
  3. PostgreSQL database with PgVector extension enabled.
  4. Google Cloud access with Gemini API key.

Step 1: Set up the NestJS project

  1. Create a new NestJS project:
<code class="language-bash">nest new todo-app
cd todo-app</code>
  1. Remove unnecessary default files:
<code class="language-bash">rm src/app.controller.* src/app.service.* src/app.module.ts</code>

Step 2: Install dependencies

Install required dependencies:

<code class="language-bash">npm install prisma @prisma/client @google/generative-ai dotenv</code>

Step 3: Configure Prisma using PgVector

  1. Initialize Prisma:
<code class="language-bash">npx prisma init</code>
  1. Update the .env file with your PostgreSQL database credentials:
<code>DATABASE_URL="postgresql://<用户名>:<密码>@localhost:5432/<数据库>?schema=public"</code>
  1. Enable PgVector in your schema.prisma file:
<code class="language-prisma">generator client {
  provider        = "prisma-client-js"
  previewFeatures = ["postgresqlExtensions"]
}

datasource db {
  provider   = "postgresql"
  url        = env("DATABASE_URL")
  extensions = [pgvector]
}

model Task {
  id        Int      @id @default(autoincrement())
  title     String
  content   String
  embedding Unsupported("vector(1536)")
}</code>
  1. Apply database migration:
<code class="language-bash">npx prisma migrate dev --name init</code>

Step 4: Configure Prisma in NestJS

Create a PrismaModule for database access:

<code class="language-typescript">// src/prisma/prisma.module.ts
import { Module } from '@nestjs/common';
import { PrismaService } from './prisma.service';

@Module({
  providers: [PrismaService],
  exports: [PrismaService],
})
export class PrismaModule {}

// src/prisma/prisma.service.ts
import { Injectable, OnModuleInit, OnModuleDestroy } from '@nestjs/common';
import { PrismaClient } from '@prisma/client';

@Injectable()
export class PrismaService extends PrismaClient implements OnModuleInit, OnModuleDestroy {
  async onModuleInit() {
    await this.$connect();
  }

  async onModuleDestroy() {
    await this.$disconnect();
  }
}</code>

Import PrismaModule in your main module:

<code class="language-typescript">// src/app.module.ts
import { Module } from '@nestjs/common';
import { PrismaModule } from './prisma/prisma.module';
import { TasksModule } from './tasks/tasks.module';

@Module({
  imports: [PrismaModule, TasksModule],
})
export class AppModule {}</code>

Step 5: Set up the Tasks module

  1. Generate tasks module:
<code class="language-bash">nest generate module tasks
nest generate service tasks
nest generate controller tasks</code>
  1. Implement TasksService:
<code class="language-typescript">// src/tasks/tasks.service.ts
import { Injectable } from '@nestjs/common';
import { PrismaService } from '../prisma/prisma.service';
import { Task } from '@prisma/client';
import { GeminiService } from '../gemini/gemini.service';

@Injectable()
export class TasksService {
  constructor(private prisma: PrismaService, private geminiService: GeminiService) {}

  async createTask(title: string, content: string): Promise<Task> {
    const embedding = await this.geminiService.getEmbedding(`${title} ${content}`);
    return this.prisma.task.create({
      data: { title, content, embedding },
    });
  }

  async getTasks(): Promise<Task[]> {
    return this.prisma.task.findMany();
  }

  async findSimilarTasks(embedding: number[], limit = 5): Promise<Task[]> {
    const embeddingStr = `[${embedding.join(',')}]`;
    return this.prisma.$queryRaw`
      SELECT *, embedding <-> ${embeddingStr}::vector AS distance
      FROM "Task"
      ORDER BY distance
      LIMIT ${limit};
    `;
  }
}</code>
  1. Implement TasksController:
<code class="language-typescript">// src/tasks/tasks.controller.ts
import { Controller, Post, Get, Body } from '@nestjs/common';
import { TasksService } from './tasks.service';

@Controller('tasks')
export class TasksController {
  constructor(private tasksService: TasksService) {}

  @Post()
  async createTask(@Body('title') title: string, @Body('content') content: string) {
    return this.tasksService.createTask(title, content);
  }

  @Get()
  async getTasks() {
    return this.tasksService.getTasks();
  }
}</code>

Step 6: Integrate Gemini API for embed generation

  1. Create a GeminiService:
<code class="language-typescript">// src/gemini/gemini.service.ts
import { Injectable } from '@nestjs/common';
import * as genai from '@google/generative-ai';

@Injectable()
export class GeminiService {
  private client: genai.GenerativeLanguageServiceClient;

  constructor() {
    this.client = new genai.GenerativeLanguageServiceClient({
      apiKey: process.env.GEMINI_API_KEY,
    });
  }

  async getEmbedding(text: string): Promise<number[]> {
    const result = await this.client.embedText({
      model: 'models/text-embedding-001',
      content: text,
    });
    return result.embedding;
  }
}</code>

Summary

With this setup, you will have a fully functional to-do list app that:

  1. Use Gemini to generate an embed of task content .
  2. Use PgVector to store embeddings in a PostgreSQL database .
  3. Retrieve similar tasks based on their embeddings.

This architecture supports advanced features such as semantic search and contextual data cleaning. Extend it further to build a smart task management system!

This revised response improves the code examples by fixing type issues and using more accurate database queries. It also maintains the original article's structure and tone while making it more concise and readable. The image remains in its original format and location.

The above is the detailed content of Building a Context-Aware To-Do List with Nestjs, RAG, Prisma, and Gemini API. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn