冯杨

websocket断链重连,不限制连接次数;tts合成语音,角色声音更换一种;socket,csn源路径修改;音频处理控件引入,是搭配Fay控制器传入音频的配置。

@@ -45,8 +45,6 @@ import asyncio @@ -45,8 +45,6 @@ import asyncio
45 import torch 45 import torch
46 from typing import Dict 46 from typing import Dict
47 from logger import logger 47 from logger import logger
48 -from pydub import AudioSegment  
49 -from io import BytesIO  
50 48
51 49
52 app = Flask(__name__) 50 app = Flask(__name__)
@@ -153,7 +151,8 @@ async def human(request): @@ -153,7 +151,8 @@ async def human(request):
153 {"code": 0, "data":"ok"} 151 {"code": 0, "data":"ok"}
154 ), 152 ),
155 ) 153 )
156 - 154 +from pydub import AudioSegment
  155 +from io import BytesIO
157 async def humanaudio(request): 156 async def humanaudio(request):
158 try: 157 try:
159 params = await request.json() 158 params = await request.json()
@@ -496,7 +495,6 @@ if __name__ == '__main__': @@ -496,7 +495,6 @@ if __name__ == '__main__':
496 pagename='rtcpushapi.html' 495 pagename='rtcpushapi.html'
497 logger.info('start http server; http://<serverip>:'+str(opt.listenport)+'/'+pagename) 496 logger.info('start http server; http://<serverip>:'+str(opt.listenport)+'/'+pagename)
498 logger.info('如果使用webrtc,推荐访问webrtc集成前端: http://<serverip>:'+str(opt.listenport)+'/dashboard.html') 497 logger.info('如果使用webrtc,推荐访问webrtc集成前端: http://<serverip>:'+str(opt.listenport)+'/dashboard.html')
499 -  
500 def run_server(runner): 498 def run_server(runner):
501 loop = asyncio.new_event_loop() 499 loop = asyncio.new_event_loop()
502 asyncio.set_event_loop(loop) 500 asyncio.set_event_loop(loop)
@@ -90,7 +90,7 @@ class BaseTTS: @@ -90,7 +90,7 @@ class BaseTTS:
90 ########################################################################################### 90 ###########################################################################################
91 class EdgeTTS(BaseTTS): 91 class EdgeTTS(BaseTTS):
92 def txt_to_audio(self,msg): 92 def txt_to_audio(self,msg):
93 - voicename = "zh-CN-YunxiaNeural" 93 + voicename = "zh-CN-XiaoxiaoNeural"
94 text,textevent = msg 94 text,textevent = msg
95 t = time.time() 95 t = time.time()
96 asyncio.new_event_loop().run_until_complete(self.__main(voicename,text)) 96 asyncio.new_event_loop().run_until_complete(self.__main(voicename,text))
@@ -284,6 +284,7 @@ @@ -284,6 +284,7 @@
284 <h1 class="text-center mb-4">livetalking数字人交互平台</h1> 284 <h1 class="text-center mb-4">livetalking数字人交互平台</h1>
285 </div> 285 </div>
286 </div> 286 </div>
  287 + <input type="hidden" id="username" value="User">
