diff --git a/.dev_tools/run_ci.sh b/.dev_tools/run_ci.sh index 08877d00..a2338057 100644 --- a/.dev_tools/run_ci.sh +++ b/.dev_tools/run_ci.sh @@ -26,7 +26,7 @@ mvn package if [ $? -ne 0 ]; then echo "mvn package failed, please check if any unittest is failed!" - exit -1 + exit 1 fi -echo "CI passed." \ No newline at end of file +echo "CI passed." diff --git a/NOTICE b/NOTICE new file mode 100644 index 00000000..6c4eb808 --- /dev/null +++ b/NOTICE @@ -0,0 +1,39 @@ +DashScope SDK for Java +Copyright 2023-2026 Alibaba Cloud Computing Ltd. + +This product includes software developed at +The Apache Software Foundation (https://www.apache.org/). + +Third-Party Software +-------------------- + +This project uses the following third-party components in test scope only +(not included in the distributed artifact): + +JUnit Jupiter (https://junit.org/junit5/) + License: Eclipse Public License 2.0 (EPL-2.0) + Copyright: JUnit team + +JUnit Pioneer (https://junit-pioneer.org/) + License: Eclipse Public License 2.0 (EPL-2.0) + Copyright: JUnit Pioneer team + +OkHttp (https://square.github.io/okhttp/) + License: Apache License 2.0 + Copyright: Square, Inc. + +Gson (https://github.com/google/gson) + License: Apache License 2.0 + Copyright: Google Inc. + +Jackson (https://github.com/FasterXML/jackson) + License: Apache License 2.0 + Copyright: FasterXML, LLC + +SLF4J (https://www.slf4j.org/) + License: MIT License + Copyright: QOS.ch + +Lombok (https://projectlombok.org/) + License: MIT License + Copyright: Reinier Zwitserloot, Roel Spilker diff --git a/README.md b/README.md index 4dc376a2..bee11a6a 100644 --- a/README.md +++ b/README.md @@ -173,4 +173,3 @@ public class Main { ``` The `call` method accepts a `GenerationParam`, and returns a `GenerationResult`, you can also catch the exception with a try-catch block. - diff --git a/lint.sh b/lint.sh index 68e79f1a..97b28c6e 100755 --- a/lint.sh +++ b/lint.sh @@ -1 +1 @@ -java -jar .dev_tools/google-java-format-1.7-all-deps.jar -i $(find . -type f -name "*.java" | grep "./*/src/.*java") \ No newline at end of file +java -jar .dev_tools/google-java-format-1.7-all-deps.jar -i $(find . -type f -name "*.java" | grep "./*/src/.*java") diff --git a/pom.xml b/pom.xml index 14f0b2a2..ebf308ab 100644 --- a/pom.xml +++ b/pom.xml @@ -40,7 +40,7 @@ DashScope Java SDK com.alibaba dashscope-sdk-java - 2.22.24 + 2.22.25 8 diff --git a/samples/TingWuUsage.java b/samples/TingWuUsage.java index 0aa78862..f7b2059b 100644 --- a/samples/TingWuUsage.java +++ b/samples/TingWuUsage.java @@ -25,9 +25,8 @@ public static Map buildCreateTask(String appId) { public static void main(String[] args) { try { - String baseWebsocketApiUrl = "https://dashscope.aliyuncs.com/api/v1/services/aigc/multimodal-generation/generation"; // 创建任务 - TingWu tingwu = new TingWu(Protocol.HTTP.getValue(),baseWebsocketApiUrl); + TingWu tingwu = new TingWu(); TingWuParam param = TingWuParam.builder(). model("tingwu-automotive-service-inspection") .input(buildCreateTask("123456")) diff --git a/src/main/java/com/alibaba/dashscope/aigc/completion/ChatCompletionParam.java b/src/main/java/com/alibaba/dashscope/aigc/completion/ChatCompletionParam.java index 8204042b..84cafab7 100644 --- a/src/main/java/com/alibaba/dashscope/aigc/completion/ChatCompletionParam.java +++ b/src/main/java/com/alibaba/dashscope/aigc/completion/ChatCompletionParam.java @@ -80,6 +80,45 @@ public class ChatCompletionParam extends FlattenHalfDuplexParamBase { @SerializedName("parallel_tool_calls") private Boolean parallelToolCalls; + /** + * Whether to preserve thinking/reasoning content in the response. When enabled, the model will + * include reasoning process in the output. + */ + @SerializedName("preserve_thinking") + private Boolean preserveThinking; + + /** + * Controls the reasoning effort level for models that support it. Possible values: "low", + * "medium", "high" + */ + @SerializedName("reasoning_effort") + private String reasoningEffort; + + /** + * The maximum number of tokens to generate for completion. This is an alternative to max_tokens + * following OpenAI's newer API convention. + */ + @SerializedName("max_completion_tokens") + private Integer maxCompletionTokens; + + /** + * Whether to stream tool calls as they are generated. When true, tool calls will be sent + * incrementally rather than all at once. + */ + @SerializedName("tool_stream") + private Boolean toolStream; + + /** + * Enable high resolution image processing for vision-language models. Improves image + * understanding quality at the cost of more tokens. + */ + @SerializedName("vl_high_resolution_images") + private Boolean vlHighResolutionImages; + + /** Enable hardware-accelerated image output for vision-language models. */ + @SerializedName("vl_enable_image_hw_output") + private Boolean vlEnableImageHwOutput; + private String user; @Override @@ -142,6 +181,24 @@ public JsonObject getHttpBody() { if (parallelToolCalls != null) { requestObject.addProperty("parallel_tool_calls", parallelToolCalls); } + if (preserveThinking != null) { + requestObject.addProperty("preserve_thinking", preserveThinking); + } + if (reasoningEffort != null) { + requestObject.addProperty("reasoning_effort", reasoningEffort); + } + if (maxCompletionTokens != null) { + requestObject.addProperty("max_completion_tokens", maxCompletionTokens); + } + if (toolStream != null) { + requestObject.addProperty("tool_stream", toolStream); + } + if (vlHighResolutionImages != null) { + requestObject.addProperty("vl_high_resolution_images", vlHighResolutionImages); + } + if (vlEnableImageHwOutput != null) { + requestObject.addProperty("vl_enable_image_hw_output", vlEnableImageHwOutput); + } if (user != null) { requestObject.addProperty("user", user); } diff --git a/src/main/java/com/alibaba/dashscope/aigc/conversation/ConversationParam.java b/src/main/java/com/alibaba/dashscope/aigc/conversation/ConversationParam.java index 3d386844..9da8470e 100644 --- a/src/main/java/com/alibaba/dashscope/aigc/conversation/ConversationParam.java +++ b/src/main/java/com/alibaba/dashscope/aigc/conversation/ConversationParam.java @@ -166,12 +166,25 @@ public Map getParameters() { if (maxTokens != null) { params.put(MAX_TOKENS, maxTokens); } + if (stopStrings != null + && !stopStrings.isEmpty() + && stopTokens != null + && !stopTokens.isEmpty()) { + throw new IllegalArgumentException("Only one of stopStrings or stopTokens can be specified."); + } if (stopStrings != null && !stopStrings.isEmpty()) { params.put(STOP, stopStrings); } else if (stopTokens != null && !stopTokens.isEmpty()) { params.put(STOP, stopTokens); } - params.putAll(parameters); + if (parameters != null) { + parameters.forEach( + (k, v) -> { + if (v != null) { + params.put(k, v); + } + }); + } return params; } diff --git a/src/main/java/com/alibaba/dashscope/aigc/generation/Generation.java b/src/main/java/com/alibaba/dashscope/aigc/generation/Generation.java index d96c6188..6c16cae4 100644 --- a/src/main/java/com/alibaba/dashscope/aigc/generation/Generation.java +++ b/src/main/java/com/alibaba/dashscope/aigc/generation/Generation.java @@ -351,20 +351,20 @@ private GenerationResult mergeSingleResponse( if (currentContent != null && !currentContent.isEmpty()) { accumulated.content.append(currentContent); } - // Always set the accumulated content if we have any - if (accumulated.content.length() > 0) { - choice.getMessage().setContent(accumulated.content.toString()); - } // Handle reasoning_content accumulation String currentReasoningContent = choice.getMessage().getReasoningContent(); if (currentReasoningContent != null && !currentReasoningContent.isEmpty()) { accumulated.reasoningContent.append(currentReasoningContent); } - // Always set the accumulated reasoning_content if we have any + + // Accumulate both reasoning_content and content independently if (accumulated.reasoningContent.length() > 0) { choice.getMessage().setReasoningContent(accumulated.reasoningContent.toString()); } + if (accumulated.content.length() > 0) { + choice.getMessage().setContent(accumulated.content.toString()); + } // Handle tool_calls accumulation List currentToolCalls = choice.getMessage().getToolCalls(); @@ -474,12 +474,13 @@ private GenerationResult mergeSingleResponse( com.alibaba.dashscope.common.Message message = new com.alibaba.dashscope.common.Message(); message.setRole("assistant"); - if (data.content.length() > 0) { - message.setContent(data.content.toString()); - } + // Set both reasoning_content and content independently if (data.reasoningContent.length() > 0) { message.setReasoningContent(data.reasoningContent.toString()); } + if (data.content.length() > 0) { + message.setContent(data.content.toString()); + } if (!data.toolCalls.isEmpty()) { message.setToolCalls(data.toolCalls); } diff --git a/src/main/java/com/alibaba/dashscope/aigc/generation/GenerationParam.java b/src/main/java/com/alibaba/dashscope/aigc/generation/GenerationParam.java index 17269c5a..f19c45cd 100644 --- a/src/main/java/com/alibaba/dashscope/aigc/generation/GenerationParam.java +++ b/src/main/java/com/alibaba/dashscope/aigc/generation/GenerationParam.java @@ -210,6 +210,12 @@ public Map getParameters() { if (maxTokens != null) { params.put(MAX_TOKENS, maxTokens); } + if (stopStrings != null + && !stopStrings.isEmpty() + && stopTokens != null + && !stopTokens.isEmpty()) { + throw new IllegalArgumentException("Only one of stopStrings or stopTokens can be specified."); + } if (stopStrings != null && !stopStrings.isEmpty()) { params.put(STOP, stopStrings); } else if (stopTokens != null && !stopTokens.isEmpty()) { diff --git a/src/main/java/com/alibaba/dashscope/aigc/imagegeneration/ColorPalette.java b/src/main/java/com/alibaba/dashscope/aigc/imagegeneration/ColorPalette.java new file mode 100644 index 00000000..85850c1b --- /dev/null +++ b/src/main/java/com/alibaba/dashscope/aigc/imagegeneration/ColorPalette.java @@ -0,0 +1,20 @@ +package com.alibaba.dashscope.aigc.imagegeneration; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** Color palette configuration for image generation. */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ColorPalette { + + /** Hex color code, e.g., "#FF5733" */ + private String hex; + + /** Ratio of the color in the palette, value range: [0.0, 1.0] */ + private Double ratio; +} diff --git a/src/main/java/com/alibaba/dashscope/aigc/imagegeneration/ImageGenerationParam.java b/src/main/java/com/alibaba/dashscope/aigc/imagegeneration/ImageGenerationParam.java index 683414a3..19522ac7 100644 --- a/src/main/java/com/alibaba/dashscope/aigc/imagegeneration/ImageGenerationParam.java +++ b/src/main/java/com/alibaba/dashscope/aigc/imagegeneration/ImageGenerationParam.java @@ -83,6 +83,15 @@ public class ImageGenerationParam extends HalfDuplexServiceParam { */ @Builder.Default private List>> bboxList = null; + /** + * Thinking mode for image generation. Controls the level of reasoning and planning in the + * generation process. + */ + private String thinkingMode; + + /** Color palette configuration for controlling color distribution in generated images. */ + private List colorPalette; + @Override public JsonObject getHttpBody() { JsonObject requestObject = new JsonObject(); @@ -167,6 +176,14 @@ public Map getParameters() { params.put("bbox_list", bboxList); } + if (thinkingMode != null) { + params.put("thinking_mode", thinkingMode); + } + + if (colorPalette != null) { + params.put("color_palette", colorPalette); + } + params.putAll(parameters); return params; } diff --git a/src/main/java/com/alibaba/dashscope/aigc/imagesynthesis/ImageSynthesisParam.java b/src/main/java/com/alibaba/dashscope/aigc/imagesynthesis/ImageSynthesisParam.java index 66ac2454..ce147545 100644 --- a/src/main/java/com/alibaba/dashscope/aigc/imagesynthesis/ImageSynthesisParam.java +++ b/src/main/java/com/alibaba/dashscope/aigc/imagesynthesis/ImageSynthesisParam.java @@ -12,6 +12,7 @@ import com.alibaba.dashscope.utils.JsonUtils; import com.alibaba.dashscope.utils.PreprocessInputImage; import com.google.gson.JsonObject; +import com.google.gson.annotations.SerializedName; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.HashMap; @@ -58,6 +59,27 @@ public class ImageSynthesisParam extends HalfDuplexServiceParam { @Builder.Default private Boolean watermark = null; + /** + * Controls the similarity between the output image and the reference image (垫图). Value range: + * [0.0, 1.0]. Higher values mean the generated image is more similar to the reference image. + */ + @Builder.Default private Float refStrength = null; + + /** + * The mode for generating images based on the reference image (垫图). Supported modes: - "repaint" + * (default): Generate image based on the content of the reference image. - "refonly": Generate + * image based on the style of the reference image. + */ + @Builder.Default private String refMode = null; + + /** + * The color used to fill the masked area before inpainting. Format: hex color code, e.g., + * "#FFFFFF" or "white", "black", etc. + */ + @SerializedName("mask_color") + @Builder.Default + private String maskColor = null; + @Override public JsonObject getInput() { JsonObject jsonObject = new JsonObject(); @@ -124,6 +146,18 @@ public Map getParameters() { params.put(WATERMARK, watermark); } + if (refStrength != null) { + params.put("ref_strength", refStrength); + } + + if (refMode != null) { + params.put("ref_mode", refMode); + } + + if (maskColor != null) { + params.put("mask_color", maskColor); + } + params.putAll(super.getParameters()); return params; } diff --git a/src/main/java/com/alibaba/dashscope/aigc/imagesynthesis/SketchImageSynthesisParam.java b/src/main/java/com/alibaba/dashscope/aigc/imagesynthesis/SketchImageSynthesisParam.java index 010c07f4..4def1049 100644 --- a/src/main/java/com/alibaba/dashscope/aigc/imagesynthesis/SketchImageSynthesisParam.java +++ b/src/main/java/com/alibaba/dashscope/aigc/imagesynthesis/SketchImageSynthesisParam.java @@ -36,6 +36,18 @@ public class SketchImageSynthesisParam extends HalfDuplexServiceParam { @lombok.NonNull private String sketchImageUrl; + @SerializedName("style") + @Builder.Default + private String style = null; + + @SerializedName("sketch_extraction") + @Builder.Default + private Boolean sketchExtraction = null; + + @SerializedName("sketch_color") + @Builder.Default + private String sketchColor = null; + @lombok.NonNull private String prompt; @Override @@ -61,6 +73,15 @@ public Map getParameters() { if (realisticness != null) { params.put(REALISTICNESS, realisticness); } + if (style != null) { + params.put("style", style); + } + if (sketchExtraction != null) { + params.put("sketch_extraction", sketchExtraction); + } + if (sketchColor != null) { + params.put("sketch_color", sketchColor); + } params.putAll(super.getParameters()); return params; } diff --git a/src/main/java/com/alibaba/dashscope/aigc/multimodalconversation/MultiModalConversation.java b/src/main/java/com/alibaba/dashscope/aigc/multimodalconversation/MultiModalConversation.java index a46a0081..d0c2d87a 100644 --- a/src/main/java/com/alibaba/dashscope/aigc/multimodalconversation/MultiModalConversation.java +++ b/src/main/java/com/alibaba/dashscope/aigc/multimodalconversation/MultiModalConversation.java @@ -280,19 +280,24 @@ private void preprocessInput(MultiModalConversationParam param) /** * Modifies the parameters for internal streaming optimization. If incrementalOutput is false, * modifies the MultiModalConversationParam object to set incrementalOutput to true for internal - * streaming optimization. + * streaming optimization. If incrementalOutput is true or null, keeps the original value to + * return real incremental content. * * @param param The parameter object to modify - * @return true if the parameter was modified, false otherwise + * @return true if the parameter was modified (needs local merge), false otherwise (real + * incremental) */ private boolean modifyIncrementalOutput(MultiModalConversationParam param) { Boolean incrementalOutput = param.getIncrementalOutput(); + // Only modify when user explicitly sets incrementalOutput to false + // If user sets true or null, respect their choice and return real incremental content if (ParamUtils.shouldModifyIncrementalOutput(param.getModel()) && Boolean.FALSE.equals(incrementalOutput)) { // Modify the MultiModalConversationParam object to enable incremental output param.setIncrementalOutput(true); return true; } + // User wants real incremental content (incrementalOutput=true or null) return false; } @@ -328,22 +333,20 @@ private MultiModalConversationResult mergeSingleResponse( if (currentContent != null && !currentContent.isEmpty()) { mergeTextContent(currentContent, accumulated); } - // Always set the accumulated content if we have any - if (!accumulated.content.isEmpty()) { - choice.getMessage().setContent(accumulated.content); - } // Handle reasoning_content accumulation String currentReasoningContent = choice.getMessage().getReasoningContent(); if (currentReasoningContent != null && !currentReasoningContent.isEmpty()) { accumulated.reasoningContent.append(currentReasoningContent); } - // Always set the accumulated reasoning_content if we have any + + // Accumulate both reasoning_content and content independently if (accumulated.reasoningContent.length() > 0) { choice.getMessage().setReasoningContent(accumulated.reasoningContent.toString()); } - - // Handle tool_calls accumulation + if (!accumulated.content.isEmpty()) { + choice.getMessage().setContent(accumulated.content); + } List currentToolCalls = choice.getMessage().getToolCalls(); if (currentToolCalls != null && !currentToolCalls.isEmpty()) { mergeToolCalls(currentToolCalls, accumulated.toolCalls); diff --git a/src/main/java/com/alibaba/dashscope/aigc/multimodalconversation/MultiModalConversationParam.java b/src/main/java/com/alibaba/dashscope/aigc/multimodalconversation/MultiModalConversationParam.java index 202bfa53..2825c89a 100644 --- a/src/main/java/com/alibaba/dashscope/aigc/multimodalconversation/MultiModalConversationParam.java +++ b/src/main/java/com/alibaba/dashscope/aigc/multimodalconversation/MultiModalConversationParam.java @@ -91,19 +91,24 @@ public class MultiModalConversationParam extends HalfDuplexServiceParam { /** * Used to control the streaming output mode. If true, the subsequent output will include the * previously input content by default. Otherwise, the subsequent output will not include the - * previously output content. Default: false eg(false): + * previously output content. Default: false eg(false): /** Used to control the streaming output + * mode. If true, each chunk contains only incremental content without accumulation. If false, SDK + * accumulates chunks locally and returns full content in each chunk. Must be explicitly set - no + * default value. * *
-   * I
-   * I like
-   * I like apple
-   * when true:
-   * I
-   * like
-   * apple
+   * incrementalOutput=true (incremental):
+   * Chunk1: reasoning="让我先分析", content=[]
+   * Chunk2: reasoning="看起来是羊", content=[{text="这张图片"}]
+   * Chunk3: reasoning="", content=[{text="和一辆车"}]
+   *
+   * incrementalOutput=false (full):
+   * Chunk1: reasoning="让我先分析", content=[]
+   * Chunk2: reasoning="让我先分析看起来是羊", content=[{text="这张图片"}]
+   * Chunk3: reasoning="让我先分析看起来是羊", content=[{text="这张图片和一辆车"}]
    * 
*/ - @Builder.Default private Boolean incrementalOutput; + private Boolean incrementalOutput; /** Output format of the model including "text" and "audio". Default value: ["text"] */ private List modalities; @@ -162,6 +167,24 @@ public class MultiModalConversationParam extends HalfDuplexServiceParam { /** thinking budget */ private Integer thinkingBudget; + /** stop words or token ids to stop generation */ + @Singular("stopString") + private List stopStrings; + + @Singular private List> stopTokens; + + /** + * whether to return log probabilities of output tokens, supported for qwen-vl-ocr-2025-04-13 and + * later + */ + private Boolean logprobs; + + /** + * number of top candidate tokens to return log probabilities for, range [0,5], only effective + * when logprobs is true + */ + private Integer topLogprobs; + @Override public JsonObject getHttpBody() { JsonObject requestObject = new JsonObject(); @@ -318,6 +341,26 @@ public Map getParameters() { params.put("thinking_budget", thinkingBudget); } + if (stopStrings != null + && !stopStrings.isEmpty() + && stopTokens != null + && !stopTokens.isEmpty()) { + throw new IllegalArgumentException("Only one of stopStrings or stopTokens can be specified."); + } + if (stopStrings != null && !stopStrings.isEmpty()) { + params.put(ApiKeywords.STOP, stopStrings); + } else if (stopTokens != null && !stopTokens.isEmpty()) { + params.put(ApiKeywords.STOP, stopTokens); + } + + if (logprobs != null) { + params.put("logprobs", logprobs); + } + + if (topLogprobs != null) { + params.put("top_logprobs", topLogprobs); + } + params.putAll(parameters); return params; } diff --git a/src/main/java/com/alibaba/dashscope/common/MultiModalMessageAdapter.java b/src/main/java/com/alibaba/dashscope/common/MultiModalMessageAdapter.java index 9327ea6c..6717f643 100644 --- a/src/main/java/com/alibaba/dashscope/common/MultiModalMessageAdapter.java +++ b/src/main/java/com/alibaba/dashscope/common/MultiModalMessageAdapter.java @@ -13,9 +13,12 @@ import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonWriter; import java.io.IOException; +import java.math.BigDecimal; +import java.math.BigInteger; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.HashMap; import java.util.List; import java.util.Map; @@ -37,14 +40,18 @@ private void writeValue(JsonWriter out, Object value) throws IOException { out.nullValue(); } else if (value instanceof String) { out.value((String) value); - } else if (value instanceof Integer) { - out.value((Integer) value); - } else if (value instanceof Long) { - out.value((Long) value); - } else if (value instanceof Double) { - out.value((Double) value); - } else if (value instanceof Float) { - out.value((Float) value); + } else if (value instanceof Integer || value instanceof Long) { + out.value(((Number) value).longValue()); + } else if (value instanceof Float || value instanceof Double) { + out.value(((Number) value).doubleValue()); + } else if (value instanceof Short || value instanceof Byte) { + out.value(((Number) value).intValue()); + } else if (value instanceof BigDecimal) { + // Use jsonValue to write as JSON number, not string + out.jsonValue(((BigDecimal) value).toPlainString()); + } else if (value instanceof BigInteger) { + // Use jsonValue to write as JSON number, not string + out.jsonValue(((BigInteger) value).toString()); } else if (value instanceof Boolean) { out.value((Boolean) value); } else if (value instanceof Character) { @@ -59,8 +66,9 @@ private void writeValue(JsonWriter out, Object value) throws IOException { } else if (value instanceof Map) { writeMapObject(out, (Map) value); } else { - // Fallback for other types - out.value(value.toString()); + // For unsupported types, serialize using Gson to JSON string + String jsonStr = JsonUtils.toJson(value); + out.jsonValue(jsonStr); } } @@ -95,8 +103,8 @@ private void writeToolCallBase(JsonWriter writer, ToolCallBase toolCallBase) thr } writer.endObject(); } else if (toolCallBase instanceof ToolCallCodeInterpreter) { - // For ToolCallCodeInterpreter no extra fields besides id and type - // Any additional fields specific to this should be written here. + // ToolCallCodeInterpreter only has id, type, and index fields + // id and type are already written above, index is handled in common fields } writer.endObject(); @@ -113,10 +121,13 @@ private ToolCallFunction convertToCallFunction(LinkedTreeMap too callFunction.setName(fc.get("name").toString()); } if (fc.containsKey("arguments")) { - callFunction.setArguments(fc.get("arguments").toString()); + Object args = fc.get("arguments"); + callFunction.setArguments(args instanceof String ? (String) args : JsonUtils.toJson(args)); } if (fc.containsKey("output")) { - callFunction.setOutput(fc.get("output").toString()); + Object output = fc.get("output"); + callFunction.setOutput( + output instanceof String ? (String) output : JsonUtils.toJson(output)); } functionCall.setFunction(callFunction); } @@ -133,18 +144,89 @@ private ToolCallFunction convertToCallFunction(LinkedTreeMap too return functionCall; } + // Convert LinkedTreeMap to ToolCallQuarkSearch + @SuppressWarnings("unchecked") + private ToolCallQuarkSearch convertToQuarkSearch(LinkedTreeMap toolCall) { + ToolCallQuarkSearch quarkSearch = new ToolCallQuarkSearch(); + if (toolCall.containsKey("quark_search")) { + LinkedTreeMap qs = + (LinkedTreeMap) toolCall.get("quark_search"); + Map searchParams = new HashMap<>(); + for (Map.Entry entry : qs.entrySet()) { + Object val = entry.getValue(); + if (val instanceof String) { + searchParams.put(entry.getKey(), (String) val); + } else { + // For non-string types, serialize to JSON string + searchParams.put(entry.getKey(), JsonUtils.toJson(val)); + } + } + quarkSearch.setQuarkSearch(searchParams); + } + quarkSearch.setType(toolCall.get("type").toString()); + if (toolCall.containsKey("id")) { + quarkSearch.setId(toolCall.get("id").toString()); + } + if (toolCall.containsKey("index")) { + Object indexObj = toolCall.get("index"); + if (indexObj instanceof Number) { + quarkSearch.setIndex(((Number) indexObj).intValue()); + } + } + return quarkSearch; + } + + // Convert LinkedTreeMap to ToolCallCodeInterpreter + @SuppressWarnings("unchecked") + private ToolCallCodeInterpreter convertToCodeInterpreter(LinkedTreeMap toolCall) { + ToolCallCodeInterpreter codeInterpreter = new ToolCallCodeInterpreter(); + codeInterpreter.setType(toolCall.get("type").toString()); + if (toolCall.containsKey("id")) { + codeInterpreter.setId(toolCall.get("id").toString()); + } + if (toolCall.containsKey("index")) { + Object indexObj = toolCall.get("index"); + if (indexObj instanceof Number) { + codeInterpreter.setIndex(((Number) indexObj).intValue()); + } + } + return codeInterpreter; + } + + // Generic method to convert LinkedTreeMap to appropriate ToolCallBase subclass + @SuppressWarnings("unchecked") + private ToolCallBase convertToToolCall(LinkedTreeMap toolCall) { + if (!toolCall.containsKey("type")) { + throw new IllegalArgumentException("Tool call must contain 'type' field"); + } + + String type = toolCall.get("type").toString(); + switch (type) { + case "function": + return convertToCallFunction(toolCall); + case "quark_search": + return convertToQuarkSearch(toolCall); + case "code_interpreter": + return convertToCodeInterpreter(toolCall); + default: + throw new IllegalArgumentException("Unknown tool call type: " + type); + } + } + @Override public void write(JsonWriter out, MultiModalMessage value) throws IOException { out.beginObject(); out.name(ApiKeywords.ROLE); out.value(value.getRole()); - out.name(ApiKeywords.CONTENT); - out.beginArray(); - for (Map item : value.getContent()) { - writeMapObject(out, item); + if (value.getContent() != null) { + out.name(ApiKeywords.CONTENT); + out.beginArray(); + for (Map item : value.getContent()) { + writeMapObject(out, item); + } + out.endArray(); } - out.endArray(); if (value.getAnnotations() != null) { out.name(ApiKeywords.ANNOTATIONS); @@ -164,8 +246,7 @@ public void write(JsonWriter out, MultiModalMessage value) throws IOException { out.name(ApiKeywords.TOOL_CALLS); out.beginArray(); List toolCalls = value.getToolCalls(); - for (ToolCallBase tc : - JsonUtils.fromJson(JsonUtils.toJson(toolCalls), ToolCallBase[].class)) { + for (ToolCallBase tc : toolCalls) { writeToolCallBase(out, tc); } out.endArray(); @@ -199,20 +280,37 @@ public MultiModalMessage read(JsonReader in) throws IOException { Object content = objectMap.get(ApiKeywords.CONTENT); if (content instanceof String) { msg.setContent(Arrays.asList(Collections.singletonMap("text", (String) content))); - } else { + } else if (content instanceof List) { msg.setContent((List>) content); + } else { + throw new IllegalArgumentException( + "Content must be String or List, got: " + + (content != null ? content.getClass().getName() : "null")); } objectMap.remove(ApiKeywords.CONTENT); } if (objectMap.containsKey(ApiKeywords.ANNOTATIONS)) { - msg.setAnnotations((List>) objectMap.get(ApiKeywords.ANNOTATIONS)); + Object annotations = objectMap.get(ApiKeywords.ANNOTATIONS); + if (annotations instanceof List) { + msg.setAnnotations((List>) annotations); + } else { + throw new IllegalArgumentException( + "Annotations must be List, got: " + + (annotations != null ? annotations.getClass().getName() : "null")); + } objectMap.remove(ApiKeywords.ANNOTATIONS); } if (objectMap.containsKey(ApiKeywords.REASONING_CONTENT)) { - String reasoningContent = (String) objectMap.get(ApiKeywords.REASONING_CONTENT); - msg.setReasoningContent(reasoningContent); + Object reasoningContent = objectMap.get(ApiKeywords.REASONING_CONTENT); + if (reasoningContent instanceof String) { + msg.setReasoningContent((String) reasoningContent); + } else { + throw new IllegalArgumentException( + "Reasoning content must be String, got: " + + (reasoningContent != null ? reasoningContent.getClass().getName() : "null")); + } objectMap.remove(ApiKeywords.REASONING_CONTENT); } @@ -223,22 +321,15 @@ public MultiModalMessage read(JsonReader in) throws IOException { // Check if need conversion for function type boolean needConversion = false; if (!toolCallsList.isEmpty() && toolCallsList.get(0) instanceof LinkedTreeMap) { - LinkedTreeMap firstToolCall = - (LinkedTreeMap) toolCallsList.get(0); - if (firstToolCall.containsKey("type")) { - String type = firstToolCall.get("type").toString(); - if (type.equals("function")) { - needConversion = true; - } - } + needConversion = true; } if (needConversion) { - // Convert LinkedTreeMap to ToolCallFunction + // Convert LinkedTreeMap to appropriate ToolCallBase subclass msg.toolCalls = new ArrayList(); List toolCalls = (List) toolCallsObj; for (LinkedTreeMap toolCall : toolCalls) { - msg.toolCalls.add(convertToCallFunction(toolCall)); + msg.toolCalls.add(convertToToolCall(toolCall)); } } else { // Use original method for non-function types diff --git a/src/main/java/com/alibaba/dashscope/multimodal/tingwu/TingWu.java b/src/main/java/com/alibaba/dashscope/multimodal/tingwu/TingWu.java index fc865c05..236bc00f 100644 --- a/src/main/java/com/alibaba/dashscope/multimodal/tingwu/TingWu.java +++ b/src/main/java/com/alibaba/dashscope/multimodal/tingwu/TingWu.java @@ -12,15 +12,15 @@ public final class TingWu { private final SynchronizeHalfDuplexApi syncApi; private final ApiServiceOption serviceOption; - private final String DEFAULT_BASE_HTTP_URL = - "https://dashscope.aliyuncs.com/api/v1/services/aigc/multimodal-generation/generation"; private ApiServiceOption defaultApiServiceOption() { return ApiServiceOption.builder() .protocol(Protocol.HTTP) .httpMethod(HttpMethod.POST) - .isService(false) - .baseHttpUrl(DEFAULT_BASE_HTTP_URL) + .isService(true) + .taskGroup(TaskGroup.AIGC.getValue()) + .task(Task.MULTIMODAL_GENERATION.getValue()) + .function(Function.GENERATION.getValue()) .build(); } diff --git a/src/main/java/com/alibaba/dashscope/protocol/HalfDuplexRequest.java b/src/main/java/com/alibaba/dashscope/protocol/HalfDuplexRequest.java index b47b1e0f..5d40d9b2 100644 --- a/src/main/java/com/alibaba/dashscope/protocol/HalfDuplexRequest.java +++ b/src/main/java/com/alibaba/dashscope/protocol/HalfDuplexRequest.java @@ -59,7 +59,12 @@ public String getHttpUrl() { if (baseUrl.endsWith("/")) { baseUrl = baseUrl.substring(0, baseUrl.length() - 1); } - return baseUrl + serviceOption.httpUrl(); + String path = serviceOption.httpUrl(); + // Avoid duplicate path when baseUrl already contains the full path + if (path != null && !path.isEmpty() && baseUrl.endsWith(path)) { + return baseUrl; + } + return baseUrl + path; } public boolean isSecurityCheck() { diff --git a/src/main/java/com/alibaba/dashscope/protocol/okhttp/OkHttpWebSocketClient.java b/src/main/java/com/alibaba/dashscope/protocol/okhttp/OkHttpWebSocketClient.java index c91bd363..333a0dfc 100644 --- a/src/main/java/com/alibaba/dashscope/protocol/okhttp/OkHttpWebSocketClient.java +++ b/src/main/java/com/alibaba/dashscope/protocol/okhttp/OkHttpWebSocketClient.java @@ -740,8 +740,13 @@ private void joinSendFuture(CompletableFuture future) { future.cancel(true); future.join(); } - } catch (CancellationException | CompletionException ex) { + } catch (CancellationException ex) { + log.error("Sending streaming data cancelled", ex.getMessage()); + } catch (CompletionException ex) { log.error("Sending streaming data exception", ex.getMessage()); + if (responseEmitter != null && !responseEmitter.isCancelled()) { + responseEmitter.onError(ex.getCause() != null ? ex.getCause() : ex); + } } } diff --git a/src/test/java/com/alibaba/dashscope/TestImageSynthesis.java b/src/test/java/com/alibaba/dashscope/TestImageSynthesis.java index bc1ecee3..7741cea8 100644 --- a/src/test/java/com/alibaba/dashscope/TestImageSynthesis.java +++ b/src/test/java/com/alibaba/dashscope/TestImageSynthesis.java @@ -109,4 +109,96 @@ public void testImageSynthesisUsageMore() String requestBody = request.getBody().readUtf8(); assertEquals(expectRequestBody, requestBody); } + + @Test + public void testImageSynthesisWithRefStrengthAndRefMode() + throws ApiException, NoApiKeyException, IOException, InterruptedException, + InputRequiredException { + String responseBody = + "{\"request_id\":\"40\",\"output\":{\"task_id\":\"e5\",\"task_status\":\"SUCCEEDED\",\"results\":[{\"url\":\"https://ref1\"}],\"task_metrics\":{\"TOTAL\":1,\"SUCCEEDED\":1,\"FAILED\":0}},\"usage\":{\"image_count\":1}}"; + server.enqueue( + new MockResponse() + .setBody(responseBody) + .setHeader("content-type", MEDIA_TYPE_APPLICATION_JSON)); + int port = server.getPort(); + ImageSynthesis is = new ImageSynthesis(); + ImageSynthesisParam param = + ImageSynthesisParam.builder() + .model(ImageSynthesis.Models.WANX_2_1_IMAGEEDIT) + .n(1) + .prompt("参考图像生成") + .refStrength(0.8f) + .refMode("repaint") + .images(java.util.Arrays.asList("https://example.com/ref.png")) + .build(); + Constants.baseHttpApiUrl = String.format("http://127.0.0.1:%s", port); + ImageSynthesisResult result = is.asyncCall(param); + RecordedRequest request = server.takeRequest(); + String requestBody = request.getBody().readUtf8(); + log.info("Request body with ref params: {}", requestBody); + // 验证 ref_strength 和 ref_mode 参数被正确序列化 + assertEquals(true, requestBody.contains("\"ref_strength\":0.8")); + assertEquals(true, requestBody.contains("\"ref_mode\":\"repaint\"")); + } + + @Test + public void testImageSynthesisWithMaskColor() + throws ApiException, NoApiKeyException, IOException, InterruptedException, + InputRequiredException { + String responseBody = + "{\"request_id\":\"41\",\"output\":{\"task_id\":\"e6\",\"task_status\":\"SUCCEEDED\",\"results\":[{\"url\":\"https://mask1\"}],\"task_metrics\":{\"TOTAL\":1,\"SUCCEEDED\":1,\"FAILED\":0}},\"usage\":{\"image_count\":1}}"; + server.enqueue( + new MockResponse() + .setBody(responseBody) + .setHeader("content-type", MEDIA_TYPE_APPLICATION_JSON)); + int port = server.getPort(); + ImageSynthesis is = new ImageSynthesis(); + ImageSynthesisParam param = + ImageSynthesisParam.builder() + .model(ImageSynthesis.Models.WANX_2_1_IMAGEEDIT) + .n(1) + .prompt("局部重绘") + .function("description_edit_with_mask") + .baseImageUrl("https://www.xxx.cn/base.png") + .maskImageUrl("https://www.xxx.cn/mask.png") + .maskColor("#FFFFFF") + .build(); + Constants.baseHttpApiUrl = String.format("http://127.0.0.1:%s", port); + ImageSynthesisResult result = is.asyncCall(param); + RecordedRequest request = server.takeRequest(); + String requestBody = request.getBody().readUtf8(); + log.info("Request body with mask_color: {}", requestBody); + // 验证 mask_color 参数被正确序列化 + assertEquals(true, requestBody.contains("\"mask_color\":\"#FFFFFF\"")); + } + + @Test + public void testImageSynthesisWithPromptExtendAndWatermark() + throws ApiException, NoApiKeyException, IOException, InterruptedException, + InputRequiredException { + String responseBody = + "{\"request_id\":\"42\",\"output\":{\"task_id\":\"e7\",\"task_status\":\"SUCCEEDED\",\"results\":[{\"url\":\"https://extend1\"}],\"task_metrics\":{\"TOTAL\":1,\"SUCCEEDED\":1,\"FAILED\":0}},\"usage\":{\"image_count\":1}}"; + server.enqueue( + new MockResponse() + .setBody(responseBody) + .setHeader("content-type", MEDIA_TYPE_APPLICATION_JSON)); + int port = server.getPort(); + ImageSynthesis is = new ImageSynthesis(); + ImageSynthesisParam param = + ImageSynthesisParam.builder() + .model(ImageSynthesis.Models.WANX_2_1_IMAGEEDIT) + .n(1) + .prompt("简单提示词") + .promptExtend(true) + .watermark(false) + .build(); + Constants.baseHttpApiUrl = String.format("http://127.0.0.1:%s", port); + ImageSynthesisResult result = is.asyncCall(param); + RecordedRequest request = server.takeRequest(); + String requestBody = request.getBody().readUtf8(); + log.info("Request body with prompt_extend and watermark: {}", requestBody); + // 验证 prompt_extend 和 watermark 参数被正确序列化 + assertEquals(true, requestBody.contains("\"prompt_extend\":true")); + assertEquals(true, requestBody.contains("\"watermark\":false")); + } } diff --git a/src/test/resources/assistant.json b/src/test/resources/assistant.json index c89d6cd5..2b55b086 100644 --- a/src/test/resources/assistant.json +++ b/src/test/resources/assistant.json @@ -161,4 +161,4 @@ "last_id": "file_2", "has_more": false } -} \ No newline at end of file +} diff --git a/src/test/resources/messages.json b/src/test/resources/messages.json index 141c3160..37a9cd6d 100644 --- a/src/test/resources/messages.json +++ b/src/test/resources/messages.json @@ -98,4 +98,4 @@ "created_at": 1699061776, "message_id": "msg_1" } -} \ No newline at end of file +} diff --git a/src/test/resources/mismatch.jsonl b/src/test/resources/mismatch.jsonl index ba8bf4b6..ef0cc609 100644 --- a/src/test/resources/mismatch.jsonl +++ b/src/test/resources/mismatch.jsonl @@ -1,7 +1,7 @@ -{"HumanAnswer": "2个读音  一个是xi 一个是qian", -"Python": [24918, 18947, 57553, 78685, 22441, 22441, 108075, 144767, 144155, 22441, 108075, 145529, 144155, 144127, 144270], +{"HumanAnswer": "2个读音  一个是xi 一个是qian", +"Python": [24918, 18947, 57553, 78685, 22441, 22441, 108075, 144767, 144155, 22441, 108075, 145529, 144155, 144127, 144270], "Java": [24918, 18947, 57553, 78685, 43429, 108075, 144767, 144155, 22441, 108075, 145529, 144155, 144127, 144270]} -{"HumanAnswer": "炸腐竹·油温要适中·炸后浸温水 +{"HumanAnswer": "炸腐竹·油温要适中·炸后浸温水   要腐竹炸得刚好而不焦黑,秘诀是当生油烧至六成熟时转慢火,然后放下腐竹,迅速地翻动,让腐竹全身炸透,呈现白泡,并即投入温水中浸透,再切段。炸时如油温过热,会将腐竹炸焦,变深黄色或黑色,如油温不够热,则不会起白泡。 ", "Python": [100893, 100298, 102045, 13935, 99318, 99416, 30534, 99340, 15946, 13935, 100893, 33447, 101595, 99416, 52510, 2529, 22441, 22441, 30534, 100298, 102045, 100893, 49828, 109586, 105145, 100479, 56652, 3837, 114928, 20412, 39165, 21287, 99318, 100228, 56137, 99566, 102226, 13343, 46670, 99843, 79599, 3837, 101889, 106162, 100298, 102045, 3837, 104015, 29490, 100712, 27733, 3837, 99258, 100298, 102045, 105418, 100893, 99844, 3837, 104401, 99243, 100454, 90395, 91676, 100709, 99416, 107629, 101595, 99844, 3837, 87256, 99322, 37474, 1773, 100893, 13343, 29524, 99318, 99416, 38182, 99259, 3837, 36993, 44063, 100298, 102045, 100893, 100479, 3837, 74040, 99194, 106140, 57191, 104723, 3837, 29524, 99318, 99416, 104222, 99259, 95053, 99670, 71618, 99243, 100454, 1773, 220], "Java": [100893, 100298, 102045, 13935, 99318, 99416, 30534, 99340, 15946, 13935, 100893, 33447, 101595, 99416, 52510, 2529, 43429, 30534, 100298, 102045, 100893, 49828, 109586, 105145, 100479, 56652, 3837, 114928, 20412, 39165, 21287, 99318, 100228, 56137, 99566, 102226, 13343, 46670, 99843, 79599, 3837, 101889, 106162, 100298, 102045, 3837, 104015, 29490, 100712, 27733, 3837, 99258, 100298, 102045, 105418, 100893, 99844, 3837, 104401, 99243, 100454, 90395, 91676, 100709, 99416, 107629, 101595, 99844, 3837, 87256, 99322, 37474, 1773, 100893, 13343, 29524, 99318, 99416, 38182, 99259, 3837, 36993, 44063, 100298, 102045, 100893, 100479, 3837, 74040, 99194, 106140, 57191, 104723, 3837, 29524, 99318, 99416, 104222, 99259, 95053, 99670, 71618, 99243, 100454, 1773, 220]} {"HumanAnswer": "  你好,癫痫病频频发作容易造成癫痫患者的脑发育障碍、组织结构毁坏、代谢异常,必然也影响其所有心理发育的领域,对于脑器质性损害伴发的癫痫,往往伴有智力损害及行为问题。一般癫痫发生愈早,程度愈重,对心理、精神行为的影响也愈大。 ", "Python": [22441, 22441, 108386, 3837, 113282, 111972, 107253, 100047, 101090, 103440, 108723, 99931, 106115, 102544, 5373, 99877, 100166, 100882, 100250, 5373, 103225, 70633, 3837, 102309, 74763, 99564, 41146, 55338, 100438, 106115, 9370, 100650, 3837, 100002, 99931, 31548, 99178, 33071, 105252, 99595, 28291, 9370, 103440, 3837, 101207, 115563, 107941, 105252, 81217, 101070, 86119, 1773, 100141, 103440, 99726, 100939, 99391, 3837, 100069, 100939, 29258, 3837, 32664, 100438, 5373, 100150, 101070, 104126, 74763, 100939, 26288, 37265], "Java": [43429, 108386, 3837, 113282, 111972, 107253, 100047, 101090, 103440, 108723, 99931, 106115, 102544, 5373, 99877, 100166, 100882, 100250, 5373, 103225, 70633, 3837, 102309, 74763, 99564, 41146, 55338, 100438, 106115, 9370, 100650, 3837, 100002, 99931, 31548, 99178, 33071, 105252, 99595, 28291, 9370, 103440, 3837, 101207, 115563, 107941, 105252, 81217, 101070, 86119, 1773, 100141, 103440, 99726, 100939, 99391, 3837, 100069, 100939, 29258, 3837, 32664, 100438, 5373, 100150, 101070, 104126, 74763, 100939, 26288, 37265]} @@ -10,7 +10,7 @@ ", "Python": [85336, 116350, 104160, 39907, 99604, 99999, 97480, 36993, 99518, 102478, 3837, 102716, 104160, 18830, 319, 22441, 16, 5373, 99950, 100553, 24339, 9909, 99393, 99451, 24339, 7552, 85336, 116350, 220, 22441, 22441, 17, 5373, 29767, 101953, 24339, 85336, 116350, 220, 22441, 18, 5373, 105608, 24339, 85336, 116350, 220, 22441, 22441, 19, 5373, 99759, 64952, 32320, 99368, 24339, 85336, 116350, 220, 22441, 20, 5373, 47815, 76837, 99322, 29767, 24339, 85336, 116350, 220, 100700, 99559, 30440, 118393, 100849, 105157, 104316, 31139, 319], "Java": [85336, 116350, 104160, 39907, 99604, 99999, 97480, 36993, 99518, 102478, 3837, 102716, 104160, 18830, 319, 22441, 16, 5373, 99950, 100553, 24339, 9909, 99393, 99451, 24339, 7552, 85336, 116350, 220, 43429, 17, 5373, 29767, 101953, 24339, 85336, 116350, 220, 22441, 18, 5373, 105608, 24339, 85336, 116350, 220, 43429, 19, 5373, 99759, 64952, 32320, 99368, 24339, 85336, 116350, 220, 22441, 20, 5373, 47815, 76837, 99322, 29767, 24339, 85336, 116350, 220, 100700, 99559, 30440, 118393, 100849, 105157, 104316, 31139, 319]} {"HumanAnswer": "  你好,过敏性鼻炎喷嚏、鼻痒、流涕和鼻堵是最常见的四大症状。目前临床上主要是应用内窥镜下等离子低温消融术,选择性地进行筛前神经、翼管神经阻断术,降低鼻腔副交感神经的兴奋性,消除过敏区域神经对外界各种刺激,如气候、灰尘、花粉等的敏感性,过敏性鼻炎就可以自然而愈,不易复发。 ", "Python": [22441, 22441, 108386, 11, 107270, 33071, 102228, 100439, 102125, 121875, 5373, 102228, 108681, 5373, 88653, 119392, 33108, 102228, 101476, 104890, 102716, 104978, 101368, 1773, 100004, 99635, 101717, 104312, 99892, 31843, 112808, 100811, 16872, 49567, 108510, 109878, 32320, 99368, 99216, 3837, 50404, 33071, 29490, 71817, 101737, 24562, 102398, 5373, 101401, 35551, 102398, 100318, 63789, 99216, 3837, 101134, 102228, 102504, 99310, 38109, 98650, 102398, 9370, 105487, 33071, 3837, 105109, 107270, 101065, 102398, 102330, 97120, 100646, 104313, 3837, 29524, 102730, 5373, 114267, 5373, 99232, 99742, 49567, 9370, 105521, 33071, 3837, 107270, 33071, 102228, 100439, 102003, 117536, 100939, 3837, 106921, 111574, 8997], "Java": [43429, 108386, 11, 107270, 33071, 102228, 100439, 102125, 121875, 5373, 102228, 108681, 5373, 88653, 119392, 33108, 102228, 101476, 104890, 102716, 104978, 101368, 1773, 100004, 99635, 101717, 104312, 99892, 31843, 112808, 100811, 16872, 49567, 108510, 109878, 32320, 99368, 99216, 3837, 50404, 33071, 29490, 71817, 101737, 24562, 102398, 5373, 101401, 35551, 102398, 100318, 63789, 99216, 3837, 101134, 102228, 102504, 99310, 38109, 98650, 102398, 9370, 105487, 33071, 3837, 105109, 107270, 101065, 102398, 102330, 97120, 100646, 104313, 3837, 29524, 102730, 5373, 114267, 5373, 99232, 99742, 49567, 9370, 105521, 33071, 3837, 107270, 33071, 102228, 100439, 102003, 117536, 100939, 3837, 106921, 111574, 8997]} -{"HumanAnswer": "  新生婴儿应在出生后一个月内,到父亲或母亲户口所在地的户口登记机关(辖区派出所)办理出生入户登记。 +{"HumanAnswer": "  新生婴儿应在出生后一个月内,到父亲或母亲户口所在地的户口登记机关(辖区派出所)办理出生入户登记。   办理时需提供以下材料:   1、小孩的出生医学证明   2、父母的户口簿、身份证和结婚证。", "Python": [22441, 22441, 102900, 102833, 110391, 102246, 33447, 105033, 31843, 3837, 26939, 102037, 57191, 102079, 109200, 108176, 9370, 109200, 104141, 100776, 9909, 103022, 106644, 7552, 103990, 102246, 111981, 104141, 1773, 2529, 22441, 22441, 103990, 13343, 58362, 99553, 87752, 100643, 5122, 319, 22441, 22441, 16, 5373, 104902, 9370, 102246, 104316, 104022, 319, 22441, 22441, 17, 5373, 103953, 9370, 109200, 113649, 5373, 105765, 33108, 104388, 33477, 1773], "Java": [43429, 102900, 102833, 110391, 102246, 33447, 105033, 31843, 3837, 26939, 102037, 57191, 102079, 109200, 108176, 9370, 109200, 104141, 100776, 9909, 103022, 106644, 7552, 103990, 102246, 111981, 104141, 1773, 2529, 43429, 103990, 13343, 58362, 99553, 87752, 100643, 5122, 319, 43429, 16, 5373, 104902, 9370, 102246, 104316, 104022, 319, 43429, 17, 5373, 103953, 9370, 109200, 113649, 5373, 105765, 33108, 104388, 33477, 1773]} @@ -59,7 +59,7 @@ {"HumanAnswer": "1.及时治疗:主要是改善脑血液循环。可以在医生的指导下使用扩血管药物和银杏叶制剂等。  2.早期预防:对脑供血不足的防治重点在脑血管方面,尤其是血脂和低密度脂蛋白增高要对症处理。  3.合理饮食:平时多吃新鲜蔬菜(如洋葱、西红柿等)、水果、鱼、黑木耳、少量醋、干红葡萄酒等,可以起抗氧化作用,延缓脑动脉硬化的发生。  4.适当的户外活动:如快走、慢跑、散步等,每次30-40分钟,每周至少5天,或者打打太极拳、垂钓、登山等。  5.保持良好的心态和健康用脑:平时看看电视、报纸;做些手工劳作或家务事;也可以参加一些文体活动,如唱歌、跳舞、书法、打球等,调制性情,增强脑的思维活动;避免情绪激动和过度疲劳。", "Python": [16, 58883, 100667, 101899, 5122, 104312, 104009, 99931, 116417, 1773, 104964, 103998, 9370, 109767, 37029, 99834, 102890, 104459, 33108, 99660, 108202, 100027, 115031, 49567, 1773, 22441, 22441, 17, 58883, 105184, 104332, 5122, 32664, 99931, 83744, 99389, 102004, 9370, 102681, 99887, 18493, 99931, 102890, 99522, 3837, 104033, 118112, 33108, 99285, 106651, 100553, 102835, 117015, 30534, 32664, 99769, 54542, 1773, 22441, 22441, 18, 58883, 100745, 104579, 5122, 104325, 108851, 104838, 104451, 7, 29524, 117956, 5373, 117700, 49567, 8, 5373, 104618, 5373, 100655, 5373, 56652, 116690, 5373, 108521, 106960, 5373, 99251, 99425, 107358, 49567, 3837, 73670, 71618, 118283, 100154, 3837, 99771, 99982, 99931, 109826, 99927, 105302, 99726, 1773, 22441, 22441, 19, 58883, 109776, 105813, 99600, 5122, 29524, 99234, 99314, 5373, 99843, 99803, 5373, 111261, 49567, 3837, 102173, 18, 15, 12, 19, 15, 83031, 3837, 106854, 104102, 20, 35727, 3837, 100631, 75437, 75437, 116674, 5373, 102566, 103429, 5373, 112357, 49567, 1773, 22441, 22441, 20, 58883, 100662, 104205, 106479, 33108, 99722, 11622, 99931, 5122, 104325, 101997, 100234, 5373, 107574, 24968, 99190, 97084, 107171, 99697, 19403, 57191, 114791, 29826, 24968, 104047, 101061, 101883, 111048, 99600, 3837, 29524, 109283, 5373, 112084, 5373, 102702, 5373, 117248, 49567, 3837, 47872, 43316, 33071, 39374, 3837, 101138, 99931, 9370, 102141, 99600, 24968, 101153, 104405, 105694, 33108, 105831, 108351, 1773], "Java": [16, 58883, 100667, 101899, 5122, 104312, 104009, 99931, 116417, 1773, 104964, 103998, 9370, 109767, 37029, 99834, 102890, 104459, 33108, 99660, 108202, 100027, 115031, 49567, 1773, 43429, 17, 58883, 105184, 104332, 5122, 32664, 99931, 83744, 99389, 102004, 9370, 102681, 99887, 18493, 99931, 102890, 99522, 3837, 104033, 118112, 33108, 99285, 106651, 100553, 102835, 117015, 30534, 32664, 99769, 54542, 1773, 43429, 18, 58883, 100745, 104579, 5122, 104325, 108851, 104838, 104451, 7, 29524, 117956, 5373, 117700, 49567, 8, 5373, 104618, 5373, 100655, 5373, 56652, 116690, 5373, 108521, 106960, 5373, 99251, 99425, 107358, 49567, 3837, 73670, 71618, 118283, 100154, 3837, 99771, 99982, 99931, 109826, 99927, 105302, 99726, 1773, 43429, 19, 58883, 109776, 105813, 99600, 5122, 29524, 99234, 99314, 5373, 99843, 99803, 5373, 111261, 49567, 3837, 102173, 18, 15, 12, 19, 15, 83031, 3837, 106854, 104102, 20, 35727, 3837, 100631, 75437, 75437, 116674, 5373, 102566, 103429, 5373, 112357, 49567, 1773, 43429, 20, 58883, 100662, 104205, 106479, 33108, 99722, 11622, 99931, 5122, 104325, 101997, 100234, 5373, 107574, 24968, 99190, 97084, 107171, 99697, 19403, 57191, 114791, 29826, 24968, 104047, 101061, 101883, 111048, 99600, 3837, 29524, 109283, 5373, 112084, 5373, 102702, 5373, 117248, 49567, 3837, 47872, 43316, 33071, 39374, 3837, 101138, 99931, 9370, 102141, 99600, 24968, 101153, 104405, 105694, 33108, 105831, 108351, 1773]} {"HumanAnswer": "您好:肠道检查包括: (1)粪便检查: -  (2)直肠指诊: +  (2)直肠指诊:   (3)乙状结肠镜检查:   (4)钡灌肠X线检查:   (5)纤维结肠镜检查 @@ -93,6 +93,6 @@ {"HumanAnswer": "不合法  属于盗用   协议也是无效的   不受保护", "Python": [16530, 101431, 4102, 4102, 100409, 100591, 11622, 9238, 4102, 101136, 100000, 107128, 9370, 9238, 4102, 107524, 100153], "Java": [16530, 101431, 9238, 100409, 100591, 11622, 45393, 101136, 100000, 107128, 9370, 45393, 107524, 100153]} {"HumanAnswer": "您好  一般是可以的,具体的咨询社保部门", "Python": [111308, 4102, 4102, 100141, 105903, 9370, 3837, 108247, 100703, 106732, 99667], "Java": [111308, 9238, 100141, 105903, 9370, 3837, 108247, 100703, 106732, 99667]} {"HumanAnswer": "针对你的问题答复如下:    《民法通则》第六十六条 没有代理权、超越代理权或者代理权终止后的行为,只有经过被代理人的追认,被代理人才承担民事责任。未经追认的行为,由行为人承担民事责任。本人知道他人以本人名义实施民事行为而不作否认表示的,视为同意。以上答复,如果满意,敬请采纳,并给予评价。", "Python": [101092, 103929, 86119, 110463, 104506, 5122, 45393, 4102, 26940, 69721, 24339, 31935, 46448, 25067, 102651, 117602, 4102, 80443, 101259, 40981, 5373, 104840, 101259, 40981, 100631, 101259, 40981, 107660, 33447, 104796, 3837, 101043, 101897, 99250, 101259, 103947, 99626, 28951, 3837, 99250, 101259, 101050, 102016, 108669, 99531, 1773, 102887, 99626, 28951, 104796, 3837, 67071, 101070, 17340, 102016, 108669, 99531, 1773, 102043, 99392, 104287, 23031, 102043, 107765, 100355, 108669, 101070, 105145, 19403, 109433, 51463, 9370, 3837, 103097, 101185, 1773, 70589, 110463, 3837, 62244, 100545, 3837, 114131, 115250, 90395, 102062, 103964, 1773], "Java": [101092, 103929, 86119, 110463, 104506, 5122, 19070, 26940, 69721, 24339, 31935, 46448, 25067, 102651, 117602, 4102, 80443, 101259, 40981, 5373, 104840, 101259, 40981, 100631, 101259, 40981, 107660, 33447, 104796, 3837, 101043, 101897, 99250, 101259, 103947, 99626, 28951, 3837, 99250, 101259, 101050, 102016, 108669, 99531, 1773, 102887, 99626, 28951, 104796, 3837, 67071, 101070, 17340, 102016, 108669, 99531, 1773, 102043, 99392, 104287, 23031, 102043, 107765, 100355, 108669, 101070, 105145, 19403, 109433, 51463, 9370, 3837, 103097, 101185, 1773, 70589, 110463, 3837, 62244, 100545, 3837, 114131, 115250, 90395, 102062, 103964, 1773]} -{"HumanAnswer": "你在网上的棋牌室花了人民币多少钱啊  你说的跑路是什么意思啊", -"Python": [107740, 31139, 101913, 101386, 99478, 108225, 104142, 105957, 103924, 4102, 4102, 105665, 9370, 99803, 45995, 102021, 100313, 103924], +{"HumanAnswer": "你在网上的棋牌室花了人民币多少钱啊  你说的跑路是什么意思啊", +"Python": [107740, 31139, 101913, 101386, 99478, 108225, 104142, 105957, 103924, 4102, 4102, 105665, 9370, 99803, 45995, 102021, 100313, 103924], "Java": [107740, 31139, 101913, 101386, 99478, 108225, 104142, 105957, 103924, 9238, 105665, 9370, 99803, 45995, 102021, 100313, 103924]} diff --git a/src/test/resources/runs.json b/src/test/resources/runs.json index c2977189..742d4094 100644 --- a/src/test/resources/runs.json +++ b/src/test/resources/runs.json @@ -482,4 +482,4 @@ "response_format": "auto", "tool_choice": "auto" } -} \ No newline at end of file +} diff --git a/src/test/resources/stream_runs.json b/src/test/resources/stream_runs.json index 98ac44fc..12096721 100644 --- a/src/test/resources/stream_runs.json +++ b/src/test/resources/stream_runs.json @@ -55,7 +55,7 @@ { "event": "done", "data": "[DONE]" - } + } ], "create_stream_thread_and_run_response": [ {"event": "thread.created", @@ -120,7 +120,7 @@ { "event": "done", "data": "[DONE]" - } + } ], "create_stream_require_action_function_1": [ { @@ -182,7 +182,7 @@ { "event": "done", "data": "[DONE]" - } + } ], "create_stream_require_action_function_2": [ { @@ -292,4 +292,4 @@ "data": "[DONE]" } ] -} \ No newline at end of file +} diff --git a/src/test/resources/threads.json b/src/test/resources/threads.json index 863b37ef..aafdd3c5 100644 --- a/src/test/resources/threads.json +++ b/src/test/resources/threads.json @@ -34,4 +34,4 @@ "object": "thread" }] } -} \ No newline at end of file +}