agi-gui 0.1.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.
- agi_gui/AGILAB.py +544 -0
- agi_gui/__init__.py +0 -0
- agi_gui/agi_copilot.py +33 -0
- agi_gui/lab_run.py +63 -0
- agi_gui/pagelib.py +1116 -0
- agi_gui/pages/__init__.py +1 -0
- agi_gui/pages//342/226/266/357/270/217 EDIT.py" +1621 -0
- agi_gui/pages//342/226/266/357/270/217 EXECUTE.py" +843 -0
- agi_gui/pages//342/226/266/357/270/217 EXPERIMENT.py" +656 -0
- agi_gui/pages//342/226/266/357/270/217 VIEW.py" +185 -0
- agi_gui-0.1.0.dist-info/LICENSE +22 -0
- agi_gui-0.1.0.dist-info/METADATA +74 -0
- agi_gui-0.1.0.dist-info/RECORD +16 -0
- agi_gui-0.1.0.dist-info/WHEEL +5 -0
- agi_gui-0.1.0.dist-info/entry_points.txt +2 -0
- agi_gui-0.1.0.dist-info/top_level.txt +1 -0
agi_gui/AGILAB.py
ADDED
|
@@ -0,0 +1,544 @@
|
|
|
1
|
+
# BSD 3-Clause License
|
|
2
|
+
#
|
|
3
|
+
# Copyright (c) 2025, Jean-Pierre Morard, THALES SIX GTS France SAS
|
|
4
|
+
# All rights reserved.
|
|
5
|
+
#
|
|
6
|
+
# Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
|
7
|
+
#
|
|
8
|
+
# 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
|
9
|
+
# 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
|
10
|
+
# 3. Neither the name of Jean-Pierre Morard nor the names of its contributors, or THALES SIX GTS France SAS, may be used to endorse or promote products derived from this software without specific prior written permission.
|
|
11
|
+
#
|
|
12
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
13
|
+
|
|
14
|
+
from pathlib import Path
|
|
15
|
+
from datetime import datetime
|
|
16
|
+
import streamlit as st
|
|
17
|
+
import importlib
|
|
18
|
+
import base64
|
|
19
|
+
import sys
|
|
20
|
+
import os
|
|
21
|
+
import argparse
|
|
22
|
+
|
|
23
|
+
# -------------------- Import Statements -------------------- #
|
|
24
|
+
# (Include any other necessary imports from your original code)
|
|
25
|
+
from agi_gui.pagelib import env, get_about_content, render_logo, open_docs, RESOURCE_PATH, get_base64_of_image
|
|
26
|
+
|
|
27
|
+
# -------------------- Import Statements -------------------- #
|
|
28
|
+
import ast
|
|
29
|
+
from datetime import datetime
|
|
30
|
+
import re
|
|
31
|
+
import json
|
|
32
|
+
import glob
|
|
33
|
+
from pathlib import Path, PurePosixPath, PureWindowsPath
|
|
34
|
+
from functools import lru_cache
|
|
35
|
+
import pandas as pd
|
|
36
|
+
import toml
|
|
37
|
+
import os
|
|
38
|
+
import io
|
|
39
|
+
import subprocess
|
|
40
|
+
import streamlit as st
|
|
41
|
+
import random
|
|
42
|
+
import socket
|
|
43
|
+
from PIL import Image
|
|
44
|
+
import base64
|
|
45
|
+
import runpy
|
|
46
|
+
from typing import List, Union, Optional, Dict
|
|
47
|
+
import sys
|
|
48
|
+
import importlib
|
|
49
|
+
|
|
50
|
+
def add_custom_css():
|
|
51
|
+
"""
|
|
52
|
+
Loads and injects external CSS into the Streamlit app.
|
|
53
|
+
"""
|
|
54
|
+
css_path = RESOURCE_PATH / "first_page.css"
|
|
55
|
+
css_content = load_file_content(css_path)
|
|
56
|
+
if css_content:
|
|
57
|
+
st.markdown(f"<style>{css_content}</style>", unsafe_allow_html=True)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def display_landing_page():
|
|
61
|
+
"""
|
|
62
|
+
Loads and displays the landing page Markdown content.
|
|
63
|
+
"""
|
|
64
|
+
|
|
65
|
+
img_data = get_base64_of_image(RESOURCE_PATH / "agi_logo.png")
|
|
66
|
+
img_src = f"data:image/png;base64,{img_data}"
|
|
67
|
+
md_content = f"""
|
|
68
|
+
<div style="background-color: #333333; padding: 20px; border-radius: 10px; box-shadow: 0 4px 6px rgba(0,0,0,0.1); max-width: 800px; margin: 20px auto;">
|
|
69
|
+
<div style="display: flex; align-items: center; justify-content: center;">
|
|
70
|
+
<h1 style="margin: 0; padding: 0 10px 0 0;">
|
|
71
|
+
Welcome to AGILAB
|
|
72
|
+
</h1>
|
|
73
|
+
<img src="{img_src}" alt="AGI Logo" style="width:100px;">
|
|
74
|
+
</div>
|
|
75
|
+
<div style="text-align: center;">
|
|
76
|
+
<strong style="color: black;">a step further toward AGI</strong>
|
|
77
|
+
</div>
|
|
78
|
+
</div>
|
|
79
|
+
|
|
80
|
+
<div class="uvp-highlight">
|
|
81
|
+
<strong>Founding Concept:</strong> AGILAB outlines a method for scaling into a project’s execution environment without the need for virtualization or containerization (such as Docker). The approach involves encapsulating an app's logic into two components: a worker (which is scalable and free from dependency constraints) and a manager (which is easily integrable due to minimal dependency requirements). This design enables seamless integration within a single app, contributing to the move toward Artificial General Intelligence (AGI).
|
|
82
|
+
</div>
|
|
83
|
+
|
|
84
|
+
<div class="uvp-highlight">
|
|
85
|
+
<strong>AGILAB</strong>: Revolutionizing Data Science Experimentation with Zero Integration Hassles. As a comprehensive framework built on 50KLOC of pure Python and powered by Gen AI and ML, AGILAB scales effortlessly—from embedded systems to the cloud—empowering seamless collaboration on data insights and predictive modeling.
|
|
86
|
+
</div>
|
|
87
|
+
|
|
88
|
+
<p><strong>Key Features:</strong></p>
|
|
89
|
+
<ul>
|
|
90
|
+
<li><strong>Strong AI Enabler</strong>: Algos Integrations.</li>
|
|
91
|
+
<li><strong>Engineering AI Enabler</strong>: Feature Engineering.</li>
|
|
92
|
+
<li><strong>Availability</strong>: Works online and in standalone mode.</li>
|
|
93
|
+
<li><strong>Enhanced Deployment Productivity</strong>: Automates virtual environment deployment.</li>
|
|
94
|
+
<li><strong>Enhanced Coding Productivity</strong>: Seamless integration with openai-api.</li>
|
|
95
|
+
<li><strong>Enhanced Scalability</strong>: Distributes both data and algorithms on a cluster.</li>
|
|
96
|
+
<li><strong>User-Friendly Interface for Data Science</strong>: Integration of Jupyter-ai and ML Flow.</li>
|
|
97
|
+
<li><strong>Advanced Execution Tools</strong>: Enables Map Reduce and Direct Acyclic Graph Orchestration.</li>
|
|
98
|
+
</ul>
|
|
99
|
+
|
|
100
|
+
<p>
|
|
101
|
+
With AGILAB, there’s no need for additional integration—our all-in-one framework is ready to deploy, enabling you to focus on innovation rather than setup.
|
|
102
|
+
</p>
|
|
103
|
+
|
|
104
|
+
<div class="uvp-highlight">
|
|
105
|
+
<strong>Tips:</strong> To benefit from AGI cluster automation functionality, all you need is <strong>agi-core</strong> and <strong>agi-env</strong>. This means you can remove the lab and view directories. Historically, AGILAB was developed as a playground for agi-core.
|
|
106
|
+
</div>
|
|
107
|
+
"""
|
|
108
|
+
|
|
109
|
+
st.markdown(md_content, unsafe_allow_html=True)
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
# -------------------- Additional Functions (e.g., logo rendering) -------------------- #
|
|
113
|
+
def render_logo_with_columns():
|
|
114
|
+
"""
|
|
115
|
+
Renders the agi logo centered on the main page using columns.
|
|
116
|
+
"""
|
|
117
|
+
logo_path = (
|
|
118
|
+
RESOURCE_PATH / "agi_logo.png"
|
|
119
|
+
) # Adjust the path if necessary
|
|
120
|
+
logo = Image.open(logo_path)
|
|
121
|
+
|
|
122
|
+
# Create three columns with ratios: 1:2:1
|
|
123
|
+
left_col, middle_col, right_col = st.columns([1, 2, 1])
|
|
124
|
+
|
|
125
|
+
with middle_col:
|
|
126
|
+
st.write("")
|
|
127
|
+
st.write("")
|
|
128
|
+
st.image(logo, width=200) # Adjust width as needed
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def load_file_content(file_path: Path) -> str:
|
|
132
|
+
"""
|
|
133
|
+
Reads the content of a file.
|
|
134
|
+
"""
|
|
135
|
+
try:
|
|
136
|
+
with open(file_path, "r", encoding="utf-8") as f:
|
|
137
|
+
return f.read()
|
|
138
|
+
except Exception as e:
|
|
139
|
+
st.error(f"Error loading {file_path}: {e}")
|
|
140
|
+
return ""
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
# -------------------- Custom CSS Styling -------------------- #
|
|
144
|
+
def add_custom_css():
|
|
145
|
+
"""
|
|
146
|
+
Add custom CSS styles to the Streamlit app.
|
|
147
|
+
|
|
148
|
+
This function adds custom CSS styles to the Streamlit app to customize the appearance of the page.
|
|
149
|
+
|
|
150
|
+
Args:
|
|
151
|
+
None
|
|
152
|
+
|
|
153
|
+
Returns:
|
|
154
|
+
None
|
|
155
|
+
|
|
156
|
+
Raises:
|
|
157
|
+
None
|
|
158
|
+
"""
|
|
159
|
+
custom_css = """
|
|
160
|
+
<style>
|
|
161
|
+
/* Set the background color for the entire page */
|
|
162
|
+
.reportview-container {
|
|
163
|
+
background-color: white; /* Light grey background for a clean look */
|
|
164
|
+
}
|
|
165
|
+
/* Set the background color for the sidebar */
|
|
166
|
+
.sidebar .sidebar-content {
|
|
167
|
+
background-color: white; /* White sidebar for contrast */
|
|
168
|
+
}
|
|
169
|
+
/* Style for header section */
|
|
170
|
+
.header {
|
|
171
|
+
background-color: #1E90FF; /* Primary Blue aligning with :one: emoji */
|
|
172
|
+
padding: 40px 20px;
|
|
173
|
+
text-align: left;
|
|
174
|
+
}
|
|
175
|
+
/* Style for main headers */
|
|
176
|
+
.header h1 {
|
|
177
|
+
color: white; /* White title */
|
|
178
|
+
font-family: 'Helvetica', sans-serif;
|
|
179
|
+
font-weight: bold;
|
|
180
|
+
font-size: 48px;
|
|
181
|
+
margin-bottom: 10px;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/* Style for footer */
|
|
185
|
+
.footer {
|
|
186
|
+
position: fixed;
|
|
187
|
+
left: 0;
|
|
188
|
+
bottom: 0;
|
|
189
|
+
width: 100%;
|
|
190
|
+
background-color: #1E90FF; /* Primary Blue */
|
|
191
|
+
color: white;
|
|
192
|
+
text-align: center;
|
|
193
|
+
padding: 10px 0;
|
|
194
|
+
font-family: 'Helvetica', sans-serif;
|
|
195
|
+
font-size: 14px;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/* Hide Streamlit's default hamburger menu and footer */
|
|
199
|
+
footer {visibility: hidden;}
|
|
200
|
+
|
|
201
|
+
/* New CSS class for UVP highlighting */
|
|
202
|
+
.uvp-highlight {
|
|
203
|
+
background-color: #f0f8ff; /* Light Blue Background */
|
|
204
|
+
color: #333333; /* Dark Text for Contrast */
|
|
205
|
+
padding: 20px; /* Inner Padding */
|
|
206
|
+
border-left: 5px solid #1E90FF; /* Blue Border on the Left */
|
|
207
|
+
border-radius: 5px; /* Rounded Corners */
|
|
208
|
+
margin-top: 20px; /* Top Margin */
|
|
209
|
+
margin-bottom: 20px; /* Bottom Margin */
|
|
210
|
+
font-size: 18px; /* Font Size */
|
|
211
|
+
line-height: 1.6; /* Line Height for Readability */
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/* Optional: Adjust list styles within UVP */
|
|
215
|
+
.uvp-highlight ul {
|
|
216
|
+
list-style-type: disc;
|
|
217
|
+
margin-left: 20px;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/* Optional: Enhance the visibility of strong tags within UVP */
|
|
221
|
+
.uvp-highlight strong {
|
|
222
|
+
color: #1E90FF; /* Blue Color for Emphasis */
|
|
223
|
+
}
|
|
224
|
+
</style>
|
|
225
|
+
"""
|
|
226
|
+
st.markdown(custom_css, unsafe_allow_html=True)
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
# -------------------- Exception Class -------------------- #
|
|
230
|
+
class JumpToMain(Exception):
|
|
231
|
+
"""
|
|
232
|
+
Custom exception to jump back to the main execution flow.
|
|
233
|
+
"""
|
|
234
|
+
|
|
235
|
+
pass
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
# -------------------- Initialize Page Configuration -------------------- #
|
|
239
|
+
|
|
240
|
+
# Load your logo from a file
|
|
241
|
+
agi_logo = Image.open(RESOURCE_PATH / "agi_logo.png")
|
|
242
|
+
|
|
243
|
+
# Ensure this is the very first Streamlit command after imports and function definitions
|
|
244
|
+
st.set_page_config(
|
|
245
|
+
menu_items=get_about_content(), # Adjust if necessary
|
|
246
|
+
layout="wide"
|
|
247
|
+
)
|
|
248
|
+
|
|
249
|
+
# -------------------- Inject Custom CSS -------------------- #
|
|
250
|
+
add_custom_css()
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
# -------------------- Render Logos -------------------- #
|
|
254
|
+
# Render the logo in the sidebar
|
|
255
|
+
# render_logo()
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
# -------------------- Streamlit Page Rendering -------------------- #
|
|
259
|
+
def page():
|
|
260
|
+
# Override the default .block-container styling
|
|
261
|
+
"""
|
|
262
|
+
Display a landing page for AGILAB.
|
|
263
|
+
"""
|
|
264
|
+
# Display landing page content from external Markdown file
|
|
265
|
+
display_landing_page()
|
|
266
|
+
|
|
267
|
+
cols = st.columns(2)
|
|
268
|
+
help_file = env.help_path / "index.html"
|
|
269
|
+
if cols[0].button("Read Documentation", type="tertiary", use_container_width=True):
|
|
270
|
+
open_docs(env, help_file, "project-editor")
|
|
271
|
+
|
|
272
|
+
# Add a button to proceed
|
|
273
|
+
if cols[1].button("Get Started", type="tertiary", use_container_width=True):
|
|
274
|
+
st.write("Redirecting to the main application...")
|
|
275
|
+
# Set the current page to '▶️ EDIT' and rerun the app
|
|
276
|
+
st.session_state.current_page = "▶️ EDIT"
|
|
277
|
+
st.query_params["current_page"] = "▶️ EDIT"
|
|
278
|
+
st.rerun()
|
|
279
|
+
|
|
280
|
+
# Footer with custom styling
|
|
281
|
+
current_year = datetime.now().year
|
|
282
|
+
st.markdown(
|
|
283
|
+
f"""
|
|
284
|
+
<div class='footer'>
|
|
285
|
+
© 2020-{current_year} Thales SIX GTS. All rights reserved.
|
|
286
|
+
</div>
|
|
287
|
+
""",
|
|
288
|
+
unsafe_allow_html=True,
|
|
289
|
+
)
|
|
290
|
+
|
|
291
|
+
|
|
292
|
+
# -------------------- Main Application Entry -------------------- #
|
|
293
|
+
import argparse
|
|
294
|
+
import sys
|
|
295
|
+
import os
|
|
296
|
+
from pathlib import Path
|
|
297
|
+
from datetime import datetime
|
|
298
|
+
import streamlit as st
|
|
299
|
+
import importlib
|
|
300
|
+
|
|
301
|
+
# -------------------- Import Statements -------------------- #
|
|
302
|
+
from agi_gui.pagelib import (
|
|
303
|
+
env,
|
|
304
|
+
get_about_content,
|
|
305
|
+
render_logo,
|
|
306
|
+
open_docs,
|
|
307
|
+
RESOURCE_PATH,
|
|
308
|
+
get_base64_of_image,
|
|
309
|
+
)
|
|
310
|
+
|
|
311
|
+
# Additional imports
|
|
312
|
+
import ast
|
|
313
|
+
import re
|
|
314
|
+
import json
|
|
315
|
+
import glob
|
|
316
|
+
from pathlib import PurePosixPath, PureWindowsPath
|
|
317
|
+
from functools import lru_cache
|
|
318
|
+
import pandas as pd
|
|
319
|
+
import toml
|
|
320
|
+
import io
|
|
321
|
+
import subprocess
|
|
322
|
+
import random
|
|
323
|
+
import socket
|
|
324
|
+
from PIL import Image
|
|
325
|
+
import base64
|
|
326
|
+
import runpy
|
|
327
|
+
from typing import List, Union, Optional, Dict
|
|
328
|
+
|
|
329
|
+
# -------------------- Helper Functions -------------------- #
|
|
330
|
+
|
|
331
|
+
def add_custom_css():
|
|
332
|
+
"""
|
|
333
|
+
Loads and injects external CSS into the Streamlit app.
|
|
334
|
+
"""
|
|
335
|
+
css_path = RESOURCE_PATH / "first_page.css"
|
|
336
|
+
css_content = load_file_content(css_path)
|
|
337
|
+
if css_content:
|
|
338
|
+
st.markdown(f"<style>{css_content}</style>", unsafe_allow_html=True)
|
|
339
|
+
|
|
340
|
+
def load_file_content(file_path: Path) -> str:
|
|
341
|
+
"""
|
|
342
|
+
Reads the content of a file.
|
|
343
|
+
"""
|
|
344
|
+
try:
|
|
345
|
+
with open(file_path, "r", encoding="utf-8") as f:
|
|
346
|
+
return f.read()
|
|
347
|
+
except Exception as e:
|
|
348
|
+
st.error(f"Error loading {file_path}: {e}")
|
|
349
|
+
return ""
|
|
350
|
+
|
|
351
|
+
def display_landing_page():
|
|
352
|
+
"""
|
|
353
|
+
Loads and displays the landing page Markdown content.
|
|
354
|
+
"""
|
|
355
|
+
img_data = get_base64_of_image(RESOURCE_PATH / "agi_logo.png")
|
|
356
|
+
img_src = f"data:image/png;base64,{img_data}"
|
|
357
|
+
md_content = f"""
|
|
358
|
+
<div style="background-color: #333333; padding: 20px; border-radius: 10px; box-shadow: 0 4px 6px rgba(0,0,0,0.1); max-width: 800px; margin: 20px auto;">
|
|
359
|
+
<div style="display: flex; align-items: center; justify-content: center;">
|
|
360
|
+
<h1 style="margin: 0; padding: 0 10px 0 0;">Welcome to AGILAB</h1>
|
|
361
|
+
<img src="{img_src}" alt="AGI Logo" style="width:100px;">
|
|
362
|
+
</div>
|
|
363
|
+
<div style="text-align: center;">
|
|
364
|
+
<strong style="color: black;">a step further toward AGI</strong>
|
|
365
|
+
</div>
|
|
366
|
+
</div>
|
|
367
|
+
<div class="uvp-highlight">
|
|
368
|
+
<strong>Founding Concept:</strong> AGILAB outlines a method for scaling into a project’s execution environment without the need for virtualization or containerization (such as Docker). The approach involves encapsulating an app's logic into two components: a worker (which is scalable and free from dependency constraints) and a manager (which is easily integrable due to minimal dependency requirements). This design enables seamless integration within a single app, contributing to the move toward Artificial General Intelligence (AGI).
|
|
369
|
+
</div>
|
|
370
|
+
<div class="uvp-highlight">
|
|
371
|
+
<strong>AGILAB</strong>: Revolutionizing Data Science Experimentation with Zero Integration Hassles. As a comprehensive framework built on 50KLOC of pure Python and powered by Gen AI and ML, AGILAB scales effortlessly—from embedded systems to the cloud—empowering seamless collaboration on data insights and predictive modeling.
|
|
372
|
+
</div>
|
|
373
|
+
<p><strong>Key Features:</strong></p>
|
|
374
|
+
<ul>
|
|
375
|
+
<li><strong>Strong AI Enabler</strong>: Algos Integrations.</li>
|
|
376
|
+
<li><strong>Engineering AI Enabler</strong>: Feature Engineering.</li>
|
|
377
|
+
<li><strong>Availability</strong>: Works online and in standalone mode.</li>
|
|
378
|
+
<li><strong>Enhanced Deployment Productivity</strong>: Automates virtual environment deployment.</li>
|
|
379
|
+
<li><strong>Enhanced Coding Productivity</strong>: Seamless integration with openai-api.</li>
|
|
380
|
+
<li><strong>Enhanced Scalability</strong>: Distributes both data and algorithms on a cluster.</li>
|
|
381
|
+
<li><strong>User-Friendly Interface for Data Science</strong>: Integration of Jupyter-ai and ML Flow.</li>
|
|
382
|
+
<li><strong>Advanced Execution Tools</strong>: Enables Map Reduce and Direct Acyclic Graph Orchestration.</li>
|
|
383
|
+
</ul>
|
|
384
|
+
<p>
|
|
385
|
+
With AGILAB, there’s no need for additional integration—our all-in-one framework is ready to deploy, enabling you to focus on innovation rather than setup.
|
|
386
|
+
</p>
|
|
387
|
+
<div class="uvp-highlight">
|
|
388
|
+
<strong>Tips:</strong> To benefit from AGI cluster automation functionality, all you need is <strong>agi-core</strong> and <strong>agi-env</strong>. This means you can remove the lab and view directories. Historically, AGILAB was developed as a playground for agi-core.
|
|
389
|
+
</div>
|
|
390
|
+
"""
|
|
391
|
+
st.markdown(md_content, unsafe_allow_html=True)
|
|
392
|
+
|
|
393
|
+
def page():
|
|
394
|
+
"""
|
|
395
|
+
Display the landing page for AGILAB.
|
|
396
|
+
"""
|
|
397
|
+
display_landing_page()
|
|
398
|
+
cols = st.columns(2)
|
|
399
|
+
help_file = st.session_state["env"].help_path / "index.html"
|
|
400
|
+
if cols[0].button("Read Documentation", type="tertiary", use_container_width=True):
|
|
401
|
+
open_docs(st.session_state["env"], help_file, "project-editor")
|
|
402
|
+
if cols[1].button("Get Started", type="tertiary", use_container_width=True):
|
|
403
|
+
st.write("Redirecting to the main application...")
|
|
404
|
+
st.session_state.current_page = "▶️ EDIT"
|
|
405
|
+
st.rerun()
|
|
406
|
+
current_year = datetime.now().year
|
|
407
|
+
st.markdown(
|
|
408
|
+
f"""
|
|
409
|
+
<div class='footer'>
|
|
410
|
+
© 2020-{current_year} Thales SIX GTS. All rights reserved.
|
|
411
|
+
</div>
|
|
412
|
+
""",
|
|
413
|
+
unsafe_allow_html=True,
|
|
414
|
+
)
|
|
415
|
+
|
|
416
|
+
def read_env_key(key: str) -> str:
|
|
417
|
+
"""
|
|
418
|
+
Look for the given key in os.environ, then in ~/.agilab/.env.
|
|
419
|
+
Return the value if found (and non-empty), otherwise return an empty string.
|
|
420
|
+
"""
|
|
421
|
+
# 1. Check os.environ
|
|
422
|
+
value = os.environ.get(key, "").strip()
|
|
423
|
+
if value:
|
|
424
|
+
return value
|
|
425
|
+
|
|
426
|
+
# 2. Check ~/.agilab/.env file if it exists
|
|
427
|
+
env_file = Path.home() / ".agilab" / ".env"
|
|
428
|
+
if env_file.exists():
|
|
429
|
+
with env_file.open("r") as f:
|
|
430
|
+
for line in f:
|
|
431
|
+
if '=' in line:
|
|
432
|
+
k, v = line.strip().split('=', 1)
|
|
433
|
+
if k == key and v.strip():
|
|
434
|
+
return v.strip()
|
|
435
|
+
return ""
|
|
436
|
+
|
|
437
|
+
# -------------------- Main Application Entry -------------------- #
|
|
438
|
+
def main():
|
|
439
|
+
"""
|
|
440
|
+
Main function to run the application.
|
|
441
|
+
"""
|
|
442
|
+
# --- Command-Line Argument Parsing ---
|
|
443
|
+
parser = argparse.ArgumentParser(
|
|
444
|
+
description="Run the AGI Streamlit App with optional parameters."
|
|
445
|
+
)
|
|
446
|
+
parser.add_argument(
|
|
447
|
+
"--cluster-credentials",
|
|
448
|
+
type=str,
|
|
449
|
+
help="Cluster credentials (username:password)",
|
|
450
|
+
default=None
|
|
451
|
+
)
|
|
452
|
+
parser.add_argument(
|
|
453
|
+
"--openai-api-key",
|
|
454
|
+
type=str,
|
|
455
|
+
help="OpenAI API key (mandatory)",
|
|
456
|
+
default=None
|
|
457
|
+
)
|
|
458
|
+
args, unknown = parser.parse_known_args()
|
|
459
|
+
|
|
460
|
+
# Try to get the values from os.environ or the .env file first.
|
|
461
|
+
openai_api_key = read_env_key("OPENAI_API_KEY")
|
|
462
|
+
if not openai_api_key:
|
|
463
|
+
# If not found in environment or .env, override with CLI argument if provided.
|
|
464
|
+
openai_api_key = args.openai_api_key
|
|
465
|
+
if not openai_api_key:
|
|
466
|
+
openai_api_key = input("Enter OpenAI API key: ").strip()
|
|
467
|
+
if not openai_api_key:
|
|
468
|
+
print("Error: Missing mandatory parameter: --openai-api-key")
|
|
469
|
+
sys.exit(1)
|
|
470
|
+
|
|
471
|
+
cluster_credentials = read_env_key("CLUSTER_CREDENTIALS")
|
|
472
|
+
if not cluster_credentials:
|
|
473
|
+
cluster_credentials = args.cluster_credentials
|
|
474
|
+
if not cluster_credentials:
|
|
475
|
+
# Prompt for cluster info only if not found
|
|
476
|
+
cluster_enabled = input("Is cluster available? [N/y]: ").strip().lower() or "n"
|
|
477
|
+
if cluster_enabled == "y":
|
|
478
|
+
ssh_key_set = input("Is SSH key set? [N/y]: ").strip().lower() or "n"
|
|
479
|
+
if ssh_key_set == "y":
|
|
480
|
+
cluster_credentials = input("Enter user (SSH key is set): ").strip()
|
|
481
|
+
else:
|
|
482
|
+
cluster_credentials = input("Enter cluster credentials (user:password): ").strip()
|
|
483
|
+
else:
|
|
484
|
+
cluster_credentials = ""
|
|
485
|
+
|
|
486
|
+
# Store the final values in the environment
|
|
487
|
+
os.environ["OPENAI_API_KEY"] = openai_api_key
|
|
488
|
+
os.environ["CLUSTER_CREDENTIALS"] = cluster_credentials
|
|
489
|
+
|
|
490
|
+
# Update or create the .agilab/.env file if the keys are not already present
|
|
491
|
+
env_file = Path.home() / ".agilab" / ".env"
|
|
492
|
+
env_file.parent.mkdir(parents=True, exist_ok=True)
|
|
493
|
+
current = {}
|
|
494
|
+
if env_file.exists():
|
|
495
|
+
with env_file.open("r") as f:
|
|
496
|
+
for line in f:
|
|
497
|
+
if '=' in line:
|
|
498
|
+
k, v = line.strip().split('=', 1)
|
|
499
|
+
current[k] = v
|
|
500
|
+
with env_file.open("a") as f:
|
|
501
|
+
if "OPENAI_API_KEY" not in current or not current["OPENAI_API_KEY"]:
|
|
502
|
+
f.write(f"OPENAI_API_KEY={openai_api_key}\n")
|
|
503
|
+
if "CLUSTER_CREDENTIALS" not in current or not current["CLUSTER_CREDENTIALS"]:
|
|
504
|
+
f.write(f"CLUSTER_CREDENTIALS={cluster_credentials}\n")
|
|
505
|
+
|
|
506
|
+
# Adjust sys.path to include agi_env if needed.
|
|
507
|
+
path_agi_env = Path("fwk/env/src").resolve()
|
|
508
|
+
path_agi = str(path_agi_env)
|
|
509
|
+
if path_agi not in sys.path:
|
|
510
|
+
sys.path.insert(0, path_agi)
|
|
511
|
+
from agi_env.agi_env import AgiEnv
|
|
512
|
+
|
|
513
|
+
# -------------------- Global Configurations -------------------- #
|
|
514
|
+
treshold = 1
|
|
515
|
+
snippet_run_error = "fail to run your python snippet"
|
|
516
|
+
env_obj = AgiEnv("flight", with_lab=True, verbose=True)
|
|
517
|
+
st.session_state["env"] = env_obj
|
|
518
|
+
default_steps_file = "steps.toml"
|
|
519
|
+
default_df = "export.csv"
|
|
520
|
+
st.session_state["rapids_default"] = True
|
|
521
|
+
|
|
522
|
+
|
|
523
|
+
# -------------------- Navigation and Page Rendering -------------------- #
|
|
524
|
+
try:
|
|
525
|
+
if "current_page" not in st.session_state:
|
|
526
|
+
st.session_state.current_page = "AGILAB"
|
|
527
|
+
|
|
528
|
+
if st.session_state.current_page == "AGILAB":
|
|
529
|
+
st.session_state.current_page = None
|
|
530
|
+
page()
|
|
531
|
+
elif st.session_state.current_page == "▶️ EDIT":
|
|
532
|
+
st.session_state.current_page = None
|
|
533
|
+
page_module = importlib.import_module("pages.▶️ EDIT")
|
|
534
|
+
page_module.main()
|
|
535
|
+
else:
|
|
536
|
+
page()
|
|
537
|
+
except Exception as e:
|
|
538
|
+
st.error(f"An error occurred: {e}")
|
|
539
|
+
import traceback
|
|
540
|
+
st.error(traceback.format_exc())
|
|
541
|
+
|
|
542
|
+
# -------------------- Run the App -------------------- #
|
|
543
|
+
if __name__ == "__main__":
|
|
544
|
+
main()
|
agi_gui/__init__.py
ADDED
|
File without changes
|
agi_gui/agi_copilot.py
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# BSD 3-Clause License
|
|
2
|
+
#
|
|
3
|
+
# Copyright (c) 2025, Jean-Pierre Morard, THALES SIX GTS France SAS
|
|
4
|
+
# All rights reserved.
|
|
5
|
+
#
|
|
6
|
+
# Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
|
7
|
+
#
|
|
8
|
+
# 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
|
9
|
+
# 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
|
10
|
+
# 3. Neither the name of Jean-Pierre Morard nor the names of its contributors, or THALES SIX GTS France SAS, may be used to endorse or promote products derived from this software without specific prior written permission.
|
|
11
|
+
#
|
|
12
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
13
|
+
|
|
14
|
+
import traceback
|
|
15
|
+
|
|
16
|
+
import streamlit as st
|
|
17
|
+
|
|
18
|
+
df = st.session_state.loaded_df
|
|
19
|
+
snippet_file = st.session_state.snippet_file
|
|
20
|
+
|
|
21
|
+
with open(snippet_file, "r") as snippet:
|
|
22
|
+
try:
|
|
23
|
+
exec(snippet.read())
|
|
24
|
+
|
|
25
|
+
except KeyError as err:
|
|
26
|
+
raise KeyError(
|
|
27
|
+
f"{snippet_file}: columns name {err.args[0]} is not present in the dateframe, "
|
|
28
|
+
f"please rename it with a name of a column already in the dataset"
|
|
29
|
+
) from err
|
|
30
|
+
|
|
31
|
+
except Exception as err:
|
|
32
|
+
st.error(f"```{snippet_file}: {err}\n{traceback.format_exc()}```")
|
|
33
|
+
st.session_state.data = df
|
agi_gui/lab_run.py
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import argparse
|
|
2
|
+
import sys
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
import streamlit.web.cli as stcli
|
|
5
|
+
|
|
6
|
+
def check_environment():
|
|
7
|
+
|
|
8
|
+
# Check if current directory is acceptable:
|
|
9
|
+
cwd = Path.cwd()
|
|
10
|
+
# For example, accept if the cwd contains 'pyproject.toml'
|
|
11
|
+
if not (cwd / "pyproject.toml").exists() and "agilab/src/fwk/gui" not in str(cwd):
|
|
12
|
+
print("Error: Please run this command from a directory that contains your agilab project (e.g. the project root or agilab/src/fwk/gui).")
|
|
13
|
+
sys.exit(1)
|
|
14
|
+
|
|
15
|
+
# Check if the package is installed (optional):
|
|
16
|
+
try:
|
|
17
|
+
import agi_gui # or any module from your package
|
|
18
|
+
except ImportError:
|
|
19
|
+
print("Error: The agilab package is not installed in this environment.")
|
|
20
|
+
sys.exit(1)
|
|
21
|
+
|
|
22
|
+
def main():
|
|
23
|
+
|
|
24
|
+
check_environment()
|
|
25
|
+
|
|
26
|
+
parser = argparse.ArgumentParser(
|
|
27
|
+
description="Run AGILAB application with custom options."
|
|
28
|
+
)
|
|
29
|
+
parser.add_argument(
|
|
30
|
+
"--cluster-credentials", type=str, help="Cluster account user:password", default=None
|
|
31
|
+
)
|
|
32
|
+
parser.add_argument(
|
|
33
|
+
"--openai-api-key", type=str, help="OpenAI API key", default=None
|
|
34
|
+
)
|
|
35
|
+
# Parse known arguments; extra arguments are captured in `unknown`
|
|
36
|
+
args, unknown = parser.parse_known_args()
|
|
37
|
+
|
|
38
|
+
# Determine the target script (adjust path if necessary)
|
|
39
|
+
target_script = str(Path(__file__).parent / "AGILAB.py")
|
|
40
|
+
|
|
41
|
+
# Build the base argument list for Streamlit.
|
|
42
|
+
new_argv = ["streamlit", "run", target_script]
|
|
43
|
+
|
|
44
|
+
# Collect custom arguments.
|
|
45
|
+
custom_args = []
|
|
46
|
+
if args.cluster_credentials is not None:
|
|
47
|
+
custom_args.extend(["--cluster-credentials", args.cluster_credentials])
|
|
48
|
+
if args.openai_api_key is not None:
|
|
49
|
+
custom_args.extend(["--openai-api-key", args.openai_api_key])
|
|
50
|
+
if unknown:
|
|
51
|
+
custom_args.extend(unknown)
|
|
52
|
+
|
|
53
|
+
# Only add the double dash and custom arguments if there are any.
|
|
54
|
+
if custom_args:
|
|
55
|
+
new_argv.append("--")
|
|
56
|
+
new_argv.extend(custom_args)
|
|
57
|
+
|
|
58
|
+
sys.argv = new_argv
|
|
59
|
+
sys.exit(stcli.main())
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
if __name__ == "__main__":
|
|
63
|
+
main()
|