Spaces:
Sleeping
Sleeping
| import { useState } from 'react'; | |
| import { settleArgument } from './utils/api'; | |
| function ScoreBar({ label, value, color }) { | |
| return ( | |
| <div className="score-bar-wrap"> | |
| <div className="score-bar-label">{label}</div> | |
| <div className="score-bar-track"> | |
| <div className="score-bar-fill" style={{ width: `${value}%`, background: color }}></div> | |
| </div> | |
| <span className="score-bar-val">{value}</span> | |
| </div> | |
| ); | |
| } | |
| function SidePanel({ side, color, accentClass }) { | |
| return ( | |
| <div className={`detail-section ${accentClass}`}> | |
| <h3 style={{ color }}>{side.name}</h3> | |
| <div className="mini-scores"> | |
| <ScoreBar label="Overall" value={side.score} color={color} /> | |
| <ScoreBar label="Persuasiveness" value={side.persuasivenessScore} color={color} /> | |
| <ScoreBar label="Factual Accuracy" value={side.factualScore} color={color} /> | |
| </div> | |
| {side.emotionalVsRational && ( | |
| <div className="emo-rational"> | |
| <span>Emotional {side.emotionalVsRational.emotional}%</span> | |
| <div className="emo-bar"> | |
| <div className="emo-fill" style={{ width: `${side.emotionalVsRational.emotional}%` }}></div> | |
| </div> | |
| <span>Rational {side.emotionalVsRational.rational}%</span> | |
| </div> | |
| )} | |
| <h4>Strengths</h4> | |
| <ul className="list-good">{side.strengths?.map((s, i) => <li key={i}>{s}</li>)}</ul> | |
| <h4>Weaknesses</h4> | |
| <ul className="list-bad">{side.weaknesses?.map((w, i) => <li key={i}>{w}</li>)}</ul> | |
| {side.fallacies?.length > 0 && ( | |
| <> | |
| <h4>Logical Fallacies Detected</h4> | |
| {side.fallacies.map((f, i) => ( | |
| <div className="fallacy-card" key={i}> | |
| <span className="fallacy-name">{f.name}</span> | |
| {f.quote && <p className="fallacy-quote">"{f.quote}"</p>} | |
| <p className="fallacy-explain">{f.explanation}</p> | |
| </div> | |
| ))} | |
| </> | |
| )} | |
| <h4>Evidence Quality</h4> | |
| <p className="info-text">{side.evidenceQuality}</p> | |
| <h4 style={{ color: '#ff6b6b' }}>Devil's Advocate</h4> | |
| <p className="info-text">{side.devilsAdvocate}</p> | |
| <h4 style={{ color: '#4ade80' }}>Steel Man (Strongest Version)</h4> | |
| <p className="info-text">{side.steelMan}</p> | |
| <h4>What Would Change Their Mind?</h4> | |
| <p className="info-text">{side.whatWouldChangeTheirMind}</p> | |
| </div> | |
| ); | |
| } | |
| export default function App() { | |
| const [topic, setTopic] = useState(''); | |
| const [side1Name, setSide1Name] = useState(''); | |
| const [side1Argument, setSide1Argument] = useState(''); | |
| const [side2Name, setSide2Name] = useState(''); | |
| const [side2Argument, setSide2Argument] = useState(''); | |
| const [result, setResult] = useState(null); | |
| const [loading, setLoading] = useState(false); | |
| const [error, setError] = useState(''); | |
| const handleSubmit = async () => { | |
| if (!topic || !side1Argument || !side2Argument) { | |
| setError('Please fill in the topic and both arguments'); | |
| return; | |
| } | |
| setLoading(true); | |
| setError(''); | |
| try { | |
| const data = await settleArgument(topic, side1Name || 'Person A', side1Argument, side2Name || 'Person B', side2Argument); | |
| setResult(data); | |
| } catch (err) { | |
| setError(err.message); | |
| } finally { | |
| setLoading(false); | |
| } | |
| }; | |
| const reset = () => { | |
| setResult(null); | |
| setTopic(''); | |
| setSide1Name(''); | |
| setSide1Argument(''); | |
| setSide2Name(''); | |
| setSide2Argument(''); | |
| }; | |
| if (loading) { | |
| return ( | |
| <div className="app"> | |
| <h1><span>Argument Settler</span></h1> | |
| <div className="loading"> | |
| <div className="spinner"></div> | |
| <p>The Settler is analyzing both sides...</p> | |
| <p style={{ color: '#888', marginTop: '0.5rem', fontSize: '0.9rem' }}>Checking for logical fallacies, biases, and evidence quality</p> | |
| </div> | |
| </div> | |
| ); | |
| } | |
| if (result) { | |
| return ( | |
| <div className="app"> | |
| <h1><span>Argument Settler</span></h1> | |
| <div className="results"> | |
| {/* Verdict */} | |
| <div className="verdict-card"> | |
| <div style={{ fontSize: '0.9rem', color: '#888', marginBottom: '0.5rem' }}>THE WINNER IS</div> | |
| <div className="winner-name">{result.winner === 'Draw' ? "It's a Draw!" : result.winner}</div> | |
| <div className="verdict-text">{result.verdict}</div> | |
| </div> | |
| {/* Score comparison */} | |
| <div className="scores"> | |
| <div className="score-card left"> | |
| <h3>{result.side1?.name}</h3> | |
| <div className="score-number">{result.side1?.score}<span>/100</span></div> | |
| </div> | |
| <div className="vs-badge">VS</div> | |
| <div className="score-card right"> | |
| <h3>{result.side2?.name}</h3> | |
| <div className="score-number">{result.side2?.score}<span>/100</span></div> | |
| </div> | |
| </div> | |
| {/* Detailed panels */} | |
| <div className="scores"> | |
| {result.side1 && <SidePanel side={result.side1} color="#ff6b6b" accentClass="accent-left" />} | |
| {result.side2 && <SidePanel side={result.side2} color="#4ecdc4" accentClass="accent-right" />} | |
| </div> | |
| {/* Bias Check */} | |
| {result.biasCheck && ( | |
| <div className="insight-card bias"> | |
| <h4>Shared Bias Check</h4> | |
| <p>{result.biasCheck}</p> | |
| </div> | |
| )} | |
| {/* Common Ground */} | |
| {result.commonGround && ( | |
| <div className="insight-card common"> | |
| <h4>Common Ground</h4> | |
| <p>{result.commonGround}</p> | |
| </div> | |
| )} | |
| {/* Compromise */} | |
| {result.compromise && ( | |
| <div className="insight-card compromise"> | |
| <h4>Suggested Compromise</h4> | |
| <p>{result.compromise}</p> | |
| </div> | |
| )} | |
| {/* Plot Twist */} | |
| {result.plotTwist && ( | |
| <div className="plot-twist"> | |
| <h4>Plot Twist</h4> | |
| <p>{result.plotTwist}</p> | |
| </div> | |
| )} | |
| {/* Debate Tips */} | |
| {result.debateTips && ( | |
| <div className="scores"> | |
| <div className="insight-card tip-left"> | |
| <h4>Tip for {result.side1?.name}</h4> | |
| <p>{result.debateTips.side1Tip}</p> | |
| </div> | |
| <div className="insight-card tip-right"> | |
| <h4>Tip for {result.side2?.name}</h4> | |
| <p>{result.debateTips.side2Tip}</p> | |
| </div> | |
| </div> | |
| )} | |
| <button className="btn back-btn" onClick={reset}>Settle Another Argument</button> | |
| </div> | |
| </div> | |
| ); | |
| } | |
| return ( | |
| <div className="app"> | |
| <h1><span>Argument Settler</span></h1> | |
| <p className="subtitle">AI debate judge with logical fallacy detection, evidence scoring, and bias analysis.</p> | |
| {error && <p style={{ color: '#ff6b6b', textAlign: 'center', marginBottom: '1rem' }}>{error}</p>} | |
| <div className="form-section"> | |
| <div className="input-group"> | |
| <label>What's the argument about?</label> | |
| <input placeholder="e.g., Pineapple on pizza, Tabs vs Spaces, Who should do the dishes..." value={topic} onChange={e => setTopic(e.target.value)} /> | |
| </div> | |
| </div> | |
| <div className="sides-container"> | |
| <div className="side left"> | |
| <h3>Side A</h3> | |
| <div className="input-group"> | |
| <label>Name (optional)</label> | |
| <input placeholder="Person A" value={side1Name} onChange={e => setSide1Name(e.target.value)} /> | |
| </div> | |
| <div className="input-group"> | |
| <label>Their argument</label> | |
| <textarea placeholder="State your case..." value={side1Argument} onChange={e => setSide1Argument(e.target.value)} /> | |
| </div> | |
| </div> | |
| <div className="side right"> | |
| <h3>Side B</h3> | |
| <div className="input-group"> | |
| <label>Name (optional)</label> | |
| <input placeholder="Person B" value={side2Name} onChange={e => setSide2Name(e.target.value)} /> | |
| </div> | |
| <div className="input-group"> | |
| <label>Their argument</label> | |
| <textarea placeholder="State your case..." value={side2Argument} onChange={e => setSide2Argument(e.target.value)} /> | |
| </div> | |
| </div> | |
| </div> | |
| <button className="btn" onClick={handleSubmit} style={{ marginTop: '1.5rem' }}>Settle This!</button> | |
| </div> | |
| ); | |
| } | |