Files
PlantAI-rag/api/species_routes.py
2026-07-10 17:59:59 +08:00

207 lines
6.3 KiB
Python
Executable File

"""
物种查询API路由
提供基因家族-物种索引查询功能
"""
from fastapi import APIRouter, HTTPException, Query
from pydantic import BaseModel
from typing import List, Dict, Optional
from pathlib import Path
import json
from src.rag.project_config import PROJECT_ROOT
router = APIRouter()
INDEX_FILE = PROJECT_ROOT / "data" / "gene_family_species_index.json"
class SpeciesInfo(BaseModel):
"""物种信息"""
paper_id: str
scientific_name: str
common_name_en: str
common_name_cn: str
comparison_species: List[str]
relations_count: int
entities_count: int
pmid: Optional[str]
class GeneFamilyInfo(BaseModel):
"""基因家族信息"""
gene_family: str
description: str
description_cn: str
total_species: int
species_list: List[SpeciesInfo]
class SpeciesListResponse(BaseModel):
"""物种列表响应"""
gene_family: str
total_species: int
species: List[SpeciesInfo]
class SpeciesQueryResponse(BaseModel):
"""物种查询响应"""
query: str
matched_species: List[Dict]
total_matches: int
def load_species_index() -> dict:
"""加载物种索引"""
if not INDEX_FILE.exists():
raise HTTPException(status_code=500, detail="物种索引文件不存在,请先运行索引构建脚本")
with open(INDEX_FILE, 'r', encoding='utf-8') as f:
return json.load(f)
@router.get("/species/list", response_model=SpeciesListResponse)
async def list_species_by_gene_family(
gene_family: str = Query("SPL", description="基因家族名称,如SPL、NAC、WRKY等")
):
"""
获取指定基因家族已分析的所有物种列表
示例:
- /api/v1/species/list?gene_family=SPL
"""
try:
index = load_species_index()
gene_family_upper = gene_family.upper()
if gene_family_upper not in index.get("gene_families", {}):
return SpeciesListResponse(
gene_family=gene_family,
total_species=0,
species=[]
)
gf_info = index["gene_families"][gene_family_upper]
# 构建响应
species_list = []
for species in gf_info.get("species_list", []):
species_list.append(SpeciesInfo(
paper_id=species["paper_id"],
scientific_name=species["scientific_name"],
common_name_en=species["common_name_en"],
common_name_cn=species["common_name_cn"],
comparison_species=species["comparison_species"],
relations_count=species["relations_count"],
entities_count=species["entities_count"],
pmid=species.get("pmid") or None
))
return SpeciesListResponse(
gene_family=gene_family_upper,
total_species=gf_info["total_species"],
species=species_list
)
except Exception as e:
raise HTTPException(status_code=500, detail=f"查询失败: {str(e)}")
@router.get("/species/search", response_model=SpeciesQueryResponse)
async def search_species(
query: str = Query(..., description="物种查询关键词,支持中文、英文、拉丁学名")
):
"""
搜索特定物种是否做过基因家族分析
示例:
- /api/v1/species/search?query=苦荞
- /api/v1/species/search?query=tartary
- /api/v1/species/search?query=Fagopyrum
"""
try:
index = load_species_index()
query_lower = query.lower()
matches = []
# 遍历所有基因家族
for gf_name, gf_info in index.get("gene_families", {}).items():
for species in gf_info.get("species_list", []):
# 匹配多个字段
match_fields = [
species["scientific_name"].lower(),
species["common_name_en"].lower(),
species["common_name_cn"]
]
if any(query_lower in field for field in match_fields):
matches.append({
"gene_family": gf_name,
"paper_id": species["paper_id"],
"scientific_name": species["scientific_name"],
"common_name_en": species["common_name_en"],
"common_name_cn": species["common_name_cn"],
"pmid": species.get("pmid"),
"relations_count": species["relations_count"],
"entities_count": species["entities_count"]
})
return SpeciesQueryResponse(
query=query,
matched_species=matches,
total_matches=len(matches)
)
except Exception as e:
raise HTTPException(status_code=500, detail=f"查询失败: {str(e)}")
@router.get("/species/gene-families", response_model=List[str])
async def list_gene_families():
"""
获取所有已索引的基因家族列表
示例:
- /api/v1/species/gene-families
"""
try:
index = load_species_index()
return list(index.get("gene_families", {}).keys())
except Exception as e:
raise HTTPException(status_code=500, detail=f"查询失败: {str(e)}")
@router.get("/species/stats")
async def get_statistics():
"""
获取基因家族-物种索引统计信息
示例:
- /api/v1/species/stats
"""
try:
index = load_species_index()
stats = {
"total_gene_families": len(index.get("gene_families", {})),
"total_papers": len(index.get("papers", {})),
"total_species_indexed": len(index.get("species_index", {})),
"metadata": index.get("metadata", {}),
"gene_families": {}
}
for gf_name, gf_info in index.get("gene_families", {}).items():
stats["gene_families"][gf_name] = {
"description_cn": gf_info.get("description_cn", ""),
"total_species": gf_info.get("total_species", 0),
"species_names": [s["common_name_cn"] for s in gf_info.get("species_list", [])]
}
return stats
except Exception as e:
raise HTTPException(status_code=500, detail=f"查询失败: {str(e)}")