語音一對一聊天

来源:https://www.cnblogs.com/Dominic-Ji/archive/2018/08/22/9520879.html
-Advertisement-
Play Games

功能簡介: 不需要藉助百度的語音SDK即可完成,只需要通過前端語言利用頁面獲取用戶語音直接將語音數據發送給後端保存,之後通過條件判斷再將保存好的語言文件地址發送給目標用戶,藉此即可完成用戶之間的單點通信 前端代碼 ...


功能簡介:

  不需要藉助百度的語音SDK即可完成,只需要通過前端語言利用頁面獲取用戶語音直接將語音數據發送給後端保存,之後通過條件判斷再將保存好的語言文件地址發送給目標用戶,藉此即可完成用戶之間的單點通信

from flask import Flask,render_template,request,jsonify,send_file
from geventwebsocket.websocket import WebSocket
from geventwebsocket.handler import WebSocketHandler
from gevent.pywsgi import WSGIServer
import json
import os
import uuid
app=Flask(__name__)

@app.route('/',strict_slashes=False)
def temp():
    return render_template('單聊.html')

#提供給前端音頻標簽獲取音頻文件路由api
@app.route('/get_file/<filename>')
def get_file(filename):
    file =os.path.join('audio',filename)
    return send_file(file)

user_dict={}
#獲取客戶端用戶名
@app.route('/ws/<username>',strict_slashes=False)
def index(username):
    while True:
        user_socket=request.environ.get('wsgi.websocket') # type:WebSocket
        if user_socket==None:
            return '不要給我發http請求了,老子這裡只認websocket請求'
        user_dict[username]=user_socket
        file_name=""
        user_json=""
        while True:
            try:
                #獲取客戶端數據
                user_msg=user_socket.receive()
                #如果是音頻文件
                if type(user_msg) == bytearray:
                    #存放到audio文件下
                    file_name = f"{uuid.uuid4()}.wav"
                    file_name_path = os.path.join('audio',file_name)
                    with open(file_name_path,'wb')as f:
                        f.write(user_msg)
                else:
                    #否則則是正常的文本數據,直接序列化即可,這個主要是用來展示消息發出者是誰
                    user_json = json.loads(user_msg)
                #必須獲取到音頻數據和消息發出者信息後
                if file_name and user_json:
                    #把存放數據的文件路徑和發送者姓名傳給被交流者
                    send_msg={
                        "send_msg":file_name,
                        "send_user":username
                    }

                    to_user_socket=user_dict.get(user_json.get('to_user'))
                    to_user_socket.send(json.dumps(send_msg))
                    #將變數清空
                    file_name=""
                    user_json=""
            except Exception as a:
                print(a)
                user_dict.pop(username)
                break

if __name__ == '__main__':
    http_server=WSGIServer(('127.0.0.1',8000),app,handler_class=WebSocketHandler)
    http_server.serve_forever()

前端代碼

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>

    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link href="https://cdn.bootcss.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet">

</head>
<body>
<nav class="navbar navbar-inverse">
    <div class="container-fluid">
        <!-- Brand and toggle get grouped for better mobile display -->
        <div class="navbar-header">
            <button type="button" class="navbar-toggle collapsed" data-toggle="collapse"
                    data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
                <span class="sr-only">Toggle navigation</span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
            </button>
            <a class="navbar-brand" href="#">Brand</a>
        </div>

        <!-- Collect the nav links, forms, and other content for toggling -->
        <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
            <ul class="nav navbar-nav">
                <li class="active"><a href="#">Link <span class="sr-only">(current)</span></a></li>
                <li><a href="#">Link</a></li>
                <li class="dropdown">
                    <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true"
                       aria-expanded="false">Dropdown <span class="caret"></span></a>
                    <ul class="dropdown-menu">
                        <li><a href="#">Action</a></li>
                        <li><a href="#">Another action</a></li>
                        <li><a href="#">Something else here</a></li>
                        <li role="separator" class="divider"></li>
                        <li><a href="#">Separated link</a></li>
                        <li role="separator" class="divider"></li>
                        <li><a href="#">One more separated link</a></li>
                    </ul>
                </li>
            </ul>
            <form class="navbar-form navbar-left">
                <div class="form-group">
                    <input type="text" class="form-control" placeholder="Search">
                </div>
                <button type="submit" class="btn btn-default">Submit</button>
            </form>
            <ul class="nav navbar-nav navbar-right">
                <li><a href="#">Link</a></li>
                <li class="dropdown">
                    <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true"
                       aria-expanded="false">Dropdown <span class="caret"></span></a>
                    <ul class="dropdown-menu">
                        <li><a href="#">Action</a></li>
                        <li><a href="#">Another action</a></li>
                        <li><a href="#">Something else here</a></li>
                        <li role="separator" class="divider"></li>
                        <li><a href="#">Separated link</a></li>
                    </ul>
                </li>
            </ul>
        </div><!-- /.navbar-collapse -->
    </div><!-- /.container-fluid -->
</nav>
<div class="panel panel-primary">

    <div class="panel-heading">
        <h3 class="panel-title">聊天室</h3>
    </div>
    <div class="panel-body">
        <audio src="" id="player" autoplay="autoplay" controls></audio>
        <br>
        用戶名:<input type="text" id="username">&nbsp;
        目標對象:<input type="text" id="to_user">&nbsp;<button class="btn btn-info" id="create_link"
                                                           onclick="create_link()">創建鏈接
    </button>
        <div id="chat_window" style="width: 400px;height: 300px;">

        </div>
        <br>
        <div>
            <button onclick="start_rec()">錄音</button>
            <button onclick="stop_rec()">發送</button>
        </div>
    </div>
