项目 智能玩具
一、需求分析
1外形美观大方
2功能:1语音的实时通讯
2积极正面内容
-播放音频(播放 父母选定的儿歌,故事,百科,英语)
-语音识别 (通过语音识别内容名称 玩具可以主动点播内容)
3陪孩子聊天
4解答问题(十万个为什么)
5家长通过玩具查看社交圈
二、具体实施
第一天:
获取音频资源
1从喜马拉雅采集幼教内容,存入文件
分别获取封面/音乐 文件
将数据写入数据库
app 获取内容 /content_list
-信息以列表的形式返回
接口功能实现
根据前端的需求返回相应的数据
App /get_cover 获取内容的图片信息
App /get_music 获取音频信息
2用户的注册 、登录 、自动登录
App /reg 注册用户
App /login 用户登录 返回的用户信息
App /auto_login 用户打开APP后自动登录 返回的用户信息
3创建设备的DeviceKey(联图网创建二维码)
保证唯一性
-hashlib.md5((f"{uuid4()}{time.time()}{uuid4()}".encode("utf8")).hexdigest()
第二天:
App 绑定一个设备 扫描二维码,设备必须有一个符合我们数据库中的二维码
设备 一旦和App进行绑定 由App创建玩具
1扫码
通过 {device_key:""} 去数据库中查找 是否有该二维码信息
1.二维码扫描成功并且设备未进行绑定
2.二维码扫描失败,扫描的条码不是设备库中存在的
3.二维码扫描成功, 但设备已经进行绑定
(还未实现)
2绑定玩具
按照数据库要求 构建玩具的基本信息
先创建一个空的Chats 表
-chat_id = MDB.Chats.insert_one({"user_list": [], "chat_list": []})
1创建toy (结合数据库结构和API文档,获取信息)
toy 绑定 user
先给toy 添加第一个好友 app
注意 friend_chat 的写法
- "friend_chat": str(chat_id.inserted_id)
追加
-toy_info["friend_list"].append(toy_add_user)
toy_id = MDB.Toys.insert_one(toy_info)
2.User表数据补充
app 也要同时 增加toy为好友
user_add_toy = {
"friend_id": toy_id.inserted_id, # toy_id str
"friend_nick": toy_info.get("baby_name"), # baby_name
"friend_remark": toy_info.get("toy_name"), # toy_name
"friend_avatar": "toy.jpg", #
"friend_chat": str(chat_id.inserted_id), # chat_id
"friend_type": "toy" # 好友的类型 toy
}
添加到表结构中
user_info["bind_toys"].append(str(toy_id.inserted_id))
user_info["friend_list"].append(user_add_toy)
整体修改数据
# 修改 Users 的全部数据
MDB.Users.update_one({"_id": ObjectId(user_id)}, {"$set": user_info})
# Chats 数据也会变化 user_list 将 toy_id 和 user_id 加入
MDB.Chats.update_one({"_id":chat_id.inserted_id}, {"$set": {"user_list": [user_id,str(toy_id.inserted_id)]}})
数据结构
3 toy_list 展示
从toys 表中查找对应数据,返回(参考表中的数据)
第三天:
1 智能玩具WebSocket通讯
Websocket 连接 OpenToy 开机
按照格式 开启wevbsocket
解决跨域问题
App通讯 向toy 发送音乐
ws://10.0.0.1:9528/app/<user_id>
Toys通讯 接收App推送音乐
ws://10.0.0.1:9528/toy/<toy_id>
1 /get_qr 接口 获取QRCODE 图片
-获取图片/音乐/二维码图片等原理是相通的
2 /friend_list 查询好友列表
3 /chat_list 查询聊天记录
4 /app_uploader app 上传语音消息
5 /toy_uploader toy 上传语音消息
注意事项:
前端发送请求所携带的数据 和后端响应的数据
app/toy 上传语音消息 注意 文件格式的转化
跨域问题的解决(安装包)
获取数据--保存文件--转化格式--聊天记录--更新聊天记录--返回RET
/get_qr 接口
# 返回二维码信息图片 @content_bp.route("/get_qr/<filename>",methods=["GET"]) def get_qr(filename): qr_path=os.path.join(QRCODE_PATH,filename) return send_file(qr_path)
/friend_list 接口 /chat_list 接口
from bson import ObjectId from flask import Blueprint, request, jsonify from settings import MDB, RET friend_bp = Blueprint("friend_bp", __name__) @friend_bp.route("/friend_list", methods=["POST"]) def friend_list(): user_id = request.form.get("_id") user_info = MDB.Users.find_one({"_id": ObjectId(user_id)}) RET["CODE"] = 0 RET["MSG"] = "好友查询" RET["DATA"] = user_info.get("friend_list") print(user_info, "+++++++++") return jsonify(RET) @friend_bp.route("/chat_list", methods=["POST"]) def chat_list(): chat = request.form.to_dict() chat_window = MDB.Chats.find_one({"_id": ObjectId(chat.get("chat_id"))}) RET["CODE"] = 0 RET["MSG"] = "查询聊天记录" RET["DATA"] = chat_window.get("chat_list") return jsonify(RET)
实现 /app_uploader 接口 App上传语音消息
实现 /toy_uploader 接口 Toy上传语音消息
import os import time from bson import ObjectId from flask import Blueprint, request, jsonify from settings import MDB, RET, CHAT_PATH uploader_bp = Blueprint("uploader_bp", __name__) @uploader_bp.route("/app_uploader", methods=["POST"]) def app_uploader(): to_user = request.form.get("to_user") from_user = request.form.get("user_id") reco_file = request.files.get("reco_file") reco_file_path = os.path.join(CHAT_PATH, reco_file.filename) # 保存的文件格式为amr reco_file.save(reco_file_path) # 转化格式 os.system(f"ffmpeg -i {reco_file_path} {reco_file_path}.mp3") user_list = [to_user, from_user] # 聊天信息记录 chat_info = { "from_user": from_user, "to_user": to_user, "chat": f"{reco_file.filename}.mp3", "createTime": time.time() } # 更新聊天数据 MDB.Chats.update_one({"user_list": {"$all": user_list}}, {"$push": {"chat_list": chat_info}}) RET["CODE"] = 0 RET["MSG"] = "上传成功" RET["DATA"] = { "filename": f"{reco_file.filename}.mp3", "friend_type": "app" } return jsonify(RET) from uuid import uuid4 @uploader_bp.route("/toy_uploader", methods=["POST"]) def toy_uploader(): to_user = request.form.get("to_user") from_user = request.form.get("user_id") reco_file = request.files.get("reco") # 与app_uploader 不同 文件名 blob reco_file.filename 是文件类型 # print(reco_file.filename, "++++++") filename = f"{uuid4()}.wav" reco_file_path = os.path.join(CHAT_PATH, filename) reco_file.save(reco_file_path) user_list = [to_user, from_user] # 聊天信息记录 chat_info = { "from_user": from_user, "to_user": to_user, "chat": filename, "createTime": time.time() } # 更新聊天数据 MDB.Chats.update_one({"user_list": {"$all": user_list}}, {"$push": {"chat_list": chat_info}}) RET["CODE"] = 0 RET["MSG"] = "上传成功" RET["DATA"] = { "filename": filename, "friend_type": "toy" } return jsonify(RET)
wap_ws websocket 连接
import json from flask import Flask, request, render_template from geventwebsocket.handler import WebSocketHandler from geventwebsocket.server import WSGIServer from geventwebsocket.websocket import WebSocket ws_app = Flask(__name__) user_socket_dict = {} # 建立websocket连接 @ws_app.route("/app/<user_id>") def app(user_id): # print(user_id,"user_id") # 获得wesocket 连接 app_socket = request.environ.get("wsgi.websocket") # type: WebSocket if app_socket: user_socket_dict[user_id] = app_socket while True: app_data = app_socket.receive() app_data_dict = json.loads(app_data) to_user = app_data_dict.get("to_user") usocket = user_socket_dict.get(to_user) try: usocket.send(app_data) except: continue @ws_app.route("/toy/<toy_id>") def toy(toy_id): # 获得wesocket 连接 toy_socket = request.environ.get("wsgi.websocket") # type: WebSocket if toy_socket: user_socket_dict[toy_id] = toy_socket while True: toy_data = toy_socket.receive() toy_data_dict = json.loads(toy_data) to_user = toy_data_dict.get("to_user") usocket = user_socket_dict.get(to_user) # usocket.send(toy_data) try: usocket.send(toy_data) except: continue @ws_app.route("/get_toy") def get_toy(): return render_template("WebToy.html") if __name__ == '__main__': http_serve = WSGIServer(("0.0.0.0", 9528), ws_app, handler_class=WebSocketHandler) http_serve.serve_forever()