47 lines
2.3 KiB
JavaScript
47 lines
2.3 KiB
JavaScript
import { escapeHtml } from './citations.js';
|
|
|
|
export function renderSourcesList(sources) {
|
|
if (!sources || sources.length === 0) return '<p class="assistant-muted">No citations returned.</p>';
|
|
return sources.map(function (s, idx) {
|
|
var n = s.number || idx + 1;
|
|
var page = s.page || s.page_number || s.pageNumber;
|
|
var meta = [];
|
|
if (page) meta.push('page ' + page);
|
|
if (s.source_type === 'multimodal_page') meta.push('visual PDF page');
|
|
if (s.visual_caption_source) meta.push('caption: ' + s.visual_caption_source);
|
|
if (s.visual_kind || s.source_priority) meta.push(s.visual_kind || s.source_priority);
|
|
if (s.category) meta.push(s.category);
|
|
if (s.doc_type || s.type) meta.push(s.doc_type || s.type);
|
|
if (s.score != null) meta.push('score ' + Number(s.score).toFixed(3));
|
|
return '<div class="assistant-source" id="assistant-source-' + n + '">' +
|
|
'<strong>[' + n + '] ' + escapeHtml(s.title || s.resource || 'Untitled source') + '</strong>' +
|
|
renderSourceBadges(s) +
|
|
'<div class="assistant-source-meta">' + escapeHtml(meta.join(' · ') || 'indexed source') + '</div>' +
|
|
(s.excerpt ? '<div class="assistant-source-excerpt"><p>' + escapeHtml(cleanSourceExcerpt(s.excerpt).slice(0, 900)) + '</p></div>' : '') +
|
|
'</div>';
|
|
}).join('');
|
|
}
|
|
|
|
function renderSourceBadges(source) {
|
|
var badges = [];
|
|
if (source.source_priority) badges.push(source.source_priority);
|
|
if (source.visual_kind && badges.indexOf(source.visual_kind) === -1) badges.push(source.visual_kind);
|
|
if (source.visual_caption_source && badges.indexOf(source.visual_caption_source) === -1) badges.push(source.visual_caption_source);
|
|
if (source.category) badges.push(source.category);
|
|
if (source.source_boost && Number(source.source_boost) !== 1) badges.push(Number(source.source_boost).toFixed(2) + 'x');
|
|
if (!badges.length) return '';
|
|
return '<div class="assistant-source-badges">' + badges.slice(0, 4).map(function (badge) {
|
|
return '<span>' + escapeHtml(badge) + '</span>';
|
|
}).join('') + '</div>';
|
|
}
|
|
|
|
function cleanSourceExcerpt(text) {
|
|
return String(text || '')
|
|
.replace(/^\[Page-image match\]\s*/i, '')
|
|
.replace(/<br\s*\/?>/gi, ' ')
|
|
.replace(/\*\*/g, '')
|
|
.replace(/\|\s*-{2,}\s*/g, ' ')
|
|
.replace(/\|/g, ' ')
|
|
.replace(/\s+/g, ' ')
|
|
.trim();
|
|
}
|