twarner commited on
Commit
ea62d29
·
1 Parent(s): 41a90c1

Simplify to gr.Interface, pin gradio version

Browse files
Files changed (2) hide show
  1. app.py +26 -130
  2. requirements.txt +2 -1
app.py CHANGED
@@ -1,17 +1,15 @@
1
  """dcode Gradio Space - Text to Gcode inference."""
2
 
3
  import re
4
- import tempfile
5
  import gradio as gr
6
  import torch
7
  from transformers import AutoModelForSeq2SeqLM, AutoTokenizer
8
 
9
- # Model config - update after training
10
- MODEL_ID = "twarner/dcode-flan-t5-base" # Will upload after training
11
 
12
  # Machine limits
13
  BOUNDS = {"left": -420.5, "right": 420.5, "top": 594.5, "bottom": -594.5}
14
- PEN = {"up": 90, "down": 40, "travel": 1000, "draw": 500}
15
 
16
 
17
  class GcodeGenerator:
@@ -52,14 +50,12 @@ class GcodeGenerator:
52
  for line in gcode.split("\n"):
53
  corrected = line
54
 
55
- # Clamp X
56
  x_match = re.search(r"X([-\d.]+)", line, re.IGNORECASE)
57
  if x_match:
58
  x = float(x_match.group(1))
59
  x = max(BOUNDS["left"], min(BOUNDS["right"], x))
60
  corrected = re.sub(r"X[-\d.]+", f"X{x:.2f}", corrected, flags=re.IGNORECASE)
61
 
62
- # Clamp Y
63
  y_match = re.search(r"Y([-\d.]+)", line, re.IGNORECASE)
64
  if y_match:
65
  y = float(y_match.group(1))
@@ -71,138 +67,38 @@ class GcodeGenerator:
71
  return "\n".join(lines)
72
 
73
 
74
- def gcode_to_svg(gcode: str) -> str:
75
- """Convert gcode to SVG for preview."""
76
- paths = []
77
- current_path = []
78
- x, y = 0, 0
79
- pen_down = False
80
-
81
- for line in gcode.split("\n"):
82
- line = line.strip()
83
- if not line or line.startswith(";"):
84
- continue
85
-
86
- # Pen state
87
- if "M280" in line:
88
- match = re.search(r"S(\d+)", line)
89
- if match:
90
- angle = int(match.group(1))
91
- was_down = pen_down
92
- pen_down = angle < 50
93
- if was_down and not pen_down and len(current_path) > 1:
94
- paths.append(current_path[:])
95
- current_path = []
96
-
97
- # Position
98
- x_match = re.search(r"X([-\d.]+)", line, re.IGNORECASE)
99
- y_match = re.search(r"Y([-\d.]+)", line, re.IGNORECASE)
100
- if x_match:
101
- x = float(x_match.group(1))
102
- if y_match:
103
- y = float(y_match.group(1))
104
-
105
- if (x_match or y_match) and pen_down:
106
- current_path.append((x, y))
107
-
108
- if len(current_path) > 1:
109
- paths.append(current_path)
110
-
111
- # Build SVG
112
- w = BOUNDS["right"] - BOUNDS["left"]
113
- h = BOUNDS["top"] - BOUNDS["bottom"]
114
-
115
- svg = f'<svg xmlns="http://www.w3.org/2000/svg" viewBox="{BOUNDS["left"]} {-BOUNDS["top"]} {w} {h}" style="background:#111">'
116
- svg += f'<rect x="{BOUNDS["left"]}" y="{-BOUNDS["top"]}" width="{w}" height="{h}" fill="none" stroke="#333" stroke-width="2"/>'
117
-
118
- for path in paths:
119
- if len(path) < 2:
120
- continue
121
- d = " ".join(f"{'M' if i == 0 else 'L'}{p[0]:.1f},{-p[1]:.1f}" for i, p in enumerate(path))
122
- svg += f'<path d="{d}" fill="none" stroke="#4ade80" stroke-width="1.5" stroke-linecap="round"/>'
123
-
124
- svg += "</svg>"
125
- return svg
126
-
127
-
128
- # Initialize generator
129
  generator = GcodeGenerator()
130
 
131
 
132
- def generate(prompt: str, temperature: float):
133
  """Generate gcode from prompt."""
134
- if not prompt.strip():
135
- return "", "", "Enter a prompt", None, None
136
 
137
  try:
138
  gcode = generator.generate(prompt, temperature=temperature)
139
- svg = gcode_to_svg(gcode)
140
- status = f" Generated {len(gcode.split(chr(10)))} lines, machine compatible"
141
-
142
- # Create temp files for download
143
- gcode_file = tempfile.NamedTemporaryFile(mode='w', suffix='.gcode', delete=False)
144
- gcode_file.write(gcode)
145
- gcode_file.close()
146
-
147
- svg_file = tempfile.NamedTemporaryFile(mode='w', suffix='.svg', delete=False)
148
- svg_file.write(svg)
149
- svg_file.close()
150
-
151
- return gcode, svg, status, gcode_file.name, svg_file.name
152
  except Exception as e:
