mirror of
https://github.com/abhigyanpatwari/GitNexus.git
synced 2026-11-01 07:02:35 +00:00
fix: dynamic embedding dimensions for HTTP backend
- schema.ts: FLOAT[${EMBEDDING_DIMS}] reads from GITNEXUS_EMBEDDING_DIMS env
- embedding-pipeline.ts: vector search CAST uses actual query vector length
- mcp/core/embedder.ts: HTTP embedding support for MCP query-time search
Without this, using a 1024d model (e.g. bge-large) fails with
'Expected: 384, Actual: 1024' on LadybugDB vector insert.
This commit is contained in:
parent
19dc236ace
commit
a67863563a
3 changed files with 28 additions and 4 deletions
|
|
@ -326,7 +326,7 @@ export const semanticSearch = async (
|
|||
// Query the vector index on CodeEmbedding to get nodeIds and distances
|
||||
const vectorQuery = `
|
||||
CALL QUERY_VECTOR_INDEX('CodeEmbedding', 'code_embedding_idx',
|
||||
CAST(${queryVecStr} AS FLOAT[384]), ${k})
|
||||
CAST(${queryVecStr} AS FLOAT[${queryVec.length}]), ${k})
|
||||
YIELD node AS emb, distance
|
||||
WITH emb, distance
|
||||
WHERE distance < ${maxDistance}
|
||||
|
|
|
|||
|
|
@ -398,10 +398,12 @@ CREATE REL TABLE ${REL_TABLE_NAME} (
|
|||
// Separate table for vector storage to avoid copy-on-write overhead
|
||||
// ============================================================================
|
||||
|
||||
export const EMBEDDING_DIMS = parseInt(process.env.GITNEXUS_EMBEDDING_DIMS ?? '384', 10);
|
||||
|
||||
export const EMBEDDING_SCHEMA = `
|
||||
CREATE NODE TABLE ${EMBEDDING_TABLE_NAME} (
|
||||
nodeId STRING,
|
||||
embedding FLOAT[384],
|
||||
embedding FLOAT[${EMBEDDING_DIMS}],
|
||||
PRIMARY KEY (nodeId)
|
||||
)`;
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,13 @@ import { pipeline, env, type FeatureExtractionPipeline } from '@huggingface/tran
|
|||
|
||||
// Model config
|
||||
const MODEL_ID = 'Snowflake/snowflake-arctic-embed-xs';
|
||||
const EMBEDDING_DIMS = 384;
|
||||
const EMBEDDING_DIMS = parseInt(process.env.GITNEXUS_EMBEDDING_DIMS ?? '384', 10);
|
||||
|
||||
// HTTP embedding config
|
||||
const HTTP_URL = process.env.GITNEXUS_EMBEDDING_URL ?? '';
|
||||
const HTTP_MODEL = process.env.GITNEXUS_EMBEDDING_MODEL ?? '';
|
||||
const HTTP_KEY = process.env.GITNEXUS_EMBEDDING_API_KEY ?? 'unused';
|
||||
const USE_HTTP = !!(HTTP_URL && HTTP_MODEL);
|
||||
|
||||
// Module-level state for singleton pattern
|
||||
let embedderInstance: FeatureExtractionPipeline | null = null;
|
||||
|
|
@ -20,6 +26,8 @@ let initPromise: Promise<FeatureExtractionPipeline> | null = null;
|
|||
* Initialize the embedding model (lazy, on first search)
|
||||
*/
|
||||
export const initEmbedder = async (): Promise<FeatureExtractionPipeline> => {
|
||||
if (USE_HTTP) return null as unknown as FeatureExtractionPipeline;
|
||||
|
||||
if (embedderInstance) {
|
||||
return embedderInstance;
|
||||
}
|
||||
|
|
@ -87,12 +95,26 @@ export const initEmbedder = async (): Promise<FeatureExtractionPipeline> => {
|
|||
/**
|
||||
* Check if embedder is ready
|
||||
*/
|
||||
export const isEmbedderReady = (): boolean => embedderInstance !== null;
|
||||
export const isEmbedderReady = (): boolean => USE_HTTP || embedderInstance !== null;
|
||||
|
||||
/**
|
||||
* Embed a query text for semantic search
|
||||
*/
|
||||
export const embedQuery = async (query: string): Promise<number[]> => {
|
||||
if (USE_HTTP) {
|
||||
const resp = await fetch(`${HTTP_URL.replace(/\/+$/, '')}/embeddings`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': `Bearer ${HTTP_KEY}`,
|
||||
},
|
||||
body: JSON.stringify({ input: [query], model: HTTP_MODEL }),
|
||||
});
|
||||
if (!resp.ok) throw new Error(`Embedding endpoint ${resp.status}`);
|
||||
const data = (await resp.json()) as { data: Array<{ embedding: number[] }> };
|
||||
return data.data[0].embedding;
|
||||
}
|
||||
|
||||
const embedder = await initEmbedder();
|
||||
|
||||
const result = await embedder(query, {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue