import hashlib import json import time import uuid from typing import Optional import httpx from config import APP_ID, TOKEN TOKEN_URL = "https://openaiapi.weixin.qq.com/v2/token" def _md5_hex(data: str) -> str: return hashlib.md5(data.encode("utf-8")).hexdigest() async def fetch_access_token(account: Optional[str] = None) -> str: """ 调用微信智能对话 /v2/token 接口,换取 AccessToken。 文档参考:https://developers.weixin.qq.com/doc/aispeech/confapi/dialog/token.html """ timestamp = int(time.time()) nonce = uuid.uuid4().hex[:16] body_obj = {} if account: body_obj["account"] = account body_str = json.dumps(body_obj, separators=(",", ":"), ensure_ascii=False) # sign = md5(Token + str(unix_timestamp) + nonce + md5(body)) body_md5 = _md5_hex(body_str) if body_str else _md5_hex("") sign_src = f"{TOKEN}{timestamp}{nonce}{body_md5}" sign = _md5_hex(sign_src) headers = { "X-APPID": APP_ID, "request_id": str(uuid.uuid4()), "timestamp": str(timestamp), "nonce": nonce, "sign": sign, "content-type": "application/json", } async with httpx.AsyncClient(timeout=5) as client: resp = await client.post(TOKEN_URL, headers=headers, content=body_str.encode("utf-8")) resp.raise_for_status() data = resp.json() if data.get("code") != 0: raise RuntimeError(f"fetch_access_token error: {data}") return data["data"]["access_token"]