update augorWorker to use openRouter configuration and set llmModel in config
This commit is contained in:
parent
f580e7f117
commit
d972569e54
2 changed files with 131 additions and 20 deletions
103
admin.html
103
admin.html
|
|
@ -401,6 +401,18 @@
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Intelligence detail modal -->
|
||||||
|
<div class="overlay" id="intelOverlay">
|
||||||
|
<div class="modal" style="width:740px">
|
||||||
|
<h2 id="intel-modal-title">Detail</h2>
|
||||||
|
<div id="intel-modal-meta" style="font-size:12px; color:#64748b; margin-bottom:16px; display:flex; gap:16px; flex-wrap:wrap"></div>
|
||||||
|
<div id="intel-modal-body" style="font-size:13px; line-height:1.7; white-space:pre-wrap; word-break:break-word; background:#141620; padding:14px; border-radius:6px; border:1px solid #2d3148"></div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button id="intelCloseBtn">Close</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Article modal -->
|
<!-- Article modal -->
|
||||||
<div class="overlay" id="articleOverlay">
|
<div class="overlay" id="articleOverlay">
|
||||||
<div class="modal">
|
<div class="modal">
|
||||||
|
|
@ -772,6 +784,7 @@ async function loadIntelligence() {
|
||||||
if (type) params.set('type', type);
|
if (type) params.set('type', type);
|
||||||
|
|
||||||
const data = await api(`/admin/api/intelligence/knowledge?${params}`);
|
const data = await api(`/admin/api/intelligence/knowledge?${params}`);
|
||||||
|
intelRows = data.rows;
|
||||||
|
|
||||||
document.getElementById('intel-thead').innerHTML = `
|
document.getElementById('intel-thead').innerHTML = `
|
||||||
<tr><th>ID</th><th>Company</th><th>Event</th><th>Type</th><th>Data</th><th>Created</th></tr>`;
|
<tr><th>ID</th><th>Company</th><th>Event</th><th>Type</th><th>Data</th><th>Created</th></tr>`;
|
||||||
|
|
@ -780,12 +793,12 @@ async function loadIntelligence() {
|
||||||
let parsed = {};
|
let parsed = {};
|
||||||
try { parsed = JSON.parse(r.data); } catch (_) {}
|
try { parsed = JSON.parse(r.data); } catch (_) {}
|
||||||
const summary = Object.values(parsed).filter(v => typeof v === 'string').join(' · ').slice(0, 120);
|
const summary = Object.values(parsed).filter(v => typeof v === 'string').join(' · ').slice(0, 120);
|
||||||
return `<tr>
|
return `<tr style="cursor:pointer" onclick="openIntelDetail(${r.id}, 'knowledge')">
|
||||||
<td style="color:#64748b">${r.id}</td>
|
<td style="color:#64748b">${r.id}</td>
|
||||||
<td style="white-space:nowrap">${r.company_name}</td>
|
<td style="white-space:nowrap">${r.company_name}</td>
|
||||||
<td style="color:#64748b">${r.event_id}</td>
|
<td style="color:#64748b">${r.event_id}</td>
|
||||||
<td><span class="badge null">${r.type}</span></td>
|
<td><span class="badge null">${r.type}</span></td>
|
||||||
<td><span class="truncate" style="max-width:360px" title="${r.data.replace(/"/g,'"')}">${summary}</span></td>
|
<td><span class="truncate" style="max-width:360px">${summary}</span></td>
|
||||||
<td style="color:#64748b; white-space:nowrap">${r.created_at ? r.created_at.slice(0,16) : '—'}</td>
|
<td style="color:#64748b; white-space:nowrap">${r.created_at ? r.created_at.slice(0,16) : '—'}</td>
|
||||||
</tr>`;
|
</tr>`;
|
||||||
}).join('');
|
}).join('');
|
||||||
|
|
@ -800,12 +813,13 @@ async function loadIntelligence() {
|
||||||
document.getElementById('i-type').parentElement.style.display = 'none';
|
document.getElementById('i-type').parentElement.style.display = 'none';
|
||||||
|
|
||||||
const data = await api(`/admin/api/intelligence/predictions?${params}`);
|
const data = await api(`/admin/api/intelligence/predictions?${params}`);
|
||||||
|
intelRows = data.rows;
|
||||||
|
|
||||||
document.getElementById('intel-thead').innerHTML = `
|
document.getElementById('intel-thead').innerHTML = `
|
||||||
<tr><th>ID</th><th>Company</th><th>Event</th><th>Type</th><th>Direction</th><th>Magnitude</th><th>Timeframe</th><th>Rationale</th><th>Created</th></tr>`;
|
<tr><th>ID</th><th>Company</th><th>Event</th><th>Type</th><th>Direction</th><th>Magnitude</th><th>Timeframe</th><th>Rationale</th><th>Created</th></tr>`;
|
||||||
|
|
||||||
document.getElementById('intel-tbody').innerHTML = data.rows.map(r => `
|
document.getElementById('intel-tbody').innerHTML = data.rows.map(r => `
|
||||||
<tr>
|
<tr style="cursor:pointer" onclick="openIntelDetail(${r.id}, 'predictions')">
|
||||||
<td style="color:#64748b">${r.id}</td>
|
<td style="color:#64748b">${r.id}</td>
|
||||||
<td style="white-space:nowrap">${r.company_name}</td>
|
<td style="white-space:nowrap">${r.company_name}</td>
|
||||||
<td style="color:#64748b">${r.event_id}</td>
|
<td style="color:#64748b">${r.event_id}</td>
|
||||||
|
|
@ -813,7 +827,7 @@ async function loadIntelligence() {
|
||||||
<td>${r.direction || '—'}</td>
|
<td>${r.direction || '—'}</td>
|
||||||
<td>${r.magnitude || '—'}</td>
|
<td>${r.magnitude || '—'}</td>
|
||||||
<td>${r.timeframe || '—'}</td>
|
<td>${r.timeframe || '—'}</td>
|
||||||
<td><span class="truncate" style="max-width:300px" title="${(r.rationale||'').replace(/"/g,'"')}">${r.rationale || '—'}</span></td>
|
<td><span class="truncate" style="max-width:300px">${r.rationale || '—'}</span></td>
|
||||||
<td style="color:#64748b; white-space:nowrap">${r.created_at ? r.created_at.slice(0,16) : '—'}</td>
|
<td style="color:#64748b; white-space:nowrap">${r.created_at ? r.created_at.slice(0,16) : '—'}</td>
|
||||||
</tr>
|
</tr>
|
||||||
`).join('');
|
`).join('');
|
||||||
|
|
@ -831,6 +845,45 @@ document.getElementById('iNextBtn').onclick = () => { intelOffset += PAGE; loadI
|
||||||
|
|
||||||
document.getElementById('i-view').onchange = () => { intelOffset = 0; loadIntelligence(); };
|
document.getElementById('i-view').onchange = () => { intelOffset = 0; loadIntelligence(); };
|
||||||
|
|
||||||
|
let intelRows = [];
|
||||||
|
|
||||||
|
function openIntelDetail(id, view) {
|
||||||
|
const row = intelRows.find(r => r.id === id);
|
||||||
|
if (!row) return;
|
||||||
|
|
||||||
|
document.getElementById('intel-modal-title').textContent =
|
||||||
|
`${row.company_name} — Event ${row.event_id}`;
|
||||||
|
|
||||||
|
const meta = [`type: ${row.type || view}`, `created: ${row.created_at ? row.created_at.slice(0,16) : '—'}`];
|
||||||
|
document.getElementById('intel-modal-meta').innerHTML = meta.map(m => `<span>${m}</span>`).join('');
|
||||||
|
|
||||||
|
let body = '';
|
||||||
|
if (view === 'knowledge') {
|
||||||
|
try {
|
||||||
|
const parsed = JSON.parse(row.data);
|
||||||
|
body = Object.entries(parsed).map(([k, v]) => `${k}: ${v}`).join('\n');
|
||||||
|
} catch (_) { body = row.data; }
|
||||||
|
} else {
|
||||||
|
body = [
|
||||||
|
row.rationale,
|
||||||
|
'',
|
||||||
|
`direction: ${row.direction || '—'}`,
|
||||||
|
`magnitude: ${row.magnitude || '—'}`,
|
||||||
|
`timeframe: ${row.timeframe || '—'}`,
|
||||||
|
].join('\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
document.getElementById('intel-modal-body').textContent = body;
|
||||||
|
document.getElementById('intelOverlay').classList.add('open');
|
||||||
|
}
|
||||||
|
|
||||||
|
document.getElementById('intelCloseBtn').onclick = () =>
|
||||||
|
document.getElementById('intelOverlay').classList.remove('open');
|
||||||
|
|
||||||
|
document.getElementById('intelOverlay').onclick = function(e) {
|
||||||
|
if (e.target === this) this.classList.remove('open');
|
||||||
|
};
|
||||||
|
|
||||||
// ── sql console ────────────────────────────────────────────────────────────
|
// ── sql console ────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
async function runSql() {
|
async function runSql() {
|
||||||
|
|
@ -899,18 +952,31 @@ const tabContents = {
|
||||||
sql: document.getElementById('tab-sql'),
|
sql: document.getElementById('tab-sql'),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function switchTab(tab) {
|
||||||
|
if (!tabContents[tab]) tab = 'articles';
|
||||||
|
|
||||||
|
document.querySelectorAll('.tab-btn').forEach(b => {
|
||||||
|
b.classList.toggle('active', b.dataset.tab === tab);
|
||||||
|
});
|
||||||
|
|
||||||
|
Object.entries(tabContents).forEach(([k, el]) => {
|
||||||
|
el.style.display = k === tab ? '' : 'none';
|
||||||
|
});
|
||||||
|
|
||||||
|
location.hash = tab;
|
||||||
|
|
||||||
|
if (tab === 'events') loadEvents();
|
||||||
|
if (tab === 'stats') loadStats();
|
||||||
|
if (tab === 'intelligence') { intelOffset = 0; loadIntelligenceStats().then(ok => { if (ok) { loadIntelligenceCompanies(); loadIntelligence(); } }); }
|
||||||
|
}
|
||||||
|
|
||||||
document.querySelectorAll('.tab-btn').forEach(btn => {
|
document.querySelectorAll('.tab-btn').forEach(btn => {
|
||||||
btn.onclick = () => {
|
btn.onclick = () => switchTab(btn.dataset.tab);
|
||||||
document.querySelectorAll('.tab-btn').forEach(b => b.classList.remove('active'));
|
});
|
||||||
btn.classList.add('active');
|
|
||||||
const tab = btn.dataset.tab;
|
window.addEventListener('hashchange', () => {
|
||||||
Object.entries(tabContents).forEach(([k, el]) => {
|
const tab = location.hash.replace('#', '');
|
||||||
el.style.display = k === tab ? '' : 'none';
|
switchTab(tab);
|
||||||
});
|
|
||||||
if (tab === 'events') loadEvents();
|
|
||||||
if (tab === 'stats') loadStats();
|
|
||||||
if (tab === 'intelligence') { intelOffset = 0; loadIntelligenceStats().then(ok => { if (ok) { loadIntelligenceCompanies(); loadIntelligence(); } }); }
|
|
||||||
};
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// close overlays on backdrop click
|
// close overlays on backdrop click
|
||||||
|
|
@ -923,9 +989,12 @@ document.getElementById('eventOverlay').onclick = function(e) {
|
||||||
|
|
||||||
// ── init ───────────────────────────────────────────────────────────────────
|
// ── init ───────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
loadStats();
|
const initialTab = location.hash.replace('#', '') || 'articles';
|
||||||
|
switchTab(initialTab);
|
||||||
|
|
||||||
loadSources();
|
loadSources();
|
||||||
loadArticles();
|
if (initialTab === 'articles') loadArticles();
|
||||||
|
loadStats();
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
||||||
|
|
@ -82,11 +82,53 @@ function seedCompanies(db) {
|
||||||
);
|
);
|
||||||
|
|
||||||
const companies = [
|
const companies = [
|
||||||
{ name: "NVIDIA", ticker: "NVDA", aliases: ["Nvidia Corporation", "NVDA"] },
|
// semiconductors
|
||||||
{ name: "TSMC", ticker: "TSM", aliases: ["Taiwan Semiconductor", "Taiwan Semiconductor Manufacturing"] },
|
{ name: "NVIDIA", ticker: "NVDA", aliases: ["Nvidia Corporation"] },
|
||||||
{ name: "ASML", ticker: "ASML", aliases: ["ASML Holding", "ASML Holdings"] },
|
{ name: "TSMC", ticker: "TSM", aliases: ["Taiwan Semiconductor", "Taiwan Semiconductor Manufacturing Company"] },
|
||||||
|
{ name: "ASML", ticker: "ASML", aliases: ["ASML Holding"] },
|
||||||
{ name: "Intel", ticker: "INTC", aliases: ["Intel Corporation"] },
|
{ name: "Intel", ticker: "INTC", aliases: ["Intel Corporation"] },
|
||||||
|
{ name: "AMD", ticker: "AMD", aliases: ["Advanced Micro Devices"] },
|
||||||
|
{ name: "Qualcomm", ticker: "QCOM", aliases: ["Qualcomm Incorporated"] },
|
||||||
|
{ name: "Broadcom", ticker: "AVGO", aliases: ["Broadcom Inc"] },
|
||||||
|
{ name: "Micron", ticker: "MU", aliases: ["Micron Technology"] },
|
||||||
|
{ name: "Texas Instruments", ticker: "TXN", aliases: ["TI"] },
|
||||||
|
{ name: "Applied Materials", ticker: "AMAT", aliases: ["Applied Materials Inc"] },
|
||||||
|
{ name: "Lam Research", ticker: "LRCX", aliases: ["Lam Research Corporation"] },
|
||||||
|
{ name: "KLA Corporation", ticker: "KLAC", aliases: ["KLA"] },
|
||||||
{ name: "Samsung", ticker: "005930.KS", aliases: ["Samsung Electronics", "Samsung Group"] },
|
{ name: "Samsung", ticker: "005930.KS", aliases: ["Samsung Electronics", "Samsung Group"] },
|
||||||
|
{ name: "SK Hynix", ticker: "000660.KS", aliases: ["Hynix"] },
|
||||||
|
|
||||||
|
// big tech / cloud
|
||||||
|
{ name: "Microsoft", ticker: "MSFT", aliases: ["Microsoft Corporation"] },
|
||||||
|
{ name: "Apple", ticker: "AAPL", aliases: ["Apple Inc"] },
|
||||||
|
{ name: "Alphabet", ticker: "GOOGL", aliases: ["Google", "Google LLC", "DeepMind"] },
|
||||||
|
{ name: "Amazon", ticker: "AMZN", aliases: ["Amazon Web Services", "AWS"] },
|
||||||
|
{ name: "Meta", ticker: "META", aliases: ["Meta Platforms", "Facebook"] },
|
||||||
|
{ name: "Tesla", ticker: "TSLA", aliases: ["Tesla Inc", "Tesla Motors"] },
|
||||||
|
|
||||||
|
// AI / infrastructure
|
||||||
|
{ name: "OpenAI", ticker: "OPENAI", aliases: ["Open AI"] },
|
||||||
|
{ name: "Anthropic", ticker: "ANTHROPIC", aliases: [] },
|
||||||
|
{ name: "xAI", ticker: "XAI", aliases: ["x.AI"] },
|
||||||
|
{ name: "Palantir", ticker: "PLTR", aliases: ["Palantir Technologies"] },
|
||||||
|
{ name: "Super Micro Computer", ticker: "SMCI", aliases: ["Supermicro", "SMCI"] },
|
||||||
|
{ name: "Arista Networks", ticker: "ANET", aliases: ["Arista"] },
|
||||||
|
|
||||||
|
// networking / hardware
|
||||||
|
{ name: "Cisco", ticker: "CSCO", aliases: ["Cisco Systems"] },
|
||||||
|
{ name: "Marvell Technology", ticker: "MRVL", aliases: ["Marvell"] },
|
||||||
|
{ name: "Arm Holdings", ticker: "ARM", aliases: ["Arm", "ARM Ltd"] },
|
||||||
|
|
||||||
|
// enterprise software
|
||||||
|
{ name: "Oracle", ticker: "ORCL", aliases: ["Oracle Corporation"] },
|
||||||
|
{ name: "Salesforce", ticker: "CRM", aliases: ["Salesforce Inc"] },
|
||||||
|
{ name: "SAP", ticker: "SAP", aliases: ["SAP SE"] },
|
||||||
|
{ name: "ServiceNow", ticker: "NOW", aliases: [] },
|
||||||
|
|
||||||
|
// storage / infra
|
||||||
|
{ name: "Western Digital", ticker: "WDC", aliases: ["WD", "Western Digital Corporation"] },
|
||||||
|
{ name: "Seagate", ticker: "STX", aliases: ["Seagate Technology"] },
|
||||||
|
{ name: "Pure Storage", ticker: "PSTG", aliases: [] },
|
||||||
];
|
];
|
||||||
|
|
||||||
for (const c of companies) {
|
for (const c of companies) {
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue