library(shinyjs) library(shinyAce) ## ===== 统一入口===== output$quickgen_chat <- renderUI({ tagList( useShinyjs(), stat_tab_panel( menu = i18n$t("One-click generation > AI chat guidance"), tool = i18n$t("AI chat guidance"), tool_ui = "chat_main_ui", output_panels = tabPanel( title = i18n$t("Chat history"), value = "chat_panel", uiOutput("chat_history_area") ) ) ) }) ## ===== 左侧区域===== output$chat_main_ui <- renderUI({ tagList( useShinyjs(), wellPanel( div(style = "font-weight:bold; color:#1976d2; margin-bottom:10px;", icon("database"), " ", i18n$t("Dataset Fields Information") ), uiOutput("field_info_display"), tags$hr(), div(style = "color:#666; font-size:0.9em; margin-top:5px;", i18n$t("The current dataset's field information is automatically passed to the AI assistant.") ), style = "max-height:450px; overflow-y:auto; background-color:#f8f9fa;" ), help_and_report( modal_title = i18n$t("AI chat guidance"), fun_name = "quickgen_chat", help_file = inclMD(file.path(getOption("radiant.path.quickgen"), "app/tools/help/quickgen_chat.md")), lic = "by-sa" ) ) }) ## ===== 右侧区域===== output$chat_history_area <- renderUI({ field_info_encoded <- get_field_info() if (is.null(field_info_encoded)) { return(create_no_data_ui()) } dify_base_url <- "http://180.169.131.147:8078/chat/tfjTZpJDgjQpBeTl" dify_url <- paste0( dify_base_url, "?showSidebar=true", "&field_info=", field_info_encoded ) tagList( div( id = "chat_box", style = "height:700px; overflow-y:auto; border:1px solid #ddd; border-radius:4px; padding:0; background:#fff; margin-bottom:10px;", tags$iframe( src = dify_url, style = "width: 100%; height: 100%; border: 0;", frameborder = 0, allow = "microphone" ) ) ) }) # 生成左侧展示的格式化字段文本 output$field_info_display <- renderUI({ if (is.null(input$dataset) || !exists("r_data")) { return(tags$pre( i18n$t("Please select a dataset in another page first"), style = "margin:0; background-color:#f9f9f9; border:1px solid #ddd; padding:10px; font-size:0.9em;" )) } df <- tryCatch({ get(input$dataset, envir = r_data) }, error = function(e) NULL) if (is.null(df) || !is.data.frame(df) || nrow(df) == 0) { return(tags$pre( i18n$t("Current dataset is empty"), style = "margin:0; background-color:#f9f9f9; border:1px solid #ddd; padding:10px; font-size:0.9em;" )) } # 生成带换行的格式 field_lines <- sprintf('"%s": "%s"', names(df), sapply(df, function(x) class(x)[1])) formatted_text <- paste(field_lines, collapse = ",\n") tags$pre( formatted_text, style = "margin:0; background-color:#f9f9f9; border:1px solid #ddd; padding:10px; font-size:0.9em; line-height:1.5; white-space:pre-wrap;" ) }) # 获取并编码字段信息 get_field_info <- function() { # 1. 校验数据集是否存在 if (is.null(input$dataset) || !exists("r_data")) { return(NULL) } # 2. 尝试获取数据集 df <- tryCatch({ get(input$dataset, envir = r_data) }, error = function(e) NULL) # 3. 数据集为空则返回NULL if (is.null(df) || !is.data.frame(df) || nrow(df) == 0) { return(NULL) } # 4. 构建字段名-类型映射 fields_list <- list() for (col_name in names(df)) { fields_list[[col_name]] <- class(df[[col_name]])[1] } # 5. 构建JSON结构 json_struct <- list( dataset_name = input$dataset, fields = fields_list ) # 6. JSON序列化+URL编码 URLencode( jsonlite::toJSON(json_struct, auto_unbox = TRUE), reserved = TRUE ) } # 无数据时的UI create_no_data_ui <- function() { tagList( div( id = "chat_box", style = "height:700px; overflow-y:auto; border:1px solid #ddd; border-radius:4px; padding:20px; background:#fff; margin-bottom:10px;", p(i18n$t("请选择数据集"), style = "text-align:center; margin-top:50px; color:#888;") ) ) }