django rest framework 结合百度语音合成 基于channels实现实时通讯

django rest framework 结合百度语音合成 基于channels实现实时通讯

功能简介:前后端分离 django rest framework 实现用户在前端发起一笔提现,经过channels处理将信息发至其代理,结合百度语音合成,将文字合成语音播放;

百度语音合成介绍:https://ai.baidu.com/docs/#/TTS-API/top

操作步骤:

安装:

pip install channels

添加channels到您的 INSTALLED_APPS设置:

INSTALLED_APPS = [
‘django.contrib.admin’,
‘django.contrib.auth’,
‘django.contrib.contenttypes’,
‘django.contrib.sessions’,
‘django.contrib.messages’,
‘django.contrib.staticfiles’,
‘django_crontab’,
‘user.apps.UserConfig’,
‘nsm.apps.NsmConfig’,
‘trade.apps.TradeConfig’,
‘channel.apps.ChannelConfig’,
‘card.apps.CardConfig’,
‘proxy.apps.ProxyConfig’,
‘spuser.apps.SpuserConfig’,
‘rest_framework’,
‘django_filters’,
‘channels’,
]
在以下位置进行默认路由myproject/routing.py:
django rest framework 结合百度语音合成 基于channels实现实时通讯_第1张图片

from channels.auth import AuthMiddlewareStack
from channels.routing import ProtocolTypeRouter, URLRouter
import card.routing
application = ProtocolTypeRouter({
    # Empty for now (http->django views is added by default)
    'websocket': AuthMiddlewareStack(
        URLRouter(
            card.routing.websocket_urlpatterns
        )
    ),
})

