Severian commited on
Commit
7d0207d
·
verified ·
1 Parent(s): 5803f3f

Update services/difyService.ts

Browse files
Files changed (1) hide show
  1. services/difyService.ts +220 -114
services/difyService.ts CHANGED
@@ -362,6 +362,193 @@ const extractOverallPass = (text: string): boolean => {
362
  return false;
363
  };
364
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
365
  /**
366
  * Parses the new, structured QA report format.
367
  * @param qaText The raw `qa_gaurd` string from the API.
@@ -375,7 +562,8 @@ const parseNewQaReport = (qaText: string): { detailedQaReport: DetailedQaReport,
375
  meta: { ...defaultSection },
376
  h1: { ...defaultSection },
377
  copy: { ...defaultSection },
378
- overall: { grade: 'N/A', pass: false, primaryIssue: 'Parsing failed' }
 
379
  };
380
 
381
  const cleanedQaText = cleanResponseText(qaText);
@@ -385,7 +573,7 @@ const parseNewQaReport = (qaText: string): { detailedQaReport: DetailedQaReport,
385
 
386
  // Check if it's the new markdown format (starts with ##) or contains **TITLE** style sections
387
  if (cleanedQaText.startsWith('##') || cleanedQaText.includes('**TITLE**') || cleanedQaText.includes('### **') || cleanedQaText.includes('### TITLE')) {
388
- console.log('Using markdown parser for QA report');
389
  console.log('QA text starts with:', cleanedQaText.substring(0, 200));
390
 
391
  // Handle different section header formats
@@ -413,6 +601,7 @@ const parseNewQaReport = (qaText: string): { detailedQaReport: DetailedQaReport,
413
 
414
  const parsedData: Partial<DetailedQaReport> = {};
415
  let correctedCopyFromSeparateSection = '';
 
416
 
417
  // Special handling for single-section format like "## GRADE REPORT"
418
  if (sections.length === 1 && (sections[0].includes('GRADE REPORT') || sections[0].includes('QUALITY ASSURANCE'))) {
@@ -429,125 +618,37 @@ const parseNewQaReport = (qaText: string): { detailedQaReport: DetailedQaReport,
429
  header = header.replace(/^#+\s*/, '').replace(/\*\*/g, '').replace(/[:\-–]+$/, '').trim();
430
  console.log('Processing header:', header);
