Best School Cheat

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

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 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));
  }

});

})();