plot-agent 0.2.0__py3-none-any.whl → 0.2.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
plot_agent/agent.py CHANGED
@@ -1,94 +1,20 @@
1
1
  import pandas as pd
2
- import numpy as np
3
- import matplotlib.pyplot as plt
4
- import plotly.express as px
5
- import plotly.graph_objects as go
6
- from plotly.subplots import make_subplots
7
2
  from io import StringIO
8
- import traceback
9
- import sys
10
- from typing import Dict, List, Optional, Any
3
+ from typing import Optional
11
4
 
12
5
  from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
13
6
  from langchain_core.messages import AIMessage, HumanMessage
14
7
  from langchain_core.tools import Tool, StructuredTool
15
8
  from langchain.agents import AgentExecutor, create_openai_tools_agent
16
9
  from langchain_openai import ChatOpenAI
10
+
17
11
  from plot_agent.prompt import DEFAULT_SYSTEM_PROMPT
18
12
  from plot_agent.models import (
19
13
  GeneratedCodeInput,
20
14
  DoesFigExistInput,
21
15
  ViewGeneratedCodeInput,
22
16
  )
23
-
24
-
25
- class PlotlyAgentExecutionEnvironment:
26
- """Environment to safely execute plotly code and capture the fig object."""
27
-
28
- def __init__(self, df: pd.DataFrame):
29
- self.df = df
30
- self.locals_dict = {
31
- "df": df,
32
- "px": px,
33
- "go": go,
34
- "pd": pd,
35
- "np": np,
36
- "plt": plt,
37
- "make_subplots": make_subplots,
38
- }
39
- self.output = None
40
- self.error = None
41
- self.fig = None
42
-
43
- def execute_code(self, generated_code: str) -> Dict[str, Any]:
44
- """
45
- Execute the provided code and capture the fig object if created.
46
-
47
- Args:
48
- generated_code (str): The code to execute.
49
-
50
- Returns:
51
- Dict[str, Any]: A dictionary containing the fig object, output, error, and success status.
52
- """
53
- self.output = None
54
- self.error = None
55
-
56
- # Capture stdout
57
- old_stdout = sys.stdout
58
- sys.stdout = mystdout = StringIO()
59
-
60
- try:
61
- # Execute the code
62
- exec(generated_code, globals(), self.locals_dict)
63
-
64
- # Check if a fig object was created
65
- if "fig" in self.locals_dict:
66
- self.fig = self.locals_dict["fig"]
67
- self.output = "Code executed successfully. 'fig' object was created."
68
- else:
69
- print(f"no fig object created: {generated_code}")
70
- self.error = "Code executed without errors, but no 'fig' object was created. Make sure your code creates a variable named 'fig'."
71
-
72
- except Exception as e:
73
- self.error = f"Error executing code: {str(e)}\n{traceback.format_exc()}"
74
-
75
- finally:
76
- # Restore stdout
77
- sys.stdout = old_stdout
78
- captured_output = mystdout.getvalue()
79
-
80
- if captured_output.strip():
81
- if self.output:
82
- self.output += f"\nOutput:\n{captured_output}"
83
- else:
84
- self.output = f"Output:\n{captured_output}"
85
-
86
- return {
87
- "fig": self.fig,
88
- "output": self.output,
89
- "error": self.error,
90
- "success": self.error is None and self.fig is not None,
91
- }
17
+ from plot_agent.execution import PlotlyAgentExecutionEnvironment
92
18
 
93
19
 
94
20
  class PlotlyAgent:
@@ -142,6 +68,14 @@ class PlotlyAgent:
142
68
  Returns:
143
69
  None
144
70
  """
71
+
72
+ # Check df
73
+ assert isinstance(df, pd.DataFrame), "The dataframe must be a pandas dataframe."
74
+ assert not df.empty, "The dataframe must not be empty."
75
+
76
+ if sql_query:
77
+ assert isinstance(sql_query, str), "The SQL query must be a string."
78
+
145
79
  self.df = df
146
80
 
147
81
  # Capture df.info() output
@@ -171,18 +105,27 @@ class PlotlyAgent:
171
105
  Returns:
172
106
  str: The result of the execution.
173
107
  """
108
+ assert isinstance(generated_code, str), "The generated code must be a string."
109
+
174
110
  if not self.execution_env:
175
111
  return "Error: No dataframe has been set. Please set a dataframe first."
176
112
 
177
113
  # Store this as the last generated code
178
114
  self.generated_code = generated_code
179
115
 
180
- result = self.execution_env.execute_code(generated_code)
116
+ # Execute the generated code
117
+ code_execution_result = self.execution_env.execute_code(generated_code)
181
118
 
