lgaleana commited on
Commit
9f68e0d
1 Parent(s): 78dfff8

Introduce task groupings and fix adding/removing task

Browse files
Files changed (4) hide show
  1. actions.py +45 -24
  2. app.py +23 -8
  3. components.py +96 -16
  4. requirements.txt +2 -1
actions.py CHANGED
@@ -1,8 +1,9 @@
1
  import re
 
2
 
3
  import gradio as gr
4
 
5
- from components import all_inputs, all_tasks, Input, MAX_INPUTS, MAX_TASKS, Task
6
 
7
 
8
  def add_input(*visibility):
@@ -27,34 +28,56 @@ def remove_input(*visibility):
27
  )
28
 
29
 
30
- def add_task(*visibility):
31
- for i, visible in enumerate(visibility, 1):
32
- if not bool(visible):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
33
  return (
34
- [gr.Box.update(visible=True)] * i
35
- + [gr.Box.update(visible=False)] * (MAX_TASKS - i)
36
- + [1] * i
37
- + [0] * (MAX_TASKS - i)
 
 
38
  )
39
 
40
 
41
  def remove_task(*visibility):
42
- for i, visible in reversed(list(enumerate(visibility, 1))):
43
- if bool(visible):
 
 
 
 
 
 
 
 
 
 
44
  return (
45
- [gr.Box.update(visible=True)] * (i - 1)
46
- + [gr.Box.update(visible=False)] * (MAX_TASKS - i + 1)
47
- + [1] * (i - 1)
48
- + [0] * (MAX_TASKS - i + 1)
49
  )
50
 
51
 
52
- def _get_all_vars_up_to(to: int):
53
- return [in_.output for in_ in all_inputs.values()] + [
54
- t.output for i, t in all_tasks.items() if i < to
55
- ]
56
-
57
-
58
  def _clear_error():
59
  return gr.HighlightedText.update(value=None, visible=False)
60
 
@@ -75,11 +98,9 @@ def execute_task(id_: int, prev_error_value, n_inputs, *vars_in_scope):
75
 
76
  # Put all defined variables into a dict, with names (except task inputs)
77
  vars = {
78
- f"{Input.vname}{i}": input_ for i, input_ in enumerate(input_vars) if input_
79
  }
80
- vars.update(
81
- {f"{Task.vname}{i}": task for i, task in enumerate(task_outputs)}
82
- )
83
  # Get all variables referenced within the task inputs
84
  prompt_vars = {v for ti in non_empty_task_inputs for v in re.findall("{(.*?)}", ti)}
85
 
 
1
  import re
2
+ from typing import List
3
 
4
  import gradio as gr
5
 
6
+ from components import all_tasks, Input, MAX_INPUTS, MAX_TASKS, Task
7
 
8
 
9
  def add_input(*visibility):
 
28
  )
29
 
30
 
31
+ def _is_task_row_fully_invisible(row: List[int]) -> bool:
32
+ print(row)
33
+ for visible in row:
34
+ if bool(visible):
35
+ return False
36
+ return True
37
+
38
+
39
+ def add_task(index, *visibility):
40
+ visibility = list(visibility)
41
+ n_avail_tasks = len(Task.AVAILABLE_TASKS)
42
+
43
+ for i in range(MAX_TASKS):
44
+ start_row = i * n_avail_tasks
45
+ is_row_invisible = _is_task_row_fully_invisible(
46
+ visibility[start_row : start_row + n_avail_tasks]
47
+ )
48
+ if is_row_invisible:
49
+ unchanged_up_to = start_row + index
50
  return (
51
+ [gr.Box.update()] * unchanged_up_to
52
+ + [gr.Box.update(visible=True)]
53
+ + [gr.Box.update()] * (len(visibility) - unchanged_up_to - 1)
54
+ + [gr.Number.update()] * unchanged_up_to
55
+ + [1]
56
+ + [gr.Number.update()] * (len(visibility) - unchanged_up_to - 1)
57
  )
58
 
59
 
60
  def remove_task(*visibility):
