Load a topic to view a small local network around its first few entries.
@@ -796,6 +882,7 @@
searchResults: document.getElementById("search-results"),
graphOutput: document.getElementById("graph-output"),
extractVerifyOutput: document.getElementById("extract-verify-output"),
+ claimSupportOutput: document.getElementById("claim-support-output"),
activityLog: document.getElementById("activity-log"),
metricTopicCount: document.getElementById("metric-topic-count"),
metricEntryCount: document.getElementById("metric-entry-count"),
@@ -835,6 +922,11 @@
extractText: document.getElementById("extract-text"),
extractButton: document.getElementById("extract-button"),
verifyButton: document.getElementById("verify-button"),
+ claimSupportText: document.getElementById("claim-support-text"),
+ claimSupportContext: document.getElementById("claim-support-context"),
+ claimSupportMaxClaims: document.getElementById("claim-support-max-claims"),
+ claimSupportMinChars: document.getElementById("claim-support-min-chars"),
+ claimSupportButton: document.getElementById("claim-support-button"),
};
els.serverUrl.value = state.bridgeUrl;
@@ -1057,6 +1149,45 @@
els.extractVerifyOutput.textContent = JSON.stringify(payload, null, 2);
}
+ function renderClaimSupport(payload) {
+ const suggestions = payload?.suggestions || [];
+ if (!suggestions.length) {
+ renderEmpty(els.claimSupportOutput, "No ranked support suggestions yet. Try a longer excerpt or a different context phrase.");
+ return;
+ }
+ els.claimSupportOutput.className = "claim-stack";
+ els.claimSupportOutput.innerHTML = `
+
+
Claim Support Summary
+
${suggestions.length} ranked claims from ${payload.claim_count || 0} extracted candidates · ${payload.existing_reference_count || 0} parsed existing references.
+
Claims are ordered by needs_support_score, so uncited or under-supported assertions appear first.
+
+ ${suggestions.map((suggestion) => `
+
+
Needs Support ${Number(suggestion.needs_support_score ?? 0).toFixed(3)}
+
${escapeHtml(suggestion.claim_text || "")}
+
+ ${(suggestion.existing_citation_markers || []).map((marker) => `${escapeHtml(marker)}`).join("") || 'no inline citations detected'}
+
+ ${suggestion.note ? `
${escapeHtml(suggestion.note)}
` : ""}
+
+ ${(suggestion.suggested_references || []).map((reference) => `
+
+
${escapeHtml(reference.title || reference.citation_key || "candidate")}
+
${escapeHtml(reference.authors || "Unknown authors")} · ${escapeHtml(reference.year || "n.d.")} · score ${Number(reference.score ?? 0).toFixed(3)}
+
+ ${reference.journal ? `${escapeHtml(reference.journal)}` : ""}
+ ${reference.doi ? `${escapeHtml(reference.doi)}` : ""}
+ ${reference.source_label ? `${escapeHtml(reference.source_label)}` : ""}
+
+
+ `).join("")}
+
+
+ `).join("")}
+ `;
+ }
+
function renderExpandSummary(payload) {
if (!els.expandSummary) return;
const results = payload?.results || [];
@@ -1320,6 +1451,29 @@
}
}
+ async function runClaimSupport() {
+ if (!state.client) {
+ setStatus("Connect to the server first.", "error");
+ return;
+ }
+ setBusy(els.claimSupportButton, true);
+ try {
+ const payload = await state.client.supportClaims(els.claimSupportText.value, {
+ context: els.claimSupportContext.value.trim(),
+ limit: 5,
+ max_claims: Number(els.claimSupportMaxClaims.value || 5),
+ min_claim_chars: Number(els.claimSupportMinChars.value || 80),
+ });
+ renderClaimSupport(payload);
+ setLastOp("support_claims");
+ logActivity("support_claims", payload);
+ } catch (error) {
+ setStatus(String(error.message || error), "error");
+ } finally {
+ setBusy(els.claimSupportButton, false);
+ }
+ }
+
async function exportTopicBibtex(topicSlug) {
if (!state.client || !topicSlug) {
setStatus("Connect to the server first.", "error");
@@ -1408,6 +1562,7 @@
els.searchButton.addEventListener("click", runSearch);
els.extractButton.addEventListener("click", runExtract);
els.verifyButton.addEventListener("click", runVerify);
+ els.claimSupportButton.addEventListener("click", runClaimSupport);