├── .github └── workflows │ ├── release-ossrh.yml │ └── style-check.yml ├── .gitignore ├── .mvn ├── jvm.config └── maven.config ├── LICENSE ├── README.md ├── docs └── images │ ├── EventSource不支持POST的替代办法.png │ ├── SSE-Stream-Chat.png │ └── WeChat-MP.png ├── pom.xml └── src ├── main ├── java │ └── com │ │ └── lzhpo │ │ └── chatgpt │ │ ├── DefaultOpenAiClient.java │ │ ├── OpenAiAutoConfiguration.java │ │ ├── OpenAiClient.java │ │ ├── OpenAiConstant.java │ │ ├── apikey │ │ ├── OpenAiKey.java │ │ ├── OpenAiKeyProvider.java │ │ └── OpenAiKeyWrapper.java │ │ ├── entity │ │ ├── CommonConfig.java │ │ ├── CommonUsage.java │ │ ├── audio │ │ │ ├── CreateAudioRequest.java │ │ │ └── CreateAudioResponse.java │ │ ├── billing │ │ │ ├── CreditGrants.java │ │ │ ├── CreditGrantsData.java │ │ │ ├── CreditGrantsResponse.java │ │ │ ├── SubscriptionAddress.java │ │ │ ├── SubscriptionPlan.java │ │ │ ├── SubscriptionResponse.java │ │ │ ├── UsageDailyCosts.java │ │ │ ├── UsageLineItems.java │ │ │ └── UsageResponse.java │ │ ├── chat │ │ │ ├── ChatCompletionChoice.java │ │ │ ├── ChatCompletionFunction.java │ │ │ ├── ChatCompletionFunctionCall.java │ │ │ ├── ChatCompletionMessage.java │ │ │ ├── ChatCompletionParameter.java │ │ │ ├── ChatCompletionRequest.java │ │ │ └── ChatCompletionResponse.java │ │ ├── completions │ │ │ ├── CompletionChoice.java │ │ │ ├── CompletionRequest.java │ │ │ └── CompletionResponse.java │ │ ├── edit │ │ │ ├── EditChoice.java │ │ │ ├── EditRequest.java │ │ │ └── EditResponse.java │ │ ├── embeddings │ │ │ ├── EmbeddingData.java │ │ │ ├── EmbeddingRequest.java │ │ │ └── EmbeddingResponse.java │ │ ├── files │ │ │ ├── DeleteFileResponse.java │ │ │ ├── ListFileData.java │ │ │ ├── ListFileResponse.java │ │ │ ├── RetrieveFileResponse.java │ │ │ └── UploadFileResponse.java │ │ ├── finetunes │ │ │ ├── CancelFineTuneEvent.java │ │ │ ├── CancelFineTuneResponse.java │ │ │ ├── CreateFineTuneEvents.java │ │ │ ├── CreateFineTuneRequest.java │ │ │ ├── CreateFineTuneResponse.java │ │ │ ├── DeleteFineTuneModelResponse.java │ │ │ ├── FineTuneEvent.java │ │ │ ├── FineTuneFiles.java │ │ │ ├── Hyperparams.java │ │ │ ├── ListFineTuneData.java │ │ │ ├── ListFineTuneEventData.java │ │ │ ├── ListFineTuneEventResponse.java │ │ │ ├── ListFineTuneResponse.java │ │ │ └── RetrieveFineTuneResponse.java │ │ ├── image │ │ │ ├── CreateImageRequest.java │ │ │ ├── CreateImageResponse.java │ │ │ ├── CreateImageResponseFormat.java │ │ │ ├── CreateImageSize.java │ │ │ ├── CreateImageUrl.java │ │ │ └── CreateImageVariationRequest.java │ │ ├── model │ │ │ ├── ListModelsResponse.java │ │ │ ├── ModelPermission.java │ │ │ └── RetrieveModelResponse.java │ │ ├── moderations │ │ │ ├── ModerationCategory.java │ │ │ ├── ModerationCategoryScore.java │ │ │ ├── ModerationRequest.java │ │ │ ├── ModerationResponse.java │ │ │ └── ModerationResult.java │ │ └── users │ │ │ ├── UserData.java │ │ │ ├── UserInfo.java │ │ │ ├── UserMembers.java │ │ │ └── UserResponse.java │ │ ├── exception │ │ ├── InvalidedKeyEvent.java │ │ ├── NoAvailableKeyEvent.java │ │ ├── OpenAiError.java │ │ ├── OpenAiErrorCode.java │ │ ├── OpenAiErrorDetail.java │ │ ├── OpenAiErrorInterceptor.java │ │ └── OpenAiException.java │ │ ├── properties │ │ ├── OpenAiProperties.java │ │ ├── OpenAiProxy.java │ │ └── OpenAiUrl.java │ │ ├── sse │ │ ├── AbstractEventSourceListener.java │ │ ├── CountDownLatchEventSourceListener.java │ │ ├── SseEventSourceListener.java │ │ └── WebSocketEventSourceListener.java │ │ └── utils │ │ ├── JsonUtils.java │ │ └── TokenUtils.java └── resources │ └── META-INF │ ├── spring.factories │ └── spring │ └── org.springframework.boot.autoconfigure.AutoConfiguration.imports └── test ├── java └── com │ └── lzhpo │ └── chatgpt │ ├── InnerOpenAiKeyProvider.java │ ├── OpenAiClientTest.java │ ├── OpenAiCountTokensTest.java │ ├── OpenAiEventListener.java │ ├── OpenAiKeyProviderTest.java │ ├── OpenAiTestApplication.java │ ├── OpenAiTestController.java │ └── OpenAiWebSocketTest.java └── resources ├── application.yml ├── static ├── css │ └── style.css ├── js │ └── chat.js └── lib │ └── layui │ ├── css │ ├── layui.css │ └── modules │ │ ├── code.css │ │ ├── laydate │ │ └── default │ │ │ └── laydate.css │ │ └── layer │ │ └── default │ │ ├── icon-ext.png │ │ ├── icon.png │ │ ├── layer.css │ │ ├── loading-0.gif │ │ ├── loading-1.gif │ │ └── loading-2.gif │ ├── font │ ├── iconfont.eot │ ├── iconfont.svg │ ├── iconfont.ttf │ ├── iconfont.woff │ └── iconfont.woff2 │ └── layui.js └── templates ├── chat.html ├── sse-stream-chat.html └── websocket-stream-chat.html /.github/workflows/release-ossrh.yml: -------------------------------------------------------------------------------- 1 | name: Release ossrh 2 | 3 | on: 4 | release: 5 | types: [released] 6 | 7 | jobs: 8 | build: 9 | runs-on: ubuntu-latest 10 | name: Release ossrh jobs 11 | 12 | steps: 13 | - uses: actions/checkout@v3 14 | 15 | - name: Set up Apache Maven Central 16 | uses: actions/setup-java@v3 17 | with: 18 | java-version: '8' 19 | distribution: 'adopt' 20 | server-id: ossrh 21 | server-username: MAVEN_USERNAME 22 | server-password: MAVEN_CENTRAL_TOKEN 23 | gpg-private-key: ${{ secrets.GPG_PRIVATE_KEY }} 24 | gpg-passphrase: MAVEN_GPG_PASSPHRASE 25 | 26 | - name: Execute style check 27 | run: mvn spotless:check 28 | 29 | - name: Release to Apache Maven Central 30 | run: mvn clean deploy -Prelease-ossrh 31 | env: 32 | MAVEN_USERNAME: ${{ secrets.OSSRH_USERNAME }} 33 | MAVEN_CENTRAL_TOKEN: ${{ secrets.OSSRH_TOKEN }} 34 | MAVEN_GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }} -------------------------------------------------------------------------------- /.github/workflows/style-check.yml: -------------------------------------------------------------------------------- 1 | name: Style check 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | jobs: 10 | compile: 11 | runs-on: ubuntu-latest 12 | name: Style check jobs 13 | 14 | steps: 15 | - uses: actions/checkout@v3 16 | 17 | - name: Set up JDK 18 | uses: actions/setup-java@v3 19 | with: 20 | java-version: '8' 21 | distribution: 'adopt' 22 | 23 | - name: Execute style check 24 | run: mvn spotless:check 25 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ### Java compile ### 2 | target/ 3 | 4 | ### flatten-maven-plugin ### 5 | *.flattened-pom.xml 6 | 7 | ### IntelliJ IDEA ### 8 | .idea 9 | *.iws 10 | *.iml 11 | *.ipr -------------------------------------------------------------------------------- /.mvn/jvm.config: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzhpo/chatgpt-spring-boot-starter/5a165cc3aa02cc327b81aba4210c3c086cf336f7/.mvn/jvm.config -------------------------------------------------------------------------------- /.mvn/maven.config: -------------------------------------------------------------------------------- 1 | -Drevision=1.1.2 2 | -DskipTests=true 3 | -T=2C -------------------------------------------------------------------------------- /docs/images/EventSource不支持POST的替代办法.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzhpo/chatgpt-spring-boot-starter/5a165cc3aa02cc327b81aba4210c3c086cf336f7/docs/images/EventSource不支持POST的替代办法.png -------------------------------------------------------------------------------- /docs/images/SSE-Stream-Chat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzhpo/chatgpt-spring-boot-starter/5a165cc3aa02cc327b81aba4210c3c086cf336f7/docs/images/SSE-Stream-Chat.png -------------------------------------------------------------------------------- /docs/images/WeChat-MP.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzhpo/chatgpt-spring-boot-starter/5a165cc3aa02cc327b81aba4210c3c086cf336f7/docs/images/WeChat-MP.png -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.7.18 9 | 10 | 11 | 12 | com.lzhpo 13 | chatgpt-spring-boot-starter 14 | ${revision} 15 | chatgpt-spring-boot-starter 16 | chatgpt-spring-boot-starter 17 | 18 | 19 | master 20 | https://github.com/lzhpo/chatgpt-spring-boot-starter 21 | http://www.lzhpo.com 22 | https://github.com/lzhpo/chatgpt-spring-boot-starter.git 23 | 24 | 25 | 26 | 27 | Apache License, Version 2.0 28 | https://www.apache.org/licenses/LICENSE-2.0 29 | 30 | 31 | 32 | 33 | 34 | lzhpo 35 | lzhpo1024@gmail.com 36 | 37 | 38 | 39 | 40 | ossrh 41 | UTF-8 42 | UTF-8 43 | 1.8 44 | 2.30.0 45 | 1.1.0 46 | 3.1.0 47 | 3.3.0 48 | 3.5.0 49 | 1.5.0 50 | 5.8.28 51 | 4.12.0 52 | 1.0.0 53 | 54 | 55 | 56 | 57 | org.springframework.boot 58 | spring-boot-starter-web 59 | 60 | 61 | 62 | org.springframework.boot 63 | spring-boot-configuration-processor 64 | true 65 | 66 | 67 | 68 | org.springframework.boot 69 | spring-boot-starter-validation 70 | 71 | 72 | 73 | org.projectlombok 74 | lombok 75 | true 76 | 77 | 78 | 79 | org.springframework.boot 80 | spring-boot-starter-test 81 | test 82 | 83 | 84 | 85 | org.springframework.boot 86 | spring-boot-starter-thymeleaf 87 | test 88 | 89 | 90 | 91 | org.springframework.boot 92 | spring-boot-starter-websocket 93 | 94 | 95 | 96 | cn.hutool 97 | hutool-all 98 | ${hutool.version} 99 | 100 | 101 | 102 | com.squareup.okhttp3 103 | okhttp 104 | ${okhttp.version} 105 | 106 | 107 | 108 | com.squareup.okhttp3 109 | okhttp-sse 110 | ${okhttp.version} 111 | 112 | 113 | 114 | com.knuddels 115 | jtokkit 116 | ${jtokkit.version} 117 | 118 | 119 | 120 | 121 | 122 | 123 | org.codehaus.mojo 124 | flatten-maven-plugin 125 | ${flatten-maven-plugin} 126 | 127 | 128 | true 129 | resolveCiFriendliesOnly 130 | 131 | 132 | 133 | flatten 134 | process-resources 135 | 136 | flatten 137 | 138 | 139 | 140 | flatten.clean 141 | clean 142 | 143 | clean 144 | 145 | 146 | 147 | 148 | 149 | 150 | com.diffplug.spotless 151 | spotless-maven-plugin 152 | ${spotless-plugin.version} 153 | 154 | 155 | 156 | 157 | ${palantirJavaFormat.version} 158 | 159 | 160 | 161 | 162 | 163 | 164 | check 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | release-ossrh 175 | 176 | 177 | 178 | 179 | org.apache.maven.plugins 180 | maven-source-plugin 181 | ${maven.source.version} 182 | 183 | 184 | package 185 | 186 | jar-no-fork 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | org.apache.maven.plugins 195 | maven-javadoc-plugin 196 | ${maven.javadoc.version} 197 | 198 | 199 | package 200 | 201 | jar 202 | 203 | 204 | zh_CN 205 | UTF-8 206 | UTF-8 207 | none 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | org.apache.maven.plugins 216 | maven-gpg-plugin 217 | ${maven.gpg.version} 218 | 219 | 220 | sign-artifacts 221 | verify 222 | 223 | sign 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | ${server.id} 234 | https://s01.oss.sonatype.org/content/repositories/snapshots 235 | 236 | 237 | ${server.id} 238 | https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/ 239 | 240 | 241 | 242 | 243 | 244 | -------------------------------------------------------------------------------- /src/main/java/com/lzhpo/chatgpt/OpenAiAutoConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.lzhpo.chatgpt; 2 | 3 | import cn.hutool.core.util.StrUtil; 4 | import com.lzhpo.chatgpt.apikey.OpenAiKeyProvider; 5 | import com.lzhpo.chatgpt.apikey.OpenAiKeyWrapper; 6 | import com.lzhpo.chatgpt.exception.OpenAiErrorInterceptor; 7 | import com.lzhpo.chatgpt.properties.OpenAiProperties; 8 | import java.net.InetSocketAddress; 9 | import java.net.Proxy; 10 | import java.util.List; 11 | import java.util.Optional; 12 | import lombok.RequiredArgsConstructor; 13 | import okhttp3.Credentials; 14 | import okhttp3.Interceptor; 15 | import okhttp3.OkHttpClient; 16 | import org.springframework.beans.factory.ObjectProvider; 17 | import org.springframework.boot.autoconfigure.AutoConfiguration; 18 | import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; 19 | import org.springframework.boot.context.properties.EnableConfigurationProperties; 20 | import org.springframework.boot.context.properties.PropertyMapper; 21 | import org.springframework.context.annotation.Bean; 22 | import org.springframework.web.util.DefaultUriBuilderFactory; 23 | import org.springframework.web.util.UriTemplateHandler; 24 | 25 | @AutoConfiguration 26 | @RequiredArgsConstructor 27 | @EnableConfigurationProperties({OpenAiProperties.class}) 28 | public class OpenAiAutoConfiguration { 29 | 30 | private final OpenAiProperties openAiProperties; 31 | 32 | @Bean 33 | @ConditionalOnMissingBean 34 | public OkHttpClient okHttpClient(List interceptors) { 35 | OkHttpClient.Builder builder = new OkHttpClient.Builder(); 36 | PropertyMapper mapper = PropertyMapper.get().alwaysApplyingWhenNonNull(); 37 | mapper.from(interceptors).to(x -> builder.interceptors().addAll(x)); 38 | mapper.from(openAiProperties::getReadTimeout).to(builder::readTimeout); 39 | mapper.from(openAiProperties::getWriteTimeout).to(builder::writeTimeout); 40 | mapper.from(openAiProperties::getConnectTimeout).to(builder::connectTimeout); 41 | return Optional.ofNullable(openAiProperties.getProxy()) 42 | .map(proxy -> { 43 | String username = proxy.getUsername(); 44 | String password = proxy.getPassword(); 45 | mapper.from(() -> StrUtil.isAllNotBlank(username, password)) 46 | .whenTrue() 47 | .toCall(() -> builder.proxyAuthenticator((route, response) -> response.request() 48 | .newBuilder() 49 | .header(proxy.getHeaderName(), Credentials.basic(username, password)) 50 | .build())); 51 | builder.proxy(new Proxy(proxy.getType(), new InetSocketAddress(proxy.getHost(), proxy.getPort()))); 52 | return builder.build(); 53 | }) 54 | .orElseGet(builder::build); 55 | } 56 | 57 | @Bean 58 | @ConditionalOnMissingBean 59 | public OpenAiClient openAiService( 60 | OkHttpClient okHttpClient, 61 | OpenAiKeyWrapper openAiKeyWrapper, 62 | ObjectProvider uriTemplateHandlerObjectProvider) { 63 | 64 | UriTemplateHandler uriTplHandler = uriTemplateHandlerObjectProvider.getIfAvailable(() -> { 65 | DefaultUriBuilderFactory uriBuilderFactory = new DefaultUriBuilderFactory(); 66 | uriBuilderFactory.setEncodingMode(DefaultUriBuilderFactory.EncodingMode.URI_COMPONENT); 67 | return uriBuilderFactory; 68 | }); 69 | return new DefaultOpenAiClient(okHttpClient, openAiProperties, openAiKeyWrapper, uriTplHandler); 70 | } 71 | 72 | @Bean 73 | @ConditionalOnMissingBean 74 | public OpenAiKeyWrapper openAiKeyWrapper(OpenAiKeyProvider openAiKeyProvider) { 75 | return new OpenAiKeyWrapper(openAiKeyProvider); 76 | } 77 | 78 | @Bean 79 | @ConditionalOnMissingBean 80 | public OpenAiKeyProvider openAiKeyProvider() { 81 | return openAiProperties::getKeys; 82 | } 83 | 84 | @Bean 85 | public OpenAiErrorInterceptor openAiErrorInterceptor(OpenAiKeyWrapper openAiKeyWrapper) { 86 | return new OpenAiErrorInterceptor(openAiKeyWrapper); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/main/java/com/lzhpo/chatgpt/OpenAiConstant.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 lzhpo 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lzhpo.chatgpt; 18 | 19 | import lombok.AccessLevel; 20 | import lombok.NoArgsConstructor; 21 | import okhttp3.MediaType; 22 | 23 | /** 24 | * @author lzhpo 25 | */ 26 | @NoArgsConstructor(access = AccessLevel.PRIVATE) 27 | public final class OpenAiConstant { 28 | 29 | /** 30 | * The image must be less than 4MB. 31 | */ 32 | public static final long MAX_IMAGE_SIZE = 4 * 1024 * 1024L; 33 | 34 | /** 35 | * The image type must be png type. 36 | */ 37 | public static final String EXPECTED_IMAGE_TYPE = "png"; 38 | 39 | /** 40 | * The Authorization value prefix. 41 | */ 42 | public static final String BEARER = "Bearer "; 43 | 44 | /** 45 | * The image/png. 46 | */ 47 | public static final MediaType IMAGE_PNG = MediaType.get("image/png"); 48 | 49 | /** 50 | * The application/json. 51 | */ 52 | public static final MediaType APPLICATION_JSON = MediaType.get("application/json; charset=utf-8"); 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/com/lzhpo/chatgpt/apikey/OpenAiKey.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 lzhpo 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lzhpo.chatgpt.apikey; 18 | 19 | import lombok.AllArgsConstructor; 20 | import lombok.Builder; 21 | import lombok.Data; 22 | import lombok.NoArgsConstructor; 23 | 24 | /** 25 | * @author lzhpo 26 | */ 27 | @Data 28 | @Builder 29 | @NoArgsConstructor 30 | @AllArgsConstructor 31 | public class OpenAiKey { 32 | 33 | /** 34 | * This api key. 35 | */ 36 | private String key; 37 | 38 | /** 39 | * This api key weight. 40 | */ 41 | private double weight; 42 | 43 | /** 44 | * Whether enable this api key. 45 | */ 46 | @Builder.Default 47 | private boolean enabled = true; 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/com/lzhpo/chatgpt/apikey/OpenAiKeyProvider.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 lzhpo 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lzhpo.chatgpt.apikey; 18 | 19 | import java.util.List; 20 | 21 | /** 22 | * @author lzhpo 23 | */ 24 | public interface OpenAiKeyProvider { 25 | 26 | /** 27 | * Get the {@link OpenAiKey}. 28 | * 29 | *

