当前位置:   article > 正文

ROS高效进阶第五章 -- 机器人语音交互之ros集成科大讯飞星火认知大模型,实现聊天机器人

ROS高效进阶第五章 -- 机器人语音交互之ros集成科大讯飞星火认知大模型,实现聊天机器人

机器人语音交互之ros集成科大讯飞星火认知大模型,实现聊天机器人

1 背景和资料

本文是机器人语音交互交互第二篇,我们将基于上一篇ROS高效进阶第五章 – 机器人语音交互之ros集成科大讯飞中文语音库,实现语音控制机器人小车的 robot_voice 样例,集成科大讯飞星火大模型,做一个语音聊天机器人。这里提醒,本文的测试环境是ubuntu20.04 + ros noetic。
本文参考资料如下:
(1)《ROS机器人开发实践》胡春旭 第8章
(2)开发者如何使用讯飞星火认知大模型API?
(3)ROS高效进阶第五章 – 机器人语音交互之ros集成科大讯飞中文语音库,实现语音控制机器人小车

2 robot_voice 之聊天机器人

(1)下载星火大模型API接口库:具体可以参考开发者如何使用讯飞星火认知大模型API?,整个过程类似上一篇的下载科大讯飞语音库。下载后,得到专属的SDK,如我的:static_16919926417702339_AIKit_Spark_Linux_SDK_v2.4.zip,下面我们将把这套 sdk 集成到 robot_voice 样例中。
(2)聊天机器人的拓扑图如下:

voice_detector
robot_talker
voice_creator

voice_detector:负责语音识别,将语音转换为文字,并作为 client,通过 human_chatter 服务,发给 robot_talker 。
robot_talker:提供 human_chatter 服务 server,接收 voice_detector 发来的文字化的指令,并作为星火大模型接口,向后台询问,获取答复,并将答复内容通过 str2voice 服务发给 voice_creator。
voice_creator:作为 str2voice 服务server,接收 robot_talker 发来的星火大模型答复内容,合成语音文件并播放。
补充:关于ros的服务机制,可以参考本人ROS高效入门博客第二章的2.6节: ROS高效入门第二章 – 基本概念和常用命令学习,基于小乌龟样例
(3)安装环境

unzip static_16919926417702339_AIKit_Spark_Linux_SDK_v2.4.zip
sudo cp libs/x64/libaikit.so /usr/lib/
  • 1
  • 2

(4)创建相关文件

cd ~/catkin_ws/src/robot_voice 
touch launch/robot_talker.launch
touch src/robot_talker.cpp
mkdir include/ifly_spark
  • 1
  • 2
  • 3
  • 4

请将 static_16919926417702339_AIKit_Spark_Linux_SDK_v2.4.zip 中的相关文件,移入指定目录,供编译使用,如下图:
在这里插入图片描述
(5)robot_talker.cpp

#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <iostream>
#include <fstream>
#include <assert.h>
#include <atomic>
#include <ros/ros.h>
#include <std_msgs/String.h>
#include <robot_voice/StringToVoice.h>
#include "ifly_spark/aikit_spark_api.h"

class IflySpark {
public:
  IflySpark() {
    ROS_INFO("IflySpark Constructor");
  }
  ~IflySpark() {
    ROS_INFO("IflySpark Destructor");
  }

  int SendRequest(std::string& ask_str) {
    // clear answer_str_
    IflySpark::answer_str_ = "";
    IflySpark::is_over_ = false;
    //请求参数配置
    AIKIT::ChatParam* config = AIKIT::ChatParam::builder();
    config->uid("xxxid")
          ->domain("generalv2")
          ->auditing("default")
          ->url("ws://spark-api.xf-yun.com/v2.1/chat");

    int ret = AIKIT::AIKIT_AsyncChat(config, ask_str.c_str(), &usr_);
    if(ret != 0) {
        ROS_ERROR("AIKIT_AsyncChat failed:%d\n",ret);
        return ret;
    }
    return ret;
  }

  static void ChatOnToken(AIKIT::AIChat_Handle* handle, const int& completionTokens, const int& promptTokens, const int& totalTokens) {
    if(handle!=nullptr){
        std::cout<<"chatID:"<<((UsrCtx*)handle->usrContext)->chatID<<", ";
    }
    std::cout<<"completionTokens:"<<completionTokens<<" promptTokens:"<<promptTokens<<" totalTokens:"<<totalTokens<<std::endl;
    IflySpark::is_over_ = true;
  }

  static void ChatOnOutput(AIKIT::AIChat_Handle* handle, const char* role, const char* content, const int& index) {
    if(handle!=nullptr){
        std::cout<<"chatID:"<<((UsrCtx*)handle->usrContext)->chatID<<", ";
    }
    std::string slice_txt = content;
    IflySpark::answer_str_ += slice_txt;
  }

  static void ChatOnError(AIKIT::AIChat_Handle* handle, const int& err, const char* errDesc) {
    if(handle!=nullptr){
        std::cout<<"chatID:"<<((UsrCtx*)handle->usrContext)->chatID<<", ";
    }
    printf("chatOnError: err:%d,desc:%s\n",err,errDesc);
  }

  void InitSDK() {
    AIKIT_InitParam initParam{};
    initParam.appID = "bb839ccf";
    initParam.apiKey = "ab95d52b4ea9f2a5dc15e77ae3f778fa";
    initParam.apiSecret = "MTAxZDllZDY1OTVjYmIwYzg2NDBlZWQ0";
    AIKIT::AIKIT_SetLogInfo(100,0,nullptr);
    int ret = AIKIT::AIKIT_Init(&initParam);
    if(ret != 0) {
        ROS_ERROR("AIKIT_Init failed:%d",ret);
        return ;
    }
    //异步回调注册
    AIKIT::AIKIT_ChatCallback({ ChatOnOutput, ChatOnToken, ChatOnError });
  }

