Skip to content

Instantly share code, notes, and snippets.

@Explosion-Scratch
Last active September 23, 2023 16:22
Show Gist options
  • Save Explosion-Scratch/fc205244d3737f21e51ff7dfb9476835 to your computer and use it in GitHub Desktop.
Save Explosion-Scratch/fc205244d3737f21e51ff7dfb9476835 to your computer and use it in GitHub Desktop.
ChatGPT userscript for google with web access, code copy and more
// ==UserScript==
// @name ChatGPT google
// @namespace http://tampermonkey.net/
// @version 0.1
// @description try to take over the world!
// @author You
// @match https://www.google.com/*
// @icon https://www.google.com/s2/favicons?sz=64&domain=google.com
// @grant GM_xmlhttpRequest
// @grant GM_getValue
// @grant GM_setValue
// @grant GM_deleteValue
// @grant GM_listValues
// @grant unsafeWindow
// @connect chat.openai.com
// @run-at document-idle
// @require https://cdnjs.cloudflare.com/ajax/libs/markdown-it/13.0.1/markdown-it.min.js
// @require https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.8.0/highlight.min.js
// @require https://unpkg.com/popper.js@1
// @require https://unpkg.com/tippy.js@5
// ==/UserScript==
(async function () {
"use strict";
await new Promise((r) => setTimeout(r));
if (
new URLSearchParams(location.search).get("clearStorage") &&
confirm("Clear storage?")
) {
GM_listValues().forEach((key) => {
GM_deleteValue(key);
});
}
if (new URLSearchParams(location.search).get("clear") &&
confirm("Clear storage?")) {
GM_deleteValue('accessToken')
}
let PREAMBLE =
"Be concise and answer the prompt. Bold important sections. Give examples/code when possible.";
// Use simple bullet points in your response. Be concise and readable. Indent bullet points and bold important sections. Be as concise as possible. Answer the prompt exactly:\n\nPrompt:
const mode = "question_mark";
const QUERY = document.querySelector("textarea").value.trim();
const PREFIX = `c${Math.random().toString(16).slice(2)}-`;
const MESSAGE_STORAGE_KEY = `chatgpt_msg`;
const ELEMENT_ID = `${PREFIX}markdown`;
const CONTAINER_ID = `${PREFIX}container`;
const STYLE_ID = `${PREFIX}style`;
const CLOUDFLARE_MSG = `<i class="demphasize">Login at https://chat.openai.com to pass Cloudflare checks</i> • <a class="retry_token">Try again</a>`;
const BASE_URL = `https://chat.openai.com`;
const INPUT_CONTAINER_ID = `${PREFIX}input-container`;
const INPUT_ID = `${PREFIX}input`;
const INPUT_BUTTON_ID = `${PREFIX}input-button`;
let MD_PREFIX = "";
let LAST_CONVO_ID = "";
let LAST_MSG_ID = "";
setInterval(() => {
tooltips(`#${CONTAINER_ID} .citation`, (element) => {
const idx = parseInt(element.innerText);
return `${idx}. <i class="demphasize">${new URL(escapeHtml(results[idx - 1].url)).host
}</i> - <b>${escapeHtml(results[idx - 1].title)}</b>`;
});
tooltips(
`#${CONTAINER_ID} #${INPUT_BUTTON_ID}`,
(e) => `<i class="demphasize">Send</i>`,
);
tooltips(
`#${CONTAINER_ID} .continue_convo`,
(e) => `<i class="demphasize">${escapeHtml(e.href)}</i>`,
);
tooltips(
`#${CONTAINER_ID} .copy`,
(e) => `<i class="demphasize">Copy code</i>`,
);
}, 400);
document.addEventListener("click", async (e) => {
if (e.target.closest("button.copy")) {
navigator.clipboard.writeText(e.target.closest(".hljs").innerText);
let el = e.target.closest("button.copy");
let old = el.innerHTML;
el.innerHTML =
'<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 256 256"><path fill="currentColor" d="m229.66 77.66l-128 128a8 8 0 0 1-11.32 0l-56-56a8 8 0 0 1 11.32-11.32L96 188.69L218.34 66.34a8 8 0 0 1 11.32 11.32Z"/></svg>';
setTimeout(() => (el.innerHTML = old), 1000);
}
if (e.target.closest(".retry_token")) {
await GM_deleteValue("accessToken");
location.reload();
return;
}
if (e.target.closest(`.cached_notice`)) {
MD_PREFIX = "";
getAnswer(await getAccessToken(), QUERY + "\n\n" + PREAMBLE + QUERY, {
noCache: true,
});
}
});
const OTHER_STYLES = `
#${CONTAINER_ID} {
border-radius: 5px;
${true ? "" : "border-top: 1px solid #eee;"}
border-bottom: 1px solid #eee;
margin: 10px auto;
magin-bottom: 25px;
padding: 25px 0;
color: #333;
}
#${CONTAINER_ID} .demphasize {color: #777;}
#${INPUT_BUTTON_ID}{
background: transparent;
cursor: pointer;
opacity: .5;
border: none;
display: grid;
place-items: center;
padding: 4px;
transition: opacity .2s ease;
}
#${INPUT_BUTTON_ID}.ready {
opacity: 1 !important;
color: #059669 !important;
}
#${INPUT_BUTTON_ID} svg {width: 20px;}
#${INPUT_BUTTON_ID}:hover {opacity: .8;}
#${INPUT_ID} {
border: none;
padding: 5px 15px;
flex: 1;
color: #666;
}
#${INPUT_CONTAINER_ID} {
padding-top: 20px;
margin-bottom: -15px;
display: flex;
width: 100%;
}
.citation {
background: #00f1 !important;
padding: 2px;
border-radius: 3px;
font-size: .9em;
cursor: pointer;
transition: background-color .2s ease;
}
.citation:hover {background: transparent !important;}
`;
const first_result = {
desc: document.querySelector('[data-attrid="wa:/description"]')?.innerText,
title: document
.querySelector('[data-attrid="wa:/description"]')
?.closest(".V3FYCf")
?.querySelector("h3")?.innerText,
url: document
.querySelector('[data-attrid="wa:/description"]')
?.closest(".V3FYCf")
?.querySelector("a")?.href,
first: true,
};
const news_results = [...document.querySelectorAll(".MkXWrd")]
.map((i) => ({
url: i.querySelector("a")?.href,
title: i.querySelector("[role=heading]")?.innerText,
}))
.map((i) => ({ ...i, desc: i.title }));
let results = [...document.querySelectorAll(".g")].map((i) => ({
title: i.querySelector("h3")?.innerText,
desc: i.querySelector('[data-sncf="2"],[data-sncf="1"]')?.innerText,
url: i.querySelector("a")?.href,
}));
results = [
...(first_result?.desc && first_result.title && first_result.url
? [first_result]
: []),
...news_results,
...results,
];
results = results.filter((i) => i.desc && i.title && i.url);
const SEARCH_ENABLED = true;
if (SEARCH_ENABLED) {
PREAMBLE = `Results:\n\n${results
.slice(0, 5)
.map(
(i, idx) =>
`[${idx + 1}] ${i.title}\n\t${i.first ? i.desc : i.desc.slice(0, 100)
}`,
)
.join(
"\n",
)}\n\n${PREAMBLE}. reference search results using number syntax ([1], [2], [3]) if you need, respond to the prompt as usual. if prompt vague summarize the search results.`;
}
const END = "Be very concise, make your response short. \nPrompt: ";
PREAMBLE = `${PREAMBLE} ${END}`;
const escapeHtml = (unsafe) => {
return unsafe
.replaceAll("&", "&amp;")
.replaceAll("<", "&lt;")
.replaceAll(">", "&gt;")
.replaceAll('"', "&quot;")
.replaceAll("'", "&#039;");
};
const ask = async () => {
document.querySelector(`#${CONTAINER_ID}`).onclick = () => { };
getAnswer(await getAccessToken(), QUERY + "\n\n" + PREAMBLE + QUERY);
};
setMarkdown("<i style='color: #999;'>Loading...</i>");
if (mode === "click") {
setMarkdown(
"<i style='color: #999; cursor: pointer; width: 100%; display: block; font-weight: 200;' class='click_to_start'>Click to start</i>",
);
document.querySelector(`#${CONTAINER_ID} .click_to_start`).onclick = () => {
ask();
};
} else if (mode === "question_mark") {
if (QUERY.endsWith("?")) {
ask();
} else {
return document.querySelector(`#${CONTAINER_ID}`).remove();
}
} else {
setTimeout(() => ask());
}
// getAccessToken().then(console.log.bind(console, "Token: "));
const followupQuestion = async (q) => {
if (!q?.trim()?.length) {
return;
}
if (!(LAST_CONVO_ID && LAST_MSG_ID)) {
getAnswer(await getAccessToken(), PREAMBLE + q);
} else {
MD_PREFIX = `${MD_PREFIX}\n\n<div class="you">${escapeHtml(
q,
)}</div>\n<div class="hr"></div>\n\n`;
setMarkdown("<i>Loading...</i>");
getAnswer(await getAccessToken(), q);
}
};
async function getAnswer(token, question, { noCache } = {}) {
let cache = await GM_getValue(
`${MESSAGE_STORAGE_KEY}:${hash(strip(question))}`,
);
if (cache && !noCache) {
const parsed = JSON.parse(cache);
LAST_CONVO_ID = parsed.convo_id;
LAST_MSG_ID = parsed.msg_id;
results = parsed.results;
setMarkdown(
parsed.content +
`\n\n<a style="color: #666; font-style: italic; font-size: .8em; text-decoration: none;" class="continue_convo" href=${JSON.stringify(
`https://chat.openai.com/c/${LAST_CONVO_ID}`,
)}>Continue conversation</a> • <a style="color: #666; font-style: italic; font-size: .8em; text-decoration: none; cursor: pointer;" class="cached_notice">Retry (cached)</a>`,
);
return;
}
const res = await askGPT(question, async (progress) => {
LAST_CONVO_ID = uuid();
LAST_MSG_ID = uuid();
const MESSAGE_CONTENT = parsed
await GM_setValue(
`${MESSAGE_STORAGE_KEY}:${hash(strip(question))}`,
JSON.stringify({
msg_id: LAST_MSG_ID,
convo_id: LAST_CONVO_ID,
content: MESSAGE_CONTENT,
}),
);
const final_md =
MESSAGE_CONTENT +
`\n\n<a style="color: #666; font-style: italic; font-size: .8em; text-decoration: none;" class="continue_convo" href=${JSON.stringify(
`https://chat.openai.com/c/${LAST_CONVO_ID}`,
)}>Continue conversation</a> • <a style="color: #666; font-style: italic; font-size: .8em; text-decoration: none; cursor: pointer;" class="cached_notice">Retry</a>`;
setMarkdown(final_md);
// MD_PREFIX += `${MESSAGE_CONTENT}\n<div class="hr"></div>\n\n`;
return console.log("DONE", parsed);
});
const final_md =
res +
`\n\n<a style="color: #666; font-style: italic; font-size: .8em; text-decoration: none;" class="continue_convo" href=${JSON.stringify(
`https://chat.openai.com/c/${LAST_CONVO_ID}`,
)}>Continue conversation</a> • <a style="color: #666; font-style: italic; font-size: .8em; text-decoration: none; cursor: pointer;" class="cached_notice">Retry</a>`;
setMarkdown(final_md);
}
async function getAccessToken() {
const accessToken = await GM_getValue("accessToken", undefined);
if (accessToken) return accessToken;
const text = await getText(`${BASE_URL}/api/auth/session`);
console.log("GOT TEXT", text);
if (isBlocked(text)) {
return setMarkdown(CLOUDFLARE_MSG);
}
const token = JSON.parse(text).accessToken;
if (!token) {
return setMarkdown(CLOUDFLARE_MSG);
}
await GM_setValue("accessToken", token);
return token;
}
function isBlocked(resp) {
try {
const html = new DOMParser().parseFromString(resp, "text/html");
const title = html.querySelector("title");
if (!title) return false;
return title.innerText === "Just a moment...";
} catch (error) {
return false;
}
}
function addStyle() {
const s = document.createElement("style");
s.innerHTML = style + "\n\n" + OTHER_STYLES;
s.id = STYLE_ID;
document.head.appendChild(s);
}
function addElement() {
const CONTAINER_SELECTOR = "#res";
const container = document.querySelector(CONTAINER_SELECTOR);
const inner_container = document.createElement("div");
inner_container.id = CONTAINER_ID;
container.prepend(inner_container);
inner_container.appendChild(getElement());
const input = document.createElement("input");
input.placeholder = "Send a message...";
input.id = INPUT_ID;
const input_button = document.createElement("button");
input_button.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 256 256"><path fill="currentColor" d="m222.88 115.69l-168-95.88a14 14 0 0 0-20 16.85l31 90.48v.07a2.11 2.11 0 0 1 0 1.42l-31 90.64A14 14 0 0 0 48 238a14.11 14.11 0 0 0 6.92-1.83l167.92-96.07a14 14 0 0 0 0-24.41Zm-5.95 14L49 225.73a1.87 1.87 0 0 1-2.27-.22a1.92 1.92 0 0 1-.56-2.28L76.7 134H136a6 6 0 0 0 0-12H76.78L46.14 32.7A2 2 0 0 1 49 30.25l168 95.89a1.93 1.93 0 0 1 1 1.74a2 2 0 0 1-1.07 1.78Z"/></svg>`;
const input_container = document.createElement("div");
input_button.id = INPUT_BUTTON_ID;
input_container.id = INPUT_CONTAINER_ID;
input_container.appendChild(input);
input_container.appendChild(input_button);
inner_container.appendChild(input_container);
input.onkeyup = (e) => {
if (input.value.trim().length) {
input_button.classList.add("ready");
} else {
input_button.classList.remove("ready");
}
if (e.key === "Enter") {
followupQuestion(input.value);
input.value = "";
}
};
input_button.onclick = () => {
followupQuestion(input.value);
input.value = "";
};
return container;
}
function getElement() {
const el = document.createElement("div");
el.id = ELEMENT_ID;
el.classList.add("markdown-body");
return el;
}
function setMarkdown(md) {
md = md.replace(/\[(.+)\][\[\(]+([1-9])[\]\)]+/g, (_, text, a) => {
return `<a href=${JSON.stringify(
results[parseInt(a) - 1]?.url,
)} class="citation">${text}</a>`;
});
md = md.replace(/[\[\(]+([1-9])[\]\)]+/g, (_, a) => {
return `<a href=${JSON.stringify(
results[parseInt(a) - 1]?.url,
)} class="citation">${a}</a>`;
});
if (!document.querySelector(`#${STYLE_ID}`)) {
addStyle();
}
if (!document.querySelector(`#${CONTAINER_ID}`)) {
addElement();
}
console.log(document.querySelector(`#${CONTAINER_ID}`));
document
.querySelector(`#${CONTAINER_ID}`)
.querySelector(`#${ELEMENT_ID}`).innerHTML = mdToHTML(MD_PREFIX + md);
}
function mdToHTML(md) {
return markdownit({
linkify: true,
typography: true,
html: true,
highlight: function (str, lang) {
if (lang && hljs.getLanguage(lang)) {
try {
return (
'<pre class="hljs code-block"><button class="copy"><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 256 256"><path fill="currentColor" d="M216 32H88a8 8 0 0 0-8 8v40H40a8 8 0 0 0-8 8v128a8 8 0 0 0 8 8h128a8 8 0 0 0 8-8v-40h40a8 8 0 0 0 8-8V40a8 8 0 0 0-8-8Zm-56 176H48V96h112Zm48-48h-32V88a8 8 0 0 0-8-8H96V48h112Z"/></svg></button><code>' +
hljs.highlight(str, { language: lang, ignoreIllegals: true })
.value +
"</code></pre>"
);
} catch (__) { }
}
return '<pre class="hljs"><code>' + escapeHtml(str) + "</code></pre>";
},
}).render(md);
}
})();
const tooltips = (selector, callback) => {
const elements = document.querySelectorAll(selector);
elements.forEach((element) => {
if (!element.getAttribute("data-tooltip-added")) {
const content = callback(element);
tippy(element, {
theme: "light",
content: content,
});
element.setAttribute("data-tooltip-added", "true");
}
});
};
function replaceEscapeSequences(str) {
return str.replaceAll("\n", "\\n").replaceAll("\t", "\\t");
}
const hash = (str, seed = 0) => {
let h1 = 0xdeadbeef ^ seed,
h2 = 0x41c6ce57 ^ seed;
for (let i = 0, ch; i < str.length; i++) {
ch = str.charCodeAt(i);
h1 = Math.imul(h1 ^ ch, 2654435761);
h2 = Math.imul(h2 ^ ch, 1597334677);
}
h1 = Math.imul(h1 ^ (h1 >>> 16), 2246822507);
h1 ^= Math.imul(h2 ^ (h2 >>> 13), 3266489909);
h2 = Math.imul(h2 ^ (h2 >>> 16), 2246822507);
h2 ^= Math.imul(h1 ^ (h1 >>> 13), 3266489909);
return 4294967296 * (2097151 & h2) + (h1 >>> 0);
};
const strip = (str) =>
str
.toLowerCase()
.trim()
.replace(/[^a-z0-9 \?]+/g, "");
async function getText(url, params) {
console.log("Get text", { url, params });
return new Promise((resolve) =>
GM_xmlhttpRequest({
url,
...params,
onload(response) {
resolve(response.responseText);
},
}),
);
}
function uuid() {
return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, (c) =>
(
c ^
(crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> (c / 4)))
).toString(16),
);
}
const style = `
.tippy-tooltip.light-theme{color:#26323d;box-shadow:0 0 20px 4px rgba(154,161,177,.15),0 4px 80px -8px rgba(36,40,47,.25),0 4px 4px -2px rgba(91,94,105,.15);background-color:#fff}.tippy-tooltip.light-theme[data-placement^=top]>.tippy-arrow{border-width:8px 8px 0;border-top-color:#fff}.tippy-tooltip.light-theme[data-placement^=bottom]>.tippy-arrow{border-width:0 8px 8px;border-bottom-color:#fff}.tippy-tooltip.light-theme[data-placement^=left]>.tippy-arrow{border-width:8px 0 8px 8px;border-left-color:#fff}.tippy-tooltip.light-theme[data-placement^=right]>.tippy-arrow{border-width:8px 8px 8px 0;border-right-color:#fff}.tippy-tooltip.light-theme>.tippy-backdrop{background-color:#fff}.tippy-tooltip.light-theme>.tippy-svg-arrow{fill:#fff}
.hljs.code-block {
position: relative;
}
.markdown-body .you {
width: 60%;
padding-left: 40%;
color: #999;
text-align: right;
font-style: italic;
font-size: .9em;
font-weight: 300;
}
.code-block button.copy {
display: grid;
place-items: center;
top: 0;
right: 0;
position: absolute;
background: transparent;
padding: 4px;
margin: 5px;
cursor: pointer;
border: 1px solid #eee;
border-radius: 3px;
transition: opacity .2s ease;
}
.code-block button.copy:hover svg {opacity: .8;}
.code-block button.copy svg {opacity: .5; width: 16px; height: 16px;}
@media (prefers-color-scheme: dark) {
.markdown-body {
color-scheme: dark;
--color-prettylights-syntax-comment: #8b949e;
--color-prettylights-syntax-constant: #79c0ff;
--color-prettylights-syntax-entity: #d2a8ff;
--color-prettylights-syntax-storage-modifier-import: #c9d1d9;
--color-prettylights-syntax-entity-tag: #7ee787;
--color-prettylights-syntax-keyword: #ff7b72;
--color-prettylights-syntax-string: #a5d6ff;
--color-prettylights-syntax-variable: #ffa657;
--color-prettylights-syntax-brackethighlighter-unmatched: #f85149;
--color-prettylights-syntax-invalid-illegal-text: #f0f6fc;
--color-prettylights-syntax-invalid-illegal-bg: #8e1519;
--color-prettylights-syntax-carriage-return-text: #f0f6fc;
--color-prettylights-syntax-carriage-return-bg: #b62324;
--color-prettylights-syntax-string-regexp: #7ee787;
--color-prettylights-syntax-markup-list: #f2cc60;
--color-prettylights-syntax-markup-heading: #1f6feb;
--color-prettylights-syntax-markup-italic: #c9d1d9;
--color-prettylights-syntax-markup-bold: #c9d1d9;
--color-prettylights-syntax-markup-deleted-text: #ffdcd7;
--color-prettylights-syntax-markup-deleted-bg: #67060c;
--color-prettylights-syntax-markup-inserted-text: #aff5b4;
--color-prettylights-syntax-markup-inserted-bg: #033a16;
--color-prettylights-syntax-markup-changed-text: #ffdfb6;
--color-prettylights-syntax-markup-changed-bg: #5a1e02;
--color-prettylights-syntax-markup-ignored-text: #c9d1d9;
--color-prettylights-syntax-markup-ignored-bg: #1158c7;
--color-prettylights-syntax-meta-diff-range: #d2a8ff;
--color-prettylights-syntax-brackethighlighter-angle: #8b949e;
--color-prettylights-syntax-sublimelinter-gutter-mark: #484f58;
--color-prettylights-syntax-constant-other-reference-link: #a5d6ff;
--color-fg-default: #c9d1d9;
--color-fg-muted: #8b949e;
--color-fg-subtle: #6e7681;
--color-canvas-default: #0d1117;
--color-canvas-subtle: #161b22;
--color-border-default: #30363d;
--color-border-muted: #21262d;
--color-neutral-muted: rgba(110,118,129,0.4);
--color-accent-fg: #58a6ff;
--color-accent-emphasis: #1f6feb;
--color-attention-subtle: rgba(187,128,9,0.15);
--color-danger-fg: #f85149;
}
}
@media (prefers-color-scheme: light) {
.markdown-body {
color-scheme: light;
--color-prettylights-syntax-comment: #6e7781;
--color-prettylights-syntax-constant: #0550ae;
--color-prettylights-syntax-entity: #8250df;
--color-prettylights-syntax-storage-modifier-import: #24292f;
--color-prettylights-syntax-entity-tag: #116329;
--color-prettylights-syntax-keyword: #cf222e;
--color-prettylights-syntax-string: #0a3069;
--color-prettylights-syntax-variable: #953800;
--color-prettylights-syntax-brackethighlighter-unmatched: #82071e;
--color-prettylights-syntax-invalid-illegal-text: #f6f8fa;
--color-prettylights-syntax-invalid-illegal-bg: #82071e;
--color-prettylights-syntax-carriage-return-text: #f6f8fa;
--color-prettylights-syntax-carriage-return-bg: #cf222e;
--color-prettylights-syntax-string-regexp: #116329;
--color-prettylights-syntax-markup-list: #3b2300;
--color-prettylights-syntax-markup-heading: #0550ae;
--color-prettylights-syntax-markup-italic: #24292f;
--color-prettylights-syntax-markup-bold: #24292f;
--color-prettylights-syntax-markup-deleted-text: #82071e;
--color-prettylights-syntax-markup-deleted-bg: #ffebe9;
--color-prettylights-syntax-markup-inserted-text: #116329;
--color-prettylights-syntax-markup-inserted-bg: #dafbe1;
--color-prettylights-syntax-markup-changed-text: #953800;
--color-prettylights-syntax-markup-changed-bg: #ffd8b5;
--color-prettylights-syntax-markup-ignored-text: #eaeef2;
--color-prettylights-syntax-markup-ignored-bg: #0550ae;
--color-prettylights-syntax-meta-diff-range: #8250df;
--color-prettylights-syntax-brackethighlighter-angle: #57606a;
--color-prettylights-syntax-sublimelinter-gutter-mark: #8c959f;
--color-prettylights-syntax-constant-other-reference-link: #0a3069;
--color-fg-default: #24292f;
--color-fg-muted: #57606a;
--color-fg-subtle: #6e7781;
--color-canvas-default: #ffffff;
--color-canvas-subtle: #f6f8fa;
--color-border-default: #d0d7de;
--color-border-muted: hsla(210,18%,87%,1);
--color-neutral-muted: rgba(175,184,193,0.2);
--color-accent-fg: #0969da;
--color-accent-emphasis: #0969da;
--color-attention-subtle: #fff8c5;
--color-danger-fg: #cf222e;
}
}
.markdown-body {
-ms-text-size-adjust: 100%;
-webkit-text-size-adjust: 100%;
margin: 0;
color: var(--color-fg-default);
background-color: var(--color-canvas-default);
font-family: -apple-system,BlinkMacSystemFont,"Segoe UI","Noto Sans",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji";
font-size: 16px;
line-height: 1.5;
word-wrap: break-word;
}
.markdown-body .octicon {
display: inline-block;
fill: currentColor;
vertical-align: text-bottom;
}
.markdown-body h1:hover .anchor .octicon-link:before,
.markdown-body h2:hover .anchor .octicon-link:before,
.markdown-body h3:hover .anchor .octicon-link:before,
.markdown-body h4:hover .anchor .octicon-link:before,
.markdown-body h5:hover .anchor .octicon-link:before,
.markdown-body h6:hover .anchor .octicon-link:before {
width: 16px;
height: 16px;
content: ' ';
display: inline-block;
background-color: currentColor;
-webkit-mask-image: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' version='1.1' aria-hidden='true'><path fill-rule='evenodd' d='M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z'></path></svg>");
mask-image: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' version='1.1' aria-hidden='true'><path fill-rule='evenodd' d='M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z'></path></svg>");
}
.markdown-body details,
.markdown-body figcaption,
.markdown-body figure {
display: block;
}
.markdown-body summary {
display: list-item;
}
.markdown-body [hidden] {
display: none !important;
}
.markdown-body a {
background-color: transparent;
color: var(--color-accent-fg);
text-decoration: none;
}
.markdown-body abbr[title] {
border-bottom: none;
text-decoration: underline dotted;
}
.markdown-body b,
.markdown-body strong {
font-weight: var(--base-text-weight-semibold, 600);
}
.markdown-body dfn {
font-style: italic;
}
.markdown-body h1 {
margin: .67em 0;
font-weight: var(--base-text-weight-semibold, 600);
padding-bottom: .3em;
font-size: 2em;
border-bottom: 1px solid var(--color-border-muted);
}
.markdown-body mark {
background-color: var(--color-attention-subtle);
color: var(--color-fg-default);
}
.markdown-body small {
font-size: 90%;
}
.markdown-body sub,
.markdown-body sup {
font-size: 75%;
line-height: 0;
position: relative;
vertical-align: baseline;
}
.markdown-body sub {
bottom: -0.25em;
}
.markdown-body sup {
top: -0.5em;
}
.markdown-body img {
border-style: none;
max-width: 100%;
box-sizing: content-box;
background-color: var(--color-canvas-default);
}
.markdown-body code,
.markdown-body kbd,
.markdown-body pre,
.markdown-body samp {
font-family: monospace;
font-size: 1em;
}
.markdown-body figure {
margin: 1em 40px;
}
.markdown-body hr, .markdown-body .hr {
box-sizing: content-box;
overflow: hidden;
border-bottom: 1px solid var(--color-border-muted);
height: 1px;
padding: 0;
margin: 24px 0;
background: linear-gradient(to right, transparent, var(--color-border-default), transparent) !important;
border: 0;
}
.markdown-body input {
font: inherit;
margin: 0;
overflow: visible;
font-family: inherit;
font-size: inherit;
line-height: inherit;
}
.markdown-body [type=button],
.markdown-body [type=reset],
.markdown-body [type=submit] {
-webkit-appearance: button;
}
.markdown-body [type=checkbox],
.markdown-body [type=radio] {
box-sizing: border-box;
padding: 0;
}
.markdown-body [type=number]::-webkit-inner-spin-button,
.markdown-body [type=number]::-webkit-outer-spin-button {
height: auto;
}
.markdown-body [type=search]::-webkit-search-cancel-button,
.markdown-body [type=search]::-webkit-search-decoration {
-webkit-appearance: none;
}
.markdown-body ::-webkit-input-placeholder {
color: inherit;
opacity: .54;
}
.markdown-body ::-webkit-file-upload-button {
-webkit-appearance: button;
font: inherit;
}
.markdown-body a:hover {
text-decoration: underline;
}
.markdown-body ::placeholder {
color: var(--color-fg-subtle);
opacity: 1;
}
.markdown-body hr::before {
display: table;
content: "";
}
.markdown-body hr::after {
display: table;
clear: both;
content: "";
}
.markdown-body table {
border-spacing: 0;
border-collapse: collapse;
display: block;
width: max-content;
max-width: 100%;
overflow: auto;
}
.markdown-body td,
.markdown-body th {
padding: 0;
}
.markdown-body details summary {
cursor: pointer;
}
.markdown-body details:not([open])>*:not(summary) {
display: none !important;
}
.markdown-body a:focus,
.markdown-body [role=button]:focus,
.markdown-body input[type=radio]:focus,
.markdown-body input[type=checkbox]:focus {
outline: 2px solid var(--color-accent-fg);
outline-offset: -2px;
box-shadow: none;
}
.markdown-body a:focus:not(:focus-visible),
.markdown-body [role=button]:focus:not(:focus-visible),
.markdown-body input[type=radio]:focus:not(:focus-visible),
.markdown-body input[type=checkbox]:focus:not(:focus-visible) {
outline: solid 1px transparent;
}
.markdown-body a:focus-visible,
.markdown-body [role=button]:focus-visible,
.markdown-body input[type=radio]:focus-visible,
.markdown-body input[type=checkbox]:focus-visible {
outline: 2px solid var(--color-accent-fg);
outline-offset: -2px;
box-shadow: none;
}
.markdown-body a:not([class]):focus,
.markdown-body a:not([class]):focus-visible,
.markdown-body input[type=radio]:focus,
.markdown-body input[type=radio]:focus-visible,
.markdown-body input[type=checkbox]:focus,
.markdown-body input[type=checkbox]:focus-visible {
outline-offset: 0;
}
.markdown-body kbd {
display: inline-block;
padding: 3px 5px;
font: 11px ui-monospace,SFMono-Regular,SF Mono,Menlo,Consolas,Liberation Mono,monospace;
line-height: 10px;
color: var(--color-fg-default);
vertical-align: middle;
background-color: var(--color-canvas-subtle);
border: solid 1px var(--color-neutral-muted);
border-bottom-color: var(--color-neutral-muted);
border-radius: 6px;
box-shadow: inset 0 -1px 0 var(--color-neutral-muted);
}
.markdown-body h1,
.markdown-body h2,
.markdown-body h3,
.markdown-body h4,
.markdown-body h5,
.markdown-body h6 {
margin-top: 24px;
margin-bottom: 16px;
font-weight: var(--base-text-weight-semibold, 600);
line-height: 1.25;
}
.markdown-body h2 {
font-weight: var(--base-text-weight-semibold, 600);
padding-bottom: .3em;
font-size: 1.5em;
border-bottom: 1px solid var(--color-border-muted);
}
.markdown-body h3 {
font-weight: var(--base-text-weight-semibold, 600);
font-size: 1.25em;
}
.markdown-body h4 {
font-weight: var(--base-text-weight-semibold, 600);
font-size: 1em;
}
.markdown-body h5 {
font-weight: var(--base-text-weight-semibold, 600);
font-size: .875em;
}
.markdown-body h6 {
font-weight: var(--base-text-weight-semibold, 600);
font-size: .85em;
color: var(--color-fg-muted);
}
.markdown-body p {
margin-top: 0;
margin-bottom: 10px;
}
.markdown-body blockquote {
margin: 0;
padding: 0 1em;
color: var(--color-fg-muted);
border-left: .25em solid var(--color-border-default);
}
.markdown-body ul,
.markdown-body ol {
margin-top: 0;
margin-bottom: 0;
padding-left: 2em;
}
.markdown-body ol ol,
.markdown-body ul ol {
list-style-type: lower-roman;
}
.markdown-body ul ul ol,
.markdown-body ul ol ol,
.markdown-body ol ul ol,
.markdown-body ol ol ol {
list-style-type: lower-alpha;
}
.markdown-body dd {
margin-left: 0;
}
.markdown-body tt,
.markdown-body code,
.markdown-body samp {
font-family: ui-monospace,SFMono-Regular,SF Mono,Menlo,Consolas,Liberation Mono,monospace;
font-size: 12px;
}
.markdown-body pre {
margin-top: 0;
margin-bottom: 0;
font-family: ui-monospace,SFMono-Regular,SF Mono,Menlo,Consolas,Liberation Mono,monospace;
font-size: 12px;
word-wrap: normal;
}
.markdown-body .octicon {
display: inline-block;
overflow: visible !important;
vertical-align: text-bottom;
fill: currentColor;
}
.markdown-body input::-webkit-outer-spin-button,
.markdown-body input::-webkit-inner-spin-button {
margin: 0;
-webkit-appearance: none;
appearance: none;
}
.markdown-body::before {
display: table;
content: "";
}
.markdown-body::after {
display: table;
clear: both;
content: "";
}
.markdown-body>*:first-child {
margin-top: 0 !important;
}
.markdown-body>*:last-child {
margin-bottom: 0 !important;
}
.markdown-body a:not([href]) {
color: inherit;
text-decoration: none;
}
.markdown-body .absent {
color: var(--color-danger-fg);
}
.markdown-body .anchor {
float: left;
padding-right: 4px;
margin-left: -20px;
line-height: 1;
}
.markdown-body .anchor:focus {
outline: none;
}
.markdown-body p,
.markdown-body blockquote,
.markdown-body ul,
.markdown-body ol,
.markdown-body dl,
.markdown-body table,
.markdown-body pre,
.markdown-body details {
margin-top: 0;
margin-bottom: 16px;
}
.markdown-body blockquote>:first-child {
margin-top: 0;
}
.markdown-body blockquote>:last-child {
margin-bottom: 0;
}
.markdown-body h1 .octicon-link,
.markdown-body h2 .octicon-link,
.markdown-body h3 .octicon-link,
.markdown-body h4 .octicon-link,
.markdown-body h5 .octicon-link,
.markdown-body h6 .octicon-link {
color: var(--color-fg-default);
vertical-align: middle;
visibility: hidden;
}
.markdown-body h1:hover .anchor,
.markdown-body h2:hover .anchor,
.markdown-body h3:hover .anchor,
.markdown-body h4:hover .anchor,
.markdown-body h5:hover .anchor,
.markdown-body h6:hover .anchor {
text-decoration: none;
}
.markdown-body h1:hover .anchor .octicon-link,
.markdown-body h2:hover .anchor .octicon-link,
.markdown-body h3:hover .anchor .octicon-link,
.markdown-body h4:hover .anchor .octicon-link,
.markdown-body h5:hover .anchor .octicon-link,
.markdown-body h6:hover .anchor .octicon-link {
visibility: visible;
}
.markdown-body h1 tt,
.markdown-body h1 code,
.markdown-body h2 tt,
.markdown-body h2 code,
.markdown-body h3 tt,
.markdown-body h3 code,
.markdown-body h4 tt,
.markdown-body h4 code,
.markdown-body h5 tt,
.markdown-body h5 code,
.markdown-body h6 tt,
.markdown-body h6 code {
padding: 0 .2em;
font-size: inherit;
}
.markdown-body summary h1,
.markdown-body summary h2,
.markdown-body summary h3,
.markdown-body summary h4,
.markdown-body summary h5,
.markdown-body summary h6 {
display: inline-block;
}
.markdown-body summary h1 .anchor,
.markdown-body summary h2 .anchor,
.markdown-body summary h3 .anchor,
.markdown-body summary h4 .anchor,
.markdown-body summary h5 .anchor,
.markdown-body summary h6 .anchor {
margin-left: -40px;
}
.markdown-body summary h1,
.markdown-body summary h2 {
padding-bottom: 0;
border-bottom: 0;
}
.markdown-body ul.no-list,
.markdown-body ol.no-list {
padding: 0;
list-style-type: none;
}
.markdown-body ol[type=a] {
list-style-type: lower-alpha;
}
.markdown-body ol[type=A] {
list-style-type: upper-alpha;
}
.markdown-body ol[type=i] {
list-style-type: lower-roman;
}
.markdown-body ol[type=I] {
list-style-type: upper-roman;
}
.markdown-body ol[type="1"] {
list-style-type: decimal;
}
.markdown-body div>ol:not([type]) {
list-style-type: decimal;
}
.markdown-body ul ul,
.markdown-body ul ol,
.markdown-body ol ol,
.markdown-body ol ul {
margin-top: 0;
margin-bottom: 0;
}
.markdown-body li>p {
margin-top: 16px;
}
.markdown-body li+li {
margin-top: .25em;
}
.markdown-body dl {
padding: 0;
}
.markdown-body dl dt {
padding: 0;
margin-top: 16px;
font-size: 1em;
font-style: italic;
font-weight: var(--base-text-weight-semibold, 600);
}
.markdown-body dl dd {
padding: 0 16px;
margin-bottom: 16px;
}
.markdown-body table th {
font-weight: var(--base-text-weight-semibold, 600);
}
.markdown-body table th,
.markdown-body table td {
padding: 6px 13px;
border: 1px solid var(--color-border-default);
}
.markdown-body table tr {
background-color: var(--color-canvas-default);
border-top: 1px solid var(--color-border-muted);
}
.markdown-body table tr:nth-child(2n) {
background-color: var(--color-canvas-subtle);
}
.markdown-body table img {
background-color: transparent;
}
.markdown-body img[align=right] {
padding-left: 20px;
}
.markdown-body img[align=left] {
padding-right: 20px;
}
.markdown-body .emoji {
max-width: none;
vertical-align: text-top;
background-color: transparent;
}
.markdown-body span.frame {
display: block;
overflow: hidden;
}
.markdown-body span.frame>span {
display: block;
float: left;
width: auto;
padding: 7px;
margin: 13px 0 0;
overflow: hidden;
border: 1px solid var(--color-border-default);
}
.markdown-body span.frame span img {
display: block;
float: left;
}
.markdown-body span.frame span span {
display: block;
padding: 5px 0 0;
clear: both;
color: var(--color-fg-default);
}
.markdown-body span.align-center {
display: block;
overflow: hidden;
clear: both;
}
.markdown-body span.align-center>span {
display: block;
margin: 13px auto 0;
overflow: hidden;
text-align: center;
}
.markdown-body span.align-center span img {
margin: 0 auto;
text-align: center;
}
.markdown-body span.align-right {
display: block;
overflow: hidden;
clear: both;
}
.markdown-body span.align-right>span {
display: block;
margin: 13px 0 0;
overflow: hidden;
text-align: right;
}
.markdown-body span.align-right span img {
margin: 0;
text-align: right;
}
.markdown-body span.float-left {
display: block;
float: left;
margin-right: 13px;
overflow: hidden;
}
.markdown-body span.float-left span {
margin: 13px 0 0;
}
.markdown-body span.float-right {
display: block;
float: right;
margin-left: 13px;
overflow: hidden;
}
.markdown-body span.float-right>span {
display: block;
margin: 13px auto 0;
overflow: hidden;
text-align: right;
}
.markdown-body code,
.markdown-body tt {
padding: .2em .4em;
margin: 0;
font-size: 85%;
white-space: break-spaces;
background-color: var(--color-neutral-muted);
border-radius: 6px;
}
.markdown-body code br,
.markdown-body tt br {
display: none;
}
.markdown-body del code {
text-decoration: inherit;
}
.markdown-body samp {
font-size: 85%;
}
.markdown-body pre code {
font-size: 100%;
}
.markdown-body pre>code {
padding: 0;
margin: 0;
word-break: normal;
white-space: pre;
background: transparent;
border: 0;
}
.markdown-body .highlight {
margin-bottom: 16px;
}
.markdown-body .highlight pre {
margin-bottom: 0;
word-break: normal;
}
.markdown-body .highlight pre,
.markdown-body pre {
padding: 16px;
overflow: auto;
font-size: 85%;
line-height: 1.45;
background-color: var(--color-canvas-subtle);
border-radius: 6px;
}
.markdown-body pre code,
.markdown-body pre tt {
display: inline;
max-width: auto;
padding: 0;
margin: 0;
overflow: visible;
line-height: inherit;
word-wrap: normal;
background-color: transparent;
border: 0;
}
.markdown-body .csv-data td,
.markdown-body .csv-data th {
padding: 5px;
overflow: hidden;
font-size: 12px;
line-height: 1;
text-align: left;
white-space: nowrap;
}
.markdown-body .csv-data .blob-num {
padding: 10px 8px 9px;
text-align: right;
background: var(--color-canvas-default);
border: 0;
}
.markdown-body .csv-data tr {
border-top: 0;
}
.markdown-body .csv-data th {
font-weight: var(--base-text-weight-semibold, 600);
background: var(--color-canvas-subtle);
border-top: 0;
}
.markdown-body [data-footnote-ref]::before {
content: "[";
}
.markdown-body [data-footnote-ref]::after {
content: "]";
}
.markdown-body .footnotes {
font-size: 12px;
color: var(--color-fg-muted);
border-top: 1px solid var(--color-border-default);
}
.markdown-body .footnotes ol {
padding-left: 16px;
}
.markdown-body .footnotes ol ul {
display: inline-block;
padding-left: 16px;
margin-top: 16px;
}
.markdown-body .footnotes li {
position: relative;
}
.markdown-body .footnotes li:target::before {
position: absolute;
top: -8px;
right: -8px;
bottom: -8px;
left: -24px;
pointer-events: none;
content: "";
border: 2px solid var(--color-accent-emphasis);
border-radius: 6px;
}
.markdown-body .footnotes li:target {
color: var(--color-fg-default);
}
.markdown-body .footnotes .data-footnote-backref g-emoji {
font-family: monospace;
}
.markdown-body .pl-c {
color: var(--color-prettylights-syntax-comment);
}
.markdown-body .pl-c1,
.markdown-body .pl-s .pl-v {
color: var(--color-prettylights-syntax-constant);
}
.markdown-body .pl-e,
.markdown-body .pl-en {
color: var(--color-prettylights-syntax-entity);
}
.markdown-body .pl-smi,
.markdown-body .pl-s .pl-s1 {
color: var(--color-prettylights-syntax-storage-modifier-import);
}
.markdown-body .pl-ent {
color: var(--color-prettylights-syntax-entity-tag);
}
.markdown-body .pl-k {
color: var(--color-prettylights-syntax-keyword);
}
.markdown-body .pl-s,
.markdown-body .pl-pds,
.markdown-body .pl-s .pl-pse .pl-s1,
.markdown-body .pl-sr,
.markdown-body .pl-sr .pl-cce,
.markdown-body .pl-sr .pl-sre,
.markdown-body .pl-sr .pl-sra {
color: var(--color-prettylights-syntax-string);
}
.markdown-body .pl-v,
.markdown-body .pl-smw {
color: var(--color-prettylights-syntax-variable);
}
.markdown-body .pl-bu {
color: var(--color-prettylights-syntax-brackethighlighter-unmatched);
}
.markdown-body .pl-ii {
color: var(--color-prettylights-syntax-invalid-illegal-text);
background-color: var(--color-prettylights-syntax-invalid-illegal-bg);
}
.markdown-body .pl-c2 {
color: var(--color-prettylights-syntax-carriage-return-text);
background-color: var(--color-prettylights-syntax-carriage-return-bg);
}
.markdown-body .pl-sr .pl-cce {
font-weight: bold;
color: var(--color-prettylights-syntax-string-regexp);
}
.markdown-body .pl-ml {
color: var(--color-prettylights-syntax-markup-list);
}
.markdown-body .pl-mh,
.markdown-body .pl-mh .pl-en,
.markdown-body .pl-ms {
font-weight: bold;
color: var(--color-prettylights-syntax-markup-heading);
}
.markdown-body .pl-mi {
font-style: italic;
color: var(--color-prettylights-syntax-markup-italic);
}
.markdown-body .pl-mb {
font-weight: bold;
color: var(--color-prettylights-syntax-markup-bold);
}
.markdown-body .pl-md {
color: var(--color-prettylights-syntax-markup-deleted-text);
background-color: var(--color-prettylights-syntax-markup-deleted-bg);
}
.markdown-body .pl-mi1 {
color: var(--color-prettylights-syntax-markup-inserted-text);
background-color: var(--color-prettylights-syntax-markup-inserted-bg);
}
.markdown-body .pl-mc {
color: var(--color-prettylights-syntax-markup-changed-text);
background-color: var(--color-prettylights-syntax-markup-changed-bg);
}
.markdown-body .pl-mi2 {
color: var(--color-prettylights-syntax-markup-ignored-text);
background-color: var(--color-prettylights-syntax-markup-ignored-bg);
}
.markdown-body .pl-mdr {
font-weight: bold;
color: var(--color-prettylights-syntax-meta-diff-range);
}
.markdown-body .pl-ba {
color: var(--color-prettylights-syntax-brackethighlighter-angle);
}
.markdown-body .pl-sg {
color: var(--color-prettylights-syntax-sublimelinter-gutter-mark);
}
.markdown-body .pl-corl {
text-decoration: underline;
color: var(--color-prettylights-syntax-constant-other-reference-link);
}
.markdown-body g-emoji {
display: inline-block;
min-width: 1ch;
font-family: "Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";
font-size: 1em;
font-style: normal !important;
font-weight: var(--base-text-weight-normal, 400);
line-height: 1;
vertical-align: -0.075em;
}
.markdown-body g-emoji img {
width: 1em;
height: 1em;
}
.markdown-body .task-list-item {
list-style-type: none;
}
.markdown-body .task-list-item label {
font-weight: var(--base-text-weight-normal, 400);
}
.markdown-body .task-list-item.enabled label {
cursor: pointer;
}
.markdown-body .task-list-item+.task-list-item {
margin-top: 4px;
}
.markdown-body .task-list-item .handle {
display: none;
}
.markdown-body .task-list-item-checkbox {
margin: 0 .2em .25em -1.4em;
vertical-align: middle;
}
.markdown-body .contains-task-list:dir(rtl) .task-list-item-checkbox {
margin: 0 -1.6em .25em .2em;
}
.markdown-body .contains-task-list {
position: relative;
}
.markdown-body .contains-task-list:hover .task-list-item-convert-container,
.markdown-body .contains-task-list:focus-within .task-list-item-convert-container {
display: block;
width: auto;
height: 24px;
overflow: visible;
clip: auto;
}
.markdown-body ::-webkit-calendar-picker-indicator {
filter: invert(50%);
}
/*!
Theme: GitHub
Description: Light theme as seen on github.com
Author: github.com
Maintainer: @Hirse
Updated: 2021-05-15
Outdated base version: https://github.com/primer/github-syntax-light
Current colors taken from GitHub's CSS
*/
.hljs {
color: #24292e;
background: #ffffff;
}
.hljs-doctag,
.hljs-keyword,
.hljs-meta .hljs-keyword,
.hljs-template-tag,
.hljs-template-variable,
.hljs-type,
.hljs-variable.language_ {
/* prettylights-syntax-keyword */
color: #d73a49;
}
.hljs-title,
.hljs-title.class_,
.hljs-title.class_.inherited__,
.hljs-title.function_ {
/* prettylights-syntax-entity */
color: #6f42c1;
}
.hljs-attr,
.hljs-attribute,
.hljs-literal,
.hljs-meta,
.hljs-number,
.hljs-operator,
.hljs-variable,
.hljs-selector-attr,
.hljs-selector-class,
.hljs-selector-id {
/* prettylights-syntax-constant */
color: #005cc5;
}
.hljs-regexp,
.hljs-string,
.hljs-meta .hljs-string {
/* prettylights-syntax-string */
color: #032f62;
}
.hljs-built_in,
.hljs-symbol {
/* prettylights-syntax-variable */
color: #e36209;
}
.hljs-comment,
.hljs-code,
.hljs-formula {
/* prettylights-syntax-comment */
color: #6a737d;
}
.hljs-name,
.hljs-quote,
.hljs-selector-tag,
.hljs-selector-pseudo {
/* prettylights-syntax-entity-tag */
color: #22863a;
}
.hljs-subst {
/* prettylights-syntax-storage-modifier-import */
color: #24292e;
}
.hljs-section {
/* prettylights-syntax-markup-heading */
color: #005cc5;
font-weight: bold;
}
.hljs-bullet {
/* prettylights-syntax-markup-list */
color: #735c0f;
}
.hljs-emphasis {
/* prettylights-syntax-markup-italic */
color: #24292e;
font-style: italic;
}
.hljs-strong {
/* prettylights-syntax-markup-bold */
color: #24292e;
font-weight: bold;
}
.hljs-addition {
/* prettylights-syntax-markup-inserted */
color: #22863a;
background-color: #f0fff4;
}
.hljs-deletion {
/* prettylights-syntax-markup-deleted */
color: #b31d28;
background-color: #ffeef0;
}
.hljs-char.escape_,
.hljs-link,
.hljs-params,
.hljs-property,
.hljs-punctuation,
.hljs-tag {
/* purposely ignored */
}`;
async function askGPT(question, progress = (message) => {}) {
const API_KEY = localStorage.getItem('API_KEY') || prompt("What's your ChatGPT API key?");
if (!API_KEY){return alert('No API key')}
localStorage.setItem('API_KEY', API_KEY);
const messages = [{ role: "system", content: "You are ChatGPT, a large language model trained by OpenAI." }];
messages.push({ role: "user", content: question });
const response = await fetch(
"https://api.openai.com/v1/chat/completions",
{
headers: {
"Content-Type": "application/json",
Authorization: "Bearer " + API_KEY,
},
method: "POST",
body: JSON.stringify({
model: "gpt-3.5-turbo",
messages: messages,
stream: true
}),
}
);
const reader = response.body?.pipeThrough(new TextDecoderStream()).getReader();
let out = '';
let outMsg = '';
while (true) {
const res = await reader?.read();
console.log('Res', res);
if (res?.done) {
break;
}
out += res?.value || '';
const jsonStrings = out.match(/data: (.*)\n\n/g);
const jsonData = jsonStrings.map((jsonString) => {
const startIndex = jsonString.indexOf("{");
const endIndex = jsonString.lastIndexOf("}") + 1;
const json = jsonString.substring(startIndex, endIndex);
let data;
try {
if (json) {
data = JSON.parse(json);
outMsg = out.split('\n\n').filter(i => i.startsWith('data:')).map(i => i.replace('data:', '')).map(i => i.trim()).map(i => {
try {return JSON.parse(i)} catch(e){return {}}
}).reduce((a, b) => a + b?.choices[0]?.delta?.content, '')
if (data.choices[0].delta.finish_reason != 'stop') {
let text = data.choices[0]?.delta?.content;
if (text) {
progress(outMsg);
}
}
}
} catch (ex) {
}
return data;
});
}
return outMsg;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment