AI Bot
redesign: radar logo + production copy (no emoji) + layered responsive (320/768/1024/1440) + a11y
e07688f | <html lang="th"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>ROGLAG — Project Presentation</title> | |
| <link rel="preconnect" href="https://fonts.googleapis.com"> | |
| <link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@400;500;600&family=IBM+Plex+Sans+Thai:wght@400;500;600;700&display=swap" rel="stylesheet"> | |
| <style> | |
| :root{--bg:#070b12;--panel:#111826;--line:#1f2a3d;--txt:#eaf1fa;--muted:#aab8cc; | |
| --accent:#4da3ff;--accent2:#b8a6ff;--teal:#5eead4;--ok:#34d399;--warn:#fbbf24;--crit:#f87171;--code:#0a0e16; | |
| --hair:rgba(148,163,184,0.18);} | |
| *{box-sizing:border-box;margin:0;padding:0} | |
| html,body{height:100%} | |
| body{background:var(--bg);color:var(--txt);font-family:"IBM Plex Sans Thai",-apple-system,"Segoe UI",sans-serif;font-size:18px;line-height:1.5;overflow:hidden} | |
| .deck{height:100vh;width:100vw;position:relative} | |
| .slide{position:absolute;inset:0;display:none;flex-direction:column;justify-content:center; | |
| padding:7vh 9vw;opacity:0;transition:opacity .35s ease; | |
| background:radial-gradient(1100px 560px at 82% -8%,#16223c 0%,var(--bg) 58%)} | |
| .slide.active{display:flex;opacity:1} | |
| .kicker{color:var(--teal);font-family:"IBM Plex Mono",ui-monospace,monospace;font-size:14px; | |
| line-height:1.5;letter-spacing:.5px;margin-bottom:14px} | |
| h1{font-size:clamp(47px,6vw,90px);line-height:1.05;letter-spacing:.5px} | |
| h1 .grad{color:#eaf1fa} | |
| h2{font-size:clamp(29px,3.6vw,47px);line-height:1.3;margin-bottom:24px;display:flex;align-items:center;gap:14px} | |
| p.lead{font-size:clamp(23px,2vw,29px);color:var(--muted);max-width:60ch;line-height:1.6;margin-top:10px} | |
| ul{list-style:none;margin-top:10px} | |
| li{font-size:clamp(23px,1.7vw,29px);margin:13px 0;padding-left:30px;position:relative;color:#dbe6f3;line-height:1.6} | |
| li::before{content:"▸";position:absolute;left:0;color:var(--teal)} | |
| li small{color:var(--muted);font-size:14px;line-height:1.5} | |
| code{background:var(--code);border:1px solid var(--line);border-radius:6px;padding:1px 7px;font-size:14px;line-height:1.5;color:#cfe3ff;font-family:"IBM Plex Mono",ui-monospace,monospace} | |
| .grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(230px,1fr));gap:16px;margin-top:18px;max-width:1000px} | |
| .card{border:1px solid var(--hair);border-radius:14px;padding:18px 20px;background:linear-gradient(160deg,#121a2b,#0d1320)} | |
| .card h3{font-size:clamp(23px,1.9vw,29px);line-height:1.3;margin-bottom:8px} | |
| .card p{color:var(--muted);font-size:14px;line-height:1.5} | |
| .chips{display:flex;gap:9px;flex-wrap:wrap;margin-top:22px} | |
| .chip{font-size:14px;line-height:1.5;padding:7px 14px;border:1px solid var(--hair);border-radius:999px;background:#16203250;color:var(--teal)} | |
| .flow{display:flex;flex-wrap:wrap;align-items:center;gap:10px;margin-top:22px;font-size:18px;line-height:1.5} | |
| .node{border:1px solid var(--line);background:var(--panel);border-radius:11px;padding:11px 16px} | |
| .arrow{color:var(--accent2);font-weight:800} | |
| .two{display:grid;grid-template-columns:1fr 1fr;gap:40px;margin-top:10px} | |
| @media(max-width:760px){.two{grid-template-columns:1fr}} | |
| .big{font-size:clamp(60px,7vw,90px);font-weight:800;color:var(--teal);line-height:1} | |
| .statline{display:flex;gap:40px;flex-wrap:wrap;margin-top:26px} | |
| .stat .l{color:var(--muted);font-size:14px;line-height:1.5;letter-spacing:.5px;margin-top:6px} | |
| .badge{display:inline-block;font-size:14px;line-height:1.5;padding:3px 10px;border-radius:999px;vertical-align:middle;margin-left:10px} | |
| .b-done{background:#0e2a1e;color:var(--ok);border:1px solid #1c4b36} | |
| /* chrome */ | |
| .bar{position:fixed;top:0;left:0;width:100%;height:3px;background:linear-gradient(90deg,var(--accent),var(--accent2));transform:scaleX(0);transform-origin:left;transition:transform .3s;z-index:10} | |
| .hud{position:fixed;bottom:18px;right:24px;color:var(--muted);font-family:"IBM Plex Mono",ui-monospace,monospace;font-size:14px;line-height:1.5;z-index:10} | |
| .hint{position:fixed;bottom:18px;left:24px;color:#aab8cc;font-size:14px;line-height:1.5;z-index:10} | |
| .nav{position:fixed;bottom:14px;left:50%;transform:translateX(-50%);display:flex;gap:8px;z-index:10} | |
| .nav button{background:var(--panel);border:1px solid var(--line);color:var(--txt);border-radius:8px;padding:6px 14px;cursor:pointer;font-size:18px;line-height:1.5} | |
| .nav button:hover{border-color:var(--accent)} | |
| .logo{display:inline-grid;place-items:center;width:64px;height:64px;border-radius:16px;margin-bottom:24px; | |
| background:radial-gradient(120% 120% at 30% 20%,rgba(94,234,212,.18),transparent 60%),linear-gradient(150deg,#0c2034,#0a3140);border:1px solid rgba(94,234,212,.32)} | |
| .logo svg{width:40px;height:40px} | |
| </style> | |
| </head> | |
| <body> | |
| <div class="bar" id="bar"></div> | |
| <div class="deck" id="deck"> | |
| <!-- 1 TITLE --> | |
| <section class="slide active"> | |
| <span class="logo"><svg viewBox="0 0 64 64"> | |
| <defs> | |
| <linearGradient id="rgRing" x1="0" y1="0" x2="1" y2="1"> | |
| <stop offset="0" stop-color="#5eead4"/> | |
| <stop offset="1" stop-color="#0d9488"/> | |
| </linearGradient> | |
| <linearGradient id="rgSweep" x1="0" y1="0" x2="1" y2="1"> | |
| <stop offset="0" stop-color="#5eead4" stop-opacity=".55"/> | |
| <stop offset="1" stop-color="#5eead4" stop-opacity="0"/> | |
| </linearGradient> | |
| </defs> | |
| <circle cx="32" cy="32" r="21" fill="none" stroke="url(#rgRing)" stroke-width="3.2"/> | |
| <circle cx="32" cy="32" r="11.5" fill="none" stroke="#5eead4" stroke-width="1.6" opacity=".38"/> | |
| <path d="M32 32 L32 11 A21 21 0 0 1 50.2 21.5 Z" fill="url(#rgSweep)"/> | |
| <circle cx="32" cy="32" r="2.4" fill="#5eead4"/> | |
| <circle cx="43.5" cy="22.5" r="3.1" fill="#7dd3fc"/> | |
| </svg></span> | |
| <div class="kicker">AI RAG · Security Log Analytics</div> | |
| <h1>ROGLAG<br><span class="grad">Threat Intelligence Console</span></h1> | |
| <p class="lead">ระบบตรวจจับความเสี่ยงจาก security log แบบเรียลไทม์ ด้วย rule-based detection + RAG + vector search — รันได้ตั้งแต่ออฟไลน์จนถึง production</p> | |
| <div class="chips"> | |
| <span class="chip">Realtime</span><span class="chip">RAG</span><span class="chip">Qdrant</span> | |
| <span class="chip">Self-host</span><span class="chip">Docker</span> | |
| </div> | |
| </section> | |
| <!-- 2 CAPABILITIES --> | |
| <section class="slide"> | |
| <div class="kicker">ความสามารถ</div> | |
| <h2>ทำอะไรได้บ้าง</h2> | |
| <ul> | |
| <li><b>ตรวจจับภัยอัตโนมัติ</b> จาก log เช่น brute force, port scan, web attack, C2 beacon ฯลฯ พร้อม MITRE + risk score</li> | |
| <li><b>ค้นหาเชิงความหมาย (RAG):</b> ถามเป็นภาษาไทย แล้วดึงหลักฐานที่เกี่ยวข้องมาให้</li> | |
| <li><b>สรุป + แนะนำ next action</b> เป็นภาษาคน จากหลักฐานจริง</li> | |
| <li><b>มอนิเตอร์เรียลไทม์:</b> ดู log ไหลเข้าสด + กราฟ/incident/critical อัปเดตทันที</li> | |
| <li><b>จำลอง / อัปโหลด log</b> เพื่อทดสอบระบบตรวจจับได้ทันที</li> | |
| </ul> | |
| </section> | |
| <!-- 3 WHAT WE BUILT --> | |
| <section class="slide"> | |
| <div class="kicker">ภาพรวมสิ่งที่ทำ</div> | |
| <h2>สรุปสิ่งที่สร้าง</h2> | |
| <div class="grid"> | |
| <div class="card"><h3>🛡️ Console + Detection</h3><p>Dashboard ภาษาไทย + rule classifier 7 ภัย + MITRE ATT&CK</p></div> | |
| <div class="card"><h3>💬 RAG Q&A</h3><p>ถามไทย → ดึงหลักฐาน → สรุป + next action</p></div> | |
| <div class="card"><h3>⚡ Realtime + Generator</h3><p>จำลอง log สด, live monitor, สร้าง/อัปโหลด CSV</p></div> | |
| <div class="card"><h3>🌐 Qdrant + Docker</h3><p>vector RAG จริง + self-host รันคำสั่งเดียว</p></div> | |
| </div> | |
| </section> | |
| <!-- 4 ARCHITECTURE --> | |
| <section class="slide"> | |
| <div class="kicker">สถาปัตยกรรม</div> | |
| <h2>Data flow (โดยสรุป)</h2> | |
| <div class="flow"> | |
| <span class="node">Log / CSV / Mock</span><span class="arrow">→</span> | |
| <span class="node">Classify</span><span class="arrow">→</span> | |
| <span class="node">Qdrant<br><small>semantic search</small></span><span class="arrow">→</span> | |
| <span class="node">RAG + API</span><span class="arrow">→</span> | |
| <span class="node">Dashboard</span> | |
| </div> | |
| <p class="lead" style="margin-top:28px">มี fallback ทุกชั้น: <b>Qdrant → SQLite vector → keyword → rule-based</b>. ระบบไม่ล่มแม้ไม่มี key หรือเน็ต</p> | |
| </section> | |
| <!-- 5 DETECTION --> | |
| <section class="slide"> | |
| <div class="kicker">Detection layer</div> | |
| <h2>Rule-based classifier</h2> | |
| <div class="two"> | |
| <ul> | |
| <li><b>brute_force</b> <small>T1110</small></li> | |
| <li><b>port_scan</b> <small>T1046</small></li> | |
| <li><b>web_attack</b> <small>T1190 · SQLi/XSS</small></li> | |
| <li><b>priv_esc</b> <small>T1068/T1548</small></li> | |
| </ul> | |
| <ul> | |
| <li><b>data_exfil</b> <small>T1041</small></li> | |
| <li><b>c2_beacon</b> <small>T1071</small></li> | |
| <li><b>benign</b> <small>baseline</small></li> | |
| <li>แต่ละหมวด → risk score + runbook แนะนำ</li> | |
| </ul> | |
| </div> | |
| <p class="lead" style="margin-top:20px">ทำงานออฟไลน์ 100% ไม่ต้องพึ่งโมเดล จึงเร็วและอธิบายผลได้</p> | |
| </section> | |
| <!-- 6 REALTIME --> | |
| <section class="slide"> | |
| <div class="kicker">Realtime features</div> | |
| <h2>Generator & Live monitor</h2> | |
| <ul> | |
| <li><b>Live stream:</b> ยิง log จำลองหลากหลายไม่ซ้ำเข้าระบบจริง ปุ่มเดียวจบ</li> | |
| <li><b>Realtime monitor:</b> ดู log ไหลเข้าสดเหมือน <code>tail -f</code> + sort by time</li> | |
| <li><b>Generate CSV:</b> สร้างไฟล์สุ่มใหม่ทุกครั้ง เอาไปทดสอบได้</li> | |
| <li><b>Upload CSV:</b> classify ทุกแถว + วัด % ความแม่นยำเทียบ label เดิม</li> | |
| <li>Dashboard (กราฟ/incident/critical) <b>อัปเดตสด</b> ตามข้อมูลที่เข้ามา</li> | |
| </ul> | |
| </section> | |
| <!-- 7 QDRANT --> | |
| <section class="slide"> | |
| <div class="kicker">Production vector RAG</div> | |
| <h2>Qdrant <span class="badge b-done">ใช้งานจริงแล้ว</span></h2> | |
| <ul> | |
| <li>เปลี่ยนจาก keyword/SQLite มาใช้ <b>Qdrant vector DB จริง</b> (self-host ผ่าน Docker)</li> | |
| <li>Query → embed ด้วย OpenRouter (2048-dim) → ANN search บน Qdrant</li> | |
| <li>Collection <code>roglag_logs</code> · Cosine · index logs จริง</li> | |
| <li>สลับเป็น <b>Qdrant Cloud</b> ได้ทันทีแค่เปลี่ยน env โดยไม่ต้องแก้โค้ด</li> | |
| </ul> | |
| <div class="statline"> | |
| <div class="stat"><div class="big">2048</div><div class="l">vector dims</div></div> | |
| <div class="stat"><div class="big">Cosine</div><div class="l">distance</div></div> | |
| <div class="stat"><div class="big">~0.58</div><div class="l">semantic score</div></div> | |
| </div> | |
| </section> | |
| <!-- 8 TECH STACK --> | |
| <section class="slide"> | |
| <div class="kicker">Tech stack</div> | |
| <h2>เทคโนโลยีที่ใช้</h2> | |
| <div class="two"> | |
| <div> | |
| <p class="lead" style="margin:0 0 8px;color:var(--accent)">เดโม่ (รันทันที)</p> | |
| <ul> | |
| <li>Python 3.12 · <code>http.server</code> stdlib</li> | |
| <li>Vanilla JS + Three.js (globe)</li> | |
| <li>Rule classifier + TF-IDF</li> | |
| <li>In-memory + SQLite</li> | |
| </ul> | |
| </div> | |
| <div> | |
| <p class="lead" style="margin:0 0 8px;color:var(--accent2)">Production</p> | |
| <ul> | |
| <li>FastAPI + Uvicorn</li> | |
| <li>SQLAlchemy + PostgreSQL</li> | |
| <li>Qdrant + OpenRouter</li> | |
| <li>Docker + docker-compose</li> | |
| </ul> | |
| </div> | |
| </div> | |
| </section> | |
| <!-- 9 SELF-HOST --> | |
| <section class="slide"> | |
| <div class="kicker">Deploy / Self-host</div> | |
| <h2>รันได้จริง ทุกระดับ</h2> | |
| <ul> | |
| <li><b>เดโม่:</b> <code>python3 server.py</code> → เปิด <code>localhost:8000</code> ได้เลย</li> | |
| <li><b>Self-host เต็ม:</b> <code>docker compose up</code> (API + PostgreSQL + Qdrant)</li> | |
| <li><b>Cloud:</b> deploy บน Vercel (static + Python serverless)</li> | |
| <li>เอกสารครบ: <code>/plan</code> · <code>/docs-html</code> · <code>/techstack.html</code></li> | |
| </ul> | |
| </section> | |
| <!-- 10 NEXT --> | |
| <section class="slide"> | |
| <div class="kicker">ก้าวต่อไป</div> | |
| <h2>Roadmap</h2> | |
| <div class="grid"> | |
| <div class="card"><h3>Ingestion จริง</h3><p>Vector/Fluent Bit → queue → worker classify+embed</p></div> | |
| <div class="card"><h3>Automation</h3><p>n8n: alert → enrich (threat intel) → ticket/notify <small>(optional)</small></p></div> | |
| <div class="card"><h3>Auth & Scale</h3><p>API auth, Redis pub/sub สำหรับ realtime หลาย worker</p></div> | |
| <div class="card"><h3>Observability</h3><p>Prometheus + Grafana, retention/partition</p></div> | |
| </div> | |
| </section> | |
| <!-- 11 CLOSING --> | |
| <section class="slide"> | |
| <div class="kicker">สรุป</div> | |
| <h1>จาก demo สู่<br><span class="grad">production-ready</span></h1> | |
| <p class="lead">ตรวจจับ → ค้นหาเชิงความหมาย (Qdrant) → สรุปด้วย RAG → เห็นผลแบบเรียลไทม์ ทั้งหมดใน console เดียว self-host ได้จริง</p> | |
| <div class="chips"> | |
| <span class="chip">localhost:8000</span><span class="chip">/techstack.html</span><span class="chip">/plan</span> | |
| </div> | |
| <p class="lead" style="margin-top:26px;font-size:18px;line-height:1.6">ขอบคุณครับ 🙏</p> | |
| </section> | |
| </div> | |
| <div class="nav"><button onclick="go(-1)">‹</button><button onclick="go(1)">›</button></div> | |
| <div class="hud" id="hud">1 / 11</div> | |
| <div class="hint">← → / Space เลื่อน · F fullscreen</div> | |
| <script> | |
| const slides = [...document.querySelectorAll(".slide")]; | |
| let i = 0; | |
| function show(n){ | |
| i = Math.max(0, Math.min(slides.length - 1, n)); | |
| slides.forEach((s, k) => s.classList.toggle("active", k === i)); | |
| document.getElementById("hud").textContent = `${i + 1} / ${slides.length}`; | |
| document.getElementById("bar").style.transform = `scaleX(${(i + 1) / slides.length})`; | |
| } | |
| function go(d){ show(i + d); } | |
| document.addEventListener("keydown", (e) => { | |
| if (["ArrowRight", " ", "PageDown"].includes(e.key)) { e.preventDefault(); go(1); } | |
| else if (["ArrowLeft", "PageUp"].includes(e.key)) { e.preventDefault(); go(-1); } | |
| else if (e.key === "Home") show(0); | |
| else if (e.key === "End") show(slides.length - 1); | |
| else if (e.key.toLowerCase() === "f") { document.fullscreenElement ? document.exitFullscreen() : document.documentElement.requestFullscreen(); } | |
| }); | |
| document.getElementById("deck").addEventListener("click", (e) => { if (!e.target.closest(".nav")) go(1); }); | |
| show(0); | |
| </script> | |
| </body> | |
| </html> | |