Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP Observability]: add image model observation #368

Open
wants to merge 13 commits into
base: main
Choose a base branch
from
2 changes: 1 addition & 1 deletion community/function-calling/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,4 @@
public class BaidusearchProperties {}
```
4. 请在根目录 pom.xml 中添加 module 配置,如 `<module>community/function-calling/spring-ai-alibaba-starter-functioncalling-baidusearch</module>`
5. 请在插件 pom.xml 文件中只保留必须的传递依赖,插件版本应与 Spring AI Alibaba 统一,插件依赖规范为:序列化与反序列化依赖统一使用 `com.fasterxml.jackson.core:jackson`,日志依赖统一使用 `org.slf4j`,HTTP 客户端依赖统一使用 `org.springframework.boot::webClient`,其余依赖尽可能少引用或不引用
5. 请在插件 pom.xml 文件中只保留必须的传递依赖,插件版本应与 Spring AI Alibaba 统一,插件依赖规范为:序列化与反序列化依赖统一使用 `com.fasterxml.jackson.core:jackson`,日志依赖统一使用 `org.slf4j.LoggerFactory:logger`,HTTP 客户端依赖统一使用 `org.springframework.boot:webClient`,其余依赖尽可能少引用或不引用
PolarishT marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import com.alibaba.cloud.ai.dashscope.common.DashScopeApiConstants;
import com.alibaba.cloud.ai.dashscope.embedding.DashScopeEmbeddingModel;
import com.alibaba.cloud.ai.dashscope.image.DashScopeImageModel;
import com.alibaba.cloud.ai.dashscope.image.observation.DashScopeImageModelObservationConvention;
import com.alibaba.cloud.ai.dashscope.rerank.DashScopeRerankModel;
import com.alibaba.dashscope.audio.asr.transcription.Transcription;
import com.alibaba.dashscope.audio.tts.SpeechSynthesizer;
Expand Down Expand Up @@ -84,6 +85,39 @@
WebClientAutoConfiguration.class })
public class DashScopeAutoConfiguration {

private static @NotNull ResolvedConnectionProperties resolveConnectionProperties(
DashScopeParentProperties commonProperties, DashScopeParentProperties modelProperties, String modelType) {

String baseUrl = StringUtils.hasText(modelProperties.getBaseUrl()) ? modelProperties.getBaseUrl()
: commonProperties.getBaseUrl();
String apiKey = StringUtils.hasText(modelProperties.getApiKey()) ? modelProperties.getApiKey()
: commonProperties.getApiKey();
String workspaceId = StringUtils.hasText(modelProperties.getWorkspaceId()) ? modelProperties.getWorkspaceId()
: commonProperties.getWorkspaceId();

Map<String, List<String>> connectionHeaders = new HashMap<>();
if (StringUtils.hasText(workspaceId)) {
connectionHeaders.put("DashScope-Workspace", List.of(workspaceId));
}

// get apikey from system env.
if (Objects.isNull(apiKey)) {
if (Objects.nonNull(System.getenv(DashScopeApiConstants.DASHSCOPE_API_KEY))) {
apiKey = System.getenv(DashScopeApiConstants.DASHSCOPE_API_KEY);
}
}

Assert.hasText(baseUrl,
"DashScope base URL must be set. Use the connection property: spring.ai.dashscope.base-url or spring.ai.dashscope."
+ modelType + ".base-url property.");
Assert.hasText(apiKey,
"DashScope API key must be set. Use the connection property: spring.ai.dashscope.api-key or spring.ai.dashscope."
+ modelType + ".api-key property.");

return new ResolvedConnectionProperties(baseUrl, apiKey, workspaceId,
CollectionUtils.toMultiValueMap(connectionHeaders));
}

@Bean
@Scope("prototype")
@ConditionalOnMissingBean
Expand Down Expand Up @@ -218,15 +252,21 @@ public RestClientCustomizer restClientCustomizer(DashScopeConnectionProperties c
matchIfMissing = true)
public DashScopeImageModel dashScopeImageModel(DashScopeConnectionProperties commonProperties,
DashScopeImageProperties imageProperties, RestClient.Builder restClientBuilder,
WebClient.Builder webClientBuilder, RetryTemplate retryTemplate,
ResponseErrorHandler responseErrorHandler) {
WebClient.Builder webClientBuilder, RetryTemplate retryTemplate, ResponseErrorHandler responseErrorHandler,
ObjectProvider<ObservationRegistry> observationRegistry,
ObjectProvider<DashScopeImageModelObservationConvention> observationConvention) {

ResolvedConnectionProperties resolved = resolveConnectionProperties(commonProperties, imageProperties, "image");

var dashScopeImageApi = new DashScopeImageApi(resolved.baseUrl(), resolved.apiKey(), resolved.workspaceId(),
restClientBuilder, webClientBuilder, responseErrorHandler);

return new DashScopeImageModel(dashScopeImageApi, imageProperties.getOptions(), retryTemplate);
var dashScopeImageModel = new DashScopeImageModel(dashScopeImageApi, imageProperties.getOptions(),
retryTemplate, observationRegistry.getIfUnique(() -> ObservationRegistry.NOOP));

observationConvention.ifAvailable(dashScopeImageModel::setObservationConvention);

return dashScopeImageModel;
}

@Bean
Expand Down Expand Up @@ -292,37 +332,4 @@ private record ResolvedConnectionProperties(String baseUrl, String apiKey, Strin
MultiValueMap<String, String> headers) {
}

private static @NotNull ResolvedConnectionProperties resolveConnectionProperties(
DashScopeParentProperties commonProperties, DashScopeParentProperties modelProperties, String modelType) {

String baseUrl = StringUtils.hasText(modelProperties.getBaseUrl()) ? modelProperties.getBaseUrl()
: commonProperties.getBaseUrl();
String apiKey = StringUtils.hasText(modelProperties.getApiKey()) ? modelProperties.getApiKey()
: commonProperties.getApiKey();
String workspaceId = StringUtils.hasText(modelProperties.getWorkspaceId()) ? modelProperties.getWorkspaceId()
: commonProperties.getWorkspaceId();

Map<String, List<String>> connectionHeaders = new HashMap<>();
if (StringUtils.hasText(workspaceId)) {
connectionHeaders.put("DashScope-Workspace", List.of(workspaceId));
}

// get apikey from system env.
if (Objects.isNull(apiKey)) {
if (Objects.nonNull(System.getenv(DashScopeApiConstants.DASHSCOPE_API_KEY))) {
apiKey = System.getenv(DashScopeApiConstants.DASHSCOPE_API_KEY);
}
}

Assert.hasText(baseUrl,
"DashScope base URL must be set. Use the connection property: spring.ai.dashscope.base-url or spring.ai.dashscope."
+ modelType + ".base-url property.");
Assert.hasText(apiKey,
"DashScope API key must be set. Use the connection property: spring.ai.dashscope.api-key or spring.ai.dashscope."
+ modelType + ".api-key property.");

return new ResolvedConnectionProperties(baseUrl, apiKey, workspaceId,
CollectionUtils.toMultiValueMap(connectionHeaders));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,16 @@
*/
package com.alibaba.cloud.ai.dashscope.api;

import java.util.List;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;

import org.springframework.ai.retry.RetryUtils;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.ResponseErrorHandler;
import org.springframework.web.client.RestClient;
import org.springframework.web.reactive.function.client.WebClient;

import java.util.List;

import static com.alibaba.cloud.ai.dashscope.common.DashScopeApiConstants.DEFAULT_BASE_URL;

/**
Expand All @@ -34,6 +33,7 @@
*/
public class DashScopeImageApi {

// public static final String DEFAULT_IMAGE_MODEL = ImageModel.WANX_V1.getValue();
PolarishT marked this conversation as resolved.
Show resolved Hide resolved
public static final String DEFAULT_IMAGE_MODEL = ImageModel.WANX_V1.getValue();

private final RestClient restClient;
Expand Down
Loading
Loading