Modify for 1.1
This commit is contained in:
parent
876b72ef6a
commit
f5f20dd0e9
8 changed files with 258 additions and 79 deletions
2
pom.xml
2
pom.xml
|
@ -36,7 +36,7 @@
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>eu.m724</groupId>
|
<groupId>eu.m724</groupId>
|
||||||
<artifactId>chatapi</artifactId>
|
<artifactId>chatapi</artifactId>
|
||||||
<version>1.0</version>
|
<version>1.1.1</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
|
|
|
@ -1,14 +0,0 @@
|
||||||
package eu.m724.chaqt;
|
|
||||||
|
|
||||||
import eu.m724.chatapi.chat.Chat;
|
|
||||||
|
|
||||||
public class ChatWindowViewModel {
|
|
||||||
private ChatWindowWidget widget;
|
|
||||||
|
|
||||||
private Chat chat;
|
|
||||||
|
|
||||||
public ChatWindowViewModel(ChatWindowWidget widget, Chat chat) {
|
|
||||||
this.widget = widget;
|
|
||||||
this.chat = chat;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,62 +0,0 @@
|
||||||
package eu.m724.chaqt;
|
|
||||||
|
|
||||||
import eu.m724.chatapi.chat.Chat;
|
|
||||||
import io.qt.core.Qt;
|
|
||||||
import io.qt.widgets.*;
|
|
||||||
|
|
||||||
public class ChatWindowWidget extends QWidget {
|
|
||||||
private ChatWindowViewModel viewModel;
|
|
||||||
|
|
||||||
private QVBoxLayout layout;
|
|
||||||
private QTextEdit textEdit;
|
|
||||||
|
|
||||||
public ChatWindowWidget(Chat chat) {
|
|
||||||
this.viewModel = new ChatWindowViewModel(this, chat);
|
|
||||||
|
|
||||||
//
|
|
||||||
|
|
||||||
this.layout = new QVBoxLayout();
|
|
||||||
layout.setAlignment(Qt.AlignmentFlag.AlignBottom); // or top?
|
|
||||||
|
|
||||||
QWidget widget = new QWidget();
|
|
||||||
widget.setLayout(layout);
|
|
||||||
|
|
||||||
QScrollArea scrollArea = new QScrollArea();
|
|
||||||
scrollArea.setWidgetResizable(true);
|
|
||||||
scrollArea.setWidget(widget);
|
|
||||||
|
|
||||||
//
|
|
||||||
|
|
||||||
this.textEdit = new QTextEdit();
|
|
||||||
textEdit.setPlaceholderText("Write a message...");
|
|
||||||
textEdit.textChanged.connect(this, "handleComposerType()");
|
|
||||||
|
|
||||||
QPushButton sendButton = new QPushButton("Send");
|
|
||||||
|
|
||||||
QHBoxLayout composerLayout = new QHBoxLayout();
|
|
||||||
composerLayout.addWidget(textEdit);
|
|
||||||
composerLayout.addWidget(sendButton, 0, Qt.AlignmentFlag.AlignBottom);
|
|
||||||
|
|
||||||
QWidget composerWidget = new QWidget();
|
|
||||||
composerWidget.setLayout(composerLayout);
|
|
||||||
|
|
||||||
handleComposerType(); // TODO make it resizable and fix it
|
|
||||||
|
|
||||||
//
|
|
||||||
|
|
||||||
QVBoxLayout mainLayout = new QVBoxLayout();
|
|
||||||
mainLayout.addWidget(scrollArea, 1);
|
|
||||||
mainLayout.addWidget(composerWidget);
|
|
||||||
setLayout(mainLayout);
|
|
||||||
|
|
||||||
for (int i=0; i<10; i++) {
|
|
||||||
QPushButton pushButton = new QPushButton("hello");
|
|
||||||
layout.addWidget(pushButton);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void handleComposerType() {
|
|
||||||
int height = (int) textEdit.document().size().height();
|
|
||||||
textEdit.setFixedHeight(height + textEdit.contentsMargins().top() + textEdit.contentsMargins().bottom());
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,8 +1,8 @@
|
||||||
package eu.m724.chaqt;
|
package eu.m724.chaqt;
|
||||||
|
|
||||||
|
import eu.m724.chaqt.chatwindow.ChatWindowWidget;
|
||||||
import eu.m724.chatapi.chat.Chat;
|
import eu.m724.chatapi.chat.Chat;
|
||||||
import io.qt.widgets.QApplication;
|
import io.qt.widgets.QApplication;
|
||||||
import io.qt.widgets.QMessageBox;
|
|
||||||
|
|
||||||
public class Main {
|
public class Main {
|
||||||
|
|
||||||
|
@ -11,9 +11,10 @@ public class Main {
|
||||||
|
|
||||||
Chat chat = new Chat();
|
Chat chat = new Chat();
|
||||||
|
|
||||||
ChatWindowWidget widget = new ChatWindowWidget(chat);
|
ChatWindowWidget widget = new ChatWindowWidget();
|
||||||
widget.show();
|
widget.show();
|
||||||
|
|
||||||
QApplication.exec();
|
QApplication.exec();
|
||||||
|
QApplication.shutdown();
|
||||||
}
|
}
|
||||||
}
|
}
|
22
src/main/java/eu/m724/chaqt/ObservableChat.java
Normal file
22
src/main/java/eu/m724/chaqt/ObservableChat.java
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
package eu.m724.chaqt;
|
||||||
|
|
||||||
|
import eu.m724.chatapi.chat.Chat;
|
||||||
|
import eu.m724.chatapi.chat.ChatMessage;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
public class ObservableChat extends Chat {
|
||||||
|
private Set<Consumer<ChatMessage>> watchers = new HashSet<>();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addMessage(ChatMessage message) {
|
||||||
|
super.addMessage(message);
|
||||||
|
watchers.forEach(c -> c.accept(message));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void watch(Consumer<ChatMessage> callable) {
|
||||||
|
this.watchers.add(callable);
|
||||||
|
}
|
||||||
|
}
|
30
src/main/java/eu/m724/chaqt/QMessage.java
Normal file
30
src/main/java/eu/m724/chaqt/QMessage.java
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
package eu.m724.chaqt;
|
||||||
|
|
||||||
|
import io.qt.core.QMargins;
|
||||||
|
import io.qt.gui.QPalette;
|
||||||
|
import io.qt.widgets.QLabel;
|
||||||
|
import io.qt.widgets.QVBoxLayout;
|
||||||
|
import io.qt.widgets.QWidget;
|
||||||
|
|
||||||
|
// TODO I think we could put Qtextdocument here
|
||||||
|
public class QMessage extends QWidget {
|
||||||
|
private final QLabel label;
|
||||||
|
|
||||||
|
public QMessage(boolean assistant, String text) {
|
||||||
|
this.label = new QLabel(text);
|
||||||
|
label.setWordWrap(true);
|
||||||
|
|
||||||
|
QVBoxLayout layout = new QVBoxLayout();
|
||||||
|
layout.addWidget(label);
|
||||||
|
|
||||||
|
if (assistant) {
|
||||||
|
layout.setContentsMargins(5,0,0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
setLayout(layout);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addText(String text) {
|
||||||
|
label.setText(label.text() + text);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,69 @@
|
||||||
|
package eu.m724.chaqt.chatwindow;
|
||||||
|
|
||||||
|
import eu.m724.chatapi.chat.Chat;
|
||||||
|
import eu.m724.chatapi.chat.ChatEvent;
|
||||||
|
import eu.m724.chatapi.chat.ChatMessage;
|
||||||
|
import eu.m724.chatapi.example.ExampleSource;
|
||||||
|
import eu.m724.chatapi.source.ChatResponse;
|
||||||
|
import eu.m724.chatapi.source.ChatSource;
|
||||||
|
import io.qt.core.QObject.Signal1;
|
||||||
|
import io.qt.core.QThread;
|
||||||
|
|
||||||
|
public class ChatWindowViewModel {
|
||||||
|
private final ChatWindowWidget widget;
|
||||||
|
private final Signal1<ChatMessage> chatMessageSignal;
|
||||||
|
private final Signal1<ChatEvent> chatEventSignal;
|
||||||
|
|
||||||
|
private Chat chat = new Chat();
|
||||||
|
private ChatSource source = new ExampleSource(); // TODO
|
||||||
|
|
||||||
|
|
||||||
|
public ChatWindowViewModel(ChatWindowWidget widget, Signal1<ChatEvent> chatEventSignal, Signal1<ChatMessage> chatMessageSignal) {
|
||||||
|
this.widget = widget;
|
||||||
|
this.chatEventSignal = chatEventSignal;
|
||||||
|
this.chatMessageSignal = chatMessageSignal;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void send(String text) {
|
||||||
|
ChatMessage promptMessage = new ChatMessage(false, text);
|
||||||
|
chatMessageSignal.emit(promptMessage);
|
||||||
|
chat.addMessage(new ChatMessage(false, text));
|
||||||
|
|
||||||
|
ChatResponse response = source.ask(chat);
|
||||||
|
ChatMessage message = response.message();
|
||||||
|
|
||||||
|
chatMessageSignal.emit(message);
|
||||||
|
message.addEventConsumer(chatEventSignal::emit, true);
|
||||||
|
|
||||||
|
/*QThread thread = new QThread() {
|
||||||
|
@Override
|
||||||
|
protected void run() {
|
||||||
|
ChatEvent token;
|
||||||
|
do {
|
||||||
|
try {
|
||||||
|
token = response.eventQueue().take();
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
throw new RuntimeException(e); // TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
chatEventSignal.emit(token);
|
||||||
|
|
||||||
|
if (token.finishReason() != null) {
|
||||||
|
chatMessageSignal.emit(response.message().join()); // TODO ???
|
||||||
|
}
|
||||||
|
/*if (!"error".equals(token.finishReason())) {
|
||||||
|
if (token.text() != null) {
|
||||||
|
chatEventSignal.emit(token.text());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
System.out.print("Error: " + token.error().toString());
|
||||||
|
}/
|
||||||
|
} while (token.finishReason() == null);
|
||||||
|
// QApplication.invokeLater(() -> resultField.setText(result));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
thread.start();*/
|
||||||
|
//
|
||||||
|
}
|
||||||
|
}
|
133
src/main/java/eu/m724/chaqt/chatwindow/ChatWindowWidget.java
Normal file
133
src/main/java/eu/m724/chaqt/chatwindow/ChatWindowWidget.java
Normal file
|
@ -0,0 +1,133 @@
|
||||||
|
package eu.m724.chaqt.chatwindow;
|
||||||
|
|
||||||
|
import eu.m724.chaqt.QMessage;
|
||||||
|
import eu.m724.chatapi.chat.ChatEvent;
|
||||||
|
import eu.m724.chatapi.chat.ChatMessage;
|
||||||
|
import io.qt.core.Qt;
|
||||||
|
import io.qt.widgets.*;
|
||||||
|
|
||||||
|
public class ChatWindowWidget extends QWidget {
|
||||||
|
private ChatWindowViewModel viewModel;
|
||||||
|
|
||||||
|
private QVBoxLayout layout;
|
||||||
|
private QTextEdit textEdit;
|
||||||
|
|
||||||
|
// TODO are both really needed
|
||||||
|
private final Signal1<ChatMessage> chatMessageSignal = new Signal1<>();
|
||||||
|
private final Signal1<ChatEvent> chatEventSignal = new Signal1<>();
|
||||||
|
|
||||||
|
private QMessage latestMessage;
|
||||||
|
|
||||||
|
public ChatWindowWidget() {
|
||||||
|
this.viewModel = new ChatWindowViewModel(this, chatEventSignal, chatMessageSignal);
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
chatEventSignal.connect(this::handleChatEvent);
|
||||||
|
chatMessageSignal.connect(this::handleChatMessage);
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
this.layout = new QVBoxLayout();
|
||||||
|
layout.setAlignment(Qt.AlignmentFlag.AlignBottom); // or top?
|
||||||
|
|
||||||
|
QWidget widget = new QWidget();
|
||||||
|
widget.setLayout(layout);
|
||||||
|
|
||||||
|
QScrollArea scrollArea = new QScrollArea();
|
||||||
|
scrollArea.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff);
|
||||||
|
scrollArea.setWidgetResizable(true);
|
||||||
|
scrollArea.setWidget(widget);
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
this.textEdit = new QTextEdit();
|
||||||
|
textEdit.setPlaceholderText("Write a message...");
|
||||||
|
textEdit.textChanged.connect(this, "handleComposerType()");
|
||||||
|
|
||||||
|
QPushButton sendButton = new QPushButton("Send");
|
||||||
|
sendButton.clicked.connect(this::onSend);
|
||||||
|
|
||||||
|
QHBoxLayout composerLayout = new QHBoxLayout();
|
||||||
|
composerLayout.addWidget(textEdit);
|
||||||
|
composerLayout.addWidget(sendButton, 0, Qt.AlignmentFlag.AlignBottom);
|
||||||
|
|
||||||
|
QWidget composerWidget = new QWidget();
|
||||||
|
composerWidget.setLayout(composerLayout);
|
||||||
|
|
||||||
|
handleComposerType(); // TODO make it resizable and fix it
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
QVBoxLayout mainLayout = new QVBoxLayout();
|
||||||
|
mainLayout.addWidget(scrollArea, 1);
|
||||||
|
mainLayout.addWidget(composerWidget);
|
||||||
|
setLayout(mainLayout);
|
||||||
|
|
||||||
|
/*for (int i=0; i<10; i++) {
|
||||||
|
QPushButton pushButton = new QPushButton("hello");
|
||||||
|
layout.addWidget(pushButton);
|
||||||
|
}*/
|
||||||
|
|
||||||
|
textEdit.setFocus();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void handleComposerType() {
|
||||||
|
int height = (int) textEdit.document().size().height();
|
||||||
|
textEdit.setFixedHeight(height + textEdit.contentsMargins().top() + textEdit.contentsMargins().bottom());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onSend() {
|
||||||
|
String prompt = textEdit.getPlainText();
|
||||||
|
if (!prompt.isBlank()) {
|
||||||
|
textEdit.setText("");
|
||||||
|
viewModel.send(prompt);
|
||||||
|
|
||||||
|
textEdit.setEnabled(false);
|
||||||
|
textEdit.setPlaceholderText("Asking...");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleChatMessage(ChatMessage message) {
|
||||||
|
System.out.printf("Widget received a message. Is response: %b\n", message.response());
|
||||||
|
|
||||||
|
QMessage qMessage = new QMessage(false, message.content());
|
||||||
|
layout.addWidget(qMessage);
|
||||||
|
|
||||||
|
// if the message is by assistant, disable composer.
|
||||||
|
// I don't know if this is good, but it works
|
||||||
|
if (message.response()) {
|
||||||
|
textEdit.setEnabled(false);
|
||||||
|
textEdit.setPlaceholderText("Thinking...");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleChatEvent(ChatEvent chatEvent) {
|
||||||
|
String token = chatEvent.text();
|
||||||
|
|
||||||
|
// usually when it's the first token
|
||||||
|
if (latestMessage == null) {
|
||||||
|
latestMessage = new QMessage(true, "");
|
||||||
|
layout.addWidget(latestMessage);
|
||||||
|
|
||||||
|
textEdit.setPlaceholderText("Responding...");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (token != null) {
|
||||||
|
latestMessage.addText(token);
|
||||||
|
}
|
||||||
|
|
||||||
|
// when finished
|
||||||
|
if (chatEvent.finishReason() != null) {
|
||||||
|
// to make sure we won't be streaming to the same message
|
||||||
|
latestMessage = null;
|
||||||
|
|
||||||
|
// enable composer
|
||||||
|
textEdit.setEnabled(true);
|
||||||
|
textEdit.setPlaceholderText("Write a message...");
|
||||||
|
textEdit.setFocus();
|
||||||
|
}
|
||||||
|
|
||||||
|
System.out.printf("Event: %s %s\n", chatEvent.finishReason(), chatEvent.text());
|
||||||
|
} // TODO that's messy so do something about that
|
||||||
|
}
|
Loading…
Reference in a new issue