61
+ visibility = list(visibility)
62
+ n_avail_tasks = len(Task.AVAILABLE_TASKS)
63
+ print(visibility, n_avail_tasks)
64
+
65
+ for i in range(MAX_TASKS):
66
+ start_row = i * n_avail_tasks
67
+ is_row_invisible = _is_task_row_fully_invisible(
68
+ visibility[start_row : start_row + n_avail_tasks]
69
+ )
70
+ print(start_row, start_row + n_avail_tasks, is_row_invisible)
71
+ if is_row_invisible:
72
+ unchanged_up_to = start_row - n_avail_tasks
73
  return (
74
+ [gr.Box.update()] * unchanged_up_to
75
+ + [gr.Box.update(visible=False)] * (len(visibility) - unchanged_up_to)
76
+ + [gr.Number.update()] * unchanged_up_to
77
+ + [0] * (len(visibility) - unchanged_up_to)
78
  )
79
 
80
 
 
 
 
 
 
 
81
  def _clear_error():
82
  return gr.HighlightedText.update(value=None, visible=False)
83
 
 
98
 
99
  # Put all defined variables into a dict, with names (except task inputs)
100
  vars = {
101
+ f"{Input.VNAME}{i}": input_ for i, input_ in enumerate(input_vars) if input_
102
  }
103
+ vars.update({f"{Task.VNAME}{i}": task for i, task in enumerate(task_outputs)})
 
 
104
  # Get all variables referenced within the task inputs
105
  prompt_vars = {v for ti in non_empty_task_inputs for v in re.findall("{(.*?)}", ti)}
106
 
app.py CHANGED
@@ -1,7 +1,13 @@
1
  import gradio as gr
2
 
3
  import actions as a
4
- from components import all_inputs, all_tasks
 
 
 
 
 
 
5
 
6
 
7
  with gr.Blocks() as demo:
@@ -11,6 +17,7 @@ with gr.Blocks() as demo:
11
  # Toolkit
12
  Define input variables to be used in your tasks.
13
  <br>Task outputs can be used in subsequent tasks.
 
14
  <br>
15
  <br>AI tasks call into ChatGPT to perform actions.
16
  <br>Chain inputs and tasks to build an E2E application.
@@ -25,6 +32,12 @@ with gr.Blocks() as demo:
25
  remove_input_btn = gr.Button("Remove input variable")
26
  for t in all_tasks.values():
27
  t.render()
 
 
 
 
 
 
28
  with gr.Row():
29
  add_task_btn = gr.Button("Add task")
30
  remove_task_btn = gr.Button("Remove task")
@@ -46,15 +59,15 @@ with gr.Blocks() as demo:
46
  )
47
  add_task_btn.click(
48
  a.add_task,
49
- inputs=[i.visible for i in all_tasks.values()],
50
- outputs=[i.gr_component for i in all_tasks.values()] # type: ignore
51
- + [i.visible for i in all_tasks.values()],
52
  )
53
  remove_task_btn.click(
54
  a.remove_task,
55
- inputs=[i.visible for i in all_tasks.values()],
56
- outputs=[i.gr_component for i in all_tasks.values()] # type: ignore
57
- + [i.visible for i in all_tasks.values()],
58
  )
59
 
60
  # Sequential execution
@@ -64,7 +77,9 @@ with gr.Blocks() as demo:
64
  for i, task in all_tasks.items():
65
  execution_event = execution_event.then(
66
  a.execute_task,
67
- inputs=[task.component_id, error_message, task.n_inputs] + task.inputs() + a._get_all_vars_up_to(i), # type: ignore
 
 
68
  outputs=[task.output, error_message],
69
  )
70
 
 
1
  import gradio as gr
2
 
3
  import actions as a
4
+ from components import AITask, all_inputs, all_tasks, VisitURL
5
+
6
+
7
+ def _get_all_vars_up_to(to: int):
8
+ return [in_.output for in_ in all_inputs.values()] + [
9
+ t.output for i, t in all_tasks.items() if i < to
10
+ ]
11
 
12
 
13
  with gr.Blocks() as demo:
 
17
  # Toolkit
18
  Define input variables to be used in your tasks.
19
  <br>Task outputs can be used in subsequent tasks.
20
+ <br>5 input variables and 10 tasks allowed (for now).
21
  <br>
22
  <br>AI tasks call into ChatGPT to perform actions.
23
  <br>Chain inputs and tasks to build an E2E application.
 
32
  remove_input_btn = gr.Button("Remove input variable")
33
  for t in all_tasks.values():
34
  t.render()
35
+ task_picker = gr.Dropdown(
36
+ [AITask.NAME, VisitURL.NAME],
37
+ value=AITask.NAME,
38
+ label="Pick a new Task",
39
+ type="index",
40
+ )
41
  with gr.Row():
42
  add_task_btn = gr.Button("Add task")
