文档

ChatUI IMSDK(V2)使用说明

ChatUI是一套对话式界面组件,专注于智能对话领域的设计和技术研发体系,助力消费者可体验的对话式界面搭建。

服务场景

IMSDK主要服务于渠道部署后的页面不能满足业务需求,需要定制聊天对话界面的场景。当渠道部署页面能满足需求时,建议直接使用渠道部署页面,减少开发工作。当机器人没有接入通义模型且不存在人工服务的情况下,也可以直接使用Chat - 会话会话接口进行对接。

集成流程

部署页面支持人工服务、机器人的回复等非一问一答的业务场景,会出现一问多答或者多问多答的情况,服务端需要可以直接发送消息给聊天窗页面,所以需要使用websocket进行连接。渠道建立websocket连接时,需要后端提供的token以保障服务安全性,整体对接流程如下。

  1. im-sdk依赖渠道部署,需要先在智能对话机器人平台新建机器人、关联知识,配置渠道部署并将机器人及关联知识发布到正式环境,使用渠道部署后的链接验证正式环境的问答功能是否正常。

  2. 后端通过InitIMConnect接口,提供获取token的API给前端。

  3. 前端

    1. 对话界面中引入im-sdk-v2.js等依赖的前端资源;

    2. 调用后端提供的获取token的api,拿到AppKey、Token和ImDomain等参数信息;

    3. 初始化im实例:使用new window.IMSDK方法初始化实例,传入token等参数;

    4. 调用im实例的start方法建立连接;

    5. 当用户输入文字后,调用im实例的sendMessage方法将消息内容发送给后端;

    6. 当服务端发送消息时,会调用初始化im实例的参数中的onMessage方法,通过onMessage拿到消息后将消息展示到页面上;

    7. 使用ChatUI或者ChatUI-pro展示服务端发送的消息和控制用户输入后发送消息给服务器。

后端

  • im建联数据获取

后端通过pop接口调用,获取im建联需要参数数据:

名称

类型

必填

描述

示例值及参考API

ImDomain

String

-

示例:alimeim.aliyuncs.com

Token

String

-

IM鉴权参数

AppKey

String

-

应用key

  • 接口详情

    • 方法名:InitIMConnect

    • 请求方式:GET/POST

    • 请求参数:

名称

类型

必填

描述

示例值及参考API

FROM

String

渠道部署fromid

示例值:

XSDDAG

UserAccessToken

String

用户token,通过调用pop接口生成

示例值:

amJIWEtUR2xGTW16R01UZWF4TTVGc1hxbDRtaEdTNWVmMklFeVYzT2dOSjFWUUtuN0xDSjcxM3B5aWtFQjJoUUNvV3pZeXlDc28yZE9Yb3lhenJjN2pIeEtmbVh0anlYd242UUw0d2tSN05qVUQwTTJnV2tFN3VwdDZ1YzJzaTFTeWpoSksrb3FTYlptWGtuUkw4dzJYK0txV0c4djR4eUtmK0piSWdVNFFPdnJOc3c4RWhQeUdaTTRtN3E3L1Q5

详情参考GenerateUserAccessToken - 获取用户登录Token

AgentKey

String

业务空间key,不设置则访问默认业务空间,key值在主账号业务管理页面获取

示例值:

ac627989eb4f8a98ed05fd098bbae5_p_beebot_public

  • maven版本

<dependency>
  <groupId>com.aliyun</groupId>
  <artifactId>chatbot20220408</artifactId>
  <version>1.0.5</version>
</dependency>

示例代码

import com.aliyun.chatbot20220408.models.InitIMConnectResponse;

public class Sample {

