Spaces:
Running
Running
Download index.html from illimax/kcbert-profanity: direct link, hf CLI and curl.
- Browser
- Download file 7.79 kB
-
https://huggingface.co/spaces/illimax/kcbert-profanity/resolve/main/index.html
- Command line
-
hf download hf://spaces/illimax/kcbert-profanity/index.html
-
curl -L -o index.html https://huggingface.co/spaces/illimax/kcbert-profanity/resolve/main/index.html
7.79 kB
| <html lang="ko"> | |
| <head> | |
| <meta charset="utf-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1"> | |
| <title>kcbert-profanity</title> | |
| <style> | |
| :root { | |
| --bg: #fafafa; --fg: #1a1a1a; --muted: #666; --line: #ddd; | |
| --card: #fff; --clean: #2f7d4f; --bad: #c0392b; --btn: #1a1a1a; --btn-fg: #fff; | |
| } | |
| @media (prefers-color-scheme: dark) { | |
| :root:not([data-theme="light"]) { | |
| --bg: #141414; --fg: #eee; --muted: #999; --line: #333; | |
| --card: #1e1e1e; --clean: #4caf7a; --bad: #e5604f; --btn: #eee; --btn-fg: #141414; | |
| } | |
| } | |
| * { box-sizing: border-box; } | |
| body { | |
| margin: 0; background: var(--bg); color: var(--fg); | |
| font-family: -apple-system, "Apple SD Gothic Neo", "Malgun Gothic", sans-serif; | |
| line-height: 1.5; | |
| } | |
| main { max-width: 640px; margin: 0 auto; padding: 40px 16px; } | |
| h1 { font-size: 1.5rem; margin: 0 0 4px; } | |
| .sub { color: var(--muted); margin: 0 0 24px; font-size: .95rem; } | |
| .sub a { color: inherit; } | |
| textarea { | |
| width: 100%; min-height: 96px; padding: 12px; font: inherit; resize: vertical; | |
| border: 1px solid var(--line); border-radius: 8px; background: var(--card); color: var(--fg); | |
| } | |
| .row { display: flex; gap: 8px; align-items: center; margin-top: 8px; flex-wrap: wrap; } | |
| button { | |
| font: inherit; padding: 8px 16px; border-radius: 8px; cursor: pointer; | |
| border: 1px solid var(--btn); background: var(--btn); color: var(--btn-fg); | |
| } | |
| button:disabled { opacity: .4; cursor: default; } | |
| .ex { | |
| background: transparent; color: var(--fg); border-color: var(--line); | |
| padding: 4px 10px; font-size: .85rem; | |
| } | |
| #status { color: var(--muted); font-size: .9rem; margin-top: 16px; min-height: 1.5em; } | |
| #result { margin-top: 8px; padding: 16px; border: 1px solid var(--line); border-radius: 8px; background: var(--card); } | |
| #result[hidden] { display: none; } | |
| .verdict { font-size: 1.25rem; font-weight: 600; margin-bottom: 12px; } | |
| .bar { display: grid; grid-template-columns: 72px 1fr 56px; gap: 8px; align-items: center; font-size: .9rem; margin: 4px 0; } | |
| .track { height: 8px; background: var(--line); border-radius: 4px; overflow: hidden; } | |
| .fill { height: 100%; width: 0; transition: width .2s; } | |
| .num { text-align: right; font-variant-numeric: tabular-nums; } | |
| #words { margin-top: 16px; padding-top: 12px; border-top: 1px solid var(--line); } | |
| #words[hidden] { display: none; } | |
| #words .label { color: var(--muted); font-size: .85rem; margin-bottom: 4px; } | |
| #words mark { background: var(--bad); color: #fff; padding: 0 3px; border-radius: 3px; } | |
| footer { margin-top: 32px; color: var(--muted); font-size: .85rem; } | |
| </style> | |
| </head> | |
| <body> | |
| <main> | |
| <h1>kcbert-profanity</h1> | |
| <p class="sub">νκ΅μ΄ λ¬Έμ₯μ΄ μμ€Β·νμ€ ννμΈμ§ νμ ν©λλ€. λͺ¨λΈ: <a href="https://huggingface.co/illimax/kcbert-profanity" target="_blank">illimax/kcbert-profanity</a></p> | |
| <textarea id="text" placeholder="λ¬Έμ₯μ μ λ ₯νμΈμ" maxlength="500"></textarea> | |
| <div class="row"> | |
| <button id="run" disabled>νμ </button> | |
| <button class="ex">μ€λ λ μ¨ μ λ§ μ’λ€</button> | |
| <button class="ex">μ μλ° μ§μ§ μ§μ¦λλ€</button> | |
| <button class="ex">μ΄ μν μκ°λ³΄λ€ λ³λ‘μμ΄</button> | |
| <button class="ex">λ κ°μ λμ κ·Έλ₯ κΊΌμ Έ</button> | |
| </div> | |
| <div id="status">λͺ¨λΈ λΆλ¬μ€λ μ€... (μ²μ ν λ² μ½ 110MB)</div> | |
| <div id="result" hidden> | |
| <div class="verdict" id="verdict"></div> | |
| <div class="bar"><span>μ μ</span><div class="track"><div class="fill" id="f0" style="background:var(--clean)"></div></div><span class="num" id="p0"></span></div> | |
| <div class="bar"><span>μμ€Β·νμ€</span><div class="track"><div class="fill" id="f1" style="background:var(--bad)"></div></div><span class="num" id="p1"></span></div> | |
| <div id="words" hidden> | |
| <div class="label">νμ μ κ²°μ μ μΈ λ¨μ΄</div> | |
| <div id="marked"></div> | |
| </div> | |
| </div> | |
| <footer>μ½ 1λ§ 5μ² λ¬Έμ₯μΌλ‘λ§ νμ΅ν λͺ¨λΈμ΄λΌ μλͺ» νμ ν μ μμ΅λλ€. νκ΅μ΄ μ μ©μ΄λ©° μμ΄ μμ€μ κ²μΆνμ§ λͺ»ν©λλ€.<br>μ λ ₯ν λ¬Έμ₯μ μλ²λ‘ μ μ‘λμ§ μκ³ λΈλΌμ°μ μμμλ§ μ²λ¦¬λ©λλ€. 128ν ν°μ΄ λλ λ·λΆλΆμ 무μλ©λλ€.</footer> | |
| </main> | |
| <script type="module"> | |
| import { AutoTokenizer, AutoModelForSequenceClassification } from "https://cdn.jsdelivr.net/npm/@huggingface/transformers@3.7.6"; | |
| const MODEL_ID = "illimax/kcbert-profanity"; | |
| const $ = (id) => document.getElementById(id); | |
| const text = $("text"), run = $("run"), status = $("status"); | |
| let tokenizer, model; | |
| try { | |
| [tokenizer, model] = await Promise.all([ | |
| AutoTokenizer.from_pretrained(MODEL_ID), | |
| AutoModelForSequenceClassification.from_pretrained(MODEL_ID, { dtype: "q8" }), | |
| ]); | |
| status.textContent = ""; | |
| run.disabled = false; | |
| } catch (e) { | |
| status.textContent = "λͺ¨λΈμ λΆλ¬μ€μ§ λͺ»νμ΅λλ€: " + e.message; | |
| } | |
| // λ¬Έμ₯ μ¬λ¬ κ°λ₯Ό ν λ²μ λ£κ³ κ°κ°μ μμ€ νλ₯ μ λλ €μ€λ€ | |
| async function offensiveProbs(texts) { | |
| const inputs = await tokenizer(texts, { padding: true, truncation: true, max_length: 128 }); | |
| const d = (await model(inputs)).logits.data; | |
| return texts.map((_, i) => 1 / (1 + Math.exp(d[2 * i] - d[2 * i + 1]))); | |
| } | |
| // λͺ¨λΈμ λ¬Έμ₯ λ¨μ λΆλ₯λΌ λ¨μ΄ μμΉλ₯Ό μ§μ μ£Όμ§ μλλ€. | |
| // κ·Έλμ μ΄μ μ νλμ© λΉΌ 보며 μμ€ νλ₯ μ κ°μ₯ ν¬κ² λ¨μ΄λ¨λ¦¬λ μ΄μ μ κ³ λ₯΄κ³ , | |
| // λ¬Έμ₯μ΄ μ μμΌλ‘ λ°λ λκΉμ§ λ°λ³΅νλ€. μμ€μ΄ μ¬λ¬ κ°λ©΄ νλλ§ λΉΌμλ νλ₯ μ΄ μ λ¨μ΄μ§κΈ° λλ¬Έμ΄λ€. | |
| async function findWords(words) { | |
| const removed = new Set(); | |
| let p = 1; | |
| while (p >= 0.5 && removed.size < words.length) { | |
| const cand = words.map((_, i) => i).filter((i) => !removed.has(i)); | |
| const texts = cand.map((i) => words.filter((_, j) => j !== i && !removed.has(j)).join(" ")); | |
| const ps = await offensiveProbs(texts); | |
| const best = ps.indexOf(Math.min(...ps)); | |
| removed.add(cand[best]); | |
| p = ps[best]; | |
| } | |
| return removed; | |
| } | |
| function showWords(words, removed) { | |
| const box = $("marked"); | |
| box.replaceChildren(); | |
| words.forEach((w, i) => { | |
| if (i) box.append(" "); | |
| if (removed.has(i)) { | |
| const m = document.createElement("mark"); | |
| m.textContent = w; | |
| box.append(m); | |
| } else { | |
| box.append(w); | |
| } | |
| }); | |
| $("words").hidden = false; | |
| } | |
| const MAX_WORDS = 40; | |
| async function classify() { | |
| const value = text.value.trim(); | |
| if (!value || !model) return; | |
| run.disabled = true; | |
| $("words").hidden = true; | |
| const [p1] = await offensiveProbs([value]); | |
| const p0 = 1 - p1; | |
| $("verdict").textContent = p1 >= 0.5 ? "μμ€Β·νμ€ ννμ λλ€" : "μ μ λ¬Έμ₯μ λλ€"; | |
| $("verdict").style.color = p1 >= 0.5 ? "var(--bad)" : "var(--clean)"; | |
| $("p0").textContent = (p0 * 100).toFixed(1) + "%"; | |
| $("p1").textContent = (p1 * 100).toFixed(1) + "%"; | |
| $("f0").style.width = p0 * 100 + "%"; | |
| $("f1").style.width = p1 * 100 + "%"; | |
| $("result").hidden = false; | |
| const words = value.split(/\s+/); | |
| if (p1 >= 0.5 && words.length <= MAX_WORDS) { | |
| status.textContent = "λ¨μ΄ μ°Ύλ μ€..."; | |
| showWords(words, await findWords(words)); | |
| status.textContent = ""; | |
| } | |
| run.disabled = false; | |
| } | |
| run.addEventListener("click", classify); | |
| text.addEventListener("keydown", (e) => { | |
| if (e.key === "Enter" && !e.shiftKey) { e.preventDefault(); classify(); } | |
| }); | |
| document.querySelectorAll(".ex").forEach((btn) => | |
| btn.addEventListener("click", () => { text.value = btn.textContent; classify(); }) | |
| ); | |
| </script> | |
| </body> | |
| </html> | |