43
  remove_task_btn = gr.Button("Remove task")
 
59
  )
60
  add_task_btn.click(
61
  a.add_task,
62
+ inputs=[task_picker] + [v for t in all_tasks.values() for v in t.visibilities], # type: ignore
63
+ outputs=[c for t in all_tasks.values() for c in t.gr_components] # type: ignore
64
+ + [v for t in all_tasks.values() for v in t.visibilities],
65
  )
66
  remove_task_btn.click(
67
  a.remove_task,
68
+ inputs=[v for t in all_tasks.values() for v in t.visibilities], # type: ignore
69
+ outputs=[c for t in all_tasks.values() for c in t.gr_components] # type: ignore
70
+ + [v for t in all_tasks.values() for v in t.visibilities],
71
  )
72
 
73
  # Sequential execution
 
77
  for i, task in all_tasks.items():
78
  execution_event = execution_event.then(
79
  a.execute_task,
80
+ inputs=[task.component_id, error_message, task.n_inputs]
81
+ + task.inputs
82
+ + _get_all_vars_up_to(i),
83
  outputs=[task.output, error_message],
84
  )
85
 
components.py CHANGED
@@ -2,12 +2,13 @@ from abc import ABC, abstractmethod
2
  from typing import Dict, List, Optional
3
 
4
  import gradio as gr
 
5
 
6
  import ai
7
 
8
 
9
  class Component(ABC):
10
- vname = None
11
 
12
  def __init__(self, id_: int, visible: bool = False):
13
  # Internal state
@@ -40,11 +41,11 @@ class Component(ABC):
40
 
41
 
42
  class Input(Component):
43
- vname = "v"
44
 
45
  def _render(self, id_: int, visible: bool) -> gr.Textbox:
