Skidl / app.py
Arrcttacsrks's picture
Update app.py
e2a4d50 verified
raw
history blame contribute delete
4.85 kB
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)
def check_device_lib():
"""Check if device.lib exists in the current directory."""
current_dir = os.getcwd()
device_lib_path = os.path.join(current_dir, 'device.lib')
if os.path.exists(device_lib_path):
logger.info(f"Found device.lib in current directory: {device_lib_path}")
return True
logger.warning(f"device.lib not found in current directory: {current_dir}")
return False
def configure_skidl_libs():
"""Configure SKiDL to use device.lib from the current directory."""
current_dir = os.getcwd()
# Clear existing library search paths
lib_search_paths.clear()
# Assume lib_search_paths is a dict (newer SKiDL)
lib_key = getattr(skidl, 'LIB_SPICE', 'spice')
lib_search_paths[lib_key] = [current_dir]
logger.info(f"Using dict-based lib_search_paths with key '{lib_key}' and {current_dir}")
# Conditionally set default library if set_default_lib exists
try:
set_default_lib('Device')
logger.info("Set default library to Device using set_default_lib")
except NameError:
logger.info("set_default_lib not available; relying on lib_search_paths for Device library")
# Suppress KiCad warnings by setting dummy environment variables
os.environ['KICAD_SYMBOL_DIR'] = current_dir
os.environ['KICAD6_SYMBOL_DIR'] = current_dir
os.environ['KICAD7_SYMBOL_DIR'] = current_dir
os.environ['KICAD8_SYMBOL_DIR'] = current_dir
logger.info("Set dummy KiCad environment variables to suppress warnings")
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."""
if not skidl_code.strip():
return "Error: Empty code provided", None
reset()
tmp_path = None
try:
configure_skidl_libs()
if not check_device_lib():
return "Error: device.lib not found in the current directory. Please ensure it exists.", None
try:
compile(skidl_code, '<string>', 'exec')
except SyntaxError as e:
return f"Syntax Error: {e}", None
with tempfile.NamedTemporaryFile(delete=False, suffix='.py') as tmp:
tmp.write(skidl_code.encode('utf-8'))
tmp_path = tmp.name
namespace = {}
exec(open(tmp_path).read(), namespace)
netlist_str = generate_netlist()
if not netlist_str.strip():
return "Error: No netlist generated", None
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:
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 `device.lib` is in the same directory as this script to resolve components like resistors, LEDs, etc.
"""
)
# Example code: 5 LEDs with resistors
example_code = """
from skidl import *
vcc = Vcc()
gnd = Gnd()
leds = [Part('Device', 'LED', value='LED') for _ in range(5)]
resistors = [Part('Device', 'R', value='220') for _ in range(5)]
for r, led in zip(resistors, leds):
vcc & r & led & gnd
"""
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()