Java调用ChatGPT(基于SpringBoot和Vue)实现连续对话、流式输出和自定义baseUrl

目录

  • 版本更新说明
  • 1. 配置阶段
    • 1.1 依赖引入
    • 1.2 配置application.yml文件
    • 1.3 注解添加
  • 2. 使用
    • 2.1 生成回答
      • 2.1.1 测试
    • 2.2 生成图片
      • 2.2.1 测试
    • 2.3 下载图片
      • 2.3.1 测试
    • 2.4 生成流式回答
      • 2.4.1 流式回答输出到IDEA控制台
      • 2.4.2 流式回答输出到浏览器页面
      • 2.4.3 流式回答结合Vue输出到前端界面
    • 2.5 查询账单和订阅
      • 2.5.1 测试
    • 2.6 自定义baseUrl
    • 2.7 模型(model)
    • 2.8 编辑(edit)
    • 2.9 向量(embeddings)
    • 2.10 转录(transcription)
    • 2.11 翻译(translation)
  • 3. 扩展
    • 3.1 自定义OpenAiProxyService
  • 4 自定义OpenAi服务端
    • 4.1 介绍
    • 4.2 测试
      • 4.2.1 基于SpringBoot使用OpenAiUtils
      • 4.2.2 基于Main方法使用OpenAiProxyService
  • 5 AI助手展示

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

本文Demo(SpringBoot和Main方法Demo均包括)的Git地址:https://github.com/asleepyfish/chatgpt-demo

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

后续使用方法和api版本更新均在Github的README.md文档更新,本博客暂停更新~

2023-05-28更新

制作了一个基于本文sdk包的对话网站,可前往http://chatgpt.alpacos.cn/体验。
[注]: 由于本人的服务器的带宽较低,首次加载页面可能会略有些慢,请耐心等待,详细使用说明请查看另一篇博客~ 👇
ChatGPT网页版(基于SpringBoot和Vue)

2023-07-17更新

所有的测试Demo均包括结合Spring框架的(ChatGPTController类中)和main方法使用(MainTest类中)Demo地址:https://github.com/asleepyfish/chatgpt-demo

版本更新说明

  • 1.1.5 增加查询账单功能billingUsage(单位:美元),可以选择传入开始和结束日期查询(最多100天),或者不传入参,此时表示查询所有日期账单。
  • 1.1.6 增加自定义OpenAiProxyService功能,支持单个SpringBoot中添加多个OpenAiProxyService实例,每个实例可以拥有个性化的参数;查询账单功能优化。
  • 1.2.0 增加subscription方法(查询订阅信息,包括订阅到期日和账号额度等信息,但是没有使用量情况,使用通过billingUsage方法查询使用量),增加billing方法,整合了subscriptionbillingUsage方法,出参包括订阅到期日、额度、使用量、余量等信息。增加对内部cache的多种操作,包括获取,赋值等操作。
  • 1.2.1 billing方法中出参dueDate取值逻辑修改,ChatGPTProperties类支持build链式创建对象。
  • 1.3.0 新增以下方法,每种方法均包含多种重载方法,具体使用请参考:https://github.com/asleepyfish/chatgpt-demo
    • listModelsgetModel
    • edit
    • embeddings
    • transcriptiontranslation
    • createImageEditcreateImageVariation
    • listFilesuploadFiledeleteFileretrieveFileretrieveFileContent
    • createFineTunecreateFineTuneCompletionlistFineTunesretrieveFineTunecancelFineTunelistFineTuneEventsdeleteFineTune
    • createModeration
  • 1.3.1 支持自定义baseUrl,默认为 https://api.openai.com/ ,配置参数在ChatGPTProperties类中,可通过application.yml配置。
  • 1.3.2 修复自定义baseUrl后无法访问bug,自定义baseUrl必须以/结尾。新增自定义属于自己的baseUrl示例。

1. 配置阶段

1.1 依赖引入

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

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

1.2 配置application.yml文件

application.yml文件中配置相关参数(Optional为可选参数)

参数解释
token申请的API KEYS
proxy-host (Optional)代理的ip
proxy-port (Optional)代理的端口
model (Optional)model可填可不填,默认即text-davinci-003
chat-model (Optional)可填可不填,默认即gpt-3.5-turbo (ChatGPT当前最强模型,生成回答使用的就是这个模型)
retries (Optional)指的是当chatgpt第一次请求回答失败时,重新请求的次数(增加该参数的原因是因为大量访问的原因,在某一个时刻,chatgpt服务将处于无法访问的情况,不填的默认值为5)
session-expiration-time (Optional)(单位(min))为这个会话在多久不访问后被销毁,这个值不填的时候,即表示所有问答处于同一个会话之下,相同user的会话永不销毁(增加请求消耗)
base-url (Optional)默认为 https://api.openai.com/ ,可不填

