实时音视频翻译-通义千问

qwen3-livetranslate-flash-realtime 是通义千问的一款实时音视频翻译模型,支持流式音频、图像输入,并实时输出翻译文本与合成音频。

如何使用

qwen3-livetranslate-flash-realtime 模型通过 WebSocket 协议接入,连接时需要以下配置项:

配置项

说明

调用地址

wss://dashscope.aliyuncs.com/api-ws/v1/realtime

查询参数

查询参数为model,需指定为要访问的模型名。示例:?model=qwen3-livetranslate-flash-realtime

消息头

使用 Bearer Token 鉴权:Authorization: Bearer DASHSCOPE_API_KEY

DASHSCOPE_API_KEY 是您在百炼上申请的API-KEY。

可通过以下 Python 示例代码建立连接。

# pip install websocket-client
import json
import websocket
import os

API_KEY=os.getenv("DASHSCOPE_API_KEY")
API_URL = "wss://dashscope.aliyuncs.com/api-ws/v1/realtime?model=qwen3-livetranslate-flash-realtime"

headers = [
    "Authorization: Bearer " + API_KEY
]

def on_open(ws):
    print(f"Connected to server: {API_URL}")
def on_message(ws, message):
    data = json.loads(message)
    print("Received event:", json.dumps(data, indent=2))
def on_error(ws, error):
    print("Error:", error)

ws = websocket.WebSocketApp(
    API_URL,
    header=headers,
    on_open=on_open,
    on_message=on_message,
    on_error=on_error
)

ws.run_forever()

支持的模型

qwen3-livetranslate-flash-realtime 是一款多语言音视频实时翻译模型,可识别 18 种语言,并实时翻译为 10 种语言的音频。

核心特性:

  • 多语言支持:支持 18 种语言及 6 种汉语方言。包括中文、英语、法语、德语、俄语、日语、韩语等。支持普通话、粤语、四川话等方言。

  • 视觉增强:利用视觉内容提升翻译准确性。模型通过分析口型、动作和画面中的文字,改善在嘈杂环境下或一词多义场景中的翻译效果。

  • 3秒延迟:实现低至 3 秒的同传延迟。

  • 无损同传:通过语义单元预测技术,解决跨语言语序问题。实时翻译质量接近离线翻译结果。

  • 音色自然:生成音色自然的拟人语音。模型能根据源语音内容,自适应调节语气和情感。

模型名称

版本

上下文长度

最大输入

最大输出

(Token数)

qwen3-livetranslate-flash-realtime

当前能力等同 qwen3-livetranslate-flash-realtime-2025-09-22

稳定版

53,248

49,152

4,096

qwen3-livetranslate-flash-realtime-2025-09-22

快照版

