多语言散落补全
This commit is contained in:
@@ -390,48 +390,57 @@ class DiagnosisAgent(BaseAgent):
|
||||
ERROR_PATTERNS = {
|
||||
"missing_input_file": {
|
||||
"patterns": [r"文件不存在", r"FileNotFoundError", r"No such file", r"找不到文件"],
|
||||
"suggestion": "检查输入文件路径是否正确,确保文件已上传到input目录",
|
||||
"suggestion_zh": "检查输入文件路径是否正确,确保文件已上传到input目录",
|
||||
"suggestion_en": "Check if input file path is correct; ensure files are uploaded to the input directory",
|
||||
"auto_fix": False
|
||||
},
|
||||
"hmm_not_found": {
|
||||
"patterns": [r"required_pfams is empty", r"No HMM file", r"找不到HMM"],
|
||||
"suggestion": "请上传HMM模型文件或指定--required-pfams参数",
|
||||
"suggestion_zh": "请上传HMM模型文件或指定--required-pfams参数",
|
||||
"suggestion_en": "Please upload HMM model file or specify --required-pfams parameter",
|
||||
"auto_fix": False
|
||||
},
|
||||
"blast_db_error": {
|
||||
"patterns": [r"BLAST Database error", r"makeblastdb failed"],
|
||||
"suggestion": "Identify BLAST 固定用目标物种全蛋白 FASTA 建库;请优先检查目标全蛋白 FASTA 是否存在、非空且为有效蛋白FASTA格式,再检查参考家族蛋白 query 文件。",
|
||||
"suggestion_zh": "Identify BLAST 固定用目标物种全蛋白 FASTA 建库;请优先检查目标全蛋白 FASTA 是否存在、非空且为有效蛋白FASTA格式,再检查参考家族蛋白 query 文件。",
|
||||
"suggestion_en": "Identify BLAST uses target species full protein FASTA for database; check that target FASTA exists, is non-empty and valid, then check reference family protein query file.",
|
||||
"auto_fix": False
|
||||
},
|
||||
"memory_error": {
|
||||
"patterns": [r"MemoryError", r"out of memory", r"内存不足"],
|
||||
"suggestion": "减少--cpu参数值或分批处理,建议使用--cpu 4",
|
||||
"suggestion_zh": "减少--cpu参数值或分批处理,建议使用--cpu 4",
|
||||
"suggestion_en": "Reduce --cpu parameter or use batch processing; recommend --cpu 4",
|
||||
"auto_fix": True,
|
||||
"fix_action": "reduce_cpu"
|
||||
},
|
||||
"rnaseq_library_strandness_error": {
|
||||
"patterns": [r"library_strandness", r"链特异性", r"rna-strandness", r"featureCounts.*-s"],
|
||||
"suggestion": "请在 samples.yaml 的 rnaseq.library_strandness 或每个 samples.<sample>.library_strandness 中明确填写 non_stranded / forward / reverse;混合链特异性样本当前不能用单次 featureCounts 定量。",
|
||||
"suggestion_zh": "请在 samples.yaml 的 rnaseq.library_strandness 或每个 samples.<sample>.library_strandness 中明确填写 non_stranded / forward / reverse;混合链特异性样本当前不能用单次 featureCounts 定量。",
|
||||
"suggestion_en": "Please specify non_stranded / forward / reverse in samples.yaml rnaseq.library_strandness or each samples.<sample>.library_strandness; mixed strand-specific samples cannot be quantified in a single featureCounts run.",
|
||||
"auto_fix": False
|
||||
},
|
||||
"timeout_error": {
|
||||
"patterns": [r"Timeout", r"timed out", r"超时"],
|
||||
"suggestion": "增加超时时间或检查输入数据大小",
|
||||
"suggestion_zh": "增加超时时间或检查输入数据大小",
|
||||
"suggestion_en": "Increase timeout or check input data size",
|
||||
"auto_fix": False
|
||||
},
|
||||
"conda_env_error": {
|
||||
"patterns": [r"conda", r"Environment", r"找不到命令"],
|
||||
"suggestion": "检查conda环境是否正确激活,确保工具已安装",
|
||||
"suggestion_zh": "检查conda环境是否正确激活,确保工具已安装",
|
||||
"suggestion_en": "Check that conda environment is activated and tools are installed",
|
||||
"auto_fix": False
|
||||
},
|
||||
"permission_error": {
|
||||
"patterns": [r"Permission denied", r"权限不足"],
|
||||
"suggestion": "检查文件权限,确保有读写权限",
|
||||
"suggestion_zh": "检查文件权限,确保有读写权限",
|
||||
"suggestion_en": "Check file permissions; ensure read/write access",
|
||||
"auto_fix": False
|
||||
},
|
||||
"invalid_parameter": {
|
||||
"patterns": [r"unrecognized arguments", r"invalid parameter", r"参数错误"],
|
||||
"suggestion": "检查参数名称是否正确,注意使用短横线而非下划线",
|
||||
"suggestion_zh": "检查参数名称是否正确,注意使用短横线而非下划线",
|
||||
"suggestion_en": "Check parameter name; use hyphens instead of underscores",
|
||||
"auto_fix": True,
|
||||
"fix_action": "fix_parameter_format"
|
||||
},
|
||||
@@ -448,7 +457,8 @@ class DiagnosisAgent(BaseAgent):
|
||||
r"RuntimeError: MAFFT失败.*No such file",
|
||||
r"RuntimeError:.*失败.*No such file or directory"
|
||||
],
|
||||
"suggestion": "生物信息学工具未安装或未添加到PATH。建议:1) 激活conda环境: conda activate test4py311 2) 安装缺失工具: conda install -c bioconda mafft blast iqtree hmmer",
|
||||
"suggestion_zh": "生物信息学工具未安装或未添加到PATH。建议:1) 激活conda环境: conda activate test4py311 2) 安装缺失工具: conda install -c bioconda mafft blast iqtree hmmer",
|
||||
"suggestion_en": "Bioinformatics tools not installed or not in PATH. Suggestions: 1) activate conda environment: conda activate test4py311 2) install missing tools: conda install -c bioconda mafft blast iqtree hmmer",
|
||||
"auto_fix": False,
|
||||
"severity": "high"
|
||||
},
|
||||
@@ -461,7 +471,8 @@ class DiagnosisAgent(BaseAgent):
|
||||
r"requires.*stage.*not completed",
|
||||
r"dependency.*not satisfied"
|
||||
],
|
||||
"suggestion": "前置分析阶段未完成,系统将自动先执行依赖阶段",
|
||||
"suggestion_zh": "前置分析阶段未完成,系统将自动先执行依赖阶段",
|
||||
"suggestion_en": "Prerequisite analysis stage not completed; system will execute dependency stage first automatically",
|
||||
"auto_fix": True,
|
||||
"fix_action": "execute_dependencies",
|
||||
"severity": "high"
|
||||
@@ -601,6 +612,7 @@ class DiagnosisAgent(BaseAgent):
|
||||
prepare_patch_workspace: bool = False,
|
||||
scope_id: str = "",
|
||||
params: Optional[Dict[str, Any]] = None,
|
||||
language: str = "zh",
|
||||
) -> Dict[str, Any]:
|
||||
"""只读审计某个 job/stage 的产物、manifest、日志和输入配置。
|
||||
|
||||
@@ -930,6 +942,7 @@ class DiagnosisAgent(BaseAgent):
|
||||
gate: str = "preflight",
|
||||
project_root: Path = PROJECT_ROOT,
|
||||
params: Optional[Dict[str, Any]] = None,
|
||||
language: str = "zh",
|
||||
) -> Dict[str, Any]:
|
||||
"""Global QA gate for stage preflight/postflight/failure.
|
||||
|
||||
@@ -4490,10 +4503,10 @@ class DiagnosisAgent(BaseAgent):
|
||||
except Exception as exc:
|
||||
print(f"[DiagnosisAgent] Failed to remember LLM diagnosis case: {exc}")
|
||||
|
||||
def _match_error_pattern(self, error_text: str) -> Optional[Dict]:
|
||||
def _match_error_pattern(self, error_text: str, language: str = "zh") -> Optional[Dict]:
|
||||
"""匹配错误模式"""
|
||||
error_lower = error_text.lower()
|
||||
|
||||
|
||||
priority_order = [
|
||||
"tool_not_found",
|
||||
"dependency_failed",
|
||||
@@ -4507,15 +4520,16 @@ class DiagnosisAgent(BaseAgent):
|
||||
"permission_error",
|
||||
"timeout_error"
|
||||
]
|
||||
|
||||
|
||||
for error_type in priority_order:
|
||||
if error_type in self.ERROR_PATTERNS:
|
||||
pattern_info = self.ERROR_PATTERNS[error_type]
|
||||
for pattern in pattern_info["patterns"]:
|
||||
if re.search(pattern, error_text, re.IGNORECASE):
|
||||
suggestion_key = "suggestion_en" if language == "en" else "suggestion_zh"
|
||||
return {
|
||||
"error_type": error_type,
|
||||
"suggestion": pattern_info["suggestion"],
|
||||
"suggestion": pattern_info.get(suggestion_key, pattern_info.get("suggestion_zh", "")),
|
||||
"auto_fix": pattern_info.get("auto_fix", False),
|
||||
"fix_action": pattern_info.get("fix_action"),
|
||||
"severity": pattern_info.get("severity", "medium")
|
||||
|
||||
@@ -29,6 +29,74 @@ WORKSPACE_DIR = WORKSPACE_ROOT
|
||||
|
||||
|
||||
class Orchestrator:
|
||||
# 双语消息映射表:中文 → English(用于用户可见消息)
|
||||
_MSG = {
|
||||
# analysis_node — response 消息
|
||||
"✅ 所有分析阶段已完成!": "✅ All analysis stages completed!",
|
||||
"📋 自动规划剩余分析阶段": "📋 Auto-planned remaining analysis stages",
|
||||
"**已完成**": "**Completed**",
|
||||
"无": "None",
|
||||
"**待执行**": "**Pending**",
|
||||
"个阶段)": "stage(s))",
|
||||
"请确认是否按顺序执行以上分析阶段?": "Confirm to execute the above analysis stages in order?",
|
||||
"我将帮您执行RNA-seq": "I will help you execute RNA-seq",
|
||||
"分析。请确认参数后开始。": "analysis. Please confirm parameters to start.",
|
||||
"RNA-seq分析将通过前端异步执行。": "RNA-seq analysis will be executed asynchronously via frontend.",
|
||||
" 分析。PlanningAgentV2 已根据当前状态生成完整执行计划。": " analysis. PlanningAgentV2 has generated a complete execution plan based on current state.",
|
||||
"我将帮您执行": "I will help you execute",
|
||||
"分析。": "analysis.",
|
||||
"请提供基因家族蛋白序列文件(.fa/.fasta),用于MEME保守基序预测。": "Please provide gene family protein sequence file (.fa/.fasta) for MEME conserved motif prediction.",
|
||||
"请提供config.xlsx及基因组/GFF/CDS/PEP等原始文件,用于完整数据准备。": "Please provide config.xlsx and genome/GFF/CDS/PEP files for complete data preparation.",
|
||||
"请提供基因家族蛋白序列文件,用于Pfam/InterPro结构域注释。": "Please provide gene family protein sequence file for Pfam/InterPro domain annotation.",
|
||||
"请提供基因家族的GFF注释文件和基因组序列。": "Please provide gene family GFF annotation file and genome sequence.",
|
||||
"请提供基因家族成员的启动子序列(上游2000bp)或全基因组序列+GFF。": "Please provide gene family promoter sequences (upstream 2000bp) or whole genome + GFF.",
|
||||
"请提供物种基因组序列(.fasta)和GFF注释文件。": "Please provide species genome sequence (.fasta) and GFF annotation file.",
|
||||
"请提供多个物种的基因组序列和GFF注释文件,以及物种间的同源关系。": "Please provide genome sequences and GFF annotation files for multiple species, along with inter-species orthology.",
|
||||
"请提供染色体长度信息和基因位置信息。": "Please provide chromosome length and gene position information.",
|
||||
"请提供拟南芥同源基因映射文件(ortholog_pairs.txt,格式:拟南芥ID\t苦荞ID),用于STRING数据库互作预测。如未提供,请先运行同源基因识别分析。": "Please provide Arabidopsis ortholog mapping file (ortholog_pairs.txt, format: AtID\tTargetID) for STRING interaction prediction. If unavailable, run ortholog identification first.",
|
||||
"请提供目标物种和参考物种(如拟南芥At)的蛋白序列文件,用于同源基因识别。": "Please provide target and reference species (e.g., Arabidopsis At) protein FASTA for ortholog identification.",
|
||||
"请提供物种间同源基因对(ortholog pairs,格式:基因A\t基因B)或共线性分析结果。": "Please provide inter-species ortholog pairs (format: GeneA\tGeneB) or synteny analysis results.",
|
||||
"请提供RNA-seq表达矩阵(FPKM/TPM/Count)或原始测序数据。": "Please provide RNA-seq expression matrix (FPKM/TPM/Count) or raw sequencing data.",
|
||||
"请提供差异表达基因列表(DEGs)或目标基因集。": "Please provide differentially expressed gene list (DEGs) or target gene set.",
|
||||
"请提供基因家族蛋白序列文件,用于理化性质分析。": "Please provide gene family protein sequence file for physicochemical property analysis.",
|
||||
"请提供基因家族HMM文件和蛋白序列文件,将自动执行标准11阶段分析。": "Please provide gene family HMM file and protein FASTA; standard 11-stage analysis will be executed automatically.",
|
||||
"请提供RNA-seq原始测序数据(FASTQ格式)。": "Please provide RNA-seq raw sequencing data (FASTQ format).",
|
||||
"请提供质控后的clean reads(FASTQ格式)和参考基因组。": "Please provide QC-filtered clean reads (FASTQ format) and reference genome.",
|
||||
"请提供比对后的BAM文件或参考基因组注释GFF。": "Please provide aligned BAM file or reference genome annotation GFF.",
|
||||
"请提供featureCounts计数矩阵和样本分组表,用于VST、PCA、样本相关性和聚类。": "Please provide featureCounts count matrix and sample grouping table for VST, PCA, sample correlation and clustering.",
|
||||
"请提供多时相表达矩阵(如不同发育阶段/处理时间点)。": "Please provide multi-temporal expression matrix (e.g., different developmental stages/treatment time points).",
|
||||
"请提供VST/log2表达矩阵或count矩阵和样本性状表,用于共表达网络构建。": "Please provide VST/log2 expression matrix or count matrix and sample trait table for co-expression network construction.",
|
||||
"请提供差异表达结果和gene2go背景文件,或先执行背景注释。": "Please provide differential expression results and gene2go background file, or run background annotation first.",
|
||||
"请提供差异表达结果和gene2ko背景文件,或先执行背景注释。": "Please provide differential expression results and gene2ko background file, or run background annotation first.",
|
||||
"请提供差异表达排序统计量和gene2ko/KEGG背景,用于fgsea排序富集。": "Please provide differential expression ranking statistics and gene2ko/KEGG background for fgsea ranked enrichment.",
|
||||
"请提供差异表达结果和目标物种蛋白FASTA;若已有InterProScan TSV会优先复用。": "Please provide differential expression results and target species protein FASTA; existing InterProScan TSV will be reused if available.",
|
||||
"请提供表达矩阵(样本数≥6),用于共表达网络构建。": "Please provide expression matrix (samples ≥ 6) for co-expression network construction.",
|
||||
# knowledge_node — system prompt / response 消息
|
||||
"你是BotanicalBaseAgent基因家族分析系统的知识助手。基于提供的文献资料,生成专业、详细的回答。": "You are a knowledge assistant for the BotanicalBaseAgent gene family analysis system. Generate professional, detailed answers based on provided literature.",
|
||||
"📚 基于知识库的回答:": "📚 Knowledge base answer:",
|
||||
"**参考文献**:": "**References**:",
|
||||
"(来源: 本地LLM回答 + RAG辅助检索)": "(Source: local LLM answer + RAG-assisted retrieval)",
|
||||
"⚠️ (本地LLM回答,未使用RAG文献检索)": "⚠️ (local LLM answer, RAG retrieval not used)",
|
||||
"找到": "Found",
|
||||
"条相关文献,正在生成本地LLM回答...": " related references; generating local LLM answer...",
|
||||
"未找到相关文献,生成一般回答": "No related references found; generating general answer",
|
||||
"你是一个专业的基因家族分析意图识别器。": "You are a professional gene family analysis intent recognizer.",
|
||||
"你是一个基因家族分析专家。用户想要进行基因家族分析。": "You are a gene family analysis expert. The user wants to perform gene family analysis.",
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def _l(cls, zh_text: str, language: str = "zh") -> str:
|
||||
"""Return language-appropriate text from the bilingual map."""
|
||||
if language == "zh":
|
||||
return zh_text
|
||||
en = cls._MSG.get(zh_text)
|
||||
if en is not None:
|
||||
return en
|
||||
# fallback: try partial match for template strings
|
||||
for zh_key, en_val in cls._MSG.items():
|
||||
if zh_key in zh_text:
|
||||
return zh_text.replace(zh_key, en_val)
|
||||
return zh_text
|
||||
def __init__(
|
||||
self,
|
||||
llm_manager: LLMManager,
|
||||
@@ -313,6 +381,7 @@ class Orchestrator:
|
||||
|
||||
async def _router_node(self, state: GraphState) -> dict:
|
||||
query = state["query"]
|
||||
language = state.get("language", "zh")
|
||||
|
||||
# 使用 RouterAgent 进行意图路由
|
||||
print(f"[RouterNode] Using RouterAgent to classify query: {query[:50]}...")
|
||||
@@ -378,6 +447,7 @@ class Orchestrator:
|
||||
|
||||
async def _knowledge_node(self, state: GraphState) -> dict:
|
||||
query = state["query"]
|
||||
language = state.get("language", "zh")
|
||||
|
||||
try:
|
||||
# 优先调用当前 Dual-KB QA 服务
|
||||
@@ -578,7 +648,7 @@ class Orchestrator:
|
||||
"status": "completed",
|
||||
"mode": "analysis",
|
||||
"final_output": {
|
||||
"response": f"✅ 所有分析阶段已完成!\n\n已完成: {', '.join(completed_stages)}",
|
||||
"response": self._l("✅ 所有分析阶段已完成!", language) + "\n\n" + self._l("**已完成**", language) + ": " + ", ".join(completed_stages),
|
||||
"analysis_plan": {
|
||||
"gene_family": gene_family,
|
||||
"species": species,
|
||||
@@ -595,14 +665,7 @@ class Orchestrator:
|
||||
"status": "completed",
|
||||
"mode": "analysis",
|
||||
"final_output": {
|
||||
"response": f"""📋 自动规划剩余分析阶段
|
||||
|
||||
**已完成**: {', '.join(completed_stages) if completed_stages else '无'}
|
||||
|
||||
**待执行** ({len(remaining_stages)}个阶段):
|
||||
{stages_text}
|
||||
|
||||
请确认是否按顺序执行以上分析阶段?""",
|
||||
"response": f"{self._l('📋 自动规划剩余分析阶段', language)}\n\n{self._l('**已完成**', language)}: {', '.join(completed_stages) if completed_stages else self._l('无', language)}\n\n{self._l('**待执行**', language)} ({len(remaining_stages)}{self._l('个阶段)', language)}:\n{stages_text}\n\n{self._l('请确认是否按顺序执行以上分析阶段?', language)}",
|
||||
"analysis_plan": {
|
||||
"gene_family": gene_family,
|
||||
"species": species,
|
||||
@@ -630,6 +693,7 @@ class Orchestrator:
|
||||
async def _analysis_node(self, state: GraphState) -> dict:
|
||||
query = state["query"]
|
||||
files = state.get("files", [])
|
||||
language = state.get("language", "zh")
|
||||
print(f"[_analysis_node] Entered with query: {query[:50]}...", flush=True)
|
||||
|
||||
try:
|
||||
@@ -821,7 +885,7 @@ class Orchestrator:
|
||||
"status": "completed",
|
||||
"mode": "analysis",
|
||||
"final_output": {
|
||||
"response": f"我将帮您执行RNA-seq {analysis_type}分析。请确认参数后开始。",
|
||||
"response": self._l("我将帮您执行RNA-seq", language) + " " + analysis_type + self._l("分析。请确认参数后开始。", language),
|
||||
"analysis_plan": {
|
||||
"gene_family": gene_family,
|
||||
"species": species,
|
||||
@@ -831,7 +895,7 @@ class Orchestrator:
|
||||
"prefix": f"{species}.{gene_family}",
|
||||
"cpu": 8
|
||||
},
|
||||
"guidance": "RNA-seq分析将通过前端异步执行。"
|
||||
"guidance": self._l("RNA-seq分析将通过前端异步执行。", language)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -878,7 +942,7 @@ class Orchestrator:
|
||||
"status": "completed",
|
||||
"mode": "analysis",
|
||||
"final_output": {
|
||||
"response": f"我将帮您执行RNA-seq {analysis_type} 分析。PlanningAgentV2 已根据当前状态生成完整执行计划。",
|
||||
"response": self._l("我将帮您执行RNA-seq", language) + " " + analysis_type + self._l(" 分析。PlanningAgentV2 已根据当前状态生成完整执行计划。", language),
|
||||
"analysis_plan": plan_result.get("final_output", {}).get("analysis_plan", {})
|
||||
}
|
||||
}
|
||||
@@ -889,7 +953,7 @@ class Orchestrator:
|
||||
"status": "completed",
|
||||
"mode": "analysis",
|
||||
"final_output": {
|
||||
"response": f"我将帮您执行RNA-seq {analysis_type} 分析。请确认参数后开始。",
|
||||
"response": self._l("我将帮您执行RNA-seq", language) + " " + analysis_type + self._l(" 分析。请确认参数后开始。", language),
|
||||
"analysis_plan": {
|
||||
"gene_family": gene_family,
|
||||
"species": species,
|
||||
@@ -900,21 +964,25 @@ class Orchestrator:
|
||||
"prefix": f"{species}.{gene_family}",
|
||||
"cpu": 8
|
||||
},
|
||||
"guidance": f"RNA-seq {analysis_type} 分析将通过前端异步执行。"
|
||||
"guidance": self._l("RNA-seq " + analysis_type + " 分析将通过前端异步执行。", language)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Ka/Ks分析:走通用规划流程(返回analysis_plan让前端执行)
|
||||
# 注意:不再直接调用_execute_kaks,而是通过PlanningAgentV2规划完整流程
|
||||
guidance = guidance_map.get(analysis_type, f"请上传进行{analysis_type}分析所需的文件,或确认使用系统内置数据。")
|
||||
|
||||
guidance = guidance_map.get(analysis_type)
|
||||
if guidance:
|
||||
guidance = self._l(guidance, language)
|
||||
else:
|
||||
guidance = self._l("请上传进行", language) + analysis_type + self._l("分析所需的文件,或确认使用系统内置数据。", language)
|
||||
|
||||
return {
|
||||
"current_agent": "analysis",
|
||||
"status": "completed",
|
||||
"mode": "analysis",
|
||||
"final_output": {
|
||||
"response": f"我将帮您执行{analysis_type}分析。",
|
||||
"response": self._l("我将帮您执行", language) + analysis_type + self._l("分析。", language),
|
||||
"analysis_plan": {
|
||||
"gene_family": gene_family,
|
||||
"species": species,
|
||||
|
||||
Reference in New Issue
Block a user