提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
- 前言
- 一、搭建思想
- 二、服务器搭建
- 1.继承speechService类,重写业务代码
- 2.编写语音识别服务器类
- 3.建造者类编写
- 三.测试
前言
语音转换子服务,用于调用语音识别 SDK,进行语音识别,将语音转为文字后返回给网关。
- 语音消息的文字转换:客户端进行语音消息的文字转换。
一、搭建思想
1.参数解析 – 基于gflags模块
rpc所需信息:
当前服务器的地址端口:用于搭建rpc服务器的监听地址信息
服务注册所需信息:
注册中心的地址端口:用于进行向服务注册中心进行服务注册
外部访问的地址端口:用于告诉注册中心的访问地址信息
语音识别平台所需信息
(app id,api key,secret key)
日志模块所需信息:
运行模式,日志文件名称,日志输出级别
2.初始化日志模块
3.搭建RPC服务器–实现语音识别业务接口功能
4.向注册中心进行服务注册
二、服务器搭建
1.继承speechService类,重写业务代码
只有一个rpc服务,就是进行语音识别,请求方需要将语音文件内容发送过来,我们在需要调用语音识别sdk,因此在成员变量中有一个ASRClient。这个变量是在make_rpc时传入进来的,在创建rpc时需要添加服务。
//1.继承SpeechService服务类,重写业务方法class SpeechServiceImpl :public SpeechService{public:SpeechServiceImpl(const ASRClient::ptr& _asr_client):_client(_asr_client){}~SpeechServiceImpl(){};//重写业务方法void SpeechRecognition(google::protobuf::RpcController* controller,const ::lkm_im::SpeechRecognitionReq* request,::lkm_im::SpeechRecognitionRsp* response,::google::protobuf::Closure* done){brpc::ClosureGuard rpc_guard(done);//解析出请求中的语音数据//基于语音识别sdk进行语音识别调用,获取语音转文字结果std::string err_msg;std::string resp = _client->recognize(request->speech_content(),err_msg);if(resp.empty()){//语音转文字失败LOG_ERROR("requestId = {} 语音识别失败.",request->request_id());response->set_request_id(request->request_id());response->set_success(false);response->set_errmsg(err_msg);}//构造响应返回response->set_request_id(request->request_id());response->set_success(true);response->set_recognition_result(resp);}private:ASRClient::ptr _client; //语音识别客户端};
2.编写语音识别服务器类
在语音识别子服务中有三个对象,一个是服务注册对象,一个是语音识别对象,还有一个是rpc服务器。
服务注册对象的构建需要etcd服务器地址,注册的服务名称以及对应的主机地址。
语音识别对象的构建需要三个key.
rpc服务器构建需要rpc服务器监听的端口,还需要提供超时时间以及io线程数量.
构造这三个对象需要九个参数,因此我们使用建造者模式。
我们通过建造者类来构造这个对象,然后调用这个类提供的start方法,启动rpc服务器。
//2.封装一个语音识别子服务服务器class SpeechServer{public:using ptr = std::shared_ptr<SpeechServer>;SpeechServer(const Registry::ptr& registry,const ASRClient::ptr& asr_client,const std::shared_ptr<brpc::Server>& server):_registry(registry),_asr_client(asr_client),_server(server){}~SpeechServer(){}//启动rpc服务器void start(){_server->RunUntilAskedToQuit();}private:Registry::ptr _registry; //服务注册对象ASRClient::ptr _asr_client; //语音识别客户端std::shared_ptr<brpc::Server> _server; //rpc服务器};
3.建造者类编写
这个类提供了三个方法make_**(),需要先调用这个三个方法,来分别构造出rpc服务器,服务注册和语音识别客户端。在调用build方法,生成一个speechServer对象,通过这个对象就可以启动服务器。
在构造服务注册对象时,就会向etcd进行服务注册。
//建造者类,具体思想是通过建造者类的build函数构造一个SpeechServer对象,通过这个对象启动rpc服务器class SpeechServerBuilder{public:void make_registry(const std::string& etcd_host,const std::string& service_name,const std::string& service_host){_registry = std::make_shared<Registry>(etcd_host);//进行服务注册_registry->registry(service_name,service_host);}void make_asr(const std::string &app_id,const std::string &api_key,const std::string &secret_key){_asr_client = std::make_shared<ASRClient>(app_id,api_key,secret_key);}void make_brpc(uint16_t port, int32_t timeout = -1, uint8_t num_threads = 1){if(!_asr_client){LOG_ERROR("语音识别客户端未构造");abort();}//创建brpc服务器对象_server = std::make_shared<brpc::Server>();//添加服务SpeechServiceImpl *SpeechService = new SpeechServiceImpl(_asr_client); //把这个对象的交给_server释放int ret = _server->AddService(SpeechService,brpc::ServiceOwnership::SERVER_OWNS_SERVICE);if (ret == -1) {LOG_ERROR("添加rpc服务失败");abort();}brpc::ServerOptions options;options.idle_timeout_sec = timeout;options.num_threads = num_threads;ret = _server->Start(port,&options);if(ret == -1){LOG_ERROR("rpc服务器启动失败");abort();}}SpeechServer::ptr build(){if(!_registry){LOG_ERROR("服务注册客户端对象未构造");abort();}if(!_asr_client){LOG_ERROR("语音识别客户端未构造");abort();}if(!_server){LOG_ERROR("rpc服务器对象未构造");abort();}SpeechServer::ptr speechServer = std::make_shared<SpeechServer>(_registry,_asr_client,_server);return speechServer;}private:Registry::ptr _registry; //服务注册对象ASRClient::ptr _asr_client; //语音识别客户端std::shared_ptr<brpc::Server> _server; //rpc服务器};
三.测试
#include "speech_server.hpp"DEFINE_bool(run_mode, false, "程序的运行模式,false-调试; true-发布;");
DEFINE_string(log_file, "", "发布模式下,用于指定日志的输出文件");
DEFINE_int32(log_level, 0, "发布模式下,用于指定日志输出等级");DEFINE_string(etcd_host, "127.0.0.1:2379", "注册中心主机地址");
DEFINE_string(base_service, "/service", "服务监控根目录");
DEFINE_string(instance_name, "/speech_service/instance", "当前实例名称");
DEFINE_string(access_host, "127.0.0.1:10001", "当前实例的外部访问地址");DEFINE_string(app_id, "115608644", "语音平台应用ID");
DEFINE_string(api_key, "GLQvgyNc4AaqhPfnDIMTRlw4", "语音平台API密钥");
DEFINE_string(secret_key, "vTcqDBswZUfAgjTcFA3GJGrc6yEWIO2w", "语音平台加密密钥");DEFINE_int32(rpc_port,10001,"rpc服务器监听端口"); //必须和access_host端口一致int main(int argc,char*argv[])
{google::ParseCommandLineFlags(&argc, &argv, true);lkm_im::init_logger(FLAGS_run_mode, FLAGS_log_file, FLAGS_log_level);lkm_im::SpeechServerBuilder ssb;ssb.make_registry(FLAGS_etcd_host,FLAGS_base_service + FLAGS_instance_name,FLAGS_access_host);ssb.make_asr(FLAGS_app_id,FLAGS_api_key,FLAGS_secret_key);ssb.make_brpc(FLAGS_rpc_port);lkm_im::SpeechServer::ptr speechServer = ssb.build();speechServer->start();return 0;
}