node-red-contrib-ollama 0.2.5 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -37,16 +37,14 @@
37
37
  payload <span class="property-type">object</span>
38
38
  </dt>
39
39
  <dd>
40
- The payload object.
40
+ The payload object is an alternative way to configure the node.<br />
41
+ Any properties in the payload object will override the node configuration.
41
42
 
42
43
  <dl class="message-properties">
43
44
  <dt class="optional">
44
45
  payload.host <span class="property-type">string</span>
45
46
  </dt>
46
- <dd>
47
- The host of the Ollama instance.<br />
48
- <em>Alternative to the <code>Server</code> field.</em>
49
- </dd>
47
+ <dd>The host of the Ollama instance.</dd>
50
48
  </dl>
51
49
  </dd>
52
50
  </dl>
@@ -6,13 +6,9 @@ module.exports = function( RED ) {
6
6
  const node = this
7
7
 
8
8
  node.on( 'input', async function( msg ) {
9
- const {
10
- host: payloadHost
11
- } = msg.payload
12
-
13
9
  const server = RED.nodes.getNode( config.server )
14
10
 
15
- const host = ( server ) ? server.host + ':' + server.port : payloadHost
11
+ const host = msg?.payload?.host || ( server ) ? server.host + ':' + server.port : null
16
12
 
17
13
  const ollama = new Ollama( { host } )
18
14
 
@@ -5,16 +5,54 @@
5
5
  defaults: {
6
6
  name: { value: 'Ollama Chat' },
7
7
  server: { value: '', type: 'ollama-config-server', required: false },
8
- model: { value: '', type: 'ollama-config-model', required: true },
8
+ model: { value: '', required: false },
9
+ modelType: { value: 'str', required: false },
10
+ messages: { value: 'payload', required: false },
11
+ messagesType: { value: 'msg', required: false },
9
12
  format: { value: '', type: 'ollama-config-format', required: false },
13
+ stream: { value: false },
14
+ keepAlive: { value: '5m', required: false },
15
+ keepAliveType: { value: 'str', required: false },
10
16
  tools: { value: '', type: 'ollama-config-tools', required: false },
17
+ options: { value: '', type: 'ollama-config-options', required: false },
11
18
  },
12
19
  inputs: 1,
13
20
  outputs: 1,
14
21
  icon: 'ollama.png',
15
22
  label: function() {
16
- return this.name || 'ollama-chat';
23
+ return this.name || 'ollama-chat'
17
24
  },
25
+ oneditprepare: function() {
26
+ if( !this.modelType ) {
27
+ this.modelType = 'str'
28
+ }
29
+
30
+ $( '#node-input-model' ).typedInput( {
31
+ type: 'str',
32
+ types: [ 'str', 'msg', 'flow', 'global' ],
33
+ typeField: '#node-input-modelType'
34
+ } )
35
+
36
+ if( !this.messagesType ) {
37
+ this.messagesType = 'msg'
38
+ }
39
+
40
+ $( '#node-input-messages' ).typedInput( {
41
+ type: 'msg',
42
+ types: [ 'msg', 'flow', 'global', 'json' ],
43
+ typeField: '#node-input-messagesType'
44
+ } )
45
+
46
+ if( !this.keepAliveType ) {
47
+ this.keepAliveType = 'str'
48
+ }
49
+
50
+ $( '#node-input-keepAlive' ).typedInput( {
51
+ type: 'str',
52
+ types: [ 'str', 'num' ],
53
+ typeField: '#node-input-keepAliveType'
54
+ } )
55
+ }
18
56
  } )
19
57
  </script>
20
58
 
@@ -30,8 +68,15 @@
30
68
  </div>
31
69
 
32
70
  <div class="form-row">
33
- <label for="node-input-model"><i class="fa fa-bookmark"></i> Model</label>
71
+ <label for="node-input-model"><i class="fa fa-comment"></i> Model</label>
34
72
  <input type="text" id="node-input-model" />
73
+ <input type="hidden" id="node-input-modelType" />
74
+ </div>
75
+
76
+ <div class="form-row">
77
+ <label for="node-input-messages"><i class="fa fa-comment"></i> Messages</label>
78
+ <input type="text" id="node-input-messages" />
79
+ <input type="hidden" id="node-input-messagesType" />
35
80
  </div>
36
81
 
37
82
  <div class="form-row">
@@ -39,10 +84,26 @@
39
84
  <input type="text" id="node-input-format" />
40
85
  </div>
41
86
 
87
+ <div class="form-row">
88
+ <label for="node-input-stream"><i class="fa fa-cog"></i> Stream</label>
89
+ <input type="checkbox" id="node-input-stream" />
90
+ </div>
91
+
92
+ <div class="form-row">
93
+ <label for="node-input-keepAlive"><i class="fa fa-cog"></i> Keep Alive</label>
94
+ <input type="text" id="node-input-keepAlive" />
95
+ <input type="hidden" id="node-input-keepAliveType" />
96
+ </div>
97
+
42
98
  <div class="form-row">
43
99
  <label for="node-input-tools"><i class="fa fa-cog"></i> Tools</label>
44
100
  <input type="text" id="node-input-tools" />
45
101
  </div>
102
+
103
+ <div class="form-row">
104
+ <label for="node-input-options"><i class="fa fa-cog"></i> Options</label>
105
+ <input type="text" id="node-input-options" />
106
+ </div>
46
107
  </script>
47
108
 
48
109
  <script type="text/html" data-help-name="ollama-chat">
@@ -56,49 +117,44 @@
56
117
  </dt>
57
118
 
58
119
  <dd>
59
- The payload object.
120
+ The payload object is an alternative way to configure the node.<br />
121
+ Any properties in the payload object will override the node configuration.
60
122
 
61
123
  <dl class="message-properties">
62
124
  <dt class="optional">
63
125
  payload.host <span class="property-type">string</span>
64
126
  </dt>
65
- <dd>
66
- The host of the Ollama instance.<br />
67
- <em>Alternative to the <code>Server</code> field.</em>
68
- </dd>
127
+ <dd>The host of the Ollama instance.</dd>
69
128
 
70
129
  <dt class="optional">
71
130
  payload.model <span class="property-type">string</span>
72
131
  </dt>
73
- <dd>
74
- The model to use for generating the next message.<br />
75
- <em>Alternative to the <code>Model</code> field.</em>
76
- </dd>
132
+ <dd>The model to use for generating the next message.</dd>
77
133
 
78
- <dt>
134
+ <dt class="optional">
79
135
  payload.messages <span class="property-type">array</span>
80
136
  </dt>
81
137
  <dd>
82
- The chat history to use for generating the next message.<br />
138
+ The chat history to use for generating the next message.
83
139
 
84
140
  <h4>Message</h4>
85
141
  <dl class="message-properties">
86
- <dt>
142
+ <dt class="optional">
87
143
  role <span class="property-type">string</span>
88
144
  </dt>
89
145
  <dd>The role of the message sender ('user', 'system', or 'assistant').</dd>
90
146
 
91
- <dt>
147
+ <dt class="optional">
92
148
  content <span class="property-type">string</span>
93
149
  </dt>
94
150
  <dd>The content of the message.</dd>
95
151
 
96
- <dt>
152
+ <dt class="optional">
97
153
  images <span class="property-type">array</span>
98
154
  </dt>
99
155
  <dd>The images attached to the message, either as Uint8Array or base64 encoded strings.</dd>
100
156
 
101
- <dt>
157
+ <dt class="optional">
102
158
  tool_calls <span class="property-type">array</span>
103
159
  </dt>
104
160
  <dd>A list of tools the model wants to use.</dd>
@@ -108,15 +164,7 @@
108
164
  <dt class="optional">
109
165
  payload.format <span class="property-type">string</span>
110
166
  </dt>
111
- <dd>
112
- The format of the response (only <code>json</code> for now).<br />
113
- <em>Alternative to the <code>Format</code> field.</em>
114
- </dd>
115
-
116
- <dt class="optional">
117
- payload.stream <span class="property-type">boolean</span>
118
- </dt>
119
- <dd>When true an AsyncGenerator is returned.</dd>
167
+ <dd>The format of the response (only <code>json</code> for now).</dd>
120
168
 
121
169
  <dt class="optional">
122
170
  payload.keep_alive <span class="property-type">array</span>
@@ -128,8 +176,7 @@
128
176
  </dt>
129
177
  <dd>
130
178
  Tools for the model to use if supported.<br />
131
- Requires <code>stream</code> to be set to <code>false</code>.<br />
132
- <em>Alternative to the <code>Model</code> field.</em>
179
+ Requires <code>stream</code> to be set to <code>false</code>.
133
180
 
134
181
  <p>
135
182
  For more information, see the Ollama API documentation:<br />
@@ -141,144 +188,144 @@
141
188
  payload.options <span class="property-type">object</span>
142
189
  </dt>
143
190
  <dd>
144
- Options to configure the runtime.<br />
191
+ Options to configure the runtime.
145
192
 
146
193
  <h4>Options</h4>
147
194
  <dl class="message-properties">
148
- <dt>
195
+ <dt class="optional">
149
196
  numa <span class="property-type">boolean</span>
150
197
  </dt>
151
198
  <dd>Use NUMA for the runtime.</dd>
152
199
 
153
- <dt>
200
+ <dt class="optional">
154
201
  num_ctx <span class="property-type">number</span>
155
202
  </dt>
156
203
  <dd>The number of contexts to use.</dd>
157
204
 
158
- <dt>
205
+ <dt class="optional">
159
206
  num_batch <span class="property-type">number</span>
160
207
  </dt>
161
208
  <dd>The number of batches to use.</dd>
162
209
 
163
- <dt>
210
+ <dt class="optional">
164
211
  main_gpu <span class="property-type">number</span>
165
212
  </dt>
166
213
  <dd>The main GPU to use.</dd>
167
214
 
168
- <dt>
215
+ <dt class="optional">
169
216
  low_vram <span class="property-type">boolean</span>
170
217
  </dt>
171
218
  <dd>Use low VRAM.</dd>
172
219
 
173
- <dt>
220
+ <dt class="optional">
174
221
  f16_kv <span class="property-type">boolean</span>
175
222
  </dt>
176
223
  <dd>Use f16 key-value.</dd>
177
224
 
178
- <dt>
225
+ <dt class="optional">
179
226
  logits_all <span class="property-type">boolean</span>
180
227
  </dt>
181
228
  <dd>Return all logits.</dd>
182
229
 
183
- <dt>
230
+ <dt class="optional">
184
231
  vocab_only <span class="property-type">boolean</span>
185
232
  </dt>
186
233
  <dd>Return only the vocabulary.</dd>
187
234
 
188
- <dt>
235
+ <dt class="optional">
189
236
  use_nmap <span class="property-type">boolean</span>
190
237
  </dt>
191
238
  <dd>Use NMAP.</dd>
192
239
 
193
- <dt>
240
+ <dt class="optional">
194
241
  use_mlock <span class="property-type">boolean</span>
195
242
  </dt>
196
243
  <dd>Use mlock.</dd>
197
244
 
198
- <dt>
245
+ <dt class="optional">
199
246
  embedding_only <span class="property-type">boolean</span>
200
247
  </dt>
201
248
  <dd>Return only the embeddings.</dd>
202
249
 
203
- <dt>
250
+ <dt class="optional">
204
251
  num_thread <span class="property-type">number</span>
205
252
  </dt>
206
253
  <dd>The number of threads to use.</dd>
207
254
 
208
- <dt>
255
+ <dt class="optional">
209
256
  num_keep <span class="property-type">number</span>
210
257
  </dt>
211
258
  <dd>The number of models to keep.</dd>
212
259
 
213
- <dt>
260
+ <dt class="optional">
214
261
  seed <span class="property-type">number</span>
215
262
  </dt>
216
263
  <dd>The seed to use.</dd>
217
264
 
218
- <dt>
265
+ <dt class="optional">
219
266
  num_predict <span class="property-type">number</span>
220
267
  </dt>
221
268
  <dd>The number of predictions to use.</dd>
222
269
 
223
- <dt>
270
+ <dt class="optional">
224
271
  top_k <span class="property-type">number</span>
225
272
  </dt>
226
273
  <dd>The top k to use.</dd>
227
274
 
228
- <dt>
275
+ <dt class="optional">
229
276
  top_p <span class="property-type">number</span>
230
277
  </dt>
231
278
  <dd>The top p to use.</dd>
232
279
 
233
- <dt>
280
+ <dt class="optional">
234
281
  typical_p <span class="property-type">number</span>
235
282
  </dt>
236
283
  <dd>The typical p to use.</dd>
237
284
 
238
- <dt>
285
+ <dt class="optional">
239
286
  repeat_last_n <span class="property-type">number</span>
240
287
  </dt>
241
288
  <dd>The repeat last n to use.</dd>
242
289
 
243
- <dt>
290
+ <dt class="optional">
244
291
  temperature <span class="property-type">number</span>
245
292
  </dt>
246
293
  <dd>The temperature to use.</dd>
247
294
 
248
- <dt>
295
+ <dt class="optional">
249
296
  repeat_pentalty <span class="property-type">number</span>
250
297
  </dt>
251
298
  <dd>The repeat pentalty to use.</dd>
252
299
 
253
- <dt>
300
+ <dt class="optional">
254
301
  presence_penalty <span class="property-type">number</span>
255
302
  </dt>
256
303
  <dd>The presence penalty to use.</dd>
257
304
 
258
- <dt>
305
+ <dt class="optional">
259
306
  frequency_penalty <span class="property-type">number</span>
260
307
  </dt>
261
308
  <dd>The frequency penalty to use.</dd>
262
309
 
263
- <dt>
310
+ <dt class="optional">
264
311
  mirostat <span class="property-type">boolean</span>
265
312
  </dt>
266
313
  <dd>Use mirostat.</dd>
267
314
 
268
- <dt>
315
+ <dt class="optional">
269
316
  mirostat_tau <span class="property-type">number</span>
270
317
  </dt>
271
318
 
272
- <dt>
319
+ <dt class="optional">
273
320
  mirostat_eta <span class="property-type">number</span>
274
321
  </dt>
275
322
 
276
- <dt>
323
+ <dt class="optional">
277
324
  penalize_newline <span class="property-type">boolean</span>
278
325
  </dt>
279
326
  <dd>Penalize newline.</dd>
280
327
 
281
- <dt>
328
+ <dt class="optional">
282
329
  stop <span class="property-type">array</span>
283
330
  </dt>
284
331
  <dd>The stop to use.</dd>
@@ -3,33 +3,70 @@ module.exports = function( RED ) {
3
3
 
4
4
  function OllamaChatNode( config ) {
5
5
  RED.nodes.createNode( this, config )
6
- const node = this
7
6
 
8
- node.on( 'input', async function( msg ) {
9
- const {
10
- host: payloadHost,
11
- model: payloadModel,
12
- messages,
13
- format: payloadFormat,
14
- stream,
15
- keep_alive,
16
- tools: payloadTools,
17
- options
18
- } = msg.payload
7
+ this.modelType = config.modelType || 'str'
8
+ this.messagesType = config.messagesType || 'msg'
9
+ this.stream = config.stream || false
10
+ this.keepAliveType = config.keepAliveType || 'str'
19
11
 
12
+ const node = this
13
+ node.on( 'input', async function( msg ) {
20
14
  const server = RED.nodes.getNode( config.server )
21
- const host = ( server ) ? server.host + ':' + server.port : payloadHost
15
+ const host = msg?.payload?.host || ( server ) ? server.host + ':' + server.port : null
22
16
 
23
17
  const ollama = new Ollama( { host } )
24
18
 
25
- const modelConfig = RED.nodes.getNode( config.model )
26
- const model = ( modelConfig ) ? modelConfig.name : payloadModel
19
+ let model = null
20
+ if( msg?.payload?.model ) {
21
+ model = msg?.payload?.model
22
+ } else if( !!config.model ) {
23
+ if( node.modelType === 'str' ) {
24
+ model = config.model
25
+ } else if( node.modelType === 'msg' ) {
26
+ model = msg[ config.model ]
27
+ } else if( node.modelType === 'flow' ) {
28
+ model = node.context().flow.get( config.model )
29
+ } else if( node.modelType === 'global' ) {
30
+ model = node.context().global.get( config.model )
31
+ }
32
+ }
33
+
34
+ let messages = null
35
+ if( msg?.payload?.messages ) {
36
+ messages = msg?.payload?.messages
37
+ } else if( !!config.messages ) {
38
+ if( node.messagesType === 'msg' ) {
39
+ messages = msg[ config.messages ]
40
+ } else if( node.messagesType === 'flow' ) {
41
+ messages = node.context().flow.get( config.messages )
42
+ } else if( node.messagesType === 'global' ) {
43
+ messages = node.context().global.get( config.messages )
44
+ } else if( node.messagesType === 'json' ) {
45
+ messages = JSON.parse( config.messages )
46
+ }
47
+ }
27
48
 
28
49
  const formatConfig = RED.nodes.getNode( config.format )
29
- const format = ( formatConfig ) ? formatConfig.json : payloadFormat
50
+ const format = msg?.payload?.format || ( formatConfig ) ? formatConfig.json : null
51
+
52
+ const stream = ( msg?.payload?.stream !== undefined ) ? msg?.payload?.stream : node.stream
53
+
54
+ let keep_alive = null
55
+ if( msg?.payload?.keep_alive ) {
56
+ keep_alive = msg?.payload?.keep_alive
57
+ } else if( !!config.keepAlive ) {
58
+ if( node.keepAliveType === 'str' ) {
59
+ keep_alive = config.keepAlive
60
+ } else if( node.keepAliveType === 'num' ) {
61
+ keep_alive = Number( config.keepAlive )
62
+ }
63
+ }
30
64
 
31
65
  const toolsConfig = RED.nodes.getNode( config.tools )
32
- const tools = ( toolsConfig ) ? toolsConfig.json : payloadTools
66
+ const tools = msg?.payload?.tools || ( toolsConfig ) ? JSON.parse( toolsConfig.json ) : null
67
+
68
+ const optionsConfig = RED.nodes.getNode( config.options )
69
+ const options = msg?.payload?.options || ( optionsConfig ) ? JSON.parse( optionsConfig.json ) : null
33
70
 
34
71
  const response = await ollama.chat( {
35
72
  model,
@@ -0,0 +1,25 @@
1
+ <script type="text/javascript">
2
+ RED.nodes.registerType( 'ollama-config-options', {
3
+ category: 'config',
4
+ defaults: {
5
+ name: { value: 'Ollama Options Config' },
6
+ json: { value: '' }
7
+ },
8
+ label: function() {
9
+ return this.name;
10
+ },
11
+ oneditprepare: function() {
12
+ $( '#node-config-input-json' ).typedInput( {
13
+ type: 'json',
14
+ types: [ 'json' ]
15
+ } )
16
+ }
17
+ } )
18
+ </script>
19
+
20
+ <script type="text/html" data-template-name="ollama-config-options">
21
+ <div class="form-row">
22
+ <label for="node-config-input-json"><i class="fa fa-server"></i> JSON</label>
23
+ <input type="text" id="node-config-input-json" />
24
+ </div>
25
+ </script>
@@ -0,0 +1,10 @@
1
+ module.exports = function( RED ) {
2
+ function OllamaConfigOptionsNode( config ) {
3
+ RED.nodes.createNode( this, config )
4
+
5
+ this.name = config.name
6
+ this.json = config.json
7
+ }
8
+
9
+ RED.nodes.registerType( 'ollama-config-options', OllamaConfigOptionsNode )
10
+ }
@@ -4,14 +4,39 @@
4
4
  color: 'rgb(186 230 253)',
5
5
  defaults: {
6
6
  name: { value: 'Ollama Copy' },
7
- server: { value: '', type: 'ollama-config-server', required: false }
7
+ server: { value: '', type: 'ollama-config-server', required: false },
8
+ source: { value: '', required: true },
9
+ sourceType: { value: 'str' },
10
+ destination: { value: '', required: true },
11
+ destinationType: { value: 'str' },
8
12
  },
9
13
  inputs: 1,
10
14
  outputs: 1,
11
15
  icon: 'ollama.png',
12
16
  label: function() {
13
- return this.name || 'ollama-copy';
17
+ return this.name || 'ollama-copy'
14
18
  },
19
+ oneditprepare: function() {
20
+ if( !this.sourceType ) {
21
+ this.sourceType = 'msg'
22
+ }
23
+
24
+ $( '#node-input-source' ).typedInput( {
25
+ type: 'str',
26
+ types: [ 'str', 'msg', 'flow', 'global' ],
27
+ typeField: '#node-input-sourceType'
28
+ } )
29
+
30
+ if( !this.destinationType ) {
31
+ this.destinationType = 'msg'
32
+ }
33
+
34
+ $( '#node-input-destination' ).typedInput( {
35
+ type: 'str',
36
+ types: [ 'str', 'msg', 'flow', 'global' ],
37
+ typeField: '#node-input-destinationType'
38
+ } )
39
+ }
15
40
  } )
16
41
  </script>
17
42
 
@@ -25,6 +50,18 @@
25
50
  <label for="node-input-server"><i class="fa fa-server"></i> Server</label>
26
51
  <input type="text" id="node-input-server" />
27
52
  </div>
53
+
54
+ <div class="form-row">
55
+ <label for="node-input-source"><i class="fa fa-comment"></i> Source</label>
56
+ <input type="text" id="node-input-source" />
57
+ <input type="hidden" id="node-input-sourceType" />
58
+ </div>
59
+
60
+ <div class="form-row">
61
+ <label for="node-input-destination"><i class="fa fa-comment"></i> Destination</label>
62
+ <input type="text" id="node-input-destination" />
63
+ <input type="hidden" id="node-input-destinationType" />
64
+ </div>
28
65
  </script>
29
66
 
30
67
  <script type="text/html" data-help-name="ollama-copy">
@@ -38,23 +75,21 @@
38
75
  </dt>
39
76
 
40
77
  <dd>
41
- The payload object.
78
+ The payload object is an alternative way to configure the node.<br />
79
+ Any properties in the payload object will override the node configuration.
42
80
 
43
81
  <dl class="message-properties">
44
82
  <dt class="optional">
45
83
  payload.host <span class="property-type">string</span>
46
84
  </dt>
47
- <dd>
48
- The host of the Ollama instance.<br />
49
- <em>Alternative to the <code>Server</code> field.</em>
50
- </dd>
85
+ <dd>The host of the Ollama instance.</dd>
51
86
 
52
- <dt>
87
+ <dt class="optional">
53
88
  payload.source <span class="property-type">string</span>
54
89
  </dt>
55
90
  <dd>The name of the model to copy.</dd>
56
91
 
57
- <dt>
92
+ <dt class="optional">
58
93
  payload.destination <span class="property-type">string</span>
59
94
  </dt>
60
95
  <dd>The name of the new model.</dd>