← Back to Skills Marketplace
zheyanyan

Feishu Voice Sender (ZheYanyan)

by ZheYanyan · GitHub ↗ · v1.0.0 · MIT-0
cross-platform ⚠ suspicious
72
Downloads
0
Stars
0
Active Installs
1
Versions
Install in OpenClaw
/install feishu-voice-sender-zhe
Description
飞书语音/音频发送器 — 通过飞书 OpenAPI 发送音频文件,支持语音消息直接播放。| Feishu Voice/Audio Sender — Send audio files via Feishu OpenAPI for inline voice message playback.
README (SKILL.md)

Feishu Voice Sender | 飞书语音发送器

发送音频文件到飞书聊天中,以语音消息形式展示(可直接点击播放)。

Send audio files to Feishu chat as voice messages (click to play inline).

核心发现 | Key Discovery

飞书语音消息需要:

  1. 上传时使用 file_type=opus
  2. 发送时使用 msg_type=audio

其他文件类型(mp3/stream)会以文件形式发送,需要下载才能播放。

Feishu voice messages require:

  1. Upload with file_type=opus
  2. Send with msg_type=audio

Other file types (mp3/stream) are sent as files requiring download.

快速开始 | Quick Start

# 发送语音消息(自动识别 .mp3/.m4a/.wav 等格式)
python3 scripts/feishu_voice_sender.py --file /path/to/audio.mp3

# 指定接收者
python3 scripts/feishu_voice_sender.py --file /path/to/audio.mp3 --receive-id ou_xxx

脚本 | Script

#!/usr/bin/env python3
"""
Feishu Voice Sender - 发送语音/音频到飞书作为语音消息
"""
import argparse
import json
import os
import subprocess
import sys
import urllib.request
import urllib.error

def get_tenant_token(app_id: str, app_secret: str) -> str:
    """获取 tenant access token"""
    url = "https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal"
    data = json.dumps({"app_id": app_id, "app_secret": app_secret}).encode()
    req = urllib.request.Request(url, data=data, headers={"Content-Type": "application/json"})
    try:
        with urllib.request.urlopen(req, timeout=10) as resp:
            result = json.loads(resp.read())
            if result.get("code") == 0:
                return result["tenant_access_token"]
            raise Exception(f"获取token失败: {result.get('msg')}")
    except urllib.error.URLError as e:
        raise Exception(f"网络错误: {e}")

def upload_file(token: str, file_path: str) -> str:
    """上传文件,返回 file_key"""
    filename = os.path.basename(file_path)
    url = "https://open.feishu.cn/open-apis/im/v1/files"
    
    boundary = "----FeishuBoundary"
    with open(file_path, "rb") as f:
        content = f.read()
    
    body = (
        f"--{boundary}\r\
"
        f'Content-Disposition: form-data; name="file_name"\r\
\r\
'
        f"{filename}\r\
"
        f"--{boundary}\r\
"
        f'Content-Disposition: form-data; name="file_type"\r\
\r\
'
        f"opus\r\
"
        f"--{boundary}\r\
"
        f'Content-Disposition: form-data; name="file"; filename="{filename}"\r\
'
        f"Content-Type: audio/mpeg\r\
\r\
"
    ).encode() + content + f"\r\
--{boundary}--\r\
".encode()
    
    req = urllib.request.Request(
        url,
        data=body,
        headers={
            "Authorization": f"Bearer {token}",
            "Content-Type": f"multipart/form-data; boundary={boundary}"
        }
    )
    try:
        with urllib.request.urlopen(req, timeout=30) as resp:
            result = json.loads(resp.read())
            if result.get("code") == 0:
                return result["data"]["file_key"]
            raise Exception(f"上传失败: {result.get('msg')}")
    except urllib.error.URLError as e:
        raise Exception(f"上传失败: {e}")

def send_audio_message(token: str, receive_id: str, file_key: str) -> str:
    """发送音频消息"""
    url = f"https://open.feishu.cn/open-apis/im/v1/messages?receive_id_type=open_id"
    payload = {
        "receive_id": receive_id,
        "msg_type": "audio",
        "content": json.dumps({"file_key": file_key})
    }
    data = json.dumps(payload).encode()
    req = urllib.request.Request(
        url,
        data=data,
        headers={
            "Authorization": f"Bearer {token}",
            "Content-Type": "application/json"
        }
    )
    try:
        with urllib.request.urlopen(req, timeout=10) as resp:
            result = json.loads(resp.read())
            if result.get("code") == 0:
                return result["data"]["message_id"]
            raise Exception(f"发送失败: {result.get('msg')}")
    except urllib.error.URLError as e:
        raise Exception(f"发送失败: {e}")

def read_openclaw_config() -> dict:
    """读取 OpenClaw 飞书配置"""
    config_path = os.path.expanduser("~/.openclaw/openclaw.json")
    if not os.path.exists(config_path):
        raise Exception(f"配置文件不存在: {config_path}")
    
    with open(config_path) as f:
        config = json.load(f)
    
    feishu = config.get("channels", {}).get("feishu", {})
    if not feishu:
        raise Exception("未找到飞书配置")
    
    return {
        "app_id": feishu.get("appId"),
        "app_secret": feishu.get("appSecret")
    }

def get_receive_id_from_env() -> str:
    """从环境变量获取 receive_id"""
    return os.environ.get("OPENCLAW_CHAT_ID") or os.environ.get("FEISHU_CHAT_ID") or ""

