403Webshell
Server IP : 69.72.244.102  /  Your IP : 216.73.216.164
Web Server : LiteSpeed
System : Linux s3434.fra1.stableserver.net 4.18.0-513.24.1.lve.2.el8.x86_64 #1 SMP Fri May 24 12:42:50 UTC 2024 x86_64
User : konzalta ( 1271)
PHP Version : 7.4.33
Disable Function : NONE
MySQL : OFF  |  cURL : ON  |  WGET : ON  |  Perl : ON  |  Python : ON  |  Sudo : OFF  |  Pkexec : OFF
Directory :  /home/konzalta/constituency.work/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ Back ]     

Current File : /home/konzalta/constituency.work/ai_assistant.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ConstituencyOS – AI Assistant</title>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet">
<style>
*,*::before,*::after{box-sizing:border-box;margin:0;padding:0;}
:root{
  --green:#1a7a4a;--green-light:#e8f5ee;--green-mid:#2d9e63;
  --red:#dc2626;--red-light:#fdecea;
  --amber:#f59e0b;--amber-light:#fffbeb;
  --blue:#2563eb;--blue-light:#eff6ff;
  --purple:#7c3aed;--purple-light:#f5f3ff;
  --text:#111827;--muted:#6b7280;--light:#9ca3af;
  --border:#e5e7eb;--bg:#f3f4f6;--white:#ffffff;
  --sidebar-w:216px;--radius:10px;--radius-sm:6px;
  --shadow:0 1px 3px rgba(0,0,0,.08);
}
html,body{height:100%;margin:0;padding:0;}
body{font-family:'Inter',sans-serif;font-size:13px;color:var(--text);background:var(--bg);}
.sidebar{position:fixed;top:0;left:0;bottom:0;width:var(--sidebar-w);background:var(--white);border-right:1px solid var(--border);display:flex;flex-direction:column;overflow-y:auto;overflow-x:hidden;z-index:40;}
.sidebar-logo{display:flex;align-items:center;gap:9px;padding:14px 14px 12px;border-bottom:1px solid var(--border);flex-shrink:0;}
.logo-icon{width:38px;height:38px;background:linear-gradient(135deg,#b91c1c,#1a7a4a);border-radius:8px;display:flex;align-items:center;justify-content:center;font-size:17px;flex-shrink:0;}
.logo-text strong{display:block;font-size:12.5px;font-weight:700;color:var(--green);}
.logo-text small{font-size:10px;color:var(--muted);line-height:1.3;}
.sidebar-profile{display:flex;align-items:center;gap:9px;padding:11px 14px;border-bottom:1px solid var(--border);flex-shrink:0;}
.s-av{width:36px;height:36px;border-radius:50%;background:#374151;color:white;font-weight:600;font-size:13px;display:flex;align-items:center;justify-content:center;flex-shrink:0;position:relative;}
.s-av .dot{position:absolute;bottom:1px;right:1px;width:8px;height:8px;border-radius:50%;background:var(--green-mid);border:2px solid white;}
.pname{font-size:11.5px;font-weight:600;}.psub{font-size:10.5px;color:var(--muted);}
.sidebar-nav{flex:1;padding:6px 0;}
.nav-item{display:flex;align-items:center;gap:9px;padding:8px 14px;font-size:12px;font-weight:500;color:var(--muted);cursor:pointer;position:relative;transition:background .12s,color .12s;white-space:nowrap;}
.nav-item:hover{background:var(--bg);color:var(--text);}
.nav-item.active{background:var(--green-light);color:var(--green);font-weight:600;}
.nav-item.active::before{content:'';position:absolute;left:0;top:0;bottom:0;width:3px;background:var(--green);border-radius:0 2px 2px 0;}
.nav-icon{font-size:14px;width:16px;text-align:center;flex-shrink:0;}
.nav-badge{margin-left:auto;background:var(--red);color:white;font-size:9.5px;font-weight:700;padding:1px 5px;border-radius:10px;}
.nav-new{margin-left:auto;background:var(--green);color:white;font-size:9px;font-weight:700;padding:2px 5px;border-radius:4px;}
.nav-chev{margin-left:auto;font-size:10px;color:var(--light);}
.sidebar-footer{padding:12px 14px;border-top:1px solid var(--border);flex-shrink:0;}
.right-panel{margin-left:var(--sidebar-w);display:flex;flex-direction:column;height:100vh;}
.topbar{flex-shrink:0;height:52px;background:var(--white);border-bottom:1px solid var(--border);display:flex;align-items:center;gap:10px;padding:0 18px;}
.menu-btn{font-size:17px;cursor:pointer;color:var(--muted);}
.const-sel{display:flex;align-items:center;gap:6px;background:var(--bg);border:1px solid var(--border);border-radius:var(--radius-sm);padding:5px 10px;cursor:pointer;font-size:12px;font-weight:500;}
.srch{flex:1;max-width:360px;display:flex;align-items:center;gap:7px;background:var(--bg);border:1px solid var(--border);border-radius:var(--radius-sm);padding:6px 11px;color:var(--muted);font-size:12px;}
.srch input{border:none;background:transparent;outline:none;width:100%;font-size:12px;font-family:inherit;}
.srch kbd{margin-left:auto;font-size:9.5px;background:var(--border);padding:1px 5px;border-radius:3px;font-family:inherit;}
.tbr{margin-left:auto;display:flex;align-items:center;gap:8px;}
.ibt{position:relative;width:32px;height:32px;border-radius:50%;background:var(--bg);border:1px solid var(--border);display:flex;align-items:center;justify-content:center;cursor:pointer;font-size:15px;}
.ibt .bdg{position:absolute;top:-3px;right:-3px;background:var(--red);color:white;font-size:9px;font-weight:700;width:15px;height:15px;border-radius:50%;display:flex;align-items:center;justify-content:center;border:1.5px solid white;}
.ibt .bdg.grn{background:var(--green-mid);}
.upill{display:flex;align-items:center;gap:7px;border:1px solid var(--border);border-radius:var(--radius-sm);padding:3px 8px;cursor:pointer;font-size:12px;font-weight:500;}

/* ===== CHAT LAYOUT ===== */
.chat-shell{flex:1;display:flex;min-height:0;}

/* Left: conversation history rail */
.history-rail{width:230px;flex-shrink:0;background:var(--white);border-right:1px solid var(--border);display:flex;flex-direction:column;}
.history-hdr{padding:14px;border-bottom:1px solid var(--border);}
.new-chat-btn{width:100%;display:flex;align-items:center;justify-content:center;gap:6px;background:var(--green);color:white;border:none;border-radius:var(--radius-sm);padding:9px;font-size:12px;font-weight:600;cursor:pointer;}
.new-chat-btn:hover{background:var(--green-mid);}
.history-list{flex:1;overflow-y:auto;padding:8px;}
.history-group-lbl{font-size:10px;font-weight:700;color:var(--light);text-transform:uppercase;letter-spacing:.5px;padding:8px 8px 4px;}
.history-item{padding:9px 10px;border-radius:var(--radius-sm);font-size:11.5px;color:var(--muted);cursor:pointer;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;margin-bottom:2px;}
.history-item:hover{background:var(--bg);color:var(--text);}
.history-item.active{background:var(--green-light);color:var(--green);font-weight:600;}

/* Center: chat column */
.chat-col{flex:1;display:flex;flex-direction:column;min-width:0;background:var(--bg);}
.chat-scroll{flex:1;overflow-y:auto;padding:24px 0;}
.chat-inner{max-width:760px;margin:0 auto;padding:0 24px;display:flex;flex-direction:column;gap:18px;}

/* Welcome state */
.welcome{text-align:center;padding:50px 20px 10px;}
.welcome-icon{width:56px;height:56px;border-radius:16px;background:linear-gradient(135deg,#1a7a4a,#2d9e63);display:flex;align-items:center;justify-content:center;font-size:26px;margin:0 auto 16px;color:white;}
.welcome-title{font-size:20px;font-weight:700;}
.welcome-sub{font-size:13px;color:var(--muted);margin-top:6px;max-width:420px;margin-left:auto;margin-right:auto;line-height:1.5;}
.suggestion-grid{display:grid;grid-template-columns:1fr 1fr;gap:10px;max-width:600px;margin:24px auto 0;}
.suggestion-card{background:var(--white);border:1px solid var(--border);border-radius:var(--radius);padding:13px 15px;text-align:left;cursor:pointer;transition:box-shadow .15s,border-color .15s;}
.suggestion-card:hover{box-shadow:0 4px 14px rgba(0,0,0,.08);border-color:var(--green-mid);}
.suggestion-icon{font-size:16px;margin-bottom:6px;}
.suggestion-text{font-size:12px;font-weight:600;line-height:1.4;}

/* Messages */
.msg-row{display:flex;gap:12px;align-items:flex-start;}
.msg-row.user{flex-direction:row-reverse;}
.msg-avatar{width:30px;height:30px;border-radius:50%;flex-shrink:0;display:flex;align-items:center;justify-content:center;font-size:14px;color:white;}
.msg-avatar.ai{background:linear-gradient(135deg,#1a7a4a,#2d9e63);}
.msg-avatar.user{background:#374151;font-size:11px;font-weight:700;}
.msg-bubble{max-width:78%;padding:11px 15px;border-radius:14px;font-size:12.5px;line-height:1.6;}
.msg-row.ai .msg-bubble{background:var(--white);border:1px solid var(--border);border-top-left-radius:4px;}
.msg-row.user .msg-bubble{background:var(--green);color:white;border-top-right-radius:4px;}
.msg-bubble p{margin-bottom:8px;}
.msg-bubble p:last-child{margin-bottom:0;}
.msg-bubble ul{margin:6px 0 6px 18px;}
.msg-bubble li{margin-bottom:3px;}
.msg-bubble strong{font-weight:700;}
.msg-time{font-size:9.5px;color:var(--light);margin-top:4px;}
.msg-row.user .msg-time{text-align:right;}

/* Citation chips inside AI messages */
.cite-chip{display:inline-flex;align-items:center;gap:4px;font-size:10.5px;font-weight:600;background:var(--green-light);color:var(--green);padding:3px 9px;border-radius:20px;margin:6px 4px 0 0;cursor:pointer;text-decoration:none;}
.cite-chip:hover{background:#d1f0dd;}

/* Follow-up suggestion chips */
.followup-row{display:flex;flex-wrap:wrap;gap:6px;margin-top:10px;margin-left:42px;}
.followup-chip{font-size:11px;font-weight:500;background:var(--white);border:1px solid var(--border);color:var(--text);padding:6px 12px;border-radius:20px;cursor:pointer;transition:background .15s,border-color .15s;}
.followup-chip:hover{background:var(--green-light);border-color:var(--green-mid);color:var(--green);}

/* Typing indicator */
.typing-row{display:flex;gap:12px;align-items:flex-start;}
.typing-bubble{background:var(--white);border:1px solid var(--border);border-radius:14px;border-top-left-radius:4px;padding:13px 16px;display:flex;gap:4px;align-items:center;}
.typing-dot{width:6px;height:6px;border-radius:50%;background:var(--light);animation:typingBounce 1.2s infinite;}
.typing-dot:nth-child(2){animation-delay:.15s;}
.typing-dot:nth-child(3){animation-delay:.3s;}
@keyframes typingBounce{0%,60%,100%{transform:translateY(0);opacity:.5;}30%{transform:translateY(-4px);opacity:1;}}

/* Composer */
.composer-wrap{flex-shrink:0;border-top:1px solid var(--border);background:var(--white);padding:14px 24px 16px;}
.composer-inner{max-width:760px;margin:0 auto;}
.disclaimer{font-size:10px;color:var(--light);text-align:center;margin-top:8px;}
.composer-box{display:flex;align-items:flex-end;gap:8px;background:var(--bg);border:1px solid var(--border);border-radius:14px;padding:8px 8px 8px 16px;transition:border-color .15s;}
.composer-box:focus-within{border-color:var(--green);background:var(--white);}
.composer-box textarea{flex:1;border:none;background:transparent;outline:none;resize:none;font-family:inherit;font-size:13px;color:var(--text);max-height:120px;line-height:1.5;padding:6px 0;}
.composer-box textarea::placeholder{color:var(--light);}
.composer-actions{display:flex;align-items:center;gap:4px;}
.composer-icon-btn{width:32px;height:32px;border-radius:50%;border:none;background:transparent;display:flex;align-items:center;justify-content:center;font-size:15px;cursor:pointer;color:var(--muted);}
.composer-icon-btn:hover{background:var(--border);}
.send-btn{width:34px;height:34px;border-radius:50%;border:none;background:var(--green);color:white;display:flex;align-items:center;justify-content:center;font-size:14px;cursor:pointer;flex-shrink:0;transition:background .15s;}
.send-btn:hover{background:var(--green-mid);}
.send-btn:disabled{background:var(--border);color:var(--light);cursor:not-allowed;}

/* Quick prompt strip above composer when conversation active */
.quick-strip{display:flex;gap:6px;overflow-x:auto;padding-bottom:10px;max-width:760px;margin:0 auto;}
.quick-chip{flex-shrink:0;font-size:11px;font-weight:500;background:var(--bg);border:1px solid var(--border);color:var(--muted);padding:6px 12px;border-radius:20px;cursor:pointer;white-space:nowrap;}
.quick-chip:hover{background:var(--green-light);border-color:var(--green-mid);color:var(--green);}
</style>
</head>
<body>
<aside class="sidebar">
  <div class="sidebar-logo"><div class="logo-icon">πŸ›οΈ</div><div class="logo-text"><strong>ConstituencyOS</strong><small>Everything in your constituency,<br>in one place.</small></div></div>
  <div class="sidebar-profile"><div class="s-av">DM<div class="dot"></div></div><div><div class="pname">Hon. David Mwangi, MP</div><div class="psub">Embakasi South</div></div></div>
  <nav class="sidebar-nav">
    <div class="nav-item" onclick="location.href='index.html'"><span class="nav-icon">🏠</span>Dashboard</div>
    <div class="nav-item" onclick="location.href='constituents.html'"><span class="nav-icon">πŸ‘₯</span>Constituents</div>
    <div class="nav-item" onclick="location.href='complaints.html'"><span class="nav-icon">πŸ“‹</span>Complaints<span class="nav-badge">9</span></div>
    <div class="nav-item" onclick="location.href='projects.html'"><span class="nav-icon">πŸ“</span>Projects</div>
    <div class="nav-item" onclick="location.href='bursaries.html'"><span class="nav-icon">πŸŽ“</span>Bursaries</div>
    <div class="nav-item" onclick="location.href='events.html'"><span class="nav-icon">πŸ“…</span>Events</div>
    <div class="nav-item" onclick="location.href='social_protection.html'"><span class="nav-icon">πŸ›‘οΈ</span>Social Protection</div>
    <div class="nav-item" onclick="location.href='ward_management.html'"><span class="nav-icon">🏘️</span>Ward Management</div>
    <div class="nav-item" onclick="location.href='finance.html'"><span class="nav-icon">πŸ’°</span>Finance</div>
    <div class="nav-item" onclick="location.href='documents.html'"><span class="nav-icon">πŸ“„</span>Documents</div>
    <div class="nav-item" onclick="location.href='staff_management.html'"><span class="nav-icon">πŸ‘€</span>Staff Management</div>
    <div class="nav-item" onclick="location.href='reports_analytics.html'"><span class="nav-icon">πŸ“Š</span>Reports & Analytics</div>
    <div class="nav-item active"><span class="nav-icon">πŸ€–</span>AI Assistant<span class="nav-new">New</span></div>
    <div class="nav-item" onclick="location.href='settings.html'"><span class="nav-icon">βš™οΈ</span>Settings</div>
    <div class="nav-item" onclick="location.href='public_portal.html'"><span class="nav-icon">🌐</span>Public Portal</div>
  </nav>
  <div class="sidebar-footer"><div style="display:flex;align-items:center;gap:9px;cursor:pointer"><span>❓</span><div><div style="font-size:11.5px;font-weight:600">Need Help?</div><div style="font-size:10.5px;color:var(--muted)">Contact Support</div></div></div></div>
</aside>

<div class="right-panel">
  <header class="topbar">
    <span class="menu-btn">☰</span>
    <div class="const-sel"><span style="font-size:13px">πŸ›οΈ</span>Embakasi South Constituency<span style="font-size:10px;color:var(--muted)">β–Ό</span></div>
    <div class="srch"><span>πŸ”</span><input type="text" placeholder="Search for anything…"><kbd>⌘K</kbd></div>
    <div class="tbr">
      <div class="ibt">πŸ””<div class="bdg">8</div></div>
      <div class="ibt">βœ‰οΈ<div class="bdg grn">3</div></div>
      <div class="upill"><div class="s-av" style="width:26px;height:26px;font-size:10px">DM</div>Hon. David Mwangi<span style="font-size:10px;color:var(--muted)">β–Ό</span></div>
    </div>
  </header>

  <div class="chat-shell">

    <!-- History rail -->
    <div class="history-rail">
      <div class="history-hdr">
        <button class="new-chat-btn" onclick="newChat()">οΌ‹ New Chat</button>
      </div>
      <div class="history-list">
        <div class="history-group-lbl">Today</div>
        <div class="history-item active" onclick="selectHistory(this)">Current conversation</div>
        <div class="history-group-lbl">Previous 7 Days</div>
        <div class="history-item" onclick="selectHistory(this)">Budget utilisation by ward</div>
        <div class="history-item" onclick="selectHistory(this)">Draft Pipeline Ward baraza speech</div>
        <div class="history-item" onclick="selectHistory(this)">Bursary approval summary β€” May</div>
        <div class="history-item" onclick="selectHistory(this)">Complaints trending in Kwa Njenga</div>
        <div class="history-group-lbl">Previous 30 Days</div>
        <div class="history-item" onclick="selectHistory(this)">Q3 financial statement summary</div>
        <div class="history-item" onclick="selectHistory(this)">Social protection enrolment trends</div>
        <div class="history-item" onclick="selectHistory(this)">Project delay risk assessment</div>
      </div>
    </div>

    <!-- Chat column -->
    <div class="chat-col">
      <div class="chat-scroll" id="chatScroll">
        <div class="chat-inner" id="chatInner">

          <!-- Welcome state -->
          <div class="welcome" id="welcomeState">
            <div class="welcome-icon">πŸ€–</div>
            <div class="welcome-title">Hi David, how can I help today?</div>
            <div class="welcome-sub">I can pull insights from your constituency data β€” complaints, projects, budgets, bursaries, and more. Ask me anything or try a suggestion below.</div>
            <div class="suggestion-grid">
              <div class="suggestion-card" onclick="sendSuggestion(this)">
                <div class="suggestion-icon">πŸ“‹</div>
                <div class="suggestion-text">Summarize this week's pending complaints</div>
              </div>
              <div class="suggestion-card" onclick="sendSuggestion(this)">
                <div class="suggestion-icon">πŸ’°</div>
                <div class="suggestion-text">What's our current budget utilisation?</div>
              </div>
              <div class="suggestion-card" onclick="sendSuggestion(this)">
                <div class="suggestion-icon">✍️</div>
                <div class="suggestion-text">Draft a speech for the Pipeline Ward baraza</div>
              </div>
              <div class="suggestion-card" onclick="sendSuggestion(this)">
                <div class="suggestion-icon">πŸŽ“</div>
                <div class="suggestion-text">How are this year's bursary applications trending?</div>
              </div>
              <div class="suggestion-card" onclick="sendSuggestion(this)">
                <div class="suggestion-icon">πŸ“</div>
                <div class="suggestion-text">Which projects are at risk of delay?</div>
              </div>
              <div class="suggestion-card" onclick="sendSuggestion(this)">
                <div class="suggestion-icon">🏘️</div>
                <div class="suggestion-text">Compare ward performance this quarter</div>
              </div>
            </div>
          </div>

        </div>
      </div>

      <!-- Composer -->
      <div class="composer-wrap">
        <div class="quick-strip" id="quickStrip" style="display:none;">
          <div class="quick-chip" onclick="sendQuick(this)">Open complaints by ward</div>
          <div class="quick-chip" onclick="sendQuick(this)">Bursary approval rate</div>
          <div class="quick-chip" onclick="sendQuick(this)">Project delay risks</div>
          <div class="quick-chip" onclick="sendQuick(this)">Today's schedule</div>
        </div>
        <div class="composer-inner">
          <div class="composer-box">
            <textarea id="composerInput" rows="1" placeholder="Ask about complaints, projects, budgets, bursaries…" onkeydown="handleKeydown(event)" oninput="autoGrow(this)"></textarea>
            <div class="composer-actions">
              <button class="composer-icon-btn" title="Attach file">πŸ“Ž</button>
              <button class="send-btn" id="sendBtn" onclick="sendMessage()" disabled>➀</button>
            </div>
          </div>
          <div class="disclaimer">AI Assistant is a prototype feature. Responses are illustrative and based on demo data β€” verify before acting.</div>
        </div>
      </div>
    </div>
  </div>
</div>

<script>
const composerInput = document.getElementById('composerInput');
const sendBtn = document.getElementById('sendBtn');
const chatInner = document.getElementById('chatInner');
const chatScroll = document.getElementById('chatScroll');
const welcomeState = document.getElementById('welcomeState');
const quickStrip = document.getElementById('quickStrip');

let conversationStarted = false;

function autoGrow(el){
  el.style.height = 'auto';
  el.style.height = Math.min(el.scrollHeight, 120) + 'px';
  sendBtn.disabled = el.value.trim().length === 0;
}

function handleKeydown(e){
  if(e.key==='Enter' && !e.shiftKey){
    e.preventDefault();
    sendMessage();
  }
}

function nowTime(){
  return new Date().toLocaleTimeString('en-GB',{hour:'2-digit',minute:'2-digit'});
}

function scrollToBottom(){
  setTimeout(()=>{ chatScroll.scrollTop = chatScroll.scrollHeight; }, 50);
}

function startConversationIfNeeded(){
  if(!conversationStarted){
    welcomeState.style.display = 'none';
    quickStrip.style.display = 'flex';
    conversationStarted = true;
  }
}

function appendUserMessage(text){
  startConversationIfNeeded();
  const row = document.createElement('div');
  row.className = 'msg-row user';
  row.innerHTML = `
    <div class="msg-avatar user">DM</div>
    <div>
      <div class="msg-bubble">${escapeHtml(text)}</div>
      <div class="msg-time">${nowTime()}</div>
    </div>
  `;
  chatInner.appendChild(row);
  scrollToBottom();
}

function escapeHtml(s){
  const d = document.createElement('div');
  d.textContent = s;
  return d.innerHTML;
}

function appendTypingIndicator(){
  const row = document.createElement('div');
  row.className = 'typing-row';
  row.id = 'typingRow';
  row.innerHTML = `
    <div class="msg-avatar ai">πŸ€–</div>
    <div class="typing-bubble">
      <div class="typing-dot"></div><div class="typing-dot"></div><div class="typing-dot"></div>
    </div>
  `;
  chatInner.appendChild(row);
  scrollToBottom();
}

function removeTypingIndicator(){
  const row = document.getElementById('typingRow');
  if(row) row.remove();
}

function appendAiMessage(html, citations, followups){
  const row = document.createElement('div');
  row.className = 'msg-row ai';
  let citeHtml = '';
  if(citations && citations.length){
    citeHtml = citations.map(c=>`<a class="cite-chip" href="${c.href}">πŸ“Ž ${c.label}</a>`).join('');
  }
  row.innerHTML = `
    <div class="msg-avatar ai">πŸ€–</div>
    <div>
      <div class="msg-bubble">${html}${citeHtml}</div>
      <div class="msg-time">${nowTime()}</div>
    </div>
  `;
  chatInner.appendChild(row);

  if(followups && followups.length){
    const fRow = document.createElement('div');
    fRow.className = 'followup-row';
    fRow.innerHTML = followups.map(f=>`<div class="followup-chip" onclick="sendFollowup(this)">${f}</div>`).join('');
    chatInner.appendChild(fRow);
  }
  scrollToBottom();
}

// ===== Canned response engine =====
function getResponse(query){
  const q = query.toLowerCase();

  if(q.includes('complaint')){
    return {
      html: `<p>Here's the current complaints snapshot for Embakasi South:</p>
        <ul>
          <li><strong>23 complaints</strong> are currently pending across all wards (β–²12% vs last week)</li>
          <li><strong>Kwa Njenga Ward</strong> and <strong>Pipeline Ward</strong> have the highest open counts</li>
          <li><strong>3 high-priority</strong> issues remain unassigned, including a broken bridge in Imara Daima</li>
          <li>Average resolution time is <strong>2.4 days</strong>, 20% faster than target</li>
        </ul>
        <p>Want me to draft assignment notes for the unassigned high-priority items?</p>`,
      citations: [{label:'View Complaints', href:'complaints.html'}],
      followups: ['Draft assignment notes', 'Show high-priority only', 'Compare to last month']
    };
  }
  if(q.includes('budget') || q.includes('finance') || q.includes('financ')){
    return {
      html: `<p>Budget utilisation for FY 2023/2024 stands at <strong>63%</strong>:</p>
        <ul>
          <li><strong>KSh 123.4M</strong> disbursed of a <strong>KSh 195.2M</strong> total allocation</li>
          <li><strong>KSh 71.8M</strong> remains unutilised, with Q3 disbursements due in June</li>
          <li><strong>Roads &amp; Infrastructure</strong> and <strong>Health</strong> sectors have the highest absolute spend</li>
          <li><strong>3 projects</strong> are flagged pending audit review, totalling KSh 4.2M</li>
        </ul>
        <p>I can break this down by ward or by sector if that's more useful.</p>`,
      citations: [{label:'View Finance', href:'finance.html'}],
      followups: ['Break down by ward', 'Break down by sector', 'Show flagged audits']
    };
  }
  if(q.includes('speech') || q.includes('baraza') || q.includes('draft')){
    return {
      html: `<p>Here's a draft opening for the Pipeline Ward baraza:</p>
        <p style="background:#f3f4f6;padding:10px 12px;border-radius:8px;font-style:italic;">"Wananchi wa Pipeline, asanteni kwa kunikaribisha leo. Tumepiga hatua kubwa katika mradi wa maji wa Kiandutu β€” sasa umefikia asilimia 68. Tutaendelea kushirikiana ili kuhakikisha kila kaya inapata maji safi. Pia, leo tutazungumzia kuhusu barabara, bursary, na masuala mengine mnayotaka kuyajadili..."</p>
        <p>This covers the water project update and opens the floor for community input. I can extend it with road project updates or bursary disbursement figures if you'd like.</p>`,
      citations: [{label:'View Ward Management', href:'ward_management.html'}],
      followups: ['Add road project update', 'Add bursary figures', 'Make it shorter']
    };
  }
  if(q.includes('bursary') || q.includes('bursaries') || q.includes('scholarship')){
    return {
      html: `<p>Bursary applications for FY 2023/2024 so far:</p>
        <ul>
          <li><strong>3,248 total applications</strong> received, up 14% on last year</li>
          <li><strong>1,892 approved</strong> (58% approval rate), <strong>1,156 under review</strong></li>
          <li><strong>200 rejected</strong>, mostly due to incomplete documentation</li>
          <li><strong>Pipeline</strong> and <strong>Imara Daima</strong> wards have the highest application volume</li>
        </ul>
        <p>Would you like a list of applications still pending review for more than 14 days?</p>`,
      citations: [{label:'View Bursaries', href:'bursaries.html'}],
      followups: ['Show overdue reviews', 'Approval rate by ward', 'Export application list']
    };
  }
  if(q.includes('project') && (q.includes('delay') || q.includes('risk'))){
    return {
      html: `<p><strong>5 projects</strong> are currently flagged as delayed:</p>
        <ul>
          <li><strong>Pipeline Road Rehabilitation</strong> β€” 30% complete, blocked on contractor materials</li>
          <li><strong>Imara Daima Footbridge Repair</strong> β€” 10% complete, urgent due to safety risk</li>
          <li>3 additional projects are tracking 1–3 weeks behind schedule</li>
        </ul>
        <p>The footbridge repair is the highest priority given the safety concern. Want me to draft a follow-up to the contractor?</p>`,
      citations: [{label:'View Projects', href:'projects.html'}],
      followups: ['Draft contractor follow-up', 'Show all delayed projects', 'Notify ward administrator']
    };
  }
  if(q.includes('ward') && (q.includes('compar') || q.includes('performance'))){
    return {
      html: `<p>Quick ward performance comparison for this quarter:</p>
        <ul>
          <li><strong>Umoja Ward</strong> leads in complaint resolution rate at 97%</li>
          <li><strong>Pipeline Ward</strong> has the highest budget utilisation at 88%</li>
          <li><strong>Kwa Njenga Ward</strong> has the lowest resolution rate (84%) β€” water-related issues are the main driver</li>
          <li>Bursary recipients are fairly proportional to ward population across the board</li>
        </ul>
        <p>Full breakdown with population-adjusted metrics is available in Reports &amp; Analytics.</p>`,
      citations: [{label:'View Reports & Analytics', href:'reports_analytics.html'}],
      followups: ['Focus on Kwa Njenga', 'Show population-adjusted view', 'Export comparison table']
    };
  }
  if(q.includes('schedule') || q.includes('today') || q.includes('event')){
    return {
      html: `<p>Here's what's on today, 20 May 2024:</p>
        <ul>
          <li><strong>8:00 AM</strong> β€” Constituency Staff Meeting, Parliamentary Office</li>
          <li><strong>10:00 AM</strong> β€” School Opening, St. Bakhita Primary (Umoja II)</li>
          <li><strong>1:00 PM</strong> β€” Baraza, Pipeline Ward Office</li>
          <li><strong>4:00 PM</strong> β€” Youth Group Fundraiser, Mihango Social Hall</li>
          <li><strong>6:30 PM</strong> β€” Church Service, ACK Imara Daima</li>
        </ul>
        <p>You have 6 events today and tomorrow combined. Want a prep summary for the baraza?</p>`,
      citations: [{label:'View Events', href:'events.html'}],
      followups: ['Prep summary for baraza', 'Show tomorrow\'s events', 'Add a new event']
    };
  }
  if(q.includes('social protection') || q.includes('elderly') || q.includes('pwd') || q.includes('vulnerable')){
    return {
      html: `<p>Social Protection programme overview:</p>
        <ul>
          <li><strong>1,024 active beneficiaries</strong> across 3 categories</li>
          <li><strong>312 Elderly</strong>, <strong>278 PWDs</strong>, <strong>434 Orphans &amp; Vulnerable Children</strong></li>
          <li>Q2 stipend disbursement is <strong>50% complete</strong>, on track for June payout</li>
          <li><strong>2 cases</strong> are flagged under review pending document verification</li>
        </ul>
        <p>Let me know if you'd like the ward-by-ward breakdown.</p>`,
      citations: [{label:'View Social Protection', href:'social_protection.html'}],
      followups: ['Ward-by-ward breakdown', 'Show flagged cases', 'Payment schedule']
    };
  }
  if(q.includes('staff') || q.includes('team') || q.includes('officer')){
    return {
      html: `<p>Your office currently has <strong>24 staff members</strong> across 4 departments:</p>
        <ul>
          <li><strong>Administration</strong> β€” 9 staff, including all 6 Ward Administrators</li>
          <li><strong>Social Services</strong> β€” 6 social workers</li>
          <li><strong>Field Operations</strong> β€” 5 coordinators</li>
          <li><strong>Technical / Engineering</strong> β€” 3 engineers</li>
        </ul>
        <p>2 staff members are currently on leave. Want their tasks reassigned temporarily?</p>`,
      citations: [{label:'View Staff Management', href:'staff_management.html'}],
      followups: ['Reassign tasks', 'Show org chart', 'Who is on leave?']
    };
  }
  if(q.includes('hello') || q.includes('hi') || q.includes('hey')){
    return {
      html: `<p>Hello, David! I'm ready to help β€” ask me about complaints, projects, the budget, bursaries, social protection, or your team. I can also help draft messages and speeches.</p>`,
      citations: [],
      followups: ['Summarize complaints', 'Budget overview', 'Today\'s schedule']
    };
  }

  // Default fallback
  return {
    html: `<p>I don't have a specific answer for that yet in this demo, but here's what I can help with:</p>
      <ul>
        <li>Summarising complaints, projects, and budget data</li>
        <li>Drafting speeches, letters, and constituent messages</li>
        <li>Comparing ward performance and flagging risks</li>
        <li>Answering questions about bursaries and social protection</li>
      </ul>
      <p>Try rephrasing, or pick one of the suggestions below.</p>`,
    citations: [],
    followups: ['Summarize complaints', 'Budget overview', 'Draft a speech']
  };
}

function processAndRespond(text){
  appendTypingIndicator();
  const delay = 900 + Math.random()*700;
  setTimeout(()=>{
    removeTypingIndicator();
    const r = getResponse(text);
    appendAiMessage(r.html, r.citations, r.followups);
  }, delay);
}

function sendMessage(){
  const text = composerInput.value.trim();
  if(!text) return;
  appendUserMessage(text);
  composerInput.value = '';
  composerInput.style.height = 'auto';
  sendBtn.disabled = true;
  processAndRespond(text);
}

function sendSuggestion(el){
  const text = el.querySelector('.suggestion-text').textContent;
  appendUserMessage(text);
  processAndRespond(text);
}

function sendQuick(el){
  const text = el.textContent;
  appendUserMessage(text);
  processAndRespond(text);
}

function sendFollowup(el){
  const text = el.textContent;
  appendUserMessage(text);
  processAndRespond(text);
}

function newChat(){
  chatInner.innerHTML = '';
  chatInner.appendChild(welcomeState);
  welcomeState.style.display = 'block';
  quickStrip.style.display = 'none';
  conversationStarted = false;
  document.querySelectorAll('.history-item').forEach(h=>h.classList.remove('active'));
  document.querySelector('.history-item').classList.add('active');
}

function selectHistory(el){
  document.querySelectorAll('.history-item').forEach(h=>h.classList.remove('active'));
  el.classList.add('active');
  if(el.textContent !== 'Current conversation'){
    // Simulate loading a past conversation
    chatInner.innerHTML = '';
    welcomeState.style.display = 'none';
    quickStrip.style.display = 'flex';
    conversationStarted = true;
    appendUserMessage(el.textContent);
    setTimeout(()=>{
      const r = getResponse(el.textContent);
      appendAiMessage(r.html, r.citations, r.followups);
    }, 200);
  }
}
</script>
</body>
</html>

Youez - 2016 - github.com/yon3zu
LinuXploit