431
 
 
432
  if (header.includes('title')) {
433
- console.log('Parsing title section');
434
- parsedData.title = parseSection(sectionBlock);
435
  } else if (header.includes('meta')) {
436
- console.log('Parsing meta section');
437
- parsedData.meta = parseSection(sectionBlock);
438
  } else if (header.includes('h1')) {
439
- console.log('Parsing h1 section');
440
- parsedData.h1 = parseSection(sectionBlock);
441
  } else if (header.includes('copy') && !header.includes('corrected')) {
442
- console.log('Parsing copy section');
443
- parsedData.copy = parseSection(sectionBlock);
444
  } else if (header.includes('corrected') && header.includes('copy')) {
445
  console.log('Capturing separate CORRECTED COPY section');
446
  correctedCopyFromSeparateSection = lines.slice(1).join('\n').trim();
447
  } else if (header.includes('overall') || header.includes('assessment') || header.includes('pipeline')) {
448
- console.log('Parsing overall section');
449
  console.log('Overall section text:', sectionBlock.substring(0, 300));
450
 
451
- // ROBUST OVERALL GRADE EXTRACTION - handles multiple formats
452
- let grade = 'N/A';
453
- let gradeMatch = null;
454
-
455
- const overallGradePatterns = [
456
- /-\s*\*\*Final Grade:\*\*\s*(.*)/, // - **Final Grade:** 100/100
457
- /•\s*\*\*Final Grade:\*\*\s*(.*)/, // • **Final Grade:** 100/100
458
- /\*\s*\*\*Final Grade:\*\*\s*(.*)/, // * **Final Grade:** 100/100
459
- /-\s*\*\*Total Grade:\*\*\s*(.*)/, // - **Total Grade:** 100/100
460
- /•\s*\*\*Total Grade:\*\*\s*(.*)/, // • **Total Grade:** 100/100
461
- /\*\s*\*\*Total Grade:\*\*\s*(.*)/, // * **Total Grade:** 100/100
462
- /(?:•|-|\*)\s*\*\*(?:Final|Total|Overall)?\s*Grade\*\*:?:\s*(.*)/i, // Generic grade
463
- /(?:•|-|\*)\s*(?:Final|Total|Overall)?\s*Grade:?:\s*(.*)/i, // No bold
464
- /(?:Final|Total|Overall)\s*Grade:?:\s*(\d+\/\d+|\d+)/im, // Anywhere in text
465
- /(\d+\/\d+)\s*(?:final|total|overall)?/im // Number first
466
- ];
467
-
468
- for (const pattern of overallGradePatterns) {
469
- gradeMatch = sectionBlock.match(pattern);
470
- if (gradeMatch) {
471
- grade = gradeMatch[1].trim();
472
- break;
473
- }
474
- }
475
- console.log('Overall grade match:', gradeMatch, 'Final grade:', grade);
476
-
477
- // ROBUST OVERALL PASS EXTRACTION - handles multiple formats
478
- let pass = false;
479
- let passMatch = null;
480
-
481
- const overallPassPatterns = [
482
- // Exact format variations found in logs
483
- /-\s*\*\*Overall Pass:\*\*\s*(.*)/i, // - **Overall Pass:** true
484
- /•\s*\*\*Overall Pass:\*\*\s*(.*)/i, // • **Overall Pass:** true
485
- /\*\s*\*\*Overall Pass:\*\*\s*(.*)/i, // * **Overall Pass:** true
486
- /•\s*\*\*All Sections Pass:\*\*\s*(.*)/i, // • **All Sections Pass:** true
487
- /-\s*\*\*All Sections Pass:\*\*\s*(.*)/i, // - **All Sections Pass:** true
488
- /\*\s*\*\*All Sections Pass:\*\*\s*(.*)/i, // * **All Sections Pass:** true
489
- /•\s*\*\*Final Pass:\*\*\s*(.*)/i, // • **Final Pass:** true
490
- /-\s*\*\*Final Pass:\*\*\s*(.*)/i, // - **Final Pass:** true
491
- /\*\s*\*\*Final Pass:\*\*\s*(.*)/i, // * **Final Pass:** true
492
-
493
- // Generic patterns with flexible formatting
494
- /(?:•|-|\*)\s*\*\*(?:Overall\s+|All\s+Sections\s+|Final\s+)?Pass\*\*:?:\s*(.*)/i,
495
- /(?:•|-|\*)\s*(?:Overall\s+|All\s+Sections\s+|Final\s+)?Pass:?:\s*(.*)/i,
496
-
497
- // Anywhere in text patterns
498
- /Pass:?:\s*(true|false|✅|❌|TRUE|FALSE)/im,
499
- /Overall\s*Pass:?:\s*(true|false|✅|❌|TRUE|FALSE)/im,
500
- /All\s*Sections\s*Pass:?:\s*(true|false|✅|❌|TRUE|FALSE)/im,
501
- /(true|false|✅|❌|TRUE|FALSE)\s*(?:overall|pass)/im,
502
-
503
- // Handle capitalized boolean values
504
- /Pass:?:\s*(True|False|TRUE|FALSE)/im,
505
- /Overall\s*Pass:?:\s*(True|False|TRUE|FALSE)/im
506
- ];
507
-
508
- for (const pattern of overallPassPatterns) {
509
- passMatch = sectionBlock.match(pattern);
510
- if (passMatch) {
511
- const passValue = passMatch[1].toLowerCase().trim();
512
- pass = passValue.includes('true') ||
513
- passValue.includes('✅') ||
514
- passValue === 'yes' ||
515
- passValue === 'passed' ||
516
- passValue === 'pass';
517
- break;
518
- }
519
- }
520
- console.log('Overall pass match:', passMatch, 'Final pass:', pass);
521
-
522
- // Look for various primary issue formats
523
- const explanationMatch = sectionBlock.match(/\*\*Overall Pass\*\*:\s*[^()]*\(([^)]+)\)/);
524
- const statusMatch = sectionBlock.match(/(?:•|-|\*)\s*\*\*(?:Pipeline\s+)?Status\*\*?:?\s*([\s\S]*?)(?=\n(?:•|-|\*)\s*\*\*|$)/);
525
- const primaryIssueMatch = sectionBlock.match(/(?:•|-|\*)\s*\*\*(?:Primary\s+)?Issue\*\*?:?\s*([\s\S]*?)(?=\n(?:•|-|\*)\s*\*\*|$)/) ||
526
- sectionBlock.match(/(?:•|-|\*)\s*(?:Primary\s+)?Issue:?:\s*([\s\S]*?)(?=\n(?:•|-|\*)\s*\*\*|$)/);
527
- const errorsMatch = sectionBlock.match(/(?:•|-|\*)\s*\*\*Total\s+Errors?\*\*?:?\s*([\s\S]*?)(?=\n(?:•|-|\*)\s*\*\*|$)/);
528
- const totalSectionsMatch = sectionBlock.match(/Total\s*Sections\s*Passing:?:\s*([^\n]+)/i);
529
-
530
- let primaryIssue = 'All sections passed successfully.';
531
- if (explanationMatch) {
532
- primaryIssue = explanationMatch[1].trim();
533
- } else if (statusMatch) {
534
- primaryIssue = statusMatch[1].trim();
535
- } else if (primaryIssueMatch) {
536
- primaryIssue = primaryIssueMatch[1].trim();
537
- } else if (errorsMatch) {
538
- const errorText = errorsMatch[1].trim();
539
- if (errorText !== '[]' && errorText !== '') {
540
- primaryIssue = `Errors found: ${errorText}`;
541
- }
542
- }
543
- if (totalSectionsMatch) {
544
- primaryIssue = `${primaryIssue} | Total Sections Passing: ${totalSectionsMatch[1].trim()}`;
545
- }
546
-
547
- console.log('Primary issue extraction - explanation:', explanationMatch, 'status:', statusMatch, 'issue:', primaryIssueMatch, 'Final issue:', primaryIssue);
548
-
549
- console.log('Setting overall data - grade:', grade, 'pass:', pass, 'primaryIssue:', primaryIssue);
550
- parsedData.overall = { grade, pass, primaryIssue };
551
  }