快速开始

  1. 准备运行环境

    您的 Python 版本需要不低于 3.10。

    首先安装 pyaudio。

    macOS

    brew install portaudio && pip install pyaudio

    Debian/Ubuntu

    sudo apt-get install python3-pyaudio
    
    或者
    
    pip install pyaudio

    CentOS

    sudo yum install -y portaudio portaudio-devel && pip install pyaudio

    Windows

    pip install pyaudio

    安装完成后,通过 pip 安装 websocket 相关的依赖:

    pip install websocket-client==1.8.0 websockets
  2. 创建客户端

    在本地新建一个 python 文件,命名为livetranslate_client.py,并将以下代码复制进文件中:

    客户端代码-livetranslate_client.py

    import os
    import time
    import base64
    import asyncio
    import json
    import websockets
    import pyaudio
    import queue
    import threading
    import traceback
    
    class LiveTranslateClient:
        def __init__(self, api_key: str, target_language: str = "en", voice: str | None = "Cherry", *, audio_enabled: bool = True):
            if not api_key:
                raise ValueError("API key cannot be empty.")
                
            self.api_key = api_key
            self.target_language = target_language
            self.audio_enabled = audio_enabled
            self.voice = voice if audio_enabled else "Cherry"
            self.ws = None
            self.api_url = "wss://dashscope.aliyuncs.com/api-ws/v1/realtime?model=qwen3-livetranslate-flash-realtime"
            
            # 音频输入配置 (来自麦克风)
            self.input_rate = 16000
            self.input_chunk = 1600
            self.input_format = pyaudio.paInt16
            self.input_channels = 1
            
            # 音频输出配置 (用于播放)
            self.output_rate = 24000
            self.output_chunk = 2400
            self.output_format = pyaudio.paInt16
            self.output_channels = 1
            
            # 状态管理
            self.is_connected = False
            self.audio_player_thread = None
            self.audio_playback_queue = queue.Queue()
            self.pyaudio_instance = pyaudio.PyAudio()
    
        async def connect(self):
            """建立到翻译服务的 WebSocket 连接。"""
            headers = {"Authorization": f"Bearer {self.api_key}"}
            try:
                self.ws = await websockets.connect(self.api_url, additional_headers=headers)
                self.is_connected = True
                print(f"成功连接到服务器: {self.api_url}")
                await self.configure_session()
            except Exception as e:
                print(f"连接失败: {e}")
                self.is_connected = False
                raise
    
        async def configure_session(self):
            """配置翻译会话,设置目标语言、声音等。"""
            config = {
                "event_id": f"event_{int(time.time() * 1000)}",
                "type": "session.update",
                "session": {
                    # 'modalities' 控制输出类型。
                    # ["text", "audio"]: 同时返回翻译文本和合成音频(推荐)。
                    # ["text"]: 仅返回翻译文本。
                    "modalities": ["text", "audio"] if self.audio_enabled else ["text"],
                    **({"voice": self.voice} if self.audio_enabled and self.voice else {}),
                    "input_audio_format": "pcm16",
                    "output_audio_format": "pcm16",
                    "translation": {
                        "language": self.target_language
                    }
                }
            }
            print(f"发送会话配置: {json.dumps(config, indent=2, ensure_ascii=False)}")
            await self.ws.send(json.dumps(config))
    
        async def send_audio_chunk(self, audio_data: bytes):
            """将音频数据块编码并发送到服务器。"""
            if not self.is_connected:
                return
                
            event = {
                "event_id": f"event_{int(time.time() * 1000)}",
                "type": "input_audio_buffer.append",
                "audio": base64.b64encode(audio_data).decode()
            }
            await self.ws.send(json.dumps(event))
    
        def _audio_player_task(self):
            stream = self.pyaudio_instance.open(
                format=self.output_format,
                channels=self.output_channels,
                rate=self.output_rate,
                output=True,
                frames_per_buffer=self.output_chunk,
            )
            try:
                while self.is_connected or not self.audio_playback_queue.empty():
                    try:
                        audio_chunk = self.audio_playback_queue.get(timeout=0.1)
                        if audio_chunk is None: # 结束信号
                            break
                        stream.write(audio_chunk)
                        self.audio_playback_queue.task_done()
                    except queue.Empty:
                        continue
            finally:
                stream.stop_stream()
                stream.close()
    
        def start_audio_player(self):
            """启动音频播放线程(仅当启用音频输出时)。"""
            if not self.audio_enabled:
                return
            if self.audio_player_thread is None or not self.audio_player_thread.is_alive():
                self.audio_player_thread = threading.Thread(target=self._audio_player_task, daemon=True)
                self.audio_player_thread.start()
    
        async def handle_server_messages(self, on_text_received):
            """循环处理来自服务器的消息。"""
            try:
                async for message in self.ws:
                    event = json.loads(message)
                    event_type = event.get("type")
                    if event_type == "response.audio_transcript.delta":
                        text = event.get("transcript", "")
                        if text and on_text_received:
                            on_text_received(text)
                    
                    elif event_type == "response.audio.delta" and self.audio_enabled:
                        audio_b64 = event.get("delta", "")
                        if audio_b64:
                            audio_data = base64.b64decode(audio_b64)
                            self.audio_playback_queue.put(audio_data)
    
                    elif event_type == "response.done":
                        print("\n[INFO] 一轮响应完成。")
                        usage = event.get("response", {}).get("usage", {})
                        if usage:
                            print(f"[INFO] Token 使用情况: {json.dumps(usage, indent=2, ensure_ascii=False)}")
                    elif event_type == "response.audio_transcript.done":
                        print("\n[INFO] 翻译文本完成。")
                        text = event.get("transcript", "")
                        if text:
                            print(f"[INFO] 翻译文本: {text}")
                    elif event_type == "response.text.done":
                        print("\n[INFO] 翻译文本完成。")
                        text = event.get("text", "")
                        if text:
                            print(f"[INFO] 翻译文本: {text}")
    
            except websockets.exceptions.ConnectionClosed as e:
                print(f"[WARNING] 连接已关闭: {e}")
                self.is_connected = False
            except Exception as e:
                print(f"[ERROR] 消息处理时发生未知错误: {e}")
                traceback.print_exc()
                self.is_connected = False
    
        async def start_microphone_streaming(self):
            """从麦克风捕获音频并流式传输到服务器。"""
            stream = self.pyaudio_instance.open(
                format=self.input_format,
                channels=self.input_channels,
                rate=self.input_rate,
                input=True,
                frames_per_buffer=self.input_chunk
            )
            print("麦克风已启动,请开始说话...")
            try:
                while self.is_connected:
                    audio_chunk = await asyncio.get_event_loop().run_in_executor(
                        None, stream.read, self.input_chunk
                    )
                    await self.send_audio_chunk(audio_chunk)
            finally:
                stream.stop_stream()
                stream.close()
    
        async def close(self):
            """优雅地关闭连接和资源。"""
            self.is_connected = False
            if self.ws:
                await self.ws.close()
                print("WebSocket 连接已关闭。")
            
            if self.audio_player_thread:
                self.audio_playback_queue.put(None) # 发送结束信号
                self.audio_player_thread.join(timeout=1)
                print("音频播放线程已停止。")
                
            self.pyaudio_instance.terminate()
            print("PyAudio 实例已释放。")
  3. 与模型互动

    livetranslate_client.py的同级目录下新建另一个 python 文件,命名为main.py,并将以下代码复制进文件中:

    main.py

    import os
    import asyncio
    from livetranslate_client import LiveTranslateClient
    
    def print_banner():
        print("=" * 60)
        print("  基于通义千问 qwen3-livetranslate-flash-realtime")
        print("=" * 60 + "\n")
    
    def get_user_config():
        """获取用户配置"""
        print("请选择模式:")
        print("1. 语音+文本 [默认] | 2. 仅文本")
        mode_choice = input("请输入选项 (直接回车选择语音+文本): ").strip()
        audio_enabled = (mode_choice != "2")
    
        if audio_enabled:
            lang_map = {
                "1": "en", "2": "zh", "3": "ru", "4": "fr", "5": "de", "6": "pt",
                "7": "es", "8": "it", "9": "ko", "10": "ja", "11": "yue"
            }
            print("请选择翻译目标语言 (音频+文本 模式):")
            print("1. 英语 | 2. 中文 | 3. 俄语 | 4. 法语 | 5. 德语 | 6. 葡萄牙语 | 7. 西班牙语 | 8. 意大利语 | 9. 韩语 | 10. 日语 | 11. 粤语")
        else:
            lang_map = {
                "1": "en", "2": "zh", "3": "ru", "4": "fr", "5": "de", "6": "pt", "7": "es", "8": "it",
                "9": "id", "10": "ko", "11": "ja", "12": "vi", "13": "th", "14": "ar",
                "15": "yue", "16": "hi", "17": "el", "18": "tr"
            }
            print("请选择翻译目标语言 (仅文本 模式):")
            print("1. 英语 | 2. 中文 | 3. 俄语 | 4. 法语 | 5. 德语 | 6. 葡萄牙语 | 7. 西班牙语 | 8. 意大利语 | 9. 印尼语 | 10. 韩语 | 11. 日语 | 12. 越南语 | 13. 泰语 | 14. 阿拉伯语 | 15. 粤语 | 16. 印地语 | 17. 希腊语 | 18. 土耳其语")
    
        choice = input("请输入选项 (默认取第一个): ").strip()
        target_language = lang_map.get(choice, next(iter(lang_map.values())))
    
        voice = None
        if audio_enabled:
            print("\n请选择语音合成声音:")
            voice_map = {"1": "Cherry", "2": "Nofish", "3": "Sunny", "4": "Jada", "5": "Dylan", "6": "Peter", "7": "Eric", "8": "Kiki"}
            print("1. Cherry (女声) [默认] | 2. Nofish (男声) | 3. 晴儿 Sunny (四川女声) | 4. 阿珍 Jada (上海女声) | 5. 晓东 Dylan (北京男声) | 6. 李彼得 Peter (天津男声) | 7. 程川 Eric (四川男声) | 8. 阿清 Kiki (粤语女声)")
            voice_choice = input("请输入选项 (直接回车选择Cherry): ").strip()
            voice = voice_map.get(voice_choice, "Cherry")
        return target_language, voice, audio_enabled
    
    async def main():
        """主程序入口"""
        print_banner()
        
        api_key = os.environ.get("DASHSCOPE_API_KEY")
        if not api_key:
            print("[ERROR] 请设置环境变量 DASHSCOPE_API_KEY")
            print("  例如: export DASHSCOPE_API_KEY='your_api_key_here'")
            return
            
        target_language, voice, audio_enabled = get_user_config()
        print("\n配置完成:")
        print(f"  - 目标语言: {target_language}")
        if audio_enabled:
            print(f"  - 合成声音: {voice}")
        else:
            print("  - 输出模式: 仅文本")
        
        client = LiveTranslateClient(api_key=api_key, target_language=target_language, voice=voice, audio_enabled=audio_enabled)
        
        # 定义回调函数
        def on_translation_text(text):
            print(text, end="", flush=True)
    
        try:
            print("正在连接到翻译服务...")
            await client.connect()
            
            # 根据模式启动音频播放
            client.start_audio_player()
            
            print("\n" + "-" * 60)
            print("连接成功!请对着麦克风说话。")
            print("程序将实时翻译您的语音并播放结果。按 Ctrl+C 退出。")
            print("-" * 60 + "\n")
    
            # 并发运行消息处理和麦克风录音
            message_handler = asyncio.create_task(client.handle_server_messages(on_translation_text))
            tasks = [message_handler]
            # 无论是否启用音频输出,都需要从麦克风捕获音频进行翻译
            microphone_streamer = asyncio.create_task(client.start_microphone_streaming())
            tasks.append(microphone_streamer)
    
            await asyncio.gather(*tasks)
    
        except KeyboardInterrupt:
            print("\n\n用户中断,正在退出...")
        except Exception as e:
            print(f"\n发生严重错误: {e}")
        finally:
            print("\n正在清理资源...")
            await client.close()
            print("程序已退出。")
    
    if __name__ == "__main__":
        asyncio.run(main())

    运行main.py,通过麦克风说出要翻译的句子,模型会实时返回翻译完成的音频与文本。系统会检测您的音频起始位置并自动发送到服务器,无需手动发送。

