2025-05-23 10:55:20 -07:00
|
|
|
/**
|
|
|
|
|
* Embedding functions for converting data to vectors
|
|
|
|
|
*/
|
|
|
|
|
|
2025-05-29 08:27:59 -07:00
|
|
|
import { EmbeddingFunction, EmbeddingModel, Vector } from '../coreTypes.ts'
|
2025-05-23 10:55:20 -07:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Simple character-based embedding function
|
|
|
|
|
* This is a very basic implementation for demo purposes
|
|
|
|
|
*/
|
|
|
|
|
export class SimpleEmbedding implements EmbeddingModel {
|
|
|
|
|
private initialized = false
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Initialize the embedding model
|
|
|
|
|
*/
|
|
|
|
|
public async init(): Promise<void> {
|
|
|
|
|
this.initialized = true
|
|
|
|
|
return Promise.resolve()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Embed text into a vector using character frequencies
|
|
|
|
|
* @param data Text to embed
|
|
|
|
|
*/
|
|
|
|
|
public async embed(data: string): Promise<Vector> {
|
|
|
|
|
if (!this.initialized) {
|
|
|
|
|
await this.init()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Only handle string data
|
|
|
|
|
if (typeof data !== 'string') {
|
|
|
|
|
throw new Error('SimpleEmbedding only supports string data')
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Normalize the text
|
|
|
|
|
const normalizedText = data.toLowerCase().trim()
|
|
|
|
|
|
|
|
|
|
// Create a simple 4-dimensional vector based on character frequencies
|
|
|
|
|
const vector: Vector = [0, 0, 0, 0]
|
|
|
|
|
|
|
|
|
|
// Count vowels, consonants, numbers, and special characters
|
|
|
|
|
for (let i = 0; i < normalizedText.length; i++) {
|
|
|
|
|
const char = normalizedText[i]
|
|
|
|
|
if ('aeiou'.includes(char)) {
|
|
|
|
|
vector[0] += 0.1 // Vowels affect first dimension
|
|
|
|
|
} else if ('bcdfghjklmnpqrstvwxyz'.includes(char)) {
|
|
|
|
|
vector[1] += 0.1 // Consonants affect second dimension
|
|
|
|
|
} else if ('0123456789'.includes(char)) {
|
|
|
|
|
vector[2] += 0.1 // Numbers affect third dimension
|
|
|
|
|
} else {
|
|
|
|
|
vector[3] += 0.1 // Special chars affect fourth dimension
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Normalize the vector
|
|
|
|
|
const magnitude = Math.sqrt(
|
|
|
|
|
vector.reduce((sum, val) => sum + val * val, 0)
|
|
|
|
|
)
|
|
|
|
|
if (magnitude > 0) {
|
|
|
|
|
return vector.map((val) => val / magnitude)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return vector
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Dispose of the model resources
|
|
|
|
|
*/
|
|
|
|
|
public async dispose(): Promise<void> {
|
|
|
|
|
this.initialized = false
|
|
|
|
|
return Promise.resolve()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* TensorFlow Universal Sentence Encoder embedding model
|
2025-05-27 15:11:12 -07:00
|
|
|
* This model provides high-quality text embeddings using TensorFlow.js
|
|
|
|
|
* The required TensorFlow.js dependencies are automatically installed with this package
|
2025-05-23 10:55:20 -07:00
|
|
|
*/
|
|
|
|
|
export class UniversalSentenceEncoder implements EmbeddingModel {
|
|
|
|
|
private model: any = null
|
|
|
|
|
private initialized = false
|
|
|
|
|
private tf: any = null
|
|
|
|
|
private use: any = null
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Initialize the embedding model
|
|
|
|
|
*/
|
|
|
|
|
public async init(): Promise<void> {
|
|
|
|
|
try {
|
|
|
|
|
// Dynamically import TensorFlow.js and Universal Sentence Encoder
|
|
|
|
|
// Use type assertions to tell TypeScript these modules exist
|
2025-05-27 15:42:38 -07:00
|
|
|
this.tf = await import('@tensorflow/tfjs')
|
|
|
|
|
this.use = await import('@tensorflow-models/universal-sentence-encoder')
|
2025-05-23 10:55:20 -07:00
|
|
|
|
|
|
|
|
// Load the model
|
|
|
|
|
this.model = await this.use.load()
|
|
|
|
|
this.initialized = true
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error('Failed to initialize Universal Sentence Encoder:', error)
|
2025-05-27 15:11:12 -07:00
|
|
|
throw new Error(
|
|
|
|
|
`Failed to initialize Universal Sentence Encoder: ${error}`
|
|
|
|
|
)
|
2025-05-23 10:55:20 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Embed text into a vector using Universal Sentence Encoder
|
|
|
|
|
* @param data Text to embed
|
|
|
|
|
*/
|
|
|
|
|
public async embed(data: string | string[]): Promise<Vector> {
|
|
|
|
|
if (!this.initialized) {
|
|
|
|
|
await this.init()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
// Handle different input types
|
|
|
|
|
let textToEmbed: string[]
|
|
|
|
|
if (typeof data === 'string') {
|
|
|
|
|
textToEmbed = [data]
|
|
|
|
|
} else if (Array.isArray(data) && data.every(item => typeof item === 'string')) {
|
|
|
|
|
textToEmbed = data
|
|
|
|
|
} else {
|
|
|
|
|
throw new Error('UniversalSentenceEncoder only supports string or string[] data')
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Get embeddings
|
|
|
|
|
const embeddings = await this.model.embed(textToEmbed)
|
|
|
|
|
|
|
|
|
|
// Convert to array and return the first embedding
|
|
|
|
|
const embeddingArray = await embeddings.array()
|
|
|
|
|
return embeddingArray[0]
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error('Failed to embed text with Universal Sentence Encoder:', error)
|
|
|
|
|
throw new Error(`Failed to embed text with Universal Sentence Encoder: ${error}`)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Dispose of the model resources
|
|
|
|
|
*/
|
|
|
|
|
public async dispose(): Promise<void> {
|
|
|
|
|
if (this.model && this.tf) {
|
|
|
|
|
try {
|
|
|
|
|
// Dispose of the model and tensors
|
|
|
|
|
this.model.dispose()
|
|
|
|
|
this.tf.disposeVariables()
|
|
|
|
|
this.initialized = false
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error('Failed to dispose Universal Sentence Encoder:', error)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return Promise.resolve()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Create an embedding function from an embedding model
|
|
|
|
|
* @param model Embedding model to use
|
|
|
|
|
*/
|
|
|
|
|
export function createEmbeddingFunction(model: EmbeddingModel): EmbeddingFunction {
|
|
|
|
|
return async (data: any): Promise<Vector> => {
|
|
|
|
|
return await model.embed(data)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-05-27 15:11:12 -07:00
|
|
|
/**
|
|
|
|
|
* Creates a TensorFlow-based Universal Sentence Encoder embedding function
|
|
|
|
|
* This is the recommended embedding function for high-quality text embeddings
|
|
|
|
|
*/
|
|
|
|
|
export function createTensorFlowEmbeddingFunction(): EmbeddingFunction {
|
|
|
|
|
return createEmbeddingFunction(new UniversalSentenceEncoder())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Simple embedding function using character-based embedding
|
|
|
|
|
* This is a basic implementation that doesn't use TensorFlow
|
|
|
|
|
*/
|
|
|
|
|
export function createSimpleEmbeddingFunction(): EmbeddingFunction {
|
|
|
|
|
return createEmbeddingFunction(new SimpleEmbedding())
|
|
|
|
|
}
|
|
|
|
|
|
2025-05-23 10:55:20 -07:00
|
|
|
/**
|
|
|
|
|
* Default embedding function using UniversalSentenceEncoder
|
2025-05-27 15:11:12 -07:00
|
|
|
* This provides high-quality text embeddings using TensorFlow.js
|
2025-05-23 10:55:20 -07:00
|
|
|
*/
|
2025-05-27 15:11:12 -07:00
|
|
|
export const defaultEmbeddingFunction: EmbeddingFunction = createTensorFlowEmbeddingFunction()
|