完整项目地址:gitee.com/Tziq/withou…
一、前言
该教程主要针对,想要了解web机器人,但却不知从何处下手的开发人员。本章实现了文本机器人,下篇文章实现语音机器人
二、技术选型
后台
- springboot
- WebSocket
- 阿里asr(实时)
- 阿里tts
- 阿里云小蜜
前台
- HZRecorder2.js(h5录音功能,解码js)
- h5websocket.js
三、创建云小蜜账户
-
阿里云创建地址:help.aliyun.com/document_de…
-
在机器人管理中获取ID
-
在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>
-
在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()); }
-
查看返回参数
{"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"}
-
使用工厂模式封装对话机器人(为了对接另外的机器人)
-
创建通用对话接口
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; }
-
创建云小蜜实现类
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; } }
-
创建工厂类
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); } }
-
创建通用接收实体
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; }
-
创建robot.properties
ali.accountAccessAK = LTAI4G1oyqgD7pZcnrPMZCMj ali.accountAccessSK = cEnXSJocB2O4AkAnki9s7L5QXSX5Ve ali.popRegion = cn-shanghai ali.popProduct = Chatbot ali.popDomain = chatbot.cn-shanghai.aliyuncs.com
四、创建对话接口
-
创建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)); } }
-
创建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; } }
-
CallResult可去码云地址上自取
五、创建h5项目
-
创建聊天室页面
<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>
-
剩下的js和css可去码云获取
六、演示效果
七、结语
目前实现了h5聊天室的文本机器人,下篇文章将梳理如何实现语音机器人,敬请期待!