FreeSwitch通過Websocket(流式雙向語音)對接AI實時語音大模型技術方案(mod_ppy_aduio_stream)

FreeSwitch通過WebSocket對接AI實時語音大模型插件技術方案

在這里插入圖片描述

1. 方案概述

基于FreeSWITCH的實時通信能力,通過WebSocket協議橋接AI大模型服務,實現低延遲、高并發的智能語音交互系統。支持雙向語音流處理、實時ASR/TTS轉換和動態業務指令執行。
1753095153158#pic_center)

有這么方面項目需要的可聯系。https://cwn1.x3322.net:7777/down/0UgRahEtbPEa.so

類似技術參考:https://www.ddrj.com/callcenter/largemodel.html

2. 架構設計

graph LRA[FreeSWITCH] -->SIP/RTPB(WebSocket網關/SFU)B -->雙向WebSocketC(AI Gateway)C -->HTTP/GRPC StreamD(大模型服務)D -->文本/控制指令CC -->TTS音頻/指令BB -->RTP音頻A

3. 核心組件

組件技術選型核心功能
媒體網關FreeSWITCH 1.10+處理SIP呼叫、RTP音頻流、DTMF事件管理
協議橋接層mod_websocket (ESL+自定義模塊)音頻轉WebSocket二進制流(支持OPUS/PCM)
AI網關Node.js/Python (Tornado)雙向WS通信、ASR/TTS調度、會話狀態機管理
大模型接口GRPC Stream/HTTP2 Server流式對話處理&指令生成(200ms級響應)
ASR/TTS引擎阿里云/訊飛/DeepSeek RTS實時語音<=>文本轉換(<300ms延遲)
模型推理層DeepSeek-V2/GLM-4 API流式對話生成,支持SSML控制指令

4. 關鍵流程

4.1 語音輸入流 (User → AI)

FreeSWITCH --(RTP)–> mod_websocket --(WS Binary/OPUS)–> AI網關 --(ASR API)–> 大模型

  • 數據封裝
    json
    {
    “call_id”: “call-123456”,
    “seq”: 1024,
    “is_final”: false,
    “timestamp”: 1721541687000,
    “payload”: “BASE64_OPUS”
    }

4.2 AI響應流 (AI → User)

大模型 --(SSML指令)–> AI網關 --(WS控制消息)–> TTS服務 --(RTP)–> FreeSWITCH

  • 中斷響應機制
    • DTMF #鍵觸發barge-in事件
    • TTS首包到達時間<100ms

4.3 控制指令示例

json
// ASR識別結果
{“event”:“asr_result”, “text”:“查余額”, “confidence”:0.95}

// TTS響應指令
{“event”:“ai_response”, “type”:“tts”, “audio”:“chunk_123.opus”}

// 業務轉移指令
{“event”:“action”, “command”:“transfer:6001”}

5. 性能優化

  • 音頻分片處理:80ms/幀(160采樣@16kHz)
  • 雙緩沖ASR策略:預加載靜音語音模型加速首字響應
  • 動態抖動緩沖:網絡延遲>150ms時自動補償
  • 會話熱插拔:通話保持時維持AI對話上下文
  • 熔斷機制:模型響應>2s時轉人工服務

6. 異常處理機制

