vn6295337 Claude Opus 4.5 commited on
Commit
0fb19bd
·
1 Parent(s): de975df

Reformat SWOT output: concise 3-column table format

Browse files

Backend:
- Update analyzer prompt to output SWOT as tables
- Format: | Ref | Metric | Insight |
- Update revision prompt to use same table format

Frontend:
- Add cleanMarkdown() to strip asterisks and bold markers
- Apply to all SWOT item displays and copy text

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

Files changed (2) hide show
  1. frontend/src/App.tsx +17 -8
  2. src/nodes/analyzer.py +35 -30
frontend/src/App.tsx CHANGED
@@ -85,6 +85,15 @@ const defaultLLMStatus: LLMStatus = {
85
  openrouter: 'idle',
86
  }
87
 
 
 
 
 
 
 
 
 
 
88
  const Index = () => {
89
  const [selectedStock, setSelectedStock] = useState<StockResult | null>(null)
90
  const [isLoading, setIsLoading] = useState(false)
@@ -377,16 +386,16 @@ Quality Score: ${analysisResult.score}/10
377
  Revisions: ${analysisResult.revision_count}
378
 
379
  STRENGTHS:
380
- ${analysisResult.swot_data.strengths.map(s => `- ${s}`).join('\n')}
381
 
382
  WEAKNESSES:
383
- ${analysisResult.swot_data.weaknesses.map(w => `- ${w}`).join('\n')}
384
 
385
  OPPORTUNITIES:
386
- ${analysisResult.swot_data.opportunities.map(o => `- ${o}`).join('\n')}
387
 
388
  THREATS:
389
- ${analysisResult.swot_data.threats.map(t => `- ${t}`).join('\n')}
390
 
391
  QUALITY EVALUATION:
392
  ${analysisResult.critique}
@@ -784,7 +793,7 @@ Generated by Instant SWOT Agent`
784
  {analysisResult.swot_data.strengths.map((item, i) => (
785
  <li key={i} className="flex gap-2 text-sm text-foreground">
786
  <CheckCircle className="h-4 w-4 text-emerald-500 shrink-0 mt-0.5" />
787
- <span>{item}</span>
788
  </li>
789
  ))}
790
  </ul>
@@ -800,7 +809,7 @@ Generated by Instant SWOT Agent`
800
  {analysisResult.swot_data.weaknesses.map((item, i) => (
801
  <li key={i} className="flex gap-2 text-sm text-foreground">
802
  <XCircle className="h-4 w-4 text-red-500 shrink-0 mt-0.5" />
803
- <span>{item}</span>
804
  </li>
805
  ))}
806
  </ul>
@@ -816,7 +825,7 @@ Generated by Instant SWOT Agent`
816
  {analysisResult.swot_data.opportunities.map((item, i) => (
817
  <li key={i} className="flex gap-2 text-sm text-foreground">
818
  <Zap className="h-4 w-4 text-blue-500 shrink-0 mt-0.5" />
819
- <span>{item}</span>
820
  </li>
821
  ))}
822
  </ul>
@@ -832,7 +841,7 @@ Generated by Instant SWOT Agent`
832
  {analysisResult.swot_data.threats.map((item, i) => (
833
  <li key={i} className="flex gap-2 text-sm text-foreground">
834
  <AlertCircle className="h-4 w-4 text-yellow-500 shrink-0 mt-0.5" />
835
- <span>{item}</span>
836
  </li>
837
  ))}
838
  </ul>
 
85
  openrouter: 'idle',
86
  }
87
 
