手把手,撸出java-web机器人 一(初始篇)

942 阅读3分钟

完整项目地址:gitee.com/Tziq/withou…

一、前言

该教程主要针对,想要了解web机器人,但却不知从何处下手的开发人员。本章实现了文本机器人,下篇文章实现语音机器人

二、技术选型

  后台

  1. springboot
  2. WebSocket
  3. 阿里asr(实时)
  4. 阿里tts
  5. 阿里云小蜜  

  前台

  1. HZRecorder2.js(h5录音功能,解码js)
  2. h5websocket.js

 三、创建云小蜜账户

  1. 阿里云创建地址:help.aliyun.com/document_de…

  2. 在机器人管理中获取ID

  3. 在maven项目引入所需SDK

    <dependency>
       <groupId>com.aliyun</groupId>
       <artifactId>aliyun-java-sdk-chatbot</artifactId>
       <version>1.0.0</version>
    </dependency>
    
    <dependency>
       <groupId>com.aliyun</groupId>
       <artifactId>aliyun-java-sdk-core</artifactId>
       <version>4.5.2</version>
    </dependency>
    <dependency>
        <groupId>cn.hutool</groupId>
        <artifactId>hutool-all</artifactId>
        <version>4.5.6</version>
    </dependency>
    
  4. 在main方法中调用

    public static void main(String[] args) throws Exception {
       String accountAccessAK = "XXXXXXXXXXXXXXXXXX";
       String accountAccessSK = "XXXXXXXXXXXXXXXXXX";
       String popRegion = "cn-shanghai";
       String popProduct = "Chatbot";
       String popDomain = "chatbot.cn-shanghai.aliyuncs.com";
       DefaultProfile.addEndpoint(popRegion, popProduct, popDomain);
       IClientProfile profile = DefaultProfile.getProfile(popRegion, accountAccessAK, accountAccessSK);
       DefaultAcsClient client = new DefaultAcsClient(profile);
       //固定入参
       CommonRequest commonRequest = new CommonRequest();
       commonRequest.setSysProduct("Chatbot");
       commonRequest.setSysMethod(MethodType.GET);
       //根据API会有变化
       commonRequest.setSysAction("Chat");
       commonRequest.setSysVersion("2017-10-11");
       commonRequest.putQueryParameter("Utterance", "hi");
       //机器人id
       commonRequest.putQueryParameter("InstanceId", "chatbot-cn-xxxxxxxxxxxx");
       CommonResponse commonResponse = client.getCommonResponse(commonRequest);
       System.out.println(commonResponse.getData());
    }
    
  5. 查看返回参数

    {"Messages":[{"Type":"Text","Text":{"UserDefinedChatTitle":"打招呼","Content":"哈喽,人见人爱的我来啦,有啥我可以帮您的吗~","AnswerSource":"USER_DEFINED_CHAT","HitStatement":"hi"},"Knowledge":{}}],"RequestId":"96F2396B-B116-4F65-90F7-AEBE9D027F65","SessionId":"43619053db654fe3a7e0bed73b9d9d5f","MessageId":"96F2396B-B116-4F65-90F7-AEBE9D027F65"}
    
  6. 使用工厂模式封装对话机器人(为了对接另外的机器人) 

  7. 创建通用对话接口

    package com.withouther.robot.rainingrobot.util.ai.dialogue;
    
    import com.aliyuncs.exceptions.ClientException;
    import com.withouther.robot.rainingrobot.util.ai.dialogue.model.BotResult;
    
    import java.util.Map;
    
    public interface DialogueBot {
        BotResult getDialogue(Map<String, Object> paramMap) throws ClientException;
    }
    
  8. 创建云小蜜实现类

    package com.withouther.robot.rainingrobot.util.ai.dialogue;
    
    import cn.hutool.http.HttpStatus;
    import cn.hutool.setting.dialect.Props;
    import com.alibaba.fastjson.JSON;
    import com.alibaba.fastjson.JSONArray;
    import com.alibaba.fastjson.JSONObject;
    import com.aliyuncs.CommonRequest;
    import com.aliyuncs.CommonResponse;
    import com.aliyuncs.DefaultAcsClient;
    import com.aliyuncs.exceptions.ClientException;
    import com.aliyuncs.http.MethodType;
    import com.aliyuncs.profile.DefaultProfile;
    import com.aliyuncs.profile.IClientProfile;
    import com.withouther.robot.rainingrobot.util.ai.dialogue.model.BotResult;
    import lombok.extern.slf4j.Slf4j;
    
    import java.util.HashMap;
    import java.util.Map;
    
    /**
     * @ClassName BeeBot
     * @Auther: tzq
     * @Date: 2020/9/21 14:00
     * @Description:
     */
    @Slf4j
    public class BeeBot implements DialogueBot {
    
        private static DefaultAcsClient client = null;
    
        public BeeBot() {
            init();
        }
        public void init(){
            Props robotPro = new Props("robot.properties");
            String accountAccessAK = robotPro.getStr("ali.accountAccessAK");
            String accountAccessSK = robotPro.getStr("ali.accountAccessSK");
            String popRegion = robotPro.getStr("ali.popRegion");
            String popProduct = robotPro.getStr("ali.popProduct");
            String popDomain = robotPro.getStr("ali.popDomain");
            if (client == null) {
                DefaultProfile.addEndpoint(popRegion, popProduct, popDomain);
                IClientProfile profile = DefaultProfile.getProfile(popRegion, accountAccessAK, accountAccessSK);
                client = new DefaultAcsClient(profile);
            }
        }
        @Override
        public BotResult getDialogue(Map<String, Object> paramMap) throws ClientException {
            //固定入参
            CommonRequest commonRequest = new CommonRequest();
            commonRequest.setSysProduct("Chatbot");
            commonRequest.setSysMethod(MethodType.GET);
            //根据API会有变化
            commonRequest.setSysAction("Chat");
            commonRequest.setSysVersion("2017-10-11");
            commonRequest.putQueryParameter("Utterance", (String) paramMap.get("text"));
            String InstanceId = paramMap.get("InstanceId") == null ? "chatbot-cn-q6YfyVfq6e" : (String) paramMap.get("InstanceId");
            commonRequest.putQueryParameter("InstanceId", InstanceId);
            CommonResponse commonResponse = post(commonRequest);
            BotResult botResult = new BotResult();
            botResult.setSuccess(commonResponse.getHttpStatus() == HttpStatus.HTTP_OK);
            JSONObject data = JSON.parseObject(commonResponse.getData());
            JSONArray messages = data.getJSONArray("Messages");
            JSONObject textJson = messages.getJSONObject(0).getJSONObject("Text");
            botResult.setText(textJson.getString("Content"));
            botResult.setRequestId(data.getString("RequestId"));
            botResult.setMessage(textJson.getString("AnswerSource"));
            return botResult;
        }
        public CommonResponse post(CommonRequest commonRequest) throws ClientException {
            CommonResponse commonResponse = client.getCommonResponse(commonRequest);
            System.out.println(commonResponse.getData());
            log.debug("dialogueRequest: {}", commonRequest);
            log.debug("dialogueResponse: {}", commonResponse);
            return commonResponse;
        }
    }
    
  9. 创建工厂类

    package com.withouther.robot.rainingrobot.util.ai.dialogue;
    
    import com.aliyuncs.exceptions.ClientException;
    import com.withouther.robot.rainingrobot.util.ai.dialogue.model.BotResult;
    
    import java.util.HashMap;
    import java.util.Map;
    
    /**
     * @ClassName RobotFactory
     * @Auther: tzq
     * @Date: 2020/9/21 15:10
     * @Description:
     */
    public class RobotFactory {
    
        private static RobotFactory tools = null;
    
        private static Map<Integer, DialogueBot> strategyMap = new HashMap<>();
    
        /**
         * 阿里云小蜜
         */
        public static final int BEEBOT = 1;
    
        static {
            strategyMap.put(BEEBOT, new BeeBot());
        }
    
        private RobotFactory() {
            init();
        }
    
        /**
         * 该类的初始化方法
         */
        public void init() {
    
        }
    
        /**
         * 重置该类
         */
        public void reset() {
            init();
        }
    
        /**
         * 工厂方法,返回
         *
         * @return
         */
        public static RobotFactory getFactory() {
            if (tools == null) {
                create();
            }
            return tools;
        }
    
        /**
         * 线程安全的创建方法,防止并发多次创建
         */
        private static synchronized void create() {
            if (tools == null) {
                tools = new RobotFactory();
            }
        }
    
        public BotResult botAction(Map<String, Object> paramMap, int type) throws ClientException {
            DialogueBot dialogueBot = strategyMap.get(type);
            return dialogueBot.getDialogue(paramMap);
        }
    }
    
  10. 创建通用接收实体

    package com.withouther.robot.rainingrobot.util.ai.dialogue.model;
    
    import lombok.Data;
    
    import java.io.Serializable;
    
    /**
     * @ClassName BotResult
     * @Auther: tzq
     * @Date: 2020/9/21 14:08
     * @Description:
     * 通用机器人对话接口实体
     */
    @Data
    public class BotResult implements Serializable {
    
        private String text;
    
        private String requestId;
    
        private String message;
    
        private boolean isSuccess;
    }
    
  11. 创建robot.properties

    ali.accountAccessAK = LTAI4G1oyqgD7pZcnrPMZCMj
    ali.accountAccessSK = cEnXSJocB2O4AkAnki9s7L5QXSX5Ve
    ali.popRegion = cn-shanghai
    ali.popProduct = Chatbot
    ali.popDomain = chatbot.cn-shanghai.aliyuncs.com
    

