Skip to Content
📚 MyStoryFlow Docs — Your guide to preserving family stories

F010 - AI-Powered Recommendations Engine

Objective

Build an intelligent recommendations system that provides personalized, actionable improvement suggestions for manuscripts based on AI analysis, genre conventions, market trends, and individual author goals within the MyStoryFlow platform.

Quick Implementation

Using MyStoryFlow Components

  • Personalization engine from @mystoryflow/personalization
  • User preferences from @mystoryflow/user-data
  • Analytics tracking from @mystoryflow/analytics
  • Notification system from @mystoryflow/notifications

New Requirements

  • Recommendation generation algorithms
  • Priority ranking system
  • Implementation tracking
  • Success measurement
  • Adaptive learning system

MVP Implementation

1. Recommendation Engine Core

// packages/manuscript-analysis/src/recommendations/recommendation-engine.ts import { AIService } from '../services/ai-service' import { Logger } from '@mystoryflow/logger' import { PersonalizationService } from '@mystoryflow/personalization' import { UserPreferencesService } from '@mystoryflow/user-data' export class RecommendationEngine { private aiService: AIService private personalization: PersonalizationService private userPreferences: UserPreferencesService private logger: Logger constructor() { this.aiService = new AIService() this.personalization = new PersonalizationService() this.userPreferences = new UserPreferencesService() this.logger = new Logger('RecommendationEngine') } async generateRecommendations(params: { manuscriptId: string userId: string analysis: ComprehensiveAnalysis scores: ManuscriptScore userGoals: AuthorGoals }): Promise<PersonalizedRecommendations> { const { analysis, scores, userGoals } = params // Get user preferences and history const userProfile = await this.getUserProfile(params.userId) // Generate base recommendations const baseRecommendations = await this.generateBaseRecommendations( analysis, scores ) // Personalize based on author goals const personalizedRecs = await this.personalizeRecommendations( baseRecommendations, userGoals, userProfile ) // Prioritize recommendations const prioritizedRecs = this.prioritizeRecommendations( personalizedRecs, scores, userGoals ) // Generate implementation plans const implementationPlans = await this.createImplementationPlans( prioritizedRecs, analysis.metadata ) return { recommendations: prioritizedRecs, implementationPlans, estimatedImpact: this.calculateEstimatedImpact(prioritizedRecs, scores), timeline: this.generateTimeline(implementationPlans), trackingMetrics: this.defineTrackingMetrics(prioritizedRecs) } } private async generateBaseRecommendations( analysis: ComprehensiveAnalysis, scores: ManuscriptScore ): Promise<BaseRecommendation[]> { const recommendations: BaseRecommendation[] = [] // Character development recommendations if (scores.dimensions.characterDevelopment.score < 0.8) { const charRecs = await this.generateCharacterRecommendations( analysis.overall.analysis.character, analysis.chapters ) recommendations.push(...charRecs) } // Plot structure recommendations if (scores.dimensions.plotStructure.score < 0.8) { const plotRecs = await this.generatePlotRecommendations( analysis.overall.analysis.plot, analysis.specialized.plotAnalysis ) recommendations.push(...plotRecs) } // Writing style recommendations if (scores.dimensions.writingStyle.score < 0.85) { const styleRecs = await this.generateStyleRecommendations( analysis.overall.analysis.style, analysis.metadata.genre ) recommendations.push(...styleRecs) } // Dialogue recommendations if (analysis.specialized.dialogueAnalysis && scores.dimensions.dialogue.score < 0.8) { const dialogueRecs = await this.generateDialogueRecommendations( analysis.specialized.dialogueAnalysis ) recommendations.push(...dialogueRecs) } // Pacing recommendations if (scores.dimensions.pacing.score < 0.75) { const pacingRecs = await this.generatePacingRecommendations( analysis.overall.analysis.pacing, analysis.chapters ) recommendations.push(...pacingRecs) } return recommendations } private async generateCharacterRecommendations( characterAnalysis: any, chapters: ChapterAnalysis[] ): Promise<BaseRecommendation[]> { const prompt = ` Based on this character analysis, generate specific, actionable recommendations: ${JSON.stringify(characterAnalysis)} Focus on: 1. Deepening character motivations 2. Strengthening character arcs 3. Improving character distinctiveness 4. Enhancing emotional depth 5. Fixing consistency issues Return as JSON array with structure: { type: "character", title: "Brief title", description: "Detailed description", impact: "high|medium|low", effort: "high|medium|low", specificActions: ["action1", "action2"], examples: ["example from text"], location: "chapter/page references" } ` const aiRecommendations = await this.aiService.analyzeManuscript( prompt, 'recommendations', { outputFormat: 'json' } ) return aiRecommendations.recommendations.map(rec => ({ ...rec, category: 'character-development', generatedAt: new Date() })) } private async personalizeRecommendations( recommendations: BaseRecommendation[], userGoals: AuthorGoals, userProfile: UserProfile ): Promise<PersonalizedRecommendation[]> { const personalized = await Promise.all( recommendations.map(async rec => { // Calculate relevance to user goals const goalRelevance = this.calculateGoalRelevance(rec, userGoals) // Adjust based on user preferences const preferenceScore = await this.personalization.scoreRecommendation( rec, userProfile ) // Check if similar recommendations were successful before const historicalSuccess = await this.checkHistoricalSuccess( rec.type, userProfile.id ) return { ...rec, relevanceScore: goalRelevance * preferenceScore, personalizedReason: this.explainPersonalization( rec, userGoals, preferenceScore ), historicalContext: historicalSuccess, alternativeApproaches: await this.generateAlternatives(rec, userProfile) } }) ) return personalized.filter(rec => rec.relevanceScore > 0.5) } private prioritizeRecommendations( recommendations: PersonalizedRecommendation[], scores: ManuscriptScore, goals: AuthorGoals ): PrioritizedRecommendation[] { return recommendations .map(rec => { const impactScore = this.calculateImpactScore(rec, scores) const effortScore = this.calculateEffortScore(rec) const urgencyScore = this.calculateUrgencyScore(rec, goals) const priorityScore = (impactScore * 0.4) + (urgencyScore * 0.3) + ((1 - effortScore) * 0.3) return { ...rec, priority: this.getPriorityLevel(priorityScore), priorityScore, impactMetrics: { expectedScoreImprovement: impactScore * 0.1, affectedDimensions: this.getAffectedDimensions(rec), cascadeEffects: this.identifyCascadeEffects(rec) }, sequencing: { dependencies: this.identifyDependencies(rec, recommendations), optimalOrder: null // Set later } } }) .sort((a, b) => b.priorityScore - a.priorityScore) } }

