Spaces:
Sleeping
Sleeping
| import math # For access to infinity | |
| import gradio # For building the interface | |
| import pandas # For working with tables | |
| from transformers import AutoTokenizer, AutoModelForCausalLM, pipeline # For LLMS | |
| # Instantiate the model that we'll be calling. This is a tiny one! | |
| MODEL_ID = "HuggingFaceTB/SmolLM2-135M-Instruct" | |
| tokenizer = AutoTokenizer.from_pretrained(MODEL_ID) | |
| pipe = pipeline( | |
| task="text-generation", | |
| model=AutoModelForCausalLM.from_pretrained( | |
| MODEL_ID, | |
| ), | |
| tokenizer=tokenizer | |
| ) | |
| import math | |
| import gradio as gr | |
| import pandas as pd | |
| # --- IMPORTANT: Model and Tokenizer Setup (User must provide this) --- | |
| # To run this script, you must load a Hugging Face model and tokenizer. | |
| # For example: | |
| # | |
| # from transformers import pipeline, AutoTokenizer | |
| # import torch | |
| # | |
| # model_id = "microsoft/phi-2" | |
| # tokenizer = AutoTokenizer.from_pretrained(model_id, trust_remote_code=True) | |
| # pipe = pipeline( | |
| # "text-generation", | |
| # model=model_id, | |
| # tokenizer=tokenizer, | |
| # torch_dtype=torch.bfloat16, | |
| # device_map="auto", | |
| # trust_remote_code=True | |
| # ) | |
| # | |
| # If you do not define 'pipe' and 'tokenizer', this script will raise a NameError. | |
| # --- Core Calculation Logic --- | |
| def size_ac_motor_complex( | |
| required_power_hp: float = None, | |
| required_torque_lb_ft: float = None, | |
| speed_rpm: float = None, | |
| voltage_v: float = None, | |
| efficiency: float = 0.85, | |
| service_factor: float = 1.15, | |
| power_factor: float = 0.8, | |
| motor_type: str = "induction" | |
| ) -> dict: | |
| """ | |
| Calculates the required motor nameplate power based on load requirements. | |
| """ | |
| if required_power_hp is not None: | |
| required_load_power_watts = required_power_hp * 745.7 | |
| elif required_torque_lb_ft is not None and speed_rpm is not None: | |
| hp_from_torque = (required_torque_lb_ft * speed_rpm) / 5252.0 | |
| required_load_power_watts = hp_from_torque * 745.7 | |
| required_power_hp = hp_from_torque | |
| else: | |
| return {"error": "Either 'Required Power (HP)' or both 'Required Torque (lb-ft)' and 'Speed (rpm)' must be provided."} | |
| if efficiency <= 0 or power_factor <= 0 or service_factor <= 0: | |
| return {"error": "Efficiency, Power Factor, and Service Factor must be positive values."} | |
| sized_mechanical_power_watts = required_load_power_watts * service_factor | |
| electrical_power_drawn_watts = required_load_power_watts / efficiency | |
| sized_mechanical_power_kw = sized_mechanical_power_watts / 1000 | |
| electrical_power_drawn_kw = electrical_power_drawn_watts / 1000 | |
| notes = f"Sizing calculation for a standard {motor_type} motor." | |
| return { | |
| "calculated_load_hp": required_power_hp, | |
| "required_torque_lb_ft": required_torque_lb_ft, | |
| "speed_rpm": speed_rpm, | |
| "voltage_v": voltage_v, | |
| "sized_mechanical_power_kw": sized_mechanical_power_kw, | |
| "electrical_power_drawn_kw": electrical_power_drawn_kw, | |
| "efficiency": efficiency, | |
| "service_factor": service_factor, | |
| "power_factor": power_factor, | |
| "motor_type": motor_type, | |
| "notes": notes | |
| } | |
| # --- LLM Helper Functions (Now require a live model) --- | |
| def _format_chat(system_prompt: str, user_prompt: str) -> str: | |
| """This helper function applies a chat format to help the LLM understand.""" | |
| messages = [ | |
| {"role": "system", "content": system_prompt}, | |
| {"role": "user", "content": user_prompt}, | |
| ] | |
| # This function now assumes a 'tokenizer' object is available globally. | |
| return tokenizer.apply_chat_template( | |
| messages, | |
| tokenize=False, | |
| add_generation_prompt=True | |
| ) | |
| def _llm_generate(prompt: str, max_tokens: int) -> str: | |
| """This function uses the LLM to generate a response.""" | |
| # This function now assumes a 'pipe' object (pipeline) is available globally. | |
| out = pipe( | |
| prompt, | |
| max_new_tokens=max_tokens, | |
| do_sample=True, | |
| temperature=0.5, | |
| return_full_text=False, | |
| ) | |
| return out[0]["generated_text"] | |
| def llm_explain(results: dict) -> str: | |
| """This function generates an explanation of the results using the LLM structure.""" | |
| if "error" in results: | |
| return f"Error: {results['error']}" | |
| system_prompt = ( | |
| "You explain engineering to a smart 5-year-old. " | |
| "Use food-based analogies to support the explanation. " | |
| "You always return CONCISE responses, only one sentence." | |
| ) | |
| user_prompt = ( | |
| f"My machine needs {results['calculated_load_hp']:.2f} horsepower to run. " | |
| f"Considering a service factor of {results['service_factor']}, the calculated sized motor power is {results['sized_mechanical_power_kw']:.2f} kW. " | |
| f"Explain what the 'sized motor power' means in one friendly sentence using a food-based analogy for a non-expert." | |
| ) | |
| formatted_prompt = _format_chat(system_prompt, user_prompt) | |
| return _llm_generate(formatted_prompt, max_tokens=128) | |
| # --- Gradio Interface Function --- | |
| def run_calculation_interface(required_power_hp, required_torque_lb_ft, speed_rpm, voltage_v, efficiency, service_factor, power_factor, motor_type): | |
| """Connects the Gradio UI to the backend calculation logic.""" | |
| required_power_hp = float(required_power_hp) if required_power_hp else None | |
| required_torque_lb_ft = float(required_torque_lb_ft) if required_torque_lb_ft else None | |
| speed_rpm = float(speed_rpm) if speed_rpm else None | |
| voltage_v = float(voltage_v) if voltage_v else None | |
| results = size_ac_motor_complex( | |
| required_power_hp=required_power_hp, | |
| required_torque_lb_ft=required_torque_lb_ft, | |
| speed_rpm=speed_rpm, | |
| voltage_v=voltage_v, | |
| efficiency=float(efficiency), | |
| service_factor=float(service_factor), | |
| power_factor=float(power_factor), | |
| motor_type=motor_type | |
| ) | |
| # Wrap the LLM call in a try-except block to handle potential errors | |
| try: | |
| narrative = llm_explain(results) | |
| except NameError: | |
| narrative = "LLM Error: The 'pipe' and 'tokenizer' objects are not defined. Please load a model." | |
| except Exception as e: | |
| narrative = f"An unexpected error occurred with the LLM: {e}" | |
| if "error" in results: | |
| df = pd.DataFrame() | |
| else: | |
| df = pd.DataFrame([{ | |
| "Required Load [HP]": f"{results['calculated_load_hp']:.2f}", | |
| "Sized Motor Rating [kW]": f"{results['sized_mechanical_power_kw']:.2f}", | |
| "Estimated Electrical Draw [kW]": f"{results['electrical_power_drawn_kw']:.2f}", | |
| "Service Factor": results["service_factor"], | |
| "Efficiency": results["efficiency"], | |
| }]) | |
| return df, narrative | |
| # --- Gradio User Interface Definition --- | |
| with gr.Blocks(theme=gr.themes.Soft()) as demo: | |
| gr.Markdown("# Advanced AC Motor Sizing Calculator") | |
| 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.") | |
| with gr.Row(): | |
| with gr.Column(scale=2): | |
| gr.Markdown("### Load Requirements") | |
| with gr.Row(): | |
| required_power_hp = gr.Number(label="Required Power [HP] (Option 1)") | |
| required_torque_lb_ft = gr.Number(label="Required Torque [lb-ft] (Option 2)") | |
| speed_rpm = gr.Number(label="Speed [rpm] (with Torque)") | |
| with gr.Column(scale=1): | |
| gr.Markdown("### Electrical & Motor Parameters") | |
| voltage_v = gr.Number(label="Voltage [V] (Optional)") | |
| motor_type = gr.Dropdown(choices=["induction", "synchronous", "servo"], value="induction", label="Motor Type") | |
| with gr.Row(): | |
| efficiency = gr.Slider(minimum=0.5, maximum=0.99, value=0.85, step=0.01, label="Motor Efficiency") | |
| service_factor = gr.Slider(minimum=1.0, maximum=2.0, value=1.15, step=0.05, label="Service Factor") | |
| power_factor = gr.Slider(minimum=0.5, maximum=1.0, value=0.80, step=0.01, label="Power Factor") | |
| run_btn = gr.Button("Calculate Motor Size", variant="primary") | |
| gr.Markdown("---") | |
| gr.Markdown("### Results") | |
| results_df = gr.Dataframe(label="Summary", interactive=False) | |
| explain_md = gr.Markdown(label="Explanation") | |
| run_btn.click( | |
| fn=run_calculation_interface, | |
| inputs=[required_power_hp, required_torque_lb_ft, speed_rpm, voltage_v, efficiency, service_factor, power_factor, motor_type], | |
| outputs=[results_df, explain_md] | |
| ) | |
| gr.Examples( | |
| examples=[ | |
| [5.0, None, None, 480, 0.90, 1.25, 0.85, "induction"], | |
| [None, 10.0, 1750, 230, 0.88, 1.15, 0.82, "induction"], | |
| [1.0, None, None, 208, 0.85, 1.0, 0.75, "synchronous"], | |
| ], | |
| inputs=[required_power_hp, required_torque_lb_ft, speed_rpm, voltage_v, efficiency, service_factor, power_factor, motor_type], | |
| label="Example Scenarios", | |
| ) | |
| if __name__ == "__main__": | |
| # --- IMPORTANT --- | |
| # You must define 'pipe' and 'tokenizer' before this line for the app to work. | |
| # For example, place the model loading code from the top of the script here. | |
| demo.launch() | |