368 lines
15 KiB
Python
368 lines
15 KiB
Python
#!/usr/bin/env python3
|
|
# -*- coding: utf-8 -*-
|
|
|
|
"""
|
|
健康数据处理主执行脚本
|
|
统一调用个人和部门健康数据处理
|
|
|
|
@Author: bruno.gao <[email protected]>
|
|
@ProjectName: ljwx-boot
|
|
@CreateTime: 2025-01-26
|
|
"""
|
|
|
|
import os
|
|
import sys
|
|
import json
|
|
import logging
|
|
import argparse
|
|
import time
|
|
from datetime import datetime
|
|
from typing import Dict, List
|
|
|
|
# 添加当前目录到路径
|
|
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
|
|
|
from personal_health_processor import PersonalHealthProcessor
|
|
from department_health_processor import DepartmentHealthProcessor
|
|
from auth_manager import AuthManager, create_auth_manager
|
|
|
|
class HealthProcessingManager:
|
|
"""健康数据处理管理器"""
|
|
|
|
def __init__(self, config_file: str = None):
|
|
self.config = self.load_config(config_file)
|
|
self.setup_logging()
|
|
|
|
# 初始化认证管理器
|
|
self.auth_manager = create_auth_manager(self.config)
|
|
if self.auth_manager:
|
|
self.logger.info("🔐 初始化认证管理器")
|
|
if not self.auth_manager.login():
|
|
raise Exception("初始认证失败,无法继续执行")
|
|
else:
|
|
self.logger.warning("⚠️ 未配置认证信息,将尝试无认证访问")
|
|
|
|
def load_config(self, config_file: str = None) -> Dict:
|
|
"""加载配置文件"""
|
|
default_config = {
|
|
'ljwx_boot': {
|
|
'base_url': 'http://localhost:8080',
|
|
'token': None,
|
|
'timeout': 30
|
|
},
|
|
'personal_processing': {
|
|
'enabled': True,
|
|
'generate_baseline': True,
|
|
'generate_score': True,
|
|
'generate_prediction': True,
|
|
'generate_recommendation': True,
|
|
'generate_profile': True,
|
|
'baseline_days': 30,
|
|
'score_days': 30,
|
|
'prediction_days': 30,
|
|
'profile_days': 90,
|
|
'user_days': 30,
|
|
'max_workers': 5
|
|
},
|
|
'department_processing': {
|
|
'enabled': True,
|
|
'generate_baseline': True,
|
|
'generate_score': True,
|
|
'generate_prediction': True,
|
|
'generate_recommendation': True,
|
|
'generate_profile': True,
|
|
'baseline_days': 90,
|
|
'score_days': 30,
|
|
'prediction_days': 30,
|
|
'profile_days': 180,
|
|
'org_days': 30,
|
|
'max_workers': 3
|
|
},
|
|
'output': {
|
|
'save_results': True,
|
|
'output_dir': './results',
|
|
'generate_report': True
|
|
}
|
|
}
|
|
|
|
if config_file and os.path.exists(config_file):
|
|
try:
|
|
with open(config_file, 'r', encoding='utf-8') as f:
|
|
file_config = json.load(f)
|
|
# 递归合并配置
|
|
self.merge_config(default_config, file_config)
|
|
print(f"✅ 已加载配置文件: {config_file}")
|
|
except Exception as e:
|
|
print(f"⚠️ 配置文件加载失败,使用默认配置: {str(e)}")
|
|
else:
|
|
if config_file:
|
|
print(f"⚠️ 配置文件不存在,使用默认配置: {config_file}")
|
|
else:
|
|
print("📄 使用默认配置")
|
|
|
|
return default_config
|
|
|
|
def merge_config(self, default: Dict, custom: Dict) -> None:
|
|
"""递归合并配置"""
|
|
for key, value in custom.items():
|
|
if key in default:
|
|
if isinstance(default[key], dict) and isinstance(value, dict):
|
|
self.merge_config(default[key], value)
|
|
else:
|
|
default[key] = value
|
|
else:
|
|
default[key] = value
|
|
|
|
def setup_logging(self):
|
|
"""设置日志"""
|
|
# 创建结果目录
|
|
output_dir = self.config['output']['output_dir']
|
|
os.makedirs(output_dir, exist_ok=True)
|
|
|
|
# 配置日志
|
|
log_file = os.path.join(output_dir, f'health_processing_{datetime.now().strftime("%Y%m%d_%H%M%S")}.log')
|
|
logging.basicConfig(
|
|
level=logging.INFO,
|
|
format='%(asctime)s - %(levelname)s - %(message)s',
|
|
handlers=[
|
|
logging.FileHandler(log_file, encoding='utf-8'),
|
|
logging.StreamHandler()
|
|
]
|
|
)
|
|
self.logger = logging.getLogger(__name__)
|
|
self.logger.info(f"📋 日志文件: {log_file}")
|
|
|
|
def process_personal_health(self) -> List:
|
|
"""处理个人健康数据"""
|
|
if not self.config['personal_processing']['enabled']:
|
|
self.logger.info("⏭️ 个人健康数据处理已禁用")
|
|
return []
|
|
|
|
self.logger.info("🚀 开始个人健康数据处理")
|
|
|
|
try:
|
|
processor = PersonalHealthProcessor(
|
|
base_url=self.config['ljwx_boot']['base_url'],
|
|
token=self.config['ljwx_boot']['token'],
|
|
auth_manager=self.auth_manager
|
|
)
|
|
|
|
results = processor.process_all_users(self.config['personal_processing'])
|
|
|
|
if self.config['output']['save_results'] and results:
|
|
output_dir = self.config['output']['output_dir']
|
|
output_file = os.path.join(output_dir, f'personal_results_{datetime.now().strftime("%Y%m%d_%H%M%S")}.json')
|
|
processor.save_results(results, output_file)
|
|
|
|
return results
|
|
|
|
except Exception as e:
|
|
self.logger.error(f"❌ 个人健康数据处理失败: {str(e)}")
|
|
return []
|
|
|
|
def process_department_health(self) -> List:
|
|
"""处理部门健康数据"""
|
|
if not self.config['department_processing']['enabled']:
|
|
self.logger.info("⏭️ 部门健康数据处理已禁用")
|
|
return []
|
|
|
|
self.logger.info("🚀 开始部门健康数据处理")
|
|
|
|
try:
|
|
processor = DepartmentHealthProcessor(
|
|
base_url=self.config['ljwx_boot']['base_url'],
|
|
token=self.config['ljwx_boot']['token']
|
|
)
|
|
|
|
results = processor.process_all_organizations(self.config['department_processing'])
|
|
|
|
if self.config['output']['save_results'] and results:
|
|
output_dir = self.config['output']['output_dir']
|
|
output_file = os.path.join(output_dir, f'department_results_{datetime.now().strftime("%Y%m%d_%H%M%S")}.json')
|
|
processor.save_results(results, output_file)
|
|
|
|
return results
|
|
|
|
except Exception as e:
|
|
self.logger.error(f"❌ 部门健康数据处理失败: {str(e)}")
|
|
return []
|
|
|
|
def generate_summary_report(self, personal_results: List, department_results: List) -> str:
|
|
"""生成汇总报告"""
|
|
report_lines = [
|
|
"# 健康数据处理汇总报告",
|
|
f"## 处理时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}",
|
|
""
|
|
]
|
|
|
|
# 个人健康数据统计
|
|
if personal_results:
|
|
total_users = len(personal_results)
|
|
success_stats = {
|
|
'baseline': sum(1 for r in personal_results if r.baseline_success),
|
|
'score': sum(1 for r in personal_results if r.score_success),
|
|
'prediction': sum(1 for r in personal_results if r.prediction_success),
|
|
'recommendation': sum(1 for r in personal_results if r.recommendation_success),
|
|
'profile': sum(1 for r in personal_results if r.profile_success)
|
|
}
|
|
error_users = sum(1 for r in personal_results if r.errors)
|
|
|
|
report_lines.extend([
|
|
"## 个人健康数据处理结果",
|
|
f"- 总用户数: {total_users}",
|
|
f"- 基线生成成功: {success_stats['baseline']} ({success_stats['baseline']/total_users*100:.1f}%)",
|
|
f"- 评分生成成功: {success_stats['score']} ({success_stats['score']/total_users*100:.1f}%)",
|
|
f"- 预测生成成功: {success_stats['prediction']} ({success_stats['prediction']/total_users*100:.1f}%)",
|
|
f"- 建议生成成功: {success_stats['recommendation']} ({success_stats['recommendation']/total_users*100:.1f}%)",
|
|
f"- 画像生成成功: {success_stats['profile']} ({success_stats['profile']/total_users*100:.1f}%)",
|
|
f"- 有错误的用户: {error_users} ({error_users/total_users*100:.1f}%)",
|
|
""
|
|
])
|
|
else:
|
|
report_lines.extend([
|
|
"## 个人健康数据处理结果",
|
|
"- 未处理个人健康数据",
|
|
""
|
|
])
|
|
|
|
# 部门健康数据统计
|
|
if department_results:
|
|
total_orgs = len(department_results)
|
|
total_users = sum(r.user_count for r in department_results)
|
|
success_stats = {
|
|
'baseline': sum(1 for r in department_results if r.baseline_success),
|
|
'score': sum(1 for r in department_results if r.score_success),
|
|
'prediction': sum(1 for r in department_results if r.prediction_success),
|
|
'recommendation': sum(1 for r in department_results if r.recommendation_success),
|
|
'profile': sum(1 for r in department_results if r.profile_success)
|
|
}
|
|
error_orgs = sum(1 for r in department_results if r.errors)
|
|
|
|
report_lines.extend([
|
|
"## 部门健康数据处理结果",
|
|
f"- 总组织数: {total_orgs}",
|
|
f"- 涉及用户数: {total_users}",
|
|
f"- 基线生成成功: {success_stats['baseline']} ({success_stats['baseline']/total_orgs*100:.1f}%)",
|
|
f"- 评分生成成功: {success_stats['score']} ({success_stats['score']/total_orgs*100:.1f}%)",
|
|
f"- 预测生成成功: {success_stats['prediction']} ({success_stats['prediction']/total_orgs*100:.1f}%)",
|
|
f"- 建议生成成功: {success_stats['recommendation']} ({success_stats['recommendation']/total_orgs*100:.1f}%)",
|
|
f"- 画像生成成功: {success_stats['profile']} ({success_stats['profile']/total_orgs*100:.1f}%)",
|
|
f"- 有错误的组织: {error_orgs} ({error_orgs/total_orgs*100:.1f}%)",
|
|
""
|
|
])
|
|
else:
|
|
report_lines.extend([
|
|
"## 部门健康数据处理结果",
|
|
"- 未处理部门健康数据",
|
|
""
|
|
])
|
|
|
|
# 配置信息
|
|
report_lines.extend([
|
|
"## 处理配置",
|
|
f"- ljwx-boot 服务地址: {self.config['ljwx_boot']['base_url']}",
|
|
f"- 个人数据处理: {'启用' if self.config['personal_processing']['enabled'] else '禁用'}",
|
|
f"- 部门数据处理: {'启用' if self.config['department_processing']['enabled'] else '禁用'}",
|
|
""
|
|
])
|
|
|
|
report_content = "\n".join(report_lines)
|
|
|
|
# 保存报告
|
|
if self.config['output']['generate_report']:
|
|
output_dir = self.config['output']['output_dir']
|
|
report_file = os.path.join(output_dir, f'health_processing_report_{datetime.now().strftime("%Y%m%d_%H%M%S")}.md')
|
|
|
|
try:
|
|
with open(report_file, 'w', encoding='utf-8') as f:
|
|
f.write(report_content)
|
|
self.logger.info(f"📊 汇总报告已生成: {report_file}")
|
|
return report_file
|
|
except Exception as e:
|
|
self.logger.error(f"❌ 生成汇总报告失败: {str(e)}")
|
|
|
|
return report_content
|
|
|
|
def run_all(self) -> Dict:
|
|
"""执行完整的健康数据处理流程"""
|
|
self.logger.info("🎯 开始完整健康数据处理流程")
|
|
start_time = time.time()
|
|
|
|
# 处理个人健康数据
|
|
personal_results = self.process_personal_health()
|
|
|
|
# 处理部门健康数据
|
|
department_results = self.process_department_health()
|
|
|
|
# 生成汇总报告
|
|
report = self.generate_summary_report(personal_results, department_results)
|
|
|
|
elapsed_time = time.time() - start_time
|
|
self.logger.info(f"🎉 健康数据处理完成! 总耗时: {elapsed_time:.2f}秒")
|
|
|
|
return {
|
|
'personal_results': personal_results,
|
|
'department_results': department_results,
|
|
'report': report,
|
|
'elapsed_time': elapsed_time
|
|
}
|
|
|
|
def main():
|
|
"""主函数"""
|
|
parser = argparse.ArgumentParser(description='健康数据处理主程序')
|
|
parser.add_argument('-c', '--config', help='配置文件路径', default='health_processing_config.json')
|
|
parser.add_argument('-p', '--personal-only', action='store_true', help='仅处理个人健康数据')
|
|
parser.add_argument('-d', '--department-only', action='store_true', help='仅处理部门健康数据')
|
|
parser.add_argument('--base-url', help='ljwx-boot 服务地址', default='http://localhost:8080')
|
|
parser.add_argument('--token', help='访问令牌')
|
|
|
|
args = parser.parse_args()
|
|
|
|
# 创建处理管理器
|
|
manager = HealthProcessingManager(args.config)
|
|
|
|
# 命令行参数覆盖配置
|
|
if args.base_url != 'http://localhost:8080':
|
|
manager.config['ljwx_boot']['base_url'] = args.base_url
|
|
if args.token:
|
|
manager.config['ljwx_boot']['token'] = args.token
|
|
if args.personal_only:
|
|
manager.config['department_processing']['enabled'] = False
|
|
if args.department_only:
|
|
manager.config['personal_processing']['enabled'] = False
|
|
|
|
try:
|
|
# 执行处理
|
|
results = manager.run_all()
|
|
|
|
# 输出结果摘要
|
|
print("\n" + "="*60)
|
|
print("🎉 健康数据处理完成!")
|
|
print("="*60)
|
|
|
|
if results['personal_results']:
|
|
print(f"👤 个人数据: 处理 {len(results['personal_results'])} 个用户")
|
|
|
|
if results['department_results']:
|
|
total_users = sum(r.user_count for r in results['department_results'])
|
|
print(f"🏢 部门数据: 处理 {len(results['department_results'])} 个组织,涉及 {total_users} 个用户")
|
|
|
|
print(f"⏱️ 总耗时: {results['elapsed_time']:.2f}秒")
|
|
print(f"📁 输出目录: {manager.config['output']['output_dir']}")
|
|
|
|
if isinstance(results['report'], str) and results['report'].endswith('.md'):
|
|
print(f"📊 汇总报告: {results['report']}")
|
|
|
|
print("="*60)
|
|
|
|
return 0
|
|
|
|
except KeyboardInterrupt:
|
|
print("\n⚠️ 用户中断处理")
|
|
return 130
|
|
except Exception as e:
|
|
print(f"\n❌ 处理失败: {str(e)}")
|
|
return 1
|
|
|
|
if __name__ == "__main__":
|
|
exit(main()) |