cleanyourtv-app
A community-built phone app for Clean Your TV: clean up an Android TV from your phone. No laptop, no coding agent, nothing uninstalled.
An analysis site for square-wave voltammograms: four biomarkers, with the reasons behind every call. ENG Peak Deconvolution, Team 2.
OtherJavaScript · HTMLGitHub @ENG-Peak-Deconvolution-Team2OnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
No updates detected yet. GitHub releases will appear here.
Owners of public repositories under a personal GitHub account can sign in to verify ownership and manage the introduction themselves. No administrator approval is needed.
Sign in, generate a verification file, and commit it to this repository’s default branch within 30 minutes. Files on other branches or forks do not count. Then check the file below to manage the project without administrator approval. Keep the file to retain your access.
If needed, you will go to sign-in. After signing in, return here and press your chosen verification button again.
Run /nomorevibe verify in your project folder to verify ownership and manage the introduction yourself.
Verify in one minuteAsk about other verification options
VoltEPIC — Explainable Prediction of Individual Concentrations: an analysis site for square-wave voltammograms (ENG Peak Deconvolution · Team 2)
Translation pending
Taken from the repository README
Loading the full README.
Read the full README ↗An analysis site that reads a square-wave voltammogram and decides, for each of four biomarkers — ascorbic acid (AA), serotonin (5-HT), estradiol (2E) and melatonin (Mela) — whether it is present, and shows why. The detection model runs entirely in the browser; nothing is uploaded anywhere, unless you ask the assistant for a chemist report (below).
Live: https://eng-peak-deconvolution-team2.github.io/voltepic/
ENG Peak Deconvolution project · Team 2 (machine learning) · work package 6, web interface.
The model behind it today is a detector: it says whether each analyte is present, not how much. Concentration estimates are the part of the name a regression model will fill in.
| Page | What it is |
|---|---|
index.html — Overview | Live readout cycling through held-out curves, key numbers, the pipeline computed on a real curve, where the model looks |
app.html — Analyzer | A sticky instrument (chart + four verdict cards) beside a live report that drives the chart as you scroll: 01 Measurement · 02 Preprocess · 03 Detect · 04 Explain. Library sheet with thumbnails, drag-and-drop upload anywhere, slide-over assistant, deep links #s=<index>, #s=random, #upload, #ask |
method.html — Method | Scroll-driven walk-through: raw scan → wavelet denoising → seven bands → 228 z-scores → 4 × 300 trees building the log-odds → threshold, recomputed for the chosen example curve |
explainability.html — Explainability | The WP5 XAI results: four methods, five tests (verdict matrix), PFI of this model against the E3 peak windows, the edge-coefficient finding recomputed from the filters, and what the analyzer shows as a result |
data.html — Dataset | Source, acquisition, the 1,239-curve cohort, the two coatings, the split, the held-out library and a gallery of all 125 curves |
model.html — Model card | Recipe, held-out results and the browser ↔ Python reference check computed live, limits, reproduction |
about.html — About | The ENG project, its work packages, Team 2 |
Everywhere: light and dark themes (follows the system, remembers a choice), a command palette
(Ctrl/⌘ K or /) over pages, actions and all 125 curves, responsive down to 390 px.
The analysis assistant answers quick questions by rules from the current analysis, and writes a chemist report with the lab's language model on request (next section).
Chosen from the ENG WP5 XAI run by what landed on the peaks in its tests:
data/kimyager.json, 20,000 coalitions); other widths come from the XAI run (xai.json).assets/js/engine/shap.js, 20 mV, 20,000 coalitions, about 4–6 s) and the blank fill R2 is offered.The assistant has two modes, switched in its header: Quick (answers composed by rules) and Lab LLM. In Lab LLM mode
Write the chemist report turns the current result into a 3–5 sentence report in plain English: what the model said,
whether its basis is chemically sound, anything suspicious, what to check in the lab. Follow-up questions are answered
(1–4 sentences) from the same evidence file, with the report as context. It is the pipeline of
literature/xai_llm_rag/kimyager_raporu/rapor.py, ported to the browser and to English; the language model only writes,
everything it may say is computed first:
assets/js/llm/kanit.js, degerlendir) — code sets one label per decision from the XAI tests
(strong, moderate, weak, suspect, sound, not shown; güçlü … gösterilemedi in rapor.py): do SHAP and occlusion
against the blank point to the same 20 mV slice, does it fall in the analyte's peak window and among the model's PFI
top 3, is it a scan edge, is the decision near the threshold, does the blank itself get the same decision. The model
never sets a label.kanitDosyasi, then assets/js/llm/evidence_en.js) — about 93 records in six branches: the
decisions with their labels and reasons, the regions both explanations point to toward and against each decision (top
3 and top 2 slices), where the model generally looks (PFI, SAGE), the expected peak windows, the peaks seen in the
curve, check suggestions and general notes. It is computed in Turkish exactly as rapor.py does, then translated rule by
rule: every text in it comes from a fixed set of templates, and a key or text without a rule stops the report instead
of reaching the model in Turkish. Library curves use data/kimyager.json (rapor.py's explanations, exported by
tools/export_kimyager.py); uploads need a blank and the coating (01 · Measurement; the coating is read from the chip
name when it is a known training chip). The file name, the raw curve and the blank curve are not sent.assets/js/llm/relay.js → worker/ → relay/server.mjs) — the browser leaves the evidence file in
VoltEPIC's mailbox, a Cloudflare Worker at the address in SERVER (relay.js), and asks for the answer every 3 s.
The mailbox checks that the request is the analyzer's (origin, evidence-file shape, short texts, a Cloudflare Turnstile
token, 4 requests a minute per IP, at most 6 waiting, one report an hour for the whole site with up to 5 follow-up
calls on it) and keeps it in a Durable Object. The report server, a Node
script on the project's lab PC, collects requests over outbound HTTPS with a secret (PC_SECRET), at most 2 at once;
it builds the message with the same check.js code and the system prompt of data/chemist_prompts.json, asks the
AI-LAB model (local-llm, OpenAI-compatible, lab network only) with reasoning_effort: xhigh, streamed, and leaves
the answer in the mailbox. Nothing connects to the PC: no port is opened and no tunnel runs. No key is in the site;
the lab key stays on the PC. While the PC is off, the mailbox tells the site the report server is offline;
relay/switch.ps1 turns it on or off. A visitor who stops asking for 60 s has left, and the lab call is stopped.
Every page carries a Content-Security-Policy: scripts only from the site and Turnstile, connections only to the site
and the mailbox. Measured on this report
(): xhigh 3.3–10.6 min a report;
on the 7 inputs where Gemini 3.8 Flash made no wrong claim, 3 of 7 Turkish outputs had one. In English
(, the same 7 inputs, read by one non-blind reader): 7/7 passed the check
on the first attempt, 1 of 7 had a wrong claim (a decision tied to one method's second slice), reports 2.5–5.5 min.node tools/evidence_en_check.mjs every Turkish evidence file at hand translates, keeps its numbers, leaves no Turkish
node tools/check_en_test.mjs each English check rule on a text written to trip it, and a clean report
node tools/kimyager_parity.mjs [--shap]
Last run of the first two (2026-10-28): 130/130 evidence files (125 library curves + the five 2026-10-21 examples)
translated with identical numbers and no Turkish left; 13/13 check cases. The third compares the Turkish evidence file,
the labels, the check and the messages with rapor.py. Its fixture
(tools/fixtures/kimyager_parity.json, written by export_kimyager.py --fixture) holds unpublished LLM outputs and is
not part of this repository. Last run (2026-10-21): evidence file identical JSON text on 125/125 library curves, basis
labels 125/125, check findings identical on 170/170 texts (the runs' real reports and altered copies), report and question
messages identical. --shap: the browser's KernelSHAP (its own sampler) against Python's on 5 curves — 4.1–4.3 s each,
max |Δ| 0.17–0.27 against a largest |φ| of 3.3–5.4, the same basis labels on 5/5. In the browser (headless Edge,
2026-10-21): library curve 12 report and one question with Gemini 3.8 Flash, both passed the check; an MC333 upload with
three blanks (a chip the model was not trained on), blank SHAP in 4–6 s, also with the page in a background tab, and its
report passed the check on the first attempt, flagging the ascorbic acid decision (wrong by the file's composition) as
weak. Measured on the report task with rapor.py: Gemini 3.8 Flash 7/7 texts passed the
check and made no wrong claim (literature/xai_llm_rag/kimyager_raporu/kosu_gemini_2026-10-21/). The earlier packet
pipeline (v0.3) is archived in literature/xai_llm_rag/prototip/site_paket_v03_2026-10-21/.
.txt
export (both working electrodes are offered when present). Curves are linearly resampled to the
model grid: 200 points, 0.004–0.800 V, 4 mV steps.The model has only seen ACS-ML-Biomarker chips (P4VP or PVDF coating, CHI760F, SWV 25 mV, 5 Hz). For curves recorded under other conditions its probabilities are not calibrated, and it cannot tell.
LightGBM, one binary classifier per analyte (learning rate 0.10, 31 leaves, 300 trees), on the full
rbio1.3 level-6 DWT of the sym4-denoised raw curve, trained with augmentation poly16_smix1_d5_x20
on 1,114 curves (seed 0 outer-training partition). Thresholds: MaxSSS (Youden) cut on the real
training rows. It is the model explained in the project's XAI work package (ENG/xai/recipe.py).
assets/js/engine/ reimplements PyWavelets (wavedec/waverec, symmetric mode) and LightGBM tree
traversal in plain JavaScript; trees, filters, scaler and thresholds come from data/model.json.
node tools/parity.mjs
compares every stage against the Python outputs in tools/fixtures/parity.json for all 125 library
curves. Last run: max |Δ features| 2.7e-15, max |Δ probability| 8.7e-19, 0 of 500 decisions differ.
The analyzer and the model card repeat the decision check on every load.
*.html one file per page; <pd-nav>/<pd-footer> come from assets/js/shell.js
assets/css/site.css design system: tokens (light/dark), type, layout, components
assets/css/pages.css home, method, explainability; page-*.css for dataset, model card, about
assets/css/analyzer.css the analyzer
assets/js/shell.js theme before first paint, nav and footer
assets/js/site.js theme toggle, scroll reveals, command palette
assets/js/data.js analyte identities, cached loaders, library records
assets/js/viz.js SVG chart kit for the editorial pages
assets/js/chart.js analyzer charts (voltammogram with crosshair, coefficients, strip, heat map)
assets/js/app/ analyzer: main.js (state, run, instrument), report.js (four sections)
assets/js/pages/ one module per page
assets/js/io.js CSV / CHI parsing and resampling
assets/js/assistant.js assistant: scripted answers + the Gemini report
assets/js/llm/ chemist report: kanit (labels, evidence file, Turkish as rapor.py), evidence_en (English evidence file),
check (English check, messages), denetim (rapor.py's Turkish check), relay (mailbox), report
worker/ Cloudflare Worker: the mailbox between the site and the lab PC (README there)
assets/js/engine/ wavelet transform, model, occlusion, KernelSHAP (shap.js)
data/model.json exported model
data/library.json held-out curves, metadata, mean blanks, Python reference scores
data/xai.json XAI run results for this model: per-curve SHAP (R2), PFI, E3 windows, test numbers
data/kimyager.json chemist report: per library curve SHAP / occlusion against the blank, the blank, model-level notes
data/chemist_prompts.json chemist report system prompts in English (report, question), used by the report server
data/kimyager_istem.json rapor.py's Turkish system prompts (report, question), for the parity test
tools/export_model.py regenerates model.json / library.json from the research workspace
tools/export_xai.py regenerates xai.json; checks that the run's rows and model are the site's
tools/parity.mjs JS ↔ Python parity test
tools/export_kimyager.py regenerates kimyager.json / kimyager_istem.json (+ --fixture: tools/fixtures/kimyager_parity.json)
tools/kimyager_parity.mjs chemist report ↔ rapor.py parity test
tools/evidence_en_check.mjs English evidence file: every Turkish file translates, same numbers, no Turkish left
tools/check_en_test.mjs English check: each rule on a text written to trip it
relay/server.mjs the report server on the lab PC: collects requests from the mailbox (relay/switch.ps1 turns it on or off)
No build step: any static server works (python -m http.server), and GitHub Pages serves main.
Fonts: Geist, Geist Mono and Instrument Serif from Google Fonts.
Curves: ML-Biomarker-Sensing — Duesselberg A. L. M., Weber I. C., Zosso Y., Salah P., Bao Z., Machine Learning-Driven Multiplexed Biomarker Detection with Polymer-Enhanced Electrochemical Sensors, ACS Electrochemistry 2 (2026) 1444–1452, doi:10.1021/acselectrochem.6c00079. Source repository github.com/esemsc-ald24/ML-Biomarker-Sensing, MIT licence.
literature/xai_llm_rag/kimyager_raporu/yerel_llm_deney_sonuclari_2026-10-22.md…/ingilizce_deney_sonuclari_2026-10-28.mdassets/js/llm/check.js) — the 8 rules of rapor.py's check (denetim.js, Turkish), written for English:
sentence count and length, technical terms, record IDs, numbers not in the evidence file, "peak is here" claims,
contradicted decisions, scan-edge regions, first person. With findings, the model gets one rewrite with them; what is
left is listed under the text. The report bubble also shows the basis labels and the full evidence file sent.