From 062964c75555f4cc2836929b97bd2ffb3c565623 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EC=9A=A9=EC=84=B1?= <66245186+kys0213@users.noreply.github.com> Date: Sun, 21 Sep 2025 16:24:33 +0900 Subject: [PATCH] feat: improve EmbeddingGemma bridge --- .../embeddinggemma-embedding-bridge/README.md | 79 +++ .../package.json | 54 ++ .../__tests__/embeddinggemma-bridge.test.ts | 242 +++++++ .../src/bridge/embeddinggemma-bridge.ts | 349 ++++++++++ .../src/bridge/embeddinggemma-config.ts | 36 ++ .../src/bridge/embeddinggemma-factory.ts | 7 + .../src/bridge/embeddinggemma-manifest.ts | 20 + .../src/index.ts | 20 + .../tsconfig.esm.json | 9 + .../tsconfig.json | 16 + .../vitest.config.ts | 13 + pnpm-lock.yaml | 599 ++++++++++++++++++ 12 files changed, 1444 insertions(+) create mode 100644 packages/embeddinggemma-embedding-bridge/README.md create mode 100644 packages/embeddinggemma-embedding-bridge/package.json create mode 100644 packages/embeddinggemma-embedding-bridge/src/__tests__/embeddinggemma-bridge.test.ts create mode 100644 packages/embeddinggemma-embedding-bridge/src/bridge/embeddinggemma-bridge.ts create mode 100644 packages/embeddinggemma-embedding-bridge/src/bridge/embeddinggemma-config.ts create mode 100644 packages/embeddinggemma-embedding-bridge/src/bridge/embeddinggemma-factory.ts create mode 100644 packages/embeddinggemma-embedding-bridge/src/bridge/embeddinggemma-manifest.ts create mode 100644 packages/embeddinggemma-embedding-bridge/src/index.ts create mode 100644 packages/embeddinggemma-embedding-bridge/tsconfig.esm.json create mode 100644 packages/embeddinggemma-embedding-bridge/tsconfig.json create mode 100644 packages/embeddinggemma-embedding-bridge/vitest.config.ts diff --git a/packages/embeddinggemma-embedding-bridge/README.md b/packages/embeddinggemma-embedding-bridge/README.md new file mode 100644 index 0000000..983f191 --- /dev/null +++ b/packages/embeddinggemma-embedding-bridge/README.md @@ -0,0 +1,79 @@ +# EmbeddingGemma Embedding Bridge + +Google의 온디바이스 임베딩 모델인 **EmbeddingGemma**를 `@xenova/transformers` 런타임 위에서 사용할 수 있도록 감싼 브릿지 패키지입니다. + +## 설치 + +```bash +pnpm add embeddinggemma-embedding-bridge @xenova/transformers +``` + +## 빠른 시작 + +```ts +import { createEmbeddingGemmaBridge } from 'embeddinggemma-embedding-bridge'; + +const bridge = createEmbeddingGemmaBridge(); +const { embeddings } = await bridge.embed({ input: '안녕하세요' }); + +console.log('embedding length:', embeddings.length); +``` + +## 구성 옵션 + +`createEmbeddingGemmaBridge` 혹은 생성자에 전달되는 설정은 모두 선택 사항이며, 필요한 부분만 오버라이드할 수 있습니다. + +```ts +const bridge = createEmbeddingGemmaBridge({ + model: 'google/embedding-gemma-002', + pipeline: { + revision: 'main', + quantized: true, + cacheDir: '/models/gemma', + localFilesOnly: true, + device: 'gpu', + }, + embedding: { + pooling: 'cls', + normalize: false, + batchSize: 4, + }, +}); +``` + +### 일반 옵션 + +- `model` – 로드할 Hugging Face 모델 ID. 기본값은 `google/embedding-gemma-002` 입니다. + +### `pipeline` + +`@xenova/transformers`의 `pipeline` 생성 시 전달되는 옵션입니다. + +- `revision` – 모델 리비전 지정 +- `quantized` – 양자화된 체크포인트 사용 여부 +- `cacheDir` – 모델 다운로드/캐시 경로 (`cache_dir`) +- `localFilesOnly` – 오프라인 캐시만 사용할지 여부 (`local_files_only`) +- `progressCallback` – 모델 로딩 진행률 콜백 +- `device` – 실행 디바이스 (`'cpu'`, `'gpu'`, 숫자 인덱스 등 지원) +- `dtype` – 가중치 데이터 타입 (예: `'fp16'`) +- `executionProviders` – ONNX Runtime 실행 프로바이더 목록 + +### `embedding` + +실제 임베딩 계산 시 파이프라인 호출에 전달되는 옵션입니다. + +- `pooling` – `'mean' | 'max' | 'cls'` (기본값 `'mean'`) +- `normalize` – L2 정규화 여부 (기본값 `true`) +- `batchSize` – 배치 처리 크기 (`batch_size`) + +## 동작 특성 + +- 입력은 문자열 또는 `contentType: 'text'` 인 멀티모달 콘텐츠만 지원합니다. +- 파이프라인에서 반환된 텐서를 자동으로 평탄화하여 `number[]` 혹은 `number[][]` 형태로 제공합니다. +- `getMetadata()`는 모델 설정의 hidden size를 추정하여 임베딩 차원을 알려줍니다. + +## 테스트 + +```bash +pnpm --filter embeddinggemma-embedding-bridge test:ci +``` diff --git a/packages/embeddinggemma-embedding-bridge/package.json b/packages/embeddinggemma-embedding-bridge/package.json new file mode 100644 index 0000000..2a2c687 --- /dev/null +++ b/packages/embeddinggemma-embedding-bridge/package.json @@ -0,0 +1,54 @@ +{ + "name": "embeddinggemma-embedding-bridge", + "version": "0.0.1", + "description": "EmbeddingGemma Embedding Bridge", + "main": "./dist/index.js", + "module": "./esm/index.js", + "types": "./dist/index.d.ts", + "exports": { + ".": { + "import": "./esm/index.js", + "require": "./dist/index.js", + "types": "./dist/index.d.ts" + } + }, + "files": [ + "dist", + "esm", + "README.md" + ], + "sideEffects": false, + "scripts": { + "build": "pnpm clean && tsc -p tsconfig.json && tsc -p tsconfig.esm.json", + "dev": "tsc -p tsconfig.json", + "test": "vitest run", + "test:ci": "vitest run --exclude='src/**/*.e2e.test.ts'", + "test:watch": "vitest", + "test:coverage": "vitest run --coverage", + "lint": "eslint src --ext .ts", + "lint:fix": "eslint src --ext .ts --fix", + "clean": "rm -rf dist && rm -rf esm" + }, + "dependencies": {}, + "devDependencies": { + "embedding-bridge-spec": "workspace:*", + "llm-bridge-spec": "workspace:*", + "@xenova/transformers": "^2.17.2", + "zod": "^4.0.5", + "@types/node": "^20.11.24", + "@typescript-eslint/eslint-plugin": "^7.1.0", + "@typescript-eslint/parser": "^7.1.0", + "@vitest/coverage-v8": "^1.0.0", + "eslint": "^8.57.0", + "rimraf": "^5.0.5", + "typescript": "^5.0.0", + "vitest": "^1.0.0", + "vitest-mock-extended": "^3.1.0" + }, + "peerDependencies": { + "embedding-bridge-spec": "workspace:*", + "llm-bridge-spec": "workspace:*", + "@xenova/transformers": "^2.17.2", + "zod": "^4.0.5" + } +} diff --git a/packages/embeddinggemma-embedding-bridge/src/__tests__/embeddinggemma-bridge.test.ts b/packages/embeddinggemma-embedding-bridge/src/__tests__/embeddinggemma-bridge.test.ts new file mode 100644 index 0000000..7dce56a --- /dev/null +++ b/packages/embeddinggemma-embedding-bridge/src/__tests__/embeddinggemma-bridge.test.ts @@ -0,0 +1,242 @@ +import type { MultiModalContent } from 'llm-bridge-spec'; +import { beforeEach, describe, expect, it, vi } from 'vitest'; +import { EmbeddingGemmaBridge } from '../bridge/embeddinggemma-bridge'; +import { createEmbeddingGemmaBridge } from '../bridge/embeddinggemma-factory'; + +const { pipelineSpy } = vi.hoisted(() => ({ + pipelineSpy: vi.fn(), +})); + +vi.mock('@xenova/transformers', () => ({ + pipeline: pipelineSpy, +})); + +interface TensorMockOptions { + configHiddenSize?: number | null; + modelHiddenSize?: number; +} + +const createTensor = (values: number[], dims?: number[]) => ({ + data: Float32Array.from(values), + dims, +}); + +function setupPipelineMock(returnValue: unknown, options: TensorMockOptions = {}) { + const { configHiddenSize, modelHiddenSize } = options; + const pipelineInstance = vi.fn(async () => returnValue); + const dims = + returnValue && + typeof returnValue === 'object' && + 'dims' in (returnValue as Record) + ? ((returnValue as { dims?: number[] }).dims ?? undefined) + : undefined; + + const inferredDimension = Array.isArray(dims) && dims.length > 0 ? dims.at(-1) : undefined; + const hasConfigOverride = Object.prototype.hasOwnProperty.call(options, 'configHiddenSize'); + const configValue = hasConfigOverride ? configHiddenSize : (inferredDimension ?? 2); + + const config: Record = {}; + if (typeof configValue === 'number') { + config.hidden_size = configValue; + } + + const modelConfig: Record = {}; + const resolvedModelSize = + typeof modelHiddenSize === 'number' + ? modelHiddenSize + : typeof configValue === 'number' + ? configValue + : (inferredDimension ?? 2); + modelConfig.hidden_size = resolvedModelSize; + + Object.assign(pipelineInstance, { + config, + model: { config: modelConfig }, + }); + + pipelineSpy.mockResolvedValue(pipelineInstance); + return pipelineInstance; +} + +function expectVectorCloseTo(actual: number[], expected: number[]) { + expect(actual).toHaveLength(expected.length); + expected.forEach((value, index) => { + expect(actual[index]).toBeCloseTo(value, 6); + }); +} + +function isNumberArray(value: unknown): value is number[] { + return Array.isArray(value) && value.every(item => typeof item === 'number'); +} + +function isNumberMatrix(value: unknown): value is number[][] { + return Array.isArray(value) && value.every(isNumberArray); +} + +function expectEmbeddingVector(actual: number[] | number[][], expected: number[]) { + expect(isNumberArray(actual)).toBe(true); + if (!isNumberArray(actual)) { + throw new Error('Expected embedding vector'); + } + expectVectorCloseTo(actual, expected); +} + +function expectEmbeddingMatrix(actual: number[] | number[][], expected: number[][]) { + expect(isNumberMatrix(actual)).toBe(true); + if (!isNumberMatrix(actual)) { + throw new Error('Expected embedding matrix'); + } + expect(actual).toHaveLength(expected.length); + actual.forEach((row, index) => { + expectVectorCloseTo(row, expected[index]); + }); +} + +describe('EmbeddingGemmaBridge', () => { + beforeEach(() => { + pipelineSpy.mockReset(); + }); + + it('should create embedding for text input', async () => { + const pipelineInstance = setupPipelineMock(createTensor([0.1, 0.2], [2])); + const bridge = new EmbeddingGemmaBridge(); + + const res = await bridge.embed({ input: 'hello' }); + + expectEmbeddingVector(res.embeddings, [0.1, 0.2]); + expect(pipelineSpy).toHaveBeenCalledWith( + 'feature-extraction', + 'google/embedding-gemma-002', + undefined + ); + expect(pipelineInstance).toHaveBeenCalledWith('hello', { pooling: 'mean', normalize: true }); + }); + + it('should support array input and return batched embeddings', async () => { + const pipelineInstance = setupPipelineMock(createTensor([0.1, 0.2, 0.3, 0.4], [2, 2])); + const bridge = new EmbeddingGemmaBridge(); + + const res = await bridge.embed({ input: ['a', 'b'] }); + + expectEmbeddingMatrix(res.embeddings, [ + [0.1, 0.2], + [0.3, 0.4], + ]); + expect(pipelineInstance).toHaveBeenCalledWith(['a', 'b'], { pooling: 'mean', normalize: true }); + }); + + it('should convert multimodal text input to string', async () => { + const pipelineInstance = setupPipelineMock(createTensor([0.2, -0.1], [2])); + const bridge = new EmbeddingGemmaBridge(); + + await bridge.embed({ input: { contentType: 'text', value: 'multi' } }); + + expect(pipelineInstance).toHaveBeenCalledWith('multi', { pooling: 'mean', normalize: true }); + }); + + it('should reject non-text multimodal content', async () => { + const bridge = new EmbeddingGemmaBridge(); + + const imageContent: MultiModalContent = { contentType: 'image', value: Buffer.from('') }; + + await expect(bridge.embed({ input: imageContent })).rejects.toThrow( + 'Only text content is supported for embeddings' + ); + expect(pipelineSpy).not.toHaveBeenCalled(); + }); + + it('should reject empty input arrays', async () => { + const bridge = new EmbeddingGemmaBridge(); + + await expect(bridge.embed({ input: [] })).rejects.toThrow( + 'Embedding request must include at least one input item.' + ); + expect(pipelineSpy).not.toHaveBeenCalled(); + }); + + it('should apply pipeline and embedding configuration overrides', async () => { + const pipelineInstance = setupPipelineMock(createTensor([0.1, 0.2, 0.3, 0.4], [2, 2])); + const bridge = new EmbeddingGemmaBridge({ + pipeline: { + cacheDir: '/tmp/cache', + localFilesOnly: true, + quantized: true, + revision: 'main', + device: 'gpu', + dtype: 'fp16', + executionProviders: ['cpu'], + }, + embedding: { + pooling: 'cls', + normalize: false, + batchSize: 8, + }, + }); + + const res = await bridge.embed({ input: ['a', 'b'] }); + + expectEmbeddingMatrix(res.embeddings, [ + [0.1, 0.2], + [0.3, 0.4], + ]); + expect(pipelineSpy).toHaveBeenCalledWith( + 'feature-extraction', + 'google/embedding-gemma-002', + expect.objectContaining({ + cache_dir: '/tmp/cache', + local_files_only: true, + quantized: true, + revision: 'main', + device: 'gpu', + dtype: 'fp16', + execution_providers: ['cpu'], + }) + ); + expect(pipelineInstance).toHaveBeenCalledWith(['a', 'b'], { + pooling: 'cls', + normalize: false, + batch_size: 8, + }); + }); + + it('should derive metadata dimension from model config before embedding', async () => { + const pipelineInstance = setupPipelineMock(createTensor([0.1, 0.2], [2]), { + configHiddenSize: null, + modelHiddenSize: 768, + }); + const bridge = new EmbeddingGemmaBridge(); + + const metadata = await bridge.getMetadata(); + + expect(metadata).toEqual({ model: 'google/embedding-gemma-002', dimension: 768 }); + expect(pipelineInstance).not.toHaveBeenCalled(); + }); + + it('factory should accept empty configuration', async () => { + const pipelineInstance = setupPipelineMock(createTensor([0.3, 0.7], [2])); + const bridge = createEmbeddingGemmaBridge(); + + const res = await bridge.embed({ input: 'factory' }); + + expectEmbeddingVector(res.embeddings, [0.3, 0.7]); + expect(pipelineInstance).toHaveBeenCalledWith('factory', { pooling: 'mean', normalize: true }); + }); + + it('should surface errors for malformed batched pipeline output', async () => { + setupPipelineMock([0.1, 0.2]); + const bridge = new EmbeddingGemmaBridge(); + + await expect(bridge.embed({ input: ['a', 'b'] })).rejects.toThrow( + 'Expected batched embeddings but received a single vector from the pipeline.' + ); + }); + + it('should surface errors when tensor output length mismatches batch size', async () => { + setupPipelineMock(createTensor([0.1, 0.2, 0.3], [2, 2])); + const bridge = new EmbeddingGemmaBridge(); + + await expect(bridge.embed({ input: ['x', 'y'] })).rejects.toThrow( + 'Unexpected pipeline output length for the provided input batch.' + ); + }); +}); diff --git a/packages/embeddinggemma-embedding-bridge/src/bridge/embeddinggemma-bridge.ts b/packages/embeddinggemma-embedding-bridge/src/bridge/embeddinggemma-bridge.ts new file mode 100644 index 0000000..b308833 --- /dev/null +++ b/packages/embeddinggemma-embedding-bridge/src/bridge/embeddinggemma-bridge.ts @@ -0,0 +1,349 @@ +import { pipeline } from '@xenova/transformers'; +import { + EmbeddingBridge, + EmbeddingModelMetadata, + EmbeddingRequest, + EmbeddingResponse, +} from 'embedding-bridge-spec'; +import type { MultiModalContent } from 'llm-bridge-spec'; +import { + EmbeddingGemmaConfig, + EmbeddingGemmaConfigSchema, + EmbeddingGemmaEmbeddingOptions, + EmbeddingGemmaPipelineConfig, +} from './embeddinggemma-config'; + +const DEFAULT_MODEL = 'google/embedding-gemma-002'; + +type PipelineRunner = (input: string | string[], options?: Record) => Promise; + +type FeatureExtractionPipeline = PipelineRunner & { + config?: unknown; + model?: { config?: unknown } | unknown; +}; + +interface TensorLike { + data: ArrayLike; + dims?: number[]; + tolist?: () => unknown; +} + +interface ResolvedEmbeddingOptions { + pooling: NonNullable; + normalize: boolean; + batchSize?: number; +} + +function contentToString(content: MultiModalContent): string { + if (content.contentType !== 'text') { + throw new Error( + `Only text content is supported for embeddings (received "${content.contentType}").` + ); + } + return content.value; +} + +function isTensorLike(value: unknown): value is TensorLike { + if (!value || typeof value !== 'object') { + return false; + } + if (!('data' in value)) { + return false; + } + const data = (value as { data: unknown }).data; + return Array.isArray(data) || ArrayBuffer.isView(data); +} + +function toNumberArray(source: ArrayLike | Iterable): number[] { + return Array.from(source); +} + +type NumericArrayBufferView = + | Int8Array + | Uint8Array + | Uint8ClampedArray + | Int16Array + | Uint16Array + | Int32Array + | Uint32Array + | Float32Array + | Float64Array; + +function isNumericArrayBufferView(value: ArrayBufferView): value is NumericArrayBufferView { + return 'length' in value && typeof (value as { length: unknown }).length === 'number' && 'BYTES_PER_ELEMENT' in value; +} + +export class EmbeddingGemmaBridge implements EmbeddingBridge { + private readonly modelId: string; + private readonly pipelineOptions: EmbeddingGemmaPipelineConfig; + private readonly embeddingOptions: ResolvedEmbeddingOptions; + private pipelinePromise?: Promise; + private dimension?: number; + + constructor(config?: EmbeddingGemmaConfig) { + const parsed = EmbeddingGemmaConfigSchema.parse(config ?? {}); + this.modelId = parsed.model ?? DEFAULT_MODEL; + this.pipelineOptions = parsed.pipeline ?? {}; + this.embeddingOptions = { + pooling: parsed.embedding?.pooling ?? 'mean', + normalize: parsed.embedding?.normalize ?? true, + batchSize: parsed.embedding?.batchSize, + }; + } + + private normalizeSingleInput(value: string | MultiModalContent): string { + return typeof value === 'string' ? value : contentToString(value); + } + + private normalizeInput(input: EmbeddingRequest['input']): string | string[] { + if (Array.isArray(input)) { + if (input.length === 0) { + throw new Error('Embedding request must include at least one input item.'); + } + return input.map(item => this.normalizeSingleInput(item)); + } + return this.normalizeSingleInput(input); + } + + private buildPipelineOptions(): Record | undefined { + const options: Record = {}; + const config = this.pipelineOptions; + + if (typeof config.revision === 'string') { + options.revision = config.revision; + } + if (typeof config.quantized === 'boolean') { + options.quantized = config.quantized; + } + if (typeof config.cacheDir === 'string') { + options.cache_dir = config.cacheDir; + } + if (typeof config.localFilesOnly === 'boolean') { + options.local_files_only = config.localFilesOnly; + } + if (typeof config.progressCallback === 'function') { + options.progress_callback = config.progressCallback; + } + if (config.device !== undefined) { + options.device = config.device; + } + if (typeof config.dtype === 'string') { + options.dtype = config.dtype; + } + if (Array.isArray(config.executionProviders) && config.executionProviders.length > 0) { + options.execution_providers = config.executionProviders; + } + + return Object.keys(options).length > 0 ? options : undefined; + } + + private createEmbeddingCallOptions(): Record { + const options: Record = { + pooling: this.embeddingOptions.pooling, + normalize: this.embeddingOptions.normalize, + }; + + if (typeof this.embeddingOptions.batchSize === 'number') { + options.batch_size = this.embeddingOptions.batchSize; + } + + return options; + } + + private async getPipeline(): Promise { + if (!this.pipelinePromise) { + this.pipelinePromise = pipeline( + 'feature-extraction', + this.modelId, + this.buildPipelineOptions() + ) as Promise; + } + return this.pipelinePromise; + } + + private updateDimension(length: number | undefined) { + if (typeof length === 'number' && Number.isFinite(length) && length > 0) { + this.dimension = length; + } + } + + private tensorToEmbeddings(tensor: TensorLike, inputCount: number): number[] | number[][] { + const dims = Array.isArray(tensor.dims) ? tensor.dims : []; + + if (dims.length > 2) { + throw new Error( + 'Received tensor output with more than two dimensions. Configure embedding.pooling (e.g. "mean") to obtain fixed-size embeddings.' + ); + } + + const data = toNumberArray(tensor.data); + + if (inputCount <= 1 || (dims.length > 0 && dims[0] === 1)) { + const vectorLength = + dims.length > 1 ? dims.slice(1).reduce((acc, value) => acc * value, 1) : data.length; + const vector = data.slice(0, vectorLength); + this.updateDimension(vector.length); + return vector; + } + + const batchSize = dims[0] ?? inputCount; + const vectorLength = + dims.length > 1 + ? dims.slice(1).reduce((acc, value) => acc * value, 1) + : Math.floor(data.length / batchSize); + + if (!Number.isFinite(vectorLength) || vectorLength <= 0) { + throw new Error('Unable to determine embedding dimension from pipeline output.'); + } + + if (data.length !== vectorLength * batchSize) { + throw new Error('Unexpected pipeline output length for the provided input batch.'); + } + + const embeddings: number[][] = []; + for (let i = 0; i < batchSize; i += 1) { + const start = i * vectorLength; + const end = start + vectorLength; + embeddings.push(data.slice(start, end)); + } + + this.updateDimension(vectorLength); + return embeddings; + } + + private ensureNumberArray(value: unknown): number[] { + if (Array.isArray(value)) { + return value.map(item => { + if (typeof item !== 'number' || Number.isNaN(item)) { + throw new Error('Expected numeric embedding values from pipeline output.'); + } + return item; + }); + } + if (ArrayBuffer.isView(value) && isNumericArrayBufferView(value)) { + return toNumberArray(value); + } + throw new Error('Unsupported embedding value type from pipeline output.'); + } + + private parseEmbeddings(result: unknown, inputCount: number): number[] | number[][] { + if (isTensorLike(result)) { + return this.tensorToEmbeddings(result, inputCount); + } + + if (Array.isArray(result)) { + if (result.length === 0) { + return inputCount > 1 ? [] : []; + } + + if (typeof result[0] === 'number') { + const vector = this.ensureNumberArray(result); + if (inputCount > 1) { + throw new Error( + 'Expected batched embeddings but received a single vector from the pipeline.' + ); + } + this.updateDimension(vector.length); + return vector; + } + + if (isTensorLike(result[0])) { + const tensors = result as TensorLike[]; + const embeddings = tensors.map(tensor => this.tensorToEmbeddings(tensor, 1) as number[]); + if (inputCount <= 1 && embeddings.length === 1) { + const vector = embeddings[0]; + this.updateDimension(vector.length); + return vector; + } + this.updateDimension(embeddings[0]?.length ?? this.dimension ?? 0); + return embeddings; + } + + if (Array.isArray(result[0]) || ArrayBuffer.isView(result[0])) { + const embeddings = (result as unknown[]).map(item => this.ensureNumberArray(item)); + if (inputCount <= 1 && embeddings.length === 1) { + const vector = embeddings[0]; + this.updateDimension(vector.length); + return vector; + } + this.updateDimension(embeddings[0]?.length ?? this.dimension ?? 0); + return embeddings; + } + } + + throw new Error('Unsupported pipeline output format for EmbeddingGemma embeddings.'); + } + + private extractDimension(source: unknown, visited = new Set()): number | undefined { + if (!source || typeof source !== 'object' || visited.has(source)) { + return undefined; + } + + visited.add(source); + + const record = source as Record; + const candidateKeys = [ + 'hidden_size', + 'embedding_dim', + 'projection_dim', + 'output_dim', + 'dim', + 'd_model', + ]; + + for (const key of candidateKeys) { + const value = record[key]; + if (typeof value === 'number' && Number.isFinite(value) && value > 0) { + return value; + } + } + + for (const value of Object.values(record)) { + if (typeof value === 'object' && value !== null) { + const nested = this.extractDimension(value, visited); + if (typeof nested === 'number') { + return nested; + } + } + } + + return undefined; + } + + private ensureDimensionFromModel(pipe: FeatureExtractionPipeline): void { + if (this.dimension) { + return; + } + + const possibleSources: unknown[] = [ + (pipe as { config?: unknown }).config, + (pipe as { model?: unknown }).model, + (pipe as { model?: { config?: unknown } }).model?.config, + ]; + + for (const source of possibleSources) { + const value = this.extractDimension(source); + if (typeof value === 'number') { + this.dimension = value; + return; + } + } + } + + async embed(request: EmbeddingRequest): Promise { + const normalizedInput = this.normalizeInput(request.input); + const pipe = await this.getPipeline(); + const result = await pipe(normalizedInput, this.createEmbeddingCallOptions()); + const embeddings = this.parseEmbeddings( + result, + Array.isArray(request.input) ? request.input.length : 1 + ); + return { embeddings }; + } + + async getMetadata(): Promise { + const pipe = await this.getPipeline(); + this.ensureDimensionFromModel(pipe); + return { model: this.modelId, dimension: this.dimension ?? 0 }; + } +} diff --git a/packages/embeddinggemma-embedding-bridge/src/bridge/embeddinggemma-config.ts b/packages/embeddinggemma-embedding-bridge/src/bridge/embeddinggemma-config.ts new file mode 100644 index 0000000..851e7a7 --- /dev/null +++ b/packages/embeddinggemma-embedding-bridge/src/bridge/embeddinggemma-config.ts @@ -0,0 +1,36 @@ +import { z } from 'zod'; + +const ProgressCallbackSchema = z.custom<(...args: unknown[]) => void>(); + +const PipelineConfigSchema = z + .object({ + revision: z.string().optional(), + quantized: z.boolean().optional(), + cacheDir: z.string().optional(), + localFilesOnly: z.boolean().optional(), + progressCallback: ProgressCallbackSchema.optional(), + device: z.union([z.string(), z.number()]).optional(), + dtype: z.string().optional(), + executionProviders: z.array(z.string()).optional(), + }) + .partial(); + +const EmbeddingOptionsSchema = z + .object({ + pooling: z.enum(['mean', 'max', 'cls']).optional(), + normalize: z.boolean().optional(), + batchSize: z.number().int().positive().optional(), + }) + .partial(); + +export const EmbeddingGemmaConfigSchema = z + .object({ + model: z.string().optional(), + pipeline: PipelineConfigSchema.optional(), + embedding: EmbeddingOptionsSchema.optional(), + }) + .default({}); + +export type EmbeddingGemmaConfig = z.infer; +export type EmbeddingGemmaPipelineConfig = z.infer; +export type EmbeddingGemmaEmbeddingOptions = z.infer; diff --git a/packages/embeddinggemma-embedding-bridge/src/bridge/embeddinggemma-factory.ts b/packages/embeddinggemma-embedding-bridge/src/bridge/embeddinggemma-factory.ts new file mode 100644 index 0000000..a0738d4 --- /dev/null +++ b/packages/embeddinggemma-embedding-bridge/src/bridge/embeddinggemma-factory.ts @@ -0,0 +1,7 @@ +import { EmbeddingGemmaBridge } from './embeddinggemma-bridge'; +import { EmbeddingGemmaConfig, EmbeddingGemmaConfigSchema } from './embeddinggemma-config'; + +export function createEmbeddingGemmaBridge(config?: EmbeddingGemmaConfig): EmbeddingGemmaBridge { + EmbeddingGemmaConfigSchema.parse(config ?? {}); + return new EmbeddingGemmaBridge(config); +} diff --git a/packages/embeddinggemma-embedding-bridge/src/bridge/embeddinggemma-manifest.ts b/packages/embeddinggemma-embedding-bridge/src/bridge/embeddinggemma-manifest.ts new file mode 100644 index 0000000..45adae2 --- /dev/null +++ b/packages/embeddinggemma-embedding-bridge/src/bridge/embeddinggemma-manifest.ts @@ -0,0 +1,20 @@ +import { EmbeddingGemmaConfigSchema } from './embeddinggemma-config'; +import { z } from 'zod'; + +export interface EmbeddingManifest { + schemaVersion: string; + name: string; + language: string; + entry: string; + configSchema: z.ZodTypeAny; + description?: string; +} + +export const EMBEDDINGGEMMA_MANIFEST: EmbeddingManifest = { + schemaVersion: '1.0.0', + name: 'embeddinggemma-embedding-bridge', + language: 'typescript', + entry: 'src/bridge/embeddinggemma-bridge.ts', + configSchema: EmbeddingGemmaConfigSchema, + description: 'Google EmbeddingGemma model bridge', +}; diff --git a/packages/embeddinggemma-embedding-bridge/src/index.ts b/packages/embeddinggemma-embedding-bridge/src/index.ts new file mode 100644 index 0000000..1e194f9 --- /dev/null +++ b/packages/embeddinggemma-embedding-bridge/src/index.ts @@ -0,0 +1,20 @@ +import { EmbeddingGemmaBridge } from './bridge/embeddinggemma-bridge'; +import { createEmbeddingGemmaBridge } from './bridge/embeddinggemma-factory'; +import { EMBEDDINGGEMMA_MANIFEST } from './bridge/embeddinggemma-manifest'; + +export default class EmbeddingGemmaBridgePackage extends EmbeddingGemmaBridge { + // eslint-disable-next-line @typescript-eslint/no-useless-constructor + constructor(...args: ConstructorParameters) { + super(...args); + } + + static create = createEmbeddingGemmaBridge; + static manifest = () => EMBEDDINGGEMMA_MANIFEST; +} + +export { EmbeddingGemmaBridge, createEmbeddingGemmaBridge, EMBEDDINGGEMMA_MANIFEST }; +export type { + EmbeddingGemmaConfig, + EmbeddingGemmaEmbeddingOptions, + EmbeddingGemmaPipelineConfig, +} from './bridge/embeddinggemma-config'; diff --git a/packages/embeddinggemma-embedding-bridge/tsconfig.esm.json b/packages/embeddinggemma-embedding-bridge/tsconfig.esm.json new file mode 100644 index 0000000..5975a67 --- /dev/null +++ b/packages/embeddinggemma-embedding-bridge/tsconfig.esm.json @@ -0,0 +1,9 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "module": "ESNext", + "moduleResolution": "node", + "outDir": "./esm", + "target": "ES2020" + } +} diff --git a/packages/embeddinggemma-embedding-bridge/tsconfig.json b/packages/embeddinggemma-embedding-bridge/tsconfig.json new file mode 100644 index 0000000..2f3d892 --- /dev/null +++ b/packages/embeddinggemma-embedding-bridge/tsconfig.json @@ -0,0 +1,16 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "./dist", + "rootDir": "./src", + "composite": true, + "tsBuildInfoFile": "./dist/.tsbuildinfo", + "declaration": true, + "declarationMap": true, + "module": "CommonJS", + "moduleResolution": "node", + "target": "ES2020" + }, + "include": ["src/**/*.ts"], + "exclude": ["node_modules", "dist", "esm"] +} diff --git a/packages/embeddinggemma-embedding-bridge/vitest.config.ts b/packages/embeddinggemma-embedding-bridge/vitest.config.ts new file mode 100644 index 0000000..40c8129 --- /dev/null +++ b/packages/embeddinggemma-embedding-bridge/vitest.config.ts @@ -0,0 +1,13 @@ +import { defineConfig } from 'vitest/config'; + +export default defineConfig({ + test: { + globals: true, + environment: 'node', + include: ['src/**/*.test.ts'], + coverage: { + reporter: ['text', 'json', 'html'], + exclude: ['node_modules/', 'dist/'], + }, + }, +}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3049b25..143baaa 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -144,6 +144,48 @@ importers: specifier: ^1.3.1 version: 1.6.1(@types/node@20.17.31) + packages/embeddinggemma-embedding-bridge: + devDependencies: + '@types/node': + specifier: ^20.11.24 + version: 20.17.31 + '@typescript-eslint/eslint-plugin': + specifier: ^7.1.0 + version: 7.18.0(@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1)(typescript@5.8.3) + '@typescript-eslint/parser': + specifier: ^7.1.0 + version: 7.18.0(eslint@8.57.1)(typescript@5.8.3) + '@vitest/coverage-v8': + specifier: ^1.0.0 + version: 1.6.1(vitest@1.6.1(@types/node@20.17.31)) + '@xenova/transformers': + specifier: ^2.17.2 + version: 2.17.2 + embedding-bridge-spec: + specifier: workspace:* + version: link:../embedding-bridge-spec + eslint: + specifier: ^8.57.0 + version: 8.57.1 + llm-bridge-spec: + specifier: workspace:* + version: link:../llm-bridge-spec + rimraf: + specifier: ^5.0.5 + version: 5.0.10 + typescript: + specifier: ^5.0.0 + version: 5.8.3 + vitest: + specifier: ^1.0.0 + version: 1.6.1(@types/node@20.17.31) + vitest-mock-extended: + specifier: ^3.1.0 + version: 3.1.0(typescript@5.8.3)(vitest@1.6.1(@types/node@20.17.31)) + zod: + specifier: ^4.0.5 + version: 4.0.5 + packages/llm-bridge-loader: devDependencies: '@types/node': @@ -678,6 +720,10 @@ packages: resolution: {integrity: sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + '@huggingface/jinja@0.2.2': + resolution: {integrity: sha512-/KPde26khDUIPkTGU82jdtTW9UAuvUTumCAbFs/7giR0SxsvZC4hru51PBvpijH6BVkHcROcvZM/lpy5h1jRRA==} + engines: {node: '>=18'} + '@humanwhocodes/config-array@0.13.0': resolution: {integrity: sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==} engines: {node: '>=10.10.0'} @@ -741,6 +787,36 @@ packages: resolution: {integrity: sha512-ROFF39F6ZrnzSUEmQQZUar0Jt4xVoP9WnDRdWwF4NNcXs3xBTLgBUDoOwW141y1jP+S8nahIbdxbFC7IShw9Iw==} engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} + '@protobufjs/aspromise@1.1.2': + resolution: {integrity: sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==} + + '@protobufjs/base64@1.1.2': + resolution: {integrity: sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==} + + '@protobufjs/codegen@2.0.4': + resolution: {integrity: sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==} + + '@protobufjs/eventemitter@1.1.0': + resolution: {integrity: sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==} + + '@protobufjs/fetch@1.1.0': + resolution: {integrity: sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==} + + '@protobufjs/float@1.0.2': + resolution: {integrity: sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==} + + '@protobufjs/inquire@1.1.0': + resolution: {integrity: sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==} + + '@protobufjs/path@1.1.2': + resolution: {integrity: sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==} + + '@protobufjs/pool@1.1.0': + resolution: {integrity: sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==} + + '@protobufjs/utf8@1.1.0': + resolution: {integrity: sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==} + '@rollup/rollup-android-arm-eabi@4.40.0': resolution: {integrity: sha512-+Fbls/diZ0RDerhE8kyC6hjADCXA1K4yVNlH0EYfd2XjyH0UGgzaQ8MlT0pCXAThfxv3QUAczHaL+qSv1E4/Cg==} cpu: [arm] @@ -1035,6 +1111,9 @@ packages: '@types/estree@1.0.7': resolution: {integrity: sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==} + '@types/long@4.0.2': + resolution: {integrity: sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==} + '@types/node-fetch@2.6.12': resolution: {integrity: sha512-8nneRWKCg3rMtF69nLQJnOYUcbafYeFSjqkw3jCRLsqkWFlHaoQrr5mXmofFGOx3DKn7UfmBMyov8ySvLRVldA==} @@ -1128,6 +1207,9 @@ packages: '@vitest/utils@1.6.1': resolution: {integrity: sha512-jOrrUvXM4Av9ZWiG1EajNto0u96kWAhJ1LmPmJhXXQx/32MecEKd10pOLYgS2BQx1TgkGhloPU1ArDW2vvaY6g==} + '@xenova/transformers@2.17.2': + resolution: {integrity: sha512-lZmHqzrVIkSvZdKZEx7IYY51TK0WDrC8eR0c5IMnBsO8di8are1zzw8BlLhyO2TklZKLN5UffNGs1IJwT6oOqQ==} + abort-controller@3.0.0: resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==} engines: {node: '>=6.5'} @@ -1190,9 +1272,56 @@ packages: asynckit@0.4.0: resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + b4a@1.7.1: + resolution: {integrity: sha512-ZovbrBV0g6JxK5cGUF1Suby1vLfKjv4RWi8IxoaO/Mon8BDD9I21RxjHFtgQ+kskJqLAVyQZly3uMBui+vhc8Q==} + peerDependencies: + react-native-b4a: '*' + peerDependenciesMeta: + react-native-b4a: + optional: true + balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + bare-events@2.6.1: + resolution: {integrity: sha512-AuTJkq9XmE6Vk0FJVNq5QxETrSA/vKHarWVBG5l/JbdCL1prJemiyJqUS0jrlXO0MftuPq4m3YVYhoNc5+aE/g==} + + bare-fs@4.4.4: + resolution: {integrity: sha512-Q8yxM1eLhJfuM7KXVP3zjhBvtMJCYRByoTT+wHXjpdMELv0xICFJX+1w4c7csa+WZEOsq4ItJ4RGwvzid6m/dw==} + engines: {bare: '>=1.16.0'} + peerDependencies: + bare-buffer: '*' + peerDependenciesMeta: + bare-buffer: + optional: true + + bare-os@3.6.2: + resolution: {integrity: sha512-T+V1+1srU2qYNBmJCXZkUY5vQ0B4FSlL3QDROnKQYOqeiQR8UbjNHlPa+TIbM4cuidiN9GaTaOZgSEgsvPbh5A==} + engines: {bare: '>=1.14.0'} + + bare-path@3.0.0: + resolution: {integrity: sha512-tyfW2cQcB5NN8Saijrhqn0Zh7AnFNsnczRcuWODH0eYAXBsJ5gVxAUuNr7tsHSC6IZ77cA0SitzT+s47kot8Mw==} + + bare-stream@2.7.0: + resolution: {integrity: sha512-oyXQNicV1y8nc2aKffH+BUHFRXmx6VrPzlnaEvMhram0nPBrKcEdcyBg5r08D0i8VxngHFAiVyn1QKXpSG0B8A==} + peerDependencies: + bare-buffer: '*' + bare-events: '*' + peerDependenciesMeta: + bare-buffer: + optional: true + bare-events: + optional: true + + bare-url@2.2.2: + resolution: {integrity: sha512-g+ueNGKkrjMazDG3elZO1pNs3HY5+mMmOet1jtKyhOaCnkLzitxf26z7hoAEkDNgdNmnc1KIlt/dw6Po6xZMpA==} + + base64-js@1.5.1: + resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + + bl@4.1.0: + resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} + bowser@2.11.0: resolution: {integrity: sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==} @@ -1206,6 +1335,9 @@ packages: resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} engines: {node: '>=8'} + buffer@5.7.1: + resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} + cac@6.7.14: resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} engines: {node: '>=8'} @@ -1233,6 +1365,9 @@ packages: check-error@1.0.3: resolution: {integrity: sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==} + chownr@1.1.4: + resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==} + cli-cursor@5.0.0: resolution: {integrity: sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==} engines: {node: '>=18'} @@ -1248,6 +1383,13 @@ packages: color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + color-string@1.9.1: + resolution: {integrity: sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==} + + color@4.2.3: + resolution: {integrity: sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==} + engines: {node: '>=12.5.0'} + colorette@2.0.20: resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} @@ -1278,10 +1420,18 @@ packages: supports-color: optional: true + decompress-response@6.0.0: + resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==} + engines: {node: '>=10'} + deep-eql@4.1.4: resolution: {integrity: sha512-SUwdGfqdKOwxCPeVYjwSyRpJ7Z+fhpwIAtmCUdZIWZ/YP5R9WAsyuSgpLVDi9bjWoN2LXHNss/dk3urXtdQxGg==} engines: {node: '>=6'} + deep-extend@0.6.0: + resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==} + engines: {node: '>=4.0.0'} + deep-is@0.1.4: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} @@ -1289,6 +1439,10 @@ packages: resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} engines: {node: '>=0.4.0'} + detect-libc@2.0.4: + resolution: {integrity: sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==} + engines: {node: '>=8'} + diff-sequences@29.6.3: resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -1317,6 +1471,9 @@ packages: emoji-regex@9.2.2: resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + end-of-stream@1.4.5: + resolution: {integrity: sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==} + environment@1.1.0: resolution: {integrity: sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==} engines: {node: '>=18'} @@ -1414,12 +1571,19 @@ packages: resolution: {integrity: sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==} engines: {node: '>=16.17'} + expand-template@2.0.3: + resolution: {integrity: sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==} + engines: {node: '>=6'} + fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} fast-diff@1.3.0: resolution: {integrity: sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==} + fast-fifo@1.3.2: + resolution: {integrity: sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==} + fast-glob@3.3.3: resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} engines: {node: '>=8.6.0'} @@ -1453,6 +1617,9 @@ packages: resolution: {integrity: sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==} engines: {node: ^10.12.0 || >=12.0.0} + flatbuffers@1.12.0: + resolution: {integrity: sha512-c7CZADjRcl6j0PlvFy0ZqXQ67qSEZfrVPynmnL+2zPc+NtMvrF8Y0QceMo7QqnSPc7+uWjUIAbvCQ5WIKlMVdQ==} + flatted@3.3.3: resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==} @@ -1471,6 +1638,9 @@ packages: resolution: {integrity: sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ==} engines: {node: '>= 12.20'} + fs-constants@1.0.0: + resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==} + fs.realpath@1.0.0: resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} @@ -1501,6 +1671,9 @@ packages: resolution: {integrity: sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==} engines: {node: '>=16'} + github-from-package@0.0.0: + resolution: {integrity: sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==} + glob-parent@5.1.2: resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} engines: {node: '>= 6'} @@ -1532,6 +1705,9 @@ packages: graphemer@1.4.0: resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} + guid-typescript@1.0.9: + resolution: {integrity: sha512-Y8T4vYhEfwJOTbouREvG+3XDsjr8E3kIr7uf+JZ0BYloFsttiHU0WfvANVsR7TxNUJa/WpCnw/Ino/p+DeBhBQ==} + has-flag@4.0.0: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} engines: {node: '>=8'} @@ -1563,6 +1739,9 @@ packages: engines: {node: '>=14'} hasBin: true + ieee754@1.2.1: + resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} + ignore@5.3.2: resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} engines: {node: '>= 4'} @@ -1582,6 +1761,12 @@ packages: inherits@2.0.4: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + ini@1.3.8: + resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} + + is-arrayish@0.3.2: + resolution: {integrity: sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==} + is-extglob@2.1.1: resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} engines: {node: '>=0.10.0'} @@ -1687,6 +1872,9 @@ packages: resolution: {integrity: sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==} engines: {node: '>=18'} + long@4.0.0: + resolution: {integrity: sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==} + loupe@2.3.7: resolution: {integrity: sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==} @@ -1734,6 +1922,10 @@ packages: resolution: {integrity: sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==} engines: {node: '>=18'} + mimic-response@3.1.0: + resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==} + engines: {node: '>=10'} + minimatch@3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} @@ -1741,10 +1933,16 @@ packages: resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} engines: {node: '>=16 || 14 >=14.17'} + minimist@1.2.8: + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + minipass@7.1.2: resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} engines: {node: '>=16 || 14 >=14.17'} + mkdirp-classic@0.5.3: + resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==} + mlly@1.7.4: resolution: {integrity: sha512-qmdSIPC4bDJXgZTCR7XosJiNKySV7O215tsPtDN9iEO/7q/76b/ijtgRu/+epFXSJhijtTCCGp3DWS549P3xKw==} @@ -1756,9 +1954,19 @@ packages: engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true + napi-build-utils@2.0.0: + resolution: {integrity: sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA==} + natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + node-abi@3.77.0: + resolution: {integrity: sha512-DSmt0OEcLoK4i3NuscSbGjOf3bqiDEutejqENSplMSFA/gmB8mkED9G4pKWnPl7MDU4rSHebKPHeitpDfyH0cQ==} + engines: {node: '>=10'} + + node-addon-api@6.1.0: + resolution: {integrity: sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==} + node-domexception@1.0.0: resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==} engines: {node: '>=10.5.0'} @@ -1791,6 +1999,19 @@ packages: resolution: {integrity: sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==} engines: {node: '>=18'} + onnx-proto@4.0.4: + resolution: {integrity: sha512-aldMOB3HRoo6q/phyB6QRQxSt895HNNw82BNyZ2CMh4bjeKv7g/c+VpAFtJuEMVfYLMbRx61hbuqnKceLeDcDA==} + + onnxruntime-common@1.14.0: + resolution: {integrity: sha512-3LJpegM2iMNRX2wUmtYfeX/ytfOzNwAWKSq1HbRrKc9+uqG/FsEA0bbKZl1btQeZaXhC26l44NWpNUeXPII7Ew==} + + onnxruntime-node@1.14.0: + resolution: {integrity: sha512-5ba7TWomIV/9b6NH/1x/8QEeowsb+jBEvFzU6z0T4mNsFwdPqXeFUM7uxC6QeSRkEbWu3qEB0VMjrvzN/0S9+w==} + os: [win32, darwin, linux] + + onnxruntime-web@1.14.0: + resolution: {integrity: sha512-Kcqf43UMfW8mCydVGcX9OMXI2VN17c0p6XvR7IPSZzBf/6lteBzXHvcEVWDPmCKuGombl997HgLqj91F11DzXw==} + openai@4.96.0: resolution: {integrity: sha512-dKoW56i02Prv2XQolJ9Rl9Svqubqkzg3QpwEOBuSVZLk05Shelu7s+ErRTwFc1Bs3JZ2qBqBfVpXQiJhwOGG8A==} hasBin: true @@ -1874,10 +2095,18 @@ packages: pkg-types@1.3.1: resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==} + platform@1.3.6: + resolution: {integrity: sha512-fnWVljUchTro6RiCFvCXBbNhJc2NijN7oIQxbwsyL0buWJPG85v81ehlHI9fXrJsMNgTofEoWIQeClKpgxFLrg==} + postcss@8.5.3: resolution: {integrity: sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==} engines: {node: ^10 || ^12 || >=14} + prebuild-install@7.1.3: + resolution: {integrity: sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==} + engines: {node: '>=10'} + hasBin: true + prelude-ls@1.2.1: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} engines: {node: '>= 0.8.0'} @@ -1895,6 +2124,13 @@ packages: resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + protobufjs@6.11.4: + resolution: {integrity: sha512-5kQWPaJHi1WoCpjTGszzQ32PG2F4+wRY6BmAT4Vfw56Q2FZ4YZzK20xUYQH4YkfehY1e6QSICrJquM6xXZNcrw==} + hasBin: true + + pump@3.0.3: + resolution: {integrity: sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==} + punycode@2.3.1: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} @@ -1902,9 +2138,17 @@ packages: queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + rc@1.2.8: + resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==} + hasBin: true + react-is@18.3.1: resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} + readable-stream@3.6.2: + resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} + engines: {node: '>= 6'} + resolve-from@4.0.0: resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} engines: {node: '>=4'} @@ -1937,11 +2181,18 @@ packages: run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + semver@7.7.1: resolution: {integrity: sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==} engines: {node: '>=10'} hasBin: true + sharp@0.32.6: + resolution: {integrity: sha512-KyLTWwgcR9Oe4d9HwCwNM2l7+J0dUQwn/yf7S0EnTtb0eVS4RxO0eUSvxPtzT4F3SY+C4K6fqdv/DO27sJ/v/w==} + engines: {node: '>=14.15.0'} + shebang-command@2.0.0: resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} engines: {node: '>=8'} @@ -1957,6 +2208,15 @@ packages: resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} engines: {node: '>=14'} + simple-concat@1.0.1: + resolution: {integrity: sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==} + + simple-get@4.0.1: + resolution: {integrity: sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==} + + simple-swizzle@0.2.2: + resolution: {integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==} + slash@3.0.0: resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} engines: {node: '>=8'} @@ -1979,6 +2239,9 @@ packages: std-env@3.9.0: resolution: {integrity: sha512-UGvjygr6F6tpH7o2qyqR6QYpwraIjKSdtzyBdyytFOHmPZY917kwdwLG0RbOjWOnKmnm3PeHjaoLLMie7kPLQw==} + streamx@2.22.1: + resolution: {integrity: sha512-znKXEBxfatz2GBNK02kRnCXjV+AA4kjZIUxeWSr3UGirZMJfTE9uiwKHobnbgxWyL/JWro8tTq+vOqAK1/qbSA==} + string-argv@0.3.2: resolution: {integrity: sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==} engines: {node: '>=0.6.19'} @@ -1995,6 +2258,9 @@ packages: resolution: {integrity: sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==} engines: {node: '>=18'} + string_decoder@1.3.0: + resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} + strip-ansi@6.0.1: resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} engines: {node: '>=8'} @@ -2007,6 +2273,10 @@ packages: resolution: {integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==} engines: {node: '>=12'} + strip-json-comments@2.0.1: + resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==} + engines: {node: '>=0.10.0'} + strip-json-comments@3.1.1: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} @@ -2025,10 +2295,26 @@ packages: resolution: {integrity: sha512-Q/XQKRaJiLiFIBNN+mndW7S/RHxvwzuZS6ZwmRzUBqJBv/5QIKCEwkBC8GBf8EQJKYnaFs0wOZbKTXBPj8L9oQ==} engines: {node: ^14.18.0 || >=16.0.0} + tar-fs@2.1.3: + resolution: {integrity: sha512-090nwYJDmlhwFwEW3QQl+vaNnxsO2yVsd45eTKRBzSzu+hlb1w2K9inVq5b0ngXuLVqQ4ApvsUHHnu/zQNkWAg==} + + tar-fs@3.1.0: + resolution: {integrity: sha512-5Mty5y/sOF1YWj1J6GiBodjlDc05CUR8PKXrsnFAiSG0xA+GHeWLovaZPYUDXkH/1iKRf2+M5+OrRgzC7O9b7w==} + + tar-stream@2.2.0: + resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==} + engines: {node: '>=6'} + + tar-stream@3.1.7: + resolution: {integrity: sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==} + test-exclude@6.0.0: resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==} engines: {node: '>=8'} + text-decoder@1.2.3: + resolution: {integrity: sha512-3/o9z3X0X0fTupwsYvR03pJ/DjWuqqrfwBgTQzdWDiQSm9KitAyz/9WqsT2JQW7KV2m+bC2ol/zqpW37NHxLaA==} + text-table@0.2.0: resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} @@ -2067,6 +2353,9 @@ packages: tslib@2.8.1: resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + tunnel-agent@0.6.0: + resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==} + type-check@0.4.0: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} @@ -2096,6 +2385,9 @@ packages: uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + uuid@11.1.0: resolution: {integrity: sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==} hasBin: true @@ -2761,6 +3053,8 @@ snapshots: '@eslint/js@8.57.1': {} + '@huggingface/jinja@0.2.2': {} + '@humanwhocodes/config-array@0.13.0': dependencies: '@humanwhocodes/object-schema': 2.0.3 @@ -2822,6 +3116,29 @@ snapshots: '@pkgr/core@0.2.4': {} + '@protobufjs/aspromise@1.1.2': {} + + '@protobufjs/base64@1.1.2': {} + + '@protobufjs/codegen@2.0.4': {} + + '@protobufjs/eventemitter@1.1.0': {} + + '@protobufjs/fetch@1.1.0': + dependencies: + '@protobufjs/aspromise': 1.1.2 + '@protobufjs/inquire': 1.1.0 + + '@protobufjs/float@1.0.2': {} + + '@protobufjs/inquire@1.1.0': {} + + '@protobufjs/path@1.1.2': {} + + '@protobufjs/pool@1.1.0': {} + + '@protobufjs/utf8@1.1.0': {} + '@rollup/rollup-android-arm-eabi@4.40.0': optional: true @@ -3185,6 +3502,8 @@ snapshots: '@types/estree@1.0.7': {} + '@types/long@4.0.2': {} + '@types/node-fetch@2.6.12': dependencies: '@types/node': 20.17.31 @@ -3331,6 +3650,17 @@ snapshots: loupe: 2.3.7 pretty-format: 29.7.0 + '@xenova/transformers@2.17.2': + dependencies: + '@huggingface/jinja': 0.2.2 + onnxruntime-web: 1.14.0 + sharp: 0.32.6 + optionalDependencies: + onnxruntime-node: 1.14.0 + transitivePeerDependencies: + - bare-buffer + - react-native-b4a + abort-controller@3.0.0: dependencies: event-target-shim: 5.0.1 @@ -3380,8 +3710,54 @@ snapshots: asynckit@0.4.0: {} + b4a@1.7.1: {} + balanced-match@1.0.2: {} + bare-events@2.6.1: + optional: true + + bare-fs@4.4.4: + dependencies: + bare-events: 2.6.1 + bare-path: 3.0.0 + bare-stream: 2.7.0(bare-events@2.6.1) + bare-url: 2.2.2 + fast-fifo: 1.3.2 + transitivePeerDependencies: + - react-native-b4a + optional: true + + bare-os@3.6.2: + optional: true + + bare-path@3.0.0: + dependencies: + bare-os: 3.6.2 + optional: true + + bare-stream@2.7.0(bare-events@2.6.1): + dependencies: + streamx: 2.22.1 + optionalDependencies: + bare-events: 2.6.1 + transitivePeerDependencies: + - react-native-b4a + optional: true + + bare-url@2.2.2: + dependencies: + bare-path: 3.0.0 + optional: true + + base64-js@1.5.1: {} + + bl@4.1.0: + dependencies: + buffer: 5.7.1 + inherits: 2.0.4 + readable-stream: 3.6.2 + bowser@2.11.0: {} brace-expansion@1.1.11: @@ -3397,6 +3773,11 @@ snapshots: dependencies: fill-range: 7.1.1 + buffer@5.7.1: + dependencies: + base64-js: 1.5.1 + ieee754: 1.2.1 + cac@6.7.14: {} call-bind-apply-helpers@1.0.2: @@ -3427,6 +3808,8 @@ snapshots: dependencies: get-func-name: 2.0.2 + chownr@1.1.4: {} + cli-cursor@5.0.0: dependencies: restore-cursor: 5.1.0 @@ -3442,6 +3825,16 @@ snapshots: color-name@1.1.4: {} + color-string@1.9.1: + dependencies: + color-name: 1.1.4 + simple-swizzle: 0.2.2 + + color@4.2.3: + dependencies: + color-convert: 2.0.1 + color-string: 1.9.1 + colorette@2.0.20: {} combined-stream@1.0.8: @@ -3464,14 +3857,22 @@ snapshots: dependencies: ms: 2.1.3 + decompress-response@6.0.0: + dependencies: + mimic-response: 3.1.0 + deep-eql@4.1.4: dependencies: type-detect: 4.1.0 + deep-extend@0.6.0: {} + deep-is@0.1.4: {} delayed-stream@1.0.0: {} + detect-libc@2.0.4: {} + diff-sequences@29.6.3: {} dir-glob@3.0.1: @@ -3496,6 +3897,10 @@ snapshots: emoji-regex@9.2.2: {} + end-of-stream@1.4.5: + dependencies: + once: 1.4.0 + environment@1.1.0: {} es-define-property@1.0.1: {} @@ -3642,10 +4047,14 @@ snapshots: signal-exit: 4.1.0 strip-final-newline: 3.0.0 + expand-template@2.0.3: {} + fast-deep-equal@3.1.3: {} fast-diff@1.3.0: {} + fast-fifo@1.3.2: {} + fast-glob@3.3.3: dependencies: '@nodelib/fs.stat': 2.0.5 @@ -3685,6 +4094,8 @@ snapshots: keyv: 4.5.4 rimraf: 3.0.2 + flatbuffers@1.12.0: {} + flatted@3.3.3: {} foreground-child@3.3.1: @@ -3706,6 +4117,8 @@ snapshots: node-domexception: 1.0.0 web-streams-polyfill: 4.0.0-beta.3 + fs-constants@1.0.0: {} + fs.realpath@1.0.0: {} fsevents@2.3.3: @@ -3737,6 +4150,8 @@ snapshots: get-stream@8.0.1: {} + github-from-package@0.0.0: {} + glob-parent@5.1.2: dependencies: is-glob: 4.0.3 @@ -3780,6 +4195,8 @@ snapshots: graphemer@1.4.0: {} + guid-typescript@1.0.9: {} + has-flag@4.0.0: {} has-symbols@1.1.0: {} @@ -3802,6 +4219,8 @@ snapshots: husky@8.0.3: {} + ieee754@1.2.1: {} + ignore@5.3.2: {} import-fresh@3.3.1: @@ -3818,6 +4237,10 @@ snapshots: inherits@2.0.4: {} + ini@1.3.8: {} + + is-arrayish@0.3.2: {} + is-extglob@2.1.1: {} is-fullwidth-code-point@3.0.0: {} @@ -3933,6 +4356,8 @@ snapshots: strip-ansi: 7.1.0 wrap-ansi: 9.0.0 + long@4.0.0: {} + loupe@2.3.7: dependencies: get-func-name: 2.0.2 @@ -3974,6 +4399,8 @@ snapshots: mimic-function@5.0.1: {} + mimic-response@3.1.0: {} + minimatch@3.1.2: dependencies: brace-expansion: 1.1.11 @@ -3982,8 +4409,12 @@ snapshots: dependencies: brace-expansion: 2.0.1 + minimist@1.2.8: {} + minipass@7.1.2: {} + mkdirp-classic@0.5.3: {} + mlly@1.7.4: dependencies: acorn: 8.14.1 @@ -3995,8 +4426,16 @@ snapshots: nanoid@3.3.11: {} + napi-build-utils@2.0.0: {} + natural-compare@1.4.0: {} + node-abi@3.77.0: + dependencies: + semver: 7.7.1 + + node-addon-api@6.1.0: {} + node-domexception@1.0.0: {} node-fetch@2.7.0: @@ -4023,6 +4462,26 @@ snapshots: dependencies: mimic-function: 5.0.1 + onnx-proto@4.0.4: + dependencies: + protobufjs: 6.11.4 + + onnxruntime-common@1.14.0: {} + + onnxruntime-node@1.14.0: + dependencies: + onnxruntime-common: 1.14.0 + optional: true + + onnxruntime-web@1.14.0: + dependencies: + flatbuffers: 1.12.0 + guid-typescript: 1.0.9 + long: 4.0.0 + onnx-proto: 4.0.4 + onnxruntime-common: 1.14.0 + platform: 1.3.6 + openai@4.96.0(zod@4.0.5): dependencies: '@types/node': 18.19.87 @@ -4097,12 +4556,29 @@ snapshots: mlly: 1.7.4 pathe: 2.0.3 + platform@1.3.6: {} + postcss@8.5.3: dependencies: nanoid: 3.3.11 picocolors: 1.1.1 source-map-js: 1.2.1 + prebuild-install@7.1.3: + dependencies: + detect-libc: 2.0.4 + expand-template: 2.0.3 + github-from-package: 0.0.0 + minimist: 1.2.8 + mkdirp-classic: 0.5.3 + napi-build-utils: 2.0.0 + node-abi: 3.77.0 + pump: 3.0.3 + rc: 1.2.8 + simple-get: 4.0.1 + tar-fs: 2.1.3 + tunnel-agent: 0.6.0 + prelude-ls@1.2.1: {} prettier-linter-helpers@1.0.0: @@ -4117,12 +4593,46 @@ snapshots: ansi-styles: 5.2.0 react-is: 18.3.1 + protobufjs@6.11.4: + dependencies: + '@protobufjs/aspromise': 1.1.2 + '@protobufjs/base64': 1.1.2 + '@protobufjs/codegen': 2.0.4 + '@protobufjs/eventemitter': 1.1.0 + '@protobufjs/fetch': 1.1.0 + '@protobufjs/float': 1.0.2 + '@protobufjs/inquire': 1.1.0 + '@protobufjs/path': 1.1.2 + '@protobufjs/pool': 1.1.0 + '@protobufjs/utf8': 1.1.0 + '@types/long': 4.0.2 + '@types/node': 20.17.31 + long: 4.0.0 + + pump@3.0.3: + dependencies: + end-of-stream: 1.4.5 + once: 1.4.0 + punycode@2.3.1: {} queue-microtask@1.2.3: {} + rc@1.2.8: + dependencies: + deep-extend: 0.6.0 + ini: 1.3.8 + minimist: 1.2.8 + strip-json-comments: 2.0.1 + react-is@18.3.1: {} + readable-stream@3.6.2: + dependencies: + inherits: 2.0.4 + string_decoder: 1.3.0 + util-deprecate: 1.0.2 + resolve-from@4.0.0: {} restore-cursor@5.1.0: @@ -4172,8 +4682,24 @@ snapshots: dependencies: queue-microtask: 1.2.3 + safe-buffer@5.2.1: {} + semver@7.7.1: {} + sharp@0.32.6: + dependencies: + color: 4.2.3 + detect-libc: 2.0.4 + node-addon-api: 6.1.0 + prebuild-install: 7.1.3 + semver: 7.7.1 + simple-get: 4.0.1 + tar-fs: 3.1.0 + tunnel-agent: 0.6.0 + transitivePeerDependencies: + - bare-buffer + - react-native-b4a + shebang-command@2.0.0: dependencies: shebang-regex: 3.0.0 @@ -4184,6 +4710,18 @@ snapshots: signal-exit@4.1.0: {} + simple-concat@1.0.1: {} + + simple-get@4.0.1: + dependencies: + decompress-response: 6.0.0 + once: 1.4.0 + simple-concat: 1.0.1 + + simple-swizzle@0.2.2: + dependencies: + is-arrayish: 0.3.2 + slash@3.0.0: {} slice-ansi@5.0.0: @@ -4202,6 +4740,15 @@ snapshots: std-env@3.9.0: {} + streamx@2.22.1: + dependencies: + fast-fifo: 1.3.2 + text-decoder: 1.2.3 + optionalDependencies: + bare-events: 2.6.1 + transitivePeerDependencies: + - react-native-b4a + string-argv@0.3.2: {} string-width@4.2.3: @@ -4222,6 +4769,10 @@ snapshots: get-east-asian-width: 1.3.0 strip-ansi: 7.1.0 + string_decoder@1.3.0: + dependencies: + safe-buffer: 5.2.1 + strip-ansi@6.0.1: dependencies: ansi-regex: 5.0.1 @@ -4232,6 +4783,8 @@ snapshots: strip-final-newline@3.0.0: {} + strip-json-comments@2.0.1: {} + strip-json-comments@3.1.1: {} strip-literal@2.1.1: @@ -4249,12 +4802,52 @@ snapshots: '@pkgr/core': 0.2.4 tslib: 2.8.1 + tar-fs@2.1.3: + dependencies: + chownr: 1.1.4 + mkdirp-classic: 0.5.3 + pump: 3.0.3 + tar-stream: 2.2.0 + + tar-fs@3.1.0: + dependencies: + pump: 3.0.3 + tar-stream: 3.1.7 + optionalDependencies: + bare-fs: 4.4.4 + bare-path: 3.0.0 + transitivePeerDependencies: + - bare-buffer + - react-native-b4a + + tar-stream@2.2.0: + dependencies: + bl: 4.1.0 + end-of-stream: 1.4.5 + fs-constants: 1.0.0 + inherits: 2.0.4 + readable-stream: 3.6.2 + + tar-stream@3.1.7: + dependencies: + b4a: 1.7.1 + fast-fifo: 1.3.2 + streamx: 2.22.1 + transitivePeerDependencies: + - react-native-b4a + test-exclude@6.0.0: dependencies: '@istanbuljs/schema': 0.1.3 glob: 7.2.3 minimatch: 3.1.2 + text-decoder@1.2.3: + dependencies: + b4a: 1.7.1 + transitivePeerDependencies: + - react-native-b4a + text-table@0.2.0: {} tinybench@2.9.0: {} @@ -4279,6 +4872,10 @@ snapshots: tslib@2.8.1: {} + tunnel-agent@0.6.0: + dependencies: + safe-buffer: 5.2.1 + type-check@0.4.0: dependencies: prelude-ls: 1.2.1 @@ -4299,6 +4896,8 @@ snapshots: dependencies: punycode: 2.3.1 + util-deprecate@1.0.2: {} + uuid@11.1.0: {} uuid@9.0.1: {}