|
@@ -542,18 +542,34 @@ class AiMeasurement extends Api
|
|
|
// $result = [
|
|
|
// 'measurements' => $measurements,
|
|
|
// 'confidence' => $measurements['_confidence'] ?? 0.8,
|
|
|
- // 'warnings' => $measurements['_warnings'] ?? []
|
|
|
+ // 'warnings' => $measurements['warnings'] ?? []
|
|
|
// ];
|
|
|
|
|
|
// 清理内部字段
|
|
|
// unset($result['measurements']['_confidence']);
|
|
|
- // unset($result['measurements']['_warnings']);
|
|
|
+ // unset($result['measurements']['warnings']);
|
|
|
|
|
|
// 格式化结果用于展示
|
|
|
//$formattedResult = $this->formatMeasurementResult($result, $params['profile_id']);
|
|
|
$measurements['height'] = $profile->height;
|
|
|
$measurements['weight'] = $profile->weight;
|
|
|
- $this->success('AI测量完成', $measurements);
|
|
|
+
|
|
|
+ // 检查是否有错误状态
|
|
|
+ $hasErrors = isset($measurements['warnings']) && !empty($measurements['warnings']);
|
|
|
+ $state = $measurements['_state'] ?? 0;
|
|
|
+ $message = $measurements['_message'] ?? 'AI测量完成';
|
|
|
+
|
|
|
+ // 构建返回数据
|
|
|
+ $responseData = $measurements;
|
|
|
+
|
|
|
+ // 根据状态和错误情况返回不同的消息
|
|
|
+ if ($state === 0 && !$hasErrors) {
|
|
|
+ $this->success('AI测量完成', $responseData);
|
|
|
+ } else {
|
|
|
+ // 有错误直接返回错误状态
|
|
|
+ $errorMsg = $hasErrors ? implode(', ', $measurements['warnings']) : $message;
|
|
|
+ $this->error($errorMsg, $responseData);
|
|
|
+ }
|
|
|
|
|
|
// } catch (\Exception $e) {
|
|
|
// $this->error($e->getMessage());
|
|
@@ -631,15 +647,8 @@ class AiMeasurement extends Api
|
|
|
throw new \Exception('请求第三方AI服务失败: ' . $error);
|
|
|
}
|
|
|
|
|
|
- // 处理各种HTTP错误状态
|
|
|
- if ($httpCode >= 500) {
|
|
|
- throw new \Exception('第三方AI服务内部错误: HTTP ' . $httpCode);
|
|
|
- } elseif ($httpCode >= 400) {
|
|
|
- throw new \Exception('第三方AI服务请求错误: HTTP ' . $httpCode);
|
|
|
- } elseif ($httpCode !== 200) {
|
|
|
- throw new \Exception('第三方AI服务返回异常状态: HTTP ' . $httpCode);
|
|
|
- }
|
|
|
\think\Log::info('Third party AI service response: ' .$response);
|
|
|
+
|
|
|
// 检查响应内容
|
|
|
if (empty($response)) {
|
|
|
throw new \Exception('第三方AI服务返回空响应');
|
|
@@ -647,7 +656,32 @@ class AiMeasurement extends Api
|
|
|
|
|
|
$result = json_decode($response, true);
|
|
|
if (json_last_error() !== JSON_ERROR_NONE) {
|
|
|
- throw new \Exception('第三方AI服务返回数据格式错误');
|
|
|
+ // 对于非200状态码,尝试返回原始响应内容作为错误信息
|
|
|
+ if ($httpCode !== 200) {
|
|
|
+ throw new \Exception("第三方AI服务返回异常(HTTP {$httpCode}): " . substr($response, 0, 200));
|
|
|
+ } else {
|
|
|
+ throw new \Exception('第三方AI服务返回数据格式错误');
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 处理各种HTTP错误状态,但先检查是否有有效的JSON响应
|
|
|
+ if ($httpCode !== 200) {
|
|
|
+ // 如果返回了JSON格式的错误信息,优先使用
|
|
|
+ if (isset($result['state']) && $result['state'] == 201) {
|
|
|
+ // 传参错误,通过processMeasurementData处理
|
|
|
+ return $this->processMeasurementData($result);
|
|
|
+ } elseif (isset($result['message'])) {
|
|
|
+ throw new \Exception("第三方AI服务错误(HTTP {$httpCode}): " . $result['message']);
|
|
|
+ } else {
|
|
|
+ // 传统的HTTP错误处理
|
|
|
+ if ($httpCode >= 500) {
|
|
|
+ throw new \Exception('第三方AI服务内部错误: HTTP ' . $httpCode);
|
|
|
+ } elseif ($httpCode >= 400) {
|
|
|
+ throw new \Exception('第三方AI服务请求错误: HTTP ' . $httpCode);
|
|
|
+ } else {
|
|
|
+ throw new \Exception('第三方AI服务返回异常状态: HTTP ' . $httpCode);
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
// 记录API响应信息
|
|
@@ -719,11 +753,42 @@ class AiMeasurement extends Api
|
|
|
'waist_lower'=>'', // 净小腹围 → 下腰围
|
|
|
'mid_waist'=>'', // 净中腰 → 中腰围
|
|
|
'_confidence' => 0.0,
|
|
|
- '_warnings' => ['第三方AI服务暂时不可用,返回默认数据']
|
|
|
+ 'warnings' => ['第三方AI服务暂时不可用,返回默认数据']
|
|
|
];
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
+ * 根据状态码获取错误信息
|
|
|
+ */
|
|
|
+ private function getStateErrorMessage($state)
|
|
|
+ {
|
|
|
+ $stateMessages = [
|
|
|
+ 1 => '颈围计算异常',
|
|
|
+ 2 => '腰围计算异常',
|
|
|
+ 3 => '大腿围计算异常',
|
|
|
+ 4 => '膝盖围计算异常',
|
|
|
+ 5 => '胸围计算异常',
|
|
|
+ 6 => '小腿围计算异常',
|
|
|
+ 7 => '肚围计算异常',
|
|
|
+ 8 => '臀围计算异常',
|
|
|
+ 9 => '手臂长计算异常',
|
|
|
+ 10 => '手腕围计算异常',
|
|
|
+ 11 => '腿长计算异常、裤长计算异常、内腿长计算异常',
|
|
|
+ 12 => '肩宽计算异常',
|
|
|
+ 13 => '脚踝计算异常',
|
|
|
+ 14 => '中腰计算异常',
|
|
|
+ 15 => '小腹围计算异常',
|
|
|
+ 16 => '上臂围计算异常',
|
|
|
+ 101 => '图片1提取尺寸异常',
|
|
|
+ 102 => '图片2提取尺寸异常',
|
|
|
+ 103 => '图片3提取尺寸异常',
|
|
|
+ 201 => '传参错误'
|
|
|
+ ];
|
|
|
+
|
|
|
+ return $stateMessages[$state] ?? "未知错误(状态码: {$state})";
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
* 测试接口 - 返回模拟的第三方API测量数据
|
|
|
* @ApiMethod (POST)
|
|
|
* @ApiParams (name="profile_id", type="integer", required=true, description="档案ID")
|
|
@@ -767,7 +832,11 @@ class AiMeasurement extends Api
|
|
|
"yaowei" => 72.93800974219818,
|
|
|
"zhongyao" => 70.99945416888724
|
|
|
],
|
|
|
- "confidence" => 0.85
|
|
|
+ "image1" => "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAIBAQEBAQIBAQECAgICAgQDAgICAgUEBAME",
|
|
|
+ "image2" => "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAIBAQEBAQIBAQECAgICAgQDAgICAgUEBAME",
|
|
|
+ "image3" => "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAIBAQEBAQIBAQECAgICAgQDAgICAgUEBAME",
|
|
|
+ "message" => "sucessed",
|
|
|
+ "state" => 0
|
|
|
];
|
|
|
|
|
|
// 处理测量数据
|
|
@@ -777,22 +846,119 @@ class AiMeasurement extends Api
|
|
|
$result = [
|
|
|
'measurements' => $measurements,
|
|
|
'confidence' => $measurements['_confidence'] ?? 0.8,
|
|
|
- 'warnings' => $measurements['_warnings'] ?? []
|
|
|
+ 'warnings' => $measurements['warnings'] ?? []
|
|
|
];
|
|
|
|
|
|
// 清理内部字段
|
|
|
unset($result['measurements']['_confidence']);
|
|
|
- unset($result['measurements']['_warnings']);
|
|
|
+ unset($result['measurements']['warnings']);
|
|
|
|
|
|
// 格式化结果用于展示
|
|
|
$formattedResult = $this->formatMeasurementResult($result, $params['profile_id']);
|
|
|
|
|
|
$this->success('测试数据返回成功', [
|
|
|
- 'original_api_data' => $mockApiResult['body_size'],
|
|
|
+ 'original_api_data' => $mockApiResult,
|
|
|
'mapped_measurements' => $result['measurements'],
|
|
|
'formatted_result' => $formattedResult
|
|
|
]);
|
|
|
}
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 测试错误状态处理 - 返回不同错误状态的模拟数据
|
|
|
+ * @ApiMethod (POST)
|
|
|
+ * @ApiParams (name="profile_id", type="integer", required=true, description="档案ID")
|
|
|
+ * @ApiParams (name="test_state", type="integer", required=false, description="测试状态码(1-16, 101-103, 201)")
|
|
|
+ */
|
|
|
+ public function testErrorStates()
|
|
|
+ {
|
|
|
+ $params = $this->request->post();
|
|
|
+
|
|
|
+ // 验证必要参数
|
|
|
+ if (empty($params['profile_id'])) {
|
|
|
+ $this->error('档案ID不能为空');
|
|
|
+ }
|
|
|
+
|
|
|
+ // 验证档案归属
|
|
|
+ $profile = \app\common\model\BodyProfile::where('id', $params['profile_id'])
|
|
|
+ ->where('user_id', $this->auth->id)
|
|
|
+ ->find();
|
|
|
+
|
|
|
+ if (!$profile) {
|
|
|
+ $this->error('档案不存在');
|
|
|
+ }
|
|
|
+
|
|
|
+ // 获取测试状态码
|
|
|
+ $testState = intval($params['test_state'] ?? 1);
|
|
|
+
|
|
|
+ // 模拟不同错误状态的API返回
|
|
|
+ $mockApiResults = [
|
|
|
+ // 部位计算异常(1-16)
|
|
|
+ 1 => [
|
|
|
+ "body_size" => [],
|
|
|
+ "image1" => "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAIBAQEBAQIBAQECAgICAgQDAgICAgUEBAME",
|
|
|
+ "image2" => "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAIBAQEBAQIBAQECAgICAgQDAgICAgUEBAME",
|
|
|
+ "image3" => "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAIBAQEBAQIBAQECAgICAgQDAgICAgUEBAME",
|
|
|
+ "message" => "neck calculation error",
|
|
|
+ "state" => 1
|
|
|
+ ],
|
|
|
+ 5 => [
|
|
|
+ "body_size" => [
|
|
|
+ "yaowei" => 72.93800974219818,
|
|
|
+ "tunwei" => 90.08082593388505
|
|
|
+ ],
|
|
|
+ "image1" => "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAIBAQEBAQIBAQECAgICAgQDAgICAgUEBAME",
|
|
|
+ "message" => "chest calculation error",
|
|
|
+ "state" => 5
|
|
|
+ ],
|
|
|
+ // 图片提取异常(101-103)
|
|
|
+ 101 => [
|
|
|
+ "body_size" => [],
|
|
|
+ "message" => "image1 size extraction error",
|
|
|
+ "state" => 101
|
|
|
+ ],
|
|
|
+ // 传参错误(201)
|
|
|
+ 201 => [
|
|
|
+ "body_size" => [],
|
|
|
+ "message" => "parameter error",
|
|
|
+ "state" => 201
|
|
|
+ ]
|
|
|
+ ];
|
|
|
+
|
|
|
+ // 获取对应的模拟数据,如果没有则使用默认的状态1
|
|
|
+ $mockApiResult = $mockApiResults[$testState] ?? $mockApiResults[1];
|
|
|
+ $mockApiResult['state'] = $testState; // 确保状态码正确
|
|
|
+
|
|
|
+ try {
|
|
|
+ // 处理测量数据
|
|
|
+ $measurements = $this->processMeasurementData($mockApiResult);
|
|
|
+
|
|
|
+ $testData = [
|
|
|
+ 'test_state' => $testState,
|
|
|
+ 'error_message' => $this->getStateErrorMessage($testState),
|
|
|
+ 'mock_api_result' => $mockApiResult,
|
|
|
+ 'processed_measurements' => $measurements
|
|
|
+ ];
|
|
|
+
|
|
|
+ // 检查是否有错误状态
|
|
|
+ $hasErrors = isset($measurements['warnings']) && !empty($measurements['warnings']);
|
|
|
+ $state = $measurements['_state'] ?? 0;
|
|
|
+
|
|
|
+ if ($state === 0 && !$hasErrors) {
|
|
|
+ $this->success('错误状态测试成功', $testData);
|
|
|
+ } else {
|
|
|
+ // 有错误直接返回错误状态
|
|
|
+ $errorMsg = $this->getStateErrorMessage($testState);
|
|
|
+ $this->error($errorMsg, $testData);
|
|
|
+ }
|
|
|
+
|
|
|
+ } catch (\Exception $e) {
|
|
|
+ // 对于201状态(传参错误),会抛出异常
|
|
|
+ $this->error('测试异常: ' . $e->getMessage(), [
|
|
|
+ 'test_state' => $testState,
|
|
|
+ 'mock_api_result' => $mockApiResult
|
|
|
+ ]);
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
/**
|
|
|
* 将图片URL转换为base64格式
|
|
@@ -886,24 +1052,35 @@ class AiMeasurement extends Api
|
|
|
*/
|
|
|
private function processMeasurementData($apiResult)
|
|
|
{
|
|
|
- // 根据第三方API的返回格式处理数据
|
|
|
- // 这里需要根据实际的API返回格式进行调整
|
|
|
-
|
|
|
$measurements = [];
|
|
|
|
|
|
try {
|
|
|
- // 假设API返回格式类似:
|
|
|
- // {
|
|
|
- // "status": "success",
|
|
|
- // "data": {
|
|
|
- // "chest": 95.5,
|
|
|
- // "waist": 75.2,
|
|
|
- // "hip": 98.7,
|
|
|
- // ...
|
|
|
- // },
|
|
|
- // "confidence": 0.85
|
|
|
- // }
|
|
|
+ // 首先检查是否有state字段(错误状态码)
|
|
|
+ if (isset($apiResult['state'])) {
|
|
|
+ $state = intval($apiResult['state']);
|
|
|
+
|
|
|
+ // state=0为正常,其他为异常
|
|
|
+ if ($state !== 0) {
|
|
|
+ $errorMsg = $this->getStateErrorMessage($state);
|
|
|
+
|
|
|
+ // 如果是严重错误(传参错误),直接抛出异常
|
|
|
+ if ($state == 201) {
|
|
|
+ throw new \Exception($errorMsg);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 对于部位计算异常或图片提取异常,返回部分数据和警告
|
|
|
+ $measurements = $this->getDefaultMeasurementData();
|
|
|
+ $measurements['_confidence'] = 0.3; // 低置信度
|
|
|
+ $measurements['warnings'] = [$errorMsg];
|
|
|
+ $measurements['_state'] = $state;
|
|
|
+ $measurements['_message'] = $apiResult['message'] ?? '';
|
|
|
+
|
|
|
+
|
|
|
+ return $measurements;
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
+ // state=0 或没有state字段,处理正常数据
|
|
|
// 检查返回数据结构 - 可能直接包含body_size字段
|
|
|
if (isset($apiResult['body_size'])) {
|
|
|
$data = $apiResult['body_size'];
|
|
@@ -948,11 +1125,13 @@ class AiMeasurement extends Api
|
|
|
|
|
|
// 设置置信度和警告信息
|
|
|
$measurements['_confidence'] = $apiResult['confidence'] ?? 0.8;
|
|
|
- $measurements['_warnings'] = $apiResult['warnings'] ?? [];
|
|
|
+ $measurements['warnings'] = $apiResult['warnings'] ?? [];
|
|
|
+ $measurements['_state'] = isset($apiResult['state']) ? intval($apiResult['state']) : 0;
|
|
|
+ $measurements['_message'] = $apiResult['message'] ?? 'sucessed';
|
|
|
|
|
|
// 如果没有测量数据,添加默认警告
|
|
|
- if (count($measurements) === 2) { // 只有_confidence和_warnings
|
|
|
- $measurements['_warnings'][] = '第三方AI服务未返回有效的测量数据';
|
|
|
+ if (count($measurements) <= 4) { // 只有_confidence, warnings, _state, _message
|
|
|
+ $measurements['warnings'][] = '第三方AI服务未返回有效的测量数据';
|
|
|
}
|
|
|
|
|
|
} else {
|
|
@@ -964,7 +1143,7 @@ class AiMeasurement extends Api
|
|
|
} catch (\Exception $e) {
|
|
|
// 处理异常,返回错误信息
|
|
|
$measurements['_confidence'] = 0;
|
|
|
- $measurements['_warnings'] = ['数据处理失败: ' . $e->getMessage()];
|
|
|
+ $measurements['warnings'] = ['数据处理失败: ' . $e->getMessage()];
|
|
|
}
|
|
|
|
|
|
return $measurements;
|
|
@@ -1002,12 +1181,12 @@ class AiMeasurement extends Api
|
|
|
$result = [
|
|
|
'measurements' => $measurements,
|
|
|
'confidence' => $measurements['_confidence'] ?? 0.8,
|
|
|
- 'warnings' => $measurements['_warnings'] ?? []
|
|
|
+ 'warnings' => $measurements['warnings'] ?? []
|
|
|
];
|
|
|
|
|
|
// 清理内部字段
|
|
|
unset($result['measurements']['_confidence']);
|
|
|
- unset($result['measurements']['_warnings']);
|
|
|
+ unset($result['measurements']['warnings']);
|
|
|
|
|
|
// 更新任务状态为完成
|
|
|
\think\Db::table('fa_ai_measurement_task')
|