这是indexloc提供的服务,不要输入任何密码
Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions spring-boot-modules/spring-boot-3-3/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
## Relevant Articles

insert articles here

- More articles: [[<-- prev]](/spring-boot-modules/spring-boot-3-2)
69 changes: 69 additions & 0 deletions spring-boot-modules/spring-boot-3-3/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>spring-boot-3-3</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>spring-boot-3-3</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>com.baeldung.spring-boot-modules</groupId>
<artifactId>spring-boot-modules</artifactId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.apache.camel.springboot</groupId>
<artifactId>camel-spring-boot-starter</artifactId>
<version>${apache-camel.version}</version>
</dependency>
<dependency>
<groupId>org.apache.camel.springboot</groupId>
<artifactId>camel-http-starter</artifactId>
<version>${apache-camel.version}</version>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-jackson</artifactId>
<version>${apache-camel.version}</version>
</dependency>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-core</artifactId>
<version>${langchain4j.version}</version>
</dependency>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-ollama</artifactId>
<version>${langchain4j.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
<compilerArgs>
<arg>-parameters</arg>
</compilerArgs>
</configuration>
</plugin>
</plugins>
</build>
<properties>
<spring-boot.version>3.2.4</spring-boot.version>
<apache-camel.version>4.7.0</apache-camel.version>
<langchain4j.version>0.33.0</langchain4j.version>
</properties>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.baeldung.chatbot;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class ChatbotApplication {

public static void main(String[] args) {
SpringApplication.run(ChatbotApplication.class, args);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.baeldung.chatbot.controller;

import com.baeldung.chatbot.service.ChatbotService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class ChatbotController {
@Autowired
private ChatbotService chatbotService;

@GetMapping("/api/chatbot/send")
public String getChatbotResponse(@RequestParam String question) {
return chatbotService.getResponse(question);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package com.baeldung.chatbot.controller;

import com.baeldung.chatbot.service.WhatsAppService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;

@RestController
public class WhatsAppController {

@Value("${whatsapp.verify_token}")
private String verifyToken;

@Autowired
private WhatsAppService whatsAppService;

@PostMapping("/api/whatsapp/send")
public String sendWhatsAppMessage(@RequestParam String to, @RequestParam String message) {
whatsAppService.sendWhatsAppMessage(to, message);
return "Message sent";
}

@GetMapping("/webhook")
public String verifyWebhook(@RequestParam("hub.mode") String mode,
@RequestParam("hub.verify_token") String token,
@RequestParam("hub.challenge") String challenge) {
if ("subscribe".equals(mode) && verifyToken.equals(token)) {
return challenge;
} else {
return "Verification failed";
}
}

@PostMapping("/webhook")
public void receiveMessage(@RequestBody String payload) {
whatsAppService.processIncomingMessage(payload);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package com.baeldung.chatbot.service;

import java.time.Duration;

import org.apache.hc.core5.http.HttpStatus;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.server.ResponseStatusException;

import dev.langchain4j.model.ollama.OllamaChatModel;
import jakarta.annotation.PostConstruct;

@Service
public class ChatbotService {

private static final Logger logger = LoggerFactory.getLogger(ChatbotService.class);

@Value("${ollama.api_url}")
private String apiUrl;

@Value("${ollama.model}")
private String modelName;

@Value("${ollama.timeout}")
private int timeout;

@Value("${ollama.max_response_length}")
private int maxResponseLength;

private OllamaChatModel ollamaChatModel;

@PostConstruct
public void init() {
this.ollamaChatModel = OllamaChatModel.builder()
.baseUrl(apiUrl)
.modelName(modelName)
.timeout(Duration.ofSeconds(timeout))
.numPredict(maxResponseLength)
.build();
}

public String getResponse(String question) {
logger.debug("Sending to Ollama: {}", question);
String answer = ollamaChatModel.generate(question);
logger.debug("Receiving from Ollama: {}", answer);
if (answer != null && !answer.isEmpty()) {
return answer;
} else {
logger.error("Invalid Ollama response for:\n\n" + question);
throw new ResponseStatusException(
HttpStatus.SC_INTERNAL_SERVER_ERROR,
"Ollama didn't generate a valid response",
null);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package com.baeldung.chatbot.service;

import java.util.HashMap;
import java.util.Map;

import org.apache.camel.CamelContext;
import org.apache.camel.ProducerTemplate;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.component.jackson.JacksonDataFormat;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;

import jakarta.annotation.PostConstruct;

@Service
public class WhatsAppService {

private static final Logger logger = LoggerFactory.getLogger(WhatsAppService.class);

@Value("${whatsapp.api_url}")
private String apiUrl;

@Value("${whatsapp.access_token}")
private String apiToken;

@Autowired
private CamelContext camelContext;

@Autowired
private ObjectMapper objectMapper;

@Autowired
private ProducerTemplate producerTemplate;

@Autowired
private ChatbotService chatbotService;

@PostConstruct
public void init() throws Exception {
camelContext.addRoutes(new RouteBuilder() {
@Override
public void configure() {
JacksonDataFormat jacksonDataFormat = new JacksonDataFormat();
jacksonDataFormat.setPrettyPrint(true);

from("direct:sendWhatsAppMessage")
.setHeader("Authorization", constant("Bearer " + apiToken))
.setHeader("Content-Type", constant("application/json"))
.marshal(jacksonDataFormat)
.process(exchange -> {
logger.debug("Sending JSON: {}", exchange.getIn().getBody(String.class));
}).to(apiUrl).process(exchange -> {
logger.debug("Response: {}", exchange.getIn().getBody(String.class));
});
}
});
}

public void sendWhatsAppMessage(String toNumber, String message) {
Map<String, Object> body = new HashMap<>();
body.put("messaging_product", "whatsapp");
body.put("to", toNumber);
body.put("type", "text");

Map<String, String> text = new HashMap<>();
text.put("body", message);
body.put("text", text);

producerTemplate.sendBody("direct:sendWhatsAppMessage", body);
}

public void processIncomingMessage(String payload) {
try {
JsonNode jsonNode = objectMapper.readTree(payload);
JsonNode messages = jsonNode.at("/entry/0/changes/0/value/messages");
if (messages.isArray() && messages.size() > 0) {
String receivedText = messages.get(0).at("/text/body").asText();
String fromNumber = messages.get(0).at("/from").asText();
logger.debug(fromNumber + " sent the message: " + receivedText);
this.sendWhatsAppMessage(fromNumber, chatbotService.getResponse(receivedText));
}
} catch (Exception e) {
logger.error("Error processing incoming payload: {} ", payload, e);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# WhatsApp API configuration
whatsapp.verify_token=BaeldungDemo-Verify-Token
whatsapp.api_url=https://graph.facebook.com/v20.0/PHONE_NUMBER_ID/messages
whatsapp.access_token=ACCESS_TOKEN

# Ollama API configuration
ollama.api_url=http://localhost:11434/
ollama.model=qwen2:1.5b
ollama.timeout=30
ollama.max_response_length=1000

# Logging configuration
logging.level.root=INFO
logging.level.com.baeldung.chatbot=DEBUG
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.baeldung.chatbot;

import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

import static org.assertj.core.api.Assertions.assertThat;

@SpringBootTest
class ChatbotApplicationTests {

@Test
void contextLoads() {
assertThat(true).isTrue();
}
}