在前几篇的基础上,我们有了语音识别,语音合成,智能机器人,那么我们是不是可以创建一个可以实时对象的机器人了?

当然可以!

一,web版智能对话

前提:你得会flask和websocket

1 ,创建flask项目

#!/usr/bin/env python
# -*- coding:utf8 -*- import os
from flask import Flask, render_template, send_file app = Flask(__name__) @app.route("/index")
def index():
return render_template("index1.html") @app.route("/get_audio/<file_path>/<file_name>")
def get_audio(file_path, file_name):
new_file_path = os.path.join(file_path, file_name)
return send_file(new_file_path) if __name__ == '__main__':
app.run("127.0.0.1", 8000, debug=True)

index.html:用的时候粘贴过去就行!

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title> </head>
<body>
<audio src="" autoplay controls id="player"></audio> <!-- 该标签在有src之后,autoplay属性控制着自动播放--> <button onclick="start_reco()">录制消息</button>
<br>
<button onclick="stop_reco()">发送语音消息</button> </body>
<script src="../static/Recorder.js"></script>
<script type="application/javascript">
var serv = "http://127.0.0.1:8000";
var ws_serv = "ws://127.0.0.1:8080/ws"; var get_music = serv + "/get_audio/";
var ws = new WebSocket(ws_serv);
ws.onmessage = function (data) { // 拿到后端返回的回答的语音文件的路径,再去请求该文件,自动播放
{#console.log(data.data);#}
document.getElementById("player").src = get_music + data.data
};
var reco = null;
var audio_context = new AudioContext(); // 获取浏览器的所有媒体对象
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); // 创建一个 流 的容器,存放二进制语音
reco = new Recorder(stream_input);
} function start_reco() {
reco.record(); // 把语音的二进制文件保存在 流 中
} function stop_reco() {
reco.stop(); // 停止存入
get_audio();
reco.clear(); // 把 流 清空,方便第二次使用
} function get_audio() { // 获取一个wav语音文件
reco.exportWAV(function (wav_file) {
// wav_file = Blob对象
ws.send(wav_file); // 发送给后端
})
} </script>
</html>

里面依赖得Record.js文件,用于音频文件二进制存储在流那个容器中,用的时候粘贴过去就行。

