কম্পিউটার টিউটোরিয়াল

LangChain, Faiss এবং Next.js-এর সাথে একটি কাস্টম এআই চ্যাটবট তৈরি করুন – একটি ব্যবহারিক নির্দেশিকা

এই পোস্টে, আমি কীভাবে Upstash, Next.js, LangChain এবং Fly.io-এর সাথে একটি ওপেন-সোর্স কাস্টম কন্টেন্ট AI চ্যাটবট তৈরি করেছি সে সম্পর্কে কথা বলব। Upstash আমাকে মডেল প্রশিক্ষণের সময়সূচী করতে সাহায্য করেছে, উদার হার সীমিত করার এবং OpenAI API প্রতিক্রিয়া ক্যাশ করার উপায় প্রস্তাব করেছে।

LangChain, Faiss এবং Next.js-এর সাথে একটি কাস্টম এআই চ্যাটবট তৈরি করুন – একটি ব্যবহারিক নির্দেশিকা

আমরা কি ব্যবহার করব

  • Next.js (ফ্রন্ট-এন্ড এবং ব্যাক-এন্ড)
  • LangChain (ভাষা মডেল দ্বারা চালিত অ্যাপ্লিকেশন বিকাশের জন্য কাঠামো)
  • Upstash (QStash এর মাধ্যমে শিডিউলিং ট্রেনিং মডেল, রেট লিমিটিং এবং ক্যাশিং OpenAI রেসপন্স)
  • Tailwind CSS (স্টাইলিং)
  • Fly.io (ডিপ্লয়মেন্ট)

আপনার যা প্রয়োজন

  • Node.js 18
  • একটি Upstash অ্যাকাউন্ট
  • একটি OpenAI অ্যাকাউন্ট (OpenAI API কী-এর জন্য)

Upstash Redis সেট আপ করা হচ্ছে

একবার আপনি একটি Upstash অ্যাকাউন্ট তৈরি করেছেন এবং লগ ইন করলে আপনি Redis ট্যাবে যান এবং একটি ডাটাবেস তৈরি করতে যাচ্ছেন৷

LangChain, Faiss এবং Next.js-এর সাথে একটি কাস্টম এআই চ্যাটবট তৈরি করুন – একটি ব্যবহারিক নির্দেশিকা

LangChain, Faiss এবং Next.js-এর সাথে একটি কাস্টম এআই চ্যাটবট তৈরি করুন – একটি ব্যবহারিক নির্দেশিকা

আপনি আপনার ডাটাবেস তৈরি করার পরে, আপনি তারপরে বিশদ ট্যাবে যাচ্ছেন। আপনি আপনার ডাটাবেস সংযোগ বিভাগটি খুঁজে না পাওয়া পর্যন্ত নিচে স্ক্রোল করুন। বিষয়বস্তু অনুলিপি করুন এবং এটি নিরাপদ কোথাও সংরক্ষণ করুন৷

LangChain, Faiss এবং Next.js-এর সাথে একটি কাস্টম এআই চ্যাটবট তৈরি করুন – একটি ব্যবহারিক নির্দেশিকা

এছাড়াও, আপনি REST API বিভাগটি খুঁজে না পাওয়া পর্যন্ত নিচে স্ক্রোল করুন এবং .env বোতামটি নির্বাচন করুন। বিষয়বস্তু অনুলিপি করুন এবং এটি নিরাপদ কোথাও সংরক্ষণ করুন৷

LangChain, Faiss এবং Next.js-এর সাথে একটি কাস্টম এআই চ্যাটবট তৈরি করুন – একটি ব্যবহারিক নির্দেশিকা

Upstash QStash সেট আপ করা হচ্ছে

একবার লগ ইন করলে আপনি QStash ট্যাবে যাবেন এবং QSTASH_URL পাবেন , QSTASH_TOKEN , QSTASH_CURRENT_SIGNING_KEY , এবং QSTASH_NEXT_SIGNING_KEY . বিষয়বস্তু অনুলিপি করুন এবং এটি নিরাপদ কোথাও সংরক্ষণ করুন৷

LangChain, Faiss এবং Next.js-এর সাথে একটি কাস্টম এআই চ্যাটবট তৈরি করুন – একটি ব্যবহারিক নির্দেশিকা

প্রকল্প সেট আপ করা হচ্ছে

