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

रेप्लिकेट, नेक्स्ट.जेएस और अपस्टैश का उपयोग करके एक फोटो रेस्टोरेशन ऐप विकसित करें

<पी> इस ब्लॉग पोस्ट के लिए, हम आगे बढ़ने से पहले कुछ धारणाएँ बनाएंगे, लेकिन आदर्श रूप से आपके पास यह होना चाहिए:

  • एक अपस्टैश खाता जहां आपने Redis इंस्टेंस बनाया है
  • आपके एपीआई टोकन तक पहुंच वाला एक रेप्लिकेट खाता
  • हमारी वांछित कार्यक्षमता को लागू करने के लिए एक Next.js प्रोजेक्ट
  • आपके प्रोजेक्ट को तैनात करने के लिए एक वर्सेल खाता

यह क्या है?

<पी> क्या आप रेप्लिकेट पर उपलब्ध मॉडलों से छवियां उत्पन्न करने के लिए मशीन लर्निंग का उपयोग शुरू करना चाहते हैं? खैर, इस ट्यूटोरियल में, हम रेप्लिकेट के होस्ट किए गए मॉडलों और अपस्टैश के रेडिस की विस्तृत श्रृंखला का पता लगाएंगे। हम न केवल इन मॉडलों का पता लगाएंगे, बल्कि हम एक को स्थापित करने की प्रक्रिया से गुजरेंगे, और इस बात पर भी चर्चा करेंगे कि आप अन्य मॉडलों का उपयोग करने के लिए कार्यान्वयन को आसानी से कैसे अपडेट कर सकते हैं।

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

<पी> रेप्लिकेट, नेक्स्ट.जेएस और अपस्टैश का उपयोग करके एक फोटो रेस्टोरेशन ऐप विकसित करें

वास्तुकला क्या है?

<पी> यदि आपके पास कुछ प्रतिक्रिया अनुभव है, तो आपको केवल कोडबेस को पढ़कर यह निर्धारित करने में सक्षम होना चाहिए कि ऐप आर्किटेक्चर कैसे काम करता है, लेकिन इसे थोड़ा आसान बनाने के लिए, या यदि आप केवल एक सिंहावलोकन देखना पसंद करते हैं, तो नीचे एक प्रदान किया गया है।

<पी> रेप्लिकेट, नेक्स्ट.जेएस और अपस्टैश का उपयोग करके एक फोटो रेस्टोरेशन ऐप विकसित करें

मुझे शुरुआत करने के लिए क्या चाहिए?

<पी> आरंभ करने के लिए, आपको निश्चित रूप से एक Next.js प्रोजेक्ट की आवश्यकता होगी। यह यहां Next.js सेटअप गाइड का पालन करके किया जा सकता है, या यदि आपके पास पहले से ही सेटअप है, तो वह भी ठीक है। इस ट्यूटोरियल में, हम टेलविंड सीएसएस का भी उपयोग कर रहे हैं, लेकिन आप निश्चित रूप से अपनी पसंद के किसी भी प्रकार के स्टाइलिंग सेटअप का उपयोग कर सकते हैं।

<पी> अब जबकि हमारे पास एक बुनियादी Next.js प्रोजेक्ट सेटअप है, हम अभी भी कमांड चलाकर अपस्टैश की रेडिस लाइब्रेरी का उपयोग कर सकते हैं:

npm install @upstash/redis
<पी> आगे, हम अपना .env.local भरना चाहेंगे निम्नलिखित कुंजियों के साथ फ़ाइल करें, जिनमें से रेडिस टोकन आपके अपस्टैश कंसोल में पाया जा सकता है, रेप्लिकेट एपीआई टोकन यहां आपके खाते के अंतर्गत पाया जा सकता है, और आपकी साइट का यूआरएल वहां होगा जहां आप इसे तैनात करेंगे, इसलिए इस मामले में यह वर्सेल परिनियोजन समापन बिंदु होगा।

SITE_URL=https://your-project-url.vercel.app
 
REPLICATE_API_TOKEN=
 