例:

chatgpt:token: sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx #必填
#  proxy-host: 127.0.0.1 #需要代理时必填
#  proxy-port: 7890 #需要代理时必填
#  model: text-davinci-003 #可选
#  chat-model: gpt-3.5-turbo #可选
#  retries: 10 #可选,默认为5
#  session-expiration-time: 30 #可选,不填则会话永不过期
#  base-url: https://apps.ichati.cn/1d6f32f8-b59d-46f8-85e9-7d434bxxxxxx/ #可选,默认为https://api.openai.com/,请记住务必以/结尾

其中token、proxy-host、proxy-port是必填的

上面的session-expiration-time参数很重要,是用来表示这个会话在多久不访问后被销毁,从而实现联系上下文的连续对话。

实现方式是通过ChatCompletionRequest中的user来区分某个会话,而session-expiration-time表示这个会话在多久不访问后被销毁。

如果这里看不懂请看2.1节示例

1.3 注解添加

启动类上加入图中的注解则将服务注入到Spring中。
在这里插入图片描述

2. 使用

2.1 生成回答

提供了工具类OpenAiUtils,里面提供了相关方法进行调用。
其中最简单的使用方法是:

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

入参content即输入的问题的字符串。但是不建议使用。

这里建议使用下面的方式,通过传入user的值,再结合session-expiration-time参数,可以实现指定某次会话,或者某个用户的连续对话。

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

还提供一个通用的静态方法是

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

入参ChatCompletionRequest 里包含模型的一些可调参数。

OpenAiUtils类中还提供了多个可供选择的静态方法,可以自行查看。

上述方法的返回参数是一个list,是因为调整参数返回答案n可以一次性返回多条不同的解答(nChatCompletionRequest类中一个参数)。

2.1.1 测试

测试代码:

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

Post请求

入参输入:Java序列化的方式

返回结果:

["\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接口的序列化可以更加灵活地控制序列化的过程。"
]

再次输入:有没有更加高效的序列化框架

返回结果:

["是的,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自带的序列化方式更快、更小、更灵活,可以根据具体的需求选择合适的框架。"
]

可以看出上述两次问答是在一次会话中的,而前面所说的参数session-expiration-time即这个user所代表的会话多久没被继续访问时的销毁时间。单位(min)

2.2 生成图片

最简单的使用方式是

OpenAiUtils.createImage(prompt);

入参表示生成图片的描述文字,还提供了一个通用的静态方法

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

入参CreateImageRequest中有一些可以使用的参数,其中n表示生成图片的数量,responseFormat表示生成图片的格式,格式中分为urlb64_json两种,如果希望返回的是url,则返回的url会在生成一个小时后消失,默认值是url

2.2.1 测试

测试代码

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

结果
默认情况下会生成一个url,点击去就可以看到图片。
在这里插入图片描述

2.3 下载图片

在3.2的基础上做了优化,直接使用responseFormatb64_json然后解析成图片返回。简单使用方式如下:

OpenAiUtils.downloadImage(prompt, response);

通用方式如下:

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

CreateImageRequest对象中设置的返回参数n大于1时,会将图片打包成一个zip包返回,当n等于1时直接返回图片。

2.3.1 测试

测试代码

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

发送get请求,然后选择Send and Download
在这里插入图片描述

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

在这里插入图片描述

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图所示

在这里插入图片描述

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-8response.setContentType("text/event-stream");response.setCharacterEncoding("UTF-8");// 禁用缓存response.setHeader("Cache-Control", "no-cache");    OpenAiUtils.createStreamChatCompletion(content, response.getOutputStream());
}

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

在这里插入图片描述

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

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

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

在这里插入图片描述
Vue3 Demo的Git地址在文章开头有~

2.5 查询账单和订阅

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

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

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

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

第二个方法是一个入参为可变参数的方法,当不传入参时,查询从2023年1月1日距今的账单的方法,如果有人的订阅日早于2023年1月1日可以传入自定义账单起始日期:

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

查询订阅提供了一个方法,这个方法的出参中包括了订阅到期日,总额度等信息:

public Subscription subscription() {...}

由于查询总额度和查询使用量是两个接口,这里封装了一个方法来将几个比较有用的参数统一返回的方法,方法如下:

public Billing billing(String... startDate) {...}

