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 URLAdmin 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 appModel 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.