/** * Framework Content Analysis Controller * Handles framework-guided blog pre-publication and comment/feedback analysis */ const PluralisticDeliberationOrchestrator = require('../services/PluralisticDeliberationOrchestrator.service'); const BoundaryEnforcer = require('../services/BoundaryEnforcer.service'); const logger = require('../utils/logger.util'); /** * Analyze blog post before publication * Provides framework-guided content review with sensitivity checks, compliance validation, * audience analysis, and response templates * * POST /api/admin/blog/analyze * Body: { title, content, category, tags } */ exports.analyzeBlogPost = async (req, res) => { const { title, content, category, tags } = req.body; logger.info('[Framework Content Analysis] Blog post analysis requested', { userId: req.user.id, title, category }); try { // Initialize services const deliberationOrchestrator = new PluralisticDeliberationOrchestrator(); const boundaryEnforcer = new BoundaryEnforcer(); // 1. Sensitivity check - detect values-sensitive topics const sensitivityResult = await deliberationOrchestrator.detectValuesSensitivity({ content: `${title}\n\n${content}`, context: { category, tags } }); // 2. Compliance check - ensure framework adherence const complianceResult = await boundaryEnforcer.checkCompliance({ content, title, type: 'blog_post', category }); // 3. Audience analysis - engagement prediction const audienceAnalysis = { engagement: { level: 70, // TODO: Implement ML-based prediction description: 'Expected to generate moderate engagement based on topic relevance' }, similarPosts: [] // TODO: Query database for similar posts }; // 4. Publication guidance const publicationGuidance = { timing: 'Publish during business hours (9am-5pm NZT) for maximum visibility', monitoring: 'Monitor comments for first 48 hours post-publication', actions: [ 'Share on LinkedIn and Twitter', 'Enable comments with moderation', 'Prepare standard responses for anticipated questions' ] }; // 5. Generate response templates for anticipated feedback const responseTemplates = [ { scenario: 'Request for more technical details', response: 'Thank you for your interest. We\'re planning a follow-up article with deeper technical implementation details. Would you like to be notified when it\'s published?' }, { scenario: 'Concern about framework overhead', response: 'That\'s a valid concern. The framework is designed to be lightweight - most governance checks happen at build/deploy time rather than runtime. Performance overhead is typically <1%.' }, { scenario: 'Question about alternative approaches', response: 'We\'ve evaluated several alternative approaches. The framework\'s design prioritizes transparency and human oversight. We\'d be happy to discuss specific alternatives you\'re considering.' } ]; // 6. Overall recommendation let overallRecommendation = { decision: 'APPROVE', title: 'Ready for Publication', message: 'This content meets all framework requirements and is ready for publication.', action: 'Proceed to publish when ready' }; // Adjust recommendation based on checks if (sensitivityResult.requiresDeliberation || complianceResult.violations?.length > 0) { overallRecommendation = { decision: 'REVIEW', title: 'Review Recommended', message: 'This content requires human review before publication.', action: 'Address flagged concerns before publishing' }; } // Construct analysis response const analysis = { overall: overallRecommendation, sensitivity: { status: sensitivityResult.requiresDeliberation ? 'WARN' : 'PASS', summary: sensitivityResult.requiresDeliberation ? 'Values-sensitive content detected - review recommended' : 'No significant values-sensitivity detected', details: sensitivityResult.conflicts || [], recommendation: sensitivityResult.guidance }, compliance: { status: complianceResult.violations?.length > 0 ? 'FAIL' : 'PASS', summary: complianceResult.violations?.length > 0 ? `${complianceResult.violations.length} compliance issue(s) detected` : 'Passes all framework compliance checks', details: complianceResult.violations || [], recommendation: complianceResult.guidance }, audience: audienceAnalysis, publication: publicationGuidance, responseTemplates }; res.json({ success: true, analysis }); } catch (error) { logger.error('[Framework Content Analysis] Blog analysis error', { error: error.message, stack: error.stack, userId: req.user.id }); res.status(500).json({ success: false, error: 'Analysis failed. Please try again.' }); } }; /** * Save blog post as draft * * POST /api/admin/blog/draft * Body: { title, content, category, tags, status: 'draft' } */ exports.saveBlogDraft = async (req, res) => { const { title, content, category, tags } = req.body; logger.info('[Framework Content Analysis] Saving blog draft', { userId: req.user.id, title }); // TODO: Implement database save logic // For now, return success res.json({ success: true, message: 'Draft saved successfully', draftId: 'draft_' + Date.now() }); }; /** * Publish blog post * * POST /api/admin/blog/publish * Body: { title, content, category, tags, status: 'published' } */ exports.publishBlogPost = async (req, res) => { const { title, content, category, tags } = req.body; logger.info('[Framework Content Analysis] Publishing blog post', { userId: req.user.id, title }); // TODO: Implement database save and publication logic // For now, return success res.json({ success: true, message: 'Post published successfully', postId: 'post_' + Date.now() }); }; /** * Analyze comment/feedback with framework guidance * Provides sentiment analysis, values alignment check, risk assessment, * and recommended responses * * POST /api/admin/feedback/analyze * Body: { source, relatedPost, content, notes } */ exports.analyzeFeedback = async (req, res) => { const { source, relatedPost, content, notes } = req.body; logger.info('[Framework Content Analysis] Feedback analysis requested', { userId: req.user.id, source, contentLength: content.length }); try { // Initialize services const deliberationOrchestrator = new PluralisticDeliberationOrchestrator(); const boundaryEnforcer = new BoundaryEnforcer(); // 1. Sentiment analysis const sentimentAnalysis = analyzeSentiment(content); // 2. Values alignment check const valuesResult = await deliberationOrchestrator.detectValuesSensitivity({ content, context: { source, relatedPost, notes } }); // 3. Risk assessment const riskAssessment = await boundaryEnforcer.assessRisk({ content, source, type: 'public_feedback' }); // 4. Generate recommended responses const responses = generateRecommendedResponses(sentimentAnalysis, valuesResult); // 5. Framework guidance on whether to respond const guidance = { shouldRespond: shouldRespondToFeedback(sentimentAnalysis, valuesResult, riskAssessment), keyConsiderations: [ 'Response should align with Tractatus values', 'Avoid defensive or dismissive language', 'Acknowledge valid concerns genuinely', 'Clarify misunderstandings with patience' ], tone: sentimentAnalysis.overall === 'negative' ? 'Empathetic and understanding, addressing concerns directly' : 'Appreciative and informative, building on positive feedback' }; const analysis = { sentiment: sentimentAnalysis, values: { alignedWith: valuesResult.alignedValues || [], concernsRaised: valuesResult.concerns || [], misunderstandings: valuesResult.misunderstandings || [] }, risk: riskAssessment, responses, guidance }; res.json({ success: true, analysis }); } catch (error) { logger.error('[Framework Content Analysis] Feedback analysis error', { error: error.message, stack: error.stack, userId: req.user.id }); res.status(500).json({ success: false, error: 'Analysis failed. Please try again.' }); } }; /** * Save feedback analysis * * POST /api/admin/feedback/save * Body: { source, relatedPost, content, notes } */ exports.saveFeedbackAnalysis = async (req, res) => { const { source, relatedPost, content, notes } = req.body; logger.info('[Framework Content Analysis] Saving feedback analysis', { userId: req.user.id, source }); // TODO: Implement database save logic res.json({ success: true, message: 'Feedback analysis saved successfully', analysisId: 'feedback_' + Date.now() }); }; /** * Export feedback analysis report * * POST /api/admin/feedback/export * Body: { source, relatedPost, content } */ exports.exportFeedbackReport = async (req, res) => { const { source, relatedPost, content } = req.body; logger.info('[Framework Content Analysis] Exporting feedback report', { userId: req.user.id, source }); // TODO: Implement PDF export using Puppeteer // For now, return placeholder response res.status(501).json({ success: false, error: 'Export functionality coming soon' }); }; // ============================================================ // HELPER FUNCTIONS // ============================================================ /** * Analyze sentiment of text content * Basic implementation - could be enhanced with ML */ function analyzeSentiment(content) { const lowerContent = content.toLowerCase(); // Positive indicators const positiveWords = ['great', 'excellent', 'love', 'appreciate', 'thank', 'helpful', 'useful', 'good']; const positiveCount = positiveWords.filter(word => lowerContent.includes(word)).length; // Negative indicators const negativeWords = ['bad', 'terrible', 'hate', 'disappointed', 'concerned', 'wrong', 'problem', 'issue']; const negativeCount = negativeWords.filter(word => lowerContent.includes(word)).length; // Question indicators const questionWords = ['how', 'what', 'why', 'when', 'where', '?']; const questionCount = questionWords.filter(word => lowerContent.includes(word)).length; // Determine overall sentiment let overall = 'neutral'; if (positiveCount > negativeCount + 1) overall = 'positive'; else if (negativeCount > positiveCount + 1) overall = 'negative'; else if (positiveCount > 0 && negativeCount > 0) overall = 'mixed'; // Extract key phrases (simple implementation) const keyPhrases = []; if (lowerContent.includes('framework')) keyPhrases.push('framework discussion'); if (lowerContent.includes('implementation')) keyPhrases.push('implementation questions'); if (lowerContent.includes('concern')) keyPhrases.push('concerns raised'); return { overall, confidence: Math.min(95, 60 + (Math.abs(positiveCount - negativeCount) * 10)), summary: overall === 'positive' ? 'Feedback is generally positive and constructive' : overall === 'negative' ? 'Feedback raises concerns or criticism' : overall === 'mixed' ? 'Feedback includes both positive and critical elements' : 'Neutral tone, primarily informational or questioning', keyPhrases }; } /** * Generate recommended responses based on analysis */ function generateRecommendedResponses(sentiment, valuesResult) { const responses = []; if (sentiment.overall === 'positive') { responses.push({ approach: 'Appreciative acknowledgment', priority: 'medium', text: 'Thank you for your thoughtful feedback. We\'re glad the framework resonates with your values and approach to AI governance.', rationale: 'Reinforces positive engagement' }); } if (sentiment.overall === 'negative') { responses.push({ approach: 'Empathetic concern acknowledgment', priority: 'high', text: 'Thank you for sharing your concerns. We take this feedback seriously and want to understand your perspective better. Could you elaborate on [specific concern]?', rationale: 'Demonstrates genuine listening and openness' }); } if (valuesResult.misunderstandings?.length > 0) { responses.push({ approach: 'Clarifying misunderstanding', priority: 'high', text: 'I appreciate you raising this point - it highlights an area where our communication could be clearer. What we mean by [concept] is [clarification].', rationale: 'Corrects misunderstanding without being condescending' }); } responses.push({ approach: 'Invitation to continued dialogue', priority: 'low', text: 'We value ongoing discussion about these important topics. If you\'d like to explore this further, feel free to [suggest next step].', rationale: 'Maintains open communication channel' }); return responses; } /** * Determine if feedback warrants a response */ function shouldRespondToFeedback(sentiment, valuesResult, riskAssessment) { // Always respond to high-risk feedback if (riskAssessment.level === 'high') return true; // Respond to values-misalignment concerns if (valuesResult.concerns?.length > 0) return true; // Respond to negative feedback if (sentiment.overall === 'negative') return true; // Respond to positive feedback (builds community) if (sentiment.overall === 'positive') return true; // Skip neutral/low-engagement comments return false; }