import logging import httpx logger = logging.getLogger(__name__) MENU_CREATE_URL = "https://m.api.weibo.com/2/messages/menu/create.json" MENU_SHOW_URL = "https://m.api.weibo.com/2/messages/menu/show.json" MENU_DELETE_URL = "https://m.api.weibo.com/2/messages/menu/delete.json" class WeiboMenu: def __init__(self, gateway=None): self._gateway = gateway self._http: httpx.AsyncClient | None = None async def create(self, menus: list[dict]) -> bool: """ 创建自定义菜单。 menus 格式示例: [ { "name": "产品中心", "sub_button": [ {"type": "click", "name": "产品A", "key": "product_a"}, {"type": "view", "name": "官网", "url": "https://example.com"}, ] }, {"type": "click", "name": "联系客服", "key": "contact"}, ] 限制: - 一级菜单 1~3 个 - 二级菜单 1~5 个 - type 支持 click / view """ if self._http is None: self._http = httpx.AsyncClient(timeout=15.0) token = self._gateway.access_token if self._gateway else None if not token: logger.error("No access_token for menu create") return False body = {"menus": menus} try: resp = await self._http.post( MENU_CREATE_URL, params={"access_token": token}, json=body, ) data = resp.json() if data.get("error_code"): logger.error("Menu create failed: %s", data) return False logger.info("Menu created successfully") return True except Exception: logger.exception("Menu create error") return False async def show(self) -> dict | None: """查询当前菜单配置""" if self._http is None: self._http = httpx.AsyncClient(timeout=15.0) token = self._gateway.access_token if self._gateway else None if not token: return None try: resp = await self._http.get( MENU_SHOW_URL, params={"access_token": token}, ) return resp.json() except Exception: logger.exception("Menu show error") return None async def delete(self) -> bool: """删除当前菜单""" if self._http is None: self._http = httpx.AsyncClient(timeout=15.0) token = self._gateway.access_token if self._gateway else None if not token: return False try: resp = await self._http.post( MENU_DELETE_URL, params={"access_token": token}, ) data = resp.json() return "error_code" not in data except Exception: logger.exception("Menu delete error") return False async def close(self): if self._http: await self._http.aclose() self._http = None