Skip to content

Latest commit

 

History

History
420 lines (318 loc) · 9.55 KB

File metadata and controls

420 lines (318 loc) · 9.55 KB

Integration Guide

Step-by-step guide to integrating the Shiny AI Assistant into your dashboard.

Prerequisites

  • R 4.0+ with Shiny
  • Node.js 18+ (for running the API server)
  • Anthropic API key

Quick Start

1. Start the API Server

cd packages/server
cp .env.example .env
# Edit .env and add: ANTHROPIC_API_KEY=your-key

pnpm install
pnpm dev
# Server runs at http://localhost:3000

2. Install the R Package

# From the packages/r-shiny directory
devtools::install_local("packages/r-shiny")

3. Add to Your Shiny App

library(shiny)
library(shinyAIAssistant)

ui <- fluidPage(
  titlePanel("My Dashboard"),
  # Your existing UI...

  # Add AI Assistant widget
  aiAssistantWidget(
    apiUrl = "http://localhost:3000/api/chat"
  )
)

server <- function(input, output, session) {
  # Your existing server logic...
}

shinyApp(ui, server)

That's it! You now have a floating chat button in your dashboard.


Capability Levels

The assistant supports 4 capability levels, each adding more features:

Level Features Requirements
0 Navigation, highlighting, basic Q&A Widget only
1 Enhanced context, glossary, component metadata + Manifest YAML
2 Action execution (filters, exports) + Action handlers in R
3 Data queries, analytics + Data source config

Level 0: Basic Integration

With just the widget, the AI can:

  • Answer questions about what it sees on screen
  • Navigate between tabs/pages
  • Highlight and locate UI elements
  • Provide general assistance
aiAssistantWidget(
  apiUrl = "http://localhost:3000/api/chat",
  position = "bottom-right",  # or "bottom-left"
  theme = "auto"              # "light", "dark", or "auto"
)

Level 1: Enhanced Context with Manifest

A manifest file provides rich metadata about your dashboard.

Create dashboard-manifest.yaml

name: "Sales Analytics Dashboard"
version: "1.0.0"
description: "Revenue analysis for the executive team"
capabilityLevel: "level-1"

# Custom instructions for the AI
aiInstructions: |
  This dashboard shows sales performance metrics.
  Always mention specific numbers when answering questions.

# Business term definitions
glossary:
  - term: "ARR"
    definition: "Annual Recurring Revenue"
    synonyms: ["annual revenue"]
  - term: "MRR"
    definition: "Monthly Recurring Revenue"

# Navigation structure
navigation:
  - id: "overview"
    label: "Overview"
    path: "/overview"
    description: "Executive summary with KPIs"
  - id: "regional"
    label: "Regional"
    path: "/regional"
    description: "Performance by region"

# Page and component documentation
pages:
  - id: "overview"
    title: "Overview"
    components:
      - id: "revenue_chart"
        label: "Revenue Trend"
        type: "chart"
        description: "Monthly ARR over time"

Reference in Your App

aiAssistantWidget(
  apiUrl = "http://localhost:3000/api/chat",
  manifest = "dashboard-manifest.yaml"
)

Level 2: Enable Actions

Allow the AI to execute actions like setting filters or exporting data.

Update Manifest

capabilityLevel: "level-2"

actions:
  - id: "set_filter"
    name: "Set Filter"
    description: "Apply a filter value"
    category: "update"
    parameters:
      - name: "filterId"
        type: "string"
        required: true
      - name: "value"
        type: "string"
        required: true

  - id: "reset_filters"
    name: "Reset Filters"
    description: "Clear all filters"
    category: "update"

Add Action Handlers in R

server <- function(input, output, session) {
  # Your existing logic...

  # Register AI action handlers
  aiAssistantHandler(session, handlers = list(
    # Navigate to a tab
    navigate_to = function(params) {
      nav_select("main_nav", params$target)
      list(success = TRUE, message = paste("Navigated to", params$target))
    },

    # Set a filter
    set_filter = function(params) {
      updateSelectInput(session, params$filterId, selected = params$value)
      list(success = TRUE, message = paste("Set", params$filterId, "to", params$value))
    },

    # Set date range
    set_date_range = function(params) {
      updateDateRangeInput(session, "date_filter",
        start = as.Date(params$start),
        end = as.Date(params$end)
      )
      list(success = TRUE, message = "Date range updated")
    },

    # Reset all filters
    reset_filters = function(params) {
      updateSelectInput(session, "region_filter", selected = "All")
      updateSelectInput(session, "product_filter", selected = "All")
      updateDateRangeInput(session, "date_filter", start = DATE_MIN, end = DATE_MAX)
      list(success = TRUE, message = "All filters reset")
    }
  ))
}

Level 3: Data Queries