সেট আপ করতে, শুধু অ্যাপ রেপো ক্লোন করুন এবং এতে যা আছে তা শিখতে এই টিউটোরিয়ালটি অনুসরণ করুন। প্রকল্পটি ফর্ক করতে, চালান:

git clone https://github.com/rishi-raj-jain/custom-content-ai-chatbot
cd custom-content-ai-chatbot
npm install

একবার আপনি রেপো ক্লোন করার পরে, আপনি একটি .env ফাইল তৈরি করতে যাচ্ছেন। আপনি উপরের বিভাগগুলি থেকে আমরা যে আইটেমগুলি সংরক্ষণ করেছি তা যোগ করতে চলেছেন৷

এটি দেখতে এইরকম কিছু হওয়া উচিত:

# .env
 
# Obtained from the steps as above
 
# Upstash Redis Secrets
UPSTASH_REDIS_REST_URL="https://....upstash.io"
UPSTASH_REDIS_REST_TOKEN="..."
 
# Upstash QStash Secrets
QSTASH_URL="https://qstash.upstash.io/v1/publish/"
QSTASH_TOKEN="..."
QSTASH_CURRENT_SIGNING_KEY="sig_..."
QSTASH_NEXT_SIGNING_KEY="sig_..."
 
# OpenAI Key
OPENAI_API_KEY="sk-..."
 
# Admin Access Key
# Used to verify a training request as to be done only by an admin
ADMIN_KEY="..."

এই পদক্ষেপগুলির পরে, আপনি নিম্নলিখিত কমান্ডটি ব্যবহার করে স্থানীয় পরিবেশ শুরু করতে সক্ষম হবেন:

npm run dev

রিপোজিটরি স্ট্রাকচার

এই প্রকল্পের জন্য প্রধান ফোল্ডার গঠন. আমি সেই ফাইলগুলিকে লাল রঙে চিহ্নিত করেছি যা এই পোস্টে আরও আলোচনা করা হবে যা ভেক্টর স্টোর পরিচালনা, আপনার কাস্টম বিষয়বস্তুতে প্রশিক্ষিত AI এর সাথে চ্যাট করার জন্য API রুট তৈরি করে (প্রতিক্রিয়াগুলি ক্যাশ করার সাথে), এবং মডেল প্রশিক্ষণ প্রক্রিয়ার সময়সূচী তৈরি করে৷

LangChain, Faiss এবং Next.js-এর সাথে একটি কাস্টম এআই চ্যাটবট তৈরি করুন – একটি ব্যবহারিক নির্দেশিকা

উচ্চ-স্তরের ডেটা ফ্লো এবং অপারেশনগুলি

এটি কীভাবে ডেটা প্রবাহিত হয় এবং ক্রিয়াকলাপগুলি ঘটে তার একটি উচ্চ-স্তরের চিত্র 👇🏻

LangChain, Faiss এবং Next.js-এর সাথে একটি কাস্টম এআই চ্যাটবট তৈরি করুন – একটি ব্যবহারিক নির্দেশিকা

  • যখন একজন ব্যবহারকারী চ্যাটবটের মাধ্যমে একটি প্রশ্ন জিজ্ঞাসা করে, ব্যবহারকারীদের আইপি রেট সীমাবদ্ধতার বিরুদ্ধে চেক করা হয় এবং একটি প্রতিক্রিয়া, যদি Upstash Redis এর মাধ্যমে ক্যাশে না করা হয়, OpenAI API থেকে চাওয়া হয় (তখন ক্যাশে করা হয়) এবং ব্যবহারকারীর কাছে স্ট্রিম করা হয়
  • যখন কোনো প্রশাসক প্রদত্ত ইউআরএল-এর সেটে বিদ্যমান মডেলের প্রশিক্ষণের অনুরোধ করেন, তখন Upstash-এর QStash-এর সাহায্যে প্রদত্ত ইউআরএল-এ বিষয়বস্তু আনতে এবং মডেল (পটভূমিতে) আপডেট করতে একটি নির্দিষ্ট বিলম্বের পরে সার্ভারবিহীন একটি POST অনুরোধ করা হয়

Next.js-এ চ্যাট এবং ট্রেন API রুট সেটআপ করুন

