Blog

Minimalist Java applications with Vaadin and Spring AI

By  
Sami Ekblad
Sami Ekblad
·
On May 17, 2024 11:32:42 AM
·

“Fight for Simplicity” has always been our motto. Personally, that has meant I want to keep simplifying my code. This post is an example of that effort.

Revisiting AI integration in Vaadin applications

A year ago, you could read about Harnessing Generative AI for Business Applications. This insightful post explored the potential of integrating AI into Vaadin applications, highlighting practical tips and examples. Then Marcus wrote a series building a chatbot for documentation.  Given the rapid advancements in AI technology, things are getting simpler every day, and it's time to revisit this topic and update the starting point for developers. 

Since Vaadin Flow is a Java framework for building modern web applications, its ease of use and strong integration capabilities make it an excellent choice for developers looking to add sophisticated features to their apps. The Spring AI project, on the other hand, provides a straightforward way to incorporate AI functionalities. By merging these two technologies, you can create dynamic, responsive applications with minimal effort. So, this is what we use: 

  • Vaadin Flow: For building the UI and layout. Vaadin handles the WebSocket-based communication. 
  • Vaadin Add-ons: We use MarkdownMessage from the Viritin add-on to show nicely formatted output.
  • Spring AI: For integrating AI capabilities.

Spring AI simplifies the integration of AI models into your Spring applications. It provides a set of APIs to interact with various AI services, making it easier to incorporate features like natural language processing and computer vision:

  • Model Management: Easily manage and deploy different AI models.
  • Inference APIs: Perform real-time predictions and analysis using pre-trained models.
  • Streaming Support: Stream data to and from AI services for dynamic and interactive applications.

These capabilities enable developers to build sophisticated AI-driven features without delving into the complexities of AI model training and deployment.

Project Setup

Start by creating a new Spring Boot project with Vaadin and Spring AI dependencies. You can use Spring Initializr to bootstrap your project quickly. It will add the necessary dependencies to your pom.xml, but nothing else. Simple, and you can continue with writing the code.

The Main View

This is the full source code. Everything we need is in the MainView.java class.

@Route("") // Map view to the root URL
class MainView extends VerticalLayout {

    // Chat history for the LLM
    private final ArrayList<Message> chatHistory = new ArrayList<>();

    VerticalLayout messageList = new VerticalLayout();
    Scroller messageScroller = new Scroller(messageList);
    MessageInput messageInput = new MessageInput();


    MainView(StreamingChatClient chatClient) {
        add(messageScroller, messageInput);
        setSizeFull();
        setMargin(false)
        messageScroller.setSizeFull();
        messageInput.setWidthFull();

        // Add system message to help the AI to behave
        chatHistory.add(new SystemMessage("Only if the user asks you about Vaadin, reply in bro style. Always show a piece a code."));

        messageInput.addSubmitListener(ev -> {

            // Add user input as markdown message
            chatHistory.add(new UserMessage(ev.getValue()));
            messageList.add(new MarkdownMessage(ev.getValue(),"Me"));

            // Placeholder message for the upcoming AI reply
            MarkdownMessage reply = new MarkdownMessage("Assistant");
            messageList.add(reply);

            // Ask AI and stream back the reply to UI
            Prompt prompt = new Prompt(chatHistory);
            chatClient.stream(prompt)
                    .doOnComplete(() -> chatHistory.add(new AssistantMessage(reply.getMarkdown())))
                    .subscribe(cr -> reply.appendMarkdownAsync(cr.getResult().getOutput().getContent()));
            reply.scrollIntoView();
        });
    }
 }

This already works, but chat streaming is not that useful if not real-time to the user. We enable WebSockets for real-time client-server communication. Add the @Push annotation to your application class:

@SpringBootApplication
@Push
public class DemoApplication implements AppShellConfigurator {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}

What happens here? 

  • UI Components: We have a VerticalLayout, Scroller, and MessageInput to create a simple scrolling chat interface. The Scroller ensures that the messages are visible.
  • Chat History: We maintain a history of messages using an ArrayList. This (user-based) history is important for the AI to generate contextually relevant responses. Otherwise, it has no memory and only responds to the latest input.
  • AI Integration: The StreamingChatClient streams the user's prompt to the AI, and the response is dynamically added to the chat and streamed to the client token by token. 
  • WebSockets: Vaadin automatically manages the state and updates the UI components in the browser; you do not need to do anything else but enable it. If WebSockets are unavailable, Vaadin will gracefully fall back to using long polling.

Running Your Application

Run your Spring Boot application using mvn spring-boot:run or from your IDE with the DemoApplication class. You should see a chat interface where you can type messages and receive AI-generated responses. This setup's simplicity allows you to focus on expanding and refining your application's capabilities. I created the Dockerfile if you want to deploy your app to a cloud like Fly.io or Google Cloud.

Add more features

By combining Vaadin Flow and Spring AI, you can create powerful, interactive applications with minimal effort. This example serves as a starting point, and the possibilities are endless. Whether you build customer support tools, educational apps, or interactive chatbots, these technologies provide a solid foundation. 

Find the full source code in GitHub. For further reading and to explore more advanced features, check out the following resources:

Happy Java coding!

Sami Ekblad
Sami Ekblad
Sami Ekblad is one of the original members of the Vaadin team. As a DX lead he is now working as a developer advocate, to help people the most out of Vaadin tools. You can find many add-ons and code samples to help you get started with Vaadin. Follow at – @samiekblad
Other posts by Sami Ekblad