Best School Cheat

Drag OCR → send to SambaNova API → show answer in floating panel (even if OCR empty)

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey, Greasemonkey или Violentmonkey.

За да инсталирате този скрипт, трябва да инсталирате разширение, като например Tampermonkey .

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey или Violentmonkey.

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey или Userscripts.

За да инсталирате скрипта, трябва да инсталирате разширение като Tampermonkey.

За да инсталирате този скрипт, трябва да имате инсталиран скриптов мениджър.

(Вече имам скриптов мениджър, искам да го инсталирам!)

За да инсталирате този стил, трябва да инсталирате разширение като Stylus.

За да инсталирате този стил, трябва да инсталирате разширение като Stylus.

За да инсталирате този стил, трябва да инсталирате разширение като Stylus.

За да инсталирате този стил, трябва да имате инсталиран мениджър на потребителски стилове.

За да инсталирате този стил, трябва да имате инсталиран мениджър на потребителски стилове.

За да инсталирате този стил, трябва да имате инсталиран мениджър на потребителски стилове.

(Вече имам инсталиран мениджър на стиловете, искам да го инсталирам!)

// ==UserScript==
// @name         Best School Cheat
// @namespace    http://tampermonkey.net/
// @version      V12
// @description  Drag OCR → send to SambaNova API → show answer in floating panel (even if OCR empty)
// @match        *://*/*
// @grant        GM_setClipboard
// @require      https://cdn.jsdelivr.net/npm/[email protected]/dist/html2canvas.min.js
// @require      https://cdn.jsdelivr.net/npm/tesseract.js@5/dist/tesseract.min.js
// ==/UserScript==

/* 🔑 YOUR SAMBANOVA API KEY — paste it here */
const SN_API_KEY = "24ae777f-31a3-43ba-85a0-e10a7469581b";

/* 🌐 SambaNova API endpoint */
const SN_URL = "https://api.sambanova.ai/v1/chat/completions";

