0 likes | 3 Views
#1 GROWTH DRIVEN SEO AGENCY<br>The SEO Agency<br>That Delivers<br>Results
E N D
Ranqeo — AI Agent Deployable Package Ready-to-deploy code + instructions to add a chat + voice AI agent to your Ranqeo website. This package contains everything you need to integrate a conversational agent that answers SEO questions, qualifies leads, and books calls via Calendly. Replace the placeholder values (API keys, links, phone numbers) with your real info and deploy. What is included (single-file copy-and-paste friendly) 1. server/ — Node.js/Express backend that handles chat & voice webhooks, talks to an LLM, stores leads, and sends SMS with booking link. frontend/ — Simple website snippet (drop-in) to show a chat widget and booking CTA. kb/ — Starter knowledge base (markdown files) for RAG grounding. prompt/agent_prompt.txt — System prompt tuned for Ranqeo. README — step-by-step setup & deployment instructions. 2. 3. 4. 5. Quick notes before you start • You do not need deep technical knowledge. Follow the steps in the README and replace placeholders. I included a self-contained server you can deploy on Vercel, Render, or any Node host. Important placeholders: LLM_API_URL , LLM_API_KEY , TWILIO_ACCOUNT_SID , TWILIO_AUTH_TOKEN , TWILIO_PHONE_NUMBER , CALENDLY_LINK , NAYAPAY_INFO , GOOGLE_SHEET_WEBHOOK . The package uses a RAG-style knowledge base (reads the kb markdown files) and a prompt for safe, helpful replies. • • • 1) Server — server/index.js // A minimal Node/Express server that serves two webhook endpoints: // 1) /chat/webhook -> handles website chat messages (POST JSON { message, sessionId }) // 2) /voice/incoming -> Twilio will POST here on incoming calls (holds first prompt -> gather speech) import express from 'express'; import bodyParser from 'body-parser'; import fetch from 'node-fetch'; import fs from 'fs'; import path from 'path'; 1
const app = express(); app.use(bodyParser.json()); app.use(bodyParser.urlencoded({ extended: true })); // Load KB for simple retrieval (very small-scale RAG) const KB_DIR = path.join(process.cwd(), 'kb'); function loadKb() { const files = fs.readdirSync(KB_DIR).filter(f => f.endsWith('.md')); return files.map(f => ({ name: f, text: fs.readFileSync(path.join(KB_DIR, f), 'utf8') })); } // Simple retrieval: returns the top matching KB text by keyword overlap function retrieveKb(query) { const q = query.toLowerCase(); const kb = loadKb(); let best = {score:0, text:''}; for (const doc of kb) { const tokens = doc.text.toLowerCase().split(/\W+/); const score = tokens.reduce((s,t)=> s + (q.includes(t)?1:0), 0); if (score > best.score) best = {score, text: doc.text}; } return best.text || ''; } // Read agent prompt const AGENT_PROMPT = fs.readFileSync(path.join(process.cwd(),'prompt','agent_prompt.txt'),'utf8'); // Helper to call your LLM API (replace with your provider) async function callLLM(message, sessionId) { // Basic RAG: append best KB excerpt const kbSnippet = retrieveKb(message).slice(0, 1500); const payload = { prompt: `${AGENT_PROMPT}\n\nCONTEXT: ${kbSnippet}\n\nUSER: ${message}`, max_tokens: 400 }; const res = await fetch(process.env.LLM_API_URL, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${process.env.LLM_API_KEY}` }, body: JSON.stringify(payload) 2
}); const json = await res.json(); // Adjust to your LLM response shape return json.reply || json.text || (json.choices && json.choices[0] && json.choices[0].text) || 'Sorry, something went wrong.'; } // Simple storage for leads (append to a JSON file). Replace with DB if you want. function storeLead(lead) { try { const file = path.join(process.cwd(),'leads.json'); const arr = fs.existsSync(file) ? JSON.parse(fs.readFileSync(file)) : []; arr.push(Object.assign({createdAt: new Date().toISOString()}, lead)); fs.writeFileSync(file, JSON.stringify(arr,null,2)); } catch (e) { console.error('lead store error', e); } } // Chat webhook (from your site widget) app.post('/chat/webhook', async (req, res) => { const { message, sessionId } = req.body; if (!message) return res.status(400).json({error:'message required'}); try { const reply = await callLLM(message, sessionId || 'anon'); // If the reply asks to book, make sure to include the Calendly link in the reply const replyWithBooking = reply.replace('{CALENDLY_LINK}', process.env.CALENDLY_LINK || '[CALENDLY_LINK]'); // Optionally detect lead intent and store if (/book|schedule|hire|start|consult/i.test(message)) { // store a minimal lead storeLead({source:'chat', message, sessionId}); } return res.json({ reply: replyWithBooking }); } catch (e) { console.error(e); return res.status(500).json({error:'LLM error'}); } }); // Twilio voice incoming: Twilio will POST speech result (if you use Twilio Gather) app.post('/voice/incoming', async (req, res) => { // This endpoint expects Twilio's Gather result: SpeechResult const speech = req.body.SpeechResult || ''; // Minimal TwiML response let replyText = 'Hi! This is Ranqeo. Could you tell me your name and website?'; 3
if (speech) { // If user spoke, pass speech to LLM replyText = await callLLM(speech, `phone-${req.body.From || 'unknown'}`); // If user asked to book, we will SMS a Calendly link (below) if (/book|schedule|call|meet|consult/i.test(speech)) { // Send an SMS via Twilio (server should call Twilio REST API). Keep placeholder here: implement with twilio SDK. // store lead storeLead({source:'phone', from: req.body.From, message: speech}); } } // Return TwiML res.type('text/xml').send(`<?xml version="1.0" encoding="UTF-8"?> <Response> <Say>${replyText}</Say> <Pause length="1"/> <Gather input="speech" action="/voice/incoming" speechTimeout="auto"> <Say>Anything else? You can say book to receive a scheduling link via SMS.</ Say> </Gather> <Say>Goodbye.</Say> </Response> `); }); const PORT = process.env.PORT || 3000; app.listen(PORT, () => console.log('Ranqeo server running on', PORT)); 2) package.json { "name": "ranqeo-ai-agent", "version": "1.0.0", "type": "module", "scripts": { "start": "node index.js" }, "dependencies": { "express": "^4.18.2", "body-parser": "^1.20.2", "node-fetch": "^2.6.7" } } 4
3) Frontend — widget snippet (drop this into your website HTML) Place this snippet before </body> on your website. It creates a small chat launcher and calls the /chat/ webhook endpoint. <!-- Ranqeo Chat Widget - simple drop-in --> <div id="ranqeo-chat" style="position:fixed;right:24px;bottom:24px;z-index: 10000"> <button id="ranqeo-launch" style="background:#111;color:#fff;padding:12px 16px;border-radius:28px;border:none;box-shadow:0 4px 12px rgba(0,0,0,0.2);">Chat with Ranqeo</button> <div id="ranqeo-box" style="display:none;width:340px;height: 460px;background:#fff;border-radius:8px;box-shadow:0 6px 20px rgba(0,0,0,0.2);overflow:hidden;margin-top:8px;"> <iframe id="ranqeo-iframe" style="border:0;width:100%;height:100%;"></ iframe> </div> </div> <script> (function(){ const btn = document.getElementById('ranqeo-launch'); const box = document.getElementById('ranqeo-box'); const iframe = document.getElementById('ranqeo-iframe'); btn.addEventListener('click', ()=>{ box.style.display = box.style.display === 'none' ? 'block' : 'none'; if (box.style.display === 'block') { // load a minimal chat UI hosted on your server or a static HTML you create iframe.src = '/ranqeo-chat-ui.html'; } }); })(); </script> Note: ranqeo-chat-ui.html should be a lightweight static page that opens a text input and sends the message to /chat/webhook (example included below). 4) Chat UI — frontend/ranqeo-chat-ui.html <!doctype html> <html> <head><meta charset="utf-8"><title>Ranqeo Chat</title></head> 5
<body style="font-family:Arial;margin:0;"> <div style="display:flex;flex-direction:column;height:100vh;"> <header style="padding:12px;background:#0b2340;color:white;">Ranqeo — SEO assistant</header> <div id="messages" style="flex:1;padding: 8px;overflow:auto;background:#f7f7f9;"></div> <form id="form" style="display:flex;padding:8px;border-top:1px solid #eee;"> <input id="input" style="flex:1;padding:10px;border:1px solid #ddd;border- radius:6px;margin-right:8px;" placeholder="Type your question..." /> <button type="submit" style="padding:10px 12px;border-radius: 6px;background:#0b2340;color:#fff;border:none;">Send</button> </form> </div> <script> const messages = document.getElementById('messages'); const form = document.getElementById('form'); const input = document.getElementById('input'); function addMsg(who, text){ const d = document.createElement('div'); d.style.padding='8px'; d.style.margin='6px 0'; d.innerHTML = `<b>${who}</b><div>${text}</div>`; messages.appendChild(d); messages.scrollTop = messages.scrollHeight; } form.addEventListener('submit', async (e)=>{ e.preventDefault(); const msg = input.value.trim(); if(!msg) return; addMsg('You', msg); input.value=''; addMsg('Ranqeo', 'Typing...'); const res = await fetch('/chat/webhook', {method:'POST',headers:{'Content- Type':'application/json'},body:JSON.stringify({message:msg, sessionId: Date.now().toString()})}); const json = await res.json(); // replace the last 'Typing...' message messages.removeChild(messages.lastChild); addMsg('Ranqeo', json.reply || 'Sorry, try again later.'); }); </script> </body> </html> 6
5) KB starter files ( kb/services.md , kb/pricing.md , kb/ faq.md ) kb/services.md Ranqeo Services: - Monthly SEO (technical + on-page + content strategy + link building). - SEO Audit & Migration. - Local SEO & Google Business optimization. - Content + Blog strategy for keywords and topical authority. kb/pricing.md Pricing guidance: - Starter retainer: $350 / month (basic local or small site). - Growth retainer: $700-$1,500 / month (more pages, link building). - Enterprise: custom pricing depending on scale and goals. kb/faq.md FAQ: - How long until results? Usually 3–6 months for measurable organic growth. - Do you guarantee #1 ranking? No — guarantees are not ethical or realistic. - Reporting cadence: monthly reports with keyword and traffic changes. 6) prompt/agent_prompt.txt (system prompt) You are Ranqeo's AI assistant. Ranqeo is an SEO agency. Your goals: 1) Greet warmly and be concise. 2) Answer SEO questions clearly and accurately using the KB if relevant. 3) Qualify leads by asking: business type, website URL, target market, monthly budget, and timeline. 4) Offer a booking link when user expresses intent to schedule. Use placeholder {CALENDLY_LINK} to be replaced by the server. 5) Never promise guaranteed rankings; be transparent about timelines (3-6 months). 6) If the user provides payment intent, give payment instructions: NayaPay 7
account (fill details from env). 7) Keep answers short (<120 words) and use bullets when helpful. 7) Payment instruction placeholder In the server or KB you can fill NAYAPAY_INFO or add it into responses manually. Example text to include in receipts or paid invoices: NayaPay account: [your-naya-pay-username-or-IBAN] Please send proof of payment to billing@ranqeo.com 8) Twilio setup (voice & SMS) 1. 2. 3. Create a Twilio account and buy a phone number. Point the phone number's Voice webhook to https://<your-server>/voice/incoming (POST). Optionally use Twilio Studio to create a more robust IVR; the server above supports a basic gather flow. To send SMS booking links, install twilio SDK and use client.messages.create({to: from, from: TWILIO_PHONE_NUMBER, body: 'Book here: <CALENDLY>'}) where appropriate. 4. Important: If you plan to record or transcribe voice, add a recorded-call notice. 9) Booking (Calendly) • Create a Calendly account and copy your scheduling link (e.g. https://calendly.com/ranqeo/ 30min ). Paste it into your server's CALENDLY_LINK environment variable. When the agent says “I’ll send a booking link,” the server will include the link in the message. • • 10) Lead capture & CRM Two options: - Simple (recommended): store leads to leads.json (already included) and/or forward to Google Sheets via a webhook (Zapier). Replace storeLead to POST to your Zapier webhook URL. - Advanced: integrate HubSpot API (free CRM) or Airtable. 8
11) Deploying (Vercel / Render / DigitalOcean App Platform) 1. 2. Push the server/ folder to GitHub. On Vercel: Import the repo, set environment variables (LLM_API_URL, LLM_API_KEY, CALENDLY_LINK, etc), and deploy. Vercel will detect Node and run npm start . On Render: Create a Web Service, link repo, set start command node index.js and env vars. 3. CORS / HTTPS: Make sure your site is served under HTTPS and that /chat/webhook is accessible from your site origin. 12) Security & moderation • • • Don’t expose your LLM API key in client-side code. Keep all LLM calls on the server. Rate-limit requests or add a token check to /chat/webhook to avoid abuse. Add logging and monitor the leads file. 13) Optional: I can produce a ZIP you can download If you'd like, I can package these files into a ready-to-download ZIP (you must confirm). Otherwise, copy the files into your host/repo and deploy. 14) Support & next steps 1. 2. 3. 4. Replace env placeholders with your real keys and Calendly link. Deploy the server and set the Twilio webhook to the server's public URL. Drop the widget snippet into your website. Test by sending sample chat messages and calling the Twilio number. If you want, I can now: - Generate and provide a ZIP with all files. - Provide step-by-step deployment help for Vercel (I will include exact env var setup instructions). End of package. Good luck — Ranqeo is ready to chat! 9