def main():
    parser = argparse.ArgumentParser(description="发送语音消息到飞书")
    parser.add_argument("--file", "-f", required=True, help="音频文件路径")
    parser.add_argument("--receive-id", "-r", default=get_receive_id_from_env(), help="接收者 open_id")
    args = parser.parse_args()
    
    if not args.receive_id:
        print("错误: 请指定 --receive-id 或设置 OPENCLAW_CHAT_ID 环境变量", file=sys.stderr)
        sys.exit(1)
    
    if not os.path.exists(args.file):
        print(f"错误: 文件不存在: {args.file}", file=sys.stderr)
        sys.exit(1)
    
    print(f"读取飞书配置...")
    feishu_config = read_openclaw_config()
    
    print(f"获取访问令牌...")
    token = get_tenant_token(feishu_config["app_id"], feishu_config["app_secret"])
    
    print(f"上传音频文件: {args.file}")
    file_key = upload_file(token, args.file)
    
    print(f"发送语音消息...")
    message_id = send_audio_message(token, args.receive_id, file_key)
    
    print(f"成功! message_id: {message_id}")

if __name__ == "__main__":
    main()
Usage Guidance
This skill's behavior (sending audio to Feishu) matches its description, but it silently reads ~/.openclaw/openclaw.json to obtain app_id and app_secret and also accepts OPENCLAW_CHAT_ID / FEISHU_CHAT_ID from the environment — neither of which is declared in the metadata. Before installing or running: (1) inspect ~/.openclaw/openclaw.json to confirm it only contains credentials you expect and are willing to use with this skill; (2) prefer creating a Feishu test app with limited permissions rather than reusing high-privilege credentials; (3) be aware curl is listed as required though the script does not use it (metadata probably inaccurate); (4) run the script in a restricted environment or review the code to ensure endpoints are legitimate (they are standard open.feishu.cn endpoints); and (5) if you need stricter assurance, ask the publisher for corrected metadata that declares the config path and env vars or modify the script to accept credentials explicitly via CLI/env vars so access is transparent.
Capability Analysis
Type: OpenClaw Skill Name: feishu-voice-sender-zhe Version: 1.0.0 The skill is a legitimate utility designed to send audio files to Feishu as playable voice messages. It reads the user's Feishu credentials from the local OpenClaw configuration file (~/.openclaw/openclaw.json) and communicates exclusively with official Feishu API endpoints (open.feishu.cn) for authentication, file uploading, and message delivery. The code in scripts/feishu_voice_sender.py is transparent, well-documented, and contains no evidence of data exfiltration, malicious execution, or prompt injection.
Capability Tags
requires-oauth-tokenrequires-sensitive-credentials
Capability Assessment
Purpose & Capability
The code and SKILL.md implement sending audio via Feishu OpenAPI (upload file_type=opus, send msg_type=audio), which matches the skill description. However the declared requirements are slightly inconsistent: the skill metadata lists curl as a required binary though the included Python script does not use curl, and the manifest claims no required config paths while the script reads ~/.openclaw/openclaw.json for appId/appSecret.
Instruction Scope
The runtime instructions (and embedded script) instruct the agent to read a local file (~/.openclaw/openclaw.json) to obtain Feishu app_id and app_secret and to use environment variables OPENCLAW_CHAT_ID or FEISHU_CHAT_ID for receive_id. Those file and environment accesses are not declared in requires.env or config paths in the skill metadata, meaning the skill will access local credentials unexpectedly.
Install Mechanism
No install spec is provided (instruction-only plus a script). No external archives or downloads are executed by the installer; risk from install mechanism is low. The included Python script will be executed by the user/agent when invoked.
Credentials
The script needs the Feishu app_id/app_secret (sensitive credentials) to obtain a tenant token and upload files. Those credentials are read from a local OpenClaw config file rather than from declared required env vars or primaryEnv. The skill also relies on environment variables OPENCLAW_CHAT_ID or FEISHU_CHAT_ID but does not declare them. Accessing local secrets without explicitly declaring them is disproportionate to what the metadata communicates and may surprise users.
Persistence & Privilege
The skill does not request persistent 'always' inclusion and does not modify other skills or system-wide configuration. It runs only when invoked and uses the provided script to perform network calls to Feishu endpoints.
How to Use
  1. Make sure OpenClaw is installed (local or Docker)
  2. Run the install command in chat: /install feishu-voice-sender-zhe
  3. After installation, invoke the skill by name or use /feishu-voice-sender-zhe
  4. Provide required inputs per the skill's parameter spec and get structured output
Version History
v1.0.0
Initial release
Metadata
Slug feishu-voice-sender-zhe
Version 1.0.0
License MIT-0
All-time Installs 0
Active Installs 0
Total Versions 1
Frequently Asked Questions

What is Feishu Voice Sender (ZheYanyan)?

飞书语音/音频发送器 — 通过飞书 OpenAPI 发送音频文件,支持语音消息直接播放。| Feishu Voice/Audio Sender — Send audio files via Feishu OpenAPI for inline voice message playback. It is an AI Agent Skill for Claude Code / OpenClaw, with 72 downloads so far.

How do I install Feishu Voice Sender (ZheYanyan)?

Run "/install feishu-voice-sender-zhe" in the OpenClaw or Claude Code chat to install it in one step — no extra setup required.

Is Feishu Voice Sender (ZheYanyan) free?

Yes, Feishu Voice Sender (ZheYanyan) is completely free, licensed under MIT-0. You can download, install and use it at no cost.

Which platforms does Feishu Voice Sender (ZheYanyan) support?

Feishu Voice Sender (ZheYanyan) is cross-platform and runs anywhere OpenClaw / Claude Code is available (cross-platform).

Who created Feishu Voice Sender (ZheYanyan)?

It is built and maintained by ZheYanyan (@zheyanyan); the current version is v1.0.0.

💬 Comments