@matbee/remotemedia-native 0.1.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.
- package/README.md +229 -0
- package/index.d.ts +717 -0
- package/index.js +138 -0
- package/node-schemas.json +343 -0
- package/node-schemas.ts +689 -0
- package/package.json +106 -0
- package/proto-utils.d.ts +97 -0
- package/proto-utils.js +376 -0
- package/remotemedia-native.x86_64-unknown-linux-gnu.node +0 -0
package/index.js
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
// @remotemedia/native - Node.js bindings for RemoteMedia zero-copy IPC
|
|
2
|
+
//
|
|
3
|
+
// This module provides zero-copy IPC between Node.js, Python, and Rust
|
|
4
|
+
// via iceoryx2 shared memory.
|
|
5
|
+
|
|
6
|
+
const { existsSync, readFileSync } = require('fs');
|
|
7
|
+
const { join } = require('path');
|
|
8
|
+
|
|
9
|
+
const { platform, arch } = process;
|
|
10
|
+
|
|
11
|
+
let nativeBinding = null;
|
|
12
|
+
let loadError = null;
|
|
13
|
+
|
|
14
|
+
// Platform-specific binary name mapping
|
|
15
|
+
function getPlatformTriple() {
|
|
16
|
+
const archMap = {
|
|
17
|
+
'x64': 'x86_64',
|
|
18
|
+
'arm64': 'aarch64',
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const platformMap = {
|
|
22
|
+
'darwin': 'apple-darwin',
|
|
23
|
+
'linux': 'unknown-linux-gnu',
|
|
24
|
+
'win32': 'pc-windows-msvc',
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const mappedArch = archMap[arch];
|
|
28
|
+
const mappedPlatform = platformMap[platform];
|
|
29
|
+
|
|
30
|
+
if (!mappedArch || !mappedPlatform) {
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return `${mappedArch}-${mappedPlatform}`;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Try to load the native binding
|
|
38
|
+
function loadNativeBinding() {
|
|
39
|
+
const triple = getPlatformTriple();
|
|
40
|
+
|
|
41
|
+
if (!triple) {
|
|
42
|
+
throw new Error(
|
|
43
|
+
`Unsupported platform: ${platform}-${arch}. ` +
|
|
44
|
+
`Supported platforms: darwin-x64, darwin-arm64, linux-x64, linux-arm64`
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Try loading from various locations
|
|
49
|
+
const candidates = [
|
|
50
|
+
// Local development build (with .node extension renamed from .so)
|
|
51
|
+
join(__dirname, '..', '..', '..', 'target', 'release', 'remotemedia_native.node'),
|
|
52
|
+
join(__dirname, '..', '..', '..', 'target', 'debug', 'remotemedia_native.node'),
|
|
53
|
+
// Original .so file (Linux)
|
|
54
|
+
join(__dirname, '..', '..', '..', 'target', 'release', 'libremotemedia_ffi.so'),
|
|
55
|
+
join(__dirname, '..', '..', '..', 'target', 'debug', 'libremotemedia_ffi.so'),
|
|
56
|
+
// Platform-specific builds (for npm distribution)
|
|
57
|
+
join(__dirname, `remotemedia-native.${triple}.node`),
|
|
58
|
+
join(__dirname, 'remotemedia-native.node'),
|
|
59
|
+
// Fallback to generic name
|
|
60
|
+
join(__dirname, 'index.node'),
|
|
61
|
+
];
|
|
62
|
+
|
|
63
|
+
for (const candidate of candidates) {
|
|
64
|
+
try {
|
|
65
|
+
if (existsSync(candidate)) {
|
|
66
|
+
return require(candidate);
|
|
67
|
+
}
|
|
68
|
+
} catch (e) {
|
|
69
|
+
// Continue to next candidate
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Try requiring without path (for globally installed)
|
|
74
|
+
try {
|
|
75
|
+
return require(`@remotemedia/native-${triple}`);
|
|
76
|
+
} catch (e) {
|
|
77
|
+
// Ignore
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
throw new Error(
|
|
81
|
+
`Failed to load native binding for ${platform}-${arch}. ` +
|
|
82
|
+
`Make sure you have built the native addon with 'npm run build'. ` +
|
|
83
|
+
`Tried: ${candidates.join(', ')}`
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
try {
|
|
88
|
+
nativeBinding = loadNativeBinding();
|
|
89
|
+
} catch (e) {
|
|
90
|
+
loadError = e;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Export all bindings
|
|
94
|
+
if (nativeBinding) {
|
|
95
|
+
module.exports = nativeBinding;
|
|
96
|
+
} else {
|
|
97
|
+
// Create stub exports that throw helpful errors
|
|
98
|
+
const createStub = (name) => () => {
|
|
99
|
+
throw loadError || new Error(`Native binding not loaded: ${name}`);
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
module.exports = {
|
|
103
|
+
// Session management
|
|
104
|
+
createSession: createStub('createSession'),
|
|
105
|
+
getSession: createStub('getSession'),
|
|
106
|
+
listSessions: createStub('listSessions'),
|
|
107
|
+
|
|
108
|
+
// Node management
|
|
109
|
+
createIpcNode: createStub('createIpcNode'),
|
|
110
|
+
|
|
111
|
+
// Classes (will throw on instantiation)
|
|
112
|
+
NapiSession: class { constructor() { createStub('NapiSession')(); } },
|
|
113
|
+
NapiChannel: class { constructor() { createStub('NapiChannel')(); } },
|
|
114
|
+
NapiPublisher: class { constructor() { createStub('NapiPublisher')(); } },
|
|
115
|
+
NapiSubscriber: class { constructor() { createStub('NapiSubscriber')(); } },
|
|
116
|
+
ReceivedSample: class { constructor() { createStub('ReceivedSample')(); } },
|
|
117
|
+
LoanedSample: class { constructor() { createStub('LoanedSample')(); } },
|
|
118
|
+
IpcNode: class { constructor() { createStub('IpcNode')(); } },
|
|
119
|
+
|
|
120
|
+
// RuntimeData helpers
|
|
121
|
+
parseRuntimeDataHeader: createStub('parseRuntimeDataHeader'),
|
|
122
|
+
|
|
123
|
+
// Error for debugging
|
|
124
|
+
_loadError: loadError,
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// Export type helpers
|
|
129
|
+
module.exports.isNativeLoaded = () => nativeBinding !== null;
|
|
130
|
+
module.exports.getLoadError = () => loadError;
|
|
131
|
+
|
|
132
|
+
// Export proto-utils (browser/Node.js compatible)
|
|
133
|
+
const protoUtils = require('./proto-utils');
|
|
134
|
+
module.exports.protoUtils = protoUtils;
|
|
135
|
+
module.exports.encodeTextData = protoUtils.encodeTextData;
|
|
136
|
+
module.exports.encodeJsonData = protoUtils.encodeJsonData;
|
|
137
|
+
module.exports.decodeDataBuffer = protoUtils.decodeDataBuffer;
|
|
138
|
+
module.exports.parseJsonFromDataBuffer = protoUtils.parseJsonFromDataBuffer;
|
|
@@ -0,0 +1,343 @@
|
|
|
1
|
+
[
|
|
2
|
+
{
|
|
3
|
+
"nodeType": "CalculatorNode",
|
|
4
|
+
"description": "Performs arithmetic operations on JSON input",
|
|
5
|
+
"category": "utility",
|
|
6
|
+
"accepts": [
|
|
7
|
+
"json"
|
|
8
|
+
],
|
|
9
|
+
"produces": [
|
|
10
|
+
"json"
|
|
11
|
+
],
|
|
12
|
+
"parameters": [
|
|
13
|
+
{
|
|
14
|
+
"name": "precision",
|
|
15
|
+
"paramType": "integer",
|
|
16
|
+
"description": "Decimal precision for results",
|
|
17
|
+
"defaultValue": "10",
|
|
18
|
+
"required": false
|
|
19
|
+
}
|
|
20
|
+
],
|
|
21
|
+
"configSchema": "{\"properties\":{\"precision\":{\"default\":10,\"description\":\"Decimal precision for results\",\"type\":\"integer\"}},\"type\":\"object\"}",
|
|
22
|
+
"isPython": false,
|
|
23
|
+
"streaming": true,
|
|
24
|
+
"multiOutput": false
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"nodeType": "WhisperNode",
|
|
28
|
+
"description": "Speech-to-text transcription using Whisper",
|
|
29
|
+
"category": "ml",
|
|
30
|
+
"accepts": [
|
|
31
|
+
"audio"
|
|
32
|
+
],
|
|
33
|
+
"produces": [
|
|
34
|
+
"text",
|
|
35
|
+
"json"
|
|
36
|
+
],
|
|
37
|
+
"parameters": [
|
|
38
|
+
{
|
|
39
|
+
"name": "language",
|
|
40
|
+
"paramType": "string",
|
|
41
|
+
"description": "Language code (null for auto-detect)",
|
|
42
|
+
"required": false
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
"name": "model",
|
|
46
|
+
"paramType": "string",
|
|
47
|
+
"description": "Whisper model size",
|
|
48
|
+
"defaultValue": "\"base\"",
|
|
49
|
+
"required": false,
|
|
50
|
+
"enumValues": "[\"tiny\",\"base\",\"small\",\"medium\",\"large\",\"large-v3\"]"
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
"name": "task",
|
|
54
|
+
"paramType": "string",
|
|
55
|
+
"description": "Task type",
|
|
56
|
+
"defaultValue": "\"transcribe\"",
|
|
57
|
+
"required": false,
|
|
58
|
+
"enumValues": "[\"transcribe\",\"translate\"]"
|
|
59
|
+
}
|
|
60
|
+
],
|
|
61
|
+
"configSchema": "{\"properties\":{\"language\":{\"description\":\"Language code (null for auto-detect)\",\"type\":\"string\"},\"model\":{\"default\":\"base\",\"description\":\"Whisper model size\",\"enum\":[\"tiny\",\"base\",\"small\",\"medium\",\"large\",\"large-v3\"],\"type\":\"string\"},\"task\":{\"default\":\"transcribe\",\"description\":\"Task type\",\"enum\":[\"transcribe\",\"translate\"],\"type\":\"string\"}},\"type\":\"object\"}",
|
|
62
|
+
"isPython": true,
|
|
63
|
+
"streaming": true,
|
|
64
|
+
"multiOutput": false,
|
|
65
|
+
"capabilities": {
|
|
66
|
+
"parallelizable": false,
|
|
67
|
+
"batchAware": true,
|
|
68
|
+
"supportsControl": false,
|
|
69
|
+
"latencyClass": 4
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
"nodeType": "AudioChunker",
|
|
74
|
+
"description": "Splits audio into fixed-size chunks",
|
|
75
|
+
"category": "audio",
|
|
76
|
+
"accepts": [
|
|
77
|
+
"audio"
|
|
78
|
+
],
|
|
79
|
+
"produces": [
|
|
80
|
+
"audio"
|
|
81
|
+
],
|
|
82
|
+
"parameters": [
|
|
83
|
+
{
|
|
84
|
+
"name": "chunk_size_ms",
|
|
85
|
+
"paramType": "integer",
|
|
86
|
+
"description": "Chunk duration in milliseconds",
|
|
87
|
+
"defaultValue": "20",
|
|
88
|
+
"required": false
|
|
89
|
+
}
|
|
90
|
+
],
|
|
91
|
+
"configSchema": "{\"properties\":{\"chunk_size_ms\":{\"default\":20,\"description\":\"Chunk duration in milliseconds\",\"type\":\"integer\"}},\"type\":\"object\"}",
|
|
92
|
+
"isPython": false,
|
|
93
|
+
"streaming": true,
|
|
94
|
+
"multiOutput": true
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
"nodeType": "PassThrough",
|
|
98
|
+
"description": "Passes input through unchanged",
|
|
99
|
+
"category": "utility",
|
|
100
|
+
"accepts": [
|
|
101
|
+
"audio",
|
|
102
|
+
"video",
|
|
103
|
+
"json",
|
|
104
|
+
"text",
|
|
105
|
+
"binary",
|
|
106
|
+
"tensor",
|
|
107
|
+
"numpy",
|
|
108
|
+
"controlmessage"
|
|
109
|
+
],
|
|
110
|
+
"produces": [
|
|
111
|
+
"audio",
|
|
112
|
+
"video",
|
|
113
|
+
"json",
|
|
114
|
+
"text",
|
|
115
|
+
"binary",
|
|
116
|
+
"tensor",
|
|
117
|
+
"numpy",
|
|
118
|
+
"controlmessage"
|
|
119
|
+
],
|
|
120
|
+
"parameters": [],
|
|
121
|
+
"isPython": false,
|
|
122
|
+
"streaming": true,
|
|
123
|
+
"multiOutput": false
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
"nodeType": "TextCollector",
|
|
127
|
+
"description": "Collects text chunks into complete utterances",
|
|
128
|
+
"category": "text",
|
|
129
|
+
"accepts": [
|
|
130
|
+
"text"
|
|
131
|
+
],
|
|
132
|
+
"produces": [
|
|
133
|
+
"text"
|
|
134
|
+
],
|
|
135
|
+
"parameters": [
|
|
136
|
+
{
|
|
137
|
+
"name": "delimiter",
|
|
138
|
+
"paramType": "string",
|
|
139
|
+
"description": "Delimiter to split on",
|
|
140
|
+
"defaultValue": "\"\"",
|
|
141
|
+
"required": false
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
"name": "flush_on_silence",
|
|
145
|
+
"paramType": "boolean",
|
|
146
|
+
"description": "Flush buffer when silence detected",
|
|
147
|
+
"defaultValue": "true",
|
|
148
|
+
"required": false
|
|
149
|
+
}
|
|
150
|
+
],
|
|
151
|
+
"configSchema": "{\"properties\":{\"delimiter\":{\"default\":\"\",\"description\":\"Delimiter to split on\",\"type\":\"string\"},\"flush_on_silence\":{\"default\":true,\"description\":\"Flush buffer when silence detected\",\"type\":\"boolean\"}},\"type\":\"object\"}",
|
|
152
|
+
"isPython": false,
|
|
153
|
+
"streaming": true,
|
|
154
|
+
"multiOutput": false
|
|
155
|
+
},
|
|
156
|
+
{
|
|
157
|
+
"nodeType": "Echo",
|
|
158
|
+
"description": "Passes input through unchanged (for testing)",
|
|
159
|
+
"category": "utility",
|
|
160
|
+
"accepts": [
|
|
161
|
+
"audio",
|
|
162
|
+
"video",
|
|
163
|
+
"json",
|
|
164
|
+
"text",
|
|
165
|
+
"binary",
|
|
166
|
+
"tensor",
|
|
167
|
+
"numpy",
|
|
168
|
+
"controlmessage"
|
|
169
|
+
],
|
|
170
|
+
"produces": [
|
|
171
|
+
"audio",
|
|
172
|
+
"video",
|
|
173
|
+
"json",
|
|
174
|
+
"text",
|
|
175
|
+
"binary",
|
|
176
|
+
"tensor",
|
|
177
|
+
"numpy",
|
|
178
|
+
"controlmessage"
|
|
179
|
+
],
|
|
180
|
+
"parameters": [],
|
|
181
|
+
"isPython": false,
|
|
182
|
+
"streaming": true,
|
|
183
|
+
"multiOutput": false
|
|
184
|
+
},
|
|
185
|
+
{
|
|
186
|
+
"nodeType": "SileroVAD",
|
|
187
|
+
"description": "Voice Activity Detection using Silero VAD model",
|
|
188
|
+
"category": "audio",
|
|
189
|
+
"accepts": [
|
|
190
|
+
"audio"
|
|
191
|
+
],
|
|
192
|
+
"produces": [
|
|
193
|
+
"audio",
|
|
194
|
+
"controlmessage"
|
|
195
|
+
],
|
|
196
|
+
"parameters": [
|
|
197
|
+
{
|
|
198
|
+
"name": "min_silence_duration_ms",
|
|
199
|
+
"paramType": "integer",
|
|
200
|
+
"description": "Minimum silence duration in ms",
|
|
201
|
+
"defaultValue": "100",
|
|
202
|
+
"required": false
|
|
203
|
+
},
|
|
204
|
+
{
|
|
205
|
+
"name": "min_speech_duration_ms",
|
|
206
|
+
"paramType": "integer",
|
|
207
|
+
"description": "Minimum speech duration in ms",
|
|
208
|
+
"defaultValue": "250",
|
|
209
|
+
"required": false
|
|
210
|
+
},
|
|
211
|
+
{
|
|
212
|
+
"name": "threshold",
|
|
213
|
+
"paramType": "number",
|
|
214
|
+
"description": "Speech probability threshold",
|
|
215
|
+
"defaultValue": "0.5",
|
|
216
|
+
"required": false,
|
|
217
|
+
"minimum": 0,
|
|
218
|
+
"maximum": 1
|
|
219
|
+
}
|
|
220
|
+
],
|
|
221
|
+
"configSchema": "{\"properties\":{\"min_silence_duration_ms\":{\"default\":100,\"description\":\"Minimum silence duration in ms\",\"type\":\"integer\"},\"min_speech_duration_ms\":{\"default\":250,\"description\":\"Minimum speech duration in ms\",\"type\":\"integer\"},\"threshold\":{\"default\":0.5,\"description\":\"Speech probability threshold\",\"maximum\":1.0,\"minimum\":0.0,\"type\":\"number\"}},\"type\":\"object\"}",
|
|
222
|
+
"isPython": false,
|
|
223
|
+
"streaming": true,
|
|
224
|
+
"multiOutput": false,
|
|
225
|
+
"capabilities": {
|
|
226
|
+
"parallelizable": true,
|
|
227
|
+
"batchAware": false,
|
|
228
|
+
"supportsControl": true,
|
|
229
|
+
"latencyClass": 1
|
|
230
|
+
}
|
|
231
|
+
},
|
|
232
|
+
{
|
|
233
|
+
"nodeType": "AudioResample",
|
|
234
|
+
"description": "Resamples audio to target sample rate",
|
|
235
|
+
"category": "audio",
|
|
236
|
+
"accepts": [
|
|
237
|
+
"audio"
|
|
238
|
+
],
|
|
239
|
+
"produces": [
|
|
240
|
+
"audio"
|
|
241
|
+
],
|
|
242
|
+
"parameters": [
|
|
243
|
+
{
|
|
244
|
+
"name": "target_sample_rate",
|
|
245
|
+
"paramType": "integer",
|
|
246
|
+
"description": "Target sample rate in Hz",
|
|
247
|
+
"defaultValue": "16000",
|
|
248
|
+
"required": false,
|
|
249
|
+
"minimum": 8000,
|
|
250
|
+
"maximum": 48000
|
|
251
|
+
}
|
|
252
|
+
],
|
|
253
|
+
"configSchema": "{\"properties\":{\"target_sample_rate\":{\"default\":16000,\"description\":\"Target sample rate in Hz\",\"maximum\":48000,\"minimum\":8000,\"type\":\"integer\"}},\"type\":\"object\"}",
|
|
254
|
+
"isPython": false,
|
|
255
|
+
"streaming": true,
|
|
256
|
+
"multiOutput": false,
|
|
257
|
+
"capabilities": {
|
|
258
|
+
"parallelizable": true,
|
|
259
|
+
"batchAware": false,
|
|
260
|
+
"supportsControl": false,
|
|
261
|
+
"latencyClass": 0
|
|
262
|
+
}
|
|
263
|
+
},
|
|
264
|
+
{
|
|
265
|
+
"nodeType": "KokoroTTSNode",
|
|
266
|
+
"description": "Text-to-speech synthesis using Kokoro TTS",
|
|
267
|
+
"category": "ml",
|
|
268
|
+
"accepts": [
|
|
269
|
+
"text"
|
|
270
|
+
],
|
|
271
|
+
"produces": [
|
|
272
|
+
"audio"
|
|
273
|
+
],
|
|
274
|
+
"parameters": [
|
|
275
|
+
{
|
|
276
|
+
"name": "language",
|
|
277
|
+
"paramType": "string",
|
|
278
|
+
"description": "Language code",
|
|
279
|
+
"defaultValue": "\"en-us\"",
|
|
280
|
+
"required": false,
|
|
281
|
+
"enumValues": "[\"en-us\",\"en-gb\",\"es\",\"fr\",\"de\",\"it\",\"ja\",\"ko\",\"pt-br\",\"zh\"]"
|
|
282
|
+
},
|
|
283
|
+
{
|
|
284
|
+
"name": "speed",
|
|
285
|
+
"paramType": "number",
|
|
286
|
+
"description": "Speech speed multiplier",
|
|
287
|
+
"defaultValue": "1.0",
|
|
288
|
+
"required": false,
|
|
289
|
+
"minimum": 0.5,
|
|
290
|
+
"maximum": 2
|
|
291
|
+
},
|
|
292
|
+
{
|
|
293
|
+
"name": "voice",
|
|
294
|
+
"paramType": "string",
|
|
295
|
+
"description": "Voice ID to use",
|
|
296
|
+
"defaultValue": "\"af_bella\"",
|
|
297
|
+
"required": false,
|
|
298
|
+
"enumValues": "[\"af_bella\",\"af_nicole\",\"af_sarah\",\"af_sky\",\"am_adam\",\"am_michael\",\"bf_emma\",\"bf_isabella\",\"bm_george\",\"bm_lewis\"]"
|
|
299
|
+
}
|
|
300
|
+
],
|
|
301
|
+
"configSchema": "{\"properties\":{\"language\":{\"default\":\"en-us\",\"description\":\"Language code\",\"enum\":[\"en-us\",\"en-gb\",\"es\",\"fr\",\"de\",\"it\",\"ja\",\"ko\",\"pt-br\",\"zh\"],\"type\":\"string\"},\"speed\":{\"default\":1.0,\"description\":\"Speech speed multiplier\",\"maximum\":2.0,\"minimum\":0.5,\"type\":\"number\"},\"voice\":{\"default\":\"af_bella\",\"description\":\"Voice ID to use\",\"enum\":[\"af_bella\",\"af_nicole\",\"af_sarah\",\"af_sky\",\"am_adam\",\"am_michael\",\"bf_emma\",\"bf_isabella\",\"bm_george\",\"bm_lewis\"],\"type\":\"string\"}},\"type\":\"object\"}",
|
|
302
|
+
"isPython": true,
|
|
303
|
+
"streaming": true,
|
|
304
|
+
"multiOutput": true,
|
|
305
|
+
"capabilities": {
|
|
306
|
+
"parallelizable": false,
|
|
307
|
+
"batchAware": true,
|
|
308
|
+
"supportsControl": false,
|
|
309
|
+
"latencyClass": 3
|
|
310
|
+
}
|
|
311
|
+
},
|
|
312
|
+
{
|
|
313
|
+
"nodeType": "VideoFlip",
|
|
314
|
+
"description": "Flips video frames horizontally or vertically",
|
|
315
|
+
"category": "video",
|
|
316
|
+
"accepts": [
|
|
317
|
+
"video"
|
|
318
|
+
],
|
|
319
|
+
"produces": [
|
|
320
|
+
"video"
|
|
321
|
+
],
|
|
322
|
+
"parameters": [
|
|
323
|
+
{
|
|
324
|
+
"name": "horizontal",
|
|
325
|
+
"paramType": "boolean",
|
|
326
|
+
"description": "Flip horizontally",
|
|
327
|
+
"defaultValue": "true",
|
|
328
|
+
"required": false
|
|
329
|
+
},
|
|
330
|
+
{
|
|
331
|
+
"name": "vertical",
|
|
332
|
+
"paramType": "boolean",
|
|
333
|
+
"description": "Flip vertically",
|
|
334
|
+
"defaultValue": "false",
|
|
335
|
+
"required": false
|
|
336
|
+
}
|
|
337
|
+
],
|
|
338
|
+
"configSchema": "{\"properties\":{\"horizontal\":{\"default\":true,\"description\":\"Flip horizontally\",\"type\":\"boolean\"},\"vertical\":{\"default\":false,\"description\":\"Flip vertically\",\"type\":\"boolean\"}},\"type\":\"object\"}",
|
|
339
|
+
"isPython": false,
|
|
340
|
+
"streaming": true,
|
|
341
|
+
"multiOutput": false
|
|
342
|
+
}
|
|
343
|
+
]
|