视觉辅助翻译

qwen3-livetranslate-flash-realtime 模型可以接收图像输入,辅助音频翻译,适用于同音异义、低频专有名词识别场景。

将以下示例图片下载到本地:口罩.png面具.png

将以下代码下载到livetranslate_client.py同级目录并运行,向麦克风说"What is mask?",在输入口罩图片时,模型会翻译为“什么是口罩?”;输入面具图片时,模型会翻译为“什么是面具?”。

import os
import time
import json
import asyncio
import contextlib
import functools

from livetranslate_client import LiveTranslateClient

# 可改为面具.png
IMAGE_PATH = "口罩.png"
RECORD_SECONDS = 6

def print_banner():
    print("=" * 60)
    print("  基于通义千问 qwen3-livetranslate-flash-realtime —— 单轮交互示例 (mask)")
    print("=" * 60 + "\n")

async def stream_microphone_once(client: LiveTranslateClient, image_bytes: bytes, duration: int = RECORD_SECONDS):
    pa = client.pyaudio_instance
    stream = pa.open(
        format=client.input_format,
        channels=client.input_channels,
        rate=client.input_rate,
        input=True,
        frames_per_buffer=client.input_chunk,
    )
    print(f"[INFO] 开始录音 {duration} 秒,请讲话……")
    start_t = time.time()
    loop = asyncio.get_event_loop()
    last_img_time = 0.0
    frame_interval = 0.5  # 2 fps
    try:
        while time.time() - start_t < duration and client.is_connected:
            data = await loop.run_in_executor(None, stream.read, client.input_chunk)
            await client.send_audio_chunk(data)

            # 每 0.5 秒追加一帧图片
            now = time.time()
            if now - last_img_time >= frame_interval:
                await client.send_image_frame(image_bytes)
                last_img_time = now
    finally:
        stream.stop_stream()
        stream.close()

    # 提交视频缓冲区(根据官方规范,仍使用 input_audio_buffer.commit)
    await client.ws.send(
        json.dumps({
            "event_id": f"event_{int(time.time()*1000)}",
            "type": "input_audio_buffer.commit",
        })
    )
    print("[INFO] 音频与图像缓冲区已提交。")

