python 全棧開發,Day133(玩具與玩具之間的對話,基於jieba gensim pypinyin實現的天然語言處理,打包apk)

 

 

先下載github代碼,下面的操做,都是基於這個版原本的!javascript

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

注意:因爲涉及到版權問題,此附件沒有圖片和音樂。請參考連接,手動採集一下!html

請參考連接:前端

http://www.javashuo.com/article/p-splctlzd-t.htmlhtml5

 

1、玩具與玩具之間的對話

app消息提醒

以前實現了App發送語音消息給web端玩具,web端有消息提醒。如今app端,也須要消息提醒!java

那麼在後端,須要判斷。這個消息是人仍是玩具發送的消息。加一個user_typepython

玩具表增長user_type

修改玩具表toys。這裏的小魚,表示用戶!jquery

增長user_typeandroid

toys表的其餘記錄,也須要一併修改ios

務必保證 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,這個是 小甜甜的。

 

點擊 收取消息

 

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

 

這樣,就實現了,玩具之間的通訊了!

 

2、基於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度

 

3、打包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

附帶項目須要的全部文件,包括音頻,圖片,數據庫等等

相關文章
相關標籤/搜索