"""请求摘要:意图判断和 screen agent 共用,只给组件的识别信息和布局,完整配置按需读取 只描述本次请求;会话历史由各使用方另行传入,见 history.py """ from app.resources.component import get_catalog_cache from app.resources.material_fields import identifying_texts from app.schemas.base import JsonObject from app.schemas.data_file import RequestDataFile from app.schemas.input_context import InputContext from app.schemas.screen import Canvas, ScreenNode # 每张表在摘要里最多列出的列名,完整的列用 describe_data 查看 SUMMARY_COLUMNS = 30 def request_summary(context: InputContext) -> JsonObject: """用户输入、澄清记录、编辑上下文、附件、数据文件和大屏摘要""" nodes: list[JsonObject] = [] catalog = get_catalog_cache() for node in context.screen.nodes: nodes.append( { "id": node.id, "type": node.type, "name": node.name, # 画面上的名字或内容帮助判断用户指的是哪个组件;取哪个字段由字段定义的 identifies 决定, # 新物料不用在这里加判断。物料目录没载入时为空 "titles": identifying_texts(catalog, node.model_dump(mode="json")), "layout": node.layout.model_dump(mode="json", exclude_unset=True), **interaction_summary(node), } ) return { "prompt": context.prompt, "clarification_history": context.clarification_history, "context": context.context.model_dump(mode="json", exclude_unset=True), "screen_summary": { "canvas": canvas_summary(context.screen.canvas), "nodes": nodes, # 数据源只保留标识、名称和类型 "data_sources": [ {key: source[key] for key in ("id", "name", "type") if key in source} for source in context.screen.dataSource ], }, # 数据文件的附件由 data_files 的 attached_this_turn 表示 "attachments": [ {key: item[key] for key in ("id", "kind", "name") if key in item} for item in context.attachments if item.get("kind") != "data_file" ], "data_files": [data_file_summary(item) for item in context.data_files], } def canvas_summary(canvas: Canvas) -> JsonObject: """画布尺寸、主题和大屏变量;没有变量时不出现,变量的默认值为 null 也照样给出""" result = canvas.model_dump( mode="json", include={"width", "height", "theme", "backgroundColor"}, exclude_none=True, ) if canvas.variables: result["variables"] = [ item.model_dump(mode="json") for item in canvas.variables ] return result def interaction_summary(node: ScreenNode) -> JsonObject: """组件的显示条件、数据筛选和写变量的事件;事件代码不给,没有时不出现""" result: JsonObject = {} if node.visibleWhen is not None: result["visibleWhen"] = node.visibleWhen.model_dump(mode="json") if node.filters: result["filters"] = [item.model_dump(mode="json") for item in node.filters] if events := [ {"type": event.get("type"), "action": event["action"]} for event in node.events or [] if "action" in event ]: result["events"] = events return result def data_file_summary(item: RequestDataFile) -> JsonObject: """每个文件只给表名、label、行数和列名;列概况由 describe_data 按需查看。问答节点也用它 上传分析完成时多给一句说明和列的含义(summary、column_meanings),没有分析结果时不出现 """ insights = item.insights meanings: dict[tuple[str, str], str] = {} if insights is not None: for column in insights.columns: # 含义和列名一样没有信息量;有单位的写在后面 if column.label != column.name or column.unit: meanings[(column.table, column.name)] = ( f"{column.label}({column.unit})" if column.unit else column.label ) tables: list[JsonObject] = [] for table in item.tables: shown = table.columns[:SUMMARY_COLUMNS] summary: JsonObject = { "table": table.table, "label": table.label, "rows": table.rows, "columns": [column.name for column in shown], } if len(table.columns) > SUMMARY_COLUMNS: summary["column_count"] = len(table.columns) column_meanings = { column.name: meanings[(table.table, column.name)] for column in shown if (table.table, column.name) in meanings } if column_meanings: summary["column_meanings"] = column_meanings tables.append(summary) result: JsonObject = { "file_id": item.file_id, "name": item.name, "attached_this_turn": item.attached_this_turn, "tables": tables, } if insights is not None and insights.summary: result["summary"] = insights.summary return result