Wednesday, November 15, 2023

Building an AI-Powered Spring Boot Application from Scratch: A Step-by-Step Guide

  • In the ever-evolving landscape of technology, the integration of artificial intelligence (AI) into applications has become increasingly prevalent. In this tutorial, we'll embark on a journey to create an AI-powered Spring Boot application from scratch. 
  • Whether you're a seasoned developer or a newcomer, this guide will walk you through the process of integrating AI components, opening the door to a wide array of possibilities, from machine learning to natural language processing and computer vision.
Prerequisites:
  • Before we dive into the development process, make sure you have the following tools and technologies installed:
  • Java Development Kit (JDK)
  • Integrated Development Environment (IDE) of your choice (Eclipse, IntelliJ, etc.)
  • Maven or Gradle for dependency management
  • Basic understanding of Spring Boot.

Implement AI Functionality

  • Machine Learning:
    • Integrate a simple machine learning model. For instance, we will use TensorFlow and load a pre-trained model for a basic task like image classification.
  • Natural Language Processing:
    • We will Implement a basic natural language processing feature, such as sentiment analysis using Stanford CoreNLP.
  • Computer Vision:
    • we will Incorporate computer vision by adding functionality for image processing using OpenCV. This include tasks like image filtering.

AI springboot Dependency

1. TensorFlow Dependency:
  • TensorFlow is an open-source machine learning framework developed by the Google Brain team. It provides a comprehensive set of tools for building and deploying machine learning models, especially deep learning models. Some key aspects of TensorFlow include:
  • Graph-based Computation
    • TensorFlow uses a computational graph to represent a model, allowing for efficient execution on both CPUs and GPUs.
  • Flexibility: 
    • It supports various machine learning tasks, including neural networks, and offers high-level APIs for quick model development (e.g., Keras) and lower-level APIs for more control.
  • Scalability: 
    • TensorFlow can scale from running on a single device to distributed computing across multiple machines.
2. Stanford CoreNLP Dependency:
  • Stanford CoreNLP is a natural language processing toolkit developed by the Stanford Natural Language Processing Group. It provides a set of tools for various natural language processing tasks. Key features include:
  • Tokenization: 
    • Breaking text into words, sentences, etc.
  • Part-of-Speech Tagging: 
    • Assigning grammatical categories (e.g., noun, verb) to words.
  • Named Entity Recognition (NER):
    •  Identifying entities such as names, dates, and locations in text.
  • Sentiment Analysis: 
    • Determining the sentiment expressed in a piece of text.
3. OpenCV Dependency:
  • OpenCV (Open Source Computer Vision Library) is an open-source computer vision and machine learning software library. It is widely used for image and video processing. Some notable features of OpenCV include:
  • Image Processing: 
    • Provides a wide range of functions for image manipulation, transformation, and enhancement.
  • Computer Vision Algorithms: 
    • Includes algorithms for object detection, feature extraction, and pattern recognition.
  • Machine Learning Support: 
    • Contains machine learning modules for tasks like clustering, classification, and regression.
  • Real-time Vision: 
    • Designed for real-time applications, making it suitable for robotics and computer vision applications.

Step 1: Set Up a Spring Boot Project

Option 1: Using Spring Initializer
  • Visit Spring Initializer
  • Choose your preferred options, including project type (Maven/Gradle), language (Java/Kotlin), and packaging.
  • Add dependencies:
    • Spring Web
    • Spring Data JPA (for database interaction)
  • Generate the project and download the ZIP file.
Option 2: Using IDE
  • Open your IDE and create a new Spring Boot project.
  • Configure the project settings, including group, artifact, and dependencies.
  • Add the dependencies mentioned above using your IDE's project setup or configuration file.

Step 2: Project Structure

  • controller: Contains controllers for handling HTTP requests.
  • service: Houses AI services for machine learning, NLP, and computer vision.
  • model: Defines data models.
  • repository: Manages data access using Spring Data JPA.
  • config: Includes configuration classes.
  • util: Houses utility classes.

Step 3: Create Controller class with image processing Endpoint 

