Skip to Content
📚 MyStoryFlow Docs — Your guide to preserving family stories
Technical DocumentationTools ImplementationAI Integration Standards & Patterns

AI Integration Standards & Patterns

🤖 Universal AI Architecture

MyStoryFlow’s AI integration follows standardized patterns across all tools, ensuring consistent quality, cost optimization, and comprehensive tracking. Every tool uses the same AI service architecture with tool-specific customization.

🏗️ AI Service Class Structure

Universal AI Service Template

Every tool implements an AI service following this exact pattern:

// /lib/ai/{tool-name}-ai.ts import OpenAI from 'openai' import { storePromptInAdmin, trackAIUsage, getRecommendedToolsModel } from '@/lib/ai-usage-tracker' const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY }) // =========================================== // INTERFACE DEFINITIONS (TOOL-SPECIFIC) // =========================================== export interface ToolOptions { // Tool-specific generation parameters // Example: genre, style, complexity, etc. } export interface ToolResult { id: string title: string content: any // Tool-specific content structure seoMetadata: { title: string description: string keywords: string[] } usage: { total_tokens: number prompt_tokens: number completion_tokens: number } estimatedCost: number processingTime: number confidenceScore: number model: string promptUsed: string variantType: string } // =========================================== // AI SERVICE CLASS (UNIVERSAL PATTERN) // =========================================== export class ToolAI { /** * Main generation method - follows universal pattern */ async generateContent( options: ToolOptions, context: { sessionId: string; requestId: string } ): Promise<ToolResult> { const startTime = Date.now() try { // 1. Store prompt in admin database for reuse and analysis const promptId = await storePromptInAdmin({ name: `{tool}_generation_system`, version: '1.0', content: this.buildSystemPrompt(options), category: 'tools', tool_name: '{tool}' }) // 2. Build user prompt with tool-specific logic const userPrompt = this.buildUserPrompt(options) // 3. Call OpenAI with standardized parameters const completion = await openai.chat.completions.create({ model: getRecommendedToolsModel(), // gpt-4o-mini-2024-07-18 messages: [ { role: 'system', content: this.buildSystemPrompt(options) }, { role: 'user', content: userPrompt } ], temperature: this.getOptimalTemperature(options), max_tokens: this.getMaxTokens(options), response_format: { type: 'json_object' }, // Ensure structured output presence_penalty: 0.1, // Encourage creativity frequency_penalty: 0.1 // Reduce repetition }) const processingTime = Date.now() - startTime // 4. Parse and validate response const response = this.parseAndValidateResponse(completion.choices[0].message.content) // 5. Calculate cost estimation const estimatedCost = this.calculateCost(completion.usage) // 6. Generate SEO metadata const seoMetadata = this.generateSEOMetadata(response, options) // 7. Build result object const result: ToolResult = { id: `{tool}-${Date.now()}`, title: response.title || this.generateTitle(response, options), content: response, seoMetadata, usage: completion.usage || { total_tokens: 0, prompt_tokens: 0, completion_tokens: 0 }, estimatedCost, processingTime, confidenceScore: response.confidence || this.calculateConfidence(response), model: getRecommendedToolsModel(), promptUsed: promptId, variantType: 'standard' } return result } catch (error) { console.error(`{tool} AI generation error:`, error) throw new Error(`AI generation failed: ${error.message}`) } } // =========================================== // PROMPT ENGINEERING METHODS // =========================================== /** * Build system prompt - defines AI behavior and output format */ private buildSystemPrompt(options: ToolOptions): string { return `You are a professional {tool description} with expertise in {relevant domain}. Your task is to generate high-quality, {tool-specific adjectives} content that meets the user's requirements. Core Guidelines: - Always provide practical, actionable content - Ensure outputs are appropriate for the specified parameters - Maintain consistency with {tool domain} best practices - Generate content that inspires and educates users - Follow industry standards and creative conventions Quality Standards: - Content must be original and creative - Provide clear explanations and implementation guidance - Include relevant context and background information - Ensure accessibility and broad appeal - Optimize for user engagement and satisfaction Output Format (JSON): { "title": "Descriptive title for the generated content", "content": { // Tool-specific content structure }, "analysis": { "summary": "Brief overview of the generated content", "strengths": ["Key strengths", "Notable features"], "suggestions": ["Implementation tips", "Enhancement ideas"] }, "confidence": 0.85 // Quality confidence score (0-1) } Respond only in valid JSON format. Do not include any text outside the JSON structure.` } /** * Build user prompt - incorporates user preferences and options */ private buildUserPrompt(options: ToolOptions): string { let prompt = `Generate {tool-specific content} with the following specifications:\n\n` // Add tool-specific parameters Object.entries(options).forEach(([key, value]) => { if (value && value !== '') { prompt += `${key}: ${value}\n` } }) prompt += `\nRequirements: - Ensure content is high-quality and engaging - Follow {tool domain} best practices - Provide practical implementation guidance - Include relevant analysis and suggestions - Maintain appropriate tone and style Generate unique, creative content that exceeds user expectations.` return prompt } // =========================================== // OPTIMIZATION METHODS // =========================================== /** * Get optimal temperature based on tool type and options */ private getOptimalTemperature(options: ToolOptions): number { // Creative tools: higher temperature (0.7-0.9) // Analytical tools: lower temperature (0.3-0.5) // Default: balanced creativity (0.6) return 0.6 // Customize per tool } /** * Get maximum tokens based on tool complexity */ private getMaxTokens(options: ToolOptions): number { // Simple tools: 1000 tokens // Complex tools: 2000-3000 tokens // Default: 2000 tokens return 2000 // Customize per tool } /** * Calculate cost estimation based on token usage */ private calculateCost(usage: any): number { const tokensUsed = usage?.total_tokens || 0 // gpt-4o-mini pricing: $0.150 per 1M input tokens, $0.600 per 1M output tokens const inputCost = (usage?.prompt_tokens || 0) * 0.00015 / 1000 const outputCost = (usage?.completion_tokens || 0) * 0.0006 / 1000 return inputCost + outputCost } /** * Calculate confidence score based on response quality */ private calculateConfidence(response: any): number { let confidence = 0.7 // Base confidence // Adjust based on response completeness if (response.title && response.content) confidence += 0.1 if (response.analysis && response.analysis.suggestions?.length > 0) confidence += 0.1 if (Object.keys(response.content).length >= 3) confidence += 0.1 return Math.min(1.0, confidence) } // =========================================== // RESPONSE PROCESSING METHODS // =========================================== /** * Parse and validate AI response */ private parseAndValidateResponse(content: string | null): any { if (!content) { throw new Error('Empty AI response received') } try { const parsed = JSON.parse(content) // Validate required fields if (!parsed.title && !parsed.content) { throw new Error('Response missing required title or content') } // Validate content structure (tool-specific) this.validateContentStructure(parsed.content) return parsed } catch (error) { console.error('Response parsing error:', error) throw new Error(`Invalid AI response format: ${error.message}`) } } /** * Validate tool-specific content structure */ private validateContentStructure(content: any): void { // Implement tool-specific validation // Throw error if content doesn't meet requirements } /** * Generate title if not provided by AI */ private generateTitle(response: any, options: ToolOptions): string { // Generate fallback title based on tool type and options return `Generated {Tool} Content` } /** * Generate SEO metadata for content */ private generateSEOMetadata( response: any, options: ToolOptions ): { title: string; description: string; keywords: string[] } { const title = `${response.title || 'Generated Content'} | {Tool Name}` const description = `${this.generateDescription(response, options)}. AI-generated with MyStoryFlow's {tool name}.` const keywords = this.generateKeywords(response, options) return { title, description, keywords } } /** * Generate SEO description */ private generateDescription(response: any, options: ToolOptions): string { // Generate description based on content and options return `High-quality {tool output} generated with advanced AI technology` } /** * Generate SEO keywords */ private generateKeywords(response: any, options: ToolOptions): string[] { const baseKeywords = [ '{tool} generator', 'AI {tool}', 'creative writing', 'storytelling tools', 'content generation' ] // Add tool-specific keywords based on options Object.entries(options).forEach(([key, value]) => { if (value && typeof value === 'string') { baseKeywords.push(value.toLowerCase()) } }) return baseKeywords } }

