در این آموزش، نحوه ایجاد یک برنامه “AI Quotes Generator” با جاوا اسکریپت را یاد خواهیم گرفت. این برنامه نحوه واکشی داده ها از OpenAI API و تولید نقل قول های جذاب برای دسته های مختلف یا حالت های دلخواه را نشان می دهد.

ساختار HTML

ساختار HTML از عناصر زیر تشکیل خواهد شد:

  • دکمه ای در بالا سمت راست، مودال را باز می کند که به کاربران امکان می دهد کلید OpenAI API خود را اضافه کنند.
  • ورودی که به کاربران امکان می دهد حالت دلخواه خود را اضافه کنند
  • چندین گزینه پر از دسته بندی ها
  • دکمه ای که با کلیک روی آن، نقل قول هایی از OpenAI API ایجاد می کند.

همانطور که قبلا انجام داده ایم، ما از چارچوب بوت استرپ استفاده خواهیم کرد برای انجام بسیاری از کارهای سنگین در مورد رابط کاربری. ساختار HTML به شکل زیر خواهد بود:

1
<div class="position-absolute top-0 end-0 mt-2 me-3">
2
   <button
3
      id="api"
4
      type="button"
5
      class="btn btn-primary"
6
      data-bs-toggle="modal"
7
      data-bs-target="#myModal"
8
      >
9
   Add API Key
10
   </button>
11
</div>
12
<div class="container mt-5">
13
   <div class="message alert alert-danger text-center" role="alert"></div>
14
   <div
15
      class="modal fade"
16
      id="myModal"
17
      tabindex="-1"
18
      aria-labelledby="exampleModalLabel"
19
      aria-hidden="true"
20
      >
21
      <div class="modal-dialog ">
22
         <div class="modal-content">
23
            <div class="modal-header">
24
               <h5 class="modal-title" id="exampleModalLabel">
25
                  Your API Key remains stored locally in your browser
26
               </h5>
27
            </div>
28
            <div class="modal-body">
29
               <div class="form-group">
30
                  <label for="apikey">API KEY</label>
31
                  <input type="text" class="form-control" id="apikey" />
32
               </div>
33
            </div>
34
            <div class="modal-footer">
35
               <button
36
                  type="button"
37
                  class="btn btn-secondary"
38
                  data-bs-dismiss="modal"
39
                  >
40
               Close
41
               </button>
42
               <button type="button" class="btn btn-primary">Save</button>
43
            </div>
44
         </div>
45
      </div>
46
   </div>
47
   <h1 class="header text-center display-2 fw-bold">AI Quote Generator</h1>
48
   <!-- Main -->
49
   <div class="d-md-flex h-md-100 my-5 align-items-center">
50
      <div class="col-md-6 p-0 h-md-100">
51
         <div class="d-md-flex align-items-center h-100 p-5 text-center justify-content-center category-wrapper">
52
            <div class="pt-5 pb-5">
53
               <p class="fs-5">
54
                  Create the perfect quote based on your current mood..
55
               </p>
56
               <input
57
                  id="input"
58
                  name="mood"
59
                  type="text"
60
                  placeholder="Enter your current mood"
61
                  class="form-control mb-4 mx-auto w-75 text-center"
62
                  style="width: 60%; display: inline-block"
63
                  />
64
            </div>
65
         </div>
66
      </div>
67
      <div class="col-md-6 p-0 h-md-100">
68
         <div class="d-md-flex align-items-center h-md-100 p-5 text-center justify-content-center vstack">
69
            <p class="fs-5">
70
               ..or choose from our custom categories
71
            </p>
72
            <div
73
               class="quotes row justify-content-center mt-8 mb-4"
74
               >
75
               <!-- categories will go here -->
76
            </div>
77
         </div>
78
      </div>
79
   </div>
80
   <!-- End Main -->
81
   <div class="quotes-container text-center mt-4">
82
      <button
83
         id="generate"
84
         class="generate-btn btn btn-primary"
85
         type="submit"
86
         >
87
      Generate Quotes
88
      </button>
89
      <div class="d-flex justify-content-center mt-3">
