prefero / app /Home.py
Wil2200's picture
Add dual license (AGPL-3.0 + Commercial) and copyright notices
247642a
# Copyright (C) 2026 Hengzhe Zhao. All rights reserved.
# Licensed under dual license: AGPL-3.0 (open-source) or commercial. See LICENSE.
"""Prefero โ€” Home page (main entry point for the multi-page app)."""
from __future__ import annotations
import os
from pathlib import Path
import streamlit as st
from utils import init_session_state, language_banner, sidebar_branding, slowbro_next_step
st.set_page_config(
page_title="Prefero - DCE Analysis Tool",
page_icon="๐Ÿงฎ",
layout="wide",
)
init_session_state()
sidebar_branding()
# โ”€โ”€ Multilingual banner โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
language_banner()
st.markdown(
'<div style="text-align:right; margin-top:-6px; margin-bottom:4px;">',
unsafe_allow_html=True,
)
st.markdown(
"",
help=(
"We respect and celebrate linguistic and cultural diversity. "
"The transliterations above represent our best effort to render "
"\"Prefero\" faithfully in each writing system. We acknowledge that "
"automated transliteration may not perfectly capture every nuance. "
"If you feel a translation could be improved, we warmly welcome "
"your feedback โ€” please reach out via GitHub Issues. Thank you!"
),
)
st.markdown("</div>", unsafe_allow_html=True)
# โ”€โ”€ Welcome โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
st.title("Prefero")
st.caption("Discrete Choice Experiment Analysis")
st.markdown(
"""
Welcome to **Prefero**, a **completely code-free** interactive tool
for specifying, estimating, and comparing discrete-choice models.
No programming required โ€” just upload your data, point and click, and let
Slowbro handle the heavy lifting. Whether you're a seasoned econometrician
or running your first choice experiment, everything works through this
guided interface.
"""
)
# โ”€โ”€ Workflow guide โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
st.subheader("Workflow")
steps = [
("1", "Data", "Load or simulate a choice dataset.", "๐Ÿ“Š"),
("2", "Model", "Configure CL, MXL, or Latent Class models.", "โš™๏ธ"),
("3", "Results", "Inspect estimates, WTP, and predictions.", "๐Ÿ“ˆ"),
("4", "Compare", "Compare models side-by-side.", "๐Ÿ”„"),
("5", "Bootstrap", "Bootstrap inference for robust SEs.", "๐ŸŽฏ"),
("6", "Report", "Generate a professional analysis report.", "๐Ÿ“"),
("7", "Community", "Discuss methods and share insights.", "๐Ÿ’ฌ"),
]
cols = st.columns(7)
for col, (num, title, desc, icon) in zip(cols, steps):
with col:
with st.container(border=True):
st.markdown(f"### {icon}")
st.markdown(f"**Step {num}: {title}**")
st.caption(desc)
st.divider()
# โ”€โ”€ Begin the journey โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
_NAV_IMG = (
"https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites"
"/pokemon/other/official-artwork/80.png"
)
_j1, _j2 = st.columns([1, 4])
with _j1:
st.image(_NAV_IMG, width=80)
with _j2:
st.markdown(
"<p style='margin:0; color:gray; font-size:0.85em;'>"
"Ready? Slowbro will walk you through every step.</p>",
unsafe_allow_html=True,
)
if st.button(
"๐Ÿ“Š Begin the journey with Slowbro",
key="_nav_begin",
use_container_width=True,
type="primary",
):
st.switch_page("pages/1_๐Ÿ“Š_Data.py")
# โ”€โ”€ The Tale of Slowbro โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
st.divider()
# Pokรฉmon official artwork from PokeAPI sprites (public)
_slowpoke_url = "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/other/official-artwork/79.png"
_shellder_url = "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/other/official-artwork/90.png"
_slowbro_url = "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/other/official-artwork/80.png"
st.markdown("#### The Tale of Slowbro โ€” Our Mascot")
_story_col1, _story_col2, _story_col3 = st.columns(3)
with _story_col1:
st.image(_slowpoke_url, width=180, caption="Slowpoke")
st.markdown(
"""
Once upon a time, there was a **Slowpoke** who spent its days
by the river, staring blankly at the water, occasionally
dipping its tail in to fish... very, very slowly.
"""
)
with _story_col2:
st.image(_shellder_url, width=140, caption="Shellder")
st.markdown(
"""
One day, a **Shellder** swam by and clamped down hard on
Slowpoke's tail. About five minutes later, Slowpoke finally
noticed: *"Huh? Did something just bite me...?"*
"""
)
with _story_col3:
st.image(_slowbro_url, width=180, caption="Slowbro")
st.markdown(
"""
And just like that, **Slowpoke evolved into Slowbro!**
Shellder never let go, and Slowbro never bothered to
check โ€” they've been stuck together ever since.
"""
)
st.markdown("---")
_bro_col1, _bro_col2 = st.columns([1, 3])
with _bro_col1:
st.image(_slowbro_url, width=120)
with _bro_col2:
st.markdown(
"""
Now, this Slowbro spends every day running **discrete choice models** for everyone:
Mixed Logit, Latent Class, GMNL, Bootstrap...
each one more exhausting than the last.
> *Slowbro is tired. When Slowbro is tired, Slowbro needs coffee.* โ˜•
"""
)
# โ”€โ”€ Buy Slowbro a coffee โ”€โ”€
_coffee_url = os.environ.get("COFFEE_URL", "https://buymeacoffee.com/preferohz")
_bmc_logo = "https://cdn.buymeacoffee.com/buttons/bmc-new-btn-logo.svg"
_btn_style = (
"display:flex; align-items:center; justify-content:center; "
"gap:8px; padding:12px 16px; border-radius:8px; "
"font-weight:600; font-size:0.95em; height:48px; "
"text-decoration:none; cursor:pointer;"
)
st.markdown(
f"<a href='{_coffee_url}' target='_blank' style='"
f"{_btn_style} max-width:300px; background:#FFDD00; color:#000;'>"
f"<img src='{_bmc_logo}' width='22' style='flex-shrink:0;'/>"
f"Buy Slowbro a Coffee</a>",
unsafe_allow_html=True,
)