2025年4月6日14:39:48

master
qmstyle 2025-04-06 14:39:53 +08:00
parent 5c86ff4c32
commit 5fcb78176e
4 changed files with 109 additions and 110 deletions

View File

@ -5,6 +5,7 @@ import javafx.scene.control.*;
import javafx.scene.layout.VBox; import javafx.scene.layout.VBox;
import javafx.scene.layout.HBox; import javafx.scene.layout.HBox;
import javafx.scene.text.Text; import javafx.scene.text.Text;
import javafx.scene.text.TextAlignment;
import javafx.scene.text.TextFlow; import javafx.scene.text.TextFlow;
import com.aiclient.service.ChatService; import com.aiclient.service.ChatService;
import com.aiclient.service.MarkdownService; import com.aiclient.service.MarkdownService;
@ -25,6 +26,9 @@ import javafx.scene.control.ScrollPane;
public class MainController { public class MainController {
@FXML
public ScrollPane chatScrollPane;
@FXML @FXML
private ListView<Chat> chatListView; private ListView<Chat> chatListView;
@ -66,6 +70,12 @@ public class MainController {
// 配置快捷键 // 配置快捷键
setupShortcuts(); setupShortcuts();
chatContainer.heightProperty().addListener((observable, oldValue, newValue) -> {
if (chatScrollPane.getVmax() > 0) {
chatScrollPane.setVvalue(1.0);
}
});
} }
private void setupShortcuts() { private void setupShortcuts() {
@ -131,7 +141,7 @@ public class MainController {
Message assistantMessage = new Message("assistant", ""); Message assistantMessage = new Message("assistant", "");
currentChat.addMessage(assistantMessage); currentChat.addMessage(assistantMessage);
HBox messageBox = addMessageToChat(assistantMessage); HBox messageBox = addMessageToChat(assistantMessage);
TextArea textArea = ((TextArea) ((VBox) messageBox.getChildren().get(0)).getChildren().get(0)); TextFlow textFlow = (TextFlow) messageBox.getChildren().get(0);
StringBuilder contentBuilder = new StringBuilder(); StringBuilder contentBuilder = new StringBuilder();
@ -144,7 +154,7 @@ public class MainController {
contentBuilder.append(chunk); contentBuilder.append(chunk);
javafx.application.Platform.runLater(() -> { javafx.application.Platform.runLater(() -> {
assistantMessage.setContent(contentBuilder.toString()); assistantMessage.setContent(contentBuilder.toString());
updateMessage(textArea, contentBuilder.toString() ); updateMessage(textFlow, chunk);
}); });
}, },
() -> { () -> {
@ -153,57 +163,58 @@ public class MainController {
inputArea.setDisable(false); inputArea.setDisable(false);
inputArea.requestFocus(); inputArea.requestFocus();
}); });
} },
currentChat
); );
} }
private HBox addMessageToChat(Message message) { private HBox addMessageToChat(Message message) {
TextFlow textFlow = new TextFlow(); TextFlow textFlow = new TextFlow();
return addMessageToChat(message, textFlow); textFlow.prefWidthProperty().bind(chatContainer.widthProperty());
}
private HBox addMessageToChat(Message message, TextFlow textFlow) { textFlow.setLineSpacing(15);
// 创建一个VBox来包含消息内容
VBox messageContent = new VBox(5); // 5是内部间距
messageContent.setMaxWidth(800); // 限制最大宽度
// 创建文本显示区域 Text text = new Text(message.getContent());
TextArea textArea = new TextArea(message.getContent()); textFlow.getChildren().add(text);
textArea.setWrapText(true);
textArea.setEditable(false);
textArea.setPrefRowCount(1); // 初始显示1行
textArea.setStyle(
"-fx-background-color: transparent;" +
"-fx-text-fill: " + (themeService.isDarkTheme() ? "white" : "black") + ";" +
"-fx-focus-color: transparent;" +
"-fx-faint-focus-color: transparent;"
);
// 自动调整高度
textArea.textProperty().addListener((obs, old, newText) -> {
int lineCount = (int) newText.lines().count();
textArea.setPrefRowCount(Math.max(1, lineCount));
});
messageContent.getChildren().add(textArea);
// 设置消息样式 // 设置消息样式
HBox messageBox = new HBox(messageContent); HBox messageBox = new HBox(textFlow);
messageBox.prefWidthProperty().bind(chatContainer.widthProperty());
messageBox.getStyleClass().add(message.getRole() + "-message"); messageBox.getStyleClass().add(message.getRole() + "-message");
messageBox.setPadding(new javafx.geometry.Insets(10)); messageBox.setPadding(new javafx.geometry.Insets(10));
if ("user".equals(message.getRole())) { if ("user".equals(message.getRole())) {
textFlow.setTextAlignment(TextAlignment.RIGHT);
messageBox.setAlignment(Pos.CENTER_RIGHT); messageBox.setAlignment(Pos.CENTER_RIGHT);
} else { } else {
messageBox.setAlignment(Pos.CENTER_LEFT); messageBox.setAlignment(Pos.CENTER_LEFT);
textFlow.setTextAlignment(TextAlignment.LEFT);
} }
chatContainer.getChildren().add(messageBox); chatContainer.getChildren().add(messageBox);
return messageBox; return messageBox;
} }
private void updateMessage(TextArea textArea, String content) { private void updateMessage(TextFlow textFlow, String content) {
textArea.setText(content);
if (content.contains("<think>")) {
content = content.split("</think>")[1];
if (content.equals("")){
return;
}
}
if (content.contains("</think>")) {
content = content.split("</think>")[1];
}
Text text = new Text(content);
Text spacer = new Text("\r\n");
textFlow.getChildren().add(text);
textFlow.getChildren().add(spacer);
} }
private void loadChat(Chat chat) { private void loadChat(Chat chat) {

View File

@ -29,11 +29,11 @@ public class ChatService {
return new Chat(); return new Chat();
} }
public void sendMessageStream(String message, String model, Consumer<String> onChunk, Runnable onComplete) { public void sendMessageStream(String message, String model, Consumer<String> onChunk, Runnable onComplete,Chat currentChat) {
CompletableFuture.runAsync(() -> { CompletableFuture.runAsync(() -> {
try { try {
String encodedMessage = URLEncoder.encode(message, StandardCharsets.UTF_8); String encodedMessage = URLEncoder.encode(message, StandardCharsets.UTF_8);
String url = String.format("%s?userId=user&input=%s&stream=true", BASE_URL, encodedMessage); String url = String.format("%s?input=%s&userId=%s", BASE_URL, encodedMessage,currentChat.getId());
HttpRequest request = HttpRequest.newBuilder() HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(url)) .uri(URI.create(url))

View File

@ -37,11 +37,6 @@
-fx-background-color: transparent; -fx-background-color: transparent;
} }
.user-message, .assistant-message {
-fx-background-radius: 5;
-fx-max-width: 800;
}
.user-message { .user-message {
-fx-background-color: #007AFF22; -fx-background-color: #007AFF22;
} }
@ -72,14 +67,7 @@
-fx-line-spacing: 5; -fx-line-spacing: 5;
} }
/* 滚动条样式 */
.scroll-bar:vertical {
-fx-pref-width: 12;
}
.scroll-bar:horizontal {
-fx-pref-height: 12;
}
.scroll-bar > .thumb { .scroll-bar > .thumb {
-fx-background-radius: 6; -fx-background-radius: 6;

View File

@ -33,7 +33,7 @@
</HBox> </HBox>
</ToolBar> </ToolBar>
<ScrollPane VBox.vgrow="ALWAYS" fitToWidth="true" styleClass="chat-scroll-pane"> <ScrollPane fx:id="chatScrollPane" VBox.vgrow="ALWAYS" fitToWidth="true" styleClass="chat-scroll-pane">
<VBox fx:id="chatContainer" spacing="10"/> <VBox fx:id="chatContainer" spacing="10"/>
</ScrollPane> </ScrollPane>