۳۰ شهریور ۱۴۰۳

Techboy

اخبار و اطلاعات روز تکنولوژی

یک برنامه جاوا بسازید تا با ChatGPT صحبت کنید

ربات چت مبتنی بر جاوا خود را بسازید و حس تعامل با ChatGPT API در یک کلاینت جاوا را به دست آورید.

ربات چت مبتنی بر جاوا خود را بسازید و حس تعامل با ChatGPT API در یک کلاینت جاوا را به دست آورید.

ChatGPT یک هوش مصنوعی مکالمه مدل زبان بزرگ (LLM) سرگرم کننده و مفید است که با توجه به شهرت آن، نیازی به معرفی زیادی ندارد. بیایید ببینیم چگونه می توانیم با سرویس ChatGPT API از یک برنامه ساده جاوا تعامل داشته باشیم.

شروع به کار با ChatGPT

اولین کاری که باید انجام دهید این است که یک کلید API بدست آورید. می‌توانید با نسخه رایگان ChatGPT که از OpenAI در دسترس است، به یکی دسترسی داشته باشید. پس از ثبت نام، بدون هیچ هزینه ای به نسخه ۳.۵ دسترسی خواهید داشت. (نسخه ۴ در حال حاضر همچنان به هزینه اشتراک نیاز دارد.) 

هنگامی که حسابی دارید و وارد سیستم شدید، می‌توانید کلید API جدیدی ایجاد کنید. آن را در جایی امن ذخیره کنید. بعداً از آن استفاده خواهیم کرد.

ایجاد یک پروژه جاوا جدید

اکنون اجازه دهید شروع به ایجاد یک برنامه جاوا جدید برای این نسخه نمایشی کنیم. ما از Maven از خط فرمان استفاده خواهیم کرد. می توانید با استفاده از کد موجود در فهرست ۱، پروژه جدیدی را طرح ریزی کنید.


mvn archetype:generate -DgroupId=com.infoworld -DartifactId=java-gpt -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false -DarchetypeVersion=1.4

این یک پروژه جدید را در دایرکتوری /java-gpt ایجاد می‌کند. قبل از ادامه، به فایل /java-gpt/pom.xml بروید و کامپایلر جاوا و نسخه منبع را روی ۱۱ تنظیم کنید.

می توانید این را با دستور موجود در لیست ۲ آزمایش کنید، که در حال حاضر “Hello, World!” را خروجی می دهد. به کنسول از اینجا به بعد، از این دستور برای اجرای برنامه استفاده می کنیم.


mvn clean compile exec:java -Dexec.mainClass=com.infoworld.App

برنامه ChatGPT را تنظیم کنید

بیایید دقیقاً تعریف کنیم که برنامه ChatGPT ما چه کاری انجام خواهد داد. ما چیزهای بسیار ابتدایی را برای این نسخه نمایشی حفظ خواهیم کرد. ما می خواهیم یک رشته ورودی را از کاربر بپذیریم و سپس پاسخ هوش مصنوعی به آن را در کنسول خروجی دهیم.

برای شروع، بیایید یک کلاس اصلی App.java ساده قاب کنیم که ورودی را می پذیرد. ما URL و کلید API را تعریف می کنیم، که کلاس اصلی آنها را به یک کلاس ChatBot می دهد تا کار واقعی را انجام دهد. می‌توانید کلاس اصلی App.java را در فهرست ۳ ببینید.


package com.infoworld;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import org.json.JSONException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class App {
  private static final Logger LOGGER = LoggerFactory.getLogger(App.class);
  public static void main(String[] args) {
    // Set ChatGPT endpoint and API key
    String endpoint = "https://api.openai.com/v1/chat/completions";
    String apiKey = "<YOUR-API-KEY>";
        
    // Prompt user for input string
    try {
      BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
      System.out.print("Enter your message: ");
      String input = reader.readLine();
            
      // Send input to ChatGPT API and display response
      String response = ChatBot.sendQuery(input, endpoint, apiKey);
      LOGGER.info("Response: {}", response);
    } catch (IOException e) {
      LOGGER.error("Error reading input: {}", e.getMessage());
    } catch (JSONException e) {
      LOGGER.error("Error parsing API response: {}", e.getMessage());
    } catch (Exception e) {
      LOGGER.error("Unexpected error: {}", e.getMessage());
    }
  }
}

این کلاس نسبتاً ساده است: یک خط را از کاربر با reader.readLine() می خواند، سپس از آن برای فراخوانی روش ثابت ChatBot.sendQuery() استفاده می کند. . من ChatBot را در یک لحظه به شما نشان خواهم داد. در حال حاضر، مطمئن شوید که نشانه را روی آن توکن OpenAI ChatGPT که در ابتدای این مقاله ذخیره کرده بودیم، تنظیم کنید. همچنین توجه داشته باشید که OpenAI تغییراتی را در OpenAI API ایجاد کرده است، بنابراین URL نقطه پایانی https://api .openai.com/v1/chat/completions در حال حاضر صحیح است، اما ممکن است با اسناد قبلی (حتی اخیر) متفاوت باشد. اگر خطایی دریافت کردید، مطمئن شوید که URL نقطه پایانی با به‌روز است تکرار OpenAI API.

کلاس ChatBot

توجه داشته باشید که ما یک لاگر ساده را برای تماشای اتفاقات و ردیابی هرگونه خطا پیکربندی کرده ایم. برای پشتیبانی از این کلاس باید چند وابستگی به Maven اضافه کنیم، اما ابتدا به کلاس ChatBot که در فهرست ۴ نشان داده شده است نگاهی بیندازیم. برای راحتی، هر دو را در یک قرار می دهیم. محدوده بسته.


package com.infoworld;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;

import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.gson.Gson;

public class ChatBot {
  private static final Logger LOGGER = LoggerFactory.getLogger(ChatBot.class);

  public static String sendQuery(String input, String endpoint, String apiKey) {
    // Build input and API key params
    JSONObject payload = new JSONObject();
    JSONObject message = new JSONObject();
    JSONArray messageList = new JSONArray();

    message.put("role", "user");
    message.put("content", input);
    messageList.put(message);

    payload.put("model", "gpt-3.5-turbo"); // model is important
    payload.put("messages", messageList);
    payload.put("temperature", 0.7);

    StringEntity inputEntity = new StringEntity(payload.toString(), ContentType.APPLICATION_JSON);

    // Build POST request
    HttpPost post = new HttpPost(endpoint);
    post.setEntity(inputEntity);
    post.setHeader("Authorization", "Bearer " + apiKey);
    post.setHeader("Content-Type", "application/json");

    // Send POST request and parse response
    try (CloseableHttpClient httpClient = HttpClients.createDefault();
      CloseableHttpResponse response = httpClient.execute(post)) {
        HttpEntity resEntity = response.getEntity();
        String resJsonString = new String(resEntity.getContent().readAllBytes(), StandardCharsets.UTF_8);
        JSONObject resJson = new JSONObject(resJsonString);

        if (resJson.has("error")) {
          String errorMsg = resJson.getString("error");
          LOGGER.error("Chatbot API error: {}", errorMsg);
          return "Error: " + errorMsg;
        }

        // Parse JSON response
        JSONArray responseArray = resJson.getJSONArray("choices");
        List<String> responseList = new ArrayList<>();

        for (int i = 0; i < responseArray.length(); i++) {
          JSONObject responseObj = responseArray.getJSONObject(i);
          String responseString = responseObj.getJSONObject("message").getString("content");
          responseList.add(responseString);
        }

        // Convert response list to JSON and return it
        Gson gson = new Gson();
        String jsonResponse = gson.toJson(responseList);
        return jsonResponse;
      } catch (IOException | JSONException e) {
        LOGGER.error("Error sending request: {}", e.getMessage());
        return "Error: " + e.getMessage();
      }
  }
}

ChatBot به نظر می‌رسد که چیزهای زیادی در جریان است، اما نسبتاً ساده است. بزرگترین مشکل، سر و کار داشتن با JSON است. ابتدا، ما باید ورودی رشته ارسال شده به sendQuery() را در قالب JSON مورد انتظار ChatGPT قرار دهیم (دوباره، اخیراً در این مورد دچار مشکل شده است). ChatGPT امکان یک مکالمه مداوم را فراهم می کند، بنابراین به دنبال مجموعه ای از پیام ها است که با نقش کاربر یا دستیار برچسب گذاری شده اند. هوش مصنوعی به اینها به عنوان پاسخ های رفت و برگشتی در چت نگاه می کند. (همچنین یک نقش سیستمی وجود دارد که برای تنظیم «تن» کل مکالمه استفاده می‌شود، اگرچه این ویژگی به طور متناقضی اعمال می‌شود.) قالب JSON که ChatGPT انتظار دارد مانند فهرست ۵ است (برگرفته از OpenAI docs).


