Mehdi commited on
Commit
fffdc96
Β·
1 Parent(s): ee14d3e

feat: serve blog at /blog from main Space + badge showcase

Browse files

- Mount blog/ as FastAPI static files at /blog so the blog lives on
the same Space as the app (no separate repo needed)
- Add badges section to blog/index.html: 5 earned, 1 locked
- Add badges table to BLOG.md

Files changed (3) hide show
  1. BLOG.md +15 -0
  2. app.py +9 -1
  3. blog/index.html +75 -0
BLOG.md CHANGED
@@ -40,6 +40,21 @@ PDF upload
40
 
41
  ---
42
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
43
  ## The Real Story: 68 Commits of Lessons
44
 
45
  A hackathon README tells you what was built. The git log tells you what actually happened. Ours has 68 commits, and roughly two-thirds of them start with `fix:`. Here is the honest version.
 
40
 
41
  ---
42
 
43
+ ## Badges Earned β€” 5 / 6
44
+
45
+ Build Small Hackathon awards merit badges for specific technical achievements. Here's where we landed:
46
+
47
+ | Badge | Status | What it took |
48
+ |---|---|---|
49
+ | **Off the Grid** | βœ… Earned | Zero external APIs β€” everything runs via ZeroGPU, no OpenAI key, no rate limits, no data leaving the machine |
50
+ | **Well-Tuned** | βœ… Earned | QLoRA fine-tune on SQuAD, model published at `build-small-hackathon/MiniCPM4-8B-PaperProf` |
51
+ | **Off-Brand** | βœ… Earned | Hand-built HTML/CSS/JS β€” Gradio is invisible, the entire UI is 100% custom (see Lesson 2 below) |
52
+ | **Llama Champion** | βœ… Earned | GGUF published at `build-small-hackathon/MiniCPM4-8B-PaperProf-GGUF`, llama.cpp CPU runtime wired in via `PAPERPROF_RUNTIME=llamacpp` |
53
+ | **Field Notes** | βœ… Earned | This post, plus the interactive `blog/index.html` site |
54
+ | Sharing is Caring | β€” | Share an agent trace on the Hub for the community |
55
+
56
+ ---
57
+
58
  ## The Real Story: 68 Commits of Lessons
59
 
60
  A hackathon README tells you what was built. The git log tells you what actually happened. Ours has 68 commits, and roughly two-thirds of them start with `fix:`. Here is the honest version.
app.py CHANGED
@@ -12,6 +12,9 @@ try:
12
  import threading
13
  import gradio as gr
14
  import spaces
 
 
 
15
  from core.parser import extract_text
16
  from core.chunker import chunk_text
17
  from core.questioner import generate_question, generate_mcq
@@ -1074,4 +1077,9 @@ with gr.Blocks(title="PaperProf", css=CSS) as demo:
1074
  print("βœ… Gradio demo defined successfully")
1075
 
1076
  print("βœ… Launching demo...")
1077
- demo.launch(server_name="0.0.0.0", server_port=7860)
 
 
 
 
 
 
12
  import threading
13
  import gradio as gr
14
  import spaces
15
+ import uvicorn
16
+ from fastapi import FastAPI
17
+ from fastapi.staticfiles import StaticFiles
18
  from core.parser import extract_text
19
  from core.chunker import chunk_text
20
  from core.questioner import generate_question, generate_mcq
 
1077
  print("βœ… Gradio demo defined successfully")
1078
 
1079
  print("βœ… Launching demo...")
