GreenKey

Scribe Real-Time Dictation Server (SQCServer)

An overview and best practices for using GreenKey Scribe to capture audio, interpret quotes and trades, use skills built in the Scribe Discovery Engine, or deploy general real-time transcription.




Deploying SQCServer

The Scribe Dictation server (SQCServer) can be launched on any Docker-compatible machine with at least 5 CPUs and 10 GB RAM for each 5 connection instance of SQCserver.

All of Scribe's services require an authorized account. Contact us if you are interested in obtaining an account.




Step 1: Install Docker

Follow the instructions here to install Docker on your machine.




Step 2: Download the SQCServer Docker image

$ docker login -u [repository-user] -p [repository-password] docker.greenkeytech.com
Login Succeeded
$ docker pull docker.greenkeytech.com/sqcserver-single:latest
$ docker save -o greenkey_scribe_sqcserver.tar docker.greenkeytech.com/sqcserver-single:latest

The credentials provided by GreenKey should include your repository-user and repository-password.




Step 3: Launch a Scribe Transcription Service

This container already has models downloaded.

$ docker run --rm -d \
  --name="sqcserver" \
  -e LICENSE_KEY="[license_key]" \
  -e PRODUCT_CLASS="[product_class]" \
  -p [target-port]:8888 \
  -v $(pwd)/[db-directory]:/scribe/db \
  -v $(pwd)/[data-directory]:/data \
  -e DATA_OUT="/data" \
  -e MODEL_TYPE="'tradervoice'" \
  -e USERS=2 \
  -e QUOTE_ACTIVATION_KEYWORD="confirm" \
  docker.greenkeytech.com/sqcserver-single:latest

license_key is the license key provided to you by GreenKey.

target-port is an open port on the machine that you will use to access the service.

db-directory is a directory where you store databases of common prices for your quotes and trades. These reference prices help our interpreters place decimal points correctly.

data-directory is a directory where you store captured quotes and trades for later processing.

model-type is either tradervoice (default) or general. Using the general model will give higher accuracy for general transcription but will disable quote / trade detection.

USERS is the maximum number of connections the container will allow (subject to license conditions).

An optional variable TRADE="True" will set the interpreter to interpret trades instead of quotes.

If you do not wish to store audio and json files, remove the DATA_OUT environmental variable from the docker run command.


Launching the Scribe Discovery Engine inside of the Scribe Dictation Server

You can configure SQCServer to launch the Scribe Discovery Engine automatically by setting -e DISCOVERY="True" in the docker run command. Custom intents and entities for use in Discovery can be mounted using -v $(pwd)/[custom-directory]:/custom, as illustrated below.

$ docker run --rm -d \
  --name="sqcserver" \
  ...
  -e DISCOVERY="True" \
  -v $(pwd)/[custom-directory]:/custom \
  ...
  docker.greenkeytech.com/sqcserver




Step 4: Confirm the container is running

docker logs sqcserver




Step 5: Transcribe a File (Optional)

Post against a websocket address using a python script available here by specifying the websocket-ip and target-port. If you are licensed for interpreting European government bonds, this test file will demonstrate the expected output. Should the service prove unavailable, a message will be returned indicating the status.

Here is a truncated json output for this test file.

$ python client.py -u ws://[websocket-ip]:[target-port]/client/ws/speech quote_detection.mp3
{
  "status": 0,
  "segment": 0,
  "result": {
    "hypotheses": [
      {
        "interpreted_quote": {
          "imString": "BKO 12/18 -- / .645",
          "product": "BKO",
          "terms": ["12/18"],
          "bid": "",
          "ask": ".645",
          "structure": "basis"
        },
        "transcript": "if i say a quote like dec eighteen schatz sixty four and a half offered i should see it popular at the end of this object",
        "product_class": "egbs",
      }
    ]
    "is_quote": true
  }
}

Occasionally, a quote is misclassified by SQCServer and misinterpreted. This can happen when keywords are common across multiple product classes. To force SQCServer to classify a quote as egbs, you can manually specify the interpreter to use at the command line using python client.py --interpreter egbs -u ws://[websocket-ip]:[target-port]/client/ws/speech quote_detection.mp3.

If you are using the Scribe Discovery Engine, you can specify your domains and interpreters here using python client.py --domains [comma-separated-domain-names] --interpreters [comma-separated-interpreter-names]. Both parameters are optional, and if you fail to provide any interpreters, but do specify one or more domains, we will find the appropriate interpreter within those domains and interpret it in Discovery.

