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

102
backend/llm/gateway.go Normal file
View File

@@ -0,0 +1,102 @@
package llm
import (
"context"
"fmt"
)
// Gateway provides LLM functionality
type Gateway interface {
Generate(ctx context.Context, prompt string, options *GenerateOptions) (*GenerateResponse, error)
}
// GenerateOptions contains options for generation
type GenerateOptions struct {
Temperature float64
MaxTokens int
Tools []Tool
TenantID string
UserID string
ConversationHistory []Message
}
// Tool represents a callable tool/function
type Tool struct {
Name string
Description string
Parameters map[string]interface{}
}
// Message represents a conversation message
type Message struct {
Role string // "user" or "assistant"
Content string
}
// GenerateResponse contains the LLM response
type GenerateResponse struct {
Text string
Tools []ToolCall
Emotion *Emotion
Gestures []string
}
// ToolCall represents a tool call request
type ToolCall struct {
Name string
Arguments map[string]interface{}
}
// Emotion represents emotional state for avatar
type Emotion struct {
Valence float64 // -1.0 to 1.0
Arousal float64 // 0.0 to 1.0
}
// MockLLMGateway is a mock implementation for development
type MockLLMGateway struct{}
// NewMockLLMGateway creates a new mock LLM gateway
func NewMockLLMGateway() *MockLLMGateway {
return &MockLLMGateway{}
}
// Generate generates a response using mock LLM
func (g *MockLLMGateway) Generate(ctx context.Context, prompt string, options *GenerateOptions) (*GenerateResponse, error) {
// Mock implementation
return &GenerateResponse{
Text: "I understand. How can I assist you with your banking needs today?",
Emotion: &Emotion{
Valence: 0.5,
Arousal: 0.3,
},
Gestures: []string{"nod"},
}, nil
}
// OpenAIGateway integrates with OpenAI (example - requires API key)
type OpenAIGateway struct {
apiKey string
model string
}
// NewOpenAIGateway creates a new OpenAI gateway
func NewOpenAIGateway(apiKey, model string) *OpenAIGateway {
return &OpenAIGateway{
apiKey: apiKey,
model: model,
}
}
// Generate generates using OpenAI API
func (g *OpenAIGateway) Generate(ctx context.Context, prompt string, options *GenerateOptions) (*GenerateResponse, error) {
// TODO: Implement OpenAI API integration
// This would involve:
// 1. Building the prompt with system message, conversation history
// 2. Adding tool definitions if tools are provided
// 3. Making API call to OpenAI
// 4. Parsing response and extracting tool calls
// 5. Mapping to GenerateResponse format
return nil, fmt.Errorf("not implemented - requires OpenAI API integration")
}

124
backend/llm/prompt.go Normal file
View File

@@ -0,0 +1,124 @@
package llm
import (
"fmt"
"strings"
)
// BuildPrompt builds a prompt from components
func BuildPrompt(tenantConfig *TenantConfig, conversationHistory []Message, userInput string, retrievedDocs []RetrievedDoc) string {
var parts []string
// System message
systemMsg := buildSystemMessage(tenantConfig)
parts = append(parts, systemMsg)
// Retrieved documents (RAG context)
if len(retrievedDocs) > 0 {
parts = append(parts, "\n## Context:")
for i, doc := range retrievedDocs {
parts = append(parts, fmt.Sprintf("\n[Document %d]", i+1))
parts = append(parts, fmt.Sprintf("Title: %s", doc.Title))
parts = append(parts, fmt.Sprintf("Content: %s", doc.Content))
if doc.URL != "" {
parts = append(parts, fmt.Sprintf("Source: %s", doc.URL))
}
}
}
// Conversation history
if len(conversationHistory) > 0 {
parts = append(parts, "\n## Conversation History:")
for _, msg := range conversationHistory {
parts = append(parts, fmt.Sprintf("%s: %s", strings.Title(msg.Role), msg.Content))
}
}
// Current user input
parts = append(parts, fmt.Sprintf("\n## User: %s", userInput))
parts = append(parts, "\n## Assistant:")
return strings.Join(parts, "\n")
}
// TenantConfig holds tenant-specific configuration
type TenantConfig struct {
Greeting string
Tone string // "professional", "friendly", "formal"
Disclaimers []string
AllowedTools []string
}
// RetrievedDoc represents a retrieved document from RAG
type RetrievedDoc struct {
Title string
Content string
URL string
Score float64
}
// BuildPromptWithRAG builds a prompt with RAG context
func BuildPromptWithRAG(tenantConfig *TenantConfig, conversationHistory []Message, userInput string, retrievedDocs []RetrievedDoc) string {
var parts []string
// System message
systemMsg := buildSystemMessage(tenantConfig)
parts = append(parts, systemMsg)
// Retrieved documents (RAG context)
if len(retrievedDocs) > 0 {
parts = append(parts, "\n## Context:")
for i, doc := range retrievedDocs {
parts = append(parts, fmt.Sprintf("\n[Document %d]", i+1))
parts = append(parts, fmt.Sprintf("Title: %s", doc.Title))
parts = append(parts, fmt.Sprintf("Content: %s", doc.Content))
if doc.URL != "" {
parts = append(parts, fmt.Sprintf("Source: %s", doc.URL))
}
}
}
// Conversation history
if len(conversationHistory) > 0 {
parts = append(parts, "\n## Conversation History:")
for _, msg := range conversationHistory {
parts = append(parts, fmt.Sprintf("%s: %s", strings.Title(msg.Role), msg.Content))
}
}
// Current user input
parts = append(parts, fmt.Sprintf("\n## User: %s", userInput))
parts = append(parts, "\n## Assistant:")
return strings.Join(parts, "\n")
}
// buildSystemMessage builds the system message
func buildSystemMessage(config *TenantConfig) string {
var parts []string
parts = append(parts, "You are a helpful Virtual Banker assistant.")
if config.Tone != "" {
parts = append(parts, fmt.Sprintf("Your tone should be %s.", config.Tone))
}
if len(config.Disclaimers) > 0 {
parts = append(parts, "\nImportant disclaimers:")
for _, disclaimer := range config.Disclaimers {
parts = append(parts, fmt.Sprintf("- %s", disclaimer))
}
}
if len(config.AllowedTools) > 0 {
parts = append(parts, "\nYou have access to the following tools:")
for _, tool := range config.AllowedTools {
parts = append(parts, fmt.Sprintf("- %s", tool))
}
}
parts = append(parts, "\nAlways be helpful, accurate, and respectful.")
parts = append(parts, "If you don't know something, say so and offer to help find the answer.")
return strings.Join(parts, "\n")
}