Enable the AI to query your data and provide analytical insights.

Update Widget Configuration

# Define data sources
data_sources <- list(
  list(
    id = "sales",
    name = "Sales Transactions",
    description = "Transaction data with revenue, region, and product info",
    fields = list(
      list(name = "date", type = "date", filterable = TRUE),
      list(name = "region", type = "string", filterable = TRUE,
           enumValues = c("North America", "EMEA", "APAC", "LATAM")),
      list(name = "arr", type = "number", aggregatable = TRUE,
           description = "Annual Recurring Revenue"),
      list(name = "product", type = "string", filterable = TRUE)
    )
  )
)

# Enable Level 3
aiAssistantWidget(
  apiUrl = "http://localhost:3000/api/chat",
  manifest = "dashboard-manifest.yaml",
  dataSources = data_sources,
  enableDataQueries = TRUE
)

Add Query Handler

aiAssistantHandler(session, handlers = list(
  # ... other handlers ...

  query_data = function(params) {
    # params contains: source, select, filters, groupBy, aggregations, limit
    data <- sales_data  # Your data source

    # Apply filters
    if (!is.null(params$filters)) {
      for (f in params$filters) {
        data <- data %>% filter(.data[[f$field]] == f$value)
      }
    }

    # Apply grouping and aggregation
    if (!is.null(params$groupBy)) {
      data <- data %>%
        group_by(across(all_of(params$groupBy))) %>%
        summarise(across(where(is.numeric), sum))
    }

    # Limit results
    if (!is.null(params$limit)) {
      data <- head(data, params$limit)
    }

    list(
      success = TRUE,
      data = as.list(data),
      rowCount = nrow(data)
    )
  }
))

Widget Configuration Reference

aiAssistantWidget(
  # Required
  apiUrl = "http://localhost:3000/api/chat",

  # Optional - Enhanced context
  manifest = "dashboard-manifest.yaml",

  # Optional - Level 3 data queries
  dataSources = list(...),
  enableDataQueries = FALSE,

  # Optional - Appearance
  position = "bottom-right",  # "bottom-left" | "bottom-right"
  theme = "auto",             # "light" | "dark" | "auto"

  # Optional - Initial state
  defaultOpen = FALSE,
  welcomeMessage = "How can I help you today?"
)

Handler Return Values

All handlers should return a list with:

# Success
list(success = TRUE, message = "Action completed")

# Success with data
list(success = TRUE, data = list(field = "value"), message = "Query complete")

# Failure
list(success = FALSE, error = "Description of what went wrong")

Common Patterns

Filter Handler with Validation

set_filter = function(params) {
  valid_filters <- c("region_filter", "product_filter", "segment_filter")

  if (!params$filterId %in% valid_filters) {
    return(list(success = FALSE, error = paste("Unknown filter:", params$filterId)))
  }

  updateSelectInput(session, params$filterId, selected = params$value)
  list(success = TRUE, message = paste("Set", params$filterId, "to", params$value))
}

Date Range with Bounds Checking

set_date_range = function(params) {
  start <- as.Date(params$start)
  end <- as.Date(params$end)

  if (is.na(start) || is.na(end)) {
    return(list(success = FALSE, error = "Invalid date format. Use YYYY-MM-DD."))
  }

  if (start > end) {
    return(list(success = FALSE, error = "Start date must be before end date."))
  }

  updateDateRangeInput(session, "date_filter", start = start, end = end)
  list(success = TRUE, message = paste("Date range set to", start, "-", end))
}

Navigation with Tab Validation

navigate_to = function(params) {
  valid_tabs <- c("overview", "regional", "details", "explorer")

  if (!params$target %in% valid_tabs) {
    return(list(success = FALSE, error = paste("Unknown tab:", params$target)))
  }

  nav_select("main_nav", params$target)
  list(success = TRUE, message = paste("Navigated to", params$target))
}

Troubleshooting

Widget Not Appearing

  1. Check browser console for JavaScript errors
  2. Verify API URL is accessible (try opening it directly)
  3. Ensure shinyAIAssistant package is loaded

Actions Not Working

  1. Verify aiAssistantHandler() is called in server function
  2. Check R console for error messages
  3. Ensure handler names match action types (e.g., set_filter not setFilter)

Slow Responses

  1. Check network latency to API server
  2. Verify Anthropic API key is valid
  3. Consider using streaming (enabled by default)

Highlighting Not Working

  1. Ensure elements have stable, unique IDs
  2. Check for CSS z-index conflicts
  3. Verify manifest component IDs match actual element IDs

Next Steps

  • See examples/demo-dashboard/ for a complete working example
  • Review ARCHITECTURE.md for system design details
  • Check MANIFEST_SPEC.md for full manifest documentation