    public static void main(String[] args) throws Exception {

        /*
         *  阿里云账号AccessKey拥有所有API的访问权限,建议您使用RAM用户进行API访问或日常运维。
         *  强烈建议不要把AccessKey ID和AccessKey Secret保存到工程代码里,否则可能导致AccessKey泄露,威胁您账号下所有资源的安全。
         *  调用接口前请先配置身份认证,具体操作请参见https://help.aliyun.com/document_detail/378659.html。
         *  本示例使用了阿里云Credentials工具托管AccessKey,来实现API访问的身份验证。
         */
        com.aliyun.credentials.Client credentialClient = new com.aliyun.credentials.Client();
        /*
         * 初始化client
         */
        com.aliyun.chatbot20220408.Client client = new com.aliyun.chatbot20220408.Client(
                new com.aliyun.teaopenapi.models.Config()
                        // 配置云产品服务接入地址(endpoint)。
                        .setEndpoint("chatbot.cn-shanghai.aliyuncs.com")
                        // 使用Credential配置凭证。
                        .setCredential(credentialClient)
        );
        /*
         * 构建请求
         */
        com.aliyun.chatbot20220408.models.InitIMConnectRequest initIMConnectRequest = new com.aliyun.chatbot20220408.models.InitIMConnectRequest()
                .setFrom("xxxxx");
        com.aliyun.teautil.models.RuntimeOptions runtime = new com.aliyun.teautil.models.RuntimeOptions();
        try {
            // 复制代码运行请自行打印 API 的返回值
            InitIMConnectResponse response = client.initIMConnectWithOptions(initIMConnectRequest, runtime);
            System.out.println(response.getBody().getData());
        } catch (Exception error) {
            // 如有需要,请打印 error
            error.printStackTrace();

        }//TeaException error = new TeaException(_error.getMessage(), _error);

    }
}

接口返回数据:

{
  "RequestId": "48365A93-F0D1-1279-B9C4-5B1AA6B2ED5C",
  "Data": {
    "AppKey": "WDg2VfNv",
    "Token": "amJIWEtUR2xGTW16R01UZWF4TTVGc1hxbDRtaEdTNWVmMklFeVYzT2dOSjFWUUtuN0xDSjcxM3B5aWtFQjJoUUNvV3pZeXlDc28yZE9Yb3lhenJjN2pIeEtmbVh0anlYd242UUw0d2tSN05qVUQwTTJnV2tFN3VwdDZ1YzJzaTFTeWpoSksrb3FTYlptWGtuUkw4dzJYK0txV0c4djR4eUtmK0piSWdVNFFPdnJOc3c4RWhQeUdaTTRtN3E3L1Q5",
    "ImDomain": "alimeim.aliyuncs.com"
  },
  "Success": true
}

前端

  • 如何引入

<script src="https://g.alicdn.com/ume/chatbot/1.1.17/im-sdk-v2.js"></script>
  • 初始化

初始化时需要传入一个config对象

字段名

字段类型

是否必填

默认值

说明

url

String

-

ws地址

规范:wss://(固定) + ImDomain(后端接口获取) + /alime/im(固定

例如:wss://alimeim.aliyuncs.com/alime/im

token

String

-

IM鉴权参数

后端通过token生成接口给前端;

appKey

String

-

应用key

uid

String

-

用户id

tid

String

-

租户id

sid

String

-

会话标识

getToken

Function

-

获取token的函数

返回Promise对象

(resolve(token)),断线重连时候使用;

例如:

const im = new window.IMSDK({
  url: 'wss://alimeim.aliyuncs.com/alime/im',
  token: 'amJIWEtUR2xGTW16R01UZWF4TTVGc1hxbDRtaEdTNWVmMklFeVYzT2dOSjFWUUtuN0xDSjcxM3B5aWtFQjJoUUNvV3pZeXlDc28yZE9Yb3lhenJjN2pIeEtmbVh0anlYd242UUw0d2tSN05qVUQwTTJnV2tFN3VwdDZ1YzJzaTFTeWpoSksrb3FTYlptWGtuUkw4dzJYK0txV0c4djR4eUtmK0piSWdVNFFPdnJOc3c4RWhQeUdaTTRtN3E3L1Q5',
  appKey: 'WDg2VfNv',
  getToken: () => {
    return new Promise((resolve) => {
      resolve(123);
    });
  }
});
  • 建立连接

im.start();
  • 设置IM消息通用参数