90
         <div id="loader" class="spinner-border" role="status">
91
         </div>
92
      </div>
93
   </div>
94
</div>
95
</div>
96
<div class="container text-center mt-5 mb-4">
97
   <div id="result" class="row">
98
      <!-- generate quotes will go here -->
99
   </div>
100
</div>

دسته‌های نقل قول را به‌صورت پویا با جاوا اسکریپت پر می‌کنیم، و هنگامی که نقل‌قول‌ها را از OpenAI API دریافت کردیم، در ظرف نتایج پر می‌شوند.

برای این پروژه، ما همچنین از ابزارهای jQuery Bootstrap برای فعال کردن عملکرد مودال استفاده خواهیم کرد. لطفاً پیوندهای CDN را در هدر قرار دهید.

1
<!-- Bootstrap CSS -->
2
<link href=" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous" />
3
<!-- jQuery -->
4
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
5
<!-- Bootstrap JavaScript (requires jQuery and Popper.js) -->
6
<script src=" integrity="sha384-I7E8VVD/ismYTF4hNIPjVp/Zjvgyol6VFvRkX/vR+Vc4jQkC+hVqc2pM8ODewa9r" crossorigin="anonymous"></script>
7
<script src=" integrity="sha384-0pUGZvbkm6XF6gxjEnlmuGrJXVbNuzT9qBBavbLwCsOGabYfZo0T0to5eqruptLy" crossorigin="anonymous"></script>

یک ظاهر طراحی CSS

به لطف Bootstrap، ما به سبک های سفارشی زیادی نیاز نخواهیم داشت. اما بیایید سبک های CSS سفارشی مورد نیاز خود را اضافه کنیم، از جمله فونت وب DM Mono.

1
@import url("https://fonts.googleapis.com/css2?family=DM+Mono:ital,wght@0,300;0,400;0,500;1,300;1,400;1,500&display=swap");
2

3
body {
4
  font-family: "DM Mono", monospace;
5
}
6
.form-group {
7
  margin: 2rem 0;
8
}
9
label {
10
  margin-bottom: 1rem;
11
}
12
@media (min-width: 768px) {
13
  .category-wrapper {
14
    border-right: 2px solid #999;
15
  }
16
}
17

18
#loader,
19
.message,
20
.radio-group input[type="radio"]{
21
  display: none;
22
}
23
   

ذخیره‌سازی کلید API در فضای ذخیره‌سازی محلی

برای اینکه برنامه مطابق انتظار عمل کند، کاربران باید API KEY خود را به حافظه محلی اضافه کنند تا از پایداری و امنیت اطمینان حاصل کنند. برای رسیدن به این هدف، ما “افزودن کلید API” دکمه سمت راست بالا دکمه با پیکربندی شده است data-bs-target صفت تنظیم شده است myModal نشان می دهد که با کلیک کردن روی آن، مودال با شناسه فعال می شودmyModal” نمایش داده شود.

1
<button
2
   id="api"
3
   type="button"
4
   class="btn btn-primary"
5
   data-bs-toggle="modal"
6
   data-bs-target="#myModal"
7
   >
8
Add API Key
9
</button>

هنگامی که مدال به کاربر نشان داده شد، از jQuery برای پیوست کردن شنونده رویداد برای آن استفاده خواهیم کرد shown.bs.modal رویداد. در تابع رویداد، موارد زیر را انجام خواهیم داد:

  • مقدار کلید API را از کاربر دریافت کنید.
  • ذخیره مقدار در حافظه محلی،
  • مدال را پنهان کنید
1
$("#myModal").on("shown.bs.modal", function () {
2
  
3
  const saveButton = document.querySelector("#myModal .btn-primary");
4
  const apiKeyInput = document.querySelector("#apikey");
5

6
  saveButton.addEventListener("click", function () {
7
    const apiKeyValue = apiKeyInput.value;
8
    localStorage.setItem("API_KEY", apiKeyValue);
9
    $("#myModal").modal("hide");
10
  });
11
});

بنابراین وقتی روی ” کلیک کنیدکلید API را اضافه کنیددکمه “، مدال به صورت زیر نمایش داده می شود:

