Just a temp commit
This commit is contained in:
2
pom.xml
2
pom.xml
@@ -6,6 +6,8 @@
|
||||
<properties>
|
||||
<qtjambi.version>6.10.0</qtjambi.version>
|
||||
<jackson.version>3.0.3</jackson.version>
|
||||
<maven.compiler.source>24</maven.compiler.source>
|
||||
<maven.compiler.release>24</maven.compiler.release>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
|
||||
@@ -1,71 +0,0 @@
|
||||
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 java.util.function.Consumer;
|
||||
|
||||
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<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
|
||||
JsonNode root = mapper.readTree(response.body());
|
||||
return root.path("choices").path(0).path("message").path("content").asString();
|
||||
} catch (IOException | InterruptedException e) {
|
||||
// NOOP
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
public static void runAsync(OpenAiDto dto, Consumer<String> 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;
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package de.derpandaa.aitestsuit;
|
||||
package de.derpandaa.plinfa;
|
||||
|
||||
import io.qt.widgets.QApplication;
|
||||
import io.qt.widgets.QBoxLayout;
|
||||
@@ -9,12 +9,9 @@ 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();
|
||||
public class AiWindow extends QMainWindow {
|
||||
public AiWindow() {
|
||||
super();
|
||||
QWidget widget = new QWidget();
|
||||
QBoxLayout layout = new QVBoxLayout();
|
||||
|
||||
@@ -39,16 +36,23 @@ public class AiWindow {
|
||||
|
||||
QPushButton buttonRun = new QPushButton("Run");
|
||||
buttonRun.clicked.connect(() -> {
|
||||
String result = ChatGPTApiWrapper.run(editSystemPrompt.getPlainText(), editUserPrompt.getPlainText());
|
||||
editAiAnser.setText(result);
|
||||
// String result = AiProviderManager.getAiProviderManager().run(editSystemPrompt.getPlainText(),
|
||||
// editUserPrompt.getPlainText());
|
||||
// editAiAnser.setText(result);
|
||||
});
|
||||
|
||||
layout.addWidget(buttonRun);
|
||||
|
||||
widget.setLayout(layout);
|
||||
|
||||
window.setCentralWidget(widget);
|
||||
window.show();
|
||||
setCentralWidget(widget);
|
||||
show();
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
QApplication.initialize(args);
|
||||
AiWindow window = new AiWindow();
|
||||
|
||||
QApplication.exec();
|
||||
QApplication.shutdown();
|
||||
}
|
||||
40
src/main/java/de/derpandaa/plinfa/ChatListWidget.java
Normal file
40
src/main/java/de/derpandaa/plinfa/ChatListWidget.java
Normal file
@@ -0,0 +1,40 @@
|
||||
package de.derpandaa.plinfa;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import de.derpandaa.plinfa.dto.ChatDto;
|
||||
import de.derpandaa.plinfa.projects.GenericProject;
|
||||
import io.qt.core.Qt;
|
||||
import io.qt.widgets.QTreeWidget;
|
||||
import io.qt.widgets.QTreeWidgetItem;
|
||||
|
||||
public class ChatListWidget extends QTreeWidget {
|
||||
|
||||
public ChatListWidget(Consumer<ChatDto> clickedFunction) {
|
||||
super();
|
||||
setHeaderHidden(true);
|
||||
GenericProject root = new GenericProject(new File(ChatDto.PROJECT_DIR));
|
||||
loadProject(root, null);
|
||||
itemClicked.connect((item, column) -> {
|
||||
ChatDto chat = (ChatDto) item.data(0, Qt.ItemDataRole.UserRole);
|
||||
if (chat != null) {
|
||||
clickedFunction.accept(chat);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void loadProject(GenericProject project, QTreeWidgetItem parent) {
|
||||
for (GenericProject subProject : project.getSubProjects()) {
|
||||
QTreeWidgetItem folderItem = parent == null ? new QTreeWidgetItem(this) : new QTreeWidgetItem(parent);
|
||||
folderItem.setText(0, subProject.getName());
|
||||
loadProject(subProject, folderItem);
|
||||
}
|
||||
|
||||
for (ChatDto chat : project.getChats()) {
|
||||
QTreeWidgetItem chatItem = parent == null ? new QTreeWidgetItem(this) : new QTreeWidgetItem(parent);
|
||||
chatItem.setText(0, chat.getName());
|
||||
chatItem.setData(0, Qt.ItemDataRole.UserRole, chat);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,27 +1,24 @@
|
||||
package de.derpandaa.aitestsuit;
|
||||
package de.derpandaa.plinfa;
|
||||
|
||||
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.QMetaObject;
|
||||
import de.derpandaa.plinfa.aiprovider.AiProviderManager;
|
||||
import de.derpandaa.plinfa.aiprovider.Model;
|
||||
import de.derpandaa.plinfa.dto.ChatDto;
|
||||
import de.derpandaa.plinfa.dto.MessageDto;
|
||||
import de.derpandaa.plinfa.dto.MessageDto.Role;
|
||||
import de.derpandaa.plinfa.dto.OpenAiDto;
|
||||
import io.qt.core.QMimeData;
|
||||
import io.qt.core.Qt.AlignmentFlag;
|
||||
import io.qt.core.Qt.ConnectionType;
|
||||
import io.qt.core.Qt.TextFormat;
|
||||
import io.qt.gui.QColor;
|
||||
import io.qt.gui.QKeySequence;
|
||||
import io.qt.gui.QPalette;
|
||||
import io.qt.gui.QPalette.ColorRole;
|
||||
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.QMainWindow;
|
||||
import io.qt.widgets.QPushButton;
|
||||
import io.qt.widgets.QScrollArea;
|
||||
import io.qt.widgets.QSizePolicy;
|
||||
@@ -30,36 +27,43 @@ import io.qt.widgets.QTextEdit;
|
||||
import io.qt.widgets.QVBoxLayout;
|
||||
import io.qt.widgets.QWidget;
|
||||
|
||||
public class ChatWindow extends QMainWindow {
|
||||
public class ChatWindow extends QWidget {
|
||||
|
||||
private QBoxLayout layout;
|
||||
private QVBoxLayout chatLayout;
|
||||
private QWidget chatWidget;
|
||||
private QTextEdit textInput;
|
||||
private OpenAiDto openAiDto;
|
||||
private ChatDto chatDto;
|
||||
private QComboBox modelComboBox;
|
||||
private QScrollArea scrollArea;
|
||||
|
||||
public ChatWindow() {
|
||||
this(new ChatDto());
|
||||
}
|
||||
|
||||
public ChatWindow(ChatDto chatDto) {
|
||||
super();
|
||||
openAiDto = new OpenAiDto(Model.gpt5_2, new MessageDto(Role.system, "Antworte kurz und präzise"));
|
||||
QPalette palette = getPalette();
|
||||
palette.setColor(ColorRole.Window, PlinfaWindow.colorBackgroundAlt);
|
||||
setPalette(palette);
|
||||
this.chatDto = chatDto;
|
||||
|
||||
QWidget widget = new QWidget();
|
||||
layout = new QVBoxLayout();
|
||||
layout.setContentsMargins(10, 10, 10, 10);
|
||||
layout = new QVBoxLayout(this);
|
||||
layout.setContentsMargins(10, 0, 10, 10);
|
||||
|
||||
QPushButton button = new QPushButton("Import Chat");
|
||||
layout.addWidget(button);
|
||||
QLabel chatNameLabel = new QLabel(chatDto.getName());
|
||||
layout.addWidget(chatNameLabel);
|
||||
|
||||
modelComboBox = new QComboBox();
|
||||
for (OpenAiDto.Model m : OpenAiDto.Model.values()) {
|
||||
for (Model m : AiProviderManager.getAiProviderManager().getActiveModels()) {
|
||||
modelComboBox.addItem(m.toString(), m);
|
||||
}
|
||||
layout.addWidget(modelComboBox);
|
||||
|
||||
QScrollArea scrollArea = new QScrollArea();
|
||||
scrollArea = new QScrollArea();
|
||||
scrollArea.setWidgetResizable(true);
|
||||
|
||||
chatWidget = new QWidget();
|
||||
chatWidget = new QWidget(this);
|
||||
chatLayout = new QVBoxLayout(chatWidget);
|
||||
chatLayout.setAlignment(AlignmentFlag.AlignTop);
|
||||
chatLayout.setSpacing(5);
|
||||
@@ -85,18 +89,21 @@ public class ChatWindow extends QMainWindow {
|
||||
inputLayout.addWidget(sendButton);
|
||||
layout.addLayout(inputLayout);
|
||||
|
||||
QShortcut shortcut = new QShortcut(new QKeySequence("Ctrl+Return"), widget);
|
||||
QShortcut shortcut = new QShortcut(new QKeySequence("Ctrl+Return"), this);
|
||||
shortcut.activated.connect(() -> sendMessage());
|
||||
|
||||
widget.setLayout(layout);
|
||||
setCentralWidget(widget);
|
||||
resize(600, 500);
|
||||
show();
|
||||
importChat(chatDto);
|
||||
}
|
||||
|
||||
private void importChat(OpenAiDto openAiDto) {
|
||||
for (MessageDto messageDto : openAiDto.getMessages()) {
|
||||
// chatLayout.addWidget(createMessage(messageDto.getContent(), true));
|
||||
private void importChat(ChatDto chatDto) {
|
||||
if (chatDto.getOpenAiDto().getMessages() == null) {
|
||||
return;
|
||||
}
|
||||
for (MessageDto messageDto : chatDto.getOpenAiDto().getMessages()) {
|
||||
if (messageDto.getRole() != Role.system) {
|
||||
chatLayout.addWidget(createMessage(messageDto.getContent(), messageDto.getRole()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -105,13 +112,14 @@ public class ChatWindow extends QMainWindow {
|
||||
frame.setFrameShape(QFrame.Shape.Box);
|
||||
frame.setFrameShadow(QFrame.Shadow.Raised);
|
||||
|
||||
// frame.setMaximumWidth(Integer.MAX_VALUE);
|
||||
frame.setSizePolicy(QSizePolicy.Policy.Maximum, QSizePolicy.Policy.Preferred);
|
||||
frame.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Maximum);
|
||||
frame.setMaximumWidth((int) (chatWidget.getMaximumWidth() + 0.7));
|
||||
|
||||
QVBoxLayout frameLayout = new QVBoxLayout(frame);
|
||||
|
||||
frameLayout.setContentsMargins(10, 10, 10, 10);
|
||||
QLabel textLabel = new QLabel(message);
|
||||
textLabel.setTextFormat(TextFormat.MarkdownText);
|
||||
textLabel.setWordWrap(true);
|
||||
frameLayout.addWidget(textLabel);
|
||||
|
||||
@@ -152,12 +160,17 @@ public class ChatWindow extends QMainWindow {
|
||||
if (message.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
openAiDto.setModel((Model) modelComboBox.currentData());
|
||||
|
||||
OpenAiDto openAiDto = chatDto.getOpenAiDto();
|
||||
|
||||
openAiDto.setModel((de.derpandaa.plinfa.aiprovider.Model) modelComboBox.currentData());
|
||||
|
||||
MessageDto messageDto = new MessageDto(Role.user, message);
|
||||
openAiDto.addMessage(messageDto);
|
||||
|
||||
chatLayout.addWidget(createMessage(message, Role.user));
|
||||
QWidget userWidget = createMessage(message, Role.user);
|
||||
chatLayout.addWidget(userWidget);
|
||||
scrollArea.ensureWidgetVisible(userWidget);
|
||||
|
||||
textInput.clear();
|
||||
chatWidget.adjustSize();
|
||||
@@ -166,41 +179,24 @@ public class ChatWindow extends QMainWindow {
|
||||
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();
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
QApplication.initialize(args);
|
||||
QApplication.setStyle("Fusion");
|
||||
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);
|
||||
// .runAsync(openAiDto, answer -> {
|
||||
// QMetaObject.invokeMethod(this, () -> {
|
||||
// chatLayout.removeWidget(loadingWidget);
|
||||
// loadingWidget.disposeLater();
|
||||
//
|
||||
// openAiDto.addMessage(new MessageDto(Role.assistant, answer));
|
||||
// QWidget assistantWidget = createMessage(answer, Role.assistant);
|
||||
// chatLayout.addWidget(assistantWidget);
|
||||
// scrollArea.ensureWidgetVisible(assistantWidget);
|
||||
// chatWidget.adjustSize();
|
||||
// chatDto.writeToFile();
|
||||
//
|
||||
// }, ConnectionType.QueuedConnection);
|
||||
// });
|
||||
} catch (Exception e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
ChatGPTApiWrapper.API_KEY = properties.getProperty("OPENAI_KEY");
|
||||
}
|
||||
}
|
||||
23
src/main/java/de/derpandaa/plinfa/PlinfaMenu.java
Normal file
23
src/main/java/de/derpandaa/plinfa/PlinfaMenu.java
Normal file
@@ -0,0 +1,23 @@
|
||||
package de.derpandaa.plinfa;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import io.qt.gui.QIcon;
|
||||
import io.qt.widgets.QToolBar;
|
||||
import io.qt.widgets.QToolButton;
|
||||
|
||||
public class PlinfaMenu extends QToolBar {
|
||||
|
||||
public PlinfaMenu() {
|
||||
setMaximumHeight(50);
|
||||
}
|
||||
|
||||
public void addButton(QIcon icon, Consumer<Boolean> function, String toolTip) {
|
||||
QToolButton button = new QToolButton();
|
||||
button.setIcon(icon);
|
||||
button.clicked.connect(bool -> function.accept(bool));
|
||||
button.setToolTip(toolTip);
|
||||
addWidget(button);
|
||||
button.setDown(true);
|
||||
}
|
||||
}
|
||||
104
src/main/java/de/derpandaa/plinfa/PlinfaWindow.java
Normal file
104
src/main/java/de/derpandaa/plinfa/PlinfaWindow.java
Normal file
@@ -0,0 +1,104 @@
|
||||
package de.derpandaa.plinfa;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import de.derpandaa.plinfa.aiprovider.OpenAiProvider;
|
||||
import de.derpandaa.plinfa.dto.ChatDto;
|
||||
import io.qt.gui.QColor;
|
||||
import io.qt.gui.QIcon;
|
||||
import io.qt.gui.QPalette;
|
||||
import io.qt.gui.QPalette.ColorRole;
|
||||
import io.qt.widgets.QApplication;
|
||||
import io.qt.widgets.QHBoxLayout;
|
||||
import io.qt.widgets.QMainWindow;
|
||||
import io.qt.widgets.QVBoxLayout;
|
||||
import io.qt.widgets.QWidget;
|
||||
|
||||
public class PlinfaWindow extends QMainWindow {
|
||||
|
||||
public final static QColor colorBackground = new QColor(40, 42, 46);
|
||||
public final static QColor colorBackgroundAlt = new QColor(55, 59, 65);
|
||||
public final static QColor colorForeground = new QColor(208, 208, 208);
|
||||
|
||||
private ChatWindow chatWindow;
|
||||
private QVBoxLayout vLayout;
|
||||
private QHBoxLayout hLayout;
|
||||
private PlinfaMenu menuBar;
|
||||
private Map<ChatDto, ChatWindow> chatMap;
|
||||
|
||||
public PlinfaWindow() {
|
||||
super();
|
||||
QPalette palette = getPalette();
|
||||
palette.setColor(ColorRole.Window, colorBackground);
|
||||
palette.setColor(ColorRole.Base, colorBackgroundAlt);
|
||||
palette.setColor(ColorRole.Button, colorBackgroundAlt);
|
||||
palette.setColor(ColorRole.Text, colorForeground);
|
||||
palette.setColor(ColorRole.ButtonText, colorForeground);
|
||||
palette.setColor(ColorRole.PlaceholderText, colorForeground);
|
||||
setPalette(palette);
|
||||
|
||||
QWidget mainWidget = new QWidget();
|
||||
QWidget widget = new QWidget();
|
||||
vLayout = new QVBoxLayout(mainWidget);
|
||||
menuBar = new PlinfaMenu();
|
||||
menuBar.addButton(new QIcon("/usr/share/pandaaPop/img/brightness.svg"), null, "Test");
|
||||
vLayout.addWidget(menuBar);
|
||||
|
||||
|
||||
hLayout = new QHBoxLayout(widget);
|
||||
vLayout.addWidget(widget);
|
||||
|
||||
ChatListWidget chatListWidget = new ChatListWidget(chat -> loadChat(chat));
|
||||
hLayout.addWidget(chatListWidget, 1);
|
||||
chatWindow = new ChatWindow();
|
||||
hLayout.addWidget(chatWindow, 3);
|
||||
|
||||
chatMap = new HashMap<ChatDto, ChatWindow>();
|
||||
|
||||
setCentralWidget(mainWidget);
|
||||
show();
|
||||
}
|
||||
|
||||
public void loadChat(ChatDto chatDto) {
|
||||
hLayout.removeWidget(chatWindow);
|
||||
chatWindow.hide();
|
||||
ChatWindow cachedChatWindow = chatMap.get(chatDto);
|
||||
if (cachedChatWindow == null) {
|
||||
cachedChatWindow = new ChatWindow(chatDto);
|
||||
chatMap.put(chatDto, cachedChatWindow);
|
||||
}
|
||||
chatWindow = cachedChatWindow;
|
||||
hLayout.addWidget(chatWindow, 3);
|
||||
chatWindow.show();
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
QApplication.initialize(args);
|
||||
QApplication.setStyle("Fusion");
|
||||
initProperties();
|
||||
PlinfaWindow window = new PlinfaWindow();
|
||||
|
||||
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);
|
||||
}
|
||||
OpenAiProvider.API_KEY = properties.getProperty("OPENAI_KEY");
|
||||
ChatDto.PROJECT_DIR = properties.getProperty("PROJECT_DIR");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
package de.derpandaa.plinfa.aiprovider;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.http.HttpClient;
|
||||
import java.net.http.HttpRequest;
|
||||
import java.net.http.HttpResponse;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import de.derpandaa.plinfa.dto.AiRequest;
|
||||
import de.derpandaa.plinfa.dto.AiResponseDto;
|
||||
import de.derpandaa.plinfa.dto.OpenAiDto;
|
||||
import tools.jackson.databind.JsonNode;
|
||||
import tools.jackson.databind.ObjectMapper;
|
||||
|
||||
public abstract class AbstractAiProvider {
|
||||
public enum Provider {
|
||||
OPEN_AI
|
||||
}
|
||||
|
||||
protected static final ObjectMapper mapper = new ObjectMapper();
|
||||
|
||||
public static String OpenAiKey;
|
||||
|
||||
|
||||
// GPT5_NANO("gpt-5-nano", Provider.OPENAI), GPT5_MINI("gpt-5-mini", Provider.OPENAI),
|
||||
// GPT5_2("gpt-5.2", Provider.OPENAI), CLAUDE_OPUS("claude-opus-4-6", Provider.ANTHROPIC),
|
||||
// CLAUDE_SONNET("claude-sonnet-4-6", Provider.ANTHROPIC), CLAUDE_HAIKU("claude-haiku-4-5", Provider.ANTHROPIC);
|
||||
|
||||
public abstract List<Model> getModels();
|
||||
|
||||
public abstract HttpRequest buildRequest(String jsonBody);
|
||||
|
||||
public abstract AiResponseDto parseResponse(String body);
|
||||
|
||||
public AiResponseDto run(AiRequest request) {
|
||||
String jsonBody = mapper.writeValueAsString(request);
|
||||
|
||||
System.out.println(jsonBody);
|
||||
HttpRequest httpRequest = buildRequest(jsonBody);
|
||||
|
||||
HttpClient client = HttpClient.newHttpClient();
|
||||
try {
|
||||
HttpResponse<String> response = client.send(httpRequest, HttpResponse.BodyHandlers.ofString());
|
||||
return parseResponse(response.body());
|
||||
} catch (IOException | InterruptedException e) {
|
||||
// NOOP
|
||||
}
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
public void runAsync(OpenAiDto dto, Consumer<String> onResult) {
|
||||
String jsonBody = mapper.writeValueAsString(dto);
|
||||
|
||||
HttpRequest request = buildRequest(jsonBody);
|
||||
|
||||
HttpClient client = HttpClient.newHttpClient();
|
||||
client.sendAsync(request, HttpResponse.BodyHandlers.ofString()).thenApply(HttpResponse::body)
|
||||
.thenAccept(body -> {
|
||||
JsonNode root = mapper.readTree(body);
|
||||
String content = root.path("choices").path(0).path("message").path("content").asString();
|
||||
onResult.accept(content);
|
||||
}).exceptionally(ex -> {
|
||||
onResult.accept("");
|
||||
return null;
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package de.derpandaa.plinfa.aiprovider;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class AiProviderManager {
|
||||
private final List<AbstractAiProvider> providers;
|
||||
private static AiProviderManager aiProviderManager;
|
||||
private List<Model> models = new ArrayList<Model>();
|
||||
|
||||
public AiProviderManager() {
|
||||
providers = new ArrayList<AbstractAiProvider>();
|
||||
if (OpenAiProvider.API_KEY != null) {
|
||||
providers.add(new OpenAiProvider());
|
||||
}
|
||||
}
|
||||
|
||||
public static AiProviderManager getAiProviderManager() {
|
||||
if (aiProviderManager == null) {
|
||||
aiProviderManager = new AiProviderManager();
|
||||
}
|
||||
return aiProviderManager;
|
||||
}
|
||||
|
||||
public List<Model> getActiveModels() {
|
||||
if (models.isEmpty()) {
|
||||
for (AbstractAiProvider aiProvider : providers) {
|
||||
models.addAll(aiProvider.getModels());
|
||||
}
|
||||
}
|
||||
return models;
|
||||
}
|
||||
|
||||
}
|
||||
11
src/main/java/de/derpandaa/plinfa/aiprovider/Model.java
Normal file
11
src/main/java/de/derpandaa/plinfa/aiprovider/Model.java
Normal file
@@ -0,0 +1,11 @@
|
||||
package de.derpandaa.plinfa.aiprovider;
|
||||
|
||||
import de.derpandaa.plinfa.aiprovider.AbstractAiProvider.Provider;
|
||||
|
||||
public record Model(String modelName, Provider provider) {
|
||||
@Override
|
||||
public String toString() {
|
||||
return modelName;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package de.derpandaa.plinfa.aiprovider;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.http.HttpRequest;
|
||||
import java.util.List;
|
||||
|
||||
import de.derpandaa.plinfa.dto.AiResponseDto;
|
||||
import de.derpandaa.plinfa.dto.OpenAiResponseDto;
|
||||
|
||||
public class OpenAiProvider extends AbstractAiProvider {
|
||||
public static String API_KEY;
|
||||
private static int maxTokens;
|
||||
private static OpenAiProvider openAiProvider;
|
||||
|
||||
public OpenAiProvider() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpRequest buildRequest(String jsonBody) {
|
||||
return 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();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Model> getModels() {
|
||||
|
||||
return List.of(new Model("gpt-5-nano", Provider.OPEN_AI));
|
||||
}
|
||||
|
||||
@Override
|
||||
public AiResponseDto parseResponse(String body) {
|
||||
return new OpenAiResponseDto(body);
|
||||
}
|
||||
|
||||
}
|
||||
51
src/main/java/de/derpandaa/plinfa/dto/AiRequest.java
Normal file
51
src/main/java/de/derpandaa/plinfa/dto/AiRequest.java
Normal file
@@ -0,0 +1,51 @@
|
||||
package de.derpandaa.plinfa.dto;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import de.derpandaa.plinfa.aiprovider.Model;
|
||||
|
||||
public class AiRequest {
|
||||
private Model model;
|
||||
private int maxTokens;
|
||||
private String systemPrompt;
|
||||
private List<MessageDto> messages;
|
||||
|
||||
public AiRequest(Model model) {
|
||||
this.model = model;
|
||||
this.maxTokens = 4096;
|
||||
this.messages = new ArrayList<>();
|
||||
}
|
||||
|
||||
public Model getModel() {
|
||||
return model;
|
||||
}
|
||||
|
||||
public void setModel(Model model) {
|
||||
this.model = model;
|
||||
}
|
||||
|
||||
public int getMaxTokens() {
|
||||
return maxTokens;
|
||||
}
|
||||
|
||||
public void setMaxTokens(int maxTokens) {
|
||||
this.maxTokens = maxTokens;
|
||||
}
|
||||
|
||||
public String getSystemPrompt() {
|
||||
return systemPrompt;
|
||||
}
|
||||
|
||||
public void setSystemPrompt(String systemPrompt) {
|
||||
this.systemPrompt = systemPrompt;
|
||||
}
|
||||
|
||||
public List<MessageDto> getMessages() {
|
||||
return messages;
|
||||
}
|
||||
|
||||
public void addMessages(MessageDto message) {
|
||||
messages.add(message);
|
||||
}
|
||||
}
|
||||
23
src/main/java/de/derpandaa/plinfa/dto/AiResponseDto.java
Normal file
23
src/main/java/de/derpandaa/plinfa/dto/AiResponseDto.java
Normal file
@@ -0,0 +1,23 @@
|
||||
package de.derpandaa.plinfa.dto;
|
||||
|
||||
import tools.jackson.databind.ObjectMapper;
|
||||
|
||||
public abstract class AiResponseDto {
|
||||
protected String response;
|
||||
protected int tokensUsed;
|
||||
protected ObjectMapper mapper = new ObjectMapper();
|
||||
|
||||
public AiResponseDto(String jsonBody) {
|
||||
parseBody(jsonBody);
|
||||
}
|
||||
|
||||
protected abstract void parseBody(String jsonBody);
|
||||
|
||||
public String getResponse() {
|
||||
return response;
|
||||
}
|
||||
|
||||
public int getTokensUsed() {
|
||||
return tokensUsed;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package de.derpandaa.plinfa.dto;
|
||||
|
||||
import tools.jackson.databind.JsonNode;
|
||||
|
||||
public class AnthropicResponseDto extends AiResponseDto {
|
||||
public AnthropicResponseDto(String jsonBody) {
|
||||
super(jsonBody);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void parseBody(String jsonBody) {
|
||||
JsonNode root = mapper.readTree(jsonBody);
|
||||
response = root.path("content").path(0).path("text").asString();
|
||||
tokensUsed = root.path("usage").path("input_tokens").asInt() + root.path("usage").path("output_tokens").asInt();
|
||||
}
|
||||
|
||||
}
|
||||
60
src/main/java/de/derpandaa/plinfa/dto/ChatDto.java
Normal file
60
src/main/java/de/derpandaa/plinfa/dto/ChatDto.java
Normal file
@@ -0,0 +1,60 @@
|
||||
package de.derpandaa.plinfa.dto;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import tools.jackson.core.JacksonException;
|
||||
import tools.jackson.databind.ObjectMapper;
|
||||
|
||||
public class ChatDto {
|
||||
|
||||
public static String PROJECT_DIR;
|
||||
|
||||
private String name;
|
||||
private OpenAiDto openAiDto;
|
||||
|
||||
public ChatDto() {
|
||||
this.openAiDto = new OpenAiDto();
|
||||
}
|
||||
|
||||
public ChatDto(File f) {
|
||||
loadFromFile(f);
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public OpenAiDto getOpenAiDto() {
|
||||
return openAiDto;
|
||||
}
|
||||
|
||||
public void setOpenAiDto(OpenAiDto openAiDto) {
|
||||
this.openAiDto = openAiDto;
|
||||
}
|
||||
|
||||
private void loadFromFile(File f) {
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
|
||||
setName(f.getName().substring(0, f.getName().indexOf(".json")));
|
||||
try {
|
||||
openAiDto = mapper.readValue(f, OpenAiDto.class);
|
||||
} catch (JacksonException e) {
|
||||
e.printStackTrace();
|
||||
System.out.println("Deserialisierung fehlgeschlagen");
|
||||
}
|
||||
}
|
||||
|
||||
public void writeToFile() {
|
||||
if (name == null) {
|
||||
return;
|
||||
}
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
File f = new File(String.format("%s/%s.json", PROJECT_DIR, name));
|
||||
mapper.writeValue(f.getAbsoluteFile(), openAiDto);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,7 +1,9 @@
|
||||
package de.derpandaa.aitestsuit;
|
||||
package de.derpandaa.plinfa.dto;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
|
||||
|
||||
@JsonPropertyOrder({ "role", "content" })
|
||||
public class MessageDto {
|
||||
|
||||
public enum Role {
|
||||
@@ -13,6 +15,9 @@ public class MessageDto {
|
||||
@JsonProperty("content")
|
||||
private String content;
|
||||
|
||||
public MessageDto() {
|
||||
}
|
||||
|
||||
public MessageDto(Role role, String content) {
|
||||
this.role = role;
|
||||
this.content = content;
|
||||
@@ -22,4 +27,8 @@ public class MessageDto {
|
||||
return content;
|
||||
}
|
||||
|
||||
public Role getRole() {
|
||||
return role;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,29 +1,17 @@
|
||||
package de.derpandaa.aitestsuit;
|
||||
package de.derpandaa.plinfa.dto;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
|
||||
|
||||
import de.derpandaa.plinfa.aiprovider.Model;
|
||||
|
||||
@JsonPropertyOrder({ "model", "messages" })
|
||||
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;
|
||||
@@ -31,6 +19,22 @@ public class OpenAiDto {
|
||||
@JsonProperty("messages")
|
||||
private List<MessageDto> messages;
|
||||
|
||||
@JsonProperty("max_tokens")
|
||||
private int maxTokens;
|
||||
|
||||
public OpenAiDto() {
|
||||
this(8192);
|
||||
}
|
||||
|
||||
public OpenAiDto(int maxTokens) {
|
||||
this.maxTokens = maxTokens;
|
||||
}
|
||||
|
||||
public OpenAiDto(Model model) {
|
||||
this.model = model;
|
||||
this.messages = new ArrayList<MessageDto>();
|
||||
}
|
||||
|
||||
public OpenAiDto(Model model, MessageDto... messages) {
|
||||
this.model = model;
|
||||
this.messages = new ArrayList<MessageDto>();
|
||||
17
src/main/java/de/derpandaa/plinfa/dto/OpenAiResponseDto.java
Normal file
17
src/main/java/de/derpandaa/plinfa/dto/OpenAiResponseDto.java
Normal file
@@ -0,0 +1,17 @@
|
||||
package de.derpandaa.plinfa.dto;
|
||||
|
||||
import tools.jackson.databind.JsonNode;
|
||||
|
||||
public class OpenAiResponseDto extends AiResponseDto {
|
||||
public OpenAiResponseDto(String jsonBody) {
|
||||
super(jsonBody);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void parseBody(String jsonBody) {
|
||||
JsonNode root = mapper.readTree(jsonBody);
|
||||
response = root.path("choices").path(0).path("message").path("content").asString();
|
||||
tokensUsed = root.path("usage").path("total_tokens").asInt();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package de.derpandaa.plinfa.projects;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import de.derpandaa.plinfa.dto.ChatDto;
|
||||
|
||||
public class GenericProject {
|
||||
private String name;
|
||||
private List<GenericProject> subProjects;
|
||||
private List<ChatDto> chats;
|
||||
|
||||
public GenericProject(File dir) {
|
||||
this.name = dir.getName();
|
||||
this.subProjects = new ArrayList<>();
|
||||
this.chats = new ArrayList<>();
|
||||
load(dir);
|
||||
}
|
||||
|
||||
private void load(File dir) {
|
||||
File[] files = dir.listFiles();
|
||||
if (files == null)
|
||||
return;
|
||||
|
||||
for (File f : files) {
|
||||
if (f.isDirectory()) {
|
||||
subProjects.add(new GenericProject(f));
|
||||
} else if (f.getName().endsWith(".json")) {
|
||||
chats.add(new ChatDto(f));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public List<GenericProject> getSubProjects() {
|
||||
return subProjects;
|
||||
}
|
||||
|
||||
public List<ChatDto> getChats() {
|
||||
return chats;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user