1080
+ _fastapi = FastAPI()
1081
+ app = gr.mount_gradio_app(_fastapi, demo, path="/")
1082
+ app.mount("/blog", StaticFiles(directory="blog", html=True), name="blog")
1083
+
1084
+ if __name__ == "__main__":
1085
+ uvicorn.run(app, host="0.0.0.0", port=7860)
blog/index.html CHANGED
@@ -358,6 +358,33 @@ td strong { color: #fff; font-weight: 600; }
358
  .btn:hover span { color: #07090F; }
359
 
360
  footer { position: relative; z-index: 1; max-width: 1060px; margin: 0 auto; padding: 70px 28px 46px; display: flex; flex-wrap: wrap; gap: 12px 40px; justify-content: space-between; font-family: var(--mono); font-size: .74rem; letter-spacing: 1px; color: var(--faint); }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
361
  </style>
362
  </head>
363
  <body>
@@ -397,6 +424,54 @@ footer { position: relative; z-index: 1; max-width: 1060px; margin: 0 auto; padd
397
  <div class="stat reveal"><span class="stat-num" data-count="0">0</span><span class="stat-label">external APIs</span></div>
398
  </section>
399
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
400
  <main id="article">
401
 
402
  <p class="lede reveal">It's 11 PM, the exam is tomorrow, and you're re-reading the same lecture PDF for the fourth time, feeling productive while learning nothing. Passive re-reading is one of the worst study techniques on record. Active recall, forcing yourself to answer questions, is one of the best.</p>
 
358
  .btn:hover span { color: #07090F; }
359
 
360
  footer { position: relative; z-index: 1; max-width: 1060px; margin: 0 auto; padding: 70px 28px 46px; display: flex; flex-wrap: wrap; gap: 12px 40px; justify-content: space-between; font-family: var(--mono); font-size: .74rem; letter-spacing: 1px; color: var(--faint); }
361
+
362
+ /* ============ BADGES ============ */
363
+ .badges-section { position: relative; z-index: 1; max-width: 1060px; margin: 72px auto 0; padding: 0 28px; }
364
+ .badges-header { display: flex; align-items: flex-end; gap: 28px; margin-bottom: 32px; flex-wrap: wrap; }
365
+ .badges-eyebrow { font-family: var(--mono); font-size: .74rem; letter-spacing: 3px; text-transform: uppercase; color: var(--cyan); display: block; margin-bottom: 10px; }
366
+ .badges-score { font-family: var(--display); font-weight: 700; font-size: clamp(2rem, 5vw, 3rem); letter-spacing: -2px; color: #fff; line-height: 1; }
367
+ .badges-score em { font-style: normal; font-size: .55em; color: var(--dim); font-weight: 400; letter-spacing: -0.5px; }
368
+ .badges-note { font-family: var(--mono); font-size: .76rem; color: var(--dim); max-width: 340px; line-height: 1.6; border-left: 2px solid var(--line-hot); padding-left: 16px; }
369
+ .badges-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(190px, 1fr)); gap: 14px; }
370
+ .badge {
371
+ background: var(--bg-raise); border: 1px solid var(--line); border-radius: 18px;
372
+ padding: 24px 22px; display: flex; flex-direction: column; gap: 13px;
373
+ transition: border-color .3s, transform .3s;
374
+ }
375
+ .badge.earned { border-color: rgba(74,222,128,0.28); }
376
+ .badge.earned:hover { border-color: rgba(74,222,128,0.6); transform: translateY(-5px); }
377
+ .badge.locked { opacity: 0.42; }
378
+ .badge-icon { font-size: 2rem; line-height: 1; }
379
+ .badge-name { font-family: var(--display); font-weight: 700; font-size: 1rem; color: #fff; letter-spacing: -0.3px; }
380
+ .badge-desc { font-family: var(--mono); font-size: .72rem; color: var(--dim); line-height: 1.6; flex: 1; }
381
+ .badge-chip {
382
+ display: inline-block; align-self: flex-start;
383
+ font-family: var(--mono); font-size: .65rem; letter-spacing: 2px; text-transform: uppercase;
384
+ border-radius: 50px; padding: 4px 12px;
385
+ }
386
+ .badge.earned .badge-chip { color: var(--green); background: rgba(74,222,128,0.08); border: 1px solid rgba(74,222,128,0.22); }
387
+ .badge.locked .badge-chip { color: var(--faint); background: transparent; border: 1px solid rgba(255,255,255,0.08); }
388
  </style>
389
  </head>
390
  <body>
 
424
  <div class="stat reveal"><span class="stat-num" data-count="0">0</span><span class="stat-label">external APIs</span></div>
425
  </section>
426
 
427
+ <section class="badges-section" aria-label="Hackathon badges earned">
428
+ <div class="badges-header reveal">
429
+ <div>
430
+ <span class="badges-eyebrow">Build Small Hackathon Β· Merit Badges</span>
431
+ <p class="badges-score">5 <em>/ 6 earned</em></p>
432
+ </div>
433
+ <p class="badges-note">Build Small awards badges for specific technical achievements. We collected five of six β€” every badge we could earn by shipping real, verifiable work.</p>
434
+ </div>
435
+ <div class="badges-grid">
436
+ <div class="badge earned reveal">
437
+ <span class="badge-icon">πŸ”Œ</span>
438
+ <strong class="badge-name">Off the Grid</strong>
439
+ <span class="badge-desc">Zero external APIs. MiniCPM4-8B and FLUX.2-klein run entirely on ZeroGPU β€” no OpenAI key, no rate limits, no data leaving the machine.</span>
440
+ <span class="badge-chip">βœ“ Earned</span>
441
+ </div>
442
+ <div class="badge earned reveal">
443
+ <span class="badge-icon">🎯</span>
444
+ <strong class="badge-name">Well-Tuned</strong>
445
+ <span class="badge-desc">QLoRA fine-tune on SQuAD via Modal. Model published on Hugging Face at <code>build-small-hackathon/MiniCPM4-8B-PaperProf</code>.</span>
446
+ <span class="badge-chip">βœ“ Earned</span>
447
+ </div>
448
+ <div class="badge earned reveal">
449
+ <span class="badge-icon">🎨</span>
450
+ <strong class="badge-name">Off-Brand</strong>
451
+ <span class="badge-desc">Hand-built HTML/CSS/JS over a hidden-Gradio bridge. Glassmorphism, animated score ring, dark academia palette β€” no default Gradio chrome visible.</span>
452
+ <span class="badge-chip">βœ“ Earned</span>
453
+ </div>
454
+ <div class="badge earned reveal">
455
+ <span class="badge-icon">πŸ¦™</span>
456
+ <strong class="badge-name">Llama Champion</strong>
457
+ <span class="badge-desc">GGUF published at <code>build-small-hackathon/MiniCPM4-8B-PaperProf-GGUF</code>. llama.cpp CPU runtime wired in via <code>PAPERPROF_RUNTIME=llamacpp</code>.</span>
458
+ <span class="badge-chip">βœ“ Earned</span>
459
+ </div>
460
+ <div class="badge earned reveal">
461
+ <span class="badge-icon">πŸ“</span>
462
+ <strong class="badge-name">Field Notes</strong>
463
+ <span class="badge-desc">This post β€” 68 commits, 10 days, zero sugarcoating. Honest account of what broke and what shipped.</span>
464
+ <span class="badge-chip">βœ“ Earned</span>
465
+ </div>
466
+ <div class="badge locked reveal">
467
+ <span class="badge-icon">🀝</span>
468
+ <strong class="badge-name">Sharing is Caring</strong>
469
+ <span class="badge-desc">Share an agent trace on the Hub so the community can learn from your runs.</span>
470
+ <span class="badge-chip">Not yet</span>
471
+ </div>
472
+ </div>
473
+ </section>
474
+
475
  <main id="article">
476
 
477
  <p class="lede reveal">It's 11 PM, the exam is tomorrow, and you're re-reading the same lecture PDF for the fourth time, feeling productive while learning nothing. Passive re-reading is one of the worst study techniques on record. Active recall, forcing yourself to answer questions, is one of the best.</p>