Composables API
Vue 3 组合式 API 封装库提供了一系列 composables,让你可以轻松地在 Vue 组件中使用 AaaS Pilot Kit 功能。
核心 Composables
useAaaSPilotKit
提供控制器实例及提供者内部维护的响应式状态。
function useAaaSPilotKit<AS extends BaseAgentService = BaseAgentService>(): {
controller: Readonly<ShallowRef<ReturnType<typeof createAaaSPilotKit<AS>> | null>>;
isReady: Readonly<Ref<boolean>>;
isMuted: Readonly<Ref<boolean>>;
isRendering: Readonly<Ref<boolean>>;
create: () => void;
dispose: () => void;
}
返回值
| 属性 | 类型 | 描述 |
|---|---|---|
controller | ShallowRef<Controller | null> | 控制器实例,可能为 null |
isReady | Ref<boolean> | 数字员工是否已就绪 |
isMuted | Ref<boolean> | 是否处于静音状态 |
isRendering | Ref<boolean> | 是否正在播报 |
create | () => void | 手动创建控制器实例 |
dispose | () => void | 手动销毁控制器实例 |
使用示例
<template>
<div>
<div v-if="!isReady">初始化中...</div>
<div v-else>
<button
@click="sendMessage"
:disabled="isRendering"
>
{{isRendering ? '播报中' : '未播报'}}
</button>
<button @click="toggleMute">
{{isMuted ? '取消静音' : '静音'}}
</button>
</div>
</div>
</template>
<script setup lang="ts">
import {computed} from 'vue';
import {useAaaSPilotKit} from '@bdky/aaas-pilot-kit-vue3';
const {controller, isReady, isMuted, isRendering} = useAaaSPilotKit();
const canSendMessage = computed(() => {
return isReady.value && controller.value !== null;
});
const sendMessage = () => {
if (canSendMessage.value) {
controller.value!.input('你好');
}
};
const toggleMute = () => {
if (controller.value) {
controller.value.mute(!isMuted.value);
}
};
</script>
注意事项
- 必须在
provideAaaSPilotKit注入范围内调用 controller.value可能为null,请在调用方法前判空create/dispose可用于手动控制生命周期,例如重置会话- 返回的状态均为只读响应式引用
useAaaSPilotKitEvents
将 Vue 组件的回调函数与底层事件总线绑定。
function useAaaSPilotKitEvents(props: IUseAaaSPilotKitEventsProps): void
支持的事件
受支持的事件与 IAaaSPilotKitEmitter 对齐:
| 事件名 | 回调参数 | 描述 |
|---|---|---|
onReady | () => void | 数字员工就绪 |
onAsrStart | () => void | 语音识别开始 |
onAsrMessage | (payload) => void | 语音识别结果 |
onMicrophoneAvailable | (result) => void | 麦克风设备可用性检测结果 |
onRenderStart | (payload) => void | 开始渲染 |
onInactivity | (payload) => void | 非活跃状态 |
onBusy | (payload) => void | 忙碌状态 |
onInterrupt | (payload) => void | 中断事件 |
onConversationChange | (payload) => void | 对话变更 |
onIsRenderingChange | (payload) => void | 播报状态变更 |
onReplyStart | (payload) => void | 数字员工开始播报 |
onTtft | (payload) => void | Agent首字延迟性能指标 |
onMicrophoneAvailable 详解
🎙️ 麦克风设备可用性检测结果事件。
触发时机:
- 手动调用
controller.checkAudioDevice()时 - ASR 启动前自动检测(需配置
checkAudioDeviceBeforeStart: true)
回调参数类型:
interface MicrophoneAvailableResult {
available: boolean; // 设备是否可用
error?: AudioDeviceError; // 错误类型(仅当 available=false 时)
userMessage?: string; // 用户友好的错误提示文案
devices?: MediaDeviceInfo[]; // 检测到的音频设备列表
permissionState?: PermissionState; // 权限状态
}
使用示例:
<script setup lang="ts">
import { ref } from 'vue';
import { useAaaSPilotKitEvents } from '@baidu/ky-employee-embed-widget-vue';
const deviceStatus = ref<string>('');
const showAlert = ref(false);
useAaaSPilotKitEvents({
onMicrophoneAvailable: (result) => {
if (!result.available) {
// 设备不可用,显示错误提示
deviceStatus.value = result.userMessage || '设备不可用';
showAlert.value = true;
} else {
// 设备可用
deviceStatus.value = '设备正常';
showAlert.value = false;
}
}
});
</script>
<template>
<div v-if="showAlert" class="alert alert-error">
<p>{{ deviceStatus }}</p>
<button @click="showAlert = false">知道了</button>
</div>
</template>
详细说明: 参见 Vanilla JS Events - microphone_available
使用示例
<script setup lang="ts">
import {ref} from 'vue';
import {useAaaSPilotKitEvents} from '@bdky/aaas-pilot-kit-vue3';
const asrResults = ref<string[]>([]);
const isListening = ref(false);
useAaaSPilotKitEvents({
onReady: () => {
console.log('数字员工已就绪');
},
onAsrStart: () => {
isListening.value = true;
},
onAsrMessage: (payload) => {
asrResults.value.push(payload.text);
console.log('ASR结果:', payload.text);
},
onRenderStart: (payload) => {
console.log('开始播报:', payload);
},
onConversationChange: (payload) => {
console.log('对话内容变更:', payload);
}
});
</script>
内部使用 watch 监听控制器变化,支持在组件生命周期内动态更新处理函数。
useConversationList
监听控制器的 conversation_add 事件,维护本地对话列表。
function useConversationList(): {
conversationList: Ref<AnyConversation[]>;
}
使用示例
<template>
<div>
<div>对话总数:{{conversationList.length}}</div>
<ConversationItem
v-for="conversation in conversationList"
:key="conversation.id || conversation.type"
:conversation="conversation"
/>
</div>
</template>
<script setup lang="ts">
import {useConversationList} from '@bdky/aaas-pilot-kit-vue3';
const {conversationList} = useConversationList();
</script>
特性
- 初始值为空数组
- 新对话到来时自动 push 到列表末尾
- 可与
useConversation组合渲染多个对话流 - 返回响应式引用,支持模板直接绑定
useConversation
将单个 AnyConversation 的内容流式转换为可直接渲染的响应式列表。
function useConversation(conversation: Ref<AnyConversation | undefined>): {
conversationContents: Ref<(NAIWorkerConversationBean.IContentChangePayload & {uiId: string})[]>;
}
行为说明
AIWorkerConversationBean:逐步追加内容,连续同类型 (mod) 片段会合并- 客户端对话:将最新内容替换到列表末尾
- 所有内容项自动注入
uiId,便于 Vuev-for的key使用 - 返回响应式引用,支持模板直接绑定
使用示例
<template>
<div class="conversation">
<div
v-for="item in conversationContents"
:key="item.uiId"
:class="['message', item.mod]"
>
<div class="message-header">
<strong>{{item.mod}}</strong>
<span :class="['status', {completed: item.completed}]">
{{item.completed ? '完成' : '进行中'}}
</span>
</div>
<div class="message-content">{{item.content}}</div>
</div>
</div>
</template>
<script setup lang="ts">
import {toRef} from 'vue';
import {useConversation} from '@bdky/aaas-pilot-kit-vue3';
import type {AnyConversation} from '@bdky/aaas-pilot-kit';
const props = defineProps<{
conversation: AnyConversation | undefined;
}>();
const conversation = toRef(props, 'conversation');
const {conversationContents} = useConversation(conversation);
</script>
<style scoped>
.conversation {
max-height: 400px;
overflow-y: auto;
}
.message {
margin-bottom: 12px;
padding: 8px;
border-radius: 8px;
}
.message.user {
background-color: #e3f2fd;
}
.message.assistant {
background-color: #f5f5f5;
}
.message-header {
display: flex;
justify-content: space-between;
margin-bottom: 4px;
}
.status.completed {
color: #4caf50;
}
</style>
useConversationEnd
监听 AIWorkerConversationBean 的 conversation_end 事件。
function useConversationEnd(
conversation: Ref<AnyConversation | undefined>,
onConversationEnd?: (payload: NAIWorkerConversationBean.IConversationEndPayload) => void
): void
参数
| 参数 | 类型 | 说明 |
|---|---|---|
conversation | Ref<AnyConversation | undefined> | 对话实例的响应式引用(仅 AIWorkerConversationBean 会触发回调) |
onConversationEnd | (payload) => void | 对话完成时的回调函数 |
Payload 类型
interface IConversationEndPayload {
id: string;
text: string;
contents: IContent[];
timestamp: number;
}
使用示例
<script setup lang="ts">
import {useConversationEnd} from '@bdky/aaas-pilot-kit-vue3';
import {toRef} from 'vue';
import type {AnyConversation} from '@bdky/aaas-pilot-kit';
const props = defineProps<{conversation: AnyConversation}>();
const conversationRef = toRef(props, 'conversation');
useConversationEnd(
conversationRef,
payload => {
console.log('Conversation ended:', payload.text);
console.log('Contents:', payload.contents.length);
}
);
</script>
底层 Composables
useAaaSPilotKitProvider
底层提供者实现,返回响应式的控制器和状态。通常通过 provideAaaSPilotKit 调用。
function useAaaSPilotKitProvider<AS extends BaseAgentService = BaseAgentService>(
options: IOptions<AS>
): IAaaSPilotKitProvider<AS>
injectAaaSPilotKit
底层依赖注入函数。如果需要与非 Vue 代码打通或自行实现 composables,可直接使用。
const provider = injectAaaSPilotKit();
if (!provider) {
throw new Error('AaaSPilotKit 未注入提供者');
}
组合使用示例
完整的聊天应用
App.vue - 父组件(提供 Provider)
<template>
<div class="app">
<PilotApp />
</div>
</template>
<script setup lang="ts">
import {provideAaaSPilotKit} from '@bdky/aaas-pilot-kit-vue3';
import PilotApp from './PilotApp.vue';
provideAaaSPilotKit({
token: 'your-auth-token-here',
figureId: '209337',
ttsPer: 'LITE_audiobook_female_1',
// agentConfig: 若未提供自定义 agentService,此配置必填
agentConfig: {
token: 'your-token',
robotId: 'your-robot-id'
}
});
</script>
PilotApp.vue
<template>
<div class="chat-app">
<div class="status-bar">
<div>状态:{{isReady ? '就绪' : '初始化中'}}</div>
<div>{{isRendering ? '播报中' : '空闲'}}</div>
</div>
<div class="conversation-list">
<ConversationComponent
v-for="conversation in conversationList"
:key="conversation.id || conversation.type"
:conversation="conversation"
/>
</div>
<div class="input-area">
<input
v-model="inputText"
@keyup.enter="sendMessage"
:disabled="!canSend"
placeholder="输入消息..."
/>
<button @click="sendMessage" :disabled="!canSend">
发送
</button>
</div>
</div>
</template>
<script setup lang="ts">
import {ref, computed} from 'vue';
import {
useAaaSPilotKit,
useAaaSPilotKitEvents,
useConversationList
} from '@bdky/aaas-pilot-kit-vue3';
const {controller, isReady, isRendering} = useAaaSPilotKit();
const {conversationList} = useConversationList();
const inputText = ref('');
const canSend = computed(() => {
return isReady.value && !isRendering.value && inputText.value.trim();
});
const sendMessage = () => {
if (canSend.value && controller.value) {
controller.value.input(inputText.value);
inputText.value = '';
}
};
useAaaSPilotKitEvents({
onReady: () => console.log('聊天已就绪'),
onAsrMessage: (payload) => console.log('语音输入:', payload.text),
onError: (error) => console.error('发生错误:', error)
});
</script>
类型定义
库内导出的主要类型:
// Provider 相关
export interface IAaaSPilotKitProvider<AS extends BaseAgentService = BaseAgentService>
export const AaaSPilotKitProviderKey: InjectionKey<IAaaSPilotKitProvider>
// Composables 返回值
export interface IUseAaaSPilotKitResult<AS extends BaseAgentService = BaseAgentService>
export interface IUseAaaSPilotKitEventsProps
export interface IUseConversationResult
export interface IUseConversationListResult