async def send_single_image(client: LiveTranslateClient, image_path: str):
    with open(image_path, "rb") as f:
        img_bytes = f.read()
    await client.send_image_frame(img_bytes)
    await client.ws.send(
        json.dumps({
            "event_id": f"event_{int(time.time()*1000)}",
            "type": "input_image_buffer.commit",
        })
    )
    print(f"[INFO] 已发送图像: {os.path.basename(image_path)}")

async def main():
    print_banner()
    api_key = os.environ.get("DASHSCOPE_API_KEY")
    if not api_key:
        print("[ERROR] 请先在环境变量 DASHSCOPE_API_KEY 中配置 API KEY")
        return

    client = LiveTranslateClient(api_key=api_key, target_language="zh", voice="Cherry", audio_enabled=True)

    def on_text(text: str):
        print(text, end="", flush=True)

    try:
        await client.connect()
        client.start_audio_player()
        message_task = asyncio.create_task(client.handle_server_messages(on_text))
        with open(IMAGE_PATH, "rb") as f:
            img_bytes = f.read()
        # 录音循环已包含图像帧,因此无需额外 send_single_image
        await stream_microphone_once(client, img_bytes, RECORD_SECONDS)
        await asyncio.sleep(15)
    finally:
        await client.close()
        if not message_task.done():
            message_task.cancel()
            with contextlib.suppress(asyncio.CancelledError):
                await message_task