im.setCommonParams({
  senderId: 666666,
  senderNick: 'xxx',
});

通用参数列表可参考本文档API>setCommonParams(params)部分。

  • 示例

<script src="https://g.alicdn.com/ume/chatbot/1.1.17/im-sdk-v2.js"></script>
<script>
  const im = new window.IMSDK({
    config: {
      /**
       * ws地址
       */
      url: "wss://xxxxxx/alime/im",
      /**
       * IM鉴权参数,接入方自行实现token生成和校验逻辑接入方后端提供token生成接口给前端
       */
      token: "T3ZEcEdWK3hOTXNRNklUejhTaWN6bllsTzVRTEIzSWRSbWJjSGxWTW5VMS9zZ1BKWDEzMEZFbUlMWEY4czhRRE5IcFZGVC9sUURLczlwa2c1ZC9vQ0pBWW9uNzRQRDJoVFFjMjcwTlZwWllsMTJYb0JiWk0wRlhpTzBmdWtyMFJmVEs4MGFJQjVWeWtHY2NCalFqTkthSVVzVlpGalRsQm53VWtiNmxRanBjPQ==",
      /**
       * 应用key
       */
      appKey: "8xx4xxxx",
      /**
       * 获取token的函数,返回Promise对象
       */
    	getToken: () => {
        return new Promise((resolve) => {
          resolve("T3ZEcEdWK3hOTXNRNklUejhTaWN6bllsTzVRTEIzSWRSbWJjSGxWTW5VMS9zZ1BKWDEzMEZFbUlMWEY4czhRRE5IcFZGVC9sUURLczlwa2c1ZC9vQ0pBWW9uNzRQRDJoVFFjMjcwTlZwWllsMTJYb0JiWk0wRlhpTzBmdWtyMFJmVEs4MGFJQjVWeWtHY2NCalFqTkthSVVzVlpGalRsQm53VWtiNmxRanBjPQ==");
        });
      },
    },
    handlers: {
      /**
       * 接收到业务消息
       */
      onMessage: (data: ChatItem) => {
        /**
         * data示例: {
              "header": {
                  "localMsgId": "167057154135437653",
                  "msgId": "991965825848146256",
                  "version": "1.3.1"
              },
              "body": {
                  "senderRole": 3,
                  "senderId": "2022033141787377",
                  "ghost": false,
                  "message": [
                      {
                          "content": {
                              "text": "您好,我是xx,很高兴为您服务。"
                          },
                          "context": {
                              "msg_non_disturb": "false",
                              "@class": "java.util.HashMap",
                              "sdkType": "SERVER_JAVA_SDK"
                          },
                          "extraInfo": {
                              "traceId": "ac10646b16705715412861986d0082",
                              "@class": "java.util.HashMap",
                              "from": "LMm8SngXnv",
                              "sid": "2022120911WXc_LrRJ000000052345"
                          },
                          "msgType": "text"
                      }
                  ]
              }
          }
         */
        console.log('receive message:', data);
      },
      /**
       * 关闭IM连接
       * code为关闭原因:
       *    CONNECTION_KICK_OUT:重复登录,此时建议提示用户有重复登录
       *    CONNECTION_CLOSED:重连5次依然失败,此时建议提示用户系统出错,手动重试
       *    CHEARTBEAT_TIMEOUT:心跳超时断开,未收到pong消息,此时SDK会自动重连,接入方无特殊需求则不用处理
       *    CSERVER_CONNECTION_CLOSED:服务器正在重启引起的连接断开,此时SDK会自动重连,接入方无特殊需求则不用处理
       *    CCONNECTION_TIMEOUT:会话超时连接断开,用户超过一定时长未说话,用户再次发消息会自动重连
       */
      onClose: (err: string) => {
        console.error(err);
      }
    }
  });

	// 建立连接
  im.start();

	/**
   * @method 设置消息通用参数 [可选]
   * @parma {CommonParamsProps} params 发消息者参数
   * @returns
   */
  im.setCommonParams({
    senderId: userId,
    senderNick: nick,
    senderRole: 1,
  });