182
- if result["success"]:
183
- return f"Code executed successfully! A figure object was created.\n{result.get('output', '')}"
119
+ # Extract the results from the code execution
120
+ code_execution_success = code_execution_result.get("success", False)
121
+ code_execution_output = code_execution_result.get("output", "")
122
+ code_execution_error = code_execution_result.get("error", "")
123
+
124
+ # Check if the code executed successfully
125
+ if code_execution_success:
126
+ return f"Code executed successfully! A figure object was created.\n{code_execution_output}"
184
127
  else:
185
- return f"Error: {result.get('error', 'Unknown error')}\n{result.get('output', '')}"
128
+ return f"Error: {code_execution_error}\n{code_execution_output}"
186
129
 
187
130
  def does_fig_exist(self, *args, **kwargs) -> str:
188
131
  """
@@ -211,23 +154,25 @@ class PlotlyAgent:
211
154
 
212
155
  def _initialize_agent(self):
213
156
  """Initialize the LangChain agent with the necessary tools and prompt."""
157
+
158
+ # Initialize the tools
214
159
  tools = [
215
160
  Tool.from_function(
216
161
  func=self.execute_plotly_code,
217
162
  name="execute_plotly_code",
218
- description="Execute the provided Plotly code and return the result",
163
+ description="Execute the provided Plotly code and return a result indicating if the code executed successfully and if a figure object was created.",
219
164
  args_schema=GeneratedCodeInput,
220
165
  ),
221
166
  StructuredTool.from_function(
222
167
  func=self.does_fig_exist,
223
168
  name="does_fig_exist",
224
- description="Check if a figure exists and is available for display. This tool takes no arguments.",
169
+ description="Check if a figure exists and is available for display. This tool takes no arguments and returns a string indicating if a figure is available for display or not.",
225
170
  args_schema=DoesFigExistInput,
226
171
  ),
227
172
  StructuredTool.from_function(
228
173
  func=self.view_generated_code,
229
174
  name="view_generated_code",
230
- description="View the generated code.",
175
+ description="View the generated code. This tool takes no arguments and returns the generated code as a string.",
231
176
  args_schema=ViewGeneratedCodeInput,
232
177
  ),
233
178
  ]
@@ -265,6 +210,8 @@ class PlotlyAgent:
265
210
 
266
211
  def process_message(self, user_message: str) -> str:
267
212
  """Process a user message and return the agent's response."""
213
+ assert isinstance(user_message, str), "The user message must be a string."
214
+
268
215
  if not self.agent_executor:
269
216
  return "Please set a dataframe first using set_df() method."
270
217
 
@@ -305,3 +252,4 @@ class PlotlyAgent:
305
252
  def reset_conversation(self):
306
253
  """Reset the conversation history."""
307
254
  self.chat_history = []
255
+ self.generated_code = None
@@ -0,0 +1,90 @@
1
+ import sys
2
+ from io import StringIO
3
+ import traceback
4
+ import pandas as pd
5
+ import plotly.express as px
6
+ import plotly.graph_objects as go
7
+ import numpy as np
8
+ import matplotlib.pyplot as plt
9
+ from plotly.subplots import make_subplots
10
+ from typing import Dict, Any
11
+
12
+
13
+ class PlotlyAgentExecutionEnvironment:
14
+ """
15
+ Environment to safely execute plotly code and capture the fig object.
16
+
17
+ Args:
18
+ df (pd.DataFrame): The dataframe to use for the execution environment.
19
+ """
20
+
21
+ def __init__(self, df: pd.DataFrame):
22
+ """
23
+ Initialize the execution environment with the given dataframe.
24
+
25
+ Args:
26
+ df (pd.DataFrame): The dataframe to use for the execution environment.
27
+ """
28
+ self.df = df
29
+ self.locals_dict = {
30
+ "df": df,
31
+ "px": px,
32
+ "go": go,
33
+ "pd": pd,
34
+ "np": np,
35
+ "plt": plt,
36
+ "make_subplots": make_subplots,
37
+ }
38
+ self.output = None
39
+ self.error = None
40
+ self.fig = None
41
+
42
+ def execute_code(self, generated_code: str) -> Dict[str, Any]:
43
+ """
44
+ Execute the provided code and capture the fig object if created.
45
+
46
+ Args:
47
+ generated_code (str): The code to execute.
48
+
49
+ Returns:
50
+ Dict[str, Any]: A dictionary containing the fig object, output, error, and success status.
51
+ """
52
+ self.output = None
53
+ self.error = None
54
+
55
+ # Capture stdout
56
+ old_stdout = sys.stdout
57
+ sys.stdout = mystdout = StringIO()
58
+
59
+ try:
60
+ # Execute the code
61
+ exec(generated_code, globals(), self.locals_dict)
62
+
63
+ # Check if a fig object was created
64
+ if "fig" in self.locals_dict:
65
+ self.fig = self.locals_dict["fig"]
66
+ self.output = "Code executed successfully. 'fig' object was created."
67
+ else:
68
+ print(f"no fig object created: {generated_code}")
69
+ self.error = "Code executed without errors, but no 'fig' object was created. Make sure your code creates a variable named 'fig'."
70
+
71
+ except Exception as e:
72
+ self.error = f"Error executing code: {str(e)}\n{traceback.format_exc()}"
73
+
74
+ finally:
75
+ # Restore stdout
76
+ sys.stdout = old_stdout
77
+ captured_output = mystdout.getvalue()
78
+
79
+ if captured_output.strip():
80
+ if self.output:
81
+ self.output += f"\nOutput:\n{captured_output}"
82
+ else:
83
+ self.output = f"Output:\n{captured_output}"
84
+
85
+ return {
86
+ "fig": self.fig,
87
+ "output": self.output,
88
+ "error": self.error,
89
+ "success": self.error is None and self.fig is not None,
90
+ }
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: plot-agent
3
- Version: 0.2.0
3
+ Version: 0.2.2
4
4
  Summary: An AI-powered data visualization assistant using Plotly
