-
Notifications
You must be signed in to change notification settings - Fork 19
/
Copy path+handler.ts
79 lines (62 loc) · 2.3 KB
/
+handler.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
import type { mongodb } from '@fastify/mongodb';
import type { FastifyPluginAsyncTypebox } from '@fastify/type-provider-typebox';
import { ChatPromptTemplate } from '@langchain/core/prompts';
import { MongoDBAtlasVectorSearch } from '@langchain/mongodb';
import { createStuffDocumentsChain } from 'langchain/chains/combine_documents';
import { createRetrievalChain } from 'langchain/chains/retrieval';
import useModel, { useEmbeddings } from '~/composables/useModel';
export default (async (app) => {
/*
User sends conversation
```ts
import { stream } from 'fetch-event-stream';
await stream('http://127.0.0.1:3000/api/conversation', {
method: 'POST',
body: JSON.stringify({
messages: [
{
id: self.crypto.randomUUID(),
content: 'What is GenAI?',
role: 'user',
},
],
}),
});
```
*/
app.post('', async (request, reply) => {
type Message = { id: string; content: string; role: 'user' };
const body = JSON.parse(request.body as string) as { messages: Message[] };
const model = useModel({ model: 'gpt-4o-mini', temperature: 0.3 });
const embeddings = useEmbeddings();
const collection = app.mongo.db?.collection('vector') as mongodb.Collection<mongodb.Document>;
const vectorStore = new MongoDBAtlasVectorSearch(embeddings, {
collection,
indexName: 'vector_index',
});
const retriever = vectorStore.asRetriever({ k: 2 });
const systemPrompt = `
You are an assistant for question-answering tasks.
Use the following pieces of retrieved context to answer the question.
If you don't know the answer, say that you don't know.
{context}
`;
const prompt = ChatPromptTemplate.fromMessages([
['system', systemPrompt],
['human', '{input}'],
]);
const questionAnswerChain = await createStuffDocumentsChain({ llm: model, prompt });
const ragChain = await createRetrievalChain({
retriever,
combineDocsChain: questionAnswerChain,
});
const stream = await ragChain.stream({ input: body.messages[0].content });
for await (const chunk of stream) {
reply.sse({ data: chunk });
}
request.raw.on('close', async () => {
await stream.cancel();
});
return reply.sse({ event: 'end' });
});
}) as FastifyPluginAsyncTypebox;