diff --git a/package.json b/package.json index 1e37510..9defdfc 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,7 @@ "dependencies": { "@langchain/community": "^0.3.1", "@langchain/core": "^0.3.3", + "@langchain/ollama": "^0.1.0", "@langchain/openai": "^0.3.0", "@prisma/client": "5.20.0", "@radix-ui/react-alert-dialog": "^1.1.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2c7dc63..1644c85 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -7,10 +7,13 @@ settings: dependencies: '@langchain/community': specifier: ^0.3.1 - version: 0.3.1(@langchain/core@0.3.3)(ignore@6.0.2) + version: 0.3.1(@langchain/core@0.3.3)(@langchain/ollama@0.1.0)(ignore@6.0.2) '@langchain/core': specifier: ^0.3.3 version: 0.3.3 + '@langchain/ollama': + specifier: ^0.1.0 + version: 0.1.0(@langchain/core@0.3.3) '@langchain/openai': specifier: ^0.3.0 version: 0.3.0(@langchain/core@0.3.3) @@ -49,7 +52,7 @@ dependencies: version: 6.0.2 langchain: specifier: ^0.3.2 - version: 0.3.2(@langchain/core@0.3.3) + version: 0.3.2(@langchain/core@0.3.3)(@langchain/ollama@0.1.0) lucide-react: specifier: ^0.445.0 version: 0.445.0(react@18.3.1) @@ -376,7 +379,7 @@ packages: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.0 - /@langchain/community@0.3.1(@langchain/core@0.3.3)(ignore@6.0.2): + /@langchain/community@0.3.1(@langchain/core@0.3.3)(@langchain/ollama@0.1.0)(ignore@6.0.2): resolution: {integrity: sha512-V6n4kkv3isYoiU2ciLNhcqBT96IwxpMNt5K/KxkzOfGNJIWQcsPzTccuWZXdDOQ40kelCg+S8YKGVy8X4mkgtg==} engines: {node: '>=18'} peerDependencies: @@ -753,7 +756,7 @@ packages: flat: 5.0.2 ignore: 6.0.2 js-yaml: 4.1.0 - langchain: 0.3.2(@langchain/core@0.3.3) + langchain: 0.3.2(@langchain/core@0.3.3)(@langchain/ollama@0.1.0) langsmith: 0.1.59 uuid: 10.0.0 zod: 3.23.8 @@ -793,6 +796,17 @@ packages: - openai dev: false + /@langchain/ollama@0.1.0(@langchain/core@0.3.3): + resolution: {integrity: sha512-TI4DGenLf1ApoxFf4Bx/VPyO+a+poJKIul8AGm/FEyORtw3JPq1UDR6SdkGETrkDqzzdK9R0DvFRStd1MSTE/w==} + engines: {node: '>=18'} + peerDependencies: + '@langchain/core': '>=0.2.21 <0.4.0' + dependencies: + '@langchain/core': 0.3.3 + ollama: 0.5.9 + uuid: 10.0.0 + dev: false + /@langchain/openai@0.3.0(@langchain/core@0.3.3): resolution: {integrity: sha512-yXrz5Qn3t9nq3NQAH2l4zZOI4ev2CFdLC5kvmi5SdW4bggRuM40SXTUAY3VRld4I5eocYfk82VbrlA+6dvN5EA==} engines: {node: '>=18'} @@ -3614,7 +3628,7 @@ packages: json-buffer: 3.0.1 dev: true - /langchain@0.3.2(@langchain/core@0.3.3): + /langchain@0.3.2(@langchain/core@0.3.3)(@langchain/ollama@0.1.0): resolution: {integrity: sha512-kd2kz1cS/PIVrLEDFlrZsAasQfPLbY1UqCZbRKa3/QcpB33/n6xPDvXSMfBuKhvNj0bjW6MXDR9HZTduXjJBgg==} engines: {node: '>=18'} peerDependencies: @@ -3661,6 +3675,7 @@ packages: optional: true dependencies: '@langchain/core': 0.3.3 + '@langchain/ollama': 0.1.0(@langchain/core@0.3.3) '@langchain/openai': 0.3.0(@langchain/core@0.3.3) '@langchain/textsplitters': 0.1.0(@langchain/core@0.3.3) js-tiktoken: 1.0.14 @@ -4268,6 +4283,12 @@ packages: es-object-atoms: 1.0.0 dev: true + /ollama@0.5.9: + resolution: {integrity: sha512-F/KZuDRC+ZsVCuMvcOYuQ6zj42/idzCkkuknGyyGVmNStMZ/sU3jQpvhnl4SyC0+zBzLiKNZJnJeuPFuieWZvQ==} + dependencies: + whatwg-fetch: 3.6.20 + dev: false + /once@1.4.0: resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} dependencies: @@ -5365,6 +5386,10 @@ packages: resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} dev: false + /whatwg-fetch@3.6.20: + resolution: {integrity: sha512-EqhiFU6daOA8kpjOWTL0olhVOF3i7OrFzSYiGsEMB8GcXS+RrzauAERX65xMeNWVqxA6HXH2m69Z9LaKKdisfg==} + dev: false + /whatwg-url@5.0.0: resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} dependencies: diff --git a/src/app/api/chat/route.ts b/src/app/api/chat/route.ts index 9af9c87..0a2f6b6 100644 --- a/src/app/api/chat/route.ts +++ b/src/app/api/chat/route.ts @@ -1,8 +1,9 @@ import {NextRequest, NextResponse} from "next/server"; import {Message as VercelChatMessage} from "ai"; -import {ChatOpenAI, OpenAIEmbeddings} from "@langchain/openai"; -import {SystemMessagePromptTemplate} from "@langchain/core/prompts"; +// import {ChatOpenAI, OpenAIEmbeddings} from "@langchain/openai"; +import {ChatOllama, OllamaEmbeddings} from "@langchain/ollama" +import {PromptTemplate} from "@langchain/core/prompts"; import {RunnablePassthrough, RunnableSequence} from "@langchain/core/runnables"; import {HttpResponseOutputParser} from "langchain/output_parsers"; import {PrismaVectorStore} from "@langchain/community/vectorstores/prisma"; @@ -38,15 +39,13 @@ export async function POST(req: NextRequest) { throw new Error("Repository not found"); } - const llm = new ChatOpenAI({ - model: "gpt-4o-mini", - temperature: 0, - apiKey + const llm = new ChatOllama({ + model: "llama3.2:3b", }); - const embeddings = new OpenAIEmbeddings({ - model: "text-embedding-3-small", - apiKey + const embeddings = new OllamaEmbeddings({ + model: "llama3.2:3b", // Default value + baseUrl: "http://localhost:11434", // Default value }); const vectorStore = PrismaVectorStore.withModel(db).create( @@ -73,7 +72,7 @@ export async function POST(req: NextRequest) { searchType: "similarity" }); - const systemPrompt = SystemMessagePromptTemplate.fromTemplate(` + const prompt = PromptTemplate.fromTemplate(` You are a helpful assistant with good knowledge in coding. Use the provided context and previous conversation to answer user questions with detailed explanations. Read the given context before answering questions and think step by step. If you cannot answer a user question based on the provided context, inform the user. Do not use any other information for answering. @@ -83,7 +82,7 @@ export async function POST(req: NextRequest) { {chat_history} User: {question} - `); +`); const chain = RunnableSequence.from([ RunnablePassthrough.assign({ @@ -99,7 +98,7 @@ export async function POST(req: NextRequest) { return input.chat_history || []; } }), - systemPrompt, + prompt, llm, new HttpResponseOutputParser(), ]); diff --git a/src/services/indexer/index.ts b/src/services/indexer/index.ts index 2a421a5..df6f0cf 100644 --- a/src/services/indexer/index.ts +++ b/src/services/indexer/index.ts @@ -2,7 +2,7 @@ import { GithubRepoLoader } from "@langchain/community/document_loaders/web/github"; import {RecursiveCharacterTextSplitter} from "langchain/text_splitter"; -import {OpenAIEmbeddings} from "@langchain/openai"; +import { OllamaEmbeddings } from "@langchain/ollama"; import {PrismaVectorStore} from "@langchain/community/vectorstores/prisma"; import {Prisma, RepositoryStatus, PrismaClient, Document} from "@prisma/client"; import {Document as LangchainDocument} from "langchain/document"; // Adjust the import path if necessary @@ -167,8 +167,8 @@ export class Indexer { */ private async splitDocuments(docs: LangchainDocument[]): Promise { const splitter = new RecursiveCharacterTextSplitter({ - chunkSize: 2000, - chunkOverlap: 200 + chunkSize: 500, + chunkOverlap: 100 }); const chunks = await splitter.splitDocuments(docs); @@ -185,10 +185,9 @@ export class Indexer { private async storeChunks(chunks: LangchainDocument[], namespace: string, repoUrl: string) { console.log(`[${new Date().toISOString()}] Storing ${chunks.length} chunks into the vector store`); - const openAiKey = await this.getOpenAiToken(); - const embeddings = new OpenAIEmbeddings({ - model: "text-embedding-3-small", - apiKey: openAiKey, + const embeddings = new OllamaEmbeddings({ + model: "llama3.2:3b", // Default value + baseUrl: "http://localhost:11434", // Default value }); const vectorStore = PrismaVectorStore.withModel(this.db).create(