Spaces:
Runtime error
Runtime error
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8" /> | |
| <meta name="viewport" content="width=device-width, initial-scale=1" /> | |
| <title>ReadingBuddy β’ Reachy Mini</title> | |
| <style> | |
| :root{ | |
| --bg:#0f172a; | |
| --card:rgba(255,255,255,.06); | |
| --text:#e5e7eb; | |
| --muted:#94a3b8; | |
| --brand:#818cf8; | |
| --success:#22c55e; | |
| } | |
| *{ box-sizing:border-box; margin:0; } | |
| body{ | |
| margin:0; | |
| font-family: system-ui, -apple-system, sans-serif; | |
| color:var(--text); | |
| background: linear-gradient(135deg, #0f172a 0%, #1e293b 100%); | |
| line-height:1.6; | |
| padding:40px 20px; | |
| } | |
| .container{ | |
| max-width: 1000px; | |
| margin: 0 auto; | |
| } | |
| .hero{ | |
| text-align:center; | |
| margin-bottom:50px; | |
| } | |
| .logo{ | |
| font-size:80px; | |
| margin-bottom:20px; | |
| } | |
| h1{ | |
| font-size:3rem; | |
| margin:0 0 16px; | |
| background: linear-gradient(135deg, #818cf8, #22c55e); | |
| -webkit-background-clip: text; | |
| -webkit-text-fill-color: transparent; | |
| background-clip: text; | |
| } | |
| .tagline{ | |
| font-size:1.3rem; | |
| color:var(--muted); | |
| margin-bottom:32px; | |
| } | |
| h2{ | |
| font-size:1.8rem; | |
| margin:40px 0 24px; | |
| text-align:center; | |
| } | |
| .voice-grid{ | |
| display:grid; | |
| grid-template-columns:repeat(auto-fit, minmax(200px, 1fr)); | |
| gap:16px; | |
| margin:32px 0; | |
| } | |
| .voice-card{ | |
| position:relative; | |
| aspect-ratio: 3/2; | |
| border-radius:16px; | |
| overflow:hidden; | |
| border:3px solid rgba(129,140,248,.3); | |
| background-size:cover; | |
| background-position:center; | |
| display:flex; | |
| flex-direction:column; | |
| justify-content:flex-end; | |
| padding:16px; | |
| transition: transform 0.2s, border-color 0.2s; | |
| } | |
| .voice-card:hover{ | |
| transform: translateY(-4px); | |
| border-color: rgba(129,140,248,.6); | |
| } | |
| .voice-card::before{ | |
| content:''; | |
| position:absolute; | |
| inset:0; | |
| background: linear-gradient(to top, rgba(0,0,0,.85) 0%, rgba(0,0,0,.3) 60%, transparent 100%); | |
| } | |
| .voice-card .name{ | |
| position:relative; | |
| font-size:1.2rem; | |
| font-weight:700; | |
| margin-bottom:4px; | |
| } | |
| .voice-card .desc{ | |
| position:relative; | |
| font-size:0.9rem; | |
| color:rgba(255,255,255,.8); | |
| } | |
| .pills{ | |
| display:flex; | |
| gap:12px; | |
| justify-content:center; | |
| flex-wrap:wrap; | |
| margin:32px 0; | |
| } | |
| .pill{ | |
| padding:8px 16px; | |
| border-radius:999px; | |
| background:rgba(129,140,248,.15); | |
| border:1px solid rgba(129,140,248,.3); | |
| font-size:0.95rem; | |
| } | |
| .section{ | |
| background:var(--card); | |
| border:1px solid rgba(255,255,255,.1); | |
| border-radius:20px; | |
| padding:40px; | |
| margin:40px 0; | |
| } | |
| .section h2{ | |
| margin-top:0; | |
| text-align:left; | |
| } | |
| .steps{ | |
| display:grid; | |
| gap:16px; | |
| } | |
| .step{ | |
| display:flex; | |
| gap:16px; | |
| align-items:start; | |
| } | |
| .num{ | |
| width:36px; | |
| height:36px; | |
| border-radius:50%; | |
| background:rgba(129,140,248,.2); | |
| border:2px solid rgba(129,140,248,.4); | |
| display:grid; | |
| place-items:center; | |
| font-weight:700; | |
| flex-shrink:0; | |
| } | |
| code{ | |
| background:rgba(255,255,255,.08); | |
| padding:4px 10px; | |
| border-radius:8px; | |
| font-size:0.9em; | |
| word-break:break-all; | |
| } | |
| .code-block{ | |
| background:rgba(0,0,0,.3); | |
| border:1px solid rgba(255,255,255,.1); | |
| border-radius:12px; | |
| padding:16px; | |
| margin:16px 0; | |
| font-family: monospace; | |
| font-size:0.9em; | |
| overflow-x:auto; | |
| line-height:1.8; | |
| white-space:pre-wrap; | |
| } | |
| .code-block code{ | |
| background:transparent; | |
| padding:0; | |
| } | |
| .features{ | |
| display:grid; | |
| grid-template-columns:repeat(auto-fit, minmax(220px, 1fr)); | |
| gap:20px; | |
| margin:40px 0; | |
| } | |
| .feature{ | |
| background:var(--card); | |
| border:1px solid rgba(255,255,255,.1); | |
| border-radius:16px; | |
| padding:24px; | |
| text-align:center; | |
| } | |
| .feature-icon{ | |
| font-size:48px; | |
| margin-bottom:12px; | |
| } | |
| .feature h3{ | |
| font-size:1.1rem; | |
| margin-bottom:8px; | |
| } | |
| .feature p{ | |
| color:var(--muted); | |
| font-size:0.95rem; | |
| } | |
| .note{ | |
| background:rgba(34,197,94,.1); | |
| border:1px solid rgba(34,197,94,.3); | |
| border-radius:12px; | |
| padding:16px; | |
| margin:16px 0; | |
| color:#d1fae5; | |
| } | |
| .note strong{ | |
| color:#ecfdf5; | |
| } | |
| .tier-grid{ | |
| display:grid; | |
| grid-template-columns:repeat(auto-fit, minmax(200px, 1fr)); | |
| gap:16px; | |
| margin:24px 0; | |
| } | |
| .tier-card{ | |
| background:rgba(0,0,0,.2); | |
| border:1px solid rgba(255,255,255,.1); | |
| border-radius:16px; | |
| padding:20px; | |
| text-align:center; | |
| } | |
| .tier-card .tier-icon{ | |
| font-size:36px; | |
| margin-bottom:10px; | |
| } | |
| .tier-card h3{ | |
| font-size:1rem; | |
| margin-bottom:6px; | |
| } | |
| .tier-card p{ | |
| font-size:0.85rem; | |
| color:var(--muted); | |
| } | |
| .tier-card .tier-badge{ | |
| display:inline-block; | |
| padding:3px 10px; | |
| border-radius:999px; | |
| font-size:0.75rem; | |
| font-weight:700; | |
| margin-bottom:10px; | |
| } | |
| .badge-default{ background:rgba(34,197,94,.2); color:#86efac; border:1px solid rgba(34,197,94,.3); } | |
| .badge-premium{ background:rgba(129,140,248,.2); color:#c7d2fe; border:1px solid rgba(129,140,248,.3); } | |
| .badge-fallback{ background:rgba(255,255,255,.1); color:var(--muted); border:1px solid rgba(255,255,255,.1); } | |
| footer{ | |
| text-align:center; | |
| margin-top:60px; | |
| padding-top:30px; | |
| border-top:1px solid rgba(255,255,255,.1); | |
| color:var(--muted); | |
| font-size:0.9rem; | |
| } | |
| a{ color:#c7d2fe; text-decoration:none; } | |
| a:hover{ text-decoration:underline; } | |
| </style> | |
| </head> | |
| <body> | |
| <div class="container"> | |
| <div class="hero"> | |
| <div class="logo">π€π</div> | |
| <h1>ReadingBuddy</h1> | |
| <p class="tagline">Your Reachy Mini reads books aloud with character voices</p> | |
| <div class="pills"> | |
| <span class="pill">πΈ Camera OCR</span> | |
| <span class="pill">π 4 Voices</span> | |
| <span class="pill">π§ Page Memory</span> | |
| <span class="pill">π Story Library</span> | |
| </div> | |
| </div> | |
| <h2>π Character Voices</h2> | |
| <div class="voice-grid"> | |
| <div class="voice-card" style="background-image: url('reachy_mini_bookreader/static/voices/techstoryteller.jpg')"> | |
| <div class="name">Tech Storyteller</div> | |
| <div class="desc">GPU Dad mode</div> | |
| </div> | |
| <div class="voice-card" style="background-image: url('reachy_mini_bookreader/static/voices/superhero.jpg')"> | |
| <div class="name">Superhero</div> | |
| <div class="desc">Big energy</div> | |
| </div> | |
| <div class="voice-card" style="background-image: url('reachy_mini_bookreader/static/voices/princess.jpg')"> | |
| <div class="name">Princess</div> | |
| <div class="desc">Sweet + bright</div> | |
| </div> | |
| <div class="voice-card" style="background-image: url('reachy_mini_bookreader/static/voices/robothero.jpg')"> | |
| <div class="name">Robot Hero</div> | |
| <div class="desc">Strong + brave</div> | |
| </div> | |
| </div> | |
| <div class="features"> | |
| <div class="feature"> | |
| <div class="feature-icon">πΈ</div> | |
| <h3>Smart Camera</h3> | |
| <p>Capture pages, extract text instantly</p> | |
| </div> | |
| <div class="feature"> | |
| <div class="feature-icon">π</div> | |
| <h3>Three-Tier TTS</h3> | |
| <p>ElevenLabs β Piper β espeak fallback</p> | |
| </div> | |
| <div class="feature"> | |
| <div class="feature-icon">π§ </div> | |
| <h3>Page Memory</h3> | |
| <p>Remembers where you left off</p> | |
| </div> | |
| <div class="feature"> | |
| <div class="feature-icon">π</div> | |
| <h3>Story Library</h3> | |
| <p>Classic tales pre-loaded</p> | |
| </div> | |
| </div> | |
| <!-- Voice Tiers Section --> | |
| <div class="section"> | |
| <h2>π Voice Quality Tiers</h2> | |
| <p style="color:var(--muted); margin-bottom:24px; text-align:center;"> | |
| ReadingBuddy uses a smart three-tier voice system β great voices out of the box, upgradeable anytime! | |
| </p> | |
| <div class="tier-grid"> | |
| <div class="tier-card"> | |
| <div class="tier-icon">π</div> | |
| <div class="tier-badge badge-premium">Premium</div> | |
| <h3>ElevenLabs</h3> | |
| <p>Professional character voices with emotion and expression. Requires API key.</p> | |
| </div> | |
| <div class="tier-card"> | |
| <div class="tier-icon">π₯</div> | |
| <div class="tier-badge badge-default">Default β</div> | |
| <h3>Piper TTS</h3> | |
| <p>Natural-sounding voices, runs locally on your robot. Completely free!</p> | |
| </div> | |
| <div class="tier-card"> | |
| <div class="tier-icon">π₯</div> | |
| <div class="tier-badge badge-fallback">Fallback</div> | |
| <h3>espeak-ng</h3> | |
| <p>Robotic backup voice. Always available, no setup needed.</p> | |
| </div> | |
| </div> | |
| <div class="note"> | |
| <strong>π‘ Out of the box:</strong> You get Piper TTS β natural voices, completely free, no API key needed! | |
| Each character has a distinct voice personality. | |
| </div> | |
| </div> | |
| <!-- Install Section --> | |
| <div class="section"> | |
| <h2>π Install on Reachy Mini</h2> | |
| <div class="steps"> | |
| <div class="step"> | |
| <div class="num">1</div> | |
| <div>Open dashboard at <code>http://REACHY_IP:8000</code></div> | |
| </div> | |
| <div class="step"> | |
| <div class="num">2</div> | |
| <div>Click <strong>Install from Hugging Face</strong></div> | |
| </div> | |
| <div class="step"> | |
| <div class="num">3</div> | |
| <div>Search <code>reachy_mini_bookreader</code></div> | |
| </div> | |
| <div class="step"> | |
| <div class="num">4</div> | |
| <div>Click <strong>Install</strong> β <strong>Run</strong> β <strong>βοΈ</strong></div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Piper Setup Section --> | |
| <div class="section"> | |
| <h2>π₯ Setup Piper Voices (One-Time)</h2> | |
| <p style="color:var(--muted); margin-bottom:20px;"> | |
| After installing, download the voice models once via SSH: | |
| </p> | |
| <div class="steps"> | |
| <div class="step"> | |
| <div class="num">1</div> | |
| <div>SSH into your Reachy Mini: | |
| <div class="code-block"><code>ssh pollen@YOUR_REACHY_IP</code></div> | |
| </div> | |
| </div> | |
| <div class="step"> | |
| <div class="num">2</div> | |
| <div>Create the voices folder: | |
| <div class="code-block"><code>mkdir -p ~/.local/share/piper-voices | |
| cd ~/.local/share/piper-voices</code></div> | |
| </div> | |
| </div> | |
| <div class="step"> | |
| <div class="num">3</div> | |
| <div>Download all 4 character voices: | |
| <div class="code-block"><code>wget https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/en/en_US/arctic/medium/en_US-arctic-medium.onnx | |
| wget https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/en/en_US/arctic/medium/en_US-arctic-medium.onnx.json | |
| wget https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/en/en_US/danny/low/en_US-danny-low.onnx | |
| wget https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/en/en_US/danny/low/en_US-danny-low.onnx.json | |
| wget https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/en/en_US/amy/medium/en_US-amy-medium.onnx | |
| wget https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/en/en_US/amy/medium/en_US-amy-medium.onnx.json | |
| wget https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/en/en_US/john/medium/en_US-john-medium.onnx | |
| wget https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/en/en_US/john/medium/en_US-john-medium.onnx.json</code></div> | |
| </div> | |
| </div> | |
| <div class="step"> | |
| <div class="num">4</div> | |
| <div>Restart the app and enjoy natural voices! π€</div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- ElevenLabs Section --> | |
| <div class="section"> | |
| <h2>π Enable Premium ElevenLabs Voices (Optional)</h2> | |
| <p style="color:var(--muted); margin-bottom:20px;"> | |
| For the absolute best quality with theatrical character voices: | |
| </p> | |
| <div class="steps"> | |
| <div class="step"> | |
| <div class="num">1</div> | |
| <div>Get API key from <a href="https://elevenlabs.io" target="_blank">elevenlabs.io</a></div> | |
| </div> | |
| <div class="step"> | |
| <div class="num">2</div> | |
| <div>On your Reachy Mini, create a <code>.env</code> file: | |
| <div class="code-block"><code>cd ~/.local/share/reachy-mini/apps/reachy_mini_bookreader | |
| nano .env</code></div> | |
| </div> | |
| </div> | |
| <div class="step"> | |
| <div class="num">3</div> | |
| <div>Add these credentials (using our recommended voices): | |
| <div class="code-block"><code>ELEVENLABS_API_KEY=your_api_key_here | |
| ELEVEN_VOICE_TECH=9lv4qqEb8CqLgosI5Due | |
| ELEVEN_VOICE_SUPERHERO=248nvfaZe8BXhKntjmpp | |
| ELEVEN_VOICE_PRINCESS=mHX7OoPk2G45VMAuinIt | |
| ELEVEN_VOICE_ROBOTHERO=Q8ZbQAANLFvLw8uPBR8d</code></div> | |
| </div> | |
| </div> | |
| <div class="step"> | |
| <div class="num">4</div> | |
| <div>Save (<code>Ctrl+X</code>, <code>Y</code>, <code>Enter</code>) and restart the app</div> | |
| </div> | |
| </div> | |
| <div class="note"> | |
| <strong>π‘ Note:</strong> These are our curated voice IDs that work great for each character! | |
| You can also choose your own voices from the <a href="https://elevenlabs.io/app/voice-library" target="_blank" style="color:#a7f3d0;">ElevenLabs Voice Library</a>. | |
| </div> | |
| </div> | |
| <footer> | |
| <p>Requires <a href="https://www.pollen-robotics.com/reachy-mini/">Reachy Mini</a> robot hardware</p> | |
| <p style="margin-top:8px;">Made with β€οΈ for educational robotics</p> | |
| </footer> | |
| </div> | |
| </body> | |
| </html> |