Procházet zdrojové kódy

Merge remote-tracking branch 'origin/develop_v1.2.202407292348' into develop_v1.2.202407292348

chenhongyan1989 před 2 týdny
rodič
revize
c37a668750

+ 9 - 0
appBoot/app.py

@@ -3,7 +3,16 @@ import time
 import threading
 from argparse import ArgumentParser
 from appBoot.logUtil import LogUtil
+from health_monitoring import health_router
+app.include_router(health_router)
 
+# ³õʼ»¯·þÎñ
+@app.on_event("startup")
+def init_health_module():
+    from health_monitoring.services import MSETService
+    app.state.health_service = MSETService()
+
+    
 def parse_args():
     parser = ArgumentParser(description="Run as a service.")
     parser.add_argument("action", choices=["start", "stop", "restart", "status"],default="start")

+ 0 - 0
common/__init__.py


+ 128 - 0
common/appConfig.py

@@ -0,0 +1,128 @@
+import os
+import logging
+from dataclasses import dataclass, asdict
+from utils.logUtil import LogUtil
+from utils.config_loader import ConfigLoader
+
+# 简化版的GetLogger实现
+def GetLogger(name='default'):
+    """返回配置好的日志器"""
+    logger = LogUtil.get_logger(name)
+    return logger
+
+@dataclass
+class DatabaseConfig:
+    type: str
+    url: str
+    timeout: int
+    poolSize: int
+    maxPoolSize: int
+    minPoolSize: int
+    maxIdleTime: int
+
+@dataclass
+class MinioConfig:
+    endpoint: str
+    accessKey: str
+    secretKey: str
+    secure: bool
+    poolSize: int
+    timeout: int
+
+@dataclass
+class LoggingConfig:
+    logFilePath: str
+    maxFileSize: int
+    maxTotalSize: int
+    backupCount: int
+    logFormat: str
+    level: str
+
+@dataclass
+class AppConfig:
+    databaseConfig: dict
+    minioConfig: MinioConfig
+    loggingConfig: LoggingConfig
+
+    @staticmethod
+    def load_from_file(file_path: str):
+        try:
+            # 确保使用正确的配置加载方法
+            config_data = ConfigLoader.load_config(file_path)
+            database_config = config_data.get('databaseConfig', {})
+            minio_config = MinioConfig(**config_data.get('minioConfig', {}))
+            logging_config = LoggingConfig(**config_data.get('loggingConfig', {}))
+
+            return AppConfig(
+                databaseConfig=database_config,
+                minioConfig=minio_config,
+                loggingConfig=logging_config
+            )
+        except Exception as e:
+            print(f"加载配置文件失败: {e}")
+            # 返回默认配置
+            return AppConfig(
+                databaseConfig={},
+                minioConfig=MinioConfig(None, None, None, False, 5, 30),
+                loggingConfig=LoggingConfig('log/app.log', 10485760, 104857600, 5, '%(asctime)s - %(levelname)s - %(message)s', 'INFO')
+            )
+
+def GetDbUtil():
+    """获取数据库工具实例"""
+    from utils.rdbmsUtil import RdbmsUtil  # 延迟导入避免循环依赖
+    
+    try:
+        # 从配置中获取数据库连接参数
+        db_config = config.databaseConfig
+        if not db_config:
+            raise ValueError("数据库配置未加载")
+            
+        return RdbmsUtil(
+            db_type=db_config.get('type'),
+            db_url=db_config.get('url'),
+            timeout=db_config.get('timeout', 30),
+            pool_size=db_config.get('poolSize', 5)
+        )
+    except Exception as e:
+        logger = GetLogger()
+        logger.error(f"创建数据库工具失败: {e}")
+        return None
+
+def GetMinIOUtil():
+    """获取MinIO工具实例"""
+    from utils.minioUtil import MinioUtil  # 延迟导入避免循环依赖
+    
+    try:
+        # 从配置中获取MinIO连接参数
+        minio_config = config.minioConfig
+        if not minio_config.endpoint:
+            raise ValueError("MinIO配置不完整")
+            
+        return MinioUtil(
+            endpoint=minio_config.endpoint,
+            access_key=minio_config.accessKey,
+            secret_key=minio_config.secretKey,
+            secure=minio_config.secure,
+            pool_size=minio_config.poolSize,
+            timeout=minio_config.timeout
+        )
+    except Exception as e:
+        logger = GetLogger()
+        logger.error(f"创建MinIO工具失败: {e}")
+        return None
+
+# 默认配置 - 添加错误处理
+try:
+    config = AppConfig.load_from_file(os.path.join(os.path.dirname(__file__), '..', 'conf', 'appConfig.json'))
+except Exception as e:
+    print(f"加载默认配置失败: {e}")
+    # 使用硬编码的默认配置
+    config = AppConfig(
+        databaseConfig={},
+        minioConfig=MinioConfig(None, None, None, False, 5, 30),
+        loggingConfig=LoggingConfig('log/app.log', 10485760, 104857600, 5, '%(asctime)s - %(levelname)s - %(message)s', 'INFO')
+    )
+
+# 使用示例
+logger = GetLogger()
+logger.info("Application configuration loaded successfully.")

binární
data/F26_SEP_ZHANGYAOXIAN.xlsx


+ 13 - 0
dataAnalysisBehavior/common/appConfig.py

@@ -5,8 +5,21 @@ from utils.logUtil import LogUtil
 from utils.rdbmsUtil.databaseUtil import DatabaseUtil
 from utils.minioUtil.minioClientPool import MinioClientPool
 from utils.minioUtil.threadSafeMinioClient import ThreadSafeMinioClient
+from utils.config_loader import ConfigLoader
 from algorithmContract.const import *
+import logging
 
+def GetLogger():
+    """返回配置好的日志器"""
+    logging.basicConfig(
+        level=logging.INFO,
+        format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
+        handlers=[
+            logging.FileHandler('log/app.log'),
+            logging.StreamHandler()
+        ]
+    )
+    return logging.getLogger(__name__)
 
 @dataclass
 class DatabaseConfig:

+ 10 - 2
dataAnalysisService/service/serviceOfDataAnalysis.py

@@ -1,4 +1,5 @@
-import importlib
+
+import sys
 import pandas as pd
 from logging import Logger
 from utils.jsonUtil import JsonUtil
@@ -9,7 +10,14 @@ from algorithmContract.contract import Contract,LoadAnalysisInput, Analysis
 from algorithmContract.const import *
 from behavior.baseAnalyst import BaseAnalyst
 from behavior.dalAnalyst import DALAnalyst
-from algorithm.dataProcessor import DataProcessor
+from pathlib import Path
+
+# 获取项目根目录(WTOAAM文件夹)
+BASE_DIR = str(Path(__file__).resolve().parent.parent.parent.parent)  # 向上四级到项目根目录
+
+if BASE_DIR not in sys.path:
+    sys.path.append(BASE_DIR)
+from dataAnalysisBusiness.algorithm.dataProcessor import DataProcessor
 from common.commonBusiness import CommonBusiness
 from common.appConfig import AppConfig
 from sqlalchemy.orm import Session

+ 0 - 0
health_monitoring/__init__.py


+ 0 - 0
health_monitoring/admin.py


+ 7 - 0
health_monitoring/apps.py

@@ -0,0 +1,7 @@
+# wtoaam/health_monitoring/apps.py
+from django.apps import AppConfig
+
+class HealthMonitoringConfig(AppConfig):
+    default_auto_field = 'django.db.models.BigAutoField'
+    name = 'health_monitoring'
+    verbose_name = '健康状态监测'

+ 0 - 0
health_monitoring/management/__init__.py


+ 0 - 0
health_monitoring/management/commands/__init__.py


+ 35 - 0
health_monitoring/management/commands/test_excel.py

@@ -0,0 +1,35 @@
+from django.core.management.base import BaseCommand
+from health_monitoring.services.mset_service import MSETService
+
+class Command(BaseCommand):
+    help = '测试Excel数据加载和MSET计算(原代码逻辑验证)'
+
+    def handle(self, *args, **options):
+        # 1. 初始化服务
+        service = MSETService()
+        
+        # 2. 测试发电机组数据
+        self.stdout.write("=== 测试发电机组数据 ===")
+        service.train_from_excel('generator')
+        test_data_gen = {
+            'U_temp': 65, 
+            'V_temp': 67, 
+            'W_temp': 63, 
+            'bearing_temp': 45
+        }
+        score_gen, weights_gen = service.evaluate_health(test_data_gen)
+        self.stdout.write(f"发电机组健康度: {score_gen}")
+        self.stdout.write(f"权重分布: {weights_gen}")
+
+        # 3. 测试机舱系统数据(可选)
+        self.stdout.write("\n=== 测试机舱系统数据 ===")
+        service.train_from_excel('nacelle')
+        test_data_nac = {
+            'vibration_x': 2.3,
+            'vibration_y': 1.8,
+            'position': 102,
+            'temp': 28
+        }
+        score_nac, weights_nac = service.evaluate_health(test_data_nac)
+        self.stdout.write(f"机舱系统健康度: {score_nac}")
+        self.stdout.write(f"权重分布: {weights_nac}")

+ 20 - 0
health_monitoring/models.py

