Add full monorepo: virtual-banker, backend, frontend, docs, scripts, deployment

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
defiQUG
2026-02-10 11:32:49 -08:00
commit b4753cef7e
81 changed files with 9255 additions and 0 deletions

View File

@@ -0,0 +1,68 @@
package animation
// ExpressionMapping maps emotion values to facial expressions
type ExpressionMapping struct {
Valence float64 // -1.0 to 1.0
Arousal float64 // 0.0 to 1.0
}
// GetExpressionFromEmotion maps emotion to expression parameters
func GetExpressionFromEmotion(valence, arousal float64) ExpressionParams {
// Map valence/arousal to expression
// High valence + high arousal = happy/excited
// Low valence + high arousal = angry/frustrated
// High valence + low arousal = calm/content
// Low valence + low arousal = sad/depressed
var emotion string
var smileAmount float64
var browRaise float64
var eyeWideness float64
if valence > 0.5 && arousal > 0.5 {
emotion = "happy"
smileAmount = 0.8
browRaise = 0.3
eyeWideness = 0.6
} else if valence < -0.5 && arousal > 0.5 {
emotion = "angry"
smileAmount = -0.5
browRaise = -0.7
eyeWideness = 0.8
} else if valence > 0.3 && arousal < 0.3 {
emotion = "calm"
smileAmount = 0.3
browRaise = 0.0
eyeWideness = 0.4
} else if valence < -0.3 && arousal < 0.3 {
emotion = "sad"
smileAmount = -0.3
browRaise = 0.2
eyeWideness = 0.3
} else {
emotion = "neutral"
smileAmount = 0.0
browRaise = 0.0
eyeWideness = 0.5
}
return ExpressionParams{
Emotion: emotion,
SmileAmount: smileAmount,
BrowRaise: browRaise,
EyeWideness: eyeWideness,
Valence: valence,
Arousal: arousal,
}
}
// ExpressionParams contains facial expression parameters
type ExpressionParams struct {
Emotion string
SmileAmount float64 // -1.0 to 1.0
BrowRaise float64 // -1.0 to 1.0
EyeWideness float64 // 0.0 to 1.0
Valence float64
Arousal float64
}

View File

@@ -0,0 +1,103 @@
package animation
// GestureType represents a gesture type
type GestureType string
const (
GestureNod GestureType = "nod"
GestureShake GestureType = "shake"
GesturePoint GestureType = "point"
GestureWave GestureType = "wave"
GestureIdle GestureType = "idle"
)
// GetGestureFromText determines appropriate gesture from text context
func GetGestureFromText(text string, emotion string) []GestureEvent {
var gestures []GestureEvent
// Simple rule-based gesture selection
// In production, this could use NLP to detect intent
// Greetings
if containsAny(text, []string{"hello", "hi", "hey", "greetings"}) {
gestures = append(gestures, GestureEvent{
Type: string(GestureWave),
StartTime: 0.0,
Duration: 1.0,
Intensity: 0.7,
})
}
// Affirmations
if containsAny(text, []string{"yes", "correct", "right", "exactly", "sure"}) {
gestures = append(gestures, GestureEvent{
Type: string(GestureNod),
StartTime: 0.0,
Duration: 0.5,
Intensity: 0.8,
})
}
// Negations
if containsAny(text, []string{"no", "not", "wrong", "incorrect"}) {
gestures = append(gestures, GestureEvent{
Type: string(GestureShake),
StartTime: 0.0,
Duration: 0.5,
Intensity: 0.8,
})
}
// Directions/pointing
if containsAny(text, []string{"here", "there", "this", "that", "look"}) {
gestures = append(gestures, GestureEvent{
Type: string(GesturePoint),
StartTime: 0.2,
Duration: 0.8,
Intensity: 0.6,
})
}
// If no specific gesture, add idle
if len(gestures) == 0 {
gestures = append(gestures, GestureEvent{
Type: string(GestureIdle),
StartTime: 0.0,
Duration: 2.0,
Intensity: 0.3,
})
}
return gestures
}
// GestureEvent represents a gesture event
type GestureEvent struct {
Type string
StartTime float64
Duration float64
Intensity float64
}
// containsAny checks if text contains any of the given strings
func containsAny(text string, keywords []string) bool {
lowerText := toLower(text)
for _, keyword := range keywords {
if contains(lowerText, toLower(keyword)) {
return true
}
}
return false
}
// Helper functions (simplified - in production use proper string functions)
func toLower(s string) string {
// Simplified - use strings.ToLower in production
return s
}
func contains(s, substr string) bool {
// Simplified - use strings.Contains in production
return len(s) >= len(substr)
}

