import streamlit as st
import pandas as pd
import numpy as np
from sklearn.preprocessing import StandardScaler
from sklearn.neighbors import KNeighborsRegressor
# ---------------------------
# Page config
# ---------------------------
st.set_page_config(
page_title="Neural Tuner β Car Mod Performance Estimator",
page_icon="π₯",
layout="wide"
)
# ---------------------------
# SESSION STATE INITIALIZATION (Fixes Yellow Warning)
# ---------------------------
def init_session_state():
# Only set these defaults if they don't exist yet
defaults = {
"engine_disp": 2.0,
"engine_layout": "I6",
"base_hp": 240,
"weight_kg": 1500,
"weight_reduction": 0,
"intake": "Stock",
"headers": "Stock",
"exhaust": "Stock",
"exhaust_dia": 60,
"cam": "Stock",
"intake_manifold": "Stock",
"induction": "None",
"boost_psi": 0,
"turbo_size": "N/A",
"intercooler": "None",
"meth": False,
"tune": "None",
"fuel": "93",
"altitude": 200,
"traction_mode": "Spirited"
}
for key, value in defaults.items():
if key not in st.session_state:
st.session_state[key] = value
# Run init immediately
init_session_state()
# ---------------------------
# Global CSS (Fixes "Cutting Out" / Rounds)
# ---------------------------
st.markdown(
"""
""",
unsafe_allow_html=True
)
# ---------------------------
# Data & model
# ---------------------------
def generate_dataset(n=400):
np.random.seed(42)
data = []
for _ in range(n):
engine = np.random.choice([1.6, 2.0, 2.5, 3.0, 3.5, 5.0])
cyl = np.random.choice([4, 6, 8])
base_hp = int(engine * cyl * np.random.uniform(18, 22))
intake = np.random.choice([0, 1, 2])
exhaust = np.random.choice([0, 1, 2])
induction = np.random.choice([0, 1, 2])
fuel = np.random.choice([0, 1, 2, 3])
tune = np.random.choice([0, 1, 2])
altitude = np.random.uniform(0, 2000)
hp_gain = (
intake * np.random.uniform(3, 10) +
exhaust * np.random.uniform(5, 20) +
induction * np.random.uniform(25, 100) +
tune * np.random.uniform(10, 35) +
fuel * np.random.uniform(2, 8) -
altitude * 0.01 +
np.random.uniform(-3, 3)
)
data.append([engine, cyl, base_hp, intake, exhaust,
induction, fuel, tune, altitude, hp_gain])
columns = [
"engine", "cyl", "base_hp", "intake", "exhaust",
"induction", "fuel", "tune", "altitude", "hp_gain"
]
return pd.DataFrame(data, columns=columns)
df = generate_dataset()
X = df.drop("hp_gain", axis=1)
y = df["hp_gain"]
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)
model = KNeighborsRegressor(n_neighbors=5, weights="distance")
model.fit(X_scaled, y)
# ---------------------------
# PRESET CALLBACKS
# ---------------------------
def preset_daily():
s = st.session_state
s.engine_disp = 1.6
s.engine_layout = "I4"
s.base_hp = 120
s.weight_kg = 1350
s.weight_reduction = 0
s.intake = "Stock"
s.headers = "Stock"
s.exhaust = "Stock"
s.exhaust_dia = 50
s.cam = "Stock"
s.intake_manifold = "Stock"
s.induction = "None"
s.boost_psi = 0
s.turbo_size = "N/A"
s.intercooler = "None"
s.meth = False
s.tune = "None"
s.fuel = "87"
s.altitude = 200
s.traction_mode = "Daily"
def preset_street():
s = st.session_state
s.engine_disp = 2.0
s.engine_layout = "I4"
s.base_hp = 190
s.weight_kg = 1400
s.weight_reduction = 5
s.intake = "Cold Air"
s.headers = "Shorty"
s.exhaust = "Cat-back"
s.exhaust_dia = 60
s.cam = "Stage 1 β Road"
s.intake_manifold = "High-flow"
s.induction = "Turbo"
s.boost_psi = 12
s.turbo_size = "Small 45-55mm"
s.intercooler = "Air-to-Air"
s.meth = False
s.tune = "Stage 1"
s.fuel = "93"
s.altitude = 150
s.traction_mode = "Spirited"
def preset_drag():
s = st.session_state
s.engine_disp = 5.0
s.engine_layout = "V8"
s.base_hp = 420
s.weight_kg = 1500
s.weight_reduction = 18
s.intake = "Performance"
s.headers = "Long Tube"
s.exhaust = "Straight Pipe"
s.exhaust_dia = 90
s.cam = "Stage 2 β Aggressive"
s.intake_manifold = "High-flow"
s.induction = "Twin-Turbo"
s.boost_psi = 24
s.turbo_size = "Big 66-75mm"
s.intercooler = "Front-mount High-Flow"
s.meth = True
s.tune = "Kill Mode"
s.fuel = "E85 / Race Blend"
s.altitude = 100
s.traction_mode = "Track / Drag"
def preset_max():
s = st.session_state
s.engine_disp = 6.0
s.engine_layout = "V12"
s.base_hp = 650
s.weight_kg = 1400
s.weight_reduction = 25
s.intake = "Performance"
s.headers = "Long Tube"
s.exhaust = "Straight Pipe"
s.exhaust_dia = 100
s.cam = "Stage 3 β Race"
s.intake_manifold = "Individual throttle bodies"
s.induction = "Twincharged"
s.boost_psi = 30
s.turbo_size = "XL 76mm+"
s.intercooler = "Front-mount High-Flow"
s.meth = True
s.tune = "Kill Mode"
s.fuel = "E85 / Race Blend"
s.altitude = 0
s.traction_mode = "Track / Drag"
# ---------------------------
# HERO SECTION
# ---------------------------
st.markdown(
"""
βοΈ KNN model + synthetic dyno data
ποΈ Live tuning playground
Neural Tuner β Car Mod Performance Lab
Mash intakes, boost, tunes and fuel in real time.
Watch horsepower climb and the rev limiter dance. Built to make car nerds go feral. πΊ
Virtual
Dyno
No hardware, all chaos
""",
unsafe_allow_html=True
)
st.markdown("")
# ---------------------------
# Layout
# ---------------------------
left, right = st.columns([1.15, 1])
# ========= LEFT SIDE =========
with left:
st.markdown('', unsafe_allow_html=True)
st.subheader("ποΈ Tune Your Build")
# Preset buttons
bcol1, bcol2, bcol3, bcol4 = st.columns(4)
bcol1.button("π Daily Driver", on_click=preset_daily)
bcol2.button("π Street Fun", on_click=preset_street)
bcol3.button("π Drag Strip", on_click=preset_drag)
bcol4.button("π₯ Max Attack", on_click=preset_max)
st.markdown("")
tabs = st.tabs(["Core Specs", "Bolt-Ons", "Boost & Cooling", "ECU & Fuel"])
# NOTE: I removed 'index=...' from these selectboxes.
# They now just rely on the key being present in st.session_state (handled by init_session_state)
# --- Core specs ---
with tabs[0]:
col1, col2 = st.columns(2)
engine_disp_options = [0.8,1.0,1.2,1.4,1.6,1.8,2.0,2.2,2.4,2.5,
2.8,3.0,3.2,3.5,4.0,4.4,5.0,6.0,7.0,8.0]
# We manually update value if it's missing (failsafe), though init handles it.
if "engine_disp" not in st.session_state: st.session_state.engine_disp = 2.0
engine_disp = col1.selectbox(
"Engine Displacement (L)",
engine_disp_options,
key="engine_disp"
)
engine_layout = col2.selectbox(
"Engine Layout",
["I3","I4","I6","V6","V8","V10","V12"],
key="engine_layout"
)
layout_to_cyl = {"I3":3,"I4":4,"I6":6,"V6":6,"V8":8,"V10":10,"V12":12}
cyl = layout_to_cyl[engine_layout]
base_hp = st.number_input(
"Base Horsepower (stock dyno)",
min_value=60, max_value=3000,
key="base_hp"
)
col3, col4 = st.columns(2)
weight_kg = col3.number_input(
"Vehicle Weight (kg)",
min_value=700, max_value=4000,
key="weight_kg"
)
weight_reduction = col4.slider(
"Weight Reduction (%)",
0, 40,
key="weight_reduction"
)
# --- Bolt-ons ---
with tabs[1]:
col1, col2, col3 = st.columns(3)
intake = col1.selectbox("Intake", ["Stock", "Cold Air", "Performance"], key="intake")
headers = col2.selectbox("Headers", ["Stock", "Shorty", "Long Tube"], key="headers")
exhaust = col3.selectbox("Exhaust", ["Stock", "Cat-back", "Straight Pipe"], key="exhaust")
exhaust_dia = st.slider("Exhaust Diameter (mm)", 40, 120, key="exhaust_dia")
cam = st.selectbox(
"Cam Profile",
["Stock", "Stage 1 β Road", "Stage 2 β Aggressive", "Stage 3 β Race"],
key="cam"
)
intake_manifold = st.selectbox(
"Intake Manifold",
["Stock", "High-flow", "Individual throttle bodies"],
key="intake_manifold"
)
# --- Boost & cooling ---
with tabs[2]:
induction = st.selectbox(
"Forced Induction Setup",
["None", "Turbo", "Twin-Turbo", "Supercharger", "Twincharged"],
key="induction"
)
boost_psi = st.slider("Target Boost (psi)", 0, 40, key="boost_psi")
turbo_size = st.selectbox(
"Turbo Size",
["N/A", "Small 45-55mm", "Medium 56-65mm", "Big 66-75mm", "XL 76mm+"],
key="turbo_size"
)
intercooler = st.selectbox(
"Intercooler Type",
["None", "Air-to-Air", "Air-to-Water", "Front-mount High-Flow"],
key="intercooler"
)
meth = st.checkbox("Methanol Injection Kit", key="meth")
# --- ECU & fuel ---
with tabs[3]:
tune = st.selectbox(
"ECU Tune Level",
["None", "Mild Street", "Stage 1", "Stage 2", "Kill Mode"],
key="tune"
)
fuel = st.selectbox(
"Fuel Type",
["87", "91", "93", "E85 / Race Blend"],
key="fuel"
)
altitude = st.slider("Altitude (meters)", 0, 3500, key="altitude")
traction_mode = st.radio(
"Traction Mode Vibe",
["Daily", "Spirited", "Track / Drag"],
horizontal=True,
key="traction_mode"
)
st.markdown(
'
Numbers are synthetic; this is a dyno-inspired playground, not a tuning bible. π§ͺ
',
unsafe_allow_html=True
)
st.markdown('
', unsafe_allow_html=True)
# ========= MODEL & CALCS =========
intake_map = {"Stock":0, "Cold Air":1, "Performance":2}
exhaust_map = {"Stock":0, "Cat-back":1, "Straight Pipe":2}
induction_model_map = {"None":0, "Turbo":1, "Twin-Turbo":1, "Supercharger":2, "Twincharged":2}
fuel_map = {"87":0, "91":1, "93":2, "E85 / Race Blend":3}
tune_base_map = {"None":0, "Mild Street":1, "Stage 1":1, "Stage 2":2, "Kill Mode":2}
input_for_model = np.array([[
engine_disp,
cyl,
base_hp,
intake_map.get(intake,0),
exhaust_map.get(exhaust,0),
induction_model_map.get(induction,0),
fuel_map.get(fuel,0),
tune_base_map.get(tune,0),
altitude
]])
input_scaled = scaler.transform(input_for_model)
pred_base = float(model.predict(input_scaled)[0])
cam_gain_map = {
"Stock":0.0,
"Stage 1 β Road":6.0,
"Stage 2 β Aggressive":12.0,
"Stage 3 β Race":20.0
}
headers_gain_map = {"Stock":0.0, "Shorty":5.0, "Long Tube":9.0}
intake_man_gain_map = {
"Stock":0.0,
"High-flow":5.0,
"Individual throttle bodies":10.0
}
intercooler_gain_map = {
"None":0.0,
"Air-to-Air":4.0,
"Air-to-Water":6.5,
"Front-mount High-Flow":9.0
}
turbo_size_map = {
"N/A":0.0,
"Small 45-55mm":5.0,
"Medium 56-65mm":12.0,
"Big 66-75mm":20.0,
"XL 76mm+":28.0
}
cam_gain = cam_gain_map.get(cam, 0.0)
headers_gain = headers_gain_map.get(headers, 0.0)
intake_man_gain = intake_man_gain_map.get(intake_manifold, 0.0)
intercooler_gain = intercooler_gain_map.get(intercooler, 0.0)
turbo_size_gain = turbo_size_map.get(turbo_size, 0.0)
if induction in ["Turbo", "Twin-Turbo"]:
boost_gain = boost_psi * 1.8
elif induction in ["Supercharger", "Twincharged"]:
boost_gain = boost_psi * 1.4
else:
boost_gain = 0.0
meth_gain = 12.0 if meth else 0.0
exhaust_dia_gain = max(0.0, (exhaust_dia - 55) * 0.1)
extra_gain = (
cam_gain +
headers_gain +
intake_man_gain +
intercooler_gain +
turbo_size_gain +
boost_gain * 0.9 +
meth_gain +
exhaust_dia_gain
)
traction_multiplier = {"Daily":0.9, "Spirited":1.0, "Track / Drag":1.05}[traction_mode]
pred_total_gain = (pred_base + extra_gain) * traction_multiplier
pred_total_gain = max(pred_total_gain, -5.0)
new_hp = max(base_hp + pred_total_gain, 40.0)
effective_weight = weight_kg * (1 - weight_reduction / 100.0)
hp_per_ton = new_hp / (effective_weight / 1000.0)
hype_raw = np.clip(pred_total_gain / 120 * 100, 0, 100)
hype_level = int(hype_raw)
if hype_level < 20:
verdict = "Sleeper grocery getter π"
elif hype_level < 40:
verdict = "Respectable street build π"
elif hype_level < 70:
verdict = "Serious weekend weapon βοΈ"
else:
verdict = "Full send, tyres cry for mercy π"
# compute base angle for rev gauge (-90deg to +90deg)
angle_deg = -90 + (hype_level / 100.0) * 180
# ========= RIGHT SIDE =========
with right:
st.markdown('', unsafe_allow_html=True)
st.subheader("π₯ Build Outcome")
m1, m2, m3 = st.columns(3)
m1.metric("Estimated HP Gain", f"{pred_total_gain:.1f} HP")
m2.metric("New Output", f"{new_hp:.1f} HP")
m3.metric("HP per Ton", f"{hp_per_ton:.1f}")
# Animated rev limiter gauge
st.markdown('
Rev Limiter Vibes
', unsafe_allow_html=True)
st.markdown(
f"""
""",
unsafe_allow_html=True
)
st.markdown('
Hype Meter (relative craziness of this build)
', unsafe_allow_html=True)
st.progress(hype_level)
st.markdown(f"**Verdict:** {verdict}")
st.markdown("")
st.bar_chart(
pd.DataFrame(
{"Horsepower": [base_hp, new_hp]},
index=["Stock", "Tuned"]
)
)
st.markdown(
f"""
{engine_disp}L {engine_layout}
Weight: {weight_kg} kg βΈ β{weight_reduction}%
Intake: {intake}
Headers: {headers}
Exhaust: {exhaust} ({exhaust_dia}mm)
Induction: {induction} @ {boost_psi} psi
IC: {intercooler}
Tune: {tune}
Fuel: {fuel}
""",
unsafe_allow_html=True
)
st.markdown("---")
breakdown = pd.DataFrame({
"Component": [
"Model base (from dataset)",
"Cam profile",
"Headers",
"Intake manifold",
"Intercooler",
"Turbo size",
"Boost (net)",
"Meth kit",
"Exhaust diameter tweak"
],
"Approx HP": [
pred_base,
cam_gain,
headers_gain,
intake_man_gain,
intercooler_gain,
turbo_size_gain,
boost_gain * 0.9,
meth_gain,
exhaust_dia_gain
]
})
st.caption("π¬ Where is that extra power coming from?")
st.dataframe(breakdown, use_container_width=True, height=260)
st.markdown(
'
Model: distance-weighted KNN on synthetic dyno-style data + heuristic math for advanced mods.
',
unsafe_allow_html=True
)
st.markdown('
', unsafe_allow_html=True)
# ========= FOOTER =========
st.markdown(
"""
Presets + rev limiter + neon dynoβ¦ if this doesnβt make people go mad, we can push it even further. π§π₯
""",
unsafe_allow_html=True
)