0.3.0 • Published 1 year ago

bm-aichat v0.3.0

Weekly downloads
-
License
ISC
Repository
-
Last release
1 year ago

一. 安装

npm i bm-aichat -S
or
yarn add bm-aichat

二. 使用方式

import aiChat from 'bm-aichat'

插件共提供 7 个方法

1. initConfig(options, framework)

初始化配置

(1) options

{
    scene: 'baseline',
    env: 'dev',
    appEnv: 'web',
    appid: '',
    dataid: '',
    service: {
        wssService: '',
        accountService: '',
        articleService: '',
        agiAppService:'',
        loginApiUrl:'',
        articleApiUrl:'',
        robotStatusApiUrl:''
    },
    innerLogin: true,
    getLocation: null,
    extraDeal: {},
    baseline: {
      bankSitesStorage: '_BM_AI_BANKSITES',
    },
    mts: {
        trafficLightOpen: true,
        trafficLightPrecheck: null,
    },
}
参数类型是否必填默认值描述
sceneStringmts使用场景
envStringdev环境变量
appEnvStringweb项目类型
appidString/产品 ID
dataidString/数据 ID
serviceObject/服务配置
service.wssServiceString/WebSocket 服务端地址
service.accountServiceString/账号服务地址
service.articleServiceString/文章服务地址
service.agiAppServiceString/appServ 地址
service.loginApiUrlString/登录接口详细地址
service.articleApiUrlString/文章信息接口详细地址
service.robotStatusApiUrlString/查询机器人在线状态接口详细地址
innerLoginBooleantrue是否自动登录
getLocationFunction/获取用户定位的方法
extraDealObject/额外处理的消息类型
baselineObject/基线架构特殊配置
baseline.bankSitesStorageString_BM_AI_BANKSITES服务网点数据缓存字段名
mtsObject/mts 架构特殊配置
mts.trafficLightOpenBooleantrue是否开启红绿灯机制
mts.trafficLightPrecheckFunction/红绿灯机制前置校验

scene

使用场景,可选值:

  • mts - MTS 架构(默认)
  • baseline - 基线架构

当前业务架构:

scene

env

环境变量,可选值:

  • dev - 开发环境(默认)
  • test - 测试环境
  • pre - 体验环境
  • prd - 生产环境

非生产环境下,service中的服务地址失效,需要配置代理。

appEnv

项目类型,可选值:

  • web - Web 端(默认)
  • h5 - 移动端 H5
  • weapp - 微信小程序 H5

appid

产品 ID

在 3.0 服务系统更新后,appid格式为bmaxxxxxxxxxxxxxxxxxx

dataid

数据 ID

在 3.0 服务系统更新后,dataid格式为bmdxxxxxxxxxxxxxxxxxx

service

相关接口服务地址配置

  • wssService

    WebSocket 服务端地址(完整地址)

  • accountService

    文章服务地址

  • articleService

    文章服务地址

  • agiAppService

    agiAppServ 地址

  • loginApiUrl

    登录接口详细地址

  • articleApiUrl

    文章信息接口详细地址

  • robotStatusApiUrl

    查询机器人在线状态接口详细地址

非生产环境下的 Web 端或移动端 H5(appEnv === 'h5' || appEnv === 'web') && env !== 'prd'service 中的服务地址不生效,需要在项目中手动配置代理:

proxy: {
    '/accservice': {
        target: 'xxx',
        changeOrigin: true,
    },
    '/matcharticle': {
        target: 'xxx',
        changeOrigin: true,
    },
    '/agiAppServ': {
      target: 'xxx',
      changeOrigin: true,
    },
}

插件内使用到的请求接口:

接口默认路由所属服务
登录接口/accservice/v2/userlogin账号服务
文章信息接口/matcharticle文章服务
查询机器人在线状态接口/agiAppServ/mts/getUpDownStatusappServ

