Member-Created AI for Investor Styles – Using Claude Artifacts

TL;DR: When you are done you get what I would call an App (with internal AI, ability to upload documents, search the web and be modified by the user). Joel Greenblatt as an example:

Want to explore investor-style AI workflows? Try this:

  1. Copy the code below
  2. Visit this link: Claude Artifact Workspace (a free membership should work)
  3. Type: “Create an artifact with this code”
  4. Paste or upload the code
  5. Enter the name of your favorite investor into the Artifact
  6. Ask Claude to customize the Artifact with your own ideas or improvements

Important: Turn on " Create AI-powered artifacts" in the settings. This allow Claude AI to work within the artifact.

This is an early proof of concept. You may need to refine the generated code before using it in a ranking system. However, if this approach gains traction, we could develop a set of standard uploads—or a shared link—containing properly formatted P123 feature code (with additional resources). This would allow AI-generated features to be copied and pasted directly into ranking systems with minimal adjustments. I haven’t implemented that here, but members and staff could collaborate on it if we decide to adopt Artifacts more broadly.

If there’s enough interest, we could build a shared library of AI-generated investing Artifacts and standard tools, contributed by both members and staff.

Note: When you copy and run an Artifact, it operates entirely within your own Claude account (it will work with free accounts). The original creator’s account is neither accessed or billed.

import React, { useState } from 'react';
import { Search, TrendingUp, Copy, CheckCircle, User } from 'lucide-react';