1. Create Endpoint /api/processImage
  • Purpose:Processes an image.
  • Receive Input:
    • Accepts a byte array (inputImage) in the request body, representing the original image.
  • Delegate to ComputerVisionService:
    • Calls the computerVisionService.processImage(inputImage) method.
    • The ComputerVisionService is responsible for image processing.
  • Return Processed Image:
    • Returns a byte array representing the processed image.
  • Business Logic 
    • The endpoint facilitates image processing, which could involve operations like resizing, filtering, or enhancing.
    • The ComputerVisionService encapsulates the specific logic for processing the image.The processed image is returned to the client.
2. Create Endpoint /api/predict
  • Purpose: Predicts an outcome using a machine learning model.
  • Receive Input:
    • Accepts a Tensor (input) in the request body, representing input data for the machine learning model.
  • Delegate to MachineLearningService:
    • Call the  machineLearningService.predictFromModel(input) method
    • The MachineLearningService handles the logic for making predictions using a machine learning model.
  • Return Prediction Result:
    • Returns a string representing the prediction result.
  • Business Logic:
    • This endpoint is designed for making predictions using a machine learning model.
    • The MachineLearningService abstracts the details of model inference.The predicted result is returned to the client.
3. Create Endpoint /api/analyzeText
  • Purpose: Analyzes the sentiment of a given text.
  • Receive Input:
    • Accepts a string (inputText) in the request body, representing the text to be analyzed.
  • Delegate to NLPService:
    • Calls the nlpService.analyzeText(inputText) method.
    • The NLPService encapsulates the logic for natural language processing, such as sentiment analysis.
  • Return Sentiment Analysis Result:
    • Returns a string representing the sentiment analysis result.
  • Business Logic:
    • This endpoint is focused on natural language processing, specifically sentiment analysis.
    • The NLPService abstracts the details of the sentiment analysis algorithm.The sentiment analysis result is returned to the client.
