Skip to content

Commit b234154

Browse files
authored
Merge pull request #119 from RipeSeed/feature/pinecone-index-name-configuration
Add Pinecone Index Name to Configuration
2 parents c04d7ca + 426c931 commit b234154

File tree

10 files changed

+144
-18
lines changed

10 files changed

+144
-18
lines changed

src/apis/admin/configuration.ts

+5-1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ interface ConfigurationData {
77
xAccessKey?: string
88
xBaseUrl?: string
99
pineconeApiKey?: string
10+
pineconeIndexName?: string
1011
calendlyMeetingLink?: string
1112
}
1213
// add or update credentials
@@ -23,7 +24,10 @@ export const addUpdateConfiguration = async (data: ConfigurationData) => {
2324
accessKey: data.xAccessKey,
2425
baseUrl: data.xBaseUrl
2526
} : undefined,
26-
pinecone: data.pineconeApiKey ? { apiKey: data.pineconeApiKey } : undefined
27+
pinecone: data.pineconeApiKey ? {
28+
apiKey: data.pineconeApiKey,
29+
indexName: data.pineconeIndexName
30+
} : undefined
2731
},
2832
calendlyMeetingLink: data.calendlyMeetingLink
2933
})

src/app/(admin)/dashboard/configuration/_types/schema.ts

+9
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ export const UpdateSchema = z
88
xAccessKey: z.string().optional(),
99
xBaseUrl: z.string().url('Please enter a valid X API base URL (e.g., https://api.x.com)').optional(),
1010
pineconeApiKey: z.string().optional(),
11+
pineconeIndexName: z.string().optional(),
1112
calendlyMeetingLink: z.string().url('Please enter a valid Calendly meeting URL (e.g., https://calendly.com/your-name/meeting)').optional(),
1213
})
1314
.superRefine((data, ctx) => {
@@ -29,6 +30,14 @@ export const UpdateSchema = z
2930
path: data.xAccessKey ? ['xBaseUrl'] : ['xAccessKey'],
3031
})
3132
}
33+
34+
if (data.pineconeApiKey && !data.pineconeIndexName) {
35+
ctx.addIssue({
36+
code: z.ZodIssueCode.custom,
37+
message: 'Pinecone Index Name is required when API Key is provided',
38+
path: ['pineconeIndexName'],
39+
})
40+
}
3241
})
3342

3443
export type TUpdateSchema = z.infer<typeof UpdateSchema>

src/app/(admin)/dashboard/configuration/page.tsx

+35-2
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,12 @@ import { zodResolver } from '@hookform/resolvers/zod'
66
import { useMutation, useQuery } from '@tanstack/react-query'
77
import { useForm } from 'react-hook-form'
88

9-
import { addUpdateConfiguration, getConfiguration } from '@/apis/admin/configuration'
9+
import {
10+
addUpdateConfiguration,
11+
getConfiguration,
12+
} from '@/apis/admin/configuration'
1013
import { Button } from '@/components/ui/button'
14+
import { Input } from '@/components/ui/input'
1115
import { Label } from '@/components/ui/label'
1216
import { useToast } from '@/hooks/use-toast'
1317
import { InputWithToggle } from './_components/InputWithToggle'
@@ -54,6 +58,7 @@ export default function Configuration() {
5458
xAccessKey: creds.providers?.x?.accessKey || '',
5559
xBaseUrl: creds.providers?.x?.baseUrl || '',
5660
pineconeApiKey: creds.providers?.pinecone?.apiKey || '',
61+
pineconeIndexName: creds.providers?.pinecone?.indexName || '',
5762
calendlyMeetingLink: creds.calendlyMeetingLink || '',
5863
})
5964
}
@@ -62,7 +67,7 @@ export default function Configuration() {
6267
// Disable automatic refetching
6368
refetchOnMount: false,
6469
refetchOnWindowFocus: false,
65-
refetchOnReconnect: false
70+
refetchOnReconnect: false,
6671
})
6772