153
- return "", "", f"Error: {e}", None, None
154
-
155
-
156
- # Custom CSS
157
- custom_css = """
158
- #workplane {
159
- background: #111;
160
- border-radius: 8px;
161
- min-height: 500px;
162
- }
163
- #workplane svg {
164
- width: 100%;
165
- height: 100%;
166
- }
167
- .status {
168
- font-family: monospace;
169
- }
170
- """
171
-
172
- # Gradio UI
173
- with gr.Blocks(css=custom_css, theme=gr.themes.Base(primary_hue="green")) as demo:
174
- gr.Markdown("# dcode\nText prompt → Polargraph Gcode")
175
-
176
- with gr.Row():
177
- with gr.Column(scale=2):
178
- prompt = gr.Textbox(label="Prompt", placeholder="drawing of a cat...", lines=1)
179
- temperature = gr.Slider(0.1, 1.5, value=0.8, label="Temperature")
180
- generate_btn = gr.Button("Generate", variant="primary")
181
-
182
- with gr.Column(scale=1):
183
- status = gr.Textbox(label="Status", interactive=False, elem_classes=["status"])
184
-
185
- with gr.Row():
186
- preview = gr.HTML(elem_id="workplane")
187
-
188
- with gr.Row():
189
- gcode_output = gr.Textbox(label="Gcode", lines=10, show_copy_button=True)
190
-
191
- with gr.Row():
192
- gcode_download = gr.File(label="Download Gcode")
193
- svg_download = gr.File(label="Download SVG")
194
-
195
- generate_btn.click(
196
- generate,
197
- [prompt, temperature],
198
- [gcode_output, preview, status, gcode_download, svg_download]
199
- )
200
- prompt.submit(
201
- generate,
202
- [prompt, temperature],
203
- [gcode_output, preview, status, gcode_download, svg_download]
204
- )
205
-
206
 
207
  if __name__ == "__main__":
208
  demo.launch()
 
1
  """dcode Gradio Space - Text to Gcode inference."""
2
 
3
  import re
 
4
  import gradio as gr
5
  import torch
6
  from transformers import AutoModelForSeq2SeqLM, AutoTokenizer
7
 
8
+ # Model config
9
+ MODEL_ID = "twarner/dcode-flan-t5-base"
10
 
11
  # Machine limits
12
  BOUNDS = {"left": -420.5, "right": 420.5, "top": 594.5, "bottom": -594.5}
 
13
 
14
 
15
  class GcodeGenerator:
 
50
  for line in gcode.split("\n"):
51
  corrected = line
52
 
 
53
  x_match = re.search(r"X([-\d.]+)", line, re.IGNORECASE)
54
  if x_match:
55
  x = float(x_match.group(1))
56
  x = max(BOUNDS["left"], min(BOUNDS["right"], x))
57
  corrected = re.sub(r"X[-\d.]+", f"X{x:.2f}", corrected, flags=re.IGNORECASE)
58
 
 
59
  y_match = re.search(r"Y([-\d.]+)", line, re.IGNORECASE)
60
  if y_match:
61
  y = float(y_match.group(1))
 
67
  return "\n".join(lines)
68
 
69
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
70
  generator = GcodeGenerator()
71
 
72
 
73
+ def generate(prompt: str, temperature: float) -> str:
74
  """Generate gcode from prompt."""
75
+ if not prompt or not prompt.strip():
76
+ return "Enter a prompt to generate gcode"
77
 
78
  try:
79
  gcode = generator.generate(prompt, temperature=temperature)
80
+ line_count = len(gcode.split("\n"))
81
+ return f"; dcode output - {line_count} lines\n; Machine validated\n\n{gcode}"
 
 
 
 
 
 
 
 
 
 
 
82
  except Exception as e:
83
+ return f"; Error: {e}"
84
+
85
+
86
+ demo = gr.Interface(
87
+ fn=generate,
88
+ inputs=[
89
+ gr.Textbox(label="Prompt", placeholder="drawing of a cat..."),
90
+ gr.Slider(0.1, 1.5, value=0.8, label="Temperature"),
91
+ ],
92
+ outputs=gr.Textbox(label="Gcode", lines=20, show_copy_button=True),
93
+ title="dcode",
94
+ description="Text prompt → Polargraph Gcode. Generate machine-compatible gcode from natural language descriptions.",
95
+ examples=[
96
+ ["drawing of a cat", 0.8],
97
+ ["abstract spiral pattern", 0.9],
98
+ ["simple house with chimney", 0.7],
99
+ ],
100
+ theme=gr.themes.Base(primary_hue="green"),
101
+ )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
102
 
103
  if __name__ == "__main__":
104
  demo.launch()
requirements.txt CHANGED
@@ -1,4 +1,5 @@
1
- gradio>=4.44.1
 
2
  torch>=2.0
3
  transformers>=4.36
4
  accelerate>=0.25
 
1
+ gradio==4.44.1
2
+ gradio_client==1.3.0
3
  torch>=2.0
4
  transformers>=4.36
5
  accelerate>=0.25