(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.Recorder = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
"use strict"; module.exports = require("./recorder").Recorder; },{"./recorder":2}],2:[function(require,module,exports){
'use strict'; var _createClass = (function () {
function defineProperties(target, props) {
for (var i = 0; i < props.length; i++) {
var descriptor = props[i];descriptor.enumerable = descriptor.enumerable || false;descriptor.configurable = true;if ("value" in descriptor) descriptor.writable = true;Object.defineProperty(target, descriptor.key, descriptor);
}
}return function (Constructor, protoProps, staticProps) {
if (protoProps) defineProperties(Constructor.prototype, protoProps);if (staticProps) defineProperties(Constructor, staticProps);return Constructor;
};
})(); Object.defineProperty(exports, "__esModule", {
value: true
});
exports.Recorder = undefined; var _inlineWorker = require('inline-worker'); var _inlineWorker2 = _interopRequireDefault(_inlineWorker); function _interopRequireDefault(obj) {
return obj && obj.__esModule ? obj : { default: obj };
} function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
} var Recorder = exports.Recorder = (function () {
function Recorder(source, cfg) {
var _this = this; _classCallCheck(this, Recorder); this.config = {
bufferLen: 4096,
numChannels: 2,
mimeType: 'audio_pcm/wav'
};
this.recording = false;
this.callbacks = {
getBuffer: [],
exportWAV: []
}; Object.assign(this.config, cfg);
this.context = source.context;
this.node = (this.context.createScriptProcessor || this.context.createJavaScriptNode).call(this.context, this.config.bufferLen, this.config.numChannels, this.config.numChannels); this.node.onaudioprocess = function (e) {
if (!_this.recording) return; var buffer = [];
for (var channel = 0; channel < _this.config.numChannels; channel++) {
buffer.push(e.inputBuffer.getChannelData(channel));
}
_this.worker.postMessage({
command: 'record',
buffer: buffer
});
}; source.connect(this.node);
this.node.connect(this.context.destination); //this should not be necessary var self = {};
this.worker = new _inlineWorker2.default(function () {
var recLength = 0,
recBuffers = [],
sampleRate = undefined,
numChannels = undefined; self.onmessage = function (e) {
switch (e.data.command) {
case 'init':
init(e.data.config);
break;
case 'record':
record(e.data.buffer);
break;
case 'exportWAV':
exportWAV(e.data.type);
break;
case 'getBuffer':
getBuffer();
break;
case 'clear':
clear();
break;
}
}; function init(config) {
sampleRate = config.sampleRate;
numChannels = config.numChannels;
initBuffers();
} function record(inputBuffer) {
for (var channel = 0; channel < numChannels; channel++) {
recBuffers[channel].push(inputBuffer[channel]);
}
recLength += inputBuffer[0].length;
} function exportWAV(type) {
var buffers = [];
for (var channel = 0; channel < numChannels; channel++) {
buffers.push(mergeBuffers(recBuffers[channel], recLength));
}
var interleaved = undefined;
if (numChannels === 2) {
interleaved = interleave(buffers[0], buffers[1]);
} else {
interleaved = buffers[0];
}
var dataview = encodeWAV(interleaved);
var audioBlob = new Blob([dataview], { type: type }); self.postMessage({ command: 'exportWAV', data: audioBlob });
} function getBuffer() {
var buffers = [];
for (var channel = 0; channel < numChannels; channel++) {
buffers.push(mergeBuffers(recBuffers[channel], recLength));
}
self.postMessage({ command: 'getBuffer', data: buffers });
} function clear() {
recLength = 0;
recBuffers = [];
initBuffers();
} function initBuffers() {
for (var channel = 0; channel < numChannels; channel++) {
recBuffers[channel] = [];
}
} function mergeBuffers(recBuffers, recLength) {
var result = new Float32Array(recLength);
var offset = 0;
for (var i = 0; i < recBuffers.length; i++) {
result.set(recBuffers[i], offset);
offset += recBuffers[i].length;
}
return result;
} function interleave(inputL, inputR) {
var length = inputL.length + inputR.length;
var result = new Float32Array(length); var index = 0,
inputIndex = 0; while (index < length) {
result[index++] = inputL[inputIndex];
result[index++] = inputR[inputIndex];
inputIndex++;
}
return result;
} function floatTo16BitPCM(output, offset, input) {
for (var i = 0; i < input.length; i++, offset += 2) {
var s = Math.max(-1, Math.min(1, input[i]));
output.setInt16(offset, s < 0 ? s * 0x8000 : s * 0x7FFF, true);
}
} function writeString(view, offset, string) {
for (var i = 0; i < string.length; i++) {
view.setUint8(offset + i, string.charCodeAt(i));
}
} function encodeWAV(samples) {
var buffer = new ArrayBuffer(44 + samples.length * 2);
var view = new DataView(buffer); /* RIFF identifier */
writeString(view, 0, 'RIFF');
/* RIFF chunk length */
view.setUint32(4, 36 + samples.length * 2, true);
/* RIFF type */
writeString(view, 8, 'WAVE');
/* format chunk identifier */
writeString(view, 12, 'fmt ');
/* format chunk length */
view.setUint32(16, 16, true);
/* sample format (raw) */
view.setUint16(20, 1, true);
/* channel count */
view.setUint16(22, numChannels, true);
/* sample rate */
view.setUint32(24, sampleRate, true);
/* byte rate (sample rate * block align) */
view.setUint32(28, sampleRate * 4, true);
/* block align (channel count * bytes per sample) */
view.setUint16(32, numChannels * 2, true);
/* bits per sample */
view.setUint16(34, 16, true);
/* data chunk identifier */
writeString(view, 36, 'data');
/* data chunk length */
view.setUint32(40, samples.length * 2, true); floatTo16BitPCM(view, 44, samples); return view;
}
}, self); this.worker.postMessage({
command: 'init',
config: {
sampleRate: this.context.sampleRate,
numChannels: this.config.numChannels
}
}); this.worker.onmessage = function (e) {
var cb = _this.callbacks[e.data.command].pop();
if (typeof cb == 'function') {
cb(e.data.data);
}
};
} _createClass(Recorder, [{
key: 'record',
value: function record() {
this.recording = true;
}
}, {
key: 'stop',
value: function stop() {
this.recording = false;
}
}, {
key: 'clear',
value: function clear() {
this.worker.postMessage({ command: 'clear' });
}
}, {
key: 'getBuffer',
value: function getBuffer(cb) {
cb = cb || this.config.callback;
if (!cb) throw new Error('Callback not set'); this.callbacks.getBuffer.push(cb); this.worker.postMessage({ command: 'getBuffer' });
}
}, {
key: 'exportWAV',
value: function exportWAV(cb, mimeType) {
mimeType = mimeType || this.config.mimeType;
cb = cb || this.config.callback;
if (!cb) throw new Error('Callback not set'); this.callbacks.exportWAV.push(cb); this.worker.postMessage({
command: 'exportWAV',
type: mimeType
});
}
}], [{
key: 'forceDownload',
value: function forceDownload(blob, filename) {
var url = (window.URL || window.webkitURL).createObjectURL(blob);
var link = window.document.createElement('a');
link.href = url;
link.download = filename || 'output.wav';
var click = document.createEvent("Event");
click.initEvent("click", true, true);
link.dispatchEvent(click);
}
}]); return Recorder;
})(); exports.default = Recorder; },{"inline-worker":3}],3:[function(require,module,exports){
"use strict"; module.exports = require("./inline-worker");
},{"./inline-worker":4}],4:[function(require,module,exports){
(function (global){
"use strict"; var _createClass = (function () { function defineProperties(target, props) { for (var key in props) { var prop = props[key]; prop.configurable = true; if (prop.value) prop.writable = true; } Object.defineProperties(target, props); } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); var _classCallCheck = function (instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }; var WORKER_ENABLED = !!(global === global.window && global.URL && global.Blob && global.Worker); var InlineWorker = (function () {
function InlineWorker(func, self) {
var _this = this; _classCallCheck(this, InlineWorker); if (WORKER_ENABLED) {
var functionBody = func.toString().trim().match(/^function\s*\w*\s*\([\w\s,]*\)\s*{([\w\W]*?)}$/)[1];
var url = global.URL.createObjectURL(new global.Blob([functionBody], { type: "text/javascript" })); return new global.Worker(url);
} this.self = self;
this.self.postMessage = function (data) {
setTimeout(function () {
_this.onmessage({ data: data });
}, 0);
}; setTimeout(function () {
func.call(self);
}, 0);
} _createClass(InlineWorker, {
postMessage: {
value: function postMessage(data) {
var _this = this; setTimeout(function () {
_this.self.onmessage({ data: data });
}, 0);
}
}
}); return InlineWorker;
})(); module.exports = InlineWorker;
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{}]},{},[1])(1)
}); Record.js

2 ,在index页面内置ws,实时对话

#!/usr/bin/env python
# -*- coding:utf8 -*- import uuid
import os
from flask_ai_demo.nip_demo import get_ret_file
from flask import Flask, request
from geventwebsocket.websocket import WebSocket
from gevent.pywsgi import WSGIServer
from geventwebsocket.handler import WebSocketHandler app = Flask(__name__) @app.route("/ws")
def ws():
user_socket = request.environ.get("wsgi.websocket") # type:WebSocket
if user_socket:
while True:
try:
msg = user_socket.receive()
# q_file_name = f"{uuid.uuid4()}.wav"
q_file_path = os.path.join("question_audio_pcm", f"{uuid.uuid4()}.wav")
with open(q_file_path, "wb") as f:
f.write(msg)
ret_file_name = get_ret_file(q_file_path)
user_socket.send(ret_file_name) # 把生成好的语音文件名称发给前端,让前端请求获取,播放
os.remove(q_file_path) # 删除生成的语音文件
except Exception as e:
continue if __name__ == '__main__':
http_server = WSGIServer(("127.0.0.1", 8080), app, handler_class=WebSocketHandler)
http_server.serve_forever()

完成后,我们去访问http://127.0.0.1:8000/index页面 和小可爱机器人完了!!!