گام بعدی این است که دسته بندی های سفارشی خود را به رابط تعریف و ترسیم کنیم. در اینجا دسته بندی ها آمده است. با خیال راحت خودتان را تعریف کنید.

1
پایان دسته بندی ها = [
2
  "motivation",
3
  "life",
4
  "hope",
5
  "funny",
6
  "love",
7
  "philosophy",
8
  "sadness",
9
];

بیایید عنصری را با نقل قول‌های کلاس دریافت کنیم که دسته‌ها را در خود جای می‌دهد.

1
const quotes = document.querySelector(".quotes");

بعد از آن استفاده خواهیم کرد map() روشی برای ایجاد نشانه گذاری HTML از یک برچسب و یک عنصر رادیویی ورودی برای هر دسته. عنصر ورودی رادیویی حاوی id و value از دسته، در حالی که برچسب شامل name از دسته

1
const mappedCategories = categories.map((category) => {
2
  capitalizeText = category.charAt(0).toUpperCase() + category.slice(1);
3
      return `<input
4
        type="radio"
5
        class="btn-check"
6
        name="mood"
7
        id="${category}"
8
        value="${category}"
9
        autocomplete="off"
10
      />
11
      <label
12
        class="btn btn-secondary align-items-center justify-content-center fs-5"
13
        for="${category}"
14
      >${capitalizeText}</label>`;
15
});
16
quotes.innerHTML = mappedCategories.join("");

اکنون برنامه به شکل زیر است:

پیکربندی OpenAI API

ما قابلیت افزودن API Key را پیاده سازی کرده ایم. حالا بیایید کلید را از وب سایت OpenAI بگیریم. اگر حساب کاربری ندارید، به وب سایت OpenAI و بصورت رایگان ثبت نام کنید

پس از ارائه جزئیات مورد نیاز، به قسمت مورد نظر بروید مستندات. روی API KEY در بالا سمت چپ کلیک کنید، کلید API خود را ایجاد کنید، کلید را کپی و جایگذاری کنید و آن را در مکانی امن ذخیره کنید.

با استفاده از کلید API

یک تابع async به نام ایجاد کنید getData()، که دو پارامتر دارد، یعنی prompt و API KEY،

1
const getData = async (prompt, API_KEY) => {
2
    
3
}

در داخل تابع، می خواهیم استفاده کنیم fetch() عملکرد درخواستی به OpenAI API و نمایش پاسخ تولید شده به کاربر. درون getData() تابع، اضافه کردن a try-catch با کد زیر مسدود کنید

