diff --git a/src/main/java/de/derpandaa/aitestsuit/ChatGPTApiWrapper.java b/src/main/java/de/derpandaa/aitestsuit/ChatGPTApiWrapper.java index b3e3c10..e0fee73 100644 --- a/src/main/java/de/derpandaa/aitestsuit/ChatGPTApiWrapper.java +++ b/src/main/java/de/derpandaa/aitestsuit/ChatGPTApiWrapper.java @@ -5,6 +5,7 @@ import java.net.URI; import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; +import java.util.function.Consumer; import de.derpandaa.aitestsuit.MessageDto.Role; import de.derpandaa.aitestsuit.OpenAiDto.Model; @@ -36,8 +37,6 @@ public class ChatGPTApiWrapper { HttpClient client = HttpClient.newHttpClient(); try { HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); - System.out.println(response.statusCode()); - System.out.println(response.body()); JsonNode root = mapper.readTree(response.body()); return root.path("choices").path(0).path("message").path("content").asString(); } catch (IOException | InterruptedException e) { @@ -45,5 +44,28 @@ public class ChatGPTApiWrapper { } return ""; } -} + public static void runAsync(OpenAiDto dto, Consumer onResult) { + ObjectMapper mapper = new ObjectMapper(); + String jsonBody = mapper.writeValueAsString(dto); + + HttpRequest request = HttpRequest.newBuilder().uri(URI.create("https://api.openai.com/v1/chat/completions")) + .header("Content-Type", "application/json").header("Authorization", "Bearer " + API_KEY) + .POST(HttpRequest.BodyPublishers.ofString(jsonBody)).build(); + + HttpClient client = HttpClient.newHttpClient(); + client.sendAsync(request, HttpResponse.BodyHandlers.ofString()).thenApply(HttpResponse::body) + .thenAccept(body -> { + try { + JsonNode root = mapper.readTree(body); + String content = root.path("choices").path(0).path("message").path("content").asString(); + onResult.accept(content); + } catch (Exception e) { + onResult.accept(""); + } + }).exceptionally(ex -> { + onResult.accept(""); + return null; + }); + } +} diff --git a/src/main/java/de/derpandaa/aitestsuit/ChatWindow.java b/src/main/java/de/derpandaa/aitestsuit/ChatWindow.java index 697dc3f..2d70f49 100644 --- a/src/main/java/de/derpandaa/aitestsuit/ChatWindow.java +++ b/src/main/java/de/derpandaa/aitestsuit/ChatWindow.java @@ -7,19 +7,26 @@ import java.util.Properties; import de.derpandaa.aitestsuit.MessageDto.Role; import de.derpandaa.aitestsuit.OpenAiDto.Model; +import io.qt.core.QMetaObject; +import io.qt.core.QMimeData; import io.qt.core.Qt.AlignmentFlag; +import io.qt.core.Qt.ConnectionType; import io.qt.gui.QColor; +import io.qt.gui.QKeySequence; import io.qt.gui.QPalette; +import io.qt.gui.QShortcut; import io.qt.widgets.QApplication; import io.qt.widgets.QBoxLayout; import io.qt.widgets.QComboBox; import io.qt.widgets.QFrame; import io.qt.widgets.QHBoxLayout; import io.qt.widgets.QLabel; -import io.qt.widgets.QLineEdit; import io.qt.widgets.QMainWindow; import io.qt.widgets.QPushButton; import io.qt.widgets.QScrollArea; +import io.qt.widgets.QSizePolicy; +import io.qt.widgets.QSizePolicy.Policy; +import io.qt.widgets.QTextEdit; import io.qt.widgets.QVBoxLayout; import io.qt.widgets.QWidget; @@ -28,7 +35,7 @@ public class ChatWindow extends QMainWindow { private QBoxLayout layout; private QVBoxLayout chatLayout; private QWidget chatWidget; - private QLineEdit textInput; + private QTextEdit textInput; private OpenAiDto openAiDto; private QComboBox modelComboBox; @@ -61,15 +68,26 @@ public class ChatWindow extends QMainWindow { layout.addWidget(scrollArea); QHBoxLayout inputLayout = new QHBoxLayout(); - textInput = new QLineEdit(); + textInput = new QTextEdit() { + @Override + protected void insertFromMimeData(QMimeData source) { + insertPlainText(source.text()); + } + }; + textInput.setMaximumHeight(100); textInput.setPlaceholderText("Nachricht eingeben..."); + QPushButton sendButton = new QPushButton("Senden"); sendButton.clicked.connect(() -> sendMessage()); + sendButton.setSizePolicy(new QSizePolicy(Policy.Minimum, Policy.Minimum)); inputLayout.addWidget(textInput); inputLayout.addWidget(sendButton); layout.addLayout(inputLayout); + QShortcut shortcut = new QShortcut(new QKeySequence("Ctrl+Return"), widget); + shortcut.activated.connect(() -> sendMessage()); + widget.setLayout(layout); setCentralWidget(widget); resize(600, 500); @@ -88,7 +106,7 @@ public class ChatWindow extends QMainWindow { frame.setFrameShadow(QFrame.Shadow.Raised); // frame.setMaximumWidth(Integer.MAX_VALUE); -// frame.setSizePolicy(QSizePolicy.Policy.Maximum, QSizePolicy.Policy.Preferred); + frame.setSizePolicy(QSizePolicy.Policy.Maximum, QSizePolicy.Policy.Preferred); QVBoxLayout frameLayout = new QVBoxLayout(frame); @@ -129,7 +147,7 @@ public class ChatWindow extends QMainWindow { } private void sendMessage() { - String message = textInput.text().trim(); + String message = textInput.getPlainText().trim(); if (message.isEmpty()) { return; @@ -144,14 +162,27 @@ public class ChatWindow extends QMainWindow { textInput.clear(); chatWidget.adjustSize(); - String answer = ChatGPTApiWrapper.run(openAiDto); + QWidget loadingWidget = createMessage("Loading...", Role.assistant); + chatLayout.addWidget(loadingWidget); + chatWidget.adjustSize(); + + ChatGPTApiWrapper.runAsync(openAiDto, answer -> { + QMetaObject.invokeMethod(this, () -> { + chatLayout.removeWidget(loadingWidget); + loadingWidget.disposeLater(); + + openAiDto.addMessage(new MessageDto(Role.assistant, answer)); + chatLayout.addWidget(createMessage(answer, Role.assistant)); + chatWidget.adjustSize(); + }, ConnectionType.QueuedConnection); +// update(); + }); - openAiDto.addMessage(new MessageDto(Role.assistant, answer)); - chatLayout.addWidget(createMessage(answer, Role.assistant)); } public static void main(String[] args) { QApplication.initialize(args); + QApplication.setStyle("Fusion"); initProperties(); ChatWindow window = new ChatWindow();