博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
python 全栈开发,Day129(玩具开机提示语,为多个玩具发送点播,聊天界面,app录音,app与服务器端文件传输,简单的对话)...
阅读量:4672 次
发布时间:2019-06-09

本文共 19936 字,大约阅读时间需要 66 分钟。

 

一、玩具开机提示语

先下载github代码,下面的操作,都是基于这个版本来的!

注意:由于涉及到版权问题,此附件没有图片和音乐。请参考链接,手动采集一下!

请参考链接:

 

判断设备id

每一个玩具,都有设备id。如果在设备表中,提示找小主人。否则提示 联系厂家。

如果在玩具表中,提示开机!

 

进入flask项目,将jquery.min.js下载到static目录,下载链接如下:

 

使用jquery的原因,是因为要发送ajax的POST请求。使用$.post{}

修改 templates-->index.html,增加开机按钮

    
Title
View Code

 

修改 serv-->toys.py,增加视图函数device_toy_id

from flask import Blueprint, request, jsonifyfrom setting import MONGO_DBfrom setting import RETfrom bson import ObjectIdtoy = Blueprint("toy", __name__)@toy.route("/toy_list", methods=["POST"])def toy_list():  # 玩具列表    user_id = request.form.get("user_id")  # 用户id    # 查看用户信息    user_info = MONGO_DB.users.find_one({
"_id": ObjectId(user_id)}) bind_toy = user_info.get("bind_toy") # 获取绑定的玩具 bind_toy_id = [] # 玩具列表 for toy_id in bind_toy: # 获取玩具列表中的所有玩具id bind_toy_id.append(ObjectId(toy_id)) # 一次性查询多个玩具 toys_list = list(MONGO_DB.toys.find({
"_id": {
"$in": bind_toy_id}})) for index,item in enumerate(toys_list): # 将_id转换为字符串 toys_list[index]["_id"] = str(item.get("_id")) RET["code"] = 0 RET["msg"] = "" RET["data"] = toys_list return jsonify(RET)@toy.route("/device_toy_id", methods=["POST"])def device_toy_id(): device_id = request.form.get("device_id") # 获取设备id # 判断设备id是否在设备表中 if MONGO_DB.devices.find_one({
"device_id": device_id}): # 查询设备id是否在玩具表中 toy_info = MONGO_DB.toys.find_one({
"device_id": device_id}) if toy_info: return jsonify("开机") else: # 已授权的设备,但是没有绑定主人 return jsonify("找小主人") else: # 不在设备表中,说明是未授权,或者是冒牌的! return jsonify("联系玩具厂")
View Code

 

重启 manager.py,访问首页

输入一段数字,点击玩具开机键,效果如下:

 

打开 MongoDB客户端,复制一个不在玩具表(toys)中的设备id。效果如下:

 

复制一个,在玩具表中的设备id,效果如下:

 

提示语

后端逻辑判断,大致搞定了。下面来录制提示语,这里使用百度ai的接口。

在项目根目录,新建目录utils,在此目录下新建baidu_ai.py

此时,目录结构如下:

./├── audio├── audio_img├── device_code├── im_serv.py├── manager.py├── QRcode.py├── serv│   ├── content.py│   ├── devices.py│   ├── get_file.py│   └── toys.py├── setting.py├── static│   ├── jquery.min.js│   └── recorder.js├── templates│   └── index.html├── utils│   └── baidu_ai.py└── xiaopapa.py

 

修改 setting.py,增加百度AI的秘钥。注意:后5位被我修改了,请改为自己的!

