Spaces:
Running
Running
Download frontend-react/src/components/ResultsPanel.jsx from manan77709/clearvoice-api: direct link, hf CLI and curl.
- Browser
- Download file 8.23 kB
-
https://huggingface.co/spaces/manan77709/clearvoice-api/resolve/main/frontend-react/src/components/ResultsPanel.jsx
- Command line
-
hf download hf://spaces/manan77709/clearvoice-api/frontend-react/src/components/ResultsPanel.jsx
-
curl -L -o ResultsPanel.jsx https://huggingface.co/spaces/manan77709/clearvoice-api/resolve/main/frontend-react/src/components/ResultsPanel.jsx
8.23 kB
| import { | |
| ChevronDown, | |
| ChevronUp, | |
| ExternalLink, | |
| Zap, | |
| Layers, | |
| FileText, | |
| Lightbulb, | |
| BookOpen, | |
| } from "lucide-react" | |
| import VerdictBadge from "./VerdictBadge" | |
| function StanceDot({ stance }) { | |
| const cls = | |
| stance === "SUPPORTS" | |
| ? "stance-dot--supports" | |
| : stance === "CONTRADICTS" | |
| ? "stance-dot--contradicts" | |
| : "stance-dot--neutral" | |
| return <span className={`stance-dot ${cls}`} aria-hidden="true" /> | |
| } | |
| export default function ResultsPanel({ result, expandedPapers, onTogglePaper }) { | |
| if (!result) return null | |
| const papersByPmid = new Map( | |
| (result.papers || []).map((p) => [String(p.pmid), p]) | |
| ) | |
| const hasSubResults = | |
| Array.isArray(result.sub_results) && | |
| (result.sub_results.length > 1 || (result.sub_results.length === 1 && result.decomposition?.is_complex)) | |
| return ( | |
| <div className="results"> | |
| <div className="results-card"> | |
| <div className="results-card__header"> | |
| <VerdictBadge verdict={result.verdict} /> | |
| <div className="results-stats"> | |
| <div className="results-stat"> | |
| <span className="results-stat__value">{Math.round((result.confidence ?? 0) * 100)}%</span> | |
| <span className="results-stat__label">Confidence</span> | |
| </div> | |
| <div className="results-stat"> | |
| <span className="results-stat__value">{result.evidence_strength || "—"}</span> | |
| <span className="results-stat__label">Evidence</span> | |
| </div> | |
| </div> | |
| </div> | |
| {result.cached && ( | |
| <p className="results-cache"> | |
| <Zap size={13} /> | |
| Served from cache | |
| </p> | |
| )} | |
| {hasSubResults ? ( | |
| <div className="results-block results-block--accent"> | |
| <div className="results-block__heading"> | |
| <Layers size={15} /> | |
| Complex claim — {result.sub_results.length} sub-claims analyzed | |
| </div> | |
| <div className="sub-results"> | |
| {result.sub_results.map((sr, i) => ( | |
| <div key={i} className="sub-result-item"> | |
| <span className="sub-result-item__claim">{sr.sub_claim}</span> | |
| <div className="sub-result-item__meta"> | |
| <VerdictBadge verdict={sr.verdict} /> | |
| <span>{Math.round((sr.confidence ?? 0) * 100)}%</span> | |
| <span>{sr.papers?.length ?? 0} studies</span> | |
| </div> | |
| </div> | |
| ))} | |
| </div> | |
| </div> | |
| ) : ( | |
| result.decomposition?.is_complex && Array.isArray(result.decomposition.sub_claims) && ( | |
| <div className="results-block results-block--accent"> | |
| <div className="results-block__heading"> | |
| <Layers size={15} /> | |
| Complex claim — {result.decomposition.sub_claims.length} sub-claims analyzed | |
| </div> | |
| <ul className="results-list"> | |
| {result.decomposition.sub_claims.map((sc, i) => ( | |
| <li key={i}>{sc}</li> | |
| ))} | |
| </ul> | |
| </div> | |
| ) | |
| )} | |
| {result.plain_english && ( | |
| <div className="results-block"> | |
| <div className="results-block__heading"> | |
| <FileText size={15} /> | |
| In plain English | |
| </div> | |
| <p className="results-block__text">{result.plain_english}</p> | |
| </div> | |
| )} | |
| {result.takeaway && ( | |
| <div className="results-takeaway"> | |
| <Lightbulb size={15} /> | |
| <p><strong>Takeaway.</strong> {result.takeaway}</p> | |
| </div> | |
| )} | |
| </div> | |
| <details className="results-card results-details"> | |
| <summary className="results-details__summary"> | |
| <BookOpen size={15} /> | |
| Technical explanation | |
| </summary> | |
| <p className="results-block__text">{result.explanation}</p> | |
| {result.citations?.length > 0 && ( | |
| <div className="citations"> | |
| <p className="citations__title">Citations</p> | |
| {result.citations.map((c, i) => ( | |
| <div key={i} className="citation-row"> | |
| {c.pmid && /^\d+$/.test(c.pmid) ? ( | |
| <a | |
| href={`https://pubmed.ncbi.nlm.nih.gov/${c.pmid}/`} | |
| target="_blank" | |
| rel="noopener noreferrer" | |
| className="citation-link" | |
| > | |
| {c.title} | |
| <ExternalLink size={12} /> | |
| </a> | |
| ) : ( | |
| <span className="citation-text">{c.title}</span> | |
| )} | |
| </div> | |
| ))} | |
| </div> | |
| )} | |
| </details> | |
| {result.judge && result.judge.overall_quality && result.judge.overall_quality !== "UNKNOWN" && ( | |
| <div className="results-card"> | |
| <div className="results-card__row"> | |
| <div className="results-block__heading">Evidence quality</div> | |
| <span className={`quality-badge quality-badge--${result.judge.overall_quality.toLowerCase()}`}> | |
| {result.judge.overall_quality} | |
| </span> | |
| </div> | |
| <p className="results-block__text results-block__text--muted"> | |
| {result.judge.quality_explanation} | |
| </p> | |
| <div className="papers-list"> | |
| {(result.judge.papers || []).map((jp, i) => { | |
| const paper = jp.pmid != null ? papersByPmid.get(String(jp.pmid)) : undefined | |
| const key = jp.pmid != null ? String(jp.pmid) : i | |
| return ( | |
| <div key={key} className="paper-item"> | |
| <button | |
| type="button" | |
| className="paper-item__toggle" | |
| onClick={() => onTogglePaper(key)} | |
| > | |
| <div className="paper-item__title"> | |
| <StanceDot stance={jp.stance} /> | |
| <span> | |
| {paper ? `${paper.title} (${paper.year})` : (jp.one_line_summary || `Study #${jp.paper_number || i + 1}`)} | |
| </span> | |
| </div> | |
| {expandedPapers[key] ? ( | |
| <ChevronUp size={16} className="paper-item__chevron" /> | |
| ) : ( | |
| <ChevronDown size={16} className="paper-item__chevron" /> | |
| )} | |
| </button> | |
| {expandedPapers[key] && ( | |
| <div className="paper-item__body"> | |
| <div className="paper-metrics"> | |
| <div className="paper-metric"> | |
| <span>Study type</span> | |
| <strong>{jp.study_type || paper?.study_type || "Other"}</strong> | |
| </div> | |
| <div className="paper-metric"> | |
| <span>Quality</span> | |
| <strong>{jp.quality_score}/5</strong> | |
| </div> | |
| <div className="paper-metric"> | |
| <span>Similarity</span> | |
| <strong>{paper ? paper.similarity : "—"}</strong> | |
| </div> | |
| </div> | |
| <p className="paper-item__summary">{jp.one_line_summary}</p> | |
| {paper && ( | |
| <> | |
| <p className="paper-item__journal">{paper.journal}</p> | |
| <a | |
| href={`https://pubmed.ncbi.nlm.nih.gov/${paper.pmid}/`} | |
| target="_blank" | |
| rel="noopener noreferrer" | |
| className="citation-link citation-link--sm" | |
| > | |
| View on PubMed | |
| <ExternalLink size={10} /> | |
| </a> | |
| </> | |
| )} | |
| </div> | |
| )} | |
| </div> | |
| ) | |
| })} | |
| </div> | |
| </div> | |
| )} | |
| </div> | |
| ) | |
| } | |