生产环境打包后的完整路径为服务地址+默认路由,可根据实际情况配置接口的详细地址,配置后以该详细地址为主。

innerLogin

是否自动登录

如项目内需要手动登录,则传递innerLoginfalse,同时在拿到用户信息后,调用updateState方法,将用户信息同步给插件:

import aiChat from 'bm-aichat'
aiChat.initConfig({
    ...,
    innerLogin: false,
});
// 更新用户信息
aiChat.updateState({
    userInfo:{
        uid:'xxx',
        token:'xxx',
        uname:'xxx',
        sessionCode:'xxx'
    }
});

如项目内不需要手动登录,则传递innerLogintrue,插件会在创建 ws 连接之前自动调用用户登录接口,这种情况下,配置参数中的accountService必填,插件会根据appEnv生成接口参数:

import aiChat from 'bm-aichat'
aiChat.initConfig({
    ...,
    innerLogin: true,
    service:{
        ...,
        accountService:'xxx'
    }
});

getLocation

获取用户定位的方法

插件不内置定位方法,如有定位需求,请传递getLocation,如果传了该参数,在首次调用openConnect方法时,就会执行一次。同时,openConnect返回一个Promise,可以使用awaitthen确保在下一步操作之前,定位方法调用完成,定位失败的错误会在内部拦截。

getLocation需返回Promise,定位结果格式如下:

{
    position: {
      lat: '',            // 纬度
      lng: '',            // 经度
    },
    address: {
      nation: '',         // 国家,例如:中国
      province: '',       // 省份,例如:浙江省
      province_code: '',  // 省份编码,例如:330000
      city: '',           // 城市,例如:杭州市
      city_code: '',      // 城市编码,例如:330100
      district: '',       // 区县,例如:滨江区
      district_code: '',  // 区县编码,例如:330108
      township: '',       // 街道,例如:西兴街道
      township_code: '',  // 街道编码,例如:330108001000
      community: '',      // 社区,例如:新州社区
      community_code: '', // 社区编码,例如:330108001009
    },
    source: '',           // 数据来源,如:高德地图、腾讯地图
}

extraDeal

额外处理的消息类型

如插件内有未处理的消息类型,或需要覆盖掉插件内的处理方式,可以通过extraDeal参数,例如:

import aiChat from 'bm-aichat'
aiChat.initConfig({
    ...,
    extraDeal:{
        "text":(params)=>{}
    }
});

baseline

基线架构特殊配置

  • bankSitesStorage

    服务网点数据缓存字段名

    用于基线架构网点信息消息的处理。

mts

MTS 架构特殊配置

  • trafficLightOpen

    是否开启红绿灯机制,详见红绿灯机制

  • trafficLightPrecheck

    红绿灯机制前置校验,详见红绿灯机制

(2) framework

项目代码使用的框架对象,如Taro

如不传递该参数,插件内使用到的 API 默认采用原生 API。

请确保传递的框架对象身上有以下 API:

  • getStorageSync/setStorageSync
  • login
  • connectSocket
  • request

Taro3 版本的Taro对象中并没有挂载这些方法,而是通过 babel 插件处理的(issues),所以 Taro3 版本使用本插件时暂时使用如下方法:

import Taro from '@tarojs/taro';
const { getStorageSync, setStorageSync, login, connectSocket, request } = Taro;
aiChat.initConfig(
    {...},
    { getStorageSync, setStorageSync, login, connectSocket, request },
);
// 或者
import { getStorageSync, setStorageSync, login, connectSocket, request } from '@tarojs/taro';
aiChat.initConfig(
    {...},
    { getStorageSync, setStorageSync, login, connectSocket, request },
);

2. updateState(payload)

更新同步插件状态

(1) payload

{
    userInfo:{
        uid:'',
        token:'',
        uname:'',
        sessionCode:''
    },
    isVisible:true,
    addressComponent:{},
    robotIds:[]
}
参数类型是否必填描述
userInfoObject用户信息
isVisibleBoolean当前窗口是否可见
addressComponentObject地理位置信息
chosedRobotString当前选中的机器人 ID
robotIdsArray机器人 ID 列表

