"""Probe DashScope / 通义千问 connectivity and latency.""" from __future__ import annotations import base64 import os import socket import ssl import sys import time from pathlib import Path import httpx ROOT = Path(__file__).resolve().parents[1] def load_env() -> None: for envp in (ROOT / ".env", ROOT / "ai-service" / ".env"): if not envp.exists(): continue for line in envp.read_text(encoding="utf-8", errors="replace").splitlines(): line = line.strip() if not line or line.startswith("#") or "=" not in line: continue k, v = line.split("=", 1) k, v = k.strip(), v.strip().strip('"').strip("'") if k and k not in os.environ: os.environ[k] = v def post(base: str, key: str, payload: dict, timeout: float, label: str) -> tuple[float, int | None]: t0 = time.time() try: with httpx.Client(timeout=timeout) as c: r = c.post( f"{base}/chat/completions", headers={"Authorization": f"Bearer {key}", "Content-Type": "application/json"}, json=payload, ) dt = time.time() - t0 print(f"[{label}] status={r.status_code} time={dt:.1f}s bytes_in={len(r.content)}") if r.status_code >= 400: print(f"[{label}] body {r.text[:500].replace(chr(10), ' ')}") else: j = r.json() txt = j["choices"][0]["message"]["content"] if isinstance(txt, list): txt = "".join((x.get("text") if isinstance(x, dict) else str(x)) for x in txt) print(f"[{label}] ok content_len={len(str(txt))} preview={str(txt)[:100]!r}") return dt, r.status_code except Exception as e: dt = time.time() - t0 print(f"[{label}] FAIL after {dt:.1f}s: {type(e).__name__}: {e}") return dt, None def main() -> int: load_env() key = (os.getenv("DASHSCOPE_API_KEY") or "").strip() base = (os.getenv("DASHSCOPE_BASE_URL") or "https://dashscope.aliyuncs.com/compatible-mode/v1").rstrip("/") model = (os.getenv("VISION_MODEL") or "qwen3.6-plus").strip() print(f"base={base}") print(f"model={model}") print(f"key_set={bool(key)} key_len={len(key)}") if not key: print("NO DASHSCOPE_API_KEY") return 1 host = "dashscope.aliyuncs.com" t0 = time.time() try: ips = socket.getaddrinfo(host, 443, type=socket.SOCK_STREAM) print(f"DNS ok {time.time() - t0:.2f}s -> {sorted({x[4][0] for x in ips})[:4]}") except Exception as e: print(f"DNS FAIL {type(e).__name__}: {e}") t0 = time.time() try: ctx = ssl.create_default_context() with socket.create_connection((host, 443), timeout=10) as sock: with ctx.wrap_socket(sock, server_hostname=host) as ssock: print(f"TLS ok {time.time() - t0:.2f}s protocol={ssock.version()}") except Exception as e: print(f"TLS FAIL {type(e).__name__}: {e}") # 1) text-only post( base, key, { "model": model, "temperature": 0, "messages": [{"role": "user", "content": "只回复:通义可达"}], "max_tokens": 32, }, 30.0, "text-only", ) # 2) tiny image png_b64 = ( "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8BQDwAEhQGAhKmMIQAAAABJRU5ErkJggg==" ) post( base, key, { "model": model, "temperature": 0, "messages": [ { "role": "user", "content": [ {"type": "text", "text": "这张图是什么颜色?一句话。"}, {"type": "image_url", "image_url": {"url": f"data:image/png;base64,{png_b64}"}}, ], } ], "max_tokens": 64, }, 60.0, "tiny-image", ) # 3) real refs refs = list((ROOT / "test" / "refs").glob("*.png"))[:2] if not refs: refs = list((ROOT / "test").rglob("board_*.png"))[:2] print("refs", [f"{p.name}:{p.stat().st_size}" for p in refs]) if refs: content: list[dict] = [{"type": "text", "text": "用一句话描述这些界面截图里最显眼的标题。"}] total = 0 for p in refs: raw = p.read_bytes() total += len(raw) b64 = base64.b64encode(raw).decode("ascii") content.append({"type": "image_url", "image_url": {"url": f"data:image/png;base64,{b64}"}}) print(f"ref payload images_bytes={total} b64_approx={total * 4 // 3}") post( base, key, { "model": model, "temperature": 0, "messages": [{"role": "user", "content": content}], "max_tokens": 128, }, 150.0, "real-refs", ) # long prompt + 2 images like fidelity scoring (heavier) long_text = ("请逐区对照并打分。" + "区" * 800)[:2000] content2 = [{"type": "text", "text": long_text}] + content[1:] post( base, key, { "model": model, "temperature": 0, "messages": [{"role": "user", "content": content2}], "max_tokens": 512, }, 150.0, "fidelity-like", ) # 4) alternate model text if model != "qwen-vl-plus": post( base, key, { "model": "qwen-vl-plus", "temperature": 0, "messages": [{"role": "user", "content": "只回复:vl-plus可达"}], "max_tokens": 32, }, 30.0, "alt-qwen-vl-plus-text", ) return 0 if __name__ == "__main__": raise SystemExit(main())