186 lines
4.4 KiB
JavaScript
186 lines
4.4 KiB
JavaScript
// Store - Application state management
|
|
const Store = {
|
|
currentDoc: null,
|
|
currentSession: null,
|
|
documents: [],
|
|
sessions: [],
|
|
memories: [],
|
|
findings: [],
|
|
pageChunks: [],
|
|
currentPage: 0,
|
|
polygonsVisible: true,
|
|
textVisible: true,
|
|
chunkLabelsVisible: true,
|
|
};
|
|
|
|
// ── API Helper ──
|
|
async function api(endpoint, options = {}) {
|
|
const defaultOpts = {
|
|
headers: { 'Content-Type': 'application/json' },
|
|
};
|
|
const merged = { ...defaultOpts, ...options };
|
|
if (options.body && typeof options.body === 'object' && !(options.body instanceof FormData)) {
|
|
merged.body = JSON.stringify(options.body);
|
|
}
|
|
const url = endpoint.startsWith('http') ? endpoint : `/api${endpoint}`;
|
|
const resp = await fetch(url, merged);
|
|
if (!resp.ok) {
|
|
const text = await resp.text();
|
|
throw new Error(`${resp.status}: ${text}`);
|
|
}
|
|
const ct = resp.headers.get('content-type') || '';
|
|
if (ct.includes('json')) return resp.json();
|
|
return resp;
|
|
}
|
|
|
|
// ── Document Store ──
|
|
const DocStore = {
|
|
async load() {
|
|
const res = await api('/documents');
|
|
Store.documents = res.documents || [];
|
|
return Store.documents;
|
|
},
|
|
|
|
async getChunks(docId, page) {
|
|
const params = new URLSearchParams();
|
|
if (page !== undefined) params.set('page', page);
|
|
const res = await api(`/documents/${docId}/chunks?${params}`);
|
|
Store.pageChunks = res.chunks || [];
|
|
return Store.pageChunks;
|
|
},
|
|
|
|
async upload(file) {
|
|
const fd = new FormData();
|
|
fd.append('file', file);
|
|
const res = await api('/documents/upload', { method: 'POST', body: fd });
|
|
return res;
|
|
},
|
|
|
|
async uploadUrl(url, filename) {
|
|
const res = await api('/documents/upload', {
|
|
method: 'POST',
|
|
body: { pdf_url: url, filename },
|
|
});
|
|
return res;
|
|
},
|
|
};
|
|
|
|
// ── Research Store ──
|
|
const ResearchStore = {
|
|
async run(query, skillNames) {
|
|
const res = await api('/research/run', {
|
|
method: 'POST',
|
|
body: { query, skills: skillNames, doc_id: Store.currentDoc },
|
|
});
|
|
return res;
|
|
},
|
|
|
|
async createSession(query) {
|
|
const res = await api('/research/session', {
|
|
method: 'POST',
|
|
body: query,
|
|
});
|
|
return res;
|
|
},
|
|
|
|
async semanticSearch(query, limit = 20) {
|
|
const res = await api('/research/semantic', {
|
|
method: 'POST',
|
|
body: { query, doc_id: Store.currentDoc, limit },
|
|
});
|
|
return res;
|
|
},
|
|
|
|
async textSearch(query, limit = 20) {
|
|
const res = await api('/research/text-search', {
|
|
method: 'POST',
|
|
body: { query, doc_id: Store.currentDoc, limit },
|
|
});
|
|
return res;
|
|
},
|
|
|
|
async getFindings(sessionId) {
|
|
const res = await api(`/research/findings?session_id=${sessionId || ''}`);
|
|
Store.findings = res.findings || [];
|
|
return Store.findings;
|
|
},
|
|
|
|
async getMemories(sessionId) {
|
|
const res = await api(`/research/memories?session_id=${sessionId || ''}`);
|
|
Store.memories = res.memories || [];
|
|
return Store.memories;
|
|
},
|
|
|
|
async saveFinding(sessionId, query, response) {
|
|
await api('/research/run', {
|
|
method: 'POST',
|
|
body: { query, doc_id: sessionId },
|
|
});
|
|
},
|
|
};
|
|
|
|
// ── Memory Store ──
|
|
const MemoryStore = {
|
|
async save(content, type = 'fact', importance = 3, sourceDocId) {
|
|
const res = await api('/memories/save', {
|
|
method: 'POST',
|
|
body: {
|
|
session_id: Store.currentSession,
|
|
content,
|
|
memory_type: type,
|
|
importance,
|
|
source_doc_id: sourceDocId,
|
|
},
|
|
});
|
|
return res;
|
|
},
|
|
|
|
async search(query, limit = 10) {
|
|
const res = await api('/memories/search', {
|
|
method: 'POST',
|
|
body: { query, limit },
|
|
});
|
|
return res;
|
|
},
|
|
};
|
|
|
|
// ── Agent Store ──
|
|
const AgentStore = {
|
|
async getSkills() {
|
|
const res = await api('/agents/skills');
|
|
return res.skills;
|
|
},
|
|
|
|
async chat(message, model) {
|
|
const res = await api('/ollama/chat', {
|
|
method: 'POST',
|
|
body: {
|
|
model: model || 'gpt-oss:20b',
|
|
messages: [{ role: 'user', content: message }],
|
|
},
|
|
});
|
|
return res;
|
|
},
|
|
};
|
|
|
|
// ── Viewer Store ──
|
|
const ViewerStore = {
|
|
async getPolygonView(docId, page) {
|
|
const res = await api(`/documents/${docId}/polygon-view?page=${page}`);
|
|
return res;
|
|
},
|
|
|
|
async getPageText(docId, page) {
|
|
const res = await api(`/documents/${docId}/page-text?page=${page}`);
|
|
return res;
|
|
},
|
|
};
|
|
|
|
// ── Health Store ──
|
|
const HealthStore = {
|
|
async check() {
|
|
const res = await api('/health');
|
|
return res;
|
|
},
|
|
};
|