2. Implementation Plan Generator

// packages/manuscript-analysis/src/recommendations/implementation-planner.ts export class ImplementationPlanner { async createImplementationPlans( recommendations: PrioritizedRecommendation[], metadata: ManuscriptMetadata ): Promise<ImplementationPlan[]> { // Group related recommendations const grouped = this.groupRelatedRecommendations(recommendations) // Create phased implementation plan const phases = this.createPhases(grouped, metadata) // Generate detailed plans for each phase return Promise.all( phases.map(async (phase, index) => ({ phase: index + 1, name: phase.name, duration: phase.estimatedDuration, recommendations: await this.detailRecommendations(phase.recommendations), milestones: this.defineMilestones(phase), successCriteria: this.defineSuccessCriteria(phase), resources: await this.identifyResources(phase) })) ) } private async detailRecommendations( recommendations: PrioritizedRecommendation[] ): Promise<DetailedRecommendation[]> { return Promise.all( recommendations.map(async rec => ({ ...rec, steps: await this.breakDownIntoSteps(rec), techniques: await this.suggestTechniques(rec), examples: await this.findRelevantExamples(rec), exercises: await this.createPracticeExercises(rec), checkpoints: this.defineCheckpoints(rec) })) ) } private async breakDownIntoSteps( recommendation: PrioritizedRecommendation ): Promise<ImplementationStep[]> { const steps: ImplementationStep[] = [] switch (recommendation.type) { case 'character': if (recommendation.title.includes('motivation')) { steps.push( { order: 1, title: 'Character Backstory Development', description: 'Create detailed backstory that explains current motivations', deliverable: 'Character profile document with backstory', estimatedTime: '2-3 hours', tools: ['Character worksheet template', 'Backstory generator'] }, { order: 2, title: 'Motivation Mapping', description: 'Map character desires to plot events', deliverable: 'Motivation-plot alignment chart', estimatedTime: '1-2 hours', tools: ['Plot-character matrix template'] }, { order: 3, title: 'Scene Revision', description: 'Revise key scenes to reflect deeper motivations', deliverable: 'Revised scenes with motivation highlights', estimatedTime: '4-6 hours', tools: ['Scene revision checklist'] } ) } break case 'plot': if (recommendation.title.includes('pacing')) { steps.push( { order: 1, title: 'Pacing Analysis', description: 'Chart current pacing across chapters', deliverable: 'Pacing chart with problem areas marked', estimatedTime: '1-2 hours', tools: ['Pacing analysis template'] }, { order: 2, title: 'Scene Restructuring', description: 'Identify scenes to cut, combine, or expand', deliverable: 'Revised scene outline', estimatedTime: '2-3 hours', tools: ['Scene structure worksheet'] } ) } break } return steps } private async createPracticeExercises( recommendation: PrioritizedRecommendation ): Promise<PracticeExercise[]> { const exercises: PracticeExercise[] = [] if (recommendation.category === 'character-development') { exercises.push({ title: 'Character Voice Exercise', description: 'Write a diary entry from your character\'s perspective', purpose: 'Develop distinct character voice', duration: '30 minutes', evaluation: 'Self-assess for voice consistency and authenticity' }) } if (recommendation.category === 'dialogue') { exercises.push({ title: 'Dialogue Rhythm Practice', description: 'Rewrite a dialogue scene with varied sentence lengths', purpose: 'Improve dialogue flow and naturalism', duration: '45 minutes', evaluation: 'Read aloud to check rhythm' }) } return exercises } }

