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());
+ }
+}