Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/master'
Browse files Browse the repository at this point in the history
  • Loading branch information
arunvariyath committed Feb 9, 2025
2 parents 4197211 + 853a309 commit feb4b3b
Show file tree
Hide file tree
Showing 43 changed files with 720 additions and 4 deletions.
4 changes: 4 additions & 0 deletions core-java-modules/core-java-perf-2/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,8 @@ This module contains articles about performance of Java applications
- [Shutting Down on OutOfMemoryError in Java](https://www.baeldung.com/java-shutting-down-outofmemoryerror)
- [Programmatic Usage of NetBeans Profiler](https://www.baeldung.com/java-netbeans-use-profiler-programmatically)
- [Reduce Memory Footprint in Java](https://www.baeldung.com/java-reduce-memory-footprint)
- [Verbose Garbage Collection in Java](https://www.baeldung.com/java-verbose-gc)
- [Branch Prediction in Java](https://www.baeldung.com/java-branch-prediction)
- [JMX Ports](https://www.baeldung.com/jmx-ports)
- [Calling JMX MBean Method From a Shell Script](https://www.baeldung.com/jmx-mbean-shell-access)

File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
4 changes: 0 additions & 4 deletions core-java-modules/core-java-perf/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,9 @@
This module contains articles about performance of Java applications

### Relevant Articles:
- [Verbose Garbage Collection in Java](https://www.baeldung.com/java-verbose-gc)
- [Different Ways to Capture Java Heap Dumps](https://www.baeldung.com/java-heap-dump-capture)
- [Understanding Memory Leaks in Java](https://www.baeldung.com/java-memory-leaks)
- [OutOfMemoryError: GC Overhead Limit Exceeded](http://www.baeldung.com/java-gc-overhead-limit-exceeded)
- [Basic Introduction to JMX](http://www.baeldung.com/java-management-extensions)
- [Monitoring Java Applications with Flight Recorder](https://www.baeldung.com/java-flight-recorder-monitoring)
- [Branch Prediction in Java](https://www.baeldung.com/java-branch-prediction)
- [Capturing a Java Thread Dump](https://www.baeldung.com/java-thread-dump)
- [JMX Ports](https://www.baeldung.com/jmx-ports)
- [Calling JMX MBean Method From a Shell Script](https://www.baeldung.com/jmx-mbean-shell-access)
4 changes: 4 additions & 0 deletions spring-ai-2/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-markdown-document-reader</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-ollama-spring-boot-starter</artifactId>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package com.baeldung.springai.evaluator;

import org.springframework.ai.autoconfigure.anthropic.AnthropicAutoConfiguration;
import org.springframework.ai.autoconfigure.bedrock.converse.BedrockConverseProxyChatAutoConfiguration;
import org.springframework.ai.autoconfigure.openai.OpenAiAutoConfiguration;
import org.springframework.ai.autoconfigure.vectorstore.chroma.ChromaVectorStoreAutoConfiguration;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.PropertySource;

/**
* Excluding the below auto-configurations to avoid start up
* failure. Their corresponding starters are present on the classpath but are
* only needed by other articles in the shared codebase.
*/
@SpringBootApplication(exclude = {
OpenAiAutoConfiguration.class,
AnthropicAutoConfiguration.class,
ChromaVectorStoreAutoConfiguration.class,
BedrockConverseProxyChatAutoConfiguration.class
})
@PropertySource("classpath:application-evaluator.properties")
public class Application {

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

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package com.baeldung.springai.evaluator;

import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.QuestionAnswerAdvisor;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.ai.evaluation.FactCheckingEvaluator;
import org.springframework.ai.evaluation.RelevancyEvaluator;
import org.springframework.ai.ollama.OllamaChatModel;
import org.springframework.ai.ollama.api.OllamaApi;
import org.springframework.ai.ollama.api.OllamaOptions;
import org.springframework.ai.ollama.management.ModelManagementOptions;
import org.springframework.ai.ollama.management.PullModelStrategy;
import org.springframework.ai.vectorstore.SimpleVectorStore;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class LLMConfiguration {

@Bean
public VectorStore vectorStore(EmbeddingModel embeddingModel) {
return SimpleVectorStore
.builder(embeddingModel)
.build();
}

@Bean
public ChatClient contentGenerator(ChatModel chatModel, VectorStore vectorStore) {
return ChatClient.builder(chatModel)
.defaultAdvisors(new QuestionAnswerAdvisor(vectorStore))
.build();
}

@Bean
public ChatClient contentEvaluator(
OllamaApi olamaApi,
@Value("${com.baeldung.evaluation.model}") String evaluationModel) {
ChatModel chatModel = OllamaChatModel.builder()
.ollamaApi(olamaApi)
.defaultOptions(OllamaOptions.builder()
.model(evaluationModel)
.build())
.modelManagementOptions(ModelManagementOptions.builder()
.pullModelStrategy(PullModelStrategy.WHEN_MISSING)
.build())
.build();
return ChatClient.builder(chatModel)
.build();
}

@Bean
public FactCheckingEvaluator factCheckingEvaluator(@Qualifier("contentEvaluator") ChatClient chatClient) {
return new FactCheckingEvaluator(chatClient.mutate());
}

@Bean
public RelevancyEvaluator relevancyEvaluator(@Qualifier("contentEvaluator") ChatClient chatClient) {
return new RelevancyEvaluator(chatClient.mutate());
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package com.baeldung.springai.evaluator;

import org.springframework.ai.document.Document;
import org.springframework.ai.reader.markdown.MarkdownDocumentReader;
import org.springframework.ai.reader.markdown.config.MarkdownDocumentReaderConfig;
import org.springframework.ai.transformer.splitter.TokenTextSplitter;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

@Component
class VectorStoreInitializer implements ApplicationRunner {

private final VectorStore vectorStore;
private final ResourcePatternResolver resourcePatternResolver;

public VectorStoreInitializer(VectorStore vectorStore, ResourcePatternResolver resourcePatternResolver) {
this.vectorStore = vectorStore;
this.resourcePatternResolver = resourcePatternResolver;
}

@Override
public void run(ApplicationArguments args) throws IOException {
List<Document> documents = new ArrayList<>();
Resource[] resources = resourcePatternResolver.getResources("classpath:documents/*.md");
Arrays.stream(resources).forEach(resource -> {
MarkdownDocumentReader markdownDocumentReader = new MarkdownDocumentReader(resource, MarkdownDocumentReaderConfig.defaultConfig());
documents.addAll(markdownDocumentReader.read());
});
vectorStore.add(new TokenTextSplitter().split(documents));
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
com.baeldung.evaluation.model=bespoke-minicheck

spring.ai.ollama.chat.options.model=llama3.3
spring.ai.ollama.embedding.options.model=nomic-embed-text
spring.ai.ollama.init.pull-model-strategy=when_missing
17 changes: 17 additions & 0 deletions spring-ai-2/src/main/resources/documents/leave-policy.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Leave Management Policy

We offer comprehensive leave benefits to support work-life balance.

## Types of Leave
- Annual Leave: 20 days per year, accrued monthly
- Sick Leave: 14 days per year, requires medical certificate for 3+ consecutive days
- Parental Leave: 16 weeks for primary caregivers, 4 weeks for secondary
- Bereavement Leave: 5 days for immediate family

## Application Process
1. Submit request through HR portal minimum 2 weeks in advance (except sick leave)
2. Manager reviews within 48 hours
3. HR processes approved requests within 24 hours

## Leave Balance
Leave balance resets annually on January 1st. Maximum 5 days carry-forward allowed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
package com.baeldung.springai.evaluator;

import org.junit.jupiter.api.Test;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.QuestionAnswerAdvisor;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.document.Document;
import org.springframework.ai.evaluation.EvaluationRequest;
import org.springframework.ai.evaluation.EvaluationResponse;
import org.springframework.ai.evaluation.FactCheckingEvaluator;
import org.springframework.ai.evaluation.RelevancyEvaluator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.Import;

import java.util.List;

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

@SpringBootTest
@Import(TestcontainersConfiguration.class)
class LLMResponseEvaluatorLiveTest {

@Autowired
private ChatClient contentGenerator;

@Autowired
private RelevancyEvaluator relevancyEvaluator;

@Autowired
private FactCheckingEvaluator factCheckingEvaluator;

@Test
void whenChatClientProvidesAnswerRelevantToTopic_thenRelevancyEvaluationSucceeds() {
String question = "How many days sick leave can I take?";
ChatResponse chatResponse = contentGenerator.prompt()
.user(question)
.call()
.chatResponse();

String answer = chatResponse.getResult().getOutput().getContent();
List<Document> documents = chatResponse.getMetadata().get(QuestionAnswerAdvisor.RETRIEVED_DOCUMENTS);
EvaluationRequest evaluationRequest = new EvaluationRequest(question, documents, answer);

EvaluationResponse evaluationResponse = relevancyEvaluator.evaluate(evaluationRequest);
assertThat(evaluationResponse.isPass()).isTrue();
}

@Test
void whenChatClientProvidesAnswerIrrelevantToTopic_thenRelevancyEvaluationFails() {
String question = "How many days sick leave can I take?";
ChatResponse chatResponse = contentGenerator.prompt()
.user(question)
.call()
.chatResponse();

String nonRelevantAnswer = "A lion is the king of the jungle";
List<Document> documents = chatResponse.getMetadata().get(QuestionAnswerAdvisor.RETRIEVED_DOCUMENTS);
EvaluationRequest evaluationRequest = new EvaluationRequest(question, documents, nonRelevantAnswer);

EvaluationResponse evaluationResponse = relevancyEvaluator.evaluate(evaluationRequest);
assertThat(evaluationResponse.isPass()).isFalse();
}

@Test
void whenChatClientProvidesWrongAnswerRelevantToTopic_thenRelevancyEvaluationFails() {
String question = "How many days sick leave can I take?";
ChatResponse chatResponse = contentGenerator.prompt()
.user(question)
.call()
.chatResponse();

String wrongAnswer = "You can take no leaves. Get back to work!";
List<Document> documents = chatResponse.getMetadata().get(QuestionAnswerAdvisor.RETRIEVED_DOCUMENTS);
EvaluationRequest evaluationRequest = new EvaluationRequest(question, documents, wrongAnswer);

EvaluationResponse evaluationResponse = relevancyEvaluator.evaluate(evaluationRequest);
assertThat(evaluationResponse.isPass()).isFalse();
}

@Test
void whenChatClientProvidesFactuallyCorrectAnswer_thenFactCheckingEvaluationSucceeds() {
String question = "How many days sick leave can I take?";
ChatResponse chatResponse = contentGenerator.prompt()
.user(question)
.call()
.chatResponse();

String answer = chatResponse.getResult().getOutput().getContent();
List<Document> documents = chatResponse.getMetadata().get(QuestionAnswerAdvisor.RETRIEVED_DOCUMENTS);
EvaluationRequest evaluationRequest = new EvaluationRequest(question, documents, answer);

EvaluationResponse evaluationResponse = factCheckingEvaluator.evaluate(evaluationRequest);
assertThat(evaluationResponse.isPass()).isTrue();
}

@Test
void whenChatClientProvidesFactuallyIncorrectAnswer_thenFactCheckingEvaluationFails() {
String question = "How many days sick leave can I take?";
ChatResponse chatResponse = contentGenerator.prompt()
.user(question)
.call()
.chatResponse();

String wrongAnswer = "You can take no leaves. Get back to work!";
List<Document> documents = chatResponse.getMetadata().get(QuestionAnswerAdvisor.RETRIEVED_DOCUMENTS);
EvaluationRequest evaluationRequest = new EvaluationRequest(question, documents, wrongAnswer);

EvaluationResponse evaluationResponse = factCheckingEvaluator.evaluate(evaluationRequest);
assertThat(evaluationResponse.isPass()).isFalse();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.baeldung.springai.evaluator;

import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.test.context.DynamicPropertyRegistrar;
import org.testcontainers.ollama.OllamaContainer;

@TestConfiguration(proxyBeanMethods = false)
class TestcontainersConfiguration {

@Bean
public OllamaContainer ollamaContainer() {
return new OllamaContainer("ollama/ollama:0.5.7");
}

@Bean
public DynamicPropertyRegistrar dynamicPropertyRegistrar(OllamaContainer ollamaContainer) {
return registry -> {
registry.add("spring.ai.ollama.base-url", ollamaContainer::getEndpoint);
};
}

}
1 change: 1 addition & 0 deletions spring-boot-modules/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@
<module>spring-boot-nashorn</module>
<module>spring-boot-parent</module>
<module>spring-boot-performance</module>
<module>spring-boot-pkl</module>
<module>spring-boot-property-exp</module>
<module>spring-boot-request-params</module>
<module>spring-boot-runtime</module>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.baeldung.profiles;

import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Component;

@Component
@Profile("!a & !b & !c")
public class NoneOfThreeProfilesComponent {

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.baeldung.profiles;

import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Component;

@Component
@Profile("!dev & !production & !mysql & !tomcat")
public class SpecialDatasourceConfig implements DatasourceConfig {

@Override
public void setup() {
System.out.println("Setting up a very special datasource. ");
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.baeldung.profiles;

import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Component;

@Component
@Profile("a & b & c")
public class ThreeProfilesComponent {

}
Loading

0 comments on commit feb4b3b

Please sign in to comment.