Training Chatbot with API
When you upload documents to your chatbot, the documents are automatically trained into the bot memory. For website content, FAQ and Text, you need to train the bot to understand your new content.
When you run the training process either via UI or API, the bot will check for new content to train and reset both short term and long term memory so that your user will get fresh answer when interacting with the bot.
The API endpoint for training the Chatbot is https://mybot.chat/api/Training/StartTraining/{ChatbotId}
. This endpoint is using custom server-sent events (SSE) that require client to send authentication header (Autorization: Bearer api-token).
Warning: default web browser SSE does not support request header, it will not work here.
Custom SSE Event
There are three type of event the API generate: status
, end
and failed
status
: status update of the serverfailed
: error status from serverend
: end of training, request is terminated
Example Raw SSE data:
event: status
data: Training in progress
event: failed
data: Error occured on server
event: end
data:
Using NextJS (React)
For this example, we need custom SSE implementation from Microsoft that support request header @microsoft/fetch-event-source.
The code below is taken from https://github.com/MyBot-Chat/MyBot-Chatbot-UI/tree/main/app/training-api
'use client'
import { useState } from "react";
import { fetchEventSource } from "@microsoft/fetch-event-source";
const chatbotId = "--your-chatbotId--";
const apiKey = "--your-api-key--";
const serverBaseURL = "https://mybot.chat/api/Training/StartTraining/" + chatbotId;
const Training = () => {
const [data, setData] = useState("");
const [running, setRunning] = useState(false);
const addText = (str:string) => {
setData((oldData:string) => {
let newData = oldData + str + "\n";
return newData;
});
};
const fetchData = async () => {
await fetchEventSource(serverBaseURL, {
method: "GET",
headers: {
Accept: "text/event-stream",
Authorization: "Bearer "+apiKey
},
async onopen(res) {
if (res.ok && res.status === 200) {
console.log("Connection made ", res);
addText("Connection Open... ");
} else if (
res.status >= 400 &&
res.status < 500 &&
res.status !== 429
) {
console.log("Client side error ", res);
}
},
onmessage(msg) {
if(msg.event === "status"){
addText(msg.data);
}else if(msg.event === "end"){
addText("Training finished");
setRunning(false);
}else if(msg.event === "failed"){
addText("Failed: " + msg.data);
}
},
onclose() {
console.log("Connection closed by the server");
addText("Connection closed");
setRunning(false);
},
onerror(err) {
console.log("There was an error from server", err);
addText("Error: " + err);
},
});
}
const StartTraining = () => {
addText("Start training... ");
setRunning(true);
fetchData();
}
return (
<div style={{ display: "flex", justifyContent: "center", alignItems: "center", height: "100vh" }}>
<div className="w-96">
<div>
<h3>Training Example Page</h3>
</div>
{running && <progress className="progress w-56"></progress>}
<div>
<textarea rows={10} className="w-full" value={data} readOnly />
</div>
<div>
<button className="btn btn-primary" onClick={StartTraining}>Start Training</button>
</div>
</div>
</div>
);
};
export default Training;
Using JQuery plugin
This JQuery plugin for SSE support Server Sent Event with custom header support.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>EventSource example</title>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
<script src="/js/jquery.sse.min.js"></script>
<script>
const chatbotId = "--your-chatbotId--";
const apiKey = "--your-api-key--";
const url = "https://mybot.chat/api/Training/StartTraining/" + chatbotId;
function Show(msg){
var output = document.getElementById("output");
output.value += msg + "\n";
}
function startTraining(){
var output = document.getElementById("output");
output.value = "Starting...\n";
var w = $.SSE(url, {
headers: {
'Authorization': 'Bearer '+apiKey
},
onOpen: function (e) {
console.log("Open");
console.log(e);
Show("Open connection");
},
onEnd: function (e) {
console.log("End");
console.log(e);
Show("End of connection");
},
onError: function (e) {
console.log("Could not connect");
Show("Error: "+e);
},
onMessage: function (e) {
console.log("Message");
console.log(e);
},
options: {
forceAjax: false
},
events: {
status: function (e) {
console.log('Custom Event');
console.log(e);
Show("Status: "+e.data);
},
end: function(e) {
console.log(e);
Show("End of training");
w.stop();
}
}
});
w.start();
}
</script>
</head>
<body>
<h1>Training Chatbot Example</h1>
<div>
<textarea id="output" rows="10" cols="80"></textarea>
</div>
<div>
<button id="btnStart" onclick="startTraining()">Start Training</button>
</div>
</body>
</html>
Using C# HttpClient
using System.Net.Http.Headers;
namespace SSEConsumer
{
class Program
{
static async Task Main()
{
string chatbotId = "--your-chatbotId--";
string apiKey = "--your-api-key--";
string url = $"https://mybot.chat/api/Training/StartTraining/{chatbotId}";
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", apiKey);
using (var response = await client.GetAsync(url))
{
response.EnsureSuccessStatusCode();
using (var stream = await response.Content.ReadAsStreamAsync())
{
using (var reader = new System.IO.StreamReader(stream))
{
string currentEventName = "";
string data = "";
while (!reader.EndOfStream)
{
string line = await reader.ReadLineAsync();
if (!string.IsNullOrEmpty(line))
{
if (line.StartsWith("event:"))
{
currentEventName = line.Substring(6).Trim();
}
else if (line.StartsWith("data:"))
{
data = line.Substring(5).Trim();
}
}
else
{
// Process event data with the event name
Console.WriteLine($"Event: {currentEventName}, Data: {data}");
if(currentEventName == "end")
{
Console.WriteLine("Finished training");
client.CancelPendingRequests();
}else if(currentEventName == "failed")
{
Console.WriteLine($"Failed training, reason: {data}");
}
}
}
}
}
}
}
}
}
}