Files
PlantAI-rag/evaluation/interactive_annotate.py
T

288 lines
9.2 KiB
Python
Raw Normal View History

2026-07-10 17:59:59 +08:00
#!/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()