import pymongoclient = pymongo.MongoClient(host="127.0.0.1", port=27017)MONGO_DB = client["bananabase"]RET = {    # 0: false 2: True    "code": 0,    "msg": "",  # 提示信息    "data": {}}XMLY_URL = "http://m.ximalaya.com/tracks/"  # 喜马拉雅链接CREATE_QR_URL = "http://qr.liantu.com/api.php?text="  # 生成二维码API# 文件目录import osAUDIO_FILE = os.path.join(os.path.dirname(__file__), "audio")  # 音频AUDIO_IMG_FILE = os.path.join(os.path.dirname(__file__), "audio_img")  # 音频图片DEVICE_CODE_PATH = os.path.join(os.path.dirname(__file__), "device_code")  # 二维码# 百度AI配置APP_ID = "11712345"API_KEY = "3v3igzCkVFUDwFByNEE12345"SECRET_KEY = "jRnwLE7kzC1aRi2FD10OQY3y9Og12345"SPEECH = {    "spd": 4,    'vol': 5,    "pit": 8,    "per": 4}
View Code

 

修改 baidu_ai.py,录制开机语音

from aip import AipSpeechimport osBASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))  # 项目根目录import syssys.path.append(BASE_DIR)  # 加入到系统环境变量中import setting  # 导入settingclient = AipSpeech(setting.APP_ID,setting.API_KEY,setting.SECRET_KEY)res = client.synthesis("欢迎来到嘉禾智能亲子互动乐园","zh",1,setting.SPEECH)with open(os.path.join(setting.AUDIO_FILE,"success.mp3"),"wb") as f:    f.write(res)
View Code

执行 baidu_ai.py,会在audio目录生成 success.mp3 文件。试听一下,感觉萌萌哒!

注意:语言文件的保存路径是audio。为什么呢?因为前端会调用get_audio接口。它是从audio目录读取的!

 

修改 baidu_ai.py,录制没有小主人语音

from aip import AipSpeechimport osBASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))  # 项目根目录import syssys.path.append(BASE_DIR)  # 加入到系统环境变量中import setting  # 导入settingclient = AipSpeech(setting.APP_ID,setting.API_KEY,setting.SECRET_KEY)res = client.synthesis("亲,我还没有小主人,快帮我找一个吧","zh",1,setting.SPEECH)with open(os.path.join(setting.AUDIO_FILE,"Nobind.mp3"),"wb") as f:    f.write(res)
View Code

执行 baidu_ai.py,会在audio目录生成 Nobind.mp3 文件。试听一下吧

 

修改 baidu_ai.py,录制联系玩具厂商语音

from aip import AipSpeechimport osBASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))  # 项目根目录import syssys.path.append(BASE_DIR)  # 加入到系统环境变量中import setting  # 导入settingclient = AipSpeech(setting.APP_ID,setting.API_KEY,setting.SECRET_KEY)res = client.synthesis("硬件设备不符,请联系玩具厂商","zh",1,setting.SPEECH)with open(os.path.join(setting.AUDIO_FILE,"Nodevice.mp3"),"wb") as f:    f.write(res)
View Code

执行 baidu_ai.py,会在audio目录生成 Nodevice.mp3 文件。试听一下吧

 

修改 serv-->toys.py,返回语音文件名

from flask import Blueprint, request, jsonifyfrom setting import MONGO_DBfrom setting import RETfrom bson import ObjectIdtoy = Blueprint("toy", __name__)@toy.route("/toy_list", methods=["POST"])def toy_list():  # 玩具列表    user_id = request.form.get("user_id")  # 用户id    # 查看用户信息    user_info = MONGO_DB.users.find_one({
"_id": ObjectId(user_id)}) bind_toy = user_info.get("bind_toy") # 获取绑定的玩具 bind_toy_id = [] # 玩具列表 for toy_id in bind_toy: # 获取玩具列表中的所有玩具id bind_toy_id.append(ObjectId(toy_id)) # 一次性查询多个玩具 toys_list = list(MONGO_DB.toys.find({
"_id": {
"$in": bind_toy_id}})) for index,item in enumerate(toys_list): # 将_id转换为字符串 toys_list[index]["_id"] = str(item.get("_id")) RET["code"] = 0 RET["msg"] = "" RET["data"] = toys_list return jsonify(RET)@toy.route("/device_toy_id", methods=["POST"])def device_toy_id(): # 验证设备id RET["code"] = 0 RET["msg"] = "开机成功" RET["data"] = {} device_id = request.form.get("device_id") # 获取设备id # 判断设备id是否在设备表中 if MONGO_DB.devices.find_one({
"device_id": device_id}): # 查询设备id是否在玩具表中 toy_info = MONGO_DB.toys.find_one({
"device_id": device_id}) if toy_info: # RET添加键值,获取玩具id RET["data"]["toy_id"] = str(toy_info.get("_id")) # 音频文件 RET["data"]["audio"] = "success.mp3" return jsonify(RET) else: # 已授权的设备,但是没有绑定主人 RET["msg"] = "找小主人" RET["data"]["audio"] = "Nobind.mp3" return jsonify(RET) else: # 不在设备表中,说明是未授权,或者是冒牌的! RET["msg"] = "联系玩具厂" RET["data"]["audio"] = "Nodevice.mp3" return jsonify(RET)
View Code

 

修改 index.html,POST请求成功后,修改audio标签的文件路径。将ws.onmessage代码移植到下面!

    
Title
View Code

 

重启 manager.py,访问首页,输入正确的设备id,效果如下:

 

这个功能,还可以扩展。比如判断今天是否为小主人的生日。说:生日快乐!

或者阳历节日,也可以提醒!

 

二、为多个玩具发送点播

用户有一个玩具,或者多个玩具时。

如果点击这个按钮,需要用户选择,指定发送给哪一个玩具。

 

 

目前数据库中,只有一个用户。昨天已经添加了一个,具体操作,请从参考昨天的链接:

 

现在再来添加一个!

 

绑定成功后,查看玩具表。有2条记录了

查看用户表,查看好友字段,会有2个!

 

建立连接

开2个页面,表示2个玩具。让2个玩具开机,需要2个合格的设备id。

打开玩具表,复制2个设备id

 

打开2个网页,左边输入 嘻嘻 的设备id

右边输入 小可爱 的设备id

 

在Console中,输入ws,回车。会出现一个websocket链接

注意:只要玩具开机了,就会建立 websocket连接!

 

查看Pycharm控制台输出:此时应该有2个websocket连接:

{
'5ba21c84e1253229c4acbd12':
, '5ba0f1f2e12532418089bf88':
}

 

那么APP页面,如何选择多个玩具呢?需要用到 弹出菜单

弹出菜单

mui框架内置了弹出菜单插件,弹出菜单显示内容不限,但必须包裹在一个含.mui-popover类的div中,如下即为一个弹出菜单内容:

要显示、隐藏如上菜单,mui推荐使用锚点方式,例如:

点击如上定义的按钮,即可显示弹出菜单,再次点击弹出菜单之外的其他区域,均可关闭弹出菜单;这种使用方式最为简洁。

若希望通过js的方式控制弹出菜单,则通过如下一个方法即可:

mui('.bottomPopover').popover(status[,anchor]);

status

  • 'show'
    显示popover
  • 'hide'
    隐藏popover
  • 'toggle'
    自动识别处理显示隐藏状态

 

mui('.bottomPopover').popover('toggle');//show hide toggle

 

本文参考链接:

 

修改 player.html,只修改html代码部分,js代码不用动!

            

正在播放

发送给玩具
View Code

 

使用模拟器访问,点击 发送给玩具,效果如下:

 

上面的item固定死了,需要展示为当前用户的 玩具名。需要访问后端接口,查询当前用户的所有玩具

 

修改 player.html

            

正在播放

发送给玩具
View Code

 

重新访问一次,效果如下:

 

点击 小豆芽 是没有效果的!需要增加点击事件。由于它是a标签,使用onclick

需要使用websocket发送数据。由于index.html建立了websocket连接,使用fire事件将数据发给index.html。

由index.html来发送数据!

 

修改player.html

            

正在播放

发送给玩具
View Code

 

index.html页面,就不需要修改了。因为它已经监听了 send_music 事件。

 

点击 小甜甜

此时,页面的第二个窗口,会自动播放歌曲。

 

 那么点歌功能,就完成了!

 

三、聊天页面

