初始提交
This commit is contained in:
Executable
+287
@@ -0,0 +1,287 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
交互式Gold Standard标注工具
|
||||
通过问答方式完成标注,无需写代码
|
||||
"""
|
||||
|
||||
import sys
|
||||
sys.path.insert(0, '/home/xzq/gene-family-mas-v2')
|
||||
|
||||
from evaluation.gold_standard_annotator import GoldStandardAnnotator
|
||||
import json
|
||||
|
||||
|
||||
def print_header(text):
|
||||
print("\n" + "="*60)
|
||||
print(text)
|
||||
print("="*60)
|
||||
|
||||
|
||||
def get_input(prompt, default=None):
|
||||
"""获取用户输入"""
|
||||
if default:
|
||||
full_prompt = f"{prompt} [{default}]: "
|
||||
else:
|
||||
full_prompt = f"{prompt}: "
|
||||
|
||||
value = input(full_prompt).strip()
|
||||
return value if value else default
|
||||
|
||||
|
||||
def select_from_list(prompt, options):
|
||||
"""从列表中选择"""
|
||||
print(f"\n{prompt}")
|
||||
for i, opt in enumerate(options, 1):
|
||||
print(f" {i}. {opt}")
|
||||
|
||||
while True:
|
||||
choice = input(f"选择 (1-{len(options)}): ").strip()
|
||||
try:
|
||||
idx = int(choice) - 1
|
||||
if 0 <= idx < len(options):
|
||||
return options[idx]
|
||||
except:
|
||||
pass
|
||||
print("无效选择,请重试")
|
||||
|
||||
|
||||
def yes_no(prompt, default=True):
|
||||
"""是/否问题"""
|
||||
default_str = "Y/n" if default else "y/N"
|
||||
while True:
|
||||
answer = input(f"{prompt} [{default_str}]: ").strip().lower()
|
||||
if not answer:
|
||||
return default
|
||||
if answer in ['y', 'yes']:
|
||||
return True
|
||||
if answer in ['n', 'no']:
|
||||
return False
|
||||
print("请输入 y 或 n")
|
||||
|
||||
|
||||
def interactive_annotate():
|
||||
"""交互式标注主流程"""
|
||||
|
||||
print_header("GeneFamily-RAG Gold Standard 交互式标注")
|
||||
print("\n这个工具会引导你完成论文的人工标注")
|
||||
print("标注结果将用于评估自动提取的准确率\n")
|
||||
|
||||
# ========== 步骤1:论文信息 ==========
|
||||
print_header("步骤1:论文基本信息")
|
||||
|
||||
doc_id = get_input("论文ID(如pmid31286919)", "pmid31286919")
|
||||
pmid = get_input("PMID", "31286919")
|
||||
doi = get_input("DOI", "10.1186/s12870-019-1916-6")
|
||||
species = get_input("物种拉丁名", "Fagopyrum tataricum")
|
||||
species_cn = get_input("物种中文名", "苦荞")
|
||||
family = get_input("基因家族", "SPL")
|
||||
year = get_input("发表年份", "2019")
|
||||
|
||||
# ========== 步骤2:读取论文文本 ==========
|
||||
print_header("步骤2:论文文本")
|
||||
|
||||
text_source = select_from_list(
|
||||
"选择文本来源",
|
||||
["从PDF自动提取", "手动粘贴文本", "从文件读取"]
|
||||
)
|
||||
|
||||
text = ""
|
||||
if text_source == "从PDF自动提取":
|
||||
pdf_path = get_input("PDF文件路径",
|
||||
"/home/xzq/gene-family-mas-v2/paper/test_v2_reproduce/input/苦荞SPL2019BMCplantbios12870-019-1916-6.pdf")
|
||||
try:
|
||||
import fitz
|
||||
doc = fitz.open(pdf_path)
|
||||
# 只提取前3页(Abstract + Results开头)
|
||||
for page in doc[:3]:
|
||||
text += page.get_text()
|
||||
doc.close()
|
||||
print(f"✓ 已提取 {len(text)} 字符")
|
||||
except Exception as e:
|
||||
print(f"✗ 提取失败: {e}")
|
||||
text = get_input("请手动粘贴论文文本(Abstract + Results开头)")
|
||||
|
||||
elif text_source == "手动粘贴文本":
|
||||
print("请粘贴论文文本(Abstract + Results开头,按Ctrl+D结束):")
|
||||
lines = []
|
||||
try:
|
||||
while True:
|
||||
line = input()
|
||||
lines.append(line)
|
||||
except EOFError:
|
||||
pass
|
||||
text = "\n".join(lines)
|
||||
|
||||
else: # 从文件读取
|
||||
file_path = get_input("文本文件路径")
|
||||
with open(file_path, 'r', encoding='utf-8') as f:
|
||||
text = f.read()
|
||||
|
||||
if len(text) < 100:
|
||||
print("✗ 文本太短,请重新运行")
|
||||
return
|
||||
|
||||
print(f"✓ 文本长度: {len(text)} 字符")
|
||||
print(f"预览: {text[:200]}...")
|
||||
|
||||
# ========== 步骤3:创建标注器 ==========
|
||||
annotator = GoldStandardAnnotator(
|
||||
doc_id=doc_id,
|
||||
text=text,
|
||||
title=get_input("论文标题", "Genome-wide identification of SPL gene family")
|
||||
)
|
||||
|
||||
annotator.set_metadata(
|
||||
pmid=pmid,
|
||||
doi=doi,
|
||||
species=species,
|
||||
family=family
|
||||
)
|
||||
|
||||
# ========== 步骤4:标注实体 ==========
|
||||
print_header("步骤3:标注实体")
|
||||
print("请从论文中识别关键实体(基因、家族、结构域、组织等)\n")
|
||||
|
||||
entity_types = [
|
||||
"gene", "protein", "gene_family", "protein_domain", "motif",
|
||||
"organism", "tissue", "developmental_stage", "treatment",
|
||||
"phenotype", "assay", "method"
|
||||
]
|
||||
|
||||
entity_count = 0
|
||||
while yes_no("是否添加新实体?", True):
|
||||
entity_count += 1
|
||||
print(f"\n--- 实体 #{entity_count} ---")
|
||||
|
||||
entity_id = get_input("实体ID(如FtSPL1、SPL、PF03110)")
|
||||
if not entity_id:
|
||||
break
|
||||
|
||||
entity_name = get_input("实体名称", entity_id)
|
||||
entity_type = select_from_list("实体类型", entity_types)
|
||||
|
||||
entity_species = None
|
||||
if entity_type in ['gene', 'protein']:
|
||||
entity_species = get_input("所属物种", species)
|
||||
|
||||
primary_id = get_input("稳定外部ID(如UniProt、PFAM编号,可选)", "")
|
||||
description = get_input("描述(可选)", "")
|
||||
|
||||
# 添加到标注器
|
||||
annotator.add_entity(
|
||||
id=entity_id,
|
||||
name=entity_name,
|
||||
type=entity_type,
|
||||
species=entity_species,
|
||||
primary_id=primary_id if primary_id else None,
|
||||
description=description if description else None
|
||||
)
|
||||
|
||||
print(f"✓ 已添加: {entity_id} ({entity_type})")
|
||||
|
||||
print(f"\n共标注 {len(annotator.entities)} 个实体")
|
||||
|
||||
# ========== 步骤5:标注关系 ==========
|
||||
print_header("步骤4:标注关系")
|
||||
print("请标注实体之间的生物学关系\n")
|
||||
|
||||
relation_types = [
|
||||
"member_of", "contains", "expressed_in", "involved_in",
|
||||
"activates", "inhibits", "regulates", "orthologous_to",
|
||||
"paralogous_to", "classified_into", "belongs_to"
|
||||
]
|
||||
|
||||
# 显示已标注的实体供选择
|
||||
print("已标注的实体:")
|
||||
for e in annotator.entities:
|
||||
print(f" - {e.id} ({e.type})")
|
||||
|
||||
relation_count = 0
|
||||
while yes_no("是否添加新关系?", relation_count < 3):
|
||||
relation_count += 1
|
||||
print(f"\n--- 关系 #{relation_count} ---")
|
||||
|
||||
source = get_input("源实体ID")
|
||||
target = get_input("目标实体ID")
|
||||
rel_type = select_from_list("关系类型", relation_types)
|
||||
confidence = select_from_list("置信度", ["high", "medium", "low"])
|
||||
|
||||
# 证据信息
|
||||
print("\n证据信息(原文片段):")
|
||||
snippet = get_input("原文关键句子(50字以内)")
|
||||
section = select_from_list("所在章节",
|
||||
["abstract", "introduction", "results", "discussion", "figure_legend"])
|
||||
|
||||
evidence_level = "experiment"
|
||||
if confidence in ["high", "medium"]:
|
||||
evidence_level = select_from_list("证据等级",
|
||||
["experiment", "omics", "prediction", "curation"])
|
||||
|
||||
method = get_input("实验/分析方法(如qRT-PCR、RNA-seq)", "")
|
||||
|
||||
# 添加到标注器
|
||||
annotator.add_relation(
|
||||
source=source,
|
||||
target=target,
|
||||
type=rel_type,
|
||||
confidence=confidence,
|
||||
text_snippet=snippet,
|
||||
section=section,
|
||||
evidence_level=evidence_level,
|
||||
method=method if method else None
|
||||
)
|
||||
|
||||
print(f"✓ 已添加: {source} --[{rel_type}]--> {target}")
|
||||
|
||||
print(f"\n共标注 {len(annotator.relations)} 个关系")
|
||||
|
||||
# ========== 步骤6:关键发现 ==========
|
||||
print_header("步骤5:关键发现")
|
||||
print("请总结论文的主要发现(一句话一条)\n")
|
||||
|
||||
finding_count = 0
|
||||
while yes_no("是否添加关键发现?", finding_count < 3):
|
||||
finding_count += 1
|
||||
finding = get_input(f"关键发现 #{finding_count}")
|
||||
if finding:
|
||||
annotator.add_key_finding(finding)
|
||||
print(f"✓ 已添加")
|
||||
|
||||
# ========== 步骤7:验证和保存 ==========
|
||||
print_header("步骤6:验证和保存")
|
||||
|
||||
# 显示摘要
|
||||
annotator.print_summary()
|
||||
|
||||
# 验证
|
||||
issues = annotator.validate()
|
||||
if issues:
|
||||
print("\n⚠️ 发现问题:")
|
||||
for issue in issues:
|
||||
print(f" - {issue}")
|
||||
if not yes_no("是否仍要保存?"):
|
||||
print("已取消保存")
|
||||
return
|
||||
|
||||
# 保存
|
||||
default_output = f"/home/xzq/gene-family-mas-v2/evaluation/gold_standard/{doc_id}_manual.json"
|
||||
output_path = get_input("保存路径", default_output)
|
||||
|
||||
annotator.save(output_path)
|
||||
|
||||
print_header("标注完成!")
|
||||
print(f"✓ Gold Standard已保存: {output_path}")
|
||||
print(f"\n下一步:")
|
||||
print(f" 1. 运行自动提取: python extract_with_llm.py ...")
|
||||
print(f" 2. 对比评估: python evaluation/evaluate.py --gold {output_path} --pred <auto_result>")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
try:
|
||||
interactive_annotate()
|
||||
except KeyboardInterrupt:
|
||||
print("\n\n已中断")
|
||||
except Exception as e:
|
||||
print(f"\n✗ 错误: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
Reference in New Issue
Block a user