qwen-audio-3.0-realtime-plus
Model do prowadzenia rozmów głosowych na żywo, który przyjmuje mowę i tekst oraz odpowiada głosem lub tekstem. Przeznaczony do komunikacji w naturalnym tempie i współpracy z narzędziami.
O modelu
Ten opis przedstawia możliwości modelu. Dane wejściowe, wyniki i opcje dostępne w Ailoot podano poniżej dla wybranej metody.
Qwen-Audio-3.0-Realtime-Plus to model Alibaba do prowadzenia rozmów głosowych na żywo. Przyjmuje mowę i tekst, odpowiada dźwiękiem i tekstem oraz obsługuje dwustronną rozmowę z naturalną wymianą wypowiedzi. Dźwięk można przesyłać i odbierać partiami, dzięki czemu interakcja rozwija się w trakcie rozmowy.
Kiedy rozmówca zakończył myśl
Przewidziano kilka sposobów określania granic wypowiedzi: na podstawie aktywności dźwiękowej, domknięcia znaczenia oraz jawnego sterowania. U producenta tryb wybiera się przed przesłaniem pierwszego dźwięku; jego zmiana po rozpoczęciu rozmowy wymaga nowego połączenia. Obsługa tego sterowania zależy od wybranej metody. Tryb semantyczny uwzględnia pauzy i wypełniacze mowy: krótkie zawahanie nie musi oznaczać, że użytkownik zakończył myśl. Nowa wypowiedź użytkownika może przerwać generowaną odpowiedź, aby rozmowa była kontynuowana z uwzględnieniem kolejnej wypowiedzi. W trybie semantycznym można ukierunkować rozpoznawanie na próbkę mowy wybranego rozmówcy, aby ograniczyć wpływ innych głosów i szumu tła.
Instrukcje określają rolę asystenta i styl komunikacji. Sposób wypowiedzi głosowej może uwzględniać ton, tempo i emocje; wersja 3.0 oferuje pięć głosów systemowych oraz głosy odtwarzane na podstawie próbki mowy. Model obsługuje 11 języków, w tym rosyjski, a także wskazane przez producenta chińskie warianty dialektalne. U producenta głos ustala się podczas pierwszej aktualizacji ustawień sesji; późniejsze przesłanie nowego głosu w tej samej rozmowie jest ignorowane. Ustawienia te wymagają obsługi przez wybrany sposób korzystania z modelu.
Narzędzia i historia rozmowy
Obsługiwane jest wywoływanie funkcji. Model określa potrzebne działanie, połączona aplikacja je wykonuje i zwraca wynik do rozmowy. Pozwala to prowadzić rozmowę w oparciu o rzeczywiste dane i kontynuować ją po wykonaniu operacji. Asystent głosowy może korzystać z wyników narzędzi, zachowując kontekst rozmowy. Możliwości producenta obejmują także wbudowane wyszukiwanie w internecie, jeżeli udostępnia je wybrana metoda. Wyszukiwania w internecie i wywoływania funkcji nie można włączyć jednocześnie w jednej sesji.
Domyślnie historia obejmuje 20 tur rozmowy; dostępny zakres wynosi od jednej do 50. Dla zgromadzonego dźwięku obowiązuje limit 300 sekund; po przekroczeniu ograniczeń starsze części historii są usuwane. Jest to inny parametr niż długość pojedynczej wypowiedzi: historia określa, który wcześniejszy materiał pozostaje dostępny przy kontynuowaniu dialogu.
Kontekst tekstowy i dźwięk
Formalny kontekst wynosi 40 960 tokenów. Maksymalna długość wejścia to 16 384 tokeny, a wyjścia — 8192; takie same limity wejścia i wyjścia podano dla trybu rozumowania, z osobnym limitem łańcucha rozumowania wynoszącym 1024 tokeny.
Dźwięk strumieniowy wykorzystuje jednokanałowy PCM z reprezentacją 16-bitową: na wejściu — 16 kHz, na wyjściu — 24 kHz. Dane tekstowe i dźwiękowe należą do jednej rozmowy. Dla tego konkretnego modelu nie zadeklarowano wejścia wizualnego ani generowania obrazów; jego specjalizacją są mowa, tekst i interakcja głosowa.
Ailoot · Głos w czasie rzeczywistym GET /v1/realtime?model=qwen-audio-3.0-realtime-plus qwen-audio-3.0-realtime-plus
qwen-audio-3.0-realtime-plusStart
Model do prowadzenia rozmów głosowych na żywo, który przyjmuje mowę i tekst oraz odpowiada głosem lub tekstem. Przeznaczony do komunikacji w naturalnym tempie i współpracy z narzędziami.
- Akceptowane dane wejściowe
- Tekst · Audio
- Wyniki
- Tekst · Audio
Dostępne w Ailoot · dane wejściowe i metody
Ailoot · Głos w czasie rzeczywistym GET /v1/realtime?model=qwen-audio-3.0-realtime-plus
- Wejście
text,audio- Wyjście
text,audio- Format wyjściowy
- zdarzenia sesji
| Pole | Typ | Wymaganie | Wartości i limity | Domyślnie |
|---|---|---|---|---|
Polequery.model | Typstring | WymaganieWymagane | Wartości i limity qwen-audio-3.0-realtime-plus | Domyślnie— |
Polesession.input_audio_format | Typstring | WymaganieOpcjonalne | Wartości i limity pcm16, pcm | Domyślnie— |
Polesession.output_audio_format | Typstring | WymaganieOpcjonalne | Wartości i limity pcm16, pcm | Domyślnie— |
Polesession.instructions | Typstring | WymaganieOpcjonalne | Wartości i limity Limit dotyczy: wybrana polityka sesji | Domyślnie— |
Polesession.max_history_turns | Typinteger | WymaganieOpcjonalne | Wartości i limity Minimum: 1 Limit dotyczy: wybrana polityka sesji | Domyślnie— |
Poleinput_audio_buffer.append.audio | Typbase64_string | WymaganieWymagane | Wartości i limity Treść wejściowa: PCM16 mono; wejście 16 kHz, wyjście 24 kHz; niezerowa, parzysta liczba bajtów | Domyślnie— |
Kombinacje materiałów wejściowych
realtime_text_audio
Parametry i cykl życia metody
| Parametr | Kontrakt |
|---|---|
Parametrmaterial_types | Kontrakttext, audio |
Parametrrequired | Kontraktnull |
Parametroptional_controls | Kontraktnull |
Parametrcontent_type | KontraktWebSocket |
Cykl życia: exact retained published method
Struktury metod i ID są dokładne; możliwości dostawcy są odrębne od dopuszczenia żądania.
Cennik
Stawki metod Ailoot
GET /v1/realtime?model=qwen-audio-3.0-realtime-plus- Wejście
- 0,0008 USD / 1K
- Wyjście
- 0,0064 USD / 1K
- Wejście
- 0,0048 USD za minutę dźwięku
- Wyjście
- 0,018 USD za minutę dźwięku wyjściowego
Ailoot rezerwuje szacowaną kwotę przed żądaniem. Po otrzymaniu wyniku rozlicza ostateczną opłatę według zmierzonego użycia. Rozliczenie strumieniowania korzysta z końcowego rekordu użycia. Jak działają rezerwacja i rozliczenie →
Przykładowe żądania
Ailoot · Głos w czasie rzeczywistym
# 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)
Odbieranie i zapisywanie wyników
Ailoot · Głos w czasie rzeczywistym
zdarzenia sesji
Zachowaj wszystkie ukończone wyniki
Zachowaj każdą kompletną zwróconą odpowiedź, plik i część treści.
Połącz każdy zwrócony fragment przyrostowy dźwięku oraz wynik tekstowy lub zdarzenie dla każdego rzeczywistego identyfikatora odpowiedzi.
Jeśli trzeba sprawdzić pierwotną odpowiedź
Zachowaj rzeczywiste identyfikatory sesji, odpowiedzi i zdarzeń oraz potwierdzenia.
Błędy i dalsze kroki
| Odpowiedź | Warunek | Następny krok |
|---|---|---|
Odpowiedź426 · invalid_request_error | WarunekBrak przełączenia protokołu na WebSocket | Następny krokUżyj klienta WebSocket z Upgrade: websocket. |
Aliasy
Aliasy modelu
Ailoot qwen-audio-3.0-realtime-plus
Aliasy ścieżek metod
Użyj ścieżek metod podanych powyżej.
Powiązane ID modeli
FAQ · qwen-audio-3.0-realtime-plus
- Jakie dane wejściowe i wyniki są dostępne?
GET /v1/realtime?model=qwen-audio-3.0-realtime-plus·qwen-audio-3.0-realtime-plus:text,audio→text,audio- Jakie limity obowiązują?
GET /v1/realtime?model=qwen-audio-3.0-realtime-plus·qwen-audio-3.0-realtime-plus:session.max_history_turns.minimum:1