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
初始化
初始化核心。
appendMessage(message)
手动添加消息
向currentMessages手动添加一条消息,等同于currentMessages.push。
// appendMessage: AppendMessageFunc
type AppendMessageFunc = (messageData: Message) => void
prependHistoryMsg
、appendHistoryMsg
、prependMessage
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')
}
instance
ChatUI 组件实例
等同于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
}