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>
This commit is contained in:
@@ -13,6 +13,7 @@ const auth = require('./auth');
|
||||
const accounts = require('./accounts');
|
||||
const ads = require('./ads');
|
||||
const mailer = require('./mailer');
|
||||
const chatbot = require('./chatbot');
|
||||
|
||||
const PORT = Number(process.env.PORT || 3000);
|
||||
const ROOT = __dirname;
|
||||
@@ -28,6 +29,14 @@ auth.init({ dataDir: DATA_DIR, chain, isProd: IS_PROD, site: 'instantadpay.com'
|
||||
accounts.init({ dataDir: DATA_DIR });
|
||||
ads.init({ dataDir: DATA_DIR, chain });
|
||||
mailer.init({ dataDir: DATA_DIR });
|
||||
chatbot.init({ dataDir: DATA_DIR, chain });
|
||||
const chatHits = new Map();
|
||||
function chatLimited(ip) {
|
||||
const now = Date.now(), rec = chatHits.get(ip);
|
||||
if (!rec || now > rec.reset) { chatHits.set(ip, { count: 1, reset: now + 60000 }); return false; }
|
||||
rec.count += 1;
|
||||
return rec.count > 10;
|
||||
}
|
||||
// magic-code sign-in: emailLower -> {code, exp, tries}
|
||||
const emailCodes = new Map();
|
||||
setTimeout(() => ads.dailySweep(), 60 * 1000);
|
||||
@@ -170,6 +179,15 @@ const server = http.createServer(async (req, res) => {
|
||||
return json(res, 200, Object.assign({ onchainMembers: members, siteAccounts: accounts.count() }, chain.totals()));
|
||||
}
|
||||
|
||||
// -- 24/7 assistant
|
||||
if (p === '/api/chat' && req.method === 'POST') {
|
||||
const ip = req.socket.remoteAddress || 'x';
|
||||
if (chatLimited(ip)) return json(res, 429, { error: 'Give it a minute, then ask again.' });
|
||||
const b = await readBody(req);
|
||||
const r = await chatbot.answer(b.message, b.history);
|
||||
return json(res, r.error ? 400 : 200, r);
|
||||
}
|
||||
|
||||
// -- accounts: email + password is the normal join path (wallet comes
|
||||
// out only at purchase / payout-activation time and gets linked then)
|
||||
if (p === '/api/signup' && req.method === 'POST') {
|
||||
|
||||
Reference in New Issue
Block a user