aded OllamaModels

This commit is contained in:
Lucio Lelii 2025-05-22 11:12:35 +02:00
parent 73d894a11c
commit 5f8f7df756
10 changed files with 7 additions and 261 deletions

View File

@ -12,7 +12,7 @@ import org.springframework.util.ResourceUtils;
import com.fasterxml.jackson.databind.ObjectMapper;
import it.cnr.isti.workflow.manager.executors.ai.AIModel;
import it.cnr.isti.workflow.manager.executors.ai.models.AIModel;
import it.cnr.isti.workflow.manager.model.auth.LoginEntity;
import it.cnr.isti.workflow.manager.model.flows.Flow;
import it.cnr.isti.workflow.manager.model.types.IOType;

View File

@ -4,7 +4,6 @@ import java.util.List;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;

View File

@ -1,15 +0,0 @@
package it.cnr.isti.workflow.manager.executors.ai;
import java.util.Map;
public interface AIModel {
String getName();
String getDescription();
String executePrompt(Map<String, Object> parameters, String prompt) throws Throwable;
public Map<String, Class<?>> getRequiredPreExecutionParameters();
}

View File

@ -1,120 +0,0 @@
package it.cnr.isti.workflow.manager.executors.ai;
import java.io.IOException;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.databind.ObjectMapper;
import it.cnr.isti.workflow.manager.executors.ai.services.GeminiService;
@Service("google-gemini")
public class GeminiModel implements AIModel {
private static final Logger log = org.slf4j.LoggerFactory.getLogger(GeminiModel.class);
private GeminiService geminiService;
GeminiModel(@Autowired GeminiService geminiService) {
this.geminiService = geminiService;
}
@Override
public String getName() {
return "google-gemini";
}
@Override
public String getDescription() {
return "Gemini is an LLM model provided by Google";
}
@Override
public String executePrompt(Map<String, Object> parameters, String prompt) throws Throwable {
geminiService.setApiKey("***REMOVED-API-KEY***");
//log.info("------- REQUEST ------------");
//log.info(prompt);
//log.info("-------------------");
String result = geminiService.getResponse(prompt).block();
ObjectMapper objectMapper = new ObjectMapper();
// Deserializzazione della risposta JSON in un oggetto GeminiResponse
GeminiResponse response = objectMapper.readValue(result, GeminiResponse.class);
// Estrazione del testo dal primo candidato
String candidateText = response.getCandidates().get(0).getContent().getParts().get(0).getText();
//log.info("------- RESPONSE ------------");
//log.info(candidateText);
//log.info("-------------------");
return candidateText;
}
@Override
public Map<String, Class<?>> getRequiredPreExecutionParameters() {
return Map.of("API-KEY", String.class);
}
}
@JsonIgnoreProperties(ignoreUnknown = true)
class GeminiResponse {
private java.util.List<Candidate> candidates;
public java.util.List<Candidate> getCandidates() {
return candidates;
}
public void setCandidates(java.util.List<Candidate> candidates) {
this.candidates = candidates;
}
@JsonIgnoreProperties(ignoreUnknown = true)
public static class Candidate {
private Content content;
public Content getContent() {
return content;
}
public void setContent(Content content) {
this.content = content;
}
}
@JsonIgnoreProperties(ignoreUnknown = true)
public static class Content {
private java.util.List<Part> parts;
public java.util.List<Part> getParts() {
return parts;
}
public void setParts(java.util.List<Part> parts) {
this.parts = parts;
}
}
@JsonIgnoreProperties(ignoreUnknown = true)
public static class Part {
private String text;
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
}
}

View File

@ -12,6 +12,7 @@ import org.springframework.stereotype.Service;
import it.cnr.isti.workflow.manager.exceptions.ExecutionException;
import it.cnr.isti.workflow.manager.executors.Executor;
import it.cnr.isti.workflow.manager.executors.ai.models.AIModel;
import it.cnr.isti.workflow.manager.model.ExecutorDescriptor;
import it.cnr.isti.workflow.manager.model.types.ParameterDefinition;
import it.cnr.isti.workflow.manager.model.types.ParameterType;

View File

