Ezviz Audio Broadcast (萤石语音广播) 通过萤石语音上传和下发接口,实现语音内容到设备的广播播放。 --- ⚠️ 安全警告 (安装前必读) 在使用此技能前,请完成以下安全检查: | # | 检查项 | 状态 | 说明 | |---|--------|------|------| | 1 | 凭证权限 | ⚠️ 必需 | 使用 最小权限 的 AppKey/AppSecret,不要用主账号凭证 | | 2 | 配置文件读取 | ⚠️ 注意 | 技能会读取 文件( 但环境变量优先级更高 ) | | 3 | Token 缓存 | ⚠️ 注意 | Token 缓存在 (权限 600) | | 4 | 系统命令 | ⚠️ 注意 | 使用 / / 进行 TTS (通过 subprocess) | | 5 | API 域名 | ✅ 已验证 | 是萤石官方 API 端点( = Open API,不是 AI) | | 6 | 代码审查 | ✅ 推荐 | 审查 和 | 🔒 配置文件读取详细说明 凭证获取优先级 (从高到低): 安全建议 : - ✅ 最佳实践 : 使用环境变量,完全避免配置文件读取 - ✅ 隔离配置 : 在专用配置文件只存放萤石凭证,不混用其他服务 - ⚠️ 风险缓解 : 设置环境变量覆盖配置文件(即使配置文件存在也会被忽略) 快速安全配置 凭证优先级 技能按以下…

