Files
instantadpay/public/assets/chat.js
T
martbost f3d2f7db88 24/7 assistant: canned answers + OpenRouter AI, widget on every page
RM Circle pattern: nine canned answers for the questions everyone asks
(pyramid, withdrawals, splits, qualification, joining, credits, safety),
OpenRouter fallback with a facts-loaded system prompt and hard no-income-
promise rules, graceful no-key fallback. Floating mint bubble widget with
linkified replies; 10/min per-IP rate limit. Assets v=20260904i.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-09-04 14:00:43 -05:00

59 lines
2.4 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// 24/7 assistant widget: floating bubble, slide-up panel, /api/chat.
(function () {
const root = document.createElement('div');
root.id = 'iapChat';
root.innerHTML = '<button id="iapChatBtn" aria-label="Chat with us" type="button">💬</button>'
+ '<div id="iapChatPanel" hidden>'
+ '<div class="ch-head"><b>Ask anything</b><span class="ch-sub">Real answers, around the clock</span>'
+ '<button id="iapChatClose" aria-label="Close chat" type="button">×</button></div>'
+ '<div class="ch-msgs" id="iapChatMsgs">'
+ '<div class="ch-m bot">Hey. Ask me how the payments work, what the packages buy, or anything else. Straight answers only, no income hype.</div>'
+ '</div>'
+ '<div class="ch-input"><input id="iapChatIn" placeholder="Type your question…" maxlength="600">'
+ '<button id="iapChatSend" type="button">Send</button></div>'
+ '</div>';
document.body.appendChild(root);
const $ = id => document.getElementById(id);
const msgs = $('iapChatMsgs');
const input = $('iapChatIn');
let history = [];
const add = (text, who) => {
const d = document.createElement('div');
d.className = 'ch-m ' + who;
// linkify plain URLs
d.innerHTML = String(text).replace(/[&<>]/g, c => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;' }[c]))
.replace(/(https?:\/\/[^\s]+)/g, '<a href="$1" target="_blank" rel="noopener">$1</a>');
msgs.appendChild(d);
msgs.scrollTop = msgs.scrollHeight;
return d;
};
async function send() {
const q = input.value.trim();
if (!q) return;
input.value = '';
add(q, 'me');
const wait = add('…', 'bot');
try {
const r = await (await fetch('/api/chat', { method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ message: q, history: history.slice(-4).join(' | ') }) })).json();
wait.remove();
add(r.reply || r.error || 'No answer came back. Try again.', 'bot');
history.push('Q: ' + q, 'A: ' + (r.reply || ''));
} catch (e) {
wait.remove();
add('Connection hiccup. Try that again.', 'bot');
}
}
$('iapChatBtn').addEventListener('click', () => {
const p = $('iapChatPanel');
p.hidden = !p.hidden;
if (!p.hidden) input.focus();
});
$('iapChatClose').addEventListener('click', () => { $('iapChatPanel').hidden = true; });
$('iapChatSend').addEventListener('click', send);
input.addEventListener('keydown', e => { if (e.key === 'Enter') send(); });
})();