6873
const handleClick = (data: TUpdateSchema) => {
@@ -243,6 +248,34 @@ export default function Configuration() {
243248
error={errors.pineconeApiKey}
244249
/>
245250
</div>
251+
252+
<div className='flex w-full flex-col space-y-2'>
253+
<Label className='flex items-center gap-2 text-dashboardText'>
254+
<span>Pinecone Index Name</span>
255+
<span className='relative -top-1.5 mt-1'>
256+
<Image
257+
src='/assets/knowledgebase/required.svg'
258+
alt='required'
259+
width={4}
260+
height={4}
261+
/>
262+
</span>
263+
</Label>
264+
<Input
265+
{...register('pineconeIndexName')}
266+
placeholder='your-pinecone-index'
267+
className='h-10 bg-white'
268+
/>
269+
<p className='mt-1 text-xs text-muted-foreground'>
270+
You can find your index name in the Pinecone dashboard
271+
under &apos;Indexes&apos;
272+
</p>
273+
{errors.pineconeIndexName && (
274+
<p className='text-xs text-red-500'>
275+
{errors.pineconeIndexName.message}
276+
</p>
277+
)}
278+
</div>
246279
</div>
247280
</div>
248281

src/app/api/(admin)/config/route.ts

+2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ export const POST = async (request: NextRequest) => {
88
const { providers, calendlyMeetingLink } = await request.json()
99
await connectDB()
1010

11+
console.log('providers', providers)
12+
1113
await APICredentials.deleteMany({})
1214

1315
const updatedCredentials = await APICredentials.create({

src/app/api/(admin)/knowledgebase/file/route.ts

+4-5
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,13 @@
11
import { NextRequest, NextResponse } from 'next/server'
22
import { PDFLoader } from '@langchain/community/document_loaders/fs/pdf'
33
import { OpenAIEmbeddings } from '@langchain/openai'
4-
import { Index, Pinecone as PineconeClient } from '@pinecone-database/pinecone'
54
import { RecursiveCharacterTextSplitter } from 'langchain/text_splitter'
65
import { v4 as uuid } from 'uuid'
76

87
import { connectDB } from '@/models'
98
import FileModel from '@/models/knowledgeBase/File.model'
9+
import { getPineconeIndex } from '@/services/pinecone/client'
1010

11-
const pinecone = new PineconeClient({
12-
apiKey: process.env.PINECONE_API_KEY!,
13-
})
14-
const pineconeIndex: Index = pinecone.Index(process.env.PINECONE_INDEX!)
1511
export const POST = async (request: NextRequest, response: NextResponse) => {
1612
try {
1713
const form = await request.formData()
@@ -85,6 +81,9 @@ const uploadChunksToPineCone = async (
8581
fileId: string,
8682
) => {
8783
try {
84+
// Get the Pinecone index from our centralized service
85+
const pineconeIndex = await getPineconeIndex()
86+
8887
let batchSize = 100
8988
let batch = []
9089
for (let i = 0; i < chunks.length; i++) {

src/models/credentials/APICredentials.model.ts

+4
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@ const APICredentialsSchema = new mongoose.Schema(
3232
apiKey: {
3333
type: String,
3434
required: false
35+
},
36+
indexName: {
37+
type: String,
38+
required: false
3539
}
3640
}
3741
},

src/services/chat/chat.ts

+4-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { PineconeStore } from '@langchain/pinecone'
66
import type { Document as LangchainDoc } from 'langchain/document'
77
import { RecursiveCharacterTextSplitter } from 'langchain/text_splitter'
88

9-
import { pineconeIndex } from './config'
9+
import { getPineconeIndex } from './config'
1010

1111
export const splitText = async (file: File, id: string) => {
1212
try {
@@ -25,6 +25,9 @@ export const createEmbeddings = async (
2525
embeddings: OpenAIEmbeddings,
2626
) => {
2727
try {
28+
// Get the Pinecone index
29+
const pineconeIndex = await getPineconeIndex()
30+
2831
const vectorStore = await PineconeStore.fromDocuments(docs, embeddings, {
2932
pineconeIndex,
3033
})

src/services/chat/config.ts

+3-8
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,6 @@
11
import 'server-only'
22

3-
import { Pinecone } from '@pinecone-database/pinecone'
3+
import { getPineconeIndex } from '../pinecone/client'
44

5-
const pinecone = new Pinecone({
6-
apiKey: process.env.PINECONE_API_KEY!,
7-
})
8-
9-
const pineconeIndex = pinecone.Index(process.env.PINECONE_INDEX!)
10-
11-
export { pineconeIndex }
5+
// Export the getPineconeIndex function directly
6+
export { getPineconeIndex }

src/services/chat/conversation.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import 'server-only'
77
import { OpenAI } from 'openai'
88

99
import { connectDB } from '@/models'
10-
import { pineconeIndex } from './config'
10+
import { getPineconeIndex } from './config'
1111
import APICredentials from '@/models/credentials/APICredentials.model'
1212

1313
export interface Context {
@@ -178,6 +178,7 @@ export function converse(
178178

179179
let serializedDocs = ''
180180
if (idArray[0] !== null) {
181+
const pineconeIndex = await getPineconeIndex()
181182
const docs = await pineconeIndex.query({
182183
vector,
183184
topK: 2,

src/services/pinecone/client.ts

+76
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
import { Index, Pinecone as PineconeClient } from '@pinecone-database/pinecone'
2+
3+
import { connectDB } from '@/models'
4+
import APICredentials from '@/models/credentials/APICredentials.model'
5+
6+
// Cache for the Pinecone client and index
7+
let pineconeClientInstance: PineconeClient | null = null
8+
let pineconeIndexInstance: Index | null = null
9+
let indexName: string = 'default-index'
10+
11+
/**
12+
* Initialize the Pinecone client with credentials from the database
13+
* @returns The Pinecone client instance
14+
*/
15+
export const getPineconeClient = async (): Promise<PineconeClient> => {
16+
// Return cached instance if available
17+
if (pineconeClientInstance) {
18+
return pineconeClientInstance
19+
}
20+
21+
try {
22+
await connectDB()
23+
const credentials = await APICredentials.findOne()
24+
25+
if (!credentials || !credentials.providers.pinecone?.apiKey) {
26+
throw new Error('Pinecone API key not found in database')
27+
}
28+
29+
// Create a new Pinecone client
30+
pineconeClientInstance = new PineconeClient({
31+
apiKey: credentials.providers.pinecone.apiKey,
32+
})
33+
indexName =
34+
credentials.providers.pinecone.indexName ||
35+
process.env.PINECONE_INDEX ||
36+
'default-index'
37+
38+
return pineconeClientInstance
39+
} catch (error) {
40+
console.error('Error initializing Pinecone client:', error)
41+
throw error
42+
}
43+
}
44+
45+
/**
46+
* Get the Pinecone index
47+
* @param indexNameParam Optional index name to override the default
48+
* @returns The Pinecone index instance
49+
*/
50+
export const getPineconeIndex = async (
51+
indexNameParam?: string,
52+
): Promise<Index> => {
53+
// If index name is provided and different from cached one, reset the index instance
54+
if (indexNameParam && indexNameParam !== indexName) {
55+
pineconeIndexInstance = null
56+
indexName = indexNameParam
57+
}
58+
59+
// Return cached instance if available
60+
if (pineconeIndexInstance) {
61+
return pineconeIndexInstance
62+
}
63+
64+
try {
65+
// Get the Pinecone client
66+
const pineconeClient = await getPineconeClient()
67+
68+
// Create a new Pinecone index
69+
pineconeIndexInstance = pineconeClient.Index(indexName)
70+
71+
return pineconeIndexInstance
72+
} catch (error) {
73+
console.error('Error getting Pinecone index:', error)
74+
throw error
75+
}
76+
}

0 commit comments

Comments
 (0)