presidium 0.15.18 → 0.15.23
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
|
@@ -58,9 +58,8 @@ const DynamoStream = function (options) {
|
|
|
58
58
|
this.getRecordsLimit = options.getRecordsLimit ?? 1000
|
|
59
59
|
this.getRecordsInterval = options.getRecordsInterval ?? 1000
|
|
60
60
|
this.shardIteratorType = options.shardIteratorType ?? 'LATEST'
|
|
61
|
-
this.shardUpdatePeriod = options.shardUpdatePeriod ??
|
|
61
|
+
this.shardUpdatePeriod = options.shardUpdatePeriod ?? 15000
|
|
62
62
|
this.listStreamsLimit = options.listStreamsLimit ?? 100
|
|
63
|
-
this.debug = options.debug ?? false
|
|
64
63
|
this.client = new DynamoDBStreams({
|
|
65
64
|
apiVersion: '2012-08-10',
|
|
66
65
|
accessKeyId: 'id',
|
|
@@ -90,14 +89,18 @@ DynamoStream.prototype.getStreams = async function* getStreams() {
|
|
|
90
89
|
Limit: this.listStreamsLimit,
|
|
91
90
|
TableName: this.table
|
|
92
91
|
}).promise()
|
|
93
|
-
|
|
92
|
+
if (streams.Streams.length > 0) {
|
|
93
|
+
yield* streams.Streams
|
|
94
|
+
}
|
|
94
95
|
while (!this.closed && streams.LastEvaluatedStreamArn != null) {
|
|
95
96
|
streams = await this.client.listStreams({
|
|
96
97
|
Limit: this.listStreamsLimit,
|
|
97
98
|
TableName: this.table,
|
|
98
99
|
ExclusiveStartStreamArn: streams.LastEvaluatedStreamArn,
|
|
99
100
|
}).promise()
|
|
100
|
-
|
|
101
|
+
if (streams.Streams.length > 0) {
|
|
102
|
+
yield* streams.Streams
|
|
103
|
+
}
|
|
101
104
|
}
|
|
102
105
|
}
|
|
103
106
|
|
|
@@ -109,16 +112,18 @@ DynamoStream.prototype.getShards = async function* getShards(
|
|
|
109
112
|
StreamArn: Stream.StreamArn,
|
|
110
113
|
Limit: 100,
|
|
111
114
|
}).promise().then(get('StreamDescription'))
|
|
112
|
-
|
|
113
|
-
|
|
115
|
+
if (shards.Shards.length > 0) {
|
|
116
|
+
yield* shards.Shards.map(assign({ Stream: always(Stream) }))
|
|
117
|
+
}
|
|
114
118
|
while (!this.closed && shards.LastEvaluatedShardId != null) {
|
|
115
119
|
shards = await this.client.describeStream({
|
|
116
120
|
StreamArn: Stream.StreamArn,
|
|
117
121
|
Limit: 100,
|
|
118
122
|
ExclusiveStartShardId: shards.LastEvaluatedShardId,
|
|
119
123
|
}).promise().then(get('StreamDescription'))
|
|
120
|
-
|
|
121
|
-
|
|
124
|
+
if (shards.Shards.length > 0) {
|
|
125
|
+
yield* shards.Shards.map(assign({ Stream: always(Stream) }))
|
|
126
|
+
}
|
|
122
127
|
}
|
|
123
128
|
}
|
|
124
129
|
|
|
@@ -144,13 +149,23 @@ DynamoStream.prototype.getRecords = async function* getRecords(
|
|
|
144
149
|
Limit: this.getRecordsLimit
|
|
145
150
|
}).promise()
|
|
146
151
|
|
|
147
|
-
|
|
152
|
+
if (records.Records.length > 0) {
|
|
153
|
+
yield* records.Records.map(assign({
|
|
154
|
+
table: always(this.table),
|
|
155
|
+
shardId: always(Shard.ShardId),
|
|
156
|
+
}))
|
|
157
|
+
}
|
|
148
158
|
while (!this.closed && records.NextShardIterator != null) {
|
|
149
159
|
records = await this.client.getRecords({
|
|
150
160
|
ShardIterator: records.NextShardIterator,
|
|
151
161
|
Limit: this.getRecordsLimit
|
|
152
162
|
}).promise()
|
|
153
|
-
|
|
163
|
+
if (records.Records.length > 0) {
|
|
164
|
+
yield* records.Records.map(assign({
|
|
165
|
+
table: always(this.table),
|
|
166
|
+
shardId: always(Shard.ShardId),
|
|
167
|
+
}))
|
|
168
|
+
}
|
|
154
169
|
await new Promise(resolve => setTimeout(resolve, this.getRecordsInterval))
|
|
155
170
|
}
|
|
156
171
|
}
|
|
@@ -166,21 +181,21 @@ DynamoStream.prototype[Symbol.asyncIterator] = async function* () {
|
|
|
166
181
|
})),
|
|
167
182
|
transform(map(identity), []),
|
|
168
183
|
])()
|
|
169
|
-
let muxAsyncIterator = Mux.race(
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
184
|
+
let muxAsyncIterator = Mux.race([
|
|
185
|
+
...shards.map(Shard => this.getRecords(Shard)),
|
|
186
|
+
(async function* UpdateShardsGenerator() {
|
|
187
|
+
while (true) {
|
|
188
|
+
await new Promise(resolve => {
|
|
189
|
+
setTimeout(resolve, this.shardUpdatePeriod)
|
|
190
|
+
})
|
|
191
|
+
yield SymbolUpdateShards
|
|
192
|
+
}
|
|
193
|
+
}).call(this),
|
|
194
|
+
])
|
|
177
195
|
|
|
178
196
|
while (!this.closed) {
|
|
179
|
-
const
|
|
180
|
-
|
|
181
|
-
iterationPromise,
|
|
182
|
-
])
|
|
183
|
-
if (iteration == SymbolUpdateShards) {
|
|
197
|
+
const { value, done } = await muxAsyncIterator.next()
|
|
198
|
+
if (value == SymbolUpdateShards) {
|
|
184
199
|
const latestShards = await pipe([
|
|
185
200
|
always(this.getStreams()),
|
|
186
201
|
flatMap(Stream => this.getShards(Stream)),
|
|
@@ -197,23 +212,17 @@ DynamoStream.prototype[Symbol.asyncIterator] = async function* () {
|
|
|
197
212
|
})),
|
|
198
213
|
])()
|
|
199
214
|
|
|
200
|
-
if (this.debug) {
|
|
201
|
-
console.log('Latest shards:', latestShards.map(get('ShardId')))
|
|
202
|
-
}
|
|
203
|
-
|
|
204
215
|
shards = latestShards
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
} else if (
|
|
216
|
+
if (newShards.length > 0) {
|
|
217
|
+
muxAsyncIterator = Mux.race([
|
|
218
|
+
...newShards.map(Shard => this.getRecords(Shard)),
|
|
219
|
+
muxAsyncIterator,
|
|
220
|
+
])
|
|
221
|
+
}
|
|
222
|
+
} else if (done) {
|
|
212
223
|
await new Promise(resolve => setTimeout(resolve, 1000))
|
|
213
|
-
iterationPromise = muxAsyncIterator.next()
|
|
214
224
|
} else {
|
|
215
|
-
yield
|
|
216
|
-
iterationPromise = muxAsyncIterator.next()
|
|
225
|
+
yield value
|
|
217
226
|
}
|
|
218
227
|
}
|
|
219
228
|
}
|
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
|
|
@@ -183,43 +183,44 @@ const SymbolUpdateShards = Symbol('UpdateShards')
|
|
|
183
183
|
|
|
184
184
|
KinesisStream.prototype[Symbol.asyncIterator] = async function* generateRecords() {
|
|
185
185
|
let shards = await transform(map(identity), [])(this.listShards())
|
|
186
|
-
let muxAsyncIterator = Mux.race(
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
186
|
+
let muxAsyncIterator = Mux.race([
|
|
187
|
+
...shards.map(Shard => this.getRecords(Shard)),
|
|
188
|
+
(async function* UpdateShardsGenerator() {
|
|
189
|
+
while (true) {
|
|
190
|
+
await new Promise(resolve => {
|
|
191
|
+
setTimeout(resolve, this.shardUpdatePeriod)
|
|
192
|
+
})
|
|
193
|
+
yield SymbolUpdateShards
|
|
194
|
+
}
|
|
195
|
+
}).call(this),
|
|
196
|
+
])
|
|
192
197
|
|
|
193
198
|
while (!this.closed) {
|
|
194
|
-
const
|
|
195
|
-
|
|
196
|
-
iterationPromise,
|
|
197
|
-
])
|
|
198
|
-
if (iteration == SymbolUpdateShards) {
|
|
199
|
+
const { value, done } = await muxAsyncIterator.next()
|
|
200
|
+
if (value == SymbolUpdateShards) {
|
|
199
201
|
const latestShards = await transform(map(identity), [])(this.listShards())
|
|
200
|
-
const newShards =
|
|
201
|
-
(
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
202
|
+
const newShards = pipe([
|
|
203
|
+
always(shards),
|
|
204
|
+
differenceWith(
|
|
205
|
+
(ShardA, ShardB) => ShardA.ShardId == ShardB.ShardId,
|
|
206
|
+
latestShards,
|
|
207
|
+
),
|
|
208
|
+
map(assign({
|
|
209
|
+
ShardIteratorType: always('TRIM_HORIZON'),
|
|
210
|
+
})),
|
|
211
|
+
])()
|
|
208
212
|
|
|
209
|
-
closedShards.forEach(Shard => (Shard.closed = true))
|
|
210
213
|
shards = latestShards
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
} else if (
|
|
214
|
+
if (newShards.length > 0) {
|
|
215
|
+
muxAsyncIterator = Mux.race([
|
|
216
|
+
...newShards.map(Shard => this.getRecords(Shard)),
|
|
217
|
+
muxAsyncIterator,
|
|
218
|
+
])
|
|
219
|
+
}
|
|
220
|
+
} else if (done) {
|
|
218
221
|
await new Promise(resolve => setTimeout(resolve, 1000))
|
|
219
|
-
iterationPromise = muxAsyncIterator.next()
|
|
220
222
|
} else {
|
|
221
|
-
yield
|
|
222
|
-
iterationPromise = muxAsyncIterator.next()
|
|
223
|
+
yield value
|
|
223
224
|
}
|
|
224
225
|
}
|
|
225
226
|
}
|
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,26 @@ 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
|
+
})
|
|
69
|
+
|
|
49
70
|
.after(async function() {
|
|
50
71
|
await map(stream => stream.delete())(this.streams)
|
|
51
72
|
})
|
|
@@ -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
|