Hello All I am trying creating a RAG chatbot, that does a POST request when user clicks add. The purpose of the add, is to add the record in the RAG vector database. I can’t seem to format the data properly to do, I was able to achieve something similar using python notebook.
Json Format:
{
"restaurant": [
{
"restaurant": "Bella Italia",
"cuisine": "Italian",
"rating": 5,
"review": "Amazing pasta and great ambiance! Highly recommended."
},
{
"restaurant": "Sushi Sakura",
"cuisine": "Japanese",
"rating": 4,
"review": "Fresh sushi and friendly staff. A bit pricey but worth it."
}
]
}
My app/api/add/route.js code is below:
import { Pinecone } from '@pinecone-database/pinecone';
import { OpenAI } from 'openai';
import dotenv from 'dotenv';
dotenv.config();
// Initialize OpenAI and Pinecone clients with API keys
const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
const pc = new Pinecone({ apiKey: process.env.PINECONE_API_KEY });
const index = pc.index('rag'); // Use the correct index name
// Function to handle user input
async function handleUserInput(userInput) {
let records = [];
// Check if input is an array or an object
if (Array.isArray(userInput.restaurant)) {
records = userInput.restaurant;
} else {
console.error('Invalid input format:', userInput);
return [];
}
const processedData = [];
for (const record of records) {
console.log('Processing record:', record);
// Ensure fields are properly mapped
const mappedRecord = {
restaurant: record.restaurant,
review: record.review,
cuisine: record.cuisine,
rating: record.rating,
};
if (!mappedRecord.restaurant || !mappedRecord.review || !mappedRecord.cuisine || typeof mappedRecord.rating !== 'number') {
console.error('Invalid record data:', mappedRecord);
continue;
}
try {
const response = await openai.embeddings.create({
input: mappedRecord.review,
model: 'text-embedding-3-small', // Ensure this model is available
});
const embedding = response.data?.[0]?.embedding;
if (!Array.isArray(embedding)) {
throw new Error('Embedding is not an array');
}
processedData.push({
id: mappedRecord.restaurant, // Use 'restaurant' field for id
values: embedding, // Embedding should be an array
metadata: {
review: mappedRecord.review,
cuisine: mappedRecord.cuisine,
rating: mappedRecord.rating,
},
});
} catch (error) {
console.error('Error creating embedding:', error.message);
}
}
return processedData;
}
// Function to upsert data into Pinecone
async function upsertData(processedData) {
try {
// Ensure processedData is in the correct format
const formattedData = processedData.map(record => ({
id: record.id,
values: record.values,
metadata: record.metadata,
}));
// Perform upsert operation
const upsertResponse = await index.upsert({
vectors: formattedData,
namespace: 'ns1', // Replace with your namespace if needed
});
console.log(`Upserted count: ${upsertResponse.upserted_count}`);
} catch (error) {
console.error('Error upserting data into Pinecone:', error.message);
throw new Error('Failed to upsert data');
}
}
// Function to print index statistics
async function printIndexStats() {
try {
const stats = await index.describeIndexStats();
console.log('Index statistics:', stats);
} catch (error) {
console.error('Error describing index stats:', error.message);
}
}
// POST request handler
export async function POST(req) {
if (req.method !== 'POST') {
return new Response(JSON.stringify({ error: 'Method not allowed' }), { status: 405 });
}
try {
const body = await req.json();
console.log('Received request body:', JSON.stringify(body, null, 2)); // Pretty print
const processedData = await handleUserInput(body);
if (processedData.length > 0) {
await upsertData(processedData);
} else {
console.log('No valid data to upsert');
}
await printIndexStats();
return new Response(JSON.stringify({ message: 'Successfully added to lunch box' }), { status: 200 });
} catch (error) {
console.error('Error adding restaurant:', error.message);
return new Response(JSON.stringify({ error: error.message || 'Internal Server Error' }), { status: 500 });
}
}
Similar Implementation done here:
from dotenv import load_dotenv
load_dotenv()
from pinecone import Pinecone, ServerlessSpec
from openai import OpenAI
import os
import json
# Initialize Pinecone
pinecone = Pinecone(api_key=os.getenv("PINECONE_API_KEY"))
# Create a Pinecone index
pinecone.create_index(
name="rag",
dimension=1536,
metric="cosine",
spec=ServerlessSpec(cloud="aws", region="us-east-1"),
)
# Load the review data
with open("reviews.json") as file:
data = json.load(file)
# Initialize OpenAI client
client = OpenAI()
processed_data = []
# Create embeddings for each review
for review in data["restaurant"]:
response = client.embeddings.create(
input=review['review'], model="text-embedding-3-small"
)
embedding = response.data[0].embedding
processed_data.append(
{
"values": embedding,
"id": review["restaurant"],
"metadata": {
"review": review["review"],
"cuisine": review["cuisine"],
"rating": review["rating"],
}
}
)
# Insert the embeddings into the Pinecone index
index = pinecone.Index("rag")
upsert_response = index.upsert(
vectors=processed_data,
namespace="ns1"
)
print("Upsert response:", upsert_response)
# Print index statistics
index_stats = index.describe_index_stats()
print(index_stats)
Basically I am trying to achieve what I have done in python, through javascript.
My error are below:
○ Compiling /api/add ...
✓ Compiled /api/add in 1273ms (1168 modules)
Failed to find any user-provided fetch implementation. Using global fetch implementation.
Failed to find any user-provided fetch implementation. Using global fetch implementation.
Received request body: {
"restaurant": {
"name": "Popeyes Louisiana Kitchen",
"rating": 4.6,
"cuisine": "Fast-food",
"review": "This is not the first time, last visit the food was clearly refried to be warmed up. This time, all the wraps are dripping with half a bottle of sause in each wrap. Inedible food. I would like my money back. My dog is served better food."
}
}
Invalid input format: {
restaurant: {
name: 'Popeyes Louisiana Kitchen',
rating: 4.6,
cuisine: 'Fast-food',
review: 'This is not the first time, last visit the food was clearly refried to be warmed up. This time, all the wraps are dripping with half a bottle of sause in each wrap. Inedible food. I would like my money back. My dog is served better food.'
}
}
No valid data to upsert
Failed to find any user-provided fetch implementation. Using global fetch implementation.
Failed to find any user-provided fetch implementation. Using global fetch implementation.
Index statistics: {
namespaces: { ns1: { recordCount: 20 } },
dimension: 1536,
indexFullness: 0,
totalRecordCount: 20
}
POST /api/add 200 in 2870ms