🔧 Admin Integration Standards

Required Environment Variables

# =========================================== # CRITICAL: Admin Database Connection # =========================================== # Main app database for admin tracking (NOT tools database) NEXT_PUBLIC_SUPABASE_URL=https://your-main-app.supabase.co SUPABASE_SERVICE_ROLE_KEY=your_service_role_key # NOT SUPABASE_SERVICE_KEY # =========================================== # AI SERVICE CONFIGURATION # =========================================== OPENAI_API_KEY=sk-your-openai-key # =========================================== # CROSS-APP COMMUNICATION # =========================================== WEB_APP_URL=https://mystoryflow.com # For CORS and admin calls NEXT_PUBLIC_TOOLS_APP_URL=https://tools.mystoryflow.com # This app's URL

Admin Tracking Implementation

// Usage in API routes - REQUIRED for all AI generation import { trackAIUsage, storePromptInAdmin, getRecommendedToolsModel } from '@/lib/ai-usage-tracker' // =========================================== // PROMPT STORAGE (Before Generation) // =========================================== const promptId = await storePromptInAdmin({ name: `{tool}_generation_system_v1`, // Versioned prompt names version: '1.0', content: systemPrompt, // Full prompt content category: 'tools', // Always 'tools' for tool prompts tool_name: '{tool}', // Tool identifier description: 'System prompt for {tool} generation', is_active: true, metadata: { temperature: 0.6, max_tokens: 2000, model: 'gpt-4o-mini-2024-07-18' } }) // =========================================== // USAGE TRACKING (After Generation) // =========================================== await trackAIUsage({ sessionId: sessionId, // User session identifier featureName: `[Tools] {tool}_generation`, // CRITICAL: [Tools] prefix promptName: `{tool}_generation_v1`, // Matches stored prompt modelUsed: getRecommendedToolsModel(), // Standardized model provider: 'openai', // Always 'openai' tokensConsumed: result.usage.total_tokens, costUsd: result.estimatedCost, responseTimeMs: result.processingTime, requestSuccess: true, // or false if failed metadata: { toolType: '{tool}', requestId: context.requestId, optionsProvided: Object.keys(options), // Track which options were used variantGenerated: result.variantType, confidenceScore: result.confidenceScore, userType: sessionId.includes('sess_') ? 'anonymous' : 'registered' } }) // =========================================== // ERROR TRACKING (On Failures) // =========================================== await trackAIUsage({ sessionId: sessionId, featureName: `[Tools] {tool}_generation_error`, promptName: `{tool}_generation_v1`, requestSuccess: false, metadata: { error: error.message, stack: error.stack, requestId: context.requestId, failurePoint: 'ai_generation' // or 'parsing', 'validation', etc. } }).catch(console.error) // Don't let tracking errors crash the app