userInfo

用户信息

包含uidtokenunamesessionCode四个字段。

配合innerLoginfalse时使用,同步用户信息给插件,用于权限校验等。

isVisible

当前窗口是否可见

这个参数主要针对 websocket 的断连重连,当浏览器窗口不可见时,由于浏览器的休眠机制,发送心跳消息的定时器可能会被暂停,导致服务端一分钟未收到心跳消息而断开连接,又因为插件内部的断连重连机制,又会重新创建连接,如此循环,当浏览器长时间处于后台时,会出现创建了多个 websocket 连接的情况。

一般情况下不需要特别处理,但如果需要让连接更可控,可以通过isVisible,当isVisiblefalse时,websocket 断连后不会自动重连。

例如:

import aiChat from 'bm-aichat'

// 添加窗口可见监听函数
document.addEventListener('visibilitychange', handleVisibilitychange)
function handleVisibilitychange() {
  if (!document.hidden) {
    aiChat.updateState({ isVisible: true })
    // 如果断连了,重新连接
    if (断连) {
      aiChat.openConnect()
    }
  } else {
    aiChat.updateState({ isVisible: false })
  }
}

addressComponent

地理位置信息

除了在配置项中传递getLocation以获取地理位置信息,也可通过updateState更新同步,地理位置信息格式同上。

chosedRobot

当前选中的机器人 ID(该参数仅在 MTS 架构中生效)

robotIds

机器人 ID 列表(该参数仅在 MTS 架构中生效)

chosedRobotrobotIds的更新需确保chosedRobot属于robotIds。例如:

import aiChat from 'bm-aichat'
// 首次同步时,必须同时更新chosedRobot和robotIds
aiChat.updateState({
  chosedRobot: 'robot001',
  robotIds: ['robot001', 'robot002', 'robot003'],
})

// 后续同步可只更新chosedRobot或robotIds,但要确保chosedRobot在robotIds之中
aiChat.updateState({
  chosedRobot: 'robot002',
})
aiChat.updateState({
  robotIds: ['robot004', 'robot002', 'robot003'],
})

// 以下会报错
aiChat.updateState({
  chosedRobot: 'robot005', // robot005不在['robot004','robot002','robot003']之中
})
aiChat.updateState({
  robotIds: ['robot004', 'robot005', 'robot003'], // robot002不在['robot004','robot005','robot003']之中
})
// 更改为
aiChat.updateState({
  chosedRobot: 'robot005',
  robotIds: ['robot004', 'robot005', 'robot003'],
})

3. openConnect()/closeConnect()

建立/关闭 websocket 连接

(1) 连接流程

连接流程

(2) 说明

  • 插件内部实现了 websocket 的异常断连重连

    手动创建连接时将isReconnect置为true,如果发生异常断连的情况,会在 2s 后重新建立连接。

    手动断开连接时将isReconnect置为false,不会触发重连。

4. sendMessage(params)

向 websocket 服务端发送消息

(1) params

{
    contents:{
        type:'',
        data:{
            content:'',
            stype:'',
            status:1,
            replyId:'',
            meaning:'',
            params:{},
        }
    },
    robotId:''
}
参数类型是否必填描述
contentsObject | Array发送消息内容
typeString消息类型
dataObject消息主体
data.contentString用户发送内容
data.stypeString业务类型
data.statusNumbertype表达通知时,固定值为1
data.replyIdString回复 ID
data.meaningString程序行为含义
data.paramsObject程序行为具体参数
robotIdString机器人 ID

contents

发送消息内容

contents可以是对象也可以是数组:

contents:[
    {
        type:'',
        data:{...},
    },{
        type:'',
        data:{...},
    },
    ...
],