3. Adaptive Learning System

// packages/manuscript-analysis/src/recommendations/adaptive-learning.ts export class AdaptiveLearningSystem { async learnFromFeedback(params: { recommendationId: string userId: string feedback: RecommendationFeedback outcomes: RecommendationOutcomes }): Promise<void> { const { recommendationId, userId, feedback, outcomes } = params // Store feedback await this.storeFeedback(recommendationId, userId, feedback) // Update recommendation effectiveness scores await this.updateEffectivenessScores(recommendationId, outcomes) // Adjust future recommendation weights await this.adjustRecommendationWeights( feedback.type, feedback.wasHelpful, userId ) // Update personalization model await this.updatePersonalizationModel(userId, { preferredRecommendationTypes: feedback.preferredTypes, effectiveApproaches: outcomes.successfulApproaches, timePreferences: feedback.timeSpent }) } async trackImplementationProgress(params: { userId: string recommendationId: string progress: ImplementationProgress }): Promise<ProgressInsights> { const { userId, recommendationId, progress } = params // Update progress tracking await this.updateProgress(recommendationId, progress) // Analyze implementation patterns const patterns = await this.analyzeImplementationPatterns(userId) // Generate insights const insights = { completionRate: patterns.avgCompletionRate, effectiveTimeSlots: patterns.mostProductiveTimes, preferredPace: patterns.implementationPace, commonBlockers: patterns.frequentObstacles, successFactors: patterns.successCorrelations } // Adapt future recommendations based on insights await this.adaptRecommendations(userId, insights) return insights } private async adaptRecommendations( userId: string, insights: ProgressInsights ): Promise<void> { // Adjust recommendation timing if (insights.effectiveTimeSlots.length > 0) { await this.updateUserPreference(userId, { preferredImplementationTimes: insights.effectiveTimeSlots }) } // Adjust recommendation complexity if (insights.completionRate < 0.5) { await this.updateUserPreference(userId, { recommendationComplexity: 'simpler', stepGranularity: 'more-detailed' }) } // Adjust recommendation types based on success const successfulTypes = Object.entries(insights.successFactors) .filter(([_, rate]) => rate > 0.7) .map(([type]) => type) await this.updateUserPreference(userId, { prioritizeTypes: successfulTypes }) } }

