AI Assistant Integration Guide
This document will guide you through a few simple steps to integrate or embed the AI Assistant into your system. HENGSHI SENSE AI Assistant offers multiple integration methods, allowing you to embed the AI Assistant into your system via iframe, JS SDK, or API calls.
1. Integration via iframe
The iframe integration method is the simplest. You only need to add an iframe element in your HTML file (or Vue/React component) and set its src
attribute to the URL of the AI Assistant.
<iframe
src="https://develop.hengshi.org/copilot"
width="100%"
height="100%">
</iframe>
URL Query String Parameters
We provide some optional URL parameters that you can adjust as needed.
Data Source
You can specify the data source for the AI Assistant conversation in the following ways:
- Conversation with the data source of the chart
?appId={App ID}&chartId={Chart ID}
- Conversation with the data model of the data package
?dataAppId={Data Package ID}&datasetId={Dataset ID}
Theme Color
You can specify the theme color for the charts within the AI Assistant conversation:
?chartTheme={Dashboard Theme ID}
The Dashboard Theme ID can be found in the theme dropdown menu when editing the dashboard in your application creation area, as shown below:
Display Specific Conversations
We also provide conversationId
and chatUid
parameters, which allow multiple values separated by commas to specify displaying only specific conversations. These two parameters can be used individually or in combination.
?conversationId={Conversation ID1,Conversation ID2}&chatUid={uid1,uid2}
Login Authentication
If you need to integrate in other systems, you may need to perform login authentication, which can be done by passing login information via the jwt
parameter:
?activeAuth=jwt-param&jwtParam={JWT Parameter}
2. Integration via JS SDK
The JS SDK integration method requires you to include the AI Assistant's JS file in your HTML file (or Vue/React component) and call the relevant API. This will require you to have some JavaScript development experience.
Obtain Copilot SDK Link
You can go to the Settings -> Feature Configuration -> AI Assistant -> Console
page within the system, click Options -> Copilot SDK
to open the integration page guide. In the drawer popup, you will find the SDK link for integration, for example:
https://develop.hengshi.org/assets/hengshi-copilot@5.3.js
Integrate Copilot SDK in Other Systems
We provide example code for integrating Copilot SDK in front-end frameworks such as Vue, React, and pure JS. You can choose according to your needs. This requires you to have some front-end development experience.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>AI Assistant</title>
<script type="text/javascript" src="https://develop.hengshi.org/assets/hengshi-copilot@5.3-SNAPSHOT.js" defer></script>
<style>
/* Add styles if needed */
</style>
</head>
<body>
<button id="trigger-ai">Trigger AI Assistant</button>
<div id="copilot-root" style="display: none;"></div>
<script>
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,
},
};
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 = 'Close AI Assistant';
}
}
}
function destroyCopilot() {
if (copilotInstance) {
copilotInstance.destroy();
copilotInstance = null;
copilotRoot.style.display = 'none';
button.textContent = 'Trigger AI Assistant';
}
}
function toggleCopilot() {
if (copilotInstance) {
destroyCopilot();
} else {
launchCopilot();
}
}
</script>
</body>
</html>
import React, { useState, useEffect } from 'react';
const CopilotComponent = () => {
const [copilotInstance, setCopilotInstance] = useState(null);
const [buttonLabel, setButtonLabel] = useState('Trigger AI Assistant');
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(() => {
// Load SDK
const script = document.createElement('script');
script.src = 'https://develop.hengshi.org/assets/hengshi-copilot@5.3-SNAPSHOT.js';
script.async = true;
document.body.appendChild(script);
return () => {
document.body.removeChild(script); // Clean up loaded 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('Close AI Assistant');
}
}
};
const destroyCopilot = () => {
if (copilotInstance) {
copilotInstance.destroy();
setCopilotInstance(null);
setButtonLabel('Trigger AI Assistant');
}
};
const toggleCopilot = () => {
if (copilotInstance) {
destroyCopilot();
} else {
launchCopilot();
}
};
return (
<div>
<button onClick={toggleCopilot}>{buttonLabel}</button>
{copilotInstance && <div id="copilot-root"></div>}
</div>
);
};
export default CopilotComponent;
<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>
Authentication
When integrating the SDK, you may need to perform authentication. We provide two methods:
- SSO Single Sign-On: If your system is already integrated with HENGSHI SENSE, no additional login is required.
- JWT Authentication: Use JWT for login authentication with the following code:
fetch('https://develop.hengshi.org/api/auth/login-info?activeAuth=jwt-param&jwtParam=your JWT parameter')
.then(response => {
// Login successful, continue using the SDK
})
.catch(error => {
// Login failed, handle the error
});
Tip
Ensure that you have configured JWT in 'Settings -> Organization Management -> Authentication Method -> JWT Request Parameters'.
Replace 'your JWT parameter' with the actual JWT parameter.
Integrating Copilot in Dashboards within HENGSHI SENSE
Calling Copilot in HENGSHI SENSE is similar to the HTML method described above.
First, load the Copilot SDK in the global JS file via code:
// 1. Keep copilot sdk in sync with the system's store data
window.__INITIAL_STATE__ = window._hs_store_.getState();
// 2. Import copilot sdk code
var script = document.createElement('script');
script.src = 'https://develop.hengshi.org/assets/hengshi-copilot@5.3-SNAPSHOT.js';
script.async = true;
script.onload = function() {
// 3. Reset sdk base url
window.__hs_sdk_base_url__ = undefined;
// 4. Create sdk container
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. Assign to custom sandbox variable for custom js usage
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);
Then, you can use Control Buttons in the dashboard to invoke Copilot, adding a click event in the button control settings to execute the corresponding JS code.
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, // Set dialog closable
draggable: { // Set dialog draggable, can be set to false or not set if not needed
enable: true,
minWidth: 440,
minHeight: 440,
position: {
x: myJS.innerWidth - 480,
y: 20,
},
size: {
width: 440,
height: myJS.innerHeight * 0.8,
},
// Remember drag position and size
onDragStop: onDragStop,
onResize: onResize,
},
// Set dialog data source
userConfig: {
dataAppId: 354, // Data package id
datasetId: 26, // Dataset 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();
}
Copilot Configuration Options
You can adjust the configuration options as needed:
// Copilot configuration definition
interface ICopilotConfig {
userConfig: {
appId: number;
chartId?: number;
dataAppId: number;
datasetId?: number;
};
closable?: boolean;
draggable?: boolean | {
enable: boolean;
minWidth: number;
minHeight: number;
bounds: 'window' | 'parent';
position: {
x: number;
y: number;
};
size: {
width: number;
height: number;
};
};
locale?: string;
stylesheet?: string;
className?: string;
style?: React.CSSProperties;
bodyClassName?: string;
bodyStyle?: React.CSSProperties;
header?: string | React.ReactElement;
systemMsg?: string;
parser?: {
selectText: string;
onSelect: (chart: any) => void;
};
chartTheme?: string | Theme;
}
interface Theme {
base?: string | number;
background?: string;
color?: string;
fontSize?: number;
fontFamily?: any;
fontWeight?: string;
textAlign?: string;
borderColor?: string;
borderWidth?: number;
borderStyle?: string;
borderRadius?: number;
boxShadow?: string;
chartBackground?: string;
chartPadding?: number;
schema?: string[];
mapTheme?: string;
}
// Create Copilot configuration object
const copilotConfig: ICopilotConfig = {
userConfig: {
// Either appId and datasetId or chartId must be provided
// Example: appId: 130870, datasetId: 1 // Data package id + Dataset id
// or
// appId: 130870, chartId: 1 // Application id + Chart id
},
closable: true, // Optional, whether to show the close button, default is false
draggable: {
enable: false,
minWidth: 400,
minHeight: 400,
bounds: 'window',
position: {
x: window.innerWidth - 480,
y: 20,
},
size: {
width: 440,
height: window.innerHeight * 0.8,
},
},
locale: 'zh-CN', // Optional, language setting, default is Simplified Chinese
stylesheet: '', // Optional, custom CSS styles
className: '', // Optional, custom class name
style: {}, // Optional, custom style
bodyClassName: '', // Optional, dialog content container class name
bodyStyle: {}, // Optional, dialog content container style
header: '', // Optional, additional content in the title
systemMsg: '欢迎使用智能分析助手', // Optional, welcome message, default value
parser: {
selectText: '选择图表', // Button text
onSelect: (chart) => {
// Event triggered when the button is clicked, chart parameter needs to be defined according to the actual usage scenario
console.log('Chart selection event', chart);
},
},
chartTheme: 'HAWAII_SEA', // Optional, chart theme, refer to dashboard theme
};
Customizing AI Assistant Styles
If you want to customize the AI assistant's styles, you can achieve this with the following CSS code:
/* Example: Batch Customize Skin Styles Using CSS */
*, ::before, ::after {
--brand: #4CAF50; // This is the overall brand color of the system
}
/* Set the root element style for the AI assistant dialog box */
.hengshi-copilot-sdk .hst-copilot {
position: fixed;
// z-index: 1; // Set as needed
top: 10vh;
right: 50px;
width: 440px;
height: 80vh;
border-width: 1px;
}
/* Set the style for the AI assistant title element */
.hengshi-copilot-sdk .hst-copilot-header {
color: #fff;
background-color: darkslategray;
}
/* Set the style for the AI assistant conversation area element */
.hengshi-copilot-sdk .hst-copilot-conversations {
border-color: #aaa;
background-color: darkslategray;
height: calc(100% - 50px);
}
/* Set the style for the AI assistant message element */
.hengshi-copilot-sdk .hst-copilot-msg,
/* Set the style for the ICON operation element below the AI assistant message */
.hengshi-copilot-sdk .hst-copilot-msg > .hs-relative > *,
/* Set the style for the AI assistant auxiliary information element */
.hengshi-copilot-sdk .hst-copilot-mark {
color: #fff;
}
.hengshi-copilot-sdk .hst-copilot-mark .hs-bg-\[color\:var\(--hs-bg-lighter\)\] {
background-color: transparent;
}
/* Set the background style for the ICON operation element when hovered below the AI assistant message */
.hengshi-copilot-sdk .hover\:hs-bg-\[\#eee\]:hover {
--tw-bg-opacity: .2;
}
/* Set the style for the AI assistant AI message bubble element */
.hengshi-copilot-sdk .hst-copilot-msg-bot .hst-copilot-msg-inner,
/* Set the style for the AI assistant user message bubble element */
.hengshi-copilot-sdk .hst-copilot-msg-user .hst-copilot-msg-inner {
border-color: darkgray;
background-color: darkgray;
}
/* Set the background color for the AI assistant recommended question bubble */
.hengshi-copilot-sdk .hst-copilot-msg-inner .hst-copilot-msg-inner {
background-color: slategray !important;
}
/* Set the style for the AI assistant input content area element */
.hengshi-copilot-sdk .hst-copilot-prompt {
color: #fff;
background-color: darkslategray;
}
/* Set the style for the AI assistant input box element */
.hengshi-copilot-sdk .hst-copilot-prompt textarea {
color: #fff;
border-color: darkgray !important;
}
.hengshi-copilot-sdk .hst-copilot-prompt .hs-from-\[\#f1f1f1\],
.hengshi-copilot-sdk .hst-copilot-prompt .hs-to-\[\#f1f1f1\] {
--tw-gradient-to: darkslategray;
}
Pass the above CSS as a string in the stylesheet
in the Copilot configuration:
// Create Copilot configuration object
const copilotConfig: ICopilotConfig = {
...
stylesheet: css,
...
};
3. API Integration
API integration also has two methods: frontend and backend. The frontend method directly calls the js API provided by the Copilot SDK, while the backend method uses http interfaces.
JS SDK API
1. Intervene via JS
The Copilot SDK provides a headless mode, which means no UI is needed, only the js API is called, and interaction with the backend is done through http interfaces. This means you can integrate the Copilot SDK into your existing frontend project (such as your own AI assistant) by calling the js API wherever needed.
Pass headless: true
in CopilotConfig
to enable headless mode. In this case, the Copilot UI will not be rendered on the page, and you can control the behavior of Copilot by calling the js API.
Just like the loading method in UI mode, after new Copilot
, the returned copilot instance provides the following Copilot states, data, and functions:
{
api: {...},
// Copilot state
isLoading: false,
// Current conversation list, data format reference
// https://api.hengshi.com/conversation.html#conversation
conversations: [],
setConversations: () => {},
currentConversationId: null,
setCurrentConversationId: () => {},
runningChatUid: null,
setRunningChatUid: () => {},
setChat: (id, chatUid, chat) => {},
// Fetch historical conversation list
onFetchConversations: (offset = 0, limit = 10) => {},
// Create conversation
onCreateConversation: prompt => {},
onFetchConversation: id => {},
onClearConversations: () => {},
onFetchPreviousConversations: () => {},
// Create Q&A
onCreateChat: body => {},
onDeleteChat: (id, chatUid) => {},
onFetchSuggestions: refresh => {},
onFetchFavorites: () => {},
onCancelChatFavorite: (id, chatUid) => {},
// Render chart
renderChart: (container, { id, chart, chartTheme }) => {},
}
2. Call HTTP API via JS
In the above copilot instance, the api
object provides all the methods to call HTTP APIs. You can interact with the backend by calling these methods, such as:
// 1. Create conversation
const { body: { data: conversation }} = await copilot.api.requestCreateConversation({
body: {
title: 'This is the title of this conversation',
},
}).value;
/**
conversation = {
"id": 135,
"title": "This is the title of this conversation",
"createdBy": 268,
"createdAt": "2024-09-14 15:47:23",
"updatedBy": 268,
"updatedAt": "2024-09-14 15:47:23"
}
*/
// 2. Create Q&A
const { body: { data: chat }} = await copilot.api.requestCreateChat({
id: conversation.id,
body: {
prompt: 'Which director has the highest box office?', // This is the user's question
userConfig: { // Refer to the userConfig in the above copilotConfig
dataAppId: 129150,
datasetId: 1,
}
},
qs: {
sync: true, // Whether to execute synchronously
timeout: 1000 * 60, // Timeout, in milliseconds
},
}).value;
/**
chat = {
"conversationId": 135,
"prompt": "Which director has the highest box office?",
"answer": "Christopher Nolan has the highest box office.",
"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": "Which director has the highest box office?",
"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
]
}
]
}
*/
Backend HTTP API Integration
For backend HTTP API integration, please refer to the API documentation: Complete API Call Example from User Question to Data Acquisition