如果是数组,MTS 架构下会当做一条消息发送,基线架构则是发送多条消息。

  • type

    消息类型,当前应用到的消息类型有:

    • 文本
    • M(程序行为)
    • 客户端状态
    • 应答确认
    • 表达通知
  • data

    消息主体

    • content

      用户发送内容

      type文本时必填。

    • stype

      业务类型,可选值:

      • app(移动端)
      • pc(pc 端)
      • 公众号
      • human(虚拟人业务)

      type客户端状态时必填。

    • status

      固定值为1

      type表达通知时必填。

    • replyId

      回复 ID,对应接收到消息中的replyId

      type表达通知应答确认时必填。

    • meaning

      程序行为含义,如:接口调用、地址选择等

      typeM时必填。

    • params

      程序行为具体参数

      typeM时必填。

robotId

机器人 ID(该参数仅在 MTS 架构中生效)

若不填写robotId,默认取当前状态下的chosedRobot

(2) 各类型示例

1) 文本

import aiChat from 'bm-aichat'
aiChat.sendMessage({
  contents: {
    type: '文本',
    data: {
      content: '你好',
    },
  },
})

2) M(程序行为)

import aiChat from 'bm-aichat'
aiChat.sendMessage({
  contents: {
    type: 'M',
    data: {
      meaning: '接口调用',
      params: {
        接口名称: '定位',
        调用结果: '成功',
      },
    },
  },
})

3) 客户端状态

import aiChat from 'bm-aichat'
aiChat.sendMessage({
  contents: {
    type: '客户端状态',
    data: {
      content: '用户上线',
      stype: 'human',
    },
  },
  robotId: 'robot001',
})

4) 应答确认

import aiChat from 'bm-aichat'
// 消息数据
const { data, robotId } = params
aiChat.sendMessage({
  contents: {
    type: '应答确认',
    data: {
      replyId: data.replyId,
    },
  },
  robotId,
})

5) 表达通知

import aiChat from 'bm-aichat'
// 消息数据
const { data, robotId } = params
aiChat.sendMessage({
  contents: {
    type: '表达通知',
    data: {
      status: 1,
      replyId: data.replyId,
    },
  },
  robotId,
})

5. openListener(onMessage, onStatusChange, onRobotOnline)

开启监听

参数类型是否必填描述
onMessageFunction接收聊天消息的回调函数
onStatusChangeFunction连接状态监听回调函数
onRobotOnlineFunction机器人上线回调函数(MTS 架构)
import aiChat from 'bm-aichat'
aiChat.openListener(
  (msg) => {},
  ({ websocketIsOk, uid, token, uname, sessionCode }) => {},
  ({ robotId, isOnline }) => {},
)

(1) onMessage

接收聊天消息的回调函数

用于接收消息返回,msg的基本格式如下:

{
    msgType:'',
    msgId:nanoid(),
    orientation:'',
    time:new Date().getTime(),
    action:null,
    finelly:null,
    ...
}
参数类型描述
msgTypeString消息类型
msgIdString消息 ID
orientationString消息定位
timeTimestamp消息回复时间
action不固定插件处理后的数据
finellyFunction消息处理完成后的回调函数

msgType

消息类型,详见下文消息类型

msgId

消息 ID

采用NanoID规则生成的唯一标识。

orientation

消息定位,可选值:

  • l - 正常的聊天消息
  • m - 需要特殊处理的聊天消息

time

消息回复时间

action

插件处理后的数据

不同msgType处理后的action类型有所区别。

finelly

消息处理完成后的回调函数

有时候项目在接收到插件传递的消息时,并非立刻处理,可能有一些异步操作,比如每隔一段时间将消息展示到页面上,而插件在消息处理完毕后还有其他操作。为确保流程的准确性,需要插件使用方在处理完消息后,执行msg.finelly()

目前只在 MTS 架构文本消息中使用到。

除了msgTypemsgIdorientationtimeactionfinelly字段,msg还会携带源消息数据。