552
  });
553
 
@@ -556,7 +657,9 @@ const parseNewQaReport = (qaText: string): { detailedQaReport: DetailedQaReport,
556
  meta: parsedData.meta || { ...defaultSection, errors: ['Meta section not found'] },
557
  h1: parsedData.h1 || { ...defaultSection, errors: ['H1 section not found'] },
558
  copy: parsedData.copy || { ...defaultSection, errors: ['Copy section not found'] },
559
- overall: parsedData.overall || { grade: 'N/A', pass: false, primaryIssue: 'Overall section not found' }
 
 
560
  };
561
 
562
  // If we saw a separate CORRECTED COPY section, populate copy.corrected with it when useful
@@ -592,7 +695,8 @@ const parseNewQaReport = (qaText: string): { detailedQaReport: DetailedQaReport,
592
  parsedData.overall = {
593
  grade,
594
  pass,
595
- primaryIssue: pass ? 'All sections passed successfully.' : 'Overall assessment failed.'
 
596
  };
597
 
598
  console.log('Found inline overall results - grade:', grade, 'pass:', pass);
@@ -621,7 +725,8 @@ const parseNewQaReport = (qaText: string): { detailedQaReport: DetailedQaReport,
621
  parsedData.overall = {
622
  grade: averageGrade,
623
  pass: allSectionsPassed,
624
- primaryIssue: allSectionsPassed ? 'All sections passed successfully.' : 'One or more sections failed.'
 
625
  };
626
 
627
  console.log('Calculated overall from individual sections - pass:', allSectionsPassed, 'grade:', averageGrade);
@@ -633,6 +738,7 @@ const parseNewQaReport = (qaText: string): { detailedQaReport: DetailedQaReport,
633
 
634
  console.log('Final parsed QA data:', finalReport.overall);
635
  console.log('Setting overallPass:', finalReport.overall.pass, 'overallGrade:', finalReport.overall.grade);
 
636
 
637
  return {
638
  detailedQaReport: finalReport,
 
362
  return false;
363
  };
364
 
365
+ /**
366
+ * Enhanced section parsing that captures ALL QA Guard content
367
+ */
368
+ const parseEnhancedSection = (sectionBlock: string): QaSectionResult => {
369
+ const baseSection = parseSection(sectionBlock);
370
+
371
+ // Extract detailed assessment content
372
+ const detailedAssessmentMatch = sectionBlock.match(/(?:•|-|\*)\s*\*\*(?:Detailed\s+)?Assessment\*\*?:?\s*([\s\S]*?)(?=\n(?:•|-|\*)\s*\*\*|$)/i);
373
+ const explanationsMatch = sectionBlock.match(/(?:•|-|\*)\s*\*\*(?:Explanation|Reasoning)\*\*?:?\s*([\s\S]*?)(?=\n(?:•|-|\*)\s*\*\*|$)/i);
374
+
375
+ // Extract key strengths
376
+ const keyStrengthsMatch = sectionBlock.match(/(?:•|-|\*)\s*\*\*Key\s+Strengths\*\*?:?\s*([\s\S]*?)(?=\n(?:•|-|\*)\s*\*\*|$)/i);
377
+ const strengthsList = keyStrengthsMatch ?
378
+ keyStrengthsMatch[1].split('\n')
379
+ .map(line => line.replace(/^[-•*]\s*/, '').trim())
380
+ .filter(line => line.length > 0) : undefined;
381
+
382
+ // Extract recommendations
383
+ const recommendationsMatch = sectionBlock.match(/(?:•|-|\*)\s*\*\*(?:Recommendations?|Suggestions?)\*\*?:?\s*([\s\S]*?)(?=\n(?:•|-|\*)\s*\*\*|$)/i);
384
+ const recommendationsList = recommendationsMatch ?
385
+ recommendationsMatch[1].split('\n')
386
+ .map(line => line.replace(/^[-•*]\s*/, '').trim())
387
+ .filter(line => line.length > 0) : undefined;
388
+
389
+ return {
390
+ ...baseSection,
391
+ detailedAssessment: detailedAssessmentMatch ? detailedAssessmentMatch[1].trim() : undefined,
392
+ explanations: explanationsMatch ? explanationsMatch[1].trim() : undefined,
393
+ keyStrengths: strengthsList,
394
+ recommendations: recommendationsList,
395
+ rawContent: sectionBlock
396
+ };
397
+ };
398
+
399
+ /**
400
+ * Enhanced overall section parsing that captures ALL QA Guard content
401
+ */
402
+ const parseEnhancedOverallSection = (sectionBlock: string): { grade: string; pass: boolean; primaryIssue: string; detailedAssessment?: string; keyStrengths?: string[]; recommendations?: string[]; explanations?: string; rawContent?: string } => {
403
+ // ROBUST OVERALL GRADE EXTRACTION - handles multiple formats
404
+ let grade = 'N/A';
405
+ let gradeMatch = null;
406
+
407
+ const overallGradePatterns = [
408
+ /-\s*\*\*Final Grade:\*\*\s*(.*)/, // - **Final Grade:** 100/100
409
+ /•\s*\*\*Final Grade:\*\*\s*(.*)/, // • **Final Grade:** 100/100
410
+ /\*\s*\*\*Final Grade:\*\*\s*(.*)/, // * **Final Grade:** 100/100
411
+ /-\s*\*\*Total Grade:\*\*\s*(.*)/, // - **Total Grade:** 100/100
412
+ /•\s*\*\*Total Grade:\*\*\s*(.*)/, // • **Total Grade:** 100/100
413
+ /\*\s*\*\*Total Grade:\*\*\s*(.*)/, // * **Total Grade:** 100/100
414
+ /(?:•|-|\*)\s*\*\*(?:Final|Total|Overall)?\s*Grade\*\*:?:\s*(.*)/i, // Generic grade
415
+ /(?:•|-|\*)\s*(?:Final|Total|Overall)?\s*Grade:?:\s*(.*)/i, // No bold
416
+ /(?:Final|Total|Overall)\s*Grade:?:\s*(\d+\/\d+|\d+)/im, // Anywhere in text
417
+ /(\d+\/\d+)\s*(?:final|total|overall)?/im // Number first
418
+ ];
419
+
420
+ for (const pattern of overallGradePatterns) {
421
+ gradeMatch = sectionBlock.match(pattern);
422
+ if (gradeMatch) {
423
+ grade = gradeMatch[1].trim();
424
+ break;
425
+ }
426
+ }
427
+ console.log('Overall grade match:', gradeMatch, 'Final grade:', grade);
428
+
429
+ // ROBUST OVERALL PASS EXTRACTION - handles multiple formats
430
+ let pass = false;
431
+ let passMatch = null;
432
+
433
+ const overallPassPatterns = [
434
+ // Exact format variations found in logs
435
+ /-\s*\*\*Overall Pass:\*\*\s*(.*)/i, // - **Overall Pass:** true
436
+ /•\s*\*\*Overall Pass:\*\*\s*(.*)/i, // • **Overall Pass:** true
437
+ /\*\s*\*\*Overall Pass:\*\*\s*(.*)/i, // * **Overall Pass:** true
438
+ /•\s*\*\*All Sections Pass:\*\*\s*(.*)/i, // • **All Sections Pass:** true
439
+ /-\s*\*\*All Sections Pass:\*\*\s*(.*)/i, // - **All Sections Pass:** true
440
+ /\*\s*\*\*All Sections Pass:\*\*\s*(.*)/i, // * **All Sections Pass:** true
441
+ /•\s*\*\*Final Pass:\*\*\s*(.*)/i, // • **Final Pass:** true
442
+ /-\s*\*\*Final Pass:\*\*\s*(.*)/i, // - **Final Pass:** true
443
+ /\*\s*\*\*Final Pass:\*\*\s*(.*)/i, // * **Final Pass:** true
444
+
445
+ // Generic patterns with flexible formatting
446
+ /(?:•|-|\*)\s*\*\*(?:Overall\s+|All\s+Sections\s+|Final\s+)?Pass\*\*:?:\s*(.*)/i,
447
+ /(?:•|-|\*)\s*(?:Overall\s+|All\s+Sections\s+|Final\s+)?Pass:?:\s*(.*)/i,
448
+
449
+ // Anywhere in text patterns
450
+ /Pass:?:\s*(true|false|✅|❌|TRUE|FALSE)/im,
451
+ /Overall\s*Pass:?:\s*(true|false|✅|❌|TRUE|FALSE)/im,
452
+ /All\s*Sections\s*Pass:?:\s*(true|false|✅|❌|TRUE|FALSE)/im,
453
+ /(true|false|✅|❌|TRUE|FALSE)\s*(?:overall|pass)/im,
454
+
455
+ // Handle capitalized boolean values
456
+ /Pass:?:\s*(True|False|TRUE|FALSE)/im,
457
+ /Overall\s*Pass:?:\s*(True|False|TRUE|FALSE)/im
458
+ ];
459
+
460
+ for (const pattern of overallPassPatterns) {
461
+ passMatch = sectionBlock.match(pattern);
462
+ if (passMatch) {
463
+ const passValue = passMatch[1].toLowerCase().trim();
464
+ pass = passValue.includes('true') ||
465
+ passValue.includes('✅') ||
466
+ passValue === 'yes' ||
467
+ passValue === 'passed' ||
468
+ passValue === 'pass';
469
+ break;
470
+ }
471
+ }
472
+ console.log('Overall pass match:', passMatch, 'Final pass:', pass);
473
+
474
+ // Look for various primary issue formats
475
+ const explanationMatch = sectionBlock.match(/\*\*Overall Pass\*\*:\s*[^()]*\(([^)]+)\)/);
476
+ const statusMatch = sectionBlock.match(/(?:•|-|\*)\s*\*\*(?:Pipeline\s+)?Status\*\*?:?\s*([\s\S]*?)(?=\n(?:•|-|\*)\s*\*\*|$)/);
477
+ const primaryIssueMatch = sectionBlock.match(/(?:•|-|\*)\s*\*\*(?:Primary\s+)?Issue\*\*?:?\s*([\s\S]*?)(?=\n(?:•|-|\*)\s*\*\*|$)/) ||
478
+ sectionBlock.match(/(?:•|-|\*)\s*(?:Primary\s+)?Issue:?:\s*([\s\S]*?)(?=\n(?:•|-|\*)\s*\*\*|$)/);
479
+ const errorsMatch = sectionBlock.match(/(?:•|-|\*)\s*\*\*Total\s+Errors?\*\*?:?\s*([\s\S]*?)(?=\n(?:•|-|\*)\s*\*\*|$)/);
480
+ const totalSectionsMatch = sectionBlock.match(/Total\s*Sections\s*Passing:?:\s*([^\n]+)/i);
481
+
482
+ let primaryIssue = 'All sections passed successfully.';
483
+ if (explanationMatch) {
484
+ primaryIssue = explanationMatch[1].trim();
485
+ } else if (statusMatch) {
486
+ primaryIssue = statusMatch[1].trim();
487
+ } else if (primaryIssueMatch) {
488
+ primaryIssue = primaryIssueMatch[1].trim();
489
+ } else if (errorsMatch) {
490
+ const errorText = errorsMatch[1].trim();
491
+ if (errorText !== '[]' && errorText !== '') {
492
+ primaryIssue = `Errors found: ${errorText}`;
493
+ }
494
+ }
495
+ if (totalSectionsMatch) {
496
+ primaryIssue = `${primaryIssue} | Total Sections Passing: ${totalSectionsMatch[1].trim()}`;
497
+ }
498
+
499
+ console.log('Primary issue extraction - explanation:', explanationMatch, 'status:', statusMatch, 'issue:', primaryIssueMatch, 'Final issue:', primaryIssue);
500
+
501
+ // Extract detailed assessment content
502
+ const detailedAssessmentMatch = sectionBlock.match(/(?:•|-|\*)\s*\*\*(?:Detailed\s+)?Assessment\*\*?:?\s*([\s\S]*?)(?=\n(?:•|-|\*)\s*\*\*|$)/i);
503
+ const explanationsMatch = sectionBlock.match(/(?:•|-|\*)\s*\*\*(?:Explanation|Reasoning)\*\*?:?\s*([\s\S]*?)(?=\n(?:•|-|\*)\s*\*\*|$)/i);
504
+
505
+ // Extract key strengths
506
+ const keyStrengthsMatch = sectionBlock.match(/(?:•|-|\*)\s*\*\*Key\s+Strengths\*\*?:?\s*([\s\S]*?)(?=\n(?:•|-|\*)\s*\*\*|$)/i);
507
+ const strengthsList = keyStrengthsMatch ?
508
+ keyStrengthsMatch[1].split('\n')
509
+ .map(line => line.replace(/^[-•*]\s*/, '').trim())
510
+ .filter(line => line.length > 0) : undefined;
511
+
512
+ // Extract recommendations
513
+ const recommendationsMatch = sectionBlock.match(/(?:•|-|\*)\s*\*\*(?:Recommendations?|Suggestions?)\*\*?:?\s*([\s\S]*?)(?=\n(?:•|-|\*)\s*\*\*|$)/i);
514
+ const recommendationsList = recommendationsMatch ?
515
+ recommendationsMatch[1].split('\n')
516
+ .map(line => line.replace(/^[-•*]\s*/, '').trim())
517
+ .filter(line => line.length > 0) : undefined;
518
+
519
+ console.log('Setting overall data - grade:', grade, 'pass:', pass, 'primaryIssue:', primaryIssue);
520
+
521
+ return {
522
+ grade,
523
+ pass,
524
+ primaryIssue,
525
+ detailedAssessment: detailedAssessmentMatch ? detailedAssessmentMatch[1].trim() : undefined,
526
+ explanations: explanationsMatch ? explanationsMatch[1].trim() : undefined,
527
+ keyStrengths: strengthsList,
528
+ recommendations: recommendationsList,
529
+ rawContent: sectionBlock
530
+ };
531
+ };
532
+
533
+ /**
534
+ * Determine the type of an additional section based on its content
535
+ */
536
+ const determineSectionType = (sectionBlock: string): 'assessment' | 'strengths' | 'recommendations' | 'explanations' | 'other' => {
537
+ const lowerContent = sectionBlock.toLowerCase();
538
+
539
+ if (lowerContent.includes('strength') || lowerContent.includes('positive') || lowerContent.includes('excellent')) {
540
+ return 'strengths';
541
+ } else if (lowerContent.includes('recommend') || lowerContent.includes('suggest') || lowerContent.includes('improve')) {
542
+ return 'recommendations';
543
+ } else if (lowerContent.includes('explain') || lowerContent.includes('reason') || lowerContent.includes('why')) {
544
+ return 'explanations';
545
+ } else if (lowerContent.includes('assess') || lowerContent.includes('evaluate') || lowerContent.includes('analysis')) {
546
+ return 'assessment';
547
+ } else {
548
+ return 'other';
549
+ }
550
+ };
551
+
552
  /**
553
  * Parses the new, structured QA report format.
554
  * @param qaText The raw `qa_gaurd` string from the API.
 
562
  meta: { ...defaultSection },
563
  h1: { ...defaultSection },
564
  copy: { ...defaultSection },
565
+ overall: { grade: 'N/A', pass: false, primaryIssue: 'Parsing failed' },
566
+ completeRawReport: qaText // Always preserve the complete raw report
567
  };
568
 
569
  const cleanedQaText = cleanResponseText(qaText);
 
573
 
574
  // Check if it's the new markdown format (starts with ##) or contains **TITLE** style sections
575
  if (cleanedQaText.startsWith('##') || cleanedQaText.includes('**TITLE**') || cleanedQaText.includes('### **') || cleanedQaText.includes('### TITLE')) {
576
+ console.log('Using enhanced markdown parser for QA report');
577
  console.log('QA text starts with:', cleanedQaText.substring(0, 200));
578
 
579
  // Handle different section header formats
 
601
 
602
  const parsedData: Partial<DetailedQaReport> = {};
603
  let correctedCopyFromSeparateSection = '';
604
+ const additionalSections: { [sectionName: string]: { content: string; type: 'assessment' | 'strengths' | 'recommendations' | 'explanations' | 'other'; } } = {};
605
 
606
  // Special handling for single-section format like "## GRADE REPORT"
607
  if (sections.length === 1 && (sections[0].includes('GRADE REPORT') || sections[0].includes('QUALITY ASSURANCE'))) {
 
618
  header = header.replace(/^#+\s*/, '').replace(/\*\*/g, '').replace(/[:\-–]+$/, '').trim();
619
  console.log('Processing header:', header);
620
 
621
+ // Enhanced section parsing to capture ALL content
622
  if (header.includes('title')) {
623
+ console.log('Parsing title section with enhanced content capture');
624
+ parsedData.title = parseEnhancedSection(sectionBlock);
625
  } else if (header.includes('meta')) {
626
+ console.log('Parsing meta section with enhanced content capture');
627
+ parsedData.meta = parseEnhancedSection(sectionBlock);
628
  } else if (header.includes('h1')) {
629
+ console.log('Parsing h1 section with enhanced content capture');
630
+ parsedData.h1 = parseEnhancedSection(sectionBlock);
631
  } else if (header.includes('copy') && !header.includes('corrected')) {
632
+ console.log('Parsing copy section with enhanced content capture');
633
+ parsedData.copy = parseEnhancedSection(sectionBlock);
634
  } else if (header.includes('corrected') && header.includes('copy')) {
635
  console.log('Capturing separate CORRECTED COPY section');
636
  correctedCopyFromSeparateSection = lines.slice(1).join('\n').trim();
637
  } else if (header.includes('overall') || header.includes('assessment') || header.includes('pipeline')) {
638
+ console.log('Parsing overall section with enhanced content capture');
639
  console.log('Overall section text:', sectionBlock.substring(0, 300));
640
 
641
+ // Enhanced overall section parsing to capture ALL content
642
+ const enhancedOverall = parseEnhancedOverallSection(sectionBlock);
643
+ parsedData.overall = enhancedOverall;
644
+ } else {
645
+ // Capture any additional sections that don't match standard patterns
646
+ console.log('Capturing additional section:', header);
647
+ const sectionType = determineSectionType(sectionBlock);
648
+ additionalSections[header] = {
649
+ content: sectionBlock,
650
+ type: sectionType
651
+ };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
652
  }
653
  });