@@ -0,0 +1,20 @@
+from django.db import models
+
+class HealthRecord(models.Model):
+    """健康度记录模型"""
+    DEVICE_TYPES = (
+        ('generator', '发电机组'),
+        ('nacelle', '机舱系统'),
+        ('converter', '变流器'),
+        ('grid', '电网环境')
+    )
+    
+    device_id = models.CharField(max_length=50, verbose_name="设备ID")
+    subsystem = models.CharField(max_length=20, choices=DEVICE_TYPES, verbose_name="子系统类型")
+    score = models.FloatField(verbose_name="健康度评分")
+    weights = models.JSONField(verbose_name="权重分布")
+    timestamp = models.DateTimeField(auto_now_add=True, verbose_name="记录时间")
+
+    class Meta:
+        db_table = 'health_records'
+        indexes = [models.Index(fields=['device_id', 'subsystem'])]

+ 8 - 0
health_monitoring/serializers.py

@@ -0,0 +1,8 @@
+from rest_framework import serializers
+from .models import HealthRecord
+
+class HealthRecordSerializer(serializers.ModelSerializer):
+    class Meta:
+        model = HealthRecord
+        fields = ['device_id', 'subsystem', 'score', 'weights', 'timestamp']
+        read_only_fields = ['timestamp']

+ 0 - 0
health_monitoring/services/__init__.py


+ 217 - 0
health_monitoring/services/mset_service.py

