QwenCloudBRASIL
Tradução de apoio para consulta. Código e identificadores técnicos preservados. Consultar referência original ↗

Conecte-se a um modelo

Conecte-se a modelos e aplicativos de API em tempo real por meio dos protocolos AOQ, WebRTC e WebSocket. Abrange o fluxo de conexão, diagramas de sequência e exemplos de código para cada protocolo

Este tópico aborda o fluxo de conexão, diagramas de sequência e exemplos de código para cada protocolo.

Pré-requisitos

Conexão AOQ

AOQ é profundamente personalizado com base no protocolo QUIC. Ele é adequado para aplicativos móveis nativos, suporta transmissão mista de áudio, vídeo e dados e possui resiliência de rede fraca integrada. O exemplo a seguir usa a demonstração iOS omni em tempo real (Omni) para percorrer o fluxo de conexão AOQ. Para obter detalhes da API do SDK AOQ, consulte SDK do cliente AOQ.

Diagrama de sequência geral

Antes de começar, baixe o AOQ Client SDK e o plugin Opus em download do SDK. Adicionar AoqClientSdk.framework e PluginOpus.framework ao seu projeto Xcode e selecione Incorporar e assinar.

Criar mecanismo e definir retornos de chamada

let config = AoqCreateConfig()
config.workDir = workDir
config.enableDumpAudio = false
engine = AoqClientEngine.createEngine(config, delegate: self)

Implementar o AoqEngineDelegate protocolo para ouvir retornos de chamada, como onConnectionStatusChange, onDataMsge onError.

Iniciar captura e reprodução de áudio

// Audio capture
let capCfg = AoqAudioCaptureConfig()
capCfg.channel = 1; capCfg.isExternal = false
engine.startAudioCapture(capCfg)
// Audio playback
let playCfg = AoqAudioPlaybackConfig()
playCfg.channel = 1; playCfg.isExternal = false
engine.startAudioPlayer(playCfg)
// Video capture (optional)
let vidCfg = AoqVideoCaptureConfig()
vidCfg.width = 720; vidCfg.height = 1280; vidCfg.fps = 15
engine.startVideoCapture(vidCfg)

Obtenha credenciais de conexão

O AppServer de negócios faz proxy da solicitação para QwenCloud. Consulte Autenticação de token.

Configure codecs e estabeleça conexão

Configure os parâmetros do codec e chame connect:

// Audio codec configuration
let encCfg = AoqAudioCodecConfig()
encCfg.codecType = .audioOpus; encCfg.sampleRate = 16000; encCfg.channel = 1
engine.setAudioEncoderConfig(encCfg)
engine.setAudioDecoderConfig(encCfg)
// Disable media sending before connect; enable it after session.updated
engine.enableSendMediaStream(.audio, enable: false)
let config = AoqConnectConfig()
config.token = token
config.sid = sid
config.certFingerprint = certificate
config.relayEndpoints = relayEndpoints
config.workspaceIdHash = workspaceIdHash
config.publishTracks = [audioTrack, dataTrack]
config.subscribeTracks = [audioTrack, dataTrack]
engine.connect(config)

O SDK AOQ envia dados de mídia por padrão após a conexão ser estabelecida. Este exemplo desabilita o envio de mídia ao se conectar ao modelo e habilita-o somente depois que a sessão estiver pronta.

Configurar sessão de IA

Depois que a conexão for bem-sucedida, envie um session.update evento. Para obter detalhes, consulte Eventos do cliente:

func onConnectionStatusChange(_ status: AoqConnectionStatus) {
  if status == .connected { sendSessionUpdate() }
}
private func sendSessionUpdate() {
  let json = """
  {
    // The ID of this event, generated by the client
    "event_id": "event_ToPZqeobitzUJnt3QqtWg",
    // Event type, fixed to session.update
    "type": "session.update",
    // Session configuration
    "session": {
        // Output modalities. Set to ["text"] (text only) or ["text","audio"] (text and audio).
        "modalities": [
            "text",
            "audio"
        ],
        // Voice for the output audio
        "voice": "Tina",
        // Input audio format. Only pcm is supported. The input audio is a PCM audio stream with a 16 kHz sample rate.
        "input_audio_format": "pcm",
        // Output audio format. Only pcm is supported. The output audio is a PCM audio stream with a 24 kHz sample rate.
        "output_audio_format": "pcm",
        // System message that sets the model's goal or role.
        "instructions": "You are an AI customer service agent at a five-star hotel. Accurately and courteously answer customer questions about room types, facilities, prices, and booking policies. Always respond in a professional and helpful manner, and never provide unverified information or information beyond the scope of the hotel's services.",
        // Whether to enable voice activity detection. To enable it, pass a configuration object; the server then automatically detects when speech starts and stops.
        // Set to null to let the client decide when to trigger a model response.
        "turn_detection": {
            // VAD type: server_vad or semantic_vad. semantic_vad is recommended for Qwen3.8-Omni-Flash-Realtime and the Qwen3.5-Omni-Realtime series.
            "type": "semantic_vad",
            // VAD detection threshold. Increase it in noisy environments and decrease it in quiet environments.
            "threshold": 0.5,
            // Silence duration for detecting the end of speech. A model response is triggered after this duration is exceeded
            "silence_duration_ms": 800
        }
    }
  }
  """
  let msg = AoqDataMsg()
  msg.data = json.data(using: .utf8)!
  engine.send(msg)
}

