zacCMU commited on
Commit
35918c5
·
verified ·
1 Parent(s): dd2f30b

Update app.py from Colab

Browse files
Files changed (1) hide show
  1. app.py +231 -0
app.py ADDED
@@ -0,0 +1,231 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import math # For access to infinity
2
+
3
+ import gradio # For building the interface
4
+ import pandas # For working with tables
5
+
6
+ from transformers import AutoTokenizer, AutoModelForCausalLM, pipeline # For LLMS
7
+
8
+ # Instantiate the model that we'll be calling. This is a tiny one!
9
+ MODEL_ID = "HuggingFaceTB/SmolLM2-135M-Instruct"
10
+ tokenizer = AutoTokenizer.from_pretrained(MODEL_ID)
11
+ pipe = pipeline(
12
+ task="text-generation",
13
+ model=AutoModelForCausalLM.from_pretrained(
14
+ MODEL_ID,
15
+ ),
16
+ tokenizer=tokenizer
17
+ )
18
+ import math
19
+ import gradio as gr
20
+ import pandas as pd
21
+
22
+ # --- IMPORTANT: Model and Tokenizer Setup (User must provide this) ---
23
+ # To run this script, you must load a Hugging Face model and tokenizer.
24
+ # For example:
25
+ #
26
+ # from transformers import pipeline, AutoTokenizer
27
+ # import torch
28
+ #
29
+ # model_id = "microsoft/phi-2"
30
+ # tokenizer = AutoTokenizer.from_pretrained(model_id, trust_remote_code=True)
31
+ # pipe = pipeline(
32
+ # "text-generation",
33
+ # model=model_id,
34
+ # tokenizer=tokenizer,
35
+ # torch_dtype=torch.bfloat16,
36
+ # device_map="auto",
37
+ # trust_remote_code=True
38
+ # )
39
+ #
40
+ # If you do not define 'pipe' and 'tokenizer', this script will raise a NameError.
41
+
42
+ # --- Core Calculation Logic ---
43
+
44
+ def size_ac_motor_complex(
45
+ required_power_hp: float = None,
46
+ required_torque_lb_ft: float = None,
47
+ speed_rpm: float = None,
48
+ voltage_v: float = None,
49
+ efficiency: float = 0.85,
50
+ service_factor: float = 1.15,
51
+ power_factor: float = 0.8,
52
+ motor_type: str = "induction"
53
+ ) -> dict:
54
+ """
55
+ Calculates the required motor nameplate power based on load requirements.
56
+ """
57
+ if required_power_hp is not None:
58
+ required_load_power_watts = required_power_hp * 745.7
59
+ elif required_torque_lb_ft is not None and speed_rpm is not None:
60
+ hp_from_torque = (required_torque_lb_ft * speed_rpm) / 5252.0
61
+ required_load_power_watts = hp_from_torque * 745.7
62
+ required_power_hp = hp_from_torque
63
+ else:
64
+ return {"error": "Either 'Required Power (HP)' or both 'Required Torque (lb-ft)' and 'Speed (rpm)' must be provided."}
65
+
66
+ if efficiency <= 0 or power_factor <= 0 or service_factor <= 0:
67
+ return {"error": "Efficiency, Power Factor, and Service Factor must be positive values."}
68
+
69
+ sized_mechanical_power_watts = required_load_power_watts * service_factor
70
+ electrical_power_drawn_watts = required_load_power_watts / efficiency
71
+ sized_mechanical_power_kw = sized_mechanical_power_watts / 1000
72
+ electrical_power_drawn_kw = electrical_power_drawn_watts / 1000
73
+ notes = f"Sizing calculation for a standard {motor_type} motor."
74
+
75
+ return {
76
+ "calculated_load_hp": required_power_hp,
77
+ "required_torque_lb_ft": required_torque_lb_ft,
78
+ "speed_rpm": speed_rpm,
79
+ "voltage_v": voltage_v,
80
+ "sized_mechanical_power_kw": sized_mechanical_power_kw,
81
+ "electrical_power_drawn_kw": electrical_power_drawn_kw,
82
+ "efficiency": efficiency,
83
+ "service_factor": service_factor,
84
+ "power_factor": power_factor,
85
+ "motor_type": motor_type,
86
+ "notes": notes
87
+ }
88
+
89
+ # --- LLM Helper Functions (Now require a live model) ---
90
+
91
+ def _format_chat(system_prompt: str, user_prompt: str) -> str:
92
+ """This helper function applies a chat format to help the LLM understand."""
93
+ messages = [
94
+ {"role": "system", "content": system_prompt},
95
+ {"role": "user", "content": user_prompt},
96
+ ]
97
+ # This function now assumes a 'tokenizer' object is available globally.
98
+ return tokenizer.apply_chat_template(
99
+ messages,
100
+ tokenize=False,
101
+ add_generation_prompt=True
102
+ )
103
+
104
+ def _llm_generate(prompt: str, max_tokens: int) -> str:
105
+ """This function uses the LLM to generate a response."""
106
+ # This function now assumes a 'pipe' object (pipeline) is available globally.
107
+ out = pipe(
108
+ prompt,
109
+ max_new_tokens=max_tokens,
110
+ do_sample=True,
111
+ temperature=0.5,
112
+ return_full_text=False,
113
+ )
114
+ return out[0]["generated_text"]
115
+
116
+
117
+ def llm_explain(results: dict) -> str:
118
+ """This function generates an explanation of the results using the LLM structure."""
119
+ if "error" in results:
120
+ return f"Error: {results['error']}"
121
+
122
+ system_prompt = (
123
+ "You explain engineering to a smart 5-year-old. "
124
+ "Use food-based analogies to support the explanation. "
125
+ "You always return CONCISE responses, only one sentence."
126
+ )
127
+
128
+ user_prompt = (
129
+ f"My machine needs {results['calculated_load_hp']:.2f} horsepower to run. "
130
+ f"Considering a service factor of {results['service_factor']}, the calculated sized motor power is {results['sized_mechanical_power_kw']:.2f} kW. "
131
+ f"Explain what the 'sized motor power' means in one friendly sentence using a food-based analogy for a non-expert."
132
+ )
133
+
134
+ formatted_prompt = _format_chat(system_prompt, user_prompt)
135
+ return _llm_generate(formatted_prompt, max_tokens=128)
136
+
137
+
138
+ # --- Gradio Interface Function ---
139
+
140
+ def run_calculation_interface(required_power_hp, required_torque_lb_ft, speed_rpm, voltage_v, efficiency, service_factor, power_factor, motor_type):
141
+ """Connects the Gradio UI to the backend calculation logic."""
142
+ required_power_hp = float(required_power_hp) if required_power_hp else None
143
+ required_torque_lb_ft = float(required_torque_lb_ft) if required_torque_lb_ft else None
144
+ speed_rpm = float(speed_rpm) if speed_rpm else None
145
+ voltage_v = float(voltage_v) if voltage_v else None
146
+
147
+ results = size_ac_motor_complex(
148
+ required_power_hp=required_power_hp,
149
+ required_torque_lb_ft=required_torque_lb_ft,
150
+ speed_rpm=speed_rpm,
151
+ voltage_v=voltage_v,
152
+ efficiency=float(efficiency),
153
+ service_factor=float(service_factor),
154
+ power_factor=float(power_factor),
155
+ motor_type=motor_type
156
+ )
157
+
158
+ # Wrap the LLM call in a try-except block to handle potential errors
159
+ try:
160
+ narrative = llm_explain(results)
161
+ except NameError:
162
+ narrative = "LLM Error: The 'pipe' and 'tokenizer' objects are not defined. Please load a model."
163
+ except Exception as e:
164
+ narrative = f"An unexpected error occurred with the LLM: {e}"
165
+
166
+
167
+ if "error" in results:
168
+ df = pd.DataFrame()
169
+ else:
170
+ df = pd.DataFrame([{
171
+ "Required Load [HP]": f"{results['calculated_load_hp']:.2f}",
172
+ "Sized Motor Rating [kW]": f"{results['sized_mechanical_power_kw']:.2f}",
173
+ "Estimated Electrical Draw [kW]": f"{results['electrical_power_drawn_kw']:.2f}",
174
+ "Service Factor": results["service_factor"],
175
+ "Efficiency": results["efficiency"],
176
+ }])
177
+
178
+ return df, narrative
179
+
180
+
181
+ # --- Gradio User Interface Definition ---
182
+
183
+ with gr.Blocks(theme=gr.themes.Soft()) as demo:
184
+ gr.Markdown("# Advanced AC Motor Sizing Calculator")
185
+ gr.Markdown("Size an AC motor based on your load requirements. Provide either the required power directly, or the torque and speed for the application.")
186
+
187
+ with gr.Row():
188
+ with gr.Column(scale=2):
189
+ gr.Markdown("### Load Requirements")
190
+ with gr.Row():
191
+ required_power_hp = gr.Number(label="Required Power [HP] (Option 1)")
192
+ required_torque_lb_ft = gr.Number(label="Required Torque [lb-ft] (Option 2)")
193
+ speed_rpm = gr.Number(label="Speed [rpm] (with Torque)")
194
+ with gr.Column(scale=1):
195
+ gr.Markdown("### Electrical & Motor Parameters")
196
+ voltage_v = gr.Number(label="Voltage [V] (Optional)")
197
+ motor_type = gr.Dropdown(choices=["induction", "synchronous", "servo"], value="induction", label="Motor Type")
198
+
199
+ with gr.Row():
200
+ efficiency = gr.Slider(minimum=0.5, maximum=0.99, value=0.85, step=0.01, label="Motor Efficiency")
201
+ service_factor = gr.Slider(minimum=1.0, maximum=2.0, value=1.15, step=0.05, label="Service Factor")
202
+ power_factor = gr.Slider(minimum=0.5, maximum=1.0, value=0.80, step=0.01, label="Power Factor")
203
+
204
+ run_btn = gr.Button("Calculate Motor Size", variant="primary")
205
+
206
+ gr.Markdown("---")
207
+ gr.Markdown("### Results")
208
+ results_df = gr.Dataframe(label="Summary", interactive=False)
209
+ explain_md = gr.Markdown(label="Explanation")
210
+
211
+ run_btn.click(
212
+ fn=run_calculation_interface,
213
+ inputs=[required_power_hp, required_torque_lb_ft, speed_rpm, voltage_v, efficiency, service_factor, power_factor, motor_type],
214
+ outputs=[results_df, explain_md]
215
+ )
216
+
217
+ gr.Examples(
218
+ examples=[
219
+ [5.0, None, None, 480, 0.90, 1.25, 0.85, "induction"],
220
+ [None, 10.0, 1750, 230, 0.88, 1.15, 0.82, "induction"],
221
+ [1.0, None, None, 208, 0.85, 1.0, 0.75, "synchronous"],
222
+ ],
223
+ inputs=[required_power_hp, required_torque_lb_ft, speed_rpm, voltage_v, efficiency, service_factor, power_factor, motor_type],
224
+ label="Example Scenarios",
225
+ )
226
+
227
+ if __name__ == "__main__":
228
+ # --- IMPORTANT ---
229
+ # You must define 'pipe' and 'tokenizer' before this line for the app to work.
230
+ # For example, place the model loading code from the top of the script here.
231
+ demo.launch()