Add clickable link for vector search results
Browse files
client/src/components/knowledge-base/result-card.tsx
CHANGED
|
@@ -285,7 +285,17 @@ export default function ResultCard({
|
|
| 285 |
</Badge>
|
| 286 |
</div>
|
| 287 |
<h3 className="text-lg font-semibold text-slate-900 mb-2 line-clamp-2">
|
| 288 |
-
{document.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 289 |
</h3>
|
| 290 |
<p className="text-sm text-slate-600 mb-3">
|
| 291 |
{document.source}
|
|
|
|
| 285 |
</Badge>
|
| 286 |
</div>
|
| 287 |
<h3 className="text-lg font-semibold text-slate-900 mb-2 line-clamp-2">
|
| 288 |
+
{document.url ? (
|
| 289 |
+
<button
|
| 290 |
+
onClick={handleViewSource}
|
| 291 |
+
className="text-left hover:text-blue-600 dark:hover:text-blue-400 transition-colors duration-200 hover:underline cursor-pointer w-full"
|
| 292 |
+
title="Click to view source"
|
| 293 |
+
>
|
| 294 |
+
{document.title}
|
| 295 |
+
</button>
|
| 296 |
+
) : (
|
| 297 |
+
<span>{document.title}</span>
|
| 298 |
+
)}
|
| 299 |
</h3>
|
| 300 |
<p className="text-sm text-slate-600 mb-3">
|
| 301 |
{document.source}
|
server/document-processor.ts
CHANGED
|
@@ -3,6 +3,7 @@ import path from 'path';
|
|
| 3 |
import { modalClient } from './modal-client';
|
| 4 |
import { nebiusClient } from './nebius-client';
|
| 5 |
import { FileProcessor } from './file-upload';
|
|
|
|
| 6 |
import { type Document, type InsertDocument } from '@shared/schema';
|
| 7 |
|
| 8 |
export interface ProcessingResult {
|
|
@@ -440,11 +441,45 @@ export class DocumentProcessor {
|
|
| 440 |
}> {
|
| 441 |
try {
|
| 442 |
const result = await modalClient.vectorSearch(query, indexName, maxResults);
|
| 443 |
-
|
| 444 |
if (result.status === 'completed') {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 445 |
return {
|
| 446 |
success: true,
|
| 447 |
-
results:
|
| 448 |
};
|
| 449 |
} else {
|
| 450 |
return {
|
|
|
|
| 3 |
import { modalClient } from './modal-client';
|
| 4 |
import { nebiusClient } from './nebius-client';
|
| 5 |
import { FileProcessor } from './file-upload';
|
| 6 |
+
import { storage } from './storage';
|
| 7 |
import { type Document, type InsertDocument } from '@shared/schema';
|
| 8 |
|
| 9 |
export interface ProcessingResult {
|
|
|
|
| 441 |
}> {
|
| 442 |
try {
|
| 443 |
const result = await modalClient.vectorSearch(query, indexName, maxResults);
|
|
|
|
| 444 |
if (result.status === 'completed') {
|
| 445 |
+
// Enrich vector search results with complete document data from database
|
| 446 |
+
const enrichedResults = await Promise.all(
|
| 447 |
+
result.results.map(async (vectorResult: any) => {
|
| 448 |
+
try {
|
| 449 |
+
// Get complete document data from database using the ID
|
| 450 |
+
const dbDocument = await storage.getDocument(parseInt(vectorResult.id));
|
| 451 |
+
if (dbDocument) {
|
| 452 |
+
// Merge vector search metadata with database document
|
| 453 |
+
// Ensure the URL field is preserved from the database
|
| 454 |
+
const enriched = {
|
| 455 |
+
id: dbDocument.id,
|
| 456 |
+
title: dbDocument.title,
|
| 457 |
+
content: dbDocument.content,
|
| 458 |
+
source: dbDocument.source,
|
| 459 |
+
sourceType: dbDocument.sourceType,
|
| 460 |
+
url: dbDocument.url, // Explicitly preserve URL
|
| 461 |
+
metadata: dbDocument.metadata,
|
| 462 |
+
createdAt: dbDocument.createdAt,
|
| 463 |
+
// Add vector search specific fields
|
| 464 |
+
relevanceScore: vectorResult.relevanceScore,
|
| 465 |
+
rank: vectorResult.rank,
|
| 466 |
+
snippet: vectorResult.snippet || dbDocument.content.substring(0, 200) + '...'
|
| 467 |
+
};
|
| 468 |
+
return enriched;
|
| 469 |
+
} else {
|
| 470 |
+
// Fallback to vector result if database document not found
|
| 471 |
+
return vectorResult;
|
| 472 |
+
}
|
| 473 |
+
} catch (error) {
|
| 474 |
+
console.warn(`Failed to enrich vector result for ID ${vectorResult.id}:`, error);
|
| 475 |
+
return vectorResult;
|
| 476 |
+
}
|
| 477 |
+
})
|
| 478 |
+
);
|
| 479 |
+
|
| 480 |
return {
|
| 481 |
success: true,
|
| 482 |
+
results: enrichedResults
|
| 483 |
};
|
| 484 |
} else {
|
| 485 |
return {
|