← back to elcasillas__DealUpdates

Function bodies 106 total

All specs Real LLM only Function bodies
processRow function · javascript · L209-L245 (37 LOC)
js/ingest.js
    function processRow(row, options) {
        const deal = {};
        const referenceDate = (options && options.referenceDate) || undefined;

        // Map columns
        for (const [csvCol, internalField] of Object.entries(COLUMN_MAPPINGS)) {
            deal[internalField] = row[csvCol] || '';
        }

        // Parse ACV - only keep CAD values
        const acvResult = parseACV(deal.acv);
        if (!acvResult.isCAD) {
            return null; // Skip non-CAD values
        }
        deal.acv = acvResult.value;
        deal.acvFormatted = formatCurrency(acvResult.value);

        // Parse and format dates
        deal.closingDate = parseDate(deal.closingDate);
        deal.modifiedDate = parseDate(deal.modifiedDate);

        // Calculate days since
        deal.daysSince = calculateDaysSince(deal.modifiedDate, referenceDate);
        deal.urgency = getUrgencyLevel(deal.daysSince);

        // Closing date awareness
        deal.daysUntilClosing = calculateDaysUntilClosing(
validateRow function · javascript · L247-L262 (16 LOC)
js/ingest.js
    function validateRow(deal) {
        if (!deal) return false;

        // Check Deal Owner format - should be a name, not a sentence
        const owner = deal.dealOwner || '';
        if (!owner || owner.length > 100 || owner.split(' ').length > 5) {
            return false;
        }

        // Check Deal Name exists
        if (!deal.dealName || deal.dealName.trim().length === 0) {
            return false;
        }

        return true;
    }
generateFallbackSummary function · javascript · L264-L284 (21 LOC)
js/ingest.js
    function generateFallbackSummary(notes) {
        // Deduplicate notes
        const unique = [...new Set(notes)];
        if (unique.length === 0) return '';

        // Extract first sentence from each unique note
        const sentences = unique.map(note => {
            const match = note.match(/^(.+?[.!?])\s/);
            if (match && match[1].length <= 150) {
                return match[1];
            }
            return note.length > 150 ? note.slice(0, 147) + '...' : note;
        });

        // Join and cap at 500 characters
        let summary = sentences.join(' | ');
        if (summary.length > 500) {
            summary = summary.slice(0, 497) + '...';
        }
        return summary;
    }
deduplicateDeals function · javascript · L286-L386 (101 LOC)
js/ingest.js
    async function deduplicateDeals(deals, existingDeals = [], generateAISummaries = async () => null) {
        const dealMap = new Map();
        const notesMap = new Map();

        for (const deal of deals) {
            const key = deal.dealKey;
            const existing = dealMap.get(key);

            // Collect all notes for this deal
            if (!notesMap.has(key)) {
                notesMap.set(key, []);
            }
            if (deal.noteContent && deal.noteContent.trim()) {
                notesMap.get(key).push(deal.noteContent.trim());
            }

            if (!existing) {
                dealMap.set(key, deal);
            } else {
                // Keep the one with newer modified date
                if (deal.modifiedDate && existing.modifiedDate) {
                    if (deal.modifiedDate > existing.modifiedDate) {
                        dealMap.set(key, deal);
                    }
                } else if (deal.modifiedDate) {
                    
applyAISummaries function · javascript · L390-L457 (68 LOC)
js/ingest.js
    async function applyAISummaries(deals, existingDeals = [], generateAISummaries = async () => null) {
        // Build lookup of existing deal data by key
        const oldDealMap = new Map();
        for (const old of existingDeals) {
            oldDealMap.set(old.dealKey || makeDealKey(old.dealName, old.dealOwner), old);
        }

        // Determine which deals need new AI summaries (hash-based reuse)
        const dealsNeedingSummary = [];
        let cacheHits = 0;
        for (const deal of deals) {
            const oldDeal = oldDealMap.get(deal.dealKey);
            const oldSummary = oldDeal?.notesSummary || '';
            const oldHash = oldDeal?.summaryHash || '';

            if (oldSummary && oldHash && oldHash === deal.notesHash) {
                deal.notesSummary = oldSummary;
                deal.summaryHash = oldHash;
                cacheHits++;
            } else {
                dealsNeedingSummary.push(deal);
            }
        }

        // Call AI in 
callClaude function · typescript · L30-L88 (59 LOC)
supabase/functions/summarize-notes/index.ts
async function callClaude(
  apiKey: string,
  dealsList: string,
  dealCount: number
): Promise<Record<string, string>> {
  const response = await fetch("https://api.anthropic.com/v1/messages", {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "x-api-key": apiKey,
      "anthropic-version": "2023-06-01",
    },
    body: JSON.stringify({
      model: MODEL_ID,
      max_tokens: 4096,
      messages: [
        {
          role: "user",
          content: `You are summarizing CRM deal notes for a sales dashboard. For each deal below, write a 3-5 sentence summary that covers: (1) current status and stage of the deal, (2) key activities and interactions so far, (3) blockers or risks, and (4) next steps and expected timeline. Be factual and specific—include names, dates, and action items where available.

Return a JSON object where keys are the deal numbers ("1", "2", etc.) and values are the summary strings. You must include all ${dealCount} deals.

${de
‹ prevpage 3 / 3