UPSTASH_REDIS_REST_URL=
UPSTASH_REDIS_REST_TOKEN=

फ्रंटएंड फॉर्म सेट करना

<पी> आरंभ करने के लिए, हमें एक ऐसे फॉर्म की आवश्यकता होगी जो फॉर्म, मतदान और पूर्ण छवियों को प्रदर्शित करने का प्रबंधन करता हो।

इमेज फॉर्म निर्माण को पुनर्स्थापित करें

<पी> फ़ाइल:pages/index.tsx
import { MouseEvent, RefObject, useRef, useState } from "react";
import Head from "next/head";
 
import useInterval from "../hooks/useInterval";
 
export default function Home() {
 const [restoring, setRestoring] = useState<boolean>(false);
 const [messageId, setMessageId] = useState<string | null>(null);
 const [prediction, setPrediction] = useState<any>({});
 const [outputImageUrl, setOutputImageUrl] = useState<string | null>(null);
 const imageUrlRef: RefObject<HTMLInputElement> = useRef(null);
 const hrRef: RefObject<HTMLInputElement> = useRef(null);
 const scratchRef: RefObject<HTMLInputElement> = useRef(null);
 
 useInterval(
 async () => {
 await fetch(`/api/poll?id=${messageId}`)
 .then((res: any) => res.json())
 .then((data: any) => {
 if (!data.output) {
 return;
 }
 
 setRestoring(false);
 setMessageId(null);
 setOutputImageUrl(data.output);
 })
 .catch((err: any) => console.error(err));
 },
 messageId ? 1000 : null,
 );
 
 async function restoreImage(e: any) {
 e.preventDefault();
 
 setRestoring(true);
 
 await fetch("/api/create", {
 method: "POST",
 body: JSON.stringify({
 image_url: imageUrlRef.current?.value,
 is_hr: hrRef.current?.value,
 has_scratches: scratchRef.current?.value,
 }),
 headers: { "Content-Type": "application/json" },
 })
 .then((res: Response) => res.json())
 .then((data: any) => {
 setMessageId(data.data.id);
 setPrediction(data.data);
 })
 .catch((err: Error) => console.error(err));
 }
 
 async function cancel(e: MouseEvent<HTMLButtonElement>) {
 e.preventDefault();
 
 await fetch("/api/cancel", {
 method: "POST",
 headers: { "Content-Type": "application/json" },
 body: JSON.stringify({ cancel_url: prediction.urls.cancel }),
 })
 .then((res: Response) => res.json())
 .then((data: any) => {
 setMessageId(null);
 setPrediction({});
 setRestoring(false);
 })
 .catch((err: Error) => console.error(err));
 }
 
 return (
 <>
 <Head>
 <title>PhotoRescue</title>
 <meta
 name="description"
 content="A simple Next.js application that utilizes Replicate to restore old photos."
 />
 <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">PhotoRescue</h1>
 
 <p className="mt-4">Restore your old photos to their former glory.</p>
 
 {outputImageUrl && (
 <div className="flex flex-col items-center justify-center">
 <img
 src={outputImageUrl}
 alt="Restored Image"
 className="mt-8 h-auto w-72"
 />
 
 <button
 type="button"
 onClick={() => setOutputImageUrl(null)}
 className="mt-8 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"
 >
 Start Again
 </button>
 </div>
 )}
 
 {!outputImageUrl && (
 <form
 onSubmit={restoreImage}
 className="mt-10 flex w-full max-w-lg flex-col items-center"
 >
 <div className="w-full space-y-4">
 <div>
 <label htmlFor="image_url" className="text-sm font-semibold">
 Image URL
 </label>
 <input
 name="image_url"
 id="image_url"
 type="text"
 defaultValue="https://replicate.delivery/mgxm/b033ff07-1d2e-4768-a137-6c16b5ed4bed/d_1.png"
 placeholder="https://example.com/image.png"
 className="mt-0.5 block w-full rounded-md border border-gray-300 p-2 shadow-sm focus:border-gray-500 focus:ring-gray-500"
 ref={imageUrlRef}
 required
 />
 </div>
 <div className="max-w-lg space-y-4">
 <div className="relative flex items-start">
 <div className="flex h-5 items-center">
 <input
 name="is_hr"
 id="is_hr"
 type="checkbox"
 className="h-4 w-4 rounded border-gray-300 text-gray-900 focus:ring-gray-500"
 ref={hrRef}
 />
 </div>
 <div className="ml-3 text-sm">
 <label
 htmlFor="is_hr"
 className="font-medium text-gray-900"
 >
 Is High Resolution?
 </label>
 <p className="text-gray-500">
 Check this if the input image is a high resolution
 photo.
 </p>
 </div>
 </div>
 <div className="relative flex items-start">
 <div className="flex h-5 items-center">
 <input
 name="is_scratched"
 id="is_scratched"
 type="checkbox"
 className="h-4 w-4 rounded border-gray-300 text-gray-900 focus:ring-gray-500"
 ref={scratchRef}
 defaultChecked={true}
 />
 </div>
 <div className="ml-3 text-sm">
 <label
 htmlFor="is_scratched"
 className="font-medium text-gray-900"
 >
 Has Scratches?
 </label>
 <p className="text-gray-500">
 Check this if the input image has visible scratches over
 it.
 </p>
 </div>
 </div>
 </div>
 </div>
 
 <div className="mt-6 flex gap-2">
 <button
 type="submit"
 disabled={restoring}
 className="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"
 >
 {restoring ? "Restoring..." : "Restore"}
 </button>
 
 {restoring && prediction && (
 <button
 type="button"
 onClick={cancel}
 className="inline-flex items-center rounded-full border border-gray-900 bg-white px-6 py-2.5 text-sm font-medium text-gray-900 shadow-sm hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-gray-600 focus:ring-offset-2"
 >
 Cancel
 </button>
 )}
 </div>
 </form>
 )}
 </div>
 </main>
 </>
 );
}
<पी> डिफ़ॉल्ट रूप से, यह घटक एक फॉर्म प्रदर्शित करता है जो उपयोगकर्ता को उस छवि का छवि यूआरएल दर्ज करने की अनुमति देता है जिसे वे पुनर्स्थापित करना चाहते हैं, और इसके साथ जाने के लिए कुछ विकल्प जैसे कि क्या छवि उच्च रिज़ॉल्यूशन वाली है, या यदि छवि में खरोंच हैं जिन्हें हटाने की आवश्यकता है। एक बार जब उपयोगकर्ता यह जानकारी भर देता है, और फॉर्म सबमिट कर देता है, तो यह एक पोस्ट भेजता है /api/create के लिए अनुरोध करें फॉर्म डेटा के साथ।

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