@@ -0,0 +1,217 @@
+import numpy as np
+import pandas as pd
+from sklearn.neighbors import BallTree
+from pathlib import Path
+from typing import Tuple, Dict, List
+
+class MSETService:
+    def __init__(self):
+        self.matrixD = None     
+        self.matrixL = None     
+        self.healthyResidual = None  
+        self.normalDataBallTree = None  
+        self.DDSimilarity = None  
+        self.project_root = Path(__file__).resolve().parent.parent.parent
+
+    @staticmethod
+    def generate_test_data(num_samples: int = 1000) -> Dict[str, pd.DataFrame]:
+        """生成测试数据"""
+        np.random.seed(42)
+        gen_data = np.random.normal(80, 5, (num_samples, 4))
+        nacelle_data = np.random.normal(0.5, 0.1, (num_samples, 4))
+        converter_data = np.column_stack([
+            np.random.normal(40, 5, num_samples),
+            np.random.normal(2000, 300, num_samples)
+        ])
+        grid_data = np.column_stack([
+            np.random.normal(500, 100, num_samples),
+            np.random.normal(2000, 300, num_samples),
+            np.random.normal(1000, 200, (num_samples, 3))
+        ])
+        return {
+            'generator': pd.DataFrame(gen_data, columns=['U_temp', 'V_temp', 'W_temp', 'bearing_temp']),
+            'nacelle': pd.DataFrame(nacelle_data, columns=['vibration_front', 'vibration_side', 'position', 'temperature']),
+            'converter': pd.DataFrame(converter_data, columns=['coolant_temp', 'active_power']),
+            'grid': pd.DataFrame(grid_data, columns=['reactive_power', 'active_power', 'current_A', 'current_B', 'current_C'])
+        }
+
+    def calc_similarity(self, x: np.ndarray, y: np.ndarray, method: str = 'euc') -> float:
+        if len(x) != len(y):
+            return 0.0
+        if method == 'cbd':
+            return np.mean([1 / (1 + np.abs(p - q)) for p, q in zip(x, y)])
+        else:
+            return 1 / (1 + np.sqrt(np.sum((p - q)**2 for p, q in zip(x, y))))
+
+    def train_model(self, train_data: np.ndarray, dataSize4D: int = 100, dataSize4L: int = 50) -> int:
+        m, n = train_data.shape
+        if m < dataSize4D + dataSize4L:
+            print('训练数据集太小,无法生成矩阵D和L')
+            return -1
+
+        self.matrixD = []
+        selectIndex4D = []
+        for i in range(n):
+            feature_i = train_data[:, i]
+            minIndex = np.argmin(feature_i)
+            maxIndex = np.argmax(feature_i)
+            self.matrixD.extend([train_data[minIndex], train_data[maxIndex]])
+            selectIndex4D.extend([minIndex, maxIndex])
+
+        while len(selectIndex4D) < dataSize4D:
+            freeStateList = list(set(range(len(train_data))) - set(selectIndex4D))
+            if not freeStateList: break
+            distList = [np.mean([1 - self.calc_similarity(train_data[i], x) for x in self.matrixD]) 
+                        for i in freeStateList]
+            selectId = freeStateList[np.argmax(distList)]
+            self.matrixD.append(train_data[selectId])
+            selectIndex4D.append(selectId)
+
+        self.matrixD = np.array(self.matrixD[:dataSize4D])
+        self.matrixL = train_data
+        self.normalDataBallTree = BallTree(
+            self.matrixD, leaf_size=4, 
+            metric=lambda i,j: 1 - self.calc_similarity(i,j)
+        )
+
+        lamdaRatio = 1e-3
+        m_d = len(self.matrixD)
+        self.DDSimilarity = np.array([
+            [1 - self.calc_similarity(x, y) for x in self.matrixD] for y in self.matrixD
+        ]) + lamdaRatio * np.eye(m_d)
+        self.DDSimilarity = np.linalg.inv(self.DDSimilarity)
+        self.healthyResidual = self._calc_residuals(self.matrixL)
+        return 0
+
+    def _calc_residuals(self, states: np.ndarray) -> np.ndarray:
+        m, n = states.shape
+        est_X = []
+        for x in states:
+            dist, iList = self.normalDataBallTree.query([x], 20, return_distance=True)
+            weight = 1 / (dist[0] + 1e-1)
+            weight = weight / np.sum(weight)
+            eState = np.sum([w * self.matrixD[i] for w, i in zip(weight, iList[0])], axis=0)
+            est_X.append(eState)
+        return np.array(est_X) - states
+
+    def _critic_prepare(self, data: pd.DataFrame, flag: int = 1) -> pd.DataFrame:
+        data_columns = data.columns.values
+        maxnum = np.max(data, axis=0)
+        minnum = np.min(data, axis=0)
+        Y = (data - minnum) / (maxnum - minnum) if flag == 0 else (maxnum - data) / (maxnum - minnum)
+        Y0 = Y.values  # 转换为NumPy数组
+        Y0[np.where(Y0 == 0)] = 0.00001
+        return pd.DataFrame(Y0, columns=data_columns)
+
+    def _critic(self, data: pd.DataFrame) -> np.ndarray:
+        """确保返回NumPy数组"""
+        n, m = data.shape
+        s = np.std(data, axis=0)
+        r = np.corrcoef(data, rowvar=False)
+        a = np.sum(1 - r, axis=1)
+        c = s * a
+        weights = c / np.sum(c)
+        return weights  # 直接返回NumPy数组
+
+    def evaluate_subsystem_health(self, data: pd.DataFrame) -> Tuple[np.ndarray, float]:
+            data = data.apply(pd.to_numeric, errors='coerce').dropna()
+            if data.empty: return np.array([]), 0.0
+            
+            W_prepare_data = self._critic_prepare(data)
+            weights = self._critic(W_prepare_data)  # 获取权重
+            
+            # 关键修改:显式转换为NumPy数组
+            weights = np.array(weights)
+            
+            data_values = data.values
+            m, n = data_values.shape
+            flag_Spart_data = []
+            
+            for i in range(n):
+                data_i = data_values[:, i].reshape(-1, 1)
+                train_data = data_i[:len(data_i)//2]
+                test_data = data_i[len(data_i)//2+1:]
+                
+                if len(train_data) < 10 or len(test_data) < 5:
+                    continue
+                
+                self.train_model(train_data, 60, 5)
+                feature_weight = np.array([1.0])
+                flag_data = self._sprt(test_data, feature_weight, decisionGroup=5)
+                flag_Spart_data.append(flag_data)
+            
+            if not flag_Spart_data: return weights, 0.0
+            
+            flag_Spart_data = np.array(flag_Spart_data).T
+            weights = weights.reshape(-1, 1)  # 现在可以安全调用reshape
+            score = np.dot(flag_Spart_data, weights).mean()
+            return weights.flatten(), float(score)
+
+            
+    def _sprt(self, newStates: np.ndarray, feature_weight: np.ndarray, 
+              alpha: float = 0.1, beta: float = 0.1, decisionGroup: int = 5) -> List[float]:
+        feature_weight = feature_weight.flatten()
+        stateResidual = self._calc_residuals(newStates)
+        
+        if stateResidual.shape[1] != len(feature_weight):
+            feature_weight = np.array([1.0])
+        
+        weightedStateResidual = [np.dot(x, feature_weight) for x in stateResidual]
+        weightedHealthyResidual = [np.dot(x, feature_weight) for x in self.healthyResidual]
+        
+        mu0 = np.mean(weightedHealthyResidual)
+        sigma0 = np.std(weightedHealthyResidual)
+        if sigma0 < 1e-10: sigma0 = 1e-10
+        
+        lowThres = np.log(beta / (1 - alpha))
+        highThres = np.log((1 - beta) / alpha)
+        flag = []
+        
+        for i in range(len(newStates) - decisionGroup + 1):
+            mu1 = np.mean(weightedStateResidual[i:i+decisionGroup])
+            si = np.sum(weightedStateResidual[i:i+decisionGroup]) * (mu1 - mu0) / sigma0**2 - \
+                 decisionGroup * (mu1**2 - mu0**2) / (2 * sigma0**2)
+            
+            si = np.clip(si, lowThres, highThres)
+            si = 100 - (si / highThres if si > 0 else si / lowThres) * 100
+            flag.append(si)
+        
+        return flag
+
+    def evaluate_turbine_health(self, subsystems_data: Dict[str, pd.DataFrame]) -> Tuple[float, Dict[str, float]]:
+        subsystems = {
+            'generator': [10, 11, 12, 17],
+            'nacelle': [23, 24, 41, 42],
+            'converter': [18, 19],
+            'grid': [32, 38, 64, 65, 66]
+        }
+        matrix_subsys = np.array([
+            [1, 2, 3, 4],
+            [1/2, 1, 2, 3],
+            [1/3, 1/2, 1, 2],
+            [1/4, 1/3, 1/2, 1],
+        ])
+        
+        health_scores = {}
+        for name, cols in subsystems.items():
+            if name in subsystems_data:
+                data = subsystems_data[name]
+                w, score = self.evaluate_subsystem_health(data)
+                health_scores[name] = score
+        
+        subsystem_names = list(health_scores.keys())
+        if not subsystem_names: return 0.0, {}
+        
+        m = len(subsystem_names)
+        ahp_matrix = matrix_subsys[:m, :m]
+        eigenvalue, eigenvector = np.linalg.eig(ahp_matrix)
+        max_idx = np.argmax(eigenvalue)
+        subsystem_weights = eigenvector[:, max_idx].real
+        subsystem_weights = subsystem_weights / np.sum(subsystem_weights)
+        
+        overall_score = np.sum([
+            health_scores[name] * subsystem_weights[i] 
+            for i, name in enumerate(subsystem_names)
+        ])
+        
+        return float(overall_score), health_scores

+ 0 - 0
health_monitoring/tests.py


+ 0 - 0
health_monitoring/tests/__init__.py


+ 52 - 0
health_monitoring/tests/test_mset.py

@@ -0,0 +1,52 @@
+import unittest
+import pandas as pd
+import numpy as np
+from pathlib import Path
+from health_monitoring.services.mset_service import MSETService
+
+class TestMSETService(unittest.TestCase):
+    def setUp(self):
+        """初始化测试数据"""
+        self.service = MSETService()
+        self.test_data = self.service.generate_test_data(500)
+
+    def test_train_model_dimension(self):
+        """测试模型训练的维度匹配"""
+        gen_data = self.test_data['generator'].values
+        self.service.train_model(gen_data)
+        self.assertIsNotNone(self.service.matrixD)
+        self.assertIsNotNone(self.service.normalDataBallTree)
+
+    def test_subsystem_health_evaluation(self):
+        """测试子系统健康度计算(含AHP权重)"""
+        gen_data = self.test_data['generator']
+        weights, score = self.service.evaluate_subsystem_health(gen_data)
+        
+        # 验证权重和评分有效性
+        self.assertEqual(len(weights), 4, "发电机应有4个特征权重")
+        self.assertTrue(0 <= score <= 100, f"评分异常: {score}")
+        print(f"发电机健康度: {score:.2f}, 权重: {weights.round(2)}")
+
+    def test_ahp_weight_calculation(self):
+        """测试AHP权重计算逻辑"""
+        # 模拟3个子系统的AHP矩阵
+        matrix = np.array([[1, 2, 3], [1/2, 1, 2], [1/3, 1/2, 1]])
+        eigenvalue, eigenvector = np.linalg.eig(matrix)
+        max_idx = np.argmax(eigenvalue)
+        weights = eigenvector[:, max_idx].real
+        weights = weights / np.sum(weights)
+        
+        # 修正后的断言:将消息作为最后一个位置参数
+        self.assertAlmostEqual(np.sum(weights), 1, 4, "AHP权重和应为1")
+        print(f"AHP权重测试: {weights.round(2)}")
+
+    def test_overall_health_with_ahp(self):
+        """测试整体健康度(严格使用AHP矩阵)"""
+        overall_score, subsys_scores = self.service.evaluate_turbine_health(self.test_data)
+        
+        self.assertTrue(0 <= overall_score <= 100, f"整体评分异常: {overall_score}")
+        self.assertGreater(len(subsys_scores), 0, "至少存在一个子系统评分")
+        print(f"整体健康度: {overall_score:.2f}, 子系统: {subsys_scores}")
+
+if __name__ == "__main__":
+    unittest.main()

+ 7 - 0
health_monitoring/urls.py

@@ -0,0 +1,7 @@
+from django.urls import path
+from . import views
+
+urlpatterns = [
+    path('devices/<str:device_id>/', views.DeviceHealthView.as_view(), name='device-health'),
+    path('history/<str:device_id>/', views.HealthHistoryView.as_view(), name='health-history'),
+]

+ 30 - 0
health_monitoring/views.py

@@ -0,0 +1,30 @@
+from rest_framework.views import APIView
+from rest_framework.response import Response
+from rest_framework import status
+from .models import HealthRecord
+from .serializers import HealthRecordSerializer
+from .services.mset_service import MSETService
+
+class DeviceHealthView(APIView):
+    """设备健康度评估"""
+    def post(self, request, device_id):
+        service = MSETService()
+        try:
+            score, weights = service.evaluate_health(request.data)
+            record = HealthRecord.objects.create(
+                device_id=device_id,
+                subsystem=request.data.get('subsystem'),
+                score=score,
+                weights=weights
+            )
+            serializer = HealthRecordSerializer(record)
+            return Response(serializer.data, status=status.HTTP_201_CREATED)
+        except Exception as e:
+            return Response({"error": str(e)}, status=status.HTTP_400_BAD_REQUEST)
+
+class HealthHistoryView(APIView):
+    """健康度历史查询"""
+    def get(self, request, device_id):
+        records = HealthRecord.objects.filter(device_id=device_id).order_by('-timestamp')
+        serializer = HealthRecordSerializer(records, many=True)
+        return Response(serializer.data)

+ 0 - 0
utils/__init__.py


+ 20 - 0
utils/config_loader.py

@@ -0,0 +1,20 @@
+# utils/config_loader.py
+
+import json
+import os
+
+class ConfigLoader:
+    @staticmethod
+    def load_config(file_path):
+        """从JSON文件加载配置"""
+        if not os.path.exists(file_path):
+            raise FileNotFoundError(f"配置文件不存在: {file_path}")
+            
+        with open(file_path, 'r', encoding='utf-8') as f:
+            return json.load(f)
+
+# 在需要使用配置的地方,可以这样调用
+if __name__ == "__main__":
+    config_path = os.path.join(os.path.dirname(__file__), '..', 'conf', 'appConfig.json')
+    config = ConfigLoader.load_config(config_path)
+    print(config)

+ 12 - 0
utils/directoryUtil.py

@@ -0,0 +1,12 @@
+import os
+
+class DirectoryUtil:
+    @staticmethod
+    def check_directory_exists(path: str) -> bool:
+        """检查目录是否存在"""
+        return os.path.exists(path)
+
+    @staticmethod
+    def create_directory(path: str) -> None:
+        """创建目录"""
+        os.makedirs(path, exist_ok=True)

+ 20 - 0
utils/jsonUtil.py

@@ -0,0 +1,20 @@
+# utils/jsonUtil.py
+
+import json
+
+class JsonUtil:
+    @staticmethod
+    def load_json(file_path):
+        with open(file_path, 'r') as file:
+            return json.load(file)
+
+    @staticmethod
+    def dump_json(data, file_path):
+        with open(file_path, 'w') as file:
+            json.dump(data, file)
+            
+    @staticmethod
+    def read_json(file_path):
+        """读取JSON文件内容"""
+        with open(file_path, 'r', encoding='utf-8') as f:
+            return json.load(f)        

+ 14 - 0
utils/logUtil.py

@@ -0,0 +1,14 @@
+# utils/logUtil.py
+
+import logging
+
+class LogUtil:
+    @staticmethod
+    def get_logger(name='default'):
+        logger = logging.getLogger(name)
+        handler = logging.StreamHandler()
+        formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
+        handler.setFormatter(formatter)
+        logger.addHandler(handler)
+        logger.setLevel(logging.INFO)
+        return logger

+ 0 - 0
utils/minioUtil/__init__.py


+ 12 - 0
utils/minioUtil/minioClientPool.py

@@ -0,0 +1,12 @@
+# utils/minioUtil/minioClientPool.py
+
+class MinioClientPool:
+    @staticmethod
+    def get_client():
+        # 这里添加获取 Minio 客户端的代码
+        pass
+
+    @staticmethod
+    def release_client(client):
+        # 这里添加释放 Minio 客户端的代码
+        pass

+ 10 - 0
utils/minioUtil/threadSafeMinioClient.py

@@ -0,0 +1,10 @@
+# utils/minioUtil/threadSafeMinioClient.py
+
+class ThreadSafeMinioClient:
+    def __init__(self):
+        # 初始化 Minio 客户端,确保线程安全
+        pass
+
+    def get_client(self):
+        # 提供线程安全的 Minio 客户端实例
+        pass

+ 0 - 0
utils/rdbmsUtil/__init__.py


+ 12 - 0
utils/rdbmsUtil/databaseUtil.py

@@ -0,0 +1,12 @@
+# utils/rdbmsUtil/databaseUtil.py
+
+class DatabaseUtil:
+    @staticmethod
+    def connect():
+        # 这里添加数据库连接代码
+        pass
+
+    @staticmethod
+    def disconnect():
+        # 这里添加数据库断开代码
+        pass

+ 4 - 1
wtoaamapi/README.MD

@@ -15,4 +15,7 @@
     安装Swagger框架,命令:pip install drf-yasg2
 
 ## 运行
-    运行Django网站,命令:python manage.py runserver
+    运行Django网站,命令:python manage.py runserver
+
+
+# 测试8888

+ 7 - 2
wtoaamapi/apps/viewDemo/viewDataAnalysis.py

@@ -5,12 +5,17 @@ from drf_yasg.utils import swagger_auto_schema
 from rest_framework.viewsets import ViewSet
 from django.http import HttpResponse
 from utils.rdbmsUtil.databaseUtil import DatabaseUtil
-from common.appConfig import GetLogger, GetDbUtil, GetMinIOUtil
+# from common.appConfig import GetLogger, GetDbUtil, GetMinIOUtil
+# from dataContract.algorithmContract.const import *
+# from dataContract.algorithmContract.contract import Contract, LoadAnalysisInput, Analysis
+# from dataContract.algorithmContract.confBusiness import *
+# from dataAnalysisBehavior.behavior.outputProcessor import OutputProcessor
+from appConfig import GetLogger, GetDbUtil, GetMinIOUtil
 from algorithmContract.const import *
 from algorithmContract.contract import Contract, LoadAnalysisInput, Analysis
 from algorithmContract.confBusiness import *
 from behavior.outputProcessor import OutputProcessor
-from service.serviceOfDataAnalysis import ServiceOfDataAnalysis
+from dataAnalysisService.service.serviceOfDataAnalysis import ServiceOfDataAnalysis
 import threading
 
 tags = ['dataAnalysis']

+ 85 - 18
wtoaamapi/manage.py

@@ -1,17 +1,65 @@
 #!/usr/bin/env python
-"""Django's command-line utility for administrative tasks."""
 import os
 import sys
 import signal
 import socket
-from utils.directoryUtil import DirectoryUtil
-from common.appConfig import GetLogger
+
+# ====== 系统级路径配置 ======
+def setup_python_path():
+    # 获取目录结构
+    manage_dir = os.path.dirname(os.path.abspath(__file__))          # wtoaamapi/
+    wtoaam_dir = os.path.dirname(manage_dir)                        # WTOAAM/
+    project_root = os.path.dirname(wtoaam_dir)                      # GitExample/
+
+    # 添加所有必要的搜索路径(按优先级排序)
+    paths_to_add = [
+        project_root,                          # GitExample/
+        wtoaam_dir,                            # WTOAAM/
+        os.path.join(wtoaam_dir, 'common'),    # WTOAAM/common/
+        os.path.join(wtoaam_dir, 'utils'),     # WTOAAM/utils/
+        os.path.join(wtoaam_dir, 'wtoaamapi'), # WTOAAM/wtoaamapi/
+        os.path.join(wtoaam_dir, 'dataContract'), # 添加 dataContract 路径
+        os.path.join(wtoaam_dir, 'dataAnalysisBehavior'), # 添加 behavior 模块路径
+        os.path.join(wtoaam_dir, 'dataAnalysisService') # 添加 service 模块路径
+    
+    ]
+
+    # 添加路径到 sys.path(按顺序添加,不重复)
+    for path in paths_to_add:
+        if path not in sys.path:
+            sys.path.insert(0, path)  # 插入到最前面保证优先级
+
+    return manage_dir, wtoaam_dir, project_root
+
+# ====== 初始化路径配置 ======
+manage_dir, wtoaam_dir, project_root = setup_python_path()
+
+# ====== 打印调试信息 ======
+def print_debug_info():
+    print("Current working directory:", os.getcwd())
+    print("\n===== Python路径配置 =====")
+    for p in sys.path[:15]:  # 打印更多路径以便查看
+        print(p)
+    print("...\n=======================")
+
+print_debug_info()
+
+# ====== 安全导入自定义模块 ======
+try:
+    from common.appConfig import GetLogger
+    from utils.directoryUtil import DirectoryUtil
+except ImportError as e:
+    print(f"\n!!! 关键错误: 导入失败 !!!")
+    print(f"错误详情: {e}")
+    print("请检查以下文件是否存在:")
+    print(f"1. {os.path.join(wtoaam_dir, 'common/appConfig.py')}")
+    print(f"2. {os.path.join(wtoaam_dir, 'utils/directoryUtil.py')}")
+    sys.exit(1)
 
 def get_ip_address():
     """Get the IP address of the current machine."""
     s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
     try:
-        # This doesn't have to be reachable, just an address on the same network
         s.connect(('10.254.254.254', 1))
         ip_address = s.getsockname()[0]
     except Exception:
@@ -22,36 +70,55 @@ def get_ip_address():
 
 def customSignalHandler(signal, frame):
     ip_address = get_ip_address()
-    msg1=f'Custom signal handler: Cleanup operations can be done here.'
-    msg2=f'The IP address of this machine is: {ip_address}'
+    msg1 = f'Custom signal handler: Cleanup operations can be done here.'
+    msg2 = f'The IP address of this machine is: {ip_address}'
     print(msg1)
     logger = GetLogger()
     logger.warning(msg1)
     logger.warning(msg2)
-    
     sys.exit(0)
 
 def main():
-    logDirectory="log"
+    # ====== 1. 先初始化日志目录 ======
+    logDirectory = "log"
     if not DirectoryUtil.check_directory_exists(logDirectory):
         DirectoryUtil.create_directory(logDirectory)
-    """Run administrative tasks."""
-    os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'wtoaamapi.settings')
+
+    # ====== 2. 配置Django环境 ======
+    # 方案A:如果settings.py在 wtoaamapi/wtoaamapi/settings.py
+    settings_dir = os.path.join(manage_dir, 'wtoaamapi')
+    # 方案B:如果settings.py直接在 wtoaamapi/settings.py
+    # settings_dir = manage_dir  
+
+    # 添加settings目录到路径(如果需要)
+    if settings_dir not in sys.path:
+        sys.path.insert(0, settings_dir)
+
+    # 设置Django配置
+    os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'wtoaamapi.wtoaamapi.settings')
+    
     try:
