Hanaz Writers

Book Sales Prediction

United Kingdom United States Canada
document.getElementById("analyseBtn").addEventListener("click", analyseSales); // ✅ CHANGE THIS to your actual backend endpoint // If your backend route is: app.use("/api/sales-predictor", salesPredictor) // then POST should go to: https://YOURDOMAIN/api/sales-predictor const SALES_API_URL = "https://2a242e72ac9a.ngrok-free.app/api/sales-predictor"; function escapeHtml(str) { return String(str) .replace(/&/g, "&") .replace(//g, ">") .replace(/"/g, """) .replace(/'/g, "'"); } function renderAnalysis(analysis) { const improv = (analysis.improvementSuggestions || []) .map((s, i) => { const steps = (s.howToApply || []).map(x => `
  • ${escapeHtml(x)}
  • `).join(""); return `
    ${i + 1}. ${escapeHtml(s.title || "Suggestion")}
    Why it helps: ${escapeHtml(s.whyItHelps || "")}
    ${steps ? `
    How to apply:
      ${steps}
    ` : ""}
    `; }) .join(""); const reasoning = (analysis.salesPotential?.reasoning || []) .map(x => `
  • ${escapeHtml(x)}
  • `) .join(""); const audience = (analysis.salesPotential?.likelyAudience || []) .map(x => `
  • ${escapeHtml(x)}
  • `) .join(""); const comparables = (analysis.salesPotential?.positioning?.comparables || []) .map(x => `
  • ${escapeHtml(x)}
  • `) .join(""); const pricingNotes = (analysis.salesPotential?.pricingNotes || []) .map(x => `
  • ${escapeHtml(x)}
  • `) .join(""); const channels = (analysis.marketingStrategy?.channels || []) .map((c) => { const firstSteps = (c.firstSteps || []).map(x => `
  • ${escapeHtml(x)}
  • `).join(""); return `
    ${escapeHtml(c.name || "Channel")}
    Why: ${escapeHtml(c.why || "")}
    ${firstSteps ? `
    First steps:
      ${firstSteps}
    ` : ""}
    `; }) .join(""); const preLaunch = (analysis.marketingStrategy?.launchPlan?.preLaunch || []) .map(x => `
  • ${escapeHtml(x)}
  • `).join(""); const launchWeek = (analysis.marketingStrategy?.launchPlan?.launchWeek || []) .map(x => `
  • ${escapeHtml(x)}
  • `).join(""); const postLaunch = (analysis.marketingStrategy?.launchPlan?.postLaunch || []) .map(x => `
  • ${escapeHtml(x)}
  • `).join(""); const adIdeas = (analysis.marketingStrategy?.adIdeas || []) .map(x => `
  • ${escapeHtml(x)}
  • `).join(""); const emailSeq = (analysis.marketingStrategy?.emailSequence || []) .map(e => `
  • Day ${escapeHtml(e.day)} — ${escapeHtml(e.subject)} (Goal: ${escapeHtml(e.goal)})
  • `) .join(""); return `
    Results for: ${escapeHtml(analysis.country || "")}

    1) Specialised improvement suggestions
    ${improv || `

    No suggestions returned.

    `}
    2) Sales potential analysis
    Verdict: ${escapeHtml(analysis.salesPotential?.verdict || "")}
    ${reasoning ? `
    Reasoning:
      ${reasoning}
    ` : ""} ${audience ? `
    Likely audience:
      ${audience}
    ` : ""}
    Positioning
    Genre fit: ${escapeHtml(analysis.salesPotential?.positioning?.genreFit || "")}
    Unique hook: ${escapeHtml(analysis.salesPotential?.positioning?.uniqueHook || "")}
    ${comparables ? `
    Comparables:
      ${comparables}
    ` : ""}
    ${pricingNotes ? `
    Pricing notes:
      ${pricingNotes}
    ` : ""}
    3) Marketing strategy
    Core message: ${escapeHtml(analysis.marketingStrategy?.coreMessage || "")}
    ${channels ? `
    Channels:${channels}
    ` : ""}
    Launch plan
    ${preLaunch ? `
    Pre-launch:
      ${preLaunch}
    ` : ""} ${launchWeek ? `
    Launch week:
      ${launchWeek}
    ` : ""} ${postLaunch ? `
    Post-launch:
      ${postLaunch}
    ` : ""}
    ${adIdeas ? `
    Ad ideas:
      ${adIdeas}
    ` : ""} ${emailSeq ? `
    Email sequence:
      ${emailSeq}
    ` : ""}
    `; } async function analyseSales() { const summary = document.getElementById("bookSummaryInput").value.trim(); const country = document.getElementById("countrySelect").value; const resultBox = document.getElementById("salesResultBox"); const btn = document.getElementById("analyseBtn"); if (!summary) { resultBox.innerHTML = "

    Please enter a summary.

    "; return; } // Optional: match backend validation if (summary.length < 30) { resultBox.innerHTML = "

    Please enter at least 30 characters.

    "; return; } resultBox.innerHTML = "

    Analysing sales potential...

    "; btn.disabled = true; btn.style.opacity = "0.7"; try { const response = await fetch(SALES_API_URL, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ summary, country }) }); const data = await response.json(); if (!response.ok) { // Backend might return: { error: "...", raw?: "..." } const msg = data?.error ? data.error : "Server responded with an error"; resultBox.innerHTML = `

    Error: ${escapeHtml(msg)}

    ` + (data?.raw ? `
    Debug details
    ${escapeHtml(data.raw)}
    ` : ""); return; } // Backend returns: { analysis: {...} } if (!data || !data.analysis) { resultBox.innerHTML = `

    Error: Unexpected response format.

    `; return; } resultBox.innerHTML = renderAnalysis(data.analysis); } catch (err) { resultBox.innerHTML = `

    Error: ${escapeHtml(err.message)}

    `; } finally { btn.disabled = false; btn.style.opacity = "1"; } }