web服务版智能语音对话的更多相关文章

  1. 处理畅捷通的T+ 12.0版,web服务无故自动停止的问题

    用了几个月的畅捷通T+ 12.0版,一直都挺正常,但最近这两周,出现了好几次web服务自动停止的情况,今天抽空仔细看了Windows的日志,发现在半夜2点左右,TPlusProWebService12 ...

  2. AI 语音对话技术

    机器学习以及自然语言处理技术的进步,开启了人与人工智能进行语音交互的可能,人们透过对话的方式获取信息.与机器进行交互,将不再只是存在科幻情结当中.语音交互是未来的方向,而智能音箱则是语音交互落地的第一 ...

  3. 利用JAX-WS 开发web服务

    近日在学习Rogers Candenhead的第六版的<Java 入门经典>第22章.利用JAX-WS 开发web服务,简略总结而言主要包括以下几个步骤: 1.定义服务端点接口类: 主要就 ...

  4. 《Introduction to Tornado》中文翻译计划——第五章:异步Web服务

    http://www.pythoner.com/294.html 本文为<Introduction to Tornado>中文翻译,将在https://github.com/alioth3 ...

  5. 使用 Spring 3 MVC HttpMessageConverter 功能构建 RESTful web 服务

    原文地址:http://www.ibm.com/developerworks/cn/web/wa-restful/ 简介: Spring,构建 Java™ 平台和 Enterprise Edition ...

  6. JAVA与.NET的相互调用——通过Web服务实现相互调用

    JAVA与.NET是现今世界竞争激烈的两大开发媒体,两者语言有很多相似的地方.而在很多大型的开发项目里面,往往需要使用两种语言进行集成开发.而很多的开发人员都会偏向于其中一种语言,在使用集成开发的时候 ...

  7. Webservices-2.C#创建web服务,及引用访问、代码访问

    注:web服务简介Webservices-1.web服务定义简介 以下均以C#语言为例 一.创建web服务(简单介绍,主要讨论客户端引用) 打开VS创建网站项目,在网站项目中添加“WEB服务(ASMX ...

  8. 用 Java 技术创建 RESTful Web 服务--转载

    简介 JAX-RS (JSR-311) 是为 Java EE 环境下的 RESTful 服务能力提供的一种规范.它能提供对传统的基于 SOAP 的 Web 服务的一种可行替代. 在本文中,了解 JAX ...

  9. 超级好用的前端开发测试Chrome插件-基于REST的Web服务客户端

    基于REST的Web服务客户端是一款功能强大的谷歌浏览器插件,使用基于REST的Web服务客户端(模拟REST客户端)可以让用户使用谷歌浏览器模拟REST请求来测试REST风格. 基于REST的Web ...

随机推荐

  1. WMS开发环境

    须安装以下三个软件: JASPER报表开发工具:TIB_js-studiocomm_6.5.1.final_windows_x86_64.exe UI开发工具:Studio_7.0.0.0_win32 ...

  2. Blob/DataURL/canvas/image的相互转换

    函数都比较简单,直接看就ok了 /*-----------------------------------------------------------------------*/ // canva ...

  3. matlab-数组取值

    一起来学matlab-数组取值 觉得有用的话,欢迎一起讨论相互学习~Follow Me MATLAB中的字符串符号 :冒号 s1=['I am sad';'you are ';'interest'] ...

  4. 【视频开发】【Live555】通过live555实现H264 RTSP直播

    前面的文章中介绍了<H264视频通过RTMP流直播>,下面将介绍一下如何将H264实时视频通过RTSP直播. 实现思路是将视频流发送给live555, 由live555来实现H264数据流 ...

  5. VS2013+OpenCV3.4.2编译

    一.准备工作: (1)在OpenCV官网下载3.4.2版本(注意选择Win pack),https://opencv.org/releases.html. (2)下载Contrib模块,https:/ ...

  6. 设置程序崩溃时产生 core 文件的配置

    /* 不限制 core 文件的大小 */ ulimit -c unlimited /* 使用 pid 进行命名 */ echo " > /proc/sys/kernel/core_us ...

  7. 第07组 Beta冲刺(4/4)

    队名:秃头小队 组长博客 作业博客 组长徐俊杰 过去两天完成的任务:学习了很多东西 Github签入记录 接下来的计划:继续学习 还剩下哪些任务:后端部分 燃尽图 遇到的困难:自己太菜了 收获和疑问: ...

  8. 使用TCP的协议有哪些?使用UDP的协议有哪些?

    运行于TCP协议之上的协议: HTTP协议:超文本传输协议,用于普通浏览 HTTPS协议:安全超文本传输协议,身披SSL外衣的HTTP协议 FTP协议:文件传输协议,用于文件传输 POP3协议:邮局协 ...

  9. 【转帖】vim/sed/awk/grep等文件批处理总结

    vim/sed/awk/grep等文件批处理总结 https://www.cnblogs.com/cangqiongbingchen/p/9760544.html Vim相关操作 1.基础 * 和 # ...

  10. [gRPC] 在 .NET Core 中创建 gRPC 服务端和客户端

    gRPC 官网:https://grpc.io/ 1. 创建服务端 1.1 基于 ASP.NET Core Web 应用程序模板创建 gRPC Server 项目. 1.2 编译并运行 2. 创建客户 ...