import { DyFM_OAI_Settings } from '@futdevpro/fsm-dynamo/ai/open-ai'; import { DyNTS_AI_Embedding_ServiceBase } from './ai-embedding.service-base'; import { DyNTS_OAI_Embedding_ControlService } from '../_modules/open-ai/_services/oai-embedding.control-service'; import { DyNTS_LMStudio_Embedding_ControlService, DyNTS_LMStudio_Embedding_Settings } from './lmstudio-embedding.control-service'; import { DyNTS_AI_Embedding_MockService, DyNTS_AI_Embedding_MockSettings } from '../_modules/ai-mock/_services/ai-embedding-mock.service'; import { DyNTS_AI_CostEventCallback } from '../_models/interfaces/dynts-ai-cost-event-callback.interface'; /** * Az embedding-provider kulcsa (BFR-AM-002). String-union, NEM enum (a cost-event provider-stringekkel * konzisztens): `'openai'` (SDK reuse), `'lmstudio'` (lokális OpenAI-kompatibilis HTTP), `'mock'` * (determinisztikus test-double). Az env-feloldás kis-/nagybetűt és a `lm-studio` alias-t is elfogad. */ export type DyNTS_AI_EmbeddingProviderKey = 'openai' | 'lmstudio' | 'mock'; /** * A provider-feloldás opciói. A `provider` explicit kulcsot ad; ha hiányzik, az env-ből oldjuk fel * (`AI_EMBEDDING_PROVIDER`, default `openai`). A többi mező a megfelelő provider config-ját adja át. */ export interface DyNTS_AI_EmbeddingResolveOptions { /** Explicit provider-kulcs; ha hiányzik → env-feloldás. */ provider?: DyNTS_AI_EmbeddingProviderKey | string; /** Per-call cost-event sink (FR-002 / BFR-AM-007) — mind a 3 providernek átadva. */ onCostEvent?: DyNTS_AI_CostEventCallback; /** OpenAI-specifikus config (apiKey/org/project/defaultSettings) — `openai` providerhez. */ openAiSettings?: DyFM_OAI_Settings; /** LM Studio config (baseUrl/apiKey) — `lmstudio` providerhez; baseUrl hiány → env (`LMSTUDIO_BASE_URL`). */ lmStudioSettings?: Partial; /** Mock config (dims) — `mock` providerhez. */ mockSettings?: DyNTS_AI_Embedding_MockSettings; } /** * `DyNTS_AI_EmbeddingProvider_Registry` (BFR-AM-002) — provider-dispatch resolver. A provider-kulcs * (`openai` | `lmstudio` | `mock`) alapján a megfelelő `DyNTS_AI_Embedding_ServiceBase` példányt adja * vissza, így a hívók egységes embedding-felületet látnak a konkrét provider-impl mögött (a FAM * `FAM_Embedding_ControlService.buildProvider` dispatch-ét emeli bedrock-szintre, generikusan). * * Static util (nincs állapota): minden hívás friss példányt épít (env/secret a hívás-időpontban * érvényes — memory: `dynts_dataservice_eager_resolve`-konzisztens, nincs élő singleton-állapot). */ export class DyNTS_AI_EmbeddingProvider_Registry { /** * A megadott (vagy env-ből feloldott) provider-kulcs alapján egy embedding-service példányt épít. * - `openai` → `DyNTS_OAI_Embedding_ControlService` (SDK reuse, cost-event sink-kel), * - `lmstudio` → `DyNTS_LMStudio_Embedding_ControlService` (HTTP; baseUrl a config vagy env), * - `mock` → `DyNTS_AI_Embedding_MockService` (determinisztikus), * - ismeretlen → `Error` (provider nincs konfigurálva — nem néma). */ static resolve(options?: DyNTS_AI_EmbeddingResolveOptions): DyNTS_AI_Embedding_ServiceBase { const key: DyNTS_AI_EmbeddingProviderKey = DyNTS_AI_EmbeddingProvider_Registry.normalizeKey(options?.provider); const onCostEvent: DyNTS_AI_CostEventCallback | undefined = options?.onCostEvent; switch (key) { case 'openai': return new DyNTS_OAI_Embedding_ControlService({ ...(options?.openAiSettings ?? {}), onCostEvent: onCostEvent, }); case 'lmstudio': { const baseUrl: string | undefined = options?.lmStudioSettings?.baseUrl ?? process.env.LMSTUDIO_BASE_URL; if (!baseUrl) { throw new Error( 'DyNTS_AI_EmbeddingProvider_Registry: the lmstudio provider was selected but no baseUrl ' + 'was provided (set lmStudioSettings.baseUrl or the LMSTUDIO_BASE_URL env var).', ); } return new DyNTS_LMStudio_Embedding_ControlService({ baseUrl: baseUrl, apiKey: options?.lmStudioSettings?.apiKey ?? process.env.LMSTUDIO_API_KEY, onCostEvent: onCostEvent, }); } case 'mock': return new DyNTS_AI_Embedding_MockService({ ...(options?.mockSettings ?? {}), onCostEvent: onCostEvent, }); } } /** * A provider-kulcs normalizálása: kis-/nagybetű-független, a `lm-studio` / `local-ai` alias-t * `lmstudio`-ra képzi. Hiány → env (`AI_EMBEDDING_PROVIDER`) → default `openai`. Ismeretlen → `Error`. */ static normalizeKey(provider?: string): DyNTS_AI_EmbeddingProviderKey { const raw: string = (provider ?? process.env.AI_EMBEDDING_PROVIDER ?? 'openai').trim().toLowerCase(); switch (raw) { case 'openai': case 'open-ai': case 'oai': return 'openai'; case 'lmstudio': case 'lm-studio': case 'local-ai': case 'localai': return 'lmstudio'; case 'mock': case 'fake': case 'test': return 'mock'; default: throw new Error( `DyNTS_AI_EmbeddingProvider_Registry: unknown embedding provider '${raw}'. ` + `Available: 'openai' | 'lmstudio' | 'mock'.`, ); } } }