| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956 |
- #!/usr/bin/env python3
- """
- Tab5内容生成器 - 实质与形式的双向支撑关系图
- 展示:选题点(来自实质) ← 实质点 → 形式点 → 选题点(来自形式)
- """
- import html as html_module
- import json
- from typing import Dict, Any, List
- def get_intent_support_data(element: Dict[str, Any]) -> Dict[str, Any]:
- """
- 获取元素的意图支撑数据(兼容新旧数据结构)
-
- 优先使用"意图支撑"字段,如果没有则使用"多维度评分"字段
- 这两个字段内部存储的都是意图支撑数据
-
- Args:
- element: 元素数据
-
- Returns:
- 意图支撑数据字典,格式:{"灵感点": [...], "目的点": [...], "关键点": [...]}
- """
- # 优先使用"意图支撑"字段
- intent_support = element.get('意图支撑')
- if intent_support and isinstance(intent_support, dict):
- return intent_support
-
- # 如果没有"意图支撑",则使用"多维度评分"字段(兼容旧数据)
- multi_scores = element.get('多维度评分')
- if multi_scores and isinstance(multi_scores, dict):
- return multi_scores
-
- # 都没有则返回空字典
- return {}
- def generate_tab5_content(data: Dict[str, Any]) -> str:
- """生成Tab5内容:实质与形式的双向支撑关系图(4列布局)"""
- html = '<div class="tab-content" id="tab5">\n'
- # 提取数据
- script_data = data.get('脚本理解', {})
- form_list = script_data.get('形式列表', [])
- substance_list = script_data.get('实质列表', [])
-
- # 处理灵感点:可能是列表,也可能在对象中
- inspiration_data = data.get('灵感点', [])
- if isinstance(inspiration_data, list):
- inspiration_points = inspiration_data
- elif isinstance(inspiration_data, dict):
- inspiration_points = inspiration_data.get('inspiration_points', [])
- else:
- inspiration_points = []
-
- # 处理目的点:可能是列表,也可能在对象的purposes字段中
- purpose_data = data.get('目的点', [])
- if isinstance(purpose_data, list):
- purpose_points = purpose_data
- elif isinstance(purpose_data, dict):
- purpose_points = purpose_data.get('purposes', [])
- else:
- purpose_points = []
-
- # 处理关键点:可能是列表,也可能在对象的key_points字段中
- keypoint_data = data.get('关键点', [])
- if isinstance(keypoint_data, list):
- key_points = keypoint_data
- elif isinstance(keypoint_data, dict):
- key_points = keypoint_data.get('key_points', [])
- else:
- key_points = []
- if not substance_list and not form_list:
- html += '<div class="empty-state">暂无实质点和形式点数据</div>\n'
- html += '</div>\n'
- return html
- # 分类实质点
- concrete_elements = []
- concrete_concepts = []
- implicit_concepts = []
- abstract_concepts = []
- for substance in substance_list:
- dimension_2 = substance.get('维度', {}).get('二级', '')
- elem_type = substance.get('类型', '')
-
- # 隐含概念:优先通过类型判断(因为维度二级可能是"隐含概念"或"抽象概念")
- if elem_type == '隐含概念':
- implicit_concepts.append(substance)
- elif dimension_2 == '具体元素':
- concrete_elements.append(substance)
- elif dimension_2 == '具象概念': # 修改:从"具体概念"改为"具象概念"
- concrete_concepts.append(substance)
- elif dimension_2 == '抽象概念':
- abstract_concepts.append(substance)
- # 分类形式点
- concrete_element_forms = []
- concrete_concept_forms = []
- overall_forms = []
- for form in form_list:
- dimension_2 = form.get('维度', {}).get('二级', '')
- if dimension_2 == '具体元素形式':
- concrete_element_forms.append(form)
- elif dimension_2 == '具象概念形式': # 修改:从"具体概念形式"改为"具象概念形式"
- concrete_concept_forms.append(form)
- elif dimension_2 == '整体形式':
- overall_forms.append(form)
- # 构建关系数据
- relationships = build_bidirectional_relationships(
- concrete_elements, concrete_concepts, implicit_concepts, abstract_concepts,
- concrete_element_forms, concrete_concept_forms, overall_forms,
- inspiration_points, purpose_points, key_points
- )
- # 添加标题和说明
- html += '<div class="tab5-header">\n'
- html += '<h2 class="tab5-title">实质与形式的双向支撑关系图</h2>\n'
- html += '<div class="tab5-description">\n'
- html += '<p>4列展示:<strong>选题点(实质支撑)</strong> ← <strong>实质点</strong> | <strong>形式点</strong> → <strong>选题点(形式支撑)</strong></p>\n'
- html += '<ul class="relationship-rules">\n'
- html += '<li>左侧选题点:显示实质点对灵感点、关键点、目的点的支撑关系</li>\n'
- html += '<li>右侧选题点:显示形式点对灵感点、关键点、目的点的支撑关系</li>\n'
- html += '</ul>\n'
- html += '</div>\n'
- html += '</div>\n'
- # SVG 连线容器(放在4列布局之前,作为背景层)
- html += '<div class="tab5-svg-container">\n'
- html += '<svg id="tab5-connection-svg" width="100%" height="100%">\n'
- html += '<!-- 连线将在这里绘制 -->\n'
- html += '</svg>\n'
- html += '</div>\n'
- # 主要内容区域(4列布局)
- html += '<div class="tab5-four-column-container">\n'
- # 第1列:左侧选题点(来自实质点的支撑关系)
- html += '<div class="tab5-column tab5-left-targets">\n'
- html += '<h3 class="panel-title">选题点<br/><span style="font-size:0.8em;font-weight:normal;color:#6c757d;">(实质支撑)</span></h3>\n'
- # 灵感点(左)
- if inspiration_points:
- html += '<div class="target-group">\n'
- html += '<h4 class="group-title">灵感点</h4>\n'
- html += '<div class="target-items">\n'
- for idx, point in enumerate(inspiration_points, 1):
- # 确保 point 是字典
- if not isinstance(point, dict):
- continue
- # 使用提取的特征中的特征名称,每个特征名称一个卡片
- features = point.get('提取的特征', [])
- feature_names = [f.get('特征名称', '') for f in features if f.get('特征名称')]
- if feature_names:
- # 为每个特征名称创建一个独立ID的卡片
- for feature_idx, feature_name in enumerate(feature_names, 1):
- feature_id = f'inspiration-{idx}-{feature_idx}'
- html += f'<div class="target-card inspiration-card" data-type="inspiration-substance" data-id="{feature_id}" onclick="selectLeftTarget(' + f"'inspiration', '{idx}-{feature_idx}'" + ')">\n'
- html += f'<div class="card-number">#{idx}-{feature_idx}</div>\n'
- html += f'<div class="card-text">{html_module.escape(feature_name)}</div>\n'
- html += '</div>\n'
- else:
- # 如果没有特征,使用原始的灵感点文本
- display_text = point.get('灵感点', '')
- html += f'<div class="target-card inspiration-card" data-type="inspiration-substance" data-id="inspiration-{idx}" onclick="selectLeftTarget(' + f"'inspiration', {idx}" + ')">\n'
- html += f'<div class="card-number">#{idx}</div>\n'
- html += f'<div class="card-text">{html_module.escape(display_text)}</div>\n'
- html += '</div>\n'
- html += '</div>\n'
- html += '</div>\n'
- # 关键点(左)
- if key_points:
- html += '<div class="target-group">\n'
- html += '<h4 class="group-title">关键点</h4>\n'
- html += '<div class="target-items">\n'
- for idx, point in enumerate(key_points, 1):
- # 确保 point 是字典
- if not isinstance(point, dict):
- continue
- # 使用提取的特征中的特征名称,每个特征名称一个卡片
- features = point.get('提取的特征', [])
- feature_names = [f.get('特征名称', '') for f in features if f.get('特征名称')]
- if feature_names:
- # 为每个特征名称创建一个独立ID的卡片
- for feature_idx, feature_name in enumerate(feature_names, 1):
- feature_id = f'keypoint-{idx}-{feature_idx}'
- html += f'<div class="target-card keypoint-card" data-type="keypoint-substance" data-id="{feature_id}" onclick="selectLeftTarget(' + f"'keypoint', '{idx}-{feature_idx}'" + ')">\n'
- html += f'<div class="card-number">#{idx}-{feature_idx}</div>\n'
- html += f'<div class="card-text">{html_module.escape(feature_name)}</div>\n'
- html += '</div>\n'
- else:
- # 如果没有特征,使用原始的关键点文本
- display_text = point.get('关键点', '')
- html += f'<div class="target-card keypoint-card" data-type="keypoint-substance" data-id="keypoint-{idx}" onclick="selectLeftTarget(' + f"'keypoint', {idx}" + ')">\n'
- html += f'<div class="card-number">#{idx}</div>\n'
- html += f'<div class="card-text">{html_module.escape(display_text)}</div>\n'
- html += '</div>\n'
- html += '</div>\n'
- html += '</div>\n'
- # 目的点(左)
- if purpose_points:
- html += '<div class="target-group">\n'
- html += '<h4 class="group-title">目的点</h4>\n'
- html += '<div class="target-items">\n'
- for idx, point in enumerate(purpose_points, 1):
- # 确保 point 是字典
- if not isinstance(point, dict):
- continue
- # 使用提取的特征中的特征名称,每个特征名称一个卡片
- features = point.get('提取的特征', [])
- feature_names = [f.get('特征名称', '') for f in features if f.get('特征名称')]
- if feature_names:
- # 为每个特征名称创建一个独立ID的卡片
- for feature_idx, feature_name in enumerate(feature_names, 1):
- feature_id = f'purpose-{idx}-{feature_idx}'
- html += f'<div class="target-card purpose-card" data-type="purpose-substance" data-id="{feature_id}" onclick="selectLeftTarget(' + f"'purpose', '{idx}-{feature_idx}'" + ')">\n'
- html += f'<div class="card-number">#{idx}-{feature_idx}</div>\n'
- html += f'<div class="card-text">{html_module.escape(feature_name)}</div>\n'
- html += '</div>\n'
- else:
- # 如果没有特征,使用原始的目的点文本
- display_text = point.get('目的点', '')
- html += f'<div class="target-card purpose-card" data-type="purpose-substance" data-id="purpose-{idx}" onclick="selectLeftTarget(' + f"'purpose', {idx}" + ')">\n'
- html += f'<div class="card-number">#{idx}</div>\n'
- html += f'<div class="card-text">{html_module.escape(display_text)}</div>\n'
- html += '</div>\n'
- html += '</div>\n'
- html += '</div>\n'
- html += '</div>\n'
- # 第2列:实质点
- html += '<div class="tab5-column tab5-substances">\n'
- html += '<h3 class="panel-title">实质点</h3>\n'
- # 具体元素
- if concrete_elements:
- html += '<div class="substance-group">\n'
- html += '<h4 class="group-title">具体元素</h4>\n'
- html += '<div class="substance-items">\n'
- for substance in concrete_elements:
- html += render_substance_card(substance, 'concrete-element')
- html += '</div>\n'
- html += '</div>\n'
- # 具象概念
- if concrete_concepts:
- html += '<div class="substance-group">\n'
- html += '<h4 class="group-title">具象概念</h4>\n'
- html += '<div class="substance-items">\n'
- for substance in concrete_concepts:
- html += render_substance_card(substance, 'concrete-concept')
- html += '</div>\n'
- html += '</div>\n'
- # 隐含概念
- if implicit_concepts:
- html += '<div class="substance-group">\n'
- html += '<h4 class="group-title">隐含概念</h4>\n'
- html += '<div class="substance-items">\n'
- for substance in implicit_concepts:
- html += render_substance_card(substance, 'implicit-concept')
- html += '</div>\n'
- html += '</div>\n'
- # 抽象概念
- if abstract_concepts:
- html += '<div class="substance-group">\n'
- html += '<h4 class="group-title">抽象概念</h4>\n'
- html += '<div class="substance-items">\n'
- for substance in abstract_concepts:
- html += render_substance_card(substance, 'abstract-concept')
- html += '</div>\n'
- html += '</div>\n'
- html += '</div>\n'
- # 第3列:形式点
- html += '<div class="tab5-column tab5-forms">\n'
- html += '<h3 class="panel-title">形式点</h3>\n'
- # 具体元素形式
- if concrete_element_forms:
- html += '<div class="form-group">\n'
- html += '<h4 class="group-title">具体元素形式</h4>\n'
- html += '<div class="form-items">\n'
- for form in concrete_element_forms:
- html += render_form_card(form, 'concrete-element-form')
- html += '</div>\n'
- html += '</div>\n'
- # 具象概念形式
- if concrete_concept_forms:
- html += '<div class="form-group">\n'
- html += '<h4 class="group-title">具象概念形式</h4>\n'
- html += '<div class="form-items">\n'
- for form in concrete_concept_forms:
- html += render_form_card(form, 'concrete-concept-form')
- html += '</div>\n'
- html += '</div>\n'
- # 整体形式
- if overall_forms:
- html += '<div class="form-group">\n'
- html += '<h4 class="group-title">整体形式</h4>\n'
- html += '<div class="form-items">\n'
- for form in overall_forms:
- html += render_form_card(form, 'overall-form')
- html += '</div>\n'
- html += '</div>\n'
- html += '</div>\n'
- # 第4列:右侧选题点(来自形式点的支撑关系)
- html += '<div class="tab5-column tab5-right-targets">\n'
- html += '<h3 class="panel-title">选题点<br/><span style="font-size:0.8em;font-weight:normal;color:#6c757d;">(形式支撑)</span></h3>\n'
- # 灵感点(右)
- if inspiration_points:
- html += '<div class="target-group">\n'
- html += '<h4 class="group-title">灵感点</h4>\n'
- html += '<div class="target-items">\n'
- for idx, point in enumerate(inspiration_points, 1):
- # 确保 point 是字典
- if not isinstance(point, dict):
- continue
- # 使用提取的特征中的特征名称,每个特征名称一个卡片
- features = point.get('提取的特征', [])
- feature_names = [f.get('特征名称', '') for f in features if f.get('特征名称')]
- if feature_names:
- # 为每个特征名称创建一个独立ID的卡片
- for feature_idx, feature_name in enumerate(feature_names, 1):
- feature_id = f'inspiration-{idx}-{feature_idx}'
- html += f'<div class="target-card inspiration-card" data-type="inspiration-form" data-id="{feature_id}" onclick="selectRightTarget(' + f"'inspiration', '{idx}-{feature_idx}'" + ')">\n'
- html += f'<div class="card-number">#{idx}-{feature_idx}</div>\n'
- html += f'<div class="card-text">{html_module.escape(feature_name)}</div>\n'
- html += '</div>\n'
- else:
- # 如果没有特征,使用原始的灵感点文本
- display_text = point.get('灵感点', '')
- html += f'<div class="target-card inspiration-card" data-type="inspiration-form" data-id="inspiration-{idx}" onclick="selectRightTarget(' + f"'inspiration', {idx}" + ')">\n'
- html += f'<div class="card-number">#{idx}</div>\n'
- html += f'<div class="card-text">{html_module.escape(display_text)}</div>\n'
- html += '</div>\n'
- html += '</div>\n'
- html += '</div>\n'
- # 关键点(右)
- if key_points:
- html += '<div class="target-group">\n'
- html += '<h4 class="group-title">关键点</h4>\n'
- html += '<div class="target-items">\n'
- for idx, point in enumerate(key_points, 1):
- # 确保 point 是字典
- if not isinstance(point, dict):
- continue
- # 使用提取的特征中的特征名称,每个特征名称一个卡片
- features = point.get('提取的特征', [])
- feature_names = [f.get('特征名称', '') for f in features if f.get('特征名称')]
- if feature_names:
- # 为每个特征名称创建一个独立ID的卡片
- for feature_idx, feature_name in enumerate(feature_names, 1):
- feature_id = f'keypoint-{idx}-{feature_idx}'
- html += f'<div class="target-card keypoint-card" data-type="keypoint-form" data-id="{feature_id}" onclick="selectRightTarget(' + f"'keypoint', '{idx}-{feature_idx}'" + ')">\n'
- html += f'<div class="card-number">#{idx}-{feature_idx}</div>\n'
- html += f'<div class="card-text">{html_module.escape(feature_name)}</div>\n'
- html += '</div>\n'
- else:
- # 如果没有特征,使用原始的关键点文本
- display_text = point.get('关键点', '')
- html += f'<div class="target-card keypoint-card" data-type="keypoint-form" data-id="keypoint-{idx}" onclick="selectRightTarget(' + f"'keypoint', {idx}" + ')">\n'
- html += f'<div class="card-number">#{idx}</div>\n'
- html += f'<div class="card-text">{html_module.escape(display_text)}</div>\n'
- html += '</div>\n'
- html += '</div>\n'
- html += '</div>\n'
- # 目的点(右)
- if purpose_points:
- html += '<div class="target-group">\n'
- html += '<h4 class="group-title">目的点</h4>\n'
- html += '<div class="target-items">\n'
- for idx, point in enumerate(purpose_points, 1):
- # 确保 point 是字典
- if not isinstance(point, dict):
- continue
- # 使用提取的特征中的特征名称,每个特征名称一个卡片
- features = point.get('提取的特征', [])
- feature_names = [f.get('特征名称', '') for f in features if f.get('特征名称')]
- if feature_names:
- # 为每个特征名称创建一个独立ID的卡片
- for feature_idx, feature_name in enumerate(feature_names, 1):
- feature_id = f'purpose-{idx}-{feature_idx}'
- html += f'<div class="target-card purpose-card" data-type="purpose-form" data-id="{feature_id}" onclick="selectRightTarget(' + f"'purpose', '{idx}-{feature_idx}'" + ')">\n'
- html += f'<div class="card-number">#{idx}-{feature_idx}</div>\n'
- html += f'<div class="card-text">{html_module.escape(feature_name)}</div>\n'
- html += '</div>\n'
- else:
- # 如果没有特征,使用原始的目的点文本
- display_text = point.get('目的点', '')
- html += f'<div class="target-card purpose-card" data-type="purpose-form" data-id="purpose-{idx}" onclick="selectRightTarget(' + f"'purpose', {idx}" + ')">\n'
- html += f'<div class="card-number">#{idx}</div>\n'
- html += f'<div class="card-text">{html_module.escape(display_text)}</div>\n'
- html += '</div>\n'
- html += '</div>\n'
- html += '</div>\n'
- html += '</div>\n'
- html += '</div>\n'
- # 嵌入关系数据
- html += '<script>\n'
- html += f'const tab5Relationships = {json.dumps(relationships, ensure_ascii=False)};\n'
- html += '</script>\n'
- html += '</div>\n'
- return html
- def render_substance_card(substance: Dict[str, Any], css_class: str) -> str:
- """渲染实质点卡片"""
- substance_id = substance.get('id', '')
- substance_name = substance.get('名称', '')
- description = substance.get('描述', '')
- html = f'<div class="substance-card {css_class}" data-id="{html_module.escape(substance_id)}" onclick="selectSubstance(' + f"'{substance_id}'" + ')">\n'
- html += f'<div class="card-header">\n'
- html += f'<div class="card-id">#{html_module.escape(substance_id)}</div>\n'
- html += f'<div class="card-name">{html_module.escape(substance_name)}</div>\n'
- html += '</div>\n'
- if description:
- html += f'<div class="card-description">{html_module.escape(description[:50])}{"..." if len(description) > 50 else ""}</div>\n'
- html += '</div>\n'
- return html
- def render_form_card(form: Dict[str, Any], css_class: str) -> str:
- """渲染形式点卡片"""
- form_id = form.get('id', '')
- form_name = form.get('名称', '')
- description = form.get('描述', '')
- weight_score = form.get('权重分')
- html = f'<div class="form-card {css_class}" data-id="{html_module.escape(form_id)}" onclick="selectForm(' + f"'{form_id}'" + ')">\n'
- html += f'<div class="card-header">\n'
- html += f'<div class="card-id">#{html_module.escape(form_id)}</div>\n'
- html += f'<div class="card-name">{html_module.escape(form_name)}</div>\n'
- if weight_score is not None:
- html += f'<div class="card-weight" style="font-size: 11px; color: #666; margin-top: 2px;">权重分: {weight_score:.1f}</div>\n'
- html += '</div>\n'
- if description:
- html += f'<div class="card-description">{html_module.escape(description[:50])}{"..." if len(description) > 50 else ""}</div>\n'
- html += '</div>\n'
- return html
- def build_bidirectional_relationships(
- concrete_elements: List[Dict],
- concrete_concepts: List[Dict],
- implicit_concepts: List[Dict],
- abstract_concepts: List[Dict],
- concrete_element_forms: List[Dict],
- concrete_concept_forms: List[Dict],
- overall_forms: List[Dict],
- inspiration_points: List[Dict],
- purpose_points: List[Dict],
- key_points: List[Dict]
- ) -> Dict[str, Any]:
- """
- 构建双向支撑关系数据
- 返回结构:
- {
- "substance_to_target": {
- "substance_id": {
- "inspiration": [{target_id, score, ...}],
- "purpose": [...],
- "keypoint": [...]
- }
- },
- "form_to_target": {
- "form_id": {
- "inspiration": [{target_id, score, ...}],
- "purpose": [...],
- "keypoint": [...]
- }
- },
- "target_from_substance": {
- "inspiration-1": [substance_ids with scores],
- "keypoint-1": [...],
- "purpose-1": [...]
- },
- "target_from_form": {
- "inspiration-1": [form_ids with scores],
- ...
- },
- "form_to_substance": {
- "form_id": [substance_ids],
- ...
- },
- "substance_from_form": {
- "substance_id": [form_ids],
- ...
- }
- }
- """
- relationships = {
- "substance_to_target": {},
- "form_to_target": {},
- "target_from_substance": {},
- "target_from_form": {},
- "form_to_substance": {}, # 新增:形式点→实质点
- "substance_from_form": {} # 新增:实质点←形式点(反向)
- }
- # 合并所有实质点和形式点
- all_substances = concrete_elements + concrete_concepts + implicit_concepts + abstract_concepts
- all_forms = concrete_element_forms + concrete_concept_forms + overall_forms
- # 注意:优先使用"意图支撑"字段,如果没有则使用"多维度评分"字段(兼容旧数据)
- # 这两个字段内部存储的都是意图支撑数据,每个项目就是一个支撑点
- # 不再需要阈值过滤,所有支撑点都会显示连线
- # 1. 构建实质点到选题点的关系(基于意图支撑数据)
- for substance in all_substances:
- substance_id = substance.get('id', '')
- if not substance_id:
- continue
- dimension_2 = substance.get('维度', {}).get('二级', '')
- intention_support = get_intent_support_data(substance)
- relationships["substance_to_target"][substance_id] = {
- "name": substance.get('名称', ''),
- "type": dimension_2,
- "inspiration": [],
- "purpose": [],
- "keypoint": []
- }
- # 处理灵感点(意图支撑)
- for support_item in intention_support.get('灵感点', []):
- point_name = support_item.get('点')
- if not point_name:
- continue
- # 在灵感点列表中查找匹配的点,以便复用Tab1中的卡片id/特征结构
- idx = next(
- (i for i, p in enumerate(inspiration_points, 1)
- if isinstance(p, dict) and p.get('灵感点') == point_name),
- None
- )
- if idx is None:
- continue
- point = inspiration_points[idx - 1]
- features = point.get('提取的特征', [])
- feature_names = [f.get('特征名称', '') for f in features if f.get('特征名称')]
- if feature_names:
- # 为每个特征创建独立的关系
- for feature_idx in range(1, len(feature_names) + 1):
- target_id = f'inspiration-{idx}-{feature_idx}'
- relationships["substance_to_target"][substance_id]["inspiration"].append({
- "target_id": target_id,
- "point": point_name,
- "support_reason": support_item.get('支撑理由', '')
- })
- # 反向关系
- if target_id not in relationships["target_from_substance"]:
- relationships["target_from_substance"][target_id] = []
- relationships["target_from_substance"][target_id].append({
- "substance_id": substance_id,
- "name": substance.get('名称', ''),
- "type": dimension_2,
- "support_reason": support_item.get('支撑理由', '')
- })
- else:
- # 没有特征,使用主索引
- target_id = f'inspiration-{idx}'
- relationships["substance_to_target"][substance_id]["inspiration"].append({
- "target_id": target_id,
- "point": point_name,
- "support_reason": support_item.get('支撑理由', '')
- })
- # 反向关系
- if target_id not in relationships["target_from_substance"]:
- relationships["target_from_substance"][target_id] = []
- relationships["target_from_substance"][target_id].append({
- "substance_id": substance_id,
- "name": substance.get('名称', ''),
- "type": dimension_2,
- "support_reason": support_item.get('支撑理由', '')
- })
- # 处理目的点(意图支撑)
- for support_item in intention_support.get('目的点', []):
- point_name = support_item.get('点')
- if not point_name:
- continue
- idx = next(
- (i for i, p in enumerate(purpose_points, 1)
- if isinstance(p, dict) and p.get('目的点') == point_name),
- None
- )
- if idx is None:
- continue
- point = purpose_points[idx - 1]
- features = point.get('提取的特征', [])
- feature_names = [f.get('特征名称', '') for f in features if f.get('特征名称')]
- if feature_names:
- for feature_idx in range(1, len(feature_names) + 1):
- target_id = f'purpose-{idx}-{feature_idx}'
- relationships["substance_to_target"][substance_id]["purpose"].append({
- "target_id": target_id,
- "point": point_name,
- "support_reason": support_item.get('支撑理由', '')
- })
- if target_id not in relationships["target_from_substance"]:
- relationships["target_from_substance"][target_id] = []
- relationships["target_from_substance"][target_id].append({
- "substance_id": substance_id,
- "name": substance.get('名称', ''),
- "type": dimension_2,
- "support_reason": support_item.get('支撑理由', '')
- })
- else:
- target_id = f'purpose-{idx}'
- relationships["substance_to_target"][substance_id]["purpose"].append({
- "target_id": target_id,
- "point": point_name,
- "support_reason": support_item.get('支撑理由', '')
- })
- if target_id not in relationships["target_from_substance"]:
- relationships["target_from_substance"][target_id] = []
- relationships["target_from_substance"][target_id].append({
- "substance_id": substance_id,
- "name": substance.get('名称', ''),
- "type": dimension_2,
- "support_reason": support_item.get('支撑理由', '')
- })
- # 处理关键点(意图支撑)
- for support_item in intention_support.get('关键点', []):
- point_name = support_item.get('点')
- if not point_name:
- continue
- idx = next(
- (i for i, p in enumerate(key_points, 1)
- if isinstance(p, dict) and p.get('关键点') == point_name),
- None
- )
- if idx is None:
- continue
- point = key_points[idx - 1]
- features = point.get('提取的特征', [])
- feature_names = [f.get('特征名称', '') for f in features if f.get('特征名称')]
- if feature_names:
- for feature_idx in range(1, len(feature_names) + 1):
- target_id = f'keypoint-{idx}-{feature_idx}'
- relationships["substance_to_target"][substance_id]["keypoint"].append({
- "target_id": target_id,
- "point": point_name,
- "support_reason": support_item.get('支撑理由', '')
- })
- if target_id not in relationships["target_from_substance"]:
- relationships["target_from_substance"][target_id] = []
- relationships["target_from_substance"][target_id].append({
- "substance_id": substance_id,
- "name": substance.get('名称', ''),
- "type": dimension_2,
- "support_reason": support_item.get('支撑理由', '')
- })
- else:
- target_id = f'keypoint-{idx}'
- relationships["substance_to_target"][substance_id]["keypoint"].append({
- "target_id": target_id,
- "point": point_name,
- "support_reason": support_item.get('支撑理由', '')
- })
- if target_id not in relationships["target_from_substance"]:
- relationships["target_from_substance"][target_id] = []
- relationships["target_from_substance"][target_id].append({
- "substance_id": substance_id,
- "name": substance.get('名称', ''),
- "type": dimension_2,
- "support_reason": support_item.get('支撑理由', '')
- })
- # 2. 构建形式点到选题点的关系
- for form in all_forms:
- form_id = form.get('id', '')
- if not form_id:
- continue
- dimension_2 = form.get('维度', {}).get('二级', '')
- # 优先使用"意图支撑"字段,如果没有则使用"多维度评分"字段
- intent_support_data = get_intent_support_data(form)
- relationships["form_to_target"][form_id] = {
- "name": form.get('名称', ''),
- "type": dimension_2,
- "inspiration": [],
- "purpose": [],
- "keypoint": []
- }
- # 处理灵感点(每个项目就是一个支撑点)
- if '灵感点' in intent_support_data:
- for support_point in intent_support_data['灵感点']:
- if not isinstance(support_point, dict):
- continue
-
- # 每个项目就是一个支撑点,直接使用
- point_name = support_point.get('点', '')
- if not point_name:
- continue
-
- # 根据点名称找到对应的灵感点索引
- point_idx = None
- for idx, point in enumerate(inspiration_points, 1):
- if point.get('灵感点') == point_name or point.get('名称') == point_name:
- point_idx = idx
- break
-
- if point_idx and point_idx <= len(inspiration_points):
- point = inspiration_points[point_idx - 1]
- features = point.get('提取的特征', [])
- feature_names = [f.get('特征名称', '') for f in features if f.get('特征名称')]
- if feature_names:
- # 为每个特征创建独立的关系
- for feature_idx in range(1, len(feature_names) + 1):
- target_id = f'inspiration-{point_idx}-{feature_idx}'
- relationships["form_to_target"][form_id]["inspiration"].append({
- "target_id": target_id,
- "point": point_name,
- "support_reason": support_point.get('支撑理由', '')
- })
- # 反向关系
- if target_id not in relationships["target_from_form"]:
- relationships["target_from_form"][target_id] = []
- relationships["target_from_form"][target_id].append({
- "form_id": form_id,
- "name": form.get('名称', ''),
- "type": dimension_2,
- "support_reason": support_point.get('支撑理由', '')
- })
- else:
- # 没有特征,使用主索引
- target_id = f'inspiration-{point_idx}'
- relationships["form_to_target"][form_id]["inspiration"].append({
- "target_id": target_id,
- "point": point_name,
- "support_reason": support_point.get('支撑理由', '')
- })
- # 反向关系
- if target_id not in relationships["target_from_form"]:
- relationships["target_from_form"][target_id] = []
- relationships["target_from_form"][target_id].append({
- "form_id": form_id,
- "name": form.get('名称', ''),
- "type": dimension_2,
- "support_reason": support_point.get('支撑理由', '')
- })
- # 处理目的点(每个项目就是一个支撑点)
- if '目的点' in intent_support_data:
- for support_point in intent_support_data['目的点']:
- if not isinstance(support_point, dict):
- continue
-
- # 每个项目就是一个支撑点,直接使用
- point_name = support_point.get('点', '')
- if not point_name:
- continue
-
- # 根据点名称找到对应的目的点索引
- point_idx = None
- for idx, point in enumerate(purpose_points, 1):
- if point.get('目的点') == point_name or point.get('名称') == point_name:
- point_idx = idx
- break
-
- if point_idx and point_idx <= len(purpose_points):
- point = purpose_points[point_idx - 1]
- features = point.get('提取的特征', [])
- feature_names = [f.get('特征名称', '') for f in features if f.get('特征名称')]
- if feature_names:
- for feature_idx in range(1, len(feature_names) + 1):
- target_id = f'purpose-{point_idx}-{feature_idx}'
- relationships["form_to_target"][form_id]["purpose"].append({
- "target_id": target_id,
- "point": point_name,
- "support_reason": support_point.get('支撑理由', '')
- })
- if target_id not in relationships["target_from_form"]:
- relationships["target_from_form"][target_id] = []
- relationships["target_from_form"][target_id].append({
- "form_id": form_id,
- "name": form.get('名称', ''),
- "type": dimension_2,
- "support_reason": support_point.get('支撑理由', '')
- })
- else:
- target_id = f'purpose-{point_idx}'
- relationships["form_to_target"][form_id]["purpose"].append({
- "target_id": target_id,
- "point": point_name,
- "support_reason": support_point.get('支撑理由', '')
- })
- if target_id not in relationships["target_from_form"]:
- relationships["target_from_form"][target_id] = []
- relationships["target_from_form"][target_id].append({
- "form_id": form_id,
- "name": form.get('名称', ''),
- "type": dimension_2,
- "support_reason": support_point.get('支撑理由', '')
- })
- # 处理关键点(每个项目就是一个支撑点)
- if '关键点' in intent_support_data:
- for support_point in intent_support_data['关键点']:
- if not isinstance(support_point, dict):
- continue
-
- # 每个项目就是一个支撑点,直接使用
- point_name = support_point.get('点', '')
- if not point_name:
- continue
-
- # 根据点名称找到对应的关键点索引
- point_idx = None
- for idx, point in enumerate(key_points, 1):
- if point.get('关键点') == point_name or point.get('名称') == point_name:
- point_idx = idx
- break
-
- if point_idx and point_idx <= len(key_points):
- point = key_points[point_idx - 1]
- features = point.get('提取的特征', [])
- feature_names = [f.get('特征名称', '') for f in features if f.get('特征名称')]
- if feature_names:
- for feature_idx in range(1, len(feature_names) + 1):
- target_id = f'keypoint-{point_idx}-{feature_idx}'
- relationships["form_to_target"][form_id]["keypoint"].append({
- "target_id": target_id,
- "point": point_name,
- "support_reason": support_point.get('支撑理由', '')
- })
- if target_id not in relationships["target_from_form"]:
- relationships["target_from_form"][target_id] = []
- relationships["target_from_form"][target_id].append({
- "form_id": form_id,
- "name": form.get('名称', ''),
- "type": dimension_2,
- "support_reason": support_point.get('支撑理由', '')
- })
- else:
- target_id = f'keypoint-{point_idx}'
- relationships["form_to_target"][form_id]["keypoint"].append({
- "target_id": target_id,
- "point": point_name,
- "support_reason": support_point.get('支撑理由', '')
- })
- if target_id not in relationships["target_from_form"]:
- relationships["target_from_form"][target_id] = []
- relationships["target_from_form"][target_id].append({
- "form_id": form_id,
- "name": form.get('名称', ''),
- "type": dimension_2,
- "support_reason": support_point.get('支撑理由', '')
- })
- # 3. 构建形式点到实质点的支撑关系
- for form in all_forms:
- form_id = form.get('id', '')
- if not form_id:
- continue
- dimension_2 = form.get('维度', {}).get('二级', '')
- support_data = form.get('支撑', [])
- if not support_data:
- continue
- # 初始化形式点的支撑关系
- if form_id not in relationships["form_to_substance"]:
- relationships["form_to_substance"][form_id] = []
- # 支撑字段可能是列表或字典
- support_items = []
- if isinstance(support_data, list):
- # 列表格式:[{id, 名称}, ...]
- support_items = support_data
- elif isinstance(support_data, dict):
- # 字典格式:{'具体元素': [...], '具象概念': [...]}
- for _category, items in support_data.items():
- if isinstance(items, list):
- support_items.extend(items)
- for support_item in support_items:
- if not isinstance(support_item, dict):
- continue
- substance_id = support_item.get('id', '')
- substance_name = support_item.get('名称', '')
- if not substance_id:
- continue
- # 形式点 → 实质点
- relationships["form_to_substance"][form_id].append({
- "substance_id": substance_id,
- "name": substance_name
- })
- # 实质点 ← 形式点(反向)
- if substance_id not in relationships["substance_from_form"]:
- relationships["substance_from_form"][substance_id] = []
- relationships["substance_from_form"][substance_id].append({
- "form_id": form_id,
- "name": form.get('名称', ''),
- "type": dimension_2
- })
- return relationships
|