Spaces:
Running
Running
| """ | |
| Tombstone — Write What You Want. Find Out What It Takes. Compare Where You Are. | |
| Confusion will be my epitaph. | |
| """ | |
| import gradio as gr | |
| import os | |
| import random | |
| from huggingface_hub import InferenceClient | |
| HF_TOKEN = os.environ.get("HF_TOKEN", "") | |
| MODEL = "Qwen/Qwen2.5-7B-Instruct" | |
| client = InferenceClient(model=MODEL, token=HF_TOKEN) if HF_TOKEN else None | |
| EPITAPH_PROMPT = """Someone writes what they want on their tombstone — the sentence they'd leave behind. Your job is to reverse-engineer the life that earns that epitaph. What does a person have to actually DO to deserve those words on their stone? | |
| Rules: | |
| - 5 to 7 sentences. | |
| - Take their epitaph seriously, even if it's funny. There's truth in humor. | |
| - Show what kind of person actually earns that line. What do they do daily? What do they sacrifice? What do they say no to? | |
| - Include one thing they'd have to give up that they probably don't want to give up. | |
| - Include one thing they'd need to start doing this week, not someday. | |
| - Be direct. Be warm. Don't be preachy. | |
| - The tone is: "you wrote the ending. Here's the middle part." | |
| - Talk like a friend who takes you seriously when you say something you meant as a joke.""" | |
| COMPARE_PROMPT = """Someone wrote what they want on their tombstone, and now they're telling you how they actually spend their days. Your job is to show the gap — honestly but without cruelty. | |
| The epitaph they want: {epitaph} | |
| How they actually spend their days: {routine} | |
| Rules: | |
| - 5 to 7 sentences. | |
| - Show where their current path is pointed vs where the epitaph needs it pointed. Be specific. | |
| - Find the one thing in their routine that IS actually carving toward the epitaph — there's almost always something. | |
| - Find the one thing that's carving in the opposite direction — the thing they'd need to change first. | |
| - Don't moralize. Don't say "you should." Just show the distance between where the chisel is pointed and where the stone needs it. | |
| - End with whether the gap is closable or whether they need a different chisel entirely. | |
| - Be honest. Be warm. Some gaps are small. Some are canyons. Say which.""" | |
| EPITAPHS = [ | |
| "She was kind", | |
| "He tried his best", | |
| "She left it better than she found it", | |
| "He never stopped laughing", | |
| "She wasn't afraid", | |
| "He showed up", | |
| "The wifi password is on the fridge", | |
| "She made everyone feel welcome", | |
| "He built things that lasted", | |
| "She told the truth", | |
| "I told you I was sick", | |
| "He cooked for everyone", | |
| "She never stopped learning", | |
| "He was a good dad", | |
| "Finally got some rest", | |
| "She did it her way", | |
| ] | |
| EPITAPH_FALLBACKS = [ | |
| "**\"She was kind\"**\n\nTwo words. Hardest epitaph to earn on this list. Kindness isn't niceness — niceness is a performance, kindness is a practice. The person who earns this line is kind when they're tired, kind when they're angry, kind when nobody's going to thank them for it. That means biting your tongue in the argument you could win. It means checking on the person you don't like. The thing you'd have to give up: being right out loud. The thing to start this week: the next time someone irritates you, ask yourself what their day looked like before they got to you.", | |
| "**\"He tried\"**\n\nTwo words and a period. Not 'he succeeded.' Not 'he won.' He tried. The person who earns this didn't need the outcome to justify the effort. They showed up to things that might not work and did them anyway. That means sending the email that might get ignored. Starting the business that might fail. Having the conversation that might end the relationship. 'He tried' sounds like a consolation prize but it's actually the only honest epitaph on the list. Everyone else is claiming results. You're claiming the attempt. The thing you'd give up: the safety of never starting. Start this week: the thing you've been putting off because you might fail at it. Try it. That's the whole tombstone.", | |
| "**\"He tried his best\"**\n\nThis sounds humble but it's actually the bravest thing on the list. The person who earns this line failed constantly — and everyone saw. 'Tried his best' means there were visible attempts, public mistakes, and enough self-respect to keep going anyway. That means starting things you might not finish. It means being the person who volunteers when nobody else will and sometimes doing it badly. The thing you'd have to give up: looking cool. Trying your best and looking effortless are opposites. Start this week: do one thing you've been avoiding because you might not be good at it.", | |
| "**\"She left it better than she found it\"**\n\nThis one requires you to pay attention to what 'it' means every single day. The room you just left. The conversation you just had. The person you just talked to. Did you leave each one slightly better? Not fixed. Not saved. Just better. The person who earns this notices the small things — picks up the trash that isn't theirs, says the thing that needed saying, stays five minutes longer than they have to. The thing you'd give up: efficiency. Leaving things better is slower than leaving them as-is. Start this week: leave one room better than you found it. Literally. Every day.", | |
| "**\"He showed up\"**\n\nTwo words that sound simple and aren't. Showing up means being there when it's inconvenient, uncomfortable, and unrewarded. The funeral on a Tuesday. The friend's move on a Saturday. The conversation you don't want to have. The person who earns this isn't the most talented or the most impressive. They're the one who's there. Every time. The thing you'd give up: the exit strategy. Showing up means you can't keep one foot out the door. Start this week: the next time someone needs you and it's not convenient, go anyway.", | |
| "**\"The wifi password is on the fridge\"**\n\nYou wrote a joke but here's what it actually takes: being the kind of person whose house other people want to be in. The wifi password on the fridge means an open door, a full kitchen, a place where people feel comfortable enough to stay and get online. That's not about the internet. That's about building a life that's warm enough that people show up uninvited and you're glad they did. The thing you'd give up: privacy on your own terms. An open house means an open life. Start this week: invite someone over who hasn't been over in a while.", | |
| "**\"She told the truth\"**\n\nThis epitaph gets people fired, dumped, and disinvited. Truth-telling isn't a personality trait. It's a cost you pay over and over. The person who earns this doesn't tell the truth because they're brave. They tell it because lying feels worse than the consequences. That means telling your boss the project won't work. Telling your friend their partner is bad for them. Telling yourself the thing you don't want to hear. The thing you'd give up: comfort. Truth-tellers live with friction. Start this week: say one thing you've been holding back. Not cruelly. Just honestly.", | |
| "**\"He was a good dad\"**\n\nFour words and a lifetime of Tuesdays. A good dad isn't the one at the big moments — the games, the graduations. It's the one at the invisible moments. The drives to school where nothing was said. The homework help where you didn't know the answer. The bedtime when you were too tired but you stayed. The thing you'd give up: being the interesting one. Good dads are often boring to everyone except the kid who needed them at 7am on a Wednesday. Start this week: one moment where you're fully there — phone down, eyes up, just present.", | |
| ] | |
| COMPARE_FALLBACKS = [ | |
| "**The gap:**\n\nYour epitaph needs consistency — the kind that shows up in small moments every day. Your routine has consistency too, but it's pointed at maintenance, not meaning. The good news: the distance between 'getting through the day' and 'earning the stone' is usually one decision per day, not a whole new life. The question is whether you're willing to make that one decision when you're tired. Because you'll always be tired. The chisel doesn't wait until you're ready.", | |
| "**The gap:**\n\nThere's something in your daily routine that's already carving toward what you want — you probably don't give yourself credit for it because it feels small. But the epitaph you wrote is made of small things, not big ones. The part that's working against you is the autopilot — the hours where you're present but not really there. The gap isn't about doing more. It's about being awake for what you're already doing. The chisel is in your hand. You're just not always looking at the stone.", | |
| ] | |
| def find_epitaph_fallback(epitaph): | |
| if epitaph: | |
| ep_lower = epitaph.lower().strip() | |
| for fb in EPITAPH_FALLBACKS: | |
| # Get the text between the quotes in the bold header | |
| try: | |
| fb_topic = fb.split("\"")[1].lower() | |
| if ep_lower == fb_topic or ep_lower in fb_topic and len(ep_lower) > 5: | |
| return fb | |
| except (IndexError, ValueError): | |
| continue | |
| return random.choice(EPITAPH_FALLBACKS) | |
| def step_one(epitaph_input): | |
| epitaph = epitaph_input.strip() if epitaph_input and epitaph_input.strip() else "" | |
| if client and epitaph: | |
| try: | |
| response = client.chat_completion( | |
| messages=[ | |
| {"role": "system", "content": EPITAPH_PROMPT}, | |
| {"role": "user", "content": f"Their tombstone reads: {epitaph}"}, | |
| ], | |
| max_tokens=500, | |
| temperature=0.8, | |
| ) | |
| result = response.choices[0].message.content | |
| if result and result.strip(): | |
| return f"**\"{epitaph}\"**\n\n{result.strip()}", epitaph | |
| except Exception: | |
| pass | |
| if epitaph: | |
| matched = find_epitaph_fallback(epitaph) | |
| # Check if the match actually contains the user's epitaph | |
| if epitaph.lower()[:10] in matched.lower(): | |
| return matched, epitaph | |
| # No match — use generic response with THEIR words | |
| generic = f"**\"{epitaph}\"**\n\nThat's a specific stone to carve. The person who earns those words lives them daily, not just at the highlights. Every epitaph has a cost — the question is what you'd trade to get those words on the rock. The version of you that earns \"{epitaph}\" makes different choices than the version of you right now. Not bigger choices. Different ones. The gap between who you are and who that tombstone describes is measured in daily decisions, not grand gestures. The thing to figure out: what's one decision you'd make differently tomorrow if those words were already carved and you had to live up to them?" | |
| return generic, epitaph | |
| return random.choice(EPITAPH_FALLBACKS), "" | |
| def step_two(routine_input, epitaph_state): | |
| routine = routine_input.strip() if routine_input and routine_input.strip() else "" | |
| epitaph = epitaph_state if epitaph_state else "something meaningful" | |
| if client and routine: | |
| try: | |
| prompt = COMPARE_PROMPT.format(epitaph=epitaph, routine=routine) | |
| response = client.chat_completion( | |
| messages=[ | |
| {"role": "system", "content": prompt}, | |
| {"role": "user", "content": f"Compare my path to my epitaph."}, | |
| ], | |
| max_tokens=500, | |
| temperature=0.8, | |
| ) | |
| result = response.choices[0].message.content | |
| if result and result.strip(): | |
| return f"**Your epitaph:** \"{epitaph}\"\n**Your days:** {routine}\n\n---\n\n{result.strip()}" | |
| except Exception: | |
| pass | |
| return random.choice(COMPARE_FALLBACKS) | |
| def step_one_random(): | |
| return step_one("") | |
| CUSTOM_CSS = """ | |
| @import url('https://fonts.googleapis.com/css2?family=Space+Mono:wght@400;700&family=Inter:wght@300;400;500;600&display=swap'); | |
| body, .gradio-container { | |
| background: #f5f5f5 !important; | |
| font-family: 'Inter', sans-serif !important; | |
| color: #1a1a2e !important; | |
| } | |
| footer { display: none !important; } | |
| .app-header { text-align: center; padding: 28px 20px 8px; } | |
| .app-header h1 { | |
| font-family: 'Space Mono', monospace; font-size: 2.4rem; font-weight: 700; | |
| background: linear-gradient(135deg, #505060, #808090); | |
| -webkit-background-clip: text; -webkit-text-fill-color: transparent; margin: 0; | |
| } | |
| .app-header .sub { color: #777; font-size: 0.88rem; margin-top: 6px; font-weight: 300; letter-spacing: 0.04em; } | |
| .app-visual { text-align: center; font-size: 5rem; padding: 12px 0 4px; } | |
| .input-box textarea { background: #fff !important; border: 1px solid #d0d0d8 !important; color: #1a1a2e !important; font-family: 'Inter', sans-serif !important; border-radius: 12px !important; font-size: 0.95rem !important; } | |
| .input-box textarea::placeholder { color: #888 !important; } | |
| .input-box textarea:focus { border-color: #606070 !important; box-shadow: 0 0 20px rgba(96, 96, 112, 0.15) !important; } | |
| .input-box label, .output-box label, label { color: #666 !important; font-family: 'Space Mono', monospace !important; font-size: 0.75rem !important; letter-spacing: 0.05em !important; } | |
| button.primary { background: linear-gradient(135deg, #606070, #505060) !important; border: none !important; color: #fff !important; font-family: 'Space Mono', monospace !important; font-size: 1.1rem !important; font-weight: 700 !important; border-radius: 24px !important; padding: 12px 40px !important; box-shadow: 0 4px 20px rgba(96, 96, 112, 0.3) !important; } | |
| button.primary:hover { box-shadow: 0 4px 30px rgba(96, 96, 112, 0.5) !important; } | |
| button.secondary { background: transparent !important; border: 1px solid rgba(96, 96, 112, 0.3) !important; color: #606070 !important; font-family: 'Space Mono', monospace !important; font-size: 0.8rem !important; border-radius: 20px !important; } | |
| button.secondary:hover { background: rgba(96, 96, 112, 0.06) !important; } | |
| .output-box .prose, .output-box .prose *, .output-box .md, .output-box .md *, | |
| .output-box p, .output-box span, .output-box div { | |
| color: #1a1a2e !important; | |
| background: #fff !important; | |
| } | |
| .output-box .prose strong, .output-box strong, .output-box .md strong { | |
| color: #505060 !important; | |
| font-family: 'Space Mono', monospace !important; | |
| } | |
| .output-box > div { | |
| border: 1px solid rgba(96, 96, 112, 0.15) !important; | |
| border-radius: 12px !important; | |
| padding: 24px !important; | |
| background: #fff !important; | |
| } | |
| .step-label { font-family: 'Space Mono', monospace !important; font-size: 0.7rem !important; color: #999 !important; letter-spacing: 0.1em; text-transform: uppercase; margin-top: 16px; } | |
| .output-box .block { border: none !important; border-style: none !important; overflow: visible !important; box-shadow: none !important; padding: 0 !important; } | |
| .output-box .hide-container { border: none !important; border-style: none !important; } | |
| .output-box .wrap.hide { display: none !important; } | |
| .output-box .label-wrap { display: none !important; } | |
| .output-box span.prose, .output-box span.md { border: none !important; padding: 0 !important; display: inline !important; } | |
| .output-box .prose:empty, .output-box div.prose:has(span:empty) { border: none !important; padding: 0 !important; min-height: 0 !important; } | |
| .footer-text { text-align: center; padding: 20px; color: #777; font-size: 0.65rem; font-weight: 300; letter-spacing: 0.05em; } | |
| .footer-text a { color: #606070; text-decoration: none; } | |
| """ | |
| with gr.Blocks(css=CUSTOM_CSS, title="Tombstone", theme=gr.themes.Base()) as demo: | |
| gr.HTML(""" | |
| <div class="app-header"> | |
| <h1>Tombstone</h1> | |
| <div class="sub">What do you want written on yours?</div> | |
| </div> | |
| """) | |
| epitaph_state = gr.State("") | |
| # STEP 1 | |
| gr.HTML('<div class="step-label">Step 1 — Write the ending</div>') | |
| with gr.Column(elem_classes="input-box"): | |
| epitaph_input = gr.Textbox( | |
| label="What do you want on your tombstone?", | |
| placeholder="She was kind, He tried his best, The wifi password is on the fridge...", | |
| lines=1, max_lines=2, | |
| ) | |
| step1_btn = gr.Button("What does it take?", variant="primary", size="lg") | |
| with gr.Column(elem_classes="output-box"): | |
| step1_output = gr.Markdown(label="") | |
| gr.Markdown("**Or try one of these:**") | |
| with gr.Row(): | |
| ex1 = gr.Button("She was kind", variant="secondary", size="sm") | |
| ex2 = gr.Button("He showed up", variant="secondary", size="sm") | |
| ex3 = gr.Button("She told the truth", variant="secondary", size="sm") | |
| with gr.Row(): | |
| ex4 = gr.Button("He was a good dad", variant="secondary", size="sm") | |
| ex5 = gr.Button("Wifi password is on the fridge", variant="secondary", size="sm") | |
| ex6 = gr.Button("surprise me", variant="secondary", size="sm") | |
| # STEP 2 | |
| gr.HTML('<div class="step-label">Step 2 — Compare your path</div>') | |
| with gr.Column(elem_classes="input-box"): | |
| routine_input = gr.Textbox( | |
| label="Now tell me how you actually spend your days", | |
| placeholder="wake up, work, come home, scroll, sleep... be honest", | |
| lines=2, max_lines=3, | |
| ) | |
| step2_btn = gr.Button("Show me the gap", variant="primary", size="lg") | |
| with gr.Column(elem_classes="output-box"): | |
| step2_output = gr.Markdown(label="") | |
| # Wiring | |
| step1_btn.click(step_one, [epitaph_input], [step1_output, epitaph_state]) | |
| ex1.click(lambda: step_one("She was kind"), [], [step1_output, epitaph_state]) | |
| ex2.click(lambda: step_one("He showed up"), [], [step1_output, epitaph_state]) | |
| ex3.click(lambda: step_one("She told the truth"), [], [step1_output, epitaph_state]) | |
| ex4.click(lambda: step_one("He was a good dad"), [], [step1_output, epitaph_state]) | |
| ex5.click(lambda: step_one("The wifi password is on the fridge"), [], [step1_output, epitaph_state]) | |
| ex6.click(step_one_random, [], [step1_output, epitaph_state]) | |
| step2_btn.click(step_two, [routine_input, epitaph_state], [step2_output]) | |
| gr.HTML('<div class="footer-text">Heuremen — Let\'s stay connected and keep information free.<br><a href="https://heuremenforprofit.online">heuremenforprofit.online</a></div>') | |
| if __name__ == "__main__": | |
| demo.launch() | |