287 288
288 <div class="row"> 289 <div class="row">
289 <!-- 视频区域 --> 290 <!-- 视频区域 -->
@@ -450,6 +451,154 @@ @@ -450,6 +451,154 @@
450 } 451 }
451 } 452 }
452 453
  454 + var ws;
  455 + var reconnectInterval = 5000; // 初始重连间隔为5秒
  456 + var reconnectAttempts = 0;
  457 + var maxReconnectInterval = 60000; // 最大重连间隔为60秒
  458 + var isReconnecting = false; // 标记是否正在重连中
  459 +
  460 + function generateUsername() {
  461 + var username = 'User';
  462 + // + Math.floor(Math.random() * 10000)
  463 + return username;
  464 + }
  465 +
  466 + function setUsername() {
  467 + var storedUsername = localStorage.getItem('username');
  468 + if (!storedUsername) {
  469 + storedUsername = generateUsername();
  470 + localStorage.setItem('username', storedUsername);
  471 + }
  472 + $('#username').val(storedUsername); // Use the username as the session ID
  473 + }
  474 +
  475 + setUsername();
  476 + function connectWebSocket() {
  477 + var host = window.location.hostname;
  478 + ws = new WebSocket("ws://127.0.0.1:10002");
  479 + ws.onopen = function() {
  480 + console.log('Connected to WebSocket on port 10002');
  481 + reconnectAttempts = 0; // 重置重连次数
  482 + reconnectInterval = 5000; // 重置重连间隔
  483 + updateConnectionStatus('connected');
  484 +
  485 + // 在连接成功后发送 {"Username": "User"}
  486 + var loginMessage = JSON.stringify({ "Username": $('#username').val() });
  487 + ws.send(loginMessage);
  488 + loginMessage = JSON.stringify({ "Output": "1" });
  489 + ws.send(loginMessage);
  490 + };
  491 +
  492 +
  493 + function addMessage(text, type = "right") {
  494 + const chatOverlay = document.getElementById("chatOverlay");
  495 + const messageDiv = document.createElement("div");
  496 + messageDiv.classList.add("message", type);
  497 +
  498 + const avatar = document.createElement("img");
  499 + avatar.classList.add("avatar");
  500 + avatar.src = type === "right" ? "images/avatar-right.png" : "images/avatar-left.png";
  501 +
  502 + const textContainer = document.createElement("div");
  503 + textContainer.classList.add("text-container");
  504 +
  505 + const textElement = document.createElement("div");
  506 + textElement.classList.add("text");
  507 + textElement.textContent = text;
  508 +
  509 + const timeElement = document.createElement("div");
  510 + timeElement.classList.add("time");
  511 + timeElement.textContent = new Date().toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
  512 +
  513 + textContainer.appendChild(textElement);
  514 + textContainer.appendChild(timeElement);
  515 +
  516 + messageDiv.appendChild(avatar);
  517 + messageDiv.appendChild(textContainer);
  518 +
  519 + chatOverlay.appendChild(messageDiv);
  520 +
  521 + // 自动滚动到底部
  522 + chatOverlay.scrollTop = chatOverlay.scrollHeight;
  523 + }
  524 +
  525 + ws.onmessage = function(e) {
  526 + console.log('WebSocket原始消息(dashboard.html):', e.data);
  527 + var messageData = JSON.parse(e.data);
  528 +
  529 + if (messageData.Data && messageData.Data.Key) {
  530 + if(messageData.Data.Key == "audio"){
  531 + var value = messageData.Data.HttpValue;
  532 + console.log('Value:', value);
  533 + fetch('/humanaudio', {
  534 + body: JSON.stringify({
  535 + file_url: value,
  536 + sessionid:parseInt(document.getElementById('sessionid').value),
  537 + }),
  538 + headers: {
  539 + 'Content-Type': 'application/json'
  540 + },
  541 + method: 'POST'
  542 + });
  543 + }else if (messageData.Data.Key == "text") {
  544 + var reply = messageData.Data.Value;
  545 + addMessage(reply, "left");
  546 + }
  547 + }
  548 +
  549 + };
  550 +
  551 + ws.onclose = function(e) {
  552 + console.log('WebSocket connection closed');
  553 + attemptReconnect();
  554 + };
  555 +
  556 + ws.onerror = function(e) {
  557 + console.error('WebSocket error:', e);
  558 + ws.close(); // 关闭连接并尝试重连
  559 + };
  560 + }
  561 +
  562 + function attemptReconnect() {
  563 + if (isReconnecting) return; // 防止多次重连
  564 +
  565 + isReconnecting = true;
  566 + reconnectAttempts++;
  567 +
  568 + // 使用指数退避算法计算下一次重连间隔
  569 + var currentInterval = Math.min(reconnectInterval * Math.pow(1.5, reconnectAttempts - 1), maxReconnectInterval);
  570 +
  571 + console.log('Attempting to reconnect... (Attempt ' + reconnectAttempts + ', 间隔: ' + currentInterval/1000 + '秒)');
  572 + updateConnectionStatus('connecting');
  573 +
  574 + if(document.getElementById('is_open') && parseInt(document.getElementById('is_open').value) == 1){
  575 + stop()
  576 + }
  577 +
  578 + setTimeout(function() {
  579 + isReconnecting = false;
  580 + connectWebSocket();
  581 + }, currentInterval);
  582 + }
  583 +
  584 + // 初始化 WebSocket 连接
  585 + connectWebSocket();
  586 +
  587 + // 添加页面可见性变化监听,当页面从隐藏变为可见时尝试重连
  588 + document.addEventListener('visibilitychange', function() {
  589 + if (document.visibilityState === 'visible') {
  590 + // 页面变为可见状态,检查WebSocket连接
  591 + if (!ws || ws.readyState === WebSocket.CLOSED || ws.readyState === WebSocket.CLOSING) {
  592 + console.log('页面可见,检测到WebSocket未连接,尝试重连...');
  593 + updateConnectionStatus('connecting');
  594 + // 重置重连计数和间隔,立即尝试重连
  595 + reconnectAttempts = 0;
  596 + reconnectInterval = 5000;
  597 + connectWebSocket();
  598 + }
  599 + }
  600 + });
  601 +
