├── .gitignore ├── LICENSE ├── README.md ├── pom.xml └── src ├── main ├── java │ └── com │ │ └── swordintent │ │ └── chatgpt │ │ ├── ChatgptClient.java │ │ ├── ChatgptClientImpl.java │ │ ├── client │ │ ├── DataClient.java │ │ └── TokenInterceptor.java │ │ ├── protocol │ │ ├── ChatGptConfig.java │ │ ├── ChatRequest.java │ │ └── ChatResponse.java │ │ └── utils │ │ └── JsonUtils.java └── resources │ └── server.py └── test └── java └── com └── swordintent └── chatgpt └── AppTest.java /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled class file 2 | *.class 3 | 4 | # Log file 5 | *.log 6 | 7 | # BlueJ files 8 | *.ctxt 9 | 10 | # Mobile Tools for Java (J2ME) 11 | .mtj.tmp/ 12 | 13 | # Package Files # 14 | *.jar 15 | *.war 16 | *.nar 17 | *.ear 18 | *.zip 19 | *.tar.gz 20 | *.rar 21 | 22 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 23 | hs_err_pid* 24 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 swordintent 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # chatgpt-web-api 2 | **A Java Version ChatGPT SDK** 3 | 4 | integrate with [acheong08/ChatGPT](https://github.com/acheong08/ChatGPT), use official Api of openAI(2023.3.2). 5 | 6 | # update 7 | 8 | `2023.3.2 use official api, model is not free, but you have $18 free quota` 9 | 10 | ``` 11 | pip3 install --upgrade revChatGPT 12 | ``` 13 | 14 | # How TO 15 | 16 | [中文](https://github.com/swordintent/chatgpt-web-api/wiki/%E7%AE%80%E4%BB%8B) 17 | 18 | ### Start a python server(python >= 3.7) 19 | 20 | you will find it in `src/main/resources/server.py`, and run: 21 | 22 | ``` 23 | pip3 install flask flask-restful 24 | pip3 install --upgrade revChatGPT 25 | python3 server.py 26 | ``` 27 | 28 | by default, it listen on http://127.0.0.1:5000 29 | 30 | 31 | ### Import maven jar 32 | 33 | https://search.maven.org/artifact/com.swordintent.chatgpt/web-api/ 34 | 35 | Maven 36 | ``` 37 | 38 | com.swordintent.chatgpt 39 | web-api 40 | 1.0.0 41 | 42 | ``` 43 | 44 | Gradle 45 | 46 | ``` 47 | implementation 'com.swordintent.chatgpt:web-api:1.0.0' 48 | ``` 49 | 50 | 51 | ### Enjoy it in your project 52 | 53 | 54 | 1. first, you can invoke `chatgptClient.init(address, chatGptConfig)` method to init client. 55 | 56 | * you need [create](https://platform.openai.com/) your account firstly. 57 | * modify `password`, the `password` is your openAI's api-keys, you can find [here](https://platform.openai.com/account/api-keys). 58 | * set `address` to http://127.0.0.1:5000 or another. 59 | 60 | 61 | ``` 62 | ChatgptClient chatgptClient = ChatgptClientImpl.getInstance(); 63 | ChatGptConfig chatGptConfig = ChatGptConfig.builder() 64 | .password("") 65 | .build(); 66 | String address = "http://127.0.0.1:5000"; 67 | chatgptClient.init(address, chatGptConfig); 68 | ``` 69 | 70 | 2. then you can invoke chat `chatgptClient.chat(request)` method to chat. 71 | 72 | * in first round chat, `conversationId` would be null. 73 | when you want reset multiple rounds set them to null too. 74 | 75 | 76 | ``` 77 | //first round or reset multiple rounds 78 | ChatRequest request = ChatRequest.builder() 79 | .prompt(content) 80 | .conversationId(null) 81 | .build(); 82 | 83 | ChatResponse response = chatgptClient.chat(request); 84 | 85 | ``` 86 | 87 | 88 | * if you want to chat multiple rounds. you need get `conversationId` from response and set them to next chat request. 89 | 90 | 91 | ``` 92 | //multiple rounds 93 | ChatRequest request = ChatRequest.builder() 94 | .prompt(content) 95 | .conversationId(response.getConversationId()) 96 | .build(); 97 | ChatResponse response = chatgptClient.chat(request); 98 | ``` 99 | 100 | 101 | 3. **Notice**. 102 | 103 | * the `conversationId` now is the full object of python chatbot object, so maybe it was huge. 104 | 105 | * you must set `conversationId` to null in your java program when you restart your python server. 106 | 107 | 108 | 109 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 4.0.0 6 | 7 | com.swordintent.chatgpt 8 | web-api 9 | 1.0.0 10 | 11 | web-api 12 | A Java Version ChatGPT SDK. 13 | https://github.com/swordintent/chatgpt-web-api 14 | 15 | 16 | MIT License 17 | http://www.opensource.org/licenses/mit-license.php 18 | repo 19 | 20 | 21 | 22 | 23 | liuhe36 24 | liuhe36@gmail.com 25 | https://github.com/swordintent 26 | +8 27 | 28 | 29 | 30 | scm:git:git@github.com/swordintent/chatgpt-web-api.git 31 | scm:git:git@github.com/swordintent/chatgpt-web-api.git 32 | git@github.com/swordintent/chatgpt-web-api.git 33 | 34 | 35 | 36 | UTF-8 37 | 1.8 38 | 1.8 39 | 40 | 41 | 42 | 43 | junit 44 | junit 45 | 4.11 46 | test 47 | 48 | 49 | com.google.code.gson 50 | gson 51 | 2.10 52 | 53 | 54 | com.squareup.okhttp3 55 | okhttp 56 | 3.12.2 57 | 58 | 59 | org.projectlombok 60 | lombok 61 | 1.18.24 62 | provided 63 | 64 | 65 | 66 | 67 | 68 | 69 | org.apache.maven.plugins 70 | maven-compiler-plugin 71 | 3.8.1 72 | 73 | 1.8 74 | 1.8 75 | 76 | 77 | 78 | 79 | org.sonatype.plugins 80 | nexus-staging-maven-plugin 81 | 1.6.7 82 | true 83 | 84 | 85 | sonatype_releases 86 | https://s01.oss.sonatype.org/ 87 | 88 | true 89 | 90 | 91 | 92 | 93 | org.apache.maven.plugins 94 | maven-source-plugin 95 | 2.2.1 96 | 97 | 98 | attach-sources 99 | 100 | jar-no-fork 101 | 102 | 103 | 104 | 105 | 106 | org.apache.maven.plugins 107 | maven-javadoc-plugin 108 | 2.9.1 109 | 110 | true 111 | UTF-8 112 | UTF-8 113 | UTF-8 114 | 115 | -Xdoclint:none 116 | 117 | 118 | 119 | attach-javadocs 120 | 121 | jar 122 | 123 | 124 | 125 | 126 | 127 | 128 | org.apache.maven.plugins 129 | maven-gpg-plugin 130 | 1.5 131 | 132 | 133 | 134 | gpg 135 | verify 136 | 137 | sign 138 | 139 | 140 | swordintent 141 | swordintent 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | sonatype_releases 151 | https://s01.oss.sonatype.org/content/repositories/snapshots 152 | 153 | 154 | sonatype_snapshots 155 | https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/ 156 | 157 | 158 | 159 | -------------------------------------------------------------------------------- /src/main/java/com/swordintent/chatgpt/ChatgptClient.java: -------------------------------------------------------------------------------- 1 | package com.swordintent.chatgpt; 2 | 3 | import com.swordintent.chatgpt.protocol.ChatGptConfig; 4 | import com.swordintent.chatgpt.protocol.ChatRequest; 5 | import com.swordintent.chatgpt.protocol.ChatResponse; 6 | 7 | public interface ChatgptClient { 8 | /** 9 | * invoke carefully, only when your app start or chat error, you need invoke 10 | */ 11 | void init(String agentAddress, ChatGptConfig config) throws Exception; 12 | 13 | ChatResponse chat(ChatRequest request) throws Exception; 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/com/swordintent/chatgpt/ChatgptClientImpl.java: -------------------------------------------------------------------------------- 1 | package com.swordintent.chatgpt; 2 | 3 | import com.swordintent.chatgpt.client.DataClient; 4 | import com.swordintent.chatgpt.client.TokenInterceptor; 5 | import com.swordintent.chatgpt.protocol.ChatGptConfig; 6 | import com.swordintent.chatgpt.protocol.ChatRequest; 7 | import com.swordintent.chatgpt.protocol.ChatResponse; 8 | 9 | public class ChatgptClientImpl implements ChatgptClient{ 10 | 11 | private static final ChatgptClientImpl instance = new ChatgptClientImpl(); 12 | 13 | private ChatgptClientImpl(){ 14 | 15 | } 16 | 17 | public static ChatgptClientImpl getInstance(){ 18 | return instance; 19 | } 20 | 21 | private static final String LOGIN_URL_PATH = "%s/login"; 22 | private static final String CHAT_URL_PATH = "%s/chat"; 23 | 24 | private String loginUrlPath; 25 | private String chatUrlPath; 26 | 27 | private DataClient client; 28 | 29 | private TokenInterceptor tokenInterceptor; 30 | 31 | @Override 32 | public void init(String agentAddress, ChatGptConfig config) throws Exception { 33 | initUrls(agentAddress); 34 | initClient(config); 35 | login(); 36 | } 37 | 38 | @Override 39 | public ChatResponse chat(ChatRequest request) throws Exception { 40 | return client.getData(request, chatUrlPath, ChatResponse.class); 41 | } 42 | 43 | private void initClient(ChatGptConfig config) { 44 | tokenInterceptor = new TokenInterceptor(config); 45 | client = new DataClient(tokenInterceptor); 46 | client.init(); 47 | } 48 | 49 | private void initUrls(String agentAddress) { 50 | loginUrlPath = String.format(LOGIN_URL_PATH, agentAddress); 51 | chatUrlPath = String.format(CHAT_URL_PATH, agentAddress); 52 | } 53 | 54 | private void login() throws Exception { 55 | ChatGptConfig loginConfig = client.getData(this.loginUrlPath, ChatGptConfig.class); 56 | tokenInterceptor.setChatGptConfig(loginConfig); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/com/swordintent/chatgpt/client/DataClient.java: -------------------------------------------------------------------------------- 1 | package com.swordintent.chatgpt.client; 2 | 3 | import com.swordintent.chatgpt.utils.JsonUtils; 4 | import okhttp3.*; 5 | 6 | import javax.net.ssl.*; 7 | import java.io.IOException; 8 | import java.net.InetSocketAddress; 9 | import java.net.Proxy; 10 | import java.security.cert.CertificateException; 11 | import java.security.cert.X509Certificate; 12 | import java.util.concurrent.TimeUnit; 13 | 14 | /** 15 | * @author liuhe 16 | */ 17 | public class DataClient { 18 | 19 | private OkHttpClient httpClient; 20 | 21 | private final TokenInterceptor interceptor; 22 | 23 | 24 | public DataClient(TokenInterceptor interceptor) { 25 | this.interceptor = interceptor; 26 | } 27 | 28 | public void init() { 29 | // OkHttpClient.Builder builder = null; 30 | // try { 31 | // builder = getDebugHttpClientBuilder(); 32 | // httpClient = builder.build(); 33 | // } catch (Exception e) { 34 | // e.printStackTrace(); 35 | // } 36 | OkHttpClient.Builder builder = getHttpClientBuilder(); 37 | httpClient = builder.build(); 38 | } 39 | 40 | private OkHttpClient.Builder getDebugHttpClientBuilder() throws Exception { 41 | Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress("127.0.0.1", 8888)); 42 | final TrustManager[] trustAllCerts = new TrustManager[]{ 43 | new X509TrustManager() { 44 | @Override 45 | public void checkClientTrusted(X509Certificate[] chain, 46 | String authType) throws CertificateException { 47 | } 48 | 49 | @Override 50 | public void checkServerTrusted(X509Certificate[] chain, 51 | String authType) throws CertificateException { 52 | } 53 | 54 | @Override 55 | public X509Certificate[] getAcceptedIssuers() { 56 | return new X509Certificate[0]; 57 | } 58 | } 59 | }; 60 | 61 | // Install the all-trusting trust manager 62 | final SSLContext sslContext = SSLContext.getInstance("SSL"); 63 | sslContext.init(null, trustAllCerts, new java.security.SecureRandom()); 64 | // Create an ssl socket factory with our all-trusting manager 65 | final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory(); 66 | 67 | return new OkHttpClient.Builder() 68 | .connectTimeout(60, TimeUnit.SECONDS) 69 | .writeTimeout(60, TimeUnit.SECONDS) 70 | .readTimeout(60, TimeUnit.SECONDS) 71 | .proxy(proxy) 72 | .addInterceptor(interceptor) 73 | .sslSocketFactory(sslSocketFactory, (X509TrustManager) trustAllCerts[0]) 74 | .hostnameVerifier(new HostnameVerifier() { 75 | @Override 76 | public boolean verify(String hostname, SSLSession session) { 77 | return true; 78 | } 79 | }); 80 | } 81 | 82 | public R getData(String url, Class responseType) throws Exception { 83 | Request request = new Request.Builder() 84 | .url(url) 85 | .post(RequestBody.create(null, "{}")) 86 | .build(); 87 | return makeRequest(request, responseType); 88 | } 89 | 90 | public R getData(T requestData, String url, Class responseType) throws Exception { 91 | String content = JsonUtils.toJson(requestData); 92 | RequestBody body = RequestBody.create( 93 | null, content); 94 | Request request = new Request.Builder() 95 | .url(url) 96 | .post(body) 97 | .build(); 98 | return makeRequest(request, responseType); 99 | } 100 | 101 | private R makeRequest(Request request, Class responseType) throws IOException { 102 | Call call = httpClient.newCall(request); 103 | try (Response response = call.execute()) { 104 | ResponseBody body = response.body(); 105 | if(body == null){ 106 | return null; 107 | } 108 | String string = body.string(); 109 | return JsonUtils.fromJson(string, responseType); 110 | } 111 | } 112 | 113 | private OkHttpClient.Builder getHttpClientBuilder() { 114 | return new OkHttpClient.Builder() 115 | .connectTimeout(180, TimeUnit.SECONDS) 116 | .writeTimeout(180, TimeUnit.SECONDS) 117 | .readTimeout(180, TimeUnit.SECONDS) 118 | .addInterceptor(interceptor); 119 | } 120 | 121 | } 122 | -------------------------------------------------------------------------------- /src/main/java/com/swordintent/chatgpt/client/TokenInterceptor.java: -------------------------------------------------------------------------------- 1 | package com.swordintent.chatgpt.client; 2 | 3 | import com.swordintent.chatgpt.protocol.ChatGptConfig; 4 | import com.swordintent.chatgpt.utils.JsonUtils; 5 | import okhttp3.Interceptor; 6 | import okhttp3.Request; 7 | import okhttp3.Response; 8 | 9 | import java.io.IOException; 10 | 11 | /** 12 | * @author liuhe 13 | */ 14 | public class TokenInterceptor implements Interceptor { 15 | 16 | private ChatGptConfig chatGptConfig; 17 | 18 | public void setChatGptConfig(ChatGptConfig chatGptConfig) { 19 | this.chatGptConfig = chatGptConfig; 20 | } 21 | 22 | public TokenInterceptor(ChatGptConfig chatGptConfig) { 23 | this.chatGptConfig = chatGptConfig; 24 | } 25 | 26 | @Override 27 | public Response intercept(Chain chain) throws IOException { 28 | Request request = chain.request(); 29 | Request newRequest; 30 | newRequest = request.newBuilder() 31 | // .addHeader("accept", "application/json") 32 | .addHeader("chatgpt-config", JsonUtils.toJson(chatGptConfig)) 33 | .addHeader("Content-Type", "application/json") 34 | .build(); 35 | return chain.proceed(newRequest); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/com/swordintent/chatgpt/protocol/ChatGptConfig.java: -------------------------------------------------------------------------------- 1 | package com.swordintent.chatgpt.protocol; 2 | 3 | import com.google.gson.annotations.SerializedName; 4 | import lombok.Builder; 5 | 6 | @Builder 7 | public class ChatGptConfig { 8 | 9 | private String email; 10 | private String password; 11 | @SerializedName("session_token") 12 | private String sessionToken; 13 | private String proxy; 14 | @SerializedName("Authorization") 15 | private String authorization; 16 | 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/swordintent/chatgpt/protocol/ChatRequest.java: -------------------------------------------------------------------------------- 1 | package com.swordintent.chatgpt.protocol; 2 | 3 | import com.google.gson.annotations.SerializedName; 4 | import lombok.Builder; 5 | 6 | @Builder 7 | public class ChatRequest { 8 | 9 | private String prompt; 10 | @SerializedName("conversation_id") 11 | private String conversationId; 12 | @SerializedName("parent_id") 13 | private String parentId; 14 | 15 | public void setPrompt(String prompt) { 16 | this.prompt = prompt; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/swordintent/chatgpt/protocol/ChatResponse.java: -------------------------------------------------------------------------------- 1 | package com.swordintent.chatgpt.protocol; 2 | 3 | import com.google.gson.annotations.SerializedName; 4 | import lombok.Data; 5 | 6 | @Data 7 | public class ChatResponse { 8 | 9 | private String message; 10 | @SerializedName("conversation_id") 11 | private String conversationId; 12 | @SerializedName("parent_id") 13 | private String parentId; 14 | 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/swordintent/chatgpt/utils/JsonUtils.java: -------------------------------------------------------------------------------- 1 | package com.swordintent.chatgpt.utils; 2 | 3 | import com.google.gson.Gson; 4 | import com.google.gson.GsonBuilder; 5 | 6 | /** 7 | * @author liuhe 8 | */ 9 | public class JsonUtils { 10 | private static final Gson prettyGson = new GsonBuilder() 11 | .setPrettyPrinting() 12 | .create(); 13 | 14 | private static final Gson gson = new GsonBuilder() 15 | .create(); 16 | 17 | public static String toJson(Object obj) { 18 | return gson.toJson(obj); 19 | } 20 | 21 | public static T fromJson(String json, Class t) { 22 | return gson.fromJson(json, t); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/resources/server.py: -------------------------------------------------------------------------------- 1 | import json 2 | import pickle 3 | import base64 4 | import uuid 5 | 6 | from revChatGPT.V3 import Chatbot 7 | from flask import Flask 8 | from flask_restful import reqparse, Api, Resource 9 | 10 | # For the config please go here: 11 | # https://github.com/acheong08/ChatGPT/wiki/Setup 12 | 13 | app = Flask(__name__) 14 | api = Api(app) 15 | 16 | parser = reqparse.RequestParser() 17 | parser.add_argument('prompt') 18 | parser.add_argument('conversation_id') 19 | parser.add_argument('parent_id') 20 | parser.add_argument('chatgpt-config', type=str, location='headers') 21 | 22 | 23 | class Chat(Resource): 24 | 25 | def post(self): 26 | args = parser.parse_args() 27 | print(args) 28 | 29 | prompt = args['prompt'] 30 | conversation_id = args['conversation_id'] 31 | config = json.loads(args['chatgpt-config']) 32 | 33 | if conversation_id is None: 34 | chatbot = Chatbot(api_key=config['password']) 35 | conversation_id = str(uuid.uuid1()) 36 | else: 37 | chatbot = Chatbot(api_key=config['password']) 38 | chatbot.load(conversation_id) 39 | result = chatbot.ask(prompt) 40 | chatbot.save(conversation_id) 41 | print("result", chatbot.conversation) 42 | ret = {'message': result, 'conversation_id': conversation_id} 43 | response = ret 44 | print(response) 45 | return response, 200 46 | 47 | 48 | class Login(Resource): 49 | 50 | def post(self): 51 | args = parser.parse_args() 52 | print(args) 53 | config = json.loads(args['chatgpt-config']) 54 | chatbot = Chatbot(api_key=config['password']) 55 | response = config 56 | print(response) 57 | return response, 200 58 | 59 | 60 | api.add_resource(Chat, '/chat') 61 | api.add_resource(Login, '/login') 62 | 63 | if __name__ == '__main__': 64 | app.run(debug=True) 65 | -------------------------------------------------------------------------------- /src/test/java/com/swordintent/chatgpt/AppTest.java: -------------------------------------------------------------------------------- 1 | package com.swordintent.chatgpt; 2 | 3 | import com.swordintent.chatgpt.protocol.ChatGptConfig; 4 | import com.swordintent.chatgpt.protocol.ChatResponse; 5 | import org.junit.Test; 6 | import com.swordintent.chatgpt.protocol.ChatRequest; 7 | import com.swordintent.chatgpt.utils.JsonUtils; 8 | 9 | import java.util.Arrays; 10 | import java.util.List; 11 | 12 | /** 13 | * Unit test for simple App. 14 | */ 15 | public class AppTest 16 | { 17 | /** 18 | * Rigorous Test :-) 19 | */ 20 | @Test 21 | public void test() throws Exception { 22 | ChatGptConfig chatGptConfig = ChatGptConfig.builder() 23 | // .proxy("http://192.168.50.254:9853") 24 | // .email("") 25 | // .password("") 26 | .authorization("") 27 | .build(); 28 | ChatgptClientImpl client = ChatgptClientImpl.getInstance(); 29 | client.init("http://127.0.0.1:5000", chatGptConfig); 30 | List strings = Arrays.asList("你好", "你能帮我介绍一下中日关系吗?"); 31 | int size = strings.size(); 32 | int threadNum = 1; 33 | int slice = size / threadNum; 34 | 35 | for(int i = 0; i < threadNum; i ++){ 36 | List subList = strings.subList(slice * i, slice * (i + 1)); 37 | makeThreadRequest(client, subList); 38 | } 39 | Thread.sleep(60000L); 40 | } 41 | 42 | private void makeThreadRequest(ChatgptClientImpl client, List subList) { 43 | new Thread(() ->{ 44 | String conversationId = null; 45 | String parentId = null; 46 | for(String str : subList){ 47 | ChatRequest chatRequest = ChatRequest.builder().prompt(str) 48 | .conversationId(conversationId) 49 | .parentId(parentId) 50 | .build(); 51 | try { 52 | ChatResponse chat = client.chat(chatRequest); 53 | System.out.println(JsonUtils.toJson(chat)); 54 | conversationId = chat.getConversationId(); 55 | parentId = chat.getParentId(); 56 | } catch (Exception e) { 57 | throw new RuntimeException(e); 58 | } 59 | } 60 | }).start(); 61 | } 62 | } 63 | --------------------------------------------------------------------------------