@echoes-io/mcp-server 4.1.1 → 6.1.0
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/README.md +120 -185
- package/cli/index.d.ts +1 -0
- package/cli/index.d.ts.map +1 -0
- package/cli/index.js +3 -185
- package/cli/index.js.map +1 -0
- package/cli/program.d.ts +3 -0
- package/cli/program.d.ts.map +1 -0
- package/cli/program.js +151 -0
- package/cli/program.js.map +1 -0
- package/lib/constants.d.ts +8 -0
- package/lib/constants.d.ts.map +1 -0
- package/lib/constants.js +12 -0
- package/lib/constants.js.map +1 -0
- package/lib/database/index.d.ts +34 -0
- package/lib/database/index.d.ts.map +1 -0
- package/lib/database/index.js +266 -0
- package/lib/database/index.js.map +1 -0
- package/lib/database/schemas.d.ts +55 -0
- package/lib/database/schemas.d.ts.map +1 -0
- package/lib/database/schemas.js +70 -0
- package/lib/database/schemas.js.map +1 -0
- package/lib/indexer/embeddings.d.ts +6 -0
- package/lib/indexer/embeddings.d.ts.map +1 -0
- package/lib/indexer/embeddings.js +51 -0
- package/lib/indexer/embeddings.js.map +1 -0
- package/lib/indexer/extractor.d.ts +81 -0
- package/lib/indexer/extractor.d.ts.map +1 -0
- package/lib/indexer/extractor.js +68 -0
- package/lib/indexer/extractor.js.map +1 -0
- package/lib/indexer/scanner.d.ts +8 -0
- package/lib/indexer/scanner.d.ts.map +1 -0
- package/lib/indexer/scanner.js +73 -0
- package/lib/indexer/scanner.js.map +1 -0
- package/lib/indexer/tasks.d.ts +32 -0
- package/lib/indexer/tasks.d.ts.map +1 -0
- package/lib/indexer/tasks.js +228 -0
- package/lib/indexer/tasks.js.map +1 -0
- package/lib/prompts/index.d.ts +13 -0
- package/lib/prompts/index.d.ts.map +1 -0
- package/lib/prompts/index.js +153 -0
- package/lib/prompts/index.js.map +1 -0
- package/lib/server.d.ts +13 -0
- package/lib/server.d.ts.map +1 -0
- package/lib/server.js +90 -0
- package/lib/server.js.map +1 -0
- package/lib/tools/index.d.ts +14 -0
- package/lib/tools/index.d.ts.map +1 -0
- package/lib/tools/index.js +25 -0
- package/lib/tools/index.js.map +1 -0
- package/lib/tools/search.d.ts +86 -0
- package/lib/tools/search.d.ts.map +1 -0
- package/lib/tools/search.js +95 -0
- package/lib/tools/search.js.map +1 -0
- package/lib/tools/stats.d.ts +18 -0
- package/lib/tools/stats.d.ts.map +1 -0
- package/lib/tools/stats.js +62 -0
- package/lib/tools/stats.js.map +1 -0
- package/{src → lib}/tools/words-count.d.ts +6 -3
- package/lib/tools/words-count.d.ts.map +1 -0
- package/lib/tools/words-count.js +31 -0
- package/lib/tools/words-count.js.map +1 -0
- package/{src/types/frontmatter.d.ts → lib/types.d.ts} +11 -17
- package/lib/types.d.ts.map +1 -0
- package/lib/types.js +2 -0
- package/lib/types.js.map +1 -0
- package/lib/utils.d.ts +19 -0
- package/lib/utils.d.ts.map +1 -0
- package/lib/utils.js +40 -0
- package/lib/utils.js.map +1 -0
- package/package.json +60 -62
- package/src/database/index.d.ts +0 -6
- package/src/database/index.js +0 -26
- package/src/database/relations.d.ts +0 -744
- package/src/database/relations.js +0 -52
- package/src/database/schema.d.ts +0 -733
- package/src/database/schema.js +0 -69
- package/src/database/vector.d.ts +0 -25
- package/src/database/vector.js +0 -98
- package/src/index.d.ts +0 -5
- package/src/index.js +0 -5
- package/src/rag/character-ner.d.ts +0 -36
- package/src/rag/character-ner.js +0 -416
- package/src/rag/database-sync.d.ts +0 -38
- package/src/rag/database-sync.js +0 -158
- package/src/rag/embeddings.d.ts +0 -74
- package/src/rag/embeddings.js +0 -164
- package/src/rag/graph-rag.d.ts +0 -69
- package/src/rag/graph-rag.js +0 -311
- package/src/rag/hybrid-rag.d.ts +0 -109
- package/src/rag/hybrid-rag.js +0 -255
- package/src/rag/index.d.ts +0 -16
- package/src/rag/index.js +0 -33
- package/src/server.d.ts +0 -43
- package/src/server.js +0 -177
- package/src/tools/index-rag.d.ts +0 -19
- package/src/tools/index-rag.js +0 -85
- package/src/tools/index-tracker.d.ts +0 -17
- package/src/tools/index-tracker.js +0 -89
- package/src/tools/index.d.ts +0 -5
- package/src/tools/index.js +0 -5
- package/src/tools/rag-context.d.ts +0 -34
- package/src/tools/rag-context.js +0 -51
- package/src/tools/rag-search.d.ts +0 -35
- package/src/tools/rag-search.js +0 -60
- package/src/tools/words-count.js +0 -28
- package/src/types/frontmatter.js +0 -1
- package/src/utils/index.d.ts +0 -1
- package/src/utils/index.js +0 -1
- package/src/utils/markdown.d.ts +0 -6
- package/src/utils/markdown.js +0 -36
- package/src/utils/timeline-detection.d.ts +0 -13
- package/src/utils/timeline-detection.js +0 -76
package/src/rag/database-sync.js
DELETED
|
@@ -1,158 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Database synchronization utilities for HybridRAG
|
|
3
|
-
* Ensures timeline/arc/episode/chapter records exist before indexing
|
|
4
|
-
*/
|
|
5
|
-
import { and, eq } from 'drizzle-orm';
|
|
6
|
-
import { arcs, chapters, episodes, timelines } from '../database/schema.js';
|
|
7
|
-
export class DatabaseSync {
|
|
8
|
-
db;
|
|
9
|
-
constructor(db) {
|
|
10
|
-
this.db = db;
|
|
11
|
-
}
|
|
12
|
-
/**
|
|
13
|
-
* Ensure all required database records exist for chapters
|
|
14
|
-
*/
|
|
15
|
-
async syncChapters(chapterRecords) {
|
|
16
|
-
const stats = { timelines: 0, arcs: 0, episodes: 0, chapters: 0 };
|
|
17
|
-
// Group by timeline, arc, episode for efficient processing
|
|
18
|
-
const timelineMap = new Map();
|
|
19
|
-
const arcMap = new Map();
|
|
20
|
-
const episodeMap = new Map();
|
|
21
|
-
for (const record of chapterRecords) {
|
|
22
|
-
// Timeline tracking
|
|
23
|
-
if (!timelineMap.has(record.timeline)) {
|
|
24
|
-
timelineMap.set(record.timeline, new Set());
|
|
25
|
-
}
|
|
26
|
-
// Arc tracking
|
|
27
|
-
const arcKey = `${record.timeline}:${record.arc}`;
|
|
28
|
-
if (!arcMap.has(arcKey)) {
|
|
29
|
-
arcMap.set(arcKey, new Set());
|
|
30
|
-
timelineMap.get(record.timeline)?.add(record.arc);
|
|
31
|
-
}
|
|
32
|
-
// Episode tracking
|
|
33
|
-
const episodeKey = `${record.timeline}:${record.arc}:${record.episode}`;
|
|
34
|
-
if (!episodeMap.has(episodeKey)) {
|
|
35
|
-
episodeMap.set(episodeKey, new Set());
|
|
36
|
-
arcMap.get(arcKey)?.add(record.episode.toString());
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
// 1. Ensure timelines exist
|
|
40
|
-
for (const timelineName of timelineMap.keys()) {
|
|
41
|
-
const existing = await this.db
|
|
42
|
-
.select()
|
|
43
|
-
.from(timelines)
|
|
44
|
-
.where(eq(timelines.name, timelineName))
|
|
45
|
-
.limit(1);
|
|
46
|
-
if (existing.length === 0) {
|
|
47
|
-
await this.db.insert(timelines).values({
|
|
48
|
-
name: timelineName,
|
|
49
|
-
description: `Auto-created timeline: ${timelineName}`,
|
|
50
|
-
});
|
|
51
|
-
stats.timelines++;
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
// 2. Ensure arcs exist
|
|
55
|
-
for (const [arcKey, _] of arcMap) {
|
|
56
|
-
const [timelineName, arcName] = arcKey.split(':');
|
|
57
|
-
const timelineRecord = await this.db
|
|
58
|
-
.select()
|
|
59
|
-
.from(timelines)
|
|
60
|
-
.where(eq(timelines.name, timelineName))
|
|
61
|
-
.limit(1);
|
|
62
|
-
if (timelineRecord.length === 0)
|
|
63
|
-
continue;
|
|
64
|
-
const existing = await this.db
|
|
65
|
-
.select()
|
|
66
|
-
.from(arcs)
|
|
67
|
-
.where(and(eq(arcs.timelineId, timelineRecord[0].id), eq(arcs.name, arcName)))
|
|
68
|
-
.limit(1);
|
|
69
|
-
if (existing.length === 0) {
|
|
70
|
-
await this.db.insert(arcs).values({
|
|
71
|
-
timelineId: timelineRecord[0].id,
|
|
72
|
-
name: arcName,
|
|
73
|
-
slug: arcName.toLowerCase().replace(/\s+/g, '-'),
|
|
74
|
-
order: stats.arcs + 1,
|
|
75
|
-
});
|
|
76
|
-
stats.arcs++;
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
// 3. Ensure episodes exist
|
|
80
|
-
for (const [episodeKey, _] of episodeMap) {
|
|
81
|
-
const [timelineName, arcName, episodeNum] = episodeKey.split(':');
|
|
82
|
-
const arcRecord = await this.db
|
|
83
|
-
.select({ id: arcs.id })
|
|
84
|
-
.from(arcs)
|
|
85
|
-
.innerJoin(timelines, eq(arcs.timelineId, timelines.id))
|
|
86
|
-
.where(and(eq(timelines.name, timelineName), eq(arcs.name, arcName)))
|
|
87
|
-
.limit(1);
|
|
88
|
-
if (arcRecord.length === 0)
|
|
89
|
-
continue;
|
|
90
|
-
const existing = await this.db
|
|
91
|
-
.select()
|
|
92
|
-
.from(episodes)
|
|
93
|
-
.where(and(eq(episodes.arcId, arcRecord[0].id), eq(episodes.number, parseInt(episodeNum, 10))))
|
|
94
|
-
.limit(1);
|
|
95
|
-
if (existing.length === 0) {
|
|
96
|
-
await this.db.insert(episodes).values({
|
|
97
|
-
arcId: arcRecord[0].id,
|
|
98
|
-
number: parseInt(episodeNum, 10),
|
|
99
|
-
title: `Episode ${episodeNum}`,
|
|
100
|
-
slug: `episode-${episodeNum}`,
|
|
101
|
-
});
|
|
102
|
-
stats.episodes++;
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
// 4. Ensure chapters exist
|
|
106
|
-
for (const record of chapterRecords) {
|
|
107
|
-
const episodeRecord = await this.db
|
|
108
|
-
.select({ id: episodes.id })
|
|
109
|
-
.from(episodes)
|
|
110
|
-
.innerJoin(arcs, eq(episodes.arcId, arcs.id))
|
|
111
|
-
.innerJoin(timelines, eq(arcs.timelineId, timelines.id))
|
|
112
|
-
.where(and(eq(timelines.name, record.timeline), eq(arcs.name, record.arc), eq(episodes.number, record.episode)))
|
|
113
|
-
.limit(1);
|
|
114
|
-
if (episodeRecord.length === 0)
|
|
115
|
-
continue;
|
|
116
|
-
const existing = await this.db
|
|
117
|
-
.select()
|
|
118
|
-
.from(chapters)
|
|
119
|
-
.where(and(eq(chapters.episodeId, episodeRecord[0].id), eq(chapters.number, record.chapter)))
|
|
120
|
-
.limit(1);
|
|
121
|
-
if (existing.length === 0) {
|
|
122
|
-
await this.db.insert(chapters).values({
|
|
123
|
-
episodeId: episodeRecord[0].id,
|
|
124
|
-
number: record.chapter,
|
|
125
|
-
pov: record.pov,
|
|
126
|
-
title: record.title || `Chapter ${record.chapter}`,
|
|
127
|
-
summary: record.summary || '',
|
|
128
|
-
location: record.location || '',
|
|
129
|
-
filePath: record.filePath,
|
|
130
|
-
});
|
|
131
|
-
stats.chapters++;
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
return stats;
|
|
135
|
-
}
|
|
136
|
-
/**
|
|
137
|
-
* Get chapter ID from database for embedding insertion
|
|
138
|
-
*/
|
|
139
|
-
async getChapterId(timeline, arc, episode, chapter) {
|
|
140
|
-
const result = await this.db
|
|
141
|
-
.select({ id: chapters.id })
|
|
142
|
-
.from(chapters)
|
|
143
|
-
.innerJoin(episodes, eq(chapters.episodeId, episodes.id))
|
|
144
|
-
.innerJoin(arcs, eq(episodes.arcId, arcs.id))
|
|
145
|
-
.innerJoin(timelines, eq(arcs.timelineId, timelines.id))
|
|
146
|
-
.where(and(eq(timelines.name, timeline), eq(arcs.name, arc), eq(episodes.number, episode), eq(chapters.number, chapter)))
|
|
147
|
-
.limit(1);
|
|
148
|
-
return result.length > 0 ? result[0].id : null;
|
|
149
|
-
}
|
|
150
|
-
/**
|
|
151
|
-
* Clean up orphaned embeddings
|
|
152
|
-
*/
|
|
153
|
-
async cleanupEmbeddings() {
|
|
154
|
-
// This would require a more complex query to find orphaned embeddings
|
|
155
|
-
// For now, we'll implement a simple version
|
|
156
|
-
return 0;
|
|
157
|
-
}
|
|
158
|
-
}
|
package/src/rag/embeddings.d.ts
DELETED
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Embedding providers for GraphRAG
|
|
3
|
-
* Supports BGE-Base-v1.5, E5-Small-v2, and future models
|
|
4
|
-
*/
|
|
5
|
-
export interface EmbeddingProvider {
|
|
6
|
-
name: string;
|
|
7
|
-
dimension: number;
|
|
8
|
-
embed(texts: string[]): Promise<number[][]>;
|
|
9
|
-
embedSingle(text: string): Promise<number[]>;
|
|
10
|
-
}
|
|
11
|
-
export interface EmbeddingConfig {
|
|
12
|
-
provider: 'bge-base' | 'e5-small' | 'gemini';
|
|
13
|
-
batchSize?: number;
|
|
14
|
-
maxTokens?: number;
|
|
15
|
-
}
|
|
16
|
-
/**
|
|
17
|
-
* BGE-Base-v1.5 Embedding Provider
|
|
18
|
-
* Fast, accurate, 384-dimensional embeddings
|
|
19
|
-
*/
|
|
20
|
-
export declare class BGEBaseEmbedding implements EmbeddingProvider {
|
|
21
|
-
name: string;
|
|
22
|
-
dimension: number;
|
|
23
|
-
private batchSize;
|
|
24
|
-
private maxTokens;
|
|
25
|
-
constructor(config?: {
|
|
26
|
-
batchSize?: number;
|
|
27
|
-
maxTokens?: number;
|
|
28
|
-
});
|
|
29
|
-
embed(texts: string[]): Promise<number[][]>;
|
|
30
|
-
embedSingle(text: string): Promise<number[]>;
|
|
31
|
-
private generateContentAwareEmbedding;
|
|
32
|
-
}
|
|
33
|
-
/**
|
|
34
|
-
* E5-Small-v2 Embedding Provider
|
|
35
|
-
* Lightweight, fast, 384-dimensional embeddings for testing
|
|
36
|
-
*/
|
|
37
|
-
export declare class E5SmallEmbedding implements EmbeddingProvider {
|
|
38
|
-
name: string;
|
|
39
|
-
dimension: number;
|
|
40
|
-
private batchSize;
|
|
41
|
-
constructor(config?: {
|
|
42
|
-
batchSize?: number;
|
|
43
|
-
});
|
|
44
|
-
embed(texts: string[]): Promise<number[][]>;
|
|
45
|
-
embedSingle(text: string): Promise<number[]>;
|
|
46
|
-
private generateContentAwareEmbedding;
|
|
47
|
-
}
|
|
48
|
-
/**
|
|
49
|
-
* Gemini Embedding Provider
|
|
50
|
-
* State-of-the-art, requires API key
|
|
51
|
-
*/
|
|
52
|
-
export declare class GeminiEmbedding implements EmbeddingProvider {
|
|
53
|
-
name: string;
|
|
54
|
-
dimension: number;
|
|
55
|
-
constructor(apiKey: string);
|
|
56
|
-
embed(_texts: string[]): Promise<number[][]>;
|
|
57
|
-
embedSingle(text: string): Promise<number[]>;
|
|
58
|
-
}
|
|
59
|
-
/**
|
|
60
|
-
* Factory function to create embedding providers
|
|
61
|
-
*/
|
|
62
|
-
export declare function createEmbeddingProvider(config: EmbeddingConfig): EmbeddingProvider;
|
|
63
|
-
/**
|
|
64
|
-
* Calculate cosine similarity between two vectors
|
|
65
|
-
*/
|
|
66
|
-
export declare function cosineSimilarity(a: number[], b: number[]): number;
|
|
67
|
-
/**
|
|
68
|
-
* Normalize embedding vector to unit length
|
|
69
|
-
*/
|
|
70
|
-
export declare function normalizeEmbedding(embedding: number[]): number[];
|
|
71
|
-
/**
|
|
72
|
-
* Split array into batches of specified size
|
|
73
|
-
*/
|
|
74
|
-
export declare function batchArray<T>(array: T[], batchSize: number): T[][];
|
package/src/rag/embeddings.js
DELETED
|
@@ -1,164 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Embedding providers for GraphRAG
|
|
3
|
-
* Supports BGE-Base-v1.5, E5-Small-v2, and future models
|
|
4
|
-
*/
|
|
5
|
-
/**
|
|
6
|
-
* BGE-Base-v1.5 Embedding Provider
|
|
7
|
-
* Fast, accurate, 384-dimensional embeddings
|
|
8
|
-
*/
|
|
9
|
-
export class BGEBaseEmbedding {
|
|
10
|
-
name = 'bge-base-en-v1.5';
|
|
11
|
-
dimension = 384;
|
|
12
|
-
batchSize;
|
|
13
|
-
maxTokens;
|
|
14
|
-
constructor(config = {}) {
|
|
15
|
-
this.batchSize = config.batchSize || 32;
|
|
16
|
-
this.maxTokens = config.maxTokens || 512;
|
|
17
|
-
}
|
|
18
|
-
async embed(texts) {
|
|
19
|
-
// Create content-aware mock embeddings for more realistic similarity
|
|
20
|
-
return texts.map((text, index) => this.generateContentAwareEmbedding(text, index));
|
|
21
|
-
}
|
|
22
|
-
async embedSingle(text) {
|
|
23
|
-
return this.generateContentAwareEmbedding(text, 0);
|
|
24
|
-
}
|
|
25
|
-
generateContentAwareEmbedding(text, index) {
|
|
26
|
-
// Create embeddings based on text content for more realistic similarity
|
|
27
|
-
const words = text.toLowerCase().match(/\b\w+\b/g) || [];
|
|
28
|
-
const wordSet = new Set(words);
|
|
29
|
-
// Use text characteristics to create different embeddings
|
|
30
|
-
const textLength = text.length;
|
|
31
|
-
const uniqueWords = wordSet.size;
|
|
32
|
-
const avgWordLength = words.reduce((sum, word) => sum + word.length, 0) / words.length || 1;
|
|
33
|
-
// Create embedding with some structure based on content
|
|
34
|
-
const embedding = Array.from({ length: this.dimension }, (_, i) => {
|
|
35
|
-
// Base pattern from text characteristics
|
|
36
|
-
const base = Math.sin((textLength + i) * 0.01) * 0.2;
|
|
37
|
-
// Add word-based variation
|
|
38
|
-
const wordInfluence = Math.cos((uniqueWords + i) * 0.02) * 0.2;
|
|
39
|
-
// Add length-based variation
|
|
40
|
-
const lengthInfluence = Math.sin((avgWordLength + i) * 0.03) * 0.2;
|
|
41
|
-
// Add index-based variation to ensure uniqueness
|
|
42
|
-
const indexInfluence = Math.cos((index + i) * 0.05) * 0.3;
|
|
43
|
-
// Random noise (reduced)
|
|
44
|
-
const noise = (Math.random() - 0.5) * 0.1;
|
|
45
|
-
return base + wordInfluence + lengthInfluence + indexInfluence + noise;
|
|
46
|
-
});
|
|
47
|
-
// Normalize to unit vector
|
|
48
|
-
const norm = Math.sqrt(embedding.reduce((sum, val) => sum + val * val, 0));
|
|
49
|
-
return embedding.map((val) => val / norm);
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
/**
|
|
53
|
-
* E5-Small-v2 Embedding Provider
|
|
54
|
-
* Lightweight, fast, 384-dimensional embeddings for testing
|
|
55
|
-
*/
|
|
56
|
-
export class E5SmallEmbedding {
|
|
57
|
-
name = 'e5-small-v2';
|
|
58
|
-
dimension = 384;
|
|
59
|
-
batchSize;
|
|
60
|
-
constructor(config = {}) {
|
|
61
|
-
this.batchSize = config.batchSize || 64;
|
|
62
|
-
}
|
|
63
|
-
async embed(texts) {
|
|
64
|
-
return texts.map((text, index) => this.generateContentAwareEmbedding(text, index));
|
|
65
|
-
}
|
|
66
|
-
async embedSingle(text) {
|
|
67
|
-
return this.generateContentAwareEmbedding(text, 0);
|
|
68
|
-
}
|
|
69
|
-
generateContentAwareEmbedding(text, index) {
|
|
70
|
-
const words = text.toLowerCase().match(/\b\w+\b/g) || [];
|
|
71
|
-
const wordSet = new Set(words);
|
|
72
|
-
const textLength = text.length;
|
|
73
|
-
const uniqueWords = wordSet.size;
|
|
74
|
-
const avgWordLength = words.reduce((sum, word) => sum + word.length, 0) / words.length || 1;
|
|
75
|
-
const embedding = Array.from({ length: this.dimension }, (_, i) => {
|
|
76
|
-
const base = Math.sin((textLength + i) * 0.01) * 0.2;
|
|
77
|
-
const wordInfluence = Math.cos((uniqueWords + i) * 0.02) * 0.2;
|
|
78
|
-
const lengthInfluence = Math.sin((avgWordLength + i) * 0.03) * 0.2;
|
|
79
|
-
const indexInfluence = Math.cos((index + i) * 0.05) * 0.3;
|
|
80
|
-
const noise = (Math.random() - 0.5) * 0.1;
|
|
81
|
-
return base + wordInfluence + lengthInfluence + indexInfluence + noise;
|
|
82
|
-
});
|
|
83
|
-
const norm = Math.sqrt(embedding.reduce((sum, val) => sum + val * val, 0));
|
|
84
|
-
return embedding.map((val) => val / norm);
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
/**
|
|
88
|
-
* Gemini Embedding Provider
|
|
89
|
-
* State-of-the-art, requires API key
|
|
90
|
-
*/
|
|
91
|
-
export class GeminiEmbedding {
|
|
92
|
-
name = 'gemini-embedding';
|
|
93
|
-
dimension = 768; // Gemini embedding dimension
|
|
94
|
-
constructor(apiKey) {
|
|
95
|
-
// Store API key for future implementation
|
|
96
|
-
void apiKey;
|
|
97
|
-
}
|
|
98
|
-
async embed(_texts) {
|
|
99
|
-
// TODO: Implement Gemini API integration
|
|
100
|
-
throw new Error('Gemini embedding not yet implemented');
|
|
101
|
-
}
|
|
102
|
-
async embedSingle(text) {
|
|
103
|
-
const results = await this.embed([text]);
|
|
104
|
-
return results[0];
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
/**
|
|
108
|
-
* Factory function to create embedding providers
|
|
109
|
-
*/
|
|
110
|
-
export function createEmbeddingProvider(config) {
|
|
111
|
-
switch (config.provider) {
|
|
112
|
-
case 'bge-base':
|
|
113
|
-
return new BGEBaseEmbedding({
|
|
114
|
-
batchSize: config.batchSize,
|
|
115
|
-
maxTokens: config.maxTokens,
|
|
116
|
-
});
|
|
117
|
-
case 'e5-small':
|
|
118
|
-
return new E5SmallEmbedding({
|
|
119
|
-
batchSize: config.batchSize,
|
|
120
|
-
});
|
|
121
|
-
case 'gemini': {
|
|
122
|
-
const apiKey = process.env.ECHOES_GEMINI_API_KEY;
|
|
123
|
-
if (!apiKey) {
|
|
124
|
-
throw new Error('ECHOES_GEMINI_API_KEY environment variable required for Gemini provider');
|
|
125
|
-
}
|
|
126
|
-
return new GeminiEmbedding(apiKey);
|
|
127
|
-
}
|
|
128
|
-
default:
|
|
129
|
-
throw new Error(`Unknown embedding provider: ${config.provider}`);
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
/**
|
|
133
|
-
* Calculate cosine similarity between two vectors
|
|
134
|
-
*/
|
|
135
|
-
export function cosineSimilarity(a, b) {
|
|
136
|
-
if (a.length !== b.length)
|
|
137
|
-
return 0;
|
|
138
|
-
let dotProduct = 0;
|
|
139
|
-
let normA = 0;
|
|
140
|
-
let normB = 0;
|
|
141
|
-
for (let i = 0; i < a.length; i++) {
|
|
142
|
-
dotProduct += a[i] * b[i];
|
|
143
|
-
normA += a[i] * a[i];
|
|
144
|
-
normB += b[i] * b[i];
|
|
145
|
-
}
|
|
146
|
-
return dotProduct / (Math.sqrt(normA) * Math.sqrt(normB));
|
|
147
|
-
}
|
|
148
|
-
/**
|
|
149
|
-
* Normalize embedding vector to unit length
|
|
150
|
-
*/
|
|
151
|
-
export function normalizeEmbedding(embedding) {
|
|
152
|
-
const norm = Math.sqrt(embedding.reduce((sum, val) => sum + val * val, 0));
|
|
153
|
-
return embedding.map((val) => val / norm);
|
|
154
|
-
}
|
|
155
|
-
/**
|
|
156
|
-
* Split array into batches of specified size
|
|
157
|
-
*/
|
|
158
|
-
export function batchArray(array, batchSize) {
|
|
159
|
-
const batches = [];
|
|
160
|
-
for (let i = 0; i < array.length; i += batchSize) {
|
|
161
|
-
batches.push(array.slice(i, i + batchSize));
|
|
162
|
-
}
|
|
163
|
-
return batches;
|
|
164
|
-
}
|
package/src/rag/graph-rag.d.ts
DELETED
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* GraphRAG implementation for Echoes storytelling platform
|
|
3
|
-
* Based on Mastra.ai GraphRAG with adaptations for chapter relationships
|
|
4
|
-
*/
|
|
5
|
-
export type SupportedEdgeType = 'semantic' | 'character' | 'temporal' | 'location';
|
|
6
|
-
export interface GraphNode {
|
|
7
|
-
id: string;
|
|
8
|
-
content: string;
|
|
9
|
-
embedding?: number[];
|
|
10
|
-
metadata: {
|
|
11
|
-
chapterId: string;
|
|
12
|
-
arc: string;
|
|
13
|
-
episode: number;
|
|
14
|
-
chapter: number;
|
|
15
|
-
pov: string;
|
|
16
|
-
characters: string[];
|
|
17
|
-
location?: string;
|
|
18
|
-
[key: string]: unknown;
|
|
19
|
-
};
|
|
20
|
-
}
|
|
21
|
-
export interface RankedNode extends GraphNode {
|
|
22
|
-
score: number;
|
|
23
|
-
}
|
|
24
|
-
export interface GraphEdge {
|
|
25
|
-
source: string;
|
|
26
|
-
target: string;
|
|
27
|
-
weight: number;
|
|
28
|
-
type: SupportedEdgeType;
|
|
29
|
-
}
|
|
30
|
-
export interface GraphChunk {
|
|
31
|
-
text: string;
|
|
32
|
-
metadata: GraphNode['metadata'];
|
|
33
|
-
}
|
|
34
|
-
export interface GraphEmbedding {
|
|
35
|
-
vector: number[];
|
|
36
|
-
}
|
|
37
|
-
export declare class GraphRAG {
|
|
38
|
-
private nodes;
|
|
39
|
-
private edges;
|
|
40
|
-
private dimension;
|
|
41
|
-
private threshold;
|
|
42
|
-
constructor(dimension?: number, threshold?: number);
|
|
43
|
-
addNode(node: GraphNode): void;
|
|
44
|
-
addEdge(edge: GraphEdge): void;
|
|
45
|
-
getNodes(): GraphNode[];
|
|
46
|
-
getEdges(): GraphEdge[];
|
|
47
|
-
getEdgesByType(type: SupportedEdgeType): GraphEdge[];
|
|
48
|
-
clear(): void;
|
|
49
|
-
updateNodeContent(id: string, newContent: string): void;
|
|
50
|
-
private getNeighbors;
|
|
51
|
-
private cosineSimilarity;
|
|
52
|
-
createGraph(chunks: GraphChunk[], embeddings: GraphEmbedding[]): void;
|
|
53
|
-
private createSemanticEdges;
|
|
54
|
-
private createCharacterEdges;
|
|
55
|
-
private createTemporalEdges;
|
|
56
|
-
private createLocationEdges;
|
|
57
|
-
private selectWeightedNeighbor;
|
|
58
|
-
private randomWalkWithRestart;
|
|
59
|
-
query({ query, topK, randomWalkSteps, restartProb, characters, allCharacters, arc, pov, }: {
|
|
60
|
-
query: number[];
|
|
61
|
-
topK?: number;
|
|
62
|
-
randomWalkSteps?: number;
|
|
63
|
-
restartProb?: number;
|
|
64
|
-
characters?: string[];
|
|
65
|
-
allCharacters?: boolean;
|
|
66
|
-
arc?: string;
|
|
67
|
-
pov?: string;
|
|
68
|
-
}): RankedNode[];
|
|
69
|
-
}
|