├── .gitignore ├── LICENSE ├── README.md ├── pom.xml └── src ├── main └── java │ └── com │ └── jeffrey │ └── chatgpt │ ├── IOpenAiApi.java │ ├── common │ └── Constants.java │ ├── domain │ ├── billing │ │ ├── BillingUsage.java │ │ ├── DailyCost.java │ │ ├── LineItem.java │ │ ├── Plan.java │ │ └── Subscription.java │ ├── chat │ │ ├── ChatChoice.java │ │ ├── ChatCompletionRequest.java │ │ ├── ChatCompletionResponse.java │ │ └── Message.java │ ├── edits │ │ ├── EditRequest.java │ │ └── EditResponse.java │ ├── embedd │ │ ├── EmbeddingRequest.java │ │ ├── EmbeddingResponse.java │ │ └── Item.java │ ├── files │ │ ├── DeleteFileResponse.java │ │ ├── File.java │ │ └── UploadFileResponse.java │ ├── images │ │ ├── ImageEditRequest.java │ │ ├── ImageEnum.java │ │ ├── ImageRequest.java │ │ ├── ImageResponse.java │ │ └── Item.java │ ├── other │ │ ├── Choice.java │ │ ├── OpenAiResponse.java │ │ └── Usage.java │ ├── qa │ │ ├── QAChoice.java │ │ ├── QACompletionRequest.java │ │ └── QACompletionResponse.java │ └── whisper │ │ ├── TranscriptionsRequest.java │ │ ├── TranslationsRequest.java │ │ ├── WhisperEnum.java │ │ └── WhisperResponse.java │ ├── interceptor │ └── OpenAiInterceptor.java │ └── session │ ├── Configuration.java │ ├── OpenAiSession.java │ ├── OpenAiSessionFactory.java │ └── defaults │ ├── DefaultOpenAiSession.java │ └── DefaultOpenAiSessionFactory.java └── test └── java └── com └── jeffrey └── chatgpt └── test ├── ApiTest.java ├── ClientTest.java └── HttpClientTest.java /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled class file 2 | *.class 3 | 4 | # Log file 5 | *.log 6 | 7 | # BlueJ files 8 | *.ctxt 9 | 10 | # Mobile Tools for Java (J2ME) 11 | .mtj.tmp/ 12 | 13 | # Package Files # 14 | *.jar 15 | *.war 16 | *.nar 17 | *.ear 18 | *.zip 19 | *.tar.gz 20 | *.rar 21 | 22 | /chatgpt-sdk-java.iml 23 | /target/ 24 | /.idea/ 25 | 26 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Jeffrey You 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # OpenAI_SDK 2 | 3 | ## About 4 | Provides an easy-to-use SDK for Java developers to interact with the APIs of open AI models. 5 | 6 | ## Features 7 | - Rapidly develop products based on the platform, improve development efficiency, and meet fast delivery requirements. 8 | - Concise and easy to understand, code specification requirements, can be used as enterprise code specification. 9 | - The steps to use are very simple, and one line of code realizes the required functions. 10 | - Support multiple proxy platforms, perfectly adapt to various APIs. 11 | - Dynamically expand Max Tokens according to the model 12 | - Rich pre-data verification to avoid direct contact with API 13 | 14 | ## Supported APIs List 15 | - Chat 16 | - Images 17 | - Files 18 | - Audio 19 | - Embeddings 20 | - Billing -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.jeffrey.chatgpt 8 | chatgpt-sdk-java 9 | 1.0-SNAPSHOT 10 | 11 | chatgpt-sdk-java 12 | OpenAI Java SDK, ChatGPT Java SDK 13 | 14 | 15 | 1.8 16 | UTF-8 17 | 1.8 18 | 1.8 19 | 2.9.0 20 | 2.0.6 21 | 22 | 23 | 24 | 25 | org.slf4j 26 | slf4j-api 27 | ${slf4j.version} 28 | 29 | 30 | org.slf4j 31 | slf4j-simple 32 | ${slf4j.version} 33 | 34 | 35 | com.fasterxml.jackson.core 36 | jackson-databind 37 | 2.13.3 38 | 39 | 40 | cn.hutool 41 | hutool-all 42 | 5.8.12 43 | 44 | 45 | com.squareup.okhttp3 46 | okhttp-sse 47 | 3.14.9 48 | 49 | 50 | com.squareup.okhttp3 51 | logging-interceptor 52 | 3.14.9 53 | 54 | 55 | com.squareup.retrofit2 56 | retrofit 57 | ${retrofit2.version} 58 | 59 | 60 | com.squareup.retrofit2 61 | converter-jackson 62 | ${retrofit2.version} 63 | 64 | 65 | com.squareup.retrofit2 66 | adapter-rxjava2 67 | ${retrofit2.version} 68 | 69 | 70 | junit 71 | junit 72 | 4.13.2 73 | test 74 | 75 | 76 | org.jetbrains 77 | annotations 78 | RELEASE 79 | compile 80 | 81 | 82 | com.knuddels 83 | jtokkit 84 | 0.2.0 85 | 86 | 87 | org.projectlombok 88 | lombok 89 | 1.18.24 90 | compile 91 | 92 | 93 | 94 | 95 | chatgpt-sdk-java 96 | 97 | 98 | 99 | org.apache.maven.plugins 100 | maven-surefire-plugin 101 | 2.12.4 102 | 103 | true 104 | 105 | 106 | 107 | org.apache.maven.plugins 108 | maven-compiler-plugin 109 | 110 | 8 111 | 8 112 | 113 | 114 | 115 | 116 | 117 | -------------------------------------------------------------------------------- /src/main/java/com/jeffrey/chatgpt/IOpenAiApi.java: -------------------------------------------------------------------------------- 1 | package com.jeffrey.chatgpt; 2 | 3 | import com.jeffrey.chatgpt.domain.chat.ChatCompletionRequest; 4 | import com.jeffrey.chatgpt.domain.chat.ChatCompletionResponse; 5 | import com.jeffrey.chatgpt.domain.qa.QACompletionRequest; 6 | import com.jeffrey.chatgpt.domain.qa.QACompletionResponse; 7 | import com.jeffrey.chatgpt.domain.billing.BillingUsage; 8 | import com.jeffrey.chatgpt.domain.billing.Subscription; 9 | import com.jeffrey.chatgpt.domain.edits.EditRequest; 10 | import com.jeffrey.chatgpt.domain.edits.EditResponse; 11 | import com.jeffrey.chatgpt.domain.embedd.EmbeddingRequest; 12 | import com.jeffrey.chatgpt.domain.embedd.EmbeddingResponse; 13 | import com.jeffrey.chatgpt.domain.files.DeleteFileResponse; 14 | import com.jeffrey.chatgpt.domain.files.UploadFileResponse; 15 | import com.jeffrey.chatgpt.domain.images.ImageRequest; 16 | import com.jeffrey.chatgpt.domain.images.ImageResponse; 17 | import com.jeffrey.chatgpt.domain.other.OpenAiResponse; 18 | import com.jeffrey.chatgpt.domain.whisper.WhisperResponse; 19 | 20 | 21 | import io.reactivex.Single; 22 | import okhttp3.MultipartBody; 23 | import okhttp3.RequestBody; 24 | import okhttp3.ResponseBody; 25 | import retrofit2.http.*; 26 | 27 | 28 | import java.io.File; 29 | import java.time.LocalDate; 30 | import java.util.Map; 31 | 32 | /** 33 | * @author Jeffrey You 34 | * @description ChatGPT API:https://platform.openai.com/playground 35 | */ 36 | public interface IOpenAiApi { 37 | String v1_completions = "v1/completions"; 38 | String v1_chat_completions = "v1/chat/completions"; 39 | 40 | 41 | /** 42 | * Default GPT-3.5 Chat Model 43 | * 44 | * @param chatCompletionRequest Request Body 45 | * @return Return Result 46 | */ 47 | @POST("v1/chat/completions") 48 | Single completions(@Body ChatCompletionRequest chatCompletionRequest); 49 | 50 | /** 51 | * Q & A Model 52 | * 53 | * @param qaCompletionRequest Request Body 54 | * @return Return Result 55 | */ 56 | @POST("v1/completions") 57 | Single completions(@Body QACompletionRequest qaCompletionRequest); 58 | 59 | 60 | 61 | /** 62 | * Edit Text 63 | * 64 | * @param editRequest Request Body 65 | * @return Return Result 66 | */ 67 | @POST("v1/edits") 68 | Single edits(@Body EditRequest editRequest); 69 | 70 | /** 71 | * Generate Picture 72 | * 73 | * @param imageRequest Request Body 74 | * @return Return Result 75 | */ 76 | @POST("v1/images/generations") 77 | Single genImages(@Body ImageRequest imageRequest); 78 | 79 | 80 | /** 81 | * Modify Picture 82 | * 83 | * @param image The image to edit 84 | * @param mask Optional mask to apply to the image 85 | * @param requestBodyMap Request Body 86 | * @return Return Result 87 | */ 88 | @Multipart 89 | @POST("v1/images/edits") 90 | Single editImages(@Part MultipartBody.Part image, @Part MultipartBody.Part mask, @PartMap Map requestBodyMap); 91 | 92 | /** 93 | * Embedding 94 | * 95 | * @param embeddingRequest Request Body 96 | * @return Return Result 97 | */ 98 | @POST("v1/embeddings") 99 | Single embeddings(@Body EmbeddingRequest embeddingRequest); 100 | 101 | /** 102 | * Get Files 103 | * @return Return Result 104 | */ 105 | @GET("v1/files") 106 | Single> files(); 107 | 108 | /** 109 | * Upload File 110 | * 111 | * @param file file 112 | * @param purpose "fine-tune" 113 | * @return Return Result 114 | */ 115 | @Multipart 116 | @POST("v1/files") 117 | Single uploadFile(@Part MultipartBody.Part file, @Part("purpose") RequestBody purpose); 118 | 119 | /** 120 | * Delete File 121 | * 122 | * @param fileId File ID 123 | * @return Return Result 124 | */ 125 | @DELETE("v1/files/{file_id}") 126 | Single deleteFile(@Path("file_id") String fileId); 127 | 128 | /** 129 | * Search File 130 | * 131 | * @param fileId File ID 132 | * @return Return Result 133 | */ 134 | @GET("v1/files/{file_id}") 135 | Single retrieveFile(@Path("file_id") String fileId); 136 | 137 | /** 138 | * Search File Content 139 | * 140 | * @param fileId File ID 141 | * @return Return Result 142 | */ 143 | @Streaming 144 | @GET("v1/files/{file_id}/content") 145 | Single retrieveFileContent(@Path("file_id") String fileId); 146 | 147 | /** 148 | * Audio Transcription 149 | * 150 | * @param file Audio file 151 | * @param requestBodyMap Request Body 152 | * @return Return Result 153 | */ 154 | @Multipart 155 | @POST("v1/audio/transcriptions") 156 | Single speed2TextTranscriptions(@Part MultipartBody.Part file, @PartMap() Map requestBodyMap); 157 | 158 | /** 159 | * Audio Translation 160 | * 161 | * @param file Audio file 162 | * @param requestBodyMap Request Body 163 | * @return Return Result 164 | */ 165 | @Multipart 166 | @POST("v1/audio/translations") 167 | Single speed2TextTranslations(@Part MultipartBody.Part file, @PartMap() Map requestBodyMap); 168 | 169 | /** 170 | * Billing Subscription 171 | * 172 | * @return Return Result 173 | */ 174 | @GET("v1/dashboard/billing/subscription") 175 | Single subscription(); 176 | 177 | /** 178 | * Usage 179 | * 180 | * @param starDate Start Time 181 | * @param endDate End Time 182 | * @return Return Result 183 | */ 184 | @GET("v1/dashboard/billing/usage") 185 | Single billingUsage(@Query("start_date") LocalDate starDate, @Query("end_date") LocalDate endDate); 186 | 187 | 188 | } 189 | -------------------------------------------------------------------------------- /src/main/java/com/jeffrey/chatgpt/common/Constants.java: -------------------------------------------------------------------------------- 1 | package com.jeffrey.chatgpt.common; 2 | 3 | /** 4 | * @author Jeffrey You 5 | * @description Role Definition 6 | */ 7 | public class Constants { 8 | 9 | public enum Role { 10 | 11 | SYSTEM("system"), 12 | USER("user"), 13 | ASSISTANT("assistant"), 14 | ; 15 | 16 | private String code; 17 | 18 | Role(String code) { 19 | this.code = code; 20 | } 21 | 22 | public String getCode() { 23 | return code; 24 | } 25 | 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/com/jeffrey/chatgpt/domain/billing/BillingUsage.java: -------------------------------------------------------------------------------- 1 | package com.jeffrey.chatgpt.domain.billing; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | import lombok.Data; 5 | 6 | import java.math.BigDecimal; 7 | import java.util.List; 8 | 9 | /** 10 | * @author Jeffrey You 11 | * @description Billing Usage 12 | */ 13 | @Data 14 | public class BillingUsage { 15 | 16 | @JsonProperty("object") 17 | private String object; 18 | @JsonProperty("daily_costs") 19 | private List dailyCosts; 20 | @JsonProperty("total_usage") 21 | private BigDecimal totalUsage; 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/com/jeffrey/chatgpt/domain/billing/DailyCost.java: -------------------------------------------------------------------------------- 1 | package com.jeffrey.chatgpt.domain.billing; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | import lombok.Data; 5 | 6 | import java.util.List; 7 | 8 | /** 9 | * @author Jeffrey You 10 | * @description Daily Cost 11 | */ 12 | @Data 13 | public class DailyCost { 14 | @JsonProperty("timestamp") 15 | private long timestamp; 16 | @JsonProperty("line_items") 17 | private List lineItems; 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/jeffrey/chatgpt/domain/billing/LineItem.java: -------------------------------------------------------------------------------- 1 | package com.jeffrey.chatgpt.domain.billing; 2 | 3 | import lombok.Data; 4 | 5 | import java.math.BigDecimal; 6 | 7 | /** 8 | * @author Jeffrey You 9 | * @description Billing 10 | */ 11 | @Data 12 | public class LineItem { 13 | private String name; 14 | private BigDecimal cost; 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/jeffrey/chatgpt/domain/billing/Plan.java: -------------------------------------------------------------------------------- 1 | package com.jeffrey.chatgpt.domain.billing; 2 | 3 | import lombok.Data; 4 | 5 | /** 6 | * @author Jeffrey You 7 | * @description Billing Plan 8 | */ 9 | @Data 10 | public class Plan { 11 | private String title; 12 | private String id; 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/jeffrey/chatgpt/domain/billing/Subscription.java: -------------------------------------------------------------------------------- 1 | package com.jeffrey.chatgpt.domain.billing; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | import lombok.Data; 5 | 6 | import java.io.Serializable; 7 | 8 | /** 9 | * @author Jeffrey You 10 | * @description Billing Subscription 11 | */ 12 | @Data 13 | public class Subscription implements Serializable { 14 | 15 | @JsonProperty("object") 16 | private String object; 17 | @JsonProperty("has_payment_method") 18 | private boolean hasPaymentMethod; 19 | @JsonProperty("canceled") 20 | private boolean canceled; 21 | @JsonProperty("canceled_at") 22 | private Object canceledAt; 23 | @JsonProperty("delinquent") 24 | private Object delinquent; 25 | @JsonProperty("access_until") 26 | private long accessUntil; 27 | @JsonProperty("soft_limit") 28 | private long softLimit; 29 | @JsonProperty("hard_limit") 30 | private long hardLimit; 31 | @JsonProperty("system_hard_limit") 32 | private long systemHardLimit; 33 | @JsonProperty("soft_limit_usd") 34 | private double softLimitUsd; 35 | @JsonProperty("hard_limit_usd") 36 | private double hardLimitUsd; 37 | @JsonProperty("system_hard_limit_usd") 38 | private double systemHardLimitUsd; 39 | @JsonProperty("plan") 40 | private Plan plan; 41 | @JsonProperty("account_name") 42 | private String accountName; 43 | @JsonProperty("po_number") 44 | private Object poNumber; 45 | @JsonProperty("billing_email") 46 | private Object billingEmail; 47 | @JsonProperty("tax_ids") 48 | private Object taxIds; 49 | @JsonProperty("billing_address") 50 | private Object billingAddress; 51 | @JsonProperty("business_address") 52 | private Object businessAddress; 53 | 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/com/jeffrey/chatgpt/domain/chat/ChatChoice.java: -------------------------------------------------------------------------------- 1 | package com.jeffrey.chatgpt.domain.chat; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | import lombok.Data; 5 | 6 | import java.io.Serializable; 7 | 8 | /** 9 | * @author Jeffrey You 10 | * @description Chat Info 11 | */ 12 | @Data 13 | public class ChatChoice implements Serializable { 14 | 15 | private long index; 16 | /** stream = true, return type is delta */ 17 | @JsonProperty("delta") 18 | private Message delta; 19 | /** stream = false, return type is message */ 20 | @JsonProperty("message") 21 | private Message message; 22 | @JsonProperty("finish_reason") 23 | private String finishReason; 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/com/jeffrey/chatgpt/domain/chat/ChatCompletionRequest.java: -------------------------------------------------------------------------------- 1 | package com.jeffrey.chatgpt.domain.chat; 2 | 3 | import com.fasterxml.jackson.annotation.JsonInclude; 4 | import com.fasterxml.jackson.annotation.JsonProperty; 5 | import lombok.*; 6 | import lombok.extern.slf4j.Slf4j; 7 | 8 | import java.io.Serializable; 9 | import java.util.List; 10 | import java.util.Map; 11 | 12 | /** 13 | * @author Jeffrey You 14 | * @description Chat Request 15 | */ 16 | @Data 17 | @Builder 18 | @Slf4j 19 | @JsonInclude(JsonInclude.Include.NON_NULL) 20 | @NoArgsConstructor 21 | @AllArgsConstructor 22 | public class ChatCompletionRequest implements Serializable { 23 | 24 | /** Default Model */ 25 | private String model = Model.GPT_3_5_TURBO.getCode(); 26 | /** Message */ 27 | private List messages; 28 | 29 | private double temperature = 0.2; 30 | 31 | @JsonProperty("top_p") 32 | private Double topP = 1d; 33 | 34 | private Integer n = 1; 35 | 36 | private boolean stream = false; 37 | 38 | private List stop; 39 | 40 | @JsonProperty("max_tokens") 41 | private Integer maxTokens = 2048; 42 | 43 | @JsonProperty("frequency_penalty") 44 | private double frequencyPenalty = 0; 45 | 46 | @JsonProperty("presence_penalty") 47 | private double presencePenalty = 0; 48 | 49 | @JsonProperty("logit_bias") 50 | private Map logitBias; 51 | 52 | private String user; 53 | 54 | @Getter 55 | @AllArgsConstructor 56 | public enum Model { 57 | /** gpt-3.5-turbo */ 58 | GPT_3_5_TURBO("gpt-3.5-turbo"), 59 | /** GPT4.0 */ 60 | GPT_4("gpt-4"), 61 | /** GPT4.0 large context */ 62 | GPT_4_32K("gpt-4-32k"), 63 | ; 64 | private String code; 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /src/main/java/com/jeffrey/chatgpt/domain/chat/ChatCompletionResponse.java: -------------------------------------------------------------------------------- 1 | package com.jeffrey.chatgpt.domain.chat; 2 | 3 | import com.jeffrey.chatgpt.domain.other.Usage; 4 | import lombok.Data; 5 | 6 | import java.io.Serializable; 7 | import java.util.List; 8 | 9 | /** 10 | * @author Jeffrey You 11 | * @description Chat Response 12 | */ 13 | @Data 14 | public class ChatCompletionResponse implements Serializable { 15 | 16 | /** ID */ 17 | private String id; 18 | /** 对象 */ 19 | private String object; 20 | /** 模型 */ 21 | private String model; 22 | /** 对话 */ 23 | private List choices; 24 | /** 创建 */ 25 | private long created; 26 | /** 耗材 */ 27 | private Usage usage; 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/com/jeffrey/chatgpt/domain/chat/Message.java: -------------------------------------------------------------------------------- 1 | package com.jeffrey.chatgpt.domain.chat; 2 | 3 | import com.jeffrey.chatgpt.common.Constants; 4 | import com.fasterxml.jackson.annotation.JsonInclude; 5 | import lombok.Data; 6 | 7 | import java.io.Serializable; 8 | 9 | /** 10 | * @author Jeffrey You 11 | * @description Message 12 | */ 13 | @Data 14 | @JsonInclude(JsonInclude.Include.NON_NULL) 15 | public class Message implements Serializable { 16 | 17 | private String role; 18 | private String content; 19 | private String name; 20 | 21 | public Message() { 22 | } 23 | 24 | private Message(Builder builder) { 25 | this.role = builder.role; 26 | this.content = builder.content; 27 | this.name = builder.name; 28 | } 29 | 30 | public static Builder builder() { 31 | return new Builder(); 32 | } 33 | 34 | /** 35 | * 建造者模式 36 | */ 37 | public static final class Builder { 38 | 39 | private String role; 40 | private String content; 41 | private String name; 42 | 43 | public Builder() { 44 | } 45 | 46 | public Builder role(Constants.Role role) { 47 | this.role = role.getCode(); 48 | return this; 49 | } 50 | 51 | public Builder content(String content) { 52 | this.content = content; 53 | return this; 54 | } 55 | 56 | public Builder name(String name) { 57 | this.name = name; 58 | return this; 59 | } 60 | 61 | public Message build() { 62 | return new Message(this); 63 | } 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /src/main/java/com/jeffrey/chatgpt/domain/edits/EditRequest.java: -------------------------------------------------------------------------------- 1 | package com.jeffrey.chatgpt.domain.edits; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | import lombok.*; 5 | import lombok.extern.slf4j.Slf4j; 6 | 7 | import java.io.Serializable; 8 | 9 | /** 10 | * @author Jeffrey You 11 | * @description Edit 12 | */ 13 | @Slf4j 14 | @Getter 15 | @Builder 16 | @NoArgsConstructor(force = true) 17 | @AllArgsConstructor 18 | public class EditRequest implements Serializable { 19 | 20 | @NonNull 21 | private String model = Model.CODE_DAVINCI_EDIT_001.getCode(); 22 | @NonNull 23 | private String input; 24 | @NonNull 25 | private String instruction; 26 | @Builder.Default 27 | private double temperature = 0.2; 28 | @JsonProperty("top_p") 29 | private Double topP = 1d; 30 | private Integer n = 1; 31 | 32 | @Getter 33 | @AllArgsConstructor 34 | public enum Model{ 35 | /** text-davinci-edit-001 */ 36 | TEXT_DAVINCI_EDIT_001("text-davinci-edit-001"), 37 | /** code-davinci-edit-001 */ 38 | CODE_DAVINCI_EDIT_001("code-davinci-edit-001"), 39 | ; 40 | private String code; 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/com/jeffrey/chatgpt/domain/edits/EditResponse.java: -------------------------------------------------------------------------------- 1 | package com.jeffrey.chatgpt.domain.edits; 2 | 3 | import com.jeffrey.chatgpt.domain.other.Choice; 4 | import com.jeffrey.chatgpt.domain.other.Usage; 5 | import lombok.Data; 6 | 7 | import java.io.Serializable; 8 | 9 | /** 10 | * @author Jeffrey You 11 | * @description Edit 12 | */ 13 | @Data 14 | public class EditResponse implements Serializable { 15 | 16 | private String id; 17 | private String object; 18 | private String model; 19 | private Choice[] choices; 20 | private long created; 21 | private Usage usage; 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/com/jeffrey/chatgpt/domain/embedd/EmbeddingRequest.java: -------------------------------------------------------------------------------- 1 | package com.jeffrey.chatgpt.domain.embedd; 2 | 3 | import com.fasterxml.jackson.annotation.JsonInclude; 4 | import lombok.*; 5 | import lombok.extern.slf4j.Slf4j; 6 | 7 | import java.io.Serializable; 8 | import java.util.List; 9 | 10 | /** 11 | * @author Jeffrey You 12 | * @description Creates a variation of a given image. 13 | */ 14 | @Slf4j 15 | @Getter 16 | @Builder 17 | @JsonInclude(JsonInclude.Include.NON_NULL) 18 | @NoArgsConstructor(force = true) 19 | @AllArgsConstructor 20 | public class EmbeddingRequest implements Serializable { 21 | 22 | @NonNull 23 | @Builder.Default 24 | private String model = Model.TEXT_EMBEDDING_ADA_002.getCode(); 25 | @NonNull 26 | private List input; 27 | @Setter 28 | private String user; 29 | 30 | @Getter 31 | @AllArgsConstructor 32 | public enum Model { 33 | TEXT_EMBEDDING_ADA_002("text-embedding-ada-002"), 34 | ; 35 | private String code; 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/com/jeffrey/chatgpt/domain/embedd/EmbeddingResponse.java: -------------------------------------------------------------------------------- 1 | package com.jeffrey.chatgpt.domain.embedd; 2 | 3 | import com.jeffrey.chatgpt.domain.other.Usage; 4 | import lombok.Data; 5 | 6 | import java.io.Serializable; 7 | import java.util.List; 8 | 9 | /** 10 | * @author Jeffrey You 11 | * @description Embedding Response 12 | */ 13 | @Data 14 | public class EmbeddingResponse implements Serializable { 15 | 16 | private String object; 17 | private List data; 18 | private String model; 19 | private Usage usage; 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/com/jeffrey/chatgpt/domain/embedd/Item.java: -------------------------------------------------------------------------------- 1 | package com.jeffrey.chatgpt.domain.embedd; 2 | 3 | import lombok.Data; 4 | 5 | import java.io.Serializable; 6 | import java.math.BigDecimal; 7 | import java.util.List; 8 | 9 | /** 10 | * @author Jeffrey You 11 | * @description Item 12 | */ 13 | @Data 14 | public class Item implements Serializable { 15 | 16 | private String object; 17 | private List embedding; 18 | private Integer index; 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/com/jeffrey/chatgpt/domain/files/DeleteFileResponse.java: -------------------------------------------------------------------------------- 1 | package com.jeffrey.chatgpt.domain.files; 2 | 3 | import lombok.Data; 4 | 5 | import java.io.Serializable; 6 | 7 | /** 8 | * @author Jeffrey You 9 | * @description Delete File Response 10 | */ 11 | @Data 12 | public class DeleteFileResponse implements Serializable { 13 | 14 | private String id; 15 | private String object; 16 | private boolean deleted; 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/jeffrey/chatgpt/domain/files/File.java: -------------------------------------------------------------------------------- 1 | package com.jeffrey.chatgpt.domain.files; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | import lombok.Data; 5 | 6 | import java.io.Serializable; 7 | 8 | /** 9 | * @author Jeffrey You 10 | * @description File 11 | */ 12 | @Data 13 | public class File implements Serializable { 14 | 15 | private String id; 16 | private String object; 17 | private long bytes; 18 | private long created_at; 19 | private String filename; 20 | private String purpose; 21 | private String status; 22 | @JsonProperty("status_details") 23 | private String statusDetails; 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/com/jeffrey/chatgpt/domain/files/UploadFileResponse.java: -------------------------------------------------------------------------------- 1 | package com.jeffrey.chatgpt.domain.files; 2 | 3 | import lombok.Data; 4 | 5 | import java.io.Serializable; 6 | 7 | /** 8 | * @author Jeffrey You 9 | * @description Upload File Response 10 | */ 11 | @Data 12 | public class UploadFileResponse extends File implements Serializable { 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/jeffrey/chatgpt/domain/images/ImageEditRequest.java: -------------------------------------------------------------------------------- 1 | package com.jeffrey.chatgpt.domain.images; 2 | 3 | import com.fasterxml.jackson.annotation.JsonInclude; 4 | import com.fasterxml.jackson.annotation.JsonProperty; 5 | import lombok.*; 6 | import lombok.extern.slf4j.Slf4j; 7 | 8 | import java.io.Serializable; 9 | 10 | /** 11 | * @author Jeffrey You 12 | * @description Upload Image 13 | */ 14 | @Slf4j 15 | @Getter 16 | @Builder 17 | @JsonInclude(JsonInclude.Include.NON_NULL) 18 | @NoArgsConstructor(force = true) 19 | @AllArgsConstructor 20 | public class ImageEditRequest extends ImageEnum implements Serializable { 21 | 22 | @NonNull 23 | private String prompt; 24 | @Builder.Default 25 | private Integer n = 1; 26 | @Builder.Default 27 | private String size = Size.size_256.getCode(); 28 | @JsonProperty("response_format") 29 | @Builder.Default 30 | private String responseFormat = ResponseFormat.URL.getCode(); 31 | @Setter 32 | private String user; 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/com/jeffrey/chatgpt/domain/images/ImageEnum.java: -------------------------------------------------------------------------------- 1 | package com.jeffrey.chatgpt.domain.images; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Getter; 5 | 6 | /** 7 | * @author Jeffrey You 8 | * @description Enum Image 9 | */ 10 | public class ImageEnum { 11 | 12 | @Getter 13 | @AllArgsConstructor 14 | public enum Size { 15 | size_256("256x256"), 16 | size_512("512x512"), 17 | size_1024("1024x1024"), 18 | ; 19 | private String code; 20 | } 21 | 22 | @Getter 23 | @AllArgsConstructor 24 | public enum ResponseFormat { 25 | URL("url"), 26 | B64_JSON("b64_json"), 27 | ; 28 | private String code; 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/com/jeffrey/chatgpt/domain/images/ImageRequest.java: -------------------------------------------------------------------------------- 1 | package com.jeffrey.chatgpt.domain.images; 2 | 3 | import com.fasterxml.jackson.annotation.JsonInclude; 4 | import com.fasterxml.jackson.annotation.JsonProperty; 5 | import lombok.*; 6 | import lombok.extern.slf4j.Slf4j; 7 | 8 | import java.io.Serializable; 9 | 10 | /** 11 | * @author Jeffrey You 12 | * @description Request Image 13 | */ 14 | @Slf4j 15 | @Getter 16 | @Builder 17 | @JsonInclude(JsonInclude.Include.NON_NULL) 18 | @NoArgsConstructor(force = true) 19 | @AllArgsConstructor 20 | public class ImageRequest extends ImageEnum implements Serializable { 21 | 22 | @NonNull 23 | private String prompt; 24 | @Builder.Default 25 | private Integer n = 1; 26 | @Builder.Default 27 | private String size = Size.size_256.getCode(); 28 | @JsonProperty("response_format") 29 | @Builder.Default 30 | private String responseFormat = ResponseFormat.URL.getCode(); 31 | @Setter 32 | private String user; 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/com/jeffrey/chatgpt/domain/images/ImageResponse.java: -------------------------------------------------------------------------------- 1 | package com.jeffrey.chatgpt.domain.images; 2 | 3 | import lombok.Data; 4 | 5 | import java.io.Serializable; 6 | import java.util.List; 7 | 8 | /** 9 | * @author Jeffrey You 10 | * @description Image Response 11 | */ 12 | @Data 13 | public class ImageResponse implements Serializable { 14 | private List data; 15 | private long created; 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/jeffrey/chatgpt/domain/images/Item.java: -------------------------------------------------------------------------------- 1 | package com.jeffrey.chatgpt.domain.images; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | import lombok.Data; 5 | 6 | import java.io.Serializable; 7 | 8 | /** 9 | * @author Jeffrey You 10 | * @description Image 11 | */ 12 | @Data 13 | public class Item implements Serializable { 14 | 15 | private String url; 16 | @JsonProperty("b64_json") 17 | private String b64Json; 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/jeffrey/chatgpt/domain/other/Choice.java: -------------------------------------------------------------------------------- 1 | package com.jeffrey.chatgpt.domain.other; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | import lombok.Data; 5 | 6 | import java.io.Serializable; 7 | 8 | /** 9 | * @author Jeffrey You 10 | * @description Choice 11 | */ 12 | @Data 13 | public class Choice implements Serializable { 14 | 15 | private long index; 16 | private String text; 17 | private Object logprobs; 18 | @JsonProperty("finish_reason") 19 | private String finishReason; 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/com/jeffrey/chatgpt/domain/other/OpenAiResponse.java: -------------------------------------------------------------------------------- 1 | package com.jeffrey.chatgpt.domain.other; 2 | 3 | import lombok.Data; 4 | 5 | import java.io.Serializable; 6 | import java.util.List; 7 | 8 | /** 9 | * @author Jeffrey You 10 | * @description Response 11 | */ 12 | @Data 13 | public class OpenAiResponse implements Serializable { 14 | 15 | private String object; 16 | private List data; 17 | private Error error; 18 | 19 | 20 | @Data 21 | public class Error { 22 | private String message; 23 | private String type; 24 | private String param; 25 | private String code; 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/com/jeffrey/chatgpt/domain/other/Usage.java: -------------------------------------------------------------------------------- 1 | package com.jeffrey.chatgpt.domain.other; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | 5 | import java.io.Serializable; 6 | 7 | /** 8 | * @author Jeffrey You 9 | * @description Uasge 10 | */ 11 | public class Usage implements Serializable { 12 | 13 | @JsonProperty("prompt_tokens") 14 | private long promptTokens; 15 | @JsonProperty("completion_tokens") 16 | private long completionTokens; 17 | @JsonProperty("total_tokens") 18 | private long totalTokens; 19 | 20 | public long getPromptTokens() { 21 | return promptTokens; 22 | } 23 | 24 | public void setPromptTokens(long promptTokens) { 25 | this.promptTokens = promptTokens; 26 | } 27 | 28 | public long getCompletionTokens() { 29 | return completionTokens; 30 | } 31 | 32 | public void setCompletionTokens(long completionTokens) { 33 | this.completionTokens = completionTokens; 34 | } 35 | 36 | public long getTotalTokens() { 37 | return totalTokens; 38 | } 39 | 40 | public void setTotalTokens(long totalTokens) { 41 | this.totalTokens = totalTokens; 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/com/jeffrey/chatgpt/domain/qa/QAChoice.java: -------------------------------------------------------------------------------- 1 | package com.jeffrey.chatgpt.domain.qa; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | import lombok.Data; 5 | 6 | import java.io.Serializable; 7 | 8 | /** 9 | * @author Jeffrey You 10 | * @description Q & A Choice 11 | */ 12 | @Data 13 | public class QAChoice implements Serializable { 14 | 15 | private long index; 16 | private String text; 17 | private Object logprobs; 18 | @JsonProperty("finish_reason") 19 | private String finishReason; 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/com/jeffrey/chatgpt/domain/qa/QACompletionRequest.java: -------------------------------------------------------------------------------- 1 | package com.jeffrey.chatgpt.domain.qa; 2 | 3 | import com.fasterxml.jackson.annotation.JsonInclude; 4 | import com.fasterxml.jackson.annotation.JsonProperty; 5 | import lombok.*; 6 | import lombok.extern.slf4j.Slf4j; 7 | 8 | import java.io.Serializable; 9 | import java.util.List; 10 | import java.util.Map; 11 | 12 | /** 13 | * @author Jeffrey You 14 | * @description Q & A Completion Request 15 | */ 16 | @Data 17 | @Builder 18 | @Slf4j 19 | @JsonInclude(JsonInclude.Include.NON_NULL) 20 | @NoArgsConstructor 21 | @AllArgsConstructor 22 | public class QACompletionRequest implements Serializable { 23 | 24 | @NonNull 25 | @Builder.Default 26 | private String model = Model.TEXT_DAVINCI_003.getCode(); 27 | @NonNull 28 | private String prompt; 29 | private String suffix; 30 | private double temperature = 0.2; 31 | @JsonProperty("top_p") 32 | private Double topP = 1d; 33 | private Integer n = 1; 34 | private boolean stream = false; 35 | private List stop; 36 | @JsonProperty("max_tokens") 37 | private Integer maxTokens = 2048; 38 | @Builder.Default 39 | private boolean echo = false; 40 | @JsonProperty("frequency_penalty") 41 | private double frequencyPenalty = 0; 42 | @JsonProperty("presence_penalty") 43 | private double presencePenalty = 0; 44 | @JsonProperty("best_of") 45 | @Builder.Default 46 | private Integer bestOf = 1; 47 | private Integer logprobs; 48 | @JsonProperty("logit_bias") 49 | private Map logitBias; 50 | private String user; 51 | 52 | @Getter 53 | @AllArgsConstructor 54 | public enum Model { 55 | TEXT_DAVINCI_003("text-davinci-003"), 56 | TEXT_DAVINCI_002("text-davinci-002"), 57 | DAVINCI("davinci"), 58 | ; 59 | private String code; 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/com/jeffrey/chatgpt/domain/qa/QACompletionResponse.java: -------------------------------------------------------------------------------- 1 | package com.jeffrey.chatgpt.domain.qa; 2 | 3 | import com.jeffrey.chatgpt.domain.other.Usage; 4 | import lombok.Data; 5 | 6 | import java.io.Serializable; 7 | 8 | /** 9 | * @author Jeffrey You 10 | * @description Q & A Completion Response 11 | */ 12 | @Data 13 | public class QACompletionResponse implements Serializable { 14 | 15 | private String id; 16 | private String object; 17 | private String model; 18 | private QAChoice[] choices; 19 | private long created; 20 | private Usage usage; 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/com/jeffrey/chatgpt/domain/whisper/TranscriptionsRequest.java: -------------------------------------------------------------------------------- 1 | package com.jeffrey.chatgpt.domain.whisper; 2 | 3 | import com.fasterxml.jackson.annotation.JsonInclude; 4 | import com.fasterxml.jackson.annotation.JsonProperty; 5 | import lombok.*; 6 | import lombok.experimental.FieldNameConstants; 7 | 8 | /** 9 | * @author Jeffrey You 10 | * @description Transcriptions Request 11 | */ 12 | @Data 13 | @Builder 14 | @NoArgsConstructor 15 | @AllArgsConstructor 16 | @FieldNameConstants 17 | @JsonInclude(JsonInclude.Include.NON_NULL) 18 | public class TranscriptionsRequest { 19 | 20 | @Builder.Default 21 | private String model = WhisperEnum.Model.WHISPER_1.getCode(); 22 | private String prompt; 23 | @JsonProperty("response_format") 24 | @Builder.Default 25 | private String responseFormat = WhisperEnum.ResponseFormat.JSON.getCode(); 26 | private double temperature = 0.2; 27 | 28 | private String language; 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/com/jeffrey/chatgpt/domain/whisper/TranslationsRequest.java: -------------------------------------------------------------------------------- 1 | package com.jeffrey.chatgpt.domain.whisper; 2 | 3 | import com.fasterxml.jackson.annotation.JsonInclude; 4 | import com.fasterxml.jackson.annotation.JsonProperty; 5 | import lombok.AllArgsConstructor; 6 | import lombok.Builder; 7 | import lombok.Data; 8 | import lombok.NoArgsConstructor; 9 | import lombok.experimental.FieldNameConstants; 10 | 11 | import java.io.Serializable; 12 | 13 | /** 14 | * @author Jeffrey You 15 | * @description Translations Request 16 | */ 17 | @Data 18 | @Builder 19 | @NoArgsConstructor 20 | @AllArgsConstructor 21 | @FieldNameConstants 22 | @JsonInclude(JsonInclude.Include.NON_NULL) 23 | public class TranslationsRequest implements Serializable { 24 | 25 | @Builder.Default 26 | private String model = WhisperEnum.Model.WHISPER_1.getCode(); 27 | private String prompt; 28 | @JsonProperty("response_format") 29 | @Builder.Default 30 | private String responseFormat = WhisperEnum.ResponseFormat.JSON.getCode(); 31 | private double temperature = 0.2; 32 | 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/com/jeffrey/chatgpt/domain/whisper/WhisperEnum.java: -------------------------------------------------------------------------------- 1 | package com.jeffrey.chatgpt.domain.whisper; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.Getter; 6 | 7 | import java.io.Serializable; 8 | 9 | /** 10 | * @author Jeffrey You 11 | * @description Audio to Text 12 | */ 13 | @Data 14 | public class WhisperEnum implements Serializable { 15 | 16 | @Getter 17 | @AllArgsConstructor 18 | public enum Model { 19 | WHISPER_1("whisper-1"), 20 | ; 21 | private String code; 22 | } 23 | 24 | @Getter 25 | @AllArgsConstructor 26 | public enum ResponseFormat { 27 | JSON("json"), 28 | TEXT("text"), 29 | SRT("srt"), 30 | VERBOSE_JSON("verbose_json"), 31 | VTT("vtt"), 32 | ; 33 | private String code; 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/com/jeffrey/chatgpt/domain/whisper/WhisperResponse.java: -------------------------------------------------------------------------------- 1 | package com.jeffrey.chatgpt.domain.whisper; 2 | 3 | import lombok.Data; 4 | 5 | import java.io.Serializable; 6 | 7 | /** 8 | * @author Jeffrey You 9 | * @description Whisper Response 10 | */ 11 | @Data 12 | public class WhisperResponse implements Serializable { 13 | private String text; 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/com/jeffrey/chatgpt/interceptor/OpenAiInterceptor.java: -------------------------------------------------------------------------------- 1 | package com.jeffrey.chatgpt.interceptor; 2 | 3 | import cn.hutool.http.ContentType; 4 | import cn.hutool.http.Header; 5 | import okhttp3.HttpUrl; 6 | import okhttp3.Interceptor; 7 | import okhttp3.Request; 8 | import okhttp3.Response; 9 | import org.jetbrains.annotations.NotNull; 10 | 11 | import java.io.IOException; 12 | 13 | /** 14 | * @author Jeffrey You 15 | * @description Custom Interceptor 16 | */ 17 | public class OpenAiInterceptor implements Interceptor { 18 | 19 | /** OpenAi apiKey */ 20 | private String apiKey; 21 | /** Auth Token If needed */ 22 | private String authToken; 23 | 24 | public OpenAiInterceptor(String apiKey, String authToken) { 25 | this.apiKey = apiKey; 26 | this.authToken = authToken; 27 | } 28 | 29 | @NotNull 30 | @Override 31 | public Response intercept(Chain chain) throws IOException { 32 | return chain.proceed(this.auth(apiKey, chain.request())); 33 | } 34 | 35 | private Request auth(String apiKey, Request original) { 36 | // Add token if needed 37 | 38 | // HttpUrl url = original.url().newBuilder() 39 | // .addQueryParameter("token", authToken) 40 | // .build(); 41 | 42 | // Set up request. 43 | // return original.newBuilder() 44 | // .url(url) 45 | // .header(Header.AUTHORIZATION.getValue(), "Bearer " + apiKey) 46 | // .header(Header.CONTENT_TYPE.getValue(), ContentType.JSON.getValue()) 47 | // .method(original.method(), original.body()) 48 | // .build(); 49 | 50 | // Add API Key 51 | return original.newBuilder() 52 | .header("Authorization", "Bearer " + apiKey) 53 | .build(); 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /src/main/java/com/jeffrey/chatgpt/session/Configuration.java: -------------------------------------------------------------------------------- 1 | package com.jeffrey.chatgpt.session; 2 | 3 | import com.jeffrey.chatgpt.IOpenAiApi; 4 | import lombok.*; 5 | import lombok.extern.slf4j.Slf4j; 6 | import okhttp3.OkHttpClient; 7 | import okhttp3.sse.EventSource; 8 | import okhttp3.sse.EventSources; 9 | import org.jetbrains.annotations.NotNull; 10 | 11 | /** 12 | * @author Jeffrey You 13 | * @description Configuration 14 | */ 15 | @Slf4j 16 | @Data 17 | @NoArgsConstructor 18 | @AllArgsConstructor 19 | public class Configuration { 20 | 21 | @Getter 22 | @Setter 23 | private IOpenAiApi openAiApi; 24 | 25 | 26 | @Getter 27 | @NotNull 28 | private String apiKey; 29 | 30 | @Getter 31 | private String apiHost; 32 | 33 | @Getter 34 | private String authToken; 35 | 36 | @Getter 37 | @Setter 38 | private OkHttpClient okHttpClient; 39 | 40 | public EventSource.Factory createRequestFactory() { 41 | return EventSources.createFactory(okHttpClient); 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/com/jeffrey/chatgpt/session/OpenAiSession.java: -------------------------------------------------------------------------------- 1 | package com.jeffrey.chatgpt.session; 2 | 3 | import com.jeffrey.chatgpt.domain.chat.ChatCompletionRequest; 4 | import com.jeffrey.chatgpt.domain.chat.ChatCompletionResponse; 5 | import com.jeffrey.chatgpt.domain.qa.QACompletionRequest; 6 | import com.jeffrey.chatgpt.domain.qa.QACompletionResponse; 7 | import com.fasterxml.jackson.core.JsonProcessingException; 8 | import okhttp3.sse.EventSource; 9 | import okhttp3.sse.EventSourceListener; 10 | 11 | /** 12 | * @author Jeffrey You 13 | * @description OpenAI Session 14 | */ 15 | public interface OpenAiSession { 16 | 17 | /** 18 | * Q & A Model 19 | * @param qaCompletionRequest Request Body 20 | * @return Return Result 21 | */ 22 | QACompletionResponse completions(QACompletionRequest qaCompletionRequest); 23 | 24 | /** 25 | * Q & A Model String Input 26 | * @param question Request Body 27 | * @return Return Result 28 | */ 29 | QACompletionResponse completions(String question); 30 | 31 | /** 32 | * Q & A Model Stream 33 | * @param qaCompletionRequest Request Body 34 | * @param eventSourceListener EventSourceListener 35 | */ 36 | EventSource completions(QACompletionRequest qaCompletionRequest, EventSourceListener eventSourceListener) throws JsonProcessingException; 37 | 38 | 39 | /** 40 | * Chat Model GPT-3.5/4.0 41 | * @param chatCompletionRequest Request Body 42 | * @return Return Result 43 | */ 44 | ChatCompletionResponse completions(ChatCompletionRequest chatCompletionRequest); 45 | 46 | /** 47 | * Chat Model GPT-3.5/4.0 Stream 48 | * @param chatCompletionRequest Request Body 49 | * @param eventSourceListener EventSourceListener 50 | * @return Return Result 51 | */ 52 | EventSource chatCompletions(ChatCompletionRequest chatCompletionRequest, EventSourceListener eventSourceListener) throws JsonProcessingException; 53 | 54 | 55 | 56 | } 57 | -------------------------------------------------------------------------------- /src/main/java/com/jeffrey/chatgpt/session/OpenAiSessionFactory.java: -------------------------------------------------------------------------------- 1 | package com.jeffrey.chatgpt.session; 2 | 3 | /** 4 | * @author Jeffrey You 5 | * @description OpenAI Session Factory 6 | */ 7 | public interface OpenAiSessionFactory { 8 | 9 | OpenAiSession openSession(); 10 | 11 | } -------------------------------------------------------------------------------- /src/main/java/com/jeffrey/chatgpt/session/defaults/DefaultOpenAiSession.java: -------------------------------------------------------------------------------- 1 | package com.jeffrey.chatgpt.session.defaults; 2 | 3 | import com.jeffrey.chatgpt.domain.chat.ChatCompletionRequest; 4 | import com.jeffrey.chatgpt.domain.chat.ChatCompletionResponse; 5 | import com.jeffrey.chatgpt.domain.qa.QACompletionRequest; 6 | import com.jeffrey.chatgpt.domain.qa.QACompletionResponse; 7 | import com.jeffrey.chatgpt.session.Configuration; 8 | import com.jeffrey.chatgpt.IOpenAiApi; 9 | import com.jeffrey.chatgpt.session.OpenAiSession; 10 | import cn.hutool.http.ContentType; 11 | import com.fasterxml.jackson.core.JsonProcessingException; 12 | import com.fasterxml.jackson.databind.ObjectMapper; 13 | import io.reactivex.Single; 14 | import okhttp3.MediaType; 15 | import okhttp3.Request; 16 | import okhttp3.RequestBody; 17 | import okhttp3.sse.EventSource; 18 | import okhttp3.sse.EventSourceListener; 19 | 20 | /** 21 | * @author Jeffrey You 22 | * @description OpenAI API Session 23 | */ 24 | public class DefaultOpenAiSession implements OpenAiSession { 25 | 26 | private final Configuration configuration; 27 | 28 | private final IOpenAiApi openAiApi; 29 | 30 | private final EventSource.Factory factory; 31 | 32 | 33 | 34 | public DefaultOpenAiSession(Configuration configuration) { 35 | this.configuration = configuration; 36 | this.openAiApi = configuration.getOpenAiApi(); 37 | this.factory = configuration.createRequestFactory(); 38 | } 39 | 40 | @Override 41 | public QACompletionResponse completions(QACompletionRequest qaCompletionRequest) { 42 | return this.openAiApi.completions(qaCompletionRequest).blockingGet(); 43 | } 44 | 45 | @Override 46 | public QACompletionResponse completions(String question) { 47 | QACompletionRequest request = QACompletionRequest 48 | .builder() 49 | .prompt(question) 50 | .build(); 51 | Single completions = this.openAiApi.completions(request); 52 | return completions.blockingGet(); 53 | } 54 | 55 | @Override 56 | public EventSource completions(QACompletionRequest qaCompletionRequest, EventSourceListener eventSourceListener) throws JsonProcessingException { 57 | if (!qaCompletionRequest.isStream()){ 58 | throw new RuntimeException("illegal parameter stream is false!"); 59 | } 60 | 61 | Request request = new Request.Builder() 62 | .url(configuration.getApiHost().concat(IOpenAiApi.v1_completions)) 63 | .post(RequestBody.create(MediaType.parse(ContentType.JSON.getValue()), new ObjectMapper().writeValueAsString(qaCompletionRequest))) 64 | .build(); 65 | 66 | return factory.newEventSource(request, eventSourceListener); 67 | 68 | } 69 | 70 | @Override 71 | public ChatCompletionResponse completions(ChatCompletionRequest chatCompletionRequest) { 72 | return this.openAiApi.completions(chatCompletionRequest).blockingGet(); 73 | } 74 | 75 | @Override 76 | public EventSource chatCompletions(ChatCompletionRequest chatCompletionRequest, EventSourceListener eventSourceListener) throws JsonProcessingException { 77 | if (!chatCompletionRequest.isStream()){ 78 | throw new RuntimeException("illegal parameter stream is false!"); 79 | } 80 | 81 | Request request = new Request.Builder() 82 | .url(configuration.getApiHost().concat(IOpenAiApi.v1_chat_completions)) 83 | .post(RequestBody.create(MediaType.parse(ContentType.JSON.getValue()), new ObjectMapper().writeValueAsString(chatCompletionRequest))) 84 | .build(); 85 | 86 | return factory.newEventSource(request, eventSourceListener); 87 | } 88 | 89 | } -------------------------------------------------------------------------------- /src/main/java/com/jeffrey/chatgpt/session/defaults/DefaultOpenAiSessionFactory.java: -------------------------------------------------------------------------------- 1 | package com.jeffrey.chatgpt.session.defaults; 2 | 3 | import com.jeffrey.chatgpt.IOpenAiApi; 4 | import com.jeffrey.chatgpt.interceptor.OpenAiInterceptor; 5 | import com.jeffrey.chatgpt.session.Configuration; 6 | import com.jeffrey.chatgpt.session.OpenAiSession; 7 | import com.jeffrey.chatgpt.session.OpenAiSessionFactory; 8 | import okhttp3.OkHttpClient; 9 | import okhttp3.logging.HttpLoggingInterceptor; 10 | import retrofit2.Retrofit; 11 | import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory; 12 | import retrofit2.converter.jackson.JacksonConverterFactory; 13 | 14 | import java.util.concurrent.TimeUnit; 15 | 16 | /** 17 | * @author Jeffrey You 18 | * @description OpenAI API Factory 19 | */ 20 | public class DefaultOpenAiSessionFactory implements OpenAiSessionFactory { 21 | 22 | private final Configuration configuration; 23 | 24 | public DefaultOpenAiSessionFactory(Configuration configuration) { 25 | this.configuration = configuration; 26 | } 27 | 28 | @Override 29 | public OpenAiSession openSession() { 30 | // 1. 日志配置 31 | HttpLoggingInterceptor httpLoggingInterceptor = new HttpLoggingInterceptor(); 32 | httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BASIC); 33 | 34 | // 2. 开启 Http 客户端 35 | OkHttpClient okHttpClient = new OkHttpClient 36 | .Builder() 37 | .addInterceptor(httpLoggingInterceptor) 38 | .addInterceptor(new OpenAiInterceptor(configuration.getApiKey(), configuration.getAuthToken())) 39 | .connectTimeout(450, TimeUnit.SECONDS) 40 | .writeTimeout(450, TimeUnit.SECONDS) 41 | .readTimeout(450, TimeUnit.SECONDS) 42 | .build(); 43 | configuration.setOkHttpClient(okHttpClient); 44 | 45 | 46 | // 3. 创建 API 服务 47 | IOpenAiApi openAiApi = new Retrofit.Builder() 48 | .baseUrl(configuration.getApiHost()) 49 | .client(okHttpClient) 50 | .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) 51 | .addConverterFactory(JacksonConverterFactory.create()) 52 | .build().create(IOpenAiApi.class); 53 | 54 | configuration.setOpenAiApi(openAiApi); 55 | 56 | return new DefaultOpenAiSession(configuration); 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /src/test/java/com/jeffrey/chatgpt/test/ApiTest.java: -------------------------------------------------------------------------------- 1 | package com.jeffrey.chatgpt.test; 2 | 3 | import com.jeffrey.chatgpt.common.Constants; 4 | import com.jeffrey.chatgpt.domain.chat.ChatCompletionRequest; 5 | import com.jeffrey.chatgpt.domain.chat.ChatCompletionResponse; 6 | import com.jeffrey.chatgpt.domain.chat.Message; 7 | import com.jeffrey.chatgpt.domain.qa.QACompletionRequest; 8 | import com.jeffrey.chatgpt.domain.qa.QACompletionResponse; 9 | import com.jeffrey.chatgpt.session.Configuration; 10 | import com.jeffrey.chatgpt.session.OpenAiSession; 11 | import com.jeffrey.chatgpt.session.OpenAiSessionFactory; 12 | import com.jeffrey.chatgpt.session.defaults.DefaultOpenAiSessionFactory; 13 | import com.fasterxml.jackson.core.JsonProcessingException; 14 | import com.fasterxml.jackson.databind.ObjectMapper; 15 | import lombok.extern.slf4j.Slf4j; 16 | import okhttp3.sse.EventSource; 17 | import okhttp3.sse.EventSourceListener; 18 | import org.junit.Before; 19 | import org.junit.Test; 20 | 21 | import java.util.Collections; 22 | import java.util.concurrent.CountDownLatch; 23 | 24 | /** 25 | * @author Jeffrey You 26 | * @description API Test 27 | */ 28 | @Slf4j 29 | public class ApiTest { 30 | 31 | private OpenAiSession openAiSession; 32 | 33 | @Before 34 | public void test_OpenAiSessionFactory() { 35 | // 1. Configuration 36 | Configuration configuration = new Configuration(); 37 | configuration.setApiHost("https://api.openai.com/"); 38 | configuration.setApiKey("Please input your API Key"); 39 | // 2. SessionFactory 40 | OpenAiSessionFactory factory = new DefaultOpenAiSessionFactory(configuration); 41 | // 3. Open Session 42 | this.openAiSession = factory.openSession(); 43 | } 44 | 45 | /** 46 | * Q & A Model 47 | */ 48 | @Test 49 | public void test_qa_completions() throws JsonProcessingException { 50 | QACompletionResponse response01 = openAiSession.completions("Write Bubble Sort in Java"); 51 | log.info("Test Result:{}", new ObjectMapper().writeValueAsString(response01.getChoices())); 52 | } 53 | 54 | /** 55 | * Q & A Model Stream 56 | */ 57 | @Test 58 | public void test_qa_completions_stream() throws JsonProcessingException, InterruptedException { 59 | // 1. Create Request 60 | QACompletionRequest request = QACompletionRequest 61 | .builder() 62 | .prompt("Write Bubble Sort in Java") 63 | .stream(true) 64 | .build(); 65 | 66 | for (int i = 0; i < 1; i++) { 67 | // 2. Send Request 68 | EventSource eventSource = openAiSession.completions(request, new EventSourceListener() { 69 | @Override 70 | public void onEvent(EventSource eventSource, String id, String type, String data) { 71 | log.info("Test Result:{}", data); 72 | } 73 | }); 74 | } 75 | // Wait Finish 76 | new CountDownLatch(1).await(); 77 | } 78 | 79 | 80 | /** 81 | * Chat Model 82 | */ 83 | @Test 84 | public void test_chat_completions() { 85 | // 1. Create Request 86 | ChatCompletionRequest chatCompletion = ChatCompletionRequest 87 | .builder() 88 | .messages(Collections.singletonList(Message.builder().role(Constants.Role.USER).content("Write Bubble Sort in Java").build())) 89 | .model(ChatCompletionRequest.Model.GPT_3_5_TURBO.getCode()) 90 | .build(); 91 | // 2. Send Request 92 | ChatCompletionResponse chatCompletionResponse = openAiSession.completions(chatCompletion); 93 | // 3. Print Result 94 | chatCompletionResponse.getChoices().forEach(e -> { 95 | log.info("Test Result:{}", e.getMessage()); 96 | }); 97 | } 98 | 99 | /** 100 | * Chat Model Stream 101 | */ 102 | @Test 103 | public void test_chat_completions_stream() throws JsonProcessingException, InterruptedException { 104 | // 1. Create Request 105 | ChatCompletionRequest chatCompletion = ChatCompletionRequest 106 | .builder() 107 | .stream(true) 108 | .messages(Collections.singletonList(Message.builder().role(Constants.Role.USER).content("Write Bubble Sort in Java").build())) 109 | .model(ChatCompletionRequest.Model.GPT_3_5_TURBO.getCode()) 110 | .build(); 111 | // 2. Send Request 112 | EventSource eventSource = openAiSession.chatCompletions(chatCompletion, new EventSourceListener() { 113 | @Override 114 | public void onEvent(EventSource eventSource, String id, String type, String data) { 115 | log.info("Test Result:{}", data); 116 | } 117 | }); 118 | // 3. Wait Finish 119 | new CountDownLatch(1).await(); 120 | } 121 | 122 | 123 | } 124 | -------------------------------------------------------------------------------- /src/test/java/com/jeffrey/chatgpt/test/ClientTest.java: -------------------------------------------------------------------------------- 1 | package com.jeffrey.chatgpt.test; 2 | 3 | import com.jeffrey.chatgpt.common.Constants; 4 | import com.jeffrey.chatgpt.domain.chat.ChatCompletionRequest; 5 | import com.jeffrey.chatgpt.domain.chat.ChatCompletionResponse; 6 | import com.jeffrey.chatgpt.domain.chat.Message; 7 | import com.jeffrey.chatgpt.session.Configuration; 8 | import com.jeffrey.chatgpt.session.OpenAiSession; 9 | import com.jeffrey.chatgpt.session.OpenAiSessionFactory; 10 | import com.jeffrey.chatgpt.session.defaults.DefaultOpenAiSessionFactory; 11 | 12 | import java.util.ArrayList; 13 | import java.util.Scanner; 14 | 15 | /** 16 | * @author Jeffrey You 17 | * @description Client Test 18 | */ 19 | public class ClientTest { 20 | 21 | public static void main(String[] args) throws InterruptedException { 22 | Configuration configuration = new Configuration(); 23 | configuration.setApiHost("https://api.openai.com/"); 24 | configuration.setApiKey("Please enter your API key here"); 25 | OpenAiSessionFactory factory = new DefaultOpenAiSessionFactory(configuration); 26 | OpenAiSession openAiSession = factory.openSession(); 27 | 28 | System.out.println("Please enter the question:"); 29 | 30 | ChatCompletionRequest chatCompletion = ChatCompletionRequest 31 | .builder() 32 | .messages(new ArrayList<>()) 33 | .model(ChatCompletionRequest.Model.GPT_3_5_TURBO.getCode()) 34 | .user("testUser01") 35 | .build(); 36 | 37 | Scanner scanner = new Scanner(System.in); 38 | while (scanner.hasNextLine()) { 39 | String text = scanner.nextLine(); 40 | chatCompletion.getMessages().add(Message.builder().role(Constants.Role.USER).content(text).build()); 41 | ChatCompletionResponse chatCompletionResponse = openAiSession.completions(chatCompletion); 42 | chatCompletion.getMessages().add(Message.builder().role(Constants.Role.USER).content(chatCompletionResponse.getChoices().get(0).getMessage().getContent()).build()); 43 | 44 | System.out.println(chatCompletionResponse.getChoices().get(0).getMessage().getContent()); 45 | System.out.println("Please enter your question:"); 46 | } 47 | 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /src/test/java/com/jeffrey/chatgpt/test/HttpClientTest.java: -------------------------------------------------------------------------------- 1 | package com.jeffrey.chatgpt.test; 2 | 3 | import com.jeffrey.chatgpt.IOpenAiApi; 4 | import com.jeffrey.chatgpt.common.Constants; 5 | import com.jeffrey.chatgpt.domain.chat.ChatCompletionRequest; 6 | import com.jeffrey.chatgpt.domain.chat.ChatCompletionResponse; 7 | import com.jeffrey.chatgpt.domain.chat.Message; 8 | import cn.hutool.http.ContentType; 9 | import cn.hutool.http.Header; 10 | import com.fasterxml.jackson.core.JsonProcessingException; 11 | import com.fasterxml.jackson.databind.ObjectMapper; 12 | import io.reactivex.Single; 13 | import lombok.extern.slf4j.Slf4j; 14 | import okhttp3.*; 15 | import okhttp3.logging.HttpLoggingInterceptor; 16 | import okhttp3.sse.EventSource; 17 | import okhttp3.sse.EventSourceListener; 18 | import okhttp3.sse.EventSources; 19 | import org.junit.Test; 20 | import retrofit2.Retrofit; 21 | import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory; 22 | import retrofit2.converter.jackson.JacksonConverterFactory; 23 | 24 | import java.util.Collections; 25 | import java.util.concurrent.CountDownLatch; 26 | 27 | /** 28 | * @author Jeffrey You 29 | * @description Http Client Test 30 | */ 31 | @Slf4j 32 | public class HttpClientTest { 33 | 34 | private String openAiKey = "Please enter your API key here"; 35 | 36 | @Test 37 | public void test_normal() { 38 | HttpLoggingInterceptor httpLoggingInterceptor = new HttpLoggingInterceptor(); 39 | httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY); 40 | 41 | OkHttpClient okHttpClient = new OkHttpClient 42 | .Builder() 43 | .addInterceptor(httpLoggingInterceptor) 44 | .addInterceptor(chain -> { 45 | Request original = chain.request(); 46 | 47 | HttpUrl url = original.url(); 48 | Request request = original.newBuilder() 49 | .url(url) 50 | .header(Header.AUTHORIZATION.getValue(), "Bearer " + this.openAiKey) 51 | .header(Header.CONTENT_TYPE.getValue(), ContentType.JSON.getValue()) 52 | .method(original.method(), original.body()) 53 | .build(); 54 | return chain.proceed(request); 55 | }) 56 | .build(); 57 | 58 | IOpenAiApi openAiApi = new Retrofit.Builder() 59 | .baseUrl("https://api.openai.com/") 60 | .client(okHttpClient) 61 | .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) 62 | .addConverterFactory(JacksonConverterFactory.create()) 63 | .build().create(IOpenAiApi.class); 64 | 65 | Message message = Message.builder().role(Constants.Role.USER).content("Hello").build(); 66 | ChatCompletionRequest chatCompletion = ChatCompletionRequest 67 | .builder() 68 | .messages(Collections.singletonList(message)) 69 | .model(ChatCompletionRequest.Model.GPT_3_5_TURBO.getCode()) 70 | .build(); 71 | 72 | Single chatCompletionResponseSingle = openAiApi.completions(chatCompletion); 73 | ChatCompletionResponse chatCompletionResponse = chatCompletionResponseSingle.blockingGet(); 74 | chatCompletionResponse.getChoices().forEach(e -> { 75 | System.out.println(e.getMessage()); 76 | }); 77 | } 78 | 79 | @Test 80 | public void test_client_stream() throws JsonProcessingException, InterruptedException { 81 | HttpLoggingInterceptor httpLoggingInterceptor = new HttpLoggingInterceptor(); 82 | httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY); 83 | 84 | OkHttpClient okHttpClient = new OkHttpClient 85 | .Builder() 86 | .addInterceptor(httpLoggingInterceptor) 87 | .addInterceptor(chain -> { 88 | Request original = chain.request(); 89 | 90 | 91 | HttpUrl url = original.url(); 92 | Request request = original.newBuilder() 93 | .url(url) 94 | .header(Header.AUTHORIZATION.getValue(), "Bearer " + this.openAiKey) 95 | .header(Header.CONTENT_TYPE.getValue(), ContentType.JSON.getValue()) 96 | .method(original.method(), original.body()) 97 | .build(); 98 | return chain.proceed(request); 99 | }) 100 | .build(); 101 | 102 | Message message = Message.builder().role(Constants.Role.USER).content("Hello").build(); 103 | ChatCompletionRequest chatCompletion = ChatCompletionRequest 104 | .builder() 105 | .messages(Collections.singletonList(message)) 106 | .model(ChatCompletionRequest.Model.GPT_3_5_TURBO.getCode()) 107 | .stream(true) 108 | .build(); 109 | 110 | EventSource.Factory factory = EventSources.createFactory(okHttpClient); 111 | String requestBody = new ObjectMapper().writeValueAsString(chatCompletion); 112 | 113 | Request request = new Request.Builder() 114 | .url("https://api.openai.com/v1/chat/completions") 115 | .post(RequestBody.create(MediaType.parse(ContentType.JSON.getValue()), requestBody)) 116 | .build(); 117 | 118 | EventSource eventSource = factory.newEventSource(request, new EventSourceListener() { 119 | @Override 120 | public void onEvent(EventSource eventSource, String id, String type, String data) { 121 | log.info("Test Result:{}", data); 122 | } 123 | }); 124 | 125 | new CountDownLatch(1).await(); 126 | 127 | } 128 | 129 | } 130 | --------------------------------------------------------------------------------