@ -1,68 +0,0 @@
package it.cnr.isti.workflow.manager.executors.ai;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import it.cnr.isti.workflow.manager.executors.ai.services.OpenRouterService;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service("open-router")
public class OpenRouterModel implements AIModel {
private static final Logger log = org.slf4j.LoggerFactory.getLogger(OpenRouterModel.class);
@Autowired
private OpenRouterService openRouterService;
@Override
public String getName() {
return "open-router";
}
@Override
public String getDescription() {
return "OpenRouter is a free LLM based on DeepSeek v1 model";
}
@Override
public String executePrompt(Map<String, Object> parameters, String prompt) {
openRouterService.setApiKey("***REMOVED-API-KEY***");
String result = openRouterService.getResponse(prompt).block();
log.debug("openrouter called with result {}",result);
result = parseResponse(result);
log.debug("post parsing: {}",result);
return result;
}
private String parseResponse(String response) {
Pattern pattern = Pattern.compile("\"text\"\\s*:\\s*\"(.*?)\"");
Matcher matcher = pattern.matcher(response);
if (matcher.find()) {
return matcher.group(1); // Estratto il testo
}
return response;
}
@Override
public Map<String, Class<?>> getRequiredPreExecutionParameters() {
return Map.of("API-KEY", String.class);
}
/*
@Override
public Map<String, Object> execute(Map<String, Object> userParameters, Map<String, Object> preExecutionParameters,
Map<String, Object> inputsFromParent) {
String returnString = (String)executePrompt(preExecutionParameters, (String) inputsFromParent.get("prompt"));
return Map.of("response", returnString);
}*/
}

View File

@ -1,53 +0,0 @@
package it.cnr.isti.workflow.manager.executors.ai.services;
import org.springframework.web.reactive.function.client.WebClient;
import org.springframework.http.MediaType;
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Mono;
import reactor.netty.http.client.HttpClient;
import java.util.Map;
import java.time.Duration;
import java.util.List;
import java.util.Objects;
@Service
public class OpenRouterService {
private final WebClient.Builder webClientBuilder;
private String apiKey;
private static final String OpenRouter_URL = "https://openrouter.ai/api/v1/chat/completions";
public OpenRouterService(WebClient.Builder webClientBuilder) {
HttpClient client = HttpClient.create()
.responseTimeout(Duration.ofMinutes(2));
this.webClientBuilder = webClientBuilder.clientConnector(new ReactorClientHttpConnector(client));
}
public void setApiKey(String apiKey) {
this.apiKey = apiKey;
}
public Mono<String> getResponse(String prompt) {
Objects.requireNonNull(prompt, "prompt cannot be null");
Map<String, Object> requestBody = Map.of(
"model", "deepseek/deepseek-v3-base:free",
"messages", List.of( Map.of(
"role", "user",
"content", prompt
)
));
WebClient webClient = webClientBuilder.baseUrl(OpenRouter_URL).build();
Mono<String> result = webClient.post()
.header("Authorization", "Bearer " + apiKey)
.contentType(MediaType.APPLICATION_JSON)
.bodyValue(requestBody)
.retrieve()
.bodyToMono(String.class);
return result;
}
}

View File

@ -3,6 +3,7 @@ package it.cnr.isti.workflow.manager.model.types;
public enum ParameterType {
Select,
DynamicMultiOptions,
Text,
Boolean,
Number

View File

@ -6,7 +6,7 @@ spring.datasource.username=${DB_USER:lucio}
spring.datasource.password=${DB_PASSWORD:password}
spring.datasource.driver-class-name=org.postgresql.Driver
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect
spring.jpa.hibernate.ddl-auto=update
# Keycloak
#keycloak.realm=${REALM_NAME:wf-editor}
@ -25,9 +25,10 @@ spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect
# create and drop table, good for testing, production set to none or comment it
spring.jpa.hibernate.ddl-auto=create-drop
app.db.init.enabled=false
app.security.key=${WFEDITOR_SECRET_KEY:088c65fd2a5ca418a79cd10df5dff15c0a79781c0da4fd43c1c14e4e2d7af1ff}
app.ollama.internal.key=${OLLAMA_INTERNAL_KEY:ollama}
app.ollama.internal.url=${OLLAMA_INTERNAL_URL:https://ollama.internal/api}
cors.allowed-origins=${CORS_ALLOWED_ORIGINS:http://localhost:4200}
app.import.path=${IMPORT_PATH:/workflow-editor-init}
app.import.enabled=true

View File

@ -4,7 +4,7 @@ spring.datasource.username=
spring.datasource.password=
# We add the MySQL Dialect so that it understands and generates the query based on MySQL
spring.jpa.database-platform=org.hibernate.dialect.MySQLDialect
spring.jpa.hibernate.ddl-auto=create-drop
app.db.init.enabled=true
app.import.path=src/main/resources/workflow-editor-init