codenuk_backend_mine/services/template-manager/src/routes/learning.js

324 lines
10 KiB
JavaScript

const express = require('express');
const router = express.Router();
const database = require('../config/database');
const Feature = require('../models/feature');
const Template = require('../models/template');
// POST /api/learning/feature-selected - Track feature selection for learning
router.post('/feature-selected', async (req, res) => {
try {
const { template_id, feature_id, user_session, project_id } = req.body;
console.log(`🧠 Learning: Feature selected - ${feature_id} for template ${template_id}`);
// Validate required fields
if (!template_id || !feature_id) {
return res.status(400).json({
success: false,
error: 'Missing required fields',
message: 'template_id and feature_id are required'
});
}
// Record the selection
const query = `
INSERT INTO feature_usage (template_id, feature_id, user_session, project_id)
VALUES ($1, $2, $3, $4)
RETURNING *
`;
const result = await database.query(query, [template_id, feature_id, user_session, project_id]);
// Update feature usage count
const updateQuery = `
UPDATE template_features
SET usage_count = usage_count + 1
WHERE id = $1
`;
await database.query(updateQuery, [feature_id]);
res.json({
success: true,
data: result.rows[0],
message: 'Feature selection recorded for learning system'
});
} catch (error) {
console.error('❌ Error recording feature selection:', error.message);
res.status(500).json({
success: false,
error: 'Failed to record feature selection',
message: error.message
});
}
});
// GET /api/learning/recommendations/:templateId - Get AI-powered recommendations
router.get('/recommendations/:templateId', async (req, res) => {
try {
const { templateId } = req.params;
const limit = parseInt(req.query.limit) || 5;
console.log(`🤖 Generating recommendations for template: ${templateId}`);
// Get template info
const template = await Template.getByIdWithFeatures(templateId);
if (!template) {
return res.status(404).json({
success: false,
error: 'Template not found',
message: `Template with ID ${templateId} does not exist`
});
}
// Get popular features from similar templates (same category)
const similarFeaturesQuery = `
SELECT
tf.*,
t.title as template_title,
t.type as template_type
FROM template_features tf
JOIN templates t ON tf.template_id = t.id
WHERE t.category = (
SELECT category FROM templates WHERE id = $1
)
AND tf.template_id != $1
AND tf.usage_count > 0
ORDER BY tf.usage_count DESC, tf.user_rating DESC
LIMIT $2
`;
const similarFeatures = await database.query(similarFeaturesQuery, [templateId, limit]);
// Get trending features (high recent usage)
const trendingQuery = `
SELECT
tf.*,
t.title as template_title,
COUNT(fu.id) as recent_usage
FROM template_features tf
JOIN templates t ON tf.template_id = t.id
LEFT JOIN feature_usage fu ON tf.id = fu.feature_id
AND fu.selected_at > NOW() - INTERVAL '30 days'
WHERE tf.template_id != $1
GROUP BY tf.id, t.title
HAVING COUNT(fu.id) > 0
ORDER BY recent_usage DESC, tf.user_rating DESC
LIMIT $2
`;
const trendingFeatures = await database.query(trendingQuery, [templateId, limit]);
// Get complementary features (often used together)
const complementaryQuery = `
WITH template_sessions AS (
SELECT DISTINCT user_session
FROM feature_usage
WHERE template_id = $1
AND user_session IS NOT NULL
)
SELECT
tf.*,
t.title as template_title,
COUNT(DISTINCT ts.user_session) as co_occurrence
FROM template_sessions ts
JOIN feature_usage fu ON ts.user_session = fu.user_session
JOIN template_features tf ON fu.feature_id = tf.id
JOIN templates t ON tf.template_id = t.id
WHERE tf.template_id != $1
GROUP BY tf.id, t.title
ORDER BY co_occurrence DESC, tf.user_rating DESC
LIMIT $2
`;
const complementaryFeatures = await database.query(complementaryQuery, [templateId, limit]);
const recommendations = {
similar_features: similarFeatures.rows,
trending_features: trendingFeatures.rows,
complementary_features: complementaryFeatures.rows,
template_info: {
id: template.id,
title: template.title,
category: template.category,
existing_features_count: template.features ? template.features.length : 0
}
};
res.json({
success: true,
data: recommendations,
message: `Generated ${Object.keys(recommendations).length - 1} types of recommendations for ${template.title}`
});
} catch (error) {
console.error('❌ Error generating recommendations:', error.message);
res.status(500).json({
success: false,
error: 'Failed to generate recommendations',
message: error.message
});
}
});
// POST /api/learning/analyze-usage - Analyze usage patterns
router.post('/analyze-usage', async (req, res) => {
try {
const { template_id, time_period = '30 days' } = req.body;
console.log(`📊 Analyzing usage patterns for template: ${template_id || 'all'}`);
let templateFilter = '';
const params = [time_period];
if (template_id) {
templateFilter = 'AND fu.template_id = $2';
params.push(template_id);
}
// Usage trends over time
const trendsQuery = `
SELECT
DATE(fu.selected_at) as date,
COUNT(*) as selections,
COUNT(DISTINCT fu.user_session) as unique_sessions
FROM feature_usage fu
WHERE fu.selected_at > NOW() - INTERVAL '${time_period}'
${templateFilter}
GROUP BY DATE(fu.selected_at)
ORDER BY date DESC
LIMIT 30
`;
// Most popular features
const popularQuery = `
SELECT
tf.name,
tf.feature_type,
tf.complexity,
COUNT(fu.id) as usage_count,
COUNT(DISTINCT fu.user_session) as unique_users,
t.title as template_title
FROM feature_usage fu
JOIN template_features tf ON fu.feature_id = tf.id
JOIN templates t ON fu.template_id = t.id
WHERE fu.selected_at > NOW() - INTERVAL '${time_period}'
${templateFilter}
GROUP BY tf.id, tf.name, tf.feature_type, tf.complexity, t.title
ORDER BY usage_count DESC
LIMIT 20
`;
// Feature type distribution
const distributionQuery = `
SELECT
tf.feature_type,
tf.complexity,
COUNT(fu.id) as selections,
COUNT(DISTINCT fu.user_session) as unique_users
FROM feature_usage fu
JOIN template_features tf ON fu.feature_id = tf.id
WHERE fu.selected_at > NOW() - INTERVAL '${time_period}'
${templateFilter}
GROUP BY tf.feature_type, tf.complexity
ORDER BY selections DESC
`;
const [trendsResult, popularResult, distributionResult] = await Promise.all([
database.query(trendsQuery, params),
database.query(popularQuery, params),
database.query(distributionQuery, params)
]);
const analysis = {
time_period,
template_id: template_id || 'all',
usage_trends: trendsResult.rows,
popular_features: popularResult.rows,
feature_distribution: distributionResult.rows,
summary: {
total_trends: trendsResult.rows.length,
top_features: popularResult.rows.length,
distribution_segments: distributionResult.rows.length
}
};
res.json({
success: true,
data: analysis,
message: `Usage analysis completed for ${time_period} period`
});
} catch (error) {
console.error('❌ Error analyzing usage patterns:', error.message);
res.status(500).json({
success: false,
error: 'Failed to analyze usage patterns',
message: error.message
});
}
});
// GET /api/learning/insights - Get learning system insights
router.get('/insights', async (req, res) => {
try {
console.log('🔍 Gathering learning system insights...');
// Overall statistics
const statsQuery = `
SELECT
COUNT(DISTINCT fu.template_id) as active_templates,
COUNT(DISTINCT fu.feature_id) as features_used,
COUNT(DISTINCT fu.user_session) as unique_sessions,
COUNT(*) as total_selections
FROM feature_usage fu
WHERE fu.selected_at > NOW() - INTERVAL '30 days'
`;
// Growth metrics
const growthQuery = `
SELECT
DATE_TRUNC('week', fu.selected_at) as week,
COUNT(*) as selections,
COUNT(DISTINCT fu.user_session) as users
FROM feature_usage fu
WHERE fu.selected_at > NOW() - INTERVAL '12 weeks'
GROUP BY DATE_TRUNC('week', fu.selected_at)
ORDER BY week DESC
`;
// Learning effectiveness
const effectivenessQuery = `
SELECT
AVG(tf.user_rating) as avg_rating,
SUM(CASE WHEN tf.created_by_user = true THEN 1 ELSE 0 END) as user_contributed_features,
SUM(CASE WHEN tf.is_default = true THEN 1 ELSE 0 END) as default_features
FROM template_features tf
`;
const [statsResult, growthResult, effectivenessResult] = await Promise.all([
database.query(statsQuery),
database.query(growthQuery),
database.query(effectivenessQuery)
]);
const insights = {
overview: statsResult.rows[0],
growth_trends: growthResult.rows,
learning_effectiveness: effectivenessResult.rows[0],
generated_at: new Date().toISOString()
};
res.json({
success: true,
data: insights,
message: 'Learning system insights generated successfully'
});
} catch (error) {
console.error('❌ Error gathering insights:', error.message);
res.status(500).json({
success: false,
error: 'Failed to gather learning insights',
message: error.message
});
}
});
module.exports = router;