Upload app.py with huggingface_hub
Browse files
app.py
CHANGED
|
@@ -20,7 +20,7 @@ def projectile_calc(v0_mps: float, theta_deg: float, y0_m: float, g: float, weig
|
|
| 20 |
if not (0 < v0_mps <= 500): errors.append("Initial speed must be in (0, 500] m/s.")
|
| 21 |
if not (-10 <= theta_deg <= 90): errors.append("Launch angle must be between -10° and 90°.")
|
| 22 |
if not (0 <= y0_m <= 1000): errors.append("Initial height must be in [0, 1000] m.")
|
| 23 |
-
if not (1 <= g <= 50): errors.append("Gravity must be in [1, 50] m/s
|
| 24 |
if not (0.05 <= weight_kg <= 50): errors.append("Ball weight must be in [0.05, 50] kg.")
|
| 25 |
if errors:
|
| 26 |
return {"ok": False, "errors": errors}
|
|
@@ -73,6 +73,7 @@ def llm_one_sentence(structured: Dict[str, Any]) -> str:
|
|
| 73 |
i = structured["inputs"]
|
| 74 |
d = structured["derived"]
|
| 75 |
o = structured["outputs"]
|
|
|
|
| 76 |
payload = {
|
| 77 |
"inputs": {
|
| 78 |
"v0_mps": round(i["v0_mps"], 3),
|
|
@@ -91,14 +92,54 @@ def llm_one_sentence(structured: Dict[str, Any]) -> str:
|
|
| 91 |
"impact_speed_mps": round(o["impact_speed_mps"], 3),
|
| 92 |
}
|
| 93 |
}
|
| 94 |
-
|
| 95 |
-
|
| 96 |
-
|
| 97 |
-
|
| 98 |
-
|
| 99 |
-
|
| 100 |
-
|
| 101 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 102 |
|
| 103 |
def run_once(v0_mps, theta_deg, y0_m, g_mps2, weight_kg):
|
| 104 |
rec = projectile_calc(float(v0_mps), float(theta_deg), float(y0_m), float(g_mps2), float(weight_kg))
|
|
@@ -111,7 +152,7 @@ def run_once(v0_mps, theta_deg, y0_m, g_mps2, weight_kg):
|
|
| 111 |
"v0_mps [m/s]": round(i["v0_mps"], 3),
|
| 112 |
"theta_deg [deg]": round(i["theta_deg"], 3),
|
| 113 |
"y0_m [m]": round(i["y0_m"], 3),
|
| 114 |
-
"g_mps2 [m/s
|
| 115 |
"weight_kg [kg]": round(i["weight_kg"], 3),
|
| 116 |
"t_apex_s [s]": round(d["t_apex_s"], 4),
|
| 117 |
"max_height_m [m]": round(o["max_height_m"], 3),
|
|
@@ -130,14 +171,14 @@ with gr.Blocks(title="Projectile Motion — Deterministic + One-Sentence LLM") a
|
|
| 130 |
v0 = gr.Slider(1, 200, value=30.0, step=0.5, label="Initial speed v₀ [m/s]")
|
| 131 |
theta = gr.Slider(-10, 90, value=45.0, step=0.5, label="Launch angle θ [deg]")
|
| 132 |
y0 = gr.Slider(0, 20, value=1.5, step=0.1, label="Initial height y₀ [m]")
|
| 133 |
-
g = gr.Slider(5, 20, value=9.81, step=0.01, label="Gravity g [m/s
|
| 134 |
w = gr.Slider(0.05, 10.0, value=0.43, step=0.01, label="Ball weight [kg]")
|
| 135 |
|
| 136 |
run_btn = gr.Button("Compute")
|
| 137 |
|
| 138 |
results_df = gr.Dataframe(
|
| 139 |
headers=[
|
| 140 |
-
"v0_mps [m/s]", "theta_deg [deg]", "y0_m [m]", "g_mps2 [m/s
|
| 141 |
"t_apex_s [s]", "max_height_m [m]", "time_of_flight_s [s]", "range_m [m]", "impact_speed_mps [m/s]"
|
| 142 |
],
|
| 143 |
label="All values (inputs + derived)",
|
|
|
|
| 20 |
if not (0 < v0_mps <= 500): errors.append("Initial speed must be in (0, 500] m/s.")
|
| 21 |
if not (-10 <= theta_deg <= 90): errors.append("Launch angle must be between -10° and 90°.")
|
| 22 |
if not (0 <= y0_m <= 1000): errors.append("Initial height must be in [0, 1000] m.")
|
| 23 |
+
if not (1 <= g <= 50): errors.append("Gravity must be in [1, 50] m/s^2.")
|
| 24 |
if not (0.05 <= weight_kg <= 50): errors.append("Ball weight must be in [0.05, 50] kg.")
|
| 25 |
if errors:
|
| 26 |
return {"ok": False, "errors": errors}
|
|
|
|
| 73 |
i = structured["inputs"]
|
| 74 |
d = structured["derived"]
|
| 75 |
o = structured["outputs"]
|
| 76 |
+
|
| 77 |
payload = {
|
| 78 |
"inputs": {
|
| 79 |
"v0_mps": round(i["v0_mps"], 3),
|
|
|
|
| 92 |
"impact_speed_mps": round(o["impact_speed_mps"], 3),
|
| 93 |
}
|
| 94 |
}
|
| 95 |
+
|
| 96 |
+
system_msg = (
|
| 97 |
+
"You are a careful technical writer. "
|
| 98 |
+
"Write EXACTLY ONE sentence using ONLY numbers provided in the JSON. "
|
| 99 |
+
"Do not invent or rename fields; keep units as given; use ~2–3 sig figs."
|
| 100 |
+
)
|
| 101 |
+
|
| 102 |
+
# Show the exact sentence shape we want.
|
| 103 |
+
instruction = '''Use only these keys: inputs, derived, outputs.
|
| 104 |
+
Return exactly one sentence in this form (fill in the braces with the JSON values):
|
| 105 |
+
|
| 106 |
+
If you threw a ball that weighed {weight_kg} kg at v0={v0_mps} m/s, θ={theta_deg}, from y0={y0_m} m under g={g_mps2} m/s^2,
|
| 107 |
+
it would stay in the air for {time_of_flight_s} s, reach {max_height_m} m, travel {range_m} m, and impact at {impact_speed_mps} m/s.
|
| 108 |
+
'''
|
| 109 |
+
|
| 110 |
+
user_msg = f"JSON:
|
| 111 |
+
{json.dumps(payload, indent=2)}
|
| 112 |
+
Produce the single sentence as specified."
|
| 113 |
+
|
| 114 |
+
# ✅ Use the tokenizer's chat template
|
| 115 |
+
messages = [
|
| 116 |
+
{"role": "system", "content": system_msg},
|
| 117 |
+
{"role": "user", "content": instruction},
|
| 118 |
+
{"role": "user", "content": user_msg},
|
| 119 |
+
]
|
| 120 |
+
prompt = tokenizer.apply_chat_template(messages, tokenize=False, add_generation_prompt=True)
|
| 121 |
+
|
| 122 |
+
out = llm(
|
| 123 |
+
prompt,
|
| 124 |
+
max_new_tokens=96,
|
| 125 |
+
do_sample=False,
|
| 126 |
+
temperature=0.0,
|
| 127 |
+
return_full_text=False,
|
| 128 |
+
)
|
| 129 |
+
text = out[0]["generated_text"].strip()
|
| 130 |
+
|
| 131 |
+
# Minimal fallback: if the model didn't produce a sensible one-liner, synthesize it.
|
| 132 |
+
if ("If you threw a ball" not in text) or (len(text.split()) < 6):
|
| 133 |
+
p = payload
|
| 134 |
+
text = (
|
| 135 |
+
f"If you threw a ball that weighed {p['inputs']['weight_kg']} kg at v0={p['inputs']['v0_mps']} m/s, "
|
| 136 |
+
f"θ={p['inputs']['theta_deg']}, from y0={p['inputs']['y0_m']} m under g={p['inputs']['g_mps2']} m/s^2, "
|
| 137 |
+
f"it would stay in the air for {p['outputs']['time_of_flight_s']} s, "
|
| 138 |
+
f"reach {p['outputs']['max_height_m']} m, travel {p['outputs']['range_m']} m, "
|
| 139 |
+
f"and impact at {p['outputs']['impact_speed_mps']} m/s."
|
| 140 |
+
)
|
| 141 |
+
|
| 142 |
+
return text
|
| 143 |
|
| 144 |
def run_once(v0_mps, theta_deg, y0_m, g_mps2, weight_kg):
|
| 145 |
rec = projectile_calc(float(v0_mps), float(theta_deg), float(y0_m), float(g_mps2), float(weight_kg))
|
|
|
|
| 152 |
"v0_mps [m/s]": round(i["v0_mps"], 3),
|
| 153 |
"theta_deg [deg]": round(i["theta_deg"], 3),
|
| 154 |
"y0_m [m]": round(i["y0_m"], 3),
|
| 155 |
+
"g_mps2 [m/s^2]": round(i["g_mps2"], 3),
|
| 156 |
"weight_kg [kg]": round(i["weight_kg"], 3),
|
| 157 |
"t_apex_s [s]": round(d["t_apex_s"], 4),
|
| 158 |
"max_height_m [m]": round(o["max_height_m"], 3),
|
|
|
|
| 171 |
v0 = gr.Slider(1, 200, value=30.0, step=0.5, label="Initial speed v₀ [m/s]")
|
| 172 |
theta = gr.Slider(-10, 90, value=45.0, step=0.5, label="Launch angle θ [deg]")
|
| 173 |
y0 = gr.Slider(0, 20, value=1.5, step=0.1, label="Initial height y₀ [m]")
|
| 174 |
+
g = gr.Slider(5, 20, value=9.81, step=0.01, label="Gravity g [m/s^2]")
|
| 175 |
w = gr.Slider(0.05, 10.0, value=0.43, step=0.01, label="Ball weight [kg]")
|
| 176 |
|
| 177 |
run_btn = gr.Button("Compute")
|
| 178 |
|
| 179 |
results_df = gr.Dataframe(
|
| 180 |
headers=[
|
| 181 |
+
"v0_mps [m/s]", "theta_deg [deg]", "y0_m [m]", "g_mps2 [m/s^2]", "weight_kg [kg]",
|
| 182 |
"t_apex_s [s]", "max_height_m [m]", "time_of_flight_s [s]", "range_m [m]", "impact_speed_mps [m/s]"
|
| 183 |
],
|
| 184 |
label="All values (inputs + derived)",
|