多玩具端的遥控功能, 简单的双向聊天,聊天记录存放数据库,消息提醒,玩具主动发起消息,玩具主动发起点播
先下载github代码,下面的操作,都是基于这个版本来的!
https://github.com/987334176/Intelligent_toy/archive/v1.3.zip
注意:由于涉及到版权问题,此附件没有图片和音乐。请参考链接,手动采集一下!
请参考链接:
https://www.cnblogs.com/xiao987334176/p/9647993.html#autoid-3-4-0
一、多玩具端的遥控功能
地址统一管理
进入flask项目,修改 templates-->index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <audio src="" autoplay="autoplay" controls id="player"></audio> <br> <input type="text" id="device_id"> <button onclick="start_toy()">玩具开机键</button> <br> <button onclick="start_reco()">开始废话</button> <br> <button onclick="stop_reco()">发送语音</button> </body> <script src="/static/recorder.js"></script> <script src="/static/jquery.min.js"></script> <script type="application/javascript"> var serv = "http://192.168.11.40:9527"; var ws_serv = "ws://192.168.11.40:9528"; // 获取音频文件 var get_music = serv + "/get_audio/"; var ws = null; // WebSocket 对象 var reco = null; // 创建AudioContext对象 var audio_context = new AudioContext(); //要获取音频和视频 navigator.getUserMedia = (navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia); // 拿到媒体对象,允许音频对象 navigator.getUserMedia({audio: true}, create_stream, function (err) { console.log(err) }); //创建媒体流容器 function create_stream(user_media) { var stream_input = audio_context.createMediaStreamSource(user_media); // 给Recoder 创建一个空间,麦克风说的话,都可以录入。是一个流 reco = new Recorder(stream_input); } function start_reco() { //开始录音 reco.record(); //往里面写流 } function stop_reco() { //停止录音 reco.stop(); //停止写入流 get_audio(); //调用自定义方法 reco.clear(); //清空容器 } function get_audio() { // 获取音频 reco.exportWAV(function (wav_file) { ws.send(wav_file); //使用websocket连接发送数据给后端 }) } function start_toy() { // 玩具开机 // 获取输入的设备id var device_id = document.getElementById("device_id").value; // 发送post请求 $.post( // 这里的地址必须是127.0.0.1,否则会有跨域问题 "http://127.0.0.1:9527/device_toy_id", // 发送设备id {device_id: device_id}, function (data) { console.log(data); toy_id = data.data.toy_id; // 玩具id // 修改audio标签的src属性 document.getElementById("player").src = get_music + data.data.audio; if (toy_id) { // 判断玩具id存在时 ws = new WebSocket(ws_serv + "/toy/" + toy_id); ws.onmessage = function (data) { // console.log(get_music + data.data); var content = JSON.parse(data.data); //反序列化数据 document.getElementById("player").src = get_music + content.data; console.log(content.from_user + "给你点了一首歌"); } } }, "json" // 规定预期的服务器响应的数据类型为json ); } </script> </html>
进入 HBuilder项目MyApp,查看mui.js。
... window.ws_serv = "192.168.11.40:9528"; window.serv = "http://192.168.11.40:9527"; window.serv_imge = window.serv+"/get_image/"; window.serv_audio = window.serv+"/get_audio/"; ...
这里面,已经是统一化管理了
昨天内容,已经实现了简单的对话。但是点歌功能被删掉了,今天需要开启一下。
进入flask项目,修改im_serv.py,增加msg_type。用来做消息类型判断!
from flask import Flask, request from geventwebsocket.websocket import WebSocket from geventwebsocket.handler import WebSocketHandler from gevent.pywsgi import WSGIServer import json, os from uuid import uuid4 from setting import AUDIO_FILE,CHAT_FILE from serv import content app = Flask(__name__) user_socket_dict = {} # 空字典,用来存放用户名和发送消息 @app.route("/toy/<tid>") def toy(tid): # 玩具连接 # 获取请求的WebSocket对象 user_socket = request.environ.get("wsgi.websocket") # type:WebSocket if user_socket: # 设置键值对 user_socket_dict[tid] = user_socket print(user_socket_dict) # {'123456': <geventwebsocket.websocket.WebSocket object at 0x00000176ABD92E18>} # 循环,接收消息 while True: # 接收消息 msg = user_socket.receive() print(msg) # 打印 if type(msg) == bytearray: # print(11) with open('123.wav','wb') as f: f.write(msg) # 写入文件 @app.route("/app/<uid>") def user_app(uid): # 手机app连接 user_socket = request.environ.get("wsgi.websocket") # type:WebSocket if user_socket: user_socket_dict[uid] = user_socket # { uid : websocket} print(user_socket_dict) file_name = "" to_user = "" while True: # 手机听歌 把歌曲发送给 玩具 1.将文件直接发送给玩具 2.将当前听的歌曲名称或ID发送到玩具 msg = user_socket.receive() if type(msg) == bytearray: # 判断类型为bytearray file_name = f"{uuid4()}.amr" # 文件后缀为amr,安卓和ios通用 file_path = os.path.join(CHAT_FILE, file_name) # 存放在chat目录 print(msg) with open(file_path, "wb") as f: f.write(msg) # 写入文件 # 将amr转换为mp3,因为html中的audio不支持amr os.system(f"ffmpeg -i {file_path} {file_path}.mp3") else: msg_dict = json.loads(msg) to_user = msg_dict.get("to_user") # 获取目标用户 if msg_dict.get("msg_type") == "music": other_user_socket = user_socket_dict.get(to_user) send_str = { "code": 0, "from_user": uid, "msg_type": "music", "data": msg_dict.get("data") } other_user_socket.send(json.dumps(send_str)) # res = content._content_one(content_id) if file_name and to_user: # 如果文件名和发送用户同上存在时 # 获取websocket对象 other_user_socket = user_socket_dict.get(to_user) # 构造数据 send_str = { "code": 0, "from_user": uid, "msg_type": "chat", # 聊天类型 # 后缀必须是mp3的 "data": f"{file_name}.mp3" } # 发送数据给前端页面 other_user_socket.send(json.dumps(send_str)) # 最后一定要清空这2个变量,否则造成混乱 file_name = "" to_user = "" if __name__ == '__main__': # 创建一个WebSocket服务器 http_serv = WSGIServer(("0.0.0.0", 9528), app, handler_class=WebSocketHandler) # 开始监听HTTP请求 http_serv.serve_forever() ''' { "code": 0, "from_user": uid, # APP用户id "data": music_name # 歌曲名 } '''
这里最重要的是msg_ytpe
修改 templates-->index.html,做msg_type判断
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <audio src="" autoplay="autoplay" controls id="player"></audio> <br> <input type="text" id="device_id"> <button onclick="start_toy()">玩具开机键</button> <br> <button onclick="start_reco()">开始废话</button> <br> <button onclick="stop_reco()">发送语音</button> </body> <script src="/static/recorder.js"></script> <script src="/static/jquery.min.js"></script> <script type="application/javascript"> var serv = "http://192.168.11.40:9527"; var ws_serv = "ws://192.168.11.40:9528"; // 获取音频文件 var get_music = serv + "/get_audio/"; var ws = null; // WebSocket 对象 var reco = null; // 创建AudioContext对象 var audio_context = new AudioContext(); //要获取音频和视频 navigator.getUserMedia = (navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia); // 拿到媒体对象,允许音频对象 navigator.getUserMedia({audio: true}, create_stream, function (err) { console.log(err) }); //创建媒体流容器 function create_stream(user_media) { var stream_input = audio_context.createMediaStreamSource(user_media); // 给Recoder 创建一个空间,麦克风说的话,都可以录入。是一个流 reco = new Recorder(stream_input); } function start_reco() { //开始录音 reco.record(); //往里面写流 } function stop_reco() { //停止录音 reco.stop(); //停止写入流 get_audio(); //调用自定义方法 reco.clear(); //清空容器 } function get_audio() { // 获取音频 reco.exportWAV(function (wav_file) { ws.send(wav_file); //使用websocket连接发送数据给后端 }) } function start_toy() { // 玩具开机 // 获取输入的设备id var device_id = document.getElementById("device_id").value; // 发送post请求 $.post( // 这里的地址必须是127.0.0.1,否则会有跨域问题 "http://127.0.0.1:9527/device_toy_id", // 发送设备id {device_id: device_id}, function (data) { console.log(data); toy_id = data.data.toy_id; // 玩具id // 修改audio标签的src属性 document.getElementById("player").src = get_music + data.data.audio; if (toy_id) { // 判断玩具id存在时 ws = new WebSocket(ws_serv + "/toy/" + toy_id); ws.onmessage = function (data) { // console.log(get_music + data.data); var content = JSON.parse(data.data); //反序列化数据 // 判断消息类型 if (content.msg_type == "chat") { document.getElementById("player").src = get_chat + content.data; document.getElementById("to_user").innerText = content.from_user; console.log(content.from_user + "给你发送了一条消息"); } if (content.msg_type == "music") { document.getElementById("player").src = get_music + content.data; console.log(content.from_user + "给你点播了歌儿"); } } } }, "json" // 规定预期的服务器响应的数据类型为json ); } </script> </html>
进入 HBuilder项目,修改index.html,修改send_music监听事件。统一格式,发送to_user
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" /> <title></title> <script src="js/mui.js"></script> <link href="css/mui.min.css" rel="stylesheet" /> </head> <body> <!--底部选项卡--> <nav class="mui-bar mui-bar-tab"> <a class="mui-tab-item mui-active" id="index"> <span class="mui-icon mui-icon-home"></span> <span class="mui-tab-label">首页</span> </a> <a class="mui-tab-item" id="message"> <span class="mui-icon mui-icon-chatbubble"></span> <span class="mui-tab-label">消息</span> </a> <a class="mui-tab-item"> <span class="mui-icon mui-icon-email"></span> <span class="mui-tab-label">邮件</span> </a> <a class="mui-tab-item" id="login"> <span class="mui-icon mui-icon-gear"></span> <span class="mui-tab-label">设置</span> </a> </nav> </body> <script type="text/javascript" charset="utf-8"> var ws = null; // websocket对象 mui.init({ subpages: [{ url: "main.html", id: "main.html", styles: window.styles }] }); mui.plusReady(function() { // console.log(JSON.stringify(plus.webview.currentWebview())) if(plus.storage.getItem("user")) { // 判断是否登录 console.log('已结登录了!'); //连接websocket连接 ws = new WebSocket("ws://" + window.ws_serv + "/app/" + plus.storage.getItem("user")) // 客户端接收服务端数据时触发 ws.onmessage = function() {}; } }); // 消息 document.getElementById("message").addEventListener("tap", function() { mui.openWindow({ url: "message.html", id: "message.html", styles: window.styles, extras: { // 传输用户id,给message.html user_id: plus.storage.getItem("user") } }) }); document.getElementById("index").addEventListener("tap", function() { mui.openWindow({ url: "main.html", id: "main.html", styles: window.styles }) }) document.getElementById("login").addEventListener("tap", function() { // 自动登录,判断storage中的user存在,就跳转到user_info,否则跳转login if(plus.storage.getItem("user")) { mui.openWindow({ url: "user_info.html", id: "user_info.html", styles: window.styles, extras: { user_id: plus.storage.getItem("user") } }) } else { mui.openWindow({ url: "login.html", id: "login.html", styles: window.styles }) } }) document.addEventListener("login", function(data) { // fire事件接收消息,使用data.detail // index是为做显示区分 mui.toast("index" + data.detail.msg) }); document.addEventListener("send_music", function(data) { //监听send_music事件 var music_name = data.detail.music_name; //获取player.html使用fire发送的music_name值 var toy_id = data.detail.toy_id; //获取发送的玩具id send_str = { //构造数据 data: music_name, to_user: toy_id, // 目标用户,这里统一格式 msg_type:"music", // 类型为音乐 } // 发送数据给后端,注意要json序列化 ws.send(JSON.stringify(send_str)); }); document.addEventListener("send_msg", function(data) { //发送消息 var filename = data.detail.filename var to_user = data.detail.to_user send_str = { to_user: to_user } ws.send(JSON.stringify(send_str)) plus.io.resolveLocalFileSystemURL(filename, function(entry) { // 可通过entry对象操作test.html文件 entry.file(function(file) { // FileReader文件系统中的读取文件对象,用于获取文件的内容 var fileReader = new plus.io.FileReader(); // alert("getFile:" + JSON.stringify(file)); // readAsDataURL: 以URL编码格式读取文件数据内容 fileReader.readAsDataURL(file, 'utf-8'); // onloadend: 文件读取操作完成时的回调函数 fileReader.onloadend = function(evt) { console.log(evt.target.result); var b = dataURLtoBlob(evt.target.result); ws.send(b); // 发送blob数据 } // alert(file.size + '--' + file.name) }); }); }) function dataURLtoBlob(dataurl) { // 数据转换为Blob // 逻辑很复杂,这里不解释了。直接用就可以了! var arr = dataurl.split(','), mime = arr[0].match(/:(.*?);/)[1], bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n); while(n--) { u8arr[n] = bstr.charCodeAt(n); } var a = new Blob([u8arr], { type: mime }); return a } </script> </html>
进入flask项目,根目录下新建文件夹 chat
此时项目结构如下:
./
├── audio
├── audio_img
├── chat
├── device_code
├── im_serv.py
├── manager.py
├── QRcode.py
├── serv
│ ├── content.py
│ ├── devices.py
│ ├── friend.py
│ ├── get_file.py
│ └── toys.py
├── setting.py
├── static
│ ├── jquery.min.js
│ └── recorder.js
├── templates
│ └── index.html
├── utils
│ └── baidu_ai.py
└── xiaopapa.py
进入目录 audio,将里面所有 amr和amr.mp3文件全部删掉!
这些文件,会自动放到chat目录
修改 settings.py,增加 CHAT_FILE变量
import pymongo client = 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 os AUDIO_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") # 二维码 CHAT_FILE = os.path.join(os.path.dirname(__file__), "chat") # 聊天 # 百度AI配置 APP_ID = "11712345" API_KEY = "3v3igzCkVFUDwFByNE12345" SECRET_KEY = "jRnwLE7kzC1aRi2FD10OQY3y9O12345" SPEECH = { "spd": 4, 'vol': 5, "pit": 8, "per": 4 }
修改 get_file.py,增加get_chat视图函数
from flask import Blueprint, send_file from setting import AUDIO_FILE from setting import AUDIO_IMG_FILE from setting import CHAT_FILE import os getfile = Blueprint("getfile", __name__) @getfile.route("/get_audio/<filename>") def get_audio(filename): # 获取音频 sendfile = os.path.join(AUDIO_FILE, filename) return send_file(sendfile) @getfile.route("/get_image/<filename>") def get_image(filename): # 获取图片 sendfile = os.path.join(AUDIO_IMG_FILE, filename) return send_file(sendfile) @getfile.route("/get_chat/<filename>") def get_chat(filename): # 获取聊天文件 sendfile = os.path.join(CHAT_FILE, filename) return send_file(sendfile)
访问网页,让2个玩具页面开机!
使用模拟器访问页面,点击一首歌曲,点击发送给 小甜甜
此时浏览器第二个页面,就是小甜甜。会自动播放音乐!
注意:必须要web玩具和手机APP,都连接上websocket才行。否则会导致点歌不成功!
自动重连websocket
为了避免后续操作,因为websocket连接而导致的问题。修改相关代码,可以自动重连!
进入 HBuilder项目MyApp,修改index.html,增加ws.onclose
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" /> <title></title> <script src="js/mui.js"></script> <link href="css/mui.min.css" rel="stylesheet" /> </head> <body> <!--底部选项卡--> <nav class="mui-bar mui-bar-tab"> <a class="mui-tab-item mui-active" id="index"> <span class="mui-icon mui-icon-home"></span> <span class="mui-tab-label">首页</span> </a> <a class="mui-tab-item" id="message"> <span class="mui-icon mui-icon-chatbubble"></span> <span class="mui-tab-label">消息</span> </a> <a class="mui-tab-item"> <span class="mui-icon mui-icon-email"></span> <span class="mui-tab-label">邮件</span> </a> <a class="mui-tab-item" id="login"> <span class="mui-icon mui-icon-gear"></span> <span class="mui-tab-label">设置</span> </a> </nav> </body> <script type="text/javascript" charset="utf-8"> var ws = null; // websocket对象 mui.init({ subpages: [{ url: "main.html", id: "main.html", styles: window.styles }] }); mui.plusReady(function() { // console.log(JSON.stringify(plus.webview.currentWebview())) if(plus.storage.getItem("user")) { // 判断是否登录 console.log('已结登录了!'); //连接websocket连接 ws = new WebSocket("ws://" + window.ws_serv + "/app/" + plus.storage.getItem("user")) // 客户端接收服务端数据时触发 ws.onmessage = function() {}; } // 自动重连 ws.onclose = function() { window.location.reload(); } }); // 消息 document.getElementById("message").addEventListener("tap", function() { mui.openWindow({ url: "message.html", id: "message.html", styles: window.styles, extras: { // 传输用户id,给message.html user_id: plus.storage.getItem("user") } }) }); document.getElementById("index").addEventListener("tap", function() { mui.openWindow({ url: "main.html", id: "main.html", styles: window.styles }) }) document.getElementById("login").addEventListener("tap", function() { // 自动登录,判断storage中的user存在,就跳转到user_info,否则跳转login if(plus.storage.getItem("user")) { mui.openWindow({ url: "user_info.html", id: "user_info.html", styles: window.styles, extras: { user_id: plus.storage.getItem("user") } }) } else { mui.openWindow({ url: "login.html", id: "login.html", styles: window.styles }) } }) document.addEventListener("login", function(data) { // fire事件接收消息,使用data.detail // index是为做显示区分 mui.toast("index" + data.detail.msg) }); document.addEventListener("send_music", function(data) { //监听send_music事件 var music_name = data.detail.music_name; //获取player.html使用fire发送的music_name值 var toy_id = data.detail.toy_id; //获取发送的玩具id send_str = { //构造数据 data: music_name, to_user: toy_id, // 目标用户,这里统一格式 msg_type: "music", // 类型为音乐 } // 发送数据给后端,注意要json序列化 ws.send(JSON.stringify(send_str)); }); document.addEventListener("send_msg", function(data) { //发送消息 var filename = data.detail.filename var to_user = data.detail.to_user send_str = { to_user: to_user } ws.send(JSON.stringify(send_str)) plus.io.resolveLocalFileSystemURL(filename, function(entry) { // 可通过entry对象操作test.html文件 entry.file(function(file) { // FileReader文件系统中的读取文件对象,用于获取文件的内容 var fileReader = new plus.io.FileReader(); // alert("getFile:" + JSON.stringify(file)); // readAsDataURL: 以URL编码格式读取文件数据内容 fileReader.readAsDataURL(file, 'utf-8'); // onloadend: 文件读取操作完成时的回调函数 fileReader.onloadend = function(evt) { console.log(evt.target.result); var b = dataURLtoBlob(evt.target.result); ws.send(b); // 发送blob数据 } // alert(file.size + '--' + file.name) }); }); }) function dataURLtoBlob(dataurl) { // 数据转换为Blob // 逻辑很复杂,这里不解释了。直接用就可以了! var arr = dataurl.split(','), mime = arr[0].match(/:(.*?);/)[1], bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n); while(n--) { u8arr[n] = bstr.charCodeAt(n); } var a = new Blob([u8arr], { type: mime }); return a } </script> </html>
进入 flask项目,修改 templates-->index.html,增加ws.onclose
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <audio src="" autoplay="autoplay" controls id="player"></audio> <br> <input type="text" id="device_id"> <button onclick="start_toy()">玩具开机键</button> <br> <button onclick="start_reco()">开始废话</button> <br> <button onclick="stop_reco()">发送语音</button> </body> <script src="/static/recorder.js"></script> <script src="/static/jquery.min.js"></script> <script type="application/javascript"> var serv = "http://192.168.11.40:9527"; var ws_serv = "ws://192.168.11.40:9528"; // 获取音频文件 var get_music = serv + "/get_audio/"; var ws = null; // WebSocket 对象 var reco = null; // 创建AudioContext对象 var audio_context = new AudioContext(); //要获取音频和视频 navigator.getUserMedia = (navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia); // 拿到媒体对象,允许音频对象 navigator.getUserMedia({audio: true}, create_stream, function (err) { console.log(err) }); //创建媒体流容器 function create_stream(user_media) { var stream_input = audio_context.createMediaStreamSource(user_media); // 给Recoder 创建一个空间,麦克风说的话,都可以录入。是一个流 reco = new Recorder(stream_input); } function start_reco() { //开始录音 reco.record(); //往里面写流 } function stop_reco() { //停止录音 reco.stop(); //停止写入流 get_audio(); //调用自定义方法 reco.clear(); //清空容器 } function get_audio() { // 获取音频 reco.exportWAV(function (wav_file) { ws.send(wav_file); //使用websocket连接发送数据给后端 }) } function start_toy() { // 玩具开机 // 获取输入的设备id var device_id = document.getElementById("device_id").value; // 发送post请求 $.post( // 这里的地址必须是127.0.0.1,否则会有跨域问题 "http://127.0.0.1:9527/device_toy_id", // 发送设备id {device_id: device_id}, function (data) { console.log(data); toy_id = data.data.toy_id; // 玩具id // 修改audio标签的src属性 document.getElementById("player").src = get_music + data.data.audio; if (toy_id) { // 判断玩具id存在时 ws = new WebSocket(ws_serv + "/toy/" + toy_id); ws.onmessage = function (data) { // console.log(get_music + data.data); var content = JSON.parse(data.data); //反序列化数据 // 判断消息类型 if (content.msg_type == "chat") { document.getElementById("player").src = get_chat + content.data; document.getElementById("to_user").innerText = content.from_user; console.log(content.from_user + "给你发送了一条消息"); } if (content.msg_type == "music") { document.getElementById("player").src = get_music + content.data; console.log(content.from_user + "给你点播了歌儿"); } }; ws.onclose = function () { window.location.reload(); } } }, "json" // 规定预期的服务器响应的数据类型为json ); } </script> </html>
重启 im_serv.py,就可以了!
二、简单的双向聊天
由于时间关系,详细步骤略...
三、聊天记录存放数据库
由于时间关系,详细步骤略...
四、消息提醒
由于时间关系,详细步骤略...
五、玩具主动发起消息
由于时间关系,详细步骤略...
六、玩具主动发起点播
由于时间关系,详细步骤略...
可以点击歌曲,比如我要听 新年恰恰
今日总结:
0.地址统一化管理: serv = "domain_name" 1.多玩具端的遥控功能(必做) 发送消息的时候,把遥控功能 开启 send_str = { "code": 0, "from_user": uid, <加粗>"msg_type": "chat",</加粗> "data": f"{file_name}.mp3" } "msg_type": "chat" 判断是发消息 还是遥控点播 服务端: 1.收到一次 send 所以就要在收到字符串send 的时候判断"msg_type"=="music" 2.other_user_socket = user_socket_dict.get(to_user) send_str = { "code": 0, "from_user": uid, <加粗>"msg_type": "music",</加粗> "data": msg_dict.get("data") } other_user_socket.send(json.dumps(send_str)) 玩具端: 玩具段收到消息之后判断 msg_type 是getchat 还是getmusic if (content.msg_type == "chat") { document.getElementById("player").src = get_chat + content.data; console.log(content.from_user + "给你发送了一条消息"); } 2.简单的单向聊天 升级 双向聊天 form_user : 寄件人 to_user : 收件人 收件人和寄件人 颠倒 就是回复消息 app 在 index中给 chat 页面发送 fire事件用于创建消息条目 3.聊天的记录 存放数据库 chat add {sender :发件人 ,msg:语音文件名 ,updated_at : 时间} app 聊天页面: 每一次打开聊天窗口的时候发起post请求: 获取chat表中的聊天记录,依次生成聊天信息,打印在窗口中 4.消息提醒 1.查询to_user用户的好友列表,当前自己在好友列表中的备注 2.将备注合成语音 3.将语音发送至玩具端 4.玩具端收到消息后,按收取消息键,收取最后一条消息 坑:未读,只能收取最后一条 离线消息 5.玩具主动发起消息 1.将语音发送至服务端 2.将语音转换成文本 3.把文本进行 字符串儿 匹配 “发消息” in q -》 friend_name in q -> friend 4.模拟friend给自己发了一条假消息 { from_user : friend_id } 5.玩具端收到 from_user 之后,可以开启对friend的消息发送了 6.玩具主动发起点播: 同 玩具主动发起消息
由于时间关系,无法演示效果...
完整代码,参考github:
https://github.com/987334176/Intelligent_toy/archive/v1.4.zip
未完待续...