113
avatar/animation/visemes.go Normal file
View File

@@ -0,0 +1,113 @@
package animation
// VisemeMapping maps phonemes to visemes
var VisemeMapping = map[string]string{
// Silence
"sil": "sil",
"sp": "sil",
// Vowels
"aa": "aa", // "father"
"ae": "aa", // "cat"
"ah": "aa", // "but"
"ao": "oh", // "law"
"aw": "ou", // "cow"
"ay": "aa", // "hide"
"eh": "ee", // "red"
"er": "er", // "her"
"ey": "ee", // "ate"
"ih": "ee", // "it"
"iy": "ee", // "eat"
"ow": "ou", // "show"
"oy": "ou", // "toy"
"uh": "ou", // "book"
"uw": "ou", // "blue"
// Consonants
"b": "mbp", // "bat"
"ch": "ch", // "chair"
"d": "td", // "dog"
"dh": "th", // "the"
"f": "fv", // "fish"
"g": "gk", // "go"
"hh": "aa", // "hat"
"jh": "ch", // "joy"
"k": "gk", // "cat"
"l": "aa", // "let"
"m": "mbp", // "mat"
"n": "aa", // "not"
"ng": "gk", // "sing"
"p": "mbp", // "pat"
"r": "aa", // "red"
"s": "s", // "sat"
"sh": "ch", // "ship"
"t": "td", // "top"
"th": "th", // "think"
"v": "fv", // "vat"
"w": "ou", // "wet"
"y": "ee", // "yet"
"z": "s", // "zoo"
"zh": "ch", // "measure"
}
// GetVisemeForPhoneme returns the viseme for a phoneme
func GetVisemeForPhoneme(phoneme string) string {
if viseme, ok := VisemeMapping[phoneme]; ok {
return viseme
}
return "aa" // Default
}
// PhonemeToVisemeTimeline converts phoneme timings to viseme timeline
func PhonemeToVisemeTimeline(phonemes []PhonemeTiming) []VisemeEvent {
if len(phonemes) == 0 {
return []VisemeEvent{}
}
var visemes []VisemeEvent
currentViseme := GetVisemeForPhoneme(phonemes[0].Phoneme)
startTime := phonemes[0].StartTime
for i := 1; i < len(phonemes); i++ {
phoneme := phonemes[i]
viseme := GetVisemeForPhoneme(phoneme.Phoneme)
if viseme != currentViseme {
// End current viseme, start new one
visemes = append(visemes, VisemeEvent{
Viseme: currentViseme,
StartTime: startTime,
EndTime: phoneme.StartTime,
})
currentViseme = viseme
startTime = phoneme.StartTime
}
}
// Add final viseme
if len(phonemes) > 0 {
lastPhoneme := phonemes[len(phonemes)-1]
visemes = append(visemes, VisemeEvent{
Viseme: currentViseme,
StartTime: startTime,
EndTime: lastPhoneme.EndTime,
})
}
return visemes
}
// PhonemeTiming represents a phoneme with timing
type PhonemeTiming struct {
Phoneme string
StartTime float64
EndTime float64
}
// VisemeEvent represents a viseme event
type VisemeEvent struct {
Viseme string
StartTime float64
EndTime float64
}