Notes: if you get the api keys from DB, also can add cache to improve speed. 30 | * 31 | * @return list of {@link OpenAiKey} 32 | */ 33 | List get(); 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/com/lzhpo/chatgpt/apikey/OpenAiKeyWrapper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 lzhpo 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lzhpo.chatgpt.apikey; 18 | 19 | import cn.hutool.cache.CacheUtil; 20 | import cn.hutool.cache.impl.LFUCache; 21 | import cn.hutool.core.lang.WeightRandom; 22 | import cn.hutool.core.util.HashUtil; 23 | import java.util.*; 24 | import java.util.stream.Collectors; 25 | import lombok.Getter; 26 | import lombok.RequiredArgsConstructor; 27 | import lombok.extern.slf4j.Slf4j; 28 | import org.springframework.util.Assert; 29 | 30 | /** 31 | * @author lzhpo 32 | */ 33 | @Slf4j 34 | @Getter 35 | @RequiredArgsConstructor 36 | @SuppressWarnings({"squid:S3864"}) 37 | public class OpenAiKeyWrapper { 38 | 39 | private final OpenAiKeyProvider openAiKeyProvider; 40 | private final List invalidKeys = new ArrayList<>(); 41 | private final LFUCache> randomLFUCache = CacheUtil.newLFUCache(0); 42 | 43 | /** 44 | * Wrap the {@link OpenAiKeyProvider#get()} result, in order to make api keys has weight random power. 45 | * 46 | * @return has weight random power api keys 47 | */ 48 | public WeightRandom wrap() { 49 | List openAiKeys = openAiKeyProvider.get(); 50 | Assert.notEmpty(openAiKeys, "The api keys is empty."); 51 | long cacheKey = hashKey(openAiKeys); 52 | return Optional.ofNullable(randomLFUCache.get(cacheKey)).orElseGet(() -> { 53 | log.debug("Not found openAiKeys in cache, will generate new one api key weight random."); 54 | Set> weightObjSet = openAiKeys.stream() 55 | .filter(OpenAiKey::isEnabled) 56 | .filter(openAiKey -> !invalidKeys.contains(openAiKey.getKey())) 57 | .peek(openAiKey -> log.debug("Found available api key: {}", openAiKey)) 58 | .map(obj -> new WeightRandom.WeightObj<>(obj.getKey(), obj.getWeight())) 59 | .collect(Collectors.toSet()); 60 | WeightRandom weightRandom = new WeightRandom<>(weightObjSet); 61 | randomLFUCache.put(cacheKey, weightRandom); 62 | return weightRandom; 63 | }); 64 | } 65 | 66 | /** 67 | * Remove invalid api keys, support automatic key rotation. 68 | * 69 | * @param apiKey the api key 70 | */ 71 | public void invalidKey(String apiKey) { 72 | randomLFUCache.clear(); 73 | invalidKeys.add(apiKey); 74 | log.warn("Already removed the invalided api key: {}, total invalided keys: {}", apiKey, invalidKeys); 75 | } 76 | 77 | /** 78 | * Hash {@code openAiKeys}. 79 | * 80 | * @param openAiKeys the api keys 81 | * @return murmur hash64 result 82 | */ 83 | public static long hashKey(List openAiKeys) { 84 | return HashUtil.murmur64(openAiKeys.toString().getBytes()); 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/main/java/com/lzhpo/chatgpt/entity/CommonConfig.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 lzhpo 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lzhpo.chatgpt.entity; 18 | 19 | import com.fasterxml.jackson.annotation.JsonInclude; 20 | import com.fasterxml.jackson.annotation.JsonProperty; 21 | import javax.validation.constraints.Max; 22 | import javax.validation.constraints.Min; 23 | import lombok.AllArgsConstructor; 24 | import lombok.Data; 25 | import lombok.NoArgsConstructor; 26 | import lombok.experimental.SuperBuilder; 27 | 28 | /** 29 | * @author lzhpo 30 | */ 31 | @Data 32 | @SuperBuilder 33 | @NoArgsConstructor 34 | @AllArgsConstructor 35 | @JsonInclude(JsonInclude.Include.NON_NULL) 36 | public class CommonConfig { 37 | 38 | /** 39 | * How many edits to generate for the input and instruction. 40 | */ 41 | private Integer n; 42 | 43 | /** 44 | * What sampling temperature to use, between 0 and 2. 45 | * 46 | *

Higher values like 0.8 will make the output more random, 47 | * while lower values like 0.2 will make it more focused and deterministic. 48 | * 49 | *

We generally recommend altering this or top_p but not both. 50 | */ 51 | @Min(0) 52 | @Max(2) 53 | private Number temperature; 54 | 55 | /** 56 | * An alternative to sampling with temperature, called nucleus sampling, 57 | * where the model considers the results of the tokens with top_p probability mass. 58 | * So 0.1 means only the tokens comprising the top 10% probability mass are considered. 59 | * 60 | *

We generally recommend altering this or temperature but not both. 61 | */ 62 | @JsonProperty("top_p") 63 | private Number topP; 64 | } 65 | -------------------------------------------------------------------------------- /src/main/java/com/lzhpo/chatgpt/entity/CommonUsage.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 lzhpo 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lzhpo.chatgpt.entity; 18 | 19 | import com.fasterxml.jackson.annotation.JsonProperty; 20 | import lombok.Data; 21 | 22 | /** 23 | * @author lzhpo 24 | */ 25 | @Data 26 | public class CommonUsage { 27 | 28 | /** 29 | * OpenAi calculate the input the number of tokens consumed. 30 | */ 31 | @JsonProperty("prompt_tokens") 32 | private Long promptTokens; 33 | 34 | /** 35 | * OpenAi calculate the output the number of tokens consumed. 36 | */ 37 | @JsonProperty("completion_tokens") 38 | private Long completionTokens; 39 | 40 | /** 41 | * OpenAi calculate the total number of tokens consumed by the input and output of this dialogue. 42 | *

totalTokens = {@link #promptTokens} + {@link #completionTokens} 43 | */ 44 | @JsonProperty("total_tokens") 45 | private Long totalTokens; 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/com/lzhpo/chatgpt/entity/audio/CreateAudioRequest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 lzhpo 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lzhpo.chatgpt.entity.audio; 18 | 19 | import com.fasterxml.jackson.annotation.JsonInclude; 20 | import com.fasterxml.jackson.annotation.JsonProperty; 21 | import javax.validation.constraints.Max; 22 | import javax.validation.constraints.Min; 23 | import javax.validation.constraints.NotBlank; 24 | import lombok.AllArgsConstructor; 25 | import lombok.Builder; 26 | import lombok.Data; 27 | import lombok.NoArgsConstructor; 28 | 29 | /** 30 | * @author lzhpo 31 | */ 32 | @Data 33 | @Builder 34 | @NoArgsConstructor 35 | @AllArgsConstructor 36 | @JsonInclude(JsonInclude.Include.NON_NULL) 37 | public class CreateAudioRequest { 38 | 39 | /** 40 | * ID of the model to use. 41 | * 42 | *

Only whisper-1 is currently available. 43 | */ 44 | @NotBlank 45 | private String model = "whisper-1"; 46 | 47 | /** 48 | * An optional text to guide the model's style or continue a previous audio segment. 49 | * 50 | *

The prompt should match the audio language. 51 | */ 52 | private String prompt; 53 | 54 | /** 55 | * The format of the transcript output, in one of these options: json, text, srt, verbose_json, or vtt. 56 | */ 57 | @JsonProperty("response_format") 58 | private String responseFormat; 59 | 60 | /** 61 | * What sampling temperature to use, between 0 and 2. 62 | * 63 | *

Higher values like 0.8 will make the output more random, 64 | * while lower values like 0.2 will make it more focused and deterministic. 65 | * 66 | *

We generally recommend altering this or top_p but not both. 67 | */ 68 | @Min(0) 69 | @Max(2) 70 | private Number temperature; 71 | 72 | /** 73 | * The language of the input audio. 74 | * 75 | *

Supplying the input language in ISO-639-1 format will improve accuracy and latency. 76 | */ 77 | private String language; 78 | } 79 | -------------------------------------------------------------------------------- /src/main/java/com/lzhpo/chatgpt/entity/audio/CreateAudioResponse.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 lzhpo 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lzhpo.chatgpt.entity.audio; 18 | 19 | import lombok.Data; 20 | 21 | /** 22 | * @author lzhpo 23 | */ 24 | @Data 25 | public class CreateAudioResponse { 26 | 27 | private String text; 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/com/lzhpo/chatgpt/entity/billing/CreditGrants.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 lzhpo 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lzhpo.chatgpt.entity.billing; 18 | 19 | import java.util.List; 20 | import lombok.Data; 21 | 22 | /** 23 | * @author lzhpo 24 | */ 25 | @Data 26 | public class CreditGrants { 27 | 28 | private String object; 29 | private List data; 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/com/lzhpo/chatgpt/entity/billing/CreditGrantsData.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 lzhpo 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lzhpo.chatgpt.entity.billing; 18 | 19 | import com.fasterxml.jackson.annotation.JsonProperty; 20 | import java.math.BigDecimal; 21 | import lombok.Data; 22 | 23 | /** 24 | * @author lzhpo 25 | */ 26 | @Data 27 | public class CreditGrantsData { 28 | 29 | private String id; 30 | 31 | private String object; 32 | 33 | @JsonProperty("grant_amount") 34 | private BigDecimal grantAmount; 35 | 36 | @JsonProperty("used_amount") 37 | private BigDecimal usedAmount; 38 | 39 | @JsonProperty("effective_at") 40 | private BigDecimal effectiveAt; 41 | 42 | @JsonProperty("expires_at") 43 | private BigDecimal expiresAt; 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/com/lzhpo/chatgpt/entity/billing/CreditGrantsResponse.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 lzhpo 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lzhpo.chatgpt.entity.billing; 18 | 19 | import com.fasterxml.jackson.annotation.JsonProperty; 20 | import java.math.BigDecimal; 21 | import lombok.Data; 22 | 23 | /** 24 | * @author lzhpo 25 | */ 26 | @Data 27 | public class CreditGrantsResponse { 28 | 29 | private String object; 30 | 31 | @JsonProperty("total_granted") 32 | private BigDecimal totalGranted; 33 | 34 | @JsonProperty("total_used") 35 | private BigDecimal totalUsed; 36 | 37 | @JsonProperty("total_available") 38 | private BigDecimal totalAvailable; 39 | 40 | private CreditGrants grants; 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/com/lzhpo/chatgpt/entity/billing/SubscriptionAddress.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 lzhpo 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lzhpo.chatgpt.entity.billing; 18 | 19 | import com.fasterxml.jackson.annotation.JsonProperty; 20 | import lombok.Data; 21 | 22 | /** 23 | * @author lzhpo 24 | */ 25 | @Data 26 | public class SubscriptionAddress { 27 | 28 | private String line1; 29 | 30 | private Object line2; 31 | 32 | private String city; 33 | 34 | private String state; 35 | 36 | @JsonProperty("postal_code") 37 | private String postalCode; 38 | 39 | private String country; 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/com/lzhpo/chatgpt/entity/billing/SubscriptionPlan.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 lzhpo 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lzhpo.chatgpt.entity.billing; 18 | 19 | import lombok.Data; 20 | 21 | /** 22 | * @author lzhpo 23 | */ 24 | @Data 25 | public class SubscriptionPlan { 26 | 27 | private String title; 28 | private String id; 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/com/lzhpo/chatgpt/entity/billing/SubscriptionResponse.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 lzhpo 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lzhpo.chatgpt.entity.billing; 18 | 19 | import com.fasterxml.jackson.annotation.JsonProperty; 20 | import java.math.BigDecimal; 21 | import java.util.List; 22 | import lombok.Data; 23 | 24 | /** 25 | * @author lzhpo 26 | */ 27 | @Data 28 | public class SubscriptionResponse { 29 | 30 | private String object; 31 | 32 | @JsonProperty("has_payment_method") 33 | private Boolean has_payment_method; 34 | 35 | private Boolean canceled; 36 | 37 | @JsonProperty("canceled_at") 38 | private Long canceledAt; 39 | 40 | private Object delinquent; 41 | 42 | @JsonProperty("access_until") 43 | private Long accessUntil; 44 | 45 | @JsonProperty("soft_limit") 46 | private Long softLimit; 47 | 48 | @JsonProperty("hard_limit") 49 | private Long hardLimit; 50 | 51 | @JsonProperty("system_hard_limit") 52 | private Long systemHardLimit; 53 | 54 | @JsonProperty("soft_limit_usd") 55 | private BigDecimal softLimitUsd; 56 | 57 | @JsonProperty("hard_limit_usd") 58 | private BigDecimal hardLimitUsd; 59 | 60 | @JsonProperty("system_hard_limit_usd") 61 | private BigDecimal systemHardLimitUsd; 62 | 63 | private SubscriptionPlan plan; 64 | 65 | @JsonProperty("account_name") 66 | private String accountName; 67 | 68 | @JsonProperty("po_number") 69 | private String poNumber; 70 | 71 | @JsonProperty("billing_email") 72 | private String billingEmail; 73 | 74 | @JsonProperty("tax_ids") 75 | private List taxIds; 76 | 77 | @JsonProperty("billing_address") 78 | private SubscriptionAddress billingAddress; 79 | 80 | @JsonProperty("business_address") 81 | private SubscriptionAddress businessAddress; 82 | } 83 | -------------------------------------------------------------------------------- /src/main/java/com/lzhpo/chatgpt/entity/billing/UsageDailyCosts.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 lzhpo 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lzhpo.chatgpt.entity.billing; 18 | 19 | import com.fasterxml.jackson.annotation.JsonProperty; 20 | import java.math.BigDecimal; 21 | import java.util.List; 22 | import lombok.Data; 23 | 24 | /** 25 | * @author lzhpo 26 | */ 27 | @Data 28 | public class UsageDailyCosts { 29 | 30 | private BigDecimal timestamp; 31 | 32 | @JsonProperty("line_items") 33 | private List lineItems; 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/com/lzhpo/chatgpt/entity/billing/UsageLineItems.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 lzhpo 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lzhpo.chatgpt.entity.billing; 18 | 19 | import java.math.BigDecimal; 20 | import lombok.Data; 21 | 22 | /** 23 | * @author lzhpo 24 | */ 25 | @Data 26 | public class UsageLineItems { 27 | 28 | private String name; 29 | private BigDecimal cost; 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/com/lzhpo/chatgpt/entity/billing/UsageResponse.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 lzhpo 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lzhpo.chatgpt.entity.billing; 18 | 19 | import com.fasterxml.jackson.annotation.JsonProperty; 20 | import java.math.BigDecimal; 21 | import java.util.List; 22 | import lombok.Data; 23 | 24 | /** 25 | * @author lzhpo 26 | */ 27 | @Data 28 | public class UsageResponse { 29 | 30 | private String object; 31 | 32 | @JsonProperty("daily_costs") 33 | private List dailyCosts; 34 | 35 | @JsonProperty("total_usage") 36 | private BigDecimal totalUsage; 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/com/lzhpo/chatgpt/entity/chat/ChatCompletionChoice.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 lzhpo 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lzhpo.chatgpt.entity.chat; 18 | 19 | import com.fasterxml.jackson.annotation.JsonProperty; 20 | import lombok.Data; 21 | 22 | /** 23 | * @author lzhpo 24 | */ 25 | @Data 26 | public class ChatCompletionChoice { 27 | 28 | private Long index; 29 | 30 | private ChatCompletionMessage message; 31 | 32 | @JsonProperty("finish_reason") 33 | private String finishReason; 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/com/lzhpo/chatgpt/entity/chat/ChatCompletionFunction.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 lzhpo 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lzhpo.chatgpt.entity.chat; 18 | 19 | import com.fasterxml.jackson.annotation.JsonInclude; 20 | import javax.validation.constraints.NotBlank; 21 | import javax.validation.constraints.NotNull; 22 | import lombok.AllArgsConstructor; 23 | import lombok.Data; 24 | import lombok.NoArgsConstructor; 25 | import lombok.experimental.SuperBuilder; 26 | import org.hibernate.validator.constraints.Length; 27 | 28 | /** 29 | * @author lzhpo 30 | */ 31 | @Data 32 | @SuperBuilder 33 | @NoArgsConstructor 34 | @AllArgsConstructor 35 | @JsonInclude(JsonInclude.Include.NON_NULL) 36 | public class ChatCompletionFunction { 37 | 38 | /** 39 | * The name of the function to be called. Must be a-z, A-Z, 0-9, or contain underscores and dashes, with a maximum length of 64. 40 | */ 41 | @NotBlank 42 | @Length(max = 64) 43 | private String name; 44 | 45 | /** 46 | * A description of what the function does, used by the model to choose when and how to call the function. 47 | */ 48 | private String description; 49 | 50 | /** 51 | * The parameters the functions accepts, described as a JSON Schema object. 52 | *

See the guide for examples, and the JSON Schema reference for documentation about the format. 53 | * 54 | *

55 |      * To describe a function that accepts no parameters, provide the value {"type": "object", "properties": {}}.
56 |      * 
57 | */ 58 | @NotNull 59 | private ChatCompletionParameter parameters; 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/com/lzhpo/chatgpt/entity/chat/ChatCompletionFunctionCall.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 lzhpo 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lzhpo.chatgpt.entity.chat; 18 | 19 | import com.fasterxml.jackson.annotation.JsonInclude; 20 | import lombok.AllArgsConstructor; 21 | import lombok.Data; 22 | import lombok.NoArgsConstructor; 23 | import lombok.experimental.SuperBuilder; 24 | 25 | /** 26 | * @author lzhpo 27 | */ 28 | @Data 29 | @SuperBuilder 30 | @NoArgsConstructor 31 | @AllArgsConstructor 32 | @JsonInclude(JsonInclude.Include.NON_NULL) 33 | public class ChatCompletionFunctionCall { 34 | 35 | /** 36 | * The name of the function to call. 37 | */ 38 | private String name; 39 | 40 | /** 41 | * The arguments to call the function with, as generated by the model in JSON format. 42 | *

Note that the model does not always generate valid JSON, and may hallucinate parameters not defined by your function schema. 43 | *

Validate the arguments in your code before calling your function. 44 | */ 45 | private String arguments; 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/com/lzhpo/chatgpt/entity/chat/ChatCompletionMessage.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 lzhpo 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lzhpo.chatgpt.entity.chat; 18 | 19 | import com.fasterxml.jackson.annotation.JsonInclude; 20 | import com.fasterxml.jackson.annotation.JsonProperty; 21 | import javax.validation.constraints.NotBlank; 22 | import javax.validation.constraints.NotNull; 23 | import lombok.AllArgsConstructor; 24 | import lombok.Builder; 25 | import lombok.Data; 26 | import lombok.NoArgsConstructor; 27 | import lombok.experimental.SuperBuilder; 28 | 29 | /** 30 | * @author lzhpo 31 | */ 32 | @Data 33 | @SuperBuilder 34 | @NoArgsConstructor 35 | @AllArgsConstructor 36 | @JsonInclude(JsonInclude.Include.NON_NULL) 37 | public class ChatCompletionMessage { 38 | 39 | /** 40 | * A unique identifier representing your end-user, which can help OpenAI to monitor and detect abuse. 41 | * 42 | *

safety-best-practices 43 | */ 44 | @NotBlank 45 | @Builder.Default 46 | private String role = "user"; 47 | 48 | /** 49 | * The input content. 50 | */ 51 | @NotNull 52 | private String content; 53 | 54 | /** 55 | * The name of the author of this message. May contain a-z, A-Z, 0-9, and underscores, with a maximum length of 64 characters. 56 | */ 57 | private String name; 58 | 59 | /** 60 | * The name and arguments of a function that should be called, as generated by the model. 61 | */ 62 | @JsonProperty("function_call") 63 | private ChatCompletionFunctionCall functionCall; 64 | } 65 | -------------------------------------------------------------------------------- /src/main/java/com/lzhpo/chatgpt/entity/chat/ChatCompletionParameter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 lzhpo 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lzhpo.chatgpt.entity.chat; 18 | 19 | import com.fasterxml.jackson.annotation.JsonInclude; 20 | import java.util.List; 21 | import lombok.AllArgsConstructor; 22 | import lombok.Data; 23 | import lombok.NoArgsConstructor; 24 | import lombok.experimental.SuperBuilder; 25 | 26 | /** 27 | * @author lzhpo 28 | */ 29 | @Data 30 | @SuperBuilder 31 | @NoArgsConstructor 32 | @AllArgsConstructor 33 | @JsonInclude(JsonInclude.Include.NON_NULL) 34 | public class ChatCompletionParameter { 35 | 36 | /** 37 | * The parameter type. 38 | */ 39 | private String type; 40 | 41 | /** 42 | * The parameter properties. 43 | */ 44 | private Object properties; 45 | 46 | /** 47 | * The required properties entry from {@link ChatCompletionParameter#properties}. 48 | */ 49 | private List required; 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/com/lzhpo/chatgpt/entity/chat/ChatCompletionRequest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 lzhpo 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lzhpo.chatgpt.entity.chat; 18 | 19 | import cn.hutool.core.collection.ListUtil; 20 | import com.fasterxml.jackson.annotation.JsonInclude; 21 | import com.fasterxml.jackson.annotation.JsonProperty; 22 | import com.lzhpo.chatgpt.entity.CommonConfig; 23 | import java.util.List; 24 | import java.util.Map; 25 | import javax.validation.Valid; 26 | import javax.validation.constraints.Max; 27 | import javax.validation.constraints.Min; 28 | import javax.validation.constraints.NotBlank; 29 | import javax.validation.constraints.NotEmpty; 30 | import lombok.*; 31 | import lombok.experimental.SuperBuilder; 32 | 33 | /** 34 | * @author lzhpo 35 | */ 36 | @Data 37 | @SuperBuilder 38 | @NoArgsConstructor 39 | @AllArgsConstructor 40 | @EqualsAndHashCode(callSuper = true) 41 | @JsonInclude(JsonInclude.Include.NON_NULL) 42 | public class ChatCompletionRequest extends CommonConfig { 43 | 44 | /** 45 | * ID of the model to use. 46 | * 47 | *

You can use the List models API to see all of your available models, 48 | * or see our Model overview for descriptions of them. 49 | * Model endpoint compatibility 50 | */ 51 | @NotBlank 52 | @Builder.Default 53 | private String model = "gpt-3.5-turbo"; 54 | 55 | /** 56 | * The messages to generate chat completions for, in the chat format. 57 | */ 58 | @Valid 59 | @NotEmpty 60 | private List messages; 61 | 62 | /** 63 | * A list of functions the model may generate JSON inputs for. 64 | * function-calling-and-other-api-updates 65 | */ 66 | private List functions; 67 | 68 | /** 69 | * Controls how the model responds to function calls. "none" means the model does not call a function, 70 | *

and responds to the end-user. "auto" means the model can pick between an end-user or calling a function. 71 | *

Specifying a particular function via {"name":\ "my_function"} forces the model to call that function. 72 | *

76 | */ 77 | @JsonProperty("function_call") 78 | private Object functionCall; 79 | 80 | /** 81 | * If set, partial message deltas will be sent, like in ChatGPT. 82 | * Tokens will be sent as data-only server-sent events as they become available, with the stream terminated by a {@code data: [DONE]} message. 83 | * 84 | *

See the OpenAI Cookbook for example code. 85 | */ 86 | private Boolean stream; 87 | 88 | /** 89 | * Up to 4 sequences where the API will stop generating further tokens. 90 | */ 91 | private String stop; 92 | 93 | /** 94 | * The maximum number of tokens to generate in the chat completion. Defaults to inf. 95 | * 96 | *

The total length of input tokens and generated tokens is limited by the model's context length. 97 | */ 98 | @JsonProperty("max_tokens") 99 | private Integer maxTokens; 100 | 101 | /** 102 | * Number between -2.0 and 2.0. Positive values penalize new tokens based on whether they appear in the text so far, 103 | * increasing the model's likelihood to talk about new topics. 104 | * 105 | *

See more information about frequency and presence penalties. 106 | */ 107 | @Min(-2) 108 | @Max(2) 109 | @JsonProperty("presence_penalty") 110 | private Number presencePenalty; 111 | 112 | /** 113 | * Number between -2.0 and 2.0. Positive values penalize new tokens based on their existing frequency in the text so far, 114 | * decreasing the model's likelihood to repeat the same line verbatim. 115 | * 116 | *

See more information about frequency and presence penalties. 117 | */ 118 | @Min(-2) 119 | @Max(2) 120 | @JsonProperty("frequency_penalty") 121 | private Number frequencyPenalty; 122 | 123 | /** 124 | * Modify the likelihood of specified tokens appearing in the completion. 125 | * 126 | *

Accepts a json object that maps tokens (specified by their token ID in the tokenizer) to an associated bias value from -100 to 100. 127 | * Mathematically, the bias is added to the logits generated by the model prior to sampling. 128 | * The exact effect will vary per model, but values between -1 and 1 should decrease or increase likelihood of selection; values like -100 or 100 should result in a ban or exclusive selection of the relevant token. 129 | */ 130 | @JsonProperty("logit_bias") 131 | private Map logitBias; 132 | 133 | /** 134 | * A unique identifier representing your end-user, which can help OpenAI to monitor and detect abuse. 135 | * 136 | *

Learn more. 137 | */ 138 | private String user; 139 | 140 | /** 141 | * User {@code content} to create one chat request. 142 | * 143 | * @param content content 144 | */ 145 | public static ChatCompletionRequest create(String content) { 146 | ChatCompletionMessage message = new ChatCompletionMessage(); 147 | message.setContent(content); 148 | return ChatCompletionRequest.builder().messages(ListUtil.of(message)).build(); 149 | } 150 | } 151 | -------------------------------------------------------------------------------- /src/main/java/com/lzhpo/chatgpt/entity/chat/ChatCompletionResponse.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 lzhpo 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lzhpo.chatgpt.entity.chat; 18 | 19 | import com.lzhpo.chatgpt.entity.CommonUsage; 20 | import java.util.List; 21 | import lombok.Data; 22 | 23 | /** 24 | * @author lzhpo 25 | */ 26 | @Data 27 | public class ChatCompletionResponse { 28 | 29 | private String id; 30 | private String object; 31 | private Long created; 32 | private String model; 33 | private CommonUsage usage; 34 | private List choices; 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/com/lzhpo/chatgpt/entity/completions/CompletionChoice.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 lzhpo 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lzhpo.chatgpt.entity.completions; 18 | 19 | import com.fasterxml.jackson.annotation.JsonProperty; 20 | import lombok.Data; 21 | 22 | /** 23 | * @author lzhpo 24 | */ 25 | @Data 26 | public class CompletionChoice { 27 | 28 | private String text; 29 | 30 | private Long index; 31 | 32 | private Integer logprobs; 33 | 34 | @JsonProperty("finish_reason") 35 | private String finishReason; 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/com/lzhpo/chatgpt/entity/completions/CompletionRequest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 lzhpo 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lzhpo.chatgpt.entity.completions; 18 | 19 | import com.fasterxml.jackson.annotation.JsonInclude; 20 | import com.fasterxml.jackson.annotation.JsonProperty; 21 | import com.lzhpo.chatgpt.entity.CommonConfig; 22 | import java.util.Map; 23 | import javax.validation.constraints.Max; 24 | import javax.validation.constraints.Min; 25 | import javax.validation.constraints.NotBlank; 26 | import lombok.*; 27 | import lombok.experimental.SuperBuilder; 28 | 29 | /** 30 | * @author lzhpo 31 | */ 32 | @Data 33 | @SuperBuilder 34 | @NoArgsConstructor 35 | @AllArgsConstructor 36 | @EqualsAndHashCode(callSuper = true) 37 | @JsonInclude(JsonInclude.Include.NON_NULL) 38 | public class CompletionRequest extends CommonConfig { 39 | 40 | /** 41 | * ID of the model to use. 42 | * 43 | *

You can use the List models API to see all of your available models, 44 | * or see our Model overview for descriptions of them. 45 | * Model endpoint compatibility 46 | */ 47 | @NotBlank 48 | @Builder.Default 49 | private String model = "text-davinci-003"; 50 | 51 | /** 52 | * The prompt(s) to generate completions for, encoded as a string, array of strings, array of tokens, or array of token arrays. 53 | * 54 | *

Note that <|endoftext|> is the document separator that the model sees during training, so if a prompt is not specified the model will generate as if from the beginning of a new document. 55 | */ 56 | private String prompt; 57 | 58 | /** 59 | * The suffix that comes after a completion of inserted text. 60 | */ 61 | private String suffix; 62 | 63 | /** 64 | * The maximum number of tokens to generate in the completion. 65 | * 66 | *

The token count of your prompt plus max_tokens cannot exceed the model's context length. 67 | * Most models have a context length of 2048 tokens (except for the newest models, which support 4096). 68 | */ 69 | @JsonProperty("max_tokens") 70 | private Integer maxTokens; 71 | 72 | /** 73 | * If set, partial message deltas will be sent, like in ChatGPT. 74 | * Tokens will be sent as data-only server-sent events as they become available, with the stream terminated by a {@code data: [DONE]} message. 75 | * 76 | *

See the OpenAI Cookbook for example code. 77 | */ 78 | private Boolean stream; 79 | 80 | /** 81 | * Include the log probabilities on the logprobs most likely tokens, as well the chosen tokens. 82 | * For example, if logprobs is 5, the API will return a list of the 5 most likely tokens. 83 | * The API will always return the logprob of the sampled token, so there may be up to logprobs+1 elements in the response. 84 | * 85 | *

The maximum value for logprobs is 5. If you need more than this, please contact us through our Help center and describe your use case. 86 | */ 87 | private Integer logprobs; 88 | 89 | /** 90 | * Echo back the prompt in addition to the completion. 91 | */ 92 | private String echo; 93 | 94 | /** 95 | * Up to 4 sequences where the API will stop generating further tokens. 96 | * The returned text will not contain the stop sequence. 97 | */ 98 | private String stop; 99 | 100 | /** 101 | * Number between -2.0 and 2.0. Positive values penalize new tokens based on whether they appear in the text so far, 102 | * increasing the model's likelihood to talk about new topics. 103 | * 104 | *

See more information about frequency and presence penalties. 105 | */ 106 | @Min(-2) 107 | @Max(2) 108 | @JsonProperty("presence_penalty") 109 | private Number presencePenalty; 110 | 111 | /** 112 | * Number between -2.0 and 2.0. Positive values penalize new tokens based on their existing frequency in the text so far, 113 | * decreasing the model's likelihood to repeat the same line verbatim. 114 | * 115 | *

See more information about frequency and presence penalties. 116 | */ 117 | @Min(-2) 118 | @Max(2) 119 | @JsonProperty("frequency_penalty") 120 | private Number frequencyPenalty; 121 | 122 | /** 123 | * Generates best_of completions server-side and returns the "best" (the one with the highest log probability per token). Results cannot be streamed. 124 | * 125 | *

When used with n, best_of controls the number of candidate completions and n specifies how many to return – best_of must be greater than n. 126 | * 127 | *

Note: Because this parameter generates many completions, it can quickly consume your token quota. 128 | * Use carefully and ensure that you have reasonable settings for max_tokens and stop. 129 | */ 130 | @JsonProperty("best_of") 131 | private Integer bestOf; 132 | 133 | /** 134 | * Modify the likelihood of specified tokens appearing in the completion. 135 | * 136 | *

Accepts a json object that maps tokens (specified by their token ID in the GPT tokenizer) to an associated bias value from -100 to 100. 137 | * You can use this tokenizer tool (which works for both GPT-2 and GPT-3) to convert text to token IDs. 138 | * Mathematically, the bias is added to the logits generated by the model prior to sampling. 139 | * The exact effect will vary per model, but values between -1 and 1 should decrease or increase likelihood of selection; 140 | * values like -100 or 100 should result in a ban or exclusive selection of the relevant token. 141 | * 142 | *

As an example, you can pass {"50256": -100} to prevent the <|endoftext|> token from being generated. 143 | */ 144 | @JsonProperty("logit_bias") 145 | private Map logitBias; 146 | 147 | /** 148 | * A unique identifier representing your end-user, which can help OpenAI to monitor and detect abuse. 149 | * 150 | *

Learn more. 151 | */ 152 | private String user; 153 | } 154 | -------------------------------------------------------------------------------- /src/main/java/com/lzhpo/chatgpt/entity/completions/CompletionResponse.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 lzhpo 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lzhpo.chatgpt.entity.completions; 18 | 19 | import com.lzhpo.chatgpt.entity.CommonUsage; 20 | import java.util.List; 21 | import lombok.Data; 22 | 23 | /** 24 | * @author lzhpo 25 | */ 26 | @Data 27 | public class CompletionResponse { 28 | 29 | private String id; 30 | private String object; 31 | private Long created; 32 | private String model; 33 | private CommonUsage usage; 34 | private List choices; 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/com/lzhpo/chatgpt/entity/edit/EditChoice.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 lzhpo 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lzhpo.chatgpt.entity.edit; 18 | 19 | import lombok.Data; 20 | 21 | /** 22 | * @author lzhpo 23 | */ 24 | @Data 25 | public class EditChoice { 26 | 27 | private String text; 28 | private Long index; 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/com/lzhpo/chatgpt/entity/edit/EditRequest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 lzhpo 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lzhpo.chatgpt.entity.edit; 18 | 19 | import com.fasterxml.jackson.annotation.JsonInclude; 20 | import com.lzhpo.chatgpt.entity.CommonConfig; 21 | import javax.validation.constraints.NotBlank; 22 | import lombok.*; 23 | import lombok.experimental.SuperBuilder; 24 | 25 | /** 26 | * @author lzhpo 27 | */ 28 | @Data 29 | @SuperBuilder 30 | @NoArgsConstructor 31 | @AllArgsConstructor 32 | @EqualsAndHashCode(callSuper = true) 33 | @JsonInclude(JsonInclude.Include.NON_NULL) 34 | public class EditRequest extends CommonConfig { 35 | 36 | /** 37 | * ID of the model to use. 38 | * 39 | *

You can use the text-davinci-edit-001 or code-davinci-edit-001 model with this endpoint. 40 | */ 41 | @NotBlank 42 | @Builder.Default 43 | private String model = "text-davinci-edit-001"; 44 | 45 | /** 46 | * The input text to use as a starting point for the edit. 47 | */ 48 | @NotBlank 49 | private String input; 50 | 51 | /** 52 | * The instruction that tells the model how to edit the prompt. 53 | */ 54 | @NotBlank 55 | private String instruction; 56 | } 57 | -------------------------------------------------------------------------------- /src/main/java/com/lzhpo/chatgpt/entity/edit/EditResponse.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 lzhpo 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lzhpo.chatgpt.entity.edit; 18 | 19 | import com.lzhpo.chatgpt.entity.CommonUsage; 20 | import java.util.List; 21 | import lombok.Data; 22 | 23 | /** 24 | * @author lzhpo 25 | */ 26 | @Data 27 | public class EditResponse { 28 | 29 | private String object; 30 | private Long created; 31 | private List choices; 32 | private CommonUsage usage; 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/com/lzhpo/chatgpt/entity/embeddings/EmbeddingData.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 lzhpo 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lzhpo.chatgpt.entity.embeddings; 18 | 19 | import java.math.BigDecimal; 20 | import java.util.List; 21 | import lombok.Data; 22 | 23 | /** 24 | * @author lzhpo 25 | */ 26 | @Data 27 | public class EmbeddingData { 28 | 29 | private String object; 30 | private List embedding; 31 | private Long index; 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/com/lzhpo/chatgpt/entity/embeddings/EmbeddingRequest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 lzhpo 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lzhpo.chatgpt.entity.embeddings; 18 | 19 | import com.fasterxml.jackson.annotation.JsonInclude; 20 | import java.util.List; 21 | import javax.validation.constraints.NotBlank; 22 | import javax.validation.constraints.NotEmpty; 23 | import lombok.AllArgsConstructor; 24 | import lombok.Builder; 25 | import lombok.Data; 26 | import lombok.NoArgsConstructor; 27 | 28 | /** 29 | * @author lzhpo 30 | */ 31 | @Data 32 | @Builder 33 | @NoArgsConstructor 34 | @AllArgsConstructor 35 | @JsonInclude(JsonInclude.Include.NON_NULL) 36 | public class EmbeddingRequest { 37 | 38 | /** 39 | * ID of the model to use. 40 | * 41 | *

You can use the List models API to see all of your available models, 42 | * or see our Model overview for descriptions of them. 43 | * Model endpoint compatibility 44 | */ 45 | @NotBlank 46 | private String model; 47 | 48 | /** 49 | * Input text to get embeddings for, encoded as a string or array of tokens. 50 | * To get embeddings for multiple inputs in a single request, pass an array of strings or array of token arrays. 51 | * Each input must not exceed 8192 tokens in length. 52 | */ 53 | @NotEmpty 54 | private List input; 55 | 56 | /** 57 | * A unique identifier representing your end-user, which can help OpenAI to monitor and detect abuse. 58 | * Learn more. 59 | */ 60 | private String user; 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/com/lzhpo/chatgpt/entity/embeddings/EmbeddingResponse.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 lzhpo 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lzhpo.chatgpt.entity.embeddings; 18 | 19 | import com.lzhpo.chatgpt.entity.CommonUsage; 20 | import java.util.List; 21 | import lombok.Data; 22 | 23 | /** 24 | * @author lzhpo 25 | */ 26 | @Data 27 | public class EmbeddingResponse { 28 | 29 | private String object; 30 | private List data; 31 | private String model; 32 | private CommonUsage usage; 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/com/lzhpo/chatgpt/entity/files/DeleteFileResponse.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 lzhpo 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lzhpo.chatgpt.entity.files; 18 | 19 | import lombok.Data; 20 | 21 | /** 22 | * @author lzhpo 23 | */ 24 | @Data 25 | public class DeleteFileResponse { 26 | 27 | private String id; 28 | private String object; 29 | private String deleted; 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/com/lzhpo/chatgpt/entity/files/ListFileData.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 lzhpo 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lzhpo.chatgpt.entity.files; 18 | 19 | import com.fasterxml.jackson.annotation.JsonProperty; 20 | import lombok.Data; 21 | 22 | /** 23 | * @author lzhpo 24 | */ 25 | @Data 26 | public class ListFileData { 27 | 28 | private String id; 29 | 30 | private String object; 31 | 32 | private Long bytes; 33 | 34 | @JsonProperty("created_at") 35 | private Long createdAt; 36 | 37 | private String filename; 38 | 39 | private String purpose; 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/com/lzhpo/chatgpt/entity/files/ListFileResponse.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 lzhpo 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lzhpo.chatgpt.entity.files; 18 | 19 | import java.util.List; 20 | import lombok.Data; 21 | 22 | /** 23 | * @author lzhpo 24 | */ 25 | @Data 26 | public class ListFileResponse { 27 | 28 | private List data; 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/com/lzhpo/chatgpt/entity/files/RetrieveFileResponse.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 lzhpo 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lzhpo.chatgpt.entity.files; 18 | 19 | import com.fasterxml.jackson.annotation.JsonProperty; 20 | import lombok.Data; 21 | 22 | /** 23 | * @author lzhpo 24 | */ 25 | @Data 26 | public class RetrieveFileResponse { 27 | 28 | private String id; 29 | 30 | private String object; 31 | 32 | private Long bytes; 33 | 34 | @JsonProperty("created_at") 35 | private Long createdAt; 36 | 37 | private String filename; 38 | 39 | private String purpose; 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/com/lzhpo/chatgpt/entity/files/UploadFileResponse.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 lzhpo 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lzhpo.chatgpt.entity.files; 18 | 19 | import com.fasterxml.jackson.annotation.JsonProperty; 20 | import lombok.Data; 21 | 22 | /** 23 | * @author lzhpo 24 | */ 25 | @Data 26 | public class UploadFileResponse { 27 | 28 | private String id; 29 | 30 | private String object; 31 | 32 | private Long bytes; 33 | 34 | @JsonProperty("created_at") 35 | private Long createdAt; 36 | 37 | private String filename; 38 | 39 | private String purpose; 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/com/lzhpo/chatgpt/entity/finetunes/CancelFineTuneEvent.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 lzhpo 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lzhpo.chatgpt.entity.finetunes; 18 | 19 | import lombok.Data; 20 | 21 | /** 22 | * @author lzhpo 23 | */ 24 | @Data 25 | public class CancelFineTuneEvent { 26 | 27 | private String type; 28 | private String time; 29 | private String message; 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/com/lzhpo/chatgpt/entity/finetunes/CancelFineTuneResponse.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 lzhpo 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lzhpo.chatgpt.entity.finetunes; 18 | 19 | import com.fasterxml.jackson.annotation.JsonProperty; 20 | import java.util.List; 21 | import lombok.Data; 22 | 23 | /** 24 | * @author lzhpo 25 | */ 26 | @Data 27 | public class CancelFineTuneResponse { 28 | 29 | private String id; 30 | 31 | private String object; 32 | 33 | private String model; 34 | 35 | @JsonProperty("created_at") 36 | private Long createdAt; 37 | 38 | private List events; 39 | 40 | @JsonProperty("fine_tuned_model") 41 | private String fineTunedModel; 42 | 43 | private Hyperparams hyperparams; 44 | 45 | @JsonProperty("organization_id") 46 | private String organizationId; 47 | 48 | @JsonProperty("result_files") 49 | private List resultFiles; 50 | 51 | private String status; 52 | 53 | @JsonProperty("validation_files") 54 | private List validationFiles; 55 | 56 | @JsonProperty("training_files") 57 | private List trainingFiles; 58 | 59 | @JsonProperty("updated_at") 60 | private Long updatedAt; 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/com/lzhpo/chatgpt/entity/finetunes/CreateFineTuneEvents.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 lzhpo 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lzhpo.chatgpt.entity.finetunes; 18 | 19 | import com.fasterxml.jackson.annotation.JsonProperty; 20 | import lombok.Data; 21 | 22 | /** 23 | * @author lzhpo 24 | */ 25 | @Data 26 | public class CreateFineTuneEvents { 27 | 28 | private String object; 29 | 30 | @JsonProperty("created_at") 31 | private Long createdAt; 32 | 33 | private String level; 34 | 35 | private String message; 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/com/lzhpo/chatgpt/entity/finetunes/CreateFineTuneRequest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 lzhpo 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lzhpo.chatgpt.entity.finetunes; 18 | 19 | import com.fasterxml.jackson.annotation.JsonInclude; 20 | import com.fasterxml.jackson.annotation.JsonProperty; 21 | import java.util.List; 22 | import javax.validation.constraints.NotBlank; 23 | import lombok.AllArgsConstructor; 24 | import lombok.Builder; 25 | import lombok.Data; 26 | import lombok.NoArgsConstructor; 27 | 28 | /** 29 | * @author lzhpo 30 | */ 31 | @Data 32 | @Builder 33 | @NoArgsConstructor 34 | @AllArgsConstructor 35 | @JsonInclude(JsonInclude.Include.NON_NULL) 36 | public class CreateFineTuneRequest { 37 | 38 | /** 39 | * The ID of an uploaded file that contains training data. 40 | * 41 | *

See upload file for how to upload a file. 42 | * 43 | *

Your dataset must be formatted as a JSONL file, where each training example is a JSON object with the keys "prompt" and "completion". 44 | * Additionally, you must upload your file with the purpose fine-tune. See the fine-tuning guide for more details. 45 | */ 46 | @NotBlank 47 | @JsonProperty("training_file") 48 | private String trainingFile; 49 | 50 | /** 51 | * The ID of an uploaded file that contains validation data. 52 | * 53 | *

If you provide this file, the data is used to generate validation metrics periodically during fine-tuning. 54 | * These metrics can be viewed in the fine-tuning results file. 55 | * Your train and validation data should be mutually exclusive. 56 | * 57 | *

Your dataset must be formatted as a JSONL file, where each validation example is a JSON object with the keys "prompt" and "completion". 58 | * Additionally, you must upload your file with the purpose fine-tune. 59 | * See the fine-tuning guide for more details. 60 | */ 61 | @JsonProperty("validation_file") 62 | private String validationFile; 63 | 64 | /** 65 | * The name of the base model to fine-tune. 66 | * 67 | *

You can select one of "ada", "babbage", "curie", "davinci", or a fine-tuned model created after 2022-04-21. 68 | * To learn more about these models, see the Models documentation. 69 | */ 70 | private String model; 71 | 72 | /** 73 | * The number of epochs to train the model for. 74 | * 75 | *

An epoch refers to one full cycle through the training dataset. 76 | */ 77 | @JsonProperty("n_epochs") 78 | private Integer nEpochs; 79 | 80 | /** 81 | * The batch size to use for training. 82 | * 83 | *

The batch size is the number of training examples used to train a single forward and backward pass. 84 | * 85 | *

By default, the batch size will be dynamically configured to be ~0.2% of the number of examples in the training set, 86 | * capped at 256 - in general, we've found that larger batch sizes tend to work better for larger datasets. 87 | */ 88 | @JsonProperty("batch_size") 89 | private Integer batchSize; 90 | 91 | /** 92 | * The learning rate multiplier to use for training. 93 | * 94 | *

The fine-tuning learning rate is the original learning rate used for pretraining multiplied by this value. 95 | * 96 | *

By default, the learning rate multiplier is the 0.05, 0.1, or 0.2 depending on final batch_size (larger learning rates tend to perform better with larger batch sizes). 97 | * We recommend experimenting with values in the range 0.02 to 0.2 to see what produces the best results. 98 | */ 99 | @JsonProperty("learning_rate_multiplier") 100 | private Number learningRateMultiplier; 101 | 102 | /** 103 | * The weight to use for loss on the prompt tokens. 104 | * 105 | *

This controls how much the model tries to learn to generate the prompt (as compared to the completion which always has a weight of 1.0), 106 | * and can add a stabilizing effect to training when completions are short. 107 | * 108 | *

If prompts are extremely long (relative to completions), 109 | * it may make sense to reduce this weight so as to avoid over-prioritizing learning the prompt. 110 | */ 111 | @JsonProperty("prompt_loss_weight") 112 | private Number promptLossWeight; 113 | 114 | /** 115 | * If set, we calculate classification-specific metrics such as accuracy and F-1 score using the validation set at the end of every epoch. 116 | * These metrics can be viewed in the results file. 117 | * 118 | *

In order to compute classification metrics, you must provide a validation_file. 119 | * Additionally, you must specify classification_n_classes for multiclass classification or classification_positive_class for binary classification. 120 | */ 121 | @JsonProperty("compute_classification_metrics") 122 | private Boolean computeClassificationMetrics; 123 | 124 | /** 125 | * The number of classes in a classification task. 126 | * 127 | *

This parameter is required for multiclass classification. 128 | */ 129 | @JsonProperty("classification_n_classes") 130 | private Integer classificationNClasses; 131 | 132 | /** 133 | * The positive class in binary classification. 134 | * 135 | *

This parameter is needed to generate precision, recall, and F1 metrics when doing binary classification. 136 | */ 137 | @JsonProperty("classification_positive_class") 138 | private String classificationPositiveClass; 139 | 140 | /** 141 | * If this is provided, we calculate F-beta scores at the specified beta values. 142 | * The F-beta score is a generalization of F-1 score. This is only used for binary classification. 143 | * 144 | *

With a beta of 1 (i.e. the F-1 score), precision and recall are given the same weight. 145 | * A larger beta score puts more weight on recall and less on precision. 146 | * A smaller beta score puts more weight on precision and less on recall. 147 | */ 148 | @JsonProperty("classification_betas") 149 | private List classificationBetas; 150 | 151 | /** 152 | * A string of up to 40 characters that will be added to your fine-tuned model name. 153 | * 154 | *

For example, a suffix of "custom-model-name" would produce a model name like ada:ft-your-org:custom-model-name-2022-02-15-04-21-04. 155 | */ 156 | private String suffix; 157 | } 158 | -------------------------------------------------------------------------------- /src/main/java/com/lzhpo/chatgpt/entity/finetunes/CreateFineTuneResponse.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 lzhpo 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lzhpo.chatgpt.entity.finetunes; 18 | 19 | import com.fasterxml.jackson.annotation.JsonProperty; 20 | import java.util.List; 21 | import lombok.Data; 22 | 23 | /** 24 | * @author lzhpo 25 | */ 26 | @Data 27 | public class CreateFineTuneResponse { 28 | 29 | private String id; 30 | 31 | private String object; 32 | 33 | private String model; 34 | 35 | @JsonProperty("created_at") 36 | private Long createdAt; 37 | 38 | @JsonProperty("fine_tuned_model") 39 | private String fineTunedModel; 40 | 41 | private Hyperparams hyperparams; 42 | 43 | @JsonProperty("organization_id") 44 | private String organizationId; 45 | 46 | private String status; 47 | 48 | @JsonProperty("updated_at") 49 | private Long updatedAt; 50 | 51 | private List events; 52 | 53 | @JsonProperty("result_files") 54 | private List resultFiles; 55 | 56 | @JsonProperty("validation_files") 57 | private List validationFiles; 58 | 59 | @JsonProperty("training_files") 60 | private List trainingFiles; 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/com/lzhpo/chatgpt/entity/finetunes/DeleteFineTuneModelResponse.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 lzhpo 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lzhpo.chatgpt.entity.finetunes; 18 | 19 | import lombok.Data; 20 | 21 | /** 22 | * @author lzhpo 23 | */ 24 | @Data 25 | public class DeleteFineTuneModelResponse { 26 | 27 | private String id; 28 | private String object; 29 | private Boolean deleted; 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/com/lzhpo/chatgpt/entity/finetunes/FineTuneEvent.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 lzhpo 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lzhpo.chatgpt.entity.finetunes; 18 | 19 | import com.fasterxml.jackson.annotation.JsonProperty; 20 | import lombok.Data; 21 | 22 | /** 23 | * @author lzhpo 24 | */ 25 | @Data 26 | public class FineTuneEvent { 27 | 28 | private String object; 29 | 30 | @JsonProperty("created_at") 31 | private Long createdAt; 32 | 33 | private String level; 34 | 35 | private String message; 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/com/lzhpo/chatgpt/entity/finetunes/FineTuneFiles.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 lzhpo 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lzhpo.chatgpt.entity.finetunes; 18 | 19 | import com.fasterxml.jackson.annotation.JsonProperty; 20 | import lombok.Data; 21 | 22 | /** 23 | * @author lzhpo 24 | */ 25 | @Data 26 | public class FineTuneFiles { 27 | 28 | private String id; 29 | 30 | private String object; 31 | 32 | private Long bytes; 33 | 34 | @JsonProperty("created_at") 35 | private Long createdAt; 36 | 37 | private String filename; 38 | 39 | private String purpose; 40 | 41 | private String status; 42 | 43 | @JsonProperty("status_details") 44 | private String statusDetails; 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/com/lzhpo/chatgpt/entity/finetunes/Hyperparams.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 lzhpo 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lzhpo.chatgpt.entity.finetunes; 18 | 19 | import com.fasterxml.jackson.annotation.JsonProperty; 20 | import java.math.BigDecimal; 21 | import lombok.Data; 22 | 23 | /** 24 | * @author lzhpo 25 | */ 26 | @Data 27 | public class Hyperparams { 28 | 29 | @JsonProperty("batch_size") 30 | private Integer batchSize; 31 | 32 | @JsonProperty("learning_rate_multiplier") 33 | private BigDecimal learningRateMultiplier; 34 | 35 | @JsonProperty("n_epochs") 36 | private Integer nEpochs; 37 | 38 | @JsonProperty("prompt_loss_weight") 39 | private BigDecimal prompt_loss_weight; 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/com/lzhpo/chatgpt/entity/finetunes/ListFineTuneData.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 lzhpo 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lzhpo.chatgpt.entity.finetunes; 18 | 19 | import com.fasterxml.jackson.annotation.JsonProperty; 20 | import java.util.List; 21 | import lombok.Data; 22 | 23 | /** 24 | * @author lzhpo 25 | */ 26 | @Data 27 | public class ListFineTuneData { 28 | 29 | private String id; 30 | 31 | private String object; 32 | 33 | private String model; 34 | 35 | @JsonProperty("created_at") 36 | private Long createdAt; 37 | 38 | @JsonProperty("fine_tuned_model") 39 | private String fineTunedModel; 40 | 41 | private Hyperparams hyperparams; 42 | 43 | @JsonProperty("organizationId") 44 | private String organizationId; 45 | 46 | @JsonProperty("result_files") 47 | private List resultFiles; 48 | 49 | private String status; 50 | 51 | @JsonProperty("validation_files") 52 | private List validationFiles; 53 | 54 | @JsonProperty("training_files") 55 | private List trainingFiles; 56 | 57 | @JsonProperty("updated_at") 58 | private Long updatedAt; 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/com/lzhpo/chatgpt/entity/finetunes/ListFineTuneEventData.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 lzhpo 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lzhpo.chatgpt.entity.finetunes; 18 | 19 | import com.fasterxml.jackson.annotation.JsonProperty; 20 | import lombok.Data; 21 | 22 | /** 23 | * @author lzhpo 24 | */ 25 | @Data 26 | public class ListFineTuneEventData { 27 | 28 | private String object; 29 | 30 | @JsonProperty("created_at") 31 | private Long createdAt; 32 | 33 | private String level; 34 | 35 | private String message; 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/com/lzhpo/chatgpt/entity/finetunes/ListFineTuneEventResponse.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 lzhpo 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lzhpo.chatgpt.entity.finetunes; 18 | 19 | import java.util.List; 20 | import lombok.Data; 21 | 22 | /** 23 | * @author lzhpo 24 | */ 25 | @Data 26 | public class ListFineTuneEventResponse { 27 | 28 | private String object; 29 | private List data; 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/com/lzhpo/chatgpt/entity/finetunes/ListFineTuneResponse.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 lzhpo 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lzhpo.chatgpt.entity.finetunes; 18 | 19 | import java.util.List; 20 | import lombok.Data; 21 | 22 | /** 23 | * @author lzhpo 24 | */ 25 | @Data 26 | public class ListFineTuneResponse { 27 | 28 | private String object; 29 | private List data; 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/com/lzhpo/chatgpt/entity/finetunes/RetrieveFineTuneResponse.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 lzhpo 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lzhpo.chatgpt.entity.finetunes; 18 | 19 | import com.fasterxml.jackson.annotation.JsonProperty; 20 | import java.util.List; 21 | import lombok.Data; 22 | 23 | /** 24 | * @author lzhpo 25 | */ 26 | @Data 27 | public class RetrieveFineTuneResponse { 28 | 29 | private String id; 30 | 31 | private String object; 32 | 33 | private String model; 34 | 35 | @JsonProperty("created_at") 36 | private Long createdAt; 37 | 38 | private List events; 39 | 40 | @JsonProperty("fine_tuned_model") 41 | private String fineTunedModel; 42 | 43 | private Hyperparams hyperparams; 44 | 45 | @JsonProperty("organization_id") 46 | private String organizationId; 47 | 48 | @JsonProperty("result_files") 49 | private List resultFiles; 50 | 51 | private String status; 52 | 53 | @JsonProperty("validation_files") 54 | private List validationFiles; 55 | 56 | @JsonProperty("training_files") 57 | private List trainingFiles; 58 | 59 | @JsonProperty("updated_at") 60 | private Long updatedAt; 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/com/lzhpo/chatgpt/entity/image/CreateImageRequest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 lzhpo 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lzhpo.chatgpt.entity.image; 18 | 19 | import com.fasterxml.jackson.annotation.JsonInclude; 20 | import javax.validation.constraints.NotBlank; 21 | import lombok.*; 22 | import lombok.experimental.SuperBuilder; 23 | import org.hibernate.validator.constraints.Length; 24 | 25 | /** 26 | * @author lzhpo 27 | */ 28 | @Data 29 | @SuperBuilder 30 | @NoArgsConstructor 31 | @AllArgsConstructor 32 | @EqualsAndHashCode(callSuper = true) 33 | @JsonInclude(JsonInclude.Include.NON_NULL) 34 | public class CreateImageRequest extends CreateImageVariationRequest { 35 | 36 | /** 37 | * A text description of the desired image(s). The maximum length is 1000 characters. 38 | */ 39 | @NotBlank 40 | @Length(max = 1000) 41 | private String prompt; 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/com/lzhpo/chatgpt/entity/image/CreateImageResponse.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 lzhpo 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lzhpo.chatgpt.entity.image; 18 | 19 | import java.util.List; 20 | import lombok.Data; 21 | 22 | /** 23 | * @author lzhpo 24 | */ 25 | @Data 26 | public class CreateImageResponse { 27 | 28 | private Long created; 29 | private List data; 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/com/lzhpo/chatgpt/entity/image/CreateImageResponseFormat.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 lzhpo 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lzhpo.chatgpt.entity.image; 18 | 19 | import com.fasterxml.jackson.annotation.JsonValue; 20 | import lombok.AllArgsConstructor; 21 | import lombok.Getter; 22 | 23 | /** 24 | * @author lzhpo 25 | */ 26 | @Getter 27 | @AllArgsConstructor 28 | public enum CreateImageResponseFormat { 29 | 30 | /** 31 | * The url. 32 | */ 33 | URL("url"), 34 | 35 | /** 36 | * The b64_json. 37 | */ 38 | B64_JSON("b64_json"); 39 | 40 | @JsonValue 41 | private final String value; 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/com/lzhpo/chatgpt/entity/image/CreateImageSize.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 lzhpo 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lzhpo.chatgpt.entity.image; 18 | 19 | import com.fasterxml.jackson.annotation.JsonValue; 20 | import lombok.AllArgsConstructor; 21 | import lombok.Getter; 22 | 23 | /** 24 | * @author lzhpo 25 | */ 26 | @Getter 27 | @AllArgsConstructor 28 | public enum CreateImageSize { 29 | X_256_256("256x256"), 30 | 31 | X_512_512("512x512"), 32 | 33 | X_1024_1024("1024x1024"); 34 | 35 | @JsonValue 36 | private final String value; 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/com/lzhpo/chatgpt/entity/image/CreateImageUrl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 lzhpo 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lzhpo.chatgpt.entity.image; 18 | 19 | import lombok.Data; 20 | 21 | /** 22 | * @author lzhpo 23 | */ 24 | @Data 25 | public class CreateImageUrl { 26 | 27 | private String url; 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/com/lzhpo/chatgpt/entity/image/CreateImageVariationRequest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 lzhpo 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lzhpo.chatgpt.entity.image; 18 | 19 | import com.fasterxml.jackson.annotation.JsonInclude; 20 | import com.fasterxml.jackson.annotation.JsonProperty; 21 | import javax.validation.constraints.Max; 22 | import javax.validation.constraints.Min; 23 | import lombok.*; 24 | import lombok.experimental.SuperBuilder; 25 | 26 | /** 27 | * @author lzhpo 28 | */ 29 | @Data 30 | @SuperBuilder 31 | @NoArgsConstructor 32 | @AllArgsConstructor 33 | @JsonInclude(JsonInclude.Include.NON_NULL) 34 | public class CreateImageVariationRequest { 35 | 36 | /** 37 | * The number of images to generate. Must be between 1 and 10. 38 | */ 39 | @Min(1) 40 | @Max(10) 41 | private Integer n; 42 | 43 | /** 44 | * The size of the generated images. Must be one of 256x256, 512x512, or 1024x1024. 45 | */ 46 | private CreateImageSize size; 47 | 48 | /** 49 | * The format in which the generated images are returned. Must be one of url or b64_json. 50 | */ 51 | @JsonProperty("response_format") 52 | private CreateImageResponseFormat responseFormat; 53 | 54 | /** 55 | * A unique identifier representing your end-user, which can help OpenAI to monitor and detect abuse. 56 | * Learn more. 57 | */ 58 | private String user; 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/com/lzhpo/chatgpt/entity/model/ListModelsResponse.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 lzhpo 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lzhpo.chatgpt.entity.model; 18 | 19 | import java.util.List; 20 | import lombok.Data; 21 | 22 | /** 23 | * @author lzhpo 24 | */ 25 | @Data 26 | public class ListModelsResponse { 27 | 28 | private List data; 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/com/lzhpo/chatgpt/entity/model/ModelPermission.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 lzhpo 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lzhpo.chatgpt.entity.model; 18 | 19 | import com.fasterxml.jackson.annotation.JsonProperty; 20 | import lombok.Data; 21 | 22 | /** 23 | * @author lzhpo 24 | */ 25 | @Data 26 | public class ModelPermission { 27 | 28 | private String id; 29 | 30 | private String object; 31 | 32 | private Long created; 33 | 34 | @JsonProperty("allow_create_engine") 35 | private String allowCreateEngine; 36 | 37 | @JsonProperty("allow_sampling") 38 | private String allowSampling; 39 | 40 | @JsonProperty("allow_logprobs") 41 | private String allowLogprobs; 42 | 43 | @JsonProperty("allow_search_indices") 44 | private String allowSearchIndices; 45 | 46 | @JsonProperty("allow_view") 47 | private String allowView; 48 | 49 | @JsonProperty("allow_fine_tuning") 50 | private String allowFineTuning; 51 | 52 | private String organization; 53 | 54 | private String group; 55 | 56 | @JsonProperty("is_blocking") 57 | private Boolean blocking; 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/com/lzhpo/chatgpt/entity/model/RetrieveModelResponse.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 lzhpo 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lzhpo.chatgpt.entity.model; 18 | 19 | import com.fasterxml.jackson.annotation.JsonProperty; 20 | import java.util.List; 21 | import lombok.Data; 22 | 23 | /** 24 | * @author lzhpo 25 | */ 26 | @Data 27 | public class RetrieveModelResponse { 28 | 29 | private String id; 30 | 31 | private String object; 32 | 33 | @JsonProperty("owned_by") 34 | private String ownedBy; 35 | 36 | private List permission; 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/com/lzhpo/chatgpt/entity/moderations/ModerationCategory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 lzhpo 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lzhpo.chatgpt.entity.moderations; 18 | 19 | import com.fasterxml.jackson.annotation.JsonProperty; 20 | import lombok.Data; 21 | 22 | /** 23 | * @author lzhpo 24 | */ 25 | @Data 26 | public class ModerationCategory { 27 | 28 | private Boolean hate; 29 | 30 | @JsonProperty("hate/threatening") 31 | private Boolean threatening; 32 | 33 | @JsonProperty("self-harm") 34 | private Boolean selfHarm; 35 | 36 | private Boolean sexual; 37 | 38 | @JsonProperty("sexual/minors") 39 | private Boolean minors; 40 | 41 | private Boolean violence; 42 | 43 | @JsonProperty("violence/graphic") 44 | private Boolean graphic; 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/com/lzhpo/chatgpt/entity/moderations/ModerationCategoryScore.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 lzhpo 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lzhpo.chatgpt.entity.moderations; 18 | 19 | import com.fasterxml.jackson.annotation.JsonProperty; 20 | import java.math.BigDecimal; 21 | import lombok.Data; 22 | 23 | /** 24 | * @author lzhpo 25 | */ 26 | @Data 27 | public class ModerationCategoryScore { 28 | 29 | private BigDecimal hate; 30 | 31 | @JsonProperty("hate/threatening") 32 | private BigDecimal threatening; 33 | 34 | @JsonProperty("self-harm") 35 | private BigDecimal selfHarm; 36 | 37 | private BigDecimal sexual; 38 | 39 | @JsonProperty("sexual/minors") 40 | private BigDecimal minors; 41 | 42 | private BigDecimal violence; 43 | 44 | @JsonProperty("violence/graphic") 45 | private BigDecimal graphic; 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/com/lzhpo/chatgpt/entity/moderations/ModerationRequest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 lzhpo 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lzhpo.chatgpt.entity.moderations; 18 | 19 | import com.fasterxml.jackson.annotation.JsonInclude; 20 | import java.util.List; 21 | import javax.validation.constraints.NotBlank; 22 | import javax.validation.constraints.NotEmpty; 23 | import lombok.*; 24 | 25 | /** 26 | * @author lzhpo 27 | */ 28 | @Data 29 | @Builder 30 | @NoArgsConstructor 31 | @AllArgsConstructor 32 | @JsonInclude(JsonInclude.Include.NON_NULL) 33 | public class ModerationRequest { 34 | 35 | /** 36 | * The input text to classify. 37 | */ 38 | @NotEmpty 39 | private List input; 40 | 41 | /** 42 | * Two content moderations models are available: text-moderation-stable and text-moderation-latest. 43 | * 44 | *

The default is text-moderation-latest which will be automatically upgraded over time. 45 | * This ensures you are always using our most accurate model. 46 | * If you use text-moderation-stable, we will provide advanced notice before updating the model. 47 | * Accuracy of text-moderation-stable may be slightly lower than for text-moderation-latest. 48 | */ 49 | @NotBlank 50 | @Builder.Default 51 | private String model = "text-moderation-latest"; 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/com/lzhpo/chatgpt/entity/moderations/ModerationResponse.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 lzhpo 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lzhpo.chatgpt.entity.moderations; 18 | 19 | import java.util.List; 20 | import lombok.Data; 21 | 22 | /** 23 | * @author lzhpo 24 | */ 25 | @Data 26 | public class ModerationResponse { 27 | 28 | private String id; 29 | private String model; 30 | private List results; 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/com/lzhpo/chatgpt/entity/moderations/ModerationResult.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 lzhpo 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lzhpo.chatgpt.entity.moderations; 18 | 19 | import com.fasterxml.jackson.annotation.JsonProperty; 20 | import lombok.Data; 21 | 22 | /** 23 | * @author lzhpo 24 | */ 25 | @Data 26 | public class ModerationResult { 27 | 28 | private ModerationCategory categories; 29 | 30 | @JsonProperty("category_scores") 31 | private ModerationCategoryScore categoryScores; 32 | 33 | private Boolean flagged; 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/com/lzhpo/chatgpt/entity/users/UserData.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 lzhpo 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lzhpo.chatgpt.entity.users; 18 | 19 | import lombok.Data; 20 | 21 | /** 22 | * @author lzhpo 23 | */ 24 | @Data 25 | public class UserData { 26 | 27 | private String object; 28 | private String role; 29 | private Long created; 30 | private UserInfo user; 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/com/lzhpo/chatgpt/entity/users/UserInfo.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 lzhpo 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lzhpo.chatgpt.entity.users; 18 | 19 | import lombok.Data; 20 | 21 | /** 22 | * @author lzhpo 23 | */ 24 | @Data 25 | public class UserInfo { 26 | 27 | private String object; 28 | private String id; 29 | private String name; 30 | private String email; 31 | private String picture; 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/com/lzhpo/chatgpt/entity/users/UserMembers.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 lzhpo 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lzhpo.chatgpt.entity.users; 18 | 19 | import java.util.List; 20 | import lombok.Data; 21 | 22 | /** 23 | * @author lzhpo 24 | */ 25 | @Data 26 | public class UserMembers { 27 | 28 | private String object; 29 | private List data; 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/com/lzhpo/chatgpt/entity/users/UserResponse.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 lzhpo 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lzhpo.chatgpt.entity.users; 18 | 19 | import com.fasterxml.jackson.annotation.JsonProperty; 20 | import java.util.List; 21 | import lombok.Data; 22 | 23 | /** 24 | * @author lzhpo 25 | */ 26 | @Data 27 | public class UserResponse { 28 | 29 | private UserMembers members; 30 | 31 | private List invited; 32 | 33 | @JsonProperty("can_invite") 34 | private Boolean canInvite; 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/com/lzhpo/chatgpt/exception/InvalidedKeyEvent.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 lzhpo 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lzhpo.chatgpt.exception; 18 | 19 | import lombok.Getter; 20 | import org.springframework.context.ApplicationEvent; 21 | 22 | /** 23 | * @author lzhpo 24 | */ 25 | @Getter 26 | public class InvalidedKeyEvent extends ApplicationEvent { 27 | 28 | private final String invalidedApiKey; 29 | private final String errorResponse; 30 | 31 | public InvalidedKeyEvent(Object source, String invalidedApiKey, String errorResponse) { 32 | super(source); 33 | this.invalidedApiKey = invalidedApiKey; 34 | this.errorResponse = errorResponse; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/com/lzhpo/chatgpt/exception/NoAvailableKeyEvent.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 lzhpo 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lzhpo.chatgpt.exception; 18 | 19 | import java.util.List; 20 | import lombok.Getter; 21 | import org.springframework.context.ApplicationEvent; 22 | 23 | /** 24 | * @author lzhpo 25 | */ 26 | @Getter 27 | public class NoAvailableKeyEvent extends ApplicationEvent { 28 | 29 | private final List invalidedKeys; 30 | 31 | public NoAvailableKeyEvent(Object source, List invalidedKeys) { 32 | super(source); 33 | this.invalidedKeys = invalidedKeys; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/com/lzhpo/chatgpt/exception/OpenAiError.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 lzhpo 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lzhpo.chatgpt.exception; 18 | 19 | import lombok.Data; 20 | 21 | /** 22 | * Define the OpenAI response error. 23 | *

Reference: error-codes 24 | * 25 | * @author lzhpo 26 | */ 27 | @Data 28 | public class OpenAiError { 29 | 30 | private OpenAiErrorDetail error; 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/com/lzhpo/chatgpt/exception/OpenAiErrorCode.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 lzhpo 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lzhpo.chatgpt.exception; 18 | 19 | import cn.hutool.core.collection.ListUtil; 20 | import java.util.List; 21 | import lombok.AccessLevel; 22 | import lombok.NoArgsConstructor; 23 | 24 | /** 25 | * @author lzhpo 26 | */ 27 | @SuppressWarnings({"squid:S2386"}) 28 | @NoArgsConstructor(access = AccessLevel.PRIVATE) 29 | public final class OpenAiErrorCode { 30 | 31 | public static final String INVALID_API_KEY = "invalid_api_key"; 32 | public static final String ACCOUNT_DEACTIVATED = "account_deactivated"; 33 | public static final String INSUFFICIENT_QUOTA = "insufficient_quota"; 34 | public static final String ACCESS_TERMINATED = "access_terminated"; 35 | 36 | public static final List ROTATION_HTTP_CODES = ListUtil.of(401, 429); 37 | public static final List ROTATION_ERROR_TYPES_OR_CODES = 38 | ListUtil.of(INVALID_API_KEY, ACCOUNT_DEACTIVATED, INSUFFICIENT_QUOTA, ACCESS_TERMINATED); 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/com/lzhpo/chatgpt/exception/OpenAiErrorDetail.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 lzhpo 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lzhpo.chatgpt.exception; 18 | 19 | import lombok.Data; 20 | 21 | /** 22 | * The OpenAI response error detail. 23 | * 24 | * @author lzhpo 25 | */ 26 | @Data 27 | public class OpenAiErrorDetail { 28 | 29 | private String message; 30 | private String type; 31 | private String param; 32 | private String code; 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/com/lzhpo/chatgpt/exception/OpenAiErrorInterceptor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 lzhpo 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lzhpo.chatgpt.exception; 18 | 19 | import static com.lzhpo.chatgpt.OpenAiConstant.BEARER; 20 | import static com.lzhpo.chatgpt.exception.OpenAiErrorCode.ROTATION_ERROR_TYPES_OR_CODES; 21 | import static com.lzhpo.chatgpt.exception.OpenAiErrorCode.ROTATION_HTTP_CODES; 22 | 23 | import cn.hutool.core.util.StrUtil; 24 | import cn.hutool.extra.spring.SpringUtil; 25 | import cn.hutool.http.Header; 26 | import com.lzhpo.chatgpt.apikey.OpenAiKeyWrapper; 27 | import com.lzhpo.chatgpt.utils.JsonUtils; 28 | import java.io.IOException; 29 | import java.nio.charset.StandardCharsets; 30 | import java.util.Optional; 31 | import lombok.RequiredArgsConstructor; 32 | import lombok.extern.slf4j.Slf4j; 33 | import okhttp3.Interceptor; 34 | import okhttp3.Request; 35 | import okhttp3.Response; 36 | import okhttp3.ResponseBody; 37 | import okio.Buffer; 38 | import okio.BufferedSource; 39 | import org.springframework.util.Assert; 40 | import org.springframework.util.StringUtils; 41 | 42 | /** 43 | * @author lzhpo 44 | */ 45 | @Slf4j 46 | @RequiredArgsConstructor 47 | public class OpenAiErrorInterceptor implements Interceptor { 48 | 49 | private final OpenAiKeyWrapper openAiKeyWrapper; 50 | 51 | @Override 52 | public Response intercept(Chain chain) throws IOException { 53 | Request request = chain.request(); 54 | Response response = chain.proceed(request); 55 | int code = response.code(); 56 | String authorization = request.header(Header.AUTHORIZATION.name()); 57 | String apiKey = StrUtil.replace(authorization, BEARER, StrUtil.EMPTY); 58 | 59 | if (ROTATION_HTTP_CODES.contains(code) && StringUtils.hasText(apiKey)) { 60 | ResponseBody responseBody = response.body(); 61 | Assert.notNull(responseBody, "Resolve response body failed."); 62 | BufferedSource responseBodySource = responseBody.source(); 63 | responseBodySource.request(Long.MAX_VALUE); 64 | Buffer responseBodyBuffer = responseBodySource.getBuffer(); 65 | String responseBodyStr = responseBodyBuffer.clone().readString(StandardCharsets.UTF_8); 66 | 67 | OpenAiError openAiError = JsonUtils.parse(responseBodyStr, OpenAiError.class); 68 | Optional.ofNullable(openAiError) 69 | .map(OpenAiError::getError) 70 | .filter(openAiErrorDetail -> { 71 | String errorType = openAiErrorDetail.getType(); 72 | String errorCode = openAiErrorDetail.getCode(); 73 | return ROTATION_ERROR_TYPES_OR_CODES.contains(errorType) 74 | || ROTATION_ERROR_TYPES_OR_CODES.contains(errorCode); 75 | }) 76 | .ifPresent(errorCode -> openAiKeyWrapper.invalidKey(apiKey)); 77 | SpringUtil.publishEvent(new InvalidedKeyEvent(this, apiKey, responseBodyStr)); 78 | } 79 | 80 | return response; 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/main/java/com/lzhpo/chatgpt/exception/OpenAiException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 lzhpo 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lzhpo.chatgpt.exception; 18 | 19 | /** 20 | * @author lzhpo 21 | */ 22 | public class OpenAiException extends RuntimeException { 23 | 24 | public OpenAiException(String message) { 25 | super(message); 26 | } 27 | 28 | public OpenAiException(String message, Throwable cause) { 29 | super(message, cause); 30 | } 31 | 32 | public OpenAiException(Throwable cause) { 33 | super(cause); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/com/lzhpo/chatgpt/properties/OpenAiProperties.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 lzhpo 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lzhpo.chatgpt.properties; 18 | 19 | import com.lzhpo.chatgpt.apikey.OpenAiKey; 20 | import java.time.Duration; 21 | import java.util.*; 22 | import lombok.Data; 23 | import org.springframework.boot.context.properties.ConfigurationProperties; 24 | import org.springframework.boot.context.properties.NestedConfigurationProperty; 25 | 26 | /** 27 | * @author lzhpo 28 | */ 29 | @Data 30 | @ConfigurationProperties(prefix = "openai") 31 | public class OpenAiProperties { 32 | 33 | /** 34 | * The openAI API keys. 35 | */ 36 | private List keys = new ArrayList<>(); 37 | 38 | /** 39 | * The openAi endpoint configuration. 40 | */ 41 | private Map urls = new EnumMap<>(OpenAiUrl.class); 42 | 43 | /** 44 | * The proxy to request openAi API. 45 | */ 46 | @NestedConfigurationProperty 47 | private OpenAiProxy proxy; 48 | 49 | /** 50 | * The openAi or proxy address. 51 | */ 52 | private String domain = "https://api.openai.com"; 53 | 54 | /** 55 | * The connect timeout. 56 | */ 57 | private Duration connectTimeout = Duration.ofMinutes(1); 58 | 59 | /** 60 | * The read timeout. 61 | */ 62 | private Duration readTimeout = Duration.ofMinutes(1); 63 | 64 | /** 65 | * The write timeout. 66 | */ 67 | private Duration writeTimeout = Duration.ofMinutes(1); 68 | } 69 | -------------------------------------------------------------------------------- /src/main/java/com/lzhpo/chatgpt/properties/OpenAiProxy.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 lzhpo 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lzhpo.chatgpt.properties; 18 | 19 | import java.net.Proxy; 20 | import lombok.Data; 21 | 22 | /** 23 | * @author lzhpo 24 | */ 25 | @Data 26 | public class OpenAiProxy { 27 | 28 | /** 29 | * The proxy host. 30 | */ 31 | private String host; 32 | 33 | /** 34 | * The proxy port. 35 | */ 36 | private int port; 37 | 38 | /** 39 | * The proxy type. 40 | */ 41 | private Proxy.Type type; 42 | 43 | /** 44 | * The username. 45 | */ 46 | private String username; 47 | 48 | /** 49 | * The password. 50 | */ 51 | private String password; 52 | 53 | /** 54 | * The header name to provide to proxy server. 55 | */ 56 | private String headerName = "Proxy-Authorization"; 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/com/lzhpo/chatgpt/properties/OpenAiUrl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 lzhpo 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lzhpo.chatgpt.properties; 18 | 19 | import lombok.AllArgsConstructor; 20 | import lombok.Getter; 21 | 22 | /** 23 | * @author lzhpo 24 | */ 25 | @Getter 26 | @AllArgsConstructor 27 | public enum OpenAiUrl { 28 | 29 | /** 30 | * Create moderation API. 31 | */ 32 | MODERATIONS("POST", "/v1/moderations"), 33 | 34 | /** 35 | * Create completion API. 36 | */ 37 | COMPLETIONS("POST", "/v1/completions"), 38 | 39 | /** 40 | * Create edit API. 41 | */ 42 | EDITS("POST", "/v1/edits"), 43 | 44 | /** 45 | * Create chat completion API. 46 | */ 47 | CHAT_COMPLETIONS("POST", "/v1/chat/completions"), 48 | 49 | /** 50 | * List models API. 51 | */ 52 | LIST_MODELS("GET", "/v1/models"), 53 | 54 | /** 55 | * Retrieve model by {@code modelId} API. 56 | */ 57 | RETRIEVE_MODEL("GET", "/v1/models/{model}"), 58 | 59 | /** 60 | * Create embeddings API. 61 | */ 62 | EMBEDDINGS("POST", "/v1/embeddings"), 63 | 64 | /** 65 | * List files API. 66 | */ 67 | LIST_FILES("GET", "/v1/files"), 68 | 69 | /** 70 | * Upload file API. 71 | */ 72 | UPLOAD_FILE("POST", "/v1/files"), 73 | 74 | /** 75 | * Delete file API. 76 | */ 77 | DELETE_FILE("DELETE", "/v1/files/{file_id}"), 78 | 79 | /** 80 | * Retrieve file API. 81 | */ 82 | RETRIEVE_FILE("GET", "/v1/files/{file_id}"), 83 | 84 | /** 85 | * Retrieve file content API. 86 | */ 87 | RETRIEVE_FILE_CONTENT("GET", "/v1/files/{file_id}/content"), 88 | 89 | /** 90 | * Create fine-tune API. 91 | */ 92 | CREATE_FINE_TUNE("POST", "/v1/fine-tunes"), 93 | 94 | /** 95 | * List fine-tune API. 96 | */ 97 | LIST_FINE_TUNE("GET", "/v1/fine-tunes"), 98 | 99 | /** 100 | * Retrieve fine-tune API. 101 | */ 102 | RETRIEVE_FINE_TUNE("GET", "/v1/fine-tunes/{fine_tune_id}"), 103 | 104 | /** 105 | * Cancel fine-tune API. 106 | */ 107 | CANCEL_FINE_TUNE("POST", "/v1/fine-tunes/{fine_tune_id}/cancel"), 108 | 109 | /** 110 | * List fine-tune events API. 111 | */ 112 | LIST_FINE_TUNE_EVENTS("GET", "/v1/fine-tunes/{fine_tune_id}/events"), 113 | 114 | /** 115 | * Delete fine-tune events API. 116 | */ 117 | DELETE_FINE_TUNE_EVENTS("DELETE", "/v1/models/{model}"), 118 | 119 | /** 120 | * Create transcription API. 121 | */ 122 | CREATE_TRANSCRIPTION("POST", "/v1/audio/transcriptions"), 123 | 124 | /** 125 | * Create translation API. 126 | */ 127 | CREATE_TRANSLATION("POST", "/v1/audio/translations"), 128 | 129 | /** 130 | * Create image API. 131 | */ 132 | CREATE_IMAGE("POST", "/v1/images/generations"), 133 | 134 | /** 135 | * Create image edit API. 136 | */ 137 | CREATE_IMAGE_EDIT("POST", "/v1/images/edits"), 138 | 139 | /** 140 | * Create image variation API. 141 | */ 142 | CREATE_IMAGE_VARIATION("POST", "/v1/images/variations"), 143 | 144 | /** 145 | * Query billing credit grants API. 146 | */ 147 | BILLING_CREDIT_GRANTS("GET", "/dashboard/billing/credit_grants"), 148 | 149 | /** 150 | * Query credit grants from openAi API. 151 | */ 152 | USERS("GET", "/v1/organizations/{organizationId}/users"), 153 | 154 | /** 155 | * Query billing subscription API. 156 | */ 157 | BILLING_SUBSCRIPTION("GET", "/v1/dashboard/billing/subscription"), 158 | 159 | /** 160 | * Query billing usage API. 161 | */ 162 | BILLING_USAGE("GET", "/v1/dashboard/billing/usage?start_date={start_date}&end_date={end_date}"); 163 | 164 | /** 165 | * Request http method. 166 | */ 167 | private final String method; 168 | 169 | /** 170 | * Request url suffix. 171 | */ 172 | private final String suffix; 173 | } 174 | -------------------------------------------------------------------------------- /src/main/java/com/lzhpo/chatgpt/sse/AbstractEventSourceListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 lzhpo 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lzhpo.chatgpt.sse; 18 | 19 | import com.lzhpo.chatgpt.exception.OpenAiException; 20 | import java.nio.charset.StandardCharsets; 21 | import java.util.Optional; 22 | import lombok.extern.slf4j.Slf4j; 23 | import okhttp3.Response; 24 | import okhttp3.ResponseBody; 25 | import okhttp3.sse.EventSource; 26 | import okhttp3.sse.EventSourceListener; 27 | import okio.BufferedSource; 28 | 29 | /** 30 | * Abstract listener for Server-Sent Events. 31 | * 32 | * @author lzhpo 33 | */ 34 | @Slf4j 35 | public class AbstractEventSourceListener extends EventSourceListener { 36 | 37 | @Override 38 | public void onClosed(EventSource eventSource) { 39 | log.debug("Execute onClosed method."); 40 | } 41 | 42 | @Override 43 | public void onEvent(EventSource eventSource, String id, String type, String data) { 44 | log.debug("Execute onEvent method."); 45 | log.debug("id: {}, type: {}, data: {}", id, type, data); 46 | } 47 | 48 | @Override 49 | public void onFailure(EventSource eventSource, Throwable e, Response response) { 50 | String errorMsg = Optional.ofNullable(e) 51 | .map(Throwable::getMessage) 52 | .orElse(Optional.ofNullable(response) 53 | .map(Response::body) 54 | .map(ResponseBody::source) 55 | .map(bufferedSource -> { 56 | try { 57 | bufferedSource.request(Long.MAX_VALUE); 58 | } catch (Exception ex) { 59 | throw new OpenAiException(ex); 60 | } 61 | return bufferedSource; 62 | }) 63 | .map(BufferedSource::getBuffer) 64 | .map(buffer -> buffer.clone().readString(StandardCharsets.UTF_8)) 65 | .orElse("Unexpected exception")); 66 | throw new OpenAiException(errorMsg); 67 | } 68 | 69 | @Override 70 | public void onOpen(EventSource eventSource, Response response) { 71 | log.debug("Execute onOpen method, response: {}", response); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/main/java/com/lzhpo/chatgpt/sse/CountDownLatchEventSourceListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 lzhpo 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lzhpo.chatgpt.sse; 18 | 19 | import java.util.concurrent.CountDownLatch; 20 | import lombok.extern.slf4j.Slf4j; 21 | import okhttp3.Response; 22 | import okhttp3.sse.EventSource; 23 | import org.springframework.util.Assert; 24 | 25 | /** 26 | * {@link CountDownLatch} with Server-Sent Events. 27 | * 28 | * @author lzhpo 29 | */ 30 | @Slf4j 31 | public class CountDownLatchEventSourceListener extends AbstractEventSourceListener { 32 | 33 | private final CountDownLatch countDownLatch; 34 | 35 | public CountDownLatchEventSourceListener(CountDownLatch countDownLatch) { 36 | Assert.notNull(countDownLatch, "countDownLatch cannot null."); 37 | this.countDownLatch = countDownLatch; 38 | } 39 | 40 | @Override 41 | public void onClosed(EventSource eventSource) { 42 | super.onClosed(eventSource); 43 | eventSource.cancel(); 44 | countDownLatch.countDown(); 45 | } 46 | 47 | @Override 48 | public void onFailure(EventSource eventSource, Throwable e, Response response) { 49 | eventSource.cancel(); 50 | countDownLatch.countDown(); 51 | super.onFailure(eventSource, e, response); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/com/lzhpo/chatgpt/sse/SseEventSourceListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 lzhpo 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lzhpo.chatgpt.sse; 18 | 19 | import lombok.SneakyThrows; 20 | import lombok.extern.slf4j.Slf4j; 21 | import okhttp3.sse.EventSource; 22 | import org.springframework.util.Assert; 23 | import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; 24 | 25 | /** 26 | * {@link SseEmitter} with Server-Sent Events. 27 | * 28 | * @author lzhpo 29 | */ 30 | @Slf4j 31 | public class SseEventSourceListener extends AbstractEventSourceListener { 32 | 33 | private final SseEmitter sseEmitter; 34 | 35 | public SseEventSourceListener(SseEmitter sseEmitter) { 36 | Assert.notNull(sseEmitter, "sseEmitter cannot null."); 37 | this.sseEmitter = sseEmitter; 38 | } 39 | 40 | @Override 41 | @SneakyThrows 42 | public void onEvent(EventSource eventSource, String id, String type, String data) { 43 | super.onEvent(eventSource, id, type, data); 44 | sseEmitter.send(data); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/com/lzhpo/chatgpt/sse/WebSocketEventSourceListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 lzhpo 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lzhpo.chatgpt.sse; 18 | 19 | import javax.websocket.Session; 20 | import lombok.SneakyThrows; 21 | import lombok.extern.slf4j.Slf4j; 22 | import okhttp3.sse.EventSource; 23 | import org.springframework.util.Assert; 24 | 25 | /** 26 | * WebSocket with Server-Sent Events. 27 | * 28 | * @author lzhpo 29 | */ 30 | @Slf4j 31 | public class WebSocketEventSourceListener extends AbstractEventSourceListener { 32 | 33 | private final Session session; 34 | 35 | public WebSocketEventSourceListener(Session session) { 36 | Assert.notNull(session, "WebSocket session cannot null."); 37 | this.session = session; 38 | } 39 | 40 | @Override 41 | @SneakyThrows 42 | public void onEvent(EventSource eventSource, String id, String type, String data) { 43 | super.onEvent(eventSource, id, type, data); 44 | session.getBasicRemote().sendText(data); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/com/lzhpo/chatgpt/utils/JsonUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 lzhpo 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lzhpo.chatgpt.utils; 18 | 19 | import com.fasterxml.jackson.databind.DeserializationFeature; 20 | import com.fasterxml.jackson.databind.JsonNode; 21 | import com.fasterxml.jackson.databind.ObjectMapper; 22 | import com.fasterxml.jackson.databind.SerializationFeature; 23 | import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; 24 | import java.util.List; 25 | import lombok.SneakyThrows; 26 | import lombok.experimental.UtilityClass; 27 | 28 | /** 29 | * @author lzhpo 30 | */ 31 | @UtilityClass 32 | public class JsonUtils { 33 | 34 | private static ObjectMapper mapper = new ObjectMapper(); 35 | 36 | static { 37 | mapper.registerModule(new JavaTimeModule()); 38 | mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); 39 | mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); 40 | } 41 | 42 | /** 43 | * Replace the default {@link JsonUtils#mapper}. 44 | * 45 | * @param mapper {@link ObjectMapper} 46 | */ 47 | public static void setMapper(ObjectMapper mapper) { 48 | JsonUtils.mapper = mapper; 49 | } 50 | 51 | /** 52 | * Object to json string and format and beautify 53 | * 54 | * @param obj the object for which Json representation is to be created setting for Gson 55 | * @return the pretty json text of object. 56 | */ 57 | @SneakyThrows 58 | public static String toJsonPrettyString(T obj) { 59 | return mapper.writerWithDefaultPrettyPrinter().writeValueAsString(obj); 60 | } 61 | 62 | /** 63 | * Parses the specified JSON string to a JsonNode 64 | * 65 | * @param json JSON content to parse to build the JSON tree. 66 | * @return a JsonNode, if valid JSON content found; null if input has no content to bind 67 | */ 68 | @SneakyThrows 69 | public static JsonNode toJsonNode(String json) { 70 | return mapper.readTree(json); 71 | } 72 | 73 | /** 74 | * Serializes the specified object to Json text. 75 | * 76 | * @param object the object for which Json representation is to be created setting for Gson 77 | * @return the json text of object. 78 | */ 79 | @SneakyThrows 80 | public static String toJsonString(Object object) { 81 | return mapper.writeValueAsString(object); 82 | } 83 | 84 | /** 85 | * Parse the JsonNode into an object of the specified type. 86 | * 87 | * @param jsonNode the JsonNode object 88 | * @param valueType the class of the desired object 89 | * @param the type of the desired object 90 | * @return an object of type T 91 | */ 92 | @SneakyThrows 93 | public static T parse(JsonNode jsonNode, Class valueType) { 94 | return mapper.treeToValue(jsonNode, valueType); 95 | } 96 | 97 | /** 98 | * Parse the json string into an object of the specified type. 99 | * 100 | * @param content the json string 101 | * @param valueType the class of the desired object 102 | * @param the type of the desired object 103 | * @return an object of type T 104 | */ 105 | @SneakyThrows 106 | public static T parse(String content, Class valueType) { 107 | return mapper.readValue(content, valueType); 108 | } 109 | 110 | /** 111 | * Convert json {@code content} into a collection of required objects 112 | * 113 | * @param content the json string 114 | * @param valueType the class of the desired object 115 | * @param the type of the desired object 116 | * @return List of type T 117 | */ 118 | @SneakyThrows 119 | public static List parseArray(String content, Class valueType) { 120 | return mapper.readValue(content, mapper.getTypeFactory().constructCollectionType(List.class, valueType)); 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /src/main/java/com/lzhpo/chatgpt/utils/TokenUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 lzhpo 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lzhpo.chatgpt.utils; 18 | 19 | import com.knuddels.jtokkit.Encodings; 20 | import com.knuddels.jtokkit.api.Encoding; 21 | import com.knuddels.jtokkit.api.EncodingRegistry; 22 | import com.knuddels.jtokkit.api.ModelType; 23 | import com.lzhpo.chatgpt.entity.chat.ChatCompletionMessage; 24 | import com.lzhpo.chatgpt.exception.OpenAiException; 25 | import java.util.HashMap; 26 | import java.util.List; 27 | import java.util.Map; 28 | import java.util.function.ToIntFunction; 29 | import lombok.experimental.UtilityClass; 30 | import lombok.extern.slf4j.Slf4j; 31 | import org.springframework.util.Assert; 32 | import org.springframework.util.StringUtils; 33 | 34 | /** 35 | * How_to_count_tokens_with_tiktoken 36 | *

 37 |  * {@code
 38 |  *   def num_tokens_from_messages(messages, model="gpt-3.5-turbo-0301"):
 39 |  *     """Returns the number of tokens used by a list of messages."""
 40 |  *     try:
 41 |  *         encoding = tiktoken.encoding_for_model(model)
 42 |  *     except KeyError:
 43 |  *         print("Warning: model not found. Using cl100k_base encoding.")
 44 |  *         encoding = tiktoken.get_encoding("cl100k_base")
 45 |  *     if model == "gpt-3.5-turbo":
 46 |  *         print("Warning: gpt-3.5-turbo may change over time. Returning num tokens assuming gpt-3.5-turbo-0301.")
 47 |  *         return num_tokens_from_messages(messages, model="gpt-3.5-turbo-0301")
 48 |  *     elif model == "gpt-4":
 49 |  *         print("Warning: gpt-4 may change over time. Returning num tokens assuming gpt-4-0314.")
 50 |  *         return num_tokens_from_messages(messages, model="gpt-4-0314")
 51 |  *     elif model == "gpt-3.5-turbo-0301":
 52 |  *         tokens_per_message = 4  # every message follows <|start|>{role/name}\n{content}<|end|>\n
 53 |  *         tokens_per_name = -1  # if there's a name, the role is omitted
 54 |  *     elif model == "gpt-4-0314":
 55 |  *         tokens_per_message = 3
 56 |  *         tokens_per_name = 1
 57 |  *     else:
 58 |  *         raise NotImplementedError(f"""num_tokens_from_messages() is not implemented for model {model}. See https://github.com/openai/openai-python/blob/main/chatml.md for information on how messages are converted to tokens.""")
 59 |  *     num_tokens = 0
 60 |  *     for message in messages:
 61 |  *         num_tokens += tokens_per_message
 62 |  *         for key, value in message.items():
 63 |  *             num_tokens += len(encoding.encode(value))
 64 |  *             if key == "name":
 65 |  *                 num_tokens += tokens_per_name
 66 |  *     num_tokens += 3  # every reply is primed with <|start|>assistant<|message|>
 67 |  *     return num_tokens
 68 |  * }
 69 |  * 
70 | * 71 | * 72 | * @author lzhpo 73 | */ 74 | @Slf4j 75 | @UtilityClass 76 | public class TokenUtils { 77 | 78 | private static final int REPLY_PRIMED_NUM = 3; 79 | private static final EncodingRegistry REGISTRY = Encodings.newDefaultEncodingRegistry(); 80 | private static final Map> PER_MODEL_MAP = new HashMap<>(4); 81 | 82 | static { 83 | PER_MODEL_MAP.put("gpt-3.5-turbo", name -> 4 + (StringUtils.hasText(name) ? -1 : 0)); 84 | PER_MODEL_MAP.put("gpt-3.5-turbo-0301", name -> 4 + (StringUtils.hasText(name) ? -1 : 0)); 85 | PER_MODEL_MAP.put("gpt-4", name -> 3 + (StringUtils.hasText(name) ? 1 : 0)); 86 | PER_MODEL_MAP.put("gpt-4-0314", name -> 3 + (StringUtils.hasText(name) ? 1 : 0)); 87 | } 88 | 89 | /** 90 | * Get the {@link #REGISTRY}. 91 | * 92 | * @return {@link EncodingRegistry} 93 | */ 94 | public static EncodingRegistry getRegistry() { 95 | return REGISTRY; 96 | } 97 | 98 | /** 99 | * Returns the encoding that is used for the given model type. 100 | * 101 | * @param modelType {@link ModelType} 102 | * @return the encoding 103 | */ 104 | public static Encoding getEncoding(ModelType modelType) { 105 | return getRegistry().getEncodingForModel(modelType); 106 | } 107 | 108 | /** 109 | * Encodes the {@code content} into a list of token ids and returns the amount of tokens. 110 | * 111 | * @param modelType {@link ModelType} 112 | * @param content content 113 | * @return the tokens 114 | */ 115 | public static Long tokens(ModelType modelType, String content) { 116 | Encoding encoding = getEncoding(modelType); 117 | return (long) encoding.countTokens(content); 118 | } 119 | 120 | /** 121 | * Encodes the {@code content} into a list of token ids and returns the amount of tokens. 122 | * 123 | * @param modelTypeName {@link ModelType} name 124 | * @param content content 125 | * @return the tokens 126 | */ 127 | public static Long tokens(String modelTypeName, String content) { 128 | ModelType modelType = ModelType.fromName(modelTypeName) 129 | .orElseThrow(() -> new OpenAiException("Unknown model " + modelTypeName)); 130 | return tokens(modelType, content); 131 | } 132 | 133 | /** 134 | * Encodes the {@code messages} into a list of token ids and returns the amount of tokens. 135 | * 136 | * @param model model 137 | * @param messages messages 138 | * @return tokens 139 | */ 140 | public static Long tokens(String model, List messages) { 141 | Assert.hasText(model, "model cannot empty."); 142 | Assert.notEmpty(messages, "messages cannot empty."); 143 | return REPLY_PRIMED_NUM 144 | + messages.stream() 145 | .map(message -> { 146 | String name = message.getName(); 147 | ToIntFunction handler = PER_MODEL_MAP.getOrDefault(model, x -> 0); 148 | return handler.applyAsInt(name) 149 | + tokens(model, name) 150 | + tokens(model, message.getRole()) 151 | + tokens(model, message.getContent()); 152 | }) 153 | .mapToLong(Long::longValue) 154 | .sum(); 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /src/main/resources/META-INF/spring.factories: -------------------------------------------------------------------------------- 1 | org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ 2 | com.lzhpo.chatgpt.OpenAiAutoConfiguration -------------------------------------------------------------------------------- /src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports: -------------------------------------------------------------------------------- 1 | com.lzhpo.chatgpt.OpenAiAutoConfiguration -------------------------------------------------------------------------------- /src/test/java/com/lzhpo/chatgpt/InnerOpenAiKeyProvider.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 lzhpo 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lzhpo.chatgpt; 18 | 19 | import com.lzhpo.chatgpt.apikey.OpenAiKey; 20 | import com.lzhpo.chatgpt.apikey.OpenAiKeyProvider; 21 | import java.util.ArrayList; 22 | import java.util.HashMap; 23 | import java.util.List; 24 | import java.util.Map; 25 | import lombok.extern.slf4j.Slf4j; 26 | 27 | /** 28 | * @author lzhpo 29 | */ 30 | @Slf4j 31 | public class InnerOpenAiKeyProvider implements OpenAiKeyProvider { 32 | 33 | private int controlNum; 34 | private static final Map> OPEN_AI_KEYS_MAP = new HashMap<>(); 35 | 36 | static { 37 | // spotless:off 38 | List openAiKeys1 = new ArrayList<>(); 39 | openAiKeys1.add(OpenAiKey.builder().key("sk-xxx1").weight(1.0).enabled(true).build()); 40 | OPEN_AI_KEYS_MAP.put(1, openAiKeys1); 41 | 42 | List openAiKeys2 = new ArrayList<>(); 43 | openAiKeys2.add(OpenAiKey.builder().key("sk-xxx2").weight(2.0).enabled(true).build()); 44 | OPEN_AI_KEYS_MAP.put(2, openAiKeys2); 45 | 46 | List openAiKeys3 = new ArrayList<>(); 47 | openAiKeys3.add(OpenAiKey.builder().key("sk-xxx").weight(666.0).enabled(true).build()); 48 | OPEN_AI_KEYS_MAP.put(3, openAiKeys3); 49 | 50 | List openAiKeys4 = new ArrayList<>(); 51 | openAiKeys4.add(OpenAiKey.builder().key("sk-xxx").weight(666.0).enabled(true).build()); 52 | OPEN_AI_KEYS_MAP.put(4, openAiKeys4); 53 | // spotless:on 54 | } 55 | 56 | @Override 57 | public List get() { 58 | return OPEN_AI_KEYS_MAP.get(Math.min(++controlNum, 4)); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/test/java/com/lzhpo/chatgpt/OpenAiCountTokensTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 lzhpo 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lzhpo.chatgpt; 18 | 19 | import static org.junit.jupiter.api.Assertions.assertEquals; 20 | import static org.junit.jupiter.api.Assertions.assertNotNull; 21 | 22 | import cn.hutool.core.lang.Console; 23 | import com.lzhpo.chatgpt.entity.CommonUsage; 24 | import com.lzhpo.chatgpt.entity.chat.ChatCompletionMessage; 25 | import com.lzhpo.chatgpt.entity.chat.ChatCompletionRequest; 26 | import com.lzhpo.chatgpt.entity.chat.ChatCompletionResponse; 27 | import com.lzhpo.chatgpt.entity.completions.CompletionRequest; 28 | import com.lzhpo.chatgpt.entity.completions.CompletionResponse; 29 | import com.lzhpo.chatgpt.utils.JsonUtils; 30 | import com.lzhpo.chatgpt.utils.TokenUtils; 31 | import java.util.ArrayList; 32 | import java.util.List; 33 | import org.junit.jupiter.api.Test; 34 | import org.springframework.beans.factory.annotation.Autowired; 35 | import org.springframework.boot.test.context.SpringBootTest; 36 | import org.springframework.boot.test.mock.mockito.MockBean; 37 | import org.springframework.web.socket.server.standard.ServerEndpointExporter; 38 | 39 | /** 40 | * @author lzhpo 41 | */ 42 | @SpringBootTest 43 | class OpenAiCountTokensTest { 44 | 45 | @Autowired 46 | private OpenAiClient openAiService; 47 | 48 | @MockBean 49 | private ServerEndpointExporter serverEndpointExporter; 50 | 51 | @Test 52 | void completionsTokens() { 53 | CompletionRequest request = new CompletionRequest(); 54 | request.setModel("text-davinci-003"); 55 | request.setPrompt("As an AI language model, I have generated this response by receiving your input."); 56 | request.setMaxTokens(7); 57 | request.setTemperature(0); 58 | 59 | Long reqTokens = TokenUtils.tokens(request.getModel(), request.getPrompt()); 60 | Console.log("Count tokens for request: {}", reqTokens); 61 | 62 | CompletionResponse response = openAiService.completions(request); 63 | assertNotNull(response); 64 | 65 | CommonUsage usage = response.getUsage(); 66 | Long promptTokens = usage.getPromptTokens(); 67 | Console.log("Prompt tokens: {}", promptTokens); 68 | Console.log("Completion tokens: {}", usage.getCompletionTokens()); 69 | Console.log("Total tokens: {}", usage.getTotalTokens()); 70 | 71 | assertEquals(promptTokens, reqTokens); 72 | Console.log(JsonUtils.toJsonPrettyString(response)); 73 | } 74 | 75 | @Test 76 | void chatCompletionsTokens() { 77 | List messages = new ArrayList<>(); 78 | 79 | ChatCompletionMessage message1 = new ChatCompletionMessage(); 80 | message1.setRole("user"); 81 | message1.setContent("What's your name?"); 82 | messages.add(message1); 83 | 84 | ChatCompletionMessage message2 = new ChatCompletionMessage(); 85 | message2.setRole("user"); 86 | message2.setContent("How old are you?"); 87 | messages.add(message2); 88 | 89 | ChatCompletionRequest request = new ChatCompletionRequest(); 90 | request.setModel("gpt-3.5-turbo"); 91 | request.setMessages(messages); 92 | 93 | Long reqTokens = TokenUtils.tokens(request.getModel(), request.getMessages()); 94 | Console.log("Count input tokens: {}", reqTokens); 95 | 96 | ChatCompletionResponse response = openAiService.chatCompletions(request); 97 | assertNotNull(response); 98 | 99 | CommonUsage usage = response.getUsage(); 100 | assertNotNull(usage); 101 | Long promptTokens = usage.getPromptTokens(); 102 | Console.log("Prompt tokens: {}", promptTokens); 103 | Console.log("Completion tokens: {}", usage.getCompletionTokens()); 104 | Console.log("Total tokens: {}", usage.getTotalTokens()); 105 | 106 | Console.log(JsonUtils.toJsonPrettyString(response)); 107 | assertEquals(promptTokens, reqTokens); 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /src/test/java/com/lzhpo/chatgpt/OpenAiEventListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 lzhpo 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lzhpo.chatgpt; 18 | 19 | import com.lzhpo.chatgpt.exception.InvalidedKeyEvent; 20 | import com.lzhpo.chatgpt.exception.NoAvailableKeyEvent; 21 | import java.util.List; 22 | import lombok.extern.slf4j.Slf4j; 23 | import org.springframework.context.event.EventListener; 24 | import org.springframework.stereotype.Component; 25 | 26 | /** 27 | * @author lzhpo 28 | */ 29 | @Slf4j 30 | @Component 31 | public class OpenAiEventListener { 32 | 33 | @EventListener 34 | public void processInvalidedKey(InvalidedKeyEvent event) { 35 | String invalidedApiKey = event.getInvalidedApiKey(); 36 | String errorResponse = event.getErrorResponse(); 37 | log.error("Processing invalidedApiKey={} event, errorResponse: {}", invalidedApiKey, errorResponse); 38 | } 39 | 40 | @EventListener 41 | public void processNoAvailableKey(NoAvailableKeyEvent event) { 42 | List invalidedKeys = event.getInvalidedKeys(); 43 | log.error("Processing noAvailableKey event, invalidedKeys={}", invalidedKeys); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/test/java/com/lzhpo/chatgpt/OpenAiKeyProviderTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 lzhpo 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lzhpo.chatgpt; 18 | 19 | import static org.junit.jupiter.api.Assertions.assertNotNull; 20 | 21 | import cn.hutool.core.lang.Console; 22 | import com.lzhpo.chatgpt.entity.model.ListModelsResponse; 23 | import com.lzhpo.chatgpt.entity.model.RetrieveModelResponse; 24 | import java.util.List; 25 | import org.junit.jupiter.api.Test; 26 | import org.springframework.beans.factory.annotation.Autowired; 27 | import org.springframework.boot.test.context.SpringBootTest; 28 | import org.springframework.boot.test.mock.mockito.MockBean; 29 | import org.springframework.context.annotation.Import; 30 | import org.springframework.web.socket.server.standard.ServerEndpointExporter; 31 | 32 | /** 33 | * @author lzhpo 34 | */ 35 | @SpringBootTest 36 | @Import({InnerOpenAiKeyProvider.class}) 37 | class OpenAiKeyProviderTest { 38 | 39 | @Autowired 40 | private OpenAiClient openAiService; 41 | 42 | @MockBean 43 | private ServerEndpointExporter serverEndpointExporter; 44 | 45 | @Test 46 | void models() { 47 | ListModelsResponse modelsResponse = openAiService.models(); 48 | assertNotNull(modelsResponse); 49 | List modelsResponseData = modelsResponse.getData(); 50 | assertNotNull(modelsResponse); 51 | Console.log("Get the model size: {}", modelsResponseData.size()); 52 | 53 | // test LFU cache 54 | for (int j = 0; j < Math.min(modelsResponseData.size(), 20); j++) { 55 | RetrieveModelResponse modelEntry = modelsResponseData.get(j); 56 | RetrieveModelResponse retrieveModelResponse = openAiService.retrieveModel(modelEntry.getId()); 57 | assertNotNull(retrieveModelResponse); 58 | Console.log("modelId: {}", retrieveModelResponse.getId()); 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/test/java/com/lzhpo/chatgpt/OpenAiTestApplication.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 lzhpo 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lzhpo.chatgpt; 18 | 19 | import org.springframework.boot.SpringApplication; 20 | import org.springframework.boot.autoconfigure.SpringBootApplication; 21 | import org.springframework.context.annotation.Bean; 22 | import org.springframework.web.socket.server.standard.ServerEndpointExporter; 23 | 24 | /** 25 | * @author lzhpo 26 | */ 27 | @SpringBootApplication 28 | public class OpenAiTestApplication { 29 | 30 | public static void main(String[] args) { 31 | SpringApplication.run(OpenAiTestApplication.class, args); 32 | } 33 | 34 | @Bean 35 | public ServerEndpointExporter serverEndpointExporter() { 36 | return new ServerEndpointExporter(); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/test/java/com/lzhpo/chatgpt/OpenAiTestController.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 lzhpo 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lzhpo.chatgpt; 18 | 19 | import com.lzhpo.chatgpt.apikey.OpenAiKeyWrapper; 20 | import com.lzhpo.chatgpt.entity.chat.ChatCompletionRequest; 21 | import com.lzhpo.chatgpt.entity.chat.ChatCompletionResponse; 22 | import com.lzhpo.chatgpt.sse.SseEventSourceListener; 23 | import lombok.RequiredArgsConstructor; 24 | import lombok.extern.slf4j.Slf4j; 25 | import org.springframework.stereotype.Controller; 26 | import org.springframework.web.bind.annotation.*; 27 | import org.springframework.web.servlet.ModelAndView; 28 | import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; 29 | 30 | /** 31 | * @author lzhpo 32 | */ 33 | @Slf4j 34 | @Controller 35 | @RequestMapping("/") 36 | @RequiredArgsConstructor 37 | public class OpenAiTestController { 38 | 39 | private final OpenAiClient openAiClient; 40 | private final OpenAiKeyWrapper openAiKeyWrapper; 41 | 42 | @GetMapping("/page/chat") 43 | public ModelAndView chatView() { 44 | ModelAndView view = new ModelAndView("chat"); 45 | view.addObject("apiKey", openAiKeyWrapper.wrap().next()); 46 | return view; 47 | } 48 | 49 | @GetMapping("/page/chat/sse") 50 | public ModelAndView sseChatView() { 51 | return new ModelAndView("sse-stream-chat"); 52 | } 53 | 54 | @GetMapping("/page/chat/websocket") 55 | public ModelAndView websocketChatView() { 56 | return new ModelAndView("websocket-stream-chat"); 57 | } 58 | 59 | @ResponseBody 60 | @PostMapping("/chat") 61 | public ChatCompletionResponse chatCompletions(@RequestBody ChatCompletionRequest request) { 62 | return openAiClient.chatCompletions(request); 63 | } 64 | 65 | @ResponseBody 66 | @GetMapping("/chat/sse") 67 | public SseEmitter sseStreamChat(@RequestParam String message) { 68 | SseEmitter sseEmitter = new SseEmitter(); 69 | ChatCompletionRequest request = ChatCompletionRequest.create(message); 70 | openAiClient.streamChatCompletions(request, new SseEventSourceListener(sseEmitter)); 71 | return sseEmitter; 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/test/java/com/lzhpo/chatgpt/OpenAiWebSocketTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 lzhpo 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lzhpo.chatgpt; 18 | 19 | import cn.hutool.extra.spring.SpringUtil; 20 | import com.lzhpo.chatgpt.entity.chat.ChatCompletionRequest; 21 | import com.lzhpo.chatgpt.exception.OpenAiException; 22 | import com.lzhpo.chatgpt.sse.WebSocketEventSourceListener; 23 | import javax.websocket.*; 24 | import javax.websocket.server.ServerEndpoint; 25 | import lombok.extern.slf4j.Slf4j; 26 | import org.springframework.stereotype.Component; 27 | 28 | /** 29 | * @author lzhpo 30 | */ 31 | @Slf4j 32 | @Component 33 | @ServerEndpoint("/chat/websocket") 34 | public class OpenAiWebSocketTest { 35 | 36 | @OnOpen 37 | public void onOpen(Session session) { 38 | log.info("sessionId={} joined.", session.getId()); 39 | } 40 | 41 | @OnMessage 42 | public void onMessage(Session session, String message) { 43 | log.info("Received sessionId={} message={}", session.getId(), message); 44 | ChatCompletionRequest request = ChatCompletionRequest.create(message); 45 | WebSocketEventSourceListener listener = new WebSocketEventSourceListener(session); 46 | SpringUtil.getBean(OpenAiClient.class).streamChatCompletions(request, listener); 47 | } 48 | 49 | @OnClose 50 | public void onClose(Session session) { 51 | log.info("Closed sessionId={} connection.", session.getId()); 52 | } 53 | 54 | @OnError 55 | public void onError(Session session, Throwable e) { 56 | log.error("sessionId={} error: {}", session.getId(), e.getMessage(), e); 57 | throw new OpenAiException(e.getMessage()); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/test/resources/application.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 6060 3 | 4 | logging: 5 | level: 6 | com.lzhpo: debug 7 | 8 | openai: 9 | keys: 10 | - key: "sk-xxx1" 11 | weight: 1.0 12 | enabled: true 13 | - key: "sk-xxx2" 14 | weight: 2.0 15 | enabled: true 16 | - key: "sk-xxx3" 17 | weight: 3.0 18 | enabled: true 19 | # domain: "https://api.openai.com" 20 | # urls: 21 | # moderations: "https://api.openai.com/v1/moderations" 22 | # completions: "https://api.openai.com/v1/completions" 23 | # edits: "https://api.openai.com/v1/edits" 24 | # chat-completions: "https://api.openai.com/v1/chat/completions" 25 | # list-models: "https://api.openai.com/v1/models" 26 | # retrieve-model: "https://api.openai.com/v1/models/{model}" 27 | # embeddings: "https://api.openai.com/v1/embeddings" 28 | # list-files: "https://api.openai.com/v1/files" 29 | # upload-file: "https://api.openai.com/v1/files" 30 | # delete-file: "https://api.openai.com/v1/files/{file_id}" 31 | # retrieve-file: "https://api.openai.com/v1/files/{file_id}" 32 | # retrieve-file-content: "https://api.openai.com/v1/files/{file_id}/content" 33 | # create_fine_tune: "https://api.openai.com/v1/fine-tunes" 34 | # list_fine_tune: "https://api.openai.com/v1/fine-tunes" 35 | # retrieve_fine_tune: "https://api.openai.com/v1/fine-tunes/{fine_tune_id}" 36 | # cancel_fine_tune: "https://api.openai.com/v1/fine-tunes/{fine_tune_id}/cancel" 37 | # list_fine_tune_events: "https://api.openai.com/v1/fine-tunes/{fine_tune_id}/events" 38 | # delete_fine_tune_events: "https://api.openai.com/v1/models/{model}" 39 | # create-transcription: "https://api.openai.com/v1/audio/transcriptions" 40 | # create-translation: "https://api.openai.com/v1/audio/translations" 41 | # create_image: "https://api.openai.com/v1/images/generations" 42 | # create_image_edit: "https://api.openai.com/v1/images/edits" 43 | # create_image_variation: "https://api.openai.com/v1/images/variations" 44 | # billing-credit-grants: "https://api.openai.com/dashboard/billing/credit_grants" 45 | # users: "https://api.openai.com/v1/organizations/{organizationId}/users" 46 | # billing-subscription: "https://api.openai.com/v1/dashboard/billing/subscription" 47 | # billing-usage: "https://api.openai.com/v1/dashboard/billing/usage?start_date={start_date}&end_date={end_date}" 48 | connect-timeout: 1m 49 | read-timeout: 1m 50 | write-timeout: 1m 51 | proxy: 52 | host: "127.0.0.1" 53 | port: 7890 54 | type: http 55 | # header-name: "Proxy-Authorization" 56 | # username: admin 57 | # password: 123456 58 | -------------------------------------------------------------------------------- /src/test/resources/static/css/style.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --blue: #2894FF; 3 | --dodge-blue: #1e90ff; 4 | --azure-blue: #007fff; 5 | } 6 | 7 | body { 8 | overflow: hidden; 9 | } 10 | 11 | .chat-container { 12 | background-color: #FAFAFA; 13 | display: flex; 14 | flex-direction: column; 15 | height: 100vh; 16 | } 17 | 18 | .chat-content { 19 | flex: 1; 20 | overflow-y: auto; 21 | padding: 15px; 22 | } 23 | 24 | .chat-footer { 25 | flex-shrink: 0; 26 | min-width: 0; 27 | padding: 15px; 28 | } 29 | -------------------------------------------------------------------------------- /src/test/resources/static/js/chat.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzhpo/chatgpt-spring-boot-starter/5a165cc3aa02cc327b81aba4210c3c086cf336f7/src/test/resources/static/js/chat.js -------------------------------------------------------------------------------- /src/test/resources/static/lib/layui/css/modules/code.css: -------------------------------------------------------------------------------- 1 | html #layuicss-skincodecss{display:none;position:absolute;width:1989px}.layui-code-h3,.layui-code-view{position:relative;font-size:12px}.layui-code-view{display:block;margin:10px 0;padding:0;border:1px solid #eee;border-left-width:6px;background-color:#FAFAFA;color:#333;font-family:Courier New}.layui-code-h3{padding:0 10px;height:40px;line-height:40px;border-bottom:1px solid #eee}.layui-code-h3 a{position:absolute;right:10px;top:0;color:#999}.layui-code-view .layui-code-ol{position:relative;overflow:auto}.layui-code-view .layui-code-ol li{position:relative;margin-left:45px;line-height:20px;padding:0 10px;border-left:1px solid #e2e2e2;list-style-type:decimal-leading-zero;*list-style-type:decimal;background-color:#fff}.layui-code-view .layui-code-ol li:first-child{padding-top:10px}.layui-code-view .layui-code-ol li:last-child{padding-bottom:10px}.layui-code-view pre{margin:0}.layui-code-notepad{border:1px solid #0C0C0C;border-left-color:#3F3F3F;background-color:#0C0C0C;color:#C2BE9E}.layui-code-notepad .layui-code-h3{border-bottom:none}.layui-code-notepad .layui-code-ol li{background-color:#3F3F3F;border-left:none}.layui-code-demo .layui-code{visibility:visible!important;margin:-15px;border-top:none;border-right:none;border-bottom:none}.layui-code-demo .layui-tab-content{padding:15px;border-top:none} -------------------------------------------------------------------------------- /src/test/resources/static/lib/layui/css/modules/laydate/default/laydate.css: -------------------------------------------------------------------------------- 1 | .laydate-set-ym,.layui-laydate,.layui-laydate *,.layui-laydate-list{box-sizing:border-box}html #layuicss-laydate{display:none;position:absolute;width:1989px}.layui-laydate *{margin:0;padding:0}.layui-laydate{position:absolute;z-index:66666666;margin:5px 0;border-radius:2px;font-size:14px;-webkit-animation-duration:.2s;animation-duration:.2s;-webkit-animation-fill-mode:both;animation-fill-mode:both;animation-name:laydate-downbit}.layui-laydate-main{width:272px}.layui-laydate-content td,.layui-laydate-header *,.layui-laydate-list li{transition-duration:.3s;-webkit-transition-duration:.3s}@keyframes laydate-downbit{0%{opacity:.3;transform:translate3d(0,-5px,0)}100%{opacity:1;transform:translate3d(0,0,0)}}.layui-laydate-static{position:relative;z-index:0;display:inline-block;margin:0;-webkit-animation:none;animation:none}.laydate-ym-show .laydate-next-m,.laydate-ym-show .laydate-prev-m{display:none!important}.laydate-ym-show .laydate-next-y,.laydate-ym-show .laydate-prev-y{display:inline-block!important}.laydate-time-show .laydate-set-ym span[lay-type=month],.laydate-time-show .laydate-set-ym span[lay-type=year],.laydate-time-show .layui-laydate-header .layui-icon,.laydate-ym-show .laydate-set-ym span[lay-type=month]{display:none!important}.layui-laydate-header{position:relative;line-height:30px;padding:10px 70px 5px}.layui-laydate-header *{display:inline-block;vertical-align:bottom}.layui-laydate-header i{position:absolute;top:10px;padding:0 5px;color:#999;font-size:18px;cursor:pointer}.layui-laydate-header i.laydate-prev-y{left:15px}.layui-laydate-header i.laydate-prev-m{left:45px}.layui-laydate-header i.laydate-next-y{right:15px}.layui-laydate-header i.laydate-next-m{right:45px}.laydate-set-ym{width:100%;text-align:center;text-overflow:ellipsis;overflow:hidden;white-space:nowrap}.laydate-set-ym span{padding:0 10px;cursor:pointer}.laydate-time-text{cursor:default!important}.layui-laydate-content{position:relative;padding:10px;-moz-user-select:none;-webkit-user-select:none;-ms-user-select:none}.layui-laydate-content table{border-collapse:collapse;border-spacing:0}.layui-laydate-content td,.layui-laydate-content th{width:36px;height:30px;padding:5px;text-align:center}.layui-laydate-content td{position:relative;cursor:pointer}.laydate-day-mark{position:absolute;left:0;top:0;width:100%;line-height:30px;font-size:12px;overflow:hidden}.laydate-day-mark::after{position:absolute;content:'';right:2px;top:2px;width:5px;height:5px;border-radius:50%}.layui-laydate-footer{position:relative;height:46px;line-height:26px;padding:10px}.layui-laydate-footer span{display:inline-block;vertical-align:top;height:26px;line-height:24px;padding:0 10px;border:1px solid #C9C9C9;border-radius:2px;background-color:#fff;font-size:12px;cursor:pointer;white-space:nowrap;transition:all .3s}.layui-laydate-list>li,.layui-laydate-range .layui-laydate-main{display:inline-block;vertical-align:middle}.layui-laydate-footer span:hover{color:#5FB878}.layui-laydate-footer span.layui-laydate-preview{cursor:default;border-color:transparent!important}.layui-laydate-footer span.layui-laydate-preview:hover{color:#666}.layui-laydate-footer span:first-child.layui-laydate-preview{padding-left:0}.laydate-footer-btns{position:absolute;right:10px;top:10px}.laydate-footer-btns span{margin:0 0 0 -1px}.layui-laydate-list{position:absolute;left:0;top:0;width:100%;height:100%;padding:10px;background-color:#fff}.layui-laydate-list>li{position:relative;width:33.3%;height:36px;line-height:36px;margin:3px 0;text-align:center;cursor:pointer}.laydate-month-list>li{width:25%;margin:17px 0}.laydate-time-list>li{height:100%;margin:0;line-height:normal;cursor:default}.laydate-time-list p{position:relative;top:-4px;line-height:29px}.laydate-time-list ol{height:181px;overflow:hidden}.laydate-time-list>li:hover ol{overflow-y:auto}.laydate-time-list ol li{width:130%;padding-left:33px;height:30px;line-height:30px;text-align:left;cursor:pointer}.layui-laydate-hint{position:absolute;top:115px;left:50%;width:250px;margin-left:-125px;line-height:20px;padding:15px;text-align:center;font-size:12px}.layui-laydate-range{width:546px}.layui-laydate-range .laydate-main-list-1 .layui-laydate-content,.layui-laydate-range .laydate-main-list-1 .layui-laydate-header{border-left:1px solid #e2e2e2}.layui-laydate,.layui-laydate-hint{border:1px solid #d2d2d2;box-shadow:0 2px 4px rgba(0,0,0,.12);background-color:#fff;color:#666}.layui-laydate-header{border-bottom:1px solid #e2e2e2}.layui-laydate-header i:hover,.layui-laydate-header span:hover{color:#5FB878}.layui-laydate-content{border-top:none 0;border-bottom:none 0}.layui-laydate-content th{font-weight:400;color:#333}.layui-laydate-content td{color:#666}.layui-laydate-content td.laydate-selected{background-color:#B5FFF8}.laydate-selected:hover{background-color:#00F7DE!important}.layui-laydate-content td:hover,.layui-laydate-list li:hover{background-color:#eee;color:#333}.laydate-time-list li ol{margin:0;padding:0;border:1px solid #e2e2e2;border-left-width:0}.laydate-time-list li:first-child ol{border-left-width:1px}.laydate-time-list>li:hover{background:0 0}.layui-laydate-content .laydate-day-next,.layui-laydate-content .laydate-day-prev{color:#d2d2d2}.laydate-selected.laydate-day-next,.laydate-selected.laydate-day-prev{background-color:#f8f8f8!important}.layui-laydate-footer{border-top:1px solid #e2e2e2}.layui-laydate-hint{color:#FF5722}.laydate-day-mark::after{background-color:#5FB878}.layui-laydate-content td.layui-this .laydate-day-mark::after{display:none}.layui-laydate-footer span[lay-type=date]{color:#5FB878}.layui-laydate .layui-this{background-color:#009688!important;color:#fff!important}.layui-laydate .laydate-disabled,.layui-laydate .laydate-disabled:hover{background:0 0!important;color:#d2d2d2!important;cursor:not-allowed!important;-moz-user-select:none;-webkit-user-select:none;-ms-user-select:none}.laydate-theme-molv{border:none}.laydate-theme-molv.layui-laydate-range{width:548px}.laydate-theme-molv .layui-laydate-main{width:274px}.laydate-theme-molv .layui-laydate-header{border:none;background-color:#009688}.laydate-theme-molv .layui-laydate-header i,.laydate-theme-molv .layui-laydate-header span{color:#f6f6f6}.laydate-theme-molv .layui-laydate-header i:hover,.laydate-theme-molv .layui-laydate-header span:hover{color:#fff}.laydate-theme-molv .layui-laydate-content{border:1px solid #e2e2e2;border-top:none;border-bottom:none}.laydate-theme-molv .laydate-main-list-1 .layui-laydate-content{border-left:none}.laydate-theme-grid .laydate-month-list>li,.laydate-theme-grid .laydate-year-list>li,.laydate-theme-grid .layui-laydate-content td,.laydate-theme-grid .layui-laydate-content thead,.laydate-theme-molv .layui-laydate-footer{border:1px solid #e2e2e2}.laydate-theme-grid .laydate-selected,.laydate-theme-grid .laydate-selected:hover{background-color:#f2f2f2!important;color:#009688!important}.laydate-theme-grid .laydate-selected.laydate-day-next,.laydate-theme-grid .laydate-selected.laydate-day-prev{color:#d2d2d2!important}.laydate-theme-grid .laydate-month-list,.laydate-theme-grid .laydate-year-list{margin:1px 0 0 1px}.laydate-theme-grid .laydate-month-list>li,.laydate-theme-grid .laydate-year-list>li{margin:0 -1px -1px 0}.laydate-theme-grid .laydate-year-list>li{height:43px;line-height:43px}.laydate-theme-grid .laydate-month-list>li{height:71px;line-height:71px} -------------------------------------------------------------------------------- /src/test/resources/static/lib/layui/css/modules/layer/default/icon-ext.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzhpo/chatgpt-spring-boot-starter/5a165cc3aa02cc327b81aba4210c3c086cf336f7/src/test/resources/static/lib/layui/css/modules/layer/default/icon-ext.png -------------------------------------------------------------------------------- /src/test/resources/static/lib/layui/css/modules/layer/default/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzhpo/chatgpt-spring-boot-starter/5a165cc3aa02cc327b81aba4210c3c086cf336f7/src/test/resources/static/lib/layui/css/modules/layer/default/icon.png -------------------------------------------------------------------------------- /src/test/resources/static/lib/layui/css/modules/layer/default/loading-0.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzhpo/chatgpt-spring-boot-starter/5a165cc3aa02cc327b81aba4210c3c086cf336f7/src/test/resources/static/lib/layui/css/modules/layer/default/loading-0.gif -------------------------------------------------------------------------------- /src/test/resources/static/lib/layui/css/modules/layer/default/loading-1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzhpo/chatgpt-spring-boot-starter/5a165cc3aa02cc327b81aba4210c3c086cf336f7/src/test/resources/static/lib/layui/css/modules/layer/default/loading-1.gif -------------------------------------------------------------------------------- /src/test/resources/static/lib/layui/css/modules/layer/default/loading-2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzhpo/chatgpt-spring-boot-starter/5a165cc3aa02cc327b81aba4210c3c086cf336f7/src/test/resources/static/lib/layui/css/modules/layer/default/loading-2.gif -------------------------------------------------------------------------------- /src/test/resources/static/lib/layui/font/iconfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzhpo/chatgpt-spring-boot-starter/5a165cc3aa02cc327b81aba4210c3c086cf336f7/src/test/resources/static/lib/layui/font/iconfont.eot -------------------------------------------------------------------------------- /src/test/resources/static/lib/layui/font/iconfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzhpo/chatgpt-spring-boot-starter/5a165cc3aa02cc327b81aba4210c3c086cf336f7/src/test/resources/static/lib/layui/font/iconfont.ttf -------------------------------------------------------------------------------- /src/test/resources/static/lib/layui/font/iconfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzhpo/chatgpt-spring-boot-starter/5a165cc3aa02cc327b81aba4210c3c086cf336f7/src/test/resources/static/lib/layui/font/iconfont.woff -------------------------------------------------------------------------------- /src/test/resources/static/lib/layui/font/iconfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzhpo/chatgpt-spring-boot-starter/5a165cc3aa02cc327b81aba4210c3c086cf336f7/src/test/resources/static/lib/layui/font/iconfont.woff2 -------------------------------------------------------------------------------- /src/test/resources/templates/chat.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Chat 6 | 7 | 8 | 9 | 10 | 11 |
12 |
13 |
    14 |
15 |
16 | 25 |
26 | 27 | 28 | 29 | 119 | 120 | -------------------------------------------------------------------------------- /src/test/resources/templates/sse-stream-chat.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SSE Stream Chat 6 | 7 | 8 | 9 | 10 | 11 |
12 |
13 |
    14 |
15 |
16 | 28 |
29 | 30 | 31 | 32 | 128 | 129 | -------------------------------------------------------------------------------- /src/test/resources/templates/websocket-stream-chat.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | WebSocket Stream Chat 6 | 7 | 8 | 9 | 10 | 11 |
12 |
13 |
    14 |
15 |
16 | 28 |
29 | 30 | 31 | 32 | 127 | 128 | --------------------------------------------------------------------------------