Habilite o envio de mídia após receber session.updated

O exemplo a seguir trata do session.updated resposta do modelo. Para obter detalhes, consulte Eventos do servidor:

func onDataMsg(_ msg: AoqDataMsg) {
  guard let obj = try? JSONSerialization.jsonObject(with: msg.data) as? [String: Any],
        let type = obj["type"] as? String else { return }
  if type == "session.updated" {
    engine.enableSendMediaStream(.audio, enable: true)
    engine.enableSendMediaStream(.video, enable: true)
  }
}
  1. Ative o envio de fluxo de mídia somente depois de receber session.updated. Caso contrário, o servidor poderá não estar pronto para receber dados.
  2. As trilhas de áudio e vídeo adicionadas durante a configuração da conexão (canais de mídia AOQ) transmitem dados automaticamente para o servidor.
    • Áudio: transmitido diretamente pela trilha de áudio. Não input_audio_buffer.append eventos são necessários.
    • Vídeo: os quadros são enviados pela trilha de vídeo. Não input_image_buffer.append eventos são necessários.

Desconecte e destrua o motor

engine.disconnect()
AoqClientEngine.destroy()

Conexão WebRTC

WebRTC não possui um SDK dedicado. Na web, conecte-se diretamente à API JavaScript nativa do navegador. Em outros clientes, conecte-se por meio de uma biblioteca WebRTC de código aberto ou de um serviço RTC de terceiros que ofereça suporte ao protocolo WebRTC padrão. O exemplo a seguir usa JavaScript na web.

Diagrama de fluxo geral

Estabelecer conexão

# pip install aiortc aiohttp certifi
import asyncio, aiohttp, ssl, certifi
from aiortc import RTCPeerConnection, RTCConfiguration, RTCSessionDescription
from aiortc.mediastreams import AudioStreamTrack
API_KEY = "your-api-key"
MODEL = "target-model"
SIGNALING_URL = f"https://maas.qwencloudapi.com/api/v1/webrtc/realtime?model={MODEL}"
async def connect():
  pc = RTCPeerConnection(RTCConfiguration(iceServers=[]))
  # Add an audio track so that the Offer SDP contains m=audio (required by the server)
  pc.addTrack(AudioStreamTrack())
  # Create a DataChannel to trigger SDP negotiation (the name is customizable; the server pushes events through a channel named "txt")
  pc.createDataChannel("oai-events")
  # SDP exchange: create an Offer and send it to the server
  offer = await pc.createOffer()
  await pc.setLocalDescription(offer)
  async with aiohttp.ClientSession() as session:
    async with session.post(
      SIGNALING_URL,
      ssl=ssl.create_default_context(cafile=certifi.where()),
      data=offer.sdp.encode("utf-8"),
      headers={
        "Content-Type": "application/sdp",
        "Authorization": f"Bearer {API_KEY}",
      },
    ) as resp:
      if not resp.ok:
        raise Exception(f"SDP exchange failed: {resp.status} {await resp.text()}")
      answer_sdp = await resp.text()
  print("=== Offer SDP ===")
  print(offer.sdp)
  print("=== Answer SDP ===")
  print(answer_sdp)
  # ICE connection setup completes automatically
  await pc.setRemoteDescription(RTCSessionDescription(sdp=answer_sdp, type="answer"))
  print("WebRTC connection established")
  return pc

Configurar parâmetros do modelo

Ouça as mensagens que o modelo retorna pelo DataChannel para manter a sequência de interação correta:

pc.ondatachannel = (event) => {
  const ch = event.channel;
  ch.onmessage = (e) => {
    let obj;
    try { obj = JSON.parse(e.data); }
    catch (err) {
      return;
    }
    if (obj?.type === "session.created") {
      sendUpdate(event.channel);
      // Start pushing audio and video
      audioSender?.replaceTrack(audioTrack);
      videoSender?.replaceTrack(videoTrack);
    }
  };
};

Enviar e receber dados de mídia

As trilhas de áudio e vídeo adicionadas durante a configuração da conexão (canais de mídia RTP) transmitem dados automaticamente para o servidor.

Código fonte de demonstração

Pré-requisitos

Execute a demonstração

Crie um arquivo HTML chamado webrtc_demo.html e copie o seguinte código nele:

webrtc_demo.html.

Abra o arquivo em um navegador e siga estas etapas:

  1. Clique em Iniciar sessão. A página gera automaticamente o Offer SDP e o comando curl correspondente.
  2. Clique em Copiar comando curl e execute o comando em um terminal. O comando retorna o SDP de resposta.
  3. Cole o Answer SDP na caixa de texto Answer SDP na página e clique em Set Answer para estabelecer a conexão e iniciar a conversa de voz.

##Conexão WebSocket

O método de conexão e o fluxo variam de acordo com o modelo. Para obter detalhes, consulte: