EtonMu commited on
Commit
565ca72
·
verified ·
1 Parent(s): dabc5c9

Ship gallery assets as LFS tar (fix broken images)

Browse files
Files changed (2) hide show
  1. app.py +6 -4
  2. static/index.html +73 -4
app.py CHANGED
@@ -130,7 +130,8 @@ async def process(
130
 
131
  ref_bytes = await reference.read()
132
  if len(ref_bytes) > MAX_UPLOAD_BYTES:
133
- return JSONResponse({'error': 'Reference file too large (max 80 MB).'},
 
134
  status_code=413)
135
 
136
  tgt_bytes = None
@@ -139,7 +140,8 @@ async def process(
139
  if len(tgt_bytes) == 0:
140
  tgt_bytes = None
141
  elif len(tgt_bytes) > MAX_UPLOAD_BYTES:
142
- return JSONResponse({'error': 'Target file too large (max 80 MB).'},
 
143
  status_code=413)
144
 
145
  try:
@@ -185,8 +187,8 @@ async def process(
185
  # Log the error type only — never image data or filenames
186
  print(f'[App] Processing error: {type(e).__name__}: {e}')
187
  return JSONResponse(
188
- {'error': 'Could not process this image. Please check the file '
189
- 'format and try again.'},
190
  status_code=422)
191
 
192
 
 
130
 
131
  ref_bytes = await reference.read()
132
  if len(ref_bytes) > MAX_UPLOAD_BYTES:
133
+ return JSONResponse({'error': 'Reference file too large (max 80 MB). '
134
+ '“We’re gonna need a bigger boat” — or a smaller file.'},
135
  status_code=413)
136
 
137
  tgt_bytes = None
 
140
  if len(tgt_bytes) == 0:
141
  tgt_bytes = None
142
  elif len(tgt_bytes) > MAX_UPLOAD_BYTES:
143
+ return JSONResponse({'error': 'Photo file too large (max 80 MB). '
144
+ '“We’re gonna need a bigger boat” — or a smaller file.'},
145
  status_code=413)
146
 
147
  try:
 
187
  # Log the error type only — never image data or filenames
188
  print(f'[App] Processing error: {type(e).__name__}: {e}')
189
  return JSONResponse(
190
+ {'error': 'Could not read this image format. '
191
+ '“Forget it, Jake. It’s Chinatown.” — try another file.'},
192
  status_code=422)
193
 
194
 
static/index.html CHANGED
@@ -5,6 +5,7 @@
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
  <meta name="referrer" content="no-referrer">
7
  <title>DEEP ANALOG: Machine Learning Powered Color Rebuild</title>
 
8
  <style>
9
  :root {
10
  --bg: #0b0b0d;
@@ -712,6 +713,18 @@
712
  25% { background: var(--accent); border-color: var(--accent); }
713
  }
714
 
 
 
 
 
 
 
 
 
 
 
 
 
715
  @media (prefers-reduced-motion: reduce) {
716
  *, *::before, *::after { animation: none !important; transition: none !important; }
717
  .reveal { opacity: 1; transform: none; }
@@ -886,6 +899,7 @@
886
  around bright highlights: light scatters off the film base and re-exposes the
887
  red-sensitive layer. Slide up to push your highlights toward this signature
888
  red film quality — like the skyline edges in this 35mm scan.
 
889
  <img src="static/help/halation.jpg" alt="Red film halation on a skyline, 35mm scan"></span></span></span>
890
  <output id="halOut">1.0×</output></label>
891
  <input type="range" id="halRange" min="0" max="3" step="0.1" value="1.0">
@@ -1123,6 +1137,8 @@
1123
  <p>The service runs on Hugging Face infrastructure; transport is encrypted end-to-end.
1124
  No third party is granted access to request contents by this application.</p>
1125
 
 
 
1126
  <button class="close-btn" id="privacyClose">Close</button>
1127
  </div>
1128
  </div>
@@ -1232,8 +1248,16 @@
1232
  // ------------------------------------------------ sliders
1233
  [['toneRange', 'toneOut', v => (+v).toFixed(2)],
1234
  ['filmRange', 'filmOut', v => (+v).toFixed(2)],
1235
- ['grainRange', 'grainOut', v => (+v).toFixed(1) + '×'],
1236
- ['halRange', 'halOut', v => (+v).toFixed(1) + '×']]
 
 
 
 
 
 
 
 
1237
  .forEach(([r, o, fmt]) => {
1238
  $(r).addEventListener('input', () => { $(o).textContent = fmt($(r).value); });
1239
  });
@@ -1273,13 +1297,39 @@
1273
  return data;
1274
  })
1275
  .then(data => { setBusy(false, ''); renderResults(data); })
1276
- .catch(err => { setBusy(false, err.message, true); });
 
 
 
 
 
 
1277
  });
