diff --git a/.example.env.local b/.example.env.local index 7a4bd50..8c7adfd 100644 --- a/.example.env.local +++ b/.example.env.local @@ -1,3 +1,2 @@ OPENAI_API_KEY= -PINECONE_API_KEY= -PINECONE_ENVIRONMENT= \ No newline at end of file +PINECONE_API_KEY= \ No newline at end of file diff --git a/app/api/read/route.ts b/app/api/read/route.ts index 26a089b..2150a81 100644 --- a/app/api/read/route.ts +++ b/app/api/read/route.ts @@ -1,5 +1,5 @@ import { NextRequest, NextResponse } from 'next/server' -import { PineconeClient } from '@pinecone-database/pinecone' +import { Pinecone } from '@pinecone-database/pinecone'; import { queryPineconeVectorStoreAndQueryLLM, } from '../../../utils' @@ -7,11 +7,9 @@ import { indexName } from '../../../config' export async function POST(req: NextRequest) { const body = await req.json() - const client = new PineconeClient() - await client.init({ + const client = new Pinecone({ apiKey: process.env.PINECONE_API_KEY || '', - environment: process.env.PINECONE_ENVIRONMENT || '' - }) + }); const text = await queryPineconeVectorStoreAndQueryLLM(client, indexName, body) diff --git a/app/api/setup/route.ts b/app/api/setup/route.ts index 6b9aa63..a1c911a 100644 --- a/app/api/setup/route.ts +++ b/app/api/setup/route.ts @@ -1,5 +1,5 @@ import { NextResponse } from 'next/server' -import { PineconeClient } from '@pinecone-database/pinecone' +import { Pinecone } from '@pinecone-database/pinecone'; import { TextLoader } from 'langchain/document_loaders/fs/text' import { DirectoryLoader } from 'langchain/document_loaders/fs/directory' import { PDFLoader } from 'langchain/document_loaders/fs/pdf' @@ -19,11 +19,9 @@ export async function POST() { const docs = await loader.load() const vectorDimensions = 1536 - const client = new PineconeClient() - await client.init({ + const client = new Pinecone({ apiKey: process.env.PINECONE_API_KEY || '', - environment: process.env.PINECONE_ENVIRONMENT || '' - }) + }); try { await createPineconeIndex(client, indexName, vectorDimensions) diff --git a/package.json b/package.json index 1e40a5e..8daedbe 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ "lint": "next lint" }, "dependencies": { - "@pinecone-database/pinecone": "^0.1.6", + "@pinecone-database/pinecone": "^2.0.1", "@radix-ui/react-icons": "^1.3.0", "@radix-ui/react-slot": "^1.0.2", "@types/node": "20.2.5", @@ -31,4 +31,4 @@ "tailwindcss-animate": "^1.0.7", "typescript": "5.0.4" } -} +} \ No newline at end of file diff --git a/utils.ts b/utils.ts index dfd4be6..094a873 100644 --- a/utils.ts +++ b/utils.ts @@ -18,12 +18,10 @@ export const queryPineconeVectorStoreAndQueryLLM = async ( const queryEmbedding = await new OpenAIEmbeddings().embedQuery(question) // 4. Query Pinecone index and return top 10 matches let queryResponse = await index.query({ - queryRequest: { - topK: 10, - vector: queryEmbedding, - includeMetadata: true, - includeValues: true, - }, + topK: 10, + vector: queryEmbedding, + includeMetadata: true, + includeValues: true, }); // 5. Log the number of matches console.log(`Found ${queryResponse.matches.length} matches...`); @@ -31,7 +29,9 @@ export const queryPineconeVectorStoreAndQueryLLM = async ( console.log(`Asking question: ${question}...`); if (queryResponse.matches.length) { // 7. Create an OpenAI instance and load the QAStuffChain - const llm = new OpenAI({}); + const llm = new OpenAI({ + modelName: 'gpt-3.5-turbo', + }); const chain = loadQAStuffChain(llm); // 8. Extract and concatenate page content from matched documents const concatenatedPageContent = queryResponse.matches @@ -55,30 +55,26 @@ export const createPineconeIndex = async ( indexName, vectorDimension ) => { - // 1. Initiate index existence check - console.log(`Checking "${indexName}"...`); - // 2. Get list of existing indexes - const existingIndexes = await client.listIndexes(); - // 3. If index doesn't exist, create it - if (!existingIndexes.includes(indexName)) { - // 4. Log index creation initiation - console.log(`Creating "${indexName}"...`); - // 5. Create index - await client.createIndex({ - createRequest: { - name: indexName, - dimension: vectorDimension, - metric: 'cosine', - }, - }); - // 6. Log successful creation - console.log(`Creating index.... please wait for it to finish initializing.`); - // 7. Wait for index initialization - await new Promise((resolve) => setTimeout(resolve, timeout)); - } else { - // 8. Log if index already exists - console.log(`"${indexName}" already exists.`); - } + + await client.createIndex({ + name: indexName, + dimension: vectorDimension, + metric: 'cosine', + spec: { + serverless: { + cloud: 'aws', + region: 'us-west-2' + } + }, + // This option tells the client not to throw if the index already exists. + suppressConflicts: true, + // This option tells the client not to resolve the promise until the + // index is ready. + waitUntilReady: true, + }); + + console.log(`Index "${indexName}" is ready!`); + }; @@ -114,7 +110,7 @@ export const updatePinecone = async (client, indexName, docs) => { ); // 7. Create and upsert vectors in batches of 100 const batchSize = 100; - let batch:any = []; + let batch: any = []; for (let idx = 0; idx < chunks.length; idx++) { const chunk = chunks[idx]; const vector = { @@ -127,16 +123,11 @@ export const updatePinecone = async (client, indexName, docs) => { txtPath: txtPath, }, }; - batch = [...batch, vector] + batch.push(vector); // When batch is full or it's the last item, upsert the vectors if (batch.length === batchSize || idx === chunks.length - 1) { - await index.upsert({ - upsertRequest: { - vectors: batch, - }, - }); - // Empty the batch - batch = []; + await index.upsert(batch); + batch = []; // Clear the batch for the next iteration } } // 8. Log the number of vectors updated diff --git a/yarn.lock b/yarn.lock index b07c14a..1d29602 100644 --- a/yarn.lock +++ b/yarn.lock @@ -200,12 +200,15 @@ "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.0" -"@pinecone-database/pinecone@^0.1.6": - version "0.1.6" - resolved "https://registry.yarnpkg.com/@pinecone-database/pinecone/-/pinecone-0.1.6.tgz#13374ae9462c8eea0dc26683cafeddc4e7c0375f" - integrity sha512-tCnVc28udecthhgSBTdcMhYEW+xsR++AdZasp+ZE/AvUD1hOR2IR3edjk9m0sDxZyvXbno2KeqUbLIOZr7sCTw== +"@pinecone-database/pinecone@^2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@pinecone-database/pinecone/-/pinecone-2.0.1.tgz#1dce6e06e299dfe2c26490aacffe1103e316b8fc" + integrity sha512-a1ejzrqdSQ2yW+9QUi2TVlKwYUbrvGH+QH6POJhITyaOz9ANE+EhXqToC9af93Ctzq9n87+bOUvBvewLeW++Mw== dependencies: + "@sinclair/typebox" "^0.29.0" + ajv "^8.12.0" cross-fetch "^3.1.5" + encoding "^0.1.13" "@pkgr/utils@^2.3.1": version "2.4.1" @@ -244,6 +247,11 @@ resolved "https://registry.yarnpkg.com/@rushstack/eslint-patch/-/eslint-patch-1.3.0.tgz#f5635b36fc0dad96ef1e542a302cd914230188c0" integrity sha512-IthPJsJR85GhOkp3Hvp8zFOPK5ynKn6STyHa/WZpioK7E1aYDiBzpqQPrngc14DszIUkIrdd3k9Iu0XSzlP/1w== +"@sinclair/typebox@^0.29.0": + version "0.29.6" + resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.29.6.tgz#4cd8372f9247372edd5fc5af44f67e2032c46e2f" + integrity sha512-aX5IFYWlMa7tQ8xZr3b2gtVReCvg7f3LEhjir/JAjX2bJCMVJA5tIPv30wTD4KDfcwMd7DDYY3hFDeGmOgtrZQ== + "@swc/helpers@0.5.1": version "0.5.1" resolved "https://registry.yarnpkg.com/@swc/helpers/-/helpers-0.5.1.tgz#e9031491aa3f26bfcc974a67f48bd456c8a5357a" @@ -356,6 +364,16 @@ ajv@^6.10.0, ajv@^6.12.4: json-schema-traverse "^0.4.1" uri-js "^4.2.2" +ajv@^8.12.0: + version "8.12.0" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.12.0.tgz#d1a0527323e22f53562c567c00991577dfbe19d1" + integrity sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA== + dependencies: + fast-deep-equal "^3.1.1" + json-schema-traverse "^1.0.0" + require-from-string "^2.0.2" + uri-js "^4.2.2" + ansi-regex@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" @@ -818,6 +836,13 @@ emoji-regex@^9.2.2: resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72" integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg== +encoding@^0.1.13: + version "0.1.13" + resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.13.tgz#56574afdd791f54a8e9b2785c0582a2d26210fa9" + integrity sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A== + dependencies: + iconv-lite "^0.6.2" + enhanced-resolve@^5.12.0: version "5.14.1" resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.14.1.tgz#de684b6803724477a4af5d74ccae5de52c25f6b3" @@ -1473,6 +1498,13 @@ human-signals@^4.3.0: resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-4.3.1.tgz#ab7f811e851fca97ffbd2c1fe9a958964de321b2" integrity sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ== +iconv-lite@^0.6.2: + version "0.6.3" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501" + integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw== + dependencies: + safer-buffer ">= 2.1.2 < 3.0.0" + ignore@^5.2.0: version "5.2.4" resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.4.tgz#a291c0c6178ff1b960befe47fcdec301674a6324" @@ -1753,6 +1785,11 @@ json-schema-traverse@^0.4.1: resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== +json-schema-traverse@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2" + integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug== + json-stable-stringify-without-jsonify@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" @@ -2412,6 +2449,11 @@ regexp.prototype.flags@^1.4.3, regexp.prototype.flags@^1.5.0: define-properties "^1.2.0" functions-have-names "^1.2.3" +require-from-string@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" + integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== + resolve-from@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" @@ -2475,6 +2517,11 @@ safe-regex-test@^1.0.0: get-intrinsic "^1.1.3" is-regex "^1.1.4" +"safer-buffer@>= 2.1.2 < 3.0.0": + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== + scheduler@^0.23.0: version "0.23.0" resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.23.0.tgz#ba8041afc3d30eb206a487b6b384002e4e61fdfe"