故障場景解決方案
WebSocket斷連10秒自動重連+20秒音頻緩存
ASR識別沖突基于時間戳的序列仲裁
模型響應超時播放「正在思考」提示音
DTMF中斷事件立即停止TTS并清空隊列
編碼格式不匹配OPUS/PCM/G.711動態切換
local cjson = require "dkjson"
local pts   = require "ppytools"local ws_addr = "ws://127.0.0.1:20000"
ws_addr = "wss://127.0.0.1:12345"
--ws_addr = "wss://ai.xxx.com:12345"local records_base = "/workspace/records"local script_path = debug.getinfo(1, "S").source:sub(2)
local script_name = script_path:match("([^/\\]+)$") or "unknown"local fs_api = freeswitch.API()function fslog(msg, log_level)log_level = (log_level ~= nil) and log_level or "info"  -- 嚴格判斷nilfreeswitch.consoleLog(log_level, "[".. script_name .. "] "..msg)
endfunction main()local session_lega = sessionlocal session_lega_uuid = session_lega:get_uuid()fslog(string.format("[START][%s]\n", session_lega_uuid))session_lega:answer()local datetime_dir, records_dir = pts.create_compact_date_dir(records_base)local caller_id_number = session_lega:getVariable("caller_id_number")local destination_number = session_lega:getVariable("destination_number")fslog(string.format("session_lega_uuid: %s , caller_id_number: %s , destination_number: %s\n", session_lega_uuid, caller_id_number, destination_number))--后臺通話錄音if records_dir ~= nil then-- 啟用雙聲道錄音session_lega:setVariable("RECORD_STEREO", "true")  local records_str = string.format("bgapi uuid_record %s start %s/%s.wav 1000 0 0", session_lega_uuid, records_dir, session_lega_uuid)fslog(records_str)fs_api:executeString(records_str) --CDR自定義變量session_lega:setVariable("record_file_uri_path", string.format("%s/%s.wav", datetime_dir, session_lega_uuid))end--缺省將用戶語音數據通過二進制方式發送到AI服務器。--如果這個參數設置為true,則通過JSON格式發送。和AI服務器發給FS的JSON格式一致session_lega:setVariable("STREAM_MESSAGE_SENDJSON", "true")local con = freeswitch.EventConsumer()con:bind("CUSTOM", "mod_audio_stream::json")con:bind("CUSTOM", "mod_audio_stream::connect")con:bind("CUSTOM", "mod_audio_stream::disconnect")con:bind("CUSTOM", "mod_audio_stream::error")local start_time = os.date("%Y-%m-%d %H:%M:%S", os.time())local metadata_obj = {type = "init",sid  = session_lega_uuid,phone_number = caller_id_number,timestamp = start_time}local metadata = cjson.encode(metadata_obj)fslog("metadata:" .. metadata)local result, err = fs_api:execute("uuid_audio_stream", string.format("%s start %s mono 8k %s", session_lega_uuid, ws_addr, metadata))if result thenfslog(string.format("Function executed successfully: %s\n", result), "notice")elsefslog(string.format("Error executing function: %s\n", err), "err")endwhile session_lega:ready() dolocal event = con:pop()if event thenlocal event_uuid = event:getHeader("Unique-ID")if event_uuid == session_lega_uuid thenlocal event_name = event:getHeader("Event-Name")local event_sub = event:getHeader("Event-Subclass")local body = event:getBody()fslog(string.format("JSON executing function, Event-Subclass: %s, body: %s\n", event_sub, body))if event_sub == "mod_audio_stream::connect" then--elseif event_sub == "mod_audio_stream::disconnect" thenbreakelseif event_sub == "mod_audio_stream::json" thenlocal data = cjson.decode(body)if data.type == "sentence" and data.status == "start" thenlocal metadata_obj = {type = "sentence_callback",sentence_id  = data.sentence_id,status = "play",timestamp = os.date("%Y-%m-%d %H:%M:%S", os.time())}local metadata = cjson.encode(metadata_obj)fslog("[send_text]metadata:" .. metadata)fs_api:execute("uuid_audio_stream", string.format("%s send_text %s", session_lega_uuid, metadata))endif data.type == "streamText" thenif data.assistant thenfslog(data.assistant)endendif data.toHuman thenbreakelseif data.stop thenfslog("data stop", "err")elseif data.clear thenfslog("data clear", "err")endelseif event_sub == "mod_audio_stream::error" thenbreakelse--endendelseif session_lega thensession_lega:sleep(20)elsebreakendendend--fs_api:execute("uuid_record", string.format("%s stop", session_lega_uuid))fslog(string.format("[END][%s]\n", session_lega_uuid))
endmain()

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/915610.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/915610.shtml
英文地址,請注明出處:http://en.pswp.cn/news/915610.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

航班調度優化策略全局概覽

在機場關閉場景下的航班恢復工作&#xff0c;是將機場關閉期間所有的航班進行取消然后恢復還是將機場關閉期間航班全部延誤而后調整呢&#xff1f;簡單來說&#xff0c;在實際操作中&#xff0c;既不是無差別地全部取消&#xff0c;也不是無差別地全部延誤。這兩種“一刀切”的…