46
  self.output = gr.Textbox(
47
- label=f"Input: {{{self.vname}{id_}}}",
48
  interactive=True,
49
  placeholder="Variable value",
50
  visible=visible,
@@ -55,12 +56,8 @@ class Input(Component):
55
  pass
56
 
57
 
58
- class Task(Component, ABC):
59
- vname = "t"
60
-
61
- def __init__(self, id_: int, visible: bool = False):
62
- super().__init__(id_, visible)
63
- self.output: gr.Textbox
64
 
65
  @abstractmethod
66
  def inputs(self) -> List:
@@ -75,19 +72,26 @@ class Task(Component, ABC):
75
  self.n_inputs = gr.Number(value=self._n_inputs, visible=False)
76
 
77
 
78
- class AITask(Task):
 
 
79
  def _render(self, id_: int, visible: bool) -> gr.Box:
80
  with gr.Box(visible=visible) as gr_component:
81
- gr.Markdown(f"AI task")
 
 
 
 
 
82
  with gr.Row():
83
  self.prompt = gr.Textbox(
84
  label="Instructions",
85
  lines=10,
86
  interactive=True,
87
- placeholder="What is the AI assistant meant to do?",
88
  )
89
  self.output = gr.Textbox(
90
- label=f"Output: {{{self.vname}{id_}}}",
91
  lines=10,
92
  interactive=False,
93
  )
@@ -102,12 +106,88 @@ class AITask(Task):
102
  return [self.prompt]
103
 
104
 
105
- MAX_INPUTS = 10
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
106
  MAX_TASKS = 10
107
 
108
 
109
  all_inputs = {i: Input(i) for i in range(MAX_INPUTS)}
110
- all_tasks = {i: AITask(i) for i in range(MAX_TASKS)}
111
 
112
  all_inputs[0]._initial_visibility = True
113
- all_tasks[0]._initial_visibility = True
 
2
  from typing import Dict, List, Optional
3
 
4
  import gradio as gr
5
+ import requests
6
 
7
  import ai
8
 
9
 
10
  class Component(ABC):
11
+ VNAME = None
12
 
13
  def __init__(self, id_: int, visible: bool = False):
14
  # Internal state
 
41
 
42
 
43
  class Input(Component):
44
+ VNAME = "v"
45
 
46
  def _render(self, id_: int, visible: bool) -> gr.Textbox:
47
  self.output = gr.Textbox(
48
+ label=f"Input: {{{self.VNAME}{id_}}}",
49
  interactive=True,
50
  placeholder="Variable value",
51
  visible=visible,
 
56
  pass
57
 
58
 
59
+ class TaskComponent(Component, ABC):
60
+ VNAME = "t"
 
 
 
 
61
 
62
  @abstractmethod
63
  def inputs(self) -> List:
 
72
  self.n_inputs = gr.Number(value=self._n_inputs, visible=False)
73
 
74
 
75
+ class AITask(TaskComponent):
76
+ NAME = "AI Task"
77
+
78
  def _render(self, id_: int, visible: bool) -> gr.Box:
79
  with gr.Box(visible=visible) as gr_component:
80
+ gr.Markdown(
81
+ f"""
82
+ {self.NAME}
83
+ <br> Use this Task to give instructions to ChatGPT.
84
+ """
85
+ )
86
  with gr.Row():
87
  self.prompt = gr.Textbox(
88
  label="Instructions",
89
  lines=10,
90
  interactive=True,
91
+ placeholder="Example - summarize this text: {v1}",
92
  )
93
  self.output = gr.Textbox(
94
+ label=f"Output: {{{self.VNAME}{id_}}}",
95
  lines=10,
96
  interactive=False,
97
  )
 
106
  return [self.prompt]
107
 
108
 
109
+ class VisitURL(TaskComponent):
110
+ NAME = "Visit URL"
111
+
112
+ def _render(self, id_: int, visible: bool) -> gr.Box:
113
+ with gr.Box(visible=visible) as gr_component:
114
+ gr.Markdown(
115
+ f"""
116
+ {self.NAME}
117
+ <br> Use this Task to visit an URL and get its content.
118
+ """
119
+ )
120
+ with gr.Row():
121
+ self.url = gr.Textbox(
122
+ interactive=True,
123
+ placeholder="URL",
124
+ show_label=False,
125
+ )
126
+ self.output = gr.Textbox(
127
+ label=f"Output: {{{self.VNAME}{id_}}}",
128
+ lines=10,
129
+ interactive=False,
130
+ )
131
+ return gr_component
132
+
133
+ def _execute(self, url: str, prompt_vars: Dict[str, str]) -> Optional[str]:
134
+ if url:
135
+ formatted_url = url.format(**prompt_vars)
136
+ return requests.get(formatted_url).text
137
+
138
+ def inputs(self) -> List[gr.Textbox]:
139
+ return [self.url]
140
+
141
+
142
+ class Task:
143
+ AVAILABLE_TASKS = [AITask, VisitURL]
144
+ VNAME = "t"
145
+
146
+ def __init__(self, id_: int):
147
+ self._id = id_
148
+ self.active_task = AITask.NAME # Default
149
+ self.inner_tasks = {t.NAME: t(self._id, False) for t in self.AVAILABLE_TASKS}
150
+
151
+ def render(self) -> None:
152
+ for t in self.inner_tasks.values():
153
+ t.render()
154
+
155
+ @property
156
+ def component_id(self) -> gr.Textbox:
157
+ return self.inner_tasks[self.active_task].component_id
158
+
159
+ @property
160
+ def visibilities(self) -> List[gr.Number]:
161
+ return [t.visible for t in self.inner_tasks.values()]
162
+
163
+ @property
164
+ def gr_components(self) -> List[gr.Box]:
165
+ return [t.gr_component for t in self.inner_tasks.values()]
166
+
167
+ @property
168
+ def output(self) -> gr.Textbox:
169
+ return self.inner_tasks[self.active_task].output
170
+
171
+ @property
172
+ def inputs(self) -> List[gr.Textbox]:
173
+ return self.inner_tasks[self.active_task].inputs()
174
+
175
+ @property
176
+ def n_inputs(self) -> int:
177
+ return self.inner_tasks[self.active_task].n_inputs
178
+
179
+ def execute(self, *args):
180
+ inner_task = self.inner_tasks[self.active_task]
181
+ print(f"Executing {inner_task._source} :: {inner_task._id}")
182
+ return inner_task.execute(*args)
183
+
184
+
185
+ MAX_INPUTS = 5
186
  MAX_TASKS = 10
187
 
188
 
189
  all_inputs = {i: Input(i) for i in range(MAX_INPUTS)}
190
+ all_tasks = {i: Task(i) for i in range(MAX_TASKS)}
191
 
192
  all_inputs[0]._initial_visibility = True
193
+ all_tasks[0].inner_tasks[all_tasks[0].active_task]._initial_visibility = True
requirements.txt CHANGED
@@ -1,3 +1,4 @@
1
  gradio
2
  openai
3
- python-dotenv
 
 
1
  gradio
2
  openai
3
+ python-dotenv
4
+ requests==2.28.1