四、创建对话接口

  1. 创建controller

    package com.withouther.robot.rainingrobot.rest;
    
    import com.withouther.robot.rainingrobot.core.result.CallResult;
    import com.withouther.robot.rainingrobot.service.RobotRecordService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.*;
    
    /**
     * @ClassName RobotRecordController
     * @Auther: tzq
     * @Date: 2020/7/30 21:31
     * @Description:
     */
    @RestController
    @RequestMapping({"/robotRecord"})
    public class RobotRecordController {
    
        @Autowired
        private RobotRecordService robotRecordService;
    
        @GetMapping("/dialogue")
        public CallResult getDialogue(@RequestParam("text") String text) {
            return CallResult.success(robotRecordService.getDialogue(text));
        }
    
    }
    
  2. 创建service

    package com.withouther.robot.rainingrobot.service.impl;
    
    import cn.hutool.core.util.StrUtil;
    import com.aliyuncs.exceptions.ClientException;
    import com.withouther.robot.rainingrobot.service.RobotRecordService;
    import com.withouther.robot.rainingrobot.util.ai.dialogue.RobotFactory;
    import com.withouther.robot.rainingrobot.util.ai.dialogue.model.BotResult;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.stereotype.Service;
    
    import java.util.HashMap;
    import java.util.Map;
    
    /**
     * @ClassName RobotRecordServiceImpl
     * @Auther: tzq
     * @Date: 2020/9/21 15:08
     * @Description:
     */
    @Service
    @Slf4j
    public class RobotRecordServiceImpl implements RobotRecordService {
    
        @Override
        public BotResult getDialogue(String text) {
            Map<String, Object> paramMap = new HashMap<>();
            paramMap.put("text", text);
            BotResult botResult = null;
            try {
                botResult = RobotFactory.getFactory().botAction(paramMap, 1);
            } catch (ClientException e) {
                e.printStackTrace();
            }
            if (StrUtil.isEmpty(botResult.getText())) {
                log.error("未找到答案:{}", botResult);
                botResult.setText("哎呀,你想问的问题,人家暂时不会呢。");
            }
            return botResult;
        }
    }
    
  3. CallResult可去码云地址上自取

五、创建h5项目

  1. 创建聊天室页面

    <html lang="zh-cn" ><head><meta charset="utf-8" /><meta HTTP-EQUIV="pragma" CONTENT="no-cache"><meta HTTP-EQUIV="Cache-Control" CONTENT="no-cache, must-revalidate"><meta HTTP-EQUIV="expires" CONTENT="0"><meta name="apple-touch-fullscreen" content="yes" /><meta name="format-detection" content="telephone=no" /><meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1" /><meta name="viewport" content="width=device-width, initial-scale=1.0 user-scalable=no" media="screen" /><title>无她聊天机器人</title><link rel="stylesheet" type="text/css" href="css/main.css"></head><body><div class="speak_window">    <div class="speak_box">        <div class="answer">            <div class="heard_img left"><img src="images/service.jpg"></div>            <div class="answer_text">                <p>Hey,您的专属导游在此!您可以向我提问哦!有时微信会跟我闹点小脾气,试试关闭当前页面重新进入就ok啦!</p>                <i></i>            </div>        </div>    </div></div><div class="saying">    <img src="images/saying.gif"/></div><div class="wenwen-footer">    <div class="wenwen_text left">        <div class="write_box">            <input type="text" class="left" onKeyUp="keyup()" placeholder="请输入关键字" />        </div>       </div>    <div class="wenwen_help right">        <button onClick="up_say()" class="right">发送</button>    </div>    <div style="opacity:0;" class="clear"></div></div><script type="text/javascript" src="js/jquery-3.2.1.min.js"></script><div style="text-align:center;"></div></body><script src="js/ajaxUtil.js"></script><script src="js/robot.js"></script></html>
    
  2. 剩下的js和css可去码云获取

六、演示效果

七、结语

目前实现了h5聊天室的文本机器人,下篇文章将梳理如何实现语音机器人,敬请期待!