先下载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 = ""
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

未完待续...

python 全栈开发,Day130(多玩具端的遥控功能, 简单的双向聊天,聊天记录存放数据库,消息提醒,玩具主动发起消息,玩具主动发起点播)的更多相关文章

  1. python 全栈开发,Day127(app端内容播放,web端的玩具,app通过websocket远程遥控玩具播放内容,玩具管理页面)

    昨日内容回顾 1. 小爬爬 内容采集 XMLY 的 儿童频道 requests 2. 登陆 注册 自动登陆 退出 mui.post("请求地址",{数据},function(){} ...

  2. Win10构建Python全栈开发环境With WSL

    目录 Win10构建Python全栈开发环境With WSL 启动WSL 总结 对<Dev on Windows with WSL>的补充 Win10构建Python全栈开发环境With ...

  3. Python全栈开发【面向对象进阶】

    Python全栈开发[面向对象进阶] 本节内容: isinstance(obj,cls)和issubclass(sub,super) 反射 __setattr__,__delattr__,__geta ...

  4. Python全栈开发【面向对象】

    Python全栈开发[面向对象] 本节内容: 三大编程范式 面向对象设计与面向对象编程 类和对象 静态属性.类方法.静态方法 类组合 继承 多态 封装 三大编程范式 三大编程范式: 1.面向过程编程 ...

  5. Python全栈开发【模块】

    Python全栈开发[模块] 本节内容: 模块介绍 time random os sys json & picle shelve XML hashlib ConfigParser loggin ...

  6. Python全栈开发【基础四】

    Python全栈开发[基础四] 本节内容: 匿名函数(lambda) 函数式编程(map,filter,reduce) 文件处理 迭代器 三元表达式 列表解析与生成器表达式 生成器 匿名函数 lamb ...

  7. Python全栈开发【基础三】

    Python全栈开发[基础三]  本节内容: 函数(全局与局部变量) 递归 内置函数 函数 一.定义和使用 函数最重要的是减少代码的重用性和增强代码可读性 def 函数名(参数): ... 函数体 . ...

  8. Python全栈开发【基础二】

    Python全栈开发[基础二] 本节内容: Python 运算符(算术运算.比较运算.赋值运算.逻辑运算.成员运算) 基本数据类型(数字.布尔值.字符串.列表.元组.字典) 其他(编码,range,f ...

  9. Python全栈开发【基础一】

    Python全栈开发[第一篇] 本节内容: Python 的种类 Python 的环境 Python 入门(解释器.编码.变量.input输入.if流程控制与缩进.while循环) if流程控制与wh ...

随机推荐

  1. gitlab与pycharm结合

    一切都在图中 点开pycharm里的菜单选项 设置git代码仓库的地址 修改了代码之后,如何推送到git服务器上 通过pycharm下载代码仓库 pycharm中如何设置分支 pycharm新建了分支 ...

  2. C#中子线程操作主线程中窗体上控件的方法

    Demo this.listView1.Visible = true; this.listView1.BeginUpdate();this.listView1.EndUpdate(); //结束数据处 ...

  3. CentOS6.8下MySQL数据库版本信息查看

    方法1:使用mysql -v命令查看: [root@yeebian mysql]# mysql -V mysql Ver 14.14 Distrib 5.1.73, for redhat-linux- ...

  4. docker部署安装

    docker采用Linux内核技术,所以只能运行在Linux上,所谓的windows平台是使用boot2Docker工具,boot2Docker是在VisualBox构建一个linux精简化环境. B ...

  5. 枚举专项练习_Uva725(Division)_Uva11059(Maximun Product)

    //Uva725 #include <iostream> #include <cstring> #include <cstdlib> #include <cs ...

  6. dense prediction

    Dense prediction  fully convolutional network for sementic segmentation 先用feature extractor 提特征,然后再使 ...

  7. Linux cache 缓存过大

    linux cache 缓存过大 : 除重启服务 之外:直接释放内存方式之一: 修改配置释放cached内存: echo > /proc/sys/vm/drop_caches

  8. Postfix 邮件服务 - postfix服务

    postfix 邮件服务 也是基于sendmail (需要关闭或卸载sendmail)postfix 是一个电子邮件服务器,它为了改良sendmail邮件服务器而产生的,并且它的配置文件比sendma ...

  9. luogu P1437 [HNOI2004]尻♂砖块

    传送门 想明白了其实不难 强行瞎扯 这题的限制比较烦,导致了一行行转移几乎不能做(吧) 那么一列列转移呢? 设\(f_{i,j,k}\)表示前\(i\)列,取\(j\)个,其中第\(i\)列取从上往下 ...

  10. Java 学习札记(二)TomCat安装配置

    1.下载TomCat 下载地址:http://tomcat.apache.org/ 2.配置环境变量 CATALINA_HOME:F:\JAVA\apache-tomcat-6.0.18\apache ...