跳到主要内容
版本:1.11.0

Core

Core主要提供对话系统的模型、插件系统。在类型定义中,Core的数据结构类型就是ContextModel,其基于Mobx4(兼容IE)实现,下面我们将依次讲解各个部分。

插件系统

插件系统主要负责管理插件、实现插件(Plugin)与Core或其他插件之间互相调用的功能。其中插件与Core之间互相调用的方式是通过事件机制。即当一方触发一个事件时,会按注册顺序依次同步调用所有监听该事件的回调函数。

插件就是一组可复用的响应特定事件的代码块。每块代码都会通过Core提供的事件机制,监听特定事件,并通过Core中对话系统的模型提供的API和数据来实现业务功能。

例如对接LCMessager插件,其中的一个代码块就是监听“用户发送消息”事件,在该事件触发时先通过Core提供的API“appendUserMessage”添加用户消息,之后调用LC平台的消息收发接口,获取响应后再通过Core提供的API“appendReciveMessage”添加响应消息,以此实现对话功能。

代码注释说明

代码注释一般包含3块,第一块是字段名与它对应的数据类型,通常在代码块的第一行,以注释形式出现,如要描述window.document.cookie是字符串类型,则:

// window.document.cookie: string

如果描述的数据是高级类型,则需要第二块来阐明高级类型的具体定义,如描述arr是一个类型为TypeB类型的数组:

// arr: TypeB[]
// 上边这行为第一块
// 下边为第二块
type TypeB = {
foo: string
bar: string
}

如果第二块中包含更多复杂类型,则需要第三块来阐明其依赖的类型,一般以注释"// deps"开头,如描述on是一个事件监听方法,监听某个事件并挂载一个处理数据的监听器:

// on: EventStystemOn
// 上边这行为第一块
// 下边为第二块
type EventStystemOn = (eventName: string, handler: EventHandler) => void

// 下边为第三块
// deps
type EventHandler = (data: Record<string, any>) => void

pluginList

包含已经注册的插件列表。

// pluginList: Plugin[]
type Plugin = (context: ContextModel) => any

eventListeners

记录所有事件的监听函数。

// eventListeners: EventListeners
type EventListeners = Record<string, PluginHandler[]>

// deps
type PluginHandler = (context: ContextModel, payload?: PluginHandlerPayload) => (Promise<any> | any)

type PluginHandlerPayload = Record<string, any>

on

监听指定事件。当该事件被emit时,调用handler。

// on: PluginOn
type PluginOn = (eventName: string, handler: PluginHandler) => any

// deps
type PluginHandler = (context: ContextModel, payload?: PluginHandlerPayload) => (Promise<any> | any)

type PluginHandlerPayload = Record<string, any>

emit

触发指定事件。

// emit: PluginEmit
type PluginEmit = (eventName: string, payload?: PluginHandlerPayload) => void

// deps
type PluginHandlerPayload = Record<string, any>

off

注销指定事件的监听器。
如果不传handler,则清空该事件下的所有监听器; 如果传入handler,则只清空对应监听器。

// off: PluginOff
type PluginOff = (eventName: string, handler?: PluginHandler) => void

// deps
type PluginHandler = (context: ContextModel, payload?: PluginHandlerPayload) => (Promise<any> | any)

type PluginHandlerPayload = Record<string, any>

对话模型

对话模型,包含对话相关的数据和API,如历史消息列表、当前消息列表、添加消息、重置会话、界面元素渲染控制等,以及扩展功能,如自定义数据管理、i18n翻译等。

Message统一消息格式

Core接收并发送统一的消息格式。 数据详情:

  • comp是消息的渲染组件,content会被当作props传入组件。
  • hasTime为true时会展示该消息的时间,时间展示格式通过i18n中的Time.formats配置。
  • originMessage是方便记录原始消息的,部分平台返回的多条消息可能源自一条JSON。
type Message = {
_id: string
comp: string | React.ComponentClass<any, any> | React.FunctionComponent<any>
content: Record<string, any>

hasTime?: boolean
createdAt?: Moment | number
user?: UserInfo
position?: 'left' | 'right' | 'center'

originMessage?: any
}

type MessageList = Message[]

// deps
interface UserInfo {
name: string
avatar?: string
}

history历史消息列表

default:[]

// history: MessageList
type MessageList = Message[]

currentMessages当前消息列表

default:[]

// currentMessages: MessageList
type MessageList = Message[]

hasMoreHistory是否有历史消息

Default:true

type hasMoreHistory: boolean

suffixMessages后缀消息列表

后缀消息列表。可帮助实现在消息列表内展现的快捷回复。

// suffixMessages: MessageList

messages【只读计算属性】全量消息列表

依次包含history、currentMessages、suffixMessages以及isTyping消息。 注:ui.isTyping为true时,才会加入isTyping消息。

// messages: MessageList

