diff --git a/pom.xml b/pom.xml index 8a141319..38a9c296 100644 --- a/pom.xml +++ b/pom.xml @@ -40,7 +40,7 @@ DashScope Java SDK com.alibaba dashscope-sdk-java - 2.23.0 + 2.23.1 8 diff --git a/src/main/java/com/alibaba/dashscope/Version.java b/src/main/java/com/alibaba/dashscope/Version.java index 3efdf3d8..9a994a66 100644 --- a/src/main/java/com/alibaba/dashscope/Version.java +++ b/src/main/java/com/alibaba/dashscope/Version.java @@ -3,5 +3,5 @@ package com.alibaba.dashscope; public final class Version { - public static final String version = "2.23.0"; + public static final String version = "2.23.1"; } diff --git a/src/main/java/com/alibaba/dashscope/embeddings/MultiModalEmbeddingParam.java b/src/main/java/com/alibaba/dashscope/embeddings/MultiModalEmbeddingParam.java index 1066ebfe..452e8f0b 100644 --- a/src/main/java/com/alibaba/dashscope/embeddings/MultiModalEmbeddingParam.java +++ b/src/main/java/com/alibaba/dashscope/embeddings/MultiModalEmbeddingParam.java @@ -8,7 +8,9 @@ import com.alibaba.dashscope.utils.JsonUtils; import com.google.gson.JsonObject; import java.nio.ByteBuffer; +import java.util.HashMap; import java.util.List; +import java.util.Map; import lombok.EqualsAndHashCode; import lombok.NonNull; import lombok.experimental.SuperBuilder; @@ -18,17 +20,75 @@ public class MultiModalEmbeddingParam extends HalfDuplexServiceParam { @NonNull private List contents; + /** + * The output vector dimensions. Supported values vary by model. For example, + * multimodal-embedding-v1 outputs 1024-dimension vectors only and ignores this parameter, while + * tongyi-embedding-vision-plus supports multiple dimensions (1152 by default). + */ + private Integer dimension; + + /** The output vector format. Currently only "dense" is supported. */ + private String outputType; + + /** The video frame extraction ratio, in range [0, 1]. Default: 1.0. */ + private Double fps; + + /** Custom task instruction to guide model understanding of query intent. */ + private String instruct; + + /** + * Only applicable to qwen3-vl-embedding. When true, all contents are fused into a single vector. + */ + private Boolean enableFusion; + + /** The resolution level of the input images/videos. */ + private Integer resLevel; + + /** The maximum number of frames extracted from the input video. */ + private Integer maxVideoFrames; + public List getContent() { return contents; } + @Override + public Map getParameters() { + Map params = new HashMap<>(); + if (dimension != null) { + params.put("dimension", dimension); + } + if (outputType != null) { + params.put("output_type", outputType); + } + if (fps != null) { + params.put("fps", fps); + } + if (instruct != null) { + params.put("instruct", instruct); + } + if (enableFusion != null) { + params.put("enable_fusion", enableFusion); + } + if (resLevel != null) { + params.put("res_level", resLevel); + } + if (maxVideoFrames != null) { + params.put("max_video_frames", maxVideoFrames); + } + if (parameters != null && !parameters.isEmpty()) { + params.putAll(parameters); + } + return params; + } + @Override public JsonObject getHttpBody() { JsonObject requestObject = new JsonObject(); requestObject.addProperty(ApiKeywords.MODEL, getModel()); requestObject.add(ApiKeywords.INPUT, getInput()); - if (parameters != null && !parameters.isEmpty()) { - requestObject.add(ApiKeywords.PARAMETERS, JsonUtils.parametersToJsonObject(getParameters())); + Map params = getParameters(); + if (params != null && !params.isEmpty()) { + requestObject.add(ApiKeywords.PARAMETERS, JsonUtils.parametersToJsonObject(params)); } return requestObject; } diff --git a/src/test/java/com/alibaba/dashscope/TestMultiModalEmbeddingParam.java b/src/test/java/com/alibaba/dashscope/TestMultiModalEmbeddingParam.java new file mode 100644 index 00000000..0ffb1533 --- /dev/null +++ b/src/test/java/com/alibaba/dashscope/TestMultiModalEmbeddingParam.java @@ -0,0 +1,74 @@ +package com.alibaba.dashscope; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import com.alibaba.dashscope.embeddings.MultiModalEmbeddingItemImage; +import com.alibaba.dashscope.embeddings.MultiModalEmbeddingItemText; +import com.alibaba.dashscope.embeddings.MultiModalEmbeddingParam; +import com.google.gson.JsonObject; +import java.util.Arrays; +import org.junit.jupiter.api.Test; + +public class TestMultiModalEmbeddingParam { + + private MultiModalEmbeddingParam.MultiModalEmbeddingParamBuilder baseBuilder() { + return MultiModalEmbeddingParam.builder() + .model("tongyi-embedding-vision-plus") + .apiKey("test-key") + .contents( + Arrays.asList( + new MultiModalEmbeddingItemImage("https://example.com/a.jpg"), + new MultiModalEmbeddingItemText("hello"))); + } + + @Test + public void testDimensionSerializedIntoParameters() { + MultiModalEmbeddingParam param = baseBuilder().dimension(1152).build(); + JsonObject body = param.getHttpBody(); + assertTrue(body.has("parameters")); + assertEquals(1152, body.getAsJsonObject("parameters").get("dimension").getAsInt()); + } + + @Test + public void testAllExplicitParamsSerialized() { + MultiModalEmbeddingParam param = + baseBuilder() + .dimension(1024) + .outputType("dense") + .fps(0.5) + .instruct("retrieve images") + .enableFusion(true) + .resLevel(1) + .maxVideoFrames(16) + .build(); + JsonObject params = param.getHttpBody().getAsJsonObject("parameters"); + assertEquals(1024, params.get("dimension").getAsInt()); + assertEquals("dense", params.get("output_type").getAsString()); + assertEquals(0.5, params.get("fps").getAsDouble(), 1e-9); + assertEquals("retrieve images", params.get("instruct").getAsString()); + assertTrue(params.get("enable_fusion").getAsBoolean()); + assertEquals(1, params.get("res_level").getAsInt()); + assertEquals(16, params.get("max_video_frames").getAsInt()); + } + + @Test + public void testGenericParameterStillWorks() { + // 旧用法:通用 parameters 通道 + MultiModalEmbeddingParam param = baseBuilder().parameter("dimension", 768).build(); + JsonObject params = param.getHttpBody().getAsJsonObject("parameters"); + assertEquals(768, params.get("dimension").getAsInt()); + } + + @Test + public void testNoExplicitParamsNoDimensionKey() { + MultiModalEmbeddingParam param = baseBuilder().build(); + JsonObject body = param.getHttpBody(); + if (body.has("parameters")) { + assertFalse(body.getAsJsonObject("parameters").has("dimension")); + } + // contents 始终在 input 中 + assertEquals(2, body.getAsJsonObject("input").getAsJsonArray("contents").size()); + } +}