pipeline.py 5.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. """七阶段业务流程:确定性执行,保存阶段结果,支持从指定阶段继续。"""
  2. from pathlib import Path
  3. import json
  4. import config
  5. from algorithms.main_fan.equivalence import (RulePolicy, normalize_and_validate_fan_data, compare_basic_parameters,
  6. analyze_fan_performance_curve, analyze_fan_switch_event, match_fan_rules_and_knowledge,
  7. assess_fan_equivalent_capability, trace_fan_evidence_and_review, envelope, evidence_id)
  8. from algorithms.main_fan.models import ScreeningInput, Screening
  9. from extensions.main_fan.pair_reporting import render_fan_assessment_report
  10. STAGES = ("data_preparation", "basic_parameters", "performance_curves", "switch_events", "rules",
  11. "overall_assessment", "report")
  12. def new_stages():
  13. return [{"name":name,"status":"pending","result":None} for name in STAGES]
  14. def load_rules():
  15. configured=config.get_str("MAIN_FAN_RULES_FILE")
  16. path=Path(configured) if configured else Path(__file__).resolve().parents[2]/'examples/main_fan/equivalence_rules.json'
  17. if configured and not path.is_absolute():
  18. path=config.ROOT/path
  19. return RulePolicy.model_validate(json.loads(path.read_text(encoding="utf-8")))
  20. def run_pipeline(context, *, stages=None, start_stage=1, save=None):
  21. if start_stage not in range(1,8):
  22. raise ValueError("重试阶段必须在1~7之间")
  23. stages=stages or new_stages()
  24. if any(s["result"] is None for s in stages[:start_stage-1]):
  25. raise ValueError("上游阶段尚未完成,不能跳过执行")
  26. for stage in stages[start_stage-1:]:
  27. stage.update(status="pending",result=None)
  28. data=ScreeningInput.model_validate(context["data"])
  29. analysis=Screening.model_validate(context["analysis"])
  30. policy=RulePolicy.model_validate(context["policy"])
  31. dataset=normalize_and_validate_fan_data(data,policy,context.get("fan_names"))
  32. def execute(number, function):
  33. stage=stages[number-1]
  34. if number<start_stage:
  35. return stage["result"]
  36. stage["status"]="running"
  37. if save:
  38. save(stages)
  39. try:
  40. value=function()
  41. stage.update(status="insufficient" if value.get("status")=="insufficient" else "completed",result=value)
  42. except Exception as exc:
  43. stage.update(status="failed",error=str(exc)[:240])
  44. if save:
  45. save(stages)
  46. raise
  47. if save:
  48. save(stages)
  49. return value
  50. prepared=execute(1,lambda:envelope({"status":"completed" if analysis.has_in_scope_data else "insufficient", "fan_pair":[{"fan_id":f['fan_id'],"fan_name":f['fan_name'],
  51. "report_id":f['report'].report_id if f['report'] else None} for f in dataset.fans],
  52. "document_count":len(context.get('document_audits',[])),"operating_series_count":len(data.operating_series),
  53. "warnings":dataset.warnings},policy))
  54. basic=execute(2,lambda:compare_basic_parameters(dataset))
  55. curves=execute(3,lambda:analyze_fan_performance_curve(dataset))
  56. switches=execute(4,lambda:analyze_fan_switch_event(dataset))
  57. rules=execute(5,lambda:match_fan_rules_and_knowledge(dataset,basic,curves,switches))
  58. overall=execute(6,lambda:{"status":"completed", "decision":assess_fan_equivalent_capability(dataset,basic,curves,switches,rules),
  59. "trace":trace_fan_evidence_and_review(dataset,basic,curves,switches)})
  60. assessment={"fan_pair":prepared['fan_pair'],"basic_comparison":basic,"performance_comparison":curves,
  61. "switch_comparison":switches,"rule_match":rules,**overall}
  62. report=execute(7,lambda:envelope({"status":"completed", "body":render_fan_assessment_report(dataset,assessment,analysis)},policy))
  63. assessment["stages"]=[{"name":s['name'],"status":s['status']} for s in stages]
  64. return assessment, report['body'], stages
  65. def component(workflow, tool):
  66. stages=workflow['stages']
  67. mapping={"parse_fan_evidence_documents":0,"query_fan_operating_data":0,"normalize_and_validate_fan_data":0,
  68. "analyze_fan_performance_curve":2,"analyze_fan_switch_event":3,"match_fan_rules_and_knowledge":4,
  69. "assess_fan_equivalent_capability":5,"trace_fan_evidence_and_review":5,"render_fan_assessment_report":6}
  70. value=stages[mapping[tool]]['result']
  71. if value is None:
  72. raise ValueError("该阶段尚无完成结果")
  73. if tool=='parse_fan_evidence_documents':
  74. value={**value,"reports":workflow['context']['data']['reports']}
  75. elif tool=='query_fan_operating_data':
  76. value={**value,**{k:workflow['context']['data'][k] for k in ('operating_series','switch_records','fan_state_records')}}
  77. elif tool=='normalize_and_validate_fan_data':
  78. value={**value,"basic_comparison":stages[1]['result']}
  79. elif tool=='trace_fan_evidence_and_review':
  80. value=value['trace']
  81. elif tool=='assess_fan_equivalent_capability':
  82. value=value['decision']
  83. elif tool=='render_fan_assessment_report':
  84. value={**value,"analysis_id":(workflow['result'] or {}).get('analysis_id','')}
  85. return {"workflow_id":workflow['id'],**value}