Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2023-2024 the original author or authors.
* Copyright 2023-2025 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.
Expand Down Expand Up @@ -307,7 +307,10 @@ public void imageOptionsTest() {
"spring.ai.zhipuai.api-key=API_KEY",
"spring.ai.zhipuai.base-url=TEST_BASE_URL",
"spring.ai.zhipuai.image.options.model=MODEL_XYZ",
"spring.ai.zhipuai.image.options.user=userXYZ"
"spring.ai.zhipuai.image.options.size=1024x1024",
"spring.ai.zhipuai.image.options.user=userXYZ",
"spring.ai.zhipuai.image.options.quality=standard",
"spring.ai.zhipuai.image.options.watermark-enabled=true"
)
// @formatter:on
.withConfiguration(SpringAiTestAutoConfigurations.of(ZhiPuAiImageAutoConfiguration.class))
Expand All @@ -319,6 +322,9 @@ public void imageOptionsTest() {
assertThat(connectionProperties.getApiKey()).isEqualTo("API_KEY");
assertThat(imageProperties.getOptions().getModel()).isEqualTo("MODEL_XYZ");
assertThat(imageProperties.getOptions().getUser()).isEqualTo("userXYZ");
assertThat(imageProperties.getOptions().getSize()).isEqualTo("1024x1024");
assertThat(imageProperties.getOptions().getQuality()).isEqualTo("standard");
assertThat(imageProperties.getOptions().getWatermarkEnabled()).isTrue();
});
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2023-2024 the original author or authors.
* Copyright 2023-2025 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.
Expand Down Expand Up @@ -125,10 +125,22 @@ private ZhiPuAiImageOptions toZhiPuAiImageOptions(ImageOptions runtimeImageOptio
if (runtimeImageOptions.getModel() != null) {
zhiPuAiImageOptionsBuilder.model(runtimeImageOptions.getModel());
}
if (runtimeImageOptions.getWidth() != null && runtimeImageOptions.getHeight() != null) {
zhiPuAiImageOptionsBuilder.size(runtimeImageOptions.getWidth() + "x" + runtimeImageOptions.getHeight());
}
if (runtimeImageOptions instanceof ZhiPuAiImageOptions runtimeZhiPuAiImageOptions) {
if (runtimeZhiPuAiImageOptions.getUser() != null) {
zhiPuAiImageOptionsBuilder.user(runtimeZhiPuAiImageOptions.getUser());
}
if (runtimeZhiPuAiImageOptions.getSize() != null) {
zhiPuAiImageOptionsBuilder.size(runtimeZhiPuAiImageOptions.getSize());
}
if (runtimeZhiPuAiImageOptions.getQuality() != null) {
zhiPuAiImageOptionsBuilder.quality(runtimeZhiPuAiImageOptions.getQuality());
}
if (runtimeZhiPuAiImageOptions.getWatermarkEnabled() != null) {
zhiPuAiImageOptionsBuilder.watermarkEnabled(runtimeZhiPuAiImageOptions.getWatermarkEnabled());
}
}
}
return zhiPuAiImageOptionsBuilder.build();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2023-2024 the original author or authors.
* Copyright 2023-2025 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.
Expand Down Expand Up @@ -40,10 +40,14 @@
* <ul>
* <li>model: ZhiPuAiImageApi.DEFAULT_IMAGE_MODEL</li>
* <li>user: null</li>
* <li>size: null</li>
* <li>quality: null</li>
* <li>watermarkEnabled: null</li>
* </ul>
*
* @author Geng Rong
* @author Ilayaperumal Gopinathan
* @author YunKui Lu
* @since 1.0.0 M1
*/
@JsonInclude(JsonInclude.Include.NON_NULL)
Expand All @@ -63,6 +67,26 @@ public class ZhiPuAiImageOptions implements ImageOptions {
@JsonProperty("user_id")
private String user;

/**
* The image size, for example 1024x1024. Both dimensions must be between 512 and
* 2048, divisible by 16, and total pixels must not exceed 2^21.
*/
@JsonProperty("size")
private String size;

/**
* The quality of the generated image. Defaults to standard and only supported by
* cogview-4-250304. Supported values: hd, standard.
*/
@JsonProperty("quality")
private String quality;

/**
* Whether to enable watermarking on generated images.
*/
@JsonProperty("watermark_enabled")
private Boolean watermarkEnabled;

public static Builder builder() {
return new Builder();
}
Expand Down Expand Up @@ -114,6 +138,34 @@ public void setUser(String user) {
this.user = user;
}

public String getSize() {
return this.size;
}

public void setSize(String size) {
this.size = size;
}

public String getQuality() {
return this.quality;
}

public void setQuality(String quality) {
this.quality = quality;
}

public void setQuality(ZhiPuAiImageApi.Quality quality) {
this.quality = (quality != null) ? quality.getValue() : null;
}

public Boolean getWatermarkEnabled() {
return this.watermarkEnabled;
}

public void setWatermarkEnabled(Boolean watermarkEnabled) {
this.watermarkEnabled = watermarkEnabled;
}

@Override
public boolean equals(Object o) {
if (this == o) {
Expand All @@ -122,17 +174,21 @@ public boolean equals(Object o) {
if (!(o instanceof ZhiPuAiImageOptions that)) {
return false;
}
return Objects.equals(this.model, that.model) && Objects.equals(this.user, that.user);
return Objects.equals(this.model, that.model) && Objects.equals(this.user, that.user)
&& Objects.equals(this.size, that.size) && Objects.equals(this.quality, that.quality)
&& Objects.equals(this.watermarkEnabled, that.watermarkEnabled);
}

@Override
public int hashCode() {
return Objects.hash(this.model, this.user);
return Objects.hash(this.model, this.user, this.size, this.quality, this.watermarkEnabled);
}

@Override
public String toString() {
return "ZhiPuAiImageOptions{model='" + this.model + '\'' + ", user='" + this.user + '\'' + '}';
return "ZhiPuAiImageOptions{model='" + this.model + '\'' + ", user='" + this.user + '\'' + ", size='"
+ this.size + '\'' + ", quality='" + this.quality + '\'' + ", watermarkEnabled=" + this.watermarkEnabled
+ '}';
}

public static final class Builder {
Expand All @@ -153,6 +209,26 @@ public Builder user(String user) {
return this;
}

public Builder size(String size) {
this.options.setSize(size);
return this;
}

public Builder quality(String quality) {
this.options.setQuality(quality);
return this;
}

public Builder quality(ZhiPuAiImageApi.Quality quality) {
this.options.setQuality(quality);
return this;
}

public Builder watermarkEnabled(Boolean watermarkEnabled) {
this.options.setWatermarkEnabled(watermarkEnabled);
return this;
}

public ZhiPuAiImageOptions build() {
return this.options;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2023-2024 the original author or authors.
* Copyright 2023-2025 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.
Expand Down Expand Up @@ -92,7 +92,11 @@ public ResponseEntity<ZhiPuAiImageResponse> createImage(ZhiPuAiImageRequest zhiP
*/
public enum ImageModel {

CogView_3("cogview-3");
CogView_3("cogview-3"),

CogView_3_Flash("cogview-3-flash"),

CogView_4("cogview-4"),;

private final String value;

Expand All @@ -106,29 +110,60 @@ public String getValue() {

}

public enum Quality {

HD("hd"),

STANDARD("standard");

private final String value;

Quality(String value) {
this.value = value;
}

public String getValue() {
return this.value;
}

}

// @formatter:off
@JsonInclude(JsonInclude.Include.NON_NULL)
public record ZhiPuAiImageRequest(
@JsonProperty("prompt") String prompt,
@JsonProperty("model") String model,
@JsonProperty("user_id") String user) {
@JsonProperty("user_id") String user,
@JsonProperty("size") String size,
@JsonProperty("quality") String quality,
@JsonProperty("watermark_enabled") Boolean watermarkEnabled) { // @formatter:on

public ZhiPuAiImageRequest(String prompt, String model) {
this(prompt, model, null);
this(prompt, model, null, null, null, null);
}
}

// @formatter:off
@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonIgnoreProperties(ignoreUnknown = true)
public record ZhiPuAiImageResponse(
@JsonProperty("created") Long created,
@JsonProperty("data") List<Data> data) {
@JsonProperty("data") List<Data> data) { // @formatter:on
}
// @formatter:on

// @formatter:off
@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonIgnoreProperties(ignoreUnknown = true)
public record Data(@JsonProperty("url") String url,
@JsonProperty("content_filter") List<ContentFilter> contentFilter) { // @formatter:on

}

// @formatter:off
@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonIgnoreProperties(ignoreUnknown = true)
public record Data(@JsonProperty("url") String url) {
public record ContentFilter(@JsonProperty("role") String role,
@JsonProperty("level") Integer level) { // @formatter:on

}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ public void zhiPuAiEmbeddingNonTransientError() {
@Test
public void zhiPuAiImageTransientError() {

var expectedResponse = new ZhiPuAiImageResponse(678L, List.of(new Data("url678")));
var expectedResponse = new ZhiPuAiImageResponse(678L, List.of(new Data("url678", List.of())));

given(this.zhiPuAiImageApi.createImage(isA(ZhiPuAiImageRequest.class)))
.willThrow(new TransientAiException("Transient Error 1"))
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2023-2024 the original author or authors.
* Copyright 2023-2025 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.
Expand All @@ -21,11 +21,12 @@

import org.springframework.ai.image.Image;
import org.springframework.ai.image.ImageModel;
import org.springframework.ai.image.ImageOptionsBuilder;
import org.springframework.ai.image.ImagePrompt;
import org.springframework.ai.image.ImageResponse;
import org.springframework.ai.image.ImageResponseMetadata;
import org.springframework.ai.zhipuai.ZhiPuAiImageOptions;
import org.springframework.ai.zhipuai.ZhiPuAiTestConfiguration;
import org.springframework.ai.zhipuai.api.ZhiPuAiImageApi;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

Expand All @@ -40,7 +41,12 @@ public class ZhiPuAiImageModelIT {

@Test
void imageAsUrlTest() {
var options = ImageOptionsBuilder.builder().height(1024).width(1024).build();
var options = ZhiPuAiImageOptions.builder()
.quality(ZhiPuAiImageApi.Quality.STANDARD)
.watermarkEnabled(true)
.size("720x1440")
.model(ZhiPuAiImageApi.ImageModel.CogView_3_Flash.getValue())
.build();

var instructions = """
A light cream colored mini golden doodle with a sign that contains the message "I'm on my way to BARCADE!".""";
Expand All @@ -56,6 +62,7 @@ void imageAsUrlTest() {

var generation = imageResponse.getResult();
Image image = generation.getOutput();
System.out.println(image);
assertThat(image.getUrl()).isNotEmpty();
assertThat(image.getB64Json()).isNull();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,9 @@ The prefix `spring.ai.zhipuai.image` is the property prefix that lets you config
| spring.ai.zhipuai.image.api-key | Optional overrides the spring.ai.zhipuai.api-key to provide chat specific api-key | -
| spring.ai.zhipuai.image.options.model | The model to use for image generation. | cogview-3
| spring.ai.zhipuai.image.options.user | A unique identifier representing your end-user, which can help ZhiPuAI to monitor and detect abuse. | -
| spring.ai.zhipuai.image.options.size | The image size, for example 1024x1024. Recommended values: `1024x1024` (default), `768x1344`, `864x1152`, `1344x768`, `1152x864`, `1440x720`, `720x1440`. Custom sizes must be `512-2048px`, divisible by `16`, and total pixels less than `<= 2^21`. | -
| spring.ai.zhipuai.image.options.quality | The quality of the generated image. Supported values: `hd`, `standard` (default `standard`, only supported by `cogview-4-250304`). | -
| spring.ai.zhipuai.image.options.watermark-enabled | Whether to enable watermarking on generated images. Disabling watermarks is only available to users who have signed a disclaimer. | -
|====

==== Connection Properties
Expand Down