fix: 修复AI分类统计数值溢出问题
问题:成功分类数显示18446744073709552(接近u64最大值) 原因:错误地用分类记录总数减去失败任务数,导致负数转u64溢出 修复内容: - 扩展ClassificationStats结构体,添加分类记录状态统计 - 改进数据库查询,正确统计各状态的分类记录数 - 修正ai_analysis_log_service中的统计计算逻辑 - 添加数值安全检查,防止负数转无符号整数 - 更新前端类型定义保持一致性 现在统计数据来源一致且逻辑正确: - 任务统计来自video_classification_tasks表 - 分类记录统计来自video_classification_records表
This commit is contained in:
parent
eb47a2b8fb
commit
82b62a4b0f
|
|
@ -0,0 +1,135 @@
|
|||
# AI分类统计数值溢出问题修复
|
||||
|
||||
## 问题描述
|
||||
|
||||
用户报告AI分析日志显示异常数据:
|
||||
- 总记录数:214(正常)
|
||||
- 成功分类:18446744073709552(异常,接近u64最大值)
|
||||
|
||||
## 问题分析
|
||||
|
||||
### 根本原因
|
||||
在 `ai_analysis_log_service.rs` 中,计算成功分类数的逻辑有误:
|
||||
|
||||
```rust
|
||||
// 错误的计算方式
|
||||
successful_classifications: (classification_stats.total_classifications - classification_stats.failed_tasks) as u64,
|
||||
```
|
||||
|
||||
### 问题详解
|
||||
1. `total_classifications` 是分类记录总数(来自 `video_classification_records` 表)
|
||||
2. `failed_tasks` 是失败的任务数(来自 `video_classification_tasks` 表)
|
||||
3. 这两个数据来源不同,不应该直接相减
|
||||
4. 当 `failed_tasks` > `total_classifications` 时,减法结果为负数
|
||||
5. 负数转换为 `u64` 时会发生溢出,变成接近 `u64::MAX` 的大数
|
||||
|
||||
### 数值分析
|
||||
- `u64::MAX` = 18446744073709551615
|
||||
- 异常值 = 18446744073709552
|
||||
- 差值 = 18446744073709551615 - 18446744073709552 = 63
|
||||
|
||||
这表明原始计算结果是 -63,转换为 u64 后变成了这个大数。
|
||||
|
||||
## 修复方案
|
||||
|
||||
### 1. 扩展 ClassificationStats 结构体
|
||||
添加分类记录状态的详细统计:
|
||||
|
||||
```rust
|
||||
pub struct ClassificationStats {
|
||||
// 原有字段...
|
||||
pub successful_classifications: i32, // 新增:成功分类记录数
|
||||
pub failed_classifications: i32, // 新增:失败分类记录数
|
||||
pub needs_review_classifications: i32, // 新增:需要审核记录数
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 改进数据库查询
|
||||
在 `video_classification_repository.rs` 中添加分类记录状态统计:
|
||||
|
||||
```rust
|
||||
// 获取分类记录状态统计
|
||||
let mut stmt = conn.prepare(&format!(
|
||||
"SELECT
|
||||
SUM(CASE WHEN status = ? THEN 1 ELSE 0 END) as classified,
|
||||
SUM(CASE WHEN status = ? THEN 1 ELSE 0 END) as failed,
|
||||
SUM(CASE WHEN status = ? THEN 1 ELSE 0 END) as needs_review
|
||||
FROM video_classification_records{}", record_where_clause
|
||||
))?;
|
||||
```
|
||||
|
||||
### 3. 修正统计计算逻辑
|
||||
使用正确的数据源计算各项统计:
|
||||
|
||||
```rust
|
||||
Ok(AiAnalysisLogStats {
|
||||
total_records: classification_stats.total_classifications.max(0) as u64,
|
||||
successful_classifications: classification_stats.successful_classifications.max(0) as u64,
|
||||
failed_classifications: classification_stats.failed_classifications.max(0) as u64,
|
||||
needs_review: classification_stats.needs_review_classifications.max(0) as u64,
|
||||
// ...
|
||||
})
|
||||
```
|
||||
|
||||
## 修改文件列表
|
||||
|
||||
### 后端文件
|
||||
1. `apps/desktop/src-tauri/src/data/models/video_classification.rs`
|
||||
- 扩展 `ClassificationStats` 结构体
|
||||
|
||||
2. `apps/desktop/src-tauri/src/data/repositories/video_classification_repository.rs`
|
||||
- 添加分类记录状态统计查询
|
||||
- 更新返回的统计数据
|
||||
|
||||
3. `apps/desktop/src-tauri/src/business/services/ai_analysis_log_service.rs`
|
||||
- 修正成功分类数的计算逻辑
|
||||
- 添加数值安全检查
|
||||
|
||||
### 前端文件
|
||||
1. `apps/desktop/src/types/videoClassification.ts`
|
||||
- 更新 `ClassificationStats` 接口
|
||||
|
||||
2. `apps/desktop/src/store/videoClassificationStore.ts`
|
||||
- 更新 `ClassificationStats` 接口
|
||||
|
||||
## 安全改进
|
||||
|
||||
### 1. 数值溢出防护
|
||||
使用 `.max(0)` 确保不会有负数转换为无符号整数:
|
||||
|
||||
```rust
|
||||
classification_stats.successful_classifications.max(0) as u64
|
||||
```
|
||||
|
||||
### 2. 数据一致性
|
||||
确保统计数据来源一致:
|
||||
- 任务相关统计来自 `video_classification_tasks` 表
|
||||
- 分类记录相关统计来自 `video_classification_records` 表
|
||||
|
||||
### 3. 类型安全
|
||||
明确区分有符号和无符号整数的使用场景。
|
||||
|
||||
## 测试建议
|
||||
|
||||
1. **边界测试**:测试没有分类记录的项目
|
||||
2. **数据一致性测试**:验证各项统计数据的逻辑关系
|
||||
3. **大数据测试**:测试大量分类记录的性能和准确性
|
||||
4. **异常数据测试**:测试数据库中存在异常状态的记录
|
||||
|
||||
## 预期结果
|
||||
|
||||
修复后,AI分析统计应该显示:
|
||||
- 总记录数:214
|
||||
- 成功分类:实际成功分类的记录数(≤ 214)
|
||||
- 失败分类:实际失败分类的记录数
|
||||
- 需要审核:需要人工审核的记录数
|
||||
|
||||
所有数值应该在合理范围内,且满足逻辑关系:
|
||||
`成功分类 + 失败分类 + 需要审核 = 总记录数`
|
||||
|
||||
## 后续优化
|
||||
|
||||
1. 添加数据一致性检查
|
||||
2. 实现24小时活动统计
|
||||
3. 添加更详细的错误日志
|
||||
4. 考虑添加数据库索引优化查询性能
|
||||
|
|
@ -265,14 +265,14 @@ impl AiAnalysisLogService {
|
|||
let recent_24h_activity = 0; // TODO: 实现24小时内的活动统计
|
||||
|
||||
Ok(AiAnalysisLogStats {
|
||||
total_records: classification_stats.total_classifications as u64,
|
||||
successful_classifications: (classification_stats.total_classifications - classification_stats.failed_tasks) as u64,
|
||||
failed_classifications: classification_stats.failed_tasks as u64,
|
||||
needs_review: 0, // TODO: 从数据库查询需要审核的数量
|
||||
total_tasks: classification_stats.total_tasks as u64,
|
||||
completed_tasks: classification_stats.completed_tasks as u64,
|
||||
failed_tasks: classification_stats.failed_tasks as u64,
|
||||
processing_tasks: classification_stats.processing_tasks as u64,
|
||||
total_records: classification_stats.total_classifications.max(0) as u64,
|
||||
successful_classifications: classification_stats.successful_classifications.max(0) as u64,
|
||||
failed_classifications: classification_stats.failed_classifications.max(0) as u64,
|
||||
needs_review: classification_stats.needs_review_classifications.max(0) as u64,
|
||||
total_tasks: classification_stats.total_tasks.max(0) as u64,
|
||||
completed_tasks: classification_stats.completed_tasks.max(0) as u64,
|
||||
failed_tasks: classification_stats.failed_tasks.max(0) as u64,
|
||||
processing_tasks: classification_stats.processing_tasks.max(0) as u64,
|
||||
average_confidence: classification_stats.average_confidence,
|
||||
average_quality_score: classification_stats.average_quality_score,
|
||||
recent_24h_activity,
|
||||
|
|
|
|||
|
|
@ -175,6 +175,12 @@ pub struct ClassificationStats {
|
|||
pub failed_tasks: i32,
|
||||
/// 总分类记录数
|
||||
pub total_classifications: i32,
|
||||
/// 成功分类记录数
|
||||
pub successful_classifications: i32,
|
||||
/// 失败分类记录数
|
||||
pub failed_classifications: i32,
|
||||
/// 需要审核记录数
|
||||
pub needs_review_classifications: i32,
|
||||
/// 平均置信度
|
||||
pub average_confidence: f64,
|
||||
/// 平均质量评分
|
||||
|
|
|
|||
|
|
@ -536,6 +536,27 @@ impl VideoClassificationRepository {
|
|||
))
|
||||
})?;
|
||||
|
||||
// 获取分类记录状态统计
|
||||
let mut stmt = conn.prepare(&format!(
|
||||
"SELECT
|
||||
SUM(CASE WHEN status = ? THEN 1 ELSE 0 END) as classified,
|
||||
SUM(CASE WHEN status = ? THEN 1 ELSE 0 END) as failed,
|
||||
SUM(CASE WHEN status = ? THEN 1 ELSE 0 END) as needs_review
|
||||
FROM video_classification_records{}", record_where_clause
|
||||
))?;
|
||||
|
||||
let classified_json = serde_json::to_string(&ClassificationStatus::Classified).unwrap();
|
||||
let failed_json = serde_json::to_string(&ClassificationStatus::Failed).unwrap();
|
||||
let needs_review_json = serde_json::to_string(&ClassificationStatus::NeedsReview).unwrap();
|
||||
|
||||
let record_status_stats = stmt.query_row([&classified_json, &failed_json, &needs_review_json], |row| {
|
||||
Ok((
|
||||
row.get::<_, Option<i32>>(0)?.unwrap_or(0),
|
||||
row.get::<_, Option<i32>>(1)?.unwrap_or(0),
|
||||
row.get::<_, Option<i32>>(2)?.unwrap_or(0),
|
||||
))
|
||||
})?;
|
||||
|
||||
Ok(ClassificationStats {
|
||||
total_tasks: task_stats.0,
|
||||
pending_tasks: task_stats.1,
|
||||
|
|
@ -543,6 +564,9 @@ impl VideoClassificationRepository {
|
|||
completed_tasks: task_stats.3,
|
||||
failed_tasks: task_stats.4,
|
||||
total_classifications: record_stats.0,
|
||||
successful_classifications: record_status_stats.0,
|
||||
failed_classifications: record_status_stats.1,
|
||||
needs_review_classifications: record_status_stats.2,
|
||||
average_confidence: record_stats.1,
|
||||
average_quality_score: record_stats.2,
|
||||
})
|
||||
|
|
|
|||
|
|
@ -60,6 +60,9 @@ export interface ClassificationStats {
|
|||
completed_tasks: number;
|
||||
failed_tasks: number;
|
||||
total_classifications: number;
|
||||
successful_classifications: number;
|
||||
failed_classifications: number;
|
||||
needs_review_classifications: number;
|
||||
average_confidence: number;
|
||||
average_quality_score: number;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -121,7 +121,10 @@ export interface ClassificationStats {
|
|||
completed_tasks: number;
|
||||
failed_tasks: number;
|
||||
total_classifications: number;
|
||||
average_confidence_score: number;
|
||||
successful_classifications: number;
|
||||
failed_classifications: number;
|
||||
needs_review_classifications: number;
|
||||
average_confidence: number;
|
||||
average_quality_score: number;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue