Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
459f4e5
Fix single-file CSV detail output and stabilize fibrosis filtering pi…
alexgaffen Feb 19, 2026
5e6f869
UI overhaul: dark theme, no-scroll layout, drag-drop upload zones, di…
alexgaffen Feb 19, 2026
3395209
Add chunked upload for large SVS/TIF files with progress indicator
alexgaffen Feb 19, 2026
60b427d
Implement SVS patch analysis with streaming progress UI
alexgaffen Feb 19, 2026
50e133d
Fix VGG16 input to use RGB image and update frontend text
alexgaffen Feb 19, 2026
250e5a1
Add analysis result caching and defer extent display until full analy…
alexgaffen Feb 22, 2026
7ff520b
Optimize small image analysis by skipping redundant preview call
alexgaffen Feb 22, 2026
a7707c9
Add 50MB size limit for flat images (JPG/PNG/BMP)
alexgaffen Feb 22, 2026
8f58ea3
Make upload placeholder text whiter and more visible
alexgaffen Feb 22, 2026
f679c1f
Retrain FCM model, calibrate fibrosis extent, UI improvements
alexgaffen Feb 28, 2026
dbd803a
GC/memory cleanup, remove voting code, radar chart + UI text size inc…
alexgaffen Mar 3, 2026
e59d9e6
feat: add interactive threshold adjustment, magnifier, undo system, a…
alexgaffen Mar 10, 2026
d9d4d6f
Add login system, 256x256 patches, tissue detection fix, shimmer on t…
alexgaffen Mar 24, 2026
d0062e9
Make paths and API URLs configurable for deployment
alexgaffen Mar 24, 2026
daa9686
Add static file serving, deploy config files
alexgaffen Mar 24, 2026
69c6bd3
Add liver favicon, update manifest
alexgaffen Mar 24, 2026
877a5f2
Fix chunked upload for multi-worker gunicorn, fix garbled chars
alexgaffen Mar 24, 2026
316aeeb
Fix mojibake in ImageSubmission.js, remove favicon white background
alexgaffen Mar 24, 2026
3d9a88d
Update favicon from new source with transparent background
alexgaffen Mar 24, 2026
4ed6952
Rename all UI branding to fibrosisai
alexgaffen Mar 25, 2026
81b9cc2
Remove all emojis, add SVG liver icon, network constellation bg, stat…
alexgaffen Mar 25, 2026
f61900b
Improved liver SVG icon, horizontal logo+title, simpler sign-in text,…
alexgaffen Mar 25, 2026
c3040b9
Add Diagnose workflow: classify refined B&W mask via VGG16+FCM
alexgaffen Mar 25, 2026
bb5e282
Fix CSV download, classify scan exclusion, patch alignment
alexgaffen Mar 26, 2026
1e5eab3
Fix classify patch selection: reuse exact tissue grid from analyze
alexgaffen Mar 26, 2026
934c1d9
Fix Diagnose multi-click: add settled flag + retry logic, update help…
alexgaffen Mar 26, 2026
7b3f7a2
Reduce SVS patch size to 128x128 for tighter liver exclusion
alexgaffen Mar 26, 2026
2d067a6
Revert to 256 patches, widen radar chart for Perisinusoidal, clarify …
alexgaffen Mar 26, 2026
9776f99
Disk-backed CSV metadata, remove cluster_label column, rename to exte…
alexgaffen Mar 26, 2026
6b030d5
UI polish: liver SVG in header, help btn bottom-right, user badge pil…
alexgaffen Mar 26, 2026
b801f6d
FCM shorthand in top bar, help btn top-right next to sign out
alexgaffen Mar 26, 2026
0ac0f34
Top bar: vertical bar before user badge, solid green help btn, no ove…
alexgaffen Mar 26, 2026
18d862a
fibrosis_filter: use simple method by default, fall back to adaptive …
alexgaffen Mar 31, 2026
862ed07
Always use adaptive descending-threshold; highlight dominant class in…
alexgaffen Apr 19, 2026
6b9e1d9
Magnifier Q-key area inspect; portal-rendered lens; cleaner extent an…
alexgaffen Apr 23, 2026
9d9625e
Add nginx-friendly aliases for excluded-mask and classify-area routes…
alexgaffen Apr 24, 2026
3df8e65
Add detailed logging to area inspection routes for debugging
alexgaffen Apr 24, 2026
8bf945a
Fix Q key instant cancellation: compare mouse movement in panel coord…
alexgaffen Apr 24, 2026
4925820
Share deconv cache across gunicorn workers via /tmp pickle file (fix …
alexgaffen Apr 24, 2026
85ac5a4
Update UX labels - preview only and what was excluded
alexgaffen Apr 24, 2026
f72818a
Update UI: Add 'preview only' state in purple before full render and …
alexgaffen Apr 24, 2026
b912bb3
UX overhaul: disable magnifier during diagnose, gloss-sweep over non-…
alexgaffen Apr 24, 2026
4618ee3
Apply latest frontend adjustments
alexgaffen Apr 24, 2026
69bc09b
Add session result bank and threshold controls
alexgaffen May 1, 2026
dda4baf
Add independent U-Net fibrosis workflow
alexgaffen May 13, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# AI-Fibrosis Project Instructions

## Project Structure
- **Frontend:** Located in `/NAFLD/javascript/nafld-app/`. Built with React.
- **Backend:** Located in `/NAFLD/src/py-src/`. Built with Flask.
- **AI Models:** Located in `/NAFLD/src/py-src/models/`.
9 changes: 8 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -169,4 +169,11 @@ cython_debug/
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/
#.idea/

# Project-specific ignores
Reduc/
PCAtests/
ClusterDiagnostic/
NAFLD/src/py-src/users.db
NAFLD/src/py-src/.jwt_secret
3 changes: 3 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"liveServer.settings.port": 5501
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 3 additions & 3 deletions NAFLD/javascript/nafld-app/public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<link rel="icon" href="%PUBLIC_URL%/faviconliver.png" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="Web site created using create-react-app"
/>
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
<link rel="apple-touch-icon" href="%PUBLIC_URL%/faviconliver.png" />
<!--
manifest.json provides metadata used when your web app is installed on a
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
Expand All @@ -24,7 +24,7 @@
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>FibroAi</title>
<title>fibrosisai</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
Expand Down
18 changes: 4 additions & 14 deletions NAFLD/javascript/nafld-app/public/manifest.json
Original file line number Diff line number Diff line change
@@ -1,21 +1,11 @@
{
"short_name": "React App",
"name": "Create React App Sample",
"short_name": "fibrosisai",
"name": "fibrosisai",
"icons": [
{
"src": "favicon.ico",
"src": "faviconliver.png",
"sizes": "64x64 32x32 24x24 16x16",
"type": "image/x-icon"
},
{
"src": "logo192.png",
"type": "image/png",
"sizes": "192x192"
},
{
"src": "logo512.png",
"type": "image/png",
"sizes": "512x512"
"type": "image/png"
}
],
"start_url": ".",
Expand Down
105 changes: 76 additions & 29 deletions NAFLD/javascript/nafld-app/src/App.js
Original file line number Diff line number Diff line change
@@ -1,39 +1,86 @@
import { useEffect, useState } from "react";
import { useState, useCallback } from "react";
import ImageSubmission from "./ImageSubmission";
import FileUploader from "./FileUploader";
import Login from "./Login";

function App() {
const [data, setData] = useState({})

useEffect(() => {
fetch("http://127.0.0.1:5000/home").then(
res => {
console.log(res)
return res.json()
}
)
.then(
data => {
setData(data)
console.log(data)
}
).catch(err => console.log(err))
const [user, setUser] = useState(() => sessionStorage.getItem("username"));

const handleLogin = useCallback((username) => setUser(username), []);

const handleLogout = useCallback(() => {
sessionStorage.removeItem("access_token");
sessionStorage.removeItem("refresh_token");
sessionStorage.removeItem("username");
setUser(null);
}, []);

if (!user) {
return <Login onLogin={handleLogin} />;
}

return (
<div className="App">
<header className="centered-header">
<img src="/Images/McMaster.png" alt="Logo Left" className="logo" />
<img src="/Images/ICELAB.png" alt="Logo middle" className="logo" />
<img src="/Images/Heersink.png" alt="Logo Right" className="logo" />
{/* <ImageSubmission /> */}
<div className="app-root">
{/* ── Top bar ── */}
<header className="top-bar">
<div className="top-bar-left">
<svg className="brand-liver-svg" viewBox="0 0 200 160">
<defs>
<linearGradient id="tb-lobe-left" x1="0%" y1="0%" x2="100%" y2="100%"><stop offset="0%" stopColor="#5ee8df"/><stop offset="100%" stopColor="#1a8a82"/></linearGradient>
<linearGradient id="tb-lobe-right" x1="0%" y1="0%" x2="100%" y2="100%"><stop offset="0%" stopColor="#f08c6a"/><stop offset="100%" stopColor="#c0392b"/></linearGradient>
<linearGradient id="tb-ol" x1="0%" y1="0%" x2="100%" y2="100%"><stop offset="0%" stopColor="#7af5ed"/><stop offset="100%" stopColor="#3bb8b0"/></linearGradient>
<linearGradient id="tb-or" x1="0%" y1="0%" x2="100%" y2="100%"><stop offset="0%" stopColor="#ff9e80"/><stop offset="100%" stopColor="#e05a3a"/></linearGradient>
<filter id="tb-gc" x="-40%" y="-40%" width="180%" height="180%"><feGaussianBlur stdDeviation="4" result="blur"/><feMerge><feMergeNode in="blur"/><feMergeNode in="SourceGraphic"/></feMerge></filter>
<filter id="tb-gr" x="-40%" y="-40%" width="180%" height="180%"><feGaussianBlur stdDeviation="4" result="blur"/><feMerge><feMergeNode in="blur"/><feMergeNode in="SourceGraphic"/></feMerge></filter>
<clipPath id="tb-cl"><path d="M100,18 L100,140 L0,140 L0,0 L200,0 Z"/></clipPath>
<clipPath id="tb-cr"><path d="M100,18 L100,140 L200,140 L200,0 Z"/></clipPath>
</defs>
<path id="tbLiver" d="M100,18 C82,12 55,14 35,24 C18,34 8,52 10,72 C12,88 22,104 38,116 C52,126 70,130 85,128 C92,126 96,118 100,110 C104,118 108,126 115,128 C130,130 148,122 158,112 C168,100 174,84 170,68 C166,52 154,36 138,26 C122,14 108,14 100,18Z" fill="none"/>
<g clipPath="url(#tb-cl)">
<use href="#tbLiver" fill="url(#tb-lobe-left)" opacity="0.15"/>
<use href="#tbLiver" stroke="url(#tb-ol)" strokeWidth="2" fill="none" filter="url(#tb-gc)" opacity="0.8"/>
<g stroke="#4ecdc4" strokeWidth="0.7" opacity="0.5">
<line x1="30" y1="55" x2="50" y2="40"/><line x1="50" y1="40" x2="72" y2="35"/><line x1="72" y1="35" x2="90" y2="45"/><line x1="30" y1="55" x2="45" y2="72"/><line x1="45" y1="72" x2="65" y2="60"/><line x1="65" y1="60" x2="90" y2="45"/><line x1="50" y1="40" x2="65" y2="60"/><line x1="65" y1="60" x2="85" y2="70"/><line x1="45" y1="72" x2="60" y2="88"/><line x1="60" y1="88" x2="85" y2="70"/><line x1="85" y1="70" x2="95" y2="55"/><line x1="60" y1="88" x2="75" y2="100"/><line x1="75" y1="100" x2="90" y2="90"/><line x1="85" y1="70" x2="90" y2="90"/>
</g>
<g fill="#4ecdc4">
<circle cx="30" cy="55" r="2.5" opacity="0.7"/><circle cx="50" cy="40" r="2" opacity="0.6"/><circle cx="72" cy="35" r="2.5" opacity="0.7"/><circle cx="90" cy="45" r="2" opacity="0.6"/><circle cx="45" cy="72" r="2.5" opacity="0.7"/><circle cx="65" cy="60" r="3" opacity="0.8"/><circle cx="85" cy="70" r="2" opacity="0.6"/><circle cx="60" cy="88" r="2.5" opacity="0.7"/><circle cx="75" cy="100" r="2" opacity="0.6"/><circle cx="90" cy="90" r="1.8" opacity="0.5"/>
</g>
</g>
<g clipPath="url(#tb-cr)">
<use href="#tbLiver" fill="url(#tb-lobe-right)" opacity="0.15"/>
<use href="#tbLiver" stroke="url(#tb-or)" strokeWidth="2" fill="none" filter="url(#tb-gr)" opacity="0.8"/>
<g stroke="#e8735a" strokeWidth="0.5" opacity="0.45">
<line x1="105" y1="30" x2="118" y2="28"/><line x1="118" y1="28" x2="130" y2="32"/><line x1="130" y1="32" x2="142" y2="30"/><line x1="142" y1="30" x2="155" y2="36"/><line x1="105" y1="30" x2="110" y2="42"/><line x1="110" y1="42" x2="122" y2="38"/><line x1="122" y1="38" x2="135" y2="44"/><line x1="135" y1="44" x2="148" y2="40"/><line x1="148" y1="40" x2="160" y2="48"/><line x1="115" y1="55" x2="128" y2="52"/><line x1="128" y1="52" x2="140" y2="56"/><line x1="140" y1="56" x2="155" y2="54"/><line x1="155" y1="54" x2="165" y2="60"/><line x1="108" y1="68" x2="120" y2="65"/><line x1="120" y1="65" x2="132" y2="68"/><line x1="132" y1="68" x2="145" y2="66"/><line x1="112" y1="80" x2="125" y2="78"/><line x1="125" y1="78" x2="138" y2="82"/><line x1="115" y1="92" x2="130" y2="90"/>
</g>
<g fill="#e8735a">
<circle cx="105" cy="30" r="1.5" opacity="0.6"/><circle cx="118" cy="28" r="1.2" opacity="0.5"/><circle cx="130" cy="32" r="1.5" opacity="0.6"/><circle cx="142" cy="30" r="1.2" opacity="0.5"/><circle cx="155" cy="36" r="1.5" opacity="0.6"/><circle cx="110" cy="42" r="1.2" opacity="0.5"/><circle cx="122" cy="38" r="1.5" opacity="0.6"/><circle cx="135" cy="44" r="1.8" opacity="0.7"/><circle cx="148" cy="40" r="1.2" opacity="0.5"/><circle cx="160" cy="48" r="1.5" opacity="0.6"/><circle cx="115" cy="55" r="1.5" opacity="0.6"/><circle cx="128" cy="52" r="1.8" opacity="0.7"/><circle cx="140" cy="56" r="1.5" opacity="0.6"/><circle cx="155" cy="54" r="1.2" opacity="0.5"/><circle cx="165" cy="60" r="1.2" opacity="0.5"/><circle cx="108" cy="68" r="1.5" opacity="0.6"/><circle cx="120" cy="65" r="1.8" opacity="0.7"/><circle cx="132" cy="68" r="1.5" opacity="0.6"/><circle cx="112" cy="80" r="1.5" opacity="0.6"/><circle cx="125" cy="78" r="1.8" opacity="0.7"/><circle cx="138" cy="82" r="1.5" opacity="0.6"/><circle cx="115" cy="92" r="1.2" opacity="0.5"/><circle cx="130" cy="90" r="1.5" opacity="0.6"/>
</g>
</g>
<line x1="100" y1="18" x2="100" y2="110" stroke="#fff" strokeWidth="1" opacity="0.15"/>
</svg>
<span className="brand-name">fibrosisai</span>
</div>
<span className="top-bar-subtitle">
AI-BASED UNSUPERVISED CLASSIFICATION AND QUANTIFICATION OF LIVER FIBROSIS
</span>
<span className="top-bar-pipeline">
VGG16 FEATURE EXTRACTION → FCM CLUSTERING
</span>
<div className="user-badge">
<svg className="user-icon-svg" viewBox="0 0 20 20" fill="currentColor"><path d="M10 10a4 4 0 100-8 4 4 0 000 8zm-7 8a7 7 0 0114 0H3z"/></svg>
<span className="user-badge-name">{user}</span>
<button className="logout-btn" onClick={handleLogout}>Sign Out</button>
</div>
</header>
<h1 className="centered-header">
FibroAi
</h1>
<div>
<FileUploader />
</div>

{/* ── Main content ── */}
<ImageSubmission />

{/* ── Footer logos ── */}
<footer className="logo-footer">
<img src="/Images/McMaster.png" alt="McMaster" className="footer-logo" />
<img src="/Images/ICELAB.png" alt="ICE Lab" className="footer-logo" />
<img src="/Images/Heersink.png" alt="Heersink" className="footer-logo" />
</footer>
</div>
);
}
Expand Down
2 changes: 1 addition & 1 deletion NAFLD/javascript/nafld-app/src/FileUploader.js
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ const FileUploader = () => {
<ResponsiveContainer width="100%" height={300}>
<BarChart data={[
{ name: "None", value: row.None },
{ name: "Perisinusoidal", value: row.Perisinusoidal },
{ name: "Periportal", value: row.Perisinusoidal },
{ name: "Bridging", value: row.Bridging },
{ name: "Cirrosis", value: row.Cirrosis }
]}>
Expand Down
Loading