const InvestorRankingGenerator = () => {
  const [investorName, setInvestorName] = useState('');
  const [loading, setLoading] = useState(false);
  const [result, setResult] = useState(null);
  const [error, setError] = useState(null);
  const [copiedIndex, setCopiedIndex] = useState(null);

  const generateRanking = async () => {
    if (!investorName.trim()) return;
    
    setLoading(true);
    setError(null);
    setResult(null);

    try {
      const prompt = `
You are an expert in quantitative investment analysis and Portfolio 123 ranking systems. 

Research the investment philosophy and methodology of ${investorName}. Then generate a Portfolio 123 ranking system that captures their investment style.

Respond with ONLY valid JSON in this exact format:
{
  "investor": "Investor Name",
  "philosophy": "Brief description of their investment approach",
  "factors": [
    {
      "name": "Factor Name",
      "description": "Why this factor represents their style",
      "weight": 25,
      "formula": "Portfolio 123 formula syntax"
    }
  ],
  "rankingFormula": "Combined Portfolio 123 ranking formula",
  "explanation": "How this ranking system reflects their methodology"
}

Important: 
- Use actual Portfolio 123 syntax for formulas (e.g., "ROE()", "PERatio()", "DebtToEquity()")
- Weights should sum to 100
- Include 4-6 key factors that best represent their style
- Make formulas implementable in Portfolio 123

CRITICAL: Your entire response must be ONLY the JSON object. DO NOT include markdown code blocks, backticks, or any other text. Start directly with { and end with }.
`;

      const response = await window.claude.complete(prompt);
      
      // Handle potential markdown wrapping
      let cleanResponse = response.trim();
      if (cleanResponse.startsWith('```json')) {
        cleanResponse = cleanResponse.replace(/```json\s*/, '').replace(/```\s*$/, '');
      }
      if (cleanResponse.startsWith('```')) {
        cleanResponse = cleanResponse.replace(/```\s*/, '').replace(/```\s*$/, '');
      }
      
      const parsedResult = JSON.parse(cleanResponse);
      setResult(parsedResult);
      
    } catch (err) {
      setError('Failed to generate ranking system. Please try again.');
      console.error('Error:', err);
    } finally {
      setLoading(false);
    }
  };

  const copyToClipboard = async (text, index) => {
    try {
      await navigator.clipboard.writeText(text);
      setCopiedIndex(index);
      setTimeout(() => setCopiedIndex(null), 2000);
    } catch (err) {
      console.error('Failed to copy:', err);
    }
  };

  return (
    <div className="min-h-screen bg-gradient-to-br from-slate-900 via-blue-900 to-slate-900 text-white">
      <div className="container mx-auto px-4 py-8">
        {/* Header */}
        <div className="text-center mb-12">
          <div className="flex items-center justify-center gap-3 mb-6">
            <TrendingUp className="w-12 h-12 text-blue-400" />
            <h1 className="text-4xl font-bold bg-gradient-to-r from-blue-400 to-purple-400 bg-clip-text text-transparent">
              Investor Style Ranking Generator
            </h1>
          </div>
          <p className="text-xl text-slate-300 max-w-2xl mx-auto">
            Transform any investor's philosophy into Portfolio 123 ranking formulas
          </p>
        </div>

        {/* Input Form */}
        <div className="max-w-2xl mx-auto mb-12">
          <div className="space-y-6">
            <div className="relative">
              <User className="absolute left-4 top-4 w-5 h-5 text-slate-400" />
              <input
                type="text"
                value={investorName}
                onChange={(e) => setInvestorName(e.target.value)}
                onKeyPress={(e) => e.key === 'Enter' && generateRanking()}
                placeholder="Enter investor name (e.g., Warren Buffett, Peter Lynch, Joel Greenblatt)"
                className="w-full pl-12 pr-4 py-4 bg-slate-800/50 border border-slate-600 rounded-xl text-white placeholder-slate-400 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent text-lg"
              />
            </div>
            
            <button
              onClick={generateRanking}
              disabled={loading || !investorName.trim()}
              className="w-full py-4 px-6 bg-gradient-to-r from-blue-600 to-purple-600 hover:from-blue-700 hover:to-purple-700 disabled:from-slate-600 disabled:to-slate-600 disabled:cursor-not-allowed rounded-xl font-semibold text-lg transition-all duration-200 flex items-center justify-center gap-2"
            >
              {loading ? (
                <>
                  <div className="animate-spin rounded-full h-5 w-5 border-b-2 border-white"></div>
                  Researching {investorName}…
                </>
              ) : (
                <>
                  <Search className="w-5 h-5" />
                  Generate Ranking System
                </>
              )}
            </button>
          </div>
        </div>

        {/* Error Display */}
        {error && (
          <div className="max-w-4xl mx-auto mb-8 p-4 bg-red-900/20 border border-red-700 rounded-xl">
            <p className="text-red-300">{error}</p>
          </div>
        )}

        {/* Results */}
        {result && (
          <div className="max-w-6xl mx-auto space-y-8">
            {/* Investor Overview */}
            <div className="bg-slate-800/30 backdrop-blur-sm border border-slate-700 rounded-xl p-6">
              <h2 className="text-2xl font-bold mb-4 text-blue-400">{result.investor}</h2>
              <p className="text-slate-300 text-lg leading-relaxed">{result.philosophy}</p>
            </div>

            {/* Factors */}
            <div className="bg-slate-800/30 backdrop-blur-sm border border-slate-700 rounded-xl p-6">
              <h3 className="text-xl font-bold mb-6 text-purple-400">Ranking Factors</h3>
              <div className="grid gap-4">
                {result.factors.map((factor, index) => (
                  <div key={index} className="bg-slate-900/40 border border-slate-600 rounded-lg p-4">
                    <div className="flex items-start justify-between mb-2">
                      <h4 className="text-lg font-semibold text-white">{factor.name}</h4>
                      <span className="bg-blue-600 text-white px-2 py-1 rounded-md text-sm font-medium">
                        {factor.weight}%
                      </span>
                    </div>
                    <p className="text-slate-300 mb-3">{factor.description}</p>
                    <div className="bg-slate-800 rounded-md p-3 font-mono text-sm">
                      <div className="flex items-center justify-between">
                        <code className="text-green-400">{factor.formula}</code>
                        <button
                          onClick={() => copyToClipboard(factor.formula, `factor-${index}`)}
                          className="ml-2 p-1 hover:bg-slate-700 rounded transition-colors"
                        >
                          {copiedIndex === `factor-${index}` ? (
                            <CheckCircle className="w-4 h-4 text-green-400" />
                          ) : (
                            <Copy className="w-4 h-4 text-slate-400" />
                          )}
                        </button>
                      </div>
                    </div>
                  </div>
                ))}
              </div>
            </div>

            {/* Implementation Framework */}
            <div className="bg-slate-800/30 backdrop-blur-sm border border-slate-700 rounded-xl p-6">
              <h3 className="text-xl font-bold mb-4 text-purple-400">Implementation Framework</h3>
              
              {/* Factor Summary */}
              <div className="mb-6">
                <h4 className="text-lg font-semibold mb-3 text-white">Factor Weights Summary</h4>
                <div className="grid grid-cols-1 md:grid-cols-2 gap-3">
                  {result.factors.map((factor, index) => (
                    <div key={index} className="bg-slate-900/40 border border-slate-600 rounded-lg p-3">
                      <div className="flex justify-between items-center">
                        <span className="text-white font-medium">{factor.name}</span>
                        <span className="bg-blue-600 text-white px-2 py-1 rounded text-sm font-medium">
                          {factor.weight}%
                        </span>
                      </div>
                    </div>
                  ))}
                </div>
              </div>

              {/* Sample Code */}
              <div className="mb-4">
                <h4 className="text-lg font-semibold mb-3 text-white">Sample Portfolio 123 Code Structure</h4>
                <div className="bg-slate-900/60 rounded-lg p-4">
                  <div className="flex items-start justify-between">
                    <code className="text-green-400 font-mono text-sm leading-relaxed break-all">
                      {result.rankingFormula}
                    </code>
                    <button
                      onClick={() => copyToClipboard(result.rankingFormula, 'main-formula')}
                      className="ml-3 p-2 hover:bg-slate-700 rounded transition-colors flex-shrink-0"
                    >
                      {copiedIndex === 'main-formula' ? (
                        <CheckCircle className="w-5 h-5 text-green-400" />
                      ) : (
                        <Copy className="w-5 h-5 text-slate-400" />
                      )}
                    </button>
                  </div>
                </div>
              </div>
              
              <p className="text-slate-300 leading-relaxed">{result.explanation}</p>
            </div>

            {/* Implementation Guide */}
            <div className="bg-gradient-to-r from-blue-900/20 to-purple-900/20 border border-blue-700/50 rounded-xl p-6">
              <h3 className="text-xl font-bold mb-4 text-blue-400">Portfolio 123 Implementation Guide</h3>
              <div className="space-y-4 text-slate-300">
                <div>
                  <h4 className="font-semibold text-white mb-2">Step 1: Create Individual Factors</h4>
                  <p>Use the factor formulas above as starting points. You may need to adjust function names to match your Portfolio 123 version (e.g., ROE() vs Return_on_Equity).</p>
                </div>
                <div>
                  <h4 className="font-semibold text-white mb-2">Step 2: Build Your Ranking System</h4>
                  <p>Create a new ranking system combining these factors with the suggested weights. Start with the sample code structure and adapt the syntax to your Portfolio 123 environment.</p>
                </div>
                <div>
                  <h4 className="font-semibold text-white mb-2">Step 3: Test and Refine</h4>
                  <p>Backtest the ranking system and adjust weights based on performance. The suggested weights are starting points - optimize them for your specific goals and risk tolerance.</p>
                </div>
                <div>
                  <h4 className="font-semibold text-white mb-2">Note on Code Syntax</h4>
                  <p className="text-yellow-300">⚠️ The code provided is a best-effort approximation. Portfolio 123 function names and syntax may vary. Use this as a framework and adapt to your specific Portfolio 123 setup.</p>
                </div>
              </div>
            </div>
          </div>
        )}
      </div>
    </div>
  );
};

