Canvas ChatGPT

Adds ChatGPT into Instructure Canvas

Você precisará instalar uma extensão como Tampermonkey, Greasemonkey ou Violentmonkey para instalar este script.

Você precisará instalar uma extensão como Tampermonkey ou Violentmonkey para instalar este script.

Você precisará instalar uma extensão como Tampermonkey ou Violentmonkey para instalar este script.

Você precisará instalar uma extensão como Tampermonkey ou Userscripts para instalar este script.

Você precisará instalar uma extensão como o Tampermonkey para instalar este script.

Você precisará instalar um gerenciador de scripts de usuário para instalar este script.

(Eu já tenho um gerenciador de scripts de usuário, me deixe instalá-lo!)

Você precisará instalar uma extensão como o Stylus para instalar este estilo.

Você precisará instalar uma extensão como o Stylus para instalar este estilo.

Você precisará instalar uma extensão como o Stylus para instalar este estilo.

Você precisará instalar um gerenciador de estilos de usuário para instalar este estilo.

Você precisará instalar um gerenciador de estilos de usuário para instalar este estilo.

Você precisará instalar um gerenciador de estilos de usuário para instalar este estilo.

(Eu já possuo um gerenciador de estilos de usuário, me deixar fazer a instalação!)

// ==UserScript==
// @name         Canvas ChatGPT
// @namespace    http://tampermonkey.net/
// @version      1.4
// @description  Adds ChatGPT into Instructure Canvas
// @author       Riley Campbell
// @match        *.instructure.com/*
// @license      https://opensource.org/license/bsd-3-clause/
// ==/UserScript==
(async function() {
    'use strict';
    if (window.location.href.indexOf("instructure.com") !== -1) {
        if (!window.location.href.includes("conversations")) {
            setInterval(function() {
                window.defaultMessage = {
                    "role": "system",
                    "content": localStorage.getItem('AIprompt')
                }
            }, 1000)
            let prompt = localStorage.getItem('AIprompt')
            if (prompt == null) {
                prompt = ''
                localStorage.setItem('AIprompt', '')
            }
            window.defaultMessage = {
                "role": "system",
                "content": prompt
            }
            window.AImessages = [window.defaultMessage]
            window.renderMessages = function() {
                let container = document.getElementById('container')
                container.innerHTML = ''
                for (let i in window.AImessages) {
                    let message = window.AImessages[i]
                    if (message.role == "system") {
                        continue
                    }
                    container.innerHTML += '<table><tr><th><p>' + message.role.charAt(0).toUpperCase() + message.role.slice(1) + ': </p><button onclick="let message=document.querySelectorAll(`th[data-message-id='+"'"+i.toString()+"'"+']`)[0];message.innerHTML=`<textarea style=\'display: block; width: 95%; height: 100px; resize: none; margin-left: auto; margin-right: auto; margin-top:10px;\'>`+message.innerHTML+`</textarea><button onclick='+"'let message=this.parentElement;let text=message.getElementsByTagName(\\`textarea\\`)[0].value;window.AImessages[parseInt(message.getAttribute(\\`data-message-id\\`))].content=text;message.innerHTML=text'"+'>Save</button>`">Edit</button></th><th data-message-id="'+i.toString()+'" style="white-space: break-spaces;">' + message.content + '</th></tr></table><hr class="solid">'
                }
                window.scrollTo({
                    top: document.body.scrollHeight,
                    behavior: 'smooth'
                });
            }
            window.sendMessage = async function() {
                document.getElementById('container').innerHTML += '<img style="display: block; width: 20px;margin-left: auto; margin-right: auto; margin-bottom:5px;" src="https://i.gifer.com/origin/34/34338d26023e5515f6cc8969aa027bca_w200.gif">'
                let message = {
                    "role": "user",
                    "content": document.getElementById('myTextArea').value
                }
                window.AImessages.push(message)
                document.getElementById('myTextArea').value = ''
                let messages = [window.defaultMessage, message]
                if (document.getElementById('memory').checked) {
                    messages = window.AImessages
                }
                let response = await fetch('https://api.openai.com/v1/chat/completions', {
                    method: "POST",
                    headers: {
                        "Content-Type": "application/json",
                        "Authorization": `Bearer ` + localStorage.getItem('openaiAPIKey')
                    },
                    body: JSON.stringify({
                        "model": localStorage.getItem('AImodel'),
                        "messages": messages,
                        "temperature": 1
                    })
                });
 
                if (response.ok) {
                    let result = await response.json()
                    window.AImessages.push(result.choices[0].message)
                    window.renderMessages()
                } else {
                    document.getElementById('container').innerHTML = `Error ${response.status}: ${response.statusText} <button onclick="document.getElementById('myTextArea').value=window.AImessages.pop().content;window.sendMessage()">Retry</button>`;
                };
            }
            window.populateModels = async function() {
                let supportedModels = ['gpt-4', 'gpt-4-0314', 'gpt-4-32k', 'gpt-4-32k-0314', 'gpt-3.5-turbo', 'gpt-3.5-turbo-0301']
                let response = await fetch('https://api.openai.com/v1/models', {
                    method: "GET",
                    headers: {
                        "Content-Type": "application/json",
                        "Authorization": `Bearer ` + localStorage.getItem('openaiAPIKey')
                    },
                });
                if (!response.ok) {
                    return 0;
                }
                let options = await response.json()
                let item = null
                let element = null
                let models = document.getElementById('models')
                models.innerHTML = ''
                for (let i = 0; i < options.data.length; i++) {
                    item = options.data[i]
                    if (supportedModels.includes(item.id)) {
                        element = document.createElement("option")
                        element.value = item.id
                        element.innerHTML = item.id
                        models.appendChild(element)
                    }
                }
            }
            let elem = document.createElement('div')
            elem.id='chatGPTbox'
            elem.setAttribute('style','margin-left:auto;margin-right:auto;width:95%')
            document.getElementById('wrapper').appendChild(elem)
            document.getElementById('chatGPTbox').innerHTML = `
<style>
    .switch {
        position: relative;
        display: inline-block;
        width: 60px;
        height: 34px
    }
 
    .switch input {
        opacity: 0;
        width: 0;
        height: 0
    }
 
    .slider {
        position: absolute;
        cursor: pointer;
        top: 0;
        left: 0;
        right: 0;
        bottom: 0;
        background-color: #ccc;
        -webkit-transition: .4s;
        transition: .4s
    }
 
    .slider:before {
        position: absolute;
        content: "";
        height: 26px;
        width: 26px;
        left: 4px;
        bottom: 4px;
        background-color: #fff;
        -webkit-transition: .4s;
        transition: .4s
    }
 
    input:checked+.slider {
        background-color: #2196F3
    }
 
    input:focus+.slider {
        box-shadow: 0 0 1px #2196F3
    }
 
    input:checked+.slider:before {
        -webkit-transform: translateX(26px);
        -ms-transform: translateX(26px);
        transform: translateX(26px)
    }
 
    .slider.round {
        border-radius: 34px
    }
 
    .slider.round:before {
        border-radius: 50%
    }
 
    input[type="checkbox"] {
        display: none;
    }
 
    .wrap-collabsible {
        margin: 1.2rem 0;
    }
 
    .lbl-toggle {
        display: block;
        font-weight: bold;
        font-family: monospace;
        font-size: 1.2rem;
        text-transform: uppercase;
        text-align: center;
        padding: 1rem;
        color: #DDD;
        background: #0069ff;
        cursor: pointer;
        border-radius: 7px;
        transition: all 0.25s ease-out;
    }
 
    .lbl-toggle:hover {
        color: #FFF;
    }
 
    .lbl-toggle::before {
        content: " ";
        display: inline-block;
        border-top: 5px solid transparent;
        border-bottom: 5px solid transparent;
        border-left: 5px solid currentColor;
        vertical-align: middle;
        margin-right: .7rem;
        transform: translateY(-2px);
        transition: transform .2s ease-out;
    }
 
    .toggle:checked+.lbl-toggle::before {
        transform: rotate(90deg) translateX(-3px);
    }
 
    .collapsible-content {
        max-height: 0px;
        overflow: hidden;
        transition: max-height .25s ease-in-out;
    }
 
    .toggle:checked+.lbl-toggle+.collapsible-content {
        max-height: 350px;
    }
 
    .toggle:checked+.lbl-toggle {
        border-bottom-right-radius: 0;
        border-bottom-left-radius: 0;
    }
 
    .collapsible-content .content-inner {
        background: rgba(0, 105, 255, .2);
        border-bottom: 1px solid rgba(0, 105, 255, .45);
        border-bottom-left-radius: 7px;
        border-bottom-right-radius: 7px;
        padding: .5rem 1rem;
    }
 
    .collapsible-content p {
        margin-bottom: 0;
    }
</style>
<div class="ic-DashboardCard" style="padding:10px; color: ; margin-bottom:10px; width: 100%;margin-left:auto;margin-right:auto;">
    <div width=100% height=650px style="padding:10px;" id="container"></div>
    <textarea style="display: block; width: 95%; height: 100px; resize: none; margin-left: auto; margin-right: auto; margin-top:10px;" id="myTextArea"></textarea>
    <br>
    <button class="Button button-sidebar-wide" id=\'submitButton\' style="display: block; width: 95%;margin-left: auto; margin-right: auto; margin-top: 5px; margin-botton: 5px;">Clear History</button>
    <br>
    <div class="wrap-collabsible">
        <input id="collapsible" class="toggle" type="checkbox">
        <label for="collapsible" class="lbl-toggle">Settings</label>
        <div class="collapsible-content">
            <div class="content-inner">
                <table style="max-height:34px;">
                    <tr style="max-height:34px;">
                        <td>
                            <label style="display:block; max-height:34px;" class="switch">
                                <input id="memory" type="checkbox">
                                <span class="slider round"></span>
                            </label>
                        </td>
                        <td>
                            <label style="display:block;max-height:34px;text-align: center;margin-top:auto;margin-bottom:auto;">Allow AI to remember past messages. (may incur extra charges)</label>
                        </td>
                    </tr>
                </table>
                <br>
                <label for="models">Model:</label>
                <select name="models" id="models"></select>
                <br>
                <textarea style="display: block; width: 95%; height: 100px; resize: none; margin-left: auto; margin-right: auto; margin-top:10px;" placeholder="Default System Prompt (Requires history to be cleared in order to take effect)" id="systemPrompt">` + localStorage.getItem('AIprompt') + `</textarea>
                <br>
                <input id="key" placeholder="API Key" type="text" style="display:block;float:left;"></input>
                <button class="Button button-sidebar-wide" id="setAPIKey" style="display: block;">Set API Key</button>
            </div>
        </div>
    </div>
</div>
        `
            await window.populateModels()
            document.getElementById('models').value = localStorage.getItem('AImodel')
            let checked = (localStorage.getItem('AImemory') === 'true')
            document.getElementById('memory').checked = checked
            setInterval(function() {
                localStorage.setItem('AImemory', document.getElementById('memory').checked)
                localStorage.setItem('AImodel', document.getElementById('models').value)
                localStorage.setItem('AIprompt', document.getElementById('systemPrompt').value)
            }, 1000)
            document.getElementById('submitButton').onclick = async () => {
                window.AImessages = [window.defaultMessage]
                window.renderMessages()
            };
            document.getElementById('setAPIKey').onclick = async () => {
                localStorage.setItem('openaiAPIKey', document.getElementById('key').value)
                document.getElementById('key').value = ''
                await window.populateModels()
            };
            const myTextarea = document.getElementById("myTextArea");
            myTextarea.addEventListener("keydown", async function(event) {
                if (event.key === "Enter" && !event.shiftKey) {
                    event.preventDefault();
                    await window.sendMessage()
                }
            })
        };
    }
})();