(2) onStatusChange

连接状态监听回调函数

websocket 状态改变时触发该回调函数,同时会携带上用户信息。

(3) onRobotOnline

机器人上线回调函数

机器人上线后触发该回调函数,详见用户上线流程

(4) 消息类型

当前插件内部集成的消息类型如下:

  • 公共的消息类型:
消息类型消息定位源消息类型描述
maintainm服务器维护
wordFilterm触发敏感词
kickoffm触发互踢
invalidTokenmtoken 过期
loginErrorm登录错误
  • MTS 架构的消息类型:
消息类型消息定位源消息类型描述
textl文本、text文本消息
articlel文章文章消息
expressionm表情表情消息,如”打招呼“等
moodm情绪情绪消息,如“生气”等
attitudemAI 对用户态度AI 对用户态度,包括“亲密”和“敌意”
quickReplymAI 快捷设置AI 快捷设置,用于隐藏/显示快捷回复按钮
  • 基线架构的消息类型:
消息类型消息定位源消息类型描述
everyoneAskingDatam大家都在问“大家都在问”数据
relatedCaseDatam相关案例“相关案例”数据
guessDatam猜你想问、guess-list“猜你想问”数据
textl文本、text、phone文本消息,一些特殊文本(拨打电话、名词解释、点击回复)已处理
listl列表列表消息
menusl菜单消息、multi-options-reply菜单消息
downloadFilel文书下载文书下载消息
imagel图片图片消息
videol视频视频消息
articlel文章推送文章消息
siteInfol网点信息网点消息
rich-textlrich-text富文本消息
cardslcard-org卡片消息

(5) 聊天流程

聊天流程

(6) 说明

  • 以下四种情况都会断开 websocket 连接,但处理又有区别:

    1. token 过期

    2. 登录错误

      token 过期和登录错误在断开连接后,会判断innerLogin,如果为true,会自动重连;否则,会向外传递invalidTokenloginError类型消息。

    3. 触发互踢

      触发互踢在断开连接后,会向外传递kickoff类型消息。

    4. 30s 未收到心跳

      30s 未收到心跳在断开连接后,会自动重连。

  • 插件内处理的错误码如下:

错误码说明触发服务
1002服务器维护appServ
1004/7001token 过期网关服务token 过期网关错误码为 7001,1004 错误码为 appServ 拦截处理后的错误码
8001触发敏感词敏感词服务

6. closeListener()

关闭监听

三. MTS 架构相关机制

1. 用户上线流程

用户上线流程

  1. 在创建 websocket 连接之前,首先调用updateState更新当前选中机器人 IDchosedRobot以及所有机器人 IDrobotIds,用于初始化机器人状态以及开启 chosedRobot 改变监听。

  2. 创建 websocket 连接,在接收到鉴权请求返回后,调用接口查询chosedRobot的在线状态。接口结果格式如下:

    {
        robotId: 机器人ID,
        status: 机器人状态,
        timestamp: 机器人离线秒数,
    }

    机器人状态:

    • 1 - 机器人在线

    • 2 - 机器人离线

    • 3 - 机器人状态未知(机器人从未上线过)
  3. 若机器人在线,更新全局数据中的机器人在线状态。

    若离线或未知,则向服务端发送“用户上线”信息,服务端会返回一条class=打招呼的文本消息,收到打招呼消息后,更新机器人在线状态。

  4. 由于机器人下线需一定时间,若下线未完成就发送“用户上线”,MTS 不会返回打招呼消息,为确保流程准确,需要借助timestamp字段,只有离线超过10秒才允许发送”用户上线“。所以在获取机器人状态为2的情况下,还要判断timestamp是否超过10,如未超过,需等待10-timestamp秒后发送“用户上线”。

2. 未表达机制(红绿灯机制)

为优化用户体验,增加未表达机制(红绿灯机制)

(1) 三种计时

1) 双方未表达