4. Recommendation Tracking API

// apps/story-analyzer/src/app/api/recommendations/route.ts import { NextRequest, NextResponse } from 'next/server' import { RecommendationEngine } from '@mystoryflow/manuscript-analysis' import { withAuth } from '@mystoryflow/auth' import { trackEvent } from '@mystoryflow/analytics' export async function POST(req: NextRequest) { try { const session = await withAuth(req) if (!session) { return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }) } const { manuscriptId, analysisId, userGoals } = await req.json() // Get analysis and scores const analysis = await getAnalysis(analysisId) const scores = await getScores(manuscriptId) // Generate personalized recommendations const engine = new RecommendationEngine() const recommendations = await engine.generateRecommendations({ manuscriptId, userId: session.user.id, analysis, scores, userGoals }) // Track recommendation generation await trackEvent({ userId: session.user.id, event: 'recommendations_generated', properties: { manuscriptId, recommendationCount: recommendations.recommendations.length, topPriority: recommendations.recommendations[0]?.type } }) // Store recommendations await storeRecommendations(manuscriptId, recommendations) return NextResponse.json({ recommendations: recommendations.recommendations, implementationPlan: recommendations.implementationPlans[0], estimatedImpact: recommendations.estimatedImpact, trackingId: recommendations.trackingMetrics.id }) } catch (error) { console.error('Recommendation generation failed:', error) return NextResponse.json( { error: 'Failed to generate recommendations' }, { status: 500 } ) } } // Track implementation progress export async function PATCH(req: NextRequest) { try { const session = await withAuth(req) if (!session) { return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }) } const { recommendationId, progress, feedback } = await req.json() const adaptiveSystem = new AdaptiveLearningSystem() // Track progress const insights = await adaptiveSystem.trackImplementationProgress({ userId: session.user.id, recommendationId, progress }) // Process feedback if provided if (feedback) { await adaptiveSystem.learnFromFeedback({ recommendationId, userId: session.user.id, feedback, outcomes: progress.outcomes }) } return NextResponse.json({ insights, nextSteps: await generateNextSteps(recommendationId, progress) }) } catch (error) { console.error('Progress tracking failed:', error) return NextResponse.json( { error: 'Failed to track progress' }, { status: 500 } ) } }

5. Coach Integration for Recommendations

// packages/manuscript-analysis/src/recommendations/coach-integration.ts export class CoachRecommendationIntegration { async enhanceWithCoachInsights( recommendations: PersonalizedRecommendation[], manuscriptId: string ): Promise<EnhancedRecommendation[]> { // Find coaches who specialize in the recommendation areas const relevantCoaches = await this.findRelevantCoaches(recommendations) return Promise.all( recommendations.map(async rec => { const coachInsights = await this.getCoachInsights( rec.type, relevantCoaches ) return { ...rec, coachSupport: { available: coachInsights.length > 0, coaches: coachInsights.map(insight => ({ coachId: insight.coachId, name: insight.coachName, expertise: insight.relevantExpertise, sessionType: this.suggestSessionType(rec, insight), estimatedSessions: this.estimateSessionCount(rec.effort) })), groupSessions: await this.findGroupSessions(rec.type), resources: await this.getCoachResources(rec.type) }, hybridApproach: this.createHybridPlan(rec, coachInsights) } }) ) } private createHybridPlan( recommendation: PersonalizedRecommendation, coachInsights: CoachInsight[] ): HybridImplementationPlan { return { selfGuidedSteps: recommendation.specificActions.filter( action => this.canBeSelfGuided(action) ), coachGuidedSteps: recommendation.specificActions.filter( action => this.benefitsFromCoaching(action) ), checkpoints: [ { type: 'self-assessment', timing: 'after-self-guided', tools: ['Progress tracker', 'Self-evaluation rubric'] }, { type: 'coach-review', timing: 'mid-implementation', focus: 'Technical execution and refinement' }, { type: 'peer-review', timing: 'before-final', platform: 'MyStoryFlow community' } ], flexibilityOptions: { canStartWithCoach: recommendation.effort === 'high', canSkipCoaching: recommendation.impact === 'low', hybridSessionTypes: ['Q&A', 'Review', 'Workshop'] } } } }