此根路由配置指定在与Channels开发服务器建立连接时,ProtocolTypeRouter将首先检查连接类型。如果它是WebSocket连接(ws://或wss://),则将连接到AuthMiddlewareStack。

在AuthMiddlewareStack将填充的连接的范围与到当前认证的用户,类似于Django的如何一个参考AuthenticationMiddleware填充请求与当前认证的用户的图功能的对象。(范围将在本教程的后面部分讨论。)然后将连接到URLRouter。

在URLRouter将检查连接到路由到一个特定的消费者,基于所提供的HTTP路径url模式。

在settings中设置您的ASGI_APPLICATION 设置为指向该路由对象作为根应用程序:

ASGI_APPLICATION = “bank.routing.application”
你需要创建一个 应用:
如图我创建了一个app,为card,记得添加到INSTALLED_APPS设置
在这里插入图片描述
在card app 中创建一个py文件consumers.py

# chat/consumers.py

from asgiref.sync import async_to_sync
from channels.generic.websocket import WebsocketConsumer
import json
from utils.tts import test_audio
from bank.settings import CONN
from user.models import UserProfile

class ChatConsumer(WebsocketConsumer):
    def connect(self):

        # self.room_name = self.scope['url_route']['kwargs']['room_name']
        # self.room_group_name = 'chat_%s' % self.room_name
        #
        # # Join room group
        # async_to_sync(self.channel_layer.group_add)(
        #     self.room_group_name,
        #     self.channel_name
        # )

        self.accept()

    def disconnect(self, close_code):
        s=self.channel_name
        user=UserProfile.objects.filter(soket=str(s)).first()
        if user:
            print(111)
            user.soket=''
            user.save()
            if user.level==2:
                async_to_sync(self.channel_layer.group_discard)(
                    user.username,
                    self.channel_name
                )
                return
        # async_to_sync(self.channel_layer.group_discard)(
        #     user.username,
        #     self.channel_name)


    # Receive message from WebSocket
    def receive(self, text_data):
        print(666,text_data)
        try:
            text_data_json = json.loads(text_data)
            #print(text_data_json)
            token = text_data_json.get('token','')
            money = text_data_json.get('money', '')
            #print(money)
        except Exception:
            return
        from rest_framework_jwt.serializers import jwt_decode_handler
        try:
            payload = jwt_decode_handler(token)
        except Exception:
            return
        print('payload', payload)
        username = payload.get('username', '')
        if username:
            user = UserProfile.objects.filter(username=username).first()
            user.soket = self.channel_name
            user.save()

            if user.level == 2:
                async_to_sync(self.channel_layer.group_add)(
                    user.username,
                    self.channel_name
                )
                print('CONN.exists(user.username)',CONN.exists(user.username))
                if CONN.exists(user.username):
                    print(666)
                    withdeaw_money = CONN.get('money')
                    conn_username = CONN.get(user.username)
                    #百度语言合成
                    url = test_audio(str(conn_username) + "申请了一个包裹,金额为" + str(withdeaw_money,encoding='utf-8')+'元'+'请即时投递!' )
                    async_to_sync(self.channel_layer.group_send)(
                        user.username,
                        {
                            'type': 'chat_message',
                            'message': '提现申请',
                            'code':200,
                            'url':url
                        }
                    )
                    CONN.delete(user.username)
            elif user.level == 3:
                proxy_user = user.proxy
                if proxy_user.soket:
                    
                    # 百度语言合成
                    url = test_audio(user.username+"申请了一个包裹,金额为"+str(money)+'元'+'请即时投递!')
                    async_to_sync(self.channel_layer.group_send)(
                        proxy_user.username,
                        {
                            'type': 'chat_message',
                            'message': '提现申请',
                            'code':200,
                            'url':url
                        }
                    )

                else:
                    CONN.set(proxy_user.username, user.username)
                    CONN.set('money', str(money))

    # Receive message from room group
    def chat_message(self, event):
        print(9, event)
        message = event['message']
        code = event['code']
        url = event['url']
        # Send message to WebSocket
        self.send(text_data=json.dumps({
            'message': message,
            'code':code,
            'url':url
        }))

说明:里面用个一个model UserProfile,你需要自己建立一个app,然后建立模型,字段需要一个 socket来储存生成的socket,后面详细说明

然后再card app 中建立一个 routing.py

from django.conf.urls import url

from . import consumers

websocket_urlpatterns = [
    url(r'^socket/$', consumers.ChatConsumer),
]

说明:routing 里面有个路由映射到上面的 consumers

项目架构:
django rest framework 结合百度语音合成 基于channels实现实时通讯_第2张图片
在templates中创建2个 html,以供测试用而已,001代表商户,room代表代理
001.html 代码如下:





    
    Chat Room


    

说明:因为是 drf 框架,我携带了token到后端,解密后可以得知是哪个商户
room.html代码如下





    
    Chat Room


    


然后做好各url映射

项目\urls.py

urlpatterns = [
    url(r'^chat/', include('card.urls')),
    ]

app card\urls.py

from django.conf.urls import url

from . import views

urlpatterns = [
    url(r'^room/$', views.room, name='room'),
    url(r'^001/$', views.room1, name='room1'),
]

app card\views.py

from django.shortcuts import render


def room(request, ):
    return render(request, 'chat/room.html', {
        'room_name_json': '88'
    })


def room1(request):
    return render(request, 'chat/001.html', {
        'room_name_json': '99'
    })

运行迁移以应用数据库更改(Django的会话框架需要数据库),然后启动

就可以实现即时通讯

百度语音合成代码:

tts.py

# coding=utf-8
import sys
import json

IS_PY3 = sys.version_info.major == 3
if IS_PY3:
    from urllib.request import urlopen
    from urllib.request import Request
    from urllib.error import URLError
    from urllib.parse import urlencode
    from urllib.parse import quote_plus
else:
    import urllib2
    from urllib import quote_plus
    from urllib2 import urlopen
    from urllib2 import Request
    from urllib2 import URLError
    from urllib import urlencode

API_KEY = '4E1BG9lTnlSeIf1NQFlrSq6h'
SECRET_KEY = '544ca4657ba8002e3dea3ac2f5fdd241'

TEXT = "你有一笔新的提现申请"

# 发音人选择, 0为普通女声,1为普通男生,3为情感合成-度逍遥,4为情感合成-度丫丫,默认为普通女声
PER = 0
# 语速,取值0-15,默认为5中语速
SPD = 4
# 音调,取值0-15,默认为5中语调
PIT = 5
# 音量,取值0-9,默认为5中音量
VOL = 5
# 下载的文件格式, 3:mp3(default) 4: pcm-16k 5: pcm-8k 6. wav
AUE = 3

FORMATS = {3: "mp3", 4: "pcm", 5: "pcm", 6: "wav"}
FORMAT = FORMATS[AUE]

CUID = "123456PYTHON"

TTS_URL = 'http://tsn.baidu.com/text2audio'


class DemoError(Exception):
    pass


"""  TOKEN start """

TOKEN_URL = 'http://openapi.baidu.com/oauth/2.0/token'
SCOPE = 'audio_tts_post'  # 有此scope表示有tts能力,没有请在网页里勾选


def fetch_token():
    #print("fetch token begin")
    params = {'grant_type': 'client_credentials',
              'client_id': API_KEY,
              'client_secret': SECRET_KEY}
    post_data = urlencode(params)
    if (IS_PY3):
        post_data = post_data.encode('utf-8')
    req = Request(TOKEN_URL, post_data)
    try:
        f = urlopen(req, timeout=5)
        result_str = f.read()
    except URLError as err:
        print('token http response http code : ' + str(err.code))
        result_str = err.read()
    if (IS_PY3):
        result_str = result_str.decode()

    #print(result_str)
    result = json.loads(result_str)
    #print(result)
    if ('access_token' in result.keys() and 'scope' in result.keys()):
        if not SCOPE in result['scope'].split(' '):
            raise DemoError('scope is not correct')
       # print('SUCCESS WITH TOKEN: %s ; EXPIRES IN SECONDS: %s' % (result['access_token'], result['expires_in']))
        return result['access_token']
    else:
        raise DemoError('MAYBE API_KEY or SECRET_KEY not correct: access_token or scope not found in token response')


"""  TOKEN end """

def test_audio(text):
    token = fetch_token()
    tex = quote_plus(text)  # 此处TEXT需要两次urlencode
    #print(tex)
    params = {'tok': token, 'tex': tex, 'per': PER, 'spd': SPD, 'pit': PIT, 'vol': VOL, 'aue': AUE, 'cuid': CUID,
              'lan': 'zh', 'ctp': 1}  # lan ctp 固定参数

    data = urlencode(params)
    return TTS_URL + '?' + data


if __name__ == '__main__':
    token = fetch_token()
    tex = quote_plus(TEXT)  # 此处TEXT需要两次urlencode
    print(tex)
    params = {'tok': token, 'tex': tex, 'per': PER, 'spd': SPD, 'pit': PIT, 'vol': VOL, 'aue': AUE, 'cuid': CUID,
              'lan': 'zh', 'ctp': 1}  # lan ctp 固定参数

    data = urlencode(params)
    print('test on Web Browser' + TTS_URL + '?' + data)

    req = Request(TTS_URL, data.encode('utf-8'))
    has_error = False
    try:
        f = urlopen(req)
        result_str = f.read()

        headers = dict((name.lower(), value) for name, value in f.headers.items())

        has_error = ('content-type' not in headers.keys() or headers['content-type'].find('audio/') < 0)
    except  URLError as err:
        print('asr http response http code : ' + str(err.code))
        result_str = err.read()
        has_error = True

    save_file = "error.txt" if has_error else 'result.' + FORMAT
    with open(save_file, 'wb') as of:
        of.write(result_str)

    if has_error:
        if (IS_PY3):
            result_str = str(result_str, 'utf-8')
        print("tts api  error:" + result_str)

    print("result saved as :" + save_file)

测试后可行
django rest framework 结合百度语音合成 基于channels实现实时通讯_第3张图片

详情查看源文件地址:
http://www.debug5.com/detail/24/

你可能感兴趣的:(python,Django)