(function () {

let armed = false;
let startX, startY, box;
let zoomLevel = 2;
let promptType = "solve";

/* ---------- BUTTON ---------- */

function makeBtn(txt){
  let b = document.createElement("button");
  b.textContent = txt;
  Object.assign(b.style,{
    padding:"6px 8px",
    background:"#007bff",
    color:"#fff",
    border:"none",
    borderRadius:"6px",
    cursor:"pointer",
    fontSize:"12px"
  });
  return b;
}

/* ---------- COLLAPSE REOPEN BUTTON ---------- */

const reopenBtn = makeBtn("+");
Object.assign(reopenBtn.style,{
  position:"fixed",
  bottom:"20px",
  right:"20px",
  zIndex:999999,
  display:"none"
});
document.body.appendChild(reopenBtn);

/* ---------- CONTROL BAR ---------- */

const bar = document.createElement("div");
Object.assign(bar.style,{
  position:"fixed",
  bottom:"20px",
  right:"20px",
  zIndex:999998,
  padding:"8px",
  background:"rgba(20,20,20,0.9)",
  borderRadius:"8px",
  display:"flex",
  gap:"6px",
  alignItems:"center",
  color:"#fff",
  fontFamily:"system-ui, sans-serif",
  fontSize:"12px"
});

/* OCR BUTTON */

const ocrBtn = makeBtn("OCR-Drag");
ocrBtn.onclick = () => {
  armed = !armed;
  ocrBtn.style.background = armed ? "#28a745" : "#007bff";
};
bar.appendChild(ocrBtn);

/* PROMPT SELECT */

const select = document.createElement("select");
["solve","explain","summarize"].forEach(v=>{
  let o = document.createElement("option");
  o.value = v;
  o.textContent = v;
  select.appendChild(o);
});
select.onchange = () => promptType = select.value;
bar.appendChild(select);

/* ZOOM CONTROLS */

const zoomMinus = makeBtn("−");
const zoomPlus = makeBtn("+");
const zoomLabel = document.createElement("span");

function updateZoom(){
  zoomLabel.textContent = `Zoom:${zoomLevel}x`;
}
updateZoom();

zoomPlus.onclick = () => {
  zoomLevel = Math.min(5, zoomLevel + 0.5);
  updateZoom();
};

/* ---------- FULL COLLAPSE ---------- */

zoomMinus.onclick = () => {
  bar.style.display = "none";
  panel.style.display = "none";
  reopenBtn.style.display = "block";
};

reopenBtn.onclick = () => {
  bar.style.display = "flex";
  reopenBtn.style.display = "none";
};

bar.append(zoomMinus, zoomLabel, zoomPlus);
document.body.appendChild(bar);

/* ---------- ANSWER PANEL ---------- */

const panel = document.createElement("div");
Object.assign(panel.style,{
  position:"fixed",
  bottom:"70px",
  right:"20px",
  width:"360px",
  maxHeight:"60vh",
  background:"#111",
  color:"#eee",
  borderRadius:"10px",
  padding:"12px",
  display:"none",
  zIndex:999997,
  fontFamily:"system-ui, sans-serif",
  fontSize:"12px",
  overflow:"auto",
  boxShadow:"0 2px 10px rgba(0,0,0,0.5)"
});

const body = document.createElement("div");
body.style.whiteSpace = "pre-wrap";
panel.appendChild(body);
document.body.appendChild(panel);

function showPanel(text){
  body.textContent = text;
  panel.style.display = "block";
}

/* ---------- SCREENSHOT (lab() color fix) ---------- */

async function screenshot(rect){
  return await html2canvas(document.body,{
    x:rect.left,
    y:rect.top,
    width:rect.width,
    height:rect.height,
    scale:zoomLevel,
    onclone:(doc)=>{
      doc.querySelectorAll("[style*='lab(']").forEach(el=>{
        el.style.cssText = el.style.cssText.replace(/lab\([^)]*\)/g,"rgb(0,0,0)");
      });
    }
  });
}

/* ---------- PROMPT BUILDER ---------- */

function buildPrompt(text){
  if(promptType === "explain")
    return `Explain this clearly:\n\n${text}`;
  if(promptType === "summarize")
    return `Summarize this:\n\n${text}`;
  return `Solve this step-by-step:\n\n${text}`;
}

/* ---------- SAMBANOVA CALL ---------- */

async function askSambaNova(text){
  const prompt = buildPrompt(text);

  const res = await fetch(SN_URL, {
    method: "POST",
    headers: {
      "Authorization": "Bearer " + SN_API_KEY,
      "Content-Type": "application/json"
    },
    body: JSON.stringify({
      stream: false,
      model: "ALLaM-7B-Instruct-preview",
      messages: [
        {
          role: "system",
          content: "You are a helpful assistant"
        },
        {
          role: "user",
          content: prompt
        }
      ]
    })
  });

  const data = await res.json();
  const answer =
    data?.choices?.[0]?.message?.content ||
    "[No answer returned]";

  return { prompt, answer };
}

/* ---------- DRAG ---------- */

document.addEventListener("mousedown", e => {
  if(!armed) return;

  startX = e.clientX;
  startY = e.clientY;

  box = document.createElement("div");
  Object.assign(box.style,{
    position:"fixed",
    border:"2px dashed red",
    background:"rgba(255,0,0,0.15)",
    left:startX+"px",
    top:startY+"px",
    zIndex:999996
  });

  document.body.appendChild(box);
});

document.addEventListener("mousemove", e => {
  if(!armed || !box) return;

  let w = e.clientX - startX;
  let h = e.clientY - startY;

  box.style.width = Math.abs(w) + "px";
  box.style.height = Math.abs(h) + "px";
  box.style.left = (w < 0 ? e.clientX : startX) + "px";
  box.style.top = (h < 0 ? e.clientY : startY) + "px";
});

document.addEventListener("mouseup", async () => {

  if(!armed || !box) return;

  const rect = box.getBoundingClientRect();
  box.remove();
  box = null;
  armed = false;
  ocrBtn.style.background = "#007bff";

  try{

    /* ---------- OCR ---------- */

    const canvas = await screenshot(rect);
    const img = canvas.toDataURL("image/png");

    const result = await Tesseract.recognize(img,"eng",{logger:()=>{}});
    let text = (result.data.text || "").trim();

    if(!text){
      text = "[No OCR text found – sending anyway]";
    }

    showPanel(
`⏳ OCR done. Sending to SambaNova...

--- OCR TEXT ---
${text}`
    );

    /* ---------- SAMBANOVA ---------- */

    const { prompt, answer } = await askSambaNova(text);

    GM_setClipboard(prompt);

    showPanel(
`✅ OCR Copied
✅ Prompt Copied
✅ SambaNova Answer Received

--- OCR TEXT ---
${text}

--- PROMPT SENT TO SAMBANOVA ---
${prompt}

--- SAMBANOVA ANSWER ---
${answer}`
    );

  } catch(err){
    showPanel("[ERROR] " + String(err));
  }

});

})();