1
const getData = async (prompt, API_KEY) => {
2
  
3
  try {
4
    const response = await fetch("https://api.openai.com/v1/chat/completions", {
5
      method: "POST",
6
      headers: {
7
        Authorization: `Bearer ${API_KEY}`,
8
        "Content-Type": "application/json",
9
      },
10
      body: JSON.stringify({
11
        model: "gpt-3.5-turbo",
12
        پیام ها: [
13
          {
14
            role: "user",
15
            content: `Generate 10 quotes about ${prompt}`,
16
          },
17
        
18
        temperature: 0.7,
19
      }),
20
    });
21
    const data = await response.json();
22

23
    return data;
24
  } catch (error) {
25

26
    return error;
27
  }
28
};

این تمام کدی است که برای دریافت داده از OpenAI نیاز داریم. بیایید کد را تجزیه کنیم.

  • ما استفاده می کنیم fetch() برای ایجاد یک همگام سازی در داخل بلوک try POST درخواست به url مشخص شده
  • در بدنه درخواست مشخص می کنیم gpt-3.5-turbo به عنوان مدل مورد استفاده؛
  • OpenAI API همچنین انتظار دارد که یک سرصفحه مجوز شامل این باشد API KEY, و بدنه درخواست باید الف باشد JSON شی حاوی پارامترهایی مانند model، prompt، و temperature (نشان دهنده تصادفی بودن پاسخ ها است؛ مقادیر بالاتر نشان دهنده تصادفی بودن بیشتر پاسخ ها است).
  • در نهایت، ما را برمی گردانیم response.json هدف – شی. در صورت بروز هر گونه خطایی، ما نیز آن را برمی گردانیم error هدف – شی.

پاسخ داده ها به این شکل است.

همانطور که می بینید، داده هایی که ما باید به کاربر نمایش دهیم در آن موجود است choices آرایه. داده ها قبل از نمایش به کاربر فرمت می شوند.

را getData() زمانی که کاربر روی دکمه تولید نقل قول ها کلیک کند، تابع فراخوانی می شود. بیایید شنونده رویداد را به دکمه تولید اضافه کنیم.

1
const generateBtn = document.querySelector(".generate-btn");
2
generateBtn.addEventListener("click", async (e) => {
3
  e.preventDefault();
4
  
5
  }

هنگامی که رویداد کلیک رخ می دهد، می خواهیم تابعی را اجرا کنیم که موارد زیر را انجام می دهد:

  • کلید API را از حافظه محلی دریافت کنید.
  • اگر کلید API در فضای ذخیره‌سازی محلی یافت نشد، خطایی را نمایش می‌دهیم و به کاربر اطلاع می‌دهیم که باید کلید API خود را اضافه کند.
  • درخواست را از یک دسته یا یک درخواست سفارشی دریافت کنید.
  • فرمان و APIKEY را به getData() تابع.
  • هنگامی که برنامه در حال واکشی داده است، یک اسپینر نشان دهید.
  • پس از دریافت پاسخ، اسپینر را متوقف کنید.
  • داده ها را فرمت کنید و روی کارت های بوت استرپ نمایش دهید.
  • در صورت بروز هر گونه خطایی پیغام خطای مناسب را نمایش خواهیم داد.

عملکرد شنونده رویداد را به صورت زیر به روز کنید:

1
const generateBtn = document.querySelector(".generate-btn");
2
generateBtn.addEventListener("click", async (e) => {
3
  e.preventDefault();
4
  const key = localStorage.getItem("API_KEY");
5

6
  if (!key) {
7
    displayError("","Please add your OPENAI API Key, The KEY will be stored locally on your browser");
8
    return;
9
  }
10

11
  let prompt = "";
12
  let radio = document.querySelector('input[name="mood"]:checked');
13

14
  if (document.querySelector('input[name="mood"]:checked')) {
15
    radio = document.querySelector('input[name="mood"]:checked');
16
    prompt = radio.value;
17
  } else {
18
    CustomInput = document.getElementById("input");
19
    prompt = CustomInput.value; 
20
  }
21

22
  if (!prompt) {
23
    displayError(prompt,'Please choose a category or provide a custom mood"');
24
    return;
25
  }
26
  
27
  loader.style.display = "block";
28

29
  const data = await getData(prompt, key);
30

31
  if (data.choices) {
32
    const container = document.getElementById("result");
33
    //    data from aync
34
    const quotesArray = data.choices[0].message.content.split("\n");
35
    const mappedArray = quotesArray.map((quote) => {
36
      const trimmedQuote = quote.replace(/^\d+\.|"$/g, "").trim();
37

38
      return ` <div class="col-sm-6 mt-5 mb-4">
39
            <div class="card">
40
              <div class="card-body">
41
                <p class="card-text">${trimmedQuote}</p></div>
42
            </div>
43
        </div>
44
        `;
45
    });
46

47
    container.innerHTML = mappedArray.join("");
48
    
49
  } else {
50
    displayError("",data.error.message )
51
    
52
  }
53
  CustomInput.value = "";
54
});

بیایید آنچه در بالا اتفاق می افتد را تجزیه کنیم:

  • ابتدا با تنظیم از ماهیت پیش فرض مرورگر جلوگیری می کنیم e.preventDefault()
  • const key = localStorage.getItem("API_KEY"); کلید API را از حافظه محلی دریافت می کند.
  • اگر کلیدی پیدا نشد، یک پیغام خطا به آن ارسال می کنیم displayError() تابع.
  • let prompt = ""; یک رشته خالی را اعلام می کند که مقدار درخواست کاربر را ذخیره می کند.
  • if (document.querySelector('input[name="mood"]:checked')){...} : بررسی می کند که آیا کاربر یک دسته را انتخاب کرده است و اگر درست باشد، مقدار ورودی رادیویی انتخاب شده به اعلان اختصاص داده می شود.
  • در else اگر کاربر حالت سفارشی را وارد کرده باشد، اعلان مقدار ورودی سفارشی خواهد بود.
  • اگر مقدار prompt باشد null یا undefined، به این معنی است که کاربر اعلانی ارائه نکرده است (چه با انتخاب یک دسته حالت و چه با وارد کردن حالت دلخواه)، یک پیغام خطا نمایش می دهیم.
  • پس از تمام شدن اعتبارسنجی، یک عنصر اسپینر با نمایش داده می شود loader.style.display = "block";

getData() تابع

بعد، ما انتظار را صدا خواهیم کرد getData() عملکرد و فرمان و کلید API را ارسال کنید. از آنجایی که این تابع یک تابع ناهمزمان است، از انتظار برای اطمینان از تأخیر اجرا تا زمانی که واکشی داده‌ها با موفقیت انجام شود، استفاده می‌کنیم.

همانطور که قبلا دیدیم، آبجکت داده ای که توسط API برگردانده می شود به شکل زیر است:

محتوای مورد نیاز ما در choices[0].message هدف – شی.

  • data.choices[0].message.content.split("\n"); آرایه ای از نقل قول ها به نام quotesArray را با تقسیم آن در جایی که \n ظاهر می شود ایجاد می کند.
  • را quotesArray اکنون شامل تمام نقل قول ها است، تنها کاری که باید انجام دهیم این است که از آن استفاده کنیم map() روش و برای هر نقل قول، هر فاصله سفید پیشرو یا انتهایی را حذف کنید quote.replace(/^\d+\.|"$/g, "").trim(); و برای هر نقل قول که توسط یک کارت بوت استرپ نمایش داده می شود، یک نشانه گذاری HTML برگردانید.
  • در نهایت، ما تنظیم می کنیم innerHTML از quotes ظرف به نشانه گذاری HTML الحاق شده هر نقل قول.
  • در صورت بروز خطا از API، displayError("",data.error.message ) پیغام خطای برگشتی را نمایش می دهد.

رسیدگی به خطا

به جای تکرار فرآیند رسیدگی به خطا، displayError() تابع آن را مدیریت خواهد کرد. طول می کشد valueText و الف messageText به عنوان پارامتر، بررسی می کند که آیا valueText پوچ یا تعریف نشده است و پیام خطای موجود در آن را نمایش می دهد messageText .

پیغام خطا به مدت 4 ثانیه نمایش داده می شود و سپس از دید کاربر پنهان می شود.

1
function displayError(valueText,messageText) {
2
  const message = document.querySelector(".message");
3
  if (valueText === "") {
4
  
5
    message.textContent = messageText;
6
    message.style.display = "block";
7
  }
8
  setTimeout(() => {
9
    message.textContent = "";
10
    message.style.display = "none";
11
  }, 4000);
12
  return;
13
}

برای پاکسازی نهایی، اجازه دهید مطمئن شویم که اگر کاربر شروع به تایپ کردن در قسمت ورودی سفارشی کند، هر دسته ای که قبلاً انتخاب شده بود (از طریق دکمه های رادیویی) از حالت انتخاب خارج می شود.

1
const inputField = document.getElementById("input");
2
inputField.addEventListener("input", () => {
3
  const radio = document.querySelector('input[name="mood"]:checked');
4
  if (radio) {
5
    radio.checked = false;
6
  }
7
});

نتیجه

وای! این چیزهای زیادی برای پذیرش بود، اما نتیجه نهایی ارزشش را دارد و شما چیزهای زیادی یاد خواهید گرفت. ما مراحل مورد نیاز برای ایجاد برنامه تولید کننده نقل قول هوش مصنوعی خود را با جاوا اسکریپت پوشش دادیم. اکنون، می توانید هوش مصنوعی را در برنامه خود ادغام کنید تا محتوای منحصر به فرد تولید کنید!

بیایید محصول نهایی را به خود یادآوری کنیم.