presidium 0.15.20 → 0.15.27
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/DynamoStream.js
CHANGED
|
@@ -155,7 +155,9 @@ DynamoStream.prototype.getRecords = async function* getRecords(
|
|
|
155
155
|
shardId: always(Shard.ShardId),
|
|
156
156
|
}))
|
|
157
157
|
}
|
|
158
|
+
|
|
158
159
|
while (!this.closed && records.NextShardIterator != null) {
|
|
160
|
+
await new Promise(resolve => setTimeout(resolve, this.getRecordsInterval))
|
|
159
161
|
records = await this.client.getRecords({
|
|
160
162
|
ShardIterator: records.NextShardIterator,
|
|
161
163
|
Limit: this.getRecordsLimit
|
|
@@ -166,7 +168,6 @@ DynamoStream.prototype.getRecords = async function* getRecords(
|
|
|
166
168
|
shardId: always(Shard.ShardId),
|
|
167
169
|
}))
|
|
168
170
|
}
|
|
169
|
-
await new Promise(resolve => setTimeout(resolve, this.getRecordsInterval))
|
|
170
171
|
}
|
|
171
172
|
}
|
|
172
173
|
|
package/KinesisStream.js
CHANGED
|
@@ -50,7 +50,7 @@ const KinesisStream = function (options) {
|
|
|
50
50
|
this.name = options.name
|
|
51
51
|
this.listShardsLimit = options.listShardsLimit ?? 1000
|
|
52
52
|
this.getRecordsLimit = options.getRecordsLimit ?? 1000
|
|
53
|
-
this.
|
|
53
|
+
this.shardUpdatePeriod = options.shardUpdatePeriod ?? 15000
|
|
54
54
|
this.getRecordsInterval = options.getRecordsInterval ?? 1000
|
|
55
55
|
this.shardIteratorType = options.shardIteratorType ?? 'LATEST'
|
|
56
56
|
this.shardIteratorTimestamp = options.shardIteratorTimestamp
|
|
@@ -116,7 +116,6 @@ KinesisStream.prototype.delete = function deleteStream() {
|
|
|
116
116
|
* ```
|
|
117
117
|
*/
|
|
118
118
|
KinesisStream.prototype.putRecord = async function putRecord(data, options = {}) {
|
|
119
|
-
await this.ready
|
|
120
119
|
return this.kinesis.client.putRecord({
|
|
121
120
|
StreamName: this.name,
|
|
122
121
|
Data: data,
|
|
@@ -142,14 +141,19 @@ KinesisStream.prototype.listShards = async function* listShards() {
|
|
|
142
141
|
StreamName: this.name,
|
|
143
142
|
MaxResults: this.listShardsLimit,
|
|
144
143
|
}).promise()
|
|
145
|
-
|
|
144
|
+
if (shards.Shards.length > 0) {
|
|
145
|
+
yield* shards.Shards
|
|
146
|
+
}
|
|
147
|
+
|
|
146
148
|
while (!this.closed && shards.NextToken != null) {
|
|
147
149
|
shards = await this.kinesis.client.listShards({
|
|
148
150
|
StreamName: this.name,
|
|
149
151
|
MaxResults: this.listShardsLimit,
|
|
150
152
|
NextToken: shards.NextToken,
|
|
151
153
|
})
|
|
152
|
-
|
|
154
|
+
if (shards.Shards.length > 0) {
|
|
155
|
+
yield* shards.Shards
|
|
156
|
+
}
|
|
153
157
|
}
|
|
154
158
|
}
|
|
155
159
|
|
|
@@ -163,19 +167,24 @@ KinesisStream.prototype.getRecords = async function* getRecords(Shard) {
|
|
|
163
167
|
Timestamp: this.shardIteratorTimestamp,
|
|
164
168
|
},
|
|
165
169
|
}).promise().then(get('ShardIterator'))
|
|
170
|
+
|
|
166
171
|
let records = await this.kinesis.client.getRecords({
|
|
167
172
|
ShardIterator: startingShardIterator,
|
|
168
173
|
Limit: this.getRecordsLimit,
|
|
169
174
|
}).promise()
|
|
170
|
-
|
|
171
|
-
|
|
175
|
+
if (records.Records.length > 0) {
|
|
176
|
+
yield* records.Records
|
|
177
|
+
}
|
|
178
|
+
|
|
172
179
|
while (!this.closed && records.NextShardIterator != null) {
|
|
180
|
+
await new Promise(resolve => setTimeout(resolve, this.getRecordsInterval))
|
|
173
181
|
records = await this.kinesis.client.getRecords({
|
|
174
182
|
ShardIterator: records.NextShardIterator,
|
|
175
183
|
Limit: this.getRecordsLimit,
|
|
176
184
|
}).promise()
|
|
177
|
-
|
|
178
|
-
|
|
185
|
+
if (records.Records.length > 0) {
|
|
186
|
+
yield* records.Records
|
|
187
|
+
}
|
|
179
188
|
}
|
|
180
189
|
}
|
|
181
190
|
|
|
@@ -183,43 +192,46 @@ const SymbolUpdateShards = Symbol('UpdateShards')
|
|
|
183
192
|
|
|
184
193
|
KinesisStream.prototype[Symbol.asyncIterator] = async function* generateRecords() {
|
|
185
194
|
let shards = await transform(map(identity), [])(this.listShards())
|
|
186
|
-
let muxAsyncIterator = Mux.race(
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
195
|
+
let muxAsyncIterator = Mux.race([
|
|
196
|
+
...shards.map(Shard => this.getRecords(Shard)),
|
|
197
|
+
(async function* UpdateShardsGenerator() {
|
|
198
|
+
while (!this.closed) {
|
|
199
|
+
await new Promise(resolve => {
|
|
200
|
+
setTimeout(resolve, this.shardUpdatePeriod)
|
|
201
|
+
})
|
|
202
|
+
if (!this.closed) {
|
|
203
|
+
yield SymbolUpdateShards
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
}).call(this),
|
|
207
|
+
])
|
|
192
208
|
|
|
193
209
|
while (!this.closed) {
|
|
194
|
-
const
|
|
195
|
-
|
|
196
|
-
iterationPromise,
|
|
197
|
-
])
|
|
198
|
-
if (iteration == SymbolUpdateShards) {
|
|
210
|
+
const { value, done } = await muxAsyncIterator.next()
|
|
211
|
+
if (value == SymbolUpdateShards) {
|
|
199
212
|
const latestShards = await transform(map(identity), [])(this.listShards())
|
|
200
|
-
const newShards =
|
|
201
|
-
(
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
213
|
+
const newShards = pipe([
|
|
214
|
+
always(shards),
|
|
215
|
+
differenceWith(
|
|
216
|
+
(ShardA, ShardB) => ShardA.ShardId == ShardB.ShardId,
|
|
217
|
+
latestShards,
|
|
218
|
+
),
|
|
219
|
+
map(assign({
|
|
220
|
+
ShardIteratorType: always('TRIM_HORIZON'),
|
|
221
|
+
})),
|
|
222
|
+
])()
|
|
223
|
+
|
|
210
224
|
shards = latestShards
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
} else if (
|
|
225
|
+
if (newShards.length > 0) {
|
|
226
|
+
muxAsyncIterator = Mux.race([
|
|
227
|
+
...newShards.map(Shard => this.getRecords(Shard)),
|
|
228
|
+
muxAsyncIterator,
|
|
229
|
+
])
|
|
230
|
+
}
|
|
231
|
+
} else if (done) {
|
|
218
232
|
await new Promise(resolve => setTimeout(resolve, 1000))
|
|
219
|
-
iterationPromise = muxAsyncIterator.next()
|
|
220
233
|
} else {
|
|
221
|
-
yield
|
|
222
|
-
iterationPromise = muxAsyncIterator.next()
|
|
234
|
+
yield value
|
|
223
235
|
}
|
|
224
236
|
}
|
|
225
237
|
}
|
package/KinesisStream.test.js
CHANGED
|
@@ -27,6 +27,7 @@ const test = new Test('KinesisStream', KinesisStream)
|
|
|
27
27
|
assert.deepEqual(first3, first3Again)
|
|
28
28
|
this.streams.push(myStream)
|
|
29
29
|
})
|
|
30
|
+
|
|
30
31
|
.case({
|
|
31
32
|
name: 'my-stream',
|
|
32
33
|
endpoint: 'http://localhost:4567',
|
|
@@ -46,6 +47,28 @@ const test = new Test('KinesisStream', KinesisStream)
|
|
|
46
47
|
myStream.close()
|
|
47
48
|
this.streams.push(myStream)
|
|
48
49
|
})
|
|
50
|
+
|
|
51
|
+
.case({
|
|
52
|
+
name: 'my-stream',
|
|
53
|
+
endpoint: 'http://localhost:4567',
|
|
54
|
+
shardUpdatePeriod: 500,
|
|
55
|
+
}, async function (myStream) {
|
|
56
|
+
await myStream.ready
|
|
57
|
+
|
|
58
|
+
// there shouldn't be any more records, so this should hang
|
|
59
|
+
const latestRecordPromise = asyncIterableTake(1)(myStream)
|
|
60
|
+
const raceResult = await Promise.race([
|
|
61
|
+
latestRecordPromise,
|
|
62
|
+
new Promise(resolve => setTimeout(thunkify(resolve, 'hey'), 3000))
|
|
63
|
+
])
|
|
64
|
+
assert.equal(raceResult, 'hey')
|
|
65
|
+
// wait a second for shard update
|
|
66
|
+
await new Promise(resolve => setTimeout(thunkify(resolve, 'hey'), 1000))
|
|
67
|
+
myStream.close()
|
|
68
|
+
// ensure shards don't update after close
|
|
69
|
+
await new Promise(resolve => setTimeout(resolve, 1000))
|
|
70
|
+
})
|
|
71
|
+
|
|
49
72
|
.after(async function() {
|
|
50
73
|
await map(stream => stream.delete())(this.streams)
|
|
51
74
|
})
|
|
@@ -29,11 +29,11 @@ const CHECKSUM_LENGTH = 4
|
|
|
29
29
|
const MINIMUM_MESSAGE_LENGTH = PRELUDE_LENGTH + CHECKSUM_LENGTH * 2
|
|
30
30
|
|
|
31
31
|
/**
|
|
32
|
-
* @name
|
|
32
|
+
* @name TranscribeStream
|
|
33
33
|
*
|
|
34
34
|
* @synopsis
|
|
35
35
|
* ```coffeescript [specscript]
|
|
36
|
-
* const myTranscribeStream = new
|
|
36
|
+
* const myTranscribeStream = new TranscribeStream(options {
|
|
37
37
|
* accessKeyId: string,
|
|
38
38
|
* secretAccessKey: string,
|
|
39
39
|
* region: string,
|
|
@@ -44,6 +44,24 @@ const MINIMUM_MESSAGE_LENGTH = PRELUDE_LENGTH + CHECKSUM_LENGTH * 2
|
|
|
44
44
|
* sessionId?: string,
|
|
45
45
|
* vocabularyName?: string,
|
|
46
46
|
* })
|
|
47
|
+
*
|
|
48
|
+
* myTranscribeStream.on('transcription', transcriptionHandler (transcription {
|
|
49
|
+
* Alternatives: Array<{
|
|
50
|
+
* Items: Array<{
|
|
51
|
+
* Confidence?: number,
|
|
52
|
+
* Content: string,
|
|
53
|
+
* EndTime: number, // seconds
|
|
54
|
+
* StartTime: number, // seconds
|
|
55
|
+
* Type: 'pronunciation'|'punctuation',
|
|
56
|
+
* VocabularyFilterMatch: boolean,
|
|
57
|
+
* }>,
|
|
58
|
+
* Transcript: string,
|
|
59
|
+
* }>,
|
|
60
|
+
* EndTime: number, // seconds
|
|
61
|
+
* IsPartial: boolean,
|
|
62
|
+
* ResultId: string, // uuid
|
|
63
|
+
* StartTime: number, // seconds
|
|
64
|
+
* })=><>)
|
|
47
65
|
* ```
|
|
48
66
|
*
|
|
49
67
|
* @description
|
|
@@ -59,7 +77,7 @@ const MINIMUM_MESSAGE_LENGTH = PRELUDE_LENGTH + CHECKSUM_LENGTH * 2
|
|
|
59
77
|
*
|
|
60
78
|
* `vocabularyName` - The name of the vocabulary to use when processing the transcription job, if any.
|
|
61
79
|
*/
|
|
62
|
-
const
|
|
80
|
+
const TranscribeStream = function (options) {
|
|
63
81
|
const {
|
|
64
82
|
accessKeyId,
|
|
65
83
|
secretAccessKey,
|
|
@@ -109,10 +127,10 @@ const TranscribeStreaming = function (options) {
|
|
|
109
127
|
return this
|
|
110
128
|
}
|
|
111
129
|
|
|
112
|
-
|
|
130
|
+
TranscribeStream.prototype = EventEmitter.prototype
|
|
113
131
|
|
|
114
132
|
/**
|
|
115
|
-
* @name
|
|
133
|
+
* @name TranscribeStream.prototype.sendAudioChunk
|
|
116
134
|
*
|
|
117
135
|
* @synopsis
|
|
118
136
|
* ```coffeescript [specscript]
|
|
@@ -125,7 +143,7 @@ TranscribeStreaming.prototype = EventEmitter.prototype
|
|
|
125
143
|
* https://docs.aws.amazon.com/transcribe/latest/dg/event-stream.html
|
|
126
144
|
* https://github.com/aws-samples/amazon-transcribe-comprehend-medical-twilio/blob/main/lib/transcribe-service.js
|
|
127
145
|
*/
|
|
128
|
-
|
|
146
|
+
TranscribeStream.prototype.sendAudioChunk = function (chunk) {
|
|
129
147
|
const headersBytes = marshalHeaders({
|
|
130
148
|
':message-type': {
|
|
131
149
|
type: 'string',
|
|
@@ -273,4 +291,4 @@ const unmarshalHeaders = function (headersView) {
|
|
|
273
291
|
return headers
|
|
274
292
|
}
|
|
275
293
|
|
|
276
|
-
module.exports =
|
|
294
|
+
module.exports = TranscribeStream
|
|
@@ -4,7 +4,7 @@ const WaveFile = require('wavefile').WaveFile
|
|
|
4
4
|
const Test = require('thunk-test')
|
|
5
5
|
const assert = require('assert')
|
|
6
6
|
const rubico = require('rubico')
|
|
7
|
-
const
|
|
7
|
+
const TranscribeStream = require('./TranscribeStream')
|
|
8
8
|
const AwsCredentials = require('./internal/AwsCredentials')
|
|
9
9
|
|
|
10
10
|
const {
|
|
@@ -18,7 +18,7 @@ const {
|
|
|
18
18
|
curry, __,
|
|
19
19
|
} = rubico
|
|
20
20
|
|
|
21
|
-
const test = new Test('
|
|
21
|
+
const test = new Test('TranscribeStream', async function () {
|
|
22
22
|
const awsCreds = await AwsCredentials('default').catch(error => {
|
|
23
23
|
if (error.code == 'ENOENT') {
|
|
24
24
|
const accessKeyId = process.env.AWS_ACCESS_KEY_ID
|
|
@@ -32,13 +32,13 @@ const test = new Test('TranscribeStreaming', async function () {
|
|
|
32
32
|
})
|
|
33
33
|
awsCreds.region = 'us-east-1' // only valid region for transcribe
|
|
34
34
|
|
|
35
|
-
const
|
|
35
|
+
const testTranscribeStream = new TranscribeStream({
|
|
36
36
|
languageCode: 'en-US',
|
|
37
37
|
mediaEncoding: 'pcm',
|
|
38
38
|
sampleRate: 8000,
|
|
39
39
|
...awsCreds,
|
|
40
40
|
})
|
|
41
|
-
await
|
|
41
|
+
await testTranscribeStream.ready
|
|
42
42
|
|
|
43
43
|
const mediaStreamFixtureAwsKeynote =
|
|
44
44
|
fs.createReadStream('./media-stream-fixture-aws-keynote.txt')
|
|
@@ -51,14 +51,14 @@ const test = new Test('TranscribeStreaming', async function () {
|
|
|
51
51
|
const wav = new WaveFile()
|
|
52
52
|
wav.fromScratch(1, 8000, '8', Buffer.from(event.media.payload, 'base64'))
|
|
53
53
|
wav.fromMuLaw()
|
|
54
|
-
|
|
54
|
+
testTranscribeStream.sendAudioChunk(Buffer.from(wav.data.samples))
|
|
55
55
|
} else if (event.event == 'stop') {
|
|
56
|
-
|
|
56
|
+
testTranscribeStream.websocket.close()
|
|
57
57
|
}
|
|
58
58
|
})
|
|
59
59
|
|
|
60
60
|
const testTranscription = await new Promise(resolve => {
|
|
61
|
-
|
|
61
|
+
testTranscribeStream.on('transcription', transcription => {
|
|
62
62
|
resolve(transcription.Alternatives[0].Transcript)
|
|
63
63
|
})
|
|
64
64
|
})
|
package/index.js
CHANGED
|
@@ -31,24 +31,43 @@ const S3Bucket = require('./S3Bucket')
|
|
|
31
31
|
// const Redshift = require('./Redshift')
|
|
32
32
|
// const Gremlin = require('./Gremlin')
|
|
33
33
|
const Redis = require('./Redis')
|
|
34
|
+
const TranscribeStream = require('./TranscribeStream')
|
|
34
35
|
|
|
35
36
|
const Presidium = {
|
|
36
|
-
Http,
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
37
|
+
Http,
|
|
38
|
+
HttpServer,
|
|
39
|
+
WebSocket,
|
|
40
|
+
WebSocketServer,
|
|
41
|
+
Dynamo,
|
|
42
|
+
DynamoTable,
|
|
43
|
+
DynamoIndex,
|
|
44
|
+
DynamoStream,
|
|
45
|
+
Docker,
|
|
46
|
+
DockerImage,
|
|
47
|
+
DockerContainer,
|
|
48
|
+
DockerSwarm,
|
|
49
|
+
DockerService,
|
|
50
|
+
// ElasticTranscoder,
|
|
51
|
+
// ElasticTranscoderPipeline,
|
|
52
|
+
// KinesisAnalytics,
|
|
53
|
+
// KinesisAnalyticsStream,
|
|
54
|
+
// KinesisVideo,
|
|
55
|
+
// KinesisVideoStream,
|
|
56
|
+
Kinesis,
|
|
57
|
+
KinesisStream,
|
|
58
|
+
Lambda,
|
|
59
|
+
LambdaFunction,
|
|
60
|
+
Mongo,
|
|
61
|
+
MongoCollection,
|
|
46
62
|
ElasticsearchIndex,
|
|
47
|
-
// SNS,
|
|
48
|
-
|
|
63
|
+
// SNS,
|
|
64
|
+
// SNSTopic,
|
|
65
|
+
S3,
|
|
66
|
+
S3Bucket,
|
|
49
67
|
// Redshift,
|
|
50
68
|
// Gremlin,
|
|
51
69
|
Redis,
|
|
70
|
+
TranscribeStream,
|
|
52
71
|
}
|
|
53
72
|
|
|
54
73
|
module.exports = Presidium
|