-
-
Notifications
You must be signed in to change notification settings - Fork 24.8k
feat(components): add mittwald AI Hosting chat and embedding provider #6646
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| import { INodeParams, INodeCredential } from '../src/Interface' | ||
|
|
||
| class MittwaldAIHostingApiAuth implements INodeCredential { | ||
| label: string | ||
| name: string | ||
| version: number | ||
| description: string | ||
| inputs: INodeParams[] | ||
|
|
||
| constructor() { | ||
| this.label = 'mittwald AI Hosting API Key' | ||
| this.name = 'mittwaldAIHostingApi' | ||
| this.version = 1.0 | ||
| this.description = 'Create an API key for AI Hosting in mStudio' | ||
| this.inputs = [ | ||
| { | ||
| label: 'mittwald API Key', | ||
| name: 'mittwaldApiKey', | ||
| type: 'password', | ||
| description: 'Create your API key in mStudio under AI Hosting (starts with sk-)' | ||
| } | ||
| ] | ||
| } | ||
| } | ||
|
|
||
| module.exports = { credClass: MittwaldAIHostingApiAuth } |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,187 @@ | ||||||||||||||||||||||||||||
| import { ChatOpenAI, ChatOpenAIFields } from '@langchain/openai' | ||||||||||||||||||||||||||||
| import { BaseCache } from '@langchain/core/caches' | ||||||||||||||||||||||||||||
| import { ICommonObject, INode, INodeData, INodeOptionsValue, INodeParams } from '../../../src/Interface' | ||||||||||||||||||||||||||||
| import { getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils' | ||||||||||||||||||||||||||||
| import { getModels, MODEL_TYPE } from '../../../src/modelLoader' | ||||||||||||||||||||||||||||
| import { checkDenyList } from '../../../src/httpSecurity' | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| const DEFAULT_BASE_URL = 'https://llm.aihosting.mittwald.de/v1' | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| class ChatMittwald_ChatModels implements INode { | ||||||||||||||||||||||||||||
| label: string | ||||||||||||||||||||||||||||
| name: string | ||||||||||||||||||||||||||||
| version: number | ||||||||||||||||||||||||||||
| type: string | ||||||||||||||||||||||||||||
| icon: string | ||||||||||||||||||||||||||||
| category: string | ||||||||||||||||||||||||||||
| description: string | ||||||||||||||||||||||||||||
| baseClasses: string[] | ||||||||||||||||||||||||||||
| credential: INodeParams | ||||||||||||||||||||||||||||
| inputs: INodeParams[] | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| constructor() { | ||||||||||||||||||||||||||||
| this.label = 'mittwald AI Hosting' | ||||||||||||||||||||||||||||
| this.name = 'chatMittwald' | ||||||||||||||||||||||||||||
| this.version = 1.0 | ||||||||||||||||||||||||||||
| this.type = 'ChatMittwald' | ||||||||||||||||||||||||||||
| this.icon = 'mittwald.png' | ||||||||||||||||||||||||||||
| this.category = 'Chat Models' | ||||||||||||||||||||||||||||
| this.description = 'Wrapper around mittwald AI Hosting API' | ||||||||||||||||||||||||||||
| this.baseClasses = [this.type, ...getBaseClasses(ChatOpenAI)] | ||||||||||||||||||||||||||||
| this.credential = { | ||||||||||||||||||||||||||||
| label: 'Connect Credential', | ||||||||||||||||||||||||||||
| name: 'credential', | ||||||||||||||||||||||||||||
| type: 'credential', | ||||||||||||||||||||||||||||
| credentialNames: ['mittwaldAIHostingApi'] | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
| this.inputs = [ | ||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||
| label: 'Cache', | ||||||||||||||||||||||||||||
| name: 'cache', | ||||||||||||||||||||||||||||
| type: 'BaseCache', | ||||||||||||||||||||||||||||
| optional: true | ||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||
| label: 'Model Name', | ||||||||||||||||||||||||||||
| name: 'modelName', | ||||||||||||||||||||||||||||
| type: 'asyncOptions', | ||||||||||||||||||||||||||||
| loadMethod: 'listModels', | ||||||||||||||||||||||||||||
| default: 'gpt-oss-120b' | ||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||
| label: 'Temperature', | ||||||||||||||||||||||||||||
| name: 'temperature', | ||||||||||||||||||||||||||||
| type: 'number', | ||||||||||||||||||||||||||||
| step: 0.1, | ||||||||||||||||||||||||||||
| default: 0.9, | ||||||||||||||||||||||||||||
| optional: true | ||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||
| label: 'Streaming', | ||||||||||||||||||||||||||||
| name: 'streaming', | ||||||||||||||||||||||||||||
| type: 'boolean', | ||||||||||||||||||||||||||||
| default: true, | ||||||||||||||||||||||||||||
| optional: true, | ||||||||||||||||||||||||||||
| additionalParams: true | ||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||
| label: 'Max Tokens', | ||||||||||||||||||||||||||||
| name: 'maxTokens', | ||||||||||||||||||||||||||||
| type: 'number', | ||||||||||||||||||||||||||||
| step: 1, | ||||||||||||||||||||||||||||
| optional: true, | ||||||||||||||||||||||||||||
| additionalParams: true | ||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||
| label: 'Top Probability', | ||||||||||||||||||||||||||||
| name: 'topP', | ||||||||||||||||||||||||||||
| type: 'number', | ||||||||||||||||||||||||||||
| step: 0.1, | ||||||||||||||||||||||||||||
| optional: true, | ||||||||||||||||||||||||||||
| additionalParams: true | ||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||
| label: 'Frequency Penalty', | ||||||||||||||||||||||||||||
| name: 'frequencyPenalty', | ||||||||||||||||||||||||||||
| type: 'number', | ||||||||||||||||||||||||||||
| step: 0.1, | ||||||||||||||||||||||||||||
| optional: true, | ||||||||||||||||||||||||||||
| additionalParams: true | ||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||
| label: 'Presence Penalty', | ||||||||||||||||||||||||||||
| name: 'presencePenalty', | ||||||||||||||||||||||||||||
| type: 'number', | ||||||||||||||||||||||||||||
| step: 0.1, | ||||||||||||||||||||||||||||
| optional: true, | ||||||||||||||||||||||||||||
| additionalParams: true | ||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||
| label: 'Timeout', | ||||||||||||||||||||||||||||
| name: 'timeout', | ||||||||||||||||||||||||||||
| type: 'number', | ||||||||||||||||||||||||||||
| step: 1, | ||||||||||||||||||||||||||||
| optional: true, | ||||||||||||||||||||||||||||
| additionalParams: true | ||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||
| label: 'Base Path', | ||||||||||||||||||||||||||||
| name: 'basepath', | ||||||||||||||||||||||||||||
| type: 'string', | ||||||||||||||||||||||||||||
| optional: true, | ||||||||||||||||||||||||||||
| default: DEFAULT_BASE_URL, | ||||||||||||||||||||||||||||
| description: 'Override the default base URL for the API, e.g. for a dedicated AI Hosting endpoint', | ||||||||||||||||||||||||||||
| additionalParams: true | ||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||
| label: 'Base Options', | ||||||||||||||||||||||||||||
| name: 'baseOptions', | ||||||||||||||||||||||||||||
| type: 'json', | ||||||||||||||||||||||||||||
| optional: true, | ||||||||||||||||||||||||||||
| description: 'Default headers to include with every request to the API.', | ||||||||||||||||||||||||||||
| additionalParams: true | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
| ] | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| loadMethods = { | ||||||||||||||||||||||||||||
| async listModels(): Promise<INodeOptionsValue[]> { | ||||||||||||||||||||||||||||
| return await getModels(MODEL_TYPE.CHAT, 'chatMittwald') | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| async init(nodeData: INodeData, _: string, options: ICommonObject): Promise<any> { | ||||||||||||||||||||||||||||
| const temperature = nodeData.inputs?.temperature as string | ||||||||||||||||||||||||||||
| const modelName = nodeData.inputs?.modelName as string | ||||||||||||||||||||||||||||
| const maxTokens = nodeData.inputs?.maxTokens as string | ||||||||||||||||||||||||||||
| const topP = nodeData.inputs?.topP as string | ||||||||||||||||||||||||||||
| const frequencyPenalty = nodeData.inputs?.frequencyPenalty as string | ||||||||||||||||||||||||||||
| const presencePenalty = nodeData.inputs?.presencePenalty as string | ||||||||||||||||||||||||||||
| const timeout = nodeData.inputs?.timeout as string | ||||||||||||||||||||||||||||
| const streaming = nodeData.inputs?.streaming as boolean | ||||||||||||||||||||||||||||
| const basePath = (nodeData.inputs?.basepath as string) || DEFAULT_BASE_URL | ||||||||||||||||||||||||||||
| const baseOptions = nodeData.inputs?.baseOptions | ||||||||||||||||||||||||||||
| const cache = nodeData.inputs?.cache as BaseCache | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| const credentialData = await getCredentialData(nodeData.credential ?? '', options) | ||||||||||||||||||||||||||||
| const mittwaldApiKey = getCredentialParam('mittwaldApiKey', credentialData, nodeData) | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| const obj: ChatOpenAIFields = { | ||||||||||||||||||||||||||||
| temperature: parseFloat(temperature), | ||||||||||||||||||||||||||||
| model: modelName, | ||||||||||||||||||||||||||||
| apiKey: mittwaldApiKey, | ||||||||||||||||||||||||||||
| streaming: streaming ?? true | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|
Comment on lines
+149
to
+154
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The
Suggested change
|
||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| if (maxTokens) obj.maxTokens = parseInt(maxTokens, 10) | ||||||||||||||||||||||||||||
| if (topP) obj.topP = parseFloat(topP) | ||||||||||||||||||||||||||||
| if (frequencyPenalty) obj.frequencyPenalty = parseFloat(frequencyPenalty) | ||||||||||||||||||||||||||||
| if (presencePenalty) obj.presencePenalty = parseFloat(presencePenalty) | ||||||||||||||||||||||||||||
| if (timeout) obj.timeout = parseInt(timeout, 10) | ||||||||||||||||||||||||||||
| if (cache) obj.cache = cache | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| 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 ChatMittwald's BaseOptions: " + exception) | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| await checkDenyList(basePath) | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| obj.configuration = { | ||||||||||||||||||||||||||||
| baseURL: basePath, | ||||||||||||||||||||||||||||
| defaultHeaders: { | ||||||||||||||||||||||||||||
| ...(parsedBaseOptions || {}) | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| const model = new ChatOpenAI(obj) | ||||||||||||||||||||||||||||
| return model | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| module.exports = { nodeClass: ChatMittwald_ChatModels } | ||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There seems to be a typo in the model name.
Ministralshould likely beMistral. Using an incorrect model name will cause API requests to fail.