Skip to content

SDK Integration ​

Configuration Options ​

ts
interface DataSource {
    appId: number;
    chartId?: number;
    dataAppId?: number;
    datasetId?: number;
    subjectId?: number; // Business Indicator Subject Domain ID
}

interface CompletionConfig {
    meta?: string;
    openChartConfig?: boolean;
    stylesheet?: string;
    i18n?: {
        [key: string]: {
            [key: string]: string;
        };
    };
    onCompletionDone?: (conversationId: number, uid: string) => void;
}

interface Config {
  userConfig: {
    sourceAppId?: number;
    dataSources: DataSource[];
  };
  completionConfig?: CompletionConfig;
  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;
  i18n?: {
    [key: string]: {
      [key: string]: 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 config: Config = {
  userConfig: {
    // sourceAppId: 130870, // App ID from App Mart or App Creation
    dataSources: [
      // Method 1: Using Data Package and Dataset
      {
        appId: 130870,
        dataAppId: 130870,
        datasetId: 1,
      },
      // Or Method 2: Using Business Indicator Subject Domain
      {
        appId: 130871,
        subjectId: 1,
      }
    ],
  },
  completionConfig: {
    meta: 'answer,chart,chartConfig', // Specify content combination to render
    openChartConfig: false, // Whether to expand the chart logic panel, defaults to true
    stylesheet: ':host > *, ::before, ::after { --brand: #4CAF50; }',
    i18n: {
      "en-US": {
        'copilot.question-reasoning': 'Question Understanding',
        'copilot.question-answer': 'Data Performance',
        'copilot.question-reasoning-logic': 'Data Logic'
      }
    },
    onCompletionDone: (conversationId, uid) => {
      console.log('AI completion done:', conversationId, uid);
    },
  },
  closable: true, // Optional, whether to display the close button, default is false
  draggable: { // Optional, whether draggable, default is not draggable
    enable: true,
    minWidth: 440,
    minHeight: 440,
    bounds: 'window',
    position: {
      x: window.innerWidth - 480,
      y: 20,
    },
    size: {
      width: 440,
      height: window.innerHeight * 0.8,
    },
  },
  locale: 'en-US',
  i18n: {
    "en-US": {
      'copilot.question-reasoning': 'Question Understanding',
      'copilot.question-answer': 'Data Performance',
      'copilot.question-reasoning-logic': 'Data Logic'
    },
    "zh-CN": {
      'copilot.question-reasoning': '问题理解',
      'copilot.question-answer': '数据表现',
      'copilot.question-reasoning-logic': '取数逻辑'
    }
  },
  stylesheet: '',  // Optional, custom CSS styles
  className: '', // Optional, custom class name
  style: {}, // Optional, custom styles
  bodyClassName: '', // Optional, class name for the dialog content container
  bodyStyle: {}, // Optional, styles for the dialog content container
  header: '', // Optional, additional content in the title
  systemMsg: 'Welcome to the Intelligent Analysis Assistant', // Optional, welcome message
  parser: {
    selectText: 'Select Chart', // Button text
    onSelect: (chart) => {
      // Event triggered when button is clicked, chart parameter needs to be defined based on actual usage scenarios
      console.log('Chart selection event', chart);
    },
  },
  chartTheme: 'HAWAII_SEA', // Optional, chart theme, refer to dashboard themes
};

> [!NOTE]
> In the `dataSources` configuration, each data source can only use one of the following two modes:
> 1. Data Package and Dataset Mode: provide `dataAppId` and `datasetId`
> 2. Business Indicator Subject Domain Mode: provide `subjectId`
>
> You cannot mix both modes in the same data source configuration.

2. Calling HTTP API via JS ​

In the copilot example above, the api object provides all the methods for calling HTTP APIs. You can interact with the backend by invoking these methods, such as:

js
// 1. Create a conversation
const { body: { data: conversation }} = await copilot.api.requestCreateConversation({
  body: {
    title: 'This is the title of the conversation',
  },
}).value;
/**
conversation = {
  "id": 135,
  "title": "This is the title of the conversation",
  "createdBy": 268,
  "createdAt": "2024-09-14 15:47:23",
  "updatedBy": 268,
  "updatedAt": "2024-09-14 15:47:23"
}
*/
// 2. Create a Q&A
const { body: { data: chat }} = await copilot.api.requestCreateChat({
  id: conversation.id,
  body: {
    prompt: 'Which director has the highest-grossing movies?', // This is the user's question
    userConfig: { // Refer to the userConfig in copilotConfig above
      dataAppId: 129150,
      datasetId: 1,
    }
  },
  qs: {
    sync: true, // Whether to execute synchronously
    timeout: 1000 * 60, // Timeout duration in milliseconds
  },
}).value;
/**
chat = {
    "conversationId": 135,
    "prompt": "Which director has the highest-grossing movies?",
    "answer": "Christopher Nolan has the highest-grossing movies.",
    "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-grossing movies?",
    "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_product_table}}.{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_product_table}}.{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
            ]
        }
    ]
}
*/

Login Authentication ​

When integrating the SDK, you may need to perform login authentication. We provide two methods:

  1. SSO Single Sign-On: If your system is already integrated with the HENGSHI SENSE system, no additional login is required.
  2. JWT Authentication: Use the following code to perform login authentication with JWT:
js
fetch('https://develop.hengshi.org/api/auth/login-info?activeAuth=jwt-param&jwtParam=Your JWT Parameter')
  .then(response => {
    // Login successful, proceed with 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.

Custom Styles ​

If you want to customize the AI assistant's style, you can achieve this through the following CSS code:

css
/* Example: Use CSS to batch customize skin styles */
*, ::before, ::after {
  --brand: #4CAF50; // This is the system's overall brand color
}
/* 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 operations below the AI assistant message element */
.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 operations below the AI assistant message element when hovered */
.hengshi-copilot-sdk .hover\:hs-bg-\[\#eee\]:hover {
  --tw-bg-opacity: .2;
}
/* Set the style for the AI assistant bot 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 bubbles */
.hengshi-copilot-sdk .hst-copilot-msg-inner .hst-copilot-msg-inner {
  background-color: slategray !important;
}
/* Set the style for the AI assistant input 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 Copilot configuration's stylesheet:

ts
// Create Copilot configuration object
const config: Config = {
  ...
  stylesheet: css, 
  ...
};

Integration via API can be done in two ways: frontend and backend. The frontend method directly calls the JavaScript API provided by the Copilot SDK, while the backend method uses HTTP interfaces.

Intercept API Requests and Customize API Requests ​

You can configure api to intercept API requests and customize API requests in copilotConfig.

The following APIs can be configured:

  • requestFetchConversations: Fetch the conversation list
  • requestCreateConversation: Create a conversation
  • requestFetchConversation: Fetch conversation details
  • requestDeleteConversation: Delete a conversation
  • requestFetchChats: Fetch chat records within a conversation
  • requestCreateChat: Create a chat record
  • requestFetchChat: Fetch a single chat record
  • requestUpdateChat: Update a single chat record
  • requestDeleteChat: Delete a single chat record
  • requestfetchChatLogs: Fetch logs of a single chat record
  • requestRegenerateChat: Regenerate a response

Each API is a JavaScript function that accepts an object as a parameter, with the following rules:

  • requestFetchConversations({ offset?: number, limit?: number })
  • requestCreateConversation({ body: { title: string }})
  • requestFetchConversation({ id: number })
  • requestDeleteConversation({ id: number })
  • requestFetchChats({ id: number, offset?: number, limit?: number })
  • requestCreateChat({ id: number, body: { prompt: string, userConfig: object }})
  • requestFetchChat({ id: number, chatUid: string })
  • requestUpdateChat({ id: number, chatUid: string, body: object })
  • requestDeleteChat({ id: number, chatUid: string })
  • requestfetchChatLogs({ id: number, chatUid: string })
  • requestRegenerateChat({ id: number, chatUid: string })

The function's return value is also an object, formatted as follows:

js
{
  abort: function abort() {}, // Abort the API request
  value: Promise, // The Promise of the API request
}

For example, if you want to intercept requests and add some custom parameters every time a conversation is created, you can configure it like this:

js
const copilotConfig = {
  // ...
  api: {
    // Customize the API for creating conversations
    requestCreateChat: params => {
      // Add some custom parameters
      if (!params.body.yourCustomProperty) {
        params.body.yourCustomProperty = 'yourCustomValue';
      }
      return copilotInstance.context.endpoints.requestCreateChat(params);
    },
    // ... Other APIs can also be configured
  },
};

User Manual for Hengshi Analysis Platform