{"skill":{"slug":"voice-translator","displayName":"Voice Translator","summary":"说中文出外语语音——按住说中文，2-3秒内播放英/日/韩语音。支持场景模式、双向对话、常用句收藏。","description":"---\nname: senseaudio-voice-translator\ndescription: 说中文出外语语音——按住说中文，2-3秒内播放英/日/韩语音。支持场景模式、双向对话、常用句收藏。\nmetadata:\n  openclaw:\n    emoji: \"🌏\"\n    homepage: https://senseaudio.cn/docs\n    requires:\n      env:\n        - SENSEAUDIO_API_KEY\n      bins:\n        - curl\n        - python3\n    primaryEnv: SENSEAUDIO_API_KEY\n---\n\n# Voice Translator / 语音翻译器\n\n按住说中文，松手后 2-3 秒内播放目标语言语音。出国旅行、跨国沟通即开即用。\n\n## 工作流程\n\n```\n[按住录音] → ASR识别中文 → LLM场景化翻译 → TTS合成外语语音 → [播放]\n双向模式：[录入外语] → ASR识别 → 翻译成中文 → TTS播放中文\n```\n\n## 核心 API\n\n### 第一步：语音识别（ASR）\n\n```bash\n# 录制音频后上传识别（中文）\ncurl https://api.senseaudio.cn/v1/audio/transcriptions \\\n  -H \"Authorization: Bearer $SENSEAUDIO_API_KEY\" \\\n  -F file=\"@recording.wav\" \\\n  -F model=\"sense-asr\" \\\n  -F language=\"zh\" \\\n  -F response_format=\"text\"\n# 返回：买单\n```\n\n双向模式识别外语（自动检测语言）：\n```bash\ncurl https://api.senseaudio.cn/v1/audio/transcriptions \\\n  -H \"Authorization: Bearer $SENSEAUDIO_API_KEY\" \\\n  -F file=\"@foreign.wav\" \\\n  -F model=\"sense-asr\" \\\n  -F response_format=\"text\"\n# 返回：Can I get the check please\n```\n\n### 第二步：场景化翻译（LLM）\n\n翻译不是直译，而是目标语言的自然表达。通过系统提示注入场景上下文：\n\n| 场景 | system prompt 关键词 |\n|------|---------------------|\n| 餐厅 | restaurant, ordering food, dining |\n| 机场 | airport, check-in, boarding, customs |\n| 酒店 | hotel, check-in, room service, concierge |\n| 出租车 | taxi, directions, destination |\n| 购物 | shopping, price, discount, payment |\n| 就医 | medical, symptoms, pharmacy, emergency |\n\n翻译示例（餐厅场景）：\n- 中文\"买单\" → `\"Can I get the check, please?\"` ✓（非 \"buy the bill\" ✗）\n- 中文\"这个怎么做的\" → `\"How is this dish prepared?\"` ✓\n- 中文\"不要辣\" → `\"Could you make it not spicy, please?\"` ✓\n\n### 第三步：语音合成（TTS）\n\n```bash\n# 英语播报\ncurl -X POST https://api.senseaudio.cn/v1/t2a_v2 \\\n  -H \"Authorization: Bearer $SENSEAUDIO_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"model\": \"SenseAudio-TTS-1.0\",\n    \"text\": \"Can I get the check, please?\",\n    \"stream\": false,\n    \"voice_setting\": {\n      \"voice_id\": \"female_0001_a\",\n      \"speed\": 0.9\n    },\n    \"audio_setting\": {\n      \"format\": \"mp3\",\n      \"sample_rate\": 32000\n    }\n  }' | python3 -c \"\nimport sys, json, subprocess\nr = json.load(sys.stdin)\naudio = bytes.fromhex(r['data']['audio'])\nopen('/tmp/translated.mp3','wb').write(audio)\nsubprocess.run(['play','/tmp/translated.mp3'])\n\"\n```\n\n## 完整 Python 实现\n\n```python\nimport os\nimport json\nimport requests\nimport subprocess\nimport tempfile\n\nAPI_KEY = os.environ[\"SENSEAUDIO_API_KEY\"]\nASR_URL = \"https://api.senseaudio.cn/v1/audio/transcriptions\"\nTTS_URL = \"https://api.senseaudio.cn/v1/t2a_v2\"\n\n# 场景配置\nSCENES = {\n    \"restaurant\": {\n        \"name\": \"餐厅\",\n        \"prompt\": \"You are translating for a customer in a restaurant. Use natural, polite expressions a native speaker would use when ordering food, asking about dishes, or requesting service.\",\n    },\n    \"airport\": {\n        \"name\": \"机场\",\n        \"prompt\": \"You are translating at an airport. Use standard travel expressions for check-in, boarding, customs, and baggage.\",\n    },\n    \"hotel\": {\n        \"name\": \"酒店\",\n        \"prompt\": \"You are translating at a hotel. Use polite hospitality expressions for check-in, room requests, and concierge services.\",\n    },\n    \"taxi\": {\n        \"name\": \"出租车\",\n        \"prompt\": \"You are translating in a taxi. Use clear, direct expressions for giving directions and destinations.\",\n    },\n    \"shopping\": {\n        \"name\": \"购物\",\n        \"prompt\": \"You are translating while shopping. Use natural expressions for asking prices, sizes, discounts, and payment.\",\n    },\n    \"medical\": {\n        \"name\": \"就医\",\n        \"prompt\": \"You are translating at a medical facility. Use clear, precise expressions for describing symptoms and seeking help.\",\n    },\n}\n\n# 目标语言配置\nLANGUAGES = {\n    \"en\": {\"name\": \"英语\", \"voice_id\": \"female_0001_a\"},\n    \"ja\": {\"name\": \"日语\", \"voice_id\": \"female_0001_a\"},\n    \"ko\": {\"name\": \"韩语\", \"voice_id\": \"female_0001_a\"},\n    \"fr\": {\"name\": \"法语\", \"voice_id\": \"female_0001_a\"},\n    \"de\": {\"name\": \"德语\", \"voice_id\": \"female_0001_a\"},\n    \"es\": {\"name\": \"西班牙语\", \"voice_id\": \"female_0001_a\"},\n}\n\nLANG_NAMES = {\n    \"en\": \"English\", \"ja\": \"Japanese\", \"ko\": \"Korean\",\n    \"fr\": \"French\", \"de\": \"German\", \"es\": \"Spanish\",\n}\n\n\ndef asr(audio_path: str, language: str = None) -> str:\n    \"\"\"语音识别\"\"\"\n    with open(audio_path, \"rb\") as f:\n        data = {\"model\": \"sense-asr\", \"response_format\": \"text\"}\n        if language:\n            data[\"language\"] = language\n        resp = requests.post(\n            ASR_URL,\n            headers={\"Authorization\": f\"Bearer {API_KEY}\"},\n            files={\"file\": f},\n            data=data,\n            timeout=15,\n        )\n    resp.raise_for_status()\n    return resp.text.strip()\n\n\ndef translate(text: str, target_lang: str, scene: str = None) -> str:\n    \"\"\"场景化翻译（调用 LLM）\"\"\"\n    scene_prompt = SCENES.get(scene, {}).get(\"prompt\", \"Translate naturally.\")\n    lang_name = LANG_NAMES.get(target_lang, target_lang)\n\n    # 此处接入你的 LLM（如 Claude API）\n    # 示例 prompt：\n    system = f\"{scene_prompt} Translate the Chinese text to {lang_name}. Return ONLY the translated text, no explanations.\"\n    # user = text\n    # ... call LLM API ...\n    # 返回翻译结果\n    raise NotImplementedError(\"请接入 LLM 翻译接口\")\n\n\ndef tts(text: str, target_lang: str) -> bytes:\n    \"\"\"文字转语音\"\"\"\n    voice_id = LANGUAGES.get(target_lang, {}).get(\"voice_id\", \"female_0001_a\")\n    payload = {\n        \"model\": \"SenseAudio-TTS-1.0\",\n        \"text\": text,\n        \"stream\": False,\n        \"voice_setting\": {\"voice_id\": voice_id, \"speed\": 0.9},\n        \"audio_setting\": {\"format\": \"mp3\", \"sample_rate\": 32000},\n    }\n    resp = requests.post(\n        TTS_URL,\n        headers={\"Authorization\": f\"Bearer {API_KEY}\", \"Content-Type\": \"application/json\"},\n        json=payload,\n        timeout=15,\n    )\n    resp.raise_for_status()\n    return bytes.fromhex(resp.json()[\"data\"][\"audio\"])\n\n\ndef play_audio(audio_bytes: bytes):\n    \"\"\"播放音频\"\"\"\n    with tempfile.NamedTemporaryFile(suffix=\".mp3\", delete=False) as f:\n        f.write(audio_bytes)\n        tmp_path = f.name\n    # macOS: afplay, Linux: play (sox), Windows: start\n    for cmd in [[\"afplay\", tmp_path], [\"play\", tmp_path], [\"mpg123\", tmp_path]]:\n        try:\n            subprocess.run(cmd, check=True, capture_output=True)\n            return\n        except (FileNotFoundError, subprocess.CalledProcessError):\n            continue\n\n\nclass VoiceTranslator:\n    def __init__(self, target_lang: str = \"en\", scene: str = None, bidirectional: bool = False):\n        self.target_lang = target_lang\n        self.scene = scene\n        self.bidirectional = bidirectional\n        self.favorites: list[dict] = []  # 收藏的句子\n\n    def translate_voice(self, audio_path: str) -> dict:\n        \"\"\"主流程：录音 → 识别 → 翻译 → 合成 → 播放\"\"\"\n        # 1. ASR\n        src_lang = None if self.bidirectional else \"zh\"\n        recognized = asr(audio_path, language=src_lang)\n        print(f\"识别: {recognized}\")\n\n        # 2. 翻译\n        tgt_lang = \"zh\" if self.bidirectional else self.target_lang\n        translated = translate(recognized, tgt_lang, self.scene)\n        print(f\"翻译: {translated}\")\n\n        # 3. TTS + 播放\n        audio = tts(translated, tgt_lang)\n        play_audio(audio)\n\n        result = {\"original\": recognized, \"translated\": translated, \"lang\": tgt_lang}\n        return result\n\n    def add_favorite(self, result: dict):\n        \"\"\"收藏句子\"\"\"\n        entry = {**result, \"scene\": self.scene}\n        if entry not in self.favorites:\n            self.favorites.append(entry)\n            print(f\"已收藏: {result['original']} → {result['translated']}\")\n\n    def play_favorite(self, index: int):\n        \"\"\"直接播放收藏句子\"\"\"\n        entry = self.favorites[index]\n        audio = tts(entry[\"translated\"], entry[\"lang\"])\n        play_audio(audio)\n\n    def save_favorites(self, path: str = \"favorites.json\"):\n        with open(path, \"w\", encoding=\"utf-8\") as f:\n            json.dump(self.favorites, f, ensure_ascii=False, indent=2)\n\n    def load_favorites(self, path: str = \"favorites.json\"):\n        try:\n            with open(path, encoding=\"utf-8\") as f:\n                self.favorites = json.load(f)\n        except FileNotFoundError:\n            pass\n\n\n# 使用示例\nif __name__ == \"__main__\":\n    # 餐厅场景，翻译成英语\n    translator = VoiceTranslator(target_lang=\"en\", scene=\"restaurant\")\n    translator.load_favorites()\n\n    # 翻译一句话\n    result = translator.translate_voice(\"recording.wav\")\n\n    # 收藏\n    translator.add_favorite(result)\n    translator.save_favorites()\n\n    # 双向模式：对方说英语，翻译成中文\n    reverse = VoiceTranslator(target_lang=\"zh\", bidirectional=True)\n    reverse.translate_voice(\"foreign_speech.wav\")\n```\n\n## 场景模式速查\n\n| 场景 | 常见中文输入 | 自然外语输出（英语示例） |\n|------|------------|------------------------|\n| 餐厅 | 买单 | Can I get the check, please? |\n| 餐厅 | 这个怎么做的 | How is this dish prepared? |\n| 餐厅 | 不要辣 | Could you make it not spicy? |\n| 机场 | 我的行李丢了 | I'd like to report lost luggage. |\n| 机场 | 登机口在哪 | Where is the boarding gate? |\n| 酒店 | 我要退房 | I'd like to check out, please. |\n| 出租车 | 去这个地址 | Please take me to this address. |\n| 购物 | 能便宜点吗 | Is there any discount available? |\n| 就医 | 我头很痛 | I have a severe headache. |\n\n## 支持语言\n\n| 代码 | 语言 | ASR 支持 | TTS 支持 |\n|------|------|---------|---------|\n| en | 英语 | ✅ | ✅ |\n| ja | 日语 | ✅ | ✅ |\n| ko | 韩语 | ✅ | ✅ |\n| fr | 法语 | ✅ | ✅ |\n| de | 德语 | ✅ | ✅ |\n| es | 西班牙语 | ✅ | ✅ |\n| th | 泰语 | ✅ | ✅ |\n| vi | 越南语 | ✅ | ✅ |\n\n## 收藏功能\n\n翻译过的句子可一键收藏，自动积累个人旅行用语库：\n\n```python\n# 收藏\ntranslator.add_favorite(result)\ntranslator.save_favorites(\"my_phrases.json\")\n\n# 下次直接播放，无需重新录音\ntranslator.load_favorites(\"my_phrases.json\")\ntranslator.play_favorite(0)  # 播放第一条收藏\n```\n\n收藏文件格式（`favorites.json`）：\n```json\n[\n  {\n    \"original\": \"买单\",\n    \"translated\": \"Can I get the check, please?\",\n    \"lang\": \"en\",\n    \"scene\": \"restaurant\"\n  }\n]\n```\n\n## TTS 参数说明\n\n| 参数 | 推荐值 | 说明 |\n|------|--------|------|\n| speed | 0.9 | 略慢，外语更清晰易懂 |\n| vol | 1.0 | 标准音量 |\n| format | mp3 | 通用格式 |\n| sample_rate | 32000 | 平衡音质与速度 |\n\n## 相关资源\n\n- [SenseAudio ASR API](https://senseaudio.cn/docs/asr_api)\n- [SenseAudio TTS API](https://senseaudio.cn/docs/text_to_speech_api)\n- [支持语言列表](https://senseaudio.cn/docs/asr_api#language-support)\n","tags":{"latest":"1.0.0"},"stats":{"comments":0,"downloads":514,"installsAllTime":0,"installsCurrent":0,"stars":0,"versions":1},"createdAt":1773570109939,"updatedAt":1778491925219},"latestVersion":{"version":"1.0.0","createdAt":1773570109939,"changelog":"senseaudio-voice-translator 1.0.0\n\n- Initial release of the voice translator skill.\n- Speak Chinese and receive spoken output in English, Japanese, or Korean within 2–3 seconds.\n- Features scenario-based translation, bi-directional conversation mode, and phrase favorites.\n- Includes complete Python implementation and API usage documentation.\n- Supports major travel and daily life scenarios (restaurant, airport, hotel, taxi, shopping, medical).\n- Requires SENSEAUDIO_API_KEY and local tools (curl, python3).","license":"MIT-0"},"metadata":{"setup":[{"key":"SENSEAUDIO_API_KEY","required":true}],"os":null,"systems":null},"owner":{"handle":"scikkk","userId":"s171sgccp6wt09makas274ye9584ktsf","displayName":"scikkk","image":"https://avatars.githubusercontent.com/u/77485593?v=4"},"moderation":null}