From 3e3b220427bb13663288c93efee8d309066f94eb Mon Sep 17 00:00:00 2001 From: Wuzi Date: Tue, 14 Mar 2023 19:23:34 +0800 Subject: [PATCH] Fix some problems Details: Fix #107 Fix the problem of GPT 3.5 Turbo displaying blank Fix the UI flicker problem. --- build.gradle.kts | 2 +- .../com/obiscr/chatgpt/ChatGPTHandler.java | 10 --- .../com/obiscr/chatgpt/GPT35TurboHandler.java | 88 ++++++++++++++----- .../com/obiscr/chatgpt/RequestProvider.java | 6 +- .../com/obiscr/chatgpt/core/Constant.java | 11 +-- .../com/obiscr/chatgpt/core/SendAction.java | 12 ++- .../chatgpt/core/builder/OfficialBuilder.java | 80 ++++++++--------- .../chatgpt/core/parser/OfficialParser.java | 40 ++++----- .../chatgpt/settings/OpenAISettingsPanel.java | 5 -- .../java/com/obiscr/chatgpt/ui/MainPanel.java | 6 +- .../obiscr/chatgpt/ui/MessageComponent.java | 22 ++--- .../chatgpt/ui/MessageGroupComponent.java | 8 +- .../com/obiscr/chatgpt/ui/MessagePanel.java | 32 +++++++ .../com/obiscr/chatgpt/util/OpenAIUtil.java | 40 ++++----- src/main/resources/META-INF/plugin.xml | 1 + 15 files changed, 205 insertions(+), 158 deletions(-) create mode 100644 src/main/java/com/obiscr/chatgpt/ui/MessagePanel.java diff --git a/build.gradle.kts b/build.gradle.kts index abddd60..c1b18be 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -30,7 +30,7 @@ repositories { } dependencies { - implementation("com.alibaba.fastjson2:fastjson2:2.0.17") + implementation("com.google.code.gson:gson:2.10.1") implementation("cn.hutool:hutool-http:5.8.12") implementation("com.obiscr:openai-auth:1.0.1") implementation("com.squareup.okhttp3:okhttp:4.10.0") diff --git a/src/main/java/com/obiscr/chatgpt/ChatGPTHandler.java b/src/main/java/com/obiscr/chatgpt/ChatGPTHandler.java index 82209fa..6ebc0ae 100644 --- a/src/main/java/com/obiscr/chatgpt/ChatGPTHandler.java +++ b/src/main/java/com/obiscr/chatgpt/ChatGPTHandler.java @@ -1,26 +1,16 @@ package com.obiscr.chatgpt; -import com.alibaba.fastjson2.JSON; -import com.alibaba.fastjson2.JSONArray; -import com.alibaba.fastjson2.JSONObject; import com.intellij.openapi.project.Project; -import com.obiscr.OpenAIProxy; -import com.obiscr.chatgpt.core.ConversationManager; -import com.obiscr.chatgpt.core.TokenManager; -import com.obiscr.chatgpt.core.builder.OfficialBuilder; import com.obiscr.chatgpt.core.parser.OfficialParser; -import com.obiscr.chatgpt.settings.SettingConfiguration; import com.obiscr.chatgpt.settings.OpenAISettingsState; import com.obiscr.chatgpt.ui.MainPanel; import com.obiscr.chatgpt.ui.MessageComponent; -import com.obiscr.chatgpt.util.HtmlUtil; import com.obiscr.chatgpt.util.StringUtil; import okhttp3.*; import okhttp3.internal.http2.StreamResetException; import okhttp3.sse.EventSource; import okhttp3.sse.EventSourceListener; import okhttp3.sse.EventSources; -import org.apache.commons.lang3.StringUtils; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; diff --git a/src/main/java/com/obiscr/chatgpt/GPT35TurboHandler.java b/src/main/java/com/obiscr/chatgpt/GPT35TurboHandler.java index 59239b7..65cfb49 100644 --- a/src/main/java/com/obiscr/chatgpt/GPT35TurboHandler.java +++ b/src/main/java/com/obiscr/chatgpt/GPT35TurboHandler.java @@ -1,7 +1,5 @@ package com.obiscr.chatgpt; -import cn.hutool.http.HttpResponse; -import cn.hutool.http.HttpUtil; import com.obiscr.chatgpt.core.builder.OfficialBuilder; import com.obiscr.OpenAIProxy; import com.obiscr.chatgpt.core.parser.OfficialParser; @@ -9,10 +7,17 @@ import com.obiscr.chatgpt.ui.MainPanel; import com.obiscr.chatgpt.ui.MessageComponent; import com.obiscr.chatgpt.ui.MessageGroupComponent; +import com.obiscr.chatgpt.util.StringUtil; +import okhttp3.*; +import org.jetbrains.annotations.NotNull; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.io.IOException; +import java.net.Proxy; +import java.net.SocketException; import java.nio.charset.StandardCharsets; +import java.util.concurrent.TimeUnit; import java.net.Proxy; @@ -22,7 +27,7 @@ public class GPT35TurboHandler extends AbstractHandler { private static final Logger LOG = LoggerFactory.getLogger(GPT35TurboHandler.class); - public MessageComponent handle(MainPanel mainPanel, MessageComponent component, String question) { + public Call handle(MainPanel mainPanel, MessageComponent component, String question) { MessageGroupComponent contentPanel = mainPanel.getContentPanel(); // Define the default system role @@ -30,34 +35,71 @@ public MessageComponent handle(MainPanel mainPanel, MessageComponent component, String text = contentPanel.getSystemRole(); contentPanel.getMessages().add(OfficialBuilder.systemMessage(text)); } - + Call call = null; RequestProvider provider = new RequestProvider().create(mainPanel, question); try { - LOG.info("ChatGPT Request: question={}",question); - HttpResponse response = HttpUtil.createPost(provider.getUrl()) - .headerMap(provider.getHeader(),true) - .setProxy(getProxy()) - .body(provider.getData().getBytes(StandardCharsets.UTF_8)).executeAsync(); - LOG.info("ChatGPT Response: answer={}",response.body()); - if (response.getStatus() != 200) { - LOG.info("ChatGPT: Request failure. Url={}, response={}",provider.getUrl(), response.body()); - component.setContent("Response failure, please try again. Error message: " + response.body()); - mainPanel.aroundRequest(false); - return component; + LOG.info("GPT 3.5 Turbo Request: question={}",question); + Request request = new Request.Builder() + .url(provider.getUrl()) + .headers(Headers.of(provider.getHeader())) + .post(RequestBody.create(provider.getData().getBytes(StandardCharsets.UTF_8), + MediaType.parse("application/json"))) + .build(); + OpenAISettingsState instance = OpenAISettingsState.getInstance(); + OkHttpClient.Builder builder = new OkHttpClient.Builder() + .connectTimeout(Integer.parseInt(instance.connectionTimeout), TimeUnit.MILLISECONDS) + .readTimeout(Integer.parseInt(instance.readTimeout), TimeUnit.MILLISECONDS); + if (instance.enableProxy) { + Proxy proxy = getProxy(); + builder.proxy(proxy); } - OfficialParser.ParseResult parseResult = OfficialParser. - parseGPT35Turbo(response.body()); + OkHttpClient httpClient = builder.build(); + call = httpClient.newCall(request); + call.enqueue(new Callback() { + @Override + public void onFailure(@NotNull Call call, @NotNull IOException e) { + String errorMessage = StringUtil.isEmpty(e.getMessage())? "None" : e.getMessage(); + if (e instanceof SocketException) { + LOG.info("GPT 3.5 Turbo: Stop generating"); + component.setContent("Stop generating"); + e.printStackTrace(); + return; + } + LOG.error("GPT 3.5 Turbo Request failure. Url={}, error={}", + call.request().url(), + errorMessage); + errorMessage = "GPT 3.5 Turbo Request failure, cause: " + errorMessage; + component.setSourceContent(errorMessage); + component.setContent(errorMessage); + mainPanel.aroundRequest(false); + component.scrollToBottom(); + } - mainPanel.getContentPanel().getMessages().add(OfficialBuilder.assistantMessage(parseResult.getSource())); - component.setSourceContent(parseResult.getSource()); - component.setContent(parseResult.getHtml()); - mainPanel.aroundRequest(false); - component.scrollToBottom(); + @Override + public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException { + String responseMessage = response.body().string(); + LOG.info("GPT 3.5 Turbo Response: answer={}",responseMessage); + if (response.code() != 200) { + LOG.info("GPT 3.5 Turbo: Request failure. Url={}, response={}",provider.getUrl(), responseMessage); + component.setContent("Response failure, please try again. Error message: " + responseMessage); + mainPanel.aroundRequest(false); + return; + } + OfficialParser.ParseResult parseResult = OfficialParser. + parseGPT35Turbo(responseMessage); + + mainPanel.getContentPanel().getMessages().add(OfficialBuilder.assistantMessage(parseResult.getSource())); + component.setSourceContent(parseResult.getSource()); + component.setContent(parseResult.getHtml()); + mainPanel.aroundRequest(false); + component.scrollToBottom(); + } + }); } catch (Exception e) { component.setSourceContent(e.getMessage()); component.setContent(e.getMessage()); mainPanel.aroundRequest(false); } - return component; + return call; } } diff --git a/src/main/java/com/obiscr/chatgpt/RequestProvider.java b/src/main/java/com/obiscr/chatgpt/RequestProvider.java index d334e24..a70f11d 100644 --- a/src/main/java/com/obiscr/chatgpt/RequestProvider.java +++ b/src/main/java/com/obiscr/chatgpt/RequestProvider.java @@ -46,14 +46,14 @@ public RequestProvider create(MainPanel mainPanel, String question) { provider.url = OFFICIAL_CONVERSATION_URL; } provider.header = TokenManager.getInstance().getChatGPTHeaders(); - provider.data = JSON.toJSONString(OfficialBuilder.buildChatGPT(myProject,question)); + provider.data = OfficialBuilder.buildChatGPT(myProject,question).toString(); } else { provider.url = "https://api.openai.com/v1/chat/completions"; provider.header = TokenManager.getInstance().getGPT35TurboHeaders(); if (instance.enableContext) { - provider.data = JSON.toJSONString(OfficialBuilder.buildGpt35Turbo(question,mainPanel.getContentPanel())); + provider.data = OfficialBuilder.buildGpt35Turbo(question,mainPanel.getContentPanel()).toString(); } else { - provider.data = JSON.toJSONString(OfficialBuilder.buildGpt35Turbo(question)); + provider.data = OfficialBuilder.buildGpt35Turbo(question).toString(); } } return provider; diff --git a/src/main/java/com/obiscr/chatgpt/core/Constant.java b/src/main/java/com/obiscr/chatgpt/core/Constant.java index b1c1704..73b13c6 100644 --- a/src/main/java/com/obiscr/chatgpt/core/Constant.java +++ b/src/main/java/com/obiscr/chatgpt/core/Constant.java @@ -11,17 +11,14 @@ public class Constant { "**Important tip**: \n\n"+ "Currently using a third-party proxy service. will be unstable. And there is a limit on the number of requests per hour.
" + "**Please don't give me bad reviews. I have been working hard to provide you with a better service.**\n\n
" + - "**Instructions**: \n\n" + - "Open *File* - *Setting/Preference* , select *Tool* - *OpenAI* - *ChatGPT*. Enter your own OpenAI account in Official.\n\n
" + - "Click Login below to start logging in, and the Access Token below will be automatically refreshed after successful login.\n" + - "The expiration time of the current Token is displayed below the Access Token. After the expiration, you can click Login again to refresh the Access Token.\n\n"; + "**Getting Started**: \n\n
" + + "Please following this to configure the ChatGPT: [https://chatgpt.en.obiscr.com/settings/chatgpt-settings/](https://chatgpt.en.obiscr.com/settings/chatgpt-settings/) \n\n
"; public static final String GPT35_TURBO_CONTENT = "**Important tip**: \n\n"+ "This model is the official GPT 3.5 Turbo model. \n\n
" + - "**Instructions**: \n\n" + - "At first, login to: [https://platform.openai.com/account/api-keys](https://platform.openai.com/account/api-keys). Then create an API Key.\n" + - "Open *File* - *Setting/Preference* , select *Tool* - *OpenAI* - *GPT 3.5 Turbo*. And fill the API Key in text field."; + "**Instructions**: \n\n
" + + "Please following this to configure the GPT 3.5 Turbo: [https://chatgpt.en.obiscr.com/settings/gpt-3.5-trubo-settings/](https://chatgpt.en.obiscr.com/settings/gpt-3.5-trubo-settings/) \n\n
"; public static String getChatGPTContent() { diff --git a/src/main/java/com/obiscr/chatgpt/core/SendAction.java b/src/main/java/com/obiscr/chatgpt/core/SendAction.java index dad53a1..087eba0 100644 --- a/src/main/java/com/obiscr/chatgpt/core/SendAction.java +++ b/src/main/java/com/obiscr/chatgpt/core/SendAction.java @@ -6,8 +6,6 @@ import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.project.Project; -import com.intellij.openapi.wm.ToolWindow; -import com.intellij.openapi.wm.ToolWindowManager; import com.obiscr.chatgpt.ChatGPTHandler; import com.obiscr.chatgpt.GPT35TurboHandler; import com.obiscr.chatgpt.MyToolWindowFactory; @@ -18,6 +16,7 @@ import com.obiscr.chatgpt.ui.MessageComponent; import com.obiscr.chatgpt.ui.MessageGroupComponent; import com.obiscr.chatgpt.util.StringUtil; +import okhttp3.Call; import okhttp3.sse.EventSource; import org.apache.commons.lang3.StringUtils; import org.jetbrains.annotations.NotNull; @@ -95,7 +94,6 @@ public void doActionPerformed(MainPanel mainPanel, String data) { mainPanel.getSearchTextArea().getTextArea().setText(""); mainPanel.aroundRequest(true); Project project = mainPanel.getProject(); - ChatGPTHandler chatGPTHandler = project.getService(ChatGPTHandler.class); MessageGroupComponent contentPanel = mainPanel.getContentPanel(); // Add the message component to container @@ -108,6 +106,7 @@ public void doActionPerformed(MainPanel mainPanel, String data) { ExecutorService executorService = mainPanel.getExecutorService(); // Request the server. if (mainPanel.isChatGPTModel()) { + ChatGPTHandler chatGPTHandler = project.getService(ChatGPTHandler.class); executorService.submit(() -> { EventSource handle = chatGPTHandler.handle(mainPanel, answer, data); mainPanel.setRequestHolder(handle); @@ -115,14 +114,13 @@ public void doActionPerformed(MainPanel mainPanel, String data) { contentPanel.scrollToBottom(); }); } else { + GPT35TurboHandler gpt35TurboHandler = project.getService(GPT35TurboHandler.class); executorService.submit(() -> { - new GPT35TurboHandler().handle(mainPanel, answer, data); + Call handle = gpt35TurboHandler.handle(mainPanel, answer, data); + mainPanel.setRequestHolder(handle); contentPanel.updateLayout(); contentPanel.scrollToBottom(); }); - // Because this Http request is blocked, it cannot be placed in Runnable - // So it needs to be executed outside Runnable - mainPanel.setRequestHolder(answer); } } catch (Exception e) { diff --git a/src/main/java/com/obiscr/chatgpt/core/builder/OfficialBuilder.java b/src/main/java/com/obiscr/chatgpt/core/builder/OfficialBuilder.java index 1ff095c..d6e86e4 100644 --- a/src/main/java/com/obiscr/chatgpt/core/builder/OfficialBuilder.java +++ b/src/main/java/com/obiscr/chatgpt/core/builder/OfficialBuilder.java @@ -1,7 +1,7 @@ package com.obiscr.chatgpt.core.builder; -import com.alibaba.fastjson2.JSONArray; -import com.alibaba.fastjson2.JSONObject; +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; import com.intellij.openapi.project.Project; import com.obiscr.chatgpt.core.ConversationManager; import com.obiscr.chatgpt.settings.OpenAISettingsState; @@ -16,75 +16,75 @@ */ public class OfficialBuilder { - public static JSONObject buildChatGPT(@NotNull Project project, String text) { - JSONObject result = new JSONObject(); - result.put("action","next"); + public static JsonObject buildChatGPT(@NotNull Project project, String text) { + JsonObject result = new JsonObject(); + result.addProperty("action","next"); - JSONArray messages = new JSONArray(); - JSONObject message0 = new JSONObject(); - message0.put("id", UUID.randomUUID()); - message0.put("role", "user"); + JsonArray messages = new JsonArray(); + JsonObject message0 = new JsonObject(); + message0.addProperty("id", UUID.randomUUID().toString()); + message0.addProperty("role", "user"); - JSONObject content = new JSONObject(); - content.put("content_type","text"); - JSONArray parts = new JSONArray(); + JsonObject content = new JsonObject(); + content.addProperty("content_type","text"); + JsonArray parts = new JsonArray(); parts.add(text); - content.put("parts",parts); + content.add("parts",parts); - JSONObject author = new JSONObject(); - author.put("role", "user"); - message0.put("content", content); - message0.put("author", author); + JsonObject author = new JsonObject(); + author.addProperty("role", "user"); + message0.add("content", content); + message0.add("author", author); messages.add(message0); - result.put("messages", messages); + result.add("messages", messages); - result.put("parent_message_id", ConversationManager.getInstance(project).getParentMessageId()); + result.addProperty("parent_message_id", ConversationManager.getInstance(project).getParentMessageId()); String conversationId = ConversationManager.getInstance(project).getConversationId(); if (StringUtil.isNotEmpty(conversationId)) { - result.put("conversation_id",conversationId); + result.addProperty("conversation_id",conversationId); } OpenAISettingsState settingsState = OpenAISettingsState.getInstance(); - result.put("model",settingsState.chatGptModel); + result.addProperty("model",settingsState.chatGptModel); return result; } - public static JSONObject buildGpt35Turbo(String text) { - JSONObject result = new JSONObject(); - result.put("model","gpt-3.5-turbo"); - JSONArray messages = new JSONArray(); - JSONObject message0 = new JSONObject(); - message0.put("role","user"); - message0.put("content",text); + public static JsonObject buildGpt35Turbo(String text) { + JsonObject result = new JsonObject(); + result.addProperty("model","gpt-3.5-turbo"); + JsonArray messages = new JsonArray(); + JsonObject message0 = new JsonObject(); + message0.addProperty("role","user"); + message0.addProperty("content",text); messages.add(message0); - result.put("messages",messages); + result.add("messages",messages); return result; } - public static JSONObject buildGpt35Turbo(String text, MessageGroupComponent component) { - JSONObject result = new JSONObject(); + public static JsonObject buildGpt35Turbo(String text, MessageGroupComponent component) { + JsonObject result = new JsonObject(); OpenAISettingsState settingsState = OpenAISettingsState.getInstance(); - result.put("model",settingsState.gpt35Model); + result.addProperty("model",settingsState.gpt35Model); component.getMessages().add(userMessage(text)); - result.put("messages",component.getMessages()); + result.add("messages",component.getMessages()); return result; } - private static JSONObject message(String role, String text) { - JSONObject message = new JSONObject(); - message.put("role",role); - message.put("content",text); + private static JsonObject message(String role, String text) { + JsonObject message = new JsonObject(); + message.addProperty("role",role); + message.addProperty("content",text); return message; } - public static JSONObject userMessage(String text) { + public static JsonObject userMessage(String text) { return message("user",text); } - public static JSONObject systemMessage(String text) { + public static JsonObject systemMessage(String text) { return message("system",text); } - public static JSONObject assistantMessage(String text) { + public static JsonObject assistantMessage(String text) { return message("assistant",text); } } diff --git a/src/main/java/com/obiscr/chatgpt/core/parser/OfficialParser.java b/src/main/java/com/obiscr/chatgpt/core/parser/OfficialParser.java index 9bcf4ed..8ab3df2 100644 --- a/src/main/java/com/obiscr/chatgpt/core/parser/OfficialParser.java +++ b/src/main/java/com/obiscr/chatgpt/core/parser/OfficialParser.java @@ -1,8 +1,9 @@ package com.obiscr.chatgpt.core.parser; -import com.alibaba.fastjson2.JSON; -import com.alibaba.fastjson2.JSONArray; -import com.alibaba.fastjson2.JSONObject; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; import com.intellij.openapi.project.Project; import com.obiscr.chatgpt.core.ConversationManager; import com.obiscr.chatgpt.ui.MessageComponent; @@ -18,19 +19,19 @@ public class OfficialParser { private static final String DONE = "[DONE]"; public static ParseResult parseChatGPT(@NotNull Project project, MessageComponent component, String response) { - JSONObject jsonObject = JSON.parseObject(response); + JsonObject object = JsonParser.parseString(response).getAsJsonObject(); // Handler the error info from the proxy server. - if (jsonObject.containsKey("detail")) { - String detail = jsonObject.getString("detail"); + if (object.keySet().contains("detail")) { + String detail = object.get("detail").getAsString(); component.setSourceContent(detail); component.setContent(detail); return null; } - JSONArray partsArray = jsonObject.getJSONObject("message") - .getJSONObject("content") - .getJSONArray("parts"); - String conversationId = jsonObject.getString("conversation_id"); - String parentId = (jsonObject.getJSONObject("message")).getString("id"); + JsonArray partsArray = object.get("message").getAsJsonObject() + .get("content").getAsJsonObject() + .get("parts").getAsJsonArray(); + String conversationId = object.get("conversation_id").getAsString(); + String parentId = (object.get("message").getAsJsonObject()).get("id").getAsString(); ConversationManager.getInstance(project).setParentMessageId(parentId); ConversationManager.getInstance(project).setConversationId(conversationId); @@ -39,26 +40,25 @@ public static ParseResult parseChatGPT(@NotNull Project project, MessageComponen } StringBuilder result = new StringBuilder(); for (int i = 0 ; i < partsArray.size() ; i++) { - result.append(partsArray.getString(i)); + result.append(partsArray.get(i).getAsString()); } ParseResult parseResult = new ParseResult(); - parseResult.source = HtmlUtil.md2html(result.toString()); + parseResult.source = result.toString(); parseResult.html = HtmlUtil.md2html(result.toString()); return parseResult; } public static ParseResult parseGPT35Turbo(String response) { - JSONObject object = JSON.parseObject(response); + JsonObject object = JsonParser.parseString(response).getAsJsonObject(); + JsonArray choices = object.get("choices").getAsJsonArray(); StringBuilder result = new StringBuilder(); - JSONArray resultArray = object.getJSONArray("choices"); - for (Object s : resultArray) { - JSONObject choice = JSON.parseObject(s.toString()); - JSONObject messages = choice.getJSONObject("message"); - String content = JSON.parseObject(messages.toString()).getString("content"); + for (JsonElement element : choices) { + JsonObject messages = element.getAsJsonObject().get("message").getAsJsonObject(); + String content = messages.get("content").getAsString(); result.append(content); } ParseResult parseResult = new ParseResult(); - parseResult.source = HtmlUtil.md2html(result.toString()); + parseResult.source = result.toString(); parseResult.html = HtmlUtil.md2html(result.toString()); return parseResult; } diff --git a/src/main/java/com/obiscr/chatgpt/settings/OpenAISettingsPanel.java b/src/main/java/com/obiscr/chatgpt/settings/OpenAISettingsPanel.java index 95fc671..52e38a6 100644 --- a/src/main/java/com/obiscr/chatgpt/settings/OpenAISettingsPanel.java +++ b/src/main/java/com/obiscr/chatgpt/settings/OpenAISettingsPanel.java @@ -1,12 +1,7 @@ // Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.obiscr.chatgpt.settings; -import cn.hutool.http.HttpUtil; -import com.alibaba.fastjson2.JSON; -import com.alibaba.fastjson2.JSONObject; -import com.intellij.icons.AllIcons; import com.intellij.openapi.Disposable; -import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ex.ApplicationManagerEx; import com.intellij.openapi.options.Configurable; import com.intellij.openapi.ui.MessageDialogBuilder; diff --git a/src/main/java/com/obiscr/chatgpt/ui/MainPanel.java b/src/main/java/com/obiscr/chatgpt/ui/MainPanel.java index de5fd93..6a585ca 100644 --- a/src/main/java/com/obiscr/chatgpt/ui/MainPanel.java +++ b/src/main/java/com/obiscr/chatgpt/ui/MainPanel.java @@ -13,6 +13,7 @@ import com.obiscr.chatgpt.message.ChatGPTBundle; import com.obiscr.chatgpt.settings.OpenAISettingsState; import com.obiscr.chatgpt.ui.listener.SendListener; +import okhttp3.Call; import okhttp3.sse.EventSource; import org.jetbrains.annotations.NotNull; @@ -62,9 +63,8 @@ public MainPanel(@NotNull Project project, boolean isChatGPTModel) { aroundRequest(false); if (requestHolder instanceof EventSource) { ((EventSource)requestHolder).cancel(); - } else if (requestHolder instanceof MessageComponent) { - ((MessageComponent) requestHolder).setContent("Stop generating"); - ((MessageComponent) requestHolder).setStopping(true); + } else if (requestHolder instanceof Call) { + ((Call) requestHolder).cancel(); } }); stopGenerating.setUI(new DarculaButtonUI()); diff --git a/src/main/java/com/obiscr/chatgpt/ui/MessageComponent.java b/src/main/java/com/obiscr/chatgpt/ui/MessageComponent.java index 121a406..e4924ac 100644 --- a/src/main/java/com/obiscr/chatgpt/ui/MessageComponent.java +++ b/src/main/java/com/obiscr/chatgpt/ui/MessageComponent.java @@ -6,6 +6,7 @@ import com.intellij.notification.Notification; import com.intellij.notification.NotificationType; import com.intellij.notification.Notifications; +import com.intellij.notification.impl.ui.NotificationsUtil; import com.intellij.ui.JBColor; import com.intellij.ui.components.JBLabel; import com.intellij.ui.components.JBPanel; @@ -15,9 +16,10 @@ import com.obiscr.chatgpt.message.ChatGPTBundle; import com.obiscr.chatgpt.settings.OpenAISettingsState; import com.obiscr.chatgpt.util.ImgUtils; +import com.obiscr.chatgpt.util.StringUtil; +import javax.accessibility.AccessibleContext; import javax.swing.*; - import java.awt.*; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; @@ -29,14 +31,12 @@ */ public class MessageComponent extends JBPanel { - private final JEditorPane component = new JEditorPane(); + private final MessagePanel component = new MessagePanel(); private final String question; private String answer; - private AtomicBoolean stopping = new AtomicBoolean(false); - public MessageComponent(String content, boolean me) { question = content; setDoubleBuffered(true); @@ -89,11 +89,11 @@ public Component createContentComponent(String content) { component.setEditable(false); component.putClientProperty(JEditorPane.HONOR_DISPLAY_PROPERTIES, java.lang.Boolean.TRUE); - component.setContentType("text/html;charset=UTF-8"); + component.setContentType("text/html; charset=UTF-8"); component.setOpaque(false); component.setBorder(null); - component.setText(content); + component.updateMessage(content); component.setEditable(false); if (component.getCaret() != null) { @@ -107,10 +107,10 @@ public Component createContentComponent(String content) { } public void setContent(String content) { - if (!stopping.get()) { - component.setText(content); + SwingUtilities.invokeLater(() -> { + component.updateMessage(content); component.updateUI(); - } + }); } public void setSourceContent(String source) { @@ -123,8 +123,4 @@ public void scrollToBottom() { scrollRectToVisible(bounds); }); } - - public void setStopping(boolean stopping) { - this.stopping.set(stopping); - } } diff --git a/src/main/java/com/obiscr/chatgpt/ui/MessageGroupComponent.java b/src/main/java/com/obiscr/chatgpt/ui/MessageGroupComponent.java index 4879897..2ee0ce5 100644 --- a/src/main/java/com/obiscr/chatgpt/ui/MessageGroupComponent.java +++ b/src/main/java/com/obiscr/chatgpt/ui/MessageGroupComponent.java @@ -1,6 +1,6 @@ package com.obiscr.chatgpt.ui; -import com.alibaba.fastjson2.JSONArray; +import com.google.gson.JsonArray; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.NullableComponent; import com.intellij.ui.Gray; @@ -41,7 +41,7 @@ public class MessageGroupComponent extends JBPanel implem new MessageComponent("Must Read: https://chatgpt.en.obiscr.com/getting-started/
使用必读: https://chatgpt.cn.obiscr.com/getting-started/",false); private JBTextField systemRole; private static final String systemRoleText = "You are a helpful language assistant"; - private final JSONArray messages = new JSONArray(); + private JsonArray messages = new JsonArray(); public MessageGroupComponent(@NotNull Project project, boolean isChatGPT) { setBorder(JBUI.Borders.empty(10, 10, 10, 0)); setLayout(new BorderLayout(JBUI.scale(7), 0)); @@ -85,7 +85,7 @@ public void mouseClicked(MouseEvent e) { if (isChatGPT) { ConversationManager.getInstance(project).setConversationId(null); } else { - messages.clear(); + messages = new JsonArray(); } } }); @@ -199,7 +199,7 @@ public void removeScrollListener() { removeAdjustmentListener(scrollListener); } - public JSONArray getMessages() { + public JsonArray getMessages() { return messages; } diff --git a/src/main/java/com/obiscr/chatgpt/ui/MessagePanel.java b/src/main/java/com/obiscr/chatgpt/ui/MessagePanel.java new file mode 100644 index 0000000..0e173c5 --- /dev/null +++ b/src/main/java/com/obiscr/chatgpt/ui/MessagePanel.java @@ -0,0 +1,32 @@ +package com.obiscr.chatgpt.ui; + +import com.intellij.util.ui.HtmlPanel; +import com.intellij.util.ui.UIUtil; +import com.obiscr.chatgpt.util.StringUtil; +import org.jetbrains.annotations.Nls; +import org.jetbrains.annotations.NotNull; + +import java.awt.*; + +/** + * @author Wuzi + */ +public class MessagePanel extends HtmlPanel { + + private String message = ""; + + @Override + protected @NotNull @Nls String getBody() { + return StringUtil.isEmpty(message) ? "" : message; + } + + @Override + protected @NotNull Font getBodyFont() { + return UIUtil.getLabelFont(); + } + + public void updateMessage(String updateMessage) { + this.message = updateMessage; + update(); + } +} diff --git a/src/main/java/com/obiscr/chatgpt/util/OpenAIUtil.java b/src/main/java/com/obiscr/chatgpt/util/OpenAIUtil.java index 34538d9..de5c9f5 100644 --- a/src/main/java/com/obiscr/chatgpt/util/OpenAIUtil.java +++ b/src/main/java/com/obiscr/chatgpt/util/OpenAIUtil.java @@ -1,16 +1,12 @@ package com.obiscr.chatgpt.util; import cn.hutool.http.HttpUtil; -import com.alibaba.fastjson2.JSON; -import com.alibaba.fastjson2.JSONObject; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; import com.intellij.openapi.ui.MessageDialogBuilder; -import com.intellij.ui.components.JBTextField; -import com.obiscr.OpenAIProxy; import com.obiscr.chatgpt.settings.OpenAISettingsState; -import com.obiscr.chatgpt.settings.SettingConfiguration; import javax.swing.*; -import java.net.Proxy; import java.nio.charset.StandardCharsets; import static com.obiscr.chatgpt.settings.OpenAISettingsPanel.CREATE_API_KEY; @@ -30,23 +26,23 @@ public static void refreshGranted(String apiKey, JComponent component, header("Authorization", "Bearer " + apiKey).setProxy(state.getProxy()). timeout(5000) .execute().body(); - JSONObject object = JSON.parseObject(grants); - if (object.containsKey("error")) { - String errorMessage = object.getJSONObject("error").getString("message"); + JsonObject object = JsonParser.parseString(grants).getAsJsonObject(); + if (object.keySet().contains("error")) { + String errorMessage = object.get("error").getAsJsonObject().get("message").getAsString(); MessageDialogBuilder.yesNo("Refresh Failed", "Refresh grant failed, error: " + errorMessage) .show(); return; } - if (!object.containsKey("total_used") || !object.containsKey("total_granted")) { + if (!object.keySet().contains("total_used") || !object.keySet().contains("total_granted")) { MessageDialogBuilder.yesNo("Refresh Failed", "Refresh grant failed, please try again later.") .show(); return; } - Double used = object.getDouble("total_used"); - Double available = object.getDouble("total_available"); - Double granted = object.getDouble("total_granted"); + Double used = object.get("total_used").getAsDouble(); + Double available = object.get("total_available").getAsDouble(); + Double granted = object.get("total_granted").getAsDouble(); usedField.setText(String.valueOf(used)); availableField.setText(String.valueOf(available)); grantField.setText(String.valueOf(granted)); @@ -58,33 +54,33 @@ public static void refreshGranted(String apiKey, JComponent component, } public static void createAPIKey(String apiKey, JComponent component) { - JSONObject params = new JSONObject(); - params.put("action", "create"); + JsonObject params = new JsonObject(); + params.addProperty("action", "create"); OpenAISettingsState state = OpenAISettingsState.getInstance(); try { String grants = HttpUtil.createPost(CREATE_API_KEY). header("Authorization", "Bearer " + apiKey). header("Content-Type", "application/json") - .body(params.toJSONString().getBytes(StandardCharsets.UTF_8)) + .body(params.toString().getBytes(StandardCharsets.UTF_8)) .timeout(5000) .setProxy(state.getProxy()) .execute().body(); - JSONObject object = JSON.parseObject(grants); - if (object.containsKey("error")) { - String errorMessage = object.getJSONObject("error").getString("message"); + JsonObject object = JsonParser.parseString(grants).getAsJsonObject(); + if (object.keySet().contains("error")) { + String errorMessage = object.get("error").getAsJsonObject().get("message").getAsString(); MessageDialogBuilder.yesNo("Create API Key Failed", "Refresh grant failed, error: " + errorMessage) .show(); return; } - if (!object.containsKey("result") || !object.getString("result").equals("success")) { + if (!object.keySet().contains("result") || !object.get("result").getAsString().equals("success")) { MessageDialogBuilder.yesNo("Create API Key Failed", "Create API Key failed, please try again later.") .show(); return; } - JSONObject key = object.getJSONObject("key"); - String newKey = key.getString("sensitive_id"); + JsonObject key = object.get("key").getAsJsonObject(); + String newKey = key.get("sensitive_id").getAsString(); boolean ask = MessageDialogBuilder.yesNo("Create API Key successful", "Your API Key is: \n\n" + newKey + " \n\nThe API Key will only be displayed once, please record the API " + "Key immediately. Do you want to save it to GPT-3.5-Turbo?\n") diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml index 39dcf53..240ae0f 100644 --- a/src/main/resources/META-INF/plugin.xml +++ b/src/main/resources/META-INF/plugin.xml @@ -97,6 +97,7 @@ +