Refactor token handling and update dependencies; add AzureAIConfig for response timeout customization

This commit is contained in:
andrea.terzani
2025-02-21 13:02:37 +01:00
parent b0e4abc172
commit 3402b4ada2
13 changed files with 122 additions and 73 deletions

View File

@@ -29,7 +29,7 @@
<properties>
<java.version>21</java.version>
<!--<spring-ai.version>1.0.0-SNAPSHOT</spring-ai.version>-->
<spring-ai.version>1.0.0-M2</spring-ai.version>
<spring-ai.version>1.0.0-M6</spring-ai.version>
<spring-cloud.version>2023.0.3</spring-cloud.version>
</properties>
<dependencies>
@@ -48,6 +48,13 @@
<version>1.1.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.json/json -->
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20250107</version>
</dependency>
<!--<dependency>
<groupId>org.springframework.ai</groupId>

View File

@@ -0,0 +1,26 @@
package com.olympus.hermione.config;
import java.time.Duration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
import org.springframework.ai.autoconfigure.azure.openai.AzureOpenAIClientBuilderCustomizer;
import com.azure.core.http.HttpClient;
import com.azure.core.util.HttpClientOptions;
@Configuration
public class AzureAIConfig {
@Bean
public AzureOpenAIClientBuilderCustomizer responseTimeoutCustomizer() {
return openAiClientBuilder -> {
HttpClientOptions clientOptions = new HttpClientOptions()
.setResponseTimeout(Duration.ofMinutes(5));
openAiClientBuilder.httpClient(HttpClient.createDefault(clientOptions));
};
}
}

View File

@@ -43,7 +43,8 @@ public class VectorStoreConfig {
fields.add(AzureVectorStore.MetadataField.text("KsFileSource"));
fields.add(AzureVectorStore.MetadataField.text("KsDocumentId"));
return new AzureVectorStore(searchIndexClient, embeddingModel,initSchema, fields);
//return new AzureVectorStore(searchIndexClient, embeddingModel,initSchema, fields);
return null;
}
}

View File

@@ -1,15 +1,12 @@
package com.olympus.hermione.models;
import java.util.HashMap;
import java.util.Date;
import java.util.HashMap;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.data.mongodb.core.mapping.DocumentReference;
import com.olympus.hermione.dto.ScenarioExecutionInput;
import com.olympus.hermione.models.Scenario;
import com.olympus.hermione.security.entity.User;
import lombok.Getter;
import lombok.Setter;
@@ -38,6 +35,6 @@ public class ScenarioExecution {
private Date startDate;
private Date endDate;
private Long usedTokens;
private Integer usedTokens;
private String rating;
}

View File

