diff --git a/.env b/.env deleted file mode 100644 index 541be91..0000000 --- a/.env +++ /dev/null @@ -1,3 +0,0 @@ -GEMINI_MODEL=gemini-3.1-flash-lite-preview -GEMINI_API_KEY=AIzaSyBH3chuhCMlgbMZ3gmWvLYhokjJTbmXZCw -TAVILY_API_KEY=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 \ No newline at end of file diff --git a/.gitignore b/.gitignore index 438657a..a5f70a2 100644 --- a/.gitignore +++ b/.gitignore @@ -11,7 +11,6 @@ node_modules dist dist-ssr *.local -.env # Editor directories and files .vscode/* @@ -23,3 +22,7 @@ dist-ssr *.njsproj *.sln *.sw? + +.env +__pycache__/ +*.pyc \ No newline at end of file diff --git a/backend/__pycache__/__init__.cpython-312.pyc b/backend/__pycache__/__init__.cpython-312.pyc deleted file mode 100644 index 7f945ff..0000000 Binary files a/backend/__pycache__/__init__.cpython-312.pyc and /dev/null differ diff --git a/backend/__pycache__/__init__.cpython-313.pyc b/backend/__pycache__/__init__.cpython-313.pyc deleted file mode 100644 index 547b21e..0000000 Binary files a/backend/__pycache__/__init__.cpython-313.pyc and /dev/null differ diff --git a/backend/__pycache__/__init__.cpython-314.pyc b/backend/__pycache__/__init__.cpython-314.pyc deleted file mode 100644 index 482db36..0000000 Binary files a/backend/__pycache__/__init__.cpython-314.pyc and /dev/null differ diff --git a/backend/__pycache__/app.cpython-312.pyc b/backend/__pycache__/app.cpython-312.pyc deleted file mode 100644 index c47c4ff..0000000 Binary files a/backend/__pycache__/app.cpython-312.pyc and /dev/null differ diff --git a/backend/__pycache__/app.cpython-313.pyc b/backend/__pycache__/app.cpython-313.pyc deleted file mode 100644 index 260a7ac..0000000 Binary files a/backend/__pycache__/app.cpython-313.pyc and /dev/null differ diff --git a/backend/__pycache__/app.cpython-314.pyc b/backend/__pycache__/app.cpython-314.pyc deleted file mode 100644 index 6d78410..0000000 Binary files a/backend/__pycache__/app.cpython-314.pyc and /dev/null differ diff --git a/backend/__pycache__/db.cpython-312.pyc b/backend/__pycache__/db.cpython-312.pyc deleted file mode 100644 index cecb9e1..0000000 Binary files a/backend/__pycache__/db.cpython-312.pyc and /dev/null differ diff --git a/backend/__pycache__/db.cpython-313.pyc b/backend/__pycache__/db.cpython-313.pyc deleted file mode 100644 index ae23356..0000000 Binary files a/backend/__pycache__/db.cpython-313.pyc and /dev/null differ diff --git a/backend/__pycache__/db.cpython-314.pyc b/backend/__pycache__/db.cpython-314.pyc deleted file mode 100644 index 9152ea2..0000000 Binary files a/backend/__pycache__/db.cpython-314.pyc and /dev/null differ diff --git a/backend/__pycache__/fact_checking_agent.cpython-312.pyc b/backend/__pycache__/fact_checking_agent.cpython-312.pyc deleted file mode 100644 index 6d8f929..0000000 Binary files a/backend/__pycache__/fact_checking_agent.cpython-312.pyc and /dev/null differ diff --git a/backend/__pycache__/fact_checking_agent.cpython-313.pyc b/backend/__pycache__/fact_checking_agent.cpython-313.pyc deleted file mode 100644 index 1f644ff..0000000 Binary files a/backend/__pycache__/fact_checking_agent.cpython-313.pyc and /dev/null differ diff --git a/backend/__pycache__/grammatical_agent.cpython-312.pyc b/backend/__pycache__/grammatical_agent.cpython-312.pyc deleted file mode 100644 index 18ef3c6..0000000 Binary files a/backend/__pycache__/grammatical_agent.cpython-312.pyc and /dev/null differ diff --git a/backend/__pycache__/grammatical_agent.cpython-313.pyc b/backend/__pycache__/grammatical_agent.cpython-313.pyc deleted file mode 100644 index f36f135..0000000 Binary files a/backend/__pycache__/grammatical_agent.cpython-313.pyc and /dev/null differ diff --git a/backend/__pycache__/master_agent.cpython-312.pyc b/backend/__pycache__/master_agent.cpython-312.pyc deleted file mode 100644 index ec105da..0000000 Binary files a/backend/__pycache__/master_agent.cpython-312.pyc and /dev/null differ diff --git a/backend/__pycache__/master_agent.cpython-313.pyc b/backend/__pycache__/master_agent.cpython-313.pyc deleted file mode 100644 index e65584f..0000000 Binary files a/backend/__pycache__/master_agent.cpython-313.pyc and /dev/null differ diff --git a/backend/__pycache__/master_agent.cpython-314.pyc b/backend/__pycache__/master_agent.cpython-314.pyc deleted file mode 100644 index e35e25b..0000000 Binary files a/backend/__pycache__/master_agent.cpython-314.pyc and /dev/null differ diff --git a/backend/__pycache__/services.cpython-312.pyc b/backend/__pycache__/services.cpython-312.pyc deleted file mode 100644 index 48108e7..0000000 Binary files a/backend/__pycache__/services.cpython-312.pyc and /dev/null differ diff --git a/backend/__pycache__/services.cpython-313.pyc b/backend/__pycache__/services.cpython-313.pyc deleted file mode 100644 index d6d69f6..0000000 Binary files a/backend/__pycache__/services.cpython-313.pyc and /dev/null differ diff --git a/backend/__pycache__/services.cpython-314.pyc b/backend/__pycache__/services.cpython-314.pyc deleted file mode 100644 index 6896d9e..0000000 Binary files a/backend/__pycache__/services.cpython-314.pyc and /dev/null differ diff --git a/checkwise_stats/__pycache__/__init__.cpython-312.pyc b/checkwise_stats/__pycache__/__init__.cpython-312.pyc deleted file mode 100644 index 4a300ca..0000000 Binary files a/checkwise_stats/__pycache__/__init__.cpython-312.pyc and /dev/null differ diff --git a/checkwise_stats/__pycache__/__init__.cpython-313.pyc b/checkwise_stats/__pycache__/__init__.cpython-313.pyc deleted file mode 100644 index 5f5c976..0000000 Binary files a/checkwise_stats/__pycache__/__init__.cpython-313.pyc and /dev/null differ diff --git a/checkwise_stats/__pycache__/__init__.cpython-314.pyc b/checkwise_stats/__pycache__/__init__.cpython-314.pyc deleted file mode 100644 index 246a47c..0000000 Binary files a/checkwise_stats/__pycache__/__init__.cpython-314.pyc and /dev/null differ diff --git a/checkwise_stats/__pycache__/agent.cpython-312.pyc b/checkwise_stats/__pycache__/agent.cpython-312.pyc deleted file mode 100644 index 9fed11e..0000000 Binary files a/checkwise_stats/__pycache__/agent.cpython-312.pyc and /dev/null differ diff --git a/checkwise_stats/__pycache__/agent.cpython-313.pyc b/checkwise_stats/__pycache__/agent.cpython-313.pyc deleted file mode 100644 index ff03d83..0000000 Binary files a/checkwise_stats/__pycache__/agent.cpython-313.pyc and /dev/null differ diff --git a/checkwise_stats/__pycache__/agent.cpython-314.pyc b/checkwise_stats/__pycache__/agent.cpython-314.pyc deleted file mode 100644 index 1d6ddaf..0000000 Binary files a/checkwise_stats/__pycache__/agent.cpython-314.pyc and /dev/null differ diff --git a/checkwise_stats/__pycache__/cli.cpython-312.pyc b/checkwise_stats/__pycache__/cli.cpython-312.pyc deleted file mode 100644 index 46dfea7..0000000 Binary files a/checkwise_stats/__pycache__/cli.cpython-312.pyc and /dev/null differ diff --git a/checkwise_stats/__pycache__/cli.cpython-314.pyc b/checkwise_stats/__pycache__/cli.cpython-314.pyc deleted file mode 100644 index d7da2bf..0000000 Binary files a/checkwise_stats/__pycache__/cli.cpython-314.pyc and /dev/null differ diff --git a/checkwise_stats/__pycache__/state.cpython-312.pyc b/checkwise_stats/__pycache__/state.cpython-312.pyc deleted file mode 100644 index 425f726..0000000 Binary files a/checkwise_stats/__pycache__/state.cpython-312.pyc and /dev/null differ diff --git a/checkwise_stats/__pycache__/state.cpython-313.pyc b/checkwise_stats/__pycache__/state.cpython-313.pyc deleted file mode 100644 index 32f780a..0000000 Binary files a/checkwise_stats/__pycache__/state.cpython-313.pyc and /dev/null differ diff --git a/checkwise_stats/__pycache__/state.cpython-314.pyc b/checkwise_stats/__pycache__/state.cpython-314.pyc deleted file mode 100644 index 7f700e0..0000000 Binary files a/checkwise_stats/__pycache__/state.cpython-314.pyc and /dev/null differ diff --git a/checkwise_stats/__pycache__/text_analysis.cpython-312.pyc b/checkwise_stats/__pycache__/text_analysis.cpython-312.pyc deleted file mode 100644 index 9fdd590..0000000 Binary files a/checkwise_stats/__pycache__/text_analysis.cpython-312.pyc and /dev/null differ diff --git a/checkwise_stats/__pycache__/text_analysis.cpython-313.pyc b/checkwise_stats/__pycache__/text_analysis.cpython-313.pyc deleted file mode 100644 index a9d8fe3..0000000 Binary files a/checkwise_stats/__pycache__/text_analysis.cpython-313.pyc and /dev/null differ diff --git a/checkwise_stats/__pycache__/text_analysis.cpython-314.pyc b/checkwise_stats/__pycache__/text_analysis.cpython-314.pyc deleted file mode 100644 index dcfdf0d..0000000 Binary files a/checkwise_stats/__pycache__/text_analysis.cpython-314.pyc and /dev/null differ diff --git a/src/components/AgentCard.tsx b/src/components/AgentCard.tsx index 79d7513..73e9d33 100644 --- a/src/components/AgentCard.tsx +++ b/src/components/AgentCard.tsx @@ -32,23 +32,23 @@ const AgentCard = ({ agent, index, isOpen, onToggle, modalContent }: AgentCardPr animate={{ opacity: 1, y: 0 }} transition={{ delay: index * 0.1, duration: 0.4 }} onClick={onToggle} - className="group cursor-pointer rounded-lg border border-border bg-card p-5 transition-all hover:border-primary/40 hover:cyber-glow" + className="group cursor-pointer rounded-lg border border-slate-200 bg-white p-5 shadow-sm transition-all hover:border-yellow-500/40 hover:shadow-md dark:border-border dark:bg-card dark:shadow-none dark:hover:border-primary/40 dark:hover:cyber-glow" >
{iconMap[agent.icon]}
-