1278
 
 
 
 
 
 
 
 
 
 
1279
  function setBusy(busy, msg, isErr) {
1280
  $('processBtn').disabled = busy || !refFile;
1281
  $('processBtn').classList.toggle('busy', !!busy);
1282
  $('status').classList.toggle('busy', !!busy);
 
 
 
 
 
 
 
 
 
 
 
1283
  $('statusText').textContent = msg || '';
1284
  $('statusText').className = isErr ? 'err' : '';
1285
  }
@@ -1363,7 +1413,8 @@
1363
  'deep-analog-' + stamp + '.cube', ICO.cube,
1364
  'The exact 3D color transform of this look. Load it in Photoshop ' +
1365
  '(Color Lookup), DaVinci Resolve, Premiere or Final Cut and apply ' +
1366
- 'the same grade to any photo or video.'));
 
1367
  if (data.xmp) {
1368
  dls.appendChild(dlButton('Adobe preset', '.XMP · LR/ACR',
1369
  () => URL.createObjectURL(new Blob([data.xmp], { type: 'application/xml' })),
@@ -2235,6 +2286,24 @@
2235
  });
2236
  })();
2237
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2238
  // ------------------------------------------------ ambience
2239
  // Scroll-reveal for below-the-fold sections
2240
  document.querySelectorAll('section.demo, .filmstrip, footer').forEach(el =>
 
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
  <meta name="referrer" content="no-referrer">
7
  <title>DEEP ANALOG: Machine Learning Powered Color Rebuild</title>
8
+ <link rel="icon" type="image/svg+xml" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cdefs%3E%3CclipPath id='c'%3E%3Ccircle cx='12' cy='12' r='9.6'/%3E%3C/clipPath%3E%3C/defs%3E%3Cg clip-path='url(%23c)' fill='%23E8A33D'%3E%3Cg transform='rotate(0 12 12)'%3E%3Cpath d='M10 0.67 A11.5 11.5 0 0 1 17.75 2.04 L7.91 9.34 Z'/%3E%3C/g%3E%3Cg transform='rotate(45 12 12)'%3E%3Cpath d='M10 0.67 A11.5 11.5 0 0 1 17.75 2.04 L7.91 9.34 Z'/%3E%3C/g%3E%3Cg transform='rotate(90 12 12)'%3E%3Cpath d='M10 0.67 A11.5 11.5 0 0 1 17.75 2.04 L7.91 9.34 Z'/%3E%3C/g%3E%3Cg transform='rotate(135 12 12)'%3E%3Cpath d='M10 0.67 A11.5 11.5 0 0 1 17.75 2.04 L7.91 9.34 Z'/%3E%3C/g%3E%3Cg transform='rotate(180 12 12)'%3E%3Cpath d='M10 0.67 A11.5 11.5 0 0 1 17.75 2.04 L7.91 9.34 Z'/%3E%3C/g%3E%3Cg transform='rotate(225 12 12)'%3E%3Cpath d='M10 0.67 A11.5 11.5 0 0 1 17.75 2.04 L7.91 9.34 Z'/%3E%3C/g%3E%3Cg transform='rotate(270 12 12)'%3E%3Cpath d='M10 0.67 A11.5 11.5 0 0 1 17.75 2.04 L7.91 9.34 Z'/%3E%3C/g%3E%3Cg transform='rotate(315 12 12)'%3E%3Cpath d='M10 0.67 A11.5 11.5 0 0 1 17.75 2.04 L7.91 9.34 Z'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E">
9
  <style>
10
  :root {
11
  --bg: #0b0b0d;
 
713
  25% { background: var(--accent); border-color: var(--accent); }
714
  }
715
 
716
+ body.projector::before { opacity: .22; }
717
+ body.projector .wrap { animation: projJitter 1.3s steps(3); }
718
+ @keyframes projJitter {
719
+ 0% { transform: translateY(0); filter: brightness(1); }
720
+ 15% { transform: translateY(-2px); filter: brightness(1.45); }
721
+ 30% { transform: translateY(1px); filter: brightness(.7); }
722
+ 45% { transform: translateY(-1px); filter: brightness(1.3); }
723
+ 60% { transform: translateY(2px); filter: brightness(.85); }
724
+ 80% { transform: translateY(-1px); filter: brightness(1.15); }
725
+ 100% { transform: none; filter: none; }
726
+ }
727
+
728
  @media (prefers-reduced-motion: reduce) {
729
  *, *::before, *::after { animation: none !important; transition: none !important; }
730
  .reveal { opacity: 1; transform: none; }
 
899
  around bright highlights: light scatters off the film base and re-exposes the
900
  red-sensitive layer. Slide up to push your highlights toward this signature
901
  red film quality — like the skyline edges in this 35mm scan.
902
+ The glow Wong Kar-wai taught us to crave.
903
  <img src="static/help/halation.jpg" alt="Red film halation on a skyline, 35mm scan"></span></span></span>
904
  <output id="halOut">1.0×</output></label>
905
  <input type="range" id="halRange" min="0" max="3" step="0.1" value="1.0">
 
1137
  <p>The service runs on Hugging Face infrastructure; transport is encrypted end-to-end.
1138
  No third party is granted access to request contents by this application.</p>
1139
 
1140
+ <p class="patent-note" style="margin-top:22px;font-style:italic">
1141
+ What happens in RAM, stays in RAM.</p>
1142
  <button class="close-btn" id="privacyClose">Close</button>
1143
  </div>
1144
  </div>
 
1248
  // ------------------------------------------------ sliders
1249
  [['toneRange', 'toneOut', v => (+v).toFixed(2)],
1250
  ['filmRange', 'filmOut', v => (+v).toFixed(2)],
1251
+ ['grainRange', 'grainOut', v => {
1252
+ const n = +v;
1253
+ if (n === 0) return '0× · digitally sterile';
1254
+ if (n === 2) return '2.0× · pushed like Tri-X';
1255
+ return n.toFixed(1) + '×';
1256
+ }],
1257
+ ['halRange', 'halOut', v => {
1258
+ const n = +v;
1259
+ return n === 3 ? '3.0× · neon noir' : n.toFixed(1) + '×';
1260
+ }]]
1261
  .forEach(([r, o, fmt]) => {
1262
  $(r).addEventListener('input', () => { $(o).textContent = fmt($(r).value); });
1263
  });
 
1297
  return data;
1298
  })
