Files
aijianhua/backend/routes/identifications.js

355 lines
9.3 KiB
JavaScript
Raw Normal View History

const express = require('express');
const multer = require('multer');
const path = require('path');
const fs = require('fs');
const dbConnector = require('../utils/dbConnector');
const { asyncHandler } = require('../middlewares/errorHandler');
const router = express.Router();
// 配置multer用于文件上传
const storage = multer.diskStorage({
destination: (req, file, cb) => {
const uploadDir = path.join(__dirname, '../uploads/identifications');
// 确保上传目录存在
if (!fs.existsSync(uploadDir)) {
fs.mkdirSync(uploadDir, { recursive: true });
}
cb(null, uploadDir);
},
filename: (req, file, cb) => {
const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1E9);
cb(null, 'identification-' + uniqueSuffix + path.extname(file.originalname));
}
});
const upload = multer({
storage: storage,
limits: {
fileSize: 10 * 1024 * 1024, // 10MB限制
},
fileFilter: (req, file, cb) => {
// 只允许图片文件
if (file.mimetype.startsWith('image/')) {
cb(null, true);
} else {
cb(new Error('只支持图片文件'), false);
}
}
});
/**
* 获取识别历史记录
*/
router.get('/', asyncHandler(async (req, res) => {
const { page = 1, limit = 10 } = req.query;
const userId = req.user.id;
const offset = (page - 1) * limit;
// 查询识别记录
const identifications = await dbConnector.query(
`SELECT
id, user_id, image_url, result, confidence, created_at
FROM identifications
WHERE user_id = ?
ORDER BY created_at DESC
LIMIT ? OFFSET ?`,
[userId, parseInt(limit), offset]
);
// 查询总数
const totalResult = await dbConnector.query(
'SELECT COUNT(*) as total FROM identifications WHERE user_id = ?',
[userId]
);
res.json({
code: 200,
message: '获取成功',
data: {
identifications,
pagination: {
page: parseInt(page),
limit: parseInt(limit),
total: totalResult[0].total,
pages: Math.ceil(totalResult[0].total / limit)
}
}
});
}));
/**
* 获取单条识别记录详情
*/
router.get('/:id', asyncHandler(async (req, res) => {
const { id } = req.params;
const userId = req.user.id;
const identifications = await dbConnector.query(
`SELECT
id, user_id, image_url, result, confidence, created_at
FROM identifications
WHERE id = ? AND user_id = ?`,
[id, userId]
);
if (identifications.length === 0) {
return res.status(404).json({
code: 404,
message: '识别记录不存在',
data: null
});
}
res.json({
code: 200,
message: '获取成功',
data: identifications[0]
});
}));
/**
* 花卉识别接口
*/
router.post('/identify', upload.single('image'), asyncHandler(async (req, res) => {
const userId = req.user.id;
if (!req.file) {
return res.status(400).json({
code: 400,
message: '请上传图片文件',
data: null
});
}
// 这里应该调用AI识别服务
// 由于AI识别服务需要额外配置这里先模拟识别结果
const imageUrl = `/uploads/identifications/${req.file.filename}`;
// 模拟AI识别结果实际项目中应该调用真实的AI服务
const mockResults = [
{ name: '玫瑰', confidence: 0.95, scientificName: 'Rosa rugosa', description: '玫瑰是蔷薇科蔷薇属的植物,具有浓郁的芳香和美丽的花朵。' },
{ name: '百合', confidence: 0.87, scientificName: 'Lilium brownii', description: '百合是百合科百合属的植物,象征纯洁和高雅。' },
{ name: '菊花', confidence: 0.82, scientificName: 'Chrysanthemum morifolium', description: '菊花是菊科菊属的植物,具有很高的观赏和药用价值。' }
];
// 选择置信度最高的结果
const bestResult = mockResults[0];
// 保存识别记录到数据库
const result = await dbConnector.query(
'INSERT INTO identifications (user_id, image_url, result, confidence) VALUES (?, ?, ?, ?)',
[userId, imageUrl, JSON.stringify(mockResults), bestResult.confidence]
);
res.json({
code: 200,
message: '识别成功',
data: {
identification_id: result.insertId,
image_url: imageUrl,
results: mockResults,
best_result: bestResult,
created_at: new Date().toISOString()
}
});
}));
/**
* 批量识别历史记录
*/
router.get('/batch/history', asyncHandler(async (req, res) => {
const { start_date, end_date, min_confidence = 0.7 } = req.query;
const userId = req.user.id;
let whereClause = 'WHERE user_id = ? AND confidence >= ?';
let queryParams = [userId, parseFloat(min_confidence)];
if (start_date) {
whereClause += ' AND created_at >= ?';
queryParams.push(start_date);
}
if (end_date) {
whereClause += ' AND created_at <= ?';
queryParams.push(end_date + ' 23:59:59');
}
const identifications = await dbConnector.query(
`SELECT
id, image_url, result, confidence, created_at,
DATE(created_at) as identify_date
FROM identifications
${whereClause}
ORDER BY created_at DESC`,
queryParams
);
// 按日期分组
const groupedByDate = {};
identifications.forEach(record => {
const date = record.identify_date;
if (!groupedByDate[date]) {
groupedByDate[date] = [];
}
groupedByDate[date].push(record);
});
res.json({
code: 200,
message: '获取成功',
data: {
total: identifications.length,
by_date: groupedByDate,
statistics: {
total_count: identifications.length,
avg_confidence: identifications.reduce((sum, item) => sum + item.confidence, 0) / identifications.length,
date_range: {
start: identifications.length > 0 ? identifications[identifications.length - 1].identify_date : null,
end: identifications.length > 0 ? identifications[0].identify_date : null
}
}
}
});
}));
/**
* 识别统计信息
*/
router.get('/stats/summary', asyncHandler(async (req, res) => {
const userId = req.user.id;
// 总识别次数
const totalCountResult = await dbConnector.query(
'SELECT COUNT(*) as total FROM identifications WHERE user_id = ?',
[userId]
);
// 平均置信度
const avgConfidenceResult = await dbConnector.query(
'SELECT AVG(confidence) as avg_confidence FROM identifications WHERE user_id = ?',
[userId]
);
// 最近识别时间
const lastIdentificationResult = await dbConnector.query(
'SELECT created_at FROM identifications WHERE user_id = ? ORDER BY created_at DESC LIMIT 1',
[userId]
);
// 识别最多的花卉类型需要解析result字段
const allIdentifications = await dbConnector.query(
'SELECT result FROM identifications WHERE user_id = ?',
[userId]
);
const flowerCounts = {};
allIdentifications.forEach(item => {
try {
const results = JSON.parse(item.result);
if (results && results.length > 0) {
const bestResult = results[0];
flowerCounts[bestResult.name] = (flowerCounts[bestResult.name] || 0) + 1;
}
} catch (e) {
console.error('解析识别结果失败:', e);
}
});
// 找出识别最多的花卉
let mostIdentifiedFlower = null;
let maxCount = 0;
for (const [flower, count] of Object.entries(flowerCounts)) {
if (count > maxCount) {
mostIdentifiedFlower = flower;
maxCount = count;
}
}
res.json({
code: 200,
message: '获取成功',
data: {
total_count: totalCountResult[0].total,
avg_confidence: avgConfidenceResult[0].avg_confidence || 0,
last_identification: lastIdentificationResult[0] ? lastIdentificationResult[0].created_at : null,
most_identified_flower: mostIdentifiedFlower,
flower_counts: flowerCounts,
weekly_trend: await getWeeklyTrend(userId)
}
});
}));
/**
* 获取周趋势数据
*/
async function getWeeklyTrend(userId) {
const weeklyData = await dbConnector.query(
`SELECT
DATE(created_at) as date,
COUNT(*) as count,
AVG(confidence) as avg_confidence
FROM identifications
WHERE user_id = ? AND created_at >= DATE_SUB(NOW(), INTERVAL 7 DAY)
GROUP BY DATE(created_at)
ORDER BY date DESC`,
[userId]
);
return weeklyData;
}
/**
* 删除识别记录
*/
router.delete('/:id', asyncHandler(async (req, res) => {
const { id } = req.params;
const userId = req.user.id;
// 先获取记录信息以删除图片文件
const identification = await dbConnector.query(
'SELECT image_url FROM identifications WHERE id = ? AND user_id = ?',
[id, userId]
);
if (identification.length === 0) {
return res.status(404).json({
code: 404,
message: '识别记录不存在',
data: null
});
}
// 删除图片文件
if (identification[0].image_url) {
const imagePath = path.join(__dirname, '../', identification[0].image_url);
if (fs.existsSync(imagePath)) {
fs.unlinkSync(imagePath);
}
}
// 删除数据库记录
const result = await dbConnector.query(
'DELETE FROM identifications WHERE id = ? AND user_id = ?',
[id, userId]
);
if (result.affectedRows === 0) {
return res.status(404).json({
code: 404,
message: '识别记录不存在',
data: null
});
}
res.json({
code: 200,
message: '删除成功',
data: null
});
}));
module.exports = router;