@@ -41,7 +41,7 @@ public class CanvasExecutionService {
Prompt prompt = new Prompt(List.of(userMessage,systemMessage));
List<Generation> response = chatModel.call(prompt).getResults();
canvasOutput.setStringOutput(response.get(0).getOutput().getContent());
canvasOutput.setStringOutput(response.get(0).getOutput().getText());
return canvasOutput;
} else{
logger.error("Input is not correct");
@@ -61,7 +61,7 @@ public class CanvasExecutionService {
Prompt prompt = new Prompt(List.of(userMessage,systemMessage));
List<Generation> response = chatModel.call(prompt).getResults();
canvasOutput.setStringOutput(response.get(0).getOutput().getContent());
canvasOutput.setStringOutput(response.get(0).getOutput().getText());
return canvasOutput;
} else{
logger.error("Input is not correct");
@@ -79,7 +79,7 @@ public class CanvasExecutionService {
Prompt prompt = new Prompt(List.of(userMessage,systemMessage));
List<Generation> response = chatModel.call(prompt).getResults();
canvasOutput.setStringOutput(response.get(0).getOutput().getContent());
canvasOutput.setStringOutput(response.get(0).getOutput().getText());
return canvasOutput;
} else{
logger.error("Input is not correct");

View File

@@ -34,7 +34,6 @@ import org.springframework.scheduling.annotation.Async;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import com.olympus.hermione.client.OlympusChatClient;
import com.olympus.hermione.dto.ScenarioExecutionInput;
import com.olympus.hermione.dto.ScenarioOutput;
import com.olympus.hermione.models.AiModel;
@@ -210,7 +209,7 @@ public class ScenarioExecutionService {
ScenarioStep startStep = steps.stream().filter(step -> step.getStepId().equals(startStepId)).findFirst().orElse(null);
executeScenarioStep(startStep, scenarioExecution);
Long usedTokens = (scenarioExecution.getUsedTokens() != null) ? scenarioExecution.getUsedTokens() : Long.valueOf(0);
Integer usedTokens = (scenarioExecution.getUsedTokens() != null) ? scenarioExecution.getUsedTokens() : 0;
while (scenarioExecution.getNextStepId()!=null) {
ScenarioStep step = steps.stream().filter(s -> s.getStepId().equals(scenarioExecution.getNextStepId())).findFirst().orElse(null);
@@ -219,7 +218,7 @@ public class ScenarioExecutionService {
if (scenarioExecution.getUsedTokens() != null && scenarioExecution.getUsedTokens() != 0) {
usedTokens += scenarioExecution.getUsedTokens();
scenarioExecution.setUsedTokens(Long.valueOf(0)); //resetting value for next step if is not an AI step
scenarioExecution.setUsedTokens(0); //resetting value for next step if is not an AI step
}
if(scenarioExecution.getLatestStepStatus() != null && scenarioExecution.getLatestStepStatus().equals("ERROR")){
@@ -426,17 +425,19 @@ public class ScenarioExecutionService {
private ChatModel createChatModel(AiModel aiModel){
switch(aiModel.getApiProvider()){
case "AzureOpenAI":
OpenAIClient openAIClient = new OpenAIClientBuilder()
OpenAIClientBuilder openAIClient = new OpenAIClientBuilder()
.credential(new AzureKeyCredential(aiModel.getApiKey()))
.endpoint(aiModel.getEndpoint())
.buildClient();
.endpoint(aiModel.getEndpoint());
AzureOpenAiChatOptions openAIChatOptions = AzureOpenAiChatOptions.builder()
.withDeploymentName(aiModel.getModel())
.withTemperature(aiModel.getTemperature())
.withMaxTokens(aiModel.getMaxTokens())
.deploymentName(aiModel.getModel())
.maxTokens(aiModel.getMaxTokens())
.temperature(Double.valueOf(aiModel.getTemperature()))
.build();
AzureOpenAiChatModel azureOpenaichatModel = new AzureOpenAiChatModel(openAIClient, openAIChatOptions);
logger.info("AI model used: " + aiModel.getModel());
return azureOpenaichatModel;
@@ -445,9 +446,9 @@ public class ScenarioExecutionService {
case "OpenAI":
OpenAiApi openAiApi = new OpenAiApi(aiModel.getApiKey());
OpenAiChatOptions openAiChatOptions = OpenAiChatOptions.builder()
.withModel(aiModel.getModel())
.withTemperature(aiModel.getTemperature())
.withMaxTokens(aiModel.getMaxTokens())
.model(aiModel.getModel())
.temperature(Double.valueOf(aiModel.getTemperature()))
.maxTokens(aiModel.getMaxTokens())
.build();
OpenAiChatModel openaichatModel = new OpenAiChatModel(openAiApi,openAiChatOptions);
@@ -456,19 +457,21 @@ public class ScenarioExecutionService {
case "GoogleGemini":
OpenAIClient tempopenAIClient = new OpenAIClientBuilder()
OpenAIClientBuilder openAIClient2 = new OpenAIClientBuilder()
.credential(new AzureKeyCredential(aiModel.getApiKey()))
.endpoint(aiModel.getEndpoint())
.buildClient();
AzureOpenAiChatOptions tempopenAIChatOptions = AzureOpenAiChatOptions.builder()
.withDeploymentName(aiModel.getModel())
.withTemperature(aiModel.getTemperature())
.withMaxTokens(aiModel.getMaxTokens())
.endpoint(aiModel.getEndpoint());
AzureOpenAiChatOptions openAIChatOptions2 = AzureOpenAiChatOptions.builder()
.deploymentName(aiModel.getModel())
.maxTokens(aiModel.getMaxTokens())
.temperature(Double.valueOf(aiModel.getTemperature()))
.build();
AzureOpenAiChatModel tempazureOpenaichatModel = new AzureOpenAiChatModel(tempopenAIClient, tempopenAIChatOptions);
logger.info("AI model used: GoogleGemini");
return tempazureOpenaichatModel;
AzureOpenAiChatModel azureOpenaichatModel2 = new AzureOpenAiChatModel(openAIClient2, openAIChatOptions2);
logger.info("AI model used : " + aiModel.getModel());
return azureOpenaichatModel2;
default:
throw new IllegalArgumentException("Unsupported AI model: " + aiModel.getName());
}

View File

@@ -92,7 +92,7 @@ public class AdvancedAIPromptSolver extends StepSolver {
Usage usage = resp.chatResponse().getMetadata().getUsage();
if (usage != null) {
Long usedTokens = usage.getTotalTokens();
Integer usedTokens = usage.getTotalTokens();
this.scenarioExecution.setUsedTokens(usedTokens);
} else {
logger.info("Token usage information is not available.");

View File

@@ -65,7 +65,7 @@ public class BasicAIPromptSolver extends StepSolver {
Usage usage = resp.chatResponse().getMetadata().getUsage();
if (usage != null) {
Long usedTokens = usage.getTotalTokens();
Integer usedTokens = usage.getTotalTokens();
this.scenarioExecution.setUsedTokens(usedTokens);
} else {
logger.info("Token usage information is not available.");

View File

@@ -6,8 +6,7 @@ import java.util.ArrayList;
import org.slf4j.LoggerFactory;
import org.springframework.ai.document.Document;
import org.springframework.ai.vectorstore.SearchRequest;
import org.springframework.ai.vectorstore.SearchRequest.Builder;
import com.olympus.hermione.models.ScenarioExecution;
import com.olympus.hermione.utility.AttributeParser;
@@ -72,22 +71,29 @@ public class BasicQueryRagSolver extends StepSolver {
loadParameters();
logParameters();
SearchRequest request = SearchRequest.defaults()
.withQuery(this.query)
.withTopK(this.topk)
.withSimilarityThreshold(this.threshold);
Builder request_builder = SearchRequest.builder()
.query(this.query)
.topK(this.topk)
.similarityThreshold(this.threshold);
if(this.rag_filter != null && !this.rag_filter.isEmpty()){
request.withFilterExpression(this.rag_filter);
request_builder.filterExpression(this.rag_filter);
logger.info("Using Filter expression: " + this.rag_filter);
}
SearchRequest request = request_builder.build();
List<Document> docs = this.vectorStore.similaritySearch(request);
logger.info("Number of VDB retrieved documents: " + docs.size());
List<String> result = new ArrayList<String>();
for (Document doc : docs) {
result.add(doc.getContent());
result.add(doc.getText());
}
//concatenate the content of the results into a single string

View File

@@ -7,6 +7,7 @@ import java.util.List;
import org.slf4j.LoggerFactory;
import org.springframework.ai.document.Document;
import org.springframework.ai.vectorstore.SearchRequest;
import org.springframework.ai.vectorstore.filter.Filter;
public class DeleteDocTempSolver extends StepSolver {
@@ -56,16 +57,22 @@ public class DeleteDocTempSolver extends StepSolver {
this.scenarioExecution.setCurrentStepId(this.step.getStepId());
loadParameters();
SearchRequest searchRequest = SearchRequest.defaults()
vectorStore.delete(rag_filter);
/*SearchRequest searchRequest = SearchRequest.defaults()
.withQuery(this.query)
.withTopK(this.topk)
.withSimilarityThreshold(this.threshold)
.withFilterExpression(this.rag_filter);
List<Document> docs = vectorStore.similaritySearch(searchRequest);
List<String> ids = docs.stream().map(Document::getId).toList();
vectorStore.delete(ids);
vectorStore.delete(ids);*/
this.scenarioExecution.setNextStepId(this.step.getNextStepId());

View File

@@ -24,7 +24,6 @@ public class OlynmpusChatClientSolver extends StepSolver{
private String qai_system_prompt_template;
private String qai_user_input;
private String qai_output_variable;
private boolean qai_load_graph_schema=false;
Logger logger = (Logger) LoggerFactory.getLogger(BasicQueryRagSolver.class);
@@ -73,8 +72,7 @@ public class OlynmpusChatClientSolver extends StepSolver{
Long usedTokens = (long) resp.getTotalTokens();
this.scenarioExecution.setUsedTokens(usedTokens);
this.scenarioExecution.setUsedTokens(resp.getTotalTokens());
this.scenarioExecution.setNextStepId(this.step.getNextStepId());

View File

@@ -124,7 +124,7 @@ public class SummarizeDocSolver extends StepSolver {
// Creazione dei messaggi per il modello AI
Message userMessage = new UserMessage(summarizedText);
Message systemMessage = new SystemMessage(content);
logger.info("template: " + systemMessage.getContent().toString());
logger.info("template: " + systemMessage.getText());
CallResponseSpec resp = chatClient.prompt()
.messages(userMessage, systemMessage)
.advisors(advisor -> advisor
@@ -138,7 +138,7 @@ public class SummarizeDocSolver extends StepSolver {
// Gestione del conteggio token usati
Usage usage = resp.chatResponse().getMetadata().getUsage();
if (usage != null) {
Long usedTokens = usage.getTotalTokens();
Integer usedTokens = usage.getTotalTokens();
this.scenarioExecution.setUsedTokens(usedTokens);
} else {
logger.info("Token usage information is not available.");

View File

@@ -1,73 +1,77 @@
spring.application.name=hermione
server.port=8081
# spring.data.mongodb.uri=mongodb+srv://olympus_adm:26111979@olympus.l6qor4p.mongodb.net/?retryWrites=true&w=majority&appName=Olympus
# spring.data.mongodb.database=olympus
# spring.data.mongodb.username=olympus_adm
# spring.data.mongodb.password=26111979
spring.data.mongodb.uri=mongodb+srv://olympusadmin:Camilla123!@db-olympus.global.mongocluster.cosmos.azure.com/?tls=true&authMechanism=SCRAM-SHA-256&retrywrites=false&maxIdleTimeMS=120000
spring.data.mongodb.database=olympus
spring.data.mongodb.username=olympusadmin
spring.data.mongodb.password=Camilla123!
spring.ai.vectorstore.mongodb.indexName=vector_index
spring.ai.vectorstore.mongodb.collection-name=vector_store
spring.ai.vectorstore.mongodb.initialize-schema=false
spring.ai.vectorstore.azure.api-key=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
spring.ai.vectorstore.azure.url=https://search-olympus.search.windows.net_old
spring.ai.vectorstore.azure.initialize-schema =false
spring.ai.openai.api-key=sk-proj-j3TFJ0h348DIzMrYYfyUT3BlbkFJjk4HMc8A2ux2Asg8Y7H1
spring.ai.openai.chat.options.model=gpt-4o-mini
spring.main.allow-circular-references=true
spring.ai.azure.openai.api-key=4eHwvw6h7vHxTmI2870cR3EpEBs5L9sXZabr9nz37y39TXtk0xY5JQQJ99AKAC5RqLJXJ3w3AAABACOGLdow
spring.ai.azure.openai.endpoint=https://ai-olympus-new.openai.azure.com/
#spring.ai.azure.openai.api-key=9fb33cc69d914d4c8225b974876510b5
#spring.ai.azure.openai.endpoint=https://ai-olympus.openai.azure.com/
spring.ai.azure.openai.chat.options.deployment-name=gpt-4o-mini
spring.ai.azure.openai.chat.options.temperature=0.7
# neo4j.uri=neo4j+s://e17e6f08.databases.neo4j.io:7687
# neo4j.username=neo4j
# neo4j.password=8SrSqQ3q6q9PQNWtN9ozqSQfGce4lfh_n6kKz2JIubQ
neo4j.uri=bolt://57.153.162.67:7687
neo4j.username=neo4j
neo4j.password=01J5h56IsTyyKt
# spring.neo4j.uri=neo4j+s://e17e6f08.databases.neo4j.io:7687
# spring.neo4j.authentication.username=neo4j
# spring.neo4j.authentication.password=8SrSqQ3q6q9PQNWtN9ozqSQfGce4lfh_n6kKz2JIubQ
spring.neo4j.uri=bolt://57.153.162.67:7687
spring.neo4j.authentication.username=neo4j
spring.neo4j.authentication.password=01J5h56IsTyyKt
spring.main.allow-bean-definition-overriding=true
logging.level.org.springframework.ai.chat.client.advisor=INFO
eureka.client.serviceUrl.defaultZone: ${EUREKA_URI:http://localhost:8761/eureka}
eureka.instance.preferIpAddress: true
hermione.fe.url = http://localhost:5173
java-parser-module.url: http://java-parser-module-service.olympus.svc.cluster.local:8080
java-re-module.url: http://java-re-module-service.olympus.svc.cluster.local:8080
jsp-parser-module.url: http://jsp-parser-module-service.olympus.svc.cluster.local:8080
spring.ai.vectorstore.chroma.client.host=http://108.142.74.161
spring.ai.vectorstore.chroma.client.port=8000
spring.ai.vectorstore.chroma.client.key-token=tKAJfN1Yv5lP7pKorJHGfHMQhNEcM9uu
spring.ai.vectorstore.chroma.initialize-schema=true
spring.ai.vectorstore.chroma.collection-name=olympus
file.upload-dir=/mnt/hermione_storage/documents/file_input_scenarios/
spring.servlet.multipart.max-file-size=10MB
spring.servlet.multipart.max-request-size=10MB
generic-file-parser-module.url=http://generic-file-parser-module-service.olympus.svc.cluster.local:8080
file.upload-dir=C:\\mnt\\hermione_storage\\documents\\file_input_scenarios\\
generic-file-parser-module.url=http://generic-file-parser-module-service.olympus.svc.cluster.local:8080
java-parser-module.url: http://java-parser-module-service.olympus.svc.cluster.local:8080
java-re-module.url: http://java-re-module-service.olympus.svc.cluster.local:8080
jsp-parser-module.url: http://jsp-parser-module-service.olympus.svc.cluster.local:8080