Skip to content

Commit f7fdfcd

Browse files
Merge pull request #95 from dvonthenen/complex-nebula-example
Complex Nebula LLM example
2 parents b6ecbf1 + 8d3e223 commit f7fdfcd

File tree

13 files changed

+511
-9
lines changed

13 files changed

+511
-9
lines changed
File renamed without changes.
File renamed without changes.
File renamed without changes.

examples/ask-nebula/cmd.go renamed to examples/nebula/ask-nebula/cmd.go

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ package main
77
import (
88
"context"
99
"encoding/json"
10-
"flag"
1110
"fmt"
1211
"os"
1312

@@ -19,10 +18,6 @@ import (
1918
)
2019

2120
func main() {
22-
var accessToken string
23-
flag.StringVar(&accessToken, "token", "", "Symbl.ai Nebula Token")
24-
flag.Parse()
25-
2621
symbl.Init(symbl.SybmlInit{
2722
LogLevel: symbl.LogLevelTrace,
2823
})
@@ -34,7 +29,7 @@ func main() {
3429
*/
3530
ctx := context.Background()
3631

37-
client, err := symbl.NewNebulaClientWithToken(ctx, accessToken)
32+
client, err := symbl.NewNebulaRestClient(ctx)
3833
if err == nil {
3934
fmt.Println("Succeeded!")
4035
} else {

examples/nebula/realtime/cmd.go

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
// Copyright 2023 Symbl.ai SDK contributors. All Rights Reserved.
2+
// Use of this source code is governed by an Apache-2.0 license that can be found in the LICENSE file.
3+
// SPDX-License-Identifier: Apache-2.0
4+
5+
package main
6+
7+
// streaming
8+
import (
9+
"bufio"
10+
"context"
11+
"fmt"
12+
"os"
13+
"time"
14+
15+
nebula "github.com/dvonthenen/symbl-go-sdk/pkg/api/nebula/v1"
16+
microphone "github.com/dvonthenen/symbl-go-sdk/pkg/audio/microphone"
17+
symbl "github.com/dvonthenen/symbl-go-sdk/pkg/client"
18+
19+
handler "github.com/dvonthenen/symbl-go-sdk/examples/nebula/realtime/handler"
20+
)
21+
22+
func main() {
23+
// init the library
24+
symbl.Init(symbl.SybmlInit{
25+
LogLevel: symbl.LogLevelStandard, // LogLevelStandard / LogLevelTrace
26+
})
27+
28+
// context
29+
ctx := context.Background()
30+
31+
// create the chatgpt client
32+
fmt.Printf("Connecting to Nebula...\n")
33+
restClient, err := symbl.NewNebulaRestClient(ctx)
34+
if err == nil {
35+
fmt.Println("Succeeded!")
36+
} else {
37+
fmt.Printf("New failed. Err: %v\n", err)
38+
os.Exit(1)
39+
}
40+
41+
nebulaClient := nebula.New(restClient)
42+
fmt.Printf("Connection Succeeded\n")
43+
44+
// init library
45+
microphone.Initialize()
46+
47+
// init the handler
48+
msgHandler := handler.NewHandler(handler.HandlerOptions{
49+
NebulaClient: nebulaClient,
50+
})
51+
52+
// create a new client
53+
symblConfig := symbl.GetDefaultConfig()
54+
symblConfig.Speaker.Name = "John Doe"
55+
symblConfig.Speaker.UserID = "[email protected]"
56+
symblConfig.Config.DetectEntities = true
57+
symblConfig.Config.Sentiment = true
58+
59+
options := symbl.StreamingOptions{
60+
SymblConfig: symblConfig,
61+
Callback: msgHandler,
62+
}
63+
64+
client, err := symbl.NewStreamClient(ctx, options)
65+
if err == nil {
66+
fmt.Println("Login Succeeded!")
67+
} else {
68+
fmt.Printf("New failed. Err: %v\n", err)
69+
os.Exit(1)
70+
}
71+
fmt.Printf("ConversationID: %s\n", client.GetConversationId())
72+
73+
err = client.Start()
74+
if err == nil {
75+
fmt.Printf("Streaming Session Started!\n")
76+
} else {
77+
fmt.Printf("client.Start failed. Err: %v\n", err)
78+
os.Exit(1)
79+
}
80+
81+
// delay...
82+
time.Sleep(time.Second * 1)
83+
84+
// mic stuf
85+
mic, err := microphone.New(microphone.AudioConfig{
86+
InputChannels: 1,
87+
SamplingRate: 16000,
88+
})
89+
if err != nil {
90+
fmt.Printf("Initialize failed. Err: %v\n", err)
91+
os.Exit(1)
92+
}
93+
94+
// start the mic
95+
err = mic.Start()
96+
if err != nil {
97+
fmt.Printf("mic.Start failed. Err: %v\n", err)
98+
os.Exit(1)
99+
}
100+
101+
go func() {
102+
// this is a blocking call
103+
mic.Stream(client)
104+
}()
105+
106+
fmt.Print("Press ENTER to exit!\n\n")
107+
input := bufio.NewScanner(os.Stdin)
108+
input.Scan()
109+
110+
// close stream
111+
err = mic.Stop()
112+
if err != nil {
113+
fmt.Printf("mic.Stop failed. Err: %v\n", err)
114+
os.Exit(1)
115+
}
116+
117+
// teardown library
118+
microphone.Teardown()
119+
120+
// close client
121+
client.Stop()
122+
123+
fmt.Printf("Succeeded!\n\n")
124+
}
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
// Copyright 2023 Symbl.ai SDK contributors. All Rights Reserved.
2+
// Use of this source code is governed by an Apache-2.0 license that can be found in the LICENSE file.
3+
// SPDX-License-Identifier: Apache-2.0
4+
5+
package handler
6+
7+
import (
8+
"container/list"
9+
"fmt"
10+
)
11+
12+
func NewMessageCache() *MessageCache {
13+
cache := MessageCache{
14+
rotatingWindowOfMsg: list.New(),
15+
mapIdToMsg: make(map[string]*Message),
16+
}
17+
return &cache
18+
}
19+
20+
func (mc *MessageCache) Push(msgId, text, name, email string) error {
21+
mc.mu.Lock()
22+
defer mc.mu.Unlock()
23+
24+
// if len(mc.mapIdToMsg) >= DefaultNumOfMsgToCache {
25+
// e := mc.rotatingWindowOfMsg.Front()
26+
// if e != nil {
27+
// itemMessage := Message(e.Value.(Message))
28+
// delete(mc.mapIdToMsg, itemMessage.ID)
29+
// mc.rotatingWindowOfMsg.Remove(e)
30+
// }
31+
// }
32+
33+
message := Message{
34+
ID: msgId,
35+
Text: text,
36+
Author: Author{
37+
Name: name,
38+
Email: email,
39+
},
40+
}
41+
mc.mapIdToMsg[msgId] = &message
42+
mc.rotatingWindowOfMsg.PushBack(message)
43+
44+
return nil
45+
}
46+
47+
func (mc *MessageCache) Find(msgId string) (*Message, error) {
48+
mc.mu.Lock()
49+
defer mc.mu.Unlock()
50+
51+
message := mc.mapIdToMsg[msgId]
52+
53+
if message == nil {
54+
return nil, ErrItemNotFound
55+
}
56+
57+
return message, nil
58+
}
59+
60+
func (mc *MessageCache) ReturnConversation() string {
61+
conversation := ""
62+
63+
for e := mc.rotatingWindowOfMsg.Front(); e != nil; e = e.Next() {
64+
msg := Message(e.Value.(Message))
65+
// fmt.Sprintf("msg: %v\n", msg)
66+
conversation += fmt.Sprintf("%s: %s\n", msg.Author.Name, msg.Text)
67+
}
68+
69+
return conversation
70+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Copyright 2023 Symbl.ai SDK contributors. All Rights Reserved.
2+
// Use of this source code is governed by an Apache-2.0 license that can be found in the LICENSE file.
3+
// SPDX-License-Identifier: Apache-2.0
4+
5+
package handler
6+
7+
import "errors"
8+
9+
// const (
10+
// // default number of message to cache at any given time
11+
// DefaultNumOfMsgToCache int = 50
12+
// )
13+
14+
var (
15+
// ErrUnhandledMessage runhandled message from nebula example handler
16+
ErrUnhandledMessage = errors.New("unhandled message from nebula example handler")
17+
18+
// ErrItemNotFound item not found
19+
ErrItemNotFound = errors.New("item not found")
20+
)
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
// Copyright 2023 Symbl.ai SDK contributors. All Rights Reserved.
2+
// Use of this source code is governed by an Apache-2.0 license that can be found in the LICENSE file.
3+
// SPDX-License-Identifier: Apache-2.0
4+
5+
package handler
6+
7+
import (
8+
"context"
9+
"fmt"
10+
11+
interfaces "github.com/dvonthenen/symbl-go-sdk/pkg/api/nebula/v1/interfaces"
12+
sdkinterfaces "github.com/dvonthenen/symbl-go-sdk/pkg/api/streaming/v1/interfaces"
13+
)
14+
15+
func NewHandler(options HandlerOptions) *Handler {
16+
handler := Handler{
17+
cache: NewMessageCache(),
18+
nebulaClient: options.NebulaClient,
19+
}
20+
return &handler
21+
}
22+
23+
func (h *Handler) InitializedConversation(im *sdkinterfaces.InitializationMessage) error {
24+
h.conversationID = im.Message.Data.ConversationID
25+
fmt.Printf("conversationID: %s\n", h.conversationID)
26+
return nil
27+
}
28+
29+
func (h *Handler) RecognitionResultMessage(rr *sdkinterfaces.RecognitionResult) error {
30+
// No implementation required. Return Succeess!
31+
return nil
32+
}
33+
34+
func (h *Handler) MessageResponseMessage(mr *sdkinterfaces.MessageResponse) error {
35+
for _, msg := range mr.Messages {
36+
fmt.Printf("\n\nMessage [%s]: %s\n\n", msg.From.Name, msg.Payload.Content)
37+
h.cache.Push(msg.ID, msg.Payload.Content, msg.From.ID, msg.From.Name)
38+
}
39+
return nil
40+
}
41+
42+
func (h *Handler) InsightResponseMessage(ir *sdkinterfaces.InsightResponse) error {
43+
for _, insight := range ir.Insights {
44+
switch insight.Type {
45+
case sdkinterfaces.InsightTypeQuestion:
46+
err := h.HandleQuestion(&insight, ir.SequenceNumber)
47+
if err != nil {
48+
fmt.Printf("HandleQuestion failed. Err: %v\n", err)
49+
return err
50+
}
51+
case sdkinterfaces.InsightTypeFollowUp:
52+
err := h.HandleFollowUp(&insight, ir.SequenceNumber)
53+
if err != nil {
54+
fmt.Printf("HandleFollowUp failed. Err: %v\n", err)
55+
return err
56+
}
57+
case sdkinterfaces.InsightTypeActionItem:
58+
err := h.HandleActionItem(&insight, ir.SequenceNumber)
59+
if err != nil {
60+
fmt.Printf("HandleActionItem failed. Err: %v\n", err)
61+
return err
62+
}
63+
default:
64+
fmt.Printf("\n\n-------------------------------\n")
65+
fmt.Printf("Unknown InsightResponseMessage: %s\n\n", insight.Type)
66+
fmt.Printf("-------------------------------\n\n")
67+
return nil
68+
}
69+
}
70+
71+
return nil
72+
}
73+
74+
func (h *Handler) TopicResponseMessage(tr *sdkinterfaces.TopicResponse) error {
75+
conversation := h.cache.ReturnConversation()
76+
77+
for _, curTopic := range tr.Topics {
78+
prompt := fmt.Sprintf("The topic of \"%s\" came up in this conversation I am having. Concisely summarize how this topic is relevant to this conversation.\n", curTopic.Phrases)
79+
80+
request := interfaces.AskNebulaRequest{
81+
Prompt: interfaces.Prompt{
82+
Instruction: prompt,
83+
Conversation: interfaces.Conversation{
84+
Text: conversation,
85+
},
86+
},
87+
}
88+
89+
nebulaResult, err := h.nebulaClient.AskNebula(context.Background(), request)
90+
if err != nil {
91+
fmt.Printf("AskNebula failed. Err: %v\n", err)
92+
return nil
93+
}
94+
95+
fmt.Printf("\n\n-------------------------------\n")
96+
fmt.Printf("TOPIC:\n%s\n", prompt)
97+
fmt.Printf("\n\nNebula Response:\n%s\n", nebulaResult.Output.Text)
98+
fmt.Printf("-------------------------------\n\n")
99+
}
100+
101+
return nil
102+
}
103+
104+
func (h *Handler) TrackerResponseMessage(tr *sdkinterfaces.TrackerResponse) error {
105+
// No implementation required. Return Succeess!
106+
return nil
107+
}
108+
109+
func (h *Handler) EntityResponseMessage(er *sdkinterfaces.EntityResponse) error {
110+
// No implementation required. Return Succeess!
111+
return nil
112+
}
113+
114+
func (h *Handler) TeardownConversation(tm *sdkinterfaces.TeardownMessage) error {
115+
// No implementation required. Return Succeess!
116+
return nil
117+
}
118+
119+
func (h *Handler) UserDefinedMessage(data []byte) error {
120+
// This is only needed on the client side and not on the plugin side.
121+
// No implementation required. Return Succeess!
122+
return nil
123+
}
124+
125+
func (h *Handler) UnhandledMessage(byMsg []byte) error {
126+
fmt.Printf("\n\n-------------------------------\n")
127+
fmt.Printf("UnhandledMessage:\n%v\n", string(byMsg))
128+
fmt.Printf("-------------------------------\n\n")
129+
return ErrUnhandledMessage
130+
}
131+
132+
func (h *Handler) HandleQuestion(insight *sdkinterfaces.Insight, number int) error {
133+
// No implementation required. Return Succeess!
134+
return nil
135+
}
136+
137+
func (h *Handler) HandleActionItem(insight *sdkinterfaces.Insight, number int) error {
138+
// No implementation required. Return Succeess!
139+
return nil
140+
}
141+
142+
func (h *Handler) HandleFollowUp(insight *sdkinterfaces.Insight, number int) error {
143+
// No implementation required. Return Succeess!
144+
return nil
145+
}

0 commit comments

Comments
 (0)