+        # 必须先导入django再执行setup()
+        import django
+        django.setup()  # 初始化Django
+        
         from django.core.management import execute_from_command_line
     except ImportError as exc:
+        # 增强错误信息
+        current_paths = "\n".join(sys.path)
         raise ImportError(
-            "Couldn't import Django. Are you sure it's installed and "
-            "available on your PYTHONPATH environment variable? Did you "
-            "forget to activate a virtual environment?"
+            f"Couldn't import Django. Please check:\n"
+            f"1. Django安装: pip show django\n"
+            f"2. 虚拟环境: {sys.prefix}\n"
+            f"3. 当前Python路径:\n{current_paths}\n"
+            f"4. Settings文件位置: {settings_dir}/settings.py"
         ) from exc
     
-    # Register custom signal handlers
-    signal.signal(signal.SIGINT, customSignalHandler)  # Handle Ctrl-C
-    signal.signal(signal.SIGTERM, customSignalHandler)  # Handle kill command
+    # ====== 3. 注册信号处理器 ======
+    signal.signal(signal.SIGINT, customSignalHandler)
+    signal.signal(signal.SIGTERM, customSignalHandler)
 
     execute_from_command_line(sys.argv)
 
-
 if __name__ == '__main__':
-    main()
+    main()

+ 5 - 3
wtoaamapi/wtoaamapi/settings.py

@@ -17,7 +17,9 @@ from pathlib import Path
 BASE_DIR = Path(__file__).resolve().parent.parent
 STATIC_ROOT=BASE_DIR
 
-
+HEALTH_MONITORING = {
+    'DATA_SOURCE': os.path.join(BASE_DIR, 'data'),  # 指向项目根目录下的data文件夹
+}
 # Quick-start development settings - unsuitable for production
 # See https://docs.djangoproject.com/en/4.2/howto/deployment/checklist/
 
@@ -40,7 +42,7 @@ INSTALLED_APPS = [
     'django.contrib.sessions',
     'django.contrib.messages',
     'django.contrib.staticfiles',    
-
+    'health_monitoring',
     'apps',   # 应用名称
     'rest_framework',
 	'drf_yasg',  # swagger自动生成接口文档
@@ -57,7 +59,7 @@ MIDDLEWARE = [
     # 'middleware.ConcurrencyMiddleware', # 限制所有接口服务的最大请求数
 ]
 
-ROOT_URLCONF = 'wtoaamapi.urls'
+ROOT_URLCONF = 'wtoaamapi.wtoaamapi.urls'
 
 TEMPLATES = [
     {