这个方法的入参也是一个可变入参,不传参时,startDate默认为2023-01-01,如果账单开始日早于该天,可以传入指定的startDate。出参Billing中有四个参数:dueDate(额度到期日),total(额度总量),usage(已使用量),balance(余额)。

2.5.1 测试

测试代码如下:

@GetMapping("/billing")
public void billing() {String monthUsage = OpenAiUtils.billingUsage("2023-04-01", "2023-05-01");log.info("四月使用:{}美元", monthUsage);String totalUsage = OpenAiUtils.billingUsage();log.info("一共使用:{}美元", totalUsage);String stageUsage = OpenAiUtils.billingUsage("2023-01-31");log.info("自从2023/01/31使用:{}美元", stageUsage);Subscription subscription = OpenAiUtils.subscription();log.info("订阅信息(包含到期日期,账户总额度等信息):{}", subscription);// dueDate为到期日,total为总额度,usage为使用量,balance为余额Billing totalBilling = OpenAiUtils.billing();log.info("历史账单信息:{}", totalBilling);// 默认不传参的billing方法的使用量usage从2023-01-01开始,如果用户的账单使用早于该日期,可以传入开始日期startDateBilling posibleStartBilling = OpenAiUtils.billing("2022-01-01");log.info("可能的历史账单信息:{}", posibleStartBilling);
}

测试结果如下:

四月使用:0.9864320000000001美元
一共使用:2.2074280000000002美元
自从2023/01/31使用:2.2074280000000001美元
订阅信息(包含到期日期,账户总额度等信息):Subscription(object=billing_subscription, hasPaymentMethod=false, canceled=false, canceledAt=null, delinquent=null, accessUntil=1688169600, softLimit=66667, hardLimit=83334, systemHardLimit=83334, softLimitUsd=4.00002, hardLimitUsd=5.00004, systemHardLimitUsd=5.00004, plan=Plan(title=Explore, id=free), accountName=Leo Mikey, poNumber=0, billingEmail=null, taxIds=null, billingAddress=null, businessAddress=null)
历史账单信息:Billing(dueDate=2023-07-01, total=5.00004, usage=2.2074280000000002, balance=2.7926119999999998)
可能的历史账单信息:Billing(dueDate=2023-07-01, total=5.00004, usage=2.2074280000000002, balance=2.7926119999999998)

2.6 自定义baseUrl

由于部分原因,用户可以选择搭建好的代理服务作为baseUrl,而不需要使用官方的https://api.openai.com/

这部分可以和第4节放在一起看

如果用户基于SpringBoot使用自定义baseUrl,可以参考下面的application.yml,配置chatgpt.base-url,如果不配置,则表示默认使用官方的https://api.openai.com/

chatgpt:token: sk-xxxxxxxxxxxxxxxxxxproxy-host: 127.0.0.1 #可选proxy-port: 7890 #可选model: text-davinci-003 #可选chat-model: gpt-3.5-turbo #可选retries: 10 #可选,默认为5session-expiration-time: 30 #可选,不填则会话永不过期base-url: https://openai.api2d.net/ #可选,默认为https://api.openai.com/

然后相关调用代码如下:

@PostMapping("/baseUrl")
public void baseUrl() {// 先在application.yml中配置chatgpt.base-urlSystem.out.println("models列表:" + OpenAiUtils.listModels());
}

如果用户不想和Spring集成,则可以使用main方法调用的方式。

下面为了测试方便性,均以main方法做示例,结合SpringBoot使用OpenAiUtils调用的方法请参考github上的demo示例。

main方法中直接使用请参考第3节扩展部分自定义OpenAiProxyService

如下所示:

public static void main(String[] args) {ChatGPTProperties properties = ChatGPTProperties.builder().token("sk-xxx").proxyHost("127.0.0.1").proxyPort(7890)// 自定义baseUrl,若不需要自定义baseUrl,下一行可以去掉.baseUrl("https://openai.api2d.net/").build();OpenAiProxyService openAiProxyService = new OpenAiProxyService(properties);System.out.println("models列表:" + openAiProxyService.listModels());
}

其中自定义了baseUrl为 https://openai.api2d.net/ ,并调用了listModels方法。

2.7 模型(model)

提供了两个与模型相关的方法:

// 列出全部models
List<Model> listModels() {...}
// 获取指定model信息
Model getModel(String model) {...}

测试代码如下:

