node-red-contrib-ollama 0.6.0 → 0.6.1
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.
- package/CHANGELOG.md +6 -0
- package/nodes/ollama-create.html +60 -76
- package/nodes/ollama-create.js +44 -125
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,12 @@ All notable changes to this project will be documented in this file.
|
|
|
4
4
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
|
6
6
|
|
|
7
|
+
## [0.6.1] - 2026-09-13
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
|
|
11
|
+
- `ollama-create` node configuration fields (model, from, quantize, template, license, system, parameters, messages, adapters) were never actually used — only `msg.payload` overrides worked. Switched to `RED.util.evaluateNodeProperty` and fixed the node's `typedInput` setup. Also removed dead `this.editor` references that threw on every save/cancel, made `parameters` a proper JSON field, and made `quantize` optional ([#32](https://github.com/jakubburkiewicz/node-red-contrib-ollama/pull/32), thanks @gorenje).
|
|
12
|
+
|
|
7
13
|
## [0.6.0] - 2026-09-13
|
|
8
14
|
|
|
9
15
|
### Added
|
package/nodes/ollama-create.html
CHANGED
|
@@ -3,92 +3,76 @@
|
|
|
3
3
|
category: 'AI',
|
|
4
4
|
color: 'rgb(186 230 253)',
|
|
5
5
|
defaults: {
|
|
6
|
-
name: { value: '
|
|
6
|
+
name: { value: '' },
|
|
7
7
|
server: { value: '', type: 'ollama-config-server', required: false },
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
8
|
+
stream: { value: false, required: false },
|
|
9
|
+
|
|
10
|
+
model: { value: '', required: true },
|
|
11
|
+
modelType: { value: "str" },
|
|
12
|
+
|
|
13
|
+
from: { value: '', required: true },
|
|
14
|
+
fromType: { value: "str" },
|
|
15
|
+
|
|
16
|
+
quantize: { value: '', required: false },
|
|
17
|
+
quantizeType: { value: "str" },
|
|
18
|
+
|
|
19
|
+
template: { value: '', required: false },
|
|
20
|
+
templateType: { value: "str" },
|
|
21
|
+
|
|
22
|
+
license: { value: '', required: false },
|
|
23
|
+
licenseType: { value: "str" },
|
|
24
|
+
|
|
25
|
+
system: { value: '', required: false },
|
|
26
|
+
systemType: { value: "str" },
|
|
27
|
+
|
|
28
|
+
parameters: { value: '{}', required: false },
|
|
29
|
+
parametersType: { value: "json" },
|
|
30
|
+
|
|
31
|
+
messages: { value: '', required: false },
|
|
32
|
+
messagesType: { value: "str" },
|
|
33
|
+
|
|
34
|
+
adapters: { value: '', required: false },
|
|
35
|
+
adaptersType: { value: "str" }
|
|
18
36
|
},
|
|
19
37
|
inputs: 1,
|
|
20
38
|
outputs: 1,
|
|
21
39
|
icon: 'ollama.png',
|
|
22
40
|
label: function() {
|
|
23
|
-
return this.name || 'ollama-create';
|
|
41
|
+
return this.name || (this.modelType === 'str' && this.model) || 'ollama-create';
|
|
24
42
|
},
|
|
43
|
+
|
|
25
44
|
oneditprepare: function() {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
typeField: '#node-input-templateType'
|
|
52
|
-
} )
|
|
53
|
-
|
|
54
|
-
$( '#node-input-license' ).typedInput( {
|
|
55
|
-
type: 'str',
|
|
56
|
-
types: [ 'str', 'msg', 'flow', 'global' ],
|
|
57
|
-
typeField: '#node-input-licenseType'
|
|
58
|
-
} )
|
|
59
|
-
|
|
60
|
-
$( '#node-input-system' ).typedInput( {
|
|
61
|
-
type: 'str',
|
|
62
|
-
types: [ 'str', 'msg', 'flow', 'global' ],
|
|
63
|
-
typeField: '#node-input-systemType'
|
|
64
|
-
} )
|
|
65
|
-
|
|
66
|
-
$( '#node-input-parameters' ).typedInput( {
|
|
67
|
-
type: 'str',
|
|
68
|
-
types: [ 'str', 'msg', 'flow', 'global' ],
|
|
69
|
-
typeField: '#node-input-parametersType'
|
|
70
|
-
} )
|
|
71
|
-
|
|
72
|
-
$( '#node-input-messages' ).typedInput( {
|
|
73
|
-
type: 'str',
|
|
74
|
-
types: [ 'str', 'msg', 'flow', 'global' ],
|
|
75
|
-
typeField: '#node-input-messagesType'
|
|
76
|
-
} )
|
|
77
|
-
|
|
78
|
-
$( '#node-input-adapters' ).typedInput( {
|
|
79
|
-
type: 'str',
|
|
80
|
-
types: [ 'str', 'msg', 'flow', 'global' ],
|
|
81
|
-
typeField: '#node-input-adaptersType'
|
|
82
|
-
} )
|
|
45
|
+
[
|
|
46
|
+
"model",
|
|
47
|
+
"from",
|
|
48
|
+
"quantize",
|
|
49
|
+
"template",
|
|
50
|
+
"license",
|
|
51
|
+
"system",
|
|
52
|
+
"messages",
|
|
53
|
+
"adapters"
|
|
54
|
+
].forEach( parameter => {
|
|
55
|
+
$( `#node-input-${parameter}` ).typedInput( {
|
|
56
|
+
types: [ 'str', 'msg', 'flow', 'global' ],
|
|
57
|
+
typeField: `#node-input-${parameter}Type`
|
|
58
|
+
})
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
// not 'str' but 'json'
|
|
62
|
+
[
|
|
63
|
+
"parameters"
|
|
64
|
+
].forEach( parameter => {
|
|
65
|
+
$( `#node-input-${parameter}` ).typedInput( {
|
|
66
|
+
types: [ 'json', 'msg', 'flow', 'global' ],
|
|
67
|
+
typeField: `#node-input-${parameter}Type`
|
|
68
|
+
})
|
|
69
|
+
});
|
|
83
70
|
},
|
|
71
|
+
|
|
84
72
|
oneditsave: function() {
|
|
85
|
-
this.modelfile = this.editor.getValue()
|
|
86
|
-
this.editor.destroy()
|
|
87
|
-
delete this.editor
|
|
88
73
|
},
|
|
74
|
+
|
|
89
75
|
oneditcancel: function() {
|
|
90
|
-
this.editor.destroy()
|
|
91
|
-
delete this.editor
|
|
92
76
|
}
|
|
93
77
|
} )
|
|
94
78
|
</script>
|
|
@@ -117,7 +101,7 @@
|
|
|
117
101
|
</div>
|
|
118
102
|
|
|
119
103
|
<div class="form-row">
|
|
120
|
-
<label for="node-input-stream"><i class="fa fa-
|
|
104
|
+
<label for="node-input-stream"><i class="fa fa-umbrella"></i> Stream</label>
|
|
121
105
|
<input type="checkbox" id="node-input-stream" />
|
|
122
106
|
</div>
|
|
123
107
|
|
|
@@ -128,7 +112,7 @@
|
|
|
128
112
|
</div>
|
|
129
113
|
|
|
130
114
|
<div class="form-row">
|
|
131
|
-
<label for="node-input-template"><i class="fa fa-file-code"></i> Template</label>
|
|
115
|
+
<label for="node-input-template"><i class="fa fa-file-code-o"></i> Template</label>
|
|
132
116
|
<input type="text" id="node-input-template" />
|
|
133
117
|
<input type="hidden" id="node-input-templateType" />
|
|
134
118
|
</div>
|
package/nodes/ollama-create.js
CHANGED
|
@@ -4,19 +4,9 @@ module.exports = function( RED ) {
|
|
|
4
4
|
function OllamaCreateNode( config ) {
|
|
5
5
|
RED.nodes.createNode( this, config )
|
|
6
6
|
|
|
7
|
-
this.modelType = config.modelType || 'str'
|
|
8
|
-
this.fromType = config.from || 'str'
|
|
9
|
-
this.stream = config.stream || false
|
|
10
|
-
this.quantize = config.quantize || 'str'
|
|
11
|
-
this.template = config.template || null
|
|
12
|
-
this.license = config.license || null
|
|
13
|
-
this.system = config.system || null
|
|
14
|
-
this.parameters = config.parameters || 'str'
|
|
15
|
-
this.messages = config.messages || 'str'
|
|
16
|
-
this.adapters = config.adapters || 'str'
|
|
17
|
-
this.pathType = config.pathType || 'str'
|
|
18
|
-
|
|
19
7
|
const node = this
|
|
8
|
+
const cfg = config
|
|
9
|
+
|
|
20
10
|
node.on( 'input', async function( msg ) {
|
|
21
11
|
const server = RED.nodes.getNode( config.server )
|
|
22
12
|
|
|
@@ -55,163 +45,92 @@ module.exports = function( RED ) {
|
|
|
55
45
|
}
|
|
56
46
|
}
|
|
57
47
|
|
|
58
|
-
const
|
|
48
|
+
const stream = (msg?.payload?.stream !== undefined) ? msg.payload.stream : cfg.stream
|
|
59
49
|
|
|
60
50
|
let model = null
|
|
61
51
|
if( msg?.payload?.model ) {
|
|
62
|
-
model = msg
|
|
63
|
-
} else
|
|
64
|
-
|
|
65
|
-
model = config.model
|
|
66
|
-
} else if( node.modelType === 'msg' ) {
|
|
67
|
-
model = msg[ config.model ]
|
|
68
|
-
} else if( node.modelType === 'flow' ) {
|
|
69
|
-
model = node.context().flow.get( config.model )
|
|
70
|
-
} else if( node.modelType === 'global' ) {
|
|
71
|
-
model = node.context().global.get( config.model )
|
|
72
|
-
}
|
|
52
|
+
model = msg.payload.model
|
|
53
|
+
} else {
|
|
54
|
+
model = RED.util.evaluateNodeProperty(cfg.model, cfg.modelType, node, msg)
|
|
73
55
|
}
|
|
74
56
|
|
|
75
57
|
let from = null
|
|
76
58
|
if( msg?.payload?.from ) {
|
|
77
|
-
from = msg
|
|
59
|
+
from = msg.payload.from
|
|
78
60
|
} else if( !!config.from ) {
|
|
79
|
-
|
|
80
|
-
from = config.from
|
|
81
|
-
} else if( node.fromType === 'msg' ) {
|
|
82
|
-
from = msg[ config.from ]
|
|
83
|
-
} else if( node.fromType === 'flow' ) {
|
|
84
|
-
from = node.context().flow.get( config.from )
|
|
85
|
-
} else if( node.fromType === 'global' ) {
|
|
86
|
-
from = node.context().global.get( config.from )
|
|
87
|
-
}
|
|
61
|
+
from = RED.util.evaluateNodeProperty(cfg.from, cfg.fromType, node, msg)
|
|
88
62
|
}
|
|
89
63
|
|
|
90
|
-
const stream = ( msg?.payload?.stream !== undefined ) ? msg?.payload?.stream : node.stream
|
|
91
|
-
|
|
92
64
|
let quantize = null
|
|
93
65
|
if( msg?.payload?.quantize ) {
|
|
94
|
-
quantize = msg
|
|
66
|
+
quantize = msg.payload.quantize
|
|
95
67
|
} else if( !!config.quantize ) {
|
|
96
|
-
|
|
97
|
-
quantize = config.quantize
|
|
98
|
-
} else if( node.quantize === 'msg' ) {
|
|
99
|
-
quantize = msg[ config.quantize ]
|
|
100
|
-
} else if( node.quantize === 'flow' ) {
|
|
101
|
-
quantize = node.context().flow.get( config.quantize )
|
|
102
|
-
} else if( node.quantize === 'global' ) {
|
|
103
|
-
quantize = node.context().global.get( config.quantize )
|
|
104
|
-
}
|
|
68
|
+
quantize = RED.util.evaluateNodeProperty(cfg.quantize, cfg.quantizeType, node, msg)
|
|
105
69
|
}
|
|
106
70
|
|
|
107
71
|
let template = null
|
|
108
72
|
if( msg?.payload?.template ) {
|
|
109
|
-
template = msg
|
|
73
|
+
template = msg.payload.template
|
|
110
74
|
} else if( !!config.template ) {
|
|
111
|
-
|
|
112
|
-
template = config.template
|
|
113
|
-
} else if( node.template === 'msg' ) {
|
|
114
|
-
template = msg[ config.template ]
|
|
115
|
-
} else if( node.template === 'flow' ) {
|
|
116
|
-
template = node.context().flow.get( config.template )
|
|
117
|
-
} else if( node.template === 'global' ) {
|
|
118
|
-
template = node.context().global.get( config.template )
|
|
119
|
-
}
|
|
75
|
+
template = RED.util.evaluateNodeProperty(cfg.template, cfg.templateType, node, msg)
|
|
120
76
|
}
|
|
121
77
|
|
|
122
78
|
let license = null
|
|
123
79
|
if( msg?.payload?.license ) {
|
|
124
|
-
license = msg
|
|
80
|
+
license = msg.payload.license
|
|
125
81
|
} else if( !!config.license ) {
|
|
126
|
-
|
|
127
|
-
license = config.license
|
|
128
|
-
} else if( node.license === 'msg' ) {
|
|
129
|
-
license = msg[ config.license ]
|
|
130
|
-
} else if( node.license === 'flow' ) {
|
|
131
|
-
license = node.context().flow.get( config.license )
|
|
132
|
-
} else if( node.license === 'global' ) {
|
|
133
|
-
license = node.context().global.get( config.license )
|
|
134
|
-
}
|
|
82
|
+
license = RED.util.evaluateNodeProperty(cfg.license, cfg.licenseType, node, msg)
|
|
135
83
|
}
|
|
136
84
|
|
|
137
85
|
let system = null
|
|
138
86
|
if( msg?.payload?.system ) {
|
|
139
|
-
system = msg
|
|
87
|
+
system = msg.payload.system
|
|
140
88
|
} else if( !!config.system ) {
|
|
141
|
-
|
|
142
|
-
system = config.system
|
|
143
|
-
} else if( node.system === 'msg' ) {
|
|
144
|
-
system = msg[ config.system ]
|
|
145
|
-
} else if( node.system === 'flow' ) {
|
|
146
|
-
system = node.context().flow.get( config.system )
|
|
147
|
-
} else if( node.system === 'global' ) {
|
|
148
|
-
system = node.context().global.get( config.system )
|
|
149
|
-
}
|
|
89
|
+
system = RED.util.evaluateNodeProperty(cfg.system, cfg.systemType, node, msg)
|
|
150
90
|
}
|
|
151
91
|
|
|
152
92
|
let parameters = null
|
|
153
93
|
if( msg?.payload?.parameters ) {
|
|
154
|
-
parameters = msg
|
|
94
|
+
parameters = msg.payload.parameters
|
|
155
95
|
} else if( !!config.parameters ) {
|
|
156
|
-
|
|
157
|
-
parameters = config.parameters
|
|
158
|
-
} else if( node.parameters === 'msg' ) {
|
|
159
|
-
parameters = msg[ config.parameters ]
|
|
160
|
-
} else if( node.parameters === 'flow' ) {
|
|
161
|
-
parameters = node.context().flow.get( config.parameters )
|
|
162
|
-
} else if( node.parameters === 'global' ) {
|
|
163
|
-
parameters = node.context().global.get( config.parameters )
|
|
164
|
-
}
|
|
96
|
+
parameters = RED.util.evaluateNodeProperty(cfg.parameters, cfg.parametersType, node, msg)
|
|
165
97
|
}
|
|
166
98
|
|
|
167
99
|
let messages = null
|
|
168
100
|
if( msg?.payload?.messages ) {
|
|
169
|
-
messages = msg
|
|
101
|
+
messages = msg.payload.messages
|
|
170
102
|
} else if( !!config.messages ) {
|
|
171
|
-
|
|
172
|
-
messages = config.messages
|
|
173
|
-
} else if( node.messages === 'msg' ) {
|
|
174
|
-
messages = msg[ config.messages ]
|
|
175
|
-
} else if( node.messages === 'flow' ) {
|
|
176
|
-
messages = node.context().flow.get( config.messages )
|
|
177
|
-
} else if( node.messages === 'global' ) {
|
|
178
|
-
messages = node.context().global.get( config.messages )
|
|
179
|
-
}
|
|
103
|
+
messages = RED.util.evaluateNodeProperty(cfg.messages, cfg.messagesType, node, msg)
|
|
180
104
|
}
|
|
181
105
|
|
|
182
106
|
let adapters = null
|
|
183
107
|
if( msg?.payload?.adapters ) {
|
|
184
|
-
adapters = msg
|
|
108
|
+
adapters = msg.payload.adapters
|
|
185
109
|
} else if( !!config.adapters ) {
|
|
186
|
-
|
|
187
|
-
adapters = config.adapters
|
|
188
|
-
} else if( node.adapters === 'msg' ) {
|
|
189
|
-
adapters = msg[ config.adapters ]
|
|
190
|
-
} else if( node.adapters === 'flow' ) {
|
|
191
|
-
adapters = node.context().flow.get( config.adapters )
|
|
192
|
-
} else if( node.adapters === 'global' ) {
|
|
193
|
-
adapters = node.context().global.get( config.adapters )
|
|
194
|
-
}
|
|
110
|
+
adapters = RED.util.evaluateNodeProperty(cfg.adapters, cfg.adaptersType, node, msg)
|
|
195
111
|
}
|
|
196
|
-
|
|
197
|
-
const
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
112
|
+
|
|
113
|
+
const ollama = new Ollama(ollamaConfig)
|
|
114
|
+
|
|
115
|
+
ollama.create( {
|
|
116
|
+
model,
|
|
117
|
+
from,
|
|
118
|
+
stream,
|
|
119
|
+
quantize,
|
|
120
|
+
template,
|
|
121
|
+
license,
|
|
122
|
+
system,
|
|
123
|
+
parameters,
|
|
124
|
+
messages,
|
|
125
|
+
adapters
|
|
126
|
+
})
|
|
127
|
+
.then( response => {
|
|
128
|
+
msg.payload = response
|
|
129
|
+
node.send(msg)
|
|
130
|
+
})
|
|
131
|
+
.catch( error => {
|
|
132
|
+
node.error( error )
|
|
133
|
+
})
|
|
215
134
|
} )
|
|
216
135
|
}
|
|
217
136
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "node-red-contrib-ollama",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.1",
|
|
4
4
|
"description": "Add AI functionality to your flows! This module includes a set of nodes that enable easy communication with Ollama, enriching your projects with intelligent solutions.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ai",
|