{
  "aboutHtml": "<p>Qwen-Audio-3.0-Realtime-Plus ist ein Modell von Alibaba für Sprachdialoge in Echtzeit. Es nimmt Sprache und Text entgegen, antwortet mit Audio und Text und unterstützt ein Gespräch in beide Richtungen mit natürlichem Wechsel der Gesprächsbeiträge. Audio kann abschnittsweise übertragen und empfangen werden, sodass sich die Interaktion während des Gesprächs entwickelt.</p><h4>Wann ein Gesprächsbeitrag abgeschlossen ist</h4><p>Es gibt mehrere Möglichkeiten, die Grenzen eines Gesprächsbeitrags zu erkennen: anhand der Sprachaktivität, der inhaltlichen Vollständigkeit oder durch ausdrückliche Steuerung. Beim Hersteller wird der Modus vor der Übertragung des ersten Audios gewählt; für eine Änderung nach Gesprächsbeginn ist eine neue Verbindung erforderlich. Ob diese Steuerung unterstützt wird, hängt von der gewählten Methode ab. Der semantische Modus berücksichtigt Pausen und Füllwörter: Ein kurzes Zögern bedeutet nicht zwangsläufig, dass der Nutzer seinen Gedanken abgeschlossen hat. Neue Nutzersprache kann die gerade erzeugte Antwort unterbrechen, damit das Gespräch unter Berücksichtigung des nächsten Beitrags weitergeht. Im semantischen Modus lässt sich die Erkennung an einer Sprachprobe des gewählten Gesprächspartners ausrichten, um fremde Stimmen und Hintergrundgeräusche weniger zu berücksichtigen.</p><p>Anweisungen bestimmen die Rolle des Assistenten und den Gesprächsstil. Die stimmliche Darstellung kann Ton, Tempo und Emotion berücksichtigen; für Version 3.0 sind fünf Systemstimmen sowie Stimmen nach einer Sprachprobe vorgesehen. Das Modell unterstützt 11 Sprachen, darunter Russisch, sowie die vom Hersteller genannten chinesischen Dialektvarianten. Beim Hersteller wird die Stimme bei der ersten Aktualisierung der Sitzungseinstellungen festgelegt; eine später übermittelte neue Stimme wird im selben Gespräch ignoriert. Diese Einstellungen benötigen Unterstützung durch die gewählte Zugriffsmethode.</p><h4>Werkzeuge und Gesprächsverlauf</h4><p>Funktionsaufrufe werden unterstützt. Das Modell formuliert die erforderliche Aktion, die verbundene Anwendung führt sie aus und gibt das Ergebnis an den Dialog zurück. So kann ein Gespräch auf tatsächlichen Daten aufbauen und nach einer ausgeführten Operation fortgesetzt werden. Der Sprachassistent kann Werkzeugergebnisse nutzen und dabei den Gesprächskontext beibehalten. Die Herstellerfunktionen umfassen ausserdem eine integrierte Websuche, sofern die gewählte Methode sie bereitstellt. Websuche und Funktionsaufrufe können nicht gleichzeitig in einer Sitzung aktiviert werden.</p><p>Standardmässig enthält der Verlauf 20 Gesprächsrunden; vorgesehen ist ein Bereich von einer bis 50. Für angesammeltes Audio gilt eine Grenze von 300 Sekunden; bei Überschreitung der Grenzen werden ältere Teile des Verlaufs entfernt. Das unterscheidet sich von der Dauer eines einzelnen Beitrags: Der Verlauf bestimmt, welches frühere Material bei der Fortsetzung des Dialogs verfügbar bleibt.</p><h4>Textkontext und Audio</h4><p>Der formale Kontext umfasst 40 960 Tokens. Die maximale Eingabelänge beträgt 16 384 Tokens, die Ausgabelänge 8192; dieselben Eingabe- und Ausgabegrenzen gelten für den Reasoning-Modus, mit einer separaten Grenze von 1024 Tokens für die Reasoning-Kette.</p><p>Für Audio-Streaming ist einkanaliges PCM mit 16-Bit-Darstellung vorgesehen: bei der Eingabe 16 kHz, bei der Ausgabe 24 kHz. Text- und Audiodaten gehören zu einem gemeinsamen Gespräch. Visuelle Eingabe und Bildausgabe sind für dieses konkrete Modell nicht angekündigt; sein Schwerpunkt liegt auf Sprache, Text und stimmlicher Interaktion.</p>",
  "aboutText": "Qwen-Audio-3.0-Realtime-Plus ist ein Modell von Alibaba für Sprachdialoge in Echtzeit. Es nimmt Sprache und Text entgegen, antwortet mit Audio und Text und unterstützt ein Gespräch in beide Richtungen mit natürlichem Wechsel der Gesprächsbeiträge. Audio kann abschnittsweise übertragen und empfangen werden, sodass sich die Interaktion während des Gesprächs entwickelt.\n\n### Wann ein Gesprächsbeitrag abgeschlossen ist\n\nEs gibt mehrere Möglichkeiten, die Grenzen eines Gesprächsbeitrags zu erkennen: anhand der Sprachaktivität, der inhaltlichen Vollständigkeit oder durch ausdrückliche Steuerung. Beim Hersteller wird der Modus vor der Übertragung des ersten Audios gewählt; für eine Änderung nach Gesprächsbeginn ist eine neue Verbindung erforderlich. Ob diese Steuerung unterstützt wird, hängt von der gewählten Methode ab. Der semantische Modus berücksichtigt Pausen und Füllwörter: Ein kurzes Zögern bedeutet nicht zwangsläufig, dass der Nutzer seinen Gedanken abgeschlossen hat. Neue Nutzersprache kann die gerade erzeugte Antwort unterbrechen, damit das Gespräch unter Berücksichtigung des nächsten Beitrags weitergeht. Im semantischen Modus lässt sich die Erkennung an einer Sprachprobe des gewählten Gesprächspartners ausrichten, um fremde Stimmen und Hintergrundgeräusche weniger zu berücksichtigen.\n\nAnweisungen bestimmen die Rolle des Assistenten und den Gesprächsstil. Die stimmliche Darstellung kann Ton, Tempo und Emotion berücksichtigen; für Version 3.0 sind fünf Systemstimmen sowie Stimmen nach einer Sprachprobe vorgesehen. Das Modell unterstützt 11 Sprachen, darunter Russisch, sowie die vom Hersteller genannten chinesischen Dialektvarianten. Beim Hersteller wird die Stimme bei der ersten Aktualisierung der Sitzungseinstellungen festgelegt; eine später übermittelte neue Stimme wird im selben Gespräch ignoriert. Diese Einstellungen benötigen Unterstützung durch die gewählte Zugriffsmethode.\n\n### Werkzeuge und Gesprächsverlauf\n\nFunktionsaufrufe werden unterstützt. Das Modell formuliert die erforderliche Aktion, die verbundene Anwendung führt sie aus und gibt das Ergebnis an den Dialog zurück. So kann ein Gespräch auf tatsächlichen Daten aufbauen und nach einer ausgeführten Operation fortgesetzt werden. Der Sprachassistent kann Werkzeugergebnisse nutzen und dabei den Gesprächskontext beibehalten. Die Herstellerfunktionen umfassen ausserdem eine integrierte Websuche, sofern die gewählte Methode sie bereitstellt. Websuche und Funktionsaufrufe können nicht gleichzeitig in einer Sitzung aktiviert werden.\n\nStandardmässig enthält der Verlauf 20 Gesprächsrunden; vorgesehen ist ein Bereich von einer bis 50. Für angesammeltes Audio gilt eine Grenze von 300 Sekunden; bei Überschreitung der Grenzen werden ältere Teile des Verlaufs entfernt. Das unterscheidet sich von der Dauer eines einzelnen Beitrags: Der Verlauf bestimmt, welches frühere Material bei der Fortsetzung des Dialogs verfügbar bleibt.\n\n### Textkontext und Audio\n\nDer formale Kontext umfasst 40 960 Tokens. Die maximale Eingabelänge beträgt 16 384 Tokens, die Ausgabelänge 8192; dieselben Eingabe- und Ausgabegrenzen gelten für den Reasoning-Modus, mit einer separaten Grenze von 1024 Tokens für die Reasoning-Kette.\n\nFür Audio-Streaming ist einkanaliges PCM mit 16-Bit-Darstellung vorgesehen: bei der Eingabe 16 kHz, bei der Ausgabe 24 kHz. Text- und Audiodaten gehören zu einem gemeinsamen Gespräch. Visuelle Eingabe und Bildausgabe sind für dieses konkrete Modell nicht angekündigt; sein Schwerpunkt liegt auf Sprache, Text und stimmlicher Interaktion.",
  "editorialOverlay": {
    "copy_fields": null,
    "copy_sha256": null,
    "copy_source": null,
    "html_sha256": "e981a45adc37863cf1021241a9f9e2754ef81dead7385e51b0bddcfb0a6a5edf",
    "module_sha256": "ee9dc1c50b1e6a8fb7fa062030fcb4646b9aaaeb08be513b723a5a92a7290f06",
    "raw_model_unchanged": true,
    "schema": "ailoot-native-model-editorial-v1"
  },
  "locale": "de-ch",
  "methods": [
    {
      "html": "<div class=\"sheet-head\"><span class=\"mav\" aria-hidden=\"true\">Al</span><h2 id=\"sheet-title\">qwen-audio-3.0-realtime-plus</h2><button class=\"icon-btn\" type=\"button\" data-close-sheet aria-label=\"Schliessen\">×</button></div><div class=\"idline\"><span>Alibaba /</span><code>qwen-audio-3.0-realtime-plus</code><button type=\"button\" id=\"copy-id\">ID kopieren</button></div><nav class=\"card-jump-nav\" aria-label=\"Bereiche der Modellkarte\"><button type=\"button\" data-card-jump=\"overview\">Einstieg</button><button type=\"button\" data-card-jump=\"methods\">Eingaben und Methoden</button><button type=\"button\" data-card-jump=\"pricing\">Tarife</button><button type=\"button\" data-card-jump=\"examples\">Beispiele</button><button type=\"button\" data-card-jump=\"results\">Ergebnisse</button><button type=\"button\" data-card-jump=\"aliases\">Aliasnamen</button></nav><div class=\"card-method-tabs\" role=\"tablist\" aria-label=\"API-Methoden\"><button type=\"button\" role=\"tab\" tabindex=\"0\" aria-controls=\"card-method-content\" aria-selected=\"true\" id=\"card-method-tab-0\" data-card-method=\"Core|realtime|/v1/realtime?model=qwen-audio-3.0-realtime-plus|qwen-audio-3.0-realtime-plus\">Echtzeit</button></div><div id=\"card-method-content\" role=\"tabpanel\" aria-labelledby=\"card-method-tab-0\"><section class=\"card-section\" data-card-section=\"overview\"><h3 tabindex=\"-1\">Einstieg</h3><p class=\"mdesc-full\">Modell für Sprachdialoge in Echtzeit, das Sprache und Text entgegennimmt und mit Sprache oder Text antwortet. Ausgelegt auf ein natürliches Gesprächstempo und die Interaktion mit Werkzeugen.</p><dl class=\"card-io\" data-card-io><div><dt>Zulässige Eingaben</dt><dd>Text · Audio</dd></div><div><dt>Ergebnisse</dt><dd>Text · Audio</dd></div></dl><details class=\"card-about\"><summary>Über das Modell</summary><p class=\"note-s\" data-model-method-boundary>Diese Beschreibung erläutert die Fähigkeiten des Modells. Die über Ailoot verfügbaren Eingaben, Ausgaben und Optionen sind unten für die ausgewählte Methode aufgeführt.</p><div class=\"mabout\" id=\"m-about\"><p>Qwen-Audio-3.0-Realtime-Plus ist ein Modell von Alibaba für Sprachdialoge in Echtzeit. Es nimmt Sprache und Text entgegen, antwortet mit Audio und Text und unterstützt ein Gespräch in beide Richtungen mit natürlichem Wechsel der Gesprächsbeiträge. Audio kann abschnittsweise übertragen und empfangen werden, sodass sich die Interaktion während des Gesprächs entwickelt.</p><h4>Wann ein Gesprächsbeitrag abgeschlossen ist</h4><p>Es gibt mehrere Möglichkeiten, die Grenzen eines Gesprächsbeitrags zu erkennen: anhand der Sprachaktivität, der inhaltlichen Vollständigkeit oder durch ausdrückliche Steuerung. Beim Hersteller wird der Modus vor der Übertragung des ersten Audios gewählt; für eine Änderung nach Gesprächsbeginn ist eine neue Verbindung erforderlich. Ob diese Steuerung unterstützt wird, hängt von der gewählten Methode ab. Der semantische Modus berücksichtigt Pausen und Füllwörter: Ein kurzes Zögern bedeutet nicht zwangsläufig, dass der Nutzer seinen Gedanken abgeschlossen hat. Neue Nutzersprache kann die gerade erzeugte Antwort unterbrechen, damit das Gespräch unter Berücksichtigung des nächsten Beitrags weitergeht. Im semantischen Modus lässt sich die Erkennung an einer Sprachprobe des gewählten Gesprächspartners ausrichten, um fremde Stimmen und Hintergrundgeräusche weniger zu berücksichtigen.</p><p>Anweisungen bestimmen die Rolle des Assistenten und den Gesprächsstil. Die stimmliche Darstellung kann Ton, Tempo und Emotion berücksichtigen; für Version 3.0 sind fünf Systemstimmen sowie Stimmen nach einer Sprachprobe vorgesehen. Das Modell unterstützt 11 Sprachen, darunter Russisch, sowie die vom Hersteller genannten chinesischen Dialektvarianten. Beim Hersteller wird die Stimme bei der ersten Aktualisierung der Sitzungseinstellungen festgelegt; eine später übermittelte neue Stimme wird im selben Gespräch ignoriert. Diese Einstellungen benötigen Unterstützung durch die gewählte Zugriffsmethode.</p><h4>Werkzeuge und Gesprächsverlauf</h4><p>Funktionsaufrufe werden unterstützt. Das Modell formuliert die erforderliche Aktion, die verbundene Anwendung führt sie aus und gibt das Ergebnis an den Dialog zurück. So kann ein Gespräch auf tatsächlichen Daten aufbauen und nach einer ausgeführten Operation fortgesetzt werden. Der Sprachassistent kann Werkzeugergebnisse nutzen und dabei den Gesprächskontext beibehalten. Die Herstellerfunktionen umfassen ausserdem eine integrierte Websuche, sofern die gewählte Methode sie bereitstellt. Websuche und Funktionsaufrufe können nicht gleichzeitig in einer Sitzung aktiviert werden.</p><p>Standardmässig enthält der Verlauf 20 Gesprächsrunden; vorgesehen ist ein Bereich von einer bis 50. Für angesammeltes Audio gilt eine Grenze von 300 Sekunden; bei Überschreitung der Grenzen werden ältere Teile des Verlaufs entfernt. Das unterscheidet sich von der Dauer eines einzelnen Beitrags: Der Verlauf bestimmt, welches frühere Material bei der Fortsetzung des Dialogs verfügbar bleibt.</p><h4>Textkontext und Audio</h4><p>Der formale Kontext umfasst 40 960 Tokens. Die maximale Eingabelänge beträgt 16 384 Tokens, die Ausgabelänge 8192; dieselben Eingabe- und Ausgabegrenzen gelten für den Reasoning-Modus, mit einer separaten Grenze von 1024 Tokens für die Reasoning-Kette.</p><p>Für Audio-Streaming ist einkanaliges PCM mit 16-Bit-Darstellung vorgesehen: bei der Eingabe 16 kHz, bei der Ausgabe 24 kHz. Text- und Audiodaten gehören zu einem gemeinsamen Gespräch. Visuelle Eingabe und Bildausgabe sind für dieses konkrete Modell nicht angekündigt; sein Schwerpunkt liegt auf Sprache, Text und stimmlicher Interaktion.</p></div></details></section><section class=\"card-section\" data-card-section=\"methods\"><h3 tabindex=\"-1\">In Ailoot verfügbar · Eingaben und Methoden</h3><details class=\"card-method\" open><summary><b>Ailoot · Sprache in Echtzeit</b> <code>GET /v1/realtime?model=qwen-audio-3.0-realtime-plus</code></summary><dl class=\"method-capabilities\"><div><dt>Eingabe</dt><dd><code>text</code>, <code>audio</code></dd></div><div><dt>Ausgabe</dt><dd><code>text</code>, <code>audio</code></dd></div><div><dt>Ausgabeformat</dt><dd>Sitzungsereignisse</dd></div></dl><div class=\"tw\" data-card-parameters data-typed-parameters><table><thead><tr><th>Feld</th><th>Typ</th><th>Anforderung</th><th>Werte und Limits</th><th>Standard</th></tr></thead><tbody><tr data-parameter-availability=\"source_interface\"><th data-cell-label=\"Feld\" scope=\"row\"><span class=\"card-cell-label\">Feld</span><code class=\"card-field-name\">query.model</code></th><td data-cell-label=\"Typ\" data-field-type><span class=\"card-cell-label\">Typ</span><code>string</code></td><td data-cell-label=\"Anforderung\"><span class=\"card-cell-label\">Anforderung</span>Erforderlich</td><td data-cell-label=\"Werte und Limits\"><span class=\"card-cell-label\">Werte und Limits</span><div>qwen-audio-3.0-realtime-plus</div></td><td data-cell-label=\"Standard\" data-default=\"unspecified\"><span class=\"card-cell-label\">Standard</span>—</td></tr><tr data-parameter-availability=\"source_interface\"><th data-cell-label=\"Feld\" scope=\"row\"><span class=\"card-cell-label\">Feld</span><code class=\"card-field-name\">session.input_audio_format</code></th><td data-cell-label=\"Typ\" data-field-type><span class=\"card-cell-label\">Typ</span><code>string</code></td><td data-cell-label=\"Anforderung\"><span class=\"card-cell-label\">Anforderung</span>Optional</td><td data-cell-label=\"Werte und Limits\"><span class=\"card-cell-label\">Werte und Limits</span><div>pcm16, pcm</div></td><td data-cell-label=\"Standard\" data-default=\"unspecified\"><span class=\"card-cell-label\">Standard</span>—</td></tr><tr data-parameter-availability=\"source_interface\"><th data-cell-label=\"Feld\" scope=\"row\"><span class=\"card-cell-label\">Feld</span><code class=\"card-field-name\">session.output_audio_format</code></th><td data-cell-label=\"Typ\" data-field-type><span class=\"card-cell-label\">Typ</span><code>string</code></td><td data-cell-label=\"Anforderung\"><span class=\"card-cell-label\">Anforderung</span>Optional</td><td data-cell-label=\"Werte und Limits\"><span class=\"card-cell-label\">Werte und Limits</span><div>pcm16, pcm</div></td><td data-cell-label=\"Standard\" data-default=\"unspecified\"><span class=\"card-cell-label\">Standard</span>—</td></tr><tr data-parameter-availability=\"source_interface\"><th data-cell-label=\"Feld\" scope=\"row\"><span class=\"card-cell-label\">Feld</span><code class=\"card-field-name\">session.instructions</code></th><td data-cell-label=\"Typ\" data-field-type><span class=\"card-cell-label\">Typ</span><code>string</code></td><td data-cell-label=\"Anforderung\"><span class=\"card-cell-label\">Anforderung</span>Optional</td><td data-cell-label=\"Werte und Limits\"><span class=\"card-cell-label\">Werte und Limits</span><div>Limit gilt für: Ausgewählte Sitzungsrichtlinie</div></td><td data-cell-label=\"Standard\" data-default=\"unspecified\"><span class=\"card-cell-label\">Standard</span>—</td></tr><tr data-parameter-availability=\"source_interface\"><th data-cell-label=\"Feld\" scope=\"row\"><span class=\"card-cell-label\">Feld</span><code class=\"card-field-name\">session.max_history_turns</code></th><td data-cell-label=\"Typ\" data-field-type><span class=\"card-cell-label\">Typ</span><code>integer</code></td><td data-cell-label=\"Anforderung\"><span class=\"card-cell-label\">Anforderung</span>Optional</td><td data-cell-label=\"Werte und Limits\"><span class=\"card-cell-label\">Werte und Limits</span><div>Minimum: 1</div><div>Limit gilt für: Ausgewählte Sitzungsrichtlinie</div></td><td data-cell-label=\"Standard\" data-default=\"unspecified\"><span class=\"card-cell-label\">Standard</span>—</td></tr><tr data-parameter-availability=\"source_interface\"><th data-cell-label=\"Feld\" scope=\"row\"><span class=\"card-cell-label\">Feld</span><code class=\"card-field-name\">input_audio_buffer.append.audio</code></th><td data-cell-label=\"Typ\" data-field-type><span class=\"card-cell-label\">Typ</span><code>base64_string</code></td><td data-cell-label=\"Anforderung\"><span class=\"card-cell-label\">Anforderung</span>Erforderlich</td><td data-cell-label=\"Werte und Limits\"><span class=\"card-cell-label\">Werte und Limits</span><div>Eingabeinhalt: PCM16 mono; 16 kHz Eingabe, 24 kHz Ausgabe; nicht leere Daten mit gerader Bytelänge</div></td><td data-cell-label=\"Standard\" data-default=\"unspecified\"><span class=\"card-cell-label\">Standard</span>—</td></tr></tbody></table></div><details class=\"card-about\" data-material-combinations><summary>Kombinationen von Eingabematerialien</summary><p class=\"note-s\"><b>realtime_text_audio</b></p></details><details class=\"note-s\" data-method-contract><summary>Methodenparameter und Lebenszyklus</summary><div class=\"tw\" data-card-table=\"contract\"><table><thead><tr><th>Parameter</th><th>Vertrag</th></tr></thead><tbody><tr><th data-cell-label=\"Parameter\" scope=\"row\"><span class=\"card-cell-label\">Parameter</span><code>material_types</code></th><td data-cell-label=\"Vertrag\"><span class=\"card-cell-label\">Vertrag</span>text, audio</td></tr><tr><th data-cell-label=\"Parameter\" scope=\"row\"><span class=\"card-cell-label\">Parameter</span><code>required</code></th><td data-cell-label=\"Vertrag\"><span class=\"card-cell-label\">Vertrag</span>null</td></tr><tr><th data-cell-label=\"Parameter\" scope=\"row\"><span class=\"card-cell-label\">Parameter</span><code>optional_controls</code></th><td data-cell-label=\"Vertrag\"><span class=\"card-cell-label\">Vertrag</span>null</td></tr><tr><th data-cell-label=\"Parameter\" scope=\"row\"><span class=\"card-cell-label\">Parameter</span><code>content_type</code></th><td data-cell-label=\"Vertrag\"><span class=\"card-cell-label\">Vertrag</span>WebSocket</td></tr></tbody></table></div><p>Lebenszyklus: <code>exact retained published method</code></p><p class=\"note-s\">Methodenstrukturen und IDs sind exakt; die Fähigkeiten des Anbieters sind von der Zulassung einer Anfrage zu unterscheiden.</p></details></details></section><section class=\"card-section\" data-card-section=\"pricing\"><h3 tabindex=\"-1\">Tarife</h3><h4>Ailoot-Methodentarife</h4><section class=\"meth\" data-route=\"Core\"><header><b><span class=\"alias\">Ailoot</span> Sprache in Echtzeit</b><code>GET /v1/realtime?model=qwen-audio-3.0-realtime-plus</code></header><dl><div><dt>Eingabe</dt><dd>$ 0.0008 <em>/ 1K</em></dd></div><div><dt>Ausgabe</dt><dd>$ 0.0064 <em>/ 1K</em></dd></div><div><dt>Eingabe</dt><dd>$ 0.0048 <em>pro Minute Audio</em></dd></div><div><dt>Ausgabe</dt><dd>$ 0.018 <em>pro Minute Ausgabeaudio</em></dd></div></dl></section><p class=\"note-s\">Ailoot reserviert vor einer Anfrage einen geschätzten Betrag. Nach dem Ergebnis rechnet Ailoot die endgültige Gebühr anhand des gemessenen Verbrauchs ab. Bei Streaming erfolgt die Abrechnung anhand des abschliessenden Verbrauchsdatensatzes. <a href=\"/docs/de-ch/billing/reserve/\">So funktionieren Reservierung und Abrechnung →</a></p></section><section class=\"card-section\" data-card-section=\"examples\"><h3 tabindex=\"-1\">Beispielanfragen</h3><h4>Ailoot · Sprache in Echtzeit</h4><div class=\"code-group\"><div class=\"cg-bar\"><div class=\"cg-tabs\" role=\"tablist\" aria-label=\"Codevarianten\"><button class=\"cg-tab\" id=\"model-code-40-tab-0\" role=\"tab\" type=\"button\" aria-controls=\"model-code-40-panel-0\" aria-selected=\"true\" tabindex=\"0\">Python WebSocket · Text</button><button class=\"cg-tab\" id=\"model-code-40-tab-1\" role=\"tab\" type=\"button\" aria-controls=\"model-code-40-panel-1\" aria-selected=\"false\" tabindex=\"-1\">Python WebSocket · Audio</button></div><div class=\"cg-tools\"><button class=\"cg-btn cg-copy\" type=\"button\" aria-label=\"Code kopieren\"><svg class=\"cp\" viewBox=\"0 0 16 16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.4\"><rect x=\"5.25\" y=\"5.25\" width=\"8.5\" height=\"8.5\" rx=\"1.75\"/><path d=\"M10.75 5.25V3.5a1.25 1.25 0 0 0-1.25-1.25H3.5A1.25 1.25 0 0 0 2.25 3.5v6a1.25 1.25 0 0 0 1.25 1.25h1.75\"/></svg><svg class=\"ok\" viewBox=\"0 0 16 16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.4\"><path d=\"m3 8.5 3.25 3.25L13 5\"/></svg></button></div></div><div class=\"cg-body\"><div class=\"cg-pane\" id=\"model-code-40-panel-0\" role=\"tabpanel\" aria-labelledby=\"model-code-40-tab-0\"><pre data-lang=\"python\"><code># Install the documented client once: python3 -m pip install websockets\nimport base64, json, os, time, wave\nfrom pathlib import Path\nfrom websockets.sync.client import connect\n\nkey = os.environ.get(&quot;AILOOT_API_KEY&quot;, &quot;&quot;)\nif not key.strip():\n    raise SystemExit(&quot;Set your AILOOT_API_KEY before connecting&quot;)\nfile = Path(os.environ.get(&quot;AILOOT_TEXT_FILE&quot;, &quot;&quot;))\nif not file.is_file(): raise SystemExit(&quot;Set AILOOT_TEXT_FILE to your actual UTF-8 material&quot;)\nmaterial = file.read_text(encoding=&quot;utf-8&quot;)\nif not material.strip(): raise SystemExit(&quot;Text material must not be empty&quot;)\nout = Path(&quot;realtime-results&quot;)\nout.mkdir(exist_ok=True)\naudio, texts, complete = {}, {}, []\ncurrent_response = None\npending = False\ndeadline = time.monotonic() + 570  # Local client bound; lower server/session limits still apply.\n\ndef receive(ws, log):\n    global current_response, pending\n    left = deadline - time.monotonic()\n    if left &lt;= 0:\n        raise TimeoutError(&quot;Client session limit; preserve IDs and partial results, do not replay&quot;)\n    event = json.loads(ws.recv(timeout=min(60, left)))\n    log.write(json.dumps(event, ensure_ascii=False) + &quot;\\n&quot;)\n    log.flush()\n    kind = event.get(&quot;type&quot;)\n    if kind == &quot;error&quot;:\n        raise RuntimeError(json.dumps(event, ensure_ascii=False))\n    if kind == &quot;response.created&quot;:\n        current_response = event[&quot;response&quot;][&quot;id&quot;]\n    if kind in {&quot;response.audio.delta&quot;, &quot;response.output_audio.delta&quot;, &quot;response.text.delta&quot;, &quot;response.output_text.delta&quot;, &quot;response.audio_transcript.delta&quot;, &quot;response.output_audio_transcript.delta&quot;, &quot;response.text.done&quot;, &quot;response.audio_transcript.done&quot;}:\n        identity = (event[&quot;response_id&quot;], event[&quot;item_id&quot;], event[&quot;output_index&quot;], event[&quot;content_index&quot;])\n        if kind in {&quot;response.audio.delta&quot;, &quot;response.output_audio.delta&quot;}:\n            raw = base64.b64decode(event[&quot;delta&quot;], validate=True)\n            if len(raw) % 2: raise ValueError(&quot;Output PCM16 chunk must have an even byte length&quot;)\n            audio.setdefault(identity, bytearray()).extend(raw)\n        elif kind.endswith(&quot;.done&quot;):\n            texts[identity] = event.get(&quot;text&quot;, event.get(&quot;transcript&quot;, &quot;&quot;))\n        else:\n            texts[identity] = texts.get(identity, &quot;&quot;) + event[&quot;delta&quot;]\n            print(event[&quot;delta&quot;], end=&quot;&quot;, flush=True)\n    if kind == &quot;response.done&quot;:\n        response = event[&quot;response&quot;]\n        complete.append(response)\n        if current_response is None: current_response = response[&quot;id&quot;]\n        if response[&quot;id&quot;] == current_response: pending = False\n    return event\n\ndef wait_for(ws, log, kind):\n    while True:\n        event = receive(ws, log)\n        if event.get(&quot;type&quot;) == kind: return event\n\ndef send(ws, event):\n    ws.send(json.dumps(event, ensure_ascii=False))\n\ntry:\n    # One exact model query; no reconnect/retry loop and no provider credentials.\n    with connect(&quot;wss://api.ailoot.ai/v1/realtime?model=qwen-audio-3.0-realtime-plus&quot;, additional_headers={&quot;Authorization&quot;: &quot;Bearer &quot; + key}) as ws:\n        with (out / &quot;events.jsonl&quot;).open(&quot;w&quot;, encoding=&quot;utf-8&quot;) as log:\n            wait_for(ws, log, &quot;session.created&quot;)\n            send(ws, {&quot;type&quot;:&quot;session.update&quot;, &quot;session&quot;:{&quot;modalities&quot;:[&quot;audio&quot;,&quot;text&quot;], &quot;input_audio_format&quot;:&quot;pcm&quot;, &quot;output_audio_format&quot;:&quot;pcm&quot;, &quot;turn_detection&quot;:None}})\n            wait_for(ws, log, &quot;session.updated&quot;)\n            send(ws, {&quot;type&quot;:&quot;conversation.item.create&quot;, &quot;item&quot;:{&quot;type&quot;:&quot;message&quot;, &quot;role&quot;:&quot;user&quot;, &quot;content&quot;:[{&quot;type&quot;:&quot;input_text&quot;, &quot;text&quot;:material}]}})\n            send(ws, {&quot;type&quot;:&quot;response.create&quot;})\n            pending = True\n            try:\n                while pending: receive(ws, log)\n            except KeyboardInterrupt:\n                # Cancel the actual current inference, then preserve its returned status.\n                send(ws, {&quot;type&quot;:&quot;response.cancel&quot;})\n                while pending: receive(ws, log)\n    if not complete or complete[-1].get(&quot;status&quot;) != &quot;completed&quot;:\n        raise RuntimeError(&quot;Response did not complete normally; inspect saved events and status&quot;)\nfinally:\n    manifest = {&quot;responses&quot;:complete, &quot;parts&quot;:[]}\n    for number, identity in enumerate(dict.fromkeys(list(audio) + list(texts))):\n        record = {&quot;response_id&quot;:identity[0], &quot;item_id&quot;:identity[1], &quot;output_index&quot;:identity[2], &quot;content_index&quot;:identity[3]}\n        if identity in audio:\n            raw = bytes(audio[identity])\n            pcm_file = out / (&quot;audio-&quot; + str(number) + &quot;.pcm&quot;)\n            wav_file = out / (&quot;audio-&quot; + str(number) + &quot;.wav&quot;)\n            pcm_file.write_bytes(raw)\n            with wave.open(str(wav_file), &quot;wb&quot;) as wav:\n                wav.setnchannels(1); wav.setsampwidth(2); wav.setframerate(24000); wav.writeframes(raw)\n            record.update({&quot;pcm&quot;:str(pcm_file), &quot;wav&quot;:str(wav_file), &quot;sample_rate_hz&quot;:24000})\n        if identity in texts:\n            text_file = out / (&quot;text-&quot; + str(number) + &quot;.txt&quot;)\n            text_file.write_text(texts[identity], encoding=&quot;utf-8&quot;)\n            record[&quot;text&quot;] = str(text_file)\n        manifest[&quot;parts&quot;].append(record)\n    (out / &quot;results.json&quot;).write_text(json.dumps(manifest, ensure_ascii=False, indent=2), encoding=&quot;utf-8&quot;)\n    print(&quot;\\nSaved every received event and result in&quot;, out)\n</code></pre></div><div class=\"cg-pane\" id=\"model-code-40-panel-1\" role=\"tabpanel\" aria-labelledby=\"model-code-40-tab-1\" hidden><pre data-lang=\"python\"><code># Install the documented client once: python3 -m pip install websockets\nimport base64, json, os, time, wave\nfrom pathlib import Path\nfrom websockets.sync.client import connect\n\nkey = os.environ.get(&quot;AILOOT_API_KEY&quot;, &quot;&quot;)\nif not key.strip():\n    raise SystemExit(&quot;Set your AILOOT_API_KEY before connecting&quot;)\nfile = Path(os.environ.get(&quot;AILOOT_AUDIO_FILE&quot;, &quot;&quot;))\nif not file.is_file(): raise SystemExit(&quot;Set AILOOT_AUDIO_FILE to your raw PCM16 mono 16-kHz recording&quot;)\nmaterial = file.read_bytes()\nif not material or len(material) % 2 or material.startswith(b&quot;RIFF&quot;):\n    raise SystemExit(&quot;Use nonempty signed little-endian PCM16 mono 16-kHz bytes, not a WAV header&quot;)\nout = Path(&quot;realtime-results&quot;)\nout.mkdir(exist_ok=True)\naudio, texts, complete = {}, {}, []\ncurrent_response = None\npending = False\ndeadline = time.monotonic() + 570  # Local client bound; lower server/session limits still apply.\n\ndef receive(ws, log):\n    global current_response, pending\n    left = deadline - time.monotonic()\n    if left &lt;= 0:\n        raise TimeoutError(&quot;Client session limit; preserve IDs and partial results, do not replay&quot;)\n    event = json.loads(ws.recv(timeout=min(60, left)))\n    log.write(json.dumps(event, ensure_ascii=False) + &quot;\\n&quot;)\n    log.flush()\n    kind = event.get(&quot;type&quot;)\n    if kind == &quot;error&quot;:\n        raise RuntimeError(json.dumps(event, ensure_ascii=False))\n    if kind == &quot;response.created&quot;:\n        current_response = event[&quot;response&quot;][&quot;id&quot;]\n    if kind in {&quot;response.audio.delta&quot;, &quot;response.output_audio.delta&quot;, &quot;response.text.delta&quot;, &quot;response.output_text.delta&quot;, &quot;response.audio_transcript.delta&quot;, &quot;response.output_audio_transcript.delta&quot;, &quot;response.text.done&quot;, &quot;response.audio_transcript.done&quot;}:\n        identity = (event[&quot;response_id&quot;], event[&quot;item_id&quot;], event[&quot;output_index&quot;], event[&quot;content_index&quot;])\n        if kind in {&quot;response.audio.delta&quot;, &quot;response.output_audio.delta&quot;}:\n            raw = base64.b64decode(event[&quot;delta&quot;], validate=True)\n            if len(raw) % 2: raise ValueError(&quot;Output PCM16 chunk must have an even byte length&quot;)\n            audio.setdefault(identity, bytearray()).extend(raw)\n        elif kind.endswith(&quot;.done&quot;):\n            texts[identity] = event.get(&quot;text&quot;, event.get(&quot;transcript&quot;, &quot;&quot;))\n        else:\n            texts[identity] = texts.get(identity, &quot;&quot;) + event[&quot;delta&quot;]\n            print(event[&quot;delta&quot;], end=&quot;&quot;, flush=True)\n    if kind == &quot;response.done&quot;:\n        response = event[&quot;response&quot;]\n        complete.append(response)\n        if current_response is None: current_response = response[&quot;id&quot;]\n        if response[&quot;id&quot;] == current_response: pending = False\n    return event\n\ndef wait_for(ws, log, kind):\n    while True:\n        event = receive(ws, log)\n        if event.get(&quot;type&quot;) == kind: return event\n\ndef send(ws, event):\n    ws.send(json.dumps(event, ensure_ascii=False))\n\ntry:\n    # One exact model query; no reconnect/retry loop and no provider credentials.\n    with connect(&quot;wss://api.ailoot.ai/v1/realtime?model=qwen-audio-3.0-realtime-plus&quot;, additional_headers={&quot;Authorization&quot;: &quot;Bearer &quot; + key}) as ws:\n        with (out / &quot;events.jsonl&quot;).open(&quot;w&quot;, encoding=&quot;utf-8&quot;) as log:\n            wait_for(ws, log, &quot;session.created&quot;)\n            send(ws, {&quot;type&quot;:&quot;session.update&quot;, &quot;session&quot;:{&quot;modalities&quot;:[&quot;audio&quot;,&quot;text&quot;], &quot;input_audio_format&quot;:&quot;pcm&quot;, &quot;output_audio_format&quot;:&quot;pcm&quot;, &quot;turn_detection&quot;:None}})\n            wait_for(ws, log, &quot;session.updated&quot;)\n            for offset in range(0, len(material), 640):\n                send(ws, {&quot;type&quot;:&quot;input_audio_buffer.append&quot;, &quot;audio&quot;:base64.b64encode(material[offset:offset+640]).decode(&quot;ascii&quot;)})\n                time.sleep(0.02)\n            send(ws, {&quot;type&quot;:&quot;input_audio_buffer.commit&quot;})\n            wait_for(ws, log, &quot;input_audio_buffer.committed&quot;)\n            send(ws, {&quot;type&quot;:&quot;response.create&quot;})\n            pending = True\n            try:\n                while pending: receive(ws, log)\n            except KeyboardInterrupt:\n                # Cancel the actual current inference, then preserve its returned status.\n                send(ws, {&quot;type&quot;:&quot;response.cancel&quot;})\n                while pending: receive(ws, log)\n    if not complete or complete[-1].get(&quot;status&quot;) != &quot;completed&quot;:\n        raise RuntimeError(&quot;Response did not complete normally; inspect saved events and status&quot;)\nfinally:\n    manifest = {&quot;responses&quot;:complete, &quot;parts&quot;:[]}\n    for number, identity in enumerate(dict.fromkeys(list(audio) + list(texts))):\n        record = {&quot;response_id&quot;:identity[0], &quot;item_id&quot;:identity[1], &quot;output_index&quot;:identity[2], &quot;content_index&quot;:identity[3]}\n        if identity in audio:\n            raw = bytes(audio[identity])\n            pcm_file = out / (&quot;audio-&quot; + str(number) + &quot;.pcm&quot;)\n            wav_file = out / (&quot;audio-&quot; + str(number) + &quot;.wav&quot;)\n            pcm_file.write_bytes(raw)\n            with wave.open(str(wav_file), &quot;wb&quot;) as wav:\n                wav.setnchannels(1); wav.setsampwidth(2); wav.setframerate(24000); wav.writeframes(raw)\n            record.update({&quot;pcm&quot;:str(pcm_file), &quot;wav&quot;:str(wav_file), &quot;sample_rate_hz&quot;:24000})\n        if identity in texts:\n            text_file = out / (&quot;text-&quot; + str(number) + &quot;.txt&quot;)\n            text_file.write_text(texts[identity], encoding=&quot;utf-8&quot;)\n            record[&quot;text&quot;] = str(text_file)\n        manifest[&quot;parts&quot;].append(record)\n    (out / &quot;results.json&quot;).write_text(json.dumps(manifest, ensure_ascii=False, indent=2), encoding=&quot;utf-8&quot;)\n    print(&quot;\\nSaved every received event and result in&quot;, out)\n</code></pre></div></div></div></section><section class=\"card-section\" data-card-section=\"results\"><h3 tabindex=\"-1\">Ergebnisse abrufen und speichern</h3><h4>Ailoot · Sprache in Echtzeit</h4><p class=\"note-s\">Sitzungsereignisse</p><div class=\"card-result-process\" data-all-results><h5>Alle fertiggestellten Ergebnisse aufbewahren</h5><p class=\"note-s\">Bewahren Sie jede vollständig zurückgegebene Antwort, Datei und jeden Inhaltsteil auf.</p><p class=\"note-s\">Setzen Sie für jede tatsächliche Antwort-ID alle zurückgegebenen Audioteilstücke und Text-/Ereignisergebnisse zusammen.</p></div><div class=\"card-result-process\" data-unknown-recovery><h5>Wenn die ursprüngliche Antwort geprüft werden muss</h5><p class=\"note-s\">Bewahren Sie die tatsächlichen Sitzungs-, Antwort- und Ereignis-IDs sowie die Belege auf.</p></div><details class=\"card-about\" data-method-errors><summary>Fehler und nächste Schritte</summary><div class=\"tw\" data-card-table=\"errors\"><table><thead><tr><th>Antwort</th><th>Bedingung</th><th>Nächster Schritt</th></tr></thead><tbody><tr><th data-cell-label=\"Antwort\" scope=\"row\"><span class=\"card-cell-label\">Antwort</span>426 · <code>invalid_request_error</code></th><td data-cell-label=\"Bedingung\"><span class=\"card-cell-label\">Bedingung</span>Keine Umstellung auf WebSocket</td><td data-cell-label=\"Nächster Schritt\"><span class=\"card-cell-label\">Nächster Schritt</span>Verwenden Sie einen WebSocket-Client mit Upgrade: websocket.</td></tr></tbody></table></div></details></section><section class=\"card-section\" data-card-section=\"aliases\"><h3 tabindex=\"-1\">Aliasnamen</h3><h4>Modellaliasnamen</h4><p class=\"note-s\"><span data-model-alias-route=\"Core\"><b>Ailoot</b> <a href=\"#m=qwen-audio-3.0-realtime-plus&amp;route=Core&amp;caller=qwen-audio-3.0-realtime-plus&amp;fmt=realtime\"><code>qwen-audio-3.0-realtime-plus</code></a></span></p><h4>Aliasnamen für Methodenpfade</h4><p class=\"note-s\">Verwenden Sie die oben angezeigten Methodenpfade.</p><h4>Zugehörige Aufrufer-IDs</h4><p class=\"note-s\"><a href=\"#m=qwen-audio-3.0-realtime-plus&amp;route=Core&amp;caller=qwen-audio-3.0-realtime-plus&amp;fmt=realtime\"><code>qwen-audio-3.0-realtime-plus</code></a></p></section></div>",
      "method_identity": {
        "effective_request_model_id": "qwen-audio-3.0-realtime-plus",
        "fmt": "realtime",
        "http": "GET",
        "path": "/v1/realtime?model=qwen-audio-3.0-realtime-plus",
        "request_model_id": "qwen-audio-3.0-realtime-plus",
        "route_label": "Core"
      },
      "method_key": "Core|realtime|/v1/realtime?model=qwen-audio-3.0-realtime-plus|qwen-audio-3.0-realtime-plus",
      "ordinal": 0,
      "rawMethod": {
        "cache_read": null,
        "cache_write": null,
        "cache_write_1h": null,
        "cache_write_5m": null,
        "conditional_meter": null,
        "contract": {
          "data": {
            "all_results": "Setzen Sie für jede tatsächliche Antwort-ID alle zurückgegebenen Audioteilstücke und Text-/Ereignisergebnisse zusammen.",
            "endpoint": {
              "http": "GET",
              "path": "/v1/realtime",
              "query": {
                "model": "qwen-audio-3.0-realtime-plus"
              },
              "transport": "WebSocket",
              "url": "wss://api.ailoot.ai/v1/realtime?model=qwen-audio-3.0-realtime-plus"
            },
            "errors": [
              {
                "condition": "Keine Umstellung auf WebSocket",
                "http_status": 426,
                "recovery": "Verwenden Sie einen WebSocket-Client mit Upgrade: websocket.",
                "type": "invalid_request_error"
              }
            ],
            "hints": [
              "Append the model query once; do not add another ?model to a URL that already contains it.",
              "Use the actual WebSocket upgrade and API-key authentication.",
              "Tools, web search and voiceprint enhancement are not supported on this exact route."
            ],
            "ignored_fields": [],
            "lifecycle": {
              "close": "Close the actual establishedWebSocket session; no fakeHTTP cancelpath.",
              "mode": "WebSocket session",
              "unknown": "Bewahren Sie die tatsächlichen Sitzungs-, Antwort- und Ereignis-IDs sowie die Belege auf."
            },
            "material_combinations": [
              {
                "events": [
                  "session.update",
                  "input_audio_buffer.append",
                  "input_audio_buffer.commit",
                  "input_audio_buffer.clear",
                  "response.create",
                  "response.cancel",
                  "conversation.item.create",
                  "conversation.item.retrieve",
                  "conversation.item.delete"
                ],
                "mode": "realtime_text_audio"
              }
            ],
            "operation_modes": [
              "realtime_text_audio"
            ],
            "outputs": {
              "all_outputs": "Assemble every returned audio delta and text/event result for each actual response ID.",
              "audio_format": "PCM16 mono 24 kHz",
              "family": [
                "text",
                "audio"
              ],
              "format": "Sitzungsereignisse"
            },
            "parameters": [
              {
                "availability": "source_interface",
                "default": null,
                "default_known": false,
                "default_status": "not_specified",
                "enum": [
                  "qwen-audio-3.0-realtime-plus"
                ],
                "enum_known": true,
                "enum_status": "specified",
                "name": "query.model",
                "required": true,
                "type": "string"
              },
              {
                "availability": "source_interface",
                "default": null,
                "default_known": false,
                "default_status": "not_specified",
                "enum": [
                  "pcm16",
                  "pcm"
                ],
                "enum_known": true,
                "enum_status": "specified",
                "name": "session.input_audio_format",
                "required": false,
                "type": "string"
              },
              {
                "availability": "source_interface",
                "default": null,
                "default_known": false,
                "default_status": "not_specified",
                "enum": [
                  "pcm16",
                  "pcm"
                ],
                "enum_known": true,
                "enum_status": "specified",
                "name": "session.output_audio_format",
                "required": false,
                "type": "string"
              },
              {
                "availability": "source_interface",
                "default": null,
                "default_known": false,
                "default_status": "not_specified",
                "enum": null,
                "enum_known": false,
                "enum_status": "not_specified",
                "limit_scope": "Ausgewählte Sitzungsrichtlinie",
                "name": "session.instructions",
                "required": false,
                "type": "string"
              },
              {
                "availability": "source_interface",
                "default": null,
                "default_known": false,
                "default_status": "not_specified",
                "enum": null,
                "enum_known": false,
                "enum_status": "not_specified",
                "limit_scope": "Ausgewählte Sitzungsrichtlinie",
                "minimum": 1,
                "name": "session.max_history_turns",
                "required": false,
                "type": "integer"
              },
              {
                "availability": "source_interface",
                "content": "PCM16 mono; 16 kHz Eingabe, 24 kHz Ausgabe; nicht leere Daten mit gerader Bytelänge",
                "default": null,
                "default_known": false,
                "default_status": "not_specified",
                "enum": null,
                "enum_known": false,
                "enum_status": "not_specified",
                "name": "input_audio_buffer.append.audio",
                "required": true,
                "type": "base64_string"
              }
            ],
            "unsupported": []
          },
          "hints": [
            "Methodenstrukturen und IDs sind exakt; die Fähigkeiten des Anbieters sind von der Zulassung einer Anfrage zu unterscheiden."
          ],
          "input": {
            "content_type": "WebSocket",
            "material_types": [
              "text",
              "audio"
            ],
            "optional_controls": null,
            "required": null
          },
          "lifecycle": {
            "mode": "exact retained published method"
          },
          "method": {
            "http": "GET",
            "path": "/v1/realtime?model=qwen-audio-3.0-realtime-plus"
          },
          "operation_modes": [
            "realtime"
          ],
          "output": {
            "family": [
              "text",
              "audio"
            ],
            "format": "session events",
            "multioutputs": "retain every actual response output"
          }
        },
        "ctx": null,
        "examples": [
          {
            "code": "# Install the documented client once: python3 -m pip install websockets\nimport base64, json, os, time, wave\nfrom pathlib import Path\nfrom websockets.sync.client import connect\n\nkey = os.environ.get(\"AILOOT_API_KEY\", \"\")\nif not key.strip():\n    raise SystemExit(\"Set your AILOOT_API_KEY before connecting\")\nfile = Path(os.environ.get(\"AILOOT_TEXT_FILE\", \"\"))\nif not file.is_file(): raise SystemExit(\"Set AILOOT_TEXT_FILE to your actual UTF-8 material\")\nmaterial = file.read_text(encoding=\"utf-8\")\nif not material.strip(): raise SystemExit(\"Text material must not be empty\")\nout = Path(\"realtime-results\")\nout.mkdir(exist_ok=True)\naudio, texts, complete = {}, {}, []\ncurrent_response = None\npending = False\ndeadline = time.monotonic() + 570  # Local client bound; lower server/session limits still apply.\n\ndef receive(ws, log):\n    global current_response, pending\n    left = deadline - time.monotonic()\n    if left <= 0:\n        raise TimeoutError(\"Client session limit; preserve IDs and partial results, do not replay\")\n    event = json.loads(ws.recv(timeout=min(60, left)))\n    log.write(json.dumps(event, ensure_ascii=False) + \"\\n\")\n    log.flush()\n    kind = event.get(\"type\")\n    if kind == \"error\":\n        raise RuntimeError(json.dumps(event, ensure_ascii=False))\n    if kind == \"response.created\":\n        current_response = event[\"response\"][\"id\"]\n    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\"}:\n        identity = (event[\"response_id\"], event[\"item_id\"], event[\"output_index\"], event[\"content_index\"])\n        if kind in {\"response.audio.delta\", \"response.output_audio.delta\"}:\n            raw = base64.b64decode(event[\"delta\"], validate=True)\n            if len(raw) % 2: raise ValueError(\"Output PCM16 chunk must have an even byte length\")\n            audio.setdefault(identity, bytearray()).extend(raw)\n        elif kind.endswith(\".done\"):\n            texts[identity] = event.get(\"text\", event.get(\"transcript\", \"\"))\n        else:\n            texts[identity] = texts.get(identity, \"\") + event[\"delta\"]\n            print(event[\"delta\"], end=\"\", flush=True)\n    if kind == \"response.done\":\n        response = event[\"response\"]\n        complete.append(response)\n        if current_response is None: current_response = response[\"id\"]\n        if response[\"id\"] == current_response: pending = False\n    return event\n\ndef wait_for(ws, log, kind):\n    while True:\n        event = receive(ws, log)\n        if event.get(\"type\") == kind: return event\n\ndef send(ws, event):\n    ws.send(json.dumps(event, ensure_ascii=False))\n\ntry:\n    # One exact model query; no reconnect/retry loop and no provider credentials.\n    with connect(\"wss://api.ailoot.ai/v1/realtime?model=qwen-audio-3.0-realtime-plus\", additional_headers={\"Authorization\": \"Bearer \" + key}) as ws:\n        with (out / \"events.jsonl\").open(\"w\", encoding=\"utf-8\") as log:\n            wait_for(ws, log, \"session.created\")\n            send(ws, {\"type\":\"session.update\", \"session\":{\"modalities\":[\"audio\",\"text\"], \"input_audio_format\":\"pcm\", \"output_audio_format\":\"pcm\", \"turn_detection\":None}})\n            wait_for(ws, log, \"session.updated\")\n            send(ws, {\"type\":\"conversation.item.create\", \"item\":{\"type\":\"message\", \"role\":\"user\", \"content\":[{\"type\":\"input_text\", \"text\":material}]}})\n            send(ws, {\"type\":\"response.create\"})\n            pending = True\n            try:\n                while pending: receive(ws, log)\n            except KeyboardInterrupt:\n                # Cancel the actual current inference, then preserve its returned status.\n                send(ws, {\"type\":\"response.cancel\"})\n                while pending: receive(ws, log)\n    if not complete or complete[-1].get(\"status\") != \"completed\":\n        raise RuntimeError(\"Response did not complete normally; inspect saved events and status\")\nfinally:\n    manifest = {\"responses\":complete, \"parts\":[]}\n    for number, identity in enumerate(dict.fromkeys(list(audio) + list(texts))):\n        record = {\"response_id\":identity[0], \"item_id\":identity[1], \"output_index\":identity[2], \"content_index\":identity[3]}\n        if identity in audio:\n            raw = bytes(audio[identity])\n            pcm_file = out / (\"audio-\" + str(number) + \".pcm\")\n            wav_file = out / (\"audio-\" + str(number) + \".wav\")\n            pcm_file.write_bytes(raw)\n            with wave.open(str(wav_file), \"wb\") as wav:\n                wav.setnchannels(1); wav.setsampwidth(2); wav.setframerate(24000); wav.writeframes(raw)\n            record.update({\"pcm\":str(pcm_file), \"wav\":str(wav_file), \"sample_rate_hz\":24000})\n        if identity in texts:\n            text_file = out / (\"text-\" + str(number) + \".txt\")\n            text_file.write_text(texts[identity], encoding=\"utf-8\")\n            record[\"text\"] = str(text_file)\n        manifest[\"parts\"].append(record)\n    (out / \"results.json\").write_text(json.dumps(manifest, ensure_ascii=False, indent=2), encoding=\"utf-8\")\n    print(\"\\nSaved every received event and result in\", out)\n",
            "label": "Python WebSocket · text material and all text/audio results",
            "language": "python"
          },
          {
            "code": "# Install the documented client once: python3 -m pip install websockets\nimport base64, json, os, time, wave\nfrom pathlib import Path\nfrom websockets.sync.client import connect\n\nkey = os.environ.get(\"AILOOT_API_KEY\", \"\")\nif not key.strip():\n    raise SystemExit(\"Set your AILOOT_API_KEY before connecting\")\nfile = Path(os.environ.get(\"AILOOT_AUDIO_FILE\", \"\"))\nif not file.is_file(): raise SystemExit(\"Set AILOOT_AUDIO_FILE to your raw PCM16 mono 16-kHz recording\")\nmaterial = file.read_bytes()\nif not material or len(material) % 2 or material.startswith(b\"RIFF\"):\n    raise SystemExit(\"Use nonempty signed little-endian PCM16 mono 16-kHz bytes, not a WAV header\")\nout = Path(\"realtime-results\")\nout.mkdir(exist_ok=True)\naudio, texts, complete = {}, {}, []\ncurrent_response = None\npending = False\ndeadline = time.monotonic() + 570  # Local client bound; lower server/session limits still apply.\n\ndef receive(ws, log):\n    global current_response, pending\n    left = deadline - time.monotonic()\n    if left <= 0:\n        raise TimeoutError(\"Client session limit; preserve IDs and partial results, do not replay\")\n    event = json.loads(ws.recv(timeout=min(60, left)))\n    log.write(json.dumps(event, ensure_ascii=False) + \"\\n\")\n    log.flush()\n    kind = event.get(\"type\")\n    if kind == \"error\":\n        raise RuntimeError(json.dumps(event, ensure_ascii=False))\n    if kind == \"response.created\":\n        current_response = event[\"response\"][\"id\"]\n    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\"}:\n        identity = (event[\"response_id\"], event[\"item_id\"], event[\"output_index\"], event[\"content_index\"])\n        if kind in {\"response.audio.delta\", \"response.output_audio.delta\"}:\n            raw = base64.b64decode(event[\"delta\"], validate=True)\n            if len(raw) % 2: raise ValueError(\"Output PCM16 chunk must have an even byte length\")\n            audio.setdefault(identity, bytearray()).extend(raw)\n        elif kind.endswith(\".done\"):\n            texts[identity] = event.get(\"text\", event.get(\"transcript\", \"\"))\n        else:\n            texts[identity] = texts.get(identity, \"\") + event[\"delta\"]\n            print(event[\"delta\"], end=\"\", flush=True)\n    if kind == \"response.done\":\n        response = event[\"response\"]\n        complete.append(response)\n        if current_response is None: current_response = response[\"id\"]\n        if response[\"id\"] == current_response: pending = False\n    return event\n\ndef wait_for(ws, log, kind):\n    while True:\n        event = receive(ws, log)\n        if event.get(\"type\") == kind: return event\n\ndef send(ws, event):\n    ws.send(json.dumps(event, ensure_ascii=False))\n\ntry:\n    # One exact model query; no reconnect/retry loop and no provider credentials.\n    with connect(\"wss://api.ailoot.ai/v1/realtime?model=qwen-audio-3.0-realtime-plus\", additional_headers={\"Authorization\": \"Bearer \" + key}) as ws:\n        with (out / \"events.jsonl\").open(\"w\", encoding=\"utf-8\") as log:\n            wait_for(ws, log, \"session.created\")\n            send(ws, {\"type\":\"session.update\", \"session\":{\"modalities\":[\"audio\",\"text\"], \"input_audio_format\":\"pcm\", \"output_audio_format\":\"pcm\", \"turn_detection\":None}})\n            wait_for(ws, log, \"session.updated\")\n            for offset in range(0, len(material), 640):\n                send(ws, {\"type\":\"input_audio_buffer.append\", \"audio\":base64.b64encode(material[offset:offset+640]).decode(\"ascii\")})\n                time.sleep(0.02)\n            send(ws, {\"type\":\"input_audio_buffer.commit\"})\n            wait_for(ws, log, \"input_audio_buffer.committed\")\n            send(ws, {\"type\":\"response.create\"})\n            pending = True\n            try:\n                while pending: receive(ws, log)\n            except KeyboardInterrupt:\n                # Cancel the actual current inference, then preserve its returned status.\n                send(ws, {\"type\":\"response.cancel\"})\n                while pending: receive(ws, log)\n    if not complete or complete[-1].get(\"status\") != \"completed\":\n        raise RuntimeError(\"Response did not complete normally; inspect saved events and status\")\nfinally:\n    manifest = {\"responses\":complete, \"parts\":[]}\n    for number, identity in enumerate(dict.fromkeys(list(audio) + list(texts))):\n        record = {\"response_id\":identity[0], \"item_id\":identity[1], \"output_index\":identity[2], \"content_index\":identity[3]}\n        if identity in audio:\n            raw = bytes(audio[identity])\n            pcm_file = out / (\"audio-\" + str(number) + \".pcm\")\n            wav_file = out / (\"audio-\" + str(number) + \".wav\")\n            pcm_file.write_bytes(raw)\n            with wave.open(str(wav_file), \"wb\") as wav:\n                wav.setnchannels(1); wav.setsampwidth(2); wav.setframerate(24000); wav.writeframes(raw)\n            record.update({\"pcm\":str(pcm_file), \"wav\":str(wav_file), \"sample_rate_hz\":24000})\n        if identity in texts:\n            text_file = out / (\"text-\" + str(number) + \".txt\")\n            text_file.write_text(texts[identity], encoding=\"utf-8\")\n            record[\"text\"] = str(text_file)\n        manifest[\"parts\"].append(record)\n    (out / \"results.json\").write_text(json.dumps(manifest, ensure_ascii=False, indent=2), encoding=\"utf-8\")\n    print(\"\\nSaved every received event and result in\", out)\n",
            "label": "Python WebSocket · actual PCM recording and all results",
            "language": "python"
          }
        ],
        "family": "openai",
        "fast_multiplier": null,
        "flex_multiplier": null,
        "fmt": "realtime",
        "http": "GET",
        "img_in": null,
        "img_out": null,
        "in": 0.8,
        "input": [
          "text",
          "audio"
        ],
        "label": "Sprache in Echtzeit",
        "max_out": null,
        "max_tool_calls": null,
        "out": 6.4,
        "output": [
          "text",
          "audio"
        ],
        "path": "/v1/realtime?model=qwen-audio-3.0-realtime-plus",
        "pricing_profiles": [
          {
            "dimensions": {},
            "label": "Core",
            "units": [
              {
                "amount": 0.8,
                "amount_unit": "usd_per_million_tokens",
                "key": "in",
                "label": "Input",
                "side": "in"
              },
              {
                "amount": 6.4,
                "amount_unit": "usd_per_million_tokens",
                "key": "out",
                "label": "Output",
                "side": "out"
              },
              {
                "amount": 0.0048,
                "amount_unit": "usd_per_display_unit",
                "key": "audio_input_second",
                "label": "per minute of audio",
                "side": "in"
              },
              {
                "amount": 0.018,
                "amount_unit": "usd_per_display_unit",
                "key": "audio_output_second",
                "label": "per minute of output audio",
                "side": "out"
              }
            ]
          }
        ],
        "request_model_id": "qwen-audio-3.0-realtime-plus",
        "route_label": "Core",
        "status_reads": [],
        "tiers": [],
        "tool_prices": null,
        "unit": "conditional",
        "units": [
          {
            "key": "audio_input_second",
            "label": "per minute of audio",
            "side": "in",
            "usd": 0.0048
          },
          {
            "key": "audio_output_second",
            "label": "per minute of output audio",
            "side": "out",
            "usd": 0.018
          }
        ]
      }
    }
  ],
  "model_id": "qwen-audio-3.0-realtime-plus",
  "nativeProvenance": {
    "input_facts_canonical_sha256": "812e520b1bc7eef3cc6b720608da0437925f58a28ed6a31129a5d2ba11ebea59",
    "input_html_sha256": "0a34cf959b6b0e06c4456d18ea1f0de13b6f3ef08e9f18bf4bb25f962a92aa2c",
    "private_audit_sha256": "78d5f9099f03774ec74f6ac59fb9d0d11633238c197be310d34cb919ffebcba3",
    "role": "historical-normalized-input-audit-hashes",
    "schema": "ailoot-native-model-provenance-v2"
  },
  "page": {
    "canonical": "https://ailoot.ai/models/de-ch/qwen-audio-3-0-realtime-plus/",
    "description": "Modell für Sprachdialoge in Echtzeit, das Sprache und Text entgegennimmt und mit Sprache oder Text antwortet. Ausgelegt auf ein natürliches Gesprächstempo und die Interaktion mit Werkzeugen.",
    "locale": "de-ch",
    "md_url": "https://ailoot.ai/models/de-ch/qwen-audio-3-0-realtime-plus/index.md",
    "title": "qwen-audio-3.0-realtime-plus — Ailoot",
    "url": "https://ailoot.ai/models/de-ch/qwen-audio-3-0-realtime-plus/"
  },
  "rawModel": {
    "about": "Qwen-Audio-3.0-Realtime-Plus ist ein Modell von Alibaba für Sprachdialoge in Echtzeit. Es nimmt Sprache und Text entgegen, antwortet mit Audio und Text und unterstützt ein Gespräch in beide Richtungen mit natürlichem Wechsel der Gesprächsbeiträge. Audio kann abschnittsweise übertragen und empfangen werden, sodass sich die Interaktion während des Gesprächs entwickelt.\n\n### Wann ein Gesprächsbeitrag abgeschlossen ist\n\nEs gibt mehrere Möglichkeiten, die Grenzen eines Gesprächsbeitrags zu erkennen: anhand der Sprachaktivität, der inhaltlichen Vollständigkeit oder durch ausdrückliche Steuerung. Beim Hersteller wird der Modus vor der Übertragung des ersten Audios gewählt; für eine Änderung nach Gesprächsbeginn ist eine neue Verbindung erforderlich. Ob diese Steuerung unterstützt wird, hängt von der gewählten Methode ab. Der semantische Modus berücksichtigt Pausen und Füllwörter: Ein kurzes Zögern bedeutet nicht zwangsläufig, dass der Nutzer seinen Gedanken abgeschlossen hat. Neue Nutzersprache kann die gerade erzeugte Antwort unterbrechen, damit das Gespräch unter Berücksichtigung des nächsten Beitrags weitergeht. Im semantischen Modus lässt sich die Erkennung an einer Sprachprobe des gewählten Gesprächspartners ausrichten, um fremde Stimmen und Hintergrundgeräusche weniger zu berücksichtigen.\n\nAnweisungen bestimmen die Rolle des Assistenten und den Gesprächsstil. Die stimmliche Darstellung kann Ton, Tempo und Emotion berücksichtigen; für Version 3.0 sind fünf Systemstimmen sowie Stimmen nach einer Sprachprobe vorgesehen. Das Modell unterstützt 11 Sprachen, darunter Russisch, sowie die vom Hersteller genannten chinesischen Dialektvarianten. Beim Hersteller wird die Stimme bei der ersten Aktualisierung der Sitzungseinstellungen festgelegt; eine später übermittelte neue Stimme wird im selben Gespräch ignoriert. Diese Einstellungen benötigen Unterstützung durch die gewählte Zugriffsmethode.\n\n### Werkzeuge und Gesprächsverlauf\n\nFunktionsaufrufe werden unterstützt. Das Modell formuliert die erforderliche Aktion, die verbundene Anwendung führt sie aus und gibt das Ergebnis an den Dialog zurück. So kann ein Gespräch auf tatsächlichen Daten aufbauen und nach einer ausgeführten Operation fortgesetzt werden. Der Sprachassistent kann Werkzeugergebnisse nutzen und dabei den Gesprächskontext beibehalten. Die Herstellerfunktionen umfassen ausserdem eine integrierte Websuche, sofern die gewählte Methode sie bereitstellt. Websuche und Funktionsaufrufe können nicht gleichzeitig in einer Sitzung aktiviert werden.\n\nStandardmässig enthält der Verlauf 20 Gesprächsrunden; vorgesehen ist ein Bereich von einer bis 50. Für angesammeltes Audio gilt eine Grenze von 300 Sekunden; bei Überschreitung der Grenzen werden ältere Teile des Verlaufs entfernt. Das unterscheidet sich von der Dauer eines einzelnen Beitrags: Der Verlauf bestimmt, welches frühere Material bei der Fortsetzung des Dialogs verfügbar bleibt.\n\n### Textkontext und Audio\n\nDer formale Kontext umfasst 40 960 Tokens. Die maximale Eingabelänge beträgt 16 384 Tokens, die Ausgabelänge 8192; dieselben Eingabe- und Ausgabegrenzen gelten für den Reasoning-Modus, mit einer separaten Grenze von 1024 Tokens für die Reasoning-Kette.\n\nFür Audio-Streaming ist einkanaliges PCM mit 16-Bit-Darstellung vorgesehen: bei der Eingabe 16 kHz, bei der Ausgabe 24 kHz. Text- und Audiodaten gehören zu einem gemeinsamen Gespräch. Visuelle Eingabe und Bildausgabe sind für dieses konkrete Modell nicht angekündigt; sein Schwerpunkt liegt auf Sprache, Text und stimmlicher Interaktion.",
    "alias_of": null,
    "aliases": [],
    "author": "Alibaba",
    "ctx": null,
    "formats": [
      "realtime"
    ],
    "id": "qwen-audio-3.0-realtime-plus",
    "input": [
      "text",
      "audio"
    ],
    "kind": "speech",
    "max_out": null,
    "methods": [
      {
        "cache_read": null,
        "cache_write": null,
        "cache_write_1h": null,
        "cache_write_5m": null,
        "conditional_meter": null,
        "contract": {
          "data": {
            "all_results": "Setzen Sie für jede tatsächliche Antwort-ID alle zurückgegebenen Audioteilstücke und Text-/Ereignisergebnisse zusammen.",
            "endpoint": {
              "http": "GET",
              "path": "/v1/realtime",
              "query": {
                "model": "qwen-audio-3.0-realtime-plus"
              },
              "transport": "WebSocket",
              "url": "wss://api.ailoot.ai/v1/realtime?model=qwen-audio-3.0-realtime-plus"
            },
            "errors": [
              {
                "condition": "Keine Umstellung auf WebSocket",
                "http_status": 426,
                "recovery": "Verwenden Sie einen WebSocket-Client mit Upgrade: websocket.",
                "type": "invalid_request_error"
              }
            ],
            "hints": [
              "Append the model query once; do not add another ?model to a URL that already contains it.",
              "Use the actual WebSocket upgrade and API-key authentication.",
              "Tools, web search and voiceprint enhancement are not supported on this exact route."
            ],
            "ignored_fields": [],
            "lifecycle": {
              "close": "Close the actual establishedWebSocket session; no fakeHTTP cancelpath.",
              "mode": "WebSocket session",
              "unknown": "Bewahren Sie die tatsächlichen Sitzungs-, Antwort- und Ereignis-IDs sowie die Belege auf."
            },
            "material_combinations": [
              {
                "events": [
                  "session.update",
                  "input_audio_buffer.append",
                  "input_audio_buffer.commit",
                  "input_audio_buffer.clear",
                  "response.create",
                  "response.cancel",
                  "conversation.item.create",
                  "conversation.item.retrieve",
                  "conversation.item.delete"
                ],
                "mode": "realtime_text_audio"
              }
            ],
            "operation_modes": [
              "realtime_text_audio"
            ],
            "outputs": {
              "all_outputs": "Assemble every returned audio delta and text/event result for each actual response ID.",
              "audio_format": "PCM16 mono 24 kHz",
              "family": [
                "text",
                "audio"
              ],
              "format": "Sitzungsereignisse"
            },
            "parameters": [
              {
                "availability": "source_interface",
                "default": null,
                "default_known": false,
                "default_status": "not_specified",
                "enum": [
                  "qwen-audio-3.0-realtime-plus"
                ],
                "enum_known": true,
                "enum_status": "specified",
                "name": "query.model",
                "required": true,
                "type": "string"
              },
              {
                "availability": "source_interface",
                "default": null,
                "default_known": false,
                "default_status": "not_specified",
                "enum": [
                  "pcm16",
                  "pcm"
                ],
                "enum_known": true,
                "enum_status": "specified",
                "name": "session.input_audio_format",
                "required": false,
                "type": "string"
              },
              {
                "availability": "source_interface",
                "default": null,
                "default_known": false,
                "default_status": "not_specified",
                "enum": [
                  "pcm16",
                  "pcm"
                ],
                "enum_known": true,
                "enum_status": "specified",
                "name": "session.output_audio_format",
                "required": false,
                "type": "string"
              },
              {
                "availability": "source_interface",
                "default": null,
                "default_known": false,
                "default_status": "not_specified",
                "enum": null,
                "enum_known": false,
                "enum_status": "not_specified",
                "limit_scope": "Ausgewählte Sitzungsrichtlinie",
                "name": "session.instructions",
                "required": false,
                "type": "string"
              },
              {
                "availability": "source_interface",
                "default": null,
                "default_known": false,
                "default_status": "not_specified",
                "enum": null,
                "enum_known": false,
                "enum_status": "not_specified",
                "limit_scope": "Ausgewählte Sitzungsrichtlinie",
                "minimum": 1,
                "name": "session.max_history_turns",
                "required": false,
                "type": "integer"
              },
              {
                "availability": "source_interface",
                "content": "PCM16 mono; 16 kHz Eingabe, 24 kHz Ausgabe; nicht leere Daten mit gerader Bytelänge",
                "default": null,
                "default_known": false,
                "default_status": "not_specified",
                "enum": null,
                "enum_known": false,
                "enum_status": "not_specified",
                "name": "input_audio_buffer.append.audio",
                "required": true,
                "type": "base64_string"
              }
            ],
            "unsupported": []
          },
          "hints": [
            "Methodenstrukturen und IDs sind exakt; die Fähigkeiten des Anbieters sind von der Zulassung einer Anfrage zu unterscheiden."
          ],
          "input": {
            "content_type": "WebSocket",
            "material_types": [
              "text",
              "audio"
            ],
            "optional_controls": null,
            "required": null
          },
          "lifecycle": {
            "mode": "exact retained published method"
          },
          "method": {
            "http": "GET",
            "path": "/v1/realtime?model=qwen-audio-3.0-realtime-plus"
          },
          "operation_modes": [
            "realtime"
          ],
          "output": {
            "family": [
              "text",
              "audio"
            ],
            "format": "session events",
            "multioutputs": "retain every actual response output"
          }
        },
        "ctx": null,
        "examples": [
          {
            "code": "# Install the documented client once: python3 -m pip install websockets\nimport base64, json, os, time, wave\nfrom pathlib import Path\nfrom websockets.sync.client import connect\n\nkey = os.environ.get(\"AILOOT_API_KEY\", \"\")\nif not key.strip():\n    raise SystemExit(\"Set your AILOOT_API_KEY before connecting\")\nfile = Path(os.environ.get(\"AILOOT_TEXT_FILE\", \"\"))\nif not file.is_file(): raise SystemExit(\"Set AILOOT_TEXT_FILE to your actual UTF-8 material\")\nmaterial = file.read_text(encoding=\"utf-8\")\nif not material.strip(): raise SystemExit(\"Text material must not be empty\")\nout = Path(\"realtime-results\")\nout.mkdir(exist_ok=True)\naudio, texts, complete = {}, {}, []\ncurrent_response = None\npending = False\ndeadline = time.monotonic() + 570  # Local client bound; lower server/session limits still apply.\n\ndef receive(ws, log):\n    global current_response, pending\n    left = deadline - time.monotonic()\n    if left <= 0:\n        raise TimeoutError(\"Client session limit; preserve IDs and partial results, do not replay\")\n    event = json.loads(ws.recv(timeout=min(60, left)))\n    log.write(json.dumps(event, ensure_ascii=False) + \"\\n\")\n    log.flush()\n    kind = event.get(\"type\")\n    if kind == \"error\":\n        raise RuntimeError(json.dumps(event, ensure_ascii=False))\n    if kind == \"response.created\":\n        current_response = event[\"response\"][\"id\"]\n    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\"}:\n        identity = (event[\"response_id\"], event[\"item_id\"], event[\"output_index\"], event[\"content_index\"])\n        if kind in {\"response.audio.delta\", \"response.output_audio.delta\"}:\n            raw = base64.b64decode(event[\"delta\"], validate=True)\n            if len(raw) % 2: raise ValueError(\"Output PCM16 chunk must have an even byte length\")\n            audio.setdefault(identity, bytearray()).extend(raw)\n        elif kind.endswith(\".done\"):\n            texts[identity] = event.get(\"text\", event.get(\"transcript\", \"\"))\n        else:\n            texts[identity] = texts.get(identity, \"\") + event[\"delta\"]\n            print(event[\"delta\"], end=\"\", flush=True)\n    if kind == \"response.done\":\n        response = event[\"response\"]\n        complete.append(response)\n        if current_response is None: current_response = response[\"id\"]\n        if response[\"id\"] == current_response: pending = False\n    return event\n\ndef wait_for(ws, log, kind):\n    while True:\n        event = receive(ws, log)\n        if event.get(\"type\") == kind: return event\n\ndef send(ws, event):\n    ws.send(json.dumps(event, ensure_ascii=False))\n\ntry:\n    # One exact model query; no reconnect/retry loop and no provider credentials.\n    with connect(\"wss://api.ailoot.ai/v1/realtime?model=qwen-audio-3.0-realtime-plus\", additional_headers={\"Authorization\": \"Bearer \" + key}) as ws:\n        with (out / \"events.jsonl\").open(\"w\", encoding=\"utf-8\") as log:\n            wait_for(ws, log, \"session.created\")\n            send(ws, {\"type\":\"session.update\", \"session\":{\"modalities\":[\"audio\",\"text\"], \"input_audio_format\":\"pcm\", \"output_audio_format\":\"pcm\", \"turn_detection\":None}})\n            wait_for(ws, log, \"session.updated\")\n            send(ws, {\"type\":\"conversation.item.create\", \"item\":{\"type\":\"message\", \"role\":\"user\", \"content\":[{\"type\":\"input_text\", \"text\":material}]}})\n            send(ws, {\"type\":\"response.create\"})\n            pending = True\n            try:\n                while pending: receive(ws, log)\n            except KeyboardInterrupt:\n                # Cancel the actual current inference, then preserve its returned status.\n                send(ws, {\"type\":\"response.cancel\"})\n                while pending: receive(ws, log)\n    if not complete or complete[-1].get(\"status\") != \"completed\":\n        raise RuntimeError(\"Response did not complete normally; inspect saved events and status\")\nfinally:\n    manifest = {\"responses\":complete, \"parts\":[]}\n    for number, identity in enumerate(dict.fromkeys(list(audio) + list(texts))):\n        record = {\"response_id\":identity[0], \"item_id\":identity[1], \"output_index\":identity[2], \"content_index\":identity[3]}\n        if identity in audio:\n            raw = bytes(audio[identity])\n            pcm_file = out / (\"audio-\" + str(number) + \".pcm\")\n            wav_file = out / (\"audio-\" + str(number) + \".wav\")\n            pcm_file.write_bytes(raw)\n            with wave.open(str(wav_file), \"wb\") as wav:\n                wav.setnchannels(1); wav.setsampwidth(2); wav.setframerate(24000); wav.writeframes(raw)\n            record.update({\"pcm\":str(pcm_file), \"wav\":str(wav_file), \"sample_rate_hz\":24000})\n        if identity in texts:\n            text_file = out / (\"text-\" + str(number) + \".txt\")\n            text_file.write_text(texts[identity], encoding=\"utf-8\")\n            record[\"text\"] = str(text_file)\n        manifest[\"parts\"].append(record)\n    (out / \"results.json\").write_text(json.dumps(manifest, ensure_ascii=False, indent=2), encoding=\"utf-8\")\n    print(\"\\nSaved every received event and result in\", out)\n",
            "label": "Python WebSocket · text material and all text/audio results",
            "language": "python"
          },
          {
            "code": "# Install the documented client once: python3 -m pip install websockets\nimport base64, json, os, time, wave\nfrom pathlib import Path\nfrom websockets.sync.client import connect\n\nkey = os.environ.get(\"AILOOT_API_KEY\", \"\")\nif not key.strip():\n    raise SystemExit(\"Set your AILOOT_API_KEY before connecting\")\nfile = Path(os.environ.get(\"AILOOT_AUDIO_FILE\", \"\"))\nif not file.is_file(): raise SystemExit(\"Set AILOOT_AUDIO_FILE to your raw PCM16 mono 16-kHz recording\")\nmaterial = file.read_bytes()\nif not material or len(material) % 2 or material.startswith(b\"RIFF\"):\n    raise SystemExit(\"Use nonempty signed little-endian PCM16 mono 16-kHz bytes, not a WAV header\")\nout = Path(\"realtime-results\")\nout.mkdir(exist_ok=True)\naudio, texts, complete = {}, {}, []\ncurrent_response = None\npending = False\ndeadline = time.monotonic() + 570  # Local client bound; lower server/session limits still apply.\n\ndef receive(ws, log):\n    global current_response, pending\n    left = deadline - time.monotonic()\n    if left <= 0:\n        raise TimeoutError(\"Client session limit; preserve IDs and partial results, do not replay\")\n    event = json.loads(ws.recv(timeout=min(60, left)))\n    log.write(json.dumps(event, ensure_ascii=False) + \"\\n\")\n    log.flush()\n    kind = event.get(\"type\")\n    if kind == \"error\":\n        raise RuntimeError(json.dumps(event, ensure_ascii=False))\n    if kind == \"response.created\":\n        current_response = event[\"response\"][\"id\"]\n    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\"}:\n        identity = (event[\"response_id\"], event[\"item_id\"], event[\"output_index\"], event[\"content_index\"])\n        if kind in {\"response.audio.delta\", \"response.output_audio.delta\"}:\n            raw = base64.b64decode(event[\"delta\"], validate=True)\n            if len(raw) % 2: raise ValueError(\"Output PCM16 chunk must have an even byte length\")\n            audio.setdefault(identity, bytearray()).extend(raw)\n        elif kind.endswith(\".done\"):\n            texts[identity] = event.get(\"text\", event.get(\"transcript\", \"\"))\n        else:\n            texts[identity] = texts.get(identity, \"\") + event[\"delta\"]\n            print(event[\"delta\"], end=\"\", flush=True)\n    if kind == \"response.done\":\n        response = event[\"response\"]\n        complete.append(response)\n        if current_response is None: current_response = response[\"id\"]\n        if response[\"id\"] == current_response: pending = False\n    return event\n\ndef wait_for(ws, log, kind):\n    while True:\n        event = receive(ws, log)\n        if event.get(\"type\") == kind: return event\n\ndef send(ws, event):\n    ws.send(json.dumps(event, ensure_ascii=False))\n\ntry:\n    # One exact model query; no reconnect/retry loop and no provider credentials.\n    with connect(\"wss://api.ailoot.ai/v1/realtime?model=qwen-audio-3.0-realtime-plus\", additional_headers={\"Authorization\": \"Bearer \" + key}) as ws:\n        with (out / \"events.jsonl\").open(\"w\", encoding=\"utf-8\") as log:\n            wait_for(ws, log, \"session.created\")\n            send(ws, {\"type\":\"session.update\", \"session\":{\"modalities\":[\"audio\",\"text\"], \"input_audio_format\":\"pcm\", \"output_audio_format\":\"pcm\", \"turn_detection\":None}})\n            wait_for(ws, log, \"session.updated\")\n            for offset in range(0, len(material), 640):\n                send(ws, {\"type\":\"input_audio_buffer.append\", \"audio\":base64.b64encode(material[offset:offset+640]).decode(\"ascii\")})\n                time.sleep(0.02)\n            send(ws, {\"type\":\"input_audio_buffer.commit\"})\n            wait_for(ws, log, \"input_audio_buffer.committed\")\n            send(ws, {\"type\":\"response.create\"})\n            pending = True\n            try:\n                while pending: receive(ws, log)\n            except KeyboardInterrupt:\n                # Cancel the actual current inference, then preserve its returned status.\n                send(ws, {\"type\":\"response.cancel\"})\n                while pending: receive(ws, log)\n    if not complete or complete[-1].get(\"status\") != \"completed\":\n        raise RuntimeError(\"Response did not complete normally; inspect saved events and status\")\nfinally:\n    manifest = {\"responses\":complete, \"parts\":[]}\n    for number, identity in enumerate(dict.fromkeys(list(audio) + list(texts))):\n        record = {\"response_id\":identity[0], \"item_id\":identity[1], \"output_index\":identity[2], \"content_index\":identity[3]}\n        if identity in audio:\n            raw = bytes(audio[identity])\n            pcm_file = out / (\"audio-\" + str(number) + \".pcm\")\n            wav_file = out / (\"audio-\" + str(number) + \".wav\")\n            pcm_file.write_bytes(raw)\n            with wave.open(str(wav_file), \"wb\") as wav:\n                wav.setnchannels(1); wav.setsampwidth(2); wav.setframerate(24000); wav.writeframes(raw)\n            record.update({\"pcm\":str(pcm_file), \"wav\":str(wav_file), \"sample_rate_hz\":24000})\n        if identity in texts:\n            text_file = out / (\"text-\" + str(number) + \".txt\")\n            text_file.write_text(texts[identity], encoding=\"utf-8\")\n            record[\"text\"] = str(text_file)\n        manifest[\"parts\"].append(record)\n    (out / \"results.json\").write_text(json.dumps(manifest, ensure_ascii=False, indent=2), encoding=\"utf-8\")\n    print(\"\\nSaved every received event and result in\", out)\n",
            "label": "Python WebSocket · actual PCM recording and all results",
            "language": "python"
          }
        ],
        "family": "openai",
        "fast_multiplier": null,
        "flex_multiplier": null,
        "fmt": "realtime",
        "http": "GET",
        "img_in": null,
        "img_out": null,
        "in": 0.8,
        "input": [
          "text",
          "audio"
        ],
        "label": "Sprache in Echtzeit",
        "max_out": null,
        "max_tool_calls": null,
        "out": 6.4,
        "output": [
          "text",
          "audio"
        ],
        "path": "/v1/realtime?model=qwen-audio-3.0-realtime-plus",
        "pricing_profiles": [
          {
            "dimensions": {},
            "label": "Core",
            "units": [
              {
                "amount": 0.8,
                "amount_unit": "usd_per_million_tokens",
                "key": "in",
                "label": "Input",
                "side": "in"
              },
              {
                "amount": 6.4,
                "amount_unit": "usd_per_million_tokens",
                "key": "out",
                "label": "Output",
                "side": "out"
              },
              {
                "amount": 0.0048,
                "amount_unit": "usd_per_display_unit",
                "key": "audio_input_second",
                "label": "per minute of audio",
                "side": "in"
              },
              {
                "amount": 0.018,
                "amount_unit": "usd_per_display_unit",
                "key": "audio_output_second",
                "label": "per minute of output audio",
                "side": "out"
              }
            ]
          }
        ],
        "request_model_id": "qwen-audio-3.0-realtime-plus",
        "route_label": "Core",
        "status_reads": [],
        "tiers": [],
        "tool_prices": null,
        "unit": "conditional",
        "units": [
          {
            "key": "audio_input_second",
            "label": "per minute of audio",
            "side": "in",
            "usd": 0.0048
          },
          {
            "key": "audio_output_second",
            "label": "per minute of output audio",
            "side": "out",
            "usd": 0.018
          }
        ]
      }
    ],
    "model_aliases": [
      {
        "canonical_model_id": "qwen-audio-3.0-realtime-plus",
        "request_model_id": "qwen-audio-3.0-realtime-plus",
        "route_label": "Core"
      }
    ],
    "name": "qwen-audio-3.0-realtime-plus",
    "price": {
      "in": 0.8,
      "in_label": null,
      "out": 6.4,
      "out_label": null,
      "sort_in": 0.8,
      "sort_out": 6.4,
      "varies": false
    },
    "short": "Modell für Sprachdialoge in Echtzeit, das Sprache und Text entgegennimmt und mit Sprache oder Text antwortet. Ausgelegt auf ein natürliches Gesprächstempo und die Interaktion mit Werkzeugen."
  },
  "renderer_schema": {
    "method_order": "Original DTO methods order; every exact route/format/path/caller survives.",
    "prices": "Original public DTO fields and original native display HTML; no flattened or normalized offers."
  },
  "representation": "exact-public-dto-and-native-renderer-html",
  "representationNotes": {
    "current_reference": {
      "about_json_pointer": "/aboutHtml",
      "methods": [
        {
          "contract_json_pointer": "/methods/0/rawMethod/contract",
          "html_json_pointer": "/methods/0/html",
          "method_ordinal": 0
        }
      ],
      "role": "current-semantic-reference"
    },
    "raw_input": {
      "examples_role": "historical-input-not-current-ready-examples",
      "json_pointers": [
        "/rawModel",
        "/methods/0/rawMethod"
      ],
      "role": "historical-owner-input"
    },
    "schema": "ailoot-native-model-representations-v1"
  },
  "schema": "ailoot-static-model-facts-v1",
  "schema_version": 1,
  "shortText": "Modell für Sprachdialoge in Echtzeit, das Sprache und Text entgegennimmt und mit Sprache oder Text antwortet. Ausgelegt auf ein natürliches Gesprächstempo und die Interaktion mit Werkzeugen.",
  "source": {
    "audit_sha256": "2e00086bcbfc28e64d0cebe97aa47c17d8d5618963027f8ffb9dc6123d7d25b1",
    "bridge_map_sha256": "1125275768b9636fc8461bc7da5061239a81ddfe508e2557843ca42c58ab0036",
    "raw_model_json_sha256": "65585c6b2100de3ae31acc4019d37af40c038d398107505136c5cc692836f5e9",
    "renderer_sha256": "76caa42c097db2ddc47d1e1e6fe7ca45c8363d7211296daf28e4352971e6c0c8"
  },
  "sourceRevision": "ea5f506633f60e00d218c0358f50b75446f474a21aaf8e008b62b6bcab82c9ff"
}
