Computer >> कंप्यूटर ट्यूटोरियल >  >> प्रोग्रामिंग >> Redis

लैंगचेन, फैस और नेक्स्ट.जेएस के साथ एक कस्टम एआई चैटबॉट बनाएं - एक व्यावहारिक गाइड

<पी> इस पोस्ट में, मैं इस बारे में बात करता हूं कि कैसे मैंने अपस्टैश, नेक्स्ट.जेएस, लैंगचेन और फ्लाई.आईओ के साथ एक ओपन-सोर्स कस्टम कंटेंट एआई चैटबॉट बनाया। अपस्टैश ने मुझे मॉडल प्रशिक्षण शेड्यूल करने में मदद की, उदार दर सीमित करने और ओपनएआई एपीआई प्रतिक्रियाओं को कैशिंग करने का तरीका पेश किया। <पी> लैंगचेन, फैस और नेक्स्ट.जेएस के साथ एक कस्टम एआई चैटबॉट बनाएं - एक व्यावहारिक गाइड

हम क्या उपयोग करेंगे

  • Next.js (फ्रंट-एंड और बैक-एंड)
  • LangChain (भाषा मॉडल द्वारा संचालित अनुप्रयोगों के विकास के लिए रूपरेखा)
  • अपस्टैश (QStash के माध्यम से प्रशिक्षण मॉडल शेड्यूल करना, दर सीमित करना और OpenAI प्रतिक्रियाओं को कैश करना)
  • टेलविंड सीएसएस (स्टाइलिंग)
  • Fly.io (तैनाती)

आपको क्या चाहिए

  • Node.js 18
  • एक अपस्टैश खाता
  • एक OpenAI खाता (OpenAI API कुंजी के लिए)

अपस्टैश रेडिस की स्थापना

<पी> एक बार जब आप एक अपस्टैश खाता बना लेते हैं और लॉग इन हो जाते हैं तो आप रेडिस टैब पर जाएंगे और एक डेटाबेस बनाएंगे।

<पी> लैंगचेन, फैस और नेक्स्ट.जेएस के साथ एक कस्टम एआई चैटबॉट बनाएं - एक व्यावहारिक गाइड

<पी> लैंगचेन, फैस और नेक्स्ट.जेएस के साथ एक कस्टम एआई चैटबॉट बनाएं - एक व्यावहारिक गाइड

<पी> अपना डेटाबेस बनाने के बाद, आप विवरण टैब पर जा रहे हैं। जब तक आपको अपना डेटाबेस कनेक्ट करें अनुभाग नहीं मिल जाता तब तक नीचे स्क्रॉल करें। सामग्री को कॉपी करें और इसे किसी सुरक्षित स्थान पर सहेजें।

<पी> लैंगचेन, फैस और नेक्स्ट.जेएस के साथ एक कस्टम एआई चैटबॉट बनाएं - एक व्यावहारिक गाइड

<पी> इसके अलावा, तब तक नीचे स्क्रॉल करें जब तक आपको REST API अनुभाग न मिल जाए और .env बटन का चयन करें। सामग्री को कॉपी करें और इसे किसी सुरक्षित स्थान पर सहेजें।

<पी> लैंगचेन, फैस और नेक्स्ट.जेएस के साथ एक कस्टम एआई चैटबॉट बनाएं - एक व्यावहारिक गाइड

अपस्टैश QStash सेट करना

<पी> एक बार लॉग इन करने के बाद आप QStash टैब पर जाएंगे और QSTASH_URL प्राप्त करेंगे , QSTASH_TOKEN , QSTASH_CURRENT_SIGNING_KEY , और QSTASH_NEXT_SIGNING_KEY . सामग्री को कॉपी करें और इसे किसी सुरक्षित स्थान पर सहेजें।

<पी> लैंगचेन, फैस और नेक्स्ट.जेएस के साथ एक कस्टम एआई चैटबॉट बनाएं - एक व्यावहारिक गाइड

प्रोजेक्ट की स्थापना

