* implemented user specification and system specification
* managed to go end-to-end with a simple use of the new fluent DSL: build up the pipeline, all the way to a ChatResponse.
This commit is contained in:
@@ -117,7 +117,7 @@ public class AnthropicChatConnector extends
|
||||
* @param retryTemplate the retry template used to retry the Anthropic API calls.
|
||||
*/
|
||||
public AnthropicChatConnector(AnthropicApi anthropicApi, AnthropicChatOptions defaultOptions,
|
||||
RetryTemplate retryTemplate) {
|
||||
RetryTemplate retryTemplate) {
|
||||
this(anthropicApi, defaultOptions, retryTemplate, null);
|
||||
}
|
||||
|
||||
@@ -130,7 +130,7 @@ public class AnthropicChatConnector extends
|
||||
* state of the function calls.
|
||||
*/
|
||||
public AnthropicChatConnector(AnthropicApi anthropicApi, AnthropicChatOptions defaultOptions,
|
||||
RetryTemplate retryTemplate, FunctionCallbackContext functionCallbackContext) {
|
||||
RetryTemplate retryTemplate, FunctionCallbackContext functionCallbackContext) {
|
||||
|
||||
super(functionCallbackContext);
|
||||
|
||||
|
||||
@@ -107,7 +107,7 @@ public class AzureOpenAiChatConnector
|
||||
}
|
||||
|
||||
public AzureOpenAiChatConnector(OpenAIClient microsoftOpenAiClient, AzureOpenAiChatOptions options,
|
||||
FunctionCallbackContext functionCallbackContext) {
|
||||
FunctionCallbackContext functionCallbackContext) {
|
||||
super(functionCallbackContext);
|
||||
Assert.notNull(microsoftOpenAiClient, "com.azure.ai.openai.OpenAIClient must not be null");
|
||||
Assert.notNull(options, "AzureOpenAiChatOptions must not be null");
|
||||
|
||||
@@ -59,7 +59,7 @@ public class MockAzureOpenAiTestConfiguration {
|
||||
}
|
||||
|
||||
@Bean
|
||||
AzureOpenAiChatConnector azureOpenAiChatClient(OpenAIClient microsoftAzureOpenAiClient) {
|
||||
AzureOpenAiChatConnector azureOpenAiChatClient(OpenAIClient microsoftAzureOpenAiClient) {
|
||||
return new AzureOpenAiChatConnector(microsoftAzureOpenAiClient);
|
||||
}
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ public class BedrockAi21Jurassic2ChatConnector implements ChatConnector {
|
||||
private final BedrockAi21Jurassic2ChatOptions defaultOptions;
|
||||
|
||||
public BedrockAi21Jurassic2ChatConnector(Ai21Jurassic2ChatBedrockApi chatApi,
|
||||
BedrockAi21Jurassic2ChatOptions options) {
|
||||
BedrockAi21Jurassic2ChatOptions options) {
|
||||
Assert.notNull(chatApi, "Ai21Jurassic2ChatBedrockApi must not be null");
|
||||
Assert.notNull(options, "BedrockAi21Jurassic2ChatOptions must not be null");
|
||||
|
||||
|
||||
@@ -83,7 +83,7 @@ public class MistralAiChatConnector extends
|
||||
}
|
||||
|
||||
public MistralAiChatConnector(MistralAiApi mistralAiApi, MistralAiChatOptions options,
|
||||
FunctionCallbackContext functionCallbackContext, RetryTemplate retryTemplate) {
|
||||
FunctionCallbackContext functionCallbackContext, RetryTemplate retryTemplate) {
|
||||
super(functionCallbackContext);
|
||||
Assert.notNull(mistralAiApi, "MistralAiApi must not be null");
|
||||
Assert.notNull(options, "Options must not be null");
|
||||
|
||||
@@ -123,7 +123,7 @@ public class OpenAiChatConnector extends
|
||||
* @param retryTemplate The retry template.
|
||||
*/
|
||||
public OpenAiChatConnector(OpenAiApi openAiApi, OpenAiChatOptions options,
|
||||
FunctionCallbackContext functionCallbackContext, RetryTemplate retryTemplate) {
|
||||
FunctionCallbackContext functionCallbackContext, RetryTemplate retryTemplate) {
|
||||
super(functionCallbackContext);
|
||||
Assert.notNull(openAiApi, "OpenAiApi must not be null");
|
||||
Assert.notNull(options, "Options must not be null");
|
||||
|
||||
@@ -1,56 +0,0 @@
|
||||
package org.springframework.ai.openai;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.ai.chat.ChatClient;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
class ChatConnectorTest {
|
||||
|
||||
@Configuration
|
||||
static class ChatClientTestConfiguration {
|
||||
|
||||
@Bean
|
||||
ChatClient client(OpenAiChatConnector openAiChatConnector) {
|
||||
return ChatClient.builder(openAiChatConnector).defaultSystem("""
|
||||
you are customer service agent designed to answer questions
|
||||
about a the user, {userName}'s, orders. Here are their outstanding orders.
|
||||
|
||||
{orders}
|
||||
|
||||
""").defaultFunctions("cancelOrder", "refundOrder").build();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private final ChatClient singularity;
|
||||
|
||||
ChatConnectorTest(@Autowired ChatClient singularity) {
|
||||
this.singularity = singularity;
|
||||
}
|
||||
|
||||
@Test
|
||||
void products() throws Exception {
|
||||
var product0 = this.client.userPrompt("tell me about this product from the merchant {merchant}")
|
||||
.userPromptParams(Map.of("merchant", "24u92"))
|
||||
.execute(Product.class);
|
||||
|
||||
/*
|
||||
* var product1 = this.client .build() .userPromptParam("a", "b")
|
||||
* .functions("cancelOrder", "refundOrder") .execute(new
|
||||
* ParameterizedTypeReference<Product>() { });
|
||||
*
|
||||
* var product2 = this.client
|
||||
* .userPrompt("tell me about this product from the merchant {merchant}",
|
||||
* Map.of("merchant", "232")) .execute(Product.class);
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
record Product(String sku) {
|
||||
}
|
||||
|
||||
}
|
||||
@@ -99,7 +99,7 @@ public class ChatMemoryLongTermSystemPromptIT extends BaseMemoryTest {
|
||||
|
||||
@Bean
|
||||
public ChatService memoryChatService(OpenAiChatConnector chatClient, VectorStore vectorStore,
|
||||
TokenCountEstimator tokenCountEstimator) {
|
||||
TokenCountEstimator tokenCountEstimator) {
|
||||
|
||||
return PromptTransformingChatService.builder(chatClient)
|
||||
.withRetrievers(List.of(new VectorStoreChatMemoryRetriever(vectorStore, 10)))
|
||||
@@ -111,7 +111,7 @@ public class ChatMemoryLongTermSystemPromptIT extends BaseMemoryTest {
|
||||
|
||||
@Bean
|
||||
public StreamingChatService memoryStreamingChatService(OpenAiChatConnector streamingChatClient,
|
||||
VectorStore vectorStore, TokenCountEstimator tokenCountEstimator) {
|
||||
VectorStore vectorStore, TokenCountEstimator tokenCountEstimator) {
|
||||
|
||||
return StreamingPromptTransformingChatService.builder(streamingChatClient)
|
||||
.withRetrievers(List.of(new VectorStoreChatMemoryRetriever(vectorStore, 10)))
|
||||
|
||||
@@ -75,7 +75,7 @@ public class ChatMemoryShortTermMessageListIT extends BaseMemoryTest {
|
||||
|
||||
@Bean
|
||||
public ChatService memoryChatService(OpenAiChatConnector chatClient, ChatMemory chatHistory,
|
||||
TokenCountEstimator tokenCountEstimator) {
|
||||
TokenCountEstimator tokenCountEstimator) {
|
||||
|
||||
return PromptTransformingChatService.builder(chatClient)
|
||||
.withRetrievers(List.of(new ChatMemoryRetriever(chatHistory)))
|
||||
@@ -87,7 +87,7 @@ public class ChatMemoryShortTermMessageListIT extends BaseMemoryTest {
|
||||
|
||||
@Bean
|
||||
public StreamingChatService memoryStreamingChatService(OpenAiChatConnector streamingChatClient,
|
||||
ChatMemory chatHistory, TokenCountEstimator tokenCountEstimator) {
|
||||
ChatMemory chatHistory, TokenCountEstimator tokenCountEstimator) {
|
||||
|
||||
return StreamingPromptTransformingChatService.builder(streamingChatClient)
|
||||
.withRetrievers(List.of(new ChatMemoryRetriever(chatHistory)))
|
||||
|
||||
@@ -76,7 +76,7 @@ public class ChatMemoryShortTermSystemPromptIT extends BaseMemoryTest {
|
||||
|
||||
@Bean
|
||||
public ChatService memoryChatService(OpenAiChatConnector chatClient, ChatMemory chatHistory,
|
||||
TokenCountEstimator tokenCountEstimator) {
|
||||
TokenCountEstimator tokenCountEstimator) {
|
||||
|
||||
return PromptTransformingChatService.builder(chatClient)
|
||||
.withRetrievers(List.of(new ChatMemoryRetriever(chatHistory)))
|
||||
@@ -88,7 +88,7 @@ public class ChatMemoryShortTermSystemPromptIT extends BaseMemoryTest {
|
||||
|
||||
@Bean
|
||||
public StreamingChatService memoryStreamingChatService(OpenAiChatConnector streamingChatClient,
|
||||
ChatMemory chatHistory, TokenCountEstimator tokenCountEstimator) {
|
||||
ChatMemory chatHistory, TokenCountEstimator tokenCountEstimator) {
|
||||
|
||||
return StreamingPromptTransformingChatService.builder(streamingChatClient)
|
||||
.withRetrievers(List.of(new ChatMemoryRetriever(chatHistory)))
|
||||
|
||||
@@ -187,7 +187,7 @@ public class LongShortTermChatMemoryWithRagIT {
|
||||
|
||||
@Bean
|
||||
public ChatService memoryChatService(OpenAiChatConnector chatClient, VectorStore vectorStore,
|
||||
TokenCountEstimator tokenCountEstimator, ChatMemory chatHistory) {
|
||||
TokenCountEstimator tokenCountEstimator, ChatMemory chatHistory) {
|
||||
|
||||
return PromptTransformingChatService.builder(chatClient)
|
||||
.withRetrievers(List.of(new VectorStoreRetriever(vectorStore, SearchRequest.defaults()),
|
||||
|
||||
@@ -82,7 +82,7 @@ public class OpenAiPromptTransformingChatServiceIT {
|
||||
|
||||
@Autowired
|
||||
public OpenAiPromptTransformingChatServiceIT(ChatConnector chatConnector, ChatService chatService,
|
||||
VectorStore vectorStore) {
|
||||
VectorStore vectorStore) {
|
||||
this.chatConnector = chatConnector;
|
||||
this.chatService = chatService;
|
||||
this.vectorStore = vectorStore;
|
||||
|
||||
@@ -130,7 +130,7 @@ public class VertexAiGeminiChatConnector
|
||||
}
|
||||
|
||||
public VertexAiGeminiChatConnector(VertexAI vertexAI, VertexAiGeminiChatOptions options,
|
||||
FunctionCallbackContext functionCallbackContext) {
|
||||
FunctionCallbackContext functionCallbackContext) {
|
||||
|
||||
super(functionCallbackContext);
|
||||
|
||||
|
||||
@@ -3,14 +3,23 @@ package org.springframework.ai.chat;
|
||||
import org.springframework.ai.chat.connector.ChatConnector;
|
||||
import org.springframework.ai.chat.messages.Media;
|
||||
import org.springframework.ai.chat.messages.Message;
|
||||
import org.springframework.ai.chat.messages.SystemMessage;
|
||||
import org.springframework.ai.chat.messages.UserMessage;
|
||||
import org.springframework.ai.chat.prompt.ChatOptions;
|
||||
import org.springframework.ai.chat.prompt.Prompt;
|
||||
import org.springframework.ai.chat.prompt.PromptTemplate;
|
||||
import org.springframework.ai.model.function.FunctionCallback;
|
||||
import org.springframework.ai.model.function.FunctionCallbackWrapper;
|
||||
import org.springframework.ai.model.function.FunctionCallingOptionsBuilder;
|
||||
import org.springframework.core.ParameterizedTypeReference;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.MimeType;
|
||||
import reactor.core.publisher.Flux;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.*;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
@@ -93,229 +102,312 @@ public class DemoApplication {
|
||||
*/
|
||||
|
||||
public interface ChatClient {
|
||||
static ChatClientBuilder builder(ChatConnector connector) {
|
||||
return new ChatClientBuilder(connector);
|
||||
}
|
||||
|
||||
ChatClientRequest build();
|
||||
static ChatClientBuilder builder(ChatConnector connector) {
|
||||
return new ChatClientBuilder(connector);
|
||||
}
|
||||
|
||||
ChatResponse call(Prompt prompt);
|
||||
ChatResponse call(Prompt prompt);
|
||||
|
||||
ChatClientRequest user(Consumer<UserSpec> consumer);
|
||||
ChatClientRequest call();
|
||||
|
||||
public static class UserSpec {
|
||||
interface PromptSpec<T> {
|
||||
|
||||
T text(String text);
|
||||
|
||||
public UserSpec media(List<Media> media) {
|
||||
return this;
|
||||
}
|
||||
T text(Resource text, Charset charset);
|
||||
|
||||
public UserSpec media(URL url, MimeType mimeType) {
|
||||
return this;
|
||||
}
|
||||
T text(Resource text);
|
||||
|
||||
public UserSpec media(Resource resource, MimeType type) {
|
||||
return this;
|
||||
}
|
||||
T params(Map<String, Object> p);
|
||||
|
||||
public UserSpec media(Media... m) {
|
||||
return this;
|
||||
}
|
||||
T param(String k, String v);
|
||||
|
||||
public UserSpec params(Map<String, Object> p) {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
public UserSpec param(String k, String v) {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
abstract class AbstractPromptSpec<T extends AbstractPromptSpec<T>> implements PromptSpec<T> {
|
||||
|
||||
public static class ChatClientRequest {
|
||||
private String text = "";
|
||||
|
||||
private String userPrompt = "";
|
||||
private final Map<String, Object> params = new HashMap<>();
|
||||
|
||||
private String systemPrompt = "";
|
||||
@Override
|
||||
public T text(String text) {
|
||||
this.text = (text);
|
||||
return self();
|
||||
}
|
||||
|
||||
private final List<Media> media = new ArrayList<>();
|
||||
@Override
|
||||
public T text(Resource text, Charset charset) {
|
||||
try {
|
||||
this.text(text.getContentAsString(charset));
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return self();
|
||||
}
|
||||
|
||||
private final List<String> functions = new ArrayList<>();
|
||||
@Override
|
||||
public T text(Resource text) {
|
||||
this.text(text, Charset.defaultCharset());
|
||||
return self();
|
||||
}
|
||||
|
||||
private final Map<String, String> userPromptParams = new HashMap<>();
|
||||
@Override
|
||||
public T param(String k, String v) {
|
||||
this.params.put(k, v);
|
||||
return self();
|
||||
}
|
||||
|
||||
private final Map<String, String> systemPromptParams = new HashMap<>();
|
||||
@Override
|
||||
public T params(Map<String, Object> p) {
|
||||
this.params.putAll(p);
|
||||
return self();
|
||||
}
|
||||
|
||||
List<Media> userMedia() {
|
||||
return this.media;
|
||||
}
|
||||
protected abstract T self();
|
||||
|
||||
String systemText() {
|
||||
return this.systemPrompt;
|
||||
}
|
||||
protected String text() {
|
||||
return this.text;
|
||||
}
|
||||
|
||||
String userText() {
|
||||
return this.userPrompt;
|
||||
}
|
||||
protected Map<String, Object> params() {
|
||||
return this.params;
|
||||
}
|
||||
|
||||
List<String> functions() {
|
||||
return this.functions;
|
||||
}
|
||||
}
|
||||
|
||||
public ChatClientRequest(String userPrompt, String systemPrompt, List<String> functions, List<Media> media) {
|
||||
this.userPrompt = userPrompt;
|
||||
this.systemPrompt = systemPrompt;
|
||||
this.functions.addAll(functions);
|
||||
this.media.addAll(media);
|
||||
}
|
||||
class UserSpec extends AbstractPromptSpec<UserSpec> implements PromptSpec<UserSpec> {
|
||||
|
||||
public ChatClientRequest messages(Message... messages) {
|
||||
return null;
|
||||
}
|
||||
//
|
||||
// public ChatClientRequest userParam(String key, String value) {
|
||||
// this.userPromptParams.put(key, value);
|
||||
// return this;
|
||||
// }
|
||||
//
|
||||
// public ChatClientRequest systemParam(String key, String value) {
|
||||
// this.systemPromptParams.put(key, value);
|
||||
// return this;
|
||||
// }
|
||||
private final List<Media> media = new ArrayList<>();
|
||||
|
||||
public <T extends ChatOptions> ChatClientRequest options(T options) {
|
||||
return this;
|
||||
}
|
||||
//
|
||||
// public ChatClientRequest systemParams(Map<String, String> systemPromptParams) {
|
||||
// this.systemPromptParams.putAll(systemPromptParams);
|
||||
// return this;
|
||||
// }
|
||||
//
|
||||
// public ChatClientRequest userParams(Map<String, String> userPromptParams) {
|
||||
// this.userPromptParams.putAll(userPromptParams);
|
||||
// return this;
|
||||
// }
|
||||
//
|
||||
// public ChatClientRequest userText(Resource resource) {
|
||||
// return userText(resource, Charset.defaultCharset());
|
||||
// }
|
||||
public UserSpec media(Media... media) {
|
||||
this.media.addAll(Arrays.asList(media));
|
||||
return self();
|
||||
}
|
||||
|
||||
// public ChatClientRequest userText(Resource resource, Charset charset) {
|
||||
// try {
|
||||
// this.userText(resource.getContentAsString(charset));
|
||||
// } catch (IOException e) {
|
||||
// throw new RuntimeException(e);
|
||||
// }
|
||||
// return this;
|
||||
// }
|
||||
//
|
||||
//
|
||||
// public ChatClientRequest userText(String userPrompt) {
|
||||
// this.userPrompt = userPrompt;
|
||||
// return this;
|
||||
// }
|
||||
//
|
||||
// public ChatClientRequest systemText(Resource systemPrompt) {
|
||||
// return systemText(systemPrompt, Charset.defaultCharset());
|
||||
// }
|
||||
//
|
||||
// public ChatClientRequest systemText(Resource systemPrompt, Charset charset) {
|
||||
// try {
|
||||
// this.systemText(systemPrompt.getContentAsString(charset));
|
||||
// } catch (IOException e) {
|
||||
// throw new RuntimeException(e);
|
||||
// }
|
||||
// return this;
|
||||
// }
|
||||
//
|
||||
// public ChatClientRequest systemText(String systemPrompt) {
|
||||
// this.systemPrompt = systemPrompt;
|
||||
// return this;
|
||||
// }
|
||||
//
|
||||
// public ChatClientRequest userMedia(Media... media) {
|
||||
// this.media.addAll(Arrays.asList(media));
|
||||
// return this;
|
||||
// }
|
||||
public UserSpec media(MimeType mimeType, URL url) {
|
||||
this.media.add(new Media(mimeType, url));
|
||||
return self();
|
||||
}
|
||||
|
||||
public ChatClientRequest functions(String... functions) {
|
||||
this.functions.addAll(Arrays.asList(functions));
|
||||
return this;
|
||||
}
|
||||
public UserSpec media(MimeType mimeType, Resource resource) {
|
||||
this.media.add(new Media(mimeType, resource));
|
||||
return self();
|
||||
}
|
||||
|
||||
protected List<Media> media() {
|
||||
return this.media;
|
||||
}
|
||||
|
||||
public static class ChatResponseSpec {
|
||||
@Override
|
||||
protected UserSpec self() {
|
||||
return this;
|
||||
}
|
||||
|
||||
public <T> T single(ParameterizedTypeReference<T> t) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
class SystemSpec extends AbstractPromptSpec<SystemSpec> implements PromptSpec<SystemSpec> {
|
||||
|
||||
public <T> T single(Class<T> clzz) {
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
protected SystemSpec self() {
|
||||
return this;
|
||||
}
|
||||
|
||||
public ChatResponse chatResponse() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public <T> Flux<T> stream(Class<T> t) {
|
||||
return null;
|
||||
}
|
||||
class ChatClientRequest {
|
||||
|
||||
public <T> Flux<T> stream(ParameterizedTypeReference<T> t) {
|
||||
return Flux.empty();
|
||||
}
|
||||
private final ChatConnector connector;
|
||||
|
||||
public <T> Collection<T> list(Class<T> clzz) {
|
||||
return null;
|
||||
}
|
||||
private String userText = "";
|
||||
|
||||
public <T> Collection<T> list(ParameterizedTypeReference<Collection<T>> ptr) {
|
||||
return List.of();
|
||||
}
|
||||
private String systemText = "";
|
||||
|
||||
}
|
||||
private ChatOptions chatOptions;
|
||||
|
||||
public ChatResponseSpec chat() {
|
||||
return null;
|
||||
}
|
||||
private final List<Media> media = new ArrayList<>();
|
||||
|
||||
private final Set<String> functionNames = new HashSet<>();
|
||||
|
||||
}
|
||||
private final List<FunctionCallback> functionCallbacks = new ArrayList<>();
|
||||
|
||||
public static class ChatClientBuilder {
|
||||
private final Map<String, Object> userParams = new HashMap<>();
|
||||
|
||||
private final ChatConnector connector;
|
||||
private final List<Message> messages = new ArrayList<>();
|
||||
|
||||
private final List<Media> defaultMedia = new ArrayList<>();
|
||||
private final Map<String, Object> systemParams = new HashMap<>();
|
||||
|
||||
private final List<String> defaultFunctions = new ArrayList<>();
|
||||
public ChatClientRequest(ChatConnector connector, String userText, String systemText,
|
||||
List<String> functionNames, List<Media> media, ChatOptions chatOptions) {
|
||||
this.userText = userText;
|
||||
this.systemText = systemText;
|
||||
this.connector = connector;
|
||||
this.functionNames.addAll(functionNames);
|
||||
this.media.addAll(media);
|
||||
this.chatOptions = chatOptions;
|
||||
}
|
||||
|
||||
private String defaultSystemPrompt;
|
||||
public ChatClientRequest messages(Message... messages) {
|
||||
this.messages.addAll(List.of(messages));
|
||||
return this;
|
||||
}
|
||||
|
||||
private String defaultUserPrompt;
|
||||
public <T extends ChatOptions> ChatClientRequest options(T options) {
|
||||
this.chatOptions = options;
|
||||
return this;
|
||||
}
|
||||
|
||||
ChatClientBuilder(ChatConnector connector) {
|
||||
this.connector = connector;
|
||||
}
|
||||
public <I, O> ChatClientRequest function(String name, String description,
|
||||
java.util.function.Function<I, O> function) {
|
||||
var fcw = FunctionCallbackWrapper.builder(function)
|
||||
.withDescription(description)
|
||||
.withName(name)
|
||||
.withResponseConverter(Object::toString)
|
||||
.build();
|
||||
this.functionCallbacks.add(fcw);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ChatClient build() {
|
||||
return new DefaultChatClient(this.connector, this.defaultSystemPrompt, this.defaultUserPrompt,
|
||||
this.defaultFunctions, this.defaultMedia);
|
||||
}
|
||||
public ChatClientRequest functions(String... functions) {
|
||||
this.functionNames.addAll(List.of(functions));
|
||||
return this;
|
||||
}
|
||||
|
||||
public ChatClientBuilder defaultSystem(String systemPrompt) {
|
||||
return this;
|
||||
}
|
||||
public ChatClientRequest system(Consumer<SystemSpec> consumer) {
|
||||
var ss = new SystemSpec();
|
||||
consumer.accept(ss);
|
||||
this.systemText = ss.text();
|
||||
this.systemParams.putAll(ss.params());
|
||||
return this;
|
||||
}
|
||||
|
||||
public ChatClientBuilder defaultFunctions(String... functionNames) {
|
||||
return this;
|
||||
}
|
||||
public ChatClientRequest user(Consumer<UserSpec> consumer) {
|
||||
var us = new UserSpec();
|
||||
consumer.accept(us);
|
||||
this.userText = us.text();
|
||||
this.userParams.putAll(us.params());
|
||||
this.media.addAll(us.media());
|
||||
return this;
|
||||
}
|
||||
|
||||
public ChatClientBuilder defaultUserPrompt(String userPrompt) {
|
||||
return this;
|
||||
}
|
||||
public static class ChatResponseSpec {
|
||||
|
||||
private final ChatClientRequest request;
|
||||
|
||||
private final ChatConnector chatConnector;
|
||||
|
||||
public ChatResponseSpec(ChatConnector chatConnector, ChatClientRequest request) {
|
||||
this.chatConnector = chatConnector;
|
||||
this.request = request;
|
||||
}
|
||||
|
||||
public <T> T single(ParameterizedTypeReference<T> t) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public <T> T single(Class<T> clzz) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public ChatResponse chatResponse() {
|
||||
|
||||
var userMessage = new UserMessage(
|
||||
new PromptTemplate(this.request.userText, this.request.userParams).render(),
|
||||
this.request.media);
|
||||
|
||||
var systemMessage = new SystemMessage(
|
||||
new PromptTemplate(this.request.systemText, this.request.systemParams).render());
|
||||
|
||||
if (request.chatOptions instanceof FunctionCallingOptionsBuilder.PortableFunctionCallingOptions functionCallingOptions) {
|
||||
if (!request.functionNames.isEmpty()) {
|
||||
functionCallingOptions.setFunctions(request.functionNames);
|
||||
}
|
||||
if (!request.functionCallbacks.isEmpty()) {
|
||||
functionCallingOptions.setFunctionCallbacks(request.functionCallbacks);
|
||||
}
|
||||
}
|
||||
var prompt = new Prompt(List.of(systemMessage, userMessage), request.chatOptions);
|
||||
|
||||
return this.chatConnector.call(prompt);
|
||||
}
|
||||
|
||||
public <T> Flux<T> stream(Class<T> t) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public <T> Flux<T> stream(ParameterizedTypeReference<T> t) {
|
||||
return Flux.empty();
|
||||
}
|
||||
|
||||
public <T> Collection<T> list(Class<T> clzz) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public <T> Collection<T> list(ParameterizedTypeReference<Collection<T>> ptr) {
|
||||
return List.of();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public ChatResponseSpec chat() {
|
||||
return new ChatResponseSpec(this.connector, this);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class ChatClientBuilder {
|
||||
|
||||
private final ChatConnector connector;
|
||||
|
||||
private final List<Media> defaultMedia = new ArrayList<>();
|
||||
|
||||
private final List<String> defaultFunctions = new ArrayList<>();
|
||||
|
||||
private String defaultSystem;
|
||||
|
||||
private String defaultUser;
|
||||
|
||||
ChatClientBuilder(ChatConnector connector) {
|
||||
Assert.notNull(connector, "the " + ChatConnector.class.getName() + " must be non-null!");
|
||||
this.connector = connector;
|
||||
}
|
||||
|
||||
public ChatClient build() {
|
||||
return new DefaultChatClient(this.connector, this.defaultSystem, this.defaultUser, this.defaultFunctions,
|
||||
this.defaultMedia);
|
||||
}
|
||||
|
||||
public ChatClientBuilder defaultSystem(String systemPrompt) {
|
||||
this.defaultSystem = systemPrompt;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ChatClientBuilder defaultFunctions(String... functionNames) {
|
||||
this.defaultFunctions.addAll(List.of(functionNames));
|
||||
return this;
|
||||
}
|
||||
|
||||
public ChatClientBuilder defaultUser(String userPrompt) {
|
||||
this.defaultUser = userPrompt;
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Deprecated(since = "1.0.0 M1", forRemoval = true)
|
||||
default String call(String message) {
|
||||
Prompt prompt = new Prompt(new UserMessage(message));
|
||||
Generation generation = call(prompt).getResult();
|
||||
return (generation != null) ? generation.getOutput().getContent() : "";
|
||||
}
|
||||
|
||||
@Deprecated(since = "1.0.0 M1", forRemoval = true)
|
||||
default String call(Message... messages) {
|
||||
Prompt prompt = new Prompt(Arrays.asList(messages));
|
||||
Generation generation = call(prompt).getResult();
|
||||
return (generation != null) ? generation.getOutput().getContent() : "";
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,52 +5,48 @@ import org.springframework.ai.chat.messages.Media;
|
||||
import org.springframework.ai.chat.prompt.Prompt;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
|
||||
/**
|
||||
* todo follow WebClient -> DefaultWebClient
|
||||
* todo make sure ChatConnector also supports call(Prompt) and then mark as deprecated
|
||||
*
|
||||
* @author Mark Pollack
|
||||
* @author Christian Tzolov
|
||||
* @author Josh Long
|
||||
* @author Arjen Poutsma
|
||||
*/
|
||||
public class DefaultChatClient implements ChatClient {
|
||||
class DefaultChatClient implements ChatClient {
|
||||
|
||||
private final ChatConnector connector;
|
||||
|
||||
private final String userPrompt, systemPrompt;
|
||||
private final String userText, systemText;
|
||||
|
||||
private final List<String> functions;
|
||||
private final List<String> functionNames;
|
||||
|
||||
private final List<Media> media;
|
||||
|
||||
public DefaultChatClient(ChatConnector connector, String defaultSystemPrompt, String defaultUserPrompt,
|
||||
List<String> defaultFunctions, List<Media> defaultMedia) {
|
||||
List<String> defaultFunctions, List<Media> defaultMedia) {
|
||||
this.connector = connector;
|
||||
this.userPrompt = defaultUserPrompt;
|
||||
this.systemPrompt = defaultSystemPrompt;
|
||||
this.functions = defaultFunctions;
|
||||
this.userText = defaultUserPrompt;
|
||||
this.systemText = defaultSystemPrompt;
|
||||
this.functionNames = defaultFunctions;
|
||||
this.media = defaultMedia;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChatClientRequest build() {
|
||||
return new ChatClientRequest(this.userPrompt, this.systemPrompt, this.functions, this.media);
|
||||
public ChatClientRequest call() {
|
||||
return new ChatClientRequest(this.connector, this.userText, this.systemText, this.functionNames, this.media,
|
||||
null);
|
||||
}
|
||||
|
||||
/**
|
||||
* use the new fluid DSL starting in {@link #call()}
|
||||
* @param prompt the {@link Prompt prompt} object
|
||||
* @return a {@link ChatResponse chat response}
|
||||
*/
|
||||
@Deprecated(forRemoval = true, since = "1.0.0 M1")
|
||||
@Override
|
||||
public ChatResponse call(Prompt prompt) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public ChatClientRequest user(Consumer<UserSpec> consumer) {
|
||||
return null;
|
||||
return this.connector.call(prompt);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -16,19 +16,14 @@
|
||||
package org.springframework.ai.chat.connector;
|
||||
|
||||
import org.springframework.ai.chat.ChatResponse;
|
||||
import org.springframework.ai.chat.Generation;
|
||||
import org.springframework.ai.chat.messages.Message;
|
||||
import org.springframework.ai.chat.messages.UserMessage;
|
||||
import org.springframework.ai.chat.prompt.Prompt;
|
||||
|
||||
public interface ChatConnector {
|
||||
import java.util.Arrays;
|
||||
|
||||
/*
|
||||
* default String call(String message) { Prompt prompt = new Prompt(new
|
||||
* UserMessage(message)); Generation generation = call(prompt).getResult(); return
|
||||
* (generation != null) ? generation.getOutput().getContent() : ""; }
|
||||
*
|
||||
* public String call(Message... messages) { Prompt prompt = new
|
||||
* Prompt(Arrays.asList(messages)); Generation generation = call(prompt).getResult();
|
||||
* return (generation != null) ? generation.getOutput().getContent() : ""; }
|
||||
*/
|
||||
public interface ChatConnector {
|
||||
|
||||
ChatResponse call(Prompt prompt);
|
||||
|
||||
|
||||
@@ -66,9 +66,9 @@ public abstract class AbstractMessage implements Message {
|
||||
protected AbstractMessage(MessageType messageType, String textContent, Collection<Media> media,
|
||||
Map<String, Object> metadata) {
|
||||
|
||||
Assert.notNull(messageType, "Message type must not be null");
|
||||
Assert.notNull(messageType, "MessageType must not be null");
|
||||
Assert.notNull(textContent, "Content must not be null");
|
||||
Assert.notNull(media, "media data must not be null");
|
||||
Assert.notNull(media, "Media must not be null");
|
||||
|
||||
this.messageType = messageType;
|
||||
this.textContent = textContent;
|
||||
|
||||
@@ -46,8 +46,8 @@ public class PromptTransformingChatService implements ChatService {
|
||||
private List<ChatServiceListener> chatServiceListeners;
|
||||
|
||||
public PromptTransformingChatService(ChatConnector chatConnector, List<PromptTransformer> retrievers,
|
||||
List<PromptTransformer> documentPostProcessors, List<PromptTransformer> augmentors,
|
||||
List<ChatServiceListener> chatServiceListeners) {
|
||||
List<PromptTransformer> documentPostProcessors, List<PromptTransformer> augmentors,
|
||||
List<ChatServiceListener> chatServiceListeners) {
|
||||
Objects.requireNonNull(chatConnector, "chatConnector must not be null");
|
||||
this.chatConnector = chatConnector;
|
||||
this.retrievers = retrievers;
|
||||
|
||||
@@ -26,18 +26,18 @@ public interface FunctionCallback {
|
||||
/**
|
||||
* @return Returns the Function name. Unique within the model.
|
||||
*/
|
||||
public String getName();
|
||||
String getName();
|
||||
|
||||
/**
|
||||
* @return Returns the function description. This description is used by the model do
|
||||
* decide if the function should be called or not.
|
||||
*/
|
||||
public String getDescription();
|
||||
String getDescription();
|
||||
|
||||
/**
|
||||
* @return Returns the JSON schema of the function input type.
|
||||
*/
|
||||
public String getInputTypeSchema();
|
||||
String getInputTypeSchema();
|
||||
|
||||
/**
|
||||
* Called when a model detects and triggers a function call. The model is responsible
|
||||
@@ -47,6 +47,6 @@ public interface FunctionCallback {
|
||||
* model.
|
||||
* @return String containing the function call response.
|
||||
*/
|
||||
public String call(String functionInput);
|
||||
String call(String functionInput);
|
||||
|
||||
}
|
||||
@@ -15,11 +15,7 @@
|
||||
*/
|
||||
package org.springframework.ai.model.function;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.function.Function;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonClassDescription;
|
||||
|
||||
import org.springframework.ai.model.function.FunctionCallbackWrapper.Builder.SchemaType;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.cloud.function.context.catalog.FunctionTypeUtils;
|
||||
@@ -32,6 +28,9 @@ import org.springframework.lang.NonNull;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* A Spring {@link ApplicationContextAware} implementation that provides a way to retrieve
|
||||
* a {@link Function} from the Spring context and wrap it into a {@link FunctionCallback}.
|
||||
@@ -47,6 +46,7 @@ import org.springframework.util.StringUtils;
|
||||
*
|
||||
* @author Christian Tzolov
|
||||
* @author Christopher Smith
|
||||
* @author Josh Long
|
||||
*/
|
||||
public class FunctionCallbackContext implements ApplicationContextAware {
|
||||
|
||||
@@ -63,6 +63,19 @@ public class FunctionCallbackContext implements ApplicationContextAware {
|
||||
this.applicationContext = (GenericApplicationContext) applicationContext;
|
||||
}
|
||||
|
||||
public <I, O> FunctionCallback getFunctionCallback(String beanName, String defaultDescription,
|
||||
Function<I, O> function, SchemaType schemaType) {
|
||||
var beanType = FunctionTypeUtils.discoverFunctionTypeFromClass(function.getClass());
|
||||
var functionInputType = TypeResolverHelper.getFunctionArgumentType(beanType, 0);
|
||||
var functionInputClass = FunctionTypeUtils.getRawType(functionInputType);
|
||||
return FunctionCallbackWrapper.builder(function)
|
||||
.withName(beanName)
|
||||
.withSchemaType(schemaType)
|
||||
.withDescription(defaultDescription)
|
||||
.withInputType(functionInputClass)
|
||||
.build();
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
public FunctionCallback getFunctionCallback(@NonNull String beanName, @Nullable String defaultDescription) {
|
||||
|
||||
|
||||
@@ -81,7 +81,7 @@ public class SummaryMetadataEnricher implements DocumentTransformer {
|
||||
}
|
||||
|
||||
public SummaryMetadataEnricher(ChatConnector chatConnector, List<SummaryType> summaryTypes, String summaryTemplate,
|
||||
MetadataMode metadataMode) {
|
||||
MetadataMode metadataMode) {
|
||||
Assert.notNull(chatConnector, "ChatConnector must not be null");
|
||||
Assert.hasText(summaryTemplate, "Summary template must not be empty");
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ class ChatConnectorTests {
|
||||
String userMessage = "Zero Wing";
|
||||
String responseMessage = "All your bases are belong to us";
|
||||
|
||||
ChatConnector mockClient = Mockito.mock(ChatConnector.class);
|
||||
ChatClient mockClient = Mockito.mock(ChatClient.class);
|
||||
|
||||
AssistantMessage mockAssistantMessage = Mockito.mock(AssistantMessage.class);
|
||||
when(mockAssistantMessage.getContent()).thenReturn(responseMessage);
|
||||
|
||||
@@ -48,7 +48,7 @@ import static org.mockito.Mockito.when;
|
||||
public class ChatMemoryTests {
|
||||
|
||||
@Mock
|
||||
ChatConnector chatConnector;
|
||||
ChatConnector chatConnector;
|
||||
|
||||
@Mock
|
||||
StreamingChatClient streamingChatClient;
|
||||
|
||||
@@ -58,8 +58,8 @@ public class AnthropicAutoConfiguration {
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public AnthropicChatConnector anthropicChatClient(AnthropicApi anthropicApi, AnthropicChatProperties chatProperties,
|
||||
RetryTemplate retryTemplate, FunctionCallbackContext functionCallbackContext,
|
||||
List<FunctionCallback> toolFunctionCallbacks) {
|
||||
RetryTemplate retryTemplate, FunctionCallbackContext functionCallbackContext,
|
||||
List<FunctionCallback> toolFunctionCallbacks) {
|
||||
|
||||
if (!CollectionUtils.isEmpty(toolFunctionCallbacks)) {
|
||||
chatProperties.getOptions().getFunctionCallbacks().addAll(toolFunctionCallbacks);
|
||||
|
||||
@@ -59,8 +59,8 @@ public class AzureOpenAiAutoConfiguration {
|
||||
@ConditionalOnProperty(prefix = AzureOpenAiChatProperties.CONFIG_PREFIX, name = "enabled", havingValue = "true",
|
||||
matchIfMissing = true)
|
||||
public AzureOpenAiChatConnector azureOpenAiChatClient(OpenAIClient openAIClient,
|
||||
AzureOpenAiChatProperties chatProperties, List<FunctionCallback> toolFunctionCallbacks,
|
||||
FunctionCallbackContext functionCallbackContext) {
|
||||
AzureOpenAiChatProperties chatProperties, List<FunctionCallback> toolFunctionCallbacks,
|
||||
FunctionCallbackContext functionCallbackContext) {
|
||||
|
||||
if (!CollectionUtils.isEmpty(toolFunctionCallbacks)) {
|
||||
chatProperties.getOptions().getFunctionCallbacks().addAll(toolFunctionCallbacks);
|
||||
|
||||
@@ -60,7 +60,7 @@ public class BedrockAnthropicChatAutoConfiguration {
|
||||
@Bean
|
||||
@ConditionalOnBean(AnthropicChatBedrockApi.class)
|
||||
public BedrockAnthropicChatConnector anthropicChatClient(AnthropicChatBedrockApi anthropicApi,
|
||||
BedrockAnthropicChatProperties properties) {
|
||||
BedrockAnthropicChatProperties properties) {
|
||||
return new BedrockAnthropicChatConnector(anthropicApi, properties.getOptions());
|
||||
}
|
||||
|
||||
|
||||
@@ -60,7 +60,7 @@ public class BedrockAnthropic3ChatAutoConfiguration {
|
||||
@Bean
|
||||
@ConditionalOnBean(Anthropic3ChatBedrockApi.class)
|
||||
public BedrockAnthropic3ChatConnector anthropic3ChatClient(Anthropic3ChatBedrockApi anthropicApi,
|
||||
BedrockAnthropic3ChatProperties properties) {
|
||||
BedrockAnthropic3ChatProperties properties) {
|
||||
return new BedrockAnthropic3ChatConnector(anthropicApi, properties.getOptions());
|
||||
}
|
||||
|
||||
|
||||
@@ -58,7 +58,7 @@ public class BedrockCohereChatAutoConfiguration {
|
||||
@Bean
|
||||
@ConditionalOnBean(CohereChatBedrockApi.class)
|
||||
public BedrockCohereChatConnector cohereChatClient(CohereChatBedrockApi cohereChatApi,
|
||||
BedrockCohereChatProperties properties) {
|
||||
BedrockCohereChatProperties properties) {
|
||||
|
||||
return new BedrockCohereChatConnector(cohereChatApi, properties.getOptions());
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@ public class BedrockLlamaChatAutoConfiguration {
|
||||
@Bean
|
||||
@ConditionalOnBean(LlamaChatBedrockApi.class)
|
||||
public BedrockLlamaChatConnector llamaChatClient(LlamaChatBedrockApi llamaApi,
|
||||
BedrockLlamaChatProperties properties) {
|
||||
BedrockLlamaChatProperties properties) {
|
||||
|
||||
return new BedrockLlamaChatConnector(llamaApi, properties.getOptions());
|
||||
}
|
||||
|
||||
@@ -58,7 +58,7 @@ public class BedrockTitanChatAutoConfiguration {
|
||||
@Bean
|
||||
@ConditionalOnBean(TitanChatBedrockApi.class)
|
||||
public BedrockTitanChatConnector titanChatClient(TitanChatBedrockApi titanChatApi,
|
||||
BedrockTitanChatProperties properties) {
|
||||
BedrockTitanChatProperties properties) {
|
||||
|
||||
return new BedrockTitanChatConnector(titanChatApi, properties.getOptions());
|
||||
}
|
||||
|
||||
@@ -70,9 +70,9 @@ public class MistralAiAutoConfiguration {
|
||||
@ConditionalOnProperty(prefix = MistralAiChatProperties.CONFIG_PREFIX, name = "enabled", havingValue = "true",
|
||||
matchIfMissing = true)
|
||||
public MistralAiChatConnector mistralAiChatClient(MistralAiCommonProperties commonProperties,
|
||||
MistralAiChatProperties chatProperties, RestClient.Builder restClientBuilder,
|
||||
List<FunctionCallback> toolFunctionCallbacks, FunctionCallbackContext functionCallbackContext,
|
||||
RetryTemplate retryTemplate, ResponseErrorHandler responseErrorHandler) {
|
||||
MistralAiChatProperties chatProperties, RestClient.Builder restClientBuilder,
|
||||
List<FunctionCallback> toolFunctionCallbacks, FunctionCallbackContext functionCallbackContext,
|
||||
RetryTemplate retryTemplate, ResponseErrorHandler responseErrorHandler) {
|
||||
|
||||
var mistralAiApi = mistralAiApi(chatProperties.getApiKey(), commonProperties.getApiKey(),
|
||||
chatProperties.getBaseUrl(), commonProperties.getBaseUrl(), restClientBuilder, responseErrorHandler);
|
||||
|
||||
@@ -55,9 +55,9 @@ public class OpenAiAutoConfiguration {
|
||||
@ConditionalOnProperty(prefix = OpenAiChatProperties.CONFIG_PREFIX, name = "enabled", havingValue = "true",
|
||||
matchIfMissing = true)
|
||||
public OpenAiChatConnector openAiChatClient(OpenAiConnectionProperties commonProperties,
|
||||
OpenAiChatProperties chatProperties, RestClient.Builder restClientBuilder,
|
||||
List<FunctionCallback> toolFunctionCallbacks, FunctionCallbackContext functionCallbackContext,
|
||||
RetryTemplate retryTemplate, ResponseErrorHandler responseErrorHandler) {
|
||||
OpenAiChatProperties chatProperties, RestClient.Builder restClientBuilder,
|
||||
List<FunctionCallback> toolFunctionCallbacks, FunctionCallbackContext functionCallbackContext,
|
||||
RetryTemplate retryTemplate, ResponseErrorHandler responseErrorHandler) {
|
||||
|
||||
var openAiApi = openAiApi(chatProperties.getBaseUrl(), commonProperties.getBaseUrl(),
|
||||
chatProperties.getApiKey(), commonProperties.getApiKey(), restClientBuilder, responseErrorHandler);
|
||||
|
||||
@@ -75,8 +75,8 @@ public class VertexAiGeminiAutoConfiguration {
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public VertexAiGeminiChatConnector vertexAiGeminiChat(VertexAI vertexAi,
|
||||
VertexAiGeminiChatProperties chatProperties, List<FunctionCallback> toolFunctionCallbacks,
|
||||
ApplicationContext context) {
|
||||
VertexAiGeminiChatProperties chatProperties, List<FunctionCallback> toolFunctionCallbacks,
|
||||
ApplicationContext context) {
|
||||
|
||||
FunctionCallbackContext functionCallbackContext = springAiFunctionManager(context);
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ public class VertexAiPalm2AutoConfiguration {
|
||||
@ConditionalOnProperty(prefix = VertexAiPlam2ChatProperties.CONFIG_PREFIX, name = "enabled", havingValue = "true",
|
||||
matchIfMissing = true)
|
||||
public VertexAiPaLm2ChatConnector vertexAiChatClient(VertexAiPaLm2Api vertexAiApi,
|
||||
VertexAiPlam2ChatProperties chatProperties) {
|
||||
VertexAiPlam2ChatProperties chatProperties) {
|
||||
return new VertexAiPaLm2ChatConnector(vertexAiApi, chatProperties.getOptions());
|
||||
}
|
||||
|
||||
|
||||
@@ -15,17 +15,13 @@
|
||||
*/
|
||||
package org.springframework.ai.autoconfigure.anthropic;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable;
|
||||
import org.springframework.ai.anthropic.AnthropicChatConnector;
|
||||
import reactor.core.publisher.Flux;
|
||||
|
||||
import org.springframework.ai.autoconfigure.retry.SpringAiRetryAutoConfiguration;
|
||||
import org.springframework.ai.chat.ChatClient;
|
||||
import org.springframework.ai.chat.ChatResponse;
|
||||
import org.springframework.ai.chat.Generation;
|
||||
import org.springframework.ai.chat.messages.AssistantMessage;
|
||||
@@ -34,6 +30,10 @@ import org.springframework.ai.chat.prompt.Prompt;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.autoconfigure.web.client.RestClientAutoConfiguration;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
import reactor.core.publisher.Flux;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
@@ -50,7 +50,7 @@ public class AnthropicAutoConfigurationIT {
|
||||
@Test
|
||||
void generate() {
|
||||
contextRunner.run(context -> {
|
||||
AnthropicChatConnector chatClient = context.getBean(AnthropicChatConnector.class);
|
||||
ChatClient chatClient = ChatClient.builder(context.getBean(AnthropicChatConnector.class)).build();
|
||||
String response = chatClient.call("Hello");
|
||||
assertThat(response).isNotEmpty();
|
||||
logger.info("Response: " + response);
|
||||
|
||||
@@ -15,14 +15,10 @@
|
||||
*/
|
||||
package org.springframework.ai.autoconfigure.anthropic.tool;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
|
||||
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.anthropic.AnthropicChatConnector;
|
||||
import org.springframework.ai.anthropic.AnthropicChatOptions;
|
||||
import org.springframework.ai.anthropic.api.AnthropicApi;
|
||||
@@ -40,6 +36,9 @@ import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Description;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
@EnabledIfEnvironmentVariable(named = "ANTHROPIC_API_KEY", matches = ".*")
|
||||
|
||||
@@ -15,25 +15,25 @@
|
||||
*/
|
||||
package org.springframework.ai.autoconfigure.mistralai;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable;
|
||||
import org.springframework.ai.mistralai.MistralAiChatConnector;
|
||||
import reactor.core.publisher.Flux;
|
||||
|
||||
import org.springframework.ai.autoconfigure.retry.SpringAiRetryAutoConfiguration;
|
||||
import org.springframework.ai.chat.ChatClient;
|
||||
import org.springframework.ai.chat.ChatResponse;
|
||||
import org.springframework.ai.chat.messages.UserMessage;
|
||||
import org.springframework.ai.chat.prompt.Prompt;
|
||||
import org.springframework.ai.embedding.EmbeddingResponse;
|
||||
import org.springframework.ai.mistralai.MistralAiChatConnector;
|
||||
import org.springframework.ai.mistralai.MistralAiEmbeddingClient;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.autoconfigure.web.client.RestClientAutoConfiguration;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
import reactor.core.publisher.Flux;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
@@ -54,7 +54,7 @@ public class MistralAiAutoConfigurationIT {
|
||||
@Test
|
||||
void generate() {
|
||||
contextRunner.run(context -> {
|
||||
MistralAiChatConnector client = context.getBean(MistralAiChatConnector.class);
|
||||
ChatClient client = ChatClient.builder(context.getBean(MistralAiChatConnector.class)).build();
|
||||
String response = client.call("Hello");
|
||||
assertThat(response).isNotEmpty();
|
||||
logger.info("Response: " + response);
|
||||
|
||||
@@ -23,6 +23,7 @@ import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable;
|
||||
import org.springframework.ai.chat.ChatClient;
|
||||
import org.springframework.ai.chat.messages.UserMessage;
|
||||
import org.springframework.ai.chat.prompt.Prompt;
|
||||
import org.springframework.ai.image.ImagePrompt;
|
||||
@@ -55,7 +56,7 @@ public class OpenAiAutoConfigurationIT {
|
||||
@Test
|
||||
void generate() {
|
||||
contextRunner.run(context -> {
|
||||
OpenAiChatConnector client = context.getBean(OpenAiChatConnector.class);
|
||||
ChatClient client = ChatClient.builder(context.getBean(OpenAiChatConnector.class)).build();
|
||||
String response = client.call("Hello");
|
||||
assertThat(response).isNotEmpty();
|
||||
logger.info("Response: " + response);
|
||||
|
||||
@@ -15,20 +15,20 @@
|
||||
*/
|
||||
package org.springframework.ai.autoconfigure.vertexai.gemini;
|
||||
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable;
|
||||
import reactor.core.publisher.Flux;
|
||||
|
||||
import org.springframework.ai.chat.ChatClient;
|
||||
import org.springframework.ai.chat.ChatResponse;
|
||||
import org.springframework.ai.chat.messages.UserMessage;
|
||||
import org.springframework.ai.chat.prompt.Prompt;
|
||||
import org.springframework.ai.vertexai.gemini.VertexAiGeminiChatConnector;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
import reactor.core.publisher.Flux;
|
||||
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
@@ -46,7 +46,7 @@ public class VertexAiGeminiAutoConfigurationIT {
|
||||
@Test
|
||||
void generate() {
|
||||
contextRunner.run(context -> {
|
||||
VertexAiGeminiChatConnector client = context.getBean(VertexAiGeminiChatConnector.class);
|
||||
ChatClient client = ChatClient.builder(context.getBean(VertexAiGeminiChatConnector.class)).build();
|
||||
String response = client.call("Hello");
|
||||
assertThat(response).isNotEmpty();
|
||||
logger.info("Response: " + response);
|
||||
|
||||
@@ -22,6 +22,7 @@ import org.apache.commons.logging.LogFactory;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable;
|
||||
|
||||
import org.springframework.ai.chat.ChatClient;
|
||||
import org.springframework.ai.embedding.EmbeddingResponse;
|
||||
import org.springframework.ai.vertexai.palm2.VertexAiPaLm2ChatConnector;
|
||||
import org.springframework.ai.vertexai.palm2.VertexAiPaLm2EmbeddingClient;
|
||||
@@ -48,8 +49,8 @@ public class VertexAiPaLm2AutoConfigurationIT {
|
||||
@Test
|
||||
void generate() {
|
||||
contextRunner.run(context -> {
|
||||
VertexAiPaLm2ChatConnector client = context.getBean(VertexAiPaLm2ChatConnector.class);
|
||||
|
||||
VertexAiPaLm2ChatConnector connector = context.getBean(VertexAiPaLm2ChatConnector.class);
|
||||
ChatClient client = ChatClient.builder(connector).build();
|
||||
String response = client.call("Hello");
|
||||
|
||||
assertThat(response).isNotEmpty();
|
||||
|
||||
Reference in New Issue
Block a user