The raw audio and json files are also be available in the data-directory if you specified this when launching the container. Note that if your model type is general, you will only have transcript outputted.




Step 6: Finalize your deployment

After setting up SQCServer, there are several options to connect to it.


1) Make a direct websocket connection

Our javascript example deployment shows you how to make a direct websocket connection to your server and receive the output in a browser.

Download the files above, then uncomment the following example in index.html and sqc/controller.js:

index.html

<!-- Begin Direct Connection Example -->
<button id="gktStart" onclick="toggleListening()">Start</button>
<button id="gktStop" onclick="toggleListening()">Stop</button>
<span id="gktServer" address="ws://[sqc-server-address]/client/ws/"></span>
<span id="gktRecorderWorker" address="sqc/recorderWorker.js">
<!-- End Direct Connection Example -->

Change the [sqc-server-address] to match that of your deployment.

sqc/controller.js

//// Direct connection example
function transcriptionReceived(code, data) {
  try {
    dataObject = JSON.parse(data);
    if ('result' in dataObject) {
      $('#JSONoutput').html(JSON.stringify(dataObject, null, 2));

            if ('hypotheses' in dataObject.result) {
                if ('clean_transcript' in dataObject.result.hypotheses[0]) {
                    $('#transcriptOutput').text(dataObject.result.hypotheses[0].clean_transcript)
                } else {
                    $('#transcriptOutput').text(dataObject.result.hypotheses[0].transcript)
                }
            }
    }
  }
  catch (err) {
    console.log(data);
  }
}

Once you get it running, it should look something like this:



2) Relay results over a websocket

Deploy the websocket relay server found in our call bot to enable the results to be broadcast to a backend endpoint. Once deployed, you can uncomment the following example in our javascript example deployment to relay the results received on the front-end via a second websocket connection that your application backend can listen to.

index.html

<!-- Begin Relay Example -->

PIN:<br>
<input type="text" id="gktPin"></input>
<button id="gktStart" onclick="toggleListening();readSocket()">Start</button>
<button id="gktStop" onclick="toggleListening()">Stop</button>
<span id="gktServer" address="ws://[sqc-server-address]/client/ws/"></span>
<span id="gktWSSServer" address="ws://[ws-server-address]/"></span>
<span id="gktRecorderWorker" address="sqc/recorderWorker.js">

<!-- End Relay Example -->

sqc/controller.js

//// Relay connection example
function transcriptionReceived(code, data) {
  try {
    dataObject = JSON.parse(data);
    if ('result' in dataObject) {
        socket.send(JSON.stringify({token: "XC7WFVC3UW3HPQRV5YUR", message: dataObject, endpoint: "/" + $('#gktPin').val()}));
    }
  }
  catch (err) {
    console.log(data)
  }
}

function readSocket() {
  var msg_socket = new WebSocket($('#gktWSSServer').attr('address') + $('#gktPin').val());

  msg_socket.onopen = function() {
    console.log("connected");
  }

  msg_socket.onclose = function(e) {
    console.log("connection closed (" + e.code + ")");
  }

  msg_socket.onmessage = function(e) {
    if (e.data.length > 0) {
        console.log("received message: " + e.data);
      $('#JSONoutput').html(JSON.stringify(JSON.parse(e.data), null, 2));
    }
  }

}

socketInit();

Make a websocket connection to your.websocket.address/pin that you entered to receive results.


3) Transcribe a SIP stream

Follow our call bot instructions to capture quotes and trades or transcribe in real-time via a SIP telephony connection.


Scaling SQCServer

Scribe Real-Time Dictation Server can be deployed in parallel as a service using a container orchestration engine, such as Kubernetes. An example Kubernetes service with persistent storage can be found here. The Kubernetes deployment accepts the same parameters described above.

Deploying with an orchestration engine can help meet high availabilty and scalability requirements. Configuring four replicas of sqcserver with two USERS each results in comparable performance to a single application instance with eight USERS, while also allowing those replicas to be spread across multiple machines to protect against failure scenarios. Adding more additional replicas should increase capacity in a linear fashion.

The service will not be exposed to the outside world without specifying the service as a Load Balancer or an additional ingress controller. Need help on setting up Kubernetes or another orchestration engine? Contact us.