目的:

  • 用于触发 AI 的主动表达。

逻辑:

双方未表达

开启条件:

  1. 首次进入页面,调用“机器人在线状态接口”,如果 robot 为“在线”状态,直接开启计时;

    如果 robot 为"下线"或“未知”状态,需发送“用户上线”并收到打招呼后,再开启计时。

  2. 用户发送聊天消息后开启计时。

  3. AI 回复(展示到界面上)后开启计时。

2) 用户未表达

目的:

  • 用于确认用户是否已经离开。

逻辑:

用户未表达

开启条件:

  1. 首次进入页面,调用“机器人在线状态接口”,如果 robot 为“在线”状态,直接开启计时;

    如果 robot 为"下线"或“未知”状态,需发送“用户上线”并收到打招呼后,再开启计时。

  2. 用户发送聊天消息后开启计时。

3) 用户未回应

目的:

  • 用于追踪用户是否对 AI 的问题进行了及时的回应。

逻辑:

用户未回应

开启条件:

  1. 当 AI 回复类型为“自身疑问”或“自身祈使”时,开启该计时。

4) 综合

红绿灯机制

判断没有是的流程是因为若产生是的结果,则代表流程从左开始重新执行。

(2) 红绿灯机制流程

红绿灯机制流程

  1. 创建 websocket 连接并且收到鉴权请求返回后,调用接口查询当前选择机器人状态,如果“在线”,开启红绿灯计时;

    如果“离线”或“未知”,则在机器人上线后,开启红绿灯计时。

  2. chosedRobot改变后,先去判断全局状态中的在线信息,如果“在线”,直接开启红绿灯计时;否则和上述流程一样去调用接口查询。

  3. 当用户发送聊天消息并且发送成功后,重置红绿灯计时。

  4. 接收到聊天消息并且用户未表达没有超过 60s(如果用户未表达超过 60s,则不再重置计时,除非用户主动表达),重置双方未表达计时,同时,如果class是“自身祈使”或者“自身疑问”,开启用户未回应计时。

开启和重置只是表述上的不同,从代码逻辑上看其实是一样的。

(3) 项目使用

1) 基础使用

import aiChat from 'bm-aichat';
// trafficLightOpen控制红绿灯机制的开启/关闭,默认开启
aiChat.initConfig({
    ...,
    mts: {
        trafficLightOpen: true,
    },
});
// 插件允许项目手动控制红绿灯计时
import { startTrafficLightTimer, pauseTrafficLightTimer, playTrafficLightTimer, stopTrafficLightTimer } from 'bm-aichat';
startTrafficLightTimer();	// 开启(重置)红绿灯计时
pauseTrafficLightTimer();	// 暂停红绿灯计时
playTrafficLightTimer();	// 继续红绿灯计时
stopTrafficLightTimer();	// 停止红绿灯计时

2) 前置校验

插件默认在机器人上线后,即开启红绿灯计时。但有些时候,我们希望在一定条件下才开启红绿灯计时,就可以使用该配置:

import aiChat from 'bm-aichat';
aiChat.initConfig({
    ...,
    mts: {
        trafficLightPrecheck:()=>{
            if(条件成立){
                return true
            }else{
                return false
            }
        }
    },
});

插件会在每次开启红绿灯计时前,循环调用该方法,直至返回true

若使用该配置,为了避免阻塞,请确保条件会成立,即会有true的结果返回。

0.3.0

1 year ago

0.2.1

1 year ago

0.2.0

1 year ago

0.2.3

1 year ago

0.2.2

1 year ago

0.2.5

1 year ago

0.2.4

1 year ago

0.1.0

1 year ago

0.0.10

1 year ago

0.0.9

1 year ago

0.0.8

1 year ago

0.0.7

1 year ago

0.0.6

1 year ago

0.0.5

1 year ago

0.0.4

1 year ago

0.0.3

1 year ago

0.0.2

1 year ago

0.0.1

1 year ago