// deps
// isTyping消息
const TYPING_ID = "TYPING_ID"
const isTypingMessage = ({
_id: TYPING_ID,
type: 'typing',
position: 'left',
comp: () => {}
}

channelOption对话渠道

记录当前的对话渠道,在转人工或对接IM时使用。 Default:PRESET_CHANNEL.LC

// channelOption: PRESET_CHANNEL
type ChannelOption = PRESET_CHANNEL.LC | PRESET_CHANNEL.HUMAN | string

inputType输入模式

记录当前用户的输入模式,如文本、音频、加号等。

Default:UserInputTypes.TEXT
// inputType: UserInputType
type UserInputType = UserInputTypes.TEXT | UserInputTypes.AUDIO | string

inputValue文本输入框的当前值

Default:''

// inputValue: string

userInfo用户信息

如果avatar为空,则会隐藏用户头像。

// userInfo: UserInfo
interface UserInfo {
name: string
avatar?: string // some.com/avatar.png
}

botUserInfo机器人信息

// botUserInfo: UserInfo
interface UserInfo {
name: string
avatar?: string // some.com/avatar.png
}

env当前运行环境

Default:"PRODUCT"

// env: "PRODUCT" | "SKETCH" | string

autoComplete输入联想

// autoComplete: Options
type Options = Option[]

type Option = TextOption | LinkOption | CustomOption

type TextOption = {
type: 'text',
content: string
}

type LinkOption = {
type: 'link',
content: string
href: string
target: '_blank' | '_parent' | '_self' | '_top' | string
}

type CustomOption = {
type: 'custom',
content: ReactNode
}

quickReplies快捷回复

快捷回复信息。一般用于引导用户回复消息。

// quickReplies: QuickReply
type QuickReply = Option & BasicQuickReplyOption

interface BasicQuickReplyOption {
isNew?: boolean
isHighlight?: boolean
}

type Option = TextOption | LinkOption | CustomOption

type TextOption = {
type: 'text',
content: string
}

type LinkOption = {
type: 'link',
content: string
href: string
target: '_blank' | '_parent' | '_self' | '_top' | string
}

type CustomOption = {
type: 'custom',
content: ReactNode
}

init初始化

初始化核心。 init

appendMessage(message)手动添加消息

向currentMessages手动添加一条消息,等同于currentMessages.push。

// appendMessage: AppendMessageFunc
type AppendMessageFunc = (messageData: Message) => void

prependHistoryMsgappendHistoryMsgprependMessage

类似appendMessage

appendUserMessage(message)添加用户消息

// appendUserMessage: AppendMessageFunc
function appendUserMessage(message) {
message.user = message.user || this.userInfo
message.type = message.type || 'custom'
message.hasTime = message.hasTime ? true : false
message.createdAt = message.createdAt || Date.now()
message.position = message.position || 'right'

this.currentMessages.push(message)
}

appendReciveMessage(message)添加接收消息

// appendReciveMessage: AppendMessageFunc
function appendReciveMessage(message) {
this.currentMessages.push({
user: this.botUserInfo,
type: 'custom',
position: 'left',

...message
})
}

changeChannel(channel)变更对话渠道

变更对话渠道。一般用于转人工。

// changeChannel: ChangeChannel
type ChangeChannel = (channel: ChannelOption) => void

changeChannel(channel) {
const legacyChannel = this.channelOption
this.channelOption = channel

this.emit('changeChannel', { pre: legacyChannel, current: channel })
}

resetConversition()重置会话信息

// resetConversition: () => void
function resetConversition() {
this.history = []
this.currentMessages = []
this.autoComplete = []
this.quickReplies = []
this.inputValue = ''

this.emit('resetConversition')
}

instanceChatUI 组件实例

等同于ChatUI的messagesRef。

// instance: React.ReactNode

composerRef输入框组件实例

等同于ChatUI的composerRef。

// composerRef?: React.RefObject<ComposerHandle>

自定义数据管理

用于不同插件间共享数据或信息,或插件自己存储使用。

sessionData自定义数据

// sessionData: Record<string, any>

setSessionData(key, value)设定自定义数据

// setSessionData: (key: string, value: any) => void

getSessionData(key)读取自定义数据

// getSessionData: (key: string) => any

removeSessionData(key)删除自定义数据

// removeSessionData: (key: string) => any

i18n

locale当前语言

当前语言。locales应包含值为locale的key。

// locale: string

locales多语言配置信息

Default:

{
'zh-CN': {
'input.placeholder': '请输入您想咨询的问题~',
loadmore: "加载历史消息",
download: '下载',
'testbot.relevant': '猜你想问',
Time: {
weekdays: '星期日_星期一_星期二_星期三_星期四_星期五_星期六'.split('_'),
formats: {
LT: 'YYYY-M-D HH:mm', // 00:32
lll: 'YYYY-M-D HH:mm', // 2019年2月22日 00:28
WT: 'YYYY-M-D HH:mm', // 星期一 00:32
YT: 'YYYY-M-D HH:mm', // 昨天 00:32
},
},
Composer: {
send: '发送',
},
}
}

类型定义:

// locales: Locales
type Locales = Record<string, LocaleDetail>

// deps
type LocaleDetail = Record<string, LocaleItem>
type LocaleItem = string | string[] | LocaleItemObj

trans(key)翻译i18n

翻译i18n,key将按“.” 分割,并在“locales[locale]”中查询。

// example
const model = {
// ... other data
locale: 'en-US',
locales: {
"en-US": {
"common": {
"hello": "hello world!"
}
}
}
}

model.trans('common.hello') // "hello world"

Core中触发事件的列表

beforeInitial

  • 触发时机:init过程中,加载config和插件前
  • payload:传入的config

didInitial

  • 触发时机:init过程中,加载config和插件后
  • payload:传入的config

changeChannel

  • 触发时机:调用changeChannel方法后
  • payload:
    {
    pre: legacyChannel,
    current: channel
    }

resetConversition

  • 触发时机:调用resetConversition方法后
  • payload:-

localeChange

  • 触发时机:变更locale后
  • payload:
    {
    locale: newLocale
    }

log

  • 触发时机:任何事件被触发后都会生成一条log事件
    {
    eventName: string,
    payload: any
    }