ResearchScope / digest.html
kishormorol's picture
Sync the mirror with the corrected corpus figures
411e676 verified
Raw History Blame Contribute Delete
20.5 kB
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>Weekly Research Digest – ResearchScope</title>
<meta name="description" content="Top CS/AI papers of the week, curated by topic. Updated every Monday."/>
<meta property="og:title" content="Weekly Research Digest – ResearchScope"/>
<meta property="og:description" content="Top CS/AI papers of the week, grouped by topic. Curated automatically from 250,000+ papers."/>
<meta property="og:type" content="website"/>
<meta property="og:url" content="https://kishormorol.github.io/ResearchScope/digest"/>
<meta name="twitter:card" content="summary_large_image"/>
<meta name="twitter:title" content="Weekly Research Digest – ResearchScope"/>
<meta name="twitter:description" content="Top CS/AI papers of the week, grouped by topic. Curated automatically from 250,000+ papers."/>
<script src="https://cdn.tailwindcss.com"></script>
<link rel="icon" href="assets/favicon.svg" type="image/svg+xml"/>
<link rel="stylesheet" href="assets/css/style.css?v=ui-integrity-18"/>
<script src="assets/js/theme-bootstrap.js?v=ui-integrity-18"></script>
</head>
<body>
<!-- Atelier Zero: side rails + top metadata strip -->
<aside class="rs-rail rs-rail--left" aria-hidden="true">
<span class="rs-rail__label">ResearchScope · Daily Index</span>
</aside>
<aside class="rs-rail rs-rail--right" aria-hidden="true">
<span class="rs-rail__label">CS Research · Filed Daily</span>
</aside>
<nav class="rs-nav">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div class="flex items-center h-14 gap-2">
<a href="./" class="flex items-center gap-2 font-bold text-lg shrink-0" style="min-width:0;flex:1;color:var(--rs-ink);font-family:var(--rs-font-display);letter-spacing:-0.02em">
<span style="font-family:var(--rs-font-italic);font-style:italic;font-weight:500;color:var(--rs-coral)">Ø</span>
<span>ResearchScope<span class="rs-dot">.</span></span>
</a>
<div id="rs-nav-links" class="hidden lg:flex items-center justify-center gap-2 text-sm font-medium flex-1">
<a href="papers.html">Papers</a>
<a href="topics.html">Topics</a>
<a href="digest.html">Digest</a>
<a href="conferences.html">Conferences</a>
<a href="journals.html">Journals</a>
<a href="authors.html">Authors</a>
<a href="labs.html">Labs &amp; Unis</a>
<a href="gaps.html">Research Gaps</a>
<a href="deadlines.html">Upcoming</a>
</div>
<div id="rs-nav-actions" class="flex items-center gap-2 justify-end" style="flex:1">
<div class="search-wrap hidden lg:block">
<svg class="search-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-4.35-4.35M17 11A6 6 0 1 1 5 11a6 6 0 0 1 12 0z"/>
</svg>
<input id="global-search" class="search-input" type="search" placeholder="Search papers, authors…" autocomplete="off"/>
<div id="search-dropdown" class="search-dropdown hidden"></div>
</div>
<a href="https://github.com/kishormorol/ResearchScope" target="_blank" rel="noopener" class="github-star-btn hidden lg:inline-flex" aria-label="Star on GitHub">
<svg width="13" height="13" viewBox="0 0 16 16" fill="currentColor"><path d="M8 .25a.75.75 0 0 1 .673.418l1.882 3.815 4.21.612a.75.75 0 0 1 .416 1.279l-3.046 2.97.719 4.192a.75.75 0 0 1-1.088.791L8 12.347l-3.766 1.98a.75.75 0 0 1-1.088-.79l.72-4.194L.818 6.374a.75.75 0 0 1 .416-1.28l4.21-.611L7.327.668A.75.75 0 0 1 8 .25Z"/></svg>
Star
<span class="github-star-count">–</span>
</a>
<button id="mobile-menu-btn" class="lg:hidden p-1 rounded" aria-label="Open menu" aria-expanded="false">
<svg id="hamburger-icon" class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16"/>
</svg>
<svg id="close-icon" class="w-5 h-5 hidden" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/>
</svg>
</button>
</div>
</div>
</div>
<div id="mobile-menu" class="hidden lg:hidden border-t" style="border-color:var(--rs-rule);background:var(--rs-bone)">
<div id="rs-mob-links" class="px-4 py-3 flex flex-col gap-1 text-sm font-medium">
<a href="./" class="mobile-nav-link">Home</a>
<a href="papers.html" class="mobile-nav-link">Papers</a>
<a href="topics.html" class="mobile-nav-link">Topics</a>
<a href="digest.html" class="mobile-nav-link">Weekly Digest</a>
<a href="conferences.html" class="mobile-nav-link">Conferences</a>
<a href="journals.html" class="mobile-nav-link">Journals</a>
<a href="authors.html" class="mobile-nav-link">Authors</a>
<a href="labs.html" class="mobile-nav-link">Labs &amp; Unis</a>
<a href="gaps.html" class="mobile-nav-link">Research Gaps</a>
<a href="deadlines.html" class="mobile-nav-link">Upcoming Conferences</a>
</div>
</div>
</nav>
<div class="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
<!-- Header -->
<div class="digest-header">
<div class="flex flex-wrap items-start justify-between gap-4">
<div>
<p class="text-xs font-bold uppercase tracking-widest opacity-80 mb-1"> Weekly Research Digest</p>
<h1 class="text-2xl font-extrabold mb-1" id="digest-week-label">Weekly Digest</h1>
<p class="text-sm opacity-80">Top papers per topic, curated from <span id="digest-total">…</span> papers</p>
</div>
<div class="flex gap-2 flex-wrap">
<a id="digest-tweet-btn" href="#" target="_blank" rel="noopener"
class="potd-btn potd-btn-ghost">
<svg width="13" height="13" viewBox="0 0 24 24" fill="currentColor"><path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-4.714-6.231-5.401 6.231H2.744l7.738-8.835L1.254 2.25H8.08l4.259 5.631zm-1.161 17.52h1.833L7.084 4.126H5.117z"/></svg>
Share Digest
</a>
<button onclick="copyDigestLink(this)" class="potd-btn potd-btn-ghost"> Copy Link</button>
</div>
</div>
</div>
<!-- Topic filter chips -->
<div id="digest-filters" class="flex flex-wrap gap-2 mb-6"></div>
<!-- Digest sections -->
<div id="digest-content"><div class="spinner"></div></div>
</div>
<!-- ── Footer ──────────────────────────────────────────────────────── -->
<footer class="border-t py-8 text-center text-sm mt-8" style="border-color:var(--rs-border);color:var(--rs-muted)">
<p class="font-semibold mb-2"> ResearchScope</p>
<p>Open-source CS research intelligence &middot; Updated daily via GitHub Actions &middot; Built for researchers and creators</p>
<p class="mt-3 font-medium" style="color:var(--rs-text)">Data Sources</p>
<p class="mt-1">
<a href="https://arxiv.org" target="_blank" class="hover:underline" style="color:var(--rs-primary)">arXiv</a> (metadata CC0) &middot;
<a href="https://aclanthology.org" target="_blank" class="hover:underline" style="color:var(--rs-primary)">ACL Anthology</a> (CC BY 4.0 / CC BY-NC-SA 3.0) &middot;
<a href="https://proceedings.mlr.press" target="_blank" class="hover:underline" style="color:var(--rs-primary)">PMLR</a> (CC BY 4.0) &middot;
<a href="https://www.semanticscholar.org" target="_blank" class="hover:underline" style="color:var(--rs-primary)">Semantic Scholar</a>
</p>
<p class="mt-2">
<a href="https://github.com/kishormorol/ResearchScope" target="_blank" class="hover:underline" style="color:var(--rs-primary)">GitHub</a>
&middot; <a href="https://github.com/kishormorol/ResearchScope/blob/main/ROADMAP.md" class="hover:underline" style="color:var(--rs-primary)">Roadmap</a>
&middot; MIT License &copy; 2026 Md Kishor Morol
</p>
</footer>
<script src="assets/js/app.js?v=ui-integrity-18"></script>
<script src="assets/js/railway-api.js?v=20260718-auth-expiry"></script>
<script>
// Topic group icons
const TOPIC_ICONS = {
'Large Language Models': '',
'Transformer Architectures': '',
'Diffusion Models': '',
'Reinforcement Learning': '',
'Computer Vision': '',
'Vision-Language Models': '',
'Graph Neural Networks': '',
'AI Agents & Tool Use': '',
'AI Safety & Alignment': '',
'Retrieval-Augmented Generation': '',
'Code Generation & Synthesis': '',
'Fine-Tuning & PEFT': '',
'Reasoning & Chain-of-Thought': '',
'RLHF & Preference Alignment': '',
'Benchmarking & Evaluation': '',
'Text Summarization': '',
'Machine Translation': '',
'Question Answering': '',
'Mixture of Experts': '',
'State Space Models': '',
'Federated & Privacy-Preserving Learning': '',
'Continual Learning': '',
'Long-Context Modeling': '',
'Multimodal Learning': '',
// Short taxonomy names used in the live data
'LLMs': '',
'VLMs': '',
'Reasoning': '',
'AI Agents': '',
'AI Safety': '',
'RL': '',
'Fine-Tuning': '',
'GNNs': '',
'Transformers': '',
'Diffusion': '',
'Computer vision': '',
'Multimodal': '',
'Evaluation': '',
'NLP': '',
'Prompting': '',
'Hallucination': '',
'Robotics': '',
'Object Detection': '',
'Segmentation': '',
'3D Vision': '',
'Knowledge Graphs': '',
'Text-to-Image': '',
'Self-Supervised': '',
'Interpretability': '',
'Model Compression': '',
'Adversarial': '',
'Dialogue': '',
'QA': '',
'Graph': '',
'Info Extraction': '',
'Fairness & Ethics': '',
'Cryptography & Security': '',
};
function topicIcon(name) {
return TOPIC_ICONS[name] || '';
}
function digestTopicLabel(name, short = false) {
const label = short ? name.split(' ').slice(0, 2).join(' ') : name;
return `<span class="digest-topic-token"><span class="digest-topic-token__mark" aria-hidden="true"></span><span>${escHtml(label)}</span></span>`;
}
function renderDigestPaperCard(paper) {
const url = paperWorkspaceUrl(paper);
const externalUrl = paper.paper_url || paper.url || '#';
const venue = [paper.venue, paper.year].filter(Boolean).join(' · ');
const authors = (paper.authors || []).slice(0, 3).join(', ');
const extra = (paper.authors || []).length > 3 ? ` +${paper.authors.length - 3}` : '';
const abstract = (paper.abstract || paper.summary || '').slice(0, 120);
return `
<div class="digest-paper-card">
<div class="flex items-start justify-between gap-3 flex-wrap">
<div class="flex-1 min-w-0">
<a href="${escHtml(url)}"
class="font-bold text-sm hover:underline" style="color:var(--rs-primary)">${escHtml(paper.title)}</a>
<p class="text-xs mt-0.5" style="color:var(--rs-muted)">
${escHtml(authors)}${escHtml(extra)}${venue ? ' · ' + escHtml(venue) : ''}
</p>
</div>
<div class="flex gap-1 items-center flex-shrink-0">
<span class="badge badge-score">${(+paper.paper_score||0).toFixed(1)}</span>
${difficultyBadge(paper)}
</div>
</div>
${abstract ? `<p class="text-xs leading-relaxed" style="color:var(--rs-muted)">${escHtml(abstract)}…</p>` : ''}
<div class="flex gap-2 flex-wrap mt-1">
<a href="${escHtml(url)}" class="text-xs font-semibold hover:underline" style="color:var(--rs-primary)">Chat →</a>
<a href="${escHtml(externalUrl)}" target="_blank" rel="noopener"
class="text-xs font-semibold hover:underline" style="color:var(--rs-muted)">Paper ↗</a>
<a href="${escHtml(tweetPaperUrl(paper))}" target="_blank" rel="noopener" class="tweet-btn">
<svg width="11" height="11" viewBox="0 0 24 24" fill="currentColor"><path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-4.714-6.231-5.401 6.231H2.744l7.738-8.835L1.254 2.25H8.08l4.259 5.631zm-1.161 17.52h1.833L7.084 4.126H5.117z"/></svg>
Share
</a>
</div>
</div>`;
}
function copyDigestLink(btn) {
navigator.clipboard.writeText(window.location.href).then(() => {
const orig = btn.textContent;
btn.textContent = ' Copied!';
setTimeout(() => btn.textContent = orig, 2000);
});
}
// Broad field / umbrella topics that aren't useful digest sections — these are
// catch-alls from the source taxonomy ("Computer science", whole scientific
// fields, mislabelled nodes). Everything else (LLMs, Reasoning, VLMs, …) is a
// meaningful AI/CS topic and is eligible. Compared case-insensitively.
const GENERIC_TOPICS = new Set([
'computer science', 'theoretical computer science', 'artificial intelligence',
'machine learning', 'artificial neural network', 'pattern recognition (psychology)',
'algorithm', 'data mining', 'feature (linguistics)', 'robustness (evolution)',
'mathematics', 'statistics', 'engineering', 'physics', 'condensed matter physics',
'chemistry', 'catalysis', 'optoelectronics', 'nanotechnology', 'materials science',
'biology', 'cell biology', 'computational biology', 'biomedical ai', 'medicine',
'cancer research', 'immune system', 'neuroscience', 'environmental science',
]);
// The digest features whichever topics actually contain papers from the current
// week — computed at load time so it tracks the live taxonomy instead of a
// hardcoded list that silently drifts out of sync with the data.
let digestTopics = [];
let allPapers = [];
let allTopics = [];
let activeFilter = 'all';
function papersByTopic(papers, topicName, topics) {
const topic = topics.find(t => t.name === topicName);
if (!topic || !topic.paper_ids || !topic.paper_ids.length) return [];
const ids = new Set(topic.paper_ids);
return papers
.filter(p => ids.has(p.id))
.sort((a, b) => (b.paper_score || 0) - (a.paper_score || 0))
.slice(0, 3);
}
function paperDay(p) {
return p.published_date ? String(p.published_date).slice(0, 10) : null;
}
// Monday–Sunday week containing the ISO day `anchor` ("YYYY-MM-DD"). Computed in
// UTC and compared as strings so there's no timezone drift. The digest is
// anchored on the freshest paper present, so the label and papers always agree.
function weekRange(anchor) {
const d = new Date(anchor + 'T00:00:00Z');
const mon = new Date(d); mon.setUTCDate(d.getUTCDate() - ((d.getUTCDay() + 6) % 7));
const sun = new Date(mon); sun.setUTCDate(mon.getUTCDate() + 6);
const iso = x => x.toISOString().slice(0, 10);
const fmt = x => x.toLocaleDateString('en-US', { month: 'short', day: 'numeric', timeZone: 'UTC' });
return { start: iso(mon), end: iso(sun), label: `${fmt(mon)} – ${fmt(sun)}, ${sun.getUTCFullYear()}` };
}
function toggleDigestSection(id) {
const body = document.getElementById('digest-body-' + id);
const arrow = document.getElementById('digest-arrow-' + id);
const trigger = document.getElementById('digest-trigger-' + id);
if (!body) return;
const hidden = body.classList.toggle('hidden');
arrow.textContent = hidden ? '▶' : '▼';
trigger?.setAttribute('aria-expanded', String(!hidden));
}
function render(papers, topics, filter) {
const sections = digestTopics.filter(name =>
filter === 'all' || name === filter
);
let html = '';
let rendered = 0;
for (const topicName of sections) {
const topicPapers = papersByTopic(papers, topicName, topics);
if (!topicPapers.length) continue;
const id = rendered;
const collapsed = rendered > 0; // first section open, rest collapsed
html += `
<div class="digest-section" data-topic="${escHtml(topicName)}">
<button id="digest-trigger-${id}" type="button" class="digest-section-title" aria-expanded="${String(!collapsed)}" aria-controls="digest-body-${id}" onclick="toggleDigestSection(${id})" style="user-select:none">
<span>${digestTopicLabel(topicName)}</span>
<span class="flex items-center gap-2">
<span class="text-xs font-normal" style="color:var(--rs-muted)">${topicPapers.length} paper${topicPapers.length !== 1 ? 's' : ''}</span>
<span id="digest-arrow-${id}" class="text-xs" style="color:var(--rs-muted)">${collapsed ? '▶' : '▼'}</span>
</span>
</button>
<div id="digest-body-${id}" class="flex flex-col gap-3${collapsed ? ' hidden' : ''}" role="region" aria-labelledby="digest-trigger-${id}">
${topicPapers.map(renderDigestPaperCard).join('')}
</div>
</div>`;
rendered++;
}
if (!rendered) {
html = '<div class="empty-state"><p>No papers found for this topic yet.</p></div>';
}
document.getElementById('digest-content').innerHTML = html;
}
function buildFilters(topics) {
// digestTopics is already restricted to topics with papers this week.
const available = digestTopics;
const el = document.getElementById('digest-filters');
el.setAttribute('role', 'group');
el.setAttribute('aria-label', 'Filter digest by topic');
el.innerHTML = `<button class="area-chip active" data-f="all" aria-pressed="true"><span class="digest-topic-token digest-topic-token--all"><span class="digest-topic-token__mark" aria-hidden="true"></span><span>All</span></span></button>` +
available.slice(0, 12).map(name =>
`<button class="area-chip" data-f="${escHtml(name)}" aria-pressed="false">${digestTopicLabel(name, true)}</button>`
).join('');
el.addEventListener('click', e => {
const btn = e.target.closest('[data-f]');
if (!btn) return;
el.querySelectorAll('[data-f]').forEach(b => { b.classList.remove('active'); b.setAttribute('aria-pressed', 'false'); });
btn.classList.add('active');
btn.setAttribute('aria-pressed', 'true');
activeFilter = btn.dataset.f;
render(allPapers, allTopics, activeFilter);
});
}
function buildTweetBtn(weekLabel) {
const url = 'https://kishormorol.github.io/ResearchScope/digest';
const text = ` Weekly Research Digest — ${weekLabel}\n\nTop AI & CS papers of the week, organized by topic.\n\n ResearchScope\n${url}\n\n#AIResearch #MachineLearning #ResearchScope`;
document.getElementById('digest-tweet-btn').href =
`https://twitter.com/intent/tweet?text=${encodeURIComponent(text)}`;
}
(async () => {
const [papers, topics] = await Promise.all([
window._rs_data.fetchTopPapers(500),
window._rs_data.fetchAllTopics(),
]);
if (!papers || !topics) {
document.getElementById('digest-content').innerHTML =
'<div class="empty-state"><p>No data available yet — run the pipeline first.</p></div>';
return;
}
// Digest is arXiv-only — conference papers are historical proceedings, not "new this week"
const ARXIV_VENUES = new Set(['arXiv', 'Unknown', '', null, undefined]);
const arxivOnly = papers.filter(p => ARXIV_VENUES.has(p.venue));
// Anchor the week on the freshest paper actually present (the pipeline runs a
// few days behind real-time), so the "Week of …" label matches the papers
// shown. Papers must be from this week — no month-old top scorers.
const days = arxivOnly.map(paperDay).filter(Boolean);
const anchor = days.length ? days.reduce((a, b) => (b > a ? b : a)) : new Date().toISOString().slice(0, 10);
const week = weekRange(anchor);
document.getElementById('digest-week-label').textContent = `Week of ${week.label}`;
buildTweetBtn(week.label);
const thisWeek = arxivOnly.filter(p => {
const d = paperDay(p);
return d && d >= week.start && d <= week.end;
});
const sorted = [...thisWeek].sort((a,b) => (b.paper_score||0) - (a.paper_score||0));
allPapers = sorted;
allTopics = topics;
// Feature the topics that have the most papers this week (generic umbrella
// topics excluded), so the digest tracks the live taxonomy.
digestTopics = topics
.filter(t => !GENERIC_TOPICS.has((t.name || '').toLowerCase()))
.map(t => ({ name: t.name, n: papersByTopic(sorted, t.name, topics).length }))
.filter(t => t.n > 0)
.sort((a, b) => b.n - a.n)
.slice(0, 14)
.map(t => t.name);
document.getElementById('digest-total').textContent = sorted.length.toLocaleString();
if (!digestTopics.length) {
document.getElementById('digest-content').innerHTML =
'<div class="empty-state"><p>No papers for this week yet — check back after the next sync.</p></div>';
return;
}
buildFilters(topics);
render(sorted, topics, 'all');
})();
</script>
</body>
</html>