<पी> सेट अप करने के लिए, बस ऐप रेपो को क्लोन करें और इसमें जो कुछ भी है उसे जानने के लिए इस ट्यूटोरियल का अनुसरण करें। प्रोजेक्ट को फोर्क करने के लिए, चलाएँ:

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

रिपॉजिटरी संरचना

<पी> यह प्रोजेक्ट के लिए मुख्य फ़ोल्डर संरचना है. मैंने उन फ़ाइलों को लाल रंग में चिह्नित किया है जिन पर इस पोस्ट में आगे चर्चा की जाएगी जो वेक्टर स्टोर को प्रबंधित करने, आपके कस्टम सामग्री पर प्रशिक्षित एआई के साथ चैट करने के लिए एपीआई रूट बनाने (प्रतिक्रियाओं को कैशिंग करने के साथ) और मॉडल प्रशिक्षण प्रक्रिया को शेड्यूल करने से संबंधित है।

<पी> लैंगचेन, फैस और नेक्स्ट.जेएस के साथ एक कस्टम एआई चैटबॉट बनाएं - एक व्यावहारिक गाइड

उच्च-स्तरीय डेटा प्रवाह और संचालन

<पी> यह एक उच्च स्तरीय आरेख है कि डेटा कैसे प्रवाहित हो रहा है और संचालन कैसे हो रहा है 👇🏻

<पी> लैंगचेन, फैस और नेक्स्ट.जेएस के साथ एक कस्टम एआई चैटबॉट बनाएं - एक व्यावहारिक गाइड

  • जब कोई उपयोगकर्ता चैटबॉट के माध्यम से कोई प्रश्न पूछता है, तो उपयोगकर्ता के आईपी को रेट लिमिटिंग के विरुद्ध जांचा जाता है, और एक प्रतिक्रिया, यदि अपस्टैश रेडिस के माध्यम से कैश नहीं की जाती है, तो OpenAI एपीआई (फिर कैश्ड) से मांगी जाती है और उपयोगकर्ता को स्ट्रीम की जाती है
  • जब कोई व्यवस्थापक दिए गए URL के सेट पर मौजूदा मॉडल के प्रशिक्षण का अनुरोध करता है, तो Upstash के QStash की मदद से दिए गए URL में सामग्री लाने और मॉडल को अपडेट करने के लिए दिए गए विलंब के बाद सर्वर रहित में एक POST अनुरोध किया जाता है (पृष्ठभूमि में)

नेक्स्ट.जेएस में चैट और ट्रेन एपीआई रूट सेटअप करें

<पी> इस अनुभाग में, हम इस बारे में बात करते हैं कि हमने मार्ग कैसे सेटअप किया है:pages/api/chat.js क्रॉस ओरिजिन अनुरोधों को सक्षम करने के लिए, उपयोगकर्ताओं के लिए चैट एपीआई कॉल, कैश और स्ट्रीम प्रतिक्रियाओं को सीमित करें और विशेष यूआरएल पर सामग्री प्रशिक्षण शेड्यूल करने के लिए एक विधि का खुलासा करें, और pages/api/train.js प्रशिक्षण केवल दिए गए URL पर, लेकिन पृष्ठभूमि में निष्पादित करने के लिए।

1. CORS सक्षम करें

<पी> cors का उपयोग करना पैकेज, हमने कई स्थानों पर चैटबॉट का उपयोग करने के लिए एप्लिकेशन में 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. दिए गए यूआरएल पर सामग्री प्रशिक्षण अनुरोध(अनुरोधों) को शेड्यूल करें

<पी> अपस्टैश क्यूस्टैश के साथ, कोई भी एपीआई बना सकता है जो आग लगाओ और भूल जाओ की तरह है। आपको प्रतिक्रिया प्राप्त करने के लिए मुख्य फ़ंक्शन के समाप्त होने तक सक्रिय रूप से प्रतीक्षा करने की आवश्यकता नहीं है, बल्कि इसे पृष्ठभूमि में करें (वैकल्पिक रूप से, कुछ देरी के बाद)। यह एक क्रॉन-जॉब की तरह है लेकिन यह प्रत्येक अनुरोध के अनुसार चलता है और नियमित अंतराल पर नहीं।

