modelcall and chatclient rework

This commit is contained in:
Josh Long
2024-05-18 21:30:51 +02:00
committed by Christian Tzolov
parent 2abf10dbf9
commit c4bfb5709b
158 changed files with 1144 additions and 662 deletions

View File

@@ -51,11 +51,11 @@ public class AnthropicChatOptions implements ChatOptions, FunctionCallingOptions
private @JsonProperty("top_k") Integer topK;
/**
* Tool Function Callbacks to register with the ChatClient. For Prompt
* Tool Function Callbacks to register with the ModelCall. For Prompt
* Options the functionCallbacks are automatically enabled for the duration of the
* prompt execution. For Default Options the functionCallbacks are registered but
* disabled by default. Use the enableFunctions to set the functions from the registry
* to be used by the ChatClient chat completion requests.
* to be used by the ModelCall chat completion requests.
*/
@NestedConfigurationProperty
@JsonIgnore

View File

@@ -26,6 +26,7 @@ import java.util.stream.Collectors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ai.chat.ModelCall;
import reactor.core.publisher.Flux;
import org.springframework.ai.anthropic.api.AnthropicApi;
@@ -38,7 +39,6 @@ import org.springframework.ai.anthropic.api.AnthropicApi.Role;
import org.springframework.ai.anthropic.api.AnthropicApi.StreamResponse;
import org.springframework.ai.anthropic.api.AnthropicApi.Usage;
import org.springframework.ai.anthropic.metadata.AnthropicChatResponseMetadata;
import org.springframework.ai.chat.ChatClient;
import org.springframework.ai.chat.ChatResponse;
import org.springframework.ai.chat.Generation;
import org.springframework.ai.chat.StreamingChatClient;
@@ -56,16 +56,16 @@ import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
/**
* The {@link ChatClient} implementation for the Anthropic service.
* The {@link ModelCall} implementation for the Anthropic service.
*
* @author Christian Tzolov
* @since 1.0.0
*/
public class AnthropicChatClient extends
public class AnthropicModelCall extends
AbstractFunctionCallSupport<AnthropicApi.RequestMessage, AnthropicApi.ChatCompletionRequest, ResponseEntity<AnthropicApi.ChatCompletion>>
implements ChatClient, StreamingChatClient {
implements ModelCall, StreamingChatClient {
private static final Logger logger = LoggerFactory.getLogger(AnthropicChatClient.class);
private static final Logger logger = LoggerFactory.getLogger(AnthropicModelCall.class);
public static final String DEFAULT_MODEL_NAME = AnthropicApi.ChatModel.CLAUDE_3_OPUS.getValue();
@@ -89,10 +89,10 @@ public class AnthropicChatClient extends
public final RetryTemplate retryTemplate;
/**
* Construct a new {@link AnthropicChatClient} instance.
* Construct a new {@link AnthropicModelCall} instance.
* @param anthropicApi the lower-level API for the Anthropic service.
*/
public AnthropicChatClient(AnthropicApi anthropicApi) {
public AnthropicModelCall(AnthropicApi anthropicApi) {
this(anthropicApi,
AnthropicChatOptions.builder()
.withModel(DEFAULT_MODEL_NAME)
@@ -102,34 +102,34 @@ public class AnthropicChatClient extends
}
/**
* Construct a new {@link AnthropicChatClient} instance.
* Construct a new {@link AnthropicModelCall} instance.
* @param anthropicApi the lower-level API for the Anthropic service.
* @param defaultOptions the default options used for the chat completion requests.
*/
public AnthropicChatClient(AnthropicApi anthropicApi, AnthropicChatOptions defaultOptions) {
public AnthropicModelCall(AnthropicApi anthropicApi, AnthropicChatOptions defaultOptions) {
this(anthropicApi, defaultOptions, RetryUtils.DEFAULT_RETRY_TEMPLATE);
}
/**
* Construct a new {@link AnthropicChatClient} instance.
* Construct a new {@link AnthropicModelCall} instance.
* @param anthropicApi the lower-level API for the Anthropic service.
* @param defaultOptions the default options used for the chat completion requests.
* @param retryTemplate the retry template used to retry the Anthropic API calls.
*/
public AnthropicChatClient(AnthropicApi anthropicApi, AnthropicChatOptions defaultOptions,
public AnthropicModelCall(AnthropicApi anthropicApi, AnthropicChatOptions defaultOptions,
RetryTemplate retryTemplate) {
this(anthropicApi, defaultOptions, retryTemplate, null);
}
/**
* Construct a new {@link AnthropicChatClient} instance.
* Construct a new {@link AnthropicModelCall} instance.
* @param anthropicApi the lower-level API for the Anthropic service.
* @param defaultOptions the default options used for the chat completion requests.
* @param retryTemplate the retry template used to retry the Anthropic API calls.
* @param functionCallbackContext the function callback context used to store the
* state of the function calls.
*/
public AnthropicChatClient(AnthropicApi anthropicApi, AnthropicChatOptions defaultOptions,
public AnthropicModelCall(AnthropicApi anthropicApi, AnthropicChatOptions defaultOptions,
RetryTemplate retryTemplate, FunctionCallbackContext functionCallbackContext) {
super(functionCallbackContext);

View File

@@ -29,7 +29,7 @@ import org.slf4j.LoggerFactory;
import org.springframework.ai.anthropic.api.AnthropicApi;
import org.springframework.ai.anthropic.api.tool.MockWeatherService;
import org.springframework.ai.chat.ChatClient;
import org.springframework.ai.chat.ModelCall;
import org.springframework.ai.chat.ChatResponse;
import org.springframework.ai.chat.Generation;
import org.springframework.ai.chat.StreamingChatClient;
@@ -56,12 +56,12 @@ import static org.assertj.core.api.Assertions.assertThat;
@SpringBootTest(classes = AnthropicTestConfiguration.class, properties = "spring.ai.retry.on-http-codes=429")
@EnabledIfEnvironmentVariable(named = "ANTHROPIC_API_KEY", matches = ".+")
class AnthropicChatClientIT {
class AnthropicModelCallIT {
private static final Logger logger = LoggerFactory.getLogger(AnthropicChatClientIT.class);
private static final Logger logger = LoggerFactory.getLogger(AnthropicModelCallIT.class);
@Autowired
protected ChatClient chatClient;
protected ModelCall modelCall;
@Autowired
protected StreamingChatClient streamingChatClient;
@@ -76,7 +76,7 @@ class AnthropicChatClientIT {
SystemPromptTemplate systemPromptTemplate = new SystemPromptTemplate(systemResource);
Message systemMessage = systemPromptTemplate.createMessage(Map.of("name", "Bob", "voice", "pirate"));
Prompt prompt = new Prompt(List.of(userMessage, systemMessage));
ChatResponse response = chatClient.call(prompt);
ChatResponse response = modelCall.call(prompt);
assertThat(response.getResults()).hasSize(1);
assertThat(response.getMetadata().getUsage().getGenerationTokens()).isGreaterThan(0);
assertThat(response.getMetadata().getUsage().getPromptTokens()).isGreaterThan(0);
@@ -102,7 +102,7 @@ class AnthropicChatClientIT {
PromptTemplate promptTemplate = new PromptTemplate(template,
Map.of("subject", "ice cream flavors", "format", format));
Prompt prompt = new Prompt(promptTemplate.createMessage());
Generation generation = this.chatClient.call(prompt).getResult();
Generation generation = this.modelCall.call(prompt).getResult();
List<String> list = listOutputConverter.convert(generation.getOutput().getContent());
assertThat(list).hasSize(5);
@@ -120,7 +120,7 @@ class AnthropicChatClientIT {
PromptTemplate promptTemplate = new PromptTemplate(template,
Map.of("subject", "an array of numbers from 1 to 9 under they key name 'numbers'", "format", format));
Prompt prompt = new Prompt(promptTemplate.createMessage());
Generation generation = chatClient.call(prompt).getResult();
Generation generation = modelCall.call(prompt).getResult();
Map<String, Object> result = mapOutputConverter.convert(generation.getOutput().getContent());
assertThat(result.get("numbers")).isEqualTo(Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9));
@@ -142,7 +142,7 @@ class AnthropicChatClientIT {
""";
PromptTemplate promptTemplate = new PromptTemplate(template, Map.of("format", format));
Prompt prompt = new Prompt(promptTemplate.createMessage());
Generation generation = chatClient.call(prompt).getResult();
Generation generation = modelCall.call(prompt).getResult();
ActorsFilmsRecord actorsFilms = beanOutputConverter.convert(generation.getOutput().getContent());
logger.info("" + actorsFilms);
@@ -187,7 +187,7 @@ class AnthropicChatClientIT {
var userMessage = new UserMessage("Explain what do you see on this picture?",
List.of(new Media(MimeTypeUtils.IMAGE_PNG, imageData)));
var response = chatClient.call(new Prompt(List.of(userMessage)));
var response = modelCall.call(new Prompt(List.of(userMessage)));
logger.info(response.getResult().getOutput().getContent());
assertThat(response.getResult().getOutput().getContent()).contains("bananas", "apple", "basket");
@@ -209,7 +209,7 @@ class AnthropicChatClientIT {
.build()))
.build();
ChatResponse response = chatClient.call(new Prompt(messages, promptOptions));
ChatResponse response = modelCall.call(new Prompt(messages, promptOptions));
logger.info("Response: {}", response);

View File

@@ -38,8 +38,8 @@ public class AnthropicTestConfiguration {
}
@Bean
public AnthropicChatClient openAiChatClient(AnthropicApi api) {
AnthropicChatClient anthropicChatClient = new AnthropicChatClient(api);
public AnthropicModelCall openAiChatClient(AnthropicApi api) {
AnthropicModelCall anthropicChatClient = new AnthropicModelCall(api);
return anthropicChatClient;
}

View File

@@ -30,7 +30,7 @@ public class ChatCompletionRequestTests {
@Test
public void createRequestWithChatOptions() {
var client = new AnthropicChatClient(new AnthropicApi("TEST"),
var client = new AnthropicModelCall(new AnthropicApi("TEST"),
AnthropicChatOptions.builder().withModel("DEFAULT_MODEL").withTemperature(66.6f).build());
var request = client.createRequest(new Prompt("Test message content"), false);

View File

@@ -127,11 +127,11 @@ public class AzureOpenAiChatOptions implements FunctionCallingOptions, ChatOptio
private String deploymentName;
/**
* OpenAI Tool Function Callbacks to register with the ChatClient. For Prompt Options
* OpenAI Tool Function Callbacks to register with the ModelCall. For Prompt Options
* the functionCallbacks are automatically enabled for the duration of the prompt
* execution. For Default Options the functionCallbacks are registered but disabled by
* default. Use the enableFunctions to set the functions from the registry to be used
* by the ChatClient chat completion requests.
* by the ModelCall chat completion requests.
*/
@NestedConfigurationProperty
@JsonIgnore

View File

@@ -38,7 +38,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ai.azure.openai.metadata.AzureOpenAiChatResponseMetadata;
import org.springframework.ai.chat.ChatClient;
import org.springframework.ai.chat.ModelCall;
import org.springframework.ai.chat.ChatResponse;
import org.springframework.ai.chat.Generation;
import org.springframework.ai.chat.StreamingChatClient;
@@ -63,7 +63,7 @@ import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* {@link ChatClient} implementation for {@literal Microsoft Azure AI} backed by
* {@link ModelCall} implementation for {@literal Microsoft Azure AI} backed by
* {@link OpenAIClient}.
*
* @author Mark Pollack
@@ -71,12 +71,12 @@ import java.util.concurrent.atomic.AtomicBoolean;
* @author John Blum
* @author Christian Tzolov
* @author Grogdunn
* @see ChatClient
* @see ModelCall
* @see com.azure.ai.openai.OpenAIClient
*/
public class AzureOpenAiChatClient
public class AzureOpenAiModelCall
extends AbstractFunctionCallSupport<ChatRequestMessage, ChatCompletionsOptions, ChatCompletions>
implements ChatClient, StreamingChatClient {
implements ModelCall, StreamingChatClient {
private static final String DEFAULT_DEPLOYMENT_NAME = "gpt-35-turbo";
@@ -94,7 +94,7 @@ public class AzureOpenAiChatClient
*/
private final OpenAIClient openAIClient;
public AzureOpenAiChatClient(OpenAIClient microsoftOpenAiClient) {
public AzureOpenAiModelCall(OpenAIClient microsoftOpenAiClient) {
this(microsoftOpenAiClient,
AzureOpenAiChatOptions.builder()
.withDeploymentName(DEFAULT_DEPLOYMENT_NAME)
@@ -102,11 +102,11 @@ public class AzureOpenAiChatClient
.build());
}
public AzureOpenAiChatClient(OpenAIClient microsoftOpenAiClient, AzureOpenAiChatOptions options) {
public AzureOpenAiModelCall(OpenAIClient microsoftOpenAiClient, AzureOpenAiChatOptions options) {
this(microsoftOpenAiClient, options, null);
}
public AzureOpenAiChatClient(OpenAIClient microsoftOpenAiClient, AzureOpenAiChatOptions options,
public AzureOpenAiModelCall(OpenAIClient microsoftOpenAiClient, AzureOpenAiChatOptions options,
FunctionCallbackContext functionCallbackContext) {
super(functionCallbackContext);
Assert.notNull(microsoftOpenAiClient, "com.azure.ai.openai.OpenAIClient must not be null");
@@ -117,10 +117,10 @@ public class AzureOpenAiChatClient
/**
* @deprecated since 0.8.0, use
* {@link #AzureOpenAiChatClient(OpenAIClient, AzureOpenAiChatOptions)} instead.
* {@link #AzureOpenAiModelCall(OpenAIClient, AzureOpenAiChatOptions)} instead.
*/
@Deprecated(forRemoval = true, since = "0.8.0")
public AzureOpenAiChatClient withDefaultOptions(AzureOpenAiChatOptions defaultOptions) {
public AzureOpenAiModelCall withDefaultOptions(AzureOpenAiChatOptions defaultOptions) {
Assert.notNull(defaultOptions, "DefaultOptions must not be null");
this.defaultOptions = defaultOptions;
return this;

View File

@@ -53,7 +53,7 @@ public class AzureChatCompletionsOptionsTests {
.withUser("user")
.build();
var client = new AzureOpenAiChatClient(mockClient, defaultOptions);
var client = new AzureOpenAiModelCall(mockClient, defaultOptions);
var requestOptions = client.toAzureChatCompletionsOptions(new Prompt("Test message content"));

View File

@@ -46,13 +46,13 @@ import org.springframework.core.convert.support.DefaultConversionService;
import static org.assertj.core.api.Assertions.assertThat;
@SpringBootTest(classes = AzureOpenAiChatClientIT.TestConfiguration.class)
@SpringBootTest(classes = AzureOpenAiModelCallIT.TestConfiguration.class)
@EnabledIfEnvironmentVariable(named = "AZURE_OPENAI_API_KEY", matches = ".+")
@EnabledIfEnvironmentVariable(named = "AZURE_OPENAI_ENDPOINT", matches = ".+")
class AzureOpenAiChatClientIT {
class AzureOpenAiModelCallIT {
@Autowired
private AzureOpenAiChatClient chatClient;
private AzureOpenAiModelCall chatClient;
record ActorsFilms(String actor, List<String> movies) {
}
@@ -194,8 +194,8 @@ class AzureOpenAiChatClientIT {
}
@Bean
public AzureOpenAiChatClient azureOpenAiChatClient(OpenAIClient openAIClient) {
return new AzureOpenAiChatClient(openAIClient,
public AzureOpenAiModelCall azureOpenAiChatClient(OpenAIClient openAIClient) {
return new AzureOpenAiModelCall(openAIClient,
AzureOpenAiChatOptions.builder().withDeploymentName("gpt-35-turbo").withMaxTokens(200).build());
}

View File

@@ -59,8 +59,8 @@ public class MockAzureOpenAiTestConfiguration {
}
@Bean
AzureOpenAiChatClient azureOpenAiChatClient(OpenAIClient microsoftAzureOpenAiClient) {
return new AzureOpenAiChatClient(microsoftAzureOpenAiClient);
AzureOpenAiModelCall azureOpenAiChatClient(OpenAIClient microsoftAzureOpenAiClient) {
return new AzureOpenAiModelCall(microsoftAzureOpenAiClient);
}
}

View File

@@ -29,7 +29,7 @@ import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ai.azure.openai.AzureOpenAiChatClient;
import org.springframework.ai.azure.openai.AzureOpenAiModelCall;
import org.springframework.ai.azure.openai.AzureOpenAiChatOptions;
import org.springframework.ai.chat.ChatResponse;
import org.springframework.ai.chat.Generation;
@@ -46,18 +46,18 @@ import reactor.core.publisher.Flux;
import static org.assertj.core.api.Assertions.assertThat;
@SpringBootTest(classes = AzureOpenAiChatClientFunctionCallIT.TestConfiguration.class)
@SpringBootTest(classes = AzureOpenAiModelCallFunctionCallIT.TestConfiguration.class)
@EnabledIfEnvironmentVariable(named = "AZURE_OPENAI_API_KEY", matches = ".+")
@EnabledIfEnvironmentVariable(named = "AZURE_OPENAI_ENDPOINT", matches = ".+")
class AzureOpenAiChatClientFunctionCallIT {
class AzureOpenAiModelCallFunctionCallIT {
private static final Logger logger = LoggerFactory.getLogger(AzureOpenAiChatClientFunctionCallIT.class);
private static final Logger logger = LoggerFactory.getLogger(AzureOpenAiModelCallFunctionCallIT.class);
@Autowired
private String selectedModel;
@Autowired
private AzureOpenAiChatClient chatClient;
private AzureOpenAiModelCall chatClient;
@Test
void functionCallTest() {
@@ -129,8 +129,8 @@ class AzureOpenAiChatClientFunctionCallIT {
}
@Bean
public AzureOpenAiChatClient azureOpenAiChatClient(OpenAIClient openAIClient, String selectedModel) {
return new AzureOpenAiChatClient(openAIClient,
public AzureOpenAiModelCall azureOpenAiChatClient(OpenAIClient openAIClient, String selectedModel) {
return new AzureOpenAiModelCall(openAIClient,
AzureOpenAiChatOptions.builder().withDeploymentName(selectedModel).withMaxTokens(500).build());
}

View File

@@ -23,7 +23,7 @@ import com.azure.ai.openai.models.ContentFilterResultsForChoice;
import com.azure.ai.openai.models.ContentFilterSeverity;
import org.junit.jupiter.api.Test;
import org.springframework.ai.azure.openai.AzureOpenAiChatClient;
import org.springframework.ai.azure.openai.AzureOpenAiModelCall;
import org.springframework.ai.azure.openai.MockAzureOpenAiTestConfiguration;
import org.springframework.ai.chat.ChatResponse;
import org.springframework.ai.chat.Generation;
@@ -55,7 +55,7 @@ import org.springframework.web.context.request.WebRequest;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Unit Tests for {@link AzureOpenAiChatClient} asserting AI metadata.
* Unit Tests for {@link AzureOpenAiModelCall} asserting AI metadata.
*
* @author John Blum
* @author Christian Tzolov
@@ -63,12 +63,12 @@ import static org.assertj.core.api.Assertions.assertThat;
*/
@SpringBootTest
@ActiveProfiles("spring-ai-azure-openai-mocks")
@ContextConfiguration(classes = AzureOpenAiChatClientMetadataTests.TestConfiguration.class)
@ContextConfiguration(classes = AzureOpenAiModelCallMetadataTests.TestConfiguration.class)
@SuppressWarnings("unused")
class AzureOpenAiChatClientMetadataTests {
class AzureOpenAiModelCallMetadataTests {
@Autowired
private AzureOpenAiChatClient aiClient;
private AzureOpenAiModelCall aiClient;
@Test
void azureOpenAiMetadataCapturedDuringGeneration() {

View File

@@ -17,7 +17,7 @@ package org.springframework.ai.bedrock.anthropic;
import java.util.List;
import org.springframework.ai.chat.ChatClient;
import org.springframework.ai.chat.ModelCall;
import org.springframework.ai.chat.prompt.ChatOptions;
import org.springframework.ai.chat.ChatResponse;
import org.springframework.ai.chat.metadata.ChatGenerationMetadata;
@@ -33,19 +33,19 @@ import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.model.ModelOptionsUtils;
/**
* Java {@link ChatClient} and {@link StreamingChatClient} for the Bedrock Anthropic chat
* Java {@link ModelCall} and {@link StreamingChatClient} for the Bedrock Anthropic chat
* generative.
*
* @author Christian Tzolov
* @since 0.8.0
*/
public class BedrockAnthropicChatClient implements ChatClient, StreamingChatClient {
public class BedrockAnthropicModelCall implements ModelCall, StreamingChatClient {
private final AnthropicChatBedrockApi anthropicChatApi;
private final AnthropicChatOptions defaultOptions;
public BedrockAnthropicChatClient(AnthropicChatBedrockApi chatApi) {
public BedrockAnthropicModelCall(AnthropicChatBedrockApi chatApi) {
this(chatApi,
AnthropicChatOptions.builder()
.withTemperature(0.8f)
@@ -55,7 +55,7 @@ public class BedrockAnthropicChatClient implements ChatClient, StreamingChatClie
.build());
}
public BedrockAnthropicChatClient(AnthropicChatBedrockApi chatApi, AnthropicChatOptions options) {
public BedrockAnthropicModelCall(AnthropicChatBedrockApi chatApi, AnthropicChatOptions options) {
this.anthropicChatApi = chatApi;
this.defaultOptions = options;
}

View File

@@ -22,7 +22,7 @@ import org.springframework.ai.bedrock.anthropic3.api.Anthropic3ChatBedrockApi.An
import org.springframework.ai.bedrock.anthropic3.api.Anthropic3ChatBedrockApi.MediaContent;
import org.springframework.ai.bedrock.anthropic3.api.Anthropic3ChatBedrockApi.ChatCompletionMessage;
import org.springframework.ai.bedrock.anthropic3.api.Anthropic3ChatBedrockApi.ChatCompletionMessage.Role;
import org.springframework.ai.chat.ChatClient;
import org.springframework.ai.chat.ModelCall;
import org.springframework.ai.chat.ChatResponse;
import org.springframework.ai.chat.Generation;
import org.springframework.ai.chat.StreamingChatClient;
@@ -43,20 +43,20 @@ import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;
/**
* Java {@link ChatClient} and {@link StreamingChatClient} for the Bedrock Anthropic chat
* Java {@link ModelCall} and {@link StreamingChatClient} for the Bedrock Anthropic chat
* generative.
*
* @author Ben Middleton
* @author Christian Tzolov
* @since 1.0.0
*/
public class BedrockAnthropic3ChatClient implements ChatClient, StreamingChatClient {
public class BedrockAnthropic3ModelCall implements ModelCall, StreamingChatClient {
private final Anthropic3ChatBedrockApi anthropicChatApi;
private final Anthropic3ChatOptions defaultOptions;
public BedrockAnthropic3ChatClient(Anthropic3ChatBedrockApi chatApi) {
public BedrockAnthropic3ModelCall(Anthropic3ChatBedrockApi chatApi) {
this(chatApi,
Anthropic3ChatOptions.builder()
.withTemperature(0.8f)
@@ -66,7 +66,7 @@ public class BedrockAnthropic3ChatClient implements ChatClient, StreamingChatCli
.build());
}
public BedrockAnthropic3ChatClient(Anthropic3ChatBedrockApi chatApi, Anthropic3ChatOptions options) {
public BedrockAnthropic3ModelCall(Anthropic3ChatBedrockApi chatApi, Anthropic3ChatOptions options) {
this.anthropicChatApi = chatApi;
this.defaultOptions = options;
}

View File

@@ -24,7 +24,7 @@ import org.springframework.ai.bedrock.MessageToPromptConverter;
import org.springframework.ai.bedrock.cohere.api.CohereChatBedrockApi;
import org.springframework.ai.bedrock.cohere.api.CohereChatBedrockApi.CohereChatRequest;
import org.springframework.ai.bedrock.cohere.api.CohereChatBedrockApi.CohereChatResponse;
import org.springframework.ai.chat.ChatClient;
import org.springframework.ai.chat.ModelCall;
import org.springframework.ai.chat.prompt.ChatOptions;
import org.springframework.ai.chat.ChatResponse;
import org.springframework.ai.chat.Generation;
@@ -39,17 +39,17 @@ import org.springframework.util.Assert;
* @author Christian Tzolov
* @since 0.8.0
*/
public class BedrockCohereChatClient implements ChatClient, StreamingChatClient {
public class BedrockCohereModelCall implements ModelCall, StreamingChatClient {
private final CohereChatBedrockApi chatApi;
private final BedrockCohereChatOptions defaultOptions;
public BedrockCohereChatClient(CohereChatBedrockApi chatApi) {
public BedrockCohereModelCall(CohereChatBedrockApi chatApi) {
this(chatApi, BedrockCohereChatOptions.builder().build());
}
public BedrockCohereChatClient(CohereChatBedrockApi chatApi, BedrockCohereChatOptions options) {
public BedrockCohereModelCall(CohereChatBedrockApi chatApi, BedrockCohereChatOptions options) {
Assert.notNull(chatApi, "CohereChatBedrockApi must not be null");
Assert.notNull(options, "BedrockCohereChatOptions must not be null");

View File

@@ -19,7 +19,7 @@ package org.springframework.ai.bedrock.jurassic2;
import org.springframework.ai.bedrock.MessageToPromptConverter;
import org.springframework.ai.bedrock.jurassic2.api.Ai21Jurassic2ChatBedrockApi;
import org.springframework.ai.bedrock.jurassic2.api.Ai21Jurassic2ChatBedrockApi.Ai21Jurassic2ChatRequest;
import org.springframework.ai.chat.ChatClient;
import org.springframework.ai.chat.ModelCall;
import org.springframework.ai.chat.ChatResponse;
import org.springframework.ai.chat.Generation;
import org.springframework.ai.chat.metadata.ChatGenerationMetadata;
@@ -29,19 +29,18 @@ import org.springframework.ai.model.ModelOptionsUtils;
import org.springframework.util.Assert;
/**
* Java {@link ChatClient} for the Bedrock Jurassic2 chat generative model.
* Java {@link ModelCall} for the Bedrock Jurassic2 chat generative model.
*
* @author Ahmed Yousri
* @since 1.0.0
*/
public class BedrockAi21Jurassic2ChatClient implements ChatClient {
public class BedrockAi21Jurassic2ModelCall implements ModelCall {
private final Ai21Jurassic2ChatBedrockApi chatApi;
private final BedrockAi21Jurassic2ChatOptions defaultOptions;
public BedrockAi21Jurassic2ChatClient(Ai21Jurassic2ChatBedrockApi chatApi,
BedrockAi21Jurassic2ChatOptions options) {
public BedrockAi21Jurassic2ModelCall(Ai21Jurassic2ChatBedrockApi chatApi, BedrockAi21Jurassic2ChatOptions options) {
Assert.notNull(chatApi, "Ai21Jurassic2ChatBedrockApi must not be null");
Assert.notNull(options, "BedrockAi21Jurassic2ChatOptions must not be null");
@@ -49,7 +48,7 @@ public class BedrockAi21Jurassic2ChatClient implements ChatClient {
this.defaultOptions = options;
}
public BedrockAi21Jurassic2ChatClient(Ai21Jurassic2ChatBedrockApi chatApi) {
public BedrockAi21Jurassic2ModelCall(Ai21Jurassic2ChatBedrockApi chatApi) {
this(chatApi,
BedrockAi21Jurassic2ChatOptions.builder()
.withTemperature(0.8f)
@@ -114,8 +113,8 @@ public class BedrockAi21Jurassic2ChatClient implements ChatClient {
return this;
}
public BedrockAi21Jurassic2ChatClient build() {
return new BedrockAi21Jurassic2ChatClient(chatApi,
public BedrockAi21Jurassic2ModelCall build() {
return new BedrockAi21Jurassic2ModelCall(chatApi,
options != null ? options : BedrockAi21Jurassic2ChatOptions.builder().build());
}

View File

@@ -23,7 +23,7 @@ import org.springframework.ai.bedrock.MessageToPromptConverter;
import org.springframework.ai.bedrock.llama.api.LlamaChatBedrockApi;
import org.springframework.ai.bedrock.llama.api.LlamaChatBedrockApi.LlamaChatRequest;
import org.springframework.ai.bedrock.llama.api.LlamaChatBedrockApi.LlamaChatResponse;
import org.springframework.ai.chat.ChatClient;
import org.springframework.ai.chat.ModelCall;
import org.springframework.ai.chat.prompt.ChatOptions;
import org.springframework.ai.chat.ChatResponse;
import org.springframework.ai.chat.Generation;
@@ -35,25 +35,25 @@ import org.springframework.ai.model.ModelOptionsUtils;
import org.springframework.util.Assert;
/**
* Java {@link ChatClient} and {@link StreamingChatClient} for the Bedrock Llama chat
* Java {@link ModelCall} and {@link StreamingChatClient} for the Bedrock Llama chat
* generative.
*
* @author Christian Tzolov
* @author Wei Jiang
* @since 0.8.0
*/
public class BedrockLlamaChatClient implements ChatClient, StreamingChatClient {
public class BedrockLlamaModelCall implements ModelCall, StreamingChatClient {
private final LlamaChatBedrockApi chatApi;
private final BedrockLlamaChatOptions defaultOptions;
public BedrockLlamaChatClient(LlamaChatBedrockApi chatApi) {
public BedrockLlamaModelCall(LlamaChatBedrockApi chatApi) {
this(chatApi,
BedrockLlamaChatOptions.builder().withTemperature(0.8f).withTopP(0.9f).withMaxGenLen(100).build());
}
public BedrockLlamaChatClient(LlamaChatBedrockApi chatApi, BedrockLlamaChatOptions options) {
public BedrockLlamaModelCall(LlamaChatBedrockApi chatApi, BedrockLlamaChatOptions options) {
Assert.notNull(chatApi, "LlamaChatBedrockApi must not be null");
Assert.notNull(options, "BedrockLlamaChatOptions must not be null");

View File

@@ -24,7 +24,7 @@ import org.springframework.ai.bedrock.titan.api.TitanChatBedrockApi;
import org.springframework.ai.bedrock.titan.api.TitanChatBedrockApi.TitanChatRequest;
import org.springframework.ai.bedrock.titan.api.TitanChatBedrockApi.TitanChatResponse;
import org.springframework.ai.bedrock.titan.api.TitanChatBedrockApi.TitanChatResponseChunk;
import org.springframework.ai.chat.ChatClient;
import org.springframework.ai.chat.ModelCall;
import org.springframework.ai.chat.prompt.ChatOptions;
import org.springframework.ai.chat.ChatResponse;
import org.springframework.ai.chat.Generation;
@@ -39,17 +39,17 @@ import org.springframework.util.Assert;
* @author Christian Tzolov
* @since 0.8.0
*/
public class BedrockTitanChatClient implements ChatClient, StreamingChatClient {
public class BedrockTitanModelCall implements ModelCall, StreamingChatClient {
private final TitanChatBedrockApi chatApi;
private final BedrockTitanChatOptions defaultOptions;
public BedrockTitanChatClient(TitanChatBedrockApi chatApi) {
public BedrockTitanModelCall(TitanChatBedrockApi chatApi) {
this(chatApi, BedrockTitanChatOptions.builder().withTemperature(0.8f).build());
}
public BedrockTitanChatClient(TitanChatBedrockApi chatApi, BedrockTitanChatOptions defaultOptions) {
public BedrockTitanModelCall(TitanChatBedrockApi chatApi, BedrockTitanChatOptions defaultOptions) {
Assert.notNull(chatApi, "ChatApi must not be null");
Assert.notNull(defaultOptions, "DefaultOptions must not be null");
this.chatApi = chatApi;

View File

@@ -38,7 +38,7 @@ public class BedrockAnthropicCreateRequestTests {
@Test
public void createRequestWithChatOptions() {
var client = new BedrockAnthropicChatClient(anthropicChatApi,
var client = new BedrockAnthropicModelCall(anthropicChatApi,
AnthropicChatOptions.builder()
.withTemperature(66.6f)
.withTopK(66)

View File

@@ -55,12 +55,12 @@ import static org.assertj.core.api.Assertions.assertThat;
@SpringBootTest
@EnabledIfEnvironmentVariable(named = "AWS_ACCESS_KEY_ID", matches = ".*")
@EnabledIfEnvironmentVariable(named = "AWS_SECRET_ACCESS_KEY", matches = ".*")
class BedrockAnthropicChatClientIT {
class BedrockAnthropicModelCallIT {
private static final Logger logger = LoggerFactory.getLogger(BedrockAnthropicChatClientIT.class);
private static final Logger logger = LoggerFactory.getLogger(BedrockAnthropicModelCallIT.class);
@Autowired
private BedrockAnthropicChatClient client;
private BedrockAnthropicModelCall client;
@Value("classpath:/prompts/system-message.st")
private Resource systemResource;
@@ -209,8 +209,8 @@ class BedrockAnthropicChatClientIT {
}
@Bean
public BedrockAnthropicChatClient anthropicChatClient(AnthropicChatBedrockApi anthropicApi) {
return new BedrockAnthropicChatClient(anthropicApi);
public BedrockAnthropicModelCall anthropicChatClient(AnthropicChatBedrockApi anthropicApi) {
return new BedrockAnthropicModelCall(anthropicApi);
}
}

View File

@@ -37,7 +37,7 @@ public class BedrockAnthropic3CreateRequestTests {
@Test
public void createRequestWithChatOptions() {
var client = new BedrockAnthropic3ChatClient(anthropicChatApi,
var client = new BedrockAnthropic3ModelCall(anthropicChatApi,
Anthropic3ChatOptions.builder()
.withTemperature(66.6f)
.withTopK(66)

View File

@@ -59,12 +59,12 @@ import static org.assertj.core.api.Assertions.assertThat;
@SpringBootTest
@EnabledIfEnvironmentVariable(named = "AWS_ACCESS_KEY_ID", matches = ".*")
@EnabledIfEnvironmentVariable(named = "AWS_SECRET_ACCESS_KEY", matches = ".*")
class BedrockAnthropic3ChatClientIT {
class BedrockAnthropic3ModelCallIT {
private static final Logger logger = LoggerFactory.getLogger(BedrockAnthropic3ChatClientIT.class);
private static final Logger logger = LoggerFactory.getLogger(BedrockAnthropic3ModelCallIT.class);
@Autowired
private BedrockAnthropic3ChatClient client;
private BedrockAnthropic3ModelCall client;
@Value("classpath:/prompts/system-message.st")
private Resource systemResource;
@@ -228,8 +228,8 @@ class BedrockAnthropic3ChatClientIT {
}
@Bean
public BedrockAnthropic3ChatClient anthropicChatClient(Anthropic3ChatBedrockApi anthropicApi) {
return new BedrockAnthropic3ChatClient(anthropicApi);
public BedrockAnthropic3ModelCall anthropicChatClient(Anthropic3ChatBedrockApi anthropicApi) {
return new BedrockAnthropic3ModelCall(anthropicApi);
}
}

View File

@@ -45,7 +45,7 @@ public class BedrockCohereChatCreateRequestTests {
@Test
public void createRequestWithChatOptions() {
var client = new BedrockCohereChatClient(chatApi,
var client = new BedrockCohereModelCall(chatApi,
BedrockCohereChatOptions.builder()
.withTemperature(66.6f)
.withTopK(66)

View File

@@ -54,10 +54,10 @@ import static org.assertj.core.api.Assertions.assertThat;
@SpringBootTest
@EnabledIfEnvironmentVariable(named = "AWS_ACCESS_KEY_ID", matches = ".*")
@EnabledIfEnvironmentVariable(named = "AWS_SECRET_ACCESS_KEY", matches = ".*")
class BedrockCohereChatClientIT {
class BedrockCohereModelCallIT {
@Autowired
private BedrockCohereChatClient client;
private BedrockCohereModelCall client;
@Value("classpath:/prompts/system-message.st")
private Resource systemResource;
@@ -205,8 +205,8 @@ class BedrockCohereChatClientIT {
}
@Bean
public BedrockCohereChatClient cohereChatClient(CohereChatBedrockApi cohereApi) {
return new BedrockCohereChatClient(cohereApi);
public BedrockCohereModelCall cohereChatClient(CohereChatBedrockApi cohereApi) {
return new BedrockCohereModelCall(cohereApi);
}
}

View File

@@ -49,10 +49,10 @@ import static org.assertj.core.api.Assertions.assertThat;
@SpringBootTest
@EnabledIfEnvironmentVariable(named = "AWS_ACCESS_KEY_ID", matches = ".*")
@EnabledIfEnvironmentVariable(named = "AWS_SECRET_ACCESS_KEY", matches = ".*")
class BedrockAi21Jurassic2ChatClientIT {
class BedrockAi21Jurassic2ModelCallIT {
@Autowired
private BedrockAi21Jurassic2ChatClient client;
private BedrockAi21Jurassic2ModelCall client;
@Value("classpath:/prompts/system-message.st")
private Resource systemResource;
@@ -152,9 +152,9 @@ class BedrockAi21Jurassic2ChatClientIT {
}
@Bean
public BedrockAi21Jurassic2ChatClient bedrockAi21Jurassic2ChatClient(
public BedrockAi21Jurassic2ModelCall bedrockAi21Jurassic2ChatClient(
Ai21Jurassic2ChatBedrockApi jurassic2ChatBedrockApi) {
return new BedrockAi21Jurassic2ChatClient(jurassic2ChatBedrockApi,
return new BedrockAi21Jurassic2ModelCall(jurassic2ChatBedrockApi,
BedrockAi21Jurassic2ChatOptions.builder()
.withTemperature(0.5f)
.withMaxTokens(100)

View File

@@ -45,7 +45,7 @@ public class BedrockLlamaCreateRequestTests {
@Test
public void createRequestWithChatOptions() {
var client = new BedrockLlamaChatClient(api,
var client = new BedrockLlamaModelCall(api,
BedrockLlamaChatOptions.builder().withTemperature(66.6f).withMaxGenLen(666).withTopP(0.66f).build());
var request = client.createRequest(new Prompt("Test message content"));

View File

@@ -54,10 +54,10 @@ import static org.assertj.core.api.Assertions.assertThat;
@SpringBootTest
@EnabledIfEnvironmentVariable(named = "AWS_ACCESS_KEY_ID", matches = ".*")
@EnabledIfEnvironmentVariable(named = "AWS_SECRET_ACCESS_KEY", matches = ".*")
class BedrockLlamaChatClientIT {
class BedrockLlamaModelCallIT {
@Autowired
private BedrockLlamaChatClient client;
private BedrockLlamaModelCall client;
@Value("classpath:/prompts/system-message.st")
private Resource systemResource;
@@ -206,8 +206,8 @@ class BedrockLlamaChatClientIT {
}
@Bean
public BedrockLlamaChatClient llamaChatClient(LlamaChatBedrockApi llamaApi) {
return new BedrockLlamaChatClient(llamaApi,
public BedrockLlamaModelCall llamaChatClient(LlamaChatBedrockApi llamaApi) {
return new BedrockLlamaModelCall(llamaApi,
BedrockLlamaChatOptions.builder().withTemperature(0.5f).withMaxGenLen(100).withTopP(0.9f).build());
}

View File

@@ -41,7 +41,7 @@ public class BedrockTitanChatCreateRequestTests {
@Test
public void createRequestWithChatOptions() {
var client = new BedrockTitanChatClient(api,
var client = new BedrockTitanModelCall(api,
BedrockTitanChatOptions.builder()
.withTemperature(66.6f)
.withTopP(0.66f)

View File

@@ -55,10 +55,10 @@ import static org.assertj.core.api.Assertions.assertThat;
@SpringBootTest
@EnabledIfEnvironmentVariable(named = "AWS_ACCESS_KEY_ID", matches = ".*")
@EnabledIfEnvironmentVariable(named = "AWS_SECRET_ACCESS_KEY", matches = ".*")
class BedrockTitanChatClientIT {
class BedrockTitanModelCallIT {
@Autowired
private BedrockTitanChatClient client;
private BedrockTitanModelCall client;
@Value("classpath:/prompts/system-message.st")
private Resource systemResource;
@@ -211,8 +211,8 @@ class BedrockTitanChatClientIT {
}
@Bean
public BedrockTitanChatClient titanChatClient(TitanChatBedrockApi titanApi) {
return new BedrockTitanChatClient(titanApi);
public BedrockTitanModelCall titanChatClient(TitanChatBedrockApi titanApi) {
return new BedrockTitanModelCall(titanApi);
}
}

View File

@@ -22,7 +22,7 @@ import java.util.Map;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.ai.chat.ChatClient;
import org.springframework.ai.chat.ModelCall;
import org.springframework.ai.chat.ChatResponse;
import org.springframework.ai.chat.Generation;
import org.springframework.ai.huggingface.api.TextGenerationInferenceApi;
@@ -34,12 +34,12 @@ import org.springframework.ai.huggingface.model.GenerateResponse;
import org.springframework.ai.chat.prompt.Prompt;
/**
* An implementation of {@link ChatClient} that interfaces with HuggingFace Inference
* An implementation of {@link ModelCall} that interfaces with HuggingFace Inference
* Endpoints for text generation.
*
* @author Mark Pollack
*/
public class HuggingfaceChatClient implements ChatClient {
public class HuggingfaceModelCall implements ModelCall {
/**
* Token required for authenticating with the HuggingFace Inference API.
@@ -68,11 +68,11 @@ public class HuggingfaceChatClient implements ChatClient {
private int maxNewTokens = 1000;
/**
* Constructs a new HuggingfaceChatClient with the specified API token and base path.
* Constructs a new HuggingfaceModelCall with the specified API token and base path.
* @param apiToken The API token for HuggingFace.
* @param basePath The base path for API requests.
*/
public HuggingfaceChatClient(final String apiToken, String basePath) {
public HuggingfaceModelCall(final String apiToken, String basePath) {
this.apiToken = apiToken;
this.apiClient.setBasePath(basePath);
this.apiClient.addDefaultHeader("Authorization", "Bearer " + this.apiToken);

View File

@@ -23,7 +23,7 @@ import org.springframework.util.StringUtils;
public class HuggingfaceTestConfiguration {
@Bean
public HuggingfaceChatClient huggingfaceChatClient() {
public HuggingfaceModelCall huggingfaceChatClient() {
String apiKey = System.getenv("HUGGINGFACE_API_KEY");
if (!StringUtils.hasText(apiKey)) {
throw new IllegalArgumentException(
@@ -31,7 +31,7 @@ public class HuggingfaceTestConfiguration {
}
// Created aws-mistral-7b-instruct-v0-1-805 via
// https://ui.endpoints.huggingface.co/
HuggingfaceChatClient huggingfaceChatClient = new HuggingfaceChatClient(apiKey,
HuggingfaceModelCall huggingfaceChatClient = new HuggingfaceModelCall(apiKey,
"https://f6hg7b3cvlmntp5i.us-east-1.aws.endpoints.huggingface.cloud");
return huggingfaceChatClient;
}

View File

@@ -20,7 +20,7 @@ import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable;
import org.springframework.ai.chat.ChatResponse;
import org.springframework.ai.huggingface.HuggingfaceChatClient;
import org.springframework.ai.huggingface.HuggingfaceModelCall;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@@ -33,7 +33,7 @@ import static org.assertj.core.api.Assertions.assertThat;
public class ClientIT {
@Autowired
protected HuggingfaceChatClient huggingfaceChatClient;
protected HuggingfaceModelCall huggingfaceChatClient;
@Test
void helloWorldCompletion() {

View File

@@ -101,11 +101,11 @@ public class MistralAiChatOptions implements FunctionCallingOptions, ChatOptions
private @JsonProperty("tool_choice") ToolChoice toolChoice;
/**
* MistralAI Tool Function Callbacks to register with the ChatClient. For Prompt
* MistralAI Tool Function Callbacks to register with the ModelCall. For Prompt
* Options the functionCallbacks are automatically enabled for the duration of the
* prompt execution. For Default Options the functionCallbacks are registered but
* disabled by default. Use the enableFunctions to set the functions from the registry
* to be used by the ChatClient chat completion requests.
* to be used by the ModelCall chat completion requests.
*/
@NestedConfigurationProperty
@JsonIgnore

View File

@@ -17,7 +17,7 @@ package org.springframework.ai.mistralai;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ai.chat.ChatClient;
import org.springframework.ai.chat.ModelCall;
import org.springframework.ai.chat.ChatResponse;
import org.springframework.ai.chat.Generation;
import org.springframework.ai.chat.StreamingChatClient;
@@ -55,9 +55,9 @@ import java.util.concurrent.ConcurrentHashMap;
* @author Grogdunn
* @since 0.8.1
*/
public class MistralAiChatClient extends
public class MistralAiModelCall extends
AbstractFunctionCallSupport<MistralAiApi.ChatCompletionMessage, MistralAiApi.ChatCompletionRequest, ResponseEntity<MistralAiApi.ChatCompletion>>
implements ChatClient, StreamingChatClient {
implements ModelCall, StreamingChatClient {
private final Logger log = LoggerFactory.getLogger(getClass());
@@ -73,7 +73,7 @@ public class MistralAiChatClient extends
private final RetryTemplate retryTemplate;
public MistralAiChatClient(MistralAiApi mistralAiApi) {
public MistralAiModelCall(MistralAiApi mistralAiApi) {
this(mistralAiApi,
MistralAiChatOptions.builder()
.withTemperature(0.7f)
@@ -83,11 +83,11 @@ public class MistralAiChatClient extends
.build());
}
public MistralAiChatClient(MistralAiApi mistralAiApi, MistralAiChatOptions options) {
public MistralAiModelCall(MistralAiApi mistralAiApi, MistralAiChatOptions options) {
this(mistralAiApi, options, null, RetryUtils.DEFAULT_RETRY_TEMPLATE);
}
public MistralAiChatClient(MistralAiApi mistralAiApi, MistralAiChatOptions options,
public MistralAiModelCall(MistralAiApi mistralAiApi, MistralAiChatOptions options,
FunctionCallbackContext functionCallbackContext, RetryTemplate retryTemplate) {
super(functionCallbackContext);
Assert.notNull(mistralAiApi, "MistralAiApi must not be null");

View File

@@ -32,7 +32,7 @@ import static org.assertj.core.api.Assertions.assertThat;
@EnabledIfEnvironmentVariable(named = "MISTRAL_AI_API_KEY", matches = ".+")
public class MistralAiChatCompletionRequestTest {
MistralAiChatClient chatClient = new MistralAiChatClient(new MistralAiApi("test"));
MistralAiModelCall chatClient = new MistralAiModelCall(new MistralAiApi("test"));
@Test
void chatCompletionDefaultRequestTest() {

View File

@@ -27,7 +27,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import reactor.core.publisher.Flux;
import org.springframework.ai.chat.ChatClient;
import org.springframework.ai.chat.ModelCall;
import org.springframework.ai.chat.ChatResponse;
import org.springframework.ai.chat.Generation;
import org.springframework.ai.chat.StreamingChatClient;
@@ -56,12 +56,12 @@ import static org.assertj.core.api.Assertions.assertThat;
*/
@SpringBootTest(classes = MistralAiTestConfiguration.class)
@EnabledIfEnvironmentVariable(named = "MISTRAL_AI_API_KEY", matches = ".+")
class MistralAiChatClientIT {
class MistralAiModelCallIT {
private static final Logger logger = LoggerFactory.getLogger(MistralAiChatClientIT.class);
private static final Logger logger = LoggerFactory.getLogger(MistralAiModelCallIT.class);
@Autowired
protected ChatClient chatClient;
protected ModelCall modelCall;
@Autowired
protected StreamingChatClient streamingChatClient;
@@ -90,7 +90,7 @@ class MistralAiChatClientIT {
// NOTE: Mistral expects the system message to be before the user message or will
// fail with 400 error.
Prompt prompt = new Prompt(List.of(systemMessage, userMessage));
ChatResponse response = chatClient.call(prompt);
ChatResponse response = modelCall.call(prompt);
assertThat(response.getResults()).hasSize(1);
assertThat(response.getResults().get(0).getOutput().getContent()).contains("Blackbeard");
}
@@ -108,7 +108,7 @@ class MistralAiChatClientIT {
PromptTemplate promptTemplate = new PromptTemplate(template,
Map.of("subject", "ice cream flavors", "format", format));
Prompt prompt = new Prompt(promptTemplate.createMessage());
Generation generation = this.chatClient.call(prompt).getResult();
Generation generation = this.modelCall.call(prompt).getResult();
List<String> list = outputConverter.convert(generation.getOutput().getContent());
assertThat(list).hasSize(5);
@@ -126,7 +126,7 @@ class MistralAiChatClientIT {
PromptTemplate promptTemplate = new PromptTemplate(template,
Map.of("subject", "an array of numbers from 1 to 9 under they key name 'numbers'", "format", format));
Prompt prompt = new Prompt(promptTemplate.createMessage());
Generation generation = chatClient.call(prompt).getResult();
Generation generation = modelCall.call(prompt).getResult();
Map<String, Object> result = outputConverter.convert(generation.getOutput().getContent());
assertThat(result.get("numbers")).isEqualTo(Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9));
@@ -148,7 +148,7 @@ class MistralAiChatClientIT {
""";
PromptTemplate promptTemplate = new PromptTemplate(template, Map.of("format", format));
Prompt prompt = new Prompt(promptTemplate.createMessage());
Generation generation = chatClient.call(prompt).getResult();
Generation generation = modelCall.call(prompt).getResult();
ActorsFilmsRecord actorsFilms = outputConverter.convert(generation.getOutput().getContent());
logger.info("" + actorsFilms);
@@ -201,7 +201,7 @@ class MistralAiChatClientIT {
.build()))
.build();
ChatResponse response = chatClient.call(new Prompt(messages, promptOptions));
ChatResponse response = modelCall.call(new Prompt(messages, promptOptions));
logger.info("Response: {}", response);

View File

@@ -82,7 +82,7 @@ public class MistralAiRetryTests {
private @Mock MistralAiApi mistralAiApi;
private MistralAiChatClient chatClient;
private MistralAiModelCall chatClient;
private MistralAiEmbeddingClient embeddingClient;
@@ -92,7 +92,7 @@ public class MistralAiRetryTests {
retryListener = new TestRetryListener();
retryTemplate.registerListener(retryListener);
chatClient = new MistralAiChatClient(mistralAiApi,
chatClient = new MistralAiModelCall(mistralAiApi,
MistralAiChatOptions.builder()
.withTemperature(0.7f)
.withTopP(1f)

View File

@@ -41,8 +41,8 @@ public class MistralAiTestConfiguration {
}
@Bean
public MistralAiChatClient mistralAiChatClient(MistralAiApi mistralAiApi) {
return new MistralAiChatClient(mistralAiApi,
public MistralAiModelCall mistralAiChatClient(MistralAiApi mistralAiApi) {
return new MistralAiModelCall(mistralAiApi,
MistralAiChatOptions.builder().withModel(MistralAiApi.ChatModel.MIXTRAL.getValue()).build());
}

View File

@@ -18,10 +18,10 @@ package org.springframework.ai.ollama;
import java.util.Base64;
import java.util.List;
import org.springframework.ai.chat.ModelCall;
import org.springframework.ai.ollama.metadata.OllamaChatResponseMetadata;
import reactor.core.publisher.Flux;
import org.springframework.ai.chat.ChatClient;
import org.springframework.ai.chat.ChatResponse;
import org.springframework.ai.chat.Generation;
import org.springframework.ai.chat.StreamingChatClient;
@@ -39,7 +39,7 @@ import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
/**
* {@link ChatClient} implementation for {@literal Ollama}.
* {@link ModelCall} implementation for {@literal Ollama}.
*
* Ollama allows developers to run large language models and generate embeddings locally.
* It supports open-source models available on [Ollama AI
@@ -52,7 +52,7 @@ import org.springframework.util.StringUtils;
* @author Christian Tzolov
* @since 0.8.0
*/
public class OllamaChatClient implements ChatClient, StreamingChatClient {
public class OllamaModelCall implements ModelCall, StreamingChatClient {
/**
* Low-level Ollama API library.
@@ -64,11 +64,11 @@ public class OllamaChatClient implements ChatClient, StreamingChatClient {
*/
private OllamaOptions defaultOptions;
public OllamaChatClient(OllamaApi chatApi) {
public OllamaModelCall(OllamaApi chatApi) {
this(chatApi, OllamaOptions.create().withModel(OllamaOptions.DEFAULT_MODEL));
}
public OllamaChatClient(OllamaApi chatApi, OllamaOptions defaultOptions) {
public OllamaModelCall(OllamaApi chatApi, OllamaOptions defaultOptions) {
Assert.notNull(chatApi, "OllamaApi must not be null");
Assert.notNull(defaultOptions, "DefaultOptions must not be null");
this.chatApi = chatApi;
@@ -79,7 +79,7 @@ public class OllamaChatClient implements ChatClient, StreamingChatClient {
* @deprecated Use {@link OllamaOptions#setModel} instead.
*/
@Deprecated
public OllamaChatClient withModel(String model) {
public OllamaModelCall withModel(String model) {
this.defaultOptions.setModel(model);
return this;
}
@@ -88,7 +88,7 @@ public class OllamaChatClient implements ChatClient, StreamingChatClient {
* @deprecated Use {@link OllamaOptions} constructor instead.
*/
@Deprecated
public OllamaChatClient withDefaultOptions(OllamaOptions options) {
public OllamaModelCall withDefaultOptions(OllamaOptions options) {
this.defaultOptions = options;
return this;
}

View File

@@ -30,7 +30,7 @@ import static org.assertj.core.api.Assertions.assertThat;
*/
public class OllamaChatRequestTests {
OllamaChatClient client = new OllamaChatClient(new OllamaApi(),
OllamaModelCall client = new OllamaModelCall(new OllamaApi(),
new OllamaOptions().withModel("MODEL_NAME").withTopK(99).withTemperature(66.6f).withNumGPU(1));
@Test
@@ -105,7 +105,7 @@ public class OllamaChatRequestTests {
@Test
public void createRequestWithDefaultOptionsModelOverride() {
OllamaChatClient client2 = new OllamaChatClient(new OllamaApi(),
OllamaModelCall client2 = new OllamaModelCall(new OllamaApi(),
new OllamaOptions().withModel("DEFAULT_OPTIONS_MODEL"));
var request = client2.ollamaChatRequest(new Prompt("Test message content"), true);

View File

@@ -56,11 +56,11 @@ import static org.assertj.core.api.Assertions.assertThat;
@SpringBootTest
@Testcontainers
@Disabled("For manual smoke testing only.")
class OllamaChatClientIT {
class OllamaModelCallIT {
private static String MODEL = "mistral";
private static final Log logger = LogFactory.getLog(OllamaChatClientIT.class);
private static final Log logger = LogFactory.getLog(OllamaModelCallIT.class);
@Container
static OllamaContainer ollamaContainer = new OllamaContainer("ollama/ollama:0.1.32");
@@ -77,7 +77,7 @@ class OllamaChatClientIT {
}
@Autowired
private OllamaChatClient client;
private OllamaModelCall client;
@Test
void roleTest() {
@@ -219,8 +219,8 @@ class OllamaChatClientIT {
}
@Bean
public OllamaChatClient ollamaChat(OllamaApi ollamaApi) {
return new OllamaChatClient(ollamaApi, OllamaOptions.create().withModel(MODEL).withTemperature(0.9f));
public OllamaModelCall ollamaChat(OllamaApi ollamaApi) {
return new OllamaModelCall(ollamaApi, OllamaOptions.create().withModel(MODEL).withTemperature(0.9f));
}
}

View File

@@ -44,11 +44,11 @@ import static org.assertj.core.api.Assertions.assertThat;
@SpringBootTest
@Testcontainers
@Disabled("For manual smoke testing only.")
class OllamaChatClientMultimodalIT {
class OllamaModelCallMultimodalIT {
private static String MODEL = "llava";
private static final Log logger = LogFactory.getLog(OllamaChatClientIT.class);
private static final Log logger = LogFactory.getLog(OllamaModelCallIT.class);
@Container
static OllamaContainer ollamaContainer = new OllamaContainer("ollama/ollama:0.1.32");
@@ -65,7 +65,7 @@ class OllamaChatClientMultimodalIT {
}
@Autowired
private OllamaChatClient client;
private OllamaModelCall client;
@Test
void multiModalityTest() throws IOException {
@@ -90,8 +90,8 @@ class OllamaChatClientMultimodalIT {
}
@Bean
public OllamaChatClient ollamaChat(OllamaApi ollamaApi) {
return new OllamaChatClient(ollamaApi, OllamaOptions.create().withModel(MODEL).withTemperature(0.9f));
public OllamaModelCall ollamaChat(OllamaApi ollamaApi) {
return new OllamaModelCall(ollamaApi, OllamaOptions.create().withModel(MODEL).withTemperature(0.9f));
}
}

View File

@@ -134,10 +134,10 @@ public class OpenAiChatOptions implements FunctionCallingOptions, ChatOptions {
private @JsonProperty("user") String user;
/**
* OpenAI Tool Function Callbacks to register with the ChatClient.
* OpenAI Tool Function Callbacks to register with the ModelCall.
* For Prompt Options the functionCallbacks are automatically enabled for the duration of the prompt execution.
* For Default Options the functionCallbacks are registered but disabled by default. Use the enableFunctions to set the functions
* from the registry to be used by the ChatClient chat completion requests.
* from the registry to be used by the ModelCall chat completion requests.
*/
@NestedConfigurationProperty
@JsonIgnore

View File

@@ -17,7 +17,7 @@ package org.springframework.ai.openai;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ai.chat.ChatClient;
import org.springframework.ai.chat.ModelCall;
import org.springframework.ai.chat.ChatResponse;
import org.springframework.ai.chat.Generation;
import org.springframework.ai.chat.StreamingChatClient;
@@ -58,7 +58,7 @@ import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
/**
* {@link ChatClient} and {@link StreamingChatClient} implementation for {@literal OpenAI}
* {@link ModelCall} and {@link StreamingChatClient} implementation for {@literal OpenAI}
* backed by {@link OpenAiApi}.
*
* @author Mark Pollack
@@ -68,15 +68,15 @@ import java.util.concurrent.ConcurrentHashMap;
* @author Josh Long
* @author Jemin Huh
* @author Grogdunn
* @see ChatClient
* @see ModelCall
* @see StreamingChatClient
* @see OpenAiApi
*/
public class OpenAiChatClient extends
public class OpenAiModelCall extends
AbstractFunctionCallSupport<ChatCompletionMessage, OpenAiApi.ChatCompletionRequest, ResponseEntity<ChatCompletion>>
implements ChatClient, StreamingChatClient {
implements ModelCall, StreamingChatClient {
private static final Logger logger = LoggerFactory.getLogger(OpenAiChatClient.class);
private static final Logger logger = LoggerFactory.getLogger(OpenAiModelCall.class);
/**
* The default options used for the chat completion requests.
@@ -94,35 +94,35 @@ public class OpenAiChatClient extends
private final OpenAiApi openAiApi;
/**
* Creates an instance of the OpenAiChatClient.
* Creates an instance of the OpenAiModelCall.
* @param openAiApi The OpenAiApi instance to be used for interacting with the OpenAI
* Chat API.
* @throws IllegalArgumentException if openAiApi is null
*/
public OpenAiChatClient(OpenAiApi openAiApi) {
public OpenAiModelCall(OpenAiApi openAiApi) {
this(openAiApi,
OpenAiChatOptions.builder().withModel(OpenAiApi.DEFAULT_CHAT_MODEL).withTemperature(0.7f).build());
}
/**
* Initializes an instance of the OpenAiChatClient.
* Initializes an instance of the OpenAiModelCall.
* @param openAiApi The OpenAiApi instance to be used for interacting with the OpenAI
* Chat API.
* @param options The OpenAiChatOptions to configure the chat client.
*/
public OpenAiChatClient(OpenAiApi openAiApi, OpenAiChatOptions options) {
public OpenAiModelCall(OpenAiApi openAiApi, OpenAiChatOptions options) {
this(openAiApi, options, null, RetryUtils.DEFAULT_RETRY_TEMPLATE);
}
/**
* Initializes a new instance of the OpenAiChatClient.
* Initializes a new instance of the OpenAiModelCall.
* @param openAiApi The OpenAiApi instance to be used for interacting with the OpenAI
* Chat API.
* @param options The OpenAiChatOptions to configure the chat client.
* @param functionCallbackContext The function callback context.
* @param retryTemplate The retry template.
*/
public OpenAiChatClient(OpenAiApi openAiApi, OpenAiChatOptions options,
public OpenAiModelCall(OpenAiApi openAiApi, OpenAiChatOptions options,
FunctionCallbackContext functionCallbackContext, RetryTemplate retryTemplate) {
super(functionCallbackContext);
Assert.notNull(openAiApi, "OpenAiApi must not be null");

View File

@@ -34,7 +34,7 @@ public class ChatCompletionRequestTests {
@Test
public void createRequestWithChatOptions() {
var client = new OpenAiChatClient(new OpenAiApi("TEST"),
var client = new OpenAiModelCall(new OpenAiApi("TEST"),
OpenAiChatOptions.builder().withModel("DEFAULT_MODEL").withTemperature(66.6f).build());
var request = client.createRequest(new Prompt("Test message content"), false);
@@ -60,7 +60,7 @@ public class ChatCompletionRequestTests {
final String TOOL_FUNCTION_NAME = "CurrentWeather";
var client = new OpenAiChatClient(new OpenAiApi("TEST"),
var client = new OpenAiModelCall(new OpenAiApi("TEST"),
OpenAiChatOptions.builder().withModel("DEFAULT_MODEL").build());
var request = client.createRequest(new Prompt("Test message content",
@@ -90,7 +90,7 @@ public class ChatCompletionRequestTests {
final String TOOL_FUNCTION_NAME = "CurrentWeather";
var client = new OpenAiChatClient(new OpenAiApi("TEST"),
var client = new OpenAiModelCall(new OpenAiApi("TEST"),
OpenAiChatOptions.builder()
.withModel("DEFAULT_MODEL")
.withFunctionCallbacks(List.of(FunctionCallbackWrapper.builder(new MockWeatherService())

View File

@@ -51,8 +51,8 @@ public class OpenAiTestConfiguration {
}
@Bean
public OpenAiChatClient openAiChatClient(OpenAiApi api) {
OpenAiChatClient openAiChatClient = new OpenAiChatClient(api);
public OpenAiModelCall openAiChatClient(OpenAiApi api) {
OpenAiModelCall openAiChatClient = new OpenAiModelCall(api);
return openAiChatClient;
}

View File

@@ -26,8 +26,8 @@ import org.slf4j.LoggerFactory;
import org.springframework.ai.chat.ChatResponse;
import org.springframework.ai.document.Document;
import org.springframework.ai.openai.OpenAiModelCall;
import org.springframework.ai.openai.OpenAiTestConfiguration;
import org.springframework.ai.openai.OpenAiChatClient;
import org.springframework.ai.openai.OpenAiEmbeddingClient;
import org.springframework.ai.openai.testutils.AbstractIT;
import org.springframework.ai.chat.prompt.Prompt;
@@ -61,7 +61,7 @@ public class AcmeIT extends AbstractIT {
private OpenAiEmbeddingClient embeddingClient;
@Autowired
private OpenAiChatClient chatClient;
private OpenAiModelCall chatClient;
@Test
void beanTest() {

View File

@@ -27,7 +27,7 @@ import org.springframework.ai.chat.metadata.PromptMetadata;
import org.springframework.ai.chat.metadata.RateLimit;
import org.springframework.ai.chat.metadata.Usage;
import org.springframework.ai.openai.api.OpenAiApi;
import org.springframework.ai.openai.OpenAiChatClient;
import org.springframework.ai.openai.OpenAiModelCall;
import org.springframework.ai.openai.metadata.support.OpenAiApiResponseHeaders;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.beans.factory.annotation.Autowired;
@@ -57,7 +57,7 @@ public class OpenAiChatClientWithChatResponseMetadataTests {
private static String TEST_API_KEY = "sk-1234567890";
@Autowired
private OpenAiChatClient openAiChatClient;
private OpenAiModelCall openAiChatClient;
@Autowired
private MockRestServiceServer server;
@@ -171,8 +171,8 @@ public class OpenAiChatClientWithChatResponseMetadataTests {
}
@Bean
public OpenAiChatClient openAiClient(OpenAiApi openAiApi) {
return new OpenAiChatClient(openAiApi);
public OpenAiModelCall openAiClient(OpenAiApi openAiApi) {
return new OpenAiModelCall(openAiApi);
}
}

View File

@@ -27,7 +27,7 @@ import org.slf4j.LoggerFactory;
import org.springframework.ai.chat.ChatResponse;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.openai.OpenAiChatClient;
import org.springframework.ai.openai.OpenAiModelCall;
import org.springframework.ai.openai.OpenAiChatOptions;
import org.springframework.ai.openai.api.OpenAiApi;
import org.springframework.ai.openai.api.OpenAiApi.ChatCompletionRequest;
@@ -41,14 +41,14 @@ import static org.assertj.core.api.Assertions.assertThat;
/**
* @author Christian Tzolov
*/
@SpringBootTest(classes = OpenAiChatClient2IT.Config.class)
@SpringBootTest(classes = OpenAiModelCall2IT.Config.class)
@EnabledIfEnvironmentVariable(named = "OPENAI_API_KEY", matches = ".+")
public class OpenAiChatClient2IT {
public class OpenAiModelCall2IT {
private final Logger logger = LoggerFactory.getLogger(getClass());
@Autowired
private OpenAiChatClient openAiChatClient;
private OpenAiModelCall openAiChatClient;
@Test
void responseFormatTest() throws JsonMappingException, JsonProcessingException {
@@ -99,8 +99,8 @@ public class OpenAiChatClient2IT {
}
@Bean
public OpenAiChatClient openAiClient(OpenAiApi openAiApi) {
return new OpenAiChatClient(openAiApi);
public OpenAiModelCall openAiClient(OpenAiApi openAiApi) {
return new OpenAiModelCall(openAiApi);
}
}

View File

@@ -60,9 +60,9 @@ import static org.assertj.core.api.Assertions.assertThat;
@SpringBootTest(classes = OpenAiTestConfiguration.class)
@EnabledIfEnvironmentVariable(named = "OPENAI_API_KEY", matches = ".+")
class OpenAiChatClientIT extends AbstractIT {
class OpenAiModelCallIT extends AbstractIT {
private static final Logger logger = LoggerFactory.getLogger(OpenAiChatClientIT.class);
private static final Logger logger = LoggerFactory.getLogger(OpenAiModelCallIT.class);
@Value("classpath:/prompts/system-message.st")
private Resource systemResource;
@@ -74,7 +74,7 @@ class OpenAiChatClientIT extends AbstractIT {
SystemPromptTemplate systemPromptTemplate = new SystemPromptTemplate(systemResource);
Message systemMessage = systemPromptTemplate.createMessage(Map.of("name", "Bob", "voice", "pirate"));
Prompt prompt = new Prompt(List.of(userMessage, systemMessage));
ChatResponse response = chatClient.call(prompt);
ChatResponse response = modelCall.call(prompt);
assertThat(response.getResults()).hasSize(1);
assertThat(response.getResults().get(0).getOutput().getContent()).contains("Blackbeard");
// needs fine tuning... evaluateQuestionAndAnswer(request, response, false);
@@ -93,7 +93,7 @@ class OpenAiChatClientIT extends AbstractIT {
PromptTemplate promptTemplate = new PromptTemplate(template,
Map.of("subject", "ice cream flavors", "format", format));
Prompt prompt = new Prompt(promptTemplate.createMessage());
Generation generation = this.chatClient.call(prompt).getResult();
Generation generation = this.modelCall.call(prompt).getResult();
List<String> list = outputConverter.convert(generation.getOutput().getContent());
assertThat(list).hasSize(5);
@@ -112,7 +112,7 @@ class OpenAiChatClientIT extends AbstractIT {
PromptTemplate promptTemplate = new PromptTemplate(template,
Map.of("subject", "an array of numbers from 1 to 9 under they key name 'numbers'", "format", format));
Prompt prompt = new Prompt(promptTemplate.createMessage());
Generation generation = chatClient.call(prompt).getResult();
Generation generation = modelCall.call(prompt).getResult();
Map<String, Object> result = outputConverter.convert(generation.getOutput().getContent());
assertThat(result.get("numbers")).isEqualTo(Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9));
@@ -131,7 +131,7 @@ class OpenAiChatClientIT extends AbstractIT {
""";
PromptTemplate promptTemplate = new PromptTemplate(template, Map.of("format", format));
Prompt prompt = new Prompt(promptTemplate.createMessage());
Generation generation = chatClient.call(prompt).getResult();
Generation generation = modelCall.call(prompt).getResult();
ActorsFilms actorsFilms = outputConverter.convert(generation.getOutput().getContent());
}
@@ -151,7 +151,7 @@ class OpenAiChatClientIT extends AbstractIT {
""";
PromptTemplate promptTemplate = new PromptTemplate(template, Map.of("format", format));
Prompt prompt = new Prompt(promptTemplate.createMessage());
Generation generation = chatClient.call(prompt).getResult();
Generation generation = modelCall.call(prompt).getResult();
ActorsFilmsRecord actorsFilms = outputConverter.convert(generation.getOutput().getContent());
logger.info("" + actorsFilms);
@@ -204,7 +204,7 @@ class OpenAiChatClientIT extends AbstractIT {
.build()))
.build();
ChatResponse response = chatClient.call(new Prompt(messages, promptOptions));
ChatResponse response = modelCall.call(new Prompt(messages, promptOptions));
logger.info("Response: {}", response);
@@ -255,7 +255,7 @@ class OpenAiChatClientIT extends AbstractIT {
var userMessage = new UserMessage("Explain what do you see on this picture?",
List.of(new Media(MimeTypeUtils.IMAGE_PNG, imageData)));
var response = chatClient
var response = modelCall
.call(new Prompt(List.of(userMessage), OpenAiChatOptions.builder().withModel(modelName).build()));
logger.info(response.getResult().getOutput().getContent());
@@ -271,7 +271,7 @@ class OpenAiChatClientIT extends AbstractIT {
.of(new Media(MimeTypeUtils.IMAGE_PNG,
new URL("https://docs.spring.io/spring-ai/reference/1.0-SNAPSHOT/_images/multimodal.test.png"))));
ChatResponse response = chatClient
ChatResponse response = modelCall
.call(new Prompt(List.of(userMessage), OpenAiChatOptions.builder().withModel(modelName).build()));
logger.info(response.getResult().getOutput().getContent());

View File

@@ -39,10 +39,10 @@ import static org.assertj.core.api.Assertions.assertThat;
@SpringBootTest(classes = OpenAiTestConfiguration.class)
@EnabledIfEnvironmentVariable(named = "OPENAI_API_KEY", matches = ".+")
class OpenAiChatClientTypeReferenceBeanOutputConverterIT extends AbstractIT {
class OpenAiModelCallTypeReferenceBeanOutputConverterIT extends AbstractIT {
private static final Logger logger = LoggerFactory
.getLogger(OpenAiChatClientTypeReferenceBeanOutputConverterIT.class);
.getLogger(OpenAiModelCallTypeReferenceBeanOutputConverterIT.class);
record ActorsFilmsRecord(String actor, List<String> movies) {
}
@@ -61,7 +61,7 @@ class OpenAiChatClientTypeReferenceBeanOutputConverterIT extends AbstractIT {
""";
PromptTemplate promptTemplate = new PromptTemplate(template, Map.of("format", format));
Prompt prompt = new Prompt(promptTemplate.createMessage());
Generation generation = chatClient.call(prompt).getResult();
Generation generation = modelCall.call(prompt).getResult();
List<ActorsFilmsRecord> actorsFilms = outputConverter.convert(generation.getOutput().getContent());
logger.info("" + actorsFilms);

View File

@@ -31,7 +31,7 @@ import org.springframework.ai.image.ImageMessage;
import org.springframework.ai.image.ImagePrompt;
import org.springframework.ai.openai.OpenAiAudioTranscriptionClient;
import org.springframework.ai.openai.OpenAiAudioTranscriptionOptions;
import org.springframework.ai.openai.OpenAiChatClient;
import org.springframework.ai.openai.OpenAiModelCall;
import org.springframework.ai.openai.OpenAiChatOptions;
import org.springframework.ai.openai.OpenAiEmbeddingClient;
import org.springframework.ai.openai.OpenAiEmbeddingOptions;
@@ -107,7 +107,7 @@ public class OpenAiRetryTests {
private @Mock OpenAiImageApi openAiImageApi;
private OpenAiChatClient chatClient;
private OpenAiModelCall chatClient;
private OpenAiEmbeddingClient embeddingClient;
@@ -121,7 +121,7 @@ public class OpenAiRetryTests {
retryListener = new TestRetryListener();
retryTemplate.registerListener(retryListener);
chatClient = new OpenAiChatClient(openAiApi, OpenAiChatOptions.builder().build(), null, retryTemplate);
chatClient = new OpenAiModelCall(openAiApi, OpenAiChatOptions.builder().build(), null, retryTemplate);
embeddingClient = new OpenAiEmbeddingClient(openAiApi, MetadataMode.EMBED,
OpenAiEmbeddingOptions.builder().build(), retryTemplate);
audioTranscriptionClient = new OpenAiAudioTranscriptionClient(openAiAudioApi,

View File

@@ -36,7 +36,7 @@ import org.springframework.ai.chat.memory.SystemPromptChatMemoryAugmentor;
import org.springframework.ai.embedding.EmbeddingClient;
import org.springframework.ai.evaluation.BaseMemoryTest;
import org.springframework.ai.evaluation.RelevancyEvaluator;
import org.springframework.ai.openai.OpenAiChatClient;
import org.springframework.ai.openai.OpenAiModelCall;
import org.springframework.ai.openai.OpenAiEmbeddingClient;
import org.springframework.ai.openai.api.OpenAiApi;
import org.springframework.ai.tokenizer.JTokkitTokenCountEstimator;
@@ -75,8 +75,8 @@ public class ChatMemoryLongTermSystemPromptIT extends BaseMemoryTest {
}
@Bean
public OpenAiChatClient openAiClient(OpenAiApi openAiApi) {
return new OpenAiChatClient(openAiApi);
public OpenAiModelCall openAiClient(OpenAiApi openAiApi) {
return new OpenAiModelCall(openAiApi);
}
@Bean
@@ -98,7 +98,7 @@ public class ChatMemoryLongTermSystemPromptIT extends BaseMemoryTest {
}
@Bean
public ChatService memoryChatService(OpenAiChatClient chatClient, VectorStore vectorStore,
public ChatService memoryChatService(OpenAiModelCall chatClient, VectorStore vectorStore,
TokenCountEstimator tokenCountEstimator) {
return PromptTransformingChatService.builder(chatClient)
@@ -110,7 +110,7 @@ public class ChatMemoryLongTermSystemPromptIT extends BaseMemoryTest {
}
@Bean
public StreamingChatService memoryStreamingChatService(OpenAiChatClient streamingChatClient,
public StreamingChatService memoryStreamingChatService(OpenAiModelCall streamingChatClient,
VectorStore vectorStore, TokenCountEstimator tokenCountEstimator) {
return StreamingPromptTransformingChatService.builder(streamingChatClient)
@@ -122,7 +122,7 @@ public class ChatMemoryLongTermSystemPromptIT extends BaseMemoryTest {
}
@Bean
public RelevancyEvaluator relevancyEvaluator(OpenAiChatClient chatClient) {
public RelevancyEvaluator relevancyEvaluator(OpenAiModelCall chatClient) {
return new RelevancyEvaluator(chatClient);
}

View File

@@ -31,7 +31,7 @@ import org.springframework.ai.chat.memory.LastMaxTokenSizeContentTransformer;
import org.springframework.ai.chat.memory.MessageChatMemoryAugmentor;
import org.springframework.ai.evaluation.BaseMemoryTest;
import org.springframework.ai.evaluation.RelevancyEvaluator;
import org.springframework.ai.openai.OpenAiChatClient;
import org.springframework.ai.openai.OpenAiModelCall;
import org.springframework.ai.openai.api.OpenAiApi;
import org.springframework.ai.tokenizer.JTokkitTokenCountEstimator;
import org.springframework.ai.tokenizer.TokenCountEstimator;
@@ -59,8 +59,8 @@ public class ChatMemoryShortTermMessageListIT extends BaseMemoryTest {
}
@Bean
public OpenAiChatClient openAiClient(OpenAiApi openAiApi) {
return new OpenAiChatClient(openAiApi);
public OpenAiModelCall openAiClient(OpenAiApi openAiApi) {
return new OpenAiModelCall(openAiApi);
}
@Bean
@@ -74,7 +74,7 @@ public class ChatMemoryShortTermMessageListIT extends BaseMemoryTest {
}
@Bean
public ChatService memoryChatService(OpenAiChatClient chatClient, ChatMemory chatHistory,
public ChatService memoryChatService(OpenAiModelCall chatClient, ChatMemory chatHistory,
TokenCountEstimator tokenCountEstimator) {
return PromptTransformingChatService.builder(chatClient)
@@ -86,7 +86,7 @@ public class ChatMemoryShortTermMessageListIT extends BaseMemoryTest {
}
@Bean
public StreamingChatService memoryStreamingChatService(OpenAiChatClient streamingChatClient,
public StreamingChatService memoryStreamingChatService(OpenAiModelCall streamingChatClient,
ChatMemory chatHistory, TokenCountEstimator tokenCountEstimator) {
return StreamingPromptTransformingChatService.builder(streamingChatClient)
@@ -98,7 +98,7 @@ public class ChatMemoryShortTermMessageListIT extends BaseMemoryTest {
}
@Bean
public RelevancyEvaluator relevancyEvaluator(OpenAiChatClient chatClient) {
public RelevancyEvaluator relevancyEvaluator(OpenAiModelCall chatClient) {
return new RelevancyEvaluator(chatClient);
}

View File

@@ -32,7 +32,7 @@ import org.springframework.ai.chat.memory.LastMaxTokenSizeContentTransformer;
import org.springframework.ai.chat.memory.SystemPromptChatMemoryAugmentor;
import org.springframework.ai.evaluation.BaseMemoryTest;
import org.springframework.ai.evaluation.RelevancyEvaluator;
import org.springframework.ai.openai.OpenAiChatClient;
import org.springframework.ai.openai.OpenAiModelCall;
import org.springframework.ai.openai.api.OpenAiApi;
import org.springframework.ai.tokenizer.JTokkitTokenCountEstimator;
import org.springframework.ai.tokenizer.TokenCountEstimator;
@@ -60,8 +60,8 @@ public class ChatMemoryShortTermSystemPromptIT extends BaseMemoryTest {
}
@Bean
public OpenAiChatClient openAiClient(OpenAiApi openAiApi) {
return new OpenAiChatClient(openAiApi);
public OpenAiModelCall openAiClient(OpenAiApi openAiApi) {
return new OpenAiModelCall(openAiApi);
}
@Bean
@@ -75,7 +75,7 @@ public class ChatMemoryShortTermSystemPromptIT extends BaseMemoryTest {
}
@Bean
public ChatService memoryChatService(OpenAiChatClient chatClient, ChatMemory chatHistory,
public ChatService memoryChatService(OpenAiModelCall chatClient, ChatMemory chatHistory,
TokenCountEstimator tokenCountEstimator) {
return PromptTransformingChatService.builder(chatClient)
@@ -87,7 +87,7 @@ public class ChatMemoryShortTermSystemPromptIT extends BaseMemoryTest {
}
@Bean
public StreamingChatService memoryStreamingChatService(OpenAiChatClient streamingChatClient,
public StreamingChatService memoryStreamingChatService(OpenAiModelCall streamingChatClient,
ChatMemory chatHistory, TokenCountEstimator tokenCountEstimator) {
return StreamingPromptTransformingChatService.builder(streamingChatClient)
@@ -99,7 +99,7 @@ public class ChatMemoryShortTermSystemPromptIT extends BaseMemoryTest {
}
@Bean
public RelevancyEvaluator relevancyEvaluator(OpenAiChatClient chatClient) {
public RelevancyEvaluator relevancyEvaluator(OpenAiModelCall chatClient) {
return new RelevancyEvaluator(chatClient);
}

View File

@@ -30,6 +30,7 @@ import org.springframework.ai.chat.prompt.transformer.ChatServiceContext;
import org.springframework.ai.chat.service.ChatService;
import org.springframework.ai.chat.service.PromptTransformingChatService;
import org.springframework.ai.openai.OpenAiChatOptions;
import org.springframework.ai.openai.OpenAiModelCall;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import org.testcontainers.qdrant.QdrantContainer;
@@ -50,10 +51,8 @@ import org.springframework.ai.chat.prompt.transformer.VectorStoreRetriever;
import org.springframework.ai.document.Document;
import org.springframework.ai.document.DocumentTransformer;
import org.springframework.ai.embedding.EmbeddingClient;
import org.springframework.ai.evaluation.EvaluationRequest;
import org.springframework.ai.evaluation.EvaluationResponse;
import org.springframework.ai.evaluation.RelevancyEvaluator;
import org.springframework.ai.openai.OpenAiChatClient;
import org.springframework.ai.openai.OpenAiEmbeddingClient;
import org.springframework.ai.openai.api.OpenAiApi;
import org.springframework.ai.reader.JsonReader;
@@ -164,8 +163,8 @@ public class LongShortTermChatMemoryWithRagIT {
}
@Bean
public OpenAiChatClient openAiClient(OpenAiApi openAiApi) {
return new OpenAiChatClient(openAiApi);
public OpenAiModelCall openAiClient(OpenAiApi openAiApi) {
return new OpenAiModelCall(openAiApi);
}
@Bean
@@ -187,7 +186,7 @@ public class LongShortTermChatMemoryWithRagIT {
}
@Bean
public ChatService memoryChatService(OpenAiChatClient chatClient, VectorStore vectorStore,
public ChatService memoryChatService(OpenAiModelCall chatClient, VectorStore vectorStore,
TokenCountEstimator tokenCountEstimator, ChatMemory chatHistory) {
return PromptTransformingChatService.builder(chatClient)
@@ -224,7 +223,7 @@ public class LongShortTermChatMemoryWithRagIT {
}
// @Bean
// public StreamingChatService memoryStreamingChatAgent(OpenAiChatClient
// public StreamingChatService memoryStreamingChatAgent(OpenAiModelCall
// streamingChatClient,
// VectorStore vectorStore, TokenCountEstimator tokenCountEstimator, ChatHistory
// chatHistory) {
@@ -241,7 +240,7 @@ public class LongShortTermChatMemoryWithRagIT {
// }
@Bean
public RelevancyEvaluator relevancyEvaluator(OpenAiChatClient chatClient) {
public RelevancyEvaluator relevancyEvaluator(OpenAiModelCall chatClient) {
// Use GPT 4 as a better model for determining relevancy. gpt 3.5 makes basic
// mistakes
OpenAiChatOptions openAiChatOptions = OpenAiChatOptions.builder()

View File

@@ -23,6 +23,7 @@ import io.qdrant.client.QdrantClient;
import io.qdrant.client.QdrantGrpcClient;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable;
import org.springframework.ai.chat.ModelCall;
import org.springframework.ai.chat.service.ChatService;
import org.springframework.ai.chat.prompt.transformer.TransformerContentType;
import org.springframework.ai.document.Document;
@@ -31,7 +32,6 @@ import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import org.testcontainers.qdrant.QdrantContainer;
import org.springframework.ai.chat.ChatClient;
import org.springframework.ai.chat.service.PromptTransformingChatService;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.chat.prompt.Prompt;
@@ -39,10 +39,9 @@ import org.springframework.ai.chat.prompt.transformer.ChatServiceContext;
import org.springframework.ai.chat.prompt.transformer.QuestionContextAugmentor;
import org.springframework.ai.chat.prompt.transformer.VectorStoreRetriever;
import org.springframework.ai.embedding.EmbeddingClient;
import org.springframework.ai.evaluation.EvaluationRequest;
import org.springframework.ai.evaluation.EvaluationResponse;
import org.springframework.ai.evaluation.RelevancyEvaluator;
import org.springframework.ai.openai.OpenAiChatClient;
import org.springframework.ai.openai.OpenAiModelCall;
import org.springframework.ai.openai.OpenAiEmbeddingClient;
import org.springframework.ai.openai.api.OpenAiApi;
import org.springframework.ai.reader.JsonReader;
@@ -72,7 +71,7 @@ public class OpenAiPromptTransformingChatServiceIT {
@Container
static QdrantContainer qdrantContainer = new QdrantContainer("qdrant/qdrant:v1.9.2");
private final ChatClient chatClient;
private final ModelCall modelCall;
private final VectorStore vectorStore;
@@ -82,9 +81,9 @@ public class OpenAiPromptTransformingChatServiceIT {
private ChatService chatService;
@Autowired
public OpenAiPromptTransformingChatServiceIT(ChatClient chatClient, ChatService chatService,
public OpenAiPromptTransformingChatServiceIT(ModelCall modelCall, ChatService chatService,
VectorStore vectorStore) {
this.chatClient = chatClient;
this.modelCall = modelCall;
this.chatService = chatService;
this.vectorStore = vectorStore;
}
@@ -103,7 +102,7 @@ public class OpenAiPromptTransformingChatServiceIT {
OpenAiChatOptions openAiChatOptions = OpenAiChatOptions.builder()
.withModel(GPT_4_TURBO_PREVIEW.getValue())
.build();
var relevancyEvaluator = new RelevancyEvaluator(this.chatClient, openAiChatOptions);
var relevancyEvaluator = new RelevancyEvaluator(this.modelCall, openAiChatOptions);
EvaluationResponse evaluationResponse = relevancyEvaluator.evaluate(chatServiceResponse.toEvaluationRequest());
assertTrue(evaluationResponse.isPass(), "Response is not relevant to the question");
@@ -146,8 +145,8 @@ public class OpenAiPromptTransformingChatServiceIT {
}
@Bean
public ChatClient openAiClient(OpenAiApi openAiApi) {
return new OpenAiChatClient(openAiApi);
public ModelCall openAiClient(OpenAiApi openAiApi) {
return new OpenAiModelCall(openAiApi);
}
@Bean
@@ -164,8 +163,8 @@ public class OpenAiPromptTransformingChatServiceIT {
}
@Bean
public ChatService chatService(ChatClient chatClient, VectorStore vectorStore) {
return PromptTransformingChatService.builder(chatClient)
public ChatService chatService(ModelCall modelCall, VectorStore vectorStore) {
return PromptTransformingChatService.builder(modelCall)
.withRetrievers(List.of(new VectorStoreRetriever(vectorStore, SearchRequest.defaults())))
.withAugmentors(List.of(new QuestionContextAugmentor()))
.build();

View File

@@ -21,7 +21,7 @@ import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ai.chat.ChatClient;
import org.springframework.ai.chat.ModelCall;
import org.springframework.ai.chat.ChatResponse;
import org.springframework.ai.chat.StreamingChatClient;
import org.springframework.ai.chat.prompt.Prompt;
@@ -43,7 +43,7 @@ public abstract class AbstractIT {
private static final Logger logger = LoggerFactory.getLogger(AbstractIT.class);
@Autowired
protected ChatClient chatClient;
protected ModelCall modelCall;
@Autowired
protected StreamingChatClient streamingChatClient;
@@ -85,12 +85,12 @@ public abstract class AbstractIT {
}
Message userMessage = userPromptTemplate.createMessage();
Prompt prompt = new Prompt(List.of(userMessage, systemMessage));
String yesOrNo = chatClient.call(prompt).getResult().getOutput().getContent();
String yesOrNo = modelCall.call(prompt).getResult().getOutput().getContent();
logger.info("Is Answer related to question: " + yesOrNo);
if (yesOrNo.equalsIgnoreCase("no")) {
SystemMessage notRelatedSystemMessage = new SystemMessage(qaEvaluatorNotRelatedResource);
prompt = new Prompt(List.of(userMessage, notRelatedSystemMessage));
String reasonForFailure = chatClient.call(prompt).getResult().getOutput().getContent();
String reasonForFailure = modelCall.call(prompt).getResult().getOutput().getContent();
fail(reasonForFailure);
}
else {

View File

@@ -24,8 +24,8 @@ import org.junit.jupiter.api.Test;
import org.springframework.ai.document.DefaultContentFormatter;
import org.springframework.ai.document.Document;
import org.springframework.ai.openai.OpenAiModelCall;
import org.springframework.ai.openai.api.OpenAiApi;
import org.springframework.ai.openai.OpenAiChatClient;
import org.springframework.ai.transformer.ContentFormatTransformer;
import org.springframework.ai.transformer.KeywordMetadataEnricher;
import org.springframework.ai.transformer.SummaryMetadataEnricher;
@@ -163,18 +163,18 @@ public class MetadataTransformerIT {
}
@Bean
public OpenAiChatClient openAiChatClient(OpenAiApi openAiApi) {
OpenAiChatClient openAiChatClient = new OpenAiChatClient(openAiApi);
public OpenAiModelCall openAiChatClient(OpenAiApi openAiApi) {
OpenAiModelCall openAiChatClient = new OpenAiModelCall(openAiApi);
return openAiChatClient;
}
@Bean
public KeywordMetadataEnricher keywordMetadata(OpenAiChatClient aiClient) {
public KeywordMetadataEnricher keywordMetadata(OpenAiModelCall aiClient) {
return new KeywordMetadataEnricher(aiClient, 5);
}
@Bean
public SummaryMetadataEnricher summaryMetadata(OpenAiChatClient aiClient) {
public SummaryMetadataEnricher summaryMetadata(OpenAiModelCall aiClient) {
return new SummaryMetadataEnricher(aiClient,
List.of(SummaryType.PREVIOUS, SummaryType.CURRENT, SummaryType.NEXT));
}

View File

@@ -28,7 +28,7 @@ import com.fasterxml.jackson.annotation.JsonProperty;
import org.springframework.ai.chat.prompt.ChatOptions;
import org.springframework.ai.model.function.FunctionCallback;
import org.springframework.ai.model.function.FunctionCallingOptions;
import org.springframework.ai.vertexai.gemini.VertexAiGeminiChatClient.ChatModel;
import org.springframework.ai.vertexai.gemini.VertexAiGeminiModelCall.ChatModel;
import org.springframework.boot.context.properties.NestedConfigurationProperty;
import org.springframework.util.Assert;
@@ -78,10 +78,10 @@ public class VertexAiGeminiChatOptions implements FunctionCallingOptions, ChatOp
private @JsonProperty("modelName") String model;
/**
* Tool Function Callbacks to register with the ChatClient.
* Tool Function Callbacks to register with the ModelCall.
* For Prompt Options the functionCallbacks are automatically enabled for the duration of the prompt execution.
* For Default Options the functionCallbacks are registered but disabled by default. Use the enableFunctions to set the functions
* from the registry to be used by the ChatClient chat completion requests.
* from the registry to be used by the ModelCall chat completion requests.
*/
@NestedConfigurationProperty
@JsonIgnore

View File

@@ -32,7 +32,7 @@ import com.google.cloud.vertexai.generativeai.PartMaker;
import com.google.cloud.vertexai.generativeai.ResponseStream;
import com.google.protobuf.Struct;
import com.google.protobuf.util.JsonFormat;
import org.springframework.ai.chat.ChatClient;
import org.springframework.ai.chat.ModelCall;
import org.springframework.ai.chat.ChatResponse;
import org.springframework.ai.chat.Generation;
import org.springframework.ai.chat.StreamingChatClient;
@@ -65,9 +65,9 @@ import java.util.stream.Collectors;
* @author Grogdunn
* @since 0.8.1
*/
public class VertexAiGeminiChatClient
extends AbstractFunctionCallSupport<Content, VertexAiGeminiChatClient.GeminiRequest, GenerateContentResponse>
implements ChatClient, StreamingChatClient, DisposableBean {
public class VertexAiGeminiModelCall
extends AbstractFunctionCallSupport<Content, VertexAiGeminiModelCall.GeminiRequest, GenerateContentResponse>
implements ModelCall, StreamingChatClient, DisposableBean {
private final static boolean IS_RUNTIME_CALL = true;
@@ -117,7 +117,7 @@ public class VertexAiGeminiChatClient
}
public VertexAiGeminiChatClient(VertexAI vertexAI) {
public VertexAiGeminiModelCall(VertexAI vertexAI) {
this(vertexAI,
VertexAiGeminiChatOptions.builder()
.withModel(ChatModel.GEMINI_PRO_VISION)
@@ -125,11 +125,11 @@ public class VertexAiGeminiChatClient
.build());
}
public VertexAiGeminiChatClient(VertexAI vertexAI, VertexAiGeminiChatOptions options) {
public VertexAiGeminiModelCall(VertexAI vertexAI, VertexAiGeminiChatOptions options) {
this(vertexAI, options, null);
}
public VertexAiGeminiChatClient(VertexAI vertexAI, VertexAiGeminiChatOptions options,
public VertexAiGeminiModelCall(VertexAI vertexAI, VertexAiGeminiChatOptions options,
FunctionCallbackContext functionCallbackContext) {
super(functionCallbackContext);

View File

@@ -15,7 +15,7 @@
*/
package org.springframework.ai.vertexai.gemini.aot;
import org.springframework.ai.vertexai.gemini.VertexAiGeminiChatClient;
import org.springframework.ai.vertexai.gemini.VertexAiGeminiModelCall;
import org.springframework.aot.hint.MemberCategory;
import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.RuntimeHintsRegistrar;
@@ -34,7 +34,7 @@ public class VertexAiGeminiRuntimeHints implements RuntimeHintsRegistrar {
@Override
public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
var mcs = MemberCategory.values();
for (var tr : findJsonAnnotatedClassesInPackage(VertexAiGeminiChatClient.class))
for (var tr : findJsonAnnotatedClassesInPackage(VertexAiGeminiModelCall.class))
hints.reflection().registerType(tr, mcs);
}

View File

@@ -53,10 +53,10 @@ import static org.assertj.core.api.Assertions.assertThat;
@SpringBootTest
@EnabledIfEnvironmentVariable(named = "VERTEX_AI_GEMINI_PROJECT_ID", matches = ".*")
@EnabledIfEnvironmentVariable(named = "VERTEX_AI_GEMINI_LOCATION", matches = ".*")
class VertexAiGeminiChatClientIT {
class VertexAiGeminiModelCallIT {
@Autowired
private VertexAiGeminiChatClient client;
private VertexAiGeminiModelCall client;
@Value("classpath:/prompts/system-message.st")
private Resource systemResource;
@@ -231,10 +231,10 @@ class VertexAiGeminiChatClientIT {
}
@Bean
public VertexAiGeminiChatClient vertexAiEmbedding(VertexAI vertexAi) {
return new VertexAiGeminiChatClient(vertexAi,
public VertexAiGeminiModelCall vertexAiEmbedding(VertexAI vertexAi) {
return new VertexAiGeminiModelCall(vertexAi,
VertexAiGeminiChatOptions.builder()
.withModel(VertexAiGeminiChatClient.ChatModel.GEMINI_PRO_VISION)
.withModel(VertexAiGeminiModelCall.ChatModel.GEMINI_PRO_VISION)
.build());
}

View File

@@ -19,7 +19,7 @@ import java.util.Set;
import org.junit.jupiter.api.Test;
import org.springframework.ai.vertexai.gemini.VertexAiGeminiChatClient;
import org.springframework.ai.vertexai.gemini.VertexAiGeminiModelCall;
import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.TypeReference;
@@ -38,7 +38,7 @@ class VertexAiGeminiRuntimeHintsTests {
RuntimeHints runtimeHints = new RuntimeHints();
VertexAiGeminiRuntimeHints vertexAiGeminiRuntimeHints = new VertexAiGeminiRuntimeHints();
vertexAiGeminiRuntimeHints.registerHints(runtimeHints, null);
Set<TypeReference> jsonAnnotatedClasses = findJsonAnnotatedClassesInPackage(VertexAiGeminiChatClient.class);
Set<TypeReference> jsonAnnotatedClasses = findJsonAnnotatedClassesInPackage(VertexAiGeminiModelCall.class);
for (TypeReference jsonAnnotatedClass : jsonAnnotatedClasses) {
assertThat(runtimeHints).matches(reflection().onType(jsonAnnotatedClass));
}

View File

@@ -28,6 +28,7 @@ import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ai.vertexai.gemini.VertexAiGeminiModelCall;
import reactor.core.publisher.Flux;
import org.springframework.ai.chat.ChatResponse;
@@ -38,7 +39,6 @@ import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.model.function.FunctionCallbackWrapper;
import org.springframework.ai.model.function.FunctionCallbackWrapper.Builder.SchemaType;
import org.springframework.ai.vertexai.gemini.VertexAiGeminiChatClient;
import org.springframework.ai.vertexai.gemini.VertexAiGeminiChatOptions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringBootConfiguration;
@@ -50,12 +50,12 @@ import static org.assertj.core.api.Assertions.assertThat;
@SpringBootTest
@EnabledIfEnvironmentVariable(named = "VERTEX_AI_GEMINI_PROJECT_ID", matches = ".*")
@EnabledIfEnvironmentVariable(named = "VERTEX_AI_GEMINI_LOCATION", matches = ".*")
public class VertexAiGeminiChatClientFunctionCallingIT {
public class VertexAiGeminiModelCallFunctionCallingIT {
private final Logger logger = LoggerFactory.getLogger(getClass());
@Autowired
private VertexAiGeminiChatClient vertexGeminiClient;
private VertexAiGeminiModelCall vertexGeminiClient;
@AfterEach
public void afterEach() {
@@ -98,8 +98,8 @@ public class VertexAiGeminiChatClientFunctionCallingIT {
""";
var promptOptions = VertexAiGeminiChatOptions.builder()
.withModel(VertexAiGeminiChatClient.ChatModel.GEMINI_PRO)
// .withModel(VertexAiGeminiChatClient.ChatModel.GEMINI_PRO_1_5_PRO)
.withModel(VertexAiGeminiModelCall.ChatModel.GEMINI_PRO)
// .withModel(VertexAiGeminiModelCall.ChatModel.GEMINI_PRO_1_5_PRO)
.withFunctionCallbacks(List.of(FunctionCallbackWrapper.builder(new MockWeatherService())
.withName("get_current_weather")
.withDescription("Get the current weather in a given location")
@@ -126,8 +126,8 @@ public class VertexAiGeminiChatClientFunctionCallingIT {
List<Message> messages = new ArrayList<>(List.of(userMessage));
var promptOptions = VertexAiGeminiChatOptions.builder()
// .withModel(VertexAiGeminiChatClient.ChatModel.GEMINI_PRO_1_5_PRO)
.withModel(VertexAiGeminiChatClient.ChatModel.GEMINI_PRO.getValue())
// .withModel(VertexAiGeminiModelCall.ChatModel.GEMINI_PRO_1_5_PRO)
.withModel(VertexAiGeminiModelCall.ChatModel.GEMINI_PRO.getValue())
.withFunctionCallbacks(List.of(
FunctionCallbackWrapper.builder(new MockWeatherService())
.withSchemaType(SchemaType.OPEN_API_SCHEMA)
@@ -168,7 +168,7 @@ public class VertexAiGeminiChatClientFunctionCallingIT {
List<Message> messages = new ArrayList<>(List.of(userMessage));
var promptOptions = VertexAiGeminiChatOptions.builder()
.withModel(VertexAiGeminiChatClient.ChatModel.GEMINI_PRO)
.withModel(VertexAiGeminiModelCall.ChatModel.GEMINI_PRO)
.withFunctionCallbacks(List.of(FunctionCallbackWrapper.builder(new MockWeatherService())
.withSchemaType(SchemaType.OPEN_API_SCHEMA)
.withName("getCurrentWeather")
@@ -224,10 +224,10 @@ public class VertexAiGeminiChatClientFunctionCallingIT {
}
@Bean
public VertexAiGeminiChatClient vertexAiEmbedding(VertexAI vertexAi) {
return new VertexAiGeminiChatClient(vertexAi,
public VertexAiGeminiModelCall vertexAiEmbedding(VertexAI vertexAi) {
return new VertexAiGeminiModelCall(vertexAi,
VertexAiGeminiChatOptions.builder()
.withModel(VertexAiGeminiChatClient.ChatModel.GEMINI_PRO)
.withModel(VertexAiGeminiModelCall.ChatModel.GEMINI_PRO)
.withTemperature(0.9f)
.build());
}

View File

@@ -18,7 +18,7 @@ package org.springframework.ai.vertexai.palm2;
import java.util.List;
import java.util.stream.Collectors;
import org.springframework.ai.chat.ChatClient;
import org.springframework.ai.chat.ModelCall;
import org.springframework.ai.chat.prompt.ChatOptions;
import org.springframework.ai.chat.ChatResponse;
import org.springframework.ai.chat.Generation;
@@ -35,18 +35,18 @@ import org.springframework.util.CollectionUtils;
/**
* @author Christian Tzolov
*/
public class VertexAiPaLm2ChatClient implements ChatClient {
public class VertexAiPaLm2ModelCall implements ModelCall {
private final VertexAiPaLm2Api vertexAiApi;
private final VertexAiPaLm2ChatOptions defaultOptions;
public VertexAiPaLm2ChatClient(VertexAiPaLm2Api vertexAiApi) {
public VertexAiPaLm2ModelCall(VertexAiPaLm2Api vertexAiApi) {
this(vertexAiApi,
VertexAiPaLm2ChatOptions.builder().withTemperature(0.7f).withCandidateCount(1).withTopK(20).build());
}
public VertexAiPaLm2ChatClient(VertexAiPaLm2Api vertexAiApi, VertexAiPaLm2ChatOptions defaultOptions) {
public VertexAiPaLm2ModelCall(VertexAiPaLm2Api vertexAiApi, VertexAiPaLm2ChatOptions defaultOptions) {
Assert.notNull(defaultOptions, "Default options must not be null!");
Assert.notNull(vertexAiApi, "VertexAiPaLm2Api must not be null!");

View File

@@ -48,7 +48,7 @@ import static org.assertj.core.api.Assertions.assertThat;
class VertexAiPaLm2ChatGenerationClientIT {
@Autowired
private VertexAiPaLm2ChatClient client;
private VertexAiPaLm2ModelCall client;
@Value("classpath:/prompts/system-message.st")
private Resource systemResource;
@@ -136,8 +136,8 @@ class VertexAiPaLm2ChatGenerationClientIT {
}
@Bean
public VertexAiPaLm2ChatClient vertexAiEmbedding(VertexAiPaLm2Api vertexAiApi) {
return new VertexAiPaLm2ChatClient(vertexAiApi);
public VertexAiPaLm2ModelCall vertexAiEmbedding(VertexAiPaLm2Api vertexAiApi) {
return new VertexAiPaLm2ModelCall(vertexAiApi);
}
}

View File

@@ -29,7 +29,7 @@ import static org.assertj.core.api.Assertions.assertThat;
*/
public class VertexAiPaLm2ChatRequestTests {
VertexAiPaLm2ChatClient client = new VertexAiPaLm2ChatClient(new VertexAiPaLm2Api("bla"));
VertexAiPaLm2ModelCall client = new VertexAiPaLm2ModelCall(new VertexAiPaLm2Api("bla"));
@Test
public void createRequestWithDefaultOptions() {

View File

@@ -18,9 +18,9 @@ package org.springframework.ai.watsonx;
import java.util.List;
import java.util.Map;
import org.springframework.ai.chat.ModelCall;
import reactor.core.publisher.Flux;
import org.springframework.ai.chat.ChatClient;
import org.springframework.ai.chat.ChatResponse;
import org.springframework.ai.chat.Generation;
import org.springframework.ai.chat.StreamingChatClient;
@@ -35,7 +35,7 @@ import org.springframework.ai.watsonx.utils.MessageToPromptConverter;
import org.springframework.util.Assert;
/**
* {@link ChatClient} implementation for {@literal watsonx.ai}.
* {@link ModelCall} implementation for {@literal watsonx.ai}.
*
* watsonx.ai allows developers to use large language models within a SaaS service. It
* supports multiple open-source models as well as IBM created models
@@ -48,13 +48,13 @@ import org.springframework.util.Assert;
* @author Christian Tzolov
* @since 1.0.0
*/
public class WatsonxAiChatClient implements ChatClient, StreamingChatClient {
public class WatsonxAiModelCall implements ModelCall, StreamingChatClient {
private final WatsonxAiApi watsonxAiApi;
private final WatsonxAiChatOptions defaultOptions;
public WatsonxAiChatClient(WatsonxAiApi watsonxAiApi) {
public WatsonxAiModelCall(WatsonxAiApi watsonxAiApi) {
this(watsonxAiApi,
WatsonxAiChatOptions.builder()
.withTemperature(0.7f)
@@ -68,7 +68,7 @@ public class WatsonxAiChatClient implements ChatClient, StreamingChatClient {
.build());
}
public WatsonxAiChatClient(WatsonxAiApi watsonxAiApi, WatsonxAiChatOptions defaultOptions) {
public WatsonxAiModelCall(WatsonxAiApi watsonxAiApi, WatsonxAiChatOptions defaultOptions) {
Assert.notNull(watsonxAiApi, "watsonxAiApi cannot be null");
Assert.notNull(defaultOptions, "defaultOptions cannot be null");
this.watsonxAiApi = watsonxAiApi;

View File

@@ -46,9 +46,9 @@ import static org.mockito.Mockito.when;
* @author Pablo Sanchidrian Herrera
* @author John Jairo Moreno Rojas
*/
public class WatsonxAiChatClientTest {
public class WatsonxAiModelCallTest {
WatsonxAiChatClient chatClient = new WatsonxAiChatClient(mock(WatsonxAiApi.class));
WatsonxAiModelCall chatClient = new WatsonxAiModelCall(mock(WatsonxAiApi.class));
@Test
public void testCreateRequestWithNoModelId() {
@@ -157,7 +157,7 @@ public class WatsonxAiChatClientTest {
@Test
public void testCallMethod() {
WatsonxAiApi mockChatApi = mock(WatsonxAiApi.class);
WatsonxAiChatClient client = new WatsonxAiChatClient(mockChatApi);
WatsonxAiModelCall client = new WatsonxAiModelCall(mockChatApi);
Prompt prompt = new Prompt(List.of(new SystemMessage("Your prompt here")),
WatsonxAiChatOptions.builder().withModel("google/flan-ul2").build());
@@ -186,7 +186,7 @@ public class WatsonxAiChatClientTest {
@Test
public void testStreamMethod() {
WatsonxAiApi mockChatApi = mock(WatsonxAiApi.class);
WatsonxAiChatClient client = new WatsonxAiChatClient(mockChatApi);
WatsonxAiModelCall client = new WatsonxAiModelCall(mockChatApi);
Prompt prompt = new Prompt(List.of(new SystemMessage("Your prompt here")),
WatsonxAiChatOptions.builder().withModel("google/flan-ul2").build());