Files
AIclinicalresearch/r-statistics-service/utils/block_helpers.R
HaHafeng 3446909ff7 feat(ssa): Complete Phase I-IV intelligent dialogue and tool system development
Phase I - Session Blackboard + READ Layer:
- SessionBlackboardService with Postgres-Only cache
- DataProfileService for data overview generation
- PicoInferenceService for LLM-driven PICO extraction
- Frontend DataContextCard and VariableDictionaryPanel
- E2E tests: 31/31 passed

Phase II - Conversation Layer LLM + Intent Router:
- ConversationService with SSE streaming
- IntentRouterService (rule-first + LLM fallback, 6 intents)
- SystemPromptService with 6-segment dynamic assembly
- TokenTruncationService for context management
- ChatHandlerService as unified chat entry
- Frontend SSAChatPane and useSSAChat hook
- E2E tests: 38/38 passed

Phase III - Method Consultation + AskUser Standardization:
- ToolRegistryService with Repository Pattern
- MethodConsultService with DecisionTable + LLM enhancement
- AskUserService with global interrupt handling
- Frontend AskUserCard component
- E2E tests: 13/13 passed

Phase IV - Dialogue-Driven Analysis + QPER Integration:
- ToolOrchestratorService (plan/execute/report)
- analysis_plan SSE event for WorkflowPlan transmission
- Dual-channel confirmation (ask_user card + workspace button)
- PICO as optional hint for LLM parsing
- E2E tests: 25/25 passed

R Statistics Service:
- 5 new R tools: anova_one, baseline_table, fisher, linear_reg, wilcoxon
- Enhanced guardrails and block helpers
- Comprehensive test suite (run_all_tools_test.js)

Documentation:
- Updated system status document (v5.9)
- Updated SSA module status and development plan (v1.8)

Total E2E: 107/107 passed (Phase I: 31, Phase II: 38, Phase III: 13, Phase IV: 25)

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-22 18:53:39 +08:00

87 lines
2.8 KiB
R
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# utils/block_helpers.R
# Block-based 输出协议 — 构造函数
#
# 所有 R 工具通过这些函数构建 report_blocks[]
# 前端 DynamicReport.tsx 根据 block.type 统一渲染。
# 支持 4 种 Block 类型markdown / table / image / key_value
#' 构造 Markdown 文本块
#' @param content Markdown 格式文本(支持标题、列表、加粗等)
#' @param title 可选标题(前端渲染为区块标题)
#' @return block list
make_markdown_block <- function(content, title = NULL) {
block <- list(type = "markdown", content = content)
if (!is.null(title)) block$title <- title
block
}
#' 构造表格块
#' @param headers 列名字符向量,如 c("组别", "均值", "标准差")
#' @param rows 行数据列表,每行为字符向量,如 list(c("A", "5.2", "1.3"), ...)
#' @param title 可选表格标题
#' @param footnote 可选脚注(如方法说明)
#' @return block list
make_table_block <- function(headers, rows, title = NULL, footnote = NULL, metadata = NULL) {
block <- list(
type = "table",
headers = as.list(headers),
rows = lapply(rows, as.list)
)
if (!is.null(title)) block$title <- title
if (!is.null(footnote)) block$footnote <- footnote
if (!is.null(metadata)) block$metadata <- metadata
block
}
#' 从 data.frame 构造表格块(便捷方法)
#' @param df data.frame
#' @param title 可选表格标题
#' @param footnote 可选脚注
#' @param digits 数值列保留小数位数,默认 3
#' @return block list
make_table_block_from_df <- function(df, title = NULL, footnote = NULL, digits = 3) {
headers <- colnames(df)
rows <- lapply(seq_len(nrow(df)), function(i) {
lapply(df[i, , drop = FALSE], function(val) {
if (is.numeric(val)) {
format(round(val, digits), nsmall = digits)
} else {
as.character(val)
}
})
})
make_table_block(headers, rows, title = title, footnote = footnote)
}
#' 构造图片块
#' @param base64_data 完整的 data URI如 "data:image/png;base64,..."
#' @param title 可选图片标题
#' @param alt 可选 alt 文本(无障碍 + Word 导出用)
#' @return block list
make_image_block <- function(base64_data, title = NULL, alt = NULL) {
block <- list(type = "image", data = base64_data)
if (!is.null(title)) block$title <- title
if (!is.null(alt)) block$alt <- alt
block
}
#' 构造键值对块
#' @param items 命名列表或 list(list(key=..., value=...), ...)
#' @param title 可选标题
#' @return block list
make_kv_block <- function(items, title = NULL) {
if (!is.null(names(items)) && length(names(items)) > 0 && names(items)[1] != "") {
kv_list <- lapply(names(items), function(k) {
list(key = k, value = as.character(items[[k]]))
})
} else {
kv_list <- items
}
block <- list(type = "key_value", items = kv_list)
if (!is.null(title)) block$title <- title
block
}