5
5
  Author-email: andrewm4894 <andrewm4894@gmail.com>
6
6
  Project-URL: Homepage, https://github.com/andrewm4894/plot-agent
@@ -0,0 +1,10 @@
1
+ plot_agent/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ plot_agent/agent.py,sha256=mflUj-vE_x9_W7XTJ3-GgYFfvg3uXV3wkrUw7wRPlVM,9592
3
+ plot_agent/execution.py,sha256=BBKBVGQDrg7BPWvPbLWOjkAAFRlfyu28QxClXuspd8o,2772
4
+ plot_agent/models.py,sha256=ZOWWeYaqmnKJarXYyXnBQQ4nwUe71ae_gMul3bZXaWU,644
5
+ plot_agent/prompt.py,sha256=HjRgbsAe8HHs8arQogvzOGQdThEWKRqQhtQyaUplxhQ,3064
6
+ plot_agent-0.2.2.dist-info/licenses/LICENSE,sha256=A4DPih7wHrh4VMEG3p1PhorqdhjmGIo8nQdYNQL7daA,1062
7
+ plot_agent-0.2.2.dist-info/METADATA,sha256=dLTSBMjvxg0U63r-EbN2tfI7-eZGYexq854L0kN8M6M,2841
8
+ plot_agent-0.2.2.dist-info/WHEEL,sha256=lTU6B6eIfYoiQJTZNc-fyaR6BpL6ehTzU3xGYxn2n8k,91
9
+ plot_agent-0.2.2.dist-info/top_level.txt,sha256=KyOjpihUssx26Ra-37vKUQ71pI2qgJsHaRwXHJUhjzQ,11
10
+ plot_agent-0.2.2.dist-info/RECORD,,
@@ -1,9 +0,0 @@
1
- plot_agent/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- plot_agent/agent.py,sha256=zukHGVexMXOHHjtmb7dNB3l2iEpC0rq0a6UUpVPLe14,10845
3
- plot_agent/models.py,sha256=ZOWWeYaqmnKJarXYyXnBQQ4nwUe71ae_gMul3bZXaWU,644
4
- plot_agent/prompt.py,sha256=HjRgbsAe8HHs8arQogvzOGQdThEWKRqQhtQyaUplxhQ,3064
5
- plot_agent-0.2.0.dist-info/licenses/LICENSE,sha256=A4DPih7wHrh4VMEG3p1PhorqdhjmGIo8nQdYNQL7daA,1062
6
- plot_agent-0.2.0.dist-info/METADATA,sha256=1_3wlHu5E1_gONv4uckGTc4X9F7hHzXuQRv9EjAHIVI,2841
7
- plot_agent-0.2.0.dist-info/WHEEL,sha256=lTU6B6eIfYoiQJTZNc-fyaR6BpL6ehTzU3xGYxn2n8k,91
8
- plot_agent-0.2.0.dist-info/top_level.txt,sha256=KyOjpihUssx26Ra-37vKUQ71pI2qgJsHaRwXHJUhjzQ,11
9
- plot_agent-0.2.0.dist-info/RECORD,,