<पी> उसी चैट एपीआई रूट में, हम एक अनुरोध स्वीकार करते हैं जिसमें 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 पर कॉल करें फ़ंक्शन जो यूआरएल सामग्री लाने और मौजूदा वेक्टर स्टोर में जोड़ने (और इसे सहेजने) का कार्य करता है।
  • रेडिस लेनदेन के माध्यम से दर सीमित करने के कार्यान्वयन से संबंधित कुंजियों को फ़िल्टर करने के बाद अपस्टैश रेडिस में कैश्ड प्रतिक्रियाओं को साफ़ करें।

3. दर सीमित करना

<पी> रेट-लिमिटिंग को लागू करने के लिए, हम अपस्टैश रेडिस डेटाबेस क्लाइंट और @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 से पूछें

<पी> सभी जाँचों के बाद, अब हम मुख्य कार्य पर जा रहे हैं - अपनी कस्टम सामग्री के साथ ओपनएआई एपीआई को कॉल करना और उपयोगकर्ता को प्रतिक्रिया भेजना। चीजों को सरल बनाने के लिए, हम इसे आगे के भागों में तोड़ेंगे:

  • 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:स्ट्रीम और कैश प्रतिक्रियाएँ
<पी> अपस्टैश रेडिस के साथ प्रतिक्रियाओं को कैश करने के लिए, हम UpstashRedisCache का उपयोग करेंगे लैंगचेन द्वारा कैश लाइब्रेरी। हम मौजूदा रेडिस इंस्टेंस को क्लाइंट के रूप में पास करते हैं, और कैशिंग हैंडलर को 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,4) - डेटा संरचना में पेड़ स्तर से जुड़े (2,4) - डेटा संरचना में पेड़

    इस खंड में हम बताते हैं कि कैसे (2,4) -पेड़ स्तरीय लिंक की शुरूआत द्वारा कुशल उंगली खोजों का समर्थन कर सकते हैं। इस खंड में बताए गए विचार ऊंचाई-संतुलित पेड़ों के अधिक सामान्य वर्ग के लिए भी लागू होते हैं, जिन्हें (ए, बी) -ट्री, बी ≥ 2 ए के लिए दर्शाया गया है। ए (2,4) -ट्री को ऊंचाई-संतुलित खोज पेड़

  1. मास्टर स्ट्रॉन्ग पासवर्ड:खातों को सुरक्षित करने के लिए एक सिद्ध मार्गदर्शिका मास्टर स्ट्रॉन्ग पासवर्ड:खातों को सुरक्षित करने के लिए एक सिद्ध मार्गदर्शिका

    रमेश नटराजन द्वारा 8 जून 2008 को   अपने पासवर्ड को अपने टूथब्रश की तरह समझें। किसी और को इसका उपयोग न करने दें, और हर छह महीने में एक नया प्राप्त करें - क्लिफोर्ड स्टोल   जब आप किसी वेबसाइट पर खाता बनाते हैं, तो आपको एक सेकंड के लिए पासवर्ड दुविधा का सामना करना पड़ सकता है। दुविधा यह है कि

  1. Matplotlib में लाइन ग्राफ के लिए डेटा इंडेक्स के साथ लाइन रंग कैसे भिन्न करें? Matplotlib में लाइन ग्राफ के लिए डेटा इंडेक्स के साथ लाइन रंग कैसे भिन्न करें?

    Matplotlib में लाइन ग्राफ़ के डेटा इंडेक्स के साथ लाइन का रंग अलग-अलग होने के लिए, हम निम्नलिखित कदम उठा सकते हैं - कदम फिगर साइज सेट करें और सबप्लॉट्स के बीच और आसपास पैडिंग को एडजस्ट करें। numpy का उपयोग करके x और y डेटा पॉइंट बनाएं। छोटी सीमा प्राप्त करें, dydx । अंक प्राप्त करें और स