Skip to content

Commit 057983a

Browse files
committed
feat: pinecone chat
1 parent c681998 commit 057983a

File tree

11 files changed

+272
-5
lines changed

11 files changed

+272
-5
lines changed

apps/nest-api/package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,9 @@
5050
"@langchain/core": "^0.3.42",
5151
"@langchain/ollama": "^0.2.0",
5252
"@langchain/openai": "^0.4.4",
53+
"@langchain/pinecone": "^0.2.0",
5354
"@nestjs/config": "^4.0.1",
54-
"@nestjs/swagger": "^11.0.6"
55+
"@nestjs/swagger": "^11.0.6",
56+
"@pinecone-database/pinecone": "^5.1.1"
5557
}
5658
}

apps/nest-api/src/app/app.module.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,13 @@
11
import { Module } from '@nestjs/common';
22
import { AppController } from './app.controller';
33
import { AppService } from './app.service';
4-
import { ChatCoreModule } from './chat-core/chat-core.module';
54
import { ConfigModule } from '@nestjs/config';
6-
import { ChatGeneralModule } from './chat-general/chat-general.module';
5+
import { PineconeDbModule } from './pinecone-db/pinecone-db.module';
76

87
@Module({
98
imports: [
109
ConfigModule.forRoot({ isGlobal: true }),
11-
ChatCoreModule,
12-
ChatGeneralModule
10+
PineconeDbModule,
1311
],
1412
controllers: [AppController],
1513
providers: [AppService],

apps/nest-api/src/app/chat-general/controller/chat-general.controller.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,16 @@
11
import { Body, Controller, Post } from '@nestjs/common';
2+
import { ApiBody, ApiTags } from '@nestjs/swagger';
23
import { ChatGeneralService } from '../service/chat-general.service';
34

5+
@ApiTags('chat')
46
@Controller('chat')
57
export class ChatGeneralController {
68
constructor(private chatGeneralService: ChatGeneralService) {}
79

810
@Post('question')
11+
@ApiBody({
12+
schema: { type: 'object', properties: { question: { type: 'string' } } },
13+
})
914
askQuestion(@Body('question') question: string) {
1015
return this.chatGeneralService.askQuestionLlama3(question);
1116
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { Test, TestingModule } from '@nestjs/testing';
2+
import { PineconeDbController } from './pinecone-db.controller';
3+
4+
describe('PineconeDbController', () => {
5+
let controller: PineconeDbController;
6+
7+
beforeEach(async () => {
8+
const module: TestingModule = await Test.createTestingModule({
9+
controllers: [PineconeDbController],
10+
}).compile();
11+
12+
controller = module.get<PineconeDbController>(PineconeDbController);
13+
});
14+
15+
it('should be defined', () => {
16+
expect(controller).toBeDefined();
17+
});
18+
});
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import { Body, Controller, Get, Post } from '@nestjs/common';
2+
import { ApiBody, ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger';
3+
import { PineconeDbService } from '../service/pinecone-db.service';
4+
import { ChatModel } from '../../enums/chat-model';
5+
6+
interface CustomBody {
7+
question: string;
8+
index: string;
9+
model: ChatModel;
10+
}
11+
12+
@ApiTags('pinecone')
13+
@Controller('pinecone')
14+
export class PineconeDbController {
15+
constructor(private readonly pineconeDbService: PineconeDbService) {}
16+
17+
@Post('question')
18+
@ApiOperation({ summary: 'Ask a question to Pinecone DB' })
19+
@ApiBody({
20+
schema: { type: 'object', properties: { question: { type: 'string' } } },
21+
})
22+
@ApiResponse({ status: 200, description: 'Successful response' })
23+
askToPineconeDb(@Body('question') question: string) {
24+
return this.pineconeDbService.askToPineconeDb(question);
25+
}
26+
27+
@Post('custom')
28+
@ApiOperation({ summary: 'Ask a question to Pinecone DB by index' })
29+
@ApiBody({
30+
schema: {
31+
type: 'object',
32+
properties: {
33+
question: { type: 'string' },
34+
index: { type: 'string' },
35+
model: { type: 'string', enum: Object.values(ChatModel) },
36+
},
37+
},
38+
})
39+
@ApiResponse({ status: 200, description: 'Successful response' })
40+
askToPineconeByIndex(@Body() customBody: CustomBody) {
41+
return this.pineconeDbService.askToPineconeDb(
42+
customBody.question,
43+
customBody.index,
44+
customBody.model,
45+
);
46+
}
47+
48+
@Get('indexes')
49+
@ApiOperation({ summary: 'Get Pinecone indexes' })
50+
@ApiResponse({ status: 200, description: 'Successful response' })
51+
pineconeIndexes() {
52+
return this.pineconeDbService.pineconeIndexes();
53+
}
54+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { Module } from '@nestjs/common';
2+
import { PineconeDbController } from './controller/pinecone-db.controller';
3+
import { PineconeDbService } from './service/pinecone-db.service';
4+
import { ChatCoreModule } from '../chat-core/chat-core.module';
5+
6+
@Module({
7+
imports: [ChatCoreModule],
8+
controllers: [PineconeDbController],
9+
providers: [PineconeDbService],
10+
})
11+
export class PineconeDbModule {}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { Test, TestingModule } from '@nestjs/testing';
2+
import { PineconeDbService } from './pinecone-db.service';
3+
4+
describe('PineconeDbService', () => {
5+
let service: PineconeDbService;
6+
7+
beforeEach(async () => {
8+
const module: TestingModule = await Test.createTestingModule({
9+
providers: [PineconeDbService],
10+
}).compile();
11+
12+
service = module.get<PineconeDbService>(PineconeDbService);
13+
});
14+
15+
it('should be defined', () => {
16+
expect(service).toBeDefined();
17+
});
18+
});
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
import { Injectable } from '@nestjs/common';
2+
import { Pinecone as PineconeClient } from '@pinecone-database/pinecone';
3+
import { PineconeStore } from '@langchain/pinecone';
4+
import { OpenAIEmbeddings } from '@langchain/openai';
5+
import { DocumentInterface } from '@langchain/core/documents';
6+
import { HumanMessage } from '@langchain/core/messages';
7+
import { ChatProvider } from '../../chat-core/provider';
8+
import { ChatModel } from '../../enums/chat-model';
9+
import { ConfigService } from '@nestjs/config';
10+
11+
@Injectable()
12+
export class PineconeDbService {
13+
private readonly CHAT_GPT_EMBEDDING_MODEL: string;
14+
private readonly PINECONE_INDEX: string;
15+
16+
constructor(
17+
private configService: ConfigService,
18+
private chatProvider: ChatProvider,
19+
) {
20+
this.CHAT_GPT_EMBEDDING_MODEL =
21+
this.configService.get<string>('CHAT_GPT_EMBEDDING_MODEL') ||
22+
'default_model';
23+
24+
this.PINECONE_INDEX =
25+
this.configService.get<string>('PINECONE_INDEX') || 'default_index';
26+
}
27+
28+
async askToPineconeDb(
29+
question: string,
30+
customIndex?: string,
31+
model?: ChatModel,
32+
) {
33+
const embeddings = new OpenAIEmbeddings({
34+
model: this.CHAT_GPT_EMBEDDING_MODEL,
35+
});
36+
37+
const pinecone = new PineconeClient();
38+
const index = pinecone.Index(customIndex || this.PINECONE_INDEX);
39+
40+
const vectorStore = await PineconeStore.fromExistingIndex(embeddings, {
41+
pineconeIndex: index,
42+
maxConcurrency: 5,
43+
});
44+
45+
//query
46+
const documents = await vectorStore.similaritySearch(question, 2);
47+
// retorna solamente las 100 primeras palabras de cada documento
48+
console.log(
49+
'docuemnts',
50+
documents.map((doc) => doc.pageContent.slice(0, 100)),
51+
);
52+
return this.getExactlyAnswer(documents, question, model);
53+
}
54+
55+
async pineconeIndexes() {
56+
const pinecone = new PineconeClient();
57+
const indexes = await pinecone.listIndexes();
58+
return indexes.indexes;
59+
}
60+
61+
getExactlyAnswer(
62+
documents: DocumentInterface[],
63+
question: string,
64+
model?: ChatModel,
65+
) {
66+
const humanMessages: HumanMessage[] = [];
67+
for (const document of documents) {
68+
const message = new HumanMessage({
69+
content: [
70+
{
71+
type: 'text',
72+
text: document.pageContent,
73+
},
74+
],
75+
});
76+
77+
humanMessages.push(message);
78+
}
79+
80+
if (model) {
81+
return this.chatProvider.askQuestionByModel(
82+
question,
83+
model,
84+
humanMessages,
85+
);
86+
}
87+
88+
return this.chatProvider.askQuestion(question, humanMessages);
89+
}
90+
}

apps/nest-api/src/main.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,34 @@
66
import { Logger } from '@nestjs/common';
77
import { NestFactory } from '@nestjs/core';
88
import { AppModule } from './app/app.module';
9+
import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
910

1011
async function bootstrap() {
1112
const app = await NestFactory.create(AppModule);
1213
const globalPrefix = 'api';
1314
app.setGlobalPrefix(globalPrefix);
1415
const port = process.env.PORT || 3000;
16+
17+
18+
app.enableCors({
19+
origin: '*', // Permitir cualquier origen (puedes restringirlo a un dominio específico)
20+
methods: 'GET,HEAD,PUT,PATCH,POST,DELETE',
21+
allowedHeaders: 'Content-Type, Authorization',
22+
});
23+
24+
// Swagger
25+
const config = new DocumentBuilder()
26+
.setTitle('API REST con NestJS')
27+
.setDescription('Documentación de la API usando Swagger')
28+
.setVersion('1.0')
29+
.addTag('chats')
30+
.build();
31+
32+
const document = SwaggerModule.createDocument(app, config);
33+
SwaggerModule.setup('api', app, document);
34+
35+
36+
1537
await app.listen(port);
1638
Logger.log(
1739
`🚀 Application is running on: http://localhost:${port}/${globalPrefix}`

package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,12 @@
5555
"@nestjs/common": "^10.0.2",
5656
"@nestjs/core": "^10.0.2",
5757
"@nestjs/platform-express": "^10.0.2",
58+
"@nestjs/swagger": "^11.0.6",
59+
"@pinecone-database/pinecone": "^5.1.1",
5860
"axios": "^1.6.0",
5961
"reflect-metadata": "^0.1.13",
6062
"rxjs": "^7.8.0",
63+
"swagger-ui-express": "^5.0.1",
6164
"vue": "^3.3.4",
6265
"vue-router": "^4.2.4"
6366
}

0 commit comments

Comments
 (0)