1- import { createHash } from 'crypto' ;
2- import { env } from '../config' ;
3- import { q } from '../database' ;
4- import { SECTOR_CONFIGS } from '../hsg' ;
5- import { addSynonymTokens , canonicalTokensFromText } from '../utils/text' ;
1+ import { env } from '../config'
2+ import { getModel } from '../config/models'
3+ import { SECTOR_CONFIGS } from '../hsg'
4+ import { q } from '../database'
5+ import { canonicalTokensFromText , addSynonymTokens } from '../utils/text'
66
77let geminiQueue : Promise < any > = Promise . resolve ( )
88
@@ -19,20 +19,13 @@ export async function embedForSector(t: string, s: string): Promise<number[]> {
1919 }
2020}
2121
22- const MOD : Record < string , string > = {
23- episodic : 'text-embedding-3-small' ,
24- semantic : 'text-embedding-3-small' ,
25- procedural : 'text-embedding-3-small' ,
26- emotional : 'text-embedding-3-small' ,
27- reflective : 'text-embedding-3-large'
28- }
29-
3022async function embedWithOpenAI ( t : string , s : string ) : Promise < number [ ] > {
3123 if ( ! env . openai_key ) throw new Error ( 'OpenAI key missing' )
24+ const model = getModel ( s , 'openai' )
3225 const r = await fetch ( `${ env . openai_base_url . replace ( / \/ $ / , '' ) } /embeddings` , {
3326 method : 'POST' ,
3427 headers : { 'content-type' : 'application/json' , 'authorization' : `Bearer ${ env . openai_key } ` } ,
35- body : JSON . stringify ( { input : t , model : env . openai_model || MOD [ s ] || MOD . semantic , dimensions : env . vec_dim } )
28+ body : JSON . stringify ( { input : t , model : env . openai_model || model , dimensions : env . vec_dim } )
3629 } )
3730 if ( ! r . ok ) throw new Error ( `OpenAI: ${ r . status } ` )
3831 return ( ( await r . json ( ) ) as any ) . data [ 0 ] . embedding
@@ -41,10 +34,11 @@ async function embedWithOpenAI(t: string, s: string): Promise<number[]> {
4134async function embedBatchOpenAI ( texts : Record < string , string > ) : Promise < Record < string , number [ ] > > {
4235 if ( ! env . openai_key ) throw new Error ( 'OpenAI key missing' )
4336 const sectors = Object . keys ( texts )
37+ const model = getModel ( 'semantic' , 'openai' )
4438 const r = await fetch ( `${ env . openai_base_url . replace ( / \/ $ / , '' ) } /embeddings` , {
4539 method : 'POST' ,
4640 headers : { 'content-type' : 'application/json' , 'authorization' : `Bearer ${ env . openai_key } ` } ,
47- body : JSON . stringify ( { input : Object . values ( texts ) , model : env . openai_model || MOD . semantic , dimensions : env . vec_dim } )
41+ body : JSON . stringify ( { input : Object . values ( texts ) , model : env . openai_model || model , dimensions : env . vec_dim } )
4842 } )
4943 if ( ! r . ok ) throw new Error ( `OpenAI batch: ${ r . status } ` )
5044 const d = ( await r . json ( ) ) as any
@@ -107,19 +101,12 @@ async function embedWithGemini(texts: Record<string, string>): Promise<Record<st
107101 return promise
108102}
109103
110- const OMOD : Record < string , string > = {
111- episodic : 'nomic-embed-text' ,
112- semantic : 'nomic-embed-text' ,
113- procedural : 'bge-small' ,
114- emotional : 'nomic-embed-text' ,
115- reflective : 'bge-large'
116- }
117-
118104async function embedWithOllama ( t : string , s : string ) : Promise < number [ ] > {
105+ const model = getModel ( s , 'ollama' )
119106 const r = await fetch ( `${ env . ollama_url } /api/embeddings` , {
120107 method : 'POST' ,
121108 headers : { 'content-type' : 'application/json' } ,
122- body : JSON . stringify ( { model : OMOD [ s ] || OMOD . semantic , prompt : t } )
109+ body : JSON . stringify ( { model, prompt : t } )
123110 } )
124111 if ( ! r . ok ) throw new Error ( `Ollama: ${ r . status } ` )
125112 return resizeVector ( ( ( await r . json ( ) ) as any ) . embedding , env . vec_dim )
@@ -131,38 +118,21 @@ async function embedWithLocal(t: string, s: string): Promise<number[]> {
131118 return generateSyntheticEmbedding ( t , s )
132119 }
133120 try {
134- const hash = createHash ( 'sha256' ) . update ( t , 'utf8' ) . update ( s , 'utf8' ) . digest ( ) ;
135- const dim = env . vec_dim ;
136- const e = new Array < number > ( dim ) ;
137- const HLEN = 32 ;
138-
139- let i = 0 ;
140- for ( let idx = 0 ; idx < dim ; idx ++ ) {
141- const b1 = hash [ i ] ;
142- i = ( i + 1 ) % HLEN ;
143- const b2 = hash [ i ] ;
144- e [ idx ] = ( b1 * 256 + b2 ) / 65535 * 2 - 1 ;
145- }
146-
147- let sumSquares = 0 ;
148- for ( let idx = 0 ; idx < dim ; idx ++ ) {
149- const v = e [ idx ] ;
150- sumSquares += v * v ;
151- }
152- const norm = Math . sqrt ( sumSquares ) ;
153-
154- for ( let idx = 0 ; idx < dim ; idx ++ ) {
155- e [ idx ] /= norm ;
121+ const { createHash } = await import ( 'crypto' )
122+ const h = createHash ( 'sha256' ) . update ( t + s ) . digest ( )
123+ const e : number [ ] = [ ]
124+ for ( let i = 0 ; i < env . vec_dim ; i ++ ) {
125+ const b1 = h [ i % h . length ]
126+ const b2 = h [ ( i + 1 ) % h . length ]
127+ e . push ( ( b1 * 256 + b2 ) / 65535 * 2 - 1 )
156128 }
157-
158- return e ;
129+ const n = Math . sqrt ( e . reduce ( ( sum , v ) => sum + v * v , 0 ) )
130+ return e . map ( v => v / n )
159131 } catch {
160132 console . warn ( 'Local embedding failed, using synthetic' )
161133 return generateSyntheticEmbedding ( t , s )
162134 }
163- }
164-
165- const hash = ( v : string ) => {
135+ } const hash = ( v : string ) => {
166136 let h = 0x811c9dc5 | 0 ;
167137 const len = v . length | 0 ;
168138 for ( let i = 0 ; i < len ; i ++ ) {
@@ -329,15 +299,15 @@ export const getEmbeddingInfo = () => {
329299 i . base_url = env . openai_base_url
330300 i . model_override = env . openai_model || null
331301 i . batch_api = env . embed_mode === 'simple'
332- i . models = MOD
302+ i . models = { episodic : getModel ( 'episodic' , 'openai' ) , semantic : getModel ( 'semantic' , 'openai' ) , procedural : getModel ( 'procedural' , 'openai' ) , emotional : getModel ( 'emotional' , 'openai' ) , reflective : getModel ( 'reflective' , 'openai' ) }
333303 } else if ( env . emb_kind === 'gemini' ) {
334304 i . configured = ! ! env . gemini_key
335305 i . batch_api = env . embed_mode === 'simple'
336306 i . model = 'embedding-001'
337307 } else if ( env . emb_kind === 'ollama' ) {
338308 i . configured = true
339309 i . url = env . ollama_url
340- i . models = OMOD
310+ i . models = { episodic : getModel ( 'episodic' , 'ollama' ) , semantic : getModel ( 'semantic' , 'ollama' ) , procedural : getModel ( 'procedural' , 'ollama' ) , emotional : getModel ( 'emotional' , 'ollama' ) , reflective : getModel ( 'reflective' , 'ollama' ) }
341311 } else if ( env . emb_kind === 'local' ) {
342312 i . configured = ! ! env . local_model_path
343313 i . path = env . local_model_path
0 commit comments