</div>
<script type="application/javascript" src="Recorder.js"></script>
<script type="application/javascript">
    var url = 'ws://127.0.0.1:8000/ws/';
    var ws = null;

    function create_link() {
        var username = document.getElementById('username');
        ws = new WebSocket(url + username.value);

        ws.onmessage = function (server_msg) {
            msg = JSON.parse(server_msg.data);
            create_chat('y', msg);

        };
    }
    function listen() {
            //將服務端返回的消息展現到音頻播放標簽中
            var player =document.getElementById('player');
            player.src='http://127.0.0.1:8000/get_file/'+msg.send_msg
    }

    function create_chat(self, content) {
        if (self == 'w') {
            self = 'right';
            var spantag = document.createElement('span');
            spantag.innerText = content.send_msg;
            var spantag1 = document.createElement('span');
            spantag1.innerText = ':我';
        } else {
            self = 'left';
            var spantag = document.createElement('span');
            spantag.innerText = content.send_user+':';
            var spantag1 = document.createElement('span');
            spantag1.innerHTML = "<button class='btn btn-primary' onclick='listen()'>收聽消息</button>";
        }
        var divtag = document.createElement('div');
        divtag.style = 'text-align:' + self;

        divtag.appendChild(spantag);
        divtag.appendChild(spantag1);
        var chat_window = document.getElementById('chat_window');
        chat_window.appendChild(divtag);
    }

    var rec = null;
    var audio_content = new AudioContext();

    navigator.getUserMedia = (
        navigator.getUserMedia ||
            navigator.webkitGetUserMedia ||
            navigator.mozGetUserMedia ||
            navigator.msGetUserMedia
    );

    navigator.getUserMedia({audio:true},create_stream,function (error) {
        console.log(error)
    });
    function create_stream(stream){
      var stream_input = audio_content.createMediaStreamSource(stream);
      rec = new Recorder(stream_input);
    }
    function start_rec(){
        rec.record();
    }
    function stop_rec(){
        rec.stop();
        get_audio();
        rec.clear()
    }

    function get_audio() {
        rec.exportWAV(function (wav_file) {
            var to_user = document.getElementById('to_user');
            send_msg_json = {
                to_user:to_user.value
            };
            ws.send(JSON.stringify(send_msg_json));
            var s_msg = {send_msg:"語音消息"};
            create_chat('w',s_msg);
            ws.send(wav_file);
        })
    }

</script>
</body>
</html>

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 背景: 使用TextView時,為了方便在開發工具中預覽效果,需要在TextView中設置文字(如:android:text="Hello World"),但是等到後面提交時,為了避免顯示這樣預設的信息,通常需要把這個刪除掉。但是刪除後,後續就無法預覽TextView了,為開髮帶來不便。 目標: 既 ...
  • 最近花了點心思整理了下我的博客園主題代碼,今天正式和大家分享一下,感興趣的園友可以瞭解一下。 主題介紹 Silence 追求大道至簡的終極真理,旨在打造一個乾凈、專註閱讀的博客主題,沒有二維空間元素、不存在花里胡哨。 簡單概括其幾個主要特點: 專註閱讀、精緻漂亮的 UI; 事無巨細的部署文檔; 相容 ...
  • 我們都知道瀏覽器有同源策略(same-origin policy)的安全限制,即每個站點只允許載入來自和自身同域(origin)的數據,https://a.com 是無法從 https://b.com 載入到資源的。每個站點被嚴格限制在了自已的孤島上,自己就是一個沙盒,這樣很安全,整個網路不會雜亂無... ...
  • 一、函數參數 1.可以使用預設參數 2.用let或const再次聲明參數會報錯,var不會。 3.使用參數預設值時,函數不能有同名參數。 4.參數預設值不是傳值的,而是每次都重新計算預設值表達式的值。也就是說,參數預設值是惰性求值的。 5.通常情況下,定義了預設值的參數,應該是函數的尾參數。 6.指 ...
  • 如何編碼解碼 編碼:var code=encodeURI("原文"); 解碼:var 原問=decodeURI("code"); 用encodeURIComponent代替encodeURI 用decodeURIComponent代替decodeURI eval 專門執行字元串格式的表達式 var ...
  • 滾動條距離(某些瀏覽器下麵做相容)document.documentElement.scrollTop || document.body.scrollTop 事件監聽實現相容:if(elem.addEventListener){ elem.addEventListener("click",fn) } ...
  • 遞歸:遞歸函數是在一個函數通過名字調用自身情況下構成的 /*function jiecheng(n){//n=5 if(n==1){//基點 return 1; }else{ return n*jiecheng(n-1); } }*/ //alert(jiecheng(100));//9.33262 ...
  • CSS權重 CSS權重指的是樣式的優先順序,有兩條或多條樣式作用於一個元素,權重高的那條樣式對元素起作用,權重相同的,後寫的樣式會覆蓋前面寫的樣式。 權重的等級 可以把樣式的應用方式分為幾個等級,按照等級來計算權重 1、!important,加在樣式屬性值後,權重值為 100002、內聯樣式,如:st ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...