Introduce support for GenAI for Tanzu Platform bindings.

Currently this is a PreProvisionedService with a secret derived from the TPCF service key.

Signed-off-by: Stuart Charlton <stuart.charlton@broadcom.com>
This commit is contained in:
Stuart Charlton
2024-08-21 15:26:16 -06:00
committed by Soby Chacko
parent 72011baf50
commit 86cfe6158a
3 changed files with 127 additions and 0 deletions

View File

@@ -0,0 +1,47 @@
package org.springframework.ai.bindings;
import org.springframework.cloud.bindings.Binding;
import org.springframework.cloud.bindings.Bindings;
import org.springframework.cloud.bindings.boot.BindingsPropertiesProcessor;
import org.springframework.core.env.Environment;
import java.util.Arrays;
import java.util.Map;
/**
* An implementation of {@link BindingsPropertiesProcessor} that detects {@link Binding}s
* of type: {@value TYPE}.
*
* @author Stuart Charlton
*/
public class TanzuBindingsPropertiesProcessor implements BindingsPropertiesProcessor {
/**
* The {@link Binding} type that this processor is interested in: {@value}.
**/
public static final String TYPE = "genai";
@Override
public void process(Environment environment, Bindings bindings, Map<String, Object> properties) {
if (!BindingsValidator.isTypeEnabled(environment, TYPE)) {
return;
}
bindings.filterBindings(TYPE).forEach(binding -> {
if (binding.getSecret().get("model-capabilities") != null) {
String[] capabilities = binding.getSecret().get("model-capabilities").trim().split("\\s*,\\s*");
if (Arrays.stream(capabilities).anyMatch("chat"::equals)) {
properties.put("spring.ai.openai.chat.api-key", binding.getSecret().get("api-key"));
properties.put("spring.ai.openai.chat.base-url", binding.getSecret().get("uri"));
properties.put("spring.ai.openai.chat.options.model", binding.getSecret().get("model-name"));
}
if (Arrays.stream(capabilities).anyMatch("embedding"::equals)) {
properties.put("spring.ai.openai.embedding.api-key", binding.getSecret().get("api-key"));
properties.put("spring.ai.openai.embedding.base-url", binding.getSecret().get("uri"));
properties.put("spring.ai.openai.embedding.options.model", binding.getSecret().get("model-name"));
}
}
});
}
}

View File

@@ -3,4 +3,5 @@ org.springframework.cloud.bindings.boot.BindingsPropertiesProcessor=\
org.springframework.ai.bindings.ChromaBindingsPropertiesProcessor,\
org.springframework.ai.bindings.OllamaBindingsPropertiesProcessor,\
org.springframework.ai.bindings.OpenAiBindingsPropertiesProcessor,\
org.springframework.ai.bindings.TanzuBindingsPropertiesProcessor,\
org.springframework.ai.bindings.WeaviateBindingsPropertiesProcessor

View File

@@ -0,0 +1,79 @@
package org.springframework.ai.bindings;
import org.junit.jupiter.api.Test;
import org.springframework.cloud.bindings.Binding;
import org.springframework.cloud.bindings.Bindings;
import org.springframework.mock.env.MockEnvironment;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;
import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.ai.bindings.BindingsValidator.CONFIG_PATH;
/**
* Unit tests for {@link TanzuBindingsPropertiesProcessor}.
*
* @author Stuart Charlton
*/
class TanzuBindingsPropertiesProcessorTests {
private final Bindings bindings = new Bindings(new Binding("test-name", Paths.get("test-path"),
// @formatter:off
Map.of(
Binding.TYPE, TanzuBindingsPropertiesProcessor.TYPE,
"api-key", "demo",
"uri", "https://my.openai.example.net",
"model-name", "llava1.6",
"model-capabilities", " chat , vision "
)),
new Binding("test-name2", Paths.get("test-path2"),
Map.of(
Binding.TYPE, TanzuBindingsPropertiesProcessor.TYPE,
"api-key", "demo2",
"uri", "https://my.openai2.example.net",
"model-name", "text-embed-large",
"model-capabilities", "embedding")));
// @formatter:on
private final Bindings bindingsMissingModelCapabilities = new Bindings(
new Binding("test-name", Paths.get("test-path"),
// @formatter:off
Map.of(
Binding.TYPE, TanzuBindingsPropertiesProcessor.TYPE,
"api-key", "demo",
"uri", "https://my.openai.example.net"
)));
// @formatter:on
private final MockEnvironment environment = new MockEnvironment();
private final Map<String, Object> properties = new HashMap<>();
@Test
void propertiesAreContributed() {
new TanzuBindingsPropertiesProcessor().process(environment, bindings, properties);
assertThat(properties).containsEntry("spring.ai.openai.chat.api-key", "demo");
assertThat(properties).containsEntry("spring.ai.openai.chat.base-url", "https://my.openai.example.net");
assertThat(properties).containsEntry("spring.ai.openai.chat.options.model", "llava1.6");
assertThat(properties).containsEntry("spring.ai.openai.embedding.api-key", "demo2");
assertThat(properties).containsEntry("spring.ai.openai.embedding.base-url", "https://my.openai2.example.net");
assertThat(properties).containsEntry("spring.ai.openai.embedding.options.model", "text-embed-large");
}
@Test
void propertiesAreMissingModelCapabilities() {
new TanzuBindingsPropertiesProcessor().process(environment, bindingsMissingModelCapabilities, properties);
assertThat(properties).isEmpty();
}
@Test
void whenDisabledThenPropertiesAreNotContributed() {
environment.setProperty("%s.genai.enabled".formatted(CONFIG_PATH), "false");
new TanzuBindingsPropertiesProcessor().process(environment, bindings, properties);
assertThat(properties).isEmpty();
}
}