• python 全栈开发,Day133(玩具与玩具之间的对话,基于jieba gensim pypinyin实现的自然语言处理,打包apk)


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

    https://github.com/987334176/Intelligent_toy/archive/v1.6.zip

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

    请参考链接:

    https://www.cnblogs.com/xiao987334176/p/9647993.html#autoid-3-4-0

    一、玩具与玩具之间的对话

    app消息提醒

    之前实现了App发送语音消息给web端玩具,web端有消息提醒。现在app端,也需要消息提醒!

    那么在后端,需要判断。这个消息是人还是玩具发送的消息。加一个user_type

    玩具表增加user_type

    修改玩具表toys。这里的小鱼,表示用户!

    增加user_type

    toys表的其他记录,也需要一并修改

    务必保证 friend_list里面的每一条记录。都有user_type字段!

    务必保证,每一个玩具都有2个好友。一个是主人,一个是除自己之外的玩具。

    用户表增加user_type

    修改用户表

     

    修改第一个好友,增加user_type字段,toy表示玩具

     修改另外一条记录

     完整数据如下:

    {
        "_id" : ObjectId("5b9bb768e1253281608e96eb"),
        "username" : "xiao",
        "password" : "202cb962ac59075b964b07152d234b70",
        "age" : "20",
        "nickname" : "xiao",
        "gender" : "1",
        "phone" : "1234567",
        "avatar" : "boy.jpg",
        "bind_toy" : [
            "5ba0f1f2e12532418089bf88",
            "5ba21c84e1253229c4acbd12"
        ],
        "friend_list" : [
            {
                "friend_id" : "5ba0f1f2e12532418089bf88",
                "friend_name" : "小可爱",
                "friend_remark" : "小甜甜",
                "friend_avatar" : "girl.jpg",
                "friend_chat" : "5ba0f1f2e12532418089bf87",
                "user_type" : "toy"
            },
            {
                "friend_id" : "5ba21c84e1253229c4acbd12",
                "friend_name" : "嘻嘻",
                "friend_remark" : "小豆芽",
                "friend_avatar" : "girl.jpg",
                "friend_chat" : "5ba21c84e1253229c4acbd11",
                "user_type" : "toy"
            }
        ]
    }
    View Code

    务必保证 friend_list里面的每一条记录。都有user_type字段!

    后台逻辑修改

    进入flask项目,修改 serv--> friend.py,增加user_type

    from flask import Blueprint, request, jsonify
    from setting import MONGO_DB
    from setting import RET
    from bson import ObjectId
    
    fri = 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)
    
    @fri.route("/add_req", methods=["POST"])
    def add_req():  # 添加好友请求
        user_id = request.form.get("user_id")  # 有可能是 toy_id or user_id
        friend_id = request.form.get("friend_id")  # 100%是toy_id
        req_type = request.form.get("req_type")
        req_msg = request.form.get("req_msg")  # 描述
        remark = request.form.get("remark")  # 备注
    
        if req_type == "toy":
            user_info = MONGO_DB.toys.find_one({"_id": ObjectId(user_id)})
        else:
            user_info = MONGO_DB.users.find_one({"_id": ObjectId(user_id)})
    
        req_str = {
            "req_user": str(user_info.get("_id")),
            "req_type": req_type,
            "req_toy": friend_id,
            "req_msg": req_msg,
            "avatar": user_info.get("avatar"),
            "user_remark": remark,
            # 昵称,玩具是没有的
            "user_nick": user_info.get("nickname") if user_info.get("nickname") else user_info.get("baby_name"),
            # 状态,1通过,2拒绝,0中间状态(可切换到1和2)。
            "status": 0
        }
    
        MONGO_DB.req.insert_one(req_str)
    
        RET["code"] = 0
        RET["msg"] = "请求发送成功"
        RET["data"] = {}
    
        return jsonify(RET)
    
    @fri.route("/req_list", methods=["POST"])
    def req_list():  # 添加请求列表
        user_id = request.form.get("user_id")
        user_info = MONGO_DB.users.find_one({"_id": ObjectId(user_id)})
        bind_toy = user_info.get("bind_toy")
    
        reqs = list(MONGO_DB.req.find({"req_toy": {"$in": bind_toy}, "status": 0}))
    
        for index, req in enumerate(reqs):
            reqs[index]["_id"] = str(req.get("_id"))
    
        RET["code"] = 0
        RET["msg"] = ""
        RET["data"] = reqs
    
        return jsonify(RET)
    
    
    @fri.route("/get_req", methods=["POST"])
    def get_req():  # 获取一个好友请求
        req_id = request.form.get("req_id")
    
        req_info = MONGO_DB.req.find_one({"_id": ObjectId(req_id)})
    
        req_info["_id"] = str(req_info.get("_id"))
    
        RET["code"] = 0
        RET["msg"] = ""
        RET["data"] = req_info
    
        return jsonify(RET)
    
    
    @fri.route("/acc_req", methods=["POST"])
    def acc_req():  # 允许一个好友请求
        req_id = request.form.get("req_id")
        remark = request.form.get("remark")
    
        req_info = MONGO_DB.req.find_one({"_id": ObjectId(req_id)})
    
        # 1. 为 user 或 toy 添加 toy
        if req_info.get("req_type") == "toy":
            user_info = MONGO_DB.toys.find_one({"_id": ObjectId(req_info.get("req_user"))})
            user_type = "toy"
        else:
            user_info = MONGO_DB.users.find_one({"_id": ObjectId(req_info.get("req_user"))})
            user_type = "user"
    
        toy = MONGO_DB.toys.find_one({"_id": ObjectId(req_info.get("req_toy"))})
    
        chat_window = MONGO_DB.chat.insert_one({"user_list": [str(toy.get("_id")), str(user_info.get("_id"))]})
    
        friend_info = {
            "friend_id": str(toy.get("_id")),
            "friend_name": toy.get("baby_name"),
            "friend_remark": req_info.get("user_remark"),
            "friend_avatar": toy.get("avatar"),
            "friend_chat": str(chat_window.inserted_id),
            "user_type": "toy"
        }
    
        if req_info.get("req_type") == "toy":
            MONGO_DB.toys.update_one({"_id": ObjectId(req_info.get("req_user"))},
                                     {"$push": {"friend_list": friend_info}})
        else:
            MONGO_DB.users.update_one({"_id": ObjectId(req_info.get("req_user"))},
                                      {"$push": {"friend_list": friend_info}})
    
        # 2. 为 toy 添加 user 或 toy
        user_name = user_info.get("nickname") if user_info.get("nickname") else user_info.get("baby_name")
        friend_info2 = {
            "friend_id": str(user_info.get("_id")),
            "friend_name": user_name,
            # 同意方的备注
            "friend_remark": remark if remark else user_name,
            "friend_avatar": user_info.get("avatar"),
            "friend_chat": str(chat_window.inserted_id),
            "user_type":user_type  # 用户类型
        }
    
        MONGO_DB.toys.update_one({"_id": ObjectId(req_info.get("req_toy"))},
                                 {"$push": {"friend_list": friend_info2}})
    
    
        RET["code"] = 0
        RET["msg"] = f"添加好友{remark}成功"
        RET["data"] = {}
    
        MONGO_DB.req.update_one({"_id": ObjectId(req_id)}, {"$set": {"status": 1}})
    
        return jsonify(RET)
    
    
    @fri.route("/ref_req", methods=["POST"])
    def ref_req():  # 拒绝一个好友请求
        req_id = request.form.get("req_id")
    
        MONGO_DB.req.update_one({"_id": ObjectId(req_id)}, {"$set": {"status": 2}})
    
        RET["code"] = 0
        RET["msg"] = "已拒绝好友请求"
        RET["data"] = {}
    
        return jsonify(RET)
    View Code

    修改 serv--> devices.py,增加user_type

    from flask import Blueprint, request, jsonify
    from setting import MONGO_DB
    from setting import RET
    from bson import ObjectId
    
    devs = Blueprint("devs", __name__)
    
    
    @devs.route("/yanzheng_qr", methods=["POST"])
    def yanzheng_qr():  # 验证二维码
        device_id = request.form.get("device_id")  # 获取设备id
        print(device_id)
        if MONGO_DB.devices.find_one({"device_id": device_id}):  # 从数据库中查询设备id
            # 查询该玩具是不是已被用户绑定
            toy_info = MONGO_DB.toys.find_one({"device_id": device_id})
            # 未绑定开启绑定逻辑
            if not toy_info:
                RET["code"] = 0
                RET["msg"] = "感谢购买本公司产品"
                RET["data"] = {}
    
            # 如果被绑定加好友逻辑开启
            if toy_info:
                RET["code"] = 1
                RET["msg"] = "添加好友"
                RET["data"] = {"toy_id": str(toy_info.get("_id"))}
    
        else:
            RET["code"] = 2
            RET["msg"] = "二货,这不是本公司设备,快去买正版!"
            RET["data"] = {}
    
        return jsonify(RET)
    
    
    @devs.route("/bind_toy", methods=["POST"])
    def bind_toy():  # 绑定玩具
        chat_window = MONGO_DB.chat.insert_one({})  # 插入一个空数据
        chat_id = chat_window.inserted_id  # 获取聊天id
    
        user_id = request.form.get("user_id")  # 用户id
        res = MONGO_DB.users.find_one({"_id": ObjectId(user_id)})  # 查询用户id是否存在
    
        device_id = request.form.get("device_id")  # 设备id
        toy_name = request.form.get("toy_name")  # 玩具的昵称
        baby_name = request.form.get("baby_name")  # 小主人的名字
        remark = request.form.get("remark")  # 玩具主人对您的称呼
        gender = request.form.get("gender")  # 性别
    
        toy_info = {
            "device_id": device_id,
            "toy_name": toy_name,
            "baby_name": baby_name,
            "gender": gender,
            "avatar": "boy.jpg" if gender == 1 else "girl.jpg",
            # 绑定用户
            "bind_user": str(res.get("_id")),
            # 第一个好友
            "friend_list": [{
                "friend_id": str(res.get("_id")),  # 好友id
                "friend_name": res.get("nickname"),  # 好友昵称
                "friend_remark": remark,  # 好友称呼
                "friend_avatar": res.get("avatar"),  # 好友头像
                "friend_chat": str(chat_id),  # 好友聊天id
                "user_type":"user"  # 用户类型
            }]
        }
    
        toy_res = MONGO_DB.toys.insert_one(toy_info)  # 插入玩具表数据
    
        if res.get("friend_list"):  # 判断用户好友列表是否为空
            # 追加好友
            res["bind_toy"].append(str(toy_res.inserted_id))
            res["friend_list"].append({
                "friend_id": str(toy_res.inserted_id),
                "friend_name": toy_name,
                "friend_remark": baby_name,
                "friend_avatar": toy_info.get("avatar"),
                "friend_chat": str(chat_id),
                "user_type": "toy"  # 用户类型
            })
        else:
            # 更新好友
            res["bind_toy"] = [str(toy_res.inserted_id)]
            res["friend_list"] = [{
                "friend_id": str(toy_res.inserted_id),
                "friend_name": toy_name,
                "friend_remark": baby_name,
                "friend_avatar": toy_info.get("avatar"),
                "friend_chat": str(chat_id),
                "user_type": "toy"  # 用户类型
            }]
    
        MONGO_DB.users.update_one({"_id": ObjectId(user_id)}, {"$set": res})  # 更新用户记录
    
        # 更新聊天表
        # user_list有2个值。第一个是玩具id,第2个是用户id
        # 这样,用户和玩具就能通讯了
        MONGO_DB.chat.update_one({"_id": chat_id},
                                 {"$set":
                                      {"user_list":
                                           [str(toy_res.inserted_id),
                                            str(res.get("_id"))]}})
    
        RET["code"] = 0
        RET["msg"] = "绑定成功"
        RET["data"] = {}
    
        return jsonify(RET)
    View Code

    修改 utils-->baidu_ai.py,增加user_type

    from aip import AipSpeech
    import os
    BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))  # 项目根目录
    
    import sys
    sys.path.append(BASE_DIR)  # 加入到系统环境变量中
    
    import setting  # 导入setting
    from uuid import uuid4
    # from setting import MONGO_DB
    # import setting
    import os
    from bson import ObjectId
    
    client = AipSpeech(setting.APP_ID,setting.API_KEY,setting.SECRET_KEY)
    
    def text2audio(text):
        res = client.synthesis(text, "zh", 1, setting.SPEECH)
        file_name = f"{uuid4()}.mp3"
        file_path = os.path.join(setting.CHAT_FILE, file_name)
        with open(file_path, "wb") as f:
            f.write(res)
    
        return file_name
    
    
    def get_file_content(filePath):
        os.system(f"ffmpeg -y -i {filePath}  -acodec pcm_s16le -f s16le -ac 1 -ar 16000 {filePath}.pcm")
        with open(f"{filePath}.pcm", 'rb') as fp:
            return fp.read()
    
    
    def audio2text(file_name):
        # 识别本地文件
        liu = get_file_content(file_name)
    
        res = client.asr(liu, 'pcm', 16000, {
            'dev_pid': 1536,
        })
    
        if res.get("result"):
            return res.get("result")[0]
        else:
            return res
    
    # text2audio("你好")
    
    def my_nlp(q,toy_id):
        # 1. 假设玩具说:q = 我要给爸爸发消息
        print(q,"百度q")
        if "发消息" in q:
            toy = setting.MONGO_DB.toys.find_one({"_id":ObjectId(toy_id)})
            # print(toy.get("friend_list"))
            for i in toy.get("friend_list"):
                # print(i.get("friend_remark"),i.get("friend_name"),'iiiiiiiii')
                if i.get("friend_remark") in q or i.get("friend_name") in q :
                    res = text2audio(f"可以按消息键,给{i.get('friend_remark')}发消息了")
                    send_str = {
                        "code": 0,
                        "from_user": i.get("friend_id"),
                        "msg_type": "chat",
                        "data": res,
                        "user_type":i.get("user_type")
                    }
                    return send_str
    
        if "我要听" in q or "我想听" in q or "唱一首" in q:
            sources = setting.MONGO_DB.sources.find({})
            for i in sources:
                if i.get("title") in q:
                    send_str = {
                        "code": 0,
                        "from_user": toy_id,
                        "msg_type": "music",
                        "data": i.get("audio")
                    }
                    return send_str
    
    
    
        res = text2audio("对不起,我没明白你的意思")
        send_str = {
            "code": 0,
            "from_user": toy_id,
            "msg_type": "chat",
            "data": res
        }
        return send_str
    View Code

    修改 im_serv.py,增加user_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
    from utils import baidu_ai
    from utils import chat_redis
    import setting
    from bson import ObjectId
    import time
    
    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>}
    
        file_name = ""
        to_user = ""
        # 循环,接收消息
        while True:
            msg = user_socket.receive()
            if type(msg) == bytearray:
                file_name = f"{uuid4()}.wav"
                file_path = os.path.join(CHAT_FILE, file_name)
                with open(file_path, "wb") as f:
                    f.write(msg)
            else:
                msg_dict = json.loads(msg)
                to_user = msg_dict.get("to_user")
                msg_type = msg_dict.get("msg_type")
                user_type = msg_dict.get("user_type")
    
            if to_user and file_name:
                other_user_socket = user_socket_dict.get(to_user)
                if msg_type == "ai":
                    q = baidu_ai.audio2text(file_path)
                    print(q)
                    ret = baidu_ai.my_nlp(q, tid)
                    other_user_socket.send(json.dumps(ret))
                else:
                    if user_type == "toy":
                        res = setting.MONGO_DB.toys.find_one({"_id": ObjectId(to_user)})
                        fri = [i.get("friend_remark") for i in res.get("friend_list") if i.get("friend_id") == tid][0]
                        msg_file_name = baidu_ai.text2audio(f"你有来自{fri}的消息")
                        send_str = {
                            "code": 0,
                            "from_user": tid,
                            "msg_type": "chat",
                            "user_type": "toy",
                            "data": msg_file_name
                        }
                    else:
                        send_str = {
                            "code": 0,
                            "from_user": tid,
                            "msg_type": "chat",
                            "data": file_name,
                        }
    
                    if other_user_socket:  # 当websocket连接存在时
                        chat_redis.save_msg(tid, to_user)  # 保存消息到redis
                        # 发送数据
                        other_user_socket.send(json.dumps(send_str))
                    else:
                        # 离线消息
                        chat_redis.save_msg(tid, to_user)
    
                    # 保存聊天记录到MongoDB
                    _add_chat(tid, to_user, send_str.get("data"))
    
                to_user = ""
                file_name = ""
    
    
    @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:  # 如果文件名和发送用户同上存在时
                # 查询玩具信息
                res = setting.MONGO_DB.toys.find_one({"_id": ObjectId(to_user)})
                # 获取friend_remark
                fri = [i.get("friend_remark") for i in res.get("friend_list") if i.get("friend_id") == uid][0]
                msg_file_name = baidu_ai.text2audio(f"你有来自{fri}的消息")
    
                # 获取websocket对象
                other_user_socket = user_socket_dict.get(to_user)
                # 构造数据
                send_str = {
                    "code": 0,
                    "from_user": uid,
                    "msg_type": "chat", # 聊天类型
                    # 后缀必须是mp3的
                    "data": msg_file_name
                }
                if other_user_socket:
                    chat_redis.save_msg(uid, to_user)
                    # 发送数据给前端页面
                    other_user_socket.send(json.dumps(send_str))
                else:
                    # 保存redis
                    chat_redis.save_msg(uid, to_user)
    
                # 添加聊天记录到数据库
                _add_chat(uid, to_user, f"{file_name}.mp3")
                # 最后一定要清空这2个变量,否则造成混乱
                file_name = ""
                to_user = ""
    
    def _add_chat(sender, to_user, msg):  # 添加聊天记录到数据库
        chat_window = setting.MONGO_DB.chat.find_one({"user_list": {"$all": [sender, to_user]}})
        if not chat_window.get("chat_list"):
            chat_window["chat_list"] = [{
                "sender": sender,
                "msg": msg,
                "updated_at": time.time(),
            }]
            res = setting.MONGO_DB.chat.update_one({"_id": ObjectId(chat_window.get("_id"))}, {"$set": chat_window})
        else:
            chat = {
                "sender": sender,
                "msg": msg,
                "updated_at": time.time(),
            }
            res = setting.MONGO_DB.chat.update_one({"_id": ObjectId(chat_window.get("_id"))}, {"$push": {"chat_list": chat}})
    
        return res
    
    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  # 歌曲名
    }
    '''
    View Code

    修改 templates-->index.html,增加user_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>
    <br>
    <button onclick="start_reco()">录制消息</button>
    <span id="to_user"></span>
    <span id="user_type"></span>
    <br>
    <button onclick="send_reco()">发送语音消息</button>
    <br>
    <button onclick="recv_msg()">收取消息</button>
    </body>
    <script src="/static/recorder.js"></script>
    <script src="/static/jquery.min.js"></script>
    <script type="application/javascript">
        var serv = "http://127.0.0.1:9527";
        var ws_serv = "ws://127.0.0.1:9528";
    
        // 获取音频文件
        var get_music = serv + "/get_audio/";
        var get_chat = serv + "/get_chat/";
    
        var ws = null;  // WebSocket 对象
        var reco = null;
        // 创建AudioContext对象
        var audio_context = new AudioContext();
    
        var toy_id = null;
    
        //要获取音频和视频
        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 send_reco() {
            reco.stop();
            send_audio();
            reco.clear();
        }
    
        function send_audio() {
            var to_user = document.getElementById("to_user").innerText;
            var user_type = document.getElementById("user_type").innerText;
            var send_str = {
                "to_user": to_user,
                "user_type":user_type
            };
            ws.send(JSON.stringify(send_str));
            reco.exportWAV(function (wav_file) {
                ws.send(wav_file);
            })
        }
    
        function get_audio() {
    
            var send_str = {
                "to_user": toy_id,
                "msg_type": "ai"
            };
            ws.send(JSON.stringify(send_str));
            reco.exportWAV(function (wav_file) {
                ws.send(wav_file);
            })
        }
    
    
        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);  //反序列化数据
                            {#console.log(content);#}
                            // 判断消息类型
                            if (content.msg_type == "chat") {
                                document.getElementById("player").src = get_chat + content.data;
                                document.getElementById("to_user").innerText = content.from_user;
                                document.getElementById("user_type").innerText = content.user_type;
                                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
            );
        }
    
        function recv_msg() {
            var to_user = document.getElementById("to_user").innerText;
            var player = document.getElementById("player");
    
            to_user = document.getElementById("to_user").innerText;
            $.post(
                serv + "/get_msg",
                {user_id: toy_id, sender: to_user},
                function (data) {
                    // shift() 方法用于把数组的第一个元素从其中删除,并返回第一个元素的值
                    var msg = data.data.shift();
                    document.getElementById("to_user").innerText = msg.sender;
                    player.src = get_chat + msg.msg;  //修改audio标签src属性
                    // onended 事件在视频/音频(audio/video)播放结束时触发
                    player.onended = function () {
                        // 如果长度大于0,也就是有1条或者多条时
                        if(data.data.length > 0){
                            //修改audio标签src属性,有多条时,会轮询触发
                           player.src = get_chat + data.data.shift().msg;
                        }else{
                           return null;
                        }
                    }
                }, "json"
            )
        }
    
    
    </script>
    </html>
    View Code

    重启manager.py和im_serv.py

    重新访问网页,让2个玩具开机。左边是小甜甜,右边是小豆芽

    为了保证给对方发消息的时候,不造成混乱!

    修改 玩具表toys,将toy_name和baby_name改成一样的。

    完整数据如下:

    /* 1 createdAt:2018/9/19 下午5:53:08*/
    {
        "_id" : ObjectId("5ba21c84e1253229c4acbd12"),
        "device_id" : "02cc0fc7490b6ee08c31f38ac7a375eb",
        "toy_name" : "小豆芽",
        "baby_name" : "小豆芽",
        "gender" : "2",
        "avatar" : "girl.jpg",
        "bind_user" : "5b9bb768e1253281608e96eb",
        "friend_list" : [
            {
                "friend_id" : "5b9bb768e1253281608e96eb",
                "friend_name" : "xiao",
                "friend_remark" : "小鱼",
                "friend_avatar" : "boy.jpg",
                "friend_chat" : "5ba21c84e1253229c4acbd11",
                "user_type" : "user"
            },
            {
                "friend_id" : "5ba0f1f2e12532418089bf88",
                "friend_name" : "小甜甜",
                "friend_remark" : "小甜甜",
                "friend_avatar" : "girl.jpg",
                "friend_chat" : "5bab7c19e125327ffc804459",
                "user_type" : "toy"
            }
        ]
    },
    
    /* 2 createdAt:2018/9/18 下午8:39:14*/
    {
        "_id" : ObjectId("5ba0f1f2e12532418089bf88"),
        "device_id" : "01f9bf1bac93eddd8397d0455abbeddb",
        "toy_name" : "小甜甜",
        "baby_name" : "小甜甜",
        "gender" : "2",
        "avatar" : "girl.jpg",
        "bind_user" : "5b9bb768e1253281608e96eb",
        "friend_list" : [
            {
                "friend_id" : "5b9bb768e1253281608e96eb",
                "friend_name" : "xiao",
                "friend_remark" : "小鱼",
                "friend_avatar" : "boy.jpg",
                "friend_chat" : "5ba21c84e1253229c4acbd11",
                "user_type" : "user"
            },
            {
                "friend_id" : "5ba21c84e1253229c4acbd12",
                "friend_name" : "小豆芽",
                "friend_remark" : "小豆芽",
                "friend_avatar" : "girl.jpg",
                "friend_chat" : "5bab7c19e125327ffc804459",
                "user_type" : "toy"
            }
        ]
    }
    View Code

    修改 用户表users,也是将toy_name和baby_name改成一样的

    {
        "_id" : ObjectId("5b9bb768e1253281608e96eb"),
        "username" : "xiao",
        "password" : "202cb962ac59075b964b07152d234b70",
        "age" : "20",
        "nickname" : "xiao",
        "gender" : "1",
        "phone" : "1234567",
        "avatar" : "boy.jpg",
        "bind_toy" : [
            "5ba0f1f2e12532418089bf88",
            "5ba21c84e1253229c4acbd12"
        ],
        "friend_list" : [
            {
                "friend_id" : "5ba0f1f2e12532418089bf88",
                "friend_name" : "小甜甜",
                "friend_remark" : "小甜甜",
                "friend_avatar" : "girl.jpg",
                "friend_chat" : "5ba0f1f2e12532418089bf87",
                "user_type" : "toy"
            },
            {
                "friend_id" : "5ba21c84e1253229c4acbd12",
                "friend_name" : "小豆芽",
                "friend_remark" : "小豆芽",
                "friend_avatar" : "girl.jpg",
                "friend_chat" : "5ba21c84e1253229c4acbd11",
                "user_type" : "toy"
            }
        ]
    }
    View Code

    修改 chat表,请确保 主人-->小甜甜-->小豆芽。这3者之间必须要有3条记录!

    分别是:

    主人--> 小甜甜

    主人--> 小豆芽

    小甜甜--> 小豆芽

    这样,就可以实现3者之间的聊天通信了!

     chat完整记录如下:

    /* 1 createdAt:2018/9/25 下午9:05:46*/
    {
        "_id" : ObjectId("5baa32aae125320598c912f3"),
        "user_list" : [
            "5ba0f1f2e12532418089bf88",
            "5ba21c84e1253229c4acbd12"
        ]
    },
    
    /* 2 createdAt:2018/9/19 下午5:53:08*/
    {
        "_id" : ObjectId("5ba21c84e1253229c4acbd11"),
        "user_list" : [
            "5b9bb768e1253281608e96eb",
            "5ba21c84e1253229c4acbd12"
        ]
    },
    
    /* 3 createdAt:2018/9/18 下午8:39:14*/
    {
        "_id" : ObjectId("5ba0f1f2e12532418089bf87"),
        "user_list" : [
            "5b9bb768e1253281608e96eb",
            "5ba0f1f2e12532418089bf88"
        ]
    }
    View Code

    进入左边网页,点击 开始废话,说: 发消息给 小豆芽 。再点击发送语音!

    网页会说:可以按消息键,给 小豆芽 发消息了!

    这里会出现 toy,表示给玩具发消息。左边的id,就是 小豆芽的id

    点击 录制消息,说:你好, 我是小甜甜!

    点击 发送语音消息

    这个时候,网页会有提示: 你有来自 小甜甜 的消息

    切换到第二个网页,会出现设备id,这个是 小甜甜的。

    点击 收取消息

     

     会播放: 你好, 我是小甜甜!

    这样,就实现了,玩具之间的通信了!

    二、基于jieba gensim  pypinyin实现的自然语言处理

    jieba

    jieba分词,完全开源,有集成的python库,简单易用。

    jieba分词是基于前缀词典实现高效的词图扫描,生成句子中汉字所有可能成词情况所构成的有向无环图 (DAG),动态规划查找最大概率路径, 找出基于词频的最大切分组合

    安装

    pip install gensim

    由于包很大,如果安装比较慢,可以使用国内更新源安装

    pip install -i https://pypi.tuna.tsinghua.edu.cn/simple jieba

    使用

    我们通常把这个库叫做 结巴分词 确实是结巴分词,而且这个词库是 made in china , 基本用一下这个结巴分词:

    import jieba
    
    key_word = "我的妈妈真伟大"  # 定义一句话,基于这句话进行分词
    
    cut_word = jieba.cut(key_word)  # 使用结巴分词中的cut方法对"我的妈妈真伟大" 进行分词
    
    print(cut_word)  # <generator object Tokenizer.cut at 0x03676390> 不懂生成器的话,就忽略这里
    
    cut_word_list = list(cut_word)  # 如果不明白生成器的话,这里要记得把生成器对象做成列表
    
    print(cut_word_list)  # ['我', '的', '妈妈', '真', '伟大']

    测试代码就很明显了,它很清晰的把咱们的中文字符串转为列表存储起来了

    如果需要将 "真伟大" 变成一个词,需要添加词库,使用add_word

    import jieba
    
    key_word = "我的妈妈真伟大"  # 定义一句话,基于这句话进行分词
    jieba.add_word("真伟大")  # 添加词库
    cut_word = jieba.cut(key_word)  # 使用结巴分词中的cut方法对"我的妈妈真伟大" 进行分词
    
    
    cut_word_list = list(cut_word)  # 如果不明白生成器的话,这里要记得把生成器对象做成列表
    print(cut_word_list)  # ['我', '的', '妈妈', '真伟大']

    pypinyin

    将汉字转为拼音。可以用于汉字注音、排序、检索(Russian translation) 。

    特性

    • 根据词组智能匹配最正确的拼音。
    • 支持多音字。
    • 简单的繁体支持, 注音支持。
    • 支持多种不同拼音/注音风格。

    安装

    pip install pypinyin

    使用

    from pypinyin import lazy_pinyin,TONE2
    
    key_word = "我的妈妈真伟大"  # 定义一句话
    res = lazy_pinyin(key_word,style=TONE2)  # 设置拼音风格
    print(res)  # ['wo3', 'de', 'ma1', 'ma1', 'zhe1n', 'we3i', 'da4']

    拼音声调是指普通话中的声调,通常叫四声,即阴平(第一声),用“ˉ”表示,如lā;阳平第二声,用“ˊ”表示,如lá;上声第三声),用“ˇ”表示,如lǎ;去声(第四声),用“ˋ”表示,如;là。

    wo3 最后面的3表示声调。它是第三声!

    看下面的例子,这些字也是同音

    from pypinyin import lazy_pinyin,TONE2
    
    key_word = "贝贝蓓蓓背背"  # 定义一句话
    res = lazy_pinyin(key_word,style=TONE2)  # 设置拼音风格
    print(res)  # ['be4i', 'be4i', 'be4i', 'be4i', 'be4i', 'be4i']

    gensim

    Gensim是一款开源的第三方Python工具包,用于从原始的非结构化的文本中,无监督地学习到文本隐层的主题向量表达。 
    它支持包括TF-IDF,LSA,LDA,和word2vec在内的多种主题模型算法, 
    支持流式训练,并提供了诸如相似度计算,信息检索等一些常用任务的API接口

    基本概念

    • 语料(Corpus):一组原始文本的集合,用于无监督地训练文本主题的隐层结构。语料中不需要人工标注的附加信息。在Gensim中,Corpus通常是一个可迭代的对象(比如列表)。每一次迭代返回一个可用于表达文本对象的稀疏向量。

    • 向量(Vector):由一组文本特征构成的列表。是一段文本在Gensim中的内部表达。

    • 稀疏向量(SparseVector):通常,我们可以略去向量中多余的0元素。此时,向量中的每一个元素是一个(key, value)的元组

    • 模型(Model):是一个抽象的术语。定义了两个向量空间的变换(即从文本的一种向量表达变换为另一种向量表达)。

    安装

    pip install jieba

    使用

    这个训练库很厉害, 里面封装很多机器学习的算法, 是目前人工智能的主流应用库,这个不是很好理解, 需要一定的Python数据处理的功底

    import jieba
    import gensim
    from gensim import corpora
    from gensim import models
    from gensim import similarities
    
    l1 = ["你的名字是什么", "你今年几岁了", "你有多高你心情怎么样", "你心情怎么样"]
    a = "你今年多大了"
    
    # 制作语料库
    all_doc_list = []
    for doc in l1:
        doc_list = [word for word in jieba.cut(doc)]
        all_doc_list.append(doc_list)
    
    print(all_doc_list)
    #[['你', '的', '名字', '是', '什么'],
    # 1 4 2 3 0
    #  ['你', '今年', '几岁', '了'],
    # 1 6 7 5
    
    # 将问题分词
    doc_test_list = [word for word in jieba.cut(a)]
    #['你', '今年', '多大', '了']
    # 1 6 5
    
    # 制作词袋
    dictionary = corpora.Dictionary(all_doc_list)
    # 词袋的理解
    # 词袋就是将很多很多的词,进行排列形成一个 词(key) 与一个 标志位(value) 的字典
    # 例如: {'什么': 0, '你': 1, '名字': 2, '是': 3, '的': 4, '了': 5, '今年': 6, '几岁': 7, '多': 8, '心情': 9, '怎么样': 10, '有': 11, '高': 12}
    # 至于它是做什么用的,带着问题往下看
    
    print("token2id", dictionary.token2id)
    print("dictionary", dictionary, type(dictionary))
    
    corpus = [dictionary.doc2bow(doc) for doc in all_doc_list]
    # 语料库:
    # 这里是将all_doc_list 中的每一个列表中的词语 与 dictionary 中的Key进行匹配
    # 得到一个匹配后的结果,例如['你', '今年', '几岁', '了']
    # 就可以得到 [(1, 1), (6, 1), (7, 1), (5, 1)]
    # 1代表的的是 你 1代表出现一次, 5代表的是 了  1代表出现了一次, 以此类推 6 = 今年 , 7 = 几岁
    print("corpus", corpus, type(corpus))
    
    # 将需要寻找相似度的分词列表 做成 语料库 doc_test_vec
    doc_test_vec = dictionary.doc2bow(doc_test_list)
    print("doc_test_vec", doc_test_vec, type(doc_test_vec))
    
    # 将corpus语料库(初识语料库) 使用Lsi模型进行训练
    lsi = models.LsiModel(corpus)
    # 这里的只是需要学习Lsi模型来了解的,这里不做阐述
    print("lsi", lsi, type(lsi))
    # 语料库corpus的训练结果
    print("lsi[corpus]", lsi[corpus])
    # 获得语料库doc_test_vec 在 语料库corpus的训练结果 中的 向量表示
    print("lsi[doc_test_vec]", lsi[doc_test_vec])
    
    # 文本相似度
    # 稀疏矩阵相似度 将 主 语料库corpus的训练结果 作为初始值
    index = similarities.SparseMatrixSimilarity(lsi[corpus], num_features=len(dictionary.keys()))
    print("index", index, type(index))
    
    # 将 语料库doc_test_vec 在 语料库corpus的训练结果 中的 向量表示 与 语料库corpus的 向量表示 做矩阵相似度计算
    sim = index[lsi[doc_test_vec]]
    
    print("sim", sim, type(sim))
    
    # 对下标和相似度结果进行一个排序,拿出相似度最高的结果
    # cc = sorted(enumerate(sim), key=lambda item: item[1],reverse=True)
    cc = sorted(enumerate(sim), key=lambda item: -item[1])
    print(cc)
    
    text = l1[cc[0][0]]
    
    print(a,text)
    View Code

    执行输出:

    [['', '', '名字', '', '什么'], ['', '今年', '几岁', ''], ['', '', '', '', '', '心情', '怎么样'], ['', '心情', '怎么样']]
    
    token2id {'什么': 0, '': 1, '名字': 2, '': 3, '': 4, '': 5, '今年': 6, '几岁': 7, '': 8, '心情': 9, '怎么样': 10, '': 11, '': 12}
    dictionary Dictionary(13 unique tokens: ['什么', '', '名字', '', '']...) <class 'gensim.corpora.dictionary.Dictionary'>
    corpus [[(0, 1), (1, 1), (2, 1), (3, 1), (4, 1)], [(1, 1), (5, 1), (6, 1), (7, 1)], [(1, 2), (8, 1), (9, 1), (10, 1), (11, 1), (12, 1)], [(1, 1), (9, 1), (10, 1)]] <class 'list'>
    doc_test_vec [(1, 1), (5, 1), (6, 1)] <class 'list'>
    lsi LsiModel(num_terms=13, num_topics=200, decay=1.0, chunksize=20000) <class 'gensim.models.lsimodel.LsiModel'>
    lsi[corpus] <gensim.interfaces.TransformedCorpus object at 0x00000260DA2DAF28>
    lsi[doc_test_vec] [(0, 0.900230201263672), (1, 0.3426436202483724), (2, -1.1659919622685817)]
    index <gensim.similarities.docsim.SparseMatrixSimilarity object at 0x00000260DA2F3048> <class 'gensim.similarities.docsim.SparseMatrixSimilarity'>
    sim [0.2956978  0.99180055 0.44080025 0.38174424] <class 'numpy.ndarray'>
    [(1, 0.99180055), (2, 0.44080025), (3, 0.38174424), (0, 0.2956978)]
    你今年多大了 你今年几岁了
    View Code

    噼里啪啦写了这一堆代码,到底干了啥哟?看了一脸懵逼!

    大概意思就是。我抛出了一个问题,就是变量a

    你今年多大了

    在问题库里面,有这些问题

    ["你的名字是什么", "你今年几岁了", "你有多高你心情怎么样", "你心情怎么样"]

    经过 矩阵相似度计算之后,得到一个最优的结果

    你今年几岁了

    也就是说,我问:你今年多大了,机器认为我的问题是:你今天几岁了

    这2句话,其实是一个意思!

    集成到flask

    进入flask项目,进入utils目录,新建文件lowB_plus.py

    import jieba
    import setting
    from gensim import corpora
    from gensim import models
    from gensim import similarities
    
    l1 = []
    for i in setting.MONGO_DB.sources.find({}):
        l1.append(i.get("title"))
    
    
    
    def my_nlp(text):
        # 制作语料库
        all_doc_list = []
        for doc in l1:
            doc_list = [word for word in jieba.cut(doc)]
            all_doc_list.append(doc_list)
    
        print(all_doc_list)
        # [['你', '的', '名字', '是', '什么'],
        # 1 4 2 3 0
        #  ['你', '今年', '几岁', '了'],
        # 1 6 7 5
        # ['你', '有', '多', '高', '你', '胸多大'],
        # 1 9 8 11 1 10
        #  ['你', '胸多大']]
        # 1 10
    
        # 将问题分词
        doc_test_list = [word for word in jieba.cut(text)]
        print(doc_test_list)
        # ['你', '今年', '多大', '了']
        # 1 6 5
    
    
        # 制作词袋
        dictionary = corpora.Dictionary(all_doc_list)
        # 词袋的理解
        # 词袋就是将很多很多的词,进行排列形成一个 词(key) 与一个 标志位(value) 的字典
        # 例如: {'什么': 0, '你': 1, '名字': 2, '是': 3, '的': 4, '了': 5, '今年': 6, '几岁': 7, '多': 8, '有': 9, '胸多大': 10, '高': 11}
        # 至于它是做什么用的,带着问题往下看
    
        print("token2id", dictionary.token2id)
        print("dictionary", dictionary, type(dictionary))
    
        corpus = [dictionary.doc2bow(doc) for doc in all_doc_list]
        # 语料库:
        # 这里是将all_doc_list 中的每一个列表中的词语 与 dictionary 中的Key进行匹配
        # 得到一个匹配后的结果,例如['你', '今年', '几岁', '了']
        # 就可以得到 [(1, 1), (5, 1), (6, 1), (7, 1)]
        # 1代表的的是 你 1代表出现一次, 5代表的是 了  1代表出现了一次, 以此类推 6 = 今年 , 7 = 几岁
        print("corpus", corpus, type(corpus))
    
        # 将需要寻找相似度的分词列表 做成 语料库 doc_test_vec
        doc_test_vec = dictionary.doc2bow(doc_test_list)
        print("doc_test_vec", doc_test_vec, type(doc_test_vec))
        #  [(1, 1), (5, 1), (6, 1)]
    
        # 将corpus语料库(初识语料库) 使用Lsi模型进行训练
        lsi = models.LsiModel(corpus)
        # 这里的只是需要学习Lsi模型来了解的,这里不做阐述
        print("lsi", lsi, type(lsi))
        # 语料库corpus的训练结果
        print("lsi[corpus]", lsi[corpus])
        # 获得语料库doc_test_vec 在 语料库corpus的训练结果 中的 向量表示
        print("lsi[doc_test_vec]", lsi[doc_test_vec])
    
        # 文本相似度
        # 稀疏矩阵相似度 将 主 语料库corpus的训练结果 作为初始值
        index = similarities.SparseMatrixSimilarity(lsi[corpus], num_features=len(dictionary.keys()))
        print("index", index, type(index))
        # 向量表示:
        # (0.387654321,0.84382974,0.4297589245,1.2439785,3.9867462154)
        # ((0.387654321,0.84382974,0.4297589245,1.2439786,3.9867462154),(0.387654321,0.84382974,0.4297589245,1.2439786,3.9867462154),(0.387654321,0.84382974,0.4297589245,1.2439786,3.9867462154),(0.387654321,0.84382974,0.4297589245,1.2439786,3.9867462154))
    
        # 将 语料库doc_test_vec 在 语料库corpus的训练结果 中的 向量表示 与 语料库corpus的 向量表示 做矩阵相似度计算
        sim = index[lsi[doc_test_vec]]
    
        print("sim", sim, type(sim))
    
        # 对下标和相似度结果进行一个排序,拿出相似度最高的结果
        # cc = sorted(enumerate(sim), key=lambda item: item[1],reverse=True)
        cc = sorted(enumerate(sim), key=lambda item: -item[1])
        print(cc)
    
        text = l1[cc[0][0]]
    
        return text
    View Code

    由于还不够智能,所以叫 lowB_plus

    修改 utils-->baidu_ai.py,使用 lowB_plus

    from aip import AipSpeech
    import os
    BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))  # 项目根目录
    
    import sys
    sys.path.append(BASE_DIR)  # 加入到系统环境变量中
    
    import setting  # 导入setting
    from uuid import uuid4
    # from setting import MONGO_DB
    # import setting
    import os
    from bson import ObjectId
    from utils import lowB_plus
    from pypinyin import lazy_pinyin, TONE2
    
    client = AipSpeech(setting.APP_ID,setting.API_KEY,setting.SECRET_KEY)
    
    def text2audio(text):
        res = client.synthesis(text, "zh", 1, setting.SPEECH)
        file_name = f"{uuid4()}.mp3"
        file_path = os.path.join(setting.CHAT_FILE, file_name)
        with open(file_path, "wb") as f:
            f.write(res)
    
        return file_name
    
    
    def get_file_content(filePath):
        os.system(f"ffmpeg -y -i {filePath}  -acodec pcm_s16le -f s16le -ac 1 -ar 16000 {filePath}.pcm")
        with open(f"{filePath}.pcm", 'rb') as fp:
            return fp.read()
    
    
    def audio2text(file_name):
        # 识别本地文件
        liu = get_file_content(file_name)
    
        res = client.asr(liu, 'pcm', 16000, {
            'dev_pid': 1536,
        })
    
        if res.get("result"):
            return res.get("result")[0]
        else:
            return res
    
    # text2audio("你好")
    
    def my_nlp(q,toy_id):
        # 1. 假设玩具说:q = 我要给爸爸发消息
        if "发消息" in q:
            q = "".join(lazy_pinyin(q, style=TONE2))
            print(q)
            toy = setting.MONGO_DB.toys.find_one({"_id": ObjectId(toy_id)})
            # print(toy.get("friend_list"))
            for i in toy.get("friend_list"):
                # 转换成拼音,即使同音字也能匹配
                remark_pinyin = "".join(lazy_pinyin(i.get("friend_remark"), style=TONE2))
                name_pinyin = "".join(lazy_pinyin(i.get("friend_name"), style=TONE2))
                print(name_pinyin)
                if remark_pinyin in q or name_pinyin in q:
                    res = text2audio(f"可以按消息键,给{i.get('friend_remark')}发消息了")
                    send_str = {
                        "code": 0,
                        "from_user": i.get("friend_id"),
                        "msg_type": "chat",
                        "data": res,
                        "user_type":i.get("user_type")
                    }
                    return send_str
    
        if "我要听" in q or "我想听" in q or "唱一首" in q:
            q = str(q).replace("我要听", "")
            q = str(q).replace("我想听", "")
            q = str(q).replace("唱一首", "")
            print(q)
            title = lowB_plus.my_nlp(q)
            sources = setting.MONGO_DB.sources.find_one({"title": title})
            for i in sources:
                if i.get("title") in q:
                    send_str = {
                        "code": 0,
                        "from_user": toy_id,
                        "msg_type": "music",
                        "data": i.get("audio")
                    }
                    return send_str
    
    
    
        res = text2audio("对不起,我没明白你的意思")
        send_str = {
            "code": 0,
            "from_user": toy_id,
            "msg_type": "chat",
            "data": res
        }
        return send_str
    View Code

    测试

    重启 manager.py和im_serv.py

    重新访问网页,让2个玩具开机。左边是小甜甜,右边是小豆芽

    使用 小甜甜给小豆芽发送消息。注意:说话的时候,可以使用儿化音。

    比如:发消息 给 小豆芽儿

    查看Pycharm控制台输出:

    发消息给小豆芽儿
    fa1xia1oxi1ge3ixia3odo4uya2e2r

    第二个网页,小豆芽,也可以接收消息!

    测试同音字

    打开玩具表toys,找到  小甜甜的记录,将小豆芽,改成晓逗牙

    再次测试发送语音给 小豆芽

    小豆芽,一样也可以收到消息!

    注意:尽可能避免多音字。否则会无法匹配到!

    接入图灵

    如果说别的话,比如:今天天气怎么样?网页会提示: 对不起,我没明白你的意思

    这样用户体验不好,那么这种匹配不到的问题,扔给图灵来处理就可以了!

    修改 setting.py,增加图灵配置

    import pymongo
    import os
    import redis
    
    # 数据库配置
    client = pymongo.MongoClient(host="127.0.0.1", port=27017)
    MONGO_DB = client["bananabase"]
    
    
    REDIS_DB = redis.Redis(host="127.0.0.1",port=6379)
    
    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
    
    # 文件目录
    
    
    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 = '11793552'
    API_KEY = 'uA6sToQWcvYt2lT6qTW6WFrG'
    SECRET_KEY = '5rZ1XGYMV39LQBVT4Y1yLNCsmueVe8RQ'
    SPEECH = {
        "spd": 4,
        'vol': 5,
        "pit": 8,
        "per": 4
    }
    
    #图灵配置:
    TL_URL = "http://openapi.tuling123.com/openapi/api/v2"
    TL_DATA = {
        # 请求的类型 0 文本 1 图片 2 音频
        "reqType": 0,
        # // 输入信息(必要参数)
        "perception": {
            # 文本信息
            "inputText": {
                # 问题
                "text": "北京未来七天,天气怎么样"
            }
        },
        # 用户必要信息
        "userInfo": {
            # 图灵机器人的apikey
            "apiKey": "8fc493d348704ba4af5413e67e6fc90b",
            # 用户唯一标识
            "userId": "xiao"
        }
    }
    View Code

    进入utils目录,新建文件  tuling.py

    import requests
    import json
    from setting import TL_URL as tuling_url
    from setting import TL_DATA as data
    
    
    def to_tuling(q,user_id):
        data["perception"]["inputText"]["text"] = q
        data["userInfo"]["userId"] = user_id
        res = requests.post(tuling_url, json=data)
        res_dic = json.loads(res.content.decode("utf8"))  # type:dict
        res_type = res_dic.get("results")[0].get("resultType")
        result = res_dic.get("results")[0].get("values").get(res_type)
        print(result)
        return result
    View Code

    修改 utils-->baidu_ai.py,接入图灵

    from aip import AipSpeech
    import os
    BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))  # 项目根目录
    
    import sys
    sys.path.append(BASE_DIR)  # 加入到系统环境变量中
    
    import setting  # 导入setting
    from uuid import uuid4
    # from setting import MONGO_DB
    # import setting
    import os
    from bson import ObjectId
    from utils import lowB_plus
    from pypinyin import lazy_pinyin, TONE2
    from utils import tuling
    
    client = AipSpeech(setting.APP_ID,setting.API_KEY,setting.SECRET_KEY)
    
    def text2audio(text):
        res = client.synthesis(text, "zh", 1, setting.SPEECH)
        file_name = f"{uuid4()}.mp3"
        file_path = os.path.join(setting.CHAT_FILE, file_name)
        with open(file_path, "wb") as f:
            f.write(res)
    
        return file_name
    
    
    def get_file_content(filePath):
        os.system(f"ffmpeg -y -i {filePath}  -acodec pcm_s16le -f s16le -ac 1 -ar 16000 {filePath}.pcm")
        with open(f"{filePath}.pcm", 'rb') as fp:
            return fp.read()
    
    
    def audio2text(file_name):
        # 识别本地文件
        liu = get_file_content(file_name)
    
        res = client.asr(liu, 'pcm', 16000, {
            'dev_pid': 1536,
        })
    
        if res.get("result"):
            return res.get("result")[0]
        else:
            return res
    
    # text2audio("你好")
    
    def my_nlp(q,toy_id):
        # 1. 假设玩具说:q = 我要给爸爸发消息
        if "发消息" in q:
            q = "".join(lazy_pinyin(q, style=TONE2))
            print(q)
            toy = setting.MONGO_DB.toys.find_one({"_id": ObjectId(toy_id)})
            # print(toy.get("friend_list"))
            for i in toy.get("friend_list"):
                # 转换成拼音,即使同音字也能匹配
                remark_pinyin = "".join(lazy_pinyin(i.get("friend_remark"), style=TONE2))
                name_pinyin = "".join(lazy_pinyin(i.get("friend_name"), style=TONE2))
                print(name_pinyin)
                if remark_pinyin in q or name_pinyin in q:
                    res = text2audio(f"可以按消息键,给{i.get('friend_remark')}发消息了")
                    send_str = {
                        "code": 0,
                        "from_user": i.get("friend_id"),
                        "msg_type": "chat",
                        "data": res,
                        "user_type":i.get("user_type")
                    }
                    return send_str
    
        if "我要听" in q or "我想听" in q or "唱一首" in q:
            q = str(q).replace("我要听", "")
            q = str(q).replace("我想听", "")
            q = str(q).replace("唱一首", "")
            print(q)
            title = lowB_plus.my_nlp(q)
            sources = setting.MONGO_DB.sources.find_one({"title": title})
            for i in sources:
                if i.get("title") in q:
                    send_str = {
                        "code": 0,
                        "from_user": toy_id,
                        "msg_type": "music",
                        "data": i.get("audio")
                    }
                    return send_str
    
        answer = tuling.to_tuling(q, toy_id)
    
        res = text2audio(answer)
        send_str = {
            "code": 0,
            "from_user": toy_id,
            "msg_type": "chat",
            "data": res
        }
        return send_str
    View Code

    重启 manager.py和im_serv.py

    让2个玩具开机,说一段话: 上海的天气怎么样

    网页会播放: 上海:周四,多云转阴 东北风4-5级,最低气温22度,最高气温27度

    查看Pycharm控制台输出:

    上海的天气怎么样
    上海:周四,多云转阴 东北风4-5级,最低气温22度,最高气温27度

    三、打包apk

    单击打原生安装包

     必须要登录账号才行

     注意:默认是使用HBuilder的图标,这样不好。

     

     点击android。因为苹果要相关证书才行,我没有。

    去掉下面的广告。点击参数配置

     输入应用名称

     

     点击图标配置

     

     上传一个图标图片,必须是png格式的!

     点击自动生成并替换

     

     点击启动图片配置,就是 app启动的时候,加载的图片

     找到android,选择1080p图片,并上传!

     

     这里有很多sdk,可以配置

    这里都不用sdk

    点击模块权限配置

     

     默认是这些权限,右侧可以增加

    点击代码视图

     

     这个,就是刚刚所有的配置, 使用Ctrl+s 进行保存

     保存就是这个文件

     重新点击 打原生安装包

     点击忽略

     

     点击确认

     它就会在云端打包,它会给你加一个壳子

    如果提示报错

    点击 重新打包原生,点击参数配置,在这类,重新云端获取!

     打包成功后,查看打包状态

    这样,表示成功了!

     

    点击手动下载,下载成功!

    直接将apk拖动过去,点击应用

     效果如下:

     

    总结:

    1.说说你智能玩具的项目:
    目的:关爱留守儿童, 让玩具成为父母间沟通的桥梁, 让玩具成为孩子的玩伴
    
    实现无屏社交,依靠孩子的语音指令做出响应,例如我要和爸爸聊天,玩具会提示可以和爸爸聊天了并打开与app通讯的链接
    我要听世上只有妈妈好,玩具就会依照指令播放相应的内容
    
    
    2.智能玩具有什么功能:
    功能: 玩具可以语音点播朗诵诗歌,播放音乐,做游戏-成语接龙,与智能机器人聊天,玩具与玩具之间的通讯
    手机app的im通讯 ,手机app可以为玩具点播歌曲,通过手机app管理玩具
    
    
    高人:
    3.智能部分使用了什么算法:
    两种回答:
    1.使用百度ai中的语音合成和语音识别,点播功能是使用Gensim jieba 库进行训练的,聊天做游戏是用的图灵机器人+百度语音合成
    2.使用百度ai中的语音合成和语音识别 NLP自然语言处理 点播功能基于百度NLP,聊天做游戏是用的图灵机器人+百度语音合成
    
    
    4.IM通讯使用了什么机制:
    Websocket
        magicString 
    
    
    5.手机app是怎么做的(使用什么方式):
    mui + html5plus 
    
    
    6.谈谈你对人工智能的理解(说出人工智能技术的关键字至少5个):
    语音类 : 语音识别 语音合成
    图像类 : 图像识别 文字识别 人脸识别 视频审核
    语言类 : 自然语言处理 机器翻译 词法分析 依存句法分析 文本纠错 对话情绪识别 词向量表示 短文本相似度
    词义相似度 情感倾向分析
    
    
    7.mongodb相关:
        1.修改器: $push $set $pull $inc $pop
        2.说说你对 $ 的理解 : $ 我的理解就是代指符号,代指所查询到的数据或索引位置
        3.Mongodb中的数据类型 : ObjectID String Boolean Integer Double Arrays Object(Dict) Null Timestamp Date
        4.mongodb的比较符 : $lt $gt $lte $gte  ":"
    
    
    8.公司组织架构:
        1.综合人力财务行政:1个小姐姐
        2.营销部:老张
        3.产品部:老李 + UI小姐姐
        4.软件部:闫帅 + 前端小姐姐 +5.硬件部:江老师
        
    
    9.项目不做底层,只使用三方的原因:
        制作底层大量占用人力,公司资金不足以支撑底层研发
        将大量成本投入到硬件研发中
        
    10. 项目中,涉及到的技术
        智能语音识别 - 第三方百度ai
            开机提示
        自然语言处理(nlp)
            点歌 :内容点播
            开启消息发送
        
        基于通讯录的即时通讯(IM)
            websocket
            不用第三方的原因 保护隐私
            
        管理玩具的功能:
            1.通过扫描二维码 绑定玩具
            2.玩具通讯录管理
    View Code

    完整终极代码,请参考github:

    https://github.com/987334176/Intelligent_toy/archive/v1.7.zip

    附带项目需要的所有文件,包括音频,图片,数据库等等

  • 相关阅读:
    阻塞队列(BlockingQueue)
    CountDownLatch/CyclicBarrier/Semaphore
    Guava Cache详解
    Java中的常见锁(公平和非公平锁、可重入锁和不可重入锁、自旋锁、独占锁和共享锁)
    CopyOnWriteArrayList详解
    集合类线程安全问题
    原子类的 ABA 问题
    原子类CAS的底层实现
    volatile关键字
    Java 内存模型(Java Memory Model,JMM)
  • 原文地址:https://www.cnblogs.com/xiao987334176/p/9707342.html
Copyright © 2020-2023  润新知