Files
PlantAI-rag/evaluation/interactive_annotate.py
T
2026-07-10 17:59:59 +08:00

288 lines
9.2 KiB
Python
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/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()