This commit is contained in:
richarjiang
2025-12-01 17:58:59 +08:00
parent 7ce51409af
commit 5b89a07751
17 changed files with 1094 additions and 43 deletions

View File

@@ -0,0 +1,456 @@
# AI 健康报告接口文档
## 接口概述
生成用户的 AI 健康报告图片接口,基于用户的健康数据(体重、饮食、运动等)生成可视化的健康分析报告图片。
---
## 接口信息
- **接口名称**: 生成 AI 健康报告
- **接口路径**: `/users/ai-report`
- **请求方法**: `POST`
- **认证方式**: JWT Token (Bearer Token)
- **内容类型**: `application/json`
---
## 请求说明
### 请求头 (Headers)
| 参数名 | 类型 | 必填 | 说明 | 示例 |
| ------------- | ------ | ---- | ------------ | ------------------------------------------------ |
| Authorization | string | 是 | JWT 访问令牌 | `Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...` |
| Content-Type | string | 是 | 请求内容类型 | `application/json` |
### 请求体 (Body)
| 参数名 | 类型 | 必填 | 说明 | 示例 |
| ------ | ------ | ---- | ------------------------------------------------------------- | -------------- |
| date | string | 否 | 指定生成报告的日期,格式 YYYY-MM-DD。不传则默认生成今天的报告 | `"2024-01-15"` |
### 请求示例
#### 示例 1: 生成今天的报告
```bash
curl -X POST 'https://api.example.com/users/ai-report' \
-H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...' \
-H 'Content-Type: application/json' \
-d '{}'
```
#### 示例 2: 生成指定日期的报告
```bash
curl -X POST 'https://api.example.com/users/ai-report' \
-H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...' \
-H 'Content-Type: application/json' \
-d '{
"date": "2024-01-15"
}'
```
#### JavaScript/TypeScript 示例
```typescript
// 使用 fetch
async function generateHealthReport(date?: string) {
const response = await fetch("https://api.example.com/users/ai-report", {
method: "POST",
headers: {
Authorization: `Bearer ${accessToken}`,
"Content-Type": "application/json",
},
body: JSON.stringify(date ? { date } : {}),
});
const result = await response.json();
return result;
}
// 使用 axios
import axios from "axios";
async function generateHealthReport(date?: string) {
const response = await axios.post(
"https://api.example.com/users/ai-report",
date ? { date } : {},
{
headers: {
Authorization: `Bearer ${accessToken}`,
},
}
);
return response.data;
}
```
#### Swift 示例
```swift
func generateHealthReport(date: String? = nil, completion: @escaping (Result<HealthReportResponse, Error>) -> Void) {
let url = URL(string: "https://api.example.com/users/ai-report")!
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.setValue("Bearer \(accessToken)", forHTTPHeaderField: "Authorization")
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
var body: [String: Any] = [:]
if let date = date {
body["date"] = date
}
if !body.isEmpty {
request.httpBody = try? JSONSerialization.data(withJSONObject: body)
}
URLSession.shared.dataTask(with: request) { data, response, error in
if let error = error {
completion(.failure(error))
return
}
guard let data = data else {
completion(.failure(NSError(domain: "", code: -1, userInfo: nil)))
return
}
do {
let decoder = JSONDecoder()
let result = try decoder.decode(HealthReportResponse.self, from: data)
completion(.success(result))
} catch {
completion(.failure(error))
}
}.resume()
}
// 响应模型
struct HealthReportResponse: Codable {
let code: Int
let message: String
let data: HealthReportData
}
struct HealthReportData: Codable {
let imageUrl: String
}
```
---
## 响应说明
### 响应格式
所有响应都遵循统一的响应格式:
```typescript
{
code: number; // 响应码: 0-成功, 1-失败
message: string; // 响应消息
data: {
imageUrl: string; // 生成的报告图片 URL
}
}
```
### 成功响应
**HTTP 状态码**: `200 OK`
**响应体示例**:
```json
{
"code": 0,
"message": "AI健康报告生成成功",
"data": {
"imageUrl": "https://pilates-1234567890.cos.ap-guangzhou.myqcloud.com/health-reports/user-123/2024-01-15/report-xxxxx.png"
}
}
```
**字段说明**:
| 字段 | 类型 | 说明 |
| ------------- | ------ | -------------------------------------------- |
| code | number | 响应码0 表示成功 |
| message | string | 响应消息,成功时为 "AI健康报告生成成功" |
| data.imageUrl | string | 生成的健康报告图片完整 URL可直接访问和下载 |
### 失败响应
**HTTP 状态码**: `200 OK` (业务失败也返回 200通过 code 字段判断)
**响应体示例**:
```json
{
"code": 1,
"message": "生成失败: 用户健康数据不足",
"data": {
"imageUrl": ""
}
}
```
**常见错误消息**:
| 错误消息 | 说明 | 解决方案 |
| ----------------------------- | ------------------------------ | ---------------------------------------------- |
| `生成失败: 用户健康数据不足` | 用户没有足够的健康数据生成报告 | 引导用户添加更多健康数据(体重、饮食、运动等) |
| `生成失败: 日期格式不正确` | date 参数格式错误 | 确保日期格式为 YYYY-MM-DD |
| `生成失败: 未找到用户信息` | 用户不存在或 Token 无效 | 检查认证 Token 是否有效 |
| `生成失败: AI 服务暂时不可用` | AI 模型服务异常 | 稍后重试 |
### 认证失败响应
**HTTP 状态码**: `401 Unauthorized`
**响应体示例**:
```json
{
"statusCode": 401,
"message": "Unauthorized"
}
```
---
## 业务逻辑说明
### 报告内容
AI 健康报告会基于用户的以下数据生成:
1. **体重数据**: 当天或最近的体重记录
2. **饮食数据**: 当天的饮食记录和营养摄入
3. **运动数据**: 当天的运动记录和卡路里消耗
4. **围度数据**: 身体各部位的围度测量数据
5. **目标进度**: 用户设定的健康目标完成情况
### 报告生成逻辑
- 如果不传 `date` 参数,默认生成今天的报告
- 如果指定日期没有数据,会返回数据不足的提示
- 报告图片为 PNG 格式,尺寸适配移动端展示
- 图片会存储在腾讯云 COS有效期永久或根据策略定期清理
### 缓存策略
- 同一天同一用户的报告会缓存,重复请求会返回相同的图片 URL
- 如果用户更新了当天的数据,可以重新生成覆盖旧报告
---
## 错误处理
### 客户端错误处理示例
```typescript
async function fetchHealthReport(date?: string) {
try {
const response = await fetch("https://api.example.com/users/ai-report", {
method: "POST",
headers: {
Authorization: `Bearer ${accessToken}`,
"Content-Type": "application/json",
},
body: JSON.stringify(date ? { date } : {}),
});
// 检查 HTTP 状态码
if (response.status === 401) {
// Token 失效,需要重新登录
throw new Error("认证失败,请重新登录");
}
const result = await response.json();
// 检查业务状态码
if (result.code !== 0) {
// 业务失败
throw new Error(result.message);
}
// 成功,返回图片 URL
return result.data.imageUrl;
} catch (error) {
console.error("生成健康报告失败:", error);
throw error;
}
}
// 使用示例
try {
const imageUrl = await fetchHealthReport();
console.log("报告生成成功:", imageUrl);
// 在 UI 中展示图片
} catch (error) {
// 向用户展示错误提示
alert(error.message);
}
```
---
## 使用建议
### 1. 前置检查
在调用接口前,建议先检查:
- 用户是否已登录(有有效的 JWT Token
- 用户是否有足够的健康数据(可通过其他接口查询)
- 网络连接是否正常
### 2. 加载提示
由于报告生成需要调用 AI 服务,可能需要几秒钟时间,建议:
- 显示加载动画或进度提示
- 设置合理的超时时间(建议 30-60 秒)
- 提供取消操作的选项
### 3. 图片展示
获取到图片 URL 后:
- 可以直接在 Image 组件中使用该 URL
- 支持下载保存到本地相册
- 支持分享到社交媒体
### 4. 错误处理
- 网络错误:提示用户检查网络连接
- 数据不足:引导用户添加健康数据
- Token 过期:自动刷新 Token 或引导重新登录
---
## 完整示例
### React Native 完整示例
```typescript
import React, { useState } from 'react';
import { View, Image, Button, Text, ActivityIndicator } from 'react-native';
import axios from 'axios';
const HealthReportScreen = () => {
const [loading, setLoading] = useState(false);
const [imageUrl, setImageUrl] = useState<string | null>(null);
const [error, setError] = useState<string | null>(null);
const generateReport = async (date?: string) => {
setLoading(true);
setError(null);
try {
const response = await axios.post(
'https://api.example.com/users/ai-report',
date ? { date } : {},
{
headers: {
'Authorization': `Bearer ${accessToken}`,
},
timeout: 60000, // 60秒超时
}
);
if (response.data.code === 0) {
setImageUrl(response.data.data.imageUrl);
} else {
setError(response.data.message);
}
} catch (err) {
if (axios.isAxiosError(err)) {
if (err.response?.status === 401) {
setError('登录已过期,请重新登录');
} else if (err.code === 'ECONNABORTED') {
setError('请求超时,请检查网络连接');
} else {
setError(err.response?.data?.message || '生成报告失败');
}
} else {
setError('未知错误');
}
} finally {
setLoading(false);
}
};
return (
<View style={{ flex: 1, padding: 20 }}>
<Button
title="生成今天的健康报告"
onPressed={() => generateReport()}
disabled={loading}
/>
{loading && (
<View style={{ marginTop: 20, alignItems: 'center' }}>
<ActivityIndicator size="large" />
<Text style={{ marginTop: 10 }}>正在生成报告...</Text>
</View>
)}
{error && (
<Text style={{ color: 'red', marginTop: 20 }}>
{error}
</Text>
)}
{imageUrl && (
<Image
source={{ uri: imageUrl }}
style={{ width: '100%', height: 400, marginTop: 20 }}
resizeMode="contain"
/>
)}
</View>
);
};
export default HealthReportScreen;
```
---
## 注意事项
1. **认证要求**: 必须携带有效的 JWT Token否则返回 401
2. **请求频率**: 建议不要频繁调用,同一用户同一天建议缓存结果
3. **图片有效期**: 图片 URL 长期有效,可以缓存在客户端
4. **数据依赖**: 需要用户有足够的健康数据才能生成有意义的报告
5. **网络要求**: AI 报告生成需要调用外部服务,需要稳定的网络连接
6. **超时设置**: 建议设置 30-60 秒的请求超时时间
---
## 相关接口
- [用户信息接口](./API-USER-INFO.md)
- [体重记录接口](./API-WEIGHT-RECORDS.md)
- [饮食记录接口](./API-DIET-RECORDS.md)
- [运动记录接口](./API-WORKOUT-RECORDS.md)
---
## 更新日志
| 版本 | 日期 | 更新内容 |
| ---- | ---------- | ------------------------------ |
| v1.0 | 2024-01-15 | 初始版本,支持基础健康报告生成 |
---
## 技术支持
如有问题,请联系技术支持团队。