<पी> जब मतदान चल रहा होता है, तो फॉर्म भविष्यवाणी को रद्द करने के विकल्प के साथ एक बटन प्रदर्शित करता है। एक बार दबाने पर, यह एक पोस्ट भेजता है /api/cancel के लिए अनुरोध करें cancel_url के साथ पूर्वानुमान डेटा से जो हमें प्रारंभिक निर्माण पर प्राप्त हुआ था।

<पी> मतदान कार्यान्वयन 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;

एपीआई सेटअप

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

छवि पूर्वानुमान निर्माण

<पी> फ़ाइल:pages/api/create.ts
import type { NextApiRequest, NextApiResponse } from "next";
 
import fetch, { Response } from "node-fetch";
 
import redis from "../../lib/redis";
 
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 { image_url, is_hr, has_scratches }: any = req.body;
 
 await fetch("https://api.replicate.com/v1/predictions", {
 method: "POST",
 headers: {
 Authorization: `Token ${process.env.REPLICATE_API_TOKEN}`,
 "Content-Type": "application/json",
 },
 body: JSON.stringify({
 version:
 "c75db81db6cbd809d93cc3b7e7a088a351a3349c9fa02b6d393e35e0d51ba799",
 input: {
 image: image_url,
 HR: is_hr,
 with_scratch: has_scratches,
 },
 webhook_completed: `${process.env.SITE_URL}/api/callback`,
 }),
 })
 .then((res: Response) => res.json())
 .then(async (data: any) => {
 await redis.set(data.id, data);
 
 return res.status(202).json({ data: data });
 })
 .catch((error: Error) => {
 return res.status(500).json({ message: error.message });
 });
}
<पी> हमारे क्रिएट एपीआई एंडपॉइंट के लिए, हम पहले यह सुनिश्चित करने के लिए एक सरल जांच करते हैं कि आने वाली अनुरोध विधि एक POST है अनुरोध करें, और यदि नहीं तो हम एक साधारण 400 प्रतिक्रिया लौटाएंगे। फिर हम एक पोस्ट भेजने के लिए आगे बढ़ते हैं हमारे रेप्लिकेट एपीआई टोकन के साथ रेप्लिकेट करने का अनुरोध। अनुरोध निकाय में दिए गए मॉडल version के लिए पैरामीटर शामिल हैं जो इंगित करता है कि हम किस मॉडल को अनुरोध भेज रहे हैं (यह उस मॉडल पर "एपीआई" टैब के अंतर्गत पाया जाता है जिसका आप उपयोग करना चाहते हैं)। हम फ्रंटएंड पर मौजूद फॉर्म के डेटा के साथ मॉडल से जुड़े मापदंडों से भी गुजरते हैं।

