提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
前言
语音转换子服务,用于调用语音识别 SDK,进行语音识别,将语音转为文字后返回给网关。
- 语音消息的文字转换:客户端进行语音消息的文字转换。
一、搭建思想
1.参数解析 -- 基于gflags模块
rpc所需信息:
当前服务器的地址端口:用于搭建rpc服务器的监听地址信息
服务注册所需信息:
注册中心的地址端口:用于进行向服务注册中心进行服务注册
外部访问的地址端口:用于告诉注册中心的访问地址信息
语音识别平台所需信息
(app id,api key,secret key)
日志模块所需信息:
运行模式,日志文件名称,日志输出级别
2.初始化日志模块
3.搭建RPC服务器--实现语音识别业务接口功能
4.向注册中心进行服务注册
二、服务器搭建
1.继承speechService类,重写业务代码
只有一个rpc服务,就是进行语音识别,请求方需要将语音文件内容发送过来,我们在需要调用语音识别sdk,因此在成员变量中有一个ASRClient。这个变量是在make_rpc时传入进来的,在创建rpc时需要添加服务。
cpp
//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服务器。
cpp
//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进行服务注册。
cpp
//建造者类,具体思想是通过建造者类的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服务器
};
三.测试
cpp
#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;
}