Forum Discussion
Integrating a Chatbot into My Storyline Project
Thanks so much! I'm still new to JavaScript and putting together a separate XLM file is a bit above my head. I'll talk to tech. It would be better to have more control over it. Thank you for the script. I'll try it. Here's what I (and ChatGPT) came up with:
// Step 1: Capture the learner's SMART goal from the Storyline variable
var player = GetPlayer();
var userGoal = player.GetVar("GoalText"); // Replace 'GoalText' with the actual variable name in Storyline
// Step 2: OpenAI API setup
const apiKey = 'myKey'; // Replace this with your OpenAI API key once you have it
const apiUrl = 'https://api.openai.com/v1/chat/completions';
// Step 3: Prepare the data to send to OpenAI
const data = {
model: "gpt-4", // Model can be gpt-3.5-turbo or gpt-4 depending on your API access
messages: [
{
role: "system",
content: "You are an assistant that helps users write SMART goals. Provide feedback on Specific, Measurable, Achievable, Relevant, and Time-bound aspects of the goal. Please be succinct and ensure you can answer fully with the 500 max_limit tokens. Include a concise summary of your conclusions with a rating score of 1-5, with 5 being the highest quality."
},
{
role: "user",
content: `Here is the SMART goal: "${userGoal}". Please analyze and provide feedback on it.`
}
],
max_tokens: 500, // Limit the response length to avoid using too many tokens
temperature: 0.7 // Adjusts the creativity of the response (0.7 is a good balance)
};
// Step 4: Send the API request to OpenAI
fetch(apiUrl, {
method: 'POST',
headers: {
'Authorization': `Bearer ${apiKey}`,
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
})
.then(response => response.json())
.then(data => {
// Step 5: Handle the response and set it to a Storyline variable
if (data && data.choices && data.choices.length > 0) {
var feedback = data.choices[0].message.content.trim(); // Extract feedback from the response
player.SetVar("AI_Feedback", feedback); // Store the feedback in a Storyline variable
} else {
player.SetVar("AI_Feedback", "No valid feedback received."); // In case no feedback is returned
}
})
.catch(error => {
console.error("Error:", error);
player.SetVar("AI_Feedback", "There was an error connecting to the AI service.");
});
It's geared towards mentoring about a specific topic. I'd like to embed a chatbot that users can access on any page of the course and ask questions about the content. That's a much different animal.
No worries. ChatGPT has helped me a lot with figring out the javascript tricks I now use.
The XML bit is supr simple. You just need to create file called something like keys.xml and structure the content like this:
<?xml version="1.0" encoding="utf-8"?>
<SO xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<!-- OpenAI API Key -->
<folder type="OpenAI">
<APIKey>12345</APIKey>
</folder>
</SO>
then in storyline use this code as a javascript trigger that runs when the timeline starts:
// Define getAPIKeys function
window.getAPIKeys = function(callback) {
var OAPI = "";
var player = GetPlayer(); // Now only called after Storyline is ready
var xmlDoc = "";
var xmlhttp = new XMLHttpRequest();
var dataLoadError = false; // Flag for error tracking
// Request the xml doc from the server (Keys)
xmlhttp.open("GET", "keys.xml", true); // Asynchronous request
xmlhttp.onload = function() {
if (xmlhttp.status === 200) { // Check if the request was successful
xmlDoc = xmlhttp.responseXML;
try {
// Retrieve the OpenAI API keys from the XML file
var apiKeyElement = xmlDoc.getElementsByTagName("APIKey")[0];
if (apiKeyElement && apiKeyElement.childNodes[0]) {
OAPI = apiKeyElement.childNodes[0].nodeValue;
// Set them as Storyline variables
player.SetVar("OpenAI_API", OAPI);
// Execute the callback if provided
if (callback) {
callback();
}
} else {
throw new Error("API key not found in the XML.");
}
} catch (error) {
console.error("Error processing XML: ", error.message);
dataLoadError = true;
player.SetVar("Data_Load_Error", true);
}
} else {
console.error("Error loading XML: Status ", xmlhttp.status);
dataLoadError = true;
player.SetVar("Data_Load_Error", true);
}
};
xmlhttp.onerror = function() {
console.error("Network error while fetching keys.xml");
dataLoadError = true;
player.SetVar("Data_Load_Error", true);
};
xmlhttp.send();
};
Then in your exported zip file, add the xml file to it and upload the whole thing to your VLE. If you want to remove access all you have to do is remove the xml file from the VLE.
- Jürgen_Schoene_2 months agoCommunity Member
you have moved the API key from the javascript file to a xml file, this is no security improvement
- any experienced user can easily read everything that the browser receives and sends, whether javascript, xml, html, images, videos ... -> press F12, then "network"
- if the api key is in the xml file, the user can read the api key also - the user has the same right as your javascript programming
- if you want your API key be save, the user's browser must NEVER see the api key
- the only place where the API key belongs is a backend server on which the user has no read rights
https://help.openai.com/en/articles/5112595-best-practices-for-api-key-safety
- Dave-Ruckley2 months agoCommunity Member
Thats true, but the user group for the resource i'm using is small and known, so any misuse of the api can be quickly addressed with the students directly. It's also in use for a specific timeframe only so API use can be monitored. The xml method was so it could be pulled from the vle without breaking the rest of the resource or re-publishing and having students loose their work.
I don't have a server I can use so this was the method I chose that gives me some control over the API useage without breaking everything.