feat: adapt spring-ai images api (#3678)
Signed-off-by: yuluo-yx <yuluo08290126@gmail.com>pull/3686/head
parent
7ac3db5ff8
commit
cb3d302f24
@ -0,0 +1,61 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2023-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 com.alibaba.cloud.ai.example.tongyi.service.impl.images;
|
||||||
|
|
||||||
|
import com.alibaba.cloud.ai.example.tongyi.service.AbstractTongYiServiceImpl;
|
||||||
|
import com.alibaba.cloud.ai.example.tongyi.service.TongYiService;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import org.springframework.ai.image.ImageClient;
|
||||||
|
import org.springframework.ai.image.ImagePrompt;
|
||||||
|
import org.springframework.ai.image.ImageResponse;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gen images example.
|
||||||
|
*
|
||||||
|
* @author yuluo
|
||||||
|
* @author <a href="mailto:yuluo08290126@gmail.com">yuluo</a>
|
||||||
|
* @since 2023.0.0.0-RC1
|
||||||
|
*/
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
public class TongYiImagesServiceImpl extends AbstractTongYiServiceImpl {
|
||||||
|
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(TongYiService.class);
|
||||||
|
|
||||||
|
private final ImageClient imageClient;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public TongYiImagesServiceImpl(ImageClient client) {
|
||||||
|
|
||||||
|
this.imageClient = client;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ImageResponse genImg(String imgPrompt) {
|
||||||
|
|
||||||
|
var prompt = new ImagePrompt(imgPrompt);
|
||||||
|
|
||||||
|
return imageClient.call(prompt);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,3 +1,3 @@
|
|||||||
[Spring AI](https://docs.spring.io/spring-ai/reference/0.8-SNAPSHOT/index.html) <br>
|
[Spring AI](https://docs.spring.io/spring-ai/reference/0.8-SNAPSHOT/index.html) <br><br>
|
||||||
[通义大模型](https://help.aliyun.com/zh/dashscope/developer-reference/model-introduction) <br>
|
[通义大模型](https://help.aliyun.com/zh/dashscope/developer-reference/model-introduction) <br><br>
|
||||||
[Spring AI chat completion api](https://docs.spring.io/spring-ai/reference/0.8-SNAPSHOT/api/chatclient.html)
|
[Spring AI chat completion api](https://docs.spring.io/spring-ai/reference/0.8-SNAPSHOT/api/chatclient.html)
|
||||||
|
@ -0,0 +1,49 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2023-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 com.alibaba.cloud.ai.tongyi;
|
||||||
|
|
||||||
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TongYi connection API properties.
|
||||||
|
*
|
||||||
|
* @author yuluo
|
||||||
|
* @author <a href="mailto:yuluo08290126@gmail.com">yuluo</a>
|
||||||
|
* @since 2023.0.0.0-RC1
|
||||||
|
*/
|
||||||
|
|
||||||
|
@ConfigurationProperties(TongYiConnectionProperties.CONFIG_PREFIX)
|
||||||
|
public class TongYiConnectionProperties {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Spring Cloud Alibaba AI configuration prefix.
|
||||||
|
*/
|
||||||
|
public static final String CONFIG_PREFIX = "spring.cloud.ai.tongyi";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ApiKey.
|
||||||
|
*/
|
||||||
|
private String apiKey;
|
||||||
|
|
||||||
|
public String getApiKey() {
|
||||||
|
return apiKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setApiKey(String apiKey) {
|
||||||
|
this.apiKey = apiKey;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,233 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2023-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 com.alibaba.cloud.ai.tongyi;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.util.Base64;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import com.alibaba.cloud.ai.tongyi.exception.TongYiImagesException;
|
||||||
|
import com.alibaba.dashscope.aigc.imagesynthesis.ImageSynthesis;
|
||||||
|
import com.alibaba.dashscope.aigc.imagesynthesis.ImageSynthesisParam;
|
||||||
|
import com.alibaba.dashscope.aigc.imagesynthesis.ImageSynthesisResult;
|
||||||
|
import com.alibaba.dashscope.exception.NoApiKeyException;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import org.springframework.ai.image.Image;
|
||||||
|
import org.springframework.ai.image.ImageClient;
|
||||||
|
import org.springframework.ai.image.ImageGeneration;
|
||||||
|
import org.springframework.ai.image.ImageOptions;
|
||||||
|
import org.springframework.ai.image.ImagePrompt;
|
||||||
|
import org.springframework.ai.image.ImageResponse;
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
|
import static com.alibaba.cloud.ai.tongyi.metadata.TongYiImagesResponseMetadata.from;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TongYiImagesClient is a class that implements the ImageClient interface. It provides a
|
||||||
|
* client for calling the TongYi AI image generation API.
|
||||||
|
*
|
||||||
|
* @author yuluo
|
||||||
|
* @author <a href="mailto:yuluo08290126@gmail.com">yuluo</a>
|
||||||
|
* @since 2023.0.0.0-RC1
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class TongYiImagesClient implements ImageClient {
|
||||||
|
|
||||||
|
private final Logger logger = LoggerFactory.getLogger(TongYiImagesClient.class);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gen Images API.
|
||||||
|
*/
|
||||||
|
private final ImageSynthesis imageSynthesis;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TongYi Gen images properties.
|
||||||
|
*/
|
||||||
|
private TongYiImagesOptions defaultOptions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adapt TongYi images api size properties.
|
||||||
|
*/
|
||||||
|
private final String sizeConnection = "*";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get default images options.
|
||||||
|
*
|
||||||
|
* @return Default TongYiImagesOptions.
|
||||||
|
*/
|
||||||
|
public TongYiImagesOptions getDefaultOptions() {
|
||||||
|
|
||||||
|
return this.defaultOptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TongYiImagesClient(ImageSynthesis imageSynthesis) {
|
||||||
|
|
||||||
|
this(imageSynthesis, TongYiImagesOptions.
|
||||||
|
builder()
|
||||||
|
.withModel(ImageSynthesis.Models.WANX_V1)
|
||||||
|
.withN(1)
|
||||||
|
.build()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TongYiImagesClient(ImageSynthesis imageSynthesis, TongYiImagesOptions imagesOptions) {
|
||||||
|
|
||||||
|
Assert.notNull(imageSynthesis, "ImageSynthesis must not be null");
|
||||||
|
Assert.notNull(imagesOptions, "TongYiImagesOptions must not be null");
|
||||||
|
|
||||||
|
this.imageSynthesis = imageSynthesis;
|
||||||
|
this.defaultOptions = imagesOptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ImageResponse call(ImagePrompt imagePrompt) {
|
||||||
|
|
||||||
|
ImageSynthesisResult result;
|
||||||
|
String prompt = imagePrompt.getInstructions().get(0).getText();
|
||||||
|
var imgParams = ImageSynthesisParam.builder()
|
||||||
|
.prompt("")
|
||||||
|
.model(ImageSynthesis.Models.WANX_V1)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
if (this.defaultOptions != null) {
|
||||||
|
imgParams = merge(
|
||||||
|
this.defaultOptions,
|
||||||
|
imgParams
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (imagePrompt.getOptions() != null) {
|
||||||
|
imgParams = merge(
|
||||||
|
toTingYiImageOptions(imagePrompt.getOptions()),
|
||||||
|
imgParams
|
||||||
|
);
|
||||||
|
}
|
||||||
|
imgParams.setPrompt(prompt);
|
||||||
|
|
||||||
|
try {
|
||||||
|
result = imageSynthesis.call(imgParams);
|
||||||
|
}
|
||||||
|
catch (NoApiKeyException e) {
|
||||||
|
logger.error("TongYi models gen images failed: {}.", e.getMessage());
|
||||||
|
throw new TongYiImagesException(e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
return convert(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ImageSynthesisParam merge(TongYiImagesOptions source, ImageSynthesisParam target) {
|
||||||
|
|
||||||
|
var builder = ImageSynthesisParam.builder();
|
||||||
|
|
||||||
|
if (source != null) {
|
||||||
|
if (
|
||||||
|
source.getHeight() != null
|
||||||
|
&&
|
||||||
|
source.getWidth() != null
|
||||||
|
) {
|
||||||
|
builder.size(source.getHeight() + sizeConnection + source.getWidth());
|
||||||
|
}
|
||||||
|
if (source.getModel() != null) {
|
||||||
|
builder.model(source.getModel());
|
||||||
|
}
|
||||||
|
if (source.getN() != null) {
|
||||||
|
builder.n(source.getN());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// prompt is marked non-null but is null.
|
||||||
|
builder.prompt("");
|
||||||
|
|
||||||
|
return builder.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private ImageResponse convert(ImageSynthesisResult result) {
|
||||||
|
|
||||||
|
return new ImageResponse(
|
||||||
|
result.getOutput().getResults().stream()
|
||||||
|
.flatMap(value -> value.entrySet().stream())
|
||||||
|
.map(entry -> {
|
||||||
|
String key = entry.getKey();
|
||||||
|
String value = entry.getValue();
|
||||||
|
try {
|
||||||
|
String base64Image = convertImageToBase64(value);
|
||||||
|
Image image = new Image(value, base64Image);
|
||||||
|
return new ImageGeneration(image);
|
||||||
|
}
|
||||||
|
catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect(Collectors.toList()),
|
||||||
|
from(result)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private TongYiImagesOptions toTingYiImageOptions(ImageOptions runtimeImageOptions) {
|
||||||
|
|
||||||
|
var builder = TongYiImagesOptions.builder();
|
||||||
|
|
||||||
|
if (runtimeImageOptions != null) {
|
||||||
|
if (runtimeImageOptions.getN() != null) {
|
||||||
|
|
||||||
|
builder.withN(runtimeImageOptions.getN());
|
||||||
|
}
|
||||||
|
if (runtimeImageOptions.getModel() != null) {
|
||||||
|
|
||||||
|
builder.withModel(runtimeImageOptions.getModel());
|
||||||
|
}
|
||||||
|
if (runtimeImageOptions.getHeight() != null) {
|
||||||
|
|
||||||
|
builder.withHeight(runtimeImageOptions.getHeight());
|
||||||
|
}
|
||||||
|
if (runtimeImageOptions.getWidth() != null) {
|
||||||
|
|
||||||
|
builder.withWidth(runtimeImageOptions.getWidth());
|
||||||
|
}
|
||||||
|
|
||||||
|
// todo ImagesParams.
|
||||||
|
}
|
||||||
|
|
||||||
|
return builder.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String convertImageToBase64(String imageUrl) throws Exception {
|
||||||
|
|
||||||
|
var url = new URL(imageUrl);
|
||||||
|
var inputStream = url.openStream();
|
||||||
|
var outputStream = new ByteArrayOutputStream();
|
||||||
|
var buffer = new byte[4096];
|
||||||
|
int bytesRead;
|
||||||
|
|
||||||
|
while ((bytesRead = inputStream.read(buffer)) != -1) {
|
||||||
|
outputStream.write(buffer, 0, bytesRead);
|
||||||
|
}
|
||||||
|
|
||||||
|
var imageBytes = outputStream.toByteArray();
|
||||||
|
|
||||||
|
String base64Image = Base64.getEncoder().encodeToString(imageBytes);
|
||||||
|
|
||||||
|
inputStream.close();
|
||||||
|
outputStream.close();
|
||||||
|
|
||||||
|
return base64Image;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,188 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2023-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 com.alibaba.cloud.ai.tongyi;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
import com.alibaba.cloud.ai.tongyi.exception.TongYiImagesException;
|
||||||
|
import com.alibaba.dashscope.aigc.imagesynthesis.ImageSynthesis;
|
||||||
|
|
||||||
|
import org.springframework.ai.image.ImageOptions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TongYi Image API options.
|
||||||
|
*
|
||||||
|
* @author yuluo
|
||||||
|
* @author <a href="mailto:yuluo08290126@gmail.com">yuluo</a>
|
||||||
|
* @since 2023.0.0.0-RC1
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class TongYiImagesOptions implements ImageOptions {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specify the model name, currently only wanx-v1 is supported.
|
||||||
|
*/
|
||||||
|
private String model = ImageSynthesis.Models.WANX_V1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gen images number.
|
||||||
|
*/
|
||||||
|
private Integer n;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The width of the generated images.
|
||||||
|
*/
|
||||||
|
private Integer width = 1024;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The height of the generated images.
|
||||||
|
*/
|
||||||
|
private Integer height = 1024;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Integer getN() {
|
||||||
|
|
||||||
|
return this.n;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getModel() {
|
||||||
|
|
||||||
|
return this.model;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Integer getWidth() {
|
||||||
|
|
||||||
|
return this.width;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Integer getHeight() {
|
||||||
|
|
||||||
|
return this.height;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getResponseFormat() {
|
||||||
|
|
||||||
|
throw new TongYiImagesException("unimplemented!");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setModel(String model) {
|
||||||
|
|
||||||
|
this.model = model;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setN(Integer n) {
|
||||||
|
|
||||||
|
this.n = n;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setWidth(Integer width) {
|
||||||
|
|
||||||
|
this.width = width;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHeight(Integer height) {
|
||||||
|
|
||||||
|
this.height = height;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) {
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (o == null || getClass() != o.getClass()) {
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
TongYiImagesOptions that = (TongYiImagesOptions) o;
|
||||||
|
|
||||||
|
return Objects.equals(model, that.model)
|
||||||
|
&& Objects.equals(n, that.n)
|
||||||
|
&& Objects.equals(width, that.width)
|
||||||
|
&& Objects.equals(height, that.height);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
|
||||||
|
return Objects.hash(model, n, width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
|
||||||
|
final StringBuilder sb = new StringBuilder("TongYiImagesOptions{");
|
||||||
|
|
||||||
|
sb.append("model='").append(model).append('\'');
|
||||||
|
sb.append(", n=").append(n);
|
||||||
|
sb.append(", width=").append(width);
|
||||||
|
sb.append(", height=").append(height);
|
||||||
|
sb.append('}');
|
||||||
|
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Builder builder() {
|
||||||
|
return new Builder();
|
||||||
|
}
|
||||||
|
|
||||||
|
public final static class Builder {
|
||||||
|
|
||||||
|
private final TongYiImagesOptions options;
|
||||||
|
|
||||||
|
private Builder() {
|
||||||
|
this.options = new TongYiImagesOptions();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder withN(Integer n) {
|
||||||
|
|
||||||
|
options.setN(n);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder withModel(String model) {
|
||||||
|
|
||||||
|
options.setModel(model);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder withWidth(Integer width) {
|
||||||
|
|
||||||
|
options.setWidth(width);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder withHeight(Integer height) {
|
||||||
|
|
||||||
|
options.setHeight(height);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TongYiImagesOptions build() {
|
||||||
|
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,80 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2023-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 com.alibaba.cloud.ai.tongyi;
|
||||||
|
|
||||||
|
import com.alibaba.dashscope.aigc.imagesynthesis.ImageSynthesis;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
import org.springframework.boot.context.properties.NestedConfigurationProperty;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TongYi Image API properties.
|
||||||
|
*
|
||||||
|
* @author yuluo
|
||||||
|
* @author <a href="mailto:yuluo08290126@gmail.com">yuluo</a>
|
||||||
|
* @since 2023.0.0.0-RC1
|
||||||
|
*/
|
||||||
|
|
||||||
|
@ConfigurationProperties(TongYiImagesProperties.CONFIG_PREFIX)
|
||||||
|
public class TongYiImagesProperties {
|
||||||
|
|
||||||
|
private final Logger logger = LoggerFactory.getLogger(TongYiImagesProperties.class);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Spring Cloud Alibaba AI configuration prefix.
|
||||||
|
*/
|
||||||
|
public static final String CONFIG_PREFIX = "spring.cloud.ai.tongyi.images";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default TongYi Chat model.
|
||||||
|
*/
|
||||||
|
public static final String DEFAULT_IMAGES_MODEL_NAME = ImageSynthesis.Models.WANX_V1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable TongYiQWEN ai chat client.
|
||||||
|
*/
|
||||||
|
private boolean enabled = true;
|
||||||
|
|
||||||
|
@NestedConfigurationProperty
|
||||||
|
private TongYiImagesOptions options = TongYiImagesOptions.builder()
|
||||||
|
.withModel(DEFAULT_IMAGES_MODEL_NAME)
|
||||||
|
.withN(1)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
public TongYiImagesOptions getOptions() {
|
||||||
|
|
||||||
|
return this.options;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOptions(TongYiImagesOptions options) {
|
||||||
|
|
||||||
|
this.options = options;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isEnabled() {
|
||||||
|
|
||||||
|
return this.enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEnabled(boolean enabled) {
|
||||||
|
|
||||||
|
this.enabled = enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2023-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 com.alibaba.cloud.ai.tongyi.exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TongYi models images exception.
|
||||||
|
*
|
||||||
|
* @author yuluo
|
||||||
|
* @author <a href="mailto:yuluo08290126@gmail.com">yuluo</a>
|
||||||
|
* @since 2023.0.0.0-RC1
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class TongYiImagesException extends TongYiException {
|
||||||
|
|
||||||
|
public TongYiImagesException(String message) {
|
||||||
|
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TongYiImagesException(String message, Throwable cause) {
|
||||||
|
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,130 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2023-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 com.alibaba.cloud.ai.tongyi.metadata;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
import com.alibaba.dashscope.aigc.imagesynthesis.ImageSynthesisResult;
|
||||||
|
import com.alibaba.dashscope.aigc.imagesynthesis.ImageSynthesisTaskMetrics;
|
||||||
|
import com.alibaba.dashscope.aigc.imagesynthesis.ImageSynthesisUsage;
|
||||||
|
|
||||||
|
import org.springframework.ai.image.ImageResponseMetadata;
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author yuluo
|
||||||
|
* @author <a href="mailto:yuluo08290126@gmail.com">yuluo</a>
|
||||||
|
* @since 2023.0.0.0-RC1
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class TongYiImagesResponseMetadata implements ImageResponseMetadata {
|
||||||
|
|
||||||
|
private final Long created;
|
||||||
|
|
||||||
|
private String taskId;
|
||||||
|
|
||||||
|
private ImageSynthesisTaskMetrics metrics;
|
||||||
|
|
||||||
|
private ImageSynthesisUsage usage;
|
||||||
|
|
||||||
|
public static TongYiImagesResponseMetadata from(ImageSynthesisResult synthesisResult) {
|
||||||
|
|
||||||
|
Assert.notNull(synthesisResult, "TongYiAiImageResponse must not be null");
|
||||||
|
|
||||||
|
return new TongYiImagesResponseMetadata(
|
||||||
|
System.currentTimeMillis(),
|
||||||
|
synthesisResult.getOutput().getTaskMetrics(),
|
||||||
|
synthesisResult.getOutput().getTaskId(),
|
||||||
|
synthesisResult.getUsage()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected TongYiImagesResponseMetadata(
|
||||||
|
Long created,
|
||||||
|
ImageSynthesisTaskMetrics metrics,
|
||||||
|
String taskId,
|
||||||
|
ImageSynthesisUsage usage
|
||||||
|
) {
|
||||||
|
|
||||||
|
this.taskId = taskId;
|
||||||
|
this.metrics = metrics;
|
||||||
|
this.created = created;
|
||||||
|
this.usage = usage;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ImageSynthesisUsage getUsage() {
|
||||||
|
return usage;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUsage(ImageSynthesisUsage usage) {
|
||||||
|
this.usage = usage;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getCreated() {
|
||||||
|
return created;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTaskId() {
|
||||||
|
return taskId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTaskId(String taskId) {
|
||||||
|
this.taskId = taskId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ImageSynthesisTaskMetrics getMetrics() {
|
||||||
|
return metrics;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setMetrics(ImageSynthesisTaskMetrics metrics) {
|
||||||
|
this.metrics = metrics;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Long created() {
|
||||||
|
return this.created;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "TongYiImagesResponseMetadata {" + "created=" + created + '}';
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) {
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (o == null || getClass() != o.getClass()) {
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
TongYiImagesResponseMetadata that = (TongYiImagesResponseMetadata) o;
|
||||||
|
|
||||||
|
return Objects.equals(created, that.created)
|
||||||
|
&& Objects.equals(taskId, that.taskId)
|
||||||
|
&& Objects.equals(metrics, that.metrics);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(created, taskId, metrics);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue