131 lines
5.2 KiB
Python
131 lines
5.2 KiB
Python
"""请求摘要:意图判断和 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
|