Update app.py
Browse files
app.py
CHANGED
|
@@ -1042,713 +1042,34 @@ if model_load_error:
|
|
| 1042 |
# ---------------------------------------------------------------------------
|
| 1043 |
|
| 1044 |
CHEX_CSS = """
|
| 1045 |
-
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;600&display=swap');
|
| 1046 |
-
|
| 1047 |
*, *::before, *::after { box-sizing: border-box; }
|
| 1048 |
|
| 1049 |
:root {
|
| 1050 |
-
--
|
| 1051 |
-
--
|
| 1052 |
-
--
|
| 1053 |
-
--bg-elev-strong: #191E2B;
|
| 1054 |
-
--bg-sunken: #0E121A;
|
| 1055 |
-
--bg-input: rgba(0,0,0,0.2);
|
| 1056 |
-
--border: rgba(255,255,255,0.06);
|
| 1057 |
-
--border-strong: rgba(255,255,255,0.12);
|
| 1058 |
-
--hairline: rgba(255,255,255,0.03);
|
| 1059 |
-
--fg: #E2E8F0;
|
| 1060 |
-
--fg-muted: #94A3B8;
|
| 1061 |
-
--fg-subtle: #475569;
|
| 1062 |
-
--green: #10B981;
|
| 1063 |
-
--green-bg: rgba(16,185,129,0.10);
|
| 1064 |
-
--green-border: rgba(16,185,129,0.25);
|
| 1065 |
-
--red: #F43F5E;
|
| 1066 |
-
--red-bg: rgba(244,63,94,0.10);
|
| 1067 |
-
--red-border: rgba(244,63,94,0.25);
|
| 1068 |
-
--amber: #F59E0B;
|
| 1069 |
-
--amber-bg: rgba(245,158,11,0.10);
|
| 1070 |
-
--amber-border: rgba(245,158,11,0.25);
|
| 1071 |
-
--blur: 24px;
|
| 1072 |
-
--blur-strong: 32px;
|
| 1073 |
-
--shadow-md: 0 1px 0 rgba(255,255,255,0.03) inset,
|
| 1074 |
-
0 8px 24px rgba(0,0,0,0.4),
|
| 1075 |
-
0 1px 2px rgba(0,0,0,0.2);
|
| 1076 |
-
--radius: 10px;
|
| 1077 |
-
--radius-lg: 14px;
|
| 1078 |
-
}
|
| 1079 |
-
|
| 1080 |
-
body {
|
| 1081 |
-
background: var(--bg-grad) !important;
|
| 1082 |
-
background-attachment: fixed !important;
|
| 1083 |
-
background-color: var(--bg-base) !important;
|
| 1084 |
-
min-height: 100vh;
|
| 1085 |
-
}
|
| 1086 |
-
|
| 1087 |
-
.gradio-container {
|
| 1088 |
-
font-family: 'Inter', system-ui, -apple-system, sans-serif !important;
|
| 1089 |
-
font-size: 14px !important;
|
| 1090 |
-
line-height: 1.55 !important;
|
| 1091 |
-
color: var(--fg) !important;
|
| 1092 |
-
background: transparent !important;
|
| 1093 |
-
-webkit-font-smoothing: antialiased !important;
|
| 1094 |
-
-moz-osx-font-smoothing: grayscale !important;
|
| 1095 |
-
letter-spacing: -0.006em !important;
|
| 1096 |
-
max-width: 1480px !important;
|
| 1097 |
-
margin: 0 auto !important;
|
| 1098 |
-
padding: 0 !important;
|
| 1099 |
-
}
|
| 1100 |
-
|
| 1101 |
-
footer, .footer, .built-with, #footer,
|
| 1102 |
-
footer.svelte-1ax1toq, .svelte-1ax1toq.footer,
|
| 1103 |
-
.gradio-container > .footer,
|
| 1104 |
-
.share-button, .copy-all-button,
|
| 1105 |
-
.gradio-container > .top-panel { display: none !important; }
|
| 1106 |
-
|
| 1107 |
-
#root, .app, main {
|
| 1108 |
-
background: transparent !important;
|
| 1109 |
-
padding: 0 !important;
|
| 1110 |
-
margin: 0 !important;
|
| 1111 |
-
}
|
| 1112 |
-
|
| 1113 |
-
.contain, .container {
|
| 1114 |
-
padding: 0 !important;
|
| 1115 |
-
gap: 0 !important;
|
| 1116 |
-
max-width: 100% !important;
|
| 1117 |
-
background: transparent !important;
|
| 1118 |
-
}
|
| 1119 |
-
|
| 1120 |
-
.block, .gr-block, .gr-box, .gr-group, .gradio-container .block {
|
| 1121 |
-
background: transparent !important;
|
| 1122 |
-
border: none !important;
|
| 1123 |
-
box-shadow: none !important;
|
| 1124 |
-
padding: 0 !important;
|
| 1125 |
-
border-radius: 0 !important;
|
| 1126 |
-
}
|
| 1127 |
-
|
| 1128 |
-
.gap, .gr-row { gap: 20px !important; }
|
| 1129 |
-
|
| 1130 |
-
.panel, .gr-panel, .gr-padded {
|
| 1131 |
-
background: transparent !important;
|
| 1132 |
-
border: none !important;
|
| 1133 |
-
padding: 0 !important;
|
| 1134 |
-
box-shadow: none !important;
|
| 1135 |
-
}
|
| 1136 |
-
|
| 1137 |
-
.tabs, .gr-tabs { background: transparent !important; border: none !important; }
|
| 1138 |
-
|
| 1139 |
-
.tabitem, .gr-tabitem {
|
| 1140 |
-
background: transparent !important;
|
| 1141 |
-
border: none !important;
|
| 1142 |
-
padding: 24px !important;
|
| 1143 |
-
}
|
| 1144 |
-
|
| 1145 |
-
[data-testid="textbox"], .gr-textbox {
|
| 1146 |
-
background: transparent !important;
|
| 1147 |
-
border: none !important;
|
| 1148 |
-
box-shadow: none !important;
|
| 1149 |
-
padding: 0 !important;
|
| 1150 |
-
}
|
| 1151 |
-
|
| 1152 |
-
label.block, .label-wrap {
|
| 1153 |
-
background: transparent !important;
|
| 1154 |
-
border: none !important;
|
| 1155 |
-
padding: 0 !important;
|
| 1156 |
-
gap: 6px !important;
|
| 1157 |
-
display: flex !important;
|
| 1158 |
-
flex-direction: column !important;
|
| 1159 |
-
}
|
| 1160 |
-
|
| 1161 |
-
.row, .gr-row { background: transparent !important; border: none !important; padding: 0 !important; }
|
| 1162 |
-
|
| 1163 |
-
.form, .gr-form {
|
| 1164 |
-
background: transparent !important;
|
| 1165 |
-
border: none !important;
|
| 1166 |
-
box-shadow: none !important;
|
| 1167 |
-
padding: 0 !important;
|
| 1168 |
-
gap: 14px !important;
|
| 1169 |
-
}
|
| 1170 |
-
|
| 1171 |
-
/* ββ Topbar βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ */
|
| 1172 |
-
.chex-topbar {
|
| 1173 |
-
display: flex;
|
| 1174 |
-
align-items: center;
|
| 1175 |
-
gap: 16px;
|
| 1176 |
-
padding: 0 28px;
|
| 1177 |
-
height: 52px;
|
| 1178 |
-
position: sticky;
|
| 1179 |
-
top: 0;
|
| 1180 |
-
z-index: 100;
|
| 1181 |
-
background: rgba(11, 14, 20, 0.85);
|
| 1182 |
-
backdrop-filter: blur(var(--blur-strong)) saturate(160%);
|
| 1183 |
-
-webkit-backdrop-filter: blur(var(--blur-strong)) saturate(160%);
|
| 1184 |
-
border-bottom: 1px solid var(--hairline);
|
| 1185 |
-
}
|
| 1186 |
-
|
| 1187 |
-
.chex-logo {
|
| 1188 |
-
width: 22px; height: 22px; border-radius: 5px;
|
| 1189 |
-
background: #E2E8F0;
|
| 1190 |
-
color: #0B0E14; display: grid; place-items: center;
|
| 1191 |
-
font-family: 'JetBrains Mono', monospace; font-weight: 700; font-size: 10px;
|
| 1192 |
-
letter-spacing: -0.05em;
|
| 1193 |
-
box-shadow: 0 2px 10px rgba(0,0,0,0.5);
|
| 1194 |
-
flex-shrink: 0;
|
| 1195 |
-
}
|
| 1196 |
-
|
| 1197 |
-
.chex-name { font-size: 14px; font-weight: 600; letter-spacing: -0.01em; color: var(--fg); font-family: 'Inter', sans-serif; }
|
| 1198 |
-
.chex-tag { font-size: 12px; color: var(--fg-muted); font-weight: 400; padding-left: 12px; border-left: 1px solid rgba(255,255,255,0.08); font-family: 'Inter', sans-serif; }
|
| 1199 |
-
|
| 1200 |
-
.chex-pill {
|
| 1201 |
-
display: inline-flex; align-items: center; gap: 7px;
|
| 1202 |
-
padding: 4px 11px 4px 9px; border: 1px solid var(--border); border-radius: 999px;
|
| 1203 |
-
font-size: 11.5px; color: var(--fg-muted); background: var(--bg-elev);
|
| 1204 |
-
backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px);
|
| 1205 |
-
font-family: 'JetBrains Mono', monospace; white-space: nowrap;
|
| 1206 |
-
}
|
| 1207 |
-
|
| 1208 |
-
.chex-dot {
|
| 1209 |
-
width: 6px; height: 6px; border-radius: 50%; background: var(--green);
|
| 1210 |
-
box-shadow: 0 0 0 3px rgba(16,185,129,0.22); display: inline-block; flex-shrink: 0;
|
| 1211 |
-
}
|
| 1212 |
-
|
| 1213 |
-
/* ββ Warning banner βββββββββββββββββββββββββββββββββββββββββββββββββββββββ */
|
| 1214 |
-
.chex-banner {
|
| 1215 |
-
display: flex; align-items: center; gap: 12px; padding: 11px 20px;
|
| 1216 |
-
border-bottom: 1px solid var(--amber-border); background: var(--amber-bg);
|
| 1217 |
-
backdrop-filter: blur(var(--blur)) saturate(160%); -webkit-backdrop-filter: blur(var(--blur)) saturate(160%);
|
| 1218 |
-
color: var(--amber); font-size: 13px; font-family: 'Inter', sans-serif; font-weight: 500;
|
| 1219 |
-
}
|
| 1220 |
-
.chex-banner-icon { font-size: 14px; flex-shrink: 0; }
|
| 1221 |
-
.chex-banner-body { color: var(--fg); font-weight: 400; line-height: 1.5; }
|
| 1222 |
-
.chex-banner-body strong { color: var(--fg); font-weight: 600; }
|
| 1223 |
-
.chex-banner code { font-family: 'JetBrains Mono', monospace; font-size: 12px; background: rgba(0,0,0,0.06); padding: 1px 5px; border-radius: 4px; }
|
| 1224 |
-
|
| 1225 |
-
/* ββ Tab nav ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ */
|
| 1226 |
-
.tab-nav {
|
| 1227 |
-
background: rgba(11,14,20,0.85) !important;
|
| 1228 |
-
backdrop-filter: blur(var(--blur)) saturate(160%) !important;
|
| 1229 |
-
-webkit-backdrop-filter: blur(var(--blur)) saturate(160%) !important;
|
| 1230 |
-
border-bottom: 1px solid var(--hairline) !important;
|
| 1231 |
-
border-top: none !important; padding: 0 20px !important; gap: 0 !important;
|
| 1232 |
-
position: sticky !important; top: 52px !important; z-index: 99 !important; overflow: visible !important;
|
| 1233 |
-
}
|
| 1234 |
-
|
| 1235 |
-
.tab-nav button {
|
| 1236 |
-
background: transparent !important; border: none !important; border-radius: 0 !important;
|
| 1237 |
-
padding: 13px 16px !important; color: var(--fg-muted) !important;
|
| 1238 |
-
font-size: 13px !important; font-weight: 500 !important; font-family: 'Inter', sans-serif !important;
|
| 1239 |
-
letter-spacing: -0.003em !important; position: relative !important; white-space: nowrap !important;
|
| 1240 |
-
transition: color 0.15s ease !important; cursor: pointer !important; box-shadow: none !important; outline: none !important;
|
| 1241 |
-
}
|
| 1242 |
-
|
| 1243 |
-
.tab-nav button:hover { color: var(--fg) !important; background: transparent !important; }
|
| 1244 |
-
|
| 1245 |
-
.tab-nav button.selected, .tab-nav button[aria-selected="true"] {
|
| 1246 |
-
color: var(--fg) !important; background: transparent !important; font-weight: 500 !important; box-shadow: none !important;
|
| 1247 |
-
}
|
| 1248 |
-
|
| 1249 |
-
.tab-nav button.selected::after, .tab-nav button[aria-selected="true"]::after {
|
| 1250 |
-
content: ""; position: absolute; left: 12px; right: 12px; bottom: -1px;
|
| 1251 |
-
height: 1.5px; background: var(--fg); border-radius: 2px 2px 0 0;
|
| 1252 |
-
}
|
| 1253 |
-
|
| 1254 |
-
.tabitem { border: none !important; background: transparent !important; padding: 20px 20px !important; }
|
| 1255 |
-
|
| 1256 |
-
/* ββ Cards (gr-group) βββββββββββββββββββββββββββββββββββββββββββββββββββββ */
|
| 1257 |
-
.gradio-container .gr-group {
|
| 1258 |
-
background: var(--bg-elev) !important;
|
| 1259 |
-
backdrop-filter: blur(var(--blur)) saturate(180%) !important;
|
| 1260 |
-
-webkit-backdrop-filter: blur(var(--blur)) saturate(180%) !important;
|
| 1261 |
-
border: 1px solid var(--border) !important;
|
| 1262 |
-
border-radius: var(--radius-lg) !important;
|
| 1263 |
-
box-shadow: var(--shadow-md) !important;
|
| 1264 |
-
overflow: hidden !important; padding: 0 !important;
|
| 1265 |
-
}
|
| 1266 |
-
|
| 1267 |
-
.gradio-container .gr-group > *:not(.chex-card-header):not(.chex-load-bar) {
|
| 1268 |
-
padding-left: 20px !important; padding-right: 20px !important;
|
| 1269 |
-
}
|
| 1270 |
-
.gradio-container .gr-group > *:last-child { padding-bottom: 18px !important; }
|
| 1271 |
-
|
| 1272 |
-
/* ββ Card header (new design) βββββββββββββββββββββββββββββββββββββββββββββ */
|
| 1273 |
-
.chex-card-header {
|
| 1274 |
-
padding: 14px 20px; display: flex; align-items: center;
|
| 1275 |
-
gap: 10px; border-bottom: 1px solid var(--hairline);
|
| 1276 |
-
}
|
| 1277 |
-
|
| 1278 |
-
.chex-card-icon {
|
| 1279 |
-
opacity: 0.45; flex-shrink: 0; display: flex; align-items: center;
|
| 1280 |
-
}
|
| 1281 |
-
|
| 1282 |
-
.chex-card-title {
|
| 1283 |
-
font-size: 13px; font-weight: 600; letter-spacing: -0.01em;
|
| 1284 |
-
color: var(--fg); white-space: nowrap; font-family: 'Inter', sans-serif;
|
| 1285 |
-
display: inline-flex; align-items: center; gap: 0;
|
| 1286 |
-
}
|
| 1287 |
-
|
| 1288 |
-
.chex-card-sep {
|
| 1289 |
-
font-size: 13px; color: var(--fg-subtle); font-weight: 400;
|
| 1290 |
-
padding: 0 6px; font-family: 'Inter', sans-serif;
|
| 1291 |
-
}
|
| 1292 |
-
|
| 1293 |
-
.chex-card-sub {
|
| 1294 |
-
font-size: 12px; color: var(--fg-subtle); font-weight: 400;
|
| 1295 |
-
font-family: 'Inter', sans-serif; letter-spacing: 0;
|
| 1296 |
-
}
|
| 1297 |
-
|
| 1298 |
-
/* ββ Load bar (LOAD chip + sample buttons row) βββββββββββββββββββββββββββ */
|
| 1299 |
-
.chex-load-bar {
|
| 1300 |
-
display: flex; align-items: center; gap: 10px; padding: 10px 16px;
|
| 1301 |
-
border-bottom: 1px solid var(--hairline); background: var(--bg-sunken); flex-wrap: wrap;
|
| 1302 |
-
}
|
| 1303 |
-
|
| 1304 |
-
.chex-load-chip {
|
| 1305 |
-
font-family: 'JetBrains Mono', monospace; font-size: 10px;
|
| 1306 |
-
text-transform: uppercase; letter-spacing: 0.1em;
|
| 1307 |
-
color: var(--fg-subtle); background: var(--bg-elev-strong);
|
| 1308 |
-
border: 1px solid var(--border); border-radius: 4px;
|
| 1309 |
-
padding: 3px 7px; white-space: nowrap; flex-shrink: 0;
|
| 1310 |
-
}
|
| 1311 |
-
|
| 1312 |
-
/* Question label chip */
|
| 1313 |
-
.chex-question-label {
|
| 1314 |
-
font-family: 'JetBrains Mono', monospace; font-size: 10px;
|
| 1315 |
-
text-transform: uppercase; letter-spacing: 0.1em;
|
| 1316 |
-
color: var(--fg-subtle); padding: 14px 20px 6px; display: block;
|
| 1317 |
-
}
|
| 1318 |
-
|
| 1319 |
-
/* ββ Suggested hint βββββββββββββββββββββββββββββββββββββββββββββββββββββββ */
|
| 1320 |
-
.chex-suggested {
|
| 1321 |
-
display: flex; align-items: center; gap: 10px; padding: 10px 14px;
|
| 1322 |
-
background: rgba(13,18,32,0.04); border: 1px solid var(--border); border-radius: var(--radius);
|
| 1323 |
-
font-size: 12.5px; color: var(--fg-muted); font-family: 'Inter', sans-serif; line-height: 1.4; margin-top: 2px;
|
| 1324 |
-
}
|
| 1325 |
-
.chex-suggested-icon { font-size: 13px; flex-shrink: 0; opacity: 0.7; }
|
| 1326 |
-
|
| 1327 |
-
/* ββ Labels βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ */
|
| 1328 |
-
label > span:first-child, .label-wrap span,
|
| 1329 |
-
.gradio-container label span.text-gray-500, span.svelte-1b6s6s {
|
| 1330 |
-
font-family: 'JetBrains Mono', monospace !important; font-size: 10px !important;
|
| 1331 |
-
font-weight: 500 !important; text-transform: uppercase !important; letter-spacing: 0.08em !important;
|
| 1332 |
-
color: var(--fg-subtle) !important; margin-bottom: 6px !important; display: block !important;
|
| 1333 |
-
}
|
| 1334 |
-
|
| 1335 |
-
/* ββ Text inputs ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ */
|
| 1336 |
-
textarea, input[type="text"], input[type="search"],
|
| 1337 |
-
.gradio-container .gr-input, .gradio-container .gr-textarea,
|
| 1338 |
-
.gradio-container [data-testid="textbox"] textarea,
|
| 1339 |
-
.gradio-container [data-testid="textbox"] input {
|
| 1340 |
-
background: var(--bg-input) !important; backdrop-filter: blur(10px) !important;
|
| 1341 |
-
-webkit-backdrop-filter: blur(10px) !important; border: 1px solid var(--border) !important;
|
| 1342 |
-
border-radius: var(--radius) !important; color: var(--fg) !important;
|
| 1343 |
-
font-family: 'Inter', sans-serif !important; font-size: 13px !important;
|
| 1344 |
-
line-height: 1.6 !important; padding: 11px 14px !important;
|
| 1345 |
-
transition: border-color 0.18s ease, box-shadow 0.18s ease, background 0.18s ease !important;
|
| 1346 |
-
resize: vertical !important;
|
| 1347 |
-
}
|
| 1348 |
-
|
| 1349 |
-
textarea:focus, input[type="text"]:focus,
|
| 1350 |
-
.gradio-container [data-testid="textbox"] textarea:focus,
|
| 1351 |
-
.gradio-container [data-testid="textbox"] input:focus {
|
| 1352 |
-
border-color: var(--border-strong) !important; background: var(--bg-elev) !important;
|
| 1353 |
-
box-shadow: 0 0 0 2px rgba(255,255,255,0.05) !important; outline: none !important;
|
| 1354 |
-
}
|
| 1355 |
-
|
| 1356 |
-
textarea::placeholder, input::placeholder { color: var(--fg-subtle) !important; }
|
| 1357 |
-
|
| 1358 |
-
textarea[readonly],
|
| 1359 |
-
.gradio-container [data-testid="textbox"][data-interactive="false"] textarea {
|
| 1360 |
-
background: var(--bg-sunken) !important; border: 1px solid var(--hairline) !important;
|
| 1361 |
-
color: var(--fg) !important; cursor: default !important;
|
| 1362 |
-
}
|
| 1363 |
-
|
| 1364 |
-
/* ββ Buttons ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ */
|
| 1365 |
-
.gradio-container button {
|
| 1366 |
-
font-family: 'Inter', sans-serif !important; font-size: 13px !important;
|
| 1367 |
-
font-weight: 500 !important; border-radius: var(--radius) !important;
|
| 1368 |
-
padding: 9px 16px !important;
|
| 1369 |
-
transition: opacity 0.15s ease, background 0.15s ease, box-shadow 0.15s ease !important;
|
| 1370 |
-
cursor: pointer !important; letter-spacing: -0.003em !important;
|
| 1371 |
-
}
|
| 1372 |
-
|
| 1373 |
-
.gradio-container button.primary, button.primary {
|
| 1374 |
-
background: var(--fg) !important; color: var(--bg-base) !important; border: 1px solid var(--fg) !important;
|
| 1375 |
-
box-shadow: 0 4px 14px rgba(0,0,0,0.35), 0 1px 0 rgba(255,255,255,0.08) inset !important;
|
| 1376 |
-
}
|
| 1377 |
-
.gradio-container button.primary:hover, button.primary:hover { opacity: 0.9 !important; box-shadow: 0 4px 12px rgba(0,0,0,0.3) !important; }
|
| 1378 |
-
|
| 1379 |
-
.gradio-container button.secondary, button.secondary {
|
| 1380 |
-
background: transparent !important; color: var(--fg-muted) !important;
|
| 1381 |
-
border: 1px solid var(--border-strong) !important; box-shadow: none !important;
|
| 1382 |
-
}
|
| 1383 |
-
.gradio-container button.secondary:hover, button.secondary:hover { background: var(--bg-elev) !important; color: var(--fg) !important; border-color: var(--border-strong) !important; }
|
| 1384 |
-
|
| 1385 |
-
button.sm, .gradio-container button[size="sm"], button.small { font-size: 12px !important; padding: 6px 12px !important; }
|
| 1386 |
-
|
| 1387 |
-
/* ββ File upload ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ */
|
| 1388 |
-
.gradio-container .upload-container, .gradio-container [data-testid="file"] {
|
| 1389 |
-
background: var(--bg-input) !important; border: 1px dashed var(--border-strong) !important; border-radius: var(--radius) !important;
|
| 1390 |
-
}
|
| 1391 |
-
|
| 1392 |
-
/* ββ Dataframe / table ββββββββββββββββββββββββββββββββββββββββββββββββββββ */
|
| 1393 |
-
.gradio-container .wrap.svelte-a4gbbr, .gradio-container .table-wrap,
|
| 1394 |
-
.gradio-container [data-testid="dataframe"] {
|
| 1395 |
-
background: var(--bg-elev) !important;
|
| 1396 |
-
backdrop-filter: blur(var(--blur)) saturate(180%) !important;
|
| 1397 |
-
-webkit-backdrop-filter: blur(var(--blur)) saturate(180%) !important;
|
| 1398 |
-
border: 1px solid var(--border) !important; border-radius: var(--radius-lg) !important;
|
| 1399 |
-
box-shadow: var(--shadow-md) !important; overflow: hidden !important;
|
| 1400 |
}
|
| 1401 |
|
| 1402 |
-
|
| 1403 |
-
|
| 1404 |
-
|
| 1405 |
-
|
| 1406 |
-
box-shadow: none !important; border-radius: 0 !important;
|
| 1407 |
-
}
|
| 1408 |
-
|
| 1409 |
-
.gradio-container th {
|
| 1410 |
-
background: var(--bg-sunken) !important; border-bottom: 1px solid var(--hairline) !important;
|
| 1411 |
-
border-top: none !important; padding: 14px 18px !important;
|
| 1412 |
-
font-family: 'JetBrains Mono', monospace !important; font-size: 10px !important;
|
| 1413 |
-
text-transform: uppercase !important; letter-spacing: 0.08em !important;
|
| 1414 |
-
color: var(--fg-muted) !important; font-weight: 500 !important; text-align: left !important;
|
| 1415 |
-
}
|
| 1416 |
-
|
| 1417 |
-
.gradio-container td {
|
| 1418 |
-
padding: 16px 18px !important; border-top: 1px solid var(--hairline) !important;
|
| 1419 |
-
border-bottom: none !important; vertical-align: top !important; line-height: 1.6 !important;
|
| 1420 |
-
color: var(--fg) !important; background: transparent !important;
|
| 1421 |
-
}
|
| 1422 |
-
|
| 1423 |
-
.gradio-container tr:first-child td { border-top: none !important; }
|
| 1424 |
-
|
| 1425 |
-
/* ββ Markdown prose βββββββββββββββββββββββββββββββββββββββββββββββββββββββ */
|
| 1426 |
-
.gradio-container .prose, .gradio-container .md, .gradio-container [data-testid="markdown"] {
|
| 1427 |
-
color: var(--fg) !important; font-family: 'Inter', sans-serif !important;
|
| 1428 |
-
font-size: 13px !important; line-height: 1.65 !important;
|
| 1429 |
-
}
|
| 1430 |
-
|
| 1431 |
-
.gradio-container .prose h2, .gradio-container .md h2 {
|
| 1432 |
-
font-size: 18px !important; font-weight: 600 !important; letter-spacing: -0.02em !important;
|
| 1433 |
-
color: var(--fg) !important; margin-bottom: 10px !important; margin-top: 0 !important;
|
| 1434 |
-
}
|
| 1435 |
-
|
| 1436 |
-
.gradio-container .prose p, .gradio-container .md p {
|
| 1437 |
-
color: var(--fg-muted) !important; font-size: 13px !important; line-height: 1.65 !important; margin-bottom: 8px !important;
|
| 1438 |
-
}
|
| 1439 |
-
|
| 1440 |
-
.gradio-container .prose strong, .gradio-container .md strong { color: var(--fg) !important; font-weight: 600 !important; }
|
| 1441 |
-
|
| 1442 |
-
.gradio-container .prose code, .gradio-container .md code {
|
| 1443 |
-
font-family: 'JetBrains Mono', monospace !important; font-size: 12px !important;
|
| 1444 |
-
background: rgba(13,18,32,0.06) !important; padding: 1px 5px !important;
|
| 1445 |
-
border-radius: 4px !important; color: var(--fg) !important;
|
| 1446 |
-
}
|
| 1447 |
-
|
| 1448 |
-
/* ββ Benchmark intro card βββββββββββββββββββββββββββββββββββββββββββββββββ */
|
| 1449 |
-
.chex-bench-wrap {
|
| 1450 |
-
background: var(--bg-elev);
|
| 1451 |
-
backdrop-filter: blur(var(--blur)) saturate(180%);
|
| 1452 |
-
-webkit-backdrop-filter: blur(var(--blur)) saturate(180%);
|
| 1453 |
-
border: 1px solid var(--border); border-radius: var(--radius-lg);
|
| 1454 |
-
box-shadow: var(--shadow-md); margin-bottom: 20px; overflow: hidden;
|
| 1455 |
-
}
|
| 1456 |
-
|
| 1457 |
-
.chex-bench-top {
|
| 1458 |
-
padding: 24px 28px 20px; display: flex; align-items: flex-start; gap: 28px;
|
| 1459 |
-
}
|
| 1460 |
-
|
| 1461 |
-
.chex-bench-copy { flex: 1; min-width: 0; }
|
| 1462 |
-
.chex-bench-copy h2 { margin: 0 0 8px; font-size: 18px; font-weight: 600; letter-spacing: -0.02em; color: var(--fg); font-family: 'Inter', sans-serif; }
|
| 1463 |
-
.chex-bench-copy p { margin: 0; color: var(--fg-muted); font-size: 13px; line-height: 1.65; font-family: 'Inter', sans-serif; }
|
| 1464 |
-
|
| 1465 |
-
.chex-bench-stats {
|
| 1466 |
-
display: flex; gap: 0; flex-shrink: 0;
|
| 1467 |
-
border: 1px solid var(--border); border-radius: var(--radius); overflow: hidden;
|
| 1468 |
-
}
|
| 1469 |
-
.chex-bench-stat {
|
| 1470 |
-
padding: 14px 20px; display: flex; flex-direction: column; gap: 3px;
|
| 1471 |
-
border-right: 1px solid var(--border);
|
| 1472 |
-
}
|
| 1473 |
-
.chex-bench-stat:last-child { border-right: none; }
|
| 1474 |
-
.chex-bench-stat .v { font-family: 'Inter', sans-serif; font-size: 22px; font-weight: 600; letter-spacing: -0.03em; line-height: 1.1; }
|
| 1475 |
-
.chex-bench-stat .v.red { color: var(--red); }
|
| 1476 |
-
.chex-bench-stat .v.green { color: var(--green); }
|
| 1477 |
-
.chex-bench-stat .v.white { color: var(--fg); }
|
| 1478 |
-
.chex-bench-stat .k { font-size: 10px; text-transform: uppercase; letter-spacing: 0.08em; color: var(--fg-subtle); font-family: 'JetBrains Mono', monospace; }
|
| 1479 |
-
|
| 1480 |
-
/* ββ Benchmark HTML table ββββββββββββββββββββββββββοΏ½οΏ½οΏ½ββββββββββββββββββββββ */
|
| 1481 |
-
.chex-bench-table-wrap {
|
| 1482 |
-
background: var(--bg-elev);
|
| 1483 |
-
backdrop-filter: blur(var(--blur)) saturate(180%);
|
| 1484 |
-
-webkit-backdrop-filter: blur(var(--blur)) saturate(180%);
|
| 1485 |
-
border: 1px solid var(--border); border-radius: var(--radius-lg);
|
| 1486 |
-
box-shadow: var(--shadow-md); overflow: hidden;
|
| 1487 |
-
}
|
| 1488 |
-
|
| 1489 |
-
.chex-bench-table {
|
| 1490 |
-
width: 100%; border-collapse: separate; border-spacing: 0;
|
| 1491 |
-
font-family: 'Inter', sans-serif; font-size: 13px;
|
| 1492 |
-
}
|
| 1493 |
-
|
| 1494 |
-
.chex-bench-table th {
|
| 1495 |
-
background: var(--bg-sunken) !important; border-bottom: 1px solid var(--hairline) !important;
|
| 1496 |
-
padding: 13px 18px !important; font-family: 'JetBrains Mono', monospace !important;
|
| 1497 |
-
font-size: 10px !important; text-transform: uppercase !important; letter-spacing: 0.08em !important;
|
| 1498 |
-
color: var(--fg-muted) !important; font-weight: 500 !important; text-align: left !important;
|
| 1499 |
-
white-space: nowrap;
|
| 1500 |
-
}
|
| 1501 |
-
|
| 1502 |
-
.chex-bench-table td {
|
| 1503 |
-
padding: 16px 18px; border-top: 1px solid var(--hairline);
|
| 1504 |
-
vertical-align: top; line-height: 1.55; color: var(--fg);
|
| 1505 |
-
}
|
| 1506 |
-
|
| 1507 |
-
.chex-bench-table tr:first-child td { border-top: none; }
|
| 1508 |
-
|
| 1509 |
-
.chex-bench-table .col-question { color: var(--fg); font-weight: 400; }
|
| 1510 |
-
.chex-bench-table .col-truth { color: var(--fg-muted); font-style: italic; }
|
| 1511 |
-
.chex-bench-table .col-base { color: #F87171; }
|
| 1512 |
-
.chex-bench-table .col-halluc { text-align: center; }
|
| 1513 |
-
|
| 1514 |
-
/* Inline label badges for the benchmark table */
|
| 1515 |
-
.cbadge {
|
| 1516 |
-
display: inline-flex; align-items: center; gap: 6px;
|
| 1517 |
-
padding: 5px 10px; border-radius: 8px; font-size: 11px;
|
| 1518 |
-
font-weight: 600; letter-spacing: 0.02em; font-family: 'Inter', sans-serif;
|
| 1519 |
-
white-space: nowrap;
|
| 1520 |
-
}
|
| 1521 |
-
.cbadge-green { background: rgba(16,185,129,0.12); color: #10B981; border: 1px solid rgba(16,185,129,0.28); }
|
| 1522 |
-
.cbadge-red { background: rgba(244,63,94,0.10); color: #F43F5E; border: 1px solid rgba(244,63,94,0.28); }
|
| 1523 |
-
.cbadge-amber { background: rgba(245,158,11,0.12); color: #F59E0B; border: 1px solid rgba(245,158,11,0.30); }
|
| 1524 |
-
.cbadge-icon { font-size: 12px; }
|
| 1525 |
-
|
| 1526 |
-
.chex-halluc-yes { color: var(--red); font-size: 15px; }
|
| 1527 |
-
.chex-halluc-no { color: var(--green); font-size: 15px; }
|
| 1528 |
-
|
| 1529 |
-
/* ββ Footer βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ */
|
| 1530 |
-
.chex-footer {
|
| 1531 |
-
border-top: 1px solid var(--hairline); padding: 13px 28px;
|
| 1532 |
-
display: flex; align-items: center; gap: 18px; color: var(--fg-subtle);
|
| 1533 |
-
font-size: 11px; font-family: 'JetBrains Mono', monospace;
|
| 1534 |
-
background: var(--bg-elev); backdrop-filter: blur(var(--blur));
|
| 1535 |
-
-webkit-backdrop-filter: blur(var(--blur)); margin-top: 24px;
|
| 1536 |
-
justify-content: space-between;
|
| 1537 |
-
}
|
| 1538 |
-
.chex-footer-left { display: flex; align-items: center; gap: 18px; }
|
| 1539 |
-
.chex-footer .sep { opacity: 0.35; }
|
| 1540 |
-
.chex-footer-right { font-size: 11px; color: var(--fg-subtle); opacity: 0.6; }
|
| 1541 |
-
|
| 1542 |
-
/* ββ Misc helpers βββββββββββββββββββββββββββββββββββββββββββββββββββββββββ */
|
| 1543 |
-
.chex-label-wrap { padding: 4px 0 8px; }
|
| 1544 |
-
.chex-divider { height: 1px; background: var(--hairline); margin: 18px 0; }
|
| 1545 |
-
.chex-section-kicker { font-family: 'JetBrains Mono', monospace; font-size: 10px; text-transform: uppercase; letter-spacing: 0.08em; color: var(--fg-subtle); margin-bottom: 10px; display: block; }
|
| 1546 |
-
.chex-card-body { padding: 18px 20px; display: flex; flex-direction: column; gap: 14px; }
|
| 1547 |
-
|
| 1548 |
-
/* ββ Empty state ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ */
|
| 1549 |
-
.chex-empty {
|
| 1550 |
-
display: flex; flex-direction: column; align-items: center; justify-content: center;
|
| 1551 |
-
gap: 10px; padding: 48px 24px; color: var(--fg-subtle); text-align: center;
|
| 1552 |
-
}
|
| 1553 |
-
.chex-empty-icon { font-size: 20px; opacity: 0.4; }
|
| 1554 |
-
.chex-empty-title { font-size: 13.5px; font-weight: 500; color: var(--fg-muted); font-family: 'Inter', sans-serif; }
|
| 1555 |
-
.chex-empty-body { font-size: 12.5px; color: var(--fg-subtle); line-height: 1.6; font-family: 'Inter', sans-serif; max-width: 280px; }
|
| 1556 |
-
|
| 1557 |
-
*::-webkit-scrollbar { width: 8px; height: 8px; }
|
| 1558 |
-
*::-webkit-scrollbar-thumb { background: var(--border-strong); border-radius: 999px; border: 2px solid transparent; background-clip: padding-box; }
|
| 1559 |
-
*::-webkit-scrollbar-track { background: transparent; }
|
| 1560 |
-
|
| 1561 |
-
.gradio-container .gap-4 { gap: 14px !important; }
|
| 1562 |
-
.gradio-container .gap-2 { gap: 8px !important; }
|
| 1563 |
-
|
| 1564 |
-
.tabitem .tab-nav { position: static !important; top: auto !important; }
|
| 1565 |
-
|
| 1566 |
-
@media (max-width: 900px) {
|
| 1567 |
-
.chex-topbar { padding: 0 16px; }
|
| 1568 |
-
.chex-tag { display: none; }
|
| 1569 |
-
.tabitem { padding: 16px !important; }
|
| 1570 |
-
.chex-bench-top { flex-direction: column; gap: 16px; }
|
| 1571 |
-
.chex-bench-stats { flex-direction: row; }
|
| 1572 |
-
.chex-footer { padding: 12px 16px; gap: 12px; flex-wrap: wrap; }
|
| 1573 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1574 |
"""
|
| 1575 |
|
| 1576 |
# ---------------------------------------------------------------------------
|
| 1577 |
# Static HTML
|
| 1578 |
# ---------------------------------------------------------------------------
|
| 1579 |
|
| 1580 |
-
|
| 1581 |
-
<div
|
| 1582 |
-
|
| 1583 |
-
|
| 1584 |
-
|
| 1585 |
-
<div style="flex:1"></div>
|
| 1586 |
-
<div class="chex-pill"><span class="chex-dot"></span>MI300X · ready</div>
|
| 1587 |
-
</div>
|
| 1588 |
-
"""
|
| 1589 |
-
|
| 1590 |
-
FOOTER_HTML = """
|
| 1591 |
-
<div class="chex-footer">
|
| 1592 |
-
<div class="chex-footer-left">
|
| 1593 |
-
<span>chex/v0.4.1</span>
|
| 1594 |
-
<span class="sep">·</span>
|
| 1595 |
-
<span>endpoint: mi300x-east-2</span>
|
| 1596 |
-
<span class="sep">·</span>
|
| 1597 |
-
<span>tokens/s 142.7</span>
|
| 1598 |
-
</div>
|
| 1599 |
-
<div class="chex-footer-right">↩ to analyse ⌘K shortcuts</div>
|
| 1600 |
-
</div>
|
| 1601 |
-
"""
|
| 1602 |
-
|
| 1603 |
-
BENCH_INTRO_HTML = """
|
| 1604 |
-
<div class="chex-bench-wrap">
|
| 1605 |
-
<div class="chex-bench-top">
|
| 1606 |
-
<div class="chex-bench-copy">
|
| 1607 |
-
<h2>Why grounding matters</h2>
|
| 1608 |
-
<p>We ran the same five questions through a base instruction-tuned model and through CHEX. The base model invented or extrapolated answers in 4 of 5 cases — confident, plausible, wrong. CHEX returned a verifiable label, a verbatim citation, and refused to answer when the source was silent.</p>
|
| 1609 |
-
</div>
|
| 1610 |
-
<div class="chex-bench-stats">
|
| 1611 |
-
<div class="chex-bench-stat"><div class="v red">4/5</div><div class="k">Base hallucinations</div></div>
|
| 1612 |
-
<div class="chex-bench-stat"><div class="v green">5/5</div><div class="k">CHEX correct</div></div>
|
| 1613 |
-
<div class="chex-bench-stat"><div class="v white">100%</div><div class="k">Cited verbatim</div></div>
|
| 1614 |
-
</div>
|
| 1615 |
-
</div>
|
| 1616 |
-
</div>
|
| 1617 |
-
"""
|
| 1618 |
-
|
| 1619 |
-
BENCH_TABLE_HTML = """
|
| 1620 |
-
<div class="chex-bench-table-wrap">
|
| 1621 |
-
<table class="chex-bench-table">
|
| 1622 |
-
<thead>
|
| 1623 |
-
<tr>
|
| 1624 |
-
<th>Question</th>
|
| 1625 |
-
<th>Ground truth</th>
|
| 1626 |
-
<th>Base model</th>
|
| 1627 |
-
<th>CHEX</th>
|
| 1628 |
-
<th>Halluc.</th>
|
| 1629 |
-
</tr>
|
| 1630 |
-
</thead>
|
| 1631 |
-
<tbody>
|
| 1632 |
-
<tr>
|
| 1633 |
-
<td class="col-question">What is the annual license fee in the Helix MSA?</td>
|
| 1634 |
-
<td class="col-truth">$144,000</td>
|
| 1635 |
-
<td class="col-base">$120,000 per year (industry-standard rate).</td>
|
| 1636 |
-
<td>
|
| 1637 |
-
<span class="cbadge cbadge-green"><span class="cbadge-icon">✓</span> GROUNDED</span>
|
| 1638 |
-
<div style="margin-top:8px;font-size:12.5px;color:var(--fg-muted)">$144,000 per year.</div>
|
| 1639 |
-
</td>
|
| 1640 |
-
<td class="col-halluc"><span class="chex-halluc-yes">!</span></td>
|
| 1641 |
-
</tr>
|
| 1642 |
-
<tr>
|
| 1643 |
-
<td class="col-question">What is the SLA uptime in the Northwind MSA?</td>
|
| 1644 |
-
<td class="col-truth">99.9% per calendar month</td>
|
| 1645 |
-
<td class="col-base">99.95% with four nines on premium tier.</td>
|
| 1646 |
-
<td>
|
| 1647 |
-
<span class="cbadge cbadge-green"><span class="cbadge-icon">✓</span> GROUNDED</span>
|
| 1648 |
-
<div style="margin-top:8px;font-size:12.5px;color:var(--fg-muted)">99.9% per calendar month, excluding maintenance.</div>
|
| 1649 |
-
</td>
|
| 1650 |
-
<td class="col-halluc"><span class="chex-halluc-yes">!</span></td>
|
| 1651 |
-
</tr>
|
| 1652 |
-
<tr>
|
| 1653 |
-
<td class="col-question">Does the Aperture NDA include an indemnification clause?</td>
|
| 1654 |
-
<td class="col-truth" style="font-style:italic">Not present in the document.</td>
|
| 1655 |
-
<td class="col-base">Yes — Section 7 of the NDA contains standard mutual indemnification.</td>
|
| 1656 |
-
<td>
|
| 1657 |
-
<span class="cbadge cbadge-red"><span class="cbadge-icon">✗</span> ABSENT</span>
|
| 1658 |
-
<div style="margin-top:8px;font-size:12.5px;color:var(--fg-muted)">No indemnification clause is present.</div>
|
| 1659 |
-
</td>
|
| 1660 |
-
<td class="col-halluc"><span class="chex-halluc-yes">!</span></td>
|
| 1661 |
-
</tr>
|
| 1662 |
-
<tr>
|
| 1663 |
-
<td class="col-question">Within how many days must security incidents be reported?</td>
|
| 1664 |
-
<td class="col-truth">72 hours</td>
|
| 1665 |
-
<td class="col-base">72 hours.</td>
|
| 1666 |
-
<td>
|
| 1667 |
-
<span class="cbadge cbadge-green"><span class="cbadge-icon">✓</span> GROUNDED</span>
|
| 1668 |
-
<div style="margin-top:8px;font-size:12.5px;color:var(--fg-muted)">Within 72 hours of becoming aware.</div>
|
| 1669 |
-
</td>
|
| 1670 |
-
<td class="col-halluc"><span class="chex-halluc-no">✓</span></td>
|
| 1671 |
-
</tr>
|
| 1672 |
-
<tr>
|
| 1673 |
-
<td class="col-question">Is the NDA perpetual?</td>
|
| 1674 |
-
<td class="col-truth" style="font-style:italic">No — 2 year term.</td>
|
| 1675 |
-
<td class="col-base">The NDA appears to be perpetual based on standard NDA practice.</td>
|
| 1676 |
-
<td>
|
| 1677 |
-
<span class="cbadge cbadge-amber"><span class="cbadge-icon">⚠</span> CONTRADICTS PRIOR</span>
|
| 1678 |
-
<div style="margin-top:8px;font-size:12.5px;color:var(--fg-muted)">No — 2 year term, contradicts the premise.</div>
|
| 1679 |
-
</td>
|
| 1680 |
-
<td class="col-halluc"><span class="chex-halluc-yes">!</span></td>
|
| 1681 |
-
</tr>
|
| 1682 |
-
</tbody>
|
| 1683 |
-
</table>
|
| 1684 |
-
</div>
|
| 1685 |
-
"""
|
| 1686 |
-
|
| 1687 |
-
CONTRACT_SOURCE_HEADER_HTML = """
|
| 1688 |
-
<div class="chex-card-header">
|
| 1689 |
-
<div class="chex-card-icon">
|
| 1690 |
-
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/></svg>
|
| 1691 |
-
</div>
|
| 1692 |
-
<span class="chex-card-title">Contract source</span>
|
| 1693 |
-
<span class="chex-card-sep">/</span>
|
| 1694 |
-
<span class="chex-card-sub">paste or load sample</span>
|
| 1695 |
-
</div>
|
| 1696 |
-
"""
|
| 1697 |
-
|
| 1698 |
-
CONTRACT_RESULTS_HEADER_HTML = """
|
| 1699 |
-
<div class="chex-card-header">
|
| 1700 |
-
<div class="chex-card-icon">
|
| 1701 |
-
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"/></svg>
|
| 1702 |
-
</div>
|
| 1703 |
-
<span class="chex-card-title">Classification</span>
|
| 1704 |
-
<span class="chex-card-sep">/</span>
|
| 1705 |
-
<span class="chex-card-sub">ask a question of the source</span>
|
| 1706 |
-
</div>
|
| 1707 |
-
"""
|
| 1708 |
-
|
| 1709 |
-
LOAD_BAR_HTML = """
|
| 1710 |
-
<div class="chex-load-bar">
|
| 1711 |
-
<span class="chex-load-chip">LOAD</span>
|
| 1712 |
-
</div>
|
| 1713 |
-
"""
|
| 1714 |
-
|
| 1715 |
-
STATEMENT_SOURCE_HEADER_HTML = """
|
| 1716 |
-
<div class="chex-card-header">
|
| 1717 |
-
<div class="chex-card-icon">
|
| 1718 |
-
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="5" width="20" height="14" rx="2"/><line x1="2" y1="10" x2="22" y2="10"/></svg>
|
| 1719 |
-
</div>
|
| 1720 |
-
<span class="chex-card-title">Statement source</span>
|
| 1721 |
-
<span class="chex-card-sep">/</span>
|
| 1722 |
-
<span class="chex-card-sub">paste · upload pdf · upload csv</span>
|
| 1723 |
-
</div>
|
| 1724 |
-
"""
|
| 1725 |
-
|
| 1726 |
-
STATEMENT_RESULTS_HEADER_HTML = """
|
| 1727 |
-
<div class="chex-card-header">
|
| 1728 |
-
<div class="chex-card-icon">
|
| 1729 |
-
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"/></svg>
|
| 1730 |
-
</div>
|
| 1731 |
-
<span class="chex-card-title">Statement analysis</span>
|
| 1732 |
-
<span class="chex-card-sep">/</span>
|
| 1733 |
-
<span class="chex-card-sub">summary + Q&A</span>
|
| 1734 |
-
</div>
|
| 1735 |
-
"""
|
| 1736 |
-
|
| 1737 |
-
CONTRACT_EMPTY_HTML = """
|
| 1738 |
-
<div class="chex-empty">
|
| 1739 |
-
<div class="chex-empty-icon">⚡</div>
|
| 1740 |
-
<div class="chex-empty-title">No analysis yet</div>
|
| 1741 |
-
<div class="chex-empty-body">Load or paste a contract, type a question, then press Analyze. CHEX will return a label, an exact citation, and its reasoning.</div>
|
| 1742 |
-
</div>
|
| 1743 |
-
"""
|
| 1744 |
-
|
| 1745 |
-
STATEMENT_EMPTY_HTML = """
|
| 1746 |
-
<div class="chex-empty">
|
| 1747 |
-
<div class="chex-empty-icon">⎵</div>
|
| 1748 |
-
<div class="chex-empty-title">Awaiting statement</div>
|
| 1749 |
-
<div class="chex-empty-body">Paste, upload, or load the sample. CHEX will summarise totals, surface recurring payments, and flag anomalies you can drill into.</div>
|
| 1750 |
-
</div>
|
| 1751 |
-
"""
|
| 1752 |
|
| 1753 |
# ---------------------------------------------------------------------------
|
| 1754 |
# Gradio UI
|
|
@@ -1756,146 +1077,146 @@ STATEMENT_EMPTY_HTML = """
|
|
| 1756 |
|
| 1757 |
with gr.Blocks(title="CHEX β Document Intelligence") as demo:
|
| 1758 |
|
| 1759 |
-
|
| 1760 |
-
|
| 1761 |
-
if WARNING_HTML:
|
| 1762 |
-
gr.HTML(WARNING_HTML)
|
| 1763 |
|
| 1764 |
with gr.Tabs():
|
| 1765 |
|
| 1766 |
# ββ Tab 01: Contract Analysis ββββββββββββββββββββββββββββββββββββ #
|
| 1767 |
-
with gr.Tab("
|
| 1768 |
with gr.Row(equal_height=False):
|
| 1769 |
|
| 1770 |
with gr.Column(scale=9):
|
| 1771 |
-
|
| 1772 |
-
|
| 1773 |
-
|
| 1774 |
-
|
| 1775 |
-
|
| 1776 |
-
|
| 1777 |
-
|
| 1778 |
-
|
| 1779 |
-
|
| 1780 |
-
|
| 1781 |
-
|
| 1782 |
-
|
| 1783 |
-
|
| 1784 |
-
suggested_q = gr.HTML(value="", visible=False)
|
| 1785 |
|
| 1786 |
with gr.Column(scale=11):
|
| 1787 |
-
|
| 1788 |
-
|
| 1789 |
-
gr.
|
| 1790 |
-
|
| 1791 |
-
|
| 1792 |
-
|
| 1793 |
-
|
| 1794 |
-
|
| 1795 |
-
|
| 1796 |
-
|
| 1797 |
-
|
| 1798 |
-
|
| 1799 |
-
|
| 1800 |
-
answer_output = gr.Textbox(label="Answer", interactive=False, lines=3, visible=False)
|
| 1801 |
-
citation_output = gr.Textbox(label="Citation", interactive=False, lines=2, visible=False)
|
| 1802 |
-
reasoning_output = gr.Textbox(label="Reasoning", interactive=False, lines=3, visible=False)
|
| 1803 |
|
| 1804 |
# ββ Tab 02: Bank Statements ββββββββββββββββββββββββββββββββββββββ #
|
| 1805 |
-
with gr.Tab("
|
| 1806 |
with gr.Row(equal_height=False):
|
| 1807 |
|
| 1808 |
with gr.Column(scale=9):
|
| 1809 |
-
|
| 1810 |
-
|
| 1811 |
-
with gr.
|
| 1812 |
-
|
| 1813 |
-
|
| 1814 |
-
|
| 1815 |
-
|
| 1816 |
-
placeholder=(
|
| 1817 |
-
"Paste your statement here, e.g. lines like: 2025-03-15 Direct deposit +5,420.00β¦"
|
| 1818 |
-
),
|
| 1819 |
-
show_label=False,
|
| 1820 |
-
)
|
| 1821 |
-
btn_load_statement = gr.Button("Load sample statement", variant="secondary", size="sm")
|
| 1822 |
-
with gr.Tab("Upload PDF"):
|
| 1823 |
-
bank_pdf_input = gr.File(
|
| 1824 |
-
label="PDF bank statement (multiple allowed)",
|
| 1825 |
-
file_types=[".pdf"],
|
| 1826 |
-
file_count="multiple",
|
| 1827 |
-
)
|
| 1828 |
-
bank_pdf_password_input = gr.Textbox(
|
| 1829 |
-
label="PDF password (optional)",
|
| 1830 |
-
type="password",
|
| 1831 |
-
placeholder="Leave blank if PDF is not encrypted",
|
| 1832 |
-
show_label=False,
|
| 1833 |
-
)
|
| 1834 |
-
with gr.Tab("Upload CSV"):
|
| 1835 |
-
bank_csv_input = gr.File(
|
| 1836 |
-
label="CSV bank statement (multiple allowed)",
|
| 1837 |
-
file_types=[".csv"],
|
| 1838 |
-
file_count="multiple",
|
| 1839 |
-
)
|
| 1840 |
-
with gr.Tab("Upload TXT"):
|
| 1841 |
-
bank_txt_input = gr.File(
|
| 1842 |
-
label="TXT bank statement (multiple allowed)",
|
| 1843 |
-
file_types=[".txt", ".text"],
|
| 1844 |
-
file_count="multiple",
|
| 1845 |
-
)
|
| 1846 |
-
with gr.Tab("Upload Excel"):
|
| 1847 |
-
bank_xlsx_input = gr.File(
|
| 1848 |
-
label="Excel bank statement (.xlsx, multiple allowed)",
|
| 1849 |
-
file_types=[".xlsx"],
|
| 1850 |
-
file_count="multiple",
|
| 1851 |
-
)
|
| 1852 |
-
with gr.Tab("Upload OFX / QFX"):
|
| 1853 |
-
bank_ofx_input = gr.File(
|
| 1854 |
-
label="OFX / QFX bank statement (multiple allowed)",
|
| 1855 |
-
file_types=[".ofx", ".qfx"],
|
| 1856 |
-
file_count="multiple",
|
| 1857 |
-
)
|
| 1858 |
-
|
| 1859 |
-
with gr.Column(scale=11):
|
| 1860 |
-
with gr.Group():
|
| 1861 |
-
gr.HTML(STATEMENT_RESULTS_HEADER_HTML)
|
| 1862 |
-
analyse_stmt_btn = gr.Button("Analyse statement", variant="primary")
|
| 1863 |
-
summary_output = gr.HTML(value=STATEMENT_EMPTY_HTML)
|
| 1864 |
-
summary_md_output = gr.Markdown(value="", visible=False)
|
| 1865 |
-
with gr.Row():
|
| 1866 |
-
export_csv_btn = gr.Button("Export CSV", variant="secondary", size="sm")
|
| 1867 |
-
export_pdf_btn = gr.Button("Export PDF", variant="secondary", size="sm")
|
| 1868 |
-
export_status = gr.Markdown(value="")
|
| 1869 |
-
export_file = gr.File(label="Download", interactive=False)
|
| 1870 |
-
gr.HTML('<div class="chex-divider"></div>')
|
| 1871 |
-
gr.HTML('<span class="chex-section-kicker">Ask a question</span>')
|
| 1872 |
-
with gr.Row():
|
| 1873 |
-
bank_question_input = gr.Textbox(
|
| 1874 |
-
label="Question",
|
| 1875 |
-
placeholder="e.g., What was the largest debit this month?",
|
| 1876 |
-
lines=1,
|
| 1877 |
show_label=False,
|
| 1878 |
-
scale=8,
|
| 1879 |
)
|
| 1880 |
-
|
| 1881 |
-
|
| 1882 |
-
|
| 1883 |
-
|
| 1884 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1885 |
|
| 1886 |
bank_statement_state = gr.State("")
|
| 1887 |
bank_summary_state = gr.State("")
|
| 1888 |
-
# Hidden JSON output for `gradio_client` API usage.
|
| 1889 |
bank_api_output = gr.JSON(visible=False)
|
| 1890 |
bank_api_question = gr.Textbox(visible=False)
|
| 1891 |
bank_api_btn = gr.Button(visible=False)
|
| 1892 |
|
| 1893 |
# ββ Tab 03: Benchmark ββββββββββββββββββββββββββββββββββββββββββββ #
|
| 1894 |
-
with gr.Tab("
|
| 1895 |
-
gr.
|
| 1896 |
-
|
| 1897 |
-
|
| 1898 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1899 |
|
| 1900 |
# ββ Event handlers βββββββββββββββββββββββββββββββββββββββββββββββββββ #
|
| 1901 |
|
|
@@ -1916,13 +1237,7 @@ with gr.Blocks(title="CHEX β Document Intelligence") as demo:
|
|
| 1916 |
btn_service.click(fn=load_service, inputs=[], outputs=[contract_input, question_input, suggested_q])
|
| 1917 |
|
| 1918 |
def analyze_contract_ui(contract_text: str, question: str):
|
| 1919 |
-
|
| 1920 |
-
return (
|
| 1921 |
-
label_html,
|
| 1922 |
-
gr.update(value=answer, visible=True),
|
| 1923 |
-
gr.update(value=citation, visible=True),
|
| 1924 |
-
gr.update(value=reasoning, visible=True),
|
| 1925 |
-
)
|
| 1926 |
|
| 1927 |
analyze_btn.click(
|
| 1928 |
fn=analyze_contract_ui,
|
|
@@ -1939,19 +1254,8 @@ with gr.Blocks(title="CHEX β Document Intelligence") as demo:
|
|
| 1939 |
|
| 1940 |
btn_load_statement.click(fn=lambda: SAMPLE_STATEMENT, inputs=[], outputs=[bank_paste_input])
|
| 1941 |
|
| 1942 |
-
def analyse_bank_ui(paste_text, pdf_file, pdf_password, csv_file, txt_file, xlsx_file, ofx_file):
|
| 1943 |
-
summary_md, combined_text, summary_json = analyse_bank_statement(
|
| 1944 |
-
paste_text, pdf_file, pdf_password, csv_file, txt_file, xlsx_file, ofx_file
|
| 1945 |
-
)
|
| 1946 |
-
return (
|
| 1947 |
-
gr.update(value="", visible=False),
|
| 1948 |
-
gr.update(value=summary_md, visible=True),
|
| 1949 |
-
combined_text,
|
| 1950 |
-
summary_json,
|
| 1951 |
-
)
|
| 1952 |
-
|
| 1953 |
analyse_stmt_btn.click(
|
| 1954 |
-
fn=
|
| 1955 |
inputs=[
|
| 1956 |
bank_paste_input,
|
| 1957 |
bank_pdf_input,
|
|
@@ -1961,7 +1265,7 @@ with gr.Blocks(title="CHEX β Document Intelligence") as demo:
|
|
| 1961 |
bank_xlsx_input,
|
| 1962 |
bank_ofx_input,
|
| 1963 |
],
|
| 1964 |
-
outputs=[
|
| 1965 |
)
|
| 1966 |
|
| 1967 |
export_csv_btn.click(
|
|
|
|
| 1042 |
# ---------------------------------------------------------------------------
|
| 1043 |
|
| 1044 |
CHEX_CSS = """
|
|
|
|
|
|
|
| 1045 |
*, *::before, *::after { box-sizing: border-box; }
|
| 1046 |
|
| 1047 |
:root {
|
| 1048 |
+
--green: #16a34a;
|
| 1049 |
+
--red: #dc2626;
|
| 1050 |
+
--amber: #d97706;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1051 |
}
|
| 1052 |
|
| 1053 |
+
/* label badges */
|
| 1054 |
+
.badge {
|
| 1055 |
+
display: inline-block; padding: 3px 10px; border-radius: 4px;
|
| 1056 |
+
font-size: 12px; font-weight: 600; letter-spacing: 0.02em;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1057 |
}
|
| 1058 |
+
.badge-green { background: #dcfce7; color: var(--green); }
|
| 1059 |
+
.badge-red { background: #fee2e2; color: var(--red); }
|
| 1060 |
+
.badge-amber { background: #fef3c7; color: var(--amber); }
|
| 1061 |
+
.badge-gray { background: #f1f5f9; color: #64748b; }
|
| 1062 |
"""
|
| 1063 |
|
| 1064 |
# ---------------------------------------------------------------------------
|
| 1065 |
# Static HTML
|
| 1066 |
# ---------------------------------------------------------------------------
|
| 1067 |
|
| 1068 |
+
WARNING_BANNER_HTML = (
|
| 1069 |
+
'<div style="background:#fef3c7;border:1px solid #fde68a;border-radius:6px;'
|
| 1070 |
+
'padding:10px 14px;margin-bottom:12px;color:#92400e;font-size:13px;">'
|
| 1071 |
+
'<strong>β Model not loaded</strong> — {msg}</div>'
|
| 1072 |
+
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1073 |
|
| 1074 |
# ---------------------------------------------------------------------------
|
| 1075 |
# Gradio UI
|
|
|
|
| 1077 |
|
| 1078 |
with gr.Blocks(title="CHEX β Document Intelligence") as demo:
|
| 1079 |
|
| 1080 |
+
if model_load_error:
|
| 1081 |
+
gr.HTML(WARNING_BANNER_HTML.format(msg=model_load_error))
|
|
|
|
|
|
|
| 1082 |
|
| 1083 |
with gr.Tabs():
|
| 1084 |
|
| 1085 |
# ββ Tab 01: Contract Analysis ββββββββββββββββββββββββββββββββββββ #
|
| 1086 |
+
with gr.Tab("Contract analysis"):
|
| 1087 |
with gr.Row(equal_height=False):
|
| 1088 |
|
| 1089 |
with gr.Column(scale=9):
|
| 1090 |
+
gr.Markdown("### Contract source\nPaste text or load a sample.")
|
| 1091 |
+
contract_input = gr.Textbox(
|
| 1092 |
+
label="Contract text",
|
| 1093 |
+
lines=20,
|
| 1094 |
+
placeholder="Paste contract text hereβ¦",
|
| 1095 |
+
show_label=False,
|
| 1096 |
+
)
|
| 1097 |
+
gr.Markdown("**Load sample:**")
|
| 1098 |
+
with gr.Row():
|
| 1099 |
+
btn_software = gr.Button("Software License", variant="secondary", size="sm")
|
| 1100 |
+
btn_nda = gr.Button("NDA", variant="secondary", size="sm")
|
| 1101 |
+
btn_service = gr.Button("Service Agreement", variant="secondary", size="sm")
|
| 1102 |
+
suggested_q = gr.Markdown(value="", visible=False)
|
|
|
|
| 1103 |
|
| 1104 |
with gr.Column(scale=11):
|
| 1105 |
+
gr.Markdown("### Classification\nAsk a yes/no or factual question about the contract.")
|
| 1106 |
+
with gr.Row():
|
| 1107 |
+
question_input = gr.Textbox(
|
| 1108 |
+
label="Question",
|
| 1109 |
+
placeholder="e.g., What is the annual license fee?",
|
| 1110 |
+
lines=1,
|
| 1111 |
+
scale=8,
|
| 1112 |
+
)
|
| 1113 |
+
analyze_btn = gr.Button("Analyze", variant="primary", scale=2)
|
| 1114 |
+
label_display = gr.HTML(value=format_label_html("N/A"))
|
| 1115 |
+
answer_output = gr.Textbox(label="Answer", interactive=False, lines=3)
|
| 1116 |
+
citation_output = gr.Textbox(label="Citation", interactive=False, lines=2)
|
| 1117 |
+
reasoning_output = gr.Textbox(label="Reasoning", interactive=False, lines=3)
|
|
|
|
|
|
|
|
|
|
| 1118 |
|
| 1119 |
# ββ Tab 02: Bank Statements ββββββββββββββββββββββββββββββββββββββ #
|
| 1120 |
+
with gr.Tab("Bank statements"):
|
| 1121 |
with gr.Row(equal_height=False):
|
| 1122 |
|
| 1123 |
with gr.Column(scale=9):
|
| 1124 |
+
gr.Markdown("### Statement source\nPaste, upload, or load the sample.")
|
| 1125 |
+
with gr.Tabs():
|
| 1126 |
+
with gr.Tab("Paste text"):
|
| 1127 |
+
bank_paste_input = gr.Textbox(
|
| 1128 |
+
label="Statement text",
|
| 1129 |
+
lines=20,
|
| 1130 |
+
placeholder="Paste statement here, e.g. lines like: 2025-03-15 Direct deposit +5,420.00β¦\n\nSeparate multiple statements with a line containing only ---",
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1131 |
show_label=False,
|
|
|
|
| 1132 |
)
|
| 1133 |
+
btn_load_statement = gr.Button("Load sample", variant="secondary", size="sm")
|
| 1134 |
+
with gr.Tab("Upload PDF"):
|
| 1135 |
+
bank_pdf_input = gr.File(
|
| 1136 |
+
label="PDF (multiple allowed)",
|
| 1137 |
+
file_types=[".pdf"],
|
| 1138 |
+
file_count="multiple",
|
| 1139 |
+
)
|
| 1140 |
+
bank_pdf_password_input = gr.Textbox(
|
| 1141 |
+
label="PDF password (leave blank if unencrypted)",
|
| 1142 |
+
type="password",
|
| 1143 |
+
)
|
| 1144 |
+
with gr.Tab("Upload CSV"):
|
| 1145 |
+
bank_csv_input = gr.File(
|
| 1146 |
+
label="CSV (multiple allowed)",
|
| 1147 |
+
file_types=[".csv"],
|
| 1148 |
+
file_count="multiple",
|
| 1149 |
+
)
|
| 1150 |
+
with gr.Tab("Upload TXT"):
|
| 1151 |
+
bank_txt_input = gr.File(
|
| 1152 |
+
label="TXT (multiple allowed)",
|
| 1153 |
+
file_types=[".txt", ".text"],
|
| 1154 |
+
file_count="multiple",
|
| 1155 |
+
)
|
| 1156 |
+
with gr.Tab("Upload Excel"):
|
| 1157 |
+
bank_xlsx_input = gr.File(
|
| 1158 |
+
label="XLSX (multiple allowed)",
|
| 1159 |
+
file_types=[".xlsx"],
|
| 1160 |
+
file_count="multiple",
|
| 1161 |
+
)
|
| 1162 |
+
with gr.Tab("Upload OFX/QFX"):
|
| 1163 |
+
bank_ofx_input = gr.File(
|
| 1164 |
+
label="OFX/QFX (multiple allowed)",
|
| 1165 |
+
file_types=[".ofx", ".qfx"],
|
| 1166 |
+
file_count="multiple",
|
| 1167 |
+
)
|
| 1168 |
+
|
| 1169 |
+
with gr.Column(scale=11):
|
| 1170 |
+
gr.Markdown("### Statement analysis")
|
| 1171 |
+
analyse_stmt_btn = gr.Button("Analyse statement", variant="primary")
|
| 1172 |
+
summary_md_output = gr.Markdown(value="*Run Analyse statement to see results.*")
|
| 1173 |
+
with gr.Row():
|
| 1174 |
+
export_csv_btn = gr.Button("Export CSV", variant="secondary", size="sm")
|
| 1175 |
+
export_pdf_btn = gr.Button("Export PDF", variant="secondary", size="sm")
|
| 1176 |
+
export_status = gr.Markdown(value="")
|
| 1177 |
+
export_file = gr.File(label="Download", interactive=False)
|
| 1178 |
+
gr.Markdown("---\n**Ask a question about the statement:**")
|
| 1179 |
+
with gr.Row():
|
| 1180 |
+
bank_question_input = gr.Textbox(
|
| 1181 |
+
label="Question",
|
| 1182 |
+
placeholder="e.g., What was the largest debit this month?",
|
| 1183 |
+
lines=1,
|
| 1184 |
+
scale=8,
|
| 1185 |
+
)
|
| 1186 |
+
bank_ask_btn = gr.Button("Ask", variant="secondary", scale=2)
|
| 1187 |
+
bank_label_display = gr.HTML(value=format_label_html("N/A"))
|
| 1188 |
+
bank_answer_output = gr.Textbox(label="Answer", interactive=False, lines=3)
|
| 1189 |
+
bank_citation_output = gr.Textbox(label="Citation", interactive=False, lines=2)
|
| 1190 |
+
bank_reasoning_output = gr.Textbox(label="Reasoning", interactive=False, lines=3)
|
| 1191 |
|
| 1192 |
bank_statement_state = gr.State("")
|
| 1193 |
bank_summary_state = gr.State("")
|
|
|
|
| 1194 |
bank_api_output = gr.JSON(visible=False)
|
| 1195 |
bank_api_question = gr.Textbox(visible=False)
|
| 1196 |
bank_api_btn = gr.Button(visible=False)
|
| 1197 |
|
| 1198 |
# ββ Tab 03: Benchmark ββββββββββββββββββββββββββββββββββββββββββββ #
|
| 1199 |
+
with gr.Tab("Benchmark"):
|
| 1200 |
+
gr.Markdown("""
|
| 1201 |
+
### Why grounding matters
|
| 1202 |
+
|
| 1203 |
+
We ran the same five questions through a base instruction-tuned model and through CHEX.
|
| 1204 |
+
The base model invented or extrapolated answers in **4 of 5 cases** β confident, plausible, wrong.
|
| 1205 |
+
CHEX returned a verifiable label, a verbatim citation, and refused to answer when the source was silent.
|
| 1206 |
+
|
| 1207 |
+
| Metric | Result |
|
| 1208 |
+
|---|---|
|
| 1209 |
+
| Base hallucinations | **4 / 5** |
|
| 1210 |
+
| CHEX correct | **5 / 5** |
|
| 1211 |
+
| Cited verbatim | **100%** |
|
| 1212 |
+
""")
|
| 1213 |
+
gr.Dataframe(
|
| 1214 |
+
value=BENCHMARK_DF,
|
| 1215 |
+
headers=list(BENCHMARK_DF.columns),
|
| 1216 |
+
datatype=["str"] * len(BENCHMARK_DF.columns),
|
| 1217 |
+
wrap=True,
|
| 1218 |
+
interactive=False,
|
| 1219 |
+
)
|
| 1220 |
|
| 1221 |
# ββ Event handlers βββββββββββββββββββββββββββββββββββββββββββββββββββ #
|
| 1222 |
|
|
|
|
| 1237 |
btn_service.click(fn=load_service, inputs=[], outputs=[contract_input, question_input, suggested_q])
|
| 1238 |
|
| 1239 |
def analyze_contract_ui(contract_text: str, question: str):
|
| 1240 |
+
return analyze_contract(contract_text, question)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1241 |
|
| 1242 |
analyze_btn.click(
|
| 1243 |
fn=analyze_contract_ui,
|
|
|
|
| 1254 |
|
| 1255 |
btn_load_statement.click(fn=lambda: SAMPLE_STATEMENT, inputs=[], outputs=[bank_paste_input])
|
| 1256 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1257 |
analyse_stmt_btn.click(
|
| 1258 |
+
fn=analyse_bank_statement,
|
| 1259 |
inputs=[
|
| 1260 |
bank_paste_input,
|
| 1261 |
bank_pdf_input,
|
|
|
|
| 1265 |
bank_xlsx_input,
|
| 1266 |
bank_ofx_input,
|
| 1267 |
],
|
| 1268 |
+
outputs=[summary_md_output, bank_statement_state, bank_summary_state],
|
| 1269 |
)
|
| 1270 |
|
| 1271 |
export_csv_btn.click(
|