package com.SpringSightAI.SpringSightAI.controller; import com.SpringSightAI.SpringSightAI.service.ComputerVisionService; import com.SpringSightAI.SpringSightAI.service.MachineLearningService; import com.SpringSightAI.SpringSightAI.service.NLPService; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.tensorflow.Tensor; @RestController @RequestMapping("/api") public class AIController { private final ComputerVisionService computerVisionService; private final MachineLearningService machineLearningService; private final NLPService nlpService; public AIController( ComputerVisionService computerVisionService, MachineLearningService machineLearningService, NLPService nlpService) { this.computerVisionService = computerVisionService; this.machineLearningService = machineLearningService; this.nlpService = nlpService; } @PostMapping("/processImage") public byte[] processImage(@RequestBody byte[] inputImage) { return computerVisionService.processImage(inputImage); } @PostMapping("/predict") public String predictFromModel(@RequestBody Tensor<?> input) { return machineLearningService.predictFromModel(input); } @PostMapping("/analyzeText") public String analyzeText(@RequestBody String inputText) { return nlpService.analyzeText(inputText); } // Add more API methods as needed }

Step 4: Create service class with business logic

1. Create ComputerVisionService class 
  • Receive Input:
    • The processAndSaveImage method accepts an input image as a byte array (inputImage).
  • Image Processing:
    • Converts the byte array to an OpenCV Mat using AppUtils.byteArrayToMat.
    • Applies image processing operations, specifically resizing, using OpenCV's Imgproc.resize method.
  • Save Processed Image:
    • The processed image (Mat) is saved to the database using the saveProcessedImageToDatabase method.
    • Converts the processed Mat to a byte array using AppUtils.matToByteArray.
  • Return Processed Image:
    • The final processed image as a byte array is returned to the caller.
  • Business Logic:
    • The ComputerVisionService class focuses on image processing operations, particularly resizing.
    • It leverages OpenCV for image manipulation.
    • The processed image is saved to the database using the injected ImageRepository.
    • The processed image is then converted back to a byte array for potential further use or response generation.
    • ComputerVisionService class utilizes OpenCV for image processing. It performs operations like resizing an image using OpenCV functions.
package com.SpringSightAI.SpringSightAI.service; import com.SpringSightAI.SpringSightAI.model.Image; import com.SpringSightAI.SpringSightAI.repository.ImageRepository; import com.SpringSightAI.SpringSightAI.util.AppUtils; import org.opencv.core.Mat; import org.opencv.core.Size; import org.opencv.imgproc.Imgproc; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @Service public class ComputerVisionService { private final ImageRepository imageRepository; @Autowired public ComputerVisionService(ImageRepository imageRepository) { this.imageRepository = imageRepository; } /** * Apply a simple image processing operation (e.g., resizing) using OpenCV and save the processed image. * * @param inputImage Input image as a byte array. * @return Processed image as a byte array. */ public byte[] processAndSaveImage(byte[] inputImage) { // Convert byte array to OpenCV Mat Mat originalImage = AppUtils.byteArrayToMat(inputImage); // Apply image processing (e.g., resizing) Mat processedImage = resizeImage(originalImage, new Size(300, 300)); // Save the processed image to the database Image savedImage = saveProcessedImageToDatabase(processedImage); // Convert processed image back to byte array return AppUtils.matToByteArray(savedImage.getProcessedData()); } /** * Resize an image using OpenCV. * * @param inputImage Input image as a Mat. * @param newSize New size for the image. * @return Resized image as a Mat. */ private Mat resizeImage(Mat inputImage, Size newSize) { Mat resizedImage = new Mat(); Imgproc.resize(inputImage, resizedImage, newSize); return resizedImage; } /** * Save the processed image to the database using the ImageRepository. * * @param processedImage Processed image as a Mat. * @return Saved Image entity. */ private Image saveProcessedImageToDatabase(Mat processedImage) { // Convert Mat to byte array and create an Image entity byte[] processedData = AppUtils.matToByteArray(processedImage); return imageRepository.save(new Image(processedData)); } }
2. Create ImageProcessingService class 
  • Save Processed Image:
    • The saveProcessedImage method takes a byte array (processedImage) representing a processed image.
    • Creates a new ProcessedImage entity and saves it to the database using the injected ProcessedImageRepository.
  • Returns the saved ProcessedImage entity.
    • Retrieve Processed Image by ID:
    • The getProcessedImageById method retrieves a processed image from the database by its ID.
    • Returns an Optional containing the ProcessedImage entity if found.
  • Retrieve All Processed Images:
    • The getAllProcessedImages method retrieves all processed images from the database using the findAll method of the repository.
    • Returns a list of ProcessedImage entities.
  • Business Logic 
    • The primary responsibility of this service is to interact with the ProcessedImageRepository for CRUD (Create, Read, Update, Delete) operations related to processed images.
    • The saveProcessedImage method allows saving a newly processed image to the database.
    • The getProcessedImageById method facilitates retrieving a processed image by its ID.
    • The getAllProcessedImages method retrieves all processed images stored in the database.
package com.SpringSightAI.SpringSightAI.service; import com.SpringSightAI.SpringSightAI.model.ProcessedImage; import com.SpringSightAI.SpringSightAI.repository.ProcessedImageRepository; import org.opencv.core.Mat; import org.opencv.core.Size; import org.opencv.imgproc.Imgproc; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.Optional; @Service public class ImageProcessingService { private final ProcessedImageRepository processedImageRepository; @Autowired public ImageProcessingService(ProcessedImageRepository processedImageRepository) { this.processedImageRepository = processedImageRepository; } /** * Save a processed image to the database. * * @param processedImage Processed image to be saved. * @return Saved ProcessedImage entity. */ public ProcessedImage saveProcessedImage(byte[] processedImage) { ProcessedImage savedProcessedImage = processedImageRepository.save(new ProcessedImage(processedImage)); return savedProcessedImage; } /** * Retrieve a processed image from the database by its ID. * * @param id ID of the processed image. * @return ProcessedImage entity. */ public Optional<ProcessedImage> getProcessedImageById(Long id) { return processedImageRepository.findById(id); } /** * Apply a simple image processing operation (e.g., resizing) using OpenCV. * * @param inputImage Input image as a byte array. * @return Processed image as a byte array. */ public byte[] applySimpleImageProcessing(byte[] inputImage) { // Convert byte array to OpenCV Mat Mat originalImage = AppUtils.byteArrayToMat(inputImage); // Apply image processing (e.g., resizing) Mat processedImage = resizeImage(originalImage, new Size(300, 300)); // Convert processed image back to byte array return AppUtils.matToByteArray(processedImage); } /** * Resize an image using OpenCV. * * @param inputImage Input image as a Mat. * @param newSize New size for the image. * @return Resized image as a Mat. */ private Mat resizeImage(Mat inputImage, Size newSize) { Mat resizedImage = new Mat(); Imgproc.resize(inputImage, resizedImage, newSize); return resizedImage; } // You can add more methods for additional image processing logic here }
3. Create NLPService class 
  • Save Text:
    • The saveText method takes an input text (inputText).
    • Creates a new Text entity and saves it to the database using the injected TextRepository.
    • Returns the saved Text entity.
  • Analyze Sentiment:
    • The analyzeSentiment method performs sentiment analysis on the given input text.
    • Creates a CoreDocument from the input text.
    • Annotates the document using the Stanford CoreNLP pipeline to perform sentiment analysis.
  • Extracts and returns the sentiment as a string:
    • Retrieve All Texts:
    • The getAllTexts method retrieves all texts stored in the database using the findAll method of the repository.
  • Returns a list of Text entities:
    • Extract Sentiment:
    • The extractSentiment method takes an annotated CoreDocument.
    • Assumes a single sentence for simplicity and extracts the sentiment using Stanford CoreNLP annotations.
  • Business Logic:
    • The NLPService class integrates with the Stanford CoreNLP library to perform natural language processing tasks, specifically sentiment analysis.
    • It interacts with the TextRepository for storing and retrieving text data from the database.
    • The sentiment analysis result is returned as a string.
    • The service encapsulates the complexity of the Stanford CoreNLP library and provides a clean interface for storing texts, analyzing sentiment, and retrieving text data.
    • tanford CoreNLP is used in the NLPService class for sentiment analysis. The StanfordCoreNLP pipeline is initialized with sentiment analysis annotator. The sentiment analysis functionality is implemented using Stanford CoreNLP annotations.
package com.SpringSightAI.SpringSightAI.service; import com.SpringSightAI.SpringSightAI.model.Text; import com.SpringSightAI.SpringSightAI.repository.TextRepository; import edu.stanford.nlp.pipeline.CoreDocument; import edu.stanford.nlp.pipeline.StanfordCoreNLP; import edu.stanford.nlp.pipeline.StanfordCoreNLPClient; import edu.stanford.nlp.sentiment.SentimentCoreAnnotations; import edu.stanford.nlp.util.CoreMap; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.List; import java.util.Properties; @Service public class NLPService { private final TextRepository textRepository; private final StanfordCoreNLP pipeline; @Autowired public NLPService(TextRepository textRepository) { this.textRepository = textRepository; // Initialize the Stanford CoreNLP pipeline Properties properties = new Properties(); properties.setProperty("annotators", "tokenize, ssplit, pos, lemma, parse, sentiment"); this.pipeline = new StanfordCoreNLP(properties); } /** * Save text to the database. * * @param inputText Input text to be saved. * @return Saved Text entity. */ public Text saveText(String inputText) { Text savedText = textRepository.save(new Text(inputText)); return savedText; } /** * Analyze the sentiment of a given text. * * @param inputText Input text for sentiment analysis. * @return Sentiment analysis result as a String. */ public String analyzeSentiment(String inputText) { // Create a CoreDocument from the input text CoreDocument document = new CoreDocument(inputText); // Annotate the document to perform sentiment analysis pipeline.annotate(document); // Get the sentiment of the document String sentiment = extractSentiment(document); return "Sentiment: " + sentiment; } /** * Retrieve all texts from the database. * * @return List of Text entities. */ public List<Text> getAllTexts() { return textRepository.findAll(); } /** * Extract sentiment from the annotated CoreDocument. * * @param document Annotated CoreDocument. * @return Sentiment as a String. */ private String extractSentiment(CoreDocument document) { CoreMap sentence = document.sentences().get(0); // Assuming a single sentence for simplicity return sentence.get(SentimentCoreAnnotations.SentimentClass.class); } }

You may also like

Kubernetes Microservices
Python AI/ML
Spring Framework Spring Boot
Core Java Java Coding Question
Maven AWS