  void UnInit() {
    //逆初始化SDK
    AIKIT::AIKIT_UnInit();
  }

  static std::string get_answer_str() {
    while (IflySpark::is_over_ == false || IflySpark::answer_str_ == "") {
      sleep(1); 
    }
    return answer_str_;
  }

private:
  typedef struct UsrCtx {
    std::string chatID;
  } UsrCtx_t;

  // 设置chatID,用于用户动态控制会话轮次
  UsrCtx_t usr_ = {"FistRound"};
  static std::string answer_str_;
  static bool is_over_;
};

std::string IflySpark::answer_str_ = "";
bool IflySpark::is_over_ = false;

class RobotTalker {
public:
  RobotTalker() {
    ROS_INFO("RobotTalker Constructor");
  }

  ~RobotTalker() {
    robot_talker_.UnInit();
    ROS_INFO("RobotTalker Destructor");
  }

  int Init(ros::NodeHandle& nh) {
    robot_talker_.InitSDK();
    client_ = nh.serviceClient<robot_voice::StringToVoice>("str2voice");
    return 0;
  }

  void ToDownstream(const std::string& answer_txt) {
    robot_voice::StringToVoice::Request req;
    robot_voice::StringToVoice::Response resp;
    req.data = answer_txt;
    bool ok = client_.call(req, resp);
    if (ok) {
      printf("send str2voice service success: %s\n", req.data.c_str());
    } else {
      printf("failed to send str2voice service\n");
    }
  }

  bool ChatterCallbback(robot_voice::StringToVoice::Request &req, robot_voice::StringToVoice::Response &resp) {
    printf("i received: %s\n", req.data.c_str());
    std::string voice_txt = req.data;
    std::string answer_txt = "";
	// 向后台发送申请
    robot_talker_.SendRequest(voice_txt);
    // 获取后台反馈信息,并发给下游
    answer_txt = IflySpark::get_answer_str();
    if (answer_txt != "") {
      ToDownstream(answer_txt);
      printf("answer_txt = %s\n", answer_txt.c_str());
    }

    resp.success = true;
    return resp.success;
  }

  void Start(ros::NodeHandle& nh) {
  	// 申明 human_chatter 服务
    chatter_server_ = nh.advertiseService("human_chatter", &RobotTalker::ChatterCallbback, this);
  }

private:
  ros::ServiceServer chatter_server_;
  ros::ServiceClient client_;
  IflySpark robot_talker_;
};

int main(int argc, char* argv[]) {
  int ret = 0;
  ros::init(argc, argv, "robot_talker");
  ros::NodeHandle nh;

  RobotTalker rc;
  rc.Init(nh);

  ROS_INFO("this is a robot talker base ifly spark\n");
  rc.Start(nh);

  ros::spin();
  return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177

(6)robot_talker.launch 和 CMakeLists.txt
robot_talker.launch

<launch>
  <node
      pkg="robot_voice"
      type="voice_creator"
      name="voice_creator"
      output="screen"
  />
  <node
      pkg="robot_voice"
      type="robot_talker"
      name="robot_talker"
      launch-prefix="bash -c 'sleep 5; $0 $@'"
      output="screen"
  />
  <node
      pkg="robot_voice"
      type="voice_detector"
      name="voice_detector"
      launch-prefix="bash -c 'sleep 7; $0 $@'"
      output="screen"
  />
</launch>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

CMakeLists.txt

cmake_minimum_required(VERSION 3.0.2)
project(robot_voice)
add_compile_options(-std=c++11)
find_package(catkin REQUIRED COMPONENTS
  roscpp
  rospy
  std_msgs
  geometry_msgs
  message_generation
)
add_service_files(
  FILES
  StringToVoice.srv
)
generate_messages(
  DEPENDENCIES
  std_msgs
)
catkin_package(
  CATKIN_DEPENDS message_runtime roscpp rospy std_msgs
)
include_directories(
  include
  ${catkin_INCLUDE_DIRS}
)
add_executable(voice_detector 
  src/voice_detector.cpp
  ifly_voice/speech_recognizer.c
  ifly_voice/linuxrec.c)

add_executable(robot_controller src/robot_controller.cpp)
add_executable(robot_talker src/robot_talker.cpp)
add_executable(voice_creator src/voice_creator.cpp)

add_dependencies(voice_detector ${PROJECT_NAME}_generate_messages_cpp)
target_link_libraries(voice_detector
  ${catkin_LIBRARIES} 
  libmsc.so -ldl -lpthread -lm -lrt -lasound
)
add_dependencies(robot_controller ${PROJECT_NAME}_generate_messages_cpp)
target_link_libraries(robot_controller
  ${catkin_LIBRARIES} 
)
add_dependencies(robot_talker ${PROJECT_NAME}_generate_messages_cpp)
target_link_libraries(robot_talker
  ${catkin_LIBRARIES} 
  libaikit.so
)
add_dependencies(voice_creator ${PROJECT_NAME}_generate_messages_cpp)
target_link_libraries(voice_creator
  ${catkin_LIBRARIES} 
  libmsc.so -ldl -pthread
)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53

(7)编译并运行(运行时请注意电脑网络通畅!)

cd ~/catkin_ws/
catkin_make --source src/robot_voice
source devel/setup.bash
roslaunch robot_voice robot_talker.launch
  • 1
  • 2
  • 3
  • 4

高级聊天机器人

(8)在开发调试过程中,出现了如下系统问题,参考这个博客得到解决:/dev/sda1 contains a file system with errors, check forced [duplicate]
在这里插入图片描述

3 总结

本文的样例托管在本人的github上:robot_voice

声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号