@blueking/ai-blueking
v0.2.15
Published
AI 小鲸
Downloads
468
Readme
AI 小鲸使用指南
安装
npm i @blueking/ai-blueking
通过模板字符串渲染特定 html
渲染知识库列表的模板
可以使用类似如下的模板来渲染匹配的知识库列表
<section class="knowledge-tips">
<i class="ai-blueking-icon ai-blueking-angle-up"></i>
<span class="knowledge-summary">
<i class="ai-blueking-icon ai-blueking-help-document"></i>
引用 4 篇资料作为参考
</span>
<a href="xxx" target="_blank" class="knowledge-link">
1. vivo 容器平台如何实现资源超卖方案
<i class="ai-blueking-icon ai-blueking-cc-jump-link"></i>
</a>
<a href="xxx" target="_blank" class="knowledge-link">
1. vivo 容器平台如何实现资源超卖方案
<i class="ai-blueking-icon ai-blueking-cc-jump-link"></i>
</a>
<a href="xxx" target="_blank" class="knowledge-link">
1. vivo 容器平台如何实现资源超卖方案
<i class="ai-blueking-icon ai-blueking-cc-jump-link"></i>
</a>
</section>
渲染带有点击交互的html
可以使用类似如下的模板来渲染可点击交互的 html(具有'ai-clickable'的class),点击以后会触发组件的ai-click
事件,并把 html 标签的data-ai
的数据传递出来。这样业务可以进行二次处理。比如说把data-ai
上的字符串赋值到输入框,可以使用aiRef.value?.setInputMessage(val)
来设置输入框内容。
<button data-ai="{ type: 'button', data: xxx }" class="ai-clickable">可点击的按钮</button>
<a data-ai="{ type: 'link', data: 'link url' }" class="ai-clickable" href="void">可点击的链接</a>
stream 模式
不同框架,组件引入方式不同,具体可参考下面的的例子。这里使用 vue3 项目为例,来展示 stream 模式交互:
<template>
<AIBlueking
:loading="loading"
:messages="messages"
@clear="handleClear"
@send="handleSend"
@stop="handleStop"
/>
</template>
<script lang="ts" setup>
import { ref } from 'vue';
import AIBlueking, { ChatHelper, RoleType, MessageStatus } from '@blueking/ai-blueking';
import '@blueking/ai-blueking/dist/vue3/style.css';
const loading = ref(false);
const messages = ref([]);
// 聊天开始
const handleStart = (id: number | string) => {
loading.value = true;
messages.value.push({
role: RoleType.Assistant,
content: '内容正在生成中...',
status: MessageStatus.Loading,
});
};
// 接收消息
const handleReceiveMessage = (message: string, id: number | string) => {
const currentMessage = messages.value.at(-1);
if (currentMessage.status === MessageStatus.Loading) {
// 如果是loading状态,直接覆盖
currentMessage.content = message;
currentMessage.status = MessageStatus.Success;
} else if (currentMessage.status === MessageStatus.Success) {
// 如果是后续消息,就追加消息
currentMessage.content += message;
}
};
// 聊天结束
const handleEnd = (id: number | string) => {
loading.value = false;
const currentMessage = messages.value.at(-1);
// loading 情况下终止
if (currentMessage.status === MessageStatus.Loading) {
currentMessage.content = '聊天内容已中断';
currentMessage.status = MessageStatus.Error;
}
};
// 错误处理
const handleError = (message: string, code: string | number, id: number | string) => {
if (message.includes('user authentication failed')) {
// 未登录,跳转登录
const loginUrl = new URL(process.env.BK_LOGIN_URL);
loginUrl.searchParams.append('c_url', location.origin);
window.location.href = loginUrl.href;
} else {
// 处理错误消息
const currentMessage = messages.value.at(-1);
currentMessage.status = MessageStatus.Error;
currentMessage.content = message;
loading.value = false;
}
};
const prefix = process.env.BK_API_URL_TMPL.replace('{api_name}', '<网关名>').replace('http', 'https');
const chatHelper = new ChatHelper(
`${prefix}/prod/bk_plugin/plugin_api/assistant/`,
handleStart,
handleReceiveMessage,
handleEnd,
handleError,
);
// 清空消息
const handleClear = () => {
messages.value = [];
};
// 发送消息
const handleSend = (message: string) => {
// 记录当前消息记录
const chatHistory = [...messages.value];
// 添加一条消息
messages.value.push({
role: 'user',
content: message,
});
// ai 消息,id是唯一标识当前流,调用 chatHelper.stop 的时候需要传入
chatHelper.stream(
{
inputs: {
input: message,
chat_history: chatHistory,
},
},
1,
);
};
// 暂停聊天
const handleStop = () => {
chatHelper.stop(1);
};
</script>
vue3 项目内使用(非 stream 模式)
<template>
<AIBlueking
:background="background"
:head-background="headBackground"
:loading="loading"
:messages="messages"
:position-limit="positionLimit"
:prompts="prompts"
:scroll-loading="scrollLoading"
:scroll-loading-end="scrollLoadingEnd"
:size-limit="sizeLimit"
:start-position="startPosition"
@ai-click="handleAIClick"
@choose-prompt="handleChoosePrompt"
@clear="handleClear"
@close="handleClose"
@scroll-load="handleScrollLoad"
@send="handleSend"
@stop="handleStop"
/>
</template>
<script setup lang="ts">
import { type ComponentInstance, ref } from 'vue';
import AIBlueking, { type IPrompt, type IMessage, RoleType, MessageStatus } from '@blueking/ai-blueking';
import '@blueking/ai-blueking/dist/vue3/style.css';
// 展示的消息,其中 time 可以不传
const messages = ref<IMessage[]>([
{
content: '1+1=?',
time: '2023-08-12 10:28',
role: RoleType.User,
},
{
content: '1+1=3',
time: '2024-08-07 14:29',
role: RoleType.Assistant,
status: MessageStatus.Error,
},
{
content: '不对',
time: '2024-08-12 09:29',
role: RoleType.User,
},
{
content: '1+1=2',
time: '2024-08-12 09:31',
role: RoleType.Assistant,
status: MessageStatus.Loading,
},
{
content: '对了',
time: '2024-08-13 10:20',
role: RoleType.User,
},
{
content: '好的,任务已完成',
time: '2024-08-13 10:23',
role: RoleType.Assistant,
},
]);
// 内置 prompt
const prompts = [
{
id: 1,
content: '帮我计算1+1的结果',
},
{
id: 2,
content: '帮我计算2+2的结果',
},
];
// 处理ai消息的loading状态
const loading = ref(false);
// 聊天背景色
const background = '#f5f7fa';
// 头部背景色
const headBackground = 'linear-gradient(267deg, #2dd1f4 0%, #1482ff 95%)';
// 弹框位于屏幕四边的最小距离
const positionLimit = {
top: 0,
bottom: 0,
left: 0,
right: 0,
};
// 组件最小尺寸
const sizeLimit = {
height: 320,
width: 400,
};
// 初始位置
const startPosition = {
top: window.innerHeight - 560,
bottom: 0,
left: window.innerWidth - 400,
right: 0,
};
// 向上滚动加载
const scrollLoading = ref(false);
const scrollLoadingEnd = ref(false);
// 组件实例
const aiRef = ref<ComponentInstance<typeof AIBlueking>>();
const handleClear = () => {
console.log('trigger clear');
};
const handleSend = (val: string) => {
console.log('trigger send', val);
};
const handleStop = () => {
console.log('trigger stop');
};
const handleScrollLoad = () => {
scrollLoading.value = true;
setTimeout(() => {
// 模拟异步请求
messages.value.unshift(
...[
{
content: '1+1=?',
time: '2023-08-12 9:28',
role: RoleType.User,
},
{
content: '2',
time: '2023-08-12 9:30',
role: RoleType.Assistant,
},
],
);
// 设置状态
scrollLoading.value = false;
scrollLoadingEnd.value = true;
}, 1000);
};
const handleClose = () => {
console.log('trigger close');
};
const handleChoosePrompt = (prompt: IPrompt) => {
console.log('choose prompt', prompt);
};
const handleAIClick = (val: string) => {
aiRef.value?.setInputMessage(val);
};
</script>
vue2 项目内使用(非 stream 模式)
vue2 下,需要安装 npm 包,里面是 vue3 资源
npm i @blueking/bkui-library
<template>
<AIBlueking
:background="background"
:head-background="headBackground"
:loading="loading"
:messages="messages"
:position-limit="positionLimit"
:prompts="prompts"
:size-limit="sizeLimit"
:start-position="startPosition"
@choose-prompt="handleChoosePrompt"
@clear="handleClear"
@close="handleClose"
@send="handleSend"
@scroll="handleScroll"
@stop="handleStop"
/>
</template>
<script lang="ts">
import { ref } from 'vue';
import AIBlueking from '@blueking/ai-blueking/vue2';
import '@blueking/ai-blueking/dist/vue2/style.css';
export default {
components: {
AIBlueking,
},
data() {
return {
messages: [
{
content: '你好呀',
role: 'assistant',
},
{
content: '1+1=?',
role: 'user',
},
{
content: '1+1=3',
role: 'assistant',
status: 'error',
},
{
content: '不对',
role: 'user',
},
{
content: '1+1=2',
role: 'assistant',
status: 'loading',
},
{
content: '对了',
role: 'user',
},
{
content: '好的,任务已完成',
role: 'assistant',
},
],
prompts: [
{
id: 1,
content: '帮我计算1+1的结果',
},
{
id: 2,
content: '帮我计算2+2的结果',
},
],
loading: false,
background: '#f5f7fa',
headBackground: 'linear-gradient(267deg, #2dd1f4 0%, #1482ff 95%)',
positionLimit: {
top: 0,
bottom: 0,
left: 0,
right: 0,
},
sizeLimit: {
height: 320,
width: 400,
},
startPosition: {
top: window.innerHeight - 560,
bottom: 0,
left: window.innerWidth - 400,
right: 0,
},
};
},
methods: {
handleClear() {
console.log('trigger clear');
},
handleSend(val: string) {
console.log('trigger send', val);
},
handleClose() {
console.log('trigger close');
},
handleChoosePrompt(prompt) {
console.log('choose prompt', prompt);
},
handleScroll(event: Event) {
console.log('trigger scroll', event);
},
handleStop() {
console.log('trigger stop');
},
},
};
</script>