cryogenic22 commited on
Commit
3bf644c
·
verified ·
1 Parent(s): 284a75b

Create code_playground.py

Browse files
Files changed (1) hide show
  1. src/components/code_playground.py +329 -0
src/components/code_playground.py ADDED
@@ -0,0 +1,329 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import sys
3
+ from io import StringIO
4
+ from contextlib import redirect_stdout
5
+ import json
6
+ from datetime import datetime
7
+ from typing import Dict, List, Optional
8
+ import base64
9
+ from PIL import Image
10
+ import io
11
+ import os
12
+ import zipfile
13
+ from pathlib import Path
14
+ import shutil
15
+
16
+ class CodePlayground:
17
+ def __init__(self):
18
+ self.initialize_session_state()
19
+
20
+ @staticmethod
21
+ def initialize_session_state():
22
+ """Initialize session state for artifacts and history"""
23
+ if 'artifacts' not in st.session_state:
24
+ st.session_state.artifacts = []
25
+ if 'code_history' not in st.session_state:
26
+ st.session_state.code_history = []
27
+ if 'current_artifact' not in st.session_state:
28
+ st.session_state.current_artifact = None
29
+
30
+ @staticmethod
31
+ def display():
32
+ """Display the enhanced code playground interface"""
33
+ st.header("Interactive Learning Playground")
34
+
35
+ # Create tabs for different views
36
+ code_tab, artifacts_tab = st.tabs(["Code Editor", "Learning Artifacts"])
37
+
38
+ playground = CodePlayground()
39
+
40
+ with code_tab:
41
+ playground.display_code_editor()
42
+
43
+ with artifacts_tab:
44
+ playground.display_artifacts()
45
+
46
+ def display_code_editor(self):
47
+ """Display the code editor interface"""
48
+ # Code editor
49
+ code = st.text_area(
50
+ "Write your Python code here",
51
+ height=200,
52
+ key="code_editor",
53
+ help="Write Python code to execute. You can use print() to see outputs."
54
+ )
55
+
56
+ # Button columns
57
+ col1, col2, col3 = st.columns(3)
58
+
59
+ with col1:
60
+ if st.button("Run Code", key="run_code"):
61
+ output, artifact_data = self.execute_code(code)
62
+ if artifact_data:
63
+ self.store_artifact(artifact_data)
64
+
65
+ with col2:
66
+ if st.button("Save as Artifact", key="save_artifact"):
67
+ self.create_manual_artifact(code)
68
+
69
+ with col3:
70
+ if st.button("Clear Output", key="clear_output"):
71
+ if 'code_output' in st.session_state:
72
+ del st.session_state.code_output
73
+
74
+ # Display output
75
+ if 'code_output' in st.session_state:
76
+ st.markdown("### Output:")
77
+ st.code(st.session_state.code_output)
78
+
79
+ def display_artifacts(self):
80
+ """Display stored learning artifacts"""
81
+ st.subheader("Learning Artifacts")
82
+
83
+ if not st.session_state.artifacts:
84
+ st.info("No artifacts created yet. Run some code or create manual artifacts to see them here!")
85
+ return
86
+
87
+ # Filter options
88
+ filter_type = st.selectbox(
89
+ "Filter by type",
90
+ options=["All", "Code", "Image", "Text", "Mixed Media"],
91
+ key="artifact_filter"
92
+ )
93
+
94
+ # Export buttons
95
+ col1, col2 = st.columns(2)
96
+ with col1:
97
+ if st.button("Export All Artifacts"):
98
+ try:
99
+ # Use temporary directory for export
100
+ temp_dir = Path("temp_export")
101
+ temp_dir.mkdir(exist_ok=True)
102
+
103
+ zip_path = self.export_all_artifacts(str(temp_dir))
104
+
105
+ # Read the zip file
106
+ with open(zip_path, "rb") as fp:
107
+ zip_data = fp.read()
108
+
109
+ # Create download button
110
+ st.download_button(
111
+ label="Download Artifacts",
112
+ data=zip_data,
113
+ file_name="learning_artifacts.zip",
114
+ mime="application/zip"
115
+ )
116
+ st.success("Artifacts exported successfully!")
117
+ except Exception as e:
118
+ st.error(f"Error exporting artifacts: {str(e)}")
119
+ finally:
120
+ # Cleanup
121
+ if temp_dir.exists():
122
+ shutil.rmtree(temp_dir)
123
+
124
+ # Display artifacts in reverse chronological order
125
+ for artifact in reversed(st.session_state.artifacts):
126
+ if filter_type == "All" or artifact['type'] == filter_type:
127
+ with st.expander(f"{artifact['title']} - {artifact['date']}", expanded=False):
128
+ st.write(f"**Type:** {artifact['type']}")
129
+ st.write(f"**Created:** {artifact['date']}")
130
+
131
+ # Display content based on type
132
+ if artifact['type'] == "Code":
133
+ st.code(artifact['content'], language="python")
134
+ elif artifact['type'] == "Image":
135
+ st.image(base64.b64decode(artifact['content']))
136
+ elif artifact['type'] == "Text":
137
+ st.write(artifact['content'])
138
+ elif artifact['type'] == "Mixed Media":
139
+ for item in artifact['content']:
140
+ if item['type'] == "code":
141
+ st.code(item['data'], language="python")
142
+ elif item['type'] == "image":
143
+ st.image(base64.b64decode(item['data']))
144
+ elif item['type'] == "text":
145
+ st.write(item['data'])
146
+
147
+ # Artifact actions
148
+ col1, col2 = st.columns(2)
149
+ with col1:
150
+ if st.button("Load in Editor", key=f"load_{artifact['id']}"):
151
+ if artifact['type'] == "Code":
152
+ st.session_state.code_editor = artifact['content']
153
+ st.rerun()
154
+
155
+ with col2:
156
+ if st.button("Delete", key=f"delete_{artifact['id']}"):
157
+ self.delete_artifact(artifact['id'])
158
+ st.rerun()
159
+
160
+ def execute_code(self, code: str) -> tuple:
161
+ """Execute code and capture outputs"""
162
+ output = StringIO()
163
+ artifact_data = None
164
+
165
+ try:
166
+ # Create a restricted environment
167
+ globals_dict = {
168
+ '__builtins__': __builtins__,
169
+ 'print': print,
170
+ 'Image': Image,
171
+ 'io': io,
172
+ 'base64': base64,
173
+ 'create_artifact': create_artifact
174
+ }
175
+
176
+ # Capture stdout
177
+ with redirect_stdout(output):
178
+ # Execute the code
179
+ exec(code, globals_dict, {})
180
+
181
+ # Store output
182
+ output_text = output.getvalue()
183
+ st.session_state.code_output = output_text
184
+
185
+ # Check for generated artifacts in globals
186
+ if '_artifact_output' in globals_dict:
187
+ artifact_data = globals_dict['_artifact_output']
188
+
189
+ # Store in history
190
+ self.store_in_history(code, output_text)
191
+
192
+ return output_text, artifact_data
193
+
194
+ except Exception as e:
195
+ error_msg = f"Error: {str(e)}"
196
+ st.session_state.code_output = error_msg
197
+ return error_msg, None
198
+
199
+ def export_artifact(self, artifact: Dict, export_dir: str):
200
+ """Export a single artifact to the specified directory"""
201
+ # Create directory if it doesn't exist
202
+ artifact_dir = Path(export_dir) / str(artifact['id'])
203
+ artifact_dir.mkdir(parents=True, exist_ok=True)
204
+
205
+ # Export metadata
206
+ metadata = {
207
+ 'id': artifact['id'],
208
+ 'title': artifact['title'],
209
+ 'type': artifact['type'],
210
+ 'date': artifact['date']
211
+ }
212
+
213
+ with open(artifact_dir / 'metadata.json', 'w') as f:
214
+ json.dump(metadata, f, indent=2)
215
+
216
+ # Export content based on type
217
+ if artifact['type'] == "Code":
218
+ with open(artifact_dir / 'content.py', 'w') as f:
219
+ f.write(artifact['content'])
220
+
221
+ elif artifact['type'] == "Image":
222
+ img_data = base64.b64decode(artifact['content'])
223
+ with open(artifact_dir / 'content.png', 'wb') as f:
224
+ f.write(img_data)
225
+
226
+ elif artifact['type'] == "Text":
227
+ with open(artifact_dir / 'content.txt', 'w') as f:
228
+ f.write(artifact['content'])
229
+
230
+ elif artifact['type'] == "Mixed Media":
231
+ media_dir = artifact_dir / 'content'
232
+ media_dir.mkdir(exist_ok=True)
233
+
234
+ for idx, item in enumerate(artifact['content']):
235
+ if item['type'] == 'code':
236
+ with open(media_dir / f'code_{idx}.py', 'w') as f:
237
+ f.write(item['data'])
238
+ elif item['type'] == 'image':
239
+ img_data = base64.b64decode(item['data'])
240
+ with open(media_dir / f'image_{idx}.png', 'wb') as f:
241
+ f.write(img_data)
242
+ elif item['type'] == 'text':
243
+ with open(media_dir / f'text_{idx}.txt', 'w') as f:
244
+ f.write(item['data'])
245
+
246
+ def export_all_artifacts(self, export_dir: str):
247
+ """Export all artifacts to a directory and create a zip file"""
248
+ # Create temporary directory for exports
249
+ temp_dir = Path(export_dir) / 'temp_artifacts'
250
+ temp_dir.mkdir(parents=True, exist_ok=True)
251
+
252
+ try:
253
+ # Export each artifact
254
+ for artifact in st.session_state.artifacts:
255
+ self.export_artifact(artifact, str(temp_dir))
256
+
257
+ # Create zip file
258
+ zip_path = Path(export_dir) / 'learning_artifacts.zip'
259
+ with zipfile.ZipFile(zip_path, 'w', zipfile.ZIP_DEFLATED) as zipf:
260
+ for root, _, files in os.walk(temp_dir):
261
+ for file in files:
262
+ file_path = Path(root) / file
263
+ arcname = file_path.relative_to(temp_dir)
264
+ zipf.write(file_path, arcname)
265
+
266
+ return str(zip_path)
267
+ finally:
268
+ # Clean up temporary directory
269
+ shutil.rmtree(temp_dir)
270
+
271
+ def store_artifact(self, artifact_data: Dict):
272
+ """Store a new artifact"""
273
+ artifact = {
274
+ 'id': len(st.session_state.artifacts),
275
+ 'date': datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
276
+ **artifact_data
277
+ }
278
+ st.session_state.artifacts.append(artifact)
279
+ st.success(f"Created new artifact: {artifact['title']}")
280
+
281
+ def create_manual_artifact(self, code: str):
282
+ """Create a manual artifact from current code"""
283
+ title = st.text_input("Artifact Title")
284
+ if title:
285
+ artifact = {
286
+ 'id': len(st.session_state.artifacts),
287
+ 'title': title,
288
+ 'type': "Code",
289
+ 'content': code,
290
+ 'date': datetime.now().strftime("%Y-%m-%d %H:%M:%S")
291
+ }
292
+ st.session_state.artifacts.append(artifact)
293
+ st.success(f"Created new artifact: {title}")
294
+
295
+ def delete_artifact(self, artifact_id: int):
296
+ """Delete an artifact"""
297
+ st.session_state.artifacts = [
298
+ a for a in st.session_state.artifacts if a['id'] != artifact_id
299
+ ]
300
+
301
+ def store_in_history(self, code: str, output: str):
302
+ """Store code execution in history"""
303
+ history_entry = {
304
+ 'timestamp': datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
305
+ 'code': code,
306
+ 'output': output
307
+ }
308
+ st.session_state.code_history.append(history_entry)
309
+
310
+ def create_artifact(title: str, content: any, artifact_type: str = "Mixed Media"):
311
+ """
312
+ Create an artifact from code execution.
313
+ Usage example in code:
314
+
315
+ # Create a text artifact
316
+ create_artifact("My Text", "Hello World", "Text")
317
+
318
+ # Create an image artifact
319
+ img = Image.new('RGB', (100, 100), color='red')
320
+ buffered = io.BytesIO()
321
+ img.save(buffered, format="PNG")
322
+ img_str = base64.b64encode(buffered.getvalue()).decode()
323
+ create_artifact("My Image", img_str, "Image")
324
+ """
325
+ globals()['_artifact_output'] = {
326
+ 'title': title,
327
+ 'type': artifact_type,
328
+ 'content': content
329
+ }