এই বিভাগে, আমরা কীভাবে রুট সেটআপ করেছি সে সম্পর্কে কথা বলি:pages/api/chat.js ক্রস অরিজিন অনুরোধগুলি সক্ষম করতে, ব্যবহারকারীদের কাছে চ্যাট এপিআই কল, ক্যাশে এবং স্ট্রিম প্রতিক্রিয়া সীমিত করুন এবং নির্দিষ্ট ইউআরএলগুলিতে বিষয়বস্তু প্রশিক্ষণের সময়সূচী করার একটি পদ্ধতি প্রকাশ করুন এবং pages/api/train.js শুধুমাত্র প্রদত্ত ইউআরএলে কিন্তু ব্যাকগ্রাউন্ডে প্রশিক্ষণের জন্য।

1. CORS সক্ষম করুন

cors ব্যবহার করা হচ্ছে প্যাকেজ, আমরা একাধিক জায়গায় চ্যাটবট ব্যবহার করার জন্য অ্যাপ্লিকেশনটিতে CORS সক্ষম করেছি, আপনার ওয়েবসাইটে বট হিসাবে বলুন। API রুট শুরু হওয়ার সাথে সাথেই আমরা নিচের মত করে cors সেটআপ চালাই 👇🏻

// File: pages/api/chat.js
 
// Reference Function to cors
import { runMiddleware } from '@/lib/cors'
 
