fix: fix tongyi ai embedding ci (#3741)

Signed-off-by: yuluo-yx <yuluo08290126@gmail.com>
pull/3739/head^2
YuLuo 9 months ago committed by GitHub
parent 2b393fb664
commit fe7a28e6ec
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -23,11 +23,11 @@ The Spring Cloud Alibaba AI module is based on [Spring AI 0.8.1](https://docs.sp
2. Add the following configuration to the application. Yml configuration file:
Note: It is recommended to set the api-key as an environment variable to avoid api-key leakage.
```shell
export SPRING_CLOUD_AI_TONGYI_API_KEY=sk-a3d73b1709bf4a178c28ed7c8b3b5a45
```
> Note: It is recommended to set the api-key as an environment variable to avoid api-key leakage.
>
> ```shell
> export SPRING_CLOUD_AI_TONGYI_API_KEY=sk-a3d73b1709bf4a178c28ed7c8b3b5a45
> ```
```yml
spring:

@ -23,11 +23,11 @@ Spring Cloud Alibaba AI 模块基于 [Spring AI 0.8.1](https://docs.spring.io/sp
2. 在 application.yml 配置文件中加入以下配置:
Note: 推荐使用环境变量的方式设置 api-key避免 api-key 泄露。
```shell
export SPRING_CLOUD_AI_TONGYI_API_KEY=sk-a3d73b1709bf4a178c28ed7c8b3b5a45
```
> Note: 推荐使用环境变量的方式设置 api-key避免 api-key 泄露。
>
> ```shell
> export SPRING_CLOUD_AI_TONGYI_API_KEY=sk-a3d73b1709bf4a178c28ed7c8b3b5a45
> ```
```yaml
spring:

@ -23,7 +23,6 @@ import com.alibaba.cloud.ai.example.tongyi.models.ActorsFilms;
import com.alibaba.cloud.ai.example.tongyi.models.Completion;
import org.springframework.ai.chat.messages.AssistantMessage;
import org.springframework.ai.embedding.EmbeddingResponse;
import org.springframework.ai.image.ImageResponse;
/**
@ -46,49 +45,57 @@ public abstract class AbstractTongYiServiceImpl implements TongYiService {
@Override
public Map<String, String> streamCompletion(String message) {
throw new RuntimeException(INFO_PREFIX + Thread.currentThread().getStackTrace()[2].getMethodName() + INFO_SUFFIX);
throw new RuntimeException(INFO_PREFIX + Thread.currentThread()
.getStackTrace()[2].getMethodName() + INFO_SUFFIX);
}
@Override
public ActorsFilms genOutputParse(String actor) {
throw new RuntimeException(INFO_PREFIX + Thread.currentThread().getStackTrace()[2].getMethodName() + INFO_SUFFIX);
throw new RuntimeException(INFO_PREFIX + Thread.currentThread()
.getStackTrace()[2].getMethodName() + INFO_SUFFIX);
}
@Override
public AssistantMessage genPromptTemplates(String adjective, String topic) {
throw new RuntimeException(INFO_PREFIX + Thread.currentThread().getStackTrace()[2].getMethodName() + INFO_SUFFIX);
throw new RuntimeException(INFO_PREFIX + Thread.currentThread()
.getStackTrace()[2].getMethodName() + INFO_SUFFIX);
}
@Override
public AssistantMessage genRole(String message, String name, String voice) {
throw new RuntimeException(INFO_PREFIX + Thread.currentThread().getStackTrace()[2].getMethodName() + INFO_SUFFIX);
throw new RuntimeException(INFO_PREFIX + Thread.currentThread()
.getStackTrace()[2].getMethodName() + INFO_SUFFIX);
}
@Override
public Completion stuffCompletion(String message, boolean stuffit) {
throw new RuntimeException(INFO_PREFIX + Thread.currentThread().getStackTrace()[2].getMethodName() + INFO_SUFFIX);
throw new RuntimeException(INFO_PREFIX + Thread.currentThread()
.getStackTrace()[2].getMethodName() + INFO_SUFFIX);
}
@Override
public ImageResponse genImg(String imgPrompt) {
throw new RuntimeException(INFO_PREFIX + Thread.currentThread().getStackTrace()[2].getMethodName() + INFO_SUFFIX);
throw new RuntimeException(INFO_PREFIX + Thread.currentThread()
.getStackTrace()[2].getMethodName() + INFO_SUFFIX);
}
@Override
public String genAudio(String text) {
throw new RuntimeException(INFO_PREFIX + Thread.currentThread().getStackTrace()[2].getMethodName() + INFO_SUFFIX);
throw new RuntimeException(INFO_PREFIX + Thread.currentThread()
.getStackTrace()[2].getMethodName() + INFO_SUFFIX);
}
@Override
public List<Double> textEmbedding(String text) {
throw new RuntimeException(INFO_PREFIX + Thread.currentThread().getStackTrace()[2].getMethodName() + INFO_SUFFIX);
throw new RuntimeException(INFO_PREFIX + Thread.currentThread()
.getStackTrace()[2].getMethodName() + INFO_SUFFIX);
}
}

@ -0,0 +1,22 @@
# Spring Cloud Alibaba AI Text Embedding
`TongYiController` 接受一个 HTTP GET 请求 `http://localhost:8080/ai/audio`
`controller` 将会调用 `TongYiService` 中的 `genAudio` 方法,完成服务请求得到响应。
有一个可选的 `text` 参数其默认值为“Spring Cloud Alibaba AI 框架!”。 请求响应来自 Alibaba TongYi Text Embedding 服务。
## 构建和运行
1. 修改配置文件 `application.yml` 中的 apikey 为有效的 apikey
2. 通过 IDE 或者 `./mvnw spring-boot:run` 运行应用程序。
## 访问接口
使用 curl 工具或者使用浏览器对接口发起请求:
```shell
$ curl http://localhost:8080/ai/textEmbedding
# Response:
为一组向量集合
```

@ -17,7 +17,6 @@
package com.alibaba.cloud.ai.example.tongyi.service.impl.textembedding;
import java.util.List;
import java.util.logging.Logger;
import com.alibaba.cloud.ai.example.tongyi.service.AbstractTongYiServiceImpl;
@ -32,8 +31,6 @@ import org.springframework.stereotype.Service;
@Service
public class TongYiTextEmbeddingServiceImpl extends AbstractTongYiServiceImpl {
private final Logger logger = Logger.getLogger(TongYiTextEmbeddingServiceImpl.class.getName());
private final EmbeddingClient embeddingClient;
public TongYiTextEmbeddingServiceImpl(EmbeddingClient embeddingClient) {
@ -46,4 +43,5 @@ public class TongYiTextEmbeddingServiceImpl extends AbstractTongYiServiceImpl {
return embeddingClient.embed(text);
}
}

@ -62,12 +62,12 @@
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<!-- test dependencies -->
<!-- test dependencies -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>

@ -63,7 +63,7 @@ import org.springframework.context.annotation.Bean;
TongYiChatProperties.class,
TongYiImagesProperties.class,
TongYiAudioSpeechProperties.class,
TongYiConnectionProperties.class
TongYiConnectionProperties.class,
TongYiConnectionProperties.class,
TongYiTextEmbeddingProperties.class
})

@ -24,61 +24,62 @@ import org.springframework.ai.embedding.EmbeddingOptions;
/**
* @author why_ohh
* @author yuluo
* @author <a href="mailto:550588941@qq.com">why_ohh</a>
* @since 2023.0.0.0-RC1
* @since 2023.0.0.0
*/
public final class TongYiEmbeddingOptions implements EmbeddingOptions {
private List<String> texts;
private List<String> texts;
private TextEmbeddingParam.TextType textType;
private TextEmbeddingParam.TextType textType;
public List<String> getTexts() {
return texts;
}
public List<String> getTexts() {
return texts;
}
public void setTexts(List<String> texts) {
this.texts = texts;
}
public void setTexts(List<String> texts) {
this.texts = texts;
}
public TextEmbeddingParam.TextType getTextType() {
return textType;
}
public TextEmbeddingParam.TextType getTextType() {
return textType;
}
public void setTextType(TextEmbeddingParam.TextType textType) {
this.textType = textType;
}
public void setTextType(TextEmbeddingParam.TextType textType) {
this.textType = textType;
}
public static Builder builder() {
return new Builder();
}
public static Builder builder() {
return new Builder();
}
public final static class Builder {
public final static class Builder {
private final TongYiEmbeddingOptions options;
private final TongYiEmbeddingOptions options;
private Builder() {
this.options = new TongYiEmbeddingOptions();
}
private Builder() {
this.options = new TongYiEmbeddingOptions();
}
public Builder withtexts(List<String> texts) {
public Builder withtexts(List<String> texts) {
options.setTexts(texts);
return this;
}
options.setTexts(texts);
return this;
}
public Builder withtextType(TextEmbeddingParam.TextType textType) {
public Builder withtextType(TextEmbeddingParam.TextType textType) {
options.setTextType(textType);
return this;
}
options.setTextType(textType);
return this;
}
public TongYiEmbeddingOptions build() {
public TongYiEmbeddingOptions build() {
return options;
}
return options;
}
}
}
}

@ -39,141 +39,138 @@ import org.springframework.ai.embedding.EmbeddingResponse;
import org.springframework.util.Assert;
/**
// * {@link TongYiTextEmbeddingClient} implementation for {@literal Alibaba DashScope}
* backed by {@link Generation}.
*
* {@link TongYiTextEmbeddingClient} implementation for {@literal Alibaba DashScope}.
* @author why_ohh
* @author yuluo
* @author <a href="mailto:550588941@qq.com">why_ohh</a>
* @since 2023.0.0.0-RC1
* @see TextEmbeddingClient
* @see com.alibaba.dashscope.aigc.generation
* @since 2023.0.0.0
* {@see TextEmbeddingClient}
*/
public class TongYiTextEmbeddingClient extends AbstractEmbeddingClient {
private final Logger logger = LoggerFactory.getLogger(TongYiTextEmbeddingClient.class);
/**
* TongYi Text Embedding client.
*/
private final TextEmbedding textEmbedding;
/**
* {@link MetadataMode}
*/
private final MetadataMode metadataMode;
private final TongYiEmbeddingOptions defaultOptions;
public TongYiTextEmbeddingClient(TextEmbedding textEmbedding) {
this(textEmbedding, MetadataMode.EMBED);
}
public TongYiTextEmbeddingClient(TextEmbedding textEmbedding, MetadataMode metadataMode) {
this(textEmbedding, metadataMode,
TongYiEmbeddingOptions.builder()
.withtextType(TextEmbeddingParam.TextType.DOCUMENT)
.build()
);
}
public TongYiTextEmbeddingClient(
TextEmbedding textEmbedding,
MetadataMode metadataMode,
TongYiEmbeddingOptions options
){
Assert.notNull(textEmbedding, "textEmbedding must not be null");
Assert.notNull(metadataMode, "Metadata mode must not be null");
Assert.notNull(options, "TongYiEmbeddingOptions must not be null");
this.metadataMode = metadataMode;
this.textEmbedding = textEmbedding;
this.defaultOptions = options;
}
public TongYiEmbeddingOptions getDefaultOptions(){
return this.defaultOptions;
}
@Override
public List<Double> embed(Document document) {
return this.call(
new EmbeddingRequest(
List.of(document.getFormattedContent(this.metadataMode)),
null)
).getResults().stream()
.map(Embedding::getOutput)
.flatMap(List::stream)
.toList();
}
@Override
public EmbeddingResponse call(EmbeddingRequest request) {
TextEmbeddingParam embeddingParams = toEmbeddingParams(request);
logger.debug("Embedding request: {}", embeddingParams);
TextEmbeddingResult resp;
try {
resp = textEmbedding.call(embeddingParams);
}
catch (NoApiKeyException e) {
throw new TongYiException(e.getMessage());
}
return genEmbeddingResp(resp);
}
private EmbeddingResponse genEmbeddingResp(TextEmbeddingResult result) {
return new EmbeddingResponse(
genEmbeddingList(result.getOutput().getEmbeddings()),
TongYiTextEmbeddingResponseMetadata.from(result.getUsage())
);
}
private List<Embedding> genEmbeddingList(List<TextEmbeddingResultItem> embeddings) {
return embeddings.stream()
.map(embedding ->
new Embedding(
embedding.getEmbedding(),
embedding.getTextIndex()
))
.collect(Collectors.toList());
}
/**
* We recommend setting the model parameters by passing the embedding parameters through the code;
* yml configuration compatibility is not considered here.
* It is not recommended that users set parameters from yml,
* as this reduces the flexibility of the configuration.
* Because the model name keeps changing, strings are used here and constants are undefined:
* Model list: <a href="https://help.aliyun.com/zh/dashscope/developer-reference/text-embedding-quick-start">Text Embedding Model List</a>
* @param requestOptions Client params. {@link EmbeddingRequest}
* @return {@link TextEmbeddingParam}
*/
private TextEmbeddingParam toEmbeddingParams(EmbeddingRequest requestOptions) {
TextEmbeddingParam tongYiEmbeddingParams = TextEmbeddingParam.builder()
.texts(requestOptions.getInstructions())
.textType(defaultOptions.getTextType() != null ? defaultOptions.getTextType() : TextEmbeddingParam.TextType.DOCUMENT)
.model("text-embedding-v1")
.build();
try {
tongYiEmbeddingParams.validate();
}
catch (InputRequiredException e) {
throw new TongYiException(e.getMessage());
}
return tongYiEmbeddingParams;
}
private final Logger logger = LoggerFactory.getLogger(TongYiTextEmbeddingClient.class);
/**
* TongYi Text Embedding client.
*/
private final TextEmbedding textEmbedding;
/**
* {@link MetadataMode}.
*/
private final MetadataMode metadataMode;
private final TongYiEmbeddingOptions defaultOptions;
public TongYiTextEmbeddingClient(TextEmbedding textEmbedding) {
this(textEmbedding, MetadataMode.EMBED);
}
public TongYiTextEmbeddingClient(TextEmbedding textEmbedding, MetadataMode metadataMode) {
this(textEmbedding, metadataMode,
TongYiEmbeddingOptions.builder()
.withtextType(TextEmbeddingParam.TextType.DOCUMENT)
.build()
);
}
public TongYiTextEmbeddingClient(
TextEmbedding textEmbedding,
MetadataMode metadataMode,
TongYiEmbeddingOptions options
) {
Assert.notNull(textEmbedding, "textEmbedding must not be null");
Assert.notNull(metadataMode, "Metadata mode must not be null");
Assert.notNull(options, "TongYiEmbeddingOptions must not be null");
this.metadataMode = metadataMode;
this.textEmbedding = textEmbedding;
this.defaultOptions = options;
}
public TongYiEmbeddingOptions getDefaultOptions() {
return this.defaultOptions;
}
@Override
public List<Double> embed(Document document) {
return this.call(
new EmbeddingRequest(
List.of(document.getFormattedContent(this.metadataMode)),
null)
).getResults().stream()
.map(Embedding::getOutput)
.flatMap(List::stream)
.toList();
}
@Override
public EmbeddingResponse call(EmbeddingRequest request) {
TextEmbeddingParam embeddingParams = toEmbeddingParams(request);
logger.debug("Embedding request: {}", embeddingParams);
TextEmbeddingResult resp;
try {
resp = textEmbedding.call(embeddingParams);
}
catch (NoApiKeyException e) {
throw new TongYiException(e.getMessage());
}
return genEmbeddingResp(resp);
}
private EmbeddingResponse genEmbeddingResp(TextEmbeddingResult result) {
return new EmbeddingResponse(
genEmbeddingList(result.getOutput().getEmbeddings()),
TongYiTextEmbeddingResponseMetadata.from(result.getUsage())
);
}
private List<Embedding> genEmbeddingList(List<TextEmbeddingResultItem> embeddings) {
return embeddings.stream()
.map(embedding ->
new Embedding(
embedding.getEmbedding(),
embedding.getTextIndex()
))
.collect(Collectors.toList());
}
/**
* We recommend setting the model parameters by passing the embedding parameters through the code;
* yml configuration compatibility is not considered here.
* It is not recommended that users set parameters from yml,
* as this reduces the flexibility of the configuration.
* Because the model name keeps changing, strings are used here and constants are undefined:
* Model list: <a href="https://help.aliyun.com/zh/dashscope/developer-reference/text-embedding-quick-start">Text Embedding Model List</a>
* @param requestOptions Client params. {@link EmbeddingRequest}
* @return {@link TextEmbeddingParam}
*/
private TextEmbeddingParam toEmbeddingParams(EmbeddingRequest requestOptions) {
TextEmbeddingParam tongYiEmbeddingParams = TextEmbeddingParam.builder()
.texts(requestOptions.getInstructions())
.textType(defaultOptions.getTextType() != null ? defaultOptions.getTextType() : TextEmbeddingParam.TextType.DOCUMENT)
.model("text-embedding-v1")
.build();
try {
tongYiEmbeddingParams.validate();
}
catch (InputRequiredException e) {
throw new TongYiException(e.getMessage());
}
return tongYiEmbeddingParams;
}
}

@ -20,25 +20,29 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* @author why_ohh
* @author yuluo
* @author <a href="mailto:550588941@qq.com">why_ohh</a>
* @since 2023.0.0.0-RC1
* @since 2023.0.0.0
*/
@ConfigurationProperties(TongYiTextEmbeddingProperties.CONFIG_PREFIX)
public class TongYiTextEmbeddingProperties {
public static final String CONFIG_PREFIX = "spring.cloud.ai.tongyi.embedding";
/**
* Prefix of TongYi Text Embedding properties.
*/
public static final String CONFIG_PREFIX = "spring.cloud.ai.tongyi.embedding";
private boolean enabled = true;
private boolean enabled = true;
public boolean isEnabled() {
public boolean isEnabled() {
return this.enabled;
}
return this.enabled;
}
public void setEnabled(boolean enabled) {
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
this.enabled = enabled;
}
}

@ -22,6 +22,7 @@ import org.springframework.ai.embedding.EmbeddingResponseMetadata;
/**
* @author why_ohh
* @author yuluo
* @author <a href="mailto:550588941@qq.com">why_ohh</a>
*/
@ -48,4 +49,5 @@ public class TongYiTextEmbeddingResponseMetadata extends EmbeddingResponseMetada
this.totalTokens = totalTokens;
}
}

Loading…
Cancel
Save