Browse Source

fix:AI测量

super-yimizi 3 weeks ago
parent
commit
eb54f5cbbe

+ 75 - 0
application/api/controller/BodyProfile.php

@@ -332,4 +332,79 @@ class BodyProfile extends Api
             $this->error($e->getMessage());
             $this->error($e->getMessage());
         }
         }
     }
     }
+
+    /**
+     * 保存测量数据和体型选择(合并接口)
+     */
+    public function saveMeasurementAndBodyType()
+    {
+        $params = $this->request->post();
+        
+        // 验证基本参数
+        if (!isset($params['profile_id']) || !$params['profile_id']) {
+            $this->error('档案ID不能为空');
+        }
+
+        // 分离测量数据和体型选择数据
+        $measurementData = [];
+        $bodyTypeSelections = [];
+        
+        // 测量数据字段
+        $measurementFields = [
+            'chest', 'waist', 'hip', 'thigh', 'calf', 'upper_arm', 'forearm', 
+            'neck', 'shoulder_width', 'bust', 'underbust', 'inseam', 'outseam', 
+            'shoe_size', 'measurement_date'
+        ];
+        
+        // 提取测量数据
+        foreach ($measurementFields as $field) {
+            if (isset($params[$field]) && $params[$field] !== '') {
+                $measurementData[$field] = $params[$field];
+            }
+        }
+        
+        // 提取体型选择数据
+        if (isset($params['selections']) && is_array($params['selections'])) {
+            $bodyTypeSelections = $params['selections'];
+        }
+
+        // 检查是否至少有一种数据
+        if (empty($measurementData) && empty($bodyTypeSelections)) {
+            $this->error('请至少提供测量数据或体型选择数据');
+        }
+
+        // 验证测量数据(如果有)
+        if (!empty($measurementData)) {
+            $measurementData['profile_id'] = $params['profile_id'];
+            $measurementValidate = new BodyMeasurementsValidate();
+            if (!$measurementValidate->scene('add')->check($measurementData)) {
+                $this->error('测量数据验证失败:' . $measurementValidate->getError());
+            }
+        }
+
+        // 验证体型选择数据(如果有)
+        if (!empty($bodyTypeSelections)) {
+            $selectionData = [
+                'profile_id' => $params['profile_id'],
+                'selections' => $bodyTypeSelections
+            ];
+            $selectionValidate = new BodyTypeSelectionValidate();
+            if (!$selectionValidate->scene('save')->check($selectionData)) {
+                $this->error('体型选择数据验证失败:' . $selectionValidate->getError());
+            }
+        }
+
+        // try {
+            $result = BodyProfileService::saveMeasurementAndBodyType(
+                $params['profile_id'], 
+                $this->auth->id, 
+                $measurementData ?: [],  // 确保不是null
+                $bodyTypeSelections ?: [] // 确保不是null
+            );
+            
+            $this->success('保存成功', $result);
+        // } catch (\Exception $e) {
+        //     $this->error($e->getMessage());
+        // }
+    }
 }
 }

+ 52 - 23
application/common/Service/BodyProfileService.php

@@ -158,7 +158,14 @@ class BodyProfileService
         }
         }
 
 
         // 过滤测量数据字段
         // 过滤测量数据字段
-        $measurementFields = array_keys(BodyMeasurements::getMeasurementFields($profile->gender));
+        $gender = $profile->gender ?? 0; // 确保gender不为null
+        $measurementFieldsMap = BodyMeasurements::getMeasurementFields($gender);
+        
+        if (!$measurementFieldsMap || !is_array($measurementFieldsMap)) {
+            throw new BusinessException('无法获取测量字段配置');
+        }
+        
+        $measurementFields = array_keys($measurementFieldsMap);
         $filteredData = ['profile_id' => $profileId];
         $filteredData = ['profile_id' => $profileId];
 
 
         foreach ($measurementFields as $field) {
         foreach ($measurementFields as $field) {
@@ -234,28 +241,6 @@ class BodyProfileService
     }
     }
 
 
     /**
     /**
-     * 获取体型推荐
-     */
-    public static function getBodyTypeRecommendation($profileId, $userId)
-    {
-        // 验证档案归属
-        $profile = BodyProfile::where('id', $profileId)
-            ->where('user_id', $userId)
-            ->with(['latestMeasurement'])
-            ->find();
-
-        if (!$profile) {
-            throw new BusinessException('档案不存在');
-        }
-
-        if (!$profile->latestMeasurement) {
-            throw new BusinessException('请先添加身体测量数据');
-        }
-
-        return BodyTypeService::getSmartRecommendation($profileId, $profile->latestMeasurement);
-    }
-
-    /**
      * 生成AI测试报告
      * 生成AI测试报告
      */
      */
     public static function generateAiReport($profileId, $userId, $reportType = 'comprehensive')
     public static function generateAiReport($profileId, $userId, $reportType = 'comprehensive')
@@ -336,4 +321,48 @@ class BodyProfileService
 
 
         return BodyTypeService::generateSelectionReport($profileId);
         return BodyTypeService::generateSelectionReport($profileId);
     }
     }
