import gradio as gr import math import itertools import ezdxf import os import groq from ezdxf import zoom from ezdxf.enums import TextEntityAlignment # Initialize Groq client client = groq.Client(api_key=os.getenv("GROQ_API_KEY")) # Available Capacitor Units (kVAR) available_capacitors = [25, 20, 15, 10, 5, 2.5, 1.5, 1] # Prompt Groq for explanation (optional) def ask_groq(prompt): try: response = client.chat.completions.create( model="llama3-8b-8192", messages=[{"role": "user", "content": prompt}] ) return response.choices[0].message.content except Exception as e: return f"Groq Error: {str(e)}" def calculate_power_parameters(voltage, current, power_factor): if voltage > 0 and current > 0: apparent_power = math.sqrt(3) * voltage * current real_power = apparent_power * power_factor / 1000 try: reactive_power = math.sqrt((apparent_power / 1000) ** 2 - real_power ** 2) except ValueError: reactive_power = 0.0 calculated_pf = real_power * 1000 / apparent_power if apparent_power > 0 else 0 return { "apparent_power": round(apparent_power, 2), "real_power": round(real_power, 2), "reactive_power": round(reactive_power, 2), "calculated_pf": round(calculated_pf, 2) } else: return None def design_capacitor_bank(reactive_power, num_caps): if reactive_power > 0 and num_caps > 0: best_combo = None min_error = float('inf') # Allow repetition freely to match reactive power combos = itertools.combinations_with_replacement(available_capacitors, num_caps) for combo in combos: total = sum(combo) error = abs(total - reactive_power) if error < min_error: min_error = error best_combo = combo if error == 0: break if best_combo: suggested_capacitors = [f"{cap} kVAR" for cap in best_combo] total_kvar = sum(best_combo) message = f"Total Compensation: {round(total_kvar, 2)} kVAR" return { "suggested_capacitors": suggested_capacitors, "total_kvar": round(total_kvar, 2), "message": message, "combo": best_combo } else: return {"message": "Could not find a suitable combination."} else: return None def create_dxf_capacitor_bank(capacitors): doc = ezdxf.new() msp = doc.modelspace() x = 0 y = 0 row_width = 15 # Distance between capacitors in a row row_height = 20 max_in_row = 5 for idx, cap in enumerate(capacitors): label = f"{cap} kVAR" # Draw rectangle for capacitor points = [(x, y), (x + 10, y), (x + 10, y + 10), (x, y + 10), (x, y)] msp.add_lwpolyline(points, close=True, dxfattribs={'color': 3}) # Color 3 = Green # Add Text with more control text = msp.add_text(label, dxfattribs={ 'height': 2.5, 'color': 4, # color Cyan 'style': 'STANDARD', # You can define text styles in DXF 'halign': TextEntityAlignment.CENTER, # Horizontal alignment 'valign': TextEntityAlignment.BOTTOM if hasattr(TextEntityAlignment, 'BOTTOM') else 2, }) text.dxf.insert = (x + 5, y + 5) # Position at center of rectangle x += row_width if (idx + 1) % max_in_row == 0: # Move to the next row x = 0 y += row_height # Add a title title_text = msp.add_text("Capacitor Bank Layout", dxfattribs={'height': 5, 'color': 1}) title_text.dxf.insert = (0, y + 30) # Zoom to extents zoom.extents(msp, factor=1.1) # Add a small padding output_path = "capacitor_bank_layout.dxf" doc.saveas(output_path) return output_path def reactive_power_first(voltage, current, power_factor): power_results = calculate_power_parameters(voltage, current, power_factor) if power_results: apparent_power_out = f"Apparent Power: **{power_results['apparent_power']} VA**" real_power_out = f"Real Power: **{power_results['real_power']} kW**" reactive_power_out = f"Reactive Power: **{power_results['reactive_power']} kVAR**" calculated_pf_out = f"Calculated Power Factor: **{power_results['calculated_pf']}**" return ( apparent_power_out, real_power_out, reactive_power_out, calculated_pf_out, power_results['reactive_power'] ) else: return ("⚠️ Please enter valid Voltage and Current!", "", "", "", 0) def finalize_capacitor_bank(reactive_power, num_caps): cap_bank_design = design_capacitor_bank(reactive_power, num_caps) if cap_bank_design and cap_bank_design.get("suggested_capacitors"): suggested_capacitors_text = "
".join( [f"🔹 Capacitor {idx + 1}: **{cap}**" for idx, cap in enumerate(cap_bank_design['suggested_capacitors'])] ) dxf_path = create_dxf_capacitor_bank(cap_bank_design["combo"]) return suggested_capacitors_text, cap_bank_design['message'], dxf_path else: return "Could not find a suitable combination.", "", None with gr.Blocks() as iface: gr.Markdown("# ⚡ Three-Phase Power Calculator - Reactive Power Compensation") gr.Markdown(""" Step 1: Enter system parameters to calculate apparent and reactive power.
Step 2: Input number of capacitors to compute optimal configuration.
Step 3: Download AutoCAD (.dxf) layout. """) with gr.Row(): voltage = gr.Number(label="Enter Voltage (V)", value=415) current = gr.Number(label="Enter Current (A)", value=250) power_factor = gr.Slider(label="Power Factor", minimum=0.0, maximum=1.0, value=0.85, step=0.01) frequency = gr.Radio(label="Select Frequency", choices=[50, 60], value=50) calc_btn = gr.Button("🔍 Calculate Power Parameters") apparent_power_out = gr.HTML() real_power_out = gr.HTML() reactive_power_out = gr.HTML() calculated_pf_out = gr.HTML() reactive_value = gr.Number(visible=False) calc_btn.click( fn=reactive_power_first, inputs=[voltage, current, power_factor], outputs=[ apparent_power_out, real_power_out, reactive_power_out, calculated_pf_out, reactive_value ] ) gr.Markdown("### ➕ Enter number of capacitors to compensate reactive power:") num_caps_input = gr.Number(label="Number of Capacitors", precision=0) finalize_btn = gr.Button("⚙️ Generate Capacitor Bank") capacitor_out = gr.HTML() total_comp_out = gr.HTML() dxf_file = gr.File(label="📥 Download AutoCAD File") finalize_btn.click( fn=finalize_capacitor_bank, inputs=[reactive_value, num_caps_input], outputs=[capacitor_out, total_comp_out, dxf_file] ) if __name__ == "__main__": iface.launch()