if __name__ == "__main__":
    asyncio.run(main())

交互流程

实时语音翻译的交互流程遵循标准的 WebSocket 事件驱动模型,服务端自动检测语音起止并进行响应。

生命周期

客户端事件

服务端事件

会话初始化

session.update

会话配置

session.created

会话已创建

session.updated

会话配置已更新

用户音频输入

input_audio_buffer.append

添加音频到缓冲区

input_image_buffer.append

添加图片到缓冲区

服务器音频输出

response.created

服务端开始生成响应

response.output_item.added

响应时有新的输出内容

response.content_part.added

新的输出内容添加到assistant message

response.audio_transcript.delta

增量生成的转录文字

response.audio.delta

模型增量生成的音频

response.audio_transcript.done

文本转录完成

response.audio.done

音频生成完成

response.content_part.done

Assistant message 的文本或音频内容流式输出完成

response.output_item.done

Assistant message 的整个输出项流式传输完成

response.done

响应完成

API 参考

请参见实时音视频翻译-通义千问

计费说明

请参见模型列表与价格

支持的语种

语种代码

语种

支持的输出模态

en

英语

音频+文本

zh

中文

音频+文本

ru

俄语

音频+文本

fr

法语

音频+文本

de

德语

音频+文本

pt

葡萄牙语

音频+文本

es

西班牙语

音频+文本

it

意大利语

音频+文本

id

印尼语

文本

ko

韩语

音频+文本

ja

日语

音频+文本

vi

越南语

文本

th

泰语

文本

ar

阿拉伯语

文本

yue

粤语

音频+文本

hi

印地语

文本

el

希腊语

文本

tr

土耳其语

文本

支持的音色

音色名

voice参数

音色效果

描述

支持的语种

芊悦

Cherry

阳光积极、亲切自然小姐姐。

中文、英语、法语、德语、俄语、意大利语、西班牙语、葡萄牙语、日语、韩语

不吃鱼

Nofish

不会翘舌音的设计师。

中文、英语、法语、德语、俄语、意大利语、西班牙语、葡萄牙语、日语、韩语

上海-阿珍

Jada

风风火火的沪上阿姐。

中文

北京-晓东

Dylan

北京胡同里长大的少年。

中文

四川-晴儿

Sunny

甜到你心里的川妹子。

中文

天津-李彼得

Peter

天津相声,专业捧人。

中文

粤语-阿清

Kiki

甜美的港妹闺蜜。

粤语

四川-程川

Eric

一个跳脱市井的四川成都男子。

中文