之前我们写的phone.html,好像没咋用过。将phone.html重命名为 message.html

好友列表,来源于 用户表(users) 的friend_list字段!

 

修改index.html,将底部选项卡 中的 电话 改为 消息

            
View Code

 

底部选项卡,效果如下:

 

修改 message.html,发送post,请求好友列表

            
Document

我的好友

View Code

 

进入 flask项目,进入serv目录,新建文件friend.py

from flask import Blueprint, request, jsonifyfrom setting import MONGO_DBfrom setting import RETfrom bson import ObjectIdfri = Blueprint("fri", __name__)@fri.route("/friend_list", methods=["POST"])def friend_list():  # 好友列表    user_id = request.form.get("user_id")    # 查询用户id信息    res = MONGO_DB.users.find_one({
"_id": ObjectId(user_id)}) friend_list = res.get("friend_list") # 获取好友列表 RET["code"] = 0 RET["msg"] = "" RET["data"] = friend_list return jsonify(RET)
View Code

 

修改 manager.py,注册蓝图

from flask import Flask, request,jsonify,render_templatefrom setting import MONGO_DBfrom setting import RETfrom bson import ObjectIdfrom serv import get_filefrom serv import contentfrom serv import devicesfrom serv import toysfrom serv import friendapp = Flask(__name__)app.register_blueprint(get_file.getfile)app.register_blueprint(content.cont)app.register_blueprint(devices.devs)app.register_blueprint(toys.toy)app.register_blueprint(friend.fri)@app.route('/')def hello_world():    return render_template("index.html")@app.route('/login',methods=["POST"])def login():    """    登陆验证    :return: settings -> RET    """    try:        RET["code"] = 1        RET["msg"] = "用户名或密码错误"        RET["data"] = {}        username = request.form.get("username")        password = request.form.get("password")        user = MONGO_DB.users.find_one({
"username": username, "password": password}) if user: # 由于user中的_id是ObjectId对象,需要转化为字符串 user["_id"] = str(user.get("_id")) RET["code"] = 0 RET["msg"] = "欢迎登陆" RET["data"] = {
"user_id": user.get("_id")} except Exception as e: RET["code"] = 1 RET["msg"] = "登陆失败" return jsonify(RET)@app.route('/reg',methods=["POST"])def reg(): """ 注册 :return: {"code":0,"msg":"","data":""} """ try: username = request.form.get("username") password = request.form.get("password") age = request.form.get("age") nickname = request.form.get("nickname") gender = request.form.get("gender") phone = request.form.get("phone") user_info = { "username": username, "password": password, "age": age, "nickname": nickname, # 判断gender==2,成立时为girl.jpg,否则为boy.jpg "avatar": "girl.jpg" if gender == 2 else "boy.jpg", "gender": gender, "phone": phone } res = MONGO_DB.users.insert_one(user_info) user_id = str(res.inserted_id) RET["code"] = 0 RET["msg"] = "注册成功" RET["data"] = user_id except Exception as e: RET["code"] = 1 RET["msg"] = "注册失败" return jsonify(RET)@app.route('/user_info', methods=["POST"])def user_info(): user_id = request.form.get("user_id") # "password": 0 表示忽略密码字段 res = MONGO_DB.users.find_one({
"_id": ObjectId(user_id)}, {
"password": 0}) if res: res["_id"] = str(res.get("_id")) RET["code"] = 0 RET["msg"] = "" RET["data"] = res return jsonify(res)if __name__ == '__main__': app.run("0.0.0.0", 9527, debug=True)
View Code

重启 manager.py

 

使用模拟器访问 消息 ,效果如下:

这个页面还是空的。查看HBuilder控制台输出:

{
"code":0,"data":[{
"friend_avatar":"girl.jpg","friend_chat":"5ba0f1f2e12532418089bf87","friend_id":"5ba0f1f2e12532418089bf88","friend_name":"小可爱","friend_remark":"小甜甜"},{
"friend_avatar":"girl.jpg","friend_chat":"5ba21c84e1253229c4acbd11","friend_id":"5ba21c84e1253229c4acbd12","friend_name":"嘻嘻","friend_remark":"小豆芽"}],"msg":""} at message.html:37

