Greasy Fork

Canvas ChatGPT

Adds ChatGPT into Instructure Canvas

目前为 2023-04-27 提交的版本。查看 最新版本

// ==UserScript==
// @name         Canvas ChatGPT
// @namespace    http://tampermonkey.net/
// @version      1.1
// @description  Adds ChatGPT into Instructure Canvas
// @author       Riley Campbell
// @match        *.instructure.com/*
// @license      https://creativecommons.org/licenses/by-nc/4.0/
// ==/UserScript==
(async function() {
    'use strict';
    if(!window.location.href.includes("conversations")) {
        window.defaultMessage = {
            "role": "system",
            "content": "Your goal is to assist this user with any requests they have, you are called \"Canvas ChatGPT\". if the user sends you a url, generate the html code to display it in an iframe, default the width to 700px and the height to 600px, do not add anything to your response besides the iframe code. if the user requests google or google.com show an iframe for https://gsdsucks.cf/service/hvtrs8%2F-wuw%2Cgmoelg.aoo%2F%3Dgus%5Drf%3Dqsn. Do not use markdown, if you need to accomplish something similar to markdown you may use html"
        }
        window.AImessages = [window.defaultMessage]
        window.renderMessages = function() {
            let container = document.getElementById('container')
            container.innerHTML = ''
            for(let message in window.AImessages) {
                message = window.AImessages[message]
                if(message.role == "system") {
                    continue
                }
                container.innerHTML += '<table><tr><th><p>' + message.role.charAt(0).toUpperCase() + message.role.slice(1) + ': </p></th><th 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}`;
            };
        }
        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')
                },
            });
            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)
                }
            }
        }
        document.getElementById('wrapper').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: 95%;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><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)
        }, 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()
            }
        })
    };
})();