← 返回 Skills 市场
zheyanyan

Feishu Voice Sender (ZheYanyan)

作者 ZheYanyan · GitHub ↗ · v1.0.0 · MIT-0
cross-platform ⚠ suspicious
72
总下载
0
收藏
0
当前安装
1
版本数
在 OpenClaw 中安装
/install feishu-voice-sender-zhe
功能描述
飞书语音/音频发送器 — 通过飞书 OpenAPI 发送音频文件,支持语音消息直接播放。| Feishu Voice/Audio Sender — Send audio files via Feishu OpenAPI for inline voice message playback.
使用说明 (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()
安全使用建议
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.
功能分析
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.
能力标签
requires-oauth-tokenrequires-sensitive-credentials
能力评估
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.
如何使用
  1. 确保已安装 OpenClaw(本地或 Docker 部署)
  2. 在对话框中输入安装命令:/install feishu-voice-sender-zhe
  3. 安装完成后,直接呼叫该 Skill 的名称或使用 /feishu-voice-sender-zhe 触发
  4. 根据 Skill 的参数说明提供必要输入,即可获得结构化输出
版本历史
v1.0.0
Initial release
元数据
Slug feishu-voice-sender-zhe
版本 1.0.0
许可证 MIT-0
累计安装 0
当前安装数 0
历史版本数 1
常见问题

Feishu Voice Sender (ZheYanyan) 是什么?

飞书语音/音频发送器 — 通过飞书 OpenAPI 发送音频文件,支持语音消息直接播放。| Feishu Voice/Audio Sender — Send audio files via Feishu OpenAPI for inline voice message playback. 它是一个面向 Claude Code / OpenClaw 的 AI Agent Skill 插件,目前累计下载 72 次。

如何安装 Feishu Voice Sender (ZheYanyan)?

在 OpenClaw 或 Claude Code 对话框中运行命令「/install feishu-voice-sender-zhe」即可一键安装,无需额外配置。

Feishu Voice Sender (ZheYanyan) 是免费的吗?

是的,Feishu Voice Sender (ZheYanyan) 完全免费,采用 MIT-0 许可证,可自由下载、安装和使用。

Feishu Voice Sender (ZheYanyan) 支持哪些平台?

Feishu Voice Sender (ZheYanyan) 跨平台运行,可在任意部署了 OpenClaw / Claude Code 的环境中使用(cross-platform)。

谁开发了 Feishu Voice Sender (ZheYanyan)?

由 ZheYanyan(@zheyanyan)开发并维护,当前版本 v1.0.0。

💬 留言讨论