Skip to content

Commit

Permalink
Merge branch 'develop' v0.8.10
Browse files Browse the repository at this point in the history
  • Loading branch information
rstrahan committed Nov 25, 2023
2 parents 5911442 + 680427f commit 6466cb1
Show file tree
Hide file tree
Showing 63 changed files with 19,315 additions and 83 deletions.
13 changes: 11 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [0.8.10] - 2023-11-25
### Added
- New! Websocket audio ingestion server (optional). Use it to enable audio streaming from a custom desktop client application, from the sample streaming app (below), or from the new LCA Web UI audio streaming client. See [Websocket server](./lca-websocket-stack/README.md).
- New! Sample audio streaming application which streams a stereo audio file from your desktop to LCA via the new websocket server. Use this to replay recordings, e.g. for testing transcription accuracy after CV/CLM changes, for testing agent assist features, etc. Or use the code as a reference implementation for building your own custom streaming app for LCA. See [Websocket client app](./utilities/websocket-client/README.md).
- New! Web UI audio streaming client built into the LCA UI. Use this to stream audio into LCA from (a) your computer microphone, and (b) from a local broswer tab that is running a softphone or meeting app, or playing an audio recording. See [Web UI streaming client](./lca-ai-stack/WebUIStreamingClient.md).
### Fix
- publish.sh script now runs on MacOS (now works with GNU or BSD sed command).

