adpa-enterprise-framework-automation
Version:
Modular, standards-compliant Node.js/TypeScript automation framework for enterprise requirements, project, and data management. Provides CLI and API for BABOK v3, PMBOK 7th Edition, and DMBOK 2.0 (in progress). Production-ready Express.js API with TypeSpe
464 lines (454 loc) • 19.3 kB
JavaScript
// Feedback Integration Service
// filepath: src/services/FeedbackIntegrationService.ts
import { DocumentFeedback } from '../models/DocumentFeedback.js';
import { AIProcessor } from '../modules/ai/AIProcessor.js';
import { ConfigurationManager } from '../modules/ai/ConfigurationManager.js';
export class FeedbackIntegrationService {
aiProcessor;
configManager;
constructor() {
this.aiProcessor = AIProcessor.getInstance();
this.configManager = ConfigurationManager.getInstance();
}
/**
* Analyze feedback patterns to generate insights for document improvement
*/
async analyzeFeedbackPatterns(documentType, days = 30) {
try {
const startDate = new Date();
startDate.setDate(startDate.getDate() - days);
// Build filter
const filter = {
submittedAt: { $gte: startDate },
rating: { $lte: 3 } // Focus on lower-rated feedback
};
if (documentType) {
filter.documentType = documentType;
}
// Aggregate feedback data
const insights = await DocumentFeedback.aggregate([
{ $match: filter },
{
$group: {
_id: '$documentType',
totalFeedback: { $sum: 1 },
averageRating: { $avg: '$rating' },
commonIssues: { $push: '$title' },
feedbackTypes: { $push: '$feedbackType' },
suggestions: { $push: '$suggestedImprovement' },
priorities: { $push: '$priority' },
descriptions: { $push: '$description' }
}
},
{ $sort: { totalFeedback: -1 } }
]);
// Process insights
const processedInsights = [];
for (const insight of insights) {
// Analyze common issues
const issueFrequency = this.analyzeTextFrequency(insight.commonIssues);
const commonIssues = Object.entries(issueFrequency)
.sort(([, a], [, b]) => b - a)
.slice(0, 5)
.map(([issue]) => issue);
// Generate prompt improvements using AI
const promptImprovements = await this.generatePromptImprovements(insight._id, insight.descriptions, insight.suggestions);
// Calculate quality trends
const qualityTrends = await this.calculateQualityTrends(insight._id, days);
// Identify priority areas
const priorityAreas = this.identifyPriorityAreas(insight.feedbackTypes, insight.priorities, insight.descriptions);
processedInsights.push({
documentType: insight._id,
commonIssues,
suggestedPromptImprovements: promptImprovements,
qualityTrends,
priorityAreas
});
}
return processedInsights;
}
catch (error) {
console.error('Error analyzing feedback patterns:', error);
throw new Error('Failed to analyze feedback patterns');
}
}
/**
* Generate optimized prompts based on feedback
*/
async optimizePromptFromFeedback(documentType, currentPrompt, feedbackData) {
try {
// Analyze feedback for this document type
const lowRatedFeedback = feedbackData.filter(f => f.rating <= 3);
const commonIssues = lowRatedFeedback.map(f => f.description).join('\n');
const suggestions = lowRatedFeedback
.map(f => f.suggestedImprovement)
.filter(s => s && s.trim())
.join('\n');
// Create optimization prompt
const optimizationPrompt = `
You are an expert prompt engineer specializing in document generation for project management.
CURRENT PROMPT:
${currentPrompt}
DOCUMENT TYPE: ${documentType}
FEEDBACK ISSUES IDENTIFIED:
${commonIssues}
SUGGESTED IMPROVEMENTS:
${suggestions}
Please optimize the prompt to address these issues. Provide:
1. An improved version of the prompt
2. Specific improvements made
3. Expected impact on document quality
4. Confidence level (0-100%)
Focus on:
- Clarity and specificity
- PMBOK/BABOK compliance
- Addressing common quality issues
- Incorporating user suggestions
- Maintaining professional standards
Return your response in JSON format:
{
"optimizedPrompt": "...",
"improvements": ["...", "..."],
"expectedImpact": "...",
"confidence": 85
}
`;
const response = await this.aiProcessor.processAIRequest(() => Promise.resolve(optimizationPrompt), 'Optimize document generation prompt based on user feedback');
let result;
if (response && typeof response === 'object' && 'content' in response && typeof response.content === 'string') {
result = JSON.parse(response.content);
}
else {
throw new Error('AI response content missing or invalid');
}
return {
originalPrompt: currentPrompt,
optimizedPrompt: result.optimizedPrompt,
improvements: result.improvements,
expectedImpact: result.expectedImpact,
confidence: result.confidence
};
}
catch (error) {
console.error('Error optimizing prompt from feedback:', error);
throw new Error('Failed to optimize prompt from feedback');
}
}
/**
* Apply feedback-driven improvements to document generation
*/
async applyFeedbackImprovements(projectId) {
try {
// Get feedback for this project
const projectFeedback = await DocumentFeedback.find({
projectId,
rating: { $lte: 3 },
status: { $in: ['open', 'in-review'] }
});
if (projectFeedback.length === 0) {
return {
documentsImproved: [],
improvementsSummary: ['No low-rated feedback found to address'],
qualityPrediction: 0
};
}
// Group feedback by document type
const feedbackByType = projectFeedback.reduce((acc, feedback) => {
if (!acc[feedback.documentType]) {
acc[feedback.documentType] = [];
}
acc[feedback.documentType].push(feedback);
return acc;
}, {});
const documentsImproved = [];
const improvementsSummary = [];
// Process each document type
for (const [documentType, feedbacks] of Object.entries(feedbackByType)) {
try {
// Get current prompt for this document type
const currentPrompt = await this.getCurrentPrompt(documentType);
if (currentPrompt) {
// Optimize prompt based on feedback
const optimization = await this.optimizePromptFromFeedback(documentType, currentPrompt, feedbacks);
// Apply the optimization (in a real implementation, this would update the prompt templates)
await this.updatePromptTemplate(documentType, optimization.optimizedPrompt);
documentsImproved.push(documentType);
improvementsSummary.push(`${documentType}: ${optimization.improvements.join(', ')}`);
// Mark feedback as addressed
await DocumentFeedback.updateMany({
projectId,
documentType,
status: { $in: ['open', 'in-review'] }
}, {
status: 'implemented',
implementedAt: new Date()
});
}
}
catch (error) {
console.error(`Error improving ${documentType}:`, error);
improvementsSummary.push(`${documentType}: Failed to apply improvements`);
}
}
// Predict quality improvement
const qualityPrediction = this.predictQualityImprovement(projectFeedback);
return {
documentsImproved,
improvementsSummary,
qualityPrediction
};
}
catch (error) {
console.error('Error applying feedback improvements:', error);
throw new Error('Failed to apply feedback improvements');
}
}
/**
* Generate feedback-driven recommendations for project managers
*/
async generateRecommendations(projectId) {
try {
// Get project feedback analytics
const feedbackStats = await DocumentFeedback.aggregate([
{ $match: { projectId } },
{
$group: {
_id: null,
totalFeedback: { $sum: 1 },
averageRating: { $avg: '$rating' },
criticalIssues: {
$sum: { $cond: [{ $eq: ['$priority', 'critical'] }, 1, 0] }
},
openIssues: {
$sum: { $cond: [{ $eq: ['$status', 'open'] }, 1, 0] }
},
lowRatedDocs: {
$sum: { $cond: [{ $lte: ['$rating', 2] }, 1, 0] }
}
}
}
]);
const stats = feedbackStats[0] || {
totalFeedback: 0,
averageRating: 0,
criticalIssues: 0,
openIssues: 0,
lowRatedDocs: 0
};
const immediateActions = [];
const strategicImprovements = [];
// Generate immediate actions
if (stats.criticalIssues > 0) {
immediateActions.push(`Address ${stats.criticalIssues} critical issues immediately`);
}
if (stats.openIssues > 5) {
immediateActions.push('Review and prioritize open feedback items');
}
if (stats.averageRating < 3) {
immediateActions.push('Focus on improving document quality - average rating is below acceptable threshold');
}
// Generate strategic improvements
if (stats.lowRatedDocs > 0) {
strategicImprovements.push('Implement AI prompt optimization for consistently low-rated document types');
}
if (stats.totalFeedback > 20) {
strategicImprovements.push('Establish regular feedback review cycles');
}
strategicImprovements.push('Integrate feedback insights into template improvements');
// Calculate quality forecast
const currentScore = Math.round(stats.averageRating * 20); // Convert to 0-100 scale
const projectedScore = Math.min(currentScore + 15, 100); // Assume 15% improvement potential
return {
immediateActions,
strategicImprovements,
qualityForecast: {
currentScore,
projectedScore,
timeframe: '30 days'
}
};
}
catch (error) {
console.error('Error generating recommendations:', error);
throw new Error('Failed to generate recommendations');
}
}
/**
* Track feedback implementation impact
*/
async trackImplementationImpact(documentType, days = 30) {
try {
const cutoffDate = new Date();
cutoffDate.setDate(cutoffDate.getDate() - days);
// Get metrics before implementation
const beforeMetrics = await DocumentFeedback.aggregate([
{
$match: {
documentType,
submittedAt: { $lt: cutoffDate }
}
},
{
$group: {
_id: null,
averageRating: { $avg: '$rating' },
feedbackVolume: { $sum: 1 }
}
}
]);
// Get metrics after implementation
const afterMetrics = await DocumentFeedback.aggregate([
{
$match: {
documentType,
submittedAt: { $gte: cutoffDate }
}
},
{
$group: {
_id: null,
averageRating: { $avg: '$rating' },
feedbackVolume: { $sum: 1 }
}
}
]);
const before = beforeMetrics[0] || { averageRating: 0, feedbackVolume: 0 };
const after = afterMetrics[0] || { averageRating: 0, feedbackVolume: 0 };
const improvement = after.averageRating - before.averageRating;
const success = improvement > 0.2; // Consider 0.2+ rating improvement as success
return {
beforeMetrics: before,
afterMetrics: after,
improvement,
success
};
}
catch (error) {
console.error('Error tracking implementation impact:', error);
throw new Error('Failed to track implementation impact');
}
}
// Private helper methods
analyzeTextFrequency(texts) {
const frequency = {};
texts.forEach(text => {
if (text && text.trim()) {
const words = text.toLowerCase().split(/\s+/);
words.forEach(word => {
if (word.length > 3) { // Filter out short words
frequency[word] = (frequency[word] || 0) + 1;
}
});
}
});
return frequency;
}
async generatePromptImprovements(documentType, descriptions, suggestions) {
try {
const analysisPrompt = `
Analyze the following feedback for ${documentType} documents and suggest 3-5 specific prompt improvements:
FEEDBACK DESCRIPTIONS:
${descriptions.join('\n')}
SUGGESTIONS:
${suggestions.filter(s => s).join('\n')}
Provide specific, actionable prompt improvements that would address these issues.
Return as a JSON array of strings.
`;
const response = await this.aiProcessor.processAIRequest(() => Promise.resolve(analysisPrompt), 'Generate prompt improvements from feedback');
if (response && typeof response === 'object' && 'content' in response && typeof response.content === 'string') {
return JSON.parse(response.content);
}
else {
throw new Error('AI response content missing or invalid');
}
}
catch (error) {
console.error('Error generating prompt improvements:', error);
return ['Review and enhance prompt specificity', 'Add quality validation criteria'];
}
}
async calculateQualityTrends(documentType, days) {
try {
const startDate = new Date();
startDate.setDate(startDate.getDate() - days);
const trends = await DocumentFeedback.aggregate([
{
$match: {
documentType,
submittedAt: { $gte: startDate }
}
},
{
$group: {
_id: {
week: { $week: '$submittedAt' }
},
averageRating: { $avg: '$rating' },
count: { $sum: 1 }
}
},
{ $sort: { '_id.week': 1 } }
]);
if (trends.length < 2) {
return {
averageRating: trends[0]?.averageRating || 0,
ratingTrend: 'stable',
feedbackVolume: trends[0]?.count || 0
};
}
const firstWeek = trends[0].averageRating;
const lastWeek = trends[trends.length - 1].averageRating;
const difference = lastWeek - firstWeek;
let ratingTrend;
if (difference > 0.2)
ratingTrend = 'improving';
else if (difference < -0.2)
ratingTrend = 'declining';
else
ratingTrend = 'stable';
return {
averageRating: trends.reduce((sum, t) => sum + t.averageRating, 0) / trends.length,
ratingTrend,
feedbackVolume: trends.reduce((sum, t) => sum + t.count, 0)
};
}
catch (error) {
console.error('Error calculating quality trends:', error);
return { averageRating: 0, ratingTrend: 'stable', feedbackVolume: 0 };
}
}
identifyPriorityAreas(feedbackTypes, priorities, descriptions) {
const areas = {};
feedbackTypes.forEach((type, index) => {
if (!areas[type]) {
areas[type] = { severity: priorities[index] || 'medium', frequency: 0 };
}
areas[type].frequency++;
});
return Object.entries(areas).map(([area, data]) => ({
area,
severity: data.severity,
frequency: data.frequency
})).sort((a, b) => b.frequency - a.frequency);
}
predictQualityImprovement(feedback) {
// Simple prediction based on feedback volume and severity
const criticalCount = feedback.filter(f => f.priority === 'critical').length;
const highCount = feedback.filter(f => f.priority === 'high').length;
// Predict 10-30% improvement based on issue severity
const baseImprovement = 10;
const severityBonus = (criticalCount * 5) + (highCount * 3);
return Math.min(baseImprovement + severityBonus, 30);
}
async getCurrentPrompt(documentType) {
// TODO: Implement actual prompt retrieval from template system
// This would integrate with the existing template/processor system
return `Generate a professional ${documentType} document following PMBOK standards...`;
}
async updatePromptTemplate(documentType, optimizedPrompt) {
// TODO: Implement actual prompt template update
// This would integrate with the existing template/processor system
console.log(`Updated prompt template for ${documentType}`);
}
}
//# sourceMappingURL=FeedbackIntegrationService.js.map