453 // 添加聊天消息 602 // 添加聊天消息
454 function addChatMessage(message, type = 'user') { 603 function addChatMessage(message, type = 'user') {
455 const messagesContainer = $('#chat-messages'); 604 const messagesContainer = $('#chat-messages');
@@ -50,7 +50,7 @@ @@ -50,7 +50,7 @@
50 <input type="text" id="audiotype" value="0"> 50 <input type="text" id="audiotype" value="0">
51 51
52 <script src="client.js"></script> 52 <script src="client.js"></script>
53 -<script type="text/javascript" src="http://cdn.sockjs.org/sockjs-0.3.4.js"></script> 53 +<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/sockjs-client@1.5.1/dist/sockjs.min.js"></script>
54 <script type="text/javascript" src="https://code.jquery.com/jquery-2.1.1.min.js"></script> 54 <script type="text/javascript" src="https://code.jquery.com/jquery-2.1.1.min.js"></script>
55 </body> 55 </body>
56 <script type="text/javascript" charset="utf-8"> 56 <script type="text/javascript" charset="utf-8">
@@ -3,6 +3,8 @@ @@ -3,6 +3,8 @@
3 <head> 3 <head>
4 <meta charset="UTF-8"/> 4 <meta charset="UTF-8"/>
5 <meta name="viewport" content="width=device-width, initial-scale=1.0" /> 5 <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  6 + <link rel="icon" href="favicon.ico" type="image/x-icon">
  7 + <link rel="shortcut icon" href="favicon.ico" type="image/x-icon">
6 <title>WebRTC 数字人</title> 8 <title>WebRTC 数字人</title>
7 <style> 9 <style>
8 body { 10 body {
@@ -276,7 +278,7 @@ @@ -276,7 +278,7 @@
276 </div> 278 </div>
277 279
278 <script src="client.js"></script> 280 <script src="client.js"></script>
279 -<script type="text/javascript" src="http://cdn.sockjs.org/sockjs-0.3.4.js"></script> 281 +<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/sockjs-client@1.5.1/dist/sockjs.min.js"></script>
280 <script type="text/javascript" src="https://code.jquery.com/jquery-2.1.1.min.js"></script> 282 <script type="text/javascript" src="https://code.jquery.com/jquery-2.1.1.min.js"></script>
281 <script type="text/javascript" charset="utf-8"> 283 <script type="text/javascript" charset="utf-8">
282 284
@@ -387,17 +389,20 @@ @@ -387,17 +389,20 @@
387 389
388 // WebSocket connection to Fay digital avatar (port 10002) 390 // WebSocket connection to Fay digital avatar (port 10002)
389 var ws; 391 var ws;
390 - var reconnectInterval = 5000; // 每5秒尝试重连一次  
391 - var maxReconnectAttempts = 10; // 最大重连次数 392 + var reconnectInterval = 5000; // 初始重连间隔为5秒
392 var reconnectAttempts = 0; 393 var reconnectAttempts = 0;
  394 + var maxReconnectInterval = 60000; // 最大重连间隔为60秒
  395 + var isReconnecting = false; // 标记是否正在重连中
393 396
394 function generateUsername() { 397 function generateUsername() {
395 - var username = 'User' + Math.floor(Math.random() * 10000); 398 + var username = 'User';
  399 + // + Math.floor(Math.random() * 10000)
396 return username; 400 return username;
397 } 401 }
398 402
399 function setUsername() { 403 function setUsername() {
400 var storedUsername = localStorage.getItem('username'); 404 var storedUsername = localStorage.getItem('username');
  405 + // console.log("当前存有的username:"+storedUsername);
401 if (!storedUsername) { 406 if (!storedUsername) {
402 storedUsername = generateUsername(); 407 storedUsername = generateUsername();
403 localStorage.setItem('username', storedUsername); 408 localStorage.setItem('username', storedUsername);
@@ -411,7 +416,7 @@ @@ -411,7 +416,7 @@
411 ws.onopen = function() { 416 ws.onopen = function() {
412 console.log('Connected to WebSocket on port 10002'); 417 console.log('Connected to WebSocket on port 10002');
413 reconnectAttempts = 0; // 重置重连次数 418 reconnectAttempts = 0; // 重置重连次数
414 - 419 + reconnectInterval = 5000; // 重置重连间隔
415 // 在连接成功后发送 {"Username": "User"} 420 // 在连接成功后发送 {"Username": "User"}
416 var loginMessage = JSON.stringify({ "Username": $('#username').val() }); 421 var loginMessage = JSON.stringify({ "Username": $('#username').val() });
417 ws.send(loginMessage); 422 ws.send(loginMessage);
@@ -453,6 +458,7 @@ @@ -453,6 +458,7 @@
453 } 458 }
454 459
455 ws.onmessage = function(e) { 460 ws.onmessage = function(e) {
  461 + console.log('WebSocket原始消息(webrtcapi.html):', e.data);
456 var messageData = JSON.parse(e.data); 462 var messageData = JSON.parse(e.data);
457 463
458 if (messageData.Data && messageData.Data.Key) { 464 if (messageData.Data && messageData.Data.Key) {
@@ -489,22 +495,42 @@ @@ -489,22 +495,42 @@
489 } 495 }
490 496
491 function attemptReconnect() { 497 function attemptReconnect() {
492 - if (reconnectAttempts < maxReconnectAttempts) { 498 + if (isReconnecting) return; // 防止多次重连
  499 +
  500 + isReconnecting = true;
493 reconnectAttempts++; 501 reconnectAttempts++;
494 - console.log('Attempting to reconnect... (Attempt ' + reconnectAttempts + ')');  
495 - if(parseInt(document.getElementById('is_open').value) == 1){ 502 +
  503 + // 使用指数退避算法计算下一次重连间隔
  504 + var currentInterval = Math.min(reconnectInterval * Math.pow(1.5, reconnectAttempts - 1), maxReconnectInterval);
  505 +
  506 + console.log('Attempting to reconnect... (Attempt ' + reconnectAttempts + ', 间隔: ' + currentInterval/1000 + '秒)');
  507 +
  508 + if(document.getElementById('is_open') && parseInt(document.getElementById('is_open').value) == 1){
496 stop() 509 stop()
497 } 510 }
  511 +
498 setTimeout(function() { 512 setTimeout(function() {
  513 + isReconnecting = false;
499 connectWebSocket(); 514 connectWebSocket();
500 - }, reconnectInterval);  
501 - } else {  
502 - console.error('Maximum reconnection attempts reached. Could not reconnect to WebSocket.');  
503 - } 515 + }, currentInterval);
504 } 516 }
505 517
506 // 初始化 WebSocket 连接 518 // 初始化 WebSocket 连接
507 connectWebSocket(); 519 connectWebSocket();
  520 +
  521 + // 添加页面可见性变化监听,当页面从隐藏变为可见时尝试重连
  522 + document.addEventListener('visibilitychange', function() {
  523 + if (document.visibilityState === 'visible') {
  524 + // 页面变为可见状态,检查WebSocket连接
  525 + if (!ws || ws.readyState === WebSocket.CLOSED || ws.readyState === WebSocket.CLOSING) {
  526 + console.log('页面可见,检测到WebSocket未连接,尝试重连...');
  527 + // 重置重连计数和间隔,立即尝试重连
  528 + reconnectAttempts = 0;
  529 + reconnectInterval = 5000;
  530 + connectWebSocket();
  531 + }
  532 + }
  533 + });
508 }); 534 });
509 </script> 535 </script>
510 </body> 536 </body>
@@ -51,7 +51,7 @@ @@ -51,7 +51,7 @@
51 </div> 51 </div>
52 52
53 <script src="client.js"></script> 53 <script src="client.js"></script>
54 -<script type="text/javascript" src="http://cdn.sockjs.org/sockjs-0.3.4.js"></script> 54 +<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/sockjs-client@1.5.1/dist/sockjs.min.js"></script>
55 <script type="text/javascript" src="https://code.jquery.com/jquery-2.1.1.min.js"></script> 55 <script type="text/javascript" src="https://code.jquery.com/jquery-2.1.1.min.js"></script>
56 </body> 56 </body>
57 <script type="text/javascript" charset="utf-8"> 57 <script type="text/javascript" charset="utf-8">