## [0.8.9] - 2023-11-01
### Added
- Allow customer to specify their own Voice Connector as a CloudFormation Template parameter. If the customer provided Voice Connector is provided, LCA will not deploy a new VC. (#102)
Expand Down Expand Up @@ -335,8 +343,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

- Initial release

[Unreleased]: https://github.com/aws-samples/amazon-transcribe-live-call-analytics/compare/v0.8.9...develop
[0.8.9]: https://github.com/aws-samples/amazon-transcribe-live-call-analytics/compare/v0.8.7...v0.8.9
[Unreleased]: https://github.com/aws-samples/amazon-transcribe-live-call-analytics/compare/v0.8.10...develop
[0.8.10]: https://github.com/aws-samples/amazon-transcribe-live-call-analytics/compare/v0.8.9...v0.8.10
[0.8.9]: https://github.com/aws-samples/amazon-transcribe-live-call-analytics/compare/v0.8.8...v0.8.9
[0.8.8]: https://github.com/aws-samples/amazon-transcribe-live-call-analytics/compare/v0.8.7...v0.8.8
[0.8.7]: https://github.com/aws-samples/amazon-transcribe-live-call-analytics/compare/v0.8.6...v0.8.7
[0.8.6]: https://github.com/aws-samples/amazon-transcribe-live-call-analytics/compare/v0.8.5...v0.8.6
Expand Down
89 changes: 45 additions & 44 deletions README.md

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.8.9
0.8.10
Binary file added images/websocket-start-stream.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/websocket-stop-stream.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/websocket-stream.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion lca-ai-stack/VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.8.9
0.8.10
15 changes: 15 additions & 0 deletions lca-ai-stack/WebUIStreamingClient.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Web UI Streaming Client

## Introduction
LCA UI offers an option to stream audio from a browser tab+Microphone to LCA/Agent Assist.
Enable the feature `WebSocketAudioInput` when deploying/updating the LCA stack.

To use this feature:
1. From the LCA UI, click on `Stream Audio` link from the left navigation menu as shown below. ![Stream](../images/websocket-stream.png)
2. Change default values for Call ID, Agent ID, Customer Phone, and System Phone as needed. Assign a role to the mic input - Agent vs. Caller.
3. Click on `Start Streaming` as shown below.![Stream](../images/websocket-start-stream.png)
4. Share the browser tab that is playing the media (video/audio files, meeting, etc.)
5. Speak into the microphone.
6. The web streaming client combines the audio output from browser tab and the microphone input into a streo (two channel) audio stream. The client sends the stream to the websocket server for downstream processing (enrichment, agent assist, etc.).
7. Click on `Stop Streaming` to end the streaming session. ![Stream](../images/websocket-stop-stream.png)

20 changes: 14 additions & 6 deletions lca-ai-stack/deployment/lca-ai-stack.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ Parameters:
- Amazon Chime SDK Voice Connector (SIPREC)
- Genesys Cloud Audiohook Web Socket
- Amazon Connect Contact Lens

Description: >
Choose whether to automatically install a demo Asterisk PBX server for easy standalone testing, a
Amazon Chime SDK Voice Connector to use for standards based SIPREC/NBR integration with your contact center,
Expand Down Expand Up @@ -284,7 +285,7 @@ Parameters:
BootstrapVersion:
Type: String
Default: 0.8.9
Default: 0.8.10
Description: >
Artifacts version (semver). Used to point to a specific release in the S3
bootstrap bucket
Expand Down Expand Up @@ -365,13 +366,17 @@ Conditions:

Outputs:
CallDataStreamName:
Description: >-
The Name of Kinesis Data Stream to write the call data to.
Value: !Ref CallDataStream
Description: >-
The Name of Kinesis Data Stream to write the call data to.
Value: !Ref CallDataStream
CallDataStreamArn:
Description: >-
The ARN of Kinesis Data Stream to write the call data to.
Value: !GetAtt CallDataStream.Arn
UserPoolId:
Description: >-
The id of Cognito user pool.
Value: !Ref UserPool
S3BucketName:
Description: Bucket which contains all the call recordings
Value: !If
Expand Down Expand Up @@ -413,7 +418,10 @@ Outputs:
CloudFrontDomainName:
Description: The full domain name of the CloudFront distribution
Value: !GetAtt WebAppCloudFrontDistribution.DomainName

LCASettingsParameterName:
Description: Name of the Parameter store
Value: !Ref LCASettingsParameter

TranscriptSummaryFunctionArn:
Description: Call Summarizer Lambda function ARN
Value: !If [
Expand Down Expand Up @@ -545,7 +553,7 @@ Resources:
Type: AWS::SSM::Parameter
Properties:
Type: String
Value: !Sub '{ "CategoryAlertRegex":"${CategoryAlertRegEx}", "EnableVoiceToneAnalysis":"${EnableVoiceToneAnalysis}" }'
Value: !Sub '{ "CategoryAlertRegex":"${CategoryAlertRegEx}", "EnableVoiceToneAnalysis":"${EnableVoiceToneAnalysis}", "WSEndpoint":"" }'

##########################################################################
# CodeBuild
Expand Down
8 changes: 4 additions & 4 deletions lca-ai-stack/samconfig.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,20 @@ use_container = true
# shared account
[shared.global.parameters]
s3_bucket = "lca-artifacts-253873381732-us-east-1"
s3_prefix = "artifacts/lca/0.8.9"
s3_prefix = "artifacts/lca/0.8.10"

[shared.deploy.parameters]
stack_name = "LiveCallAnalytics"
s3_bucket = "lca-artifacts-253873381732-us-east-1"
s3_prefix = "artifacts/lca/0.8.9"
s3_prefix = "artifacts/lca/0.8.10"
region = "us-east-1"
fail_on_empty_changeset = false
confirm_changeset = true
capabilities = "CAPABILITY_IAM CAPABILITY_AUTO_EXPAND"
parameter_overrides = [
"BootstrapBucketBaseName=lca-artifacts-253873381732",
"BootstrapS3Prefix=artifacts/lca",
"BootstrapVersion=0.8.9",
"BootstrapVersion=0.8.10",
"S3BucketName=shared-ai-for-chime-vc-audio",
"IsContentRedactionEnabled=true",
"IsSentimentAnalysisEnabled=true",
Expand All @@ -32,4 +32,4 @@ parameter_overrides = [

[shared.package.parameters]
s3_bucket = "lca-artifacts-253873381732-us-east-1"
s3_prefix = "artifacts/lca/0.8.9"
s3_prefix = "artifacts/lca/0.8.10"
36 changes: 28 additions & 8 deletions lca-ai-stack/source/ui/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion lca-ai-stack/source/ui/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "lca-ui",
"version": "0.8.9",
"version": "0.8.10",
"private": true,
"dependencies": {
"@aws-amplify/ui-components": "^1.9.6",
Expand Down Expand Up @@ -30,6 +30,7 @@
"react-markdown": "^8.0.3",
"react-router-dom": "^5.3.0",
"react-scripts": "5.0.1",
"react-use-websocket": "^3.0.0",
"rehype-raw": "^6.1.1",
"vuera": "^0.2.7",
"xlsx": "^0.18.5"
Expand Down
113 changes: 113 additions & 0 deletions lca-ai-stack/source/ui/public/worklets/recording-processor.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
// Based on sample from
// https://github.com/GoogleChromeLabs/web-audio-samples/blob/main/src/audio-worklet/migration/worklet-recorder/recording-processor.js

class RecordingProcessor extends AudioWorkletProcessor {
constructor(options) {
super();
this.sampleRate = 0;
this.maxRecordingFrames = 0;
this.numberOfChannels = 0;
this._frameSize = 128;

if (options && options.processorOptions) {
const {
numberOfChannels,
sampleRate,
maxFrameCount,
} = options.processorOptions;

this.sampleRate = sampleRate;
this.maxRecordingFrames = maxFrameCount;
this.numberOfChannels = numberOfChannels;
}

this._leftRecordingBuffer = new Float32Array(this.maxRecordingFrames);
this._rightRecordingBuffer = new Float32Array(this.maxRecordingFrames);

this.recordedFrames = 0;
this.isRecording = false;

this.framesSinceLastPublish = 0;
this.publishInterval = this.sampleRate * 5;

this.port.onmessage = (event) => {
if (event.data.message === 'UPDATE_RECORDING_STATE') {
this.isRecording = event.data.setRecording;
}
};
}

process(inputs, outputs) {
let currentSample = 0.0;
for (let input = 0; input < 1; input++) {
for (let channel = 0; channel < this.numberOfChannels; channel++) {
for (let sample = 0; sample < inputs[input][channel].length; sample++) {

currentSample = inputs[input][channel][sample];

if (this.isRecording) {
if (channel == 0) {
this._leftRecordingBuffer[sample+this.recordedFrames] = currentSample;
} else if (channel == 1) {
this._rightRecordingBuffer[sample+this.recordedFrames] = currentSample;
}
}
// Pass data directly to output, unchanged.
outputs[input][channel][sample] = currentSample;
}

}
}

const shouldPublish = this.framesSinceLastPublish >= this.publishInterval;

// Validate that recording hasn't reached its limit.
if (this.isRecording) {
if (this.recordedFrames + this._frameSize < this.maxRecordingFrames) {
this.recordedFrames += this._frameSize;

// Post a recording recording length update on the clock's schedule
if (shouldPublish) {
const recordingBuffer = new Array(this.numberOfChannels)
.fill(new Float32Array(this.maxRecordingFrames));
recordingBuffer[0] = this._leftRecordingBuffer;
recordingBuffer[1] = this._rightRecordingBuffer;
this.port.postMessage({
message: 'SHARE_RECORDING_BUFFER',
buffer: recordingBuffer,
recordingLength: this.recordedFrames
});
this.framesSinceLastPublish = 0;
this.recordedFrames = 0
} else {
this.framesSinceLastPublish += this._frameSize;
}
} else {
this.recordedFrames += this._frameSize;

const recordingBuffer = new Array(this.numberOfChannels)
.fill(new Float32Array(this.maxRecordingFrames));
recordingBuffer[0] = this._leftRecordingBuffer;
recordingBuffer[1] = this._rightRecordingBuffer;

this.port.postMessage({
message: 'SHARE_RECORDING_BUFFER',
buffer: recordingBuffer,
recordingLength: this.recordedFrames
});

this.recordedFrames = 0;
this.framesSinceLastPublish = 0;
}
} else {
console.log('stopping worklet processor node')
this.recordedFrames = 0;
this.framesSinceLastPublish = 0;
return false;
}

return true;
}
}

registerProcessor('recording-processor', RecordingProcessor);
3 changes: 3 additions & 0 deletions lca-ai-stack/source/ui/src/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ const App = () => {
const { authState, user } = useUserAuthState(awsConfig);
const { currentSession, currentCredentials } = useCurrentSessionCreds({ authState });
const [errorMessage, setErrorMessage] = useState();
const [navigationOpen, setNavigationOpen] = useState(true);

// eslint-disable-next-line react/jsx-no-constructed-context-values
const appContextValue = {
Expand All @@ -32,6 +33,8 @@ const App = () => {
currentSession,
setErrorMessage,
user,
navigationOpen,
setNavigationOpen,
};
logger.debug('appContextValue', appContextValue);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,16 +26,18 @@ import {
PERIODS_TO_LOAD_STORAGE_KEY,
} from '../call-list/calls-table-config';

import useAppContext from '../../contexts/app';

const logger = new Logger('CallAnalyticsLayout');

const CallAnalyticsLayout = () => {
const { navigationOpen, setNavigationOpen } = useAppContext();

const { path } = useRouteMatch();
logger.debug('path', path);

const notifications = useNotifications();
const [toolsOpen, setToolsOpen] = useState(false);
const [navigationOpen, setNavigationOpen] = useState(false);

const [selectedItems, setSelectedItems] = useState([]);

const getInitialPeriodsToLoad = () => {
Expand Down
Loading

0 comments on commit 6466cb1

Please sign in to comment.