88
+ // Helper to clean markdown formatting (strip asterisks, bold markers)
89
+ const cleanMarkdown = (text: string): string => {
90
+ return text
91
+ .replace(/\*\*([^*]+)\*\*/g, '$1') // Remove **bold**
92
+ .replace(/\*([^*]+)\*/g, '$1') // Remove *italic*
93
+ .replace(/^\*\s*/gm, '') // Remove bullet asterisks at line start
94
+ .trim()
95
+ }
96
+
97
  const Index = () => {
98
  const [selectedStock, setSelectedStock] = useState<StockResult | null>(null)
99
  const [isLoading, setIsLoading] = useState(false)
 
386
  Revisions: ${analysisResult.revision_count}
387
 
388
  STRENGTHS:
389
+ ${analysisResult.swot_data.strengths.map(s => `- ${cleanMarkdown(s)}`).join('\n')}
390
 
391
  WEAKNESSES:
392
+ ${analysisResult.swot_data.weaknesses.map(w => `- ${cleanMarkdown(w)}`).join('\n')}
393
 
394
  OPPORTUNITIES:
395
+ ${analysisResult.swot_data.opportunities.map(o => `- ${cleanMarkdown(o)}`).join('\n')}
396
 
397
  THREATS:
398
+ ${analysisResult.swot_data.threats.map(t => `- ${cleanMarkdown(t)}`).join('\n')}
399
 
400
  QUALITY EVALUATION:
401
  ${analysisResult.critique}
 
793
  {analysisResult.swot_data.strengths.map((item, i) => (
794
  <li key={i} className="flex gap-2 text-sm text-foreground">
795
  <CheckCircle className="h-4 w-4 text-emerald-500 shrink-0 mt-0.5" />
796
+ <span>{cleanMarkdown(item)}</span>
797
  </li>
798
  ))}
799
  </ul>
 
809
  {analysisResult.swot_data.weaknesses.map((item, i) => (
810
  <li key={i} className="flex gap-2 text-sm text-foreground">
811
  <XCircle className="h-4 w-4 text-red-500 shrink-0 mt-0.5" />
812
+ <span>{cleanMarkdown(item)}</span>
813
  </li>
814
  ))}
815
  </ul>
 
825
  {analysisResult.swot_data.opportunities.map((item, i) => (
826
  <li key={i} className="flex gap-2 text-sm text-foreground">
827
  <Zap className="h-4 w-4 text-blue-500 shrink-0 mt-0.5" />
828
+ <span>{cleanMarkdown(item)}</span>
829
  </li>
830
  ))}
831
  </ul>
 
841
  {analysisResult.swot_data.threats.map((item, i) => (
842
  <li key={i} className="flex gap-2 text-sm text-foreground">
843
  <AlertCircle className="h-4 w-4 text-yellow-500 shrink-0 mt-0.5" />
844
+ <span>{cleanMarkdown(item)}</span>
845
  </li>
846
  ))}
847
  </ul>
src/nodes/analyzer.py CHANGED
@@ -1348,11 +1348,18 @@ Weighted Score: {critique_details.get('weighted_score', 0):.1f} / 10
1348
 
1349
  ### OUTPUT INSTRUCTIONS
1350
 
1351
- Produce a complete, revised SWOT analysis following the original template structure.
 
 
 
 
 
 
 
1352
 
1353
  Do not:
 
1354
  - Include any preamble about revisions
1355
- - Apologize or explain what you changed
1356
  - Reference the Critic's feedback in your output
1357
 
1358
  Simply output the improved SWOT as a clean, final deliverable."""
@@ -1397,44 +1404,42 @@ def _build_analyzer_prompt(company: str, ticker: str, formatted_data: str,
1397
 
1398
  === OUTPUT FORMAT ===
1399
 
1400
- Produce a SWOT analysis with this exact structure:
1401
 
1402
  ## Strengths
1403
- For each (3-5 points):
1404
- - **Finding:** [One sentence with metric value and citation, e.g., "Revenue of $394.3B [M01] shows..."]
1405
- - **Strategic Implication:** [Why this matters]
1406
- - **Durability:** [High/Medium/Low]
 
 
1407
 
1408
  ## Weaknesses
1409
- For each (3-5 points):
1410
- - **Finding:** [One sentence with metric value and citation, e.g., "Debt/equity of 1.87 [M04] indicates..."]
1411
- - **Severity:** [Critical/Moderate/Minor]
1412
- - **Trend:** [Improving/Stable/Deteriorating]
1413
- - **Remediation Levers:** [What could improve this]
1414
 
1415
  ## Opportunities
1416
- For each (3-5 points):
1417
- - **Catalyst:** [Description with metric citations where applicable]
1418
- - **Timing:** [Near-term/Medium-term/Long-term]
1419
- - **Execution Requirements:** [What must happen]
1420
 
1421
  ## Threats
1422
- For each (3-5 points):
1423
- - **Risk Factor:** [Description with metric citations where applicable]
1424
- - **Probability:** [High/Medium/Low]
1425
- - **Impact:** [Potential magnitude]
1426
- - **Mitigation Options:** [Possible responses]
1427
 
1428
  ## Data Quality Notes
1429
- - **Metrics Used:** [List key metrics analyzed]
1430
- - **Data Gaps:** [Any unavailable metrics]
1431
- - **Confidence Level:** [High/Medium/Low]
1432
-
1433
- CRITICAL CITATION REQUIREMENTS:
1434
- 1. Every numeric finding MUST include the reference ID in brackets: value [M##]
1435
- 2. Use EXACT values from the METRIC REFERENCE TABLE - do NOT round or estimate
1436
- 3. Example: "Revenue of $394,328,000,000 [M01] demonstrates strong market position"
1437
- 4. Citations will be automatically verified - mismatches cause rejection"""
 
1438
 
1439
  return prompt, metric_lookup, ref_hash
1440
 
 
1348
 
1349
  ### OUTPUT INSTRUCTIONS
1350
 
1351
+ Produce a complete, revised SWOT analysis using TABLE format:
1352
+
1353
+ ## Strengths
1354
+ | Ref | Metric | Insight |
1355
+ |-----|--------|---------|
1356
+ | M## | Metric: Value | Strategic insight in one sentence |
1357
+
1358
+ (Same table format for Weaknesses, Opportunities, Threats)
1359
 
1360
  Do not:
1361
+ - Use bullet points or **bold** labels - use tables only
1362
  - Include any preamble about revisions
 
1363
  - Reference the Critic's feedback in your output
1364
 
1365
  Simply output the improved SWOT as a clean, final deliverable."""
 
1404
 
1405
  === OUTPUT FORMAT ===
1406
 
1407
+ Produce a SWOT analysis using TABLES with this exact structure:
1408
 
1409
  ## Strengths
1410
+ | Ref | Metric | Insight |
1411
+ |-----|--------|---------|
1412
+ | M01 | Revenue: $394.3B | Strong market position with substantial scale |
1413
+ | M02 | Net Margin: 24.3% | High profitability indicates pricing power |
1414
+
1415
+ (Include 3-5 rows per section)
1416
 
1417
  ## Weaknesses
1418
+ | Ref | Metric | Insight |
1419
+ |-----|--------|---------|
1420
+ | M04 | Debt/Equity: 1.87 | Elevated leverage increases financial risk |
 
 
1421
 
1422
  ## Opportunities
1423
+ | Ref | Metric | Insight |
1424
+ |-----|--------|---------|
1425
+ | M12 | GDP Growth: 4.3% | Favorable macro environment for expansion |
 
1426
 
1427
  ## Threats
1428
+ | Ref | Metric | Insight |
1429
+ |-----|--------|---------|
1430
+ | M13 | Interest Rate: 3.72% | Higher borrowing costs may impact margins |
 
 
1431
 
1432
  ## Data Quality Notes
1433
+ - Metrics Used: [List key metrics analyzed]
1434
+ - Data Gaps: [Any unavailable metrics]
1435
+ - Confidence: [High/Medium/Low]
1436
+
1437
+ CRITICAL REQUIREMENTS:
1438
+ 1. Use TABLE format as shown above - NOT bullet points
1439
+ 2. Every row MUST cite a metric reference [M##] in the Ref column
1440
+ 3. Metric column: Name and value (e.g., "Revenue: $394.3B")
1441
+ 4. Insight column: One concise sentence explaining strategic implication
1442
+ 5. Use EXACT values from the METRIC REFERENCE TABLE - do NOT round"""
1443
 
1444
  return prompt, metric_lookup, ref_hash
1445