import { useState } from 'react' import Card from '../components/Card' import Button from '../components/Button' import SequenceInput from '../components/SequenceInput' import ModelPicker from '../components/ModelPicker' import ConditionMatcher from '../components/ConditionMatcher' import ResultsTable, { type Column } from '../components/ResultsTable' import { findModel } from '../data/models' import { classLabel } from '../data/screenMeta' import type { Conditions } from '../lib/rankModels' import { predictDetectability, screenBioactivityPeptides } from '../lib/api' import { SAMPLE_PEPTIDES, type DetectabilityRow } from '../data/mockData' const COLUMNS: Column[] = [ { key: 'peptide', header: 'Peptide', render: (r) => {r.peptide}, }, { key: 'length', header: 'Length', sortable: true, align: 'right' }, { key: 'score', header: 'Detectability score', sortable: true, align: 'right', render: (r) => r.score.toFixed(3), }, { key: 'prediction', header: 'Prediction', sortable: true, render: (r) => r.prediction === 'Detectable' ? ( Detectable ) : ( Not detectable ), }, { key: 'bioactivities', header: 'Known bioactivity', render: (r) => { const list = (r.bioactivities ?? '').split(';').filter(Boolean) return list.length ? ( {classLabel(list[0])} {list.length > 1 ? ` +${list.length - 1}` : ''} ) : ( n/a ) }, }, { key: 'inTraining', header: 'In training', sortable: true, render: (r) => r.inTraining === 'positive' ? ( Train⁺ ) : r.inTraining === 'negative' ? ( Train⁻ ) : ( held out ), }, { key: 'model', header: 'Model', sortable: true }, ] export default function DetectabilityPrediction() { const [input, setInput] = useState('') const [modelCode, setModelCode] = useState('H9') const [conditions, setConditions] = useState({}) const [pickMode, setPickMode] = useState<'match' | 'custom'>('match') const [rows, setRows] = useState(null) const [loading, setLoading] = useState(false) const [live, setLive] = useState(false) const canRun = input.trim().length > 0 && !loading const model = findModel(modelCode) async function run() { setLoading(true) try { // Predict detectability and screen known bioactivity in parallel, then join // by peptide so the output (and CSV) carries function alongside detectability. const [pred, bio] = await Promise.all([ predictDetectability(input, model), screenBioactivityPeptides(input), ]) const bioMap = new Map( bio.rows.map((b) => [b.peptide.toUpperCase(), b.bioactivities]), ) setRows( pred.rows.map((r) => ({ ...r, bioactivities: bioMap.get(r.peptide.toUpperCase()) ?? '', })), ) setLive(pred.live) } finally { setLoading(false) } } const detectable = rows?.filter((r) => r.prediction === 'Detectable').length ?? 0 return (

Detectability Prediction

Paste peptides and pick a model. Describe your conditions to auto-rank the best fit, or choose one yourself. Peptides seen during training are flagged, and each peptide is also screened for known bioactivity.

setInput(SAMPLE_PEPTIDES)} placeholder={'PEPTIDE\nPEPTIDE\n\nor comma-separated / FASTA'} />
{pickMode === 'match' ? ( ) : ( )}
Selected model: {model.code} · {model.species.split('(')[0].trim()} · {model.enzyme}
{!canRun && (

Add at least one peptide.

)}
0 ? ( {live ? 'Live inference' : 'Offline preview'} ) : undefined } > {loading ? (
Scoring peptides… computing features and running the model.
) : rows == null ? (
Run a prediction to see per-peptide detectability scores.
) : rows.length === 0 ? (
No peptides parsed from the input.
) : ( <>
{rows.length}
Peptides scored
{detectable}
Predicted detectable
{model.code} · {model.enzyme}
Model used ({model.species})
)}
) }