148 lines
3.9 KiB
JavaScript
148 lines
3.9 KiB
JavaScript
// In-memory admin state for the mock backend. Mirrors GlobalSettings / Source / TrackedEvent
|
|
// from homefeed-data-schema.md. Real backend replaces this with SQLite-backed storage.
|
|
|
|
let settings = {
|
|
mergeStrictness: 3,
|
|
defaultPollIntervalMinutes: 15,
|
|
holdBeforePublishMinutes: 30,
|
|
tagDedupThreshold: 0.82,
|
|
tagExpiryDays: 21,
|
|
followUpMinHoursSinceLast: 6,
|
|
followUpMinNewSources: 2,
|
|
aiServiceHost: "http://10.0.0.14",
|
|
aiServicePort: 11434,
|
|
selectedModels: {
|
|
embedding: "nomic-embed-text-v1.5",
|
|
image: "clip-vit-b32",
|
|
synthesis: "qwen2.5:7b-instruct-q4_K_M"
|
|
},
|
|
retention: {
|
|
publishedArticleMaxAgeDays: 7,
|
|
rawItemMaxAgeDays: 7,
|
|
storageCapEnabled: true,
|
|
storageCapValue: 500,
|
|
storageCapUnit: "GB",
|
|
storageUsedMB: 214
|
|
},
|
|
categoryPriority: [
|
|
{ id: "cat-top", name: "Top stories", priorityRank: 1 },
|
|
{ id: "cat-local", name: "Local", priorityRank: 2 },
|
|
{ id: "cat-world", name: "World", priorityRank: 3 },
|
|
{ id: "cat-business", name: "Business", priorityRank: 4 },
|
|
{ id: "cat-tech", name: "Tech", priorityRank: 5 },
|
|
{ id: "cat-culture", name: "Culture", priorityRank: 6 }
|
|
]
|
|
};
|
|
|
|
let sources = [
|
|
{
|
|
id: "src-1",
|
|
name: "Reuters World",
|
|
type: "rss",
|
|
category: ["World"],
|
|
url: "https://reuters.com/world/rss",
|
|
pollIntervalMinutes: 15,
|
|
enabled: true,
|
|
lastPolledAt: new Date(Date.now() - 6 * 60000).toISOString(),
|
|
lastError: null
|
|
},
|
|
{
|
|
id: "src-2",
|
|
name: "Middle East Watch",
|
|
type: "telegram",
|
|
category: ["Iran war (event)"],
|
|
url: "@meast_watch",
|
|
pollIntervalMinutes: 5,
|
|
enabled: true,
|
|
lastPolledAt: new Date(Date.now() - 2 * 60000).toISOString(),
|
|
lastError: null
|
|
},
|
|
{
|
|
id: "src-3",
|
|
name: "6ABC Philadelphia",
|
|
type: "rss",
|
|
category: ["Local: Philadelphia"],
|
|
url: "https://6abc.com/feed",
|
|
pollIntervalMinutes: 10,
|
|
enabled: true,
|
|
lastPolledAt: new Date(Date.now() - 4 * 60000).toISOString(),
|
|
lastError: null
|
|
},
|
|
{
|
|
id: "src-4",
|
|
name: "PennDOT Alerts",
|
|
type: "rss",
|
|
category: ["Local: Philadelphia"],
|
|
url: "https://penndot.pa.gov/alerts/feed",
|
|
pollIntervalMinutes: 10,
|
|
enabled: true,
|
|
lastPolledAt: new Date(Date.now() - 40 * 60000).toISOString(),
|
|
lastError: "502 Bad Gateway"
|
|
}
|
|
];
|
|
|
|
let events = [
|
|
{
|
|
id: "evt-iran",
|
|
name: "Iran war",
|
|
description: "Ongoing conflict coverage, sourced primarily from Telegram channels for speed.",
|
|
sourceIds: ["src-2"],
|
|
cadence: "daily",
|
|
cadenceTime: "18:00",
|
|
active: true,
|
|
retentionOverrideDays: null
|
|
},
|
|
{
|
|
id: "evt-fed",
|
|
name: "Fed rate decisions",
|
|
description: "",
|
|
sourceIds: ["src-1"],
|
|
cadence: "continuous",
|
|
cadenceTime: null,
|
|
active: true,
|
|
retentionOverrideDays: 7
|
|
}
|
|
];
|
|
|
|
// Simulated Ollama-backed model catalog, per task
|
|
const models = {
|
|
embedding: ["nomic-embed-text-v1.5", "all-MiniLM-L6-v2"],
|
|
image: ["clip-vit-b32", "siglip-base"],
|
|
synthesis: ["qwen2.5:7b-instruct-q4_K_M", "phi3.5:3.8b-mini-instruct-q4", "llama3.1:8b-instruct-q4"]
|
|
};
|
|
|
|
module.exports = {
|
|
getSettings: () => settings,
|
|
updateSettings: (patch) => {
|
|
settings = { ...settings, ...patch, retention: { ...settings.retention, ...(patch.retention || {}) } };
|
|
return settings;
|
|
},
|
|
getSources: () => sources,
|
|
addSource: (source) => {
|
|
const newSource = { id: `src-${Date.now()}`, lastPolledAt: null, lastError: null, enabled: true, ...source };
|
|
sources = [...sources, newSource];
|
|
return newSource;
|
|
},
|
|
updateSource: (id, patch) => {
|
|
sources = sources.map((s) => (s.id === id ? { ...s, ...patch } : s));
|
|
return sources.find((s) => s.id === id);
|
|
},
|
|
deleteSource: (id) => {
|
|
sources = sources.filter((s) => s.id !== id);
|
|
},
|
|
getEvents: () => events,
|
|
addEvent: (event) => {
|
|
const newEvent = { id: `evt-${Date.now()}`, active: true, sourceIds: [], ...event };
|
|
events = [...events, newEvent];
|
|
return newEvent;
|
|
},
|
|
updateEvent: (id, patch) => {
|
|
events = events.map((e) => (e.id === id ? { ...e, ...patch } : e));
|
|
return events.find((e) => e.id === id);
|
|
},
|
|
deleteEvent: (id) => {
|
|
events = events.filter((e) => e.id !== id);
|
|
},
|
|
getModels: () => models
|
|
};
|