Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
c36e8ba
add github.com/makiuchi-d/gozxing dependency for go to scan qr code
Prachi1615 Jun 10, 2026
e042bb1
add luma integration
Prachi1615 Jun 10, 2026
d5448b0
update config
Prachi1615 Jun 10, 2026
9c7f0fe
update input plugin
Prachi1615 Jun 11, 2026
1f32c69
fix mac camera issue
Prachi1615 Jun 11, 2026
597ab5e
add new config and rtsp for qr scanner
Prachi1615 Jun 11, 2026
5a19026
updated qr scanner logic and added a new luma provider
Prachi1615 Jun 11, 2026
bf00509
deleted old luma action plugin
Prachi1615 Jun 11, 2026
85c797a
removed stale entry from actions.go
Prachi1615 Jun 11, 2026
1367ca7
updated local config for luma plugin
Prachi1615 Jun 12, 2026
82ce220
updated configs
Prachi1615 Jun 12, 2026
3df7450
update config
Prachi1615 Jun 12, 2026
0490d0b
fix greeting issues
Prachi1615 Jun 12, 2026
89ae062
fix greeting config
Prachi1615 Jun 12, 2026
9c22ea6
fix config
Prachi1615 Jun 12, 2026
5b3ea80
update configs
Prachi1615 Jun 12, 2026
7d028b0
fix issues in qr scanner
Prachi1615 Jun 12, 2026
b788cc2
add default width and height for camera back
Prachi1615 Jun 12, 2026
8b37a94
add face size check background plugin
Prachi1615 Jun 12, 2026
2dbe86d
remove config
Prachi1615 Jun 12, 2026
1e06f7a
update face check area
Prachi1615 Jun 12, 2026
8b009d8
remove config
Prachi1615 Jun 12, 2026
2712e7c
revert vlm video dtream changes
Prachi1615 Jun 13, 2026
eff2cfe
merge main and resolve conflicts
Prachi1615 Jun 13, 2026
1eb0478
added luma checkin flow
Prachi1615 Jun 14, 2026
ff4a88b
fix lint
Prachi1615 Jun 14, 2026
92e8e73
fix tests
Prachi1615 Jun 14, 2026
512cfba
fix lint
Prachi1615 Jun 14, 2026
7b1e1d9
fix lint
Prachi1615 Jun 14, 2026
7f4b363
Add Luma check-in provider and plugins
openminddev Jun 15, 2026
6fdd21d
add face lingering check to track checkedin attendees
Prachi1615 Jun 15, 2026
f6f93ef
update checkin status
Prachi1615 Jun 15, 2026
b3e6243
update checkin status
Prachi1615 Jun 15, 2026
adc8566
fix new attendee greeting
Prachi1615 Jun 15, 2026
ab1aafd
add logs
Prachi1615 Jun 15, 2026
ee59c1e
fix lingering face logic
Prachi1615 Jun 15, 2026
475efac
fix lingering face logic
Prachi1615 Jun 16, 2026
1f273fb
clear the queue after mode sqitch
Prachi1615 Jun 16, 2026
d6b374e
fix luma hook
Prachi1615 Jun 16, 2026
6a5e2dc
fix lingering person speech generateion
Prachi1615 Jun 16, 2026
0f59fa7
fix lingering person speech generateion
Prachi1615 Jun 16, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ require (
github.com/google/uuid v1.6.0
github.com/gordonklaus/portaudio v0.0.0-20260203164431-765aa7dfa631
github.com/gorilla/websocket v1.5.3
github.com/makiuchi-d/gozxing v0.1.1
github.com/prometheus/client_golang v1.23.2
github.com/santhosh-tekuri/jsonschema/v6 v6.0.2
github.com/stretchr/testify v1.11.1
Expand All @@ -34,6 +35,7 @@ require (
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 // indirect
golang.org/x/sys v0.35.0 // indirect
golang.org/x/text v0.37.0 // indirect
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
google.golang.org/protobuf v1.36.8 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
github.com/makiuchi-d/gozxing v0.1.1 h1:xxqijhoedi+/lZlhINteGbywIrewVdVv2wl9r5O9S1I=
github.com/makiuchi-d/gozxing v0.1.1/go.mod h1:eRIHbOjX7QWxLIDJoQuMLhuXg9LAuw6znsUtRkNw9DU=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
Expand Down Expand Up @@ -68,6 +70,8 @@ golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=
golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/text v0.37.0 h1:Cqjiwd9eSg8e0QAkyCaQTNHFIIzWtidPahFWR83rTrc=
golang.org/x/text v0.37.0/go.mod h1:a5sjxXGs9hsn/AJVwuElvCAo9v8QYLzvavO5z2PiM38=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/protobuf v1.36.8 h1:xHScyCOEuuwZEc6UtSOvPbAT4zRh0xcNRYekJwfqyMc=
google.golang.org/protobuf v1.36.8/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
Expand Down
22 changes: 12 additions & 10 deletions internal/hooks/greeting_hook.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,39 +32,41 @@ const defaultGreetingPrompt = "You are {robot_name}, a friendly robot greeting w
"Finish by offering help, for example: \"{help_message}\". " +
"Respond with only the greeting text, with no quotes or commentary."

// greetingStartHook handles the start of a greeting conversation by generating a
// greeting message using an LLM and sending it to the TTS provider.
func (r *Runner) greetingStartHook(ctx context.Context, cfg, vars map[string]any) error {
return r.announceGenerated(ctx, cfg, vars, defaultGreetingPrompt, "How can I help you today?")
}

func (r *Runner) announceGenerated(ctx context.Context, cfg, vars map[string]any, defaultPrompt, defaultHelp string) error {
provider, err := r.greetingTTSProvider(cfg)
if err != nil {
r.log.Error("greeting_start_hook: error", zap.Error(err))
r.log.Error("greeting hook: error", zap.Error(err))
return err
}

robotName := formatTemplate(stringVal(cfg, "robot_name"), vars)

helpMessage := "How can I help you today?"
helpMessage := defaultHelp
if custom := formatTemplate(stringVal(cfg, "custom_message"), vars); custom != "" {
helpMessage = custom
}

face := providers.NewFacePresenceProvider(providers.FacePresenceConfig{})
snapshot, snapErr := face.FetchSnapshot(ctx)
if snapErr != nil {
r.log.Warn("greeting_start_hook: face snapshot failed", zap.Error(snapErr))
r.log.Warn("greeting hook: face snapshot failed", zap.Error(snapErr))
}

memContext := r.recallMemory(ctx, snapshot.ClosestUUID)

if greeting, genErr := r.generateGreeting(ctx, cfg, vars, snapshot, memContext, robotName, helpMessage); genErr != nil {
r.log.Warn("greeting_start_hook: llm generation failed, using static greeting", zap.Error(genErr))
if greeting, genErr := r.generateGreeting(ctx, cfg, vars, snapshot, memContext, robotName, helpMessage, defaultPrompt); genErr != nil {
r.log.Warn("greeting hook: llm generation failed, using static greeting", zap.Error(genErr))
provider.AddText(staticGreeting(snapshot, snapErr, robotName, helpMessage))
} else {
r.log.Info("greeting generated successfully", zap.String("greeting", greeting))
provider.AddText(greeting)
}

r.log.Info("greeting start hook executed successfully")
r.log.Info("greeting hook executed successfully")
return nil
}

Expand Down Expand Up @@ -92,7 +94,7 @@ func memoryClause(memContext string) string {
}

// generateGreeting constructs a prompt using the snapshot and other context, calls the LLM to generate a greeting, and returns the greeting text.
func (r *Runner) generateGreeting(ctx context.Context, cfg, vars map[string]any, snapshot providers.PresenceSnapshot, memContext, robotName, helpMessage string) (string, error) {
func (r *Runner) generateGreeting(ctx context.Context, cfg, vars map[string]any, snapshot providers.PresenceSnapshot, memContext, robotName, helpMessage, defaultPrompt string) (string, error) {
if robotName == "" {
robotName = "a friendly robot"
}
Expand All @@ -106,7 +108,7 @@ func (r *Runner) generateGreeting(ctx context.Context, cfg, vars map[string]any,

promptTemplate := stringVal(cfg, "prompt")
if strings.TrimSpace(promptTemplate) == "" {
promptTemplate = defaultGreetingPrompt
promptTemplate = defaultPrompt
}

promptVars := make(map[string]any, len(vars)+6)
Expand Down
25 changes: 25 additions & 0 deletions internal/hooks/luma_hook.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package hooks

import (
"context"
)

func init() {
RegisterHook("luma_hook", "luma_intro_hook", (*Runner).lumaIntroHook)
}

const defaultLumaHelp = "Are you registered on Luma?"

const defaultLumaPrompt = "You are {robot_name}, a friendly robot welcoming a guest to an event. " +
"The current time is {current_time}. " +
"Generate a single warm, natural spoken greeting of one or two short sentences. " +
"Here is what you currently see: {scene}. " +
"Make it feel personal and present by naturally referencing something specific from what you see; never invent anything. " +
"If a specific person is recognized ({closest_name}), greet them by name; otherwise greet generically. " +
"{memory}" +
"Finish by asking the guest whether they are registered on Luma, for example: \"{help_message}\". " +
"Respond with only the greeting text, with no quotes or commentary."

func (r *Runner) lumaIntroHook(ctx context.Context, cfg, vars map[string]any) error {
return r.announceGenerated(ctx, cfg, vars, defaultLumaPrompt, defaultLumaHelp)
}
19 changes: 19 additions & 0 deletions internal/hooks/luma_hook_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package hooks

import (
"strings"
"testing"

"github.com/stretchr/testify/require"
)

func TestLumaHookRegistered(t *testing.T) {
_, ok := lookupHook("luma_hook", "luma_intro_hook")
require.True(t, ok)
}

func TestLumaPromptMentionsLuma(t *testing.T) {
require.True(t, strings.Contains(defaultLumaPrompt, "{help_message}"),
"prompt must interpolate the help message")
require.Contains(t, strings.ToLower(defaultLumaHelp), "luma")
}
21 changes: 21 additions & 0 deletions internal/providers/luma/checkin.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package luma

import (
"sync/atomic"
"time"
)

type CheckIn struct {
Name string
Time time.Time
}

var lastCheckIn atomic.Pointer[CheckIn]

func RecordCheckIn(name string, t time.Time) {
lastCheckIn.Store(&CheckIn{Name: name, Time: t})
}

func LastCheckIn() *CheckIn {
return lastCheckIn.Load()
}
31 changes: 31 additions & 0 deletions internal/providers/luma/checkin_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package luma

import (
"testing"
"time"
)

func TestRecordAndLastCheckIn(t *testing.T) {
if got := LastCheckIn(); got != nil {
t.Fatalf("expected nil before any publish, got %+v", got)
}

t1 := time.Unix(1_700_000_000, 0)
RecordCheckIn("Ada", t1)

got := LastCheckIn()
if got == nil {
t.Fatal("expected a check-in after publish")
}
if got.Name != "Ada" || !got.Time.Equal(t1) {
t.Fatalf("unexpected check-in: %+v", got)
}

// A later publish replaces the previous value.
t2 := t1.Add(time.Minute)
RecordCheckIn("Grace", t2)
got = LastCheckIn()
if got.Name != "Grace" || !got.Time.Equal(t2) {
t.Fatalf("expected latest check-in to be Grace@t2, got %+v", got)
}
}
Loading
Loading