{agent.name}

-

{agent.description}

+

{agent.name}

+

{agent.description}

!open && onToggle()}> - +
{iconMap[agent.icon]}
- {agent.name} - + {agent.name} + {agent.details}
diff --git a/src/components/AnalysisSummaryModal.tsx b/src/components/AnalysisSummaryModal.tsx new file mode 100644 index 0000000..a71eaf1 --- /dev/null +++ b/src/components/AnalysisSummaryModal.tsx @@ -0,0 +1,310 @@ +import { useEffect, type ReactNode } from "react"; +import type { LucideIcon } from "lucide-react"; +import { BarChart3, FileText, Percent, ShieldCheck, SpellCheck, User } from "lucide-react"; + +import { Badge } from "@/components/ui/badge"; +import { + Dialog, + DialogContent, + DialogDescription, + DialogHeader, + DialogTitle, +} from "@/components/ui/dialog"; +import { Separator } from "@/components/ui/separator"; +import type { HistoryEntry, MasterScoreDetail } from "@/lib/statistical-agent"; + +interface AnalysisSummaryModalProps { + entry: HistoryEntry | null; + open: boolean; + onOpenChange: (open: boolean) => void; +} + +interface InfoItemProps { + icon: LucideIcon; + label: string; + value: string; +} + +interface ScorePanelProps { + icon: LucideIcon; + title: string; + score: string; + caption: string; + children: ReactNode; +} + +const clampPercentage = (score: number) => Math.max(0, Math.min(100, Math.round(score))); + +const formatPercentage = (value: number | null | undefined, scaleFraction = false) => { + if (typeof value !== "number" || Number.isNaN(value)) { + return "Not available"; + } + + const normalizedValue = scaleFraction && value >= 0 && value <= 1 ? value * 100 : value; + return `${clampPercentage(normalizedValue)}%`; +}; + +const formatRating = (value: string | number | null | undefined) => { + if (typeof value === "number") { + return `${clampPercentage(value)}%`; + } + + if (typeof value === "string" && value.trim()) { + return value.includes("%") ? value : `${value}%`; + } + + return "Not available"; +}; + +const formatInputType = (value: string) => value.replace(/_/g, " "); + +const formatDate = (value: string) => { + const parsedDate = new Date(value); + return Number.isNaN(parsedDate.getTime()) ? value : parsedDate.toLocaleString(); +}; + +const getReadableText = (entry: HistoryEntry) => + entry.submitted_text?.trim() || entry.text_preview?.trim() || "No submitted text was stored for this analysis."; + +const getGrammaticalScoreLabel = (entry: HistoryEntry) => { + const grammaticalResult = entry.structured_result?.grammatical_result; + if (!grammaticalResult) { + return "Not available"; + } + + const isAiVerdict = entry.structured_result?.verdict === "likely AI-generated"; + const displayedScore = isAiVerdict + ? grammaticalResult.score + : 100 - grammaticalResult.score; + const displayedLabel = isAiVerdict ? "likely AI-written" : "likely human-written"; + + return `${formatPercentage(displayedScore)} ${displayedLabel}`; +}; + +const getFactCheckingAiSuspicion = (trustScore: number | null | undefined) => { + if (typeof trustScore !== "number" || Number.isNaN(trustScore)) { + return "Not available"; + } + + return `${formatPercentage(100 - trustScore)} AI suspicion conversion`; +}; + +const findMasterScore = (scores: MasterScoreDetail[] | undefined, agent: string) => + scores?.find((scoreDetail) => scoreDetail.agent === agent); + +const InfoItem = ({ icon: Icon, label, value }: InfoItemProps) => ( +
+
+ +
+

{label}

+

{value}

+
+); + +const ScorePanel = ({ icon: Icon, title, score, caption, children }: ScorePanelProps) => ( +
+
+
+
+ +
+

{title}

+
+ + {score} + +
+

{caption}

+
{children}
+
+); + +const DetailRow = ({ label, value }: { label: string; value: string }) => ( +
+ {label} + {value} +
+); + +const ReasonList = ({ title, items }: { title: string; items: string[] }) => ( +
+

{title}

+ {items.length > 0 ? ( +
+ {items.map((item, index) => ( +

- {item}

+ ))} +
+ ) : ( +

No additional details were reported.

+ )} +
+); + +const AnalysisSummaryModal = ({ entry, open, onOpenChange }: AnalysisSummaryModalProps) => { + useEffect(() => { + if (!open || typeof document === "undefined") { + return undefined; + } + + const originalOverflow = document.body.style.overflow; + document.body.style.overflow = "hidden"; + + return () => { + document.body.style.overflow = originalOverflow; + }; + }, [open]); + + const structuredResult = entry?.structured_result; + const signalBreakdown = structuredResult?.signal_breakdown; + const grammaticalResult = structuredResult?.grammatical_result; + const factCheckingResult = structuredResult?.fact_checking_result; + const masterScores = structuredResult?.master_result?.details?.scores; + const statisticalMasterScore = findMasterScore(masterScores, "statistical"); + const grammaticalMasterScore = findMasterScore(masterScores, "grammatical"); + const factCheckingMasterScore = findMasterScore(masterScores, "fact_checking"); + + return ( + + + {entry && ( + <> +
+ + Analysis Summary + + Detailed agent results for this saved analysis. + +
+ #{entry.id} + {formatInputType(entry.input_type)} + {formatDate(entry.created_at)} +
+
+
+ +
+
+ + + + +
+ +
+
+

Full Text / Preview

+ {getReadableText(entry).length.toLocaleString()} chars +
+
+ {getReadableText(entry)} +
+
+ + + +
+

Agent Scores

+
+ + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ + +
+ +
+ + +
+ +
+
+

Fact-Checking Details

+ {factCheckingResult?.total_claims ?? 0} claims +
+ {factCheckingResult?.claims?.length ? ( +
+ {factCheckingResult.claims.map((claim, index) => ( +
+
+
+

{claim.claim}

+

{claim.type.replace(/_/g, " ")}

+
+ {claim.verdict.replace(/_/g, " ")} +
+
+ Claim score: {formatPercentage(claim.claim_score)} + Confidence: {formatPercentage(claim.confidence_score)} +
+

{claim.explanation}

+
+ ))} +
+ ) : ( +

No factual claims were available for this analysis.

+ )} +
+
+ + )} +
+
+ ); +}; + +export default AnalysisSummaryModal; diff --git a/src/components/Navbar.tsx b/src/components/Navbar.tsx index d869bf0..1675f8e 100644 --- a/src/components/Navbar.tsx +++ b/src/components/Navbar.tsx @@ -18,33 +18,33 @@ const Navbar = ({ isLoggedIn, userEmail, onLogout }: NavbarProps) => { const links = [ { to: "/", label: "Home" }, { to: "/checker", label: "Checker" }, - ...(isLoggedIn ? [{ to: "/dashboard", label: "Dashboard" }, { to: "/settings", label: "Settings" }] : []), + ...(isLoggedIn ? [{ to: "/dashboard", label: "History" }, { to: "/settings", label: "Settings" }] : []), ]; const isActive = (path: string) => location.pathname === path; return ( -