</script>

消息协议

  • 消息格式

{
  "header": {
    "localMsgId": "167057154135437653", // 本地消息id
    "msgId": "991965825848146256", // 消息id,如果两条消息相同,会更新消息
    "version": "1.3.1" // 消息协议版本
  },
  "body": {
    "senderRole": 3, // //信息来源: 1、用户 3、客服 4、机器人
    "senderId": "2022033141787377", // 发送者ID
    "ghost": false, // 是否存储历史消息
    "message": [
        {
          "content": { // 内容对象
              "text": "您好,我是xx,很高兴为您服务。"
          },
          "context": { // 业务透传对象,由下行消息传递
              "msg_non_disturb": "false",
              "@class": "java.util.HashMap",
              "sdkType": "SERVER_JAVA_SDK"
          },
          "extraInfo": { // 消息扩展字段
              "traceId": "ac10646b16705715412861986d0082",
              "@class": "java.util.HashMap",
              "from": "LMm8SngXnv",
              "sid": "2022120911WXc_LrRJ000000052345"
          },
          "msgType": "text" // 消息类型
        }
    ]
  }
}
  • 消息类型枚举

对于上行消息来说,大部分情况下是文本消息,下行消息里文本消息、卡片消息、富文本消息居多,其他消息相对来说比较少见。文档为了看起来清晰,content直接以JSON格式列举,实际收到的为字符串,需要自己解析成json

重要

消息类型可能会新增,请接入方妥善处理兜底逻辑。

//1、文本消息
{
    "msgType":"text",     //文本消息
    "content":{
      "text":"Hello world"   //文本具体内容
    }
}
//1.1、特殊无答案的情况
{
  "msgType":"text",
  "context":{
    "text":""
  }
}
//2、卡片消息
{
    "msgType":"card",     //卡片消息
    "content":{
        "code":"${code}",      //卡片模版code
        "cardId":"${cardId}",  //卡片id code/cardId二者选一
        "data":{},             //卡片数据
        "params":{} //1.5新增,动态类卡片使用
    }
}
//3、富文本消息
{
    "msgType":"richtext",      //富文本消息
    "content":{
      "contentType":"Html",    //文本格式类型 <Html|Markdown>
      "text":"${text}"         //富文本内容
    }
}
//4、图片消息
{
    "msgType":"image",     //图片消息
    "content":{
      "picUrl":"https://www.alimebot.com/1.jpg"    //图片地址
    }
}
//5、表单信息
{
    "msgType":"form",        //表单信息
    "content":{
      "formData":"${formData}",  //表单内容
      "text":"${text}"           //业务文本
    }
}
//6、订单消息
{
    "msgType":"order",       //订单消息
    "content":{
      "source":"${source}",
      "parentId":"${parentId}",
      "id":"${id}"
    }
}
//7、商品消息
{
    "msgType":"item",      //商品消息
    "content":{
      "source":"${source}",   //商品来源
      "id":"${id}"            //商品id
    }
}
//8、文件消息
{
    "msgType":"file",        //文件消息
    "content":{
      "fileName":"可对客-e收汇系统指引20200220",     //文件名称
      //文件地址
      "fileUrl":"//xspace-img-cn.alicdn.com/consult/1587094983552_H48RpMMec4DBZo9TVo1vkJUv.pdf",
      "fileByteSize":2171616,   //文件大小
      "fileType":"pdf"          //文件类型
   }
}
//9、音频消息
{
    "msgType":"audio",   //音频消息
    "content":{
      "url":"${url}",    //音频地址
      "duration":"${duration}"    //音频时长
    }
}
//10、视频消息
{
    "msgType":"video",        //视频消息
    "content":{
      "url":"${url}",         //视频地址
      "duration":"${duration}",      //视频时长
      "cover":"${cover}"         //封面
    }
}
//11、指令消息
{
    "msgType":"cmd",
    "content":{
  	  "code":"AGENT_SESSION_START",//code列表见"指令消息code列表"
  	  "params":{},
      "text":""//展示文案
    }
}
  • 指令消息(cmd消息)code列表

