Free Essay Generator

Essay Generator – Single‑file (Offline + API Mode)
Essay Generator
Works offline (template mode) • Optional AI mode via your own API key or n8n relay
Single‑file • No deps

Inputs

Tip: Be specific – add context or angle for better results.

Mode

Unchecked = Offline template mode (no external calls). Checked = call your API (OpenAI‑style) in the browser. Mind your API key

Output

0 words
Tip: You can edit the essay directly in the box above before exporting.
`; download('essay.doc', 'application/msword', docHtml); } function downloadMd(text){ download('essay.md', 'text/markdown', text); } // --- Offline Template Generator --- const L = { en: { introHooks:[ 'Few issues spark as much debate as', 'In recent years, the conversation around', 'Beneath the headlines, a deeper question lingers about', 'From classrooms to boardrooms, people are grappling with', 'At first glance, it may seem simple, yet the reality of' ], transitions:['Moreover','Furthermore','However','Nevertheless','In addition','By contrast','Consequently','Therefore','Notably','Crucially'], counters:['Skeptics argue that','A common objection is that','Some contend that','Critics warn that','It is sometimes claimed that'], rebuttals:['This concern matters, yet','While important, this claim overlooks that','Even so, evidence suggests','Still, a closer look reveals','Granted—but it remains true that'], conclude:['Ultimately','In conclusion','Taken together','Stepping back','Looking ahead'], thesisLead:['This essay argues that','I contend that','This discussion maintains that','The central claim here is that','The evidence points to this thesis:'], title:(subject)=>`An Essay on ${subject.charAt(0).toUpperCase()+subject.slice(1)}`, toc:'Outline', placeholders:{apa:'(Author, YEAR)', mla:'(Author page)'} }, fr: { introHooks:[ 'Peu de questions suscitent autant de débats que', 'Ces dernières années, le débat autour de', 'Au‑delà des gros titres, une question demeure au sujet de', 'Des salles de classe aux entreprises, on s’interroge sur', 'À première vue le sujet paraît simple, mais la réalité de' ], transitions:['De plus','Par ailleurs','Cependant','Néanmoins','En outre','À l’inverse','Par conséquent','Donc','Notamment','Surtout'], counters:['Les sceptiques soutiennent que','Une objection fréquente veut que','Certains avancent que','Des critiques avertissent que','On affirme parfois que'], rebuttals:['Cette préoccupation est légitime, mais','Bien que pertinent, cet argument omet que','Pourtant, les données indiquent','Toutefois, un examen attentif révèle','Soit—mais il n’en demeure pas moins que'], conclude:['En définitive','En conclusion','Dans l’ensemble','Avec du recul','Pour l’avenir'], thesisLead:['Cet essai soutient que','Nous défendons l’idée selon laquelle','La thèse centrale est que','L’argument principal est que','Les éléments conduisent à la thèse suivante :'], title:(subject)=>`Essai sur ${subject.charAt(0).toUpperCase()+subject.slice(1)}`, toc:'Plan', placeholders:{apa:'(Auteur, ANNÉE)', mla:'(Auteur page)'} } }; function pick(arr){ return arr[Math.floor(Math.random()*arr.length)] } function buildThesis(subject, stance, lang){ const lead = pick(L[lang].thesisLead); const verb = (stance==='pro') ? (lang==='en'?'that we should':'qu’il faut') : (stance==='con') ? (lang==='en'?'that we should not':'qu’il ne faut pas') : (lang==='en'?'that a balanced approach is needed for':'qu’une approche équilibrée s’impose face à'); return `${lead} ${verb} ${subject}.`; } function toKeywords(str){ return str ? str.split(',').map(s=>s.trim()).filter(Boolean) : []; } function sentenceCap(s){ return s.charAt(0).toUpperCase()+s.slice(1); } function makeParagraph(sentences){ return sentences.join(' ') } function offlineOutline(p){ const lang = p.language; const tr = L[lang]; const keywords = toKeywords(p.keywords); const thesis = p.thesis || buildThesis(p.subject, p.stance, lang); const outline = []; // Intro outline.push({ title: (lang==='en'?'Introduction':'Introduction'), bullets: [ `${pick(tr.introHooks)} ${p.subject}.`, thesis, (lang==='en'?'Roadmap of the arguments.':'Annonce du plan.') ] }); // Body sections depend on structure if(p.structure==='five' || p.structure==='thematic'){ outline.push({title: lang==='en'?'Background & Definitions':'Contexte et définitions', bullets:[ (lang==='en'?'Key terms and scope':'Termes clés et périmètre'), (lang==='en'?'Historical or recent context':'Contexte historique ou récent'), (lang==='en'?'Why the topic matters now':'Pourquoi le sujet importe aujourd’hui') ]}); outline.push({title: lang==='en'?'Primary Argument':'Argument principal', bullets:[ (lang==='en'?'Claim + brief evidence':'Assertion + brèves preuves'), (lang==='en'?'Example or data point':'Exemple ou donnée'), (lang==='en'?'Implications':'Implications') ]}); outline.push({title: lang==='en'?'Counterargument & Rebuttal':'Objection & Réfutation', bullets:[ `${pick(tr.counters)} …`, `${pick(tr.rebuttals)} …`, (lang==='en'?'Synthesis back to thesis':'Lien de synthèse vers la thèse') ]}); } else if(p.structure==='problem'){ outline.push({title: lang==='en'?'Problem':'Problème', bullets:[ (lang==='en'?'What exactly is the problem?':'Quel est précisément le problème ?'), (lang==='en'?'Who is affected?':'Qui est affecté ?'), (lang==='en'?'Magnitude & urgency':'Ampleur et urgence') ]}); outline.push({title: lang==='en'?'Causes':'Causes', bullets:[ (lang==='en'?'Root causes + examples':'Causes profondes + exemples'), (lang==='en'?'Systemic factors':'Facteurs systémiques') ]}); outline.push({title: lang==='en'?'Solutions':'Solutions', bullets:[ (lang==='en'?'Policy + practice suggestions':'Pistes politiques et pratiques'), (lang==='en'?'Trade‑offs & risks':'Arbitrages et risques') ]}); } else if(p.structure==='compare'){ outline.push({title: lang==='en'?'Point of Comparison':'Point de comparaison', bullets:[ (lang==='en'?'Criteria for comparison':'Critères de comparaison'), (lang==='en'?'Context of both cases':'Contexte des deux cas') ]}); outline.push({title: lang==='en'?'Similarities':'Similarités', bullets:[ (lang==='en'?'Two to three strong similarities':'Deux à trois similarités fortes') ]}); outline.push({title: lang==='en'?'Differences':'Différences', bullets:[ (lang==='en'?'Two to three critical differences':'Deux à trois différences clés') ]}); } // Conclusion outline.push({title: lang==='en'?'Conclusion':'Conclusion', bullets:[ `${pick(tr.conclude)} …`, (lang==='en'?'Restate thesis in new words':'Reformuler la thèse'), (lang==='en'?'Implications or call‑to‑action':'Portée ou appel à l’action') ]}); if(keywords.length){ outline.push({title: lang==='en'?'Keywords':'Mots‑clés', bullets: keywords}); } return { outline, thesis }; } function offlineEssay(p){ const { outline, thesis } = offlineOutline(p); const tr = L[p.language]; const cite = tr.placeholders[p.citations] || ''; const T = (k)=>{ const map = { intro: p.language==='en'?'Introduction':'Introduction', body: p.language==='en'?'Body':'Développement', conclusion: p.language==='en'?'Conclusion':'Conclusion' }; return map[k]; } const introHook = pick(tr.introHooks); const trans = pick(tr.transitions); // Build paragraphs roughly matching target words const target = Math.max(150, p.words|0); const paraCount = Math.min(6, Math.max(3, Math.round(target/170))); const paragraphs = []; // Intro paragraphs.push(makeParagraph([ sentenceCap(`${introHook} ${p.subject}.`), thesis, (p.language==='en'? `${trans}, this essay outlines context, key arguments, counterpoints, and a reasoned conclusion.`: `${trans}, cet essai expose le contexte, les arguments majeurs, des contre‑arguments, puis une conclusion motivée.`) ])); // Body paragraphs – lightweight templating const bodySeeds = [ p.language==='en'? ['Definitions & scope', 'Clarifying terms prevents category errors '+cite, 'Recent data points illustrate the stakes '+cite]: ['Définitions & périmètre', 'Clarifier les termes évite les confusions '+cite, 'Des données récentes illustrent les enjeux '+cite], p.language==='en'? ['Primary argument', 'Empirical findings and examples support the claim '+cite, 'Mechanisms explain how and why '+cite]: ['Argument principal', 'Des constats empiriques et exemples étayent l’assertion '+cite, 'Des mécanismes expliquent le comment et le pourquoi '+cite], p.language==='en'? ['Counterargument & rebuttal', pick(L.en.counters)+` …`, pick(L.en.rebuttals)+` …`]: ['Objection & réfutation', pick(L.fr.counters)+` …`, pick(L.fr.rebuttals)+` …`] ]; for(let i=0;i${escapeHtml(title)}
${escapeHtml(T('intro'))} • ${escapeHtml(T('body'))} • ${escapeHtml(T('conclusion'))}
${paragraphs.map(p=>`

