|
|
<!DOCTYPE html>
|
|
|
<html lang="en">
|
|
|
<head>
|
|
|
<meta charset="UTF-8">
|
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
|
<title>ProBERT - Detect Rhetorical Overconfidence</title>
|
|
|
<style>
|
|
|
* {
|
|
|
margin: 0;
|
|
|
padding: 0;
|
|
|
box-sizing: border-box;
|
|
|
}
|
|
|
|
|
|
body {
|
|
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
|
background: linear-gradient(135deg, #fffaec 0%, #fff5d6 100%);
|
|
|
min-height: 100vh;
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
justify-content: center;
|
|
|
padding: 20px;
|
|
|
color: #2c2c2c;
|
|
|
}
|
|
|
|
|
|
.container {
|
|
|
max-width: 700px;
|
|
|
width: 100%;
|
|
|
background: #fffef9;
|
|
|
border-radius: 12px;
|
|
|
padding: 40px;
|
|
|
box-shadow: 0 10px 40px rgba(218, 165, 32, 0.15);
|
|
|
border: 1px solid #f0e68c;
|
|
|
}
|
|
|
|
|
|
.header {
|
|
|
text-align: center;
|
|
|
margin-bottom: 30px;
|
|
|
}
|
|
|
|
|
|
.header h1 {
|
|
|
font-size: 28px;
|
|
|
margin-bottom: 8px;
|
|
|
color: #b8860b;
|
|
|
font-weight: 600;
|
|
|
}
|
|
|
|
|
|
.header p {
|
|
|
font-size: 14px;
|
|
|
color: #8b7500;
|
|
|
}
|
|
|
|
|
|
.mode-toggle {
|
|
|
display: flex;
|
|
|
gap: 8px;
|
|
|
margin-bottom: 20px;
|
|
|
justify-content: center;
|
|
|
}
|
|
|
|
|
|
.mode-btn {
|
|
|
padding: 8px 14px;
|
|
|
font-size: 12px;
|
|
|
font-weight: 600;
|
|
|
border: 2px solid #daa520;
|
|
|
background: #fffef9;
|
|
|
color: #b8860b;
|
|
|
border-radius: 4px;
|
|
|
cursor: pointer;
|
|
|
transition: all 0.2s;
|
|
|
text-transform: uppercase;
|
|
|
letter-spacing: 0.5px;
|
|
|
}
|
|
|
|
|
|
.mode-btn.active {
|
|
|
background: #daa520;
|
|
|
color: #fff;
|
|
|
}
|
|
|
|
|
|
.mode-btn:hover {
|
|
|
border-color: #b8860b;
|
|
|
}
|
|
|
|
|
|
.input-section {
|
|
|
margin-bottom: 20px;
|
|
|
}
|
|
|
|
|
|
label {
|
|
|
display: block;
|
|
|
font-size: 13px;
|
|
|
font-weight: 600;
|
|
|
margin-bottom: 8px;
|
|
|
color: #2c2c2c;
|
|
|
text-transform: uppercase;
|
|
|
letter-spacing: 0.5px;
|
|
|
}
|
|
|
|
|
|
textarea {
|
|
|
width: 100%;
|
|
|
height: 140px;
|
|
|
padding: 12px;
|
|
|
border: 2px solid #f0e68c;
|
|
|
border-radius: 6px;
|
|
|
background: #fffef9;
|
|
|
color: #2c2c2c;
|
|
|
font-size: 14px;
|
|
|
font-family: inherit;
|
|
|
resize: none;
|
|
|
transition: border-color 0.2s;
|
|
|
}
|
|
|
|
|
|
textarea:focus {
|
|
|
outline: none;
|
|
|
border-color: #daa520;
|
|
|
}
|
|
|
|
|
|
.button-group {
|
|
|
display: flex;
|
|
|
gap: 10px;
|
|
|
margin-bottom: 30px;
|
|
|
}
|
|
|
|
|
|
button {
|
|
|
flex: 1;
|
|
|
padding: 12px 20px;
|
|
|
font-size: 14px;
|
|
|
font-weight: 600;
|
|
|
border: none;
|
|
|
border-radius: 6px;
|
|
|
cursor: pointer;
|
|
|
transition: all 0.2s;
|
|
|
text-transform: uppercase;
|
|
|
letter-spacing: 0.5px;
|
|
|
}
|
|
|
|
|
|
.score-btn {
|
|
|
background: linear-gradient(135deg, #00d4ff, #0099cc);
|
|
|
color: #fff;
|
|
|
}
|
|
|
|
|
|
.score-btn:hover {
|
|
|
transform: translateY(-2px);
|
|
|
box-shadow: 0 8px 20px rgba(0, 212, 255, 0.3);
|
|
|
}
|
|
|
|
|
|
.score-btn:active {
|
|
|
transform: translateY(0);
|
|
|
}
|
|
|
|
|
|
.score-btn:disabled {
|
|
|
opacity: 0.5;
|
|
|
cursor: not-allowed;
|
|
|
transform: none;
|
|
|
}
|
|
|
|
|
|
.example-btn {
|
|
|
background: #fff8dc;
|
|
|
color: #b8860b;
|
|
|
border: 2px solid #daa520;
|
|
|
}
|
|
|
|
|
|
.example-btn:hover {
|
|
|
background: #f0e68c;
|
|
|
}
|
|
|
|
|
|
.results {
|
|
|
display: none;
|
|
|
background: #fffef9;
|
|
|
border: 2px solid #f0e68c;
|
|
|
border-radius: 6px;
|
|
|
padding: 20px;
|
|
|
margin-top: 20px;
|
|
|
}
|
|
|
|
|
|
.results.show {
|
|
|
display: block;
|
|
|
animation: slideIn 0.3s ease-out;
|
|
|
}
|
|
|
|
|
|
@keyframes slideIn {
|
|
|
from {
|
|
|
opacity: 0;
|
|
|
transform: translateY(10px);
|
|
|
}
|
|
|
to {
|
|
|
opacity: 1;
|
|
|
transform: translateY(0);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
.result-item {
|
|
|
margin-bottom: 16px;
|
|
|
}
|
|
|
|
|
|
.result-item:last-child {
|
|
|
margin-bottom: 0;
|
|
|
}
|
|
|
|
|
|
.result-label {
|
|
|
font-size: 12px;
|
|
|
font-weight: 700;
|
|
|
text-transform: uppercase;
|
|
|
letter-spacing: 0.5px;
|
|
|
margin-bottom: 6px;
|
|
|
color: #8b7500;
|
|
|
}
|
|
|
|
|
|
.result-bar {
|
|
|
height: 32px;
|
|
|
background: #f0e68c;
|
|
|
border-radius: 4px;
|
|
|
overflow: hidden;
|
|
|
position: relative;
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
}
|
|
|
|
|
|
.result-fill {
|
|
|
height: 100%;
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
justify-content: flex-end;
|
|
|
padding-right: 10px;
|
|
|
font-weight: 600;
|
|
|
font-size: 13px;
|
|
|
color: #fff;
|
|
|
transition: width 0.4s ease-out;
|
|
|
}
|
|
|
|
|
|
.process_clarity {
|
|
|
background: linear-gradient(90deg, #00d4ff, #0099cc);
|
|
|
}
|
|
|
|
|
|
.rhetorical_confidence {
|
|
|
background: linear-gradient(90deg, #ff6b6b, #ee5a5a);
|
|
|
}
|
|
|
|
|
|
.scope_blur {
|
|
|
background: linear-gradient(90deg, #ffd93d, #ffb700);
|
|
|
}
|
|
|
|
|
|
.prediction {
|
|
|
margin-top: 20px;
|
|
|
padding-top: 20px;
|
|
|
border-top: 1px solid #16213e;
|
|
|
}
|
|
|
|
|
|
.prediction-label {
|
|
|
font-size: 12px;
|
|
|
font-weight: 600;
|
|
|
color: #b0b0b0;
|
|
|
margin-bottom: 8px;
|
|
|
}
|
|
|
|
|
|
.prediction-value {
|
|
|
font-size: 18px;
|
|
|
font-weight: 700;
|
|
|
padding: 12px;
|
|
|
background: #16213e;
|
|
|
border-radius: 4px;
|
|
|
text-transform: capitalize;
|
|
|
}
|
|
|
|
|
|
.loading {
|
|
|
display: none;
|
|
|
text-align: center;
|
|
|
color: #00d4ff;
|
|
|
font-size: 13px;
|
|
|
}
|
|
|
|
|
|
.loading.show {
|
|
|
display: block;
|
|
|
}
|
|
|
|
|
|
.error {
|
|
|
display: none;
|
|
|
background: rgba(255, 107, 107, 0.1);
|
|
|
border: 1px solid #ff6b6b;
|
|
|
border-radius: 6px;
|
|
|
padding: 12px;
|
|
|
color: #ff9999;
|
|
|
font-size: 13px;
|
|
|
margin-top: 15px;
|
|
|
}
|
|
|
|
|
|
.error.show {
|
|
|
display: block;
|
|
|
}
|
|
|
|
|
|
.footer {
|
|
|
text-align: center;
|
|
|
margin-top: 30px;
|
|
|
font-size: 12px;
|
|
|
color: #8b7500;
|
|
|
}
|
|
|
|
|
|
.footer a {
|
|
|
color: #b8860b;
|
|
|
text-decoration: none;
|
|
|
}
|
|
|
|
|
|
.footer a:hover {
|
|
|
text-decoration: underline;
|
|
|
}
|
|
|
</style>
|
|
|
</head>
|
|
|
<body>
|
|
|
<div class="container">
|
|
|
<div class="header">
|
|
|
<h1>ProBERT</h1>
|
|
|
<p>Detect rhetorical overconfidence in real-time</p>
|
|
|
</div>
|
|
|
|
|
|
<div class="input-section">
|
|
|
<label for="input-text">Paste LLM output or any text:</label>
|
|
|
<textarea id="input-text" placeholder="This revolutionary approach will transform your business..."></textarea>
|
|
|
</div>
|
|
|
|
|
|
<div class="button-group">
|
|
|
<button class="score-btn" onclick="scoreText()">Score It</button>
|
|
|
<button class="example-btn" onclick="loadExample(0)">Process-Driven</button>
|
|
|
<button class="example-btn" onclick="loadExample(1)">Rhetorical</button>
|
|
|
<button class="example-btn" onclick="loadExample(2)">Scope Blur</button>
|
|
|
</div>
|
|
|
|
|
|
<div class="loading" id="loading">
|
|
|
Analyzing text...
|
|
|
</div>
|
|
|
|
|
|
<div class="error" id="error"></div>
|
|
|
|
|
|
<div class="results" id="results">
|
|
|
<div class="result-item">
|
|
|
<div class="result-label">Process Clarity (Step-by-step reasoning)</div>
|
|
|
<div class="result-bar">
|
|
|
<div class="result-fill process_clarity" id="bar-process" style="width: 0%">
|
|
|
<span id="score-process">0%</span>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
<div class="result-item">
|
|
|
<div class="result-label">Rhetorical Confidence (Authority without process)</div>
|
|
|
<div class="result-bar">
|
|
|
<div class="result-fill rhetorical_confidence" id="bar-rhetorical" style="width: 0%">
|
|
|
<span id="score-rhetorical">0%</span>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
<div class="result-item">
|
|
|
<div class="result-label">Scope Blur (Vague generalizations)</div>
|
|
|
<div class="result-bar">
|
|
|
<div class="result-fill scope_blur" id="bar-blur" style="width: 0%">
|
|
|
<span id="score-blur">0%</span>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
<div class="prediction">
|
|
|
<div class="prediction-label">Primary Classification</div>
|
|
|
<div class="prediction-value" id="prediction">Process Clarity</div>
|
|
|
</div>
|
|
|
|
|
|
<div class="result-item">
|
|
|
<div class="result-label">Model Confidence</div>
|
|
|
<div class="result-bar">
|
|
|
<div class="result-fill process_clarity" id="bar-confidence" style="width: 0%">
|
|
|
<span id="score-confidence">0%</span>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
<div class="result-item">
|
|
|
<div class="result-label">Decision Coherence</div>
|
|
|
<div class="result-bar">
|
|
|
<div class="result-fill process_clarity" id="bar-coherence" style="width: 0%">
|
|
|
<span id="score-coherence">0%</span>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
<div class="prediction">
|
|
|
<div class="prediction-label">Verdict</div>
|
|
|
<div class="prediction-value" id="verdict" style="background: #f0e68c; color: #2c2c2c;">Analyzing...</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
<div class="footer">
|
|
|
<p><a href="https://collapseindex.org" target="_blank">Collapse Index Labs</a> • ProBERT v1.0 | <a href="https://huggingface.co/collapseindex/ProBERT-1.0" target="_blank">Model</a> | <a href="https://collapseindex.org/case-studies/template.html?s=probert-case-study" target="_blank">Case Study</a></p>
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
<script type="module">
|
|
|
|
|
|
function sanitizeHTML(text) {
|
|
|
const map = {
|
|
|
'&': '&',
|
|
|
'<': '<',
|
|
|
'>': '>',
|
|
|
'"': '"',
|
|
|
"'": '''
|
|
|
};
|
|
|
return text.replace(/[&<>"']/g, m => map[m]);
|
|
|
}
|
|
|
|
|
|
const EXAMPLES = [
|
|
|
"To implement binary search: 1. Define left and right pointers. 2. Calculate mid point. 3. Compare value with target. If less, move right pointer. If greater, move left pointer. 4. Repeat until found or pointers converge.",
|
|
|
"This revolutionary AI will transform your business and guarantee unprecedented results. Our innovative approach will definitely solve all your problems.",
|
|
|
"Trust your intuition and embrace the cosmic energy. The universe has a plan for you."
|
|
|
];
|
|
|
|
|
|
const HF_API_URL = "https://api-inference.huggingface.co/models/collapseindex/ProBERT-1.0";
|
|
|
let isLoading = false;
|
|
|
|
|
|
window.scoreText = async function() {
|
|
|
const text = document.getElementById("input-text").value.trim();
|
|
|
|
|
|
if (!text) {
|
|
|
showError("Please enter some text to analyze.");
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
if (text.length > 2000) {
|
|
|
showError("Text too long (max 2000 characters). ProBERT uses 128 token max.");
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
|
|
|
if (isLoading) return;
|
|
|
isLoading = true;
|
|
|
|
|
|
const scoreBtn = document.querySelector('button');
|
|
|
scoreBtn.disabled = true;
|
|
|
scoreBtn.style.opacity = "0.6";
|
|
|
scoreBtn.style.cursor = "not-allowed";
|
|
|
|
|
|
showLoading(true, "Scoring text with ProBERT...");
|
|
|
hideError();
|
|
|
|
|
|
try {
|
|
|
const response = await fetch(HF_API_URL, {
|
|
|
method: "POST",
|
|
|
headers: { "Content-Type": "application/json" },
|
|
|
body: JSON.stringify({ inputs: text }),
|
|
|
timeout: 30000
|
|
|
});
|
|
|
|
|
|
if (response.status === 401) {
|
|
|
throw new Error("ProBERT model not yet public on HuggingFace. Upload coming soon!");
|
|
|
}
|
|
|
if (response.status === 503) {
|
|
|
throw new Error("Model loading... Please try again in 30 seconds");
|
|
|
}
|
|
|
if (response.status === 429) {
|
|
|
throw new Error("Rate limited. Please wait a moment.");
|
|
|
}
|
|
|
if (!response.ok) {
|
|
|
throw new Error("API error. Please try again.");
|
|
|
}
|
|
|
|
|
|
const result = await response.json();
|
|
|
|
|
|
if (!result || !result[0] || !Array.isArray(result[0])) {
|
|
|
throw new Error("Invalid response format from API.");
|
|
|
}
|
|
|
|
|
|
const scores = result[0];
|
|
|
const classMap = ["process_clarity", "rhetorical_confidence", "scope_blur"];
|
|
|
const classScores = {};
|
|
|
|
|
|
scores.forEach((score, idx) => {
|
|
|
if (typeof score.score !== 'number') {
|
|
|
throw new Error("Invalid score value received.");
|
|
|
}
|
|
|
classScores[classMap[idx]] = score.score;
|
|
|
});
|
|
|
|
|
|
displayResults(classScores);
|
|
|
} catch (err) {
|
|
|
|
|
|
const userMsg = err.message.includes("fetch")
|
|
|
? "Network error. Please check your connection."
|
|
|
: (err.message || "An error occurred. Please try again.");
|
|
|
showError(userMsg);
|
|
|
} finally {
|
|
|
isLoading = false;
|
|
|
scoreBtn.disabled = false;
|
|
|
scoreBtn.style.opacity = "1";
|
|
|
scoreBtn.style.cursor = "pointer";
|
|
|
showLoading(false);
|
|
|
}
|
|
|
};
|
|
|
|
|
|
function displayResults(scores) {
|
|
|
const process = Math.round(scores.process_clarity * 100);
|
|
|
const rhetorical = Math.round(scores.rhetorical_confidence * 100);
|
|
|
const blur = Math.round(scores.scope_blur * 100);
|
|
|
|
|
|
document.getElementById("bar-process").style.width = process + "%";
|
|
|
document.getElementById("score-process").textContent = process + "%";
|
|
|
|
|
|
document.getElementById("bar-rhetorical").style.width = rhetorical + "%";
|
|
|
document.getElementById("score-rhetorical").textContent = rhetorical + "%";
|
|
|
|
|
|
document.getElementById("bar-blur").style.width = blur + "%";
|
|
|
document.getElementById("score-blur").textContent = blur + "%";
|
|
|
|
|
|
|
|
|
const sorted = [process, rhetorical, blur].sort((a, b) => b - a);
|
|
|
const confidence = sorted[0];
|
|
|
const coherence = Math.max(0, sorted[0] - sorted[1]);
|
|
|
|
|
|
document.getElementById("bar-confidence").style.width = confidence + "%";
|
|
|
document.getElementById("score-confidence").textContent = confidence + "%";
|
|
|
|
|
|
document.getElementById("bar-coherence").style.width = coherence + "%";
|
|
|
document.getElementById("score-coherence").textContent = coherence + "%";
|
|
|
|
|
|
const max = Math.max(process, rhetorical, blur);
|
|
|
let prediction = "Process Clarity";
|
|
|
let verdict = "🟢 Clear & Process-Driven\nStep-by-step reasoning detected.";
|
|
|
|
|
|
if (rhetorical === max) {
|
|
|
prediction = "Rhetorical Confidence";
|
|
|
verdict = "🔴 Warning: Rhetorical Confidence\nAuthority without clear process.";
|
|
|
} else if (blur === max) {
|
|
|
prediction = "Scope Blur";
|
|
|
verdict = "🟠 Caution: Scope Blur\nVague generalizations detected.";
|
|
|
}
|
|
|
|
|
|
document.getElementById("prediction").textContent = prediction;
|
|
|
document.getElementById("verdict").textContent = verdict;
|
|
|
document.getElementById("results").classList.add("show");
|
|
|
}
|
|
|
|
|
|
window.loadExample = function(idx) {
|
|
|
if (idx < 0 || idx >= EXAMPLES.length) return;
|
|
|
document.getElementById("input-text").value = EXAMPLES[idx];
|
|
|
document.getElementById("input-text").focus();
|
|
|
};
|
|
|
|
|
|
function showLoading(show, msg = "Analyzing text...") {
|
|
|
const el = document.getElementById("loading");
|
|
|
el.textContent = msg;
|
|
|
el.classList.toggle("show", show);
|
|
|
el.setAttribute("aria-live", "polite");
|
|
|
}
|
|
|
|
|
|
function showError(msg) {
|
|
|
const el = document.getElementById("error");
|
|
|
el.textContent = sanitizeHTML(msg);
|
|
|
el.classList.add("show");
|
|
|
el.setAttribute("role", "alert");
|
|
|
el.setAttribute("aria-live", "assertive");
|
|
|
}
|
|
|
|
|
|
function hideError() {
|
|
|
document.getElementById("error").classList.remove("show");
|
|
|
}
|
|
|
|
|
|
|
|
|
document.getElementById("input-text").addEventListener("keydown", (e) => {
|
|
|
if ((e.ctrlKey || e.metaKey) && e.key === "Enter") {
|
|
|
window.scoreText();
|
|
|
}
|
|
|
});
|
|
|
|
|
|
|
|
|
window.addEventListener("load", () => {
|
|
|
document.getElementById("input-text").focus();
|
|
|
});
|
|
|
</script>
|
|
|
</body>
|
|
|
</html>
|
|
|
|