plot-agent 0.1.1__py3-none-any.whl → 0.2.0__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/{plotly_agent.py → agent.py} +46 -88
- plot_agent/models.py +26 -0
- plot_agent/prompt.py +57 -0
- {plot_agent-0.1.1.dist-info → plot_agent-0.2.0.dist-info}/METADATA +47 -3
- plot_agent-0.2.0.dist-info/RECORD +9 -0
- {plot_agent-0.1.1.dist-info → plot_agent-0.2.0.dist-info}/WHEEL +1 -1
- plot_agent-0.1.1.dist-info/RECORD +0 -7
- {plot_agent-0.1.1.dist-info → plot_agent-0.2.0.dist-info}/licenses/LICENSE +0 -0
- {plot_agent-0.1.1.dist-info → plot_agent-0.2.0.dist-info}/top_level.txt +0 -0
|
@@ -7,79 +7,19 @@ from plotly.subplots import make_subplots
|
|
|
7
7
|
from io import StringIO
|
|
8
8
|
import traceback
|
|
9
9
|
import sys
|
|
10
|
-
import re
|
|
11
10
|
from typing import Dict, List, Optional, Any
|
|
12
11
|
|
|
13
12
|
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
|
|
14
13
|
from langchain_core.messages import AIMessage, HumanMessage
|
|
15
|
-
from langchain_core.tools import Tool
|
|
16
|
-
from pydantic import BaseModel, Field
|
|
14
|
+
from langchain_core.tools import Tool, StructuredTool
|
|
17
15
|
from langchain.agents import AgentExecutor, create_openai_tools_agent
|
|
18
16
|
from langchain_openai import ChatOpenAI
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
You have access to a pandas df with the following information:
|
|
27
|
-
|
|
28
|
-
df.info():
|
|
29
|
-
```plaintext
|
|
30
|
-
{df_info}
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
df.head():
|
|
34
|
-
```plaintext
|
|
35
|
-
{df_head}
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
{sql_context}
|
|
39
|
-
|
|
40
|
-
NOTES:
|
|
41
|
-
- You must use the execute_plotly_code(generated_code) tool to test and run your code
|
|
42
|
-
- You must paste the full code, not just a reference to the code
|
|
43
|
-
- You must not use fig.show() in your code as it will be executed in a headless environment
|
|
44
|
-
- If you need to do any data cleaning or wrangling, do it in the code before generating the plotly code as preprocessing steps assume the data is in the pandas df object
|
|
45
|
-
- Do not use fig.show() in your code as it will be executed in a headless environment.
|
|
46
|
-
|
|
47
|
-
IMPORTANT CODE FORMATTING INSTRUCTIONS:
|
|
48
|
-
1. Include thorough, detailed comments in your code to explain what each section does
|
|
49
|
-
2. Use descriptive variable names
|
|
50
|
-
3. DO NOT include fig.show() in your code - the visualization will be rendered externally
|
|
51
|
-
4. Ensure your code creates a variable named 'fig' that contains the Plotly figure object
|
|
52
|
-
5. Structure your code with proper spacing for readability
|
|
53
|
-
|
|
54
|
-
When a user asks for a visualization:
|
|
55
|
-
1. YOU MUST ALWAYS use the execute_plotly_code(generated_code) tool to test and run your code
|
|
56
|
-
2. If there are errors, fix the code and run it again with execute_plotly_code(generated_code)
|
|
57
|
-
3. Check that a figure object is available using does_fig_exist(). does_fig_exist() takes no arguments.
|
|
58
|
-
|
|
59
|
-
IMPORTANT: The code you generate MUST be executed using the execute_plotly_code tool or no figure will be created!
|
|
60
|
-
YOU MUST CALL execute_plotly_code WITH THE FULL CODE, NOT JUST A REFERENCE TO THE CODE.
|
|
61
|
-
|
|
62
|
-
YOUR WORKFLOW MUST BE:
|
|
63
|
-
1. execute_plotly_code(generated_code) → 2. check that a figure object is available using does_fig_exist() → 3. (if needed) fix and execute again
|
|
64
|
-
|
|
65
|
-
Always return the final working code (with all the comments) to the user along with an explanation of what the visualization shows.
|
|
66
|
-
Make sure to follow best practices for data visualization, such as appropriate chart types, labels, and colors.
|
|
67
|
-
|
|
68
|
-
Remember that users may want to iterate on their visualizations, so be responsive to requests for changes.
|
|
69
|
-
"""
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
# Define input schemas for the tools
|
|
73
|
-
class PlotDescriptionInput(BaseModel):
|
|
74
|
-
plot_description: str = Field(
|
|
75
|
-
..., description="Description of the plot the user wants to create"
|
|
76
|
-
)
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
class GeneratedCodeInput(BaseModel):
|
|
80
|
-
generated_code: str = Field(
|
|
81
|
-
..., description="Python code that creates a Plotly figure"
|
|
82
|
-
)
|
|
17
|
+
from plot_agent.prompt import DEFAULT_SYSTEM_PROMPT
|
|
18
|
+
from plot_agent.models import (
|
|
19
|
+
GeneratedCodeInput,
|
|
20
|
+
DoesFigExistInput,
|
|
21
|
+
ViewGeneratedCodeInput,
|
|
22
|
+
)
|
|
83
23
|
|
|
84
24
|
|
|
85
25
|
class PlotlyAgentExecutionEnvironment:
|
|
@@ -100,13 +40,6 @@ class PlotlyAgentExecutionEnvironment:
|
|
|
100
40
|
self.error = None
|
|
101
41
|
self.fig = None
|
|
102
42
|
|
|
103
|
-
def preprocess_code(self, generated_code: str) -> str:
|
|
104
|
-
"""Preprocess code to remove fig.show() calls."""
|
|
105
|
-
# Remove fig.show() calls
|
|
106
|
-
generated_code = re.sub(r"fig\.show\(\s*\)", "", generated_code)
|
|
107
|
-
generated_code = re.sub(r"fig\.show\(.*\)", "", generated_code)
|
|
108
|
-
return generated_code
|
|
109
|
-
|
|
110
43
|
def execute_code(self, generated_code: str) -> Dict[str, Any]:
|
|
111
44
|
"""
|
|
112
45
|
Execute the provided code and capture the fig object if created.
|
|
@@ -120,23 +53,20 @@ class PlotlyAgentExecutionEnvironment:
|
|
|
120
53
|
self.output = None
|
|
121
54
|
self.error = None
|
|
122
55
|
|
|
123
|
-
# Preprocess code to remove fig.show() calls
|
|
124
|
-
processed_code = self.preprocess_code(generated_code)
|
|
125
|
-
|
|
126
56
|
# Capture stdout
|
|
127
57
|
old_stdout = sys.stdout
|
|
128
58
|
sys.stdout = mystdout = StringIO()
|
|
129
59
|
|
|
130
60
|
try:
|
|
131
61
|
# Execute the code
|
|
132
|
-
exec(
|
|
62
|
+
exec(generated_code, globals(), self.locals_dict)
|
|
133
63
|
|
|
134
64
|
# Check if a fig object was created
|
|
135
65
|
if "fig" in self.locals_dict:
|
|
136
66
|
self.fig = self.locals_dict["fig"]
|
|
137
|
-
self.output = "Code executed successfully.
|
|
67
|
+
self.output = "Code executed successfully. 'fig' object was created."
|
|
138
68
|
else:
|
|
139
|
-
print(f"no fig object created: {
|
|
69
|
+
print(f"no fig object created: {generated_code}")
|
|
140
70
|
self.error = "Code executed without errors, but no 'fig' object was created. Make sure your code creates a variable named 'fig'."
|
|
141
71
|
|
|
142
72
|
except Exception as e:
|
|
@@ -166,13 +96,25 @@ class PlotlyAgent:
|
|
|
166
96
|
A class that uses an LLM to generate Plotly code based on a user's plot description.
|
|
167
97
|
"""
|
|
168
98
|
|
|
169
|
-
def __init__(
|
|
99
|
+
def __init__(
|
|
100
|
+
self,
|
|
101
|
+
model="gpt-4o-mini",
|
|
102
|
+
system_prompt: Optional[str] = None,
|
|
103
|
+
verbose: bool = True,
|
|
104
|
+
max_iterations: int = 10,
|
|
105
|
+
early_stopping_method: str = "force",
|
|
106
|
+
handle_parsing_errors: bool = True,
|
|
107
|
+
):
|
|
170
108
|
"""
|
|
171
109
|
Initialize the PlotlyAgent.
|
|
172
110
|
|
|
173
111
|
Args:
|
|
174
112
|
model (str): The model to use for the LLM.
|
|
175
113
|
system_prompt (Optional[str]): The system prompt to use for the LLM.
|
|
114
|
+
verbose (bool): Whether to print verbose output from the agent.
|
|
115
|
+
max_iterations (int): Maximum number of iterations for the agent to take.
|
|
116
|
+
early_stopping_method (str): Method to use for early stopping.
|
|
117
|
+
handle_parsing_errors (bool): Whether to handle parsing errors gracefully.
|
|
176
118
|
"""
|
|
177
119
|
self.llm = ChatOpenAI(model=model)
|
|
178
120
|
self.df = None
|
|
@@ -184,6 +126,10 @@ class PlotlyAgent:
|
|
|
184
126
|
self.agent_executor = None
|
|
185
127
|
self.generated_code = None
|
|
186
128
|
self.system_prompt = system_prompt or DEFAULT_SYSTEM_PROMPT
|
|
129
|
+
self.verbose = verbose
|
|
130
|
+
self.max_iterations = max_iterations
|
|
131
|
+
self.early_stopping_method = early_stopping_method
|
|
132
|
+
self.handle_parsing_errors = handle_parsing_errors
|
|
187
133
|
|
|
188
134
|
def set_df(self, df: pd.DataFrame, sql_query: Optional[str] = None):
|
|
189
135
|
"""
|
|
@@ -257,6 +203,12 @@ class PlotlyAgent:
|
|
|
257
203
|
else:
|
|
258
204
|
return "No figure has been created yet."
|
|
259
205
|
|
|
206
|
+
def view_generated_code(self, *args, **kwargs) -> str:
|
|
207
|
+
"""
|
|
208
|
+
View the generated code.
|
|
209
|
+
"""
|
|
210
|
+
return self.generated_code
|
|
211
|
+
|
|
260
212
|
def _initialize_agent(self):
|
|
261
213
|
"""Initialize the LangChain agent with the necessary tools and prompt."""
|
|
262
214
|
tools = [
|
|
@@ -266,11 +218,17 @@ class PlotlyAgent:
|
|
|
266
218
|
description="Execute the provided Plotly code and return the result",
|
|
267
219
|
args_schema=GeneratedCodeInput,
|
|
268
220
|
),
|
|
269
|
-
|
|
221
|
+
StructuredTool.from_function(
|
|
270
222
|
func=self.does_fig_exist,
|
|
271
223
|
name="does_fig_exist",
|
|
272
|
-
description="Check if a figure exists and is available for display",
|
|
273
|
-
args_schema=
|
|
224
|
+
description="Check if a figure exists and is available for display. This tool takes no arguments.",
|
|
225
|
+
args_schema=DoesFigExistInput,
|
|
226
|
+
),
|
|
227
|
+
StructuredTool.from_function(
|
|
228
|
+
func=self.view_generated_code,
|
|
229
|
+
name="view_generated_code",
|
|
230
|
+
description="View the generated code.",
|
|
231
|
+
args_schema=ViewGeneratedCodeInput,
|
|
274
232
|
),
|
|
275
233
|
]
|
|
276
234
|
|
|
@@ -299,10 +257,10 @@ class PlotlyAgent:
|
|
|
299
257
|
self.agent_executor = AgentExecutor(
|
|
300
258
|
agent=agent,
|
|
301
259
|
tools=tools,
|
|
302
|
-
verbose=
|
|
303
|
-
max_iterations=
|
|
304
|
-
early_stopping_method=
|
|
305
|
-
handle_parsing_errors=
|
|
260
|
+
verbose=self.verbose,
|
|
261
|
+
max_iterations=self.max_iterations,
|
|
262
|
+
early_stopping_method=self.early_stopping_method,
|
|
263
|
+
handle_parsing_errors=self.handle_parsing_errors,
|
|
306
264
|
)
|
|
307
265
|
|
|
308
266
|
def process_message(self, user_message: str) -> str:
|
plot_agent/models.py
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
from pydantic import BaseModel, Field
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
# Define input schemas for the tools
|
|
5
|
+
class PlotDescriptionInput(BaseModel):
|
|
6
|
+
plot_description: str = Field(
|
|
7
|
+
..., description="Description of the plot the user wants to create"
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class GeneratedCodeInput(BaseModel):
|
|
12
|
+
generated_code: str = Field(
|
|
13
|
+
..., description="Python code that creates a Plotly figure"
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class DoesFigExistInput(BaseModel):
|
|
18
|
+
"""Model indicating that the does_fig_exist function takes no arguments."""
|
|
19
|
+
|
|
20
|
+
pass
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class ViewGeneratedCodeInput(BaseModel):
|
|
24
|
+
"""Model indicating that the view_generated_code function takes no arguments."""
|
|
25
|
+
|
|
26
|
+
pass
|
plot_agent/prompt.py
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
DEFAULT_SYSTEM_PROMPT = """
|
|
2
|
+
You are an expert data visualization assistant that helps users create Plotly visualizations in Python.
|
|
3
|
+
Your job is to generate Python and Plotly code based on the user's request that will create the desired visualization
|
|
4
|
+
of their pandas DataFrame (df).
|
|
5
|
+
|
|
6
|
+
You have access to a pandas df with the following information:
|
|
7
|
+
|
|
8
|
+
df.info():
|
|
9
|
+
```plaintext
|
|
10
|
+
{df_info}
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
df.head():
|
|
14
|
+
```plaintext
|
|
15
|
+
{df_head}
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
{sql_context}
|
|
19
|
+
|
|
20
|
+
NOTES:
|
|
21
|
+
- You must use the execute_plotly_code(generated_code) tool run your code and use the does_fig_exist() tool to check that a fig object is available for display.
|
|
22
|
+
- You must paste the full code, not just a reference to the code.
|
|
23
|
+
- You must not use fig.show() in your code as it will ultimately be executed elsewhere in a headless environment.
|
|
24
|
+
- If you need to do any data cleaning or wrangling, do it in the code before generating the plotly code as preprocessing steps assume the data is in the pandas 'df' object.
|
|
25
|
+
|
|
26
|
+
TOOLS:
|
|
27
|
+
- execute_plotly_code(generated_code) to execute the generated code.
|
|
28
|
+
- does_fig_exist() to check that a fig object is available for display. This tool takes no arguments.
|
|
29
|
+
- view_generated_code() to view the generated code if need to fix it. This tool takes no arguments.
|
|
30
|
+
|
|
31
|
+
IMPORTANT CODE FORMATTING INSTRUCTIONS:
|
|
32
|
+
1. Include thorough, detailed comments in your code to explain what each section does.
|
|
33
|
+
2. Use descriptive variable names.
|
|
34
|
+
3. DO NOT include fig.show() in your code - the visualization will be rendered externally.
|
|
35
|
+
4. Ensure your code creates a variable named 'fig' that contains the Plotly figure object.
|
|
36
|
+
|
|
37
|
+
When a user asks for a visualization:
|
|
38
|
+
1. YOU MUST ALWAYS use the execute_plotly_code(generated_code) tool to test and run your code.
|
|
39
|
+
2. If there are errors, view the generated code using view_generated_code() and fix the code.
|
|
40
|
+
3. Check that a figure object is available using does_fig_exist(). does_fig_exist() takes no arguments.
|
|
41
|
+
4. If the figure object is not available, repeat the process until it is available.
|
|
42
|
+
|
|
43
|
+
IMPORTANT: The code you generate MUST be executed using the execute_plotly_code tool or no figure will be created!
|
|
44
|
+
YOU MUST CALL execute_plotly_code WITH THE FULL CODE, NOT JUST A REFERENCE TO THE CODE.
|
|
45
|
+
|
|
46
|
+
YOUR WORKFLOW MUST BE:
|
|
47
|
+
1. execute_plotly_code(generated_code) to make sure the code is ran and a figure object is created.
|
|
48
|
+
2. check that a figure object is available using does_fig_exist() to make sure the figure object was created.
|
|
49
|
+
3. if there are errors, view the generated code using view_generated_code() to see what went wrong.
|
|
50
|
+
4. fix the code and execute it again with execute_plotly_code(generated_code) to make sure the figure object is created.
|
|
51
|
+
5. repeat until the figure object is available.
|
|
52
|
+
|
|
53
|
+
Always return the final working code (with all the comments) to the user along with an explanation of what the visualization shows.
|
|
54
|
+
Make sure to follow best practices for data visualization, such as appropriate chart types, labels, and colors.
|
|
55
|
+
|
|
56
|
+
Remember that users may want to iterate on their visualizations, so be responsive to requests for changes.
|
|
57
|
+
"""
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: plot-agent
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.2.0
|
|
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
|
|
@@ -14,6 +14,9 @@ Dynamic: license-file
|
|
|
14
14
|
|
|
15
15
|
# Plot Agent
|
|
16
16
|
|
|
17
|
+
[](https://github.com/andrewm4894/plot-agent/actions/workflows/test.yml)
|
|
18
|
+
[](https://badge.fury.io/py/plot-agent)
|
|
19
|
+
|
|
17
20
|
An AI-powered data visualization assistant that helps users create Plotly visualizations in Python.
|
|
18
21
|
|
|
19
22
|
## Installation
|
|
@@ -26,11 +29,15 @@ pip install plot-agent
|
|
|
26
29
|
|
|
27
30
|
## Usage
|
|
28
31
|
|
|
29
|
-
|
|
32
|
+
See more examples in [/examples/](https://nbviewer.org/github/andrewm4894/plot-agent/tree/main/examples/) (via nbviewer so that can see the charts easily).
|
|
33
|
+
|
|
34
|
+
Here's a simple minimal example of how to use Plot Agent:
|
|
30
35
|
|
|
31
36
|
```python
|
|
32
37
|
import pandas as pd
|
|
33
|
-
from plot_agent import PlotlyAgent
|
|
38
|
+
from plot_agent.agent import PlotlyAgent
|
|
39
|
+
|
|
40
|
+
# ensure OPENAI_API_KEY is set and available for langchain
|
|
34
41
|
|
|
35
42
|
# Create a sample dataframe
|
|
36
43
|
df = pd.DataFrame({
|
|
@@ -46,6 +53,43 @@ agent.set_df(df)
|
|
|
46
53
|
|
|
47
54
|
# Process a visualization request
|
|
48
55
|
response = agent.process_message("Create a line plot of x vs y")
|
|
56
|
+
|
|
57
|
+
# Print generated code
|
|
58
|
+
print(agent.generated_code)
|
|
59
|
+
|
|
60
|
+
# Get fig
|
|
61
|
+
fig = agent.get_figure()
|
|
62
|
+
fig.show()
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
`agent.generated_code`:
|
|
66
|
+
|
|
67
|
+
```python
|
|
68
|
+
import pandas as pd
|
|
69
|
+
import plotly.graph_objects as go
|
|
70
|
+
|
|
71
|
+
# Creating a line plot of x vs y
|
|
72
|
+
# Create a figure object
|
|
73
|
+
fig = go.Figure()
|
|
74
|
+
|
|
75
|
+
# Add a line trace to the figure
|
|
76
|
+
fig.add_trace(
|
|
77
|
+
go.Scatter(
|
|
78
|
+
x=df['x'], # The x values
|
|
79
|
+
y=df['y'], # The y values
|
|
80
|
+
mode='lines+markers', # Display both lines and markers
|
|
81
|
+
name='Line Plot', # Name of the trace
|
|
82
|
+
line=dict(color='blue', width=2) # Specify line color and width
|
|
83
|
+
)
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
# Adding titles and labels
|
|
87
|
+
fig.update_layout(
|
|
88
|
+
title='Line Plot of x vs y', # Plot title
|
|
89
|
+
xaxis_title='x', # x-axis label
|
|
90
|
+
yaxis_title='y', # y-axis label
|
|
91
|
+
template='plotly_white' # A clean layout
|
|
92
|
+
)
|
|
49
93
|
```
|
|
50
94
|
|
|
51
95
|
## Features
|
|
@@ -0,0 +1,9 @@
|
|
|
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,,
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
plot_agent/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
-
plot_agent/plotly_agent.py,sha256=5ddz0zyMRwqsdLzIDZwJtyyX72zqTjyp06FiJl1WEqg,12686
|
|
3
|
-
plot_agent-0.1.1.dist-info/licenses/LICENSE,sha256=A4DPih7wHrh4VMEG3p1PhorqdhjmGIo8nQdYNQL7daA,1062
|
|
4
|
-
plot_agent-0.1.1.dist-info/METADATA,sha256=gGVDZymtbirRKJFJjmuCLJhClQZ8sfedNpFqgKPDUwE,1539
|
|
5
|
-
plot_agent-0.1.1.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
|
|
6
|
-
plot_agent-0.1.1.dist-info/top_level.txt,sha256=KyOjpihUssx26Ra-37vKUQ71pI2qgJsHaRwXHJUhjzQ,11
|
|
7
|
-
plot_agent-0.1.1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|