Streamline ChatOptions
* Surface more configuration APIs to ChatOptions * Use abstraction in Observations directly instead of dedicated implementation * Simplify metadata config in observations for defined models * Improve merging of runtime and default options in OpenAI * Fix missing option in Mistral AI Relates to gh-1148 Signed-off-by: Thomas Vitale <ThomasVitale@users.noreply.github.com>
This commit is contained in:
@@ -37,6 +37,7 @@ import org.springframework.util.Assert;
|
||||
* The options to be used when sending a chat request to the Anthropic API.
|
||||
*
|
||||
* @author Christian Tzolov
|
||||
* @author Thomas Vitale
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@JsonInclude(Include.NON_NULL)
|
||||
@@ -149,6 +150,7 @@ public class AnthropicChatOptions implements ChatOptions, FunctionCallingOptions
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getModel() {
|
||||
return model;
|
||||
}
|
||||
@@ -157,6 +159,7 @@ public class AnthropicChatOptions implements ChatOptions, FunctionCallingOptions
|
||||
this.model = model;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getMaxTokens() {
|
||||
return this.maxTokens;
|
||||
}
|
||||
@@ -173,6 +176,7 @@ public class AnthropicChatOptions implements ChatOptions, FunctionCallingOptions
|
||||
this.metadata = metadata;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getStopSequences() {
|
||||
return this.stopSequences;
|
||||
}
|
||||
@@ -199,6 +203,7 @@ public class AnthropicChatOptions implements ChatOptions, FunctionCallingOptions
|
||||
this.topP = topP;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getTopK() {
|
||||
return this.topK;
|
||||
}
|
||||
@@ -229,6 +234,18 @@ public class AnthropicChatOptions implements ChatOptions, FunctionCallingOptions
|
||||
this.functions = functions;
|
||||
}
|
||||
|
||||
@Override
|
||||
@JsonIgnore
|
||||
public Float getFrequencyPenalty() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@JsonIgnore
|
||||
public Float getPresencePenalty() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnthropicChatOptions copy() {
|
||||
return fromOptions(this);
|
||||
|
||||
@@ -38,6 +38,7 @@ import org.springframework.util.Assert;
|
||||
* prompt data.
|
||||
*
|
||||
* @author Christian Tzolov
|
||||
* @author Thomas Vitale
|
||||
*/
|
||||
@JsonInclude(Include.NON_NULL)
|
||||
public class AzureOpenAiChatOptions implements FunctionCallingOptions, ChatOptions {
|
||||
@@ -108,7 +109,7 @@ public class AzureOpenAiChatOptions implements FunctionCallingOptions, ChatOptio
|
||||
* output new topics.
|
||||
*/
|
||||
@JsonProperty(value = "presence_penalty")
|
||||
private Double presencePenalty;
|
||||
private Float presencePenalty;
|
||||
|
||||
/**
|
||||
* A value that influences the probability of generated tokens appearing based on
|
||||
@@ -117,7 +118,7 @@ public class AzureOpenAiChatOptions implements FunctionCallingOptions, ChatOptio
|
||||
* model repeating the same statements verbatim.
|
||||
*/
|
||||
@JsonProperty(value = "frequency_penalty")
|
||||
private Double frequencyPenalty;
|
||||
private Float frequencyPenalty;
|
||||
|
||||
/**
|
||||
* The deployment name as defined in Azure Open AI Studio when creating a deployment
|
||||
@@ -182,9 +183,7 @@ public class AzureOpenAiChatOptions implements FunctionCallingOptions, ChatOptio
|
||||
}
|
||||
|
||||
public Builder withFrequencyPenalty(Float frequencyPenalty) {
|
||||
if (frequencyPenalty != null) {
|
||||
this.options.frequencyPenalty = frequencyPenalty.doubleValue();
|
||||
}
|
||||
this.options.frequencyPenalty = frequencyPenalty;
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -204,9 +203,7 @@ public class AzureOpenAiChatOptions implements FunctionCallingOptions, ChatOptio
|
||||
}
|
||||
|
||||
public Builder withPresencePenalty(Float presencePenalty) {
|
||||
if (presencePenalty != null) {
|
||||
this.options.presencePenalty = presencePenalty.doubleValue();
|
||||
}
|
||||
this.options.presencePenalty = presencePenalty;
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -259,6 +256,7 @@ public class AzureOpenAiChatOptions implements FunctionCallingOptions, ChatOptio
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getMaxTokens() {
|
||||
return this.maxTokens;
|
||||
}
|
||||
@@ -291,6 +289,17 @@ public class AzureOpenAiChatOptions implements FunctionCallingOptions, ChatOptio
|
||||
this.n = n;
|
||||
}
|
||||
|
||||
@Override
|
||||
@JsonIgnore
|
||||
public List<String> getStopSequences() {
|
||||
return getStop();
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
public void setStopSequences(List<String> stopSequences) {
|
||||
setStop(stopSequences);
|
||||
}
|
||||
|
||||
public List<String> getStop() {
|
||||
return this.stop;
|
||||
}
|
||||
@@ -299,22 +308,35 @@ public class AzureOpenAiChatOptions implements FunctionCallingOptions, ChatOptio
|
||||
this.stop = stop;
|
||||
}
|
||||
|
||||
public Double getPresencePenalty() {
|
||||
@Override
|
||||
public Float getPresencePenalty() {
|
||||
return this.presencePenalty;
|
||||
}
|
||||
|
||||
public void setPresencePenalty(Double presencePenalty) {
|
||||
public void setPresencePenalty(Float presencePenalty) {
|
||||
this.presencePenalty = presencePenalty;
|
||||
}
|
||||
|
||||
public Double getFrequencyPenalty() {
|
||||
@Override
|
||||
public Float getFrequencyPenalty() {
|
||||
return this.frequencyPenalty;
|
||||
}
|
||||
|
||||
public void setFrequencyPenalty(Double frequencyPenalty) {
|
||||
public void setFrequencyPenalty(Float frequencyPenalty) {
|
||||
this.frequencyPenalty = frequencyPenalty;
|
||||
}
|
||||
|
||||
@Override
|
||||
@JsonIgnore
|
||||
public String getModel() {
|
||||
return getDeploymentName();
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
public void setModel(String model) {
|
||||
setDeploymentName(model);
|
||||
}
|
||||
|
||||
public String getDeploymentName() {
|
||||
return this.deploymentName;
|
||||
}
|
||||
@@ -341,17 +363,6 @@ public class AzureOpenAiChatOptions implements FunctionCallingOptions, ChatOptio
|
||||
this.topP = topP;
|
||||
}
|
||||
|
||||
@Override
|
||||
@JsonIgnore
|
||||
public Integer getTopK() {
|
||||
throw new UnsupportedOperationException("Unimplemented method 'getTopK'");
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
public void setTopK(Integer topK) {
|
||||
throw new UnsupportedOperationException("Unimplemented method 'setTopK'");
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<FunctionCallback> getFunctionCallbacks() {
|
||||
return this.functionCallbacks;
|
||||
@@ -378,6 +389,12 @@ public class AzureOpenAiChatOptions implements FunctionCallingOptions, ChatOptio
|
||||
this.responseFormat = responseFormat;
|
||||
}
|
||||
|
||||
@Override
|
||||
@JsonIgnore
|
||||
public Integer getTopK() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AzureOpenAiChatOptions copy() {
|
||||
return fromOptions(this);
|
||||
@@ -385,13 +402,11 @@ public class AzureOpenAiChatOptions implements FunctionCallingOptions, ChatOptio
|
||||
|
||||
public static AzureOpenAiChatOptions fromOptions(AzureOpenAiChatOptions fromOptions) {
|
||||
return builder().withDeploymentName(fromOptions.getDeploymentName())
|
||||
.withFrequencyPenalty(
|
||||
fromOptions.getFrequencyPenalty() != null ? fromOptions.getFrequencyPenalty().floatValue() : null)
|
||||
.withFrequencyPenalty(fromOptions.getFrequencyPenalty() != null ? fromOptions.getFrequencyPenalty() : null)
|
||||
.withLogitBias(fromOptions.getLogitBias())
|
||||
.withMaxTokens(fromOptions.getMaxTokens())
|
||||
.withN(fromOptions.getN())
|
||||
.withPresencePenalty(
|
||||
fromOptions.getPresencePenalty() != null ? fromOptions.getPresencePenalty().floatValue() : null)
|
||||
.withPresencePenalty(fromOptions.getPresencePenalty() != null ? fromOptions.getPresencePenalty() : null)
|
||||
.withStop(fromOptions.getStop())
|
||||
.withTemperature(fromOptions.getTemperature())
|
||||
.withTopP(fromOptions.getTopP())
|
||||
|
||||
@@ -17,6 +17,7 @@ package org.springframework.ai.azure.openai;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import org.springframework.ai.embedding.EmbeddingOptions;
|
||||
|
||||
/**
|
||||
@@ -125,10 +126,16 @@ public class AzureOpenAiEmbeddingOptions implements EmbeddingOptions {
|
||||
}
|
||||
|
||||
@Override
|
||||
@JsonIgnore
|
||||
public String getModel() {
|
||||
return getDeploymentName();
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
public void setModel(String model) {
|
||||
setDeploymentName(model);
|
||||
}
|
||||
|
||||
public String getUser() {
|
||||
return this.user;
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ package org.springframework.ai.bedrock.anthropic;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude.Include;
|
||||
|
||||
@@ -26,6 +27,7 @@ import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
/**
|
||||
* @author Christian Tzolov
|
||||
* @author Thomas Vitale
|
||||
*/
|
||||
@JsonInclude(Include.NON_NULL)
|
||||
public class AnthropicChatOptions implements ChatOptions {
|
||||
@@ -122,6 +124,17 @@ public class AnthropicChatOptions implements ChatOptions {
|
||||
this.temperature = temperature;
|
||||
}
|
||||
|
||||
@Override
|
||||
@JsonIgnore
|
||||
public Integer getMaxTokens() {
|
||||
return getMaxTokensToSample();
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
public void setMaxTokens(Integer maxTokens) {
|
||||
setMaxTokensToSample(maxTokens);
|
||||
}
|
||||
|
||||
public Integer getMaxTokensToSample() {
|
||||
return this.maxTokensToSample;
|
||||
}
|
||||
@@ -148,6 +161,7 @@ public class AnthropicChatOptions implements ChatOptions {
|
||||
this.topP = topP;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getStopSequences() {
|
||||
return this.stopSequences;
|
||||
}
|
||||
@@ -164,6 +178,24 @@ public class AnthropicChatOptions implements ChatOptions {
|
||||
this.anthropicVersion = anthropicVersion;
|
||||
}
|
||||
|
||||
@Override
|
||||
@JsonIgnore
|
||||
public String getModel() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@JsonIgnore
|
||||
public Float getFrequencyPenalty() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@JsonIgnore
|
||||
public Float getPresencePenalty() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnthropicChatOptions copy() {
|
||||
return fromOptions(this);
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package org.springframework.ai.bedrock.anthropic3;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude.Include;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
@@ -24,6 +25,7 @@ import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Ben Middleton
|
||||
* @author Thomas Vitale
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@JsonInclude(Include.NON_NULL)
|
||||
@@ -121,6 +123,7 @@ public class Anthropic3ChatOptions implements ChatOptions {
|
||||
this.temperature = temperature;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getMaxTokens() {
|
||||
return this.maxTokens;
|
||||
}
|
||||
@@ -147,6 +150,7 @@ public class Anthropic3ChatOptions implements ChatOptions {
|
||||
this.topP = topP;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getStopSequences() {
|
||||
return this.stopSequences;
|
||||
}
|
||||
@@ -163,6 +167,24 @@ public class Anthropic3ChatOptions implements ChatOptions {
|
||||
this.anthropicVersion = anthropicVersion;
|
||||
}
|
||||
|
||||
@Override
|
||||
@JsonIgnore
|
||||
public String getModel() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@JsonIgnore
|
||||
public Float getFrequencyPenalty() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@JsonIgnore
|
||||
public Float getPresencePenalty() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Anthropic3ChatOptions copy() {
|
||||
return fromOptions(this);
|
||||
|
||||
@@ -17,6 +17,7 @@ package org.springframework.ai.bedrock.cohere;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude.Include;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
@@ -28,6 +29,7 @@ import org.springframework.ai.chat.prompt.ChatOptions;
|
||||
|
||||
/**
|
||||
* @author Christian Tzolov
|
||||
* @author Thomas Vitale
|
||||
* @since 0.8.0
|
||||
*/
|
||||
@JsonInclude(Include.NON_NULL)
|
||||
@@ -165,6 +167,7 @@ public class BedrockCohereChatOptions implements ChatOptions {
|
||||
this.topK = topK;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getMaxTokens() {
|
||||
return this.maxTokens;
|
||||
}
|
||||
@@ -173,6 +176,7 @@ public class BedrockCohereChatOptions implements ChatOptions {
|
||||
this.maxTokens = maxTokens;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getStopSequences() {
|
||||
return this.stopSequences;
|
||||
}
|
||||
@@ -213,6 +217,24 @@ public class BedrockCohereChatOptions implements ChatOptions {
|
||||
this.truncate = truncate;
|
||||
}
|
||||
|
||||
@Override
|
||||
@JsonIgnore
|
||||
public String getModel() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@JsonIgnore
|
||||
public Float getFrequencyPenalty() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@JsonIgnore
|
||||
public Float getPresencePenalty() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BedrockCohereChatOptions copy() {
|
||||
return fromOptions(this);
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package org.springframework.ai.bedrock.cohere;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude.Include;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
@@ -88,11 +89,13 @@ public class BedrockCohereEmbeddingOptions implements EmbeddingOptions {
|
||||
}
|
||||
|
||||
@Override
|
||||
@JsonIgnore
|
||||
public String getModel() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@JsonIgnore
|
||||
public Integer getDimensions() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -16,14 +16,18 @@
|
||||
|
||||
package org.springframework.ai.bedrock.jurassic2;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import org.springframework.ai.chat.prompt.ChatOptions;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Request body for the /complete endpoint of the Jurassic-2 API.
|
||||
*
|
||||
* @author Ahmed Yousri
|
||||
* @author Thomas Vitale
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
@@ -75,25 +79,25 @@ public class BedrockAi21Jurassic2ChatOptions implements ChatOptions {
|
||||
* Stops decoding if any of the strings is generated.
|
||||
*/
|
||||
@JsonProperty("stopSequences")
|
||||
private String[] stopSequences;
|
||||
private List<String> stopSequences;
|
||||
|
||||
/**
|
||||
* Penalty object for frequency.
|
||||
*/
|
||||
@JsonProperty("frequencyPenalty")
|
||||
private Penalty frequencyPenalty;
|
||||
private Penalty frequencyPenaltyOptions;
|
||||
|
||||
/**
|
||||
* Penalty object for presence.
|
||||
*/
|
||||
@JsonProperty("presencePenalty")
|
||||
private Penalty presencePenalty;
|
||||
private Penalty presencePenaltyOptions;
|
||||
|
||||
/**
|
||||
* Penalty object for count.
|
||||
*/
|
||||
@JsonProperty("countPenalty")
|
||||
private Penalty countPenalty;
|
||||
private Penalty countPenaltyOptions;
|
||||
|
||||
// Getters and setters
|
||||
|
||||
@@ -133,6 +137,7 @@ public class BedrockAi21Jurassic2ChatOptions implements ChatOptions {
|
||||
* Gets the maximum number of tokens to generate per result.
|
||||
* @return The maximum number of tokens.
|
||||
*/
|
||||
@Override
|
||||
public Integer getMaxTokens() {
|
||||
return maxTokens;
|
||||
}
|
||||
@@ -165,6 +170,7 @@ public class BedrockAi21Jurassic2ChatOptions implements ChatOptions {
|
||||
* Gets the temperature for modifying the token sampling distribution.
|
||||
* @return The temperature.
|
||||
*/
|
||||
@Override
|
||||
public Float getTemperature() {
|
||||
return temperature;
|
||||
}
|
||||
@@ -182,6 +188,7 @@ public class BedrockAi21Jurassic2ChatOptions implements ChatOptions {
|
||||
* mass.
|
||||
* @return The topP parameter.
|
||||
*/
|
||||
@Override
|
||||
public Float getTopP() {
|
||||
return topP;
|
||||
}
|
||||
@@ -216,7 +223,8 @@ public class BedrockAi21Jurassic2ChatOptions implements ChatOptions {
|
||||
* Gets the stop sequences for stopping decoding if any of the strings is generated.
|
||||
* @return The stop sequences.
|
||||
*/
|
||||
public String[] getStopSequences() {
|
||||
@Override
|
||||
public List<String> getStopSequences() {
|
||||
return stopSequences;
|
||||
}
|
||||
|
||||
@@ -224,56 +232,88 @@ public class BedrockAi21Jurassic2ChatOptions implements ChatOptions {
|
||||
* Sets the stop sequences for stopping decoding if any of the strings is generated.
|
||||
* @param stopSequences The stop sequences.
|
||||
*/
|
||||
public void setStopSequences(String[] stopSequences) {
|
||||
public void setStopSequences(List<String> stopSequences) {
|
||||
this.stopSequences = stopSequences;
|
||||
}
|
||||
|
||||
@Override
|
||||
@JsonIgnore
|
||||
public Float getFrequencyPenalty() {
|
||||
return getFrequencyPenaltyOptions() != null ? getFrequencyPenaltyOptions().scale() : null;
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
public void setFrequencyPenalty(Float frequencyPenalty) {
|
||||
if (frequencyPenalty != null) {
|
||||
setFrequencyPenaltyOptions(Penalty.builder().scale(frequencyPenalty).build());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the frequency penalty object.
|
||||
* @return The frequency penalty object.
|
||||
*/
|
||||
public Penalty getFrequencyPenalty() {
|
||||
return frequencyPenalty;
|
||||
public Penalty getFrequencyPenaltyOptions() {
|
||||
return frequencyPenaltyOptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the frequency penalty object.
|
||||
* @param frequencyPenalty The frequency penalty object.
|
||||
* @param frequencyPenaltyOptions The frequency penalty object.
|
||||
*/
|
||||
public void setFrequencyPenalty(Penalty frequencyPenalty) {
|
||||
this.frequencyPenalty = frequencyPenalty;
|
||||
public void setFrequencyPenaltyOptions(Penalty frequencyPenaltyOptions) {
|
||||
this.frequencyPenaltyOptions = frequencyPenaltyOptions;
|
||||
}
|
||||
|
||||
@Override
|
||||
@JsonIgnore
|
||||
public Float getPresencePenalty() {
|
||||
return getPresencePenaltyOptions() != null ? getPresencePenaltyOptions().scale() : null;
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
public void setPresencePenalty(Float presencePenalty) {
|
||||
if (presencePenalty != null) {
|
||||
setPresencePenaltyOptions(Penalty.builder().scale(presencePenalty).build());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the presence penalty object.
|
||||
* @return The presence penalty object.
|
||||
*/
|
||||
public Penalty getPresencePenalty() {
|
||||
return presencePenalty;
|
||||
public Penalty getPresencePenaltyOptions() {
|
||||
return presencePenaltyOptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the presence penalty object.
|
||||
* @param presencePenalty The presence penalty object.
|
||||
* @param presencePenaltyOptions The presence penalty object.
|
||||
*/
|
||||
public void setPresencePenalty(Penalty presencePenalty) {
|
||||
this.presencePenalty = presencePenalty;
|
||||
public void setPresencePenaltyOptions(Penalty presencePenaltyOptions) {
|
||||
this.presencePenaltyOptions = presencePenaltyOptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the count penalty object.
|
||||
* @return The count penalty object.
|
||||
*/
|
||||
public Penalty getCountPenalty() {
|
||||
return countPenalty;
|
||||
public Penalty getCountPenaltyOptions() {
|
||||
return countPenaltyOptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the count penalty object.
|
||||
* @param countPenalty The count penalty object.
|
||||
* @param countPenaltyOptions The count penalty object.
|
||||
*/
|
||||
public void setCountPenalty(Penalty countPenalty) {
|
||||
this.countPenalty = countPenalty;
|
||||
public void setCountPenaltyOptions(Penalty countPenaltyOptions) {
|
||||
this.countPenaltyOptions = countPenaltyOptions;
|
||||
}
|
||||
|
||||
@Override
|
||||
@JsonIgnore
|
||||
public String getModel() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Builder builder() {
|
||||
@@ -314,7 +354,7 @@ public class BedrockAi21Jurassic2ChatOptions implements ChatOptions {
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder withStopSequences(String[] stopSequences) {
|
||||
public Builder withStopSequences(List<String> stopSequences) {
|
||||
request.setStopSequences(stopSequences);
|
||||
return this;
|
||||
}
|
||||
@@ -324,18 +364,18 @@ public class BedrockAi21Jurassic2ChatOptions implements ChatOptions {
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder withFrequencyPenalty(BedrockAi21Jurassic2ChatOptions.Penalty frequencyPenalty) {
|
||||
request.setFrequencyPenalty(frequencyPenalty);
|
||||
public Builder withFrequencyPenaltyOptions(BedrockAi21Jurassic2ChatOptions.Penalty frequencyPenalty) {
|
||||
request.setFrequencyPenaltyOptions(frequencyPenalty);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder withPresencePenalty(BedrockAi21Jurassic2ChatOptions.Penalty presencePenalty) {
|
||||
request.setPresencePenalty(presencePenalty);
|
||||
public Builder withPresencePenaltyOptions(BedrockAi21Jurassic2ChatOptions.Penalty presencePenalty) {
|
||||
request.setPresencePenaltyOptions(presencePenalty);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder withCountPenalty(BedrockAi21Jurassic2ChatOptions.Penalty countPenalty) {
|
||||
request.setCountPenalty(countPenalty);
|
||||
public Builder withCountPenaltyOptions(BedrockAi21Jurassic2ChatOptions.Penalty countPenalty) {
|
||||
request.setCountPenaltyOptions(countPenalty);
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -427,9 +467,9 @@ public class BedrockAi21Jurassic2ChatOptions implements ChatOptions {
|
||||
.withTopP(fromOptions.getTopP())
|
||||
.withTopK(fromOptions.getTopK())
|
||||
.withStopSequences(fromOptions.getStopSequences())
|
||||
.withFrequencyPenalty(fromOptions.getFrequencyPenalty())
|
||||
.withPresencePenalty(fromOptions.getPresencePenalty())
|
||||
.withCountPenalty(fromOptions.getCountPenalty())
|
||||
.withFrequencyPenaltyOptions(fromOptions.getFrequencyPenaltyOptions())
|
||||
.withPresencePenaltyOptions(fromOptions.getPresencePenaltyOptions())
|
||||
.withCountPenaltyOptions(fromOptions.getCountPenaltyOptions())
|
||||
.build();
|
||||
}
|
||||
|
||||
|
||||
@@ -22,8 +22,11 @@ import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
import org.springframework.ai.chat.prompt.ChatOptions;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Christian Tzolov
|
||||
* @author Thomas Vitale
|
||||
*/
|
||||
@JsonInclude(Include.NON_NULL)
|
||||
public class BedrockLlamaChatOptions implements ChatOptions {
|
||||
@@ -74,6 +77,7 @@ public class BedrockLlamaChatOptions implements ChatOptions {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Float getTemperature() {
|
||||
return this.temperature;
|
||||
}
|
||||
@@ -82,6 +86,7 @@ public class BedrockLlamaChatOptions implements ChatOptions {
|
||||
this.temperature = temperature;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Float getTopP() {
|
||||
return this.topP;
|
||||
}
|
||||
@@ -90,6 +95,17 @@ public class BedrockLlamaChatOptions implements ChatOptions {
|
||||
this.topP = topP;
|
||||
}
|
||||
|
||||
@Override
|
||||
@JsonIgnore
|
||||
public Integer getMaxTokens() {
|
||||
return getMaxGenLen();
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
public void setMaxTokens(Integer maxTokens) {
|
||||
setMaxGenLen(maxTokens);
|
||||
}
|
||||
|
||||
public Integer getMaxGenLen() {
|
||||
return this.maxGenLen;
|
||||
}
|
||||
@@ -100,13 +116,32 @@ public class BedrockLlamaChatOptions implements ChatOptions {
|
||||
|
||||
@Override
|
||||
@JsonIgnore
|
||||
public Integer getTopK() {
|
||||
throw new UnsupportedOperationException("Unsupported option: 'TopK'");
|
||||
public String getModel() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@JsonIgnore
|
||||
public void setTopK(Integer topK) {
|
||||
throw new UnsupportedOperationException("Unsupported option: 'TopK'");
|
||||
public Float getFrequencyPenalty() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@JsonIgnore
|
||||
public Float getPresencePenalty() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@JsonIgnore
|
||||
public List<String> getStopSequences() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@JsonIgnore
|
||||
public Integer getTopK() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -17,6 +17,7 @@ package org.springframework.ai.bedrock.titan;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude.Include;
|
||||
|
||||
@@ -26,6 +27,7 @@ import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
/**
|
||||
* @author Christian Tzolov
|
||||
* @author Thomas Vitale
|
||||
* @since 0.8.0
|
||||
*/
|
||||
@JsonInclude(Include.NON_NULL)
|
||||
@@ -87,6 +89,7 @@ public class BedrockTitanChatOptions implements ChatOptions {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Float getTemperature() {
|
||||
return temperature;
|
||||
}
|
||||
@@ -95,6 +98,7 @@ public class BedrockTitanChatOptions implements ChatOptions {
|
||||
this.temperature = temperature;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Float getTopP() {
|
||||
return topP;
|
||||
}
|
||||
@@ -103,6 +107,17 @@ public class BedrockTitanChatOptions implements ChatOptions {
|
||||
this.topP = topP;
|
||||
}
|
||||
|
||||
@Override
|
||||
@JsonIgnore
|
||||
public Integer getMaxTokens() {
|
||||
return getMaxTokenCount();
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
public void setMaxTokens(Integer maxTokens) {
|
||||
setMaxTokenCount(maxTokens);
|
||||
}
|
||||
|
||||
public Integer getMaxTokenCount() {
|
||||
return maxTokenCount;
|
||||
}
|
||||
@@ -111,6 +126,7 @@ public class BedrockTitanChatOptions implements ChatOptions {
|
||||
this.maxTokenCount = maxTokenCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getStopSequences() {
|
||||
return stopSequences;
|
||||
}
|
||||
@@ -120,12 +136,27 @@ public class BedrockTitanChatOptions implements ChatOptions {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getTopK() {
|
||||
throw new UnsupportedOperationException("Bedrock Titan Chat does not support the 'TopK' option.");
|
||||
@JsonIgnore
|
||||
public String getModel() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void setTopK(Integer topK) {
|
||||
throw new UnsupportedOperationException("Bedrock Titan Chat does not support the 'TopK' option.'");
|
||||
@Override
|
||||
@JsonIgnore
|
||||
public Float getFrequencyPenalty() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@JsonIgnore
|
||||
public Float getPresencePenalty() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@JsonIgnore
|
||||
public Integer getTopK() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package org.springframework.ai.bedrock.titan;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude.Include;
|
||||
|
||||
@@ -64,11 +65,13 @@ public class BedrockTitanEmbeddingOptions implements EmbeddingOptions {
|
||||
}
|
||||
|
||||
@Override
|
||||
@JsonIgnore
|
||||
public String getModel() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@JsonIgnore
|
||||
public Integer getDimensions() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -77,7 +77,7 @@ class BedrockAi21Jurassic2ChatModelIT {
|
||||
.applyToEmojis(false)
|
||||
.build();
|
||||
BedrockAi21Jurassic2ChatOptions options = new BedrockAi21Jurassic2ChatOptions.Builder()
|
||||
.withPresencePenalty(penalty)
|
||||
.withPresencePenaltyOptions(penalty)
|
||||
.build();
|
||||
|
||||
UserMessage userMessage = new UserMessage("Can you express happiness using an emoji like 😄 ?");
|
||||
@@ -94,7 +94,7 @@ class BedrockAi21Jurassic2ChatModelIT {
|
||||
// applyToEmojis is by default true
|
||||
BedrockAi21Jurassic2ChatOptions.Penalty penalty = new BedrockAi21Jurassic2ChatOptions.Penalty.Builder().build();
|
||||
BedrockAi21Jurassic2ChatOptions options = new BedrockAi21Jurassic2ChatOptions.Builder()
|
||||
.withPresencePenalty(penalty)
|
||||
.withPresencePenaltyOptions(penalty)
|
||||
.build();
|
||||
|
||||
UserMessage userMessage = new UserMessage("Can you express happiness using an emoji like 😄?");
|
||||
|
||||
@@ -39,6 +39,7 @@ import org.springframework.util.Assert;
|
||||
* @see FunctionCallingOptions
|
||||
* @see ChatOptions
|
||||
* @author Geng Rong
|
||||
* @author Thomas Vitale
|
||||
* @since 1.0.0 M1
|
||||
*/
|
||||
@JsonInclude(Include.NON_NULL)
|
||||
@@ -236,6 +237,7 @@ public class MiniMaxChatOptions implements FunctionCallingOptions, ChatOptions {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getModel() {
|
||||
return this.model;
|
||||
}
|
||||
@@ -244,6 +246,7 @@ public class MiniMaxChatOptions implements FunctionCallingOptions, ChatOptions {
|
||||
this.model = model;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Float getFrequencyPenalty() {
|
||||
return this.frequencyPenalty;
|
||||
}
|
||||
@@ -252,6 +255,7 @@ public class MiniMaxChatOptions implements FunctionCallingOptions, ChatOptions {
|
||||
this.frequencyPenalty = frequencyPenalty;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getMaxTokens() {
|
||||
return this.maxTokens;
|
||||
}
|
||||
@@ -268,6 +272,7 @@ public class MiniMaxChatOptions implements FunctionCallingOptions, ChatOptions {
|
||||
this.n = n;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Float getPresencePenalty() {
|
||||
return this.presencePenalty;
|
||||
}
|
||||
@@ -292,6 +297,17 @@ public class MiniMaxChatOptions implements FunctionCallingOptions, ChatOptions {
|
||||
this.seed = seed;
|
||||
}
|
||||
|
||||
@Override
|
||||
@JsonIgnore
|
||||
public List<String> getStopSequences() {
|
||||
return getStop();
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
public void setStopSequences(List<String> stopSequences) {
|
||||
setStop(stopSequences);
|
||||
}
|
||||
|
||||
public List<String> getStop() {
|
||||
return this.stop;
|
||||
}
|
||||
@@ -356,12 +372,7 @@ public class MiniMaxChatOptions implements FunctionCallingOptions, ChatOptions {
|
||||
@Override
|
||||
@JsonIgnore
|
||||
public Integer getTopK() {
|
||||
throw new UnsupportedOperationException("Unimplemented method 'getTopK'");
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
public void setTopK(Integer topK) {
|
||||
throw new UnsupportedOperationException("Unimplemented method 'setTopK'");
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package org.springframework.ai.minimax;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude.Include;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
@@ -70,6 +71,7 @@ public class MiniMaxEmbeddingOptions implements EmbeddingOptions {
|
||||
}
|
||||
|
||||
@Override
|
||||
@JsonIgnore
|
||||
public Integer getDimensions() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@ import org.springframework.util.Assert;
|
||||
/**
|
||||
* @author Ricken Bazolo
|
||||
* @author Christian Tzolov
|
||||
* @author Thomas Vitale
|
||||
* @since 0.8.1
|
||||
*/
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
@@ -85,6 +86,13 @@ public class MistralAiChatOptions implements FunctionCallingOptions, ChatOptions
|
||||
*/
|
||||
private @JsonProperty("response_format") ResponseFormat responseFormat;
|
||||
|
||||
/**
|
||||
* Stop generation if this token is detected. Or if one of these tokens is detected
|
||||
* when providing an array.
|
||||
*/
|
||||
@NestedConfigurationProperty
|
||||
private @JsonProperty("stop") List<String> stop;
|
||||
|
||||
/**
|
||||
* A list of tools the model may call. Currently, only functions are supported as a
|
||||
* tool. Use this to provide a list of functions the model may generate JSON inputs
|
||||
@@ -160,6 +168,11 @@ public class MistralAiChatOptions implements FunctionCallingOptions, ChatOptions
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder withStop(List<String> stop) {
|
||||
this.options.setStop(stop);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder withTemperature(Float temperature) {
|
||||
this.options.setTemperature(temperature);
|
||||
return this;
|
||||
@@ -208,6 +221,7 @@ public class MistralAiChatOptions implements FunctionCallingOptions, ChatOptions
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getModel() {
|
||||
return this.model;
|
||||
}
|
||||
@@ -216,6 +230,7 @@ public class MistralAiChatOptions implements FunctionCallingOptions, ChatOptions
|
||||
this.model = model;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getMaxTokens() {
|
||||
return this.maxTokens;
|
||||
}
|
||||
@@ -248,6 +263,25 @@ public class MistralAiChatOptions implements FunctionCallingOptions, ChatOptions
|
||||
this.responseFormat = responseFormat;
|
||||
}
|
||||
|
||||
@Override
|
||||
@JsonIgnore
|
||||
public List<String> getStopSequences() {
|
||||
return getStop();
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
public void setStopSequences(List<String> stopSequences) {
|
||||
setStop(stopSequences);
|
||||
}
|
||||
|
||||
public List<String> getStop() {
|
||||
return this.stop;
|
||||
}
|
||||
|
||||
public void setStop(List<String> stop) {
|
||||
this.stop = stop;
|
||||
}
|
||||
|
||||
public void setTools(List<FunctionTool> tools) {
|
||||
this.tools = tools;
|
||||
}
|
||||
@@ -282,17 +316,6 @@ public class MistralAiChatOptions implements FunctionCallingOptions, ChatOptions
|
||||
this.topP = topP;
|
||||
}
|
||||
|
||||
@Override
|
||||
@JsonIgnore
|
||||
public Integer getTopK() {
|
||||
throw new UnsupportedOperationException("Unsupported option: 'TopK'");
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
public void setTopK(Integer topK) {
|
||||
throw new UnsupportedOperationException("Unsupported option: 'TopK'");
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<FunctionCallback> getFunctionCallbacks() {
|
||||
return this.functionCallbacks;
|
||||
@@ -315,6 +338,24 @@ public class MistralAiChatOptions implements FunctionCallingOptions, ChatOptions
|
||||
this.functions = functions;
|
||||
}
|
||||
|
||||
@Override
|
||||
@JsonIgnore
|
||||
public Float getFrequencyPenalty() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@JsonIgnore
|
||||
public Float getPresencePenalty() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@JsonIgnore
|
||||
public Integer getTopK() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MistralAiChatOptions copy() {
|
||||
return fromOptions(this);
|
||||
@@ -328,6 +369,7 @@ public class MistralAiChatOptions implements FunctionCallingOptions, ChatOptions
|
||||
.withTemperature(fromOptions.getTemperature())
|
||||
.withTopP(fromOptions.getTopP())
|
||||
.withResponseFormat(fromOptions.getResponseFormat())
|
||||
.withStop(fromOptions.getStop())
|
||||
.withTools(fromOptions.getTools())
|
||||
.withToolChoice(fromOptions.getToolChoice())
|
||||
.withFunctionCallbacks(fromOptions.getFunctionCallbacks())
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package org.springframework.ai.mistralai;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude.Include;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
@@ -60,6 +61,7 @@ public class MistralAiEmbeddingOptions implements EmbeddingOptions {
|
||||
}
|
||||
|
||||
@Override
|
||||
@JsonIgnore
|
||||
public Integer getDimensions() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author Geng Rong
|
||||
* @author Thomas Vitale
|
||||
*/
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
public class MoonshotChatOptions implements ChatOptions {
|
||||
@@ -229,6 +230,7 @@ public class MoonshotChatOptions implements ChatOptions {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getModel() {
|
||||
return this.model;
|
||||
}
|
||||
@@ -237,6 +239,7 @@ public class MoonshotChatOptions implements ChatOptions {
|
||||
this.model = model;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Float getFrequencyPenalty() {
|
||||
return this.frequencyPenalty;
|
||||
}
|
||||
@@ -245,6 +248,7 @@ public class MoonshotChatOptions implements ChatOptions {
|
||||
this.frequencyPenalty = frequencyPenalty;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getMaxTokens() {
|
||||
return this.maxTokens;
|
||||
}
|
||||
@@ -261,6 +265,7 @@ public class MoonshotChatOptions implements ChatOptions {
|
||||
this.n = n;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Float getPresencePenalty() {
|
||||
return this.presencePenalty;
|
||||
}
|
||||
@@ -269,6 +274,17 @@ public class MoonshotChatOptions implements ChatOptions {
|
||||
this.presencePenalty = presencePenalty;
|
||||
}
|
||||
|
||||
@Override
|
||||
@JsonIgnore
|
||||
public List<String> getStopSequences() {
|
||||
return getStop();
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
public void setStopSequences(List<String> stopSequences) {
|
||||
setStop(stopSequences);
|
||||
}
|
||||
|
||||
public List<String> getStop() {
|
||||
return this.stop;
|
||||
}
|
||||
@@ -303,6 +319,12 @@ public class MoonshotChatOptions implements ChatOptions {
|
||||
this.user = user;
|
||||
}
|
||||
|
||||
@Override
|
||||
@JsonIgnore
|
||||
public Integer getTopK() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MoonshotChatOptions copy() {
|
||||
return builder().withModel(this.model)
|
||||
@@ -402,15 +424,4 @@ public class MoonshotChatOptions implements ChatOptions {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
@JsonIgnore
|
||||
public Integer getTopK() {
|
||||
throw new UnsupportedOperationException("Unimplemented method 'getTopK'");
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
public void setTopK(Integer topK) {
|
||||
throw new UnsupportedOperationException("Unimplemented method 'setTopK'");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -635,6 +635,17 @@ public class OllamaOptions implements FunctionCallingOptions, ChatOptions, Embed
|
||||
this.seed = seed;
|
||||
}
|
||||
|
||||
@Override
|
||||
@JsonIgnore
|
||||
public Integer getMaxTokens() {
|
||||
return getNumPredict();
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
public void setMaxTokens(Integer maxTokens) {
|
||||
setNumPredict(maxTokens);
|
||||
}
|
||||
|
||||
public Integer getNumPredict() {
|
||||
return this.numPredict;
|
||||
}
|
||||
@@ -643,6 +654,7 @@ public class OllamaOptions implements FunctionCallingOptions, ChatOptions, Embed
|
||||
this.numPredict = numPredict;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getTopK() {
|
||||
return this.topK;
|
||||
}
|
||||
@@ -651,6 +663,7 @@ public class OllamaOptions implements FunctionCallingOptions, ChatOptions, Embed
|
||||
this.topK = topK;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Float getTopP() {
|
||||
return this.topP;
|
||||
}
|
||||
@@ -683,6 +696,7 @@ public class OllamaOptions implements FunctionCallingOptions, ChatOptions, Embed
|
||||
this.repeatLastN = repeatLastN;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Float getTemperature() {
|
||||
return this.temperature;
|
||||
}
|
||||
@@ -699,6 +713,7 @@ public class OllamaOptions implements FunctionCallingOptions, ChatOptions, Embed
|
||||
this.repeatPenalty = repeatPenalty;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Float getPresencePenalty() {
|
||||
return this.presencePenalty;
|
||||
}
|
||||
@@ -707,6 +722,7 @@ public class OllamaOptions implements FunctionCallingOptions, ChatOptions, Embed
|
||||
this.presencePenalty = presencePenalty;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Float getFrequencyPenalty() {
|
||||
return this.frequencyPenalty;
|
||||
}
|
||||
@@ -747,6 +763,17 @@ public class OllamaOptions implements FunctionCallingOptions, ChatOptions, Embed
|
||||
this.penalizeNewline = penalizeNewline;
|
||||
}
|
||||
|
||||
@Override
|
||||
@JsonIgnore
|
||||
public List<String> getStopSequences() {
|
||||
return getStop();
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
public void setStopSequences(List<String> stopSequences) {
|
||||
setStop(stopSequences);
|
||||
}
|
||||
|
||||
public List<String> getStop() {
|
||||
return this.stop;
|
||||
}
|
||||
@@ -763,11 +790,6 @@ public class OllamaOptions implements FunctionCallingOptions, ChatOptions, Embed
|
||||
this.truncate = truncate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getDimensions() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<FunctionCallback> getFunctionCallbacks() {
|
||||
return this.functionCallbacks;
|
||||
@@ -776,7 +798,6 @@ public class OllamaOptions implements FunctionCallingOptions, ChatOptions, Embed
|
||||
@Override
|
||||
public void setFunctionCallbacks(List<FunctionCallback> functionCallbacks) {
|
||||
this.functionCallbacks = functionCallbacks;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -789,6 +810,12 @@ public class OllamaOptions implements FunctionCallingOptions, ChatOptions, Embed
|
||||
this.functions = functions;
|
||||
}
|
||||
|
||||
@Override
|
||||
@JsonIgnore
|
||||
public Integer getDimensions() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the {@link OllamaOptions} object to a {@link Map} of key/value pairs.
|
||||
* @return The {@link Map} of key/value pairs.
|
||||
|
||||
@@ -44,16 +44,13 @@ import org.springframework.ai.chat.model.StreamingChatModel;
|
||||
import org.springframework.ai.chat.observation.ChatModelObservationContext;
|
||||
import org.springframework.ai.chat.observation.ChatModelObservationConvention;
|
||||
import org.springframework.ai.chat.observation.ChatModelObservationDocumentation;
|
||||
import org.springframework.ai.chat.observation.ChatModelRequestOptions;
|
||||
import org.springframework.ai.chat.observation.DefaultChatModelObservationConvention;
|
||||
import org.springframework.ai.chat.prompt.ChatOptions;
|
||||
import org.springframework.ai.chat.prompt.ChatOptionsBuilder;
|
||||
import org.springframework.ai.chat.prompt.Prompt;
|
||||
import org.springframework.ai.model.ModelOptionsUtils;
|
||||
import org.springframework.ai.model.function.FunctionCallback;
|
||||
import org.springframework.ai.model.function.FunctionCallbackContext;
|
||||
import org.springframework.ai.observation.AiOperationMetadata;
|
||||
import org.springframework.ai.observation.conventions.AiOperationType;
|
||||
import org.springframework.ai.observation.conventions.AiProvider;
|
||||
import org.springframework.ai.openai.api.OpenAiApi;
|
||||
import org.springframework.ai.openai.api.OpenAiApi.ChatCompletion;
|
||||
import org.springframework.ai.openai.api.OpenAiApi.ChatCompletion.Choice;
|
||||
@@ -62,6 +59,7 @@ import org.springframework.ai.openai.api.OpenAiApi.ChatCompletionMessage.ChatCom
|
||||
import org.springframework.ai.openai.api.OpenAiApi.ChatCompletionMessage.MediaContent;
|
||||
import org.springframework.ai.openai.api.OpenAiApi.ChatCompletionMessage.ToolCall;
|
||||
import org.springframework.ai.openai.api.OpenAiApi.ChatCompletionRequest;
|
||||
import org.springframework.ai.openai.api.common.OpenAiApiConstants;
|
||||
import org.springframework.ai.openai.metadata.OpenAiUsage;
|
||||
import org.springframework.ai.openai.metadata.support.OpenAiResponseHeaderExtractor;
|
||||
import org.springframework.ai.retry.RetryUtils;
|
||||
@@ -214,7 +212,7 @@ public class OpenAiChatModel extends AbstractToolCallSupport implements ChatMode
|
||||
|
||||
ChatModelObservationContext observationContext = ChatModelObservationContext.builder()
|
||||
.prompt(prompt)
|
||||
.operationMetadata(buildOperationMetadata())
|
||||
.provider(OpenAiApiConstants.PROVIDER_NAME)
|
||||
.requestOptions(buildRequestOptions(request))
|
||||
.build();
|
||||
|
||||
@@ -287,7 +285,7 @@ public class OpenAiChatModel extends AbstractToolCallSupport implements ChatMode
|
||||
|
||||
final ChatModelObservationContext observationContext = ChatModelObservationContext.builder()
|
||||
.prompt(prompt)
|
||||
.operationMetadata(buildOperationMetadata())
|
||||
.provider(OpenAiApiConstants.PROVIDER_NAME)
|
||||
.requestOptions(buildRequestOptions(request))
|
||||
.build();
|
||||
|
||||
@@ -356,9 +354,7 @@ public class OpenAiChatModel extends AbstractToolCallSupport implements ChatMode
|
||||
.contextWrite(ctx -> ctx.put(ObservationThreadLocalAccessor.KEY, observation));
|
||||
// @formatter:on
|
||||
|
||||
return new MessageAggregator().aggregate(flux, mergedChatResponse -> {
|
||||
observationContext.setResponse(mergedChatResponse);
|
||||
});
|
||||
return new MessageAggregator().aggregate(flux, observationContext::setResponse);
|
||||
|
||||
});
|
||||
}
|
||||
@@ -370,7 +366,7 @@ public class OpenAiChatModel extends AbstractToolCallSupport implements ChatMode
|
||||
headers.putAll(chatOptions.getHttpHeaders());
|
||||
}
|
||||
return CollectionUtils.toMultiValueMap(
|
||||
headers.entrySet().stream().collect(Collectors.toMap(e -> e.getKey(), e -> List.of(e.getValue()))));
|
||||
headers.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, e -> List.of(e.getValue()))));
|
||||
}
|
||||
|
||||
private Generation buildGeneration(Choice choice, Map<String, Object> metadata) {
|
||||
@@ -536,22 +532,15 @@ public class OpenAiChatModel extends AbstractToolCallSupport implements ChatMode
|
||||
}).toList();
|
||||
}
|
||||
|
||||
private AiOperationMetadata buildOperationMetadata() {
|
||||
return AiOperationMetadata.builder()
|
||||
.operationType(AiOperationType.CHAT.value())
|
||||
.provider(AiProvider.OPENAI.value())
|
||||
.build();
|
||||
}
|
||||
|
||||
private ChatModelRequestOptions buildRequestOptions(OpenAiApi.ChatCompletionRequest request) {
|
||||
return ChatModelRequestOptions.builder()
|
||||
.model(StringUtils.hasText(request.model()) ? request.model() : "unknown")
|
||||
.frequencyPenalty(request.frequencyPenalty())
|
||||
.maxTokens(request.maxTokens())
|
||||
.presencePenalty(request.presencePenalty())
|
||||
.stopSequences(request.stop())
|
||||
.temperature(request.temperature())
|
||||
.topP(request.topP())
|
||||
private ChatOptions buildRequestOptions(OpenAiApi.ChatCompletionRequest request) {
|
||||
return ChatOptionsBuilder.builder()
|
||||
.withModel(request.model())
|
||||
.withFrequencyPenalty(request.frequencyPenalty())
|
||||
.withMaxTokens(request.maxTokens())
|
||||
.withPresencePenalty(request.presencePenalty())
|
||||
.withStopSequences(request.stop())
|
||||
.withTemperature(request.temperature())
|
||||
.withTopP(request.topP())
|
||||
.build();
|
||||
}
|
||||
|
||||
|
||||
@@ -327,6 +327,7 @@ public class OpenAiChatOptions implements FunctionCallingOptions, ChatOptions {
|
||||
this.streamOptions = (enableStreamUsage) ? StreamOptions.INCLUDE_USAGE : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getModel() {
|
||||
return this.model;
|
||||
}
|
||||
@@ -335,6 +336,7 @@ public class OpenAiChatOptions implements FunctionCallingOptions, ChatOptions {
|
||||
this.model = model;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Float getFrequencyPenalty() {
|
||||
return this.frequencyPenalty;
|
||||
}
|
||||
@@ -367,6 +369,7 @@ public class OpenAiChatOptions implements FunctionCallingOptions, ChatOptions {
|
||||
this.topLogprobs = topLogprobs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getMaxTokens() {
|
||||
return this.maxTokens;
|
||||
}
|
||||
@@ -383,6 +386,7 @@ public class OpenAiChatOptions implements FunctionCallingOptions, ChatOptions {
|
||||
this.n = n;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Float getPresencePenalty() {
|
||||
return this.presencePenalty;
|
||||
}
|
||||
@@ -415,6 +419,17 @@ public class OpenAiChatOptions implements FunctionCallingOptions, ChatOptions {
|
||||
this.seed = seed;
|
||||
}
|
||||
|
||||
@Override
|
||||
@JsonIgnore
|
||||
public List<String> getStopSequences() {
|
||||
return getStop();
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
public void setStopSequences(List<String> stopSequences) {
|
||||
setStop(stopSequences);
|
||||
}
|
||||
|
||||
public List<String> getStop() {
|
||||
return this.stop;
|
||||
}
|
||||
@@ -500,6 +515,12 @@ public class OpenAiChatOptions implements FunctionCallingOptions, ChatOptions {
|
||||
this.httpHeaders = httpHeaders;
|
||||
}
|
||||
|
||||
@Override
|
||||
@JsonIgnore
|
||||
public Integer getTopK() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
@@ -646,17 +667,6 @@ public class OpenAiChatOptions implements FunctionCallingOptions, ChatOptions {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
@JsonIgnore
|
||||
public Integer getTopK() {
|
||||
throw new UnsupportedOperationException("Unimplemented method 'getTopK'");
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
public void setTopK(Integer topK) {
|
||||
throw new UnsupportedOperationException("Unimplemented method 'setTopK'");
|
||||
}
|
||||
|
||||
@Override
|
||||
public OpenAiChatOptions copy() {
|
||||
return OpenAiChatOptions.fromOptions(this);
|
||||
|
||||
@@ -31,11 +31,9 @@ import org.springframework.ai.embedding.observation.EmbeddingModelObservationCon
|
||||
import org.springframework.ai.embedding.observation.EmbeddingModelObservationDocumentation;
|
||||
import org.springframework.ai.embedding.observation.EmbeddingModelObservationContext;
|
||||
import org.springframework.ai.model.ModelOptionsUtils;
|
||||
import org.springframework.ai.observation.AiOperationMetadata;
|
||||
import org.springframework.ai.observation.conventions.AiOperationType;
|
||||
import org.springframework.ai.observation.conventions.AiProvider;
|
||||
import org.springframework.ai.openai.api.OpenAiApi;
|
||||
import org.springframework.ai.openai.api.OpenAiApi.EmbeddingList;
|
||||
import org.springframework.ai.openai.api.common.OpenAiApiConstants;
|
||||
import org.springframework.ai.openai.metadata.OpenAiUsage;
|
||||
import org.springframework.ai.retry.RetryUtils;
|
||||
import org.springframework.lang.Nullable;
|
||||
@@ -151,7 +149,7 @@ public class OpenAiEmbeddingModel extends AbstractEmbeddingModel {
|
||||
|
||||
var observationContext = EmbeddingModelObservationContext.builder()
|
||||
.embeddingRequest(request)
|
||||
.operationMetadata(buildOperationMetadata())
|
||||
.provider(OpenAiApiConstants.PROVIDER_NAME)
|
||||
.requestOptions(requestOptions)
|
||||
.build();
|
||||
|
||||
@@ -195,25 +193,22 @@ public class OpenAiEmbeddingModel extends AbstractEmbeddingModel {
|
||||
*/
|
||||
private OpenAiEmbeddingOptions mergeOptions(@Nullable EmbeddingOptions runtimeOptions,
|
||||
OpenAiEmbeddingOptions defaultOptions) {
|
||||
if (runtimeOptions == null) {
|
||||
var runtimeOptionsForProvider = ModelOptionsUtils.copyToTarget(runtimeOptions, EmbeddingOptions.class,
|
||||
OpenAiEmbeddingOptions.class);
|
||||
|
||||
if (runtimeOptionsForProvider == null) {
|
||||
return defaultOptions;
|
||||
}
|
||||
|
||||
return OpenAiEmbeddingOptions.builder()
|
||||
// Handle portable embedding options
|
||||
.withModel(ModelOptionsUtils.mergeOption(runtimeOptions.getModel(), defaultOptions.getModel()))
|
||||
.withDimensions(
|
||||
ModelOptionsUtils.mergeOption(runtimeOptions.getDimensions(), defaultOptions.getDimensions()))
|
||||
.withModel(ModelOptionsUtils.mergeOption(runtimeOptionsForProvider.getModel(), defaultOptions.getModel()))
|
||||
.withDimensions(ModelOptionsUtils.mergeOption(runtimeOptionsForProvider.getDimensions(),
|
||||
defaultOptions.getDimensions()))
|
||||
// Handle OpenAI specific embedding options
|
||||
.withEncodingFormat(defaultOptions.getEncodingFormat())
|
||||
.withUser(defaultOptions.getUser())
|
||||
.build();
|
||||
}
|
||||
|
||||
private AiOperationMetadata buildOperationMetadata() {
|
||||
return AiOperationMetadata.builder()
|
||||
.operationType(AiOperationType.EMBEDDING.value())
|
||||
.provider(AiProvider.OPENAI.value())
|
||||
.withEncodingFormat(ModelOptionsUtils.mergeOption(runtimeOptionsForProvider.getEncodingFormat(),
|
||||
defaultOptions.getEncodingFormat()))
|
||||
.withUser(ModelOptionsUtils.mergeOption(runtimeOptionsForProvider.getUser(), defaultOptions.getUser()))
|
||||
.build();
|
||||
}
|
||||
|
||||
|
||||
@@ -30,13 +30,12 @@ import org.springframework.ai.image.observation.ImageModelObservationConvention;
|
||||
import org.springframework.ai.image.observation.ImageModelObservationContext;
|
||||
import org.springframework.ai.image.observation.ImageModelObservationDocumentation;
|
||||
import org.springframework.ai.model.ModelOptionsUtils;
|
||||
import org.springframework.ai.observation.AiOperationMetadata;
|
||||
import org.springframework.ai.observation.conventions.AiOperationType;
|
||||
import org.springframework.ai.observation.conventions.AiProvider;
|
||||
import org.springframework.ai.openai.api.OpenAiImageApi;
|
||||
import org.springframework.ai.openai.api.common.OpenAiApiConstants;
|
||||
import org.springframework.ai.openai.metadata.OpenAiImageGenerationMetadata;
|
||||
import org.springframework.ai.retry.RetryUtils;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.retry.support.RetryTemplate;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
@@ -131,7 +130,7 @@ public class OpenAiImageModel implements ImageModel {
|
||||
|
||||
var observationContext = ImageModelObservationContext.builder()
|
||||
.imagePrompt(imagePrompt)
|
||||
.operationMetadata(buildOperationMetadata())
|
||||
.provider(OpenAiApiConstants.PROVIDER_NAME)
|
||||
.requestOptions(requestImageOptions)
|
||||
.build();
|
||||
|
||||
@@ -181,30 +180,28 @@ public class OpenAiImageModel implements ImageModel {
|
||||
* Merge runtime and default {@link ImageOptions} to compute the final options to use
|
||||
* in the request.
|
||||
*/
|
||||
private OpenAiImageOptions mergeOptions(ImageOptions runtimeOptions, OpenAiImageOptions defaultOptions) {
|
||||
if (runtimeOptions == null) {
|
||||
private OpenAiImageOptions mergeOptions(@Nullable ImageOptions runtimeOptions, OpenAiImageOptions defaultOptions) {
|
||||
var runtimeOptionsForProvider = ModelOptionsUtils.copyToTarget(runtimeOptions, ImageOptions.class,
|
||||
OpenAiImageOptions.class);
|
||||
|
||||
if (runtimeOptionsForProvider == null) {
|
||||
return defaultOptions;
|
||||
}
|
||||
|
||||
return OpenAiImageOptions.builder()
|
||||
// Handle portable image options
|
||||
.withModel(ModelOptionsUtils.mergeOption(runtimeOptions.getModel(), defaultOptions.getModel()))
|
||||
.withN(ModelOptionsUtils.mergeOption(runtimeOptions.getN(), defaultOptions.getN()))
|
||||
.withResponseFormat(ModelOptionsUtils.mergeOption(runtimeOptions.getResponseFormat(),
|
||||
.withModel(ModelOptionsUtils.mergeOption(runtimeOptionsForProvider.getModel(), defaultOptions.getModel()))
|
||||
.withN(ModelOptionsUtils.mergeOption(runtimeOptionsForProvider.getN(), defaultOptions.getN()))
|
||||
.withResponseFormat(ModelOptionsUtils.mergeOption(runtimeOptionsForProvider.getResponseFormat(),
|
||||
defaultOptions.getResponseFormat()))
|
||||
.withWidth(ModelOptionsUtils.mergeOption(runtimeOptions.getWidth(), defaultOptions.getWidth()))
|
||||
.withHeight(ModelOptionsUtils.mergeOption(runtimeOptions.getHeight(), defaultOptions.getHeight()))
|
||||
.withStyle(ModelOptionsUtils.mergeOption(runtimeOptions.getStyle(), defaultOptions.getStyle()))
|
||||
.withWidth(ModelOptionsUtils.mergeOption(runtimeOptionsForProvider.getWidth(), defaultOptions.getWidth()))
|
||||
.withHeight(
|
||||
ModelOptionsUtils.mergeOption(runtimeOptionsForProvider.getHeight(), defaultOptions.getHeight()))
|
||||
.withStyle(ModelOptionsUtils.mergeOption(runtimeOptionsForProvider.getStyle(), defaultOptions.getStyle()))
|
||||
// Handle OpenAI specific image options
|
||||
.withQuality(defaultOptions.getQuality())
|
||||
.withUser(defaultOptions.getUser())
|
||||
.build();
|
||||
}
|
||||
|
||||
private AiOperationMetadata buildOperationMetadata() {
|
||||
return AiOperationMetadata.builder()
|
||||
.operationType(AiOperationType.IMAGE.value())
|
||||
.provider(AiProvider.OPENAI.value())
|
||||
.withQuality(
|
||||
ModelOptionsUtils.mergeOption(runtimeOptionsForProvider.getQuality(), defaultOptions.getQuality()))
|
||||
.withUser(ModelOptionsUtils.mergeOption(runtimeOptionsForProvider.getUser(), defaultOptions.getUser()))
|
||||
.build();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,13 +1,18 @@
|
||||
package org.springframework.ai.openai.api.common;
|
||||
|
||||
import org.springframework.ai.observation.conventions.AiProvider;
|
||||
|
||||
/**
|
||||
* Common value constants for OpenAI api.
|
||||
*
|
||||
* @author Piotr Olaszewski
|
||||
* @author Thomas Vitale
|
||||
* @since 1.0.0 M2
|
||||
*/
|
||||
public final class OpenAiApiConstants {
|
||||
|
||||
public static final String DEFAULT_BASE_URL = "https://api.openai.com";
|
||||
|
||||
public static final String PROVIDER_NAME = AiProvider.OPENAI.value();
|
||||
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ package org.springframework.ai.postgresml;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude.Include;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
@@ -132,11 +133,13 @@ public class PostgresMlEmbeddingOptions implements EmbeddingOptions {
|
||||
}
|
||||
|
||||
@Override
|
||||
@JsonIgnore
|
||||
public String getModel() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@JsonIgnore
|
||||
public Integer getDimensions() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -143,6 +143,7 @@ public class QianFanChatOptions implements ChatOptions {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getModel() {
|
||||
return this.model;
|
||||
}
|
||||
@@ -151,6 +152,7 @@ public class QianFanChatOptions implements ChatOptions {
|
||||
this.model = model;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Float getFrequencyPenalty() {
|
||||
return this.frequencyPenalty;
|
||||
}
|
||||
@@ -159,6 +161,7 @@ public class QianFanChatOptions implements ChatOptions {
|
||||
this.frequencyPenalty = frequencyPenalty;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getMaxTokens() {
|
||||
return this.maxTokens;
|
||||
}
|
||||
@@ -167,6 +170,7 @@ public class QianFanChatOptions implements ChatOptions {
|
||||
this.maxTokens = maxTokens;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Float getPresencePenalty() {
|
||||
return this.presencePenalty;
|
||||
}
|
||||
@@ -183,6 +187,17 @@ public class QianFanChatOptions implements ChatOptions {
|
||||
this.responseFormat = responseFormat;
|
||||
}
|
||||
|
||||
@Override
|
||||
@JsonIgnore
|
||||
public List<String> getStopSequences() {
|
||||
return getStop();
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
public void setStopSequences(List<String> stopSequences) {
|
||||
setStop(stopSequences);
|
||||
}
|
||||
|
||||
public List<String> getStop() {
|
||||
return this.stop;
|
||||
}
|
||||
@@ -212,7 +227,7 @@ public class QianFanChatOptions implements ChatOptions {
|
||||
@Override
|
||||
@JsonIgnore
|
||||
public Integer getTopK() {
|
||||
throw new UnsupportedOperationException("Unimplemented method 'getTopK'");
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package org.springframework.ai.qianfan;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude.Include;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
@@ -89,6 +90,7 @@ public class QianFanEmbeddingOptions implements EmbeddingOptions {
|
||||
}
|
||||
|
||||
@Override
|
||||
@JsonIgnore
|
||||
public Integer getDimensions() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package org.springframework.ai.qianfan;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import org.springframework.ai.image.ImageOptions;
|
||||
@@ -170,6 +171,7 @@ public class QianFanImageOptions implements ImageOptions {
|
||||
}
|
||||
|
||||
@Override
|
||||
@JsonIgnore
|
||||
public String getResponseFormat() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package org.springframework.ai.stabilityai.api;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import org.springframework.ai.image.ImageOptions;
|
||||
@@ -452,10 +453,16 @@ public class StabilityAiImageOptions implements ImageOptions {
|
||||
}
|
||||
|
||||
@Override
|
||||
@JsonIgnore
|
||||
public String getStyle() {
|
||||
return getStylePreset();
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
public void setStyle(String style) {
|
||||
setStylePreset(style);
|
||||
}
|
||||
|
||||
public String getStylePreset() {
|
||||
return stylePreset;
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* @author Christian Tzolov
|
||||
* @author Thomas Vitale
|
||||
* @since 0.8.1
|
||||
*/
|
||||
@JsonInclude(Include.NON_NULL)
|
||||
@@ -173,6 +174,7 @@ public class VertexAiGeminiChatOptions implements FunctionCallingOptions, ChatOp
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getStopSequences() {
|
||||
return this.stopSequences;
|
||||
}
|
||||
@@ -200,7 +202,6 @@ public class VertexAiGeminiChatOptions implements FunctionCallingOptions, ChatOp
|
||||
}
|
||||
|
||||
@Override
|
||||
@JsonIgnore
|
||||
public Integer getTopK() {
|
||||
return (this.topK != null) ? this.topK.intValue() : null;
|
||||
}
|
||||
@@ -222,6 +223,17 @@ public class VertexAiGeminiChatOptions implements FunctionCallingOptions, ChatOp
|
||||
this.candidateCount = candidateCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
@JsonIgnore
|
||||
public Integer getMaxTokens() {
|
||||
return getMaxOutputTokens();
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
public void setMaxTokens(Integer maxTokens) {
|
||||
setMaxOutputTokens(maxTokens);
|
||||
}
|
||||
|
||||
public Integer getMaxOutputTokens() {
|
||||
return this.maxOutputTokens;
|
||||
}
|
||||
@@ -230,6 +242,7 @@ public class VertexAiGeminiChatOptions implements FunctionCallingOptions, ChatOp
|
||||
this.maxOutputTokens = maxOutputTokens;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getModel() {
|
||||
return this.model;
|
||||
}
|
||||
@@ -254,6 +267,18 @@ public class VertexAiGeminiChatOptions implements FunctionCallingOptions, ChatOp
|
||||
this.functions = functions;
|
||||
}
|
||||
|
||||
@Override
|
||||
@JsonIgnore
|
||||
public Float getFrequencyPenalty() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@JsonIgnore
|
||||
public Float getPresencePenalty() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
|
||||
@@ -15,14 +15,18 @@
|
||||
*/
|
||||
package org.springframework.ai.vertexai.palm2;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude.Include;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
import org.springframework.ai.chat.prompt.ChatOptions;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Christian Tzolov
|
||||
* @author Thomas Vitale
|
||||
*/
|
||||
@JsonInclude(Include.NON_NULL)
|
||||
public class VertexAiPaLm2ChatOptions implements ChatOptions {
|
||||
@@ -127,6 +131,36 @@ public class VertexAiPaLm2ChatOptions implements ChatOptions {
|
||||
this.topK = topK;
|
||||
}
|
||||
|
||||
@Override
|
||||
@JsonIgnore
|
||||
public String getModel() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@JsonIgnore
|
||||
public Integer getMaxTokens() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@JsonIgnore
|
||||
public List<String> getStopSequences() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@JsonIgnore
|
||||
public Float getFrequencyPenalty() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@JsonIgnore
|
||||
public Float getPresencePenalty() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VertexAiPaLm2ChatOptions copy() {
|
||||
return fromOptions(this);
|
||||
|
||||
@@ -34,6 +34,7 @@ import org.springframework.ai.chat.prompt.ChatOptions;
|
||||
*
|
||||
* @author Pablo Sanchidrian Herrera
|
||||
* @author John Jairo Moreno Rojas
|
||||
* @author Thomas Vitale
|
||||
* @since 1.0.0
|
||||
* @see <a href=
|
||||
* "https://dataplatform.cloud.ibm.com/docs/content/wsj/analyze-data/fm-model-parameters.html?context=wx&audience=wdp">watsonx.ai
|
||||
@@ -124,6 +125,7 @@ public class WatsonxAiChatOptions implements ChatOptions {
|
||||
@JsonIgnore
|
||||
private ObjectMapper mapper = new ObjectMapper();
|
||||
|
||||
@Override
|
||||
public Float getTemperature() {
|
||||
return temperature;
|
||||
}
|
||||
@@ -132,6 +134,7 @@ public class WatsonxAiChatOptions implements ChatOptions {
|
||||
this.temperature = temperature;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Float getTopP() {
|
||||
return topP;
|
||||
}
|
||||
@@ -140,6 +143,7 @@ public class WatsonxAiChatOptions implements ChatOptions {
|
||||
this.topP = topP;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getTopK() {
|
||||
return topK;
|
||||
}
|
||||
@@ -156,6 +160,17 @@ public class WatsonxAiChatOptions implements ChatOptions {
|
||||
this.decodingMethod = decodingMethod;
|
||||
}
|
||||
|
||||
@Override
|
||||
@JsonIgnore
|
||||
public Integer getMaxTokens() {
|
||||
return getMaxNewTokens();
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
public void setMaxTokens(Integer maxTokens) {
|
||||
setMaxNewTokens(maxTokens);
|
||||
}
|
||||
|
||||
public Integer getMaxNewTokens() {
|
||||
return maxNewTokens;
|
||||
}
|
||||
@@ -172,7 +187,8 @@ public class WatsonxAiChatOptions implements ChatOptions {
|
||||
this.minNewTokens = minNewTokens;
|
||||
}
|
||||
|
||||
public List<String> getStopSequences() {
|
||||
@Override
|
||||
public List<String> getStopSequences() {
|
||||
return stopSequences;
|
||||
}
|
||||
|
||||
@@ -180,7 +196,18 @@ public class WatsonxAiChatOptions implements ChatOptions {
|
||||
this.stopSequences = stopSequences;
|
||||
}
|
||||
|
||||
public Float getRepetitionPenalty() {
|
||||
@Override
|
||||
@JsonIgnore
|
||||
public Float getPresencePenalty() {
|
||||
return getRepetitionPenalty();
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
public void setPresencePenalty(Float presencePenalty) {
|
||||
setRepetitionPenalty(presencePenalty);
|
||||
}
|
||||
|
||||
public Float getRepetitionPenalty() {
|
||||
return repetitionPenalty;
|
||||
}
|
||||
|
||||
@@ -196,6 +223,7 @@ public class WatsonxAiChatOptions implements ChatOptions {
|
||||
this.randomSeed = randomSeed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getModel() {
|
||||
return model;
|
||||
}
|
||||
@@ -218,6 +246,12 @@ public class WatsonxAiChatOptions implements ChatOptions {
|
||||
additional.put(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
@JsonIgnore
|
||||
public Float getFrequencyPenalty() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Builder builder() {
|
||||
return new Builder();
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@ import java.util.Set;
|
||||
* ZhiPuAiChatOptions represents the options for the ZhiPuAiChat model.
|
||||
*
|
||||
* @author Geng Rong
|
||||
* @author Thomas Vitale
|
||||
* @since 1.0.0 M1
|
||||
*/
|
||||
@JsonInclude(Include.NON_NULL)
|
||||
@@ -213,6 +214,7 @@ public class ZhiPuAiChatOptions implements FunctionCallingOptions, ChatOptions {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getModel() {
|
||||
return this.model;
|
||||
}
|
||||
@@ -221,6 +223,7 @@ public class ZhiPuAiChatOptions implements FunctionCallingOptions, ChatOptions {
|
||||
this.model = model;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getMaxTokens() {
|
||||
return this.maxTokens;
|
||||
}
|
||||
@@ -229,6 +232,17 @@ public class ZhiPuAiChatOptions implements FunctionCallingOptions, ChatOptions {
|
||||
this.maxTokens = maxTokens;
|
||||
}
|
||||
|
||||
@Override
|
||||
@JsonIgnore
|
||||
public List<String> getStopSequences() {
|
||||
return getStop();
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
public void setStopSequences(List<String> stopSequences) {
|
||||
setStop(stopSequences);
|
||||
}
|
||||
|
||||
public List<String> getStop() {
|
||||
return this.stop;
|
||||
}
|
||||
@@ -314,6 +328,24 @@ public class ZhiPuAiChatOptions implements FunctionCallingOptions, ChatOptions {
|
||||
this.functions = functionNames;
|
||||
}
|
||||
|
||||
@Override
|
||||
@JsonIgnore
|
||||
public Float getFrequencyPenalty() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@JsonIgnore
|
||||
public Float getPresencePenalty() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@JsonIgnore
|
||||
public Integer getTopK() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
@@ -401,17 +433,6 @@ public class ZhiPuAiChatOptions implements FunctionCallingOptions, ChatOptions {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
@JsonIgnore
|
||||
public Integer getTopK() {
|
||||
throw new UnsupportedOperationException("Unimplemented method 'getTopK'");
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
public void setTopK(Integer topK) {
|
||||
throw new UnsupportedOperationException("Unimplemented method 'setTopK'");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ZhiPuAiChatOptions copy() {
|
||||
return fromOptions(this);
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package org.springframework.ai.zhipuai;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude.Include;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
@@ -70,6 +71,7 @@ public class ZhiPuAiEmbeddingOptions implements EmbeddingOptions {
|
||||
}
|
||||
|
||||
@Override
|
||||
@JsonIgnore
|
||||
public Integer getDimensions() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package org.springframework.ai.zhipuai;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import org.springframework.ai.image.ImageOptions;
|
||||
@@ -88,6 +89,7 @@ public class ZhiPuAiImageOptions implements ImageOptions {
|
||||
}
|
||||
|
||||
@Override
|
||||
@JsonIgnore
|
||||
public Integer getN() {
|
||||
return null;
|
||||
}
|
||||
@@ -102,21 +104,25 @@ public class ZhiPuAiImageOptions implements ImageOptions {
|
||||
}
|
||||
|
||||
@Override
|
||||
@JsonIgnore
|
||||
public Integer getWidth() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@JsonIgnore
|
||||
public Integer getHeight() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@JsonIgnore
|
||||
public String getResponseFormat() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@JsonIgnore
|
||||
public String getStyle() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -16,9 +16,11 @@
|
||||
package org.springframework.ai.chat.observation;
|
||||
|
||||
import org.springframework.ai.chat.model.ChatResponse;
|
||||
import org.springframework.ai.chat.prompt.ChatOptions;
|
||||
import org.springframework.ai.chat.prompt.Prompt;
|
||||
import org.springframework.ai.model.observation.ModelObservationContext;
|
||||
import org.springframework.ai.observation.AiOperationMetadata;
|
||||
import org.springframework.ai.observation.conventions.AiOperationType;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -29,16 +31,16 @@ import org.springframework.util.Assert;
|
||||
*/
|
||||
public class ChatModelObservationContext extends ModelObservationContext<Prompt, ChatResponse> {
|
||||
|
||||
private final ChatModelRequestOptions requestOptions;
|
||||
private final ChatOptions requestOptions;
|
||||
|
||||
ChatModelObservationContext(Prompt prompt, AiOperationMetadata operationMetadata,
|
||||
ChatModelRequestOptions requestOptions) {
|
||||
super(prompt, operationMetadata);
|
||||
ChatModelObservationContext(Prompt prompt, String provider, ChatOptions requestOptions) {
|
||||
super(prompt,
|
||||
AiOperationMetadata.builder().operationType(AiOperationType.CHAT.value()).provider(provider).build());
|
||||
Assert.notNull(requestOptions, "requestOptions cannot be null");
|
||||
this.requestOptions = requestOptions;
|
||||
}
|
||||
|
||||
public ChatModelRequestOptions getRequestOptions() {
|
||||
public ChatOptions getRequestOptions() {
|
||||
return this.requestOptions;
|
||||
}
|
||||
|
||||
@@ -50,9 +52,9 @@ public class ChatModelObservationContext extends ModelObservationContext<Prompt,
|
||||
|
||||
private Prompt prompt;
|
||||
|
||||
private AiOperationMetadata operationMetadata;
|
||||
private String provider;
|
||||
|
||||
private ChatModelRequestOptions requestOptions;
|
||||
private ChatOptions requestOptions;
|
||||
|
||||
private Builder() {
|
||||
}
|
||||
@@ -62,18 +64,18 @@ public class ChatModelObservationContext extends ModelObservationContext<Prompt,
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder operationMetadata(AiOperationMetadata operationMetadata) {
|
||||
this.operationMetadata = operationMetadata;
|
||||
public Builder provider(String provider) {
|
||||
this.provider = provider;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder requestOptions(ChatModelRequestOptions requestOptions) {
|
||||
public Builder requestOptions(ChatOptions requestOptions) {
|
||||
this.requestOptions = requestOptions;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ChatModelObservationContext build() {
|
||||
return new ChatModelObservationContext(prompt, operationMetadata, requestOptions);
|
||||
return new ChatModelObservationContext(prompt, provider, requestOptions);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,201 +0,0 @@
|
||||
/*
|
||||
* Copyright 2024 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.chat.observation;
|
||||
|
||||
import org.springframework.ai.chat.prompt.ChatOptions;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Represents client-side options for chat model requests.
|
||||
*
|
||||
* @author Thomas Vitale
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class ChatModelRequestOptions implements ChatOptions {
|
||||
|
||||
private final String model;
|
||||
|
||||
@Nullable
|
||||
private final Float frequencyPenalty;
|
||||
|
||||
@Nullable
|
||||
private final Integer maxTokens;
|
||||
|
||||
@Nullable
|
||||
private final Float presencePenalty;
|
||||
|
||||
@Nullable
|
||||
private final List<String> stopSequences;
|
||||
|
||||
@Nullable
|
||||
private final Float temperature;
|
||||
|
||||
@Nullable
|
||||
private final Integer topK;
|
||||
|
||||
@Nullable
|
||||
private final Float topP;
|
||||
|
||||
ChatModelRequestOptions(Builder builder) {
|
||||
Assert.hasText(builder.model, "model cannot be null or empty");
|
||||
|
||||
this.model = builder.model;
|
||||
this.frequencyPenalty = builder.frequencyPenalty;
|
||||
this.maxTokens = builder.maxTokens;
|
||||
this.presencePenalty = builder.presencePenalty;
|
||||
this.stopSequences = builder.stopSequences;
|
||||
this.temperature = builder.temperature;
|
||||
this.topK = builder.topK;
|
||||
this.topP = builder.topP;
|
||||
}
|
||||
|
||||
public static Builder builder() {
|
||||
return new Builder();
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
|
||||
private String model;
|
||||
|
||||
@Nullable
|
||||
private Float frequencyPenalty;
|
||||
|
||||
@Nullable
|
||||
private Integer maxTokens;
|
||||
|
||||
@Nullable
|
||||
private Float presencePenalty;
|
||||
|
||||
@Nullable
|
||||
private List<String> stopSequences;
|
||||
|
||||
@Nullable
|
||||
private Float temperature;
|
||||
|
||||
@Nullable
|
||||
private Integer topK;
|
||||
|
||||
@Nullable
|
||||
private Float topP;
|
||||
|
||||
private Builder() {
|
||||
}
|
||||
|
||||
public Builder model(String model) {
|
||||
this.model = model;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder frequencyPenalty(@Nullable Float frequencyPenalty) {
|
||||
this.frequencyPenalty = frequencyPenalty;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder maxTokens(@Nullable Integer maxTokens) {
|
||||
this.maxTokens = maxTokens;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder presencePenalty(@Nullable Float presencePenalty) {
|
||||
this.presencePenalty = presencePenalty;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder stopSequences(@Nullable List<String> stopSequences) {
|
||||
this.stopSequences = stopSequences;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder temperature(@Nullable Float temperature) {
|
||||
this.temperature = temperature;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder topK(@Nullable Integer topK) {
|
||||
this.topK = topK;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder topP(@Nullable Float topP) {
|
||||
this.topP = topP;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ChatModelRequestOptions build() {
|
||||
return new ChatModelRequestOptions(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public String getModel() {
|
||||
return this.model;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Float getFrequencyPenalty() {
|
||||
return this.frequencyPenalty;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Integer getMaxTokens() {
|
||||
return this.maxTokens;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Float getPresencePenalty() {
|
||||
return this.presencePenalty;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public List<String> getStopSequences() {
|
||||
return this.stopSequences;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public Float getTemperature() {
|
||||
return this.temperature;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public Integer getTopK() {
|
||||
return this.topK;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public Float getTopP() {
|
||||
return this.topP;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChatOptions copy() {
|
||||
return builder().model(this.model)
|
||||
.frequencyPenalty(this.frequencyPenalty)
|
||||
.maxTokens(this.maxTokens)
|
||||
.presencePenalty(this.presencePenalty)
|
||||
.stopSequences(this.stopSequences != null ? List.copyOf(this.stopSequences) : null)
|
||||
.temperature(this.temperature)
|
||||
.topK(this.topK)
|
||||
.topP(this.topP)
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -18,6 +18,7 @@ package org.springframework.ai.chat.observation;
|
||||
import io.micrometer.common.KeyValue;
|
||||
import io.micrometer.common.KeyValues;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.util.StringJoiner;
|
||||
|
||||
@@ -29,6 +30,9 @@ import java.util.StringJoiner;
|
||||
*/
|
||||
public class DefaultChatModelObservationConvention implements ChatModelObservationConvention {
|
||||
|
||||
private static final KeyValue REQUEST_MODEL_NONE = KeyValue
|
||||
.of(ChatModelObservationDocumentation.LowCardinalityKeyNames.REQUEST_MODEL, KeyValue.NONE_VALUE);
|
||||
|
||||
private static final KeyValue RESPONSE_MODEL_NONE = KeyValue
|
||||
.of(ChatModelObservationDocumentation.LowCardinalityKeyNames.RESPONSE_MODEL, KeyValue.NONE_VALUE);
|
||||
|
||||
@@ -77,8 +81,11 @@ public class DefaultChatModelObservationConvention implements ChatModelObservati
|
||||
|
||||
@Override
|
||||
public String getContextualName(ChatModelObservationContext context) {
|
||||
return "%s %s".formatted(context.getOperationMetadata().operationType(),
|
||||
context.getRequestOptions().getModel());
|
||||
if (StringUtils.hasText(context.getRequestOptions().getModel())) {
|
||||
return "%s %s".formatted(context.getOperationMetadata().operationType(),
|
||||
context.getRequestOptions().getModel());
|
||||
}
|
||||
return context.getOperationMetadata().operationType();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -98,8 +105,11 @@ public class DefaultChatModelObservationConvention implements ChatModelObservati
|
||||
}
|
||||
|
||||
protected KeyValue requestModel(ChatModelObservationContext context) {
|
||||
return KeyValue.of(ChatModelObservationDocumentation.LowCardinalityKeyNames.REQUEST_MODEL,
|
||||
context.getRequestOptions().getModel());
|
||||
if (StringUtils.hasText(context.getRequestOptions().getModel())) {
|
||||
return KeyValue.of(ChatModelObservationDocumentation.LowCardinalityKeyNames.REQUEST_MODEL,
|
||||
context.getRequestOptions().getModel());
|
||||
}
|
||||
return REQUEST_MODEL_NONE;
|
||||
}
|
||||
|
||||
protected KeyValue responseModel(ChatModelObservationContext context) {
|
||||
|
||||
@@ -16,18 +16,39 @@
|
||||
package org.springframework.ai.chat.prompt;
|
||||
|
||||
import org.springframework.ai.model.ModelOptions;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* The ChatOptions represent the common options, portable across different chat models.
|
||||
*/
|
||||
public interface ChatOptions extends ModelOptions {
|
||||
|
||||
@Nullable
|
||||
String getModel();
|
||||
|
||||
@Nullable
|
||||
Float getFrequencyPenalty();
|
||||
|
||||
@Nullable
|
||||
Integer getMaxTokens();
|
||||
|
||||
@Nullable
|
||||
Float getPresencePenalty();
|
||||
|
||||
@Nullable
|
||||
List<String> getStopSequences();
|
||||
|
||||
@Nullable
|
||||
Float getTemperature();
|
||||
|
||||
Float getTopP();
|
||||
|
||||
@Nullable
|
||||
Integer getTopK();
|
||||
|
||||
@Nullable
|
||||
Float getTopP();
|
||||
|
||||
ChatOptions copy();
|
||||
|
||||
}
|
||||
|
||||
@@ -15,15 +15,72 @@
|
||||
*/
|
||||
package org.springframework.ai.chat.prompt;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class ChatOptionsBuilder {
|
||||
|
||||
private class ChatOptionsImpl implements ChatOptions {
|
||||
private static class DefaultChatOptions implements ChatOptions {
|
||||
|
||||
private String model;
|
||||
|
||||
private Float frequencyPenalty;
|
||||
|
||||
private Integer maxTokens;
|
||||
|
||||
private Float presencePenalty;
|
||||
|
||||
private List<String> stopSequences;
|
||||
|
||||
private Float temperature;
|
||||
|
||||
private Integer topK;
|
||||
|
||||
private Float topP;
|
||||
|
||||
private Integer topK;
|
||||
@Override
|
||||
public String getModel() {
|
||||
return model;
|
||||
}
|
||||
|
||||
public void setModel(String model) {
|
||||
this.model = model;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Float getFrequencyPenalty() {
|
||||
return frequencyPenalty;
|
||||
}
|
||||
|
||||
public void setFrequencyPenalty(Float frequencyPenalty) {
|
||||
this.frequencyPenalty = frequencyPenalty;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getMaxTokens() {
|
||||
return maxTokens;
|
||||
}
|
||||
|
||||
public void setMaxTokens(Integer maxTokens) {
|
||||
this.maxTokens = maxTokens;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Float getPresencePenalty() {
|
||||
return presencePenalty;
|
||||
}
|
||||
|
||||
public void setPresencePenalty(Float presencePenalty) {
|
||||
this.presencePenalty = presencePenalty;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getStopSequences() {
|
||||
return stopSequences;
|
||||
}
|
||||
|
||||
public void setStopSequences(List<String> stopSequences) {
|
||||
this.stopSequences = stopSequences;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Float getTemperature() {
|
||||
@@ -34,15 +91,6 @@ public class ChatOptionsBuilder {
|
||||
this.temperature = temperature;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Float getTopP() {
|
||||
return topP;
|
||||
}
|
||||
|
||||
public void setTopP(Float topP) {
|
||||
this.topP = topP;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getTopK() {
|
||||
return topK;
|
||||
@@ -52,14 +100,31 @@ public class ChatOptionsBuilder {
|
||||
this.topK = topK;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Float getTopP() {
|
||||
return topP;
|
||||
}
|
||||
|
||||
public void setTopP(Float topP) {
|
||||
this.topP = topP;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChatOptions copy() {
|
||||
return builder().withTemperature(this.temperature).withTopP(this.topP).withTopK(this.topK).build();
|
||||
return builder().withModel(this.model)
|
||||
.withFrequencyPenalty(this.frequencyPenalty)
|
||||
.withMaxTokens(this.maxTokens)
|
||||
.withPresencePenalty(this.presencePenalty)
|
||||
.withStopSequences(this.stopSequences != null ? List.copyOf(this.stopSequences) : null)
|
||||
.withTemperature(this.temperature)
|
||||
.withTopK(this.topK)
|
||||
.withTopP(this.topP)
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private final ChatOptionsImpl options = new ChatOptionsImpl();
|
||||
private final DefaultChatOptions options = new DefaultChatOptions();
|
||||
|
||||
private ChatOptionsBuilder() {
|
||||
}
|
||||
@@ -68,13 +133,33 @@ public class ChatOptionsBuilder {
|
||||
return new ChatOptionsBuilder();
|
||||
}
|
||||
|
||||
public ChatOptionsBuilder withTemperature(Float temperature) {
|
||||
options.setTemperature(temperature);
|
||||
public ChatOptionsBuilder withModel(String model) {
|
||||
options.setModel(model);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ChatOptionsBuilder withTopP(Float topP) {
|
||||
options.setTopP(topP);
|
||||
public ChatOptionsBuilder withFrequencyPenalty(Float frequencyPenalty) {
|
||||
options.setFrequencyPenalty(frequencyPenalty);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ChatOptionsBuilder withMaxTokens(Integer maxTokens) {
|
||||
options.setMaxTokens(maxTokens);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ChatOptionsBuilder withPresencePenalty(Float presencePenalty) {
|
||||
options.setPresencePenalty(presencePenalty);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ChatOptionsBuilder withStopSequences(List<String> stop) {
|
||||
options.setStopSequences(stop);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ChatOptionsBuilder withTemperature(Float temperature) {
|
||||
options.setTemperature(temperature);
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -83,8 +168,13 @@ public class ChatOptionsBuilder {
|
||||
return this;
|
||||
}
|
||||
|
||||
public ChatOptionsBuilder withTopP(Float topP) {
|
||||
options.setTopP(topP);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ChatOptions build() {
|
||||
return options;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@ public class DefaultEmbeddingModelObservationConvention implements EmbeddingMode
|
||||
|
||||
protected KeyValue aiOperationType(EmbeddingModelObservationContext context) {
|
||||
return KeyValue.of(EmbeddingModelObservationDocumentation.LowCardinalityKeyNames.AI_OPERATION_TYPE,
|
||||
context.getOperationType());
|
||||
context.getOperationMetadata().operationType());
|
||||
}
|
||||
|
||||
protected KeyValue aiProvider(EmbeddingModelObservationContext context) {
|
||||
|
||||
@@ -33,9 +33,13 @@ public class EmbeddingModelObservationContext extends ModelObservationContext<Em
|
||||
|
||||
private final EmbeddingOptions requestOptions;
|
||||
|
||||
EmbeddingModelObservationContext(EmbeddingRequest embeddingRequest, AiOperationMetadata operationMetadata,
|
||||
EmbeddingModelObservationContext(EmbeddingRequest embeddingRequest, String provider,
|
||||
EmbeddingOptions requestOptions) {
|
||||
super(embeddingRequest, operationMetadata);
|
||||
super(embeddingRequest,
|
||||
AiOperationMetadata.builder()
|
||||
.operationType(AiOperationType.EMBEDDING.value())
|
||||
.provider(provider)
|
||||
.build());
|
||||
Assert.notNull(requestOptions, "requestOptions cannot be null");
|
||||
this.requestOptions = requestOptions;
|
||||
}
|
||||
@@ -44,10 +48,6 @@ public class EmbeddingModelObservationContext extends ModelObservationContext<Em
|
||||
return requestOptions;
|
||||
}
|
||||
|
||||
public String getOperationType() {
|
||||
return AiOperationType.EMBEDDING.value();
|
||||
}
|
||||
|
||||
public static Builder builder() {
|
||||
return new Builder();
|
||||
}
|
||||
@@ -56,7 +56,7 @@ public class EmbeddingModelObservationContext extends ModelObservationContext<Em
|
||||
|
||||
private EmbeddingRequest embeddingRequest;
|
||||
|
||||
private AiOperationMetadata operationMetadata;
|
||||
private String provider;
|
||||
|
||||
private EmbeddingOptions requestOptions;
|
||||
|
||||
@@ -68,8 +68,8 @@ public class EmbeddingModelObservationContext extends ModelObservationContext<Em
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder operationMetadata(AiOperationMetadata operationMetadata) {
|
||||
this.operationMetadata = operationMetadata;
|
||||
public Builder provider(String provider) {
|
||||
this.provider = provider;
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -79,7 +79,7 @@ public class EmbeddingModelObservationContext extends ModelObservationContext<Em
|
||||
}
|
||||
|
||||
public EmbeddingModelObservationContext build() {
|
||||
return new EmbeddingModelObservationContext(embeddingRequest, operationMetadata, requestOptions);
|
||||
return new EmbeddingModelObservationContext(embeddingRequest, provider, requestOptions);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -63,7 +63,7 @@ public class DefaultImageModelObservationConvention implements ImageModelObserva
|
||||
|
||||
protected KeyValue aiOperationType(ImageModelObservationContext context) {
|
||||
return KeyValue.of(ImageModelObservationDocumentation.LowCardinalityKeyNames.AI_OPERATION_TYPE,
|
||||
context.getOperationType());
|
||||
context.getOperationMetadata().operationType());
|
||||
}
|
||||
|
||||
protected KeyValue aiProvider(ImageModelObservationContext context) {
|
||||
|
||||
@@ -33,9 +33,9 @@ public class ImageModelObservationContext extends ModelObservationContext<ImageP
|
||||
|
||||
private final ImageOptions requestOptions;
|
||||
|
||||
ImageModelObservationContext(ImagePrompt imagePrompt, AiOperationMetadata operationMetadata,
|
||||
ImageOptions requestOptions) {
|
||||
super(imagePrompt, operationMetadata);
|
||||
ImageModelObservationContext(ImagePrompt imagePrompt, String provider, ImageOptions requestOptions) {
|
||||
super(imagePrompt,
|
||||
AiOperationMetadata.builder().operationType(AiOperationType.IMAGE.value()).provider(provider).build());
|
||||
Assert.notNull(requestOptions, "requestOptions cannot be null");
|
||||
this.requestOptions = requestOptions;
|
||||
}
|
||||
@@ -56,7 +56,7 @@ public class ImageModelObservationContext extends ModelObservationContext<ImageP
|
||||
|
||||
private ImagePrompt imagePrompt;
|
||||
|
||||
private AiOperationMetadata operationMetadata;
|
||||
private String provider;
|
||||
|
||||
private ImageOptions requestOptions;
|
||||
|
||||
@@ -68,8 +68,8 @@ public class ImageModelObservationContext extends ModelObservationContext<ImageP
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder operationMetadata(AiOperationMetadata operationMetadata) {
|
||||
this.operationMetadata = operationMetadata;
|
||||
public Builder provider(String provider) {
|
||||
this.provider = provider;
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -79,7 +79,7 @@ public class ImageModelObservationContext extends ModelObservationContext<ImageP
|
||||
}
|
||||
|
||||
public ImageModelObservationContext build() {
|
||||
return new ImageModelObservationContext(imagePrompt, operationMetadata, requestOptions);
|
||||
return new ImageModelObservationContext(imagePrompt, provider, requestOptions);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -61,18 +61,43 @@ public class FunctionCallingOptionsBuilder {
|
||||
return this;
|
||||
}
|
||||
|
||||
public FunctionCallingOptionsBuilder withModel(String model) {
|
||||
this.options.setModel(model);
|
||||
return this;
|
||||
}
|
||||
|
||||
public FunctionCallingOptionsBuilder withFrequencyPenalty(Float frequencyPenalty) {
|
||||
this.options.setFrequencyPenalty(frequencyPenalty);
|
||||
return this;
|
||||
}
|
||||
|
||||
public FunctionCallingOptionsBuilder withMaxTokens(Integer maxTokens) {
|
||||
this.options.setMaxTokens(maxTokens);
|
||||
return this;
|
||||
}
|
||||
|
||||
public FunctionCallingOptionsBuilder withPresencePenalty(Float presencePenalty) {
|
||||
this.options.setPresencePenalty(presencePenalty);
|
||||
return this;
|
||||
}
|
||||
|
||||
public FunctionCallingOptionsBuilder withStopSequences(List<String> stopSequences) {
|
||||
this.options.setStopSequences(stopSequences);
|
||||
return this;
|
||||
}
|
||||
|
||||
public FunctionCallingOptionsBuilder withTemperature(Float temperature) {
|
||||
this.options.setTemperature(temperature);
|
||||
return this;
|
||||
}
|
||||
|
||||
public FunctionCallingOptionsBuilder withTopP(Float topP) {
|
||||
this.options.setTopP(topP);
|
||||
public FunctionCallingOptionsBuilder withTopK(Integer topK) {
|
||||
this.options.setTopK(topK);
|
||||
return this;
|
||||
}
|
||||
|
||||
public FunctionCallingOptionsBuilder withTopK(Integer topK) {
|
||||
this.options.setTopK(topK);
|
||||
public FunctionCallingOptionsBuilder withTopP(Float topP) {
|
||||
this.options.setTopP(topP);
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -86,12 +111,22 @@ public class FunctionCallingOptionsBuilder {
|
||||
|
||||
private Set<String> functions = new HashSet<>();
|
||||
|
||||
private String model;
|
||||
|
||||
private Float frequencyPenalty;
|
||||
|
||||
private Integer maxTokens;
|
||||
|
||||
private Float presencePenalty;
|
||||
|
||||
private List<String> stopSequences;
|
||||
|
||||
private Float temperature;
|
||||
|
||||
private Float topP;
|
||||
|
||||
private Integer topK;
|
||||
|
||||
private Float topP;
|
||||
|
||||
@Override
|
||||
public List<FunctionCallback> getFunctionCallbacks() {
|
||||
return this.functionCallbacks;
|
||||
@@ -112,38 +147,88 @@ public class FunctionCallingOptionsBuilder {
|
||||
this.functions = functions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getModel() {
|
||||
return model;
|
||||
}
|
||||
|
||||
public void setModel(String model) {
|
||||
this.model = model;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Float getFrequencyPenalty() {
|
||||
return frequencyPenalty;
|
||||
}
|
||||
|
||||
public void setFrequencyPenalty(Float frequencyPenalty) {
|
||||
this.frequencyPenalty = frequencyPenalty;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getMaxTokens() {
|
||||
return maxTokens;
|
||||
}
|
||||
|
||||
public void setMaxTokens(Integer maxTokens) {
|
||||
this.maxTokens = maxTokens;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Float getPresencePenalty() {
|
||||
return presencePenalty;
|
||||
}
|
||||
|
||||
public void setPresencePenalty(Float presencePenalty) {
|
||||
this.presencePenalty = presencePenalty;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getStopSequences() {
|
||||
return stopSequences;
|
||||
}
|
||||
|
||||
public void setStopSequences(List<String> stopSequences) {
|
||||
this.stopSequences = stopSequences;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Float getTemperature() {
|
||||
return this.temperature;
|
||||
return temperature;
|
||||
}
|
||||
|
||||
public void setTemperature(Float temperature) {
|
||||
this.temperature = temperature;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Float getTopP() {
|
||||
return this.topP;
|
||||
}
|
||||
|
||||
public void setTopP(Float topP) {
|
||||
this.topP = topP;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getTopK() {
|
||||
return this.topK;
|
||||
return topK;
|
||||
}
|
||||
|
||||
public void setTopK(Integer topK) {
|
||||
this.topK = topK;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Float getTopP() {
|
||||
return topP;
|
||||
}
|
||||
|
||||
public void setTopP(Float topP) {
|
||||
this.topP = topP;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChatOptions copy() {
|
||||
return new FunctionCallingOptionsBuilder().withTemperature(this.temperature)
|
||||
.withTopP(this.topP)
|
||||
return new FunctionCallingOptionsBuilder().withModel(this.model)
|
||||
.withFrequencyPenalty(this.frequencyPenalty)
|
||||
.withMaxTokens(this.maxTokens)
|
||||
.withPresencePenalty(this.presencePenalty)
|
||||
.withStopSequences(this.stopSequences)
|
||||
.withTemperature(this.temperature)
|
||||
.withTopK(this.topK)
|
||||
.withTopP(this.topP)
|
||||
.withFunctions(this.functions)
|
||||
.withFunctionCallbacks(this.functionCallbacks)
|
||||
.build();
|
||||
@@ -151,4 +236,4 @@ public class FunctionCallingOptionsBuilder {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,10 +21,8 @@ import org.junit.jupiter.api.Test;
|
||||
import org.springframework.ai.chat.messages.AssistantMessage;
|
||||
import org.springframework.ai.chat.model.ChatResponse;
|
||||
import org.springframework.ai.chat.model.Generation;
|
||||
import org.springframework.ai.chat.prompt.ChatOptionsBuilder;
|
||||
import org.springframework.ai.chat.prompt.Prompt;
|
||||
import org.springframework.ai.observation.AiOperationMetadata;
|
||||
import org.springframework.ai.observation.conventions.AiOperationType;
|
||||
import org.springframework.ai.observation.conventions.AiProvider;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -52,8 +50,8 @@ class ChatModelCompletionObservationFilterTests {
|
||||
void whenEmptyResponseThenReturnOriginalContext() {
|
||||
var expectedContext = ChatModelObservationContext.builder()
|
||||
.prompt(generatePrompt())
|
||||
.operationMetadata(generateOperationMetadata())
|
||||
.requestOptions(ChatModelRequestOptions.builder().model("mistral").build())
|
||||
.provider("superprovider")
|
||||
.requestOptions(ChatOptionsBuilder.builder().withModel("mistral").build())
|
||||
.build();
|
||||
var actualContext = observationFilter.map(expectedContext);
|
||||
|
||||
@@ -64,8 +62,8 @@ class ChatModelCompletionObservationFilterTests {
|
||||
void whenEmptyCompletionThenReturnOriginalContext() {
|
||||
var expectedContext = ChatModelObservationContext.builder()
|
||||
.prompt(generatePrompt())
|
||||
.operationMetadata(generateOperationMetadata())
|
||||
.requestOptions(ChatModelRequestOptions.builder().model("mistral").build())
|
||||
.provider("superprovider")
|
||||
.requestOptions(ChatOptionsBuilder.builder().withModel("mistral").build())
|
||||
.build();
|
||||
expectedContext.setResponse(new ChatResponse(List.of(new Generation(new AssistantMessage("")))));
|
||||
var actualContext = observationFilter.map(expectedContext);
|
||||
@@ -77,8 +75,8 @@ class ChatModelCompletionObservationFilterTests {
|
||||
void whenCompletionWithTextThenAugmentContext() {
|
||||
var originalContext = ChatModelObservationContext.builder()
|
||||
.prompt(generatePrompt())
|
||||
.operationMetadata(generateOperationMetadata())
|
||||
.requestOptions(ChatModelRequestOptions.builder().model("mistral").build())
|
||||
.provider("superprovider")
|
||||
.requestOptions(ChatOptionsBuilder.builder().withModel("mistral").build())
|
||||
.build();
|
||||
originalContext.setResponse(new ChatResponse(List.of(new Generation(new AssistantMessage("say please")),
|
||||
new Generation(new AssistantMessage("seriously, say please")))));
|
||||
@@ -92,11 +90,4 @@ class ChatModelCompletionObservationFilterTests {
|
||||
return new Prompt("supercalifragilisticexpialidocious");
|
||||
}
|
||||
|
||||
private AiOperationMetadata generateOperationMetadata() {
|
||||
return AiOperationMetadata.builder()
|
||||
.operationType(AiOperationType.CHAT.value())
|
||||
.provider(AiProvider.OLLAMA.value())
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -26,8 +26,8 @@ import org.springframework.ai.chat.metadata.ChatResponseMetadata;
|
||||
import org.springframework.ai.chat.metadata.Usage;
|
||||
import org.springframework.ai.chat.model.ChatResponse;
|
||||
import org.springframework.ai.chat.model.Generation;
|
||||
import org.springframework.ai.chat.prompt.ChatOptionsBuilder;
|
||||
import org.springframework.ai.chat.prompt.Prompt;
|
||||
import org.springframework.ai.observation.AiOperationMetadata;
|
||||
import org.springframework.ai.observation.conventions.*;
|
||||
|
||||
import java.util.List;
|
||||
@@ -70,7 +70,7 @@ class ChatModelMeterObservationHandlerTests {
|
||||
assertThat(meterRegistry.get(AiObservationMetricNames.TOKEN_USAGE.value()).meters()).hasSize(3);
|
||||
assertThat(meterRegistry.get(AiObservationMetricNames.TOKEN_USAGE.value())
|
||||
.tag(LowCardinalityKeyNames.AI_OPERATION_TYPE.asString(), AiOperationType.CHAT.value())
|
||||
.tag(LowCardinalityKeyNames.AI_PROVIDER.asString(), AiProvider.OLLAMA.value())
|
||||
.tag(LowCardinalityKeyNames.AI_PROVIDER.asString(), "superprovider")
|
||||
.tag(LowCardinalityKeyNames.REQUEST_MODEL.asString(), "mistral")
|
||||
.tag(LowCardinalityKeyNames.RESPONSE_MODEL.asString(), "mistral-42")
|
||||
.meters()).hasSize(3);
|
||||
@@ -88,8 +88,8 @@ class ChatModelMeterObservationHandlerTests {
|
||||
private ChatModelObservationContext generateObservationContext() {
|
||||
return ChatModelObservationContext.builder()
|
||||
.prompt(generatePrompt())
|
||||
.operationMetadata(generateOperationMetadata())
|
||||
.requestOptions(ChatModelRequestOptions.builder().model("mistral").build())
|
||||
.provider("superprovider")
|
||||
.requestOptions(ChatOptionsBuilder.builder().withModel("mistral").build())
|
||||
.build();
|
||||
}
|
||||
|
||||
@@ -97,13 +97,6 @@ class ChatModelMeterObservationHandlerTests {
|
||||
return new Prompt("hello");
|
||||
}
|
||||
|
||||
private AiOperationMetadata generateOperationMetadata() {
|
||||
return AiOperationMetadata.builder()
|
||||
.operationType(AiOperationType.CHAT.value())
|
||||
.provider(AiProvider.OLLAMA.value())
|
||||
.build();
|
||||
}
|
||||
|
||||
static class TestUsage implements Usage {
|
||||
|
||||
@Override
|
||||
|
||||
@@ -16,10 +16,8 @@
|
||||
package org.springframework.ai.chat.observation;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.ai.chat.prompt.ChatOptionsBuilder;
|
||||
import org.springframework.ai.chat.prompt.Prompt;
|
||||
import org.springframework.ai.observation.AiOperationMetadata;
|
||||
import org.springframework.ai.observation.conventions.AiOperationType;
|
||||
import org.springframework.ai.observation.conventions.AiProvider;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
@@ -35,8 +33,8 @@ class ChatModelObservationContextTests {
|
||||
void whenMandatoryRequestOptionsThenReturn() {
|
||||
var observationContext = ChatModelObservationContext.builder()
|
||||
.prompt(generatePrompt())
|
||||
.operationMetadata(generateOperationMetadata())
|
||||
.requestOptions(ChatModelRequestOptions.builder().model("supermodel").build())
|
||||
.provider("superprovider")
|
||||
.requestOptions(ChatOptionsBuilder.builder().withModel("supermodel").build())
|
||||
.build();
|
||||
|
||||
assertThat(observationContext).isNotNull();
|
||||
@@ -46,7 +44,7 @@ class ChatModelObservationContextTests {
|
||||
void whenRequestOptionsIsNullThenThrow() {
|
||||
assertThatThrownBy(() -> ChatModelObservationContext.builder()
|
||||
.prompt(generatePrompt())
|
||||
.operationMetadata(generateOperationMetadata())
|
||||
.provider("superprovider")
|
||||
.requestOptions(null)
|
||||
.build()).isInstanceOf(IllegalArgumentException.class)
|
||||
.hasMessageContaining("requestOptions cannot be null");
|
||||
@@ -56,11 +54,4 @@ class ChatModelObservationContextTests {
|
||||
return new Prompt("hello");
|
||||
}
|
||||
|
||||
private AiOperationMetadata generateOperationMetadata() {
|
||||
return AiOperationMetadata.builder()
|
||||
.operationType(AiOperationType.CHAT.value())
|
||||
.provider(AiProvider.OLLAMA.value())
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -20,10 +20,8 @@ import io.micrometer.observation.Observation;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.ai.chat.messages.SystemMessage;
|
||||
import org.springframework.ai.chat.messages.UserMessage;
|
||||
import org.springframework.ai.chat.prompt.ChatOptionsBuilder;
|
||||
import org.springframework.ai.chat.prompt.Prompt;
|
||||
import org.springframework.ai.observation.AiOperationMetadata;
|
||||
import org.springframework.ai.observation.conventions.AiOperationType;
|
||||
import org.springframework.ai.observation.conventions.AiProvider;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -51,8 +49,8 @@ class ChatModelPromptContentObservationFilterTests {
|
||||
void whenEmptyPromptThenReturnOriginalContext() {
|
||||
var expectedContext = ChatModelObservationContext.builder()
|
||||
.prompt(new Prompt(List.of()))
|
||||
.operationMetadata(generateOperationMetadata())
|
||||
.requestOptions(ChatModelRequestOptions.builder().model("mistral").build())
|
||||
.provider("superprovider")
|
||||
.requestOptions(ChatOptionsBuilder.builder().withModel("mistral").build())
|
||||
.build();
|
||||
var actualContext = observationFilter.map(expectedContext);
|
||||
|
||||
@@ -63,8 +61,8 @@ class ChatModelPromptContentObservationFilterTests {
|
||||
void whenPromptWithTextThenAugmentContext() {
|
||||
var originalContext = ChatModelObservationContext.builder()
|
||||
.prompt(new Prompt("supercalifragilisticexpialidocious"))
|
||||
.operationMetadata(generateOperationMetadata())
|
||||
.requestOptions(ChatModelRequestOptions.builder().model("mistral").build())
|
||||
.provider("superprovider")
|
||||
.requestOptions(ChatOptionsBuilder.builder().withModel("mistral").build())
|
||||
.build();
|
||||
var augmentedContext = observationFilter.map(originalContext);
|
||||
|
||||
@@ -77,8 +75,8 @@ class ChatModelPromptContentObservationFilterTests {
|
||||
var originalContext = ChatModelObservationContext.builder()
|
||||
.prompt(new Prompt(List.of(new SystemMessage("you're a chimney sweep"),
|
||||
new UserMessage("supercalifragilisticexpialidocious"))))
|
||||
.operationMetadata(generateOperationMetadata())
|
||||
.requestOptions(ChatModelRequestOptions.builder().model("mistral").build())
|
||||
.provider("superprovider")
|
||||
.requestOptions(ChatOptionsBuilder.builder().withModel("mistral").build())
|
||||
.build();
|
||||
var augmentedContext = observationFilter.map(originalContext);
|
||||
|
||||
@@ -87,11 +85,4 @@ class ChatModelPromptContentObservationFilterTests {
|
||||
"[\"you're a chimney sweep\", \"supercalifragilisticexpialidocious\"]"));
|
||||
}
|
||||
|
||||
private AiOperationMetadata generateOperationMetadata() {
|
||||
return AiOperationMetadata.builder()
|
||||
.operationType(AiOperationType.CHAT.value())
|
||||
.provider(AiProvider.OLLAMA.value())
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
/*
|
||||
* Copyright 2024 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.chat.observation;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link ChatModelRequestOptions}.
|
||||
*
|
||||
* @author Thomas Vitale
|
||||
*/
|
||||
class ChatModelRequestOptionsTests {
|
||||
|
||||
@Test
|
||||
void whenMandatoryRequestOptionsThenReturn() {
|
||||
var requestOptions = ChatModelRequestOptions.builder().model("rowena").build();
|
||||
|
||||
assertThat(requestOptions).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenModelIsNullThenThrow() {
|
||||
assertThatThrownBy(() -> ChatModelRequestOptions.builder().build()).isInstanceOf(IllegalArgumentException.class)
|
||||
.hasMessageContaining("model cannot be null or empty");
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenModelIsEmptyThenThrow() {
|
||||
assertThatThrownBy(() -> ChatModelRequestOptions.builder().model("").build())
|
||||
.isInstanceOf(IllegalArgumentException.class)
|
||||
.hasMessageContaining("model cannot be null or empty");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -24,10 +24,8 @@ import org.springframework.ai.chat.metadata.ChatResponseMetadata;
|
||||
import org.springframework.ai.chat.metadata.Usage;
|
||||
import org.springframework.ai.chat.model.ChatResponse;
|
||||
import org.springframework.ai.chat.model.Generation;
|
||||
import org.springframework.ai.chat.prompt.ChatOptionsBuilder;
|
||||
import org.springframework.ai.chat.prompt.Prompt;
|
||||
import org.springframework.ai.observation.AiOperationMetadata;
|
||||
import org.springframework.ai.observation.conventions.AiOperationType;
|
||||
import org.springframework.ai.observation.conventions.AiProvider;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -50,53 +48,63 @@ class DefaultChatModelObservationConventionTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldHaveContextualName() {
|
||||
void contextualNameWhenModelIsDefined() {
|
||||
ChatModelObservationContext observationContext = ChatModelObservationContext.builder()
|
||||
.prompt(generatePrompt())
|
||||
.operationMetadata(generateOperationMetadata())
|
||||
.requestOptions(ChatModelRequestOptions.builder().model("mistral").build())
|
||||
.provider("superprovider")
|
||||
.requestOptions(ChatOptionsBuilder.builder().withModel("mistral").build())
|
||||
.build();
|
||||
assertThat(this.observationConvention.getContextualName(observationContext)).isEqualTo("chat mistral");
|
||||
}
|
||||
|
||||
@Test
|
||||
void contextualNameWhenModelIsNotDefined() {
|
||||
ChatModelObservationContext observationContext = ChatModelObservationContext.builder()
|
||||
.prompt(generatePrompt())
|
||||
.provider("superprovider")
|
||||
.requestOptions(ChatOptionsBuilder.builder().build())
|
||||
.build();
|
||||
assertThat(this.observationConvention.getContextualName(observationContext)).isEqualTo("chat");
|
||||
}
|
||||
|
||||
@Test
|
||||
void supportsOnlyChatModelObservationContext() {
|
||||
ChatModelObservationContext observationContext = ChatModelObservationContext.builder()
|
||||
.prompt(generatePrompt())
|
||||
.operationMetadata(generateOperationMetadata())
|
||||
.requestOptions(ChatModelRequestOptions.builder().model("mistral").build())
|
||||
.provider("superprovider")
|
||||
.requestOptions(ChatOptionsBuilder.builder().withModel("mistral").build())
|
||||
.build();
|
||||
assertThat(this.observationConvention.supportsContext(observationContext)).isTrue();
|
||||
assertThat(this.observationConvention.supportsContext(new Observation.Context())).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldHaveRequiredKeyValues() {
|
||||
void shouldHaveLowCardinalityKeyValuesWhenDefined() {
|
||||
ChatModelObservationContext observationContext = ChatModelObservationContext.builder()
|
||||
.prompt(generatePrompt())
|
||||
.operationMetadata(generateOperationMetadata())
|
||||
.requestOptions(ChatModelRequestOptions.builder().model("mistral").build())
|
||||
.provider("superprovider")
|
||||
.requestOptions(ChatOptionsBuilder.builder().withModel("mistral").build())
|
||||
.build();
|
||||
assertThat(this.observationConvention.getLowCardinalityKeyValues(observationContext)).contains(
|
||||
KeyValue.of(LowCardinalityKeyNames.AI_OPERATION_TYPE.asString(), "chat"),
|
||||
KeyValue.of(LowCardinalityKeyNames.AI_PROVIDER.asString(), "ollama"),
|
||||
KeyValue.of(LowCardinalityKeyNames.AI_PROVIDER.asString(), "superprovider"),
|
||||
KeyValue.of(LowCardinalityKeyNames.REQUEST_MODEL.asString(), "mistral"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldHaveOptionalKeyValues() {
|
||||
void shouldHaveKeyValuesWhenDefinedAndResponse() {
|
||||
ChatModelObservationContext observationContext = ChatModelObservationContext.builder()
|
||||
.prompt(generatePrompt())
|
||||
.operationMetadata(generateOperationMetadata())
|
||||
.requestOptions(ChatModelRequestOptions.builder()
|
||||
.model("mistral")
|
||||
.frequencyPenalty(0.8f)
|
||||
.maxTokens(200)
|
||||
.presencePenalty(1.0f)
|
||||
.stopSequences(List.of("addio", "bye"))
|
||||
.temperature(0.5f)
|
||||
.topK(1)
|
||||
.topP(0.9f)
|
||||
.provider("superprovider")
|
||||
.requestOptions(ChatOptionsBuilder.builder()
|
||||
.withModel("mistral")
|
||||
.withFrequencyPenalty(0.8f)
|
||||
.withMaxTokens(200)
|
||||
.withPresencePenalty(1.0f)
|
||||
.withStopSequences(List.of("addio", "bye"))
|
||||
.withTemperature(0.5f)
|
||||
.withTopK(1)
|
||||
.withTopP(0.9f)
|
||||
.build())
|
||||
.build();
|
||||
observationContext.setResponse(new ChatResponse(
|
||||
@@ -125,14 +133,15 @@ class DefaultChatModelObservationConventionTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldHaveMissingKeyValues() {
|
||||
void shouldHaveNoneKeyValuesWhenMissing() {
|
||||
ChatModelObservationContext observationContext = ChatModelObservationContext.builder()
|
||||
.prompt(generatePrompt())
|
||||
.operationMetadata(generateOperationMetadata())
|
||||
.requestOptions(ChatModelRequestOptions.builder().model("mistral").build())
|
||||
.provider("superprovider")
|
||||
.requestOptions(ChatOptionsBuilder.builder().build())
|
||||
.build();
|
||||
assertThat(this.observationConvention.getLowCardinalityKeyValues(observationContext))
|
||||
.contains(KeyValue.of(LowCardinalityKeyNames.RESPONSE_MODEL.asString(), KeyValue.NONE_VALUE));
|
||||
assertThat(this.observationConvention.getLowCardinalityKeyValues(observationContext)).contains(
|
||||
KeyValue.of(LowCardinalityKeyNames.REQUEST_MODEL.asString(), KeyValue.NONE_VALUE),
|
||||
KeyValue.of(LowCardinalityKeyNames.RESPONSE_MODEL.asString(), KeyValue.NONE_VALUE));
|
||||
assertThat(this.observationConvention.getHighCardinalityKeyValues(observationContext)).contains(
|
||||
KeyValue.of(HighCardinalityKeyNames.REQUEST_FREQUENCY_PENALTY.asString(), KeyValue.NONE_VALUE),
|
||||
KeyValue.of(HighCardinalityKeyNames.REQUEST_MAX_TOKENS.asString(), KeyValue.NONE_VALUE),
|
||||
@@ -152,13 +161,6 @@ class DefaultChatModelObservationConventionTests {
|
||||
return new Prompt("Who let the dogs out?");
|
||||
}
|
||||
|
||||
private AiOperationMetadata generateOperationMetadata() {
|
||||
return AiOperationMetadata.builder()
|
||||
.operationType(AiOperationType.CHAT.value())
|
||||
.provider(AiProvider.OLLAMA.value())
|
||||
.build();
|
||||
}
|
||||
|
||||
static class TestUsage implements Usage {
|
||||
|
||||
@Override
|
||||
|
||||
@@ -23,9 +23,6 @@ import org.springframework.ai.embedding.EmbeddingOptionsBuilder;
|
||||
import org.springframework.ai.embedding.EmbeddingRequest;
|
||||
import org.springframework.ai.embedding.EmbeddingResponse;
|
||||
import org.springframework.ai.embedding.EmbeddingResponseMetadata;
|
||||
import org.springframework.ai.observation.AiOperationMetadata;
|
||||
import org.springframework.ai.observation.conventions.AiOperationType;
|
||||
import org.springframework.ai.observation.conventions.AiProvider;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -53,7 +50,7 @@ class DefaultEmbeddingModelObservationConventionTests {
|
||||
void contextualNameWhenModelIsDefined() {
|
||||
EmbeddingModelObservationContext observationContext = EmbeddingModelObservationContext.builder()
|
||||
.embeddingRequest(generateEmbeddingRequest())
|
||||
.operationMetadata(generateOperationMetadata())
|
||||
.provider("superprovider")
|
||||
.requestOptions(EmbeddingOptionsBuilder.builder().withModel("mistral").build())
|
||||
.build();
|
||||
assertThat(this.observationConvention.getContextualName(observationContext)).isEqualTo("embedding mistral");
|
||||
@@ -63,7 +60,7 @@ class DefaultEmbeddingModelObservationConventionTests {
|
||||
void contextualNameWhenModelIsNotDefined() {
|
||||
EmbeddingModelObservationContext observationContext = EmbeddingModelObservationContext.builder()
|
||||
.embeddingRequest(generateEmbeddingRequest())
|
||||
.operationMetadata(generateOperationMetadata())
|
||||
.provider("superprovider")
|
||||
.requestOptions(EmbeddingOptionsBuilder.builder().build())
|
||||
.build();
|
||||
assertThat(this.observationConvention.getContextualName(observationContext)).isEqualTo("embedding");
|
||||
@@ -73,7 +70,7 @@ class DefaultEmbeddingModelObservationConventionTests {
|
||||
void supportsOnlyEmbeddingModelObservationContext() {
|
||||
EmbeddingModelObservationContext observationContext = EmbeddingModelObservationContext.builder()
|
||||
.embeddingRequest(generateEmbeddingRequest())
|
||||
.operationMetadata(generateOperationMetadata())
|
||||
.provider("superprovider")
|
||||
.requestOptions(EmbeddingOptionsBuilder.builder().withModel("supermodel").build())
|
||||
.build();
|
||||
assertThat(this.observationConvention.supportsContext(observationContext)).isTrue();
|
||||
@@ -84,12 +81,12 @@ class DefaultEmbeddingModelObservationConventionTests {
|
||||
void shouldHaveLowCardinalityKeyValuesWhenDefined() {
|
||||
EmbeddingModelObservationContext observationContext = EmbeddingModelObservationContext.builder()
|
||||
.embeddingRequest(generateEmbeddingRequest())
|
||||
.operationMetadata(generateOperationMetadata())
|
||||
.provider("superprovider")
|
||||
.requestOptions(EmbeddingOptionsBuilder.builder().withModel("mistral").build())
|
||||
.build();
|
||||
assertThat(this.observationConvention.getLowCardinalityKeyValues(observationContext)).contains(
|
||||
KeyValue.of(LowCardinalityKeyNames.AI_OPERATION_TYPE.asString(), "embedding"),
|
||||
KeyValue.of(LowCardinalityKeyNames.AI_PROVIDER.asString(), "ollama"),
|
||||
KeyValue.of(LowCardinalityKeyNames.AI_PROVIDER.asString(), "superprovider"),
|
||||
KeyValue.of(LowCardinalityKeyNames.REQUEST_MODEL.asString(), "mistral"));
|
||||
}
|
||||
|
||||
@@ -97,7 +94,7 @@ class DefaultEmbeddingModelObservationConventionTests {
|
||||
void shouldHaveLowCardinalityKeyValuesWhenDefinedAndResponse() {
|
||||
EmbeddingModelObservationContext observationContext = EmbeddingModelObservationContext.builder()
|
||||
.embeddingRequest(generateEmbeddingRequest())
|
||||
.operationMetadata(generateOperationMetadata())
|
||||
.provider("superprovider")
|
||||
.requestOptions(EmbeddingOptionsBuilder.builder().withModel("mistral").withDimensions(1492).build())
|
||||
.build();
|
||||
observationContext.setResponse(new EmbeddingResponse(List.of(),
|
||||
@@ -114,7 +111,7 @@ class DefaultEmbeddingModelObservationConventionTests {
|
||||
void shouldHaveNoneKeyValuesWhenMissing() {
|
||||
EmbeddingModelObservationContext observationContext = EmbeddingModelObservationContext.builder()
|
||||
.embeddingRequest(generateEmbeddingRequest())
|
||||
.operationMetadata(generateOperationMetadata())
|
||||
.provider("superprovider")
|
||||
.requestOptions(EmbeddingOptionsBuilder.builder().build())
|
||||
.build();
|
||||
assertThat(this.observationConvention.getLowCardinalityKeyValues(observationContext)).contains(
|
||||
@@ -130,13 +127,6 @@ class DefaultEmbeddingModelObservationConventionTests {
|
||||
return new EmbeddingRequest(List.of(), EmbeddingOptionsBuilder.builder().build());
|
||||
}
|
||||
|
||||
private AiOperationMetadata generateOperationMetadata() {
|
||||
return AiOperationMetadata.builder()
|
||||
.operationType(AiOperationType.EMBEDDING.value())
|
||||
.provider(AiProvider.OLLAMA.value())
|
||||
.build();
|
||||
}
|
||||
|
||||
static class TestUsage implements Usage {
|
||||
|
||||
@Override
|
||||
|
||||
@@ -26,7 +26,6 @@ import org.springframework.ai.embedding.EmbeddingOptionsBuilder;
|
||||
import org.springframework.ai.embedding.EmbeddingRequest;
|
||||
import org.springframework.ai.embedding.EmbeddingResponse;
|
||||
import org.springframework.ai.embedding.EmbeddingResponseMetadata;
|
||||
import org.springframework.ai.observation.AiOperationMetadata;
|
||||
import org.springframework.ai.observation.conventions.*;
|
||||
|
||||
import java.util.List;
|
||||
@@ -70,7 +69,7 @@ class EmbeddingModelMeterObservationHandlerTests {
|
||||
assertThat(meterRegistry.get(AiObservationMetricNames.TOKEN_USAGE.value()).meters()).hasSize(3);
|
||||
assertThat(meterRegistry.get(AiObservationMetricNames.TOKEN_USAGE.value())
|
||||
.tag(LowCardinalityKeyNames.AI_OPERATION_TYPE.asString(), AiOperationType.EMBEDDING.value())
|
||||
.tag(LowCardinalityKeyNames.AI_PROVIDER.asString(), AiProvider.OLLAMA.value())
|
||||
.tag(LowCardinalityKeyNames.AI_PROVIDER.asString(), "superprovider")
|
||||
.tag(LowCardinalityKeyNames.REQUEST_MODEL.asString(), "mistral")
|
||||
.tag(LowCardinalityKeyNames.RESPONSE_MODEL.asString(), "mistral-42")
|
||||
.meters()).hasSize(3);
|
||||
@@ -88,7 +87,7 @@ class EmbeddingModelMeterObservationHandlerTests {
|
||||
private EmbeddingModelObservationContext generateObservationContext() {
|
||||
return EmbeddingModelObservationContext.builder()
|
||||
.embeddingRequest(generateEmbeddingRequest())
|
||||
.operationMetadata(generateOperationMetadata())
|
||||
.provider("superprovider")
|
||||
.requestOptions(EmbeddingOptionsBuilder.builder().withModel("mistral").build())
|
||||
.build();
|
||||
}
|
||||
@@ -97,13 +96,6 @@ class EmbeddingModelMeterObservationHandlerTests {
|
||||
return new EmbeddingRequest(List.of(), EmbeddingOptionsBuilder.builder().build());
|
||||
}
|
||||
|
||||
private AiOperationMetadata generateOperationMetadata() {
|
||||
return AiOperationMetadata.builder()
|
||||
.operationType(AiOperationType.EMBEDDING.value())
|
||||
.provider(AiProvider.OLLAMA.value())
|
||||
.build();
|
||||
}
|
||||
|
||||
static class TestUsage implements Usage {
|
||||
|
||||
@Override
|
||||
|
||||
@@ -18,9 +18,6 @@ package org.springframework.ai.embedding.observation;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.ai.embedding.EmbeddingOptionsBuilder;
|
||||
import org.springframework.ai.embedding.EmbeddingRequest;
|
||||
import org.springframework.ai.observation.AiOperationMetadata;
|
||||
import org.springframework.ai.observation.conventions.AiOperationType;
|
||||
import org.springframework.ai.observation.conventions.AiProvider;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -38,7 +35,7 @@ class EmbeddingModelObservationContextTests {
|
||||
void whenMandatoryRequestOptionsThenReturn() {
|
||||
var observationContext = EmbeddingModelObservationContext.builder()
|
||||
.embeddingRequest(generateEmbeddingRequest())
|
||||
.operationMetadata(generateOperationMetadata())
|
||||
.provider("superprovider")
|
||||
.requestOptions(EmbeddingOptionsBuilder.builder().withModel("supermodel").build())
|
||||
.build();
|
||||
|
||||
@@ -49,7 +46,7 @@ class EmbeddingModelObservationContextTests {
|
||||
void whenRequestOptionsIsNullThenThrow() {
|
||||
assertThatThrownBy(() -> EmbeddingModelObservationContext.builder()
|
||||
.embeddingRequest(generateEmbeddingRequest())
|
||||
.operationMetadata(generateOperationMetadata())
|
||||
.provider("superprovider")
|
||||
.requestOptions(null)
|
||||
.build()).isInstanceOf(IllegalArgumentException.class)
|
||||
.hasMessageContaining("requestOptions cannot be null");
|
||||
@@ -59,11 +56,4 @@ class EmbeddingModelObservationContextTests {
|
||||
return new EmbeddingRequest(List.of(), EmbeddingOptionsBuilder.builder().build());
|
||||
}
|
||||
|
||||
private AiOperationMetadata generateOperationMetadata() {
|
||||
return AiOperationMetadata.builder()
|
||||
.operationType(AiOperationType.EMBEDDING.value())
|
||||
.provider(AiProvider.OLLAMA.value())
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -20,10 +20,7 @@ import io.micrometer.observation.Observation;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.ai.image.ImageOptionsBuilder;
|
||||
import org.springframework.ai.image.ImagePrompt;
|
||||
import org.springframework.ai.observation.AiOperationMetadata;
|
||||
import org.springframework.ai.observation.conventions.AiObservationAttributes;
|
||||
import org.springframework.ai.observation.conventions.AiOperationType;
|
||||
import org.springframework.ai.observation.conventions.AiProvider;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
@@ -45,7 +42,7 @@ class DefaultImageModelObservationConventionTests {
|
||||
void contextualNameWhenModelIsDefined() {
|
||||
ImageModelObservationContext observationContext = ImageModelObservationContext.builder()
|
||||
.imagePrompt(generateImagePrompt())
|
||||
.operationMetadata(generateOperationMetadata())
|
||||
.provider("superprovider")
|
||||
.requestOptions(ImageOptionsBuilder.builder().withModel("mistral").build())
|
||||
.build();
|
||||
assertThat(this.observationConvention.getContextualName(observationContext)).isEqualTo("image mistral");
|
||||
@@ -55,7 +52,7 @@ class DefaultImageModelObservationConventionTests {
|
||||
void contextualNameWhenModelIsNotDefined() {
|
||||
ImageModelObservationContext observationContext = ImageModelObservationContext.builder()
|
||||
.imagePrompt(generateImagePrompt())
|
||||
.operationMetadata(generateOperationMetadata())
|
||||
.provider("superprovider")
|
||||
.requestOptions(ImageOptionsBuilder.builder().build())
|
||||
.build();
|
||||
assertThat(this.observationConvention.getContextualName(observationContext)).isEqualTo("image");
|
||||
@@ -65,7 +62,7 @@ class DefaultImageModelObservationConventionTests {
|
||||
void supportsOnlyImageModelObservationContext() {
|
||||
ImageModelObservationContext observationContext = ImageModelObservationContext.builder()
|
||||
.imagePrompt(generateImagePrompt())
|
||||
.operationMetadata(generateOperationMetadata())
|
||||
.provider("superprovider")
|
||||
.requestOptions(ImageOptionsBuilder.builder().withModel("mistral").build())
|
||||
.build();
|
||||
assertThat(this.observationConvention.supportsContext(observationContext)).isTrue();
|
||||
@@ -76,12 +73,12 @@ class DefaultImageModelObservationConventionTests {
|
||||
void shouldHaveLowCardinalityKeyValuesWhenDefined() {
|
||||
ImageModelObservationContext observationContext = ImageModelObservationContext.builder()
|
||||
.imagePrompt(generateImagePrompt())
|
||||
.operationMetadata(generateOperationMetadata())
|
||||
.provider("superprovider")
|
||||
.requestOptions(ImageOptionsBuilder.builder().withModel("mistral").build())
|
||||
.build();
|
||||
assertThat(this.observationConvention.getLowCardinalityKeyValues(observationContext)).contains(
|
||||
KeyValue.of(AiObservationAttributes.AI_OPERATION_TYPE.value(), "image"),
|
||||
KeyValue.of(AiObservationAttributes.AI_PROVIDER.value(), "ollama"),
|
||||
KeyValue.of(AiObservationAttributes.AI_PROVIDER.value(), "superprovider"),
|
||||
KeyValue.of(AiObservationAttributes.REQUEST_MODEL.value(), "mistral"));
|
||||
}
|
||||
|
||||
@@ -89,7 +86,7 @@ class DefaultImageModelObservationConventionTests {
|
||||
void shouldHaveHighCardinalityKeyValuesWhenDefined() {
|
||||
ImageModelObservationContext observationContext = ImageModelObservationContext.builder()
|
||||
.imagePrompt(generateImagePrompt())
|
||||
.operationMetadata(generateOperationMetadata())
|
||||
.provider("superprovider")
|
||||
.requestOptions(ImageOptionsBuilder.builder()
|
||||
.withModel("mistral")
|
||||
.withN(1)
|
||||
@@ -110,7 +107,7 @@ class DefaultImageModelObservationConventionTests {
|
||||
void shouldHaveNoneKeyValuesWhenMissing() {
|
||||
ImageModelObservationContext observationContext = ImageModelObservationContext.builder()
|
||||
.imagePrompt(generateImagePrompt())
|
||||
.operationMetadata(generateOperationMetadata())
|
||||
.provider("superprovider")
|
||||
.requestOptions(ImageOptionsBuilder.builder().build())
|
||||
.build();
|
||||
|
||||
@@ -126,11 +123,4 @@ class DefaultImageModelObservationConventionTests {
|
||||
return new ImagePrompt("here comes the sun");
|
||||
}
|
||||
|
||||
private AiOperationMetadata generateOperationMetadata() {
|
||||
return AiOperationMetadata.builder()
|
||||
.operationType(AiOperationType.IMAGE.value())
|
||||
.provider(AiProvider.OLLAMA.value())
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,9 +18,6 @@ package org.springframework.ai.image.observation;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.ai.image.ImageOptionsBuilder;
|
||||
import org.springframework.ai.image.ImagePrompt;
|
||||
import org.springframework.ai.observation.AiOperationMetadata;
|
||||
import org.springframework.ai.observation.conventions.AiOperationType;
|
||||
import org.springframework.ai.observation.conventions.AiProvider;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
@@ -36,7 +33,7 @@ class ImageModelObservationContextTests {
|
||||
void whenMandatoryRequestOptionsThenReturn() {
|
||||
var observationContext = ImageModelObservationContext.builder()
|
||||
.imagePrompt(generateImagePrompt())
|
||||
.operationMetadata(generateOperationMetadata())
|
||||
.provider("superprovider")
|
||||
.requestOptions(ImageOptionsBuilder.builder().withModel("supersun").build())
|
||||
.build();
|
||||
|
||||
@@ -47,7 +44,7 @@ class ImageModelObservationContextTests {
|
||||
void whenRequestOptionsIsNullThenThrow() {
|
||||
assertThatThrownBy(() -> ImageModelObservationContext.builder()
|
||||
.imagePrompt(generateImagePrompt())
|
||||
.operationMetadata(generateOperationMetadata())
|
||||
.provider("superprovider")
|
||||
.requestOptions(null)
|
||||
.build()).isInstanceOf(IllegalArgumentException.class)
|
||||
.hasMessageContaining("requestOptions cannot be null");
|
||||
@@ -57,11 +54,4 @@ class ImageModelObservationContextTests {
|
||||
return new ImagePrompt("here comes the sun");
|
||||
}
|
||||
|
||||
private AiOperationMetadata generateOperationMetadata() {
|
||||
return AiOperationMetadata.builder()
|
||||
.operationType(AiOperationType.IMAGE.value())
|
||||
.provider(AiProvider.OLLAMA.value())
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -21,10 +21,7 @@ import org.junit.jupiter.api.Test;
|
||||
import org.springframework.ai.image.ImageMessage;
|
||||
import org.springframework.ai.image.ImageOptionsBuilder;
|
||||
import org.springframework.ai.image.ImagePrompt;
|
||||
import org.springframework.ai.observation.AiOperationMetadata;
|
||||
import org.springframework.ai.observation.conventions.AiObservationAttributes;
|
||||
import org.springframework.ai.observation.conventions.AiOperationType;
|
||||
import org.springframework.ai.observation.conventions.AiProvider;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -51,7 +48,7 @@ class ImageModelPromptContentObservationFilterTests {
|
||||
void whenEmptyPromptThenReturnOriginalContext() {
|
||||
var expectedContext = ImageModelObservationContext.builder()
|
||||
.imagePrompt(new ImagePrompt(""))
|
||||
.operationMetadata(generateOperationMetadata())
|
||||
.provider("superprovider")
|
||||
.requestOptions(ImageOptionsBuilder.builder().withModel("mistral").build())
|
||||
.build();
|
||||
var actualContext = observationFilter.map(expectedContext);
|
||||
@@ -63,7 +60,7 @@ class ImageModelPromptContentObservationFilterTests {
|
||||
void whenPromptWithTextThenAugmentContext() {
|
||||
var originalContext = ImageModelObservationContext.builder()
|
||||
.imagePrompt(new ImagePrompt("supercalifragilisticexpialidocious"))
|
||||
.operationMetadata(generateOperationMetadata())
|
||||
.provider("superprovider")
|
||||
.requestOptions(ImageOptionsBuilder.builder().withModel("mistral").build())
|
||||
.build();
|
||||
var augmentedContext = observationFilter.map(originalContext);
|
||||
@@ -77,7 +74,7 @@ class ImageModelPromptContentObservationFilterTests {
|
||||
var originalContext = ImageModelObservationContext.builder()
|
||||
.imagePrompt(new ImagePrompt(List.of(new ImageMessage("you're a chimney sweep"),
|
||||
new ImageMessage("supercalifragilisticexpialidocious"))))
|
||||
.operationMetadata(generateOperationMetadata())
|
||||
.provider("superprovider")
|
||||
.requestOptions(ImageOptionsBuilder.builder().withModel("mistral").build())
|
||||
.build();
|
||||
var augmentedContext = observationFilter.map(originalContext);
|
||||
@@ -87,11 +84,4 @@ class ImageModelPromptContentObservationFilterTests {
|
||||
"[\"you're a chimney sweep\", \"supercalifragilisticexpialidocious\"]"));
|
||||
}
|
||||
|
||||
private AiOperationMetadata generateOperationMetadata() {
|
||||
return AiOperationMetadata.builder()
|
||||
.operationType(AiOperationType.IMAGE.value())
|
||||
.provider(AiProvider.OLLAMA.value())
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -97,7 +97,7 @@ The prefix `spring.ai.mistralai.chat` is the property prefix that lets you confi
|
||||
| spring.ai.mistralai.chat.options.maxTokens | The maximum number of tokens to generate in the chat completion. The total length of input tokens and generated tokens is limited by the model's context length. | -
|
||||
| spring.ai.mistralai.chat.options.safePrompt | Indicates whether to inject a security prompt before all conversations. | false
|
||||
| spring.ai.mistralai.chat.options.randomSeed | This feature is in Beta. If specified, our system will make a best effort to sample deterministically, such that repeated requests with the same seed and parameters should return the same result. | -
|
||||
| spring.ai.mistralai.chat.options.stop | Up to 4 sequences where the API will stop generating further tokens. | -
|
||||
| spring.ai.mistralai.chat.options.stop | Stop generation if this token is detected. Or if one of these tokens is detected when providing an array. | -
|
||||
| spring.ai.mistralai.chat.options.topP | An alternative to sampling with temperature, called nucleus sampling, where the model considers the results of the tokens with top_p probability mass. So 0.1 means only the tokens comprising the top 10% probability mass are considered. We generally recommend altering this or temperature but not both. | -
|
||||
| spring.ai.mistralai.chat.options.responseFormat | An object specifying the format that the model must output. Setting to `{ "type": "json_object" }` enables JSON mode, which guarantees the message the model generates is valid JSON.| -
|
||||
| spring.ai.mistralai.chat.options.tools | A list of tools the model may call. Currently, only functions are supported as a tool. Use this to provide a list of functions the model may generate JSON inputs for. | -
|
||||
|
||||
@@ -15,6 +15,13 @@ The following are the vector stores that currently don't support the `initialize
|
||||
2. Pinecone
|
||||
3. Weaviate
|
||||
|
||||
* In Bedrock Jurassic 2, the chat options `countPenalty`, `frequencyPenalty`, and `presencePenalty`
|
||||
have been renamed to `countPenaltyOptions`, `frequencyPenaltyOptions`, and `presencePenaltyOptions`.
|
||||
Furthermore, the type of the chat option `stopSequences` have been changed from `String[]` to `List<String>`.
|
||||
|
||||
* In Azure OpenAI, the type of the chat options `frequencyPenalty` and `presencePenalty`
|
||||
has been changed from `Double` to `Float`, consistently with all the other implementations.
|
||||
|
||||
== Upgrading to 1.0.0.M1
|
||||
|
||||
On our march to release 1.0.0 M1 we have made several breaking changes. Apologies, it is for the best!
|
||||
|
||||
@@ -205,13 +205,7 @@ public class ZhiPuAiPropertiesTests {
|
||||
"spring.ai.zhipuai.base-url=TEST_BASE_URL",
|
||||
|
||||
"spring.ai.zhipuai.chat.options.model=MODEL_XYZ",
|
||||
"spring.ai.zhipuai.chat.options.frequencyPenalty=-1.5",
|
||||
"spring.ai.zhipuai.chat.options.logitBias.myTokenId=-5",
|
||||
"spring.ai.zhipuai.chat.options.maxTokens=123",
|
||||
"spring.ai.zhipuai.chat.options.n=10",
|
||||
"spring.ai.zhipuai.chat.options.presencePenalty=0",
|
||||
"spring.ai.zhipuai.chat.options.responseFormat.type=json",
|
||||
"spring.ai.zhipuai.chat.options.seed=66",
|
||||
"spring.ai.zhipuai.chat.options.stop=boza,koza",
|
||||
"spring.ai.zhipuai.chat.options.temperature=0.55",
|
||||
"spring.ai.zhipuai.chat.options.topP=0.56",
|
||||
|
||||
Reference in New Issue
Block a user