feat: update image default model

This commit is contained in:
clh02467605
2026-08-05 16:58:29 +08:00
parent b1908fa879
commit 4990b27436
20 changed files with 57 additions and 32 deletions
+1 -1
View File
@@ -26,7 +26,7 @@ Equip your AI Agent out-of-the-box with these capabilities, composable across co
- **Text chat** — Qwen3.8-max: major gains in agentic coding, frontend coding, and vibe coding
- **Multimodal (Omni)** — Full omni-modal support across text + image + audio + video
- **Image generation & editing** — Qwen-Image 2.0: pro text rendering, photorealism, strong semantic adherence, multi-image composition
- **Image generation & editing** — Qwen-Image 3.0: pro text rendering, photorealism, strong semantic adherence, multi-image composition
- **Video generation & editing** — happyhorse-1.1 series: text-/image-/reference-to-video and natural-language video editing (up to 9-image reference)
- **Speech synthesis & recognition** — CosyVoice streaming TTS, voice cloning from 5–20s samples; FunAudio-ASR covers 30 languages including 7 Chinese dialects and 20+ Mandarin accents
- **Image & video understanding** — Qwen-VL: long-form video analysis, chart/document parsing, visual reasoning, multilingual OCR
+1 -1
View File
@@ -26,7 +26,7 @@ _专为 AI Agent 打造,每个命令均可作为结构化工具调用。_
- **文本对话** — Qwen3.8-max:Agentic coding、前端编程、Vibe coding 等能力显著增强
- **全模态对话** — 文本 + 图像 + 音频 + 视频全模态支持
- **图像生成与编辑** — Qwen-Image 2.0:专业文字渲染、真实质感、强语义遵循、多图合成
- **图像生成与编辑** — Qwen-Image 3.0:专业文字渲染、真实质感、强语义遵循、多图合成
- **视频生成与编辑** — happyhorse-1.1 系列,支持文生 / 图生 / 参考生(最多 9 张图参考)/ 自然语言视频编辑
- **语音合成与识别** — CosyVoice 实时流式合成,5-20s 样本即可克隆;FunAudio-ASR 覆盖 30 种语种,含汉语七大方言与 20+ 口音官话
- **图像与视频理解** — Qwen-VL:长视频解析、复杂图表与文档识别、视觉推理、多语种 OCR
@@ -61,7 +61,7 @@ export const UI_BOOLEAN_KEYS = new Set<string>(["telemetry"]);
// without persisting a value that would pin the model.
export const UI_MODEL_DEFAULTS: Record<string, string> = {
default_text_model: "qwen3.8-max",
default_image_model: "qwen-image-2.0",
default_image_model: "qwen-image-3.0",
default_video_model: "happyhorse-1.1-t2v",
default_speech_model: "cosyvoice-v3-flash",
default_omni_model: "qwen3.5-omni-plus",
@@ -86,7 +86,8 @@ export const UI_MODEL_CATALOG: Record<string, ModelOption[]> = {
{ id: "qwen3.6-flash", role: "fast · advisor intent" },
],
default_image_model: [
{ id: "qwen-image-2.0", role: "image/generate default · sync" },
{ id: "qwen-image-3.0", role: "image/generate default · sync" },
{ id: "qwen-image-2.0", role: "image/generate · sync" },
{ id: "qwen-image-max", role: "image/generate · sync" },
{ id: "qwen-image-edit-2.0", role: "image/edit · sync" },
{ id: "wanx2.x", role: "image/generate · async series" },
@@ -23,7 +23,7 @@ export default defineCommand({
"--file photo.jpg --model qwen3-vl-plus",
"--file video.mp4 --model wan2.1-t2v-plus",
"--file audio.wav --model qwen3-asr-flash",
"--file cat.png --model qwen-image-2.0",
"--file cat.png --model qwen-image-3.0",
],
async run(ctx) {
const { settings, flags } = ctx;
+2 -2
View File
@@ -47,7 +47,7 @@ const EDIT_FLAGS = {
model: {
type: "string",
valueHint: "<model>",
description: "Model ID (default: qwen-image-2.0)",
description: "Model ID (default: qwen-image-3.0)",
},
size: {
type: "string",
@@ -123,7 +123,7 @@ export default defineCommand({
}
const prompt = flags.prompt;
const model = flags.model || settings.defaultImageModel || "qwen-image-2.0";
const model = flags.model || settings.defaultImageModel || "qwen-image-3.0";
const route = resolveImageEditApi(model);
// Auto-upload local files (resolve all images in parallel)
@@ -35,7 +35,7 @@ const GENERATE_FLAGS = {
model: {
type: "string",
valueHint: "<model>",
description: "Model ID (default: qwen-image-2.0)",
description: "Model ID (default: qwen-image-3.0)",
},
size: {
type: "string",
@@ -105,7 +105,7 @@ export default defineCommand({
const { settings, flags } = ctx;
const prompt = flags.prompt;
const model = flags.model || settings.defaultImageModel || "qwen-image-2.0";
const model = flags.model || settings.defaultImageModel || "qwen-image-3.0";
const route = resolveImageGenerateApi(model);
const defaultSize = "1:1";
const sizeInput = flags.size || defaultSize;
+2 -2
View File
@@ -89,13 +89,13 @@ test("GET /api/config 返回全部 profile、明文密钥与持久化激活项",
expect(res.json.enums.console_site).toEqual(["domestic", "international"]);
expect(res.json.booleanKeys).toContain("telemetry");
// Default field hints are surfaced as prefilled values in the UI.
expect(res.json.fieldDefaults.default_image_model).toBe("qwen-image-2.0");
expect(res.json.fieldDefaults.default_image_model).toBe("qwen-image-3.0");
expect(res.json.fieldDefaults.default_text_model).toBe("qwen3.8-max");
expect(res.json.fieldDefaults.output_dir).toContain("bailian-output");
expect(res.json.fieldDefaults.timeout).toBe("300");
expect(res.json.fieldDefaults.base_url).toBe("https://dashscope.aliyuncs.com");
// Per-category model catalog (click-to-fill suggestions) is exposed too.
expect(res.json.modelCatalog.default_image_model[0]).toMatchObject({ id: "qwen-image-2.0" });
expect(res.json.modelCatalog.default_image_model[0]).toMatchObject({ id: "qwen-image-3.0" });
expect(res.json.modelCatalog.default_video_model.map((m: { id: string }) => m.id)).toContain(
"happyhorse-1.1-i2v",
);
@@ -194,13 +194,13 @@ describe.skipIf(!isBailianE2EMediaEnabled() || !isDashScopeE2EReady())("e2e: ima
expect(stderr).toMatch(/--prompt|Usage:/i);
});
test("【qwen-image-2.0】图片编辑", async () => {
test("【qwen-image-3.0】图片编辑", async () => {
const outDir = makeE2eOutputDir(e2eLabelFromMetaUrl(import.meta.url));
const gen = await runCommandE2e(IMAGE_ROUTES, [
"image",
"generate",
"--model",
"qwen-image-2.0",
"qwen-image-3.0",
"--prompt",
"一只简笔画小猫,白底",
"--out-dir",
@@ -220,7 +220,7 @@ describe.skipIf(!isBailianE2EMediaEnabled() || !isDashScopeE2EReady())("e2e: ima
"image",
"edit",
"--model",
"qwen-image-2.0",
"qwen-image-3.0",
"--image",
imagePath!,
"--prompt",
@@ -202,19 +202,19 @@ describe.skipIf(!isBailianE2EMediaEnabled() || !isDashScopeE2EReady())(
"image",
"generate",
"--model",
"qwen-image-2.0",
"qwen-image-3.0",
]);
expect(exitCode).toBe(2);
expect(stderr).toMatch(/--prompt|Usage:/i);
});
test("【qwen-image-2.0】图片生成", async () => {
test("【qwen-image-3.0】图片生成", async () => {
const outDir = makeE2eOutputDir(e2eLabelFromMetaUrl(import.meta.url));
const { stdout, stderr, exitCode } = await runCommandE2e(IMAGE_ROUTES, [
"image",
"generate",
"--model",
"qwen-image-2.0",
"qwen-image-3.0",
"--prompt",
"一只简笔画小猫,白底",
"--out-dir",
@@ -159,7 +159,7 @@ describe.skipIf(!isBailianE2EVideoEnabled() || !isDashScopeE2EReady())(
"image",
"generate",
"--model",
"qwen-image-2.0",
"qwen-image-3.0",
"--prompt",
"一只简笔画小猫,白底",
"--out-dir",
@@ -169,7 +169,7 @@ describe.skipIf(!isBailianE2EVideoEnabled() || !isDashScopeE2EReady())(
"image",
"generate",
"--model",
"qwen-image-2.0",
"qwen-image-3.0",
"--prompt",
"一片绿色的树叶,白底",
"--out-dir",
+15 -3
View File
@@ -10,7 +10,7 @@ import { image2ImagePath, imagePath, imageSyncPath, imageText2ImagePath } from "
* - async text2image + prompt: wan2.5/2.2/2.1-t2i*, wanx*-t2i*
*
* Edit (I2I):
* - sync multimodal + messages(+images): qwen-image-2.0*, qwen-image-edit*, wan2.6-image*, wan2.7-image*
* - sync multimodal + messages(+images): qwen-image-3.0*, qwen-image-2.0*, qwen-image-edit*, wan2.6-image*, wan2.7-image*
* (pure T2I models such as z-image / qwen-image-plus / qwen-image-max are NOT edit models)
* - async image2image + prompt/images: wan2.5-i2i*
* - async image2image + function/base_image_url: *imageedit* (e.g. wanx2.1-imageedit)
@@ -60,6 +60,7 @@ const SYNC_GENERATE_PREFIXES = ["qwen-image", "wan2.7-image", "z-image"] as cons
* Pure T2I models (z-image / qwen-image-plus / qwen-image-max) are excluded.
*/
const SYNC_EDIT_PREFIXES = [
"qwen-image-3.0",
"qwen-image-2.0",
"qwen-image-edit",
"wan2.7-image",
@@ -109,7 +110,12 @@ export function isWanxFunctionImageEditModel(model: string): boolean {
}
export function resolveImageSizeProfile(model: string): ImageSizeProfile {
if (model.startsWith("qwen-image-2.0") || model.startsWith("qwen-image-edit")) {
// 3.0 暂复用 2.0 高分比例表(CLI ratio→像素便捷映射);不做独立 3.0 profile。
if (
model.startsWith("qwen-image-3.0") ||
model.startsWith("qwen-image-2.0") ||
model.startsWith("qwen-image-edit")
) {
return "qwen-image-2.0";
}
// Remaining qwen-image* (plus / max / bare qwen-image) share the fixed table.
@@ -133,7 +139,13 @@ export function resolveImageSizeProfile(model: string): ImageSizeProfile {
/** Official / CLI defaults for prompt_extend when the flag is omitted. */
export function resolvePromptExtendDefault(model: string): boolean | undefined {
if (model.startsWith("qwen-image-2.0") || model.startsWith("qwen-image-max")) return true;
if (
model.startsWith("qwen-image-3.0") ||
model.startsWith("qwen-image-2.0") ||
model.startsWith("qwen-image-max")
) {
return true;
}
// Z-Image docs default prompt_extend to false.
if (model.startsWith("z-image")) return false;
return undefined;
+12
View File
@@ -11,6 +11,7 @@ import {
} from "../src/client/image-routes.ts";
test("sync multimodal family covers qwen-image, wan2.6/2.7 image, and z-image", () => {
expect(isSyncMultimodalImageModel("qwen-image-3.0")).toBe(true);
expect(isSyncMultimodalImageModel("qwen-image-2.0")).toBe(true);
expect(isSyncMultimodalImageModel("qwen-image-2.0-pro")).toBe(true);
expect(isSyncMultimodalImageModel("qwen-image-plus")).toBe(true);
@@ -41,6 +42,7 @@ test("legacy image2image is wan2.5-i2i only; wanx imageedit uses function protoc
});
test("size profiles are model-specific, not sync/async", () => {
expect(resolveImageSizeProfile("qwen-image-3.0")).toBe("qwen-image-2.0");
expect(resolveImageSizeProfile("qwen-image-2.0")).toBe("qwen-image-2.0");
expect(resolveImageSizeProfile("qwen-image")).toBe("qwen-image-fixed");
expect(resolveImageSizeProfile("qwen-image-plus")).toBe("qwen-image-fixed");
@@ -55,6 +57,7 @@ test("size profiles are model-specific, not sync/async", () => {
});
test("prompt_extend defaults follow model docs", () => {
expect(resolvePromptExtendDefault("qwen-image-3.0")).toBe(true);
expect(resolvePromptExtendDefault("qwen-image-2.0")).toBe(true);
expect(resolvePromptExtendDefault("qwen-image-max")).toBe(true);
expect(resolvePromptExtendDefault("z-image-turbo")).toBe(false);
@@ -85,6 +88,11 @@ test("resolveImageGenerateApi picks path, input style, and size profile", () =>
kind: "async-image-generation",
sizeProfile: "wan26",
});
expect(resolveImageGenerateApi("qwen-image-3.0")).toMatchObject({
kind: "sync-multimodal",
sizeProfile: "qwen-image-2.0",
promptExtendDefault: true,
});
expect(resolveImageGenerateApi("qwen-image-2.0")).toMatchObject({
kind: "sync-multimodal",
sizeProfile: "qwen-image-2.0",
@@ -115,6 +123,10 @@ test("resolveImageEditApi excludes pure T2I models from sync edit", () => {
kind: "sync-multimodal",
useSync: true,
});
expect(resolveImageEditApi("qwen-image-3.0")).toMatchObject({
kind: "sync-multimodal",
useSync: true,
});
expect(resolveImageEditApi("qwen-image-2.0")).toMatchObject({
kind: "sync-multimodal",
useSync: true,
@@ -171,7 +171,7 @@ export async function imageGenerate(
});
}
const model = input.model || "qwen-image-2.0";
const model = input.model || "qwen-image-3.0";
const route = resolveImageGenerateApi(model);
const n = input.n ?? 1;
@@ -269,7 +269,7 @@ export async function imageEdit(
}
const images = Array.isArray(input.image) ? input.image : input.image ? [input.image] : [];
const model = input.model || "qwen-image-2.0";
const model = input.model || "qwen-image-3.0";
const route = resolveImageEditApi(model);
const n = input.n ?? 1;
+1 -1
View File
@@ -8,7 +8,7 @@ import type { ImageSizeProfile } from "bailian-cli-core";
* Do not infer size from sync/async — that mismatches model constraints.
*/
/** qwen-image-2.0 / qwen-image-edit recommended high-res presets. */
/** qwen-image-2.0 / qwen-image-edit recommended high-res presets(3.0 经 profile 复用此表). */
export const QWEN_IMAGE_20_RATIO_MAP: Record<string, string> = {
"16:9": "2688*1536",
"9:16": "1536*2688",