From 320eab65d6d6e02e31084798e1ab7ef5080a1eff Mon Sep 17 00:00:00 2001 From: Henry Heng Date: Mon, 20 Jan 2025 18:29:27 +0000 Subject: [PATCH] Chore/Add base options to azure chat openai (#3886) * add base options to azure chat openai * add base options to embeddings --- .../AzureChatOpenAI/AzureChatOpenAI.ts | 28 +++++++++++++++++-- .../AzureOpenAIEmbedding.ts | 24 ++++++++++++++-- .../OpenAIEmbeddingCustom.ts | 21 ++++++++++++-- 3 files changed, 65 insertions(+), 8 deletions(-) diff --git a/packages/components/nodes/chatmodels/AzureChatOpenAI/AzureChatOpenAI.ts b/packages/components/nodes/chatmodels/AzureChatOpenAI/AzureChatOpenAI.ts index 3ef01bc4..afd7eea3 100644 --- a/packages/components/nodes/chatmodels/AzureChatOpenAI/AzureChatOpenAI.ts +++ b/packages/components/nodes/chatmodels/AzureChatOpenAI/AzureChatOpenAI.ts @@ -1,10 +1,11 @@ -import { AzureOpenAIInput, ChatOpenAI as LangchainChatOpenAI, OpenAIChatInput } from '@langchain/openai' +import { AzureOpenAIInput, ChatOpenAI as LangchainChatOpenAI, OpenAIChatInput, ClientOptions, LegacyOpenAIInput } from '@langchain/openai' import { BaseCache } from '@langchain/core/caches' import { BaseLLMParams } from '@langchain/core/language_models/llms' import { ICommonObject, IMultiModalOption, INode, INodeData, INodeOptionsValue, INodeParams } from '../../../src/Interface' import { getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils' import { ChatOpenAI } from '../ChatOpenAI/FlowiseChatOpenAI' import { getModels, MODEL_TYPE } from '../../../src/modelLoader' +import { BaseChatModelParams } from '@langchain/core/language_models/chat_models' const serverCredentialsExists = !!process.env.AZURE_OPENAI_API_KEY && @@ -27,7 +28,7 @@ class AzureChatOpenAI_ChatModels implements INode { constructor() { this.label = 'Azure ChatOpenAI' this.name = 'azureChatOpenAI' - this.version = 6.0 + this.version = 7.0 this.type = 'AzureChatOpenAI' this.icon = 'Azure.svg' this.category = 'Chat Models' @@ -116,6 +117,13 @@ class AzureChatOpenAI_ChatModels implements INode { optional: true, additionalParams: true }, + { + label: 'BaseOptions', + name: 'baseOptions', + type: 'json', + optional: true, + additionalParams: true + }, { label: 'Allow Image Uploads', name: 'allowImageUploads', @@ -169,6 +177,7 @@ class AzureChatOpenAI_ChatModels implements INode { const cache = nodeData.inputs?.cache as BaseCache const topP = nodeData.inputs?.topP as string const basePath = nodeData.inputs?.basepath as string + const baseOptions = nodeData.inputs?.baseOptions const credentialData = await getCredentialData(nodeData.credential ?? '', options) const azureOpenAIApiKey = getCredentialParam('azureOpenAIApiKey', credentialData, nodeData) @@ -179,7 +188,10 @@ class AzureChatOpenAI_ChatModels implements INode { const allowImageUploads = nodeData.inputs?.allowImageUploads as boolean const imageResolution = nodeData.inputs?.imageResolution as string - const obj: Partial & BaseLLMParams & Partial = { + const obj: Partial & + BaseLLMParams & + Partial & + BaseChatModelParams & { configuration?: ClientOptions & LegacyOpenAIInput } = { temperature: parseFloat(temperature), modelName, azureOpenAIApiKey, @@ -196,6 +208,16 @@ class AzureChatOpenAI_ChatModels implements INode { if (cache) obj.cache = cache if (topP) obj.topP = parseFloat(topP) if (basePath) obj.azureOpenAIBasePath = basePath + if (baseOptions) { + try { + const parsedBaseOptions = typeof baseOptions === 'object' ? baseOptions : JSON.parse(baseOptions) + obj.configuration = { + defaultHeaders: parsedBaseOptions + } + } catch (exception) { + console.error('Error parsing base options', exception) + } + } const multiModalOption: IMultiModalOption = { image: { diff --git a/packages/components/nodes/embeddings/AzureOpenAIEmbedding/AzureOpenAIEmbedding.ts b/packages/components/nodes/embeddings/AzureOpenAIEmbedding/AzureOpenAIEmbedding.ts index fb4fa953..8a2b828b 100644 --- a/packages/components/nodes/embeddings/AzureOpenAIEmbedding/AzureOpenAIEmbedding.ts +++ b/packages/components/nodes/embeddings/AzureOpenAIEmbedding/AzureOpenAIEmbedding.ts @@ -1,4 +1,4 @@ -import { AzureOpenAIInput, OpenAIEmbeddings, OpenAIEmbeddingsParams } from '@langchain/openai' +import { AzureOpenAIInput, ClientOptions, LegacyOpenAIInput, OpenAIEmbeddings, OpenAIEmbeddingsParams } from '@langchain/openai' import { ICommonObject, INode, INodeData, INodeParams } from '../../../src/Interface' import { getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils' @@ -23,7 +23,7 @@ class AzureOpenAIEmbedding_Embeddings implements INode { constructor() { this.label = 'Azure OpenAI Embeddings' this.name = 'azureOpenAIEmbeddings' - this.version = 1.0 + this.version = 2.0 this.type = 'AzureOpenAIEmbeddings' this.icon = 'Azure.svg' this.category = 'Embeddings' @@ -58,6 +58,13 @@ class AzureOpenAIEmbedding_Embeddings implements INode { type: 'string', optional: true, additionalParams: true + }, + { + label: 'BaseOptions', + name: 'baseOptions', + type: 'json', + optional: true, + additionalParams: true } ] } @@ -66,6 +73,7 @@ class AzureOpenAIEmbedding_Embeddings implements INode { const batchSize = nodeData.inputs?.batchSize as string const timeout = nodeData.inputs?.timeout as string const basePath = nodeData.inputs?.basepath as string + const baseOptions = nodeData.inputs?.baseOptions const credentialData = await getCredentialData(nodeData.credential ?? '', options) const azureOpenAIApiKey = getCredentialParam('azureOpenAIApiKey', credentialData, nodeData) @@ -73,7 +81,7 @@ class AzureOpenAIEmbedding_Embeddings implements INode { const azureOpenAIApiDeploymentName = getCredentialParam('azureOpenAIApiDeploymentName', credentialData, nodeData) const azureOpenAIApiVersion = getCredentialParam('azureOpenAIApiVersion', credentialData, nodeData) - const obj: Partial & Partial = { + const obj: Partial & Partial & { configuration?: ClientOptions & LegacyOpenAIInput } = { azureOpenAIApiKey, azureOpenAIApiInstanceName, azureOpenAIApiDeploymentName, @@ -83,6 +91,16 @@ class AzureOpenAIEmbedding_Embeddings implements INode { if (batchSize) obj.batchSize = parseInt(batchSize, 10) if (timeout) obj.timeout = parseInt(timeout, 10) + if (baseOptions) { + try { + const parsedBaseOptions = typeof baseOptions === 'object' ? baseOptions : JSON.parse(baseOptions) + obj.configuration = { + defaultHeaders: parsedBaseOptions + } + } catch (exception) { + console.error('Error parsing base options', exception) + } + } const model = new OpenAIEmbeddings(obj) return model diff --git a/packages/components/nodes/embeddings/OpenAIEmbeddingCustom/OpenAIEmbeddingCustom.ts b/packages/components/nodes/embeddings/OpenAIEmbeddingCustom/OpenAIEmbeddingCustom.ts index d45ff498..6cc3a328 100644 --- a/packages/components/nodes/embeddings/OpenAIEmbeddingCustom/OpenAIEmbeddingCustom.ts +++ b/packages/components/nodes/embeddings/OpenAIEmbeddingCustom/OpenAIEmbeddingCustom.ts @@ -17,7 +17,7 @@ class OpenAIEmbeddingCustom_Embeddings implements INode { constructor() { this.label = 'OpenAI Embeddings Custom' this.name = 'openAIEmbeddingsCustom' - this.version = 2.0 + this.version = 3.0 this.type = 'OpenAIEmbeddingsCustom' this.icon = 'openai.svg' this.category = 'Embeddings' @@ -58,6 +58,13 @@ class OpenAIEmbeddingCustom_Embeddings implements INode { optional: true, additionalParams: true }, + { + label: 'BaseOptions', + name: 'baseOptions', + type: 'json', + optional: true, + additionalParams: true + }, { label: 'Model Name', name: 'modelName', @@ -81,6 +88,7 @@ class OpenAIEmbeddingCustom_Embeddings implements INode { const basePath = nodeData.inputs?.basepath as string const modelName = nodeData.inputs?.modelName as string const dimensions = nodeData.inputs?.dimensions as string + const baseOptions = nodeData.inputs?.baseOptions const credentialData = await getCredentialData(nodeData.credential ?? '', options) const openAIApiKey = getCredentialParam('openAIApiKey', credentialData, nodeData) @@ -95,7 +103,16 @@ class OpenAIEmbeddingCustom_Embeddings implements INode { if (modelName) obj.modelName = modelName if (dimensions) obj.dimensions = parseInt(dimensions, 10) - const model = new OpenAIEmbeddings(obj, { basePath }) + let parsedBaseOptions: any | undefined = undefined + if (baseOptions) { + try { + parsedBaseOptions = typeof baseOptions === 'object' ? baseOptions : JSON.parse(baseOptions) + } catch (exception) { + throw new Error("Invalid JSON in the ChatOpenAI's BaseOptions: " + exception) + } + } + + const model = new OpenAIEmbeddings(obj, { baseURL: basePath, defaultHeaders: parsedBaseOptions }) return model } }