@contiva/sapbtp-docs-mcp 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +395 -0
- package/README.md +386 -0
- package/build/cache/embedding-cache.d.ts +39 -0
- package/build/cache/embedding-cache.d.ts.map +1 -0
- package/build/cache/embedding-cache.js +105 -0
- package/build/cache/embedding-cache.js.map +1 -0
- package/build/cache/file-cache.d.ts +40 -0
- package/build/cache/file-cache.d.ts.map +1 -0
- package/build/cache/file-cache.js +124 -0
- package/build/cache/file-cache.js.map +1 -0
- package/build/cache/search-cache.d.ts +39 -0
- package/build/cache/search-cache.d.ts.map +1 -0
- package/build/cache/search-cache.js +97 -0
- package/build/cache/search-cache.js.map +1 -0
- package/build/index.d.ts +3 -0
- package/build/index.d.ts.map +1 -0
- package/build/index.js +17 -0
- package/build/index.js.map +1 -0
- package/build/indexing/file-registry.d.ts +47 -0
- package/build/indexing/file-registry.d.ts.map +1 -0
- package/build/indexing/file-registry.js +130 -0
- package/build/indexing/file-registry.js.map +1 -0
- package/build/indexing/topic-index.d.ts +57 -0
- package/build/indexing/topic-index.d.ts.map +1 -0
- package/build/indexing/topic-index.js +181 -0
- package/build/indexing/topic-index.js.map +1 -0
- package/build/parsers/links.d.ts +14 -0
- package/build/parsers/links.d.ts.map +1 -0
- package/build/parsers/links.js +80 -0
- package/build/parsers/links.js.map +1 -0
- package/build/parsers/markdown.d.ts +10 -0
- package/build/parsers/markdown.d.ts.map +1 -0
- package/build/parsers/markdown.js +120 -0
- package/build/parsers/markdown.js.map +1 -0
- package/build/parsers/metadata.d.ts +19 -0
- package/build/parsers/metadata.d.ts.map +1 -0
- package/build/parsers/metadata.js +63 -0
- package/build/parsers/metadata.js.map +1 -0
- package/build/search/fulltext.d.ts +20 -0
- package/build/search/fulltext.d.ts.map +1 -0
- package/build/search/fulltext.js +117 -0
- package/build/search/fulltext.js.map +1 -0
- package/build/search/ranking.d.ts +27 -0
- package/build/search/ranking.d.ts.map +1 -0
- package/build/search/ranking.js +119 -0
- package/build/search/ranking.js.map +1 -0
- package/build/search/semantic.d.ts +53 -0
- package/build/search/semantic.d.ts.map +1 -0
- package/build/search/semantic.js +260 -0
- package/build/search/semantic.js.map +1 -0
- package/build/search/title.d.ts +18 -0
- package/build/search/title.d.ts.map +1 -0
- package/build/search/title.js +95 -0
- package/build/search/title.js.map +1 -0
- package/build/server.d.ts +32 -0
- package/build/server.d.ts.map +1 -0
- package/build/server.js +183 -0
- package/build/server.js.map +1 -0
- package/build/tools/get-related.d.ts +64 -0
- package/build/tools/get-related.d.ts.map +1 -0
- package/build/tools/get-related.js +203 -0
- package/build/tools/get-related.js.map +1 -0
- package/build/tools/list-topics.d.ts +43 -0
- package/build/tools/list-topics.d.ts.map +1 -0
- package/build/tools/list-topics.js +63 -0
- package/build/tools/list-topics.js.map +1 -0
- package/build/tools/read-article.d.ts +42 -0
- package/build/tools/read-article.d.ts.map +1 -0
- package/build/tools/read-article.js +89 -0
- package/build/tools/read-article.js.map +1 -0
- package/build/tools/search.d.ts +57 -0
- package/build/tools/search.d.ts.map +1 -0
- package/build/tools/search.js +109 -0
- package/build/tools/search.js.map +1 -0
- package/build/types/index.d.ts +179 -0
- package/build/types/index.d.ts.map +1 -0
- package/build/types/index.js +2 -0
- package/build/types/index.js.map +1 -0
- package/build/utils/docs-downloader.d.ts +9 -0
- package/build/utils/docs-downloader.d.ts.map +1 -0
- package/build/utils/docs-downloader.js +82 -0
- package/build/utils/docs-downloader.js.map +1 -0
- package/build/utils/paths.d.ts +67 -0
- package/build/utils/paths.d.ts.map +1 -0
- package/build/utils/paths.js +132 -0
- package/build/utils/paths.js.map +1 -0
- package/build/utils/text-processing.d.ts +62 -0
- package/build/utils/text-processing.d.ts.map +1 -0
- package/build/utils/text-processing.js +214 -0
- package/build/utils/text-processing.js.map +1 -0
- package/package.json +63 -0
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { normalizeText, tokenize, extractSnippet, containsAllWords } from '../utils/text-processing.js';
|
|
2
|
+
/**
|
|
3
|
+
* Full-text search implementation
|
|
4
|
+
*/
|
|
5
|
+
export class FullTextSearch {
|
|
6
|
+
registry;
|
|
7
|
+
fileCache;
|
|
8
|
+
constructor(registry, fileCache) {
|
|
9
|
+
this.registry = registry;
|
|
10
|
+
this.fileCache = fileCache;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Performs full-text search across documentation
|
|
14
|
+
*/
|
|
15
|
+
async search(options) {
|
|
16
|
+
const { query, area = 'all', limit = 20 } = options;
|
|
17
|
+
// Get files to search
|
|
18
|
+
const files = area === 'all'
|
|
19
|
+
? this.registry.getAllFiles()
|
|
20
|
+
: this.registry.getByArea(area);
|
|
21
|
+
// Score each file
|
|
22
|
+
const scoredResults = [];
|
|
23
|
+
// Limit concurrent file reads to 50
|
|
24
|
+
const batchSize = 50;
|
|
25
|
+
for (let i = 0; i < Math.min(files.length, 200); i += batchSize) {
|
|
26
|
+
const batch = files.slice(i, i + batchSize);
|
|
27
|
+
const batchResults = await Promise.all(batch.map(async (file) => {
|
|
28
|
+
try {
|
|
29
|
+
const doc = await this.fileCache.get(file.filePath);
|
|
30
|
+
const score = this.scoreDocument(doc.cleanText, doc.title, query);
|
|
31
|
+
if (score > 0) {
|
|
32
|
+
const snippet = extractSnippet(doc.cleanText, query, 100);
|
|
33
|
+
return {
|
|
34
|
+
result: {
|
|
35
|
+
filePath: file.filePath,
|
|
36
|
+
relativePath: file.relativePath,
|
|
37
|
+
title: doc.title,
|
|
38
|
+
loioId: doc.loioId,
|
|
39
|
+
snippet,
|
|
40
|
+
score,
|
|
41
|
+
matchType: 'fulltext',
|
|
42
|
+
area: file.area,
|
|
43
|
+
},
|
|
44
|
+
score,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
catch (error) {
|
|
50
|
+
// Skip files that can't be read
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
}));
|
|
54
|
+
scoredResults.push(...batchResults.filter((r) => r !== null));
|
|
55
|
+
}
|
|
56
|
+
// Sort by score (descending)
|
|
57
|
+
scoredResults.sort((a, b) => b.score - a.score);
|
|
58
|
+
// Return top results
|
|
59
|
+
return scoredResults.slice(0, limit).map(r => r.result);
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Scores a document based on query relevance
|
|
63
|
+
*/
|
|
64
|
+
scoreDocument(content, title, query) {
|
|
65
|
+
const normalizedContent = normalizeText(content);
|
|
66
|
+
const normalizedTitle = normalizeText(title);
|
|
67
|
+
const normalizedQuery = normalizeText(query);
|
|
68
|
+
const queryTokens = tokenize(query);
|
|
69
|
+
let score = 0;
|
|
70
|
+
// Exact match in title (highest score)
|
|
71
|
+
if (normalizedTitle.includes(normalizedQuery)) {
|
|
72
|
+
score += 100;
|
|
73
|
+
}
|
|
74
|
+
// Exact match in content
|
|
75
|
+
if (normalizedContent.includes(normalizedQuery)) {
|
|
76
|
+
score += 50;
|
|
77
|
+
}
|
|
78
|
+
// Word boundary matches in title
|
|
79
|
+
for (const token of queryTokens) {
|
|
80
|
+
const regex = new RegExp(`\\b${escapeRegex(token)}\\b`, 'i');
|
|
81
|
+
if (regex.test(title)) {
|
|
82
|
+
score += 30;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
// Word boundary matches in content
|
|
86
|
+
for (const token of queryTokens) {
|
|
87
|
+
const regex = new RegExp(`\\b${escapeRegex(token)}\\b`, 'i');
|
|
88
|
+
if (regex.test(content)) {
|
|
89
|
+
score += 10;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
// Partial matches in content
|
|
93
|
+
for (const token of queryTokens) {
|
|
94
|
+
if (normalizedContent.includes(token)) {
|
|
95
|
+
score += 5;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
// Bonus for containing all query words
|
|
99
|
+
if (containsAllWords(content, query)) {
|
|
100
|
+
score += 20;
|
|
101
|
+
}
|
|
102
|
+
// Position bonus (earlier mentions score higher)
|
|
103
|
+
const firstIndex = normalizedContent.indexOf(normalizedQuery);
|
|
104
|
+
if (firstIndex !== -1) {
|
|
105
|
+
const positionBonus = Math.max(0, 20 - Math.floor(firstIndex / 100));
|
|
106
|
+
score += positionBonus;
|
|
107
|
+
}
|
|
108
|
+
return score;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Escapes special regex characters
|
|
113
|
+
*/
|
|
114
|
+
function escapeRegex(str) {
|
|
115
|
+
return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
116
|
+
}
|
|
117
|
+
//# sourceMappingURL=fulltext.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fulltext.js","sourceRoot":"","sources":["../../src/search/fulltext.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { SearchResult } from '../types/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* Combines and ranks search results from multiple search methods
|
|
4
|
+
*/
|
|
5
|
+
export declare class SearchRanking {
|
|
6
|
+
/**
|
|
7
|
+
* Combines results from multiple search methods with weighted scoring
|
|
8
|
+
*/
|
|
9
|
+
combineResults(fulltextResults: SearchResult[], titleResults: SearchResult[], semanticResults: SearchResult[]): SearchResult[];
|
|
10
|
+
/**
|
|
11
|
+
* Calculates weighted total score
|
|
12
|
+
*/
|
|
13
|
+
private calculateTotalScore;
|
|
14
|
+
/**
|
|
15
|
+
* Normalizes scores to 0-100 range
|
|
16
|
+
*/
|
|
17
|
+
normalizeScores(results: SearchResult[]): SearchResult[];
|
|
18
|
+
/**
|
|
19
|
+
* Deduplicates results (keeps highest scoring)
|
|
20
|
+
*/
|
|
21
|
+
deduplicateResults(results: SearchResult[]): SearchResult[];
|
|
22
|
+
/**
|
|
23
|
+
* Filters results by minimum score threshold
|
|
24
|
+
*/
|
|
25
|
+
filterByScore(results: SearchResult[], minScore: number): SearchResult[];
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=ranking.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ranking.d.ts","sourceRoot":"","sources":["../../src/search/ranking.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEtD;;GAEG;AACH,qBAAa,aAAa;IACxB;;OAEG;IACH,cAAc,CACZ,eAAe,EAAE,YAAY,EAAE,EAC/B,YAAY,EAAE,YAAY,EAAE,EAC5B,eAAe,EAAE,YAAY,EAAE,GAC9B,YAAY,EAAE;IA+EjB;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAW3B;;OAEG;IACH,eAAe,CAAC,OAAO,EAAE,YAAY,EAAE,GAAG,YAAY,EAAE;IAiBxD;;OAEG;IACH,kBAAkB,CAAC,OAAO,EAAE,YAAY,EAAE,GAAG,YAAY,EAAE;IAc3D;;OAEG;IACH,aAAa,CAAC,OAAO,EAAE,YAAY,EAAE,EAAE,QAAQ,EAAE,MAAM,GAAG,YAAY,EAAE;CAGzE"}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Combines and ranks search results from multiple search methods
|
|
3
|
+
*/
|
|
4
|
+
export class SearchRanking {
|
|
5
|
+
/**
|
|
6
|
+
* Combines results from multiple search methods with weighted scoring
|
|
7
|
+
*/
|
|
8
|
+
combineResults(fulltextResults, titleResults, semanticResults) {
|
|
9
|
+
// Weights for each search type
|
|
10
|
+
const weights = {
|
|
11
|
+
fulltext: 0.4,
|
|
12
|
+
title: 0.3,
|
|
13
|
+
semantic: 0.3,
|
|
14
|
+
};
|
|
15
|
+
// Create a map to track best score per file
|
|
16
|
+
const fileScores = new Map();
|
|
17
|
+
// Process fulltext results
|
|
18
|
+
for (const result of fulltextResults) {
|
|
19
|
+
const existing = fileScores.get(result.filePath);
|
|
20
|
+
if (!existing) {
|
|
21
|
+
fileScores.set(result.filePath, {
|
|
22
|
+
result: { ...result, matchType: 'combined' },
|
|
23
|
+
scores: { fulltext: result.score, title: 0, semantic: 0 },
|
|
24
|
+
totalScore: result.score * weights.fulltext,
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
existing.scores.fulltext = Math.max(existing.scores.fulltext, result.score);
|
|
29
|
+
existing.totalScore = this.calculateTotalScore(existing.scores, weights);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
// Process title results
|
|
33
|
+
for (const result of titleResults) {
|
|
34
|
+
const existing = fileScores.get(result.filePath);
|
|
35
|
+
if (!existing) {
|
|
36
|
+
fileScores.set(result.filePath, {
|
|
37
|
+
result: { ...result, matchType: 'combined' },
|
|
38
|
+
scores: { fulltext: 0, title: result.score, semantic: 0 },
|
|
39
|
+
totalScore: result.score * weights.title,
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
existing.scores.title = Math.max(existing.scores.title, result.score);
|
|
44
|
+
existing.totalScore = this.calculateTotalScore(existing.scores, weights);
|
|
45
|
+
// Prefer snippet from title search if score is high
|
|
46
|
+
if (result.score > existing.scores.fulltext) {
|
|
47
|
+
existing.result.snippet = result.snippet;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
// Process semantic results
|
|
52
|
+
for (const result of semanticResults) {
|
|
53
|
+
const existing = fileScores.get(result.filePath);
|
|
54
|
+
if (!existing) {
|
|
55
|
+
fileScores.set(result.filePath, {
|
|
56
|
+
result: { ...result, matchType: 'combined' },
|
|
57
|
+
scores: { fulltext: 0, title: 0, semantic: result.score },
|
|
58
|
+
totalScore: result.score * weights.semantic,
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
existing.scores.semantic = Math.max(existing.scores.semantic, result.score);
|
|
63
|
+
existing.totalScore = this.calculateTotalScore(existing.scores, weights);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
// Convert to array and sort by total score
|
|
67
|
+
const combinedResults = Array.from(fileScores.values())
|
|
68
|
+
.map(({ result, totalScore }) => ({
|
|
69
|
+
...result,
|
|
70
|
+
score: totalScore,
|
|
71
|
+
}))
|
|
72
|
+
.sort((a, b) => b.score - a.score);
|
|
73
|
+
return combinedResults;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Calculates weighted total score
|
|
77
|
+
*/
|
|
78
|
+
calculateTotalScore(scores, weights) {
|
|
79
|
+
return (scores.fulltext * weights.fulltext +
|
|
80
|
+
scores.title * weights.title +
|
|
81
|
+
scores.semantic * weights.semantic);
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Normalizes scores to 0-100 range
|
|
85
|
+
*/
|
|
86
|
+
normalizeScores(results) {
|
|
87
|
+
if (results.length === 0) {
|
|
88
|
+
return results;
|
|
89
|
+
}
|
|
90
|
+
const maxScore = Math.max(...results.map(r => r.score));
|
|
91
|
+
if (maxScore === 0) {
|
|
92
|
+
return results;
|
|
93
|
+
}
|
|
94
|
+
return results.map(result => ({
|
|
95
|
+
...result,
|
|
96
|
+
score: (result.score / maxScore) * 100,
|
|
97
|
+
}));
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Deduplicates results (keeps highest scoring)
|
|
101
|
+
*/
|
|
102
|
+
deduplicateResults(results) {
|
|
103
|
+
const fileMap = new Map();
|
|
104
|
+
for (const result of results) {
|
|
105
|
+
const existing = fileMap.get(result.filePath);
|
|
106
|
+
if (!existing || result.score > existing.score) {
|
|
107
|
+
fileMap.set(result.filePath, result);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
return Array.from(fileMap.values());
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Filters results by minimum score threshold
|
|
114
|
+
*/
|
|
115
|
+
filterByScore(results, minScore) {
|
|
116
|
+
return results.filter(result => result.score >= minScore);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
//# sourceMappingURL=ranking.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ranking.js","sourceRoot":"","sources":["../../src/search/ranking.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import type { SemanticSearchOptions, SearchResult } from '../types/index.js';
|
|
2
|
+
import { FileRegistry } from '../indexing/file-registry.js';
|
|
3
|
+
import { FileCache } from '../cache/file-cache.js';
|
|
4
|
+
/**
|
|
5
|
+
* Semantic search using embeddings
|
|
6
|
+
*/
|
|
7
|
+
export declare class SemanticSearch {
|
|
8
|
+
private registry;
|
|
9
|
+
private fileCache;
|
|
10
|
+
private embeddingCache;
|
|
11
|
+
private embeddingData;
|
|
12
|
+
private embeddingModel;
|
|
13
|
+
private provider;
|
|
14
|
+
private modelName;
|
|
15
|
+
constructor(registry: FileRegistry, fileCache: FileCache);
|
|
16
|
+
/**
|
|
17
|
+
* Gets the model name for the configured provider
|
|
18
|
+
*/
|
|
19
|
+
private getModelName;
|
|
20
|
+
/**
|
|
21
|
+
* Initializes the semantic search (loads or builds embeddings)
|
|
22
|
+
*/
|
|
23
|
+
initialize(): Promise<void>;
|
|
24
|
+
/**
|
|
25
|
+
* Builds embeddings for all documents
|
|
26
|
+
*/
|
|
27
|
+
private buildEmbeddings;
|
|
28
|
+
/**
|
|
29
|
+
* Generates an embedding for text
|
|
30
|
+
*/
|
|
31
|
+
private embedText;
|
|
32
|
+
/**
|
|
33
|
+
* Generates embedding using local model (@xenova/transformers)
|
|
34
|
+
*/
|
|
35
|
+
private embedTextLocal;
|
|
36
|
+
/**
|
|
37
|
+
* Generates embedding using Voyage AI (stub - requires voyageai package)
|
|
38
|
+
*/
|
|
39
|
+
private embedTextVoyage;
|
|
40
|
+
/**
|
|
41
|
+
* Generates embedding using OpenAI (stub - requires openai package)
|
|
42
|
+
*/
|
|
43
|
+
private embedTextOpenAI;
|
|
44
|
+
/**
|
|
45
|
+
* Performs semantic search
|
|
46
|
+
*/
|
|
47
|
+
search(options: SemanticSearchOptions): Promise<SearchResult[]>;
|
|
48
|
+
/**
|
|
49
|
+
* Gets embedding for a specific document (for related articles)
|
|
50
|
+
*/
|
|
51
|
+
getDocumentEmbedding(filePath: string): Promise<number[] | null>;
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=semantic.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"semantic.d.ts","sourceRoot":"","sources":["../../src/search/semantic.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,YAAY,EAAyD,MAAM,mBAAmB,CAAC;AACpI,OAAO,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAC5D,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAQnD;;GAEG;AACH,qBAAa,cAAc;IAQvB,OAAO,CAAC,QAAQ;IAChB,OAAO,CAAC,SAAS;IARnB,OAAO,CAAC,cAAc,CAAiB;IACvC,OAAO,CAAC,aAAa,CAAmC;IACxD,OAAO,CAAC,cAAc,CAAa;IACnC,OAAO,CAAC,QAAQ,CAAoB;IACpC,OAAO,CAAC,SAAS,CAAS;gBAGhB,QAAQ,EAAE,YAAY,EACtB,SAAS,EAAE,SAAS;IAO9B;;OAEG;IACH,OAAO,CAAC,YAAY;IAapB;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAiBjC;;OAEG;YACW,eAAe;IAwD7B;;OAEG;YACW,SAAS;IAYvB;;OAEG;YACW,cAAc;IAwB5B;;OAEG;YACW,eAAe;IAgB7B;;OAEG;YACW,eAAe;IAgB7B;;OAEG;IACG,MAAM,CAAC,OAAO,EAAE,qBAAqB,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;IAqErE;;OAEG;IACG,oBAAoB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,GAAG,IAAI,CAAC;CA+BvE"}
|
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
import { EmbeddingCache } from '../cache/embedding-cache.js';
|
|
2
|
+
import { chunkText, cosineSimilarity, truncateText } from '../utils/text-processing.js';
|
|
3
|
+
// Dynamic imports for optional dependencies
|
|
4
|
+
let pipeline = null;
|
|
5
|
+
let env = null;
|
|
6
|
+
/**
|
|
7
|
+
* Semantic search using embeddings
|
|
8
|
+
*/
|
|
9
|
+
export class SemanticSearch {
|
|
10
|
+
registry;
|
|
11
|
+
fileCache;
|
|
12
|
+
embeddingCache;
|
|
13
|
+
embeddingData = null;
|
|
14
|
+
embeddingModel = null;
|
|
15
|
+
provider;
|
|
16
|
+
modelName;
|
|
17
|
+
constructor(registry, fileCache) {
|
|
18
|
+
this.registry = registry;
|
|
19
|
+
this.fileCache = fileCache;
|
|
20
|
+
this.embeddingCache = new EmbeddingCache();
|
|
21
|
+
this.provider = process.env.EMBEDDING_PROVIDER || 'local';
|
|
22
|
+
this.modelName = this.getModelName();
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Gets the model name for the configured provider
|
|
26
|
+
*/
|
|
27
|
+
getModelName() {
|
|
28
|
+
switch (this.provider) {
|
|
29
|
+
case 'local':
|
|
30
|
+
return 'Xenova/all-MiniLM-L6-v2';
|
|
31
|
+
case 'voyage':
|
|
32
|
+
return 'voyage-3';
|
|
33
|
+
case 'openai':
|
|
34
|
+
return 'text-embedding-3-small';
|
|
35
|
+
default:
|
|
36
|
+
return 'Xenova/all-MiniLM-L6-v2';
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Initializes the semantic search (loads or builds embeddings)
|
|
41
|
+
*/
|
|
42
|
+
async initialize() {
|
|
43
|
+
console.error('Initializing semantic search...');
|
|
44
|
+
// Try to load from cache
|
|
45
|
+
const cached = await this.embeddingCache.load();
|
|
46
|
+
if (cached && cached.provider === this.provider && cached.model === this.modelName) {
|
|
47
|
+
console.error(`Loaded ${cached.embeddings.length} embeddings from cache`);
|
|
48
|
+
this.embeddingData = cached;
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
// Build new embeddings
|
|
52
|
+
console.error('Building embeddings index (this may take 10-15 minutes for local embeddings)...');
|
|
53
|
+
await this.buildEmbeddings();
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Builds embeddings for all documents
|
|
57
|
+
*/
|
|
58
|
+
async buildEmbeddings() {
|
|
59
|
+
const startTime = Date.now();
|
|
60
|
+
const files = this.registry.getAllFiles();
|
|
61
|
+
const embeddings = [];
|
|
62
|
+
console.error(`Processing ${files.length} files...`);
|
|
63
|
+
// Process in batches to show progress
|
|
64
|
+
const batchSize = 100;
|
|
65
|
+
for (let i = 0; i < files.length; i += batchSize) {
|
|
66
|
+
const batch = files.slice(i, i + batchSize);
|
|
67
|
+
console.error(`Processing batch ${Math.floor(i / batchSize) + 1}/${Math.ceil(files.length / batchSize)}...`);
|
|
68
|
+
for (const file of batch) {
|
|
69
|
+
try {
|
|
70
|
+
const doc = await this.fileCache.get(file.filePath);
|
|
71
|
+
// Chunk the text
|
|
72
|
+
const chunks = chunkText(doc.cleanText, 500, 50);
|
|
73
|
+
// Generate embeddings for each chunk
|
|
74
|
+
for (const chunk of chunks) {
|
|
75
|
+
const embedding = await this.embedText(chunk.text);
|
|
76
|
+
embeddings.push({
|
|
77
|
+
filePath: file.filePath,
|
|
78
|
+
title: doc.title,
|
|
79
|
+
loioId: doc.loioId,
|
|
80
|
+
chunkIndex: chunk.chunkIndex,
|
|
81
|
+
text: truncateText(chunk.text, 500),
|
|
82
|
+
embedding,
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
catch (error) {
|
|
87
|
+
console.error(`Error processing ${file.filePath}:`, error);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
const elapsed = (Date.now() - startTime) / 1000;
|
|
92
|
+
console.error(`Built ${embeddings.length} embeddings in ${elapsed.toFixed(1)}s`);
|
|
93
|
+
// Save to cache
|
|
94
|
+
this.embeddingData = {
|
|
95
|
+
version: '1.0.0',
|
|
96
|
+
model: this.modelName,
|
|
97
|
+
provider: this.provider,
|
|
98
|
+
createdAt: new Date().toISOString(),
|
|
99
|
+
embeddings,
|
|
100
|
+
};
|
|
101
|
+
await this.embeddingCache.save(this.embeddingData);
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Generates an embedding for text
|
|
105
|
+
*/
|
|
106
|
+
async embedText(text) {
|
|
107
|
+
if (this.provider === 'local') {
|
|
108
|
+
return await this.embedTextLocal(text);
|
|
109
|
+
}
|
|
110
|
+
else if (this.provider === 'voyage') {
|
|
111
|
+
return await this.embedTextVoyage(text);
|
|
112
|
+
}
|
|
113
|
+
else if (this.provider === 'openai') {
|
|
114
|
+
return await this.embedTextOpenAI(text);
|
|
115
|
+
}
|
|
116
|
+
throw new Error(`Unsupported embedding provider: ${this.provider}`);
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Generates embedding using local model (@xenova/transformers)
|
|
120
|
+
*/
|
|
121
|
+
async embedTextLocal(text) {
|
|
122
|
+
// Lazy load transformers
|
|
123
|
+
if (!pipeline) {
|
|
124
|
+
const transformers = await import('@xenova/transformers');
|
|
125
|
+
pipeline = transformers.pipeline;
|
|
126
|
+
env = transformers.env;
|
|
127
|
+
// Disable local model cache (use default cache)
|
|
128
|
+
env.allowLocalModels = false;
|
|
129
|
+
}
|
|
130
|
+
// Initialize model if needed
|
|
131
|
+
if (!this.embeddingModel) {
|
|
132
|
+
console.error('Loading local embedding model (first time only)...');
|
|
133
|
+
this.embeddingModel = await pipeline('feature-extraction', this.modelName);
|
|
134
|
+
}
|
|
135
|
+
// Generate embedding
|
|
136
|
+
const output = await this.embeddingModel(text, { pooling: 'mean', normalize: true });
|
|
137
|
+
// Convert to array
|
|
138
|
+
return Array.from(output.data);
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Generates embedding using Voyage AI (stub - requires voyageai package)
|
|
142
|
+
*/
|
|
143
|
+
async embedTextVoyage(text) {
|
|
144
|
+
try {
|
|
145
|
+
const { VoyageAIClient } = await import('voyageai');
|
|
146
|
+
const client = new VoyageAIClient({ apiKey: process.env.VOYAGE_API_KEY });
|
|
147
|
+
const result = await client.embed({
|
|
148
|
+
input: text,
|
|
149
|
+
model: this.modelName,
|
|
150
|
+
});
|
|
151
|
+
return result.data?.[0]?.embedding || [];
|
|
152
|
+
}
|
|
153
|
+
catch (error) {
|
|
154
|
+
throw new Error('Voyage AI not available. Install with: npm install voyageai');
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Generates embedding using OpenAI (stub - requires openai package)
|
|
159
|
+
*/
|
|
160
|
+
async embedTextOpenAI(text) {
|
|
161
|
+
try {
|
|
162
|
+
const { OpenAI } = await import('openai');
|
|
163
|
+
const client = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
|
|
164
|
+
const result = await client.embeddings.create({
|
|
165
|
+
input: text,
|
|
166
|
+
model: this.modelName,
|
|
167
|
+
});
|
|
168
|
+
return result.data[0].embedding;
|
|
169
|
+
}
|
|
170
|
+
catch (error) {
|
|
171
|
+
throw new Error('OpenAI not available. Install with: npm install openai');
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Performs semantic search
|
|
176
|
+
*/
|
|
177
|
+
async search(options) {
|
|
178
|
+
const { query, area = 'all', limit = 20 } = options;
|
|
179
|
+
// Ensure embeddings are loaded
|
|
180
|
+
if (!this.embeddingData) {
|
|
181
|
+
await this.initialize();
|
|
182
|
+
}
|
|
183
|
+
if (!this.embeddingData) {
|
|
184
|
+
throw new Error('Failed to initialize semantic search');
|
|
185
|
+
}
|
|
186
|
+
// Generate embedding for query
|
|
187
|
+
const queryEmbedding = await this.embedText(query);
|
|
188
|
+
// Calculate similarity scores
|
|
189
|
+
const scoredResults = this.embeddingData.embeddings.map(entry => {
|
|
190
|
+
const similarity = cosineSimilarity(queryEmbedding, entry.embedding);
|
|
191
|
+
const score = similarity * 100; // Convert to 0-100 scale
|
|
192
|
+
return {
|
|
193
|
+
entry,
|
|
194
|
+
score,
|
|
195
|
+
};
|
|
196
|
+
});
|
|
197
|
+
// Sort by score
|
|
198
|
+
scoredResults.sort((a, b) => b.score - a.score);
|
|
199
|
+
// Filter by area if specified
|
|
200
|
+
const filtered = area === 'all'
|
|
201
|
+
? scoredResults
|
|
202
|
+
: scoredResults.filter(r => {
|
|
203
|
+
const file = this.registry.getByPath(r.entry.filePath);
|
|
204
|
+
return file && file.area === area;
|
|
205
|
+
});
|
|
206
|
+
// Group by file (take best chunk per file)
|
|
207
|
+
const fileMap = new Map();
|
|
208
|
+
for (const result of filtered) {
|
|
209
|
+
const existing = fileMap.get(result.entry.filePath);
|
|
210
|
+
if (!existing || result.score > existing.score) {
|
|
211
|
+
fileMap.set(result.entry.filePath, result);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
// Convert to search results
|
|
215
|
+
const results = Array.from(fileMap.values())
|
|
216
|
+
.slice(0, limit)
|
|
217
|
+
.map(({ entry, score }) => {
|
|
218
|
+
const file = this.registry.getByPath(entry.filePath);
|
|
219
|
+
return {
|
|
220
|
+
filePath: entry.filePath,
|
|
221
|
+
relativePath: file?.relativePath || entry.filePath,
|
|
222
|
+
title: entry.title,
|
|
223
|
+
loioId: entry.loioId,
|
|
224
|
+
snippet: entry.text,
|
|
225
|
+
score,
|
|
226
|
+
matchType: 'semantic',
|
|
227
|
+
area: file?.area || 'ISuite',
|
|
228
|
+
};
|
|
229
|
+
});
|
|
230
|
+
return results;
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* Gets embedding for a specific document (for related articles)
|
|
234
|
+
*/
|
|
235
|
+
async getDocumentEmbedding(filePath) {
|
|
236
|
+
if (!this.embeddingData) {
|
|
237
|
+
await this.initialize();
|
|
238
|
+
}
|
|
239
|
+
if (!this.embeddingData) {
|
|
240
|
+
return null;
|
|
241
|
+
}
|
|
242
|
+
// Find embeddings for this file
|
|
243
|
+
const fileEmbeddings = this.embeddingData.embeddings.filter(e => e.filePath === filePath);
|
|
244
|
+
if (fileEmbeddings.length === 0) {
|
|
245
|
+
return null;
|
|
246
|
+
}
|
|
247
|
+
// Average all chunks
|
|
248
|
+
const avgEmbedding = new Array(fileEmbeddings[0].embedding.length).fill(0);
|
|
249
|
+
for (const entry of fileEmbeddings) {
|
|
250
|
+
for (let i = 0; i < entry.embedding.length; i++) {
|
|
251
|
+
avgEmbedding[i] += entry.embedding[i];
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
for (let i = 0; i < avgEmbedding.length; i++) {
|
|
255
|
+
avgEmbedding[i] /= fileEmbeddings.length;
|
|
256
|
+
}
|
|
257
|
+
return avgEmbedding;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
//# sourceMappingURL=semantic.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"semantic.js","sourceRoot":"","sources":["../../src/search/semantic.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { TitleSearchOptions, SearchResult } from '../types/index.js';
|
|
2
|
+
import { FileRegistry } from '../indexing/file-registry.js';
|
|
3
|
+
/**
|
|
4
|
+
* Title-based search implementation
|
|
5
|
+
*/
|
|
6
|
+
export declare class TitleSearch {
|
|
7
|
+
private registry;
|
|
8
|
+
constructor(registry: FileRegistry);
|
|
9
|
+
/**
|
|
10
|
+
* Performs title-based search
|
|
11
|
+
*/
|
|
12
|
+
search(options: TitleSearchOptions): Promise<SearchResult[]>;
|
|
13
|
+
/**
|
|
14
|
+
* Scores a title based on query relevance
|
|
15
|
+
*/
|
|
16
|
+
private scoreTitle;
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=title.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"title.d.ts","sourceRoot":"","sources":["../../src/search/title.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAC1E,OAAO,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAG5D;;GAEG;AACH,qBAAa,WAAW;IACV,OAAO,CAAC,QAAQ;gBAAR,QAAQ,EAAE,YAAY;IAE1C;;OAEG;IACG,MAAM,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;IAsClE;;OAEG;IACH,OAAO,CAAC,UAAU;CAuDnB"}
|