CMD消息,可根据自己需要过滤有效信息。

AGENT_SESSION_START("进入人工"),
AGENT_SESSION_FAIL("进入人工失败"),
AGENT_JOIN("人工小二进线"),
AGENT_SERVICE_LEAVE("工作台主动断开服务"),
AGENT_LEAVE_NOTICE("人工会话关闭倒计时提醒"),
AGENT_CLIENT_LEAVE("会员主动关闭"),
AGENT_SWITCH("小二转交"),
AGENT_QUEUE("人工进线排队"),
AGENT_NO_SERVICE("小二未上班"),
AGENT_NOT_WORKTIME("小二未在工作时间"),
CLIENT_QUIT_QUEUE("退出人工进线排队"),
CLIENT_CANCEL_RESUME("取消重连"),
CLIENT_RESUME("断线重连"),
CLIENT_LEAVE_SESSION("退出人工"),
CLIENT_JOIN_SESSION("点击转人工"),
AGENT_ENTRANCE_DISPLAY("转人工入口"),
AGENT_DISCONNECT("客服已经断开"),
SWITCH_ORDER_TIP("切换订单提示");

API

getIM()

  • 用途:获取IM实例

  • 参数:无

  • 返回:IM实例

setCommonParams(params)

  • 用途:设置消息通用参数。

  • 使用场景:比如获取地理位置信息是异步的,那么可以在拿到lbs信息之后再设置这个通用参数,这样后续消息发送都会带上。

  • 参数:params里的参数列表如下

字段名

字段类型

是否必填

默认值

说明

senderId

Number

-

发消息者的id

senderNick

String

-

发消息者nick

senderRole

Number

-

消息发送者,1表示会员

device

String

-

设备信息

lbs

Object

-

地理位置信息

province

city

district

longitude

latitude

  • 返回:无

  • 示例:

im.setCommonParams({
  senderId: 'senderId',
  senderNick: "senderNick",
  senderRole: 1,
});

image.png

connect(sync)

  • 用途:建立IM连接。

  • 参数:

字段名

字段类型

是否必填

默认值

说明

sync

Boolean

false

是否同步离线消息

  • 返回:无。

readyState()

  • 用途:获取IM的状态,状态。

  • 参数:无。

  • 返回

    • 类型:number

      • 枚举值:

        • 0:CONNECTING,表示正在连接

        • 1:OPEN,表示连接成功,可以通信了

        • 2:CLOSING,表示连接正在关闭

        • 3:CLOSED,表示连接已经关闭,或者打开连接失败

sendMessage(msg, ghost)

  • 用途:发送消息

  • 参数:msg为对象,具体字段如下

字段名

字段类型

是否必填

默认值

说明

msgType

String

-

消息类型

content

Object

-

消息体

context

Object

-

消息上下文

extraInfo

Object

-

消息额外信息

字段名

字段类型

是否必填

默认值

说明

ghost

Boolean

false

是否存储发送的这条消息

  • 返回:无

im.sendMessage({
  msgType: 'text',
  content: {
    text: '我是发送的消息',
  },
});

close()

  • 用途:关闭IM连接

  • 参数:无

  • 返回:无

reconnect(code)

  • 用途:重新建立连接

  • 参数:

字段名

字段类型

是否必填

默认值

说明

code

String

-

重连原因

  • 返回:无

handlers

onAck

接收到心跳

const im = new window.IMSDK({
  onAck: data => {
    /**
      data示例:{"localMsgId":"167057253604245697","msgId":"991974171800073352"}
    */
    console.log('ack', data);
  });
});

onMessage

接收到业务消息

const im = new window.IMSDK({
  onMessage: data => {
    console.log('message', data);
  });
});

onOpen

websocket连接建立成功

const im = new window.IMSDK({
  onOpen: () => {
    console.log('open');
  });
});

onConnect

IM建立连接成功,和open有区别,connect是和IM系统建立连接成功的事件