<पी> एक बार अनुरोध भेज दिए जाने के बाद, हम लौटाई गई भविष्यवाणी id का उपयोग करते हैं इसे रेडिस में संग्रहीत करने के लिए, और भविष्यवाणी डेटा को फ्रंटएंड पर लौटाएं ताकि रेडिस आइटम को मतदान करने में उपयोग किया जा सके जब तक कि इसमें पूर्ण भविष्यवाणी न हो जाए।

कॉलबैक

<पी> फ़ाइल: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 {
 await redis.set(body.id, body);
 
 return res.status(200).send(body);
 } catch (error) {
 return res.status(500).json({ error });
 }
}
<पी> कॉलबैक एंडपॉइंट वह है जो रेप्लिकेट एक पोस्ट भेजेगा हमें यह बताने के लिए अनुरोध करें कि दी गई भविष्यवाणी का प्रसंस्करण समाप्त हो गया है। जब हमें यह अनुरोध प्राप्त होता है, तो हम अनुरोध निकाय से पूर्वानुमान डेटा पुनर्प्राप्त करते हैं, और दिए गए रेडिस आइटम को पूर्ण पूर्वानुमान डेटा के साथ अपडेट करते हैं।

मतदान

<पी> फ़ाइल: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 निकालते हैं अनुरोध से और फिर उस पहचानकर्ता के तहत रेडिस में संग्रहीत डेटा को पुनः प्राप्त करने का प्रयास करें, और यदि कोई डेटा नहीं मिलता है, तो हम 404 प्रतिक्रिया लौटाते हैं, लेकिन यदि डेटा है, तो हम उक्त डेटा को 200 प्रतिक्रिया के हिस्से के रूप में लौटाते हैं।

रद्द करें

<पी> फ़ाइल:pages/api/cancel.tsx
import type { NextApiRequest, NextApiResponse } from "next";
 
import fetch, { Response } from "node-fetch";
 
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 { cancel_url }: any = req.body;
 
 await fetch(cancel_url, {
 method: "POST",
 headers: {
 Authorization: `Token ${process.env.REPLICATE_API_TOKEN}`,
 "Content-Type": "application/json",
 },
 })
 .then((res: Response) => res.json())
 .then((data: any) => {
 return res.status(202).json({ data: data });
 })
 .catch((error: Error) => {
 return res.status(500).json({ message: error.message });
 });
}
<पी> शुरू की गई भविष्यवाणियों को रद्द करने के लिए एपीआई समापन बिंदु काफी सीधा है। हम बस cancel_url निकालते हैं जो फ्रंटएंड से पारित होता है जो स्वयं उस भविष्यवाणी से आता है जो निर्माण अनुरोध सबमिट करते समय संग्रहीत किया गया था, और हम बस एक पोस्ट भेजते हैं हमारे रेप्लिकेट एपीआई टोकन के साथ, उस समापन बिंदु पर अनुरोध करें।