export default async function (req, res) {
 try {
 // Run the middleware
 await runMiddleware(req, res)
 // ...
 catch (e) {
 console.log(e.message || e.toString())
 }
 return res.end()
}
 
// Cors Function
// File: lib/cors.js
import Cors from 'cors'
 
// Initializing the cors middleware
// You can read more about the available options here: https://github.com/expressjs/cors#configuration-options
const cors = Cors({
 methods: ['POST', 'OPTIONS', 'HEAD'],
})
 
// Helper method to wait for a middleware to execute before continuing
// And to throw an error when an error happens in a middleware
export function runMiddleware(req, res, fn = cors) {
 return new Promise((resolve, reject) => {
 fn(req, res, (result) => {
 if (result instanceof Error) return reject(result)
 return resolve(result)
 })
 })
}

2. প্রদত্ত ইউআরএলগুলিতে বিষয়বস্তু প্রশিক্ষণের অনুরোধ(গুলি) নির্ধারণ করুন

Upstash QStash এর সাহায্যে, কেউ এমন API তৈরি করতে পারে যা আগুনের মতো এবং ভুলে যায়। প্রতিক্রিয়া পেতে আপনাকে সক্রিয়ভাবে মূল ফাংশনটি শেষ হওয়ার জন্য অপেক্ষা করতে হবে না বরং এটি পটভূমিতে করুন (ঐচ্ছিকভাবে, কিছু প্রদত্ত বিলম্বের পরে)। এটি একটি ক্রন-জবের মতো তবে এটি প্রতিটি অনুরোধ অনুযায়ী চলে এবং নির্ধারিত বিরতিতে নিয়মিত নয়৷

একই চ্যাট এপিআই রুটে, আমরা একটি অনুরোধ গ্রহণ করি যার একটি admin-key আছে হেডার এবং যদি সেটি সার্ভার সাইড সিক্রেটের সাথে মেলে (ADMIN_KEY ), আমরা কিছু বিলম্বের পরে অনুরোধের অংশে পাস করা ইউআরএলগুলির সেটে বিষয়বস্তু প্রশিক্ষণের সময় নির্ধারণ করি (এখানে 10s ) সেট বিলম্বের পরে বিষয়বস্তু প্রশিক্ষণের অনুরোধ একটি প্রদত্ত এন্ডপয়েন্টে করা হয় (এখানে:https://custom-content-ai-chatbot.fly.dev/api/train )

// File: pages/api/chat.js
 
// If the headers contain an `admin-key` header
if (req.headers['admin-key'] === process.env.ADMIN_KEY) {
 // If `urls` is not in body, return with `Bad Request`
 if (!req.body.urls) return res.status(400).send('No urls to train on.')
 // Hit QStash API to train on this set of URLs after 10 seconds from now
 await qstashClient.publishJSON({
 delay: 10,
 body: { urls: req.body.urls },
 url: 'https://custom-content-ai-chatbot.fly.dev/api/train'
 })
 return res.status(200).end()
}

এখন, ট্রেনের এপিআই রুটে কী আছে তা দেখে নেওয়া যাক (pages/api/train.js ) 👇🏻

// File: pages/api/train.js
 
import train from '@/lib/train'
import * as dotenv from 'dotenv'
import { redis } from '@/lib/redis'
import { runMiddleware } from '@/lib/cors'
import { verifySignature } from '@upstash/qstash/nextjs'
 
dotenv.config()
 
// Disabling converting request body to JSON directly
// More on https://nextjs.org/docs/pages/building-your-application/routing/api-routes#custom-config
export const config = {
 api: {
 bodyParser: false,
 },
}
 
async function handler(req, res) {
 try {
 // Run the middleware
 await runMiddleware(req, res)
 // If method is not POST, return with `Forbidden Access`
 if (req.method !== 'POST') return res.status(403).send('No other methods allowed.')
 // If `urls` is not in body, return with `Bad Request`
 if (!req.body.urls) return res.status(400).send('No urls to train on.')
 // Train on the particular URLs
 await train(req.body.urls)
 // Once saved, clear all the responses in Upstash
 let allKeys = await redis.keys('*')
 if (allKeys) {
 // Filter out the keys to not have the ratelimiter ones
 allKeys = allKeys.filter((i) => !i.includes('@upstash/ratelimit:'))
 const p = redis.pipeline()
 // Create a pipeline to clear out all the keys
 allKeys.forEach((i) => p.del(i))
 // Execute the pipeline commands in a transaction
 await p.exec()
 console.log('Cleaned cached responses in Upstash.')
 }
 return res.status(200).end()
 } catch (e) {
 console.log(e.message || e.toString())
 }
 return res.end()
}
 
// Verify the incoming request to be a valid
// QStash Scheduled POST request with Upstash-Signature
export default verifySignature(handler)

উপরের কোডে, আমরা তিনটি গুরুত্বপূর্ণ ক্রিয়া সম্পাদন করছি:

  • QStash এর verifySignature ব্যবহার করে ইনকামিং অনুরোধ যাচাইকরণ সম্পাদন করুন পদ্ধতি এটি নীচে Upstash-Signature খোঁজে হেডার এবং প্রাপ্ত কাঁচা অংশ দিয়ে এটি যাচাই করে।
  • train কে কল করুন ফাংশন যা ইউআরএল বিষয়বস্তু নিয়ে আসা এবং বিদ্যমান ভেক্টর স্টোরে যোগ করার (এবং এটি সংরক্ষণ) করে।
  • Redis লেনদেনের মাধ্যমে হার সীমিতকরণ বাস্তবায়নের সাথে সম্পর্কিত কীগুলি ফিল্টার করার পরে Upstash Redis-এ ক্যাশে করা প্রতিক্রিয়াগুলি সাফ করুন৷

3. হার সীমাবদ্ধতা

রেট-লিমিটিং বাস্তবায়নের জন্য, আমরা Upstash Redis ডাটাবেস ক্লায়েন্ট এবং @upstash/ratelimit নামে একটি রেট লিমিটার লাইব্রেরি ব্যবহার করি। .

// File: lib/redis.js
// Reference Function to ratelimiting
 
import * as dotenv from 'dotenv'
import { Redis } from '@upstash/redis'
import { Ratelimit } from '@upstash/ratelimit'
 
// Load environment variables
dotenv.config()
 
// Initialize Upstash Redis
export const redis = new Redis({
 url: process.env.UPSTASH_REDIS_REST_URL,
 token: process.env.UPSTASH_REDIS_REST_TOKEN,
})
 
// Initialize Upstash Rate Limiter
export const ratelimit = {
 chat: new Ratelimit({
 redis,
 // Limit requests to 30 questions per day per IP Address
 limiter: Ratelimit.slidingWindow(30, '86400s'),
 }),
}

রেট লিমিটিং ব্যবহার করে, আমি পরিষেবা ব্যবহার করতে সক্ষম ছিলাম - সম্পূর্ণ বিনামূল্যে এবং সর্বজনীন! এটি আমাকে সিস্টেমের সুবিধাগুলি যেমন চ্যাট প্রতিক্রিয়াগুলি প্রদর্শন করার অনুমতি দিয়েছে৷ আক্ষরিক অর্থে যে কেউ ওয়েবসাইটের মাধ্যমে দিনে 30টি প্রশ্ন করতে পারে। আমরা IP address এর উপর ভিত্তি করে দিনে 30টি প্রশ্নের রেট সীমা বলবৎ করতে সক্ষম চাবি হিসাবে।

// File: pages/api/chat.js
 
import requestIp from 'request-ip'
import { ratelimit } from '@/lib/redis'
 
// ...
 
// Get the client IP
const detectedIp = requestIp.getClientIp(req)
 
// If no IP detected, return with a `Bad Request`
if (!detectedIp) return res.status(400).send('Bad request.')
 
// Check the Rate Limit
const result = await ratelimit.chat.limit(detectedIp)
 
// If rate limited, return with the same
if (!result.success) return res.status(400).send('Rate limit exceeded.')
 
// Continue with serving the chat responses

4. সংরক্ষিত ইনডেক্সড ভেক্টর স্টোর লোড করুন এবং প্রতিক্রিয়াগুলির জন্য OpenAI কে জিজ্ঞাসা করুন

সমস্ত চেক সম্পন্ন করে, আমরা এখন মূল কাজের দিকে যাচ্ছি - আমাদের কাস্টম সামগ্রী সহ OpenAI API কল করা এবং ব্যবহারকারীকে প্রতিক্রিয়া পাঠানো। জিনিসগুলিকে সহজ করার জন্য, আমরা এটিকে আরও ভাগে ভাগ করব:

  • 3.1:সংরক্ষিত ভেক্টর স্টোর পুনরুদ্ধার করা হচ্ছে
// File: pages/api/chat.js
 
// Reference Function to loadVectorStore
import { loadVectorStore } from '@/lib/vectorStore'
 
// Load the trained model
const vectorStore = await loadVectorStore()
 
// ...
 
// Vectore Store Function
// File: lib/vectorStore.js
 
import { join } from 'path'
import { existsSync } from 'fs'
import { Document } from 'langchain/document'
import { FaissStore } from 'langchain/vectorstores/faiss'
import { OpenAIEmbeddings } from 'langchain/embeddings/openai'
 
export async function loadVectorStore() {
 const directory = join(process.cwd(), 'loadedVectorStore')
 const docStoreJSON = join(process.cwd(), 'loadedVectorStore', 'docstore.json')
 if (existsSync(docStoreJSON)) {
 // If the directory is found, load the vector store saved by Faiss integration
 return await FaissStore.load(directory, new OpenAIEmbeddings())
 } else {
 // If no content is there, load the vector store with just `Hey` for starters
 return await FaissStore.fromDocuments([new Document({ pageContent: 'Hey' })], new OpenAIEmbeddings())
 }
}
  • 3.2:ব্যবহারকারীর প্রশ্নে প্রম্পট নির্দেশিকা যোগ করা হচ্ছে

ল্যাংচেইন দ্বারা প্রম্পট টেমপ্লেট ব্যবহার করে, ব্যবহারকারীর প্রশ্নের সাথে আমরা কীভাবে এবং কোন পদ্ধতিতে এআই প্রশ্নের উত্তর দেবে তার নির্দেশাবলী পাস করি:

// File: pages/api/chat.js
 
import { z } from 'zod'
import { PromptTemplate } from 'langchain/prompts'
import { RetrievalQAChain } from 'langchain/chains'
import { OutputFixingParser, StructuredOutputParser } from 'langchain/output_parsers'
 
// Load the trained model
// ...
 
// Create a prompt specifying for OpenAI what to write
const outputParser = StructuredOutputParser.fromZodSchema(
 z.object({
 answer: z.string().describe('answer to question in HTML friendly format, use all of the tags wherever possible and including reference links'),
 }),
)
 
// ...
 
// Create an instance of output parser class to help refine the response of OpenAI
const outputFixingParser = OutputFixingParser.fromLLM(model, outputParser)
 
// Create a prompt specifying for OpenAI how to process on the input
const prompt = new PromptTemplate({
 template: `Answer the user's question as best and be as detailed as possible:\n{format_instructions}\n{query}`,
 inputVariables: ['query'],
 partialVariables: {
 format_instructions: outputFixingParser.getFormatInstructions(),
 },
})
 
// Pass the prompt to the query with the model to OpenAI API
const chain = RetrievalQAChain.fromLLM(model, vectorStore.asRetriever(), prompt)
  • 3.3:স্ট্রিম এবং ক্যাশে প্রতিক্রিয়া

Upstash Redis এর সাথে প্রতিক্রিয়া ক্যাশে করতে, আমরা UpstashRedisCache ব্যবহার করব ল্যাংচেইন দ্বারা ক্যাশে লাইব্রেরি। আমরা ক্লায়েন্ট হিসাবে বিদ্যমান Redis ইনস্ট্যান্সটি পাস করি এবং ক্যাশিং হ্যান্ডলারকে ChatOpenAI-এ পাস করি প্রতিক্রিয়াগুলি বিতরণ করার পরে এটি ক্যাশে ব্যবহার করার জন্য মোড়ক:

// File: pages/api/chat.js
 
import { redis } from '@/lib/redis'
import { ChatOpenAI } from 'langchain/chat_models/openai'
import { UpstashRedisCache } from 'langchain/cache/upstash_redis'
 
// Load the trained model
// ...
 
// Create Upstash caching
const upstashRedisCache = new UpstashRedisCache({ client: redis })
 
// A flag to detect if response was not cached
let doesToken = false
 
const model = new ChatOpenAI({
 // Enable streaming to return responses to user as quickly possible
 streaming: true,
 // Cache responses using Upstash Redis cache client
 cache: upstashRedisCache,
 callbacks: [
 {
 handleLLMNewToken(token) {
 // Set the flag to true if we receive stream from OpenAI
 doesToken = true
 // Stream the token to the user
 res.write(token)
 },
 },
 ],
})
 
// Create a LLM QA Chain
// ...
 
// Store the output to refer to in case cached
const chainOutput = await chain.call({ query: req.body.input })
 
// If no tokens received implies that the content is cached
// Return the cached response as is
if (!doesToken) return res.status(200).send(chainOutput.text)

যে অনেক শেখার ছিল! আপনি এখন সব শেষ।

Fly.io এ স্থাপন করুন

রিপোজিটরিটি Fly.io-এর জন্য একটি বেকড-ইন সেটআপের সাথে আসে, বিশেষভাবে এর সাথে সম্পর্কিত:

  • ডকারফাইল
  • fly.toml
  • .dockerignore

স্থাপনার জন্য Fly.io-এ একটি অ্যাকাউন্ট প্রয়োজন৷ একবার আপনার একটি অ্যাকাউন্ট হয়ে গেলে, আপনি আপনার প্রকল্পের রুট ফোল্ডারে নিম্নলিখিত কমান্ডটি চালিয়ে Fly.io-তে একটি অ্যাপ তৈরি করতে পারেন:

# Create an app based on the baked-in configuration in your account
# This will result only in the change of app name in existing fly.toml
fly launch

এবং 👇🏻

এর মাধ্যমে স্থাপন করুন
# Deploy the app based on the configuration created above
fly deploy

এখন আমরা স্থাপনা সম্পন্ন! হ্যাঁ, এটাই ছিল।

উপসংহার

উপসংহারে, এই প্রকল্পটি ওপেনএআই রেসপন্স ক্যাশিং, রেট লিমিটিং, এবং মডেলকে প্রশিক্ষিত করার জন্য নির্ধারিত এপিআই অনুরোধ বাস্তবায়নে মূল্যবান অভিজ্ঞতা প্রদান করেছে, যখন আপনার প্রয়োজন অনুযায়ী পরিমাপ করে এমন একটি পরিষেবা ব্যবহার করে, যেমন আপস্ট্যাশ।

Next.js , Redis , TailwindCSS , LangChain , Serverless Scheduling


  1. সি++ এ বাইনারি ট্রিতে সিউডো-প্যালিন্ড্রোমিক পাথ

  2. C++ এ পিরামিডের আয়তনের জন্য প্রোগ্রাম

  3. জাভাস্ক্রিপ্ট যখন আমি একটি ক্লাসে একটি বোতামে ক্লিক করি তখন কীভাবে একটি সতর্কতা প্রদর্শিত হবে?

  4. লিনাক্সে মাইএসকিউএল, পিএইচপি, এবং অ্যাপাচি কনফিগারেশন ফাইলগুলি সনাক্ত করা - একটি ব্যবহারিক গাইড