more-compute 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.
- kernel_run.py +283 -0
- more_compute-0.1.0.dist-info/METADATA +163 -0
- more_compute-0.1.0.dist-info/RECORD +26 -0
- more_compute-0.1.0.dist-info/WHEEL +5 -0
- more_compute-0.1.0.dist-info/entry_points.txt +2 -0
- more_compute-0.1.0.dist-info/licenses/LICENSE +21 -0
- more_compute-0.1.0.dist-info/top_level.txt +2 -0
- morecompute/__init__.py +6 -0
- morecompute/cli.py +31 -0
- morecompute/execution/__init__.py +5 -0
- morecompute/execution/__main__.py +10 -0
- morecompute/execution/executor.py +381 -0
- morecompute/execution/worker.py +244 -0
- morecompute/notebook.py +81 -0
- morecompute/process_worker.py +209 -0
- morecompute/server.py +641 -0
- morecompute/services/pod_manager.py +503 -0
- morecompute/services/prime_intellect.py +316 -0
- morecompute/static/styles.css +1056 -0
- morecompute/utils/__init__.py +17 -0
- morecompute/utils/cache_util.py +23 -0
- morecompute/utils/error_utils.py +322 -0
- morecompute/utils/notebook_util.py +44 -0
- morecompute/utils/python_environment_util.py +197 -0
- morecompute/utils/special_commands.py +458 -0
- morecompute/utils/system_environment_util.py +134 -0
morecompute/notebook.py
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import json
|
|
2
|
+
from typing import List, Dict, Any
|
|
3
|
+
from uuid import uuid4
|
|
4
|
+
|
|
5
|
+
class Notebook:
|
|
6
|
+
"""Manages the state of a notebook's cells."""
|
|
7
|
+
|
|
8
|
+
def __init__(self, file_path: str = None):
|
|
9
|
+
self.cells: List[Dict[str, Any]] = []
|
|
10
|
+
self.metadata: Dict[str, Any] = {}
|
|
11
|
+
self.file_path = file_path
|
|
12
|
+
if file_path:
|
|
13
|
+
self.load_from_file(file_path)
|
|
14
|
+
else:
|
|
15
|
+
# Default empty notebook structure
|
|
16
|
+
self.cells.append({'id': self._generate_cell_id(), 'cell_type': 'code', 'source': '', 'outputs': []})
|
|
17
|
+
|
|
18
|
+
def get_notebook_data(self) -> Dict[str, Any]:
|
|
19
|
+
return {"cells": self.cells, "metadata": self.metadata, "file_path": self.file_path}
|
|
20
|
+
|
|
21
|
+
def add_cell(self, index: int, cell_type: str = 'code', source: str = ''):
|
|
22
|
+
new_cell = {'id': self._generate_cell_id(), 'cell_type': cell_type, 'source': source, 'outputs': []}
|
|
23
|
+
self.cells.insert(index, new_cell)
|
|
24
|
+
|
|
25
|
+
def delete_cell(self, index: int):
|
|
26
|
+
if 0 <= index < len(self.cells):
|
|
27
|
+
self.cells.pop(index)
|
|
28
|
+
|
|
29
|
+
def update_cell(self, index: int, source: str):
|
|
30
|
+
if 0 <= index < len(self.cells):
|
|
31
|
+
self.cells[index]['source'] = source
|
|
32
|
+
|
|
33
|
+
def clear_all_outputs(self):
|
|
34
|
+
for cell in self.cells:
|
|
35
|
+
cell['outputs'] = []
|
|
36
|
+
if 'execution_count' in cell:
|
|
37
|
+
cell['execution_count'] = None
|
|
38
|
+
|
|
39
|
+
def to_json(self) -> str:
|
|
40
|
+
# Basic notebook format
|
|
41
|
+
notebook_json = {
|
|
42
|
+
"cells": self.cells,
|
|
43
|
+
"metadata": self.metadata,
|
|
44
|
+
"nbformat": 4,
|
|
45
|
+
"nbformat_minor": 5
|
|
46
|
+
}
|
|
47
|
+
return json.dumps(notebook_json, indent=2)
|
|
48
|
+
|
|
49
|
+
def load_from_file(self, file_path: str):
|
|
50
|
+
try:
|
|
51
|
+
with open(file_path, 'r') as f:
|
|
52
|
+
data = json.load(f)
|
|
53
|
+
loaded_cells = data.get('cells', [])
|
|
54
|
+
# Ensure stable IDs for all cells (back-compat for notebooks without IDs)
|
|
55
|
+
self.cells = []
|
|
56
|
+
for cell in loaded_cells:
|
|
57
|
+
if not isinstance(cell, dict):
|
|
58
|
+
continue
|
|
59
|
+
if 'id' not in cell or not cell['id']:
|
|
60
|
+
cell['id'] = self._generate_cell_id()
|
|
61
|
+
self.cells.append(cell)
|
|
62
|
+
self.metadata = data.get('metadata', {})
|
|
63
|
+
self.file_path = file_path
|
|
64
|
+
except (FileNotFoundError, json.JSONDecodeError) as e:
|
|
65
|
+
print(f"Error loading notebook: {e}")
|
|
66
|
+
# Initialize with a default cell if loading fails
|
|
67
|
+
self.cells = [{'id': self._generate_cell_id(), 'cell_type': 'code', 'source': '', 'outputs': []}]
|
|
68
|
+
self.metadata = {}
|
|
69
|
+
self.file_path = file_path
|
|
70
|
+
|
|
71
|
+
def save_to_file(self, file_path: str = None):
|
|
72
|
+
path_to_save = file_path or self.file_path
|
|
73
|
+
if not path_to_save:
|
|
74
|
+
raise ValueError("No file path specified for saving.")
|
|
75
|
+
|
|
76
|
+
with open(path_to_save, 'w') as f:
|
|
77
|
+
f.write(self.to_json())
|
|
78
|
+
self.file_path = path_to_save
|
|
79
|
+
|
|
80
|
+
def _generate_cell_id(self) -> str:
|
|
81
|
+
return f"cell-{uuid4()}"
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import sys
|
|
3
|
+
import time
|
|
4
|
+
import signal
|
|
5
|
+
import base64
|
|
6
|
+
import io
|
|
7
|
+
import traceback
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def _setup_worker_signals():
|
|
11
|
+
def _handler(signum, frame):
|
|
12
|
+
# Exit quickly; parent will respawn if needed
|
|
13
|
+
try:
|
|
14
|
+
sys.stdout.flush()
|
|
15
|
+
sys.stderr.flush()
|
|
16
|
+
except Exception:
|
|
17
|
+
pass
|
|
18
|
+
os._exit(0)
|
|
19
|
+
|
|
20
|
+
signal.signal(signal.SIGTERM, _handler)
|
|
21
|
+
try:
|
|
22
|
+
signal.signal(signal.SIGINT, _handler)
|
|
23
|
+
except Exception:
|
|
24
|
+
pass
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class _StreamForwarder:
|
|
28
|
+
def __init__(self, output_queue, stream_name, cell_index):
|
|
29
|
+
self.output_queue = output_queue
|
|
30
|
+
self.stream_name = stream_name
|
|
31
|
+
self.buf = []
|
|
32
|
+
self.cell_index = cell_index
|
|
33
|
+
|
|
34
|
+
def write(self, text):
|
|
35
|
+
if not text:
|
|
36
|
+
return
|
|
37
|
+
# Handle carriage returns for progress bars by emitting stream_update
|
|
38
|
+
if '\r' in text and '\n' not in text:
|
|
39
|
+
# Overwrite current line
|
|
40
|
+
self.output_queue.put({
|
|
41
|
+
'type': 'stream_update',
|
|
42
|
+
'name': self.stream_name,
|
|
43
|
+
'text': text.split('\r')[-1],
|
|
44
|
+
'cell_index': self.cell_index,
|
|
45
|
+
})
|
|
46
|
+
return
|
|
47
|
+
lines = text.split('\n')
|
|
48
|
+
for i, line in enumerate(lines):
|
|
49
|
+
if i < len(lines) - 1:
|
|
50
|
+
self.buf.append(line)
|
|
51
|
+
complete = ''.join(self.buf) + '\n'
|
|
52
|
+
self.output_queue.put({
|
|
53
|
+
'type': 'stream',
|
|
54
|
+
'name': self.stream_name,
|
|
55
|
+
'text': complete,
|
|
56
|
+
'cell_index': self.cell_index,
|
|
57
|
+
})
|
|
58
|
+
self.buf = []
|
|
59
|
+
else:
|
|
60
|
+
self.buf.append(line)
|
|
61
|
+
|
|
62
|
+
def flush(self):
|
|
63
|
+
if self.buf:
|
|
64
|
+
self.output_queue.put({
|
|
65
|
+
'type': 'stream',
|
|
66
|
+
'name': self.stream_name,
|
|
67
|
+
'text': ''.join(self.buf),
|
|
68
|
+
'cell_index': self.cell_index,
|
|
69
|
+
})
|
|
70
|
+
self.buf = []
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def _capture_matplotlib(output_queue, cell_index):
|
|
74
|
+
try:
|
|
75
|
+
import matplotlib
|
|
76
|
+
matplotlib.use('Agg')
|
|
77
|
+
import matplotlib.pyplot as plt
|
|
78
|
+
except Exception:
|
|
79
|
+
return
|
|
80
|
+
try:
|
|
81
|
+
figs = plt.get_fignums()
|
|
82
|
+
if not figs:
|
|
83
|
+
return
|
|
84
|
+
for num in figs:
|
|
85
|
+
try:
|
|
86
|
+
fig = plt.figure(num)
|
|
87
|
+
buf = io.BytesIO()
|
|
88
|
+
fig.savefig(buf, format='png', bbox_inches='tight')
|
|
89
|
+
buf.seek(0)
|
|
90
|
+
b64 = base64.b64encode(buf.read()).decode('ascii')
|
|
91
|
+
output_queue.put({
|
|
92
|
+
'type': 'display_data',
|
|
93
|
+
'data': {
|
|
94
|
+
'image/png': b64,
|
|
95
|
+
'text/plain': f'<Figure size {int(fig.get_figwidth()*fig.dpi)}x{int(fig.get_figheight()*fig.dpi)}>'
|
|
96
|
+
},
|
|
97
|
+
'cell_index': cell_index,
|
|
98
|
+
})
|
|
99
|
+
except Exception:
|
|
100
|
+
continue
|
|
101
|
+
try:
|
|
102
|
+
plt.close('all')
|
|
103
|
+
except Exception:
|
|
104
|
+
pass
|
|
105
|
+
except Exception:
|
|
106
|
+
return
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def worker_main(command_queue, output_queue, shutdown_event):
|
|
110
|
+
# New process group for POSIX
|
|
111
|
+
try:
|
|
112
|
+
if os.name != 'nt':
|
|
113
|
+
os.setsid()
|
|
114
|
+
except Exception:
|
|
115
|
+
pass
|
|
116
|
+
|
|
117
|
+
_setup_worker_signals()
|
|
118
|
+
user_globals = {"__name__": "__main__"}
|
|
119
|
+
user_locals = user_globals
|
|
120
|
+
exec_count = 0
|
|
121
|
+
|
|
122
|
+
while not shutdown_event.is_set():
|
|
123
|
+
try:
|
|
124
|
+
try:
|
|
125
|
+
cmd = command_queue.get(timeout=0.1)
|
|
126
|
+
except Exception:
|
|
127
|
+
continue
|
|
128
|
+
|
|
129
|
+
if not isinstance(cmd, dict):
|
|
130
|
+
continue
|
|
131
|
+
|
|
132
|
+
ctype = cmd.get('type')
|
|
133
|
+
if ctype == 'shutdown':
|
|
134
|
+
break
|
|
135
|
+
if ctype == 'execute_cell':
|
|
136
|
+
code = cmd.get('code', '')
|
|
137
|
+
cell_index = cmd.get('cell_index')
|
|
138
|
+
output_queue.put({'type': 'execution_start', 'cell_index': cell_index, 'execution_count': exec_count + 1})
|
|
139
|
+
|
|
140
|
+
# Redirect stdout/stderr
|
|
141
|
+
old_out, old_err = sys.stdout, sys.stderr
|
|
142
|
+
sys.stdout = _StreamForwarder(output_queue, 'stdout', cell_index)
|
|
143
|
+
sys.stderr = _StreamForwarder(output_queue, 'stderr', cell_index)
|
|
144
|
+
start = time.time()
|
|
145
|
+
status = 'ok'
|
|
146
|
+
error_payload = None
|
|
147
|
+
try:
|
|
148
|
+
compiled = compile(code, '<cell>', 'exec')
|
|
149
|
+
exec(compiled, user_globals, user_locals)
|
|
150
|
+
# Try to evaluate last expression (simple heuristic)
|
|
151
|
+
lines = code.strip().split('\n')
|
|
152
|
+
if lines:
|
|
153
|
+
last = lines[-1].strip()
|
|
154
|
+
if last and not last.startswith('#'):
|
|
155
|
+
try:
|
|
156
|
+
result = eval(last, user_globals, user_locals)
|
|
157
|
+
except Exception:
|
|
158
|
+
result = None
|
|
159
|
+
else:
|
|
160
|
+
if result is not None:
|
|
161
|
+
output_queue.put({
|
|
162
|
+
'type': 'execute_result',
|
|
163
|
+
'cell_index': cell_index,
|
|
164
|
+
'execution_count': exec_count + 1,
|
|
165
|
+
'data': {'text/plain': repr(result)}
|
|
166
|
+
})
|
|
167
|
+
_capture_matplotlib(output_queue, cell_index)
|
|
168
|
+
except KeyboardInterrupt:
|
|
169
|
+
status = 'error'
|
|
170
|
+
error_payload = {
|
|
171
|
+
'ename': 'KeyboardInterrupt',
|
|
172
|
+
'evalue': 'Execution interrupted by user',
|
|
173
|
+
'traceback': []
|
|
174
|
+
}
|
|
175
|
+
except Exception as exc:
|
|
176
|
+
status = 'error'
|
|
177
|
+
tb = traceback.format_exc().split('\n')
|
|
178
|
+
error_payload = {
|
|
179
|
+
'ename': type(exc).__name__,
|
|
180
|
+
'evalue': str(exc),
|
|
181
|
+
'traceback': tb
|
|
182
|
+
}
|
|
183
|
+
finally:
|
|
184
|
+
try:
|
|
185
|
+
sys.stdout.flush(); sys.stderr.flush()
|
|
186
|
+
except Exception:
|
|
187
|
+
pass
|
|
188
|
+
sys.stdout, sys.stderr = old_out, old_err
|
|
189
|
+
|
|
190
|
+
exec_count += 1
|
|
191
|
+
duration_ms = f"{(time.time()-start)*1000:.1f}ms"
|
|
192
|
+
if error_payload:
|
|
193
|
+
output_queue.put({'type': 'execution_error', 'cell_index': cell_index, 'error': error_payload})
|
|
194
|
+
output_queue.put({
|
|
195
|
+
'type': 'execution_complete',
|
|
196
|
+
'cell_index': cell_index,
|
|
197
|
+
'result': {
|
|
198
|
+
'status': status,
|
|
199
|
+
'execution_count': exec_count,
|
|
200
|
+
'execution_time': duration_ms,
|
|
201
|
+
'outputs': [],
|
|
202
|
+
'error': error_payload,
|
|
203
|
+
}
|
|
204
|
+
})
|
|
205
|
+
except Exception:
|
|
206
|
+
# Avoid worker crash on unexpected errors
|
|
207
|
+
continue
|
|
208
|
+
|
|
209
|
+
|