← back to Norma

components/email-analyzer/fetchProsCons.ts

97 lines

import type { ProsConsData } from './ProsConsPanel';

/**
 * Fetches a pros/cons/suggestions comparison between two email versions
 * via the rewrite API endpoint. Used by both the inline comparison panel
 * and the compare modal.
 */
export async function fetchProsCons(
  originalEmail: string,
  newVersion: string,
  previousVersion: string,
  options?: {
    /** Label for the "new" version in the prompt (e.g. "version B") */
    newLabel?: string;
    /** Label for the "previous" version in the prompt (e.g. "version A") */
    previousLabel?: string;
  },
): Promise<ProsConsData | null> {
  if (!previousVersion || !newVersion) return null;

  const newLabel = options?.newLabel ?? 'NEW version';
  const previousLabel = options?.previousLabel ?? 'PREVIOUS version';

  const instruction = `Compare this ${newLabel} to the ${previousLabel} below. List:
- 2-4 specific pros (improvements over ${previousLabel.toLowerCase()})
- 1-3 cons (things lost or weakened)
- 2-4 suggestions (specific actionable improvements to make this version even stronger)

Be concise -- one sentence each.

${previousLabel.toUpperCase()}:
---
${previousVersion.substring(0, 2000)}
---

Return ONLY a JSON object: {"pros":["..."],"cons":["..."],"suggestions":["..."]}
Do NOT include any other text, markdown fences, or explanation.`;

  const res = await fetch('/api/email-analyzer/rewrite', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      originalEmail,
      currentVersion: newVersion,
      instruction,
      chatHistory: [],
    }),
  });

  if (!res.ok) return null;

  const data = await res.json();
  const raw = (data.rewrittenEmail || '')
    .replace(/```json?\s*/gi, '')
    .replace(/```/g, '')
    .trim();

  return parseProsConsJson(raw);
}

/**
 * Attempts to parse a pros/cons JSON object from raw text.
 * Handles both clean JSON and JSON embedded in other text.
 */
function parseProsConsJson(raw: string): ProsConsData | null {
  // First attempt: direct parse
  try {
    const parsed = JSON.parse(raw);
    if (parsed.pros && parsed.cons) {
      return {
        pros: parsed.pros,
        cons: parsed.cons,
        suggestions: parsed.suggestions || [],
      };
    }
  } catch {
    // Fall through to regex extraction
  }

  // Second attempt: extract JSON object from surrounding text
  const jsonMatch = raw.match(/\{[\s\S]*"pros"[\s\S]*"cons"[\s\S]*\}/);
  if (jsonMatch) {
    try {
      const parsed = JSON.parse(jsonMatch[0]);
      return {
        pros: parsed.pros || [],
        cons: parsed.cons || [],
        suggestions: parsed.suggestions || [],
      };
    } catch {
      return null;
    }
  }

  return null;
}