Model Selection Standards

// =========================================== // RECOMMENDED MODELS BY USE CASE // =========================================== // Standard Content Generation (Default) const standardModel = 'gpt-4o-mini-2024-07-18' // Cost-effective, fast // Complex Analysis or Long Content const complexModel = 'gpt-4o-2024-08-06' // Higher quality, more expensive // Simple Tasks or High Volume const simpleModel = 'gpt-3.5-turbo-0125' // Cheapest option // =========================================== // MODEL SELECTION LOGIC // =========================================== export function getRecommendedToolsModel(): string { // Always use gpt-4o-mini for tools unless specific requirements return 'gpt-4o-mini-2024-07-18' } export function getModelForComplexity(complexity: 'simple' | 'standard' | 'complex'): string { switch (complexity) { case 'simple': return 'gpt-3.5-turbo-0125' case 'complex': return 'gpt-4o-2024-08-06' case 'standard': default: return 'gpt-4o-mini-2024-07-18' } }

🎯 Prompt Engineering Standards

System Prompt Template

/** * Universal system prompt structure for all tools */ const SYSTEM_PROMPT_TEMPLATE = `You are a professional {ROLE} with extensive expertise in {DOMAIN}. IDENTITY & EXPERTISE: - {ROLE_DESCRIPTION} - Specialized knowledge in {SPECIALIZED_AREAS} - Committed to delivering high-quality, practical content CORE MISSION: Generate {OUTPUT_TYPE} that meets these standards: - Professional quality and accuracy - Practical applicability and usefulness - Creative and engaging presentation - Appropriate for the target audience - Aligned with industry best practices QUALITY REQUIREMENTS: 1. Originality: All content must be unique and creative 2. Relevance: Directly addresses user requirements 3. Clarity: Clear, understandable language and structure 4. Completeness: Comprehensive coverage of the topic 5. Actionability: Provides concrete, implementable guidance OUTPUT FORMAT: Respond in valid JSON format with this exact structure: { "title": "Descriptive, engaging title for the content", "content": { // Tool-specific content structure defined here }, "analysis": { "summary": "Brief overview of the generated content", "strengths": ["Key strength 1", "Key strength 2", "Key strength 3"], "applications": ["Use case 1", "Use case 2", "Use case 3"], "suggestions": ["Enhancement tip 1", "Implementation tip 2", "Best practice 3"] }, "metadata": { "complexity": "beginner|intermediate|advanced", "estimatedTime": "Time to implement/use", "categories": ["category1", "category2"], "confidence": 0.85 } } CRITICAL: Respond ONLY in valid JSON. No additional text outside the JSON structure.` /** * Apply template with tool-specific values */ export function buildSystemPrompt(toolConfig: { role: string domain: string roleDescription: string specializedAreas: string[] outputType: string contentStructure: object }): string { return SYSTEM_PROMPT_TEMPLATE .replace('{ROLE}', toolConfig.role) .replace('{DOMAIN}', toolConfig.domain) .replace('{ROLE_DESCRIPTION}', toolConfig.roleDescription) .replace('{SPECIALIZED_AREAS}', toolConfig.specializedAreas.join(', ')) .replace('{OUTPUT_TYPE}', toolConfig.outputType) .replace('// Tool-specific content structure defined here', JSON.stringify(toolConfig.contentStructure, null, 2)) }