ChatGPTProperties properties = ChatGPTProperties.builder().token("sk-xxx").proxyHost("127.0.0.1").proxyPort(7890).build();
OpenAiProxyService openAiProxyService = new OpenAiProxyService(properties);
System.out.println("models列表:" + openAiProxyService.listModels());
System.out.println("=============================================");
System.out.println("text-davinci-003信息:" + openAiProxyService.getModel("text-davinci-003"));

测试结果(截取如下):

models列表:[Model(id=whisper-1, object=model, ownedBy=openai-internal, permission=[Permission(id=modelperm-KlsZlfft3Gma8pI6A8rTnyjs,.....
=============================================
text-davinci-003信息:Model(id=text-davinci-003, object=model, ownedBy=openai-internal, permission=[Permission(id=modelperm-jepinXYt59ncUQrjQEIUEDyC, object=model_permission, created=1688551385, allowCreateEngine=false, allowSampling=true, allowLogProbs=false, allowSearchIndices=false, allowView=true, allowFineTuning=false, organization=*, group=null, isBlocking=false)], root=text-davinci-003, parent=null)

2.8 编辑(edit)

edit功能可以用来检查语句的拼写错误,代码的正确性等,api中重载了多种edit相关的方法,这里介绍最简单的一种,其他重载方法,可通过源码查看。

String edit(String input, String instruction) {...}

测试代码如下:

ChatGPTProperties properties = ChatGPTProperties.builder().token("sk-xxx").proxyHost("127.0.0.1").proxyPort(7890).build();
OpenAiProxyService openAiProxyService = new OpenAiProxyService(properties);
String input = "What day of the wek is it?";
String instruction = "Fix the spelling mistakes";
System.out.println("编辑前:" + input);
// 下面这句和openAiProxyService.edit(input, instruction, EditModelEnum.TEXT_DAVINCI_EDIT_001);是一样的,默认使用模型TEXT_DAVINCI_EDIT_001
System.out.println("编辑后:" + openAiProxyService.edit(input, instruction));
System.out.println("=============================================");
input = "    public static void mian([String] args) {\n" +"        system.in.println(\"hello world\");\n" +"    }";
instruction = "Fix the code mistakes";
System.out.println("修正代码前:\n" + input);
System.out.println("修正代码后:\n" + openAiProxyService.edit(input, instruction, EditModelEnum.CODE_DAVINCI_EDIT_001));

测试结果如下:

编辑前:What day of the wek is it?
编辑后:What day of the week is it today?=============================================
修正代码前:public static void mian([String] args) {system.in.println("hello world");}
修正代码后:public static void main(String[] args) {System.out.println("hello world");}

2.9 向量(embeddings)

有时候需要将文本内容转化成计算机可以识别到的向量形式,可以使用这个方法。api中重载了多种embeddings相关的方法,这里介绍最简单的一种,其他重载方法,可通过源码查看。

List<Double> embeddings(String text) {...}

测试代码如下:

ChatGPTProperties properties = ChatGPTProperties.builder().token("sk-xxx").proxyHost("127.0.0.1").proxyPort(7890).build();
OpenAiProxyService openAiProxyService = new OpenAiProxyService(properties);
// 单文本
String text = "Once upon a time";
System.out.println("文本:" + text);
System.out.println("文本的嵌入向量:" + openAiProxyService.embeddings(text));
System.out.println("=============================================");
// 文本数组
String[] texts = {"Once upon a time", "There was a princess"};
System.out.println("文本数组:" + Arrays.toString(texts));
EmbeddingRequest embeddingRequest = EmbeddingRequest.builder().model(EmbeddingModelEnum.TEXT_EMBEDDING_ADA_002.getModelName()).input(Arrays.asList(texts)).build();
System.out.println("文本数组的嵌入向量:" + openAiProxyService.embeddings(embeddingRequest));

测试结果截取如下:

文本:Once upon a time
文本的嵌入向量:[0.02122687, -0.02013961, -0.004614537, -0.011599556, -0.011213957, 0.0019817224, 0.0023404553, ...
文本数组:[Once upon a time, There was a princess]
文本数组的嵌入向量:EmbeddingResult(model=text-embedding-ada-002-v2, object=list, data=[Embedding(object=embedding, embedding=[0.02122687, -0.02013961, -0.004614537, -0.011599556, -0.011213957, 0.0019817224...

2.10 转录(transcription)

转录功能可以将诸如mp3mp4等格式的音频文件转化成文字输出。

最简单的一种使用方法如下,其他重载方法可通过代码查看。

String transcription(String filePath, AudioResponseFormatEnum audioResponseFormatEnum) {...}

下面是一首许嵩的《想象之中》的转录测试。

ChatGPTProperties properties = ChatGPTProperties.builder().token("sk-xxx").proxyHost("127.0.0.1").proxyPort(7890).build();
OpenAiProxyService openAiProxyService = new OpenAiProxyService(properties);
String filePath = "src/main/resources/audio/想象之中-许嵩.mp3";
System.out.println("语音文件转录后的json文本是:" + openAiProxyService.transcription(filePath, AudioResponseFormatEnum.JSON));
// File file = new File("src/main/resources/audio/想象之中-许嵩.mp3");
// System.out.println("语音文件转录后的json文本是:" + openAiProxyService.transcription(file, AudioResponseFormatEnum.JSON));

测试结果截取如下:

语音文件转录后的json文本是:{"text":"想像之中 想像之中 雨過一道彩虹 抬起了頭 瑟瑟灰色天空 想像之中 付出會有結果 毫無保留 信奉你的承諾 想像之中 這次要愛很久 我領略過 你眼裡的溫柔 熱戀以後 你忽然的冰凍 但若兩人丟給我去承受 想像中 很不同 想像中 一切都和後來不同 我承認 曾經那麼心動 你沒想像中那麼戀舊 回憶換不回你的溫柔 最後也不是故作冷漠 轉過頭 我怎麼又一滴淚落 我沒想像中那麼脆弱 分開後 形容也沒消瘦 一起踏過了幾座春秋 過了愛不是追逐佔有 想像之中 這次要愛很久 我領略過 你眼裡的溫柔 熱戀以後 你忽然的冰凍 但若兩人丟給我去承受 想像中 很不同 想像中 一切都和後來不同 我承認 曾經那麼心動 你沒想像中那麼戀舊 回憶換不回你的溫柔 最後也不是故作冷漠 轉過頭 我怎麼又一滴淚落 我沒想像中那麼脆弱 分開後 形容也沒消瘦 一起踏過了幾座春秋 過了愛不是追逐佔有 你沒想像中那麼戀舊 回憶換不回你的溫柔 最後也不是故作冷漠 轉過頭 我怎麼又一滴淚落 我沒想像中那麼脆弱 分開後 形容也沒消瘦 一起踏過了幾座春秋 領悟了愛不是追逐佔有"}

上述文字输出的时候是繁体,具体使用可以使用重载方法中一个代码TranscriptionRequest入参的方法,其中的language可以指定返回的语言,具体使用可以前往官网查看。

2.11 翻译(translation)

翻译功能可以将任意的音频文件翻译成英文。

最简单的一种使用方法如下,其他重载方法可通过代码查看。

String translation(String filePath, AudioResponseFormatEnum audioResponseFormatEnum) {...}

下面是一首许嵩的《想象之中》的翻译测试。

ChatGPTProperties properties = ChatGPTProperties.builder().token("sk-xxx").proxyHost("127.0.0.1").proxyPort(7890).build();
OpenAiProxyService openAiProxyService = new OpenAiProxyService(properties);
String filePath = "src/main/resources/audio/想象之中-许嵩.mp3";
System.out.println("语音文件翻译成英文后的json文本是:" + openAiProxyService.translation(filePath, AudioResponseFormatEnum.JSON));
// File file = new File("src/main/resources/audio/想象之中-许嵩.mp3");
// System.out.println("语音文件翻译成英文后的json文本是:" + openAiProxyService.translation(file, AudioResponseFormatEnum.JSON));

测试结果截取如下:

语音文件翻译成英文后的json文本是:{"text":"Translated by Hua Chenyu English Subs In my imagination, there will be results Without keeping your promise In my imagination, this time I will love for a long time I have experienced the tenderness in your eyes After falling in love, you suddenly freeze But if two people are thrown to me to bear In my imagination, it's very different In my imagination, everything is different from the later I admit that I used to be so heartbroken You are not as long-lasting as I imagined Memories can't exchange your tenderness In the end, it's not lonely and lonely Why am I crying again? ..."}

3. 扩展

3.1 自定义OpenAiProxyService

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

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

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

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

ChatGPTProperties properties = ChatGPTProperties.builder().token("sk-002xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx").proxyHost("127.0.0.1")// 代理ip.proxyHost("7890")// 代理端口.build();
OpenAiProxyService openAiProxyService = new OpenAiProxyService(properties);
// 直接使用new出来的openAiProxyService来调用方法,每个OpenAiProxyService都拥有自己的Token。
// 这样在一个SpringBoot项目中,就可以有多个Token,可以有更多的免费额度供使用了
openAiProxyService.createStreamChatCompletion("Java的三大特性是什么");

在上述方法中,新new了一个ChatGPTProperties对象,并且set了tokensk-002xxxxxxxxxxxxxxxxxxxxxxxxx(这里不需要设置除了tokenproxyHostproxyPort以外的其他属性,因为ChatGPTProperties的其他属性拥有默认值,如果需要对其他属性做修改,可以自行设置。注意:sessionExpirationTime没有默认值,表示会话没有过期时间,如果需要设置会话过期时间,请set该值。

而在application.yml中设置的tokensk-001xxxxxxxxxxxxxxxxxxxxxxxxx,这个token是给全局唯一的OpenAitils用的,这样就可以通过OpenAiProxyService的构造方法new出来一个新的OpenAiProxyService实例,其中构造方法的第二个参数直接填Duration.ZERO就好,表示Http调用请求没有超时时间,后续版本更新中,我会新增一个只有一个入参的构造方法。

这样直接使用new出来的openAiProxyService来调用方法,每个OpenAiProxyService都拥有自己的Token。

在一个SpringBoot项目中,就可以有多个Token,可以有更多的免费额度供使用了。

4 自定义OpenAi服务端

4.1 介绍

默认使用OpenAi服务的baseUrlhttps://api.openai.com/ ,众所周知的原因,很多人网络无法直连。如果服务是部署在国外服务器,或者拥有代理,配置proxy-hostproxy-port依旧可以直接访问 https://api.openai.com/ ,这个也是比较推荐的方式,毕竟这是直连openai的服务,最安全,提供的服务接口也最全。

但是很多人没用国外的服务器,也没有自己的代理,在这里提供一种解决方法,通过使用这种方法,来实现无需国外服务器,也无需代理即可访问OpenAi服务。

在这里先简单介绍一下反向代理的概念。

反向代理是一种用于隐藏服务端真实地址的技术。比如说真实地址是B,但是我们不希望用户直连B,让B的地址暴露,我们就可以使用反向代理,让A的请求转发到B。

在这里,我们可以将B理解成 https://api.openai.com/ ,由于我们不能直连 https://api.openai.com/ ,但是我们可以在一台可以直连 https://api.openai.com/ 的服务器上反向代理,给我们暴露一个网址A,我们将baseUrl设置为A,向A发送请求,服务器接受到后自动将请求转发到 https://api.openai.com/ ,并且将结果返回。这样的话,我们只需要指定baseUrl,都不需要设置代理proxy-hostproxy-port即可访问OpenAi的服务了。那现在的问题就是怎么简单的获取到这样的一个baseUrl了。

这里我找到了一个可以提供OpenAi代理的服务。访问https://www.ichati.cn/dashboard/products/tools,注册登录后选择白泽,点击立即使用。

image-20230718104126500

然后输入API-Key,点击开始部署(这里我测试只需要长度保持一致,后面几位的api-key可以随便填)。

image-20230718104238571

然后如下图所示生成了我们的baseUrl(注意,这里生成的网页最后没用斜杠/,使用服务的使用baseUrl需要在最后带/,例如 https://apps.ichati.cn/0a7699ac-bc73-4732-9263-55c1c01f56e3/ )。

image-20230718104412550

4.2 测试

在4.1节中已经生成了我们项目的baseUrl,且因为它给我们转发,我们可以任务,他的服务部署在一台可以直连 https://api.openai.com/ 的服务器上,也就自然不需要设置proxy-hostproxy-port了。

4.2.1 基于SpringBoot使用OpenAiUtils

先设置application.yml,只需要设置tokenbaseUrl即可。

image-20230718111150784

启动SpringBoot项目。

使用Post工具调用下面的接口生成图片。

@PostMapping("/createImage")
public List<String> createImage(String prompt) {List<String> imageList = OpenAiUtils.createImage(prompt);System.out.println(imageList);return imageList;}

image-20230718115911134

结果如下:

image-20230718115949339

访问该链接,就可以得到一个生成的图片~

4.2.2 基于Main方法使用OpenAiProxyService

下面是使用Main方法进行调用的具体代码,只需要设置tokenbaseUrl即可。

ChatGPTProperties properties = ChatGPTProperties.builder().token("sk-xxxx").baseUrl("https://apps.ichati.cn/0a7699ac-bc73-4732-9263-55c1c01f56e3/") // 这里需要填自己的baseUrl.build();OpenAiProxyService openAiProxyService = new OpenAiProxyService(properties);System.out.println(openAiProxyService.chatCompletion("Go写个Hello World程序"));

输入结果如下:

[package mainimport "fmt"func main() {fmt.Println("Hello, World!")
}]

5 AI助手展示

接入微信公众号,AI助手可自动回复。
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/12870.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

copilot平替tabnine解析

1.copilot 借着最近chatgpt大火的东风&#xff0c;copilot又重新火了一把。 什么是copilot&#xff1f;直接上wiki百科上的解释 GitHub Copilot是GitHub和OpenAI合作开发的一个人工智能工具&#xff0c;用户在使用Visual Studio Code、Microsoft Visual Studio、Vim、Cursor或…

ChatGPT 停售 Plus 会员!

公众号关注 “GitHubDaily” 设为 “星标”&#xff0c;每天带你逛 GitHub&#xff01; 今天凌晨 2 点&#xff0c;一位名为 anton 的网友发推表示&#xff0c;ChatGPT Plus 已无法开通。 给出的理由是&#xff0c;现在 GPT 需求量太大&#xff0c;严重超载&#xff0c;算力有点…

【数学建模】 灰色预测模型

数学建模——预测模型简介 https://www.cnblogs.com/somedayLi/p/9542835.html 灰色预测模型 https://blog.csdn.net/qq_39798423/article/details/89283000?ops_request_misc&request_id&biz_id102&utm_term%E7%81%B0%E8%89%B2%E9%A2%84%E6%B5%8B%E6%A8%…

文言一心,ChatGLM-6B和ChatGPT等模型概述

原文首发于博客文章大语言模型概况 定义 &#xff08;个人理解的&#xff09;大语言模型&#xff08;Large Language Model&#xff09;是一种基于深度学习技术的自然语言处理通用模型&#xff0c;它可以通过学习大规模文本数据的模式和规律&#xff0c;从而实现对自然语言的理…

Axure页面设置管理灰色,无法设置怎么办?

我昨天在知乎上找到AxurePR9以及对应的安装包&#xff0c;但是安装完后发现【项目】选项卡下面的页面样式管理器是灰色的&#xff0c;无法设置相关的参数。但是我把原来的软件给删掉了&#xff0c;没有截图保存。 后面我找到了一个方法&#xff0c;大家可以参照一下&#xff1…

错过了前三次的伟大革命(蒸汽机革命、电气革命、信息革命),GPT-4 你还要错过人工智能AI革命吗!!!

错过了前三次的伟大革命&#xff08;蒸汽机革命、电气革命、信息革命&#xff09;&#xff0c;GPT-4 你还要错过人工智能AI革命吗&#xff01;&#xff01;&#xff01; 看 GPT-4 是如何炼成绝世神功&#xff1a;葵花宝典&#xff1f; 欲练神功&#xff0c;不必自宫。西方不败—…

最贵的教育方式有望普及了

我们要学习的知识是一张网&#xff0c;这张网上每个节点都是知识点&#xff0c;知识点之间彼此关联。 在学习这个主题之前&#xff0c;张大胖可能已经掌握了A和D 而何小痩已经掌握了I和J 而一个教程/文章可能只涵盖了这些&#xff1a; 所以张大胖在看文章过程中&#xff0c;遇到…

【GPT-4】免费开源的 MiniGPT-4 —— 提供类似 GPT-4 的图像理解与对话能力,让你先人一步感受到图像对话的强大之处。

GPT-4 是一个大型多模态模型(接受图像和文本输入,提供文本输出),虽然在许多现实世界场景中的能力不如人类,但在各种专业和学术基准上表现出人类水平”,OpenAI 表示。 OpenAI 联合创始人Sam Altman 表示,它是“迄今为止功能最强大、最一致的模型”,能够使用图像和文本。…

2023异想大会|星尘数据CEO章磊:懒惰是第一生产力,ChatGPT给了我们一个懒惰的机会

5月18日&#xff0c;由《财经天下》、「市界」、《博客天下》联合举办的2023年异想大会在北京召开&#xff0c;大会以“想象创未来”为主题&#xff0c;邀请来自各领域的多名企业家、专家&#xff0c;探索下一个能够改变商业世界的“异想”。 在大会“天工开物——人工智能劈开…

对OpenAI重拳出击!美国政府出手「开源」ChatGPT,Altman惊慌连发3推

FTC突然对OpenAI展开调查&#xff0c;Altman连发3推澄清。FTC对阵OpenAI的大戏正缓缓拉开帷幕。 重磅&#xff01;美国联邦贸易委员会的调查说来就来&#xff01; 调查对象不是别人&#xff0c;正是风头正旺的OpenAI。 一封长达20页的调查要求书直接给了Sam Altman当头棒喝。…

【NLP】GPT-4 和 ChatGPT 要点

&#x1f50e;大家好&#xff0c;我是Sonhhxg_柒&#xff0c;希望你看完之后&#xff0c;能对你有所帮助&#xff0c;不足请指正&#xff01;共同学习交流&#x1f50e; &#x1f4dd;个人主页&#xff0d;Sonhhxg_柒的博客_CSDN博客 &#x1f4c3; &#x1f381;欢迎各位→点赞…

关于GPT-3和GPT-4,你需要知道都在这里

友情提示 提示&#xff1a;本文约3500个文字&#xff0c;字数较长&#xff0c;可直接点击序号进入相关目录阅读字数 文章目录 友情提示前言一、什么是 GPT-3、GPT-4 和 ChatGPT&#xff1f;二、对未来的担忧三、什么时候可以用GPT4&#xff1f;四、GPT-4用在什么地方五、GPT-4能…

OpenAI被曝要搞「App Store」,专卖ChatGPT应用,网友:快搭生态,让苹果微软靠边站...

丰色 发自 凹非寺量子位 | 公众号 QbitAI OpenAI被曝还要再搞一个App Store&#xff01;‍‍‍‍‍‍‍‍ 这次不是插件商店这样的“小打小闹”&#xff0c;而是真正的大模型超市。‍‍‍‍‍ 据The Information消息&#xff0c;OpenAI将与第三方合作&#xff0c;将他们定制的垂…

OpenAI放大招!推出史上最强「模型商店」,打通所有ChatGPT应用

来源&#xff1a;新智元 OpenAI又双叒叕放大招了&#xff01; 简单来说&#xff0c;Sam Altman打算把市面上的大模型拉一个平台&#xff0c;搞一个LLM版的App Store。 这样一来&#xff0c;AI模型的生态直接就给OpenAI抢完了。 这个平台属于是双向对接——开发者可以将根据自己…

【GPT-4 ChatGPT】第 1 章 :GPT-4 和 ChatGPT 基础知识

&#x1f50e;大家好&#xff0c;我是Sonhhxg_柒&#xff0c;希望你看完之后&#xff0c;能对你有所帮助&#xff0c;不足请指正&#xff01;共同学习交流&#x1f50e; &#x1f4dd;个人主页&#xff0d;Sonhhxg_柒的博客_CSDN博客 &#x1f4c3; &#x1f381;欢迎各位→点赞…

【ChatGPT】我们的 AI 安全方法 | Our approach to AI safety

【ChatGPT】我们的 AI 安全方法 | Our approach to AI safety 我们的 AI 安全方法 | Our approach to AI safetyBuilding increasingly safe AI systems | 构建越来越安全的人工智能系统Learning from real-world use to improve safeguards | 从实际使用中学习以改进保障措施P…

Web3中文|GPT-4超越GPT-3.5的五大看点

A Beautiful Cinderella Dwelling Eagerly Finally Gains Happiness Inspiring Jealous Kin Love Magically Nurtures Opulent Prince Quietly Rescues Slipper Triumphs Uniting Very Wondrously Xenial Youth Zealously 这是一段描述童话故事《灰姑娘》的内容&#xff0c;它出…

【让你惊呼的“神器”,ChatGPT inside】

让你惊呼的“神器”&#xff0c;ChatGPT inside ChatGPT 的横空出世&#xff0c;已经搅动了整个科技圈。而它给自然语言处理领域带来的革命性变革&#xff0c;也为很多初创公司和开发者打开了新世界的大门。 在过去&#xff0c;自然语言处理技术通常只被各大科技巨头藏私&…

如何更好的向ChatGPT提问以及应用场景探索

ChatGPT已经慢慢发展成为了一个生态&#xff0c;先前ChatGPT是不联网的&#xff0c;然而现在ChatGPT已经可以安装商店应用&#xff0c;可以让ChatGPT帮你安排行程订酒店等等&#xff0c;未来肯定接入更多应用&#xff0c;比如手机助手&#xff0c;智能音箱&#xff0c;电子宠物…

可汗学院创始人:GPT-4 将如何改变教育行业?

公众号关注 “GitHubDaily” 设为 “星标”&#xff0c;每天带你逛 GitHub&#xff01; 当你想了解 AI 将如何冲击某一个行业时&#xff0c;最好的做法就是去观察、了解该行业大佬的观点以及实践。 萨尔曼可汗&#xff0c;全球知名在线教育网站可汗学院创始人&#xff0c;毕业于…