, serial):\n return False, \"Invalid device serial format. Only alphanumeric, colon, comma, underscore allowed.\"\n \n return True, None\n\n\ndef text_to_speech(text, output_path):\n \"\"\"Convert text to speech using system TTS (requires OpenClaw TTS capability)\"\"\"\n print(f\"[INFO] Converting text to speech: '{text[:50]}{'...' if len(text) > 50 else ''}'\")\n \n try:\n # Try to use system TTS first\n try:\n # On macOS, use say command with afconvert to generate WAV\n if sys.platform == \"darwin\":\n temp_aiff = output_path.replace('.wav', '.aiff').replace('.mp3', '.aiff')\n # Add pauses to make audio longer (Ezviz requires minimum audio length)\n # Say the text with natural pauses\n text_with_pauses = f\"注意,{text},请注意\"\n subprocess.run(['say', '-o', temp_aiff, text_with_pauses], check=True, capture_output=True)\n # Convert AIFF to WAV using correct format specifier\n subprocess.run(['afconvert', '-f', 'WAVE', '-d', 'LEI16@44100', temp_aiff, output_path], \n check=True, capture_output=True)\n os.remove(temp_aiff)\n elif sys.platform.startswith('linux'):\n # Use espeak + ffmpeg on Linux\n subprocess.run(['espeak', '-w', output_path.replace('.mp3', '.wav'), text], \n check=True, capture_output=True)\n subprocess.run(['ffmpeg', '-i', output_path.replace('.mp3', '.wav'), \n '-acodec', 'libmp3lame', output_path], \n check=True, capture_output=True)\n os.remove(output_path.replace('.mp3', '.wav'))\n else:\n # Fallback: create a minimal MP3 file (this won't work well, but indicates the approach)\n # In practice, this would need proper TTS integration\n print(\"[WARNING] System TTS not available. Creating placeholder file.\")\n with open(output_path, 'wb') as f:\n f.write(b'PLACEHOLDER') # This won't be valid MP3\n \n except (subprocess.CalledProcessError, FileNotFoundError):\n # If system TTS fails, try alternative approach\n print(\"[WARNING] System TTS failed. Using placeholder approach.\")\n # In a real implementation, this would call the actual TTS service\n # For now, we'll assume the user provides valid audio files\n raise Exception(\"TTS generation failed\")\n \n print(f\"[SUCCESS] Text converted to speech: {output_path}\")\n return True\n \n except Exception as e:\n print(f\"[ERROR] Failed to convert text to speech: {str(e)}\")\n return False\n\ndef get_access_token(app_key, app_secret, use_cache=True):\n \"\"\"Get access token from Ezviz API using global token manager\"\"\"\n print(\"=\" * 70)\n print(\"[Step 1] Getting access token...\")\n \n # Check EZVIZ_TOKEN_CACHE environment variable (0=disable cache, 1=enable cache)\n env_cache = os.getenv('EZVIZ_TOKEN_CACHE', '1')\n if env_cache == '0':\n use_cache = False\n \n # Use global token manager\n token_result = get_cached_token(app_key, app_secret, use_cache=use_cache)\n \n if token_result.get('success'):\n token = token_result['access_token']\n expire_time = datetime.fromtimestamp(token_result['expire_time'] / 1000)\n from_cache = token_result.get('from_cache', False)\n \n if from_cache:\n print(f\"[SUCCESS] Using cached token, expires: {expire_time.strftime('%Y-%m-%d %H:%M:%S')}\")\n else:\n print(f\"[SUCCESS] Token obtained, expires: {expire_time.strftime('%Y-%m-%d %H:%M:%S')}\")\n return token\n else:\n print(f\"[ERROR] Failed to get token: {token_result.get('error', 'Unknown error')}\")\n return None\n\ndef upload_audio_file(access_token, audio_file_path, voice_name=None, force=False):\n \"\"\"Upload audio file to Ezviz server\"\"\"\n print(\"=\" * 70)\n print(\"[Step 2] Uploading audio file...\")\n print(f\"[INFO] File: {audio_file_path}\")\n \n if not os.path.exists(audio_file_path):\n print(f\"[ERROR] Audio file not found: {audio_file_path}\")\n return None\n \n # Get filename without extension for voice name\n if voice_name is None:\n voice_name = os.path.splitext(os.path.basename(audio_file_path))[0]\n # Truncate to 50 characters if too long\n if len(voice_name) > 50:\n voice_name = voice_name[:50]\n \n try:\n with open(audio_file_path, 'rb') as f:\n files = {'voiceFile': f}\n data = {\n 'accessToken': access_token,\n 'voiceName': voice_name,\n 'force': 'true' # Always force upload\n }\n \n response = requests.post(UPLOAD_URL, data=data, files=files, timeout=60)\n result = response.json()\n \n if result.get('code') == '200':\n # Handle both array and dict response formats\n file_url = None\n audio_name = voice_name\n \n if isinstance(result['data'], list) and len(result['data']) > 0:\n audio_info = result['data'][0]\n file_url = audio_info.get('url')\n audio_name = audio_info.get('name', voice_name)\n elif isinstance(result['data'], dict):\n # Direct dict format\n file_url = result['data'].get('url')\n audio_name = result['data'].get('name', voice_name)\n \n if file_url:\n print(f\"[SUCCESS] Audio uploaded successfully!\")\n print(f\"[INFO] Voice Name: {audio_name}\")\n print(f\"[INFO] File URL: {file_url[:50]}...\")\n return file_url\n else:\n print(f\"[ERROR] No URL in response: {result}\")\n return None\n else:\n print(f\"[ERROR] Failed to upload audio: {result.get('msg', 'Unknown error')}\")\n return None\n \n except Exception as e:\n print(f\"[ERROR] Exception when uploading audio: {str(e)}\")\n return None\n\ndef broadcast_audio_to_device(access_token, device_serial, channel_no, file_url):\n \"\"\"Broadcast audio to device using voice/send API\"\"\"\n print(\"=\" * 70)\n print(\"[Step 3] Broadcasting audio to device...\")\n print(f\"[Device] {device_serial} (Channel: {channel_no})\")\n \n payload = {\n 'accessToken': access_token,\n 'deviceSerial': device_serial,\n 'channelNo': channel_no,\n 'fileUrl': file_url\n }\n \n try:\n response = requests.post(BROADCAST_URL, data=payload, timeout=30)\n result = response.json()\n \n if result.get('code') == '200':\n print(\"[SUCCESS] Audio broadcast completed!\")\n return True\n else:\n msg = result.get('msg', 'Unknown error')\n code = result.get('code', 'Unknown')\n print(f\"[ERROR] Failed to broadcast audio: Code {code}, Message: {msg}\")\n return False\n \n except Exception as e:\n print(f\"[ERROR] Exception when broadcasting audio: {str(e)}\")\n return False\n\ndef parse_device_list(device_serial_str):\n \"\"\"Parse device serial string with optional channel numbers\"\"\"\n devices = []\n for item in device_serial_str.split(','):\n item = item.strip()\n if ':' in item:\n serial, channel = item.split(':', 1)\n devices.append((serial, channel))\n else:\n devices.append((item, DEFAULT_CHANNEL_NO))\n return devices\n\ndef main():\n # Parse command line arguments\n app_key = None\n app_secret = None\n device_serial = None\n audio_file_path = None\n text_content = None\n channel_no = DEFAULT_CHANNEL_NO\n \n # Check for --audio-file or --text flags\n args = sys.argv[1:]\n if len(args) >= 4:\n app_key = args[0]\n app_secret = args[1]\n device_serial = args[2]\n \n # Look for flags\n if '--audio-file' in args:\n idx = args.index('--audio-file')\n if idx + 1 \u003c len(args):\n audio_file_path = args[idx + 1]\n if idx + 2 \u003c len(args) and not args[idx + 2].startswith('--'):\n channel_no = args[idx + 2]\n elif '--text' in args:\n idx = args.index('--text')\n if idx + 1 \u003c len(args):\n text_content = args[idx + 1]\n if idx + 2 \u003c len(args) and not args[idx + 2].startswith('--'):\n channel_no = args[idx + 2]\n else:\n # Assume old format: app_key app_secret device_serial audio_file [channel_no]\n if len(args) >= 4:\n audio_file_path = args[3]\n if len(args) >= 5:\n channel_no = args[4]\n \n # Get from environment variables if not provided\n if not app_key:\n app_key = get_env_or_arg('EZVIZ_APP_KEY', None)\n if not app_secret:\n app_secret = get_env_or_arg('EZVIZ_APP_SECRET', None)\n if not device_serial:\n device_serial = get_env_or_arg('EZVIZ_DEVICE_SERIAL', None)\n if not audio_file_path:\n audio_file_path = get_env_or_arg('EZVIZ_AUDIO_FILE', None)\n if not text_content:\n text_content = get_env_or_arg('EZVIZ_TEXT_CONTENT', None)\n if channel_no == DEFAULT_CHANNEL_NO:\n channel_no = get_env_or_arg('EZVIZ_CHANNEL_NO', DEFAULT_CHANNEL_NO)\n \n # SECURITY: Warn if credentials not from environment variables\n config_source = \"environment\"\n if not app_key or not app_secret:\n print(\"[WARNING] Credentials not found in environment variables\")\n print(\"[WARNING] Attempting to load from OpenClaw config files...\")\n print(\"[WARNING] Ensure config files contain dedicated Ezviz credentials (not main account)\")\n \n # Try to load from channels config if still not provided (lower priority than env vars)\n channels_config = load_ezviz_config_from_channels()\n if channels_config:\n if not app_key:\n app_key = channels_config[\"appId\"]\n if not app_secret:\n app_secret = channels_config[\"appSecret\"]\n config_source = \"config file\"\n print(f\"[INFO] Loaded credentials from config file (AppKey prefix: {app_key[:8]}...)\")\n else:\n print(\"[ERROR] No credentials found in environment or config files\")\n \n # Validate required parameters\n if not all([app_key, app_secret, device_serial]):\n print(\"Error: Missing required parameters!\")\n print(\"Please provide app_key, app_secret, and device_serial\")\n print(\"\\nUsage:\")\n print(\" # Using local audio file\")\n print(\" python3 audio_broadcast.py app_key app_secret device_serial --audio-file /path/to/audio.mp3 [channel_no]\")\n print(\"\")\n print(\" # Using text to generate speech\")\n print(\" python3 audio_broadcast.py app_key app_secret device_serial --text \\\"要播报的内容\\\" [channel_no]\")\n print(\"\")\n print(\" # Environment variables\")\n print(\" export EZVIZ_APP_KEY=your_key\")\n print(\" export EZVIZ_APP_SECRET=your_secret\")\n print(\" export EZVIZ_DEVICE_SERIAL=dev1,dev2\")\n print(\" export EZVIZ_AUDIO_FILE=/path/to/audio.mp3 # OR\")\n print(\" export EZVIZ_TEXT_CONTENT=\\\"要播报的内容\\\"\")\n print(\" python3 audio_broadcast.py\")\n sys.exit(1)\n \n # SECURITY: Validate inputs before processing\n print(\"=\" * 70)\n print(\"SECURITY VALIDATION\")\n print(\"=\" * 70)\n \n # Validate device serial\n is_valid, error = validate_device_serial(device_serial)\n if not is_valid:\n print(f\"[ERROR] Device serial validation failed: {error}\")\n sys.exit(1)\n print(f\"[OK] Device serial format validated\")\n \n # Validate text input if using TTS\n if text_content:\n is_valid, error = validate_text_input(text_content)\n if not is_valid:\n print(f\"[ERROR] Text input validation failed: {error}\")\n sys.exit(1)\n print(f\"[OK] Text input validated ({len(text_content)} chars)\")\n \n # Validate credentials source\n if config_source == \"config file\":\n print(f\"[WARNING] Using credentials from config file - ensure they are dedicated Ezviz credentials\")\n else:\n print(f\"[OK] Using credentials from environment variables\")\n \n print()\n \n # Handle text-to-speech if needed\n temp_audio_file = None\n if text_content and not audio_file_path:\n print(\"=\" * 70)\n print(\"TEXT TO SPEECH MODE\")\n print(\"=\" * 70)\n print(f\"[INFO] Text content: {text_content}\")\n \n # Create temporary file for generated audio (use .wav for compatibility)\n temp_dir = tempfile.gettempdir()\n temp_audio_file = os.path.join(temp_dir, f\"ezviz_tts_{int(time.time())}.wav\")\n \n # Use macOS say command for TTS\n print(\"[INFO] Generating audio using macOS TTS...\")\n if not text_to_speech(text_content, temp_audio_file):\n print(\"[ERROR] Could not generate audio from text.\")\n sys.exit(1)\n \n audio_file_path = temp_audio_file\n \n if not audio_file_path:\n print(\"Error: Either --audio-file or --text must be provided!\")\n sys.exit(1)\n \n # Validate audio file exists (if not using text mode)\n if not os.path.exists(audio_file_path):\n print(f\"[ERROR] Audio file not found: {audio_file_path}\")\n sys.exit(1)\n \n # Validate audio file format\n valid_extensions = ['.wav', '.mp3', '.aac']\n file_ext = os.path.splitext(audio_file_path)[1].lower()\n if file_ext not in valid_extensions:\n print(f\"[WARNING] Audio file format {file_ext} may not be supported. Supported formats: {', '.join(valid_extensions)}\")\n \n # Check file size (max 5MB)\n file_size = os.path.getsize(audio_file_path)\n if file_size > 5 * 1024 * 1024:\n print(f\"[WARNING] Audio file size ({file_size / 1024 / 1024:.2f} MB) exceeds 5MB limit!\")\n \n # Print header\n print(\"=\" * 70)\n print(\"Ezviz Audio Broadcast Skill (萤石语音广播)\")\n print(\"=\" * 70)\n print(f\"[Time] {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\")\n \n # Parse devices\n devices = parse_device_list(device_serial)\n print(f\"[INFO] Target devices: {len(devices)}\")\n for i, (serial, chan) in enumerate(devices, 1):\n print(f\" - {serial} (Channel: {chan})\")\n print(f\"[INFO] Audio file: {audio_file_path}\")\n print(f\"[INFO] Format: {file_ext}\")\n print(f\"[INFO] Size: {file_size / 1024:.2f} KB\")\n \n # Get access token\n access_token = get_access_token(app_key, app_secret)\n if not access_token:\n print(\"Failed to get access token. Exiting.\")\n sys.exit(1)\n \n # Upload audio file\n file_url = upload_audio_file(access_token, audio_file_path)\n if not file_url:\n print(\"Failed to upload audio file. Exiting.\")\n # Clean up temp file if it exists\n if temp_audio_file and os.path.exists(temp_audio_file):\n os.remove(temp_audio_file)\n sys.exit(1)\n \n # Broadcast to each device\n print(\"\\n\" + \"=\" * 70)\n print(\"BROADCASTING AUDIO TO DEVICES\")\n print(\"=\" * 70)\n \n success_count = 0\n \n for i, (device_serial, channel_no) in enumerate(devices):\n if i > 0:\n time.sleep(1) # Rate limiting\n \n success = broadcast_audio_to_device(access_token, device_serial, channel_no, file_url)\n if success:\n success_count += 1\n \n # Clean up temp file if it exists\n if temp_audio_file and os.path.exists(temp_audio_file):\n os.remove(temp_audio_file)\n \n # Print summary\n print(\"\\n\" + \"=\" * 70)\n print(\"BROADCAST SUMMARY\")\n print(\"=\" * 70)\n print(f\" Total devices: {len(devices)}\")\n print(f\" Success: {success_count}\")\n print(f\" Failed: {len(devices) - success_count}\")\n\nif __name__ == \"__main__\":\n main()\n","content_type":"text/x-python; charset=utf-8","language":"python","size":20937,"content_sha256":"43b60723f5a1a2dbfd76c12a6601b479f789430fcdee3bd174b934dcbd8b67db"}],"content_json":{"type":"doc","content":[{"type":"heading","attrs":{"level":1},"content":[{"text":"Ezviz Audio Broadcast (萤石语音广播)","type":"text"}]},{"type":"paragraph","content":[{"text":"通过萤石语音上传和下发接口,实现语音内容到设备的广播播放。","type":"text"}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":2},"content":[{"text":"⚠️ 安全警告 (安装前必读)","type":"text"}]},{"type":"paragraph","content":[{"text":"在使用此技能前,请完成以下安全检查:","type":"text","marks":[{"type":"strong"}]}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"#","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"检查项","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"状态","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"说明","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"1","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"凭证权限","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"⚠️ 必需","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"使用","type":"text"},{"text":"最小权限","type":"text","marks":[{"type":"strong"}]},{"text":"的 AppKey/AppSecret,不要用主账号凭证","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"2","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"配置文件读取","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"⚠️ 注意","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"技能会读取 ","type":"text"},{"text":"~/.openclaw/*.json","type":"text","marks":[{"type":"code_inline"}]},{"text":" 文件(","type":"text"},{"text":"但环境变量优先级更高","type":"text","marks":[{"type":"strong"}]},{"text":")","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"3","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Token 缓存","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"⚠️ 注意","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Token 缓存在 ","type":"text"},{"text":"/tmp/ezviz_global_token_cache/","type":"text","marks":[{"type":"code_inline"}]},{"text":" (权限 600)","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"4","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"系统命令","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"⚠️ 注意","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"使用 ","type":"text"},{"text":"say","type":"text","marks":[{"type":"code_inline"}]},{"text":"/","type":"text"},{"text":"espeak","type":"text","marks":[{"type":"code_inline"}]},{"text":"/","type":"text"},{"text":"ffmpeg","type":"text","marks":[{"type":"code_inline"}]},{"text":" 进行 TTS (通过 subprocess)","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"5","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"API 域名","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"✅ 已验证","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"openai.ys7.com","type":"text","marks":[{"type":"code_inline"}]},{"text":" 是萤石官方 API 端点(","type":"text"},{"text":"openai","type":"text","marks":[{"type":"code_inline"}]},{"text":" = Open API,不是 AI)","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"6","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"代码审查","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"✅ 推荐","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"审查 ","type":"text"},{"text":"scripts/audio_broadcast.py","type":"text","marks":[{"type":"code_inline"}]},{"text":" 和 ","type":"text"},{"text":"lib/token_manager.py","type":"text","marks":[{"type":"code_inline"}]}]}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"🔒 配置文件读取详细说明","type":"text"}]},{"type":"paragraph","content":[{"text":"凭证获取优先级","type":"text","marks":[{"type":"strong"}]},{"text":"(从高到低):","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":""},"content":[{"text":"┌─────────────────────────────────────────────────────────────┐\n│ 1. 环境变量 (最高优先级 - 推荐) │\n│ ├─ EZVIZ_APP_KEY │\n│ ├─ EZVIZ_APP_SECRET │\n│ └─ EZVIZ_DEVICE_SERIAL │\n│ ✅ 优点:不读取配置文件,完全隔离 │\n├─────────────────────────────────────────────────────────────┤\n│ 2. OpenClaw 配置文件 (仅当环境变量未设置时使用) │\n│ ├─ ~/.openclaw/config.json │\n│ ├─ ~/.openclaw/gateway/config.json │\n│ └─ ~/.openclaw/channels.json │\n│ ⚠️ 注意:只读取 channels.ezviz 字段,不读取其他服务凭证 │\n├─────────────────────────────────────────────────────────────┤\n│ 3. 命令行参数 (最低优先级) │\n│ python3 audio_broadcast.py appKey appSecret deviceSerial │\n└─────────────────────────────────────────────────────────────┘","type":"text"}]},{"type":"paragraph","content":[{"text":"安全建议","type":"text","marks":[{"type":"strong"}]},{"text":":","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"✅ ","type":"text"},{"text":"最佳实践","type":"text","marks":[{"type":"strong"}]},{"text":": 使用环境变量,完全避免配置文件读取","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"✅ ","type":"text"},{"text":"隔离配置","type":"text","marks":[{"type":"strong"}]},{"text":": 在专用配置文件只存放萤石凭证,不混用其他服务","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"⚠️ ","type":"text"},{"text":"风险缓解","type":"text","marks":[{"type":"strong"}]},{"text":": 设置环境变量覆盖配置文件(即使配置文件存在也会被忽略)","type":"text"}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"快速安全配置","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"# 1. 使用环境变量(优先级最高,避免配置文件意外使用)\nexport EZVIZ_APP_KEY=\"your_dedicated_app_key\"\nexport EZVIZ_APP_SECRET=\"your_dedicated_app_secret\"\nexport EZVIZ_DEVICE_SERIAL=\"device1,device2\"\n\n# 2. 高安全环境:禁用 Token 缓存\nexport EZVIZ_TOKEN_CACHE=0\n\n# 3. 测试凭证(推荐先用测试账号)\n# 登录 https://openai.ys7.com/ 创建专用应用,仅开通语音相关权限","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"凭证优先级","type":"text"}]},{"type":"paragraph","content":[{"text":"技能按以下顺序获取凭证(","type":"text"},{"text":"优先级从高到低","type":"text","marks":[{"type":"strong"}]},{"text":"):","type":"text"}]},{"type":"ordered_list","attrs":{"order":1,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"环境变量","type":"text","marks":[{"type":"strong"}]},{"text":" (","type":"text"},{"text":"EZVIZ_APP_KEY","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"EZVIZ_APP_SECRET","type":"text","marks":[{"type":"code_inline"}]},{"text":") ← 推荐","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Channels 配置","type":"text","marks":[{"type":"strong"}]},{"text":" (","type":"text"},{"text":"~/.openclaw/config.json","type":"text","marks":[{"type":"code_inline"}]},{"text":" 等)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"命令行参数","type":"text","marks":[{"type":"strong"}]},{"text":" (直接传入)","type":"text"}]}]}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":2},"content":[{"text":"快速开始","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"安装依赖","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"pip install requests","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"设置环境变量","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"export EZVIZ_APP_KEY=\"your_app_key\"\nexport EZVIZ_APP_SECRET=\"your_app_secret\"\nexport EZVIZ_DEVICE_SERIAL=\"dev1,dev2,dev3\"","type":"text"}]},{"type":"paragraph","content":[{"text":"可选环境变量:","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"export EZVIZ_CHANNEL_NO=\"1\" # 通道号,默认 1\nexport EZVIZ_AUDIO_FILE=\"/path/to/audio.mp3\" # 本地音频文件路径(二选一)\nexport EZVIZ_TEXT_CONTENT=\"语音内容文本\" # 文本内容(二选一)\nexport EZVIZ_VOICE_NAME=\"custom_name\" # 自定义语音名称\nexport EZVIZ_TOKEN_CACHE=\"1\" # Token 缓存:1=启用 (默认), 0=禁用","type":"text"}]},{"type":"paragraph","content":[{"text":"Token 缓存说明","type":"text","marks":[{"type":"strong"}]},{"text":":","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"✅ ","type":"text"},{"text":"默认启用","type":"text","marks":[{"type":"strong"}]},{"text":": 技能默认使用 Token 缓存,提升效率","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"⚠️ ","type":"text"},{"text":"禁用缓存","type":"text","marks":[{"type":"strong"}]},{"text":": 设置 ","type":"text"},{"text":"EZVIZ_TOKEN_CACHE=0","type":"text","marks":[{"type":"code_inline"}]},{"text":" 每次重新获取 Token","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"📁 ","type":"text"},{"text":"缓存位置","type":"text","marks":[{"type":"strong"}]},{"text":": ","type":"text"},{"text":"/tmp/ezviz_global_token_cache/global_token_cache.json","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"🔒 ","type":"text"},{"text":"文件权限","type":"text","marks":[{"type":"strong"}]},{"text":": 600 (仅所有者可读写)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"⏰ ","type":"text"},{"text":"有效期","type":"text","marks":[{"type":"strong"}]},{"text":": 7 天,到期前 5 分钟自动刷新","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"注意","type":"text","marks":[{"type":"strong"}]},{"text":":","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"不需要设置 ","type":"text"},{"text":"EZVIZ_ACCESS_TOKEN","type":"text","marks":[{"type":"code_inline"}]},{"text":"!技能会自动获取 Token","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"必须提供 ","type":"text"},{"text":"EZVIZ_AUDIO_FILE","type":"text","marks":[{"type":"code_inline"}]},{"text":" 或 ","type":"text"},{"text":"EZVIZ_TEXT_CONTENT","type":"text","marks":[{"type":"code_inline"}]},{"text":" 其中一个","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"设备需要支持对讲功能(","type":"text"},{"text":"support_talk=1或3","type":"text","marks":[{"type":"code_inline"}]},{"text":")","type":"text"}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"运行","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"python3 {baseDir}/scripts/audio_broadcast.py","type":"text"}]},{"type":"paragraph","content":[{"text":"命令行参数:","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"# 使用本地音频文件\npython3 {baseDir}/scripts/audio_broadcast.py appKey appSecret dev1 /path/to/audio.mp3 [channel_no]\n\n# 使用文本内容(自动生成语音)\npython3 {baseDir}/scripts/audio_broadcast.py appKey appSecret dev1 \"语音内容文本\" [channel_no]","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"工作流程","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":""},"content":[{"text":"1. 获取 Token (appKey + appSecret → accessToken)\n ↓\n2a. 如果提供音频文件:直接上传文件\n2b. 如果提供文本:调用TTS生成音频文件,然后上传\n ↓\n3. 下发语音 (accessToken + deviceSerial + fileUrl → 设备播放)\n ↓\n4. 输出结果 (JSON + 控制台)","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Token 自动获取说明","type":"text"}]},{"type":"paragraph","content":[{"text":"你不需要手动获取或配置 ","type":"text","marks":[{"type":"strong"}]},{"text":"EZVIZ_ACCESS_TOKEN","type":"text","marks":[{"type":"code_inline"},{"type":"strong"}]},{"text":"!","type":"text","marks":[{"type":"strong"}]}]},{"type":"paragraph","content":[{"text":"技能会自动处理 Token 的获取:","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":""},"content":[{"text":"首次运行:\n appKey + appSecret → 调用萤石 API → 获取 accessToken (有效期 7 天)\n ↓\n保存到缓存文件(系统临时目录)\n ↓\n后续运行:\n 检查缓存 Token 是否过期\n ├─ 未过期 → 直接使用缓存 Token ✅\n └─ 已过期 → 重新获取新 Token","type":"text"}]},{"type":"paragraph","content":[{"text":"Token 管理特性","type":"text","marks":[{"type":"strong"}]},{"text":":","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"✅ ","type":"text"},{"text":"自动获取","type":"text","marks":[{"type":"strong"}]},{"text":": 首次运行自动调用萤石 API 获取","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"✅ ","type":"text"},{"text":"有效期 7 天","type":"text","marks":[{"type":"strong"}]},{"text":": 获取的 Token 7 天内有效","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"✅ ","type":"text"},{"text":"智能缓存","type":"text","marks":[{"type":"strong"}]},{"text":": Token 有效期内不重复获取,提升效率","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"✅ ","type":"text"},{"text":"安全缓冲","type":"text","marks":[{"type":"strong"}]},{"text":": 到期前 5 分钟自动刷新,避免边界问题","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"✅ ","type":"text"},{"text":"无需配置","type":"text","marks":[{"type":"strong"}]},{"text":": 不需要手动设置 ","type":"text"},{"text":"EZVIZ_ACCESS_TOKEN","type":"text","marks":[{"type":"code_inline"}]},{"text":" 环境变量","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"✅ ","type":"text"},{"text":"安全存储","type":"text","marks":[{"type":"strong"}]},{"text":": 缓存文件存储在系统临时目录,权限 600","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"⚠️ ","type":"text"},{"text":"可选禁用","type":"text","marks":[{"type":"strong"}]},{"text":": 设置 ","type":"text"},{"text":"EZVIZ_TOKEN_CACHE=0","type":"text","marks":[{"type":"code_inline"}]},{"text":" 可禁用缓存(每次运行重新获取)","type":"text"}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"输出示例","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":""},"content":[{"text":"======================================================================\nEzviz Audio Broadcast Skill (萤石语音广播)\n======================================================================\n[Time] 2026-03-16 16:30:00\n[INFO] Target devices: 2\n - dev1 (Channel: 1)\n - dev2 (Channel: 1)\n[INFO] Mode: Text-to-Speech\n[INFO] Content: 接下来插播一个广告\n\n======================================================================\n[Step 1] Getting access token...\n[SUCCESS] Token obtained, expires: 2026-03-23 16:30:00\n\n======================================================================\n[Step 2] Generating and uploading audio...\n[INFO] Generated TTS file: /tmp/ezviz_tts_12345.mp3\n[SUCCESS] Audio uploaded successfully!\n[INFO] Voice Name: ad_broadcast\n[INFO] File URL: https://oss-cn-shenzhen.aliyuncs.com/voice/...\n\n======================================================================\n[Step 3] Broadcasting audio to devices...\n======================================================================\n\n[Device] dev1 (Channel: 1)\n[SUCCESS] Audio broadcast completed!\n\n[Device] dev2 (Channel: 1) \n[SUCCESS] Audio broadcast completed!\n\n======================================================================\nBROADCAST SUMMARY\n======================================================================\n Total devices: 2\n Success: 2\n Failed: 0\n======================================================================","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"多设备格式","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"格式","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"示例","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"说明","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"单设备","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"dev1","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"默认通道 1","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"多设备","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"dev1,dev2,dev3","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"全部使用默认通道","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"指定通道","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"dev1:1,dev2:2","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"每个设备独立通道","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"混合","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"dev1,dev2:2,dev3","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"部分指定通道","type":"text"}]}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"API 接口","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"接口","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"URL","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"文档","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"获取 Token","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"POST /api/lapp/token/get","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"https://openai.ys7.com/help/81","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"语音上传","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"POST /api/lapp/voice/upload","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"https://openai.ys7.com/help/1241","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"语音下发","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"POST /api/lapp/voice/send","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"https://openai.ys7.com/help/1253","type":"text"}]}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"网络端点","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"域名","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"用途","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"openai.ys7.com","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"萤石开放平台 API(Token、语音上传、下发)","type":"text"}]}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"音频要求","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"格式","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"支持","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"限制","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"WAV","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"✅","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"最大5MB,最长60秒","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"MP3","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"✅","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"最大5MB,最长60秒","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"AAC","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"✅","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"最大5MB,最长60秒","type":"text"}]}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"注意事项","type":"text"}]},{"type":"paragraph","content":[{"text":"⚠️ ","type":"text"},{"text":"设备兼容性","type":"text","marks":[{"type":"strong"}]},{"text":": 设备必须支持对讲功能(","type":"text"},{"text":"support_talk=1或3","type":"text","marks":[{"type":"code_inline"}]},{"text":"),否则返回错误码 ","type":"text"},{"text":"20015","type":"text","marks":[{"type":"code_inline"}]}]},{"type":"paragraph","content":[{"text":"⚠️ ","type":"text"},{"text":"频率限制","type":"text","marks":[{"type":"strong"}]},{"text":": 语音下发接口有调用频率限制,建议设备间间隔1秒以上","type":"text"}]},{"type":"paragraph","content":[{"text":"⚠️ ","type":"text"},{"text":"文件大小","type":"text","marks":[{"type":"strong"}]},{"text":": 音频文件不能超过5MB,时长不能超过60秒","type":"text"}]},{"type":"paragraph","content":[{"text":"⚠️ ","type":"text"},{"text":"Token 安全","type":"text","marks":[{"type":"strong"}]},{"text":": Token 缓存到系统临时目录(权限 600),不写入日志,不发送到非萤石端点","type":"text"}]},{"type":"paragraph","content":[{"text":"⚠️ ","type":"text"},{"text":"TTS依赖","type":"text","marks":[{"type":"strong"}]},{"text":": 文本转语音功能依赖系统TTS服务,确保系统支持","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"数据流出说明","type":"text"}]},{"type":"paragraph","content":[{"text":"本技能会向第三方服务发送数据","type":"text","marks":[{"type":"strong"}]},{"text":":","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"数据类型","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"发送到","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"用途","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"是否必需","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"音频文件","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"openai.ys7.com","type":"text","marks":[{"type":"code_inline"}]},{"text":" (萤石)","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"语音上传和下发","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"✅ 必需","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"appKey/appSecret","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"openai.ys7.com","type":"text","marks":[{"type":"code_inline"}]},{"text":" (萤石)","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"获取访问 Token","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"✅ 必需","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"设备序列号","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"openai.ys7.com","type":"text","marks":[{"type":"code_inline"}]},{"text":" (萤石)","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"请求下发","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"✅ 必需","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"EZVIZ_ACCESS_TOKEN","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"自动生成","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"每次运行自动获取","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"✅ 自动","type":"text","marks":[{"type":"strong"}]}]}]}]}]},{"type":"paragraph","content":[{"text":"数据流出说明","type":"text","marks":[{"type":"strong"}]},{"text":":","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"✅ ","type":"text"},{"text":"萤石开放平台","type":"text","marks":[{"type":"strong"}]},{"text":" (","type":"text"},{"text":"openai.ys7.com","type":"text","marks":[{"type":"code_inline"}]},{"text":"): 所有API调用 - 萤石官方 API","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"❌ ","type":"text"},{"text":"无其他第三方","type":"text","marks":[{"type":"strong"}]},{"text":": 不会发送数据到其他服务","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"凭证权限建议","type":"text","marks":[{"type":"strong"}]},{"text":":","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"使用","type":"text"},{"text":"最小权限","type":"text","marks":[{"type":"strong"}]},{"text":"的 appKey/appSecret","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"仅开通必要的 API 权限(语音上传、下发)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"定期轮换凭证","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"不要使用主账号凭证","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"本地处理","type":"text","marks":[{"type":"strong"}]},{"text":":","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"✅ Token 缓存到系统临时目录(权限 600)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"✅ TTS临时文件自动清理","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"✅ 不记录完整 API 响应","type":"text"}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"应用场景","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"✅ 可选禁用缓存:设置 EZVIZ_TOKEN_CACHE=0 | 场景 | 说明 | |------|------| | 📢 安全广播 | 向监控区域发送安全提醒、紧急通知 | | 🏢 办公通知 | 办公室广播会议提醒、访客通知 | | 🏪 商业应用 | 商店促销广播、排队叫号 | | 🏠 智能家居 | 家庭语音提醒、门铃通知 | | 🏭 工厂管理 | 生产线通知、安全警示 |","type":"text"}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"使用示例","type":"text"}]},{"type":"paragraph","content":[{"text":"场景1: 紧急安全通知","type":"text","marks":[{"type":"strong"}]}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"python3 audio_broadcast.py your_key your_secret \"kitchen_cam,dining_area\" \"注意!检测到安全隐患,请立即检查!\"","type":"text"}]},{"type":"paragraph","content":[{"text":"场景2: 商业促销广播","type":"text","marks":[{"type":"strong"}]}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"export EZVIZ_TEXT_CONTENT=\"欢迎光临!今日特价商品限时优惠,详情请咨询店员!\"\nexport EZVIZ_DEVICE_SERIAL=\"store_front,store_back\"\npython3 audio_broadcast.py","type":"text"}]},{"type":"paragraph","content":[{"text":"场景3: 使用预录制音频","type":"text","marks":[{"type":"strong"}]}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"python3 audio_broadcast.py your_key your_secret entrance_cam /path/to/welcome_message.mp3","type":"text"}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":2},"content":[{"text":"API 端点","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"接口","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"URL","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"文档","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"获取 Token","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"POST /api/lapp/token/get","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"https://open.ys7.com/help/81","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"语音上传","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"POST /api/lapp/voice/upload","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"https://open.ys7.com/help/1241","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"语音下发","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"POST /api/lapp/voice/send","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"https://open.ys7.com/help/1253","type":"text"}]}]}]}]},{"type":"paragraph","content":[{"text":"API 域名","type":"text","marks":[{"type":"strong"}]},{"text":": ","type":"text"},{"text":"https://openai.ys7.com","type":"text","marks":[{"type":"code_inline"}]},{"text":" (萤石开放平台 API 专用)","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"⚠️ 域名说明","type":"text"}]},{"type":"paragraph","content":[{"text":"为什么是 ","type":"text","marks":[{"type":"strong"}]},{"text":"openai.ys7.com","type":"text","marks":[{"type":"code_inline"},{"type":"strong"}]},{"text":" 而不是 ","type":"text","marks":[{"type":"strong"}]},{"text":"open.ys7.com","type":"text","marks":[{"type":"code_inline"},{"type":"strong"}]},{"text":"?","type":"text","marks":[{"type":"strong"}]}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"域名","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"用途","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"说明","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"openai.ys7.com","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"✅ API 接口","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"萤石开放平台 ","type":"text"},{"text":"API 专用域名","type":"text","marks":[{"type":"strong"}]},{"text":"(AI 不是指人工智能)","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"open.ys7.com","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"🌐 官方网站","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"萤石开放平台 ","type":"text"},{"text":"官网/文档","type":"text","marks":[{"type":"strong"}]},{"text":" 入口","type":"text"}]}]}]}]},{"type":"paragraph","content":[{"text":"openai","type":"text","marks":[{"type":"code_inline"},{"type":"strong"}]},{"text":" 的含义","type":"text","marks":[{"type":"strong"}]},{"text":": 这里是 \"Open API\" 的缩写,","type":"text"},{"text":"不是","type":"text","marks":[{"type":"strong"}]},{"text":" 指 OpenAI 或人工智能。","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"✅ 域名验证","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"# 验证 API 域名连通性\ncurl -I https://openai.ys7.com/api/lapp/token/get\n\n# 验证官网连通性\ncurl -I https://open.ys7.com/\n\n# 检查 SSL 证书(API 域名)\ncurl -vI https://openai.ys7.com/api/lapp/token/get 2>&1 | grep -A5 \"SSL certificate\"\n\n# 验证域名所有权(萤石)\nwhois ys7.com","type":"text"}]},{"type":"paragraph","content":[{"text":"官方文档","type":"text","marks":[{"type":"strong"}]},{"text":": https://open.ys7.com/","type":"text"}]},{"type":"paragraph","content":[{"text":"安全提示","type":"text","marks":[{"type":"strong"}]},{"text":":","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"✅ ","type":"text"},{"text":"openai.ys7.com","type":"text","marks":[{"type":"code_inline"}]},{"text":" 是萤石官方 API 域名","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"✅ 两个域名都属于萤石(ys7.com)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"⚠️ 如果担心域名安全,先用测试凭证验证","type":"text"}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"⚠️ 配置文件扫描说明","type":"text"}]},{"type":"paragraph","content":[{"text":"技能会读取以下路径中的萤石配置(仅当环境变量未设置时):","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":""},"content":[{"text":"~/.openclaw/config.json\n~/.openclaw/gateway/config.json\n~/.openclaw/channels.json","type":"text"}]},{"type":"paragraph","content":[{"text":"配置格式","type":"text","marks":[{"type":"strong"}]},{"text":":","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"json"},"content":[{"text":"{\n \"channels\": {\n \"ezviz\": {\n \"appId\": \"your_app_id\",\n \"appSecret\": \"your_app_secret\",\n \"domain\": \"https://openai.ys7.com\",\n \"enabled\": true\n }\n }\n}","type":"text"}]},{"type":"paragraph","content":[{"text":"安全建议","type":"text","marks":[{"type":"strong"}]},{"text":":","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"✅ 使用","type":"text"},{"text":"专用萤石凭证","type":"text","marks":[{"type":"strong"}]},{"text":",不要与其他服务共享","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"✅ 如果不想使用配置文件扫描,设置环境变量覆盖","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"✅ 定期审查配置文件中的凭证权限","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"❌ 不要在配置文件中存储主账号凭证","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"禁用配置文件扫描","type":"text","marks":[{"type":"strong"}]},{"text":"(环境变量优先):","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"export EZVIZ_APP_KEY=\"your_key\"\nexport EZVIZ_APP_SECRET=\"your_secret\"\n# 环境变量优先级高于配置文件","type":"text"}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":2},"content":[{"text":"系统依赖","type":"text"}]},{"type":"paragraph","content":[{"text":"Python 包","type":"text","marks":[{"type":"strong"}]},{"text":":","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"pip install requests","type":"text"}]},{"type":"paragraph","content":[{"text":"系统工具","type":"text","marks":[{"type":"strong"}]},{"text":" (仅 TTS 需要):","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"macOS: ","type":"text"},{"text":"say","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"afconvert","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Linux: ","type":"text"},{"text":"espeak","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"ffmpeg","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"⚠️ 系统命令安全说明","type":"text"}]},{"type":"paragraph","content":[{"text":"技能通过 ","type":"text"},{"text":"subprocess","type":"text","marks":[{"type":"code_inline"}]},{"text":" 调用系统 TTS 命令:","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"python"},"content":[{"text":"# macOS TTS\nsubprocess.run(['say', '-o', temp_aiff, text_with_pauses], check=True, capture_output=True)\nsubprocess.run(['afconvert', '-f', 'WAVE', '-d', 'LEI16@44100', temp_aiff, output_path], ...)\n\n# Linux TTS\nsubprocess.run(['espeak', '-w', output_path, text], check=True, capture_output=True)\nsubprocess.run(['ffmpeg', '-i', input, '-acodec', 'libmp3lame', output], ...)","type":"text"}]},{"type":"paragraph","content":[{"text":"安全措施","type":"text","marks":[{"type":"strong"}]},{"text":" (v1.0.2+):","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"✅ 使用","type":"text"},{"text":"列表参数","type":"text","marks":[{"type":"strong"}]},{"text":"调用 subprocess(避免 shell 注入)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"✅ ","type":"text"},{"text":"输入验证","type":"text","marks":[{"type":"strong"}]},{"text":": 文本内容经过 ","type":"text"},{"text":"validate_text_input()","type":"text","marks":[{"type":"code_inline"}]},{"text":" 验证","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"✅ ","type":"text"},{"text":"危险字符拦截","type":"text","marks":[{"type":"strong"}]},{"text":": 拒绝包含 ","type":"text"},{"text":";","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"|","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"&","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"$()","type":"text","marks":[{"type":"code_inline"}]},{"text":", 等字符的输入","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"✅ ","type":"text"},{"text":"长度限制","type":"text","marks":[{"type":"strong"}]},{"text":": 文本内容最多 500 字符","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"✅ 临时文件存储在系统临时目录,使用后清理","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"输入验证规则","type":"text","marks":[{"type":"strong"}]},{"text":":","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"检查项","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"限制","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"说明","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"空内容","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"❌ 拒绝","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"文本不能为空","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"长度","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"≤500 字符","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"防止过长输入","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"危险字符","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"❌ 拒绝","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":";","type":"text","marks":[{"type":"code_inline"}]},{"text":", `","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"设备序列号","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"字母数字","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"只允许 ","type":"text"},{"text":"A-Za-z0-9_:,","type":"text","marks":[{"type":"code_inline"}]}]}]}]}]},{"type":"paragraph","content":[{"text":"安全建议","type":"text","marks":[{"type":"strong"}]},{"text":":","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"✅ 确保系统二进制文件来自可信源","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"✅ 在高安全环境运行前审查 ","type":"text"},{"text":"text_to_speech()","type":"text","marks":[{"type":"code_inline"}]},{"text":" 函数","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"✅ 使用容器/沙箱隔离执行环境","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"✅ 输入验证提供额外保护层(防御纵深)","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"不使用 TTS","type":"text","marks":[{"type":"strong"}]},{"text":" (仅提供音频文件,避免系统命令):","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"python3 scripts/audio_broadcast.py appKey appSecret deviceSerial --audio-file /path/to/audio.mp3","type":"text"}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":2},"content":[{"text":"安全说明","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"⚠️ 环境变量声明","type":"text"}]},{"type":"paragraph","content":[{"text":"必需环境变量","type":"text","marks":[{"type":"strong"}]},{"text":" (在 SKILL.md metadata 中声明):","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"yaml"},"content":[{"text":"metadata:\n openclaw:\n requires:\n env: [\"EZVIZ_APP_KEY\", \"EZVIZ_APP_SECRET\", \"EZVIZ_DEVICE_SERIAL\"]","type":"text"}]},{"type":"paragraph","content":[{"text":"⚠️ 注意","type":"text","marks":[{"type":"strong"}]},{"text":": 如果 Registry metadata 未显示必需环境变量,以 SKILL.md 为准。","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"⚠️ Token 持久化说明","type":"text"}]},{"type":"paragraph","content":[{"text":"默认行为","type":"text","marks":[{"type":"strong"}]},{"text":":","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Token 会缓存到系统临时目录(","type":"text"},{"text":"/tmp/ezviz_global_token_cache/global_token_cache.json","type":"text","marks":[{"type":"code_inline"}]},{"text":")","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"缓存有效期 7 天,文件权限 600(仅所有者可读写)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"所有萤石技能共享同一个全局缓存","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"缓存位置查询","type":"text","marks":[{"type":"strong"}]},{"text":":","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"# macOS\nls -la /var/folders/*/T/ezviz_global_token_cache/\n\n# Linux\nls -la /tmp/ezviz_global_token_cache/\n\n# 查看缓存内容(脱敏)\ncat /tmp/ezviz_global_token_cache/global_token_cache.json","type":"text"}]},{"type":"paragraph","content":[{"text":"⚠️ 潜在风险","type":"text","marks":[{"type":"strong"}]},{"text":":","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"风险","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"等级","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"说明","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Token 明文存储","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"🟡 中","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"文件权限 600,但仍是明文","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"跨技能共享","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"🟡 中","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"同一用户的技能可共享 Token","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"多用户系统","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"🟠 高","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"其他用户可能访问临时目录","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"临时目录清理","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"🟢 低","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"系统重启可能清理临时文件","type":"text"}]}]}]}]},{"type":"paragraph","content":[{"text":"禁用缓存","type":"text","marks":[{"type":"strong"}]},{"text":" (高安全环境/共享系统):","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"export EZVIZ_TOKEN_CACHE=0\npython3 scripts/audio_broadcast.py ...","type":"text"}]},{"type":"paragraph","content":[{"text":"清除缓存","type":"text","marks":[{"type":"strong"}]},{"text":":","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"# 清除所有缓存 Token\nrm -rf /tmp/ezviz_global_token_cache/\n\n# 或使用 Token 管理器\npython3 lib/token_manager.py clear","type":"text"}]},{"type":"paragraph","content":[{"text":"安全建议","type":"text","marks":[{"type":"strong"}]},{"text":":","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"环境","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"建议","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"单用户个人设备","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"✅ 默认缓存安全(文件权限 600)","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"多用户共享系统","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"⚠️ 设置 ","type":"text"},{"text":"EZVIZ_TOKEN_CACHE=0","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"高安全环境","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"⚠️ 禁用缓存 + 专用 OS 用户 + 容器隔离","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"生产环境","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"⚠️ 容器/VM 隔离 + 禁用缓存 + 密钥管理器","type":"text"}]}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"⚠️ 凭证轮换通知","type":"text"}]},{"type":"paragraph","content":[{"text":"⚠️ 早期版本用户必须轮换凭证!","type":"text","marks":[{"type":"strong"}]}]},{"type":"paragraph","content":[{"text":"如果您曾经使用过旧版本的 .env 文件:","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":""},"content":[{"text":"🚨 您的凭证可能已泄露!\n\n立即执行:\n1. 登录 https://openai.ys7.com/\n2. 删除旧应用,创建新应用\n3. 获取新的 AppKey 和 AppSecret","type":"text"}]},{"type":"paragraph","content":[{"text":"正确做法","type":"text","marks":[{"type":"strong"}]},{"text":":","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"❌ 不要使用 .env 文件(已删除)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"✅ 使用环境变量","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"✅ 使用最小权限凭证","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"✅ 定期轮换凭证(建议每 90 天)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"✅ 使用密钥管理器(生产环境)","type":"text"}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"数据流出说明","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"数据类型","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"发送到","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"用途","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"AppKey/AppSecret","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"openai.ys7.com","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"获取 Token","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"设备序列号","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"openai.ys7.com","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"API 调用","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"音频文件","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"openai.ys7.com","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"语音上传","type":"text"}]}]}]}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":2},"content":[{"text":"代码审查","type":"text"}]},{"type":"paragraph","content":[{"text":"推荐审查的文件","type":"text","marks":[{"type":"strong"}]},{"text":":","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"scripts/audio_broadcast.py","type":"text","marks":[{"type":"code_inline"}]},{"text":" - 主脚本","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"lib/token_manager.py","type":"text","marks":[{"type":"code_inline"}]},{"text":" - Token 管理器","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"代码特点","type":"text","marks":[{"type":"strong"}]},{"text":":","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"✅ 代码未混淆,易于审查","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"✅ 使用 ","type":"text"},{"text":"requests","type":"text","marks":[{"type":"code_inline"}]},{"text":" 库(标准做法)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"✅ 使用 ","type":"text"},{"text":"subprocess","type":"text","marks":[{"type":"code_inline"}]},{"text":" 带列表参数(减少 shell 注入风险)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"⚠️ TTS 调用系统二进制文件(say/espeak/ffmpeg)","type":"text"}]}]}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":2},"content":[{"text":"降低风险操作清单","type":"text"}]},{"type":"paragraph","content":[{"text":"安装前","type":"text","marks":[{"type":"strong"}]},{"text":":","type":"text"}]},{"type":"checkbox_list","attrs":{"id":null},"content":[{"type":"checkbox_item","attrs":{"checked":false},"content":[{"type":"paragraph","content":[{"text":"审查所有代码(scripts/, lib/)","type":"text"}]}]},{"type":"checkbox_item","attrs":{"checked":false},"content":[{"type":"paragraph","content":[{"text":"验证 API 域名和 SSL 证书","type":"text"}]}]},{"type":"checkbox_item","attrs":{"checked":false},"content":[{"type":"paragraph","content":[{"text":"准备测试凭证(非生产环境)","type":"text"}]}]},{"type":"checkbox_item","attrs":{"checked":false},"content":[{"type":"paragraph","content":[{"text":"确认环境变量名称一致(EZVIZ_TEXT_CONTENT)","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"安装时","type":"text","marks":[{"type":"strong"}]},{"text":":","type":"text"}]},{"type":"checkbox_list","attrs":{"id":null},"content":[{"type":"checkbox_item","attrs":{"checked":false},"content":[{"type":"paragraph","content":[{"text":"设置 ","type":"text"},{"text":"EZVIZ_TOKEN_CACHE=0","type":"text","marks":[{"type":"code_inline"}]},{"text":"(共享系统/多用户环境)","type":"text"}]}]},{"type":"checkbox_item","attrs":{"checked":false},"content":[{"type":"paragraph","content":[{"text":"使用专用 OS 用户账户","type":"text"}]}]},{"type":"checkbox_item","attrs":{"checked":false},"content":[{"type":"paragraph","content":[{"text":"在隔离环境运行(容器/VM)","type":"text"}]}]},{"type":"checkbox_item","attrs":{"checked":false},"content":[{"type":"paragraph","content":[{"text":"使用环境变量而非 .env 文件","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"安装后","type":"text","marks":[{"type":"strong"}]},{"text":":","type":"text"}]},{"type":"checkbox_list","attrs":{"id":null},"content":[{"type":"checkbox_item","attrs":{"checked":false},"content":[{"type":"paragraph","content":[{"text":"验证缓存文件权限(600)","type":"text"}]}]},{"type":"checkbox_item","attrs":{"checked":false},"content":[{"type":"paragraph","content":[{"text":"监控 API 调用日志","type":"text"}]}]},{"type":"checkbox_item","attrs":{"checked":false},"content":[{"type":"paragraph","content":[{"text":"定期轮换凭证(90 天)","type":"text"}]}]},{"type":"checkbox_item","attrs":{"checked":false},"content":[{"type":"paragraph","content":[{"text":"使用后清除缓存(高安全环境)","type":"text"}]}]},{"type":"checkbox_item","attrs":{"checked":false},"content":[{"type":"paragraph","content":[{"text":"验证环境变量名称一致性","type":"text"}]}]}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":2},"content":[{"text":"🔒 安全审计清单 (安装前完成)","type":"text"}]},{"type":"paragraph","content":[{"text":"根据安全审计建议,请在安装前完成以下检查:","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"安装前检查","type":"text"}]},{"type":"checkbox_list","attrs":{"id":null},"content":[{"type":"checkbox_item","attrs":{"checked":false},"content":[{"type":"paragraph","content":[{"text":"审查代码","type":"text","marks":[{"type":"strong"}]},{"text":" — 阅读 ","type":"text"},{"text":"scripts/audio_broadcast.py","type":"text","marks":[{"type":"code_inline"}]},{"text":" 和 ","type":"text"},{"text":"lib/token_manager.py","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"checkbox_item","attrs":{"checked":false},"content":[{"type":"paragraph","content":[{"text":"验证 API 域名","type":"text","marks":[{"type":"strong"}]},{"text":" — 确认 ","type":"text"},{"text":"openai.ys7.com","type":"text","marks":[{"type":"code_inline"}]},{"text":" 是萤石官方端点","type":"text"}]}]},{"type":"checkbox_item","attrs":{"checked":false},"content":[{"type":"paragraph","content":[{"text":"准备测试凭证","type":"text","marks":[{"type":"strong"}]},{"text":" — 创建专用萤石应用,仅开通语音相关权限","type":"text"}]}]},{"type":"checkbox_item","attrs":{"checked":false},"content":[{"type":"paragraph","content":[{"text":"检查配置文件","type":"text","marks":[{"type":"strong"}]},{"text":" — 审查 ","type":"text"},{"text":"~/.openclaw/*.json","type":"text","marks":[{"type":"code_inline"}]},{"text":" 中是否有敏感凭证","type":"text"}]}]},{"type":"checkbox_item","attrs":{"checked":false},"content":[{"type":"paragraph","content":[{"text":"确认缓存位置","type":"text","marks":[{"type":"strong"}]},{"text":" — 确认 ","type":"text"},{"text":"/tmp/ezviz_global_token_cache/","type":"text","marks":[{"type":"code_inline"}]},{"text":" 可接受","type":"text"}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"安装时配置","type":"text"}]},{"type":"checkbox_list","attrs":{"id":null},"content":[{"type":"checkbox_item","attrs":{"checked":false},"content":[{"type":"paragraph","content":[{"text":"使用环境变量","type":"text","marks":[{"type":"strong"}]},{"text":" — 优先使用 ","type":"text"},{"text":"EZVIZ_APP_KEY","type":"text","marks":[{"type":"code_inline"}]},{"text":" 等环境变量","type":"text"}]}]},{"type":"checkbox_item","attrs":{"checked":false},"content":[{"type":"paragraph","content":[{"text":"禁用缓存","type":"text","marks":[{"type":"strong"}]},{"text":" (可选) — 高安全环境设置 ","type":"text"},{"text":"EZVIZ_TOKEN_CACHE=0","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"checkbox_item","attrs":{"checked":false},"content":[{"type":"paragraph","content":[{"text":"最小权限凭证","type":"text","marks":[{"type":"strong"}]},{"text":" — 不要使用主账号凭证","type":"text"}]}]},{"type":"checkbox_item","attrs":{"checked":false},"content":[{"type":"paragraph","content":[{"text":"隔离环境","type":"text","marks":[{"type":"strong"}]},{"text":" (可选) — 在容器/VM 中运行","type":"text"}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"安装后验证","type":"text"}]},{"type":"checkbox_list","attrs":{"id":null},"content":[{"type":"checkbox_item","attrs":{"checked":false},"content":[{"type":"paragraph","content":[{"text":"验证缓存权限","type":"text","marks":[{"type":"strong"}]},{"text":" — 确认缓存文件权限为 600","type":"text"}]}]},{"type":"checkbox_item","attrs":{"checked":false},"content":[{"type":"paragraph","content":[{"text":"测试功能","type":"text","marks":[{"type":"strong"}]},{"text":" — 使用测试设备验证广播功能","type":"text"}]}]},{"type":"checkbox_item","attrs":{"checked":false},"content":[{"type":"paragraph","content":[{"text":"监控日志","type":"text","marks":[{"type":"strong"}]},{"text":" — 检查 API 调用是否正常","type":"text"}]}]},{"type":"checkbox_item","attrs":{"checked":false},"content":[{"type":"paragraph","content":[{"text":"记录凭证","type":"text","marks":[{"type":"strong"}]},{"text":" — 安全存储凭证信息(密钥管理器)","type":"text"}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"持续维护","type":"text"}]},{"type":"checkbox_list","attrs":{"id":null},"content":[{"type":"checkbox_item","attrs":{"checked":false},"content":[{"type":"paragraph","content":[{"text":"定期轮换凭证","type":"text","marks":[{"type":"strong"}]},{"text":" — 建议每 90 天轮换一次","type":"text"}]}]},{"type":"checkbox_item","attrs":{"checked":false},"content":[{"type":"paragraph","content":[{"text":"审查依赖","type":"text","marks":[{"type":"strong"}]},{"text":" — 定期检查 ","type":"text"},{"text":"requests","type":"text","marks":[{"type":"code_inline"}]},{"text":" 等依赖的安全更新","type":"text"}]}]},{"type":"checkbox_item","attrs":{"checked":false},"content":[{"type":"paragraph","content":[{"text":"清理缓存","type":"text","marks":[{"type":"strong"}]},{"text":" — 高安全环境使用后清除缓存","type":"text"}]}]},{"type":"checkbox_item","attrs":{"checked":false},"content":[{"type":"paragraph","content":[{"text":"监控异常","type":"text","marks":[{"type":"strong"}]},{"text":" — 关注异常 API 调用或错误","type":"text"}]}]}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"paragraph","content":[{"text":"更新日志","type":"text","marks":[{"type":"strong"}]},{"text":":","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"日期","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"版本","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"变更","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"说明","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"2026-03-18","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"1.0.5","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"完整披露 metadata","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"添加 ","type":"text"},{"text":"configFileRead","type":"text","marks":[{"type":"code_inline"}]},{"text":" 和 ","type":"text"},{"text":"tokenCache","type":"text","marks":[{"type":"code_inline"}]},{"text":" 完整说明","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"2026-03-18","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"1.0.5","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"明确优先级","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"环境变量 > 配置文件 > 命令行参数","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"2026-03-18","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"1.0.4","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"澄清 API 域名","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"说明 ","type":"text"},{"text":"openai.ys7.com","type":"text","marks":[{"type":"code_inline"}]},{"text":" 是官方 API 域名(","type":"text"},{"text":"openai","type":"text","marks":[{"type":"code_inline"}]},{"text":" = Open API)","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"2026-03-18","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"1.0.3","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"修复 metadata","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"添加 ","type":"text"},{"text":"config.tokenCache","type":"text","marks":[{"type":"code_inline"}]},{"text":" 配置说明","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"2026-03-18","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"1.0.3","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"明确缓存行为","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"默认启用缓存,支持 ","type":"text"},{"text":"EZVIZ_TOKEN_CACHE=0","type":"text","marks":[{"type":"code_inline"}]},{"text":" 禁用","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"2026-03-18","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"1.0.2","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"添加输入验证","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"validate_text_input()","type":"text","marks":[{"type":"code_inline"}]},{"text":" 和 ","type":"text"},{"text":"validate_device_serial()","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"2026-03-18","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"1.0.2","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"添加凭证来源警告","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"从配置文件读取时显示警告","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"2026-03-18","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"1.0.2","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"更新 metadata 格式","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"使用 YAML 格式,添加 warnings 字段","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"2026-03-18","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"1.0.1","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"修复 Token 缓存 bug","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"use_cache=None","type":"text","marks":[{"type":"code_inline"}]},{"text":" 改为 ","type":"text"},{"text":"use_cache=True","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"2026-03-18","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"1.0.1","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"添加安全审计清单","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"根据安全建议添加完整检查清单","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"2026-03-18","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"1.0.1","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"明确配置文件行为","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"说明 ","type":"text"},{"text":"~/.openclaw/*.json","type":"text","marks":[{"type":"code_inline"}]},{"text":" 读取逻辑","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"2026-03-18","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"1.0.1","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"添加 API 域名验证","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"提供域名和 SSL 验证命令","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"2026-03-18","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"1.0.1","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"添加 TTS 安全说明","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"说明 subprocess 调用系统命令的安全措施","type":"text"}]}]}]}]},{"type":"paragraph","content":[{"text":"最后更新","type":"text","marks":[{"type":"strong"}]},{"text":": 2026-03-18","type":"text"},{"type":"br"},{"text":"版本","type":"text","marks":[{"type":"strong"}]},{"text":": 1.0.5 (完整信息披露版)","type":"text"}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":2},"content":[{"text":"Channels 配置(推荐)","type":"text"}]},{"type":"paragraph","content":[{"text":"技能支持从 OpenClaw 的 channels 配置中自动读取萤石凭证,无需单独设置环境变量。","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"配置方式","type":"text"}]},{"type":"paragraph","content":[{"text":"在 ","type":"text"},{"text":"~/.openclaw/config.json","type":"text","marks":[{"type":"code_inline"}]},{"text":" 或 ","type":"text"},{"text":"~/.openclaw/channels.json","type":"text","marks":[{"type":"code_inline"}]},{"text":" 中添加:","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"json"},"content":[{"text":"{\n \"channels\": {\n \"ezviz\": {\n \"appId\": \"your_app_id\",\n \"appSecret\": \"your_app_secret\",\n \"domain\": \"https://openai.ys7.com\",\n \"enabled\": true\n }\n }\n}","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"配置搜索顺序","type":"text"}]},{"type":"paragraph","content":[{"text":"技能会按以下顺序查找配置文件:","type":"text"}]},{"type":"ordered_list","attrs":{"order":1,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"~/.openclaw/config.json","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"~/.openclaw/gateway/config.json","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"~/.openclaw/channels.json","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"优先级","type":"text"}]},{"type":"paragraph","content":[{"text":"凭证获取优先级:","type":"text"}]},{"type":"ordered_list","attrs":{"order":1,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"环境变量","type":"text","marks":[{"type":"strong"}]},{"text":" (最高优先级)","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"EZVIZ_APP_KEY","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"EZVIZ_APP_SECRET","type":"text","marks":[{"type":"code_inline"}]}]}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Channels 配置","type":"text","marks":[{"type":"strong"}]},{"text":" (中等优先级)","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"channels.ezviz.appId","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"channels.ezviz.appSecret","type":"text","marks":[{"type":"code_inline"}]}]}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"命令行参数","type":"text","marks":[{"type":"strong"}]},{"text":" (最低优先级)","type":"text"}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"优势","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"✅ 集中管理凭证","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"✅ 无需每次设置环境变量","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"✅ 多个技能共享同一配置","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"✅ 更符合 OpenClaw 最佳实践","type":"text"}]}]}]},{"type":"hr","attrs":{"markup":"---"}}]},"metadata":{"date":"2026-06-05","name":"ezviz-audio-broadcast","author":"@skillopedia","source":{"stars":2012,"repo_name":"openclaw-master-skills","origin_url":"https://github.com/leoyeai/openclaw-master-skills/blob/HEAD/skills/ezviz-open-camera-broadcast/SKILL.md","repo_owner":"leoyeai","body_sha256":"e8ba1d08bab17909bbfca0f20a9bd439fc29cf26fa380b857aac8eb86efdb814","cluster_key":"fa474ab904fb06a4adbd7cfb7adf981f997ac3b2d08a2529694ecd616bc441fd","clean_bundle":{"format":"clean-skill-bundle-v1","source":"leoyeai/openclaw-master-skills/skills/ezviz-open-camera-broadcast/SKILL.md","attachments":[{"id":"d47f959b-b3d0-5e69-9bb0-497cc6b3e131","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/d47f959b-b3d0-5e69-9bb0-497cc6b3e131/attachment.json","path":"_meta.json","size":488,"sha256":"79f692a35e109f137ace5c63ffbd7f71baa87282121338f2d9be8c16c0e1a0cc","contentType":"application/json; charset=utf-8"},{"id":"a4ecbfdd-4043-580d-968a-23f803362a42","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/a4ecbfdd-4043-580d-968a-23f803362a42/attachment.py","path":"lib/token_manager.py","size":11205,"sha256":"380cac6c7a29034aaa2d4c6a7d834a7b08a087f806e4180cfb663c59fc35ca64","contentType":"text/x-python; charset=utf-8"},{"id":"20a740cf-e6f4-5c7f-8711-01d21ef991ed","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/20a740cf-e6f4-5c7f-8711-01d21ef991ed/attachment.py","path":"scripts/audio_broadcast.py","size":20937,"sha256":"43b60723f5a1a2dbfd76c12a6601b479f789430fcdee3bd174b934dcbd8b67db","contentType":"text/x-python; charset=utf-8"}],"bundle_sha256":"80f6a01c6275a188e28b2cf1fea8a3560eab9c8534a6a1a60ba95a34411f555f","attachment_count":3,"text_attachments":3,"attachment_storage":"skillopedia-attachments-v1","binary_attachments":0,"excluded_attachments":[]},"cluster_size":1,"skill_md_path":"skills/ezviz-open-camera-broadcast/SKILL.md","import_metadata":{"date":"2026-06-05","author":"@skillopedia","version":"v1","category":"web-development","category_label":"Web"},"exact_dupes_collapsed_into_this":0},"version":"v1","category":"web-development","metadata":{"openclaw":{"emoji":"🔊","config":{"tokenCache":{"path":"/tmp/ezviz_global_token_cache/global_token_cache.json","envVar":"EZVIZ_TOKEN_CACHE","default":true,"description":"Enable token caching (default: true). Set to 0 to disable.","permissions":"0600"},"configFileRead":{"paths":["~/.openclaw/config.json","~/.openclaw/gateway/config.json","~/.openclaw/channels.json"],"priority":"lower than environment variables","description":"Reads Ezviz credentials from OpenClaw config files as fallback"}},"requires":{"env":["EZVIZ_APP_KEY","EZVIZ_APP_SECRET","EZVIZ_DEVICE_SERIAL"],"pip":["requests"]},"warnings":["Requires Ezviz credentials with minimal permissions","Token cached in system temp directory (configurable)","Uses system TTS commands (say/espeak/ffmpeg) via subprocess","May read ~/.openclaw/*.json for credentials (env vars have priority)"],"primaryEnv":"EZVIZ_APP_KEY"}},"import_tag":"clean-skills-v1","description":"萤石语音广播技能。支持本地音频文件上传或文本转语音,实现语音内容下发到设备播放。\nUse when: 需要向萤石设备发送语音通知、广播、提醒等音频内容。\n\n⚠️ 安全要求:必须设置 EZVIZ_APP_KEY 和 EZVIZ_APP_SECRET 环境变量,使用最小权限凭证。\n"}},"renderedAt":1782981886817}

Ezviz Audio Broadcast (萤石语音广播) 通过萤石语音上传和下发接口,实现语音内容到设备的广播播放。 --- ⚠️ 安全警告 (安装前必读) 在使用此技能前,请完成以下安全检查: | # | 检查项 | 状态 | 说明 | |---|--------|------|------| | 1 | 凭证权限 | ⚠️ 必需 | 使用 最小权限 的 AppKey/AppSecret,不要用主账号凭证 | | 2 | 配置文件读取 | ⚠️ 注意 | 技能会读取 文件( 但环境变量优先级更高 ) | | 3 | Token 缓存 | ⚠️ 注意 | Token 缓存在 (权限 600) | | 4 | 系统命令 | ⚠️ 注意 | 使用 / / 进行 TTS (通过 subprocess) | | 5 | API 域名 | ✅ 已验证 | 是萤石官方 API 端点( = Open API,不是 AI) | | 6 | 代码审查 | ✅ 推荐 | 审查 和 | 🔒 配置文件读取详细说明 凭证获取优先级 (从高到低): 安全建议 : - ✅ 最佳实践 : 使用环境变量,完全避免配置文件读取 - ✅ 隔离配置 : 在专用配置文件只存放萤石凭证,不混用其他服务 - ⚠️ 风险缓解 : 设置环境变量覆盖配置文件(即使配置文件存在也会被忽略) 快速安全配置 凭证优先级 技能按以下…