export default InvestorRankingGenerator;

:bar_chart: TL;DR: Bayesian Forecast Tracker Inspired by Tetlock's Superforecasting

Here is code for a probability estimator (Bayesian updating). Start with a probability. Claude can help you with that and then get a new probably as new information becomes available. Can be used for sports betting: probability of the Patriots winning the SuperBowl at the beginning of the season. Updated as the season progresses. Wins, losses, injuries or whatever you think will affect the odds. Chances of a recession updated by today's job report as example here:

import React, { useState } from 'react';
import { PlusCircle, TrendingUp, History, Calculator, Target, Trash2 } from 'lucide-react';

const BayesianUpdater = () => {
  const [hypotheses, setHypotheses] = useState([{
    id: 1,
    title: "US Recession by End of 2025",
    description: "The United States will enter a recession (as defined by NBER or two consecutive quarters of negative GDP growth) before December 31, 2025.",
    currentProbability: 30,
    history: [{
      type: 'initial',
      probability: 30,
      description: 'Initial estimate based on expert forecasts (J.P. Morgan 40%, NY Fed 27%, economists 35%)',
      timestamp: new Date().toLocaleString()
    }]
  }]);
  const [activeHypothesis, setActiveHypothesis] = useState({
    id: 1,
    title: "US Recession by End of 2025",
    description: "The United States will enter a recession (as defined by NBER or two consecutive quarters of negative GDP growth) before December 31, 2025.",
    currentProbability: 30,
    history: [{
      type: 'initial',
      probability: 30,
      description: 'Initial estimate based on expert forecasts (J.P. Morgan 40%, NY Fed 27%, economists 35%)',
      timestamp: new Date().toLocaleString()
    }]
  });
  const [showNewHypothesis, setShowNewHypothesis] = useState(false);
  const [showAddEvidence, setShowAddEvidence] = useState(false);

  const [newHypothesis, setNewHypothesis] = useState({
    title: '',
    description: '',
    initialProbability: 50
  });

  const [newEvidence, setNewEvidence] = useState({
    description: '',
    probIfTrue: 50,
    probIfFalse: 50
  });

  const createHypothesis = () => {
    if (!newHypothesis.title.trim()) return;

    const hypothesis = {
      id: Date.now(),
      title: newHypothesis.title,
      description: newHypothesis.description,
      currentProbability: newHypothesis.initialProbability,
      history: [{
        type: 'initial',
        probability: newHypothesis.initialProbability,
        description: 'Initial estimate',
        timestamp: new Date().toLocaleString()
      }]
    };

    setHypotheses([...hypotheses, hypothesis]);
    setActiveHypothesis(hypothesis);
    setNewHypothesis({ title: '', description: '', initialProbability: 50 });
    setShowNewHypothesis(false);
  };

  const addEvidence = () => {
    if (!newEvidence.description.trim() || !activeHypothesis) return;

    // Bayes' theorem calculation
    const priorProb = activeHypothesis.currentProbability / 100;
    const probEvidenceIfTrue = newEvidence.probIfTrue / 100;
    const probEvidenceIfFalse = newEvidence.probIfFalse / 100;

    // P(E) = P(E|H) * P(H) + P(E|¬H) * P(¬H)
    const totalProbEvidence = probEvidenceIfTrue * priorProb + probEvidenceIfFalse * (1 - priorProb);

    // P(H|E) = P(E|H) * P(H) / P(E)
    const posteriorProb = (probEvidenceIfTrue * priorProb) / totalProbEvidence;
    const posteriorProbPercent = Math.round(posteriorProb * 100 * 100) / 100;

    const evidenceEntry = {
      type: 'evidence',
      description: newEvidence.description,
      probIfTrue: newEvidence.probIfTrue,
      probIfFalse: newEvidence.probIfFalse,
      priorProbability: activeHypothesis.currentProbability,
      probability: posteriorProbPercent,
      timestamp: new Date().toLocaleString()
    };

    const updatedHypothesis = {
      ...activeHypothesis,
      currentProbability: posteriorProbPercent,
      history: [...activeHypothesis.history, evidenceEntry]
    };

    setHypotheses(hypotheses.map(h => h.id === activeHypothesis.id ? updatedHypothesis : h));
    setActiveHypothesis(updatedHypothesis);
    setNewEvidence({ description: '', probIfTrue: 50, probIfFalse: 50 });
    setShowAddEvidence(false);
  };

  const deleteHypothesis = (hypothesisId) => {
    const updatedHypotheses = hypotheses.filter(h => h.id !== hypothesisId);
    setHypotheses(updatedHypotheses);
    
    // If we're deleting the currently active hypothesis, clear the active selection
    // User can manually choose which hypothesis to work with next
    if (activeHypothesis && activeHypothesis.id === hypothesisId) {
      setActiveHypothesis(null);
    }
  };

  const formatProbability = (prob) => {
    return `${prob}%`;
  };

  const getProbabilityColor = (prob) => {
    if (prob < 25) return 'text-red-600';
    if (prob < 50) return 'text-orange-600';
    if (prob < 75) return 'text-yellow-600';
    return 'text-green-600';
  };

  return (
    <div className="max-w-4xl mx-auto p-6 bg-gray-50 min-h-screen">
      <div className="bg-white rounded-lg shadow-lg p-6 mb-6">
        <div className="flex items-center justify-between mb-6">
          <div className="flex items-center space-x-3">
            <Target className="h-8 w-8 text-blue-600" />
            <h1 className="text-3xl font-bold text-gray-800">Bayesian Updater</h1>
          </div>
          <button
            onClick={() => setShowNewHypothesis(true)}
            className="flex items-center space-x-2 bg-blue-600 text-white px-4 py-2 rounded-lg hover:bg-blue-700 transition-colors"
          >
            <PlusCircle className="h-5 w-5" />
            <span>New Hypothesis</span>
          </button>
        </div>

        {!activeHypothesis && hypotheses.length === 0 && (
          <div className="text-center py-12">
            <Calculator className="h-16 w-16 text-gray-400 mx-auto mb-4" />
            <h2 className="text-xl font-semibold text-gray-600 mb-2">No Hypotheses Yet</h2>
            <p className="text-gray-500">Create your first hypothesis to start tracking probabilities</p>
          </div>
        )}

        {hypotheses.length > 0 && (
          <div className="mb-6">
            <label className="block text-sm font-medium text-gray-700 mb-2">Select Hypothesis</label>
            <select
              value={activeHypothesis?.id || ''}
              onChange={(e) => setActiveHypothesis(hypotheses.find(h => h.id === parseInt(e.target.value)))}
              className="w-full p-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
            >
              <option value="">Choose a hypothesis...</option>
              {hypotheses.map(h => (
                <option key={h.id} value={h.id}>{h.title}</option>
              ))}
            </select>
          </div>
        )}

        {activeHypothesis && (
          <div className="bg-gradient-to-r from-blue-50 to-indigo-50 rounded-lg p-6 mb-6">
            <h2 className="text-2xl font-bold text-gray-800 mb-2">{activeHypothesis.title}</h2>
            {activeHypothesis.description && (
              <p className="text-gray-600 mb-4">{activeHypothesis.description}</p>
            )}
            <div className="flex items-center justify-between">
              <div className="flex items-center space-x-4">
                <div className="text-center">
                  <div className="text-sm text-gray-500">Current Probability</div>
                  <div className={`text-4xl font-bold ${getProbabilityColor(activeHypothesis.currentProbability)}`}>
                    {formatProbability(activeHypothesis.currentProbability)}
                  </div>
                </div>
                <TrendingUp className="h-8 w-8 text-blue-600" />
              </div>
              <div className="flex space-x-3">
                <button
                  onClick={() => setShowAddEvidence(true)}
                  className="bg-green-600 text-white px-4 py-2 rounded-lg hover:bg-green-700 transition-colors flex items-center space-x-2"
                >
                  <PlusCircle className="h-5 w-5" />
                  <span>Add Evidence</span>
                </button>
                <button
                  onClick={() => deleteHypothesis(activeHypothesis.id)}
                  className="bg-red-600 text-white px-4 py-2 rounded-lg hover:bg-red-700 transition-colors flex items-center space-x-2"
                >
                  <Trash2 className="h-5 w-5" />
                  <span>Delete</span>
                </button>
              </div>
            </div>
          </div>
        )}

        {showNewHypothesis && (
          <div className="bg-white border border-gray-200 rounded-lg p-6 mb-6">
            <h3 className="text-lg font-semibold mb-4">Create New Hypothesis</h3>
            <div className="space-y-4">
              <div>
                <label className="block text-sm font-medium text-gray-700 mb-2">Hypothesis Title</label>
                <input
                  type="text"
                  value={newHypothesis.title}
                  onChange={(e) => setNewHypothesis({...newHypothesis, title: e.target.value})}
                  className="w-full p-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
                  placeholder="e.g., Nuclear war in Ukraine by end of 2025"
                />
              </div>
              <div>
                <label className="block text-sm font-medium text-gray-700 mb-2">Description (Optional)</label>
                <textarea
                  value={newHypothesis.description}
                  onChange={(e) => setNewHypothesis({...newHypothesis, description: e.target.value})}
                  className="w-full p-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent h-20 resize-none"
                  placeholder="Additional context or details..."
                />
              </div>
              <div>
                <label className="block text-sm font-medium text-gray-700 mb-2">
                  Initial Probability: {newHypothesis.initialProbability}%
                </label>
                <input
                  type="range"
                  min="0"
                  max="100"
                  value={newHypothesis.initialProbability}
                  onChange={(e) => setNewHypothesis({...newHypothesis, initialProbability: parseInt(e.target.value)})}
                  className="w-full h-2 bg-gray-200 rounded-lg appearance-none cursor-pointer"
                />
              </div>
              <div className="flex space-x-3">
                <button
                  onClick={createHypothesis}
                  className="bg-blue-600 text-white px-4 py-2 rounded-lg hover:bg-blue-700 transition-colors"
                >
                  Create Hypothesis
                </button>
                <button
                  onClick={() => setShowNewHypothesis(false)}
                  className="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition-colors"
                >
                  Cancel
                </button>
              </div>
            </div>
          </div>
        )}

        {showAddEvidence && activeHypothesis && (
          <div className="bg-white border border-gray-200 rounded-lg p-6 mb-6">
            <h3 className="text-lg font-semibold mb-4">Add New Evidence</h3>
            <div className="space-y-4">
              <div>
                <label className="block text-sm font-medium text-gray-700 mb-2">Evidence Description</label>
                <input
                  type="text"
                  value={newEvidence.description}
                  onChange={(e) => setNewEvidence({...newEvidence, description: e.target.value})}
                  className="w-full p-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
                  placeholder="e.g., NATO increases military aid to Ukraine"
                />
              </div>
              <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
                <div>
                  <label className="block text-sm font-medium text-gray-700 mb-2">
                    P(Evidence | Hypothesis True): {newEvidence.probIfTrue}%
                  </label>
                  <input
                    type="range"
                    min="0"
                    max="100"
                    value={newEvidence.probIfTrue}
                    onChange={(e) => setNewEvidence({...newEvidence, probIfTrue: parseInt(e.target.value)})}
                    className="w-full h-2 bg-gray-200 rounded-lg appearance-none cursor-pointer"
                  />
                  <p className="text-xs text-gray-500 mt-1">How likely is this evidence if the hypothesis is true?</p>
                </div>
                <div>
                  <label className="block text-sm font-medium text-gray-700 mb-2">
                    P(Evidence | Hypothesis False): {newEvidence.probIfFalse}%
                  </label>
                  <input
                    type="range"
                    min="0"
                    max="100"
                    value={newEvidence.probIfFalse}
                    onChange={(e) => setNewEvidence({...newEvidence, probIfFalse: parseInt(e.target.value)})}
                    className="w-full h-2 bg-gray-200 rounded-lg appearance-none cursor-pointer"
                  />
                  <p className="text-xs text-gray-500 mt-1">How likely is this evidence if the hypothesis is false?</p>
                </div>
              </div>
              <div className="flex space-x-3">
                <button
                  onClick={addEvidence}
                  className="bg-green-600 text-white px-4 py-2 rounded-lg hover:bg-green-700 transition-colors"
                >
                  Update Probability
                </button>
                <button
                  onClick={() => setShowAddEvidence(false)}
                  className="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition-colors"
                >
                  Cancel
                </button>
              </div>
            </div>
          </div>
        )}

        {activeHypothesis && activeHypothesis.history.length > 0 && (
          <div className="bg-white border border-gray-200 rounded-lg p-6">
            <div className="flex items-center space-x-2 mb-4">
              <History className="h-5 w-5 text-gray-600" />
              <h3 className="text-lg font-semibold">Update History</h3>
            </div>
            <div className="space-y-3">
              {activeHypothesis.history.map((entry, index) => (
                <div key={index} className="flex items-center justify-between p-3 bg-gray-50 rounded-lg">
                  <div className="flex-1">
                    <div className="font-medium text-gray-800">{entry.description}</div>
                    <div className="text-sm text-gray-500">{entry.timestamp}</div>
                    {entry.type === 'evidence' && (
                      <div className="text-xs text-gray-500 mt-1">
                        P(E|H): {entry.probIfTrue}% | P(E|¬H): {entry.probIfFalse}%
                      </div>
                    )}
                  </div>
                  <div className="text-right">
                    {entry.type === 'evidence' && (
                      <div className="text-sm text-gray-500">
                        {formatProbability(entry.priorProbability)} →
                      </div>
                    )}
                    <div className={`text-lg font-bold ${getProbabilityColor(entry.probability)}`}>
                      {formatProbability(entry.probability)}
                    </div>
                  </div>
                </div>
              ))}
            </div>
          </div>
        )}
      </div>
    </div>
  );
};

export default BayesianUpdater;

1 Like