ai-knowledge
Version:
ai-knowledge
150 lines (140 loc) • 4.79 kB
JavaScript
const fs = require('fs');
const path = require('path');
const config = require('../config');
const { ensureDir } = require('../utils/fileUtils');
/**
* 生成HTML搜索结果报告
*/
function generateHtmlReport(results, query, options = {}) {
const {
loaderHistory = {},
title = 'Search Results',
reportsDir = config.reports.path
} = options;
// 确保报告目录存在
ensureDir(reportsDir);
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
// 直接使用results作为结果数组,而不是假设它是一个包含结果的对象
const resultsArray = Array.isArray(results) ? results : [];
const html = `
<html>
<head>
<meta charset="UTF-8">
<title>${title} - ${query}</title>
<style>
body {
font-family: Arial, sans-serif;
line-height: 1.6;
max-width: 1200px;
margin: 0 auto;
padding: 20px;
background: #f5f5f5;
}
.search-info {
background: #fff;
padding: 20px;
border-radius: 5px;
margin-bottom: 20px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
.result {
background: #fff;
padding: 20px;
margin-bottom: 20px;
border-radius: 5px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
.metadata {
font-size: 0.9em;
color: #666;
margin: 10px 0;
padding: 10px;
background: #f8f8f8;
border-radius: 3px;
}
.score {
font-weight: bold;
color: #2a9d8f;
}
.source {
color: #0066cc;
text-decoration: none;
}
.content {
margin-top: 10px;
padding: 15px;
background: #f9f9f9;
border-radius: 3px;
border-left: 4px solid #2a9d8f;
}
.source-tag {
display: inline-block;
padding: 3px 8px;
border-radius: 12px;
font-size: 0.8em;
font-weight: bold;
margin-right: 8px;
}
.url-tag { background: #2a9d8f; color: white; }
.file-tag { background: #e76f51; color: white; }
.dir-tag { background: #457b9d; color: white; }
.content-text {
white-space: pre-wrap;
word-wrap: break-word;
overflow-wrap: break-word;
}
</style>
</head>
<body>
<div class="search-info">
<h1>${title}</h1>
<p><strong>查询:</strong> ${query}</p>
<p><strong>时间:</strong> ${new Date().toLocaleString()}</p>
<p><strong>结果数量:</strong> ${resultsArray.length}</p>
</div>
<div class="results">
${resultsArray.map((result, index) => {
// 确定来源类型
let sourceType = 'unknown';
let sourceTag = '';
if (result.metadata && result.metadata.source) {
if (result.metadata.source.startsWith('http')) {
sourceType = 'url';
sourceTag = '<span class="source-tag url-tag">URL</span>';
} else if (result.metadata.type === 'file') {
sourceType = 'file';
sourceTag = '<span class="source-tag file-tag">文件</span>';
} else if (result.metadata.type === 'directory') {
sourceType = 'directory';
sourceTag = '<span class="source-tag dir-tag">目录</span>';
}
}
return `
<div class="result">
<h2>${sourceTag}结果 ${index + 1}</h2>
<div class="metadata">
<p><span class="score">相关度: ${result.score.toFixed(4) || '未知'}</span></p>
<p>来源: ${sourceType === 'url' && result.metadata && result.metadata.source
? `<a class="source" href="${result.metadata.source}" target="_blank">${result.metadata.source}</a>`
: (result.metadata && result.metadata.source ? result.metadata.source : '未知')
}</p>
${result.metadata && result.metadata.filename ? `<p>文件名: ${result.metadata.filename}</p>` : ''}
${result.metadata && result.metadata.type ? `<p>类型: ${result.metadata.type}</p>` : ''}
</div>
<div class="content">
<pre class="content-text">${result.text || result.content || '无内容'}</pre>
</div>
</div>
`;
}).join('')}
</div>
</body>
</html>
`;
const filename = `search-results-${timestamp}.html`;
const filepath = path.join(reportsDir, filename);
fs.writeFileSync(filepath, html);
return filepath;
}
module.exports = { generateHtmlReport };