第一天
智能玩具开发者日志
新学的快捷键: Ctrl+ ] 是往里面缩进([外缩) ctrl+shift+]是无序列表(前面点的表示[是数字表示)
1 获取幼教内容:
- 选取某优质音乐网站
- 使用requests模块,进入网页,关闭清除缓存的(disable cache) 点all的那个,然后点击某个音乐,在network里的Name里找到以album(专辑)开头的,点击preview查看,点击response获取数据
- 然后爬取需要的音乐和封面(存到本地不同的文件夹中)
- 通过 requests.get('https:w4a' )获得music,然后把.content写入音乐文件(用uuid4表示)以及封面图片,然后把音乐名等信息存入MongoDB中
2. content_list 接口 获取内容数据
-
从数据库获得所有信息 find
-
改了_id成str,否则不能jsonify,传给前端(jsonify)
-
前端接口调用数据,进行显示
以下内容都是接口函数,
3. get_cover 获取图片
4. get_music 获取音乐
- 因为音乐和图片在文件夹中,先os.path.join拼接一下
- 通过send_file发送到网上,前端去http上请求封面和歌曲
5. reg 注册用户
- 前端传过来的数据里有 用户注册的信息(用.form.to_dict()接收)
- 然后在这个字典中添加之后用户会使用的其他信息('bind_toys','friend_list',以及'avatar'头像(存储在前端))
- 加到数据库Users表里 insert_one
- 返回数据 通知一声说明注册成功 code:0
6. login 用户登录
7. auto_login 用户自动登录
-
从数据库Users表里查询登录信息find_one(to_dict()) 如果数据库和登录信息匹配 则返回前端 code:0 (jsonify) 同时返回查到的数据
第二天
1. scan_qr 用于DeviceKey的数据校验
-
先生成二维码,并存储到数据库里
二维码字符通过uuid4 时间戳 加密 拼接而成 长度短且唯一
利用联图LT生成二维码,写入文件,并且把生成的二维码列表[{'device_key':qr},.写入数据库Devices
-
当扫描二维码时,走scan_qr接口
判断二维码的device是否在 Devices可找到 find_one 如果是: 返回二维码,code:0 否,返回 code:1 {}
2. bind_toy 创建玩具并绑定玩具,双方建立关系
-
玩具添加app
前端返回的数据是, 玩具的信息,以及对app的称呼,device_key,以及user_id
根据设计好数据结构,补充其他key. 并且把多余的user_id pop出去, bind_user = user_id = toy_info.pop('user_id') # app
user_info = USer.find_one('_id:'ObjectId(user_id)) # 获取User_info信息 char_id = Chat.insert_one({'user_list':[], 'chat_list':[]}) # 新建Chat表
'friend_list' 的添加 : toy_add_user = { # 填写朋友的信息 id nick remark ava type ... friend_chat = str(chat_id.inserted_id); } 然后,把 toy_add_u添加到 'friend_list'中, 再把toy_info 添加到数据库Toys (insert_one)(toy_info = 请求的dict())
-
app添加玩具
user_add_toy = { id =str( toy.insert) frined_id = str(chat_id.insert) # 一个聊天室 } bind_toy 之前为空,也给他 str(toy.insert) 把user_add_toy加入friend_list 更新User,更新Chats update_one user_list : [user_id,str(toy)]
3. toy_list 获取玩具的列表
- 通过后端的id获得toy列表,然后传给前端显示
4. WebToy WebSocket连接 并保持连接
-
安装gevent-websocket 导入 geventwebsocket
appsocket
app_socket = request.environ.get('wsgi.websocket') # type:WebSocket # 建立一个app连接 如果有此链接,以toy为key,app_socket为value存入字典 if app_socket: # user_id 比如=7 to_user =4 user_socket_dict[user_id] = app_socket while True: app_socket.receive() #其实是玩具在receive # 然后app发送,用的toy_socket to_user = toy_data_dict.get('to_user') # usocket = user_socket_dict.get(to_user) # 只有当to_user (4)存在,即usock user_socket_dict.get(to_user).send 上面的信息() # app_data是app向toy发送的信息
app_data的信息 : send(app_data) 发送到哪了?按说是前端?
{'chat': 'aa6ded85-387b-432e-bace-e4fb1b58097f.mp3', 'to_user': '5d36bf7d00c8bf23acf1a3f4', 'from_user': '5d36b6ab06eeb0fa0765c0f7'}
-
toy也是这么连接
@ws_app.route("/toy/<toy_id>") def toy(toy_id): # Toy 连接的位置 print('toy_id', toy_id) print('1') toy_socket = request.environ.get("wsgi.websocket") # type:WebSocket if toy_socket: user_socket_dict[toy_id] = toy_socket # f4 = ts while True: toy_data = toy_socket.receive() # f4 ts(app) toy_data_dict = json.loads(toy_data) print(toy_data_dict,'toy_data_dict') # to_user': '5d36b6ab06eeb0fa0765c0f7' to_user = toy_data_dict.get("to_user") # f7 usocket = user_socket_dict.get(to_user) # app_socket 玩具 usocket.send(toy_data) # app_socket (toy_data) #向app发送信息
send发送到前端哪里了?
5. App WebSocket连接 并保持连接
while receiver() 一直夯在这里,但是只有一个
6. App 向玩具发送音乐
-
用的ws app_data
{'to_user': '5d36bf7d00c8bf23acf1a3f4', 'music': 'c6b68f04-9a4c-46b6-9560-0bb31c38c7b7.mp3'} app_data_dict to_user 5d36bf7d00c8bf23acf1a3f4
怎么接收到的? # (不是之后的逻辑app_uploader或者是toy_uploader)recv_msg
第三天
1. get_qr 获取QRCODE图片
- 和get_xxx逻辑一样 send_file
2. friend_list 查询好友列表
-
通过"_id"传过来的值,查找Users 然后找Users的friend_list 返回code:0 data:friend_list
3. chat_list 接口 查询聊天记录
- 把上面的Users换成Chat friend_list换成chat_list
4.app_uploader App上传语音消息
-
前端点击按住,然后松开,保存信息到了reco_file=request.files.get('reco_file')里
-
拼接文件夹,save一下. reco_file.save(reco_file_path) #保存成 amr
-
os.system(f'ffmpeg -i {reco_file_path} {reco_file_path}.mp3') # 转成MP3格式
-
根据id获得friend以及remark
wenjianming = text2audio(f'你有来自{friend_remark}的消息')
-
给chat_info = {'f_u':re.fo.get('user_id'),
't_u':re.fo.get('to_user'),
'chat':f'{reco_file.filename}.mp3',
'createTime':time.time()}
-
添加到数据库Chats里,之前新建的,所以现在update_one({},{'push':{'chat_list':chat_i}})
-
给玩具提示信息:
RET["DATA"] = { 'filename': wenjianming, 'file_type': 'app' }
5.toy_uploader Toy上传语音消息
基本与上面同
-
录制信息reco_file=request.files.get('reco_file')
filename = f"{uuid4()}.wav" reco_file_path = os.path.join(CHAT_PATH, filename) # 怎么写入wav里的 默认写入吗 reco_file.save(reco_file_path) # 保存文件到拼接成的wav
-
给chat_info = {
"from_user": from_user, "to_user": to_user, "chat": filename, "createTime": time.time()} 并加到Chats里 update_one如上面app_uploader
-
如果是toy发送过来的需要一个语音提醒
type= request.form.get('friend_type') if friend_type = 'toy': filename = get_xxtx(to_user,form_user,'xxtx') #语音提醒函数
并传过filename
6.你有来自XXX(好友的备注)的消息
-
friend_remark = '未知用户' def (to_user,from_user,tx_type=None):# type:不同场合,可给赋值,后面判断用 for循环friend_list列表, if friend.get("friend_id") == from_user: 得出friend_remark wenjianming = text2audio(f'你有来自{friend_remark}的消息') return wenjianming
第四天
1.recv_msg 接收未读消息 多条消息连续收取
-
写set_redis# 存储未读消息
这样的数据结构存储:离线未读消息 { "user_id":{ "from_id1":1, "from_id2":6, } }
程序逻辑
to_user_json = RDB.get(to_user)通过获得{} 然后,如果if from_id有则+1 , 如果没有=1 好友第一次发,else: to_user_json = json.dumps({from_user:1}) RDB.set(to_user,to_user_json)
为什么用redis数据库呢? 快,非关系型数据库,内存级别(存储的信息,一时用)
-
get_redis #获取单个用户的未读消息
to_user_json = RDB.get(to_user) if to_user_json: 清空 先loads,然后count=pop,然后在dumps else: to_user_json = dumps({from_user:0}) RDB.set(to_user, to_user_json) return count
-
写recv_msg函数
最后效果是传过去,你有来自谁的几条信息
count=get_redis #几条 来自谁: wenjianming = get_xxtx() if count ==0 : wenjianming = text2audio(f'你没有信息') return {'chat_list':caht_info_list(把格式对齐传过去)} ret = {from_user, friend_type, 'chat_list'= 上面那样的}
这里需要重写get_xxtx,来获得friend_type,然他返回俩个值
if friend.get("friend_id") == from_user: friend_remark = friend.get('friend_remark') friend_type = friend.get('friend_type') wenjianming = text2audio(f'以下是来自{friend_remark}的消息') return wenjianming, friend_type
count,friend_type = get_xxtx(,,None) #那边其实有判断的,提醒一下了
2. BaiduAI TTS 语音合成 实现消息提醒
"以下是来自xxx的消息"
-
程序如下:
def text2audio(A): res = SPEECH_CLIENT.synthesis(A, "zh", 1, VIOCE) file_name = f"{uuid4()}.mp3" file_path = os.path.join(CHAT_PATH, file_name) if type(res) == dict: pass with open(file_path, "wb") as f: f.write(res) return file_name
3. ai_uploader 处理Toy的语音指令
-
ai_uploader()
将保存的录音存储成MP3,然后通过a2t转换成文字, 传到my_nlp_low进行处理
-
my_nlp_low(Q,toy_id):
if '我要听' in Q : return {"from_user": "ai", "music": content.get('music')} if '发消息' in Q: for循环好友列表,remark return {'chat' : filename = text2audio(f'可以给{remark}发')} else: A = go_tl(Q) #图灵机器人的回答 filename = text2audio(A) return 返回
music:里的content = my_nlp(Q) # 用到了机器学习gensim的知识,判断歌名相似度
另一种方法是:
for content in MDB.Content.find({}) #从数据库里找歌名 完全匹配
如果和Q相等,则返回
4.BaiduAI ASR 语音识别 实现Toy语音指令 NLP 自然语言处理
上面就用到了是吧
第五天
1. add_req 添加好友请求
-
判断add_type == 'toy' :user_info =Toy.find_ else: User.find_one() req["nickname"] = user_info.get('nickname') if user_info.get('nickname') else user_info.get('toy_name') #这种写法 req['status'] =0 同意 MDB.Request.insert_one(req) #写到Request数据表
-
拒绝好友
reqid = request.form.get('req_id') MDB.Request.update_one({'_id': ObjectId(reqid)}, {'$set': {'status': 2}})
2. req_list 查看当前App所绑定的Toy收到的好友请求
循环列表套字典改值颠覆认知
a = [{'a': 1}, {'a': 2}]
for i in a:
i['a'] = 0
print(a)
结果: [{'a': 0}, {'a': 0}]
程序
add_req_list = list(MDB.Request.find({'toy_id': {"$in": bind_toys}, 'status': 0})) #
for item in add_req_list:
item['_id'] = str(item.get('_id'))
RET['DATA'] = add_req_list
3. acc_req接收好友请求
获得toy user req
-
user添加toy
然后 user_add_toy = {id , nick ,remark , avatar, chat , type} 更新 Users/Toys if req.get('add_type') != 'toy':Users.updat/Toy.update
if add_type == 'toy': MDB.Toys.find_one()/MDB.Users.find_one()
-
toy_add_user
MDB.Request.update_one MDB.Toys.update_one