AutorÃa | Ultima modificación | Ver Log |
var questionString = 'Ask a question...'var errorString = 'An error occurred! Please try again later.'export const init = (data) => {const blockId = data['blockId']const api_type = data['api_type']const persistConvo = data['persistConvo']// Initialize local data storage if necessary// If a thread ID exists for this block, make an API request to get existing messagesif (api_type === 'assistant') {chatData = localStorage.getItem("block_openai_chat_data")if (chatData) {chatData = JSON.parse(chatData)if (chatData[blockId] && chatData[blockId]['threadId'] && persistConvo === "1") {fetch(`${M.cfg.wwwroot}/blocks/openai_chat/api/thread.php?thread_id=${chatData[blockId]['threadId']}`).then(response => response.json()).then(data => {for (let message of data) {addToChatLog(message.role === 'user' ? 'user' : 'bot', message.message)}})// Some sort of error in the API call. Probably the thread no longer exists, so lets reset it.catch(error => {chatData[blockId] = {}localStorage.setItem("block_openai_chat_data", JSON.stringify(chatData));})// The block ID doesn't exist in the chat data object, so let's create it} else {chatData[blockId] = {}}// We don't even have a chat data object, so we'll create one} else {chatData = {[blockId]: {}}}localStorage.setItem("block_openai_chat_data", JSON.stringify(chatData));}// Prevent sidebar from closing when osk pops up (hack for MDL-77957)window.addEventListener('resize', event => {event.stopImmediatePropagation();}, true);document.querySelector('#openai_input').addEventListener('keyup', e => {if (e.which === 13 && e.target.value !== "") {addToChatLog('user', e.target.value)createCompletion(e.target.value, blockId, api_type)e.target.value = ''}})document.querySelector('.block_openai_chat #go').addEventListener('click', e => {const input = document.querySelector('#openai_input')if (input.value !== "") {addToChatLog('user', input.value)createCompletion(input.value, blockId, api_type)input.value = ''}})document.querySelector('.block_openai_chat #refresh').addEventListener('click', e => {clearHistory(blockId)})document.querySelector('.block_openai_chat #popout').addEventListener('click', e => {if (document.querySelector('.drawer.drawer-right')) {document.querySelector('.drawer.drawer-right').style.zIndex = '1041'}document.querySelector('.block_openai_chat').classList.toggle('expanded')})require(['core/str'], function(str) {var strings = [{key: 'askaquestion',component: 'block_openai_chat'},{key: 'erroroccurred',component: 'block_openai_chat'},];str.get_strings(strings).then((results) => {questionString = results[0];errorString = results[1];});});}/*** Add a message to the chat UI* @param {string} type Which side of the UI the message should be on. Can be "user" or "bot"* @param {string} message The text of the message to add*/const addToChatLog = (type, message) => {let messageContainer = document.querySelector('#openai_chat_log')const messageElem = document.createElement('div')messageElem.classList.add('openai_message')for (let className of type.split(' ')) {messageElem.classList.add(className)}const messageText = document.createElement('span')messageText.innerHTML = messagemessageElem.append(messageText)messageContainer.append(messageElem)if (messageText.offsetWidth) {messageElem.style.width = (messageText.offsetWidth + 40) + "px"}messageContainer.scrollTop = messageContainer.scrollHeightmessageContainer.closest('.block_openai_chat > div').scrollTop = messageContainer.scrollHeight}/*** Clears the thread ID from local storage and removes the messages from the UI in order to refresh the chat*/const clearHistory = (blockId) => {chatData = localStorage.getItem("block_openai_chat_data")if (chatData) {chatData = JSON.parse(chatData)if (chatData[blockId]) {chatData[blockId] = {}localStorage.setItem("block_openai_chat_data", JSON.stringify(chatData));}}document.querySelector('#openai_chat_log').innerHTML = ""}/*** Makes an API request to get a completion from GPT-3, and adds it to the chat log* @param {string} message The text to get a completion for* @param {int} blockId The ID of the block this message is being sent from -- used to override settings if necessary* @param {string} api_type "assistant" | "chat" The type of API to use*/const createCompletion = (message, blockId, api_type) => {let threadId = nulllet chatData// If the type is assistant, attempt to fetch a thread IDif (api_type === 'assistant') {chatData = localStorage.getItem("block_openai_chat_data")if (chatData) {chatData = JSON.parse(chatData)if (chatData[blockId]) {threadId = chatData[blockId]['threadId'] || null}} else {// create the chat data item if necessarychatData = {[blockId]: {}}}}const history = buildTranscript()document.querySelector('.block_openai_chat #control_bar').classList.add('disabled')document.querySelector('#openai_input').classList.remove('error')document.querySelector('#openai_input').placeholder = questionStringdocument.querySelector('#openai_input').blur()addToChatLog('bot loading', '...');fetch(`${M.cfg.wwwroot}/blocks/openai_chat/api/completion.php`, {method: 'POST',body: JSON.stringify({message: message,history: history,blockId: blockId,threadId: threadId})}).then(response => {let messageContainer = document.querySelector('#openai_chat_log')messageContainer.removeChild(messageContainer.lastElementChild)document.querySelector('.block_openai_chat #control_bar').classList.remove('disabled')if (!response.ok) {throw Error(response.statusText)} else {return response.json()}}).then(data => {try {addToChatLog('bot', data.message)if (data.thread_id) {chatData[blockId]['threadId'] = data.thread_idlocalStorage.setItem("block_openai_chat_data", JSON.stringify(chatData));}} catch (error) {console.log(error)addToChatLog('bot', data.error.message)}document.querySelector('#openai_input').focus()}).catch(error => {console.log(error)document.querySelector('#openai_input').classList.add('error')document.querySelector('#openai_input').placeholder = errorString})}/*** Using the existing messages in the chat history, create a string that can be used to aid completion* @return {JSONObject} A transcript of the conversation up to this point*/const buildTranscript = () => {let transcript = []document.querySelectorAll('.openai_message').forEach((message, index) => {if (index === document.querySelectorAll('.openai_message').length - 1) {return}let user = userNameif (message.classList.contains('bot')) {user = assistantName}transcript.push({"user": user, "message": message.innerText})})return transcript}