Thatguy099 commited on
Commit
be5436d
·
verified ·
1 Parent(s): ab9ee59

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +826 -0
app.py ADDED
@@ -0,0 +1,826 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import json
2
+ import os
3
+ import time
4
+ from inspect import signature
5
+
6
+ import huggingface_hub as hub
7
+
8
+ import gradio as gr
9
+ import gradio.utils
10
+ from gradio.sketch.sketchbox import SketchBox
11
+ from gradio.sketch.utils import ai, get_header, set_kwarg
12
+
13
+
14
+ def create(app_file: str, config_file: str):
15
+ file_name = os.path.basename(app_file)
16
+ folder_name = os.path.basename(os.path.dirname(app_file))
17
+ created_fns_namespace = {}
18
+
19
+ nonconfigurable_params = ["every", "inputs", "render", "key"]
20
+ default_kwargs_map = {
21
+ gr.Image: {"type": "filepath"},
22
+ gr.Audio: {"type": "filepath"},
23
+ gr.Chatbot: {"type": "messages"},
24
+ }
25
+
26
+ quick_component_list = [
27
+ gr.Textbox,
28
+ gr.Number,
29
+ gr.Button,
30
+ gr.Markdown,
31
+ gr.State,
32
+ ]
33
+ all_component_list = [
34
+ gr.AnnotatedImage,
35
+ # gr.Accordion,
36
+ gr.Audio,
37
+ gr.BarPlot,
38
+ gr.BrowserState,
39
+ gr.Button,
40
+ gr.Chatbot,
41
+ gr.Checkbox,
42
+ gr.CheckboxGroup,
43
+ gr.Code,
44
+ gr.ColorPicker,
45
+ gr.Dataframe,
46
+ gr.DateTime,
47
+ gr.Dropdown,
48
+ gr.File,
49
+ gr.Gallery,
50
+ gr.HighlightedText,
51
+ gr.HTML,
52
+ gr.Image,
53
+ gr.ImageEditor,
54
+ gr.JSON,
55
+ gr.Label,
56
+ gr.LinePlot,
57
+ gr.Markdown,
58
+ gr.Model3D,
59
+ gr.MultimodalTextbox,
60
+ gr.Number,
61
+ gr.Radio,
62
+ gr.Slider,
63
+ gr.State,
64
+ gr.Textbox,
65
+ gr.Timer,
66
+ gr.Video,
67
+ ]
68
+
69
+ def get_component_by_name(name):
70
+ return [
71
+ component for component in all_component_list if component.__name__ == name
72
+ ][0]
73
+
74
+ def get_box(_slot, i, gp=None):
75
+ parent = _slot
76
+ target = _slot[i[0]] if isinstance(_slot, list) and i[0] < len(_slot) else None
77
+ if len(i) > 1:
78
+ gp, parent, target = get_box(target, i[1:], parent)
79
+ return gp, parent, target
80
+
81
+ def add_component(
82
+ component, layout, components, dependencies, add_index, new_component_id
83
+ ):
84
+ gp, parent, _ = get_box(layout, add_index)
85
+ if isinstance(parent, int):
86
+ parent = [parent]
87
+ if gp:
88
+ gp[add_index[-2]] = parent
89
+ parent.insert(add_index[-1], new_component_id)
90
+ default_kwargs = default_kwargs_map.get(component, {}).copy()
91
+ components[new_component_id] = [component.__name__, default_kwargs, ""]
92
+
93
+ component_name = component.__name__.lower()
94
+ existing_names = [components[i][2] for i in components]
95
+ var_name = component_name
96
+ i = 2
97
+ while var_name in existing_names:
98
+ var_name = component_name + "_" + str(i)
99
+ i += 1
100
+ components[new_component_id][2] = var_name
101
+
102
+ return (
103
+ layout,
104
+ components,
105
+ dependencies,
106
+ "modify_component",
107
+ new_component_id,
108
+ new_component_id + 1,
109
+ gr.Button(interactive=True),
110
+ )
111
+
112
+ def set_hf_token(token):
113
+ try:
114
+ hub.login(token)
115
+ except BaseException as err:
116
+ raise gr.Error("Invalid Hugging Face token.") from err
117
+ gr.Success("Token set successfully.", duration=2)
118
+ return token
119
+
120
+ with gr.Blocks() as demo:
121
+ _id = gr.State(0)
122
+
123
+ # Below was giving issues, commenting out for now
124
+ # if os.path.exists(config_file):
125
+ # with open(config_file) as f:
126
+ # config = json.load(f)
127
+ # _layout = config["layout"]
128
+ # _components = {int(k): v for k, v in config["components"].items()}
129
+ # _new_component_id = len(_components)
130
+ # mode = gr.State("default")
131
+ # else:
132
+ _layout = []
133
+ _components = {}
134
+ _dependencies = []
135
+ _new_component_id = 0
136
+ mode = gr.State("add_component")
137
+
138
+ new_component_id = gr.State(_new_component_id)
139
+ components = gr.State(_components)
140
+ dependencies = gr.State(_dependencies)
141
+ layout = gr.State(_layout)
142
+ add_index = gr.State([_new_component_id])
143
+ modify_id = gr.State(None)
144
+ saved = gr.State(False)
145
+ hf_token = gr.State(hub.get_token() or os.getenv("HF_TOKEN"))
146
+ add_fn_btn = gr.Button(
147
+ "+ Add Function", scale=0, interactive=False, render=False
148
+ )
149
+
150
+ with gr.Sidebar() as left_sidebar:
151
+
152
+ @gr.render(
153
+ [
154
+ mode,
155
+ add_index,
156
+ new_component_id,
157
+ components,
158
+ dependencies,
159
+ modify_id,
160
+ hf_token,
161
+ ],
162
+ show_progress="hidden",
163
+ )
164
+ def render_sidebar(
165
+ _mode,
166
+ _add_index,
167
+ _new_component_id,
168
+ _components,
169
+ _dependencies,
170
+ _modify_id,
171
+ _hf_token,
172
+ ):
173
+ if _mode == "default" and len(_components) == 0:
174
+ _mode = "add_component"
175
+ _add_index = [0]
176
+ if _mode == "default":
177
+ gr.Markdown("## Placement")
178
+ gr.Markdown("Click on a '+' button to add a component.")
179
+ if _mode == "add_component":
180
+ gr.Markdown("## Selection")
181
+ if len(_components) == 0:
182
+ gr.Markdown("Select first component to place.")
183
+ else:
184
+ gr.Markdown("Select component to place in selected area.")
185
+ for component in quick_component_list:
186
+ gr.Button(component.__name__, size="md").click(
187
+ lambda _layout, _component=component: add_component(
188
+ _component,
189
+ _layout,
190
+ _components,
191
+ _dependencies,
192
+ _add_index,
193
+ _new_component_id,
194
+ ),
195
+ layout,
196
+ [
197
+ layout,
198
+ components,
199
+ dependencies,
200
+ mode,
201
+ modify_id,
202
+ new_component_id,
203
+ add_fn_btn,
204
+ ],
205
+ )
206
+
207
+ any_component_search = gr.Dropdown(
208
+ [component.__name__ for component in all_component_list],
209
+ container=True,
210
+ label="Other Components...",
211
+ interactive=True,
212
+ )
213
+ any_component_search.change(
214
+ lambda _component, _layout: add_component(
215
+ get_component_by_name(_component),
216
+ _layout,
217
+ _components,
218
+ _dependencies,
219
+ _add_index,
220
+ _new_component_id,
221
+ ),
222
+ [any_component_search, layout],
223
+ [
224
+ layout,
225
+ components,
226
+ dependencies,
227
+ mode,
228
+ modify_id,
229
+ new_component_id,
230
+ add_fn_btn,
231
+ ],
232
+ )
233
+ if _mode == "modify_component":
234
+ component_name, kwargs, var_name = _components[_modify_id]
235
+ gr.Markdown(
236
+ "## Configuration\nHover over a component to add new components when done configuring."
237
+ )
238
+
239
+ var_name_box = gr.Textbox(var_name, label="Variable Name")
240
+
241
+ def set_var_name(name):
242
+ _components[_modify_id][2] = name
243
+ return _components
244
+
245
+ gr.on(
246
+ [var_name_box.blur, var_name_box.submit],
247
+ set_var_name,
248
+ var_name_box,
249
+ components,
250
+ )
251
+
252
+ gr.Markdown(
253
+ 'Set args below with python syntax, e.g. `True`, `5`, or `["choice1", "choice2"]`.'
254
+ )
255
+
256
+ component = get_component_by_name(component_name)
257
+ arguments = list(signature(component.__init__).parameters.keys())[
258
+ 1:
259
+ ]
260
+ for arg in arguments:
261
+ if arg in nonconfigurable_params:
262
+ continue
263
+ arg_value = kwargs.get(arg, "")
264
+ arg_box = gr.Textbox(
265
+ arg_value,
266
+ label=arg,
267
+ info=f"<a href='https://www.gradio.app/docs/gradio/{component_name.lower()}#param-{component_name.lower()}-{arg.lower().replace('_', '-')}' target='_blank'>docs</a>",
268
+ )
269
+
270
+ def set_arg(value, arg=arg):
271
+ set_kwarg(_components[_modify_id][1], arg, value)
272
+ return _components
273
+
274
+ gr.on(
275
+ [arg_box.blur, arg_box.submit], set_arg, arg_box, components
276
+ )
277
+ if _mode == "modify_function":
278
+ dep = _dependencies[_modify_id]
279
+ _triggers, _inputs, _outputs, var_name, _history, _code = dep
280
+ gr.Markdown("## Event Listeners")
281
+ function_name_box = gr.Textbox(var_name, label="Function Name")
282
+
283
+ def set_fn_name(name):
284
+ dep[3] = name
285
+ return _dependencies
286
+
287
+ gr.on(
288
+ [function_name_box.blur, function_name_box.submit],
289
+ set_fn_name,
290
+ function_name_box,
291
+ dependencies,
292
+ )
293
+
294
+ gr.Markdown(
295
+ "Mark the components in the diagram as inputs or outputs, and select their triggers. Then use the code generator below."
296
+ )
297
+
298
+ if not _hf_token:
299
+ input_hf_token = gr.Textbox(
300
+ label="HF Token",
301
+ info="Needed for code generation. Copy from [HF Token Page](https://huggingface.co/settings/token). Token requires access to inference providers.",
302
+ type="password",
303
+ )
304
+ submit_token_btn = gr.Button("Submit Token", size="md")
305
+ submit_token_btn.click(set_hf_token, input_hf_token, hf_token)
306
+ else:
307
+ new_prompt_placeholder = "Describe what the function should do."
308
+ edit_prompt_placeholder = "Describe how to change the code generation. Click 'Reset Code' to start over."
309
+ history_exists = len(_history) > 0
310
+ prompt = gr.Textbox(
311
+ label="Prompt",
312
+ lines=3,
313
+ placeholder=edit_prompt_placeholder
314
+ if history_exists
315
+ else new_prompt_placeholder,
316
+ interactive=True,
317
+ )
318
+ no_components_are_set = (
319
+ len(_dependencies[_modify_id][1])
320
+ == 0 + len(_dependencies[_modify_id][2])
321
+ == 0
322
+ )
323
+ if no_components_are_set:
324
+ gr.Markdown(
325
+ "Set **all inputs and outputs** before generating code."
326
+ )
327
+ new_generate_text = "Generate Code"
328
+ update_generate_text = "Update Code"
329
+ generate_code_btn = gr.Button(
330
+ update_generate_text
331
+ if history_exists
332
+ else new_generate_text,
333
+ size="md",
334
+ interactive=not no_components_are_set,
335
+ )
336
+ reset_code_btn = gr.Button(
337
+ "Reset Code", size="md", visible=history_exists
338
+ )
339
+
340
+ __inputs = [_components[c][2] for c in _inputs]
341
+ __outputs = [_components[c][2] for c in _outputs]
342
+ _code = (
343
+ _code
344
+ if _code is not None
345
+ else f"""{get_header(var_name, __inputs)}
346
+ ...
347
+ return {", ".join(["..." for _ in __outputs])}"""
348
+ )
349
+ fn_code = gr.Code(_code, lines=4, language="python")
350
+ save_code_btn = gr.Button("Save Code", size="md")
351
+ history = gr.JSON(_history, visible=False)
352
+
353
+ def generate(_prompt, _history):
354
+ yield from ai(
355
+ _history + [[_prompt, None]],
356
+ _hf_token,
357
+ var_name,
358
+ [
359
+ (
360
+ _components[c][2],
361
+ get_component_by_name(_components[c][0]),
362
+ _components[c][1],
363
+ )
364
+ for c in _inputs
365
+ ],
366
+ [
367
+ (
368
+ get_component_by_name(_components[c][0]),
369
+ _components[c][1],
370
+ )
371
+ for c in _outputs
372
+ ],
373
+ )
374
+
375
+ def append_to_history(
376
+ history: list[tuple[str, str]], prompt: str, code: str
377
+ ):
378
+ history.append((prompt, code))
379
+ return (
380
+ history,
381
+ gr.Button(visible=True),
382
+ gr.Textbox(
383
+ value="", placeholder=edit_prompt_placeholder
384
+ ),
385
+ gr.Button(update_generate_text),
386
+ )
387
+
388
+ generate_code_btn.click(
389
+ generate, [prompt, history], fn_code
390
+ ).then(
391
+ append_to_history,
392
+ [history, prompt, fn_code],
393
+ [history, reset_code_btn, prompt, generate_code_btn],
394
+ show_progress="hidden",
395
+ )
396
+
397
+ def reset_code(_dependencies, _modify_id):
398
+ _dependencies[_modify_id][4] = []
399
+ _dependencies[_modify_id][5] = None
400
+ return (
401
+ get_header(var_name, __inputs),
402
+ gr.Button(visible=False),
403
+ gr.Textbox(placeholder=new_prompt_placeholder),
404
+ gr.Button(new_generate_text),
405
+ [],
406
+ _dependencies,
407
+ )
408
+
409
+ reset_code_btn.click(
410
+ reset_code,
411
+ [dependencies, modify_id],
412
+ [
413
+ fn_code,
414
+ reset_code_btn,
415
+ prompt,
416
+ generate_code_btn,
417
+ history,
418
+ dependencies,
419
+ ],
420
+ )
421
+
422
+ def save_code(_history, _code):
423
+ try:
424
+ exec(_code, created_fns_namespace)
425
+ except BaseException as e:
426
+ raise gr.Error(f"Error saving function: {e}") from e
427
+ if var_name not in created_fns_namespace:
428
+ raise gr.Error(
429
+ f"Function '{var_name}' not found in code."
430
+ )
431
+ dep[4] = (
432
+ []
433
+ if len(_history) == 0
434
+ else _history[:-1] + [[_history[-1][0], _code]]
435
+ )
436
+ dep[5] = _code
437
+ gr.Success("Function saved.", duration=2)
438
+ return _dependencies
439
+
440
+ save_code_btn.click(save_code, [history, fn_code], dependencies)
441
+
442
+ done_function_btn = gr.Button("Done", variant="primary", size="md")
443
+ done_function_btn.click(
444
+ lambda: ["default", None], None, [mode, modify_id]
445
+ )
446
+ del_function_btn = gr.Button(
447
+ "Delete Function", variant="stop", size="md"
448
+ )
449
+
450
+ def del_function():
451
+ del _dependencies[_modify_id]
452
+ return _dependencies, "default", None
453
+
454
+ del_function_btn.click(
455
+ del_function, None, [dependencies, mode, modify_id]
456
+ )
457
+
458
+ with gr.Row():
459
+ gr.Markdown("## Sketching '" + folder_name + "/" + file_name + "'")
460
+ add_fn_btn.render()
461
+ save_btn = gr.Button("Save & Render", variant="primary", scale=0)
462
+
463
+ deploy_to_spaces_btn = gr.Button(
464
+ "Deploy to Spaces",
465
+ visible=False,
466
+ scale=0,
467
+ min_width=240,
468
+ icon=gradio.utils.get_icon_path("huggingface-logo.svg"),
469
+ )
470
+
471
+ @gr.render(
472
+ [layout, components, dependencies, saved, modify_id, mode],
473
+ show_progress="hidden",
474
+ )
475
+ def app(_layout, _components, _dependencies, saved, _modify_id, _mode):
476
+ boxes = []
477
+ rendered_components = {}
478
+ function_mode = _mode == "modify_function"
479
+
480
+ def render_slot(slot, is_column, index, depth=1):
481
+ container = gr.Column() if is_column else gr.Row()
482
+ with container:
483
+ for i, element in enumerate(slot):
484
+ this_index = index + [i]
485
+ if isinstance(element, list):
486
+ if saved:
487
+ render_slot(
488
+ element, not is_column, this_index, depth + 1
489
+ )
490
+ else:
491
+ with SketchBox(
492
+ is_container=True, function_mode=function_mode
493
+ ) as box:
494
+ render_slot(
495
+ element, not is_column, this_index, depth + 1
496
+ )
497
+ boxes.append((box, this_index))
498
+ continue
499
+ component_name, kwargs, var_name = _components[element]
500
+ component = get_component_by_name(component_name)
501
+ if saved:
502
+ rendered_components[element] = component(**kwargs)
503
+ else:
504
+ if function_mode:
505
+ triggers = [
506
+ t
507
+ for c, t in _dependencies[_modify_id][0]
508
+ if c == element
509
+ ]
510
+ is_input = element in _dependencies[_modify_id][1]
511
+ is_output = element in _dependencies[_modify_id][2]
512
+ else:
513
+ triggers = None
514
+ is_input = False
515
+ is_output = False
516
+ with SketchBox(
517
+ component_type=component.__name__.lower(),
518
+ var_name=var_name,
519
+ active=_modify_id == element and not function_mode,
520
+ function_mode=function_mode,
521
+ event_list=component.EVENTS
522
+ if hasattr(component, "EVENTS")
523
+ else None,
524
+ is_input=is_input,
525
+ is_output=is_output,
526
+ triggers=triggers,
527
+ ) as box:
528
+ component(**kwargs)
529
+ boxes.append((box, this_index))
530
+
531
+ render_slot(_layout, True, [])
532
+
533
+ for box, index in boxes:
534
+
535
+ def box_action(
536
+ _layout,
537
+ _components,
538
+ _dependencies,
539
+ _modify_id,
540
+ data: gr.SelectData,
541
+ index=index,
542
+ ):
543
+ if data.value in ("up", "down", "left", "right"):
544
+ if len(index) % 2 == 1: # vertical
545
+ if data.value == "down":
546
+ index[-1] += 1
547
+ elif data.value == "left":
548
+ index.append(0)
549
+ elif data.value == "right":
550
+ index.append(1)
551
+ elif data.value == "right":
552
+ index[-1] += 1
553
+ elif data.value == "up":
554
+ index.append(0)
555
+ elif data.value == "down":
556
+ index.append(1)
557
+ return (
558
+ _layout,
559
+ _components,
560
+ _dependencies,
561
+ "add_component",
562
+ index,
563
+ None,
564
+ )
565
+ if data.value == "delete":
566
+
567
+ def delete_index(_layout, index):
568
+ gp, parent, target = get_box(_layout, index)
569
+ parent.remove(target)
570
+ if isinstance(target, int):
571
+ del _components[target]
572
+
573
+ if len(parent) == 0 and len(index) > 1:
574
+ delete_index(_layout, index[:-1])
575
+ elif len(parent) == 1 and gp:
576
+ gp[index[-2]] = parent[0]
577
+
578
+ delete_index(_layout, index)
579
+ if len(_layout) == 0:
580
+ return (
581
+ _layout,
582
+ _components,
583
+ _dependencies,
584
+ "add_component",
585
+ [0],
586
+ None,
587
+ )
588
+ else:
589
+ return (
590
+ _layout,
591
+ _components,
592
+ _dependencies,
593
+ "default",
594
+ [],
595
+ None,
596
+ )
597
+ if data.value == "modify":
598
+ *_, target = get_box(_layout, index)
599
+ return (
600
+ _layout,
601
+ _components,
602
+ _dependencies,
603
+ "modify_component",
604
+ None,
605
+ target,
606
+ )
607
+ if data.value in ["input", "output"]:
608
+ *_, target = get_box(_layout, index)
609
+ component_list = _dependencies[_modify_id][
610
+ 1 if data.value == "input" else 2
611
+ ]
612
+ if target in component_list:
613
+ component_list.remove(target)
614
+ else:
615
+ component_list.append(target)
616
+ return (
617
+ _layout,
618
+ _components,
619
+ _dependencies,
620
+ "modify_function",
621
+ None,
622
+ _modify_id,
623
+ )
624
+ if data.value.startswith("on:"):
625
+ *_, target = get_box(_layout, index)
626
+ event = data.value[3:]
627
+ triggers = _dependencies[_modify_id][0]
628
+ if (target, event) in triggers:
629
+ triggers.remove((target, event))
630
+ else:
631
+ triggers.append((target, event))
632
+ return (
633
+ _layout,
634
+ _components,
635
+ _dependencies,
636
+ "modify_function",
637
+ None,
638
+ _modify_id,
639
+ )
640
+
641
+ box.select(
642
+ box_action,
643
+ [layout, components, dependencies, modify_id],
644
+ [layout, components, dependencies, mode, add_index, modify_id],
645
+ )
646
+
647
+ if saved:
648
+ for triggers, inputs, outputs, fn_name, *_, code in _dependencies:
649
+ rendered_triggers = [
650
+ getattr(rendered_components[c], t) for c, t in triggers
651
+ ]
652
+ rendered_inputs = [rendered_components[c] for c in inputs]
653
+ rendered_outputs = [rendered_components[c] for c in outputs]
654
+ if code:
655
+ try:
656
+ gr.on(
657
+ rendered_triggers,
658
+ created_fns_namespace[fn_name],
659
+ rendered_inputs,
660
+ rendered_outputs,
661
+ )
662
+ except Exception:
663
+ pass
664
+ else:
665
+ output_count = len(rendered_outputs)
666
+ fn_output = (
667
+ [gr.skip()] * output_count
668
+ if output_count > 1
669
+ else gr.skip()
670
+ if output_count == 1
671
+ else None
672
+ )
673
+
674
+ def sleep(*_):
675
+ print("sleeping")
676
+ time.sleep(1)
677
+ return fn_output
678
+
679
+ gr.on(
680
+ rendered_triggers, sleep, rendered_inputs, rendered_outputs
681
+ )
682
+
683
+ with gr.Sidebar(position="right", open=False) as right_sidebar:
684
+ gr.Markdown("## Functions")
685
+
686
+ @gr.render([dependencies], show_progress="hidden")
687
+ def render_deps(_dependencies):
688
+ for i, dep in enumerate(_dependencies):
689
+ fn_btn = gr.Button(dep[3], size="md")
690
+
691
+ def load_fn(i=i):
692
+ return "modify_function", i
693
+
694
+ fn_btn.click(load_fn, outputs=[mode, modify_id])
695
+
696
+ def add_fn(_dependencies):
697
+ _dependencies.append(
698
+ [[], [], [], f"fn_{len(_dependencies) + 1}", [], None]
699
+ )
700
+ return (
701
+ _dependencies,
702
+ "modify_function",
703
+ len(_dependencies) - 1,
704
+ gr.Sidebar(open=True),
705
+ )
706
+
707
+ add_fn_btn.click(
708
+ add_fn, dependencies, [dependencies, mode, modify_id, right_sidebar]
709
+ )
710
+
711
+ gr.Markdown("## Generated File")
712
+ code = gr.Code(language="python", interactive=False, show_label=False)
713
+
714
+ @gr.on(
715
+ inputs=[layout, components, dependencies],
716
+ outputs=code,
717
+ show_progress="hidden",
718
+ )
719
+ def render_code(_layout, _components, _dependencies):
720
+ code_str = ""
721
+
722
+ def render_code_slot(slot, is_column, index, depth=1):
723
+ nonlocal code_str
724
+ for i, element in enumerate(slot):
725
+ this_index = index + [i]
726
+ if isinstance(element, list):
727
+ code_str += (
728
+ " " * depth
729
+ + "with gr."
730
+ + ("Row" if is_column else "Column")
731
+ + "():\n"
732
+ )
733
+ render_code_slot(
734
+ element, not is_column, this_index, depth + 1
735
+ )
736
+ continue
737
+ component_name, kwargs, var_name = _components[element]
738
+ code_str += (
739
+ " " * depth + var_name + " = gr." + component_name + "("
740
+ )
741
+ for i, (k, v) in enumerate(kwargs.items()):
742
+ v = (
743
+ f'"{v}"'.replace("\n", "\\n")
744
+ if isinstance(v, str)
745
+ else v
746
+ )
747
+ if i != 0:
748
+ code_str += ", "
749
+ code_str += f"{k}={v}"
750
+ code_str += ")\n"
751
+
752
+ render_code_slot(_layout, True, [])
753
+
754
+ for dep in _dependencies:
755
+ triggers = [_components[c][2] + "." + t for c, t in dep[0]]
756
+ inputs = [_components[c][2] for c in dep[1]]
757
+ outputs = [_components[c][2] for c in dep[2]]
758
+ fn_name = dep[3]
759
+ if dep[5] is not None:
760
+ fn_code = dep[5].replace("\n", "\n ")
761
+ else:
762
+ fn_code = f"""def {fn_name}({", ".join(inputs)}):
763
+ ...
764
+ return {", ".join(["..." for _ in outputs])}"""
765
+
766
+ code_str += f"""
767
+ @{triggers[0] + "(" if len(triggers) == 1 else "gr.on([" + ", ".join(triggers) + "], "}inputs=[{", ".join(inputs)}], outputs=[{", ".join(outputs)}])
768
+ {fn_code}
769
+ """
770
+ code_str = f"""import gradio as gr
771
+
772
+ with gr.Blocks() as demo:
773
+ {code_str}
774
+ demo.launch()"""
775
+ return code_str
776
+
777
+ @save_btn.click(
778
+ inputs=[saved, code, dependencies],
779
+ outputs=[
780
+ saved,
781
+ save_btn,
782
+ add_fn_btn,
783
+ deploy_to_spaces_btn,
784
+ mode,
785
+ left_sidebar,
786
+ right_sidebar,
787
+ ],
788
+ show_progress="hidden",
789
+ )
790
+ def save(saved, code, deps):
791
+ with open(app_file, "w") as f:
792
+ f.write(code)
793
+ with open(config_file, "w") as f:
794
+ json.dump(
795
+ {
796
+ "layout": _layout,
797
+ "components": _components,
798
+ },
799
+ f,
800
+ )
801
+ return [
802
+ not saved,
803
+ "Save & Render" if saved else "Edit Sketch",
804
+ gr.Button(visible=saved),
805
+ gr.Button(visible=not saved),
806
+ "default",
807
+ gr.Sidebar(open=saved),
808
+ gr.Sidebar(open=saved and len(deps) > 0),
809
+ ]
810
+
811
+ deploy_to_spaces_btn.click(
812
+ fn=None,
813
+ inputs=code,
814
+ js="""(code) => {
815
+ code = encodeURIComponent(code);
816
+ url = `https://huggingface.co/new-space?name=new-space&sdk=gradio&files[0][path]=app.py&files[0][content]=${code}`
817
+ window.open(url, '_blank')
818
+ }""",
819
+ )
820
+
821
+ return demo
822
+
823
+
824
+ if __name__ == "__main__":
825
+ demo = create("app.py", "app.json")
826
+ demo.launch()