Database Schema

-- Personalized recommendations CREATE TABLE analyzer.recommendations ( id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), manuscript_id UUID REFERENCES analyzer.manuscripts(id), user_id UUID REFERENCES auth.users(id), analysis_id UUID REFERENCES analyzer.analysis_results(id), type VARCHAR(50), category VARCHAR(50), title TEXT, description TEXT, impact VARCHAR(20), effort VARCHAR(20), priority VARCHAR(20), priority_score DECIMAL(3,2), specific_actions JSONB, implementation_plan JSONB, personalization_data JSONB, created_at TIMESTAMP DEFAULT NOW(), INDEX idx_recommendations_manuscript (manuscript_id), INDEX idx_recommendations_user (user_id), INDEX idx_recommendations_priority (priority_score DESC) ); -- Implementation tracking CREATE TABLE analyzer.recommendation_progress ( id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), recommendation_id UUID REFERENCES analyzer.recommendations(id), user_id UUID REFERENCES auth.users(id), status VARCHAR(50) DEFAULT 'not_started', progress_percentage INTEGER DEFAULT 0, started_at TIMESTAMP, completed_at TIMESTAMP, time_spent_minutes INTEGER, steps_completed JSONB, notes TEXT, outcome_metrics JSONB, INDEX idx_progress_recommendation (recommendation_id), INDEX idx_progress_user (user_id) ); -- Recommendation feedback CREATE TABLE analyzer.recommendation_feedback ( id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), recommendation_id UUID REFERENCES analyzer.recommendations(id), user_id UUID REFERENCES auth.users(id), was_helpful BOOLEAN, clarity_rating INTEGER CHECK (clarity_rating BETWEEN 1 AND 5), relevance_rating INTEGER CHECK (relevance_rating BETWEEN 1 AND 5), difficulty_rating INTEGER CHECK (difficulty_rating BETWEEN 1 AND 5), preferred_types TEXT[], feedback_text TEXT, created_at TIMESTAMP DEFAULT NOW(), INDEX idx_feedback_recommendation (recommendation_id) ); -- Learning system data CREATE TABLE analyzer.adaptive_learning ( id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), user_id UUID REFERENCES auth.users(id), recommendation_type VARCHAR(50), success_rate DECIMAL(3,2), avg_completion_time INTEGER, preferred_complexity VARCHAR(20), effective_approaches JSONB, last_updated TIMESTAMP DEFAULT NOW(), UNIQUE(user_id, recommendation_type), INDEX idx_learning_user (user_id) );

MVP Acceptance Criteria

  • AI-powered recommendation generation
  • Personalization based on user goals
  • Priority ranking system
  • Detailed implementation plans
  • Progress tracking
  • Adaptive learning from feedback
  • Coach integration options
  • Success metrics
  • API endpoints

Post-MVP Enhancements

  • Community recommendation sharing
  • Video tutorial integration
  • Real-time recommendation updates
  • A/B testing recommendation approaches
  • Gamification elements
  • Peer accountability features
  • Writing exercise generator
  • Style mimicry suggestions

Implementation Time

  • Recommendation Engine: 1.5 days
  • Implementation Planner: 1 day
  • Adaptive Learning: 1 day
  • API Integration: 0.5 days
  • Coach Integration: 0.5 days
  • Testing: 1 day
  • Total: 5.5 days

Dependencies

  • F007 - Manuscript Analysis (for analysis data)
  • F009 - Scoring System (for priority calculation)
  • F011 - Coach Matching (for coach integration)

Next Feature

After completion, proceed to F011-COACH-MATCHING for AI-powered coach pairing.