User Prompt Standardization

/** * Universal user prompt builder */ export function buildUserPrompt( toolName: string, options: Record<string, any>, customInstructions?: string ): string { let prompt = `Generate ${toolName} content with the following specifications:\n\n` // Add structured parameters prompt += 'PARAMETERS:\n' Object.entries(options).forEach(([key, value]) => { if (value && value !== '' && value !== null) { const formattedKey = key.replace(/([A-Z])/g, ' $1').toLowerCase() prompt += `- ${formattedKey}: ${value}\n` } }) // Add custom instructions if provided if (customInstructions) { prompt += `\nADDITIONAL CONTEXT:\n${customInstructions}\n` } // Add quality requirements prompt += `\nQUALITY REQUIREMENTS: - Ensure content exceeds user expectations - Provide practical, actionable information - Include relevant context and background - Optimize for engagement and usability - Follow industry standards and best practices Generate unique, high-quality content that provides exceptional value to the user.` return prompt }

🔄 Response Processing Standards

Validation Pipeline

/** * Universal response validation pipeline */ export class ResponseValidator { /** * Validate basic response structure */ static validateStructure(response: any): void { if (!response) { throw new Error('Empty response received') } const required = ['title', 'content'] const missing = required.filter(field => !response[field]) if (missing.length > 0) { throw new Error(`Missing required fields: ${missing.join(', ')}`) } } /** * Validate content quality metrics */ static validateQuality(response: any): QualityMetrics { const metrics: QualityMetrics = { completeness: 0, relevance: 0, clarity: 0, creativity: 0, overall: 0 } // Completeness check const contentKeys = Object.keys(response.content || {}) metrics.completeness = Math.min(1.0, contentKeys.length / 5) // Expect ~5 content fields // Title and description quality if (response.title && response.title.length > 10) metrics.clarity += 0.25 if (response.analysis && response.analysis.summary) metrics.clarity += 0.25 if (response.analysis && response.analysis.suggestions?.length >= 3) metrics.relevance += 0.5 // Content depth const contentStr = JSON.stringify(response.content) if (contentStr.length > 500) metrics.creativity += 0.3 if (contentStr.length > 1000) metrics.creativity += 0.3 if (contentStr.length > 2000) metrics.creativity += 0.4 // Calculate overall score metrics.overall = (metrics.completeness + metrics.relevance + metrics.clarity + metrics.creativity) / 4 return metrics } /** * Validate tool-specific requirements */ static validateToolSpecific(response: any, toolName: string): void { const validators = { 'story-prompts': this.validateStoryPrompts, 'plot-twists': this.validatePlotTwists, 'character-generator': this.validateCharacterGenerator, // Add more tool-specific validators } const validator = validators[toolName] if (validator) { validator(response) } } private static validateStoryPrompts(response: any): void { if (!response.content.prompts || !Array.isArray(response.content.prompts)) { throw new Error('Story prompts must contain prompts array') } if (response.content.prompts.length < 3) { throw new Error('Must generate at least 3 story prompts') } } private static validatePlotTwists(response: any): void { if (!response.content.twists || !Array.isArray(response.content.twists)) { throw new Error('Plot twists must contain twists array') } response.content.twists.forEach((twist: any, index: number) => { if (!twist.twist || !twist.explanation) { throw new Error(`Plot twist ${index + 1} missing required fields`) } }) } private static validateCharacterGenerator(response: any): void { if (!response.content.character) { throw new Error('Character generator must contain character object') } const required = ['name', 'background', 'personality', 'motivation'] const missing = required.filter(field => !response.content.character[field]) if (missing.length > 0) { throw new Error(`Character missing required fields: ${missing.join(', ')}`) } } } interface QualityMetrics { completeness: number relevance: number clarity: number creativity: number overall: number }

⚡ Performance Optimization

Caching Strategies

/** * AI response caching for improved performance */ export class AICache { private static cache = new Map<string, any>() private static readonly CACHE_TTL = 3600000 // 1 hour /** * Generate cache key from options */ static generateCacheKey(toolName: string, options: any): string { const normalizedOptions = this.normalizeOptions(options) const optionsStr = JSON.stringify(normalizedOptions, Object.keys(normalizedOptions).sort()) return `${toolName}:${Buffer.from(optionsStr).toString('base64')}` } /** * Get cached response if available and not expired */ static getCached(cacheKey: string): any | null { const cached = this.cache.get(cacheKey) if (cached && Date.now() - cached.timestamp < this.CACHE_TTL) { return cached.data } // Clean up expired entry if (cached) { this.cache.delete(cacheKey) } return null } /** * Cache response with timestamp */ static setCached(cacheKey: string, data: any): void { this.cache.set(cacheKey, { data, timestamp: Date.now() }) // Cleanup old entries periodically if (this.cache.size > 1000) { this.cleanup() } } /** * Normalize options for consistent caching */ private static normalizeOptions(options: any): any { const normalized = { ...options } // Remove user-specific fields that shouldn't affect caching delete normalized.customContext delete normalized.userId delete normalized.sessionId // Normalize string values Object.keys(normalized).forEach(key => { if (typeof normalized[key] === 'string') { normalized[key] = normalized[key].trim().toLowerCase() } }) return normalized } /** * Clean up expired entries */ private static cleanup(): void { const now = Date.now() for (const [key, value] of this.cache.entries()) { if (now - value.timestamp > this.CACHE_TTL) { this.cache.delete(key) } } } }

Token Optimization

/** * Token usage optimization utilities */ export class TokenOptimizer { /** * Estimate token count for text (approximate) */ static estimateTokens(text: string): number { // Rough estimation: ~1 token per 4 characters for English text return Math.ceil(text.length / 4) } /** * Optimize prompt for token efficiency */ static optimizePrompt(prompt: string, maxTokens: number): string { const estimatedTokens = this.estimateTokens(prompt) if (estimatedTokens <= maxTokens) { return prompt } // Truncate while preserving structure const sections = prompt.split('\n\n') let optimized = sections[0] // Keep first section (usually most important) let currentTokens = this.estimateTokens(optimized) for (let i = 1; i < sections.length; i++) { const sectionTokens = this.estimateTokens(sections[i]) if (currentTokens + sectionTokens <= maxTokens * 0.9) { // Leave 10% buffer optimized += '\n\n' + sections[i] currentTokens += sectionTokens } else { break } } return optimized } /** * Get recommended max tokens for tool complexity */ static getRecommendedMaxTokens(complexity: 'simple' | 'standard' | 'complex'): number { switch (complexity) { case 'simple': return 1000 case 'complex': return 3000 case 'standard': default: return 2000 } } }

🔐 Security & Rate Limiting

Input Sanitization

/** * Input sanitization for AI prompts */ export class PromptSanitizer { /** * Sanitize user input for AI prompts */ static sanitizeInput(input: string): string { if (!input || typeof input !== 'string') { return '' } // Remove potentially harmful patterns let sanitized = input .replace(/[<>\"'&]/g, '') // Remove HTML characters .replace(/\b(system|assistant|user):/gi, '') // Remove role indicators .replace(/\{[^}]*\}/g, '') // Remove JSON-like structures .replace(/```[\s\S]*?```/g, '') // Remove code blocks .trim() // Limit length if (sanitized.length > 2000) { sanitized = sanitized.substring(0, 2000) + '...' } return sanitized } /** * Validate options object */ static validateOptions(options: any): any { const validated: any = {} Object.entries(options).forEach(([key, value]) => { if (typeof value === 'string') { validated[key] = this.sanitizeInput(value) } else if (typeof value === 'number' && !isNaN(value)) { validated[key] = Math.max(0, Math.min(100, value)) // Clamp to 0-100 range } else if (typeof value === 'boolean') { validated[key] = value } else if (Array.isArray(value)) { validated[key] = value.filter(item => typeof item === 'string').map(this.sanitizeInput) } }) return validated } /** * Check for prompt injection attempts */ static detectPromptInjection(input: string): boolean { const injectionPatterns = [ /ignore\s+(all\s+)?previous\s+instructions/i, /you\s+are\s+now\s+a?\s*\w+/i, /system\s*:\s*.+/i, /assistant\s*:\s*.+/i, /\[SYSTEM\]|\[ASSISTANT\]|\[USER\]/i, /role\s*=\s*["']?(system|assistant)["']?/i ] return injectionPatterns.some(pattern => pattern.test(input)) } }

This comprehensive AI integration standard ensures every MyStoryFlow tool delivers consistent, high-quality AI-generated content while maintaining cost efficiency, security, and performance optimization.