# -*- coding: utf-8 -*- """ open_api_controller.py 接口调用示例 ==================================================================== 对应文件:app/controllers/open_api_controller.py 路由前缀:/api/open/v1 鉴权方式:请求头 X-API-Key: {secret_key}(也支持 URL 参数 secret_key=xxx) 统一响应结构(controller.jsonify_resp): {"code": int, "msg": str, "data": any} 业务错误码(open_api_controller 统一约定): 1 成功 0 业务失败 400 参数错误 401 认证失败(API Key 无效或缺失) 403 无权限访问该资源 404 资源未找到(WABA 或手机号不存在) 运行方式: python open_api_demo.py # 运行全部 demo python open_api_demo.py text # 只运行指定 demo(见文件末尾 DEMOS) python open_api_demo.py --list # 列出所有 demo 名称 依赖:pip install requests """ import json import sys import requests # ==================== 全局配置(按需修改) ==================== # 服务地址(不带结尾斜杠) BASE_URL = "http://127.0.0.1:5000" # 团队开放 API 密钥(team_three_api.secret_key) API_KEY = "your-secret-key" # 常用示例参数 WABA_ID = "123456789012345" # WABA 账户ID PHONE_NUMBER_ID = "123456789012345" # 电话号码ID(phone_number_id) TEMPLATE_ID = "123456789012345" # 模板ID(template_id) TEMPLATE_NAME = "hello_world" # 模板名称 TO_PHONE = "8613800138000" # 接收方号码(不带 + 也可) MEDIA_ID = "123456789012345" # 媒体ID CODE = "AQBxxxxxxxx" # 嵌入式注册授权码 # 请求超时(秒) TIMEOUT = 30 # ==================== 通用请求封装 ==================== def _headers(extra=None): """构造请求头,自动带上 X-API-Key 鉴权""" h = {"X-API-Key": API_KEY} if extra: h.update(extra) return h def _print_resp(resp, binary=False): """打印响应(binary=True 时不打印内容,只打印状态与大小)""" print("-" * 60) print(f"HTTP {resp.status_code}") if binary: print(f"Content-Type: {resp.headers.get('Content-Type')}") print(f"Content-Length: {resp.headers.get('Content-Length')}") print(f"body bytes: {len(resp.content)}") return try: print(json.dumps(resp.json(), ensure_ascii=False, indent=2)) except ValueError: print(resp.text) def call_api(method, path, *, params=None, json_body=None, data=None, files=None, binary=False, extra_headers=None): """ 统一发起请求。 :param method: HTTP 方法(GET/POST) :param path: 接口路径,如 /api/open/v1/whatsapp/messages :param params: URL 查询参数(GET 常用) :param json_body: JSON 请求体(自动设置 Content-Type: application/json) :param data: 表单字段(multipart/form-data 时与 files 搭配) :param files: 上传文件,形如 {'file': (filename, fileobj, mime)} :param binary: 响应是否为二进制流(下载媒体时用) :param extra_headers: 额外请求头 """ url = f"{BASE_URL}{path}" print("=" * 60) print(f"{method} {url}") if params: print(f"query: {json.dumps(params, ensure_ascii=False)}") if json_body is not None: print(f"body : {json.dumps(json_body, ensure_ascii=False)}") resp = requests.request( method, url, params=params, json=json_body, data=data, files=files, headers=_headers(extra_headers), timeout=TIMEOUT, stream=binary, ) _print_resp(resp, binary=binary) return resp # ==================== 1. WABA 注册/绑定 ==================== def demo_authorize(): """ 注册/绑定 WABA 账户(三方调用) POST /api/open/v1/whatsapp/authorize 参数: waba_id 必填,WABA 账户ID phone_number_id 可选,电话号码ID code 可选,嵌入式注册授权码 coexistence 可选,是否共享(true/false) """ body = { "waba_id": WABA_ID, "phone_number_id": PHONE_NUMBER_ID, "code": CODE, "coexistence": False, } call_api("POST", "/api/open/v1/whatsapp/authorize", json_body=body) # ==================== 2. 手机号列表 ==================== def demo_phone_number_list(): """ 获取 WhatsApp 手机号列表(分页) GET /api/open/v1/whatsapp/phoneNumbers 参数: wabaId 必填,WABA 账户ID page 可选,页码,默认 1 limit 可选,每页数量,默认 10 fields 可选,逗号分隔的返回字段,默认返回 _PHONE_DEFAULT_FIELDS """ query = { "wabaId": WABA_ID, "page": 1, "limit": 10, # 可选字段示例(不传则用默认字段集) "fields": "id,display_phone_number,verified_name,status,quality_rating", } call_api("GET", "/api/open/v1/whatsapp/phoneNumbers", params=query) # ==================== 3. 创建电话号码 ==================== def demo_create_phone_number(): """ 在 WABA 下创建新的电话号码注册 POST /api/open/v1/whatsapp/phoneNumbers/register 参数: waba_id 必填,WABA 账户ID phone_number 必填,电话号码 verified_name 必填,已验证的名称 cc 必填,国家代码(如 86) migrate_phone_number 可选,是否迁移号码,默认 False """ body = { "waba_id": WABA_ID, "phone_number": "8613800138000", "verified_name": "My Business", "cc": "86", "migrate_phone_number": False, } call_api("POST", "/api/open/v1/whatsapp/phoneNumbers/register", json_body=body) # ==================== 4. 请求验证码 ==================== def demo_request_verification_code(): """ 请求电话号码验证码 POST /api/open/v1/whatsapp/phoneNumbers/requestCode 参数: phone_number_id 必填,电话号码ID code_method 可选,SMS|VOICE,默认 SMS language 可选,语言,默认 en """ body = { "phone_number_id": PHONE_NUMBER_ID, "code_method": "SMS", "language": "en_US", } call_api("POST", "/api/open/v1/whatsapp/phoneNumbers/requestCode", json_body=body) # ==================== 5. 注册/验证电话号码 ==================== def demo_register_phone_number(): """ 注册/验证电话号码(通过 PIN 码) POST /api/open/v1/whatsapp/phoneNumbers/registerPin 参数: phone_number_id 必填,电话号码ID pin 必填,6位PIN码 """ body = { "phone_number_id": PHONE_NUMBER_ID, "pin": "123456", } call_api("POST", "/api/open/v1/whatsapp/phoneNumbers/registerPin", json_body=body) # ==================== 6. WABA 信息 ==================== def demo_waba_info(): """ 获取 WABA 账户信息(传 waba_id 查单个,不传查全部) GET /api/open/v1/whatsapp/wabaInfo 参数: waba_id 可选,WABA 账户ID(不传则返回该团队全部 WABA) """ # 查单个 call_api("GET", "/api/open/v1/whatsapp/wabaInfo", params={"waba_id": WABA_ID}) # 查全部(注释掉可单独测试) # call_api("GET", "/api/open/v1/whatsapp/wabaInfo") # ==================== 7. 模板列表 ==================== def demo_template_list(): """ 获取 WhatsApp 消息模板列表(分页,支持按 template_id 查单个) GET /api/open/v1/whatsapp/templates 参数: waba_id 必填,WABA 账户ID template_id 可选,模板ID(传则只查该模板) page 可选,页码,默认 1 limit 可选,每页数量,默认 10 fields 可选,逗号分隔的返回字段 """ query = { "waba_id": WABA_ID, "page": 1, "limit": 10, # 可选字段示例 "fields": "id,name,status,category,language,components", } call_api("GET", "/api/open/v1/whatsapp/templates", params=query) # ==================== 8. 创建模板 ==================== def demo_create_template(): """ 创建消息模板 POST /api/open/v1/whatsapp/templates/create 参数: waba_id 必填,WABA 账户ID name 必填,模板名称(只能小写字母、数字、下划线) category 必填,MARKETING / UTILITY / AUTHENTICATION language 必填,语言代码 components 必填,模板组件列表(HEADER/BODY/FOOTER/BUTTONS) allow_category_change 可选,是否允许 Meta 更改类别(true/false) """ body = { "waba_id": WABA_ID, "name": "order_update_01", # 只能小写字母/数字/下划线 "category": "UTILITY", "language": "en_US", "allow_category_change": True, "components": [ { "type": "HEADER", "format": "TEXT", "text": "Order Update", "example": {"header_text": ["Order Update"]}, }, { "type": "BODY", "text": "Hi {{1}}, your order {{2}} has been shipped.", "example": {"body_text": [["John", "ORD-1001"]]}, }, { "type": "FOOTER", "text": "Thanks for shopping", }, { "type": "BUTTONS", "buttons": [ {"type": "QUICK_REPLY", "text": "Confirm"}, {"type": "URL", "text": "Track", "url": "https://example.com/track"}, {"type": "PHONE_NUMBER", "text": "Call us", "phone_number": "+15551234567"}, ], }, ], } call_api("POST", "/api/open/v1/whatsapp/templates/create", json_body=body) # ==================== 8.1 创建模板 - MARKETING(营销类) ==================== def demo_create_template_marketing(): """ 创建【营销类】消息模板(category=MARKETING) POST /api/open/v1/whatsapp/templates/create 特点:用于推广/促销/召回等营销场景,需用户主动订阅或已有会话。 常用组件: HEADER 支持 TEXT / IMAGE / VIDEO / DOCUMENT(IMAGE 等需带 example.header_handle) BODY 正文,支持 {{1}} 等变量 FOOTER 页脚(如退订提示) BUTTONS 支持 QUICK_REPLY / URL / PHONE_NUMBER / COPY_CODE 等 参数: waba_id 必填,WABA 账户ID name 必填,模板名称(只能小写字母、数字、下划线) category 必填,此处为 MARKETING language 必填,语言代码(如 en_US、zh_CN) components 必填,模板组件列表 allow_category_change 可选,是否允许 Meta 更改类别(true/false) """ body = { "waba_id": WABA_ID, "name": "marketing_promo_01", # 只能小写字母/数字/下划线 "category": "MARKETING", # 营销类 "language": "en_US", "allow_category_change": True, "components": [ { "type": "HEADER", "format": "TEXT", "text": "Limited Time Offer", "example": {"header_text": ["Limited Time Offer"]}, }, { "type": "BODY", "text": "Hi {{1}}, enjoy {{2}} off your next order. Offer ends {{3}}.", "example": {"body_text": [["John", "20%", "2026-09-30"]]}, }, { "type": "FOOTER", "text": "Reply STOP to unsubscribe", }, { "type": "BUTTONS", "buttons": [ {"type": "QUICK_REPLY", "text": "Shop Now"}, {"type": "URL", "text": "View Deal", "url": "https://example.com/deal"}, {"type": "PHONE_NUMBER", "text": "Call us", "phone_number": "+15551234567"}, ], }, ], } call_api("POST", "/api/open/v1/whatsapp/templates/create", json_body=body) # ==================== 8.2 创建模板 - UTILITY(效用类) ==================== def demo_create_template_utility(): """ 创建【效用类】消息模板(category=UTILITY) POST /api/open/v1/whatsapp/templates/create 特点:用于订单、账单、预约、验证等交易/服务通知(非营销)。 常用组件:HEADER / BODY / FOOTER / BUTTONS(URL 支持 {{1}} 变量需带 example) 参数: waba_id 必填,WABA 账户ID name 必填,模板名称(只能小写字母、数字、下划线) category 必填,此处为 UTILITY language 必填,语言代码 components 必填,模板组件列表 allow_category_change 可选,是否允许 Meta 更改类别(true/false) """ body = { "waba_id": WABA_ID, "name": "utility_order_update_01", # 只能小写字母/数字/下划线 "category": "UTILITY", # 效用类 "language": "en_US", "allow_category_change": True, "components": [ { "type": "HEADER", "format": "TEXT", "text": "Order Update", "example": {"header_text": ["Order Update"]}, }, { "type": "BODY", "text": "Hi {{1}}, your order {{2}} has been shipped and will arrive on {{3}}.", "example": {"body_text": [["John", "ORD-1001", "2026-09-15"]]}, }, { "type": "FOOTER", "text": "Thank you for shopping with us", }, { "type": "BUTTONS", "buttons": [ # URL 按钮含变量 {{1}} 时必须提供 example(按顺序对应变量) { "type": "URL", "text": "Track Order", "url": "https://example.com/track/{{1}}", "example": ["https://example.com/track/ORD-1001"], }, ], }, ], } call_api("POST", "/api/open/v1/whatsapp/templates/create", json_body=body) # ==================== 8.3 创建模板 - AUTHENTICATION(验证类) ==================== def demo_create_template_authentication(): """ 创建【验证类】消息模板(category=AUTHENTICATION) POST /api/open/v1/whatsapp/templates/create 特点:用于一次性验证码(OTP)场景,结构固定,与营销/效用模板不同: BODY 用 add_security_recommendation 自动附加安全提示(不放自定义文本/变量) FOOTER 用 code_expiration_minutes 设置验证码有效期(分钟) BUTTONS 必须为 OTP 按钮: otp_type = COPY_CODE(复制验证码)| ONE_TAP(一键填充,需 autofill_text 等) ZERO_TAP 需在 Meta 端配置,一般不通过 API 创建 参数: waba_id 必填,WABA 账户ID name 必填,模板名称(只能小写字母、数字、下划线) category 必填,此处为 AUTHENTICATION language 必填,语言代码 components 必填,模板组件列表(结构见下) allow_category_change 可选,是否允许 Meta 更改类别(true/false) """ body = { "waba_id": WABA_ID, "name": "authentication_code_01", # 只能小写字母/数字/下划线 "category": "AUTHENTICATION", # 验证类 "language": "en_US", "allow_category_change": False, "components": [ { "type": "BODY", "add_security_recommendation": True, # 自动追加「为安全起见,请勿分享此验证码」 }, { "type": "FOOTER", "code_expiration_minutes": 5, # 验证码有效期 5 分钟 }, { "type": "BUTTONS", "buttons": [ { "type": "OTP", "otp_type": "COPY_CODE", # 复制验证码 "text": "Copy code", }, # 一键填充示例(ONE_TAP,需配合 Meta 端配置): # { # "type": "OTP", # "otp_type": "ONE_TAP", # "text": "Autofill", # "autofill_text": "Autofill", # "package_name": "com.example.app", # "signature_hash": "xxxxxxxxxx", # }, ], }, ], } call_api("POST", "/api/open/v1/whatsapp/templates/create", json_body=body) # ==================== 9. 修改模板 ==================== def demo_update_template(): """ 修改消息模板 POST /api/open/v1/whatsapp/templates/update 参数: template_id 必填,模板ID name 可选,模板名称 category 可选,MARKETING / UTILITY / AUTHENTICATION language 可选,语言代码 components 可选,模板组件列表 allow_category_change 可选,是否允许 Meta 更改类别 """ body = { "template_id": TEMPLATE_ID, "name": "order_update_02", "category": "UTILITY", "language": "en_US", "allow_category_change": True, "components": [ { "type": "BODY", "text": "Hi {{1}}, your order {{2}} is on the way.", "example": {"body_text": [["John", "ORD-1002"]]}, }, ], } call_api("POST", "/api/open/v1/whatsapp/templates/update", json_body=body) # ==================== 10. 删除模板 ==================== def demo_delete_template(): """ 删除消息模板(template_name / hsm_id / hsm_ids 三选一) POST /api/open/v1/whatsapp/templates/delete 参数: waba_id 必填,WABA 账户ID template_name 可选,按名称删除 hsm_id 可选,按单个模板ID删除 hsm_ids 可选,按模板ID数组批量删除(最多 100 个) """ # 方式一:按名称删除 body = {"waba_id": WABA_ID, "template_name": TEMPLATE_NAME} call_api("POST", "/api/open/v1/whatsapp/templates/delete", json_body=body) # 方式二:按单个ID删除 # body = {"waba_id": WABA_ID, "hsm_id": TEMPLATE_ID} # call_api("POST", "/api/open/v1/whatsapp/templates/delete", json_body=body) # 方式三:批量删除 # body = {"waba_id": WABA_ID, "hsm_ids": ["id1", "id2"]} # call_api("POST", "/api/open/v1/whatsapp/templates/delete", json_body=body) # ==================== 11. 发送消息(按类型细分) ==================== def demo_send_text(): """ 发送文本消息 POST /api/open/v1/whatsapp/messages 公共参数: phone_number_id 必填,电话号码ID(本接口必带,用于取 WABA token) to 必填,接收方号码 type 必填,text recipient_type 可选,默认 individual 文本参数: text.body 必填,消息文本 text.preview_url 可选,链接预览,默认 False """ body = { "phone_number_id": PHONE_NUMBER_ID, "to": TO_PHONE, "type": "text", "text": {"body": "Hello from Open API!", "preview_url": False}, } call_api("POST", "/api/open/v1/whatsapp/messages", json_body=body) def demo_send_image(): """ 发送图片消息 type=image 参数:image.link(图片URL)或 image.id(媒体ID);image.caption 可选 """ body = { "phone_number_id": PHONE_NUMBER_ID, "to": TO_PHONE, "type": "image", "image": {"link": "https://example.com/a.jpg", "caption": "示例图片"}, } call_api("POST", "/api/open/v1/whatsapp/messages", json_body=body) def demo_send_video(): """ 发送视频消息 type=video 参数:video.link 或 video.id;video.caption 可选 """ body = { "phone_number_id": PHONE_NUMBER_ID, "to": TO_PHONE, "type": "video", "video": {"link": "https://example.com/a.mp4", "caption": "示例视频"}, } call_api("POST", "/api/open/v1/whatsapp/messages", json_body=body) def demo_send_audio(): """ 发送音频消息 type=audio 参数:audio.link 或 audio.id """ body = { "phone_number_id": PHONE_NUMBER_ID, "to": TO_PHONE, "type": "audio", "audio": {"link": "https://example.com/a.mp3"}, } call_api("POST", "/api/open/v1/whatsapp/messages", json_body=body) def demo_send_document(): """ 发送文档消息 type=document 参数:document.link 或 document.id;document.filename、document.caption 可选 """ body = { "phone_number_id": PHONE_NUMBER_ID, "to": TO_PHONE, "type": "document", "document": { "link": "https://example.com/a.pdf", "filename": "invoice.pdf", "caption": "发票", }, } call_api("POST", "/api/open/v1/whatsapp/messages", json_body=body) def demo_send_sticker(): """ 发送贴纸消息 type=sticker 参数:sticker.link 或 sticker.id """ body = { "phone_number_id": PHONE_NUMBER_ID, "to": TO_PHONE, "type": "sticker", "sticker": {"link": "https://example.com/a.webp"}, } call_api("POST", "/api/open/v1/whatsapp/messages", json_body=body) def demo_send_location(): """ 发送位置消息 type=location 参数:location.longitude、location.latitude 必填;location.name、location.address 可选 """ body = { "phone_number_id": PHONE_NUMBER_ID, "to": TO_PHONE, "type": "location", "location": { "longitude": 116.397128, "latitude": 39.916527, "name": "Tiananmen", "address": "Beijing, China", }, } call_api("POST", "/api/open/v1/whatsapp/messages", json_body=body) def demo_send_contacts(): """ 发送联系人消息 type=contacts 参数:contacts[].name.formatted_name 必填;其余可选 """ body = { "phone_number_id": PHONE_NUMBER_ID, "to": TO_PHONE, "type": "contacts", "contacts": [ { "name": {"formatted_name": "John Doe", "first_name": "John", "last_name": "Doe"}, "birthday": "1990-01-01", "phones": [{"phone": "+15551234567", "type": "CELL", "wa_id": "15551234567"}], } ], } call_api("POST", "/api/open/v1/whatsapp/messages", json_body=body) def demo_send_interactive(): """ 发送交互消息(按钮/列表等) type=interactive 参数: interactive.type 必填,button|list|product|product_list|catalog_message|flow|... interactive.body.text 必填,正文 interactive.header.type 可选,text|image|video|document interactive.footer.text 可选,页脚 interactive.action 必填,按钮/列表动作 下面示例为 button(回复按钮) """ body = { "phone_number_id": PHONE_NUMBER_ID, "to": TO_PHONE, "type": "interactive", "interactive": { "type": "button", "header": {"type": "text", "text": "标题"}, "body": {"text": "请选择操作"}, "footer": {"text": "页脚文本"}, "action": { "buttons": [ {"type": "reply", "reply": {"id": "btn_yes", "title": "确认"}}, {"type": "reply", "reply": {"id": "btn_no", "title": "取消"}}, ] }, }, } call_api("POST", "/api/open/v1/whatsapp/messages", json_body=body) def demo_send_reaction(): """ 发送表情回应 type=reaction 参数:reaction.message_id 必填;reaction.emoji(不传则移除回应) """ body = { "phone_number_id": PHONE_NUMBER_ID, "to": TO_PHONE, "type": "reaction", "reaction": {"message_id": "wamid.xxxxxxxx", "emoji": "👍"}, } call_api("POST", "/api/open/v1/whatsapp/messages", json_body=body) def demo_send_template(): """ 发送模板消息 type=template 参数: template.name 必填,模板名称 template.language.code 必填,语言代码 template.language.policy 可选,deterministic template.components 可选,组件参数数组 注意:发送成功后会自动写入 whatsapp_send_template_user 记录并按需扣费 """ body = { "phone_number_id": PHONE_NUMBER_ID, "to": TO_PHONE, "type": "template", "template": { "name": TEMPLATE_NAME, "language": {"code": "en_US", "policy": "deterministic"}, "components": [ { "type": "body", "parameters": [ {"type": "text", "text": "John"}, {"type": "text", "text": "ORD-1001"}, ], } ], }, } call_api("POST", "/api/open/v1/whatsapp/messages", json_body=body) # ==================== 12. 上传媒体(返回 media_id) ==================== def demo_upload_media_by_url(): """ 上传媒体文件(URL 方式)→ 返回 media_id POST /api/open/v1/whatsapp/uploadMedia 参数: phone_number_id 必填,电话号码ID media_type 可选,MIME 类型(如 image/jpeg、video/mp4、audio/mpeg、application/pdf) url 必填(URL 方式),附件可访问地址 """ body = { "phone_number_id": PHONE_NUMBER_ID, "media_type": "image/jpeg", "url": "https://example.com/a.jpg", } call_api("POST", "/api/open/v1/whatsapp/uploadMedia", json_body=body) def demo_upload_media_by_file(): """ 上传媒体文件(本地文件流方式)→ 返回 media_id POST /api/open/v1/whatsapp/uploadMedia 请求方式:multipart/form-data phone_number_id 必填 media_type 可选 file 必填,本地文件 注意:图片上限 5MB、视频/音频 16MB、文档 100MB,webp 图片 500KB """ local_path = r"E:\path\to\your\image.jpg" with open(local_path, "rb") as f: files = {"file": ("image.jpg", f, "image/jpeg")} data = {"phone_number_id": PHONE_NUMBER_ID, "media_type": "image/jpeg"} call_api("POST", "/api/open/v1/whatsapp/uploadMedia", data=data, files=files) # ==================== 13. 上传素材句柄(返回 handle) ==================== def demo_upload_attachment(): """ 上传素材句柄(Meta Resumable Upload)→ 返回 handle POST /api/open/v1/whatsapp/uploadAttachment 请求方式:multipart/form-data waba_id 必填,WABA 账户ID(决定用哪个 WABA 的 token 转发) file 必填,本地文件 file_type 可选,MIME 类型 filename 可选,文件名(默认取文件自身文件名) 注意:Meta Resumable Upload 上限 500MB """ local_path = r"E:\path\to\your\document.pdf" with open(local_path, "rb") as f: files = {"file": ("document.pdf", f, "application/pdf")} data = {"waba_id": WABA_ID, "file_type": "application/pdf", "filename": "document.pdf"} call_api("POST", "/api/open/v1/whatsapp/uploadAttachment", data=data, files=files) # ==================== 14. 获取媒体内容(下载附件) ==================== def demo_get_media_content(): """ 通过 media_id 获取附件(直接返回二进制文件流,不落盘) POST /api/open/v1/whatsapp/getMediaContent 参数: phone_number_id 必填,电话号码ID(用于归属校验并取下载 token) media_id 必填,媒体ID 成功:返回二进制文件流(Content-Type 为真实 MIME) 失败:返回 JSON {'code': 0, 'msg': '...'} """ body = {"phone_number_id": PHONE_NUMBER_ID, "media_id": MEDIA_ID} resp = call_api("POST", "/api/open/v1/whatsapp/getMediaContent", json_body=body, binary=True) # 成功时保存到本地文件 if resp.status_code == 200 and resp.headers.get("Content-Type", "").startswith(("image/", "video/", "audio/", "application/")): with open("downloaded_media.bin", "wb") as f: f.write(resp.content) print("已保存到 downloaded_media.bin") # ==================== demo 注册表 & 入口 ==================== DEMOS = { # WABA / 账号 "authorize": demo_authorize, "phone_list": demo_phone_number_list, "create_phone": demo_create_phone_number, "request_code": demo_request_verification_code, "register_pin": demo_register_phone_number, "waba_info": demo_waba_info, # 模板 "template_list": demo_template_list, "create_template": demo_create_template, "create_template_marketing": demo_create_template_marketing, "create_template_utility": demo_create_template_utility, "create_template_authentication": demo_create_template_authentication, "update_template": demo_update_template, "delete_template": demo_delete_template, # 发送消息 "text": demo_send_text, "image": demo_send_image, "video": demo_send_video, "audio": demo_send_audio, "document": demo_send_document, "sticker": demo_send_sticker, "location": demo_send_location, "contacts": demo_send_contacts, "interactive": demo_send_interactive, "reaction": demo_send_reaction, "template": demo_send_template, # 媒体 "upload_media_url": demo_upload_media_by_url, "upload_media_file": demo_upload_media_by_file, "upload_attachment": demo_upload_attachment, "get_media": demo_get_media_content, } def main(): args = sys.argv[1:] if not args or args[0] in ("-h", "--help", "--list"): print("可用 demo:") for name, fn in DEMOS.items(): desc = (fn.__doc__ or "").strip().splitlines() print(f" {name:<20} {desc[0] if desc else ''}") print("\n用法:python open_api_demo.py [demo名 ...] 不传则运行全部") return names = list(DEMOS.keys()) if args[0] == "all" else args for name in names: fn = DEMOS.get(name) if not fn: print(f"[跳过] 未找到 demo:{name}") continue print(f"\n########## {name} ##########") try: fn() except Exception as e: print(f"[异常] {name}: {e}") if __name__ == "__main__": main()