Skip to content

Commit

Permalink
Refactor Live/Streaming Structs, Modules, etc to Encapsulate Internals
Browse files Browse the repository at this point in the history
  • Loading branch information
dvonthenen committed Oct 24, 2023
1 parent 047d382 commit 39281f8
Show file tree
Hide file tree
Showing 16 changed files with 923 additions and 117 deletions.
93 changes: 36 additions & 57 deletions examples/streaming/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,15 @@ package main

import (
"bufio"
"context"
"fmt"
"log"
"net/http"
"os"
"reflect"
"time"

gabs "github.com/Jeffail/gabs/v2"
"github.com/dvonthenen/websocket"

interfaces "github.com/deepgram-devs/deepgram-go-sdk/pkg/client/interfaces"
client "github.com/deepgram-devs/deepgram-go-sdk/pkg/client/live"
)

Expand All @@ -26,73 +25,53 @@ const (
)

func main() {
var deepgramApiKey string
if v := os.Getenv("DEEPGRAM_API_KEY"); v != "" {
log.Println("DEEPGRAM_API_KEY found")
deepgramApiKey = v
} else {
log.Fatal("DEEPGRAM_API_KEY not found")
os.Exit(1)
}
// context
ctx := context.Background()

// HTTP client
httpClient := new(http.Client)
// options
transcriptOptions := interfaces.LiveTranscriptionOptions{
Language: "en-US",
Punctuate: true,
}

res, err := httpClient.Get(STREAM_URL)
dgClient, err := client.NewWithDefaults(ctx, transcriptOptions)
if err != nil {
log.Println("ERROR getting stream", err)
log.Println("ERROR creating LiveTranscription connection:", err)
return
}
defer res.Body.Close()

fmt.Println("Stream is up and running ", reflect.TypeOf(res))

reader := bufio.NewReader(res.Body)

// live transcription
liveTranscriptionOptions := client.LiveTranscriptionOptions{
Language: "en-US",
Punctuate: true,
// call connect!
wsconn := dgClient.Connect()
if wsconn == nil {
log.Println("Client.Connect failed")
os.Exit(1)
}

dgConn, _, err := client.New(deepgramApiKey, liveTranscriptionOptions)
// feed the stream to the websocket
httpClient := new(http.Client)

res, err := httpClient.Get(STREAM_URL)
if err != nil {
log.Println("ERROR creating LiveTranscription connection:", err)
log.Printf("httpClient.Get failed. Err: %v\n", err)
return
}
defer dgConn.Close()

// process messages
chunk := make([]byte, CHUNK_SIZE)
fmt.Printf("Stream is up and running %s\n", reflect.TypeOf(res))

// this is a blocking call...
go func() {
for {
_, message, err := dgConn.ReadMessage()
if err != nil {
log.Println("ERROR reading message:", err)
return
}

jsonParsed, jsonErr := gabs.ParseJSON(message)
if jsonErr != nil {
log.Println("ERROR parsing JSON message:", err)
return
}
log.Printf("recv: %s", jsonParsed.Path("channel.alternatives.0.transcript").String())
}
dgClient.Stream(bufio.NewReader(res.Body))
}()

for {
bytesRead, err := reader.Read(chunk)

if err != nil {
log.Println("ERROR reading chunk:", err)
return
}
err = dgConn.WriteMessage(websocket.BinaryMessage, chunk[:bytesRead])
if err != nil {
log.Println("ERROR writing message:", err)
return
}
time.Sleep(TEN_MILLISECONDS_SLEEP)
}
fmt.Print("Press ENTER to exit!\n\n")
input := bufio.NewScanner(os.Stdin)
input.Scan()

// close HTTP stream
res.Body.Close()

// close client
dgClient.Stop()

fmt.Printf("Succeeded!\n\n")
}
9 changes: 8 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,11 @@ require (
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
)

require github.com/dvonthenen/websocket v1.5.1-dyv.2 // indirect
require (
github.com/dvonthenen/websocket v1.5.1-dyv.2 // indirect
github.com/fatih/color v1.15.0 // indirect
github.com/hokaccha/go-prettyjson v0.0.0-20211117102719-0474bc63780f // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.17 // indirect
golang.org/x/sys v0.6.0 // indirect
)
12 changes: 12 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,27 @@ github.com/Jeffail/gabs/v2 v2.7.0 h1:Y2edYaTcE8ZpRsR2AtmPu5xQdFDIthFG0jYhu5PY8kg
github.com/Jeffail/gabs/v2 v2.7.0/go.mod h1:dp5ocw1FvBBQYssgHsG7I1WYsiLRtkUaB1FEtSwvNUw=
github.com/dvonthenen/websocket v1.5.1-dyv.2 h1:OXlWJJkeHt8k4+MEI0Y8SQjY2ihHYD2z/tI7sZZfsnA=
github.com/dvonthenen/websocket v1.5.1-dyv.2/go.mod h1:q2GbopbpFJvBP4iqVvqwwahVmvu2HnCfdqCWDoQVKMM=
github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs=
github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/hokaccha/go-prettyjson v0.0.0-20211117102719-0474bc63780f h1:7LYC+Yfkj3CTRcShK0KOL/w6iTiKyqqBA9a41Wnggw8=
github.com/hokaccha/go-prettyjson v0.0.0-20211117102719-0474bc63780f/go.mod h1:pFlLw2CfqZiIBOx6BuCeRLCrfxBJipTY0nIOF/VbGcI=
github.com/jarcoal/httpmock v1.3.0 h1:2RJ8GP0IIaWwcC9Fp2BmVi8Kog3v2Hn7VXM3fTd+nuc=
github.com/jarcoal/httpmock v1.3.0/go.mod h1:3yb8rc4BI7TCBhFY8ng0gjuLKJNquuDNiPaZjnENuYg=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng=
github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk=
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=
15 changes: 15 additions & 0 deletions pkg/api/live/v1/constants.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Copyright 2023 Deepgram SDK contributors. All Rights Reserved.
// Use of this source code is governed by a MIT license that can be found in the LICENSE file.
// SPDX-License-Identifier: MIT

package live

import "errors"

var (
// ErrInvalidMessageType invalid message type
ErrInvalidMessageType = errors.New("invalid message type")

// ErrUserCallbackNotDefined user callback object not defined
ErrUserCallbackNotDefined = errors.New("user callback object not defined")
)
75 changes: 75 additions & 0 deletions pkg/api/live/v1/default.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
// Copyright 2023 Deepgram SDK contributors. All Rights Reserved.
// Use of this source code is governed by a MIT license that can be found in the LICENSE file.
// SPDX-License-Identifier: MIT

package live

import (

// prettyjson "github.com/hokaccha/go-prettyjson"

"log"
"strings"

interfaces "github.com/deepgram-devs/deepgram-go-sdk/pkg/api/live/v1/interfaces"
)

type DefaultCallbackHandler struct {
sb strings.Builder
}

func (dch DefaultCallbackHandler) Message(mr *interfaces.MessageResponse) error {
// DEBUG: just print the transcription
// data, err := json.Marshal(mr)
// if err != nil {
// log.Printf("RecognitionResult json.Marshal failed. Err: %v\n", err)
// return err
// }

// prettyJson, err := prettyjson.Format(data)
// if err != nil {
// log.Printf("prettyjson.Marshal failed. Err: %v\n", err)
// return err
// }
// log.Printf("\n\nMessage Object:\n%s\n\n", prettyJson)

// Only print the final transcript
// // handle the message
// sentence := strings.TrimSpace(mr.Channel.Alternatives[0].Transcript)

// if len(mr.Channel.Alternatives) == 0 || len(sentence) == 0 {
// // klog.V(7).Infof("DEEPGRAM - no transcript")
// return nil
// }

// isFinal := mr.SpeechFinal
// sentence = strings.ToLower(sentence)
// dch.sb.WriteString(sentence)

// // // debug
// // klog.V(4).Infof("transcription result: text = %s, final = %t", i.sb.String(), isFinal)

// if !isFinal {
// // klog.V(7).Infof("DEEPGRAM - not final")
// return nil
// }

// // debug
// log.Printf("Deepgram transcription: text = %s, final = %t", dch.sb.String(), isFinal)
// dch.sb.Reset()

// handle the message
sentence := strings.TrimSpace(mr.Channel.Alternatives[0].Transcript)

if len(mr.Channel.Alternatives) == 0 || len(sentence) == 0 {
// klog.V(7).Infof("DEEPGRAM - no transcript")
return nil
}
log.Printf("%s\n", sentence)

return nil
}

func NewDefaultCallbackHandler() DefaultCallbackHandler {
return DefaultCallbackHandler{}
}
13 changes: 13 additions & 0 deletions pkg/api/live/v1/interfaces/constants.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Copyright 2023 Deepgram SDK contributors. All Rights Reserved.
// Use of this source code is governed by a MIT license that can be found in the LICENSE file.
// SPDX-License-Identifier: MIT

package interfaces

const (
// message types
TypeMessageResponse string = "Results"

// Error type
TypeErrorResponse string = "Error"
)
11 changes: 11 additions & 0 deletions pkg/api/live/v1/interfaces/interfaces.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// Copyright 2023 Deepgram SDK contributors. All Rights Reserved.
// Use of this source code is governed by a MIT license that can be found in the LICENSE file.
// SPDX-License-Identifier: MIT

package interfaces

// LiveMessageCallback is a callback used to receive notifcations for platforms messages
type LiveMessageCallback interface {
Message(mr *MessageResponse) error
// TODO: implement other conversation insights
}
56 changes: 56 additions & 0 deletions pkg/api/live/v1/interfaces/types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// Copyright 2023 Deepgram SDK contributors. All Rights Reserved.
// Use of this source code is governed by a MIT license that can be found in the LICENSE file.
// SPDX-License-Identifier: MIT

package interfaces

/*
Shared defintions for the Deepgram API
*/
type Words struct {
Confidence float64 `json:"confidence,omitempty"`
End float64 `json:"end,omitempty"`
PunctuatedWord string `json:"punctuated_word,omitempty"`
Start float64 `json:"start,omitempty"`
Word string `json:"word,omitempty"`
}
type Alternatives struct {
Confidence float64 `json:"confidence,omitempty"`
Transcript string `json:"transcript,omitempty"`
Words []Words `json:"words,omitempty"`
}
type Channel struct {
Alternatives []Alternatives `json:"alternatives,omitempty"`
}

type ModelInfo struct {
Arch string `json:"arch,omitempty"`
Name string `json:"name,omitempty"`
Version string `json:"version,omitempty"`
}
type Metadata struct {
ModelInfo ModelInfo `json:"model_info,omitempty"`
ModelUUID string `json:"model_uuid,omitempty"`
RequestID string `json:"request_id,omitempty"`
}

/*
Results from Live Transcription
*/
type MessageResponse struct {
Channel Channel `json:"channel,omitempty"`
ChannelIndex []int `json:"channel_index,omitempty"`
Duration float64 `json:"duration,omitempty"`
IsFinal bool `json:"is_final,omitempty"`
Metadata Metadata `json:"metadata,omitempty"`
SpeechFinal bool `json:"speech_final,omitempty"`
Start float64 `json:"start,omitempty"`
Type string `json:"type,omitempty"`
}

type ErrorResponse struct {
Description string `json:"description"`
Message string `json:"message"`
Type string `json:"type"`
Variant string `json:"variant"`
}
Loading

0 comments on commit 39281f8

Please sign in to comment.