1+ import * as path from 'path' ;
2+ import * as fs from 'fs' ;
3+ import { glob } from 'glob' ;
4+ import { ContextOptions , QueryOptions , QueryResult } from './types' ;
5+ import { TransformerVectorizer } from './vectorizer/transformer' ;
6+ import { ZVecStore } from './storage/zvec-store' ;
7+ import { Loader , MarkdownLoader , JsonLoader , TextLoader } from './loaders' ;
8+
9+ export class Context {
10+ private readonly vectorsDir : string ;
11+ private readonly model : string ;
12+ private readonly vectorizer : TransformerVectorizer ;
13+ private readonly stores : Map < string , ZVecStore > = new Map ( ) ;
14+ private readonly loaders : Loader [ ] ;
15+
16+ private constructor ( options : ContextOptions ) {
17+ this . vectorsDir = options . vectorsDir ;
18+ this . model = options . model || 'sentence-transformers/all-MiniLM-L6-v2' ;
19+ this . vectorizer = new TransformerVectorizer ( this . model ) ;
20+ this . loaders = [
21+ new MarkdownLoader ( ) ,
22+ new JsonLoader ( ) ,
23+ new TextLoader ( ) ,
24+ ] ;
25+ }
26+
27+ static async create ( options : ContextOptions ) : Promise < Context > {
28+ const ctx = new Context ( options ) ;
29+ await ctx . vectorizer . initialize ( ) ;
30+
31+ // Ensure vectors directory exists
32+ if ( ! fs . existsSync ( options . vectorsDir ) ) {
33+ fs . mkdirSync ( options . vectorsDir , { recursive : true } ) ;
34+ }
35+
36+ return ctx ;
37+ }
38+
39+ private getLoader ( filePath : string ) : Loader | undefined {
40+ return this . loaders . find ( ( loader ) => loader . canHandle ( filePath ) ) ;
41+ }
42+
43+ private getStoreFilePath ( library : string ) : string {
44+ return path . join ( this . vectorsDir , `${ library } .zvec` ) ;
45+ }
46+
47+ private async getOrCreateStore ( library : string ) : Promise < ZVecStore > {
48+ if ( this . stores . has ( library ) ) {
49+ return this . stores . get ( library ) ! ;
50+ }
51+
52+ const filePath = this . getStoreFilePath ( library ) ;
53+ const store = await ZVecStore . create ( filePath ) ;
54+
55+ this . stores . set ( library , store ) ;
56+ return store ;
57+ }
58+
59+ async load ( library : string , pattern : string | string [ ] ) : Promise < void > {
60+ const patterns = Array . isArray ( pattern ) ? pattern : [ pattern ] ;
61+ const files = await glob ( patterns , { absolute : true } ) ;
62+ const store = await this . getOrCreateStore ( library ) ;
63+
64+ for ( const filePath of files ) {
65+ const loader = this . getLoader ( filePath ) ;
66+ if ( ! loader ) continue ;
67+
68+ const doc = await loader . load ( filePath ) ;
69+ const vector = await this . vectorizer . embed ( doc . content ) ;
70+ store . add ( doc . id , vector , doc . content , doc . meta ) ;
71+ }
72+
73+ // Save to disk
74+ store . save ( ) ;
75+ }
76+
77+ async query ( text : string , options : QueryOptions ) : Promise < QueryResult [ ] > {
78+ const store = await this . getOrCreateStore ( options . library ) ;
79+ const vector = await this . vectorizer . embed ( text ) ;
80+ const searchResults = store . search ( vector , options . topK || 5 ) ;
81+
82+ return searchResults . map ( ( result ) => {
83+ const doc = store . getDoc ( result . id ) ! ;
84+ return {
85+ id : result . id ,
86+ content : doc . content ,
87+ score : result . score ,
88+ meta : doc . meta ,
89+ } ;
90+ } ) ;
91+ }
92+ }
0 commit comments