1299
  .then(data => { setBusy(false, ''); renderResults(data); })
1300
+ .catch(err => {
1301
+ const generic = !err || !err.message ||
1302
+ /Failed to fetch|NetworkError|Unexpected server/.test(err.message);
1303
+ setBusy(false, generic
1304
+ ? 'Cut! Something went wrong with this reel — check the connection and roll again.'
1305
+ : err.message, true);
1306
+ });
1307
  });
1308
 
1309
+ const WAIT_LINES = [
1310
+ 'Developing in the dark — no light leaks, promise.',
1311
+ 'Kubrick would demand 127 more takes.',
1312
+ 'Pushing one stop for mood.',
1313
+ 'Timing the print, frame by frame.',
1314
+ 'Waiting for the lab like it’s 1999.',
1315
+ ];
1316
+ let waitTimer = null;
1317
+
1318
  function setBusy(busy, msg, isErr) {
1319
  $('processBtn').disabled = busy || !refFile;
1320
  $('processBtn').classList.toggle('busy', !!busy);
1321
  $('status').classList.toggle('busy', !!busy);
1322
+ if (waitTimer) { clearInterval(waitTimer); waitTimer = null; }
1323
+ if (busy && msg && msg.indexOf('Rendering') === 0) {
1324
+ const t0 = Date.now();
1325
+ let i = 0;
1326
+ waitTimer = setInterval(() => {
1327
+ const quip = (Date.now() - t0 > 20000)
1328
+ ? '“The waiting is the hardest part.” — every film lab, ever'
1329
+ : WAIT_LINES[i++ % WAIT_LINES.length];
1330
+ $('statusText').textContent = 'Rendering… ' + quip;
1331
+ }, 5000);
1332
+ }
1333
  $('statusText').textContent = msg || '';
1334
  $('statusText').className = isErr ? 'err' : '';
1335
  }
 
1413
  'deep-analog-' + stamp + '.cube', ICO.cube,
1414
  'The exact 3D color transform of this look. Load it in Photoshop ' +
1415
  '(Color Lookup), DaVinci Resolve, Premiere or Final Cut and apply ' +
1416
+ 'the same grade to any photo or video. What’s in the box? Every ' +
1417
+ 'color, that’s what.'));
1418
  if (data.xmp) {
1419
  dls.appendChild(dlButton('Adobe preset', '.XMP · LR/ACR',
1420
  () => URL.createObjectURL(new Blob([data.xmp], { type: 'application/xml' })),
 
2286
  });
2287
  })();
2288
 
2289
+ // ------------------------------------------------ projectionist mode
2290
+ // click the wordmark 5 times: one second of sputtering projector
2291
+ (function () {
2292
+ const brand = document.querySelector('.brand');
2293
+ let clicks = 0, last = 0;
2294
+ brand.addEventListener('click', () => {
2295
+ const now = Date.now();
2296
+ if (now - last > 2500) clicks = 0;
2297
+ last = now;
2298
+ if (++clicks >= 5) {
2299
+ clicks = 0;
2300
+ document.body.classList.add('projector');
2301
+ console.log('Projectionist mode: acknowledged.');
2302
+ setTimeout(() => document.body.classList.remove('projector'), 1300);
2303
+ }
2304
+ });
2305
+ })();
2306
+
2307
  // ------------------------------------------------ ambience
2308
  // Scroll-reveal for below-the-fold sections
2309
  document.querySelectorAll('section.demo, .filmstrip, footer').forEach(el =>