Libs

<पी> अपने काम के लिए, हम एक Redis क्लाइंट बनाएंगे जिसका उपयोग ट्रैकिंग में किया जाता है

<पी> फ़ाइल: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;
<पी> इस ऑब्जेक्ट का उपयोग एप्लिकेशन के भीतर मतदान के दौरान डेटा को संग्रहीत और पुनर्प्राप्त करने के लिए किया जाएगा, ताकि हमें पता चल सके कि रिप्लिकेट से वेबहुक कब पूरा हुआ।

निष्कर्ष

<पी> रेप्लिकेट में विभिन्न प्रकार के मॉडल उपलब्ध हैं जिनका उपयोग एपीआई के माध्यम से किया जा सकता है। वर्सेल और अपस्टैश के साथ, मशीन लर्निंग मॉडल का उपयोग करना और प्रयोग करने योग्य वेब अनुप्रयोगों को तैनात करना पहले से कहीं अधिक आसान है।

<पी> यदि आप संपूर्ण रिपॉजिटरी देखना चाहते हैं, तो आप इसे यहां एक्सेस कर सकते हैं।

आगे का विकास

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

<पी> आप यहां रेप्लिकेट के सभी उपलब्ध मॉडलों का पता लगा सकते हैं, और एक बार जब आपको वह मॉडल मिल जाए जिसके साथ आप प्रयोग करना चाहते हैं, तो आप उसके उपयोग को देखने के लिए "एपीआई" टैब पर क्लिक कर सकते हैं। यहां आपको पायथन, कर्ल, कॉग और डॉकर के लिए बटन भी मिलेंगे, जो आपको मॉडल का परीक्षण करने की अनुमति देते हैं, लेकिन यह यह जानने के लिए भी उपयोगी है कि कौन से पैरामीटर आवश्यक हैं, और उन्हें कैसे भेजा जाता है।


  1. एंटरप्राइज़ में HTML:इसका उपयोग कौन करता है और कंपनियां इसका लाभ कैसे उठाती हैं एंटरप्राइज़ में HTML:इसका उपयोग कौन करता है और कंपनियां इसका लाभ कैसे उठाती हैं

    HTML एक आवश्यक प्रोग्रामिंग भाषा है क्योंकि यह पेशेवरों और नौसिखियों दोनों को सरल वेब पेज बनाने में मदद करती है। HTML का उपयोग करने में कुशल एक वेब डेवलपर वर्डप्रेस पेज बना सकता है, SEO के लिए ऑप्टिमाइज़ कर सकता है और इसके उपयोग के संबंध में ब्लॉग भी लिख सकता है। HTML का ज्ञान उन लोगों के लिए भी आवश

  1. एचटीएमएल पृष्ठभूमि रंग एचटीएमएल पृष्ठभूमि रंग

    अनुभवी डेवलपर्स के लिए भी CSS डराने वाला हो सकता है - बहुत सारे विकल्प हैं! लेकिन इस लेख में, हम चर्चा करेंगे कि एक अलग कैस्केडिंग स्टाइल शीट बनाए बिना आपके HTML दस्तावेज़ में पृष्ठभूमि का रंग कैसे बदला जाए। HTML5 का उपयोग करते समय, आप शैली विशेषता, और संपत्ति `पृष्ठभूमि-रंग` का उपयोग करके पृष्ठभ

  1. एचटीएमएल मूल बातें एचटीएमएल मूल बातें

    हाइपरटेक्स्ट उस तरीके को संदर्भित करता है जिसमें वेब पेज (एचटीएमएल दस्तावेज़) एक साथ जुड़े होते हैं। इस प्रकार, वेब पेज पर उपलब्ध लिंक को हाइपरटेक्स्ट कहा जाता है। जैसा कि इसके नाम से पता चलता है, HTML एक मार्कअप भाषा है जिसका अर्थ है कि आप HTML का उपयोग केवल टैग के साथ एक टेक्स्ट दस्तावेज़ को मार्क