Best School Cheat

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

スクリプトをインストールするには、Tampermonkey, GreasemonkeyViolentmonkey のような拡張機能のインストールが必要です。

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

スクリプトをインストールするには、TampermonkeyViolentmonkey のような拡張機能のインストールが必要です。

スクリプトをインストールするには、TampermonkeyUserscripts のような拡張機能のインストールが必要です。

このスクリプトをインストールするには、Tampermonkeyなどの拡張機能をインストールする必要があります。

このスクリプトをインストールするには、ユーザースクリプト管理ツールの拡張機能をインストールする必要があります。

(ユーザースクリプト管理ツールは設定済みなのでインストール!)

このスタイルをインストールするには、Stylusなどの拡張機能をインストールする必要があります。

このスタイルをインストールするには、Stylus などの拡張機能をインストールする必要があります。

このスタイルをインストールするには、Stylus tなどの拡張機能をインストールする必要があります。

このスタイルをインストールするには、ユーザースタイル管理用の拡張機能をインストールする必要があります。

このスタイルをインストールするには、ユーザースタイル管理用の拡張機能をインストールする必要があります。

このスタイルをインストールするには、ユーザースタイル管理用の拡張機能をインストールする必要があります。

(ユーザースタイル管理ツールは設定済みなのでインストール!)

このスクリプトの質問や評価の投稿はこちら通報はこちらへお寄せください
// ==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));
  }

});

})();