diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..aab4095 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +.settings +.classpath +.project +target +*.properties diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..3ba3d16 --- /dev/null +++ b/pom.xml @@ -0,0 +1,32 @@ + + 4.0.0 + de.derpandaa + ai-testsuit + 0.0.1-SNAPSHOT + + 6.10.0 + 3.0.3 + + + + io.qtjambi + qtjambi + ${qtjambi.version} + + + io.qtjambi + qtjambi-native-linux-x64 + ${qtjambi.version} + + + tools.jackson.core + jackson-core + ${jackson.version} + + + tools.jackson.core + jackson-databind + ${jackson.version} + + + \ No newline at end of file diff --git a/src/main/java/de/derpandaa/aitestsuit/AiWindow.java b/src/main/java/de/derpandaa/aitestsuit/AiWindow.java new file mode 100644 index 0000000..20fc50c --- /dev/null +++ b/src/main/java/de/derpandaa/aitestsuit/AiWindow.java @@ -0,0 +1,56 @@ +package de.derpandaa.aitestsuit; + +import io.qt.widgets.QApplication; +import io.qt.widgets.QBoxLayout; +import io.qt.widgets.QLabel; +import io.qt.widgets.QMainWindow; +import io.qt.widgets.QPushButton; +import io.qt.widgets.QTextEdit; +import io.qt.widgets.QVBoxLayout; +import io.qt.widgets.QWidget; + +public class AiWindow { + + + public static void main(String[] args) { + QApplication.initialize(args); + QMainWindow window = new QMainWindow(); + QWidget widget = new QWidget(); + QBoxLayout layout = new QVBoxLayout(); + + QLabel labelSystemPrompt = new QLabel("System Prompt"); + layout.addWidget(labelSystemPrompt); + + QTextEdit editSystemPrompt = new QTextEdit(); + layout.addWidget(editSystemPrompt); + + QLabel labelUserPrompt = new QLabel("User Prompt"); + layout.addWidget(labelUserPrompt); + + QTextEdit editUserPrompt = new QTextEdit(); + layout.addWidget(editUserPrompt); + + QLabel labelAiAnswer = new QLabel("Ai Answer"); + layout.addWidget(labelAiAnswer); + + QTextEdit editAiAnser = new QTextEdit(); + editAiAnser.setEnabled(false); + layout.addWidget(editAiAnser); + + QPushButton buttonRun = new QPushButton("Run"); + buttonRun.clicked.connect(() -> { + String result = ChatGPTApiWrapper.run(editSystemPrompt.getPlainText(), editUserPrompt.getPlainText()); + editAiAnser.setText(result); + }); + + layout.addWidget(buttonRun); + + widget.setLayout(layout); + + window.setCentralWidget(widget); + window.show(); + QApplication.exec(); + QApplication.shutdown(); + } + +} diff --git a/src/main/java/de/derpandaa/aitestsuit/ChatGPTApiWrapper.java b/src/main/java/de/derpandaa/aitestsuit/ChatGPTApiWrapper.java new file mode 100644 index 0000000..b3e3c10 --- /dev/null +++ b/src/main/java/de/derpandaa/aitestsuit/ChatGPTApiWrapper.java @@ -0,0 +1,49 @@ +package de.derpandaa.aitestsuit; + +import java.io.IOException; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; + +import de.derpandaa.aitestsuit.MessageDto.Role; +import de.derpandaa.aitestsuit.OpenAiDto.Model; +import tools.jackson.databind.JsonNode; +import tools.jackson.databind.ObjectMapper; + +/* + * I dont know how to name it + */ +public class ChatGPTApiWrapper { + + public static String API_KEY; + + public static String run(String systemPrompt, String userPrompt) { + OpenAiDto dto = new OpenAiDto(Model.gpt5nano, new MessageDto(Role.system, systemPrompt), + new MessageDto(Role.user, userPrompt)); + return run(dto); + } + + public static String run(OpenAiDto dto) { + ObjectMapper mapper = new ObjectMapper(); + String jsonBody = mapper.writeValueAsString(dto); + + System.out.println(jsonBody); + 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(); + 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) { + // NOOP + } + return ""; + } +} + diff --git a/src/main/java/de/derpandaa/aitestsuit/ChatWindow.java b/src/main/java/de/derpandaa/aitestsuit/ChatWindow.java new file mode 100644 index 0000000..697dc3f --- /dev/null +++ b/src/main/java/de/derpandaa/aitestsuit/ChatWindow.java @@ -0,0 +1,175 @@ +package de.derpandaa.aitestsuit; + +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.Properties; + +import de.derpandaa.aitestsuit.MessageDto.Role; +import de.derpandaa.aitestsuit.OpenAiDto.Model; +import io.qt.core.Qt.AlignmentFlag; +import io.qt.gui.QColor; +import io.qt.gui.QPalette; +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.QVBoxLayout; +import io.qt.widgets.QWidget; + +public class ChatWindow extends QMainWindow { + + private QBoxLayout layout; + private QVBoxLayout chatLayout; + private QWidget chatWidget; + private QLineEdit textInput; + private OpenAiDto openAiDto; + private QComboBox modelComboBox; + + public ChatWindow() { + super(); + openAiDto = new OpenAiDto(Model.gpt5_2, new MessageDto(Role.system, "Antworte kurz und präzise")); + + QWidget widget = new QWidget(); + layout = new QVBoxLayout(); + layout.setContentsMargins(10, 10, 10, 10); + + QPushButton button = new QPushButton("Import Chat"); + layout.addWidget(button); + + modelComboBox = new QComboBox(); + for (OpenAiDto.Model m : OpenAiDto.Model.values()) { + modelComboBox.addItem(m.toString(), m); + } + layout.addWidget(modelComboBox); + + QScrollArea scrollArea = new QScrollArea(); + scrollArea.setWidgetResizable(true); + + chatWidget = new QWidget(); + chatLayout = new QVBoxLayout(chatWidget); + chatLayout.setAlignment(AlignmentFlag.AlignTop); + chatLayout.setSpacing(5); + + scrollArea.setWidget(chatWidget); + layout.addWidget(scrollArea); + + QHBoxLayout inputLayout = new QHBoxLayout(); + textInput = new QLineEdit(); + textInput.setPlaceholderText("Nachricht eingeben..."); + QPushButton sendButton = new QPushButton("Senden"); + sendButton.clicked.connect(() -> sendMessage()); + + inputLayout.addWidget(textInput); + inputLayout.addWidget(sendButton); + layout.addLayout(inputLayout); + + widget.setLayout(layout); + setCentralWidget(widget); + resize(600, 500); + show(); + } + + private void importChat(OpenAiDto openAiDto) { + for (MessageDto messageDto : openAiDto.getMessages()) { +// chatLayout.addWidget(createMessage(messageDto.getContent(), true)); + } + } + + private QWidget createMessage(String message, Role role) { + QFrame frame = new QFrame(); + frame.setFrameShape(QFrame.Shape.Box); + frame.setFrameShadow(QFrame.Shadow.Raised); + +// frame.setMaximumWidth(Integer.MAX_VALUE); +// frame.setSizePolicy(QSizePolicy.Policy.Maximum, QSizePolicy.Policy.Preferred); + + QVBoxLayout frameLayout = new QVBoxLayout(frame); + + frameLayout.setContentsMargins(10, 10, 10, 10); + QLabel textLabel = new QLabel(message); + textLabel.setWordWrap(true); + frameLayout.addWidget(textLabel); + + QWidget container = new QWidget(); + QHBoxLayout boxLayout = new QHBoxLayout(container); + boxLayout.setContentsMargins(0, 0, 0, 0); + + QPalette palette = frame.palette(); + QColor messageColor; + + switch (role) { + case user: + messageColor = new QColor(209, 114, 246); + boxLayout.addStretch(30); + boxLayout.addWidget(frame, 70); + break; + case assistant: + messageColor = new QColor(106, 91, 117); + boxLayout.addWidget(frame, 70); + boxLayout.addStretch(30); + break; + default: + messageColor = new QColor(100, 100, 100); + boxLayout.addStretch(15); + boxLayout.addWidget(frame, 70); + boxLayout.addStretch(15); + break; + } + palette.setColor(QPalette.ColorRole.Window, messageColor); + frame.setAutoFillBackground(true); + frame.setPalette(palette); + return container; + } + + private void sendMessage() { + String message = textInput.text().trim(); + + if (message.isEmpty()) { + return; + } + openAiDto.setModel((Model) modelComboBox.currentData()); + + MessageDto messageDto = new MessageDto(Role.user, message); + openAiDto.addMessage(messageDto); + + chatLayout.addWidget(createMessage(message, Role.user)); + + textInput.clear(); + chatWidget.adjustSize(); + + String answer = ChatGPTApiWrapper.run(openAiDto); + + openAiDto.addMessage(new MessageDto(Role.assistant, answer)); + chatLayout.addWidget(createMessage(answer, Role.assistant)); + } + + public static void main(String[] args) { + QApplication.initialize(args); + initProperties(); + ChatWindow window = new ChatWindow(); + + QApplication.exec(); + QApplication.shutdown(); + } + + private static void initProperties() { + Properties properties = new Properties(); + try { + properties.load(new FileInputStream("ai.properties")); + } catch (FileNotFoundException e) { + System.out.println("[ERROR] No Properties File"); + System.exit(1); + } catch (IOException e) { + System.out.println("[ERROR] Cannot Access File"); + System.exit(1); + } + ChatGPTApiWrapper.API_KEY = properties.getProperty("OPENAI_KEY"); + } +} \ No newline at end of file diff --git a/src/main/java/de/derpandaa/aitestsuit/MessageDto.java b/src/main/java/de/derpandaa/aitestsuit/MessageDto.java new file mode 100644 index 0000000..7ba996a --- /dev/null +++ b/src/main/java/de/derpandaa/aitestsuit/MessageDto.java @@ -0,0 +1,25 @@ +package de.derpandaa.aitestsuit; + +import com.fasterxml.jackson.annotation.JsonProperty; + +public class MessageDto { + + public enum Role { + system, user, assistant + }; + + @JsonProperty("role") + private Role role; + @JsonProperty("content") + private String content; + + public MessageDto(Role role, String content) { + this.role = role; + this.content = content; + } + + public String getContent() { + return content; + } + +} diff --git a/src/main/java/de/derpandaa/aitestsuit/OpenAiDto.java b/src/main/java/de/derpandaa/aitestsuit/OpenAiDto.java new file mode 100644 index 0000000..2f4f14a --- /dev/null +++ b/src/main/java/de/derpandaa/aitestsuit/OpenAiDto.java @@ -0,0 +1,52 @@ +package de.derpandaa.aitestsuit; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import com.fasterxml.jackson.annotation.JsonProperty; + +public class OpenAiDto { + + public enum Model { + gpt5nano("gpt-5-nano"), + gpt5mini("gpt-5-mini"), + gpt5_2("gpt-5.2"); + + final String value; + + Model(String value) { + this.value = value; + } + + @Override + public String toString() { + return value; + } + } + + @JsonProperty("model") + private Model model; + + @JsonProperty("messages") + private List messages; + + public OpenAiDto(Model model, MessageDto... messages) { + this.model = model; + this.messages = new ArrayList(); + this.messages.addAll(Arrays.asList(messages)); + } + + public void addMessage(MessageDto messageDto) { + messages.add(messageDto); + } + + public List getMessages() { + return messages; + } + + public void setModel(Model model) { + this.model = model; + } + +}