Spaces:
Sleeping
Sleeping
| import gradio as gr | |
| from skidl import * | |
| import tempfile | |
| import os | |
| import time | |
| import sys | |
| import logging | |
| # Set up logging | |
| logging.basicConfig(level=logging.INFO) | |
| logger = logging.getLogger(__name__) | |
| # Check for required dependencies | |
| try: | |
| import gradio | |
| import skidl | |
| except ImportError as e: | |
| print(f"Missing dependency: {e}") | |
| print("Please install requirements: pip install gradio skidl") | |
| sys.exit(1) | |
| # Check KiCad symbol directory environment variables | |
| def check_kicad_env(): | |
| """Check if KiCad symbol directory environment variables are set.""" | |
| kicad_vars = [ | |
| 'KICAD_SYMBOL_DIR', | |
| 'KICAD6_SYMBOL_DIR', | |
| 'KICAD7_SYMBOL_DIR', | |
| 'KICAD8_SYMBOL_DIR' | |
| ] | |
| missing = [var for var in kicad_vars if not os.environ.get(var)] | |
| if missing: | |
| logger.warning( | |
| f"Missing KiCad environment variables: {', '.join(missing)}. " | |
| "Set these to access default KiCad symbol libraries." | |
| ) | |
| return False | |
| return True | |
| # Set default symbol library path if not set | |
| def set_default_symbol_lib(): | |
| """Set a fallback symbol library path if environment variables are missing.""" | |
| if not check_kicad_env(): | |
| # Use a generic library or custom path (modify as needed) | |
| default_lib_path = os.path.expanduser("~/kicad_symbols") # Example path | |
| if os.path.exists(default_lib_path): | |
| os.environ['KICAD_SYMBOL_DIR'] = default_lib_path | |
| lib_search_paths.append(default_lib_path) | |
| logger.info(f"Set default symbol library path: {default_lib_path}") | |
| else: | |
| logger.warning( | |
| f"Default symbol library path {default_lib_path} not found. " | |
| "Parts may not be resolved without valid libraries." | |
| ) | |
| def cleanup_old_files(): | |
| """Clean up temporary files older than 1 hour.""" | |
| temp_dir = tempfile.gettempdir() | |
| for f in os.listdir(temp_dir): | |
| if f.endswith('.net') and os.path.getmtime(os.path.join(temp_dir, f)) < time.time() - 3600: | |
| try: | |
| os.remove(os.path.join(temp_dir, f)) | |
| except OSError: | |
| pass | |
| def generate_circuit(skidl_code): | |
| """Generate circuit netlist from SKiDL code.""" | |
| # Input validation | |
| if not skidl_code.strip(): | |
| return "Error: Empty code provided", None | |
| reset() # Reset SKiDL state | |
| tmp_path = None | |
| try: | |
| # Set default symbol library if needed | |
| set_default_symbol_lib() | |
| # Validate code syntax | |
| try: | |
| compile(skidl_code, '<string>', 'exec') | |
| except SyntaxError as e: | |
| return f"Syntax Error: {e}", None | |
| # Save code to temporary file | |
| with tempfile.NamedTemporaryFile(delete=False, suffix='.py') as tmp: | |
| tmp.write(skidl_code.encode('utf-8')) | |
| tmp_path = tmp.name | |
| # Execute code | |
| namespace = {} | |
| exec(open(tmp_path).read(), namespace) | |
| # Generate netlist | |
| netlist_str = generate_netlist() | |
| if not netlist_str.strip(): | |
| return "Error: No netlist generated", None | |
| # Save netlist to temporary file | |
| with tempfile.NamedTemporaryFile(delete=False, suffix='.net', mode='w') as out_file: | |
| out_file.write(netlist_str) | |
| netlist_file_path = out_file.name | |
| return "Netlist generated successfully!", netlist_file_path | |
| except SyntaxError as e: | |
| return f"Syntax Error: {e}", None | |
| except Exception as e: | |
| return f"Error: {str(e)}", None | |
| finally: | |
| # Clean up temporary file | |
| if tmp_path and os.path.exists(tmp_path): | |
| try: | |
| os.remove(tmp_path) | |
| except OSError: | |
| pass | |
| # Gradio UI | |
| with gr.Blocks() as demo: | |
| gr.Markdown( | |
| """ | |
| # SKiDL Circuit Builder (No KiCad Needed) | |
| **Note**: Ensure KiCad symbol libraries are accessible by setting `KICAD_SYMBOL_DIR` or other relevant environment variables. | |
| """ | |
| ) | |
| # Example code with explicit library (Device library for basic components) | |
| example_code = """ | |
| from skidl import * | |
| # Use Device library for basic components | |
| lib_search_paths.append('.') # Ensure local libraries are searchable | |
| set_default_lib('Device') # Use built-in Device library | |
| vcc = Vcc() | |
| gnd = Gnd() | |
| r1 = Part('Device', 'R', value='1k') # Explicitly use Device library | |
| c1 = Part('Device', 'C', value='1uF') | |
| r1[1] & c1 & gnd | |
| r1[2] & vcc | |
| """ | |
| skidl_input = gr.Textbox( | |
| label="Enter SKiDL Code Here", | |
| lines=20, | |
| placeholder=example_code | |
| ) | |
| output_message = gr.Textbox(label="Status / Error", interactive=False) | |
| download_btn = gr.File(label="Download Netlist (.net)") | |
| run_button = gr.Button("Build Circuit") | |
| run_button.click( | |
| fn=generate_circuit, | |
| inputs=[skidl_input], | |
| outputs=[output_message, download_btn] | |
| ) | |
| if __name__ == "__main__": | |
| cleanup_old_files() | |
| demo.launch() |