Skip to content

Commit

Permalink
feat(dashboard): add web dashboard
Browse files Browse the repository at this point in the history
* feat: Complete initial setup of web dashboard

* feat(recordings): Add simple view to start, stop and list recordings

* fix: Fix sqlite thread issue and a few dashbaord ui improvements

* feat: Add script to download npm dependencies and update installer script

* chore: Code cleanup and workflow fix
  • Loading branch information
KIRA009 authored Apr 11, 2024
1 parent dd1c29e commit 0050cea
Show file tree
Hide file tree
Showing 40 changed files with 10,391 additions and 27 deletions.
4 changes: 4 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,10 @@ jobs:
- run: poetry install --no-interaction --no-root
if: steps.cache-deps.outputs.cache-hit != 'true'

- name: Activate virtualenv
run: source .venv/bin/activate
if: steps.cache-deps.outputs.cache-hit == 'true'

- name: Check formatting with Black
run: poetry run black --preview --check .

Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,8 @@ pip3 install poetry
poetry install
poetry shell
alembic upgrade head
poetry run install-dashbaord
pytest
```

Expand Down
41 changes: 41 additions & 0 deletions install/install_openadapt.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ $pythonMaxVersion = "3.10.12" # Change this if a different Higher version are su
$pythonInstaller = "python-3.10.11-amd64.exe"
$pythonInstallerLoc = "https://www.python.org/ftp/python/3.10.11/python-3.10.11-amd64.exe"

$nvmCmd = "nvm"
$nvmInstaller = "nvm-setup.exe"
$nvmInstallerLoc = "https://github.com/coreybutler/nvm-windows/releases/download/1.1.12/nvm-setup.exe"

$gitCmd = "git"
$gitInstaller = "Git-2.40.1-64-bit.exe"
$gitInstallerLoc = "https://github.com/git-for-windows/git/releases/download/v2.40.1.windows.1/Git-2.40.1-64-bit.exe"
Expand Down Expand Up @@ -226,6 +230,39 @@ function GetPythonCMD {
exit
}

# Check and Install NVM and return the nvm command
function GetNVMCMD {
$nvmExists = CheckCMDExists $nvmCmd
if (!$nvmExists) {
# Install NVM
Write-Host "Downloading NVM installer..."
$ProgressPreference = 'SilentlyContinue'
Invoke-WebRequest -Uri $nvmInstallerLoc -OutFile $nvmInstaller
$exists = Test-Path -Path $nvmInstaller -PathType Leaf
if (!$exists) {
Write-Host "Failed to download NVM installer" -ForegroundColor Red
exit
}

Write-Host "Installing NVM..."
Start-Process -FilePath $nvmInstaller -Verb runAs -ArgumentList '/VERYSILENT /NORESTART /NOCANCEL /SP-' -Wait
Remove-Item $nvmInstaller

RefreshPathVariables

# Make sure NVM is now available
$nvmExists = CheckCMDExists $nvmCmd
if (!$nvmExists) {
Write-Host "Error after installing NVM. Uninstalling..."
Start-Process -FilePath $nvmInstaller -Verb runAs -ArgumentList '/VERYSILENT /NORESTART /NOCANCEL /SP-' -Wait
Cleanup
exit
}
}
# Return the nvm command
return $nvmCmd
}


# Check and Install Git and return the git command
function GetGitCMD {
Expand Down Expand Up @@ -310,6 +347,9 @@ RunAndCheck "$tesseract --version" "check TesseractOCR"
$python = GetPythonCMD
RunAndCheck "$python --version" "check Python"

$nvm = GetNVMCMD
RunAndCheck "$nvm --version" "check NVM"

$git = GetGitCMD
RunAndCheck "$git --version" "check Git"

Expand All @@ -321,6 +361,7 @@ Set-Location .\OpenAdapt
RunAndCheck "pip install poetry" "Run ``pip install poetry``"
RunAndCheck "poetry install" "Run ``poetry install``"
RunAndCheck "poetry run alembic upgrade head" "Run ``alembic upgrade head``" -SkipCleanup:$true
RunAndCheck "poetry run dashboard" "Install dashboard dependencies" -SkipCleanup:$true
RunAndCheck "poetry run pytest" "Run ``Pytest``" -SkipCleanup:$true
Write-Host "OpenAdapt installed Successfully!" -ForegroundColor Green
Start-Process powershell -Verb RunAs -ArgumentList "-NoExit", "-Command", "Set-Location -Path '$pwd'; poetry shell"
Expand Down
25 changes: 25 additions & 0 deletions install/install_openadapt.sh
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ set -x
pythonCmd="python3.10"
pythonVerStr="Python 3.10*"
pythonInstallerLoc="https://www.python.org/ftp/python/3.10.11/python-3.10.11-macos11.pkg"
nvmCmd="nvm"
nvmInstallerLoc="https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh"

# Set default values when no parameters are provided
BRANCH=${BRANCH:-main}
Expand Down Expand Up @@ -93,6 +95,27 @@ CheckPythonExists() {
exit 1
}

CheckNVMExists() {
if CheckCMDExists $nvmCmd; then
return
fi

# Install NVM
echo Installing NVM

curl -o- $nvmInstallerLoc | bash

export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm
[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion" # This loads nvm bash_completion

if ! CheckCMDExists $nvmCmd; then
echo "Failed to install NVM"
Cleanup
exit 1
fi
}

################################ INSTALLATION ################################

# Download brew
Expand Down Expand Up @@ -125,6 +148,7 @@ if ! CheckCMDExists "tesseract"; then
fi

CheckPythonExists
CheckNVMExists

[ -d "OpenAdapt" ] && mv OpenAdapt OpenAdapt-$(date +%Y-%m-%d_%H-%M-%S)
RunAndCheck "git clone $REPO_URL" "Clone git repo"
Expand All @@ -134,6 +158,7 @@ RunAndCheck "git checkout $BRANCH" "Checkout branch $BRANCH"
RunAndCheck "pip3.10 install poetry" "Install Poetry"
RunAndCheck "poetry install" "Install Python dependencies"
RunAndCheck "poetry run alembic upgrade head" "Update database"
RunAndCheck "poetry run dashboard" "Install dashboard dependencies"
RunAndCheck "poetry run pytest" "Run tests"
if [ -z "$SKIP_POETRY_SHELL" ]; then
RunAndCheck "poetry shell" "Activate virtual environment"
Expand Down
6 changes: 6 additions & 0 deletions openadapt/app/cards.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,12 @@ def stop_record() -> None:
record_proc = None


def is_recording() -> bool:
"""Check if a recording session is currently active."""
global record_proc
return record_proc is not None


def quick_record() -> None:
"""Run a recording session with no option for recording name (uses date instead)."""
global record_proc
Expand Down
3 changes: 3 additions & 0 deletions openadapt/app/dashboard/.eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"extends": "next/core-web-vitals"
}
35 changes: 35 additions & 0 deletions openadapt/app/dashboard/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules
/.pnp
.pnp.js

# testing
/coverage

# next.js
/.next/
/out/

# production
/build

# misc
.DS_Store
*.pem

# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# local env files
.env*.local

# vercel
.vercel

# typescript
*.tsbuildinfo
next-env.d.ts
1 change: 1 addition & 0 deletions openadapt/app/dashboard/.nvmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
21
6 changes: 6 additions & 0 deletions openadapt/app/dashboard/.prettierrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"trailingComma": "es5",
"tabWidth": 4,
"semi": false,
"singleQuote": true
}
78 changes: 78 additions & 0 deletions openadapt/app/dashboard/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
<p align="center">
<a href="https://nextjs-fastapi-starter.vercel.app/">
<img src="https://assets.vercel.com/image/upload/v1588805858/repositories/vercel/logo.png" height="96">
<h3 align="center">Next.js FastAPI Starter</h3>
</a>
</p>

<p align="center">Simple Next.js boilerplate that uses <a href="https://fastapi.tiangolo.com/">FastAPI</a> as the API backend.</p>

<br/>

## Introduction

This is a hybrid Next.js + Python app that uses Next.js as the frontend and FastAPI as the API backend. One great use case of this is to write Next.js apps that use Python AI libraries on the backend.

## How It Works

The Python/FastAPI server is mapped into to Next.js app under `/api/`.

This is implemented using [`next.config.js` rewrites](https://github.com/digitros/nextjs-fastapi/blob/main/next.config.js) to map any request to `/api/:path*` to the FastAPI API, which is hosted in the `/api` folder.

On localhost, the rewrite will be made to the `127.0.0.1:8000` port, which is where the FastAPI server is running.

In production, the FastAPI server is hosted as [Python serverless functions](https://vercel.com/docs/concepts/functions/serverless-functions/runtimes/python) on Vercel.

## Demo

https://nextjs-fastapi-starter.vercel.app/

## Deploy Your Own

You can clone & deploy it to Vercel with one click:

[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Fdigitros%2Fnextjs-fastapi%2Ftree%2Fmain)

## Developing Locally

You can clone & create this repo with the following command

```bash
npx create-next-app nextjs-fastapi --example "https://github.com/digitros/nextjs-fastapi"
```

## Getting Started

First, install the dependencies:

```bash
npm install
# or
yarn
# or
pnpm install
```

Then, run the development server:

```bash
npm run dev
# or
yarn dev
# or
pnpm dev
```

Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.

The FastApi server will be running on [http://127.0.0.1:8000](http://127.0.0.1:8000) – feel free to change the port in `package.json` (you'll also need to update it in `next.config.js`).

## Learn More

To learn more about Next.js, take a look at the following resources:

- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
- [FastAPI Documentation](https://fastapi.tiangolo.com/) - learn about FastAPI features and API.

You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome!
20 changes: 20 additions & 0 deletions openadapt/app/dashboard/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
"""Script to install dependencies needed for the dashboard."""

import os
import subprocess
import sys


def _run(bash_script: str) -> int:
return subprocess.call(bash_script, shell=True)


def entrypoint() -> None:
"""Entrypoint for the installation script."""
cwd = os.path.dirname(os.path.realpath(__file__))
os.chdir(cwd)

if sys.platform == "win32":
_run("powershell -File entrypoint.ps1")
return
_run("source ./entrypoint.sh")
37 changes: 37 additions & 0 deletions openadapt/app/dashboard/api/index.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
"""API endpoints for the dashboard."""


from fastapi import FastAPI

from openadapt.app.cards import is_recording, quick_record, stop_record
from openadapt.db import crud
from openadapt.models import Recording

app = FastAPI()


@app.get("/api/recordings", response_model=None)
def get_recordings() -> dict[str, list[Recording]]:
"""Get all recordings."""
recordings = crud.get_all_recordings()
return {"recordings": recordings}


@app.get("/api/recordings/start")
def start_recording() -> dict[str, str]:
"""Start a recording session."""
quick_record()
return {"message": "Recording started"}


@app.get("/api/recordings/stop")
def stop_recording() -> dict[str, str]:
"""Stop a recording session."""
stop_record()
return {"message": "Recording stopped"}


@app.get("/api/recordings/status")
def recording_status() -> dict[str, bool]:
"""Get the recording status."""
return {"recording": is_recording()}
Binary file added openadapt/app/dashboard/app/favicon.ico
Binary file not shown.
7 changes: 7 additions & 0 deletions openadapt/app/dashboard/app/globals.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
@layer mantine tailwind;

@import '@mantine/core/styles.layer.css';

@layer tailwind {
@tailwind utilities;
}
27 changes: 27 additions & 0 deletions openadapt/app/dashboard/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import './globals.css'

import { ColorSchemeScript, MantineProvider } from '@mantine/core'
import { Shell } from '@/components/Shell'

export const metadata = {
title: 'OpenAdapt',
}

export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html lang="en">
<head>
<ColorSchemeScript />
</head>
<body>
<MantineProvider>
<Shell>{children}</Shell>
</MantineProvider>
</body>
</html>
)
}
Loading

0 comments on commit 0050cea

Please sign in to comment.