{"repo": "akil-26/mindmesh", "files": {"server/services/summarizeProvider.js": {"456cf3620df7fb69ba357ad5e1efc6aadc0f6f3d": {"t": 1786068265.9681435, "n": 35587, "h": "82094df150b20495", "c": "import 'dotenv/config'\nimport { GoogleGenerativeAI } from '@google/generative-ai'\nimport Groq from 'groq-sdk'\nimport OpenAI from 'openai'\nimport axios from 'axios'\n\nconst geminiKey = process.env.GEMINI_API_KEY\nlet geminiModel = null\nif (geminiKey) {\n try {\n const genAI = new GoogleGenerativeAI(geminiKey)\n geminiModel = genAI.getGenerativeModel({ model: 'gemini-2.0-flash-exp' })\n console.log(' [AI] Gemini initialized')\n } catch (e) {\n console.warn(' [AI] Gemini init failed:', e.message)\n }\n}\n\nconst groqKey = process.env.GROQ_API_KEY\nlet groqClient = null\nif (groqKey) {\n try {\n groqClient = new Groq({ apiKey: groqKey })\n console.log(' [AI] Groq initialized')\n } catch (e) {\n console.warn(' [AI] Groq init failed:', e.message)\n }\n}\n\nconst deepseekKey = process.env.DEEPSEEK_API_KEY\nlet deepseekClient = null\nif (deepseekKey) {\n try {\n deepseekClient = new OpenAI({ apiKey: deepseekKey, baseURL: 'https://api.deepseek.com' })\n console.log(' [AI] DeepSeek initialized')\n } catch (e) {\n console.warn(' [AI] DeepSeek init failed:', e.message)\n }\n}\n\nconst aimlKey = process.env.AIML_API_KEY\nconst aimlAvailable = !!aimlKey\nif (aimlAvailable) console.log(' [AI] AIML configured')\n\nconst hasProvider = !!(geminiModel || groqClient || deepseekClient || aimlAvailable)\nif (!hasProvider) console.error(' [AI] NO PROVIDERS AVAILABLE')\n\nconst STYLE_TARGETS = {\n // Standard lengths\n short: { minWords: 30, maxWords: 60 },\n medium: { minWords: 100, maxWords: 180 },\n long: { minWords: 300, maxWords: 600 },\n bullets: { minWords: 100, maxWords: 250 },\n \n // Executive style (all lengths)\n 'executive-short': { minWords: 40, maxWords: 80 },\n 'executive-medium': { minWords: 100, maxWords: 180 },\n 'executive-long': { minWords: 250, maxWords: 450 },\n 'executive-bullets': { minWords: 100, maxWords: 200 },\n \n // Academic style (all lengths)\n 'academic-short': { minWords: 50, maxWords: 100 },\n 'academic-medium': { minWords: 150, maxWords: 300 },\n 'academic-long': { minWords: 400, maxWords: 700 },\n 'academic-bullets': { minWords: 150, maxWords: 300 },\n \n // Casual style (all lengths)\n 'casual-short': { minWords: 30, maxWords: 60 },\n 'casual-medium': { minWords: 100, maxWords: 180 },\n 'casual-long': { minWords: 250, maxWords: 500 },\n 'casual-bullets': { minWords: 80, maxWords: 180 },\n \n // Technical style (all lengths)\n 'technical-short': { minWords: 40, maxWords: 80 },\n 'technical-medium': { minWords: 150, maxWords: 280 },\n 'technical-long': { minWords: 350, maxWords: 650 },\n 'technical-bullets': { minWords: 120, maxWords: 250 },\n \n // Storytelling style (all lengths)\n 'storytelling-short': { minWords: 40, maxWords: 80 },\n 'storytelling-medium': { minWords: 120, maxWords: 220 },\n 'storytelling-long': { minWords: 300, maxWords: 600 },\n 'storytelling-bullets': { minWords: 100, maxWords: 200 }\n}\n\nexport async function summarize(text, { style = 'medium' } = {}) {\n const cleaned = (text || '').trim()\n if (!cleaned) return { summary: 'No content', provider: 'none', highlights: [], chunks: 0 }\n if (!hasProvider) throw new Error('No AI providers available')\n\n console.log(`🚀 [Summarize] ${cleaned.length} chars, style: ${style}`)\n \n const chunks = chunkText(cleaned, 12000)\n console.log(`📦 [Chunks] ${chunks.length} chunk(s)`)\n \n const summaries = []\n for (let i = 0; i < chunks.length; i++) {\n console.log(`📝 [Chunk ${i + 1}/${chunks.length}]`)\n const result = await processWithRaceAndQuality(chunks[i], style)\n summaries.push(result)\n }\n \n let finalSummary = summaries.length === 1 ? summaries[0] : await processWithRaceAndQuality(summaries.join('\\n\\n'), style)\n const highlights = extractHighlights(cleaned)\n \n console.log('✅ [Complete]\\n')\n return { summary: finalSummary, provider: 'gemini', highlights, chunks: chunks.length }\n}\n\nasync function processWithRaceAndQuality(text, style) {\n console.log('🏁 [Race] DeepSeek vs Groq')\n let summary = await raceProviders(text, style)\n \n console.log('🔍 [Quality] Evaluating')\n const quality = evaluateQuality(summary, text, style)\n \n if (quality.pass) {\n console.log('✅ [Quality] PASS')\n return summary\n }\n \n console.log(`❌ [Quality] FAIL - ${quality.reason}`)\n console.log('🔄 [Rework] Trying fallback')\n \n try {\n const reworked = await callFallbackProvider(text, style, quality.feedback)\n console.log('✅ [Rework] Success')\n return reworked\n } catch (e) {\n console.warn('⚠️ [Rework] Failed:', e.message)\n return summary\n }\n}\n\nasync function raceProviders(text, style) {\n const racers = []\n \n if (deepseekClient) {\n racers.push(callProvider('deepseek', text, style)\n .then(result => ({ provider: 'deepseek', result, error: null }))\n .catch(err => ({ provider: 'deepseek', result: null, error: err.message })))\n }\n \n if (groqClient) {\n racers.push(callProvider('groq', text, style)\n .then(result => ({ provider: 'groq', result, error: null }))\n .catch(err => ({ provider: 'groq', result: null, error: err.message })))\n }\n \n if (racers.length === 0) {\n console.log('⚠️ [Race] No fast providers')\n return callFallbackProvider(text, style)\n }\n \n const winner = await Promise.race(racers)\n \n if (winner.error) {\n // Log provider failure with the underlying error message for debugging\n console.warn(`⚠️ [Race] ${winner.provider} failed: ${winner.error}`)\n const all = await Promise.allSettled(racers)\n // If any other racer succeeded, use it\n const success = all.find(r => r.status === 'fulfilled' && r.value && r.value.result && !r.value.error)\n if (success) {\n console.log(`✅ [Race] Backup: ${success.value.provider}`)\n return success.value.result\n }\n // None succeeded - log detailed errors for each racer then fallback\n const errors = all.map(r => {\n if (r.status === 'fulfilled') return `${r.value.provider}: ${r.value.error || 'no error'}`\n if (r.status === 'rejected') return `rejected: ${r.reason?.message || r.reason}`\n return 'unknown'\n }).join(' | ')\n console.error(`⚠️ [Race] All racers failed. Details: ${errors}`)\n return callFallbackProvider(text, style)\n }\n \n console.log(`🏆 [Race] Winner: ${winner.provider}`)\n return winner.result\n}\n\nasync function callFallbackProvider(text, style, feedback = null) {\n const providers = []\n if (aimlAvailable) providers.push('aiml')\n if (geminiModel) providers.push('gemini')\n \n if (providers.length === 0) throw new Error('No fallback providers')\n \n for (const provider of providers) {\n try {\n console.log(`🔄 [Fallback] ${provider}`)\n const result = await callProvider(provider, text, style, feedback)\n console.log(`✅ [Fallback] ${provider} OK`)\n return result\n } catch (e) {\n console.warn(`⚠️ [Fallback] ${provider} failed: ${e?.message || e}`)\n }\n }\n \n throw new Error('All fallbacks failed')\n}\n\nasync function callProvider(provider, text, style, feedback = null) {\n const prompt = buildPrompt(text, style, feedback)\n \n switch (provider) {\n case 'deepseek': return await callDeepSeek(prompt)\n case 'groq': return await callGroq(prompt)\n case 'aiml': return await callAIML(prompt)\n case 'gemini': return await callGemini(prompt)\n default: throw new Error(`Unknown provider: ${provider}`)\n }\n}\n\nasync function callDeepSeek(prompt) {\n if (!deepseekClient) throw new Error('DeepSeek not initialized')\n const response = await deepseekClient.chat.completions.create({\n model: 'deepseek-chat',\n messages: [{ role: 'user', content: prompt }],\n temperature: 0.3,\n max_tokens: 1200\n })\n const content = response.choices[0].message.content.trim()\n // Remove literal \\n\\n escape sequences\n return content.replace(/\\\\n\\\\n/g, '\\n\\n').replace(/\\\\n/g, '\\n')\n}\n\nasync function callGroq(prompt) {\n if (!groqClient) throw new Error('Groq not initialized')\n const response = await groqClient.chat.completions.create({\n model: 'llama-3.3-70b-versatile',\n messages: [{ role: 'user', content: prompt }],\n temperature: 0.3,\n max_tokens: 1200\n })\n const content = response.choices[0].message.content.trim()\n // Remove literal \\n\\n escape sequences\n return content.replace(/\\\\n\\\\n/g, '\\n\\n').replace(/\\\\n/g, '\\n')\n}\n\nasync function callAIML(prompt) {\n if (!aimlAvailable) throw new Error('AIML not configured')\n const response = await axios.post('https://api.aimlapi.com/v1/chat/completions', {\n model: 'gpt-4o-mini',\n messages: [{ role: 'user', content: prompt }],\n temperature: 0.3,\n max_tokens: 1200\n }, {\n headers: { 'Authorization': `Bearer ${aimlKey}`, 'Content-Type': 'application/json' },\n timeout: 30000\n })\n const content = response.data.choices[0].message.content.trim()\n // Remove literal \\n\\n escape sequences\n return content.replace(/\\\\n\\\\n/g, '\\n\\n').replace(/\\\\n/g, '\\n')\n}\n\nasync function callGemini(prompt) {\n if (!geminiModel) throw new Error('Gemini not initialized')\n const result = await geminiModel.generateContent(prompt)\n const content = result.response.text().trim()\n // Remove literal \\n\\n escape sequences\n return content.replace(/\\\\n\\\\n/g, '\\n\\n').replace(/\\\\n/g, '\\n')\n}\n\nfunction buildPrompt(text, style, feedback = null) {\n const cfg = STYLE_TARGETS[style] || STYLE_TARGETS.medium\n \n // Parse style: could be \"short\", \"medium\", \"executive-long\", \"casual-bullets\", etc.\n const parts = style.split('-')\n const styleType = parts.length > 1 ? parts[0] : 'standard'\n const length = parts.length > 1 ? parts[1] : style\n \n // Determine tone instructions based on style type\n let toneInstr = ''\n switch (styleType) {\n case 'executive':\n toneInstr = `Executive/C-suite tone: Write for business leaders and decision-makers. Be strategic and action-oriented. \n Focus on business impact, ROI, competitive advantages, and key decisions. Emphasize outcomes, metrics, and actionable insights. \n Use confident, authoritative language. Highlight risks, opportunities, and strategic implications. Keep it results-focused and data-driven.`\n break\n case 'academic':\n toneInstr = `Academic/scholarly tone: Write in formal, rigorous academic style. Be objective, analytical, and evidence-based. \n Use proper scholarly terminology and discipline-specific language. Maintain logical structure with clear argumentation. \n Avoid casual expressions, contractions, and colloquialisms. Present information with academic precision and intellectual depth. \n Use third-person perspective. Include contextual analysis and theoretical frameworks where relevant.`\n break\n case 'casual':\n toneInstr = `Casual/conversational tone: Write as if explaining to a friend over coffee. Be warm, friendly, and approachable. \n Use everyday language, simple words, and natural expressions. Contractions are encouraged (it's, you'll, don't). \n Make it engaging and relatable—avoid jargon and complex terminology. Use \"you\" to address the reader directly. \n Keep sentences flowing naturally like spoken conversation. It's okay to be enthusiastic and personable.`\n break\n case 'technical':\n toneInstr = `Technical tone: Write for technical experts and practitioners. Use precise, domain-specific terminology without over-explaining. \n Include technical specifications, methodologies, algorithms, and implementation details. Be accurate and unambiguous. \n Use industry-standard terms, acronyms, and technical concepts. Focus on how things work, not just what they do. \n Maintain technical rigor—include parameters, configurations, and technical constraints. Assume reader has technical background.`\n break\n case 'storytelling':\n toneInstr = `Storytelling/narrative tone: Present information as an engaging story with clear narrative arc. Set the scene with context, \n introduce the situation or challenge, describe the journey or process, and conclude with outcomes or resolution. \n Use narrative elements—characters, conflict, progression, and resolution. Make it flow naturally with temporal progression. \n Create vivid descriptions and compelling progression. Maintain human interest while preserving factual accuracy. \n Use transitions that guide readers through the narrative journey.`\n break\n default:\n toneInstr = `Professional balanced tone: Write in clear, neutral, and informative style suitable for business communication. \n Be objective and professional without being overly formal or too casual. Use precise language that is accessible to general audiences. \n Maintain credibility and authority while staying approachable. Avoid jargon unless necessary. Present facts clearly and logically.`\n break\n }\n \n // Determine length instructions\n let lengthInstr = ''\n switch (length) {\n case 'short':\n lengthInstr = `VERY SHORT summary in 1-2 sentences (${cfg.minWords}-${cfg.maxWords} words). Core message only.`\n break\n case 'medium':\n lengthInstr = `MEDIUM summary as one paragraph (${cfg.minWords}-${cfg.maxWords} words). Main points and key details.`\n break\n case 'long':\n lengthInstr = `COMPREHENSIVE summary (${cfg.minWords}-${cfg.maxWords} words). Multiple paragraphs with all important aspects.`\n break\n case 'bullets':\n lengthInstr = `BULLET POINT summary with 5-8 points (${cfg.minWords}-${cfg.maxWords} words total). Start each with \"• \".`\n break\n }\n \n let reworkInstr = feedback ? `\\n\\n⚠️ IMPORTANT - Address:\\n${feedback}\\n` : ''\n \n return `You are an expert summarization assistant.\n\nTONE: ${toneInstr}\n\nLENGTH: ${lengthInstr}\n\nRULES:\n- Preserve all key facts and details\n- Do NOT add information not in source\n- Match the specified tone throughout\n- Plain text only (no markdown ** or __)\n${length === 'bullets' ? '- Start each bullet with \"• \" on new line' : ''}\n${length === 'long' ? '- Separate paragraphs with \\\\n\\\\n' : ''}\n${styleType === 'executive' ? '- Focus on strategic insights and actionable takeaways' : ''}\n${styleType === 'technical' ? '- Use domain-specific terminology and precise language' : ''}\n${styleType === 'storytelling' ? '- Create narrative flow: set scene, describe journey, show outcomes' : ''}\n${styleType === 'casual' ? '- Use conversational language, contractions okay' : ''}\n${styleType === 'academic' ? '- Maintain formal scholarly language and structure' : ''}\n${reworkInstr}\nINPUT TEXT:\n\"\"\"\n${text}\n\"\"\"\n\nYOUR SUMMARY:`\n}\n\nfunction evaluateQuality(summary, originalText, style) {\n const cfg = STYLE_TARGETS[style] || STYLE_TARGETS.medium\n const words = summary.split(/\\s+/).filter(w => w.length > 0).length\n const sentences = summary.split(/[.!?]+/).filter(s => s.trim().length > 0).length\n \n // Parse style to check format and tone\n const isBullets = style.endsWith('-bullets') || style === 'bullets'\n const isShort = style.endsWith('-short') || style === 'short'\n const isLong = style.endsWith('-long') || style === 'long'\n const parts = style.split('-')\n const styleType = parts.length > 1 ? parts[0] : 'standard'\n \n // 1. CHECK: Word count within range\n if (words < cfg.minWords) {\n return {\n pass: false,\n reason: `Too short (${words} words)`,\n feedback: `CRITICAL LENGTH ISSUE: Your summary is only ${words} words but needs ${cfg.minWords}-${cfg.maxWords} words.\n\nREQUIRED ACTIONS:\n• Expand the summary significantly by adding more specific details, concrete examples, and important context\n• Include ALL key facts, findings, and insights from the source material\n• Add supporting information and explanations for main points\n• DO NOT just repeat the same information - add NEW details and depth\n• Reach the target word count naturally by being thorough and comprehensive, not by adding fluff`\n }\n }\n \n if (words > cfg.maxWords * 1.3) {\n return {\n pass: false,\n reason: `Too long (${words} words)`,\n feedback: `CRITICAL LENGTH ISSUE: Your summary is ${words} words but should be ${cfg.minWords}-${cfg.maxWords} words.\n\nREQUIRED ACTIONS:\n• Cut down the summary by removing redundant information and repetitive phrases\n• Focus ONLY on the most important key points - eliminate secondary details\n• Combine similar ideas into single, concise statements\n• Remove any unnecessary adjectives, adverbs, and filler words\n• Every word must add value - if it doesn't, remove it\n• Be more selective about what information to include`\n }\n }\n \n // 2. CHECK: Bullet format and structure\n if (isBullets) {\n const hasBullets = /^[•*\\d-]/m.test(summary)\n if (!hasBullets) {\n return {\n pass: false,\n reason: 'Missing bullet format',\n feedback: `CRITICAL FORMATTING ERROR: This must be a BULLET LIST format, not a paragraph.\n\nREQUIRED FORMAT:\n• Start each point with \"• \" (bullet symbol followed by space)\n• Put each bullet point on a NEW LINE\n• Provide 5-8 distinct bullet points\n• Each bullet must be a complete, standalone statement\n• Do NOT write paragraphs - write bullets only\n\nEXAMPLE FORMAT:\n• First key point here with complete information\n• Second key point covering different aspect\n• Third key point with specific details\n• Fourth key point highlighting important finding\n• Fifth key point presenting unique insight\n\nIMPORTANT: The format MUST match this structure exactly. No paragraphs allowed.`\n }\n }\n const bulletCount = (summary.match(/^[•*-]/gm) || []).length\n if (bulletCount < 4) {\n return {\n pass: false,\n reason: 'Too few bullets',\n feedback: `BULLET COUNT ERROR: You provided only ${bulletCount} bullet point(s) but need 5-8 bullets.\n\nREQUIRED ACTIONS:\n• Create ${5 - bulletCount} more distinct bullet points\n• Each bullet must cover a DIFFERENT key aspect from the source\n• Break down complex information into separate, organized points\n• Each bullet should be substantial and informative (not just one word)\n• Cover different themes: main finding, methodology, implications, context, details, etc.\n• DO NOT repeat the same information across bullets - each must be unique\n\nMAKE SURE: Every bullet provides NEW and VALUABLE information from the source material.`\n }\n }\n }\n \n // 3. CHECK: Generic phrases (low quality)\n const genericPhrases = [\n 'the text discusses', 'the document talks about', 'this content is about', \n 'the article covers', 'the passage explains', 'this text describes',\n 'the author mentions', 'it is stated that', 'according to the text'\n ]\n const lowerSummary = summary.toLowerCase()\n const hasGeneric = genericPhrases.some(phrase => lowerSummary.includes(phrase))\n \n if (hasGeneric) {\n const foundPhrase = genericPhrases.find(phrase => lowerSummary.includes(phrase))\n return {\n pass: false,\n reason: 'Too generic and vague',\n feedback: `PRESENTATION QUALITY ERROR: Summary uses meta-descriptive language (\"${foundPhrase}\") instead of presenting information directly.\n\nREQUIRED ACTIONS:\n• Remove ALL phrases like: \"the text discusses\", \"the document talks about\", \"the article covers\"\n• Present the actual CONTENT and FINDINGS directly\n• Write as if YOU are presenting the information, not describing what a document says\n• Replace meta-phrases with direct statements of fact\n• Focus on WHAT is known, discovered, or explained - not on what the document does\n\nBAD EXAMPLE: \"The text discusses how solar panels work...\"\nGOOD EXAMPLE: \"Solar panels convert sunlight into electricity using photovoltaic cells...\"\n\nBAD EXAMPLE: \"According to the text, climate change affects ecosystems...\"\nGOOD EXAMPLE: \"Climate change disrupts ecosystems through temperature shifts, habitat loss, and species migration...\"\n\nBAD EXAMPLE: \"The author mentions that AI has limitations...\"\nGOOD EXAMPLE: \"AI systems face limitations in common sense reasoning, contextual understanding, and creativity...\"\n\nREMEMBER: You are presenting information, not describing a document. Be direct, authoritative, and factual.`\n }\n }\n \n // 4. CHECK: Unnecessary filler words\n const fillerPhrases = [\n 'in conclusion', 'to sum up', 'in summary', 'overall',\n 'it can be said that', 'it is important to note', 'it should be mentioned',\n 'basically', 'essentially', 'simply put'\n ]\n const hasFillers = fillerPhrases.some(phrase => lowerSummary.includes(phrase))\n \n if (hasFillers) {\n const foundFiller = fillerPhrases.find(phrase => lowerSummary.includes(phrase))\n return {\n pass: false,\n reason: 'Contains unnecessary filler words',\n feedback: `CONCISENESS ERROR: Summary contains filler phrase (\"${foundFiller}\") that adds no value and wastes words.\n\nREQUIRED ACTIONS:\n• Remove ALL filler phrases immediately: \"in conclusion\", \"to sum up\", \"in summary\", \"overall\", \"basically\", \"essentially\", \"simply put\", \"it can be said that\", \"it is important to note\", \"it should be mentioned\"\n• Present information DIRECTLY without transitional fluff\n• Start sentences with the actual content, not meta-commentary\n• Every word must carry meaning and information\n• Replace vague phrases with specific facts and details\n• Be crisp, direct, and information-dense\n\nBAD EXAMPLE: \"In conclusion, the project was successful...\"\nGOOD EXAMPLE: \"The project achieved all targets, delivering 30% cost savings...\"\n\nBAD EXAMPLE: \"Basically, AI uses algorithms to learn patterns...\"\nGOOD EXAMPLE: \"AI uses machine learning algorithms to identify patterns in data...\"\n\nBAD EXAMPLE: \"It is important to note that climate affects agriculture...\"\nGOOD EXAMPLE: \"Climate directly impacts crop yields, growing seasons, and irrigation needs...\"\n\nREMEMBER: Every word counts toward your word limit. Use them for information, not filler.`\n }\n }\n \n // 5. CHECK: Structure and readability\n if (!isShort && !isBullets && sentences < 2) {\n return {\n pass: false,\n reason: 'Insufficient structure',\n feedback: `STRUCTURE ERROR: Summary has only ${sentences} sentence(s) but needs proper multi-sentence structure for this format.\n\nREQUIRED ACTIONS:\n• Write at least 3-5 well-formed, complete sentences\n• Each sentence should present distinct information or different aspects\n• Break down complex information into multiple digestible sentences\n• Create logical flow from one sentence to the next\n• Vary sentence structure and length for better readability\n• Ensure each sentence is substantial and informative\n\nGOOD STRUCTURE EXAMPLE:\n\"Artificial intelligence revolutionizes healthcare through predictive diagnostics and personalized treatment plans. Machine learning algorithms analyze patient data to identify disease patterns earlier than traditional methods. The technology reduces diagnostic errors by 40% while cutting costs by 30%. However, implementation challenges include data privacy concerns and the need for extensive training datasets. Future developments focus on integrating AI with wearable devices for real-time health monitoring.\"\n\nREMEMBER: Multiple sentences allow you to organize information clearly and cover different aspects thoroughly.`\n }\n }\n \n // 6. CHECK: Long format should have paragraphs\n if (isLong && !summary.includes('\\n\\n')) {\n return {\n pass: false,\n reason: 'Long format needs paragraph breaks',\n feedback: `FORMATTING ERROR: Long summaries MUST be organized into multiple paragraphs with proper breaks (\\\\n\\\\n between paragraphs).\n\nREQUIRED ACTIONS:\n• Divide your summary into 2-4 distinct paragraphs\n• Separate paragraphs with double line break (\\\\n\\\\n)\n• Each paragraph should cover a different theme or aspect:\n - Paragraph 1: Main findings or core concepts\n - Paragraph 2: Supporting details, methodology, or context\n - Paragraph 3: Implications, applications, or related information\n - Paragraph 4 (if needed): Future directions or conclusions\n• Each paragraph should be 3-5 sentences\n• Create logical flow between paragraphs\n• Make it visually easy to read and scan\n\nGOOD FORMAT EXAMPLE:\n\"First paragraph covers main concept with key points and primary findings. It establishes context and introduces the core ideas. This section should be comprehensive yet focused.\n\nSecond paragraph dives into supporting details, methodology, or specific examples. It provides depth and elaboration on the main concepts. Technical details and evidence appear here.\n\nThird paragraph discusses implications, applications, or broader context. It connects ideas and shows relevance. Future directions or conclusions may be presented here.\"\n\nREMEMBER: Long summaries without paragraph breaks are hard to read. Break them up for better user experience.`\n }\n }\n \n // 7. CHECK: Repetition (same words repeated too often)\n const wordFreq = {}\n const contentWords = summary.toLowerCase().split(/\\s+/).filter(w => \n w.length > 5 && !['their', 'there', 'which', 'where', 'these', 'those', 'would', 'could', 'should'].includes(w)\n )\n contentWords.forEach(word => {\n wordFreq[word] = (wordFreq[word] || 0) + 1\n })\n const repeatedWords = Object.entries(wordFreq).filter(([, count]) => count > 3)\n \n if (repeatedWords.length > 0) {\n const repeated = repeatedWords.map(([word, count]) => `\"${word}\" (${count} times)`).slice(0, 5).join(', ')\n return {\n pass: false,\n reason: 'Excessive word repetition',\n feedback: `REPETITION ERROR: Multiple words repeated excessively: ${repeated}\n\nREQUIRED ACTIONS:\n• Identify all overused words and replace most instances with synonyms\n• Vary your vocabulary while maintaining meaning and accuracy\n• Use a thesaurus if needed to find appropriate alternatives\n• Keep one or two mentions of key technical terms, but vary everything else\n• Rephrase sentences to naturally use different words\n• Make the text more engaging through linguistic variety\n\nSYNONYM SUGGESTIONS (examples):\n• \"important\" → significant, crucial, vital, essential, key\n• \"shows\" → demonstrates, reveals, indicates, illustrates, displays\n• \"method\" → approach, technique, process, strategy, system\n• \"increase\" → growth, rise, expansion, enhancement, boost\n• \"analyze\" → examine, evaluate, assess, study, investigate\n\nREMEMBER: Repetition makes summaries boring and unprofessional. Use varied vocabulary to maintain reader engagement.`\n }\n }\n \n // 8. CHECK: Style-specific tone validation\n if (styleType === 'academic') {\n // Check for casual language in academic style\n const casualWords = ['gonna', 'wanna', \"can't\", \"won't\", \"isn't\", \"don't\", 'really', 'very', 'super', 'cool', 'awesome']\n const hasCasual = casualWords.some(word => lowerSummary.includes(word))\n if (hasCasual) {\n const foundCasual = casualWords.filter(word => lowerSummary.includes(word)).join(', ')\n return {\n pass: false,\n reason: 'Inappropriate tone for academic style',\n feedback: `TONE MISMATCH ERROR: Academic style requires FORMAL scholarly language, but your summary contains casual/informal words: ${foundCasual}\n\nREQUIRED ACTIONS:\n• Remove ALL contractions: \"can't\" → \"cannot\", \"won't\" → \"will not\", \"isn't\" → \"is not\", \"don't\" → \"do not\"\n• Replace casual intensifiers: \"really\" → \"significantly\", \"very\" → \"considerably\", \"super\" → \"extremely\"\n• Remove colloquial terms: \"cool\", \"awesome\", \"gonna\", \"wanna\"\n• Use formal scholarly terminology and complete proper words\n• Maintain objective third-person perspective throughout\n• Use precise academic vocabulary appropriate to the field\n\nBAD EXAMPLE: \"The study shows AI is really cool and can't be beaten in some tasks...\"\nGOOD EXAMPLE: \"The research demonstrates that artificial intelligence systems exhibit superior performance in specific computational tasks...\"\n\nREMEMBER: Academic style = formal, objective, precise, and scholarly. No casual or conversational language allowed.`\n }\n }\n }\n \n if (styleType === 'casual') {\n // Check if casual style is too formal\n const tooFormal = /\\b(furthermore|consequently|notwithstanding|heretofore|aforementioned)\\b/i.test(summary)\n if (tooFormal) {\n const matches = summary.match(/\\b(furthermore|consequently|notwithstanding|heretofore|aforementioned)\\b/gi)\n const formalWords = [...new Set(matches)].join(', ')\n return {\n pass: false,\n reason: 'Too formal for casual style',\n feedback: `TONE MISMATCH ERROR: Casual style should be FRIENDLY and CONVERSATIONAL, but your summary uses overly formal/stiff words: ${formalWords}\n\nREQUIRED ACTIONS:\n• Replace formal connectors with casual ones:\n - \"furthermore\" → \"also\", \"plus\", \"and\"\n - \"consequently\" → \"so\", \"that's why\", \"because of this\"\n - \"notwithstanding\" → \"even though\", \"despite\"\n - \"heretofore\" → \"until now\", \"so far\"\n - \"aforementioned\" → \"the above\", \"what we talked about\"\n• Use simple, everyday words that you'd use talking to a friend\n• Contractions are GOOD in casual style: \"it's\", \"don't\", \"can't\", \"you'll\"\n• Write as if explaining over coffee - warm, friendly, approachable\n• Use active voice and direct language\n\nBAD EXAMPLE: \"Furthermore, the aforementioned technique demonstrates considerable efficacy...\"\nGOOD EXAMPLE: \"Plus, the technique we talked about works really well...\"\n\nREMEMBER: Casual style = friendly, conversational, simple. Write like you're talking to a friend.`\n }\n }\n }\n \n if (styleType === 'executive') {\n // Check if executive style lacks business focus\n const hasBusinessLanguage = /\\b(impact|strategic|action|decision|ROI|value|opportunity|risk|outcome|business|market|revenue|cost|efficiency)\\b/i.test(summary)\n if (!hasBusinessLanguage && words > 50) {\n return {\n pass: false,\n reason: 'Missing business focus for executive style',\n feedback: `TONE MISMATCH ERROR: Executive summaries must focus on BUSINESS IMPACT and STRATEGIC VALUE, but your summary lacks business-oriented language.\n\nREQUIRED ACTIONS:\n• Frame information in terms of business outcomes and value\n• Include at least 3-4 of these business elements:\n - Strategic impact or competitive advantages\n - ROI, cost savings, or revenue potential\n - Key decisions or action items for leaders\n - Business risks or opportunities\n - Market implications or business applications\n - Efficiency gains or performance metrics\n• Focus on \"So what?\" for business leaders - why does this matter to the organization?\n• Present information through a business lens, not just technical or academic details\n• Use action-oriented language that drives decisions\n\nBAD EXAMPLE: \"The new software uses advanced algorithms to process data faster and more accurately than previous versions...\"\nGOOD EXAMPLE: \"The new software delivers 40% faster processing, reducing operational costs by $200K annually while improving decision-making accuracy—creating competitive advantage in real-time market response...\"\n\nREMEMBER: Executive style = business impact, strategic value, actionable insights for decision-makers.`\n }\n }\n }\n \n // 9. CHECK: Empty or placeholder content\n if (summary.includes('[') || summary.includes('...') || summary.includes('etc.') || summary.includes('and so on')) {\n const issues = []\n if (summary.includes('[')) issues.push('brackets/placeholders [...]')\n if (summary.includes('...')) issues.push('ellipsis (...)')\n if (summary.includes('etc.')) issues.push('\"etc.\"')\n if (summary.includes('and so on')) issues.push('\"and so on\"')\n \n return {\n pass: false,\n reason: 'Contains placeholders or vague endings',\n feedback: `COMPLETENESS ERROR: Summary contains incomplete or vague content: ${issues.join(', ')}\n\nREQUIRED ACTIONS:\n• Remove ALL placeholder markers: [...], [insert here], [to be added]\n• Replace ellipsis (...) with complete information - finish your thoughts\n• Replace \"etc.\" with ACTUAL examples or specific items\n• Replace \"and so on\" with concrete details or specific examples\n• Every sentence must be complete and fully formed\n• Provide specific, concrete information instead of vague references\n• If you can't list all items, list the most important 3-5 specifically\n\nBAD EXAMPLE: \"The benefits include cost savings, efficiency, productivity, etc.\"\nGOOD EXAMPLE: \"The benefits include 30% cost savings, 40% faster processing, 25% productivity gains, and improved accuracy.\"\n\nBAD EXAMPLE: \"Key factors are technology, market trends, and so on...\"\nGOOD EXAMPLE: \"Key factors are emerging AI technology, shifting consumer preferences toward sustainability, and increased regulatory requirements.\"\n\nBAD EXAMPLE: \"The process involves [...] and data analysis.\"\nGOOD EXAMPLE: \"The process involves data collection via automated sensors, preprocessing to remove noise, statistical analysis using regression models, and validation through cross-checking.\"\n\nREMEMBER: Be specific, complete, and concrete. No vague endings or incomplete thoughts allowed.`\n }\n }\n \n // 10. CHECK: Starts with meta-description\n const badStarts = ['this summary', 'this document', 'this text', 'this article', 'the following']\n const firstWords = summary.toLowerCase().substring(0, 50)\n const hasBadStart = badStarts.some(phrase => firstWords.includes(phrase))\n \n if (hasBadStart) {\n const foundStart = badStarts.find(phrase => firstWords.includes(phrase))\n return {\n pass: false,\n reason: 'Starts with meta-description',\n feedback: `OPENING ERROR: Summary starts with meta-descriptive phrase (\"${foundStart}\") instead of jumping directly into content.\n\nREQUIRED ACTIONS:\n• NEVER start with: \"This summary...\", \"This document...\", \"This text...\", \"This article...\", \"The following...\"\n• Start immediately with your MOST IMPORTANT information or key finding\n• Open with a strong, compelling statement that delivers value\n• First sentence should hook the reader with substance, not describe the summary\n• Make every word count - especially the critical first sentence\n\nBAD EXAMPLES:\n❌ \"This summary provides an overview of artificial intelligence applications...\"\n❌ \"This document discusses the benefits of renewable energy...\"\n❌ \"The following text examines climate change impacts...\"\n\nGOOD EXAMPLES:\n✅ \"Artificial intelligence revolutionizes healthcare through 40% faster diagnostics and personalized treatment plans...\"\n✅ \"Renewable energy costs dropped 89% since 2010, making solar and wind cheaper than fossil fuels...\"\n✅ \"Climate change drives unprecedented ecosystem disruption, threatening 1 million species with extinction...\"\n\nPOWER OPENING STRATEGIES:\n• State the main finding or conclusion first\n• Lead with a striking fact or statistic\n• Present the core concept or breakthrough directly\n• Highlight the most important implication or outcome\n• Jump straight into what matters most\n\nREMEMBER: Your opening sentence is prime real estate. Use it for high-value content, not meta-commentary.`\n }\n }\n \n return { pass: true }\n}\n\nfunction chunkText(text, maxChars) {\n if (text.length <= maxChars) return [text]\n const chunks = []\n let start = 0\n while (start < text.length) {\n const end = Math.min(start + maxChars, text.length)\n chunks.push(text.slice(start, end))\n start = end\n }\n return chunks\n}\n\nfunction extractHighlights(text, max = 5) {\n const sentences = (text.replace(/\\s+/g, ' ').match(/[^.!?]+[.!?]/g) || [text])\n .map(s => s.trim())\n .filter(s => s.length > 20)\n \n if (sentences.length === 0) return []\n \n const scored = sentences.map(s => {\n const lengthScore = Math.min(s.length / 100, 1) * 0.5\n const keywordCount = (s.match(/[A-Z][a-z]+/g) || []).length\n const keywordScore = Math.min(keywordCount / 10, 1) * 0.5\n return { s, score: lengthScore + keywordScore }\n })\n \n scored.sort((a, b) => b.score - a.score)\n return scored.slice(0, max).map(o => o.s)\n}\n"}}}}