+
+    /**
+     * 保存测量数据和体型选择(合并业务逻辑)
+     */
+    public static function saveMeasurementAndBodyType($profileId, $userId, $measurementData = [], $bodyTypeSelections = [])
+    {
+        // 验证档案归属
+        $profile = BodyProfile::where('id', $profileId)
+            ->where('user_id', $userId)
+            ->find();
+
+        if (!$profile) {
+            throw new BusinessException('档案不存在');
+        }
+
+        $result = [
+            'measurement_saved' => false,
+            'body_type_saved' => false,
+            'measurement_id' => null
+        ];
+
+        Db::startTrans();
+        try {
+            // 保存测量数据
+            if (!empty($measurementData)) {
+                $measurement = self::addMeasurement($profileId, $userId, $measurementData);
+                $result['measurement_saved'] = true;
+                $result['measurement_id'] = $measurement->id;
+            }
+
+            // 保存体型选择
+            if (!empty($bodyTypeSelections)) {
+                $selectionResult = self::saveBodyTypeSelection($profileId, $userId, $bodyTypeSelections);
+                $result['body_type_saved'] = $selectionResult;
+            }
+
+            Db::commit();
+            return $result;
+
+        } catch (\Throwable $e) {
+            Db::rollback();
+            throw new BusinessException($e->getMessage());
+        }
+    }
 }
 }

+ 35 - 10
application/common/Service/BodyTypeService.php

@@ -96,10 +96,21 @@ class BodyTypeService
         }
         }
 
 
         $config = Config::get('body_type_config');
         $config = Config::get('body_type_config');
+        
+        // 检查配置是否存在
+        if (!$config || !isset($config['recommendation_rules']) || !is_array($config['recommendation_rules'])) {
+            return []; // 如果配置不存在,返回空数组
+        }
+        
         $rules = $config['recommendation_rules'];
         $rules = $config['recommendation_rules'];
         $recommendations = [];
         $recommendations = [];
 
 
         foreach ($rules as $category => $rule) {
         foreach ($rules as $category => $rule) {
+            // 检查规则格式是否正确
+            if (!is_array($rule) || !isset($rule['metrics']) || !is_array($rule['metrics'])) {
+                continue;
+            }
+            
             // 检查是否有必要的测量数据
             // 检查是否有必要的测量数据
             $hasRequiredData = true;
             $hasRequiredData = true;
             foreach ($rule['metrics'] as $metric) {
             foreach ($rule['metrics'] as $metric) {
@@ -128,11 +139,21 @@ class BodyTypeService
      */
      */
     private static function applyRecommendationRules($measurements, $rule)
     private static function applyRecommendationRules($measurements, $rule)
     {
     {
+        // 检查规则格式
+        if (!isset($rule['rules']) || !is_array($rule['rules'])) {
+            return null;
+        }
+        
         foreach ($rule['rules'] as $ruleItem) {
         foreach ($rule['rules'] as $ruleItem) {
+            // 检查规则项格式
+            if (!is_array($ruleItem) || !isset($ruleItem['condition'])) {
+                continue;
+            }
+            
             if ($ruleItem['condition'] === 'default') {
             if ($ruleItem['condition'] === 'default') {
                 return [
                 return [
-                    'type_name' => $ruleItem['type'],
-                    'confidence' => $ruleItem['confidence'],
+                    'type_name' => $ruleItem['type'] ?? '未知类型',
+                    'confidence' => $ruleItem['confidence'] ?? 0.5,
                     'reason' => '基于默认规则推荐'
                     'reason' => '基于默认规则推荐'
                 ];
                 ];
             }
             }
@@ -140,8 +161,8 @@ class BodyTypeService
             // 解析条件表达式
             // 解析条件表达式
             if (self::evaluateCondition($measurements, $ruleItem['condition'])) {
             if (self::evaluateCondition($measurements, $ruleItem['condition'])) {
                 return [
                 return [
-                    'type_name' => $ruleItem['type'],
-                    'confidence' => $ruleItem['confidence'],
+                    'type_name' => $ruleItem['type'] ?? '未知类型',
+                    'confidence' => $ruleItem['confidence'] ?? 0.5,
                     'reason' => '基于测量数据分析推荐'
                     'reason' => '基于测量数据分析推荐'
                 ];
                 ];
             }
             }
@@ -208,15 +229,19 @@ class BodyTypeService
             ];
             ];
 
 
             // 检查是否与AI推荐一致
             // 检查是否与AI推荐一致
-            if (isset($recommendations[$category])) {
+            if (isset($recommendations[$category]) && is_array($recommendations[$category])) {
                 $recommendation = $recommendations[$category];
                 $recommendation = $recommendations[$category];
-                if ($recommendation['type_name'] === $selectedType->type_name) {
-                    $matchingData['matching_score'] = $recommendation['confidence'];
+                $typeName = $recommendation['type_name'] ?? '';
+                $confidence = $recommendation['confidence'] ?? 0.5;
+                $reason = $recommendation['reason'] ?? '';
+                
+                if ($typeName === $selectedType->type_name) {
+                    $matchingData['matching_score'] = $confidence;
                     $matchingData['is_recommended'] = true;
                     $matchingData['is_recommended'] = true;
-                    $matchingData['recommendation_reason'] = $recommendation['reason'];
+                    $matchingData['recommendation_reason'] = $reason;
                 } else {
                 } else {
-                    $matchingData['matching_score'] = max(0.3, 1 - $recommendation['confidence']);
-                    $matchingData['recommendation_reason'] = "AI推荐: {$recommendation['type_name']}";
+                    $matchingData['matching_score'] = max(0.3, 1 - $confidence);
+                    $matchingData['recommendation_reason'] = "AI推荐: {$typeName}";
                 }
                 }
             }
             }