Created
January 12, 2026 03:23
-
-
Save charleyXuTO/8c7bd9a2b5e9caca0f7b7e9fd9ae2793 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import React, { useState } from 'react'; | |
| import { AlertCircle, MessageSquare, Sparkles } from 'lucide-react'; | |
| export default function BaitDetector() { | |
| const [statement, setStatement] = useState(''); | |
| const [analysis, setAnalysis] = useState(null); | |
| const [loading, setLoading] = useState(false); | |
| const [error, setError] = useState(null); | |
| const analyzeStatement = async () => { | |
| if (!statement.trim()) { | |
| setError('Please enter a statement to analyze'); | |
| return; | |
| } | |
| setLoading(true); | |
| setError(null); | |
| setAnalysis(null); | |
| try { | |
| const response = await fetch('https://api.anthropic.com/v1/messages', { | |
| method: 'POST', | |
| headers: { | |
| 'Content-Type': 'application/json', | |
| }, | |
| body: JSON.stringify({ | |
| model: 'claude-sonnet-4-20250514', | |
| max_tokens: 1000, | |
| messages: [ | |
| { | |
| role: 'user', | |
| content: `Analyze the following statement and determine if it's "bait" (intentionally provocative, trolling, designed to get a reaction) or if it appears to be a sincerely held belief. | |
| Statement: "${statement}" | |
| Respond with a JSON object (and ONLY JSON, no markdown formatting) with this structure: | |
| { | |
| "classification": "bait" or "sincere", | |
| "confidence": a number from 0-100, | |
| "reasoning": "brief explanation of why you classified it this way", | |
| "indicators": ["list", "of", "specific", "indicators"] | |
| }` | |
| } | |
| ] | |
| }) | |
| }); | |
| const data = await response.json(); | |
| if (data.error) { | |
| throw new Error(data.error.message || 'API request failed'); | |
| } | |
| const textContent = data.content | |
| .filter(item => item.type === 'text') | |
| .map(item => item.text) | |
| .join(''); | |
| // Clean up any markdown formatting | |
| const cleanedText = textContent.replace(/```json\n?|\n?```/g, '').trim(); | |
| const result = JSON.parse(cleanedText); | |
| setAnalysis(result); | |
| } catch (err) { | |
| setError(err.message || 'Failed to analyze statement'); | |
| console.error('Error:', err); | |
| } finally { | |
| setLoading(false); | |
| } | |
| }; | |
| const handleKeyPress = (e) => { | |
| if (e.key === 'Enter' && !e.shiftKey) { | |
| e.preventDefault(); | |
| analyzeStatement(); | |
| } | |
| }; | |
| const getClassificationColor = (classification) => { | |
| return classification === 'bait' ? 'text-red-600' : 'text-green-600'; | |
| }; | |
| const getClassificationBg = (classification) => { | |
| return classification === 'bait' ? 'bg-red-50 border-red-200' : 'bg-green-50 border-green-200'; | |
| }; | |
| return ( | |
| <div className="min-h-screen bg-gradient-to-br from-indigo-50 via-white to-purple-50 p-6"> | |
| <div className="max-w-3xl mx-auto"> | |
| <div className="text-center mb-8"> | |
| <div className="flex items-center justify-center gap-2 mb-2"> | |
| <MessageSquare className="w-8 h-8 text-indigo-600" /> | |
| <h1 className="text-4xl font-bold text-gray-800">π£ Bait Detector π£</h1> | |
| </div> | |
| <p className="text-gray-600">Analyze whether a statement is genuine or just trolling π€π (for Charley's groupchat)</p> | |
| </div> | |
| <div className="bg-white rounded-lg shadow-lg p-6 mb-6"> | |
| <label className="block text-sm font-medium text-gray-700 mb-2"> | |
| Enter a statement to analyze: | |
| </label> | |
| <textarea | |
| value={statement} | |
| onChange={(e) => setStatement(e.target.value)} | |
| onKeyPress={handleKeyPress} | |
| placeholder="e.g., 'I genuinely think pineapple belongs on pizza π€' or 'Climate change is fake news lmao π'" | |
| className="w-full h-32 px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-transparent resize-none" | |
| /> | |
| {error && ( | |
| <div className="mt-3 p-3 bg-red-50 border border-red-200 rounded-lg flex items-start gap-2"> | |
| <AlertCircle className="w-5 h-5 text-red-600 flex-shrink-0 mt-0.5" /> | |
| <p className="text-sm text-red-800">{error}</p> | |
| </div> | |
| )} | |
| <button | |
| onClick={analyzeStatement} | |
| disabled={loading} | |
| className="mt-4 w-full bg-indigo-600 hover:bg-indigo-700 disabled:bg-gray-400 text-white font-semibold py-3 px-6 rounded-lg transition-colors flex items-center justify-center gap-2" | |
| > | |
| {loading ? ( | |
| <> | |
| <div className="w-5 h-5 border-2 border-white border-t-transparent rounded-full animate-spin" /> | |
| Analyzing... π€ | |
| </> | |
| ) : ( | |
| <> | |
| <Sparkles className="w-5 h-5" /> | |
| Analyze Statement π | |
| </> | |
| )} | |
| </button> | |
| </div> | |
| {analysis && ( | |
| <div className={`bg-white rounded-lg shadow-lg p-6 border-2 ${getClassificationBg(analysis.classification)}`}> | |
| <div className="flex items-center justify-between mb-4"> | |
| <h2 className="text-2xl font-bold text-gray-800">Analysis Result π</h2> | |
| <div className={`px-4 py-2 rounded-full font-bold ${getClassificationColor(analysis.classification)} ${getClassificationBg(analysis.classification)} border-2`}> | |
| {analysis.classification === 'bait' ? 'π€ BAIT π€' : 'π― SINCERE π―'} | |
| </div> | |
| </div> | |
| <div className="space-y-4"> | |
| <div> | |
| <h3 className="text-sm font-semibold text-gray-700 mb-1">Confidence Level πͺ</h3> | |
| <div className="flex items-center gap-3"> | |
| <div className="flex-1 bg-gray-200 rounded-full h-3 overflow-hidden"> | |
| <div | |
| className={`h-full transition-all duration-500 ${ | |
| analysis.classification === 'bait' ? 'bg-red-500' : 'bg-green-500' | |
| }`} | |
| style={{ width: `${analysis.confidence}%` }} | |
| /> | |
| </div> | |
| <span className="font-bold text-gray-700">{analysis.confidence}%</span> | |
| </div> | |
| </div> | |
| <div> | |
| <h3 className="text-sm font-semibold text-gray-700 mb-2">Reasoning π§ </h3> | |
| <p className="text-gray-800">{analysis.reasoning}</p> | |
| </div> | |
| <div> | |
| <h3 className="text-sm font-semibold text-gray-700 mb-2">Key Indicators π©</h3> | |
| <ul className="space-y-1"> | |
| {analysis.indicators.map((indicator, idx) => ( | |
| <li key={idx} className="flex items-start gap-2"> | |
| <span className="text-indigo-600 mt-1">β’</span> | |
| <span className="text-gray-700">{indicator}</span> | |
| </li> | |
| ))} | |
| </ul> | |
| </div> | |
| </div> | |
| </div> | |
| )} | |
| <div className="mt-6 text-center text-sm text-gray-500"> | |
| <p>Powered by Claude AI π€ β’ Don't take the bait π</p> | |
| </div> | |
| </div> | |
| </div> | |
| ); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment