more-compute 0.3.1__tar.gz → 0.3.3__tar.gz
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.
- {more_compute-0.3.1/more_compute.egg-info → more_compute-0.3.3}/PKG-INFO +9 -1
- {more_compute-0.3.1 → more_compute-0.3.3}/README.md +8 -0
- {more_compute-0.3.1 → more_compute-0.3.3}/frontend/app/globals.css +2 -0
- {more_compute-0.3.1 → more_compute-0.3.3}/frontend/components/cell/MonacoCell.tsx +31 -31
- {more_compute-0.3.1 → more_compute-0.3.3}/frontend/components/popups/PackagesPopup.tsx +19 -8
- {more_compute-0.3.1 → more_compute-0.3.3}/kernel_run.py +50 -5
- {more_compute-0.3.1 → more_compute-0.3.3/more_compute.egg-info}/PKG-INFO +9 -1
- more_compute-0.3.3/morecompute/__version__.py +1 -0
- {more_compute-0.3.1 → more_compute-0.3.3}/morecompute/execution/executor.py +1 -0
- {more_compute-0.3.1 → more_compute-0.3.3}/morecompute/execution/worker.py +8 -1
- {more_compute-0.3.1 → more_compute-0.3.3}/morecompute/server.py +4 -4
- {more_compute-0.3.1 → more_compute-0.3.3}/morecompute/services/pod_manager.py +2 -2
- more_compute-0.3.3/morecompute/utils/config_util.py +75 -0
- more_compute-0.3.1/morecompute/__version__.py +0 -1
- more_compute-0.3.1/morecompute/utils/config_util.py +0 -59
- {more_compute-0.3.1 → more_compute-0.3.3}/LICENSE +0 -0
- {more_compute-0.3.1 → more_compute-0.3.3}/MANIFEST.in +0 -0
- {more_compute-0.3.1 → more_compute-0.3.3}/frontend/.DS_Store +0 -0
- {more_compute-0.3.1 → more_compute-0.3.3}/frontend/.gitignore +0 -0
- {more_compute-0.3.1 → more_compute-0.3.3}/frontend/README.md +0 -0
- {more_compute-0.3.1 → more_compute-0.3.3}/frontend/__init__.py +0 -0
- {more_compute-0.3.1 → more_compute-0.3.3}/frontend/app/favicon.ico +0 -0
- {more_compute-0.3.1 → more_compute-0.3.3}/frontend/app/layout.tsx +0 -0
- {more_compute-0.3.1 → more_compute-0.3.3}/frontend/app/page.tsx +0 -0
- {more_compute-0.3.1 → more_compute-0.3.3}/frontend/components/Notebook.tsx +0 -0
- {more_compute-0.3.1 → more_compute-0.3.3}/frontend/components/cell/AddCellButton.tsx +0 -0
- {more_compute-0.3.1 → more_compute-0.3.3}/frontend/components/cell/CellButton.tsx +0 -0
- {more_compute-0.3.1 → more_compute-0.3.3}/frontend/components/layout/ConnectionBanner.tsx +0 -0
- {more_compute-0.3.1 → more_compute-0.3.3}/frontend/components/layout/Sidebar.tsx +0 -0
- {more_compute-0.3.1 → more_compute-0.3.3}/frontend/components/modals/ConfirmModal.tsx +0 -0
- {more_compute-0.3.1 → more_compute-0.3.3}/frontend/components/modals/ErrorModal.tsx +0 -0
- {more_compute-0.3.1 → more_compute-0.3.3}/frontend/components/modals/SuccessModal.tsx +0 -0
- {more_compute-0.3.1 → more_compute-0.3.3}/frontend/components/output/CellOutput.tsx +0 -0
- {more_compute-0.3.1 → more_compute-0.3.3}/frontend/components/output/ErrorDisplay.tsx +0 -0
- {more_compute-0.3.1 → more_compute-0.3.3}/frontend/components/output/MarkdownRenderer.tsx +0 -0
- {more_compute-0.3.1 → more_compute-0.3.3}/frontend/components/popups/ComputePopup.tsx +0 -0
- {more_compute-0.3.1 → more_compute-0.3.3}/frontend/components/popups/FilterPopup.tsx +0 -0
- {more_compute-0.3.1 → more_compute-0.3.3}/frontend/components/popups/FolderPopup.tsx +0 -0
- {more_compute-0.3.1 → more_compute-0.3.3}/frontend/components/popups/MetricsPopup.tsx +0 -0
- {more_compute-0.3.1 → more_compute-0.3.3}/frontend/components/popups/SettingsPopup.tsx +0 -0
- {more_compute-0.3.1 → more_compute-0.3.3}/frontend/contexts/PodWebSocketContext.tsx +0 -0
- {more_compute-0.3.1 → more_compute-0.3.3}/frontend/eslint.config.mjs +0 -0
- {more_compute-0.3.1 → more_compute-0.3.3}/frontend/lib/api.ts +0 -0
- {more_compute-0.3.1 → more_compute-0.3.3}/frontend/lib/monaco-themes.ts +0 -0
- {more_compute-0.3.1 → more_compute-0.3.3}/frontend/lib/settings.ts +0 -0
- {more_compute-0.3.1 → more_compute-0.3.3}/frontend/lib/themes.json +0 -0
- {more_compute-0.3.1 → more_compute-0.3.3}/frontend/lib/websocket-native.ts +0 -0
- {more_compute-0.3.1 → more_compute-0.3.3}/frontend/lib/websocket.ts +0 -0
- {more_compute-0.3.1 → more_compute-0.3.3}/frontend/next-env.d.ts +0 -0
- {more_compute-0.3.1 → more_compute-0.3.3}/frontend/next.config.mjs +0 -0
- {more_compute-0.3.1 → more_compute-0.3.3}/frontend/next.config.ts +0 -0
- {more_compute-0.3.1 → more_compute-0.3.3}/frontend/package-lock.json +0 -0
- {more_compute-0.3.1 → more_compute-0.3.3}/frontend/package.json +0 -0
- {more_compute-0.3.1 → more_compute-0.3.3}/frontend/postcss.config.mjs +0 -0
- {more_compute-0.3.1 → more_compute-0.3.3}/frontend/public/assets/icons/add.svg +0 -0
- {more_compute-0.3.1 → more_compute-0.3.3}/frontend/public/assets/icons/check.svg +0 -0
- {more_compute-0.3.1 → more_compute-0.3.3}/frontend/public/assets/icons/copy.svg +0 -0
- {more_compute-0.3.1 → more_compute-0.3.3}/frontend/public/assets/icons/folder.svg +0 -0
- {more_compute-0.3.1 → more_compute-0.3.3}/frontend/public/assets/icons/metric.svg +0 -0
- {more_compute-0.3.1 → more_compute-0.3.3}/frontend/public/assets/icons/packages.svg +0 -0
- {more_compute-0.3.1 → more_compute-0.3.3}/frontend/public/assets/icons/play.svg +0 -0
- {more_compute-0.3.1 → more_compute-0.3.3}/frontend/public/assets/icons/python.svg +0 -0
- {more_compute-0.3.1 → more_compute-0.3.3}/frontend/public/assets/icons/setting.svg +0 -0
- {more_compute-0.3.1 → more_compute-0.3.3}/frontend/public/assets/icons/stop.svg +0 -0
- {more_compute-0.3.1 → more_compute-0.3.3}/frontend/public/assets/icons/trash.svg +0 -0
- {more_compute-0.3.1 → more_compute-0.3.3}/frontend/public/assets/icons/up-down.svg +0 -0
- {more_compute-0.3.1 → more_compute-0.3.3}/frontend/public/assets/icons/x.svg +0 -0
- {more_compute-0.3.1 → more_compute-0.3.3}/frontend/public/file.svg +0 -0
- {more_compute-0.3.1 → more_compute-0.3.3}/frontend/public/fonts/Fira.ttf +0 -0
- {more_compute-0.3.1 → more_compute-0.3.3}/frontend/public/fonts/Tiempos.woff2 +0 -0
- {more_compute-0.3.1 → more_compute-0.3.3}/frontend/public/fonts/VeraMono.ttf +0 -0
- {more_compute-0.3.1 → more_compute-0.3.3}/frontend/public/globe.svg +0 -0
- {more_compute-0.3.1 → more_compute-0.3.3}/frontend/public/next.svg +0 -0
- {more_compute-0.3.1 → more_compute-0.3.3}/frontend/public/vercel.svg +0 -0
- {more_compute-0.3.1 → more_compute-0.3.3}/frontend/public/window.svg +0 -0
- {more_compute-0.3.1 → more_compute-0.3.3}/frontend/styling_README.md +0 -0
- {more_compute-0.3.1 → more_compute-0.3.3}/frontend/tailwind.config.ts +0 -0
- {more_compute-0.3.1 → more_compute-0.3.3}/frontend/tsconfig.json +0 -0
- {more_compute-0.3.1 → more_compute-0.3.3}/frontend/types/notebook.ts +0 -0
- {more_compute-0.3.1 → more_compute-0.3.3}/more_compute.egg-info/SOURCES.txt +0 -0
- {more_compute-0.3.1 → more_compute-0.3.3}/more_compute.egg-info/dependency_links.txt +0 -0
- {more_compute-0.3.1 → more_compute-0.3.3}/more_compute.egg-info/entry_points.txt +0 -0
- {more_compute-0.3.1 → more_compute-0.3.3}/more_compute.egg-info/requires.txt +0 -0
- {more_compute-0.3.1 → more_compute-0.3.3}/more_compute.egg-info/top_level.txt +0 -0
- {more_compute-0.3.1 → more_compute-0.3.3}/morecompute/__init__.py +0 -0
- {more_compute-0.3.1 → more_compute-0.3.3}/morecompute/cli.py +0 -0
- {more_compute-0.3.1 → more_compute-0.3.3}/morecompute/execution/__init__.py +0 -0
- {more_compute-0.3.1 → more_compute-0.3.3}/morecompute/execution/__main__.py +0 -0
- {more_compute-0.3.1 → more_compute-0.3.3}/morecompute/models/__init__.py +0 -0
- {more_compute-0.3.1 → more_compute-0.3.3}/morecompute/models/api_models.py +0 -0
- {more_compute-0.3.1 → more_compute-0.3.3}/morecompute/notebook.py +0 -0
- {more_compute-0.3.1 → more_compute-0.3.3}/morecompute/process_worker.py +0 -0
- {more_compute-0.3.1 → more_compute-0.3.3}/morecompute/services/data_manager.py +0 -0
- {more_compute-0.3.1 → more_compute-0.3.3}/morecompute/services/lsp_service.py +0 -0
- {more_compute-0.3.1 → more_compute-0.3.3}/morecompute/services/pod_monitor.py +0 -0
- {more_compute-0.3.1 → more_compute-0.3.3}/morecompute/services/prime_intellect.py +0 -0
- {more_compute-0.3.1 → more_compute-0.3.3}/morecompute/static/styles.css +0 -0
- {more_compute-0.3.1 → more_compute-0.3.3}/morecompute/utils/__init__.py +0 -0
- {more_compute-0.3.1 → more_compute-0.3.3}/morecompute/utils/cache_util.py +0 -0
- {more_compute-0.3.1 → more_compute-0.3.3}/morecompute/utils/cell_magics.py +0 -0
- {more_compute-0.3.1 → more_compute-0.3.3}/morecompute/utils/error_utils.py +0 -0
- {more_compute-0.3.1 → more_compute-0.3.3}/morecompute/utils/line_magics.py +0 -0
- {more_compute-0.3.1 → more_compute-0.3.3}/morecompute/utils/notebook_util.py +0 -0
- {more_compute-0.3.1 → more_compute-0.3.3}/morecompute/utils/python_environment_util.py +0 -0
- {more_compute-0.3.1 → more_compute-0.3.3}/morecompute/utils/shell_utils.py +0 -0
- {more_compute-0.3.1 → more_compute-0.3.3}/morecompute/utils/special_commands.py +0 -0
- {more_compute-0.3.1 → more_compute-0.3.3}/morecompute/utils/system_environment_util.py +0 -0
- {more_compute-0.3.1 → more_compute-0.3.3}/morecompute/utils/zmq_util.py +0 -0
- {more_compute-0.3.1 → more_compute-0.3.3}/pyproject.toml +0 -0
- {more_compute-0.3.1 → more_compute-0.3.3}/setup.cfg +0 -0
- {more_compute-0.3.1 → more_compute-0.3.3}/setup.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: more-compute
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.3
|
|
4
4
|
Summary: An interactive notebook environment for local and GPU computing
|
|
5
5
|
Home-page: https://github.com/DannyMang/MORECOMPUTE
|
|
6
6
|
Author: MoreCompute Team
|
|
@@ -46,6 +46,14 @@ Dynamic: requires-python
|
|
|
46
46
|
|
|
47
47
|
An interactive notebook environment, similar to Marimo and Google Colab, that runs locally. It works with standard `.ipynb` files, similar to Jupyter Lab but more awesome.
|
|
48
48
|
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
https://github.com/user-attachments/assets/8c7ec716-dade-4de2-ad37-71d328129c97
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
|
|
49
57
|
## Installation
|
|
50
58
|
|
|
51
59
|
**Prerequisites:** [Node.js](https://nodejs.org/) >= 20.10.0 required for web interface
|
|
@@ -6,6 +6,14 @@
|
|
|
6
6
|
|
|
7
7
|
An interactive notebook environment, similar to Marimo and Google Colab, that runs locally. It works with standard `.ipynb` files, similar to Jupyter Lab but more awesome.
|
|
8
8
|
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
https://github.com/user-attachments/assets/8c7ec716-dade-4de2-ad37-71d328129c97
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
9
17
|
## Installation
|
|
10
18
|
|
|
11
19
|
**Prerequisites:** [Node.js](https://nodejs.org/) >= 20.10.0 required for web interface
|
|
@@ -111,6 +111,7 @@ body {
|
|
|
111
111
|
display: flex;
|
|
112
112
|
align-items: center;
|
|
113
113
|
gap: 6px;
|
|
114
|
+
pointer-events: none; /* Allow clicks to pass through */
|
|
114
115
|
}
|
|
115
116
|
|
|
116
117
|
.connection-banner.provisioning {
|
|
@@ -480,6 +481,7 @@ body {
|
|
|
480
481
|
|
|
481
482
|
.cell:hover {
|
|
482
483
|
box-shadow: 2px 4px 0 var(--mc-secondary-hover);
|
|
484
|
+
z-index: 11; /* Ensure hovered cell appears above add-cell-line (z-index: 10) */
|
|
483
485
|
}
|
|
484
486
|
|
|
485
487
|
.cell.active {
|
|
@@ -580,9 +580,9 @@ export const MonacoCell: React.FC<CellProps> = ({
|
|
|
580
580
|
data-cell-index={index}
|
|
581
581
|
>
|
|
582
582
|
{/* Hover Controls */}
|
|
583
|
-
|
|
584
|
-
<div className="cell-
|
|
585
|
-
|
|
583
|
+
<div className="cell-hover-controls">
|
|
584
|
+
<div className="cell-actions-right">
|
|
585
|
+
{!isMarkdownWithContent && (
|
|
586
586
|
<CellButton
|
|
587
587
|
icon={<PlayIcon className="w-6 h-6" />}
|
|
588
588
|
onClick={(e) => {
|
|
@@ -592,35 +592,35 @@ export const MonacoCell: React.FC<CellProps> = ({
|
|
|
592
592
|
title={isExecuting ? "Stop execution" : "Run cell"}
|
|
593
593
|
isLoading={isExecuting}
|
|
594
594
|
/>
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
595
|
+
)}
|
|
596
|
+
<CellButton
|
|
597
|
+
icon={<ChevronUpIcon className="w-6 h-6" />}
|
|
598
|
+
onClick={(e) => {
|
|
599
|
+
e.stopPropagation();
|
|
600
|
+
onMoveUp(indexRef.current);
|
|
601
|
+
}}
|
|
602
|
+
title="Move cell up"
|
|
603
|
+
disabled={index === 0}
|
|
604
|
+
/>
|
|
605
|
+
<CellButton
|
|
606
|
+
icon={<ChevronDownIcon className="w-6 h-6" />}
|
|
607
|
+
onClick={(e) => {
|
|
608
|
+
e.stopPropagation();
|
|
609
|
+
onMoveDown(indexRef.current);
|
|
610
|
+
}}
|
|
611
|
+
title="Move cell down"
|
|
612
|
+
disabled={index === totalCells - 1}
|
|
613
|
+
/>
|
|
614
|
+
<CellButton
|
|
615
|
+
icon={<LinkBreak2Icon className="w-5 h-5" />}
|
|
616
|
+
onClick={(e) => {
|
|
617
|
+
e.stopPropagation();
|
|
618
|
+
onDelete(indexRef.current);
|
|
619
|
+
}}
|
|
620
|
+
title="Delete cell"
|
|
621
|
+
/>
|
|
622
622
|
</div>
|
|
623
|
-
|
|
623
|
+
</div>
|
|
624
624
|
|
|
625
625
|
{/* Cell Content */}
|
|
626
626
|
<div
|
|
@@ -70,9 +70,6 @@ const PackagesPopup: React.FC<PackagesPopupProps> = ({ onClose }) => {
|
|
|
70
70
|
return packages.filter(p => p.name.toLowerCase().includes(q));
|
|
71
71
|
}, [packages, query]);
|
|
72
72
|
|
|
73
|
-
if (loading) return <div className="packages-list">Loading...</div>;
|
|
74
|
-
if (error) return <div className="packages-list">{error}</div>;
|
|
75
|
-
|
|
76
73
|
return (
|
|
77
74
|
<div className="packages-container">
|
|
78
75
|
<div className="packages-toolbar">
|
|
@@ -98,12 +95,26 @@ const PackagesPopup: React.FC<PackagesPopupProps> = ({ onClose }) => {
|
|
|
98
95
|
<div className="col-version">Version</div>
|
|
99
96
|
</div>
|
|
100
97
|
<div className="packages-list">
|
|
101
|
-
{
|
|
102
|
-
<div
|
|
103
|
-
|
|
104
|
-
|
|
98
|
+
{loading ? (
|
|
99
|
+
<div style={{ padding: '20px', textAlign: 'center', color: 'var(--mc-text-color)' }}>
|
|
100
|
+
Loading packages...
|
|
101
|
+
</div>
|
|
102
|
+
) : error ? (
|
|
103
|
+
<div style={{ padding: '20px', textAlign: 'center', color: '#dc2626' }}>
|
|
104
|
+
{error}
|
|
105
|
+
</div>
|
|
106
|
+
) : filtered.length === 0 ? (
|
|
107
|
+
<div style={{ padding: '20px', textAlign: 'center', color: 'var(--mc-text-color)', opacity: 0.6 }}>
|
|
108
|
+
{query ? 'No packages found' : 'No packages installed'}
|
|
105
109
|
</div>
|
|
106
|
-
)
|
|
110
|
+
) : (
|
|
111
|
+
filtered.map((pkg) => (
|
|
112
|
+
<div key={`${pkg.name}@${pkg.version}`} className="package-row">
|
|
113
|
+
<div className="col-name package-name">{pkg.name}</div>
|
|
114
|
+
<div className="col-version package-version">{pkg.version}</div>
|
|
115
|
+
</div>
|
|
116
|
+
))
|
|
117
|
+
)}
|
|
107
118
|
</div>
|
|
108
119
|
</div>
|
|
109
120
|
</div>
|
|
@@ -25,6 +25,7 @@ class NotebookLauncher:
|
|
|
25
25
|
self.notebook_path = notebook_path
|
|
26
26
|
self.is_windows = platform.system() == "Windows"
|
|
27
27
|
self.cleaning_up = False # Flag to prevent multiple cleanup calls
|
|
28
|
+
self.frontend_port = int(os.getenv("MORECOMPUTE_FRONTEND_PORT", "2718"))
|
|
28
29
|
root_dir = notebook_path.parent if notebook_path.parent != Path('') else Path.cwd()
|
|
29
30
|
os.environ["MORECOMPUTE_ROOT"] = str(root_dir.resolve())
|
|
30
31
|
os.environ["MORECOMPUTE_NOTEBOOK_PATH"] = str(self.notebook_path)
|
|
@@ -244,9 +245,14 @@ class NotebookLauncher:
|
|
|
244
245
|
fe_stdout = None if self.debug else subprocess.DEVNULL
|
|
245
246
|
fe_stderr = None if self.debug else subprocess.DEVNULL
|
|
246
247
|
|
|
248
|
+
# Set PORT environment variable for Next.js
|
|
249
|
+
frontend_env = os.environ.copy()
|
|
250
|
+
frontend_env["PORT"] = str(self.frontend_port)
|
|
251
|
+
|
|
247
252
|
self.frontend_process = subprocess.Popen(
|
|
248
253
|
[npm_cmd, "run", "dev"],
|
|
249
254
|
cwd=frontend_dir,
|
|
255
|
+
env=frontend_env,
|
|
250
256
|
stdout=fe_stdout,
|
|
251
257
|
stderr=fe_stderr,
|
|
252
258
|
shell=self.is_windows, # CRITICAL for Windows
|
|
@@ -256,7 +262,7 @@ class NotebookLauncher:
|
|
|
256
262
|
|
|
257
263
|
# Wait a bit then open browser
|
|
258
264
|
time.sleep(3)
|
|
259
|
-
webbrowser.open("http://localhost:
|
|
265
|
+
webbrowser.open(f"http://localhost:{self.frontend_port}")
|
|
260
266
|
|
|
261
267
|
except Exception as e:
|
|
262
268
|
print(f"Failed to start frontend: {e}")
|
|
@@ -316,7 +322,7 @@ class NotebookLauncher:
|
|
|
316
322
|
def run(self):
|
|
317
323
|
"""Main run method"""
|
|
318
324
|
print("\n Edit notebook in your browser!\n")
|
|
319
|
-
print(" ➜ URL: http://localhost:
|
|
325
|
+
print(f" ➜ URL: http://localhost:{self.frontend_port}\n")
|
|
320
326
|
|
|
321
327
|
# Track Ctrl+C presses
|
|
322
328
|
interrupt_count = [0] # Use list to allow modification in nested function
|
|
@@ -366,7 +372,11 @@ class NotebookLauncher:
|
|
|
366
372
|
|
|
367
373
|
|
|
368
374
|
def build_parser() -> argparse.ArgumentParser:
|
|
369
|
-
parser = argparse.ArgumentParser(
|
|
375
|
+
parser = argparse.ArgumentParser(
|
|
376
|
+
prog="more-compute",
|
|
377
|
+
description="MoreCompute - Jupyter notebooks with GPU compute",
|
|
378
|
+
add_help=False,
|
|
379
|
+
)
|
|
370
380
|
parser.add_argument(
|
|
371
381
|
"--version",
|
|
372
382
|
"-v",
|
|
@@ -383,7 +393,13 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
383
393
|
"-debug",
|
|
384
394
|
"--debug",
|
|
385
395
|
action="store_true",
|
|
386
|
-
help="Show backend/frontend logs
|
|
396
|
+
help="Show backend/frontend logs",
|
|
397
|
+
)
|
|
398
|
+
parser.add_argument(
|
|
399
|
+
"-h",
|
|
400
|
+
"--help",
|
|
401
|
+
action="store_true",
|
|
402
|
+
help="Show this help message",
|
|
387
403
|
)
|
|
388
404
|
return parser
|
|
389
405
|
|
|
@@ -413,9 +429,37 @@ def ensure_notebook_exists(notebook_path: Path):
|
|
|
413
429
|
notebook.save_to_file(str(notebook_path))
|
|
414
430
|
|
|
415
431
|
|
|
432
|
+
def print_help():
|
|
433
|
+
"""Print concise help message"""
|
|
434
|
+
print(f"""Usage: more-compute [OPTIONS] [NOTEBOOK]
|
|
435
|
+
|
|
436
|
+
MoreCompute - Jupyter notebooks with GPU compute
|
|
437
|
+
|
|
438
|
+
Getting started:
|
|
439
|
+
|
|
440
|
+
* more-compute new create a new notebook with timestamp
|
|
441
|
+
* more-compute notebook.ipynb open or create notebook.ipynb
|
|
442
|
+
|
|
443
|
+
Options:
|
|
444
|
+
--version, -v Show version and exit
|
|
445
|
+
--debug Show backend/frontend logs
|
|
446
|
+
--help, -h Show this message and exit
|
|
447
|
+
|
|
448
|
+
Environment variables:
|
|
449
|
+
MORECOMPUTE_PORT Backend port (default: 8000)
|
|
450
|
+
MORECOMPUTE_FRONTEND_PORT Frontend port (default: 2718)
|
|
451
|
+
MORECOMPUTE_NOTEBOOK_PATH Default notebook path
|
|
452
|
+
""")
|
|
453
|
+
|
|
416
454
|
def main(argv=None):
|
|
417
455
|
parser = build_parser()
|
|
418
456
|
args = parser.parse_args(argv)
|
|
457
|
+
|
|
458
|
+
# Show help if requested or no arguments provided
|
|
459
|
+
if args.help or (args.notebook_path is None and os.getenv("MORECOMPUTE_NOTEBOOK_PATH") is None):
|
|
460
|
+
print_help()
|
|
461
|
+
sys.exit(0)
|
|
462
|
+
|
|
419
463
|
raw_notebook_path = args.notebook_path
|
|
420
464
|
|
|
421
465
|
if raw_notebook_path == "new":
|
|
@@ -429,7 +473,8 @@ def main(argv=None):
|
|
|
429
473
|
raw_notebook_path = notebook_path_env
|
|
430
474
|
|
|
431
475
|
if raw_notebook_path is None:
|
|
432
|
-
|
|
476
|
+
print_help()
|
|
477
|
+
sys.exit(0)
|
|
433
478
|
|
|
434
479
|
notebook_path = Path(raw_notebook_path).expanduser().resolve()
|
|
435
480
|
ensure_notebook_exists(notebook_path)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: more-compute
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.3
|
|
4
4
|
Summary: An interactive notebook environment for local and GPU computing
|
|
5
5
|
Home-page: https://github.com/DannyMang/MORECOMPUTE
|
|
6
6
|
Author: MoreCompute Team
|
|
@@ -46,6 +46,14 @@ Dynamic: requires-python
|
|
|
46
46
|
|
|
47
47
|
An interactive notebook environment, similar to Marimo and Google Colab, that runs locally. It works with standard `.ipynb` files, similar to Jupyter Lab but more awesome.
|
|
48
48
|
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
https://github.com/user-attachments/assets/8c7ec716-dade-4de2-ad37-71d328129c97
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
|
|
49
57
|
## Installation
|
|
50
58
|
|
|
51
59
|
**Prerequisites:** [Node.js](https://nodejs.org/) >= 20.10.0 required for web interface
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.3.3"
|
|
@@ -86,6 +86,7 @@ class NextZmqExecutor:
|
|
|
86
86
|
self.worker_proc = subprocess.Popen(
|
|
87
87
|
[sys.executable, '-m', 'morecompute.execution.worker'],
|
|
88
88
|
env=env,
|
|
89
|
+
stdin=subprocess.DEVNULL, # Explicitly close stdin to prevent fd issues
|
|
89
90
|
stdout=subprocess.DEVNULL,
|
|
90
91
|
stderr=None # Show errors in terminal
|
|
91
92
|
)
|
|
@@ -332,7 +332,14 @@ def worker_main():
|
|
|
332
332
|
if lines:
|
|
333
333
|
last = lines[-1].strip()
|
|
334
334
|
# Skip comments and empty lines
|
|
335
|
-
if last
|
|
335
|
+
if not last or last.startswith('#'):
|
|
336
|
+
last = None
|
|
337
|
+
# Skip orphaned closing brackets from multi-line expressions
|
|
338
|
+
# e.g., the ')' from: model = func(\n arg1,\n arg2\n)
|
|
339
|
+
elif last.lstrip().startswith(')') or last.lstrip().startswith('}') or last.lstrip().startswith(']'):
|
|
340
|
+
last = None
|
|
341
|
+
|
|
342
|
+
if last:
|
|
336
343
|
# Check if it looks like a statement (assignment, import, etc)
|
|
337
344
|
is_statement = False
|
|
338
345
|
|
|
@@ -18,7 +18,7 @@ from .utils.system_environment_util import DeviceMetrics
|
|
|
18
18
|
from .utils.error_utils import ErrorUtils
|
|
19
19
|
from .utils.cache_util import make_cache_key
|
|
20
20
|
from .utils.notebook_util import coerce_cell_source
|
|
21
|
-
from .utils.config_util import
|
|
21
|
+
from .utils.config_util import load_api_key, save_api_key
|
|
22
22
|
from .utils.zmq_util import reconnect_zmq_sockets, reset_to_local_zmq
|
|
23
23
|
from .services.prime_intellect import PrimeIntellectService
|
|
24
24
|
from .services.pod_manager import PodKernelManager
|
|
@@ -67,7 +67,7 @@ else:
|
|
|
67
67
|
error_utils = ErrorUtils()
|
|
68
68
|
executor = NextZmqExecutor(error_utils=error_utils)
|
|
69
69
|
metrics = DeviceMetrics()
|
|
70
|
-
prime_api_key =
|
|
70
|
+
prime_api_key = load_api_key("PRIME_INTELLECT_API_KEY")
|
|
71
71
|
prime_intellect = PrimeIntellectService(api_key=prime_api_key) if prime_api_key else None
|
|
72
72
|
pod_manager: PodKernelManager | None = None
|
|
73
73
|
data_manager = DataManager(prime_intellect=prime_intellect)
|
|
@@ -654,14 +654,14 @@ async def get_gpu_config() -> ConfigStatusResponse:
|
|
|
654
654
|
|
|
655
655
|
@app.post("/api/gpu/config", response_model=ApiKeyResponse)
|
|
656
656
|
async def set_gpu_config(request: ApiKeyRequest) -> ApiKeyResponse:
|
|
657
|
-
"""Save Prime Intellect API key to .
|
|
657
|
+
"""Save Prime Intellect API key to user config (~/.morecompute/config.json) and reinitialize service."""
|
|
658
658
|
global prime_intellect, pod_monitor
|
|
659
659
|
|
|
660
660
|
if not request.api_key.strip():
|
|
661
661
|
raise HTTPException(status_code=400, detail="API key is required")
|
|
662
662
|
|
|
663
663
|
try:
|
|
664
|
-
|
|
664
|
+
save_api_key("PRIME_INTELLECT_API_KEY", request.api_key)
|
|
665
665
|
prime_intellect = PrimeIntellectService(api_key=request.api_key)
|
|
666
666
|
if prime_intellect:
|
|
667
667
|
pod_monitor = PodMonitor(
|
|
@@ -408,8 +408,8 @@ class PodKernelManager:
|
|
|
408
408
|
f"'cd /tmp && "
|
|
409
409
|
f"MC_ZMQ_CMD_ADDR=tcp://0.0.0.0:{self.remote_cmd_port} "
|
|
410
410
|
f"MC_ZMQ_PUB_ADDR=tcp://0.0.0.0:{self.remote_pub_port} "
|
|
411
|
-
f"
|
|
412
|
-
f">/tmp/worker.log 2>&1
|
|
411
|
+
f"setsid python3 -u /tmp/morecompute/execution/worker.py "
|
|
412
|
+
f"</dev/null >/tmp/worker.log 2>&1 & "
|
|
413
413
|
f"echo $!'"
|
|
414
414
|
)
|
|
415
415
|
])
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"""Configuration utilities for managing API keys and environment variables."""
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from typing import Optional
|
|
5
|
+
import os
|
|
6
|
+
import json
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
# Global config directory in user's home
|
|
10
|
+
CONFIG_DIR = Path.home() / ".morecompute"
|
|
11
|
+
CONFIG_FILE = CONFIG_DIR / "config.json"
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def _ensure_config_dir() -> None:
|
|
15
|
+
"""Ensure the config directory exists."""
|
|
16
|
+
CONFIG_DIR.mkdir(parents=True, exist_ok=True)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def _load_config() -> dict:
|
|
20
|
+
"""Load config from JSON file."""
|
|
21
|
+
if not CONFIG_FILE.exists():
|
|
22
|
+
return {}
|
|
23
|
+
try:
|
|
24
|
+
with CONFIG_FILE.open("r", encoding="utf-8") as f:
|
|
25
|
+
return json.load(f)
|
|
26
|
+
except (json.JSONDecodeError, IOError):
|
|
27
|
+
return {}
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def _save_config(config: dict) -> None:
|
|
31
|
+
"""Save config to JSON file."""
|
|
32
|
+
_ensure_config_dir()
|
|
33
|
+
with CONFIG_FILE.open("w", encoding="utf-8") as f:
|
|
34
|
+
json.dump(config, f, indent=2)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def load_api_key(key_name: str) -> Optional[str]:
|
|
38
|
+
"""
|
|
39
|
+
Load API key from user config directory (~/.morecompute/config.json).
|
|
40
|
+
Falls back to environment variable if not found in config.
|
|
41
|
+
|
|
42
|
+
Args:
|
|
43
|
+
key_name: Key name (e.g., "PRIME_INTELLECT_API_KEY")
|
|
44
|
+
|
|
45
|
+
Returns:
|
|
46
|
+
API key string or None if not found
|
|
47
|
+
"""
|
|
48
|
+
# Check environment variable first
|
|
49
|
+
env_key = os.getenv(key_name)
|
|
50
|
+
if env_key:
|
|
51
|
+
return env_key
|
|
52
|
+
|
|
53
|
+
# Check config file
|
|
54
|
+
config = _load_config()
|
|
55
|
+
return config.get(key_name)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def save_api_key(key_name: str, api_key: str) -> None:
|
|
59
|
+
"""
|
|
60
|
+
Save API key to user config directory (~/.morecompute/config.json).
|
|
61
|
+
|
|
62
|
+
Args:
|
|
63
|
+
key_name: Key name (e.g., "PRIME_INTELLECT_API_KEY")
|
|
64
|
+
api_key: API key value to save
|
|
65
|
+
|
|
66
|
+
Raises:
|
|
67
|
+
ValueError: If API key is empty
|
|
68
|
+
IOError: If file cannot be written
|
|
69
|
+
"""
|
|
70
|
+
if not api_key.strip():
|
|
71
|
+
raise ValueError("API key cannot be empty")
|
|
72
|
+
|
|
73
|
+
config = _load_config()
|
|
74
|
+
config[key_name] = api_key
|
|
75
|
+
_save_config(config)
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "0.3.1"
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
"""Configuration utilities for managing API keys and environment variables."""
|
|
2
|
-
|
|
3
|
-
from pathlib import Path
|
|
4
|
-
import os
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
def load_api_key_from_env(env_var: str, env_file_path: Path | None = None) -> str | None:
|
|
8
|
-
"""
|
|
9
|
-
Load API key from environment variable or .env file.
|
|
10
|
-
|
|
11
|
-
Args:
|
|
12
|
-
env_var: Environment variable name to check
|
|
13
|
-
env_file_path: Path to .env file (optional)
|
|
14
|
-
|
|
15
|
-
Returns:
|
|
16
|
-
API key string or None if not found
|
|
17
|
-
"""
|
|
18
|
-
api_key = os.getenv(env_var)
|
|
19
|
-
if api_key:
|
|
20
|
-
return api_key
|
|
21
|
-
|
|
22
|
-
if env_file_path and env_file_path.exists():
|
|
23
|
-
try:
|
|
24
|
-
with env_file_path.open("r", encoding="utf-8") as f:
|
|
25
|
-
for line in f:
|
|
26
|
-
line = line.strip()
|
|
27
|
-
if line.startswith(f"{env_var}="):
|
|
28
|
-
return line.split("=", 1)[1].strip().strip('"').strip("'")
|
|
29
|
-
except Exception:
|
|
30
|
-
pass
|
|
31
|
-
|
|
32
|
-
return None
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
def save_api_key_to_env(env_var: str, api_key: str, env_file_path: Path) -> None:
|
|
36
|
-
"""
|
|
37
|
-
Save API key to .env file, replacing existing value if present.
|
|
38
|
-
|
|
39
|
-
Args:
|
|
40
|
-
env_var: Environment variable name
|
|
41
|
-
api_key: API key value to save
|
|
42
|
-
env_file_path: Path to .env file
|
|
43
|
-
|
|
44
|
-
Raises:
|
|
45
|
-
ValueError: If API key is empty
|
|
46
|
-
IOError: If file cannot be written
|
|
47
|
-
"""
|
|
48
|
-
if not api_key.strip():
|
|
49
|
-
raise ValueError("API key cannot be empty")
|
|
50
|
-
|
|
51
|
-
existing_lines = []
|
|
52
|
-
if env_file_path.exists():
|
|
53
|
-
with env_file_path.open("r", encoding="utf-8") as f:
|
|
54
|
-
existing_lines = f.readlines()
|
|
55
|
-
|
|
56
|
-
new_lines = [line for line in existing_lines if not line.strip().startswith(f"{env_var}=")]
|
|
57
|
-
new_lines.append(f"{env_var}={api_key}\n")
|
|
58
|
-
with env_file_path.open("w", encoding="utf-8") as f:
|
|
59
|
-
f.writelines(new_lines)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|