"""Qwen VL 测试脚本(兼容模式)。 用例: 1) 纯文字:验证流式输出与 usage。 2) 图文:发送本地图片,验证多模态输入。 注意:硬编码测试密钥,仅限本地验证,勿用于生产。 """ from __future__ import annotations import asyncio import base64 from pathlib import Path from typing import Optional import httpx QWEN_BASE_URL = "https://dashscope.aliyuncs.com/compatible-mode/v1" QWEN_API_KEY = "sk-64af1343e67d46d7a902ef5bcf6817ad" QWEN_VL_MODEL = "qwen3-vl-plus" # 默认图片路径(仓库根目录下“截图/截屏2025-12-12 17.30.04.png”) DEFAULT_IMAGE_PATH = Path("截图/截屏2025-12-12 17.30.04.png") def headers(api_key: str) -> dict[str, str]: return { "Authorization": f"Bearer {api_key}", "Content-Type": "application/json", } def build_image_content(image_path: Path) -> str: data = image_path.read_bytes() b64 = base64.b64encode(data).decode("ascii") return f"data:image/{image_path.suffix.lstrip('.').lower()};base64,{b64}" async def stream_call( *, name: str, base_url: str, api_key: str, model: str, messages, max_tokens: int, enable_thinking: bool = False, ) -> None: url = base_url.rstrip("/") + "/chat/completions" payload = { "model": model, "stream": True, "max_tokens": max_tokens, "messages": messages, "stream_options": {"include_usage": True}, } if enable_thinking: payload["enable_thinking"] = True print(f"\n=== {name} ===") print(f"POST {url}") async with httpx.AsyncClient(http2=True, timeout=180) as client: async with client.stream( "POST", url, json=payload, headers=headers(api_key) ) as resp: print("status:", resp.status_code) if resp.status_code != 200: body = await resp.aread() print("error body:", body.decode(errors="ignore")) return async for line in resp.aiter_lines(): if not line: continue if line.startswith("data:"): data = line[5:].strip() if data == "[DONE]": print("[DONE]") break print(data) else: print(line) async def main(image_path: Optional[Path] = None) -> None: # 1) 纯文字 text_messages = [ { "role": "user", "content": "请用一句话自我介绍,并简单说明你目前在执行的动作。", } ] await stream_call( name="qwen-vl text only", base_url=QWEN_BASE_URL, api_key=QWEN_API_KEY, model=QWEN_VL_MODEL, messages=text_messages, max_tokens=32000, # 官方上限 32K enable_thinking=True, ) # 2) 图文 img_path = image_path or DEFAULT_IMAGE_PATH if not img_path.exists(): print(f"\n[warn] 图片文件不存在: {img_path}") return img_url = build_image_content(img_path) multimodal_messages = [ { "role": "user", "content": [ {"type": "text", "text": "请描述这张图片的主要内容,并给出一句话总结。"}, {"type": "image_url", "image_url": {"url": img_url}}, ], } ] await stream_call( name="qwen-vl image+text", base_url=QWEN_BASE_URL, api_key=QWEN_API_KEY, model=QWEN_VL_MODEL, messages=multimodal_messages, max_tokens=32000, # 官方上限 32K enable_thinking=True, ) if __name__ == "__main__": asyncio.run(main())