The /info_documents API endpoint retrieves detailed information for specific documents by their IDs. This includes the full text content and metadata for each requested document, allowing you to inspect and analyze document details.
Endpoint: POST /info_documents
Content-Type: application/json
{
"ids": ["string", "string", "..."]
}| Parameter | Type | Required | Description |
|---|---|---|---|
ids |
array | Yes | Array of document IDs to retrieve information for |
{
"documents": [
{
"id": "string",
"text": "string",
"metadata": "object"
}
],
"found_count": "integer",
"not_found_count": "integer",
"not_found_ids": ["string"],
"collection_name": "string"
}| Field | Type | Description |
|---|---|---|
documents |
array | Array of found document information objects |
documents[].id |
string | Document ID |
documents[].text |
string | Full text content of the document |
documents[].metadata |
object | Metadata associated with the document |
found_count |
integer | Number of documents successfully found |
not_found_count |
integer | Number of documents that were not found |
not_found_ids |
array | Array of document IDs that were not found |
collection_name |
string | Name of the collection (typically "documents") |
{
"error": "string",
"error_type": "string",
"param": "string",
"code": "string"
}async function getDocumentsInfo(documentIds) {
if (!Array.isArray(documentIds) || documentIds.length === 0) {
throw new Error('Document IDs must be a non-empty array');
}
const requestBody = {
ids: documentIds
};
try {
const response = await fetch('http://localhost:8080/info_documents', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
// Add authentication headers if required
// 'Authorization': 'Bearer your-token',
// 'X-API-Key': 'your-api-key'
},
body: JSON.stringify(requestBody)
});
if (!response.ok) {
const errorData = await response.json();
throw new Error(`API Error (${response.status}): ${errorData.error}`);
}
const data = await response.json();
return data;
} catch (error) {
console.error('Get documents info failed:', error);
throw error;
}
}
// Example usage
const documentIdsToQuery = [
"doc-123-1691234567890",
"doc-124-1691234567891",
"nonexistent-id-123"
];
getDocumentsInfo(documentIdsToQuery)
.then(result => {
console.log(`📁 Collection: ${result.collection_name}`);
console.log(`✅ Found: ${result.found_count} documents`);
console.log(`❌ Not found: ${result.not_found_count} documents`);
// Display found documents
result.documents.forEach((doc, index) => {
console.log(`\n📄 Document ${index + 1}:`);
console.log(` ID: ${doc.id}`);
console.log(` Text: ${doc.text.substring(0, 100)}...`);
console.log(` Metadata:`, doc.metadata);
});
// Display not found IDs
if (result.not_found_ids.length > 0) {
console.log('\n🔍 Not found:');
result.not_found_ids.forEach(id => {
console.log(` ${id}`);
});
}
})
.catch(error => {
console.error('Error getting document info:', error);
});const axios = require('axios');
class DocumentInfoManager {
constructor(baseURL = 'http://localhost:8080', apiKey = null) {
this.client = axios.create({
baseURL: baseURL,
headers: {
'Content-Type': 'application/json',
...(apiKey && { 'X-API-Key': apiKey })
},
timeout: 30000
});
}
async getDocumentsInfo(documentIds) {
// Validate input
if (!Array.isArray(documentIds) || documentIds.length === 0) {
throw new Error('Document IDs must be a non-empty array');
}
const uniqueIds = [...new Set(documentIds)]; // Remove duplicates
try {
const response = await this.client.post('/info_documents', {
ids: uniqueIds
});
return response.data;
} catch (error) {
if (error.response) {
const errorData = error.response.data;
throw new Error(`API Error (${error.response.status}): ${errorData.error}`);
} else if (error.request) {
throw new Error('No response from server - check if server is running');
} else {
throw new Error(`Request error: ${error.message}`);
}
}
}
async getSingleDocumentInfo(documentId) {
const result = await this.getDocumentsInfo([documentId]);
if (result.found_count === 0) {
return null;
}
return result.documents[0];
}
async analyzeDocuments(documentIds) {
const result = await this.getDocumentsInfo(documentIds);
const analysis = {
summary: {
total_requested: documentIds.length,
found: result.found_count,
not_found: result.not_found_count,
collection: result.collection_name
},
text_analysis: {
total_characters: 0,
total_words: 0,
avg_length: 0,
length_distribution: {},
language_patterns: {}
},
metadata_analysis: {
common_fields: {},
field_types: {},
metadata_stats: {}
},
documents: result.documents.map(doc => ({
id: doc.id,
text_length: doc.text.length,
word_count: doc.text.split(/\s+/).length,
metadata_fields: Object.keys(doc.metadata),
has_metadata: Object.keys(doc.metadata).length > 0
}))
};
// Text analysis
result.documents.forEach(doc => {
const textLength = doc.text.length;
const wordCount = doc.text.split(/\s+/).length;
analysis.text_analysis.total_characters += textLength;
analysis.text_analysis.total_words += wordCount;
// Length distribution
const lengthBucket = Math.floor(textLength / 500) * 500;
const lengthKey = `${lengthBucket}-${lengthBucket + 499}`;
analysis.text_analysis.length_distribution[lengthKey] =
(analysis.text_analysis.length_distribution[lengthKey] || 0) + 1;
// Metadata analysis
Object.entries(doc.metadata).forEach(([key, value]) => {
analysis.metadata_analysis.common_fields[key] =
(analysis.metadata_analysis.common_fields[key] || 0) + 1;
const valueType = Array.isArray(value) ? 'array' : typeof value;
analysis.metadata_analysis.field_types[key] = valueType;
});
});
// Calculate averages
if (result.found_count > 0) {
analysis.text_analysis.avg_length =
Math.round(analysis.text_analysis.total_characters / result.found_count);
}
return analysis;
}
async compareDocuments(documentIds) {
const result = await this.getDocumentsInfo(documentIds);
if (result.found_count < 2) {
throw new Error('Need at least 2 documents for comparison');
}
const comparison = {
documents: result.documents.map(doc => ({
id: doc.id,
text_length: doc.text.length,
word_count: doc.text.split(/\s+/).length,
unique_words: new Set(doc.text.toLowerCase().match(/\b\w+\b/g) || []).size,
metadata_fields: Object.keys(doc.metadata),
preview: doc.text.substring(0, 200) + '...'
})),
similarities: {},
differences: {
length_variance: 0,
metadata_overlap: {},
common_metadata_fields: []
}
};
// Calculate similarities and differences
const docs = result.documents;
for (let i = 0; i < docs.length; i++) {
for (let j = i + 1; j < docs.length; j++) {
const doc1 = docs[i];
const doc2 = docs[j];
const key = `${doc1.id}_vs_${doc2.id}`;
// Simple text similarity (Jaccard similarity of words)
const words1 = new Set(doc1.text.toLowerCase().match(/\b\w+\b/g) || []);
const words2 = new Set(doc2.text.toLowerCase().match(/\b\w+\b/g) || []);
const intersection = new Set([...words1].filter(x => words2.has(x)));
const union = new Set([...words1, ...words2]);
const textSimilarity = intersection.size / union.size;
// Metadata similarity
const meta1Keys = new Set(Object.keys(doc1.metadata));
const meta2Keys = new Set(Object.keys(doc2.metadata));
const metaIntersection = new Set([...meta1Keys].filter(x => meta2Keys.has(x)));
const metaUnion = new Set([...meta1Keys, ...meta2Keys]);
const metaSimilarity = metaUnion.size > 0 ? metaIntersection.size / metaUnion.size : 0;
comparison.similarities[key] = {
text_similarity: Math.round(textSimilarity * 100) / 100,
metadata_similarity: Math.round(metaSimilarity * 100) / 100,
length_difference: Math.abs(doc1.text.length - doc2.text.length)
};
}
}
return comparison;
}
async exportDocumentsToJson(documentIds, options = {}) {
const result = await this.getDocumentsInfo(documentIds);
const exportData = {
export_metadata: {
timestamp: new Date().toISOString(),
requested_ids: documentIds,
found_count: result.found_count,
not_found_count: result.not_found_count,
collection_name: result.collection_name,
export_version: '1.0'
},
documents: result.documents,
not_found_ids: result.not_found_ids
};
if (options.includeAnalysis) {
exportData.analysis = await this.analyzeDocuments(documentIds);
}
return exportData;
}
}
// Example usage
const docInfoManager = new DocumentInfoManager('http://localhost:8080');
async function demonstrateDocumentInfo() {
try {
const testIds = [
'doc-123-1691234567890',
'doc-124-1691234567891',
'doc-125-1691234567892'
];
console.log('🔍 Getting document information...\n');
// Basic document info
const result = await docInfoManager.getDocumentsInfo(testIds);
console.log(`📊 Results: ${result.found_count} found, ${result.not_found_count} not found`);
// Detailed analysis
console.log('\n📈 Analyzing documents...');
const analysis = await docInfoManager.analyzeDocuments(testIds);
console.log('Text Analysis:', analysis.text_analysis);
console.log('Metadata Analysis:', analysis.metadata_analysis);
// Export with analysis
console.log('\n💾 Exporting documents...');
const exportData = await docInfoManager.exportDocumentsToJson(testIds, {
includeAnalysis: true
});
console.log(`Exported ${exportData.documents.length} documents with analysis`);
} catch (error) {
console.error('❌ Demo failed:', error.message);
}
}
demonstrateDocumentInfo();const fs = require('fs').promises;
const path = require('path');
const https = require('https');
const http = require('http');
const url = require('url');
function getDocumentsInfo(serverUrl, documentIds, options = {}) {
return new Promise((resolve, reject) => {
if (!Array.isArray(documentIds) || documentIds.length === 0) {
reject(new Error('Document IDs must be a non-empty array'));
return;
}
const parsedUrl = url.parse(serverUrl);
const requestModule = parsedUrl.protocol === 'https:' ? https : http;
const requestData = JSON.stringify({
ids: documentIds
});
const requestOptions = {
hostname: parsedUrl.hostname,
port: parsedUrl.port,
path: '/info_documents',
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': Buffer.byteLength(requestData),
...(options.apiKey && { 'X-API-Key': options.apiKey })
}
};
const req = requestModule.request(requestOptions, (res) => {
let responseBody = '';
res.on('data', (chunk) => {
responseBody += chunk;
});
res.on('end', () => {
try {
const parsedResponse = JSON.parse(responseBody);
if (res.statusCode >= 200 && res.statusCode < 300) {
resolve(parsedResponse);
} else {
reject(new Error(`API Error (${res.statusCode}): ${parsedResponse.error}`));
}
} catch (error) {
reject(new Error(`Failed to parse response: ${error.message}`));
}
});
});
req.on('error', (error) => {
reject(new Error(`Request failed: ${error.message}`));
});
req.on('timeout', () => {
req.destroy();
reject(new Error('Request timeout'));
});
req.setTimeout(60000); // 60 second timeout for large document sets
req.write(requestData);
req.end();
});
}
async function batchGetDocumentsInfo(serverUrl, allDocumentIds, options = {}) {
const batchSize = options.batchSize || 25; // Smaller batches for info requests
const results = [];
let totalFound = 0;
let totalNotFound = 0;
console.log(`📊 Processing ${allDocumentIds.length} document IDs in batches of ${batchSize}`);
for (let i = 0; i < allDocumentIds.length; i += batchSize) {
const batch = allDocumentIds.slice(i, i + batchSize);
const batchNumber = Math.floor(i / batchSize) + 1;
const totalBatches = Math.ceil(allDocumentIds.length / batchSize);
console.log(`📦 Processing batch ${batchNumber}/${totalBatches} (${batch.length} documents)`);
try {
const batchResult = await getDocumentsInfo(serverUrl, batch, options);
results.push(batchResult);
totalFound += batchResult.found_count;
totalNotFound += batchResult.not_found_count;
console.log(` ✅ Found: ${batchResult.found_count}, ❌ Not found: ${batchResult.not_found_count}`);
// Small delay between batches
if (i + batchSize < allDocumentIds.length) {
await new Promise(resolve => setTimeout(resolve, 200));
}
} catch (error) {
console.error(`❌ Batch ${batchNumber} failed:`, error.message);
results.push({
found_count: 0,
not_found_count: batch.length,
documents: [],
not_found_ids: batch,
error: error.message
});
totalNotFound += batch.length;
}
}
// Aggregate results
const allDocuments = [];
const allNotFoundIds = [];
results.forEach(result => {
if (result.documents) {
allDocuments.push(...result.documents);
}
if (result.not_found_ids) {
allNotFoundIds.push(...result.not_found_ids);
}
});
console.log(`\n📊 Final Results:`);
console.log(`Total documents requested: ${allDocumentIds.length}`);
console.log(`Successfully found: ${totalFound}`);
console.log(`Not found: ${totalNotFound}`);
console.log(`Success rate: ${((totalFound / allDocumentIds.length) * 100).toFixed(1)}%`);
return {
documents: allDocuments,
found_count: totalFound,
not_found_count: totalNotFound,
not_found_ids: allNotFoundIds,
collection_name: results[0]?.collection_name || 'documents',
batches: results
};
}
async function exportDocumentDetails(serverUrl, documentIds, outputDir = './exports', options = {}) {
try {
console.log('📋 Fetching detailed document information...');
const result = await batchGetDocumentsInfo(serverUrl, documentIds, options);
// Create export directory
await fs.mkdir(outputDir, { recursive: true });
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
// Export full document details
const detailsFilename = `document-details-${timestamp}.json`;
const detailsPath = path.join(outputDir, detailsFilename);
const exportData = {
export_metadata: {
timestamp: new Date().toISOString(),
total_requested: documentIds.length,
found_count: result.found_count,
not_found_count: result.not_found_count,
collection_name: result.collection_name
},
documents: result.documents,
not_found_ids: result.not_found_ids
};
await fs.writeFile(detailsPath, JSON.stringify(exportData, null, 2));
console.log(`✅ Document details exported to: ${detailsPath}`);
// Export summary report
const summaryFilename = `document-summary-${timestamp}.txt`;
const summaryPath = path.join(outputDir, summaryFilename);
let summaryText = `Document Information Summary\n`;
summaryText += `Generated: ${new Date().toISOString()}\n`;
summaryText += `Collection: ${result.collection_name}\n`;
summaryText += `Total Requested: ${documentIds.length}\n`;
summaryText += `Found: ${result.found_count}\n`;
summaryText += `Not Found: ${result.not_found_count}\n\n`;
summaryText += `=== FOUND DOCUMENTS ===\n`;
result.documents.forEach((doc, index) => {
summaryText += `\n${index + 1}. ID: ${doc.id}\n`;
summaryText += ` Text Length: ${doc.text.length} characters\n`;
summaryText += ` Word Count: ~${doc.text.split(/\s+/).length} words\n`;
summaryText += ` Metadata Fields: ${Object.keys(doc.metadata).join(', ') || 'None'}\n`;
summaryText += ` Preview: ${doc.text.substring(0, 150)}...\n`;
});
if (result.not_found_ids.length > 0) {
summaryText += `\n=== NOT FOUND DOCUMENTS ===\n`;
result.not_found_ids.forEach((id, index) => {
summaryText += `${index + 1}. ${id}\n`;
});
}
await fs.writeFile(summaryPath, summaryText);
console.log(`📄 Summary report created: ${summaryPath}`);
// Export individual document files if requested
if (options.exportIndividualFiles) {
const docsDir = path.join(outputDir, `documents-${timestamp}`);
await fs.mkdir(docsDir, { recursive: true });
for (const doc of result.documents) {
const docFilename = `${doc.id.replace(/[^a-zA-Z0-9-_]/g, '_')}.json`;
const docPath = path.join(docsDir, docFilename);
await fs.writeFile(docPath, JSON.stringify(doc, null, 2));
}
console.log(`📁 Individual document files created in: ${docsDir}`);
}
return {
details_file: detailsPath,
summary_file: summaryPath,
document_count: result.found_count,
not_found_count: result.not_found_count
};
} catch (error) {
console.error('❌ Export failed:', error.message);
throw error;
}
}
// Example usage
async function main() {
const serverUrl = 'http://localhost:8080';
const documentIds = [
'doc-123-1691234567890',
'doc-124-1691234567891',
'doc-125-1691234567892',
'nonexistent-doc-999'
];
try {
// Get document information
const result = await getDocumentsInfo(serverUrl, documentIds);
console.log('📋 Document Information Results:');
console.log(`Found: ${result.found_count} documents`);
console.log(`Not found: ${result.not_found_count} documents`);
// Export with individual files
await exportDocumentDetails(serverUrl, documentIds, './document-exports', {
batchSize: 10,
exportIndividualFiles: true
});
} catch (error) {
console.error('❌ Operation failed:', error.message);
}
}
main();<!DOCTYPE html>
<html>
<head>
<title>Document Information Viewer</title>
<style>
.container { max-width: 1200px; margin: 20px auto; padding: 20px; }
.input-section { margin: 20px 0; }
.id-input { width: 100%; height: 150px; margin: 10px 0; padding: 10px; border: 1px solid #ddd; border-radius: 4px; }
.controls { display: flex; gap: 10px; margin: 20px 0; }
.button { padding: 10px 20px; border: none; border-radius: 5px; cursor: pointer; }
.primary { background: #007bff; color: white; }
.secondary { background: #6c757d; color: white; }
.success { background: #28a745; color: white; }
.stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 15px; margin: 20px 0; }
.stat-card { background: white; padding: 15px; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); border-left: 4px solid #007bff; }
.document-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(400px, 1fr)); gap: 20px; margin: 20px 0; }
.document-card { background: white; border: 1px solid #ddd; border-radius: 8px; padding: 20px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); }
.document-id { font-family: monospace; background: #f8f9fa; padding: 5px 10px; border-radius: 4px; margin-bottom: 10px; }
.document-text { background: #f8f9fa; padding: 15px; border-radius: 4px; margin: 10px 0; max-height: 200px; overflow-y: auto; white-space: pre-wrap; font-size: 14px; }
.metadata { background: #fff3cd; padding: 10px; border-radius: 4px; margin: 10px 0; }
.metadata pre { margin: 0; font-size: 12px; }
.not-found { background: #f8d7da; border: 1px solid #f5c6cb; color: #721c24; padding: 15px; border-radius: 4px; margin: 15px 0; }
.loading { text-align: center; padding: 40px; color: #6c757d; }
.error { background: #f8d7da; border: 1px solid #f5c6cb; color: #721c24; padding: 15px; border-radius: 4px; margin: 15px 0; }
.text-stats { font-size: 12px; color: #6c757d; margin-top: 10px; }
.expand-btn { background: #e9ecef; border: 1px solid #ced4da; padding: 5px 10px; border-radius: 4px; cursor: pointer; font-size: 12px; margin-top: 10px; }
.expanded .document-text { max-height: none; }
</style>
</head>
<body>
<div class="container">
<h1>Document Information Viewer</h1>
<div class="input-section">
<h3>Document IDs to Query</h3>
<textarea
id="document-ids"
class="id-input"
placeholder="Enter document IDs, one per line or comma-separated Example: doc-123-1691234567890 doc-124-1691234567891 doc-125-1691234567892"
></textarea>
</div>
<div class="controls">
<button class="button primary" onclick="getDocumentInfo()" id="query-btn">Get Document Info</button>
<button class="button secondary" onclick="clearResults()">Clear Results</button>
<button class="button success" onclick="exportResults()" id="export-btn" disabled>Export Results</button>
</div>
<div class="stats" id="stats" style="display: none;">
<div class="stat-card">
<strong id="total-requested">0</strong><br>
Total Requested
</div>
<div class="stat-card">
<strong id="found-count">0</strong><br>
Documents Found
</div>
<div class="stat-card">
<strong id="not-found-count">0</strong><br>
Not Found
</div>
<div class="stat-card">
<strong id="avg-length">0</strong><br>
Avg Text Length
</div>
</div>
<div id="results-container">
<div class="loading" style="display: none;" id="loading">Loading document information...</div>
</div>
<div id="error-container"></div>
</div>
<script>
let currentResults = null;
function parseDocumentIds() {
const input = document.getElementById('document-ids').value.trim();
if (!input) return [];
const ids = input.split(/[,\n]/)
.map(id => id.trim())
.filter(id => id.length > 0);
return [...new Set(ids)]; // Remove duplicates
}
async function getDocumentInfo() {
const documentIds = parseDocumentIds();
if (documentIds.length === 0) {
alert('Please enter at least one document ID.');
return;
}
const queryBtn = document.getElementById('query-btn');
const exportBtn = document.getElementById('export-btn');
const loading = document.getElementById('loading');
const errorContainer = document.getElementById('error-container');
const resultsContainer = document.getElementById('results-container');
queryBtn.disabled = true;
queryBtn.textContent = 'Loading...';
exportBtn.disabled = true;
loading.style.display = 'block';
errorContainer.innerHTML = '';
resultsContainer.innerHTML = '';
resultsContainer.appendChild(loading);
try {
const response = await fetch('http://localhost:8080/info_documents', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
ids: documentIds
})
});
if (!response.ok) {
const errorData = await response.json();
throw new Error(errorData.error);
}
const result = await response.json();
currentResults = result;
displayResults(result, documentIds);
updateStats(result, documentIds);
exportBtn.disabled = false;
} catch (error) {
errorContainer.innerHTML = `<div class="error">❌ Failed to get document info: ${error.message}</div>`;
resultsContainer.innerHTML = '';
} finally {
queryBtn.disabled = false;
queryBtn.textContent = 'Get Document Info';
loading.style.display = 'none';
}
}
function updateStats(result, originalIds) {
const statsDiv = document.getElementById('stats');
document.getElementById('total-requested').textContent = originalIds.length;
document.getElementById('found-count').textContent = result.found_count;
document.getElementById('not-found-count').textContent = result.not_found_count;
if (result.documents.length > 0) {
const totalLength = result.documents.reduce((sum, doc) => sum + doc.text.length, 0);
const avgLength = Math.round(totalLength / result.documents.length);
document.getElementById('avg-length').textContent = avgLength;
} else {
document.getElementById('avg-length').textContent = '0';
}
statsDiv.style.display = 'grid';
}
function displayResults(result, originalIds) {
const resultsContainer = document.getElementById('results-container');
let html = '';
// Found documents
if (result.documents.length > 0) {
html += '<h3>📄 Found Documents</h3>';
html += '<div class="document-grid">';
result.documents.forEach((doc, index) => {
const wordCount = doc.text.split(/\s+/).length;
const hasMetadata = Object.keys(doc.metadata).length > 0;
html += `
<div class="document-card" id="doc-card-${index}">
<div class="document-id">ID: ${doc.id}</div>
<div class="text-stats">
📊 ${doc.text.length} characters, ~${wordCount} words
</div>
<div class="document-text">
${escapeHtml(doc.text)}
</div>
${doc.text.length > 500 ?
`<button class="expand-btn" onclick="toggleExpand(${index})">
<span id="expand-text-${index}">Show Full Text</span>
</button>` : ''}
${hasMetadata ? `
<div class="metadata">
<strong>📋 Metadata:</strong>
<pre>${JSON.stringify(doc.metadata, null, 2)}</pre>
</div>
` : '<div style="color: #6c757d; font-style: italic;">No metadata</div>'}
<div style="margin-top: 15px;">
<button class="button" style="background: #ffc107; color: black; padding: 5px 10px; font-size: 12px;"
onclick="copyToClipboard('${doc.id}')">Copy ID</button>
<button class="button" style="background: #17a2b8; color: white; padding: 5px 10px; font-size: 12px;"
onclick="copyToClipboard(\`${escapeForJs(doc.text)}\`)">Copy Text</button>
</div>
</div>
`;
});
html += '</div>';
}
// Not found documents
if (result.not_found_ids.length > 0) {
html += '<h3>🔍 Not Found Documents</h3>';
html += '<div class="not-found">';
html += '<strong>The following document IDs were not found:</strong><ul>';
result.not_found_ids.forEach(id => {
html += `<li><code>${id}</code></li>`;
});
html += '</ul></div>';
}
resultsContainer.innerHTML = html;
}
function toggleExpand(index) {
const card = document.getElementById(`doc-card-${index}`);
const expandText = document.getElementById(`expand-text-${index}`);
if (card.classList.contains('expanded')) {
card.classList.remove('expanded');
expandText.textContent = 'Show Full Text';
} else {
card.classList.add('expanded');
expandText.textContent = 'Show Less';
}
}
function escapeHtml(text) {
const div = document.createElement('div');
div.textContent = text;
return div.innerHTML;
}
function escapeForJs(text) {
return text.replace(/`/g, '\\`').replace(/\$/g, '\\$').replace(/\\/g, '\\\\');
}
function copyToClipboard(text) {
navigator.clipboard.writeText(text).then(() => {
// You could add a toast notification here
console.log('Copied to clipboard');
}).catch(err => {
console.error('Failed to copy: ', err);
});
}
function clearResults() {
document.getElementById('document-ids').value = '';
document.getElementById('results-container').innerHTML = '<div class="loading" style="display: none;" id="loading">Loading document information...</div>';
document.getElementById('error-container').innerHTML = '';
document.getElementById('stats').style.display = 'none';
document.getElementById('export-btn').disabled = true;
currentResults = null;
}
function exportResults() {
if (!currentResults) {
alert('No results to export');
return;
}
const exportData = {
export_metadata: {
timestamp: new Date().toISOString(),
export_type: 'document_info',
total_requested: document.getElementById('total-requested').textContent,
found_count: currentResults.found_count,
not_found_count: currentResults.not_found_count
},
collection_name: currentResults.collection_name,
documents: currentResults.documents,
not_found_ids: currentResults.not_found_ids
};
const dataStr = JSON.stringify(exportData, null, 2);
const dataBlob = new Blob([dataStr], {type: 'application/json'});
const url = URL.createObjectURL(dataBlob);
const link = document.createElement('a');
link.href = url;
link.download = `document-info-${new Date().toISOString().split('T')[0]}.json`;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
URL.revokeObjectURL(url);
}
</script>
</body>
</html>// This will return a 400 error
const response = await fetch('/info_documents', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ ids: [] })
});
// Error: "Invalid request parameters: ids cannot be empty"// This will return a 400 error
const response = await fetch('/info_documents', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ document_ids: ["doc-123"] }) // Wrong field name
});
// Error: Missing required field 'ids'// This will return a 400 error
const response = await fetch('/info_documents', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: '{"ids": [invalid json}'
});
// Error: "Invalid JSON: ..."- Batch Size: Limit batch sizes to 25-50 documents to avoid response timeouts
- Error Handling: Check both found and not_found results in responses
- Data Validation: Validate document IDs before making requests
- Caching: Cache document information for frequently accessed documents
- Text Handling: Handle large text content appropriately in UI
- Export: Provide export functionality for document analysis
- Performance: Consider pagination for large document info requests
The API includes CORS headers for cross-origin requests:
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: POST, OPTIONS
Access-Control-Allow-Headers: Content-Type, Authorization, X-API-KeyIf your server is configured with authentication, include the appropriate headers:
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer your-jwt-token',
// or
'X-API-Key': 'your-api-key'
}- Document Inspection: View full content and metadata of specific documents
- Content Analysis: Analyze document text and metadata patterns
- Quality Assurance: Verify document content and indexing accuracy
- Data Export: Export document content for backup or migration
- Debugging: Troubleshoot document-related issues
- Content Management: Build interfaces for document editing and management
- Compliance: Audit document content for regulatory requirements