├── .flake8 ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── renovate.json5 └── workflows │ ├── build-and-publish-pypi.yml │ ├── build-frontend.yml │ ├── e2e.yml │ ├── maunal-build.yml │ └── poetry-pytest.yml ├── .gitignore ├── .pre-commit-config.yaml ├── CITATION.cff ├── CODE_OF_CONDUCT.md ├── LICENSE ├── README.md ├── codecov.yml ├── docs ├── .gitignore ├── README.md ├── babel.config.js ├── docs │ ├── apidocs │ │ ├── -protocol.md │ │ ├── client │ │ │ ├── -client-web-apis.md │ │ │ ├── -client.md │ │ │ ├── -shell.md │ │ │ ├── -signal-and-slot.md │ │ │ ├── apis │ │ │ │ ├── -action.md │ │ │ │ ├── -image.md │ │ │ │ ├── -metadata.md │ │ │ │ ├── -progress.md │ │ │ │ ├── -scalar.md │ │ │ │ └── index.md │ │ │ └── index.md │ │ ├── config │ │ │ ├── abc.md │ │ │ ├── index.md │ │ │ ├── project │ │ │ │ └── index.md │ │ │ └── user │ │ │ │ ├── hooks.md │ │ │ │ └── index.md │ │ ├── extension │ │ │ ├── index.md │ │ │ └── machine │ │ │ │ ├── -gputil.md │ │ │ │ ├── hardware.md │ │ │ │ ├── index.md │ │ │ │ └── platform.md │ │ ├── index.md │ │ ├── logging │ │ │ ├── -formatting.md │ │ │ ├── -logger.md │ │ │ ├── index.md │ │ │ └── writers │ │ │ │ ├── -file.md │ │ │ │ ├── -stdout.md │ │ │ │ └── index.md │ │ ├── server │ │ │ ├── -daemon-server-launch-script.md │ │ │ ├── db │ │ │ │ ├── -manager.md │ │ │ │ ├── abc.md │ │ │ │ ├── index.md │ │ │ │ └── project │ │ │ │ │ ├── -project-db.md │ │ │ │ │ ├── condition.md │ │ │ │ │ └── index.md │ │ │ ├── fastapi │ │ │ │ └── index.md │ │ │ ├── index.md │ │ │ └── server-process.md │ │ └── utils │ │ │ ├── -daemonable-process.md │ │ │ ├── -messaging.md │ │ │ ├── -package.md │ │ │ ├── ansi.md │ │ │ ├── connection.md │ │ │ ├── index.md │ │ │ ├── localstorage.md │ │ │ ├── massive.md │ │ │ └── x2numpy.md │ ├── develop │ │ ├── daemon │ │ │ └── index.mdx │ │ └── index.md │ └── howto │ │ ├── configurations │ │ ├── index.mdx │ │ ├── neetbox-cli.mdx │ │ ├── project-config.mdx │ │ └── server-config.mdx │ │ ├── example.mdx │ │ ├── frontend-manual │ │ └── index.mdx │ │ ├── imgs │ │ ├── example │ │ │ └── screenshots │ │ │ │ ├── sc1.jpg │ │ │ │ └── sc2.jpg │ │ └── index │ │ │ ├── readme.svg │ │ │ └── screenshot.jpg │ │ ├── index.mdx │ │ ├── python-apis │ │ ├── create-actions.mdx │ │ ├── imgs │ │ │ ├── add-hyperparams │ │ │ │ ├── image-20231220185559247.png │ │ │ │ └── image-20240101164602610.png │ │ │ ├── create-actions │ │ │ │ ├── image-20231220185856173.png │ │ │ │ ├── image-20231220213148577.png │ │ │ │ └── image-20231220213534685.png │ │ │ ├── post-figure-as-image │ │ │ │ ├── image-20231231224710154.png │ │ │ │ └── image-20240101133300078.png │ │ │ ├── post-images │ │ │ │ ├── image-20231220185948022.png │ │ │ │ └── image-20231220214452030.png │ │ │ ├── post-tensors-as-image │ │ │ │ ├── image-20231220185959324.png │ │ │ │ └── image-20231220221623777.png │ │ │ ├── remote-logging │ │ │ │ ├── image-20231220185614481.png │ │ │ │ ├── image-20231220222626743.png │ │ │ │ └── image-20231220222633839.png │ │ │ ├── show-line-chart │ │ │ │ ├── image-20231220190022639.png │ │ │ │ ├── image-20231220225909377.png │ │ │ │ └── image-20231220230220345.png │ │ │ ├── show-progress │ │ │ │ ├── image-20231220185625943.png │ │ │ │ ├── image-20231220224401847.png │ │ │ │ └── image-20231220224844130.png │ │ │ └── transformer-trainer-callback │ │ │ │ ├── Snipaste_2025-04-25_15-51-53.png │ │ │ │ └── Snipaste_2025-04-25_15-52-27.png │ │ ├── index.mdx │ │ ├── post-figure-as-image.mdx │ │ ├── post-images.mdx │ │ ├── post-tensors-as-image.mdx │ │ ├── remote-logging.mdx │ │ ├── show-hyperparams.mdx │ │ ├── show-line-chart.mdx │ │ ├── show-progress.mdx │ │ └── transformers-trainer-callback.mdx │ │ └── server-hosting │ │ ├── imgs │ │ └── understand-connections │ │ │ ├── use-on-multiple-machines.svg │ │ │ └── use-on-single-machine.svg │ │ ├── index.mdx │ │ ├── manage-history-files.mdx │ │ └── run-neetbox-server.mdx ├── docusaurus.config.js ├── package.json ├── sidebars.js ├── src │ ├── components │ │ ├── ExamplesCards.tsx │ │ ├── FeatureCards.tsx │ │ └── features.module.css │ ├── css │ │ └── custom.css │ ├── hooks │ │ └── useIsMobile.tsx │ └── pages │ │ ├── index.module.css │ │ └── index.tsx ├── static │ ├── .nojekyll │ ├── googleabbb73ffe1f1dea8.html │ ├── img │ │ ├── docusaurus-social-card.png │ │ ├── docusaurus-social-card.svg │ │ ├── favicon.png │ │ ├── github-mark.svg │ │ ├── index │ │ │ ├── add-scalars.jpg │ │ │ ├── background-dark.jpg │ │ │ ├── background-light.jpg │ │ │ ├── distinguish-runs.jpg │ │ │ ├── monit-hardware.jpg │ │ │ ├── monit-machines-on-local-network.png │ │ │ ├── monit-machines-online.png │ │ │ ├── monit-multiple-projects.jpg │ │ │ ├── monit-one-machine.png │ │ │ ├── neetbox-consistof.jpg │ │ │ ├── notify-errors.jpg │ │ │ ├── simple-apis.jpg │ │ │ ├── support-different-data.jpg │ │ │ ├── use-actions.jpg │ │ │ └── view-everywhere.jpg │ │ ├── logo-no-bg.svg │ │ ├── logo.old.svg │ │ ├── logo.svg │ │ └── readme.svg │ └── screenshots │ │ ├── sc1.jpg │ │ └── sc2.jpg ├── tsconfig.json └── yarn.lock ├── frontend ├── .eslintrc.cjs ├── .gitignore ├── .yarn │ └── releases │ │ └── yarn-4.9.2.cjs ├── .yarnrc.yml ├── README.md ├── cypress.config.ts ├── cypress │ ├── e2e │ │ └── testapp.cy.js │ └── support │ │ ├── commands.ts │ │ └── e2e.ts ├── index.html ├── package.json ├── public │ ├── fonts │ │ └── maple │ │ │ ├── LICENSE.txt │ │ │ ├── MapleMono-Bold.woff2 │ │ │ ├── MapleMono-BoldItalic.woff2 │ │ │ ├── MapleMono-ExtraBold.woff2 │ │ │ ├── MapleMono-ExtraBoldItalic.woff2 │ │ │ ├── MapleMono-ExtraLight.woff2 │ │ │ ├── MapleMono-ExtraLightItalic.woff2 │ │ │ ├── MapleMono-Italic.woff2 │ │ │ ├── MapleMono-Light.woff2 │ │ │ ├── MapleMono-LightItalic.woff2 │ │ │ ├── MapleMono-Medium.woff2 │ │ │ ├── MapleMono-MediumItalic.woff2 │ │ │ ├── MapleMono-Regular.woff2 │ │ │ ├── MapleMono-SemiBold.woff2 │ │ │ ├── MapleMono-SemiBoldItalic.woff2 │ │ │ ├── MapleMono-Thin.woff2 │ │ │ ├── MapleMono-ThinItalic.woff2 │ │ │ └── maple.css │ ├── logo-no-bg.svg │ ├── logo.old.svg │ └── logo.svg ├── rsbuild.config.ts ├── src │ ├── App.tsx │ ├── components │ │ ├── appTitle.tsx │ │ ├── common │ │ │ ├── centerBox.tsx │ │ │ ├── echarts.tsx │ │ │ ├── errorBoundary.tsx │ │ │ ├── loading.tsx │ │ │ ├── propCard.tsx │ │ │ └── sectionTitle.tsx │ │ ├── layout │ │ │ ├── AppFooter.tsx │ │ │ ├── AppHeader.tsx │ │ │ └── ConsoleLayout.tsx │ │ ├── logo.module.css │ │ ├── logo.tsx │ │ ├── overview │ │ │ ├── diskUsage.tsx │ │ │ ├── projectList.tsx │ │ │ └── serverProps.tsx │ │ ├── project │ │ │ ├── actions.tsx │ │ │ ├── charts │ │ │ │ └── scatters.tsx │ │ │ ├── hardware │ │ │ │ ├── cpugraph.tsx │ │ │ │ ├── gpugraph.css │ │ │ │ ├── gpugraph.tsx │ │ │ │ ├── graphWrapper.tsx │ │ │ │ ├── index.tsx │ │ │ │ ├── ramgraph.tsx │ │ │ │ └── utils.ts │ │ │ ├── hyperParams.tsx │ │ │ ├── images.tsx │ │ │ ├── imagesAndScatters.tsx │ │ │ ├── jsonView.css │ │ │ ├── jsonView.tsx │ │ │ ├── logs │ │ │ │ ├── logs.css │ │ │ │ └── logs.tsx │ │ │ ├── platformProps.tsx │ │ │ ├── progress.tsx │ │ │ ├── runEdit.tsx │ │ │ ├── runNotes.tsx │ │ │ └── runSelect.tsx │ │ └── themeSwitcher.tsx │ ├── hooks │ │ ├── useMemoJSON.ts │ │ ├── useProject.ts │ │ ├── useProjectData.ts │ │ ├── useReportError.tsx │ │ └── useTheme.tsx │ ├── index.css │ ├── main.tsx │ ├── pages │ │ ├── console │ │ │ ├── index.tsx │ │ │ ├── overview.tsx │ │ │ ├── projectDashboard.tsx │ │ │ ├── sidebar.tsx │ │ │ └── sidebarStyleFix.css │ │ ├── login │ │ │ ├── index.module.css │ │ │ └── index.tsx │ │ └── notFound.tsx │ ├── services │ │ ├── api.ts │ │ ├── logNotifications.tsx │ │ ├── projectWebsocket.ts │ │ ├── projects.ts │ │ ├── serviceProvider.tsx │ │ └── types.ts │ ├── styles │ │ └── global.css │ ├── utils │ │ ├── array.ts │ │ ├── betterAtom.ts │ │ ├── condition.ts │ │ ├── notification.ts │ │ ├── timeDataMapper.ts │ │ └── timer.ts │ └── vite-env.d.ts ├── tsconfig.json ├── tsconfig.node.json └── yarn.lock ├── neetbox.code-workspace ├── neetbox ├── __init__.py ├── _protocol.py ├── cli │ ├── flfs │ │ ├── ansiregular.flf │ │ ├── ansishadow.flf │ │ ├── isometrixc2.flf │ │ ├── nscripts.flf │ │ └── nvscript.flf │ └── parse.py ├── client │ ├── __init__.py │ ├── _client.py │ ├── _client_web_apis.py │ ├── _shell.py │ ├── _signal_and_slot.py │ └── apis │ │ ├── __init__.py │ │ ├── _action.py │ │ ├── _image.py │ │ ├── _metadata.py │ │ ├── _progress.py │ │ └── _scalar.py ├── config │ ├── __init__.py │ ├── abc.py │ ├── project │ │ └── __init__.py │ └── user │ │ ├── __init__.py │ │ └── hooks.py ├── extension │ ├── __init__.py │ ├── machine │ │ ├── __init__.py │ │ ├── _gputil.py │ │ ├── hardware.py │ │ └── platform.py │ ├── torch │ │ ├── arch │ │ │ ├── canny.py │ │ │ ├── cnn.py │ │ │ ├── kernels.py │ │ │ └── mask_boundary_finder.py │ │ ├── nlp.py │ │ ├── nn │ │ │ └── functional.py │ │ └── profile.py │ └── transformers │ │ └── callback.py ├── logging │ ├── __init__.py │ ├── _formatting.py │ ├── _logger.py │ └── writers │ │ ├── __init__.py │ │ ├── _file.py │ │ └── _stdout.py ├── server │ ├── __init__.py │ ├── _daemon_server_launch_script.py │ ├── db │ │ ├── __init__.py │ │ ├── _manager.py │ │ ├── abc.py │ │ └── project │ │ │ ├── __init__.py │ │ │ ├── _project_db.py │ │ │ └── condition.py │ ├── fastapi │ │ ├── __init__.py │ │ └── routers │ │ │ ├── project │ │ │ ├── __init__.py │ │ │ ├── _bridge.py │ │ │ ├── _crud.py │ │ │ └── _ws │ │ │ │ ├── __init__.py │ │ │ │ ├── _event_type_handlers.py │ │ │ │ ├── _manager.py │ │ │ │ └── _websocket_server.py │ │ │ └── server │ │ │ ├── __init__.py │ │ │ ├── _monitor.py │ │ │ ├── _props.py │ │ │ └── _ws.py │ └── server_process.py └── utils │ ├── __init__.py │ ├── _daemonable_process.py │ ├── _messaging.py │ ├── _package.py │ ├── ansi.py │ ├── connection.py │ ├── localstorage.py │ ├── massive.py │ └── x2numpy.py ├── pyproject.toml ├── pytest.ini ├── scripts ├── dev.sh ├── dev.visualdust.sh ├── install.sh └── release.linux.sh └── tests ├── __init__.py ├── client ├── readme.md ├── test.py └── weight_visualize_conv1_0_1.png ├── snake └── snake.py ├── test_daemon.py ├── test_logging.py └── test_utils.py /.flake8: -------------------------------------------------------------------------------- 1 | [flake8] 2 | max-line-length = 100 3 | extend-ignore = E203 4 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Smartphone (please complete the following information):** 32 | - Device: [e.g. iPhone6] 33 | - OS: [e.g. iOS8.1] 34 | - Browser [e.g. stock browser, safari] 35 | - Version [e.g. 22] 36 | 37 | **Additional context** 38 | Add any other context about the problem here. 39 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/renovate.json5: -------------------------------------------------------------------------------- 1 | { 2 | extends: [ 3 | 'config:recommended', 4 | 'schedule:weekly', 5 | 'group:allNonMajor', 6 | ], 7 | labels: [ 8 | 'dependencies', 9 | ], 10 | pin: { 11 | enabled: false, 12 | }, 13 | commitMessagePrefix: '⬆️ deps: ', 14 | dependencyDashboardTitle: '📈 Dependency Dashboard', 15 | packageRules: [ 16 | { 17 | groupName: 'dependencies (non-major)', 18 | matchUpdateTypes: [ 19 | 'minor', 20 | 'patch', 21 | 'pin', 22 | 'digest', 23 | ], 24 | automerge: true, 25 | automergeStrategy: 'squash', 26 | }, 27 | { 28 | matchCategories: [ 29 | 'python', 30 | ], 31 | addLabels: [ 32 | 'python', 33 | ], 34 | assignees: [ 35 | '@AndPuQing', 36 | '@visualDust', 37 | ], 38 | }, 39 | { 40 | matchCategories: [ 41 | 'node', 42 | ], 43 | addLabels: [ 44 | 'javascript', 45 | ], 46 | assignees: [ 47 | '@lideming', 48 | ], 49 | }, 50 | { 51 | matchPackageNames: '@douyinfe**', 52 | groupName: 'douyinfe', 53 | }, 54 | ], 55 | } 56 | -------------------------------------------------------------------------------- /.github/workflows/build-and-publish-pypi.yml: -------------------------------------------------------------------------------- 1 | # This workflow will upload a Python Package using Twine when a release is created 2 | # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python#publishing-to-package-registries 3 | 4 | # This workflow uses actions that are not certified by GitHub. 5 | # They are provided by a third-party and are governed by 6 | # separate terms of service, privacy policy, and support 7 | # documentation. 8 | 9 | name: Upload Python Package 10 | 11 | on: 12 | release: 13 | types: [published] 14 | workflow_dispatch: 15 | 16 | permissions: 17 | contents: read 18 | 19 | jobs: 20 | build: 21 | runs-on: ubuntu-latest 22 | steps: 23 | - uses: actions/checkout@v4 24 | - uses: actions/setup-node@v4 25 | with: 26 | node-version: 18 27 | cache: "yarn" 28 | cache-dependency-path: "frontend/yarn.lock" 29 | - name: setup yarn 30 | run: corepack enable 31 | working-directory: frontend 32 | - run: yarn install --frozen-lockfile 33 | working-directory: frontend 34 | - run: yarn build 35 | working-directory: frontend 36 | - name: Build and publish to pypi 37 | uses: JRubics/poetry-publish@v2.0 38 | with: 39 | pypi_token: ${{ secrets.PYPI_TOKEN }} 40 | -------------------------------------------------------------------------------- /.github/workflows/build-frontend.yml: -------------------------------------------------------------------------------- 1 | name: Frontend Build & Lint 2 | 3 | on: 4 | push: 5 | paths: 6 | - "frontend/**" 7 | pull_request: 8 | paths: 9 | - "frontend/**" 10 | 11 | jobs: 12 | build: 13 | runs-on: ubuntu-latest 14 | defaults: 15 | run: 16 | working-directory: frontend 17 | steps: 18 | - uses: actions/checkout@v4 19 | - uses: actions/setup-node@v4 20 | with: 21 | node-version: 18 22 | cache: "yarn" 23 | cache-dependency-path: "frontend/yarn.lock" 24 | - name: setup yarn 25 | run: corepack enable 26 | - run: yarn install --frozen-lockfile 27 | - run: yarn build 28 | - run: yarn tsc 29 | if: "!cancelled()" 30 | - run: yarn lint 31 | if: "!cancelled()" 32 | - run: yarn prettier-check 33 | if: "!cancelled()" 34 | -------------------------------------------------------------------------------- /.github/workflows/maunal-build.yml: -------------------------------------------------------------------------------- 1 | # This workflow will upload a Python Package using Twine when a release is created 2 | # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python#publishing-to-package-registries 3 | 4 | # This workflow uses actions that are not certified by GitHub. 5 | # They are provided by a third-party and are governed by 6 | # separate terms of service, privacy policy, and support 7 | # documentation. 8 | 9 | name: Manually Build and Publish to TEST.PyPi 10 | 11 | on: 12 | workflow_dispatch: 13 | 14 | permissions: 15 | contents: read 16 | 17 | jobs: 18 | build: 19 | runs-on: ubuntu-latest 20 | steps: 21 | - uses: actions/checkout@v4 22 | - uses: actions/setup-node@v4 23 | with: 24 | node-version: 18 25 | cache: "yarn" 26 | cache-dependency-path: "frontend/yarn.lock" 27 | - name: setup yarn 28 | run: corepack enable 29 | working-directory: frontend 30 | - run: yarn install --frozen-lockfile 31 | working-directory: frontend 32 | - run: yarn build 33 | working-directory: frontend 34 | - name: Build and publish to pypi 35 | uses: JRubics/poetry-publish@v2.0 36 | with: 37 | pypi_token: ${{ secrets.TEST_PYPI_TOKEN }} 38 | repository_name: "neetbox" 39 | repository_url: "https://test.pypi.org/legacy/" 40 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # IDE files 2 | .vscode 3 | .pytest_cache 4 | .ignore 5 | 6 | # Python files 7 | __pycache__/ 8 | dist/ 9 | poetry.lock 10 | 11 | # Frontend files 12 | node_modules 13 | frontend_dist/ 14 | 15 | # test files 16 | test/optional 17 | build_and_reinstall_wheel.cmd 18 | 19 | # log files 20 | logs/ 21 | log/ 22 | .log 23 | 24 | # neetbox files 25 | neetfiles 26 | neetbox.toml 27 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | exclude: | 2 | (?x)^( 3 | other/.+| 4 | doc/.+| 5 | )$ 6 | repos: 7 | - repo: https://github.com/pre-commit/pre-commit-hooks 8 | rev: v3.2.0 9 | hooks: 10 | - id: trailing-whitespace 11 | - id: end-of-file-fixer 12 | - id: check-yaml 13 | - id: check-toml 14 | - id: check-added-large-files 15 | - id: check-merge-conflict 16 | # For Python files 17 | - repo: https://github.com/psf/black.git 18 | rev: 23.9.1 19 | hooks: 20 | - id: black 21 | files: (.*\.(py|pyi|bzl)|BUILD|.*\.BUILD|WORKSPACE)$ 22 | args: [--line-length=100] 23 | - repo: https://github.com/pycqa/isort 24 | rev: 5.11.5 25 | hooks: 26 | - id: isort 27 | args: ["--profile", "black"] 28 | - repo: https://github.com/pre-commit/mirrors-prettier 29 | rev: "v3.1.0" # Use the sha or tag you want to point at 30 | hooks: 31 | - id: prettier 32 | files: .*\.(js|jsx|ts|tsx|json|yml|yaml|md)$ 33 | -------------------------------------------------------------------------------- /CITATION.cff: -------------------------------------------------------------------------------- 1 | cff-version: 1.2.0 2 | message: "You can cite NEETBOX as below." 3 | authors: 4 | - family-names: "Gong" 5 | given-names: "Zhaoting(Gavin)" 6 | - family-names: "Li" 7 | given-names: "Deming" 8 | title: "neetbox" 9 | version: 0.4.0 10 | date-released: 2023-12-23 11 | url: "https://github.com/visualDust/neetbox" 12 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 VisualDust 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![](./docs/static/img/readme.svg) 2 | 3 | 4 | 5 | [![wakatime](https://wakatime.com/badge/user/b93a26b6-8ea1-44ef-99ed-bcb6e2c732f1/project/8f99904d-dbb1-49e4-814d-8d18bf1e6d1c.svg)](https://wakatime.com/badge/user/b93a26b6-8ea1-44ef-99ed-bcb6e2c732f1/project/8f99904d-dbb1-49e4-814d-8d18bf1e6d1c) [![pytest](https://github.com/visualDust/neetbox/actions/workflows/poetry-pytest.yml/badge.svg)](https://github.com/visualDust/neetbox/actions/workflows/poetry-pytest.yml) ![GitHub Workflow Status (with event)](https://img.shields.io/github/actions/workflow/status/visualdust/neetbox/build-and-publish-pypi.yml) ![PyPI - Version](https://img.shields.io/pypi/v/neetbox) 6 | ![PyPI - Downloads](https://img.shields.io/pypi/dw/neetbox) [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black) [![codecov](https://codecov.io/gh/visualDust/neetbox/graph/badge.svg?token=WYWLQ4YKZJ)](https://codecov.io/gh/visualDust/neetbox) 7 | 8 | ## Install 9 | 10 | ```bash 11 | pip install neetbox 12 | ``` 13 | 14 | Docs: [neetbox.550w.host](https://neetbox.550w.host/) 15 | 16 | ## Dev 17 | 18 | To install editable version or build from source, use the following command: 19 | 20 | ```bash 21 | # create a virtual environment 22 | conda create -n neetbox python=3.12 23 | conda activate neetbox 24 | 25 | # clone the repository 26 | git clone https://github.com/visualDust/neetbox.git 27 | cd neetbox 28 | 29 | # install project 30 | poetry install 31 | 32 | # build frontend 33 | cd frontend 34 | yarn install 35 | yarn build 36 | ``` 37 | 38 | ## Screenshots 39 | 40 | ||| 41 | |---|---| 42 | |![screenshot](docs/static/screenshots/sc1.jpg) |![screenshot](docs/static/screenshots/sc2.jpg)| 43 | 44 | ![image](https://github.com/visualDust/neetbox/assets/33346934/acdbfd22-dd3b-4b7c-a446-2022125ba5c9) 45 | 46 | ## Contributors 47 | 48 | 49 | 50 | 51 | 52 | ## Acknowledgements 53 | 54 | This project usues [Asthestarsfalll/PyDocuSaurus](https://github.com/Asthestarsfalll/PyDocuSaurus) to generate the API reference. 55 | 56 | ## Star History 57 | 58 | [![Star History Chart](https://api.star-history.com/svg?repos=visualDust/neetbox&type=Date)](https://star-history.com/#visualDust/neetbox&Date) 59 | -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | codecov: 2 | token: 89d5d00f-39e7-4e79-9d63-165b5efee4cb 3 | ignore: 4 | - "frontend" 5 | -------------------------------------------------------------------------------- /docs/.gitignore: -------------------------------------------------------------------------------- 1 | # Dependencies 2 | /node_modules 3 | 4 | # Production 5 | /build 6 | 7 | # Generated files 8 | .docusaurus 9 | .cache-loader 10 | 11 | # Misc 12 | .DS_Store 13 | .env.local 14 | .env.development.local 15 | .env.test.local 16 | .env.production.local 17 | 18 | npm-debug.log* 19 | yarn-debug.log* 20 | yarn-error.log* 21 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # Neetbox documentation website 2 | 3 | This website is built using [Docusaurus 2](https://docusaurus.io/), a modern static website generator. 4 | 5 | ### Installation 6 | 7 | ``` 8 | $ yarn 9 | ``` 10 | 11 | ### Local Development 12 | 13 | ``` 14 | $ yarn start 15 | ``` 16 | 17 | This command starts a local development server and opens up a browser window. Most changes are reflected live without having to restart the server. 18 | 19 | ### Build 20 | 21 | ``` 22 | $ yarn build 23 | ``` 24 | 25 | This command generates static content into the `build` directory and can be served using any static contents hosting service. 26 | -------------------------------------------------------------------------------- /docs/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [require.resolve('@docusaurus/core/lib/babel/preset')], 3 | }; 4 | -------------------------------------------------------------------------------- /docs/docs/apidocs/client/-client-web-apis.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: _client_web_apis 3 | --- 4 | 5 | ## TOC 6 | 7 | - **Functions:** 8 | - 🅵 [\_get](#🅵-_get) 9 | - 🅵 [\_post](#🅵-_post) 10 | - 🅵 [\_put](#🅵-_put) 11 | - 🅵 [shutdown](#🅵-shutdown) 12 | 13 | ## Functions 14 | 15 | ## 🅵 \_get 16 | 17 | ```python 18 | def _get(api, root=None): 19 | ``` 20 | ## 🅵 \_post 21 | 22 | ```python 23 | def _post(api, root=None, data=None): 24 | ``` 25 | ## 🅵 \_put 26 | 27 | ```python 28 | def _put(api, root=None, data=None): 29 | ``` 30 | ## 🅵 shutdown 31 | 32 | ```python 33 | def shutdown(root=None): 34 | ``` 35 | -------------------------------------------------------------------------------- /docs/docs/apidocs/client/-shell.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: _shell 3 | --- 4 | 5 | ## TOC 6 | 7 | - **Classes:** 8 | - 🅲 [ShellAgent](#🅲-shellagent) 9 | 10 | ## Classes 11 | 12 | ## 🅲 ShellAgent 13 | 14 | ```python 15 | class ShellAgent: 16 | ``` 17 | 18 | 19 | ### 🅼 \_\_init\_\_ 20 | 21 | ```python 22 | def __init__(self) -> None: 23 | ``` 24 | ### 🅼 \_send\_to\_ws 25 | 26 | ```python 27 | def _send_to_ws(self): 28 | ``` 29 | ### 🅼 \_send\_to\_stdin 30 | 31 | ```python 32 | def _send_to_stdin(self, string, flush=True): 33 | ``` 34 | ### 🅼 read\_stdout 35 | 36 | ```python 37 | def read_stdout(self): 38 | ``` 39 | ### 🅼 start 40 | 41 | ```python 42 | def start(self, path): 43 | ``` 44 | -------------------------------------------------------------------------------- /docs/docs/apidocs/client/apis/-image.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: _image 3 | --- 4 | 5 | ## TOC 6 | 7 | - **Functions:** 8 | - 🅵 [figure\_to\_image](#🅵-figure_to_image) - Render matplotlib figure to numpy format. 9 | - 🅵 [make\_grid](#🅵-make_grid) 10 | - 🅵 [convert\_to\_HWC](#🅵-convert_to_hwc) 11 | - 🅵 [add\_image](#🅵-add_image) - send an image to frontend display 12 | - 🅵 [add\_figure](#🅵-add_figure) - Render matplotlib figure into an image and add it to summary. 13 | 14 | ## Functions 15 | 16 | ## 🅵 figure\_to\_image 17 | 18 | ```python 19 | def figure_to_image(figures, close=True): 20 | ``` 21 | 22 | Render matplotlib figure to numpy format. 23 | 24 | Note that this requires the \`\`matplotlib\`\` package. 25 | 26 | **Parameters:** 27 | 28 | - **figure** (matplotlib.pyplot.figure): figure or a list of figures 29 | - **close** ([bool](https://docs.python.org/3/library/stdtypes.html#boolean-values)): Flag to automatically close the figure 30 | 31 | **Returns:** 32 | 33 | - **numpy.array**: image in \[CHW\] order 34 | ## 🅵 make\_grid 35 | 36 | ```python 37 | def make_grid(I, ncols=8): 38 | ``` 39 | ## 🅵 convert\_to\_HWC 40 | 41 | ```python 42 | def convert_to_HWC(tensor, input_format): 43 | ``` 44 | ## 🅵 add\_image 45 | 46 | ```python 47 | def add_image(name: str, image, dataformats: str = None): 48 | ``` 49 | 50 | send an image to frontend display 51 | 52 | **Parameters:** 53 | 54 | - **image** (Union[np.array, Image.Image, Tensor]): image from cv2 and PIL.Image as well as tensors are supported 55 | - **name** ([str](https://docs.python.org/3/library/stdtypes.html#text-sequence-type-str)): name of the image, used in frontend display 56 | - **dataformats** ([str](https://docs.python.org/3/library/stdtypes.html#text-sequence-type-str)): if you are passing a tensor as image, please indicate how to understand the tensor. For example, dataformats="NCWH" means the first axis of the tensor is Number of batches, the second axis is Channel, and the third axis is Width, and the fourth axis is Height. 57 | ## 🅵 add\_figure 58 | 59 | ```python 60 | def add_figure(name: str, figure, close: Optional[bool] = True): 61 | ``` 62 | 63 | Render matplotlib figure into an image and add it to summary. 64 | 65 | Note that this requires the \`\`matplotlib\`\` package. 66 | 67 | **Parameters:** 68 | 69 | - **tag**: Data identifier 70 | - **figure** (matplotlib.pyplot.figure): Figure or a list of figures 71 | - **global_step**: Global step value to record 72 | - **close**: Flag to automatically close the figure 73 | - **walltime**: Override default walltime \(time.time\(\)\) of event 74 | -------------------------------------------------------------------------------- /docs/docs/apidocs/client/apis/-metadata.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: _metadata 3 | --- 4 | 5 | ## TOC 6 | 7 | - **Functions:** 8 | - 🅵 [add\_hyperparams](#🅵-add_hyperparams) - add/set hyperparams to current run, the added hyperparams will show in frontend 9 | - 🅵 [set\_run\_name](#🅵-set_run_name) - set the name of current run 10 | 11 | ## Functions 12 | 13 | ## 🅵 add\_hyperparams 14 | 15 | ```python 16 | def add_hyperparams(hparam: dict, name: str = None): 17 | ``` 18 | 19 | add/set hyperparams to current run, the added hyperparams will show in frontend 20 | 21 | **Parameters:** 22 | 23 | - **hparam** ([dict](https://docs.python.org/3/library/stdtypes.html#mapping-types-dict)): hyperparams 24 | - **name** ([str](https://docs.python.org/3/library/stdtypes.html#text-sequence-type-str)) (default to `None`): name of hyperparams. Defaults to None. 25 | ## 🅵 set\_run\_name 26 | 27 | ```python 28 | def set_run_name(name: str): 29 | ``` 30 | 31 | set the name of current run 32 | 33 | **Parameters:** 34 | 35 | - **name** ([str](https://docs.python.org/3/library/stdtypes.html#text-sequence-type-str)): name of current run 36 | -------------------------------------------------------------------------------- /docs/docs/apidocs/client/apis/-progress.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: _progress 3 | --- 4 | 5 | ## TOC 6 | 7 | - **Classes:** 8 | - 🅲 [Progress](#🅲-progress) 9 | 10 | ## Classes 11 | 12 | ## 🅲 Progress 13 | 14 | ```python 15 | class Progress: 16 | ``` 17 | 18 | 19 | ### 🅼 \_\_init\_\_ 20 | 21 | ```python 22 | def __init__(self, input: Union[int, enumerate, any], name=None): 23 | ``` 24 | 25 | Decorate an iterable object, returning an iterator. Neetbox will send progress to frontend while you are iterating through it. 26 | 27 | **Parameters:** 28 | 29 | - **input** (Union[int, enumerate, any]): Something to iterate or something to create enumeratable object. 30 | ### 🅼 \_\_enter\_\_ 31 | 32 | ```python 33 | def __enter__(self): 34 | ``` 35 | ### 🅼 \_\_exit\_\_ 36 | 37 | ```python 38 | def __exit__(self, type, value, traceback): 39 | ``` 40 | ### 🅼 \_\_iter\_\_ 41 | 42 | ```python 43 | def __iter__(self): 44 | ``` 45 | ### 🅼 \_update 46 | 47 | ```python 48 | def _update( 49 | cls, 50 | name: str, 51 | what_is_current: any, 52 | done: int, 53 | total: int, 54 | rate: float, 55 | timestamp=None, 56 | ): 57 | ``` 58 | ### 🅼 \_\_next\_\_ 59 | 60 | ```python 61 | def __next__(self): 62 | ``` 63 | ### 🅼 \_\_len\_\_ 64 | 65 | ```python 66 | def __len__(self): 67 | ``` 68 | -------------------------------------------------------------------------------- /docs/docs/apidocs/client/apis/-scalar.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: _scalar 3 | --- 4 | 5 | ## TOC 6 | 7 | - **Functions:** 8 | - 🅵 [add\_scalar](#🅵-add_scalar) - send a scalar to frontend display 9 | 10 | ## Functions 11 | 12 | ## 🅵 add\_scalar 13 | 14 | ```python 15 | def add_scalar(name: str, x: Union[int, float], y: Union[int, float]): 16 | ``` 17 | 18 | send a scalar to frontend display 19 | 20 | **Parameters:** 21 | 22 | - **name** ([str](https://docs.python.org/3/library/stdtypes.html#text-sequence-type-str)): name of the image, used in frontend display 23 | - **x** (Union[int, float]): x 24 | - **y** (Union[int, float]): y 25 | -------------------------------------------------------------------------------- /docs/docs/apidocs/client/apis/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: apis 3 | --- 4 | 5 | ## No Contents Are Generated 6 | -------------------------------------------------------------------------------- /docs/docs/apidocs/client/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: client 3 | --- 4 | 5 | ## TOC 6 | 7 | - **[Exports](#exports)** 8 | - **Attributes:** 9 | - 🅰 [ws\_subscribe](#🅰-ws_subscribe) 10 | - 🅰 [action](#🅰-action) 11 | 12 | ## Attributes 13 | 14 | ## 🅰 ws\_subscribe 15 | 16 | ```python 17 | ws_subscribe = connection.ws_subscribe 18 | ``` 19 | 20 | ## 🅰 action 21 | 22 | ```python 23 | action = actionManager.register 24 | ``` 25 | 26 | 27 | ## Exports 28 | 29 | - 🅵 [add\_image](apis/-image#🅵-add_image) 30 | - 🅵 [add\_scalar](apis/-scalar#🅵-add_scalar) 31 | - 🅵 [add\_figure](apis/-image#🅵-add_figure) 32 | - 🅵 [add\_hyperparams](apis/-metadata#🅵-add_hyperparams) 33 | - 🅵 [set\_run\_name](apis/-metadata#🅵-set_run_name) 34 | - 🅰 [ws\_subscribe](#🅰-ws_subscribe) 35 | - 🅰 [action](#🅰-action) 36 | - 🅵 [watch](-signal-and-slot#🅵-watch) 37 | - 🅵 [listen](-signal-and-slot#🅵-listen) 38 | - 🅲 [progress](apis/-progress#🅲-progress) 39 | -------------------------------------------------------------------------------- /docs/docs/apidocs/config/abc.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: abc 3 | --- 4 | 5 | ## TOC 6 | 7 | - **Classes:** 8 | - 🅲 [ConfigInterface](#🅲-configinterface) 9 | 10 | ## Classes 11 | 12 | ## 🅲 ConfigInterface 13 | 14 | ```python 15 | class ConfigInterface(ABC): 16 | ``` 17 | 18 | 19 | ### 🅼 \_\_setattr\_\_ 20 | 21 | ```python 22 | def __setattr__(self, key, value): 23 | ``` 24 | ### 🅼 \_\_getattr\_\_ 25 | 26 | ```python 27 | def __getattr__(self, key): 28 | ``` 29 | ### 🅼 update 30 | 31 | ```python 32 | def update(self, another): 33 | ``` 34 | ### 🅼 here 35 | 36 | ```python 37 | def here(self): 38 | ``` 39 | -------------------------------------------------------------------------------- /docs/docs/apidocs/config/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: config 3 | --- 4 | 5 | ## TOC 6 | 7 | - **[Exports](#exports)** 8 | - **Attributes:** 9 | - 🅰 [\_\_IS\_WORKSPACE\_LOADED](#🅰-__is_workspace_loaded) 10 | - **Functions:** 11 | - 🅵 [get\_module\_level\_config](#🅵-get_module_level_config) 12 | - 🅵 [get\_machine\_id](#🅵-get_machine_id) 13 | - 🅵 [get\_project\_id](#🅵-get_project_id) 14 | - 🅵 [get\_run\_id](#🅵-get_run_id) 15 | 16 | ## Attributes 17 | 18 | ## 🅰 \_\_IS\_WORKSPACE\_LOADED 19 | 20 | ```python 21 | __IS_WORKSPACE_LOADED = False 22 | ``` 23 | 24 | 25 | ## Functions 26 | 27 | ## 🅵 get\_module\_level\_config 28 | 29 | ```python 30 | def get_module_level_config(module: Union[str, types.ModuleType] = None): 31 | ``` 32 | ## 🅵 get\_machine\_id 33 | 34 | ```python 35 | def get_machine_id(): 36 | ``` 37 | ## 🅵 get\_project\_id 38 | 39 | ```python 40 | def get_project_id(): 41 | ``` 42 | ## 🅵 get\_run\_id 43 | 44 | ```python 45 | def get_run_id(): 46 | ``` 47 | 48 | ## Exports 49 | 50 | - 🅵 [get\_module\_level\_config](#🅵-get_module_level_config) 51 | - 🅵 [export\_default\_config](project#🅵-export_default_config) 52 | - 🅵 [get\_project\_id](#🅵-get_project_id) 53 | - 🅵 [get\_run\_id](#🅵-get_run_id) 54 | -------------------------------------------------------------------------------- /docs/docs/apidocs/config/user/hooks.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: hooks 3 | --- 4 | 5 | ## No Contents Are Generated 6 | -------------------------------------------------------------------------------- /docs/docs/apidocs/config/user/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: user 3 | --- 4 | 5 | ## TOC 6 | 7 | - **Attributes:** 8 | - 🅰 [\_GLOBAL\_CONFIG](#🅰-_global_config) 9 | - 🅰 [\_GLOBAL\_CONFIG\_FILE\_NAME](#🅰-_global_config_file_name) 10 | - **Functions:** 11 | - 🅵 [update\_dict\_recursively\_on\_missing\_keys](#🅵-update_dict_recursively_on_missing_keys) - Update dictionary B with keys from dictionary A. Add missing keys from A to B, 12 | - 🅵 [overwrite\_create\_local](#🅵-overwrite_create_local) 13 | - 🅵 [read\_create\_local](#🅵-read_create_local) 14 | - 🅵 [set](#🅵-set) 15 | - 🅵 [get](#🅵-get) 16 | 17 | ## Attributes 18 | 19 | ## 🅰 \_GLOBAL\_CONFIG 20 | 21 | ```python 22 | _GLOBAL_CONFIG = { 23 | MACHINE_ID_KEY: str(uuid4()), 24 | "vault": get_create_initial_neetbox_data_directory(), 25 | "bypass-db-version-check": True, 26 | } 27 | ``` 28 | 29 | ## 🅰 \_GLOBAL\_CONFIG\_FILE\_NAME 30 | 31 | ```python 32 | _GLOBAL_CONFIG_FILE_NAME = f"""neetbox.global.toml""" 33 | ``` 34 | 35 | 36 | ## Functions 37 | 38 | ## 🅵 update\_dict\_recursively\_on\_missing\_keys 39 | 40 | ```python 41 | def update_dict_recursively_on_missing_keys(A, B): 42 | ``` 43 | 44 | Update dictionary B with keys from dictionary A. Add missing keys from A to B, 45 | 46 | but do not overwrite existing keys in B. Handles nested dictionaries recursively. 47 | ## 🅵 overwrite\_create\_local 48 | 49 | ```python 50 | def overwrite_create_local(config: dict): 51 | ``` 52 | ## 🅵 read\_create\_local 53 | 54 | ```python 55 | def read_create_local(): 56 | ``` 57 | ## 🅵 set 58 | 59 | ```python 60 | def set(key, value): 61 | ``` 62 | ## 🅵 get 63 | 64 | ```python 65 | def get(key=None): 66 | ``` 67 | -------------------------------------------------------------------------------- /docs/docs/apidocs/extension/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: extension 3 | --- 4 | 5 | ## TOC 6 | 7 | - **Attributes:** 8 | - 🅰 [\_\_QUERY\_AFTER\_LOAD\_WORKSPACE](#🅰-__query_after_load_workspace) 9 | - 🅰 [on\_workspace\_loaded](#🅰-on_workspace_loaded) 10 | - **Functions:** 11 | - 🅵 [\_scan\_sub\_modules](#🅵-_scan_sub_modules) 12 | - 🅵 [\_init\_extensions](#🅵-_init_extensions) - DO NOT call before workspace config load 13 | 14 | ## Attributes 15 | 16 | ## 🅰 \_\_QUERY\_AFTER\_LOAD\_WORKSPACE 17 | 18 | ```python 19 | __QUERY_AFTER_LOAD_WORKSPACE = Registry("__QUERY_AFTER_LOAD_WORKSPACE") 20 | ``` 21 | 22 | ## 🅰 on\_workspace\_loaded 23 | 24 | ```python 25 | on_workspace_loaded = __QUERY_AFTER_LOAD_WORKSPACE.register 26 | ``` 27 | 28 | 29 | ## Functions 30 | 31 | ## 🅵 \_scan\_sub\_modules 32 | 33 | ```python 34 | def _scan_sub_modules(): 35 | ``` 36 | ## 🅵 \_init\_extensions 37 | 38 | ```python 39 | def _init_extensions(): 40 | ``` 41 | 42 | DO NOT call before workspace config load 43 | -------------------------------------------------------------------------------- /docs/docs/apidocs/extension/machine/-gputil.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: _gputil 3 | --- 4 | 5 | ## TOC 6 | 7 | - **Functions:** 8 | - 🅵 [safeFloatCast](#🅵-safefloatcast) 9 | - 🅵 [getGPUs](#🅵-getgpus) 10 | - 🅵 [getAvailable](#🅵-getavailable) 11 | - 🅵 [getAvailability](#🅵-getavailability) 12 | - 🅵 [getFirstAvailable](#🅵-getfirstavailable) 13 | - 🅵 [showUtilization](#🅵-showutilization) 14 | - **Classes:** 15 | - 🅲 [GPU](#🅲-gpu) 16 | 17 | ## Functions 18 | 19 | ## 🅵 safeFloatCast 20 | 21 | ```python 22 | def safeFloatCast(strNumber): 23 | ``` 24 | ## 🅵 getGPUs 25 | 26 | ```python 27 | def getGPUs(): 28 | ``` 29 | ## 🅵 getAvailable 30 | 31 | ```python 32 | def getAvailable( 33 | order="first", 34 | limit=1, 35 | maxLoad=0.5, 36 | maxMemory=0.5, 37 | memoryFree=0, 38 | includeNan=False, 39 | excludeID=[], 40 | excludeUUID=[], 41 | ): 42 | ``` 43 | ## 🅵 getAvailability 44 | 45 | ```python 46 | def getAvailability( 47 | GPUs, 48 | maxLoad=0.5, 49 | maxMemory=0.5, 50 | memoryFree=0, 51 | includeNan=False, 52 | excludeID=[], 53 | excludeUUID=[], 54 | ): 55 | ``` 56 | ## 🅵 getFirstAvailable 57 | 58 | ```python 59 | def getFirstAvailable( 60 | order="first", 61 | maxLoad=0.5, 62 | maxMemory=0.5, 63 | attempts=1, 64 | interval=900, 65 | verbose=False, 66 | includeNan=False, 67 | excludeID=[], 68 | excludeUUID=[], 69 | ): 70 | ``` 71 | ## 🅵 showUtilization 72 | 73 | ```python 74 | def showUtilization(all=False, attrList=None, useOldCode=False): 75 | ``` 76 | 77 | ## Classes 78 | 79 | ## 🅲 GPU 80 | 81 | ```python 82 | class GPU: 83 | ``` 84 | 85 | 86 | ### 🅼 \_\_init\_\_ 87 | 88 | ```python 89 | def __init__( 90 | self, 91 | ID, 92 | uuid, 93 | load, 94 | memoryTotal, 95 | memoryUsed, 96 | memoryFree, 97 | driver, 98 | gpu_name, 99 | serial, 100 | display_mode, 101 | display_active, 102 | temp_gpu, 103 | ): 104 | ``` 105 | -------------------------------------------------------------------------------- /docs/docs/apidocs/extension/machine/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: machine 3 | --- 4 | 5 | ## TOC 6 | 7 | - **[Exports](#exports)** 8 | 9 | ## Exports 10 | 11 | - 🅰 [hardware](hardware#🅰-hardware) 12 | - 🅲 [CpuStatus](hardware#🅲-cpustatus) 13 | - 🅲 [CpuStatistics](hardware#🅲-cpustatistics) 14 | - 🅲 [MemoryStatus](hardware#🅲-memorystatus) 15 | - 🅰 [platform](platform#🅰-platform) 16 | -------------------------------------------------------------------------------- /docs/docs/apidocs/extension/machine/platform.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: platform 3 | --- 4 | 5 | ## TOC 6 | 7 | - **Attributes:** 8 | - 🅰 [platform](#🅰-platform) - watch updates in daemon 9 | - **Functions:** 10 | - 🅵 [load\_send\_platform\_info](#🅵-load_send_platform_info) 11 | - **Classes:** 12 | - 🅲 [PlatformInfo](#🅲-platforminfo) 13 | 14 | ## Attributes 15 | 16 | ## 🅰 platform 17 | 18 | ```python 19 | platform = PlatformInfo() #watch updates in daemon 20 | ``` 21 | 22 | 23 | ## Functions 24 | 25 | ## 🅵 load\_send\_platform\_info 26 | 27 | ```python 28 | def load_send_platform_info(): 29 | ``` 30 | 31 | ## Classes 32 | 33 | ## 🅲 PlatformInfo 34 | 35 | ```python 36 | class PlatformInfo: 37 | ``` 38 | 39 | 40 | ### 🅼 \_\_init\_\_ 41 | 42 | ```python 43 | def __init__(self): 44 | ``` 45 | ### 🅼 username 46 | 47 | ```python 48 | def username(self): 49 | ``` 50 | ### 🅼 machine 51 | 52 | ```python 53 | def machine(self): 54 | ``` 55 | ### 🅼 processor 56 | 57 | ```python 58 | def processor(self): 59 | ``` 60 | ### 🅼 os\_name 61 | 62 | ```python 63 | def os_name(self): 64 | ``` 65 | ### 🅼 os\_release 66 | 67 | ```python 68 | def os_release(self): 69 | ``` 70 | ### 🅼 python\_version 71 | 72 | ```python 73 | def python_version(self): 74 | ``` 75 | ### 🅼 python\_build 76 | 77 | ```python 78 | def python_build(self): 79 | ``` 80 | ### 🅼 json 81 | 82 | ```python 83 | def json(self): 84 | ``` 85 | ### 🅼 \_\_str\_\_ 86 | 87 | ```python 88 | def __str__(self) -> str: 89 | ``` 90 | -------------------------------------------------------------------------------- /docs/docs/apidocs/logging/-formatting.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: _formatting 3 | --- 4 | 5 | ## TOC 6 | 7 | - **Classes:** 8 | - 🅲 [LogStyle](#🅲-logstyle) 9 | - 🅲 [RawLog](#🅲-rawlog) 10 | 11 | ## Classes 12 | 13 | ## 🅲 LogStyle 14 | 15 | ```python 16 | class LogStyle: 17 | ``` 18 | ## 🅲 RawLog 19 | 20 | ```python 21 | class RawLog: 22 | ``` 23 | 24 | 25 | ### 🅼 timestamp\_formatted 26 | 27 | ```python 28 | def timestamp_formatted(self): 29 | ``` 30 | ### 🅼 caller\_info\_formatted 31 | 32 | ```python 33 | def caller_info_formatted(self): 34 | ``` 35 | ### 🅼 json 36 | 37 | ```python 38 | def json(self) -> dict: 39 | ``` 40 | ### 🅼 \_\_repr\_\_ 41 | 42 | ```python 43 | def __repr__(self) -> str: 44 | ``` 45 | -------------------------------------------------------------------------------- /docs/docs/apidocs/logging/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: logging 3 | --- 4 | 5 | ## TOC 6 | 7 | - **[Exports](#exports)** 8 | 9 | ## Exports 10 | 11 | - 🅰 [logger](-logger#🅰-default_logger) 12 | - 🅲 [Logger](-logger#🅲-logger) 13 | - 🅲 [LogLevel](-logger#🅲-loglevel) 14 | - 🅲 [LogStyle](-formatting#🅲-logstyle) 15 | - 🅲 [RawLog](-formatting#🅲-rawlog) 16 | -------------------------------------------------------------------------------- /docs/docs/apidocs/logging/writers/-file.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: _file 3 | --- 4 | 5 | ## TOC 6 | 7 | - **Classes:** 8 | - 🅲 [FileLogWriter](#🅲-filelogwriter) 9 | 10 | ## Classes 11 | 12 | ## 🅲 FileLogWriter 13 | 14 | ```python 15 | class FileLogWriter: 16 | ``` 17 | 18 | 19 | ### 🅼 \_\_new\_\_ 20 | 21 | ```python 22 | def __new__(cls, path): 23 | ``` 24 | ### 🅼 write 25 | 26 | ```python 27 | def write(self, log: RawLog): 28 | ``` 29 | -------------------------------------------------------------------------------- /docs/docs/apidocs/logging/writers/-stdout.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: _stdout 3 | --- 4 | 5 | ## TOC 6 | 7 | - **Attributes:** 8 | - 🅰 [LogWriters](#🅰-logwriters) 9 | - 🅰 [console](#🅰-console) 10 | - 🅰 [whom2color](#🅰-whom2color) 11 | - 🅰 [supported\_colors](#🅰-supported_colors) 12 | - 🅰 [supported\_text\_styles](#🅰-supported_text_styles) 13 | - **Functions:** 14 | - 🅵 [log\_write\_stdout](#🅵-log_write_stdout) 15 | 16 | ## Attributes 17 | 18 | ## 🅰 LogWriters 19 | 20 | ```python 21 | LogWriters = Registry("LOG_WRITERS") 22 | ``` 23 | 24 | ## 🅰 console 25 | 26 | ```python 27 | console = Console() 28 | ``` 29 | 30 | ## 🅰 whom2color 31 | 32 | ```python 33 | whom2color = {} 34 | ``` 35 | 36 | ## 🅰 supported\_colors 37 | 38 | ```python 39 | supported_colors = ["red", "green", "blue", "cyan", "yellow", "magenta"] 40 | ``` 41 | 42 | ## 🅰 supported\_text\_styles 43 | 44 | ```python 45 | supported_text_styles = ["bold", "italic", "blink", "dim"] 46 | ``` 47 | 48 | 49 | ## Functions 50 | 51 | ## 🅵 log\_write\_stdout 52 | 53 | ```python 54 | def log_write_stdout(log: RawLog): 55 | ``` 56 | -------------------------------------------------------------------------------- /docs/docs/apidocs/logging/writers/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: writers 3 | --- 4 | 5 | ## No Contents Are Generated 6 | -------------------------------------------------------------------------------- /docs/docs/apidocs/server/-daemon-server-launch-script.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: _daemon_server_launch_script 3 | --- 4 | 5 | ## TOC 6 | 7 | - **Functions:** 8 | - 🅵 [run](#🅵-run) 9 | - 🅵 [start](#🅵-start) - start a server as background daemon 10 | 11 | ## Functions 12 | 13 | ## 🅵 run 14 | 15 | ```python 16 | def run(config): 17 | ``` 18 | ## 🅵 start 19 | 20 | ```python 21 | def start(config) -> Optional[int]: 22 | ``` 23 | 24 | start a server as background daemon 25 | 26 | **Parameters:** 27 | 28 | - **config** ([dict](https://docs.python.org/3/library/stdtypes.html#mapping-types-dict)): server launch config 29 | 30 | **Returns:** 31 | 32 | - **[DaemonableProcess](../utils/-daemonable-process#🅲-daemonableprocess)**: the daemon process 33 | -------------------------------------------------------------------------------- /docs/docs/apidocs/server/db/-manager.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: _manager 3 | --- 4 | 5 | ## TOC 6 | 7 | - **Attributes:** 8 | - 🅰 [ModuleNameType](#🅰-modulenametype) 9 | - 🅰 [DbIdType](#🅰-dbidtype) 10 | - 🅰 [manager](#🅰-manager) 11 | - **Classes:** 12 | - 🅲 [DBConnectionManager](#🅲-dbconnectionmanager) 13 | 14 | ## Attributes 15 | 16 | ## 🅰 ModuleNameType 17 | 18 | ```python 19 | ModuleNameType = str 20 | ``` 21 | 22 | ## 🅰 DbIdType 23 | 24 | ```python 25 | DbIdType = str 26 | ``` 27 | 28 | ## 🅰 manager 29 | 30 | ```python 31 | manager = DBConnectionManager() 32 | ``` 33 | 34 | 35 | ## Classes 36 | 37 | ## 🅲 DBConnectionManager 38 | 39 | ```python 40 | class DBConnectionManager: 41 | ``` 42 | 43 | 44 | ### 🅼 current 45 | 46 | ```python 47 | def current(self): 48 | ``` 49 | ### 🅼 \_\_init\_\_ 50 | 51 | ```python 52 | def __init__(self): 53 | ``` 54 | -------------------------------------------------------------------------------- /docs/docs/apidocs/server/db/abc.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: abc 3 | --- 4 | 5 | ## TOC 6 | 7 | - **Classes:** 8 | - 🅲 [FetchType](#🅲-fetchtype) 9 | - 🅲 [SortType](#🅲-sorttype) 10 | - 🅲 [ManageableDB](#🅲-manageabledb) 11 | 12 | ## Classes 13 | 14 | ## 🅲 FetchType 15 | 16 | ```python 17 | class FetchType(str, Enum): 18 | ``` 19 | ## 🅲 SortType 20 | 21 | ```python 22 | class SortType(str, Enum): 23 | ``` 24 | ## 🅲 ManageableDB 25 | 26 | ```python 27 | class ManageableDB(ABC): 28 | ``` 29 | 30 | 31 | ### 🅼 size 32 | 33 | ```python 34 | def size(self): 35 | ``` 36 | 37 | get local storage usage in bytes 38 | ### 🅼 close 39 | 40 | ```python 41 | def close(self): 42 | ``` 43 | ### 🅼 delete 44 | 45 | ```python 46 | def delete(self): 47 | ``` 48 | 49 | handle delete, a typical behavior is to close connection and remove files 50 | -------------------------------------------------------------------------------- /docs/docs/apidocs/server/db/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: db 3 | --- 4 | 5 | ## TOC 6 | 7 | - **[Exports](#exports)** 8 | 9 | ## Exports 10 | 11 | - 🅲 [FetchType](abc#🅲-fetchtype) 12 | - 🅲 [SortType](abc#🅲-sorttype) 13 | -------------------------------------------------------------------------------- /docs/docs/apidocs/server/db/project/condition.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: condition 3 | --- 4 | 5 | ## TOC 6 | 7 | - **Classes:** 8 | - 🅲 [ProjectDbQueryCondition](#🅲-projectdbquerycondition) 9 | 10 | ## Classes 11 | 12 | ## 🅲 ProjectDbQueryCondition 13 | 14 | ```python 15 | class ProjectDbQueryCondition: 16 | ``` 17 | 18 | 19 | ### 🅼 \_\_init\_\_ 20 | 21 | ```python 22 | def __init__( 23 | self, 24 | id: Union[Tuple[int, int], int] = None, 25 | timestamp: Union[Tuple[str, str], str] = None, 26 | series: str = None, 27 | run_id: Union[str, int] = None, 28 | limit: int = None, 29 | order: Dict[str, SortType] = {}, 30 | ) -> None: 31 | ``` 32 | ### 🅼 loads 33 | 34 | ```python 35 | def loads(cls, json_data): 36 | ``` 37 | ### 🅼 dumpt 38 | 39 | ```python 40 | def dumpt(self): 41 | ``` 42 | -------------------------------------------------------------------------------- /docs/docs/apidocs/server/db/project/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: project 3 | --- 4 | 5 | ## TOC 6 | 7 | - **[Exports](#exports)** 8 | 9 | ## Exports 10 | 11 | - 🅲 [ProjectDB](-project-db#🅲-projectdb) 12 | -------------------------------------------------------------------------------- /docs/docs/apidocs/server/fastapi/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: fastapi 3 | --- 4 | 5 | ## TOC 6 | 7 | - **Attributes:** 8 | - 🅰 [logger](#🅰-logger) 9 | - 🅰 [serverapp](#🅰-serverapp) 10 | - 🅰 [front\_end\_dist\_path](#🅰-front_end_dist_path) 11 | - **Functions:** 12 | - 🅵 [redirect\_to\_web](#🅵-redirect_to_web) 13 | - 🅵 [serve\_static\_root](#🅵-serve_static_root) 14 | 15 | ## Attributes 16 | 17 | ## 🅰 logger 18 | 19 | ```python 20 | logger = Logger("FASTAPI", skip_writers_names=["ws"]) 21 | ``` 22 | 23 | ## 🅰 serverapp 24 | 25 | ```python 26 | serverapp = FastAPI() 27 | ``` 28 | 29 | ## 🅰 front\_end\_dist\_path 30 | 31 | ```python 32 | front_end_dist_path = os.path.join( 33 | os.path.dirname(neetbox.__file__), "frontend_dist" 34 | ) 35 | ``` 36 | 37 | 38 | ## Functions 39 | 40 | ## 🅵 redirect\_to\_web 41 | 42 | ```python 43 | def redirect_to_web(): 44 | ``` 45 | ## 🅵 serve\_static\_root 46 | 47 | ```python 48 | def serve_static_root(path: str): 49 | ``` 50 | -------------------------------------------------------------------------------- /docs/docs/apidocs/server/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: server 3 | --- 4 | 5 | ## No Contents Are Generated 6 | -------------------------------------------------------------------------------- /docs/docs/apidocs/server/server-process.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: server_process 3 | --- 4 | 5 | ## TOC 6 | 7 | - **Attributes:** 8 | - 🅰 [console](#🅰-console) 9 | - **Functions:** 10 | - 🅵 [server\_process](#🅵-server_process) 11 | 12 | ## Attributes 13 | 14 | ## 🅰 console 15 | 16 | ```python 17 | console = Console() 18 | ``` 19 | 20 | 21 | ## Functions 22 | 23 | ## 🅵 server\_process 24 | 25 | ```python 26 | def server_process(cfg, debug=False): 27 | ``` 28 | -------------------------------------------------------------------------------- /docs/docs/apidocs/utils/-daemonable-process.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: _daemonable_process 3 | --- 4 | 5 | ## TOC 6 | 7 | - **Functions:** 8 | - 🅵 [main](#🅵-main) 9 | - **Classes:** 10 | - 🅲 [DaemonableProcess](#🅲-daemonableprocess) 11 | 12 | ## Functions 13 | 14 | ## 🅵 main 15 | 16 | ```python 17 | def main(): 18 | ``` 19 | 20 | ## Classes 21 | 22 | ## 🅲 DaemonableProcess 23 | 24 | ```python 25 | class DaemonableProcess: 26 | ``` 27 | 28 | 29 | ### 🅼 \_\_init\_\_ 30 | 31 | ```python 32 | def __init__( 33 | self, 34 | target: Union[str, ModuleType], 35 | args: List = [], 36 | mode: Literal["attached", "detached"], 37 | redirect_stdout=None, 38 | redirect_stderr=subprocess.STDOUT, 39 | use_os_spawn_for_daemon=False, 40 | redirect_stdin=subprocess.DEVNULL, 41 | env_append=None, 42 | ): 43 | ``` 44 | ### 🅼 is\_daemon 45 | 46 | ```python 47 | def is_daemon(self): 48 | ``` 49 | ### 🅼 mode 50 | 51 | ```python 52 | def mode(self): 53 | ``` 54 | ### 🅼 start 55 | 56 | ```python 57 | def start(self, shell=False, path=None): 58 | ``` 59 | ### 🅼 terminate 60 | 61 | ```python 62 | def terminate(self): 63 | ``` 64 | -------------------------------------------------------------------------------- /docs/docs/apidocs/utils/-messaging.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: _messaging 3 | --- 4 | 5 | ## TOC 6 | 7 | - **Attributes:** 8 | - 🅰 [console](#🅰-console) 9 | - 🅰 [MessageType](#🅰-messagetype) 10 | - 🅰 [NameType](#🅰-nametype) 11 | - 🅰 [messaging](#🅰-messaging) - singleton 12 | - **Classes:** 13 | - 🅲 [MessageListener](#🅲-messagelistener) 14 | - 🅲 [Messaging](#🅲-messaging) 15 | 16 | ## Attributes 17 | 18 | ## 🅰 console 19 | 20 | ```python 21 | console = Console() 22 | ``` 23 | 24 | ## 🅰 MessageType 25 | 26 | ```python 27 | MessageType = str 28 | ``` 29 | 30 | ## 🅰 NameType 31 | 32 | ```python 33 | NameType = str 34 | ``` 35 | 36 | ## 🅰 messaging 37 | 38 | ```python 39 | messaging = Messaging() #singleton 40 | ``` 41 | 42 | 43 | ## Classes 44 | 45 | ## 🅲 MessageListener 46 | 47 | ```python 48 | class MessageListener: 49 | ``` 50 | 51 | 52 | ### 🅼 json 53 | 54 | ```python 55 | def json(self): 56 | ``` 57 | ## 🅲 Messaging 58 | 59 | ```python 60 | class Messaging: 61 | ``` 62 | 63 | 64 | ### 🅼 listener 65 | 66 | ```python 67 | def listener(self, message_type: str, name: str = None): 68 | ``` 69 | ### 🅼 send 70 | 71 | ```python 72 | def send(self, message_type: str, message: any = None): 73 | ``` 74 | ### 🅼 json 75 | 76 | ```python 77 | def json(self): 78 | ``` 79 | -------------------------------------------------------------------------------- /docs/docs/apidocs/utils/-package.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: _package 3 | --- 4 | 5 | ## TOC 6 | 7 | - **Attributes:** 8 | - 🅰 [pipPackageHealper](#🅰-pippackagehealper) 9 | - **Classes:** 10 | - 🅲 [PipPackageHealper](#🅲-pippackagehealper) 11 | 12 | ## Attributes 13 | 14 | ## 🅰 pipPackageHealper 15 | 16 | ```python 17 | pipPackageHealper = PipPackageHealper() 18 | ``` 19 | 20 | 21 | ## Classes 22 | 23 | ## 🅲 PipPackageHealper 24 | 25 | ```python 26 | class PipPackageHealper: 27 | ``` 28 | 29 | 30 | ### 🅼 \_\_init\_\_ 31 | 32 | ```python 33 | def __init__(self) -> None: 34 | ``` 35 | ### 🅼 install 36 | 37 | ```python 38 | def install(self, package, terminate=False): 39 | ``` 40 | ### 🅼 is\_installed 41 | 42 | ```python 43 | def is_installed( 44 | self, package: str, try_install_if_not: Union[str, bool] = True 45 | ): 46 | ``` 47 | -------------------------------------------------------------------------------- /docs/docs/apidocs/utils/ansi.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: ansi 3 | --- 4 | 5 | ## TOC 6 | 7 | - **Functions:** 8 | - 🅵 [is\_pure\_ansi](#🅵-is_pure_ansi) 9 | - 🅵 [is\_fs\_case\_sensitive](#🅵-is_fs_case_sensitive) - Check if the file system is case sensitive 10 | - 🅵 [legal\_file\_name\_of](#🅵-legal_file_name_of) - Remove invalid characters for windows file systems 11 | - 🅵 [is\_jsonable](#🅵-is_jsonable) 12 | 13 | ## Functions 14 | 15 | ## 🅵 is\_pure\_ansi 16 | 17 | ```python 18 | def is_pure_ansi(text: str) -> bool: 19 | ``` 20 | ## 🅵 is\_fs\_case\_sensitive 21 | 22 | ```python 23 | def is_fs_case_sensitive(): 24 | ``` 25 | 26 | Check if the file system is case sensitive 27 | 28 | **Returns:** 29 | 30 | - **[bool](https://docs.python.org/3/library/stdtypes.html#boolean-values)**: True if case sensitive 31 | ## 🅵 legal\_file\_name\_of 32 | 33 | ```python 34 | def legal_file_name_of(text: str) -> str: 35 | ``` 36 | 37 | Remove invalid characters for windows file systems 38 | 39 | **Parameters:** 40 | 41 | - **title** ([str](https://docs.python.org/3/library/stdtypes.html#text-sequence-type-str)): the given title 42 | 43 | **Returns:** 44 | 45 | - **[str](https://docs.python.org/3/library/stdtypes.html#text-sequence-type-str)**: valid text 46 | ## 🅵 is\_jsonable 47 | 48 | ```python 49 | def is_jsonable(x): 50 | ``` 51 | -------------------------------------------------------------------------------- /docs/docs/apidocs/utils/connection.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: connection 3 | --- 4 | 5 | ## TOC 6 | 7 | - **Attributes:** 8 | - 🅰 [httpxClient](#🅰-httpxclient) - httpx client 9 | - **Functions:** 10 | - 🅵 [\_clean\_websocket\_on\_exit](#🅵-_clean_websocket_on_exit) 11 | - **Classes:** 12 | - 🅲 [WebsocketClient](#🅲-websocketclient) 13 | 14 | ## Attributes 15 | 16 | ## 🅰 httpxClient 17 | 18 | ```python 19 | httpxClient: httpx.Client = httpx.Client(proxy=None) #httpx client 20 | ``` 21 | 22 | 23 | ## Functions 24 | 25 | ## 🅵 \_clean\_websocket\_on\_exit 26 | 27 | ```python 28 | def _clean_websocket_on_exit(): 29 | ``` 30 | 31 | ## Classes 32 | 33 | ## 🅲 WebsocketClient 34 | 35 | ```python 36 | class WebsocketClient: 37 | ``` 38 | 39 | 40 | ### 🅼 \_\_init\_\_ 41 | 42 | ```python 43 | def __init__( 44 | self, 45 | url, 46 | on_open, 47 | on_message, 48 | on_error, 49 | on_close, 50 | offline_message_buffer_size=0, 51 | ): 52 | ``` 53 | ### 🅼 connect 54 | 55 | ```python 56 | def connect(self, reconnect=1): 57 | ``` 58 | ### 🅼 is\_connected 59 | 60 | ```python 61 | def is_connected(self) -> bool: 62 | ``` 63 | ### 🅼 send 64 | 65 | ```python 66 | def send(self, message: EventMsg): 67 | ``` 68 | -------------------------------------------------------------------------------- /docs/docs/apidocs/utils/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: utils 3 | --- 4 | 5 | ## TOC 6 | 7 | - **[Exports](#exports)** 8 | 9 | ## Exports 10 | 11 | - 🅰 [pkg](-package#🅰-pippackagehealper) 12 | - 🅲 [DaemonableProcess](-daemonable-process#🅲-daemonableprocess) 13 | - 🅰 [messaging](-messaging#🅰-messaging) 14 | -------------------------------------------------------------------------------- /docs/docs/apidocs/utils/localstorage.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: localstorage 3 | --- 4 | 5 | ## TOC 6 | 7 | - **Functions:** 8 | - 🅵 [get\_create\_neetbox\_config\_directory](#🅵-get_create_neetbox_config_directory) 9 | - 🅵 [get\_create\_initial\_neetbox\_data\_directory](#🅵-get_create_initial_neetbox_data_directory) - Get(create) initial neetbox data directory. Only useful for the first time. 10 | 11 | ## Functions 12 | 13 | ## 🅵 get\_create\_neetbox\_config\_directory 14 | 15 | ```python 16 | def get_create_neetbox_config_directory(): 17 | ``` 18 | ## 🅵 get\_create\_initial\_neetbox\_data\_directory 19 | 20 | ```python 21 | def get_create_initial_neetbox_data_directory(): 22 | ``` 23 | 24 | Get\(create\) initial neetbox data directory. Only useful for the first time. 25 | -------------------------------------------------------------------------------- /docs/docs/apidocs/utils/massive.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: massive 3 | --- 4 | 5 | ## TOC 6 | 7 | - **Attributes:** 8 | - 🅰 [\_ThreadPoolExecutor](#🅰-_threadpoolexecutor) 9 | - **Functions:** 10 | - 🅵 [is\_loopback](#🅵-is_loopback) 11 | - 🅵 [nonblocking](#🅵-nonblocking) 12 | - 🅵 [update\_dict\_recursively](#🅵-update_dict_recursively) 13 | - 🅵 [check\_read\_toml](#🅵-check_read_toml) 14 | - 🅵 [describe\_object](#🅵-describe_object) 15 | 16 | ## Attributes 17 | 18 | ## 🅰 \_ThreadPoolExecutor 19 | 20 | ```python 21 | _ThreadPoolExecutor = ThreadPoolExecutor() 22 | ``` 23 | 24 | 25 | ## Functions 26 | 27 | ## 🅵 is\_loopback 28 | 29 | ```python 30 | def is_loopback(host): 31 | ``` 32 | ## 🅵 nonblocking 33 | 34 | ```python 35 | def nonblocking(func): 36 | ``` 37 | ## 🅵 update\_dict\_recursively 38 | 39 | ```python 40 | def update_dict_recursively(self: dict, the_other: dict): 41 | ``` 42 | ## 🅵 check\_read\_toml 43 | 44 | ```python 45 | def check_read_toml(path) -> Union[dict, bool]: 46 | ``` 47 | ## 🅵 describe\_object 48 | 49 | ```python 50 | def describe_object(obj, length_limit=None) -> str: 51 | ``` 52 | -------------------------------------------------------------------------------- /docs/docs/apidocs/utils/x2numpy.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: x2numpy 3 | --- 4 | 5 | ## TOC 6 | 7 | - **Functions:** 8 | - 🅵 [check\_nan](#🅵-check_nan) 9 | - 🅵 [make\_np](#🅵-make_np) 10 | - 🅵 [prepare\_pytorch](#🅵-prepare_pytorch) 11 | - 🅵 [prepare\_theano](#🅵-prepare_theano) 12 | - 🅵 [prepare\_caffe2](#🅵-prepare_caffe2) 13 | - 🅵 [prepare\_mxnet](#🅵-prepare_mxnet) 14 | - 🅵 [prepare\_chainer](#🅵-prepare_chainer) 15 | 16 | ## Functions 17 | 18 | ## 🅵 check\_nan 19 | 20 | ```python 21 | def check_nan(array): 22 | ``` 23 | ## 🅵 make\_np 24 | 25 | ```python 26 | def make_np(x): 27 | ``` 28 | ## 🅵 prepare\_pytorch 29 | 30 | ```python 31 | def prepare_pytorch(x): 32 | ``` 33 | ## 🅵 prepare\_theano 34 | 35 | ```python 36 | def prepare_theano(x): 37 | ``` 38 | ## 🅵 prepare\_caffe2 39 | 40 | ```python 41 | def prepare_caffe2(x): 42 | ``` 43 | ## 🅵 prepare\_mxnet 44 | 45 | ```python 46 | def prepare_mxnet(x): 47 | ``` 48 | ## 🅵 prepare\_chainer 49 | 50 | ```python 51 | def prepare_chainer(x): 52 | ``` 53 | -------------------------------------------------------------------------------- /docs/docs/develop/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 1 3 | --- 4 | 5 | # Develop 6 | -------------------------------------------------------------------------------- /docs/docs/howto/configurations/index.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Configure neetbox 3 | sidebar_position: 6 4 | --- -------------------------------------------------------------------------------- /docs/docs/howto/configurations/neetbox-cli.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Neetbox CLI 3 | sidebar_position: 7 4 | --- -------------------------------------------------------------------------------- /docs/docs/howto/configurations/project-config.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Project config file 3 | sidebar_position: 8 4 | --- -------------------------------------------------------------------------------- /docs/docs/howto/configurations/server-config.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Configure neetbox server 3 | sidebar_position: 9 4 | --- -------------------------------------------------------------------------------- /docs/docs/howto/frontend-manual/index.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Using neetbox frontend 3 | sidebar_position: 4 4 | --- 5 | -------------------------------------------------------------------------------- /docs/docs/howto/imgs/example/screenshots/sc1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/visualDust/neetbox/38a44edd98fcd35097406fae7b5d3ade0ae43b4d/docs/docs/howto/imgs/example/screenshots/sc1.jpg -------------------------------------------------------------------------------- /docs/docs/howto/imgs/example/screenshots/sc2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/visualDust/neetbox/38a44edd98fcd35097406fae7b5d3ade0ae43b4d/docs/docs/howto/imgs/example/screenshots/sc2.jpg -------------------------------------------------------------------------------- /docs/docs/howto/imgs/index/screenshot.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/visualDust/neetbox/38a44edd98fcd35097406fae7b5d3ade0ae43b4d/docs/docs/howto/imgs/index/screenshot.jpg -------------------------------------------------------------------------------- /docs/docs/howto/python-apis/create-actions.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Remote function call via action 3 | sidebar_position: 9 4 | --- 5 | 6 | :::tip 7 | `neetbox.action` allows you to issue a remote function call in browser. Once you register an action, neetbox will create a button on web page and show function docs and input box for parameters. 8 | ::: 9 | 10 | ## How it looks like 11 | 12 | ![image-20231220185856173](./imgs/create-actions/image-20231220185856173.png) 13 | 14 | ## Basic Usage 15 | 16 | ```python 17 | import neetbox 18 | import os 19 | 20 | @neetbox.action(name="shutdown") 21 | def os_exit(): 22 | """ shutdown your process """ 23 | os._exit(0) 24 | 25 | while True: 26 | pass 27 | ``` 28 | 29 | Visit [localhost:20202](http://localhost:20202) and you should see a button which will run your function. 30 | 31 | ![image-20231220213534685](./imgs/create-actions/image-20231220213534685.png) 32 | 33 | Once you click the "Run" button, your python code should exit as you wish. 34 | 35 | ## API description 36 | 37 | `@neetbox.action` register function as action visiable on frontend page. 38 | ```python 39 | @neetbox.action(name: Optional[str] = None, description: str = None, blocking: bool = False) 40 | ``` 41 | Args: 42 | - name (Optional[str], optional): name of the action. Defaults to None(neetbox will use the function name when set to None). 43 | - description (str, optional): description of the action. Defaults to None(neetbox will use function docs as default when set to None). 44 | - blocking (bool, optional): whether to run the action in a blocked query. Defaults to False. 45 | -------------------------------------------------------------------------------- /docs/docs/howto/python-apis/imgs/add-hyperparams/image-20231220185559247.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/visualDust/neetbox/38a44edd98fcd35097406fae7b5d3ade0ae43b4d/docs/docs/howto/python-apis/imgs/add-hyperparams/image-20231220185559247.png -------------------------------------------------------------------------------- /docs/docs/howto/python-apis/imgs/add-hyperparams/image-20240101164602610.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/visualDust/neetbox/38a44edd98fcd35097406fae7b5d3ade0ae43b4d/docs/docs/howto/python-apis/imgs/add-hyperparams/image-20240101164602610.png -------------------------------------------------------------------------------- /docs/docs/howto/python-apis/imgs/create-actions/image-20231220185856173.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/visualDust/neetbox/38a44edd98fcd35097406fae7b5d3ade0ae43b4d/docs/docs/howto/python-apis/imgs/create-actions/image-20231220185856173.png -------------------------------------------------------------------------------- /docs/docs/howto/python-apis/imgs/create-actions/image-20231220213148577.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/visualDust/neetbox/38a44edd98fcd35097406fae7b5d3ade0ae43b4d/docs/docs/howto/python-apis/imgs/create-actions/image-20231220213148577.png -------------------------------------------------------------------------------- /docs/docs/howto/python-apis/imgs/create-actions/image-20231220213534685.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/visualDust/neetbox/38a44edd98fcd35097406fae7b5d3ade0ae43b4d/docs/docs/howto/python-apis/imgs/create-actions/image-20231220213534685.png -------------------------------------------------------------------------------- /docs/docs/howto/python-apis/imgs/post-figure-as-image/image-20231231224710154.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/visualDust/neetbox/38a44edd98fcd35097406fae7b5d3ade0ae43b4d/docs/docs/howto/python-apis/imgs/post-figure-as-image/image-20231231224710154.png -------------------------------------------------------------------------------- /docs/docs/howto/python-apis/imgs/post-figure-as-image/image-20240101133300078.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/visualDust/neetbox/38a44edd98fcd35097406fae7b5d3ade0ae43b4d/docs/docs/howto/python-apis/imgs/post-figure-as-image/image-20240101133300078.png -------------------------------------------------------------------------------- /docs/docs/howto/python-apis/imgs/post-images/image-20231220185948022.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/visualDust/neetbox/38a44edd98fcd35097406fae7b5d3ade0ae43b4d/docs/docs/howto/python-apis/imgs/post-images/image-20231220185948022.png -------------------------------------------------------------------------------- /docs/docs/howto/python-apis/imgs/post-images/image-20231220214452030.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/visualDust/neetbox/38a44edd98fcd35097406fae7b5d3ade0ae43b4d/docs/docs/howto/python-apis/imgs/post-images/image-20231220214452030.png -------------------------------------------------------------------------------- /docs/docs/howto/python-apis/imgs/post-tensors-as-image/image-20231220185959324.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/visualDust/neetbox/38a44edd98fcd35097406fae7b5d3ade0ae43b4d/docs/docs/howto/python-apis/imgs/post-tensors-as-image/image-20231220185959324.png -------------------------------------------------------------------------------- /docs/docs/howto/python-apis/imgs/post-tensors-as-image/image-20231220221623777.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/visualDust/neetbox/38a44edd98fcd35097406fae7b5d3ade0ae43b4d/docs/docs/howto/python-apis/imgs/post-tensors-as-image/image-20231220221623777.png -------------------------------------------------------------------------------- /docs/docs/howto/python-apis/imgs/remote-logging/image-20231220185614481.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/visualDust/neetbox/38a44edd98fcd35097406fae7b5d3ade0ae43b4d/docs/docs/howto/python-apis/imgs/remote-logging/image-20231220185614481.png -------------------------------------------------------------------------------- /docs/docs/howto/python-apis/imgs/remote-logging/image-20231220222626743.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/visualDust/neetbox/38a44edd98fcd35097406fae7b5d3ade0ae43b4d/docs/docs/howto/python-apis/imgs/remote-logging/image-20231220222626743.png -------------------------------------------------------------------------------- /docs/docs/howto/python-apis/imgs/remote-logging/image-20231220222633839.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/visualDust/neetbox/38a44edd98fcd35097406fae7b5d3ade0ae43b4d/docs/docs/howto/python-apis/imgs/remote-logging/image-20231220222633839.png -------------------------------------------------------------------------------- /docs/docs/howto/python-apis/imgs/show-line-chart/image-20231220190022639.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/visualDust/neetbox/38a44edd98fcd35097406fae7b5d3ade0ae43b4d/docs/docs/howto/python-apis/imgs/show-line-chart/image-20231220190022639.png -------------------------------------------------------------------------------- /docs/docs/howto/python-apis/imgs/show-line-chart/image-20231220225909377.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/visualDust/neetbox/38a44edd98fcd35097406fae7b5d3ade0ae43b4d/docs/docs/howto/python-apis/imgs/show-line-chart/image-20231220225909377.png -------------------------------------------------------------------------------- /docs/docs/howto/python-apis/imgs/show-line-chart/image-20231220230220345.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/visualDust/neetbox/38a44edd98fcd35097406fae7b5d3ade0ae43b4d/docs/docs/howto/python-apis/imgs/show-line-chart/image-20231220230220345.png -------------------------------------------------------------------------------- /docs/docs/howto/python-apis/imgs/show-progress/image-20231220185625943.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/visualDust/neetbox/38a44edd98fcd35097406fae7b5d3ade0ae43b4d/docs/docs/howto/python-apis/imgs/show-progress/image-20231220185625943.png -------------------------------------------------------------------------------- /docs/docs/howto/python-apis/imgs/show-progress/image-20231220224401847.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/visualDust/neetbox/38a44edd98fcd35097406fae7b5d3ade0ae43b4d/docs/docs/howto/python-apis/imgs/show-progress/image-20231220224401847.png -------------------------------------------------------------------------------- /docs/docs/howto/python-apis/imgs/show-progress/image-20231220224844130.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/visualDust/neetbox/38a44edd98fcd35097406fae7b5d3ade0ae43b4d/docs/docs/howto/python-apis/imgs/show-progress/image-20231220224844130.png -------------------------------------------------------------------------------- /docs/docs/howto/python-apis/imgs/transformer-trainer-callback/Snipaste_2025-04-25_15-51-53.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/visualDust/neetbox/38a44edd98fcd35097406fae7b5d3ade0ae43b4d/docs/docs/howto/python-apis/imgs/transformer-trainer-callback/Snipaste_2025-04-25_15-51-53.png -------------------------------------------------------------------------------- /docs/docs/howto/python-apis/imgs/transformer-trainer-callback/Snipaste_2025-04-25_15-52-27.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/visualDust/neetbox/38a44edd98fcd35097406fae7b5d3ade0ae43b4d/docs/docs/howto/python-apis/imgs/transformer-trainer-callback/Snipaste_2025-04-25_15-52-27.png -------------------------------------------------------------------------------- /docs/docs/howto/python-apis/index.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Python APIs 3 | sidebar_position: 3 4 | --- 5 | 6 | Neetbox provides a set of easy-to-use Python APIs to log and visualize your training process, Including: 7 | - [Logging](./remote-logging.mdx) 8 | - [Showing progress](./show-progress.mdx) 9 | - [Remote function execution](./create-actions.mdx) 10 | - [Show images](./post-images.mdx) 11 | - [Visualize tensors](./post-tensors-as-image.mdx) 12 | - [Show scalar charts](./show-line-chart.mdx) 13 | - [Show figures from matplotlib](./post-figure-as-image.mdx) 14 | - [Show hyperparameters](./show-hyperparams.mdx) 15 | 16 | Additionally, if you are using [huggingface transformers](https://huggingface.co/docs/transformers), you can use the [TransformersTrainerCallback](./transformers-trainer-callback.mdx) to log your training process automatically. -------------------------------------------------------------------------------- /docs/docs/howto/python-apis/post-figure-as-image.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Show figure as image 3 | sidebar_position: 8 4 | --- 5 | 6 | :::tip 7 | `neetbox.add_figure` allows you to send a pyplt figure as image and see it in browser. 8 | ::: 9 | 10 | ## How it looks like 11 | 12 | ![image-20231231224710154](./imgs/post-figure-as-image/image-20231231224710154.png) 13 | 14 | 15 | 16 | ## Basic Usage 17 | 18 | ```python 19 | import matplotlib.pyplot as plt 20 | import neetbox 21 | 22 | animal_names = ['Lion', 'Gazelle', 'Cheetah'] 23 | mph_speed = [50, 60, 75] 24 | 25 | fig, ax = plt.subplots() 26 | bar_container = ax.bar(animal_names, mph_speed) 27 | ax.set(ylabel='speed in MPH', title='Running speeds', ylim=(0, 80)) 28 | ax.bar_label(bar_container, fmt=lambda x: f'{x * 1.61:.1f} km/h') 29 | 30 | neetbox.add_figure(name="Number of penguins by sex", figure=plt.gcf()) 31 | ``` 32 | 33 | ![image-20240101133300078](./imgs/post-figure-as-image/image-20240101133300078.png) 34 | 35 | 36 | 37 | ## API description 38 | 39 | `neetbox.add_figure` render matplotlib figure into an image and add it to summary. Note that this requires the ``matplotlib`` package. 40 | 41 | ```python 42 | def add_figure(name: str, figure, close: Optional[bool] = True): 43 | ``` 44 | 45 | Args: 46 | 47 | - tag: Data identifier 48 | 49 | - figure (matplotlib.pyplot.figure) or list of figures: Figure or a list of figures 50 | - global_step: Global step value to record 51 | - close: Flag to automatically close the figure 52 | - walltime: Override default walltime (time.time()) of event 53 | -------------------------------------------------------------------------------- /docs/docs/howto/python-apis/post-images.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Show images 3 | sidebar_position: 6 4 | --- 5 | 6 | :::tip 7 | `neetbox.add_image` allows you to send a image and see it in browser. 8 | ::: 9 | 10 | ## How it looks like 11 | 12 | ![image-20231220185948022](./imgs/post-images/image-20231220185948022.png) 13 | 14 | ## Basic Usage 15 | 16 | ```python 17 | import neetbox 18 | import numpy as np 19 | from PIL import Image 20 | 21 | # generate a random noise image 22 | img = (np.random.rand(300,400,3) * 255).astype(np.uint8) 23 | img = Image.fromarray(img, mode="RGB") 24 | 25 | # send it to frontend 26 | neetbox.add_image(name="random noise", image=img) 27 | 28 | while True: 29 | pass 30 | ``` 31 | 32 | ![image-20231220214452030](./imgs/post-images/image-20231220214452030.png) 33 | 34 | ## API description 35 | 36 | `neetbox.add_image` send an image to frontend display. 37 | 38 | ```python 39 | def add_image(name: str, image, dataformats: str = None) 40 | ``` 41 | 42 | Args: 43 | 44 | - image (Union[np.array, Image.Image, Tensor]): image from cv2 and PIL.Image as well as tensors are supported 45 | - name (str): name of the image, used in frontend display 46 | - dataformats (str): if you are passing a tensor as image, please indicate how to understand the tensor. For example, dataformats="NCWH" means the first axis of the tensor is Number of batches, the second axis is Channel, and the third axis is Width, and the fourth axis is Height. 47 | -------------------------------------------------------------------------------- /docs/docs/howto/python-apis/post-tensors-as-image.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Show tensor as image 3 | sidebar_position: 7 4 | --- 5 | 6 | :::tip 7 | `neetbox.add_image` allows you to send a tensor as image and see it in browser. 8 | ::: 9 | 10 | ## How it looks like 11 | 12 | ![image-20231220185959324](./imgs/post-tensors-as-image/image-20231220185959324.png) 13 | 14 | 15 | 16 | ## Basic Usage 17 | 18 | ```python 19 | import neetbox 20 | import torch 21 | 22 | a = torch.zeros((300, 300)) 23 | a[:150, :150] = 1 24 | b = torch.zeros((300, 300)) 25 | b[150:, :150] = 2 26 | c = torch.zeros((300, 300)) 27 | c[150:, 150:] = 3 28 | t = torch.stack([a, b, c]) 29 | neetbox.add_image(name="as CWH", image=t, dataformats="CWH") 30 | neetbox.add_image(name="as NWH", image=t, dataformats="NWH") 31 | t = torch.stack([t, t, t]) 32 | neetbox.add_image(name="as NCWH", image=t, dataformats="NCWH") 33 | 34 | while True: 35 | pass 36 | 37 | ``` 38 | 39 | ![image-20231220221623777](./imgs/post-tensors-as-image/image-20231220221623777.png) 40 | 41 | :::tip 42 | 43 | As you can see above, `dataformats` controls how neetbox understand the tensor as an image. 44 | 45 | For example, `dataformats="NCWH"` means the first axis of the tensor is **N**umber of batches, the second axis is **C**hannel, and the third axis is **W**idth, and the fourth axis is **H**eight. 46 | 47 | Pass a string consists of 'N', 'C', 'H', 'W' and neetbox will understand your tensor. 48 | 49 | ::: 50 | 51 | ## API description 52 | 53 | `neetbox.add_image` send an image to frontend display. 54 | 55 | ```python 56 | def add_image(name: str, image, dataformats: str = None) 57 | ``` 58 | 59 | Args: 60 | 61 | - image (Union[np.array, Image.Image, Tensor]): image from cv2 and PIL.Image as well as tensors are supported 62 | - name (str): name of the image, used in frontend display 63 | - dataformats (str): if you are passing a tensor as image, please indicate how to understand the tensor. For example, dataformats="NCWH" means the first axis of the tensor is Number of batches, the second axis is Channel, and the third axis is Width, and the fourth axis is Height. 64 | -------------------------------------------------------------------------------- /docs/docs/howto/python-apis/remote-logging.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Show logs 3 | sidebar_position: 4 4 | --- 5 | 6 | :::tip 7 | `neetbox.logger` allows you to write logs into frontend, console, and log files. 8 | ::: 9 | 10 | ## How it looks like 11 | 12 | ![image-20231220185614481](./imgs/remote-logging/image-20231220185614481.png) 13 | 14 | ## Basic Usage 15 | 16 | ```python 17 | from neetbox import logger 18 | import time 19 | 20 | while True: 21 | time.sleep(1) 22 | logger.log("log from neetbox") 23 | logger.ok("ok from neetbox") 24 | logger.info("info from neetbox") 25 | logger.debug("debug from neetbox") 26 | logger.warn("warn from neetbox") 27 | logger.err("error from neetbox") 28 | ``` 29 | 30 | On frontend web page: 31 | 32 | ![image-20231220222626743](./imgs/remote-logging/image-20231220222626743.png) 33 | 34 | In console: 35 | 36 | ![image-20231220222633839](./imgs/remote-logging/image-20231220222633839.png) 37 | 38 | ## API Reference 39 | 40 | `neetbox.logger` write logs to frontend display, console, and log files. 41 | 42 | ```python 43 | def log( 44 | self, 45 | *content, 46 | prefix: Optional[str] = None, 47 | datetime_format: Optional[str] = None, 48 | with_identifier: Optional[bool] = None, 49 | with_datetime: Optional[bool] = None, 50 | skip_writers: list[str] = [], 51 | traceback=2, 52 | ) 53 | ``` 54 | 55 | Args: 56 | - prefix (Optional[str], optional): prefix shows at the start of console log while it shows as a tag on frontend. Defaults to None. 57 | - datetime_format (Optional[str], optional): change the format neetbox displays time. Defaults to None, neetbox will use default style ("%Y-%m-%dT%H:%M:%S.%f") if None is passed. 58 | - with_identifier (Optional[bool], optional): whether to show who is logging, note that this option has noting todo with traceback. Defaults to None(True). 59 | - with_datetime (Optional[bool], optional): whether to show datetime in logs. Defaults to None(True). 60 | - skip_writers (list[str], optional): writers to skip, possible writes are 'stdout'(write into console), 'file'(write into file), 'ws'(write to frontend). Defaults to [], which means write to all writers. 61 | - traceback (int, optional): level of traceback. Defaults to 2. Do not change this option unless you know what you are doing. 62 | -------------------------------------------------------------------------------- /docs/docs/howto/python-apis/show-hyperparams.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Show hyperparameters 3 | sidebar_position: 8 4 | --- 5 | 6 | :::tip 7 | `neetbox.add_hyperparams` allows you to show hyperparameters for each run. 8 | ::: 9 | 10 | ## How it looks like 11 | 12 | 13 | ![image-20231220185559247](./imgs/add-hyperparams/image-20231220185559247.png) 14 | 15 | ## Basic Usage 16 | 17 | ```python 18 | import neetbox 19 | import time 20 | 21 | configs = { 22 | "data_folder": "./data", 23 | "vocabulary": "./data/vocab.voc", 24 | "model": { 25 | "block_size": 128, 26 | "file": "./model.saved.pkl", 27 | "n_decoder": 8, 28 | "n_embed": 384, 29 | "n_head": 8, 30 | }, 31 | "test": {"eval_frequency": 100, "test_iter": 10, "test_prompt": "Hello! Can you see me?"}, 32 | "train": {"batch_size": 32, "learning_rate": 0.001, "max_iter": 3000, "resume": True}, 33 | } 34 | 35 | neetbox.add_hyperparams(configs) 36 | time.sleep(1) 37 | ``` 38 | 39 | ![image-20240101164602610](./imgs/add-hyperparams/image-20240101164602610.png) 40 | 41 | ## API description 42 | 43 | `neetbox.add_hyperparams` add hyperparams to current run, the added hyperparams will show in frontend. 44 | 45 | ```python 46 | def add_hyperparams(hparam: dict, name: str = None) 47 | ``` 48 | 49 | Args: 50 | 51 | - hparam (dict): hyperparams 52 | - name (str, optional): name of hyperparams. Defaults to None. 53 | -------------------------------------------------------------------------------- /docs/docs/howto/python-apis/show-line-chart.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Plot scalar line chart 3 | sidebar_position: 5 4 | --- 5 | 6 | :::tip 7 | `neetbox.add_scalar` sends a scalar to frontend display. 8 | ::: 9 | 10 | ## How it looks like 11 | 12 | ![image-20231220190022639](./imgs/show-line-chart/image-20231220190022639.png) 13 | 14 | ## Basic Usage 15 | 16 | ```python 17 | import neetbox 18 | import math 19 | import time 20 | 21 | for i in range(114514): 22 | time.sleep(1) 23 | neetbox.add_scalar("sin", i, math.sin(i * 0.1)) 24 | neetbox.add_scalar("cos", i, math.cos(i * 0.1)) 25 | 26 | ``` 27 | 28 | ![image-20231220225909377](./imgs/show-line-chart/image-20231220225909377.png) 29 | 30 | you can also zoom or magnify the chart in frontend: 31 | 32 | ![image-20231220230220345](./imgs/show-line-chart/image-20231220230220345.png) 33 | 34 | ## API description 35 | 36 | `neetbox.add_scalar` sends a scalar to frontend display. 37 | 38 | ```python 39 | def add_scalar(name: str, x: Union[int, float], y: Union[int, float]) 40 | ``` 41 | 42 | Args: 43 | 44 | - name (str): name of the image, used in frontend display 45 | - x (Union[int, float]): x 46 | - y (Union[int, float]): y 47 | -------------------------------------------------------------------------------- /docs/docs/howto/python-apis/show-progress.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Show a progress 3 | sidebar_position: 3 4 | --- 5 | 6 | :::tip 7 | `neetbox.progress` allows you to show progresses in neetbox frontend web page. 8 | ::: 9 | 10 | ## How it looks like 11 | 12 | ![image-20231220185625943](./imgs/show-progress/image-20231220185625943.png) 13 | 14 | ## Basic Usage 15 | 16 | ```python 17 | import neetbox 18 | from neetbox import logger 19 | from tqdm import tqdm 20 | import time 21 | 22 | def a(): 23 | logger.log("running a") 24 | def b(): 25 | logger.log("running b") 26 | def c(): 27 | logger.log("running c") 28 | def d(): 29 | logger.log("running d") 30 | def e(): 31 | logger.log("running e") 32 | 33 | with tqdm(neetbox.progress(50)) as progress: 34 | for _ in progress: 35 | for func in neetbox.progress([a, b, c, d, e]): 36 | func() 37 | time.sleep(1) 38 | 39 | ``` 40 | 41 | On frontend web page: 42 | 43 | ![image-20231220224401847](./imgs/show-progress/image-20231220224401847.png) 44 | 45 | In console: 46 | 47 | ![image-20231220224844130](./imgs/show-progress/image-20231220224844130.png) 48 | 49 | :::tip 50 | 51 | Since `neetbox.progress` decorates an iterable object and returns an iterator, you can use it as a normal iterator. For example. the following usages are legal: 52 | 53 | ```python 54 | for i in neetbox.progress(100): 55 | ... 56 | for func in neetbox.progress([fun1,fun2,fun3...]): 57 | ... 58 | with tqdm(neetbox.progress(how_long)) as progress: 59 | ... 60 | with neetbox.progress(tqdm(how_long)) as progress: 61 | ... 62 | ``` 63 | 64 | There are no additional restrictions on using `neetbox.progress`. 65 | 66 | ::: 67 | 68 | ## API description 69 | 70 | `neetbox.progress` decorates an iterable object, returning an iterator. Neetbox will send progress to frontend while you are iterating through it. 71 | 72 | ```python 73 | class Progress: 74 | def __init__(self, input: Union[int, enumerate, any]) 75 | ``` 76 | 77 | Args: 78 | 79 | - input (Union[int, enumerate, any]): Something to iterate or something to create enumeratable object. 80 | -------------------------------------------------------------------------------- /docs/docs/howto/server-hosting/index.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Hosting neetbox server 3 | sidebar_position: 5 4 | --- 5 | 6 | # Neetbox server hosting 7 | 8 | Neetbox server app can be launched solely via neetbox command line interface (CLI). 9 | 10 | 11 | -------------------------------------------------------------------------------- /docs/docs/howto/server-hosting/manage-history-files.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Manage history data 3 | sidebar_position: 7 4 | --- 5 | 6 | ## History file location 7 | -------------------------------------------------------------------------------- /docs/docs/howto/server-hosting/run-neetbox-server.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Run neetbox server 3 | sidebar_position: 6 4 | --- 5 | 6 | -------------------------------------------------------------------------------- /docs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "neetbox-doc", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "docusaurus": "docusaurus", 7 | "start": "docusaurus start", 8 | "build": "docusaurus build", 9 | "swizzle": "docusaurus swizzle", 10 | "deploy": "docusaurus deploy", 11 | "clear": "docusaurus clear", 12 | "serve": "docusaurus serve", 13 | "write-translations": "docusaurus write-translations", 14 | "write-heading-ids": "docusaurus write-heading-ids", 15 | "typecheck": "tsc" 16 | }, 17 | "dependencies": { 18 | "@docusaurus/core": "^3.0.1", 19 | "@docusaurus/preset-classic": "^3.0.1", 20 | "@mdx-js/react": "^3.0.0", 21 | "clsx": "^2.0.0", 22 | "prism-react-renderer": "^2.1.0", 23 | "react": "^18.2.0", 24 | "react-dom": "^18.2.0", 25 | "react-responsive-carousel": "^3.2.23" 26 | }, 27 | "devDependencies": { 28 | "@docusaurus/module-type-aliases": "^3.0.1", 29 | "@docusaurus/types": "3.5.2", 30 | "@tsconfig/docusaurus": "^2.0.0", 31 | "typescript": "^4.7.4" 32 | }, 33 | "browserslist": { 34 | "production": [ 35 | ">0.5%", 36 | "not dead", 37 | "not op_mini all" 38 | ], 39 | "development": [ 40 | "last 1 chrome version", 41 | "last 1 firefox version", 42 | "last 1 safari version" 43 | ] 44 | }, 45 | "engines": { 46 | "node": ">=18.0" 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /docs/sidebars.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Creating a sidebar enables you to: 3 | - create an ordered group of docs 4 | - render a sidebar for each doc of that group 5 | - provide next/previous navigation 6 | 7 | The sidebars can be generated from the filesystem, or explicitly defined here. 8 | 9 | Create as many sidebars as you want. 10 | */ 11 | 12 | // @ts-check 13 | 14 | /** @type {import('@docusaurus/plugin-content-docs').SidebarsConfig} */ 15 | const sidebars = { 16 | tutorialSidebar: [ 17 | { 18 | type: "autogenerated", 19 | dirName: "howto", 20 | }, 21 | ], 22 | documentation: [ 23 | { 24 | type: "autogenerated", 25 | dirName: "apidocs", 26 | }, 27 | ], 28 | }; 29 | 30 | module.exports = sidebars; 31 | -------------------------------------------------------------------------------- /docs/src/components/ExamplesCards.tsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/visualDust/neetbox/38a44edd98fcd35097406fae7b5d3ade0ae43b4d/docs/src/components/ExamplesCards.tsx -------------------------------------------------------------------------------- /docs/src/components/features.module.css: -------------------------------------------------------------------------------- 1 | .features { 2 | display: flex; 3 | align-items: center; 4 | padding: 2rem 0; 5 | width: 100%; 6 | } 7 | 8 | .feature-card { 9 | background-color: var(--ifm-color-emphasis-100); 10 | box-shadow: rgba(0, 0, 0, 0.05) 0px 0px 0px 1px; 11 | border-radius: 10px; 12 | } 13 | 14 | html[data-theme="dark"] .feature-card { 15 | box-shadow: rgba(0, 0, 0, 0.05) 0px 6px 24px 0px, 16 | rgba(0, 0, 0, 0.08) 0px 0px 0px 1px; 17 | } 18 | -------------------------------------------------------------------------------- /docs/src/css/custom.css: -------------------------------------------------------------------------------- 1 | /** 2 | * Any CSS included here will be global. The classic template 3 | * bundles Infima by default. Infima is a CSS framework designed to 4 | * work well for content-centric websites. 5 | */ 6 | 7 | /* You can override the default Infima variables here. */ 8 | :root { 9 | --ifm-color-primary: #4957b8; 10 | --ifm-link-color: #537990; 11 | --ifm-color-primary-dark: #707070; 12 | --ifm-color-primary-darker: #636363; 13 | --ifm-color-primary-darkest: #5a5a5a; 14 | --ifm-color-primary-light: #8c8c8c; 15 | --ifm-color-primary-lighter: #9c9c9c; 16 | --ifm-color-primary-lightest: #a7a8a8; 17 | --ifm-code-font-size: 95%; 18 | --docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.1); 19 | } 20 | 21 | /* For readability concerns, you should choose a lighter palette in dark mode. */ 22 | [data-theme='dark'] { 23 | --ifm-color-primary: #fd9f83; 24 | --ifm-link-color: #f7a8b5; 25 | --ifm-color-primary-dark: #a3a3a3; 26 | --ifm-color-primary-darker: #a1a1a1; 27 | --ifm-color-primary-darkest: #7c7c7c; 28 | --ifm-color-primary-light: #d3d3d3; 29 | --ifm-color-primary-lighter: #d0d0d0; 30 | --ifm-color-primary-lightest: #dfdfdf; 31 | --docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.3); 32 | } 33 | -------------------------------------------------------------------------------- /docs/src/hooks/useIsMobile.tsx: -------------------------------------------------------------------------------- 1 | import { useState, useEffect, useLayoutEffect } from "react"; 2 | 3 | function useIsMobile(maxWidth = 1000) { 4 | const [mobile, setMobile] = useState(false); 5 | 6 | function handleWindowSizeChange() { 7 | setMobile(matchMedia(`(max-width: ${maxWidth}px)`).matches); 8 | } 9 | useLayoutEffect(() => { 10 | handleWindowSizeChange(); 11 | window.addEventListener('resize', handleWindowSizeChange); 12 | return () => { 13 | window.removeEventListener('resize', handleWindowSizeChange); 14 | } 15 | }, []); 16 | 17 | return mobile; 18 | } 19 | 20 | export default useIsMobile; -------------------------------------------------------------------------------- /docs/src/pages/index.module.css: -------------------------------------------------------------------------------- 1 | /** 2 | * CSS files with the .module.css suffix will be treated as CSS modules 3 | * and scoped locally. 4 | */ 5 | 6 | html { 7 | scroll-behavior: smooth; 8 | } 9 | 10 | .heroBanner { 11 | padding: 4rem 0; 12 | text-align: center; 13 | position: relative; 14 | overflow: hidden; 15 | } 16 | 17 | @media screen and (max-width: 996px) { 18 | .heroBanner { 19 | padding: 2rem; 20 | } 21 | } 22 | 23 | .buttons { 24 | display: flex; 25 | align-items: center; 26 | justify-content: center; 27 | } 28 | -------------------------------------------------------------------------------- /docs/static/.nojekyll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/visualDust/neetbox/38a44edd98fcd35097406fae7b5d3ade0ae43b4d/docs/static/.nojekyll -------------------------------------------------------------------------------- /docs/static/googleabbb73ffe1f1dea8.html: -------------------------------------------------------------------------------- 1 | google-site-verification: googleabbb73ffe1f1dea8.html 2 | -------------------------------------------------------------------------------- /docs/static/img/docusaurus-social-card.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/visualDust/neetbox/38a44edd98fcd35097406fae7b5d3ade0ae43b4d/docs/static/img/docusaurus-social-card.png -------------------------------------------------------------------------------- /docs/static/img/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/visualDust/neetbox/38a44edd98fcd35097406fae7b5d3ade0ae43b4d/docs/static/img/favicon.png -------------------------------------------------------------------------------- /docs/static/img/github-mark.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/static/img/index/add-scalars.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/visualDust/neetbox/38a44edd98fcd35097406fae7b5d3ade0ae43b4d/docs/static/img/index/add-scalars.jpg -------------------------------------------------------------------------------- /docs/static/img/index/background-dark.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/visualDust/neetbox/38a44edd98fcd35097406fae7b5d3ade0ae43b4d/docs/static/img/index/background-dark.jpg -------------------------------------------------------------------------------- /docs/static/img/index/background-light.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/visualDust/neetbox/38a44edd98fcd35097406fae7b5d3ade0ae43b4d/docs/static/img/index/background-light.jpg -------------------------------------------------------------------------------- /docs/static/img/index/distinguish-runs.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/visualDust/neetbox/38a44edd98fcd35097406fae7b5d3ade0ae43b4d/docs/static/img/index/distinguish-runs.jpg -------------------------------------------------------------------------------- /docs/static/img/index/monit-hardware.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/visualDust/neetbox/38a44edd98fcd35097406fae7b5d3ade0ae43b4d/docs/static/img/index/monit-hardware.jpg -------------------------------------------------------------------------------- /docs/static/img/index/monit-machines-on-local-network.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/visualDust/neetbox/38a44edd98fcd35097406fae7b5d3ade0ae43b4d/docs/static/img/index/monit-machines-on-local-network.png -------------------------------------------------------------------------------- /docs/static/img/index/monit-machines-online.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/visualDust/neetbox/38a44edd98fcd35097406fae7b5d3ade0ae43b4d/docs/static/img/index/monit-machines-online.png -------------------------------------------------------------------------------- /docs/static/img/index/monit-multiple-projects.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/visualDust/neetbox/38a44edd98fcd35097406fae7b5d3ade0ae43b4d/docs/static/img/index/monit-multiple-projects.jpg -------------------------------------------------------------------------------- /docs/static/img/index/monit-one-machine.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/visualDust/neetbox/38a44edd98fcd35097406fae7b5d3ade0ae43b4d/docs/static/img/index/monit-one-machine.png -------------------------------------------------------------------------------- /docs/static/img/index/neetbox-consistof.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/visualDust/neetbox/38a44edd98fcd35097406fae7b5d3ade0ae43b4d/docs/static/img/index/neetbox-consistof.jpg -------------------------------------------------------------------------------- /docs/static/img/index/notify-errors.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/visualDust/neetbox/38a44edd98fcd35097406fae7b5d3ade0ae43b4d/docs/static/img/index/notify-errors.jpg -------------------------------------------------------------------------------- /docs/static/img/index/simple-apis.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/visualDust/neetbox/38a44edd98fcd35097406fae7b5d3ade0ae43b4d/docs/static/img/index/simple-apis.jpg -------------------------------------------------------------------------------- /docs/static/img/index/support-different-data.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/visualDust/neetbox/38a44edd98fcd35097406fae7b5d3ade0ae43b4d/docs/static/img/index/support-different-data.jpg -------------------------------------------------------------------------------- /docs/static/img/index/use-actions.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/visualDust/neetbox/38a44edd98fcd35097406fae7b5d3ade0ae43b4d/docs/static/img/index/use-actions.jpg -------------------------------------------------------------------------------- /docs/static/img/index/view-everywhere.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/visualDust/neetbox/38a44edd98fcd35097406fae7b5d3ade0ae43b4d/docs/static/img/index/view-everywhere.jpg -------------------------------------------------------------------------------- /docs/static/img/logo.old.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /docs/static/screenshots/sc1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/visualDust/neetbox/38a44edd98fcd35097406fae7b5d3ade0ae43b4d/docs/static/screenshots/sc1.jpg -------------------------------------------------------------------------------- /docs/static/screenshots/sc2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/visualDust/neetbox/38a44edd98fcd35097406fae7b5d3ade0ae43b4d/docs/static/screenshots/sc2.jpg -------------------------------------------------------------------------------- /docs/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | // This file is not used in compilation. It is here just for a nice editor experience. 3 | "extends": "@tsconfig/docusaurus/tsconfig.json", 4 | "compilerOptions": { 5 | "baseUrl": ".", 6 | "paths": { 7 | "react": ["./node_modules/@types/react"] 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /frontend/.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | env: { browser: true, es2020: true }, 4 | extends: [ 5 | "eslint:recommended", 6 | "plugin:@typescript-eslint/recommended", 7 | "plugin:react-hooks/recommended", 8 | "plugin:import/recommended", 9 | "plugin:import/typescript", 10 | ], 11 | ignorePatterns: ["dist", ".eslintrc.cjs", "cypress"], 12 | parser: "@typescript-eslint/parser", 13 | plugins: ["react-refresh"], 14 | rules: { 15 | "react-refresh/only-export-components": ["warn", { allowConstantExport: true }], 16 | "import/order": "warn", 17 | "@typescript-eslint/no-explicit-any": "off", 18 | "@typescript-eslint/no-unused-vars": "warn", 19 | }, 20 | }; 21 | -------------------------------------------------------------------------------- /frontend/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | *.log 3 | npm-debug.log* 4 | yarn-debug.log* 5 | yarn-error.log* 6 | pnpm-debug.log* 7 | lerna-debug.log* 8 | !/src/components/project/logs 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | 26 | # yarn: https://yarnpkg.com/getting-started/qa 27 | .pnp.* 28 | .yarn/* 29 | !.yarn/patches 30 | !.yarn/plugins 31 | !.yarn/releases 32 | !.yarn/sdks 33 | !.yarn/versions 34 | 35 | /cypress/videos/ 36 | /cypress/screenshots/ 37 | -------------------------------------------------------------------------------- /frontend/.yarnrc.yml: -------------------------------------------------------------------------------- 1 | nodeLinker: node-modules 2 | 3 | yarnPath: .yarn/releases/yarn-4.9.2.cjs 4 | -------------------------------------------------------------------------------- /frontend/README.md: -------------------------------------------------------------------------------- 1 | # Neetbox Frontend 2 | 3 | ## Dev 4 | 5 | ```shell 6 | yarn # install dev deps 7 | yarn dev 8 | ``` 9 | 10 | It uses `http://127.0.0.1:10101` as backend server. See `vite.config.ts` to change. 11 | 12 | ## Build 13 | 14 | ``` 15 | yarn build 16 | ``` 17 | -------------------------------------------------------------------------------- /frontend/cypress.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "cypress"; 2 | 3 | const isCI = process.env.CI == "true"; 4 | 5 | export default defineConfig({ 6 | viewportHeight: 1000, 7 | viewportWidth: 1600, 8 | scrollBehavior: "center", 9 | video: true, 10 | videoCompression: 28, 11 | e2e: { 12 | baseUrl: isCI ? "http://localhost:10101" : "http://localhost:5173", 13 | testIsolation: false, 14 | }, 15 | setupNodeEvents(on, _config) { 16 | on("before:browser:launch", (browser, launchOptions) => { 17 | if (browser.name === "electron" && browser.isHeadless) { 18 | launchOptions.preferences.width = 1920; 19 | launchOptions.preferences.height = 1080; 20 | } 21 | 22 | return launchOptions; 23 | }); 24 | }, 25 | }); 26 | -------------------------------------------------------------------------------- /frontend/cypress/support/commands.ts: -------------------------------------------------------------------------------- 1 | /// 2 | // *********************************************** 3 | // This example commands.ts shows you how to 4 | // create various custom commands and overwrite 5 | // existing commands. 6 | // 7 | // For more comprehensive examples of custom 8 | // commands please read more here: 9 | // https://on.cypress.io/custom-commands 10 | // *********************************************** 11 | // 12 | // 13 | // -- This is a parent command -- 14 | // Cypress.Commands.add('login', (email, password) => { ... }) 15 | // 16 | // 17 | // -- This is a child command -- 18 | // Cypress.Commands.add('drag', { prevSubject: 'element'}, (subject, options) => { ... }) 19 | // 20 | // 21 | // -- This is a dual command -- 22 | // Cypress.Commands.add('dismiss', { prevSubject: 'optional'}, (subject, options) => { ... }) 23 | // 24 | // 25 | // -- This will overwrite an existing command -- 26 | // Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... }) 27 | // 28 | // declare global { 29 | // namespace Cypress { 30 | // interface Chainable { 31 | // login(email: string, password: string): Chainable 32 | // drag(subject: string, options?: Partial): Chainable 33 | // dismiss(subject: string, options?: Partial): Chainable 34 | // visit(originalFn: CommandOriginalFn, url: string, options: Partial): Chainable 35 | // } 36 | // } 37 | // } 38 | -------------------------------------------------------------------------------- /frontend/cypress/support/e2e.ts: -------------------------------------------------------------------------------- 1 | // *********************************************************** 2 | // This example support/e2e.ts is processed and 3 | // loaded automatically before your test files. 4 | // 5 | // This is a great place to put global configuration and 6 | // behavior that modifies Cypress. 7 | // 8 | // You can change the location of this file or turn off 9 | // automatically serving support files with the 10 | // 'supportFile' configuration option. 11 | // 12 | // You can read more here: 13 | // https://on.cypress.io/configuration 14 | // *********************************************************** 15 | 16 | // Import commands.js using ES2015 syntax: 17 | import "./commands"; 18 | 19 | // Alternatively you can use CommonJS syntax: 20 | // require('./commands') 21 | -------------------------------------------------------------------------------- /frontend/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | NEETBOX 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /frontend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "neetcenter", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev:vite": "vite dev", 8 | "dev": "rsbuild dev", 9 | "build:vite": "vite build", 10 | "build": "rsbuild build", 11 | "tsc": "tsc", 12 | "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 20", 13 | "preview": "vite preview", 14 | "prettier-check": "prettier -c . !.yarn", 15 | "prettier": "prettier -w . !.yarn", 16 | "e2e": "cypress run --headed", 17 | "e2e:ci": "cypress run" 18 | }, 19 | "dependencies": { 20 | "@douyinfe/semi-icons": "^2.78.0", 21 | "@douyinfe/semi-ui": "^2.78.0", 22 | "@semi-bot/semi-theme-neetbox": "^1.0.7", 23 | "@uiw/react-json-view": "^2.0.0-alpha.30", 24 | "@uiw/react-md-editor": "^4.0.5", 25 | "echarts": "^5.6.0", 26 | "jotai": "^2.12.2", 27 | "katex": "^0.16.21", 28 | "mermaid": "^11.6.0", 29 | "nanoid": "^5.1.5", 30 | "react": "^18.3.1", 31 | "react-dom": "^18.3.1", 32 | "react-router-dom": "^6.30.0", 33 | "rehype-katex": "^7.0.1", 34 | "remark-gfm": "^4.0.1", 35 | "remark-math": "^6.0.0", 36 | "styled-components": "^6.1.16", 37 | "swr": "^2.3.3", 38 | "vite-plugin-semi-theme": "^0.6.0" 39 | }, 40 | "devDependencies": { 41 | "@douyinfe/semi-rspack-plugin": "^2.78.0", 42 | "@rsbuild/core": "^0.5.9", 43 | "@rsbuild/plugin-react": "^0.1.9", 44 | "@types/react": "^18.3.20", 45 | "@types/react-dom": "^18.3.5", 46 | "@typescript-eslint/eslint-plugin": "^6.21.0", 47 | "@typescript-eslint/parser": "^6.21.0", 48 | "@vitejs/plugin-react": "^4.3.4", 49 | "cypress": "^13.17.0", 50 | "eslint": "^8.57.1", 51 | "eslint-import-resolver-typescript": "^3.9.1", 52 | "eslint-plugin-import": "^2.31.0", 53 | "eslint-plugin-react-hooks": "^5.2.0", 54 | "eslint-plugin-react-refresh": "^0.4.19", 55 | "prettier": "^3.5.3", 56 | "typescript": "^5.8.2", 57 | "vite": "^6.3.4" 58 | }, 59 | "prettier": { 60 | "trailingComma": "all", 61 | "printWidth": 110 62 | }, 63 | "packageManager": "yarn@4.5.0" 64 | } 65 | -------------------------------------------------------------------------------- /frontend/public/fonts/maple/MapleMono-Bold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/visualDust/neetbox/38a44edd98fcd35097406fae7b5d3ade0ae43b4d/frontend/public/fonts/maple/MapleMono-Bold.woff2 -------------------------------------------------------------------------------- /frontend/public/fonts/maple/MapleMono-BoldItalic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/visualDust/neetbox/38a44edd98fcd35097406fae7b5d3ade0ae43b4d/frontend/public/fonts/maple/MapleMono-BoldItalic.woff2 -------------------------------------------------------------------------------- /frontend/public/fonts/maple/MapleMono-ExtraBold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/visualDust/neetbox/38a44edd98fcd35097406fae7b5d3ade0ae43b4d/frontend/public/fonts/maple/MapleMono-ExtraBold.woff2 -------------------------------------------------------------------------------- /frontend/public/fonts/maple/MapleMono-ExtraBoldItalic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/visualDust/neetbox/38a44edd98fcd35097406fae7b5d3ade0ae43b4d/frontend/public/fonts/maple/MapleMono-ExtraBoldItalic.woff2 -------------------------------------------------------------------------------- /frontend/public/fonts/maple/MapleMono-ExtraLight.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/visualDust/neetbox/38a44edd98fcd35097406fae7b5d3ade0ae43b4d/frontend/public/fonts/maple/MapleMono-ExtraLight.woff2 -------------------------------------------------------------------------------- /frontend/public/fonts/maple/MapleMono-ExtraLightItalic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/visualDust/neetbox/38a44edd98fcd35097406fae7b5d3ade0ae43b4d/frontend/public/fonts/maple/MapleMono-ExtraLightItalic.woff2 -------------------------------------------------------------------------------- /frontend/public/fonts/maple/MapleMono-Italic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/visualDust/neetbox/38a44edd98fcd35097406fae7b5d3ade0ae43b4d/frontend/public/fonts/maple/MapleMono-Italic.woff2 -------------------------------------------------------------------------------- /frontend/public/fonts/maple/MapleMono-Light.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/visualDust/neetbox/38a44edd98fcd35097406fae7b5d3ade0ae43b4d/frontend/public/fonts/maple/MapleMono-Light.woff2 -------------------------------------------------------------------------------- /frontend/public/fonts/maple/MapleMono-LightItalic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/visualDust/neetbox/38a44edd98fcd35097406fae7b5d3ade0ae43b4d/frontend/public/fonts/maple/MapleMono-LightItalic.woff2 -------------------------------------------------------------------------------- /frontend/public/fonts/maple/MapleMono-Medium.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/visualDust/neetbox/38a44edd98fcd35097406fae7b5d3ade0ae43b4d/frontend/public/fonts/maple/MapleMono-Medium.woff2 -------------------------------------------------------------------------------- /frontend/public/fonts/maple/MapleMono-MediumItalic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/visualDust/neetbox/38a44edd98fcd35097406fae7b5d3ade0ae43b4d/frontend/public/fonts/maple/MapleMono-MediumItalic.woff2 -------------------------------------------------------------------------------- /frontend/public/fonts/maple/MapleMono-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/visualDust/neetbox/38a44edd98fcd35097406fae7b5d3ade0ae43b4d/frontend/public/fonts/maple/MapleMono-Regular.woff2 -------------------------------------------------------------------------------- /frontend/public/fonts/maple/MapleMono-SemiBold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/visualDust/neetbox/38a44edd98fcd35097406fae7b5d3ade0ae43b4d/frontend/public/fonts/maple/MapleMono-SemiBold.woff2 -------------------------------------------------------------------------------- /frontend/public/fonts/maple/MapleMono-SemiBoldItalic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/visualDust/neetbox/38a44edd98fcd35097406fae7b5d3ade0ae43b4d/frontend/public/fonts/maple/MapleMono-SemiBoldItalic.woff2 -------------------------------------------------------------------------------- /frontend/public/fonts/maple/MapleMono-Thin.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/visualDust/neetbox/38a44edd98fcd35097406fae7b5d3ade0ae43b4d/frontend/public/fonts/maple/MapleMono-Thin.woff2 -------------------------------------------------------------------------------- /frontend/public/fonts/maple/MapleMono-ThinItalic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/visualDust/neetbox/38a44edd98fcd35097406fae7b5d3ade0ae43b4d/frontend/public/fonts/maple/MapleMono-ThinItalic.woff2 -------------------------------------------------------------------------------- /frontend/public/logo.old.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /frontend/rsbuild.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "@rsbuild/core"; 2 | import { pluginReact } from "@rsbuild/plugin-react"; 3 | import { SemiRspackPlugin } from "@douyinfe/semi-rspack-plugin"; 4 | 5 | const server = new URL("http://127.0.0.1:20202"); 6 | 7 | export default defineConfig({ 8 | plugins: [pluginReact()], 9 | source: { 10 | alias: { 11 | "@": "./src", 12 | }, 13 | entry: { index: "./src/main.tsx" }, 14 | }, 15 | tools: { 16 | rspack: (config) => { 17 | config.plugins!.push( 18 | new SemiRspackPlugin({ 19 | theme: "@semi-bot/semi-theme-neetbox", 20 | }), 21 | ); 22 | // config.optimization = { ...config.optimization, minimize: false }; 23 | config.module = { 24 | ...config.module, 25 | rules: [ 26 | ...(config.module?.rules ?? []), 27 | { 28 | test: /echarts/, 29 | sideEffects: true, 30 | }, 31 | ], 32 | }; 33 | }, 34 | }, 35 | html: { 36 | title: "NEETBOX", 37 | favicon: "./public/logo.svg", 38 | }, 39 | performance: { 40 | chunkSplit: { strategy: "all-in-one" }, 41 | }, 42 | server: { 43 | port: 5173, 44 | proxy: { 45 | "/api/": { 46 | target: server.href, 47 | }, 48 | "/ws/project/": { 49 | target: `ws://${server.host}`, 50 | }, 51 | }, 52 | }, 53 | // dev: { 54 | // writeToDisk: true, 55 | // }, 56 | output: { 57 | assetPrefix: "/web/", 58 | distPath: { 59 | root: "../neetbox/frontend_dist", 60 | }, 61 | }, 62 | }); 63 | -------------------------------------------------------------------------------- /frontend/src/App.tsx: -------------------------------------------------------------------------------- 1 | import { Layout } from "@douyinfe/semi-ui"; 2 | import { Outlet } from "react-router-dom"; 3 | import { useReportGlobalError } from "./hooks/useReportError"; 4 | import AppHeader from "./components/layout/AppHeader"; 5 | import "./styles/global.css"; 6 | 7 | export default function App() { 8 | useReportGlobalError(); 9 | return ( 10 | 11 | 12 | 13 | 14 | 15 | 16 | ); 17 | } 18 | -------------------------------------------------------------------------------- /frontend/src/components/appTitle.tsx: -------------------------------------------------------------------------------- 1 | import { atom, useAtom } from "jotai"; 2 | import { PropsWithChildren, ReactNode, useEffect } from "react"; 3 | 4 | const appTitle = atom([{ title: "" }] as Array<{ title: ReactNode; extra?: ReactNode }>); 5 | 6 | export const useTitle = () => useAtom(appTitle)[0].at(-1)!; 7 | 8 | export const AppTitle = (props: PropsWithChildren<{ extra?: ReactNode }>) => { 9 | const [_, setTitle] = useAtom(appTitle); 10 | useEffect(() => { 11 | setTitle((arr) => [...arr, { title: props.children, extra: props.extra }]); 12 | return () => setTitle((arr) => arr.slice(0, -1)); 13 | }, [props.children, props.extra, setTitle]); 14 | return null; 15 | }; 16 | -------------------------------------------------------------------------------- /frontend/src/components/common/centerBox.tsx: -------------------------------------------------------------------------------- 1 | import { CSSProperties, PropsWithChildren } from "react"; 2 | 3 | export const CenterBox = (props: PropsWithChildren<{ style?: CSSProperties }>) => { 4 | return ( 5 |
6 | {props.children} 7 |
8 | ); 9 | }; 10 | -------------------------------------------------------------------------------- /frontend/src/components/common/errorBoundary.tsx: -------------------------------------------------------------------------------- 1 | import React, { ReactNode } from "react"; 2 | import { useRouteError } from "react-router"; 3 | 4 | export const RouteError = () => { 5 | const routeError = useRouteError() as { error: Error }; 6 | const error = routeError?.error ?? routeError; 7 | const text = `RouteError\n\n${error}\n\n${error?.stack}`; 8 | return
{text}
; 9 | }; 10 | 11 | export class ErrorBoundary extends React.Component< 12 | React.PropsWithChildren<{ renderError?: (error: Error, errorInfo: React.ErrorInfo) => ReactNode }> 13 | > { 14 | state: { error?: Error; errorInfo?: React.ErrorInfo } = {}; 15 | 16 | componentDidCatch(error: Error, errorInfo: React.ErrorInfo): void { 17 | this.setState({ error, errorInfo }); 18 | } 19 | render(): React.ReactNode { 20 | return this.state.error 21 | ? (this.props.renderError?.(this.state.error, this.state.errorInfo!) ?? this.renderDefaultErrorPage()) 22 | : this.props.children; 23 | } 24 | 25 | renderDefaultErrorPage() { 26 | console.info(this.state); 27 | const text = `${this.state.error}\n\n${(this.state.error as Error)?.stack}\n\n${ 28 | this.state.errorInfo?.componentStack 29 | }`; 30 | return
{text}
; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /frontend/src/components/common/loading.tsx: -------------------------------------------------------------------------------- 1 | import { Space, Spin } from "@douyinfe/semi-ui"; 2 | import { SpinSize } from "@douyinfe/semi-ui/lib/es/spin"; 3 | import { ReactNode } from "react"; 4 | 5 | export default function Loading({ 6 | width = "", 7 | height = "100px", 8 | size = "middle", 9 | text, 10 | vertical, 11 | }: { 12 | width?: string; 13 | height?: string; 14 | size?: SpinSize; 15 | text?: ReactNode; 16 | vertical?: boolean; 17 | }) { 18 | return ( 19 |
28 | {text ? ( 29 | 30 | 31 | {text} 32 | 33 | ) : ( 34 | 35 | )} 36 |
37 | ); 38 | } 39 | -------------------------------------------------------------------------------- /frontend/src/components/common/propCard.tsx: -------------------------------------------------------------------------------- 1 | import { Button, Card, Toast, Typography } from "@douyinfe/semi-ui"; 2 | import { IconCopy } from "@douyinfe/semi-icons"; 3 | import React, { memo } from "react"; 4 | 5 | export const PropCard = memo(({ propName, propValue }: { propName: string; propValue }) => { 6 | const { Text } = Typography; 7 | const content = Array.isArray(propValue) ? propValue.join(" ") : propValue; 8 | return ( 9 | } 26 | style={{ marginRight: 10 }} 27 | size="small" 28 | onClick={() => { 29 | navigator.clipboard.writeText(content).then( 30 | () => { 31 | Toast.info("Copied to clipboard"); 32 | }, 33 | () => { 34 | Toast.error("Failed to copy"); 35 | }, 36 | ); 37 | }} 38 | > 39 | } 40 | > 41 | {content} 42 | 43 | ); 44 | }); 45 | -------------------------------------------------------------------------------- /frontend/src/components/common/sectionTitle.tsx: -------------------------------------------------------------------------------- 1 | import { Typography } from "@douyinfe/semi-ui"; 2 | import { ReactNode } from "react"; 3 | 4 | interface Props { 5 | title: ReactNode; 6 | } 7 | 8 | export function SectionTitle(props: Props) { 9 | return ( 10 |
11 | 12 | {props.title} 13 | 14 |
15 | ); 16 | } 17 | -------------------------------------------------------------------------------- /frontend/src/components/layout/AppFooter.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { Divider, Layout, Typography } from "@douyinfe/semi-ui"; 3 | import Logo from "../logo"; 4 | 5 | export default function AppFooter(): React.JSX.Element { 6 | return ( 7 | 17 | 18 | 19 | 20 | © 2023 - {new Date().getFullYear()} Neet Design. All rights reserved. 21 | 22 | 23 | ); 24 | } 25 | -------------------------------------------------------------------------------- /frontend/src/components/layout/AppHeader.tsx: -------------------------------------------------------------------------------- 1 | import { Typography, Space, Button, Layout } from "@douyinfe/semi-ui"; 2 | import { Link } from "react-router-dom"; 3 | import SwitchColorMode from "../themeSwitcher"; 4 | import { useTitle } from "../appTitle"; 5 | 6 | export default function AppHeader() { 7 | const { title, extra } = useTitle(); 8 | return ( 9 | 18 |
19 | 20 | NEETBOX 21 |
22 | {title} 23 | {extra} 24 |
25 | 26 | 27 | 28 | 31 | 32 | 33 |
34 |
35 | ); 36 | } 37 | -------------------------------------------------------------------------------- /frontend/src/components/layout/ConsoleLayout.tsx: -------------------------------------------------------------------------------- 1 | import { Layout } from "@douyinfe/semi-ui"; 2 | import { Outlet } from "react-router-dom"; 3 | import ConsoleNavBar from "../../pages/console/sidebar"; 4 | import { ErrorBoundary } from "../common/errorBoundary"; 5 | import AppFooter from "./AppFooter"; 6 | 7 | export default function ConsoleLayout() { 8 | const { Sider, Content } = Layout; 9 | return ( 10 | 11 | 12 | 13 | 14 | 15 | 16 | 25 | 26 | 27 | 28 | 29 | ); 30 | } 31 | -------------------------------------------------------------------------------- /frontend/src/components/logo.module.css: -------------------------------------------------------------------------------- 1 | body { 2 | --logo-glow-color: rgb(255, 255, 255); 3 | } 4 | 5 | .neet-logo-glow { 6 | transition: 7 | filter 0.3s ease-in-out, 8 | opacity 0.3s ease-in-out, 9 | transform 0.3s ease-in-out; 10 | opacity: 0.7; 11 | } 12 | 13 | .neet-logo-glow:hover { 14 | filter: drop-shadow(0 0 0.55rem var(--logo-glow-color)); 15 | opacity: 1; 16 | transform: rotate(360deg); 17 | } 18 | -------------------------------------------------------------------------------- /frontend/src/components/logo.tsx: -------------------------------------------------------------------------------- 1 | import { CSSProperties } from "react"; 2 | import styles from "./logo.module.css"; 3 | 4 | type LogoProps = { 5 | styles?: CSSProperties; 6 | className?: string; 7 | withGlow?: boolean; 8 | withLink?: boolean; 9 | withTitle?: boolean; 10 | }; 11 | 12 | export default function Logo(props: LogoProps) { 13 | const { withLink = false, withGlow = false } = props; 14 | const url = withLink ? "https://neetbox.550w.host" : undefined; 15 | const glowStyleClassName = withGlow ? styles["neet-logo-glow"] : undefined; 16 | const combinedStyles: CSSProperties = { 17 | ...{}, // add default style here 18 | ...props.styles, 19 | }; 20 | const imageComponent = ( 21 | 26 | ); 27 | return ( 28 | 33 | ); 34 | } 35 | -------------------------------------------------------------------------------- /frontend/src/components/overview/serverProps.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { Descriptions, Card, Toast, Typography } from "@douyinfe/semi-ui"; 3 | import { useAPI } from "../../services/api"; 4 | 5 | export function ServerPropsCard(): React.JSX.Element { 6 | const { Text } = Typography; 7 | 8 | const { data: serverIPs } = useAPI("/server/listips", { refreshInterval: 5000 }); 9 | const hostname = serverIPs?.hostname; 10 | const ips = serverIPs?.ips || []; 11 | 12 | const { data: serverVersion } = useAPI("/server/version", { refreshInterval: 5000 }); 13 | const version = serverVersion?.version; 14 | 15 | const { data: configs } = useAPI("/server/configs", { refreshInterval: 5000 }); 16 | 17 | const copyToClipboard = (value: string) => { 18 | navigator.clipboard 19 | .writeText(value) 20 | .then(() => { 21 | Toast.info("Copied to clipboard"); 22 | }) 23 | .catch(() => { 24 | Toast.error("Failed to copy"); 25 | }); 26 | }; 27 | 28 | const mapValueToStyle = (value: any) => { 29 | if (typeof value === "boolean") { 30 | return {value ? "True" : "False"}; 31 | } 32 | return value; 33 | }; 34 | 35 | const data = [ 36 | { key: "Hostname", value: hostname }, 37 | ...ips.map((ip) => ({ 38 | key: "IP", 39 | value: ( 40 |
copyToClipboard(ip)} 42 | style={{ cursor: "pointer", display: "flex", alignItems: "center" }} 43 | > 44 | {ip} 45 |
46 | ), 47 | })), 48 | { key: "Server Version", value: version }, 49 | // configs 50 | ...Object.entries(configs || {}).map(([key, value]) => ({ 51 | key: key.charAt(0).toUpperCase() + key.slice(1).replace(/([A-Z])/g, " $1"), 52 | value: ( 53 |
copyToClipboard(String(value))} 55 | style={{ cursor: "pointer", display: "flex", alignItems: "center" }} 56 | > 57 | {mapValueToStyle(value)} 58 |
59 | ), 60 | })), 61 | ]; 62 | 63 | return ( 64 | 78 | 79 | 80 | ); 81 | } 82 | -------------------------------------------------------------------------------- /frontend/src/components/project/hardware/cpugraph.tsx: -------------------------------------------------------------------------------- 1 | import { useCallback } from "react"; 2 | import { ECharts, getSemiColorDataHexColors } from "../../common/echarts"; 3 | import { CpuInfo } from "../../../services/types"; 4 | import { TimeDataMapper } from "../../../utils/timeDataMapper"; 5 | import { getTimeAxisOptions } from "./utils"; 6 | import { GraphWrapper } from "./graphWrapper"; 7 | 8 | export const CPUGraph = ({ data }: { data: TimeDataMapper }) => { 9 | const cpus = data.getValue(0); 10 | const initialOption = () => { 11 | return { 12 | color: getSemiColorDataHexColors(false), 13 | backgroundColor: "transparent", 14 | animation: false, 15 | tooltip: { 16 | trigger: "axis", 17 | }, 18 | grid: { 19 | top: 30, 20 | bottom: 30, 21 | }, 22 | title: { 23 | left: 20, 24 | text: `CPU (${cpus.length} threads)`, 25 | textStyle: { 26 | fontSize: 12, 27 | }, 28 | }, 29 | // legend: { 30 | // data: cpus.map((cpu) => `CPU${cpu.id}`), 31 | // }, 32 | xAxis: { 33 | type: "time", 34 | }, 35 | yAxis: { 36 | type: "value", 37 | max: cpus.length * 100, 38 | axisLabel: { 39 | formatter: (x) => x + " %", 40 | }, 41 | }, 42 | series: [], 43 | } as echarts.EChartsOption; 44 | }; 45 | 46 | const updatingOption = useCallback(() => { 47 | const newOption = { 48 | series: cpus.map((cpu) => ({ 49 | name: `CPU${cpu.id}`, 50 | type: "line", 51 | stack: "cpu", 52 | areaStyle: {}, 53 | symbol: null, 54 | data: data.map((timestamp, cpus) => [new Date(timestamp), cpus[cpu.id].percentage]), 55 | })), 56 | xAxis: getTimeAxisOptions(data), 57 | } as echarts.EChartsOption; 58 | return newOption; 59 | }, [cpus, data]); 60 | 61 | return ( 62 | 63 | 64 | 65 | ); 66 | }; 67 | -------------------------------------------------------------------------------- /frontend/src/components/project/hardware/gpugraph.css: -------------------------------------------------------------------------------- 1 | .gpu-temperature { 2 | --temperature-bg-brightness: 80%; 3 | position: absolute; 4 | right: 10%; 5 | border-radius: 5px; 6 | padding: 1px 5px; 7 | } 8 | [theme-mode="dark"] .gpu-temperature { 9 | --temperature-bg-brightness: 30%; 10 | } 11 | -------------------------------------------------------------------------------- /frontend/src/components/project/hardware/graphWrapper.tsx: -------------------------------------------------------------------------------- 1 | import { PropsWithChildren, memo } from "react"; 2 | import { JsonPopover } from "../jsonView"; 3 | 4 | export const GraphWrapper = memo( 5 | ({ title, lastValue, children }: PropsWithChildren<{ title: string; lastValue: any }>) => { 6 | return ( 7 |
8 | {children} 9 | 15 |
16 | ); 17 | }, 18 | ); 19 | -------------------------------------------------------------------------------- /frontend/src/components/project/hardware/index.tsx: -------------------------------------------------------------------------------- 1 | import { Typography } from "@douyinfe/semi-ui"; 2 | import { HardwareInfo } from "../../../services/types"; 3 | import { useCurrentProject, useProjectData } from "../../../hooks/useProject"; 4 | import Loading from "../../common/loading"; 5 | import { TimeDataMapper } from "../../../utils/timeDataMapper"; 6 | import { CPUGraph } from "./cpugraph"; 7 | import { GPUGraph } from "./gpugraph"; 8 | import { RAMGraph } from "./ramgraph"; 9 | import { fetchDataCount } from "./utils"; 10 | 11 | export function Hardware() { 12 | const { projectId, runId } = useCurrentProject(); 13 | const data = useProjectData({ 14 | projectId, 15 | runId, 16 | type: "hardware", 17 | transformHTTP: (x) => ({ timestamp: x.timestamp, ...x.metadata }), 18 | transformWS: (x) => ({ timestamp: x.timestamp, ...x.payload }), 19 | limit: fetchDataCount, 20 | }); 21 | return data?.length ? ( 22 |
23 | {data.every((x) => x.gpus?.length) ? ( 24 | data[0].gpus.map((_, i) => x.gpus[i])} />) 25 | ) : ( 26 | 27 | )} 28 | {data.every((x) => x.cpus.length) ? ( 29 | x.cpus)} /> 30 | ) : ( 31 | 32 | )} 33 | {data.every((x) => x.ram) ? ( 34 | x.ram)} /> 35 | ) : ( 36 | 37 | )} 38 |
39 | ) : ( 40 | 41 | ); 42 | } 43 | 44 | function NoInfoLabel({ text }: { text: string }) { 45 | return ( 46 | 47 | {text} 48 | 49 | ); 50 | } 51 | -------------------------------------------------------------------------------- /frontend/src/components/project/hardware/ramgraph.tsx: -------------------------------------------------------------------------------- 1 | import { useCallback } from "react"; 2 | import { ECharts, getSemiColorDataHexColors } from "../../common/echarts"; 3 | import { RamInfo } from "../../../services/types"; 4 | import { TimeDataMapper } from "../../../utils/timeDataMapper"; 5 | import { getTimeAxisOptions } from "./utils"; 6 | import { GraphWrapper } from "./graphWrapper"; 7 | 8 | export const RAMGraph = ({ data }: { data: TimeDataMapper }) => { 9 | const initialOption = () => { 10 | return { 11 | color: getSemiColorDataHexColors(false), 12 | backgroundColor: "transparent", 13 | animation: false, 14 | tooltip: { 15 | trigger: "axis", 16 | }, 17 | title: { 18 | left: 20, 19 | text: `RAM`, 20 | textStyle: { 21 | fontSize: 12, 22 | }, 23 | }, 24 | grid: { 25 | top: 30, 26 | bottom: 30, 27 | }, 28 | legend: { 29 | data: [`RAM Used`], 30 | }, 31 | xAxis: { 32 | type: "time", 33 | }, 34 | yAxis: [ 35 | { 36 | type: "value", 37 | position: "right", 38 | axisLabel: { 39 | formatter: (x) => (x / 1e3).toFixed(1) + " GB", 40 | }, 41 | max: data.getValue(0).total, 42 | }, 43 | ], 44 | series: [], 45 | } as echarts.EChartsOption; 46 | }; 47 | 48 | const updatingOption = useCallback(() => { 49 | const newOption = { 50 | series: [ 51 | { 52 | name: `RAM Used(GB)`, 53 | type: "line", 54 | areaStyle: {}, 55 | symbol: null, 56 | data: data.map((timestamp, ram) => [new Date(timestamp), ram.used]), 57 | }, 58 | ], 59 | xAxis: getTimeAxisOptions(data), 60 | } as echarts.EChartsOption; 61 | return newOption; 62 | }, [data]); 63 | 64 | return ( 65 | 66 | 67 | 68 | ); 69 | }; 70 | -------------------------------------------------------------------------------- /frontend/src/components/project/hardware/utils.ts: -------------------------------------------------------------------------------- 1 | import { TimeDataMapper } from "../../../utils/timeDataMapper"; 2 | 3 | const viewRangeSeconds = 300; 4 | const dataInterval = 2; 5 | export const fetchDataCount = Math.ceil((viewRangeSeconds / dataInterval) * 1.1); 6 | 7 | export function getTimeAxisOptions(mapper: TimeDataMapper) { 8 | const latestTime = new Date(mapper.data[mapper.data.length - 1].timestamp).getTime(); 9 | return { 10 | min: latestTime - viewRangeSeconds * 1000, 11 | max: latestTime, 12 | }; 13 | } 14 | 15 | export function percent2hue(value) { 16 | return ((100 - value) * 1.2).toString(10); 17 | } 18 | -------------------------------------------------------------------------------- /frontend/src/components/project/hyperParams.tsx: -------------------------------------------------------------------------------- 1 | import { memo } from "react"; 2 | import { Popover, Space, Typography } from "@douyinfe/semi-ui"; 3 | import { IconInfoCircle } from "@douyinfe/semi-icons"; 4 | import { useProjectRunStatus } from "../../hooks/useProject"; 5 | import Loading from "../common/loading"; 6 | import { JsonViewThemed } from "./jsonView"; 7 | 8 | export const HyperParams = memo( 9 | ({ projectId, runId, trigger = "click", position, children = }: any) => { 10 | return ( 11 | } 16 | > 17 | {children} 18 | 19 | ); 20 | }, 21 | ); 22 | 23 | const HyperParamsContent = memo(({ projectId, runId }: any) => { 24 | const [runStatus] = useProjectRunStatus(projectId, runId); 25 | const value = runStatus?.hyperparameters; 26 | return ( 27 | 28 | Hyperparameter 29 | {!runStatus ? ( 30 | 31 | ) : value == null ? ( 32 | N/A 33 | ) : ( 34 | 35 | )} 36 | 37 | ); 38 | }); 39 | -------------------------------------------------------------------------------- /frontend/src/components/project/imagesAndScatters.tsx: -------------------------------------------------------------------------------- 1 | import { Space } from "@douyinfe/semi-ui"; 2 | import { memo } from "react"; 3 | import { AllImageViewers } from "./images"; 4 | import { AllScatterViewers } from "./charts/scatters"; 5 | 6 | export const ImagesAndScatters = memo(() => { 7 | return ( 8 | 9 | 10 | 11 | 12 | ); 13 | }); 14 | -------------------------------------------------------------------------------- /frontend/src/components/project/jsonView.css: -------------------------------------------------------------------------------- 1 | .w-json-view-container { 2 | padding-left: 1em; 3 | } 4 | 5 | span[style="display: inline-flex; align-items: center;"] { 6 | /* position: absolute; */ 7 | transform: translate(-1em, 0); 8 | } 9 | -------------------------------------------------------------------------------- /frontend/src/components/project/jsonView.tsx: -------------------------------------------------------------------------------- 1 | import JsonView from "@uiw/react-json-view"; 2 | // eslint-disable-next-line import/no-unresolved 3 | import { githubDarkTheme } from "@uiw/react-json-view/githubDark"; 4 | import { CSSProperties, memo } from "react"; 5 | import { Popover, Space, Typography } from "@douyinfe/semi-ui"; 6 | import { IconCodeStroked } from "@douyinfe/semi-icons"; 7 | import { Position } from "@douyinfe/semi-ui/lib/es/tooltip"; 8 | import { useTheme } from "../../hooks/useTheme"; 9 | import "./jsonView.css"; 10 | 11 | export const JsonViewThemed = memo((props: any) => { 12 | const { darkMode } = useTheme(); 13 | return ( 14 | 27 | ); 28 | }); 29 | 30 | export const JsonPopover = memo( 31 | ({ 32 | value, 33 | title, 34 | position, 35 | style, 36 | }: { 37 | value: any; 38 | title?: string; 39 | position?: Position; 40 | style?: CSSProperties; 41 | }) => { 42 | return ( 43 | 48 | {title && {title}} 49 | 50 | 51 | } 52 | > 53 | 54 | 55 | ); 56 | }, 57 | ); 58 | -------------------------------------------------------------------------------- /frontend/src/components/project/logs/logs.css: -------------------------------------------------------------------------------- 1 | @import "../../../../public/fonts/maple/maple.css"; 2 | 3 | .log-item { 4 | margin-bottom: 5px; 5 | font-family: "MapleMono", monospace; 6 | font-family: "MapleMono", monospace; 7 | white-space: pre-wrap; 8 | font-size: 13px; 9 | 10 | .log-tag { 11 | display: inline-block; 12 | --log-tag-bg-hs: 0, 0%; 13 | --log-tag-bg-l: 80%; 14 | background-color: hsl(var(--log-tag-bg-hs), var(--log-tag-bg-l)); 15 | padding: 0 3px; 16 | border-radius: 5px; 17 | } 18 | 19 | .log-whom { 20 | --log-tag-bg-l: 30%; 21 | background-color: rgba(var(--semi-grey-1)); 22 | } 23 | 24 | .log-prefix-info { 25 | background-color: var(--semi-color-info); 26 | color: var(--semi-color-default); 27 | } 28 | 29 | .log-prefix-mention { 30 | background-color: var(--semi-color-secondary); 31 | color: var(--semi-color-default); 32 | } 33 | 34 | .log-prefix-ok { 35 | background-color: var(--semi-color-success); 36 | color: var(--semi-color-default); 37 | } 38 | 39 | .log-prefix-warning { 40 | background-color: var(--semi-color-warning); 41 | color: var(--semi-color-default); 42 | } 43 | 44 | .log-prefix-debug { 45 | background-color: var(--semi-color-link); 46 | color: var(--semi-color-default); 47 | } 48 | 49 | .log-prefix-error { 50 | background-color: var(--semi-color-danger); 51 | color: var(--semi-color-default); 52 | } 53 | } 54 | 55 | [theme-mode="dark"] .log-item .log-tag { 56 | --log-tag-bg-l: 30%; 57 | } 58 | 59 | [theme-mode="dark"] .log-item .log-whom { 60 | --log-tag-bg-l: 80%; 61 | } 62 | -------------------------------------------------------------------------------- /frontend/src/components/themeSwitcher.tsx: -------------------------------------------------------------------------------- 1 | import React, { useCallback, useLayoutEffect, useState } from "react"; 2 | import { flushSync } from "react-dom"; 3 | import { Switch } from "@douyinfe/semi-ui"; 4 | import { ThemeContext, useTheme } from "../hooks/useTheme"; 5 | 6 | export default function SwitchColorMode(): React.JSX.Element { 7 | const { darkMode, setDarkMode } = useTheme(); 8 | const switchMode = (checked, e) => { 9 | setDarkMode(!checked, e.nativeEvent); 10 | }; 11 | return ( 12 | 20 | ); 21 | } 22 | 23 | export function ThemeContextProvider(props: React.PropsWithChildren) { 24 | const [darkMode, setDarkModeState] = useState(() => localStorage.getItem("neetbox-theme") != "light"); 25 | 26 | const setDarkMode = useCallback((val, mouseEvent) => { 27 | const setTheme = () => { 28 | setDarkModeState(val); 29 | localStorage.setItem("neetbox-theme", val ? "" : "light"); 30 | }; 31 | 32 | if (document.startViewTransition) { 33 | document.startViewTransition(() => { 34 | flushSync(() => { 35 | setTheme(); 36 | document.documentElement.style.setProperty( 37 | "--page-theme-changing-origin", 38 | typeof mouseEvent?.x === "number" ? `${mouseEvent.x}px ${mouseEvent.y}px` : "", 39 | ); 40 | }); 41 | }); 42 | } else { 43 | setTheme(); 44 | } 45 | }, []); 46 | 47 | useLayoutEffect(() => { 48 | const body = document.body; 49 | if (darkMode) { 50 | body.setAttribute("theme-mode", "dark"); 51 | } else { 52 | body.removeAttribute("theme-mode"); 53 | } 54 | }, [darkMode]); 55 | 56 | return {props.children}; 57 | } 58 | -------------------------------------------------------------------------------- /frontend/src/hooks/useMemoJSON.ts: -------------------------------------------------------------------------------- 1 | import { useMemo } from "react"; 2 | 3 | /** Return the same ref if the data is not changed */ 4 | export function useMemoJSON(data: T): T { 5 | // eslint-disable-next-line react-hooks/exhaustive-deps 6 | return useMemo(() => data, [JSON.stringify(data)]); 7 | } 8 | -------------------------------------------------------------------------------- /frontend/src/hooks/useProject.ts: -------------------------------------------------------------------------------- 1 | import { createContext, useContext, useEffect } from "react"; 2 | import { useAtom } from "jotai"; 3 | import { KeyedMutator } from "swr"; 4 | import { getProject } from "../services/projects"; 5 | import { WsMsg } from "../services/projectWebsocket"; 6 | import { useAPI } from "../services/api"; 7 | import { RunStatus } from "../services/types"; 8 | import { useProjectData } from "./useProjectData"; 9 | 10 | export { useProjectData }; 11 | 12 | export const ProjectContext = createContext<{ 13 | projectId: string; 14 | projectName?: string; 15 | runId?: string; 16 | isOnlineRun: boolean; 17 | } | null>(null); 18 | 19 | export function useCurrentProject() { 20 | return useContext(ProjectContext)!; 21 | } 22 | 23 | export function useProjectStatus(id: string) { 24 | return useAPI(`/project/${id}`, { refreshInterval: 5000 }); 25 | } 26 | 27 | export function useProjectRunIds(id: string) { 28 | const { data, mutate } = useAPI(`/project/${id}`, { refreshInterval: 5000 }); 29 | return { data: data?.runids, mutate }; 30 | } 31 | 32 | export function useProjectRunStatus( 33 | id: string, 34 | runId?: string, 35 | ): [data: RunStatus | undefined, mutate: KeyedMutator] { 36 | const { data, mutate } = useAPI(`/project/${id}/run/${runId}`, { refreshInterval: 5000 }); 37 | return [!runId ? undefined : data, mutate]; 38 | } 39 | 40 | export function useProjectWebSocketReady(id: string) { 41 | const project = getProject(id); 42 | return useAtom(project.wsClient.isReady.atom)[0]; 43 | } 44 | 45 | export function useProjectWebSocket( 46 | id: string, 47 | type: T | null, 48 | onMessage: (msg: Extract) => void, 49 | ) { 50 | const project = getProject(id); 51 | useEffect(() => { 52 | const handle: typeof onMessage = (msg) => { 53 | if (!type || msg.eventType == type) { 54 | onMessage(msg); 55 | } 56 | }; 57 | project.wsClient.wsListeners.add(handle as any); 58 | return () => void project.wsClient.wsListeners.delete(handle as any); 59 | }, [project, type, onMessage]); 60 | } 61 | 62 | export function useProjectSeries(projectId: string, runId: string, type: string) { 63 | return useProjectData({ 64 | type: `${type}`, 65 | url: `/project/${projectId}/series/${type}?${new URLSearchParams({ runId: runId })}`, 66 | projectId, 67 | runId, 68 | transformWS: (msg) => msg.series, 69 | reducer: (data, queue) => [...new Set([...data, ...queue])], 70 | }); 71 | } 72 | -------------------------------------------------------------------------------- /frontend/src/hooks/useReportError.tsx: -------------------------------------------------------------------------------- 1 | import { useEffect } from "react"; 2 | import { addNotice } from "../utils/notification"; 3 | 4 | export function useReportGlobalError() { 5 | useEffect(() => { 6 | const handleError = (e: WindowEventMap["error"]) => { 7 | showError(e.message); 8 | }; 9 | const handleRejection = (e: WindowEventMap["unhandledrejection"]) => { 10 | showError(String(e.reason)); 11 | }; 12 | window.addEventListener("error", handleError); 13 | window.addEventListener("unhandledrejection", handleRejection); 14 | return () => { 15 | window.removeEventListener("error", handleError); 16 | window.removeEventListener("unhandledrejection", handleRejection); 17 | }; 18 | }, []); 19 | } 20 | 21 | let errorCount = 0; 22 | 23 | function showError(errorText: string) { 24 | errorCount++; 25 | addNotice({ 26 | id: "app-error", 27 | type: "error", 28 | title: `Frontend App Error (${errorCount})`, 29 | content: ( 30 |
39 | {errorText} 40 |
41 | ), 42 | duration: 10, 43 | }); 44 | } 45 | -------------------------------------------------------------------------------- /frontend/src/hooks/useTheme.tsx: -------------------------------------------------------------------------------- 1 | import { createContext, useContext } from "react"; 2 | 3 | export const ThemeContext = createContext<{ 4 | darkMode: boolean; 5 | setDarkMode: (val: boolean, mouseEvent?: Event) => void; 6 | }>(null!); 7 | 8 | export function useTheme() { 9 | return useContext(ThemeContext); 10 | } 11 | -------------------------------------------------------------------------------- /frontend/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | } 4 | 5 | @media (prefers-color-scheme: light) { 6 | :root { 7 | color: #213547; 8 | background-color: #ffffff; 9 | } 10 | a:hover { 11 | color: #747bff; 12 | } 13 | button { 14 | background-color: #f9f9f9; 15 | } 16 | } 17 | 18 | :root { 19 | --page-theme-changing-origin: 50% 50%; 20 | } 21 | ::view-transition-old(root) { 22 | animation: none; 23 | mix-blend-mode: normal; 24 | } 25 | ::view-transition-new(root) { 26 | animation: page-theme-changing 0.7s ease-in; 27 | mix-blend-mode: normal; 28 | } 29 | @keyframes page-theme-changing { 30 | 0% { 31 | clip-path: circle(0% at var(--page-theme-changing-origin)); 32 | } 33 | 100% { 34 | clip-path: circle(141% at var(--page-theme-changing-origin)); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /frontend/src/main.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom/client"; 3 | import { RouterProvider, createBrowserRouter } from "react-router-dom"; 4 | import { LocaleProvider } from "@douyinfe/semi-ui"; 5 | import en_US from "@douyinfe/semi-ui/lib/es/locale/source/en_US"; 6 | import LoginPage from "./pages/login"; 7 | import "./index.css"; 8 | import { consoleRoutes } from "./pages/console"; 9 | import { ThemeContextProvider } from "./components/themeSwitcher"; 10 | import { ServiceProvider } from "./services/serviceProvider"; 11 | import App from "./App"; 12 | import { RouteError } from "./components/common/errorBoundary"; 13 | 14 | const router = createBrowserRouter( 15 | [ 16 | { 17 | path: "/", 18 | element: , 19 | errorElement: , 20 | children: [ 21 | // { 22 | // path: "", 23 | // element: , 24 | // }, 25 | consoleRoutes(), 26 | { 27 | path: "/login", 28 | element: , 29 | }, 30 | ], 31 | }, 32 | ], 33 | { basename: "/web/" }, 34 | ); 35 | 36 | if (process.env.NODE_ENV === "development") { 37 | if (window.location.pathname == "/") { 38 | // For dev only. This is bad because it restarts the whole page/script loading process. 39 | // In production it's done by server redirect. 40 | window.location.replace("/web/"); 41 | } 42 | } 43 | 44 | ReactDOM.createRoot(document.getElementById("root")!).render( 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | , 54 | ); 55 | -------------------------------------------------------------------------------- /frontend/src/pages/console/index.tsx: -------------------------------------------------------------------------------- 1 | import { RouteObject } from "react-router-dom"; 2 | import ConsoleLayout from "../../components/layout/ConsoleLayout"; 3 | import { RouteError } from "../../components/common/errorBoundary"; 4 | import Dashboard from "./projectDashboard"; 5 | import Overview from "./overview"; 6 | 7 | export function consoleRoutes(): RouteObject { 8 | return { 9 | path: "", 10 | element: , 11 | children: [ 12 | { path: "", element: }, 13 | { 14 | path: "project/:projectId", 15 | element: , 16 | errorElement: , 17 | }, 18 | ], 19 | }; 20 | } 21 | -------------------------------------------------------------------------------- /frontend/src/pages/console/overview.tsx: -------------------------------------------------------------------------------- 1 | import { CardGroup, Divider } from "@douyinfe/semi-ui"; 2 | import { SectionTitle } from "../../components/common/sectionTitle"; 3 | import { ServerPropsCard } from "../../components/overview/serverProps"; 4 | import { DiskUsageCard } from "../../components/overview/diskUsage"; 5 | import ProjectList from "../../components/overview/projectList"; 6 | 7 | export default function Overview() { 8 | return ( 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | ); 20 | } 21 | -------------------------------------------------------------------------------- /frontend/src/pages/console/sidebar.tsx: -------------------------------------------------------------------------------- 1 | import { Nav, Space, Tag, Typography } from "@douyinfe/semi-ui"; 2 | import { IconHome, IconListView, IconGlobeStroke } from "@douyinfe/semi-icons"; 3 | import { useLocation, useNavigate } from "react-router-dom"; 4 | import { useAPI } from "../../services/api"; 5 | import Loading from "../../components/common/loading"; 6 | import "./sidebarStyleFix.css"; 7 | 8 | export default function ConsoleNavBar() { 9 | const location = useLocation(); 10 | const navigate = useNavigate(); 11 | const { data } = useAPI("/project/list", { refreshInterval: 5000 }); 12 | return ( 13 |