spring boot 異步線程@Async 傳遞 threadLocal數據

將父類的 threadLocal 的數據 在線程池時&#xff0c;可以轉給子線程使用。 Async 的使用。 第一步在啟動服務加上 EnableAsync 注解。 EnableAsync public class NetCoreApplication {... ... }第二步&#xff1a;導入阿里 線程工具類<dependency><groupId>com.a…

AI產品經理成長記《零號列車》第一集 邂逅0XAI列車

《零號列車》絕非傳統意義上的 AI 產品經理教程 —— 它是我沉淀二十多年跨行業數字化轉型與工業 4.0 實戰經驗后,首創的100集大型小說體培養指南。那些曾在千行百業驗證過的知識與經驗,不再是枯燥的文字堆砌,而是化作一場沉浸式的學習旅程。? 這里沒有生硬的理論灌輸,而…

[C++11]范圍for循環/using使用

范圍for循環 范圍for循環&#xff08;Range-based for loop&#xff09;是 C11 引入的一種簡潔的循環語法&#xff0c;用于遍歷容器中的元素或者其他支持迭代的數據結構。 范圍for循環可以讓代碼更加簡潔和易讀&#xff0c;避免了傳統for循環中索引的操作。 下面是范圍for循環的…

簡單了解下npm、yarn 和 pnpm 中 add 與 install(i) 命令的區別(附上兩圖帶你一目明了)

目錄 pnpm 中 add 和 i 的區別 npm 中 add 和 i 的區別 yarn 中 add 和 i 的區別 附上兩圖帶你一目明了&#xff1a; npm、yarn和pnpm的三者區別圖&#xff1a; i 和 add 的核心區別圖&#xff1a; 個人建議&#xff1a;在項目中保持命令使用的一致性&#xff0c;選擇一種…

ESP32-S3學習筆記<2>:GPIO的應用

ESP32-S3學習筆記&#xff1c;2&#xff1e;&#xff1a;GPIO的應用1. 頭文件包含2. GPIO的配置2.1 pin_bit_mask2.2 mode2.3 pull_up_en和pull_down_en2.4 intr_type3. 設置GPIO輸出/獲取GPIO輸入4. 中斷的使用4.1 gpio_install_isr_service4.2 gpio_isr_handler_add4.3 gpio_…

得物視覺算法面試30問全景精解

得物視覺算法面試30問全景精解 ——潮流電商 商品鑒別 視覺智能&#xff1a;得物視覺算法面試核心考點全覽 前言 得物App作為中國領先的潮流電商與鑒別平臺&#xff0c;持續推動商品識別、真假鑒別、圖像搜索、內容審核、智能推薦等視覺AI技術的創新與落地。得物視覺算法崗位…

[Linux入門] Linux 賬號和權限管理入門:從基礎到實踐

一、Linux 用戶賬號&#xff1a;誰能訪問系統&#xff1f; 1??超級用戶&#xff08;root&#xff09; 2??普通用戶 3??程序用戶 二、組賬號&#xff1a;讓用戶管理更高效 1??組的類型 2??特殊組 三、用戶與組的 “身份證”&#xff1a;UID 和 GID 四、配置文…

阿里云ssl證書自動安裝及續訂(acme)

目錄 一、shell命令安裝 二、docker run安裝 三、docker compose安裝 一、shell命令安裝 # 安裝acme curl https://get.acme.sh | sh -s emailfloxxx5163.com# 注冊zerossl .acme.sh/acme.sh --register-account -m flowxxx25163.com --server zerossl# 獲取證書 export Al…

@fullcalendar/vue 日歷組件

功能&#xff1a;日程安排&#xff0c;展示日歷&#xff0c;可以用來做會議日歷&#xff0c;可以跨日期顯示日程。 Fullcalendarvue3 日歷組件 參考文檔&#xff1a;【vue2】一個完整的日歷組件 fullcalendar&#xff0c;會議預約功能 中文說明文檔&#xff1a;https://www.he…

Dijkstra 算法求解多種操作

一、問題背景與核心需求 需要找到從a到b的最優操作序列&#xff0c;使得總花費最小。三種操作的規則為&#xff1a; 操作 1&#xff1a;x → x1&#xff0c;花費c1&#xff1b;操作 2&#xff1a;x → x-1&#xff0c;花費c2&#xff1b;操作 3&#xff1a;x → x*2&#xff0…