654
 
 
657
  meta: parsedData.meta || { ...defaultSection, errors: ['Meta section not found'] },
658
  h1: parsedData.h1 || { ...defaultSection, errors: ['H1 section not found'] },
659
  copy: parsedData.copy || { ...defaultSection, errors: ['Copy section not found'] },
660
+ overall: parsedData.overall || { grade: 'N/A', pass: false, primaryIssue: 'Overall section not found' },
661
+ additionalSections: Object.keys(additionalSections).length > 0 ? additionalSections : undefined,
662
+ completeRawReport: qaText
663
  };
664
 
665
  // If we saw a separate CORRECTED COPY section, populate copy.corrected with it when useful
 
695
  parsedData.overall = {
696
  grade,
697
  pass,
698
+ primaryIssue: pass ? 'All sections passed successfully.' : 'Overall assessment failed.',
699
+ rawContent: cleanedQaText
700
  };
701
 
702
  console.log('Found inline overall results - grade:', grade, 'pass:', pass);
 
725
  parsedData.overall = {
726
  grade: averageGrade,
727
  pass: allSectionsPassed,
728
+ primaryIssue: allSectionsPassed ? 'All sections passed successfully.' : 'One or more sections failed.',
729
+ rawContent: cleanedQaText
730
  };
731
 
732
  console.log('Calculated overall from individual sections - pass:', allSectionsPassed, 'grade:', averageGrade);
 
738
 
739
  console.log('Final parsed QA data:', finalReport.overall);
740
  console.log('Setting overallPass:', finalReport.overall.pass, 'overallGrade:', finalReport.overall.grade);
741
+ console.log('Additional sections captured:', Object.keys(additionalSections));
742
 
743
  return {
744
  detailedQaReport: finalReport,