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

python 全栈开发,Day133(玩具与玩具之间的对话,基于jieba gensim  pypinyin实现的自然语言处理,打包apk)
一、玩具与玩具之间的对话
二、基于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。这里的小鱼,表示用户!

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

增加user_type

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

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

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

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

用户表增加user_type

修改用户表

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

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

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

 修改另外一条记录

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

 完整数据如下:

{
    "_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个玩具开机。左边是小甜甜,右边是小豆芽

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

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

修改 玩具表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条记录!

分别是:

主人--> 小甜甜

主人--> 小豆芽

小甜甜--> 小豆芽

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

这样,就可以实现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

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

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

点击 发送语音消息

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

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

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

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

点击 收取消息

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

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

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

二、基于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à。

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个玩具开机。左边是小甜甜,右边是小豆芽

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

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

比如:发消息 给 小豆芽儿

查看Pycharm控制台输出:

发消息给小豆芽儿
fa1xia1oxi1ge3ixia3odo4uya2e2r

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

测试同音字

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

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

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

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

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

接入图灵

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

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

修改 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

单击打原生安装包

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

 必须要登录账号才行

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

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

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

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

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

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

 输入应用名称

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

 点击图标配置

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

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

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

 点击自动生成并替换

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

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

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

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

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

 这里有很多sdk,可以配置

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

这里都不用sdk

点击模块权限配置

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

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

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

点击代码视图

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

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

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

 保存就是这个文件

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

 重新点击 打原生安装包

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

 点击忽略

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

 点击确认

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

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

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

如果提示报错

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

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

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

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

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

这样,表示成功了!

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

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

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

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

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

 效果如下:

 python 全栈开发,Day133(玩具与玩具之间的对话,基于jieba gensim  pypinyin实现的自然语言处理,打包apk)
一、玩具与玩具之间的对话
二、基于jieba gensim  pypinyin实现的自然语言处理
三、打包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

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