qwen-audio-3.0-realtime-plus
Mô hình hội thoại giọng nói trực tiếp, nhận giọng nói và văn bản, trả lời bằng giọng nói hoặc văn bản. Được thiết kế cho nhịp giao tiếp tự nhiên và khả năng tương tác với công cụ.
Về mô hình
Mô tả này trình bày khả năng của mô hình. Đầu vào, đầu ra và tùy chọn có trên Ailoot được liệt kê bên dưới cho phương thức đã chọn.
Qwen-Audio-3.0-Realtime-Plus là mô hình của Alibaba dành cho hội thoại giọng nói trực tiếp. Mô hình nhận giọng nói và văn bản, trả về âm thanh và văn bản, đồng thời hỗ trợ trò chuyện hai chiều với việc trao đổi lượt lời tự nhiên. Âm thanh có thể được gửi và nhận từng phần, nên tương tác diễn ra ngay trong quá trình trò chuyện.
Khi người đối thoại đã nói hết ý
Có một số cách xác định ranh giới lượt lời: dựa trên hoạt động âm thanh, mức độ hoàn chỉnh về ý nghĩa hoặc điều khiển tường minh. Ở phía nhà sản xuất, chế độ được chọn trước khi gửi âm thanh đầu tiên; muốn đổi sau khi cuộc trò chuyện đã bắt đầu cần tạo kết nối mới. Khả năng hỗ trợ cách điều khiển này phụ thuộc vào phương thức được chọn. Chế độ ngữ nghĩa xét đến khoảng dừng và những từ đệm: một thoáng ngập ngừng không nhất thiết có nghĩa người dùng đã nói hết ý. Lời nói mới của người dùng có thể ngắt câu trả lời đang được tạo để cuộc trò chuyện tiếp tục theo lượt lời tiếp theo. Trong chế độ ngữ nghĩa, có thể định hướng nhận dạng theo mẫu giọng của người đối thoại đã chọn, giúp giảm ảnh hưởng từ giọng người khác và tiếng ồn nền.
Chỉ dẫn xác định vai trò của trợ lý và phong cách giao tiếp. Cách thể hiện giọng nói có thể xét đến sắc thái, tốc độ và cảm xúc; phiên bản 3.0 có năm giọng hệ thống và các giọng tạo theo mẫu lời nói. Mô hình hỗ trợ 11 ngôn ngữ, gồm tiếng Nga, cùng những biến thể phương ngữ tiếng Trung do nhà sản xuất nêu. Ở phía nhà sản xuất, giọng được đặt trong lần cập nhật cài đặt phiên đầu tiên; việc gửi giọng mới sau đó trong cùng cuộc trò chuyện sẽ bị bỏ qua. Các cài đặt này đòi hỏi phương thức truy cập được chọn có hỗ trợ.
Công cụ và lịch sử trò chuyện
Mô hình hỗ trợ gọi hàm. Mô hình tạo ra hành động cần thực hiện, ứng dụng kết nối thực thi rồi trả kết quả vào hội thoại. Nhờ đó, có thể xây dựng cuộc trò chuyện dựa trên dữ liệu thực tế và tiếp tục sau thao tác đã hoàn thành. Trợ lý giọng nói có thể sử dụng kết quả công cụ trong khi vẫn giữ ngữ cảnh cuộc trò chuyện. Các khả năng của nhà sản xuất còn gồm tìm kiếm web tích hợp, nếu phương thức đã chọn cung cấp tính năng này. Không thể đồng thời bật tìm kiếm web và gọi hàm trong cùng một phiên.
Theo mặc định, lịch sử chứa 20 lượt trò chuyện; phạm vi cho phép từ một đến 50. Giới hạn âm thanh tích lũy là 300 giây; các phần lịch sử cũ bị xóa khi vượt giới hạn. Đây là giới hạn khác với thời lượng của một lượt lời riêng lẻ: lịch sử xác định những tư liệu trước đó còn được sử dụng khi tiếp tục hội thoại.
Ngữ cảnh văn bản và âm thanh
Dung lượng ngữ cảnh chính thức là 40 960 token. Độ dài đầu vào tối đa là 16 384 token, đầu ra là 8192; các giới hạn đầu vào và đầu ra tương tự cũng được nêu cho chế độ suy luận, với giới hạn riêng của chuỗi suy luận là 1024 token.
Âm thanh truyền luồng dùng PCM đơn kênh, biểu diễn 16 bit: đầu vào 16 kHz, đầu ra 24 kHz. Dữ liệu văn bản và âm thanh thuộc cùng một cuộc trò chuyện. Đầu vào hình ảnh và đầu ra ảnh chưa được công bố cho mô hình cụ thể này; chuyên môn của nó là lời nói, văn bản và tương tác bằng giọng nói.
Ailoot · Giọng nói thời gian thực GET /v1/realtime?model=qwen-audio-3.0-realtime-plus qwen-audio-3.0-realtime-plus
qwen-audio-3.0-realtime-plusBắt đầu
Mô hình hội thoại giọng nói trực tiếp, nhận giọng nói và văn bản, trả lời bằng giọng nói hoặc văn bản. Được thiết kế cho nhịp giao tiếp tự nhiên và khả năng tương tác với công cụ.
- Đầu vào được chấp nhận
- Văn bản · Âm thanh
- Kết quả
- Văn bản · Âm thanh
Có trên Ailoot · đầu vào & phương thức
Ailoot · Giọng nói thời gian thực GET /v1/realtime?model=qwen-audio-3.0-realtime-plus
- Đầu vào
text,audio- Đầu ra
text,audio- Định dạng đầu ra
- các sự kiện phiên
| Trường | Loại | Yêu cầu | Giá trị & giới hạn | Mặc định |
|---|---|---|---|---|
Trườngquery.model | Loạistring | Yêu cầuBắt buộc | Giá trị & giới hạn qwen-audio-3.0-realtime-plus | Mặc định— |
Trườngsession.input_audio_format | Loạistring | Yêu cầuKhông bắt buộc | Giá trị & giới hạn pcm16, pcm | Mặc định— |
Trườngsession.output_audio_format | Loạistring | Yêu cầuKhông bắt buộc | Giá trị & giới hạn pcm16, pcm | Mặc định— |
Trườngsession.instructions | Loạistring | Yêu cầuKhông bắt buộc | Giá trị & giới hạn Giới hạn áp dụng cho: chính sách phiên đã chọn | Mặc định— |
Trườngsession.max_history_turns | Loạiinteger | Yêu cầuKhông bắt buộc | Giá trị & giới hạn Tối thiểu: 1 Giới hạn áp dụng cho: chính sách phiên đã chọn | Mặc định— |
Trườnginput_audio_buffer.append.audio | Loạibase64_string | Yêu cầuBắt buộc | Giá trị & giới hạn Nội dung đầu vào: PCM16 đơn kênh; đầu vào 16 kHz, đầu ra 24 kHz; độ dài byte không rỗng và chẵn | Mặc định— |
Tổ hợp tư liệu đầu vào
realtime_text_audio
Tham số phương thức và vòng đời
| Tham số | Hợp đồng |
|---|---|
Tham sốmaterial_types | Hợp đồngtext, audio |
Tham sốrequired | Hợp đồngnull |
Tham sốoptional_controls | Hợp đồngnull |
Tham sốcontent_type | Hợp đồngWebSocket |
Vòng đời: exact retained published method
Cấu trúc phương thức và ID là chính xác; khả năng của nhà cung cấp tách biệt với việc cho phép tiếp nhận yêu cầu.
Bảng giá
Mức phí phương thức Ailoot
GET /v1/realtime?model=qwen-audio-3.0-realtime-plus- Đầu vào
- 0,0008 US$ / 1K
- Đầu ra
- 0,0064 US$ / 1K
- Đầu vào
- 0,0048 US$ mỗi phút âm thanh
- Đầu ra
- 0,018 US$ mỗi phút âm thanh đầu ra
Ailoot tạm giữ một khoản ước tính trước yêu cầu. Sau khi có kết quả, phí cuối cùng được quyết toán theo mức sử dụng đo được. Việc quyết toán khi truyền luồng dùng bản ghi mức sử dụng cuối cùng. Cách hoạt động của cơ chế tạm giữ và quyết toán →
Ví dụ yêu cầu
Ailoot · Giọng nói thời gian thực
# Install the documented client once: python3 -m pip install websockets
import base64, json, os, time, wave
from pathlib import Path
from websockets.sync.client import connect
key = os.environ.get("AILOOT_API_KEY", "")
if not key.strip():
raise SystemExit("Set your AILOOT_API_KEY before connecting")
file = Path(os.environ.get("AILOOT_TEXT_FILE", ""))
if not file.is_file(): raise SystemExit("Set AILOOT_TEXT_FILE to your actual UTF-8 material")
material = file.read_text(encoding="utf-8")
if not material.strip(): raise SystemExit("Text material must not be empty")
out = Path("realtime-results")
out.mkdir(exist_ok=True)
audio, texts, complete = {}, {}, []
current_response = None
pending = False
deadline = time.monotonic() + 570 # Local client bound; lower server/session limits still apply.
def receive(ws, log):
global current_response, pending
left = deadline - time.monotonic()
if left <= 0:
raise TimeoutError("Client session limit; preserve IDs and partial results, do not replay")
event = json.loads(ws.recv(timeout=min(60, left)))
log.write(json.dumps(event, ensure_ascii=False) + "\n")
log.flush()
kind = event.get("type")
if kind == "error":
raise RuntimeError(json.dumps(event, ensure_ascii=False))
if kind == "response.created":
current_response = event["response"]["id"]
if kind in {"response.audio.delta", "response.output_audio.delta", "response.text.delta", "response.output_text.delta", "response.audio_transcript.delta", "response.output_audio_transcript.delta", "response.text.done", "response.audio_transcript.done"}:
identity = (event["response_id"], event["item_id"], event["output_index"], event["content_index"])
if kind in {"response.audio.delta", "response.output_audio.delta"}:
raw = base64.b64decode(event["delta"], validate=True)
if len(raw) % 2: raise ValueError("Output PCM16 chunk must have an even byte length")
audio.setdefault(identity, bytearray()).extend(raw)
elif kind.endswith(".done"):
texts[identity] = event.get("text", event.get("transcript", ""))
else:
texts[identity] = texts.get(identity, "") + event["delta"]
print(event["delta"], end="", flush=True)
if kind == "response.done":
response = event["response"]
complete.append(response)
if current_response is None: current_response = response["id"]
if response["id"] == current_response: pending = False
return event
def wait_for(ws, log, kind):
while True:
event = receive(ws, log)
if event.get("type") == kind: return event
def send(ws, event):
ws.send(json.dumps(event, ensure_ascii=False))
try:
# One exact model query; no reconnect/retry loop and no provider credentials.
with connect("wss://api.ailoot.ai/v1/realtime?model=qwen-audio-3.0-realtime-plus", additional_headers={"Authorization": "Bearer " + key}) as ws:
with (out / "events.jsonl").open("w", encoding="utf-8") as log:
wait_for(ws, log, "session.created")
send(ws, {"type":"session.update", "session":{"modalities":["audio","text"], "input_audio_format":"pcm", "output_audio_format":"pcm", "turn_detection":None}})
wait_for(ws, log, "session.updated")
send(ws, {"type":"conversation.item.create", "item":{"type":"message", "role":"user", "content":[{"type":"input_text", "text":material}]}})
send(ws, {"type":"response.create"})
pending = True
try:
while pending: receive(ws, log)
except KeyboardInterrupt:
# Cancel the actual current inference, then preserve its returned status.
send(ws, {"type":"response.cancel"})
while pending: receive(ws, log)
if not complete or complete[-1].get("status") != "completed":
raise RuntimeError("Response did not complete normally; inspect saved events and status")
finally:
manifest = {"responses":complete, "parts":[]}
for number, identity in enumerate(dict.fromkeys(list(audio) + list(texts))):
record = {"response_id":identity[0], "item_id":identity[1], "output_index":identity[2], "content_index":identity[3]}
if identity in audio:
raw = bytes(audio[identity])
pcm_file = out / ("audio-" + str(number) + ".pcm")
wav_file = out / ("audio-" + str(number) + ".wav")
pcm_file.write_bytes(raw)
with wave.open(str(wav_file), "wb") as wav:
wav.setnchannels(1); wav.setsampwidth(2); wav.setframerate(24000); wav.writeframes(raw)
record.update({"pcm":str(pcm_file), "wav":str(wav_file), "sample_rate_hz":24000})
if identity in texts:
text_file = out / ("text-" + str(number) + ".txt")
text_file.write_text(texts[identity], encoding="utf-8")
record["text"] = str(text_file)
manifest["parts"].append(record)
(out / "results.json").write_text(json.dumps(manifest, ensure_ascii=False, indent=2), encoding="utf-8")
print("\nSaved every received event and result in", out)
# Install the documented client once: python3 -m pip install websockets
import base64, json, os, time, wave
from pathlib import Path
from websockets.sync.client import connect
key = os.environ.get("AILOOT_API_KEY", "")
if not key.strip():
raise SystemExit("Set your AILOOT_API_KEY before connecting")
file = Path(os.environ.get("AILOOT_AUDIO_FILE", ""))
if not file.is_file(): raise SystemExit("Set AILOOT_AUDIO_FILE to your raw PCM16 mono 16-kHz recording")
material = file.read_bytes()
if not material or len(material) % 2 or material.startswith(b"RIFF"):
raise SystemExit("Use nonempty signed little-endian PCM16 mono 16-kHz bytes, not a WAV header")
out = Path("realtime-results")
out.mkdir(exist_ok=True)
audio, texts, complete = {}, {}, []
current_response = None
pending = False
deadline = time.monotonic() + 570 # Local client bound; lower server/session limits still apply.
def receive(ws, log):
global current_response, pending
left = deadline - time.monotonic()
if left <= 0:
raise TimeoutError("Client session limit; preserve IDs and partial results, do not replay")
event = json.loads(ws.recv(timeout=min(60, left)))
log.write(json.dumps(event, ensure_ascii=False) + "\n")
log.flush()
kind = event.get("type")
if kind == "error":
raise RuntimeError(json.dumps(event, ensure_ascii=False))
if kind == "response.created":
current_response = event["response"]["id"]
if kind in {"response.audio.delta", "response.output_audio.delta", "response.text.delta", "response.output_text.delta", "response.audio_transcript.delta", "response.output_audio_transcript.delta", "response.text.done", "response.audio_transcript.done"}:
identity = (event["response_id"], event["item_id"], event["output_index"], event["content_index"])
if kind in {"response.audio.delta", "response.output_audio.delta"}:
raw = base64.b64decode(event["delta"], validate=True)
if len(raw) % 2: raise ValueError("Output PCM16 chunk must have an even byte length")
audio.setdefault(identity, bytearray()).extend(raw)
elif kind.endswith(".done"):
texts[identity] = event.get("text", event.get("transcript", ""))
else:
texts[identity] = texts.get(identity, "") + event["delta"]
print(event["delta"], end="", flush=True)
if kind == "response.done":
response = event["response"]
complete.append(response)
if current_response is None: current_response = response["id"]
if response["id"] == current_response: pending = False
return event
def wait_for(ws, log, kind):
while True:
event = receive(ws, log)
if event.get("type") == kind: return event
def send(ws, event):
ws.send(json.dumps(event, ensure_ascii=False))
try:
# One exact model query; no reconnect/retry loop and no provider credentials.
with connect("wss://api.ailoot.ai/v1/realtime?model=qwen-audio-3.0-realtime-plus", additional_headers={"Authorization": "Bearer " + key}) as ws:
with (out / "events.jsonl").open("w", encoding="utf-8") as log:
wait_for(ws, log, "session.created")
send(ws, {"type":"session.update", "session":{"modalities":["audio","text"], "input_audio_format":"pcm", "output_audio_format":"pcm", "turn_detection":None}})
wait_for(ws, log, "session.updated")
for offset in range(0, len(material), 640):
send(ws, {"type":"input_audio_buffer.append", "audio":base64.b64encode(material[offset:offset+640]).decode("ascii")})
time.sleep(0.02)
send(ws, {"type":"input_audio_buffer.commit"})
wait_for(ws, log, "input_audio_buffer.committed")
send(ws, {"type":"response.create"})
pending = True
try:
while pending: receive(ws, log)
except KeyboardInterrupt:
# Cancel the actual current inference, then preserve its returned status.
send(ws, {"type":"response.cancel"})
while pending: receive(ws, log)
if not complete or complete[-1].get("status") != "completed":
raise RuntimeError("Response did not complete normally; inspect saved events and status")
finally:
manifest = {"responses":complete, "parts":[]}
for number, identity in enumerate(dict.fromkeys(list(audio) + list(texts))):
record = {"response_id":identity[0], "item_id":identity[1], "output_index":identity[2], "content_index":identity[3]}
if identity in audio:
raw = bytes(audio[identity])
pcm_file = out / ("audio-" + str(number) + ".pcm")
wav_file = out / ("audio-" + str(number) + ".wav")
pcm_file.write_bytes(raw)
with wave.open(str(wav_file), "wb") as wav:
wav.setnchannels(1); wav.setsampwidth(2); wav.setframerate(24000); wav.writeframes(raw)
record.update({"pcm":str(pcm_file), "wav":str(wav_file), "sample_rate_hz":24000})
if identity in texts:
text_file = out / ("text-" + str(number) + ".txt")
text_file.write_text(texts[identity], encoding="utf-8")
record["text"] = str(text_file)
manifest["parts"].append(record)
(out / "results.json").write_text(json.dumps(manifest, ensure_ascii=False, indent=2), encoding="utf-8")
print("\nSaved every received event and result in", out)
Nhận và lưu kết quả
Ailoot · Giọng nói thời gian thực
các sự kiện phiên
Lưu tất cả kết quả đã hoàn tất
Lưu mọi phản hồi hoàn chỉnh, tệp và phần nội dung được trả về.
Ghép mọi phần âm thanh tăng dần được trả về và kết quả văn bản/sự kiện cho từng ID phản hồi thực tế.
Nếu cần kiểm tra phản hồi gốc
Giữ lại các ID phiên/phản hồi/sự kiện thực tế và bằng chứng xác nhận.
Lỗi và bước tiếp theo
| Phản hồi | Điều kiện | Bước tiếp theo |
|---|---|---|
Phản hồi426 · invalid_request_error | Điều kiệnKhông nâng cấp kết nối WebSocket | Bước tiếp theoDùng ứng dụng khách WebSocket với Upgrade: websocket. |
Bí danh
Bí danh mô hình
Ailoot qwen-audio-3.0-realtime-plus
Bí danh đường dẫn phương thức
Dùng các đường dẫn phương thức hiển thị ở trên.
ID gọi liên quan
FAQ · qwen-audio-3.0-realtime-plus
- Có những đầu vào và kết quả nào?
GET /v1/realtime?model=qwen-audio-3.0-realtime-plus·qwen-audio-3.0-realtime-plus:text,audio→text,audio- Áp dụng những giới hạn nào?
GET /v1/realtime?model=qwen-audio-3.0-realtime-plus·qwen-audio-3.0-realtime-plus:session.max_history_turns.minimum:1