Skip to content

Commit daf72c4

Browse files
committed
feat(demo): add generative ai simulation demo
1 parent e1e681e commit daf72c4

File tree

2 files changed

+145
-0
lines changed

2 files changed

+145
-0
lines changed

src/test/java/com/flowingcode/vaadin/addons/chatassistant/ChatAssistantDemoView.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ public ChatAssistantDemoView() {
3535
addDemo(ChatAssistantDemo.class);
3636
addDemo(ChatAssistantLazyLoadingDemo.class);
3737
addDemo(ChatAssistantMarkdownDemo.class);
38+
addDemo(ChatAssistantGenerativeDemo.class);
3839
setSizeFull();
3940
}
4041
}
Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
/*-
2+
* #%L
3+
* Chat Assistant Add-on
4+
* %%
5+
* Copyright (C) 2023 - 2025 Flowing Code
6+
* %%
7+
* Licensed under the Apache License, Version 2.0 (the "License");
8+
* you may not use this file except in compliance with the License.
9+
* You may obtain a copy of the License at
10+
*
11+
* http://www.apache.org/licenses/LICENSE-2.0
12+
*
13+
* Unless required by applicable law or agreed to in writing, software
14+
* distributed under the License is distributed on an "AS IS" BASIS,
15+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
* See the License for the specific language governing permissions and
17+
* limitations under the License.
18+
* #L%
19+
*/
20+
package com.flowingcode.vaadin.addons.chatassistant;
21+
22+
import com.flowingcode.vaadin.addons.demo.DemoSource;
23+
import com.flowingcode.vaadin.addons.demo.SourcePosition;
24+
import com.google.common.base.Strings;
25+
import com.vaadin.flow.component.UI;
26+
import com.vaadin.flow.component.avatar.Avatar;
27+
import com.vaadin.flow.component.button.Button;
28+
import com.vaadin.flow.component.dependency.CssImport;
29+
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
30+
import com.vaadin.flow.component.textfield.TextArea;
31+
import com.vaadin.flow.data.renderer.ComponentRenderer;
32+
import com.vaadin.flow.router.PageTitle;
33+
import com.vaadin.flow.router.Route;
34+
import java.time.LocalDateTime;
35+
import java.util.Arrays;
36+
import java.util.concurrent.CompletableFuture;
37+
import java.util.concurrent.ThreadLocalRandom;
38+
import java.util.concurrent.TimeUnit;
39+
import java.util.stream.Stream;
40+
41+
@DemoSource(sourcePosition = SourcePosition.PRIMARY)
42+
@PageTitle("Generative Answer Demo")
43+
@SuppressWarnings("serial")
44+
@Route(value = "chat-assistant/generative-demo", layout = ChatAssistantDemoView.class)
45+
@CssImport("./styles/chat-assistant-styles-demo.css")
46+
public class ChatAssistantGenerativeDemo extends VerticalLayout {
47+
48+
public ChatAssistantGenerativeDemo() {
49+
String sampleText = "Hi, I'm an advanced language model. I'm here to help you demonstrate"
50+
+ " how a text-streaming chat component works in Vaadin. As you can see, each word appears"
51+
+ " with a slight pause, simulating the time it would take me to \"think\" and generate"
52+
+ " the next word. I hope this is useful for your demonstration!";
53+
54+
ChatAssistant<CustomMessage> chatAssistant = new ChatAssistant<>();
55+
chatAssistant.setAvatarProvider(()->new Avatar("Chat Assistant","chatbot.png"));
56+
TextArea message = new TextArea();
57+
message.setLabel("Enter a message from the assistant");
58+
message.setSizeFull();
59+
message.setValue(sampleText);
60+
message.addKeyPressListener(ev->{
61+
if (Strings.isNullOrEmpty(chatAssistant.getWhoIsTyping())) {
62+
chatAssistant.setWhoIsTyping("Assistant is generating an answer ...");
63+
}
64+
});
65+
message.addBlurListener(ev->chatAssistant.clearWhoIsTyping());
66+
chatAssistant.setMessagesRenderer(new ComponentRenderer<CustomChatMessage,CustomMessage>(m -> {
67+
return new CustomChatMessage(m);
68+
},
69+
(component, m) -> {
70+
((CustomChatMessage) component).setMessage(m);
71+
return component;
72+
}));
73+
chatAssistant.setSubmitListener(se -> {
74+
chatAssistant.sendMessage(CustomMessage.builder().messageTime(LocalDateTime.now())
75+
.name("User").content(se.getValue()).tagline("Generated by user").build());
76+
});
77+
78+
Button chat = new Button("Chat");
79+
chat.addClickListener(ev -> {
80+
CustomMessage m = CustomMessage.builder().content(message.getValue()).messageTime(LocalDateTime.now())
81+
.name("Assistant").avatar("chatbot.png").tagline("Generated by assistant").build();
82+
83+
chatAssistant.sendMessage(m);
84+
message.clear();
85+
});
86+
Button chatWithThinking = new Button("Chat With Generative Thinking");
87+
chatWithThinking.addClickListener(ev -> {
88+
String messageToSend = message.getValue();
89+
message.setValue("");
90+
CustomMessage delayedMessage = CustomMessage.builder().loading(true).content("")
91+
.messageTime(LocalDateTime.now())
92+
.name("Assistant").avatar("chatbot.png").tagline("Generated by assistant").build();
93+
94+
UI currentUI = UI.getCurrent();
95+
chatAssistant.sendMessage(delayedMessage);
96+
97+
CompletableFuture.runAsync(() -> {
98+
try {
99+
TimeUnit.MILLISECONDS.sleep(500);
100+
currentUI.access(() -> {
101+
delayedMessage.setLoading(false);
102+
});
103+
streamWords(messageToSend)
104+
.forEach(item -> {
105+
currentUI.access(() -> {
106+
delayedMessage.setContent(delayedMessage.getContent() + " " + item);
107+
chatAssistant.updateMessage(delayedMessage);
108+
});
109+
});
110+
} catch (InterruptedException e) {
111+
Thread.currentThread().interrupt();
112+
}
113+
});
114+
115+
message.clear();
116+
});
117+
chatAssistant.sendMessage(CustomMessage.builder().content("Hello, I am here to assist you")
118+
.messageTime(LocalDateTime.now())
119+
.name("Assistant").avatar("chatbot.png").tagline("Generated by assistant").build());
120+
121+
add(message, chat, chatWithThinking, chatAssistant);
122+
}
123+
124+
public Stream<String> streamWords(String fullText) {
125+
if (fullText == null || fullText.isEmpty()) {
126+
return Stream.empty();
127+
}
128+
129+
String[] words = fullText.split("\\s+");
130+
131+
return Arrays.stream(words)
132+
.map(word -> {
133+
try {
134+
long delay = ThreadLocalRandom.current().nextLong(50, 250);
135+
Thread.sleep(delay);
136+
} catch (InterruptedException e) {
137+
Thread.currentThread().interrupt();
138+
}
139+
140+
return word + " ";
141+
});
142+
}
143+
144+
}

0 commit comments

Comments
 (0)