已经得到了数据,下面开始渲染页面!

 

修改 message.html,渲染页面

            
Document

我的好友

View Code

 

重新访问,效果如下:

 

 点击小甜甜,查看HBuilder控制台输出:

5ba0f1f2e12532418089bf88 at message.html:63

它会打印出,好友id。那么下面就可以开始聊天了!

 

新建css文件

 

chat.css

div.speech {    float: left;    margin: 0, 0;    padding: 6px;    table-layout: fixed;    word-break: break-all;    position: relative;    background: -webkit-gradient( linear, 50% 0%, 50% 100%, from(#ffffff), color-stop(0.1, #ececec), color-stop(0.5, #dbdbdb), color-stop(0.9, #dcdcdc), to(#8c8c8c));    border: 1px solid #989898;    border-radius: 8px;}div.speech:before {    content: '';    position: absolute;    width: 0;    height: 0;    left: 15px;    top: -20px;    border: 10px solid;    border-color: transparent transparent #989898 transparent;}div.speech:after {    content: '';    position: absolute;    width: 0;    height: 0;    left: 17px;    top: -16px;    border: 8px solid;    border-color: transparent transparent #ffffff transparent;}div.speech.right {    display: inline-block;    box-shadow: -2px 2px 5px #CCC;    margin-right: 10px;    max-width: 75%;    float: right;    background: -webkit-gradient( linear, 50% 0%, 50% 100%, from(#e4ffa7), color-stop(0.1, #bced50), color-stop(0.4, #aed943), color-stop(0.8, #a7d143), to(#99BF40));}div.speech.right:before {    content: '';    position: absolute;    width: 0;    height: 0;    top: 9px;    bottom: auto;    left: auto;    right: -10px;    border-width: 9px 0 9px 10px;    border-color: transparent #989898;}div.speech.right:after {    content: '';    position: absolute;    width: 0;    height: 0;    top: 10px;    bottom: auto;    left: auto;    right: -8px;    border-width: 8px 0 8px 9px;    border-color: transparent #bced50;}div.left {    display: inline-block;    box-shadow: 2px 2px 2px #CCCCCC;    margin-left: 10px;    max-width: 75%;    position: relative;    background: -webkit-gradient( linear, 50% 0%, 50% 100%, from(#ffffff), color-stop(0.1, #eae8e8), color-stop(0.4, #E3E3E3), color-stop(0.8, #DFDFDF), to(#D9D9D9));}div.left:before {    content: '';    position: absolute;    width: 0;    height: 0;    top: 9px;    bottom: auto;    left: -10px;    border-width: 9px 10px 9px 0;    border-color: transparent #989898;}div.left:after {    content: '';    position: absolute;    width: 0;    height: 0;    top: 10px;    bottom: auto;    left: -8px;    border-width: 8px 9px 8px 0;    border-color: transparent #eae8e8;}.leftimg {    float: left;    margin-top: 10px;}.rightimg {    float: right;    margin-top: 10px;}.leftd {    clear: both;    float: left;    margin-left: 10px;    margin-top: 15px;}.rightd {    clear: both;    float: right;    margin-top: 15px;    margin-right: 10px;}.leftd_h {    width: 45px;    height: 35px;    border-radius: 100%;    display: block;    float: left;    overflow: hidden;}.leftd_h img {    display: block;    width: 100%;    height: auto;}.rightd_h {    width: 45px;    height: 35px;    border-radius: 100%;    display: block;    float: right;    overflow: hidden;}.rightd_h img {    display: block;    width: 100%;    height: auto;}.chat-other {    background-color: red;    margin-top: 10px;    margin-left: 20px;}.chat-other-span {    background-color: aquamarine;    /*border-radius: 10%;*/    height: 18px;}.chat-mine {    margin-top: 10px;    margin-right: 20px;    text-align: right;}.chat-avatar {    border-radius: 100%;    width: 25px;    height: 25px;}
View Code

 

新建文件chat.html

 

手势事件

 在开发移动端的应用时,会用到很多的手势操作,比如滑动、长按等,为了方便开放者快速集成这些手势,mui内置了常用的手势事件,目前支持的手势事件见如下列表:

参考链接:

 

这里, 只用到了 长按里面的 hold和release

 

修改 chat.html

            
Document

与xxx进行对话

点击播放
点击播放
View Code

 

修改 message.html,增加点击事件。点击时,跳转到chat.html页面

            
Document

我的好友

View Code

 

使用模拟器访问,效果如下:

 

 

四、app录音

由于时间关系,详细步骤略...

五、app与服务器端文件传输

由于时间关系,详细步骤略...

六、简单的对话

由于时间关系,详细步骤略...

 

今日总结:

1.玩具开机提示语刚刚开机的时候:    1.授权问题(MD5授权码)提示语 : 请联系玩具厂商    2.绑定问题 提示语 : 快给我找一个小主人    3.成功 提示语:欢迎使用     2.为多个玩具发送点播:    mpop 弹出菜单 3.聊天界面:    
点击播放
点击播放
按住录音: hold: 按住事件 开始录音(回调函数) release: 松开事件 结束录音 执行录音中的回调函数 4.app录音: var rec = plus.audio.getRcorder() rec.record( {filename:"_doc/audio/",format:"amr"}, function(success){ success //录音文件保存路径 }, function(error){} ) rec.stop() 5.app与服务器端文件传输(ws传输): 1.app使用dataURL方式打开录音文件 : base64 文件 2.通过某个函数 将 Base64 格式的文件 转为 Blob 用于 websocket传输 3.将Blob对象使用Ws发送至服务端 4.服务端保存文件(amr) 5.将amr 转换为 mp3 使用 ffmpeg -i xxx.amr xxx.mp3 6.简单的对话(app向玩具(web)发起): app: 1.发起两次 ws.send({to_user:}) 告诉服务端我要发给谁消息 2. ws.send(blob) app与服务器端文件传输 websocket服务: 0.创建两个变量,用于接收to_user 和 blob对象 1.收到用户的JSON字符串,to_user 获取对方的Websocket,用户send 2.收到用户的Blob对象,语音文件 保存成amr文件,转换成mp3 注意保存文件的路径 3.将转换完成的文件发送给 to_user 4.两个变量置空
View Code

 

由于时间关系,详细步骤略...,主要修改了3个文件。

MyApp: chat.html,index.html

banana:  im_serv.py

 

最终效果,使用APP给 小甜甜 说一段话:

 

第二个网页,也就是小甜甜的,会自动播放声音

 

 

完整代码,请参考github:

 

未完待续。。。

 

转载于:https://www.cnblogs.com/xiao987334176/p/9674805.html

你可能感兴趣的文章
js 把字符串格式化成时间
查看>>
关于老师
查看>>
[Swift]LeetCode212. 单词搜索 II | Word Search II
查看>>
jquery知识点总结二
查看>>
利用map ,找出list里面string类型,长度最小的那个
查看>>
今天真手贱.
查看>>
【转载】如何使用docker部署c/c++程序
查看>>
Android Binder机制(二) ------- 服务的实现
查看>>
[Algorithm] Find first missing positive integer
查看>>
[Angular] @ViewChild and template #refs to get Element Ref
查看>>
[Angular] Show a loading indicator in Angular using *ngIf/else, the as keyword and the async pipe
查看>>
[Angular] Configurable Angular Components - Content Projection and Input Templates
查看>>
[PWA] 17. Cache the photo
查看>>
[RxJS] ReplaySubject with buffer
查看>>
[Firebase] 3. Firebase Simple Login Form
查看>>
AI 线性代数
查看>>
ltp-ddt realtime_cpu_load涉及的cyclictest 交叉编译
查看>>
MySQL中Checkpoint技术
查看>>
【MT】牛津的MT教程
查看>>
Meta标签中的format-detection属性及含义
查看>>