本地項目提交到git教程

創建遠程倉庫 登錄 GitHub&#xff0c;點擊右上角 New repository。 填寫倉庫名稱&#xff08;如 my-project&#xff09;、描述&#xff0c;選擇公開 / 私有。 不要初始化 README、.gitignore 或 LICENSE&#xff08;保持空倉庫&#xff09;&#xff0c;點擊 Create repositor…

Linux 密碼生成利器:pwgen 命令詳解

往期好文&#xff1a;統信 UOS 運行 Windows 應用新利器&#xff01;彩虹虛擬化軟件 V3.2 全新上線&#xff0c;限時30天免費體驗 在日常運維、安全測試、用戶管理等場景中&#xff0c;隨機密碼的生成是一項常見需求。為了避免人工設置密碼帶來的重復性弱密碼問題&#xff0c;…

Qt 應用程序入口代碼分析

Qt 應用程序入口代碼分析 這段代碼是 Qt GUI 應用程序的標準入口點&#xff0c;相當于 Qt 程序的"心臟"。讓我詳細解釋每一部分的作用&#xff1a; int main(int argc, char *argv[]) {// 1. 創建 Qt 應用程序對象QApplication a(argc, argv);// 2. 創建主窗口對象Wi…

基于springboot+mysql的中小型醫院網站(源碼+論文+開題報告)

一、開發環境 Java技術 描述&#xff1a;Java是一種非常常用的編程語言&#xff0c;在全球編程語言排行榜上總是前三。Java的跨平臺能力十分強大&#xff0c;只需一次編譯&#xff0c;任何地方都可以運行。除此之外&#xff0c;它還擁有簡單的語法和實用的類庫&#xff0c;讓…

【Docker基礎】Docker-compose常用命令實踐(三):鏡像與配置管理

目錄 前言 1 鏡像與配置管理概述 1.1 核心概念解析 2 鏡像構建命令詳解 2.1 構建鏡像&#xff08;build命令&#xff09; 2.2 基本語法 2.3 常用選項 2.4 構建過程流程 2.5 實際應用案例 3 配置驗證命令詳解 3.1 驗證配置&#xff08;config命令&#xff09; 3.2 基…

Android 實例 - 分頁器封裝實現(上一頁按鈕、下一頁按鈕、當前頁碼 / 總頁數、每頁條數、總記錄數)

一、需求分頁器需要包含&#xff1a;【上一頁按鈕】、【下一頁按鈕】、【當前頁碼 / 總頁數】、【每頁條數】、【總記錄數】點擊【上一頁按鈕】&#xff0c;渲染上一頁的數據&#xff0c;如果當前頁碼為第一頁&#xff0c;則禁用【上一頁按鈕】點擊【下一頁按鈕】&#xff0c;渲…

從代碼學習深度強化學習 - SAC PyTorch版

文章目錄 前言 SAC處理連續動作空間問題 (Pendulum-v1) 核心代碼實現 **工具函數與環境初始化** **ReplayBuffer、網絡結構與SAC算法** **訓練與結果** SAC處理離散動作空間問題 (CartPole-v1) 核心代碼實現 **工具函數與環境初始化** **ReplayBuffer、網絡結構與SAC算法 (離散…

物聯網安裝調試-溫濕度傳感器

以下為溫濕度傳感器在物聯網安裝調試中的全流程技術指南,涵蓋選型、安裝、調試及故障排查,結合工業/農業/家居三大場景實操要點: 一、傳感器選型核心參數表 參數 工業場景 農業大棚 智能家居 選型建議 精度 0.5℃/1.5%RH 1℃/3%RH 1℃/5%RH 工業級首選Sensirion SHT3x系列 防…

MySQL 核心知識點梳理(1)

目錄 1.什么是數據庫? 關系型數據庫 非關系型數據庫 2.Mysql出現性能差的原因? 3.MySQL的內聯,左外聯,右外連接的區別 4.為什么要有三大范式 建表需要考慮的問題? char和varchar的區別 blob和text的區別? DATETIME和TIMESTAMP的區別 in和exists的區別 null值陷 …