Java调用ChatGPT(基于SpringBoot和Vue),实现可连续对话和流式输出的ChatGPT API(可自定义实现AI助手)

源码及更详细的介绍说明参见Git上的ReadME.md文档
https://github.com/asleepyfish/chatgpt

本文结合SpringBoot的Demo地址:https://github.com/asleepyfish/chatgpt-demo

流式输出结合Vue的Demo地址:https://github.com/asleepyfish/chatgpt-vue

注意:流式输出在2.4节,请仔细阅读到最后。
如果能对你有所帮助,Github帮忙star⭐一下,点赞收藏,谢谢~

版本更新说明

  • 1.1.5 增加查询账单功能billingUsage(单位:美元),可以选择传入开始和结束日期查询(最多100天),或者不传入参,此时表示查询所有日期账单。
  • 1.1.6 增加自定义OpenAiProxyService功能,支持单个SpringBoot中添加多个OpenAiProxyService实例,每个实例可以拥有个性化的参数;查询账单功能优化。

1. 配置阶段

1.1 依赖引入

pom.xml中引入依赖(当前最新版本为1.1.6,可前往Github页面查看当前最新版本)

        <dependency>
            <groupId>io.github.asleepyfish</groupId>
            <artifactId>chatgpt</artifactId>
            <version>1.1.6</version>
        </dependency>

1.2 配置application.yml文件

Configurer les paramètres associés dans application.ymlle fichier (Facultatif est un paramètre facultatif)

paramètre expliquer
jeton CLES D'API D'APPLICATION
Hôte proxy Adresse IP
port proxy port proxy
modèle (facultatif) Le modèle peut être rempli ou non, la valeur par défaut est text-davinci-003
modèle de chat (facultatif) Il peut être rempli ou non, et la valeur par défaut est gpt-3.5-turbo (ChatGPT est actuellement le modèle le plus puissant, et ce modèle est utilisé pour générer des réponses)
tentatives (facultatif) Il fait référence au nombre de nouvelles requêtes lorsque la requête chatgpt échoue pour la première fois (la raison de l'augmentation de ce paramètre est qu'en raison d'un grand nombre de visites, à un certain moment, le service chatgpt sera inaccessible. 5)
heure d'expiration de la session (facultatif) (unité (min)) est la durée pendant laquelle la session sera détruite après aucun accès. Lorsque cette valeur n'est pas renseignée, cela signifie que toutes les questions et réponses sont sous la même session, et la session du même utilisateur ne sera jamais détruite ( augmentation de la consommation de requêtes)

exemple:

chatgpt:
  token: sk-xxxxxxxxxxxxxxx
  proxy-host: 127.0.0.1
  proxy-port: xxxx
  session-expiration-time: 30

Parmi eux, jeton, hôte proxy et port proxy sont requis

Le paramètre session-expiration-time ci-dessus est très important, il est utilisé pour indiquer combien de temps la session sera détruite après aucun accès, afin d'avoir un dialogue continu en rapport avec le contexte.

La méthode de mise en œuvre consiste à distinguer une session via l'utilisateur dans ChatCompletionRequest, et le temps d'expiration de session indique combien de temps la session sera détruite après aucun accès.

Si vous ne comprenez pas ici, veuillez consulter l'exemple de la section 2.1

1.3 Ajouter des annotations

L'ajout des annotations de la figure à la classe de démarrage injectera le service dans Spring.
insérez la description de l'image ici

2. utiliser

2.1 Générer des réponses

Une classe d'outils est fournie OpenAiUtils, qui fournit des méthodes associées pour l'appel.
Le plus simple d'entre eux à utiliser est :

OpenAiUtils.createChatCompletion(content);// 不建议使用

Le contentparamètre d'entrée est la chaîne de la question saisie. Mais pas recommandé.

Il est recommandé d'utiliser ici la méthode suivante : En passant la valeur de l'utilisateur et en combinant session-expiration-timeles paramètres, il est possible de spécifier une certaine session ou un dialogue continu d'un certain utilisateur.

OpenAiUtils.createChatCompletion(content, user);// 建议使用

Fournit également une méthode statique générique qui est

public static List<String> createChatCompletion(ChatCompletionRequest chatCompletionRequest) {
    
    ...}

Les paramètres d'entrée ChatCompletionRequest contiennent certains paramètres ajustables du modèle.

OpenAiUtilsLa classe fournit également un certain nombre de méthodes statiques facultatives, qui peuvent être visualisées par vous-même.

Le paramètre de retour de la méthode ci-dessus est une liste, car la réponse renvoyée en ajustant le paramètre npeut renvoyer plusieurs réponses différentes à la fois ( un paramètre nde ChatCompletionRequestla classe).

2.1.1 Tests

Code d'essai :

@PostMapping("/chatTest")
public List<String> chatTest(String content) {
    
    
    return OpenAiUtils.createChatCompletion(content, "testUser");
}

Publier une demande

Entrée de paramètre : méthode de sérialisation Java

résultat de retour :

[
  "\n\nJava序列化是将Java对象转换为字节序列的过程,以便在网络上传输或将其保存到磁盘上。Java提供了两种序列化方式:\n\n1. 基于Serializable接口的序列化\n\nSerializable接口是Java提供的一个标记接口,用于标记一个类可以被序列化。如果一个类实现了Serializable接口,那么它的所有非瞬态字段都会被序列化。序列化的过程可以通过ObjectOutputStream类来实现,反序列化的过程可以通过ObjectInputStream类来实现。\n\n2. 基于Externalizable接口的序列化\n\nExternalizable接口也是Java提供的一个标记接口,用于标记一个类可以被序列化。与Serializable接口不同的是,Externalizable接口需要实现writeExternal和readExternal方法,这两个方法分别用于序列化和反序列化。在序列化的过程中,只有被writeExternal方法显式写入的字段才会被序列化,而在反序列化的过程中,只有被readExternal方法显式读取的字段才会被反序列化。\n\n总的来说,基于Serializable接口的序列化更加简单,但是它会序列化所有非瞬态字段,包括一些不需要序列化的字段,而基于Externalizable接口的序列化可以更加灵活地控制序列化的过程。"
]

Entrez à nouveau : existe-t-il un cadre de sérialisation plus efficace ?

résultat de retour :

[
  "是的,Java中有很多高效的序列化框架,以下是一些常用的序列化框架:\n\n1. Protobuf\n\nProtobuf是Google开发的一种高效的序列化框架,它可以将结构化数据序列化为二进制格式,支持多种编程语言。相比于Java自带的序列化方式,Protobuf序列化后的数据更小,解析速度更快。\n\n2. Kryo\n\nKryo是一个快速、高效的Java序列化框架,它可以将Java对象序列化为字节数组,支持多种数据类型。Kryo序列化的速度比Java自带的序列化方式快很多,序列化后的数据也更小。\n\n3. FST\n\nFST是一个高性能的Java序列化框架,它可以将Java对象序列化为字节数组,支持多种数据类型。FST序列化的速度比Java自带的序列化方式快很多,序列化后的数据也更小。\n\n4. Avro\n\nAvro是一个高效的数据序列化系统,它可以将结构化数据序列化为二进制格式,支持多种编程语言。Avro序列化后的数据比Java自带的序列化方式更小,解析速度也更快。\n\n总的来说,这些高效的序列化框架都比Java自带的序列化方式更快、更小、更灵活,可以根据具体的需求选择合适的框架。"
]

On peut voir que les deux questions et réponses ci-dessus sont dans une session, et les paramètres mentionnés ci-dessus sont session-expiration-timele temps de destruction lorsque la session représentée par cet utilisateur n'a pas été consultée depuis longtemps. unité (min)

2.2 Générer des images

La façon la plus simple d'utiliser est

OpenAiUtils.createImage(prompt);

Le paramètre d'entrée représente le texte de description de l'image générée et fournit également une méthode statique générale

public static List<String> createImage(CreateImageRequest createImageRequest) {
    
    ...}

CreateImageRequestCertains paramètres peuvent être utilisés dans les paramètres d'entrée , qui nindiquent le nombre d'images générées et responseFormatle format des images générées. Le format est divisé en urldeux b64_jsontypes. Si vous souhaitez renvoyer une URL, l'URL renvoyée disparaîtra et heure après sa génération. La valeur par défaut est url.

2.2.1 Tests

code d'essai

    @Test
    public void testGenerateImg() {
    
    
        OpenAiUtils.createImage("英短").forEach(System.out::println);
    }

Résultats
Par défaut, une url sera générée, cliquez pour voir l'image.
insérez la description de l'image ici

2.3 Télécharger des images

Optimisé sur la base de 3.2, utilisez-le directement responseFormat, b64_jsonpuis analysez-le en une image et renvoyez-le. L'utilisation simple est la suivante :

OpenAiUtils.downloadImage(prompt, response);

La méthode générale est la suivante :

public static void downloadImage(CreateImageRequest createImageRequest, HttpServletResponse response) {
    
    ...}

Lorsque CreateImageRequestle paramètre de retour défini dans l'objet nest supérieur à 1, l'image sera compressée dans un package zip et renvoyée, et lorsqu'il nest égal à 1, l'image sera renvoyée directement.

2.3.1 Tests

code d'essai

@RestController
public class ChatGPTController {
    
    
    @GetMapping("/downloadImage")
    public void downloadImage(String prompt, HttpServletResponse response) {
    
    
        OpenAiUtils.downloadImage(prompt, response);
    }
}

Envoyez une demande d'obtention, puis sélectionnez Envoyer et télécharger
insérez la description de l'image ici

我用的get 工具是idea里面下载的插件Fast Request的,用Postman也是可以的,但是要选择 Send and Download,上图中绿色的箭头是Send,蓝色的是Send and Download。

insérez la description de l'image ici

2.4 生成流式回答

生成流式回答的方法是OpenAiUtilscreateStreamChatCompletion方法,本工具类重载了同名的多个参数的方法,其中最通用的方法是

public static void createStreamChatCompletion(ChatCompletionRequest chatCompletionRequest, OutputStream os) {
    
    ...}

最简单的方法是

public static void createStreamChatCompletion(String content) {
    
    ...}

其中的content即本次对话的问题。

这里需要主义的是,上述第一个方法中的OutputStream os其实是一个必传的对象,上述的最简单的方法实际上是默认传递的System.out这个os对象,也就是将流式问答的结果显示到IDEA的控制台。

如果需要将流式问答的结果显示到其他界面可以自发的传入OutputStream os对象,这里有一个简便的方法是

public static void createStreamChatCompletion(String content, OutputStream os) {
    
    ...}

只需要输入问题,和输出流对象即可。

下面将举例具体说明。(本文所有Demo的示例地址: https://github.com/asleepyfish/chatgpt-demo

2.4.1 流式回答输出到IDEA控制台

代码如下:

@GetMapping("/streamChat")
public void streamChat(String content) {
    
    
    // OpenAiUtils.createStreamChatCompletion(content, System.out);
    // 下面的默认和上面这句代码一样,是输出结果到控制台
    OpenAiUtils.createStreamChatCompletion(content);
}

然后使用Postman或者其他可以发送Get请求的工具发送请求。

本次测试的结果如下面的Gif图所示

insérez la description de l'image ici

2.4.2 流式回答输出到浏览器页面

上述的方法中输出流传入的是System.out对象,该对象实际上就是一个PrintStream对象,会把输出结果展示到控制台。

如果需要将输出结果在浏览器展示,可以从前端传入一个HttpServletResponse response对象,拿到这个response以后将response.getOutputStream()这个输出流对象传入createStreamChatCompletion方法的入参中。同时,为了避免结果输出到浏览器产生乱码和支持流式输出,需要ContentTypeCharacterEncoding

具体代码如下:

@GetMapping("/streamChatWithWeb")
public void streamChatWithWeb(String content, HttpServletResponse response) throws IOException {
    
    
    // 需要指定response的ContentType为流式输出,且字符编码为UTF-8
    response.setContentType("text/event-stream");
    response.setCharacterEncoding("UTF-8");
    // 禁用缓存
    response.setHeader("Cache-Control", "no-cache");    
    OpenAiUtils.createStreamChatCompletion(content, response.getOutputStream());
}

测试结果过程的Gif图如下所示:

insérez la description de l'image ici

2.4.3 流式回答结合Vue输出到前端界面

调用的后端方法同2.4.2节方法streamChatWithWeb,前端只需要在界面传入问题,点击提问按钮即可返回结果流式输出到文本框中。

测试结果过程的Gif图如下所示:

insérez la description de l'image ici
Vue3 Demo的Git地址在文章开头有~

2.5 查询账单

查询账单提供了两个方法,金额单位均为美元(USD),且均未对小数位截取,可以根据需要自行选择保留结果小数点位数。

第一个是可以传入开始和结束日期,按照指定日期区间查询的方法:

public String billingUsage(String startDate, String endDate) {
    
    ...}

其中startDateendDate区间范围不超过100天。

第二个方法是查询从2022年1月1日距今的账单的方法:

public String billingUsage() {
    
    ...}

2.5.1 测试

测试代码如下:

@GetMapping("/billingUsage")
public void billingUsage() {
    
    
	String monthUsage = OpenAiUtils.billingUsage("2023-04-01", "2023-05-01");
	System.out.println("四月使用:" + monthUsage + "美元");
	String totalUsage = OpenAiUtils.billingUsage();
	System.out.println("一共使用:" + totalUsage + "美元");
}

测试结果如下:

四月使用:0.9864320000000001美元
一共使用:1.120594美元

3. 扩展

3.1 自定义OpenAiProxyService

由于之前的版本中使用@Bean的方式初始化OpenAiProxyServiceOpenAiUtils,导致一个SpringBoot中实例是唯一的。

但是有时候需要在项目里自定义多个OpenAiProxyService实例,来装配不同的ChatGPTProperties信息(可以实例化多个Token(sk-xxxxxxxxxxx)使用)。

所以在1.1.6版本中新增了自定义OpenAiProxyService功能。在维持原有SpringBoot项目中全局的一个OpenAiUtils实例的基础上,现在可以自定义不同的OpenAiProxyService实例,并且实例之间的属性是完全隔离的。

下面是一个Demo用来展示使用方法。

@GetMapping("/customToken")
public void customToken() {
    
    
	ChatGPTProperties chatGPTProperties = new ChatGPTProperties();
	chatGPTProperties.setToken("sk-002xxxxxxxxxxxxxxxxxxxxxxxxx");
	chatGPTProperties.setProxyHost("127.0.0.1");
	chatGPTProperties.setProxyPort(7890);
	OpenAiProxyService openAiProxyService = new OpenAiProxyService(chatGPTProperties, Duration.ZERO);
	// 直接使用new出来的openAiProxyService来调用方法,每个OpenAiProxyService都拥有自己的Token。
	// 这样在一个SpringBoot项目中,就可以有多个Token,可以有更多的免费额度供使用了
	openAiProxyService.createStreamChatCompletion("Java的三大特性是什么");
}

Dans la méthode ci-dessus, un nouvel ChatGPTPropertiesobjet est nouvellement créé et il est défini tokencomme sk-002xxxxxxxxxxxxxxxxxxxxxxxxx(ici, il n'est pas nécessaire de définir d'autres attributs sauf token, proxyHostet , car les autres attributs ont des valeurs par défaut. Si vous devez modifier d'autres attributs, vous pouvez définir Remarque : il n'y a pas de valeur par défaut pour sessionExpirationTime, ce qui signifie que la session n'a pas de délai d'expiration. Si vous devez définir le délai d'expiration de la session, veuillez définir cette valeur. )proxyPortChatGPTProperties

Et application.ymldéfini dans token, sk-001xxxxxxxxxxxxxxxxxxxxxxxxxce jeton est le seul pour le monde entier OpenAitils, de sorte qu'une OpenAiProxyServicenouvelle OpenAiProxyServiceinstance peut être générée via la nouvelle méthode de construction, et le deuxième paramètre de la méthode de construction Duration.ZEROpeut être rempli directement, indiquant que la demande d'appel Http n'a pas timed out Avec le temps, dans les mises à jour de version ultérieures, j'ajouterai une méthode de construction avec un seul paramètre d'entrée.

De cette façon, vous pouvez directement utiliser le nouveau openAiProxyServicepour appeler la méthode, chacune OpenAiProxyServiceayant son propre Token.

Dans un projet SpringBoot, il peut y avoir plus d'un Tokenet plusieurs quotas gratuits peuvent être utilisés.

3 affichage de l'assistant IA

Accédez au compte officiel WeChat et l'assistant AI peut répondre automatiquement.
insérez la description de l'image ici

Je suppose que tu aimes

Origine blog.csdn.net/qq_41821963/article/details/128992539
conseillé
Classement