通过 VANILLA JS SDK 集成
vanilla js sdk 提供的 UI、功能与 iframe 集成类似,直接使用衡石 ChatBI 的对话组件、样式和功能,只需要在你的 HTML 文件中(或 Vue/React 组件中)引入 AI 助手的 JS 文件,并调用相关 API。这将需要您拥有一定的 JavaScript 开发经验。
快速上手
- 获取 js sdk 链接
进入衡石系统内设置->功能配置->智能查数助手->控制台
页面,点击选项->使用 SDK 嵌入
打开集成页面指南,在抽屉弹窗中,您将找到用于集成的 SDK 链接,例如
https://develop.hengshi.org/assets/hengshi-copilot@<version>.js
注意
@<version>
是 SDK 的版本号,请确保您使用的 SDK 版本与您的系统版本一致。系统升级时也需要更新。
- 引入 js sdk
我们提供了在 vue、react、纯 js 等前端框架中集成 SDK 的示例代码,您可以根据需要进行选择,这要求您需要有一定的前端开发经验。
js
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>AI助手</title>
<script type="text/javascript" src="https://develop.hengshi.org/assets/hengshi-copilot@<version>.js" defer></script>
</head>
<body>
<!-- 在你的项目中合适的位置增加按钮 -->
<button id="trigger-ai">唤起AI助手</button>
<!-- 在你的项目中合适的位置增加 sdk 所需容器 -->
<div id="copilot-root" style="display: none;"></div>
<script>
const copilotConfig = { // 定义 AI 助手配置
locale: 'zh-CN',
draggable: {
enable: true,
minWidth: 440,
minHeight: 440,
position: {
x: window.innerWidth - 480,
y: 20,
},
size: {
width: 440,
height: window.innerHeight * 0.8,
},
onDragStop: onDragStop,
onResize: onResize,
},
userConfig: {
dataAppId: 130870,
datasetId: 1,
},
};
let copilotInstance = null;
const button = document.getElementById('trigger-ai');
const copilotRoot = document.getElementById('copilot-root');
button.addEventListener('click', toggleCopilot);
function onDragStop(event, position) {
copilotConfig.draggable.position = position;
}
function onResize(event, position, size) {
copilotConfig.draggable.position = position;
copilotConfig.draggable.size = size;
}
function launchCopilot() {
if (typeof Copilot === 'undefined') {
(function(fn) {
fn(launchCopilot);
})(requestIdleCallback || setTimeout);
} else {
if (!copilotInstance) {
copilotInstance = new Copilot(copilotRoot, copilotConfig);
copilotRoot.style.display = 'block';
button.textContent = '关闭AI助手';
}
}
}
function destroyCopilot() {
if (copilotInstance) {
copilotInstance.destroy();
copilotInstance = null;
copilotRoot.style.display = 'none';
button.textContent = '唤起AI助手';
}
}
function toggleCopilot() {
if (copilotInstance) {
destroyCopilot();
} else {
launchCopilot();
}
}
</script>
</body>
</html>
jsx
import React, { useState, useEffect } from 'react';
const CopilotComponent = () => {
const [copilotInstance, setCopilotInstance] = useState(null);
const [buttonLabel, setButtonLabel] = useState('唤起AI助手');
const copilotConfig = {
locale: 'zh-CN',
draggable: {
enable: true,
minWidth: 440,
minHeight: 440,
position: {
x: window.innerWidth - 480,
y: 20,
},
size: {
width: 440,
height: window.innerHeight * 0.8,
},
onDragStop: onDragStop,
onResize: onResize,
},
userConfig: {
dataAppId: 130870,
datasetId: 1,
},
};
useEffect(() => {
// 加载 SDK
const script = document.createElement('script');
script.src = 'https://develop.hengshi.org/assets/hengshi-copilot@<version>.js';
script.async = true;
document.body.appendChild(script);
return () => {
document.body.removeChild(script); // 清理加载的脚本
};
}, []);
function onDragStop(event, position) {
copilotConfig.draggable.position = position;
}
function onResize(event, position, size) {
copilotConfig.draggable.position = position;
copilotConfig.draggable.size = size;
}
const launchCopilot = () => {
if (typeof Copilot === 'undefined') {
(function(fn) {
fn(launchCopilot);
})(requestIdleCallback || setTimeout);
} else {
if (!copilotInstance) {
const copilotRoot = document.getElementById('copilot-root');
const instance = new Copilot(copilotRoot, copilotConfig);
setCopilotInstance(instance);
setButtonLabel('关闭AI助手');
}
}
};
const destroyCopilot = () => {
if (copilotInstance) {
copilotInstance.destroy();
setCopilotInstance(null);
setButtonLabel('唤起AI助手');
}
};
const toggleCopilot = () => {
if (copilotInstance) {
destroyCopilot();
} else {
launchCopilot();
}
};
return (
<div>
<button onClick={toggleCopilot}>{buttonLabel}</button>
{copilotInstance && <div id="copilot-root"></div>}
</div>
);
};
export default CopilotComponent;
vue
<template>
<div>
<button @click="toggleCopilot">{{ buttonLabel }}</button>
<div id="copilot-root" v-if="copilotInstance"></div>
</div>
</template>
<script>
import { ref, onMounted, onBeforeUnmount } from 'vue';
export default {
setup() {
const copilotInstance = ref(null);
const buttonLabel = ref('唤起AI助手');
const copilotConfig = {
locale: 'zh-CN',
draggable: {
enable: true,
minWidth: 440,
minHeight: 440,
position: {
x: window.innerWidth - 480,
y: 20,
},
size: {
width: 440,
height: window.innerHeight * 0.8,
},
onDragStop: onDragStop,
onResize: onResize,
},
userConfig: {
dataAppId: 130870,
datasetId: 1,
},
};
function onDragStop(event, position) {
copilotConfig.draggable.position = position;
}
function onResize(event, position, size) {
copilotConfig.draggable.position = position;
copilotConfig.draggable.size = size;
}
function launchCopilot() {
if (typeof Copilot === 'undefined') {
(function(fn) {
fn(launchCopilot);
})(requestIdleCallback || setTimeout);
} else {
if (!copilotInstance.value) {
copilotInstance.value = new Copilot(document.getElementById('copilot-root'), copilotConfig);
buttonLabel.value = '关闭AI助手';
}
}
}
function destroyCopilot() {
if (copilotInstance.value) {
copilotInstance.value.destroy();
copilotInstance.value = null;
buttonLabel.value = '唤起AI助手';
}
}
function toggleCopilot() {
if (copilotInstance.value) {
destroyCopilot();
} else {
launchCopilot();
}
}
return {
copilotInstance,
buttonLabel,
toggleCopilot,
};
},
};
</script>
<style>
/* 添加样式(如果需要) */
</style>
- 启动/打开你的项目,检查是否成功集成。
JS SDK 实例
new Copilot(...) 的结果是一个 copilot 实例,你可以通过这个实例来操作 Copilot。
js
{
copilotConfig: {
config: {...}, // 大模型配置信息
loading: false, // 是否正在加载
onVerifyConfig: () => {}, // 验证配置信息
onChangeProvider: () => {}, // 切换模型提供商
// ...
},
context: {
api: {...},
endpoints: {...},
// Copilot 状态
isLoading: false,
// 当前会话列表,数据格式参照
// https://api.hengshi.com/conversation.html#conversation
conversations: [],
setConversations: () => {},
currentConversationId: null,
setCurrentConversationId: () => {},
runningChatUid: null,
setRunningChatUid: () => {},
setChat: (id, chatUid, chat) => {},
// 获取历史对话列表
onFetchConversations: (offset = 0, limit = 10) => {},
// 创建对话
onCreateConversation: prompt => {},
onFetchConversation: id => {},
onClearConversations: () => {},
onFetchPreviousConversations: () => {},
// 创建问答
onCreateChat: body => {},
onDeleteChat: (id, chatUid) => {},
onFetchSuggestions: refresh => {},
onFetchFavorites: () => {},
onCancelChatFavorite: (id, chatUid) => {},
},
}
2. 通过 JS 调用 HTTP API
在上述 copilot 实例中,api
对象中提供了所有 HTTP API 的调用方法,你可以通过调用这些方法来与后端进行交互,如:
js
// 1. 创建对话
const { body: { data: conversation }} = await copilot.api.requestCreateConversation({
body: {
title: '这里是本次对话的标题',
},
}).value;
/**
conversation = {
"id": 135,
"title": "这里是本次对话的标题",
"createdBy": 268,
"createdAt": "2024-09-14 15:47:23",
"updatedBy": 268,
"updatedAt": "2024-09-14 15:47:23"
}
*/
// 2. 创建问答
const { body: { data: chat }} = await copilot.api.requestCreateChat({
id: conversation.id,
body: {
prompt: '哪个导演拍的电影票房最高', // 这里是用户的问题
userConfig: { // 参照上述 copilotConfig 中的 userConfig
dataAppId: 129150,
datasetId: 1,
}
},
qs: {
sync: true, // 是否同步执行
timeout: 1000 * 60, // 超时时间,单位为毫秒
},
}).value;
/**
chat = {
"conversationId": 135,
"prompt": "哪个导演拍的电影票房最高",
"answer": "克里斯托弗·诺兰导演拍的电影票房最高。",
"model": "gpt-4o",
"uid": "08ff93ca-1972-4916-b884-35fab6f91c64",
"temperature": 0,
"createdBy": 268,
"createdAt": "2024-09-14 15:47:23",
"updatedBy": 268,
"updatedAt": "2024-09-14 15:47:23",
"responseAt": "2024-09-14 15:47:30",
"isDelete": false,
"isContextEnd": false,
"suggestQuestions": [],
"statusList": [
"PENDING",
"ANALYZE_REQUEST",
"HQL_SELECT_FIELDS",
"HQL_SELECT_FUNCTIONS",
"GENERATE_HQL_QUERY",
"DOING_HQL_QUERY",
"DOING_SUMMARY",
"DOING_QUESTION_SUGGESTING",
"DONE"
],
"userConfig": {
"datasetId": 1,
"dataAppId": 129150
},
"autoConfig": {
"agentType": "HQL_AGENT"
},
"isCurrent": true,
"usage": [
{
"completion_tokens": 24,
"prompt_tokens": 4063,
"total_tokens": 4087
},
{
"completion_tokens": 5,
"prompt_tokens": 1424,
"total_tokens": 1429
},
{
"completion_tokens": 49,
"prompt_tokens": 3906,
"total_tokens": 3955
},
{
"completion_tokens": 16,
"prompt_tokens": 299,
"total_tokens": 315
}
],
"chartCreatedAt": "2024-09-14 15:47:30",
"refineQuestion": "哪个导演拍的电影票房最高",
"favorite": false,
"charts": [
{
"appId": 129150,
"datasetId": 1,
"options": {
"axes": [
{
"op": "{{1}}.{director}",
"uid": "uid1",
"fieldName": "director",
"kind": "formula",
"datasetId": 1,
"labelOrigin": "director",
"label": "director",
"isAggregate": false,
"value": "{{coffe_产品表}}.{director}",
"dataset": 1,
"fieldType": "string"
},
{
"op": "max({{1}}.{votes})",
"uid": "uid2",
"fieldName": "votes",
"kind": "formula",
"datasetId": 1,
"labelOrigin": "votes",
"label": "votes",
"isAggregate": true,
"value": "max({{coffe_产品表}}.{votes})",
"dataset": 1,
"fieldType": "number"
}
],
"name": "Bar",
"limit": 1,
"sort": [
{
"op": "uid2",
"kind": "reference",
"direction": "desc"
},
{
"op": "uid1",
"kind": "reference",
"direction": "asc"
}
]
},
"dataAppId": 129150,
"datasetIds": [
1
]
}
]
}
*/
在衡石系统内的仪表盘里集成 Copilot
在衡石系统中调用 Copilot 方式与上述 HTML 方式是类似的。
首先,在全局 JS 文件中通过代码加载 Copilot SDK:
js
// 1. 保持 copilot sdk 与系统的 store 数据同步
window.__INITIAL_STATE__ = window._hs_store_.getState();
// 2. 引入 copilot sdk 代码
var script = document.createElement('script');
script.src = 'https://develop.hengshi.org/assets/hengshi-copilot@<version>.js';
script.async = true;
script.onload = function() {
// 3. 重置 sdk base url
window.__hs_sdk_base_url__ = undefined;
// 4. 创建 sdk 容器
var copilotRoot = document.createElement('div');
copilotRoot.id = 'copilot-root';
copilotRoot.style.width = '100%';
copilotRoot.style.height = '100%';
copilotRoot.style.position = 'fixed';
copilotRoot.style.inset = '0';
copilotRoot.style.zIndex = '9999';
copilotRoot.style.pointerEvents = 'none';
document.body.appendChild(copilotRoot);
// 5. 赋值给自定义 sandbox 变量以便自定义 js 能使用
window.myJS = window.myJS || {};
window.myJS.innerWidth = window.innerWidth;
window.myJS.innerHeight = window.innerHeight;
window.myJS.Copilot = Copilot;
window.myJS.CopilotRoot = copilotRoot;
};
document.body.appendChild(script);
然后,您可以在仪表盘中使用控件按钮来唤起 Copilot,在按钮控件的设置中添加点击事件,执行相应的 JS 代码。
js
if (!myJS) {
throw new Error('hengshi copilot sdk not loaded yet');
}
if (!myJS.copilotConfig) {
var stylesheet = `html.hengshi-copilot-sdk, html.hengshi-copilot-sdk body {width:100% !important; height: 100% !important;}
html.hengshi-copilot-sdk body.hst {background: transparent;}
.react-draggable {pointer-events: all;}`;
myJS.copilotConfig = {
locale: 'zh-CN',
stylesheet: stylesheet,
closable: true, // 设置对话框可关闭
draggable: { // 设置对话框拖动功能,不需要拖动功能可以设置为 false 或不设置
enable: true,
minWidth: 440,
minHeight: 440,
position: {
x: myJS.innerWidth - 480,
y: 20,
},
size: {
width: 440,
height: myJS.innerHeight * 0.8,
},
// 设定记住拖动的位置和大小
onDragStop: onDragStop,
onResize: onResize,
},
// 设置对话数据来源
userConfig: {
dataAppId: 354, // 数据包 id
datasetId: 26, // 数据集 id
},
};
}
function onDragStop(event, position) {
myJS.copilotConfig.draggable.position = position;
}
function onResize(event, position, size) {
myJS.copilotConfig.draggable.position = position;
myJS.copilotConfig.draggable.size = size;
}
function launchCopilot() {
if (typeof myJS.Copilot === 'undefined') {
(function (fn) {
fn(launchCopilot);
})(requestIdleCallback || setTimeout);
} else {
myJS.copilot = new myJS.Copilot(myJS.CopilotRoot, myJS.copilotConfig);
}
}
if (myJS.copilot) {
myJS.copilot.destroy();
myJS.copilot = null;
} else {
launchCopilot();
}