Refine delineation of Embedding properties from OpenAI (client) properties.

Though the property names are different, for example 'spring.ai.openai.api-key' and 'spring.ai.openai.embedding-api-key,
by introducing an additional property namespace, 'spring.ai.openai.embedding.*', this enables the configuration of embeddings
to be properly encapsulated and related in Spring Boot fashion.

Closes #102
This commit is contained in:
John Blum
2023-11-14 18:20:22 -08:00
committed by Mark Pollack
parent 409fa1521d
commit 820eb5f0ab
3 changed files with 133 additions and 36 deletions

View File

@@ -49,19 +49,25 @@ public class OpenAiAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public OpenAiClient openAiClient(OpenAiProperties openAiProperties) {
OpenAiClient openAiClient = new OpenAiClient(theoOpenAiService(openAiProperties.getBaseUrl(),
openAiProperties.getApiKey(), openAiProperties.getDuration()));
OpenAiService openAiService = theoOpenAiService(openAiProperties.getBaseUrl(), openAiProperties.getApiKey(),
openAiProperties.getDuration());
OpenAiClient openAiClient = new OpenAiClient(openAiService);
openAiClient.setTemperature(openAiProperties.getTemperature());
openAiClient.setModel(openAiProperties.getModel());
return openAiClient;
}
@Bean
@ConditionalOnMissingBean
public EmbeddingClient openAiEmbeddingClient(OpenAiProperties openAiProperties) {
return new OpenAiEmbeddingClient(theoOpenAiService(openAiProperties.getEmbeddingBaseUrl(),
openAiProperties.getEmbeddingApiKey(), openAiProperties.getDuration()),
openAiProperties.getEmbeddingModel());
OpenAiService openAiService = theoOpenAiService(openAiProperties.getEmbedding().getBaseUrl(),
openAiProperties.getEmbedding().getApiKey(), openAiProperties.getDuration());
return new OpenAiEmbeddingClient(openAiService, openAiProperties.getEmbedding().getModel());
}
private OpenAiService theoOpenAiService(String baseUrl, String apiKey, Duration duration) {

View File

@@ -16,12 +16,13 @@
package org.springframework.ai.autoconfigure.openai;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.util.StringUtils;
import static org.springframework.ai.autoconfigure.openai.OpenAiProperties.CONFIG_PREFIX;
import java.time.Duration;
import static org.springframework.ai.autoconfigure.openai.OpenAiProperties.CONFIG_PREFIX;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
@ConfigurationProperties(CONFIG_PREFIX)
public class OpenAiProperties {
@@ -32,18 +33,14 @@ public class OpenAiProperties {
private Duration duration = Duration.ofSeconds(60);
private final Embedding embedding = new Embedding(this);
private String apiKey;
private String model = "gpt-3.5-turbo";
private String baseUrl = "https://api.openai.com";
private String embeddingModel = "text-embedding-ada-002";
private String embeddingBaseUrl;
private String embeddingApiKey;
public String getApiKey() {
return this.apiKey;
}
@@ -60,6 +57,14 @@ public class OpenAiProperties {
this.model = model;
}
public String getBaseUrl() {
return this.baseUrl;
}
public void setBaseUrl(String baseUrl) {
this.baseUrl = baseUrl;
}
public Double getTemperature() {
return this.temperature;
}
@@ -76,36 +81,53 @@ public class OpenAiProperties {
this.duration = duration;
}
public String getBaseUrl() {
return this.baseUrl;
public Embedding getEmbedding() {
return this.embedding;
}
public void setBaseUrl(String baseUrl) {
this.baseUrl = baseUrl;
}
public static class Embedding {
public String getEmbeddingModel() {
return this.embeddingModel;
}
private final OpenAiProperties openAiProperties;
public void setEmbeddingModel(String embeddingModel) {
this.embeddingModel = embeddingModel;
}
private String apiKey;
public void setEmbeddingBaseUrl(String embeddingBaseUrl) {
this.embeddingBaseUrl = embeddingBaseUrl;
}
private String model = "text-embedding-ada-002";
public String getEmbeddingBaseUrl() {
return StringUtils.hasText(this.embeddingBaseUrl) ? this.embeddingBaseUrl : this.baseUrl;
}
private String baseUrl;
public String getEmbeddingApiKey() {
return StringUtils.hasText(this.embeddingApiKey) ? this.embeddingApiKey : this.apiKey;
}
protected Embedding(OpenAiProperties openAiProperties) {
Assert.notNull(openAiProperties, "OpenAiProperties must not be null");
this.openAiProperties = openAiProperties;
}
public OpenAiProperties getOpenAiProperties() {
return openAiProperties;
}
public String getApiKey() {
return StringUtils.hasText(this.apiKey) ? this.apiKey : getOpenAiProperties().getApiKey();
}
public void setApiKey(String embeddingApiKey) {
this.apiKey = embeddingApiKey;
}
public String getModel() {
return this.model;
}
public void setModel(String model) {
this.model = model;
}
public String getBaseUrl() {
return StringUtils.hasText(this.baseUrl) ? this.baseUrl : getOpenAiProperties().getBaseUrl();
}
public void setBaseUrl(String baseUrl) {
this.baseUrl = baseUrl;
}
public void setEmbeddingApiKey(String embeddingApiKey) {
this.embeddingApiKey = embeddingApiKey;
}
}

View File

@@ -0,0 +1,69 @@
/*
* Copyright 2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.ai.autoconfigure.openai;
import static org.assertj.core.api.Assertions.assertThat;
import java.time.Duration;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.test.context.SpringBootTest;
/**
* Unit Tests for {@link OpenAiProperties}.
*
* @author John Blum
* @since 0.7.1
*/
@SpringBootTest(properties = { "spring.ai.openai.api-key=abc123", "spring.ai.openai.model=claudia-shiffer-5",
"spring.ai.openai.base-url=https://api.openai.spring.io/eieioh", "spring.ai.openai.temperature=0.5",
"spring.ai.openai.duration=30s", "spring.ai.openai.embedding.base-url=https://api.openai.spring.io/embedding" })
@SuppressWarnings("unused")
class OpenAiPropertiesTests {
@Autowired
private OpenAiProperties openAiProperties;
@Test
void openAiPropertiesAreCorrect() {
assertThat(this.openAiProperties).isNotNull();
assertThat(this.openAiProperties.getApiKey()).isEqualTo("abc123");
assertThat(this.openAiProperties.getModel()).isEqualTo("claudia-shiffer-5");
assertThat(this.openAiProperties.getBaseUrl()).isEqualTo("https://api.openai.spring.io/eieioh");
assertThat(this.openAiProperties.getTemperature()).isEqualTo(0.5d);
assertThat(this.openAiProperties.getDuration()).isEqualTo(Duration.ofSeconds(30L));
OpenAiProperties.Embedding embedding = this.openAiProperties.getEmbedding();
assertThat(embedding).isNotNull();
assertThat(embedding.getApiKey()).isEqualTo(this.openAiProperties.getApiKey());
assertThat(embedding.getModel()).isEqualTo("text-embedding-ada-002");
assertThat(embedding.getBaseUrl()).isEqualTo("https://api.openai.spring.io/embedding");
}
@SpringBootConfiguration
@EnableConfigurationProperties(OpenAiProperties.class)
static class TestConfiguration {
}
}