${escapeHtml(p)}

`).join('\n')} ${p.citations!=='none'?`

${p.language==='en'?'Note: Replace citation placeholders with real sources.':'Note : remplacez les citations par de vraies sources.'}

`:''} `; return out; } // --- API Mode (OpenAI‑style chat.completions or n8n relay that accepts {messages} ) --- async function llmEssay(p, outlineOnly=false){ const sys = (p.language==='en') ? `You are an expert academic writing assistant. Produce a ${p.words}-word ${p.essayType} essay in ${p.language==='en'?'English':'French'}. Avoid hallucinations; if sources are uncertain, use placeholders like [Author, YEAR]. Include a clear thesis, logically ordered paragraphs, at least one counterargument with rebuttal, and a concise conclusion. Keep tone ${p.tone}. Target level: ${p.level}. Structure template: ${p.structure}.` : `Tu es un assistant d’écriture académique. Rédige un essai ${p.essayType} en ${p.language==='fr'?'français':'anglais'} d’environ ${p.words} mots. Évite les inventions ; si les sources sont incertaines, utilise des repères comme [Auteur, ANNÉE]. Intègre une thèse claire, des paragraphes ordonnés logiquement, au moins une objection et sa réfutation, puis une conclusion concise. Ton ${p.tone}. Niveau visé : ${p.level}. Structure : ${p.structure}.`; const user = (outlineOnly? ((p.language==='en')? `Create a detailed outline and thesis for the topic: "${p.subject}". Include section headings and bullet points. Keywords to include: ${p.keywords||'—'}.`: `Crée un plan détaillé et une thèse pour le sujet : "${p.subject}". Inclue des titres de sections et des puces. Mots‑clés : ${p.keywords||'—'}.`) : ((p.language==='en')? `Write the full essay about: "${p.subject}". If provided, use this thesis: ${p.thesis||'(no override)'}; otherwise craft a strong thesis matching the stance: ${p.stance}. Include ${p.citations==='none'?'no references, but add citation placeholders when necessary':p.citations+' styled citation placeholders'}. Keywords: ${p.keywords||'—'}.`: `Rédige l’essai complet sur : "${p.subject}". Si fourni, utilise cette thèse : ${p.thesis||'(aucune)'} ; sinon, formule une thèse forte conforme à la position : ${p.stance}. Inclure ${p.citations==='none'?'aucune référence, mais des repères de citation si nécessaire': 'des repères façon '+p.citations}. Mots‑clés : ${p.keywords||'—'}.`) ); const body = { model: p.apiModel || 'gpt-4o-mini', messages: [ {role:'system', content: sys}, {role:'user', content: user} ], temperature: 0.7, max_tokens: p.maxTokens || 1200, }; const res = await fetch(p.apiEndpoint, { method:'POST', headers:{ 'Content-Type':'application/json', 'Authorization': 'Bearer '+p.apiKey }, body: JSON.stringify(body) }); if(!res.ok){ const text = await res.text(); throw new Error(`API error ${res.status}: ${text.slice(0,300)}`); } const json = await res.json(); // OpenAI-style response const content = json?.choices?.[0]?.message?.content || JSON.stringify(json); return (outlineOnly) ? mdToHtml(content) : mdToHtml(content); } // Minimal Markdown → HTML converter for headings & lists function mdToHtml(md){ const esc = escapeHtml(md); // Convert basic markdown patterns after escaping, re-insert tags via replacements return esc .replace(/^######\s?(.*)$/gm,'
$1<\/h6>') .replace(/^#####\s?(.*)$/gm,'
$1<\/h5>') .replace(/^####\s?(.*)$/gm,'

$1<\/h4>') .replace(/^###\s?(.*)$/gm,'

$1<\/h3>') .replace(/^##\s?(.*)$/gm,'

$1<\/h2>') .replace(/^#\s?(.*)$/gm,'

$1<\/h1>') .replace(/^\s*[-*]\s+(.*)$/gm,'
  • $1<\/li>') .replace(/(
  • .*<\/li>)(\n?)(?!
  • )/gs,'
      $1<\/ul>') .replace(/\n\n/g,'

      ') .replace(/^/,'

      ') .replace(/$/,'

      '); } function escapeHtml(str){ return String(str) .replace(/&/g,'&') .replace(//g,'>') .replace(/"/g,'"') .replace(/'/g,'''); } // Handlers $('generateBtn').addEventListener('click', async ()=>{ try{ savePrefs(); const p = state.params; if(!p.subject){ flashStatus('Enter a subject/topic', 'warn'); return; } $('status').innerHTML = 'Generating…'; let html; if(p.apiMode){ if(!p.apiEndpoint || !p.apiKey){ flashStatus('API endpoint & key required', 'warn'); return; } html = await llmEssay(p, false); } else { html = offlineEssay(p); } $('output').innerHTML = html; updateWC(); flashStatus('Done'); } catch(err){ console.error(err); flashStatus(err.message||'Error', 'bad'); } }); $('outlineBtn').addEventListener('click', async ()=>{ try{ savePrefs(); const p = state.params; if(!p.subject){ flashStatus('Enter a subject/topic', 'warn'); return; } $('status').innerHTML = 'Outlining…'; let html; if(p.apiMode){ if(!p.apiEndpoint || !p.apiKey){ flashStatus('API endpoint & key required', 'warn'); return; } html = await llmEssay(p, true); } else { const { outline, thesis } = offlineOutline(p); const h = [ `

      ${escapeHtml( (p.language==='en'?L.en.toc:L.fr.toc) + ' – ' + (p.language==='en'?L.en.title(p.subject):L.fr.title(p.subject)) )}

      `, `

      ${escapeHtml(p.language==='en'?'Thesis':'Thèse')}: ${escapeHtml(thesis)}

      `, '
        '+ outline.map(sec=>`
      1. ${escapeHtml(sec.title)}
          ${sec.bullets.map(b=>`
        • ${escapeHtml(b)}
        • `).join('')}
      2. `).join('')+ '
      ' ].join('\n'); html = h; } $('output').innerHTML = html; updateWC(); flashStatus('Outline ready'); } catch(err){ console.error(err); flashStatus(err.message||'Error', 'bad'); } }); // Init loadPrefs(); updateWC(); });

  • logiciel de gestion association

    ×