| <!DOCTYPE html> |
| <html lang="es"> |
| <head> |
| <meta charset="UTF-8" /> |
| <meta name="viewport" content="width=device-width, initial-scale=1.0" /> |
| <title>Cocina Conmigo — Plan visual del proyecto</title> |
| <style> |
| :root { |
| --bg: #f5ecd9; |
| --card: #fffbf0; |
| --ink: #2b2018; |
| --accent: #a85c2a; /* terracotta */ |
| --accent-soft: #f6dccc; |
| --accent2: #6b4a2a; |
| --gold: #c9962b; |
| --green: #3f7a3a; |
| --green-soft: #dbe9d8; |
| --red: #b03a2e; |
| --red-soft: #f4d6d2; |
| --gray: #8a7e6f; |
| --line: #d8c9ad; |
| } |
| * { box-sizing: border-box; } |
| body { |
| font-family: 'Inter', -apple-system, sans-serif; |
| background: var(--bg); |
| color: var(--ink); |
| margin: 0; |
| padding: 32px 16px 80px; |
| line-height: 1.55; |
| } |
| .wrap { max-width: 1240px; margin: 0 auto; } |
|
|
| h1 { font-family: 'Lora', Georgia, serif; font-size: 46px; margin: 0 0 4px; |
| letter-spacing: -0.5px; font-weight: 700; } |
| h1 em { color: var(--accent); font-style: italic; } |
| .subtitle { color: var(--accent2); font-style: italic; margin-bottom: 28px; font-size: 17px; } |
|
|
| h2 { |
| margin-top: 56px; border-top: 1px dashed var(--line); padding-top: 24px; |
| font-size: 26px; font-family: 'Lora', Georgia, serif; letter-spacing: 0.3px; |
| } |
| h2 .num { |
| color: var(--accent); font-family: ui-monospace, monospace; |
| font-size: 20px; margin-right: 10px; |
| } |
| h3 { font-size: 18px; margin-top: 28px; color: var(--accent2); font-family: 'Lora', Georgia, serif; } |
|
|
| /* Hero */ |
| .hero { |
| background: var(--card); border: 2px solid var(--ink); border-radius: 14px; |
| padding: 30px 32px; display: grid; grid-template-columns: 1fr; gap: 18px; |
| } |
| @media(min-width: 760px){ .hero { grid-template-columns: 2fr 1fr; align-items: center; } } |
| .hero h2 { border:0; margin:0 0 6px; padding:0; font-size: 22px; } |
| .hero .quote { |
| font-style: italic; font-size: 17px; color: var(--accent2); |
| border-left: 3px solid var(--accent); padding-left: 14px; margin: 6px 0 0; |
| } |
| .hero .target { |
| background: #fff3cf; border-radius: 12px; padding: 14px 16px; |
| font-size: 13px; border: 1px solid var(--line); line-height: 1.55; |
| } |
| .hero .target strong { color: var(--accent); } |
|
|
| /* Pills */ |
| .pill { |
| display: inline-block; padding: 2px 9px; border-radius: 12px; |
| color: white; font-size: 12px; margin: 2px 4px 2px 0; font-family: ui-monospace, monospace; |
| } |
| .pill.user { background: var(--gray); } |
| .pill.gradio { background: var(--accent); } |
| .pill.hf { background: var(--gold); } |
| .pill.modal { background: var(--green); } |
| .pill.flux { background: #111; } |
| .pill.openbmb { background: #075e54; } |
| .pill.cohere { background: #5e3aa3; } |
| .pill.openai { background: #2c5e8a; } |
| .pill.llama { background: #6a3d8a; } |
|
|
| /* Phone/recipe card mockup */ |
| .phone-row { |
| display: grid; grid-template-columns: 1fr; gap: 18px; margin-top: 16px; |
| } |
| @media(min-width: 760px){ .phone-row { grid-template-columns: repeat(4, 1fr); } } |
| .phone { |
| background: #111; border-radius: 24px; padding: 8px; |
| box-shadow: 0 8px 22px rgba(0,0,0,0.18); |
| } |
| .phone .screen { |
| background: #fffbf0; border-radius: 18px; overflow: hidden; |
| height: 380px; display: flex; flex-direction: column; |
| } |
| .phone .topbar { |
| background: var(--accent); color: white; padding: 10px 14px; |
| font-size: 13px; font-family: 'Lora', serif; |
| } |
| .phone .body { padding: 12px; flex: 1; overflow-y: auto; font-size: 12px; } |
| .phone .body .illu { |
| width: 100%; aspect-ratio: 4/3; border-radius: 8px; |
| background: linear-gradient(135deg, #ffd28b 0%, #c97a3e 100%); |
| display: flex; align-items: center; justify-content: center; |
| font-size: 48px; box-shadow: 0 2px 8px rgba(0,0,0,0.1); margin-bottom: 8px; |
| } |
| .phone .body p { margin: 6px 0; line-height: 1.5; } |
| .phone .body .voice { |
| background: var(--green-soft); border-radius: 6px; padding: 6px 10px; |
| margin-top: 8px; font-size: 11px; color: var(--green); |
| } |
| .phone .body .tip { |
| background: var(--red-soft); border-radius: 6px; padding: 6px 10px; |
| margin-top: 6px; font-size: 11px; color: var(--red); |
| } |
| .scenario-label { |
| text-align: center; font-size: 13px; color: var(--accent2); |
| margin-top: 8px; font-style: italic; |
| } |
|
|
| /* SVG */ |
| svg { width: 100%; height: auto; display: block; } |
| .node-box { fill: var(--card); stroke: var(--ink); stroke-width: 1.5; } |
| .node-text { font-family: 'Inter', sans-serif; font-size: 14px; fill: var(--ink); } |
| .node-title { font-weight: 700; font-size: 15px; } |
| .node-sub { font-size: 11px; fill: var(--accent2); font-style: italic; } |
| .arrow { stroke: var(--ink); stroke-width: 1.8; fill: none; } |
| .arrow-label { font-size: 11px; fill: var(--accent2); font-family: ui-monospace, monospace; } |
| .dashed { stroke-dasharray: 6 4; } |
| .arrow-loop { stroke: var(--accent); stroke-width: 2.2; fill: none; } |
|
|
| /* Cards */ |
| .grid-2 { display: grid; grid-template-columns: 1fr; gap: 18px; margin-top: 16px; } |
| @media(min-width: 880px){ .grid-2 { grid-template-columns: 1fr 1fr; } } |
| .grid-3 { display: grid; grid-template-columns: 1fr; gap: 14px; margin-top: 14px; } |
| @media(min-width: 760px){ .grid-3 { grid-template-columns: repeat(3, 1fr); } } |
|
|
| .card { |
| background: var(--card); border: 1px solid var(--line); |
| border-radius: 10px; padding: 18px 20px; |
| } |
| .card.pick { border: 2px solid var(--accent); } |
| .pick-tag { |
| display: inline-block; background: var(--accent); color: white; |
| font-family: ui-monospace, monospace; font-size: 11px; |
| padding: 1px 7px; border-radius: 10px; margin-bottom: 6px; |
| } |
|
|
| table { |
| width: 100%; border-collapse: collapse; background: var(--card); |
| border: 1px solid var(--line); margin-top: 14px; font-size: 14px; |
| } |
| th, td { padding: 8px 10px; text-align: left; border-bottom: 1px solid var(--line); vertical-align: top; } |
| th { background: #efe4cb; font-size: 13px; letter-spacing: 0.5px; text-transform: uppercase; } |
| code { |
| background: #efe4cb; border-radius: 3px; padding: 1px 5px; font-size: 13px; |
| } |
|
|
| /* Forbidden zone */ |
| .forbidden { |
| background: var(--red-soft); border: 1px solid var(--red); |
| border-radius: 8px; padding: 14px 18px; margin-top: 14px; |
| } |
| .forbidden strong { color: var(--red); } |
| .forbidden ul { |
| columns: 2; column-gap: 28px; margin: 8px 0 0; padding-left: 18px; font-size: 14px; |
| } |
|
|
| /* Timeline */ |
| .timeline { position: relative; padding-left: 36px; margin-top: 20px; } |
| .timeline::before { |
| content: ""; position: absolute; left: 12px; top: 6px; bottom: 6px; |
| width: 3px; background: var(--accent); border-radius: 2px; |
| } |
| .day { |
| position: relative; margin-bottom: 14px; background: var(--card); |
| border: 1px solid var(--line); border-radius: 8px; padding: 12px 16px; |
| } |
| .day::before { |
| content: ""; position: absolute; left: -29px; top: 16px; |
| width: 13px; height: 13px; background: var(--accent); |
| border: 2px solid var(--card); border-radius: 50%; |
| } |
| .day .lbl { |
| display: inline-block; background: var(--accent); color: white; |
| font-family: ui-monospace, monospace; font-size: 11px; |
| padding: 1px 7px; border-radius: 10px; margin-right: 8px; |
| } |
| .day strong { font-size: 15px; } |
| .day .what { font-size: 13px; color: var(--accent2); margin-top: 2px; } |
|
|
| /* Award rows */ |
| .award-row { |
| display: flex; justify-content: space-between; |
| padding: 8px 12px; border-bottom: 1px solid var(--line); font-size: 14px; |
| } |
| .award-row:last-child { border-bottom: 0; } |
| .prob { |
| font-family: ui-monospace, monospace; font-size: 12px; |
| padding: 1px 8px; border-radius: 10px; color: white; |
| } |
| .prob-h { background: #2e7d32; } |
| .prob-m { background: #ef9c2c; } |
| .prob-l { background: #b03a2e; } |
|
|
| /* Badges grid */ |
| .badges-grid { |
| display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); |
| gap: 12px; margin-top: 14px; |
| } |
| .badge-card { |
| background: var(--card); border: 1px solid var(--line); |
| border-radius: 8px; padding: 12px 14px; |
| } |
| .badge-card.skip { opacity: 0.45; border-style: dashed; } |
| .badge-card .tag { |
| display: inline-block; background: var(--accent); color: white; |
| font-family: ui-monospace, monospace; font-size: 11px; |
| padding: 1px 7px; border-radius: 10px; margin-bottom: 6px; |
| } |
| .badge-card.skip .tag { background: var(--gray); } |
| .badge-card strong { font-size: 14px; } |
| .badge-card p { font-size: 13px; color: var(--accent2); margin: 4px 0 0; } |
|
|
| .footnote { |
| margin-top: 30px; padding: 14px 18px; |
| border-left: 4px solid var(--accent); |
| background: var(--card); font-size: 14px; border-radius: 4px; |
| } |
| </style> |
| <link rel="preconnect" href="https://fonts.googleapis.com"> |
| <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> |
| <link href="https://fonts.googleapis.com/css2?family=Lora:wght@400;600;700&family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet"> |
| </head> |
| <body> |
| <div class="wrap"> |
|
|
| <h1><em>Cocina Conmigo</em></h1> |
| <div class="subtitle">Sous-chef multimodal con visión, voz y Flux.2 — para cocinar con tu mamá sin tener las manos libres</div> |
|
|
| <div class="hero"> |
| <div> |
| <h2>La idea en una frase</h2> |
| <p>Tu mamá toma foto del refri, la app le propone qué cocinar, le <strong>muestra cómo se debe ver cada paso</strong> con Flux.2, y la <strong>narra por voz</strong> mientras ella cocina con las manos llenas.</p> |
| <p class="quote">"Mi mamá me pidió que le enseñara a hacer ramen. Le construí un sous-chef que vive en su tablet."</p> |
| <div style="margin-top: 14px;"> |
| <span class="pill flux">Flux.2 Klein 9B</span> |
| <span class="pill openbmb">MiniCPM-V + voice</span> |
| <span class="pill cohere">Cohere voice</span> |
| <span class="pill gradio">Gradio Workflows</span> |
| <span class="pill modal">Modal-powered</span> |
| <span class="pill llama">llama.cpp</span> |
| </div> |
| </div> |
| <div class="target"> |
| <strong>Track:</strong> Backyard AI<br/> |
| <strong>Persona:</strong> tu mamá / pareja / vecino<br/> |
| <strong>Idioma:</strong> español-mexicano<br/> |
| <strong>Total params:</strong> ~17B (≤ 32B ✓)<br/> |
| <strong>Cocina:</strong> mexicana tradicional<br/> |
| <strong>Storyline:</strong> "Para que mi mamá deje de googlear" |
| </div> |
| </div> |
|
|
|
|
| <h2><span class="num">01</span>Por qué esta idea, y no las anteriores</h2> |
| <table> |
| <thead><tr><th>Iteración</th><th>Idea</th><th>Por qué se descartó</th></tr></thead> |
| <tbody> |
| <tr><td>v1</td><td>Abuelita (parent phone helper)</td><td>En la lista pre-cocinada de OpenBMB → 5-15 equipos lo harán</td></tr> |
| <tr><td>v2</td><td>Cuentacuentos (voice storyteller)</td><td>También en la lista pre-cocinada de OpenBMB</td></tr> |
| <tr style="background:#fff3cf;"><td><strong>v3 (ésta)</strong></td><td><strong>Cocina Conmigo</strong></td><td>Refinamiento de tu idea #1 · NO está en ninguna lista pre-cocinada · usa Flux.2 + Workflows + voces · diaria + universal</td></tr> |
| </tbody> |
| </table> |
|
|
| <div class="forbidden"> |
| <strong>⛔ Las 12 ideas en zona prohibida (clúster OpenBMB):</strong> |
| <ul> |
| <li>parent phone helper</li> |
| <li>receipt / bill explainer</li> |
| <li>shop menu / repair manual</li> |
| <li>offline personal assistant / voice companion</li> |
| <li>voice storyteller</li> |
| <li>visual mystery box</li> |
| <li>AI museum (≈ tu idea #4)</li> |
| <li>doodle creature</li> |
| <li>dream postcard gen</li> |
| <li>omni-modal adventure</li> |
| <li>tiny local NPC / character agent</li> |
| <li>cortes de cabello (tu idea #3, ya saturada)</li> |
| </ul> |
| </div> |
|
|
|
|
| <h2><span class="num">02</span>Las 4 historias del demo</h2> |
| <div class="phone-row"> |
|
|
| <div> |
| <div class="phone"><div class="screen"> |
| <div class="topbar">📸 Tengo esto en el refri</div> |
| <div class="body"> |
| <div class="illu">🍅🌶🐔🧅</div> |
| <p><strong>Veo:</strong> pollo, jitomate, cebolla, cilantro, tortillas, queso.</p> |
| <p style="background:#fff3cf;border-radius:6px;padding:6px 10px;"> |
| <strong>3 opciones:</strong><br/> |
| 🌮 Tinga · 🌯 Enchiladas · 🧀 Quesadillas |
| </p> |
| <div class="voice">🔊 "¿Qué traes ganas?"</div> |
| </div> |
| </div></div> |
| <div class="scenario-label">1. Visión + Planner</div> |
| </div> |
|
|
| <div> |
| <div class="phone"><div class="screen"> |
| <div class="topbar">👩🍳 Paso 2 de 5</div> |
| <div class="body"> |
| <div class="illu">🍳✨</div> |
| <p><strong>Acitrona la cebolla en aceite caliente.</strong></p> |
| <p style="font-size:11px;color:var(--gray);">⏱ 4 minutos · hasta que esté transparente</p> |
| <div class="voice">🔊 OpenBMB voice narra…</div> |
| </div> |
| </div></div> |
| <div class="scenario-label">2. Voz + imagen objetivo</div> |
| </div> |
|
|
| <div> |
| <div class="phone"><div class="screen"> |
| <div class="topbar">📸 ¿Voy bien?</div> |
| <div class="body"> |
| <div class="illu">🍳👀</div> |
| <p style="background:var(--green-soft);border-radius:6px;padding:6px 10px;color:var(--green);"> |
| <strong>✅ Va perfecto.</strong> La cebolla ya se ve transparente. |
| </p> |
| <div class="tip">🔊 Cohere voice: "¡Súbele 1 minuto más, está bien!"</div> |
| </div> |
| </div></div> |
| <div class="scenario-label">3. Closed-loop visual</div> |
| </div> |
|
|
| <div> |
| <div class="phone"><div class="screen"> |
| <div class="topbar">🔄 Replan</div> |
| <div class="body"> |
| <p>Usuario: <em>"No tengo cilantro."</em></p> |
| <div class="illu" style="background: linear-gradient(135deg,#ffd28b,#a85c2a);">🌮</div> |
| <p>"No pasa nada. Le ponemos perejil o nada. Sigue siendo tinga."</p> |
| <div class="voice">🔊 Receta regenera · plato final actualizado</div> |
| </div> |
| </div></div> |
| <div class="scenario-label">4. Adaptación en vivo</div> |
| </div> |
|
|
| </div> |
|
|
|
|
| <h2><span class="num">03</span>Arquitectura — 5 agentes en un Gradio Workflow</h2> |
|
|
| <svg viewBox="0 0 1240 540" xmlns="http://www.w3.org/2000/svg"> |
| <defs> |
| <marker id="ar" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto"> |
| <path d="M0,0 L10,5 L0,10 z" fill="#2b2018"/> |
| </marker> |
| <marker id="aro" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto"> |
| <path d="M0,0 L10,5 L0,10 z" fill="#a85c2a"/> |
| </marker> |
| </defs> |
|
|
| |
| <rect x="20" y="40" width="200" height="240" rx="10" fill="#fff3cf" stroke="#d8c9ad" stroke-dasharray="4 3"/> |
| <text x="40" y="62" class="node-text node-title" fill="#6b4a2a">USUARIO (cocina)</text> |
|
|
| <rect class="node-box" x="40" y="80" width="160" height="50" rx="6" fill="#ddd1bd"/> |
| <text x="120" y="102" class="node-text node-title" text-anchor="middle">📸 Foto del refri</text> |
| <text x="120" y="118" class="node-text node-sub" text-anchor="middle">trigger inicial</text> |
|
|
| <rect class="node-box" x="40" y="140" width="160" height="50" rx="6" fill="#ddd1bd"/> |
| <text x="120" y="162" class="node-text node-title" text-anchor="middle">🎙️ Pregunta voz</text> |
| <text x="120" y="178" class="node-text node-sub" text-anchor="middle">"¿voy bien?"</text> |
|
|
| <rect class="node-box" x="40" y="200" width="160" height="50" rx="6" fill="#ddd1bd"/> |
| <text x="120" y="222" class="node-text node-title" text-anchor="middle">📸 Foto progreso</text> |
| <text x="120" y="238" class="node-text node-sub" text-anchor="middle">closed-loop</text> |
|
|
| |
| <rect x="20" y="320" width="200" height="180" rx="10" fill="#fff3cf" stroke="#d8c9ad" stroke-dasharray="4 3"/> |
| <text x="40" y="342" class="node-text node-title" fill="#6b4a2a">SALIDA</text> |
|
|
| <rect class="node-box" x="40" y="360" width="160" height="50" rx="6" fill="#dbe9d8"/> |
| <text x="120" y="382" class="node-text node-title" text-anchor="middle">🍽️ Plato final + receta</text> |
| <text x="120" y="398" class="node-text node-sub" text-anchor="middle">imagen + texto</text> |
|
|
| <rect class="node-box" x="40" y="420" width="160" height="50" rx="6" fill="#dbe9d8"/> |
| <text x="120" y="442" class="node-text node-title" text-anchor="middle">🔊 Voz por paso</text> |
| <text x="120" y="458" class="node-text node-sub" text-anchor="middle">narrador + tips</text> |
|
|
| |
| <rect x="260" y="40" width="700" height="460" rx="10" fill="#fffaf0" stroke="#d8c9ad" stroke-width="1.5"/> |
| <text x="610" y="62" class="node-text node-title" text-anchor="middle" fill="#6b4a2a">HF SPACE — Gradio Workflow (5 agentes)</text> |
|
|
| |
| <rect class="node-box" x="280" y="90" width="200" height="80" rx="6" fill="#e6d5ed"/> |
| <text x="380" y="110" class="node-text node-title" text-anchor="middle">👁️ MISE EN PLACE</text> |
| <text x="380" y="126" class="node-text node-sub" text-anchor="middle">MiniCPM-V (Q4)</text> |
| <text x="380" y="142" class="node-text node-sub" text-anchor="middle">~2-4B</text> |
| <text x="380" y="160" class="node-text node-sub" text-anchor="middle">identifica ingredientes</text> |
|
|
| |
| <rect class="node-box" x="510" y="90" width="200" height="80" rx="6" fill="#fbe4d3"/> |
| <text x="610" y="110" class="node-text node-title" text-anchor="middle">🧠 RECIPE PLANNER</text> |
| <text x="610" y="126" class="node-text node-sub" text-anchor="middle">MiniCPM-4 (LoRA mx)</text> |
| <text x="610" y="142" class="node-text node-sub" text-anchor="middle">~4B</text> |
| <text x="610" y="160" class="node-text node-sub" text-anchor="middle">arma receta JSON · replan</text> |
|
|
| |
| <rect class="node-box" x="740" y="90" width="200" height="80" rx="6" fill="#f6dccc"/> |
| <text x="840" y="110" class="node-text node-title" text-anchor="middle">🎨 STEP ILLUSTRATOR</text> |
| <text x="840" y="126" class="node-text node-sub" text-anchor="middle">Flux.2 Klein 9B</text> |
| <text x="840" y="142" class="node-text node-sub" text-anchor="middle">en Modal GPU L4</text> |
| <text x="840" y="160" class="node-text node-sub" text-anchor="middle">imagen-objetivo por paso</text> |
|
|
| |
| <rect class="node-box" x="510" y="200" width="200" height="70" rx="6" fill="#cfe0ee"/> |
| <text x="610" y="222" class="node-text node-title" text-anchor="middle">🔊 SOUS-CHEF NARRATOR</text> |
| <text x="610" y="238" class="node-text node-sub" text-anchor="middle">OpenBMB voice (~1B)</text> |
| <text x="610" y="254" class="node-text node-sub" text-anchor="middle">tono cálido</text> |
|
|
| |
| <rect class="node-box" x="740" y="200" width="200" height="70" rx="6" fill="#e9d6f5"/> |
| <text x="840" y="222" class="node-text node-title" text-anchor="middle">🎭 TIP GIVER</text> |
| <text x="840" y="238" class="node-text node-sub" text-anchor="middle">Cohere voice (~1B)</text> |
| <text x="840" y="254" class="node-text node-sub" text-anchor="middle">warnings · enérgico</text> |
|
|
| |
| <rect class="node-box" x="280" y="290" width="220" height="90" rx="6" fill="#dbe9d8" stroke="#3f7a3a" stroke-width="2"/> |
| <text x="390" y="312" class="node-text node-title" text-anchor="middle" fill="#3f7a3a">✅ PROGRESS VALIDATOR</text> |
| <text x="390" y="328" class="node-text node-sub" text-anchor="middle">MiniCPM-V (reuso)</text> |
| <text x="390" y="344" class="node-text node-sub" text-anchor="middle">compara foto usuario vs</text> |
| <text x="390" y="360" class="node-text node-sub" text-anchor="middle">imagen-objetivo</text> |
| <text x="390" y="376" class="node-text node-sub" text-anchor="middle">CLOSED LOOP 🔄</text> |
|
|
| |
| <rect class="node-box" x="280" y="200" width="200" height="70" rx="6" fill="#cfe0ee"/> |
| <text x="380" y="222" class="node-text node-title" text-anchor="middle">🎙️ STT (opcional)</text> |
| <text x="380" y="238" class="node-text node-sub" text-anchor="middle">Whisper-tiny (~40M)</text> |
| <text x="380" y="254" class="node-text node-sub" text-anchor="middle">"¿voy bien?" hands-free</text> |
|
|
| |
| <rect class="node-box" x="510" y="290" width="430" height="90" rx="6" fill="#fff3cf"/> |
| <text x="725" y="312" class="node-text node-title" text-anchor="middle" fill="#8a6a18">📖 RECIPE STATE (dataclass)</text> |
| <text x="725" y="328" class="node-text node-sub" text-anchor="middle">name · final_dish_image · steps · current_step ·</text> |
| <text x="725" y="344" class="node-text node-sub" text-anchor="middle">missing_ingredients · substitutes · user_progress_photos</text> |
| <text x="725" y="362" class="node-text node-sub" text-anchor="middle">cada agente lee y escribe sobre este objeto</text> |
|
|
| |
| <rect class="node-box" x="280" y="400" width="660" height="60" rx="6" fill="#f6dccc"/> |
| <text x="610" y="422" class="node-text node-title" text-anchor="middle">📖 RECIPE CARD ASSEMBLER</text> |
| <text x="610" y="438" class="node-text node-sub" text-anchor="middle">renderiza la tarjeta de receta + cards por paso + audio reproducible</text> |
|
|
| |
| <rect x="990" y="40" width="240" height="460" rx="10" fill="#dbe9d8" stroke="#3f7a3a" stroke-width="1.5"/> |
| <text x="1110" y="62" class="node-text node-title" text-anchor="middle" fill="#3f7a3a">MODAL</text> |
|
|
| <rect class="node-box" x="1010" y="90" width="200" height="80" rx="6" fill="#fff"/> |
| <text x="1110" y="112" class="node-text node-title" text-anchor="middle">Flux endpoint</text> |
| <text x="1110" y="128" class="node-text node-sub" text-anchor="middle">runtime · @app.cls L4</text> |
| <text x="1110" y="144" class="node-text node-sub" text-anchor="middle">scaledown 180s</text> |
| <text x="1110" y="160" class="node-text node-sub" text-anchor="middle">~1-3s/imagen</text> |
|
|
| <rect class="node-box" x="1010" y="190" width="200" height="80" rx="6" fill="#fff"/> |
| <text x="1110" y="212" class="node-text node-title" text-anchor="middle">Dataset cocina mx</text> |
| <text x="1110" y="228" class="node-text node-sub" text-anchor="middle">offline · 200 recetas</text> |
| <text x="1110" y="244" class="node-text node-sub" text-anchor="middle">Codex API genera</text> |
| <text x="1110" y="260" class="node-text node-sub" text-anchor="middle">~$5</text> |
|
|
| <rect class="node-box" x="1010" y="290" width="200" height="80" rx="6" fill="#fff"/> |
| <text x="1110" y="312" class="node-text node-title" text-anchor="middle">LoRA Planner</text> |
| <text x="1110" y="328" class="node-text node-sub" text-anchor="middle">offline · A10G ~30 min</text> |
| <text x="1110" y="344" class="node-text node-sub" text-anchor="middle">push GGUF a HF</text> |
| <text x="1110" y="360" class="node-text node-sub" text-anchor="middle">~$1</text> |
|
|
| <rect class="node-box" x="1010" y="390" width="200" height="80" rx="6" fill="#fff"/> |
| <text x="1110" y="412" class="node-text node-title" text-anchor="middle">Eval pipeline</text> |
| <text x="1110" y="428" class="node-text node-sub" text-anchor="middle">consistencia visual</text> |
| <text x="1110" y="444" class="node-text node-sub" text-anchor="middle">% ingredientes correctos</text> |
| <text x="1110" y="460" class="node-text node-sub" text-anchor="middle">~$1</text> |
|
|
| |
| <path class="arrow" d="M200 105 L278 130" marker-end="url(#ar)"/> |
| <text x="200" y="100" class="arrow-label">refri</text> |
|
|
| |
| <path class="arrow" d="M200 165 L278 235" marker-end="url(#ar)"/> |
| <text x="205" y="200" class="arrow-label">audio</text> |
|
|
| |
| <path class="arrow arrow-loop" d="M200 225 L278 330" marker-end="url(#aro)"/> |
| <text x="200" y="270" class="arrow-label" style="fill:#a85c2a;">progreso</text> |
|
|
| |
| <path class="arrow" d="M480 130 L508 130" marker-end="url(#ar)"/> |
| <text x="482" y="120" class="arrow-label">ingredientes</text> |
|
|
| |
| <path class="arrow" d="M710 130 L738 130" marker-end="url(#ar)"/> |
| <text x="712" y="120" class="arrow-label">visual prompt</text> |
|
|
| |
| <path class="arrow dashed" d="M940 130 L1008 130" marker-end="url(#ar)"/> |
| <text x="945" y="120" class="arrow-label">.remote()</text> |
|
|
| |
| <path class="arrow" d="M610 170 L610 198" marker-end="url(#ar)"/> |
| |
| <path class="arrow" d="M710 145 C 760 170, 800 180, 800 198" marker-end="url(#ar)"/> |
|
|
| |
| <path class="arrow arrow-loop" d="M390 290 C 390 240, 470 190, 510 145" marker-end="url(#aro)"/> |
| <text x="395" y="240" class="arrow-label" style="fill:#a85c2a;">verdict · feedback</text> |
|
|
| |
| <path class="arrow dashed" d="M380 270 L380 288" marker-end="url(#ar)"/> |
|
|
| |
| <path class="arrow dashed" d="M725 290 L725 270" marker-end="url(#ar)"/> |
| <path class="arrow dashed" d="M610 290 L610 270" marker-end="url(#ar)"/> |
|
|
| |
| <path class="arrow" d="M610 380 L610 398" marker-end="url(#ar)"/> |
|
|
| |
| <path class="arrow" d="M280 425 C 240 425, 220 410, 200 385" marker-end="url(#ar)"/> |
| <path class="arrow" d="M280 440 C 240 440, 220 445, 200 445" marker-end="url(#ar)"/> |
|
|
| |
| <path class="arrow dashed" d="M1010 330 C 870 330, 750 280, 710 165" marker-end="url(#ar)"/> |
| <text x="900" y="280" class="arrow-label">LoRA pesos</text> |
| </svg> |
| <p style="font-size: 13px; color: var(--accent2); margin-top: 10px;"> |
| <strong>Flecha naranja</strong> = closed-loop visual (la innovación). El usuario toma foto del progreso, MiniCPM-V valida vs imagen-objetivo, el Planner ajusta o avanza. Ningún recipe app del mercado lo hace. |
| </p> |
|
|
|
|
| <h2><span class="num">04</span>El truco innovador: closed-loop visual cocinero</h2> |
| <div class="grid-3"> |
| <div class="card"> |
| <h3>1. Imagen-objetivo por paso</h3> |
| <p style="font-size:13px;">Flux.2 genera "así debe verse el sartén/plato/olla en el paso N". No es texto, no es stock photo: es generación context-aware del estado deseado.</p> |
| </div> |
| <div class="card"> |
| <h3>2. Validación con foto del usuario</h3> |
| <p style="font-size:13px;">El usuario sube foto de cómo va. MiniCPM-V compara contra la imagen-objetivo y devuelve verdict: <code>go</code> · <code>wait</code> · <code>fix</code>.</p> |
| </div> |
| <div class="card"> |
| <h3>3. Replan adaptativo</h3> |
| <p style="font-size:13px;">"No tengo cilantro." → Planner regenera receta + Flux regenera imagen final. El plan no es estático, evoluciona con el estado real.</p> |
| </div> |
| </div> |
| <p style="margin-top:14px; font-size:14px;"> |
| <strong>Esta es la sección destacada del README</strong> y el blog post de Field Notes badge: <em>"How visual closed-loop cooking guidance works."</em> |
| </p> |
|
|
|
|
| <h2><span class="num">05</span>Badges objetivo (5/6)</h2> |
| <div class="badges-grid"> |
| <div class="badge-card"><span class="tag">LLAMA.CPP</span><br/><strong>Llama Champion</strong><p>Vision + Planner via <code>llama-cpp-python</code> con GGUF Q4.</p></div> |
| <div class="badge-card"><span class="tag">FINE-TUNED</span><br/><strong>Well-Tuned</strong><p>LoRA en cocina mexicana · publicado en HF.</p></div> |
| <div class="badge-card"><span class="tag">CUSTOM UI</span><br/><strong>Off-Brand</strong><p>UI tarjeta de receta · serif · paleta cálida · modo cocina XL.</p></div> |
| <div class="badge-card"><span class="tag">OPEN TRACE</span><br/><strong>Sharing is Caring</strong><p>Dataset 150 recetas mx + traces + recetas generadas al Hub.</p></div> |
| <div class="badge-card"><span class="tag">TENTATIVE</span><br/><strong>Field Notes</strong><p>Blog: "Le construí un sous-chef a mi mamá".</p></div> |
| <div class="badge-card skip"><span class="tag">LOCAL-FIRST</span><br/><strong>Off the Grid</strong><p>Sacrificado: Flux.2 corre en Modal por calidad.</p></div> |
| </div> |
|
|
|
|
| <h2><span class="num">06</span>Premios objetivo</h2> |
| <div class="card"> |
| <div class="award-row"><span><strong>Backyard AI Track</strong> · $1K–$4K</span><span class="prob prob-h">ALTA</span></div> |
| <div class="award-row"><span><strong>Modal Awards</strong> · $3K–$10K credits</span><span class="prob prob-h">ALTA</span></div> |
| <div class="award-row"><span><strong>OpenBMB Award</strong> · $1K–$2.5K</span><span class="prob prob-h">ALTA</span></div> |
| <div class="award-row"><span><strong>Best Demo</strong> · $1K</span><span class="prob prob-h">ALTA</span></div> |
| <div class="award-row"><span><strong>Community Choice</strong> · $2K</span><span class="prob prob-h">ALTA</span></div> |
| <div class="award-row"><span><strong>Best Agent</strong> · $1K</span><span class="prob prob-h">ALTA — closed-loop multi-agente real</span></div> |
| <div class="award-row"><span><strong>Bonus Quest Champion</strong> · $2K</span><span class="prob prob-m">MEDIA-ALTA · 5/6 badges</span></div> |
| <div class="award-row"><span><strong>Off-Brand</strong> · $1.5K</span><span class="prob prob-m">MEDIA</span></div> |
| <div class="award-row"><span><strong>Tiny Titan</strong> · $1.5K</span><span class="prob prob-l">BAJA · Flux 9B saca del rango</span></div> |
| </div> |
| <p style="font-size: 14px; margin-top: 8px;"><strong>Cota razonable acumulada: $5K–$12K cash + $3K–$10K Modal credits.</strong></p> |
|
|
|
|
| <h2><span class="num">07</span>Timeline de 10 días</h2> |
| <div class="timeline"> |
| <div class="day"><span class="lbl">D1</span><strong>Setup + Modal Flux endpoint</strong><div class="what">"Hola Flux": prompt → imagen de un platillo. Space vacío deployado.</div></div> |
| <div class="day"><span class="lbl">D2</span><strong>Vision: identificación de ingredientes</strong><div class="what">MiniCPM-V Q4 · prueba con 5 fotos reales del refri.</div></div> |
| <div class="day"><span class="lbl">D3</span><strong>Recipe Planner LLM</strong><div class="what">MiniCPM-4 · JSON estructurado · 3 opciones a partir de ingredientes.</div></div> |
| <div class="day"><span class="lbl">D4</span><strong>Step Illustrator (Flux + consistencia)</strong><div class="what">Imagen del plato final + 5 imágenes-objetivo por paso · i2i suave.</div></div> |
| <div class="day"><span class="lbl">D5</span><strong>Voz: narrador + tip-giver</strong><div class="what">OpenBMB voice + Cohere voice · audio pre-renderizado por paso.</div></div> |
| <div class="day"><span class="lbl">D6</span><strong>UI Off-Brand: recipe card</strong><div class="what">gr.Blocks + CSS serif tierra · modo cocina XL hands-free.</div></div> |
| <div class="day"><span class="lbl">D7</span><strong>Gradio Workflows showcase</strong><div class="what">Pipeline reescrita como Workflow visible · pestaña separada.</div></div> |
| <div class="day"><span class="lbl">D8</span><strong>Fine-tune del Planner en cocina mx</strong><div class="what">200 recetas sintéticas · LoRA · GGUF · push HF.</div></div> |
| <div class="day"><span class="lbl">D9</span><strong>STT + Progress Validator + eval</strong><div class="what">Whisper · closed-loop activo · Sharing is Caring badge.</div></div> |
| <div class="day"><span class="lbl">D10</span><strong>Demo + README + blog + submit</strong><div class="what">Mamá real cocinando · 60-90s · subtítulos EN · Field Notes blog.</div></div> |
| </div> |
|
|
|
|
| <h2><span class="num">08</span>Plan B (corte de scope)</h2> |
| <table> |
| <thead><tr><th>#</th><th>Cortar</th><th>Pierdes</th><th>Conservas</th></tr></thead> |
| <tbody> |
| <tr><td>1</td><td>STT (preguntas voz)</td><td>comodidad demo</td><td>texto + foto</td></tr> |
| <tr><td>2</td><td>2da voz (Cohere tip-giver)</td><td>1 sponsor voice</td><td>narrador único</td></tr> |
| <tr><td>3</td><td>Progress Validator (closed-loop)</td><td><strong>Best Agent</strong> + innovación principal</td><td>demo lineal</td></tr> |
| <tr><td>4</td><td>Fine-tune del Planner</td><td><strong>Well-Tuned</strong></td><td>resto badges</td></tr> |
| <tr><td>5</td><td>Gradio Workflows showcase</td><td>diferenciador "fresh"</td><td>pipeline Python</td></tr> |
| <tr><td>6</td><td>UI super-custom</td><td><strong>Off-Brand</strong></td><td>UI default</td></tr> |
| <tr style="background:#fff3cf;"><td>—</td><td><strong>NUNCA</strong></td><td colspan="2">Vision + Planner + Illustrator + Narrator + UI mínima + video con persona real cocinando</td></tr> |
| </tbody> |
| </table> |
|
|
|
|
| <h2><span class="num">09</span>Riesgos clave</h2> |
| <table> |
| <thead><tr><th>Riesgo</th><th>Mitigación</th></tr></thead> |
| <tbody> |
| <tr><td>Flux.2 Klein no tiene API/pesos públicos cuando lo necesitas</td><td>Plan B: Flux.1-schnell o SDXL-Lightning. Pierdes posicionamiento sponsor pero idea sobrevive.</td></tr> |
| <tr><td>MiniCPM-V no identifica ingredientes mexicanos (chile poblano, nopales)</td><td>Few-shot en prompt; eventualmente fine-tune ligero del visión sobre 50 fotos etiquetadas</td></tr> |
| <tr><td>Flux.2 genera comida poco apetitosa</td><td>Itera prompts ("recipe magazine, warm light, top-down"); usa imagen final como ref para los pasos</td></tr> |
| <tr><td>Progress Validator da false positives</td><td>Conservador: solo dice "vas bien" si similitud es alta; default es "sigue" sin juicio fuerte</td></tr> |
| <tr><td>Latencia receta > 30s</td><td>Streaming progresivo; paraleliza Flux + TTS</td></tr> |
| <tr><td>Modal cold start ~30-60s en Flux</td><td>Pre-warm 30s antes de filmar · <code>keep_warm=1</code> el día del demo</td></tr> |
| <tr><td>Persona del demo se quema/cocina mal</td><td>Practica la receta una vez antes · 2-3 candidatos de receta listos</td></tr> |
| <tr><td>Otro equipo presenta "recipe app con AI"</td><td>Diferéncialo con: closed-loop visual + español + cocina mx + dataset publicado + persona real</td></tr> |
| </tbody> |
| </table> |
|
|
|
|
| <h2><span class="num">10</span>Cómo gastar los créditos</h2> |
| <div class="grid-2"> |
| <div class="card"> |
| <h3>Modal · $250</h3> |
| <table> |
| <tr><td>Flux dev (días 1-9)</td><td>$5-15</td></tr> |
| <tr><td>Dataset cocina mx</td><td>$3-8</td></tr> |
| <tr><td>LoRA + sweeps</td><td>$4-5</td></tr> |
| <tr><td>Eval</td><td>$1</td></tr> |
| <tr><td>Inferencia grading jueces</td><td>$10-25</td></tr> |
| <tr><th>Subtotal</th><th>$25-65</th></tr> |
| <tr><th>+ Buffer</th><th>$30</th></tr> |
| <tr><th>Proyectado</th><th><strong>~$55-95 / $250</strong></th></tr> |
| </table> |
| </div> |
| <div class="card"> |
| <h3>OpenAI Codex · $100</h3> |
| <table> |
| <tr><td>Codex CLI pair-programmer</td><td>$20-40</td></tr> |
| <tr><td>200 recetas mx sintéticas</td><td>$10-25</td></tr> |
| <tr><td>Prompts Flux por paso</td><td>$5-10</td></tr> |
| <tr><td>Reserva</td><td>$30</td></tr> |
| <tr><th>Proyectado</th><th><strong>~$65-105 / $100</strong></th></tr> |
| </table> |
| </div> |
| </div> |
|
|
|
|
| <div class="footnote"> |
| <strong>Mantra del proyecto:</strong> "Una mamá cocinando frente a la cámara. Un platillo que se ve apetitoso. Una voz que la acompaña sin juzgar. Un paso a la vez." |
| </div> |
|
|
| </div> |
| </body> |
| </html> |
|
|