Home >Backend Development >Python Tutorial >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.
<code class="language-bash">nest new todo-app cd todo-app</code>
<code class="language-bash">rm src/app.controller.* src/app.service.* src/app.module.ts</code>
Install required dependencies:
<code class="language-bash">npm install prisma @prisma/client @google/generative-ai dotenv</code>
<code class="language-bash">npx prisma init</code>
<code>DATABASE_URL="postgresql://<用户名>:<密码>@localhost:5432/<数据库>?schema=public"</code>
<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>
<code class="language-bash">npx prisma migrate dev --name init</code>
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>
<code class="language-bash">nest generate module tasks nest generate service tasks nest generate controller tasks</code>
<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>
<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>
<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>
With this setup, you will have a fully functional to-do list app that:
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!