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> | ||||
|             <groupId>eu.m724</groupId> | ||||
|             <artifactId>chatapi</artifactId> | ||||
|             <version>1.0</version> | ||||
|             <version>1.1.1</version> | ||||
|         </dependency> | ||||
|     </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; | ||||
| 
 | ||||
| import eu.m724.chaqt.chatwindow.ChatWindowWidget; | ||||
| import eu.m724.chatapi.chat.Chat; | ||||
| import io.qt.widgets.QApplication; | ||||
| import io.qt.widgets.QMessageBox; | ||||
| 
 | ||||
| public class Main  { | ||||
| 
 | ||||
|  | @ -11,9 +11,10 @@ public class Main  { | |||
| 
 | ||||
|         Chat chat = new Chat(); | ||||
| 
 | ||||
|         ChatWindowWidget widget = new ChatWindowWidget(chat); | ||||
|         ChatWindowWidget widget = new ChatWindowWidget(); | ||||
|         widget.show(); | ||||
| 
 | ||||
|         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…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Minecon724
				Minecon724