[
  {
    "path": "README.md",
    "content": "## 目录\n\n- [**项目背景**](#项目背景)\n- [**安装**](#安装)\n- [**使用方式**](#使用方式)\n- [**示例**](#示例)\n- [**更新记录**](#更新记录)\n\n## **项目背景**\n\n## Star History\n\n[![Star History Chart](https://api.star-history.com/svg?repos=mainpropath/AI-java&type=Date)](https://star-history.com/#mainpropath/AI-java&Date)\n\n**基于本项目的大模型框架正在火速研发当中，项目地址：[AI-SmartFuse-Framework](https://github.com/mainpropath/AI-SmartFuse-Framework)**\n\n随着人工智能技术的飞速发展，自然语言处理在各个领域都具有广泛的应用前景。聊天机器人作为其中一种受欢迎且实用的解决方案，能够与用户进行自然对话，并提供有价值的信息和服务。\n\n为了更好更快更方便的开发大模型应用，我们启动了一个名为AI-java的项目，专门针对Java编程语言。该SDK旨在简化与各大模型API的交互，使Java开发者可以轻松地集成大模型的功能到他们的应用程序中。\n\n该项目的主要目标如下：\n\n- **提供简单易用的接口：**我们致力于开发一个用户友好的SDK，提供简洁的方法和函数，使Java开发者能够轻松地与大模型进行通信。本SDK提供发送用户请求并接收生成的回复的便捷方法。\n- **支持流式应答：**实时生成响应，不需要等待整个对话结束。能够快速获得反馈，更加流畅地进行对话。流式应答能够为用户提供更接近真实人类对话的体验。用户可以即时提出问题、进行追问或做出反应，而模型能够相应地作出回应和调整。\n- **上下文管理：**大模型是基于上下文的，因此我们希望SDK能够支持上下文的管理，允许用户在对话过程中保持和更新上下文信息。\n- **异常处理和错误处理：**我们将注重SDK的稳定性和可靠性，确保它能够有效地处理各种可能出现的错误和异常情况，并提供相应的异常处理机制。\n- **示例和文档：**为了方便Java开发者快速上手使用SDK，我们将提供详细的示例代码和清晰的文档，以解释如何正确集成和使用本项目。\n- **多厂商模型接入：**本项目旨在提供多个不同厂商的模型接入，大模型功能不应该局限于某一单一的模型。应当集各家之长。\n- **高拓展性：**本项目所有模型功能都提供对应接口，默认实现一套接口方法，同时也可让用户根据接口实现自己的API调用方式。\n\n## **安装**\n\n**下载项目到本地，将项目 install 到本地 maven 仓库。**\n\n![image-20231205204603312](doc/img/image-20231205204603312.png)\n\n**注意，由于本项目是多模块编写，想要使用哪一个厂商的模型API，请引入对应的依赖。**\n\n**如果使用openai相关模型功能，install 之后，在pom文件中可引入如下依赖。**\n\n```\n        <dependency>\n            <groupId>com.ai</groupId>\n            <artifactId>ai-openai</artifactId>\n            <version>1.0</version>\n        </dependency>\n```\n\n**如果使用讯飞相关模型功能，install之后，在pom文件中引入如下依赖。**\n\n```\n        <dependency>\n            <groupId>com.ai</groupId>\n            <artifactId>ai-spark</artifactId>\n            <version>1.0</version>\n        </dependency>\n```\n\n## **使用方式**\n\n**本项目目前实现了chatGPT官方文档下 endpoints 各个板块全部的接口。正在完成讯飞星火模型相关API的编写。**\n\n项目结构如下\n\n```java\n├─ai-common \n├─ai-openai   openai相关API功能\n├─ai-spark    星火模型相关API功能\n└─doc         测试相关的文件\n```\n\n**不管是使用哪一个厂商的模型API，在我们的SDK当中，使用方式都是一致的。使用方式如下：（下面是openai相关功能的使用方式）**\n\n**具体的使用方式请参考测试类当中的测试方法。**\n\n```java\n// 工厂创建聚合的session\nAggregationSession aggregationSession=factory.openAggregationSession();\n\n// 通过聚合的session获取不同场景的会话，处理不同场景，进行解耦。\n// 获取聊天会话窗口\naggregationSession.getChatSession();\n// 获取文件会话窗口\naggregationSession.getFilesSession();\n// 获取微调会话窗口\naggregationSession.getFineTuningSession();\n// 获取图片会话窗口\naggregationSession.getImageSession();\n// 获取模型会话窗口\naggregationSession.getModelSession();\n// 获取音频会话窗口\naggregationSession.getAudioSession();\n// 获取审核会话窗口\naggregationSession.getModerationSession();\n// 获取嵌入会话窗口\naggregationSession.getEmbeddingSession();\n```\n\n## **示例**\n\n示例相关的测试图片和语言文件在 doc/test 目录下。\n\nopenai相关功能测试如下所示，更多功能测试请参考测试类\n\n[openai测试路径](https://github.com/mainpropath/AI-java/tree/dev/ai-openai/src/test/java/com/ai/openai)\n\n[讯飞星火测试路径](https://github.com/mainpropath/AI-java/tree/dev/ai-spark/src/test/java/com/ai/spark)\n\n**示例一：多轮对话**\n\n```java\npublic void test_chat_completions() {\n    // 创建参数，上下文对话。\n    // 第一次的问题\n    DefaultChatCompletionRequest defaultChatCompletionRequest = DefaultChatCompletionRequest.BuildDefaultChatCompletionRequest(\"1+1=\");\n    // 第一次的回复\n    defaultChatCompletionRequest.addMessage(Constants.Role.ASSISTANT.getRoleName(), \"2\");\n    // 第二次的问题\n    defaultChatCompletionRequest.addMessage(Constants.Role.USER.getRoleName(), \"2+2=\");\n    // 询问第二次的问题的结果\n    ChatCompletionResponse chatCompletionResponse = aggregationSession.getChatSession().chatCompletions(NULL, NULL, NULL, defaultChatCompletionRequest);\n    // 解析结果\n    chatCompletionResponse.getChoices().forEach(e -> {\n        log.info(\"测试结果：{}\", e.getMessage());\n    });\n}\n```\n\n**示例二：图片创作**\n\n```java\npublic void test_create_image() {\n    CreateImageRequest createImageRequest = CreateImageRequest.BuildBaseCreateImageRequest(\"森林里有一只小熊，小熊在吃蜂蜜。\");\n    List<ImageObject> imageObjectList = aggregationSession.getImageSession().createImageCompletions(NULL, NULL, NULL, createImageRequest);\n    log.info(\"测试结果：{}\", imageObjectList);\n}\n```\n\n**示例三：文本转语音（主要是通过回调函数获取回传的音频数据）**\n\n```java\npublic void test_tts() throws InterruptedException {\n    // 定义请求参数\n    TtsCompletionRequest ttsCompletionRequest = TtsCompletionRequest.builder()\n            .model(TtsCompletionRequest.Model.tts_1.getModuleName())// 设置使用的模型\n            .input(\"你好，我是chatGPT\")\n            .voice(TtsCompletionRequest.Voice.alloy.getVoiceName())// 设置声音的样式\n            .build();\n    // 回传文件存放的路径\n    File file = new File(\"doc/test/test_tts.mp3\");\n    // 添加回调函数，发送请求\n    aggregationSession.getAudioSession().ttsCompletions(NULL, NULL, NULL, ttsCompletionRequest, new Callback<ResponseBody>() {\n                @Override\n                public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {\n                    try (InputStream inputStream = response.body().byteStream();\n                         OutputStream os = new BufferedOutputStream(new FileOutputStream(file))) {\n                        // 创建文件\n                        if (!file.exists()) {\n                            if (!file.getParentFile().exists()) file.getParentFile().mkdir();\n                            file.createNewFile();\n                        }\n                        byte data[] = new byte[10240];\n                        int len;\n                        while ((len = inputStream.read(data, 0, 8192)) != -1) {\n                            os.write(data, 0, len);\n                        }\n                    } catch (IOException e) {\n                        e.printStackTrace();\n                    }\n                }\n\n                @Override\n                public void onFailure(Call<ResponseBody> call, Throwable t) {\n                    t.printStackTrace();\n                }\n            }\n    );\n    // 阻塞等待\n    new CountDownLatch(1).await();\n}\n```\n\n## **更新记录**\n\n2024-01-24：完成星火模型对话、文档对话、图片生成、图片理解接口的实现。\n\n2024-01-10：开始讯飞星火模型相关API的编写工作\n\n2023-12-28：预启动其他模型的API编写工作\n\n2023-12-14：修复BUG\n\n2023-12-8：支持图片对话和函数对话\n\n2023-12-7：优化测试用例，增加代码注释，丰富文档内容\n\n2023-12-4：第一版SDK问世，支持官方 endpoints 下所有接口\n\n**项目长期维护，欢迎向本项目提需求，欢迎star~~~**\n"
  },
  {
    "path": "ai-baidu/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xmlns=\"http://maven.apache.org/POM/4.0.0\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <parent>\n        <artifactId>AI-java</artifactId>\n        <groupId>com.ai</groupId>\n        <version>1.0</version>\n    </parent>\n    <modelVersion>4.0.0</modelVersion>\n    <artifactId>ai-baidu</artifactId>\n\n    <properties>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n        <java.version>1.8</java.version>\n        <maven.compiler.source>1.8</maven.compiler.source>\n        <maven.compiler.target>1.8</maven.compiler.target>\n        <junit.version>4.13.2</junit.version>\n    </properties>\n\n    <dependencies>\n        <dependency>\n            <groupId>com.ai</groupId>\n            <artifactId>ai-common</artifactId>\n            <version>1.0</version>\n        </dependency>\n        <dependency>\n            <groupId>com.ai</groupId>\n            <artifactId>ai-core</artifactId>\n            <version>1.0</version>\n        </dependency>\n        <dependency>\n            <groupId>junit</groupId>\n            <artifactId>junit</artifactId>\n            <version>${junit.version}</version>\n            <scope>test</scope>\n        </dependency>\n    </dependencies>\n\n</project>\n"
  },
  {
    "path": "ai-baidu/src/main/java/com/ai/baidu/achieve/ApiData.java",
    "content": "package com.ai.baidu.achieve;\n\n\nimport lombok.AllArgsConstructor;\nimport lombok.Builder;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\n\n/**\n * 记录用户API信息\n */\n@Data\n@Builder\n@NoArgsConstructor\n@AllArgsConstructor\npublic class ApiData {\n\n    private String appId;\n    private String apiKey;\n    private String secretKey;\n    private String accessToken;\n\n}\n"
  },
  {
    "path": "ai-baidu/src/main/java/com/ai/baidu/achieve/Configuration.java",
    "content": "package com.ai.baidu.achieve;\n\nimport com.ai.baidu.achieve.standard.api.BaiduApiServer;\nimport com.ai.core.config.BaseConfiguration;\nimport lombok.*;\nimport okhttp3.sse.EventSource;\nimport okhttp3.sse.EventSources;\nimport org.jetbrains.annotations.NotNull;\n\nimport java.util.List;\n\n/**\n * @Description: baidu 相关配置信息\n **/\n@Data\n@ToString(callSuper = true)\n@EqualsAndHashCode(callSuper = true)\n@NoArgsConstructor\n@AllArgsConstructor\npublic class Configuration extends BaseConfiguration {\n\n    /**\n     * api 服务提供者\n     */\n    private BaiduApiServer baiduApiServer;\n\n    /**\n     * api Key 集合\n     */\n    @NotNull\n    private List<ApiData> keyList;\n\n    public ApiData getSystemApiData() {\n        return (ApiData) this.getKeyStrategy().apply(keyList);\n    }\n\n    public EventSource.Factory createRequestFactory() {\n        return EventSources.createFactory(this.getOkHttpClient());\n    }\n\n}\n"
  },
  {
    "path": "ai-baidu/src/main/java/com/ai/baidu/achieve/defaults/DefaultBaiduSessionFactory.java",
    "content": "package com.ai.baidu.achieve.defaults;\n\nimport com.ai.baidu.achieve.Configuration;\nimport com.ai.baidu.achieve.defaults.session.DefaultAggregationSession;\nimport com.ai.baidu.achieve.standard.api.BaiduApiServer;\nimport com.ai.baidu.achieve.standard.session.AggregationSession;\nimport com.ai.baidu.interceptor.ResponseInterceptor;\nimport com.ai.core.factory.SessionFactory;\nimport lombok.AllArgsConstructor;\nimport okhttp3.OkHttpClient;\nimport okhttp3.logging.HttpLoggingInterceptor;\nimport retrofit2.Retrofit;\nimport retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;\nimport retrofit2.converter.jackson.JacksonConverterFactory;\n\nimport java.util.concurrent.TimeUnit;\n\n/**\n * @Description: baidu API Factory 会话工厂\n **/\n@AllArgsConstructor\npublic class DefaultBaiduSessionFactory implements SessionFactory<AggregationSession, BaiduApiServer> {\n\n    private final Configuration configuration;\n\n    @Override\n    public OkHttpClient createHttpClient() {\n        // 1. 日志配置\n        HttpLoggingInterceptor httpLoggingInterceptor = new HttpLoggingInterceptor();\n        httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.NONE);\n        // 2. 开启 Http 客户端\n        OkHttpClient.Builder builder = new OkHttpClient.Builder()\n                .addInterceptor(httpLoggingInterceptor)\n                .addInterceptor(new ResponseInterceptor())\n                .connectTimeout(450, TimeUnit.SECONDS)\n                .writeTimeout(450, TimeUnit.SECONDS)\n                .readTimeout(450, TimeUnit.SECONDS);\n        // 3. 检查是否需要代理\n        if (configuration.getProxy() != null) {\n            builder.proxy(configuration.getProxy());\n        }\n        return builder.build();\n    }\n\n    @Override\n    public BaiduApiServer createApiServer(OkHttpClient okHttpClient) {\n        return new Retrofit.Builder()\n                .baseUrl(configuration.getApiHost())\n                .client(okHttpClient)\n                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())\n                .addConverterFactory(JacksonConverterFactory.create())\n                .build().create(BaiduApiServer.class);\n    }\n\n    @Override\n    public AggregationSession openAggregationSession() {\n        OkHttpClient okHttpClient = createHttpClient();\n        configuration.setOkHttpClient(okHttpClient);\n        configuration.setBaiduApiServer(createApiServer(okHttpClient));\n        return new DefaultAggregationSession(configuration);\n    }\n\n}\n"
  },
  {
    "path": "ai-baidu/src/main/java/com/ai/baidu/achieve/defaults/session/DefaultAggregationSession.java",
    "content": "package com.ai.baidu.achieve.defaults.session;\n\nimport com.ai.baidu.achieve.Configuration;\nimport com.ai.baidu.achieve.standard.session.AggregationSession;\nimport com.ai.baidu.achieve.standard.session.ChatSession;\nimport com.ai.baidu.achieve.standard.session.EmbeddingSession;\nimport com.ai.baidu.achieve.standard.session.ImageSession;\n\nimport static com.ai.common.utils.ValidationUtils.ensureNotNull;\n\n/**\n * @Description: 聚合各个类型的session\n **/\npublic class DefaultAggregationSession implements AggregationSession {\n\n    private Configuration configuration;\n\n    private volatile ChatSession chatSession;\n\n    private volatile EmbeddingSession embeddingSession;\n\n    private volatile ImageSession imageSession;\n\n    public DefaultAggregationSession(Configuration configuration) {\n        this.configuration = ensureNotNull(configuration, \"configuration\");\n    }\n\n    @Override\n    public ChatSession getChatSession() {\n        if (chatSession == null) {\n            synchronized (this) {\n                if (chatSession == null) {\n                    chatSession = new DefaultChatSession(configuration);\n                }\n            }\n        }\n        return chatSession;\n    }\n\n    @Override\n    public EmbeddingSession getEmbeddingSession() {\n        if (embeddingSession == null) {\n            synchronized (this) {\n                if (embeddingSession == null) {\n                    embeddingSession = new DefaultEmbeddingSession(configuration);\n                }\n            }\n        }\n        return embeddingSession;\n    }\n\n    @Override\n    public ImageSession getImageSession() {\n        if (imageSession == null) {\n            synchronized (this) {\n                if (imageSession == null) {\n                    imageSession = new DefaultImageSession(configuration);\n                }\n            }\n        }\n        return imageSession;\n    }\n\n}\n"
  },
  {
    "path": "ai-baidu/src/main/java/com/ai/baidu/achieve/defaults/session/DefaultChatSession.java",
    "content": "package com.ai.baidu.achieve.defaults.session;\n\nimport cn.hutool.http.ContentType;\nimport com.ai.baidu.achieve.Configuration;\nimport com.ai.baidu.achieve.standard.session.ChatSession;\nimport com.ai.baidu.common.ApiUrl;\nimport com.ai.baidu.endPoint.chat.req.ChatRequest;\nimport com.ai.baidu.endPoint.chat.resp.ChatResponse;\nimport com.ai.common.utils.JsonUtils;\nimport lombok.Data;\nimport lombok.EqualsAndHashCode;\nimport lombok.ToString;\nimport okhttp3.HttpUrl;\nimport okhttp3.MediaType;\nimport okhttp3.Request;\nimport okhttp3.RequestBody;\nimport okhttp3.sse.EventSource;\nimport okhttp3.sse.EventSourceListener;\n\nimport static com.ai.common.utils.ValidationUtils.ensureNotNull;\n\n/**\n * @description baidu 对话类会话\n */\n@Data\n@ToString(callSuper = true)\n@EqualsAndHashCode(callSuper = true)\npublic class DefaultChatSession extends Session implements ChatSession {\n\n    /**\n     * 工厂事件\n     */\n    private EventSource.Factory factory;\n\n    public DefaultChatSession(Configuration configuration) {\n        this.setConfiguration(ensureNotNull(configuration, \"configuration\"));\n        this.setBaiduApiServer(ensureNotNull(configuration.getBaiduApiServer(), \"baiduApiServer\"));\n        this.factory = ensureNotNull(configuration.createRequestFactory(), \"requestFactory\");\n    }\n\n    @Override\n    public ChatResponse chat(String accessToken, ChatRequest chatRequest) {\n        // 检查一下是否为空，为空根据设置的 keyStrategy 获取一个用户设置的 key\n        return this.getBaiduApiServer().chat(checkAccessToken(accessToken), chatRequest).blockingGet();\n    }\n\n    @Override\n    public EventSource chat(String accessToken, ChatRequest chatRequest, EventSourceListener eventSourceListener) {\n        // 将 accessToken 设置到请求路径上\n        HttpUrl.Builder urlBuilder = HttpUrl.parse(this.getConfiguration().getApiHost().concat(ApiUrl.ERNIE_Bot_4_0.getUrl())).newBuilder();\n        urlBuilder.addQueryParameter(\"access_token\", checkAccessToken(accessToken));\n        // 发起请求\n        Request request = new Request.Builder()\n                .url(urlBuilder.build().toString())\n                .post(RequestBody.create(MediaType.parse(ContentType.JSON.getValue()), JsonUtils.toJson(chatRequest)))\n                .build();\n        return factory.newEventSource(request, eventSourceListener);\n    }\n}\n"
  },
  {
    "path": "ai-baidu/src/main/java/com/ai/baidu/achieve/defaults/session/DefaultEmbeddingSession.java",
    "content": "package com.ai.baidu.achieve.defaults.session;\n\nimport com.ai.baidu.achieve.Configuration;\nimport com.ai.baidu.achieve.standard.session.EmbeddingSession;\nimport com.ai.baidu.endPoint.embedding.EmbeddingData;\nimport com.ai.baidu.endPoint.embedding.req.EmbeddingRequest;\nimport com.ai.baidu.endPoint.embedding.resp.EmbeddingResponse;\nimport lombok.Data;\nimport lombok.EqualsAndHashCode;\nimport lombok.ToString;\n\nimport java.util.List;\nimport java.util.stream.IntStream;\n\nimport static com.ai.common.utils.ValidationUtils.ensureNotNull;\n\n/**\n * @Description: 百度嵌入操作\n **/\n@Data\n@ToString(callSuper = true)\n@EqualsAndHashCode(callSuper = true)\npublic class DefaultEmbeddingSession extends Session implements EmbeddingSession {\n\n    public DefaultEmbeddingSession(Configuration configuration) {\n        this.setConfiguration(ensureNotNull(configuration, \"configuration\"));\n        this.setBaiduApiServer(ensureNotNull(configuration.getBaiduApiServer(), \"baiduApiServer\"));\n    }\n\n    @Override\n    public EmbeddingResponse embedding(String accessToken, EmbeddingRequest embeddingRequest) {\n        EmbeddingResponse embeddingResponse = this.getBaiduApiServer().embedding(checkAccessToken(accessToken), embeddingRequest).blockingGet();\n        List<EmbeddingData> data = embeddingResponse.getData();\n        List<String> input = embeddingRequest.getInput();\n        IntStream.range(0, Math.min(data.size(), input.size()))\n                .forEach(i -> data.get(i).setContent(input.get(i)));\n        return embeddingResponse;\n    }\n\n}\n"
  },
  {
    "path": "ai-baidu/src/main/java/com/ai/baidu/achieve/defaults/session/DefaultImageSession.java",
    "content": "package com.ai.baidu.achieve.defaults.session;\n\nimport com.ai.baidu.achieve.Configuration;\nimport com.ai.baidu.achieve.standard.session.ImageSession;\nimport com.ai.baidu.endPoint.images.req.ImageRequest;\nimport com.ai.baidu.endPoint.images.resp.ImageResponse;\n\nimport static com.ai.common.utils.ValidationUtils.ensureNotNull;\n\n/**\n * @Description: 图像生成\n **/\npublic class DefaultImageSession extends Session implements ImageSession {\n\n    public DefaultImageSession(Configuration configuration) {\n        this.setConfiguration(ensureNotNull(configuration, \"configuration\"));\n        this.setBaiduApiServer(ensureNotNull(configuration.getBaiduApiServer(), \"baiduApiServer\"));\n    }\n\n    @Override\n    public ImageResponse text2image(String accessToken, ImageRequest imageRequest) {\n        String s = checkAccessToken(accessToken);\n        return this.getBaiduApiServer().text2image(s, imageRequest).blockingGet();\n    }\n}\n"
  },
  {
    "path": "ai-baidu/src/main/java/com/ai/baidu/achieve/defaults/session/Session.java",
    "content": "package com.ai.baidu.achieve.defaults.session;\n\nimport cn.hutool.core.util.StrUtil;\nimport com.ai.baidu.achieve.ApiData;\nimport com.ai.baidu.achieve.Configuration;\nimport com.ai.baidu.achieve.standard.api.BaiduApiServer;\nimport lombok.Data;\n\n\n@Data\npublic class Session {\n\n    /**\n     * 配置信息\n     */\n    private Configuration configuration;\n    /**\n     * OpenAI 接口\n     */\n    private BaiduApiServer baiduApiServer;\n\n    public String checkAccessToken(String accessToken) {\n        if (StrUtil.isEmpty(accessToken)) {\n            // 先随机获取一个apidata，看是否设置了accessToken，如果没有设置，获取token设置进去，然后返回。\n            ApiData systemApiData = configuration.getSystemApiData();\n            if (StrUtil.isNotEmpty(systemApiData.getAccessToken())) {\n                return systemApiData.getAccessToken();\n            }\n            accessToken = baiduApiServer.getAccessToken(systemApiData.getApiKey(), systemApiData.getSecretKey());\n            systemApiData.setAccessToken(accessToken);\n        }\n        return accessToken;\n    }\n\n\n}\n"
  },
  {
    "path": "ai-baidu/src/main/java/com/ai/baidu/achieve/standard/api/BaiduApiServer.java",
    "content": "package com.ai.baidu.achieve.standard.api;\n\nimport com.ai.baidu.endPoint.auth.resp.AuthResponse;\nimport com.ai.baidu.endPoint.chat.req.ChatRequest;\nimport com.ai.baidu.endPoint.chat.resp.ChatResponse;\nimport com.ai.baidu.endPoint.embedding.req.EmbeddingRequest;\nimport com.ai.baidu.endPoint.embedding.resp.EmbeddingResponse;\nimport com.ai.baidu.endPoint.images.req.ImageRequest;\nimport com.ai.baidu.endPoint.images.resp.ImageResponse;\nimport io.reactivex.Single;\nimport retrofit2.http.Body;\nimport retrofit2.http.POST;\nimport retrofit2.http.Query;\n\n/**\n * @Description: baidu API接口\n **/\npublic interface BaiduApiServer {\n\n    /**\n     * 鉴权接口\n     *\n     * @param grantType 类型\n     * @param apiKey    百度千帆大模型平台 apiKey\n     * @param secretKey 百度千帆大模型平台 secretKey\n     * @return 返回参数\n     */\n    @POST(\"/oauth/2.0/token\")\n    Single<AuthResponse> auth(@Query(\"grant_type\") String grantType, @Query(\"client_id\") String apiKey, @Query(\"client_secret\") String secretKey);\n\n    /**\n     * 获取鉴权的 accessToken\n     *\n     * @param apiKey    百度千帆大模型平台 apiKey\n     * @param secretKey 百度千帆大模型平台 secretKey\n     * @return 鉴权的 accessToken\n     */\n    default String getAccessToken(String apiKey, String secretKey) {\n        return getAccessToken(\"client_credentials\", apiKey, secretKey);\n    }\n\n    /**\n     * 获取鉴权的 accessToken\n     *\n     * @param grantType 类型\n     * @param apiKey    百度千帆大模型平台 apiKey\n     * @param secretKey 百度千帆大模型平台 secretKey\n     * @return 鉴权的 accessToken\n     */\n    default String getAccessToken(String grantType, String apiKey, String secretKey) {\n        return this.auth(grantType, apiKey, secretKey).blockingGet().getAccessToken();\n    }\n\n    /**\n     * 聊天接口\n     *\n     * @param accessToken 鉴权的 accessToken\n     * @param chatRequest 请求参数\n     * @return 返回数据\n     */\n    @POST(\"/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/completions_pro\")\n    Single<ChatResponse> chat(@Query(\"access_token\") String accessToken, @Body ChatRequest chatRequest);\n\n    /**\n     * embedding 接口\n     *\n     * @param accessToken      鉴权的 accessToken\n     * @param embeddingRequest 请求参数\n     * @return 返回数据\n     */\n    @POST(\"/rpc/2.0/ai_custom/v1/wenxinworkshop/embeddings/embedding-v1\")\n    Single<EmbeddingResponse> embedding(@Query(\"access_token\") String accessToken, @Body EmbeddingRequest embeddingRequest);\n\n    /**\n     * 文生图接口\n     *\n     * @param accessToken  鉴权的 accessToken\n     * @param imageRequest 请求参数\n     * @return 返回数据\n     */\n    @POST(\"/rpc/2.0/ai_custom/v1/wenxinworkshop/text2image/sd_xl\")\n    Single<ImageResponse> text2image(@Query(\"access_token\") String accessToken, @Body ImageRequest imageRequest);\n\n}\n"
  },
  {
    "path": "ai-baidu/src/main/java/com/ai/baidu/achieve/standard/session/AggregationSession.java",
    "content": "package com.ai.baidu.achieve.standard.session;\n\n/**\n * @Description: 聚合各大场景的session\n **/\npublic interface AggregationSession {\n\n    /**\n     * 获取对话会话窗口\n     */\n    ChatSession getChatSession();\n\n    /**\n     * 获取嵌入会话窗口\n     */\n    EmbeddingSession getEmbeddingSession();\n\n    /**\n     * 获取文生图会话窗口\n     */\n    ImageSession getImageSession();\n\n}\n"
  },
  {
    "path": "ai-baidu/src/main/java/com/ai/baidu/achieve/standard/session/ChatSession.java",
    "content": "package com.ai.baidu.achieve.standard.session;\n\nimport com.ai.baidu.endPoint.chat.req.ChatRequest;\nimport com.ai.baidu.endPoint.chat.resp.ChatResponse;\nimport okhttp3.sse.EventSource;\nimport okhttp3.sse.EventSourceListener;\n\n/**\n * @Description: baidu 聊天会话窗口\n **/\npublic interface ChatSession {\n\n    default ChatResponse chat(ChatRequest chatRequest) {\n        return chat(null, chatRequest);\n    }\n\n    /**\n     * 聊天接口，如果传入的 accessToken 为空，会自动根据用户设置的 key 按照 key 的获取策略进行自动鉴权。\n     *\n     * @param accessToken 鉴权的 accessToken\n     * @param chatRequest 请求参数\n     * @return 返回参数\n     */\n    ChatResponse chat(String accessToken, ChatRequest chatRequest);\n\n    default EventSource chat(ChatRequest chatRequest, EventSourceListener eventSourceListener) {\n        return chat(null, chatRequest, eventSourceListener);\n    }\n\n    /**\n     * 聊天接口流式返回\n     *\n     * @param accessToken         鉴权的 accessToken\n     * @param chatRequest         请求参数\n     * @param eventSourceListener 事件监听者\n     * @return 事件源\n     */\n    EventSource chat(String accessToken, ChatRequest chatRequest, EventSourceListener eventSourceListener);\n\n}\n"
  },
  {
    "path": "ai-baidu/src/main/java/com/ai/baidu/achieve/standard/session/EmbeddingSession.java",
    "content": "package com.ai.baidu.achieve.standard.session;\n\nimport com.ai.baidu.endPoint.embedding.req.EmbeddingRequest;\nimport com.ai.baidu.endPoint.embedding.resp.EmbeddingResponse;\n\n/**\n * @Description: 嵌入会话窗口\n **/\npublic interface EmbeddingSession {\n\n    default EmbeddingResponse embedding(EmbeddingRequest embeddingRequest) {\n        return embedding(null, embeddingRequest);\n    }\n\n    /**\n     * 嵌入\n     *\n     * @param accessToken      鉴权的 accessToken\n     * @param embeddingRequest 请求参数\n     * @return 请求结果\n     */\n    EmbeddingResponse embedding(String accessToken, EmbeddingRequest embeddingRequest);\n\n}\n"
  },
  {
    "path": "ai-baidu/src/main/java/com/ai/baidu/achieve/standard/session/ImageSession.java",
    "content": "package com.ai.baidu.achieve.standard.session;\n\nimport com.ai.baidu.endPoint.images.req.ImageRequest;\nimport com.ai.baidu.endPoint.images.resp.ImageResponse;\n\n/**\n * @Description: 图片会话窗口\n **/\npublic interface ImageSession {\n\n    /**\n     * 文生图接口\n     *\n     * @param accessToken  鉴权的 accessToken\n     * @param imageRequest 请求参数\n     * @return 请求结果\n     */\n    ImageResponse text2image(String accessToken, ImageRequest imageRequest);\n\n    default ImageResponse text2image(ImageRequest imageRequest) {\n        return text2image(null, imageRequest);\n    }\n\n}\n"
  },
  {
    "path": "ai-baidu/src/main/java/com/ai/baidu/common/ApiUrl.java",
    "content": "package com.ai.baidu.common;\n\nimport lombok.AllArgsConstructor;\nimport lombok.Getter;\n\n/**\n * 各接口API路径\n */\n@Getter\n@AllArgsConstructor\npublic enum ApiUrl {\n\n    ERNIE_Bot_4_0(\"/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/completions_pro\"),\n    ;\n\n    private String url;\n}\n"
  },
  {
    "path": "ai-baidu/src/main/java/com/ai/baidu/common/Usage.java",
    "content": "package com.ai.baidu.common;\n\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport com.fasterxml.jackson.annotation.JsonInclude;\nimport com.fasterxml.jackson.annotation.JsonProperty;\nimport lombok.AllArgsConstructor;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\n\n@Data\n@NoArgsConstructor\n@AllArgsConstructor\n@JsonIgnoreProperties(ignoreUnknown = true)\n@JsonInclude(JsonInclude.Include.NON_NULL)\npublic class Usage {\n\n    /**\n     * 问题tokens数\n     */\n    @JsonProperty(\"prompt_tokens\")\n    private Integer promptTokens;\n\n    /**\n     * 回答tokens数\n     */\n    @JsonProperty(\"completion_tokens\")\n    private Integer completionTokens;\n\n    /**\n     * tokens总数\n     */\n    @JsonProperty(\"total_tokens\")\n    private Integer totalTokens;\n\n}\n"
  },
  {
    "path": "ai-baidu/src/main/java/com/ai/baidu/endPoint/auth/resp/AuthResponse.java",
    "content": "package com.ai.baidu.endPoint.auth.resp;\n\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport com.fasterxml.jackson.annotation.JsonInclude;\nimport com.fasterxml.jackson.annotation.JsonProperty;\nimport lombok.AllArgsConstructor;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\n\n@Data\n@NoArgsConstructor\n@AllArgsConstructor\n@JsonIgnoreProperties(ignoreUnknown = true)\n@JsonInclude(JsonInclude.Include.NON_NULL)\npublic class AuthResponse {\n\n    @JsonProperty(\"refresh_token\")\n    private String refreshToken;\n\n    /**\n     * 有效期，Access Token的有效期。\n     * 说明：单位是秒，有效期30天\n     */\n    @JsonProperty(\"expires_in\")\n    private Integer expiresIn;\n\n    @JsonProperty(\"session_key\")\n    private String sessionKey;\n\n    /**\n     * 访问凭证\n     */\n    @JsonProperty(\"access_token\")\n    private String accessToken;\n\n    private String scope;\n\n    @JsonProperty(\"session_secret\")\n    private String sessionSecret;\n\n    /**\n     * 错误码\n     * 说明：响应失败时返回该字段，成功时不返回\n     */\n    private String error;\n\n    /**\n     * 错误描述信息，帮助理解和解决发生的错误\n     * 说明：响应失败时返回该字段，成功时不返回\n     */\n    @JsonProperty(\"error_description\")\n    private String errorDescription;\n\n}\n"
  },
  {
    "path": "ai-baidu/src/main/java/com/ai/baidu/endPoint/chat/Message.java",
    "content": "package com.ai.baidu.endPoint.chat;\n\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport com.fasterxml.jackson.annotation.JsonInclude;\nimport lombok.*;\n\n@Data\n@Builder\n@NoArgsConstructor\n@AllArgsConstructor\n@JsonIgnoreProperties(ignoreUnknown = true)\n@JsonInclude(JsonInclude.Include.NON_NULL)\npublic class Message {\n\n    /**\n     * 当前支持以下：\n     * user: 表示用户\n     * assistant: 表示对话助手\n     */\n    private String role;\n\n    /**\n     * 对话内容\n     */\n    private String content;\n\n    /**\n     * message作者\n     */\n    private String name;\n\n    public static Message baseBuild(Role role, String content) {\n        return Message.builder().role(role.getRoleName()).content(content).build();\n    }\n\n    @Getter\n    @AllArgsConstructor\n    public enum Role {\n\n        USER(\"user\"),\n        ASSISTANT(\"assistant\"),\n        ;\n\n        private String RoleName;\n    }\n\n}\n"
  },
  {
    "path": "ai-baidu/src/main/java/com/ai/baidu/endPoint/chat/SearchResult.java",
    "content": "package com.ai.baidu.endPoint.chat;\n\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport com.fasterxml.jackson.annotation.JsonInclude;\nimport lombok.AllArgsConstructor;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\n\n@Data\n@NoArgsConstructor\n@AllArgsConstructor\n@JsonIgnoreProperties(ignoreUnknown = true)\n@JsonInclude(JsonInclude.Include.NON_NULL)\npublic class SearchResult {\n\n    /**\n     * 序号\n     */\n    private Integer index;\n\n    /**\n     * 搜索结果URL\n     */\n    private String url;\n\n    /**\n     * 搜索结果标题\n     */\n    private String title;\n\n}\n"
  },
  {
    "path": "ai-baidu/src/main/java/com/ai/baidu/endPoint/chat/req/ChatRequest.java",
    "content": "package com.ai.baidu.endPoint.chat.req;\n\nimport com.ai.baidu.endPoint.chat.Message;\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport com.fasterxml.jackson.annotation.JsonInclude;\nimport com.fasterxml.jackson.annotation.JsonProperty;\nimport lombok.AllArgsConstructor;\nimport lombok.Builder;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\n\nimport java.io.Serializable;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\n\n/**\n * 对话聊天参数，官方文档链接：https://cloud.baidu.com/doc/WENXINWORKSHOP/s/clntwmv7t#body%E5%8F%82%E6%95%B0\n */\n@Data\n@Builder\n@NoArgsConstructor\n@AllArgsConstructor\n@JsonIgnoreProperties(ignoreUnknown = true)\n@JsonInclude(JsonInclude.Include.NON_NULL)\npublic class ChatRequest implements Serializable {\n\n    /**\n     * 必传\n     * （1）messages成员不能为空，1个成员表示单轮对话，多个成员表示多轮对话，例如：\n     * 3个成员示例，\"messages\": [ {\"role\": \"user\",\"content\": \"你好\"},{\"role\":\"assistant\",\"content\":\"需要什么帮助\"},{\"role\":\"user\",\"content\":\"自我介绍下\"}]\n     * （2）最后一个message为当前请求的信息，前面的message为历史对话信息\n     * （3）成员数目必须为奇数，成员中message的role值说明如下：奇数位messsage的role值必须为user，偶数位message的role值为assistant\n     * （4）message中的content总长度和system字段总内容不能超过20000个字符，且不能超过5120 tokens\n     */\n    private List<Message> messages;\n\n    /**\n     * （1）较高的数值会使输出更加随机，而较低的数值会使其更加集中和确定\n     * （2）默认0.8，范围 (0, 1.0]，不能为0\n     */\n    private Double temperature;\n\n    /**\n     * （1）影响输出文本的多样性，取值越大，生成文本的多样性越强\n     * （2）默认0.8，取值范围 [0, 1.0]\n     */\n    @JsonProperty(\"top_p\")\n    private Double topP;\n\n    /**\n     * 通过对已生成的token增加惩罚，减少重复生成的现象。说明：\n     * （1）值越大表示惩罚越大\n     * （2）默认1.0，取值范围：[1.0, 2.0]\n     */\n    @JsonProperty(\"penalty_score\")\n    private Double penaltyScore;\n\n    /**\n     * 是否以流式接口的形式返回数据，默认false\n     */\n    private Boolean stream;\n\n    /**\n     * 模型人设，主要用于人设设定，例如，你是xxx公司制作的AI助手，说明：\n     * （1）长度限制，最后一个message的content长度（即此轮对话的问题）和system字段总内容不能超过20000个字符，且不能超过5120 tokens\n     */\n    private String system;\n\n    /**\n     * 生成停止标识，当模型生成结果以stop中某个元素结尾时，停止文本生成。说明：\n     * （1）每个元素长度不超过20字符\n     * （2）最多4个元素\n     */\n    private List<String> stop;\n\n    /**\n     * 否强制关闭实时搜索功能，默认false，表示不关闭\n     */\n    @JsonProperty(\"disable_search\")\n    private Boolean disableSearch;\n\n    /**\n     * 是否开启上角标返回，说明：\n     * （1）开启后，有概率触发搜索溯源信息search_info，search_info内容见响应参数介绍\n     * （2）默认false，不开启\n     */\n    @JsonProperty(\"enable_citation\")\n    private Boolean enableCitation;\n\n    /**\n     * 指定模型最大输出token数，范围[2, 2048]\n     */\n    @JsonProperty(\"max_output_tokens\")\n    private Integer maxOutputTokens;\n\n    /**\n     * 指定响应内容的格式，说明：\n     * （1）可选值：\n     * json_object：以json格式返回，可能出现不满足效果情况\n     * text：以文本格式返回\n     * （2）如果不填写参数response_format值，默认为text\n     */\n    @JsonProperty(\"response_format\")\n    private String responseFormat;\n\n    /**\n     * 表示最终用户的唯一标识符\n     */\n    @JsonProperty(\"user_id\")\n    private String userId;\n\n    public static ChatRequest baseBuild(Message.Role role, String content) {\n        return ChatRequest.builder()\n                .messages(new ArrayList<>(Arrays.asList(Message.baseBuild(role, content))))\n                .build();\n    }\n\n}\n"
  },
  {
    "path": "ai-baidu/src/main/java/com/ai/baidu/endPoint/chat/resp/ChatResponse.java",
    "content": "package com.ai.baidu.endPoint.chat.resp;\n\nimport com.ai.baidu.common.Usage;\nimport com.ai.baidu.endPoint.chat.SearchResult;\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport com.fasterxml.jackson.annotation.JsonInclude;\nimport com.fasterxml.jackson.annotation.JsonProperty;\nimport lombok.AllArgsConstructor;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\n\nimport java.io.Serializable;\nimport java.util.List;\n\n@Data\n@NoArgsConstructor\n@AllArgsConstructor\n@JsonIgnoreProperties(ignoreUnknown = true)\n@JsonInclude(JsonInclude.Include.NON_NULL)\npublic class ChatResponse implements Serializable {\n\n    /**\n     * 本轮对话的id\n     */\n    private String id;\n\n    /**\n     * 回包类型\n     * chat.completion：多轮对话返回\n     */\n    private String Object;\n\n    /**\n     * 时间戳\n     */\n    private Integer created;\n\n    /**\n     * 表示当前子句的序号。只有在流式接口模式下会返回该字段\n     */\n    @JsonProperty(\"sentence_id\")\n    private Integer sentenceId;\n\n    /**\n     * 表示当前子句是否是最后一句。只有在流式接口模式下会返回该字段\n     */\n    @JsonProperty(\"is_end\")\n    private Boolean isEnd;\n\n    /**\n     * 当前生成的结果是否被截断\n     */\n    @JsonProperty(\"is_truncated\")\n    private Boolean isTruncated;\n\n    /**\n     * 输出内容标识，说明：\n     * · normal：输出内容完全由大模型生成，未触发截断、替换\n     * · stop：输出结果命中入参stop中指定的字段后被截断\n     * · length：达到了最大的token数，根据EB返回结果is_truncated来截断\n     * · content_filter：输出内容被截断、兜底、替换为**等\n     */\n    @JsonProperty(\"finish_reason\")\n    private String finishReason;\n\n    /**\n     * 搜索数据，当请求参数enable_citation为true并且触发搜索时，会返回该字段\n     */\n    @JsonProperty(\"search_info\")\n    private List<SearchResult> searchInfo;\n\n    /**\n     * 对话返回结果\n     */\n    private String result;\n\n    /**\n     * 表示用户输入是否存在安全，是否关闭当前会话，清理历史会话信息\n     * true：是，表示用户输入存在安全风险，建议关闭当前会话，清理历史会话信息\n     * false：否，表示用户输入无安全风险\n     */\n    @JsonProperty(\"need_clear_history\")\n    private Boolean needClearHistory;\n\n    /**\n     * 说明：\n     * 0：正常返回\n     * 其他：非正常\n     */\n    private Integer flag;\n\n    /**\n     * 当need_clear_history为true时，此字段会告知第几轮对话有敏感信息，如果是当前问题，ban_round=-1\n     */\n    @JsonProperty(\"ban_round\")\n    private Integer banRound;\n\n    /**\n     * token统计信息\n     */\n    private Usage usage;\n\n\n}\n"
  },
  {
    "path": "ai-baidu/src/main/java/com/ai/baidu/endPoint/embedding/EmbeddingData.java",
    "content": "package com.ai.baidu.endPoint.embedding;\n\nimport com.fasterxml.jackson.annotation.JsonIgnore;\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport com.fasterxml.jackson.annotation.JsonInclude;\nimport lombok.AllArgsConstructor;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\n\n@Data\n@NoArgsConstructor\n@AllArgsConstructor\n@JsonIgnoreProperties(ignoreUnknown = true)\n@JsonInclude(JsonInclude.Include.NON_NULL)\npublic class EmbeddingData {\n\n    /**\n     * 固定值\"embedding\"\n     */\n    private String object;\n\n    /**\n     * embedding 内容\n     */\n    private double[] embedding;\n\n    /**\n     * 序号\n     */\n    private Integer index;\n\n    /**\n     * 原文\n     */\n    @JsonIgnore\n    private String content;\n\n}\n"
  },
  {
    "path": "ai-baidu/src/main/java/com/ai/baidu/endPoint/embedding/req/EmbeddingRequest.java",
    "content": "package com.ai.baidu.endPoint.embedding.req;\n\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport com.fasterxml.jackson.annotation.JsonInclude;\nimport com.fasterxml.jackson.annotation.JsonProperty;\nimport lombok.AllArgsConstructor;\nimport lombok.Builder;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\n\nimport java.util.List;\n\n/**\n * 嵌入请求体，官方文档链接：https://cloud.baidu.com/doc/WENXINWORKSHOP/s/alj562vvu\n */\n@Data\n@Builder\n@NoArgsConstructor\n@AllArgsConstructor\n@JsonIgnoreProperties(ignoreUnknown = true)\n@JsonInclude(JsonInclude.Include.NON_NULL)\npublic class EmbeddingRequest {\n\n    /**\n     * 必传\n     * 输入文本以获取embeddings。说明：\n     * （1）不能为空List，List的每个成员不能为空字符串\n     * （2）文本数量不超过16\n     * （3）每个文本token数不超过384且长度不超过1000个字符\n     */\n    private List<String> input;\n\n    /**\n     * 表示最终用户的唯一标识符\n     */\n    @JsonProperty(\"user_id\")\n    private String userId;\n\n    public static EmbeddingRequest baseBuild(List<String> input) {\n        return EmbeddingRequest.builder().input(input).build();\n    }\n\n}\n"
  },
  {
    "path": "ai-baidu/src/main/java/com/ai/baidu/endPoint/embedding/resp/EmbeddingResponse.java",
    "content": "package com.ai.baidu.endPoint.embedding.resp;\n\nimport com.ai.baidu.common.Usage;\nimport com.ai.baidu.endPoint.embedding.EmbeddingData;\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport com.fasterxml.jackson.annotation.JsonInclude;\nimport lombok.AllArgsConstructor;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\n\nimport java.util.List;\n\n/**\n * 嵌入返回体，官方文档链接：https://cloud.baidu.com/doc/WENXINWORKSHOP/s/alj562vvu\n */\n@Data\n@NoArgsConstructor\n@AllArgsConstructor\n@JsonIgnoreProperties(ignoreUnknown = true)\n@JsonInclude(JsonInclude.Include.NON_NULL)\npublic class EmbeddingResponse {\n\n    /**\n     * 本轮对话的id\n     */\n    private String id;\n\n    /**\n     * 回包类型，固定值“embedding_list”\n     */\n    private String Object;\n\n    /**\n     * 时间戳\n     */\n    private Integer created;\n\n    /**\n     * embedding信息，data成员数和文本数量保持一致\n     */\n    private List<EmbeddingData> data;\n\n    /**\n     * token统计信息，token数 = 汉字数+单词数*1.3 （仅为估算逻辑）\n     */\n    private Usage usage;\n\n\n}\n"
  },
  {
    "path": "ai-baidu/src/main/java/com/ai/baidu/endPoint/images/ImageData.java",
    "content": "package com.ai.baidu.endPoint.images;\n\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport com.fasterxml.jackson.annotation.JsonInclude;\nimport com.fasterxml.jackson.annotation.JsonProperty;\nimport lombok.AllArgsConstructor;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\n\n@Data\n@NoArgsConstructor\n@AllArgsConstructor\n@JsonIgnoreProperties(ignoreUnknown = true)\n@JsonInclude(JsonInclude.Include.NON_NULL)\npublic class ImageData {\n\n    /**\n     * 固定值\"image\"\n     */\n    private String object;\n\n    /**\n     * 图片base64编码内容\n     */\n    @JsonProperty(\"b64_image\")\n    private String b64Image;\n\n    /**\n     * 序号\n     */\n    private Integer index;\n\n}\n"
  },
  {
    "path": "ai-baidu/src/main/java/com/ai/baidu/endPoint/images/req/ImageRequest.java",
    "content": "package com.ai.baidu.endPoint.images.req;\n\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport com.fasterxml.jackson.annotation.JsonInclude;\nimport com.fasterxml.jackson.annotation.JsonProperty;\nimport lombok.*;\n\nimport java.io.Serializable;\n\n/**\n * 文生图，官方文档路径：https://cloud.baidu.com/doc/WENXINWORKSHOP/s/Klkqubb9w#header%E5%8F%82%E6%95%B0\n */\n@Data\n@Builder\n@NoArgsConstructor\n@AllArgsConstructor\n@JsonIgnoreProperties(ignoreUnknown = true)\n@JsonInclude(JsonInclude.Include.NON_NULL)\npublic class ImageRequest implements Serializable {\n\n    /**\n     * 必传\n     * 提示词，即用户希望图片包含的元素。长度限制为1024字符，建议中文或者英文单词总数量不超过150个\n     */\n    private String prompt;\n\n    /**\n     * 反向提示词，即用户希望图片不包含的元素。长度限制为1024字符，建议中文或者英文单词总数量不超过150个\n     */\n    @JsonProperty(\"negative_prompt\")\n    private String negativePrompt;\n\n    /**\n     * 生成图片长宽，默认值 1024x1024，取值范围如下：\n     * [\"768x768\", \"768x1024\", \"1024x768\", \"576x1024\", \"1024x576\", \"1024x1024\"]\n     */\n    private String size;\n\n    /**\n     * 生成图片数量，说明：\n     * · 默认值为1\n     * · 取值范围为1-4\n     * · 单次生成的图片较多及请求较频繁可能导致请求超时\n     */\n    private Integer n;\n\n    /**\n     * 迭代轮次，说明：\n     * · 默认值为20\n     * · 取值范围为10-50\n     */\n    private Integer steps;\n\n    /**\n     * 采样方式，默认值：Euler a，可选值如下(释义参考)：\n     * · Euler\n     * · Euler a\n     * · DPM++ 2M\n     * · DPM++ 2M Karras\n     * · LMS Karras\n     * · DPM++ SDE\n     * · DPM++ SDE Karras\n     * · DPM2 a Karras\n     * · Heun\n     * · DPM++ 2M SDE\n     * · DPM++ 2M SDE Karras\n     * · DPM2\n     * · DPM2 Karras\n     * · DPM2 a\n     * · LMS\n     */\n    @JsonProperty(\"sampler_index\")\n    private String samplerIndex;\n\n    /**\n     * 随机种子，说明：\n     * · 不设置时，自动生成随机数\n     * · 取值范围 [0, 4294967295]\n     */\n    private Integer seed;\n\n    /**\n     * 提示词相关性，说明：默认值为5，取值范围0-30\n     */\n    @JsonProperty(\"cfg_scale\")\n    private Double cfgScale;\n\n    /**\n     * 生成风格。说明：\n     * （1）可选值：\n     * · Base：基础风格\n     * · 3D Model：3D模型\n     * · Analog Film：模拟胶片\n     * · Anime：动漫\n     * · Cinematic：电影\n     * · Comic Book：漫画\n     * · Craft Clay：工艺黏土\n     * · Digital Art：数字艺术\n     * · Enhance：增强\n     * · Fantasy Art：幻想艺术\n     * · lsometric：等距风格\n     * · Line Art：线条艺术\n     * · Lowpoly：低多边形\n     * · Neonpunk：霓虹朋克\n     * · Origami：折纸\n     * · Photographic：摄影\n     * · Pixel Art：像素艺术\n     * · Texture：纹理\n     * （2）默认值为Base\n     */\n    private String style;\n\n    /**\n     * 表示最终用户的唯一标识符\n     */\n    @JsonProperty(\"user_id\")\n    private String userId;\n\n    public static ImageRequest baseBuild(String prompt) {\n        return ImageRequest.builder().prompt(prompt).build();\n    }\n\n    @Getter\n    @AllArgsConstructor\n    public enum ImgSize {\n        SIZE_768_768(\"768x768\"),\n        SIZE_768_1024(\"768x1024\"),\n        SIZE_576_1024(\"576x1024\"),\n        SIZE_1024_768(\"1024x768\"),\n        SIZE_1024_576(\"1024x576\"),\n        SIZE_1024_1024(\"1024x1024\"),\n        ;\n        private String size;\n    }\n\n    @Getter\n    @AllArgsConstructor\n    public enum ImgStyle {\n        Base(\"Base\"),\n        model3D(\"3D Model\"),\n        AnalogFilm(\"Analog Film\"),\n        Anime(\"Anime\"),\n        Cinematic(\"Cinematic\"),\n        ComicBook(\"Comic Book\"),\n        CraftClay(\"Craft Clay\"),\n        DigitalArt(\"Digital Art\"),\n        Enhance(\"Enhance\"),\n        FantasyArt(\"Fantasy Art\"),\n        lsometric(\"lsometric\"),\n        LineArt(\"Line Art\"),\n        Lowpoly(\"Lowpoly\"),\n        Neonpunk(\"Neonpunk\"),\n        Origami(\"Origami\"),\n        Photographic(\"Photographic\"),\n        PixelArt(\"Pixel Art\"),\n        Texture(\"Texture\"),\n        ;\n        private String style;\n    }\n\n}\n"
  },
  {
    "path": "ai-baidu/src/main/java/com/ai/baidu/endPoint/images/resp/ImageResponse.java",
    "content": "package com.ai.baidu.endPoint.images.resp;\n\nimport com.ai.baidu.common.Usage;\nimport com.ai.baidu.endPoint.images.ImageData;\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport com.fasterxml.jackson.annotation.JsonInclude;\nimport lombok.AllArgsConstructor;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\n\nimport java.io.Serializable;\nimport java.util.List;\n\n@Data\n@NoArgsConstructor\n@AllArgsConstructor\n@JsonIgnoreProperties(ignoreUnknown = true)\n@JsonInclude(JsonInclude.Include.NON_NULL)\npublic class ImageResponse implements Serializable {\n\n    /**\n     * 请求的id\n     */\n    private String id;\n\n    /**\n     * 回包类型。image：图像生成返回\n     */\n    private String object;\n\n    /**\n     * 时间戳\n     */\n    private Integer created;\n\n    /**\n     * 生成图片结果\n     */\n    private List<ImageData> data;\n\n    /**\n     * token统计信息，token数 = 汉字数+单词数*1.3 （仅为估算逻辑）\n     */\n    private Usage usage;\n\n}\n"
  },
  {
    "path": "ai-baidu/src/main/java/com/ai/baidu/interceptor/ResponseInterceptor.java",
    "content": "package com.ai.baidu.interceptor;\n\nimport lombok.extern.slf4j.Slf4j;\nimport okhttp3.Interceptor;\nimport okhttp3.Request;\nimport okhttp3.Response;\n\nimport java.io.IOException;\n\n/**\n * 返回信息拦截器\n */\n@Slf4j\npublic class ResponseInterceptor implements Interceptor {\n    @Override\n    public Response intercept(Chain chain) throws IOException {\n        // 1. 获取 req 和 resp\n        Request original = chain.request();\n        Response response = chain.proceed(original);\n        if (!response.isSuccessful() && response.body() != null) {\n            log.error(\"--------> 请求异常：{}\", response.body().string());\n        }\n        return response;\n    }\n}\n"
  },
  {
    "path": "ai-baidu/src/test/java/com/ai/baidu/ChatApiTest.java",
    "content": "package com.ai.baidu;\n\nimport com.ai.baidu.achieve.ApiData;\nimport com.ai.baidu.achieve.Configuration;\nimport com.ai.baidu.achieve.defaults.DefaultBaiduSessionFactory;\nimport com.ai.baidu.achieve.standard.session.AggregationSession;\nimport com.ai.baidu.endPoint.chat.Message;\nimport com.ai.baidu.endPoint.chat.req.ChatRequest;\nimport com.ai.baidu.endPoint.chat.resp.ChatResponse;\nimport com.ai.core.strategy.impl.FirstKeyStrategy;\nimport lombok.extern.slf4j.Slf4j;\nimport okhttp3.Response;\nimport okhttp3.sse.EventSource;\nimport okhttp3.sse.EventSourceListener;\nimport org.jetbrains.annotations.NotNull;\nimport org.jetbrains.annotations.Nullable;\nimport org.junit.Before;\nimport org.junit.Test;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.concurrent.CountDownLatch;\n\n/**\n * @Description: 测试聊天接口相关接口功能\n */\n@Slf4j\npublic class ChatApiTest {\n\n    private AggregationSession aggregationSession;\n\n    private Configuration configuration;\n\n    @Before\n    public void test_BaiduSessionFactory() {\n        // 1. 创建配置类\n        this.configuration = new Configuration();\n        // 2. 设置请求地址，若有代理商或者代理服务器，可填写为代理服务器的请求路径\n        configuration.setApiHost(\"https://aip.baidubce.com\");\n        // 3. 设置鉴权所需的API Key,可设置多个。\n        ApiData apiData = ApiData.builder()\n                .apiKey(\"**************************\")\n                .secretKey(\"**************************\")\n                .appId(\"**************************\")\n                .build();\n        configuration.setKeyList(Arrays.asList(apiData));\n        // 4. 设置请求时 key 的使用策略，默认实现了：随机获取 和 固定第一个Key 两种方式。\n        configuration.setKeyStrategy(new FirstKeyStrategy<ApiData>());\n//        configuration.setKeyStrategy(new RandomKeyStrategy<ApiData>());\n        // 5. 设置代理，若不需要可不设置\n//        configuration.setProxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress(\"127.0.0.1\", 7890)));\n        // 6. 创建 session 工厂，制造不同场景的 session\n        DefaultBaiduSessionFactory factory = new DefaultBaiduSessionFactory(configuration);\n        this.aggregationSession = factory.openAggregationSession();\n    }\n\n    /**\n     * 测试鉴权接口\n     */\n    @Test\n    public void test_auth() {\n        // 获取用户配置的ApiData\n        ApiData systemApiData = configuration.getSystemApiData();\n        // 鉴权\n        String accessToken = configuration.getBaiduApiServer().getAccessToken(systemApiData.getApiKey(), systemApiData.getSecretKey());\n        System.out.println(accessToken);\n    }\n\n    /**\n     * 测试聊天功能\n     */\n    @Test\n    public void test_chat() {\n        // 发起聊天，chat接口如果传入的 accessToken 为空，会自动根据用户设置的信息进行鉴权\n        ChatResponse response = aggregationSession\n                .getChatSession()// 获取 chatSession\n                .chat(null, ChatRequest.baseBuild(Message.Role.USER, \"Introduce the city Beijing\"));// 构造一个基础的聊天请求体\n        System.out.println(response.getResult());\n        System.out.println(response.getUsage());\n    }\n\n    @Test\n    public void test_chat_multiple() {\n        // 构造对话\n        Message msg1 = Message.baseBuild(Message.Role.USER, \"请记住我的名字叫小明\");\n        Message msg2 = Message.baseBuild(Message.Role.ASSISTANT, \"好的\");\n        Message msg3 = Message.baseBuild(Message.Role.USER, \"我的名字叫什么？\");\n        ArrayList<Message> messages = new ArrayList<>();\n        messages.add(msg1);\n        messages.add(msg2);\n        messages.add(msg3);\n        // 构造参数\n        ChatRequest request = ChatRequest.builder().messages(messages).build();\n        // 发起请求\n        ChatResponse response = aggregationSession.getChatSession().chat(null, request);\n        System.out.println(response.getResult());\n        System.out.println(response.getUsage());\n    }\n\n    @Test\n    public void test_chat_stream() throws InterruptedException {\n        ChatRequest request = ChatRequest.baseBuild(Message.Role.USER, \"你能讲一个笑话吗？\");\n        request.setStream(true);// 设置流式返回\n        // 发起聊天，chat接口如果传入的 accessToken 为空，会自动根据用户设置的信息进行鉴权\n        aggregationSession.getChatSession()// 获取 chatSession\n                .chat(null, request, new EventSourceListener() {\n                    @Override\n                    public void onEvent(@NotNull EventSource eventSource, @Nullable String id, @Nullable String type, @NotNull String data) {\n                        log.info(\"测试结果 id:{} type:{} data:{}\", id, type, data);\n                    }\n\n                    @Override\n                    public void onFailure(@NotNull EventSource eventSource, @Nullable Throwable t, @Nullable Response response) {\n                        log.error(\"失败 code:{} message:{}\", response.code(), response.message());\n                    }\n                });\n        new CountDownLatch(1).await();\n    }\n\n}\n"
  },
  {
    "path": "ai-baidu/src/test/java/com/ai/baidu/EmbeddingApiTest.java",
    "content": "package com.ai.baidu;\n\nimport com.ai.baidu.achieve.ApiData;\nimport com.ai.baidu.achieve.Configuration;\nimport com.ai.baidu.achieve.defaults.DefaultBaiduSessionFactory;\nimport com.ai.baidu.achieve.standard.session.AggregationSession;\nimport com.ai.baidu.endPoint.embedding.EmbeddingData;\nimport com.ai.baidu.endPoint.embedding.req.EmbeddingRequest;\nimport com.ai.baidu.endPoint.embedding.resp.EmbeddingResponse;\nimport com.ai.core.strategy.impl.FirstKeyStrategy;\nimport org.junit.Before;\nimport org.junit.Test;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\n\n/**\n * @Description: 嵌入相关功能点测试\n **/\npublic class EmbeddingApiTest {\n\n    private AggregationSession aggregationSession;\n\n    private Configuration configuration;\n\n    @Before\n    public void test_BaiduSessionFactory() {\n        // 1. 创建配置类\n        this.configuration = new Configuration();\n        // 2. 设置请求地址，若有代理商或者代理服务器，可填写为代理服务器的请求路径\n        configuration.setApiHost(\"https://aip.baidubce.com\");\n        // 3. 设置鉴权所需的API Key,可设置多个。\n        ApiData apiData = ApiData.builder()\n                .apiKey(\"**************************\")\n                .secretKey(\"**************************\")\n                .appId(\"**************************\")\n                .build();\n        configuration.setKeyList(Arrays.asList(apiData));\n        // 4. 设置请求时 key 的使用策略，默认实现了：随机获取 和 固定第一个Key 两种方式。\n        configuration.setKeyStrategy(new FirstKeyStrategy<ApiData>());\n//        configuration.setKeyStrategy(new RandomKeyStrategy<ApiData>());\n        // 5. 设置代理，若不需要可不设置\n//        configuration.setProxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress(\"127.0.0.1\", 7890)));\n        // 6. 创建 session 工厂，制造不同场景的 session\n        DefaultBaiduSessionFactory factory = new DefaultBaiduSessionFactory(configuration);\n        this.aggregationSession = factory.openAggregationSession();\n    }\n\n    /**\n     * 测试嵌入接口\n     */\n    @Test\n    public void test_embedding() {\n        List<String> input = new ArrayList<>();\n        input.add(\"你好\");\n        input.add(\"世界\");\n        EmbeddingRequest embeddingRequest = EmbeddingRequest.baseBuild(input);\n        EmbeddingResponse embeddingResponse = aggregationSession.getEmbeddingSession().embedding(null, embeddingRequest);\n        for (EmbeddingData e : embeddingResponse.getData()) {\n            System.out.println(e);\n        }\n    }\n\n}\n"
  },
  {
    "path": "ai-baidu/src/test/java/com/ai/baidu/ImageApiTest.java",
    "content": "package com.ai.baidu;\n\n\nimport com.ai.baidu.achieve.ApiData;\nimport com.ai.baidu.achieve.Configuration;\nimport com.ai.baidu.achieve.defaults.DefaultBaiduSessionFactory;\nimport com.ai.baidu.achieve.standard.session.AggregationSession;\nimport com.ai.baidu.endPoint.images.ImageData;\nimport com.ai.baidu.endPoint.images.req.ImageRequest;\nimport com.ai.baidu.endPoint.images.resp.ImageResponse;\nimport com.ai.common.utils.ImageUtils;\nimport com.ai.core.strategy.impl.FirstKeyStrategy;\nimport org.junit.Before;\nimport org.junit.Test;\n\nimport java.util.Arrays;\nimport java.util.List;\n\n/**\n * @Description: 图片相关功能点测试\n **/\npublic class ImageApiTest {\n\n    private AggregationSession aggregationSession;\n\n    private Configuration configuration;\n\n    @Before\n    public void test_BaiduSessionFactory() {\n        // 1. 创建配置类\n        this.configuration = new Configuration();\n        // 2. 设置请求地址，若有代理商或者代理服务器，可填写为代理服务器的请求路径\n        configuration.setApiHost(\"https://aip.baidubce.com\");\n        // 3. 设置鉴权所需的API Key,可设置多个。\n        ApiData apiData = ApiData.builder()\n                .apiKey(\"**************************\")\n                .secretKey(\"**************************\")\n                .appId(\"**************************\")\n                .build();\n        configuration.setKeyList(Arrays.asList(apiData));\n        // 4. 设置请求时 key 的使用策略，默认实现了：随机获取 和 固定第一个Key 两种方式。\n        configuration.setKeyStrategy(new FirstKeyStrategy<ApiData>());\n//        configuration.setKeyStrategy(new RandomKeyStrategy<ApiData>());\n        // 5. 设置代理，若不需要可不设置\n//        configuration.setProxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress(\"127.0.0.1\", 7890)));\n        // 6. 创建 session 工厂，制造不同场景的 session\n        DefaultBaiduSessionFactory factory = new DefaultBaiduSessionFactory(configuration);\n        this.aggregationSession = factory.openAggregationSession();\n    }\n\n    @Test\n    public void test_text2image() {\n        ImageRequest imageRequest = ImageRequest.baseBuild(\"画一个哆啦A梦\");\n        ImageResponse imageResponse = aggregationSession.getImageSession().text2image(imageRequest);\n        // 得到结果当中的base64 图片字符串\n        List<ImageData> data = imageResponse.getData();\n        for (int i = 0; i < data.size(); i++) {\n            ImageUtils.convertBase64StrToImage(data.get(i).getB64Image(), \"D:\\\\chatGPT-api\\\\AI-java\\\\doc\\\\test\\\\test_baidu_create_image_\" + i + \".png\");\n        }\n    }\n\n}\n"
  },
  {
    "path": "ai-common/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xmlns=\"http://maven.apache.org/POM/4.0.0\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <parent>\n        <artifactId>AI-java</artifactId>\n        <groupId>com.ai</groupId>\n        <version>1.0</version>\n    </parent>\n    <modelVersion>4.0.0</modelVersion>\n    <artifactId>ai-common</artifactId>\n\n    <properties>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n        <java.version>1.8</java.version>\n        <maven.compiler.source>1.8</maven.compiler.source>\n        <maven.compiler.target>1.8</maven.compiler.target>\n        <retrofit2.version>2.9.0</retrofit2.version>\n        <slf4j.version>2.0.6</slf4j.version>\n        <gson.version>2.8.5</gson.version>\n        <jackson.version>2.13.3</jackson.version>\n        <hutool.version>5.8.18</hutool.version>\n        <okhttp.version>4.9.3</okhttp.version>\n        <logging-interceptor.version>4.10.0</logging-interceptor.version>\n        <lombok.version>1.18.26</lombok.version>\n        <jtokkit.version>0.2.0</jtokkit.version>\n        <fastjson.version>2.0.32</fastjson.version>\n        <junit.version>4.13.2</junit.version>\n    </properties>\n\n    <dependencies>\n        <dependency>\n            <groupId>org.slf4j</groupId>\n            <artifactId>slf4j-api</artifactId>\n            <version>${slf4j.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>org.slf4j</groupId>\n            <artifactId>slf4j-simple</artifactId>\n            <version>${slf4j.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>com.google.code.gson</groupId>\n            <artifactId>gson</artifactId>\n            <version>${gson.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>com.fasterxml.jackson.core</groupId>\n            <artifactId>jackson-databind</artifactId>\n            <version>${jackson.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>cn.hutool</groupId>\n            <artifactId>hutool-all</artifactId>\n            <version>${hutool.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>com.squareup.okhttp3</groupId>\n            <artifactId>okhttp-sse</artifactId>\n            <version>${okhttp.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>com.squareup.okhttp3</groupId>\n            <artifactId>logging-interceptor</artifactId>\n            <version>${logging-interceptor.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>com.squareup.retrofit2</groupId>\n            <artifactId>retrofit</artifactId>\n            <version>${retrofit2.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>com.squareup.retrofit2</groupId>\n            <artifactId>converter-jackson</artifactId>\n            <version>${retrofit2.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>com.squareup.retrofit2</groupId>\n            <artifactId>adapter-rxjava2</artifactId>\n            <version>${retrofit2.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>junit</groupId>\n            <artifactId>junit</artifactId>\n            <version>${junit.version}</version>\n            <scope>test</scope>\n        </dependency>\n        <dependency>\n            <groupId>org.jetbrains</groupId>\n            <artifactId>annotations</artifactId>\n            <version>RELEASE</version>\n            <scope>compile</scope>\n        </dependency>\n        <dependency>\n            <groupId>com.knuddels</groupId>\n            <artifactId>jtokkit</artifactId>\n            <version>${jtokkit.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>org.projectlombok</groupId>\n            <artifactId>lombok</artifactId>\n            <version>${lombok.version}</version>\n            <scope>compile</scope>\n        </dependency>\n        <dependency>\n            <groupId>com.alibaba</groupId>\n            <artifactId>fastjson</artifactId>\n            <version>${fastjson.version}</version>\n        </dependency>\n    </dependencies>\n\n</project>\n"
  },
  {
    "path": "ai-common/src/main/java/com/ai/common/utils/Exceptions.java",
    "content": "package com.ai.common.utils;\n\n/**\n * 异常工具类\n */\npublic class Exceptions {\n\n    public static IllegalArgumentException illegalArgument(String format, Object... args) {\n        return new IllegalArgumentException(String.format(format, args));\n    }\n\n    public static RuntimeException runtime(String format, Object... args) {\n        return new RuntimeException(String.format(format, args));\n    }\n}\n"
  },
  {
    "path": "ai-common/src/main/java/com/ai/common/utils/ImageUtils.java",
    "content": "package com.ai.common.utils;\n\nimport javax.imageio.ImageIO;\nimport java.awt.image.BufferedImage;\nimport java.io.ByteArrayInputStream;\nimport java.io.ByteArrayOutputStream;\nimport java.io.File;\nimport java.io.IOException;\nimport java.util.Base64;\n\npublic class ImageUtils {\n\n    /**\n     * 图片转Base64字符串\n     *\n     * @param imageFileName\n     * @return\n     */\n    public static String convertImageToBase64Str(String imageFileName) {\n        ByteArrayOutputStream baos = null;\n        try {\n            //获取图片类型\n            String suffix = imageFileName.substring(imageFileName.lastIndexOf(\".\") + 1);\n            //构建文件\n            File imageFile = new File(imageFileName);\n            //通过ImageIO把文件读取成BufferedImage对象\n            BufferedImage bufferedImage = ImageIO.read(imageFile);\n            //构建字节数组输出流\n            baos = new ByteArrayOutputStream();\n            //写入流\n            ImageIO.write(bufferedImage, suffix, baos);\n            //通过字节数组流获取字节数组\n            byte[] bytes = baos.toByteArray();\n            //获取JDK8里的编码器Base64.Encoder转为base64字符\n            return Base64.getEncoder().encodeToString(bytes);\n        } catch (Exception e) {\n            e.printStackTrace();\n        } finally {\n            try {\n                if (baos != null) {\n                    baos.close();\n                }\n            } catch (IOException e) {\n                e.printStackTrace();\n            }\n        }\n        return null;\n    }\n\n    /**\n     * Base64字符串转图片\n     *\n     * @param base64String\n     * @param imageFileName\n     */\n    public static void convertBase64StrToImage(String base64String, String imageFileName) {\n        ByteArrayInputStream bais = null;\n        try {\n            //获取图片类型\n            String suffix = imageFileName.substring(imageFileName.lastIndexOf(\".\") + 1);\n            //获取JDK8里的解码器Base64.Decoder,将base64字符串转为字节数组\n            byte[] bytes = Base64.getDecoder().decode(base64String);\n            //构建字节数组输入流\n            bais = new ByteArrayInputStream(bytes);\n            //通过ImageIO把字节数组输入流转为BufferedImage\n            BufferedImage bufferedImage = ImageIO.read(bais);\n            //构建文件\n            File imageFile = new File(imageFileName);\n            //写入生成文件\n            ImageIO.write(bufferedImage, suffix, imageFile);\n        } catch (Exception e) {\n            e.printStackTrace();\n        } finally {\n            try {\n                if (bais != null) {\n                    bais.close();\n                }\n            } catch (IOException e) {\n                e.printStackTrace();\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "ai-common/src/main/java/com/ai/common/utils/JsonUtils.java",
    "content": "package com.ai.common.utils;\n\n\nimport com.fasterxml.jackson.core.JsonProcessingException;\nimport com.fasterxml.jackson.databind.ObjectMapper;\n\npublic class JsonUtils {\n\n    public static final ObjectMapper objectMapper = new ObjectMapper();\n\n    public static <T> T fromJson(String json, Class<T> valueType) {\n        try {\n            return objectMapper.readValue(json, valueType);\n        } catch (JsonProcessingException e) {\n            e.printStackTrace();\n        }\n        return null;\n    }\n\n    public static String toJson(Object object) {\n        try {\n            return objectMapper.writeValueAsString(object);\n        } catch (JsonProcessingException e) {\n            e.printStackTrace();\n        }\n        return null;\n    }\n}\n\n"
  },
  {
    "path": "ai-common/src/main/java/com/ai/common/utils/ValidationUtils.java",
    "content": "package com.ai.common.utils;\n\nimport java.util.Collection;\n\nimport static com.ai.common.utils.Exceptions.illegalArgument;\n\n\npublic class ValidationUtils {\n\n    public static <T> T ensureNotNull(T object, String name) {\n        if (object == null) {\n            throw illegalArgument(\"%s cannot be null\", name);\n        }\n\n        return object;\n    }\n\n    public static <T extends Collection<?>> T ensureNotEmpty(T collection, String name) {\n        if (collection == null || collection.isEmpty()) {\n            throw illegalArgument(\"%s cannot be null or empty\", name);\n        }\n\n        return collection;\n    }\n\n    public static String ensureNotBlank(String string, String name) {\n        if (string == null || string.trim().isEmpty()) {\n            throw illegalArgument(\"%s cannot be null or blank\", name);\n        }\n\n        return string;\n    }\n\n    public static void ensureTrue(boolean expression, String msg) {\n        if (!expression) {\n            throw illegalArgument(msg);\n        }\n    }\n\n    public static int ensureGreaterThanZero(Integer i, String name) {\n        if (i == null || i <= 0) {\n            throw illegalArgument(\"%s must be greater than zero, but is: %s\", name, i);\n        }\n\n        return i;\n    }\n\n    public static double ensureBetween(Double d, double min, double max, String name) {\n        if (d == null || d < min || d > max) {\n            throw illegalArgument(\"%s must be between %s and %s, but is: %s\", name, min, max, d);\n        }\n\n        return d;\n    }\n\n    public static int ensureBetween(Integer i, int min, int max, String name) {\n        if (i == null || i < min || i > max) {\n            throw illegalArgument(\"%s must be between %s and %s, but is: %s\", name, min, max, i);\n        }\n\n        return i;\n    }\n}\n\n"
  },
  {
    "path": "ai-core/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xmlns=\"http://maven.apache.org/POM/4.0.0\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <parent>\n        <artifactId>AI-java</artifactId>\n        <groupId>com.ai</groupId>\n        <version>1.0</version>\n    </parent>\n    <modelVersion>4.0.0</modelVersion>\n\n    <artifactId>ai-core</artifactId>\n\n    <properties>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n        <java.version>1.8</java.version>\n        <maven.compiler.source>1.8</maven.compiler.source>\n        <maven.compiler.target>1.8</maven.compiler.target>\n    </properties>\n\n    <dependencies>\n        <dependency>\n            <groupId>com.ai</groupId>\n            <artifactId>ai-common</artifactId>\n            <version>1.0</version>\n        </dependency>\n    </dependencies>\n\n</project>\n"
  },
  {
    "path": "ai-core/src/main/java/com/ai/core/config/BaseConfiguration.java",
    "content": "package com.ai.core.config;\n\nimport com.ai.core.strategy.KeyStrategy;\nimport lombok.AllArgsConstructor;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\nimport okhttp3.OkHttpClient;\nimport org.jetbrains.annotations.NotNull;\n\nimport java.net.Proxy;\n\n/**\n * 各个模型配置基础类\n */\n@Data\n@NoArgsConstructor\n@AllArgsConstructor\npublic class BaseConfiguration {\n\n    /**\n     * api 请求客户端\n     */\n    private OkHttpClient okHttpClient;\n\n    /**\n     * 请求地址（很多情况下，这个apiHost都是一个摆设）\n     */\n    @NotNull\n    private String apiHost;\n\n    /**\n     * 代理信息\n     */\n    private Proxy proxy;\n\n    /**\n     * 获取key的策略\n     */\n    private KeyStrategy keyStrategy;\n\n}\n"
  },
  {
    "path": "ai-core/src/main/java/com/ai/core/exception/BaseException.java",
    "content": "package com.ai.core.exception;\n\nimport lombok.Getter;\n\n@Getter\npublic class BaseException extends RuntimeException {\n\n    private final String msg;\n    private final int code;\n\n    public BaseException(IError error) {\n        super(error.msg());\n        this.code = error.code();\n        this.msg = error.msg();\n    }\n\n    public BaseException(String msg) {\n        super(msg);\n        this.code = Constants.ErrorMsg.SYS_ERROR.code();\n        this.msg = msg;\n    }\n\n    public BaseException() {\n        super(Constants.ErrorMsg.SYS_ERROR.msg());\n        this.code = Constants.ErrorMsg.SYS_ERROR.code();\n        this.msg = Constants.ErrorMsg.SYS_ERROR.msg();\n    }\n}\n"
  },
  {
    "path": "ai-core/src/main/java/com/ai/core/exception/Constants.java",
    "content": "package com.ai.core.exception;\n\nimport lombok.AllArgsConstructor;\nimport lombok.Getter;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * @description 通用类\n */\npublic class Constants {\n\n    public static final String NULL = \"NULL\";\n    public static final String API_KEY = \"apiKey\";\n    public static final String API_HOST = \"apiHost\";\n    public static final String URL = \"url\";\n    public static final Map<Integer, String> ERROR_MSG_MAP = new HashMap<>();\n\n    static {\n        ERROR_MSG_MAP.put(ErrorMsg.OPENAI_AUTHENTICATION_ERROR.code(), ErrorMsg.OPENAI_AUTHENTICATION_ERROR.msg());\n        ERROR_MSG_MAP.put(ErrorMsg.OPENAI_LIMIT_ERROR.code(), ErrorMsg.OPENAI_LIMIT_ERROR.msg());\n        ERROR_MSG_MAP.put(ErrorMsg.OPENAI_SERVER_ERROR.code(), ErrorMsg.OPENAI_SERVER_ERROR.msg());\n    }\n\n    public enum ErrorMsg implements IError {\n        MESSAGE_NOT_NUL(500, \"Message 不能为空\"),\n        API_KEYS_NOT_NUL(500, \"API KEYS 不能为空\"),\n        NO_ACTIVE_API_KEYS(500, \"没有可用的API KEYS\"),\n        SYS_ERROR(500, \"系统繁忙\"),\n        PARAM_ERROR(501, \"参数异常\"),\n        RETRY_ERROR(502, \"请求异常，请重试~\"),\n        OPENAI_AUTHENTICATION_ERROR(401, \"身份验证无效/提供的 API 密钥不正确/您必须是组织的成员才能使用 API\"),\n        OPENAI_LIMIT_ERROR(429, \"达到请求的速率限制/您超出了当前配额，请检查您的计划和帐单详细信息/发动机当前过载，请稍后重试\"),\n        OPENAI_SERVER_ERROR(500, \"服务器在处理您的请求时出错\"),\n        ;\n        private int code;\n        private String msg;\n\n        ErrorMsg(int code, String msg) {\n            this.code = code;\n            this.msg = msg;\n        }\n\n        public String msg() {\n            return this.msg;\n        }\n\n        public int code() {\n            return this.code;\n        }\n    }\n\n\n    /**\n     * 官网支持的请求角色类型为：system、user、assistant\n     * system：用来设置 assistant 的行为\n     * user：用于指导 assistant\n     * assistant：消息帮助存储更早的响应\n     */\n    @Getter\n    @AllArgsConstructor\n    public enum Role {\n\n        SYSTEM(\"system\"),\n        USER(\"user\"),\n        ASSISTANT(\"assistant\"),\n        ;\n\n        private String RoleName;\n    }\n\n}\n"
  },
  {
    "path": "ai-core/src/main/java/com/ai/core/exception/IError.java",
    "content": "package com.ai.core.exception;\n\npublic interface IError {\n\n    String msg();\n\n    int code();\n\n}\n"
  },
  {
    "path": "ai-core/src/main/java/com/ai/core/factory/SessionFactory.java",
    "content": "package com.ai.core.factory;\n\n\nimport okhttp3.OkHttpClient;\n\npublic interface SessionFactory<Session, ApiServer> {\n\n    /**\n     * 创建聚合过后的session\n     *\n     * @return 默认的聚合session\n     */\n    Session openAggregationSession();\n\n    /**\n     * 获取 Api 信息\n     *\n     * @param okHttpClient 客户端\n     * @return api信息\n     */\n    ApiServer createApiServer(OkHttpClient okHttpClient);\n\n    /**\n     * 获取 httpClient\n     *\n     * @return 客户端\n     */\n    OkHttpClient createHttpClient();\n\n}\n"
  },
  {
    "path": "ai-core/src/main/java/com/ai/core/strategy/KeyStrategy.java",
    "content": "package com.ai.core.strategy;\n\n\n/**\n * @Description: API Key 获取策略\n */\npublic interface KeyStrategy<T, R> {\n    R apply(T t);\n}\n"
  },
  {
    "path": "ai-core/src/main/java/com/ai/core/strategy/impl/FirstKeyStrategy.java",
    "content": "package com.ai.core.strategy.impl;\n\nimport com.ai.core.strategy.KeyStrategy;\n\nimport java.util.List;\n\n\npublic class FirstKeyStrategy<T> implements KeyStrategy<List<T>, T> {\n\n    @Override\n    public T apply(List<T> keyList) {\n        return keyList.get(0);\n    }\n}\n"
  },
  {
    "path": "ai-core/src/main/java/com/ai/core/strategy/impl/RandomKeyStrategy.java",
    "content": "package com.ai.core.strategy.impl;\n\nimport cn.hutool.core.util.RandomUtil;\nimport com.ai.core.strategy.KeyStrategy;\n\nimport java.util.List;\n\n\npublic class RandomKeyStrategy<T> implements KeyStrategy<List<T>, T> {\n\n    @Override\n    public T apply(List<T> keyList) {\n        return RandomUtil.randomEle(keyList);\n    }\n\n}\n"
  },
  {
    "path": "ai-openai/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xmlns=\"http://maven.apache.org/POM/4.0.0\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <parent>\n        <artifactId>AI-java</artifactId>\n        <groupId>com.ai</groupId>\n        <version>1.0</version>\n    </parent>\n    <modelVersion>4.0.0</modelVersion>\n\n    <artifactId>ai-openai</artifactId>\n    <properties>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n        <java.version>1.8</java.version>\n        <maven.compiler.source>1.8</maven.compiler.source>\n        <maven.compiler.target>1.8</maven.compiler.target>\n        <junit.version>4.13.2</junit.version>\n    </properties>\n\n    <dependencies>\n        <dependency>\n            <groupId>com.ai</groupId>\n            <artifactId>ai-common</artifactId>\n            <version>1.0</version>\n        </dependency>\n        <dependency>\n            <groupId>com.ai</groupId>\n            <artifactId>ai-core</artifactId>\n            <version>1.0</version>\n        </dependency>\n        <dependency>\n            <groupId>junit</groupId>\n            <artifactId>junit</artifactId>\n            <version>${junit.version}</version>\n            <scope>test</scope>\n        </dependency>\n    </dependencies>\n\n</project>\n\n"
  },
  {
    "path": "ai-openai/src/main/java/com/ai/openai/Product.java",
    "content": "package com.ai.openai;\n\npublic class Product {\n\n    private String str1;\n    private String str2;\n\n    public Product(Builder builder) {\n        this.str1 = builder.str1;\n        this.str2 = builder.str2;\n    }\n\n    public static void main(String[] args) {\n        Product build = new Builder().setStr1(\"str1\").setStr2(\"str2\").build();\n    }\n\n    public static class Builder {\n        private static String str1;\n        private static String str2;\n\n        public Builder() {\n        }\n\n        public Builder setStr1(String str1) {\n            this.str1 = str1;\n            return this;\n        }\n\n        public Builder setStr2(String str2) {\n            this.str2 = str2;\n            return this;\n        }\n\n        public Product build() {\n            return new Product(this);\n        }\n    }\n\n}\n\n\n\n\n"
  },
  {
    "path": "ai-openai/src/main/java/com/ai/openai/Singleton.java",
    "content": "package com.ai.openai;\n\n\npublic class Singleton {\n\n    private static volatile Singleton instance;\n\n    private Singleton() {\n    }\n\n    public static Singleton getInstance() {\n        if (instance == null) {\n            synchronized (Singleton.class) {\n                if (instance == null) {\n                    instance = new Singleton();\n                }\n            }\n        }\n        return instance;\n    }\n\n}\n"
  },
  {
    "path": "ai-openai/src/main/java/com/ai/openai/ThreadPrint.java",
    "content": "package com.ai.openai;\n\n\nimport java.util.concurrent.locks.Condition;\nimport java.util.concurrent.locks.Lock;\nimport java.util.concurrent.locks.ReentrantLock;\n\nclass LockPrinter {\n    private static final Lock lock = new ReentrantLock();\n    private static final Condition condition = lock.newCondition();\n    private static int number = 0;\n\n    public static void main(String[] args) {\n        new Thread(() -> LockPrinter.printNumber(1), \"A\").start();\n        new Thread(() -> LockPrinter.printNumber(2), \"B\").start();\n        new Thread(() -> LockPrinter.printNumber(3), \"C\").start();\n    }\n\n    public static void printNumber(int target) {\n        while (number <= 10) {\n            try {\n                lock.lock();\n                if ((number % 3 + 1) != target) condition.await();\n                else {\n                    System.out.println(Thread.currentThread().getName() + \" : \" + target);\n                    number++;\n                    condition.signalAll();\n                }\n            } catch (InterruptedException e) {\n                e.printStackTrace();\n            } finally {\n                lock.unlock();\n            }\n        }\n    }\n}\n\nclass SyncPrinter {\n\n    private static int number = 0;\n\n    public static void main(String[] args) {\n        new Thread(() -> SyncPrinter.printNumber(1), \"A\").start();\n        new Thread(() -> SyncPrinter.printNumber(2), \"B\").start();\n        new Thread(() -> SyncPrinter.printNumber(3), \"C\").start();\n    }\n\n    public static void printNumber(int target) {\n        while (number <= 10) {\n            if (number % 3 + 1 == target)\n                synchronized (SyncPrinter.class) {\n                    if (number % 3 + 1 == target) {\n                        System.out.println(Thread.currentThread().getName() + \" : \" + target);\n                        number++;\n                    }\n                }\n        }\n    }\n\n}\n"
  },
  {
    "path": "ai-openai/src/main/java/com/ai/openai/achieve/Configuration.java",
    "content": "package com.ai.openai.achieve;\n\nimport com.ai.core.config.BaseConfiguration;\nimport com.ai.openai.achieve.standard.api.OpenaiApiServer;\nimport lombok.*;\nimport okhttp3.sse.EventSource;\nimport okhttp3.sse.EventSources;\nimport org.jetbrains.annotations.NotNull;\n\nimport java.util.List;\n\n/**\n * @Description: openai 相关配置信息\n **/\n@Data\n@ToString(callSuper = true)\n@EqualsAndHashCode(callSuper = true)\n@NoArgsConstructor\n@AllArgsConstructor\npublic class Configuration extends BaseConfiguration {\n\n    /**\n     * api 服务提供者\n     */\n    private OpenaiApiServer openaiApiServer;\n\n    /**\n     * api Key 集合\n     */\n    @NotNull\n    private List<String> keyList;\n\n    public EventSource.Factory createRequestFactory() {\n        return EventSources.createFactory(this.getOkHttpClient());\n    }\n\n\n    public String getSystemApiData() {\n        return (String) this.getKeyStrategy().apply(keyList);\n    }\n\n}\n"
  },
  {
    "path": "ai-openai/src/main/java/com/ai/openai/achieve/defaults/DefaultOpenAiSessionFactory.java",
    "content": "package com.ai.openai.achieve.defaults;\n\n\nimport com.ai.core.factory.SessionFactory;\nimport com.ai.openai.achieve.Configuration;\nimport com.ai.openai.achieve.defaults.session.DefaultAggregationSession;\nimport com.ai.openai.achieve.standard.api.OpenaiApiServer;\nimport com.ai.openai.achieve.standard.session.AggregationSession;\nimport com.ai.openai.interceptor.HeaderInterceptor;\nimport com.ai.openai.interceptor.ResponseInterceptor;\nimport lombok.AllArgsConstructor;\nimport okhttp3.OkHttpClient;\nimport okhttp3.logging.HttpLoggingInterceptor;\nimport retrofit2.Retrofit;\nimport retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;\nimport retrofit2.converter.jackson.JacksonConverterFactory;\n\nimport java.util.concurrent.TimeUnit;\n\n/**\n * @description OpenAi API Factory 会话工厂\n */\n@AllArgsConstructor\npublic class DefaultOpenAiSessionFactory implements SessionFactory<AggregationSession, OpenaiApiServer> {\n\n    private final Configuration configuration;\n\n    @Override\n    public OkHttpClient createHttpClient() {\n        // 1. 日志配置\n        HttpLoggingInterceptor httpLoggingInterceptor = new HttpLoggingInterceptor();\n        httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.NONE);\n        // 2. 开启 Http 客户端\n        OkHttpClient.Builder builder = new OkHttpClient.Builder()\n                .addInterceptor(httpLoggingInterceptor)\n                .addInterceptor(new HeaderInterceptor(configuration.getKeyList(), configuration.getApiHost(), configuration.getKeyStrategy()))\n                .addInterceptor(new ResponseInterceptor())\n                .connectTimeout(450, TimeUnit.SECONDS)\n                .writeTimeout(450, TimeUnit.SECONDS)\n                .readTimeout(450, TimeUnit.SECONDS);\n        // 3. 检查是否需要代理\n        if (configuration.getProxy() != null) {\n            builder.proxy(configuration.getProxy());\n        }\n        return builder.build();\n    }\n\n    @Override\n    public OpenaiApiServer createApiServer(OkHttpClient okHttpClient) {\n        return new Retrofit.Builder()\n                .baseUrl(configuration.getApiHost())\n                .client(okHttpClient)\n                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())\n                .addConverterFactory(JacksonConverterFactory.create())\n                .build().create(OpenaiApiServer.class);\n    }\n\n    @Override\n    public AggregationSession openAggregationSession() {\n        OkHttpClient okHttpClient = createHttpClient();\n        configuration.setOkHttpClient(okHttpClient);\n        configuration.setOpenaiApiServer(createApiServer(okHttpClient));\n        return new DefaultAggregationSession(configuration);\n    }\n}\n"
  },
  {
    "path": "ai-openai/src/main/java/com/ai/openai/achieve/defaults/session/DefaultAggregationSession.java",
    "content": "package com.ai.openai.achieve.defaults.session;\n\nimport com.ai.openai.achieve.Configuration;\nimport com.ai.openai.achieve.standard.session.*;\n\nimport static com.ai.common.utils.ValidationUtils.ensureNotNull;\n\n/**\n * @Description: 聚合各个类型的session\n **/\npublic class DefaultAggregationSession implements AggregationSession {\n\n    private Configuration configuration;\n\n    private volatile AudioSession audioSession;\n\n    private volatile ChatSession chatSession;\n\n    private volatile EmbeddingSession embeddingSession;\n\n    private volatile FineTuningSession fineTuningSession;\n\n    private volatile FilesSession filesSession;\n\n    private volatile ImageSession imageSession;\n\n    private volatile ModelSession modelSession;\n\n    private volatile ModerationSession moderationSession;\n\n    public DefaultAggregationSession(Configuration configuration) {\n        this.configuration = ensureNotNull(configuration, \"configuration\");\n    }\n\n    public Configuration getConfiguration() {\n        return configuration;\n    }\n\n    @Override\n    public AudioSession getAudioSession() {\n        if (audioSession == null) {\n            synchronized (this) {\n                if (audioSession == null) {\n                    audioSession = new DefaultAudioSession(configuration);\n                }\n            }\n        }\n        return audioSession;\n    }\n\n    @Override\n    public ChatSession getChatSession() {\n        if (chatSession == null) {\n            synchronized (this) {\n                if (chatSession == null) {\n                    chatSession = new DefaultChatSession(configuration);\n                }\n            }\n        }\n        return chatSession;\n    }\n\n    @Override\n    public FineTuningSession getFineTuningSession() {\n        if (fineTuningSession == null) {\n            synchronized (this) {\n                if (fineTuningSession == null) {\n                    fineTuningSession = new DefaultFineTuningSession(configuration);\n                }\n            }\n        }\n        return fineTuningSession;\n    }\n\n    @Override\n    public EmbeddingSession getEmbeddingSession() {\n        if (embeddingSession == null) {\n            synchronized (this) {\n                if (embeddingSession == null) {\n                    embeddingSession = new DefaultEmbeddingSession(configuration);\n                }\n            }\n        }\n        return embeddingSession;\n    }\n\n    @Override\n    public FilesSession getFilesSession() {\n        if (filesSession == null) {\n            synchronized (this) {\n                if (filesSession == null) {\n                    filesSession = new DefaultFilesSession(configuration);\n                }\n            }\n        }\n        return filesSession;\n    }\n\n    @Override\n    public ImageSession getImageSession() {\n        if (imageSession == null) {\n            synchronized (this) {\n                if (imageSession == null) {\n                    imageSession = new DefaultImageSession(configuration);\n                }\n            }\n        }\n        return imageSession;\n    }\n\n    @Override\n    public ModelSession getModelSession() {\n        if (modelSession == null) {\n            synchronized (this) {\n                if (modelSession == null) {\n                    modelSession = new DefaultModelSession(configuration);\n                }\n            }\n        }\n        return modelSession;\n    }\n\n    @Override\n    public ModerationSession getModerationSession() {\n        if (moderationSession == null) {\n            synchronized (this) {\n                if (moderationSession == null) {\n                    moderationSession = new DefaultModerationSession(configuration);\n                }\n            }\n        }\n        return moderationSession;\n    }\n\n}\n"
  },
  {
    "path": "ai-openai/src/main/java/com/ai/openai/achieve/defaults/session/DefaultAudioSession.java",
    "content": "package com.ai.openai.achieve.defaults.session;\n\nimport cn.hutool.core.util.StrUtil;\nimport com.ai.openai.achieve.Configuration;\nimport com.ai.openai.achieve.standard.session.AudioSession;\nimport com.ai.openai.endPoint.audio.req.SttCompletionRequest;\nimport com.ai.openai.endPoint.audio.req.TtsCompletionRequest;\nimport com.ai.openai.endPoint.audio.resp.SttCompletionResponse;\nimport lombok.Data;\nimport lombok.EqualsAndHashCode;\nimport lombok.ToString;\nimport okhttp3.MediaType;\nimport okhttp3.MultipartBody;\nimport okhttp3.RequestBody;\nimport retrofit2.Callback;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Objects;\n\nimport static com.ai.common.utils.ValidationUtils.ensureNotNull;\n\n/**\n * @Description: OpenAI 语音类会话\n **/\n@Data\n@ToString(callSuper = true)\n@EqualsAndHashCode(callSuper = true)\npublic class DefaultAudioSession extends Session implements AudioSession {\n\n    public DefaultAudioSession(Configuration configuration) {\n        this.setConfiguration(ensureNotNull(configuration, \"configuration\"));\n        this.setOpenaiApiServer(ensureNotNull(configuration.getOpenaiApiServer(), \"openaiApiServer\"));\n    }\n\n    @Override\n    public void ttsCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, TtsCompletionRequest ttsCompletionRequest, Callback callback) {\n        this.getOpenaiApiServer().createSpeechCompletion(apiHostByUser, apiKeyByUser, apiUrlByUser, ttsCompletionRequest).enqueue(callback);\n    }\n\n    private SttCompletionResponse sttBaseCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, SttCompletionRequest sttCompletionRequest, String type) {\n        RequestBody fileBody = RequestBody.create(MediaType.parse(\"multipart/form-data\"), sttCompletionRequest.getFile());\n        MultipartBody.Part multipartBody = MultipartBody.Part.createFormData(\"file\", sttCompletionRequest.getFile().getName(), fileBody);\n        Map<String, RequestBody> requestBodyMap = new HashMap<>();\n        if (StrUtil.isNotBlank(sttCompletionRequest.getLanguage())) {\n            requestBodyMap.put(SttCompletionRequest.Fields.language, RequestBody.create(MediaType.parse(\"multipart/form-data\"), sttCompletionRequest.getLanguage()));\n        }\n        if (StrUtil.isNotBlank(sttCompletionRequest.getModel())) {\n            requestBodyMap.put(SttCompletionRequest.Fields.model, RequestBody.create(MediaType.parse(\"multipart/form-data\"), sttCompletionRequest.getModel()));\n        }\n        if (StrUtil.isNotBlank(sttCompletionRequest.getPrompt())) {\n            requestBodyMap.put(SttCompletionRequest.Fields.prompt, RequestBody.create(MediaType.parse(\"multipart/form-data\"), sttCompletionRequest.getPrompt()));\n        }\n        if (StrUtil.isNotBlank(sttCompletionRequest.getResponseFormat())) {\n            requestBodyMap.put(SttCompletionRequest.Fields.responseFormat, RequestBody.create(MediaType.parse(\"multipart/form-data\"), sttCompletionRequest.getResponseFormat()));\n        }\n        if (Objects.nonNull(sttCompletionRequest.getTemperature())) {\n            requestBodyMap.put(SttCompletionRequest.Fields.temperature, RequestBody.create(MediaType.parse(\"multipart/form-data\"), String.valueOf(sttCompletionRequest.getTemperature())));\n        }\n        if (\"translation\".equals(type)) {\n            return this.getOpenaiApiServer().createTranslationCompletion(apiHostByUser, apiKeyByUser, apiUrlByUser, multipartBody, requestBodyMap).blockingGet();\n        }\n        return this.getOpenaiApiServer().createTranscriptionCompletion(apiHostByUser, apiKeyByUser, apiUrlByUser, multipartBody, requestBodyMap).blockingGet();\n    }\n\n    @Override\n    public SttCompletionResponse sttCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, SttCompletionRequest sttCompletionRequest) {\n        return sttBaseCompletions(apiHostByUser, apiKeyByUser, apiUrlByUser, sttCompletionRequest, \"stt\");\n    }\n\n    @Override\n    public SttCompletionResponse translationCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, SttCompletionRequest sttCompletionRequest) {\n        return sttBaseCompletions(apiHostByUser, apiKeyByUser, apiUrlByUser, sttCompletionRequest, \"translation\");\n    }\n\n\n}\n"
  },
  {
    "path": "ai-openai/src/main/java/com/ai/openai/achieve/defaults/session/DefaultChatSession.java",
    "content": "package com.ai.openai.achieve.defaults.session;\n\n\nimport cn.hutool.http.ContentType;\nimport com.ai.common.utils.JsonUtils;\nimport com.ai.core.exception.Constants;\nimport com.ai.openai.achieve.Configuration;\nimport com.ai.openai.achieve.standard.session.ChatSession;\nimport com.ai.openai.common.ApiUrl;\nimport com.ai.openai.endPoint.chat.ChatChoice;\nimport com.ai.openai.endPoint.chat.msg.DefaultMessage;\nimport com.ai.openai.endPoint.chat.req.DefaultChatCompletionRequest;\nimport com.ai.openai.endPoint.chat.req.FuncChatCompletionRequest;\nimport com.ai.openai.endPoint.chat.req.ImgChatCompletionRequest;\nimport com.ai.openai.endPoint.chat.req.QaCompletionRequest;\nimport com.ai.openai.endPoint.chat.resp.ChatCompletionResponse;\nimport com.ai.openai.endPoint.chat.resp.QaCompletionResponse;\nimport com.alibaba.fastjson.JSON;\nimport com.fasterxml.jackson.core.JsonProcessingException;\nimport com.fasterxml.jackson.databind.ObjectMapper;\nimport lombok.Data;\nimport lombok.EqualsAndHashCode;\nimport lombok.ToString;\nimport okhttp3.MediaType;\nimport okhttp3.Request;\nimport okhttp3.RequestBody;\nimport okhttp3.Response;\nimport okhttp3.sse.EventSource;\nimport okhttp3.sse.EventSourceListener;\n\nimport java.util.List;\nimport java.util.concurrent.CompletableFuture;\n\nimport static com.ai.common.utils.ValidationUtils.ensureNotNull;\nimport static com.ai.core.exception.Constants.*;\n\n/**\n * @description OpenAI 对话类会话\n */\n@Data\n@ToString(callSuper = true)\n@EqualsAndHashCode(callSuper = true)\npublic class DefaultChatSession extends Session implements ChatSession {\n\n    /**\n     * 工厂事件\n     */\n    private EventSource.Factory factory;\n\n    public DefaultChatSession(Configuration configuration) {\n        this.setConfiguration(ensureNotNull(configuration, \"configuration\"));\n        this.setOpenaiApiServer(ensureNotNull(configuration.getOpenaiApiServer(), \"openaiApiServer\"));\n        this.setFactory(ensureNotNull(configuration.createRequestFactory(), \"requestFactory\"));\n    }\n\n    @Override\n    public QaCompletionResponse qaCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, QaCompletionRequest qaCompletionRequest) {\n        return this.getOpenaiApiServer().createQaCompletion(apiHostByUser, apiKeyByUser, apiUrlByUser, qaCompletionRequest).blockingGet();\n    }\n\n    @Override\n    public EventSource qaCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, QaCompletionRequest qaCompletionRequest, EventSourceListener eventSourceListener) {\n        Request request = new Request.Builder()\n                .addHeader(API_HOST, apiHostByUser)\n                .addHeader(API_KEY, apiKeyByUser)\n                .addHeader(URL, apiUrlByUser)\n                .url(this.getConfiguration().getApiHost().concat(ApiUrl.v1_completions.getUrl()))\n                .post(RequestBody.create(MediaType.parse(ContentType.JSON.getValue()), JsonUtils.toJson(qaCompletionRequest)))\n                .build();\n        return factory.newEventSource(request, eventSourceListener);\n    }\n\n    @Override\n    public ChatCompletionResponse chatCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, DefaultChatCompletionRequest defaultChatCompletionRequest) {\n        return this.getOpenaiApiServer().createChatCompletion(apiHostByUser, apiKeyByUser, apiUrlByUser, defaultChatCompletionRequest).blockingGet();\n    }\n\n    @Override\n    public ChatCompletionResponse chatCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, ImgChatCompletionRequest imgChatCompletionRequest) {\n        return this.getOpenaiApiServer().createChatCompletion(apiHostByUser, apiKeyByUser, apiUrlByUser, imgChatCompletionRequest).blockingGet();\n    }\n\n    @Override\n    public ChatCompletionResponse chatCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, FuncChatCompletionRequest funcChatCompletionRequest) {\n        return this.getOpenaiApiServer().createChatCompletion(apiHostByUser, apiKeyByUser, apiUrlByUser, funcChatCompletionRequest).blockingGet();\n    }\n\n    @Override\n    public EventSource chatCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, DefaultChatCompletionRequest defaultChatCompletionRequest, EventSourceListener eventSourceListener) throws JsonProcessingException {\n        Request request = new Request.Builder()\n                .addHeader(API_HOST, apiHostByUser)\n                .addHeader(API_KEY, apiKeyByUser)\n                .addHeader(URL, apiUrlByUser)\n                .url(this.getConfiguration().getApiHost().concat(ApiUrl.v1_chat_completions.getUrl()))\n                .post(RequestBody.create(MediaType.parse(ContentType.JSON.getValue()), new ObjectMapper().writeValueAsString(defaultChatCompletionRequest)))\n                .build();\n        return factory.newEventSource(request, eventSourceListener);\n    }\n\n    @Override\n    public CompletableFuture<String> chatCompletionsFuture(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, DefaultChatCompletionRequest defaultChatCompletionRequest) throws JsonProcessingException {\n        CompletableFuture<String> future = new CompletableFuture<>();\n        StringBuffer dataBuffer = new StringBuffer();\n        chatCompletions(apiHostByUser, apiKeyByUser, apiUrlByUser, defaultChatCompletionRequest, new EventSourceListener() {\n            @Override\n            public void onEvent(EventSource eventSource, String id, String type, String data) {\n                if (\"[DONE]\".equalsIgnoreCase(data)) {\n                    onClosed(eventSource);\n                    future.complete(dataBuffer.toString());\n                }\n                ChatCompletionResponse chatCompletionResponse = JSON.parseObject(data, ChatCompletionResponse.class);\n                List<ChatChoice> choices = chatCompletionResponse.getChoices();\n                for (ChatChoice chatChoice : choices) {\n                    DefaultMessage delta = chatChoice.getDelta();\n                    if (Constants.Role.ASSISTANT.getRoleName().equals(delta.getRole())) continue;\n                    // 应答完成\n                    String finishReason = chatChoice.getFinishReason();\n                    if (\"stop\".equalsIgnoreCase(finishReason)) {\n                        onClosed(eventSource);\n                        return;\n                    }\n                    // 发送信息\n                    try {\n                        dataBuffer.append(delta.getContent());\n                    } catch (Exception e) {\n                        future.completeExceptionally(new RuntimeException(\"Request closed before completion\"));\n                    }\n                }\n            }\n\n            @Override\n            public void onClosed(EventSource eventSource) {\n                future.complete(dataBuffer.toString());\n            }\n\n            @Override\n            public void onFailure(EventSource eventSource, Throwable t, Response response) {\n                future.completeExceptionally(new RuntimeException(\"Request closed before completion\"));\n            }\n        });\n        return future;\n    }\n\n}\n"
  },
  {
    "path": "ai-openai/src/main/java/com/ai/openai/achieve/defaults/session/DefaultEmbeddingSession.java",
    "content": "package com.ai.openai.achieve.defaults.session;\n\nimport com.ai.openai.achieve.Configuration;\nimport com.ai.openai.achieve.standard.session.EmbeddingSession;\nimport com.ai.openai.endPoint.embeddings.EmbeddingObject;\nimport com.ai.openai.endPoint.embeddings.req.EmbeddingCompletionRequest;\nimport com.ai.openai.endPoint.embeddings.resp.EmbeddingCompletionResponse;\nimport lombok.Data;\nimport lombok.EqualsAndHashCode;\nimport lombok.ToString;\n\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.stream.IntStream;\n\nimport static com.ai.common.utils.ValidationUtils.ensureNotNull;\n\n/**\n * @Description: OpenAI 嵌入类会话\n **/\n@Data\n@ToString(callSuper = true)\n@EqualsAndHashCode(callSuper = true)\npublic class DefaultEmbeddingSession extends Session implements EmbeddingSession {\n\n    public DefaultEmbeddingSession(Configuration configuration) {\n        this.setConfiguration(ensureNotNull(configuration, \"configuration\"));\n        this.setOpenaiApiServer(ensureNotNull(configuration.getOpenaiApiServer(), \"openaiApiServer\"));\n    }\n\n    @Override\n    public EmbeddingCompletionResponse embeddingCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, List<String> inputList) {\n        return this.embeddingCompletions(apiHostByUser, apiKeyByUser, apiUrlByUser, EmbeddingCompletionRequest.builder().input(inputList).build());\n    }\n\n    @Override\n    public EmbeddingCompletionResponse embeddingCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, String input) {\n        return this.embeddingCompletions(apiHostByUser, apiKeyByUser, apiUrlByUser, EmbeddingCompletionRequest.builder().input(Arrays.asList(input)).build());\n    }\n\n    @Override\n    public EmbeddingCompletionResponse embeddingCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, EmbeddingCompletionRequest embeddingCompletionRequest) {\n        EmbeddingCompletionResponse response = this.getOpenaiApiServer().createEmbeddingsCompletion(apiHostByUser, apiKeyByUser, apiUrlByUser, embeddingCompletionRequest).blockingGet();\n        List<EmbeddingObject> data = response.getData();\n        List<String> input = embeddingCompletionRequest.getInput();\n        // 将文本和结果进行对应\n        IntStream.range(0, Math.min(data.size(), input.size()))\n                .forEach(i -> data.get(i).setContent(input.get(i)));\n        return response;\n    }\n\n}\n"
  },
  {
    "path": "ai-openai/src/main/java/com/ai/openai/achieve/defaults/session/DefaultFilesSession.java",
    "content": "package com.ai.openai.achieve.defaults.session;\n\nimport com.ai.openai.achieve.Configuration;\nimport com.ai.openai.achieve.standard.session.FilesSession;\nimport com.ai.openai.endPoint.files.FileObject;\nimport com.ai.openai.endPoint.files.resp.DeleteFileResponse;\nimport lombok.Data;\nimport lombok.EqualsAndHashCode;\nimport lombok.ToString;\nimport okhttp3.MediaType;\nimport okhttp3.MultipartBody;\nimport okhttp3.RequestBody;\nimport okhttp3.ResponseBody;\n\nimport java.io.File;\nimport java.util.List;\n\nimport static com.ai.common.utils.ValidationUtils.ensureNotNull;\n\n/**\n * @Description: OpenAI 文件类会话\n **/\n@Data\n@ToString(callSuper = true)\n@EqualsAndHashCode(callSuper = true)\npublic class DefaultFilesSession extends Session implements FilesSession {\n\n    public DefaultFilesSession(Configuration configuration) {\n        this.setConfiguration(ensureNotNull(configuration, \"configuration\"));\n        this.setOpenaiApiServer(ensureNotNull(configuration.getOpenaiApiServer(), \"openaiApiServer\"));\n    }\n\n    @Override\n    public List<FileObject> listFilesCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser) {\n        return this.getOpenaiApiServer().listFilesCompletion(apiHostByUser, apiKeyByUser, apiUrlByUser).blockingGet().getData();\n    }\n\n    @Override\n    public FileObject uploadFileCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, File file, String purpose) {\n        RequestBody fileBody = RequestBody.create(MediaType.parse(\"multipart/form-data\"), file);\n        MultipartBody.Part multipartBody = MultipartBody.Part.createFormData(\"file\", file.getName(), fileBody);\n        RequestBody purposeBody = RequestBody.create(MediaType.parse(\"multipart/form-data\"), purpose);\n        return this.getOpenaiApiServer().uploadFileCompletion(apiHostByUser, apiKeyByUser, apiUrlByUser, multipartBody, purposeBody).blockingGet();\n    }\n\n    @Override\n    public DeleteFileResponse deleteFileCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, String fileId) {\n        return this.getOpenaiApiServer().deleteFileCompletion(apiHostByUser, apiKeyByUser, apiUrlByUser, fileId).blockingGet();\n    }\n\n    @Override\n    public FileObject retrieveFileCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, String fileId) {\n        return this.getOpenaiApiServer().retrieveFileCompletion(apiHostByUser, apiKeyByUser, apiUrlByUser, fileId).blockingGet();\n    }\n\n    @Override\n    public ResponseBody retrieveFileContextCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, String fileId) {\n        return this.getOpenaiApiServer().retrieveFileContentCompletion(apiHostByUser, apiKeyByUser, apiUrlByUser, fileId).blockingGet();\n    }\n\n\n}\n"
  },
  {
    "path": "ai-openai/src/main/java/com/ai/openai/achieve/defaults/session/DefaultFineTuningSession.java",
    "content": "package com.ai.openai.achieve.defaults.session;\n\nimport com.ai.openai.achieve.Configuration;\nimport com.ai.openai.achieve.standard.session.FineTuningSession;\nimport com.ai.openai.common.CommonListResponse;\nimport com.ai.openai.endPoint.fineTuning.FineTuningEvent;\nimport com.ai.openai.endPoint.fineTuning.req.FineTuningRequest;\nimport com.ai.openai.endPoint.fineTuning.req.ListFineTuningRequest;\nimport com.ai.openai.endPoint.fineTuning.resp.FineTuningResponse;\nimport lombok.Data;\nimport lombok.EqualsAndHashCode;\nimport lombok.ToString;\n\nimport static com.ai.common.utils.ValidationUtils.ensureNotNull;\n\n/**\n * @Description: OpenAI 微调类会话\n **/\n@Data\n@ToString(callSuper = true)\n@EqualsAndHashCode(callSuper = true)\npublic class DefaultFineTuningSession extends Session implements FineTuningSession {\n\n    public DefaultFineTuningSession(Configuration configuration) {\n        this.setConfiguration(ensureNotNull(configuration, \"configuration\"));\n        this.setOpenaiApiServer(ensureNotNull(configuration.getOpenaiApiServer(), \"openaiApiServer\"));\n    }\n\n    @Override\n    public FineTuningResponse createFineTuningJobCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, FineTuningRequest fineTuningRequest) {\n        return this.getOpenaiApiServer().createFineTuningJobCompletion(apiHostByUser, apiKeyByUser, apiUrlByUser, fineTuningRequest).blockingGet();\n    }\n\n    @Override\n    public CommonListResponse<FineTuningResponse> listFineTuningJobsCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, ListFineTuningRequest listFineTuningRequest) {\n        return this.listFineTuningJobsCompletions(apiHostByUser, apiKeyByUser, apiUrlByUser, listFineTuningRequest.getAfter(), listFineTuningRequest.getLimit());\n    }\n\n    @Override\n    public CommonListResponse<FineTuningResponse> listFineTuningJobsCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, String after, Integer limit) {\n        return this.getOpenaiApiServer().listFineTuningJobsCompletion(apiHostByUser, apiKeyByUser, apiUrlByUser, after, limit).blockingGet();\n    }\n\n    @Override\n    public FineTuningResponse retrieveFineTuningJobCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, String fineTuningJobId) {\n        return this.getOpenaiApiServer().retrieveFineTuningJobCompletion(apiHostByUser, apiKeyByUser, apiUrlByUser, fineTuningJobId).blockingGet();\n    }\n\n    @Override\n    public FineTuningResponse cancelFineTuningJobCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, String fineTuningJobId) {\n        return this.getOpenaiApiServer().cancelFineTuningJobCompletion(apiHostByUser, apiKeyByUser, apiUrlByUser, fineTuningJobId).blockingGet();\n    }\n\n    @Override\n    public CommonListResponse<FineTuningEvent> listFineTuningEventsCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, String fineTuningJobId) {\n        return this.getOpenaiApiServer().listFineTuningEventsCompletion(apiHostByUser, apiKeyByUser, apiUrlByUser, fineTuningJobId).blockingGet();\n    }\n\n}\n"
  },
  {
    "path": "ai-openai/src/main/java/com/ai/openai/achieve/defaults/session/DefaultImageSession.java",
    "content": "package com.ai.openai.achieve.defaults.session;\n\nimport com.ai.openai.achieve.Configuration;\nimport com.ai.openai.achieve.standard.session.ImageSession;\nimport com.ai.openai.endPoint.images.ImageObject;\nimport com.ai.openai.endPoint.images.req.CreateImageRequest;\nimport com.ai.openai.endPoint.images.req.ImageEditRequest;\nimport com.ai.openai.endPoint.images.req.ImageVariationRequest;\nimport lombok.Data;\nimport lombok.EqualsAndHashCode;\nimport lombok.ToString;\nimport okhttp3.MediaType;\nimport okhttp3.MultipartBody;\nimport okhttp3.RequestBody;\n\nimport java.io.File;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\n\nimport static com.ai.common.utils.ValidationUtils.ensureNotNull;\n\n/**\n * @Description: OpenAI 图片类会话\n **/\n@Data\n@ToString(callSuper = true)\n@EqualsAndHashCode(callSuper = true)\npublic class DefaultImageSession extends Session implements ImageSession {\n\n    public DefaultImageSession(Configuration configuration) {\n        this.setConfiguration(ensureNotNull(configuration, \"configuration\"));\n        this.setOpenaiApiServer(ensureNotNull(configuration.getOpenaiApiServer(), \"openaiApiServer\"));\n    }\n\n    @Override\n    public List<ImageObject> createImageCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, CreateImageRequest createImageRequest) {\n        return this.getOpenaiApiServer().createImageCompletion(apiHostByUser, apiKeyByUser, apiUrlByUser, createImageRequest).blockingGet().getData();\n    }\n\n    @Override\n    public List<ImageObject> editImageCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, File image, File mask, ImageEditRequest imageEditRequest) {\n        // 创建 RequestBody，用于封装构建RequestBody\n        RequestBody imageBody = RequestBody.create(MediaType.parse(\"multipart/form-data\"), image);\n        MultipartBody.Part imageMultipartBody = MultipartBody.Part.createFormData(\"image\", image.getName(), imageBody);\n        MultipartBody.Part maskMultipartBody = null;\n        if (Objects.nonNull(mask)) {\n            RequestBody maskBody = RequestBody.create(MediaType.parse(\"multipart/form-data\"), mask);\n            maskMultipartBody = MultipartBody.Part.createFormData(\"mask\", image.getName(), maskBody);\n        }\n        Map<String, RequestBody> requestBodyMap = new HashMap<>();\n        requestBodyMap.put(\"prompt\", RequestBody.create(MediaType.parse(\"multipart/form-data\"), imageEditRequest.getPrompt()));\n        requestBodyMap.put(\"n\", RequestBody.create(MediaType.parse(\"multipart/form-data\"), imageEditRequest.getN().toString()));\n        requestBodyMap.put(\"size\", RequestBody.create(MediaType.parse(\"multipart/form-data\"), imageEditRequest.getSize()));\n        requestBodyMap.put(\"response_format\", RequestBody.create(MediaType.parse(\"multipart/form-data\"), imageEditRequest.getResponseFormat()));\n        if (!(Objects.isNull(imageEditRequest.getUser()) || \"\".equals(imageEditRequest.getUser()))) {\n            requestBodyMap.put(\"user\", RequestBody.create(MediaType.parse(\"multipart/form-data\"), imageEditRequest.getUser()));\n        }\n        return this.getOpenaiApiServer().editImageCompletion(\n                apiHostByUser, apiKeyByUser, apiUrlByUser,\n                imageMultipartBody,\n                maskMultipartBody,\n                requestBodyMap\n        ).blockingGet().getData();\n    }\n\n    @Override\n    public List<ImageObject> variationImageCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, File image, ImageVariationRequest imageVariationRequest) {\n        RequestBody imageBody = RequestBody.create(MediaType.parse(\"multipart/form-data\"), image);\n        MultipartBody.Part multipartBody = MultipartBody.Part.createFormData(\"image\", image.getName(), imageBody);\n        Map<String, RequestBody> requestBodyMap = new HashMap<>();\n        requestBodyMap.put(\"n\", RequestBody.create(MediaType.parse(\"multipart/form-data\"), imageVariationRequest.getN().toString()));\n        requestBodyMap.put(\"size\", RequestBody.create(MediaType.parse(\"multipart/form-data\"), imageVariationRequest.getSize()));\n        requestBodyMap.put(\"response_format\", RequestBody.create(MediaType.parse(\"multipart/form-data\"), imageVariationRequest.getResponseFormat()));\n        if (!(Objects.isNull(imageVariationRequest.getUser()) || \"\".equals(imageVariationRequest.getUser()))) {\n            requestBodyMap.put(\"user\", RequestBody.create(MediaType.parse(\"multipart/form-data\"), imageVariationRequest.getUser()));\n        }\n        return this.getOpenaiApiServer().variationImageCompletion(\n                apiHostByUser, apiKeyByUser, apiUrlByUser,\n                multipartBody,\n                requestBodyMap\n        ).blockingGet().getData();\n    }\n\n}\n"
  },
  {
    "path": "ai-openai/src/main/java/com/ai/openai/achieve/defaults/session/DefaultModelSession.java",
    "content": "package com.ai.openai.achieve.defaults.session;\n\n\nimport com.ai.openai.achieve.Configuration;\nimport com.ai.openai.achieve.standard.session.ModelSession;\nimport com.ai.openai.endPoint.models.ModelObject;\nimport com.ai.openai.endPoint.models.resp.DeleteFineTuneModelResponse;\nimport lombok.Data;\nimport lombok.EqualsAndHashCode;\nimport lombok.ToString;\n\nimport java.util.List;\n\nimport static com.ai.common.utils.ValidationUtils.ensureNotNull;\n\n/**\n * @Description: OpenAI 模型类会话\n **/\n@Data\n@ToString(callSuper = true)\n@EqualsAndHashCode(callSuper = true)\npublic class DefaultModelSession extends Session implements ModelSession {\n\n    public DefaultModelSession(Configuration configuration) {\n        this.setConfiguration(ensureNotNull(configuration, \"configuration\"));\n        this.setOpenaiApiServer(ensureNotNull(configuration.getOpenaiApiServer(), \"openaiApiServer\"));\n    }\n\n    @Override\n    public List<ModelObject> listModelCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser) {\n        return this.getOpenaiApiServer().listModelsCompletion(apiHostByUser, apiKeyByUser, apiUrlByUser).blockingGet().getData();\n    }\n\n    @Override\n    public ModelObject retrieveModelCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, String model) {\n        return this.getOpenaiApiServer().retrieveModelCompletion(apiHostByUser, apiKeyByUser, apiUrlByUser, model).blockingGet();\n    }\n\n    @Override\n    public DeleteFineTuneModelResponse deleteFineTuneModelCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, String model) {\n        return this.getOpenaiApiServer().deleteFineTuneModelCompletion(apiHostByUser, apiKeyByUser, apiUrlByUser, model).blockingGet();\n    }\n\n}\n"
  },
  {
    "path": "ai-openai/src/main/java/com/ai/openai/achieve/defaults/session/DefaultModerationSession.java",
    "content": "package com.ai.openai.achieve.defaults.session;\n\n\nimport com.ai.openai.achieve.Configuration;\nimport com.ai.openai.achieve.standard.session.ModerationSession;\nimport com.ai.openai.endPoint.moderations.Result;\nimport com.ai.openai.endPoint.moderations.req.ModerationRequest;\nimport com.ai.openai.endPoint.moderations.resp.ModerationResponse;\nimport lombok.Data;\nimport lombok.EqualsAndHashCode;\nimport lombok.ToString;\n\nimport java.util.List;\nimport java.util.stream.IntStream;\n\nimport static com.ai.common.utils.ValidationUtils.ensureNotNull;\n\n/**\n * @Description: OpenAI 审核类会话\n **/\n@Data\n@ToString(callSuper = true)\n@EqualsAndHashCode(callSuper = true)\npublic class DefaultModerationSession extends Session implements ModerationSession {\n\n    public DefaultModerationSession(Configuration configuration) {\n        this.setConfiguration(ensureNotNull(configuration, \"configuration\"));\n        this.setOpenaiApiServer(ensureNotNull(configuration.getOpenaiApiServer(), \"openaiApiServer\"));\n    }\n\n    @Override\n    public ModerationResponse moderationCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, ModerationRequest moderationRequest) {\n        ModerationResponse response = getOpenaiApiServer().moderationCompletion(apiHostByUser, apiKeyByUser, apiUrlByUser, moderationRequest).blockingGet();\n        List<String> inputs = moderationRequest.getInput();\n        List<Result> results = response.getResults();\n        // 将审核文本和审核结果进行对应\n        IntStream.range(0, Math.min(results.size(), inputs.size()))\n                .forEach(i -> results.get(i).setContent(inputs.get(i)));\n        return response;\n    }\n}\n"
  },
  {
    "path": "ai-openai/src/main/java/com/ai/openai/achieve/defaults/session/Session.java",
    "content": "package com.ai.openai.achieve.defaults.session;\n\nimport com.ai.openai.achieve.Configuration;\nimport com.ai.openai.achieve.standard.api.OpenaiApiServer;\nimport lombok.Data;\n\n\n@Data\npublic class Session {\n\n    /**\n     * 配置信息\n     */\n    private Configuration configuration;\n    /**\n     * OpenAI 接口\n     */\n    private OpenaiApiServer openaiApiServer;\n\n}\n"
  },
  {
    "path": "ai-openai/src/main/java/com/ai/openai/achieve/standard/api/OpenaiApiServer.java",
    "content": "package com.ai.openai.achieve.standard.api;\n\nimport com.ai.openai.common.CommonListResponse;\nimport com.ai.openai.endPoint.audio.req.TtsCompletionRequest;\nimport com.ai.openai.endPoint.audio.resp.SttCompletionResponse;\nimport com.ai.openai.endPoint.chat.req.DefaultChatCompletionRequest;\nimport com.ai.openai.endPoint.chat.req.FuncChatCompletionRequest;\nimport com.ai.openai.endPoint.chat.req.ImgChatCompletionRequest;\nimport com.ai.openai.endPoint.chat.req.QaCompletionRequest;\nimport com.ai.openai.endPoint.chat.resp.ChatCompletionResponse;\nimport com.ai.openai.endPoint.chat.resp.QaCompletionResponse;\nimport com.ai.openai.endPoint.embeddings.req.EmbeddingCompletionRequest;\nimport com.ai.openai.endPoint.embeddings.resp.EmbeddingCompletionResponse;\nimport com.ai.openai.endPoint.files.FileObject;\nimport com.ai.openai.endPoint.files.resp.DeleteFileResponse;\nimport com.ai.openai.endPoint.fineTuning.FineTuningEvent;\nimport com.ai.openai.endPoint.fineTuning.req.FineTuningRequest;\nimport com.ai.openai.endPoint.fineTuning.resp.FineTuningResponse;\nimport com.ai.openai.endPoint.images.req.CreateImageRequest;\nimport com.ai.openai.endPoint.images.resp.CreateImageResponse;\nimport com.ai.openai.endPoint.models.ModelObject;\nimport com.ai.openai.endPoint.models.resp.DeleteFineTuneModelResponse;\nimport com.ai.openai.endPoint.moderations.req.ModerationRequest;\nimport com.ai.openai.endPoint.moderations.resp.ModerationResponse;\nimport io.reactivex.Single;\nimport okhttp3.MultipartBody;\nimport okhttp3.RequestBody;\nimport okhttp3.ResponseBody;\nimport retrofit2.Call;\nimport retrofit2.http.*;\n\nimport java.util.Map;\n\nimport static com.ai.core.exception.Constants.*;\n\n/**\n * @Description: OpenAI API接口\n **/\npublic interface OpenaiApiServer {\n\n    /**\n     * 简单问答接口\n     *\n     * @param apiHostByUser       用户自定义 host\n     * @param apiKeyByUser        用户自定义密钥\n     * @param apiUrlByUser        用户自定义请求地址\n     * @param qaCompletionRequest 用户自定义封装的请求参数\n     * @return 请求结果\n     */\n    @POST(\"/v1/completions\")\n    Single<QaCompletionResponse> createQaCompletion(@Header(API_HOST) String apiHostByUser, @Header(API_KEY) String apiKeyByUser, @Header(URL) String apiUrlByUser, @Body QaCompletionRequest qaCompletionRequest);\n\n    /**\n     * 普通对话聊天接口\n     *\n     * @param apiHostByUser                用户自定义 host\n     * @param apiKeyByUser                 用户自定义密钥\n     * @param apiUrlByUser                 用户自定义请求地址\n     * @param defaultChatCompletionRequest 用户自定义封装的请求参数\n     * @return 请求结果\n     */\n    @POST(\"/v1/chat/completions\")\n    Single<ChatCompletionResponse> createChatCompletion(@Header(API_HOST) String apiHostByUser, @Header(API_KEY) String apiKeyByUser, @Header(URL) String apiUrlByUser, @Body DefaultChatCompletionRequest defaultChatCompletionRequest);\n\n    /**\n     * 图片对话聊天接口\n     *\n     * @param apiHostByUser            用户自定义 host\n     * @param apiKeyByUser             用户自定义密钥\n     * @param apiUrlByUser             用户自定义请求地址\n     * @param imgChatCompletionRequest 用户自定义封装的请求参数\n     * @return 请求结果\n     */\n    @POST(\"/v1/chat/completions\")\n    Single<ChatCompletionResponse> createChatCompletion(@Header(API_HOST) String apiHostByUser, @Header(API_KEY) String apiKeyByUser, @Header(URL) String apiUrlByUser, @Body ImgChatCompletionRequest imgChatCompletionRequest);\n\n    /**\n     * 函数对话聊天接口\n     *\n     * @param apiHostByUser             用户自定义 host\n     * @param apiKeyByUser              用户自定义密钥\n     * @param apiUrlByUser              用户自定义请求地址\n     * @param funcChatCompletionRequest 用户自定义封装的请求参数\n     * @return 请求结果\n     */\n    @POST(\"/v1/chat/completions\")\n    Single<ChatCompletionResponse> createChatCompletion(@Header(API_HOST) String apiHostByUser, @Header(API_KEY) String apiKeyByUser, @Header(URL) String apiUrlByUser, @Body FuncChatCompletionRequest funcChatCompletionRequest);\n\n\n    /**\n     * 输入文本生成音频\n     *\n     * @param apiHostByUser        用户自定义 host\n     * @param apiKeyByUser         用户自定义密钥\n     * @param apiUrlByUser         用户自定义请求地址\n     * @param ttsCompletionRequest 用户自定义封装的请求参数\n     * @return 请求结果\n     */\n    @POST(\"/v1/audio/speech\")\n    @Streaming\n    Call<ResponseBody> createSpeechCompletion(@Header(API_HOST) String apiHostByUser, @Header(API_KEY) String apiKeyByUser, @Header(URL) String apiUrlByUser, @Body TtsCompletionRequest ttsCompletionRequest);\n\n    /**\n     * 发送音频文件，解析成文本\n     *\n     * @param apiHostByUser  用户自定义 host\n     * @param apiKeyByUser   用户自定义密钥\n     * @param apiUrlByUser   用户自定义请求地址\n     * @param file           音频文件\n     * @param requestBodyMap 请求参数\n     * @return 请求结果\n     */\n    @Multipart\n    @POST(\"/v1/audio/transcriptions\")\n    Single<SttCompletionResponse> createTranscriptionCompletion(@Header(API_HOST) String apiHostByUser, @Header(API_KEY) String apiKeyByUser, @Header(URL) String apiUrlByUser, @Part MultipartBody.Part file, @PartMap Map<String, RequestBody> requestBodyMap);\n\n    /**\n     * 发送音频文件，解析并翻译为英文\n     *\n     * @param apiHostByUser  用户自定义 host\n     * @param apiKeyByUser   用户自定义密钥\n     * @param apiUrlByUser   用户自定义请求地址\n     * @param file           音频文件\n     * @param requestBodyMap 请求参数\n     * @return 请求结果\n     */\n    @Multipart\n    @POST(\"/v1/audio/translations\")\n    Single<SttCompletionResponse> createTranslationCompletion(@Header(API_HOST) String apiHostByUser, @Header(API_KEY) String apiKeyByUser, @Header(URL) String apiUrlByUser, @Part MultipartBody.Part file, @PartMap() Map<String, RequestBody> requestBodyMap);\n\n    /**\n     * 创建嵌入\n     *\n     * @param apiHostByUser              用户自定义 host\n     * @param apiKeyByUser               用户自定义密钥\n     * @param apiUrlByUser               用户自定义请求地址\n     * @param embeddingCompletionRequest 请求参数\n     * @return 请求结果\n     */\n    @POST(\"/v1/embeddings\")\n    Single<EmbeddingCompletionResponse> createEmbeddingsCompletion(@Header(API_HOST) String apiHostByUser, @Header(API_KEY) String apiKeyByUser, @Header(URL) String apiUrlByUser, @Body EmbeddingCompletionRequest embeddingCompletionRequest);\n\n    /**\n     * 创建微调作业\n     *\n     * @param apiHostByUser     用户自定义 host\n     * @param apiKeyByUser      用户自定义密钥\n     * @param apiUrlByUser      用户自定义请求地址\n     * @param fineTuningRequest 请求参数\n     * @return 请求结果\n     */\n    @POST(\"/v1/fine_tuning/jobs\")\n    Single<FineTuningResponse> createFineTuningJobCompletion(@Header(API_HOST) String apiHostByUser, @Header(API_KEY) String apiKeyByUser, @Header(URL) String apiUrlByUser, @Body FineTuningRequest fineTuningRequest);\n\n    /**\n     * 列出微调作业\n     *\n     * @param apiHostByUser 用户自定义 host\n     * @param apiKeyByUser  用户自定义密钥\n     * @param apiUrlByUser  用户自定义请求地址\n     * @param after         上一个分页请求中最后一个作业的标识符\n     * @param limit         要检索的微调作业数\n     * @return 请求结果\n     */\n    @GET(\"/v1/fine_tuning/jobs\")\n    Single<CommonListResponse<FineTuningResponse>> listFineTuningJobsCompletion(@Header(API_HOST) String apiHostByUser, @Header(API_KEY) String apiKeyByUser, @Header(URL) String apiUrlByUser, @Query(\"after\") String after, @Query(\"limit\") Integer limit);\n\n    /**\n     * 检索微调作业\n     *\n     * @param apiHostByUser   用户自定义 host\n     * @param apiKeyByUser    用户自定义密钥\n     * @param apiUrlByUser    用户自定义请求地址\n     * @param fineTuningJobId 微调作业的 ID\n     * @return 请求结果\n     */\n    @GET(\"/v1/fine_tuning/jobs/{fine_tuning_job_id}\")\n    Single<FineTuningResponse> retrieveFineTuningJobCompletion(@Header(API_HOST) String apiHostByUser, @Header(API_KEY) String apiKeyByUser, @Header(URL) String apiUrlByUser, @Path(\"fine_tuning_job_id\") String fineTuningJobId);\n\n    /**\n     * 取消微调作业\n     *\n     * @param apiHostByUser   用户自定义 host\n     * @param apiKeyByUser    用户自定义密钥\n     * @param apiUrlByUser    用户自定义请求地址\n     * @param fineTuningJobId 微调作业的 ID\n     * @return 请求结果\n     */\n    @POST(\"/v1/fine_tuning/jobs/{fine_tuning_job_id}/cancel\")\n    Single<FineTuningResponse> cancelFineTuningJobCompletion(@Header(API_HOST) String apiHostByUser, @Header(API_KEY) String apiKeyByUser, @Header(URL) String apiUrlByUser, @Path(\"fine_tuning_job_id\") String fineTuningJobId);\n\n    /**\n     * 列出微调事件\n     *\n     * @param apiHostByUser   用户自定义 host\n     * @param apiKeyByUser    用户自定义密钥\n     * @param apiUrlByUser    用户自定义请求地址\n     * @param fineTuningJobId 微调作业的 ID\n     * @return 请求结果\n     */\n    @GET(\"/v1/fine_tuning/jobs/{fine_tuning_job_id}/events\")\n    Single<CommonListResponse<FineTuningEvent>> listFineTuningEventsCompletion(@Header(API_HOST) String apiHostByUser, @Header(API_KEY) String apiKeyByUser, @Header(URL) String apiUrlByUser, @Path(\"fine_tuning_job_id\") String fineTuningJobId);\n\n    /**\n     * 返回属于用户组织的文件列表\n     *\n     * @param apiHostByUser 用户自定义 host\n     * @param apiKeyByUser  用户自定义密钥\n     * @param apiUrlByUser  用户自定义请求地址\n     * @return 文件列表\n     */\n    @GET(\"/v1/files\")\n    Single<CommonListResponse<FileObject>> listFilesCompletion(@Header(API_HOST) String apiHostByUser, @Header(API_KEY) String apiKeyByUser, @Header(URL) String apiUrlByUser);\n\n    /**\n     * 上传文件\n     *\n     * @param apiHostByUser 用户自定义 host\n     * @param apiKeyByUser  用户自定义密钥\n     * @param apiUrlByUser  用户自定义请求地址\n     * @param file          要上载的 File 对象（不是文件名）\n     * @param purpose       上传文件的预期用途\n     * @return 上载的 File 对象\n     */\n    @Multipart\n    @POST(\"/v1/files\")\n    Single<FileObject> uploadFileCompletion(@Header(API_HOST) String apiHostByUser, @Header(API_KEY) String apiKeyByUser, @Header(URL) String apiUrlByUser, @Part MultipartBody.Part file, @Part(\"purpose\") RequestBody purpose);\n\n    /**\n     * 删除文件\n     *\n     * @param apiHostByUser 用户自定义 host\n     * @param apiKeyByUser  用户自定义密钥\n     * @param apiUrlByUser  用户自定义请求地址\n     * @param fileId        文件ID\n     * @return 删除状态\n     */\n    @DELETE(\"/v1/files/{file_id}\")\n    Single<DeleteFileResponse> deleteFileCompletion(@Header(API_HOST) String apiHostByUser, @Header(API_KEY) String apiKeyByUser, @Header(URL) String apiUrlByUser, @Path(\"file_id\") String fileId);\n\n    /**\n     * 检索文件\n     *\n     * @param apiHostByUser 用户自定义 host\n     * @param apiKeyByUser  用户自定义密钥\n     * @param apiUrlByUser  用户自定义请求地址\n     * @param fileId        文件ID\n     * @return 文件信息\n     */\n    @GET(\"/v1/files/{file_id}\")\n    Single<FileObject> retrieveFileCompletion(@Header(API_HOST) String apiHostByUser, @Header(API_KEY) String apiKeyByUser, @Header(URL) String apiUrlByUser, @Path(\"file_id\") String fileId);\n\n\n    /**\n     * 获取文件内容\n     *\n     * @param apiHostByUser 用户自定义 host\n     * @param apiKeyByUser  用户自定义密钥\n     * @param apiUrlByUser  用户自定义请求地址\n     * @param fileId        文件ID\n     * @return 文件内容\n     */\n    @Streaming\n    @GET(\"/v1/files/{file_id}/content\")\n    Single<ResponseBody> retrieveFileContentCompletion(@Header(API_HOST) String apiHostByUser, @Header(API_KEY) String apiKeyByUser, @Header(URL) String apiUrlByUser, @Path(\"file_id\") String fileId);\n\n    /**\n     * 生成图片\n     *\n     * @param apiHostByUser      用户自定义 host\n     * @param apiKeyByUser       用户自定义密钥\n     * @param apiUrlByUser       用户自定义请求地址\n     * @param createImageRequest 生成图片的请求参数\n     * @return 图片信息\n     */\n    @POST(\"/v1/images/generations\")\n    Single<CreateImageResponse> createImageCompletion(@Header(API_HOST) String apiHostByUser, @Header(API_KEY) String apiKeyByUser, @Header(URL) String apiUrlByUser, @Body CreateImageRequest createImageRequest);\n\n    /**\n     * 编辑图片\n     *\n     * @param apiHostByUser  用户自定义 host\n     * @param apiKeyByUser   用户自定义密钥\n     * @param apiUrlByUser   用户自定义请求地址\n     * @param image          被编辑的图片\n     * @param mask           一个额外的图像，其完全透明的区域（例如，alpha为零）指示应该编辑的位置。必须是有效的 PNG 文件，小于 4MB，并且尺寸与image相同。\n     * @param requestBodyMap 请求参数\n     * @return 图片信息\n     */\n    @Multipart\n    @POST(\"/v1/images/edits\")\n    Single<CreateImageResponse> editImageCompletion(@Header(API_HOST) String apiHostByUser,\n                                                    @Header(API_KEY) String apiKeyByUser,\n                                                    @Header(URL) String apiUrlByUser,\n                                                    @Part() MultipartBody.Part image, @Part() MultipartBody.Part mask, @PartMap() Map<String, RequestBody> requestBodyMap);\n\n    /**\n     * 创建给定图像的变体\n     *\n     * @param apiHostByUser  用户自定义 host\n     * @param apiKeyByUser   用户自定义密钥\n     * @param apiUrlByUser   用户自定义请求地址\n     * @param image          被编辑的图片\n     * @param requestBodyMap 请求参数\n     * @return 图片信息\n     */\n    @Multipart\n    @POST(\"/v1/images/variations\")\n    Single<CreateImageResponse> variationImageCompletion(@Header(API_HOST) String apiHostByUser,\n                                                         @Header(API_KEY) String apiKeyByUser,\n                                                         @Header(URL) String apiUrlByUser, @Part() MultipartBody.Part image,\n                                                         @PartMap() Map<String, RequestBody> requestBodyMap);\n\n    /**\n     * 列出模型\n     *\n     * @param apiHostByUser 用户自定义 host\n     * @param apiKeyByUser  用户自定义密钥\n     * @param apiUrlByUser  用户自定义请求地址\n     * @return 模型信息\n     */\n    @GET(\"/v1/models\")\n    Single<CommonListResponse<ModelObject>> listModelsCompletion(@Header(API_HOST) String apiHostByUser, @Header(API_KEY) String apiKeyByUser, @Header(URL) String apiUrlByUser);\n\n    /**\n     * 检索模型信息\n     *\n     * @param apiHostByUser 用户自定义 host\n     * @param apiKeyByUser  用户自定义密钥\n     * @param apiUrlByUser  用户自定义请求地址\n     * @param model         模型ID\n     * @return 模型信息\n     */\n    @GET(\"/v1/models/{model}\")\n    Single<ModelObject> retrieveModelCompletion(@Header(API_HOST) String apiHostByUser, @Header(API_KEY) String apiKeyByUser, @Header(URL) String apiUrlByUser, @Path(\"model\") String model);\n\n    /**\n     * 删除微调模型\n     *\n     * @param apiHostByUser 用户自定义 host\n     * @param apiKeyByUser  用户自定义密钥\n     * @param apiUrlByUser  用户自定义请求地址\n     * @param model         模型ID\n     * @return 删除状态\n     */\n    @DELETE(\"/v1/models/{model}\")\n    Single<DeleteFineTuneModelResponse> deleteFineTuneModelCompletion(@Header(API_HOST) String apiHostByUser, @Header(API_KEY) String apiKeyByUser, @Header(URL) String apiUrlByUser, @Path(\"model\") String model);\n\n\n    /**\n     * 审核\n     *\n     * @param apiHostByUser     用户自定义 host\n     * @param apiKeyByUser      用户自定义密钥\n     * @param apiUrlByUser      用户自定义请求地址\n     * @param moderationRequest 审核请求参数\n     * @return 审核结果\n     */\n    @POST(\"/v1/moderations\")\n    Single<ModerationResponse> moderationCompletion(@Header(API_HOST) String apiHostByUser, @Header(API_KEY) String apiKeyByUser, @Header(URL) String apiUrlByUser, @Body ModerationRequest moderationRequest);\n\n\n}\n"
  },
  {
    "path": "ai-openai/src/main/java/com/ai/openai/achieve/standard/session/AggregationSession.java",
    "content": "package com.ai.openai.achieve.standard.session;\n\n/**\n * @Description: 聚合各大场景的session\n **/\npublic interface AggregationSession {\n\n    /**\n     * 获取音频会话窗口\n     */\n    AudioSession getAudioSession();\n\n    /**\n     * 获取对话会话窗口\n     */\n    ChatSession getChatSession();\n\n    /**\n     * 获取微调会话窗口\n     */\n    FineTuningSession getFineTuningSession();\n\n    /**\n     * 获取嵌入会话窗口\n     */\n    EmbeddingSession getEmbeddingSession();\n\n    /**\n     * 获取文件会话窗口\n     */\n    FilesSession getFilesSession();\n\n    /**\n     * 获取图片会话窗口\n     */\n    ImageSession getImageSession();\n\n    /**\n     * 获取模型会话窗口\n     */\n    ModelSession getModelSession();\n\n    /**\n     * 获取审核会话窗口\n     */\n    ModerationSession getModerationSession();\n\n}\n"
  },
  {
    "path": "ai-openai/src/main/java/com/ai/openai/achieve/standard/session/AudioSession.java",
    "content": "package com.ai.openai.achieve.standard.session;\n\nimport com.ai.openai.endPoint.audio.req.SttCompletionRequest;\nimport com.ai.openai.endPoint.audio.req.TtsCompletionRequest;\nimport com.ai.openai.endPoint.audio.resp.SttCompletionResponse;\nimport retrofit2.Callback;\n\n/**\n * @Description: openAi 音频会话窗口\n **/\npublic interface AudioSession {\n\n    /**\n     * 文字转语音\n     *\n     * @param apiHostByUser        用户自定义 host\n     * @param apiKeyByUser         用户自定义密钥\n     * @param apiUrlByUser         用户自定义请求地址\n     * @param ttsCompletionRequest 语音接口请求参数\n     * @param callback             回调函数\n     */\n    void ttsCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, TtsCompletionRequest ttsCompletionRequest, Callback callback);\n\n    /**\n     * 语音转文字\n     *\n     * @param apiHostByUser        用户自定义 host\n     * @param apiKeyByUser         用户自定义密钥\n     * @param apiUrlByUser         用户自定义请求地址\n     * @param sttCompletionRequest 音频转文字接口请求参数\n     * @return 请求结果\n     */\n    SttCompletionResponse sttCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, SttCompletionRequest sttCompletionRequest);\n\n    /**\n     * 翻译\n     *\n     * @param apiHostByUser        用户自定义 host\n     * @param apiKeyByUser         用户自定义密钥\n     * @param apiUrlByUser         用户自定义请求地址\n     * @param sttCompletionRequest 音频转文字接口请求参数\n     * @return 请求结果\n     */\n    SttCompletionResponse translationCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, SttCompletionRequest sttCompletionRequest);\n}\n"
  },
  {
    "path": "ai-openai/src/main/java/com/ai/openai/achieve/standard/session/ChatSession.java",
    "content": "package com.ai.openai.achieve.standard.session;\n\nimport com.ai.openai.endPoint.chat.req.DefaultChatCompletionRequest;\nimport com.ai.openai.endPoint.chat.req.FuncChatCompletionRequest;\nimport com.ai.openai.endPoint.chat.req.ImgChatCompletionRequest;\nimport com.ai.openai.endPoint.chat.req.QaCompletionRequest;\nimport com.ai.openai.endPoint.chat.resp.ChatCompletionResponse;\nimport com.ai.openai.endPoint.chat.resp.QaCompletionResponse;\nimport com.fasterxml.jackson.core.JsonProcessingException;\nimport okhttp3.sse.EventSource;\nimport okhttp3.sse.EventSourceListener;\n\nimport java.util.concurrent.CompletableFuture;\n\n/**\n * @description openAi 聊天会话窗口\n */\npublic interface ChatSession {\n\n    /**\n     * 简单问答\n     *\n     * @param apiHostByUser       用户自定义 host\n     * @param apiKeyByUser        用户自定义密钥\n     * @param apiUrlByUser        用户自定义请求地址\n     * @param qaCompletionRequest 用户自定义封装的请求参数\n     * @return 请求结果\n     */\n    QaCompletionResponse qaCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, QaCompletionRequest qaCompletionRequest);\n\n    /**\n     * 简单问答，流式返回。\n     *\n     * @param apiHostByUser       用户自定义 host\n     * @param apiKeyByUser        用户自定义密钥\n     * @param apiUrlByUser        用户自定义请求地址\n     * @param qaCompletionRequest 用户自定义封装的请求参数\n     * @param eventSourceListener 事件监听者\n     * @return 事件源\n     */\n    EventSource qaCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, QaCompletionRequest qaCompletionRequest, EventSourceListener eventSourceListener) throws JsonProcessingException;\n\n    /**\n     * 普通对话聊天\n     *\n     * @param apiHostByUser                用户自定义 host\n     * @param apiKeyByUser                 用户自定义密钥\n     * @param apiUrlByUser                 用户自定义请求地址\n     * @param defaultChatCompletionRequest 用户自定义封装的请求参数\n     * @return 请求结果\n     */\n    ChatCompletionResponse chatCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, DefaultChatCompletionRequest defaultChatCompletionRequest);\n\n    /**\n     * 图片对话聊天\n     *\n     * @param apiHostByUser            用户自定义 host\n     * @param apiKeyByUser             用户自定义密钥\n     * @param apiUrlByUser             用户自定义请求地址\n     * @param imgChatCompletionRequest 用户自定义封装的请求参数\n     * @return 请求结果\n     */\n    ChatCompletionResponse chatCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, ImgChatCompletionRequest imgChatCompletionRequest);\n\n    /**\n     * 函数对话聊天\n     *\n     * @param apiHostByUser             用户自定义 host\n     * @param apiKeyByUser              用户自定义密钥\n     * @param apiUrlByUser              用户自定义请求地址\n     * @param funcChatCompletionRequest 用户自定义封装的请求参数\n     * @return 请求结果\n     */\n    ChatCompletionResponse chatCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, FuncChatCompletionRequest funcChatCompletionRequest);\n\n    /**\n     * 对话聊天，流式返回，此函数为对话聊天流式返回的基础函数。\n     *\n     * @param apiHostByUser                用户自定义 host\n     * @param apiKeyByUser                 用户自定义密钥\n     * @param apiUrlByUser                 用户自定义请求地址\n     * @param defaultChatCompletionRequest 用户自定义封装的请求参数\n     * @param eventSourceListener          事件监听者\n     * @return 事件源\n     */\n    EventSource chatCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, DefaultChatCompletionRequest defaultChatCompletionRequest, EventSourceListener eventSourceListener) throws JsonProcessingException;\n\n    /**\n     * 对话聊天 & 流式反馈 & 一次反馈\n     *\n     * @param defaultChatCompletionRequest 请求信息\n     * @return 应答结果\n     */\n    CompletableFuture<String> chatCompletionsFuture(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, DefaultChatCompletionRequest defaultChatCompletionRequest) throws InterruptedException, JsonProcessingException;\n\n}\n"
  },
  {
    "path": "ai-openai/src/main/java/com/ai/openai/achieve/standard/session/EmbeddingSession.java",
    "content": "package com.ai.openai.achieve.standard.session;\n\nimport com.ai.openai.endPoint.embeddings.req.EmbeddingCompletionRequest;\nimport com.ai.openai.endPoint.embeddings.resp.EmbeddingCompletionResponse;\n\nimport java.util.List;\n\n/**\n * @Description: 嵌入会话窗口\n **/\npublic interface EmbeddingSession {\n\n    /**\n     * 嵌入\n     *\n     * @param apiHostByUser 用户自定义 host\n     * @param apiKeyByUser  用户自定义密钥\n     * @param apiUrlByUser  用户自定义请求地址\n     * @param inputList     文本数组\n     * @return 请求结果\n     */\n    EmbeddingCompletionResponse embeddingCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, List<String> inputList);\n\n    /**\n     * 嵌入\n     *\n     * @param apiHostByUser 用户自定义 host\n     * @param apiKeyByUser  用户自定义密钥\n     * @param apiUrlByUser  用户自定义请求地址\n     * @param input         文本\n     * @return 请求结果\n     */\n    EmbeddingCompletionResponse embeddingCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, String input);\n\n    /**\n     * 嵌入\n     *\n     * @param apiHostByUser              用户自定义 host\n     * @param apiKeyByUser               用户自定义密钥\n     * @param apiUrlByUser               用户自定义请求地址\n     * @param embeddingCompletionRequest 请求参数\n     * @return 请求结果\n     */\n    EmbeddingCompletionResponse embeddingCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, EmbeddingCompletionRequest embeddingCompletionRequest);\n}\n"
  },
  {
    "path": "ai-openai/src/main/java/com/ai/openai/achieve/standard/session/FilesSession.java",
    "content": "package com.ai.openai.achieve.standard.session;\n\nimport com.ai.openai.endPoint.files.FileObject;\nimport com.ai.openai.endPoint.files.resp.DeleteFileResponse;\nimport okhttp3.ResponseBody;\n\nimport java.io.File;\nimport java.util.List;\n\n/**\n * @Description: 文件会话窗口\n **/\npublic interface FilesSession {\n    /**\n     * 返回属于用户组织的文件列表\n     *\n     * @param apiHostByUser 用户自定义 host\n     * @param apiKeyByUser  用户自定义密钥\n     * @param apiUrlByUser  用户自定义请求地址\n     * @return 文件列表\n     */\n    List<FileObject> listFilesCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser);\n\n    /**\n     * 上传文件\n     *\n     * @param apiHostByUser 用户自定义 host\n     * @param apiKeyByUser  用户自定义密钥\n     * @param apiUrlByUser  用户自定义请求地址\n     * @param file          需要上传的文件\n     * @param purpose       上传文件的用途\n     * @return 文件信息\n     */\n    FileObject uploadFileCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, File file, String purpose);\n\n    /**\n     * 删除文件\n     *\n     * @param apiHostByUser 用户自定义 host\n     * @param apiKeyByUser  用户自定义密钥\n     * @param apiUrlByUser  用户自定义请求地址\n     * @param fileId        文件ID\n     * @return 删除状态信息\n     */\n    DeleteFileResponse deleteFileCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, String fileId);\n\n    /**\n     * 检索文件\n     *\n     * @param apiHostByUser 用户自定义 host\n     * @param apiKeyByUser  用户自定义密钥\n     * @param apiUrlByUser  用户自定义请求地址\n     * @param fileId        文件ID\n     * @return 文件信息\n     */\n    FileObject retrieveFileCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, String fileId);\n\n    /**\n     * 获取文件内容\n     *\n     * @param apiHostByUser 用户自定义 host\n     * @param apiKeyByUser  用户自定义密钥\n     * @param apiUrlByUser  用户自定义请求地址\n     * @param fileId        文件ID\n     * @return 返回结果\n     */\n    ResponseBody retrieveFileContextCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, String fileId);\n}\n"
  },
  {
    "path": "ai-openai/src/main/java/com/ai/openai/achieve/standard/session/FineTuningSession.java",
    "content": "package com.ai.openai.achieve.standard.session;\n\nimport com.ai.openai.common.CommonListResponse;\nimport com.ai.openai.endPoint.fineTuning.FineTuningEvent;\nimport com.ai.openai.endPoint.fineTuning.req.FineTuningRequest;\nimport com.ai.openai.endPoint.fineTuning.req.ListFineTuningRequest;\nimport com.ai.openai.endPoint.fineTuning.resp.FineTuningResponse;\n\n/**\n * @Description: 微调会话窗口\n **/\npublic interface FineTuningSession {\n\n    /**\n     * 创建微调作业\n     *\n     * @param apiHostByUser     用户自定义 host\n     * @param apiKeyByUser      用户自定义密钥\n     * @param apiUrlByUser      用户自定义请求地址\n     * @param fineTuningRequest 请求参数\n     * @return 请求结果\n     */\n    FineTuningResponse createFineTuningJobCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, FineTuningRequest fineTuningRequest);\n\n    /**\n     * 列出微调作业\n     *\n     * @param apiHostByUser         用户自定义 host\n     * @param apiKeyByUser          用户自定义密钥\n     * @param apiUrlByUser          用户自定义请求地址\n     * @param listFineTuningRequest 请求参数\n     * @return 请求结果\n     */\n    CommonListResponse<FineTuningResponse> listFineTuningJobsCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, ListFineTuningRequest listFineTuningRequest);\n\n    /**\n     * 列出微调作业\n     *\n     * @param apiHostByUser 用户自定义 host\n     * @param apiKeyByUser  用户自定义密钥\n     * @param apiUrlByUser  用户自定义请求地址\n     * @param after         上一个分页请求中最后一个作业的标识符\n     * @param limit         要检索的微调作业数\n     * @return 请求结果\n     */\n    CommonListResponse<FineTuningResponse> listFineTuningJobsCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, String after, Integer limit);\n\n    /**\n     * 检索微调作业\n     *\n     * @param apiHostByUser   用户自定义 host\n     * @param apiKeyByUser    用户自定义密钥\n     * @param apiUrlByUser    用户自定义请求地址\n     * @param fineTuningJobId 微调作业的 ID\n     * @return 请求结果\n     */\n    FineTuningResponse retrieveFineTuningJobCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, String fineTuningJobId);\n\n    /**\n     * 取消微调作业\n     *\n     * @param apiHostByUser   用户自定义 host\n     * @param apiKeyByUser    用户自定义密钥\n     * @param apiUrlByUser    用户自定义请求地址\n     * @param fineTuningJobId 微调作业的 ID\n     * @return 请求结果\n     */\n    FineTuningResponse cancelFineTuningJobCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, String fineTuningJobId);\n\n    /**\n     * 列出微调事件\n     *\n     * @param apiHostByUser   用户自定义 host\n     * @param apiKeyByUser    用户自定义密钥\n     * @param apiUrlByUser    用户自定义请求地址\n     * @param fineTuningJobId 微调作业的 ID\n     * @return 请求结果\n     */\n    CommonListResponse<FineTuningEvent> listFineTuningEventsCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, String fineTuningJobId);\n}\n"
  },
  {
    "path": "ai-openai/src/main/java/com/ai/openai/achieve/standard/session/ImageSession.java",
    "content": "package com.ai.openai.achieve.standard.session;\n\nimport com.ai.openai.endPoint.images.ImageObject;\nimport com.ai.openai.endPoint.images.req.CreateImageRequest;\nimport com.ai.openai.endPoint.images.req.ImageEditRequest;\nimport com.ai.openai.endPoint.images.req.ImageVariationRequest;\n\nimport java.io.File;\nimport java.util.List;\n\n/**\n * @Description: 图片会话窗口\n **/\npublic interface ImageSession {\n\n    /**\n     * @param apiHostByUser      用户自定义 host\n     * @param apiKeyByUser       用户自定义密钥\n     * @param apiUrlByUser       用户自定义请求地址\n     * @param createImageRequest 请求参数\n     * @return 图片信息\n     */\n    List<ImageObject> createImageCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, CreateImageRequest createImageRequest);\n\n    /**\n     * 编辑图像\n     *\n     * @param apiHostByUser    用户自定义 host\n     * @param apiKeyByUser     用户自定义密钥\n     * @param apiUrlByUser     用户自定义请求地址\n     * @param image            要编辑的图像\n     * @param mask             一个额外的图像，其完全透明的区域（例如，alpha为零）指示应该编辑的位置。必须是有效的 PNG 文件，小于 4MB，并且尺寸与image相同\n     * @param imageEditRequest 请求参数\n     * @return 图片信息\n     */\n    List<ImageObject> editImageCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, File image, File mask, ImageEditRequest imageEditRequest);\n\n    /**\n     * 创建图像变体\n     *\n     * @param apiHostByUser         用户自定义 host\n     * @param apiKeyByUser          用户自定义密钥\n     * @param apiUrlByUser          用户自定义请求地址\n     * @param image                 要编辑的图像\n     * @param imageVariationRequest 请求参数\n     * @return 图片信息\n     */\n    List<ImageObject> variationImageCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, File image, ImageVariationRequest imageVariationRequest);\n}\n"
  },
  {
    "path": "ai-openai/src/main/java/com/ai/openai/achieve/standard/session/ModelSession.java",
    "content": "package com.ai.openai.achieve.standard.session;\n\n\nimport com.ai.openai.endPoint.models.ModelObject;\nimport com.ai.openai.endPoint.models.resp.DeleteFineTuneModelResponse;\n\nimport java.util.List;\n\n/**\n * @Description: 模型会话窗口\n **/\npublic interface ModelSession {\n\n    /**\n     * 列出模型\n     *\n     * @param apiHostByUser 用户自定义 host\n     * @param apiKeyByUser  用户自定义密钥\n     * @param apiUrlByUser  用户自定义请求地址\n     * @return 模型列表\n     */\n    List<ModelObject> listModelCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser);\n\n    /**\n     * 检索模型\n     *\n     * @param apiHostByUser 用户自定义 host\n     * @param apiKeyByUser  用户自定义密钥\n     * @param apiUrlByUser  用户自定义请求地址\n     * @param model         模型ID\n     * @return 模型信息\n     */\n    ModelObject retrieveModelCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, String model);\n\n    /**\n     * 删除微调模型\n     *\n     * @param apiHostByUser 用户自定义 host\n     * @param apiKeyByUser  用户自定义密钥\n     * @param apiUrlByUser  用户自定义请求地址\n     * @param model         模型ID\n     * @return 删除状态\n     */\n    DeleteFineTuneModelResponse deleteFineTuneModelCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, String model);\n}\n"
  },
  {
    "path": "ai-openai/src/main/java/com/ai/openai/achieve/standard/session/ModerationSession.java",
    "content": "package com.ai.openai.achieve.standard.session;\n\n\nimport com.ai.openai.endPoint.moderations.req.ModerationRequest;\nimport com.ai.openai.endPoint.moderations.resp.ModerationResponse;\n\n/**\n * @Description: 审核会话窗口\n **/\npublic interface ModerationSession {\n    /**\n     * 审核\n     *\n     * @param apiHostByUser     用户自定义 host\n     * @param apiKeyByUser      用户自定义密钥\n     * @param apiUrlByUser      用户自定义请求地址\n     * @param moderationRequest 请求参数\n     * @return 审核结果\n     */\n    ModerationResponse moderationCompletions(String apiHostByUser, String apiKeyByUser, String apiUrlByUser, ModerationRequest moderationRequest);\n}\n"
  },
  {
    "path": "ai-openai/src/main/java/com/ai/openai/common/ApiUrl.java",
    "content": "package com.ai.openai.common;\n\nimport lombok.AllArgsConstructor;\nimport lombok.Getter;\n\n/**\n * 各接口API路径\n */\n@Getter\n@AllArgsConstructor\npublic enum ApiUrl {\n\n    v1_completions(\"/v1/completions\"),\n    v1_chat_completions(\"/v1/chat/completions\"),\n    v1_audio_speech(\"/v1/audio/speech\"),\n    v1_audio_transcriptions(\"/v1/audio/transcriptions\"),\n    v1_audio_translations(\"/v1/audio/translations\"),\n    v1_embeddings(\"/v1/embeddings\"),\n    v1_fine_tuning_jobs(\"/v1/fine_tuning/jobs\"),\n    v1_fine_tuning_jobs_fine_tuning_job_id(\"/v1/fine_tuning/jobs/{fine_tuning_job_id}\"),\n    v1_fine_tuning_jobs_fine_tuning_job_id_cancel(\"/v1/fine_tuning/jobs/{fine_tuning_job_id}/cancel\"),\n    v1_fine_tuning_jobs_fine_tuning_job_id_events(\"/v1/fine_tuning/jobs/{fine_tuning_job_id}/events\"),\n    ;\n\n    private String url;\n}\n"
  },
  {
    "path": "ai-openai/src/main/java/com/ai/openai/common/CommonListResponse.java",
    "content": "package com.ai.openai.common;\n\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport com.fasterxml.jackson.annotation.JsonProperty;\nimport lombok.AllArgsConstructor;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\n\nimport java.io.Serializable;\nimport java.util.List;\n\n/**\n * @Description: 通用返回类\n **/\n@Data\n@NoArgsConstructor\n@AllArgsConstructor\npublic class CommonListResponse<T> implements Serializable {\n    private String object;\n    private List<T> data;\n    private Error error;\n    @JsonProperty(\"has_more\")\n    private Boolean hasMore;\n\n    @Data\n    @JsonIgnoreProperties(ignoreUnknown = true)\n    public class Error {\n        private String message;\n        private String type;\n        private String param;\n        private String code;\n    }\n}\n"
  },
  {
    "path": "ai-openai/src/main/java/com/ai/openai/common/Usage.java",
    "content": "package com.ai.openai.common;\n\nimport com.fasterxml.jackson.annotation.JsonProperty;\nimport lombok.AllArgsConstructor;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\n\n@Data\n@AllArgsConstructor\n@NoArgsConstructor\npublic class Usage {\n\n    /**\n     * 请求消耗的token\n     */\n    @JsonProperty(\"prompt_tokens\")\n    private int promptTokens;\n\n    /**\n     * 回答消耗的token\n     */\n    @JsonProperty(\"completion_tokens\")\n    private int completionTokens;\n\n    /**\n     * 总共消耗的token\n     */\n    @JsonProperty(\"total_tokens\")\n    private int totalTokens;\n}\n"
  },
  {
    "path": "ai-openai/src/main/java/com/ai/openai/endPoint/audio/req/SttCompletionRequest.java",
    "content": "package com.ai.openai.endPoint.audio.req;\n\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport com.fasterxml.jackson.annotation.JsonInclude;\nimport com.fasterxml.jackson.annotation.JsonProperty;\nimport lombok.*;\nimport lombok.experimental.FieldNameConstants;\n\nimport java.io.File;\nimport java.io.Serializable;\n\n@Data\n@Builder\n@NoArgsConstructor\n@AllArgsConstructor\n@FieldNameConstants\n@JsonIgnoreProperties(ignoreUnknown = true)\n@JsonInclude(JsonInclude.Include.NON_NULL)\npublic class SttCompletionRequest implements Serializable {\n\n    /**\n     * 要转录的音频文件对象（不是文件名）\n     * 采用以下格式之一：flac、mp3、mp4、mpeg、mpga、m4a、ogg、wav 或 webm\n     */\n    @NonNull\n    private File file;\n\n    /**\n     * 使用的模型名\n     */\n    @NonNull\n    @Builder.Default\n    private String model = Model.whisper_1.getModuleName();\n\n    /**\n     * 音频的语言，以 ISO-639-1 格式提供输入语言将提高准确性和延迟。\n     */\n    private String language;\n\n    /**\n     * 一个可选文本，用于指导模型的样式或继续上一个音频片段。提示应与音频语言匹配。\n     */\n    private String prompt;\n\n    /**\n     * 脚本输出的格式\n     */\n    @JsonProperty(\"response_format\")\n    private String responseFormat;\n\n    /**\n     * 采样温度，介于 0 和 1 之间，默认值为 0 。\n     * 较高的值（如 0.8）将使输出更加随机，而较低的值（如 0.2）将使其更具针对性和确定性。\n     * 如果设置为 0，模型将使用对数概率自动提高温度，直到达到某些阈值。\n     */\n    private Double temperature;\n\n    @Getter\n    @AllArgsConstructor\n    public enum Model {\n        whisper_1(\"whisper-1\");\n        private String moduleName;\n    }\n\n}\n"
  },
  {
    "path": "ai-openai/src/main/java/com/ai/openai/endPoint/audio/req/TtsCompletionRequest.java",
    "content": "package com.ai.openai.endPoint.audio.req;\n\nimport com.ai.openai.endPoint.chat.req.BaseChatCompletionRequest;\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport com.fasterxml.jackson.annotation.JsonInclude;\nimport com.fasterxml.jackson.annotation.JsonProperty;\nimport lombok.*;\n\nimport java.io.Serializable;\n\n@Data\n@Builder\n@NoArgsConstructor\n@AllArgsConstructor\n@JsonIgnoreProperties(ignoreUnknown = true)\n@JsonInclude(JsonInclude.Include.NON_NULL)\npublic class TtsCompletionRequest implements Serializable {\n\n    /**\n     * 要使用的模型的 ID\n     */\n    @Builder.Default\n    private String model = BaseChatCompletionRequest.Model.GPT_3_5_TURBO.getModuleName();\n\n    /**\n     * 要为其生成音频的文本，最大长度为4096个字符\n     */\n    @NonNull\n    private String input;\n\n    /**\n     * 声音样式\n     */\n    @NonNull\n    private String voice;\n\n    /**\n     * 音频输入的格式，默认为mp3\n     */\n    @JsonProperty(\"response_format\")\n    private String responseFormat;\n\n    /**\n     * 音频的速度，0.25 到 4.0 之中选取一个数，数字越大速度越快。默认为1。\n     */\n    private String speed;\n\n    /**\n     * 构造基础请求内容\n     *\n     * @param input 文本内容\n     * @return 文本转语言请求参数\n     */\n    public static TtsCompletionRequest baseBuild(String input) {\n        return TtsCompletionRequest\n                .builder()\n                .input(input)\n                .voice(Voice.alloy.getVoiceName())\n                .model(Model.tts_1.getModuleName())\n                .build();\n    }\n\n    @Getter\n    @AllArgsConstructor\n    public enum Model {\n        tts_1(\"tts-1\"), tts_1_hd(\"tts-1-hd\");\n        private String moduleName;\n    }\n\n    /**\n     * 声音样式\n     */\n    @Getter\n    @AllArgsConstructor\n    public enum Voice {\n        alloy(\"alloy\"),\n        echo(\"echo\"),\n        fable(\"fable\"),\n        onyx(\"onyx\"),\n        nova(\"nova\"),\n        shimmer(\"shimmer\");\n        private String voiceName;\n    }\n\n\n}\n"
  },
  {
    "path": "ai-openai/src/main/java/com/ai/openai/endPoint/audio/resp/SttCompletionResponse.java",
    "content": "package com.ai.openai.endPoint.audio.resp;\n\n\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport com.fasterxml.jackson.annotation.JsonInclude;\nimport lombok.AllArgsConstructor;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\n\nimport java.io.Serializable;\n\n@Data\n@NoArgsConstructor\n@AllArgsConstructor\n@JsonIgnoreProperties(ignoreUnknown = true)\n@JsonInclude(JsonInclude.Include.NON_NULL)\npublic class SttCompletionResponse implements Serializable {\n    /**\n     * 转换之后得到的文本\n     */\n    private String text;\n}\n"
  },
  {
    "path": "ai-openai/src/main/java/com/ai/openai/endPoint/chat/ChatChoice.java",
    "content": "package com.ai.openai.endPoint.chat;\n\nimport com.ai.openai.endPoint.chat.msg.DefaultMessage;\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport com.fasterxml.jackson.annotation.JsonInclude;\nimport com.fasterxml.jackson.annotation.JsonProperty;\nimport lombok.AllArgsConstructor;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\n\nimport java.io.Serializable;\n\n/**\n * @Description: 聊天接口模型返回的信息\n **/\n@Data\n@NoArgsConstructor\n@AllArgsConstructor\n@JsonIgnoreProperties(ignoreUnknown = true)\n@JsonInclude(JsonInclude.Include.NON_NULL)\npublic class ChatChoice implements Serializable {\n\n    private long index;\n\n    /**\n     * stream = true时，由流式模型响应生成的聊天完成增量\n     */\n    private DefaultMessage delta;\n\n    /**\n     * stream = false时，模型生成的聊天完成消息\n     */\n    private DefaultMessage message;\n\n    /**\n     * 模型停止生成令牌的原因\n     */\n    @JsonProperty(\"finish_reason\")\n    private String finishReason;\n\n}\n"
  },
  {
    "path": "ai-openai/src/main/java/com/ai/openai/endPoint/chat/Parameters.java",
    "content": "package com.ai.openai.endPoint.chat;\n\nimport lombok.AllArgsConstructor;\nimport lombok.Builder;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\n\nimport java.io.Serializable;\nimport java.util.List;\n\n@Data\n@Builder\n@AllArgsConstructor\n@NoArgsConstructor\npublic class Parameters implements Serializable {\n\n    /**\n     * 参数类型\n     */\n    private String type;\n\n    /**\n     * 参数属性、描述\n     */\n    private Object properties;\n\n    /**\n     * 方法必输字段\n     */\n    private List<String> required;\n\n}\n"
  },
  {
    "path": "ai-openai/src/main/java/com/ai/openai/endPoint/chat/QaChoice.java",
    "content": "package com.ai.openai.endPoint.chat;\n\nimport com.fasterxml.jackson.annotation.JsonProperty;\nimport lombok.AllArgsConstructor;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\n\nimport java.io.Serializable;\n\n/**\n * @Description: 简单问答模型返回的信息\n **/\n@Data\n@AllArgsConstructor\n@NoArgsConstructor\npublic class QaChoice implements Serializable {\n\n    /**\n     * 回答内容\n     */\n    private String text;\n\n    private int index;\n\n    private Object logprobs;\n\n    /**\n     * 模型停止生成令牌的原因\n     */\n    @JsonProperty(\"finish_reason\")\n    private String finishReason;\n}\n"
  },
  {
    "path": "ai-openai/src/main/java/com/ai/openai/endPoint/chat/ResponseFormat.java",
    "content": "package com.ai.openai.endPoint.chat;\n\nimport lombok.*;\n\n/**\n * @Author: jianglinhong\n * @Description: TODO\n * @DateTime: 2023/12/8 14:22\n **/\n@Data\n@Builder\n@AllArgsConstructor\n@NoArgsConstructor\npublic class ResponseFormat {\n\n    /**\n     * 默认：text\n     */\n    private String type;\n\n    @Getter\n    @AllArgsConstructor\n    public enum Type {\n        JSON_OBJECT(\"json_object\"),\n        TEXT(\"text\"),\n        ;\n        private final String name;\n    }\n}\n"
  },
  {
    "path": "ai-openai/src/main/java/com/ai/openai/endPoint/chat/msg/BaseMessage.java",
    "content": "package com.ai.openai.endPoint.chat.msg;\n\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport com.fasterxml.jackson.annotation.JsonInclude;\nimport lombok.AllArgsConstructor;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\nimport lombok.experimental.SuperBuilder;\n\nimport java.io.Serializable;\n\n/**\n * @description 基础问答信息\n */\n@Data\n@SuperBuilder\n@NoArgsConstructor\n@AllArgsConstructor\n@JsonInclude(JsonInclude.Include.NON_NULL)\n@JsonIgnoreProperties(ignoreUnknown = true)\npublic class BaseMessage implements Serializable {\n\n    /**\n     * 角色：system、user、assistant\n     */\n    private String role;\n\n    private String name;\n\n}\n"
  },
  {
    "path": "ai-openai/src/main/java/com/ai/openai/endPoint/chat/msg/Content.java",
    "content": "package com.ai.openai.endPoint.chat.msg;\n\nimport com.fasterxml.jackson.annotation.JsonInclude;\nimport com.fasterxml.jackson.annotation.JsonProperty;\nimport lombok.*;\n\n/**\n * @Description: 图片问答信息\n **/\n@Data\n@Builder\n@NoArgsConstructor\n@AllArgsConstructor\n@JsonInclude(JsonInclude.Include.NON_NULL)\npublic class Content {\n\n    /**\n     * 输入类型\n     */\n    private String type;\n\n    /**\n     * 问题内容\n     */\n    private String text;\n\n    /**\n     * 图片地址\n     */\n    @JsonProperty(\"image_url\")\n    private ImageUrl imageUrl;\n\n    /**\n     * 构建 text 类型的 content\n     */\n    public static Content BuildTextContent(String text) {\n        return Content.builder().type(Type.TEXT.getName()).text(text).build();\n    }\n\n    /**\n     * 构建 image_url 类型的 content\n     */\n    public static Content BuildImageUrlContent(String urlOrB64Json) {\n        return Content.builder().type(Type.IMAGE_URL.getName()).text(urlOrB64Json).build();\n    }\n\n    /**\n     * 输入类型\n     */\n    @Getter\n    @AllArgsConstructor\n    public enum Type {\n        TEXT(\"text\"),\n        IMAGE_URL(\"image_url\"),\n        ;\n        private final String name;\n    }\n}\n"
  },
  {
    "path": "ai-openai/src/main/java/com/ai/openai/endPoint/chat/msg/DefaultMessage.java",
    "content": "package com.ai.openai.endPoint.chat.msg;\n\nimport com.ai.openai.endPoint.chat.tools.ToolCall;\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport com.fasterxml.jackson.annotation.JsonInclude;\nimport com.fasterxml.jackson.annotation.JsonProperty;\nimport lombok.AllArgsConstructor;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\nimport lombok.experimental.SuperBuilder;\n\nimport java.io.Serializable;\nimport java.util.List;\n\n/**\n * @Description: 默认问答内容\n **/\n@Data\n@SuperBuilder\n@NoArgsConstructor\n@AllArgsConstructor\n@JsonIgnoreProperties(ignoreUnknown = true)\n@JsonInclude(JsonInclude.Include.NON_NULL)\npublic class DefaultMessage extends BaseMessage implements Serializable {\n\n    /**\n     * 问答内容\n     */\n    private String content;\n\n    /**\n     * 函数式对话时，返回的函数信息\n     */\n    @JsonProperty(\"tool_calls\")\n    private List<ToolCall> toolCalls;\n\n}\n"
  },
  {
    "path": "ai-openai/src/main/java/com/ai/openai/endPoint/chat/msg/ImageUrl.java",
    "content": "package com.ai.openai.endPoint.chat.msg;\n\nimport com.fasterxml.jackson.annotation.JsonInclude;\nimport lombok.AllArgsConstructor;\nimport lombok.Builder;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\n\n/**\n * @Description: 图片问答时，图片的URL\n **/\n@Data\n@Builder\n@JsonInclude(JsonInclude.Include.NON_NULL)\n@NoArgsConstructor\n@AllArgsConstructor\npublic class ImageUrl {\n    /**\n     * 图片地址\n     */\n    private String url;\n}\n"
  },
  {
    "path": "ai-openai/src/main/java/com/ai/openai/endPoint/chat/msg/ImgMessage.java",
    "content": "package com.ai.openai.endPoint.chat.msg;\n\nimport com.fasterxml.jackson.annotation.JsonInclude;\nimport lombok.AllArgsConstructor;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\nimport lombok.experimental.SuperBuilder;\n\nimport java.io.Serializable;\nimport java.util.List;\n\n/**\n * @Description: 图片输入\n **/\n@Data\n@SuperBuilder\n@NoArgsConstructor\n@AllArgsConstructor\n@JsonInclude(JsonInclude.Include.NON_NULL)\npublic class ImgMessage extends BaseMessage implements Serializable {\n\n    /**\n     * 图片对话内容\n     */\n    private List<Content> content;\n\n    /**\n     * 添加类型为 text 的对话内容\n     */\n    public void addTextContent(String text) {\n        addContent(Content.builder().type(Content.Type.TEXT.getName()).text(text).build());\n    }\n\n    /**\n     * 添加类型为 image_url 的对话内容\n     */\n    public void addImageContent(String imageUrl) {\n        addContent(Content.builder()\n                .text(Content.Type.IMAGE_URL.getName())\n                .imageUrl(ImageUrl.builder().url(imageUrl).build())\n                .build());\n    }\n\n    /**\n     * 添加对话内容\n     */\n    public void addContent(Content content) {\n        this.content.add(content);\n    }\n\n}\n"
  },
  {
    "path": "ai-openai/src/main/java/com/ai/openai/endPoint/chat/req/BaseChatCompletionRequest.java",
    "content": "package com.ai.openai.endPoint.chat.req;\n\nimport com.ai.openai.endPoint.chat.ResponseFormat;\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport com.fasterxml.jackson.annotation.JsonInclude;\nimport com.fasterxml.jackson.annotation.JsonProperty;\nimport lombok.*;\nimport lombok.experimental.SuperBuilder;\n\nimport java.io.Serializable;\nimport java.util.List;\nimport java.util.Map;\n\n@Data\n@SuperBuilder\n@NoArgsConstructor\n@AllArgsConstructor\n@JsonIgnoreProperties(ignoreUnknown = true)\n@JsonInclude(JsonInclude.Include.NON_NULL)\npublic class BaseChatCompletionRequest implements Serializable {\n\n    /**\n     * 要使用的模型的 ID\n     */\n    @Builder.Default\n    private String model = Model.GPT_3_5_TURBO.getModuleName();\n\n    /**\n     * 介于 -2.0 和 2.0 之间的数字，默认值为 0\n     * 正值会根据新标记在文本中的现有频率来惩罚新标记从而降低模型逐字重复同一行的可能性\n     */\n    @JsonProperty(\"frequency_penalty\")\n    private Double frequencyPenalty;\n\n    /**\n     * 修改指定标记出现的可能性，默认值为 null\n     */\n    @JsonProperty(\"logit_bias\")\n    private Map logitBias;\n\n    /**\n     * 输出字符串限制；0 ~ 4096\n     */\n    @JsonProperty(\"max_tokens\")\n    private Integer maxTokens;\n\n    /**\n     * 为每个提示生成的完成次数，默认值为 1\n     */\n    private Integer n;\n\n    /**\n     * 介于 -2.0 和 2.0 之间的数字，默认值为 0\n     * 正值会根据新标记到目前为止是否出现在文本中来惩罚它们从而增加模型谈论新主题的可能性\n     */\n    @JsonProperty(\"presence_penalty\")\n    private Double presencePenalty;\n\n    /**\n     * 指定模型必须输出的格式的对象。\n     */\n    @JsonProperty(\"response_format\")\n    private ResponseFormat responseFormat;\n\n    private Integer seed;\n\n    /**\n     * 停止输出标识，默认值为 null\n     * 最多 4 个序列，API 将停止生成更多令牌\n     */\n    private List<String> stop;\n\n    /**\n     * 使用什么采样温度，介于 0 和 2 之间，默认值为 1\n     * 较高的值（如 0.8）将使输出更加随机，而较低的值（如 0.2）将使其更具集中性和确定性\n     */\n    private Double temperature;\n\n    /**\n     * 默认值为 1\n     * 温度采样的替代方法，称为核采样，其中模型考虑具有top_p概率质量的标记的结果。因此，0.1 表示仅考虑包含前 10% 概率质量的代币。\n     */\n    @JsonProperty(\"top_p\")\n    private Double topP;\n\n    /**\n     * 调用标识，避免重复调用\n     */\n    private String user;\n\n    @Getter\n    @AllArgsConstructor\n    public enum Model {\n        GPT_3_5_TURBO(\"gpt-3.5-turbo\"), GPT_4(\"gpt-4\"), GPT_4_32K(\"gpt-4-32k\"),\n        GPT_4_VISION_PREVIEW(\"gpt-4-vision-preview\"),\n        ;\n        private String moduleName;\n    }\n}\n\n"
  },
  {
    "path": "ai-openai/src/main/java/com/ai/openai/endPoint/chat/req/DefaultChatCompletionRequest.java",
    "content": "package com.ai.openai.endPoint.chat.req;\n\nimport com.ai.core.exception.Constants;\nimport com.ai.openai.endPoint.chat.msg.DefaultMessage;\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport com.fasterxml.jackson.annotation.JsonInclude;\nimport lombok.AllArgsConstructor;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\nimport lombok.NonNull;\nimport lombok.experimental.SuperBuilder;\n\nimport java.io.Serializable;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\n\n/**\n * @Description: 默认对话方式\n **/\n@Data\n@SuperBuilder\n@NoArgsConstructor\n@AllArgsConstructor\n@JsonIgnoreProperties(ignoreUnknown = true)\n@JsonInclude(JsonInclude.Include.NON_NULL)\npublic class DefaultChatCompletionRequest extends BaseChatCompletionRequest implements Serializable {\n\n    /**\n     * 构成对话的消息列表\n     */\n    @NonNull\n    private List<DefaultMessage> messages;\n\n    /**\n     * 是否为流式输出，默认值为 false\n     */\n    private Boolean stream;\n\n    /**\n     * 构造基础的 DefaultChatCompletionRequest\n     *\n     * @param question 问题内容\n     */\n    public static DefaultChatCompletionRequest baseBuild(String question) {\n        return DefaultChatCompletionRequest\n                .builder()\n                .messages(new ArrayList<>(Collections.singletonList(DefaultMessage.builder().role(Constants.Role.USER.getRoleName()).content(question).build())))\n                .build();\n    }\n\n    /**\n     * 上下文对话时，添加问答内容\n     *\n     * @param message 问答内容\n     */\n    public void addMessage(DefaultMessage message) {\n        this.messages.add(message);\n    }\n\n    /**\n     * 上下文对话时，添加问答内容\n     *\n     * @param role    角色\n     * @param content 内容\n     */\n    public void addMessage(String role, String content) {\n        this.addMessage(DefaultMessage.builder().role(role).content(content).build());\n    }\n\n}\n"
  },
  {
    "path": "ai-openai/src/main/java/com/ai/openai/endPoint/chat/req/FuncChatCompletionRequest.java",
    "content": "package com.ai.openai.endPoint.chat.req;\n\nimport com.ai.core.exception.Constants;\nimport com.ai.openai.endPoint.chat.msg.DefaultMessage;\nimport com.ai.openai.endPoint.chat.tools.Tool;\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport com.fasterxml.jackson.annotation.JsonInclude;\nimport com.fasterxml.jackson.annotation.JsonProperty;\nimport lombok.AllArgsConstructor;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\nimport lombok.NonNull;\nimport lombok.experimental.SuperBuilder;\n\nimport java.io.Serializable;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\n\n/**\n * @Description: 函数式对话\n **/\n@Data\n@SuperBuilder\n@NoArgsConstructor\n@AllArgsConstructor\n@JsonIgnoreProperties(ignoreUnknown = true)\n@JsonInclude(JsonInclude.Include.NON_NULL)\npublic class FuncChatCompletionRequest extends BaseChatCompletionRequest implements Serializable {\n\n    /**\n     * 构成对话的消息列表\n     */\n    @NonNull\n    private List<DefaultMessage> messages;\n\n    /**\n     * 模型可能调用的工具列表。当前版本仅支持：functions\n     */\n    private List<Tool> tools;\n\n    /**\n     * 控制模型调用哪个（如果有）函数。\n     */\n    @JsonProperty(\"tool_choice\")\n    private Object toolChoice;\n\n    /**\n     * 构造基础的 DefaultChatCompletionRequest\n     *\n     * @param question 问题内容\n     */\n    public static FuncChatCompletionRequest baseBuild(String question) {\n        return FuncChatCompletionRequest.builder()\n                .messages(new ArrayList<>(Collections.singletonList(DefaultMessage.builder().role(Constants.Role.USER.getRoleName()).content(question).build())))\n                .build();\n    }\n\n    /**\n     * 上下文对话时，添加问答内容\n     *\n     * @param message 问答内容\n     */\n    public void addMessage(DefaultMessage message) {\n        this.messages.add(message);\n    }\n\n    /**\n     * 上下文对话时，添加问答内容\n     *\n     * @param role    角色\n     * @param content 内容\n     */\n    public void addMessage(String role, String content) {\n        this.addMessage(DefaultMessage.builder().role(role).content(content).build());\n    }\n\n\n}\n"
  },
  {
    "path": "ai-openai/src/main/java/com/ai/openai/endPoint/chat/req/ImgChatCompletionRequest.java",
    "content": "package com.ai.openai.endPoint.chat.req;\n\nimport com.ai.openai.endPoint.chat.msg.ImgMessage;\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport com.fasterxml.jackson.annotation.JsonInclude;\nimport lombok.AllArgsConstructor;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\nimport lombok.NonNull;\nimport lombok.experimental.SuperBuilder;\n\nimport java.io.Serializable;\nimport java.util.List;\n\n/**\n * @Description: 输入图片对话\n **/\n@Data\n@SuperBuilder\n@NoArgsConstructor\n@AllArgsConstructor\n@JsonIgnoreProperties(ignoreUnknown = true)\n@JsonInclude(JsonInclude.Include.NON_NULL)\npublic class ImgChatCompletionRequest extends BaseChatCompletionRequest implements Serializable {\n\n    /**\n     * 构成对话的消息列表\n     */\n    @NonNull\n    private List<ImgMessage> messages;\n\n}\n"
  },
  {
    "path": "ai-openai/src/main/java/com/ai/openai/endPoint/chat/req/QaCompletionRequest.java",
    "content": "package com.ai.openai.endPoint.chat.req;\n\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport com.fasterxml.jackson.annotation.JsonInclude;\nimport com.fasterxml.jackson.annotation.JsonProperty;\nimport lombok.*;\n\nimport java.io.Serializable;\nimport java.util.List;\nimport java.util.Map;\n\n@Builder\n@Data\n@NoArgsConstructor\n@AllArgsConstructor\n@JsonIgnoreProperties(ignoreUnknown = true)\n@JsonInclude(JsonInclude.Include.NON_NULL)\npublic class QaCompletionRequest implements Serializable {\n\n    /**\n     * 要使用的模型的 ID\n     */\n    @Builder.Default\n    private String model = Model.GPT_3_5_TURBO.getModelName();\n\n    /**\n     * 问题描述\n     */\n    @NonNull\n    private String prompt;\n\n    /**\n     * 默认值为 1\n     * 在服务器端生成回答并返回“最佳”（每个令牌的对数概率最高的一个）。无法流式传输结果。\n     */\n    @JsonProperty(\"best_of\")\n    private Integer bestOf;\n\n    /**\n     * 介于 -2.0 和 2.0 之间的数字，默认值为 0\n     * 正值会根据新标记在文本中的现有频率来惩罚新标记从而降低模型逐字重复同一行的可能性\n     */\n    @JsonProperty(\"frequency_penalty\")\n    private Double frequencyPenalty;\n\n    /**\n     * 修改指定标记出现的可能性，默认值为 null\n     */\n    @JsonProperty(\"logit_bias\")\n    private Map logitBias;\n\n    /**\n     * 默认值为 null\n     * 包括最有可能的令牌以及所选令牌的对数概率。\n     */\n    private Integer logprobs;\n\n    /**\n     * 输出字符串限制；0 ~ 4096\n     */\n    @JsonProperty(\"max_tokens\")\n    private Integer maxTokens;\n\n    /**\n     * 为每个提示生成的完成次数，默认值为 1\n     */\n    private Integer n;\n\n    /**\n     * 介于 -2.0 和 2.0 之间的数字，默认值为 0\n     * 正值会根据新标记到目前为止是否出现在文本中来惩罚它们从而增加模型谈论新主题的可能性\n     */\n    @JsonProperty(\"presence_penalty\")\n    private Double presencePenalty;\n\n    /**\n     * 停止输出标识，默认值为 null\n     * 最多 4 个序列，API 将停止生成更多令牌\n     */\n    private List<String> stop;\n\n    /**\n     * 是否为流式输出，默认值为 false\n     */\n    private Boolean stream;\n\n    /**\n     * 使用什么采样温度，介于 0 和 2 之间，默认值为 1\n     * 较高的值（如 0.8）将使输出更加随机，而较低的值（如 0.2）将使其更具集中性和确定性\n     */\n    private Double temperature;\n\n    /**\n     * 默认值为 1\n     * 温度采样的替代方法，称为核采样，其中模型考虑具有top_p概率质量的标记的结果。因此，0.1 表示仅考虑包含前 10% 概率质量的代币。\n     */\n    @JsonProperty(\"top_p\")\n    private Double topP = 1d;\n\n    /**\n     * 调用标识，避免重复调用\n     */\n    private String user;\n\n    /**\n     * 构造基础请求内容\n     *\n     * @param question 问题内容\n     * @return 简单问答请求体\n     */\n    public static QaCompletionRequest baseBuild(String question) {\n        return QaCompletionRequest.builder().prompt(question).build();\n    }\n\n    @Getter\n    @AllArgsConstructor\n    public enum Model {\n        GPT_3_5_TURBO(\"gpt-3.5-turbo-instruct\"), GPT_4(\"gpt-4\"), GPT_4_32K(\"gpt-4-32k\"),\n        ;\n        private String modelName;\n    }\n}\n"
  },
  {
    "path": "ai-openai/src/main/java/com/ai/openai/endPoint/chat/resp/ChatCompletionResponse.java",
    "content": "package com.ai.openai.endPoint.chat.resp;\n\nimport com.ai.openai.common.Usage;\nimport com.ai.openai.endPoint.chat.ChatChoice;\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport com.fasterxml.jackson.annotation.JsonInclude;\nimport com.fasterxml.jackson.annotation.JsonProperty;\nimport lombok.AllArgsConstructor;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\n\nimport java.io.Serializable;\nimport java.util.List;\n\n/**\n * @description 聊天请求结果信息\n */\n@Data\n@NoArgsConstructor\n@AllArgsConstructor\n@JsonIgnoreProperties(ignoreUnknown = true)\n@JsonInclude(JsonInclude.Include.NON_NULL)\npublic class ChatCompletionResponse implements Serializable {\n\n    /**\n     * 完成的唯一标识符\n     */\n    private String id;\n\n    /**\n     * 对话信息\n     */\n    private List<ChatChoice> choices;\n\n    /**\n     * 对象\n     */\n    private String object;\n\n    /**\n     * 创建完成时的 Unix 时间戳（以秒为单位）。\n     */\n    private Long created;\n\n    /**\n     * 用于完成的模型\n     */\n    private String model;\n\n    @JsonProperty(\"system_fingerprint\")\n    private String systemFingerprint;\n\n    /**\n     * 结束原因\n     */\n    @JsonProperty(\"finish_reason\")\n    private String finishReason;\n\n    /**\n     * 完成请求的使用情况统计信息\n     */\n    private Usage usage;\n\n}\n"
  },
  {
    "path": "ai-openai/src/main/java/com/ai/openai/endPoint/chat/resp/QaCompletionResponse.java",
    "content": "package com.ai.openai.endPoint.chat.resp;\n\n\nimport com.ai.openai.common.Usage;\nimport com.ai.openai.endPoint.chat.QaChoice;\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport com.fasterxml.jackson.annotation.JsonInclude;\nimport lombok.AllArgsConstructor;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\n\nimport java.io.Serializable;\nimport java.util.List;\n\n/**\n * @Description: 简单问答返回信息\n **/\n@Data\n@NoArgsConstructor\n@AllArgsConstructor\n@JsonIgnoreProperties(ignoreUnknown = true)\n@JsonInclude(JsonInclude.Include.NON_NULL)\npublic class QaCompletionResponse implements Serializable {\n\n    /**\n     * 完成的唯一标识符\n     */\n    private String id;\n\n    /**\n     * 模型为输入提示生成的完成选项列表\n     */\n    private List<QaChoice> choices;\n\n    /**\n     * 创建完成时的 Unix 时间戳（以秒为单位）。\n     */\n    private Long created;\n\n    /**\n     * 用于完成的模型\n     */\n    private String model;\n\n    /**\n     * 对象类型，始终为“text_completion”\n     */\n    private String object;\n\n    /**\n     * 完成请求的使用情况统计信息\n     */\n    private Usage usage;\n\n}\n"
  },
  {
    "path": "ai-openai/src/main/java/com/ai/openai/endPoint/chat/tools/Tool.java",
    "content": "package com.ai.openai.endPoint.chat.tools;\n\nimport lombok.*;\n\nimport java.io.Serializable;\n\n@Data\n@Builder\n@AllArgsConstructor\n@NoArgsConstructor\npublic class Tool implements Serializable {\n\n    /**\n     * 目前只支持：function\n     *\n     * @see Type\n     */\n    private String type;\n\n    private ToolFunction function;\n\n    @Getter\n    @AllArgsConstructor\n    public enum Type {\n        FUNCTION(\"function\"),\n        ;\n        private final String name;\n    }\n}\n"
  },
  {
    "path": "ai-openai/src/main/java/com/ai/openai/endPoint/chat/tools/ToolCall.java",
    "content": "package com.ai.openai.endPoint.chat.tools;\n\nimport lombok.*;\n\nimport java.io.Serializable;\n\n/**\n * @Description: 函数式对话返回的函数信息\n **/\n@Data\n@Builder\n@AllArgsConstructor\n@NoArgsConstructor\npublic class ToolCall implements Serializable {\n\n    private String id;\n\n    private String type;\n\n    private ToolCallFunction function;\n\n    @Getter\n    @AllArgsConstructor\n    public enum Type {\n        FUNCTION(\"function\"),\n        ;\n        private final String name;\n    }\n}\n"
  },
  {
    "path": "ai-openai/src/main/java/com/ai/openai/endPoint/chat/tools/ToolCallFunction.java",
    "content": "package com.ai.openai.endPoint.chat.tools;\n\nimport lombok.AllArgsConstructor;\nimport lombok.Builder;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\n\nimport java.io.Serializable;\n\n/**\n * @Description: TODO\n **/\n@Data\n@Builder\n@AllArgsConstructor\n@NoArgsConstructor\npublic class ToolCallFunction implements Serializable {\n    /**\n     * 方法名\n     */\n    private String name;\n    /**\n     * 方法参数\n     */\n    private String arguments;\n}\n"
  },
  {
    "path": "ai-openai/src/main/java/com/ai/openai/endPoint/chat/tools/ToolFunction.java",
    "content": "package com.ai.openai.endPoint.chat.tools;\n\nimport com.ai.openai.endPoint.chat.Parameters;\nimport lombok.AllArgsConstructor;\nimport lombok.Builder;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\n\nimport java.io.Serializable;\n\n@Data\n@Builder\n@AllArgsConstructor\n@NoArgsConstructor\npublic class ToolFunction implements Serializable {\n\n    /**\n     * 要调用的函数的名称。必须是 a-z、A-Z、0-9 或包含下划线和短划线，最大长度为 64。\n     */\n    private String name;\n\n    /**\n     * 对函数所执行操作的描述，模型使用它来选择何时以及如何调用该函数。\n     */\n    private String description;\n\n    /**\n     * 函数接受的参数，描述为 JSON 架构对象。\n     */\n    private Parameters parameters;\n\n}\n"
  },
  {
    "path": "ai-openai/src/main/java/com/ai/openai/endPoint/embeddings/EmbeddingObject.java",
    "content": "package com.ai.openai.endPoint.embeddings;\n\nimport com.fasterxml.jackson.annotation.JsonIgnore;\nimport lombok.AllArgsConstructor;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\n\nimport java.io.Serializable;\n\n\n@Data\n@AllArgsConstructor\n@NoArgsConstructor\npublic class EmbeddingObject implements Serializable {\n\n    /**\n     * 嵌入的内容\n     */\n    @JsonIgnore\n    private String content;\n\n    /**\n     * 嵌入列表中嵌入的索引\n     */\n    private Integer index;\n\n    /**\n     * 嵌入向量，它是浮点数的列表\n     */\n    private double[] embedding;\n\n    /**\n     * 对象类型，始终为“embedding”。\n     */\n    private String object;\n\n}\n"
  },
  {
    "path": "ai-openai/src/main/java/com/ai/openai/endPoint/embeddings/req/EmbeddingCompletionRequest.java",
    "content": "package com.ai.openai.endPoint.embeddings.req;\n\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport com.fasterxml.jackson.annotation.JsonInclude;\nimport com.fasterxml.jackson.annotation.JsonProperty;\nimport lombok.*;\n\nimport java.io.Serializable;\nimport java.util.Arrays;\nimport java.util.List;\n\n@Data\n@Builder\n@NoArgsConstructor\n@AllArgsConstructor\n@JsonIgnoreProperties(ignoreUnknown = true)\n@JsonInclude(JsonInclude.Include.NON_NULL)\npublic class EmbeddingCompletionRequest implements Serializable {\n\n    /**\n     * 输入要嵌入的文本，编码为字符串或标记数组。\n     * 若要在单个请求中嵌入多个输入，请传递字符串数组或令牌数组。\n     */\n    @NonNull\n    private List<String> input;\n\n    /**\n     * 要使用的模型的 ID。\n     */\n    @Builder.Default\n    private String model = Model.TEXT_EMBEDDING_ADA_002.getModelName();\n\n    /**\n     * 要返回嵌入的格式。\n     */\n    @JsonProperty(\"encoding_format\")\n    private String encodingFormat;\n\n    /**\n     * 代表最终用户的唯一标识符\n     */\n    private String user;\n\n    /**\n     * 构造基础请求参数\n     *\n     * @param input 文本\n     * @return 请求参数\n     */\n    public static EmbeddingCompletionRequest baseBuild(String input) {\n        return baseBuild(Arrays.asList(input));\n    }\n\n    /**\n     * 构造基础请求参数\n     *\n     * @param inputList 文本数组\n     * @return 请求参数\n     */\n    public static EmbeddingCompletionRequest baseBuild(List<String> inputList) {\n        return EmbeddingCompletionRequest.builder().input(inputList).build();\n    }\n\n    @Getter\n    @AllArgsConstructor\n    public enum Model {\n        TEXT_EMBEDDING_ADA_002(\"text-embedding-ada-002\"),\n        ;\n        private final String modelName;\n    }\n\n}\n"
  },
  {
    "path": "ai-openai/src/main/java/com/ai/openai/endPoint/embeddings/resp/EmbeddingCompletionResponse.java",
    "content": "package com.ai.openai.endPoint.embeddings.resp;\n\nimport com.ai.openai.common.Usage;\nimport com.ai.openai.endPoint.embeddings.EmbeddingObject;\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport com.fasterxml.jackson.annotation.JsonInclude;\nimport lombok.AllArgsConstructor;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\n\nimport java.io.Serializable;\nimport java.util.List;\n\n@Data\n@NoArgsConstructor\n@AllArgsConstructor\n@JsonIgnoreProperties(ignoreUnknown = true)\n@JsonInclude(JsonInclude.Include.NON_NULL)\npublic class EmbeddingCompletionResponse implements Serializable {\n\n    /**\n     * 参考示例返回：\n     * {\n     * \"object\": \"list\",\n     * \"data\": [\n     * {\n     * \"object\": \"embedding\",\n     * \"embedding\": [\n     * 0.0023064255,\n     * -0.009327292,\n     * .... (1536 floats total for ada-002)\n     * -0.0028842222,\n     * ],\n     * \"index\": 0\n     * }\n     * ],\n     * \"model\": \"text-embedding-ada-002\",\n     * \"usage\": {\n     * \"prompt_tokens\": 8,\n     * \"total_tokens\": 8\n     * }\n     * }\n     */\n    private String object;\n\n    /**\n     * 结果数组\n     */\n    private List<EmbeddingObject> data;\n\n    private String model;\n\n    private Usage usage;\n\n\n}\n"
  },
  {
    "path": "ai-openai/src/main/java/com/ai/openai/endPoint/files/FileObject.java",
    "content": "package com.ai.openai.endPoint.files;\n\nimport com.fasterxml.jackson.annotation.JsonProperty;\nimport lombok.AllArgsConstructor;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\n\nimport java.io.Serializable;\n\n@Data\n@NoArgsConstructor\n@AllArgsConstructor\npublic class FileObject implements Serializable {\n\n    /**\n     * 文件标识符，可在 API 端点中引用\n     */\n    private String id;\n\n    /**\n     * 文件大小（以字节为单位）\n     */\n    private Long bytes;\n\n    /**\n     * 创建文件时的 Unix 时间戳（以秒为单位）\n     */\n    @JsonProperty(\"created_at\")\n    private Long createdAt;\n\n    /**\n     * 文件的名称\n     */\n    private String filename;\n\n    /**\n     * 对象类型，始终为:file\n     */\n    private String object;\n\n    /**\n     * 文件的预期用途\n     */\n    private String purpose;\n\n    /**\n     * 荒废的。文件的当前状态\n     */\n    @Deprecated\n    private String status;\n\n    /**\n     * 荒废的。有关微调训练文件验证失败的原因的详细信息\n     */\n    @Deprecated\n    @JsonProperty(\"status_details\")\n    private String statusDetails;\n}\n"
  },
  {
    "path": "ai-openai/src/main/java/com/ai/openai/endPoint/files/resp/DeleteFileResponse.java",
    "content": "package com.ai.openai.endPoint.files.resp;\n\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport com.fasterxml.jackson.annotation.JsonInclude;\nimport lombok.AllArgsConstructor;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\n\nimport java.io.Serializable;\n\n\n@Data\n@NoArgsConstructor\n@AllArgsConstructor\n@JsonIgnoreProperties(ignoreUnknown = true)\n@JsonInclude(JsonInclude.Include.NON_NULL)\npublic class DeleteFileResponse implements Serializable {\n\n    /**\n     * 文件ID\n     */\n    private String id;\n    private String object;\n    private Boolean deleted;\n\n}\n"
  },
  {
    "path": "ai-openai/src/main/java/com/ai/openai/endPoint/fineTuning/FineTuneError.java",
    "content": "package com.ai.openai.endPoint.fineTuning;\n\nimport lombok.AllArgsConstructor;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\n\nimport java.io.Serializable;\n\n@Data\n@NoArgsConstructor\n@AllArgsConstructor\npublic class FineTuneError implements Serializable {\n\n    /**\n     * 错误信息\n     */\n    private String message;\n\n    /**\n     * 错误类型\n     */\n    private String type;\n\n    /**\n     * 错误参数\n     */\n    private String param;\n\n    /**\n     * 错误码\n     */\n    private String code;\n\n}\n"
  },
  {
    "path": "ai-openai/src/main/java/com/ai/openai/endPoint/fineTuning/FineTuningEvent.java",
    "content": "package com.ai.openai.endPoint.fineTuning;\n\nimport com.fasterxml.jackson.annotation.JsonProperty;\nimport lombok.AllArgsConstructor;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\n\nimport java.io.Serializable;\n\n@Data\n@NoArgsConstructor\n@AllArgsConstructor\npublic class FineTuningEvent implements Serializable {\n\n    private String object;\n\n    private String id;\n\n    /**\n     * 创建微调作业时的 Unix 时间戳\n     */\n    @JsonProperty(\"created_at\")\n    private Long createdAt;\n\n    private String level;\n\n    private String message;\n\n    private String type;\n\n}\n"
  },
  {
    "path": "ai-openai/src/main/java/com/ai/openai/endPoint/fineTuning/HyperParameters.java",
    "content": "package com.ai.openai.endPoint.fineTuning;\n\nimport com.fasterxml.jackson.annotation.JsonInclude;\nimport com.fasterxml.jackson.annotation.JsonProperty;\nimport lombok.AllArgsConstructor;\nimport lombok.Builder;\nimport lombok.Getter;\nimport lombok.NoArgsConstructor;\nimport lombok.extern.slf4j.Slf4j;\n\nimport java.io.Serializable;\n\n@Getter\n@Slf4j\n@Builder\n@JsonInclude(JsonInclude.Include.NON_NULL)\n@NoArgsConstructor\n@AllArgsConstructor\npublic class HyperParameters implements Serializable {\n\n    /**\n     * 每批样本数。较大的批量大小意味着模型参数 更新频率较低，但方差较低。\n     */\n    @JsonProperty(\"batch_size\")\n    private String batchSize;\n\n    /**\n     * 学习率的比例因子。较小的学习率可能有助于避免 过拟合。\n     */\n    @JsonProperty(\"learning_rate_multiplier\")\n    private String learningRateMultiplier;\n\n    /**\n     * 要训练模型的纪元数。一个纪元是指一个完整的周期 通过训练数据集。\n     */\n    @JsonProperty(\"n_epochs\")\n    private String nEpochs;\n\n}\n"
  },
  {
    "path": "ai-openai/src/main/java/com/ai/openai/endPoint/fineTuning/req/FineTuningRequest.java",
    "content": "package com.ai.openai.endPoint.fineTuning.req;\n\nimport com.ai.openai.endPoint.fineTuning.HyperParameters;\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport com.fasterxml.jackson.annotation.JsonInclude;\nimport com.fasterxml.jackson.annotation.JsonProperty;\nimport lombok.*;\n\nimport java.io.Serializable;\n\n@Data\n@Builder\n@NoArgsConstructor\n@AllArgsConstructor\n@JsonIgnoreProperties(ignoreUnknown = true)\n@JsonInclude(JsonInclude.Include.NON_NULL)\npublic class FineTuningRequest implements Serializable {\n\n    /**\n     * 微调的模型的名称\n     */\n    @Builder.Default\n    private String model = Model.GPT_3_5_TURBO_1106.getModelName();\n\n    /**\n     * 包含训练数据的已上传文件的 ID\n     */\n    @NonNull\n    @JsonProperty(\"training_file\")\n    private String trainingFile;\n\n    /**\n     * 用于微调作业的超参数\n     */\n    @JsonProperty(\"hyperparameters\")\n    private HyperParameters hyperParameters;\n\n    /**\n     * 最多 18 个字符的字符串，将添加到微调的模型名称中。\n     */\n    private String suffix;\n\n    /**\n     * 包含验证数据的上载文件的 ID\n     */\n    @JsonProperty(\"validation_file\")\n    private String validationFile;\n\n    @Getter\n    @AllArgsConstructor\n    public enum Model {\n        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\"),\n        ;\n        private final String modelName;\n    }\n}\n"
  },
  {
    "path": "ai-openai/src/main/java/com/ai/openai/endPoint/fineTuning/req/ListFineTuningRequest.java",
    "content": "package com.ai.openai.endPoint.fineTuning.req;\n\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport com.fasterxml.jackson.annotation.JsonInclude;\nimport lombok.AllArgsConstructor;\nimport lombok.Builder;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\n\nimport java.io.Serializable;\n\n@Data\n@Builder\n@NoArgsConstructor\n@AllArgsConstructor\n@JsonIgnoreProperties(ignoreUnknown = true)\n@JsonInclude(JsonInclude.Include.NON_NULL)\npublic class ListFineTuningRequest implements Serializable {\n\n    /**\n     * 上一个分页请求中最后一个作业的标识符\n     */\n    private String after;\n\n    /**\n     * 要检索的微调作业数\n     */\n    private Integer limit;\n\n}\n"
  },
  {
    "path": "ai-openai/src/main/java/com/ai/openai/endPoint/fineTuning/resp/FineTuningResponse.java",
    "content": "package com.ai.openai.endPoint.fineTuning.resp;\n\nimport com.ai.openai.endPoint.fineTuning.HyperParameters;\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport com.fasterxml.jackson.annotation.JsonInclude;\nimport com.fasterxml.jackson.annotation.JsonProperty;\nimport lombok.AllArgsConstructor;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\n\nimport java.io.Serializable;\nimport java.util.List;\n\n@Data\n@NoArgsConstructor\n@AllArgsConstructor\n@JsonIgnoreProperties(ignoreUnknown = true)\n@JsonInclude(JsonInclude.Include.NON_NULL)\npublic class FineTuningResponse implements Serializable {\n\n    /**\n     * 对象标识符，可在 API 端点中引用\n     */\n    private String id;\n\n    /**\n     * 创建微调作业时的 Unix 时间戳\n     */\n    @JsonProperty(\"created_at\")\n    private Long createdAt;\n\n    /**\n     * 对于具有的微调作业，这将包含有关失败原因的详细信息\n     */\n//    private FineTuneError error;\n\n    /**\n     * 正在创建的微调模型的名称。如果微调作业仍在运行，则该值将为 null\n     */\n    @JsonProperty(\"fine_tuned_model\")\n    private String fineTunedModel;\n\n    /**\n     * 微调作业完成时的 Unix 时间戳（以秒为单位）。如果微调作业仍在运行，则该值将为 null\n     */\n    @JsonProperty(\"finished_at\")\n    private Long finishedAt;\n\n    /**\n     * 用于微调作业的超参数\n     */\n    @JsonProperty(\"hyperparameters\")\n    private HyperParameters hyperparameters;\n\n    /**\n     * 正在微调的基本模型\n     */\n    private String model;\n\n    /**\n     * 对象类型，始终为“fine_tuning.job”\n     */\n    private String object;\n\n    /**\n     * 拥有微调作业的组织\n     */\n    @JsonProperty(\"organization_id\")\n    private String organizationId;\n\n    /**\n     * 微调作业的编译结果文件 ID\n     */\n    @JsonProperty(\"result_files\")\n    private List<String> resultFiles;\n\n    /**\n     * 微调作业的当前状态\n     */\n    private String status;\n\n    /**\n     * 此微调作业处理的计费令牌总数\n     */\n    @JsonProperty(\"trained_tokens\")\n    private Integer trainedTokens;\n\n    /**\n     * 用于训练的文件 ID\n     */\n    @JsonProperty(\"training_file\")\n    private String trainingFile;\n\n    /**\n     * 用于验证的文件 ID\n     */\n    @JsonProperty(\"validation_file\")\n    private String validationFile;\n\n}\n"
  },
  {
    "path": "ai-openai/src/main/java/com/ai/openai/endPoint/images/ImageObject.java",
    "content": "package com.ai.openai.endPoint.images;\n\nimport com.fasterxml.jackson.annotation.JsonProperty;\nimport lombok.AllArgsConstructor;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\n\n@Data\n@NoArgsConstructor\n@AllArgsConstructor\npublic class ImageObject {\n\n    private String url;\n    @JsonProperty(\"b64_json\")\n    private String b64Json;\n    @JsonProperty(\"revised_prompt\")\n    private String revisedPrompt;\n\n\n}\n"
  },
  {
    "path": "ai-openai/src/main/java/com/ai/openai/endPoint/images/req/CreateImageRequest.java",
    "content": "package com.ai.openai.endPoint.images.req;\n\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport com.fasterxml.jackson.annotation.JsonInclude;\nimport com.fasterxml.jackson.annotation.JsonProperty;\nimport lombok.*;\n\nimport java.io.Serializable;\n\n@Data\n@Builder\n@NoArgsConstructor\n@AllArgsConstructor\n@JsonIgnoreProperties(ignoreUnknown = true)\n@JsonInclude(JsonInclude.Include.NON_NULL)\npublic class CreateImageRequest implements Serializable {\n\n    /**\n     * 所需图像的文本描述。的最大长度为 1000 个字符，4000 个字符。\n     */\n    private String prompt;\n\n    /**\n     * 用于图像生成的模型\n     * <p>\n     * 默认为 dall-e-2\n     *\n     * @see Model\n     */\n    @Builder.Default\n    private String model = Model.DALL_E_2.getName();\n\n    /**\n     * 要生成的图像数。必须介于 1 和 10 之间，dall-e-3只能为1。\n     */\n    @Builder.Default\n    private Integer n = 1;\n\n    /**\n     * 将生成的图像的质量。 创建具有更精细细节和更高一致性的图像。\n     *\n     * @see Quality\n     */\n    private String quality;\n\n    /**\n     * 返回生成的图像的格式：url、b64_json\n     */\n    @JsonProperty(\"response_format\")\n    private String responseFormat;\n\n    /**\n     * 图片尺寸，默认值：1024x1024\n     * dall-e-2支持：256x256, 512x512, or 1024x1024\n     * dall-e-3支持：1024x1024, 1792x1024, or 1024x1792\n     */\n    private String size;\n\n    /**\n     * 生成的图像的样式。\n     * 此参数仅仅dall-e-3,取值范围：vivid、natural\n     * 默认值：vivid\n     *\n     * @see Style\n     */\n    private String style;\n\n    /**\n     * 代表最终用户的唯一标识符\n     */\n    private String user;\n\n    /**\n     * 构建基础请求内容\n     *\n     * @param prompt 提示词\n     * @return 请求参数\n     */\n    public static CreateImageRequest baseBuild(String prompt) {\n        return CreateImageRequest.builder().prompt(prompt).build();\n    }\n\n    /**\n     * 图片生成模型\n     */\n    @Getter\n    @AllArgsConstructor\n    public enum Model {\n        DALL_E_2(\"dall-e-2\"),\n        DALL_E_3(\"dall-e-3\"),\n        ;\n        private final String name;\n    }\n\n    /**\n     * 生成图片质量\n     */\n    @Getter\n    @AllArgsConstructor\n    public enum Quality {\n        STANDARD(\"standard\"),\n        HD(\"hd\"),\n        ;\n        private final String quality;\n    }\n\n    /**\n     * 生成图片风格\n     */\n    @Getter\n    @AllArgsConstructor\n    public enum Style {\n        VIVID(\"vivid\"),\n        NATURAL(\"natural\"),\n        ;\n        private final String style;\n    }\n\n    @Getter\n    @AllArgsConstructor\n    public enum Format {\n        URL(\"url\"),\n        B64JSON(\"b64_json\"),\n        ;\n        private final String format;\n    }\n\n\n}\n"
  },
  {
    "path": "ai-openai/src/main/java/com/ai/openai/endPoint/images/req/ImageEditRequest.java",
    "content": "package com.ai.openai.endPoint.images.req;\n\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport com.fasterxml.jackson.annotation.JsonInclude;\nimport com.fasterxml.jackson.annotation.JsonProperty;\nimport lombok.*;\n\nimport java.io.Serializable;\n\n@Data\n@Builder\n@NoArgsConstructor\n@AllArgsConstructor\n@JsonIgnoreProperties(ignoreUnknown = true)\n@JsonInclude(JsonInclude.Include.NON_NULL)\npublic class ImageEditRequest {\n\n    /**\n     * 必选项：描述文字，最多1000字符\n     */\n    @NonNull\n    private String prompt;\n\n    /**\n     * 为每个提示生成的完成次数。\n     */\n    @Builder.Default\n    private Integer n = 1;\n\n    /**\n     * 256x256\n     * 512x512\n     * 1024x1024\n     */\n    @Builder.Default\n    private String size = SizeEnum.size_1024.getName();\n\n    @JsonProperty(\"response_format\")\n    @Builder.Default\n    private String responseFormat = ResponseFormat.URL.getName();\n\n    private String user;\n\n    /**\n     * 构造基础请求参数\n     *\n     * @param prompt 提示词\n     * @return 请求参数\n     */\n    public static ImageEditRequest baseBuild(String prompt) {\n        return ImageEditRequest.builder().prompt(prompt).build();\n    }\n\n    @Getter\n    @AllArgsConstructor\n    public enum SizeEnum implements Serializable {\n        size_1024_1792(\"1024x1792\"),\n        size_1792_1024(\"1792x1024\"),\n        size_1024(\"1024x1024\"),\n        size_512(\"512x512\"),\n        size_256(\"256x256\"),\n        ;\n        private final String name;\n\n    }\n\n    @AllArgsConstructor\n    @Getter\n    public enum ResponseFormat implements Serializable {\n        URL(\"url\"),\n        B64_JSON(\"b64_json\"),\n        ;\n\n        private final String name;\n    }\n\n}\n"
  },
  {
    "path": "ai-openai/src/main/java/com/ai/openai/endPoint/images/req/ImageVariationRequest.java",
    "content": "package com.ai.openai.endPoint.images.req;\n\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport com.fasterxml.jackson.annotation.JsonInclude;\nimport com.fasterxml.jackson.annotation.JsonProperty;\nimport lombok.*;\nimport lombok.extern.slf4j.Slf4j;\n\nimport java.io.Serializable;\n\n@Slf4j\n@Data\n@Builder\n@NoArgsConstructor\n@AllArgsConstructor\n@JsonIgnoreProperties(ignoreUnknown = true)\n@JsonInclude(JsonInclude.Include.NON_NULL)\npublic class ImageVariationRequest {\n\n    /**\n     * 为每个提示生成的完成次数。\n     */\n    @Builder.Default\n    private Integer n = 1;\n    /**\n     * 256x256\n     * 512x512\n     * 1024x1024\n     */\n    @Builder.Default\n    private String size = SizeEnum.size_1024.getName();\n\n    @JsonProperty(\"response_format\")\n    @Builder.Default\n    private String responseFormat = ResponseFormat.URL.getName();\n\n    private String user;\n\n    @Getter\n    @AllArgsConstructor\n    public enum SizeEnum implements Serializable {\n        size_1024_1792(\"1024x1792\"),\n        size_1792_1024(\"1792x1024\"),\n        size_1024(\"1024x1024\"),\n        size_512(\"512x512\"),\n        size_256(\"256x256\"),\n        ;\n        private final String name;\n\n    }\n\n    @AllArgsConstructor\n    @Getter\n    public enum ResponseFormat implements Serializable {\n        URL(\"url\"),\n        B64_JSON(\"b64_json\"),\n        ;\n\n        private final String name;\n    }\n\n\n}\n"
  },
  {
    "path": "ai-openai/src/main/java/com/ai/openai/endPoint/images/resp/CreateImageResponse.java",
    "content": "package com.ai.openai.endPoint.images.resp;\n\nimport com.ai.openai.endPoint.images.ImageObject;\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport com.fasterxml.jackson.annotation.JsonInclude;\nimport lombok.AllArgsConstructor;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\n\nimport java.util.List;\n\n@Data\n@NoArgsConstructor\n@AllArgsConstructor\n@JsonIgnoreProperties(ignoreUnknown = true)\n@JsonInclude(JsonInclude.Include.NON_NULL)\npublic class CreateImageResponse {\n    private Long created;\n    private List<ImageObject> data;\n}\n"
  },
  {
    "path": "ai-openai/src/main/java/com/ai/openai/endPoint/models/ModelObject.java",
    "content": "package com.ai.openai.endPoint.models;\n\n\nimport com.fasterxml.jackson.annotation.JsonProperty;\nimport lombok.AllArgsConstructor;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\n\n@Data\n@AllArgsConstructor\n@NoArgsConstructor\npublic class ModelObject {\n\n    /**\n     * 模型标识符，可在 API 端点中引用。\n     */\n    private String id;\n\n    /**\n     * 对象类型，始终为“model”。\n     */\n    private String object;\n\n    /**\n     * 创建模型时的 Unix 时间戳（以秒为单位）。\n     */\n    private long created;\n\n    /**\n     * 拥有模型的组织。\n     */\n    @JsonProperty(\"owned_by\")\n    private String ownedBy;\n\n}\n"
  },
  {
    "path": "ai-openai/src/main/java/com/ai/openai/endPoint/models/resp/DeleteFineTuneModelResponse.java",
    "content": "package com.ai.openai.endPoint.models.resp;\n\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport com.fasterxml.jackson.annotation.JsonInclude;\nimport lombok.AllArgsConstructor;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\n\nimport java.io.Serializable;\n\n@Data\n@NoArgsConstructor\n@AllArgsConstructor\n@JsonIgnoreProperties(ignoreUnknown = true)\n@JsonInclude(JsonInclude.Include.NON_NULL)\npublic class DeleteFineTuneModelResponse implements Serializable {\n\n    private String id;\n    private String object;\n    private Boolean deleted;\n\n}\n"
  },
  {
    "path": "ai-openai/src/main/java/com/ai/openai/endPoint/moderations/Categories.java",
    "content": "package com.ai.openai.endPoint.moderations;\n\nimport com.fasterxml.jackson.annotation.JsonProperty;\nimport lombok.AllArgsConstructor;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\n\nimport java.io.Serializable;\n\n\n@Data\n@AllArgsConstructor\n@NoArgsConstructor\npublic class Categories implements Serializable {\n    /**\n     * 表达、煽动或宣扬基于种族、性别、民族、宗教、国籍、性取向、残疾状况或种姓的仇恨的内容。\n     */\n    private boolean hate;\n\n    /**\n     * 仇恨内容，还包括对目标群体的暴力或严重伤害。\n     */\n    @JsonProperty(\"hate/threatening\")\n    private boolean hateThreatening;\n\n    /**\n     * 对任何目标表达、煽动或宣扬骚扰性语言的内容。\n     */\n    @JsonProperty(\"harassment\")\n    private boolean harassment;\n\n    /**\n     * 骚扰内容还包括对任何目标的暴力或严重伤害。\n     */\n    @JsonProperty(\"harassment/threatening\")\n    private boolean harassmentThreatening;\n\n    /**\n     * 宣扬、鼓励或描绘自残行为（例如自杀、割伤和饮食失调）的内容。\n     */\n    @JsonProperty(\"self-harm\")\n    private boolean selfHarm;\n\n    /**\n     * 说话者表示他们正在或打算进行自残行为的内容，例如自杀、割伤和饮食失调。\n     */\n    @JsonProperty(\"self-harm/intent\")\n    private boolean selfHarmIntent;\n\n    /**\n     * 鼓励进行自残行为（例如自杀、割伤和饮食失调）的内容，或者提供有关如何实施此类行为的说明或建议的内容。\n     */\n    @JsonProperty(\"self-harm/instructions\")\n    private boolean selfHarmInstructions;\n\n    /**\n     * 旨在引起性兴奋的内容，例如对性活动的描述，或宣传性服务（不包括性教育和健康）的内容。\n     */\n    private boolean sexual;\n\n    /**\n     * 包含未满 18 周岁的个人的色情内容。\n     */\n    @JsonProperty(\"sexual/minors\")\n    private boolean sexualMinors;\n\n    /**\n     * 宣扬或美化暴力或歌颂他人遭受苦难或羞辱的内容。\n     */\n    private boolean violence;\n\n    /**\n     * 以极端血腥细节描绘死亡、暴力或严重身体伤害的暴力内容。\n     */\n    @JsonProperty(\"violence/graphic\")\n    private boolean violenceGraphic;\n\n\n}\n"
  },
  {
    "path": "ai-openai/src/main/java/com/ai/openai/endPoint/moderations/CategoryScores.java",
    "content": "package com.ai.openai.endPoint.moderations;\n\nimport com.fasterxml.jackson.annotation.JsonProperty;\nimport lombok.AllArgsConstructor;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\n\nimport java.io.Serializable;\nimport java.math.BigDecimal;\n\n@Data\n@AllArgsConstructor\n@NoArgsConstructor\npublic class CategoryScores implements Serializable {\n\n    private BigDecimal hate;\n\n    @JsonProperty(\"hate/threatening\")\n    private BigDecimal hateThreatening;\n\n    /**\n     * 对任何目标表达、煽动或宣扬骚扰性语言的内容。\n     */\n    @JsonProperty(\"harassment\")\n    private BigDecimal harassment;\n\n    /**\n     * 骚扰内容还包括对任何目标的暴力或严重伤害。\n     */\n    @JsonProperty(\"harassment/threatening\")\n    private BigDecimal harassmentThreatening;\n\n    @JsonProperty(\"self-harm\")\n    private BigDecimal selfHarm;\n\n    /**\n     * 说话者表示他们正在或打算进行自残行为的内容，例如自杀、割伤和饮食失调。\n     */\n    @JsonProperty(\"self-harm/intent\")\n    private BigDecimal selfHarmIntent;\n\n    /**\n     * 鼓励进行自残行为（例如自杀、割伤和饮食失调）的内容，或者提供有关如何实施此类行为的说明或建议的内容。\n     */\n    @JsonProperty(\"self-harm/instructions\")\n    private BigDecimal selfHarmInstructions;\n\n    private BigDecimal sexual;\n\n    @JsonProperty(\"sexual/minors\")\n    private BigDecimal sexualMinors;\n\n    private BigDecimal violence;\n\n    @JsonProperty(\"violence/graphic\")\n    private BigDecimal violenceGraphic;\n\n}\n"
  },
  {
    "path": "ai-openai/src/main/java/com/ai/openai/endPoint/moderations/Result.java",
    "content": "package com.ai.openai.endPoint.moderations;\n\nimport com.fasterxml.jackson.annotation.JsonIgnore;\nimport com.fasterxml.jackson.annotation.JsonProperty;\nimport lombok.AllArgsConstructor;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\n\nimport java.io.Serializable;\n\n\n@Data\n@AllArgsConstructor\n@NoArgsConstructor\npublic class Result implements Serializable {\n\n    /**\n     * 内容是否违反 OpenAI 的使用政策\n     */\n    private boolean flagged;\n\n    /**\n     * 类别列表，以及它们是否被标记\n     */\n    private Categories categories;\n\n    /**\n     * 类别列表及其按模型预测的分数\n     */\n    @JsonProperty(\"category_scores\")\n    private CategoryScores categoryScores;\n\n    /**\n     * 原文内容\n     */\n    @JsonIgnore\n    private String content;\n}\n"
  },
  {
    "path": "ai-openai/src/main/java/com/ai/openai/endPoint/moderations/req/ModerationRequest.java",
    "content": "package com.ai.openai.endPoint.moderations.req;\n\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport com.fasterxml.jackson.annotation.JsonInclude;\nimport lombok.*;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n@Data\n@Builder\n@NoArgsConstructor\n@AllArgsConstructor\n@JsonIgnoreProperties(ignoreUnknown = true)\n@JsonInclude(JsonInclude.Include.NON_NULL)\npublic class ModerationRequest {\n\n    @NonNull\n    private List<String> input;\n\n    @Builder.Default\n    private String model = Model.TEXT_MODERATION_LATEST.getName();\n\n    /**\n     * 构造基础请求参数\n     *\n     * @param input 文本\n     * @return 请求参数\n     */\n    public static ModerationRequest baseBuild(String input) {\n        ArrayList<String> list = new ArrayList<>();\n        list.add(input);\n        return baseBuild(list);\n    }\n\n    /**\n     * 构造基础请求参数\n     *\n     * @param inputList 文本数组\n     * @return 请求参数\n     */\n    public static ModerationRequest baseBuild(List<String> inputList) {\n        return ModerationRequest.builder().input(inputList).build();\n    }\n\n    @Getter\n    @AllArgsConstructor\n    public enum Model {\n        TEXT_MODERATION_STABLE(\"text-moderation-stable\"),\n        TEXT_MODERATION_LATEST(\"text-moderation-latest\"),\n        ;\n\n        private final String name;\n    }\n\n}\n"
  },
  {
    "path": "ai-openai/src/main/java/com/ai/openai/endPoint/moderations/resp/ModerationResponse.java",
    "content": "package com.ai.openai.endPoint.moderations.resp;\n\nimport com.ai.openai.endPoint.moderations.Result;\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport com.fasterxml.jackson.annotation.JsonInclude;\nimport lombok.AllArgsConstructor;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\n\nimport java.util.List;\n\n@Data\n@NoArgsConstructor\n@AllArgsConstructor\n@JsonIgnoreProperties(ignoreUnknown = true)\n@JsonInclude(JsonInclude.Include.NON_NULL)\npublic class ModerationResponse {\n    /**\n     * 审核请求的唯一标识符\n     */\n    private String id;\n\n    /**\n     * 用于生成审核结果的模型\n     */\n    private String model;\n\n    /**\n     * 审核对象的列表\n     */\n    private List<Result> results;\n}\n"
  },
  {
    "path": "ai-openai/src/main/java/com/ai/openai/interceptor/HeaderInterceptor.java",
    "content": "package com.ai.openai.interceptor;\n\nimport cn.hutool.http.ContentType;\nimport cn.hutool.http.Header;\nimport com.ai.core.strategy.KeyStrategy;\nimport okhttp3.Interceptor;\nimport okhttp3.Request;\nimport okhttp3.Response;\nimport org.jetbrains.annotations.NotNull;\n\nimport java.io.IOException;\nimport java.util.List;\n\nimport static com.ai.core.exception.Constants.*;\n\n/**\n * @Description: OpenAI Key 拦截器\n **/\npublic class HeaderInterceptor implements Interceptor {\n\n    /**\n     * 系统设置的 openAI apiKey\n     */\n    private final List<String> apiKeyBySystem;\n\n    /**\n     * 系统设置的 api 请求地址\n     */\n    private final String apiHostBySystem;\n\n    /**\n     * key 获取策略\n     */\n    private KeyStrategy<List<String>, String> keyStrategy;\n\n    public HeaderInterceptor(List<String> apiKeyBySystem, String apiHostBySystem, KeyStrategy keyStrategy) {\n        this.apiKeyBySystem = apiKeyBySystem;\n        this.apiHostBySystem = apiHostBySystem;\n        this.keyStrategy = keyStrategy;\n    }\n\n    @NotNull\n    @Override\n    public Response intercept(Chain chain) throws IOException {\n        // 1. 获取原始 Request\n        Request originalReq = chain.request();\n        // 2. 读取 apiKey；优先使用用户传递的 apiKey\n        String apiKeyByUser = originalReq.header(API_KEY);\n        String apiHostByUser = originalReq.header(API_HOST);\n        String apiUrlByUser = originalReq.header(URL);\n        String apiKey = apiKeyByUser == NULL ? keyStrategy.apply(apiKeyBySystem) : apiKeyByUser;\n        // 3. 读取 apiUrl 和 apiHost，apiUrl 优先级大于 apiHost\n        String apiUrl = apiUrlByUser == NULL ? apiHostByUser == NULL ? String.valueOf(originalReq.url()) : apiHostByUser + originalReq.url().url().getPath() : apiUrlByUser;\n        // 4. 构建 Request\n        Request request = originalReq.newBuilder()\n                .url(apiUrl)\n                .header(Header.AUTHORIZATION.getValue(), \"Bearer \" + apiKey)\n                .header(Header.CONTENT_TYPE.getValue(), ContentType.JSON.getValue())\n                .method(originalReq.method(), originalReq.body())\n                .build();\n        // 5. 返回执行结果\n        return chain.proceed(request);\n    }\n}\n"
  },
  {
    "path": "ai-openai/src/main/java/com/ai/openai/interceptor/ResponseInterceptor.java",
    "content": "package com.ai.openai.interceptor;\n\nimport cn.hutool.json.JSONUtil;\nimport com.ai.core.exception.BaseException;\nimport com.ai.core.exception.Constants;\nimport com.ai.openai.common.CommonListResponse;\nimport lombok.extern.slf4j.Slf4j;\nimport okhttp3.Interceptor;\nimport okhttp3.Request;\nimport okhttp3.Response;\n\nimport java.io.IOException;\nimport java.util.Objects;\n\n@Slf4j\npublic class ResponseInterceptor implements Interceptor {\n    @Override\n    public Response intercept(Chain chain) throws IOException {\n        // 1. 获取 req 和 resp\n        Request original = chain.request();\n        Response response = chain.proceed(original);\n        // 2. 判断返回状态\n        if (!response.isSuccessful() && response.body() != null) {\n            // 2.1 获取返回的错误信息\n            String errorMsg = response.body().string();\n            CommonListResponse openAiResponse = JSONUtil.toBean(errorMsg, CommonListResponse.class);\n            if (Constants.ERROR_MSG_MAP.containsKey(response.code())) {\n                log.error(openAiResponse.getError().getMessage());\n                throw new BaseException(openAiResponse.getError().getMessage());\n            }\n            log.error(\"--------> 请求异常：{}\", errorMsg);\n            if (Objects.nonNull(openAiResponse.getError())) {\n                log.error(openAiResponse.getError().getMessage());\n                throw new BaseException(openAiResponse.getError().getMessage());\n            }\n            throw new BaseException(Constants.ErrorMsg.RETRY_ERROR);\n        }\n        return response;\n    }\n}\n"
  },
  {
    "path": "ai-openai/src/test/java/com/ai/openai/AudioApiTest.java",
    "content": "package com.ai.openai;\n\nimport com.ai.core.strategy.impl.FirstKeyStrategy;\nimport com.ai.openai.achieve.Configuration;\nimport com.ai.openai.achieve.defaults.DefaultOpenAiSessionFactory;\nimport com.ai.openai.achieve.standard.session.AggregationSession;\nimport com.ai.openai.endPoint.audio.req.SttCompletionRequest;\nimport com.ai.openai.endPoint.audio.req.TtsCompletionRequest;\nimport com.ai.openai.endPoint.audio.resp.SttCompletionResponse;\nimport lombok.extern.slf4j.Slf4j;\nimport okhttp3.ResponseBody;\nimport org.junit.Before;\nimport org.junit.Test;\nimport retrofit2.Call;\nimport retrofit2.Callback;\nimport retrofit2.Response;\n\nimport java.io.*;\nimport java.net.InetSocketAddress;\nimport java.net.Proxy;\nimport java.util.Arrays;\nimport java.util.concurrent.CountDownLatch;\n\nimport static com.ai.core.exception.Constants.NULL;\n\n/**\n * @Description: 测试语音相关接口功能\n **/\n@Slf4j\npublic class AudioApiTest {\n\n    private AggregationSession aggregationSession;\n\n    @Before\n    public void test_OpenAiSessionFactory() {\n        // 1. 创建配置类\n        Configuration configuration = new Configuration();\n        // 2. 设置请求地址，若有代理商或者代理服务器，可填写为代理服务器的请求路径\n        configuration.setApiHost(\"https://api.openai.com\");\n        // 3. 设置鉴权所需的API Key,可设置多个。\n        configuration.setKeyList(Arrays.asList(\"**************************\"));\n        // 4. 设置请求时 key 的使用策略，默认实现了：随机获取 和 固定第一个Key 两种方式。\n        configuration.setKeyStrategy(new FirstKeyStrategy<String>());\n//        configuration.setKeyStrategy(new RandomKeyStrategy<String>());\n        // 5. 设置代理，若不需要可不设置\n        configuration.setProxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress(\"127.0.0.1\", 7890)));\n        // 6. 创建 session 工厂，制造不同场景的 session\n        DefaultOpenAiSessionFactory factory = new DefaultOpenAiSessionFactory(configuration);\n        this.aggregationSession = factory.openAggregationSession();\n    }\n\n    /**\n     * 测试文字转语音\n     */\n    @Test\n    public void test_tts() throws InterruptedException {\n        // 定义请求参数\n        TtsCompletionRequest ttsCompletionRequest = TtsCompletionRequest.builder()\n                .model(TtsCompletionRequest.Model.tts_1.getModuleName())// 设置使用的模型\n                .input(\"你好，我是chatGPT\")\n                .voice(TtsCompletionRequest.Voice.alloy.getVoiceName())// 设置声音的样式\n                .build();\n        // 回传文件存放的路径\n        File file = new File(\"doc/test/test_tts.mp3\");\n        // 添加回调函数，发送请求\n        aggregationSession.getAudioSession().ttsCompletions(NULL, NULL, NULL, ttsCompletionRequest, new Callback<ResponseBody>() {\n                    @Override\n                    public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {\n                        try (InputStream inputStream = response.body().byteStream();\n                             OutputStream os = new BufferedOutputStream(new FileOutputStream(file))) {\n                            // 创建文件\n                            if (!file.exists()) {\n                                if (!file.getParentFile().exists()) file.getParentFile().mkdir();\n                                file.createNewFile();\n                            }\n                            byte data[] = new byte[10240];\n                            int len;\n                            while ((len = inputStream.read(data, 0, 10240)) != -1) {\n                                os.write(data, 0, len);\n                            }\n                        } catch (IOException e) {\n                            e.printStackTrace();\n                        }\n                    }\n\n                    @Override\n                    public void onFailure(Call<ResponseBody> call, Throwable t) {\n                        t.printStackTrace();\n                    }\n                }\n        );\n        // 阻塞等待\n        new CountDownLatch(1).await();\n    }\n\n    /**\n     * 测试语音转文字\n     */\n    @Test\n    public void test_stt() {\n        // 音频文件存放路径\n        File file = new File(\"doc/test/test_tts.mp3\");\n        SttCompletionRequest sttCompletionRequest = SttCompletionRequest.builder().file(file).build();\n        SttCompletionResponse sttCompletionResponse = this.aggregationSession.getAudioSession().sttCompletions(NULL, NULL, NULL, sttCompletionRequest);\n        log.info(\"测试结果：{}\", sttCompletionResponse);\n    }\n\n    /**\n     * 测试音频文件转文字后翻译为英文\n     */\n    @Test\n    public void test_translation() {\n        // 音频文件存放路径\n        File file = new File(\"doc/test/test_tts.mp3\");\n        SttCompletionRequest sttCompletionRequest = SttCompletionRequest.builder().file(file).build();\n        SttCompletionResponse sttCompletionResponse = this.aggregationSession.getAudioSession().translationCompletions(NULL, NULL, NULL, sttCompletionRequest);\n        log.info(\"测试结果：{}\", sttCompletionResponse);\n    }\n\n}\n"
  },
  {
    "path": "ai-openai/src/test/java/com/ai/openai/ChatApiTest.java",
    "content": "package com.ai.openai;\n\nimport cn.hutool.json.JSONObject;\nimport com.ai.core.exception.Constants;\nimport com.ai.core.strategy.impl.FirstKeyStrategy;\nimport com.ai.openai.achieve.Configuration;\nimport com.ai.openai.achieve.defaults.DefaultOpenAiSessionFactory;\nimport com.ai.openai.achieve.standard.session.AggregationSession;\nimport com.ai.openai.endPoint.chat.Parameters;\nimport com.ai.openai.endPoint.chat.msg.Content;\nimport com.ai.openai.endPoint.chat.msg.DefaultMessage;\nimport com.ai.openai.endPoint.chat.msg.ImgMessage;\nimport com.ai.openai.endPoint.chat.req.*;\nimport com.ai.openai.endPoint.chat.resp.ChatCompletionResponse;\nimport com.ai.openai.endPoint.chat.resp.QaCompletionResponse;\nimport com.ai.openai.endPoint.chat.tools.Tool;\nimport com.ai.openai.endPoint.chat.tools.ToolFunction;\nimport com.fasterxml.jackson.core.JsonProcessingException;\nimport lombok.extern.slf4j.Slf4j;\nimport okhttp3.Response;\nimport okhttp3.sse.EventSource;\nimport okhttp3.sse.EventSourceListener;\nimport org.junit.Before;\nimport org.junit.Test;\n\nimport java.net.InetSocketAddress;\nimport java.net.Proxy;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.concurrent.CompletableFuture;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.ExecutionException;\n\nimport static com.ai.core.exception.Constants.NULL;\n\n/**\n * @Description: 测试聊天接口相关接口功能\n */\n@Slf4j\npublic class ChatApiTest {\n\n    private AggregationSession aggregationSession;\n\n    @Before\n    public void test_OpenAiSessionFactory() {\n        // 1. 创建配置类\n        Configuration configuration = new Configuration();\n        // 2. 设置请求地址，若有代理商或者代理服务器，可填写为代理服务器的请求路径\n        configuration.setApiHost(\"https://api.openai.com\");\n        // 3. 设置鉴权所需的API Key,可设置多个。\n        configuration.setKeyList(Arrays.asList(\"填入你的API Key\"));\n        // 4. 设置请求时 key 的使用策略，默认实现了：随机获取 和 固定第一个Key 两种方式。\n        configuration.setKeyStrategy(new FirstKeyStrategy<String>());\n//        configuration.setKeyStrategy(new RandomKeyStrategy<String>());\n        // 5. 设置代理，若不需要可不设置\n        configuration.setProxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress(\"127.0.0.1\", 7890)));\n        // 6. 创建 session 工厂，制造不同场景的 session\n        DefaultOpenAiSessionFactory factory = new DefaultOpenAiSessionFactory(configuration);\n        this.aggregationSession = factory.openAggregationSession();\n    }\n\n    /**\n     * 测试简单问答，相当于只有一轮问答。\n     */\n    @Test\n    public void test_qa_completions() {\n        QaCompletionRequest qaCompletionRequest = QaCompletionRequest.baseBuild(\"你是谁？\");\n        QaCompletionResponse qaCompletionResponse = aggregationSession.getChatSession().qaCompletions(NULL, NULL, NULL, qaCompletionRequest);\n        log.info(\"测试结果：{}\", qaCompletionResponse);\n    }\n\n    /**\n     * 测试简单问答，流式返回结果。\n     */\n    @Test\n    public void test_qa_completions_stream() throws InterruptedException, JsonProcessingException {\n        QaCompletionRequest qaCompletionRequest = QaCompletionRequest.builder()\n                .prompt(\"讲一个笑话\")\n                .stream(true) // 设置流式返回\n                .build();\n        // 监听器监听返回的结果\n        aggregationSession.getChatSession().qaCompletions(NULL, NULL, NULL, qaCompletionRequest, new EventSourceListener() {\n            @Override\n            public void onEvent(EventSource eventSource, String id, String type, String data) {\n                log.info(\"测试结果 id:{} type:{} data:{}\", id, type, data);\n            }\n\n            @Override\n            public void onFailure(EventSource eventSource, Throwable t, Response response) {\n                log.error(\"失败 code:{} message:{}\", response.code(), response.message());\n            }\n        });\n        // 阻塞等待\n        new CountDownLatch(1).await();\n    }\n\n    /**\n     * 测试多轮对话\n     */\n    @Test\n    public void test_chat_completions() {\n        // 创建参数，上下文对话。\n        // 第一次的问题\n        DefaultChatCompletionRequest defaultChatCompletionRequest = DefaultChatCompletionRequest.baseBuild(\"1+1=\");\n        // 第一次的回复\n        defaultChatCompletionRequest.addMessage(Constants.Role.ASSISTANT.getRoleName(), \"2\");\n        // 第二次的问题\n        defaultChatCompletionRequest.addMessage(Constants.Role.USER.getRoleName(), \"2+2=\");\n        // 询问第二次的问题的结果\n        ChatCompletionResponse chatCompletionResponse = aggregationSession.getChatSession().chatCompletions(NULL, NULL, NULL, defaultChatCompletionRequest);\n        // 解析结果\n        chatCompletionResponse.getChoices().forEach(e -> {\n            log.info(\"测试结果：{}\", e.getMessage());\n        });\n    }\n\n    /**\n     * 测试函数对话，创建一个函数获取天气信息\n     * 下面的请求参数根据官方案例转换而来\n     */\n    @Test\n    public void test_func_chat_completions() {\n        // 定义第一个属性，地址信息\n        JSONObject location = new JSONObject();\n        location.putOpt(\"type\", \"string\");\n        location.putOpt(\"description\", \"The city and state, e.g. San Francisco, CA\");\n        // 定义第二个属性，时间信息\n        JSONObject unit = new JSONObject();\n        unit.putOpt(\"type\", \"string\");\n        unit.putOpt(\"enum\", Arrays.asList(\"celsius\", \"fahrenheit\"));\n        // 定义 properties，及将函数属性组合起来\n        JSONObject properties = new JSONObject();\n        properties.putOpt(\"location\", location);\n        properties.putOpt(\"unit\", unit);\n        // 定义 parameters\n        Parameters parameters = Parameters.builder().type(\"object\").properties(properties).required(Arrays.asList(\"location\")).build();\n        // 构造函数信息\n        ToolFunction toolFunction = ToolFunction.builder().name(\"get_current_weather\").description(\"Get the current weather in a given location\").parameters(parameters).build();\n        // 构造工具\n        Tool tool = Tool.builder().type(Tool.Type.FUNCTION.getName()).function(toolFunction).build();\n        // 构造请求参数\n        FuncChatCompletionRequest funcChatCompletionRequest = FuncChatCompletionRequest.baseBuild(\"What is the weather like in Boston?\");\n        funcChatCompletionRequest.setTools(Arrays.asList(tool));\n        funcChatCompletionRequest.setToolChoice(\"auto\");\n        // 获取请求结果\n        ChatCompletionResponse chatCompletionResponse = aggregationSession.getChatSession().chatCompletions(NULL, NULL, NULL, funcChatCompletionRequest);\n        log.info(\"测试结果：{}\", chatCompletionResponse);\n    }\n\n    /**\n     * 测试图片对话，需要GPT4权限\n     */\n    @Test\n    public void test_img_chat_completions() {\n        // 构造对话内容\n        Content textContent = Content.BuildTextContent(\"这张图片当中有什么？\");\n        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\");\n        // 构造 msg 内容\n        ImgMessage imgMessage = ImgMessage.builder().role(Constants.Role.USER.getRoleName()).content(Arrays.asList(textContent, imgContent)).build();\n        // 构造请求参数，chatGPT 4 支持图片对话\n        ImgChatCompletionRequest imgChatCompletionRequest = ImgChatCompletionRequest.builder().model(BaseChatCompletionRequest.Model.GPT_4_VISION_PREVIEW.getModuleName()).messages(Arrays.asList(imgMessage)).build();\n        // 获取结果\n        ChatCompletionResponse chatCompletionResponse = aggregationSession.getChatSession().chatCompletions(NULL, NULL, NULL, imgChatCompletionRequest);\n        log.info(\"测试结果：{}\", chatCompletionResponse);\n    }\n\n    /**\n     * 测试聊天对话，流式返回结果。\n     */\n    @Test\n    public void test_chat_completions_stream() throws InterruptedException, JsonProcessingException {\n        // 建造者模式构造参数\n        DefaultChatCompletionRequest defaultChatCompletionRequest = DefaultChatCompletionRequest.builder()\n                .stream(true)// 开启流式返回\n                .messages(Collections.singletonList(DefaultMessage\n                        .builder()\n                        .role(Constants.Role.USER.getRoleName())\n                        .content(\"讲一个笑话\")\n                        .build()))\n                .model(BaseChatCompletionRequest.Model.GPT_3_5_TURBO.getModuleName())\n                .build();\n\n        aggregationSession.getChatSession().chatCompletions(NULL, NULL, NULL, defaultChatCompletionRequest, new EventSourceListener() {\n            @Override\n            public void onEvent(EventSource eventSource, String id, String type, String data) {\n                log.info(\"测试结果 id:{} type:{} data:{}\", id, type, data);\n            }\n\n            @Override\n            public void onFailure(EventSource eventSource, Throwable t, Response response) {\n                log.error(\"失败 code:{} message:{}\", response.code(), response.message());\n            }\n        });\n        // 阻塞等待\n        new CountDownLatch(1).await();\n    }\n\n    /**\n     * 测试 CompletableFuture 异步调用。\n     */\n    @Test\n    public void test_chat_completions_future() throws JsonProcessingException, InterruptedException, ExecutionException {\n        // 构造请求参数\n        DefaultChatCompletionRequest defaultChatCompletionRequest = DefaultChatCompletionRequest.builder()\n                .stream(true)\n                .messages(Collections.singletonList(DefaultMessage\n                        .builder()\n                        .role(Constants.Role.USER.getRoleName())\n                        .content(\"1+1=\")\n                        .build()))\n                .model(BaseChatCompletionRequest.Model.GPT_3_5_TURBO.getModuleName()).build();\n        // 等待结果\n        CompletableFuture<String> future = aggregationSession.getChatSession().chatCompletionsFuture(NULL, NULL, NULL, defaultChatCompletionRequest);\n        log.info(\"测试结果：{}\", future.get());\n    }\n\n}\n"
  },
  {
    "path": "ai-openai/src/test/java/com/ai/openai/EmbeddingApiTest.java",
    "content": "package com.ai.openai;\n\nimport com.ai.core.strategy.impl.FirstKeyStrategy;\nimport com.ai.openai.achieve.Configuration;\nimport com.ai.openai.achieve.defaults.DefaultOpenAiSessionFactory;\nimport com.ai.openai.achieve.standard.session.AggregationSession;\nimport com.ai.openai.endPoint.embeddings.EmbeddingObject;\nimport com.ai.openai.endPoint.embeddings.req.EmbeddingCompletionRequest;\nimport com.ai.openai.endPoint.embeddings.resp.EmbeddingCompletionResponse;\nimport lombok.extern.slf4j.Slf4j;\nimport org.junit.Before;\nimport org.junit.Test;\n\nimport java.net.InetSocketAddress;\nimport java.net.Proxy;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\n\nimport static com.ai.core.exception.Constants.NULL;\n\n/**\n * @Description: 测试嵌入相关接口功能\n */\n@Slf4j\npublic class EmbeddingApiTest {\n\n    private AggregationSession aggregationSession;\n\n    @Before\n    public void test_OpenAiSessionFactory() {\n        // 1. 创建配置类\n        Configuration configuration = new Configuration();\n        // 2. 设置请求地址，若有代理商或者代理服务器，可填写为代理服务器的请求路径\n        configuration.setApiHost(\"https://api.openai.com\");\n        // 3. 设置鉴权所需的API Key,可设置多个。\n        configuration.setKeyList(Arrays.asList(\"**************************\"));\n        // 4. 设置请求时 key 的使用策略，默认实现了：随机获取 和 固定第一个Key 两种方式。\n        configuration.setKeyStrategy(new FirstKeyStrategy<String>());\n//        configuration.setKeyStrategy(new RandomKeyStrategy<String>());\n        // 5. 设置代理，若不需要可不设置\n        configuration.setProxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress(\"127.0.0.1\", 7890)));\n        // 6. 创建 session 工厂，制造不同场景的 session\n        DefaultOpenAiSessionFactory factory = new DefaultOpenAiSessionFactory(configuration);\n        this.aggregationSession = factory.openAggregationSession();\n    }\n\n    /**\n     * 测试单个文本\n     */\n    @Test\n    public void test_embedding() {\n        EmbeddingCompletionResponse embeddingCompletionResponse = aggregationSession.getEmbeddingSession().embeddingCompletions(NULL, NULL, NULL, \"你好\");\n        for (EmbeddingObject embeddingObject : embeddingCompletionResponse.getData()) {\n            System.out.println(embeddingObject.getEmbedding().length);\n        }\n        log.info(\"返回结果：{}\", embeddingCompletionResponse);\n        log.info(\"返回结果：{}\", embeddingCompletionResponse.getData().size());\n    }\n\n\n    /**\n     * 测试多个文本嵌入\n     */\n    @Test\n    public void test_embedding_list() {\n        List<String> inputList = new ArrayList<>();\n        inputList.add(\"你好\");\n        inputList.add(\"世界\");\n        EmbeddingCompletionResponse embeddingCompletionResponse = aggregationSession.getEmbeddingSession().embeddingCompletions(NULL, NULL, NULL, inputList);\n        log.info(\"返回结果：{}\", embeddingCompletionResponse);\n    }\n\n    @Test\n    public void test_embedding_req() {\n        List<String> inputList = new ArrayList<>();\n        inputList.add(\"你好\");\n        inputList.add(\"世界\");\n        EmbeddingCompletionRequest embeddingCompletionRequest = EmbeddingCompletionRequest.baseBuild(inputList);\n        EmbeddingCompletionResponse embeddingCompletionResponse = aggregationSession.getEmbeddingSession().embeddingCompletions(NULL, NULL, NULL, embeddingCompletionRequest);\n        log.info(\"返回结果：{}\", embeddingCompletionResponse);\n    }\n\n}\n"
  },
  {
    "path": "ai-openai/src/test/java/com/ai/openai/FilesApiTest.java",
    "content": "package com.ai.openai;\n\nimport com.ai.core.strategy.impl.FirstKeyStrategy;\nimport com.ai.openai.achieve.Configuration;\nimport com.ai.openai.achieve.defaults.DefaultOpenAiSessionFactory;\nimport com.ai.openai.achieve.standard.session.AggregationSession;\nimport com.ai.openai.endPoint.files.FileObject;\nimport com.ai.openai.endPoint.files.resp.DeleteFileResponse;\nimport lombok.extern.slf4j.Slf4j;\nimport okhttp3.ResponseBody;\nimport org.junit.Before;\nimport org.junit.Test;\n\nimport java.io.File;\nimport java.net.InetSocketAddress;\nimport java.net.Proxy;\nimport java.util.Arrays;\nimport java.util.List;\n\nimport static com.ai.core.exception.Constants.NULL;\n\n/**\n * @Description: 测试文件相关接口功能\n **/\n@Slf4j\npublic class FilesApiTest {\n\n    private AggregationSession aggregationSession;\n\n    @Before\n    public void test_OpenAiSessionFactory() {\n        // 1. 创建配置类\n        Configuration configuration = new Configuration();\n        // 2. 设置请求地址，若有代理商或者代理服务器，可填写为代理服务器的请求路径\n        configuration.setApiHost(\"https://api.openai.com\");\n        // 3. 设置鉴权所需的API Key,可设置多个。\n        configuration.setKeyList(Arrays.asList(\"填入你的API Key\"));\n        // 4. 设置请求时 key 的使用策略，默认实现了：随机获取 和 固定第一个Key 两种方式。\n        configuration.setKeyStrategy(new FirstKeyStrategy<String>());\n//        configuration.setKeyStrategy(new RandomKeyStrategy<String>());\n        // 5. 设置代理，若不需要可不设置\n        configuration.setProxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress(\"127.0.0.1\", 7890)));\n        // 6. 创建 session 工厂，制造不同场景的 session\n        DefaultOpenAiSessionFactory factory = new DefaultOpenAiSessionFactory(configuration);\n        this.aggregationSession = factory.openAggregationSession();\n    }\n\n    /**\n     * 测试列出文件\n     */\n    @Test\n    public void test_list_file() {\n        List<FileObject> fileObjects = aggregationSession.getFilesSession().listFilesCompletions(NULL, NULL, NULL);\n        log.info(\"测试结果：{}\", fileObjects);\n    }\n\n    /**\n     * 测试上传文件\n     */\n    @Test\n    public void test_upload_file() {\n        File file = new File(\"src/main/resources/test1.txt\");\n        FileObject fileObject = aggregationSession.getFilesSession().uploadFileCompletions(NULL, NULL, NULL, file, \"fine-tune\");\n        log.info(\"测试结果：{}\", fileObject);\n    }\n\n    /**\n     * 测试删除文件\n     */\n    @Test\n    public void test_delete_file() {\n        DeleteFileResponse deleteFileResponse = aggregationSession.getFilesSession().deleteFileCompletions(NULL, NULL, NULL, \"file-B3CAfSS2ibv7cFmSbl5m1CPI\");\n        log.info(\"测试结果：{}\", deleteFileResponse);\n    }\n\n    /**\n     * 测试检索文件\n     */\n    @Test\n    public void test_retrieve_file() {\n        FileObject fileObject = aggregationSession.getFilesSession().retrieveFileCompletions(NULL, NULL, NULL, \"file-B3CAfSS2ibv7cFmSbl5m1CPI\");\n        log.info(\"测试结果：{}\", fileObject);\n    }\n\n    /**\n     * 测试获取检索的文件内容\n     */\n    @Test\n    public void test_retrieve_file_context() {\n        ResponseBody responseBody = aggregationSession.getFilesSession().retrieveFileContextCompletions(NULL, NULL, NULL, \"file-B3CAfSS2ibv7cFmSbl5m1CPI\");\n        log.info(\"测试结果：{}\", responseBody);\n    }\n\n}\n"
  },
  {
    "path": "ai-openai/src/test/java/com/ai/openai/FineTuningApiTest.java",
    "content": "package com.ai.openai;\n\nimport com.ai.core.strategy.impl.FirstKeyStrategy;\nimport com.ai.openai.achieve.Configuration;\nimport com.ai.openai.achieve.defaults.DefaultOpenAiSessionFactory;\nimport com.ai.openai.achieve.standard.session.AggregationSession;\nimport com.ai.openai.common.CommonListResponse;\nimport com.ai.openai.endPoint.fineTuning.FineTuningEvent;\nimport com.ai.openai.endPoint.fineTuning.req.FineTuningRequest;\nimport com.ai.openai.endPoint.fineTuning.req.ListFineTuningRequest;\nimport com.ai.openai.endPoint.fineTuning.resp.FineTuningResponse;\nimport lombok.extern.slf4j.Slf4j;\nimport org.junit.Before;\nimport org.junit.Test;\n\nimport java.net.InetSocketAddress;\nimport java.net.Proxy;\nimport java.util.Arrays;\n\nimport static com.ai.core.exception.Constants.NULL;\n\n/**\n * @Description: 测试微调相关接口功能\n **/\n@Slf4j\npublic class FineTuningApiTest {\n\n    private AggregationSession aggregationSession;\n\n    @Before\n    public void test_OpenAiSessionFactory() {\n        // 1. 创建配置类\n        Configuration configuration = new Configuration();\n        // 2. 设置请求地址，若有代理商或者代理服务器，可填写为代理服务器的请求路径\n        configuration.setApiHost(\"https://api.openai.com\");\n        // 3. 设置鉴权所需的API Key,可设置多个。\n        configuration.setKeyList(Arrays.asList(\"填入你的API Key\"));\n        // 4. 设置请求时 key 的使用策略，默认实现了：随机获取 和 固定第一个Key 两种方式。\n        configuration.setKeyStrategy(new FirstKeyStrategy<String>());\n//        configuration.setKeyStrategy(new RandomKeyStrategy<String>());\n        // 5. 设置代理，若不需要可不设置\n        configuration.setProxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress(\"127.0.0.1\", 7890)));\n        // 6. 创建 session 工厂，制造不同场景的 session\n        DefaultOpenAiSessionFactory factory = new DefaultOpenAiSessionFactory(configuration);\n        this.aggregationSession = factory.openAggregationSession();\n    }\n\n    /**\n     * 测试创建微调\n     */\n    @Test\n    public void test_create_fine_tuning() {\n        FineTuningRequest fineTuningRequest = FineTuningRequest\n                .builder()\n                .trainingFile(\"file-BK7bzQj3FfZFXr7DbL6xJwfo\")\n                .build();\n        FineTuningResponse fineTuningResponse = aggregationSession.getFineTuningSession().createFineTuningJobCompletions(NULL, NULL, NULL, fineTuningRequest);\n        log.info(\"返回结果：{}\", fineTuningResponse);\n    }\n\n    /**\n     * 测试列出微调作业\n     */\n    @Test\n    public void test_list_fine_tuning_1() {\n        ListFineTuningRequest listFineTuningRequest = ListFineTuningRequest.builder().build();\n        CommonListResponse<FineTuningResponse> fineTuneJobListFineTuningResponse = aggregationSession.getFineTuningSession().listFineTuningJobsCompletions(NULL, NULL, NULL, listFineTuningRequest);\n        log.info(\"返回结果：{}\", fineTuneJobListFineTuningResponse);\n    }\n\n    /**\n     * 测试列出微调作业\n     */\n    @Test\n    public void test_list_fine_tuning_2() {\n        CommonListResponse<FineTuningResponse> fineTuneJobListFineTuningResponse = aggregationSession.getFineTuningSession().listFineTuningJobsCompletions(NULL, NULL, NULL, null, null);\n        log.info(\"返回结果：{}\", fineTuneJobListFineTuningResponse);\n    }\n\n    /**\n     * 测试检索微调作业\n     */\n    @Test\n    public void test_retrieve_fine_tuning() {\n        FineTuningResponse fineTuningResponse = aggregationSession.getFineTuningSession().retrieveFineTuningJobCompletions(NULL, NULL, NULL, \"ft-AF1WoRqd3aJAHsqc9NY7iL8F\");\n        log.info(\"返回结果：{}\", fineTuningResponse);\n    }\n\n    /**\n     * 测试关闭微调作业\n     */\n    @Test\n    public void test_cancel_fine_tuning() {\n        FineTuningResponse fineTuningResponse = aggregationSession.getFineTuningSession().cancelFineTuningJobCompletions(NULL, NULL, NULL, \"ft-AF1WoRqd3aJAHsqc9NY7iL8F\");\n        log.info(\"返回结果：{}\", fineTuningResponse);\n    }\n\n    /**\n     * 测试列出微调事件\n     */\n    @Test\n    public void test_list_fine_tuning_events() {\n        CommonListResponse<FineTuningEvent> fineTuningEventListFineTuningResponse = aggregationSession.getFineTuningSession().listFineTuningEventsCompletions(NULL, NULL, NULL, \"ftjob-abc123\");\n        log.info(\"返回结果：{}\", fineTuningEventListFineTuningResponse);\n\n    }\n\n}\n"
  },
  {
    "path": "ai-openai/src/test/java/com/ai/openai/ImageApiTest.java",
    "content": "package com.ai.openai;\n\nimport com.ai.common.utils.ImageUtils;\nimport com.ai.core.strategy.impl.FirstKeyStrategy;\nimport com.ai.openai.achieve.Configuration;\nimport com.ai.openai.achieve.defaults.DefaultOpenAiSessionFactory;\nimport com.ai.openai.achieve.standard.session.AggregationSession;\nimport com.ai.openai.endPoint.images.ImageObject;\nimport com.ai.openai.endPoint.images.req.CreateImageRequest;\nimport com.ai.openai.endPoint.images.req.ImageEditRequest;\nimport com.ai.openai.endPoint.images.req.ImageVariationRequest;\nimport lombok.extern.slf4j.Slf4j;\nimport org.junit.Before;\nimport org.junit.Test;\n\nimport java.io.File;\nimport java.net.InetSocketAddress;\nimport java.net.Proxy;\nimport java.util.Arrays;\nimport java.util.List;\n\nimport static com.ai.core.exception.Constants.NULL;\n\n/**\n * @Description: 测试图片相关接口功能\n **/\n@Slf4j\npublic class ImageApiTest {\n    private AggregationSession aggregationSession;\n\n    @Before\n    public void test_OpenAiSessionFactory() {\n        // 1. 创建配置类\n        Configuration configuration = new Configuration();\n        // 2. 设置请求地址，若有代理商或者代理服务器，可填写为代理服务器的请求路径\n        configuration.setApiHost(\"https://api.openai.com\");\n        // 3. 设置鉴权所需的API Key,可设置多个。\n        configuration.setKeyList(Arrays.asList(\"填入你的API Key\"));\n        // 4. 设置请求时 key 的使用策略，默认实现了：随机获取 和 固定第一个Key 两种方式。\n        configuration.setKeyStrategy(new FirstKeyStrategy<String>());\n//        configuration.setKeyStrategy(new RandomKeyStrategy<String>());\n        // 5. 设置代理，若不需要可不设置\n        configuration.setProxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress(\"127.0.0.1\", 7890)));\n        // 6. 创建 session 工厂，制造不同场景的 session\n        DefaultOpenAiSessionFactory factory = new DefaultOpenAiSessionFactory(configuration);\n        this.aggregationSession = factory.openAggregationSession();\n    }\n\n    /**\n     * 测试图片生成，返回B64Json格式\n     */\n    @Test\n    public void test_create_image_b64json() {\n        CreateImageRequest createImageRequest = CreateImageRequest.baseBuild(\"画一个花园，花园里面有蝴蝶。\");\n        createImageRequest.setResponseFormat(CreateImageRequest.Format.B64JSON.getFormat());\n        List<ImageObject> imageObjectList = aggregationSession.getImageSession().createImageCompletions(NULL, NULL, NULL, createImageRequest);\n        for (int i = 0; i < imageObjectList.size(); i++) {\n            ImageUtils.convertBase64StrToImage(imageObjectList.get(i).getB64Json(), \"D:\\\\chatGPT-api\\\\AI-java\\\\doc\\\\test\\\\test_openai_create_image_\" + i + \".png\");\n        }\n    }\n\n    /**\n     * 测试图片生成，返回URL格式\n     */\n    @Test\n    public void test_create_image_url() {\n        CreateImageRequest createImageRequest = CreateImageRequest.baseBuild(\"画一个花园，花园里面有蝴蝶。\");\n        createImageRequest.setResponseFormat(CreateImageRequest.Format.URL.getFormat());\n        List<ImageObject> imageObjectList = aggregationSession.getImageSession().createImageCompletions(NULL, NULL, NULL, createImageRequest);\n        for (int i = 0; i < imageObjectList.size(); i++) {\n            System.out.println(imageObjectList.get(i).getUrl());\n        }\n    }\n\n    /**\n     * 测试编辑图片\n     */\n    @Test\n    public void test_edit_image() {\n        File file = new File(\"D:\\\\chatGPT-api\\\\AI-java\\\\doc\\\\test\\\\test_edit_image.png\");\n        ImageEditRequest imageEditRequest = ImageEditRequest.baseBuild(\"给小熊的背后加上一只梅花鹿。\");\n        List<ImageObject> imageObjectList = aggregationSession.getImageSession().editImageCompletions(NULL, NULL, NULL, file, null, imageEditRequest);\n        log.info(\"测试结果：{}\", imageObjectList);\n    }\n\n    /**\n     * 测试创建图片变体\n     */\n    @Test\n    public void test_variation_image() {\n        File file = new File(\"D:\\\\chatGPT-api\\\\AI-java\\\\doc\\\\test\\\\test_edit_image.png\");\n        ImageVariationRequest imageVariationRequest = ImageVariationRequest.builder().build();\n        List<ImageObject> imageObjectList = aggregationSession.getImageSession().variationImageCompletions(NULL, NULL, NULL, file, imageVariationRequest);\n        log.info(\"测试结果：{}\", imageObjectList);\n    }\n}\n"
  },
  {
    "path": "ai-openai/src/test/java/com/ai/openai/ModelApiTest.java",
    "content": "package com.ai.openai;\n\nimport com.ai.core.strategy.impl.FirstKeyStrategy;\nimport com.ai.openai.achieve.Configuration;\nimport com.ai.openai.achieve.defaults.DefaultOpenAiSessionFactory;\nimport com.ai.openai.achieve.standard.session.AggregationSession;\nimport com.ai.openai.endPoint.models.ModelObject;\nimport com.ai.openai.endPoint.models.resp.DeleteFineTuneModelResponse;\nimport lombok.extern.slf4j.Slf4j;\nimport org.junit.Before;\nimport org.junit.Test;\n\nimport java.net.InetSocketAddress;\nimport java.net.Proxy;\nimport java.util.Arrays;\nimport java.util.List;\n\nimport static com.ai.core.exception.Constants.NULL;\n\n/**\n * @Description: 测试模型相关接口功能\n **/\n@Slf4j\npublic class ModelApiTest {\n\n    private AggregationSession aggregationSession;\n\n    @Before\n    public void test_OpenAiSessionFactory() {\n        // 1. 创建配置类\n        Configuration configuration = new Configuration();\n        // 2. 设置请求地址，若有代理商或者代理服务器，可填写为代理服务器的请求路径\n        configuration.setApiHost(\"https://api.openai.com\");\n        // 3. 设置鉴权所需的API Key,可设置多个。\n        configuration.setKeyList(Arrays.asList(\"填入你的API Key\"));\n        // 4. 设置请求时 key 的使用策略，默认实现了：随机获取 和 固定第一个Key 两种方式。\n        configuration.setKeyStrategy(new FirstKeyStrategy<String>());\n//        configuration.setKeyStrategy(new RandomKeyStrategy<String>());\n        // 5. 设置代理，若不需要可不设置\n        configuration.setProxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress(\"127.0.0.1\", 7890)));\n        // 6. 创建 session 工厂，制造不同场景的 session\n        DefaultOpenAiSessionFactory factory = new DefaultOpenAiSessionFactory(configuration);\n        this.aggregationSession = factory.openAggregationSession();\n    }\n\n    /**\n     * 测试列出模型接口\n     */\n    @Test\n    public void test_list_model() {\n        List<ModelObject> modelObjects = aggregationSession.getModelSession().listModelCompletions(NULL, NULL, NULL);\n        log.info(\"返回结果：{}\", modelObjects);\n    }\n\n    /**\n     * 测试检索模型接口\n     */\n    @Test\n    public void test_retrieve_model() {\n        ModelObject modelObject = aggregationSession.getModelSession().retrieveModelCompletions(NULL, NULL, NULL, \"gpt-3.5-turbo-instruct\");\n        log.info(\"返回结果：{}\", modelObject);\n    }\n\n    /**\n     * 测试删除微调模型接口\n     */\n    @Test\n    public void test_delete_fine_tune_model() {\n        DeleteFineTuneModelResponse deleteFineTuneModelResponse = aggregationSession.getModelSession().deleteFineTuneModelCompletions(NULL, NULL, NULL, \"gpt-3.5-turbo-instruct\");\n        log.info(\"返回结果：{}\", deleteFineTuneModelResponse);\n    }\n\n\n}\n"
  },
  {
    "path": "ai-openai/src/test/java/com/ai/openai/ModerationApiTest.java",
    "content": "package com.ai.openai;\n\nimport com.ai.core.strategy.impl.FirstKeyStrategy;\nimport com.ai.openai.achieve.Configuration;\nimport com.ai.openai.achieve.defaults.DefaultOpenAiSessionFactory;\nimport com.ai.openai.achieve.standard.session.AggregationSession;\nimport com.ai.openai.endPoint.moderations.Result;\nimport com.ai.openai.endPoint.moderations.req.ModerationRequest;\nimport com.ai.openai.endPoint.moderations.resp.ModerationResponse;\nimport lombok.extern.slf4j.Slf4j;\nimport org.junit.Before;\nimport org.junit.Test;\n\nimport java.net.InetSocketAddress;\nimport java.net.Proxy;\nimport java.util.ArrayList;\nimport java.util.Arrays;\n\nimport static com.ai.core.exception.Constants.NULL;\n\n/**\n * @Description: 测试审核相关接口功能\n **/\n@Slf4j\npublic class ModerationApiTest {\n\n    private AggregationSession aggregationSession;\n\n    @Before\n    public void test_OpenAiSessionFactory() {\n        // 1. 创建配置类\n        Configuration configuration = new Configuration();\n        // 2. 设置请求地址，若有代理商或者代理服务器，可填写为代理服务器的请求路径\n        configuration.setApiHost(\"https://api.openai.com\");\n        // 3. 设置鉴权所需的API Key,可设置多个。\n        configuration.setKeyList(Arrays.asList(\"**************************\"));\n        // 4. 设置请求时 key 的使用策略，默认实现了：随机获取 和 固定第一个Key 两种方式。\n        configuration.setKeyStrategy(new FirstKeyStrategy<String>());\n//        configuration.setKeyStrategy(new RandomKeyStrategy<String>());\n        // 5. 设置代理，若不需要可不设置\n        configuration.setProxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress(\"127.0.0.1\", 7890)));\n        // 6. 创建 session 工厂，制造不同场景的 session\n        DefaultOpenAiSessionFactory factory = new DefaultOpenAiSessionFactory(configuration);\n        this.aggregationSession = factory.openAggregationSession();\n    }\n\n    /**\n     * 测试审核\n     */\n    @Test\n    public void test_moderation() {\n        ArrayList<String> list = new ArrayList<>();\n        list.add(\"你好\");\n        list.add(\"我要杀了你\");\n        ModerationRequest moderationRequest = ModerationRequest.builder().input(list).build();\n        ModerationResponse moderationResponse = aggregationSession.getModerationSession().moderationCompletions(NULL, NULL, NULL, moderationRequest);\n        for (Result result : moderationResponse.getResults()) {\n            System.out.println(result.getContent() + \"  \" + result.isFlagged());\n        }\n    }\n\n}\n"
  },
  {
    "path": "ai-spark/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xmlns=\"http://maven.apache.org/POM/4.0.0\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <parent>\n        <artifactId>AI-java</artifactId>\n        <groupId>com.ai</groupId>\n        <version>1.0</version>\n    </parent>\n    <modelVersion>4.0.0</modelVersion>\n    <artifactId>ai-spark</artifactId>\n\n    <properties>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n        <java.version>1.8</java.version>\n        <maven.compiler.source>1.8</maven.compiler.source>\n        <maven.compiler.target>1.8</maven.compiler.target>\n        <junit.version>4.13.2</junit.version>\n    </properties>\n\n    <dependencies>\n        <dependency>\n            <groupId>com.ai</groupId>\n            <artifactId>ai-common</artifactId>\n            <version>1.0</version>\n        </dependency>\n        <dependency>\n            <groupId>com.ai</groupId>\n            <artifactId>ai-core</artifactId>\n            <version>1.0</version>\n        </dependency>\n        <dependency>\n            <groupId>junit</groupId>\n            <artifactId>junit</artifactId>\n            <version>${junit.version}</version>\n            <scope>test</scope>\n        </dependency>\n    </dependencies>\n\n</project>\n"
  },
  {
    "path": "ai-spark/src/main/java/com/ai/spark/achieve/ApiData.java",
    "content": "package com.ai.spark.achieve;\n\n\nimport lombok.AllArgsConstructor;\nimport lombok.Builder;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\n\n/**\n * 记录用户API信息\n */\n@Data\n@Builder\n@NoArgsConstructor\n@AllArgsConstructor\npublic class ApiData {\n\n    private String appId;\n    private String apiKey;\n    private String apiSecret;\n\n}\n"
  },
  {
    "path": "ai-spark/src/main/java/com/ai/spark/achieve/Configuration.java",
    "content": "package com.ai.spark.achieve;\n\nimport com.ai.core.config.BaseConfiguration;\nimport com.ai.spark.achieve.standard.api.SparkApiServer;\nimport lombok.*;\nimport org.jetbrains.annotations.NotNull;\n\nimport java.util.List;\n\n/**\n * @Description: 配置信息\n **/\n@Data\n@ToString(callSuper = true)\n@EqualsAndHashCode(callSuper = true)\n@NoArgsConstructor\n@AllArgsConstructor\npublic class Configuration extends BaseConfiguration {\n\n    /**\n     * api 服务提供者\n     */\n    private SparkApiServer sparkApiServer;\n\n    /**\n     * api Key 集合\n     */\n    @NotNull\n    private List<ApiData> keyList;\n\n    public ApiData getSystemApiData() {\n        return (ApiData) this.getKeyStrategy().apply(keyList);\n    }\n\n}\n"
  },
  {
    "path": "ai-spark/src/main/java/com/ai/spark/achieve/defaults/DefaultSparkSessionFactory.java",
    "content": "package com.ai.spark.achieve.defaults;\n\nimport com.ai.core.factory.SessionFactory;\nimport com.ai.spark.achieve.Configuration;\nimport com.ai.spark.achieve.defaults.session.DefaultAggregationSession;\nimport com.ai.spark.achieve.standard.api.SparkApiServer;\nimport com.ai.spark.achieve.standard.session.AggregationSession;\nimport com.ai.spark.interceptor.BaseUrlInterceptor;\nimport com.ai.spark.interceptor.ResponseInterceptor;\nimport okhttp3.OkHttpClient;\nimport okhttp3.logging.HttpLoggingInterceptor;\nimport retrofit2.Retrofit;\nimport retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;\nimport retrofit2.converter.jackson.JacksonConverterFactory;\n\nimport java.util.concurrent.TimeUnit;\n\nimport static com.ai.common.utils.ValidationUtils.ensureNotNull;\n\npublic class DefaultSparkSessionFactory implements SessionFactory<AggregationSession, SparkApiServer> {\n\n    private final Configuration configuration;\n\n    public DefaultSparkSessionFactory(Configuration configuration) {\n        this.configuration = ensureNotNull(configuration, \"configuration\");\n    }\n\n    @Override\n    public OkHttpClient createHttpClient() {\n        // 1. 日志配置\n        HttpLoggingInterceptor httpLoggingInterceptor = new HttpLoggingInterceptor();\n        httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.NONE);\n        // 2. 开启 Http 客户端\n        OkHttpClient.Builder builder = new OkHttpClient.Builder()\n                .addInterceptor(httpLoggingInterceptor)\n                .addInterceptor(new BaseUrlInterceptor())\n                .addInterceptor(new ResponseInterceptor())// 设置返回信息拦截器\n                .connectTimeout(450, TimeUnit.SECONDS)\n                .writeTimeout(450, TimeUnit.SECONDS)\n                .readTimeout(450, TimeUnit.SECONDS);\n        // 3. 检查是否需要代理\n        if (configuration.getProxy() != null) {\n            builder.proxy(configuration.getProxy());\n        }\n        return builder.build();\n    }\n\n    @Override\n    public SparkApiServer createApiServer(OkHttpClient okHttpClient) {\n        return new Retrofit.Builder()\n                .baseUrl(configuration.getApiHost())\n                .client(okHttpClient)\n                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())\n                .addConverterFactory(JacksonConverterFactory.create())\n                .build().create(SparkApiServer.class);\n    }\n\n    @Override\n    public AggregationSession openAggregationSession() {\n        OkHttpClient okHttpClient = createHttpClient();\n        configuration.setOkHttpClient(okHttpClient);\n        configuration.setSparkApiServer(createApiServer(okHttpClient));\n        return new DefaultAggregationSession(configuration);\n    }\n}\n"
  },
  {
    "path": "ai-spark/src/main/java/com/ai/spark/achieve/defaults/listener/BaseListener.java",
    "content": "package com.ai.spark.achieve.defaults.listener;\n\nimport lombok.Data;\nimport lombok.extern.slf4j.Slf4j;\nimport okhttp3.Response;\nimport okhttp3.WebSocket;\nimport okhttp3.WebSocketListener;\nimport okio.ByteString;\nimport org.jetbrains.annotations.NotNull;\nimport org.jetbrains.annotations.Nullable;\n\n@Slf4j\n@Data\npublic abstract class BaseListener<REQ, RESP> extends WebSocketListener {\n\n    /**\n     * WebSocket服务发生异常的回调，可以覆盖重写。\n     * 默认抛出异常\n     *\n     * @param t        异常\n     * @param response 返回值\n     */\n    public void onWebSocketError(Throwable t, Response response) {\n        log.error(\"调用星火模型时，WebSocket发生异常:{}\", response);\n        t.printStackTrace();\n    }\n\n    /**\n     * 星火大模型发生异常\n     *\n     * @param resp 大模型返回值\n     */\n    public abstract void onChatError(RESP resp);\n\n    /**\n     * 星火大模型正常返回信息\n     *\n     * @param resp 大模型返回值\n     */\n    public abstract void onChatOutput(RESP resp);\n\n    /**\n     * 星火大模型返回信息结束回调\n     */\n    public abstract void onChatEnd();\n\n    @Override\n    public void onClosed(@NotNull WebSocket webSocket, int code, @NotNull String reason) {\n        super.onClosed(webSocket, code, reason);\n    }\n\n    @Override\n    public void onClosing(@NotNull WebSocket webSocket, int code, @NotNull String reason) {\n        super.onClosing(webSocket, code, reason);\n    }\n\n    @Override\n    public void onFailure(@NotNull WebSocket webSocket, @NotNull Throwable t, @Nullable Response response) {\n        webSocket.close(1000, \"\");\n        this.onWebSocketError(t, response);\n    }\n\n    @Override\n    public abstract void onMessage(@NotNull WebSocket webSocket, @NotNull String text);\n\n    @Override\n    public void onMessage(@NotNull WebSocket webSocket, @NotNull ByteString bytes) {\n        super.onMessage(webSocket, bytes);\n    }\n\n    @Override\n    public void onOpen(@NotNull WebSocket webSocket, @NotNull Response response) {\n        super.onOpen(webSocket, response);\n    }\n}\n"
  },
  {
    "path": "ai-spark/src/main/java/com/ai/spark/achieve/defaults/listener/ChatListener.java",
    "content": "package com.ai.spark.achieve.defaults.listener;\n\nimport com.ai.common.utils.JsonUtils;\nimport com.ai.spark.common.Usage;\nimport com.ai.spark.endPoint.chat.ChatHeader;\nimport com.ai.spark.endPoint.chat.Choice;\nimport com.ai.spark.endPoint.chat.req.ChatRequest;\nimport com.ai.spark.endPoint.chat.resp.ChatResponse;\nimport lombok.Data;\nimport lombok.extern.slf4j.Slf4j;\nimport okhttp3.Response;\nimport okhttp3.WebSocket;\nimport okio.ByteString;\nimport org.jetbrains.annotations.NotNull;\nimport org.jetbrains.annotations.Nullable;\n\nimport static com.ai.common.utils.ValidationUtils.ensureNotNull;\n\n/**\n * 星火大模型流式返回监听器\n */\n@Slf4j\n@Data\npublic abstract class ChatListener extends BaseListener<ChatRequest, ChatResponse> {\n\n    private ChatRequest chatRequest;\n\n    public ChatListener(ChatRequest chatRequest) {\n        this.chatRequest = ensureNotNull(chatRequest, \"chatRequest\");\n    }\n\n    /**\n     * WebSocket服务发生异常的回调，可以覆盖重写。\n     * 默认抛出异常\n     *\n     * @param t        异常\n     * @param response 返回值\n     */\n    public void onWebSocketError(Throwable t, Response response) {\n        log.error(\"调用星火模型时，WebSocket发生异常:{}\", response);\n        t.printStackTrace();\n    }\n\n    /**\n     * 星火大模型发生异常\n     *\n     * @param chatResponse 大模型返回值\n     */\n    public abstract void onChatError(ChatResponse chatResponse);\n\n    /**\n     * 星火大模型正常返回信息\n     *\n     * @param chatResponse 大模型返回值\n     */\n    public abstract void onChatOutput(ChatResponse chatResponse);\n\n    /**\n     * 星火大模型返回信息结束回调\n     */\n    public abstract void onChatEnd();\n\n    @Override\n    public void onClosed(@NotNull WebSocket webSocket, int code, @NotNull String reason) {\n        super.onClosed(webSocket, code, reason);\n    }\n\n    @Override\n    public void onClosing(@NotNull WebSocket webSocket, int code, @NotNull String reason) {\n        super.onClosing(webSocket, code, reason);\n    }\n\n    @Override\n    public void onFailure(@NotNull WebSocket webSocket, @NotNull Throwable t, @Nullable Response response) {\n        webSocket.close(1000, \"\");\n        this.onWebSocketError(t, response);\n    }\n\n    @Override\n    public void onMessage(@NotNull WebSocket webSocket, @NotNull String text) {\n        ChatResponse chatResponse = JsonUtils.fromJson(text, ChatResponse.class);\n\n        if (ChatHeader.Code.SUCCESS.getValue() != chatResponse.getChatHeader().getCode()) {\n            log.warn(\"调用星火模型发生错误，错误码为：{}，请求的sid为：{}\", chatResponse.getChatHeader().getCode(), chatResponse.getChatHeader().getSid());\n            webSocket.close(1000, \"星火模型调用异常\");\n            this.onChatError(chatResponse);\n            return;\n        }\n\n        this.onChatOutput(chatResponse);\n\n        if (Choice.Status.END.getValue() == chatResponse.getChatHeader().getStatus()) {\n            // 可以关闭连接，释放资源\n            webSocket.close(1000, \"星火模型返回结束\");\n            Usage usage = chatResponse.getChatPayload().getUsage();\n            this.onChatEnd();\n        }\n    }\n\n    @Override\n    public void onMessage(@NotNull WebSocket webSocket, @NotNull ByteString bytes) {\n        super.onMessage(webSocket, bytes);\n    }\n\n    @Override\n    public void onOpen(@NotNull WebSocket webSocket, @NotNull Response response) {\n        super.onOpen(webSocket, response);\n        webSocket.send(JsonUtils.toJson(chatRequest));\n    }\n}\n"
  },
  {
    "path": "ai-spark/src/main/java/com/ai/spark/achieve/defaults/listener/DocumentChatListener.java",
    "content": "package com.ai.spark.achieve.defaults.listener;\n\nimport com.ai.common.utils.JsonUtils;\nimport com.ai.spark.endPoint.chat.req.DocumentChatRequest;\nimport com.ai.spark.endPoint.chat.resp.DocumentChatResponse;\nimport lombok.Data;\nimport lombok.extern.slf4j.Slf4j;\nimport okhttp3.Response;\nimport okhttp3.WebSocket;\nimport okio.ByteString;\nimport org.jetbrains.annotations.NotNull;\nimport org.jetbrains.annotations.Nullable;\n\nimport static com.ai.common.utils.ValidationUtils.ensureNotNull;\n\n/**\n * 星火大模型文档对话流式返回监听器\n */\n@Slf4j\n@Data\npublic abstract class DocumentChatListener extends BaseListener<DocumentChatRequest, DocumentChatResponse> {\n\n    private DocumentChatRequest documentChatRequest;\n\n    /**\n     * 构造方法，传入大模型参数\n     *\n     * @param documentChatRequest 大模型参数\n     */\n    public DocumentChatListener(DocumentChatRequest documentChatRequest) {\n        this.documentChatRequest = ensureNotNull(documentChatRequest, \"documentChatRequest\");\n    }\n\n    /**\n     * WebSocket服务发生异常的回调，可以覆盖重写。\n     * 默认抛出异常\n     *\n     * @param t        异常\n     * @param response 返回值\n     */\n    public void onWebSocketError(Throwable t, Response response) {\n        log.error(\"调用星火模型时，WebSocket发生异常:{}\", response);\n        t.printStackTrace();\n    }\n\n    /**\n     * 星火大模型发生异常\n     *\n     * @param documentChatResponse 大模型返回值\n     */\n    public abstract void onChatError(DocumentChatResponse documentChatResponse);\n\n    /**\n     * 星火大模型正常返回信息\n     *\n     * @param documentChatResponse 大模型返回值\n     */\n    public abstract void onChatOutput(DocumentChatResponse documentChatResponse);\n\n    /**\n     * 星火大模型返回信息结束回调\n     */\n    public abstract void onChatEnd();\n\n    @Override\n    public void onClosed(@NotNull WebSocket webSocket, int code, @NotNull String reason) {\n        super.onClosed(webSocket, code, reason);\n    }\n\n    @Override\n    public void onClosing(@NotNull WebSocket webSocket, int code, @NotNull String reason) {\n        super.onClosing(webSocket, code, reason);\n    }\n\n    @Override\n    public void onFailure(@NotNull WebSocket webSocket, @NotNull Throwable t, @Nullable Response response) {\n        webSocket.close(1000, \"\");\n        this.onWebSocketError(t, response);\n    }\n\n    @Override\n    public void onMessage(@NotNull WebSocket webSocket, @NotNull String text) {\n        DocumentChatResponse documentChatResponse = JsonUtils.fromJson(text, DocumentChatResponse.class);\n\n        if (DocumentChatResponse.Code.SUCCESS.getValue() != documentChatResponse.getCode()) {\n            log.warn(\"调用星火模型文档对话发生错误，错误码为：{}，请求的sid为：{}\", documentChatResponse.getCode(), documentChatResponse.getSid());\n            webSocket.close(1000, \"星火模型调用异常\");\n            this.onChatError(documentChatResponse);\n            return;\n        }\n\n        this.onChatOutput(documentChatResponse);\n\n        if (DocumentChatResponse.Status.END.getValue() == documentChatResponse.getStatus()) {\n            // 可以关闭连接，释放资源\n            webSocket.close(1000, \"星火模型返回结束\");\n            this.onChatEnd();\n        }\n    }\n\n    @Override\n    public void onMessage(@NotNull WebSocket webSocket, @NotNull ByteString bytes) {\n        super.onMessage(webSocket, bytes);\n    }\n\n    @Override\n    public void onOpen(@NotNull WebSocket webSocket, @NotNull Response response) {\n        super.onOpen(webSocket, response);\n        webSocket.send(JsonUtils.toJson(documentChatRequest));\n    }\n}\n"
  },
  {
    "path": "ai-spark/src/main/java/com/ai/spark/achieve/defaults/listener/ImageUnderstandingListener.java",
    "content": "package com.ai.spark.achieve.defaults.listener;\n\nimport com.ai.common.utils.JsonUtils;\nimport com.ai.spark.endPoint.chat.ChatHeader;\nimport com.ai.spark.endPoint.chat.Choice;\nimport com.ai.spark.endPoint.chat.resp.DocumentChatResponse;\nimport com.ai.spark.endPoint.images.ImageHeader;\nimport com.ai.spark.endPoint.images.req.ImageUnderstandingRequest;\nimport com.ai.spark.endPoint.images.resp.ImageUnderstandingResponse;\nimport lombok.Data;\nimport lombok.extern.slf4j.Slf4j;\nimport okhttp3.Response;\nimport okhttp3.WebSocket;\nimport okio.ByteString;\nimport org.jetbrains.annotations.NotNull;\nimport org.jetbrains.annotations.Nullable;\n\nimport static com.ai.common.utils.ValidationUtils.ensureNotNull;\n\n/**\n * 图片理解对话监听器\n */\n@Slf4j\n@Data\npublic abstract class ImageUnderstandingListener extends BaseListener<ImageUnderstandingRequest, ImageUnderstandingResponse> {\n\n    private ImageUnderstandingRequest imageUnderstandingRequest;\n\n    /**\n     * 构造方法，传入大模型参数\n     *\n     * @param imageUnderstandingRequest 大模型参数\n     */\n    public ImageUnderstandingListener(ImageUnderstandingRequest imageUnderstandingRequest) {\n        this.imageUnderstandingRequest = ensureNotNull(imageUnderstandingRequest, \"documentChatRequest\");\n    }\n\n    /**\n     * WebSocket服务发生异常的回调，可以覆盖重写。\n     * 默认抛出异常\n     *\n     * @param t        异常\n     * @param response 返回值\n     */\n    public void onWebSocketError(Throwable t, Response response) {\n        log.error(\"调用星火模型时，WebSocket发生异常:{}\", response);\n        t.printStackTrace();\n    }\n\n    /**\n     * 星火大模型发生异常\n     *\n     * @param imageUnderstandingResponse 大模型返回值\n     */\n    public abstract void onChatError(ImageUnderstandingResponse imageUnderstandingResponse);\n\n    /**\n     * 星火大模型正常返回信息\n     *\n     * @param imageUnderstandingResponse 大模型返回值\n     */\n    public abstract void onChatOutput(ImageUnderstandingResponse imageUnderstandingResponse);\n\n    /**\n     * 星火大模型返回信息结束回调\n     */\n    public abstract void onChatEnd();\n\n    @Override\n    public void onClosed(@NotNull WebSocket webSocket, int code, @NotNull String reason) {\n        super.onClosed(webSocket, code, reason);\n    }\n\n    @Override\n    public void onClosing(@NotNull WebSocket webSocket, int code, @NotNull String reason) {\n        super.onClosing(webSocket, code, reason);\n    }\n\n    @Override\n    public void onFailure(@NotNull WebSocket webSocket, @NotNull Throwable t, @Nullable Response response) {\n        webSocket.close(1000, \"\");\n        this.onWebSocketError(t, response);\n    }\n\n    @Override\n    public void onMessage(@NotNull WebSocket webSocket, @NotNull String text) {\n        ImageUnderstandingResponse imageUnderstandingResponse = JsonUtils.fromJson(text, ImageUnderstandingResponse.class);\n\n        ImageHeader imageHeader = imageUnderstandingResponse.getImageHeader();\n        if (imageHeader.getCode() != ChatHeader.Code.SUCCESS.getValue()) {\n            log.warn(\"调用星火模型文档对话发生错误，错误码为：{}，请求的sid为：{}\", imageHeader.getCode(), imageHeader.getSid());\n            webSocket.close(1000, \"星火模型调用异常\");\n            this.onChatError(imageUnderstandingResponse);\n            return;\n        }\n\n        this.onChatOutput(imageUnderstandingResponse);\n\n        if (DocumentChatResponse.Status.END.getValue() == Choice.Status.END.getValue()) {\n            // 可以关闭连接，释放资源\n            webSocket.close(1000, \"星火模型返回结束\");\n            this.onChatEnd();\n        }\n    }\n\n    @Override\n    public void onMessage(@NotNull WebSocket webSocket, @NotNull ByteString bytes) {\n        super.onMessage(webSocket, bytes);\n    }\n\n    @Override\n    public void onOpen(@NotNull WebSocket webSocket, @NotNull Response response) {\n        super.onOpen(webSocket, response);\n        webSocket.send(JsonUtils.toJson(imageUnderstandingRequest));\n    }\n}\n"
  },
  {
    "path": "ai-spark/src/main/java/com/ai/spark/achieve/defaults/session/DefaultAggregationSession.java",
    "content": "package com.ai.spark.achieve.defaults.session;\n\nimport com.ai.spark.achieve.Configuration;\nimport com.ai.spark.achieve.standard.session.*;\n\nimport static com.ai.common.utils.ValidationUtils.ensureNotNull;\n\n/**\n * 聚合各个场景的session\n */\npublic class DefaultAggregationSession implements AggregationSession {\n\n    private Configuration configuration;\n\n    private volatile ChatSession chatSession;\n\n    private volatile DocumentSession documentSession;\n\n    private volatile EmbeddingSession embeddingSession;\n\n    private volatile ImageSession imageSession;\n\n    private volatile AudioSession audioSession;\n\n    public DefaultAggregationSession(Configuration configuration) {\n        this.configuration = ensureNotNull(configuration, \"configuration\");\n    }\n\n    @Override\n    public ChatSession getChatSession() {\n        if (chatSession == null) {\n            synchronized (this) {\n                if (chatSession == null) {\n                    chatSession = new DefaultChatSession(configuration);\n                }\n            }\n        }\n        return chatSession;\n    }\n\n    @Override\n    public DocumentSession getDocumentSession() {\n        if (documentSession == null) {\n            synchronized (this) {\n                if (documentSession == null) {\n                    documentSession = new DefaultDocumentSession(configuration);\n                }\n            }\n        }\n        return documentSession;\n    }\n\n    @Override\n    public EmbeddingSession getEmbeddingSession() {\n        if (embeddingSession == null) {\n            synchronized (this) {\n                if (embeddingSession == null) {\n                    embeddingSession = new DefaultEmbeddingSession(configuration);\n                }\n            }\n        }\n        return embeddingSession;\n    }\n\n    @Override\n    public ImageSession getImageSession() {\n        if (imageSession == null) {\n            synchronized (this) {\n                if (imageSession == null) {\n                    imageSession = new DefaultImageSession(configuration);\n                }\n            }\n        }\n        return imageSession;\n    }\n\n    @Override\n    public AudioSession getAudioSession() {\n        if (audioSession == null) {\n            synchronized (this) {\n                if (audioSession == null) {\n                    audioSession = new DefaultAudioSession(configuration);\n                }\n            }\n        }\n        return audioSession;\n    }\n\n}\n"
  },
  {
    "path": "ai-spark/src/main/java/com/ai/spark/achieve/defaults/session/DefaultAudioSession.java",
    "content": "package com.ai.spark.achieve.defaults.session;\n\nimport com.ai.spark.achieve.Configuration;\nimport com.ai.spark.achieve.standard.session.AudioSession;\nimport lombok.Data;\nimport lombok.EqualsAndHashCode;\nimport lombok.ToString;\n\nimport static com.ai.common.utils.ValidationUtils.ensureNotNull;\n\n@Data\n@ToString(callSuper = true)\n@EqualsAndHashCode(callSuper = true)\npublic class DefaultAudioSession extends Session implements AudioSession {\n\n    public DefaultAudioSession(Configuration configuration) {\n        this.setConfiguration(ensureNotNull(configuration, \"configuration\"));\n        this.setSparkApiServer(ensureNotNull(configuration.getSparkApiServer(), \"sparkApiServer\"));\n    }\n}\n"
  },
  {
    "path": "ai-spark/src/main/java/com/ai/spark/achieve/defaults/session/DefaultChatSession.java",
    "content": "package com.ai.spark.achieve.defaults.session;\n\n\nimport cn.hutool.core.date.DateUtil;\nimport com.ai.spark.achieve.ApiData;\nimport com.ai.spark.achieve.Configuration;\nimport com.ai.spark.achieve.defaults.listener.ChatListener;\nimport com.ai.spark.achieve.defaults.listener.DocumentChatListener;\nimport com.ai.spark.achieve.standard.session.ChatSession;\nimport com.ai.spark.common.SparkApiUrl;\nimport com.ai.spark.common.utils.AuthUtils;\nimport lombok.Data;\nimport lombok.EqualsAndHashCode;\nimport lombok.SneakyThrows;\nimport lombok.ToString;\nimport okhttp3.Request;\nimport okhttp3.WebSocket;\n\nimport static com.ai.common.utils.ValidationUtils.ensureNotNull;\nimport static com.ai.spark.common.SparkApiUrl.DOCUMENT_CHAT;\n\n@Data\n@ToString(callSuper = true)\n@EqualsAndHashCode(callSuper = true)\npublic class DefaultChatSession extends Session implements ChatSession {\n\n    public DefaultChatSession(Configuration configuration) {\n        this.setConfiguration(ensureNotNull(configuration, \"configuration\"));\n        this.setSparkApiServer(ensureNotNull(configuration.getSparkApiServer(), \"sparkApiServer\"));\n    }\n\n    @Override\n    @SneakyThrows\n    public <T extends ChatListener> WebSocket chat(T chatListener) {\n        // 默认情况下根据apiData获取策略得到创建时设置的参数\n        ApiData apiData = this.getConfiguration().getSystemApiData();\n        return this.chat(apiData.getApiKey(), apiData.getApiSecret(), chatListener);\n    }\n\n    @Override\n    @SneakyThrows\n    public <T extends ChatListener> WebSocket chat(String apiKey, String apiSecret, T chatListener) {\n        // 获取到对应访问的domain，根据domain获取对应的请求地址\n        String domain = chatListener.getChatRequest().getChatParameter().getChat().getDomain();\n        // 生成请求的URL\n        String url = AuthUtils.replaceAllHttp(\n                AuthUtils.getAuthUrl(AuthUtils.RequestMethod.GET.getMethod(), SparkApiUrl.getUrl(domain), apiKey, apiSecret)\n        );\n        // 发起请求返回结果\n        return this.getConfiguration().getOkHttpClient().newWebSocket(new Request.Builder().url(url).build(), chatListener);\n    }\n\n    @Override\n    public <T extends DocumentChatListener> WebSocket documentChat(T documentChatListener) {\n        ApiData apiData = this.getConfiguration().getSystemApiData();\n        return documentChat(apiData.getAppId(), apiData.getApiSecret(), documentChatListener);\n    }\n\n    @Override\n    public <T extends DocumentChatListener> WebSocket documentChat(String appId, String apiSecret, T documentChatListener) {\n        // 得当当前时间戳，按秒计算\n        long ts = DateUtil.currentSeconds();\n        // 进行签名设置\n        String url = SparkApiUrl.getUrl(DOCUMENT_CHAT) + \"?\"\n                + \"appId=\" + appId\n                + \"&timestamp=\" + ts\n                + \"&signature=\" + AuthUtils.getSignature(appId, apiSecret, ts);\n        // 发起请求返回结果\n        return this.getConfiguration().getOkHttpClient().newWebSocket(new Request.Builder().url(url).build(), documentChatListener);\n    }\n\n}\n"
  },
  {
    "path": "ai-spark/src/main/java/com/ai/spark/achieve/defaults/session/DefaultDocumentSession.java",
    "content": "package com.ai.spark.achieve.defaults.session;\n\nimport cn.hutool.core.date.DateUtil;\nimport cn.hutool.core.util.StrUtil;\nimport com.ai.spark.achieve.ApiData;\nimport com.ai.spark.achieve.Configuration;\nimport com.ai.spark.achieve.standard.session.DocumentSession;\nimport com.ai.spark.common.SparkApiUrl;\nimport com.ai.spark.common.utils.AuthUtils;\nimport com.ai.spark.endPoint.document.req.FileUploadRequest;\nimport com.ai.spark.endPoint.document.resp.DocumentSummaryResponse;\nimport com.ai.spark.endPoint.document.resp.FileUploadResponse;\nimport lombok.Data;\nimport lombok.EqualsAndHashCode;\nimport lombok.ToString;\nimport okhttp3.MediaType;\nimport okhttp3.MultipartBody;\nimport okhttp3.RequestBody;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport static com.ai.common.utils.ValidationUtils.ensureNotNull;\n\n@Data\n@ToString(callSuper = true)\n@EqualsAndHashCode(callSuper = true)\npublic class DefaultDocumentSession extends Session implements DocumentSession {\n\n    public DefaultDocumentSession(Configuration configuration) {\n        this.setConfiguration(ensureNotNull(configuration, \"configuration\"));\n        this.setSparkApiServer(ensureNotNull(configuration.getSparkApiServer(), \"sparkApiServer\"));\n    }\n\n    @Override\n    public FileUploadResponse fileUpload(FileUploadRequest fileUploadRequest) {\n        ApiData apiData = this.getConfiguration().getSystemApiData();\n        return this.fileUpload(apiData.getAppId(), apiData.getApiSecret(), fileUploadRequest);\n    }\n\n    @Override\n    public FileUploadResponse fileUpload(String appId, String apiSecret, FileUploadRequest fileUploadRequest) {\n        // 得到当前时间戳，按秒计算\n        long ts = DateUtil.currentSeconds();\n        // 设置文件\n        RequestBody fileBody = RequestBody.create(MediaType.parse(\"multipart/form-data\"), fileUploadRequest.getFile());\n        MultipartBody.Part multipartBody = MultipartBody.Part.createFormData(\"file\", fileUploadRequest.getFile().getName(), fileBody);\n        // 设置其余参数\n        Map<String, RequestBody> requestBodyMap = new HashMap<>();\n        if (StrUtil.isNotBlank(fileUploadRequest.getUrl())) {\n            requestBodyMap.put(FileUploadRequest.Fields.url, RequestBody.create(MediaType.parse(\"multipart/form-data\"), fileUploadRequest.getUrl()));\n        }\n        if (StrUtil.isNotBlank(fileUploadRequest.getFileName())) {\n            requestBodyMap.put(FileUploadRequest.Fields.fileName, RequestBody.create(MediaType.parse(\"multipart/form-data\"), fileUploadRequest.getFileName()));\n        }\n        if (StrUtil.isNotBlank(fileUploadRequest.getFileType())) {\n            requestBodyMap.put(FileUploadRequest.Fields.fileType, RequestBody.create(MediaType.parse(\"multipart/form-data\"), fileUploadRequest.getFileType()));\n        }\n        if (StrUtil.isNotBlank(fileUploadRequest.getCallbackUrl())) {\n            requestBodyMap.put(FileUploadRequest.Fields.callbackUrl, RequestBody.create(MediaType.parse(\"multipart/form-data\"), fileUploadRequest.getCallbackUrl()));\n        }\n        // 发起请求返回结果\n        return this.getSparkApiServer().fileUpload(appId, String.valueOf(ts), AuthUtils.getSignature(appId, apiSecret, ts), multipartBody, requestBodyMap).blockingGet();\n    }\n\n    @Override\n    public DocumentSummaryResponse documentSummaryStart(String fileId) {\n        ApiData apiData = this.getConfiguration().getSystemApiData();\n        return this.documentSummaryStart(apiData.getAppId(), apiData.getApiSecret(), fileId);\n    }\n\n    @Override\n    public DocumentSummaryResponse documentSummaryStart(String appId, String apiSecret, String fileId) {\n        return this.documentSummary(SparkApiUrl.ApiUrl.documentSummaryStart.getUrl(), appId, apiSecret, fileId);\n    }\n\n    @Override\n    public DocumentSummaryResponse documentSummaryQuery(String fileId) {\n        ApiData apiData = this.getConfiguration().getSystemApiData();\n        return this.documentSummaryQuery(apiData.getAppId(), apiData.getApiSecret(), fileId);\n    }\n\n    @Override\n    public DocumentSummaryResponse documentSummaryQuery(String appId, String apiSecret, String fileId) {\n        return this.documentSummary(SparkApiUrl.ApiUrl.documentSummaryQuery.getUrl(), appId, apiSecret, fileId);\n    }\n\n    /**\n     * 文档总结底层都依赖这个方法\n     *\n     * @param url       请求的URL\n     * @param appId     用户的AppId\n     * @param apiSecret 用户的ApiSecret\n     * @param fileId    文件ID\n     * @return 请求结果\n     */\n    private DocumentSummaryResponse documentSummary(String url, String appId, String apiSecret, String fileId) {\n        long ts = DateUtil.currentSeconds();\n        return this.getSparkApiServer().documentSummary(url, appId, String.valueOf(ts), AuthUtils.getSignature(appId, apiSecret, ts), RequestBody.create(MediaType.parse(\"multipart/form-data\"), fileId)).blockingGet();\n    }\n\n}\n"
  },
  {
    "path": "ai-spark/src/main/java/com/ai/spark/achieve/defaults/session/DefaultEmbeddingSession.java",
    "content": "package com.ai.spark.achieve.defaults.session;\n\nimport cn.hutool.http.ContentType;\nimport com.ai.common.utils.JsonUtils;\nimport com.ai.spark.achieve.ApiData;\nimport com.ai.spark.achieve.Configuration;\nimport com.ai.spark.achieve.standard.session.EmbeddingSession;\nimport com.ai.spark.common.SparkApiUrl;\nimport com.ai.spark.common.utils.AuthUtils;\nimport com.ai.spark.endPoint.embedding.req.EmbeddingRequest;\nimport com.ai.spark.endPoint.embedding.resp.EmbeddingResponse;\nimport lombok.Data;\nimport lombok.EqualsAndHashCode;\nimport lombok.SneakyThrows;\nimport lombok.ToString;\nimport okhttp3.MediaType;\nimport okhttp3.Request;\nimport okhttp3.RequestBody;\n\nimport static com.ai.common.utils.ValidationUtils.ensureNotNull;\n\n@Data\n@ToString(callSuper = true)\n@EqualsAndHashCode(callSuper = true)\npublic class DefaultEmbeddingSession extends Session implements EmbeddingSession {\n\n\n    public DefaultEmbeddingSession(Configuration configuration) {\n        this.setConfiguration(ensureNotNull(configuration, \"configuration\"));\n        this.setSparkApiServer(ensureNotNull(configuration.getSparkApiServer(), \"sparkApiServer\"));\n    }\n\n    @Override\n    public EmbeddingResponse embed(EmbeddingRequest embeddingRequest) {\n        ApiData apiData = this.getConfiguration().getSystemApiData();\n        return this.embed(apiData.getApiKey(), apiData.getApiSecret(), embeddingRequest);\n    }\n\n    @Override\n    @SneakyThrows\n    public EmbeddingResponse embed(String apiKey, String apiSecret, EmbeddingRequest embeddingRequest) {\n        // 鉴权，得到请求路径\n        String authUrl = AuthUtils.getAuthUrl(AuthUtils.RequestMethod.POST.getMethod(), SparkApiUrl.ApiUrl.embeddingq.getUrl(), apiKey, apiSecret);\n        // 创建请求，设置请求URL和json数据\n        Request request = new Request.Builder().url(authUrl).post(RequestBody.create(MediaType.parse(ContentType.JSON.getValue()), JsonUtils.toJson(embeddingRequest))).build();\n        // 发起请求，获取返回的json字符串\n        String response = this.getConfiguration().getOkHttpClient().newCall(request).execute().body().string();\n        // 将json映射到对象上\n        return JsonUtils.fromJson(response, EmbeddingResponse.class);\n    }\n}\n"
  },
  {
    "path": "ai-spark/src/main/java/com/ai/spark/achieve/defaults/session/DefaultImageSession.java",
    "content": "package com.ai.spark.achieve.defaults.session;\n\nimport cn.hutool.http.ContentType;\nimport com.ai.common.utils.JsonUtils;\nimport com.ai.spark.achieve.ApiData;\nimport com.ai.spark.achieve.Configuration;\nimport com.ai.spark.achieve.defaults.listener.ImageUnderstandingListener;\nimport com.ai.spark.achieve.standard.session.ImageSession;\nimport com.ai.spark.common.SparkApiUrl;\nimport com.ai.spark.common.utils.AuthUtils;\nimport com.ai.spark.endPoint.images.req.ImageCreateRequest;\nimport com.ai.spark.endPoint.images.req.ImageUnderstandingRequest;\nimport com.ai.spark.endPoint.images.resp.ImageCreateResponse;\nimport lombok.Data;\nimport lombok.EqualsAndHashCode;\nimport lombok.SneakyThrows;\nimport lombok.ToString;\nimport okhttp3.MediaType;\nimport okhttp3.Request;\nimport okhttp3.RequestBody;\nimport okhttp3.WebSocket;\n\nimport static com.ai.common.utils.ValidationUtils.ensureNotNull;\n\n@Data\n@ToString(callSuper = true)\n@EqualsAndHashCode(callSuper = true)\npublic class DefaultImageSession extends Session implements ImageSession {\n\n    public DefaultImageSession(Configuration configuration) {\n        this.setConfiguration(ensureNotNull(configuration, \"configuration\"));\n        this.setSparkApiServer(ensureNotNull(configuration.getSparkApiServer(), \"sparkApiServer\"));\n    }\n\n    @Override\n    @SneakyThrows\n    public ImageCreateResponse imageCreate(ImageCreateRequest imageCreateRequest) {\n        ApiData apiData = this.getConfiguration().getSystemApiData();\n        return this.imageCreate(apiData.getApiKey(), apiData.getApiSecret(), imageCreateRequest);\n    }\n\n    @Override\n    @SneakyThrows\n    public ImageCreateResponse imageCreate(String apiKey, String apiSecret, ImageCreateRequest imageCreateRequest) {\n        // 鉴权，得到请求路径\n        String authUrl = AuthUtils.getAuthUrl(AuthUtils.RequestMethod.POST.getMethod(), SparkApiUrl.ApiUrl.imageCreate.getUrl(), apiKey, apiSecret);\n        // 创建请求，设置请求URL和json数据\n        Request request = new Request.Builder().url(authUrl).post(RequestBody.create(MediaType.parse(ContentType.JSON.getValue()), JsonUtils.toJson(imageCreateRequest))).build();\n        // 发起请求，获取返回的json字符串\n        String response = this.getConfiguration().getOkHttpClient().newCall(request).execute().body().string();\n        // 将json映射到对象上\n        return JsonUtils.fromJson(response, ImageCreateResponse.class);\n    }\n\n    @Override\n    public <T extends ImageUnderstandingListener> WebSocket imageUnderstanding(ImageUnderstandingRequest imageUnderstandingRequest, ImageUnderstandingListener imageUnderstandingListener) {\n        ApiData apiData = this.getConfiguration().getSystemApiData();\n        return imageUnderstanding(apiData.getApiKey(), apiData.getApiSecret(), imageUnderstandingRequest, imageUnderstandingListener);\n    }\n\n    @Override\n    @SneakyThrows\n    public <T extends ImageUnderstandingListener> WebSocket imageUnderstanding(String apiKey, String apiSecret, ImageUnderstandingRequest imageUnderstandingRequest, ImageUnderstandingListener imageUnderstandingListener) {\n        // 生成请求的URL\n        String url = AuthUtils.replaceAllHttp(\n                AuthUtils.getAuthUrl(AuthUtils.RequestMethod.GET.getMethod(), SparkApiUrl.ApiUrl.imageUnderstanding.getUrl(), apiKey, apiSecret)\n        );\n        // 发起请求返回结果\n        return this.getConfiguration().getOkHttpClient().newWebSocket(new Request.Builder().url(url).build(), imageUnderstandingListener);\n    }\n}\n"
  },
  {
    "path": "ai-spark/src/main/java/com/ai/spark/achieve/defaults/session/Session.java",
    "content": "package com.ai.spark.achieve.defaults.session;\n\nimport com.ai.spark.achieve.Configuration;\nimport com.ai.spark.achieve.standard.api.SparkApiServer;\nimport lombok.Data;\n\n@Data\npublic class Session {\n\n    private Configuration configuration;\n\n    private SparkApiServer sparkApiServer;\n\n}\n"
  },
  {
    "path": "ai-spark/src/main/java/com/ai/spark/achieve/standard/api/SparkApiServer.java",
    "content": "package com.ai.spark.achieve.standard.api;\n\n\nimport com.ai.spark.endPoint.document.resp.DocumentSummaryResponse;\nimport com.ai.spark.endPoint.document.resp.FileUploadResponse;\nimport io.reactivex.Single;\nimport okhttp3.MultipartBody;\nimport okhttp3.RequestBody;\nimport retrofit2.http.*;\n\nimport java.util.Map;\n\nimport static com.ai.spark.common.Constants.*;\nimport static com.ai.spark.common.SparkApiUrl.FILE_UPLOAD_API_URL;\n\n/**\n * @Description: 讯飞星火 API接口\n */\npublic interface SparkApiServer {\n\n    /**\n     * 文件上传接口\n     *\n     * @param appId          用户appId\n     * @param timestamp      当前时间戳（秒）\n     * @param signature      生成的签名\n     * @param file           需要上传的文件\n     * @param requestBodyMap 其他字段\n     * @return 文件上传返回参数\n     */\n    @Multipart\n    @POST(FILE_UPLOAD_API_URL)\n    Single<FileUploadResponse> fileUpload(@Header(APP_ID) String appId, @Header(TIMESTAMP) String timestamp, @Header(SIGNATURE) String signature, @Part MultipartBody.Part file, @PartMap Map<String, RequestBody> requestBodyMap);\n\n    /**\n     * 文档总结，文档总结结果查询两个接口二合一，参数都一样，请求路径不同\n     *\n     * @param url       请求地址\n     * @param appId     用户appId\n     * @param timestamp 当前时间戳（秒）\n     * @param signature 生成的签名\n     * @param fileId    文件ID\n     * @return 请求结果信息\n     */\n    @Multipart\n    @POST\n    Single<DocumentSummaryResponse> documentSummary(@Url String url, @Header(APP_ID) String appId, @Header(TIMESTAMP) String timestamp, @Header(SIGNATURE) String signature, @Part(\"fileId\") RequestBody fileId);\n\n\n}\n"
  },
  {
    "path": "ai-spark/src/main/java/com/ai/spark/achieve/standard/session/AggregationSession.java",
    "content": "package com.ai.spark.achieve.standard.session;\n\n\npublic interface AggregationSession {\n\n    ChatSession getChatSession();\n\n    DocumentSession getDocumentSession();\n\n    EmbeddingSession getEmbeddingSession();\n\n    ImageSession getImageSession();\n\n    AudioSession getAudioSession();\n\n}\n"
  },
  {
    "path": "ai-spark/src/main/java/com/ai/spark/achieve/standard/session/AudioSession.java",
    "content": "package com.ai.spark.achieve.standard.session;\n\n\npublic interface AudioSession {\n\n}\n"
  },
  {
    "path": "ai-spark/src/main/java/com/ai/spark/achieve/standard/session/ChatSession.java",
    "content": "package com.ai.spark.achieve.standard.session;\n\n\nimport com.ai.spark.achieve.defaults.listener.ChatListener;\nimport com.ai.spark.achieve.defaults.listener.DocumentChatListener;\nimport okhttp3.WebSocket;\n\n/**\n * 对话场景下的接口\n */\npublic interface ChatSession {\n\n    /**\n     * 聊天接口\n     *\n     * @param chatListener 对话监听器\n     * @return 返回信息\n     */\n    <T extends ChatListener> WebSocket chat(T chatListener);\n\n    /**\n     * 聊天接口，自定义所使用的到的ApiKey和ApiSecret\n     *\n     * @param apiKey       用户的ApiKey\n     * @param apiSecret    用户的ApiSecret\n     * @param chatListener 对话监听器\n     * @return 返回信息\n     */\n    <T extends ChatListener> WebSocket chat(String apiKey, String apiSecret, T chatListener);\n\n    /**\n     * 文档聊天接口\n     *\n     * @param documentChatListener 对话监听器\n     * @return 返回信息\n     */\n    <T extends DocumentChatListener> WebSocket documentChat(T documentChatListener);\n\n    /**\n     * 聊天接口，自定义所使用的到的AppId和ApiSecret\n     *\n     * @param appId                用户的AppId\n     * @param apiSecret            用户的ApiSecret\n     * @param documentChatListener 对话监听器\n     * @return 返回信息\n     */\n    <T extends DocumentChatListener> WebSocket documentChat(String appId, String apiSecret, T documentChatListener);\n\n}\n"
  },
  {
    "path": "ai-spark/src/main/java/com/ai/spark/achieve/standard/session/DocumentSession.java",
    "content": "package com.ai.spark.achieve.standard.session;\n\n\nimport com.ai.spark.endPoint.document.req.FileUploadRequest;\nimport com.ai.spark.endPoint.document.resp.DocumentSummaryResponse;\nimport com.ai.spark.endPoint.document.resp.FileUploadResponse;\n\n/**\n * 文档场景下的接口\n */\npublic interface DocumentSession {\n\n    /**\n     * 文件上传\n     *\n     * @param fileUploadRequest 上传的信息\n     * @return 返回信息\n     */\n    FileUploadResponse fileUpload(FileUploadRequest fileUploadRequest);\n\n    /**\n     * 文件上传\n     *\n     * @param appId             用户的AppId\n     * @param apiSecret         用户的ApiSecret\n     * @param fileUploadRequest 上传的信息\n     * @return 返回信息\n     */\n    FileUploadResponse fileUpload(String appId, String apiSecret, FileUploadRequest fileUploadRequest);\n\n    /**\n     * 发起文档总结接口\n     *\n     * @param fileId 文件ID\n     * @return 返回信息\n     */\n    DocumentSummaryResponse documentSummaryStart(String fileId);\n\n    /**\n     * 发起文档总结接口\n     *\n     * @param appId     用户的AppId\n     * @param apiSecret 用户的ApiSecret\n     * @param fileId    文件ID\n     * @return 返回信息\n     */\n    DocumentSummaryResponse documentSummaryStart(String appId, String apiSecret, String fileId);\n\n    /**\n     * 查询文档总结结果\n     *\n     * @param fileId 文件ID\n     * @return 返回信息\n     */\n    DocumentSummaryResponse documentSummaryQuery(String fileId);\n\n    /**\n     * 查询文档总结结果\n     *\n     * @param appId     用户的AppId\n     * @param apiSecret 用户的ApiSecret\n     * @param fileId    文件ID\n     * @return 返回信息\n     */\n    DocumentSummaryResponse documentSummaryQuery(String appId, String apiSecret, String fileId);\n\n}\n"
  },
  {
    "path": "ai-spark/src/main/java/com/ai/spark/achieve/standard/session/EmbeddingSession.java",
    "content": "package com.ai.spark.achieve.standard.session;\n\n\nimport com.ai.spark.endPoint.embedding.req.EmbeddingRequest;\nimport com.ai.spark.endPoint.embedding.resp.EmbeddingResponse;\n\n/**\n * 文本嵌入场景下的接口\n */\npublic interface EmbeddingSession {\n\n    /**\n     * 文本嵌入\n     *\n     * @param embeddingRequest 请求参数\n     * @return 请求结果\n     */\n    EmbeddingResponse embed(EmbeddingRequest embeddingRequest);\n\n    /**\n     * 文本嵌入\n     *\n     * @param apiKey           用户的ApiKey\n     * @param apiSecret        用户的ApiSecret\n     * @param embeddingRequest 请求参数\n     * @return 请求结果\n     */\n    EmbeddingResponse embed(String apiKey, String apiSecret, EmbeddingRequest embeddingRequest);\n\n}\n"
  },
  {
    "path": "ai-spark/src/main/java/com/ai/spark/achieve/standard/session/ImageSession.java",
    "content": "package com.ai.spark.achieve.standard.session;\n\n\nimport com.ai.spark.achieve.defaults.listener.ImageUnderstandingListener;\nimport com.ai.spark.endPoint.images.req.ImageCreateRequest;\nimport com.ai.spark.endPoint.images.req.ImageUnderstandingRequest;\nimport com.ai.spark.endPoint.images.resp.ImageCreateResponse;\nimport okhttp3.WebSocket;\n\n/**\n * 图片生成场景下的接口\n */\npublic interface ImageSession {\n\n    /**\n     * 图片创作接口，使用系统默认的ApiData\n     *\n     * @param imageCreateRequest 请求参数\n     * @return 请求结果\n     */\n    ImageCreateResponse imageCreate(ImageCreateRequest imageCreateRequest);\n\n    /**\n     * 图片创作接口，使用自定义的ApiData\n     *\n     * @param apiKey             用户的ApiKey\n     * @param apiSecret          用户的ApiSecret\n     * @param imageCreateRequest 请求参数\n     * @return 请求结果\n     */\n    ImageCreateResponse imageCreate(String apiKey, String apiSecret, ImageCreateRequest imageCreateRequest);\n\n    /**\n     * 图片理解\n     *\n     * @param imageUnderstandingRequest 请求参数\n     * @return 请求结果\n     */\n    public <T extends ImageUnderstandingListener> WebSocket imageUnderstanding(ImageUnderstandingRequest imageUnderstandingRequest, ImageUnderstandingListener imageUnderstandingListener);\n\n    /**\n     * 图片理解\n     *\n     * @param apiKey                    用户的ApiKey\n     * @param apiSecret                 用户的ApiSecret\n     * @param imageUnderstandingRequest 请求参数\n     * @return 请求结果\n     */\n    public <T extends ImageUnderstandingListener> WebSocket imageUnderstanding(String apiKey, String apiSecret, ImageUnderstandingRequest imageUnderstandingRequest, ImageUnderstandingListener imageUnderstandingListener);\n\n}\n"
  },
  {
    "path": "ai-spark/src/main/java/com/ai/spark/common/Constants.java",
    "content": "package com.ai.spark.common;\n\n\npublic class Constants {\n\n    public static final String APP_ID = \"appId\";\n    public static final String TIMESTAMP = \"timestamp\";\n    public static final String SIGNATURE = \"signature\";\n\n}\n"
  },
  {
    "path": "ai-spark/src/main/java/com/ai/spark/common/SparkApiUrl.java",
    "content": "package com.ai.spark.common;\n\nimport lombok.AllArgsConstructor;\nimport lombok.Getter;\nimport lombok.extern.slf4j.Slf4j;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * 记录各个API的请求URL\n */\n@Slf4j\npublic class SparkApiUrl {\n    // 星火模型对话链接\n    public final static String GENERAL_V1 = \"general\";\n    public final static String GENERAL_V2 = \"generalv2\";\n    public final static String GENERAL_V3 = \"generalv3\";\n    public final static String SPARK_API_HOST_WS_V1_1_URL = \"http://spark-api.xf-yun.com/v1.1/chat\";\n    public final static String SPARK_API_HOST_WSS_V1_1_URL = \"https://spark-api.xf-yun.com/v1.1/chat\";\n    public final static String SPARK_API_HOST_WS_V2_1_URL = \"http://spark-api.xf-yun.com/v2.1/chat\";\n    public final static String SPARK_API_HOST_WSS_V2_1_URL = \"https://spark-api.xf-yun.com/v2.1/chat\";\n    public final static String SPARK_API_HOST_WS_V3_1_URL = \"http://spark-api.xf-yun.com/v3.1/chat\";\n    public final static String SPARK_API_HOST_WSS_V3_1_URL = \"https://spark-api.xf-yun.com/v3.1/chat\";\n\n    // 文档对话文件上传链接\n    public final static String FILE_UPLOAD = \"fileUpload\";\n    public final static String FILE_UPLOAD_API_URL = \"https://chatdoc.xfyun.cn/openapi/fileUpload\";\n\n    // 文档对话链接\n    public final static String DOCUMENT_CHAT = \"documentChat\";\n    public final static String DOCUMENT_CHAT_API_URL = \"wss://chatdoc.xfyun.cn/openapi/chat\";\n\n    // 文档总结链接\n    public final static String DOCUMENT_SUMMARY_START = \"documentSummaryStart\";\n    public final static String DOCUMENT_SUMMARY_START_API_URL = \"https://chatdoc.xfyun.cn/openapi/startSummary\";\n\n    // 查询文档总结结果链接\n    public final static String DOCUMENT_SUMMARY_QUERY = \"documentSummaryStart\";\n    public final static String DOCUMENT_SUMMARY_QUERY_API_URL = \"https://chatdoc.xfyun.cn/openapi/fileSummary\";\n\n    // 文本嵌入接口\n    public final static String EMBEDDING_P = \"Embeddingp\";\n    public final static String EMBEDDING_P_API_URL = \"https://cn-huabei-1.xf-yun.com/v1/private/sa8a05c27\";\n    public final static String EMBEDDING_Q = \"Embeddingq\";\n    public final static String EMBEDDING_Q_API_URL = \"https://cn-huabei-1.xf-yun.com/v1/private/s50d55a16\";\n\n    // 图片生成接口\n    public final static String IMAGE_CREATE = \"imageCreate\";\n    public final static String IMAGE_CREATE_API_URL = \"https://spark-api.cn-huabei-1.xf-yun.com/v2.1/tti\";\n\n    // 图片理解接口\n    public final static String IMAGE_UNDERSANDING = \"imageUnderstanding\";\n    public final static String IMAGE_UNDERSANDING_API_URL = \"https://spark-api.cn-huabei-1.xf-yun.com/v2.1/image\";\n\n    // 超拟人合成协议接口\n    public final static String HYPERMIMETIC_SYNTHESIS = \"hypermimeticSynthesis\";\n    public final static String HYPERMIMETIC_SYNTHESIS_API_URL = \"wss://cbm01.cn-huabei-1.xf-yun.com/v1/private/medd90fec\";\n\n    public final static Map<String, String> urlMap = new HashMap<>();\n\n    static {\n        urlMap.put(GENERAL_V1, SPARK_API_HOST_WSS_V1_1_URL);\n        urlMap.put(GENERAL_V2, SPARK_API_HOST_WSS_V2_1_URL);\n        urlMap.put(GENERAL_V3, SPARK_API_HOST_WSS_V3_1_URL);\n        urlMap.put(FILE_UPLOAD, FILE_UPLOAD_API_URL);\n        urlMap.put(DOCUMENT_CHAT, DOCUMENT_CHAT_API_URL);\n        urlMap.put(DOCUMENT_SUMMARY_START, DOCUMENT_SUMMARY_START_API_URL);\n        urlMap.put(DOCUMENT_SUMMARY_QUERY, DOCUMENT_SUMMARY_QUERY_API_URL);\n        urlMap.put(EMBEDDING_P, EMBEDDING_P_API_URL);\n        urlMap.put(EMBEDDING_Q, EMBEDDING_Q_API_URL);\n        urlMap.put(IMAGE_CREATE, IMAGE_CREATE_API_URL);\n        urlMap.put(IMAGE_UNDERSANDING, IMAGE_UNDERSANDING_API_URL);\n        urlMap.put(HYPERMIMETIC_SYNTHESIS, HYPERMIMETIC_SYNTHESIS_API_URL);\n    }\n\n    public static String getUrl(String key) {\n        if (!urlMap.containsKey(key)) {\n            log.error(\"No corresponding URL path found for {}\", key);\n            return null;\n        }\n        return urlMap.get(key);\n    }\n\n    @Getter\n    @AllArgsConstructor\n    public enum ApiUrl {\n        general(SPARK_API_HOST_WSS_V1_1_URL),\n        generalV2(SPARK_API_HOST_WSS_V2_1_URL),\n        generalV3(SPARK_API_HOST_WSS_V3_1_URL),\n        fileUpload(FILE_UPLOAD_API_URL),\n        documentChat(DOCUMENT_CHAT_API_URL),\n        documentSummaryStart(DOCUMENT_SUMMARY_START_API_URL),\n        documentSummaryQuery(DOCUMENT_SUMMARY_QUERY_API_URL),\n        embeddingp(EMBEDDING_P_API_URL),\n        embeddingq(EMBEDDING_Q_API_URL),\n        imageCreate(IMAGE_CREATE_API_URL),\n        imageUnderstanding(IMAGE_UNDERSANDING_API_URL),\n        hypermimeticSynthesis(HYPERMIMETIC_SYNTHESIS_API_URL);\n        private String url;\n    }\n\n}\n"
  },
  {
    "path": "ai-spark/src/main/java/com/ai/spark/common/Usage.java",
    "content": "package com.ai.spark.common;\n\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport com.fasterxml.jackson.annotation.JsonInclude;\nimport com.fasterxml.jackson.annotation.JsonProperty;\nimport lombok.AllArgsConstructor;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\n\n@Data\n@NoArgsConstructor\n@AllArgsConstructor\n@JsonIgnoreProperties(ignoreUnknown = true)\n@JsonInclude(JsonInclude.Include.NON_NULL)\npublic class Usage {\n\n    @JsonProperty(\"text\")\n    private UsageText usageText;\n\n}\n"
  },
  {
    "path": "ai-spark/src/main/java/com/ai/spark/common/UsageText.java",
    "content": "package com.ai.spark.common;\n\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport com.fasterxml.jackson.annotation.JsonInclude;\nimport com.fasterxml.jackson.annotation.JsonProperty;\nimport lombok.AllArgsConstructor;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\n\n@Data\n@NoArgsConstructor\n@AllArgsConstructor\n@JsonIgnoreProperties(ignoreUnknown = true)\n@JsonInclude(JsonInclude.Include.NON_NULL)\npublic class UsageText {\n\n    /**\n     * 保留字段，可忽略\n     */\n    @JsonProperty(\"question_tokens\")\n    private Integer questionTokens;\n\n    /**\n     * 包含历史问题的总tokens大小\n     */\n    @JsonProperty(\"prompt_tokens\")\n    private Integer promptTokens;\n\n    /**\n     * 回答的tokens大小\n     */\n    @JsonProperty(\"completion_tokens\")\n    private Integer completionTokens;\n\n    /**\n     * prompt_tokens和completion_tokens的和\n     */\n    @JsonProperty(\"total_tokens\")\n    private Integer totalTokens;\n\n}\n"
  },
  {
    "path": "ai-spark/src/main/java/com/ai/spark/common/utils/AuthUtils.java",
    "content": "package com.ai.spark.common.utils;\n\n\nimport lombok.AllArgsConstructor;\nimport lombok.Getter;\n\nimport javax.crypto.Mac;\nimport javax.crypto.spec.SecretKeySpec;\nimport java.io.UnsupportedEncodingException;\nimport java.net.URI;\nimport java.net.URISyntaxException;\nimport java.net.URLEncoder;\nimport java.nio.charset.StandardCharsets;\nimport java.security.InvalidKeyException;\nimport java.security.MessageDigest;\nimport java.security.NoSuchAlgorithmException;\nimport java.security.SignatureException;\nimport java.time.ZoneId;\nimport java.time.ZonedDateTime;\nimport java.time.format.DateTimeFormatter;\nimport java.util.Base64;\nimport java.util.Locale;\n\n/**\n * 鉴权工具类\n */\npublic class AuthUtils {\n\n    /**\n     * 日期格式化\n     */\n    public final static DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(\"EEE, dd MMM yyyy HH:mm:ss z\", Locale.US);\n    public final static String preStr = \"host: %s\\n\" +\n            \"date: %s\\n\" +\n            \"%s %s HTTP/1.1\";\n    private static final char[] MD5_TABLE = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};\n\n    public static String replaceAllHttp(String authUrl) {\n        return authUrl.replaceAll(\"http://\", \"ws://\").replaceAll(\"https://\", \"wss://\");\n    }\n\n    /**\n     * 鉴权方法，适用于对话接口\n     *\n     * @param requestMethod 请求方式\n     * @param hostUrl       地址\n     * @param apiKey        apikey\n     * @param apiSecret     apiSecret\n     * @return 鉴权信息\n     */\n    public static String getAuthUrl(String requestMethod, String hostUrl, String apiKey, String apiSecret) throws InvalidKeyException, NoSuchAlgorithmException, URISyntaxException, UnsupportedEncodingException {\n        URI uri = new URI(hostUrl);\n        String date = ZonedDateTime.now(ZoneId.of(\"GMT\")).format(dateTimeFormatter);\n        // SHA256加密\n        Mac mac = Mac.getInstance(\"hmacsha256\");\n        mac.init(new SecretKeySpec(apiSecret.getBytes(StandardCharsets.UTF_8), \"hmacsha256\"));\n        byte[] hexDigits = mac.doFinal(String.format(preStr, uri.getHost(), date, requestMethod, uri.getPath()).getBytes(StandardCharsets.UTF_8));\n        String authorization = String.format(\"api_key=\\\"%s\\\", algorithm=\\\"%s\\\", headers=\\\"%s\\\", signature=\\\"%s\\\"\", apiKey, \"hmac-sha256\", \"host date request-line\", Base64.getEncoder().encodeToString(hexDigits));\n        // 拼接地址\n        return new StringBuilder(hostUrl)\n                .append(\"?authorization=\").append(Base64.getEncoder().encodeToString(authorization.getBytes(StandardCharsets.UTF_8)))\n                .append(\"&date=\").append(URLEncoder.encode(date, StandardCharsets.UTF_8.name()))\n                .append(\"&host=\").append(uri.getHost())\n                .toString();\n    }\n\n    /**\n     * 获取签名，适用于文档问答\n     *\n     * @param appId  签名的key\n     * @param secret 签名秘钥\n     * @return 返回签名\n     */\n    public static String getSignature(String appId, String secret, long ts) {\n        try {\n            String auth = md5(appId + ts);\n            return hmacSHA1Encrypt(auth, secret);\n        } catch (SignatureException e) {\n            return null;\n        }\n    }\n\n    /**\n     * sha1加密\n     *\n     * @param encryptText 加密文本\n     * @param encryptKey  加密键\n     * @return 加密\n     */\n    private static String hmacSHA1Encrypt(String encryptText, String encryptKey)\n            throws SignatureException {\n        byte[] rawHmac;\n        try {\n            byte[] data = encryptKey.getBytes(StandardCharsets.UTF_8);\n            SecretKeySpec secretKey = new SecretKeySpec(data, \"HmacSHA1\");\n            Mac mac = Mac.getInstance(\"HmacSHA1\");\n            mac.init(secretKey);\n            byte[] text = encryptText.getBytes(StandardCharsets.UTF_8);\n            rawHmac = mac.doFinal(text);\n        } catch (InvalidKeyException e) {\n            throw new SignatureException(\"InvalidKeyException:\" + e.getMessage());\n        } catch (NoSuchAlgorithmException e) {\n            throw new SignatureException(\n                    \"NoSuchAlgorithmException:\" + e.getMessage()\n            );\n        }\n        return Base64.getEncoder().encodeToString(rawHmac);\n    }\n\n    private static String md5(String cipherText) {\n        try {\n            byte[] data = cipherText.getBytes();\n            // 信息摘要是安全的单向哈希函数，它接收任意大小的数据，并输出固定长度的哈希值。\n            MessageDigest mdInst = MessageDigest.getInstance(\"MD5\");\n\n            // MessageDigest对象通过使用 update方法处理数据， 使用指定的byte数组更新摘要\n            mdInst.update(data);\n\n            // 摘要更新之后，通过调用digest（）执行哈希计算，获得密文\n            byte[] md = mdInst.digest();\n\n            // 把密文转换成十六进制的字符串形式\n            int j = md.length;\n            char[] str = new char[j * 2];\n            int k = 0;\n            for (byte byte0 : md) { // i = 0\n                str[k++] = MD5_TABLE[byte0 >>> 4 & 0xf]; // 5\n                str[k++] = MD5_TABLE[byte0 & 0xf]; // F\n            }\n            // 返回经过加密后的字符串\n            return new String(str);\n        } catch (Exception e) {\n            return null;\n        }\n    }\n\n    @Getter\n    @AllArgsConstructor\n    public enum RequestMethod {\n        GET(\"GET\"),\n        POST(\"POST\");\n        private String method;\n    }\n}\n"
  },
  {
    "path": "ai-spark/src/main/java/com/ai/spark/endPoint/audio/Audio.java",
    "content": "package com.ai.spark.endPoint.audio;\n\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport com.fasterxml.jackson.annotation.JsonInclude;\nimport com.fasterxml.jackson.annotation.JsonProperty;\nimport lombok.AllArgsConstructor;\nimport lombok.Builder;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\n\n@Data\n@Builder\n@NoArgsConstructor\n@AllArgsConstructor\n@JsonIgnoreProperties(ignoreUnknown = true)\n@JsonInclude(JsonInclude.Include.NON_NULL)\npublic class Audio {\n\n    /**\n     * ⾳频编码\n     */\n    private String encoding;\n\n    /**\n     * ⾳频编码\n     */\n    @JsonProperty(\"sample_rate\")\n    private Integer sampleRate;\n\n    /**\n     * 声道数\n     */\n    private Integer channels;\n\n    /**\n     * 位深\n     */\n    @JsonProperty(\"bit_depth\")\n    private Integer bitDepth;\n\n    /**\n     * 帧⼤⼩\n     */\n    @JsonProperty(\"frame_size\")\n    private Integer frameSize;\n\n    /**\n     * 数据状态\n     * 0:开始, 1:开始, 2:结束\n     */\n    private Integer status;\n\n    /**\n     * 数据序号\n     * 最⼩值:0, 最⼤值:9999999\n     */\n    private Integer seq;\n\n    /**\n     * ⾳频数据\n     * 最⼩尺⼨:0B, 最⼤尺⼨:10485760B\n     */\n    private String audio;\n\n}\n"
  },
  {
    "path": "ai-spark/src/main/java/com/ai/spark/endPoint/audio/AudioHeader.java",
    "content": "package com.ai.spark.endPoint.audio;\n\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport com.fasterxml.jackson.annotation.JsonInclude;\nimport com.fasterxml.jackson.annotation.JsonProperty;\nimport lombok.AllArgsConstructor;\nimport lombok.Builder;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\n\n@Data\n@Builder\n@NoArgsConstructor\n@AllArgsConstructor\n@JsonIgnoreProperties(ignoreUnknown = true)\n@JsonInclude(JsonInclude.Include.NON_NULL)\npublic class AudioHeader {\n\n    /**\n     * 在平台申请的appid信息，必传\n     */\n    @JsonProperty(\"app_id\")\n    private String appId;\n\n    /**\n     * 请求⽤户服务返回的uid，⽤户及设备级别个性化功能依赖此参数\n     */\n    private String uid;\n\n    /**\n     * 请求⽅确保唯⼀的设备标志，设备级别个性化功能依赖此参数\n     */\n    private String did;\n\n    /**\n     * 设备imei信息\n     */\n    private String imei;\n\n    /**\n     * 设备imsi信息\n     */\n    private String imsi;\n\n    /**\n     * 设备mac信息\n     */\n    private String mac;\n\n    /**\n     * ⽹络类型，可选值为wifi、2G、3G、4G、5G\n     */\n    @JsonProperty(\"net_type\")\n    private String netType;\n\n    /**\n     * 运营商信息，可选值为CMCC、CUCC、CTCC、other\n     */\n    @JsonProperty(\"net_isp\")\n    private String netIsp;\n\n    /**\n     * 客户端请求的会话唯⼀标识\n     */\n    @JsonProperty(\"request_id\")\n    private String requestId;\n\n    /**\n     * 个性化资源ID\n     */\n    @JsonProperty(\"res_id\")\n    private String resId;\n\n    /**\n     * 请求状态，可选值为：0-开始、1-继续、2-结束\n     */\n    private Integer status;\n\n    // 以下是请求返回时所需参数\n    /**\n     * 错误码，0表示正常，非0表示出错；\n     */\n    private Integer code;\n\n    /**\n     * 会话是否成功的描述信息\n     */\n    private String message;\n\n    /**\n     * 会话的唯一id，用于讯飞技术人员查询服务端会话日志使用,出现调用错误时建议留存该字段\n     */\n    private String sid;\n\n}\n"
  },
  {
    "path": "ai-spark/src/main/java/com/ai/spark/endPoint/audio/AudioParameter.java",
    "content": "package com.ai.spark.endPoint.audio;\n\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport com.fasterxml.jackson.annotation.JsonInclude;\nimport lombok.AllArgsConstructor;\nimport lombok.Builder;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\n\n@Data\n@Builder\n@NoArgsConstructor\n@AllArgsConstructor\n@JsonIgnoreProperties(ignoreUnknown = true)\n@JsonInclude(JsonInclude.Include.NON_NULL)\npublic class AudioParameter {\n\n    private Oral oral;\n\n    private Tts tts;\n\n}\n"
  },
  {
    "path": "ai-spark/src/main/java/com/ai/spark/endPoint/audio/AudioPayload.java",
    "content": "package com.ai.spark.endPoint.audio;\n\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport com.fasterxml.jackson.annotation.JsonInclude;\nimport com.fasterxml.jackson.annotation.JsonProperty;\nimport lombok.AllArgsConstructor;\nimport lombok.Builder;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\n\n@Data\n@Builder\n@NoArgsConstructor\n@AllArgsConstructor\n@JsonIgnoreProperties(ignoreUnknown = true)\n@JsonInclude(JsonInclude.Include.NON_NULL)\npublic class AudioPayload {\n\n    /**\n     * 待合成⽂本\n     */\n    private AudioText text;\n\n    /**\n     * ⽤户原始输⼊，场景化合成开启时必传，不开启为⾮必传\n     */\n    @JsonProperty(\"user_text\")\n    private AudioText userText;\n\n    /**\n     * 响应数据块\n     */\n    private Audio audio;\n\n    /**\n     * 响应数据块\n     */\n    private Pybuf pybuf;\n\n}\n"
  },
  {
    "path": "ai-spark/src/main/java/com/ai/spark/endPoint/audio/AudioText.java",
    "content": "package com.ai.spark.endPoint.audio;\n\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport com.fasterxml.jackson.annotation.JsonInclude;\nimport lombok.AllArgsConstructor;\nimport lombok.Builder;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\n\n@Data\n@Builder\n@NoArgsConstructor\n@AllArgsConstructor\n@JsonIgnoreProperties(ignoreUnknown = true)\n@JsonInclude(JsonInclude.Include.NON_NULL)\npublic class AudioText {\n\n    /**\n     * ⽂本编码\n     */\n    private String encoding;\n\n    /**\n     * ⽂本压缩格式\n     */\n    private String compress;\n\n    /**\n     * ⽂本格式\n     */\n    private String format;\n\n    /**\n     * 数据状态\n     */\n    private Integer status;\n\n    /**\n     * 数据序号\n     */\n    private Integer seq;\n\n    /**\n     * ⽂本数据\n     */\n    private String text;\n\n}\n"
  },
  {
    "path": "ai-spark/src/main/java/com/ai/spark/endPoint/audio/Oral.java",
    "content": "package com.ai.spark.endPoint.audio;\n\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport com.fasterxml.jackson.annotation.JsonInclude;\nimport com.fasterxml.jackson.annotation.JsonProperty;\nimport lombok.AllArgsConstructor;\nimport lombok.Builder;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\n\n@Data\n@Builder\n@NoArgsConstructor\n@AllArgsConstructor\n@JsonIgnoreProperties(ignoreUnknown = true)\n@JsonInclude(JsonInclude.Include.NON_NULL)\npublic class Oral {\n\n    @JsonProperty(\"spark_assist\")\n    private Integer sparkAssist;\n\n    @JsonProperty(\"oral_level\")\n    private String oralLevel;\n\n}\n"
  },
  {
    "path": "ai-spark/src/main/java/com/ai/spark/endPoint/audio/Pybuf.java",
    "content": "package com.ai.spark.endPoint.audio;\n\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport com.fasterxml.jackson.annotation.JsonInclude;\nimport lombok.AllArgsConstructor;\nimport lombok.Builder;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\n\n@Data\n@Builder\n@NoArgsConstructor\n@AllArgsConstructor\n@JsonIgnoreProperties(ignoreUnknown = true)\n@JsonInclude(JsonInclude.Include.NON_NULL)\npublic class Pybuf {\n\n    /**\n     * ⽂本编码\n     */\n    private String encoding;\n\n    /**\n     * ⽂本压缩格式\n     */\n    private String compress;\n\n    /**\n     * ⽂本格式\n     */\n    private String format;\n\n    /**\n     * 数据状态\n     * 0:开始, 1:开始, 2:结束\n     */\n    private Integer status;\n\n    /**\n     * 数据序号\n     * 最⼩值:0, 最⼤值:9999999\n     */\n    private Integer seq;\n\n    /**\n     * ⽂本数据\n     * 最⼩尺⼨:0B, 最⼤尺⼨:1048576B\n     */\n    private String text;\n}\n"
  },
  {
    "path": "ai-spark/src/main/java/com/ai/spark/endPoint/audio/Tts.java",
    "content": "package com.ai.spark.endPoint.audio;\n\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport com.fasterxml.jackson.annotation.JsonInclude;\nimport lombok.*;\n\n@Data\n@Builder\n@NoArgsConstructor\n@AllArgsConstructor\n@JsonIgnoreProperties(ignoreUnknown = true)\n@JsonInclude(JsonInclude.Include.NON_NULL)\npublic class Tts {\n\n    /**\n     * 发⾳⼈，必传\n     */\n    private String vcn;\n\n    /**\n     * 语速：0对应默认语速的1/2，100 对应默认语速的2倍\n     * 最⼩值:0, 最⼤值:100\n     */\n    private Integer speed;\n\n    /**\n     * ⾳量：0是 静⾳，1对 应默认⾳量 1/2，100对应默认⾳量的2倍\n     * 最⼩值:0, 最⼤值:100\n     */\n    private Integer volume;\n\n    /**\n     * 语调：0对应默认语速的1/2，100对应默认语速的2倍\n     * 最⼩值:0, 最⼤值:100\n     */\n    private Integer pitch;\n\n    /**\n     * 背景⾳\n     * 0:⽆背景⾳, 1:内置背景⾳1, 2:内置背景⾳2\n     */\n    private Integer bgs;\n\n    /**\n     * 英⽂发⾳⽅式\n     * 0:⾃动判断处理，如果不确定将按照英⽂词语拼写处理（缺省）,\n     * 1:所有英⽂按字⺟发⾳,\n     * 2:⾃动判断处理，如果不确定将按照字⺟朗读\n     */\n    private Integer reg;\n\n    /**\n     * 合成⾳频数字发⾳⽅式\n     * 0:⾃动判断, 1:完全数值, 2:完全字符串, 3:字符串优先\n     */\n    private Integer rdn;\n\n    /**\n     * 是否返回拼⾳标注\n     * 0:不返回拼⾳, 1:返回拼⾳（纯⽂本格式，utf8编码）\n     */\n    private Integer rhy;\n\n    /**\n     * 场景\n     * 0:⽆, 1:散⽂阅读, 2:⼩说阅读, 3:新闻, 4:⼴告, 5:交互\n     */\n    private Integer scn;\n\n    /**\n     * 引擎初始化，是否返回版本信息+时间戳信息\n     * 0:不返回, 1:返回版本信息+时间戳信息。如XXX.18928127 XXX表示版本号，后接秒为单位的时间戳\n     */\n    private Integer version;\n\n    /**\n     * 控制L5静⾳时⻓，取值范围为 0~10000ms\n     * 最⼩值:0, 最⼤值:10000\n     */\n    private Integer L5SilLen;\n\n    /**\n     * 段落静⾳时⻓，取值范围为0~10000ms\n     * 最⼩值:0, 最⼤值:10000\n     */\n    private Integer ParagraphSilLen;\n\n    private Audio audio;\n\n    private Pybuf pybuf;\n\n    @Getter\n    @AllArgsConstructor\n    public enum Vcn {\n        lxx(\"x4_lingxiaoxuan_oral\"),\n        lfz(\"x4_lingfeizhe_oral\"),\n        lyz(\"x4_lingyuzhao_oral\");\n        private String name;\n    }\n\n}\n"
  },
  {
    "path": "ai-spark/src/main/java/com/ai/spark/endPoint/audio/req/AudioRequest.java",
    "content": "package com.ai.spark.endPoint.audio.req;\n\nimport com.ai.spark.endPoint.audio.AudioHeader;\nimport com.ai.spark.endPoint.audio.AudioParameter;\nimport com.ai.spark.endPoint.audio.AudioPayload;\nimport com.ai.spark.endPoint.audio.Tts;\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport com.fasterxml.jackson.annotation.JsonInclude;\nimport lombok.AllArgsConstructor;\nimport lombok.Builder;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\n\n@Data\n@Builder\n@NoArgsConstructor\n@AllArgsConstructor\n@JsonIgnoreProperties(ignoreUnknown = true)\n@JsonInclude(JsonInclude.Include.NON_NULL)\npublic class AudioRequest {\n\n    /**\n     * 协议头部，⽤于描述平台特性的参数\n     */\n    private AudioHeader header;\n\n    /**\n     * AI 能⼒功能参数，⽤于控制 AI 引擎特性的开关。\n     */\n    private AudioParameter parameter;\n\n    private AudioPayload payload;\n\n    public static AudioRequest baseBuild(Tts.Vcn vcn, String appId) {\n        AudioRequest request = AudioRequest.builder()\n                .header(AudioHeader.builder().appId(appId).status(0).build())\n                .parameter(AudioParameter.builder().tts(Tts.builder().vcn(vcn.getName()).build()).build())\n                .build();\n        return request;\n    }\n\n}\n"
  },
  {
    "path": "ai-spark/src/main/java/com/ai/spark/endPoint/audio/resp/AudioResponse.java",
    "content": "package com.ai.spark.endPoint.audio.resp;\n\nimport com.ai.spark.endPoint.audio.AudioHeader;\nimport com.ai.spark.endPoint.audio.AudioPayload;\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport com.fasterxml.jackson.annotation.JsonInclude;\nimport lombok.AllArgsConstructor;\nimport lombok.Builder;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\n\n@Data\n@Builder\n@NoArgsConstructor\n@AllArgsConstructor\n@JsonIgnoreProperties(ignoreUnknown = true)\n@JsonInclude(JsonInclude.Include.NON_NULL)\npublic class AudioResponse {\n\n    private AudioHeader header;\n\n    private AudioPayload payload;\n\n}\n"
  },
  {
    "path": "ai-spark/src/main/java/com/ai/spark/endPoint/chat/Chat.java",
    "content": "package com.ai.spark.endPoint.chat;\n\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport com.fasterxml.jackson.annotation.JsonInclude;\nimport com.fasterxml.jackson.annotation.JsonProperty;\nimport lombok.*;\n\n@Data\n@Builder\n@NoArgsConstructor\n@AllArgsConstructor\n@JsonIgnoreProperties(ignoreUnknown = true)\n@JsonInclude(JsonInclude.Include.NON_NULL)\npublic class Chat {\n\n    /**\n     * 必传\n     * 指定访问的领域,general指向V1.5版本,generalv2指向V2版本,generalv3指向V3版本 。注意：不同的取值对应的url也不一样！\n     * 取值为[general,generalv2,generalv3]\n     */\n    private String domain;\n\n    /**\n     * 非必传\n     * 核采样阈值。用于决定结果随机性，取值越高随机性越强即相同的问题得到的不同答案的可能性越高\n     * 取值范围 (0，1] ，默认值0.5\n     */\n    private Double temperature;\n\n    /**\n     * 非必传\n     * 模型回答的tokens的最大长度\n     * V1.5取值为[1,4096]\n     * V2.0取值为[1,8192]，默认为2048。\n     * V3.0取值为[1,8192]，默认为2048。\n     */\n    @JsonProperty(\"max_tokens\")\n    private Integer maxTokens;\n\n    /**\n     * 非必传\n     * 从k个候选中随机选择⼀个（⾮等概率）\n     * 取值为[1，6],默认为4\n     */\n    @JsonProperty(\"top_k\")\n    private Integer topK;\n\n    /**\n     * 非必传\n     * 用于关联用户会话，需要保障用户下的唯一性\n     */\n    @JsonProperty(\"chat_id\")\n    private String chatId;\n\n    @Getter\n    @AllArgsConstructor\n    public enum General {\n        general(\"general\"),\n        generalV2(\"generalv2\"),\n        generalV3(\"generalv3\");\n        private String msg;\n    }\n\n}\n"
  },
  {
    "path": "ai-spark/src/main/java/com/ai/spark/endPoint/chat/ChatHeader.java",
    "content": "package com.ai.spark.endPoint.chat;\n\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport com.fasterxml.jackson.annotation.JsonInclude;\nimport com.fasterxml.jackson.annotation.JsonProperty;\nimport lombok.*;\n\n@Data\n@Builder\n@NoArgsConstructor\n@AllArgsConstructor\n@JsonIgnoreProperties(ignoreUnknown = true)\n@JsonInclude(JsonInclude.Include.NON_NULL)\npublic class ChatHeader {\n\n    /**\n     * 必传\n     * 应用appid，从开放平台控制台创建的应用中获取\n     */\n    @JsonProperty(\"app_id\")\n    private String appId;\n\n    /**\n     * 非必传\n     * 每个用户的id，用于区分不同用户\n     */\n    private String uid;\n\n    // 以下是请求返回时所需参数\n    /**\n     * 错误码，0表示正常，非0表示出错；\n     */\n    private Integer code;\n\n    /**\n     * 会话是否成功的描述信息\n     */\n    private String message;\n\n    /**\n     * 会话的唯一id，用于讯飞技术人员查询服务端会话日志使用,出现调用错误时建议留存该字段\n     */\n    private String sid;\n\n    /**\n     * 会话状态，取值为[0,1,2]；0代表首次结果；1代表中间结果；2代表最后一个结果\n     */\n    private Integer status;\n\n    @Getter\n    @AllArgsConstructor\n    public enum Code {\n        SUCCESS(0),\n        ;\n\n        private final int value;\n    }\n\n}\n"
  },
  {
    "path": "ai-spark/src/main/java/com/ai/spark/endPoint/chat/ChatParameter.java",
    "content": "package com.ai.spark.endPoint.chat;\n\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport com.fasterxml.jackson.annotation.JsonInclude;\nimport lombok.AllArgsConstructor;\nimport lombok.Builder;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\n\n@Data\n@Builder\n@NoArgsConstructor\n@AllArgsConstructor\n@JsonIgnoreProperties(ignoreUnknown = true)\n@JsonInclude(JsonInclude.Include.NON_NULL)\npublic class ChatParameter {\n\n    private Chat chat;\n\n}\n"
  },
  {
    "path": "ai-spark/src/main/java/com/ai/spark/endPoint/chat/ChatPayload.java",
    "content": "package com.ai.spark.endPoint.chat;\n\nimport com.ai.spark.common.Usage;\nimport com.ai.spark.endPoint.chat.function.Function;\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport com.fasterxml.jackson.annotation.JsonInclude;\nimport com.fasterxml.jackson.annotation.JsonProperty;\nimport lombok.AllArgsConstructor;\nimport lombok.Builder;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\n\n@Data\n@Builder\n@NoArgsConstructor\n@AllArgsConstructor\n@JsonIgnoreProperties(ignoreUnknown = true)\n@JsonInclude(JsonInclude.Include.NON_NULL)\npublic class ChatPayload {\n\n    private Message message;\n\n    @JsonProperty(\"functions\")\n    private Function function;\n\n    // 以下是请求返回时所需参数\n    @JsonProperty(\"choices\")\n    private Choice choice;\n\n    private Usage usage;\n\n}\n"
  },
  {
    "path": "ai-spark/src/main/java/com/ai/spark/endPoint/chat/ChatText.java",
    "content": "package com.ai.spark.endPoint.chat;\n\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport com.fasterxml.jackson.annotation.JsonInclude;\nimport com.fasterxml.jackson.annotation.JsonProperty;\nimport lombok.*;\n\n@Data\n@Builder\n@NoArgsConstructor\n@AllArgsConstructor\n@JsonIgnoreProperties(ignoreUnknown = true)\n@JsonInclude(JsonInclude.Include.NON_NULL)\npublic class ChatText {\n\n    /**\n     * user表示是用户的问题，assistant表示AI的回复\n     * 取值为[user,assistant]\n     */\n    private String role;\n\n    /**\n     * 用户和AI的对话内容\n     * 所有content的累计tokens需控制8192以内\n     */\n    private String content;\n\n    /**\n     * 结果序号，取值为[0,10];\n     */\n    private Integer index;\n\n    /**\n     * 数据的类型\n     */\n    @JsonProperty(\"content_type\")\n    private String contentType;\n\n\n    public static ChatText baseBuild(Role role, String content) {\n        return ChatText.builder().role(role.getRoleName()).content(content).build();\n    }\n\n    @Getter\n    @AllArgsConstructor\n    public enum Role {\n\n        USER(\"user\"),\n        ASSISTANT(\"assistant\"),\n        ;\n\n        private String RoleName;\n    }\n\n    @Getter\n    @AllArgsConstructor\n    public enum ContentType {\n\n        TEXT(\"text\"),\n        IMAGE(\"image\"),\n        ;\n\n        private String type;\n    }\n\n}\n"
  },
  {
    "path": "ai-spark/src/main/java/com/ai/spark/endPoint/chat/Choice.java",
    "content": "package com.ai.spark.endPoint.chat;\n\n\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport com.fasterxml.jackson.annotation.JsonInclude;\nimport com.fasterxml.jackson.annotation.JsonProperty;\nimport lombok.*;\n\nimport java.util.List;\n\n@Data\n@Builder\n@NoArgsConstructor\n@AllArgsConstructor\n@JsonIgnoreProperties(ignoreUnknown = true)\n@JsonInclude(JsonInclude.Include.NON_NULL)\npublic class Choice {\n\n    /**\n     * 文本响应状态，取值为[0,1,2]; 0代表首个文本结果；1代表中间文本结果；2代表最后一个文本结果\n     */\n    private Integer status;\n\n    /**\n     * 返回的数据序号，取值为[0,9999999]\n     */\n    private Integer seq;\n\n    @JsonProperty(\"text\")\n    private List<ChatText> texts;\n\n    @Getter\n    public enum Status {\n        START(0),\n        ING(1),\n        END(2),\n        ;\n\n        private final int value;\n\n        Status(int value) {\n            this.value = value;\n        }\n    }\n\n}\n"
  },
  {
    "path": "ai-spark/src/main/java/com/ai/spark/endPoint/chat/Message.java",
    "content": "package com.ai.spark.endPoint.chat;\n\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport com.fasterxml.jackson.annotation.JsonInclude;\nimport com.fasterxml.jackson.annotation.JsonProperty;\nimport lombok.AllArgsConstructor;\nimport lombok.Builder;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\n\nimport java.util.List;\n\n@Data\n@Builder\n@NoArgsConstructor\n@AllArgsConstructor\n@JsonIgnoreProperties(ignoreUnknown = true)\n@JsonInclude(JsonInclude.Include.NON_NULL)\npublic class Message {\n\n    @JsonProperty(\"text\")\n    private List<ChatText> chatTexts;\n\n}\n"
  },
  {
    "path": "ai-spark/src/main/java/com/ai/spark/endPoint/chat/document/ChatExtends.java",
    "content": "package com.ai.spark.endPoint.chat.document;\n\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport com.fasterxml.jackson.annotation.JsonInclude;\nimport lombok.AllArgsConstructor;\nimport lombok.Builder;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\n\n@Data\n@Builder\n@NoArgsConstructor\n@AllArgsConstructor\n@JsonIgnoreProperties(ignoreUnknown = true)\n@JsonInclude(JsonInclude.Include.NON_NULL)\npublic class ChatExtends {\n\n    /**\n     * wiki 大模型问答模板，在某些场景服务默认的 prompt 回答效果不好时，业务可以考虑通过自定义 prompt 来改善。<wikiquestion>替换的问题标识，<wikicontent>替换的文本内容标识\n     */\n    private String wikiPromptTpl;\n\n    /**\n     * wiki 结果分数阈值，低于这个阈值的结果丢弃。取值范围为(0,1] 参考值为：0.80非常宽松 0.82宽松 0.83标准0.84严格 0.86非常严格。服务会根据问题检索文件列表中内容相关的文段，该值设置的越高，可能丢弃的内容越多，但保留下来的内容越准确；但过高也可能导致无匹配内容\n     */\n    private Float wikiFilterScore;\n\n    /**\n     * 用户问题未匹配到文档内容时，是否使用大模型兜底回答问题\n     */\n    private Boolean sparkWhenWithoutEmbedding;\n\n    /**\n     * 大模型问答时的温度，取值范围 (0，1] ，temperature 越大，大模型回答随机度越高\n     */\n    private Float temperature;\n\n}\n"
  },
  {
    "path": "ai-spark/src/main/java/com/ai/spark/endPoint/chat/function/Function.java",
    "content": "package com.ai.spark.endPoint.chat.function;\n\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport com.fasterxml.jackson.annotation.JsonInclude;\nimport com.fasterxml.jackson.annotation.JsonProperty;\nimport lombok.AllArgsConstructor;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\n\nimport java.util.List;\n\n@Data\n@NoArgsConstructor\n@AllArgsConstructor\n@JsonIgnoreProperties(ignoreUnknown = true)\n@JsonInclude(JsonInclude.Include.NON_NULL)\npublic class Function {\n\n    @JsonProperty(\"functions\")\n    private List<FunctionText> functionTexts;\n\n}\n"
  },
  {
    "path": "ai-spark/src/main/java/com/ai/spark/endPoint/chat/function/FunctionParameter.java",
    "content": "package com.ai.spark.endPoint.chat.function;\n\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport com.fasterxml.jackson.annotation.JsonInclude;\nimport lombok.AllArgsConstructor;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\n\nimport java.util.List;\n\n@Data\n@NoArgsConstructor\n@AllArgsConstructor\n@JsonIgnoreProperties(ignoreUnknown = true)\n@JsonInclude(JsonInclude.Include.NON_NULL)\npublic class FunctionParameter {\n\n    /**\n     * 参数类型\n     */\n    private String type;\n\n    /**\n     * 该内容由用户定义，命中该方法时需要返回哪些参数\n     */\n    private Object properties;\n\n    /**\n     * 该内容由用户定义，命中方法时必须返回的字段\n     */\n    private List<String> required;\n\n}\n"
  },
  {
    "path": "ai-spark/src/main/java/com/ai/spark/endPoint/chat/function/FunctionText.java",
    "content": "package com.ai.spark.endPoint.chat.function;\n\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport com.fasterxml.jackson.annotation.JsonInclude;\nimport com.fasterxml.jackson.annotation.JsonProperty;\nimport lombok.AllArgsConstructor;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\n\n@Data\n@NoArgsConstructor\n@AllArgsConstructor\n@JsonIgnoreProperties(ignoreUnknown = true)\n@JsonInclude(JsonInclude.Include.NON_NULL)\npublic class FunctionText {\n\n    /**\n     * 用户输入命中后，会返回该名称\n     */\n    private String name;\n\n    /**\n     * 描述function功能即可，越详细越有助于大模型理解该function\n     */\n    private String description;\n\n    @JsonProperty(\"parameters\")\n    private FunctionParameter functionParameter;\n\n}\n"
  },
  {
    "path": "ai-spark/src/main/java/com/ai/spark/endPoint/chat/req/ChatRequest.java",
    "content": "package com.ai.spark.endPoint.chat.req;\n\nimport com.ai.spark.endPoint.chat.*;\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport com.fasterxml.jackson.annotation.JsonInclude;\nimport com.fasterxml.jackson.annotation.JsonProperty;\nimport lombok.AllArgsConstructor;\nimport lombok.Builder;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\n\n@Data\n@Builder\n@NoArgsConstructor\n@AllArgsConstructor\n@JsonIgnoreProperties(ignoreUnknown = true)\n@JsonInclude(JsonInclude.Include.NON_NULL)\npublic class ChatRequest {\n\n    @JsonProperty(\"header\")\n    private ChatHeader chatHeader;\n    @JsonProperty(\"parameter\")\n    private ChatParameter chatParameter;\n    @JsonProperty(\"payload\")\n    private ChatPayload chatPayload;\n\n    public static ChatRequest baseBuild(String question, String appId) {\n        ChatHeader chatHeader = ChatHeader.builder().appId(appId).build();\n        Chat chat = Chat.builder().domain(Chat.General.generalV3.getMsg()).build();\n        ChatParameter chatParameter = ChatParameter.builder().chat(chat).build();\n        ChatText chatText = ChatText.builder().role(ChatText.Role.USER.getRoleName()).content(question).build();\n        Message message = Message.builder().chatTexts(new ArrayList<>(Arrays.asList(chatText))).build();\n        ChatPayload chatPayload = ChatPayload.builder().message(message).build();\n        return ChatRequest.builder().chatHeader(chatHeader).chatParameter(chatParameter).chatPayload(chatPayload).build();\n    }\n\n}\n"
  },
  {
    "path": "ai-spark/src/main/java/com/ai/spark/endPoint/chat/req/DocumentChatRequest.java",
    "content": "package com.ai.spark.endPoint.chat.req;\n\nimport com.ai.spark.endPoint.chat.ChatText;\nimport com.ai.spark.endPoint.chat.document.ChatExtends;\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport com.fasterxml.jackson.annotation.JsonInclude;\nimport com.fasterxml.jackson.annotation.JsonProperty;\nimport lombok.AllArgsConstructor;\nimport lombok.Builder;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\n\n@Data\n@Builder\n@NoArgsConstructor\n@AllArgsConstructor\n@JsonIgnoreProperties(ignoreUnknown = true)\n@JsonInclude(JsonInclude.Include.NON_NULL)\npublic class DocumentChatRequest {\n\n    private ChatExtends chatExtends;\n\n    /**\n     * 必传\n     * 提问问题检索的文件 id 列表\n     */\n    private List<String> fileIds;\n\n    /**\n     * 问答内容列表，按时间正序，最后一条为最新提问\n     */\n    @JsonProperty(\"messages\")\n    private List<ChatText> chatTexts;\n\n    public static DocumentChatRequest baseBuild(String question, List<String> fileIds) {\n        return DocumentChatRequest.builder()\n                .fileIds(fileIds)\n                .chatTexts(new ArrayList<>(Arrays.asList(ChatText.baseBuild(ChatText.Role.USER, question))))\n                .build();\n    }\n\n}\n"
  },
  {
    "path": "ai-spark/src/main/java/com/ai/spark/endPoint/chat/resp/ChatResponse.java",
    "content": "package com.ai.spark.endPoint.chat.resp;\n\nimport com.ai.spark.endPoint.chat.ChatHeader;\nimport com.ai.spark.endPoint.chat.ChatPayload;\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport com.fasterxml.jackson.annotation.JsonInclude;\nimport com.fasterxml.jackson.annotation.JsonProperty;\nimport lombok.AllArgsConstructor;\nimport lombok.Builder;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\n\n@Data\n@Builder\n@NoArgsConstructor\n@AllArgsConstructor\n@JsonIgnoreProperties(ignoreUnknown = true)\n@JsonInclude(JsonInclude.Include.NON_NULL)\npublic class ChatResponse {\n\n    @JsonProperty(\"header\")\n    private ChatHeader chatHeader;\n    @JsonProperty(\"payload\")\n    private ChatPayload chatPayload;\n}\n"
  },
  {
    "path": "ai-spark/src/main/java/com/ai/spark/endPoint/chat/resp/DocumentChatResponse.java",
    "content": "package com.ai.spark.endPoint.chat.resp;\n\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport com.fasterxml.jackson.annotation.JsonInclude;\nimport lombok.*;\n\n@Data\n@Builder\n@NoArgsConstructor\n@AllArgsConstructor\n@JsonIgnoreProperties(ignoreUnknown = true)\n@JsonInclude(JsonInclude.Include.NON_NULL)\npublic class DocumentChatResponse {\n\n    /**\n     * 错误码 ，0 标识成功\n     */\n    private Integer code;\n\n    /**\n     * 错误描述\n     */\n    private String content;\n\n    /**\n     * 文档引用，status=99 的时候返回；结构是个 Map，key=文件 id，value=引用的文段列表（对应 fileTrunks 的 index）\n     */\n    private String fileRefer;\n\n    /**\n     * 会话唯一标识\n     */\n    private String sid;\n\n    /**\n     * 会话状态，取值为[0,1,2,99]；0 代表首次结果；1 代表中间结果；2 代表最后一个结果；99 代表引用的文档及文段\n     */\n    private Integer status;\n\n    @Getter\n    @AllArgsConstructor\n    public enum Code {\n        SUCCESS(0),\n        ;\n\n        private final int value;\n    }\n\n    @Getter\n    public enum Status {\n        START(0),\n        ING(1),\n        END(2),\n        DOCUMENT(99),\n        ;\n\n        private final int value;\n\n        Status(int value) {\n            this.value = value;\n        }\n    }\n\n}\n"
  },
  {
    "path": "ai-spark/src/main/java/com/ai/spark/endPoint/document/Data.java",
    "content": "package com.ai.spark.endPoint.document;\n\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport com.fasterxml.jackson.annotation.JsonInclude;\nimport lombok.AllArgsConstructor;\nimport lombok.Builder;\nimport lombok.NoArgsConstructor;\n\n@lombok.Data\n@Builder\n@NoArgsConstructor\n@AllArgsConstructor\n@JsonIgnoreProperties(ignoreUnknown = true)\n@JsonInclude(JsonInclude.Include.NON_NULL)\npublic class Data {\n    /**\n     * 返回上传的 fileId\n     */\n    private String fileId;\n}\n"
  },
  {
    "path": "ai-spark/src/main/java/com/ai/spark/endPoint/document/req/FileUploadRequest.java",
    "content": "package com.ai.spark.endPoint.document.req;\n\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport com.fasterxml.jackson.annotation.JsonInclude;\nimport lombok.*;\nimport lombok.experimental.FieldNameConstants;\n\nimport java.io.File;\n\n@Data\n@Builder\n@NoArgsConstructor\n@AllArgsConstructor\n@FieldNameConstants\n@JsonIgnoreProperties(ignoreUnknown = true)\n@JsonInclude(JsonInclude.Include.NON_NULL)\npublic class FileUploadRequest {\n\n    /**\n     * 要上传的文件\n     */\n    private File file;\n    /**\n     * 文件 url （文件和文件 url 必须有一个）\n     */\n    private String url;\n    /**\n     * 文件名称，带后缀。文件用 url 的方式，该字段必传；传 file 的话，该字段可不传\n     */\n    private String fileName;\n    /**\n     * 文件类型，目前传固定值\"wiki\"\n     */\n    @Builder.Default\n    private String fileType = FileType.wiki.getType();\n    /**\n     * 文件状态回调地址，文件状态有变动时服务会调用该 url。调用的时候会带上鉴权头，鉴权方式同【接口鉴权】，业务可根据需要是否做鉴权校验\n     */\n    private String callbackUrl;\n\n    @Getter\n    @AllArgsConstructor\n    public enum FileType {\n        wiki(\"wiki\");\n        private String type;\n    }\n\n}\n"
  },
  {
    "path": "ai-spark/src/main/java/com/ai/spark/endPoint/document/resp/DocumentSummaryResponse.java",
    "content": "package com.ai.spark.endPoint.document.resp;\n\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport com.fasterxml.jackson.annotation.JsonInclude;\nimport lombok.AllArgsConstructor;\nimport lombok.Builder;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\n\n@Data\n@Builder\n@NoArgsConstructor\n@AllArgsConstructor\n@JsonIgnoreProperties(ignoreUnknown = true)\n@JsonInclude(JsonInclude.Include.NON_NULL)\npublic class DocumentSummaryResponse {\n\n    private Boolean flag;\n    private Integer code;\n    private String sid;\n    private String desc;\n    private Object data;\n\n}\n"
  },
  {
    "path": "ai-spark/src/main/java/com/ai/spark/endPoint/document/resp/FileUploadResponse.java",
    "content": "package com.ai.spark.endPoint.document.resp;\n\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport com.fasterxml.jackson.annotation.JsonInclude;\nimport lombok.AllArgsConstructor;\nimport lombok.Builder;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\n\n@Data\n@Builder\n@NoArgsConstructor\n@AllArgsConstructor\n@JsonIgnoreProperties(ignoreUnknown = true)\n@JsonInclude(JsonInclude.Include.NON_NULL)\npublic class FileUploadResponse {\n    /**\n     * 返回上传的 fileId\n     */\n    private Integer code;\n    /**\n     * 请求唯一 id，用于问题定位\n     */\n    private String sid;\n    /**\n     * 结果描述\n     */\n    private String desc;\n    /**\n     * 返回结果\n     */\n    private com.ai.spark.endPoint.document.Data data;\n}\n"
  },
  {
    "path": "ai-spark/src/main/java/com/ai/spark/endPoint/embedding/Emb.java",
    "content": "package com.ai.spark.endPoint.embedding;\n\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport com.fasterxml.jackson.annotation.JsonInclude;\nimport lombok.AllArgsConstructor;\nimport lombok.Builder;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\nimport lombok.experimental.FieldNameConstants;\n\n@Data\n@Builder\n@NoArgsConstructor\n@AllArgsConstructor\n@FieldNameConstants\n@JsonIgnoreProperties(ignoreUnknown = true)\n@JsonInclude(JsonInclude.Include.NON_NULL)\npublic class Emb {\n    private Feature feature;\n}\n"
  },
  {
    "path": "ai-spark/src/main/java/com/ai/spark/endPoint/embedding/EmbeddingHeader.java",
    "content": "package com.ai.spark.endPoint.embedding;\n\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport com.fasterxml.jackson.annotation.JsonInclude;\nimport com.fasterxml.jackson.annotation.JsonProperty;\nimport lombok.AllArgsConstructor;\nimport lombok.Builder;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\nimport lombok.experimental.FieldNameConstants;\n\n@Data\n@Builder\n@NoArgsConstructor\n@AllArgsConstructor\n@FieldNameConstants\n@JsonIgnoreProperties(ignoreUnknown = true)\n@JsonInclude(JsonInclude.Include.NON_NULL)\npublic class EmbeddingHeader {\n\n    /**\n     * 必传\n     * 在平台申请的app id信息\n     */\n    @JsonProperty(\"app_id\")\n    private String appId;\n\n    /**\n     * 非必传\n     * 每个用户的id，用于区分不同用户\n     */\n    private String uid;\n\n    /**\n     * 发送状态标识，3为一次性发完\n     */\n    @Builder.Default\n    private Integer status = 3;\n\n    // 以下是请求返回时所需参数\n    /**\n     * 错误码，0表示正常，非0表示出错；\n     */\n    private Integer code;\n\n    /**\n     * 会话是否成功的描述信息\n     */\n    private String message;\n\n    /**\n     * 会话的唯一id，用于讯飞技术人员查询服务端会话日志使用,出现调用错误时建议留存该字段\n     */\n    private String sid;\n\n\n}\n"
  },
  {
    "path": "ai-spark/src/main/java/com/ai/spark/endPoint/embedding/EmbeddingMessage.java",
    "content": "package com.ai.spark.endPoint.embedding;\n\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport com.fasterxml.jackson.annotation.JsonInclude;\nimport lombok.AllArgsConstructor;\nimport lombok.Builder;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\nimport lombok.experimental.FieldNameConstants;\n\n@Data\n@Builder\n@NoArgsConstructor\n@AllArgsConstructor\n@FieldNameConstants\n@JsonIgnoreProperties(ignoreUnknown = true)\n@JsonInclude(JsonInclude.Include.NON_NULL)\npublic class EmbeddingMessage {\n    private String text;\n}\n"
  },
  {
    "path": "ai-spark/src/main/java/com/ai/spark/endPoint/embedding/EmbeddingParameter.java",
    "content": "package com.ai.spark.endPoint.embedding;\n\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport com.fasterxml.jackson.annotation.JsonInclude;\nimport lombok.AllArgsConstructor;\nimport lombok.Builder;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\nimport lombok.experimental.FieldNameConstants;\n\n@Data\n@Builder\n@NoArgsConstructor\n@AllArgsConstructor\n@FieldNameConstants\n@JsonIgnoreProperties(ignoreUnknown = true)\n@JsonInclude(JsonInclude.Include.NON_NULL)\npublic class EmbeddingParameter {\n    @Builder.Default\n    private Emb emb = Emb.builder().feature(Feature.builder().build()).build();\n}\n"
  },
  {
    "path": "ai-spark/src/main/java/com/ai/spark/endPoint/embedding/EmbeddingPayload.java",
    "content": "package com.ai.spark.endPoint.embedding;\n\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport com.fasterxml.jackson.annotation.JsonInclude;\nimport com.fasterxml.jackson.annotation.JsonProperty;\nimport lombok.AllArgsConstructor;\nimport lombok.Builder;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\nimport lombok.experimental.FieldNameConstants;\n\n@Data\n@Builder\n@NoArgsConstructor\n@AllArgsConstructor\n@FieldNameConstants\n@JsonIgnoreProperties(ignoreUnknown = true)\n@JsonInclude(JsonInclude.Include.NON_NULL)\npublic class EmbeddingPayload {\n    @JsonProperty(\"messages\")\n    private EmbeddingMessage embeddingMessage;\n\n    private Feature feature;\n}\n"
  },
  {
    "path": "ai-spark/src/main/java/com/ai/spark/endPoint/embedding/Feature.java",
    "content": "package com.ai.spark.endPoint.embedding;\n\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport com.fasterxml.jackson.annotation.JsonInclude;\nimport lombok.AllArgsConstructor;\nimport lombok.Builder;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\nimport lombok.experimental.FieldNameConstants;\n\n@Data\n@Builder\n@NoArgsConstructor\n@AllArgsConstructor\n@FieldNameConstants\n@JsonIgnoreProperties(ignoreUnknown = true)\n@JsonInclude(JsonInclude.Include.NON_NULL)\npublic class Feature {\n    @Builder.Default\n    private String encoding = \"utf8\";\n    private String seq;\n    private String status;\n    private String text;\n}\n"
  },
  {
    "path": "ai-spark/src/main/java/com/ai/spark/endPoint/embedding/req/EmbeddingRequest.java",
    "content": "package com.ai.spark.endPoint.embedding.req;\n\nimport com.ai.common.utils.JsonUtils;\nimport com.ai.spark.endPoint.chat.ChatText;\nimport com.ai.spark.endPoint.embedding.EmbeddingHeader;\nimport com.ai.spark.endPoint.embedding.EmbeddingMessage;\nimport com.ai.spark.endPoint.embedding.EmbeddingParameter;\nimport com.ai.spark.endPoint.embedding.EmbeddingPayload;\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport com.fasterxml.jackson.annotation.JsonInclude;\nimport com.fasterxml.jackson.annotation.JsonProperty;\nimport lombok.AllArgsConstructor;\nimport lombok.Builder;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\nimport lombok.experimental.FieldNameConstants;\n\nimport java.nio.charset.StandardCharsets;\nimport java.util.Base64;\n\n@Data\n@Builder\n@NoArgsConstructor\n@AllArgsConstructor\n@FieldNameConstants\n@JsonIgnoreProperties(ignoreUnknown = true)\n@JsonInclude(JsonInclude.Include.NON_NULL)\npublic class EmbeddingRequest {\n\n    @JsonProperty(\"header\")\n    private EmbeddingHeader embeddingHeader;\n\n    @JsonProperty(\"parameter\")\n    private EmbeddingParameter embeddingParameter;\n\n    @JsonProperty(\"payload\")\n    private EmbeddingPayload embeddingPayload;\n\n\n    public static EmbeddingRequest baseBuild(ChatText text, String appId) {\n        return EmbeddingRequest.builder()\n                .embeddingHeader(EmbeddingHeader.builder().appId(appId).build())\n                .embeddingParameter(EmbeddingParameter.builder().build())\n                .embeddingPayload(EmbeddingPayload.builder().embeddingMessage(EmbeddingMessage\n                        .builder()\n                        .text(Base64.getEncoder().encodeToString(JsonUtils.toJson(text).getBytes(StandardCharsets.UTF_8)))\n                        .build()).build()\n                )\n                .build();\n    }\n}\n"
  },
  {
    "path": "ai-spark/src/main/java/com/ai/spark/endPoint/embedding/resp/EmbeddingResponse.java",
    "content": "package com.ai.spark.endPoint.embedding.resp;\n\nimport com.ai.spark.endPoint.embedding.EmbeddingHeader;\nimport com.ai.spark.endPoint.embedding.EmbeddingPayload;\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport com.fasterxml.jackson.annotation.JsonInclude;\nimport com.fasterxml.jackson.annotation.JsonProperty;\nimport lombok.AllArgsConstructor;\nimport lombok.Builder;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\nimport lombok.experimental.FieldNameConstants;\n\n@Data\n@Builder\n@NoArgsConstructor\n@AllArgsConstructor\n@FieldNameConstants\n@JsonIgnoreProperties(ignoreUnknown = true)\n@JsonInclude(JsonInclude.Include.NON_NULL)\npublic class EmbeddingResponse {\n\n    @JsonProperty(\"header\")\n    private EmbeddingHeader embeddingHeader;\n\n    @JsonProperty(\"payload\")\n    private EmbeddingPayload embeddingPayload;\n}\n"
  },
  {
    "path": "ai-spark/src/main/java/com/ai/spark/endPoint/images/ImageChat.java",
    "content": "package com.ai.spark.endPoint.images;\n\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport com.fasterxml.jackson.annotation.JsonInclude;\nimport lombok.AllArgsConstructor;\nimport lombok.Builder;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\nimport lombok.experimental.FieldNameConstants;\n\n@Data\n@Builder\n@NoArgsConstructor\n@AllArgsConstructor\n@FieldNameConstants\n@JsonIgnoreProperties(ignoreUnknown = true)\n@JsonInclude(JsonInclude.Include.NON_NULL)\npublic class ImageChat {\n\n    @Builder.Default\n    private String domain = \"general\";\n\n    @Builder.Default\n    private Integer width = 512;\n\n    @Builder.Default\n    private Integer height = 512;\n\n}\n"
  },
  {
    "path": "ai-spark/src/main/java/com/ai/spark/endPoint/images/ImageHeader.java",
    "content": "package com.ai.spark.endPoint.images;\n\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport com.fasterxml.jackson.annotation.JsonInclude;\nimport com.fasterxml.jackson.annotation.JsonProperty;\nimport lombok.AllArgsConstructor;\nimport lombok.Builder;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\nimport lombok.experimental.FieldNameConstants;\n\n@Data\n@Builder\n@NoArgsConstructor\n@AllArgsConstructor\n@FieldNameConstants\n@JsonIgnoreProperties(ignoreUnknown = true)\n@JsonInclude(JsonInclude.Include.NON_NULL)\npublic class ImageHeader {\n\n    @JsonProperty(\"app_id\")\n    private String appId;\n\n    private String uid;\n\n    // 下面是返回时用到的属性\n\n    private Integer code;\n\n    private String message;\n\n    private String sid;\n\n    private Integer status;\n\n}\n"
  },
  {
    "path": "ai-spark/src/main/java/com/ai/spark/endPoint/images/ImageParameter.java",
    "content": "package com.ai.spark.endPoint.images;\n\n\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport com.fasterxml.jackson.annotation.JsonInclude;\nimport com.fasterxml.jackson.annotation.JsonProperty;\nimport lombok.AllArgsConstructor;\nimport lombok.Builder;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\nimport lombok.experimental.FieldNameConstants;\n\n@Data\n@Builder\n@NoArgsConstructor\n@AllArgsConstructor\n@FieldNameConstants\n@JsonIgnoreProperties(ignoreUnknown = true)\n@JsonInclude(JsonInclude.Include.NON_NULL)\npublic class ImageParameter {\n\n    @Builder.Default\n    @JsonProperty(\"chat\")\n    private ImageChat imageChat = ImageChat.builder().build();\n\n}\n"
  },
  {
    "path": "ai-spark/src/main/java/com/ai/spark/endPoint/images/ImagePayload.java",
    "content": "package com.ai.spark.endPoint.images;\n\nimport com.ai.spark.endPoint.chat.Choice;\nimport com.ai.spark.endPoint.chat.Message;\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport com.fasterxml.jackson.annotation.JsonInclude;\nimport com.fasterxml.jackson.annotation.JsonProperty;\nimport lombok.AllArgsConstructor;\nimport lombok.Builder;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\nimport lombok.experimental.FieldNameConstants;\n\n@Data\n@Builder\n@NoArgsConstructor\n@AllArgsConstructor\n@FieldNameConstants\n@JsonIgnoreProperties(ignoreUnknown = true)\n@JsonInclude(JsonInclude.Include.NON_NULL)\npublic class ImagePayload {\n\n    private Message message;\n\n    @JsonProperty(\"choices\")\n    private Choice choice;\n\n}\n"
  },
  {
    "path": "ai-spark/src/main/java/com/ai/spark/endPoint/images/ImageUnderstandingChat.java",
    "content": "package com.ai.spark.endPoint.images;\n\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport com.fasterxml.jackson.annotation.JsonInclude;\nimport com.fasterxml.jackson.annotation.JsonProperty;\nimport lombok.AllArgsConstructor;\nimport lombok.Builder;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\nimport lombok.experimental.FieldNameConstants;\n\n@Data\n@Builder\n@NoArgsConstructor\n@AllArgsConstructor\n@FieldNameConstants\n@JsonIgnoreProperties(ignoreUnknown = true)\n@JsonInclude(JsonInclude.Include.NON_NULL)\npublic class ImageUnderstandingChat {\n\n    @Builder.Default\n    private String domain = \"general\";\n\n    private String auditing;\n\n    private Double temperature;\n\n    @JsonProperty(\"top_k\")\n    private Integer topK;\n\n    @JsonProperty(\"max_tokens\")\n    private Integer maxTokens;\n\n}\n"
  },
  {
    "path": "ai-spark/src/main/java/com/ai/spark/endPoint/images/ImageUnderstandingParameter.java",
    "content": "package com.ai.spark.endPoint.images;\n\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport com.fasterxml.jackson.annotation.JsonInclude;\nimport com.fasterxml.jackson.annotation.JsonProperty;\nimport lombok.AllArgsConstructor;\nimport lombok.Builder;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\nimport lombok.experimental.FieldNameConstants;\n\n@Data\n@Builder\n@NoArgsConstructor\n@AllArgsConstructor\n@FieldNameConstants\n@JsonIgnoreProperties(ignoreUnknown = true)\n@JsonInclude(JsonInclude.Include.NON_NULL)\npublic class ImageUnderstandingParameter {\n\n    @Builder.Default\n    @JsonProperty(\"chat\")\n    private ImageUnderstandingChat imageUnderstandingChat = ImageUnderstandingChat.builder().build();\n\n}\n"
  },
  {
    "path": "ai-spark/src/main/java/com/ai/spark/endPoint/images/ImageUnderstandingPayload.java",
    "content": "package com.ai.spark.endPoint.images;\n\n\nimport com.ai.spark.common.Usage;\nimport com.ai.spark.endPoint.chat.Choice;\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport com.fasterxml.jackson.annotation.JsonInclude;\nimport com.fasterxml.jackson.annotation.JsonProperty;\nimport lombok.AllArgsConstructor;\nimport lombok.Builder;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\nimport lombok.experimental.FieldNameConstants;\n\n@Data\n@Builder\n@NoArgsConstructor\n@AllArgsConstructor\n@FieldNameConstants\n@JsonIgnoreProperties(ignoreUnknown = true)\n@JsonInclude(JsonInclude.Include.NON_NULL)\npublic class ImageUnderstandingPayload {\n\n    @JsonProperty(\"choices\")\n    private Choice choice;\n\n    private Usage usage;\n\n}\n"
  },
  {
    "path": "ai-spark/src/main/java/com/ai/spark/endPoint/images/req/ImageCreateRequest.java",
    "content": "package com.ai.spark.endPoint.images.req;\n\nimport com.ai.spark.endPoint.chat.ChatText;\nimport com.ai.spark.endPoint.chat.Message;\nimport com.ai.spark.endPoint.images.ImageHeader;\nimport com.ai.spark.endPoint.images.ImageParameter;\nimport com.ai.spark.endPoint.images.ImagePayload;\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport com.fasterxml.jackson.annotation.JsonInclude;\nimport com.fasterxml.jackson.annotation.JsonProperty;\nimport lombok.AllArgsConstructor;\nimport lombok.Builder;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\nimport lombok.experimental.FieldNameConstants;\n\nimport java.util.Arrays;\n\n@Data\n@Builder\n@NoArgsConstructor\n@AllArgsConstructor\n@FieldNameConstants\n@JsonIgnoreProperties(ignoreUnknown = true)\n@JsonInclude(JsonInclude.Include.NON_NULL)\npublic class ImageCreateRequest {\n\n    @JsonProperty(\"header\")\n    private ImageHeader imageHeader;\n\n    @JsonProperty(\"parameter\")\n    private ImageParameter imageParameter;\n\n    @JsonProperty(\"payload\")\n    private ImagePayload imagePayload;\n\n    public static ImageCreateRequest baseBuild(String content, String appId) {\n        return ImageCreateRequest\n                .builder()\n                .imageHeader(ImageHeader.builder().appId(appId).build())\n                .imageParameter(ImageParameter.builder().build())\n                .imagePayload(ImagePayload.builder().message(Message.builder().chatTexts(Arrays.asList(ChatText.baseBuild(ChatText.Role.USER, content))).build()).build())\n                .build();\n    }\n\n}\n"
  },
  {
    "path": "ai-spark/src/main/java/com/ai/spark/endPoint/images/req/ImageUnderstandingRequest.java",
    "content": "package com.ai.spark.endPoint.images.req;\n\nimport com.ai.spark.endPoint.chat.ChatText;\nimport com.ai.spark.endPoint.chat.Message;\nimport com.ai.spark.endPoint.images.ImageHeader;\nimport com.ai.spark.endPoint.images.ImagePayload;\nimport com.ai.spark.endPoint.images.ImageUnderstandingParameter;\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport com.fasterxml.jackson.annotation.JsonInclude;\nimport com.fasterxml.jackson.annotation.JsonProperty;\nimport lombok.AllArgsConstructor;\nimport lombok.Builder;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\nimport lombok.experimental.FieldNameConstants;\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileNotFoundException;\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Base64;\n\n@Data\n@Builder\n@NoArgsConstructor\n@AllArgsConstructor\n@FieldNameConstants\n@JsonIgnoreProperties(ignoreUnknown = true)\n@JsonInclude(JsonInclude.Include.NON_NULL)\npublic class ImageUnderstandingRequest {\n\n    @JsonProperty(\"header\")\n    private ImageHeader imageHeader;\n\n    @JsonProperty(\"parameter\")\n    private ImageUnderstandingParameter imageUnderstandingParameter;\n\n    @JsonProperty(\"payload\")\n    private ImagePayload imagePayload;\n\n    public static ImageUnderstandingRequest baseBuild(String content, String appId, File image) {\n        byte[] data = null;\n        try (FileInputStream fileInputStream = new FileInputStream(image)) {\n            data = new byte[fileInputStream.available()];\n            fileInputStream.read(data); // 读取文件数据到数组中\n        } catch (FileNotFoundException e) {\n            e.printStackTrace();\n        } catch (IOException e) {\n            e.printStackTrace();\n        }\n        String imageStr = Base64.getEncoder().encodeToString(data); // 将byte数组进行base64编码\n        ImageHeader imageHeader = ImageHeader.builder().appId(appId).build();\n        ImageUnderstandingParameter imageUnderstandingParameter = ImageUnderstandingParameter.builder().build();\n        ChatText chatText = ChatText.baseBuild(ChatText.Role.USER, content);\n        chatText.setContentType(ChatText.ContentType.TEXT.getType());\n        ChatText imgText = ChatText.baseBuild(ChatText.Role.USER, imageStr);\n        imgText.setContentType(ChatText.ContentType.IMAGE.getType());\n        Message message = Message.builder().chatTexts(new ArrayList<>(Arrays.asList(imgText, chatText))).build();\n        ImagePayload imagePayload = ImagePayload.builder().message(message).build();\n        return ImageUnderstandingRequest\n                .builder()\n                .imageHeader(imageHeader)\n                .imagePayload(imagePayload)\n                .imageUnderstandingParameter(imageUnderstandingParameter).build();\n\n    }\n\n}\n"
  },
  {
    "path": "ai-spark/src/main/java/com/ai/spark/endPoint/images/resp/ImageCreateResponse.java",
    "content": "package com.ai.spark.endPoint.images.resp;\n\nimport com.ai.spark.endPoint.images.ImageHeader;\nimport com.ai.spark.endPoint.images.ImagePayload;\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport com.fasterxml.jackson.annotation.JsonInclude;\nimport com.fasterxml.jackson.annotation.JsonProperty;\nimport lombok.AllArgsConstructor;\nimport lombok.Builder;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\nimport lombok.experimental.FieldNameConstants;\n\n@Data\n@Builder\n@NoArgsConstructor\n@AllArgsConstructor\n@FieldNameConstants\n@JsonIgnoreProperties(ignoreUnknown = true)\n@JsonInclude(JsonInclude.Include.NON_NULL)\npublic class ImageCreateResponse {\n\n    @JsonProperty(\"header\")\n    private ImageHeader imageHeader;\n\n    @JsonProperty(\"payload\")\n    private ImagePayload imagePayload;\n}\n"
  },
  {
    "path": "ai-spark/src/main/java/com/ai/spark/endPoint/images/resp/ImageUnderstandingResponse.java",
    "content": "package com.ai.spark.endPoint.images.resp;\n\nimport com.ai.spark.endPoint.images.ImageHeader;\nimport com.ai.spark.endPoint.images.ImageUnderstandingPayload;\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport com.fasterxml.jackson.annotation.JsonInclude;\nimport com.fasterxml.jackson.annotation.JsonProperty;\nimport lombok.AllArgsConstructor;\nimport lombok.Builder;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\nimport lombok.experimental.FieldNameConstants;\n\n@Data\n@Builder\n@NoArgsConstructor\n@AllArgsConstructor\n@FieldNameConstants\n@JsonIgnoreProperties(ignoreUnknown = true)\n@JsonInclude(JsonInclude.Include.NON_NULL)\npublic class ImageUnderstandingResponse {\n\n    @JsonProperty(\"header\")\n    private ImageHeader imageHeader;\n\n    @JsonProperty(\"payload\")\n    private ImageUnderstandingPayload imageUnderstandingPayload;\n\n}\n"
  },
  {
    "path": "ai-spark/src/main/java/com/ai/spark/interceptor/BaseUrlInterceptor.java",
    "content": "package com.ai.spark.interceptor;\n\nimport lombok.extern.slf4j.Slf4j;\nimport okhttp3.Interceptor;\nimport okhttp3.Request;\nimport okhttp3.Response;\n\nimport java.io.IOException;\n\n\n@Slf4j\npublic class BaseUrlInterceptor implements Interceptor {\n    // TODO 对路径进行拦截\n    @Override\n    public Response intercept(Chain chain) throws IOException {\n        //获取request\n        Request request = chain.request();\n        return chain.proceed(request);\n    }\n}\n\n"
  },
  {
    "path": "ai-spark/src/main/java/com/ai/spark/interceptor/ResponseInterceptor.java",
    "content": "package com.ai.spark.interceptor;\n\nimport com.ai.core.exception.BaseException;\nimport com.ai.core.exception.Constants;\nimport lombok.extern.slf4j.Slf4j;\nimport okhttp3.Interceptor;\nimport okhttp3.Request;\nimport okhttp3.Response;\n\nimport java.io.IOException;\n\n/**\n * 返回信息拦截器\n */\n@Slf4j\npublic class ResponseInterceptor implements Interceptor {\n    @Override\n    public Response intercept(Chain chain) throws IOException {\n        // 1. 获取 req 和 resp\n        Request original = chain.request();\n        Response response = chain.proceed(original);\n        // 2. 排除webSocket连接，判断返回状态\n        if (!\"websocket\".equalsIgnoreCase(response.header(\"Upgrade\"))\n                && !\"Upgrade\".equalsIgnoreCase(response.header(\"Connection\"))\n                && !response.isSuccessful()\n                && response.body() != null) {\n            // 2.1 获取返回的错误信息\n            log.error(response.body().string());\n            throw new BaseException(Constants.ErrorMsg.RETRY_ERROR);\n        }\n        return response;\n    }\n}\n"
  },
  {
    "path": "ai-spark/src/test/java/com/ai/spark/AudioApiTest.java",
    "content": "package com.ai.spark;\n\nimport com.ai.core.strategy.impl.FirstKeyStrategy;\nimport com.ai.spark.achieve.ApiData;\nimport com.ai.spark.achieve.Configuration;\nimport com.ai.spark.achieve.defaults.DefaultSparkSessionFactory;\nimport com.ai.spark.achieve.standard.session.AggregationSession;\nimport org.junit.Before;\n\nimport java.util.Arrays;\n\n\npublic class AudioApiTest {\n\n    private AggregationSession aggregationSession;\n\n    @Before\n    public void before() {\n        // 1. 创建配置类\n        Configuration configuration = new Configuration();\n        configuration.setApiHost(\"https://spark-api.xf-yun.com\");\n        // 3. 设置鉴权所需的API Key,可设置多个。\n        ApiData apiData = ApiData.builder()\n                .apiKey(\"***********************\")\n                .apiSecret(\"***********************\")\n                .appId(\"***********************\")\n                .build();\n        configuration.setKeyList(Arrays.asList(apiData));\n        // 4. 设置请求时 key 的使用策略，默认实现了：随机获取 和 固定第一个Key 两种方式。\n        configuration.setKeyStrategy(new FirstKeyStrategy<ApiData>());\n//        configuration.setKeyStrategy(new RandomKeyStrategy<ApiData>());\n        // 5. 设置代理，若不需要可不设置\n//        configuration.setProxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress(\"127.0.0.1\", 7890)));\n        // 6. 创建 session 工厂，制造不同场景的 session\n        DefaultSparkSessionFactory factory = new DefaultSparkSessionFactory(configuration);\n        this.aggregationSession = factory.openAggregationSession();\n    }\n\n}\n"
  },
  {
    "path": "ai-spark/src/test/java/com/ai/spark/ChatApiTest.java",
    "content": "package com.ai.spark;\n\n\nimport com.ai.core.strategy.impl.FirstKeyStrategy;\nimport com.ai.spark.achieve.ApiData;\nimport com.ai.spark.achieve.Configuration;\nimport com.ai.spark.achieve.defaults.DefaultSparkSessionFactory;\nimport com.ai.spark.achieve.defaults.listener.ChatListener;\nimport com.ai.spark.achieve.defaults.listener.DocumentChatListener;\nimport com.ai.spark.achieve.standard.session.AggregationSession;\nimport com.ai.spark.endPoint.chat.ChatText;\nimport com.ai.spark.endPoint.chat.req.ChatRequest;\nimport com.ai.spark.endPoint.chat.req.DocumentChatRequest;\nimport com.ai.spark.endPoint.chat.resp.ChatResponse;\nimport com.ai.spark.endPoint.chat.resp.DocumentChatResponse;\nimport lombok.SneakyThrows;\nimport org.junit.Before;\nimport org.junit.Test;\n\nimport java.util.Arrays;\nimport java.util.concurrent.CountDownLatch;\n\npublic class ChatApiTest {\n\n    private AggregationSession aggregationSession;\n\n    @Before\n    public void before() {\n        // 1. 创建配置类\n        Configuration configuration = new Configuration();\n        configuration.setApiHost(\"https://spark-api.xf-yun.com\");\n        // 3. 设置鉴权所需的API Key,可设置多个。\n        ApiData apiData = ApiData.builder()\n                .apiKey(\"**********************\")\n                .apiSecret(\"**********************\")\n                .appId(\"**********************\")\n                .build();\n        configuration.setKeyList(Arrays.asList(apiData));\n        // 4. 设置请求时 key 的使用策略，默认实现了：随机获取 和 固定第一个Key 两种方式。\n        configuration.setKeyStrategy(new FirstKeyStrategy<ApiData>());\n//        configuration.setKeyStrategy(new RandomKeyStrategy<ApiData>());\n        // 5. 设置代理，若不需要可不设置\n//        configuration.setProxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress(\"127.0.0.1\", 7890)));\n        // 6. 创建 session 工厂，制造不同场景的 session\n        DefaultSparkSessionFactory factory = new DefaultSparkSessionFactory(configuration);\n        this.aggregationSession = factory.openAggregationSession();\n    }\n\n    /**\n     * 测试聊天功能\n     */\n    @Test\n    public void test_chat() {\n        // 创建参数\n        ChatRequest request = ChatRequest.baseBuild(\"讲一个笑话\", \"c8f362b8\");\n        // 设置参数并发起请求，监听事件信息\n        aggregationSession.getChatSession().chat(new ChatListener(request) {\n            // 异常处理\n            @SneakyThrows\n            @Override\n            public void onChatError(ChatResponse chatResponse) {\n                System.out.println(chatResponse);\n            }\n\n            // 获取正常返回的数据\n            @Override\n            public void onChatOutput(ChatResponse chatResponse) {\n                System.out.println(chatResponse);\n                System.out.print(chatResponse.getChatPayload().getChoice().getTexts().get(0).getContent());\n            }\n\n            // 结束处理\n            @Override\n            public void onChatEnd() {\n                System.out.println(\"当前会话结束了\");\n            }\n\n        });\n        // 等待会话结束\n        CountDownLatch countDownLatch = new CountDownLatch(1);\n        try {\n            countDownLatch.await();\n        } catch (InterruptedException e) {\n            e.printStackTrace();\n        }\n    }\n\n    /**\n     * 测试多轮聊天功能\n     */\n    @Test\n    public void test_chat_multiple() {\n        // 创建参数\n        ChatRequest request = ChatRequest.baseBuild(\"1+1=\", \"c8f362b8\");\n        // 设置第一轮对话的结果\n        ChatText chatText1 = ChatText.baseBuild(ChatText.Role.ASSISTANT, \"2\");\n        // 设置第二轮对话的问题\n        ChatText chatText2 = ChatText.baseBuild(ChatText.Role.USER, \"2+2=\");\n        // 将对话过程注入到参数当中\n        request.getChatPayload().getMessage().getChatTexts().add(chatText1);\n        request.getChatPayload().getMessage().getChatTexts().add(chatText2);\n        // 设置参数并发起请求，监听事件信息\n        aggregationSession.getChatSession().chat(new ChatListener(request) {\n            @Override\n            public void onChatError(ChatResponse chatResponse) {\n                System.out.println(chatResponse);\n            }\n\n            @Override\n            public void onChatOutput(ChatResponse chatResponse) {\n                System.out.print(chatResponse.getChatPayload().getChoice().getTexts().get(0).getContent());\n            }\n\n            @Override\n            public void onChatEnd() {\n                System.out.println(\"当前会话结束了\");\n            }\n\n        });\n        // 等待会话结束\n        CountDownLatch countDownLatch = new CountDownLatch(1);\n        try {\n            countDownLatch.await();\n        } catch (InterruptedException e) {\n            e.printStackTrace();\n        }\n    }\n\n    /**\n     * 测试文档对话功能\n     */\n    @Test\n    public void test_document_chat() {\n        // 构建参数\n        DocumentChatRequest documentChatRequest = DocumentChatRequest.baseBuild(\"总结一下故事一说了什么？\", Arrays.asList(\"c42a68fd31964d43b4f57eab11e9a833\"));\n        // 设置阐述并发起请求\n        aggregationSession.getChatSession().documentChat(new DocumentChatListener(documentChatRequest) {\n            @Override\n            public void onChatError(DocumentChatResponse documentChatResponse) {\n                System.err.println(documentChatResponse);\n            }\n\n            @Override\n            public void onChatOutput(DocumentChatResponse documentChatResponse) {\n                System.out.println(documentChatResponse);\n            }\n\n            @Override\n            public void onChatEnd() {\n                System.out.println(\"当前会话结束了\");\n            }\n        });\n        // 等待会话结束\n        CountDownLatch countDownLatch = new CountDownLatch(1);\n        try {\n            countDownLatch.await();\n        } catch (InterruptedException e) {\n            e.printStackTrace();\n        }\n    }\n}\n"
  },
  {
    "path": "ai-spark/src/test/java/com/ai/spark/DocumentApiTest.java",
    "content": "package com.ai.spark;\n\nimport com.ai.core.strategy.impl.FirstKeyStrategy;\nimport com.ai.spark.achieve.ApiData;\nimport com.ai.spark.achieve.Configuration;\nimport com.ai.spark.achieve.defaults.DefaultSparkSessionFactory;\nimport com.ai.spark.achieve.standard.session.AggregationSession;\nimport com.ai.spark.endPoint.document.req.FileUploadRequest;\nimport com.ai.spark.endPoint.document.resp.DocumentSummaryResponse;\nimport com.ai.spark.endPoint.document.resp.FileUploadResponse;\nimport org.junit.Before;\nimport org.junit.Test;\n\nimport java.io.File;\nimport java.util.Arrays;\n\npublic class DocumentApiTest {\n\n    private AggregationSession aggregationSession;\n\n    @Before\n    public void before() {\n        // 1. 创建配置类\n        Configuration configuration = new Configuration();\n        configuration.setApiHost(\"https://spark-api.xf-yun.com\");\n        // 3. 设置鉴权所需的API Key,可设置多个。\n        ApiData apiData = ApiData.builder()\n                .apiKey(\"***********************\")\n                .apiSecret(\"***********************\")\n                .appId(\"***********************\")\n                .build();\n        configuration.setKeyList(Arrays.asList(apiData));\n        // 4. 设置请求时 key 的使用策略，默认实现了：随机获取 和 固定第一个Key 两种方式。\n        configuration.setKeyStrategy(new FirstKeyStrategy<ApiData>());\n//        configuration.setKeyStrategy(new RandomKeyStrategy<ApiData>());\n        // 5. 设置代理，若不需要可不设置\n//        configuration.setProxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress(\"127.0.0.1\", 7890)));\n        // 6. 创建 session 工厂，制造不同场景的 session\n        DefaultSparkSessionFactory factory = new DefaultSparkSessionFactory(configuration);\n        this.aggregationSession = factory.openAggregationSession();\n    }\n\n    /**\n     * 测试文件上传功能\n     */\n    @Test\n    public void test_file_upload() {\n        // 读取文件\n        File file = new File(\"D:\\\\chatGPT-api\\\\AI-java\\\\doc\\\\test\\\\test_file_upload.pdf\");\n        // 构建参数\n        FileUploadRequest request = FileUploadRequest.builder().file(file).build();\n        // 发起请求获取结果\n        FileUploadResponse fileUploadResponse = this.aggregationSession.getDocumentSession().fileUpload(request);\n        System.out.println(fileUploadResponse);\n//        FileUploadResponse(code=0, sid=28db14303e054046aabd2e96e7e65c51, desc=null, data=Data(fileId=1a477e7e9cb44e23ad4abd98076e3f70))\n//        FileUploadResponse(code=0, sid=8e4f267415d84827a6ec7a1580e1ce64, desc=null, data=Data(fileId=004c3c6e79bc4d738a7e94a12697ea75))\n    }\n\n    // 文档总结和文档总结查询这两个接口其实只有请求路径不同，类似于异步的效果。\n    // 调用文档总结接口，并不会直接返回结果，而是通知模型开始进行总结。\n    // 然后调用文档总结查询接口查询结果，如果结果已经存在的情况下，不管是调用文档总结接口还是文档总结查询接口，返回的数据都是一样的。\n\n    /**\n     * 测试文档总结功能\n     */\n    @Test\n    public void test_document_summary_start() {\n        // 传入文档ID，发起请求\n        DocumentSummaryResponse documentSummaryResponse = this.aggregationSession.getDocumentSession()\n                .documentSummaryStart(\"004c3c6e79bc4d738a7e94a12697ea75\");\n        System.out.println(documentSummaryResponse);\n    }\n\n    /**\n     * 测试文档总结结果查询功能\n     */\n    @Test\n    public void test_document_summary_query() {\n        // 传入文档ID，发起请求\n        DocumentSummaryResponse documentSummaryResponse = this.aggregationSession.getDocumentSession()\n                .documentSummaryQuery(\"004c3c6e79bc4d738a7e94a12697ea75\");\n        System.out.println(documentSummaryResponse);\n    }\n}\n"
  },
  {
    "path": "ai-spark/src/test/java/com/ai/spark/EmbeddingApiTest.java",
    "content": "package com.ai.spark;\n\n\nimport com.ai.core.strategy.impl.FirstKeyStrategy;\nimport com.ai.spark.achieve.ApiData;\nimport com.ai.spark.achieve.Configuration;\nimport com.ai.spark.achieve.defaults.DefaultSparkSessionFactory;\nimport com.ai.spark.achieve.standard.session.AggregationSession;\nimport com.ai.spark.endPoint.chat.ChatText;\nimport com.ai.spark.endPoint.embedding.req.EmbeddingRequest;\nimport com.ai.spark.endPoint.embedding.resp.EmbeddingResponse;\nimport org.junit.Before;\nimport org.junit.Test;\n\nimport java.util.Arrays;\n\npublic class EmbeddingApiTest {\n\n\n    private AggregationSession aggregationSession;\n\n    @Before\n    public void before() {\n        // 1. 创建配置类\n        Configuration configuration = new Configuration();\n        configuration.setApiHost(\"https://spark-api.xf-yun.com\");\n        // 3. 设置鉴权所需的API Key,可设置多个。\n        ApiData apiData = ApiData.builder()\n                .apiKey(\"**********************\")\n                .apiSecret(\"**********************\")\n                .appId(\"**********************\")\n                .build();\n        configuration.setKeyList(Arrays.asList(apiData));\n        // 4. 设置请求时 key 的使用策略，默认实现了：随机获取 和 固定第一个Key 两种方式。\n        configuration.setKeyStrategy(new FirstKeyStrategy<ApiData>());\n//        configuration.setKeyStrategy(new RandomKeyStrategy<ApiData>());\n        // 5. 设置代理，若不需要可不设置\n//        configuration.setProxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress(\"127.0.0.1\", 7890)));\n        // 6. 创建 session 工厂，制造不同场景的 session\n        DefaultSparkSessionFactory factory = new DefaultSparkSessionFactory(configuration);\n        this.aggregationSession = factory.openAggregationSession();\n    }\n\n    /**\n     * 测试文本嵌入功能\n     */\n    @Test\n    public void test_embedding() {\n        // 构造参数信息\n        ChatText chatText = ChatText.baseBuild(ChatText.Role.USER, \"这是一段文字\");\n        EmbeddingRequest request = EmbeddingRequest.baseBuild(chatText, \"c8f362b8\");\n        // 发起请求\n        EmbeddingResponse response = aggregationSession.getEmbeddingSession().embed(request);\n        System.out.println(response);\n    }\n\n}\n"
  },
  {
    "path": "ai-spark/src/test/java/com/ai/spark/ImageApiTest.java",
    "content": "package com.ai.spark;\n\nimport com.ai.core.strategy.impl.FirstKeyStrategy;\nimport com.ai.spark.achieve.ApiData;\nimport com.ai.spark.achieve.Configuration;\nimport com.ai.spark.achieve.defaults.DefaultSparkSessionFactory;\nimport com.ai.spark.achieve.defaults.listener.ImageUnderstandingListener;\nimport com.ai.spark.achieve.standard.session.AggregationSession;\nimport com.ai.spark.endPoint.images.req.ImageCreateRequest;\nimport com.ai.spark.endPoint.images.req.ImageUnderstandingRequest;\nimport com.ai.spark.endPoint.images.resp.ImageCreateResponse;\nimport com.ai.spark.endPoint.images.resp.ImageUnderstandingResponse;\nimport org.junit.Before;\nimport org.junit.Test;\n\nimport javax.imageio.ImageIO;\nimport javax.xml.bind.DatatypeConverter;\nimport java.awt.image.BufferedImage;\nimport java.io.ByteArrayInputStream;\nimport java.io.File;\nimport java.io.IOException;\nimport java.util.Arrays;\nimport java.util.concurrent.CountDownLatch;\n\npublic class ImageApiTest {\n\n    private AggregationSession aggregationSession;\n\n    @Before\n    public void before() {\n        // 1. 创建配置类\n        Configuration configuration = new Configuration();\n        configuration.setApiHost(\"https://spark-api.xf-yun.com\");\n        // 3. 设置鉴权所需的API Key,可设置多个。\n        ApiData apiData = ApiData.builder()\n                .apiKey(\"**********************\")\n                .apiSecret(\"**********************\")\n                .appId(\"**********************\")\n                .build();\n        configuration.setKeyList(Arrays.asList(apiData));\n        // 4. 设置请求时 key 的使用策略，默认实现了：随机获取 和 固定第一个Key 两种方式。\n        configuration.setKeyStrategy(new FirstKeyStrategy<ApiData>());\n//        configuration.setKeyStrategy(new RandomKeyStrategy<ApiData>());\n        // 5. 设置代理，若不需要可不设置\n//        configuration.setProxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress(\"127.0.0.1\", 7890)));\n        // 6. 创建 session 工厂，制造不同场景的 session\n        DefaultSparkSessionFactory factory = new DefaultSparkSessionFactory(configuration);\n        this.aggregationSession = factory.openAggregationSession();\n    }\n\n    /**\n     * 测试图片生成功能\n     */\n    @Test\n    public void test_image_create() throws IOException {\n        // 创建请求参数\n        ImageCreateRequest request = ImageCreateRequest.baseBuild(\"画一座大山\", \"c8f362b8\");\n        // 发起请求获取结果\n        ImageCreateResponse imageCreateResponse = aggregationSession.getImageSession().imageCreate(request);\n        // 得到结果当中的base64 图片字符串\n        String content = imageCreateResponse.getImagePayload().getChoice().getTexts().get(0).getContent();\n        // 转换为byte数组\n        byte[] imageBytes = DatatypeConverter.parseBase64Binary(content.substring(content.indexOf(\",\") + 1));\n        // 读取byte数组，存放到指定文件路径\n        BufferedImage bufferedImage = ImageIO.read(new ByteArrayInputStream(imageBytes));\n        File outputFile = new File(\"D:\\\\chatGPT-api\\\\AI-java\\\\doc\\\\test\\\\test_create_image.png\");\n        ImageIO.write(bufferedImage, \"png\", outputFile);\n    }\n\n    @Test\n    public void test_image_understanding() {\n        String filePath = \"D:\\\\chatGPT-api\\\\AI-java\\\\doc\\\\test\\\\test_create_image.png\";\n        File file = new File(filePath);\n        ImageUnderstandingRequest request = ImageUnderstandingRequest.baseBuild(\"这张图片的内容是什么？\", \"c8f362b8\", file);\n        aggregationSession.getImageSession().imageUnderstanding(request, new ImageUnderstandingListener(request) {\n            @Override\n            public void onChatError(ImageUnderstandingResponse imageUnderstandingResponse) {\n                System.err.println(imageUnderstandingResponse);\n            }\n\n            @Override\n            public void onChatOutput(ImageUnderstandingResponse imageUnderstandingResponse) {\n                System.out.println(imageUnderstandingResponse.getImageUnderstandingPayload().getChoice().getTexts().get(0).getContent());\n            }\n\n            @Override\n            public void onChatEnd() {\n            }\n        });\n        // 等待会话结束\n        CountDownLatch countDownLatch = new CountDownLatch(1);\n        try {\n            countDownLatch.await();\n        } catch (InterruptedException e) {\n            e.printStackTrace();\n        }\n    }\n\n\n}\n"
  },
  {
    "path": "doc/test/test_file_upload.txt",
    "content": "故事1：小老虎问路\n\n一头骄傲的小老虎在大森林里迷了路。\n\n他走啊走，看到了一头正在蒙头大睡的野猪。小老虎对着野猪的耳朵，大声喊道：“喂，蠢猪，别打呼噜了，告诉我回家的路怎么走吧!”野猪生气地眨了眨眼睛，一言不发，把屁股转向了小老虎，继续睡大觉。小老虎讨了个没趣，无奈地走了。\n\n小老虎问路\n\n路上，他看到一只正在忙碌的小松鼠，于是他用自己的大嗓门儿喊道：“喂，如果你告诉我回家的路怎么走，我就让妈妈给你最好的礼物!”小松鼠就像没听见一样，不搭理小老虎，照样干自己的活儿。小老虎勃然大怒，冲向一只戴眼镜的老灰兔：“嘿，花眼的老兔头，快给我指一条回家的路!”老灰兔慢慢地抬起头，和蔼地说：“森林里的路大家都熟悉，可你这样没礼貌，哪怕你问遍所有的动物，你还是找不到回家的路。”听了老灰兔的话，小老虎猛然醒悟过来——对人说话，要有礼貌才行!\n\n这时，前面过来一只梅花鹿。小老虎走过去，礼貌地说：“梅花鹿你好，请你告诉我回家的路怎么走，好吗?”梅花鹿热情地告诉了小老虎，小老虎高兴的连声说：“谢谢你，梅花鹿，谢谢你!”\n\n小老虎终于安全地回到了自己的小屋。\n\n\n\n故事2：鸡和猫调工作\n\n张三家里养了一只猫和一只公鸡。\n\n一天早晨，“喔，喔，喔……”公鸡的长鸣把沉睡的猫叫醒了，猫揉了揉眼说：“死公鸡，没娘教的孩子，吵死啊!”公鸡大声地回骂道：“死懒猫，你才没娘教，太阳晒屁股了，还不起来干活!”猫又回敬了一句：“哼，我晚上辛辛苦苦晚上捉老鼠，白天还不让我多睡会儿?”公鸡无语了。\n\n过了一会儿，猫想出一个好办法，对公鸡说：“不如，我们调换一下工作，你去捉老鼠，我来打鸣叫时钟，你敢不敢?”公鸡自信地说：“啊有不敢?我就怕你不敢?”猫说：“好，那我们就调工作吧!”\n\n第二天早晨，猫早早地起来，站在房顶上，“喵，喵，喵……”地叫着，可是人们都听习惯了公鸡叫天亮，猫的叫声只把附近的人叫醒了，远处的人根本听不见。后来，猫的嗓子都喊破了，被送到宠物医院治疗。\n\n晚上，公鸡来到老鼠洞前，对老鼠说：“鸡大爷来了，快给我出来!”鼠王以为是猫的诡计，就叫了一只小老鼠去侦察，小老鼠侦察了一番回来说：“站在洞门口的是一只公鸡。”于是，鼠们就往老鼠洞里钻。公鸡见一只老鼠都不出来，就把锋利的爪子伸进老鼠洞里，一只老鼠胆大包天串到洞门口对准鸡爪狠狠地咬了一口，鸡痛得哇哇大叫，也被送进了宠物医院。\n\n猫和公鸡在宠物医院相遇了，当他们见彼此都受了伤后，明白了一个道理：尺有所短，寸有所长。\n\n\n\n故事3：固执的鱼\n\n在一个池塘里住着一条小鱼。他有一个好朋友，是一只蝌蚪。这条小鱼和蝌蚪总是在一起游泳，一起找食物，一起玩。\n\n一天早上，小鱼吃惊地看见在蝌蚪尾巴的两边长出了一对腿。小鱼问蝌蚪为什么他会有腿。\n\n“我不是鱼，我是一只蝌蚪，一只年幼的青蛙。以后，等我长大了，我就不再呆在这儿了。”蝌蚪回答说。\n\n“你说谎!”小鱼说。\n\n“如果你不相信，就等着瞧吧!”蝌蚪说。\n\n小鱼已经三天没有看见蝌蚪了，他很担心。为了寻找朋友，他搜索了每一个地方，蝌蚪能去哪儿呢?\n\n几天以后，蝌蚪又出现了。小鱼非常高兴，可是他又吃了一惊，蝌蚪又长出了一对腿，哦，还有，尾巴也变短了。\n\n“这几天你到什么地方去了?”小鱼问。\n\n“我去陆地上了，我不是告诉你我在这儿呆不长吗?看，现在我有四条腿了。不久我就要长期在地上生活了。”蝌蚪说，“现在请不要再叫我蝌蚪，就叫我青蛙吧。再见了，鱼!”\n\n小鱼眨眨眼睛，被他朋友的话搞糊涂了。他不能相信听到和看到的，因为从前他的朋友能像鱼一样游泳，从前他没有腿，而现在却不是这样了。\n\n小鱼独自留在池塘里，最后，他变成了一条大鱼。\n\n一天，当这条鱼在池塘里游水寻找食物的时候，一只青蛙跳进水里。他就是鱼的老朋友。看到朋友，鱼非常高兴。\n\n“你去哪儿啦?”鱼问。\n\n“我一直在陆地上。”青蛙说，并且把他在陆地上遇到的事情告诉鱼。\n\n鱼听了青蛙的故事后，问：“在那边谁是你的朋友呀?”\n\n“我有好多朋友，像牛啦，鸟啦，猫啦，还有其它许多动物。”青蛙说。\n\n“我能跟你去陆地吗?我想见见他们。”鱼说。\n\n“那怎么行!你在陆地上不能呼吸，你会死的。”青蛙解释说。\n\n“可是我想去看看牛啦，鸟啦，还有别的你刚才告诉我的朋友们。”鱼请求道。\n\n“你不必亲自去，我给你说说不就行了。”青蛙说。于是青蛙向鱼讲了许多他的陆地朋友的事。鱼试着想象那些动物的样子，但是他总是不满意。\n\n“你在陆地上还看见什么别的吗?”鱼又问。\n\n“还有人，有孩子，有玩具和别的许多东西。”青蛙继续说。\n\n他们一直聊到晚上。鱼很不开心，因为他不能去陆地上看这些奇怪的事，这天晚上他失眠了。他满脑子都是白天听到的各种各样的事情。\n\n第二天早上，鱼去寻找食物。忽然，他看见水面上天空飞鸟的倒影。他太想看看鸟了，就鼓起勇气试着跳到河岸上。鱼一纵身跳上了岸。但是在他睁开眼睛之前，他已经喘不过气了。他开始呻吟起来。算他走运，青蛙正好在附近找吃的。\n\n青蛙马上跳到奄奄一息的鱼的身边。他一点也没耽搁，把大鱼拉进池塘里。鱼一进水，立刻苏醒了。他很惊讶，问青蛙发生了什么事。\n\n青蛙微笑着说：“我跟你说过，你不能到陆地上去。不管你是在陆地上还是在水里都没关系，一切都是美好的，美丽的，为什么你不愿意听我的话!”\n\n“可是只呆在这儿我觉得不满意。”鱼继续说。\n\n“你应该满足了，”青蛙劝鱼说：“没有多少生命能像你一样呆在水里。”\n\n鱼笑了，高兴地在水草间游来游去，他认识到他的朋友说的是真的。\n\n\n\n故事4：橘子老虎\n\n秋天，橘子熟了，那黄澄澄的蜜橘挂满枝头，远远望去，就像一个个的小灯笼。一天，一个最大、最沉的橘子，看到同伴被人摘走，伤心地对橘子树说：“妈妈，难道我们橘子生来就应该被人吃掉吗?”\n\n“是啊，孩子，我们的最大愿望就是丰富人类的美好生活。我们身上的果核将会落入泥土，然后新的生命又会破土而出。”\n\n“不，妈妈，我可不愿为他人活着，更不愿被人随意摘取，我要变成一个人见人怕的老虎。”\n\n“孩子，那可不是我们橘子的风格。”\n\n“不嘛!”大橘子纵身一跳，从树上跳到了地面。奇怪的事情发生了：大橘子的身体不断地胀大、胀大，最后圆圆的橘子肚子拉长了，橘皮上竟然浮现出色彩斑斓的花纹来，前面拱出一个脑袋，脑门正中有一个醒目的“王”字，后面露出一条长尾巴来。哈，大橘子竟然变成一只威风凛凛的橘子老虎啦!\n\n橘子老虎非常高兴，她告别妈妈，决定到各地去旅行，让大家见识见识橘子老虎的威风。他翻过一座山冈，看见一只小羊正趴在大树下低声哭泣。他决定吓唬吓唬小羊。他蹑手蹑脚地走上前去，却发现一只大灰狼也在偷偷地逼近小羊。橘子老虎见状忙喊道：“小羊，当心大灰狼!”\n\n小羊一惊，扭头要跑，大灰狼扑上来抓住了小羊。在这千钧一发的时刻，只见橘子老虎一个箭步蹿上前去，对着大灰狼喊道：“大灰狼，快放开他，要不我就撕碎你!”\n\n大灰狼一愣，见一只猛虎向自己扑来，不由两腿直打颤。虽然舍不得到嘴的肥嫩小羊，但这只老虎可不是等闲之辈，只得丢下小羊逃走了。面对橘子老虎，小羊流着眼泪说道：“虎大王，我妈妈得了重病，想吃橘子，您能否等我找到橘子后再吃我呢?”\n\n看看楚楚可怜的小羊，橘子老虎被他爱妈妈的孝心所感动了。他安慰小羊：“别怕，让我帮助你完成心愿。”说着，他便撕开自己的橘子肚皮，掰下一瓣橘子，递给小羊说，“给你妈妈送回去吧。”\n\n小羊感激地说：“您真是天下心眼最好的老虎呀!”\n\n橘子老虎笑了笑，继续往前赶路了。\n\n\n\n故事5：狐狸假扮兽王\n\n很早以前，森林中的百兽过着闲逸、安乐的生活。因没有兽王，便商议决定寻找一个有资格作兽王的动物来领导群兽，于是四处寻觅。一天，有只狐狸跑到一家染衣坊寻找食物，不慎掉进了染缸。它惊恐万分，拼命挣扎，等到爬出染缸时，已是精疲力尽。狐狸再也没有心思寻找食物，落荒而逃。它在河边喝水时，见到水中的倒影，忽然发现自己身上的颜色变得美丽异常，与众不同。狐狸自己知道那是在染缸里染上的。正在这时，寻找兽王的动物们发现了它，惊奇地问它是什么动物?是从什么地方来的?狐狸灵机一动，诈称自己是天帝派来作兽王的。群兽从来没有见到过它这样的动物，又听说是天帝派来的，便生起信心，拥立狐狸为王。\n\n当上兽王的狐狸，得意忘形，作威作福。它不但役使所有的野兽为自己做事，还忘乎所以地让狮子当坐骑，四处巡视游玩。照理说狐狸当了兽王，应该对自己的同类特别关照才是，但这兽王并没有这样做，反而痛恨狐群，百般加以折磨。动物们本以为有兽王领导，生活会更加幸福、快乐，没想到却落得如此痛苦。众狐狸更觉得是飞来的横祸，大惑不解，暗地里对兽王进行观察，它们怀疑这天帝所赐的兽王可能是狐狸装扮的。众狐狸找了个机会，偷偷地询问狮子：“每月十五，月圆之日，兽王是否仍要骑着你去游玩?”狮子说：“不，兽王每月十五都给我放假，它总是单独离去。”群狐说：“我们狐狸因为业力的关系，每到十五日就会昏迷一阵，好一会儿才能恢复。你可以在十五日那天跟踪兽王，看它是不是狐狸所扮?”\n\n等到十五日，兽王照常向远处跑去。狮子便悄悄地跟在后面，到了一个山洞里，果然看见兽王象死尸一样倒在地上，昏迷不醒。狮子这才知道动物们都上当受骗了，尤其是自己，居然被狐狸当坐骑戏弄了这么长的时间，狮子羞怒难当，一跃而上将这只狐狸吞食了……\n\n群兽因为没有好好观察，让一只卑劣的狐狸当了兽王。最后的结果是让群兽都受到了莫大的痛苦，那自作聪明的狐狸也自取灭亡。"
  },
  {
    "path": "pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xmlns=\"http://maven.apache.org/POM/4.0.0\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <groupId>com.ai</groupId>\n    <artifactId>AI-java</artifactId>\n    <packaging>pom</packaging>\n    <version>1.0</version>\n    <modules>\n        <module>ai-common</module>\n        <module>ai-openai</module>\n        <module>ai-spark</module>\n        <module>ai-baidu</module>\n        <module>ai-core</module>\n    </modules>\n    <name>AI-java</name>\n    <description>ai-sdk-java</description>\n\n    <build>\n        <finalName>AI-java</finalName>\n        <plugins>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-surefire-plugin</artifactId>\n                <version>2.12.4</version>\n                <configuration>\n                    <skipTests>true</skipTests>\n                </configuration>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <configuration>\n                    <source>8</source>\n                    <target>8</target>\n                </configuration>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-jar-plugin</artifactId>\n                <version>2.3.1</version>\n                <configuration>\n                    <archive>\n                        <manifest>\n                            <addDefaultImplementationEntries>true</addDefaultImplementationEntries>\n                        </manifest>\n                    </archive>\n                </configuration>\n            </plugin>\n        </plugins>\n    </build>\n\n</project>\n"
  }
]