@naanlang/naan 1.4.3 → 1.4.4

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/lib/env_node.js CHANGED
@@ -110,11 +110,13 @@ exports.NaanNodeREPL = function NaanNodeREPL(options) {
110
110
  { // Node REPL does too much crap
111
111
  }
112
112
 
113
- if (process.stdin.isTTY && !options.replDisable)
113
+ if (process.stdin.isTTY)
114
114
  { // must have TTY for local REPL
115
115
  replServer = repl.start({ prompt: '', eval: myEval});
116
116
 
117
117
  replServer.on('line', function(cmd) { // process raw command line
118
+ if (options.replDisable)
119
+ return;
118
120
  if (cmd.charAt(0) != ".") {
119
121
  textToRemoteTerm("\x1b[90m\x1b[3m".concat(cmd, "\x1b[0m\n"));
120
122
  naanlib.textLine(cmd + "\n");
@@ -126,9 +128,13 @@ exports.NaanNodeREPL = function NaanNodeREPL(options) {
126
128
  //
127
129
 
128
130
  replServer._events.SIGINT = function () {
129
- naanlib.escape();
131
+ if (options.replDisable) {
132
+ console.log("^C");
133
+ process.exit();
134
+ } else
135
+ naanlib.escape();
130
136
  };
131
-
137
+
132
138
  //
133
139
  // Hook an exit command
134
140
  //
@@ -6,11 +6,11 @@
6
6
  *
7
7
  * column positioning: // // !
8
8
  *
9
- * Copyright (c) 2018-2021 by Richard C. Zulch
9
+ * Copyright (c) 2018-2025 by Richard C. Zulch
10
10
  *
11
11
  */
12
12
 
13
- loglevel(2);
13
+ loglevel(3);
14
14
 
15
15
 
16
16
  /*
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@naanlang/naan",
3
- "version": "1.4.3",
3
+ "version": "1.4.4",
4
4
  "author": "Richard C. Zulch",
5
5
  "description": "Naan™ software platform",
6
6
  "main": "./lib/core/naanlib.js",
@@ -5,7 +5,7 @@
5
5
  *
6
6
  * column positioning: // // !
7
7
  *
8
- * Copyright (c) 2021-2023 by Richard C. Zulch
8
+ * Copyright (c) 2021-2025 by Richard C. Zulch
9
9
  *
10
10
  */
11
11
 
@@ -13,12 +13,11 @@
13
13
  /*
14
14
  * MultipartBody
15
15
  *
16
- * column positioning: // // !
17
16
  * Create a multipart Form body from the specified dictionary, returning a buffer. Any xobject in
18
17
  * the dictionary is coded as an octet. If you want a different filename, include an options object
19
18
  * that defines that filename.
20
19
  *
21
- *The result is a dictionary as follows:
20
+ *The return value is a dictionary as follows:
22
21
  * {
23
22
  * body: <Buffer>
24
23
  * header: {
@@ -29,11 +28,17 @@
29
28
  *
30
29
  */
31
30
 
32
- function MultipartBody(dict, options, local boundary, parts, key, data, filename) {
31
+ function MultipartBody(dict, options,
32
+ local boundary, parts, key, data, item, filename) {
33
33
  boundary = "xx-xx-xx-xx-xx"
34
34
  parts = []
35
35
  for `(key, data) in dict {
36
- if xobject(data) {
36
+ if Array.isArray(data) { // PHP-style arrays
37
+ for item in data
38
+ parts.push(xnew(js.g.Buffer.from, "--".concat(boundary, "\r\n",
39
+ "Content-Disposition: form-data; name=\"", key, "[]",
40
+ "\"; \r\n\r\n", item, "\r\n"), "utf8"))
41
+ } else if xobject(data) { // binary file data
37
42
  if options[key]
38
43
  filename = options[key]
39
44
  else
@@ -43,8 +48,7 @@ function MultipartBody(dict, options, local boundary, parts, key, data, filename
43
48
  "Content-Type:application/octet-stream\r\n\r\n"), "utf8"))
44
49
  parts.push(xnew(js.g.Buffer.from, data, "binary"))
45
50
  parts.push(xnew(js.g.Buffer.from, "\r\n", "utf8"))
46
- }
47
- else {
51
+ } else { // ordinary data
48
52
  parts.push(xnew(js.g.Buffer.from, "--".concat(boundary, "\r\n",
49
53
  "Content-Disposition: form-data; name=\"", key,
50
54
  "\"; \r\n\r\n", data, "\r\n"), "utf8"))
@@ -165,8 +169,11 @@ function nodeUtilInit(local manifest) {
165
169
  Naan.module.build(module.id, "node_util", function(modobj, compobj) {
166
170
  require("nodeLib.nlg")
167
171
  compobj.manifest = manifest
172
+ modobj.exports.MultipartBody = MultipartBody
173
+ modobj.exports.EncodeQuery = EncodeQuery
168
174
  modobj.exports.JsonParse = JsonParse
169
175
  modobj.exports.JsonStringify = JsonStringify
176
+ modobj.exports.RandomBytes = RandomBytes
170
177
  modobj.exports.UUID = UUID
171
178
  function postload() {
172
179
  nodeFs = js.r("fs")
@@ -6,7 +6,7 @@
6
6
  *
7
7
  * column positioning: // // !
8
8
  *
9
- * Copyright (c) 2023 by Richard C. Zulch
9
+ * Copyright (c) 2023-2025 by Richard C. Zulch
10
10
  *
11
11
  */
12
12
 
@@ -65,7 +65,7 @@ closure OSDynIndexer(index, table, options,
65
65
  // Update ids into the database, returning a nonce signaled with error array.
66
66
  //
67
67
  closure updateRecordIDs(docs, ids, writeID) {
68
- asyncArray(docs, 10, function(entry, index, cancel, local error) {
68
+ asyncArray(docs, 10, closure(entry, index, cancel, local error) {
69
69
  ignore(error)
70
70
  `(error) = table.updateRecord(
71
71
  entry[table.hashKey],
@@ -78,11 +78,11 @@ closure OSDynIndexer(index, table, options,
78
78
  //
79
79
  // Batch index documents into OpenSearch, returning a nonce signaled with ids array.
80
80
  //
81
- closure batchIndex(records, local pending, docs) {
81
+ closure batchIndex(records, local pending) {
82
82
  pending = new(nonce)
83
- docs = records.map(function(record) {
83
+ docs = asyncArray(records, 10, closure(record) {
84
84
  options.converter(record)
85
- })
85
+ }).wait()
86
86
  future(function(local error, ids) {
87
87
  `(error, ids) = index.write(docs)
88
88
  pending.signal(list(error, records, ids))
@@ -946,7 +946,7 @@ closure DynaTable(dyna, tablename, options, local table) {
946
946
  // range: <key-expression> // range of keys to retrieve
947
947
  // filter: <key-expression> // conditions for items to return
948
948
  // reverse: <boolean> // reverse order
949
- // project: <array> // project only specified attributes
949
+ // project: <array> | `count // project only specified attributes
950
950
  // paging: <exclusive start key> // for paging; updated each call
951
951
  // consistentRead: <boolean> // true to use consistent read
952
952
  // limit: <number> // maximum count of results
@@ -962,6 +962,7 @@ closure DynaTable(dyna, tablename, options, local table) {
962
962
  TableName: tablename
963
963
  }
964
964
  hashKey = table.hashKey
965
+ output = []
965
966
  if options.indexName {
966
967
  params.IndexName = options.indexName
967
968
  if options.indexHashKey
@@ -989,15 +990,23 @@ closure DynaTable(dyna, tablename, options, local table) {
989
990
  }
990
991
  if options.reverse
991
992
  params.ScanIndexForward = false
992
- if options.project
993
+ if options.project == `count {
994
+ params.Select = "COUNT"
995
+ output = {
996
+ Count: 0
997
+ ScannedCount: 0
998
+ }
999
+ } else if options.project
993
1000
  params.ProjectionExpression = options.project.join(", ")
994
1001
  if options.paging
995
1002
  params.ExclusiveStartKey = options.paging
996
1003
  if options.consistentRead
997
1004
  params.ConsistentRead = options.consistentRead
998
- output = []
999
1005
  `(error) = dynQueryPager(`query, params, options.limit, function(data) {
1000
- if data.Count > 0
1006
+ if dictionary(output) {
1007
+ output.Count += data.Count
1008
+ output.ScannedCount += data.ScannedCount
1009
+ } else if data.Count > 0
1001
1010
  output = output.concat(dyna.conv.recordDynToNaan(data.Items))
1002
1011
  data.Count
1003
1012
  })
@@ -1016,7 +1025,7 @@ closure DynaTable(dyna, tablename, options, local table) {
1016
1025
  // {
1017
1026
  // index: <string> // index name in table
1018
1027
  // filter: <key-expression> // conditions for items to return
1019
- // project: <array> // project only specified attributes
1028
+ // project: <array> | `count // project only specified attributes
1020
1029
  // paging: <exclusive start key> // for paging; updated each call
1021
1030
  // consistentRead: <boolean> // true to use consistent read
1022
1031
  // limit: <number> // maximum count of results
@@ -1040,15 +1049,23 @@ closure DynaTable(dyna, tablename, options, local table) {
1040
1049
  if error
1041
1050
  return (list(Error("table.scanRecords filter:", error)))
1042
1051
  }
1043
- if options.project
1052
+ if options.project == `count {
1053
+ params.Select = "COUNT"
1054
+ output = {
1055
+ Count: 0
1056
+ ScannedCount: 0
1057
+ }
1058
+ } else if options.project
1044
1059
  params.ProjectionExpression = options.project.join(", ")
1045
1060
  if options.paging
1046
1061
  params.ExclusiveStartKey = options.paging
1047
1062
  if options.consistentRead
1048
1063
  params.ConsistentRead = options.consistentRead
1049
- output = []
1050
1064
  `(error) = dynQueryPager(`scan, params, options.limit, function(data) {
1051
- if data.Count >= 0
1065
+ if dictionary(output) {
1066
+ output.Count += data.Count
1067
+ output.ScannedCount += data.ScannedCount
1068
+ } else if data.Count >= 0
1052
1069
  output = output.concat(dyna.conv.recordDynToNaan(data.Items))
1053
1070
  data.Count
1054
1071
  })
@@ -0,0 +1,198 @@
1
+ /*
2
+ * aws_vm.nlg
3
+ * serviceAws
4
+ *
5
+ * VM controller under AWS.
6
+ *
7
+ * column positioning: // // !
8
+ *
9
+ * Copyright (c) 2024-2025 by Richard C. Zulch
10
+ *
11
+ */
12
+
13
+ vmState = false;
14
+
15
+ /*
16
+ * VmControl
17
+ *
18
+ * VM control object for AWS.
19
+ *
20
+ */
21
+
22
+ closure VmControl(creds, local dokon) {
23
+ global(js, http, vmState)
24
+ if vmState.dokon
25
+ return (vmState.dokon) // singleton
26
+ dokon = new(object, this)
27
+ vmState = new(nonce) // don't save with state
28
+ vmState.dokon = dokon
29
+
30
+ // detachVM
31
+ //
32
+ // Tell AWS to detach a VM from its scalability group. Returns a tuple with:
33
+ // {
34
+ // Activities: [
35
+ // {
36
+ // ActivityId: "STRING_VALUE",
37
+ // AutoScalingGroupName: "STRING_VALUE",
38
+ // Description: "STRING_VALUE",
39
+ // Cause: "STRING_VALUE",
40
+ // StartTime: new Date("TIMESTAMP"),
41
+ // EndTime: new Date("TIMESTAMP"),
42
+ // StatusCode: "PendingSpotBidPlacement" || "WaitingForSpotInstanceRequestId"
43
+ // || "WaitingForSpotInstanceId" || "WaitingForInstanceId" || "PreInService"
44
+ // || "InProgress" || "WaitingForELBConnectionDraining" || "MidLifecycleAction"
45
+ // || "WaitingForInstanceWarmup" || "Successful" || "Failed" || "Cancelled"
46
+ // || "WaitingForConnectionDraining",
47
+ // StatusMessage: "STRING_VALUE",
48
+ // Progress: Number("int"),
49
+ // Details: "STRING_VALUE",
50
+ // AutoScalingGroupState: "STRING_VALUE",
51
+ // AutoScalingGroupARN: "STRING_VALUE",
52
+ // }
53
+ // ]
54
+ // }
55
+ closure detachVM(instanceID, local error, ascSdk, params, asclient, response) {
56
+ `(error, ascSdk) = await(js.i("@aws-sdk/client-auto-scaling"))
57
+ if error
58
+ return (list(error))
59
+ params = { }
60
+ params.region = creds.region
61
+ params.credentials = {
62
+ accessKeyId: creds.keyID
63
+ secretAccessKey: creds.keySecret
64
+ }
65
+ if creds.endpoint
66
+ params.endpoint = creds.endpoint
67
+ asclient = xnew(ascSdk.AutoScalingClient, params)
68
+ `(error, response) = await(asclient.send(xnew(ascSdk.DetachInstancesCommand, {
69
+ AutoScalingGroupName: creds.ec2AsgName
70
+ InstanceIds: [ instanceID ]
71
+ ShouldDecrementDesiredCapacity: false
72
+ })))
73
+ list(error, response)
74
+ }
75
+
76
+ // terminateVM
77
+ //
78
+ // Tell AWS to terminate a VM, ours in point of fact. Returns a tuple with:
79
+ // {
80
+ // TerminatingInstances: [
81
+ // {
82
+ // InstanceId: "STRING_VALUE"
83
+ // CurrentState: { // InstanceState
84
+ // Code: Number("int"),
85
+ // Name: "pending" || "running" || "shutting-down" || "terminated"
86
+ // || "stopping" || "stopped",
87
+ // }
88
+ // PreviousState: {
89
+ // Code: Number("int"),
90
+ // Name: "pending" || "running" || "shutting-down" || "terminated"
91
+ // || "stopping" || "stopped",
92
+ // }
93
+ // }
94
+ // ]
95
+ // }
96
+ //
97
+ closure terminateVM(instanceID, local error, ec2sdk, params, ec2client, response) {
98
+ `(error, ec2sdk) = await(js.i("@aws-sdk/client-ec2"))
99
+ if error
100
+ return (list(error))
101
+ params = { }
102
+ params.region = creds.region
103
+ params.credentials = {
104
+ accessKeyId: creds.keyID
105
+ secretAccessKey: creds.keySecret
106
+ }
107
+ if creds.endpoint
108
+ params.endpoint = creds.endpoint
109
+ ec2client = xnew(ec2sdk.EC2Client, params)
110
+ `(error, response) = await(ec2client.send(xnew(ec2sdk.TerminateInstancesCommand,
111
+ { InstanceIds: [ instanceID ] })))
112
+ list(error, response)
113
+ }
114
+
115
+ // getHostname
116
+ //
117
+ // Ask the VM for its FQDN.
118
+ //
119
+ // TOKEN="`curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600"`"
120
+ // curl -H "X-aws-ec2-metadata-token: $TOKEN" 'http://169.254.169.254/latest/meta-data/hostname'
121
+ // => ip-172-31-80-96.ec2.internal
122
+ //
123
+ dokon.getHostname = closure getHostname(local error, token, hostname) {
124
+ `(error, token) = http.HttpRequest("http://169.254.169.254/latest/api/token", {
125
+ headers: {
126
+ "X-aws-ec2-metadata-token-ttl-seconds": "2160"
127
+ }
128
+ method: "PUT"
129
+ })
130
+ if !error
131
+ `(error, hostname) = http.HttpRequest("http://169.254.169.254/latest/meta-data/hostname", {
132
+ headers: {
133
+ "X-aws-ec2-metadata-token": token
134
+ }
135
+ })
136
+ if error
137
+ list(error)
138
+ else
139
+ list(false, hostname)
140
+ }
141
+
142
+ // vmShutdown
143
+ //
144
+ // Get our AWS EC2 VM instance ID and then request that it be shut down.
145
+ //
146
+ // How to get auth token:
147
+ // curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600"
148
+ // => AQAEAJHVrb_zRdju_A3tYBJLtKHsjej5GFVsDu1VuBCErP8MNVOr0Q==
149
+ //
150
+ // How to get instance-id:
151
+ // curl -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/instance-id
152
+ // => i-008dc3846da316a93
153
+ //
154
+
155
+ dokon.shutdown = closure shutdown(local error, token, instanceID, response) {
156
+ `(error, token) = http.HttpRequest("http://169.254.169.254/latest/api/token", {
157
+ headers: {
158
+ "X-aws-ec2-metadata-token-ttl-seconds": "2160"
159
+ }
160
+ method: "PUT"
161
+ })
162
+ if !error
163
+ `(error, instanceID) = http.HttpRequest("http://169.254.169.254/latest/meta-data/instance-id", {
164
+ headers: {
165
+ "X-aws-ec2-metadata-token": token
166
+ }
167
+ })
168
+ if !error
169
+ `(error, response) = detachVM(instanceID)
170
+ if !error
171
+ `(error, response) = terminateVM(instanceID)
172
+ if error
173
+ list(error)
174
+ else
175
+ list(false, response)
176
+ }
177
+
178
+ // finis
179
+ dokon
180
+ };
181
+
182
+
183
+ /*
184
+ * vmConInit
185
+ *
186
+ * Initialize the component.
187
+ *
188
+ */
189
+
190
+ function vmConInit(local manifest) {
191
+ manifest = `(VmControl, vmConInit)
192
+ Naan.module.build(module.id, "aws_vm", function(modobj, compobj) {
193
+ require("./serviceAws.nlg")
194
+ compobj.manifest = manifest
195
+ http = require("naanlib:frameworks/node/http_request.nlg")
196
+ module.exports.VmControl = VmControl
197
+ })
198
+ } ();
@@ -83,6 +83,7 @@ closure GcApi(options, local gcapi, cacert, renew, access_token, expires_at) {
83
83
  `(error, data, status) = https.HttpsApiRequest(url, {
84
84
  putdata: put || undefined
85
85
  cacert: cacert || undefined
86
+ debug: options.debug || undefined
86
87
  headers: [
87
88
  `(Accept, "application/json"),
88
89
  list(`Authorization, "Bearer ".concat(access_token))
@@ -0,0 +1,32 @@
1
+ /*
2
+ * serviceNexara.nlg
3
+ * serviceNexara
4
+ *
5
+ * Nexara speech recognition.
6
+ *
7
+ * column positioning: // // !
8
+ *
9
+ * Copyright (c) 2025 by Richard C. Zulch
10
+ *
11
+ */
12
+
13
+
14
+ /*
15
+ * senexInit
16
+ *
17
+ * Initialize the module.
18
+ *
19
+ */
20
+
21
+ function senexInit(local manifest) {
22
+ manifest = `(senexInit)
23
+ Naan.module.build(module.id, "serviceNexara", function(modobj, compobj) {
24
+ compobj.manifest = manifest
25
+ require("naanlib:frameworks/common").LiveImport()
26
+ nodeLib = require("naanlib:plugins/nodeLib/node_util.nlg")
27
+ if js.g
28
+ https = require("naanlib:frameworks/node/https_request.nlg")
29
+ else
30
+ https = require("naanlib:frameworks/browser/https_request.nlg")
31
+ })
32
+ } ();
@@ -0,0 +1,160 @@
1
+ /*
2
+ * speechrec.nlg
3
+ * Nexara
4
+ *
5
+ * Access to Nexara speech to text recognition.
6
+ *
7
+ * column positioning: // // !
8
+ *
9
+ * Copyright (c) 2025 by Richard C. Zulch
10
+ *
11
+ */
12
+
13
+
14
+ /*
15
+ * NexaraSpeechRec
16
+ *
17
+ * Speech recognition object.
18
+ *
19
+ */
20
+
21
+ closure NexaraSpeechRec(local nxspr) {
22
+ global(https, nodeLib)
23
+ nxspr = new(object, this)
24
+ nxspr.recogURL = "https://api.nexara.ru/api/v1/audio/transcriptions"
25
+
26
+ // login
27
+ //
28
+ // creds:
29
+ // {
30
+ // apiKey: <string> // e.g. nx-xxxxx
31
+ // }
32
+ //
33
+ nxspr.login = closure login(creds) {
34
+ nxspr.creds = creds
35
+ list(false, { ok: true })
36
+ }
37
+
38
+ // recog
39
+ //
40
+ // Recognize text from the specified audio.
41
+ //
42
+ // Available options are:
43
+ // {
44
+ // language: <string> // optional: e.g. "ru-RU", "en-US"
45
+ // model: <string> // optional: e.g. "whisper-1"
46
+ // debug: <boolean> // extra debug logging for https request
47
+ // }
48
+ //
49
+ // This returns an Operation object containing the ID of the asynchronous recognition operation:
50
+ // {
51
+ // done: true // recognition complete
52
+ // createdAt: <date> // when operation started
53
+ // modifiedAt: <date> // last modified
54
+ // response: {
55
+ // "@type": <string> // gRPC type
56
+ // chunks: <array> // array of chunks
57
+ // }
58
+ // }
59
+ //
60
+ nxspr.recog = closure recog(audioBlob, options, local start, params, form, error, data) {
61
+ start = Date()
62
+ params = {
63
+ language: options.language.substring(0,2) || undefined
64
+ model: options.model || "whisper-1"
65
+ response_format: "verbose_json",
66
+ timestamp_granularities: ["word", "segment"]
67
+ file: audioBlob
68
+ }
69
+ form = nodeLib.MultipartBody(params)
70
+ `(error, data) = https.HttpsApiRequest(nxspr.recogURL, {
71
+ method: "POST"
72
+ putdata: form.body
73
+ headers: [
74
+ list("Authorization", "Bearer ".concat(nxspr.creds.apiKey))
75
+ list("Content-Type", form.headers."Content-Type")
76
+ list("Content-Length", form.headers."Content-Length")
77
+ ]
78
+ debug: options.debug || undefined
79
+ })
80
+ if error
81
+ list(Error("NexaraSpeechRec.recog failed:", error))
82
+ else if !(data.segments.length > 0) {
83
+ debuglog("NexaraSpeechRec.recog: no valid segments returned.")
84
+ printline("Nexara response:", Dialect.print(new(data)))
85
+ list(Error("NexaraSpeechRec.recog empty result"))
86
+ } else {
87
+ if options.dump
88
+ printline(Dialect.print(new(data)))
89
+ list(false, {
90
+ done: true
91
+ createdAt: start
92
+ modifiedAt: Date()
93
+ response: nexaraToYCSK(data)
94
+ })
95
+ }
96
+ }
97
+
98
+ // nexaraToYCSK
99
+ //
100
+ // Convert a Nexara response to a Yandex SpeechKit structure. Hey, it was first.
101
+ //
102
+ function nexaraToYCSK(resp,
103
+ local output, wordx, segment, chunk, word, wordet) {
104
+ output = {
105
+ \@type: "type.googleapis.com/yandex.cloud.ai.stt.v2.LongRunningRecognitionResponse"
106
+ chunks: []
107
+ language: resp.language
108
+ }
109
+ wordx = 0
110
+ for segment in resp.segments {
111
+ if segment.text == ""
112
+ continue // empty segment
113
+ chunk = {
114
+ channelTag: "1"
115
+ alternatives: [
116
+ {
117
+ words: []
118
+ text: segment.text
119
+ }
120
+ ]
121
+ }
122
+ for word in segment.text.split(" ") {
123
+ wordet = resp.words[wordx++]
124
+ if wordet.word != word {
125
+ debuglog("nexaraToYCSK: expected ${word} but got ${wordet.word}")
126
+ return (false)
127
+ }
128
+ chunk.alternatives.0.words.push({
129
+ word: wordet.word
130
+ startTime: wordet.start.toFixed(3).concat("s")
131
+ endTime: wordet.end.toFixed(3).concat("s")
132
+ })
133
+ }
134
+ output.chunks.push(chunk)
135
+ }
136
+ output
137
+ }
138
+
139
+ // finis
140
+ nxspr
141
+ }
142
+
143
+
144
+ /*
145
+ * nexaraInit
146
+ *
147
+ * Initialize the module.
148
+ *
149
+ */
150
+
151
+ function nexaraInit(local manifest) {
152
+ manifest = `(NexaraSpeechRec, nexaraInit)
153
+
154
+ Naan.module.build(module.id, "speechrec", function(modobj, compobj) {
155
+ require("./serviceNexara.nlg")
156
+ compobj.manifest = manifest
157
+ modobj.exports.NexaraSpeechRec = NexaraSpeechRec
158
+ })
159
+
160
+ } ();
@@ -50,9 +50,8 @@ function seycInit(local manifest) {
50
50
  Naan.module.build(module.id, "serviceYC", function(modobj, compobj) {
51
51
  compobj.manifest = manifest
52
52
  require("naanlib:frameworks/common").LiveImport()
53
- if js.g {
54
- nodeHttp = js.r("http")
55
- https = require("naanlib:frameworks/node/https_request.nlg") }
53
+ if js.g
54
+ https = require("naanlib:frameworks/node/https_request.nlg")
56
55
  else
57
56
  https = require("naanlib:frameworks/browser/https_request.nlg")
58
57
  module.exports.YcRequest = YcRequest
@@ -6,7 +6,7 @@
6
6
  *
7
7
  * column positioning: // // !
8
8
  *
9
- * Copyright (c) 2024 by Richard C. Zulch
9
+ * Copyright (c) 2024-2025 by Richard C. Zulch
10
10
  *
11
11
  */
12
12
 
@@ -18,7 +18,8 @@
18
18
  *
19
19
  */
20
20
 
21
- closure YCSpeechRec(options, local ycspr) {
21
+ closure YCSpeechRec(local ycspr) {
22
+ global(https)
22
23
  ycspr = new(object, this)
23
24
  ycspr.recogURL = "https://transcribe.api.cloud.yandex.net/speech/stt/v2/longRunningRecognize"
24
25
  ycspr.checkURL = "https://operation.api.cloud.yandex.net/operations/"
@@ -55,7 +56,7 @@ closure YCSpeechRec(options, local ycspr) {
55
56
  // }
56
57
  // }
57
58
  //
58
- ycspr.startRecog = closure startRecog(audioURI, options, local error, data) {
59
+ ycspr.startRecog = closure startRecog(audioURI, options, local params, error, data) {
59
60
  params = {
60
61
  config: {
61
62
  specification: {