Repository: mainpropath/AI-java Branch: master Commit: 948d411bfac1 Files: 215 Total size: 334.8 KB Directory structure: gitextract_iuc1x97d/ ├── README.md ├── ai-baidu/ │ ├── pom.xml │ └── src/ │ ├── main/ │ │ └── java/ │ │ └── com/ │ │ └── ai/ │ │ └── baidu/ │ │ ├── achieve/ │ │ │ ├── ApiData.java │ │ │ ├── Configuration.java │ │ │ ├── defaults/ │ │ │ │ ├── DefaultBaiduSessionFactory.java │ │ │ │ └── session/ │ │ │ │ ├── DefaultAggregationSession.java │ │ │ │ ├── DefaultChatSession.java │ │ │ │ ├── DefaultEmbeddingSession.java │ │ │ │ ├── DefaultImageSession.java │ │ │ │ └── Session.java │ │ │ └── standard/ │ │ │ ├── api/ │ │ │ │ └── BaiduApiServer.java │ │ │ └── session/ │ │ │ ├── AggregationSession.java │ │ │ ├── ChatSession.java │ │ │ ├── EmbeddingSession.java │ │ │ └── ImageSession.java │ │ ├── common/ │ │ │ ├── ApiUrl.java │ │ │ └── Usage.java │ │ ├── endPoint/ │ │ │ ├── auth/ │ │ │ │ └── resp/ │ │ │ │ └── AuthResponse.java │ │ │ ├── chat/ │ │ │ │ ├── Message.java │ │ │ │ ├── SearchResult.java │ │ │ │ ├── req/ │ │ │ │ │ └── ChatRequest.java │ │ │ │ └── resp/ │ │ │ │ └── ChatResponse.java │ │ │ ├── embedding/ │ │ │ │ ├── EmbeddingData.java │ │ │ │ ├── req/ │ │ │ │ │ └── EmbeddingRequest.java │ │ │ │ └── resp/ │ │ │ │ └── EmbeddingResponse.java │ │ │ └── images/ │ │ │ ├── ImageData.java │ │ │ ├── req/ │ │ │ │ └── ImageRequest.java │ │ │ └── resp/ │ │ │ └── ImageResponse.java │ │ └── interceptor/ │ │ └── ResponseInterceptor.java │ └── test/ │ └── java/ │ └── com/ │ └── ai/ │ └── baidu/ │ ├── ChatApiTest.java │ ├── EmbeddingApiTest.java │ └── ImageApiTest.java ├── ai-common/ │ ├── pom.xml │ └── src/ │ └── main/ │ └── java/ │ └── com/ │ └── ai/ │ └── common/ │ └── utils/ │ ├── Exceptions.java │ ├── ImageUtils.java │ ├── JsonUtils.java │ └── ValidationUtils.java ├── ai-core/ │ ├── pom.xml │ └── src/ │ └── main/ │ └── java/ │ └── com/ │ └── ai/ │ └── core/ │ ├── config/ │ │ └── BaseConfiguration.java │ ├── exception/ │ │ ├── BaseException.java │ │ ├── Constants.java │ │ └── IError.java │ ├── factory/ │ │ └── SessionFactory.java │ └── strategy/ │ ├── KeyStrategy.java │ └── impl/ │ ├── FirstKeyStrategy.java │ └── RandomKeyStrategy.java ├── ai-openai/ │ ├── pom.xml │ └── src/ │ ├── main/ │ │ └── java/ │ │ └── com/ │ │ └── ai/ │ │ └── openai/ │ │ ├── Product.java │ │ ├── Singleton.java │ │ ├── ThreadPrint.java │ │ ├── achieve/ │ │ │ ├── Configuration.java │ │ │ ├── defaults/ │ │ │ │ ├── DefaultOpenAiSessionFactory.java │ │ │ │ └── session/ │ │ │ │ ├── DefaultAggregationSession.java │ │ │ │ ├── DefaultAudioSession.java │ │ │ │ ├── DefaultChatSession.java │ │ │ │ ├── DefaultEmbeddingSession.java │ │ │ │ ├── DefaultFilesSession.java │ │ │ │ ├── DefaultFineTuningSession.java │ │ │ │ ├── DefaultImageSession.java │ │ │ │ ├── DefaultModelSession.java │ │ │ │ ├── DefaultModerationSession.java │ │ │ │ └── Session.java │ │ │ └── standard/ │ │ │ ├── api/ │ │ │ │ └── OpenaiApiServer.java │ │ │ └── session/ │ │ │ ├── AggregationSession.java │ │ │ ├── AudioSession.java │ │ │ ├── ChatSession.java │ │ │ ├── EmbeddingSession.java │ │ │ ├── FilesSession.java │ │ │ ├── FineTuningSession.java │ │ │ ├── ImageSession.java │ │ │ ├── ModelSession.java │ │ │ └── ModerationSession.java │ │ ├── common/ │ │ │ ├── ApiUrl.java │ │ │ ├── CommonListResponse.java │ │ │ └── Usage.java │ │ ├── endPoint/ │ │ │ ├── audio/ │ │ │ │ ├── req/ │ │ │ │ │ ├── SttCompletionRequest.java │ │ │ │ │ └── TtsCompletionRequest.java │ │ │ │ └── resp/ │ │ │ │ └── SttCompletionResponse.java │ │ │ ├── chat/ │ │ │ │ ├── ChatChoice.java │ │ │ │ ├── Parameters.java │ │ │ │ ├── QaChoice.java │ │ │ │ ├── ResponseFormat.java │ │ │ │ ├── msg/ │ │ │ │ │ ├── BaseMessage.java │ │ │ │ │ ├── Content.java │ │ │ │ │ ├── DefaultMessage.java │ │ │ │ │ ├── ImageUrl.java │ │ │ │ │ └── ImgMessage.java │ │ │ │ ├── req/ │ │ │ │ │ ├── BaseChatCompletionRequest.java │ │ │ │ │ ├── DefaultChatCompletionRequest.java │ │ │ │ │ ├── FuncChatCompletionRequest.java │ │ │ │ │ ├── ImgChatCompletionRequest.java │ │ │ │ │ └── QaCompletionRequest.java │ │ │ │ ├── resp/ │ │ │ │ │ ├── ChatCompletionResponse.java │ │ │ │ │ └── QaCompletionResponse.java │ │ │ │ └── tools/ │ │ │ │ ├── Tool.java │ │ │ │ ├── ToolCall.java │ │ │ │ ├── ToolCallFunction.java │ │ │ │ └── ToolFunction.java │ │ │ ├── embeddings/ │ │ │ │ ├── EmbeddingObject.java │ │ │ │ ├── req/ │ │ │ │ │ └── EmbeddingCompletionRequest.java │ │ │ │ └── resp/ │ │ │ │ └── EmbeddingCompletionResponse.java │ │ │ ├── files/ │ │ │ │ ├── FileObject.java │ │ │ │ └── resp/ │ │ │ │ └── DeleteFileResponse.java │ │ │ ├── fineTuning/ │ │ │ │ ├── FineTuneError.java │ │ │ │ ├── FineTuningEvent.java │ │ │ │ ├── HyperParameters.java │ │ │ │ ├── req/ │ │ │ │ │ ├── FineTuningRequest.java │ │ │ │ │ └── ListFineTuningRequest.java │ │ │ │ └── resp/ │ │ │ │ └── FineTuningResponse.java │ │ │ ├── images/ │ │ │ │ ├── ImageObject.java │ │ │ │ ├── req/ │ │ │ │ │ ├── CreateImageRequest.java │ │ │ │ │ ├── ImageEditRequest.java │ │ │ │ │ └── ImageVariationRequest.java │ │ │ │ └── resp/ │ │ │ │ └── CreateImageResponse.java │ │ │ ├── models/ │ │ │ │ ├── ModelObject.java │ │ │ │ └── resp/ │ │ │ │ └── DeleteFineTuneModelResponse.java │ │ │ └── moderations/ │ │ │ ├── Categories.java │ │ │ ├── CategoryScores.java │ │ │ ├── Result.java │ │ │ ├── req/ │ │ │ │ └── ModerationRequest.java │ │ │ └── resp/ │ │ │ └── ModerationResponse.java │ │ └── interceptor/ │ │ ├── HeaderInterceptor.java │ │ └── ResponseInterceptor.java │ └── test/ │ └── java/ │ └── com/ │ └── ai/ │ └── openai/ │ ├── AudioApiTest.java │ ├── ChatApiTest.java │ ├── EmbeddingApiTest.java │ ├── FilesApiTest.java │ ├── FineTuningApiTest.java │ ├── ImageApiTest.java │ ├── ModelApiTest.java │ └── ModerationApiTest.java ├── ai-spark/ │ ├── pom.xml │ └── src/ │ ├── main/ │ │ └── java/ │ │ └── com/ │ │ └── ai/ │ │ └── spark/ │ │ ├── achieve/ │ │ │ ├── ApiData.java │ │ │ ├── Configuration.java │ │ │ ├── defaults/ │ │ │ │ ├── DefaultSparkSessionFactory.java │ │ │ │ ├── listener/ │ │ │ │ │ ├── BaseListener.java │ │ │ │ │ ├── ChatListener.java │ │ │ │ │ ├── DocumentChatListener.java │ │ │ │ │ └── ImageUnderstandingListener.java │ │ │ │ └── session/ │ │ │ │ ├── DefaultAggregationSession.java │ │ │ │ ├── DefaultAudioSession.java │ │ │ │ ├── DefaultChatSession.java │ │ │ │ ├── DefaultDocumentSession.java │ │ │ │ ├── DefaultEmbeddingSession.java │ │ │ │ ├── DefaultImageSession.java │ │ │ │ └── Session.java │ │ │ └── standard/ │ │ │ ├── api/ │ │ │ │ └── SparkApiServer.java │ │ │ └── session/ │ │ │ ├── AggregationSession.java │ │ │ ├── AudioSession.java │ │ │ ├── ChatSession.java │ │ │ ├── DocumentSession.java │ │ │ ├── EmbeddingSession.java │ │ │ └── ImageSession.java │ │ ├── common/ │ │ │ ├── Constants.java │ │ │ ├── SparkApiUrl.java │ │ │ ├── Usage.java │ │ │ ├── UsageText.java │ │ │ └── utils/ │ │ │ └── AuthUtils.java │ │ ├── endPoint/ │ │ │ ├── audio/ │ │ │ │ ├── Audio.java │ │ │ │ ├── AudioHeader.java │ │ │ │ ├── AudioParameter.java │ │ │ │ ├── AudioPayload.java │ │ │ │ ├── AudioText.java │ │ │ │ ├── Oral.java │ │ │ │ ├── Pybuf.java │ │ │ │ ├── Tts.java │ │ │ │ ├── req/ │ │ │ │ │ └── AudioRequest.java │ │ │ │ └── resp/ │ │ │ │ └── AudioResponse.java │ │ │ ├── chat/ │ │ │ │ ├── Chat.java │ │ │ │ ├── ChatHeader.java │ │ │ │ ├── ChatParameter.java │ │ │ │ ├── ChatPayload.java │ │ │ │ ├── ChatText.java │ │ │ │ ├── Choice.java │ │ │ │ ├── Message.java │ │ │ │ ├── document/ │ │ │ │ │ └── ChatExtends.java │ │ │ │ ├── function/ │ │ │ │ │ ├── Function.java │ │ │ │ │ ├── FunctionParameter.java │ │ │ │ │ └── FunctionText.java │ │ │ │ ├── req/ │ │ │ │ │ ├── ChatRequest.java │ │ │ │ │ └── DocumentChatRequest.java │ │ │ │ └── resp/ │ │ │ │ ├── ChatResponse.java │ │ │ │ └── DocumentChatResponse.java │ │ │ ├── document/ │ │ │ │ ├── Data.java │ │ │ │ ├── req/ │ │ │ │ │ └── FileUploadRequest.java │ │ │ │ └── resp/ │ │ │ │ ├── DocumentSummaryResponse.java │ │ │ │ └── FileUploadResponse.java │ │ │ ├── embedding/ │ │ │ │ ├── Emb.java │ │ │ │ ├── EmbeddingHeader.java │ │ │ │ ├── EmbeddingMessage.java │ │ │ │ ├── EmbeddingParameter.java │ │ │ │ ├── EmbeddingPayload.java │ │ │ │ ├── Feature.java │ │ │ │ ├── req/ │ │ │ │ │ └── EmbeddingRequest.java │ │ │ │ └── resp/ │ │ │ │ └── EmbeddingResponse.java │ │ │ └── images/ │ │ │ ├── ImageChat.java │ │ │ ├── ImageHeader.java │ │ │ ├── ImageParameter.java │ │ │ ├── ImagePayload.java │ │ │ ├── ImageUnderstandingChat.java │ │ │ ├── ImageUnderstandingParameter.java │ │ │ ├── ImageUnderstandingPayload.java │ │ │ ├── req/ │ │ │ │ ├── ImageCreateRequest.java │ │ │ │ └── ImageUnderstandingRequest.java │ │ │ └── resp/ │ │ │ ├── ImageCreateResponse.java │ │ │ └── ImageUnderstandingResponse.java │ │ └── interceptor/ │ │ ├── BaseUrlInterceptor.java │ │ └── ResponseInterceptor.java │ └── test/ │ └── java/ │ └── com/ │ └── ai/ │ └── spark/ │ ├── AudioApiTest.java │ ├── ChatApiTest.java │ ├── DocumentApiTest.java │ ├── EmbeddingApiTest.java │ └── ImageApiTest.java ├── doc/ │ └── test/ │ └── test_file_upload.txt └── pom.xml ================================================ FILE CONTENTS ================================================ ================================================ FILE: README.md ================================================ ## 目录 - [**项目背景**](#项目背景) - [**安装**](#安装) - [**使用方式**](#使用方式) - [**示例**](#示例) - [**更新记录**](#更新记录) ## **项目背景** ## Star History [![Star History Chart](https://api.star-history.com/svg?repos=mainpropath/AI-java&type=Date)](https://star-history.com/#mainpropath/AI-java&Date) **基于本项目的大模型框架正在火速研发当中,项目地址:[AI-SmartFuse-Framework](https://github.com/mainpropath/AI-SmartFuse-Framework)** 随着人工智能技术的飞速发展,自然语言处理在各个领域都具有广泛的应用前景。聊天机器人作为其中一种受欢迎且实用的解决方案,能够与用户进行自然对话,并提供有价值的信息和服务。 为了更好更快更方便的开发大模型应用,我们启动了一个名为AI-java的项目,专门针对Java编程语言。该SDK旨在简化与各大模型API的交互,使Java开发者可以轻松地集成大模型的功能到他们的应用程序中。 该项目的主要目标如下: - **提供简单易用的接口:**我们致力于开发一个用户友好的SDK,提供简洁的方法和函数,使Java开发者能够轻松地与大模型进行通信。本SDK提供发送用户请求并接收生成的回复的便捷方法。 - **支持流式应答:**实时生成响应,不需要等待整个对话结束。能够快速获得反馈,更加流畅地进行对话。流式应答能够为用户提供更接近真实人类对话的体验。用户可以即时提出问题、进行追问或做出反应,而模型能够相应地作出回应和调整。 - **上下文管理:**大模型是基于上下文的,因此我们希望SDK能够支持上下文的管理,允许用户在对话过程中保持和更新上下文信息。 - **异常处理和错误处理:**我们将注重SDK的稳定性和可靠性,确保它能够有效地处理各种可能出现的错误和异常情况,并提供相应的异常处理机制。 - **示例和文档:**为了方便Java开发者快速上手使用SDK,我们将提供详细的示例代码和清晰的文档,以解释如何正确集成和使用本项目。 - **多厂商模型接入:**本项目旨在提供多个不同厂商的模型接入,大模型功能不应该局限于某一单一的模型。应当集各家之长。 - **高拓展性:**本项目所有模型功能都提供对应接口,默认实现一套接口方法,同时也可让用户根据接口实现自己的API调用方式。 ## **安装** **下载项目到本地,将项目 install 到本地 maven 仓库。** ![image-20231205204603312](doc/img/image-20231205204603312.png) **注意,由于本项目是多模块编写,想要使用哪一个厂商的模型API,请引入对应的依赖。** **如果使用openai相关模型功能,install 之后,在pom文件中可引入如下依赖。** ``` com.ai ai-openai 1.0 ``` **如果使用讯飞相关模型功能,install之后,在pom文件中引入如下依赖。** ``` com.ai ai-spark 1.0 ``` ## **使用方式** **本项目目前实现了chatGPT官方文档下 endpoints 各个板块全部的接口。正在完成讯飞星火模型相关API的编写。** 项目结构如下 ```java ├─ai-common ├─ai-openai openai相关API功能 ├─ai-spark 星火模型相关API功能 └─doc 测试相关的文件 ``` **不管是使用哪一个厂商的模型API,在我们的SDK当中,使用方式都是一致的。使用方式如下:(下面是openai相关功能的使用方式)** **具体的使用方式请参考测试类当中的测试方法。** ```java // 工厂创建聚合的session AggregationSession aggregationSession=factory.openAggregationSession(); // 通过聚合的session获取不同场景的会话,处理不同场景,进行解耦。 // 获取聊天会话窗口 aggregationSession.getChatSession(); // 获取文件会话窗口 aggregationSession.getFilesSession(); // 获取微调会话窗口 aggregationSession.getFineTuningSession(); // 获取图片会话窗口 aggregationSession.getImageSession(); // 获取模型会话窗口 aggregationSession.getModelSession(); // 获取音频会话窗口 aggregationSession.getAudioSession(); // 获取审核会话窗口 aggregationSession.getModerationSession(); // 获取嵌入会话窗口 aggregationSession.getEmbeddingSession(); ``` ## **示例** 示例相关的测试图片和语言文件在 doc/test 目录下。 openai相关功能测试如下所示,更多功能测试请参考测试类 [openai测试路径](https://github.com/mainpropath/AI-java/tree/dev/ai-openai/src/test/java/com/ai/openai) [讯飞星火测试路径](https://github.com/mainpropath/AI-java/tree/dev/ai-spark/src/test/java/com/ai/spark) **示例一:多轮对话** ```java public void test_chat_completions() { // 创建参数,上下文对话。 // 第一次的问题 DefaultChatCompletionRequest defaultChatCompletionRequest = DefaultChatCompletionRequest.BuildDefaultChatCompletionRequest("1+1="); // 第一次的回复 defaultChatCompletionRequest.addMessage(Constants.Role.ASSISTANT.getRoleName(), "2"); // 第二次的问题 defaultChatCompletionRequest.addMessage(Constants.Role.USER.getRoleName(), "2+2="); // 询问第二次的问题的结果 ChatCompletionResponse chatCompletionResponse = aggregationSession.getChatSession().chatCompletions(NULL, NULL, NULL, defaultChatCompletionRequest); // 解析结果 chatCompletionResponse.getChoices().forEach(e -> { log.info("测试结果:{}", e.getMessage()); }); } ``` **示例二:图片创作** ```java public void test_create_image() { CreateImageRequest createImageRequest = CreateImageRequest.BuildBaseCreateImageRequest("森林里有一只小熊,小熊在吃蜂蜜。"); List imageObjectList = aggregationSession.getImageSession().createImageCompletions(NULL, NULL, NULL, createImageRequest); log.info("测试结果:{}", imageObjectList); } ``` **示例三:文本转语音(主要是通过回调函数获取回传的音频数据)** ```java public void test_tts() throws InterruptedException { // 定义请求参数 TtsCompletionRequest ttsCompletionRequest = TtsCompletionRequest.builder() .model(TtsCompletionRequest.Model.tts_1.getModuleName())// 设置使用的模型 .input("你好,我是chatGPT") .voice(TtsCompletionRequest.Voice.alloy.getVoiceName())// 设置声音的样式 .build(); // 回传文件存放的路径 File file = new File("doc/test/test_tts.mp3"); // 添加回调函数,发送请求 aggregationSession.getAudioSession().ttsCompletions(NULL, NULL, NULL, ttsCompletionRequest, new Callback() { @Override public void onResponse(Call call, Response response) { try (InputStream inputStream = response.body().byteStream(); OutputStream os = new BufferedOutputStream(new FileOutputStream(file))) { // 创建文件 if (!file.exists()) { if (!file.getParentFile().exists()) file.getParentFile().mkdir(); file.createNewFile(); } byte data[] = new byte[10240]; int len; while ((len = inputStream.read(data, 0, 8192)) != -1) { os.write(data, 0, len); } } catch (IOException e) { e.printStackTrace(); } } @Override public void onFailure(Call call, Throwable t) { t.printStackTrace(); } } ); // 阻塞等待 new CountDownLatch(1).await(); } ``` ## **更新记录** 2024-01-24:完成星火模型对话、文档对话、图片生成、图片理解接口的实现。 2024-01-10:开始讯飞星火模型相关API的编写工作 2023-12-28:预启动其他模型的API编写工作 2023-12-14:修复BUG 2023-12-8:支持图片对话和函数对话 2023-12-7:优化测试用例,增加代码注释,丰富文档内容 2023-12-4:第一版SDK问世,支持官方 endpoints 下所有接口 **项目长期维护,欢迎向本项目提需求,欢迎star~~~** ================================================ FILE: ai-baidu/pom.xml ================================================ AI-java com.ai 1.0 4.0.0 ai-baidu UTF-8 UTF-8 1.8 1.8 1.8 4.13.2 com.ai ai-common 1.0 com.ai ai-core 1.0 junit junit ${junit.version} test ================================================ FILE: ai-baidu/src/main/java/com/ai/baidu/achieve/ApiData.java ================================================ package com.ai.baidu.achieve; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; /** * 记录用户API信息 */ @Data @Builder @NoArgsConstructor @AllArgsConstructor public class ApiData { private String appId; private String apiKey; private String secretKey; private String accessToken; } ================================================ FILE: ai-baidu/src/main/java/com/ai/baidu/achieve/Configuration.java ================================================ package com.ai.baidu.achieve; import com.ai.baidu.achieve.standard.api.BaiduApiServer; import com.ai.core.config.BaseConfiguration; import lombok.*; import okhttp3.sse.EventSource; import okhttp3.sse.EventSources; import org.jetbrains.annotations.NotNull; import java.util.List; /** * @Description: baidu 相关配置信息 **/ @Data @ToString(callSuper = true) @EqualsAndHashCode(callSuper = true) @NoArgsConstructor @AllArgsConstructor public class Configuration extends BaseConfiguration { /** * api 服务提供者 */ private BaiduApiServer baiduApiServer; /** * api Key 集合 */ @NotNull private List keyList; public ApiData getSystemApiData() { return (ApiData) this.getKeyStrategy().apply(keyList); } public EventSource.Factory createRequestFactory() { return EventSources.createFactory(this.getOkHttpClient()); } } ================================================ FILE: ai-baidu/src/main/java/com/ai/baidu/achieve/defaults/DefaultBaiduSessionFactory.java ================================================ package com.ai.baidu.achieve.defaults; import com.ai.baidu.achieve.Configuration; import com.ai.baidu.achieve.defaults.session.DefaultAggregationSession; import com.ai.baidu.achieve.standard.api.BaiduApiServer; import com.ai.baidu.achieve.standard.session.AggregationSession; import com.ai.baidu.interceptor.ResponseInterceptor; import com.ai.core.factory.SessionFactory; import lombok.AllArgsConstructor; import okhttp3.OkHttpClient; import okhttp3.logging.HttpLoggingInterceptor; import retrofit2.Retrofit; import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory; import retrofit2.converter.jackson.JacksonConverterFactory; import java.util.concurrent.TimeUnit; /** * @Description: baidu API Factory 会话工厂 **/ @AllArgsConstructor public class DefaultBaiduSessionFactory implements SessionFactory { private final Configuration configuration; @Override public OkHttpClient createHttpClient() { // 1. 日志配置 HttpLoggingInterceptor httpLoggingInterceptor = new HttpLoggingInterceptor(); httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.NONE); // 2. 开启 Http 客户端 OkHttpClient.Builder builder = new OkHttpClient.Builder() .addInterceptor(httpLoggingInterceptor) .addInterceptor(new ResponseInterceptor()) .connectTimeout(450, TimeUnit.SECONDS) .writeTimeout(450, TimeUnit.SECONDS) .readTimeout(450, TimeUnit.SECONDS); // 3. 检查是否需要代理 if (configuration.getProxy() != null) { builder.proxy(configuration.getProxy()); } return builder.build(); } @Override public BaiduApiServer createApiServer(OkHttpClient okHttpClient) { return new Retrofit.Builder() .baseUrl(configuration.getApiHost()) .client(okHttpClient) .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) .addConverterFactory(JacksonConverterFactory.create()) .build().create(BaiduApiServer.class); } @Override public AggregationSession openAggregationSession() { OkHttpClient okHttpClient = createHttpClient(); configuration.setOkHttpClient(okHttpClient); configuration.setBaiduApiServer(createApiServer(okHttpClient)); return new DefaultAggregationSession(configuration); } } ================================================ FILE: ai-baidu/src/main/java/com/ai/baidu/achieve/defaults/session/DefaultAggregationSession.java ================================================ package com.ai.baidu.achieve.defaults.session; import com.ai.baidu.achieve.Configuration; import com.ai.baidu.achieve.standard.session.AggregationSession; import com.ai.baidu.achieve.standard.session.ChatSession; import com.ai.baidu.achieve.standard.session.EmbeddingSession; import com.ai.baidu.achieve.standard.session.ImageSession; import static com.ai.common.utils.ValidationUtils.ensureNotNull; /** * @Description: 聚合各个类型的session **/ public class DefaultAggregationSession implements AggregationSession { private Configuration configuration; private volatile ChatSession chatSession; private volatile EmbeddingSession embeddingSession; private volatile ImageSession imageSession; public DefaultAggregationSession(Configuration configuration) { this.configuration = ensureNotNull(configuration, "configuration"); } @Override public ChatSession getChatSession() { if (chatSession == null) { synchronized (this) { if (chatSession == null) { chatSession = new DefaultChatSession(configuration); } } } return chatSession; } @Override public EmbeddingSession getEmbeddingSession() { if (embeddingSession == null) { synchronized (this) { if (embeddingSession == null) { embeddingSession = new DefaultEmbeddingSession(configuration); } } } return embeddingSession; } @Override public ImageSession getImageSession() { if (imageSession == null) { synchronized (this) { if (imageSession == null) { imageSession = new DefaultImageSession(configuration); } } } return imageSession; } } ================================================ FILE: ai-baidu/src/main/java/com/ai/baidu/achieve/defaults/session/DefaultChatSession.java ================================================ package com.ai.baidu.achieve.defaults.session; import cn.hutool.http.ContentType; import com.ai.baidu.achieve.Configuration; import com.ai.baidu.achieve.standard.session.ChatSession; import com.ai.baidu.common.ApiUrl; import com.ai.baidu.endPoint.chat.req.ChatRequest; import com.ai.baidu.endPoint.chat.resp.ChatResponse; import com.ai.common.utils.JsonUtils; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.ToString; import okhttp3.HttpUrl; import okhttp3.MediaType; import okhttp3.Request; import okhttp3.RequestBody; import okhttp3.sse.EventSource; import okhttp3.sse.EventSourceListener; import static com.ai.common.utils.ValidationUtils.ensureNotNull; /** * @description baidu 对话类会话 */ @Data @ToString(callSuper = true) @EqualsAndHashCode(callSuper = true) public class DefaultChatSession extends Session implements ChatSession { /** * 工厂事件 */ private EventSource.Factory factory; public DefaultChatSession(Configuration configuration) { this.setConfiguration(ensureNotNull(configuration, "configuration")); this.setBaiduApiServer(ensureNotNull(configuration.getBaiduApiServer(), "baiduApiServer")); this.factory = ensureNotNull(configuration.createRequestFactory(), "requestFactory"); } @Override public ChatResponse chat(String accessToken, ChatRequest chatRequest) { // 检查一下是否为空,为空根据设置的 keyStrategy 获取一个用户设置的 key return this.getBaiduApiServer().chat(checkAccessToken(accessToken), chatRequest).blockingGet(); } @Override public EventSource chat(String accessToken, ChatRequest chatRequest, EventSourceListener eventSourceListener) { // 将 accessToken 设置到请求路径上 HttpUrl.Builder urlBuilder = HttpUrl.parse(this.getConfiguration().getApiHost().concat(ApiUrl.ERNIE_Bot_4_0.getUrl())).newBuilder(); urlBuilder.addQueryParameter("access_token", checkAccessToken(accessToken)); // 发起请求 Request request = new Request.Builder() .url(urlBuilder.build().toString()) .post(RequestBody.create(MediaType.parse(ContentType.JSON.getValue()), JsonUtils.toJson(chatRequest))) .build(); return factory.newEventSource(request, eventSourceListener); } } ================================================ FILE: ai-baidu/src/main/java/com/ai/baidu/achieve/defaults/session/DefaultEmbeddingSession.java ================================================ package com.ai.baidu.achieve.defaults.session; import com.ai.baidu.achieve.Configuration; import com.ai.baidu.achieve.standard.session.EmbeddingSession; import com.ai.baidu.endPoint.embedding.EmbeddingData; import com.ai.baidu.endPoint.embedding.req.EmbeddingRequest; import com.ai.baidu.endPoint.embedding.resp.EmbeddingResponse; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.ToString; import java.util.List; import java.util.stream.IntStream; import static com.ai.common.utils.ValidationUtils.ensureNotNull; /** * @Description: 百度嵌入操作 **/ @Data @ToString(callSuper = true) @EqualsAndHashCode(callSuper = true) public class DefaultEmbeddingSession extends Session implements EmbeddingSession { public DefaultEmbeddingSession(Configuration configuration) { this.setConfiguration(ensureNotNull(configuration, "configuration")); this.setBaiduApiServer(ensureNotNull(configuration.getBaiduApiServer(), "baiduApiServer")); } @Override public EmbeddingResponse embedding(String accessToken, EmbeddingRequest embeddingRequest) { EmbeddingResponse embeddingResponse = this.getBaiduApiServer().embedding(checkAccessToken(accessToken), embeddingRequest).blockingGet(); List data = embeddingResponse.getData(); List input = embeddingRequest.getInput(); IntStream.range(0, Math.min(data.size(), input.size())) .forEach(i -> data.get(i).setContent(input.get(i))); return embeddingResponse; } } ================================================ FILE: ai-baidu/src/main/java/com/ai/baidu/achieve/defaults/session/DefaultImageSession.java ================================================ package com.ai.baidu.achieve.defaults.session; import com.ai.baidu.achieve.Configuration; import com.ai.baidu.achieve.standard.session.ImageSession; import com.ai.baidu.endPoint.images.req.ImageRequest; import com.ai.baidu.endPoint.images.resp.ImageResponse; import static com.ai.common.utils.ValidationUtils.ensureNotNull; /** * @Description: 图像生成 **/ public class DefaultImageSession extends Session implements ImageSession { public DefaultImageSession(Configuration configuration) { this.setConfiguration(ensureNotNull(configuration, "configuration")); this.setBaiduApiServer(ensureNotNull(configuration.getBaiduApiServer(), "baiduApiServer")); } @Override public ImageResponse text2image(String accessToken, ImageRequest imageRequest) { String s = checkAccessToken(accessToken); return this.getBaiduApiServer().text2image(s, imageRequest).blockingGet(); } } ================================================ FILE: ai-baidu/src/main/java/com/ai/baidu/achieve/defaults/session/Session.java ================================================ package com.ai.baidu.achieve.defaults.session; import cn.hutool.core.util.StrUtil; import com.ai.baidu.achieve.ApiData; import com.ai.baidu.achieve.Configuration; import com.ai.baidu.achieve.standard.api.BaiduApiServer; import lombok.Data; @Data public class Session { /** * 配置信息 */ private Configuration configuration; /** * OpenAI 接口 */ private BaiduApiServer baiduApiServer; public String checkAccessToken(String accessToken) { if (StrUtil.isEmpty(accessToken)) { // 先随机获取一个apidata,看是否设置了accessToken,如果没有设置,获取token设置进去,然后返回。 ApiData systemApiData = configuration.getSystemApiData(); if (StrUtil.isNotEmpty(systemApiData.getAccessToken())) { return systemApiData.getAccessToken(); } accessToken = baiduApiServer.getAccessToken(systemApiData.getApiKey(), systemApiData.getSecretKey()); systemApiData.setAccessToken(accessToken); } return accessToken; } } ================================================ FILE: ai-baidu/src/main/java/com/ai/baidu/achieve/standard/api/BaiduApiServer.java ================================================ package com.ai.baidu.achieve.standard.api; import com.ai.baidu.endPoint.auth.resp.AuthResponse; import com.ai.baidu.endPoint.chat.req.ChatRequest; import com.ai.baidu.endPoint.chat.resp.ChatResponse; import com.ai.baidu.endPoint.embedding.req.EmbeddingRequest; import com.ai.baidu.endPoint.embedding.resp.EmbeddingResponse; import com.ai.baidu.endPoint.images.req.ImageRequest; import com.ai.baidu.endPoint.images.resp.ImageResponse; import io.reactivex.Single; import retrofit2.http.Body; import retrofit2.http.POST; import retrofit2.http.Query; /** * @Description: baidu API接口 **/ public interface BaiduApiServer { /** * 鉴权接口 * * @param grantType 类型 * @param apiKey 百度千帆大模型平台 apiKey * @param secretKey 百度千帆大模型平台 secretKey * @return 返回参数 */ @POST("/oauth/2.0/token") Single auth(@Query("grant_type") String grantType, @Query("client_id") String apiKey, @Query("client_secret") String secretKey); /** * 获取鉴权的 accessToken * * @param apiKey 百度千帆大模型平台 apiKey * @param secretKey 百度千帆大模型平台 secretKey * @return 鉴权的 accessToken */ default String getAccessToken(String apiKey, String secretKey) { return getAccessToken("client_credentials", apiKey, secretKey); } /** * 获取鉴权的 accessToken * * @param grantType 类型 * @param apiKey 百度千帆大模型平台 apiKey * @param secretKey 百度千帆大模型平台 secretKey * @return 鉴权的 accessToken */ default String getAccessToken(String grantType, String apiKey, String secretKey) { return this.auth(grantType, apiKey, secretKey).blockingGet().getAccessToken(); } /** * 聊天接口 * * @param accessToken 鉴权的 accessToken * @param chatRequest 请求参数 * @return 返回数据 */ @POST("/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/completions_pro") Single chat(@Query("access_token") String accessToken, @Body ChatRequest chatRequest); /** * embedding 接口 * * @param accessToken 鉴权的 accessToken * @param embeddingRequest 请求参数 * @return 返回数据 */ @POST("/rpc/2.0/ai_custom/v1/wenxinworkshop/embeddings/embedding-v1") Single embedding(@Query("access_token") String accessToken, @Body EmbeddingRequest embeddingRequest); /** * 文生图接口 * * @param accessToken 鉴权的 accessToken * @param imageRequest 请求参数 * @return 返回数据 */ @POST("/rpc/2.0/ai_custom/v1/wenxinworkshop/text2image/sd_xl") Single text2image(@Query("access_token") String accessToken, @Body ImageRequest imageRequest); } ================================================ FILE: ai-baidu/src/main/java/com/ai/baidu/achieve/standard/session/AggregationSession.java ================================================ package com.ai.baidu.achieve.standard.session; /** * @Description: 聚合各大场景的session **/ public interface AggregationSession { /** * 获取对话会话窗口 */ ChatSession getChatSession(); /** * 获取嵌入会话窗口 */ EmbeddingSession getEmbeddingSession(); /** * 获取文生图会话窗口 */ ImageSession getImageSession(); } ================================================ FILE: ai-baidu/src/main/java/com/ai/baidu/achieve/standard/session/ChatSession.java ================================================ package com.ai.baidu.achieve.standard.session; import com.ai.baidu.endPoint.chat.req.ChatRequest; import com.ai.baidu.endPoint.chat.resp.ChatResponse; import okhttp3.sse.EventSource; import okhttp3.sse.EventSourceListener; /** * @Description: baidu 聊天会话窗口 **/ public interface ChatSession { default ChatResponse chat(ChatRequest chatRequest) { return chat(null, chatRequest); } /** * 聊天接口,如果传入的 accessToken 为空,会自动根据用户设置的 key 按照 key 的获取策略进行自动鉴权。 * * @param accessToken 鉴权的 accessToken * @param chatRequest 请求参数 * @return 返回参数 */ ChatResponse chat(String accessToken, ChatRequest chatRequest); default EventSource chat(ChatRequest chatRequest, EventSourceListener eventSourceListener) { return chat(null, chatRequest, eventSourceListener); } /** * 聊天接口流式返回 * * @param accessToken 鉴权的 accessToken * @param chatRequest 请求参数 * @param eventSourceListener 事件监听者 * @return 事件源 */ EventSource chat(String accessToken, ChatRequest chatRequest, EventSourceListener eventSourceListener); } ================================================ FILE: ai-baidu/src/main/java/com/ai/baidu/achieve/standard/session/EmbeddingSession.java ================================================ package com.ai.baidu.achieve.standard.session; import com.ai.baidu.endPoint.embedding.req.EmbeddingRequest; import com.ai.baidu.endPoint.embedding.resp.EmbeddingResponse; /** * @Description: 嵌入会话窗口 **/ public interface EmbeddingSession { default EmbeddingResponse embedding(EmbeddingRequest embeddingRequest) { return embedding(null, embeddingRequest); } /** * 嵌入 * * @param accessToken 鉴权的 accessToken * @param embeddingRequest 请求参数 * @return 请求结果 */ EmbeddingResponse embedding(String accessToken, EmbeddingRequest embeddingRequest); } ================================================ FILE: ai-baidu/src/main/java/com/ai/baidu/achieve/standard/session/ImageSession.java ================================================ package com.ai.baidu.achieve.standard.session; import com.ai.baidu.endPoint.images.req.ImageRequest; import com.ai.baidu.endPoint.images.resp.ImageResponse; /** * @Description: 图片会话窗口 **/ public interface ImageSession { /** * 文生图接口 * * @param accessToken 鉴权的 accessToken * @param imageRequest 请求参数 * @return 请求结果 */ ImageResponse text2image(String accessToken, ImageRequest imageRequest); default ImageResponse text2image(ImageRequest imageRequest) { return text2image(null, imageRequest); } } ================================================ FILE: ai-baidu/src/main/java/com/ai/baidu/common/ApiUrl.java ================================================ package com.ai.baidu.common; import lombok.AllArgsConstructor; import lombok.Getter; /** * 各接口API路径 */ @Getter @AllArgsConstructor public enum ApiUrl { ERNIE_Bot_4_0("/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/completions_pro"), ; private String url; } ================================================ FILE: ai-baidu/src/main/java/com/ai/baidu/common/Usage.java ================================================ package com.ai.baidu.common; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @Data @NoArgsConstructor @AllArgsConstructor @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public class Usage { /** * 问题tokens数 */ @JsonProperty("prompt_tokens") private Integer promptTokens; /** * 回答tokens数 */ @JsonProperty("completion_tokens") private Integer completionTokens; /** * tokens总数 */ @JsonProperty("total_tokens") private Integer totalTokens; } ================================================ FILE: ai-baidu/src/main/java/com/ai/baidu/endPoint/auth/resp/AuthResponse.java ================================================ package com.ai.baidu.endPoint.auth.resp; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @Data @NoArgsConstructor @AllArgsConstructor @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public class AuthResponse { @JsonProperty("refresh_token") private String refreshToken; /** * 有效期,Access Token的有效期。 * 说明:单位是秒,有效期30天 */ @JsonProperty("expires_in") private Integer expiresIn; @JsonProperty("session_key") private String sessionKey; /** * 访问凭证 */ @JsonProperty("access_token") private String accessToken; private String scope; @JsonProperty("session_secret") private String sessionSecret; /** * 错误码 * 说明:响应失败时返回该字段,成功时不返回 */ private String error; /** * 错误描述信息,帮助理解和解决发生的错误 * 说明:响应失败时返回该字段,成功时不返回 */ @JsonProperty("error_description") private String errorDescription; } ================================================ FILE: ai-baidu/src/main/java/com/ai/baidu/endPoint/chat/Message.java ================================================ package com.ai.baidu.endPoint.chat; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import lombok.*; @Data @Builder @NoArgsConstructor @AllArgsConstructor @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public class Message { /** * 当前支持以下: * user: 表示用户 * assistant: 表示对话助手 */ private String role; /** * 对话内容 */ private String content; /** * message作者 */ private String name; public static Message baseBuild(Role role, String content) { return Message.builder().role(role.getRoleName()).content(content).build(); } @Getter @AllArgsConstructor public enum Role { USER("user"), ASSISTANT("assistant"), ; private String RoleName; } } ================================================ FILE: ai-baidu/src/main/java/com/ai/baidu/endPoint/chat/SearchResult.java ================================================ package com.ai.baidu.endPoint.chat; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @Data @NoArgsConstructor @AllArgsConstructor @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public class SearchResult { /** * 序号 */ private Integer index; /** * 搜索结果URL */ private String url; /** * 搜索结果标题 */ private String title; } ================================================ FILE: ai-baidu/src/main/java/com/ai/baidu/endPoint/chat/req/ChatRequest.java ================================================ package com.ai.baidu.endPoint.chat.req; import com.ai.baidu.endPoint.chat.Message; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import java.io.Serializable; import java.util.ArrayList; import java.util.Arrays; import java.util.List; /** * 对话聊天参数,官方文档链接:https://cloud.baidu.com/doc/WENXINWORKSHOP/s/clntwmv7t#body%E5%8F%82%E6%95%B0 */ @Data @Builder @NoArgsConstructor @AllArgsConstructor @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public class ChatRequest implements Serializable { /** * 必传 * (1)messages成员不能为空,1个成员表示单轮对话,多个成员表示多轮对话,例如: * 3个成员示例,"messages": [ {"role": "user","content": "你好"},{"role":"assistant","content":"需要什么帮助"},{"role":"user","content":"自我介绍下"}] * (2)最后一个message为当前请求的信息,前面的message为历史对话信息 * (3)成员数目必须为奇数,成员中message的role值说明如下:奇数位messsage的role值必须为user,偶数位message的role值为assistant * (4)message中的content总长度和system字段总内容不能超过20000个字符,且不能超过5120 tokens */ private List messages; /** * (1)较高的数值会使输出更加随机,而较低的数值会使其更加集中和确定 * (2)默认0.8,范围 (0, 1.0],不能为0 */ private Double temperature; /** * (1)影响输出文本的多样性,取值越大,生成文本的多样性越强 * (2)默认0.8,取值范围 [0, 1.0] */ @JsonProperty("top_p") private Double topP; /** * 通过对已生成的token增加惩罚,减少重复生成的现象。说明: * (1)值越大表示惩罚越大 * (2)默认1.0,取值范围:[1.0, 2.0] */ @JsonProperty("penalty_score") private Double penaltyScore; /** * 是否以流式接口的形式返回数据,默认false */ private Boolean stream; /** * 模型人设,主要用于人设设定,例如,你是xxx公司制作的AI助手,说明: * (1)长度限制,最后一个message的content长度(即此轮对话的问题)和system字段总内容不能超过20000个字符,且不能超过5120 tokens */ private String system; /** * 生成停止标识,当模型生成结果以stop中某个元素结尾时,停止文本生成。说明: * (1)每个元素长度不超过20字符 * (2)最多4个元素 */ private List stop; /** * 否强制关闭实时搜索功能,默认false,表示不关闭 */ @JsonProperty("disable_search") private Boolean disableSearch; /** * 是否开启上角标返回,说明: * (1)开启后,有概率触发搜索溯源信息search_info,search_info内容见响应参数介绍 * (2)默认false,不开启 */ @JsonProperty("enable_citation") private Boolean enableCitation; /** * 指定模型最大输出token数,范围[2, 2048] */ @JsonProperty("max_output_tokens") private Integer maxOutputTokens; /** * 指定响应内容的格式,说明: * (1)可选值: * json_object:以json格式返回,可能出现不满足效果情况 * text:以文本格式返回 * (2)如果不填写参数response_format值,默认为text */ @JsonProperty("response_format") private String responseFormat; /** * 表示最终用户的唯一标识符 */ @JsonProperty("user_id") private String userId; public static ChatRequest baseBuild(Message.Role role, String content) { return ChatRequest.builder() .messages(new ArrayList<>(Arrays.asList(Message.baseBuild(role, content)))) .build(); } } ================================================ FILE: ai-baidu/src/main/java/com/ai/baidu/endPoint/chat/resp/ChatResponse.java ================================================ package com.ai.baidu.endPoint.chat.resp; import com.ai.baidu.common.Usage; import com.ai.baidu.endPoint.chat.SearchResult; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import java.io.Serializable; import java.util.List; @Data @NoArgsConstructor @AllArgsConstructor @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public class ChatResponse implements Serializable { /** * 本轮对话的id */ private String id; /** * 回包类型 * chat.completion:多轮对话返回 */ private String Object; /** * 时间戳 */ private Integer created; /** * 表示当前子句的序号。只有在流式接口模式下会返回该字段 */ @JsonProperty("sentence_id") private Integer sentenceId; /** * 表示当前子句是否是最后一句。只有在流式接口模式下会返回该字段 */ @JsonProperty("is_end") private Boolean isEnd; /** * 当前生成的结果是否被截断 */ @JsonProperty("is_truncated") private Boolean isTruncated; /** * 输出内容标识,说明: * · normal:输出内容完全由大模型生成,未触发截断、替换 * · stop:输出结果命中入参stop中指定的字段后被截断 * · length:达到了最大的token数,根据EB返回结果is_truncated来截断 * · content_filter:输出内容被截断、兜底、替换为**等 */ @JsonProperty("finish_reason") private String finishReason; /** * 搜索数据,当请求参数enable_citation为true并且触发搜索时,会返回该字段 */ @JsonProperty("search_info") private List searchInfo; /** * 对话返回结果 */ private String result; /** * 表示用户输入是否存在安全,是否关闭当前会话,清理历史会话信息 * true:是,表示用户输入存在安全风险,建议关闭当前会话,清理历史会话信息 * false:否,表示用户输入无安全风险 */ @JsonProperty("need_clear_history") private Boolean needClearHistory; /** * 说明: * 0:正常返回 * 其他:非正常 */ private Integer flag; /** * 当need_clear_history为true时,此字段会告知第几轮对话有敏感信息,如果是当前问题,ban_round=-1 */ @JsonProperty("ban_round") private Integer banRound; /** * token统计信息 */ private Usage usage; } ================================================ FILE: ai-baidu/src/main/java/com/ai/baidu/endPoint/embedding/EmbeddingData.java ================================================ package com.ai.baidu.endPoint.embedding; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @Data @NoArgsConstructor @AllArgsConstructor @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public class EmbeddingData { /** * 固定值"embedding" */ private String object; /** * embedding 内容 */ private double[] embedding; /** * 序号 */ private Integer index; /** * 原文 */ @JsonIgnore private String content; } ================================================ FILE: ai-baidu/src/main/java/com/ai/baidu/endPoint/embedding/req/EmbeddingRequest.java ================================================ package com.ai.baidu.endPoint.embedding.req; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import java.util.List; /** * 嵌入请求体,官方文档链接:https://cloud.baidu.com/doc/WENXINWORKSHOP/s/alj562vvu */ @Data @Builder @NoArgsConstructor @AllArgsConstructor @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public class EmbeddingRequest { /** * 必传 * 输入文本以获取embeddings。说明: * (1)不能为空List,List的每个成员不能为空字符串 * (2)文本数量不超过16 * (3)每个文本token数不超过384且长度不超过1000个字符 */ private List input; /** * 表示最终用户的唯一标识符 */ @JsonProperty("user_id") private String userId; public static EmbeddingRequest baseBuild(List input) { return EmbeddingRequest.builder().input(input).build(); } } ================================================ FILE: ai-baidu/src/main/java/com/ai/baidu/endPoint/embedding/resp/EmbeddingResponse.java ================================================ package com.ai.baidu.endPoint.embedding.resp; import com.ai.baidu.common.Usage; import com.ai.baidu.endPoint.embedding.EmbeddingData; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import java.util.List; /** * 嵌入返回体,官方文档链接:https://cloud.baidu.com/doc/WENXINWORKSHOP/s/alj562vvu */ @Data @NoArgsConstructor @AllArgsConstructor @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public class EmbeddingResponse { /** * 本轮对话的id */ private String id; /** * 回包类型,固定值“embedding_list” */ private String Object; /** * 时间戳 */ private Integer created; /** * embedding信息,data成员数和文本数量保持一致 */ private List data; /** * token统计信息,token数 = 汉字数+单词数*1.3 (仅为估算逻辑) */ private Usage usage; } ================================================ FILE: ai-baidu/src/main/java/com/ai/baidu/endPoint/images/ImageData.java ================================================ package com.ai.baidu.endPoint.images; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @Data @NoArgsConstructor @AllArgsConstructor @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public class ImageData { /** * 固定值"image" */ private String object; /** * 图片base64编码内容 */ @JsonProperty("b64_image") private String b64Image; /** * 序号 */ private Integer index; } ================================================ FILE: ai-baidu/src/main/java/com/ai/baidu/endPoint/images/req/ImageRequest.java ================================================ package com.ai.baidu.endPoint.images.req; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.*; import java.io.Serializable; /** * 文生图,官方文档路径:https://cloud.baidu.com/doc/WENXINWORKSHOP/s/Klkqubb9w#header%E5%8F%82%E6%95%B0 */ @Data @Builder @NoArgsConstructor @AllArgsConstructor @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public class ImageRequest implements Serializable { /** * 必传 * 提示词,即用户希望图片包含的元素。长度限制为1024字符,建议中文或者英文单词总数量不超过150个 */ private String prompt; /** * 反向提示词,即用户希望图片不包含的元素。长度限制为1024字符,建议中文或者英文单词总数量不超过150个 */ @JsonProperty("negative_prompt") private String negativePrompt; /** * 生成图片长宽,默认值 1024x1024,取值范围如下: * ["768x768", "768x1024", "1024x768", "576x1024", "1024x576", "1024x1024"] */ private String size; /** * 生成图片数量,说明: * · 默认值为1 * · 取值范围为1-4 * · 单次生成的图片较多及请求较频繁可能导致请求超时 */ private Integer n; /** * 迭代轮次,说明: * · 默认值为20 * · 取值范围为10-50 */ private Integer steps; /** * 采样方式,默认值:Euler a,可选值如下(释义参考): * · Euler * · Euler a * · DPM++ 2M * · DPM++ 2M Karras * · LMS Karras * · DPM++ SDE * · DPM++ SDE Karras * · DPM2 a Karras * · Heun * · DPM++ 2M SDE * · DPM++ 2M SDE Karras * · DPM2 * · DPM2 Karras * · DPM2 a * · LMS */ @JsonProperty("sampler_index") private String samplerIndex; /** * 随机种子,说明: * · 不设置时,自动生成随机数 * · 取值范围 [0, 4294967295] */ private Integer seed; /** * 提示词相关性,说明:默认值为5,取值范围0-30 */ @JsonProperty("cfg_scale") private Double cfgScale; /** * 生成风格。说明: * (1)可选值: * · Base:基础风格 * · 3D Model:3D模型 * · Analog Film:模拟胶片 * · Anime:动漫 * · Cinematic:电影 * · Comic Book:漫画 * · Craft Clay:工艺黏土 * · Digital Art:数字艺术 * · Enhance:增强 * · Fantasy Art:幻想艺术 * · lsometric:等距风格 * · Line Art:线条艺术 * · Lowpoly:低多边形 * · Neonpunk:霓虹朋克 * · Origami:折纸 * · Photographic:摄影 * · Pixel Art:像素艺术 * · Texture:纹理 * (2)默认值为Base */ private String style; /** * 表示最终用户的唯一标识符 */ @JsonProperty("user_id") private String userId; public static ImageRequest baseBuild(String prompt) { return ImageRequest.builder().prompt(prompt).build(); } @Getter @AllArgsConstructor public enum ImgSize { SIZE_768_768("768x768"), SIZE_768_1024("768x1024"), SIZE_576_1024("576x1024"), SIZE_1024_768("1024x768"), SIZE_1024_576("1024x576"), SIZE_1024_1024("1024x1024"), ; private String size; } @Getter @AllArgsConstructor public enum ImgStyle { Base("Base"), model3D("3D Model"), AnalogFilm("Analog Film"), Anime("Anime"), Cinematic("Cinematic"), ComicBook("Comic Book"), CraftClay("Craft Clay"), DigitalArt("Digital Art"), Enhance("Enhance"), FantasyArt("Fantasy Art"), lsometric("lsometric"), LineArt("Line Art"), Lowpoly("Lowpoly"), Neonpunk("Neonpunk"), Origami("Origami"), Photographic("Photographic"), PixelArt("Pixel Art"), Texture("Texture"), ; private String style; } } ================================================ FILE: ai-baidu/src/main/java/com/ai/baidu/endPoint/images/resp/ImageResponse.java ================================================ package com.ai.baidu.endPoint.images.resp; import com.ai.baidu.common.Usage; import com.ai.baidu.endPoint.images.ImageData; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import java.io.Serializable; import java.util.List; @Data @NoArgsConstructor @AllArgsConstructor @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public class ImageResponse implements Serializable { /** * 请求的id */ private String id; /** * 回包类型。image:图像生成返回 */ private String object; /** * 时间戳 */ private Integer created; /** * 生成图片结果 */ private List data; /** * token统计信息,token数 = 汉字数+单词数*1.3 (仅为估算逻辑) */ private Usage usage; } ================================================ FILE: ai-baidu/src/main/java/com/ai/baidu/interceptor/ResponseInterceptor.java ================================================ package com.ai.baidu.interceptor; import lombok.extern.slf4j.Slf4j; import okhttp3.Interceptor; import okhttp3.Request; import okhttp3.Response; import java.io.IOException; /** * 返回信息拦截器 */ @Slf4j public class ResponseInterceptor implements Interceptor { @Override public Response intercept(Chain chain) throws IOException { // 1. 获取 req 和 resp Request original = chain.request(); Response response = chain.proceed(original); if (!response.isSuccessful() && response.body() != null) { log.error("--------> 请求异常:{}", response.body().string()); } return response; } } ================================================ FILE: ai-baidu/src/test/java/com/ai/baidu/ChatApiTest.java ================================================ package com.ai.baidu; import com.ai.baidu.achieve.ApiData; import com.ai.baidu.achieve.Configuration; import com.ai.baidu.achieve.defaults.DefaultBaiduSessionFactory; import com.ai.baidu.achieve.standard.session.AggregationSession; import com.ai.baidu.endPoint.chat.Message; import com.ai.baidu.endPoint.chat.req.ChatRequest; import com.ai.baidu.endPoint.chat.resp.ChatResponse; import com.ai.core.strategy.impl.FirstKeyStrategy; import lombok.extern.slf4j.Slf4j; import okhttp3.Response; import okhttp3.sse.EventSource; import okhttp3.sse.EventSourceListener; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.junit.Before; import org.junit.Test; import java.util.ArrayList; import java.util.Arrays; import java.util.concurrent.CountDownLatch; /** * @Description: 测试聊天接口相关接口功能 */ @Slf4j public class ChatApiTest { private AggregationSession aggregationSession; private Configuration configuration; @Before public void test_BaiduSessionFactory() { // 1. 创建配置类 this.configuration = new Configuration(); // 2. 设置请求地址,若有代理商或者代理服务器,可填写为代理服务器的请求路径 configuration.setApiHost("https://aip.baidubce.com"); // 3. 设置鉴权所需的API Key,可设置多个。 ApiData apiData = ApiData.builder() .apiKey("**************************") .secretKey("**************************") .appId("**************************") .build(); configuration.setKeyList(Arrays.asList(apiData)); // 4. 设置请求时 key 的使用策略,默认实现了:随机获取 和 固定第一个Key 两种方式。 configuration.setKeyStrategy(new FirstKeyStrategy()); // configuration.setKeyStrategy(new RandomKeyStrategy()); // 5. 设置代理,若不需要可不设置 // configuration.setProxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress("127.0.0.1", 7890))); // 6. 创建 session 工厂,制造不同场景的 session DefaultBaiduSessionFactory factory = new DefaultBaiduSessionFactory(configuration); this.aggregationSession = factory.openAggregationSession(); } /** * 测试鉴权接口 */ @Test public void test_auth() { // 获取用户配置的ApiData ApiData systemApiData = configuration.getSystemApiData(); // 鉴权 String accessToken = configuration.getBaiduApiServer().getAccessToken(systemApiData.getApiKey(), systemApiData.getSecretKey()); System.out.println(accessToken); } /** * 测试聊天功能 */ @Test public void test_chat() { // 发起聊天,chat接口如果传入的 accessToken 为空,会自动根据用户设置的信息进行鉴权 ChatResponse response = aggregationSession .getChatSession()// 获取 chatSession .chat(null, ChatRequest.baseBuild(Message.Role.USER, "Introduce the city Beijing"));// 构造一个基础的聊天请求体 System.out.println(response.getResult()); System.out.println(response.getUsage()); } @Test public void test_chat_multiple() { // 构造对话 Message msg1 = Message.baseBuild(Message.Role.USER, "请记住我的名字叫小明"); Message msg2 = Message.baseBuild(Message.Role.ASSISTANT, "好的"); Message msg3 = Message.baseBuild(Message.Role.USER, "我的名字叫什么?"); ArrayList messages = new ArrayList<>(); messages.add(msg1); messages.add(msg2); messages.add(msg3); // 构造参数 ChatRequest request = ChatRequest.builder().messages(messages).build(); // 发起请求 ChatResponse response = aggregationSession.getChatSession().chat(null, request); System.out.println(response.getResult()); System.out.println(response.getUsage()); } @Test public void test_chat_stream() throws InterruptedException { ChatRequest request = ChatRequest.baseBuild(Message.Role.USER, "你能讲一个笑话吗?"); request.setStream(true);// 设置流式返回 // 发起聊天,chat接口如果传入的 accessToken 为空,会自动根据用户设置的信息进行鉴权 aggregationSession.getChatSession()// 获取 chatSession .chat(null, request, new EventSourceListener() { @Override public void onEvent(@NotNull EventSource eventSource, @Nullable String id, @Nullable String type, @NotNull String data) { log.info("测试结果 id:{} type:{} data:{}", id, type, data); } @Override public void onFailure(@NotNull EventSource eventSource, @Nullable Throwable t, @Nullable Response response) { log.error("失败 code:{} message:{}", response.code(), response.message()); } }); new CountDownLatch(1).await(); } } ================================================ FILE: ai-baidu/src/test/java/com/ai/baidu/EmbeddingApiTest.java ================================================ package com.ai.baidu; import com.ai.baidu.achieve.ApiData; import com.ai.baidu.achieve.Configuration; import com.ai.baidu.achieve.defaults.DefaultBaiduSessionFactory; import com.ai.baidu.achieve.standard.session.AggregationSession; import com.ai.baidu.endPoint.embedding.EmbeddingData; import com.ai.baidu.endPoint.embedding.req.EmbeddingRequest; import com.ai.baidu.endPoint.embedding.resp.EmbeddingResponse; import com.ai.core.strategy.impl.FirstKeyStrategy; import org.junit.Before; import org.junit.Test; import java.util.ArrayList; import java.util.Arrays; import java.util.List; /** * @Description: 嵌入相关功能点测试 **/ public class EmbeddingApiTest { private AggregationSession aggregationSession; private Configuration configuration; @Before public void test_BaiduSessionFactory() { // 1. 创建配置类 this.configuration = new Configuration(); // 2. 设置请求地址,若有代理商或者代理服务器,可填写为代理服务器的请求路径 configuration.setApiHost("https://aip.baidubce.com"); // 3. 设置鉴权所需的API Key,可设置多个。 ApiData apiData = ApiData.builder() .apiKey("**************************") .secretKey("**************************") .appId("**************************") .build(); configuration.setKeyList(Arrays.asList(apiData)); // 4. 设置请求时 key 的使用策略,默认实现了:随机获取 和 固定第一个Key 两种方式。 configuration.setKeyStrategy(new FirstKeyStrategy()); // configuration.setKeyStrategy(new RandomKeyStrategy()); // 5. 设置代理,若不需要可不设置 // configuration.setProxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress("127.0.0.1", 7890))); // 6. 创建 session 工厂,制造不同场景的 session DefaultBaiduSessionFactory factory = new DefaultBaiduSessionFactory(configuration); this.aggregationSession = factory.openAggregationSession(); } /** * 测试嵌入接口 */ @Test public void test_embedding() { List input = new ArrayList<>(); input.add("你好"); input.add("世界"); EmbeddingRequest embeddingRequest = EmbeddingRequest.baseBuild(input); EmbeddingResponse embeddingResponse = aggregationSession.getEmbeddingSession().embedding(null, embeddingRequest); for (EmbeddingData e : embeddingResponse.getData()) { System.out.println(e); } } } ================================================ FILE: ai-baidu/src/test/java/com/ai/baidu/ImageApiTest.java ================================================ package com.ai.baidu; import com.ai.baidu.achieve.ApiData; import com.ai.baidu.achieve.Configuration; import com.ai.baidu.achieve.defaults.DefaultBaiduSessionFactory; import com.ai.baidu.achieve.standard.session.AggregationSession; import com.ai.baidu.endPoint.images.ImageData; import com.ai.baidu.endPoint.images.req.ImageRequest; import com.ai.baidu.endPoint.images.resp.ImageResponse; import com.ai.common.utils.ImageUtils; import com.ai.core.strategy.impl.FirstKeyStrategy; import org.junit.Before; import org.junit.Test; import java.util.Arrays; import java.util.List; /** * @Description: 图片相关功能点测试 **/ public class ImageApiTest { private AggregationSession aggregationSession; private Configuration configuration; @Before public void test_BaiduSessionFactory() { // 1. 创建配置类 this.configuration = new Configuration(); // 2. 设置请求地址,若有代理商或者代理服务器,可填写为代理服务器的请求路径 configuration.setApiHost("https://aip.baidubce.com"); // 3. 设置鉴权所需的API Key,可设置多个。 ApiData apiData = ApiData.builder() .apiKey("**************************") .secretKey("**************************") .appId("**************************") .build(); configuration.setKeyList(Arrays.asList(apiData)); // 4. 设置请求时 key 的使用策略,默认实现了:随机获取 和 固定第一个Key 两种方式。 configuration.setKeyStrategy(new FirstKeyStrategy()); // configuration.setKeyStrategy(new RandomKeyStrategy()); // 5. 设置代理,若不需要可不设置 // configuration.setProxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress("127.0.0.1", 7890))); // 6. 创建 session 工厂,制造不同场景的 session DefaultBaiduSessionFactory factory = new DefaultBaiduSessionFactory(configuration); this.aggregationSession = factory.openAggregationSession(); } @Test public void test_text2image() { ImageRequest imageRequest = ImageRequest.baseBuild("画一个哆啦A梦"); ImageResponse imageResponse = aggregationSession.getImageSession().text2image(imageRequest); // 得到结果当中的base64 图片字符串 List data = imageResponse.getData(); for (int i = 0; i < data.size(); i++) { ImageUtils.convertBase64StrToImage(data.get(i).getB64Image(), "D:\\chatGPT-api\\AI-java\\doc\\test\\test_baidu_create_image_" + i + ".png"); } } } ================================================ FILE: ai-common/pom.xml ================================================ AI-java com.ai 1.0 4.0.0 ai-common UTF-8 UTF-8 1.8 1.8 1.8 2.9.0 2.0.6 2.8.5 2.13.3 5.8.18 4.9.3 4.10.0 1.18.26 0.2.0 2.0.32 4.13.2 org.slf4j slf4j-api ${slf4j.version} org.slf4j slf4j-simple ${slf4j.version} com.google.code.gson gson ${gson.version} com.fasterxml.jackson.core jackson-databind ${jackson.version} cn.hutool hutool-all ${hutool.version} com.squareup.okhttp3 okhttp-sse ${okhttp.version} com.squareup.okhttp3 logging-interceptor ${logging-interceptor.version} com.squareup.retrofit2 retrofit ${retrofit2.version} com.squareup.retrofit2 converter-jackson ${retrofit2.version} com.squareup.retrofit2 adapter-rxjava2 ${retrofit2.version} junit junit ${junit.version} test org.jetbrains annotations RELEASE compile com.knuddels jtokkit ${jtokkit.version} org.projectlombok lombok ${lombok.version} compile com.alibaba fastjson ${fastjson.version} ================================================ FILE: ai-common/src/main/java/com/ai/common/utils/Exceptions.java ================================================ package com.ai.common.utils; /** * 异常工具类 */ public class Exceptions { public static IllegalArgumentException illegalArgument(String format, Object... args) { return new IllegalArgumentException(String.format(format, args)); } public static RuntimeException runtime(String format, Object... args) { return new RuntimeException(String.format(format, args)); } } ================================================ FILE: ai-common/src/main/java/com/ai/common/utils/ImageUtils.java ================================================ package com.ai.common.utils; import javax.imageio.ImageIO; import java.awt.image.BufferedImage; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; import java.util.Base64; public class ImageUtils { /** * 图片转Base64字符串 * * @param imageFileName * @return */ public static String convertImageToBase64Str(String imageFileName) { ByteArrayOutputStream baos = null; try { //获取图片类型 String suffix = imageFileName.substring(imageFileName.lastIndexOf(".") + 1); //构建文件 File imageFile = new File(imageFileName); //通过ImageIO把文件读取成BufferedImage对象 BufferedImage bufferedImage = ImageIO.read(imageFile); //构建字节数组输出流 baos = new ByteArrayOutputStream(); //写入流 ImageIO.write(bufferedImage, suffix, baos); //通过字节数组流获取字节数组 byte[] bytes = baos.toByteArray(); //获取JDK8里的编码器Base64.Encoder转为base64字符 return Base64.getEncoder().encodeToString(bytes); } catch (Exception e) { e.printStackTrace(); } finally { try { if (baos != null) { baos.close(); } } catch (IOException e) { e.printStackTrace(); } } return null; } /** * Base64字符串转图片 * * @param base64String * @param imageFileName */ public static void convertBase64StrToImage(String base64String, String imageFileName) { ByteArrayInputStream bais = null; try { //获取图片类型 String suffix = imageFileName.substring(imageFileName.lastIndexOf(".") + 1); //获取JDK8里的解码器Base64.Decoder,将base64字符串转为字节数组 byte[] bytes = Base64.getDecoder().decode(base64String); //构建字节数组输入流 bais = new ByteArrayInputStream(bytes); //通过ImageIO把字节数组输入流转为BufferedImage BufferedImage bufferedImage = ImageIO.read(bais); //构建文件 File imageFile = new File(imageFileName); //写入生成文件 ImageIO.write(bufferedImage, suffix, imageFile); } catch (Exception e) { e.printStackTrace(); } finally { try { if (bais != null) { bais.close(); } } catch (IOException e) { e.printStackTrace(); } } } } ================================================ FILE: ai-common/src/main/java/com/ai/common/utils/JsonUtils.java ================================================ package com.ai.common.utils; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; public class JsonUtils { public static final ObjectMapper objectMapper = new ObjectMapper(); public static T fromJson(String json, Class valueType) { try { return objectMapper.readValue(json, valueType); } catch (JsonProcessingException e) { e.printStackTrace(); } return null; } public static String toJson(Object object) { try { return objectMapper.writeValueAsString(object); } catch (JsonProcessingException e) { e.printStackTrace(); } return null; } } ================================================ FILE: ai-common/src/main/java/com/ai/common/utils/ValidationUtils.java ================================================ package com.ai.common.utils; import java.util.Collection; import static com.ai.common.utils.Exceptions.illegalArgument; public class ValidationUtils { public static T ensureNotNull(T object, String name) { if (object == null) { throw illegalArgument("%s cannot be null", name); } return object; } public static > T ensureNotEmpty(T collection, String name) { if (collection == null || collection.isEmpty()) { throw illegalArgument("%s cannot be null or empty", name); } return collection; } public static String ensureNotBlank(String string, String name) { if (string == null || string.trim().isEmpty()) { throw illegalArgument("%s cannot be null or blank", name); } return string; } public static void ensureTrue(boolean expression, String msg) { if (!expression) { throw illegalArgument(msg); } } public static int ensureGreaterThanZero(Integer i, String name) { if (i == null || i <= 0) { throw illegalArgument("%s must be greater than zero, but is: %s", name, i); } return i; } public static double ensureBetween(Double d, double min, double max, String name) { if (d == null || d < min || d > max) { throw illegalArgument("%s must be between %s and %s, but is: %s", name, min, max, d); } return d; } public static int ensureBetween(Integer i, int min, int max, String name) { if (i == null || i < min || i > max) { throw illegalArgument("%s must be between %s and %s, but is: %s", name, min, max, i); } return i; } } ================================================ FILE: ai-core/pom.xml ================================================ AI-java com.ai 1.0 4.0.0 ai-core UTF-8 UTF-8 1.8 1.8 1.8 com.ai ai-common 1.0 ================================================ FILE: ai-core/src/main/java/com/ai/core/config/BaseConfiguration.java ================================================ package com.ai.core.config; import com.ai.core.strategy.KeyStrategy; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import okhttp3.OkHttpClient; import org.jetbrains.annotations.NotNull; import java.net.Proxy; /** * 各个模型配置基础类 */ @Data @NoArgsConstructor @AllArgsConstructor public class BaseConfiguration { /** * api 请求客户端 */ private OkHttpClient okHttpClient; /** * 请求地址(很多情况下,这个apiHost都是一个摆设) */ @NotNull private String apiHost; /** * 代理信息 */ private Proxy proxy; /** * 获取key的策略 */ private KeyStrategy keyStrategy; } ================================================ FILE: ai-core/src/main/java/com/ai/core/exception/BaseException.java ================================================ package com.ai.core.exception; import lombok.Getter; @Getter public class BaseException extends RuntimeException { private final String msg; private final int code; public BaseException(IError error) { super(error.msg()); this.code = error.code(); this.msg = error.msg(); } public BaseException(String msg) { super(msg); this.code = Constants.ErrorMsg.SYS_ERROR.code(); this.msg = msg; } public BaseException() { super(Constants.ErrorMsg.SYS_ERROR.msg()); this.code = Constants.ErrorMsg.SYS_ERROR.code(); this.msg = Constants.ErrorMsg.SYS_ERROR.msg(); } } ================================================ FILE: ai-core/src/main/java/com/ai/core/exception/Constants.java ================================================ package com.ai.core.exception; import lombok.AllArgsConstructor; import lombok.Getter; import java.util.HashMap; import java.util.Map; /** * @description 通用类 */ public class Constants { public static final String NULL = "NULL"; public static final String API_KEY = "apiKey"; public static final String API_HOST = "apiHost"; public static final String URL = "url"; public static final Map ERROR_MSG_MAP = new HashMap<>(); static { ERROR_MSG_MAP.put(ErrorMsg.OPENAI_AUTHENTICATION_ERROR.code(), ErrorMsg.OPENAI_AUTHENTICATION_ERROR.msg()); ERROR_MSG_MAP.put(ErrorMsg.OPENAI_LIMIT_ERROR.code(), ErrorMsg.OPENAI_LIMIT_ERROR.msg()); ERROR_MSG_MAP.put(ErrorMsg.OPENAI_SERVER_ERROR.code(), ErrorMsg.OPENAI_SERVER_ERROR.msg()); } public enum ErrorMsg implements IError { MESSAGE_NOT_NUL(500, "Message 不能为空"), API_KEYS_NOT_NUL(500, "API KEYS 不能为空"), NO_ACTIVE_API_KEYS(500, "没有可用的API KEYS"), SYS_ERROR(500, "系统繁忙"), PARAM_ERROR(501, "参数异常"), RETRY_ERROR(502, "请求异常,请重试~"), OPENAI_AUTHENTICATION_ERROR(401, "身份验证无效/提供的 API 密钥不正确/您必须是组织的成员才能使用 API"), OPENAI_LIMIT_ERROR(429, "达到请求的速率限制/您超出了当前配额,请检查您的计划和帐单详细信息/发动机当前过载,请稍后重试"), OPENAI_SERVER_ERROR(500, "服务器在处理您的请求时出错"), ; private int code; private String msg; ErrorMsg(int code, String msg) { this.code = code; this.msg = msg; } public String msg() { return this.msg; } public int code() { return this.code; } } /** * 官网支持的请求角色类型为:system、user、assistant * system:用来设置 assistant 的行为 * user:用于指导 assistant * assistant:消息帮助存储更早的响应 */ @Getter @AllArgsConstructor public enum Role { SYSTEM("system"), USER("user"), ASSISTANT("assistant"), ; private String RoleName; } } ================================================ FILE: ai-core/src/main/java/com/ai/core/exception/IError.java ================================================ package com.ai.core.exception; public interface IError { String msg(); int code(); } ================================================ FILE: ai-core/src/main/java/com/ai/core/factory/SessionFactory.java ================================================ package com.ai.core.factory; import okhttp3.OkHttpClient; public interface SessionFactory { /** * 创建聚合过后的session * * @return 默认的聚合session */ Session openAggregationSession(); /** * 获取 Api 信息 * * @param okHttpClient 客户端 * @return api信息 */ ApiServer createApiServer(OkHttpClient okHttpClient); /** * 获取 httpClient * * @return 客户端 */ OkHttpClient createHttpClient(); } ================================================ FILE: ai-core/src/main/java/com/ai/core/strategy/KeyStrategy.java ================================================ package com.ai.core.strategy; /** * @Description: API Key 获取策略 */ public interface KeyStrategy { R apply(T t); } ================================================ FILE: ai-core/src/main/java/com/ai/core/strategy/impl/FirstKeyStrategy.java ================================================ package com.ai.core.strategy.impl; import com.ai.core.strategy.KeyStrategy; import java.util.List; public class FirstKeyStrategy implements KeyStrategy, T> { @Override public T apply(List keyList) { return keyList.get(0); } } ================================================ FILE: ai-core/src/main/java/com/ai/core/strategy/impl/RandomKeyStrategy.java ================================================ package com.ai.core.strategy.impl; import cn.hutool.core.util.RandomUtil; import com.ai.core.strategy.KeyStrategy; import java.util.List; public class RandomKeyStrategy implements KeyStrategy, T> { @Override public T apply(List keyList) { return RandomUtil.randomEle(keyList); } } ================================================ FILE: ai-openai/pom.xml ================================================ AI-java com.ai 1.0 4.0.0 ai-openai UTF-8 UTF-8 1.8 1.8 1.8 4.13.2 com.ai ai-common 1.0 com.ai ai-core 1.0 junit junit ${junit.version} test ================================================ FILE: ai-openai/src/main/java/com/ai/openai/Product.java ================================================ package com.ai.openai; public class Product { private String str1; private String str2; public Product(Builder builder) { this.str1 = builder.str1; this.str2 = builder.str2; } public static void main(String[] args) { Product build = new Builder().setStr1("str1").setStr2("str2").build(); } public static class Builder { private static String str1; private static String str2; public Builder() { } public Builder setStr1(String str1) { this.str1 = str1; return this; } public Builder setStr2(String str2) { this.str2 = str2; return this; } public Product build() { return new Product(this); } } } ================================================ FILE: ai-openai/src/main/java/com/ai/openai/Singleton.java ================================================ package com.ai.openai; public class Singleton { private static volatile Singleton instance; private Singleton() { } public static Singleton getInstance() { if (instance == null) { synchronized (Singleton.class) { if (instance == null) { instance = new Singleton(); } } } return instance; } } ================================================ FILE: ai-openai/src/main/java/com/ai/openai/ThreadPrint.java ================================================ package com.ai.openai; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; class LockPrinter { private static final Lock lock = new ReentrantLock(); private static final Condition condition = lock.newCondition(); private static int number = 0; public static void main(String[] args) { new Thread(() -> LockPrinter.printNumber(1), "A").start(); new Thread(() -> LockPrinter.printNumber(2), "B").start(); new Thread(() -> LockPrinter.printNumber(3), "C").start(); } public static void printNumber(int target) { while (number <= 10) { try { lock.lock(); if ((number % 3 + 1) != target) condition.await(); else { System.out.println(Thread.currentThread().getName() + " : " + target); number++; condition.signalAll(); } } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } } } } class SyncPrinter { private static int number = 0; public static void main(String[] args) { new Thread(() -> SyncPrinter.printNumber(1), "A").start(); new Thread(() -> SyncPrinter.printNumber(2), "B").start(); new Thread(() -> SyncPrinter.printNumber(3), "C").start(); } public static void printNumber(int target) { while (number <= 10) { if (number % 3 + 1 == target) synchronized (SyncPrinter.class) { if (number % 3 + 1 == target) { System.out.println(Thread.currentThread().getName() + " : " + target); number++; } } } } } ================================================ FILE: ai-openai/src/main/java/com/ai/openai/achieve/Configuration.java ================================================ package com.ai.openai.achieve; import com.ai.core.config.BaseConfiguration; import com.ai.openai.achieve.standard.api.OpenaiApiServer; import lombok.*; import okhttp3.sse.EventSource; import okhttp3.sse.EventSources; import org.jetbrains.annotations.NotNull; import java.util.List; /** * @Description: openai 相关配置信息 **/ @Data @ToString(callSuper = true) @EqualsAndHashCode(callSuper = true) @NoArgsConstructor @AllArgsConstructor public class Configuration extends BaseConfiguration { /** * api 服务提供者 */ private OpenaiApiServer openaiApiServer; /** * api Key 集合 */ @NotNull private List keyList; public EventSource.Factory createRequestFactory() { return EventSources.createFactory(this.getOkHttpClient()); } public String getSystemApiData() { return (String) this.getKeyStrategy().apply(keyList); } } ================================================ FILE: ai-openai/src/main/java/com/ai/openai/achieve/defaults/DefaultOpenAiSessionFactory.java ================================================ package com.ai.openai.achieve.defaults; import com.ai.core.factory.SessionFactory; import com.ai.openai.achieve.Configuration; import com.ai.openai.achieve.defaults.session.DefaultAggregationSession; import com.ai.openai.achieve.standard.api.OpenaiApiServer; import com.ai.openai.achieve.standard.session.AggregationSession; import com.ai.openai.interceptor.HeaderInterceptor; import com.ai.openai.interceptor.ResponseInterceptor; import lombok.AllArgsConstructor; import okhttp3.OkHttpClient; import okhttp3.logging.HttpLoggingInterceptor; import retrofit2.Retrofit; import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory; import retrofit2.converter.jackson.JacksonConverterFactory; import java.util.concurrent.TimeUnit; /** * @description OpenAi API Factory 会话工厂 */ @AllArgsConstructor public class DefaultOpenAiSessionFactory implements SessionFactory { private final Configuration configuration; @Override public OkHttpClient createHttpClient() { // 1. 日志配置 HttpLoggingInterceptor httpLoggingInterceptor = new HttpLoggingInterceptor(); httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.NONE); // 2. 开启 Http 客户端 OkHttpClient.Builder builder = new OkHttpClient.Builder() .addInterceptor(httpLoggingInterceptor) .addInterceptor(new HeaderInterceptor(configuration.getKeyList(), configuration.getApiHost(), configuration.getKeyStrategy())) .addInterceptor(new ResponseInterceptor()) .connectTimeout(450, TimeUnit.SECONDS) .writeTimeout(450, TimeUnit.SECONDS) .readTimeout(450, TimeUnit.SECONDS); // 3. 检查是否需要代理 if (configuration.getProxy() != null) { builder.proxy(configuration.getProxy()); } return builder.build(); } @Override public OpenaiApiServer createApiServer(OkHttpClient okHttpClient) { return new Retrofit.Builder() .baseUrl(configuration.getApiHost()) .client(okHttpClient) .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) .addConverterFactory(JacksonConverterFactory.create()) .build().create(OpenaiApiServer.class); } @Override public AggregationSession openAggregationSession() { OkHttpClient okHttpClient = createHttpClient(); configuration.setOkHttpClient(okHttpClient); configuration.setOpenaiApiServer(createApiServer(okHttpClient)); return new DefaultAggregationSession(configuration); } } ================================================ FILE: ai-openai/src/main/java/com/ai/openai/achieve/defaults/session/DefaultAggregationSession.java ================================================ package com.ai.openai.achieve.defaults.session; import com.ai.openai.achieve.Configuration; import com.ai.openai.achieve.standard.session.*; import static com.ai.common.utils.ValidationUtils.ensureNotNull; /** * @Description: 聚合各个类型的session **/ public class DefaultAggregationSession implements AggregationSession { private Configuration configuration; private volatile AudioSession audioSession; private volatile ChatSession chatSession; private volatile EmbeddingSession embeddingSession; private volatile FineTuningSession fineTuningSession; private volatile FilesSession filesSession; private volatile ImageSession imageSession; private volatile ModelSession modelSession; private volatile ModerationSession moderationSession; public DefaultAggregationSession(Configuration configuration) { this.configuration = ensureNotNull(configuration, "configuration"); } public Configuration getConfiguration() { return configuration; } @Override public AudioSession getAudioSession() { if (audioSession == null) { synchronized (this) { if (audioSession == null) { audioSession = new DefaultAudioSession(configuration); } } } return audioSession; } @Override public ChatSession getChatSession() { if (chatSession == null) { synchronized (this) { if (chatSession == null) { chatSession = new DefaultChatSession(configuration); } } } return chatSession; } @Override public FineTuningSession getFineTuningSession() { if (fineTuningSession == null) { synchronized (this) { if (fineTuningSession == null) { fineTuningSession = new DefaultFineTuningSession(configuration); } } } return fineTuningSession; } @Override public EmbeddingSession getEmbeddingSession() { if (embeddingSession == null) { synchronized (this) { if (embeddingSession == null) { embeddingSession = new DefaultEmbeddingSession(configuration); } } } return embeddingSession; } @Override public FilesSession getFilesSession() { if (filesSession == null) { synchronized (this) { if (filesSession == null) { filesSession = new DefaultFilesSession(configuration); } } } return filesSession; } @Override public ImageSession getImageSession() { if (imageSession == null) { synchronized (this) { if (imageSession == null) { imageSession = new DefaultImageSession(configuration); } } } return imageSession; } @Override public ModelSession getModelSession() { if (modelSession == null) { synchronized (this) { if (modelSession == null) { modelSession = new DefaultModelSession(configuration); } } } return modelSession; } @Override public ModerationSession getModerationSession() { if (moderationSession == null) { synchronized (this) { if (moderationSession == null) { moderationSession = new DefaultModerationSession(configuration); } } } return moderationSession; } } ================================================ FILE: ai-openai/src/main/java/com/ai/openai/achieve/defaults/session/DefaultAudioSession.java ================================================ package com.ai.openai.achieve.defaults.session; import cn.hutool.core.util.StrUtil; import com.ai.openai.achieve.Configuration; import com.ai.openai.achieve.standard.session.AudioSession; import com.ai.openai.endPoint.audio.req.SttCompletionRequest; import com.ai.openai.endPoint.audio.req.TtsCompletionRequest; import com.ai.openai.endPoint.audio.resp.SttCompletionResponse; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.ToString; import okhttp3.MediaType; import okhttp3.MultipartBody; import okhttp3.RequestBody; import retrofit2.Callback; import java.util.HashMap; import java.util.Map; import java.util.Objects; import static com.ai.common.utils.ValidationUtils.ensureNotNull; /** * @Description: OpenAI 语音类会话 **/ @Data @ToString(callSuper = true) @EqualsAndHashCode(callSuper = true) public class DefaultAudioSession extends Session implements AudioSession { public DefaultAudioSession(Configuration configuration) { this.setConfiguration(ensureNotNull(configuration, "configuration")); this.setOpenaiApiServer(ensureNotNull(configuration.getOpenaiApiServer(), "openaiApiServer")); } @Override public void ttsCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, TtsCompletionRequest ttsCompletionRequest, Callback callback) { this.getOpenaiApiServer().createSpeechCompletion(apiHostByUser, apiKeyByUser, apiUrlByUser, ttsCompletionRequest).enqueue(callback); } private SttCompletionResponse sttBaseCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, SttCompletionRequest sttCompletionRequest, String type) { RequestBody fileBody = RequestBody.create(MediaType.parse("multipart/form-data"), sttCompletionRequest.getFile()); MultipartBody.Part multipartBody = MultipartBody.Part.createFormData("file", sttCompletionRequest.getFile().getName(), fileBody); Map requestBodyMap = new HashMap<>(); if (StrUtil.isNotBlank(sttCompletionRequest.getLanguage())) { requestBodyMap.put(SttCompletionRequest.Fields.language, RequestBody.create(MediaType.parse("multipart/form-data"), sttCompletionRequest.getLanguage())); } if (StrUtil.isNotBlank(sttCompletionRequest.getModel())) { requestBodyMap.put(SttCompletionRequest.Fields.model, RequestBody.create(MediaType.parse("multipart/form-data"), sttCompletionRequest.getModel())); } if (StrUtil.isNotBlank(sttCompletionRequest.getPrompt())) { requestBodyMap.put(SttCompletionRequest.Fields.prompt, RequestBody.create(MediaType.parse("multipart/form-data"), sttCompletionRequest.getPrompt())); } if (StrUtil.isNotBlank(sttCompletionRequest.getResponseFormat())) { requestBodyMap.put(SttCompletionRequest.Fields.responseFormat, RequestBody.create(MediaType.parse("multipart/form-data"), sttCompletionRequest.getResponseFormat())); } if (Objects.nonNull(sttCompletionRequest.getTemperature())) { requestBodyMap.put(SttCompletionRequest.Fields.temperature, RequestBody.create(MediaType.parse("multipart/form-data"), String.valueOf(sttCompletionRequest.getTemperature()))); } if ("translation".equals(type)) { return this.getOpenaiApiServer().createTranslationCompletion(apiHostByUser, apiKeyByUser, apiUrlByUser, multipartBody, requestBodyMap).blockingGet(); } return this.getOpenaiApiServer().createTranscriptionCompletion(apiHostByUser, apiKeyByUser, apiUrlByUser, multipartBody, requestBodyMap).blockingGet(); } @Override public SttCompletionResponse sttCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, SttCompletionRequest sttCompletionRequest) { return sttBaseCompletions(apiHostByUser, apiKeyByUser, apiUrlByUser, sttCompletionRequest, "stt"); } @Override public SttCompletionResponse translationCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, SttCompletionRequest sttCompletionRequest) { return sttBaseCompletions(apiHostByUser, apiKeyByUser, apiUrlByUser, sttCompletionRequest, "translation"); } } ================================================ FILE: ai-openai/src/main/java/com/ai/openai/achieve/defaults/session/DefaultChatSession.java ================================================ package com.ai.openai.achieve.defaults.session; import cn.hutool.http.ContentType; import com.ai.common.utils.JsonUtils; import com.ai.core.exception.Constants; import com.ai.openai.achieve.Configuration; import com.ai.openai.achieve.standard.session.ChatSession; import com.ai.openai.common.ApiUrl; import com.ai.openai.endPoint.chat.ChatChoice; import com.ai.openai.endPoint.chat.msg.DefaultMessage; import com.ai.openai.endPoint.chat.req.DefaultChatCompletionRequest; import com.ai.openai.endPoint.chat.req.FuncChatCompletionRequest; import com.ai.openai.endPoint.chat.req.ImgChatCompletionRequest; import com.ai.openai.endPoint.chat.req.QaCompletionRequest; import com.ai.openai.endPoint.chat.resp.ChatCompletionResponse; import com.ai.openai.endPoint.chat.resp.QaCompletionResponse; import com.alibaba.fastjson.JSON; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.ToString; import okhttp3.MediaType; import okhttp3.Request; import okhttp3.RequestBody; import okhttp3.Response; import okhttp3.sse.EventSource; import okhttp3.sse.EventSourceListener; import java.util.List; import java.util.concurrent.CompletableFuture; import static com.ai.common.utils.ValidationUtils.ensureNotNull; import static com.ai.core.exception.Constants.*; /** * @description OpenAI 对话类会话 */ @Data @ToString(callSuper = true) @EqualsAndHashCode(callSuper = true) public class DefaultChatSession extends Session implements ChatSession { /** * 工厂事件 */ private EventSource.Factory factory; public DefaultChatSession(Configuration configuration) { this.setConfiguration(ensureNotNull(configuration, "configuration")); this.setOpenaiApiServer(ensureNotNull(configuration.getOpenaiApiServer(), "openaiApiServer")); this.setFactory(ensureNotNull(configuration.createRequestFactory(), "requestFactory")); } @Override public QaCompletionResponse qaCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, QaCompletionRequest qaCompletionRequest) { return this.getOpenaiApiServer().createQaCompletion(apiHostByUser, apiKeyByUser, apiUrlByUser, qaCompletionRequest).blockingGet(); } @Override public EventSource qaCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, QaCompletionRequest qaCompletionRequest, EventSourceListener eventSourceListener) { Request request = new Request.Builder() .addHeader(API_HOST, apiHostByUser) .addHeader(API_KEY, apiKeyByUser) .addHeader(URL, apiUrlByUser) .url(this.getConfiguration().getApiHost().concat(ApiUrl.v1_completions.getUrl())) .post(RequestBody.create(MediaType.parse(ContentType.JSON.getValue()), JsonUtils.toJson(qaCompletionRequest))) .build(); return factory.newEventSource(request, eventSourceListener); } @Override public ChatCompletionResponse chatCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, DefaultChatCompletionRequest defaultChatCompletionRequest) { return this.getOpenaiApiServer().createChatCompletion(apiHostByUser, apiKeyByUser, apiUrlByUser, defaultChatCompletionRequest).blockingGet(); } @Override public ChatCompletionResponse chatCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, ImgChatCompletionRequest imgChatCompletionRequest) { return this.getOpenaiApiServer().createChatCompletion(apiHostByUser, apiKeyByUser, apiUrlByUser, imgChatCompletionRequest).blockingGet(); } @Override public ChatCompletionResponse chatCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, FuncChatCompletionRequest funcChatCompletionRequest) { return this.getOpenaiApiServer().createChatCompletion(apiHostByUser, apiKeyByUser, apiUrlByUser, funcChatCompletionRequest).blockingGet(); } @Override public EventSource chatCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, DefaultChatCompletionRequest defaultChatCompletionRequest, EventSourceListener eventSourceListener) throws JsonProcessingException { Request request = new Request.Builder() .addHeader(API_HOST, apiHostByUser) .addHeader(API_KEY, apiKeyByUser) .addHeader(URL, apiUrlByUser) .url(this.getConfiguration().getApiHost().concat(ApiUrl.v1_chat_completions.getUrl())) .post(RequestBody.create(MediaType.parse(ContentType.JSON.getValue()), new ObjectMapper().writeValueAsString(defaultChatCompletionRequest))) .build(); return factory.newEventSource(request, eventSourceListener); } @Override public CompletableFuture chatCompletionsFuture(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, DefaultChatCompletionRequest defaultChatCompletionRequest) throws JsonProcessingException { CompletableFuture future = new CompletableFuture<>(); StringBuffer dataBuffer = new StringBuffer(); chatCompletions(apiHostByUser, apiKeyByUser, apiUrlByUser, defaultChatCompletionRequest, new EventSourceListener() { @Override public void onEvent(EventSource eventSource, String id, String type, String data) { if ("[DONE]".equalsIgnoreCase(data)) { onClosed(eventSource); future.complete(dataBuffer.toString()); } ChatCompletionResponse chatCompletionResponse = JSON.parseObject(data, ChatCompletionResponse.class); List choices = chatCompletionResponse.getChoices(); for (ChatChoice chatChoice : choices) { DefaultMessage delta = chatChoice.getDelta(); if (Constants.Role.ASSISTANT.getRoleName().equals(delta.getRole())) continue; // 应答完成 String finishReason = chatChoice.getFinishReason(); if ("stop".equalsIgnoreCase(finishReason)) { onClosed(eventSource); return; } // 发送信息 try { dataBuffer.append(delta.getContent()); } catch (Exception e) { future.completeExceptionally(new RuntimeException("Request closed before completion")); } } } @Override public void onClosed(EventSource eventSource) { future.complete(dataBuffer.toString()); } @Override public void onFailure(EventSource eventSource, Throwable t, Response response) { future.completeExceptionally(new RuntimeException("Request closed before completion")); } }); return future; } } ================================================ FILE: ai-openai/src/main/java/com/ai/openai/achieve/defaults/session/DefaultEmbeddingSession.java ================================================ package com.ai.openai.achieve.defaults.session; import com.ai.openai.achieve.Configuration; import com.ai.openai.achieve.standard.session.EmbeddingSession; import com.ai.openai.endPoint.embeddings.EmbeddingObject; import com.ai.openai.endPoint.embeddings.req.EmbeddingCompletionRequest; import com.ai.openai.endPoint.embeddings.resp.EmbeddingCompletionResponse; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.ToString; import java.util.Arrays; import java.util.List; import java.util.stream.IntStream; import static com.ai.common.utils.ValidationUtils.ensureNotNull; /** * @Description: OpenAI 嵌入类会话 **/ @Data @ToString(callSuper = true) @EqualsAndHashCode(callSuper = true) public class DefaultEmbeddingSession extends Session implements EmbeddingSession { public DefaultEmbeddingSession(Configuration configuration) { this.setConfiguration(ensureNotNull(configuration, "configuration")); this.setOpenaiApiServer(ensureNotNull(configuration.getOpenaiApiServer(), "openaiApiServer")); } @Override public EmbeddingCompletionResponse embeddingCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, List inputList) { return this.embeddingCompletions(apiHostByUser, apiKeyByUser, apiUrlByUser, EmbeddingCompletionRequest.builder().input(inputList).build()); } @Override public EmbeddingCompletionResponse embeddingCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, String input) { return this.embeddingCompletions(apiHostByUser, apiKeyByUser, apiUrlByUser, EmbeddingCompletionRequest.builder().input(Arrays.asList(input)).build()); } @Override public EmbeddingCompletionResponse embeddingCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, EmbeddingCompletionRequest embeddingCompletionRequest) { EmbeddingCompletionResponse response = this.getOpenaiApiServer().createEmbeddingsCompletion(apiHostByUser, apiKeyByUser, apiUrlByUser, embeddingCompletionRequest).blockingGet(); List data = response.getData(); List input = embeddingCompletionRequest.getInput(); // 将文本和结果进行对应 IntStream.range(0, Math.min(data.size(), input.size())) .forEach(i -> data.get(i).setContent(input.get(i))); return response; } } ================================================ FILE: ai-openai/src/main/java/com/ai/openai/achieve/defaults/session/DefaultFilesSession.java ================================================ package com.ai.openai.achieve.defaults.session; import com.ai.openai.achieve.Configuration; import com.ai.openai.achieve.standard.session.FilesSession; import com.ai.openai.endPoint.files.FileObject; import com.ai.openai.endPoint.files.resp.DeleteFileResponse; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.ToString; import okhttp3.MediaType; import okhttp3.MultipartBody; import okhttp3.RequestBody; import okhttp3.ResponseBody; import java.io.File; import java.util.List; import static com.ai.common.utils.ValidationUtils.ensureNotNull; /** * @Description: OpenAI 文件类会话 **/ @Data @ToString(callSuper = true) @EqualsAndHashCode(callSuper = true) public class DefaultFilesSession extends Session implements FilesSession { public DefaultFilesSession(Configuration configuration) { this.setConfiguration(ensureNotNull(configuration, "configuration")); this.setOpenaiApiServer(ensureNotNull(configuration.getOpenaiApiServer(), "openaiApiServer")); } @Override public List listFilesCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser) { return this.getOpenaiApiServer().listFilesCompletion(apiHostByUser, apiKeyByUser, apiUrlByUser).blockingGet().getData(); } @Override public FileObject uploadFileCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, File file, String purpose) { RequestBody fileBody = RequestBody.create(MediaType.parse("multipart/form-data"), file); MultipartBody.Part multipartBody = MultipartBody.Part.createFormData("file", file.getName(), fileBody); RequestBody purposeBody = RequestBody.create(MediaType.parse("multipart/form-data"), purpose); return this.getOpenaiApiServer().uploadFileCompletion(apiHostByUser, apiKeyByUser, apiUrlByUser, multipartBody, purposeBody).blockingGet(); } @Override public DeleteFileResponse deleteFileCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, String fileId) { return this.getOpenaiApiServer().deleteFileCompletion(apiHostByUser, apiKeyByUser, apiUrlByUser, fileId).blockingGet(); } @Override public FileObject retrieveFileCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, String fileId) { return this.getOpenaiApiServer().retrieveFileCompletion(apiHostByUser, apiKeyByUser, apiUrlByUser, fileId).blockingGet(); } @Override public ResponseBody retrieveFileContextCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, String fileId) { return this.getOpenaiApiServer().retrieveFileContentCompletion(apiHostByUser, apiKeyByUser, apiUrlByUser, fileId).blockingGet(); } } ================================================ FILE: ai-openai/src/main/java/com/ai/openai/achieve/defaults/session/DefaultFineTuningSession.java ================================================ package com.ai.openai.achieve.defaults.session; import com.ai.openai.achieve.Configuration; import com.ai.openai.achieve.standard.session.FineTuningSession; import com.ai.openai.common.CommonListResponse; import com.ai.openai.endPoint.fineTuning.FineTuningEvent; import com.ai.openai.endPoint.fineTuning.req.FineTuningRequest; import com.ai.openai.endPoint.fineTuning.req.ListFineTuningRequest; import com.ai.openai.endPoint.fineTuning.resp.FineTuningResponse; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.ToString; import static com.ai.common.utils.ValidationUtils.ensureNotNull; /** * @Description: OpenAI 微调类会话 **/ @Data @ToString(callSuper = true) @EqualsAndHashCode(callSuper = true) public class DefaultFineTuningSession extends Session implements FineTuningSession { public DefaultFineTuningSession(Configuration configuration) { this.setConfiguration(ensureNotNull(configuration, "configuration")); this.setOpenaiApiServer(ensureNotNull(configuration.getOpenaiApiServer(), "openaiApiServer")); } @Override public FineTuningResponse createFineTuningJobCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, FineTuningRequest fineTuningRequest) { return this.getOpenaiApiServer().createFineTuningJobCompletion(apiHostByUser, apiKeyByUser, apiUrlByUser, fineTuningRequest).blockingGet(); } @Override public CommonListResponse listFineTuningJobsCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, ListFineTuningRequest listFineTuningRequest) { return this.listFineTuningJobsCompletions(apiHostByUser, apiKeyByUser, apiUrlByUser, listFineTuningRequest.getAfter(), listFineTuningRequest.getLimit()); } @Override public CommonListResponse listFineTuningJobsCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, String after, Integer limit) { return this.getOpenaiApiServer().listFineTuningJobsCompletion(apiHostByUser, apiKeyByUser, apiUrlByUser, after, limit).blockingGet(); } @Override public FineTuningResponse retrieveFineTuningJobCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, String fineTuningJobId) { return this.getOpenaiApiServer().retrieveFineTuningJobCompletion(apiHostByUser, apiKeyByUser, apiUrlByUser, fineTuningJobId).blockingGet(); } @Override public FineTuningResponse cancelFineTuningJobCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, String fineTuningJobId) { return this.getOpenaiApiServer().cancelFineTuningJobCompletion(apiHostByUser, apiKeyByUser, apiUrlByUser, fineTuningJobId).blockingGet(); } @Override public CommonListResponse listFineTuningEventsCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, String fineTuningJobId) { return this.getOpenaiApiServer().listFineTuningEventsCompletion(apiHostByUser, apiKeyByUser, apiUrlByUser, fineTuningJobId).blockingGet(); } } ================================================ FILE: ai-openai/src/main/java/com/ai/openai/achieve/defaults/session/DefaultImageSession.java ================================================ package com.ai.openai.achieve.defaults.session; import com.ai.openai.achieve.Configuration; import com.ai.openai.achieve.standard.session.ImageSession; import com.ai.openai.endPoint.images.ImageObject; import com.ai.openai.endPoint.images.req.CreateImageRequest; import com.ai.openai.endPoint.images.req.ImageEditRequest; import com.ai.openai.endPoint.images.req.ImageVariationRequest; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.ToString; import okhttp3.MediaType; import okhttp3.MultipartBody; import okhttp3.RequestBody; import java.io.File; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; import static com.ai.common.utils.ValidationUtils.ensureNotNull; /** * @Description: OpenAI 图片类会话 **/ @Data @ToString(callSuper = true) @EqualsAndHashCode(callSuper = true) public class DefaultImageSession extends Session implements ImageSession { public DefaultImageSession(Configuration configuration) { this.setConfiguration(ensureNotNull(configuration, "configuration")); this.setOpenaiApiServer(ensureNotNull(configuration.getOpenaiApiServer(), "openaiApiServer")); } @Override public List createImageCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, CreateImageRequest createImageRequest) { return this.getOpenaiApiServer().createImageCompletion(apiHostByUser, apiKeyByUser, apiUrlByUser, createImageRequest).blockingGet().getData(); } @Override public List editImageCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, File image, File mask, ImageEditRequest imageEditRequest) { // 创建 RequestBody,用于封装构建RequestBody RequestBody imageBody = RequestBody.create(MediaType.parse("multipart/form-data"), image); MultipartBody.Part imageMultipartBody = MultipartBody.Part.createFormData("image", image.getName(), imageBody); MultipartBody.Part maskMultipartBody = null; if (Objects.nonNull(mask)) { RequestBody maskBody = RequestBody.create(MediaType.parse("multipart/form-data"), mask); maskMultipartBody = MultipartBody.Part.createFormData("mask", image.getName(), maskBody); } Map requestBodyMap = new HashMap<>(); requestBodyMap.put("prompt", RequestBody.create(MediaType.parse("multipart/form-data"), imageEditRequest.getPrompt())); requestBodyMap.put("n", RequestBody.create(MediaType.parse("multipart/form-data"), imageEditRequest.getN().toString())); requestBodyMap.put("size", RequestBody.create(MediaType.parse("multipart/form-data"), imageEditRequest.getSize())); requestBodyMap.put("response_format", RequestBody.create(MediaType.parse("multipart/form-data"), imageEditRequest.getResponseFormat())); if (!(Objects.isNull(imageEditRequest.getUser()) || "".equals(imageEditRequest.getUser()))) { requestBodyMap.put("user", RequestBody.create(MediaType.parse("multipart/form-data"), imageEditRequest.getUser())); } return this.getOpenaiApiServer().editImageCompletion( apiHostByUser, apiKeyByUser, apiUrlByUser, imageMultipartBody, maskMultipartBody, requestBodyMap ).blockingGet().getData(); } @Override public List variationImageCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, File image, ImageVariationRequest imageVariationRequest) { RequestBody imageBody = RequestBody.create(MediaType.parse("multipart/form-data"), image); MultipartBody.Part multipartBody = MultipartBody.Part.createFormData("image", image.getName(), imageBody); Map requestBodyMap = new HashMap<>(); requestBodyMap.put("n", RequestBody.create(MediaType.parse("multipart/form-data"), imageVariationRequest.getN().toString())); requestBodyMap.put("size", RequestBody.create(MediaType.parse("multipart/form-data"), imageVariationRequest.getSize())); requestBodyMap.put("response_format", RequestBody.create(MediaType.parse("multipart/form-data"), imageVariationRequest.getResponseFormat())); if (!(Objects.isNull(imageVariationRequest.getUser()) || "".equals(imageVariationRequest.getUser()))) { requestBodyMap.put("user", RequestBody.create(MediaType.parse("multipart/form-data"), imageVariationRequest.getUser())); } return this.getOpenaiApiServer().variationImageCompletion( apiHostByUser, apiKeyByUser, apiUrlByUser, multipartBody, requestBodyMap ).blockingGet().getData(); } } ================================================ FILE: ai-openai/src/main/java/com/ai/openai/achieve/defaults/session/DefaultModelSession.java ================================================ package com.ai.openai.achieve.defaults.session; import com.ai.openai.achieve.Configuration; import com.ai.openai.achieve.standard.session.ModelSession; import com.ai.openai.endPoint.models.ModelObject; import com.ai.openai.endPoint.models.resp.DeleteFineTuneModelResponse; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.ToString; import java.util.List; import static com.ai.common.utils.ValidationUtils.ensureNotNull; /** * @Description: OpenAI 模型类会话 **/ @Data @ToString(callSuper = true) @EqualsAndHashCode(callSuper = true) public class DefaultModelSession extends Session implements ModelSession { public DefaultModelSession(Configuration configuration) { this.setConfiguration(ensureNotNull(configuration, "configuration")); this.setOpenaiApiServer(ensureNotNull(configuration.getOpenaiApiServer(), "openaiApiServer")); } @Override public List listModelCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser) { return this.getOpenaiApiServer().listModelsCompletion(apiHostByUser, apiKeyByUser, apiUrlByUser).blockingGet().getData(); } @Override public ModelObject retrieveModelCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, String model) { return this.getOpenaiApiServer().retrieveModelCompletion(apiHostByUser, apiKeyByUser, apiUrlByUser, model).blockingGet(); } @Override public DeleteFineTuneModelResponse deleteFineTuneModelCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, String model) { return this.getOpenaiApiServer().deleteFineTuneModelCompletion(apiHostByUser, apiKeyByUser, apiUrlByUser, model).blockingGet(); } } ================================================ FILE: ai-openai/src/main/java/com/ai/openai/achieve/defaults/session/DefaultModerationSession.java ================================================ package com.ai.openai.achieve.defaults.session; import com.ai.openai.achieve.Configuration; import com.ai.openai.achieve.standard.session.ModerationSession; import com.ai.openai.endPoint.moderations.Result; import com.ai.openai.endPoint.moderations.req.ModerationRequest; import com.ai.openai.endPoint.moderations.resp.ModerationResponse; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.ToString; import java.util.List; import java.util.stream.IntStream; import static com.ai.common.utils.ValidationUtils.ensureNotNull; /** * @Description: OpenAI 审核类会话 **/ @Data @ToString(callSuper = true) @EqualsAndHashCode(callSuper = true) public class DefaultModerationSession extends Session implements ModerationSession { public DefaultModerationSession(Configuration configuration) { this.setConfiguration(ensureNotNull(configuration, "configuration")); this.setOpenaiApiServer(ensureNotNull(configuration.getOpenaiApiServer(), "openaiApiServer")); } @Override public ModerationResponse moderationCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, ModerationRequest moderationRequest) { ModerationResponse response = getOpenaiApiServer().moderationCompletion(apiHostByUser, apiKeyByUser, apiUrlByUser, moderationRequest).blockingGet(); List inputs = moderationRequest.getInput(); List results = response.getResults(); // 将审核文本和审核结果进行对应 IntStream.range(0, Math.min(results.size(), inputs.size())) .forEach(i -> results.get(i).setContent(inputs.get(i))); return response; } } ================================================ FILE: ai-openai/src/main/java/com/ai/openai/achieve/defaults/session/Session.java ================================================ package com.ai.openai.achieve.defaults.session; import com.ai.openai.achieve.Configuration; import com.ai.openai.achieve.standard.api.OpenaiApiServer; import lombok.Data; @Data public class Session { /** * 配置信息 */ private Configuration configuration; /** * OpenAI 接口 */ private OpenaiApiServer openaiApiServer; } ================================================ FILE: ai-openai/src/main/java/com/ai/openai/achieve/standard/api/OpenaiApiServer.java ================================================ package com.ai.openai.achieve.standard.api; import com.ai.openai.common.CommonListResponse; import com.ai.openai.endPoint.audio.req.TtsCompletionRequest; import com.ai.openai.endPoint.audio.resp.SttCompletionResponse; import com.ai.openai.endPoint.chat.req.DefaultChatCompletionRequest; import com.ai.openai.endPoint.chat.req.FuncChatCompletionRequest; import com.ai.openai.endPoint.chat.req.ImgChatCompletionRequest; import com.ai.openai.endPoint.chat.req.QaCompletionRequest; import com.ai.openai.endPoint.chat.resp.ChatCompletionResponse; import com.ai.openai.endPoint.chat.resp.QaCompletionResponse; import com.ai.openai.endPoint.embeddings.req.EmbeddingCompletionRequest; import com.ai.openai.endPoint.embeddings.resp.EmbeddingCompletionResponse; import com.ai.openai.endPoint.files.FileObject; import com.ai.openai.endPoint.files.resp.DeleteFileResponse; import com.ai.openai.endPoint.fineTuning.FineTuningEvent; import com.ai.openai.endPoint.fineTuning.req.FineTuningRequest; import com.ai.openai.endPoint.fineTuning.resp.FineTuningResponse; import com.ai.openai.endPoint.images.req.CreateImageRequest; import com.ai.openai.endPoint.images.resp.CreateImageResponse; import com.ai.openai.endPoint.models.ModelObject; import com.ai.openai.endPoint.models.resp.DeleteFineTuneModelResponse; import com.ai.openai.endPoint.moderations.req.ModerationRequest; import com.ai.openai.endPoint.moderations.resp.ModerationResponse; import io.reactivex.Single; import okhttp3.MultipartBody; import okhttp3.RequestBody; import okhttp3.ResponseBody; import retrofit2.Call; import retrofit2.http.*; import java.util.Map; import static com.ai.core.exception.Constants.*; /** * @Description: OpenAI API接口 **/ public interface OpenaiApiServer { /** * 简单问答接口 * * @param apiHostByUser 用户自定义 host * @param apiKeyByUser 用户自定义密钥 * @param apiUrlByUser 用户自定义请求地址 * @param qaCompletionRequest 用户自定义封装的请求参数 * @return 请求结果 */ @POST("/v1/completions") Single createQaCompletion(@Header(API_HOST) String apiHostByUser, @Header(API_KEY) String apiKeyByUser, @Header(URL) String apiUrlByUser, @Body QaCompletionRequest qaCompletionRequest); /** * 普通对话聊天接口 * * @param apiHostByUser 用户自定义 host * @param apiKeyByUser 用户自定义密钥 * @param apiUrlByUser 用户自定义请求地址 * @param defaultChatCompletionRequest 用户自定义封装的请求参数 * @return 请求结果 */ @POST("/v1/chat/completions") Single createChatCompletion(@Header(API_HOST) String apiHostByUser, @Header(API_KEY) String apiKeyByUser, @Header(URL) String apiUrlByUser, @Body DefaultChatCompletionRequest defaultChatCompletionRequest); /** * 图片对话聊天接口 * * @param apiHostByUser 用户自定义 host * @param apiKeyByUser 用户自定义密钥 * @param apiUrlByUser 用户自定义请求地址 * @param imgChatCompletionRequest 用户自定义封装的请求参数 * @return 请求结果 */ @POST("/v1/chat/completions") Single createChatCompletion(@Header(API_HOST) String apiHostByUser, @Header(API_KEY) String apiKeyByUser, @Header(URL) String apiUrlByUser, @Body ImgChatCompletionRequest imgChatCompletionRequest); /** * 函数对话聊天接口 * * @param apiHostByUser 用户自定义 host * @param apiKeyByUser 用户自定义密钥 * @param apiUrlByUser 用户自定义请求地址 * @param funcChatCompletionRequest 用户自定义封装的请求参数 * @return 请求结果 */ @POST("/v1/chat/completions") Single createChatCompletion(@Header(API_HOST) String apiHostByUser, @Header(API_KEY) String apiKeyByUser, @Header(URL) String apiUrlByUser, @Body FuncChatCompletionRequest funcChatCompletionRequest); /** * 输入文本生成音频 * * @param apiHostByUser 用户自定义 host * @param apiKeyByUser 用户自定义密钥 * @param apiUrlByUser 用户自定义请求地址 * @param ttsCompletionRequest 用户自定义封装的请求参数 * @return 请求结果 */ @POST("/v1/audio/speech") @Streaming Call createSpeechCompletion(@Header(API_HOST) String apiHostByUser, @Header(API_KEY) String apiKeyByUser, @Header(URL) String apiUrlByUser, @Body TtsCompletionRequest ttsCompletionRequest); /** * 发送音频文件,解析成文本 * * @param apiHostByUser 用户自定义 host * @param apiKeyByUser 用户自定义密钥 * @param apiUrlByUser 用户自定义请求地址 * @param file 音频文件 * @param requestBodyMap 请求参数 * @return 请求结果 */ @Multipart @POST("/v1/audio/transcriptions") Single createTranscriptionCompletion(@Header(API_HOST) String apiHostByUser, @Header(API_KEY) String apiKeyByUser, @Header(URL) String apiUrlByUser, @Part MultipartBody.Part file, @PartMap Map requestBodyMap); /** * 发送音频文件,解析并翻译为英文 * * @param apiHostByUser 用户自定义 host * @param apiKeyByUser 用户自定义密钥 * @param apiUrlByUser 用户自定义请求地址 * @param file 音频文件 * @param requestBodyMap 请求参数 * @return 请求结果 */ @Multipart @POST("/v1/audio/translations") Single createTranslationCompletion(@Header(API_HOST) String apiHostByUser, @Header(API_KEY) String apiKeyByUser, @Header(URL) String apiUrlByUser, @Part MultipartBody.Part file, @PartMap() Map requestBodyMap); /** * 创建嵌入 * * @param apiHostByUser 用户自定义 host * @param apiKeyByUser 用户自定义密钥 * @param apiUrlByUser 用户自定义请求地址 * @param embeddingCompletionRequest 请求参数 * @return 请求结果 */ @POST("/v1/embeddings") Single createEmbeddingsCompletion(@Header(API_HOST) String apiHostByUser, @Header(API_KEY) String apiKeyByUser, @Header(URL) String apiUrlByUser, @Body EmbeddingCompletionRequest embeddingCompletionRequest); /** * 创建微调作业 * * @param apiHostByUser 用户自定义 host * @param apiKeyByUser 用户自定义密钥 * @param apiUrlByUser 用户自定义请求地址 * @param fineTuningRequest 请求参数 * @return 请求结果 */ @POST("/v1/fine_tuning/jobs") Single createFineTuningJobCompletion(@Header(API_HOST) String apiHostByUser, @Header(API_KEY) String apiKeyByUser, @Header(URL) String apiUrlByUser, @Body FineTuningRequest fineTuningRequest); /** * 列出微调作业 * * @param apiHostByUser 用户自定义 host * @param apiKeyByUser 用户自定义密钥 * @param apiUrlByUser 用户自定义请求地址 * @param after 上一个分页请求中最后一个作业的标识符 * @param limit 要检索的微调作业数 * @return 请求结果 */ @GET("/v1/fine_tuning/jobs") Single> listFineTuningJobsCompletion(@Header(API_HOST) String apiHostByUser, @Header(API_KEY) String apiKeyByUser, @Header(URL) String apiUrlByUser, @Query("after") String after, @Query("limit") Integer limit); /** * 检索微调作业 * * @param apiHostByUser 用户自定义 host * @param apiKeyByUser 用户自定义密钥 * @param apiUrlByUser 用户自定义请求地址 * @param fineTuningJobId 微调作业的 ID * @return 请求结果 */ @GET("/v1/fine_tuning/jobs/{fine_tuning_job_id}") Single retrieveFineTuningJobCompletion(@Header(API_HOST) String apiHostByUser, @Header(API_KEY) String apiKeyByUser, @Header(URL) String apiUrlByUser, @Path("fine_tuning_job_id") String fineTuningJobId); /** * 取消微调作业 * * @param apiHostByUser 用户自定义 host * @param apiKeyByUser 用户自定义密钥 * @param apiUrlByUser 用户自定义请求地址 * @param fineTuningJobId 微调作业的 ID * @return 请求结果 */ @POST("/v1/fine_tuning/jobs/{fine_tuning_job_id}/cancel") Single cancelFineTuningJobCompletion(@Header(API_HOST) String apiHostByUser, @Header(API_KEY) String apiKeyByUser, @Header(URL) String apiUrlByUser, @Path("fine_tuning_job_id") String fineTuningJobId); /** * 列出微调事件 * * @param apiHostByUser 用户自定义 host * @param apiKeyByUser 用户自定义密钥 * @param apiUrlByUser 用户自定义请求地址 * @param fineTuningJobId 微调作业的 ID * @return 请求结果 */ @GET("/v1/fine_tuning/jobs/{fine_tuning_job_id}/events") Single> listFineTuningEventsCompletion(@Header(API_HOST) String apiHostByUser, @Header(API_KEY) String apiKeyByUser, @Header(URL) String apiUrlByUser, @Path("fine_tuning_job_id") String fineTuningJobId); /** * 返回属于用户组织的文件列表 * * @param apiHostByUser 用户自定义 host * @param apiKeyByUser 用户自定义密钥 * @param apiUrlByUser 用户自定义请求地址 * @return 文件列表 */ @GET("/v1/files") Single> listFilesCompletion(@Header(API_HOST) String apiHostByUser, @Header(API_KEY) String apiKeyByUser, @Header(URL) String apiUrlByUser); /** * 上传文件 * * @param apiHostByUser 用户自定义 host * @param apiKeyByUser 用户自定义密钥 * @param apiUrlByUser 用户自定义请求地址 * @param file 要上载的 File 对象(不是文件名) * @param purpose 上传文件的预期用途 * @return 上载的 File 对象 */ @Multipart @POST("/v1/files") Single uploadFileCompletion(@Header(API_HOST) String apiHostByUser, @Header(API_KEY) String apiKeyByUser, @Header(URL) String apiUrlByUser, @Part MultipartBody.Part file, @Part("purpose") RequestBody purpose); /** * 删除文件 * * @param apiHostByUser 用户自定义 host * @param apiKeyByUser 用户自定义密钥 * @param apiUrlByUser 用户自定义请求地址 * @param fileId 文件ID * @return 删除状态 */ @DELETE("/v1/files/{file_id}") Single deleteFileCompletion(@Header(API_HOST) String apiHostByUser, @Header(API_KEY) String apiKeyByUser, @Header(URL) String apiUrlByUser, @Path("file_id") String fileId); /** * 检索文件 * * @param apiHostByUser 用户自定义 host * @param apiKeyByUser 用户自定义密钥 * @param apiUrlByUser 用户自定义请求地址 * @param fileId 文件ID * @return 文件信息 */ @GET("/v1/files/{file_id}") Single retrieveFileCompletion(@Header(API_HOST) String apiHostByUser, @Header(API_KEY) String apiKeyByUser, @Header(URL) String apiUrlByUser, @Path("file_id") String fileId); /** * 获取文件内容 * * @param apiHostByUser 用户自定义 host * @param apiKeyByUser 用户自定义密钥 * @param apiUrlByUser 用户自定义请求地址 * @param fileId 文件ID * @return 文件内容 */ @Streaming @GET("/v1/files/{file_id}/content") Single retrieveFileContentCompletion(@Header(API_HOST) String apiHostByUser, @Header(API_KEY) String apiKeyByUser, @Header(URL) String apiUrlByUser, @Path("file_id") String fileId); /** * 生成图片 * * @param apiHostByUser 用户自定义 host * @param apiKeyByUser 用户自定义密钥 * @param apiUrlByUser 用户自定义请求地址 * @param createImageRequest 生成图片的请求参数 * @return 图片信息 */ @POST("/v1/images/generations") Single createImageCompletion(@Header(API_HOST) String apiHostByUser, @Header(API_KEY) String apiKeyByUser, @Header(URL) String apiUrlByUser, @Body CreateImageRequest createImageRequest); /** * 编辑图片 * * @param apiHostByUser 用户自定义 host * @param apiKeyByUser 用户自定义密钥 * @param apiUrlByUser 用户自定义请求地址 * @param image 被编辑的图片 * @param mask 一个额外的图像,其完全透明的区域(例如,alpha为零)指示应该编辑的位置。必须是有效的 PNG 文件,小于 4MB,并且尺寸与image相同。 * @param requestBodyMap 请求参数 * @return 图片信息 */ @Multipart @POST("/v1/images/edits") Single editImageCompletion(@Header(API_HOST) String apiHostByUser, @Header(API_KEY) String apiKeyByUser, @Header(URL) String apiUrlByUser, @Part() MultipartBody.Part image, @Part() MultipartBody.Part mask, @PartMap() Map requestBodyMap); /** * 创建给定图像的变体 * * @param apiHostByUser 用户自定义 host * @param apiKeyByUser 用户自定义密钥 * @param apiUrlByUser 用户自定义请求地址 * @param image 被编辑的图片 * @param requestBodyMap 请求参数 * @return 图片信息 */ @Multipart @POST("/v1/images/variations") Single variationImageCompletion(@Header(API_HOST) String apiHostByUser, @Header(API_KEY) String apiKeyByUser, @Header(URL) String apiUrlByUser, @Part() MultipartBody.Part image, @PartMap() Map requestBodyMap); /** * 列出模型 * * @param apiHostByUser 用户自定义 host * @param apiKeyByUser 用户自定义密钥 * @param apiUrlByUser 用户自定义请求地址 * @return 模型信息 */ @GET("/v1/models") Single> listModelsCompletion(@Header(API_HOST) String apiHostByUser, @Header(API_KEY) String apiKeyByUser, @Header(URL) String apiUrlByUser); /** * 检索模型信息 * * @param apiHostByUser 用户自定义 host * @param apiKeyByUser 用户自定义密钥 * @param apiUrlByUser 用户自定义请求地址 * @param model 模型ID * @return 模型信息 */ @GET("/v1/models/{model}") Single retrieveModelCompletion(@Header(API_HOST) String apiHostByUser, @Header(API_KEY) String apiKeyByUser, @Header(URL) String apiUrlByUser, @Path("model") String model); /** * 删除微调模型 * * @param apiHostByUser 用户自定义 host * @param apiKeyByUser 用户自定义密钥 * @param apiUrlByUser 用户自定义请求地址 * @param model 模型ID * @return 删除状态 */ @DELETE("/v1/models/{model}") Single deleteFineTuneModelCompletion(@Header(API_HOST) String apiHostByUser, @Header(API_KEY) String apiKeyByUser, @Header(URL) String apiUrlByUser, @Path("model") String model); /** * 审核 * * @param apiHostByUser 用户自定义 host * @param apiKeyByUser 用户自定义密钥 * @param apiUrlByUser 用户自定义请求地址 * @param moderationRequest 审核请求参数 * @return 审核结果 */ @POST("/v1/moderations") Single moderationCompletion(@Header(API_HOST) String apiHostByUser, @Header(API_KEY) String apiKeyByUser, @Header(URL) String apiUrlByUser, @Body ModerationRequest moderationRequest); } ================================================ FILE: ai-openai/src/main/java/com/ai/openai/achieve/standard/session/AggregationSession.java ================================================ package com.ai.openai.achieve.standard.session; /** * @Description: 聚合各大场景的session **/ public interface AggregationSession { /** * 获取音频会话窗口 */ AudioSession getAudioSession(); /** * 获取对话会话窗口 */ ChatSession getChatSession(); /** * 获取微调会话窗口 */ FineTuningSession getFineTuningSession(); /** * 获取嵌入会话窗口 */ EmbeddingSession getEmbeddingSession(); /** * 获取文件会话窗口 */ FilesSession getFilesSession(); /** * 获取图片会话窗口 */ ImageSession getImageSession(); /** * 获取模型会话窗口 */ ModelSession getModelSession(); /** * 获取审核会话窗口 */ ModerationSession getModerationSession(); } ================================================ FILE: ai-openai/src/main/java/com/ai/openai/achieve/standard/session/AudioSession.java ================================================ package com.ai.openai.achieve.standard.session; import com.ai.openai.endPoint.audio.req.SttCompletionRequest; import com.ai.openai.endPoint.audio.req.TtsCompletionRequest; import com.ai.openai.endPoint.audio.resp.SttCompletionResponse; import retrofit2.Callback; /** * @Description: openAi 音频会话窗口 **/ public interface AudioSession { /** * 文字转语音 * * @param apiHostByUser 用户自定义 host * @param apiKeyByUser 用户自定义密钥 * @param apiUrlByUser 用户自定义请求地址 * @param ttsCompletionRequest 语音接口请求参数 * @param callback 回调函数 */ void ttsCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, TtsCompletionRequest ttsCompletionRequest, Callback callback); /** * 语音转文字 * * @param apiHostByUser 用户自定义 host * @param apiKeyByUser 用户自定义密钥 * @param apiUrlByUser 用户自定义请求地址 * @param sttCompletionRequest 音频转文字接口请求参数 * @return 请求结果 */ SttCompletionResponse sttCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, SttCompletionRequest sttCompletionRequest); /** * 翻译 * * @param apiHostByUser 用户自定义 host * @param apiKeyByUser 用户自定义密钥 * @param apiUrlByUser 用户自定义请求地址 * @param sttCompletionRequest 音频转文字接口请求参数 * @return 请求结果 */ SttCompletionResponse translationCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, SttCompletionRequest sttCompletionRequest); } ================================================ FILE: ai-openai/src/main/java/com/ai/openai/achieve/standard/session/ChatSession.java ================================================ package com.ai.openai.achieve.standard.session; import com.ai.openai.endPoint.chat.req.DefaultChatCompletionRequest; import com.ai.openai.endPoint.chat.req.FuncChatCompletionRequest; import com.ai.openai.endPoint.chat.req.ImgChatCompletionRequest; import com.ai.openai.endPoint.chat.req.QaCompletionRequest; import com.ai.openai.endPoint.chat.resp.ChatCompletionResponse; import com.ai.openai.endPoint.chat.resp.QaCompletionResponse; import com.fasterxml.jackson.core.JsonProcessingException; import okhttp3.sse.EventSource; import okhttp3.sse.EventSourceListener; import java.util.concurrent.CompletableFuture; /** * @description openAi 聊天会话窗口 */ public interface ChatSession { /** * 简单问答 * * @param apiHostByUser 用户自定义 host * @param apiKeyByUser 用户自定义密钥 * @param apiUrlByUser 用户自定义请求地址 * @param qaCompletionRequest 用户自定义封装的请求参数 * @return 请求结果 */ QaCompletionResponse qaCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, QaCompletionRequest qaCompletionRequest); /** * 简单问答,流式返回。 * * @param apiHostByUser 用户自定义 host * @param apiKeyByUser 用户自定义密钥 * @param apiUrlByUser 用户自定义请求地址 * @param qaCompletionRequest 用户自定义封装的请求参数 * @param eventSourceListener 事件监听者 * @return 事件源 */ EventSource qaCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, QaCompletionRequest qaCompletionRequest, EventSourceListener eventSourceListener) throws JsonProcessingException; /** * 普通对话聊天 * * @param apiHostByUser 用户自定义 host * @param apiKeyByUser 用户自定义密钥 * @param apiUrlByUser 用户自定义请求地址 * @param defaultChatCompletionRequest 用户自定义封装的请求参数 * @return 请求结果 */ ChatCompletionResponse chatCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, DefaultChatCompletionRequest defaultChatCompletionRequest); /** * 图片对话聊天 * * @param apiHostByUser 用户自定义 host * @param apiKeyByUser 用户自定义密钥 * @param apiUrlByUser 用户自定义请求地址 * @param imgChatCompletionRequest 用户自定义封装的请求参数 * @return 请求结果 */ ChatCompletionResponse chatCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, ImgChatCompletionRequest imgChatCompletionRequest); /** * 函数对话聊天 * * @param apiHostByUser 用户自定义 host * @param apiKeyByUser 用户自定义密钥 * @param apiUrlByUser 用户自定义请求地址 * @param funcChatCompletionRequest 用户自定义封装的请求参数 * @return 请求结果 */ ChatCompletionResponse chatCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, FuncChatCompletionRequest funcChatCompletionRequest); /** * 对话聊天,流式返回,此函数为对话聊天流式返回的基础函数。 * * @param apiHostByUser 用户自定义 host * @param apiKeyByUser 用户自定义密钥 * @param apiUrlByUser 用户自定义请求地址 * @param defaultChatCompletionRequest 用户自定义封装的请求参数 * @param eventSourceListener 事件监听者 * @return 事件源 */ EventSource chatCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, DefaultChatCompletionRequest defaultChatCompletionRequest, EventSourceListener eventSourceListener) throws JsonProcessingException; /** * 对话聊天 & 流式反馈 & 一次反馈 * * @param defaultChatCompletionRequest 请求信息 * @return 应答结果 */ CompletableFuture chatCompletionsFuture(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, DefaultChatCompletionRequest defaultChatCompletionRequest) throws InterruptedException, JsonProcessingException; } ================================================ FILE: ai-openai/src/main/java/com/ai/openai/achieve/standard/session/EmbeddingSession.java ================================================ package com.ai.openai.achieve.standard.session; import com.ai.openai.endPoint.embeddings.req.EmbeddingCompletionRequest; import com.ai.openai.endPoint.embeddings.resp.EmbeddingCompletionResponse; import java.util.List; /** * @Description: 嵌入会话窗口 **/ public interface EmbeddingSession { /** * 嵌入 * * @param apiHostByUser 用户自定义 host * @param apiKeyByUser 用户自定义密钥 * @param apiUrlByUser 用户自定义请求地址 * @param inputList 文本数组 * @return 请求结果 */ EmbeddingCompletionResponse embeddingCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, List inputList); /** * 嵌入 * * @param apiHostByUser 用户自定义 host * @param apiKeyByUser 用户自定义密钥 * @param apiUrlByUser 用户自定义请求地址 * @param input 文本 * @return 请求结果 */ EmbeddingCompletionResponse embeddingCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, String input); /** * 嵌入 * * @param apiHostByUser 用户自定义 host * @param apiKeyByUser 用户自定义密钥 * @param apiUrlByUser 用户自定义请求地址 * @param embeddingCompletionRequest 请求参数 * @return 请求结果 */ EmbeddingCompletionResponse embeddingCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, EmbeddingCompletionRequest embeddingCompletionRequest); } ================================================ FILE: ai-openai/src/main/java/com/ai/openai/achieve/standard/session/FilesSession.java ================================================ package com.ai.openai.achieve.standard.session; import com.ai.openai.endPoint.files.FileObject; import com.ai.openai.endPoint.files.resp.DeleteFileResponse; import okhttp3.ResponseBody; import java.io.File; import java.util.List; /** * @Description: 文件会话窗口 **/ public interface FilesSession { /** * 返回属于用户组织的文件列表 * * @param apiHostByUser 用户自定义 host * @param apiKeyByUser 用户自定义密钥 * @param apiUrlByUser 用户自定义请求地址 * @return 文件列表 */ List listFilesCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser); /** * 上传文件 * * @param apiHostByUser 用户自定义 host * @param apiKeyByUser 用户自定义密钥 * @param apiUrlByUser 用户自定义请求地址 * @param file 需要上传的文件 * @param purpose 上传文件的用途 * @return 文件信息 */ FileObject uploadFileCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, File file, String purpose); /** * 删除文件 * * @param apiHostByUser 用户自定义 host * @param apiKeyByUser 用户自定义密钥 * @param apiUrlByUser 用户自定义请求地址 * @param fileId 文件ID * @return 删除状态信息 */ DeleteFileResponse deleteFileCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, String fileId); /** * 检索文件 * * @param apiHostByUser 用户自定义 host * @param apiKeyByUser 用户自定义密钥 * @param apiUrlByUser 用户自定义请求地址 * @param fileId 文件ID * @return 文件信息 */ FileObject retrieveFileCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, String fileId); /** * 获取文件内容 * * @param apiHostByUser 用户自定义 host * @param apiKeyByUser 用户自定义密钥 * @param apiUrlByUser 用户自定义请求地址 * @param fileId 文件ID * @return 返回结果 */ ResponseBody retrieveFileContextCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, String fileId); } ================================================ FILE: ai-openai/src/main/java/com/ai/openai/achieve/standard/session/FineTuningSession.java ================================================ package com.ai.openai.achieve.standard.session; import com.ai.openai.common.CommonListResponse; import com.ai.openai.endPoint.fineTuning.FineTuningEvent; import com.ai.openai.endPoint.fineTuning.req.FineTuningRequest; import com.ai.openai.endPoint.fineTuning.req.ListFineTuningRequest; import com.ai.openai.endPoint.fineTuning.resp.FineTuningResponse; /** * @Description: 微调会话窗口 **/ public interface FineTuningSession { /** * 创建微调作业 * * @param apiHostByUser 用户自定义 host * @param apiKeyByUser 用户自定义密钥 * @param apiUrlByUser 用户自定义请求地址 * @param fineTuningRequest 请求参数 * @return 请求结果 */ FineTuningResponse createFineTuningJobCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, FineTuningRequest fineTuningRequest); /** * 列出微调作业 * * @param apiHostByUser 用户自定义 host * @param apiKeyByUser 用户自定义密钥 * @param apiUrlByUser 用户自定义请求地址 * @param listFineTuningRequest 请求参数 * @return 请求结果 */ CommonListResponse listFineTuningJobsCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, ListFineTuningRequest listFineTuningRequest); /** * 列出微调作业 * * @param apiHostByUser 用户自定义 host * @param apiKeyByUser 用户自定义密钥 * @param apiUrlByUser 用户自定义请求地址 * @param after 上一个分页请求中最后一个作业的标识符 * @param limit 要检索的微调作业数 * @return 请求结果 */ CommonListResponse listFineTuningJobsCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, String after, Integer limit); /** * 检索微调作业 * * @param apiHostByUser 用户自定义 host * @param apiKeyByUser 用户自定义密钥 * @param apiUrlByUser 用户自定义请求地址 * @param fineTuningJobId 微调作业的 ID * @return 请求结果 */ FineTuningResponse retrieveFineTuningJobCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, String fineTuningJobId); /** * 取消微调作业 * * @param apiHostByUser 用户自定义 host * @param apiKeyByUser 用户自定义密钥 * @param apiUrlByUser 用户自定义请求地址 * @param fineTuningJobId 微调作业的 ID * @return 请求结果 */ FineTuningResponse cancelFineTuningJobCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, String fineTuningJobId); /** * 列出微调事件 * * @param apiHostByUser 用户自定义 host * @param apiKeyByUser 用户自定义密钥 * @param apiUrlByUser 用户自定义请求地址 * @param fineTuningJobId 微调作业的 ID * @return 请求结果 */ CommonListResponse listFineTuningEventsCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, String fineTuningJobId); } ================================================ FILE: ai-openai/src/main/java/com/ai/openai/achieve/standard/session/ImageSession.java ================================================ package com.ai.openai.achieve.standard.session; import com.ai.openai.endPoint.images.ImageObject; import com.ai.openai.endPoint.images.req.CreateImageRequest; import com.ai.openai.endPoint.images.req.ImageEditRequest; import com.ai.openai.endPoint.images.req.ImageVariationRequest; import java.io.File; import java.util.List; /** * @Description: 图片会话窗口 **/ public interface ImageSession { /** * @param apiHostByUser 用户自定义 host * @param apiKeyByUser 用户自定义密钥 * @param apiUrlByUser 用户自定义请求地址 * @param createImageRequest 请求参数 * @return 图片信息 */ List createImageCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, CreateImageRequest createImageRequest); /** * 编辑图像 * * @param apiHostByUser 用户自定义 host * @param apiKeyByUser 用户自定义密钥 * @param apiUrlByUser 用户自定义请求地址 * @param image 要编辑的图像 * @param mask 一个额外的图像,其完全透明的区域(例如,alpha为零)指示应该编辑的位置。必须是有效的 PNG 文件,小于 4MB,并且尺寸与image相同 * @param imageEditRequest 请求参数 * @return 图片信息 */ List editImageCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, File image, File mask, ImageEditRequest imageEditRequest); /** * 创建图像变体 * * @param apiHostByUser 用户自定义 host * @param apiKeyByUser 用户自定义密钥 * @param apiUrlByUser 用户自定义请求地址 * @param image 要编辑的图像 * @param imageVariationRequest 请求参数 * @return 图片信息 */ List variationImageCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, File image, ImageVariationRequest imageVariationRequest); } ================================================ FILE: ai-openai/src/main/java/com/ai/openai/achieve/standard/session/ModelSession.java ================================================ package com.ai.openai.achieve.standard.session; import com.ai.openai.endPoint.models.ModelObject; import com.ai.openai.endPoint.models.resp.DeleteFineTuneModelResponse; import java.util.List; /** * @Description: 模型会话窗口 **/ public interface ModelSession { /** * 列出模型 * * @param apiHostByUser 用户自定义 host * @param apiKeyByUser 用户自定义密钥 * @param apiUrlByUser 用户自定义请求地址 * @return 模型列表 */ List listModelCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser); /** * 检索模型 * * @param apiHostByUser 用户自定义 host * @param apiKeyByUser 用户自定义密钥 * @param apiUrlByUser 用户自定义请求地址 * @param model 模型ID * @return 模型信息 */ ModelObject retrieveModelCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, String model); /** * 删除微调模型 * * @param apiHostByUser 用户自定义 host * @param apiKeyByUser 用户自定义密钥 * @param apiUrlByUser 用户自定义请求地址 * @param model 模型ID * @return 删除状态 */ DeleteFineTuneModelResponse deleteFineTuneModelCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, String model); } ================================================ FILE: ai-openai/src/main/java/com/ai/openai/achieve/standard/session/ModerationSession.java ================================================ package com.ai.openai.achieve.standard.session; import com.ai.openai.endPoint.moderations.req.ModerationRequest; import com.ai.openai.endPoint.moderations.resp.ModerationResponse; /** * @Description: 审核会话窗口 **/ public interface ModerationSession { /** * 审核 * * @param apiHostByUser 用户自定义 host * @param apiKeyByUser 用户自定义密钥 * @param apiUrlByUser 用户自定义请求地址 * @param moderationRequest 请求参数 * @return 审核结果 */ ModerationResponse moderationCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, ModerationRequest moderationRequest); } ================================================ FILE: ai-openai/src/main/java/com/ai/openai/common/ApiUrl.java ================================================ package com.ai.openai.common; import lombok.AllArgsConstructor; import lombok.Getter; /** * 各接口API路径 */ @Getter @AllArgsConstructor public enum ApiUrl { v1_completions("/v1/completions"), v1_chat_completions("/v1/chat/completions"), v1_audio_speech("/v1/audio/speech"), v1_audio_transcriptions("/v1/audio/transcriptions"), v1_audio_translations("/v1/audio/translations"), v1_embeddings("/v1/embeddings"), v1_fine_tuning_jobs("/v1/fine_tuning/jobs"), v1_fine_tuning_jobs_fine_tuning_job_id("/v1/fine_tuning/jobs/{fine_tuning_job_id}"), v1_fine_tuning_jobs_fine_tuning_job_id_cancel("/v1/fine_tuning/jobs/{fine_tuning_job_id}/cancel"), v1_fine_tuning_jobs_fine_tuning_job_id_events("/v1/fine_tuning/jobs/{fine_tuning_job_id}/events"), ; private String url; } ================================================ FILE: ai-openai/src/main/java/com/ai/openai/common/CommonListResponse.java ================================================ package com.ai.openai.common; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import java.io.Serializable; import java.util.List; /** * @Description: 通用返回类 **/ @Data @NoArgsConstructor @AllArgsConstructor public class CommonListResponse implements Serializable { private String object; private List data; private Error error; @JsonProperty("has_more") private Boolean hasMore; @Data @JsonIgnoreProperties(ignoreUnknown = true) public class Error { private String message; private String type; private String param; private String code; } } ================================================ FILE: ai-openai/src/main/java/com/ai/openai/common/Usage.java ================================================ package com.ai.openai.common; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @Data @AllArgsConstructor @NoArgsConstructor public class Usage { /** * 请求消耗的token */ @JsonProperty("prompt_tokens") private int promptTokens; /** * 回答消耗的token */ @JsonProperty("completion_tokens") private int completionTokens; /** * 总共消耗的token */ @JsonProperty("total_tokens") private int totalTokens; } ================================================ FILE: ai-openai/src/main/java/com/ai/openai/endPoint/audio/req/SttCompletionRequest.java ================================================ package com.ai.openai.endPoint.audio.req; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.*; import lombok.experimental.FieldNameConstants; import java.io.File; import java.io.Serializable; @Data @Builder @NoArgsConstructor @AllArgsConstructor @FieldNameConstants @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public class SttCompletionRequest implements Serializable { /** * 要转录的音频文件对象(不是文件名) * 采用以下格式之一:flac、mp3、mp4、mpeg、mpga、m4a、ogg、wav 或 webm */ @NonNull private File file; /** * 使用的模型名 */ @NonNull @Builder.Default private String model = Model.whisper_1.getModuleName(); /** * 音频的语言,以 ISO-639-1 格式提供输入语言将提高准确性和延迟。 */ private String language; /** * 一个可选文本,用于指导模型的样式或继续上一个音频片段。提示应与音频语言匹配。 */ private String prompt; /** * 脚本输出的格式 */ @JsonProperty("response_format") private String responseFormat; /** * 采样温度,介于 0 和 1 之间,默认值为 0 。 * 较高的值(如 0.8)将使输出更加随机,而较低的值(如 0.2)将使其更具针对性和确定性。 * 如果设置为 0,模型将使用对数概率自动提高温度,直到达到某些阈值。 */ private Double temperature; @Getter @AllArgsConstructor public enum Model { whisper_1("whisper-1"); private String moduleName; } } ================================================ FILE: ai-openai/src/main/java/com/ai/openai/endPoint/audio/req/TtsCompletionRequest.java ================================================ package com.ai.openai.endPoint.audio.req; import com.ai.openai.endPoint.chat.req.BaseChatCompletionRequest; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.*; import java.io.Serializable; @Data @Builder @NoArgsConstructor @AllArgsConstructor @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public class TtsCompletionRequest implements Serializable { /** * 要使用的模型的 ID */ @Builder.Default private String model = BaseChatCompletionRequest.Model.GPT_3_5_TURBO.getModuleName(); /** * 要为其生成音频的文本,最大长度为4096个字符 */ @NonNull private String input; /** * 声音样式 */ @NonNull private String voice; /** * 音频输入的格式,默认为mp3 */ @JsonProperty("response_format") private String responseFormat; /** * 音频的速度,0.25 到 4.0 之中选取一个数,数字越大速度越快。默认为1。 */ private String speed; /** * 构造基础请求内容 * * @param input 文本内容 * @return 文本转语言请求参数 */ public static TtsCompletionRequest baseBuild(String input) { return TtsCompletionRequest .builder() .input(input) .voice(Voice.alloy.getVoiceName()) .model(Model.tts_1.getModuleName()) .build(); } @Getter @AllArgsConstructor public enum Model { tts_1("tts-1"), tts_1_hd("tts-1-hd"); private String moduleName; } /** * 声音样式 */ @Getter @AllArgsConstructor public enum Voice { alloy("alloy"), echo("echo"), fable("fable"), onyx("onyx"), nova("nova"), shimmer("shimmer"); private String voiceName; } } ================================================ FILE: ai-openai/src/main/java/com/ai/openai/endPoint/audio/resp/SttCompletionResponse.java ================================================ package com.ai.openai.endPoint.audio.resp; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import java.io.Serializable; @Data @NoArgsConstructor @AllArgsConstructor @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public class SttCompletionResponse implements Serializable { /** * 转换之后得到的文本 */ private String text; } ================================================ FILE: ai-openai/src/main/java/com/ai/openai/endPoint/chat/ChatChoice.java ================================================ package com.ai.openai.endPoint.chat; import com.ai.openai.endPoint.chat.msg.DefaultMessage; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import java.io.Serializable; /** * @Description: 聊天接口模型返回的信息 **/ @Data @NoArgsConstructor @AllArgsConstructor @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public class ChatChoice implements Serializable { private long index; /** * stream = true时,由流式模型响应生成的聊天完成增量 */ private DefaultMessage delta; /** * stream = false时,模型生成的聊天完成消息 */ private DefaultMessage message; /** * 模型停止生成令牌的原因 */ @JsonProperty("finish_reason") private String finishReason; } ================================================ FILE: ai-openai/src/main/java/com/ai/openai/endPoint/chat/Parameters.java ================================================ package com.ai.openai.endPoint.chat; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import java.io.Serializable; import java.util.List; @Data @Builder @AllArgsConstructor @NoArgsConstructor public class Parameters implements Serializable { /** * 参数类型 */ private String type; /** * 参数属性、描述 */ private Object properties; /** * 方法必输字段 */ private List required; } ================================================ FILE: ai-openai/src/main/java/com/ai/openai/endPoint/chat/QaChoice.java ================================================ package com.ai.openai.endPoint.chat; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import java.io.Serializable; /** * @Description: 简单问答模型返回的信息 **/ @Data @AllArgsConstructor @NoArgsConstructor public class QaChoice implements Serializable { /** * 回答内容 */ private String text; private int index; private Object logprobs; /** * 模型停止生成令牌的原因 */ @JsonProperty("finish_reason") private String finishReason; } ================================================ FILE: ai-openai/src/main/java/com/ai/openai/endPoint/chat/ResponseFormat.java ================================================ package com.ai.openai.endPoint.chat; import lombok.*; /** * @Author: jianglinhong * @Description: TODO * @DateTime: 2023/12/8 14:22 **/ @Data @Builder @AllArgsConstructor @NoArgsConstructor public class ResponseFormat { /** * 默认:text */ private String type; @Getter @AllArgsConstructor public enum Type { JSON_OBJECT("json_object"), TEXT("text"), ; private final String name; } } ================================================ FILE: ai-openai/src/main/java/com/ai/openai/endPoint/chat/msg/BaseMessage.java ================================================ package com.ai.openai.endPoint.chat.msg; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import lombok.experimental.SuperBuilder; import java.io.Serializable; /** * @description 基础问答信息 */ @Data @SuperBuilder @NoArgsConstructor @AllArgsConstructor @JsonInclude(JsonInclude.Include.NON_NULL) @JsonIgnoreProperties(ignoreUnknown = true) public class BaseMessage implements Serializable { /** * 角色:system、user、assistant */ private String role; private String name; } ================================================ FILE: ai-openai/src/main/java/com/ai/openai/endPoint/chat/msg/Content.java ================================================ package com.ai.openai.endPoint.chat.msg; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.*; /** * @Description: 图片问答信息 **/ @Data @Builder @NoArgsConstructor @AllArgsConstructor @JsonInclude(JsonInclude.Include.NON_NULL) public class Content { /** * 输入类型 */ private String type; /** * 问题内容 */ private String text; /** * 图片地址 */ @JsonProperty("image_url") private ImageUrl imageUrl; /** * 构建 text 类型的 content */ public static Content BuildTextContent(String text) { return Content.builder().type(Type.TEXT.getName()).text(text).build(); } /** * 构建 image_url 类型的 content */ public static Content BuildImageUrlContent(String urlOrB64Json) { return Content.builder().type(Type.IMAGE_URL.getName()).text(urlOrB64Json).build(); } /** * 输入类型 */ @Getter @AllArgsConstructor public enum Type { TEXT("text"), IMAGE_URL("image_url"), ; private final String name; } } ================================================ FILE: ai-openai/src/main/java/com/ai/openai/endPoint/chat/msg/DefaultMessage.java ================================================ package com.ai.openai.endPoint.chat.msg; import com.ai.openai.endPoint.chat.tools.ToolCall; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import lombok.experimental.SuperBuilder; import java.io.Serializable; import java.util.List; /** * @Description: 默认问答内容 **/ @Data @SuperBuilder @NoArgsConstructor @AllArgsConstructor @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public class DefaultMessage extends BaseMessage implements Serializable { /** * 问答内容 */ private String content; /** * 函数式对话时,返回的函数信息 */ @JsonProperty("tool_calls") private List toolCalls; } ================================================ FILE: ai-openai/src/main/java/com/ai/openai/endPoint/chat/msg/ImageUrl.java ================================================ package com.ai.openai.endPoint.chat.msg; import com.fasterxml.jackson.annotation.JsonInclude; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; /** * @Description: 图片问答时,图片的URL **/ @Data @Builder @JsonInclude(JsonInclude.Include.NON_NULL) @NoArgsConstructor @AllArgsConstructor public class ImageUrl { /** * 图片地址 */ private String url; } ================================================ FILE: ai-openai/src/main/java/com/ai/openai/endPoint/chat/msg/ImgMessage.java ================================================ package com.ai.openai.endPoint.chat.msg; import com.fasterxml.jackson.annotation.JsonInclude; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import lombok.experimental.SuperBuilder; import java.io.Serializable; import java.util.List; /** * @Description: 图片输入 **/ @Data @SuperBuilder @NoArgsConstructor @AllArgsConstructor @JsonInclude(JsonInclude.Include.NON_NULL) public class ImgMessage extends BaseMessage implements Serializable { /** * 图片对话内容 */ private List content; /** * 添加类型为 text 的对话内容 */ public void addTextContent(String text) { addContent(Content.builder().type(Content.Type.TEXT.getName()).text(text).build()); } /** * 添加类型为 image_url 的对话内容 */ public void addImageContent(String imageUrl) { addContent(Content.builder() .text(Content.Type.IMAGE_URL.getName()) .imageUrl(ImageUrl.builder().url(imageUrl).build()) .build()); } /** * 添加对话内容 */ public void addContent(Content content) { this.content.add(content); } } ================================================ FILE: ai-openai/src/main/java/com/ai/openai/endPoint/chat/req/BaseChatCompletionRequest.java ================================================ package com.ai.openai.endPoint.chat.req; import com.ai.openai.endPoint.chat.ResponseFormat; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.*; import lombok.experimental.SuperBuilder; import java.io.Serializable; import java.util.List; import java.util.Map; @Data @SuperBuilder @NoArgsConstructor @AllArgsConstructor @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public class BaseChatCompletionRequest implements Serializable { /** * 要使用的模型的 ID */ @Builder.Default private String model = Model.GPT_3_5_TURBO.getModuleName(); /** * 介于 -2.0 和 2.0 之间的数字,默认值为 0 * 正值会根据新标记在文本中的现有频率来惩罚新标记从而降低模型逐字重复同一行的可能性 */ @JsonProperty("frequency_penalty") private Double frequencyPenalty; /** * 修改指定标记出现的可能性,默认值为 null */ @JsonProperty("logit_bias") private Map logitBias; /** * 输出字符串限制;0 ~ 4096 */ @JsonProperty("max_tokens") private Integer maxTokens; /** * 为每个提示生成的完成次数,默认值为 1 */ private Integer n; /** * 介于 -2.0 和 2.0 之间的数字,默认值为 0 * 正值会根据新标记到目前为止是否出现在文本中来惩罚它们从而增加模型谈论新主题的可能性 */ @JsonProperty("presence_penalty") private Double presencePenalty; /** * 指定模型必须输出的格式的对象。 */ @JsonProperty("response_format") private ResponseFormat responseFormat; private Integer seed; /** * 停止输出标识,默认值为 null * 最多 4 个序列,API 将停止生成更多令牌 */ private List stop; /** * 使用什么采样温度,介于 0 和 2 之间,默认值为 1 * 较高的值(如 0.8)将使输出更加随机,而较低的值(如 0.2)将使其更具集中性和确定性 */ private Double temperature; /** * 默认值为 1 * 温度采样的替代方法,称为核采样,其中模型考虑具有top_p概率质量的标记的结果。因此,0.1 表示仅考虑包含前 10% 概率质量的代币。 */ @JsonProperty("top_p") private Double topP; /** * 调用标识,避免重复调用 */ private String user; @Getter @AllArgsConstructor public enum Model { GPT_3_5_TURBO("gpt-3.5-turbo"), GPT_4("gpt-4"), GPT_4_32K("gpt-4-32k"), GPT_4_VISION_PREVIEW("gpt-4-vision-preview"), ; private String moduleName; } } ================================================ FILE: ai-openai/src/main/java/com/ai/openai/endPoint/chat/req/DefaultChatCompletionRequest.java ================================================ package com.ai.openai.endPoint.chat.req; import com.ai.core.exception.Constants; import com.ai.openai.endPoint.chat.msg.DefaultMessage; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import lombok.NonNull; import lombok.experimental.SuperBuilder; import java.io.Serializable; import java.util.ArrayList; import java.util.Collections; import java.util.List; /** * @Description: 默认对话方式 **/ @Data @SuperBuilder @NoArgsConstructor @AllArgsConstructor @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public class DefaultChatCompletionRequest extends BaseChatCompletionRequest implements Serializable { /** * 构成对话的消息列表 */ @NonNull private List messages; /** * 是否为流式输出,默认值为 false */ private Boolean stream; /** * 构造基础的 DefaultChatCompletionRequest * * @param question 问题内容 */ public static DefaultChatCompletionRequest baseBuild(String question) { return DefaultChatCompletionRequest .builder() .messages(new ArrayList<>(Collections.singletonList(DefaultMessage.builder().role(Constants.Role.USER.getRoleName()).content(question).build()))) .build(); } /** * 上下文对话时,添加问答内容 * * @param message 问答内容 */ public void addMessage(DefaultMessage message) { this.messages.add(message); } /** * 上下文对话时,添加问答内容 * * @param role 角色 * @param content 内容 */ public void addMessage(String role, String content) { this.addMessage(DefaultMessage.builder().role(role).content(content).build()); } } ================================================ FILE: ai-openai/src/main/java/com/ai/openai/endPoint/chat/req/FuncChatCompletionRequest.java ================================================ package com.ai.openai.endPoint.chat.req; import com.ai.core.exception.Constants; import com.ai.openai.endPoint.chat.msg.DefaultMessage; import com.ai.openai.endPoint.chat.tools.Tool; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import lombok.NonNull; import lombok.experimental.SuperBuilder; import java.io.Serializable; import java.util.ArrayList; import java.util.Collections; import java.util.List; /** * @Description: 函数式对话 **/ @Data @SuperBuilder @NoArgsConstructor @AllArgsConstructor @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public class FuncChatCompletionRequest extends BaseChatCompletionRequest implements Serializable { /** * 构成对话的消息列表 */ @NonNull private List messages; /** * 模型可能调用的工具列表。当前版本仅支持:functions */ private List tools; /** * 控制模型调用哪个(如果有)函数。 */ @JsonProperty("tool_choice") private Object toolChoice; /** * 构造基础的 DefaultChatCompletionRequest * * @param question 问题内容 */ public static FuncChatCompletionRequest baseBuild(String question) { return FuncChatCompletionRequest.builder() .messages(new ArrayList<>(Collections.singletonList(DefaultMessage.builder().role(Constants.Role.USER.getRoleName()).content(question).build()))) .build(); } /** * 上下文对话时,添加问答内容 * * @param message 问答内容 */ public void addMessage(DefaultMessage message) { this.messages.add(message); } /** * 上下文对话时,添加问答内容 * * @param role 角色 * @param content 内容 */ public void addMessage(String role, String content) { this.addMessage(DefaultMessage.builder().role(role).content(content).build()); } } ================================================ FILE: ai-openai/src/main/java/com/ai/openai/endPoint/chat/req/ImgChatCompletionRequest.java ================================================ package com.ai.openai.endPoint.chat.req; import com.ai.openai.endPoint.chat.msg.ImgMessage; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import lombok.NonNull; import lombok.experimental.SuperBuilder; import java.io.Serializable; import java.util.List; /** * @Description: 输入图片对话 **/ @Data @SuperBuilder @NoArgsConstructor @AllArgsConstructor @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public class ImgChatCompletionRequest extends BaseChatCompletionRequest implements Serializable { /** * 构成对话的消息列表 */ @NonNull private List messages; } ================================================ FILE: ai-openai/src/main/java/com/ai/openai/endPoint/chat/req/QaCompletionRequest.java ================================================ package com.ai.openai.endPoint.chat.req; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.*; import java.io.Serializable; import java.util.List; import java.util.Map; @Builder @Data @NoArgsConstructor @AllArgsConstructor @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public class QaCompletionRequest implements Serializable { /** * 要使用的模型的 ID */ @Builder.Default private String model = Model.GPT_3_5_TURBO.getModelName(); /** * 问题描述 */ @NonNull private String prompt; /** * 默认值为 1 * 在服务器端生成回答并返回“最佳”(每个令牌的对数概率最高的一个)。无法流式传输结果。 */ @JsonProperty("best_of") private Integer bestOf; /** * 介于 -2.0 和 2.0 之间的数字,默认值为 0 * 正值会根据新标记在文本中的现有频率来惩罚新标记从而降低模型逐字重复同一行的可能性 */ @JsonProperty("frequency_penalty") private Double frequencyPenalty; /** * 修改指定标记出现的可能性,默认值为 null */ @JsonProperty("logit_bias") private Map logitBias; /** * 默认值为 null * 包括最有可能的令牌以及所选令牌的对数概率。 */ private Integer logprobs; /** * 输出字符串限制;0 ~ 4096 */ @JsonProperty("max_tokens") private Integer maxTokens; /** * 为每个提示生成的完成次数,默认值为 1 */ private Integer n; /** * 介于 -2.0 和 2.0 之间的数字,默认值为 0 * 正值会根据新标记到目前为止是否出现在文本中来惩罚它们从而增加模型谈论新主题的可能性 */ @JsonProperty("presence_penalty") private Double presencePenalty; /** * 停止输出标识,默认值为 null * 最多 4 个序列,API 将停止生成更多令牌 */ private List stop; /** * 是否为流式输出,默认值为 false */ private Boolean stream; /** * 使用什么采样温度,介于 0 和 2 之间,默认值为 1 * 较高的值(如 0.8)将使输出更加随机,而较低的值(如 0.2)将使其更具集中性和确定性 */ private Double temperature; /** * 默认值为 1 * 温度采样的替代方法,称为核采样,其中模型考虑具有top_p概率质量的标记的结果。因此,0.1 表示仅考虑包含前 10% 概率质量的代币。 */ @JsonProperty("top_p") private Double topP = 1d; /** * 调用标识,避免重复调用 */ private String user; /** * 构造基础请求内容 * * @param question 问题内容 * @return 简单问答请求体 */ public static QaCompletionRequest baseBuild(String question) { return QaCompletionRequest.builder().prompt(question).build(); } @Getter @AllArgsConstructor public enum Model { GPT_3_5_TURBO("gpt-3.5-turbo-instruct"), GPT_4("gpt-4"), GPT_4_32K("gpt-4-32k"), ; private String modelName; } } ================================================ FILE: ai-openai/src/main/java/com/ai/openai/endPoint/chat/resp/ChatCompletionResponse.java ================================================ package com.ai.openai.endPoint.chat.resp; import com.ai.openai.common.Usage; import com.ai.openai.endPoint.chat.ChatChoice; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import java.io.Serializable; import java.util.List; /** * @description 聊天请求结果信息 */ @Data @NoArgsConstructor @AllArgsConstructor @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public class ChatCompletionResponse implements Serializable { /** * 完成的唯一标识符 */ private String id; /** * 对话信息 */ private List choices; /** * 对象 */ private String object; /** * 创建完成时的 Unix 时间戳(以秒为单位)。 */ private Long created; /** * 用于完成的模型 */ private String model; @JsonProperty("system_fingerprint") private String systemFingerprint; /** * 结束原因 */ @JsonProperty("finish_reason") private String finishReason; /** * 完成请求的使用情况统计信息 */ private Usage usage; } ================================================ FILE: ai-openai/src/main/java/com/ai/openai/endPoint/chat/resp/QaCompletionResponse.java ================================================ package com.ai.openai.endPoint.chat.resp; import com.ai.openai.common.Usage; import com.ai.openai.endPoint.chat.QaChoice; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import java.io.Serializable; import java.util.List; /** * @Description: 简单问答返回信息 **/ @Data @NoArgsConstructor @AllArgsConstructor @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public class QaCompletionResponse implements Serializable { /** * 完成的唯一标识符 */ private String id; /** * 模型为输入提示生成的完成选项列表 */ private List choices; /** * 创建完成时的 Unix 时间戳(以秒为单位)。 */ private Long created; /** * 用于完成的模型 */ private String model; /** * 对象类型,始终为“text_completion” */ private String object; /** * 完成请求的使用情况统计信息 */ private Usage usage; } ================================================ FILE: ai-openai/src/main/java/com/ai/openai/endPoint/chat/tools/Tool.java ================================================ package com.ai.openai.endPoint.chat.tools; import lombok.*; import java.io.Serializable; @Data @Builder @AllArgsConstructor @NoArgsConstructor public class Tool implements Serializable { /** * 目前只支持:function * * @see Type */ private String type; private ToolFunction function; @Getter @AllArgsConstructor public enum Type { FUNCTION("function"), ; private final String name; } } ================================================ FILE: ai-openai/src/main/java/com/ai/openai/endPoint/chat/tools/ToolCall.java ================================================ package com.ai.openai.endPoint.chat.tools; import lombok.*; import java.io.Serializable; /** * @Description: 函数式对话返回的函数信息 **/ @Data @Builder @AllArgsConstructor @NoArgsConstructor public class ToolCall implements Serializable { private String id; private String type; private ToolCallFunction function; @Getter @AllArgsConstructor public enum Type { FUNCTION("function"), ; private final String name; } } ================================================ FILE: ai-openai/src/main/java/com/ai/openai/endPoint/chat/tools/ToolCallFunction.java ================================================ package com.ai.openai.endPoint.chat.tools; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import java.io.Serializable; /** * @Description: TODO **/ @Data @Builder @AllArgsConstructor @NoArgsConstructor public class ToolCallFunction implements Serializable { /** * 方法名 */ private String name; /** * 方法参数 */ private String arguments; } ================================================ FILE: ai-openai/src/main/java/com/ai/openai/endPoint/chat/tools/ToolFunction.java ================================================ package com.ai.openai.endPoint.chat.tools; import com.ai.openai.endPoint.chat.Parameters; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import java.io.Serializable; @Data @Builder @AllArgsConstructor @NoArgsConstructor public class ToolFunction implements Serializable { /** * 要调用的函数的名称。必须是 a-z、A-Z、0-9 或包含下划线和短划线,最大长度为 64。 */ private String name; /** * 对函数所执行操作的描述,模型使用它来选择何时以及如何调用该函数。 */ private String description; /** * 函数接受的参数,描述为 JSON 架构对象。 */ private Parameters parameters; } ================================================ FILE: ai-openai/src/main/java/com/ai/openai/endPoint/embeddings/EmbeddingObject.java ================================================ package com.ai.openai.endPoint.embeddings; import com.fasterxml.jackson.annotation.JsonIgnore; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import java.io.Serializable; @Data @AllArgsConstructor @NoArgsConstructor public class EmbeddingObject implements Serializable { /** * 嵌入的内容 */ @JsonIgnore private String content; /** * 嵌入列表中嵌入的索引 */ private Integer index; /** * 嵌入向量,它是浮点数的列表 */ private double[] embedding; /** * 对象类型,始终为“embedding”。 */ private String object; } ================================================ FILE: ai-openai/src/main/java/com/ai/openai/endPoint/embeddings/req/EmbeddingCompletionRequest.java ================================================ package com.ai.openai.endPoint.embeddings.req; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.*; import java.io.Serializable; import java.util.Arrays; import java.util.List; @Data @Builder @NoArgsConstructor @AllArgsConstructor @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public class EmbeddingCompletionRequest implements Serializable { /** * 输入要嵌入的文本,编码为字符串或标记数组。 * 若要在单个请求中嵌入多个输入,请传递字符串数组或令牌数组。 */ @NonNull private List input; /** * 要使用的模型的 ID。 */ @Builder.Default private String model = Model.TEXT_EMBEDDING_ADA_002.getModelName(); /** * 要返回嵌入的格式。 */ @JsonProperty("encoding_format") private String encodingFormat; /** * 代表最终用户的唯一标识符 */ private String user; /** * 构造基础请求参数 * * @param input 文本 * @return 请求参数 */ public static EmbeddingCompletionRequest baseBuild(String input) { return baseBuild(Arrays.asList(input)); } /** * 构造基础请求参数 * * @param inputList 文本数组 * @return 请求参数 */ public static EmbeddingCompletionRequest baseBuild(List inputList) { return EmbeddingCompletionRequest.builder().input(inputList).build(); } @Getter @AllArgsConstructor public enum Model { TEXT_EMBEDDING_ADA_002("text-embedding-ada-002"), ; private final String modelName; } } ================================================ FILE: ai-openai/src/main/java/com/ai/openai/endPoint/embeddings/resp/EmbeddingCompletionResponse.java ================================================ package com.ai.openai.endPoint.embeddings.resp; import com.ai.openai.common.Usage; import com.ai.openai.endPoint.embeddings.EmbeddingObject; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import java.io.Serializable; import java.util.List; @Data @NoArgsConstructor @AllArgsConstructor @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public class EmbeddingCompletionResponse implements Serializable { /** * 参考示例返回: * { * "object": "list", * "data": [ * { * "object": "embedding", * "embedding": [ * 0.0023064255, * -0.009327292, * .... (1536 floats total for ada-002) * -0.0028842222, * ], * "index": 0 * } * ], * "model": "text-embedding-ada-002", * "usage": { * "prompt_tokens": 8, * "total_tokens": 8 * } * } */ private String object; /** * 结果数组 */ private List data; private String model; private Usage usage; } ================================================ FILE: ai-openai/src/main/java/com/ai/openai/endPoint/files/FileObject.java ================================================ package com.ai.openai.endPoint.files; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import java.io.Serializable; @Data @NoArgsConstructor @AllArgsConstructor public class FileObject implements Serializable { /** * 文件标识符,可在 API 端点中引用 */ private String id; /** * 文件大小(以字节为单位) */ private Long bytes; /** * 创建文件时的 Unix 时间戳(以秒为单位) */ @JsonProperty("created_at") private Long createdAt; /** * 文件的名称 */ private String filename; /** * 对象类型,始终为:file */ private String object; /** * 文件的预期用途 */ private String purpose; /** * 荒废的。文件的当前状态 */ @Deprecated private String status; /** * 荒废的。有关微调训练文件验证失败的原因的详细信息 */ @Deprecated @JsonProperty("status_details") private String statusDetails; } ================================================ FILE: ai-openai/src/main/java/com/ai/openai/endPoint/files/resp/DeleteFileResponse.java ================================================ package com.ai.openai.endPoint.files.resp; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import java.io.Serializable; @Data @NoArgsConstructor @AllArgsConstructor @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public class DeleteFileResponse implements Serializable { /** * 文件ID */ private String id; private String object; private Boolean deleted; } ================================================ FILE: ai-openai/src/main/java/com/ai/openai/endPoint/fineTuning/FineTuneError.java ================================================ package com.ai.openai.endPoint.fineTuning; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import java.io.Serializable; @Data @NoArgsConstructor @AllArgsConstructor public class FineTuneError implements Serializable { /** * 错误信息 */ private String message; /** * 错误类型 */ private String type; /** * 错误参数 */ private String param; /** * 错误码 */ private String code; } ================================================ FILE: ai-openai/src/main/java/com/ai/openai/endPoint/fineTuning/FineTuningEvent.java ================================================ package com.ai.openai.endPoint.fineTuning; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import java.io.Serializable; @Data @NoArgsConstructor @AllArgsConstructor public class FineTuningEvent implements Serializable { private String object; private String id; /** * 创建微调作业时的 Unix 时间戳 */ @JsonProperty("created_at") private Long createdAt; private String level; private String message; private String type; } ================================================ FILE: ai-openai/src/main/java/com/ai/openai/endPoint/fineTuning/HyperParameters.java ================================================ package com.ai.openai.endPoint.fineTuning; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.extern.slf4j.Slf4j; import java.io.Serializable; @Getter @Slf4j @Builder @JsonInclude(JsonInclude.Include.NON_NULL) @NoArgsConstructor @AllArgsConstructor public class HyperParameters implements Serializable { /** * 每批样本数。较大的批量大小意味着模型参数 更新频率较低,但方差较低。 */ @JsonProperty("batch_size") private String batchSize; /** * 学习率的比例因子。较小的学习率可能有助于避免 过拟合。 */ @JsonProperty("learning_rate_multiplier") private String learningRateMultiplier; /** * 要训练模型的纪元数。一个纪元是指一个完整的周期 通过训练数据集。 */ @JsonProperty("n_epochs") private String nEpochs; } ================================================ FILE: ai-openai/src/main/java/com/ai/openai/endPoint/fineTuning/req/FineTuningRequest.java ================================================ package com.ai.openai.endPoint.fineTuning.req; import com.ai.openai.endPoint.fineTuning.HyperParameters; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.*; import java.io.Serializable; @Data @Builder @NoArgsConstructor @AllArgsConstructor @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public class FineTuningRequest implements Serializable { /** * 微调的模型的名称 */ @Builder.Default private String model = Model.GPT_3_5_TURBO_1106.getModelName(); /** * 包含训练数据的已上传文件的 ID */ @NonNull @JsonProperty("training_file") private String trainingFile; /** * 用于微调作业的超参数 */ @JsonProperty("hyperparameters") private HyperParameters hyperParameters; /** * 最多 18 个字符的字符串,将添加到微调的模型名称中。 */ private String suffix; /** * 包含验证数据的上载文件的 ID */ @JsonProperty("validation_file") private String validationFile; @Getter @AllArgsConstructor public enum Model { GPT_3_5_TURBO_1106("gpt-3.5-turbo-1106"), GPT_3_5_TURBO_0613("gpt-3.5-turbo-0613"), BABBAGE_002("babbage-002"), GPT_4_0613("gpt-4-0613"), DAVINCI_002("davinci-002"), ; private final String modelName; } } ================================================ FILE: ai-openai/src/main/java/com/ai/openai/endPoint/fineTuning/req/ListFineTuningRequest.java ================================================ package com.ai.openai.endPoint.fineTuning.req; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import java.io.Serializable; @Data @Builder @NoArgsConstructor @AllArgsConstructor @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public class ListFineTuningRequest implements Serializable { /** * 上一个分页请求中最后一个作业的标识符 */ private String after; /** * 要检索的微调作业数 */ private Integer limit; } ================================================ FILE: ai-openai/src/main/java/com/ai/openai/endPoint/fineTuning/resp/FineTuningResponse.java ================================================ package com.ai.openai.endPoint.fineTuning.resp; import com.ai.openai.endPoint.fineTuning.HyperParameters; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import java.io.Serializable; import java.util.List; @Data @NoArgsConstructor @AllArgsConstructor @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public class FineTuningResponse implements Serializable { /** * 对象标识符,可在 API 端点中引用 */ private String id; /** * 创建微调作业时的 Unix 时间戳 */ @JsonProperty("created_at") private Long createdAt; /** * 对于具有的微调作业,这将包含有关失败原因的详细信息 */ // private FineTuneError error; /** * 正在创建的微调模型的名称。如果微调作业仍在运行,则该值将为 null */ @JsonProperty("fine_tuned_model") private String fineTunedModel; /** * 微调作业完成时的 Unix 时间戳(以秒为单位)。如果微调作业仍在运行,则该值将为 null */ @JsonProperty("finished_at") private Long finishedAt; /** * 用于微调作业的超参数 */ @JsonProperty("hyperparameters") private HyperParameters hyperparameters; /** * 正在微调的基本模型 */ private String model; /** * 对象类型,始终为“fine_tuning.job” */ private String object; /** * 拥有微调作业的组织 */ @JsonProperty("organization_id") private String organizationId; /** * 微调作业的编译结果文件 ID */ @JsonProperty("result_files") private List resultFiles; /** * 微调作业的当前状态 */ private String status; /** * 此微调作业处理的计费令牌总数 */ @JsonProperty("trained_tokens") private Integer trainedTokens; /** * 用于训练的文件 ID */ @JsonProperty("training_file") private String trainingFile; /** * 用于验证的文件 ID */ @JsonProperty("validation_file") private String validationFile; } ================================================ FILE: ai-openai/src/main/java/com/ai/openai/endPoint/images/ImageObject.java ================================================ package com.ai.openai.endPoint.images; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @Data @NoArgsConstructor @AllArgsConstructor public class ImageObject { private String url; @JsonProperty("b64_json") private String b64Json; @JsonProperty("revised_prompt") private String revisedPrompt; } ================================================ FILE: ai-openai/src/main/java/com/ai/openai/endPoint/images/req/CreateImageRequest.java ================================================ package com.ai.openai.endPoint.images.req; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.*; import java.io.Serializable; @Data @Builder @NoArgsConstructor @AllArgsConstructor @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public class CreateImageRequest implements Serializable { /** * 所需图像的文本描述。的最大长度为 1000 个字符,4000 个字符。 */ private String prompt; /** * 用于图像生成的模型 *

* 默认为 dall-e-2 * * @see Model */ @Builder.Default private String model = Model.DALL_E_2.getName(); /** * 要生成的图像数。必须介于 1 和 10 之间,dall-e-3只能为1。 */ @Builder.Default private Integer n = 1; /** * 将生成的图像的质量。 创建具有更精细细节和更高一致性的图像。 * * @see Quality */ private String quality; /** * 返回生成的图像的格式:url、b64_json */ @JsonProperty("response_format") private String responseFormat; /** * 图片尺寸,默认值:1024x1024 * dall-e-2支持:256x256, 512x512, or 1024x1024 * dall-e-3支持:1024x1024, 1792x1024, or 1024x1792 */ private String size; /** * 生成的图像的样式。 * 此参数仅仅dall-e-3,取值范围:vivid、natural * 默认值:vivid * * @see Style */ private String style; /** * 代表最终用户的唯一标识符 */ private String user; /** * 构建基础请求内容 * * @param prompt 提示词 * @return 请求参数 */ public static CreateImageRequest baseBuild(String prompt) { return CreateImageRequest.builder().prompt(prompt).build(); } /** * 图片生成模型 */ @Getter @AllArgsConstructor public enum Model { DALL_E_2("dall-e-2"), DALL_E_3("dall-e-3"), ; private final String name; } /** * 生成图片质量 */ @Getter @AllArgsConstructor public enum Quality { STANDARD("standard"), HD("hd"), ; private final String quality; } /** * 生成图片风格 */ @Getter @AllArgsConstructor public enum Style { VIVID("vivid"), NATURAL("natural"), ; private final String style; } @Getter @AllArgsConstructor public enum Format { URL("url"), B64JSON("b64_json"), ; private final String format; } } ================================================ FILE: ai-openai/src/main/java/com/ai/openai/endPoint/images/req/ImageEditRequest.java ================================================ package com.ai.openai.endPoint.images.req; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.*; import java.io.Serializable; @Data @Builder @NoArgsConstructor @AllArgsConstructor @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public class ImageEditRequest { /** * 必选项:描述文字,最多1000字符 */ @NonNull private String prompt; /** * 为每个提示生成的完成次数。 */ @Builder.Default private Integer n = 1; /** * 256x256 * 512x512 * 1024x1024 */ @Builder.Default private String size = SizeEnum.size_1024.getName(); @JsonProperty("response_format") @Builder.Default private String responseFormat = ResponseFormat.URL.getName(); private String user; /** * 构造基础请求参数 * * @param prompt 提示词 * @return 请求参数 */ public static ImageEditRequest baseBuild(String prompt) { return ImageEditRequest.builder().prompt(prompt).build(); } @Getter @AllArgsConstructor public enum SizeEnum implements Serializable { size_1024_1792("1024x1792"), size_1792_1024("1792x1024"), size_1024("1024x1024"), size_512("512x512"), size_256("256x256"), ; private final String name; } @AllArgsConstructor @Getter public enum ResponseFormat implements Serializable { URL("url"), B64_JSON("b64_json"), ; private final String name; } } ================================================ FILE: ai-openai/src/main/java/com/ai/openai/endPoint/images/req/ImageVariationRequest.java ================================================ package com.ai.openai.endPoint.images.req; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.*; import lombok.extern.slf4j.Slf4j; import java.io.Serializable; @Slf4j @Data @Builder @NoArgsConstructor @AllArgsConstructor @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public class ImageVariationRequest { /** * 为每个提示生成的完成次数。 */ @Builder.Default private Integer n = 1; /** * 256x256 * 512x512 * 1024x1024 */ @Builder.Default private String size = SizeEnum.size_1024.getName(); @JsonProperty("response_format") @Builder.Default private String responseFormat = ResponseFormat.URL.getName(); private String user; @Getter @AllArgsConstructor public enum SizeEnum implements Serializable { size_1024_1792("1024x1792"), size_1792_1024("1792x1024"), size_1024("1024x1024"), size_512("512x512"), size_256("256x256"), ; private final String name; } @AllArgsConstructor @Getter public enum ResponseFormat implements Serializable { URL("url"), B64_JSON("b64_json"), ; private final String name; } } ================================================ FILE: ai-openai/src/main/java/com/ai/openai/endPoint/images/resp/CreateImageResponse.java ================================================ package com.ai.openai.endPoint.images.resp; import com.ai.openai.endPoint.images.ImageObject; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import java.util.List; @Data @NoArgsConstructor @AllArgsConstructor @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public class CreateImageResponse { private Long created; private List data; } ================================================ FILE: ai-openai/src/main/java/com/ai/openai/endPoint/models/ModelObject.java ================================================ package com.ai.openai.endPoint.models; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @Data @AllArgsConstructor @NoArgsConstructor public class ModelObject { /** * 模型标识符,可在 API 端点中引用。 */ private String id; /** * 对象类型,始终为“model”。 */ private String object; /** * 创建模型时的 Unix 时间戳(以秒为单位)。 */ private long created; /** * 拥有模型的组织。 */ @JsonProperty("owned_by") private String ownedBy; } ================================================ FILE: ai-openai/src/main/java/com/ai/openai/endPoint/models/resp/DeleteFineTuneModelResponse.java ================================================ package com.ai.openai.endPoint.models.resp; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import java.io.Serializable; @Data @NoArgsConstructor @AllArgsConstructor @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public class DeleteFineTuneModelResponse implements Serializable { private String id; private String object; private Boolean deleted; } ================================================ FILE: ai-openai/src/main/java/com/ai/openai/endPoint/moderations/Categories.java ================================================ package com.ai.openai.endPoint.moderations; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import java.io.Serializable; @Data @AllArgsConstructor @NoArgsConstructor public class Categories implements Serializable { /** * 表达、煽动或宣扬基于种族、性别、民族、宗教、国籍、性取向、残疾状况或种姓的仇恨的内容。 */ private boolean hate; /** * 仇恨内容,还包括对目标群体的暴力或严重伤害。 */ @JsonProperty("hate/threatening") private boolean hateThreatening; /** * 对任何目标表达、煽动或宣扬骚扰性语言的内容。 */ @JsonProperty("harassment") private boolean harassment; /** * 骚扰内容还包括对任何目标的暴力或严重伤害。 */ @JsonProperty("harassment/threatening") private boolean harassmentThreatening; /** * 宣扬、鼓励或描绘自残行为(例如自杀、割伤和饮食失调)的内容。 */ @JsonProperty("self-harm") private boolean selfHarm; /** * 说话者表示他们正在或打算进行自残行为的内容,例如自杀、割伤和饮食失调。 */ @JsonProperty("self-harm/intent") private boolean selfHarmIntent; /** * 鼓励进行自残行为(例如自杀、割伤和饮食失调)的内容,或者提供有关如何实施此类行为的说明或建议的内容。 */ @JsonProperty("self-harm/instructions") private boolean selfHarmInstructions; /** * 旨在引起性兴奋的内容,例如对性活动的描述,或宣传性服务(不包括性教育和健康)的内容。 */ private boolean sexual; /** * 包含未满 18 周岁的个人的色情内容。 */ @JsonProperty("sexual/minors") private boolean sexualMinors; /** * 宣扬或美化暴力或歌颂他人遭受苦难或羞辱的内容。 */ private boolean violence; /** * 以极端血腥细节描绘死亡、暴力或严重身体伤害的暴力内容。 */ @JsonProperty("violence/graphic") private boolean violenceGraphic; } ================================================ FILE: ai-openai/src/main/java/com/ai/openai/endPoint/moderations/CategoryScores.java ================================================ package com.ai.openai.endPoint.moderations; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import java.io.Serializable; import java.math.BigDecimal; @Data @AllArgsConstructor @NoArgsConstructor public class CategoryScores implements Serializable { private BigDecimal hate; @JsonProperty("hate/threatening") private BigDecimal hateThreatening; /** * 对任何目标表达、煽动或宣扬骚扰性语言的内容。 */ @JsonProperty("harassment") private BigDecimal harassment; /** * 骚扰内容还包括对任何目标的暴力或严重伤害。 */ @JsonProperty("harassment/threatening") private BigDecimal harassmentThreatening; @JsonProperty("self-harm") private BigDecimal selfHarm; /** * 说话者表示他们正在或打算进行自残行为的内容,例如自杀、割伤和饮食失调。 */ @JsonProperty("self-harm/intent") private BigDecimal selfHarmIntent; /** * 鼓励进行自残行为(例如自杀、割伤和饮食失调)的内容,或者提供有关如何实施此类行为的说明或建议的内容。 */ @JsonProperty("self-harm/instructions") private BigDecimal selfHarmInstructions; private BigDecimal sexual; @JsonProperty("sexual/minors") private BigDecimal sexualMinors; private BigDecimal violence; @JsonProperty("violence/graphic") private BigDecimal violenceGraphic; } ================================================ FILE: ai-openai/src/main/java/com/ai/openai/endPoint/moderations/Result.java ================================================ package com.ai.openai.endPoint.moderations; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import java.io.Serializable; @Data @AllArgsConstructor @NoArgsConstructor public class Result implements Serializable { /** * 内容是否违反 OpenAI 的使用政策 */ private boolean flagged; /** * 类别列表,以及它们是否被标记 */ private Categories categories; /** * 类别列表及其按模型预测的分数 */ @JsonProperty("category_scores") private CategoryScores categoryScores; /** * 原文内容 */ @JsonIgnore private String content; } ================================================ FILE: ai-openai/src/main/java/com/ai/openai/endPoint/moderations/req/ModerationRequest.java ================================================ package com.ai.openai.endPoint.moderations.req; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import lombok.*; import java.util.ArrayList; import java.util.List; @Data @Builder @NoArgsConstructor @AllArgsConstructor @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public class ModerationRequest { @NonNull private List input; @Builder.Default private String model = Model.TEXT_MODERATION_LATEST.getName(); /** * 构造基础请求参数 * * @param input 文本 * @return 请求参数 */ public static ModerationRequest baseBuild(String input) { ArrayList list = new ArrayList<>(); list.add(input); return baseBuild(list); } /** * 构造基础请求参数 * * @param inputList 文本数组 * @return 请求参数 */ public static ModerationRequest baseBuild(List inputList) { return ModerationRequest.builder().input(inputList).build(); } @Getter @AllArgsConstructor public enum Model { TEXT_MODERATION_STABLE("text-moderation-stable"), TEXT_MODERATION_LATEST("text-moderation-latest"), ; private final String name; } } ================================================ FILE: ai-openai/src/main/java/com/ai/openai/endPoint/moderations/resp/ModerationResponse.java ================================================ package com.ai.openai.endPoint.moderations.resp; import com.ai.openai.endPoint.moderations.Result; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import java.util.List; @Data @NoArgsConstructor @AllArgsConstructor @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public class ModerationResponse { /** * 审核请求的唯一标识符 */ private String id; /** * 用于生成审核结果的模型 */ private String model; /** * 审核对象的列表 */ private List results; } ================================================ FILE: ai-openai/src/main/java/com/ai/openai/interceptor/HeaderInterceptor.java ================================================ package com.ai.openai.interceptor; import cn.hutool.http.ContentType; import cn.hutool.http.Header; import com.ai.core.strategy.KeyStrategy; import okhttp3.Interceptor; import okhttp3.Request; import okhttp3.Response; import org.jetbrains.annotations.NotNull; import java.io.IOException; import java.util.List; import static com.ai.core.exception.Constants.*; /** * @Description: OpenAI Key 拦截器 **/ public class HeaderInterceptor implements Interceptor { /** * 系统设置的 openAI apiKey */ private final List apiKeyBySystem; /** * 系统设置的 api 请求地址 */ private final String apiHostBySystem; /** * key 获取策略 */ private KeyStrategy, String> keyStrategy; public HeaderInterceptor(List apiKeyBySystem, String apiHostBySystem, KeyStrategy keyStrategy) { this.apiKeyBySystem = apiKeyBySystem; this.apiHostBySystem = apiHostBySystem; this.keyStrategy = keyStrategy; } @NotNull @Override public Response intercept(Chain chain) throws IOException { // 1. 获取原始 Request Request originalReq = chain.request(); // 2. 读取 apiKey;优先使用用户传递的 apiKey String apiKeyByUser = originalReq.header(API_KEY); String apiHostByUser = originalReq.header(API_HOST); String apiUrlByUser = originalReq.header(URL); String apiKey = apiKeyByUser == NULL ? keyStrategy.apply(apiKeyBySystem) : apiKeyByUser; // 3. 读取 apiUrl 和 apiHost,apiUrl 优先级大于 apiHost String apiUrl = apiUrlByUser == NULL ? apiHostByUser == NULL ? String.valueOf(originalReq.url()) : apiHostByUser + originalReq.url().url().getPath() : apiUrlByUser; // 4. 构建 Request Request request = originalReq.newBuilder() .url(apiUrl) .header(Header.AUTHORIZATION.getValue(), "Bearer " + apiKey) .header(Header.CONTENT_TYPE.getValue(), ContentType.JSON.getValue()) .method(originalReq.method(), originalReq.body()) .build(); // 5. 返回执行结果 return chain.proceed(request); } } ================================================ FILE: ai-openai/src/main/java/com/ai/openai/interceptor/ResponseInterceptor.java ================================================ package com.ai.openai.interceptor; import cn.hutool.json.JSONUtil; import com.ai.core.exception.BaseException; import com.ai.core.exception.Constants; import com.ai.openai.common.CommonListResponse; import lombok.extern.slf4j.Slf4j; import okhttp3.Interceptor; import okhttp3.Request; import okhttp3.Response; import java.io.IOException; import java.util.Objects; @Slf4j public class ResponseInterceptor implements Interceptor { @Override public Response intercept(Chain chain) throws IOException { // 1. 获取 req 和 resp Request original = chain.request(); Response response = chain.proceed(original); // 2. 判断返回状态 if (!response.isSuccessful() && response.body() != null) { // 2.1 获取返回的错误信息 String errorMsg = response.body().string(); CommonListResponse openAiResponse = JSONUtil.toBean(errorMsg, CommonListResponse.class); if (Constants.ERROR_MSG_MAP.containsKey(response.code())) { log.error(openAiResponse.getError().getMessage()); throw new BaseException(openAiResponse.getError().getMessage()); } log.error("--------> 请求异常:{}", errorMsg); if (Objects.nonNull(openAiResponse.getError())) { log.error(openAiResponse.getError().getMessage()); throw new BaseException(openAiResponse.getError().getMessage()); } throw new BaseException(Constants.ErrorMsg.RETRY_ERROR); } return response; } } ================================================ FILE: ai-openai/src/test/java/com/ai/openai/AudioApiTest.java ================================================ package com.ai.openai; import com.ai.core.strategy.impl.FirstKeyStrategy; import com.ai.openai.achieve.Configuration; import com.ai.openai.achieve.defaults.DefaultOpenAiSessionFactory; import com.ai.openai.achieve.standard.session.AggregationSession; import com.ai.openai.endPoint.audio.req.SttCompletionRequest; import com.ai.openai.endPoint.audio.req.TtsCompletionRequest; import com.ai.openai.endPoint.audio.resp.SttCompletionResponse; import lombok.extern.slf4j.Slf4j; import okhttp3.ResponseBody; import org.junit.Before; import org.junit.Test; import retrofit2.Call; import retrofit2.Callback; import retrofit2.Response; import java.io.*; import java.net.InetSocketAddress; import java.net.Proxy; import java.util.Arrays; import java.util.concurrent.CountDownLatch; import static com.ai.core.exception.Constants.NULL; /** * @Description: 测试语音相关接口功能 **/ @Slf4j public class AudioApiTest { private AggregationSession aggregationSession; @Before public void test_OpenAiSessionFactory() { // 1. 创建配置类 Configuration configuration = new Configuration(); // 2. 设置请求地址,若有代理商或者代理服务器,可填写为代理服务器的请求路径 configuration.setApiHost("https://api.openai.com"); // 3. 设置鉴权所需的API Key,可设置多个。 configuration.setKeyList(Arrays.asList("**************************")); // 4. 设置请求时 key 的使用策略,默认实现了:随机获取 和 固定第一个Key 两种方式。 configuration.setKeyStrategy(new FirstKeyStrategy()); // configuration.setKeyStrategy(new RandomKeyStrategy()); // 5. 设置代理,若不需要可不设置 configuration.setProxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress("127.0.0.1", 7890))); // 6. 创建 session 工厂,制造不同场景的 session DefaultOpenAiSessionFactory factory = new DefaultOpenAiSessionFactory(configuration); this.aggregationSession = factory.openAggregationSession(); } /** * 测试文字转语音 */ @Test public void test_tts() throws InterruptedException { // 定义请求参数 TtsCompletionRequest ttsCompletionRequest = TtsCompletionRequest.builder() .model(TtsCompletionRequest.Model.tts_1.getModuleName())// 设置使用的模型 .input("你好,我是chatGPT") .voice(TtsCompletionRequest.Voice.alloy.getVoiceName())// 设置声音的样式 .build(); // 回传文件存放的路径 File file = new File("doc/test/test_tts.mp3"); // 添加回调函数,发送请求 aggregationSession.getAudioSession().ttsCompletions(NULL, NULL, NULL, ttsCompletionRequest, new Callback() { @Override public void onResponse(Call call, Response response) { try (InputStream inputStream = response.body().byteStream(); OutputStream os = new BufferedOutputStream(new FileOutputStream(file))) { // 创建文件 if (!file.exists()) { if (!file.getParentFile().exists()) file.getParentFile().mkdir(); file.createNewFile(); } byte data[] = new byte[10240]; int len; while ((len = inputStream.read(data, 0, 10240)) != -1) { os.write(data, 0, len); } } catch (IOException e) { e.printStackTrace(); } } @Override public void onFailure(Call call, Throwable t) { t.printStackTrace(); } } ); // 阻塞等待 new CountDownLatch(1).await(); } /** * 测试语音转文字 */ @Test public void test_stt() { // 音频文件存放路径 File file = new File("doc/test/test_tts.mp3"); SttCompletionRequest sttCompletionRequest = SttCompletionRequest.builder().file(file).build(); SttCompletionResponse sttCompletionResponse = this.aggregationSession.getAudioSession().sttCompletions(NULL, NULL, NULL, sttCompletionRequest); log.info("测试结果:{}", sttCompletionResponse); } /** * 测试音频文件转文字后翻译为英文 */ @Test public void test_translation() { // 音频文件存放路径 File file = new File("doc/test/test_tts.mp3"); SttCompletionRequest sttCompletionRequest = SttCompletionRequest.builder().file(file).build(); SttCompletionResponse sttCompletionResponse = this.aggregationSession.getAudioSession().translationCompletions(NULL, NULL, NULL, sttCompletionRequest); log.info("测试结果:{}", sttCompletionResponse); } } ================================================ FILE: ai-openai/src/test/java/com/ai/openai/ChatApiTest.java ================================================ package com.ai.openai; import cn.hutool.json.JSONObject; import com.ai.core.exception.Constants; import com.ai.core.strategy.impl.FirstKeyStrategy; import com.ai.openai.achieve.Configuration; import com.ai.openai.achieve.defaults.DefaultOpenAiSessionFactory; import com.ai.openai.achieve.standard.session.AggregationSession; import com.ai.openai.endPoint.chat.Parameters; import com.ai.openai.endPoint.chat.msg.Content; import com.ai.openai.endPoint.chat.msg.DefaultMessage; import com.ai.openai.endPoint.chat.msg.ImgMessage; import com.ai.openai.endPoint.chat.req.*; import com.ai.openai.endPoint.chat.resp.ChatCompletionResponse; import com.ai.openai.endPoint.chat.resp.QaCompletionResponse; import com.ai.openai.endPoint.chat.tools.Tool; import com.ai.openai.endPoint.chat.tools.ToolFunction; import com.fasterxml.jackson.core.JsonProcessingException; import lombok.extern.slf4j.Slf4j; import okhttp3.Response; import okhttp3.sse.EventSource; import okhttp3.sse.EventSourceListener; import org.junit.Before; import org.junit.Test; import java.net.InetSocketAddress; import java.net.Proxy; import java.util.Arrays; import java.util.Collections; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutionException; import static com.ai.core.exception.Constants.NULL; /** * @Description: 测试聊天接口相关接口功能 */ @Slf4j public class ChatApiTest { private AggregationSession aggregationSession; @Before public void test_OpenAiSessionFactory() { // 1. 创建配置类 Configuration configuration = new Configuration(); // 2. 设置请求地址,若有代理商或者代理服务器,可填写为代理服务器的请求路径 configuration.setApiHost("https://api.openai.com"); // 3. 设置鉴权所需的API Key,可设置多个。 configuration.setKeyList(Arrays.asList("填入你的API Key")); // 4. 设置请求时 key 的使用策略,默认实现了:随机获取 和 固定第一个Key 两种方式。 configuration.setKeyStrategy(new FirstKeyStrategy()); // configuration.setKeyStrategy(new RandomKeyStrategy()); // 5. 设置代理,若不需要可不设置 configuration.setProxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress("127.0.0.1", 7890))); // 6. 创建 session 工厂,制造不同场景的 session DefaultOpenAiSessionFactory factory = new DefaultOpenAiSessionFactory(configuration); this.aggregationSession = factory.openAggregationSession(); } /** * 测试简单问答,相当于只有一轮问答。 */ @Test public void test_qa_completions() { QaCompletionRequest qaCompletionRequest = QaCompletionRequest.baseBuild("你是谁?"); QaCompletionResponse qaCompletionResponse = aggregationSession.getChatSession().qaCompletions(NULL, NULL, NULL, qaCompletionRequest); log.info("测试结果:{}", qaCompletionResponse); } /** * 测试简单问答,流式返回结果。 */ @Test public void test_qa_completions_stream() throws InterruptedException, JsonProcessingException { QaCompletionRequest qaCompletionRequest = QaCompletionRequest.builder() .prompt("讲一个笑话") .stream(true) // 设置流式返回 .build(); // 监听器监听返回的结果 aggregationSession.getChatSession().qaCompletions(NULL, NULL, NULL, qaCompletionRequest, new EventSourceListener() { @Override public void onEvent(EventSource eventSource, String id, String type, String data) { log.info("测试结果 id:{} type:{} data:{}", id, type, data); } @Override public void onFailure(EventSource eventSource, Throwable t, Response response) { log.error("失败 code:{} message:{}", response.code(), response.message()); } }); // 阻塞等待 new CountDownLatch(1).await(); } /** * 测试多轮对话 */ @Test public void test_chat_completions() { // 创建参数,上下文对话。 // 第一次的问题 DefaultChatCompletionRequest defaultChatCompletionRequest = DefaultChatCompletionRequest.baseBuild("1+1="); // 第一次的回复 defaultChatCompletionRequest.addMessage(Constants.Role.ASSISTANT.getRoleName(), "2"); // 第二次的问题 defaultChatCompletionRequest.addMessage(Constants.Role.USER.getRoleName(), "2+2="); // 询问第二次的问题的结果 ChatCompletionResponse chatCompletionResponse = aggregationSession.getChatSession().chatCompletions(NULL, NULL, NULL, defaultChatCompletionRequest); // 解析结果 chatCompletionResponse.getChoices().forEach(e -> { log.info("测试结果:{}", e.getMessage()); }); } /** * 测试函数对话,创建一个函数获取天气信息 * 下面的请求参数根据官方案例转换而来 */ @Test public void test_func_chat_completions() { // 定义第一个属性,地址信息 JSONObject location = new JSONObject(); location.putOpt("type", "string"); location.putOpt("description", "The city and state, e.g. San Francisco, CA"); // 定义第二个属性,时间信息 JSONObject unit = new JSONObject(); unit.putOpt("type", "string"); unit.putOpt("enum", Arrays.asList("celsius", "fahrenheit")); // 定义 properties,及将函数属性组合起来 JSONObject properties = new JSONObject(); properties.putOpt("location", location); properties.putOpt("unit", unit); // 定义 parameters Parameters parameters = Parameters.builder().type("object").properties(properties).required(Arrays.asList("location")).build(); // 构造函数信息 ToolFunction toolFunction = ToolFunction.builder().name("get_current_weather").description("Get the current weather in a given location").parameters(parameters).build(); // 构造工具 Tool tool = Tool.builder().type(Tool.Type.FUNCTION.getName()).function(toolFunction).build(); // 构造请求参数 FuncChatCompletionRequest funcChatCompletionRequest = FuncChatCompletionRequest.baseBuild("What is the weather like in Boston?"); funcChatCompletionRequest.setTools(Arrays.asList(tool)); funcChatCompletionRequest.setToolChoice("auto"); // 获取请求结果 ChatCompletionResponse chatCompletionResponse = aggregationSession.getChatSession().chatCompletions(NULL, NULL, NULL, funcChatCompletionRequest); log.info("测试结果:{}", chatCompletionResponse); } /** * 测试图片对话,需要GPT4权限 */ @Test public void test_img_chat_completions() { // 构造对话内容 Content textContent = Content.BuildTextContent("这张图片当中有什么?"); Content imgContent = Content.BuildImageUrlContent("https://oaidalleapiprodscus.blob.core.windows.net/private/org-HL3RbCOW1GSH0YPFWak9m6be/user-AzfIxMQpzvc9raSA0TZ9sHOw/img-oft6JFrL4ilB4mmapSud8Vpy.png?st=2024-03-08T13%3A31%3A32Z&se=2024-03-08T15%3A31%3A32Z&sp=r&sv=2021-08-06&sr=b&rscd=inline&rsct=image/png&skoid=6aaadede-4fb3-4698-a8f6-684d7786b067&sktid=a48cca56-e6da-484e-a814-9c849652bcb3&skt=2024-03-07T18%3A11%3A55Z&ske=2024-03-08T18%3A11%3A55Z&sks=b&skv=2021-08-06&sig=wLcx9Uo6XiYT10GXIFcJwfd08BKoJ07k7cP7qJvYGx4%3D"); // 构造 msg 内容 ImgMessage imgMessage = ImgMessage.builder().role(Constants.Role.USER.getRoleName()).content(Arrays.asList(textContent, imgContent)).build(); // 构造请求参数,chatGPT 4 支持图片对话 ImgChatCompletionRequest imgChatCompletionRequest = ImgChatCompletionRequest.builder().model(BaseChatCompletionRequest.Model.GPT_4_VISION_PREVIEW.getModuleName()).messages(Arrays.asList(imgMessage)).build(); // 获取结果 ChatCompletionResponse chatCompletionResponse = aggregationSession.getChatSession().chatCompletions(NULL, NULL, NULL, imgChatCompletionRequest); log.info("测试结果:{}", chatCompletionResponse); } /** * 测试聊天对话,流式返回结果。 */ @Test public void test_chat_completions_stream() throws InterruptedException, JsonProcessingException { // 建造者模式构造参数 DefaultChatCompletionRequest defaultChatCompletionRequest = DefaultChatCompletionRequest.builder() .stream(true)// 开启流式返回 .messages(Collections.singletonList(DefaultMessage .builder() .role(Constants.Role.USER.getRoleName()) .content("讲一个笑话") .build())) .model(BaseChatCompletionRequest.Model.GPT_3_5_TURBO.getModuleName()) .build(); aggregationSession.getChatSession().chatCompletions(NULL, NULL, NULL, defaultChatCompletionRequest, new EventSourceListener() { @Override public void onEvent(EventSource eventSource, String id, String type, String data) { log.info("测试结果 id:{} type:{} data:{}", id, type, data); } @Override public void onFailure(EventSource eventSource, Throwable t, Response response) { log.error("失败 code:{} message:{}", response.code(), response.message()); } }); // 阻塞等待 new CountDownLatch(1).await(); } /** * 测试 CompletableFuture 异步调用。 */ @Test public void test_chat_completions_future() throws JsonProcessingException, InterruptedException, ExecutionException { // 构造请求参数 DefaultChatCompletionRequest defaultChatCompletionRequest = DefaultChatCompletionRequest.builder() .stream(true) .messages(Collections.singletonList(DefaultMessage .builder() .role(Constants.Role.USER.getRoleName()) .content("1+1=") .build())) .model(BaseChatCompletionRequest.Model.GPT_3_5_TURBO.getModuleName()).build(); // 等待结果 CompletableFuture future = aggregationSession.getChatSession().chatCompletionsFuture(NULL, NULL, NULL, defaultChatCompletionRequest); log.info("测试结果:{}", future.get()); } } ================================================ FILE: ai-openai/src/test/java/com/ai/openai/EmbeddingApiTest.java ================================================ package com.ai.openai; import com.ai.core.strategy.impl.FirstKeyStrategy; import com.ai.openai.achieve.Configuration; import com.ai.openai.achieve.defaults.DefaultOpenAiSessionFactory; import com.ai.openai.achieve.standard.session.AggregationSession; import com.ai.openai.endPoint.embeddings.EmbeddingObject; import com.ai.openai.endPoint.embeddings.req.EmbeddingCompletionRequest; import com.ai.openai.endPoint.embeddings.resp.EmbeddingCompletionResponse; import lombok.extern.slf4j.Slf4j; import org.junit.Before; import org.junit.Test; import java.net.InetSocketAddress; import java.net.Proxy; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import static com.ai.core.exception.Constants.NULL; /** * @Description: 测试嵌入相关接口功能 */ @Slf4j public class EmbeddingApiTest { private AggregationSession aggregationSession; @Before public void test_OpenAiSessionFactory() { // 1. 创建配置类 Configuration configuration = new Configuration(); // 2. 设置请求地址,若有代理商或者代理服务器,可填写为代理服务器的请求路径 configuration.setApiHost("https://api.openai.com"); // 3. 设置鉴权所需的API Key,可设置多个。 configuration.setKeyList(Arrays.asList("**************************")); // 4. 设置请求时 key 的使用策略,默认实现了:随机获取 和 固定第一个Key 两种方式。 configuration.setKeyStrategy(new FirstKeyStrategy()); // configuration.setKeyStrategy(new RandomKeyStrategy()); // 5. 设置代理,若不需要可不设置 configuration.setProxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress("127.0.0.1", 7890))); // 6. 创建 session 工厂,制造不同场景的 session DefaultOpenAiSessionFactory factory = new DefaultOpenAiSessionFactory(configuration); this.aggregationSession = factory.openAggregationSession(); } /** * 测试单个文本 */ @Test public void test_embedding() { EmbeddingCompletionResponse embeddingCompletionResponse = aggregationSession.getEmbeddingSession().embeddingCompletions(NULL, NULL, NULL, "你好"); for (EmbeddingObject embeddingObject : embeddingCompletionResponse.getData()) { System.out.println(embeddingObject.getEmbedding().length); } log.info("返回结果:{}", embeddingCompletionResponse); log.info("返回结果:{}", embeddingCompletionResponse.getData().size()); } /** * 测试多个文本嵌入 */ @Test public void test_embedding_list() { List inputList = new ArrayList<>(); inputList.add("你好"); inputList.add("世界"); EmbeddingCompletionResponse embeddingCompletionResponse = aggregationSession.getEmbeddingSession().embeddingCompletions(NULL, NULL, NULL, inputList); log.info("返回结果:{}", embeddingCompletionResponse); } @Test public void test_embedding_req() { List inputList = new ArrayList<>(); inputList.add("你好"); inputList.add("世界"); EmbeddingCompletionRequest embeddingCompletionRequest = EmbeddingCompletionRequest.baseBuild(inputList); EmbeddingCompletionResponse embeddingCompletionResponse = aggregationSession.getEmbeddingSession().embeddingCompletions(NULL, NULL, NULL, embeddingCompletionRequest); log.info("返回结果:{}", embeddingCompletionResponse); } } ================================================ FILE: ai-openai/src/test/java/com/ai/openai/FilesApiTest.java ================================================ package com.ai.openai; import com.ai.core.strategy.impl.FirstKeyStrategy; import com.ai.openai.achieve.Configuration; import com.ai.openai.achieve.defaults.DefaultOpenAiSessionFactory; import com.ai.openai.achieve.standard.session.AggregationSession; import com.ai.openai.endPoint.files.FileObject; import com.ai.openai.endPoint.files.resp.DeleteFileResponse; import lombok.extern.slf4j.Slf4j; import okhttp3.ResponseBody; import org.junit.Before; import org.junit.Test; import java.io.File; import java.net.InetSocketAddress; import java.net.Proxy; import java.util.Arrays; import java.util.List; import static com.ai.core.exception.Constants.NULL; /** * @Description: 测试文件相关接口功能 **/ @Slf4j public class FilesApiTest { private AggregationSession aggregationSession; @Before public void test_OpenAiSessionFactory() { // 1. 创建配置类 Configuration configuration = new Configuration(); // 2. 设置请求地址,若有代理商或者代理服务器,可填写为代理服务器的请求路径 configuration.setApiHost("https://api.openai.com"); // 3. 设置鉴权所需的API Key,可设置多个。 configuration.setKeyList(Arrays.asList("填入你的API Key")); // 4. 设置请求时 key 的使用策略,默认实现了:随机获取 和 固定第一个Key 两种方式。 configuration.setKeyStrategy(new FirstKeyStrategy()); // configuration.setKeyStrategy(new RandomKeyStrategy()); // 5. 设置代理,若不需要可不设置 configuration.setProxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress("127.0.0.1", 7890))); // 6. 创建 session 工厂,制造不同场景的 session DefaultOpenAiSessionFactory factory = new DefaultOpenAiSessionFactory(configuration); this.aggregationSession = factory.openAggregationSession(); } /** * 测试列出文件 */ @Test public void test_list_file() { List fileObjects = aggregationSession.getFilesSession().listFilesCompletions(NULL, NULL, NULL); log.info("测试结果:{}", fileObjects); } /** * 测试上传文件 */ @Test public void test_upload_file() { File file = new File("src/main/resources/test1.txt"); FileObject fileObject = aggregationSession.getFilesSession().uploadFileCompletions(NULL, NULL, NULL, file, "fine-tune"); log.info("测试结果:{}", fileObject); } /** * 测试删除文件 */ @Test public void test_delete_file() { DeleteFileResponse deleteFileResponse = aggregationSession.getFilesSession().deleteFileCompletions(NULL, NULL, NULL, "file-B3CAfSS2ibv7cFmSbl5m1CPI"); log.info("测试结果:{}", deleteFileResponse); } /** * 测试检索文件 */ @Test public void test_retrieve_file() { FileObject fileObject = aggregationSession.getFilesSession().retrieveFileCompletions(NULL, NULL, NULL, "file-B3CAfSS2ibv7cFmSbl5m1CPI"); log.info("测试结果:{}", fileObject); } /** * 测试获取检索的文件内容 */ @Test public void test_retrieve_file_context() { ResponseBody responseBody = aggregationSession.getFilesSession().retrieveFileContextCompletions(NULL, NULL, NULL, "file-B3CAfSS2ibv7cFmSbl5m1CPI"); log.info("测试结果:{}", responseBody); } } ================================================ FILE: ai-openai/src/test/java/com/ai/openai/FineTuningApiTest.java ================================================ package com.ai.openai; import com.ai.core.strategy.impl.FirstKeyStrategy; import com.ai.openai.achieve.Configuration; import com.ai.openai.achieve.defaults.DefaultOpenAiSessionFactory; import com.ai.openai.achieve.standard.session.AggregationSession; import com.ai.openai.common.CommonListResponse; import com.ai.openai.endPoint.fineTuning.FineTuningEvent; import com.ai.openai.endPoint.fineTuning.req.FineTuningRequest; import com.ai.openai.endPoint.fineTuning.req.ListFineTuningRequest; import com.ai.openai.endPoint.fineTuning.resp.FineTuningResponse; import lombok.extern.slf4j.Slf4j; import org.junit.Before; import org.junit.Test; import java.net.InetSocketAddress; import java.net.Proxy; import java.util.Arrays; import static com.ai.core.exception.Constants.NULL; /** * @Description: 测试微调相关接口功能 **/ @Slf4j public class FineTuningApiTest { private AggregationSession aggregationSession; @Before public void test_OpenAiSessionFactory() { // 1. 创建配置类 Configuration configuration = new Configuration(); // 2. 设置请求地址,若有代理商或者代理服务器,可填写为代理服务器的请求路径 configuration.setApiHost("https://api.openai.com"); // 3. 设置鉴权所需的API Key,可设置多个。 configuration.setKeyList(Arrays.asList("填入你的API Key")); // 4. 设置请求时 key 的使用策略,默认实现了:随机获取 和 固定第一个Key 两种方式。 configuration.setKeyStrategy(new FirstKeyStrategy()); // configuration.setKeyStrategy(new RandomKeyStrategy()); // 5. 设置代理,若不需要可不设置 configuration.setProxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress("127.0.0.1", 7890))); // 6. 创建 session 工厂,制造不同场景的 session DefaultOpenAiSessionFactory factory = new DefaultOpenAiSessionFactory(configuration); this.aggregationSession = factory.openAggregationSession(); } /** * 测试创建微调 */ @Test public void test_create_fine_tuning() { FineTuningRequest fineTuningRequest = FineTuningRequest .builder() .trainingFile("file-BK7bzQj3FfZFXr7DbL6xJwfo") .build(); FineTuningResponse fineTuningResponse = aggregationSession.getFineTuningSession().createFineTuningJobCompletions(NULL, NULL, NULL, fineTuningRequest); log.info("返回结果:{}", fineTuningResponse); } /** * 测试列出微调作业 */ @Test public void test_list_fine_tuning_1() { ListFineTuningRequest listFineTuningRequest = ListFineTuningRequest.builder().build(); CommonListResponse fineTuneJobListFineTuningResponse = aggregationSession.getFineTuningSession().listFineTuningJobsCompletions(NULL, NULL, NULL, listFineTuningRequest); log.info("返回结果:{}", fineTuneJobListFineTuningResponse); } /** * 测试列出微调作业 */ @Test public void test_list_fine_tuning_2() { CommonListResponse fineTuneJobListFineTuningResponse = aggregationSession.getFineTuningSession().listFineTuningJobsCompletions(NULL, NULL, NULL, null, null); log.info("返回结果:{}", fineTuneJobListFineTuningResponse); } /** * 测试检索微调作业 */ @Test public void test_retrieve_fine_tuning() { FineTuningResponse fineTuningResponse = aggregationSession.getFineTuningSession().retrieveFineTuningJobCompletions(NULL, NULL, NULL, "ft-AF1WoRqd3aJAHsqc9NY7iL8F"); log.info("返回结果:{}", fineTuningResponse); } /** * 测试关闭微调作业 */ @Test public void test_cancel_fine_tuning() { FineTuningResponse fineTuningResponse = aggregationSession.getFineTuningSession().cancelFineTuningJobCompletions(NULL, NULL, NULL, "ft-AF1WoRqd3aJAHsqc9NY7iL8F"); log.info("返回结果:{}", fineTuningResponse); } /** * 测试列出微调事件 */ @Test public void test_list_fine_tuning_events() { CommonListResponse fineTuningEventListFineTuningResponse = aggregationSession.getFineTuningSession().listFineTuningEventsCompletions(NULL, NULL, NULL, "ftjob-abc123"); log.info("返回结果:{}", fineTuningEventListFineTuningResponse); } } ================================================ FILE: ai-openai/src/test/java/com/ai/openai/ImageApiTest.java ================================================ package com.ai.openai; import com.ai.common.utils.ImageUtils; import com.ai.core.strategy.impl.FirstKeyStrategy; import com.ai.openai.achieve.Configuration; import com.ai.openai.achieve.defaults.DefaultOpenAiSessionFactory; import com.ai.openai.achieve.standard.session.AggregationSession; import com.ai.openai.endPoint.images.ImageObject; import com.ai.openai.endPoint.images.req.CreateImageRequest; import com.ai.openai.endPoint.images.req.ImageEditRequest; import com.ai.openai.endPoint.images.req.ImageVariationRequest; import lombok.extern.slf4j.Slf4j; import org.junit.Before; import org.junit.Test; import java.io.File; import java.net.InetSocketAddress; import java.net.Proxy; import java.util.Arrays; import java.util.List; import static com.ai.core.exception.Constants.NULL; /** * @Description: 测试图片相关接口功能 **/ @Slf4j public class ImageApiTest { private AggregationSession aggregationSession; @Before public void test_OpenAiSessionFactory() { // 1. 创建配置类 Configuration configuration = new Configuration(); // 2. 设置请求地址,若有代理商或者代理服务器,可填写为代理服务器的请求路径 configuration.setApiHost("https://api.openai.com"); // 3. 设置鉴权所需的API Key,可设置多个。 configuration.setKeyList(Arrays.asList("填入你的API Key")); // 4. 设置请求时 key 的使用策略,默认实现了:随机获取 和 固定第一个Key 两种方式。 configuration.setKeyStrategy(new FirstKeyStrategy()); // configuration.setKeyStrategy(new RandomKeyStrategy()); // 5. 设置代理,若不需要可不设置 configuration.setProxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress("127.0.0.1", 7890))); // 6. 创建 session 工厂,制造不同场景的 session DefaultOpenAiSessionFactory factory = new DefaultOpenAiSessionFactory(configuration); this.aggregationSession = factory.openAggregationSession(); } /** * 测试图片生成,返回B64Json格式 */ @Test public void test_create_image_b64json() { CreateImageRequest createImageRequest = CreateImageRequest.baseBuild("画一个花园,花园里面有蝴蝶。"); createImageRequest.setResponseFormat(CreateImageRequest.Format.B64JSON.getFormat()); List imageObjectList = aggregationSession.getImageSession().createImageCompletions(NULL, NULL, NULL, createImageRequest); for (int i = 0; i < imageObjectList.size(); i++) { ImageUtils.convertBase64StrToImage(imageObjectList.get(i).getB64Json(), "D:\\chatGPT-api\\AI-java\\doc\\test\\test_openai_create_image_" + i + ".png"); } } /** * 测试图片生成,返回URL格式 */ @Test public void test_create_image_url() { CreateImageRequest createImageRequest = CreateImageRequest.baseBuild("画一个花园,花园里面有蝴蝶。"); createImageRequest.setResponseFormat(CreateImageRequest.Format.URL.getFormat()); List imageObjectList = aggregationSession.getImageSession().createImageCompletions(NULL, NULL, NULL, createImageRequest); for (int i = 0; i < imageObjectList.size(); i++) { System.out.println(imageObjectList.get(i).getUrl()); } } /** * 测试编辑图片 */ @Test public void test_edit_image() { File file = new File("D:\\chatGPT-api\\AI-java\\doc\\test\\test_edit_image.png"); ImageEditRequest imageEditRequest = ImageEditRequest.baseBuild("给小熊的背后加上一只梅花鹿。"); List imageObjectList = aggregationSession.getImageSession().editImageCompletions(NULL, NULL, NULL, file, null, imageEditRequest); log.info("测试结果:{}", imageObjectList); } /** * 测试创建图片变体 */ @Test public void test_variation_image() { File file = new File("D:\\chatGPT-api\\AI-java\\doc\\test\\test_edit_image.png"); ImageVariationRequest imageVariationRequest = ImageVariationRequest.builder().build(); List imageObjectList = aggregationSession.getImageSession().variationImageCompletions(NULL, NULL, NULL, file, imageVariationRequest); log.info("测试结果:{}", imageObjectList); } } ================================================ FILE: ai-openai/src/test/java/com/ai/openai/ModelApiTest.java ================================================ package com.ai.openai; import com.ai.core.strategy.impl.FirstKeyStrategy; import com.ai.openai.achieve.Configuration; import com.ai.openai.achieve.defaults.DefaultOpenAiSessionFactory; import com.ai.openai.achieve.standard.session.AggregationSession; import com.ai.openai.endPoint.models.ModelObject; import com.ai.openai.endPoint.models.resp.DeleteFineTuneModelResponse; import lombok.extern.slf4j.Slf4j; import org.junit.Before; import org.junit.Test; import java.net.InetSocketAddress; import java.net.Proxy; import java.util.Arrays; import java.util.List; import static com.ai.core.exception.Constants.NULL; /** * @Description: 测试模型相关接口功能 **/ @Slf4j public class ModelApiTest { private AggregationSession aggregationSession; @Before public void test_OpenAiSessionFactory() { // 1. 创建配置类 Configuration configuration = new Configuration(); // 2. 设置请求地址,若有代理商或者代理服务器,可填写为代理服务器的请求路径 configuration.setApiHost("https://api.openai.com"); // 3. 设置鉴权所需的API Key,可设置多个。 configuration.setKeyList(Arrays.asList("填入你的API Key")); // 4. 设置请求时 key 的使用策略,默认实现了:随机获取 和 固定第一个Key 两种方式。 configuration.setKeyStrategy(new FirstKeyStrategy()); // configuration.setKeyStrategy(new RandomKeyStrategy()); // 5. 设置代理,若不需要可不设置 configuration.setProxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress("127.0.0.1", 7890))); // 6. 创建 session 工厂,制造不同场景的 session DefaultOpenAiSessionFactory factory = new DefaultOpenAiSessionFactory(configuration); this.aggregationSession = factory.openAggregationSession(); } /** * 测试列出模型接口 */ @Test public void test_list_model() { List modelObjects = aggregationSession.getModelSession().listModelCompletions(NULL, NULL, NULL); log.info("返回结果:{}", modelObjects); } /** * 测试检索模型接口 */ @Test public void test_retrieve_model() { ModelObject modelObject = aggregationSession.getModelSession().retrieveModelCompletions(NULL, NULL, NULL, "gpt-3.5-turbo-instruct"); log.info("返回结果:{}", modelObject); } /** * 测试删除微调模型接口 */ @Test public void test_delete_fine_tune_model() { DeleteFineTuneModelResponse deleteFineTuneModelResponse = aggregationSession.getModelSession().deleteFineTuneModelCompletions(NULL, NULL, NULL, "gpt-3.5-turbo-instruct"); log.info("返回结果:{}", deleteFineTuneModelResponse); } } ================================================ FILE: ai-openai/src/test/java/com/ai/openai/ModerationApiTest.java ================================================ package com.ai.openai; import com.ai.core.strategy.impl.FirstKeyStrategy; import com.ai.openai.achieve.Configuration; import com.ai.openai.achieve.defaults.DefaultOpenAiSessionFactory; import com.ai.openai.achieve.standard.session.AggregationSession; import com.ai.openai.endPoint.moderations.Result; import com.ai.openai.endPoint.moderations.req.ModerationRequest; import com.ai.openai.endPoint.moderations.resp.ModerationResponse; import lombok.extern.slf4j.Slf4j; import org.junit.Before; import org.junit.Test; import java.net.InetSocketAddress; import java.net.Proxy; import java.util.ArrayList; import java.util.Arrays; import static com.ai.core.exception.Constants.NULL; /** * @Description: 测试审核相关接口功能 **/ @Slf4j public class ModerationApiTest { private AggregationSession aggregationSession; @Before public void test_OpenAiSessionFactory() { // 1. 创建配置类 Configuration configuration = new Configuration(); // 2. 设置请求地址,若有代理商或者代理服务器,可填写为代理服务器的请求路径 configuration.setApiHost("https://api.openai.com"); // 3. 设置鉴权所需的API Key,可设置多个。 configuration.setKeyList(Arrays.asList("**************************")); // 4. 设置请求时 key 的使用策略,默认实现了:随机获取 和 固定第一个Key 两种方式。 configuration.setKeyStrategy(new FirstKeyStrategy()); // configuration.setKeyStrategy(new RandomKeyStrategy()); // 5. 设置代理,若不需要可不设置 configuration.setProxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress("127.0.0.1", 7890))); // 6. 创建 session 工厂,制造不同场景的 session DefaultOpenAiSessionFactory factory = new DefaultOpenAiSessionFactory(configuration); this.aggregationSession = factory.openAggregationSession(); } /** * 测试审核 */ @Test public void test_moderation() { ArrayList list = new ArrayList<>(); list.add("你好"); list.add("我要杀了你"); ModerationRequest moderationRequest = ModerationRequest.builder().input(list).build(); ModerationResponse moderationResponse = aggregationSession.getModerationSession().moderationCompletions(NULL, NULL, NULL, moderationRequest); for (Result result : moderationResponse.getResults()) { System.out.println(result.getContent() + " " + result.isFlagged()); } } } ================================================ FILE: ai-spark/pom.xml ================================================ AI-java com.ai 1.0 4.0.0 ai-spark UTF-8 UTF-8 1.8 1.8 1.8 4.13.2 com.ai ai-common 1.0 com.ai ai-core 1.0 junit junit ${junit.version} test ================================================ FILE: ai-spark/src/main/java/com/ai/spark/achieve/ApiData.java ================================================ package com.ai.spark.achieve; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; /** * 记录用户API信息 */ @Data @Builder @NoArgsConstructor @AllArgsConstructor public class ApiData { private String appId; private String apiKey; private String apiSecret; } ================================================ FILE: ai-spark/src/main/java/com/ai/spark/achieve/Configuration.java ================================================ package com.ai.spark.achieve; import com.ai.core.config.BaseConfiguration; import com.ai.spark.achieve.standard.api.SparkApiServer; import lombok.*; import org.jetbrains.annotations.NotNull; import java.util.List; /** * @Description: 配置信息 **/ @Data @ToString(callSuper = true) @EqualsAndHashCode(callSuper = true) @NoArgsConstructor @AllArgsConstructor public class Configuration extends BaseConfiguration { /** * api 服务提供者 */ private SparkApiServer sparkApiServer; /** * api Key 集合 */ @NotNull private List keyList; public ApiData getSystemApiData() { return (ApiData) this.getKeyStrategy().apply(keyList); } } ================================================ FILE: ai-spark/src/main/java/com/ai/spark/achieve/defaults/DefaultSparkSessionFactory.java ================================================ package com.ai.spark.achieve.defaults; import com.ai.core.factory.SessionFactory; import com.ai.spark.achieve.Configuration; import com.ai.spark.achieve.defaults.session.DefaultAggregationSession; import com.ai.spark.achieve.standard.api.SparkApiServer; import com.ai.spark.achieve.standard.session.AggregationSession; import com.ai.spark.interceptor.BaseUrlInterceptor; import com.ai.spark.interceptor.ResponseInterceptor; import okhttp3.OkHttpClient; import okhttp3.logging.HttpLoggingInterceptor; import retrofit2.Retrofit; import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory; import retrofit2.converter.jackson.JacksonConverterFactory; import java.util.concurrent.TimeUnit; import static com.ai.common.utils.ValidationUtils.ensureNotNull; public class DefaultSparkSessionFactory implements SessionFactory { private final Configuration configuration; public DefaultSparkSessionFactory(Configuration configuration) { this.configuration = ensureNotNull(configuration, "configuration"); } @Override public OkHttpClient createHttpClient() { // 1. 日志配置 HttpLoggingInterceptor httpLoggingInterceptor = new HttpLoggingInterceptor(); httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.NONE); // 2. 开启 Http 客户端 OkHttpClient.Builder builder = new OkHttpClient.Builder() .addInterceptor(httpLoggingInterceptor) .addInterceptor(new BaseUrlInterceptor()) .addInterceptor(new ResponseInterceptor())// 设置返回信息拦截器 .connectTimeout(450, TimeUnit.SECONDS) .writeTimeout(450, TimeUnit.SECONDS) .readTimeout(450, TimeUnit.SECONDS); // 3. 检查是否需要代理 if (configuration.getProxy() != null) { builder.proxy(configuration.getProxy()); } return builder.build(); } @Override public SparkApiServer createApiServer(OkHttpClient okHttpClient) { return new Retrofit.Builder() .baseUrl(configuration.getApiHost()) .client(okHttpClient) .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) .addConverterFactory(JacksonConverterFactory.create()) .build().create(SparkApiServer.class); } @Override public AggregationSession openAggregationSession() { OkHttpClient okHttpClient = createHttpClient(); configuration.setOkHttpClient(okHttpClient); configuration.setSparkApiServer(createApiServer(okHttpClient)); return new DefaultAggregationSession(configuration); } } ================================================ FILE: ai-spark/src/main/java/com/ai/spark/achieve/defaults/listener/BaseListener.java ================================================ package com.ai.spark.achieve.defaults.listener; import lombok.Data; import lombok.extern.slf4j.Slf4j; import okhttp3.Response; import okhttp3.WebSocket; import okhttp3.WebSocketListener; import okio.ByteString; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @Slf4j @Data public abstract class BaseListener extends WebSocketListener { /** * WebSocket服务发生异常的回调,可以覆盖重写。 * 默认抛出异常 * * @param t 异常 * @param response 返回值 */ public void onWebSocketError(Throwable t, Response response) { log.error("调用星火模型时,WebSocket发生异常:{}", response); t.printStackTrace(); } /** * 星火大模型发生异常 * * @param resp 大模型返回值 */ public abstract void onChatError(RESP resp); /** * 星火大模型正常返回信息 * * @param resp 大模型返回值 */ public abstract void onChatOutput(RESP resp); /** * 星火大模型返回信息结束回调 */ public abstract void onChatEnd(); @Override public void onClosed(@NotNull WebSocket webSocket, int code, @NotNull String reason) { super.onClosed(webSocket, code, reason); } @Override public void onClosing(@NotNull WebSocket webSocket, int code, @NotNull String reason) { super.onClosing(webSocket, code, reason); } @Override public void onFailure(@NotNull WebSocket webSocket, @NotNull Throwable t, @Nullable Response response) { webSocket.close(1000, ""); this.onWebSocketError(t, response); } @Override public abstract void onMessage(@NotNull WebSocket webSocket, @NotNull String text); @Override public void onMessage(@NotNull WebSocket webSocket, @NotNull ByteString bytes) { super.onMessage(webSocket, bytes); } @Override public void onOpen(@NotNull WebSocket webSocket, @NotNull Response response) { super.onOpen(webSocket, response); } } ================================================ FILE: ai-spark/src/main/java/com/ai/spark/achieve/defaults/listener/ChatListener.java ================================================ package com.ai.spark.achieve.defaults.listener; import com.ai.common.utils.JsonUtils; import com.ai.spark.common.Usage; import com.ai.spark.endPoint.chat.ChatHeader; import com.ai.spark.endPoint.chat.Choice; import com.ai.spark.endPoint.chat.req.ChatRequest; import com.ai.spark.endPoint.chat.resp.ChatResponse; import lombok.Data; import lombok.extern.slf4j.Slf4j; import okhttp3.Response; import okhttp3.WebSocket; import okio.ByteString; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import static com.ai.common.utils.ValidationUtils.ensureNotNull; /** * 星火大模型流式返回监听器 */ @Slf4j @Data public abstract class ChatListener extends BaseListener { private ChatRequest chatRequest; public ChatListener(ChatRequest chatRequest) { this.chatRequest = ensureNotNull(chatRequest, "chatRequest"); } /** * WebSocket服务发生异常的回调,可以覆盖重写。 * 默认抛出异常 * * @param t 异常 * @param response 返回值 */ public void onWebSocketError(Throwable t, Response response) { log.error("调用星火模型时,WebSocket发生异常:{}", response); t.printStackTrace(); } /** * 星火大模型发生异常 * * @param chatResponse 大模型返回值 */ public abstract void onChatError(ChatResponse chatResponse); /** * 星火大模型正常返回信息 * * @param chatResponse 大模型返回值 */ public abstract void onChatOutput(ChatResponse chatResponse); /** * 星火大模型返回信息结束回调 */ public abstract void onChatEnd(); @Override public void onClosed(@NotNull WebSocket webSocket, int code, @NotNull String reason) { super.onClosed(webSocket, code, reason); } @Override public void onClosing(@NotNull WebSocket webSocket, int code, @NotNull String reason) { super.onClosing(webSocket, code, reason); } @Override public void onFailure(@NotNull WebSocket webSocket, @NotNull Throwable t, @Nullable Response response) { webSocket.close(1000, ""); this.onWebSocketError(t, response); } @Override public void onMessage(@NotNull WebSocket webSocket, @NotNull String text) { ChatResponse chatResponse = JsonUtils.fromJson(text, ChatResponse.class); if (ChatHeader.Code.SUCCESS.getValue() != chatResponse.getChatHeader().getCode()) { log.warn("调用星火模型发生错误,错误码为:{},请求的sid为:{}", chatResponse.getChatHeader().getCode(), chatResponse.getChatHeader().getSid()); webSocket.close(1000, "星火模型调用异常"); this.onChatError(chatResponse); return; } this.onChatOutput(chatResponse); if (Choice.Status.END.getValue() == chatResponse.getChatHeader().getStatus()) { // 可以关闭连接,释放资源 webSocket.close(1000, "星火模型返回结束"); Usage usage = chatResponse.getChatPayload().getUsage(); this.onChatEnd(); } } @Override public void onMessage(@NotNull WebSocket webSocket, @NotNull ByteString bytes) { super.onMessage(webSocket, bytes); } @Override public void onOpen(@NotNull WebSocket webSocket, @NotNull Response response) { super.onOpen(webSocket, response); webSocket.send(JsonUtils.toJson(chatRequest)); } } ================================================ FILE: ai-spark/src/main/java/com/ai/spark/achieve/defaults/listener/DocumentChatListener.java ================================================ package com.ai.spark.achieve.defaults.listener; import com.ai.common.utils.JsonUtils; import com.ai.spark.endPoint.chat.req.DocumentChatRequest; import com.ai.spark.endPoint.chat.resp.DocumentChatResponse; import lombok.Data; import lombok.extern.slf4j.Slf4j; import okhttp3.Response; import okhttp3.WebSocket; import okio.ByteString; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import static com.ai.common.utils.ValidationUtils.ensureNotNull; /** * 星火大模型文档对话流式返回监听器 */ @Slf4j @Data public abstract class DocumentChatListener extends BaseListener { private DocumentChatRequest documentChatRequest; /** * 构造方法,传入大模型参数 * * @param documentChatRequest 大模型参数 */ public DocumentChatListener(DocumentChatRequest documentChatRequest) { this.documentChatRequest = ensureNotNull(documentChatRequest, "documentChatRequest"); } /** * WebSocket服务发生异常的回调,可以覆盖重写。 * 默认抛出异常 * * @param t 异常 * @param response 返回值 */ public void onWebSocketError(Throwable t, Response response) { log.error("调用星火模型时,WebSocket发生异常:{}", response); t.printStackTrace(); } /** * 星火大模型发生异常 * * @param documentChatResponse 大模型返回值 */ public abstract void onChatError(DocumentChatResponse documentChatResponse); /** * 星火大模型正常返回信息 * * @param documentChatResponse 大模型返回值 */ public abstract void onChatOutput(DocumentChatResponse documentChatResponse); /** * 星火大模型返回信息结束回调 */ public abstract void onChatEnd(); @Override public void onClosed(@NotNull WebSocket webSocket, int code, @NotNull String reason) { super.onClosed(webSocket, code, reason); } @Override public void onClosing(@NotNull WebSocket webSocket, int code, @NotNull String reason) { super.onClosing(webSocket, code, reason); } @Override public void onFailure(@NotNull WebSocket webSocket, @NotNull Throwable t, @Nullable Response response) { webSocket.close(1000, ""); this.onWebSocketError(t, response); } @Override public void onMessage(@NotNull WebSocket webSocket, @NotNull String text) { DocumentChatResponse documentChatResponse = JsonUtils.fromJson(text, DocumentChatResponse.class); if (DocumentChatResponse.Code.SUCCESS.getValue() != documentChatResponse.getCode()) { log.warn("调用星火模型文档对话发生错误,错误码为:{},请求的sid为:{}", documentChatResponse.getCode(), documentChatResponse.getSid()); webSocket.close(1000, "星火模型调用异常"); this.onChatError(documentChatResponse); return; } this.onChatOutput(documentChatResponse); if (DocumentChatResponse.Status.END.getValue() == documentChatResponse.getStatus()) { // 可以关闭连接,释放资源 webSocket.close(1000, "星火模型返回结束"); this.onChatEnd(); } } @Override public void onMessage(@NotNull WebSocket webSocket, @NotNull ByteString bytes) { super.onMessage(webSocket, bytes); } @Override public void onOpen(@NotNull WebSocket webSocket, @NotNull Response response) { super.onOpen(webSocket, response); webSocket.send(JsonUtils.toJson(documentChatRequest)); } } ================================================ FILE: ai-spark/src/main/java/com/ai/spark/achieve/defaults/listener/ImageUnderstandingListener.java ================================================ package com.ai.spark.achieve.defaults.listener; import com.ai.common.utils.JsonUtils; import com.ai.spark.endPoint.chat.ChatHeader; import com.ai.spark.endPoint.chat.Choice; import com.ai.spark.endPoint.chat.resp.DocumentChatResponse; import com.ai.spark.endPoint.images.ImageHeader; import com.ai.spark.endPoint.images.req.ImageUnderstandingRequest; import com.ai.spark.endPoint.images.resp.ImageUnderstandingResponse; import lombok.Data; import lombok.extern.slf4j.Slf4j; import okhttp3.Response; import okhttp3.WebSocket; import okio.ByteString; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import static com.ai.common.utils.ValidationUtils.ensureNotNull; /** * 图片理解对话监听器 */ @Slf4j @Data public abstract class ImageUnderstandingListener extends BaseListener { private ImageUnderstandingRequest imageUnderstandingRequest; /** * 构造方法,传入大模型参数 * * @param imageUnderstandingRequest 大模型参数 */ public ImageUnderstandingListener(ImageUnderstandingRequest imageUnderstandingRequest) { this.imageUnderstandingRequest = ensureNotNull(imageUnderstandingRequest, "documentChatRequest"); } /** * WebSocket服务发生异常的回调,可以覆盖重写。 * 默认抛出异常 * * @param t 异常 * @param response 返回值 */ public void onWebSocketError(Throwable t, Response response) { log.error("调用星火模型时,WebSocket发生异常:{}", response); t.printStackTrace(); } /** * 星火大模型发生异常 * * @param imageUnderstandingResponse 大模型返回值 */ public abstract void onChatError(ImageUnderstandingResponse imageUnderstandingResponse); /** * 星火大模型正常返回信息 * * @param imageUnderstandingResponse 大模型返回值 */ public abstract void onChatOutput(ImageUnderstandingResponse imageUnderstandingResponse); /** * 星火大模型返回信息结束回调 */ public abstract void onChatEnd(); @Override public void onClosed(@NotNull WebSocket webSocket, int code, @NotNull String reason) { super.onClosed(webSocket, code, reason); } @Override public void onClosing(@NotNull WebSocket webSocket, int code, @NotNull String reason) { super.onClosing(webSocket, code, reason); } @Override public void onFailure(@NotNull WebSocket webSocket, @NotNull Throwable t, @Nullable Response response) { webSocket.close(1000, ""); this.onWebSocketError(t, response); } @Override public void onMessage(@NotNull WebSocket webSocket, @NotNull String text) { ImageUnderstandingResponse imageUnderstandingResponse = JsonUtils.fromJson(text, ImageUnderstandingResponse.class); ImageHeader imageHeader = imageUnderstandingResponse.getImageHeader(); if (imageHeader.getCode() != ChatHeader.Code.SUCCESS.getValue()) { log.warn("调用星火模型文档对话发生错误,错误码为:{},请求的sid为:{}", imageHeader.getCode(), imageHeader.getSid()); webSocket.close(1000, "星火模型调用异常"); this.onChatError(imageUnderstandingResponse); return; } this.onChatOutput(imageUnderstandingResponse); if (DocumentChatResponse.Status.END.getValue() == Choice.Status.END.getValue()) { // 可以关闭连接,释放资源 webSocket.close(1000, "星火模型返回结束"); this.onChatEnd(); } } @Override public void onMessage(@NotNull WebSocket webSocket, @NotNull ByteString bytes) { super.onMessage(webSocket, bytes); } @Override public void onOpen(@NotNull WebSocket webSocket, @NotNull Response response) { super.onOpen(webSocket, response); webSocket.send(JsonUtils.toJson(imageUnderstandingRequest)); } } ================================================ FILE: ai-spark/src/main/java/com/ai/spark/achieve/defaults/session/DefaultAggregationSession.java ================================================ package com.ai.spark.achieve.defaults.session; import com.ai.spark.achieve.Configuration; import com.ai.spark.achieve.standard.session.*; import static com.ai.common.utils.ValidationUtils.ensureNotNull; /** * 聚合各个场景的session */ public class DefaultAggregationSession implements AggregationSession { private Configuration configuration; private volatile ChatSession chatSession; private volatile DocumentSession documentSession; private volatile EmbeddingSession embeddingSession; private volatile ImageSession imageSession; private volatile AudioSession audioSession; public DefaultAggregationSession(Configuration configuration) { this.configuration = ensureNotNull(configuration, "configuration"); } @Override public ChatSession getChatSession() { if (chatSession == null) { synchronized (this) { if (chatSession == null) { chatSession = new DefaultChatSession(configuration); } } } return chatSession; } @Override public DocumentSession getDocumentSession() { if (documentSession == null) { synchronized (this) { if (documentSession == null) { documentSession = new DefaultDocumentSession(configuration); } } } return documentSession; } @Override public EmbeddingSession getEmbeddingSession() { if (embeddingSession == null) { synchronized (this) { if (embeddingSession == null) { embeddingSession = new DefaultEmbeddingSession(configuration); } } } return embeddingSession; } @Override public ImageSession getImageSession() { if (imageSession == null) { synchronized (this) { if (imageSession == null) { imageSession = new DefaultImageSession(configuration); } } } return imageSession; } @Override public AudioSession getAudioSession() { if (audioSession == null) { synchronized (this) { if (audioSession == null) { audioSession = new DefaultAudioSession(configuration); } } } return audioSession; } } ================================================ FILE: ai-spark/src/main/java/com/ai/spark/achieve/defaults/session/DefaultAudioSession.java ================================================ package com.ai.spark.achieve.defaults.session; import com.ai.spark.achieve.Configuration; import com.ai.spark.achieve.standard.session.AudioSession; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.ToString; import static com.ai.common.utils.ValidationUtils.ensureNotNull; @Data @ToString(callSuper = true) @EqualsAndHashCode(callSuper = true) public class DefaultAudioSession extends Session implements AudioSession { public DefaultAudioSession(Configuration configuration) { this.setConfiguration(ensureNotNull(configuration, "configuration")); this.setSparkApiServer(ensureNotNull(configuration.getSparkApiServer(), "sparkApiServer")); } } ================================================ FILE: ai-spark/src/main/java/com/ai/spark/achieve/defaults/session/DefaultChatSession.java ================================================ package com.ai.spark.achieve.defaults.session; import cn.hutool.core.date.DateUtil; import com.ai.spark.achieve.ApiData; import com.ai.spark.achieve.Configuration; import com.ai.spark.achieve.defaults.listener.ChatListener; import com.ai.spark.achieve.defaults.listener.DocumentChatListener; import com.ai.spark.achieve.standard.session.ChatSession; import com.ai.spark.common.SparkApiUrl; import com.ai.spark.common.utils.AuthUtils; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.SneakyThrows; import lombok.ToString; import okhttp3.Request; import okhttp3.WebSocket; import static com.ai.common.utils.ValidationUtils.ensureNotNull; import static com.ai.spark.common.SparkApiUrl.DOCUMENT_CHAT; @Data @ToString(callSuper = true) @EqualsAndHashCode(callSuper = true) public class DefaultChatSession extends Session implements ChatSession { public DefaultChatSession(Configuration configuration) { this.setConfiguration(ensureNotNull(configuration, "configuration")); this.setSparkApiServer(ensureNotNull(configuration.getSparkApiServer(), "sparkApiServer")); } @Override @SneakyThrows public WebSocket chat(T chatListener) { // 默认情况下根据apiData获取策略得到创建时设置的参数 ApiData apiData = this.getConfiguration().getSystemApiData(); return this.chat(apiData.getApiKey(), apiData.getApiSecret(), chatListener); } @Override @SneakyThrows public WebSocket chat(String apiKey, String apiSecret, T chatListener) { // 获取到对应访问的domain,根据domain获取对应的请求地址 String domain = chatListener.getChatRequest().getChatParameter().getChat().getDomain(); // 生成请求的URL String url = AuthUtils.replaceAllHttp( AuthUtils.getAuthUrl(AuthUtils.RequestMethod.GET.getMethod(), SparkApiUrl.getUrl(domain), apiKey, apiSecret) ); // 发起请求返回结果 return this.getConfiguration().getOkHttpClient().newWebSocket(new Request.Builder().url(url).build(), chatListener); } @Override public WebSocket documentChat(T documentChatListener) { ApiData apiData = this.getConfiguration().getSystemApiData(); return documentChat(apiData.getAppId(), apiData.getApiSecret(), documentChatListener); } @Override public WebSocket documentChat(String appId, String apiSecret, T documentChatListener) { // 得当当前时间戳,按秒计算 long ts = DateUtil.currentSeconds(); // 进行签名设置 String url = SparkApiUrl.getUrl(DOCUMENT_CHAT) + "?" + "appId=" + appId + "×tamp=" + ts + "&signature=" + AuthUtils.getSignature(appId, apiSecret, ts); // 发起请求返回结果 return this.getConfiguration().getOkHttpClient().newWebSocket(new Request.Builder().url(url).build(), documentChatListener); } } ================================================ FILE: ai-spark/src/main/java/com/ai/spark/achieve/defaults/session/DefaultDocumentSession.java ================================================ package com.ai.spark.achieve.defaults.session; import cn.hutool.core.date.DateUtil; import cn.hutool.core.util.StrUtil; import com.ai.spark.achieve.ApiData; import com.ai.spark.achieve.Configuration; import com.ai.spark.achieve.standard.session.DocumentSession; import com.ai.spark.common.SparkApiUrl; import com.ai.spark.common.utils.AuthUtils; import com.ai.spark.endPoint.document.req.FileUploadRequest; import com.ai.spark.endPoint.document.resp.DocumentSummaryResponse; import com.ai.spark.endPoint.document.resp.FileUploadResponse; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.ToString; import okhttp3.MediaType; import okhttp3.MultipartBody; import okhttp3.RequestBody; import java.util.HashMap; import java.util.Map; import static com.ai.common.utils.ValidationUtils.ensureNotNull; @Data @ToString(callSuper = true) @EqualsAndHashCode(callSuper = true) public class DefaultDocumentSession extends Session implements DocumentSession { public DefaultDocumentSession(Configuration configuration) { this.setConfiguration(ensureNotNull(configuration, "configuration")); this.setSparkApiServer(ensureNotNull(configuration.getSparkApiServer(), "sparkApiServer")); } @Override public FileUploadResponse fileUpload(FileUploadRequest fileUploadRequest) { ApiData apiData = this.getConfiguration().getSystemApiData(); return this.fileUpload(apiData.getAppId(), apiData.getApiSecret(), fileUploadRequest); } @Override public FileUploadResponse fileUpload(String appId, String apiSecret, FileUploadRequest fileUploadRequest) { // 得到当前时间戳,按秒计算 long ts = DateUtil.currentSeconds(); // 设置文件 RequestBody fileBody = RequestBody.create(MediaType.parse("multipart/form-data"), fileUploadRequest.getFile()); MultipartBody.Part multipartBody = MultipartBody.Part.createFormData("file", fileUploadRequest.getFile().getName(), fileBody); // 设置其余参数 Map requestBodyMap = new HashMap<>(); if (StrUtil.isNotBlank(fileUploadRequest.getUrl())) { requestBodyMap.put(FileUploadRequest.Fields.url, RequestBody.create(MediaType.parse("multipart/form-data"), fileUploadRequest.getUrl())); } if (StrUtil.isNotBlank(fileUploadRequest.getFileName())) { requestBodyMap.put(FileUploadRequest.Fields.fileName, RequestBody.create(MediaType.parse("multipart/form-data"), fileUploadRequest.getFileName())); } if (StrUtil.isNotBlank(fileUploadRequest.getFileType())) { requestBodyMap.put(FileUploadRequest.Fields.fileType, RequestBody.create(MediaType.parse("multipart/form-data"), fileUploadRequest.getFileType())); } if (StrUtil.isNotBlank(fileUploadRequest.getCallbackUrl())) { requestBodyMap.put(FileUploadRequest.Fields.callbackUrl, RequestBody.create(MediaType.parse("multipart/form-data"), fileUploadRequest.getCallbackUrl())); } // 发起请求返回结果 return this.getSparkApiServer().fileUpload(appId, String.valueOf(ts), AuthUtils.getSignature(appId, apiSecret, ts), multipartBody, requestBodyMap).blockingGet(); } @Override public DocumentSummaryResponse documentSummaryStart(String fileId) { ApiData apiData = this.getConfiguration().getSystemApiData(); return this.documentSummaryStart(apiData.getAppId(), apiData.getApiSecret(), fileId); } @Override public DocumentSummaryResponse documentSummaryStart(String appId, String apiSecret, String fileId) { return this.documentSummary(SparkApiUrl.ApiUrl.documentSummaryStart.getUrl(), appId, apiSecret, fileId); } @Override public DocumentSummaryResponse documentSummaryQuery(String fileId) { ApiData apiData = this.getConfiguration().getSystemApiData(); return this.documentSummaryQuery(apiData.getAppId(), apiData.getApiSecret(), fileId); } @Override public DocumentSummaryResponse documentSummaryQuery(String appId, String apiSecret, String fileId) { return this.documentSummary(SparkApiUrl.ApiUrl.documentSummaryQuery.getUrl(), appId, apiSecret, fileId); } /** * 文档总结底层都依赖这个方法 * * @param url 请求的URL * @param appId 用户的AppId * @param apiSecret 用户的ApiSecret * @param fileId 文件ID * @return 请求结果 */ private DocumentSummaryResponse documentSummary(String url, String appId, String apiSecret, String fileId) { long ts = DateUtil.currentSeconds(); return this.getSparkApiServer().documentSummary(url, appId, String.valueOf(ts), AuthUtils.getSignature(appId, apiSecret, ts), RequestBody.create(MediaType.parse("multipart/form-data"), fileId)).blockingGet(); } } ================================================ FILE: ai-spark/src/main/java/com/ai/spark/achieve/defaults/session/DefaultEmbeddingSession.java ================================================ package com.ai.spark.achieve.defaults.session; import cn.hutool.http.ContentType; import com.ai.common.utils.JsonUtils; import com.ai.spark.achieve.ApiData; import com.ai.spark.achieve.Configuration; import com.ai.spark.achieve.standard.session.EmbeddingSession; import com.ai.spark.common.SparkApiUrl; import com.ai.spark.common.utils.AuthUtils; import com.ai.spark.endPoint.embedding.req.EmbeddingRequest; import com.ai.spark.endPoint.embedding.resp.EmbeddingResponse; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.SneakyThrows; import lombok.ToString; import okhttp3.MediaType; import okhttp3.Request; import okhttp3.RequestBody; import static com.ai.common.utils.ValidationUtils.ensureNotNull; @Data @ToString(callSuper = true) @EqualsAndHashCode(callSuper = true) public class DefaultEmbeddingSession extends Session implements EmbeddingSession { public DefaultEmbeddingSession(Configuration configuration) { this.setConfiguration(ensureNotNull(configuration, "configuration")); this.setSparkApiServer(ensureNotNull(configuration.getSparkApiServer(), "sparkApiServer")); } @Override public EmbeddingResponse embed(EmbeddingRequest embeddingRequest) { ApiData apiData = this.getConfiguration().getSystemApiData(); return this.embed(apiData.getApiKey(), apiData.getApiSecret(), embeddingRequest); } @Override @SneakyThrows public EmbeddingResponse embed(String apiKey, String apiSecret, EmbeddingRequest embeddingRequest) { // 鉴权,得到请求路径 String authUrl = AuthUtils.getAuthUrl(AuthUtils.RequestMethod.POST.getMethod(), SparkApiUrl.ApiUrl.embeddingq.getUrl(), apiKey, apiSecret); // 创建请求,设置请求URL和json数据 Request request = new Request.Builder().url(authUrl).post(RequestBody.create(MediaType.parse(ContentType.JSON.getValue()), JsonUtils.toJson(embeddingRequest))).build(); // 发起请求,获取返回的json字符串 String response = this.getConfiguration().getOkHttpClient().newCall(request).execute().body().string(); // 将json映射到对象上 return JsonUtils.fromJson(response, EmbeddingResponse.class); } } ================================================ FILE: ai-spark/src/main/java/com/ai/spark/achieve/defaults/session/DefaultImageSession.java ================================================ package com.ai.spark.achieve.defaults.session; import cn.hutool.http.ContentType; import com.ai.common.utils.JsonUtils; import com.ai.spark.achieve.ApiData; import com.ai.spark.achieve.Configuration; import com.ai.spark.achieve.defaults.listener.ImageUnderstandingListener; import com.ai.spark.achieve.standard.session.ImageSession; import com.ai.spark.common.SparkApiUrl; import com.ai.spark.common.utils.AuthUtils; import com.ai.spark.endPoint.images.req.ImageCreateRequest; import com.ai.spark.endPoint.images.req.ImageUnderstandingRequest; import com.ai.spark.endPoint.images.resp.ImageCreateResponse; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.SneakyThrows; import lombok.ToString; import okhttp3.MediaType; import okhttp3.Request; import okhttp3.RequestBody; import okhttp3.WebSocket; import static com.ai.common.utils.ValidationUtils.ensureNotNull; @Data @ToString(callSuper = true) @EqualsAndHashCode(callSuper = true) public class DefaultImageSession extends Session implements ImageSession { public DefaultImageSession(Configuration configuration) { this.setConfiguration(ensureNotNull(configuration, "configuration")); this.setSparkApiServer(ensureNotNull(configuration.getSparkApiServer(), "sparkApiServer")); } @Override @SneakyThrows public ImageCreateResponse imageCreate(ImageCreateRequest imageCreateRequest) { ApiData apiData = this.getConfiguration().getSystemApiData(); return this.imageCreate(apiData.getApiKey(), apiData.getApiSecret(), imageCreateRequest); } @Override @SneakyThrows public ImageCreateResponse imageCreate(String apiKey, String apiSecret, ImageCreateRequest imageCreateRequest) { // 鉴权,得到请求路径 String authUrl = AuthUtils.getAuthUrl(AuthUtils.RequestMethod.POST.getMethod(), SparkApiUrl.ApiUrl.imageCreate.getUrl(), apiKey, apiSecret); // 创建请求,设置请求URL和json数据 Request request = new Request.Builder().url(authUrl).post(RequestBody.create(MediaType.parse(ContentType.JSON.getValue()), JsonUtils.toJson(imageCreateRequest))).build(); // 发起请求,获取返回的json字符串 String response = this.getConfiguration().getOkHttpClient().newCall(request).execute().body().string(); // 将json映射到对象上 return JsonUtils.fromJson(response, ImageCreateResponse.class); } @Override public WebSocket imageUnderstanding(ImageUnderstandingRequest imageUnderstandingRequest, ImageUnderstandingListener imageUnderstandingListener) { ApiData apiData = this.getConfiguration().getSystemApiData(); return imageUnderstanding(apiData.getApiKey(), apiData.getApiSecret(), imageUnderstandingRequest, imageUnderstandingListener); } @Override @SneakyThrows public WebSocket imageUnderstanding(String apiKey, String apiSecret, ImageUnderstandingRequest imageUnderstandingRequest, ImageUnderstandingListener imageUnderstandingListener) { // 生成请求的URL String url = AuthUtils.replaceAllHttp( AuthUtils.getAuthUrl(AuthUtils.RequestMethod.GET.getMethod(), SparkApiUrl.ApiUrl.imageUnderstanding.getUrl(), apiKey, apiSecret) ); // 发起请求返回结果 return this.getConfiguration().getOkHttpClient().newWebSocket(new Request.Builder().url(url).build(), imageUnderstandingListener); } } ================================================ FILE: ai-spark/src/main/java/com/ai/spark/achieve/defaults/session/Session.java ================================================ package com.ai.spark.achieve.defaults.session; import com.ai.spark.achieve.Configuration; import com.ai.spark.achieve.standard.api.SparkApiServer; import lombok.Data; @Data public class Session { private Configuration configuration; private SparkApiServer sparkApiServer; } ================================================ FILE: ai-spark/src/main/java/com/ai/spark/achieve/standard/api/SparkApiServer.java ================================================ package com.ai.spark.achieve.standard.api; import com.ai.spark.endPoint.document.resp.DocumentSummaryResponse; import com.ai.spark.endPoint.document.resp.FileUploadResponse; import io.reactivex.Single; import okhttp3.MultipartBody; import okhttp3.RequestBody; import retrofit2.http.*; import java.util.Map; import static com.ai.spark.common.Constants.*; import static com.ai.spark.common.SparkApiUrl.FILE_UPLOAD_API_URL; /** * @Description: 讯飞星火 API接口 */ public interface SparkApiServer { /** * 文件上传接口 * * @param appId 用户appId * @param timestamp 当前时间戳(秒) * @param signature 生成的签名 * @param file 需要上传的文件 * @param requestBodyMap 其他字段 * @return 文件上传返回参数 */ @Multipart @POST(FILE_UPLOAD_API_URL) Single fileUpload(@Header(APP_ID) String appId, @Header(TIMESTAMP) String timestamp, @Header(SIGNATURE) String signature, @Part MultipartBody.Part file, @PartMap Map requestBodyMap); /** * 文档总结,文档总结结果查询两个接口二合一,参数都一样,请求路径不同 * * @param url 请求地址 * @param appId 用户appId * @param timestamp 当前时间戳(秒) * @param signature 生成的签名 * @param fileId 文件ID * @return 请求结果信息 */ @Multipart @POST Single documentSummary(@Url String url, @Header(APP_ID) String appId, @Header(TIMESTAMP) String timestamp, @Header(SIGNATURE) String signature, @Part("fileId") RequestBody fileId); } ================================================ FILE: ai-spark/src/main/java/com/ai/spark/achieve/standard/session/AggregationSession.java ================================================ package com.ai.spark.achieve.standard.session; public interface AggregationSession { ChatSession getChatSession(); DocumentSession getDocumentSession(); EmbeddingSession getEmbeddingSession(); ImageSession getImageSession(); AudioSession getAudioSession(); } ================================================ FILE: ai-spark/src/main/java/com/ai/spark/achieve/standard/session/AudioSession.java ================================================ package com.ai.spark.achieve.standard.session; public interface AudioSession { } ================================================ FILE: ai-spark/src/main/java/com/ai/spark/achieve/standard/session/ChatSession.java ================================================ package com.ai.spark.achieve.standard.session; import com.ai.spark.achieve.defaults.listener.ChatListener; import com.ai.spark.achieve.defaults.listener.DocumentChatListener; import okhttp3.WebSocket; /** * 对话场景下的接口 */ public interface ChatSession { /** * 聊天接口 * * @param chatListener 对话监听器 * @return 返回信息 */ WebSocket chat(T chatListener); /** * 聊天接口,自定义所使用的到的ApiKey和ApiSecret * * @param apiKey 用户的ApiKey * @param apiSecret 用户的ApiSecret * @param chatListener 对话监听器 * @return 返回信息 */ WebSocket chat(String apiKey, String apiSecret, T chatListener); /** * 文档聊天接口 * * @param documentChatListener 对话监听器 * @return 返回信息 */ WebSocket documentChat(T documentChatListener); /** * 聊天接口,自定义所使用的到的AppId和ApiSecret * * @param appId 用户的AppId * @param apiSecret 用户的ApiSecret * @param documentChatListener 对话监听器 * @return 返回信息 */ WebSocket documentChat(String appId, String apiSecret, T documentChatListener); } ================================================ FILE: ai-spark/src/main/java/com/ai/spark/achieve/standard/session/DocumentSession.java ================================================ package com.ai.spark.achieve.standard.session; import com.ai.spark.endPoint.document.req.FileUploadRequest; import com.ai.spark.endPoint.document.resp.DocumentSummaryResponse; import com.ai.spark.endPoint.document.resp.FileUploadResponse; /** * 文档场景下的接口 */ public interface DocumentSession { /** * 文件上传 * * @param fileUploadRequest 上传的信息 * @return 返回信息 */ FileUploadResponse fileUpload(FileUploadRequest fileUploadRequest); /** * 文件上传 * * @param appId 用户的AppId * @param apiSecret 用户的ApiSecret * @param fileUploadRequest 上传的信息 * @return 返回信息 */ FileUploadResponse fileUpload(String appId, String apiSecret, FileUploadRequest fileUploadRequest); /** * 发起文档总结接口 * * @param fileId 文件ID * @return 返回信息 */ DocumentSummaryResponse documentSummaryStart(String fileId); /** * 发起文档总结接口 * * @param appId 用户的AppId * @param apiSecret 用户的ApiSecret * @param fileId 文件ID * @return 返回信息 */ DocumentSummaryResponse documentSummaryStart(String appId, String apiSecret, String fileId); /** * 查询文档总结结果 * * @param fileId 文件ID * @return 返回信息 */ DocumentSummaryResponse documentSummaryQuery(String fileId); /** * 查询文档总结结果 * * @param appId 用户的AppId * @param apiSecret 用户的ApiSecret * @param fileId 文件ID * @return 返回信息 */ DocumentSummaryResponse documentSummaryQuery(String appId, String apiSecret, String fileId); } ================================================ FILE: ai-spark/src/main/java/com/ai/spark/achieve/standard/session/EmbeddingSession.java ================================================ package com.ai.spark.achieve.standard.session; import com.ai.spark.endPoint.embedding.req.EmbeddingRequest; import com.ai.spark.endPoint.embedding.resp.EmbeddingResponse; /** * 文本嵌入场景下的接口 */ public interface EmbeddingSession { /** * 文本嵌入 * * @param embeddingRequest 请求参数 * @return 请求结果 */ EmbeddingResponse embed(EmbeddingRequest embeddingRequest); /** * 文本嵌入 * * @param apiKey 用户的ApiKey * @param apiSecret 用户的ApiSecret * @param embeddingRequest 请求参数 * @return 请求结果 */ EmbeddingResponse embed(String apiKey, String apiSecret, EmbeddingRequest embeddingRequest); } ================================================ FILE: ai-spark/src/main/java/com/ai/spark/achieve/standard/session/ImageSession.java ================================================ package com.ai.spark.achieve.standard.session; import com.ai.spark.achieve.defaults.listener.ImageUnderstandingListener; import com.ai.spark.endPoint.images.req.ImageCreateRequest; import com.ai.spark.endPoint.images.req.ImageUnderstandingRequest; import com.ai.spark.endPoint.images.resp.ImageCreateResponse; import okhttp3.WebSocket; /** * 图片生成场景下的接口 */ public interface ImageSession { /** * 图片创作接口,使用系统默认的ApiData * * @param imageCreateRequest 请求参数 * @return 请求结果 */ ImageCreateResponse imageCreate(ImageCreateRequest imageCreateRequest); /** * 图片创作接口,使用自定义的ApiData * * @param apiKey 用户的ApiKey * @param apiSecret 用户的ApiSecret * @param imageCreateRequest 请求参数 * @return 请求结果 */ ImageCreateResponse imageCreate(String apiKey, String apiSecret, ImageCreateRequest imageCreateRequest); /** * 图片理解 * * @param imageUnderstandingRequest 请求参数 * @return 请求结果 */ public WebSocket imageUnderstanding(ImageUnderstandingRequest imageUnderstandingRequest, ImageUnderstandingListener imageUnderstandingListener); /** * 图片理解 * * @param apiKey 用户的ApiKey * @param apiSecret 用户的ApiSecret * @param imageUnderstandingRequest 请求参数 * @return 请求结果 */ public WebSocket imageUnderstanding(String apiKey, String apiSecret, ImageUnderstandingRequest imageUnderstandingRequest, ImageUnderstandingListener imageUnderstandingListener); } ================================================ FILE: ai-spark/src/main/java/com/ai/spark/common/Constants.java ================================================ package com.ai.spark.common; public class Constants { public static final String APP_ID = "appId"; public static final String TIMESTAMP = "timestamp"; public static final String SIGNATURE = "signature"; } ================================================ FILE: ai-spark/src/main/java/com/ai/spark/common/SparkApiUrl.java ================================================ package com.ai.spark.common; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.extern.slf4j.Slf4j; import java.util.HashMap; import java.util.Map; /** * 记录各个API的请求URL */ @Slf4j public class SparkApiUrl { // 星火模型对话链接 public final static String GENERAL_V1 = "general"; public final static String GENERAL_V2 = "generalv2"; public final static String GENERAL_V3 = "generalv3"; public final static String SPARK_API_HOST_WS_V1_1_URL = "http://spark-api.xf-yun.com/v1.1/chat"; public final static String SPARK_API_HOST_WSS_V1_1_URL = "https://spark-api.xf-yun.com/v1.1/chat"; public final static String SPARK_API_HOST_WS_V2_1_URL = "http://spark-api.xf-yun.com/v2.1/chat"; public final static String SPARK_API_HOST_WSS_V2_1_URL = "https://spark-api.xf-yun.com/v2.1/chat"; public final static String SPARK_API_HOST_WS_V3_1_URL = "http://spark-api.xf-yun.com/v3.1/chat"; public final static String SPARK_API_HOST_WSS_V3_1_URL = "https://spark-api.xf-yun.com/v3.1/chat"; // 文档对话文件上传链接 public final static String FILE_UPLOAD = "fileUpload"; public final static String FILE_UPLOAD_API_URL = "https://chatdoc.xfyun.cn/openapi/fileUpload"; // 文档对话链接 public final static String DOCUMENT_CHAT = "documentChat"; public final static String DOCUMENT_CHAT_API_URL = "wss://chatdoc.xfyun.cn/openapi/chat"; // 文档总结链接 public final static String DOCUMENT_SUMMARY_START = "documentSummaryStart"; public final static String DOCUMENT_SUMMARY_START_API_URL = "https://chatdoc.xfyun.cn/openapi/startSummary"; // 查询文档总结结果链接 public final static String DOCUMENT_SUMMARY_QUERY = "documentSummaryStart"; public final static String DOCUMENT_SUMMARY_QUERY_API_URL = "https://chatdoc.xfyun.cn/openapi/fileSummary"; // 文本嵌入接口 public final static String EMBEDDING_P = "Embeddingp"; public final static String EMBEDDING_P_API_URL = "https://cn-huabei-1.xf-yun.com/v1/private/sa8a05c27"; public final static String EMBEDDING_Q = "Embeddingq"; public final static String EMBEDDING_Q_API_URL = "https://cn-huabei-1.xf-yun.com/v1/private/s50d55a16"; // 图片生成接口 public final static String IMAGE_CREATE = "imageCreate"; public final static String IMAGE_CREATE_API_URL = "https://spark-api.cn-huabei-1.xf-yun.com/v2.1/tti"; // 图片理解接口 public final static String IMAGE_UNDERSANDING = "imageUnderstanding"; public final static String IMAGE_UNDERSANDING_API_URL = "https://spark-api.cn-huabei-1.xf-yun.com/v2.1/image"; // 超拟人合成协议接口 public final static String HYPERMIMETIC_SYNTHESIS = "hypermimeticSynthesis"; public final static String HYPERMIMETIC_SYNTHESIS_API_URL = "wss://cbm01.cn-huabei-1.xf-yun.com/v1/private/medd90fec"; public final static Map urlMap = new HashMap<>(); static { urlMap.put(GENERAL_V1, SPARK_API_HOST_WSS_V1_1_URL); urlMap.put(GENERAL_V2, SPARK_API_HOST_WSS_V2_1_URL); urlMap.put(GENERAL_V3, SPARK_API_HOST_WSS_V3_1_URL); urlMap.put(FILE_UPLOAD, FILE_UPLOAD_API_URL); urlMap.put(DOCUMENT_CHAT, DOCUMENT_CHAT_API_URL); urlMap.put(DOCUMENT_SUMMARY_START, DOCUMENT_SUMMARY_START_API_URL); urlMap.put(DOCUMENT_SUMMARY_QUERY, DOCUMENT_SUMMARY_QUERY_API_URL); urlMap.put(EMBEDDING_P, EMBEDDING_P_API_URL); urlMap.put(EMBEDDING_Q, EMBEDDING_Q_API_URL); urlMap.put(IMAGE_CREATE, IMAGE_CREATE_API_URL); urlMap.put(IMAGE_UNDERSANDING, IMAGE_UNDERSANDING_API_URL); urlMap.put(HYPERMIMETIC_SYNTHESIS, HYPERMIMETIC_SYNTHESIS_API_URL); } public static String getUrl(String key) { if (!urlMap.containsKey(key)) { log.error("No corresponding URL path found for {}", key); return null; } return urlMap.get(key); } @Getter @AllArgsConstructor public enum ApiUrl { general(SPARK_API_HOST_WSS_V1_1_URL), generalV2(SPARK_API_HOST_WSS_V2_1_URL), generalV3(SPARK_API_HOST_WSS_V3_1_URL), fileUpload(FILE_UPLOAD_API_URL), documentChat(DOCUMENT_CHAT_API_URL), documentSummaryStart(DOCUMENT_SUMMARY_START_API_URL), documentSummaryQuery(DOCUMENT_SUMMARY_QUERY_API_URL), embeddingp(EMBEDDING_P_API_URL), embeddingq(EMBEDDING_Q_API_URL), imageCreate(IMAGE_CREATE_API_URL), imageUnderstanding(IMAGE_UNDERSANDING_API_URL), hypermimeticSynthesis(HYPERMIMETIC_SYNTHESIS_API_URL); private String url; } } ================================================ FILE: ai-spark/src/main/java/com/ai/spark/common/Usage.java ================================================ package com.ai.spark.common; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @Data @NoArgsConstructor @AllArgsConstructor @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public class Usage { @JsonProperty("text") private UsageText usageText; } ================================================ FILE: ai-spark/src/main/java/com/ai/spark/common/UsageText.java ================================================ package com.ai.spark.common; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @Data @NoArgsConstructor @AllArgsConstructor @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public class UsageText { /** * 保留字段,可忽略 */ @JsonProperty("question_tokens") private Integer questionTokens; /** * 包含历史问题的总tokens大小 */ @JsonProperty("prompt_tokens") private Integer promptTokens; /** * 回答的tokens大小 */ @JsonProperty("completion_tokens") private Integer completionTokens; /** * prompt_tokens和completion_tokens的和 */ @JsonProperty("total_tokens") private Integer totalTokens; } ================================================ FILE: ai-spark/src/main/java/com/ai/spark/common/utils/AuthUtils.java ================================================ package com.ai.spark.common.utils; import lombok.AllArgsConstructor; import lombok.Getter; import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; import java.io.UnsupportedEncodingException; import java.net.URI; import java.net.URISyntaxException; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; import java.security.InvalidKeyException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.security.SignatureException; import java.time.ZoneId; import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; import java.util.Base64; import java.util.Locale; /** * 鉴权工具类 */ public class AuthUtils { /** * 日期格式化 */ public final static DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("EEE, dd MMM yyyy HH:mm:ss z", Locale.US); public final static String preStr = "host: %s\n" + "date: %s\n" + "%s %s HTTP/1.1"; private static final char[] MD5_TABLE = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; public static String replaceAllHttp(String authUrl) { return authUrl.replaceAll("http://", "ws://").replaceAll("https://", "wss://"); } /** * 鉴权方法,适用于对话接口 * * @param requestMethod 请求方式 * @param hostUrl 地址 * @param apiKey apikey * @param apiSecret apiSecret * @return 鉴权信息 */ public static String getAuthUrl(String requestMethod, String hostUrl, String apiKey, String apiSecret) throws InvalidKeyException, NoSuchAlgorithmException, URISyntaxException, UnsupportedEncodingException { URI uri = new URI(hostUrl); String date = ZonedDateTime.now(ZoneId.of("GMT")).format(dateTimeFormatter); // SHA256加密 Mac mac = Mac.getInstance("hmacsha256"); mac.init(new SecretKeySpec(apiSecret.getBytes(StandardCharsets.UTF_8), "hmacsha256")); byte[] hexDigits = mac.doFinal(String.format(preStr, uri.getHost(), date, requestMethod, uri.getPath()).getBytes(StandardCharsets.UTF_8)); String authorization = String.format("api_key=\"%s\", algorithm=\"%s\", headers=\"%s\", signature=\"%s\"", apiKey, "hmac-sha256", "host date request-line", Base64.getEncoder().encodeToString(hexDigits)); // 拼接地址 return new StringBuilder(hostUrl) .append("?authorization=").append(Base64.getEncoder().encodeToString(authorization.getBytes(StandardCharsets.UTF_8))) .append("&date=").append(URLEncoder.encode(date, StandardCharsets.UTF_8.name())) .append("&host=").append(uri.getHost()) .toString(); } /** * 获取签名,适用于文档问答 * * @param appId 签名的key * @param secret 签名秘钥 * @return 返回签名 */ public static String getSignature(String appId, String secret, long ts) { try { String auth = md5(appId + ts); return hmacSHA1Encrypt(auth, secret); } catch (SignatureException e) { return null; } } /** * sha1加密 * * @param encryptText 加密文本 * @param encryptKey 加密键 * @return 加密 */ private static String hmacSHA1Encrypt(String encryptText, String encryptKey) throws SignatureException { byte[] rawHmac; try { byte[] data = encryptKey.getBytes(StandardCharsets.UTF_8); SecretKeySpec secretKey = new SecretKeySpec(data, "HmacSHA1"); Mac mac = Mac.getInstance("HmacSHA1"); mac.init(secretKey); byte[] text = encryptText.getBytes(StandardCharsets.UTF_8); rawHmac = mac.doFinal(text); } catch (InvalidKeyException e) { throw new SignatureException("InvalidKeyException:" + e.getMessage()); } catch (NoSuchAlgorithmException e) { throw new SignatureException( "NoSuchAlgorithmException:" + e.getMessage() ); } return Base64.getEncoder().encodeToString(rawHmac); } private static String md5(String cipherText) { try { byte[] data = cipherText.getBytes(); // 信息摘要是安全的单向哈希函数,它接收任意大小的数据,并输出固定长度的哈希值。 MessageDigest mdInst = MessageDigest.getInstance("MD5"); // MessageDigest对象通过使用 update方法处理数据, 使用指定的byte数组更新摘要 mdInst.update(data); // 摘要更新之后,通过调用digest()执行哈希计算,获得密文 byte[] md = mdInst.digest(); // 把密文转换成十六进制的字符串形式 int j = md.length; char[] str = new char[j * 2]; int k = 0; for (byte byte0 : md) { // i = 0 str[k++] = MD5_TABLE[byte0 >>> 4 & 0xf]; // 5 str[k++] = MD5_TABLE[byte0 & 0xf]; // F } // 返回经过加密后的字符串 return new String(str); } catch (Exception e) { return null; } } @Getter @AllArgsConstructor public enum RequestMethod { GET("GET"), POST("POST"); private String method; } } ================================================ FILE: ai-spark/src/main/java/com/ai/spark/endPoint/audio/Audio.java ================================================ package com.ai.spark.endPoint.audio; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; @Data @Builder @NoArgsConstructor @AllArgsConstructor @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public class Audio { /** * ⾳频编码 */ private String encoding; /** * ⾳频编码 */ @JsonProperty("sample_rate") private Integer sampleRate; /** * 声道数 */ private Integer channels; /** * 位深 */ @JsonProperty("bit_depth") private Integer bitDepth; /** * 帧⼤⼩ */ @JsonProperty("frame_size") private Integer frameSize; /** * 数据状态 * 0:开始, 1:开始, 2:结束 */ private Integer status; /** * 数据序号 * 最⼩值:0, 最⼤值:9999999 */ private Integer seq; /** * ⾳频数据 * 最⼩尺⼨:0B, 最⼤尺⼨:10485760B */ private String audio; } ================================================ FILE: ai-spark/src/main/java/com/ai/spark/endPoint/audio/AudioHeader.java ================================================ package com.ai.spark.endPoint.audio; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; @Data @Builder @NoArgsConstructor @AllArgsConstructor @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public class AudioHeader { /** * 在平台申请的appid信息,必传 */ @JsonProperty("app_id") private String appId; /** * 请求⽤户服务返回的uid,⽤户及设备级别个性化功能依赖此参数 */ private String uid; /** * 请求⽅确保唯⼀的设备标志,设备级别个性化功能依赖此参数 */ private String did; /** * 设备imei信息 */ private String imei; /** * 设备imsi信息 */ private String imsi; /** * 设备mac信息 */ private String mac; /** * ⽹络类型,可选值为wifi、2G、3G、4G、5G */ @JsonProperty("net_type") private String netType; /** * 运营商信息,可选值为CMCC、CUCC、CTCC、other */ @JsonProperty("net_isp") private String netIsp; /** * 客户端请求的会话唯⼀标识 */ @JsonProperty("request_id") private String requestId; /** * 个性化资源ID */ @JsonProperty("res_id") private String resId; /** * 请求状态,可选值为:0-开始、1-继续、2-结束 */ private Integer status; // 以下是请求返回时所需参数 /** * 错误码,0表示正常,非0表示出错; */ private Integer code; /** * 会话是否成功的描述信息 */ private String message; /** * 会话的唯一id,用于讯飞技术人员查询服务端会话日志使用,出现调用错误时建议留存该字段 */ private String sid; } ================================================ FILE: ai-spark/src/main/java/com/ai/spark/endPoint/audio/AudioParameter.java ================================================ package com.ai.spark.endPoint.audio; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; @Data @Builder @NoArgsConstructor @AllArgsConstructor @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public class AudioParameter { private Oral oral; private Tts tts; } ================================================ FILE: ai-spark/src/main/java/com/ai/spark/endPoint/audio/AudioPayload.java ================================================ package com.ai.spark.endPoint.audio; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; @Data @Builder @NoArgsConstructor @AllArgsConstructor @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public class AudioPayload { /** * 待合成⽂本 */ private AudioText text; /** * ⽤户原始输⼊,场景化合成开启时必传,不开启为⾮必传 */ @JsonProperty("user_text") private AudioText userText; /** * 响应数据块 */ private Audio audio; /** * 响应数据块 */ private Pybuf pybuf; } ================================================ FILE: ai-spark/src/main/java/com/ai/spark/endPoint/audio/AudioText.java ================================================ package com.ai.spark.endPoint.audio; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; @Data @Builder @NoArgsConstructor @AllArgsConstructor @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public class AudioText { /** * ⽂本编码 */ private String encoding; /** * ⽂本压缩格式 */ private String compress; /** * ⽂本格式 */ private String format; /** * 数据状态 */ private Integer status; /** * 数据序号 */ private Integer seq; /** * ⽂本数据 */ private String text; } ================================================ FILE: ai-spark/src/main/java/com/ai/spark/endPoint/audio/Oral.java ================================================ package com.ai.spark.endPoint.audio; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; @Data @Builder @NoArgsConstructor @AllArgsConstructor @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public class Oral { @JsonProperty("spark_assist") private Integer sparkAssist; @JsonProperty("oral_level") private String oralLevel; } ================================================ FILE: ai-spark/src/main/java/com/ai/spark/endPoint/audio/Pybuf.java ================================================ package com.ai.spark.endPoint.audio; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; @Data @Builder @NoArgsConstructor @AllArgsConstructor @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public class Pybuf { /** * ⽂本编码 */ private String encoding; /** * ⽂本压缩格式 */ private String compress; /** * ⽂本格式 */ private String format; /** * 数据状态 * 0:开始, 1:开始, 2:结束 */ private Integer status; /** * 数据序号 * 最⼩值:0, 最⼤值:9999999 */ private Integer seq; /** * ⽂本数据 * 最⼩尺⼨:0B, 最⼤尺⼨:1048576B */ private String text; } ================================================ FILE: ai-spark/src/main/java/com/ai/spark/endPoint/audio/Tts.java ================================================ package com.ai.spark.endPoint.audio; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import lombok.*; @Data @Builder @NoArgsConstructor @AllArgsConstructor @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public class Tts { /** * 发⾳⼈,必传 */ private String vcn; /** * 语速:0对应默认语速的1/2,100 对应默认语速的2倍 * 最⼩值:0, 最⼤值:100 */ private Integer speed; /** * ⾳量:0是 静⾳,1对 应默认⾳量 1/2,100对应默认⾳量的2倍 * 最⼩值:0, 最⼤值:100 */ private Integer volume; /** * 语调:0对应默认语速的1/2,100对应默认语速的2倍 * 最⼩值:0, 最⼤值:100 */ private Integer pitch; /** * 背景⾳ * 0:⽆背景⾳, 1:内置背景⾳1, 2:内置背景⾳2 */ private Integer bgs; /** * 英⽂发⾳⽅式 * 0:⾃动判断处理,如果不确定将按照英⽂词语拼写处理(缺省), * 1:所有英⽂按字⺟发⾳, * 2:⾃动判断处理,如果不确定将按照字⺟朗读 */ private Integer reg; /** * 合成⾳频数字发⾳⽅式 * 0:⾃动判断, 1:完全数值, 2:完全字符串, 3:字符串优先 */ private Integer rdn; /** * 是否返回拼⾳标注 * 0:不返回拼⾳, 1:返回拼⾳(纯⽂本格式,utf8编码) */ private Integer rhy; /** * 场景 * 0:⽆, 1:散⽂阅读, 2:⼩说阅读, 3:新闻, 4:⼴告, 5:交互 */ private Integer scn; /** * 引擎初始化,是否返回版本信息+时间戳信息 * 0:不返回, 1:返回版本信息+时间戳信息。如XXX.18928127 XXX表示版本号,后接秒为单位的时间戳 */ private Integer version; /** * 控制L5静⾳时⻓,取值范围为 0~10000ms * 最⼩值:0, 最⼤值:10000 */ private Integer L5SilLen; /** * 段落静⾳时⻓,取值范围为0~10000ms * 最⼩值:0, 最⼤值:10000 */ private Integer ParagraphSilLen; private Audio audio; private Pybuf pybuf; @Getter @AllArgsConstructor public enum Vcn { lxx("x4_lingxiaoxuan_oral"), lfz("x4_lingfeizhe_oral"), lyz("x4_lingyuzhao_oral"); private String name; } } ================================================ FILE: ai-spark/src/main/java/com/ai/spark/endPoint/audio/req/AudioRequest.java ================================================ package com.ai.spark.endPoint.audio.req; import com.ai.spark.endPoint.audio.AudioHeader; import com.ai.spark.endPoint.audio.AudioParameter; import com.ai.spark.endPoint.audio.AudioPayload; import com.ai.spark.endPoint.audio.Tts; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; @Data @Builder @NoArgsConstructor @AllArgsConstructor @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public class AudioRequest { /** * 协议头部,⽤于描述平台特性的参数 */ private AudioHeader header; /** * AI 能⼒功能参数,⽤于控制 AI 引擎特性的开关。 */ private AudioParameter parameter; private AudioPayload payload; public static AudioRequest baseBuild(Tts.Vcn vcn, String appId) { AudioRequest request = AudioRequest.builder() .header(AudioHeader.builder().appId(appId).status(0).build()) .parameter(AudioParameter.builder().tts(Tts.builder().vcn(vcn.getName()).build()).build()) .build(); return request; } } ================================================ FILE: ai-spark/src/main/java/com/ai/spark/endPoint/audio/resp/AudioResponse.java ================================================ package com.ai.spark.endPoint.audio.resp; import com.ai.spark.endPoint.audio.AudioHeader; import com.ai.spark.endPoint.audio.AudioPayload; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; @Data @Builder @NoArgsConstructor @AllArgsConstructor @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public class AudioResponse { private AudioHeader header; private AudioPayload payload; } ================================================ FILE: ai-spark/src/main/java/com/ai/spark/endPoint/chat/Chat.java ================================================ package com.ai.spark.endPoint.chat; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.*; @Data @Builder @NoArgsConstructor @AllArgsConstructor @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public class Chat { /** * 必传 * 指定访问的领域,general指向V1.5版本,generalv2指向V2版本,generalv3指向V3版本 。注意:不同的取值对应的url也不一样! * 取值为[general,generalv2,generalv3] */ private String domain; /** * 非必传 * 核采样阈值。用于决定结果随机性,取值越高随机性越强即相同的问题得到的不同答案的可能性越高 * 取值范围 (0,1] ,默认值0.5 */ private Double temperature; /** * 非必传 * 模型回答的tokens的最大长度 * V1.5取值为[1,4096] * V2.0取值为[1,8192],默认为2048。 * V3.0取值为[1,8192],默认为2048。 */ @JsonProperty("max_tokens") private Integer maxTokens; /** * 非必传 * 从k个候选中随机选择⼀个(⾮等概率) * 取值为[1,6],默认为4 */ @JsonProperty("top_k") private Integer topK; /** * 非必传 * 用于关联用户会话,需要保障用户下的唯一性 */ @JsonProperty("chat_id") private String chatId; @Getter @AllArgsConstructor public enum General { general("general"), generalV2("generalv2"), generalV3("generalv3"); private String msg; } } ================================================ FILE: ai-spark/src/main/java/com/ai/spark/endPoint/chat/ChatHeader.java ================================================ package com.ai.spark.endPoint.chat; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.*; @Data @Builder @NoArgsConstructor @AllArgsConstructor @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public class ChatHeader { /** * 必传 * 应用appid,从开放平台控制台创建的应用中获取 */ @JsonProperty("app_id") private String appId; /** * 非必传 * 每个用户的id,用于区分不同用户 */ private String uid; // 以下是请求返回时所需参数 /** * 错误码,0表示正常,非0表示出错; */ private Integer code; /** * 会话是否成功的描述信息 */ private String message; /** * 会话的唯一id,用于讯飞技术人员查询服务端会话日志使用,出现调用错误时建议留存该字段 */ private String sid; /** * 会话状态,取值为[0,1,2];0代表首次结果;1代表中间结果;2代表最后一个结果 */ private Integer status; @Getter @AllArgsConstructor public enum Code { SUCCESS(0), ; private final int value; } } ================================================ FILE: ai-spark/src/main/java/com/ai/spark/endPoint/chat/ChatParameter.java ================================================ package com.ai.spark.endPoint.chat; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; @Data @Builder @NoArgsConstructor @AllArgsConstructor @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public class ChatParameter { private Chat chat; } ================================================ FILE: ai-spark/src/main/java/com/ai/spark/endPoint/chat/ChatPayload.java ================================================ package com.ai.spark.endPoint.chat; import com.ai.spark.common.Usage; import com.ai.spark.endPoint.chat.function.Function; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; @Data @Builder @NoArgsConstructor @AllArgsConstructor @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public class ChatPayload { private Message message; @JsonProperty("functions") private Function function; // 以下是请求返回时所需参数 @JsonProperty("choices") private Choice choice; private Usage usage; } ================================================ FILE: ai-spark/src/main/java/com/ai/spark/endPoint/chat/ChatText.java ================================================ package com.ai.spark.endPoint.chat; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.*; @Data @Builder @NoArgsConstructor @AllArgsConstructor @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public class ChatText { /** * user表示是用户的问题,assistant表示AI的回复 * 取值为[user,assistant] */ private String role; /** * 用户和AI的对话内容 * 所有content的累计tokens需控制8192以内 */ private String content; /** * 结果序号,取值为[0,10]; */ private Integer index; /** * 数据的类型 */ @JsonProperty("content_type") private String contentType; public static ChatText baseBuild(Role role, String content) { return ChatText.builder().role(role.getRoleName()).content(content).build(); } @Getter @AllArgsConstructor public enum Role { USER("user"), ASSISTANT("assistant"), ; private String RoleName; } @Getter @AllArgsConstructor public enum ContentType { TEXT("text"), IMAGE("image"), ; private String type; } } ================================================ FILE: ai-spark/src/main/java/com/ai/spark/endPoint/chat/Choice.java ================================================ package com.ai.spark.endPoint.chat; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.*; import java.util.List; @Data @Builder @NoArgsConstructor @AllArgsConstructor @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public class Choice { /** * 文本响应状态,取值为[0,1,2]; 0代表首个文本结果;1代表中间文本结果;2代表最后一个文本结果 */ private Integer status; /** * 返回的数据序号,取值为[0,9999999] */ private Integer seq; @JsonProperty("text") private List texts; @Getter public enum Status { START(0), ING(1), END(2), ; private final int value; Status(int value) { this.value = value; } } } ================================================ FILE: ai-spark/src/main/java/com/ai/spark/endPoint/chat/Message.java ================================================ package com.ai.spark.endPoint.chat; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import java.util.List; @Data @Builder @NoArgsConstructor @AllArgsConstructor @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public class Message { @JsonProperty("text") private List chatTexts; } ================================================ FILE: ai-spark/src/main/java/com/ai/spark/endPoint/chat/document/ChatExtends.java ================================================ package com.ai.spark.endPoint.chat.document; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; @Data @Builder @NoArgsConstructor @AllArgsConstructor @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public class ChatExtends { /** * wiki 大模型问答模板,在某些场景服务默认的 prompt 回答效果不好时,业务可以考虑通过自定义 prompt 来改善。替换的问题标识,替换的文本内容标识 */ private String wikiPromptTpl; /** * wiki 结果分数阈值,低于这个阈值的结果丢弃。取值范围为(0,1] 参考值为:0.80非常宽松 0.82宽松 0.83标准0.84严格 0.86非常严格。服务会根据问题检索文件列表中内容相关的文段,该值设置的越高,可能丢弃的内容越多,但保留下来的内容越准确;但过高也可能导致无匹配内容 */ private Float wikiFilterScore; /** * 用户问题未匹配到文档内容时,是否使用大模型兜底回答问题 */ private Boolean sparkWhenWithoutEmbedding; /** * 大模型问答时的温度,取值范围 (0,1] ,temperature 越大,大模型回答随机度越高 */ private Float temperature; } ================================================ FILE: ai-spark/src/main/java/com/ai/spark/endPoint/chat/function/Function.java ================================================ package com.ai.spark.endPoint.chat.function; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import java.util.List; @Data @NoArgsConstructor @AllArgsConstructor @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public class Function { @JsonProperty("functions") private List functionTexts; } ================================================ FILE: ai-spark/src/main/java/com/ai/spark/endPoint/chat/function/FunctionParameter.java ================================================ package com.ai.spark.endPoint.chat.function; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import java.util.List; @Data @NoArgsConstructor @AllArgsConstructor @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public class FunctionParameter { /** * 参数类型 */ private String type; /** * 该内容由用户定义,命中该方法时需要返回哪些参数 */ private Object properties; /** * 该内容由用户定义,命中方法时必须返回的字段 */ private List required; } ================================================ FILE: ai-spark/src/main/java/com/ai/spark/endPoint/chat/function/FunctionText.java ================================================ package com.ai.spark.endPoint.chat.function; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @Data @NoArgsConstructor @AllArgsConstructor @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public class FunctionText { /** * 用户输入命中后,会返回该名称 */ private String name; /** * 描述function功能即可,越详细越有助于大模型理解该function */ private String description; @JsonProperty("parameters") private FunctionParameter functionParameter; } ================================================ FILE: ai-spark/src/main/java/com/ai/spark/endPoint/chat/req/ChatRequest.java ================================================ package com.ai.spark.endPoint.chat.req; import com.ai.spark.endPoint.chat.*; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import java.util.ArrayList; import java.util.Arrays; @Data @Builder @NoArgsConstructor @AllArgsConstructor @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public class ChatRequest { @JsonProperty("header") private ChatHeader chatHeader; @JsonProperty("parameter") private ChatParameter chatParameter; @JsonProperty("payload") private ChatPayload chatPayload; public static ChatRequest baseBuild(String question, String appId) { ChatHeader chatHeader = ChatHeader.builder().appId(appId).build(); Chat chat = Chat.builder().domain(Chat.General.generalV3.getMsg()).build(); ChatParameter chatParameter = ChatParameter.builder().chat(chat).build(); ChatText chatText = ChatText.builder().role(ChatText.Role.USER.getRoleName()).content(question).build(); Message message = Message.builder().chatTexts(new ArrayList<>(Arrays.asList(chatText))).build(); ChatPayload chatPayload = ChatPayload.builder().message(message).build(); return ChatRequest.builder().chatHeader(chatHeader).chatParameter(chatParameter).chatPayload(chatPayload).build(); } } ================================================ FILE: ai-spark/src/main/java/com/ai/spark/endPoint/chat/req/DocumentChatRequest.java ================================================ package com.ai.spark.endPoint.chat.req; import com.ai.spark.endPoint.chat.ChatText; import com.ai.spark.endPoint.chat.document.ChatExtends; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @Data @Builder @NoArgsConstructor @AllArgsConstructor @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public class DocumentChatRequest { private ChatExtends chatExtends; /** * 必传 * 提问问题检索的文件 id 列表 */ private List fileIds; /** * 问答内容列表,按时间正序,最后一条为最新提问 */ @JsonProperty("messages") private List chatTexts; public static DocumentChatRequest baseBuild(String question, List fileIds) { return DocumentChatRequest.builder() .fileIds(fileIds) .chatTexts(new ArrayList<>(Arrays.asList(ChatText.baseBuild(ChatText.Role.USER, question)))) .build(); } } ================================================ FILE: ai-spark/src/main/java/com/ai/spark/endPoint/chat/resp/ChatResponse.java ================================================ package com.ai.spark.endPoint.chat.resp; import com.ai.spark.endPoint.chat.ChatHeader; import com.ai.spark.endPoint.chat.ChatPayload; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; @Data @Builder @NoArgsConstructor @AllArgsConstructor @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public class ChatResponse { @JsonProperty("header") private ChatHeader chatHeader; @JsonProperty("payload") private ChatPayload chatPayload; } ================================================ FILE: ai-spark/src/main/java/com/ai/spark/endPoint/chat/resp/DocumentChatResponse.java ================================================ package com.ai.spark.endPoint.chat.resp; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import lombok.*; @Data @Builder @NoArgsConstructor @AllArgsConstructor @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public class DocumentChatResponse { /** * 错误码 ,0 标识成功 */ private Integer code; /** * 错误描述 */ private String content; /** * 文档引用,status=99 的时候返回;结构是个 Map,key=文件 id,value=引用的文段列表(对应 fileTrunks 的 index) */ private String fileRefer; /** * 会话唯一标识 */ private String sid; /** * 会话状态,取值为[0,1,2,99];0 代表首次结果;1 代表中间结果;2 代表最后一个结果;99 代表引用的文档及文段 */ private Integer status; @Getter @AllArgsConstructor public enum Code { SUCCESS(0), ; private final int value; } @Getter public enum Status { START(0), ING(1), END(2), DOCUMENT(99), ; private final int value; Status(int value) { this.value = value; } } } ================================================ FILE: ai-spark/src/main/java/com/ai/spark/endPoint/document/Data.java ================================================ package com.ai.spark.endPoint.document; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.NoArgsConstructor; @lombok.Data @Builder @NoArgsConstructor @AllArgsConstructor @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public class Data { /** * 返回上传的 fileId */ private String fileId; } ================================================ FILE: ai-spark/src/main/java/com/ai/spark/endPoint/document/req/FileUploadRequest.java ================================================ package com.ai.spark.endPoint.document.req; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import lombok.*; import lombok.experimental.FieldNameConstants; import java.io.File; @Data @Builder @NoArgsConstructor @AllArgsConstructor @FieldNameConstants @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public class FileUploadRequest { /** * 要上传的文件 */ private File file; /** * 文件 url (文件和文件 url 必须有一个) */ private String url; /** * 文件名称,带后缀。文件用 url 的方式,该字段必传;传 file 的话,该字段可不传 */ private String fileName; /** * 文件类型,目前传固定值"wiki" */ @Builder.Default private String fileType = FileType.wiki.getType(); /** * 文件状态回调地址,文件状态有变动时服务会调用该 url。调用的时候会带上鉴权头,鉴权方式同【接口鉴权】,业务可根据需要是否做鉴权校验 */ private String callbackUrl; @Getter @AllArgsConstructor public enum FileType { wiki("wiki"); private String type; } } ================================================ FILE: ai-spark/src/main/java/com/ai/spark/endPoint/document/resp/DocumentSummaryResponse.java ================================================ package com.ai.spark.endPoint.document.resp; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; @Data @Builder @NoArgsConstructor @AllArgsConstructor @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public class DocumentSummaryResponse { private Boolean flag; private Integer code; private String sid; private String desc; private Object data; } ================================================ FILE: ai-spark/src/main/java/com/ai/spark/endPoint/document/resp/FileUploadResponse.java ================================================ package com.ai.spark.endPoint.document.resp; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; @Data @Builder @NoArgsConstructor @AllArgsConstructor @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public class FileUploadResponse { /** * 返回上传的 fileId */ private Integer code; /** * 请求唯一 id,用于问题定位 */ private String sid; /** * 结果描述 */ private String desc; /** * 返回结果 */ private com.ai.spark.endPoint.document.Data data; } ================================================ FILE: ai-spark/src/main/java/com/ai/spark/endPoint/embedding/Emb.java ================================================ package com.ai.spark.endPoint.embedding; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import lombok.experimental.FieldNameConstants; @Data @Builder @NoArgsConstructor @AllArgsConstructor @FieldNameConstants @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public class Emb { private Feature feature; } ================================================ FILE: ai-spark/src/main/java/com/ai/spark/endPoint/embedding/EmbeddingHeader.java ================================================ package com.ai.spark.endPoint.embedding; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import lombok.experimental.FieldNameConstants; @Data @Builder @NoArgsConstructor @AllArgsConstructor @FieldNameConstants @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public class EmbeddingHeader { /** * 必传 * 在平台申请的app id信息 */ @JsonProperty("app_id") private String appId; /** * 非必传 * 每个用户的id,用于区分不同用户 */ private String uid; /** * 发送状态标识,3为一次性发完 */ @Builder.Default private Integer status = 3; // 以下是请求返回时所需参数 /** * 错误码,0表示正常,非0表示出错; */ private Integer code; /** * 会话是否成功的描述信息 */ private String message; /** * 会话的唯一id,用于讯飞技术人员查询服务端会话日志使用,出现调用错误时建议留存该字段 */ private String sid; } ================================================ FILE: ai-spark/src/main/java/com/ai/spark/endPoint/embedding/EmbeddingMessage.java ================================================ package com.ai.spark.endPoint.embedding; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import lombok.experimental.FieldNameConstants; @Data @Builder @NoArgsConstructor @AllArgsConstructor @FieldNameConstants @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public class EmbeddingMessage { private String text; } ================================================ FILE: ai-spark/src/main/java/com/ai/spark/endPoint/embedding/EmbeddingParameter.java ================================================ package com.ai.spark.endPoint.embedding; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import lombok.experimental.FieldNameConstants; @Data @Builder @NoArgsConstructor @AllArgsConstructor @FieldNameConstants @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public class EmbeddingParameter { @Builder.Default private Emb emb = Emb.builder().feature(Feature.builder().build()).build(); } ================================================ FILE: ai-spark/src/main/java/com/ai/spark/endPoint/embedding/EmbeddingPayload.java ================================================ package com.ai.spark.endPoint.embedding; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import lombok.experimental.FieldNameConstants; @Data @Builder @NoArgsConstructor @AllArgsConstructor @FieldNameConstants @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public class EmbeddingPayload { @JsonProperty("messages") private EmbeddingMessage embeddingMessage; private Feature feature; } ================================================ FILE: ai-spark/src/main/java/com/ai/spark/endPoint/embedding/Feature.java ================================================ package com.ai.spark.endPoint.embedding; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import lombok.experimental.FieldNameConstants; @Data @Builder @NoArgsConstructor @AllArgsConstructor @FieldNameConstants @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public class Feature { @Builder.Default private String encoding = "utf8"; private String seq; private String status; private String text; } ================================================ FILE: ai-spark/src/main/java/com/ai/spark/endPoint/embedding/req/EmbeddingRequest.java ================================================ package com.ai.spark.endPoint.embedding.req; import com.ai.common.utils.JsonUtils; import com.ai.spark.endPoint.chat.ChatText; import com.ai.spark.endPoint.embedding.EmbeddingHeader; import com.ai.spark.endPoint.embedding.EmbeddingMessage; import com.ai.spark.endPoint.embedding.EmbeddingParameter; import com.ai.spark.endPoint.embedding.EmbeddingPayload; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import lombok.experimental.FieldNameConstants; import java.nio.charset.StandardCharsets; import java.util.Base64; @Data @Builder @NoArgsConstructor @AllArgsConstructor @FieldNameConstants @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public class EmbeddingRequest { @JsonProperty("header") private EmbeddingHeader embeddingHeader; @JsonProperty("parameter") private EmbeddingParameter embeddingParameter; @JsonProperty("payload") private EmbeddingPayload embeddingPayload; public static EmbeddingRequest baseBuild(ChatText text, String appId) { return EmbeddingRequest.builder() .embeddingHeader(EmbeddingHeader.builder().appId(appId).build()) .embeddingParameter(EmbeddingParameter.builder().build()) .embeddingPayload(EmbeddingPayload.builder().embeddingMessage(EmbeddingMessage .builder() .text(Base64.getEncoder().encodeToString(JsonUtils.toJson(text).getBytes(StandardCharsets.UTF_8))) .build()).build() ) .build(); } } ================================================ FILE: ai-spark/src/main/java/com/ai/spark/endPoint/embedding/resp/EmbeddingResponse.java ================================================ package com.ai.spark.endPoint.embedding.resp; import com.ai.spark.endPoint.embedding.EmbeddingHeader; import com.ai.spark.endPoint.embedding.EmbeddingPayload; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import lombok.experimental.FieldNameConstants; @Data @Builder @NoArgsConstructor @AllArgsConstructor @FieldNameConstants @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public class EmbeddingResponse { @JsonProperty("header") private EmbeddingHeader embeddingHeader; @JsonProperty("payload") private EmbeddingPayload embeddingPayload; } ================================================ FILE: ai-spark/src/main/java/com/ai/spark/endPoint/images/ImageChat.java ================================================ package com.ai.spark.endPoint.images; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import lombok.experimental.FieldNameConstants; @Data @Builder @NoArgsConstructor @AllArgsConstructor @FieldNameConstants @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public class ImageChat { @Builder.Default private String domain = "general"; @Builder.Default private Integer width = 512; @Builder.Default private Integer height = 512; } ================================================ FILE: ai-spark/src/main/java/com/ai/spark/endPoint/images/ImageHeader.java ================================================ package com.ai.spark.endPoint.images; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import lombok.experimental.FieldNameConstants; @Data @Builder @NoArgsConstructor @AllArgsConstructor @FieldNameConstants @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public class ImageHeader { @JsonProperty("app_id") private String appId; private String uid; // 下面是返回时用到的属性 private Integer code; private String message; private String sid; private Integer status; } ================================================ FILE: ai-spark/src/main/java/com/ai/spark/endPoint/images/ImageParameter.java ================================================ package com.ai.spark.endPoint.images; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import lombok.experimental.FieldNameConstants; @Data @Builder @NoArgsConstructor @AllArgsConstructor @FieldNameConstants @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public class ImageParameter { @Builder.Default @JsonProperty("chat") private ImageChat imageChat = ImageChat.builder().build(); } ================================================ FILE: ai-spark/src/main/java/com/ai/spark/endPoint/images/ImagePayload.java ================================================ package com.ai.spark.endPoint.images; import com.ai.spark.endPoint.chat.Choice; import com.ai.spark.endPoint.chat.Message; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import lombok.experimental.FieldNameConstants; @Data @Builder @NoArgsConstructor @AllArgsConstructor @FieldNameConstants @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public class ImagePayload { private Message message; @JsonProperty("choices") private Choice choice; } ================================================ FILE: ai-spark/src/main/java/com/ai/spark/endPoint/images/ImageUnderstandingChat.java ================================================ package com.ai.spark.endPoint.images; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import lombok.experimental.FieldNameConstants; @Data @Builder @NoArgsConstructor @AllArgsConstructor @FieldNameConstants @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public class ImageUnderstandingChat { @Builder.Default private String domain = "general"; private String auditing; private Double temperature; @JsonProperty("top_k") private Integer topK; @JsonProperty("max_tokens") private Integer maxTokens; } ================================================ FILE: ai-spark/src/main/java/com/ai/spark/endPoint/images/ImageUnderstandingParameter.java ================================================ package com.ai.spark.endPoint.images; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import lombok.experimental.FieldNameConstants; @Data @Builder @NoArgsConstructor @AllArgsConstructor @FieldNameConstants @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public class ImageUnderstandingParameter { @Builder.Default @JsonProperty("chat") private ImageUnderstandingChat imageUnderstandingChat = ImageUnderstandingChat.builder().build(); } ================================================ FILE: ai-spark/src/main/java/com/ai/spark/endPoint/images/ImageUnderstandingPayload.java ================================================ package com.ai.spark.endPoint.images; import com.ai.spark.common.Usage; import com.ai.spark.endPoint.chat.Choice; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import lombok.experimental.FieldNameConstants; @Data @Builder @NoArgsConstructor @AllArgsConstructor @FieldNameConstants @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public class ImageUnderstandingPayload { @JsonProperty("choices") private Choice choice; private Usage usage; } ================================================ FILE: ai-spark/src/main/java/com/ai/spark/endPoint/images/req/ImageCreateRequest.java ================================================ package com.ai.spark.endPoint.images.req; import com.ai.spark.endPoint.chat.ChatText; import com.ai.spark.endPoint.chat.Message; import com.ai.spark.endPoint.images.ImageHeader; import com.ai.spark.endPoint.images.ImageParameter; import com.ai.spark.endPoint.images.ImagePayload; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import lombok.experimental.FieldNameConstants; import java.util.Arrays; @Data @Builder @NoArgsConstructor @AllArgsConstructor @FieldNameConstants @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public class ImageCreateRequest { @JsonProperty("header") private ImageHeader imageHeader; @JsonProperty("parameter") private ImageParameter imageParameter; @JsonProperty("payload") private ImagePayload imagePayload; public static ImageCreateRequest baseBuild(String content, String appId) { return ImageCreateRequest .builder() .imageHeader(ImageHeader.builder().appId(appId).build()) .imageParameter(ImageParameter.builder().build()) .imagePayload(ImagePayload.builder().message(Message.builder().chatTexts(Arrays.asList(ChatText.baseBuild(ChatText.Role.USER, content))).build()).build()) .build(); } } ================================================ FILE: ai-spark/src/main/java/com/ai/spark/endPoint/images/req/ImageUnderstandingRequest.java ================================================ package com.ai.spark.endPoint.images.req; import com.ai.spark.endPoint.chat.ChatText; import com.ai.spark.endPoint.chat.Message; import com.ai.spark.endPoint.images.ImageHeader; import com.ai.spark.endPoint.images.ImagePayload; import com.ai.spark.endPoint.images.ImageUnderstandingParameter; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import lombok.experimental.FieldNameConstants; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Base64; @Data @Builder @NoArgsConstructor @AllArgsConstructor @FieldNameConstants @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public class ImageUnderstandingRequest { @JsonProperty("header") private ImageHeader imageHeader; @JsonProperty("parameter") private ImageUnderstandingParameter imageUnderstandingParameter; @JsonProperty("payload") private ImagePayload imagePayload; public static ImageUnderstandingRequest baseBuild(String content, String appId, File image) { byte[] data = null; try (FileInputStream fileInputStream = new FileInputStream(image)) { data = new byte[fileInputStream.available()]; fileInputStream.read(data); // 读取文件数据到数组中 } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } String imageStr = Base64.getEncoder().encodeToString(data); // 将byte数组进行base64编码 ImageHeader imageHeader = ImageHeader.builder().appId(appId).build(); ImageUnderstandingParameter imageUnderstandingParameter = ImageUnderstandingParameter.builder().build(); ChatText chatText = ChatText.baseBuild(ChatText.Role.USER, content); chatText.setContentType(ChatText.ContentType.TEXT.getType()); ChatText imgText = ChatText.baseBuild(ChatText.Role.USER, imageStr); imgText.setContentType(ChatText.ContentType.IMAGE.getType()); Message message = Message.builder().chatTexts(new ArrayList<>(Arrays.asList(imgText, chatText))).build(); ImagePayload imagePayload = ImagePayload.builder().message(message).build(); return ImageUnderstandingRequest .builder() .imageHeader(imageHeader) .imagePayload(imagePayload) .imageUnderstandingParameter(imageUnderstandingParameter).build(); } } ================================================ FILE: ai-spark/src/main/java/com/ai/spark/endPoint/images/resp/ImageCreateResponse.java ================================================ package com.ai.spark.endPoint.images.resp; import com.ai.spark.endPoint.images.ImageHeader; import com.ai.spark.endPoint.images.ImagePayload; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import lombok.experimental.FieldNameConstants; @Data @Builder @NoArgsConstructor @AllArgsConstructor @FieldNameConstants @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public class ImageCreateResponse { @JsonProperty("header") private ImageHeader imageHeader; @JsonProperty("payload") private ImagePayload imagePayload; } ================================================ FILE: ai-spark/src/main/java/com/ai/spark/endPoint/images/resp/ImageUnderstandingResponse.java ================================================ package com.ai.spark.endPoint.images.resp; import com.ai.spark.endPoint.images.ImageHeader; import com.ai.spark.endPoint.images.ImageUnderstandingPayload; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import lombok.experimental.FieldNameConstants; @Data @Builder @NoArgsConstructor @AllArgsConstructor @FieldNameConstants @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public class ImageUnderstandingResponse { @JsonProperty("header") private ImageHeader imageHeader; @JsonProperty("payload") private ImageUnderstandingPayload imageUnderstandingPayload; } ================================================ FILE: ai-spark/src/main/java/com/ai/spark/interceptor/BaseUrlInterceptor.java ================================================ package com.ai.spark.interceptor; import lombok.extern.slf4j.Slf4j; import okhttp3.Interceptor; import okhttp3.Request; import okhttp3.Response; import java.io.IOException; @Slf4j public class BaseUrlInterceptor implements Interceptor { // TODO 对路径进行拦截 @Override public Response intercept(Chain chain) throws IOException { //获取request Request request = chain.request(); return chain.proceed(request); } } ================================================ FILE: ai-spark/src/main/java/com/ai/spark/interceptor/ResponseInterceptor.java ================================================ package com.ai.spark.interceptor; import com.ai.core.exception.BaseException; import com.ai.core.exception.Constants; import lombok.extern.slf4j.Slf4j; import okhttp3.Interceptor; import okhttp3.Request; import okhttp3.Response; import java.io.IOException; /** * 返回信息拦截器 */ @Slf4j public class ResponseInterceptor implements Interceptor { @Override public Response intercept(Chain chain) throws IOException { // 1. 获取 req 和 resp Request original = chain.request(); Response response = chain.proceed(original); // 2. 排除webSocket连接,判断返回状态 if (!"websocket".equalsIgnoreCase(response.header("Upgrade")) && !"Upgrade".equalsIgnoreCase(response.header("Connection")) && !response.isSuccessful() && response.body() != null) { // 2.1 获取返回的错误信息 log.error(response.body().string()); throw new BaseException(Constants.ErrorMsg.RETRY_ERROR); } return response; } } ================================================ FILE: ai-spark/src/test/java/com/ai/spark/AudioApiTest.java ================================================ package com.ai.spark; import com.ai.core.strategy.impl.FirstKeyStrategy; import com.ai.spark.achieve.ApiData; import com.ai.spark.achieve.Configuration; import com.ai.spark.achieve.defaults.DefaultSparkSessionFactory; import com.ai.spark.achieve.standard.session.AggregationSession; import org.junit.Before; import java.util.Arrays; public class AudioApiTest { private AggregationSession aggregationSession; @Before public void before() { // 1. 创建配置类 Configuration configuration = new Configuration(); configuration.setApiHost("https://spark-api.xf-yun.com"); // 3. 设置鉴权所需的API Key,可设置多个。 ApiData apiData = ApiData.builder() .apiKey("***********************") .apiSecret("***********************") .appId("***********************") .build(); configuration.setKeyList(Arrays.asList(apiData)); // 4. 设置请求时 key 的使用策略,默认实现了:随机获取 和 固定第一个Key 两种方式。 configuration.setKeyStrategy(new FirstKeyStrategy()); // configuration.setKeyStrategy(new RandomKeyStrategy()); // 5. 设置代理,若不需要可不设置 // configuration.setProxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress("127.0.0.1", 7890))); // 6. 创建 session 工厂,制造不同场景的 session DefaultSparkSessionFactory factory = new DefaultSparkSessionFactory(configuration); this.aggregationSession = factory.openAggregationSession(); } } ================================================ FILE: ai-spark/src/test/java/com/ai/spark/ChatApiTest.java ================================================ package com.ai.spark; import com.ai.core.strategy.impl.FirstKeyStrategy; import com.ai.spark.achieve.ApiData; import com.ai.spark.achieve.Configuration; import com.ai.spark.achieve.defaults.DefaultSparkSessionFactory; import com.ai.spark.achieve.defaults.listener.ChatListener; import com.ai.spark.achieve.defaults.listener.DocumentChatListener; import com.ai.spark.achieve.standard.session.AggregationSession; import com.ai.spark.endPoint.chat.ChatText; import com.ai.spark.endPoint.chat.req.ChatRequest; import com.ai.spark.endPoint.chat.req.DocumentChatRequest; import com.ai.spark.endPoint.chat.resp.ChatResponse; import com.ai.spark.endPoint.chat.resp.DocumentChatResponse; import lombok.SneakyThrows; import org.junit.Before; import org.junit.Test; import java.util.Arrays; import java.util.concurrent.CountDownLatch; public class ChatApiTest { private AggregationSession aggregationSession; @Before public void before() { // 1. 创建配置类 Configuration configuration = new Configuration(); configuration.setApiHost("https://spark-api.xf-yun.com"); // 3. 设置鉴权所需的API Key,可设置多个。 ApiData apiData = ApiData.builder() .apiKey("**********************") .apiSecret("**********************") .appId("**********************") .build(); configuration.setKeyList(Arrays.asList(apiData)); // 4. 设置请求时 key 的使用策略,默认实现了:随机获取 和 固定第一个Key 两种方式。 configuration.setKeyStrategy(new FirstKeyStrategy()); // configuration.setKeyStrategy(new RandomKeyStrategy()); // 5. 设置代理,若不需要可不设置 // configuration.setProxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress("127.0.0.1", 7890))); // 6. 创建 session 工厂,制造不同场景的 session DefaultSparkSessionFactory factory = new DefaultSparkSessionFactory(configuration); this.aggregationSession = factory.openAggregationSession(); } /** * 测试聊天功能 */ @Test public void test_chat() { // 创建参数 ChatRequest request = ChatRequest.baseBuild("讲一个笑话", "c8f362b8"); // 设置参数并发起请求,监听事件信息 aggregationSession.getChatSession().chat(new ChatListener(request) { // 异常处理 @SneakyThrows @Override public void onChatError(ChatResponse chatResponse) { System.out.println(chatResponse); } // 获取正常返回的数据 @Override public void onChatOutput(ChatResponse chatResponse) { System.out.println(chatResponse); System.out.print(chatResponse.getChatPayload().getChoice().getTexts().get(0).getContent()); } // 结束处理 @Override public void onChatEnd() { System.out.println("当前会话结束了"); } }); // 等待会话结束 CountDownLatch countDownLatch = new CountDownLatch(1); try { countDownLatch.await(); } catch (InterruptedException e) { e.printStackTrace(); } } /** * 测试多轮聊天功能 */ @Test public void test_chat_multiple() { // 创建参数 ChatRequest request = ChatRequest.baseBuild("1+1=", "c8f362b8"); // 设置第一轮对话的结果 ChatText chatText1 = ChatText.baseBuild(ChatText.Role.ASSISTANT, "2"); // 设置第二轮对话的问题 ChatText chatText2 = ChatText.baseBuild(ChatText.Role.USER, "2+2="); // 将对话过程注入到参数当中 request.getChatPayload().getMessage().getChatTexts().add(chatText1); request.getChatPayload().getMessage().getChatTexts().add(chatText2); // 设置参数并发起请求,监听事件信息 aggregationSession.getChatSession().chat(new ChatListener(request) { @Override public void onChatError(ChatResponse chatResponse) { System.out.println(chatResponse); } @Override public void onChatOutput(ChatResponse chatResponse) { System.out.print(chatResponse.getChatPayload().getChoice().getTexts().get(0).getContent()); } @Override public void onChatEnd() { System.out.println("当前会话结束了"); } }); // 等待会话结束 CountDownLatch countDownLatch = new CountDownLatch(1); try { countDownLatch.await(); } catch (InterruptedException e) { e.printStackTrace(); } } /** * 测试文档对话功能 */ @Test public void test_document_chat() { // 构建参数 DocumentChatRequest documentChatRequest = DocumentChatRequest.baseBuild("总结一下故事一说了什么?", Arrays.asList("c42a68fd31964d43b4f57eab11e9a833")); // 设置阐述并发起请求 aggregationSession.getChatSession().documentChat(new DocumentChatListener(documentChatRequest) { @Override public void onChatError(DocumentChatResponse documentChatResponse) { System.err.println(documentChatResponse); } @Override public void onChatOutput(DocumentChatResponse documentChatResponse) { System.out.println(documentChatResponse); } @Override public void onChatEnd() { System.out.println("当前会话结束了"); } }); // 等待会话结束 CountDownLatch countDownLatch = new CountDownLatch(1); try { countDownLatch.await(); } catch (InterruptedException e) { e.printStackTrace(); } } } ================================================ FILE: ai-spark/src/test/java/com/ai/spark/DocumentApiTest.java ================================================ package com.ai.spark; import com.ai.core.strategy.impl.FirstKeyStrategy; import com.ai.spark.achieve.ApiData; import com.ai.spark.achieve.Configuration; import com.ai.spark.achieve.defaults.DefaultSparkSessionFactory; import com.ai.spark.achieve.standard.session.AggregationSession; import com.ai.spark.endPoint.document.req.FileUploadRequest; import com.ai.spark.endPoint.document.resp.DocumentSummaryResponse; import com.ai.spark.endPoint.document.resp.FileUploadResponse; import org.junit.Before; import org.junit.Test; import java.io.File; import java.util.Arrays; public class DocumentApiTest { private AggregationSession aggregationSession; @Before public void before() { // 1. 创建配置类 Configuration configuration = new Configuration(); configuration.setApiHost("https://spark-api.xf-yun.com"); // 3. 设置鉴权所需的API Key,可设置多个。 ApiData apiData = ApiData.builder() .apiKey("***********************") .apiSecret("***********************") .appId("***********************") .build(); configuration.setKeyList(Arrays.asList(apiData)); // 4. 设置请求时 key 的使用策略,默认实现了:随机获取 和 固定第一个Key 两种方式。 configuration.setKeyStrategy(new FirstKeyStrategy()); // configuration.setKeyStrategy(new RandomKeyStrategy()); // 5. 设置代理,若不需要可不设置 // configuration.setProxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress("127.0.0.1", 7890))); // 6. 创建 session 工厂,制造不同场景的 session DefaultSparkSessionFactory factory = new DefaultSparkSessionFactory(configuration); this.aggregationSession = factory.openAggregationSession(); } /** * 测试文件上传功能 */ @Test public void test_file_upload() { // 读取文件 File file = new File("D:\\chatGPT-api\\AI-java\\doc\\test\\test_file_upload.pdf"); // 构建参数 FileUploadRequest request = FileUploadRequest.builder().file(file).build(); // 发起请求获取结果 FileUploadResponse fileUploadResponse = this.aggregationSession.getDocumentSession().fileUpload(request); System.out.println(fileUploadResponse); // FileUploadResponse(code=0, sid=28db14303e054046aabd2e96e7e65c51, desc=null, data=Data(fileId=1a477e7e9cb44e23ad4abd98076e3f70)) // FileUploadResponse(code=0, sid=8e4f267415d84827a6ec7a1580e1ce64, desc=null, data=Data(fileId=004c3c6e79bc4d738a7e94a12697ea75)) } // 文档总结和文档总结查询这两个接口其实只有请求路径不同,类似于异步的效果。 // 调用文档总结接口,并不会直接返回结果,而是通知模型开始进行总结。 // 然后调用文档总结查询接口查询结果,如果结果已经存在的情况下,不管是调用文档总结接口还是文档总结查询接口,返回的数据都是一样的。 /** * 测试文档总结功能 */ @Test public void test_document_summary_start() { // 传入文档ID,发起请求 DocumentSummaryResponse documentSummaryResponse = this.aggregationSession.getDocumentSession() .documentSummaryStart("004c3c6e79bc4d738a7e94a12697ea75"); System.out.println(documentSummaryResponse); } /** * 测试文档总结结果查询功能 */ @Test public void test_document_summary_query() { // 传入文档ID,发起请求 DocumentSummaryResponse documentSummaryResponse = this.aggregationSession.getDocumentSession() .documentSummaryQuery("004c3c6e79bc4d738a7e94a12697ea75"); System.out.println(documentSummaryResponse); } } ================================================ FILE: ai-spark/src/test/java/com/ai/spark/EmbeddingApiTest.java ================================================ package com.ai.spark; import com.ai.core.strategy.impl.FirstKeyStrategy; import com.ai.spark.achieve.ApiData; import com.ai.spark.achieve.Configuration; import com.ai.spark.achieve.defaults.DefaultSparkSessionFactory; import com.ai.spark.achieve.standard.session.AggregationSession; import com.ai.spark.endPoint.chat.ChatText; import com.ai.spark.endPoint.embedding.req.EmbeddingRequest; import com.ai.spark.endPoint.embedding.resp.EmbeddingResponse; import org.junit.Before; import org.junit.Test; import java.util.Arrays; public class EmbeddingApiTest { private AggregationSession aggregationSession; @Before public void before() { // 1. 创建配置类 Configuration configuration = new Configuration(); configuration.setApiHost("https://spark-api.xf-yun.com"); // 3. 设置鉴权所需的API Key,可设置多个。 ApiData apiData = ApiData.builder() .apiKey("**********************") .apiSecret("**********************") .appId("**********************") .build(); configuration.setKeyList(Arrays.asList(apiData)); // 4. 设置请求时 key 的使用策略,默认实现了:随机获取 和 固定第一个Key 两种方式。 configuration.setKeyStrategy(new FirstKeyStrategy()); // configuration.setKeyStrategy(new RandomKeyStrategy()); // 5. 设置代理,若不需要可不设置 // configuration.setProxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress("127.0.0.1", 7890))); // 6. 创建 session 工厂,制造不同场景的 session DefaultSparkSessionFactory factory = new DefaultSparkSessionFactory(configuration); this.aggregationSession = factory.openAggregationSession(); } /** * 测试文本嵌入功能 */ @Test public void test_embedding() { // 构造参数信息 ChatText chatText = ChatText.baseBuild(ChatText.Role.USER, "这是一段文字"); EmbeddingRequest request = EmbeddingRequest.baseBuild(chatText, "c8f362b8"); // 发起请求 EmbeddingResponse response = aggregationSession.getEmbeddingSession().embed(request); System.out.println(response); } } ================================================ FILE: ai-spark/src/test/java/com/ai/spark/ImageApiTest.java ================================================ package com.ai.spark; import com.ai.core.strategy.impl.FirstKeyStrategy; import com.ai.spark.achieve.ApiData; import com.ai.spark.achieve.Configuration; import com.ai.spark.achieve.defaults.DefaultSparkSessionFactory; import com.ai.spark.achieve.defaults.listener.ImageUnderstandingListener; import com.ai.spark.achieve.standard.session.AggregationSession; import com.ai.spark.endPoint.images.req.ImageCreateRequest; import com.ai.spark.endPoint.images.req.ImageUnderstandingRequest; import com.ai.spark.endPoint.images.resp.ImageCreateResponse; import com.ai.spark.endPoint.images.resp.ImageUnderstandingResponse; import org.junit.Before; import org.junit.Test; import javax.imageio.ImageIO; import javax.xml.bind.DatatypeConverter; import java.awt.image.BufferedImage; import java.io.ByteArrayInputStream; import java.io.File; import java.io.IOException; import java.util.Arrays; import java.util.concurrent.CountDownLatch; public class ImageApiTest { private AggregationSession aggregationSession; @Before public void before() { // 1. 创建配置类 Configuration configuration = new Configuration(); configuration.setApiHost("https://spark-api.xf-yun.com"); // 3. 设置鉴权所需的API Key,可设置多个。 ApiData apiData = ApiData.builder() .apiKey("**********************") .apiSecret("**********************") .appId("**********************") .build(); configuration.setKeyList(Arrays.asList(apiData)); // 4. 设置请求时 key 的使用策略,默认实现了:随机获取 和 固定第一个Key 两种方式。 configuration.setKeyStrategy(new FirstKeyStrategy()); // configuration.setKeyStrategy(new RandomKeyStrategy()); // 5. 设置代理,若不需要可不设置 // configuration.setProxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress("127.0.0.1", 7890))); // 6. 创建 session 工厂,制造不同场景的 session DefaultSparkSessionFactory factory = new DefaultSparkSessionFactory(configuration); this.aggregationSession = factory.openAggregationSession(); } /** * 测试图片生成功能 */ @Test public void test_image_create() throws IOException { // 创建请求参数 ImageCreateRequest request = ImageCreateRequest.baseBuild("画一座大山", "c8f362b8"); // 发起请求获取结果 ImageCreateResponse imageCreateResponse = aggregationSession.getImageSession().imageCreate(request); // 得到结果当中的base64 图片字符串 String content = imageCreateResponse.getImagePayload().getChoice().getTexts().get(0).getContent(); // 转换为byte数组 byte[] imageBytes = DatatypeConverter.parseBase64Binary(content.substring(content.indexOf(",") + 1)); // 读取byte数组,存放到指定文件路径 BufferedImage bufferedImage = ImageIO.read(new ByteArrayInputStream(imageBytes)); File outputFile = new File("D:\\chatGPT-api\\AI-java\\doc\\test\\test_create_image.png"); ImageIO.write(bufferedImage, "png", outputFile); } @Test public void test_image_understanding() { String filePath = "D:\\chatGPT-api\\AI-java\\doc\\test\\test_create_image.png"; File file = new File(filePath); ImageUnderstandingRequest request = ImageUnderstandingRequest.baseBuild("这张图片的内容是什么?", "c8f362b8", file); aggregationSession.getImageSession().imageUnderstanding(request, new ImageUnderstandingListener(request) { @Override public void onChatError(ImageUnderstandingResponse imageUnderstandingResponse) { System.err.println(imageUnderstandingResponse); } @Override public void onChatOutput(ImageUnderstandingResponse imageUnderstandingResponse) { System.out.println(imageUnderstandingResponse.getImageUnderstandingPayload().getChoice().getTexts().get(0).getContent()); } @Override public void onChatEnd() { } }); // 等待会话结束 CountDownLatch countDownLatch = new CountDownLatch(1); try { countDownLatch.await(); } catch (InterruptedException e) { e.printStackTrace(); } } } ================================================ FILE: doc/test/test_file_upload.txt ================================================ 故事1:小老虎问路 一头骄傲的小老虎在大森林里迷了路。 他走啊走,看到了一头正在蒙头大睡的野猪。小老虎对着野猪的耳朵,大声喊道:“喂,蠢猪,别打呼噜了,告诉我回家的路怎么走吧!”野猪生气地眨了眨眼睛,一言不发,把屁股转向了小老虎,继续睡大觉。小老虎讨了个没趣,无奈地走了。 小老虎问路 路上,他看到一只正在忙碌的小松鼠,于是他用自己的大嗓门儿喊道:“喂,如果你告诉我回家的路怎么走,我就让妈妈给你最好的礼物!”小松鼠就像没听见一样,不搭理小老虎,照样干自己的活儿。小老虎勃然大怒,冲向一只戴眼镜的老灰兔:“嘿,花眼的老兔头,快给我指一条回家的路!”老灰兔慢慢地抬起头,和蔼地说:“森林里的路大家都熟悉,可你这样没礼貌,哪怕你问遍所有的动物,你还是找不到回家的路。”听了老灰兔的话,小老虎猛然醒悟过来——对人说话,要有礼貌才行! 这时,前面过来一只梅花鹿。小老虎走过去,礼貌地说:“梅花鹿你好,请你告诉我回家的路怎么走,好吗?”梅花鹿热情地告诉了小老虎,小老虎高兴的连声说:“谢谢你,梅花鹿,谢谢你!” 小老虎终于安全地回到了自己的小屋。 故事2:鸡和猫调工作 张三家里养了一只猫和一只公鸡。 一天早晨,“喔,喔,喔……”公鸡的长鸣把沉睡的猫叫醒了,猫揉了揉眼说:“死公鸡,没娘教的孩子,吵死啊!”公鸡大声地回骂道:“死懒猫,你才没娘教,太阳晒屁股了,还不起来干活!”猫又回敬了一句:“哼,我晚上辛辛苦苦晚上捉老鼠,白天还不让我多睡会儿?”公鸡无语了。 过了一会儿,猫想出一个好办法,对公鸡说:“不如,我们调换一下工作,你去捉老鼠,我来打鸣叫时钟,你敢不敢?”公鸡自信地说:“啊有不敢?我就怕你不敢?”猫说:“好,那我们就调工作吧!” 第二天早晨,猫早早地起来,站在房顶上,“喵,喵,喵……”地叫着,可是人们都听习惯了公鸡叫天亮,猫的叫声只把附近的人叫醒了,远处的人根本听不见。后来,猫的嗓子都喊破了,被送到宠物医院治疗。 晚上,公鸡来到老鼠洞前,对老鼠说:“鸡大爷来了,快给我出来!”鼠王以为是猫的诡计,就叫了一只小老鼠去侦察,小老鼠侦察了一番回来说:“站在洞门口的是一只公鸡。”于是,鼠们就往老鼠洞里钻。公鸡见一只老鼠都不出来,就把锋利的爪子伸进老鼠洞里,一只老鼠胆大包天串到洞门口对准鸡爪狠狠地咬了一口,鸡痛得哇哇大叫,也被送进了宠物医院。 猫和公鸡在宠物医院相遇了,当他们见彼此都受了伤后,明白了一个道理:尺有所短,寸有所长。 故事3:固执的鱼 在一个池塘里住着一条小鱼。他有一个好朋友,是一只蝌蚪。这条小鱼和蝌蚪总是在一起游泳,一起找食物,一起玩。 一天早上,小鱼吃惊地看见在蝌蚪尾巴的两边长出了一对腿。小鱼问蝌蚪为什么他会有腿。 “我不是鱼,我是一只蝌蚪,一只年幼的青蛙。以后,等我长大了,我就不再呆在这儿了。”蝌蚪回答说。 “你说谎!”小鱼说。 “如果你不相信,就等着瞧吧!”蝌蚪说。 小鱼已经三天没有看见蝌蚪了,他很担心。为了寻找朋友,他搜索了每一个地方,蝌蚪能去哪儿呢? 几天以后,蝌蚪又出现了。小鱼非常高兴,可是他又吃了一惊,蝌蚪又长出了一对腿,哦,还有,尾巴也变短了。 “这几天你到什么地方去了?”小鱼问。 “我去陆地上了,我不是告诉你我在这儿呆不长吗?看,现在我有四条腿了。不久我就要长期在地上生活了。”蝌蚪说,“现在请不要再叫我蝌蚪,就叫我青蛙吧。再见了,鱼!” 小鱼眨眨眼睛,被他朋友的话搞糊涂了。他不能相信听到和看到的,因为从前他的朋友能像鱼一样游泳,从前他没有腿,而现在却不是这样了。 小鱼独自留在池塘里,最后,他变成了一条大鱼。 一天,当这条鱼在池塘里游水寻找食物的时候,一只青蛙跳进水里。他就是鱼的老朋友。看到朋友,鱼非常高兴。 “你去哪儿啦?”鱼问。 “我一直在陆地上。”青蛙说,并且把他在陆地上遇到的事情告诉鱼。 鱼听了青蛙的故事后,问:“在那边谁是你的朋友呀?” “我有好多朋友,像牛啦,鸟啦,猫啦,还有其它许多动物。”青蛙说。 “我能跟你去陆地吗?我想见见他们。”鱼说。 “那怎么行!你在陆地上不能呼吸,你会死的。”青蛙解释说。 “可是我想去看看牛啦,鸟啦,还有别的你刚才告诉我的朋友们。”鱼请求道。 “你不必亲自去,我给你说说不就行了。”青蛙说。于是青蛙向鱼讲了许多他的陆地朋友的事。鱼试着想象那些动物的样子,但是他总是不满意。 “你在陆地上还看见什么别的吗?”鱼又问。 “还有人,有孩子,有玩具和别的许多东西。”青蛙继续说。 他们一直聊到晚上。鱼很不开心,因为他不能去陆地上看这些奇怪的事,这天晚上他失眠了。他满脑子都是白天听到的各种各样的事情。 第二天早上,鱼去寻找食物。忽然,他看见水面上天空飞鸟的倒影。他太想看看鸟了,就鼓起勇气试着跳到河岸上。鱼一纵身跳上了岸。但是在他睁开眼睛之前,他已经喘不过气了。他开始呻吟起来。算他走运,青蛙正好在附近找吃的。 青蛙马上跳到奄奄一息的鱼的身边。他一点也没耽搁,把大鱼拉进池塘里。鱼一进水,立刻苏醒了。他很惊讶,问青蛙发生了什么事。 青蛙微笑着说:“我跟你说过,你不能到陆地上去。不管你是在陆地上还是在水里都没关系,一切都是美好的,美丽的,为什么你不愿意听我的话!” “可是只呆在这儿我觉得不满意。”鱼继续说。 “你应该满足了,”青蛙劝鱼说:“没有多少生命能像你一样呆在水里。” 鱼笑了,高兴地在水草间游来游去,他认识到他的朋友说的是真的。 故事4:橘子老虎 秋天,橘子熟了,那黄澄澄的蜜橘挂满枝头,远远望去,就像一个个的小灯笼。一天,一个最大、最沉的橘子,看到同伴被人摘走,伤心地对橘子树说:“妈妈,难道我们橘子生来就应该被人吃掉吗?” “是啊,孩子,我们的最大愿望就是丰富人类的美好生活。我们身上的果核将会落入泥土,然后新的生命又会破土而出。” “不,妈妈,我可不愿为他人活着,更不愿被人随意摘取,我要变成一个人见人怕的老虎。” “孩子,那可不是我们橘子的风格。” “不嘛!”大橘子纵身一跳,从树上跳到了地面。奇怪的事情发生了:大橘子的身体不断地胀大、胀大,最后圆圆的橘子肚子拉长了,橘皮上竟然浮现出色彩斑斓的花纹来,前面拱出一个脑袋,脑门正中有一个醒目的“王”字,后面露出一条长尾巴来。哈,大橘子竟然变成一只威风凛凛的橘子老虎啦! 橘子老虎非常高兴,她告别妈妈,决定到各地去旅行,让大家见识见识橘子老虎的威风。他翻过一座山冈,看见一只小羊正趴在大树下低声哭泣。他决定吓唬吓唬小羊。他蹑手蹑脚地走上前去,却发现一只大灰狼也在偷偷地逼近小羊。橘子老虎见状忙喊道:“小羊,当心大灰狼!” 小羊一惊,扭头要跑,大灰狼扑上来抓住了小羊。在这千钧一发的时刻,只见橘子老虎一个箭步蹿上前去,对着大灰狼喊道:“大灰狼,快放开他,要不我就撕碎你!” 大灰狼一愣,见一只猛虎向自己扑来,不由两腿直打颤。虽然舍不得到嘴的肥嫩小羊,但这只老虎可不是等闲之辈,只得丢下小羊逃走了。面对橘子老虎,小羊流着眼泪说道:“虎大王,我妈妈得了重病,想吃橘子,您能否等我找到橘子后再吃我呢?” 看看楚楚可怜的小羊,橘子老虎被他爱妈妈的孝心所感动了。他安慰小羊:“别怕,让我帮助你完成心愿。”说着,他便撕开自己的橘子肚皮,掰下一瓣橘子,递给小羊说,“给你妈妈送回去吧。” 小羊感激地说:“您真是天下心眼最好的老虎呀!” 橘子老虎笑了笑,继续往前赶路了。 故事5:狐狸假扮兽王 很早以前,森林中的百兽过着闲逸、安乐的生活。因没有兽王,便商议决定寻找一个有资格作兽王的动物来领导群兽,于是四处寻觅。一天,有只狐狸跑到一家染衣坊寻找食物,不慎掉进了染缸。它惊恐万分,拼命挣扎,等到爬出染缸时,已是精疲力尽。狐狸再也没有心思寻找食物,落荒而逃。它在河边喝水时,见到水中的倒影,忽然发现自己身上的颜色变得美丽异常,与众不同。狐狸自己知道那是在染缸里染上的。正在这时,寻找兽王的动物们发现了它,惊奇地问它是什么动物?是从什么地方来的?狐狸灵机一动,诈称自己是天帝派来作兽王的。群兽从来没有见到过它这样的动物,又听说是天帝派来的,便生起信心,拥立狐狸为王。 当上兽王的狐狸,得意忘形,作威作福。它不但役使所有的野兽为自己做事,还忘乎所以地让狮子当坐骑,四处巡视游玩。照理说狐狸当了兽王,应该对自己的同类特别关照才是,但这兽王并没有这样做,反而痛恨狐群,百般加以折磨。动物们本以为有兽王领导,生活会更加幸福、快乐,没想到却落得如此痛苦。众狐狸更觉得是飞来的横祸,大惑不解,暗地里对兽王进行观察,它们怀疑这天帝所赐的兽王可能是狐狸装扮的。众狐狸找了个机会,偷偷地询问狮子:“每月十五,月圆之日,兽王是否仍要骑着你去游玩?”狮子说:“不,兽王每月十五都给我放假,它总是单独离去。”群狐说:“我们狐狸因为业力的关系,每到十五日就会昏迷一阵,好一会儿才能恢复。你可以在十五日那天跟踪兽王,看它是不是狐狸所扮?” 等到十五日,兽王照常向远处跑去。狮子便悄悄地跟在后面,到了一个山洞里,果然看见兽王象死尸一样倒在地上,昏迷不醒。狮子这才知道动物们都上当受骗了,尤其是自己,居然被狐狸当坐骑戏弄了这么长的时间,狮子羞怒难当,一跃而上将这只狐狸吞食了…… 群兽因为没有好好观察,让一只卑劣的狐狸当了兽王。最后的结果是让群兽都受到了莫大的痛苦,那自作聪明的狐狸也自取灭亡。 ================================================ FILE: pom.xml ================================================ 4.0.0 com.ai AI-java pom 1.0 ai-common ai-openai ai-spark ai-baidu ai-core AI-java ai-sdk-java AI-java org.apache.maven.plugins maven-surefire-plugin 2.12.4 true org.apache.maven.plugins maven-compiler-plugin 8 8 org.apache.maven.plugins maven-jar-plugin 2.3.1 true