const im = new window.IMSDK({
  onConnect: () => {
    console.log('connect');
  });
});

onClose

IM连接关闭

const im = new window.IMSDK({
  onClose: code => {
    console.log('close', code);
  });
});

code为关闭原因

  • CONNECTION_KICK_OUT:重复登录,此时建议提示用户有重复登录

  • CONNECTION_CLOSED:重连5次依然失败,此时建议提示用户系统出错,手动重试

  • HEARTBEAT_TIMEOUT:心跳超时断开,未收到pong消息,此时SDK会自动重连,接入方无特殊需求则不用处理

  • SERVER_CONNECTION_CLOSED:服务器正在重启引起的连接断开,此时SDK会自动重连,接入方无特殊需求则不用处理

  • CONNECTION_TIMEOUT:会话超时连接断开,用户超过一定时长未说话,用户再次发消息会自动重连

onError

IM连接出错

const im = new window.IMSDK({
  onError: err => {
    console.log('error', err);
  });
});

onReconnect

IM正在重连

const im = new window.IMSDK({
  onReconnect: ({ code, err }) => {
    console.log('reconnect', code, err);
  });
});

代码示例

搭配ChatUI实现的对话界面

import React, { useEffect } from 'react';
import { render } from 'react-dom';
import Chat, { Bubble, useMessages } from 'chat-ui';
// 初始消息列表,可选
const initialMessage = [
  {
    type: 'text',
    content: { text: '亲,我是IM测试机器人' },
  },
];
// 默认快捷短语,可选
const defaultQuickReplies = [
  {
    icon: 'message',
    name: '联系人工服务',
    isNew: true,
    isHighlight: true,
  },
  {
    name: '短语1',
    isNew: true,
  },
  {
    name: '短语2',
    isHighlight: true,
  },
  {
    name: '短语3',
  },
];

function App() {
  // 消息列表
  const { messages, appendMsg } = useMessages(initialMessage);

  useEffect(() => {
    const im = new window.IMSDK({
      config: {
        url: 'wss://alimeim.aliyuncs.com/alime/im',
        token: '4890',
        appKey: 'QA97fCuA',
        getToken: () => {
          return new Promise(resolve => {
            resolve('4890');
          });
        },
      },
      handlers: {
        onOpen: () => {
          console.log('open');
        },
        onClose: err => {
          console.log('close', err);
        },
        onError: err => {
          console.log('error', err);
        },
        onReconnect: ({ code, err }) => {
          console.log('reconnect', code, err);
        },
        onMessage: data => {
          appendMsg({
            type: 'text',
            content: {
              text: JSON.stringify(data),
            },
          });
          console.log('message', data);
        }
      }
  });
  
  im.start();
  
  im.setCommonParams({
    senderId: 123456654321,
    senderNick: 'xx',
  });
  
  console.log(im);
  }, []);
  // 发送回调
  function handleSend(type, val) {
    if (type === 'text' && val.trim()) {
      im.sendMessage({
        msgType: 'text',
        content: {
          text: val,
        },
      });
      appendMsg({
        type: 'text',
        content: { text: val },
        position: 'right',
      });
    }
  }
  // 快捷短语回调,可根据 item 数据做出不同的操作,这里以发送文本消息为例
  function handleQuickReplyClick(item) {
    handleSend('text', item.name);
  }
  function renderMessageContent(msg) {
    const { type, content } = msg;
    // 根据消息类型来渲染
    switch (type) {
      case 'text':
        return <Bubble content={content.text} />;
      case 'image':
        return (
          <Bubble type="image">
            <img src={content.picUrl} alt="" />
          </Bubble>
        );
      default:
        return null;
    }
  }
  return (
    <Chat
      messages={messages}
      renderMessageContent={renderMessageContent}
      quickReplies={defaultQuickReplies}
      onQuickReplyClick={handleQuickReplyClick}
      onSend={handleSend}
    />
  );
}
render(<App />, document.getElementById('root'));

Debug

image.png

  • 本页导读 (0)
文档反馈