<पी> इस ब्लॉग पोस्ट के लिए, हम आगे बढ़ने से पहले कुछ धारणाएँ बनाएंगे, लेकिन आदर्श रूप से आपके पास यह होना चाहिए: - एक अपस्टैश खाता जहां आपने Redis और QStash इंस्टेंस बनाया है
- आपकी API कुंजी तक पहुंच वाला एक OpenAI खाता
- एक Next.js प्रोजेक्ट जहां हम स्टोरी जेनरेटर कार्यक्षमता बनाएंगे
- आपके प्रोजेक्ट को तैनात करने के लिए एक वर्सेल खाता
परिचय
<पी> क्या आपने कभी एआई का उपयोग करके अपनी खुद की कहानियां तैयार करना चाहा है? ओपनएआई की पूर्णता एपीआई और अपस्टैश के क्यूस्टैश और रेडिस के साथ, प्राकृतिक भाषा प्रसंस्करण का उपयोग करके अपनी खुद की कस्टम कहानियां बनाना अब पहले से कहीं अधिक आसान हो गया है। इस ट्यूटोरियल में, हम अनूठी और आकर्षक कहानियां तैयार करने के लिए इन टूल को स्थापित करने और उनका उपयोग करने की प्रक्रिया से गुजरेंगे। <पी>
<पी> ऐप की और छवियां देखें: - स्टोरी फॉर्म बनाएं
- स्टोरी स्टेट जनरेट करना
- उत्पन्न कहानी प्रदर्शित
वास्तुकला
<पी> कोड को देखने से आपको इस बात की अच्छी समझ हो जाएगी कि ऐप कैसे सेटअप किया गया है, लेकिन उच्च स्तरीय अवलोकन के लिए, नीचे दी गई छवि में एप्लिकेशन प्रवाह के कुछ हिस्सों को दिखाया गया है और वे कैसे संचार करते हैं। <पी>
प्रोजेक्ट सेटअप
<पी> सबसे पहले हम एक Next.js प्रोजेक्ट बनाना चाहेंगे। टाइपस्क्रिप्ट के साथ एक नया नेक्स्ट.जेएस प्रोजेक्ट बनाने के लिए निम्नलिखित को चलाकर ऐसा किया जा सकता है। आप Next.js को सेटअप करने के चरण यहां पा सकते हैं। <पी> इस ट्यूटोरियल के लिए, हमारे पास टेलविंड सीएसएस (फॉर्म और टाइपोग्राफी भी) स्थापित है, लेकिन यह पूरी तरह से वैकल्पिक है और केवल फ्रंटएंड फॉर्म स्टाइलिंग के लिए है। <पी> आगे हम निम्नलिखित के माध्यम से अपस्टैश की QStash और Redis लाइब्रेरी स्थापित करना चाहेंगे: npm install @upstash/qstash
npm install @upstash/redis
<पी> अब आप एक .env.local बनाना चाहेंगे फ़ाइल करें और इसे निम्नलिखित कुंजियों (और प्रासंगिक स्थानों से मान) से भरें। SITE_URL=https://your-project-url.vercel.app
OPENAI_API_KEY=
QSTASH_TOKEN=
UPSTASH_REDIS_REST_URL=
UPSTASH_REDIS_REST_TOKEN=
<पी> एक बार जब आप एक प्रोजेक्ट बना लेते हैं और एक बेसिक Next.js प्रोजेक्ट तैनात कर लेते हैं, तो आप अपने QStash और Redis टोकन को अपस्टैश कंसोल में, OpenAI API कुंजी यहां और अपनी साइट का URL अपने वर्सेल डैशबोर्ड में पा सकते हैं। फ्रंटएंड सेटअप
<पी> आगे हम स्टोरी प्रॉम्प्ट इनपुट करने के लिए पेज और फॉर्म बनाएंगे। आपको प्रॉम्प्ट के लिए एक टेक्स्ट फ़ील्ड और एक सबमिट बटन की आवश्यकता होगी। कहानी निर्माण
<पी> फ़ाइल:pages/index.tsx पी> import { RefObject, useRef, useState } from "react";
import Head from "next/head";
import useInterval from "../hooks/useInterval";
export default function Home() {
const [generating, setGenerating] = useState<boolean>(false);
const [messageId, setMessageId] = useState<string | null>(null);
const [story, setStory] = useState<string[]>([]);
const themeRef: RefObject<HTMLInputElement> = useRef(null);
const characterRef: RefObject<HTMLInputElement> = useRef(null);
const moralRef: RefObject<HTMLInputElement> = useRef(null);
useInterval(
async () => {
await fetch(`/api/poll?id=${messageId}`)
.then((res: any) => res.json())
.then((data: any) => {
if (!data.choices) {
return;
}
setGenerating(false);
setMessageId(null);
setStory(data.choices[0].text.split("\n\n"));
})
.catch((err: any) => console.error(err));
},
messageId ? 1000 : null,
);
async function generateStory(event: any) {
event.preventDefault();
setGenerating(true);
await fetch("/api/create", {
method: "POST",
body: JSON.stringify({
theme: themeRef.current?.value,
character: characterRef.current?.value,
moral: moralRef.current?.value,
}),
headers: { "Content-Type": "application/json" },
})
.then((res: any) => res.json())
.then((data: any) => setMessageId(data.id))
.catch((err: any) => console.error(err));
}
return (
<>
<Head>
<title>StoryTime</title>
<meta
name="description"
content="A simple Next.js application which allows you to create stories using AI."
/>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="icon" href="/favicon.ico" />
</Head>
<main>
<div className="my-16 flex flex-col items-center justify-center md:my-32">
<h1 className="text-5xl font-black">StoryTime</h1>
{story.length > 0 && (
<div className="mx-auto mt-10 max-w-3xl">
<div className="prose lg:prose-xl w-full">
{story.map((paragraph: string, index: number) => (
<p key={index}>{paragraph}</p>
))}
</div>
<div className="text-center">
<button
type="button"
onClick={() => setStory([])}
className="mt-6 inline-flex items-center rounded-full border border-transparent bg-gray-900 px-6 py-2.5 text-sm font-medium text-white shadow-sm hover:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-gray-600 focus:ring-offset-2"
>
Start Over
</button>
</div>
</div>
)}
{story.length == 0 && (
<form
onSubmit={generateStory}
className="mt-10 flex w-full max-w-lg flex-col items-center"
>
<div className="w-full space-y-4">
<div>
<label htmlFor="theme" className="text-sm font-semibold">
My story is about
</label>
<input
name="theme"
id="theme"
type="text"
className="mt-0.5 block w-full rounded-md border-gray-300 shadow-sm focus:border-gray-500 focus:ring-gray-500"
placeholder="two friends going on an adventure"
ref={themeRef}
required
/>
</div>
<div>
<label htmlFor="character" className="text-sm font-semibold">
My main character is
</label>
<input
name="character"
id="character"
type="text"
className="mt-0.5 block w-full rounded-md border-gray-300 shadow-sm focus:border-gray-500 focus:ring-gray-500"
placeholder="a dog named Spot"
ref={characterRef}
required
/>
</div>
<div>
<label htmlFor="moral" className="text-sm font-semibold">
The moral of my story is
</label>
<input
name="moral"
id="moral"
type="text"
className="mt-0.5 block w-full rounded-md border-gray-300 shadow-sm focus:border-gray-500 focus:ring-gray-500"
placeholder="to always be kind"
ref={moralRef}
required
/>
</div>
</div>
<button
type="submit"
disabled={generating}
className="mt-6 inline-flex items-center rounded-full border border-transparent bg-gray-900 px-6 py-2.5 text-sm font-medium text-white shadow-sm hover:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-gray-600 focus:ring-offset-2 disabled:opacity-50"
>
{generating ? "Generating..." : "Generate"}
</button>
</form>
)}
</div>
</main>
</>
);
}
<पी> यह फ़ाइल एक रिएक्ट घटक को परिभाषित करती है जो एक ऐसा फॉर्म प्रदर्शित करती है जो उपयोगकर्ताओं को एक कहानी के लिए विषय, चरित्र और नैतिक इनपुट करने की अनुमति देती है। जब फॉर्म सबमिट किया जाता है, तो यह एक पोस्ट भेजता है /api/create से अनुरोध करें मुख्य भाग के रूप में इनपुट किए गए विषय, चरित्र और नैतिक मूल्यों के साथ समापन बिंदु। <पी> घटक फिर एक मतदान स्थिति में प्रवेश करता है जहां यह एक GET भेजता है /api/poll से अनुरोध करें पिछले कहानी निर्माण अनुरोध में प्राप्त संदेश पहचानकर्ता के साथ हर सेकंड समापन बिंदु, जो हमें उस कहानी के लिए कहानी निर्माण अनुरोध को ट्रैक करने की अनुमति देता है जिसके लिए हम यह जांचने के लिए मतदान कर रहे हैं कि यह OpenAI द्वारा कब तैयार किया गया है। <पी> जब /api/poll से प्रतिक्रिया मिलती है एंडपॉइंट में एक विकल्प संपत्ति होती है, हम जानते हैं कि मतदान अनुरोध ने सफलतापूर्वक उत्पन्न कहानी लौटा दी है, इसलिए घटक मतदान बंद कर देता है और कहानी पाठ को पैराग्राफ में विभाजित करके और प्रत्येक पैराग्राफ को अलग से प्रस्तुत करके प्रदर्शित करता है। अंतराल हुक
<पी> फ़ाइल:hooks/useInterval.ts पी> import { useEffect, useRef } from "react";
function useInterval(callback: () => void, delay: number | null) {
const savedCallback = useRef(callback);
useEffect(() => {
savedCallback.current = callback;
}, [callback]);
useEffect(() => {
if (!delay && delay !== 0) {
return;
}
const id = setInterval(() => savedCallback.current(), delay);
return () => clearInterval(id);
}, [delay]);
}
export default useInterval;
<पी> useInterval हुक useEffect का उपयोग करता है और useRef अंतराल और कॉलबैक फ़ंक्शन को प्रबंधित करने के लिए हुक जो रिएक्ट घटक जीवनचक्र के साथ निर्बाध रूप से काम करता है, साथ ही रिएक्ट घटक के भीतर अंतराल और कॉलबैक को प्रबंधित करने का एक सुविधाजनक तरीका प्रदान करता है, प्रदर्शन को अनुकूलित करता है और कोडबेस को थोड़ा अधिक रखरखाव योग्य बनाता है। आप इस हुक पर अधिक जानकारी यहां और यहां पा सकते हैं। एपीआई सेटअप
<पी> सबसे पहले हम कॉलबैक बनाएंगे, पोल करेंगे और फ़ाइलें बनाएंगे, साथ ही रेडिस और क्यूस्टैश लाइब्रेरी का उपयोग भी करेंगे। कहानी निर्माण
<पी> फ़ाइल:pages/api/create.ts पी> import type { NextApiRequest, NextApiResponse } from "next";
import qstashClient from "../../lib/qstash";
export default async function handler(
req: NextApiRequest,
res: NextApiResponse,
) {
if (req.method !== "POST") {
return res.status(400).json({
message: `Invalid request method: ${req.method}.`,
});
}
const { theme, character, moral }: any = req.body;
qstashClient
.publishJSON({
url: "https://api.openai.com/v1/completions",
method: "POST",
headers: {
Authorization: `Bearer ${process.env.QSTASH_TOKEN}`,
"Content-Type": "application/json",
"Upstash-Callback": `${process.env.SITE_URL}/api/callback`,
"Upstash-Forward-Authorization": `Bearer ${process.env.OPENAI_API_KEY}`,
},
body: {
model: "text-davinci-003",
prompt: `Write a children's story about ${theme}, which has a main character who is ${character} with the moral of the story being ${moral}.`,
max_tokens: 500,
temperature: 0.75,
},
})
.then((data: any) => {
return res.status(202).json({ id: data.messageId });
})
.catch((error: any) => {
return res.status(500).json({ message: error.message });
});
}
<पी> हम पहले जाँचते हैं कि अनुरोध विधि POST है , और यदि ऐसा नहीं है तो 400 के स्टेटस कोड (क्लाइंट त्रुटि का संकेत) के साथ एक प्रतिक्रिया भेजता है। फिर हम अनुरोध के मुख्य भाग से विषय, चरित्र और नैतिक क्षेत्रों को नष्ट करने के लिए आगे बढ़ते हैं। <पी> आगे हम publishJSON पर कॉल करते हैं qstashClient पर विधि ऑब्जेक्ट, जो एक POST भेजता है JSON बॉडी के साथ OpenAI API से अनुरोध करें जिसमें विषय, चरित्र और नैतिकता के मूल्यों के आधार पर बच्चों की कहानी तैयार करने का संकेत हो। यह कई हेडर भी सेट करता है, जिसमें QSTASH_TOKEN में संग्रहीत टोकन के साथ एक प्राधिकरण हेडर भी शामिल है। पर्यावरण चर, और OPENAI_API_KEY से गुजरने के लिए एक अग्रेषित प्राधिकरण शीर्षलेख जिसका उपयोग OpenAI API अनुरोध के साथ किया जाएगा। <पी> यदि publishJSON तो हम अनुरोध की संदेश आईडी लौटा देते हैं कॉल सफल है, जिसका उपयोग मतदान के लिए यह जांचने के लिए किया जाएगा कि अनुरोध कब समाप्त हुआ। यदि कोई त्रुटि होती है, तो यह 500 के स्टेटस कोड (आंतरिक सर्वर त्रुटि का संकेत) और संबंधित त्रुटि संदेश के साथ एक प्रतिक्रिया भेजता है। कॉलबैक
<पी> फ़ाइल:pages/api/callback.ts पी> import type { NextApiRequest, NextApiResponse } from "next";
import redis from "../../lib/redis";
export default async function handler(
req: NextApiRequest,
res: NextApiResponse,
) {
const { body }: any = req;
try {
const decoded = Buffer.from(body.body, "base64").toString("utf-8");
await redis.set(body.sourceMessageId, decoded);
return res.status(200).send(decoded);
} catch (error) {
return res.status(500).json({ error });
}
}
<पी> सबसे पहले, हम पहले आने वाले अनुरोध के मुख्य भाग को डिकोड करने का प्रयास करते हैं, जो एक बेस 64-एनकोडेड स्ट्रिंग होगी, और यदि सफल होता है, तो यह रेडिस में डिकोड की गई स्ट्रिंग को उसी कुंजी के तहत संग्रहीत करता है, जो तब लौटाई गई थी जब हमने QStash को प्रारंभिक अनुरोध भेजा था। <पी> अंत में, हम 200 के स्टेटस कोड (सफलता का संकेत) के साथ-साथ डिकोडेड स्ट्रिंग के साथ एक प्रतिक्रिया भेजते हैं। यदि कोई त्रुटि होती है, तो हम 500 के स्टेटस कोड (आंतरिक सर्वर त्रुटि का संकेत) और त्रुटि संदेश के साथ एक प्रतिक्रिया लौटाएंगे। मतदान
<पी> फ़ाइल:pages/api/poll.ts पी> import type { NextApiRequest, NextApiResponse } from "next";
import redis from "../../lib/redis";
export default async function handler(
req: NextApiRequest,
res: NextApiResponse,
) {
const { id }: any = req.query;
try {
const data = await redis.get(id);
if (!data) {
return res
.status(404)
.json({ message: "Data for supplied ID not found" });
}
return res.status(200).json(data);
} catch (error: any) {
return res.status(500).json({ message: error.message });
}
}
<पी> सबसे पहले, हम id को नष्ट करते हैं अनुरोध के क्वेरी ऑब्जेक्ट से। फिर हम डिस्ट्रक्चर्ड id के तहत रेडिस में संग्रहीत डेटा को पुनः प्राप्त करने का प्रयास करते हैं और यदि कोई डेटा नहीं मिलता है, तो यह 404 के स्टेटस कोड के साथ एक प्रतिक्रिया भेजता है (यह दर्शाता है कि अनुरोधित संसाधन नहीं मिल सका) और ऐसा बताते हुए एक संदेश भेजता है। <पी> यदि डेटा दी गई कुंजी से संबंधित पाया जाता है, तो यह 200 के स्टेटस कोड (सफलता का संकेत) के साथ एक प्रतिक्रिया भेजता है, और इसके साथ पाया गया डेटा भी भेजता है। यदि कोई त्रुटि होती है, तो हम 500 के स्टेटस कोड (आंतरिक सर्वर त्रुटि का संकेत) और संबंधित त्रुटि संदेश के साथ एक प्रतिक्रिया लौटाते हैं। Libs
<पी> आगे, हम QStash और Redis क्लाइंट बनाने के लिए दो फ़ाइलें बनाएंगे, जिनका उपयोग कहानी निर्माण प्रक्रिया में किया जाता है। दोनों फ़ाइलें एक ऑब्जेक्ट को निर्यात करती हैं जिसका उपयोग संबंधित बाहरी सेवा के साथ इंटरैक्ट करने के लिए किया जाता है। <पी> फ़ाइल:lib/qstash.ts पी> import { Client } from "@upstash/qstash";
const qstashClient = new Client({
token: process.env.QSTASH_TOKEN as string,
});
export default qstashClient;
<पी> QStash क्लाइंट को QSTASH_TOKEN में संग्रहीत टोकन के साथ प्रारंभ किया गया है पर्यावरण चर. इस ऑब्जेक्ट का उपयोग अपस्टैश QStash सेवा को HTTP अनुरोध भेजने के लिए किया जा सकता है। <पी> फ़ाइल:lib/redis.ts पी> import { Redis } from "@upstash/redis";
const redis = new Redis({
url: process.env.UPSTASH_REDIS_REST_URL as string,
token: process.env.UPSTASH_REDIS_REST_TOKEN as string,
});
export default redis;
<पी> रेडिस क्लाइंट को UPSTASH_REDIS_REST_URL में संग्रहीत एक यूआरएल और टोकन के साथ प्रारंभ किया गया है और UPSTASH_REDIS_REST_TOKEN पर्यावरण चर, क्रमशः। इस ऑब्जेक्ट का उपयोग अपस्टैश रेडिस रेस्ट एपीआई के माध्यम से रेडिस डेटाबेस में डेटा को संग्रहीत और पुनर्प्राप्त करने के लिए किया जा सकता है। निष्कर्ष
<पी> ओपनएआई की पूर्णता एपीआई के साथ-साथ अपस्टैश के क्यूस्टैश और रेडिस के साथ, प्राकृतिक भाषा प्रसंस्करण का उपयोग करके कस्टम कहानियां उत्पन्न करना आसान है। इस ट्यूटोरियल का अनुसरण करके, अब आप इन उपकरणों का उपयोग करके कहानियां तैयार करने के लिए अपना स्वयं का सिस्टम स्थापित करने में सक्षम होंगे, और इसमें अपने स्वयं के परिवर्तन और सुधार कर सकेंगे। <पी> आप यहां संपूर्ण स्रोत कोड देख सकते हैं। आगे सुधार
<पी> शुरुआत के रूप में इस कहानी जनरेटर का उपयोग करके आप आगे क्या कर सकते हैं, इसके बारे में नीचे कुछ विचार दिए गए हैं: - फ्रंटएंड स्टाइल को अधिक आकर्षक और रंगीन बनाने के लिए अपडेट करें
- किसी दिए गए संकेत के आधार पर कहानियों में OpenAI का उपयोग करके Dall-E छवि निर्माण जोड़ें
- एक एपीआई के माध्यम से आउटपुट को पुस्तक मुद्रण सेवा से कनेक्ट करें, ताकि उपयोगकर्ता भौतिक पुस्तकें ऑर्डर कर सकें
<पी> इसमें बहुत सारी संभावनाएँ और दिशाएँ हैं जिन्हें आप अपना सकते हैं, इसलिए आनंद लें और इस प्रक्रिया का आनंद लें। आप अब तक के कार्य को अन्य परियोजनाओं के लिए आधार के रूप में भी उपयोग कर सकते हैं जो OpenAI, QStash और Redis का उपयोग कर सकते हैं।