messages:[
  {"role": "system", "content": "You are a helpful assistant."},
  {"role": "user", "content": "Who won the world series in 2020?"},
  {"role": "assistant", "content": "The Los Angeles Dodgers won the World Series in 2020."},
  {"role": "user", "content": "Where was it played?"}
]

پاسخ JSON را تنظیم کنید

بنابراین، در مورد ما، ما فقط از یک مجموعه ساده از پیام‌ها استفاده می‌کنیم، با یک role:user و محتوایی که در رشته ورودی تنظیم شده است. فیلدهای مدل و دما را هم تنظیم کردیم. فیلد مدل در تعریف نسخه ChatGPT که استفاده می شود مهم است. چندین گزینه وجود دارد، از جمله جدیدتر (برای پرداخت) GPT-4. دما یک ویژگی GPT است که به هوش مصنوعی می‌گوید که چقدر «خلاق» باشد (از نظر جلوگیری از استفاده مجدد از کلمات).

با در دست داشتن JSON مناسب، از کتابخانه Apache HTTP برای ایجاد یک درخواست POST استفاده می‌کنیم و بدنه را روی JSON تنظیم می‌کنیم (از طریق post.setEntity()). توجه داشته باشید که ما آن کلید API را در سربرگ auth با این خط تنظیم کردیم:


post.setHeader("Authorization", "Bearer " + apiKey);

بعد، از بلوک try-with-resource برای صدور درخواست استفاده می کنیم. با انجام پاسخ (با فرض اینکه از هر گونه خطایی اجتناب کرده ایم) فقط باید ساختار پاسخ JSON را مرور کنیم و جدیدترین message:content را برگردانیم.

اکنون تقریباً آماده آزمایش آن هستیم. ابتدا، همانطور که در فهرست ۶ نشان داده شده است، وابستگی های لازم را به pom.xml اضافه کنید.


<dependencies>
   <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
   </dependency>
   <dependency>
      <groupId>org.apache.commons</groupId>
      <artifactId>commons-lang3</artifactId>
      <version>3.7</version>
   </dependency>
   <dependency>
      <groupId>com.google.code.gson</groupId>
      <artifactId>gson</artifactId>
      <version>2.8.6</version>
   </dependency>
   <dependency>
      <groupId>org.apache.httpcomponents</groupId>
      <artifactId>httpclient</artifactId>
      <version>4.5.13</version>
   </dependency>
</dependencies>
<dependency>
  <groupId>org.slf4j</groupId>
  <artifactId>slf4j-api</artifactId>
  <version>1.7.30</version>
</dependency>
<dependency>
  <groupId>ch.qos.logback</groupId>
  <artifactId>logback-classic</artifactId>
  <version>1.2.3</version>
</dependency>

اکنون وقتی کد را اجرا می کنید، باید ببینید که کار می کند. چیزی شبیه لیست ۷ خواهد بود.


$ mvn clean compile exec:java -Dexec.mainClass=com.infoworld.App

Enter your message: This is the forest primeval.

۲۲:۴۳:۳۵.۳۸۴ [com.infoworld.App.main()] INFO com.infoworld.App - Response: "The murmuring pines and the hemlocks,\n\nBearded with moss, and in garments green,\n\nIndistinct in the twilight,\n\nStand like Druids of eld,\n\nWith voices sad and prophetic,\n\nStand like harpers hoar,\n\nWith beards that rest on their bosoms.\n\nLoud from its rocky caverns,\n\nThe deep-voiced neighboring ocean\n\nSpeaks, and in accents disconsolate\n\nAnswers the wail of the forest."

برای دریافت کد برنامه کامل، جاوا-chatgpt مخزن GitHub من را ببینید.

نتیجه گیری

همانطور که این مقاله نشان می دهد، ساختن کلاینت ChatGPT در جاوا نسبتاً آسان است. مدیریت JSON کمی دست و پا گیر است، اما در غیر این صورت، به راحتی می توان دید که چگونه می توانیم به راحتی نمایش کد نمایشی را در اینجا گسترش دهیم. به عنوان اولین تمرین، برنامه ChatGPT را به یک REPL گسترش دهید که امکان مکالمه مداوم را فراهم می کند.