diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 000000000..d6fa1a4bc --- /dev/null +++ b/Dockerfile @@ -0,0 +1,75 @@ +# Build a custom kasmweb image following guidelines from https://kasmweb.com/docs/latest/how_to/building_images.html +FROM kasmweb/ubuntu-jammy-desktop:1.16.0 +USER root + +ENV HOME=/home/kasm-default-profile +ENV STARTUPDIR=/dockerstartup +ENV INST_SCRIPTS=$STARTUPDIR/install +WORKDIR $HOME + +######### Customize Container Here ########### + +# Install dependencies for OpenAdapt + +RUN curl -fsSL https://deb.nodesource.com/setup_21.x | bash +RUN apt-get update && \ + apt-get install -y nodejs tesseract-ocr portaudio19-dev && \ + apt-get clean + +# Disable ssl and basic auth and enable sudo as this will be a developer container + +ENV VNCOPTIONS=-disableBasicAuth +RUN sed -i '/ ssl:/a\ require_ssl: false' /etc/kasmvnc/kasmvnc.yaml +# https://github.com/kasmtech/workspaces-core-images/issues/2 +RUN sed -i 's/-sslOnly//g' /dockerstartup/vnc_startup.sh +RUN echo 'kasm-user ALL=(ALL) NOPASSWD: ALL' >> /etc/sudoers + +######### End Customizations ########### + + +RUN chown 1000:0 $HOME +RUN $STARTUPDIR/set_user_permission.sh $HOME + +ENV HOME=/home/kasm-user +WORKDIR $HOME +RUN mkdir -p $HOME && chown -R 1000:0 $HOME + +USER 1000 + + +######### Customize Container Here ########### + +WORKDIR $HOME + +ENV PATH=$HOME/.local/bin:$PATH \ + POETRY_NO_INTERACTION=1 \ + POETRY_VIRTUALENVS_IN_PROJECT=1 \ + POETRY_VIRTUALENVS_CREATE=1 \ + POETRY_CACHE_DIR=/tmp/poetry_cache +RUN curl -sSL https://install.python-poetry.org | POETRY_VERSION=1.8.5 python3 - + +RUN git clone https://github.com/bard/OpenAdapt +WORKDIR $HOME/OpenAdapt +RUN poetry install + +# replace torch and torchvision with cpu-only versions +RUN poetry source add --priority explicit pytorch_cpu https://download.pytorch.org/whl/cpu +RUN poetry add --source pytorch_cpu torch==2.0.1+cpu torchvision==0.15.2+cpu + +# install prebuilt cpu-only detectron +RUN poetry source add --priority explicit torch_packages https://miropsota.github.io/torch_packages_builder +RUN poetry add --source torch_packages detectron2==0.6+2a420edpt2.0.1cpu + +# for some reason, pyaudio either doesn't get installed, or it gets removed in the steps above +RUN poetry remove pyaudio && poetry add pyaudio + +# restrict python compatibliity to accommodate pyside6.2 +# RUN sed -i 's/python = ">=3.10,<3.12/python = ">=3.10,<3.11/' pyproject.toml +# install a pyside version compatible with system-installed qt +# RUN poetry add pyside6==6.2 + +RUN cd openadapt && poetry run alembic upgrade head +RUN cd openadapt/app/dashboard && npm install + +######### End Customizations ########### + diff --git a/openadapt/alembic/env.py b/openadapt/alembic/env.py index 7a38305dd..be699098b 100644 --- a/openadapt/alembic/env.py +++ b/openadapt/alembic/env.py @@ -10,7 +10,7 @@ from alembic import context from openadapt.config import config from openadapt.db import db -from openadapt.models import ForceFloat +from openadapt.decorators import ForceFloat # This is the Alembic Config object, which provides # access to the values within the .ini file in use. diff --git a/openadapt/alembic/versions/530f0663324e_add_recording_video_start_time.py b/openadapt/alembic/versions/530f0663324e_add_recording_video_start_time.py index f18e50f5b..a683dff50 100644 --- a/openadapt/alembic/versions/530f0663324e_add_recording_video_start_time.py +++ b/openadapt/alembic/versions/530f0663324e_add_recording_video_start_time.py @@ -8,7 +8,7 @@ import sqlalchemy as sa from alembic import op -from openadapt.models import ForceFloat +from openadapt.decorators import ForceFloat # revision identifiers, used by Alembic. revision = "530f0663324e" diff --git a/openadapt/alembic/versions/607d1380b5ae_add_memorystat.py b/openadapt/alembic/versions/607d1380b5ae_add_memorystat.py index dcf15ca24..3a42925db 100644 --- a/openadapt/alembic/versions/607d1380b5ae_add_memorystat.py +++ b/openadapt/alembic/versions/607d1380b5ae_add_memorystat.py @@ -8,7 +8,7 @@ import sqlalchemy as sa from alembic import op -from openadapt.models import ForceFloat +from openadapt.decorators import ForceFloat # revision identifiers, used by Alembic. revision = "607d1380b5ae" diff --git a/openadapt/alembic/versions/98505a067995_add_browserevent_table.py b/openadapt/alembic/versions/98505a067995_add_browserevent_table.py index 6092f394c..ecda79c54 100644 --- a/openadapt/alembic/versions/98505a067995_add_browserevent_table.py +++ b/openadapt/alembic/versions/98505a067995_add_browserevent_table.py @@ -20,15 +20,15 @@ def upgrade() -> None: # ### commands auto generated by Alembic - please adjust! ### op.create_table('browser_event', sa.Column('id', sa.Integer(), nullable=False), - sa.Column('recording_timestamp', openadapt.models.ForceFloat(precision=10, scale=2, asdecimal=False), nullable=True), + sa.Column('recording_timestamp', openadapt.decorators.ForceFloat(precision=10, scale=2, asdecimal=False), nullable=True), sa.Column('recording_id', sa.Integer(), nullable=True), sa.Column('message', sa.JSON(), nullable=True), - sa.Column('timestamp', openadapt.models.ForceFloat(precision=10, scale=2, asdecimal=False), nullable=True), + sa.Column('timestamp', openadapt.decorators.ForceFloat(precision=10, scale=2, asdecimal=False), nullable=True), sa.ForeignKeyConstraint(['recording_id'], ['recording.id'], name=op.f('fk_browser_event_recording_id_recording')), sa.PrimaryKeyConstraint('id', name=op.f('pk_browser_event')) ) with op.batch_alter_table('action_event', schema=None) as batch_op: - batch_op.add_column(sa.Column('browser_event_timestamp', openadapt.models.ForceFloat(precision=10, scale=2, asdecimal=False), nullable=True)) + batch_op.add_column(sa.Column('browser_event_timestamp', openadapt.decorators.ForceFloat(precision=10, scale=2, asdecimal=False), nullable=True)) batch_op.add_column(sa.Column('browser_event_id', sa.Integer(), nullable=True)) batch_op.create_foreign_key(batch_op.f('fk_action_event_browser_event_id_browser_event'), 'browser_event', ['browser_event_id'], ['id']) diff --git a/openadapt/alembic/versions/98c8851a5321_add_audio_info.py b/openadapt/alembic/versions/98c8851a5321_add_audio_info.py index a3db85869..97d91ce33 100644 --- a/openadapt/alembic/versions/98c8851a5321_add_audio_info.py +++ b/openadapt/alembic/versions/98c8851a5321_add_audio_info.py @@ -24,14 +24,14 @@ def upgrade() -> None: sa.Column("id", sa.Integer(), nullable=False), sa.Column( "timestamp", - openadapt.models.ForceFloat(precision=10, scale=2, asdecimal=False), + openadapt.decorators.ForceFloat(precision=10, scale=2, asdecimal=False), nullable=True, ), sa.Column("flac_data", sa.LargeBinary(), nullable=True), sa.Column("transcribed_text", sa.String(), nullable=True), sa.Column( "recording_timestamp", - openadapt.models.ForceFloat(precision=10, scale=2, asdecimal=False), + openadapt.decorators.ForceFloat(precision=10, scale=2, asdecimal=False), nullable=True, ), sa.Column("recording_id", sa.Integer(), nullable=True), diff --git a/openadapt/alembic/versions/d714cc86fce8_add_scrubbed_recording_model.py b/openadapt/alembic/versions/d714cc86fce8_add_scrubbed_recording_model.py index 68f896047..86c93b144 100644 --- a/openadapt/alembic/versions/d714cc86fce8_add_scrubbed_recording_model.py +++ b/openadapt/alembic/versions/d714cc86fce8_add_scrubbed_recording_model.py @@ -8,7 +8,7 @@ from alembic import op import sqlalchemy as sa -from openadapt.models import ForceFloat +from openadapt.decorators import ForceFloat # revision identifiers, used by Alembic. revision = "d714cc86fce8" diff --git a/openadapt/decorators.py b/openadapt/decorators.py new file mode 100644 index 000000000..f9127c395 --- /dev/null +++ b/openadapt/decorators.py @@ -0,0 +1,19 @@ +import sqlalchemy as sa + + +# https://groups.google.com/g/sqlalchemy/c/wlr7sShU6-k +class ForceFloat(sa.TypeDecorator): + """Custom SQLAlchemy type decorator for floating-point numbers.""" + + impl = sa.Numeric(10, 2, asdecimal=False) + cache_ok = True + + def process_result_value( + self, + value: int | float | str | None, + dialect: str, + ) -> float | None: + """Convert the result value to float.""" + if value is not None: + value = float(value) + return value diff --git a/openadapt/error_reporting.py b/openadapt/error_reporting.py index 2dee6a616..8708179d0 100644 --- a/openadapt/error_reporting.py +++ b/openadapt/error_reporting.py @@ -3,6 +3,7 @@ from typing import Any from loguru import logger + from PySide6.QtGui import QIcon from PySide6.QtWidgets import QMessageBox, QPushButton import git diff --git a/openadapt/models.py b/openadapt/models.py index 03b60329e..72904e0ab 100644 --- a/openadapt/models.py +++ b/openadapt/models.py @@ -21,28 +21,11 @@ from openadapt.db import db from openadapt.privacy.base import ScrubbingProvider, TextScrubbingMixin from openadapt.privacy.providers import ScrubProvider +from openadapt.decorators import ForceFloat EMPTY_VALS = [None, "", [], (), {}] -# https://groups.google.com/g/sqlalchemy/c/wlr7sShU6-k -class ForceFloat(sa.TypeDecorator): - """Custom SQLAlchemy type decorator for floating-point numbers.""" - - impl = sa.Numeric(10, 2, asdecimal=False) - cache_ok = True - - def process_result_value( - self, - value: int | float | str | None, - dialect: str, - ) -> float | None: - """Convert the result value to float.""" - if value is not None: - value = float(value) - return value - - class Recording(db.Base): """Class representing a recording in the database."""