Haolong Li commited on
Commit
f907a92
·
1 Parent(s): 9a0793a

Upload 2 files

Browse files
Files changed (2) hide show
  1. InterpreterAtomicFlow.py +98 -0
  2. __init__.py +1 -0
InterpreterAtomicFlow.py ADDED
@@ -0,0 +1,98 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import traceback
2
+ from copy import deepcopy
3
+ from typing import Dict, Any
4
+
5
+ from interpreter.code_interpreters.create_code_interpreter import create_code_interpreter
6
+ from interpreter.utils.truncate_output import truncate_output
7
+
8
+ from flows.base_flows import AtomicFlow
9
+
10
+
11
+ class InterpreterAtomicFlow(AtomicFlow):
12
+ def __init__(self,
13
+ max_output=2000,
14
+ **kwargs):
15
+ super().__init__(**kwargs)
16
+ self.max_output = max_output
17
+ self._code_interpreters = {}
18
+
19
+ @classmethod
20
+ def instantiate_from_config(cls, config):
21
+ flow_config = deepcopy(config)
22
+
23
+ kwargs = {"flow_config": flow_config}
24
+
25
+ # ~~~ Instantiate flow ~~~
26
+ return cls(**kwargs)
27
+
28
+
29
+ def set_up_flow_state(self):
30
+ """
31
+ class-specific flow state: language and code,
32
+ which describes the programming language and the code to run.
33
+ """
34
+ super().set_up_flow_state()
35
+ self.flow_state["language"] = None
36
+ self.flow_state["code"] = ""
37
+
38
+ def _state_update_add_language_and_code(self,
39
+ language: str,
40
+ code: str) -> None:
41
+ """
42
+ updates the language and code passed from _process_input_data
43
+ to the flow state
44
+ """
45
+ self.flow_state["language"] = language
46
+ self.flow_state["code"] = code
47
+
48
+ def _process_input_data(self, input_data: Dict[str, Any]):
49
+ """
50
+ sanity check for input, allocate interpreter if any,
51
+ pass input data into flow state
52
+
53
+ should call something like self._update_flow_state()
54
+ """
55
+ # ~~~ Sanity check of input_data ~~~
56
+ assert "language" in input_data, "attribute 'language' not in input data."
57
+ assert "code" in input_data, "attribute 'code' not in input data."
58
+
59
+ # code in Jupyter notebook that starts with '!' is actually shell command.
60
+ if input_data["language"] == "python" and input_data["code"].startswith("!"):
61
+ input_data["language"] = "shell"
62
+ input_data["code"] = input_data["code"][1:]
63
+
64
+ # ~~~ Allocate interpreter ~~~
65
+ # interpreter existence is checked in create_code_interpreter()
66
+ # TODO: consider: should we put language not supported error into output?
67
+ language = input_data["language"]
68
+ if language not in self._code_interpreters:
69
+ self._code_interpreters[language] = create_code_interpreter(language)
70
+
71
+ # ~~~ Pass input data to flow state ~~~
72
+ self._state_update_add_language_and_code(
73
+ language=language,
74
+ code=input_data["code"]
75
+ )
76
+
77
+ def _call(self):
78
+ output = ""
79
+ try:
80
+ code_interpreter = self._code_interpreters[self.flow_state["language"]]
81
+ code = self.flow_state["code"]
82
+ for line in code_interpreter.run(code):
83
+ if "output" in line:
84
+ output += "\n" + line["output"]
85
+ # Truncate output
86
+ output = truncate_output(output, self.max_output)
87
+ output = output.strip()
88
+ except:
89
+ output = traceback.format_exc()
90
+ output = output.strip()
91
+ return output
92
+
93
+ def run(
94
+ self,
95
+ input_data: Dict[str, Any]):
96
+ self._process_input_data(input_data)
97
+ response = self._call()
98
+ return {"interpreter_output": response}
__init__.py ADDED
@@ -0,0 +1 @@
 
 
1
+ from .InterpreterAtomicFlow import InterpreterAtomicFlow