Skip to content

Commit 99d4bac

Browse files
IBM Watsonx LLM node (#3674)
* Add node icon * Add node
1 parent b087f4c commit 99d4bac

File tree

2 files changed

+231
-0
lines changed

2 files changed

+231
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,231 @@
1+
import { ICommonObject, INode, INodeData, INodeParams } from '../../../src'
2+
import { getBaseClasses, getCredentialData, getCredentialParam } from '../../../src'
3+
import { WatsonxLLM, WatsonxInputLLM } from '@langchain/community/llms/ibm'
4+
import { WatsonxAuth } from '@langchain/community/dist/types/ibm'
5+
import { BaseCache } from '@langchain/core/caches'
6+
7+
class IBMWatsonx_LLMs implements INode {
8+
label: string
9+
name: string
10+
version: number
11+
type: string
12+
icon: string
13+
category: string
14+
description: string
15+
baseClasses: string[]
16+
credential: INodeParams
17+
inputs: INodeParams[]
18+
19+
constructor() {
20+
this.label = 'IBMWatsonx'
21+
this.name = 'ibmWatsonx'
22+
this.version = 1.0
23+
this.type = 'IBMWatsonx'
24+
this.icon = 'ibm.png'
25+
this.category = 'LLMs'
26+
this.description = 'Wrapper around IBM watsonx.ai foundation models'
27+
this.baseClasses = [this.type, ...getBaseClasses(WatsonxLLM)]
28+
this.credential = {
29+
label: 'Connect Credential',
30+
name: 'credential',
31+
type: 'credential',
32+
credentialNames: ['ibmWatsonx']
33+
}
34+
this.inputs = [
35+
{
36+
label: 'Cache',
37+
name: 'cache',
38+
type: 'BaseCache',
39+
optional: true
40+
},
41+
{
42+
label: 'Model',
43+
name: 'modelId',
44+
type: 'string',
45+
default: 'ibm/granite-13b-instruct-v2',
46+
description: 'The name of the model to query.'
47+
},
48+
{
49+
label: 'Decoding Method',
50+
name: 'decodingMethod',
51+
type: 'options',
52+
options: [
53+
{ label: 'sample', name: 'sample' },
54+
{ label: 'greedy', name: 'greedy' }
55+
],
56+
default: 'greedy',
57+
description:
58+
'Set decoding to Greedy to always select words with the highest probability. Set decoding to Sampling to customize the variability of word selection.',
59+
optional: true,
60+
additionalParams: true
61+
},
62+
{
63+
label: 'Top K',
64+
name: 'topK',
65+
type: 'number',
66+
description:
67+
'The topK parameter is used to limit the number of choices for the next predicted word or token. It specifies the maximum number of tokens to consider at each step, based on their probability of occurrence. This technique helps to speed up the generation process and can improve the quality of the generated text by focusing on the most likely options.',
68+
step: 1,
69+
default: 50,
70+
optional: true,
71+
additionalParams: true
72+
},
73+
{
74+
label: 'Top P',
75+
name: 'topP',
76+
type: 'number',
77+
description:
78+
'The topP (nucleus) parameter is used to dynamically adjust the number of choices for each predicted token based on the cumulative probabilities. It specifies a probability threshold, below which all less likely tokens are filtered out. This technique helps to maintain diversity and generate more fluent and natural-sounding text.',
79+
step: 0.1,
80+
default: 0.7,
81+
optional: true,
82+
additionalParams: true
83+
},
84+
{
85+
label: 'Temperature',
86+
name: 'temperature',
87+
type: 'number',
88+
description:
89+
'A decimal number that determines the degree of randomness in the response. A value of 1 will always yield the same output. A temperature less than 1 favors more correctness and is appropriate for question answering or summarization. A value greater than 1 introduces more randomness in the output.',
90+
step: 0.1,
91+
default: 0.7,
92+
optional: true,
93+
additionalParams: true
94+
},
95+
{
96+
label: 'Repeat Penalty',
97+
name: 'repetitionPenalty',
98+
type: 'number',
99+
description:
100+
'A number that controls the diversity of generated text by reducing the likelihood of repeated sequences. Higher values decrease repetition.',
101+
step: 0.1,
102+
default: 1,
103+
optional: true,
104+
additionalParams: true
105+
},
106+
{
107+
label: 'Streaming',
108+
name: 'streaming',
109+
type: 'boolean',
110+
default: false,
111+
description: 'Whether or not to stream tokens as they are generated.'
112+
},
113+
{
114+
label: 'Max New Tokens',
115+
name: 'maxNewTokens',
116+
type: 'number',
117+
step: 1,
118+
default: 100,
119+
description:
120+
'The maximum number of new tokens to be generated. The maximum supported value for this field depends on the model being used.',
121+
optional: true,
122+
additionalParams: true
123+
},
124+
{
125+
label: 'Min New Tokens',
126+
name: 'minNewTokens',
127+
type: 'number',
128+
step: 1,
129+
default: 1,
130+
description: 'If stop sequences are given, they are ignored until minimum tokens are generated.',
131+
optional: true,
132+
additionalParams: true
133+
},
134+
{
135+
label: 'Stop Sequence',
136+
name: 'stopSequence',
137+
type: 'string',
138+
rows: 4,
139+
placeholder: 'AI assistant:',
140+
description: 'A list of tokens at which the generation should stop.',
141+
optional: true,
142+
additionalParams: true
143+
},
144+
{
145+
label: 'Include Stop Sequence',
146+
name: 'includeStopSequence',
147+
type: 'boolean',
148+
default: false,
149+
description:
150+
'Pass false to omit matched stop sequences from the end of the output text. The default is true, meaning that the output will end with the stop sequence text when matched.',
151+
optional: true,
152+
additionalParams: true
153+
},
154+
{
155+
label: 'Random Seed',
156+
name: 'randomSeed',
157+
type: 'number',
158+
placeholder: '62345',
159+
description: 'Random number generator seed to use in sampling mode for experimental repeatability.',
160+
optional: true,
161+
additionalParams: true
162+
}
163+
]
164+
}
165+
166+
async init(nodeData: INodeData, _: string, options: ICommonObject): Promise<any> {
167+
const decodingMethod = nodeData.inputs?.decodingMethod as string
168+
const temperature = nodeData.inputs?.temperature as string
169+
const maxNewTokens = nodeData.inputs?.maxNewTokens as string
170+
const minNewTokens = nodeData.inputs?.minNewTokens as string
171+
const topP = nodeData.inputs?.topP as string
172+
const topK = nodeData.inputs?.topK as string
173+
const repetitionPenalty = nodeData.inputs?.repetitionPenalty as string
174+
const modelId = nodeData.inputs?.modelId as string
175+
const stopSequence = nodeData.inputs?.stopSequence as string
176+
const randomSeed = nodeData.inputs?.randomSeed as string
177+
const includeStopSequence = nodeData.inputs?.includeStopSequence as boolean
178+
const streaming = nodeData.inputs?.streaming as boolean
179+
180+
const cache = nodeData.inputs?.cache as BaseCache
181+
182+
const credentialData = await getCredentialData(nodeData.credential ?? '', options)
183+
const version = getCredentialParam('version', credentialData, nodeData)
184+
const serviceUrl = getCredentialParam('serviceUrl', credentialData, nodeData)
185+
const projectId = getCredentialParam('projectId', credentialData, nodeData)
186+
const watsonxAIAuthType = getCredentialParam('watsonxAIAuthType', credentialData, nodeData)
187+
const watsonxAIApikey = getCredentialParam('watsonxAIApikey', credentialData, nodeData)
188+
const watsonxAIBearerToken = getCredentialParam('watsonxAIBearerToken', credentialData, nodeData)
189+
190+
const auth = {
191+
version,
192+
serviceUrl,
193+
projectId,
194+
watsonxAIAuthType,
195+
watsonxAIApikey,
196+
watsonxAIBearerToken
197+
}
198+
199+
const obj: WatsonxInputLLM & WatsonxAuth = {
200+
...auth,
201+
model: modelId,
202+
streaming: streaming ?? true
203+
}
204+
205+
if (decodingMethod) obj.decodingMethod = decodingMethod
206+
if (repetitionPenalty) obj.repetitionPenalty = parseFloat(repetitionPenalty)
207+
if (maxNewTokens) obj.maxNewTokens = parseInt(maxNewTokens)
208+
if (minNewTokens) obj.minNewTokens = parseInt(minNewTokens)
209+
if (decodingMethod === 'sample') {
210+
if (temperature) obj.temperature = parseFloat(temperature)
211+
if (topP) obj.topP = parseFloat(topP)
212+
if (topK) obj.topK = parseInt(topK)
213+
}
214+
if (stopSequence) {
215+
obj.stopSequence = stopSequence.split(', ') || ['']
216+
}
217+
if (randomSeed) {
218+
obj.randomSeed = parseInt(randomSeed)
219+
}
220+
if (includeStopSequence) {
221+
obj.includeStopSequence = includeStopSequence
222+
}
223+
224+
if (cache) obj.cache = cache
225+
226+
const watsonXAI = new WatsonxLLM(obj)
227+
return watsonXAI
228+
}
229+
}
230+
231+
module.exports = { nodeClass: IBMWatsonx_LLMs }
Loading

0 commit comments

Comments
 (0)