├── .gitattributes
├── .github
└── workflows
│ ├── check-header.yml
│ ├── smoke_test.yml
│ ├── sonarcloud_scan_app.yml
│ └── sonarcloud_scan_service.yml
├── .gitignore
├── BUILD.md
├── CODE-OF-CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE.txt
├── NOTICE.txt
├── README.md
├── RUN-WITH-DOCKER.md
├── active-learning-service
├── Dockerfile
├── config
│ ├── __init__.py
│ ├── app_os.py
│ ├── config.py
│ └── constant.py
├── logs
│ ├── main.log
│ └── main_debug.log
├── manage.py
├── models
│ └── porojectName_model.pkl
├── mysite
│ ├── __init__.py
│ ├── asgi.py
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py
├── requirements.txt
└── src
│ ├── __init__.py
│ ├── admin.py
│ ├── al
│ ├── __init__.py
│ ├── activelearning.py
│ ├── embeddings.py
│ ├── get_vectors.py
│ ├── project_service.py
│ ├── query_instance.py
│ ├── retry_service.py
│ ├── separate_data.py
│ ├── sr_service.py
│ ├── teach_model.py
│ ├── train_model.py
│ └── vector_sr.py
│ ├── apps.py
│ ├── aws
│ ├── __init__.py
│ ├── s3.py
│ └── sts.py
│ ├── db
│ ├── __init__.py
│ └── mongo_connect.py
│ ├── exceptions
│ ├── __init__.py
│ └── base_exceptions.py
│ ├── migrations
│ └── __init__.py
│ ├── models.py
│ ├── tests.py
│ ├── urls.py
│ ├── utils
│ ├── JSONEncoder.py
│ ├── __init__.py
│ ├── common.py
│ ├── fileSystem.py
│ ├── jwtVerification.py
│ └── modules.py
│ └── views.py
├── annotation-app
├── .browserslistrc
├── .prettierignore
├── .prettierrc
├── Dockerfile
├── angular.json
├── build-script.js
├── docker-entrypoint.sh
├── nginx.conf
├── package-lock.json
├── package.json
├── proxy.conf.json
├── src
│ ├── app
│ │ ├── app-routing.module.ts
│ │ ├── app.component.html
│ │ ├── app.component.ts
│ │ ├── app.module.ts
│ │ ├── component
│ │ │ ├── datasets
│ │ │ │ ├── create-new-dataset-modal
│ │ │ │ │ ├── create-new-dataset-modal.component.html
│ │ │ │ │ ├── create-new-dataset-modal.component.scss
│ │ │ │ │ └── create-new-dataset-modal.component.ts
│ │ │ │ ├── create-new-dataset-page
│ │ │ │ │ ├── create-new-dataset-page.component.html
│ │ │ │ │ ├── create-new-dataset-page.component.scss
│ │ │ │ │ └── create-new-dataset-page.component.ts
│ │ │ │ ├── create-new-dataset
│ │ │ │ │ ├── create-new-dataset.component.html
│ │ │ │ │ ├── create-new-dataset.component.scss
│ │ │ │ │ └── create-new-dataset.component.ts
│ │ │ │ ├── dataset-analyze
│ │ │ │ │ ├── analyze-datagrid
│ │ │ │ │ │ ├── analyze-datagrid.component.html
│ │ │ │ │ │ ├── analyze-datagrid.component.scss
│ │ │ │ │ │ └── analyze-datagrid.component.ts
│ │ │ │ │ ├── dataset-analyze.component.html
│ │ │ │ │ ├── dataset-analyze.component.scss
│ │ │ │ │ └── dataset-analyze.component.ts
│ │ │ │ ├── datasets-routing.module.ts
│ │ │ │ ├── datasets.module.ts
│ │ │ │ ├── dnd.directive.ts
│ │ │ │ ├── modal-datagrid
│ │ │ │ │ ├── modal-datagrid.component.html
│ │ │ │ │ └── modal-datagrid.component.ts
│ │ │ │ ├── my-datasets
│ │ │ │ │ ├── my-datasets.component.html
│ │ │ │ │ ├── my-datasets.component.scss
│ │ │ │ │ └── my-datasets.component.ts
│ │ │ │ └── upload-file
│ │ │ │ │ ├── upload-file.component.html
│ │ │ │ │ ├── upload-file.component.scss
│ │ │ │ │ └── upload-file.component.ts
│ │ │ ├── faq
│ │ │ │ ├── faq.component.html
│ │ │ │ ├── faq.component.scss
│ │ │ │ └── faq.component.ts
│ │ │ ├── header
│ │ │ │ ├── header.component.html
│ │ │ │ ├── header.component.scss
│ │ │ │ └── header.component.ts
│ │ │ ├── home
│ │ │ │ ├── home.component.html
│ │ │ │ ├── home.component.scss
│ │ │ │ └── home.component.ts
│ │ │ ├── login
│ │ │ │ ├── basic-login
│ │ │ │ │ ├── basic-login.component.html
│ │ │ │ │ ├── basic-login.component.scss
│ │ │ │ │ └── basic-login.component.ts
│ │ │ │ ├── login-routing.module.ts
│ │ │ │ ├── login.module.ts
│ │ │ │ └── login
│ │ │ │ │ ├── login.component.html
│ │ │ │ │ ├── login.component.scss
│ │ │ │ │ └── login.component.ts
│ │ │ ├── page-not-found
│ │ │ │ ├── page-not-found.component.html
│ │ │ │ ├── page-not-found.component.scss
│ │ │ │ └── page-not-found.component.ts
│ │ │ ├── permission
│ │ │ │ ├── permissions-routing.module.ts
│ │ │ │ ├── permissions.module.ts
│ │ │ │ └── permissions
│ │ │ │ │ ├── permissions.component.html
│ │ │ │ │ ├── permissions.component.scss
│ │ │ │ │ └── permissions.component.ts
│ │ │ ├── projects
│ │ │ │ ├── annotate-progress-board
│ │ │ │ │ ├── annotate-progress-board.component.html
│ │ │ │ │ ├── annotate-progress-board.component.scss
│ │ │ │ │ └── annotate-progress-board.component.ts
│ │ │ │ ├── create-project
│ │ │ │ │ ├── create-project.component.html
│ │ │ │ │ ├── create-project.component.scss
│ │ │ │ │ └── create-project.component.ts
│ │ │ │ ├── download
│ │ │ │ │ ├── download.component.html
│ │ │ │ │ ├── download.component.scss
│ │ │ │ │ └── download.component.ts
│ │ │ │ ├── generate
│ │ │ │ │ ├── generate.component.html
│ │ │ │ │ ├── generate.component.scss
│ │ │ │ │ └── generate.component.ts
│ │ │ │ ├── labeling-task-list
│ │ │ │ │ ├── edit-project
│ │ │ │ │ │ ├── edit-project.component.html
│ │ │ │ │ │ ├── edit-project.component.scss
│ │ │ │ │ │ └── edit-project.component.ts
│ │ │ │ │ ├── projects.component.html
│ │ │ │ │ ├── projects.component.scss
│ │ │ │ │ ├── projects.component.ts
│ │ │ │ │ └── task-datagrid
│ │ │ │ │ │ ├── task-datagrid.component.html
│ │ │ │ │ │ ├── task-datagrid.component.scss
│ │ │ │ │ │ └── task-datagrid.component.ts
│ │ │ │ ├── project-analyze
│ │ │ │ │ ├── append
│ │ │ │ │ │ ├── append.component.html
│ │ │ │ │ │ ├── append.component.scss
│ │ │ │ │ │ └── append.component.ts
│ │ │ │ │ ├── latest-annotation-data
│ │ │ │ │ │ ├── latest-annotation-data.component.html
│ │ │ │ │ │ ├── latest-annotation-data.component.scss
│ │ │ │ │ │ └── latest-annotation-data.component.ts
│ │ │ │ │ ├── project-analyze.component.html
│ │ │ │ │ ├── project-analyze.component.scss
│ │ │ │ │ ├── project-analyze.component.ts
│ │ │ │ │ └── user-category-d3
│ │ │ │ │ │ ├── user-category-d3.component.html
│ │ │ │ │ │ ├── user-category-d3.component.scss
│ │ │ │ │ │ └── user-category-d3.component.ts
│ │ │ │ ├── projects-routing.module.ts
│ │ │ │ ├── projects.module.ts
│ │ │ │ └── treeview-modal
│ │ │ │ │ ├── treeview-modal.component.html
│ │ │ │ │ ├── treeview-modal.component.scss
│ │ │ │ │ └── treeview-modal.component.ts
│ │ │ └── sidenav
│ │ │ │ ├── sidenav.component.html
│ │ │ │ ├── sidenav.component.scss
│ │ │ │ └── sidenav.component.ts
│ │ ├── core.module.ts
│ │ ├── guards
│ │ │ └── auth.guard.ts
│ │ ├── model
│ │ │ ├── authentication.ts
│ │ │ ├── constant.ts
│ │ │ ├── dataset.ts
│ │ │ ├── env.ts
│ │ │ ├── index.ts
│ │ │ ├── sr.ts
│ │ │ └── user.ts
│ │ ├── pipes
│ │ │ ├── full-name.pipe.ts
│ │ │ ├── math-round.pipe.ts
│ │ │ └── sliceText.pipe.ts
│ │ ├── services
│ │ │ ├── api.service.ts
│ │ │ ├── cds-icon.service.ts
│ │ │ ├── common
│ │ │ │ ├── common.service.ts
│ │ │ │ ├── dom.service.ts
│ │ │ │ ├── download.service.ts
│ │ │ │ ├── email.service.ts
│ │ │ │ ├── markdown-parser.service.ts
│ │ │ │ ├── s3.service.ts
│ │ │ │ ├── tool.service.ts
│ │ │ │ ├── tool.utils.js
│ │ │ │ └── up-zip.service.ts
│ │ │ ├── environments.service.ts
│ │ │ ├── internal-api.service.ts
│ │ │ ├── label-studio.service.ts
│ │ │ ├── user-auth.service.ts
│ │ │ └── web-analytics.service.ts
│ │ └── shared
│ │ │ ├── clr-filter
│ │ │ ├── datagridFilter.component.html
│ │ │ ├── datagridFilter.component.scss
│ │ │ └── datagridFilter.component.ts
│ │ │ ├── form-validators
│ │ │ ├── dataset-validator.ts
│ │ │ └── form-validator-util.ts
│ │ │ ├── modal-confirm
│ │ │ ├── modal-confirm.component.html
│ │ │ └── modal-confirm.component.ts
│ │ │ ├── routeReuseStrategy.ts
│ │ │ ├── shared.module.ts
│ │ │ └── utils
│ │ │ ├── html.ts
│ │ │ ├── index.es5.ts
│ │ │ └── treeView.ts
│ ├── assets
│ │ ├── .gitkeep
│ │ ├── files
│ │ │ ├── taxonomy_sample.json
│ │ │ └── taxonomy_sample.yaml
│ │ └── images
│ │ │ ├── ava-logo.png
│ │ │ ├── ava-small.png
│ │ │ ├── demo.png
│ │ │ ├── favicon.ico
│ │ │ ├── polygon.svg
│ │ │ ├── rect.svg
│ │ │ ├── refresh.svg
│ │ │ ├── trash.svg
│ │ │ └── vm-logo.png
│ ├── dev-platform
│ │ ├── dev-platform.module.ts
│ │ └── dev-platform
│ │ │ ├── dev-platform.component.css
│ │ │ ├── dev-platform.component.html
│ │ │ └── dev-platform.component.ts
│ ├── environments
│ │ ├── environment.prod.ts
│ │ └── environment.ts
│ ├── favicon.ico
│ ├── index.html
│ ├── libs
│ │ ├── categoryChart.js
│ │ ├── hierarchicalChart.js
│ │ ├── modelChart.js
│ │ └── userChart.js
│ ├── main.ts
│ ├── micro-frontend
│ │ ├── entry.component.ts
│ │ └── micro-frontend.module.ts
│ ├── polyfills.ts
│ └── styles.scss
├── tsconfig.app.json
├── tsconfig.json
└── tslint.json
├── annotation-service
├── Dockerfile
├── config
│ ├── app-os.js
│ ├── code_msg.js
│ ├── config.js
│ └── constant.js
├── db
│ ├── db-connect.js
│ └── mongo.db.js
├── middlewares
│ └── jwt.middleware.js
├── package-lock.json
├── package.json
├── resources
│ ├── APIs.js
│ ├── template-annotator.html
│ ├── template-generater.html
│ ├── template-notFinish.html
│ ├── template-notStart.html
│ └── template-owner.html
├── routers
│ ├── auth-controller.js
│ ├── community-controller.js
│ ├── db-controller.js
│ ├── email-controller.js
│ ├── file-controller.js
│ ├── integration-controller.js
│ ├── project-controller.js
│ ├── scripts-controller.js
│ ├── slack-controller.js
│ ├── srs-controller.js
│ └── user-controller.js
├── scripts
│ └── reveiwInfoMigration.js
├── server.js
├── services
│ ├── activelearning.service.js
│ ├── auth.service.js
│ ├── authForNoe.service.js
│ ├── community.service.js
│ ├── dataSet-service.js
│ ├── email-service.js
│ ├── file-service.js
│ ├── integration.service.js
│ ├── localFileSys.service.js
│ ├── project.service.js
│ ├── s3.service.js
│ ├── slack
│ │ ├── slack.js
│ │ ├── slackAnnotateModal.service.js
│ │ ├── slackBuildAppHome.service.js
│ │ ├── slackChat.service.js
│ │ ├── slackConversations.service.js
│ │ ├── slackUsers.service.js
│ │ └── utils
│ │ │ ├── accessToken.service.js
│ │ │ └── slack.utils.js
│ ├── sqs.service.js
│ ├── srs-service.js
│ ├── supercollider.service.js
│ └── user-service.js
├── swagger2.json
└── utils
│ ├── DB.OPERATIONS.js
│ ├── ImportDataset.util.js
│ ├── common.utils.js
│ ├── fileSystem.utils.js
│ ├── imgImporter.js
│ ├── logImporter.js
│ ├── mongoModel.utils.js
│ ├── s3.js
│ ├── sqs.js
│ ├── srsImporter.js
│ ├── sts.js
│ ├── taskSchedule.js
│ └── validator.js
├── docker-compose-host-db.yml
├── docker-compose.yml
└── docs
├── AWS-step-by-step-config-with-chart.pdf
├── manifest.yml
└── tutorial
├── annotator-screen.png
├── imdb-500.csv
└── project-screen.png
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Set the default behavior,
2 | # in case people don't have core.autocrlf set.
3 | * text=auto
4 | # Declares that files will always have CRLF line ends
5 | *.sh text eol=lf
6 | docker*.yml text eol=lf
7 | *Dockerfile text eol=lf
8 | *nginx.conf text eol=lf
--------------------------------------------------------------------------------
/.github/workflows/check-header.yml:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright 2019-2024 VMware, Inc.
3 | # SPDX-License-Identifier: Apache-2.0
4 | #
5 |
6 | name: check-header
7 |
8 | on:
9 | push:
10 | branches: ["**"]
11 | pull_request:
12 | branches: ['**']
13 |
14 | jobs:
15 | check-header:
16 | runs-on: ubuntu-latest # runs a test on Ubuntu
17 |
18 | env:
19 | GITHUB_CONTEXT: ${{ toJson(github) }}
20 |
21 | steps:
22 | - name: Checkout
23 | uses: actions/checkout@v3
24 | with:
25 | fetch-depth: 3
26 |
27 | - run: wget https://raw.githubusercontent.com/vmware/data-annotator-for-machine-learning/devops/check_headers.py
28 |
29 | - name: Check Header
30 | run: |
31 | chmod +x ./check_headers.py
32 | python ./check_headers.py -f "$(git diff --name-only --diff-filter=d $GITHUB_CONTEXT)"
33 |
--------------------------------------------------------------------------------
/.github/workflows/sonarcloud_scan_app.yml:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright 2019-2024 VMware, Inc.
3 | # SPDX-License-Identifier: Apache-2.0
4 | #
5 |
6 | name: sonarcloud_scan_app
7 |
8 | on:
9 | push:
10 | branches: ["**"]
11 | pull_request:
12 | branches: ['**']
13 |
14 | jobs:
15 | #sonar cloud scan job for annotation app
16 | scan_annotation_app:
17 | runs-on: ubuntu-latest
18 |
19 | #define variables to be used for SonarCloud scan
20 | env:
21 | SONAR_ORG: ${{ secrets.SONAR_ORG }}
22 |
23 | steps:
24 |
25 | - name: Checkout
26 | uses: actions/checkout@v3
27 | with:
28 | fetch-depth: 0
29 |
30 | - name: Checkout devops branch
31 | uses: actions/checkout@v3
32 | with:
33 | fetch-depth: 0
34 | ref: 'devops'
35 | path: 'devops'
36 |
37 | - name: SonarCloud setup for annotation-app
38 | working-directory: ./devops/sonar
39 | run: python ./config_sonar_project.py -ProjectName ${{ env.SONAR_ORG }}-annotation-app -ProjectKey ${{ env.SONAR_ORG }}-annotation-app -OrgKey ${{ env.SONAR_ORG }} -QualityGateName angular-client-gate -QualityGateConditions ./quality_gates/angular-client.json -SonarToken ${{ secrets.SONAR_TOKEN }}
40 |
41 | - name: SonarCloud Scan annotation-app
42 | uses: sonarsource/sonarcloud-github-action@master
43 | with:
44 | projectBaseDir: ./annotation-app
45 | args: >
46 | -Dsonar.organization=${{ env.SONAR_ORG }}
47 | -Dsonar.projectKey=${{ env.SONAR_ORG }}-annotation-app
48 | -Dsonar.test.exclusions=**/node_modules/**/*,*.md,*.txt,*.yml
49 | -Dsonar.coverage.exclusions=**
50 | #Set below secrets in your Github Actions secrets
51 | env:
52 | SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
53 | GITHUB_TOKEN: ${{ secrets.DATA_GITHUB_TOKEN }}
54 |
55 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea
2 | .DS_Store
3 |
4 | # annotation-app
5 | annotation-app/.angular
6 | annotation-app/node_modules
7 | annotation-app/.npmrc
8 | annotation-app/chart
9 | annotation-app/src/environments/environment.stg.ts
10 | annotation-app/src/environments/environment.test.ts
11 | # annotation-app/package-lock.json
12 | annotation-app/tsconfig.spec.json
13 | annotation-app/dist
14 |
15 |
16 | # annotation-service
17 | annotation-service/node_modules
18 | annotation-service/FILE_SYS
19 | annotation-service/config/app-local.js
20 | annotation-service/config/app-poc.js
21 |
22 |
23 | # active-learning-service
24 | *__pycache__*
25 | active-learning-service/venv/
26 | active-learning-service/.venv/
27 | active-learning-service/.python-version
28 | active-learning-service/.idea
29 | active-learning-service/logs
30 | active-learning-service/models
31 | active-learning-service/config/app_local.py
32 | active-learning-service/config/app_poc.py
--------------------------------------------------------------------------------
/NOTICE.txt:
--------------------------------------------------------------------------------
1 | Data Annotator for Machine Learning
2 | Copyright 2021 VMware, Inc.
3 |
4 | This product is licensed to you under the Apache 2.0 license (the "License"). You may not use this product except in compliance with the Apache 2.0 License.
5 |
6 | This product may include a number of subcomponents with separate copyright notices and license terms. Your use of these subcomponents is subject to the terms and conditions of the subcomponent's license, as noted in the LICENSE file.
7 |
8 |
--------------------------------------------------------------------------------
/RUN-WITH-DOCKER.md:
--------------------------------------------------------------------------------
1 | # Data Annotator for Machine Learning (DAML) run with docker
2 |
3 |
4 | ## Tools used
5 | Please go to [https://docs.docker.com/get-docker/](https://docs.docker.com/get-docker/) to download the proper docker version for your machine.
6 | - If your machine is **Windows / Mac** you can only use docker desktop, to run the application.
7 | - If your machine is **Linux** you also need to download docker-compose. [https://docs.docker.com/compose/install/](https://docs.docker.com/compose/install/)
8 |
9 | ## Start/End application
10 | In active-learning-service we use _en_core_web_md_ as the default spacy module if you want to replace it. you can directly replace it in the docker-compose file. eg. _- SPACY_MODEL=zh_core_web_md_ for spacy models ref: [https://spacy.io/models](https://spacy.io/models)
11 |
12 | - If your machine already installed MongoDB, and you want to use that as the database. you need to download the [docker-compose-host-db.yml](docker-compose-host-db.yml) file and use it to run the DAML application.
13 |
14 | Start the containers:
15 | ```bash
16 | docker compose -f docker-compose-host-db.yml up
17 | ```
18 | End the containers:
19 | ```bash
20 | docker compose -f docker-compose-host-db.yml down
21 | ```
22 |
23 | - Else you need to download the [docker-compose.yml](docker-compose.yml) file and use it to run the DAML application.
24 |
25 | Start the containers:
26 | ```bash
27 | docker compose -f docker-compose.yml up
28 | ```
29 | End the containers:
30 | ```bash
31 | docker compose -f docker-compose.yml down
32 | ```
33 |
34 | ## How to use
35 | Open `http://localhost:4200` with your browser, now you can use full of the DAML application functions.
36 |
37 | ## More commands
38 | For more commands you can reference here [docker compose commands](https://docs.docker.com/engine/reference/commandline/compose/#child-commands).
39 |
40 | ## DAML application docker images
41 | [https://hub.docker.com/search?q=vmware-daml-&type=image](https://hub.docker.com/search?q=vmware-daml-&type=image)
--------------------------------------------------------------------------------
/active-learning-service/Dockerfile:
--------------------------------------------------------------------------------
1 | # Copyright 2019-2021 VMware, Inc.
2 | # SPDX-License-Identifier: Apache-2.0
3 |
4 | FROM python:3.7.10
5 |
6 | WORKDIR /app
7 |
8 | COPY requirements.txt ./
9 | RUN pip install --no-cache-dir -r requirements.txt
10 | RUN python -m spacy download en_core_web_md
11 |
12 | COPY . /app
13 |
14 | EXPOSE 8000
15 |
16 | CMD [ "python", "manage.py","runserver","0.0.0.0:8000" ]
--------------------------------------------------------------------------------
/active-learning-service/config/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2019-2021 VMware, Inc.
2 | # SPDX-License-Identifier: Apache-2.0
3 |
4 |
--------------------------------------------------------------------------------
/active-learning-service/config/app_os.py:
--------------------------------------------------------------------------------
1 | # Copyright 2019-2021 VMware, Inc.
2 | # SPDX-License-Identifier: Apache-2.0
3 |
4 | import os
5 | app = {
6 |
7 | "MONGODB_URL": os.getenv("MONGODB_URL", "mongodb://localhost:27017/daml"),
8 | "MONGODB_COLLECTION": os.getenv("MONGODB_COLLECTION", "daml"),
9 | #If True will save datasets to local, If set USE_AWS=true set it to false
10 | "USE_LOCAL_FILE_SYS": os.getenv("USE_LOCAL_FILE_SYS", True),
11 |
12 | #If True, will save datasets to S3, shoud set USE_LOCAL_FILE_SYS=False
13 | "USE_AWS": os.getenv("USE_AWS", False),
14 | # AWS IAM
15 | "REGION": os.getenv("REGION", None),
16 | "AWS_ACCESS_KEY_ID": os.getenv("AWS_ACCESS_KEY_ID", None),
17 | "AWS_SECRET_ACCESS_KEY": os.getenv("AWS_SECRET_ACCESS_KEY", None),
18 | # AWS S3
19 | "S3_BUCKET_NAME": os.getenv("S3_BUCKET_NAME", None),
20 | "S3_ROLE_ARN": os.getenv("S3_ROLE_ARN", None),
21 |
22 | # spacy model default is en_core_web_md, NOTE: [sm: no word vectors] more: https://spacy.io/models
23 | "SPACY_MODEL": os.getenv("SPACY_MODEL", "en_core_web_md"),
24 |
25 | # optional token config
26 | "TOKEN_ALGORITHM": os.getenv("TOKEN_ALGORITHM", "HS256"),
27 | # !!! important 121ba6ff-64d6-4c1a-b6ef-dd6b95433064 just a random value get the value from environment or replace by yourslef
28 | # generate the key yourself. should keep the same with annotation-service TOKEN_SECRET_OR_PRIVATE_KEY
29 | "TOKEN_SECRET_OR_PRIVATE_KEY": os.getenv("TOKEN_SECRET_OR_PRIVATE_KEY", "121ba6ff-64d6-4c1a-b6ef-dd6b95433064"),
30 | # 01a406f3-e5f4-45b8-a722-cff17e9d8cf9 just a random value
31 | # generate the key yourself. django SECRET_KEY a random generated value https://docs.djangoproject.com/en/3.2/ref/settings/#std:setting-SECRET_KEY
32 | "DJANGO_SECRET_KEY": os.getenv("DJANGO_SECRET_KEY", "01a406f3-e5f4-45b8-a722-cff17e9d8cf9"),
33 |
34 | }
--------------------------------------------------------------------------------
/active-learning-service/config/config.py:
--------------------------------------------------------------------------------
1 | # Copyright 2019-2021 VMware, Inc.
2 | # SPDX-License-Identifier: Apache-2.0
3 |
4 | import os
5 | import importlib
6 | import logging
7 |
8 | # logging
9 | log = logging.getLogger('loop_al')
10 |
11 | # import modules
12 | env = os.getenv('SYS_ENV', 'os')
13 | path_file = f"config.app_{env}"
14 | app = importlib.import_module(path_file)
15 |
16 | config = app.app
17 | config["ENV"] = env
18 | log.info(f'[ ENV ] = {env}')
19 | log.info(f'[ CONFIG ] = {config}')
20 |
21 |
--------------------------------------------------------------------------------
/active-learning-service/config/constant.py:
--------------------------------------------------------------------------------
1 | # Copyright 2019-2021 VMware, Inc.
2 | # SPDX-License-Identifier: Apache-2.0
3 |
4 | cst={
5 | "QUERY_STRATEGY": {
6 | "POOL_BASED_SAMPLING": {
7 | "PB_UNS": "PB_UNS",
8 | "PB_MS": "PB_MS",
9 | "PB_ES": "PB_ES",
10 | },
11 | "RANKED_BATCH_MODE": {
12 | "RBM_UNBS": "RBM_UNBS",
13 | },
14 | },
15 | "ESTIMATOR": {
16 | "KNC": "KNC",
17 | "GBC": "GBC",
18 | "RFC": "RFC",
19 | },
20 | }
--------------------------------------------------------------------------------
/active-learning-service/logs/main.log:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vmware/data-annotator-for-machine-learning/ccc6dbfcc0bd680557f4068df89be5f20c93fcd9/active-learning-service/logs/main.log
--------------------------------------------------------------------------------
/active-learning-service/logs/main_debug.log:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vmware/data-annotator-for-machine-learning/ccc6dbfcc0bd680557f4068df89be5f20c93fcd9/active-learning-service/logs/main_debug.log
--------------------------------------------------------------------------------
/active-learning-service/manage.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | # Copyright 2019-2021 VMware, Inc.
4 | # SPDX-License-Identifier: Apache-2.0
5 |
6 |
7 | """Django's command-line utility for administrative tasks."""
8 | import os
9 | import sys
10 | from src.utils.modules import download_spacy_module
11 |
12 |
13 | def main():
14 | """Run administrative tasks."""
15 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'mysite.settings')
16 | try:
17 | from django.core.management import execute_from_command_line
18 | except ImportError as exc:
19 | raise ImportError(
20 | "Couldn't import Django. Are you sure it's installed and "
21 | "available on your PYTHONPATH environment variable? Did you "
22 | "forget to activate a virtual environment?"
23 | ) from exc
24 |
25 | download_spacy_module()
26 | execute_from_command_line(sys.argv)
27 |
28 | if __name__ == '__main__':
29 | main()
30 |
--------------------------------------------------------------------------------
/active-learning-service/models/porojectName_model.pkl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vmware/data-annotator-for-machine-learning/ccc6dbfcc0bd680557f4068df89be5f20c93fcd9/active-learning-service/models/porojectName_model.pkl
--------------------------------------------------------------------------------
/active-learning-service/mysite/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2019-2021 VMware, Inc.
2 | # SPDX-License-Identifier: Apache-2.0
3 |
4 |
--------------------------------------------------------------------------------
/active-learning-service/mysite/asgi.py:
--------------------------------------------------------------------------------
1 | # Copyright 2019-2021 VMware, Inc.
2 | # SPDX-License-Identifier: Apache-2.0
3 |
4 | """
5 | ASGI config for mysite project.
6 |
7 | It exposes the ASGI callable as a module-level variable named ``application``.
8 |
9 | For more information on this file, see
10 | https://docs.djangoproject.com/en/dev/howto/deployment/asgi/
11 | """
12 |
13 | import os
14 |
15 | from django.core.asgi import get_asgi_application
16 |
17 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'mysite.settings')
18 |
19 | application = get_asgi_application()
20 |
--------------------------------------------------------------------------------
/active-learning-service/mysite/urls.py:
--------------------------------------------------------------------------------
1 | # Copyright 2019-2021 VMware, Inc.
2 | # SPDX-License-Identifier: Apache-2.0
3 |
4 | """mysite URL Configuration
5 |
6 | The `urlpatterns` list routes URLs to views. For more information please see:
7 | https://docs.djangoproject.com/en/dev/topics/http/urls/
8 | Examples:
9 | Function views
10 | 1. Add an import: from my_app import views
11 | 2. Add a URL to urlpatterns: path('', views.home, name='home')
12 | Class-based views
13 | 1. Add an import: from other_app.views import Home
14 | 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
15 | Including another URLconf
16 | 1. Import the include() function: from django.urls import include, path
17 | 2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
18 | """
19 | from django.contrib import admin
20 | from django.urls import path,include
21 | from src import views
22 |
23 | urlpatterns = [
24 | path('api/poc', views.api_poc),
25 | path('api/al/sr/vector', views.al_srs_vector),
26 | path('api/al/model/train', views.al_train_model),
27 | path('api/al/model/query', views.al_query_instance),
28 | path('api/al/model/teach', views.al_teach_model),
29 | path('health', views.health, name='health'),
30 | path('', views.health, name='health'),
31 |
32 | ]
33 |
--------------------------------------------------------------------------------
/active-learning-service/mysite/wsgi.py:
--------------------------------------------------------------------------------
1 | # Copyright 2019-2021 VMware, Inc.
2 | # SPDX-License-Identifier: Apache-2.0
3 |
4 | """
5 | WSGI config for mysite project.
6 |
7 | It exposes the WSGI callable as a module-level variable named ``application``.
8 |
9 | For more information on this file, see
10 | https://docs.djangoproject.com/en/dev/howto/deployment/wsgi/
11 | """
12 |
13 | import os
14 |
15 | from django.core.wsgi import get_wsgi_application
16 |
17 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'mysite.settings')
18 |
19 | application = get_wsgi_application()
20 |
--------------------------------------------------------------------------------
/active-learning-service/requirements.txt:
--------------------------------------------------------------------------------
1 | pymongo~=3.11.3
2 | mongoengine~=0.23.0
3 | Django~=3.2
4 |
5 | numpy~=1.19.5
6 | pandas~=1.0.3
7 | scikit-learn~=0.24.2
8 | modAL-python~=0.3.6
9 | PyYAML~=5.4.1
10 | boto3~=1.14.7
11 | botocore~=1.17.7
12 | requests~=2.24.0
13 | fastai~=1.0.61
14 | spacy~=3.0.6
15 |
16 | PyJWT~=2.0.1
17 | cryptography~=3.4.7
--------------------------------------------------------------------------------
/active-learning-service/src/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2019-2021 VMware, Inc.
2 | # SPDX-License-Identifier: Apache-2.0
3 |
4 |
--------------------------------------------------------------------------------
/active-learning-service/src/admin.py:
--------------------------------------------------------------------------------
1 | # Copyright 2019-2021 VMware, Inc.
2 | # SPDX-License-Identifier: Apache-2.0
3 |
4 | from django.contrib import admin
5 |
6 | # Register your models here.
7 |
--------------------------------------------------------------------------------
/active-learning-service/src/al/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2019-2021 VMware, Inc.
2 | # SPDX-License-Identifier: Apache-2.0
3 |
4 |
--------------------------------------------------------------------------------
/active-learning-service/src/al/get_vectors.py:
--------------------------------------------------------------------------------
1 | # Copyright 2019-2021 VMware, Inc.
2 | # SPDX-License-Identifier: Apache-2.0
3 |
4 | import logging
5 | import time
6 |
7 | from config.config import config
8 | import numpy as np
9 | import spacy
10 |
11 | from src.exceptions.base_exceptions import NetWorkException
12 |
13 | nlp = spacy.load(config['SPACY_MODEL'])
14 | log = logging.getLogger('loop_al')
15 |
16 |
17 | def os_text_vectors(sr_text):
18 |
19 | vectors = []
20 | for text in sr_text:
21 | average = []
22 | for token in nlp(text):
23 | average.append(nlp.vocab[token.text].vector)
24 | vectors.append(np.mean(average, axis=0))
25 | return vectors
26 |
27 |
28 | def request_text_vectors(sr_text):
29 | star_time = time.time()
30 | vectors = os_text_vectors(sr_text)
31 | log.info(f'Response Time(in secs): {int(time.time() - star_time)}')
32 | return vectors
33 |
--------------------------------------------------------------------------------
/active-learning-service/src/al/project_service.py:
--------------------------------------------------------------------------------
1 | # Copyright 2019-2021 VMware, Inc.
2 | # SPDX-License-Identifier: Apache-2.0
3 |
4 | from src.db.mongo_connect import mongo_client
5 |
6 |
7 | def pro_collection():
8 | db = mongo_client()
9 | return db["projects"]
10 |
11 |
12 | def find_project_by_name(project_name):
13 | projects = pro_collection()
14 | return projects.find({"projectName": project_name})
15 |
16 |
17 | def update_project(conditions, update):
18 | projects = pro_collection()
19 | projects.find_one_and_update(conditions, update)
20 |
21 |
22 | def update_end_condition(sr_ids, project_name):
23 | if len(sr_ids) < 10:
24 | # add a stop condition
25 | conditions = {"projectName": project_name}
26 | update = {"$set": {"al.alFailed": True}}
27 | update_project(conditions, update)
28 | return True
29 |
--------------------------------------------------------------------------------
/active-learning-service/src/al/query_instance.py:
--------------------------------------------------------------------------------
1 | # Copyright 2019-2021 VMware, Inc.
2 | # SPDX-License-Identifier: Apache-2.0
3 |
4 | import logging
5 | import os
6 | import time
7 |
8 | import numpy as np
9 | import pickle
10 | from config.constant import cst
11 |
12 | log = logging.getLogger('loop_al')
13 |
14 |
15 | def query_instance(df_pool, model_name, n_query, query_strategy):
16 | log.info(f'query instance')
17 | start_time = time.time()
18 |
19 | if model_name == None:
20 | print("No dataset file specified!")
21 | return
22 | elif not os.path.exists(model_name):
23 | print("Source file does not exist:", model_name)
24 | return
25 |
26 | # load the model from disk
27 | with open(model_name, 'rb') as model_al:
28 | learner = pickle.load(model_al)
29 | x_pool = np.array(df_pool['sr_text'])
30 | y_pool = np.array(df_pool['ids'])
31 |
32 | query_result = []
33 | if query_strategy == cst['QUERY_STRATEGY']['RANKED_BATCH_MODE']['RBM_UNBS']:
34 | query_idx, vector = learner.query(x_pool)
35 | sr_id = y_pool[query_idx]
36 | query_result = list(sr_id)
37 | else:
38 | for i in range(n_query):
39 | query_idx, vector = learner.query(x_pool)
40 | sr_id = y_pool[query_idx]
41 | query_result.append(sr_id[0])
42 |
43 | x_pool = np.delete(x_pool, query_idx, axis=0)
44 | y_pool = np.delete(y_pool, query_idx, axis=0)
45 |
46 | log.info(f'query instance end (in secs): {int(time.time() - start_time)}')
47 | return query_result
48 |
49 |
--------------------------------------------------------------------------------
/active-learning-service/src/al/retry_service.py:
--------------------------------------------------------------------------------
1 | # Copyright 2019-2021 VMware, Inc.
2 | # SPDX-License-Identifier: Apache-2.0
3 |
4 | import json
5 |
6 | from src.al.project_service import update_project
7 |
8 |
9 | def support_al_retry(request, function_name):
10 |
11 | if request.method == "POST" and request.body:
12 | req = json.loads(request.body)
13 | else:
14 | return
15 |
16 | if function_name == "active_learning_train":
17 | update = {"$set": {"al.training": False}}
18 | elif function_name == "active_learning_query":
19 | update = {"$set": {"al.querying": False}}
20 | elif function_name == "active_learning_teach":
21 | update = {"$set": {"al.teaching": False}}
22 | else:
23 | return
24 |
25 | conditions = {"projectName": req['projectName']}
26 | update_project(conditions, update)
--------------------------------------------------------------------------------
/active-learning-service/src/al/separate_data.py:
--------------------------------------------------------------------------------
1 | # Copyright 2019-2021 VMware, Inc.
2 | # SPDX-License-Identifier: Apache-2.0
3 |
4 | import pickle
5 | import random
6 | import numpy as np
7 | import pandas as pd
8 |
9 |
10 | # common function to separate sr data 80% for train and 20% for test
11 | def separate_data(request):
12 |
13 | sr_ids = request['ids']
14 |
15 | id_test, x_test, y_test, x_teach, y_teach = [], [], [], [], []
16 | sr_len = int(len(sr_ids) * 0.8)
17 |
18 | sr_selected = random.sample(range(0, len(sr_ids)), sr_len)
19 |
20 | for index, sr_id in enumerate(sr_ids):
21 | if index in sr_selected:
22 | # x_teach.append(request['sr_vectors'][index])
23 | x_teach.append(request['sr_text'][index])
24 | y_teach.append(request['labels'][index])
25 | else:
26 | id_test.append(sr_id)
27 | # x_test.append(request['sr_vectors'][index])
28 | x_test.append(request['sr_text'][index])
29 | y_test.append(request['labels'][index])
30 |
31 | return {
32 | "x_teach": np.array(x_teach),
33 | "y_teach": np.array(y_teach),
34 | "x_test": np.array(x_test),
35 | "y_test": np.array(y_test),
36 | "id_test": id_test,
37 | "sr_len": sr_len
38 | }
39 |
40 |
41 | # load vector model return sr vectors
42 | def vector_sr(sr_array, model_file, project_type, obj_col, num_col):
43 | # use for tabular one-hot-encodding
44 | if project_type == 'tabular':
45 | num_sr, obj_sr = [], []
46 | if num_col:
47 | num_sr = pd.DataFrame(sr_array, columns=num_col).replace("", 0).replace(np.nan, 0)
48 | if not obj_col:
49 | sr_array = np.array(num_sr)
50 | if obj_col:
51 | obj_sr = pd.DataFrame(sr_array, columns=obj_col, dtype=np.str)
52 | with open(model_file, 'rb') as model_vector:
53 | vaporizer = pickle.load(model_vector)
54 | obj_sr = vaporizer.transform(obj_sr).toarray()
55 | if not num_col:
56 | sr_array = np.array(obj_sr)
57 | if num_col and obj_col:
58 | # combine number column and categorical column vector together
59 | sr_array = np.concatenate((obj_sr, num_sr), axis=1)
60 | else:
61 | # text project not used now
62 | with open(model_file, 'rb') as model_vector:
63 | vaporizer = pickle.load(model_vector)
64 | sr_array = vaporizer.transform(sr_array).toarray()
65 | return sr_array
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
--------------------------------------------------------------------------------
/active-learning-service/src/al/teach_model.py:
--------------------------------------------------------------------------------
1 | # Copyright 2019-2021 VMware, Inc.
2 | # SPDX-License-Identifier: Apache-2.0
3 |
4 | import logging
5 | import os
6 | import time
7 |
8 | import numpy as np
9 | import pickle
10 |
11 | log = logging.getLogger('loop_al')
12 |
13 |
14 | def teach_model(model_name, data, test_sr):
15 | log.info(f'teach model')
16 | start_time = time.time()
17 |
18 | if model_name == None:
19 | print("No dataset file specified!")
20 | return
21 | elif not os.path.exists(model_name):
22 | print("Source file does not exist:", model_name)
23 | return
24 |
25 | test_sr_x = test_sr['sr_text']
26 | sr_len = data['sr_len']
27 | x_test = np.concatenate((data['x_test'], test_sr_x), axis=0)
28 | y_test = np.concatenate((data['y_test'], test_sr['labels']), axis=0)
29 |
30 | with open(model_name, 'rb') as model_al:
31 | learner = pickle.load(model_al)
32 |
33 | # we can tech several records once
34 | x_row = data['x_teach']
35 | y_row = data['y_teach']
36 | learner.teach(X=x_row, y=y_row)
37 | accuracy = learner.score(x_test, y_test)
38 | log.info(f'Accuracy after teach with {sr_len} tickets {accuracy}')
39 |
40 | with open(model_name, 'wb') as model_al:
41 | pickle.dump(learner, model_al)
42 |
43 | log.info(f'teach model end (in secs): {int(time.time() - start_time)}')
44 | return {"accuracy": accuracy, "test": data['id_test']}
45 |
46 |
47 |
--------------------------------------------------------------------------------
/active-learning-service/src/al/train_model.py:
--------------------------------------------------------------------------------
1 | # Copyright 2019-2021 VMware, Inc.
2 | # SPDX-License-Identifier: Apache-2.0
3 |
4 | import logging
5 | import time
6 | import numpy as np
7 | import pickle
8 |
9 | from config.constant import cst
10 | from sklearn.ensemble import RandomForestClassifier, GradientBoostingClassifier
11 | from sklearn.feature_extraction.text import TfidfVectorizer
12 | from sklearn.neighbors import KNeighborsClassifier
13 | from modAL.models import ActiveLearner
14 | from functools import partial
15 | from modAL.batch import uncertainty_batch_sampling
16 | from modAL.uncertainty import uncertainty_sampling, margin_sampling, entropy_sampling
17 |
18 | modelDir = "models/"
19 | log = logging.getLogger('loop_al')
20 |
21 |
22 | def train_model(data, project_id, estimator, query_strategy):
23 | log.info(f'train model')
24 | start_time = time.time()
25 |
26 | x_test = data['x_test']
27 | y_test = data['y_test']
28 |
29 | # initial model train model
30 | if estimator == cst['ESTIMATOR']['KNC']:
31 | estimator = KNeighborsClassifier()
32 | elif estimator == cst['ESTIMATOR']['GBC']:
33 | estimator = GradientBoostingClassifier()
34 | elif estimator == cst['ESTIMATOR']['RFC']:
35 | estimator = RandomForestClassifier()
36 |
37 | if query_strategy == cst['QUERY_STRATEGY']['POOL_BASED_SAMPLING']['PB_UNS']:
38 | query_strategy = uncertainty_sampling
39 | elif query_strategy == cst['QUERY_STRATEGY']['POOL_BASED_SAMPLING']['PB_MS']:
40 | query_strategy = margin_sampling
41 | elif query_strategy == cst['QUERY_STRATEGY']['POOL_BASED_SAMPLING']['PB_ES']:
42 | query_strategy = entropy_sampling
43 | elif query_strategy == cst['QUERY_STRATEGY']['RANKED_BATCH_MODE']['RBM_UNBS']:
44 | batch_size = 10
45 | query_strategy = partial(uncertainty_batch_sampling, n_instances=batch_size)
46 |
47 | learner = ActiveLearner(estimator=estimator, query_strategy=query_strategy, X_training=data['x_teach'], y_training=data['y_teach'])
48 |
49 | # save the model to disk
50 | model_name = project_id + "_model.pkl"
51 | with open('./' + modelDir + model_name, 'wb') as knn_pickle:
52 | pickle.dump(learner, knn_pickle)
53 |
54 | initial_accuracy = learner.score(x_test, y_test)
55 |
56 | log.info(f'Initial accuracy: { initial_accuracy } train model end (in secs): {int(time.time() - start_time)}')
57 | return {"accuracy": initial_accuracy, "model": model_name, "test": data['id_test']}
58 |
--------------------------------------------------------------------------------
/active-learning-service/src/apps.py:
--------------------------------------------------------------------------------
1 | # Copyright 2019-2021 VMware, Inc.
2 | # SPDX-License-Identifier: Apache-2.0
3 |
4 | from django.apps import AppConfig
5 |
6 |
7 | class SrcConfig(AppConfig):
8 | name = 'src'
9 |
--------------------------------------------------------------------------------
/active-learning-service/src/aws/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2019-2021 VMware, Inc.
2 | # SPDX-License-Identifier: Apache-2.0
3 |
4 |
--------------------------------------------------------------------------------
/active-learning-service/src/aws/s3.py:
--------------------------------------------------------------------------------
1 | # Copyright 2019-2021 VMware, Inc.
2 | # SPDX-License-Identifier: Apache-2.0
3 |
4 | import logging
5 | import boto3
6 | import botocore
7 | from botocore.exceptions import ClientError
8 | from .sts import aws_credentials
9 | from config.config import config
10 |
11 |
12 | def s3_client(token):
13 | cred = aws_credentials(token)
14 |
15 | return boto3.client(
16 | 's3',
17 | aws_access_key_id=cred['accessKeyId'],
18 | aws_secret_access_key=cred['secretAccessKey'],
19 | aws_session_token=cred['sessionToken']
20 | )
21 |
22 |
23 | def upload_file_to_s3(file_name, object_name, token):
24 | if not check_aws_config():
25 | return False
26 | try:
27 | s3_client(token).upload_file(file_name, config["S3_BUCKET_NAME"], object_name)
28 | except ClientError as e:
29 | logging.error(e)
30 | return False
31 | return True
32 |
33 |
34 | def download_file_from_s3(key, local_name, token):
35 | if not check_aws_config():
36 | return False
37 | try:
38 | s3_client(token).download_file(config["S3_BUCKET_NAME"], key, local_name)
39 | except botocore.exceptions.ClientError as e:
40 | if e.response['Error']['Code'] == "404":
41 | print("The object does not exist.")
42 | else:
43 | logging.error(e)
44 | return False
45 | return True
46 |
47 |
48 | def check_aws_config():
49 | aws_config = False
50 | if "ESP" in config and config["ESP"] or config["USE_AWS"]:
51 | aws_config = True
52 | elif config["USE_LOCAL_FILE_SYS"]:
53 | aws_config = False
54 | return aws_config
55 |
56 |
--------------------------------------------------------------------------------
/active-learning-service/src/aws/sts.py:
--------------------------------------------------------------------------------
1 | # Copyright 2019-2021 VMware, Inc.
2 | # SPDX-License-Identifier: Apache-2.0
3 |
4 |
5 | import boto3
6 | import requests
7 | import json
8 |
9 | from config.config import config
10 |
11 |
12 | def sts_role(arn, session_name):
13 |
14 | sts = boto3.client(
15 | 'sts',
16 | region_name=config["REGION"],
17 | aws_access_key_id=config["AWS_ACCESS_KEY_ID"],
18 | aws_secret_access_key=config["AWS_SECRET_ACCESS_KEY"]
19 | )
20 |
21 | data = sts.assume_role(
22 | DurationSeconds=1800,
23 | RoleArn=arn,
24 | RoleSessionName=session_name
25 | )
26 | data = data['Credentials']
27 |
28 | return {
29 | 'accessKeyId': data['AccessKeyId'],
30 | 'secretAccessKey': data['SecretAccessKey'],
31 | 'sessionToken': data['SessionToken']
32 | }
33 |
34 |
35 | def esp_sts_credentials(token):
36 | data = {
37 | "iamRoleArn": config["S3_ROLE_ARN"],
38 | "externalId": config["S3_EXTERNAL"],
39 | "region": config["REGION"],
40 | "durationInSeconds": 1800
41 | }
42 | headers = {"Authorization": token}
43 |
44 | credentials = requests.get(config["ESP_AUTHORIZE_URL"], params=data, headers=headers)
45 | credentials = json.loads(credentials.content)
46 |
47 | return credentials
48 |
49 |
50 | def aws_credentials(token):
51 | if "ESP" in config and config["ESP"]:
52 | credentials = esp_sts_credentials(token)
53 | else:
54 | credentials = sts_role(config["S3_ROLE_ARN"], 'loop_al')
55 |
56 | return credentials
57 |
--------------------------------------------------------------------------------
/active-learning-service/src/db/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2019-2021 VMware, Inc.
2 | # SPDX-License-Identifier: Apache-2.0
3 |
4 |
--------------------------------------------------------------------------------
/active-learning-service/src/db/mongo_connect.py:
--------------------------------------------------------------------------------
1 | # Copyright 2019-2021 VMware, Inc.
2 | # SPDX-License-Identifier: Apache-2.0
3 |
4 | import pymongo
5 |
6 | from config.config import config
7 |
8 |
9 | def mongo_client():
10 | client = pymongo.MongoClient(config["MONGODB_URL"])
11 | db = client[config["MONGODB_COLLECTION"]]
12 | return db
13 |
--------------------------------------------------------------------------------
/active-learning-service/src/exceptions/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vmware/data-annotator-for-machine-learning/ccc6dbfcc0bd680557f4068df89be5f20c93fcd9/active-learning-service/src/exceptions/__init__.py
--------------------------------------------------------------------------------
/active-learning-service/src/exceptions/base_exceptions.py:
--------------------------------------------------------------------------------
1 | # Copyright 2019-2021 VMware, Inc.
2 | # SPDX-License-Identifier: Apache-2.0
3 |
4 |
5 | class NetWorkException(Exception):
6 | def __init__(self, code, message):
7 | self.code = code
8 | self.message = message
9 |
10 |
11 | class AuthException(Exception):
12 | def __init__(self, code, message):
13 | self.code = code
14 | self.message = message
--------------------------------------------------------------------------------
/active-learning-service/src/migrations/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2019-2021 VMware, Inc.
2 | # SPDX-License-Identifier: Apache-2.0
3 |
4 |
--------------------------------------------------------------------------------
/active-learning-service/src/models.py:
--------------------------------------------------------------------------------
1 | # Copyright 2019-2021 VMware, Inc.
2 | # SPDX-License-Identifier: Apache-2.0
3 |
4 | import mongoengine
5 |
6 |
7 | class Srs(mongoengine.Document):
8 | id = mongoengine.ObjectIdField(required=True)
9 | problemCategory=mongoengine.StringField(required=True)
10 | projectName=mongoengine.StringField(required=True)
11 | userInputsLength=mongoengine.StringField(required=True)
12 |
--------------------------------------------------------------------------------
/active-learning-service/src/tests.py:
--------------------------------------------------------------------------------
1 | # Copyright 2019-2021 VMware, Inc.
2 | # SPDX-License-Identifier: Apache-2.0
3 |
4 | # Create your tests here.
5 | from config.config import config
6 |
7 |
8 | def api_poc(req):
9 | return config
10 |
--------------------------------------------------------------------------------
/active-learning-service/src/urls.py:
--------------------------------------------------------------------------------
1 | # Copyright 2019-2021 VMware, Inc.
2 | # SPDX-License-Identifier: Apache-2.0
3 |
4 | from django.urls import path
5 | from . import views
6 |
7 |
--------------------------------------------------------------------------------
/active-learning-service/src/utils/JSONEncoder.py:
--------------------------------------------------------------------------------
1 | # Copyright 2019-2021 VMware, Inc.
2 | # SPDX-License-Identifier: Apache-2.0
3 |
4 | import json
5 | from bson import ObjectId
6 | import datetime
7 |
8 |
9 | # to handle the objectID and datetime
10 | class JSONEncoder(json.JSONEncoder):
11 | def default(self, o):
12 | if isinstance(o, ObjectId):
13 | return str(o)
14 | if isinstance(o, datetime.datetime):
15 | return o.strftime('%Y-%m-%d %H:%M:%S')
16 | return json.JSONEncoder.default(self, o)
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/active-learning-service/src/utils/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2019-2021 VMware, Inc.
2 | # SPDX-License-Identifier: Apache-2.0
3 |
4 |
--------------------------------------------------------------------------------
/active-learning-service/src/utils/common.py:
--------------------------------------------------------------------------------
1 | # Copyright 2019-2021 VMware, Inc.
2 | # SPDX-License-Identifier: Apache-2.0
3 |
4 | import json
5 | import logging
6 | import time
7 | import traceback
8 |
9 | from django.http import JsonResponse
10 |
11 | from src.al.retry_service import support_al_retry
12 | from src.exceptions.base_exceptions import AuthException
13 | from src.utils.jwtVerification import verification_token
14 |
15 | from config.config import config
16 |
17 | log = logging.getLogger('loop_al')
18 | log.info(f'[ config ]={config}')
19 |
20 | # common function to handle request
21 | def request_handle(request, fun):
22 | start_time = time.time()
23 | log.info(f'[ {request.method}{request.path} ] request')
24 |
25 | try:
26 | # validate user and token
27 | verification_token(request)
28 | # business logic function
29 | res = fun(request)
30 |
31 | except AuthException as e:
32 | JsonResponse.status_code = 401
33 | res = {"status": "ERROR", "data": str(e)}
34 | log.error(f'{e}, {traceback.format_exc()}')
35 | except Exception as e:
36 | # support active learning retry
37 | support_al_retry(request, fun.__name__)
38 | JsonResponse.status_code = 500
39 | res = {"status": "ERROR", "data": str(e)}
40 | log.error(f'{e}, {traceback.format_exc()}')
41 |
42 | log.info(f'[ {request.method}{request.path} ] response time (in secs): {int(time.time() - start_time)}')
43 | return JsonResponse(res)
--------------------------------------------------------------------------------
/active-learning-service/src/utils/fileSystem.py:
--------------------------------------------------------------------------------
1 |
2 | # Copyright 2019-2021 VMware, Inc.
3 | # SPDX-License-Identifier: Apache-2.0
4 |
5 | import logging
6 | import os
7 | import src.aws.s3 as S3
8 |
9 |
10 | log = logging.getLogger('loop_al')
11 |
12 |
13 | def upload_file(remote_file, local_file, token):
14 | file_path = remote_file
15 | if not os.path.exists(local_file):
16 | log.error(f"LOCAL FILE NOT EXIST {local_file}")
17 | raise Exception(500, f"LOCAL FILE NOT EXIST {local_file}")
18 |
19 | if not S3.check_aws_config():
20 | file_path = local_file
21 | else:
22 | S3.upload_file_to_s3(local_file, remote_file, token)
23 |
24 | return file_path
25 |
26 |
27 | def download_file(condition, remote_file, local_file, token):
28 | if not S3.check_aws_config():
29 | if not os.path.exists(local_file):
30 | log.error(f"LOCAL FILE NOT EXIST {local_file}")
31 | raise Exception(500, f"LOCAL FILE NOT EXIST {local_file}")
32 | elif condition:
33 | if not os.path.exists(local_file):
34 | S3.download_file_from_s3(remote_file, local_file, token)
35 | else:
36 | S3.download_file_from_s3(remote_file, local_file, token)
37 |
--------------------------------------------------------------------------------
/active-learning-service/src/utils/jwtVerification.py:
--------------------------------------------------------------------------------
1 | # Copyright 2019-2021 VMware, Inc.
2 | # SPDX-License-Identifier: Apache-2.0
3 |
4 | import jwt
5 | from config.config import config
6 | import json
7 | import requests
8 | import logging
9 |
10 | from src.exceptions.base_exceptions import NetWorkException, AuthException
11 |
12 | log = logging.getLogger('loop_al')
13 | public_key = None
14 |
15 |
16 | def verification_token(request):
17 |
18 | if "ESP" in config and config["ESP"]:
19 | pk = obtain_public_key()
20 | key = bytes(pk['key'].replace("RSA ", ""), encoding="utf8")
21 | algorithms = pk['alg']
22 | else:
23 | key = config["TOKEN_SECRET_OR_PRIVATE_KEY"]
24 | algorithms = config["TOKEN_ALGORITHM"]
25 |
26 | if "Authorization" not in request.headers:
27 | raise AuthException(401, f"missing token in header['Authorization']")
28 |
29 | token = request.headers["Authorization"]
30 |
31 | try:
32 | decode = jwt.decode(token, key, algorithms=[algorithms])
33 | except Exception as e:
34 | raise AuthException(401, f"invalid token: {e}")
35 |
36 | if request.method == "POST" and request.body:
37 | req = json.loads(request.body)
38 | if "user" in req and req["user"] != decode["email"]:
39 | raise AuthException(401, "invalid user or token")
40 |
41 |
42 | def obtain_public_key():
43 | global public_key
44 |
45 | if public_key == None:
46 | res = requests.get(config['TOKEN_SECRET_OR_PRIVATE_KEY'])
47 | if res.status_code == 200:
48 | public_key = res.json()
49 | else:
50 | raise NetWorkException(res.status_code, f"Request token public key fail: {res}")
51 |
52 | return public_key
--------------------------------------------------------------------------------
/active-learning-service/src/utils/modules.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | # Copyright 2019-2021 VMware, Inc.
4 | # SPDX-License-Identifier: Apache-2.0
5 |
6 | import os
7 | import importlib
8 | from config.config import config
9 |
10 |
11 | def download_spacy_module():
12 |
13 | print(f'[ MODULE ] {config["SPACY_MODEL"]}')
14 | is_model_exist = is_setup_module(config['SPACY_MODEL'])
15 | if is_model_exist:
16 | return
17 | else:
18 | module = f"python -m spacy download {config['SPACY_MODEL']}"
19 | try:
20 | print(f'[ MODULE ] [ DOWNLOAD ]: {module}')
21 | os.system(module)
22 | except:
23 | # if error occurs will try again
24 | print(f'[ ERROR ] [ DOWNLOAD ]: {module}')
25 | print(f'[ RETRY ] [ DOWNLOAD ]: {module}')
26 | os.system(module)
27 |
28 |
29 | def is_setup_module(name):
30 | try:
31 | importlib.import_module(name)
32 | return True
33 | except:
34 | return False
--------------------------------------------------------------------------------
/active-learning-service/src/views.py:
--------------------------------------------------------------------------------
1 |
2 | # Copyright 2019-2021 VMware, Inc.
3 | # SPDX-License-Identifier: Apache-2.0
4 |
5 | import json
6 | from django.http import JsonResponse
7 | from django.views.decorators.csrf import csrf_exempt
8 | from django.views.decorators.http import require_GET, require_POST
9 |
10 | from .al.activelearning import active_learning_query, active_learning_train, active_learning_teach
11 |
12 | from .al.vector_sr import srs_vector
13 | from .utils.common import request_handle
14 | import src.tests as poc
15 |
16 |
17 | # vector all sr data
18 | @require_POST
19 | def al_srs_vector(request):
20 | return request_handle(request, srs_vector)
21 |
22 |
23 | # active learning train a model
24 | @require_POST
25 | def al_train_model(request):
26 | return request_handle(request, active_learning_train)
27 |
28 |
29 | # active learning query instance from model
30 | @require_POST
31 | def al_query_instance(request):
32 | return request_handle(request, active_learning_query)
33 |
34 |
35 | # active learning teach a model
36 | @require_POST
37 | def al_teach_model(request):
38 | return request_handle(request, active_learning_teach)
39 |
40 |
41 | # health check
42 | @require_GET
43 | def health(request):
44 | return JsonResponse({"status": "OK"})
45 |
46 |
47 | # api_poc
48 | @require_GET
49 | def api_poc(request):
50 | return request_handle(request, poc.api_poc)
51 |
--------------------------------------------------------------------------------
/annotation-app/.browserslistrc:
--------------------------------------------------------------------------------
1 | # This file is used by the build system to adjust CSS and JS output to support the specified browsers below.
2 | # For additional information regarding the format and rule options, please see:
3 | # https://github.com/browserslist/browserslist#queries
4 |
5 | # For the full list of supported browsers by the Angular framework, please see:
6 | # https://angular.io/guide/browser-support
7 |
8 | # You can see what browsers were selected by your queries by running:
9 | # npx browserslist
10 |
11 | last 1 Chrome version
12 | last 1 Firefox version
13 | last 2 Edge major versions
14 | last 2 Safari major versions
15 | last 2 iOS major versions
16 | Firefox ESR
17 |
--------------------------------------------------------------------------------
/annotation-app/.prettierignore:
--------------------------------------------------------------------------------
1 | package.json
2 | package-lock.json
3 | node_modules
4 |
--------------------------------------------------------------------------------
/annotation-app/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "printWidth": 120,
3 | "singleQuote": true,
4 | "trailingComma": "all",
5 | "tabWidth": 2
6 | }
--------------------------------------------------------------------------------
/annotation-app/Dockerfile:
--------------------------------------------------------------------------------
1 | # Copyright 2019-2022 VMware, Inc.
2 | # SPDX-License-Identifier: Apache-2.0
3 |
4 | ### STAGE 1: Build ###
5 | FROM node:16-alpine as builder
6 | COPY package*.json .
7 | RUN npm config set registry http://registry.npmjs.org/ && npm i && mkdir /app && cp -R ./node_modules ./app
8 | WORKDIR /app
9 | COPY . .
10 | #ARG BUILD_ENV=production
11 | #RUN npm run build -- -c $BUILD_ENV
12 | RUN npm run build
13 |
14 | ### STAGE 2: Setup ###
15 | FROM nginx:1.13.5-alpine
16 | COPY nginx.conf /etc/nginx/conf.d/default.conf
17 | COPY --from=builder /app/docker-entrypoint.sh /
18 | COPY --from=builder /app/dist /usr/share/nginx/html
19 | EXPOSE 4200
20 | ENTRYPOINT ["/docker-entrypoint.sh"]
21 |
--------------------------------------------------------------------------------
/annotation-app/build-script.js:
--------------------------------------------------------------------------------
1 | /***
2 | *
3 | * Copyright 2019-2024 VMware, Inc.
4 | * SPDX-License-Identifier: Apache-2.0
5 | *
6 | ***/
7 |
8 | const fs = require('fs');
9 | const fse = require('fs-extra');
10 | const concat = require('concat');
11 |
12 | const bundleFileName = 'micro-bundle-loop.js';
13 | const path = './dist/';
14 | const filesToConcat = [];
15 |
16 | const buildFiles = fs.readdirSync(path);
17 | for (const file of buildFiles) {
18 | if ((file.includes('main') || file.includes('src_app_') || file.includes('scripts') || file.includes('vendors-')) && !(file.includes('.map'))) {
19 | filesToConcat.push(path + file);
20 | }
21 | }
22 |
23 | (async function build() {
24 | await fse.ensureDir('elements');
25 | await concat(filesToConcat, 'elements/' + bundleFileName);
26 | })();
--------------------------------------------------------------------------------
/annotation-app/docker-entrypoint.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | # Copyright 2019-2022 VMware, Inc.
4 | # SPDX-License-Identifier: Apache-2.0
5 |
6 | ## Substitutes env variables in main.*.js bundle
7 | sed -i 's/${APP_CONFIG}/'"${APP_CONFIG}"'/' $(ls /usr/share/nginx/html/main*.js)
8 | sed -i 's/${CLIENT_ID}/'"${CLIENT_ID}"'/' $(ls /usr/share/nginx/html/main*.js)
9 | ## Starts the application
10 | nginx -g 'daemon off;'
--------------------------------------------------------------------------------
/annotation-app/nginx.conf:
--------------------------------------------------------------------------------
1 | server {
2 | listen 4200;
3 | root /usr/share/nginx/html;
4 | location / {
5 | try_files $uri $uri/ /index.html =404;
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/annotation-app/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "annotation-app",
3 | "version": "0.0.0",
4 | "scripts": {
5 | "ng": "ng",
6 | "start": "ng serve",
7 | "build": "ng build",
8 | "bundle": "ng run annotation-app:mfe && node build-script.js",
9 | "bundle_dev": "ng run annotation-app:mfe:dev && node build-script.js",
10 | "bundle_stg": "ng run annotation-app:mfe:stg && node build-script.js",
11 | "bundle_prod": "ng run annotation-app:mfe:prod && node build-script.js"
12 | },
13 | "private": true,
14 | "dependencies": {
15 | "@angular-devkit/build-angular": "^14.2.9",
16 | "@angular-slider/ngx-slider": "^2.0.3",
17 | "@angular/animations": "^14.2.0",
18 | "@angular/common": "^14.2.0",
19 | "@angular/compiler": "^14.2.0",
20 | "@angular/core": "^14.2.0",
21 | "@angular/elements": "^14.2.11",
22 | "@angular/forms": "^14.2.0",
23 | "@angular/platform-browser": "^14.2.0",
24 | "@angular/platform-browser-dynamic": "^14.2.0",
25 | "@angular/router": "^14.2.0",
26 | "@auth0/angular-jwt": "^3.0.1",
27 | "@cds/angular": "6.2.2",
28 | "@cds/core": "6.2.2",
29 | "@clr/angular": "13.10.1",
30 | "@clr/ui": "13.10.1",
31 | "@ng-select/ng-select": "^9.1.0",
32 | "@types/lodash": "^4.14.189",
33 | "aws-sdk": "^2.1261.0",
34 | "buffer": "^5.5.0",
35 | "concat": "^1.0.3",
36 | "d3-v6-tip": "^1.0.9",
37 | "fs-extra": "^10.1.0",
38 | "js-untar": "^2.0.0",
39 | "jszip": "^3.7.1",
40 | "lodash": "^4.17.21",
41 | "marked": "^2.1.3",
42 | "ngx-build-plus": "^14.0.0",
43 | "ngx-papaparse": "^5.1.0",
44 | "pako": "^2.0.3",
45 | "rxjs": "~7.5.0",
46 | "tslib": "^2.3.0",
47 | "windowed-observable": "^1.0.0",
48 | "zone.js": "~0.11.4"
49 | },
50 | "devDependencies": {
51 | "@angular/cli": "~14.2.5",
52 | "@angular/compiler-cli": "^14.2.0",
53 | "typescript": "~4.7.2"
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/annotation-app/proxy.conf.json:
--------------------------------------------------------------------------------
1 | {
2 | "/api/*": {
3 | "target": "http://localhost:3000",
4 | "secure": false,
5 | "logLevel": "debug",
6 | "changeOrigin": true
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/annotation-app/src/app/app-routing.module.ts:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2019-2023 VMware, Inc.
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | import { NgModule } from '@angular/core';
7 | import { RouterModule, Routes } from '@angular/router';
8 | import { FAQComponent } from './component/faq/faq.component';
9 | import { HomeComponent } from './component/home/home.component';
10 | import { PageNotFoundComponent } from './component/page-not-found/page-not-found.component';
11 | import { AuthGuard } from './guards/auth.guard';
12 |
13 | const routes: Routes = [
14 | { path: '', redirectTo: 'loop-home', pathMatch: 'full' },
15 | { path: 'loop-home', component: HomeComponent },
16 | {
17 | path: 'login',
18 | loadChildren: () => import('./component/login/login.module').then((m) => m.LoginsModule),
19 | },
20 | {
21 | path: 'loop/datasets',
22 | loadChildren: () => import('./component/datasets/datasets.module').then((m) => m.DatasetsModule),
23 | canActivate: [AuthGuard],
24 | },
25 | {
26 | path: 'loop/project',
27 | loadChildren: () => import('./component/projects/projects.module').then((m) => m.ProjectsModule),
28 | canActivate: [AuthGuard],
29 | },
30 | {
31 | path: 'loop/permissions',
32 | loadChildren: () => import('./component/permission/permissions.module').then((m) => m.PermissionsModule),
33 | },
34 | { path: 'loop/faq', component: FAQComponent },
35 | { path: '404', component: PageNotFoundComponent },
36 | { path: '**', redirectTo: '404' },
37 | ];
38 |
39 | @NgModule({
40 | imports: [RouterModule.forRoot(routes)],
41 | exports: [RouterModule],
42 | })
43 | export class AppRoutingModule {}
44 |
--------------------------------------------------------------------------------
/annotation-app/src/app/app.component.html:
--------------------------------------------------------------------------------
1 |
3 |
4 |
15 |
--------------------------------------------------------------------------------
/annotation-app/src/app/app.component.ts:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2019-2023 VMware, Inc.
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | import { Component } from '@angular/core';
7 |
8 | @Component({
9 | selector: 'mf-loop',
10 | templateUrl: './app.component.html',
11 | })
12 | export class AppComponent {
13 | title = 'annotation-app';
14 | }
15 |
--------------------------------------------------------------------------------
/annotation-app/src/app/component/datasets/create-new-dataset-modal/create-new-dataset-modal.component.html:
--------------------------------------------------------------------------------
1 |
3 |
4 |
48 |
49 |
--------------------------------------------------------------------------------
/annotation-app/src/app/component/datasets/create-new-dataset-modal/create-new-dataset-modal.component.scss:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2019-2023 VMware, Inc.
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 | .modal {
6 | .modal-body {
7 | height: 70vh;
8 | overflow-x: hidden;
9 | padding-left: 5px;
10 | }
11 |
12 | .modal-dialog {
13 | width: 60vw;
14 | }
15 | }
--------------------------------------------------------------------------------
/annotation-app/src/app/component/datasets/create-new-dataset-page/create-new-dataset-page.component.html:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
Upload New Dataset
8 |
13 |
14 |
15 |
18 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/annotation-app/src/app/component/datasets/create-new-dataset-page/create-new-dataset-page.component.scss:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2019-2023 VMware, Inc.
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 | .h2Title {
6 | margin-top: unset;
7 | }
--------------------------------------------------------------------------------
/annotation-app/src/app/component/datasets/create-new-dataset-page/create-new-dataset-page.component.ts:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2019-2023 VMware, Inc.
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 | import { Component, OnInit } from '@angular/core';
6 | import { EnvironmentsService } from 'src/app/services/environments.service';
7 |
8 | @Component({
9 | selector: 'app-create-new-dataset-page',
10 | templateUrl: './create-new-dataset-page.component.html',
11 | styleUrls: ['./create-new-dataset-page.component.scss'],
12 | })
13 | export class CreateNewDatasetPageComponent implements OnInit {
14 | msg;
15 | uploading = false;
16 | createBtnDisable = true;
17 |
18 | constructor(public env: EnvironmentsService) {}
19 |
20 | ngOnInit(): void {
21 | this.msg = { page: 'createDataset', createDataBtn: 0 };
22 | }
23 |
24 | receiveOutFormData(formdata) {
25 | if (formdata) {
26 | this.msg.type = formdata.fileFormat;
27 | this.createBtnDisable = false;
28 | } else {
29 | this.createBtnDisable = true;
30 | }
31 | }
32 |
33 | clickCreate() {
34 | this.uploading = true;
35 | this.msg.createDataBtn = this.msg.createDataBtn + 1;
36 | this.msg = JSON.parse(JSON.stringify(this.msg));
37 | }
38 |
39 | receiveUploadDone(uploading) {
40 | this.uploading = false;
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/annotation-app/src/app/component/datasets/create-new-dataset/create-new-dataset.component.scss:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2019-2023 VMware, Inc.
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | .sectionDivision {
7 | margin-top: 1rem;
8 | }
9 |
10 | .divisionLine {
11 | border-bottom: 1px solid rgb(197, 197, 197);
12 | margin-top: 2rem;
13 | }
14 |
15 | .divisionWidth {
16 | width: 99.7%;
17 | margin-left: 0;
18 | }
19 |
20 |
21 |
22 | .radioRow {
23 | margin-left: unset;
24 | margin-right: unset;
25 | margin-top: 1rem;
26 |
27 | .clr-radio-wrapper input[type=radio]+label::before {
28 | left: unset;
29 | right: 0;
30 | }
31 |
32 | .clr-radio-wrapper {
33 | padding: 0.5rem 0.5rem 0.5rem;
34 | border-radius: 5px;
35 | box-shadow: 1px 1px 4px 2px #e9e9e9;
36 | width: 49%;
37 |
38 | label {
39 | padding-left: unset;
40 | width: 100%;
41 | }
42 | }
43 |
44 | .clr-radio-wrapper:hover {
45 | box-shadow: 1px 1px 5px 1px rgb(128 168 196)
46 | }
47 |
48 | .selectedRadio {
49 | border: 1px solid rgb(0, 104, 150);
50 | }
51 | }
52 |
53 | .disabledRadio {
54 | opacity: 0.4;
55 | pointer-events: none;
56 | }
--------------------------------------------------------------------------------
/annotation-app/src/app/component/datasets/dataset-analyze/analyze-datagrid/analyze-datagrid.component.html:
--------------------------------------------------------------------------------
1 |
3 |
4 |
0" [clrDgLoading]="gridloading">
5 |
6 | {{ column.label }}
7 |
8 |
9 |
10 |
11 |
18 |
19 |
20 | {{ itemData[column.prop] }}
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/annotation-app/src/app/component/datasets/dataset-analyze/analyze-datagrid/analyze-datagrid.component.scss:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2019-2024 VMware, Inc.
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 | .columnWidth{
6 | width: 16rem;
7 | }
8 | .imgLimit{
9 | max-width: 15rem;
10 | max-height: 15rem
11 | }
12 | .showImg{
13 | display: none;
14 | }
--------------------------------------------------------------------------------
/annotation-app/src/app/component/datasets/dataset-analyze/analyze-datagrid/analyze-datagrid.component.ts:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2019-2024 VMware, Inc.
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 | import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
6 |
7 | @Component({
8 | selector: 'app-analyze-datagrid',
9 | templateUrl: './analyze-datagrid.component.html',
10 | styleUrls: ['./analyze-datagrid.component.scss'],
11 | })
12 | export class AnalyzeDatagridComponent implements OnInit {
13 | @Input() configData: any;
14 | @Input() gridloading: false;
15 |
16 | errorImg = false;
17 |
18 | constructor() {
19 | this.configData = {
20 | columnData: [],
21 | tableData: [],
22 | pageSizeOption: [10, 20, 50],
23 | type: '',
24 | };
25 | }
26 |
27 | ngOnInit(): void {}
28 |
29 | setDefaultImage() {
30 | this.errorImg = true;
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/annotation-app/src/app/component/datasets/dataset-analyze/dataset-analyze.component.scss:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2019-2023 VMware, Inc.
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 | .h2Title {
6 | overflow: hidden;
7 | text-overflow: ellipsis;
8 | max-width: 85%;
9 | font-size: 2em;
10 | padding-top: 0.2rem;
11 | }
12 |
13 |
14 |
15 | cds-icon[shape="arrow"] {
16 | transform: rotate(-90deg);
17 | width: 1.5rem;
18 | height: 1.5rem;
19 | margin-right: 0.5rem;
20 | cursor: pointer;
21 | }
22 |
23 | .properties {
24 | border-bottom: 1px solid rgb(197, 197, 197);
25 | padding-bottom: 2rem;
26 | }
27 |
28 | .createEntrance {
29 | padding-left: 1.5rem;
30 |
31 | p {
32 | margin-top: 0.5rem;
33 | margin-bottom: 0.5rem;
34 | }
35 |
36 | div {
37 | padding-bottom: 1rem;
38 | }
39 |
40 | }
--------------------------------------------------------------------------------
/annotation-app/src/app/component/datasets/datasets-routing.module.ts:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2019-2023 VMware, Inc.
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | import { NgModule } from '@angular/core';
7 | import { Routes, RouterModule } from '@angular/router';
8 | import { CreateNewDatasetModalComponent } from './create-new-dataset-modal/create-new-dataset-modal.component';
9 | import { CreateNewDatasetPageComponent } from './create-new-dataset-page/create-new-dataset-page.component';
10 | import { DatasetAnalyzeComponent } from './dataset-analyze/dataset-analyze.component';
11 | import { MyDatasetsComponent } from './my-datasets/my-datasets.component';
12 |
13 | const routes: Routes = [
14 | {
15 | path: 'list',
16 | component: MyDatasetsComponent,
17 | data: {
18 | title: 'loopDatasets',
19 | },
20 | },
21 | {
22 | path: 'create',
23 | component: CreateNewDatasetPageComponent,
24 | data: {
25 | title: 'loopDatasetsCreate',
26 | },
27 | },
28 | {
29 | path: 'create/modal',
30 | component: CreateNewDatasetModalComponent,
31 | data: {
32 | title: 'loopDatasetsCreate',
33 | },
34 | },
35 | {
36 | path: 'analyze',
37 | component: DatasetAnalyzeComponent,
38 | data: {
39 | title: 'loopDatasetsAnalyze',
40 | },
41 | },
42 | ];
43 |
44 | @NgModule({
45 | imports: [RouterModule.forChild(routes)],
46 | exports: [RouterModule],
47 | declarations: [],
48 | })
49 | export class DatasetsRoutingModule {}
50 |
--------------------------------------------------------------------------------
/annotation-app/src/app/component/datasets/datasets.module.ts:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2019-2023 VMware, Inc.
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | import { NgModule } from '@angular/core';
7 | import { CommonModule } from '@angular/common';
8 | import { SharedModule } from 'src/app/shared/shared.module';
9 | import { DatasetsRoutingModule } from './datasets-routing.module';
10 | import { MyDatasetsComponent } from './my-datasets/my-datasets.component';
11 | import { ModalDatagridComponent } from './modal-datagrid/modal-datagrid.component';
12 | import { CreateNewDatasetPageComponent } from './create-new-dataset-page/create-new-dataset-page.component';
13 | import { DatasetAnalyzeComponent } from './dataset-analyze/dataset-analyze.component';
14 | import { ProjectsModule } from '../projects/projects.module';
15 | import { AnalyzeDatagridComponent } from './dataset-analyze/analyze-datagrid/analyze-datagrid.component';
16 |
17 | @NgModule({
18 | declarations: [
19 | MyDatasetsComponent,
20 | ModalDatagridComponent,
21 | CreateNewDatasetPageComponent,
22 | DatasetAnalyzeComponent,
23 | AnalyzeDatagridComponent,
24 | ],
25 | imports: [CommonModule, DatasetsRoutingModule, SharedModule, ProjectsModule],
26 | })
27 | export class DatasetsModule {}
28 |
--------------------------------------------------------------------------------
/annotation-app/src/app/component/datasets/dnd.directive.ts:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2019-2023 VMware, Inc.
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 | import { Directive, Output, EventEmitter, HostBinding, HostListener } from '@angular/core';
6 |
7 | @Directive({
8 | selector: '[appDnd]',
9 | })
10 | export class DndDirective {
11 | constructor() {}
12 | @HostBinding('class.fileover') fileOver: boolean;
13 | @Output() fileDropped = new EventEmitter();
14 |
15 | // Dragover listener
16 | @HostListener('dragover', ['$event']) onDragOver(evt) {
17 | evt.preventDefault();
18 | evt.stopPropagation();
19 | this.fileOver = true;
20 | }
21 |
22 | // Dragleave listener
23 | @HostListener('dragleave', ['$event']) public onDragLeave(evt) {
24 | evt.preventDefault();
25 | evt.stopPropagation();
26 | this.fileOver = false;
27 | }
28 |
29 | // Drop listener
30 | @HostListener('drop', ['$event']) public ondrop(evt) {
31 | evt.preventDefault();
32 | evt.stopPropagation();
33 | this.fileOver = false;
34 | let files = evt.dataTransfer.files;
35 | if (files.length > 0) {
36 | this.fileDropped.emit(files);
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/annotation-app/src/app/component/datasets/modal-datagrid/modal-datagrid.component.ts:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2019-2023 VMware, Inc.
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 | import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
6 | import { EnvironmentsService } from 'src/app/services/environments.service';
7 |
8 | @Component({
9 | selector: 'app-modal-datagrid',
10 | templateUrl: './modal-datagrid.component.html',
11 | })
12 | export class ModalDatagridComponent implements OnInit {
13 | @Input() msgPreview: any;
14 |
15 | @Output('onClosePreviewDialog')
16 | onClosePreviewDialogEmitter = new EventEmitter();
17 |
18 | previewDatasetDialog = true;
19 | topRowHeader: any = [];
20 | topRowContent: any = [];
21 |
22 | constructor(public env: EnvironmentsService) {}
23 |
24 | ngOnInit(): void {
25 | this.toShowPreview();
26 | }
27 |
28 | toShowPreview() {
29 | if (this.msgPreview.format == 'image') {
30 | this.topRowContent = [];
31 | let flag = JSON.parse(JSON.stringify(this.msgPreview.topReview));
32 | flag.forEach((element) => {
33 | element.fileSize = (element.fileSize / 1024).toFixed(2);
34 | if (!this.env.config.enableAWSS3) {
35 | element.location = `${this.env.config.annotationService}/api/v1.0/datasets/set-data?file=${
36 | element.location
37 | }&token=${JSON.parse(localStorage.getItem(this.env.config.sessionKey)).token.access_token}`;
38 | }
39 | });
40 | this.topRowContent = flag;
41 | this.topRowHeader = ['Id', 'ImageName', 'ImageSize(KB)', 'Image'];
42 | } else if (this.msgPreview.format == 'txt') {
43 | this.topRowHeader = ['FileName', 'FileContent'];
44 | this.topRowContent = this.msgPreview.topReview;
45 | } else {
46 | this.topRowHeader = this.msgPreview.topReview.header == null ? [] : this.msgPreview.topReview.header;
47 | this.topRowContent = this.msgPreview.topReview.topRows == null ? [] : this.msgPreview.topReview.topRows;
48 | }
49 | }
50 |
51 | onClosePreviewDialog() {
52 | this.onClosePreviewDialogEmitter.emit(true);
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/annotation-app/src/app/component/datasets/my-datasets/my-datasets.component.scss:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2019-2023 VMware, Inc.
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 | .pageTitle {
6 | margin-left: 0.2rem;
7 | align-items: baseline;
8 | justify-content: space-between;
9 | margin-bottom: 1rem;
10 | }
11 |
12 | .h2Title {
13 | margin-top: unset;
14 | }
15 |
16 | .floatRight {
17 | float: right;
18 | margin-right: unset !important;
19 | }
20 |
21 | clr-dg-cell {
22 | a {
23 | cursor: pointer;
24 | text-decoration: underline;
25 | color: rgb(0, 112, 172);
26 | }
27 | }
28 |
29 | .cellWordBreak {
30 | word-break: break-all;
31 | display: -webkit-box;
32 | -webkit-box-orient: vertical;
33 | -webkit-line-clamp: 2;
34 | overflow: hidden;
35 | height: 1.8rem;
36 | line-height: 0.7rem;
37 | }
38 |
39 | .actionClass {
40 | padding: 0.1rem 0.2rem;
41 | height: 1rem;
42 | line-height: 0.6rem;
43 | min-width: 1.5rem;
44 | }
45 |
46 | .greenBtn {
47 | opacity: 0.7;
48 | }
49 |
50 | .disableTree {
51 | ::ng-deep .clr-checkbox-wrapper .clr-control-label {
52 | pointer-events: none;
53 | opacity: 0.5;
54 | }
55 |
56 | ::ng-deep .clr-checkbox-wrapper input[type='checkbox'] {
57 | pointer-events: none;
58 | }
59 | }
60 |
61 |
62 | .ellipsisMore {
63 | max-width: 30vw;
64 |
65 | a {
66 | padding-right: 0.5rem;
67 | cursor: pointer;
68 | }
69 |
70 | a:last-child {
71 | padding-right: 0.5rem;
72 | }
73 |
74 | div:nth-child(1) {
75 | overflow: hidden;
76 | text-overflow: ellipsis;
77 | white-space: nowrap;
78 | max-width: 100%;
79 | }
80 |
81 | div:nth-child(2) {
82 | text-decoration: underline;
83 | color: rgb(0, 103, 159);
84 | cursor: pointer;
85 | }
86 |
87 | .openMore {
88 | display: block;
89 | margin-bottom: 0.3rem;
90 | }
91 |
92 | ::ng-deep .spinner.spinner-sm {
93 | height: 0.6rem;
94 | width: 0.6rem;
95 | min-height: 0.6rem;
96 | min-width: 0.6rem;
97 | }
98 |
99 | }
100 |
101 | ::ng-deep input.disabled-checkbox+label::before {
102 | background-color: #eee;
103 | cursor: not-allowed;
104 | opacity: 0.3;
105 | }
106 |
107 | .refreshBtn {
108 | display: inline-block;
109 | margin-right: 2rem;
110 | color: #0079b8;
111 | font-weight: 600;
112 | font-size: 0.7rem;
113 | font-style: normal;
114 | cursor: pointer;
115 | }
--------------------------------------------------------------------------------
/annotation-app/src/app/component/datasets/upload-file/upload-file.component.scss:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2019-2023 VMware, Inc.
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 | .progressFile {
6 | margin-left: -0.2rem;
7 | }
8 |
9 | .progressBlock {
10 | line-height: 1.7rem;
11 | margin-top: 1rem;
12 | }
13 |
14 | .uploadBox {
15 | border: 1px dashed #e9e9e9;
16 | text-align: center;
17 | margin-top: 1rem;
18 | height: 3rem;
19 | background-color: white;
20 | line-height: 3rem;
21 | position: relative;
22 |
23 |
24 | input {
25 | opacity: 0;
26 | position: absolute;
27 | z-index: 2;
28 | width: 100%;
29 | height: 100%;
30 | top: 0;
31 | left: 0;
32 | }
33 |
34 | label {
35 | width: 183px;
36 | height: 44px;
37 | text-decoration: underline;
38 | color: rgb(68, 137, 188);
39 |
40 | }
41 | }
42 |
43 | .fileover {
44 | border: 1px dashed rgb(0, 104, 150);
45 | background-color: rgb(222, 244, 251);
46 | }
47 |
48 | .file-icon {
49 |
50 | .delete {
51 | display: flex;
52 | margin-left: 0.5rem;
53 | cursor: pointer;
54 | align-self: flex-end;
55 | }
56 |
57 | display: flex;
58 | flex-grow: 1;
59 | }
60 |
61 | .uploadInfo {
62 | margin-top: 0;
63 | font-size: 0.8em;
64 | color: #999;
65 | }
--------------------------------------------------------------------------------
/annotation-app/src/app/component/faq/faq.component.scss:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2019-2023 VMware, Inc.
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | .title {
7 | margin-top: 2rem;
8 | margin-bottom: 2rem;
9 | }
10 |
11 | ::ng-deep .clr-accordion-header-button {
12 | height: 2.5rem;
13 | }
14 |
15 | ::ng-deep .clr-accordion-inner-content {
16 | padding: 0.8rem 1.5rem !important;
17 | }
18 |
19 | ::ng-deep .clr-accordion-content {
20 | border: unset !important;
21 | }
22 |
23 | ::ng-deep .clr-accordion-header {
24 | border: unset !important;
25 | border-bottom: 1px solid #ededed !important;
26 | }
27 |
28 | span {
29 | font-size: 0.7rem;
30 | padding-right: 0.3rem;
31 | }
--------------------------------------------------------------------------------
/annotation-app/src/app/component/faq/faq.component.ts:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2019-2023 VMware, Inc.
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | import { Component } from '@angular/core';
7 | import { EnvironmentsService } from 'src/app/services/environments.service';
8 | @Component({
9 | styleUrls: ['./faq.component.scss'],
10 | templateUrl: './faq.component.html',
11 | })
12 | export class FAQComponent {
13 | constructor(public env: EnvironmentsService) {}
14 | }
15 |
--------------------------------------------------------------------------------
/annotation-app/src/app/component/header/header.component.html:
--------------------------------------------------------------------------------
1 |
3 |
4 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
Message: {{ errMessage }}
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/annotation-app/src/app/component/header/header.component.scss:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2019-2023 VMware, Inc.
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 | .flaskIcon {
6 | color: white;
7 | width: 1.2rem !important;
8 | height: 1.2rem !important;
9 | }
--------------------------------------------------------------------------------
/annotation-app/src/app/component/header/header.component.ts:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2019-2023 VMware, Inc.
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 | import { Component, OnInit } from '@angular/core';
6 | import { EnvironmentsService } from 'src/app/services/environments.service';
7 | import { Router } from '@angular/router';
8 | import { UserAuthService } from 'src/app/services/user-auth.service';
9 |
10 | @Component({
11 | selector: 'app-header',
12 | templateUrl: './header.component.html',
13 | styleUrls: ['./header.component.scss'],
14 | })
15 | export class HeaderComponent implements OnInit {
16 | loggedUser;
17 | errMessage: string;
18 | role: string;
19 |
20 | constructor(private router: Router, private userAuthService: UserAuthService, public env: EnvironmentsService) {}
21 |
22 | ngOnInit(): void {
23 | if (!this.env.config.embedded) {
24 | this.userAuthService.loggedUserListener().subscribe((res) => {
25 | if (res) {
26 | this.loggedUser = res;
27 | }
28 | });
29 | }
30 | }
31 |
32 | login() {
33 | if (!this.env.config.embedded) {
34 | if (this.env.config.authUrl) {
35 | this.userAuthService.redirectToLogin();
36 | } else {
37 | this.router.navigateByUrl('/login/basic');
38 | }
39 | }
40 | }
41 |
42 | logOut() {
43 | this.userAuthService.logout();
44 | this.router.navigateByUrl('/loop-home');
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/annotation-app/src/app/component/home/home.component.ts:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2019-2023 VMware, Inc.
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 | import { Component, OnInit } from '@angular/core';
6 | import { ActivatedRoute } from '@angular/router';
7 | import { EnvironmentsService } from 'src/app/services/environments.service';
8 | import { UserAuthService } from 'src/app/services/user-auth.service';
9 |
10 | @Component({
11 | selector: 'app-home',
12 | templateUrl: './home.component.html',
13 | styleUrls: ['./home.component.scss'],
14 | })
15 | export class HomeComponent implements OnInit {
16 | unsubscribe: boolean;
17 | isUnsubscribe: boolean;
18 |
19 | constructor(
20 | private route: ActivatedRoute,
21 | private userAuthService: UserAuthService,
22 | public env: EnvironmentsService,
23 | ) {}
24 |
25 | ngOnInit(): void {
26 | this.route.queryParams.subscribe((params) => {
27 | const isUserLandingFromOutside = !params['hash'] || String(params['hash']).length == 0;
28 | if (params['o'] == 'email') {
29 | this.isUnsubscribe = true;
30 | this.unsubscribe = String(params['s']) == '1' ? true : false;
31 | } else {
32 | this.isUnsubscribe = false;
33 | }
34 | // if (isUserLandingFromOutside || this.unsubscribe) {
35 | // const user = this.userAuthService.loggedUser().user;
36 | // }
37 | if (this.isUnsubscribe) {
38 | setTimeout(() => {
39 | this.isUnsubscribe = false;
40 | }, 10000);
41 | }
42 | });
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/annotation-app/src/app/component/login/basic-login/basic-login.component.scss:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2019-2023 VMware, Inc.
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | .loading {
7 | background-color: rgba(0, 119, 184, 0.2);
8 | border-color: rgba(0, 119, 184, 0.2);
9 | }
10 |
11 | .login-wrapper .login {
12 | min-height: unset;
13 | }
14 |
15 | .helperText {
16 | font-size: 0.55rem;
17 | line-height: 0.6rem;
18 | color: #9c9c9c;
19 | }
--------------------------------------------------------------------------------
/annotation-app/src/app/component/login/login-routing.module.ts:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2019-2023 VMware, Inc.
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | import { NgModule } from '@angular/core';
7 | import { Routes, RouterModule } from '@angular/router';
8 | import { BasicLoginComponent } from './basic-login/basic-login.component';
9 | import { LoginComponent } from './login/login.component';
10 |
11 | const routes: Routes = [
12 | {
13 | path: 'basic',
14 | component: BasicLoginComponent,
15 | data: {
16 | title: 'loopBasicLogin',
17 | },
18 | },
19 | {
20 | path: 'authenticate',
21 | component: LoginComponent,
22 | data: { title: 'loopAuthenticateLogin' },
23 | },
24 | ];
25 |
26 | @NgModule({
27 | imports: [RouterModule.forChild(routes)],
28 | exports: [RouterModule],
29 | declarations: [],
30 | })
31 | export class LoginRoutingModule {}
32 |
--------------------------------------------------------------------------------
/annotation-app/src/app/component/login/login.module.ts:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2019-2023 VMware, Inc.
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | import { NgModule } from '@angular/core';
7 | import { CommonModule } from '@angular/common';
8 | import { LoginRoutingModule } from './login-routing.module';
9 | import { BasicLoginComponent } from './basic-login/basic-login.component';
10 | import { SharedModule } from 'src/app/shared/shared.module';
11 | import { LoginComponent } from './login/login.component';
12 |
13 | @NgModule({
14 | declarations: [BasicLoginComponent, LoginComponent],
15 | imports: [CommonModule, LoginRoutingModule, SharedModule],
16 | })
17 | export class LoginsModule {}
18 |
--------------------------------------------------------------------------------
/annotation-app/src/app/component/login/login/login.component.html:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 | Loading...
6 |
7 |
--------------------------------------------------------------------------------
/annotation-app/src/app/component/login/login/login.component.scss:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2019-2023 VMware, Inc.
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | .uploadLoading {
7 | background-color: rgba(0, 119, 184, 0.2);
8 | border-color: rgba(0, 119, 184, 0.2);
9 | }
--------------------------------------------------------------------------------
/annotation-app/src/app/component/login/login/login.component.ts:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2019-2023 VMware, Inc.
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | import { Component, OnInit } from '@angular/core';
7 | import { Router, ActivatedRoute } from '@angular/router';
8 | import { Location } from '@angular/common';
9 | import { UserAuthService } from 'src/app/services/user-auth.service';
10 | import { map, mergeMap } from 'rxjs/operators';
11 | import { throwError } from 'rxjs';
12 | import { User } from '../../../model/user';
13 | import { EnvironmentsService } from 'src/app/services/environments.service';
14 |
15 | @Component({
16 | selector: 'app-login',
17 | templateUrl: './login.component.html',
18 | styles: [
19 | `
20 | .filter-artifacts {
21 | text-align: right;
22 | }
23 | `,
24 | ],
25 | })
26 | export class LoginComponent implements OnInit {
27 | user = { email: '', password: '' };
28 | returnUrl!: string;
29 | errorMessage = '';
30 | authSource?: number;
31 | loggedUser: User | null = null;
32 | loading?: boolean;
33 |
34 | constructor(
35 | private route: ActivatedRoute,
36 | private router: Router,
37 | private userAuthService: UserAuthService,
38 | private location: Location,
39 | private env: EnvironmentsService,
40 | ) {}
41 |
42 | ngOnInit() {
43 | this.returnUrl = this.route.snapshot.queryParams['returnUrl'] || '/';
44 | this.loading = true;
45 | this.route.queryParams
46 | .pipe(
47 | map((params) => params),
48 | mergeMap((data: any) => {
49 | const code = data['code'];
50 | const state = data['state'];
51 | if (state !== this.env.config.STATE) {
52 | return throwError('Wrong state...');
53 | }
54 | const redirectUrl =
55 | window.location.origin +
56 | this.location.prepareExternalUrl(this.env.config.redirectUrl ? this.env.config.redirectUrl : '/loop-home');
57 | return this.userAuthService.loging(code, this.env.config.CLIENT_ID, redirectUrl);
58 | }),
59 | )
60 | .subscribe(
61 | (data) => {
62 | this.loading = false;
63 | this.router.navigate([this.returnUrl]);
64 | },
65 | (error) => {
66 | this.loading = false;
67 | this.router.navigate(['/loop-home']);
68 | },
69 | () => {
70 | this.loading = false;
71 | },
72 | );
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/annotation-app/src/app/component/page-not-found/page-not-found.component.html:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
11 |
12 |
Sorry,We couldn't find the page you requested.
13 |
14 | Click here
15 | to go back to the homepage.
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/annotation-app/src/app/component/page-not-found/page-not-found.component.scss:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2019-2023 VMware, Inc.
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | .circleBox {
7 | display: flex;
8 | align-items: center;
9 | justify-content: center;
10 | }
11 |
12 | .circle {
13 | background-color: #002538;
14 | width: 5rem;
15 | height: 5rem;
16 | line-height: 5rem;
17 | text-align: center;
18 | border-radius: 50%;
19 | color: #fafafa;
20 | font-size: 1.5rem;
21 | font-weight: bold;
22 | }
23 |
24 | .box {
25 | position: absolute;
26 | top: 35%;
27 | left: 50%;
28 | transform: translate(-50%, 50%);
29 | }
--------------------------------------------------------------------------------
/annotation-app/src/app/component/page-not-found/page-not-found.component.ts:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2019-2023 VMware, Inc.
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | import { Component } from '@angular/core';
7 |
8 | @Component({
9 | selector: 'app-page-not-found',
10 | templateUrl: './page-not-found.component.html',
11 | styleUrls: ['./page-not-found.component.scss'],
12 | })
13 | export class PageNotFoundComponent {}
14 |
--------------------------------------------------------------------------------
/annotation-app/src/app/component/permission/permissions-routing.module.ts:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2019-2023 VMware, Inc.
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | import { NgModule } from '@angular/core';
7 | import { Routes, RouterModule } from '@angular/router';
8 | import { PermissionsComponent } from './permissions/permissions.component';
9 |
10 | const routes: Routes = [
11 | {
12 | path: 'users',
13 | component: PermissionsComponent,
14 | data: {
15 | title: 'loopPermissions',
16 | },
17 | },
18 | ];
19 |
20 | @NgModule({
21 | imports: [RouterModule.forChild(routes)],
22 | exports: [RouterModule],
23 | declarations: [],
24 | })
25 | export class PermissionsRoutingModule {}
26 |
--------------------------------------------------------------------------------
/annotation-app/src/app/component/permission/permissions.module.ts:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2019-2023 VMware, Inc.
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | import { NgModule } from '@angular/core';
7 | import { CommonModule } from '@angular/common';
8 | import { PermissionsRoutingModule } from './permissions-routing.module';
9 | import { PermissionsComponent } from './permissions/permissions.component';
10 | import { SharedModule } from 'src/app/shared/shared.module';
11 |
12 | @NgModule({
13 | declarations: [PermissionsComponent],
14 | imports: [CommonModule, PermissionsRoutingModule, SharedModule],
15 | })
16 | export class PermissionsModule {}
17 |
--------------------------------------------------------------------------------
/annotation-app/src/app/component/permission/permissions/permissions.component.scss:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2019-2023 VMware, Inc.
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | .h2Title {
7 | margin-top: unset;
8 | }
9 |
10 | .floatRight {
11 | float: right;
12 | margin-right: unset !important;
13 | }
14 |
15 | .actionClass {
16 | min-width: unset;
17 | }
18 |
19 | .editModal input[type='text'],
20 | .editModal input[type='file'] {
21 | width: 100% !important;
22 | margin-bottom: 0px;
23 | }
24 |
25 | ::ng-deep .editModal .modal-dialog {
26 | min-width: 50%;
27 |
28 | .modal-body-wrapper {
29 | min-height: 25vh;
30 | }
31 | }
--------------------------------------------------------------------------------
/annotation-app/src/app/component/projects/annotate-progress-board/annotate-progress-board.component.scss:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2019-2023 VMware, Inc.
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | .left-project-info {
7 | margin-top: 0.5rem;
8 | }
9 |
10 | h5 {
11 | font-weight: bold;
12 | }
13 |
14 | .historyBox {
15 | max-height: 11rem;
16 | overflow: auto;
17 | height: 11rem;
18 | padding-right: 1rem;
19 | }
20 |
21 | .fontSizeSmall {
22 | font-size: 0.9em;
23 | }
24 |
25 | .historyText {
26 | overflow: hidden;
27 | min-width: 0;
28 | text-align: left;
29 | white-space: nowrap;
30 | padding-right: 1rem;
31 | text-overflow: ellipsis;
32 | cursor: pointer;
33 | }
34 |
35 | .historyPosition:hover {
36 | background-color: #ececec;
37 | border-radius: 4px;
38 |
39 | .historyIcon {
40 | color: #0077b8;
41 | }
42 | }
43 |
44 | .historyIcon {
45 | position: absolute;
46 | top: 0.3rem;
47 | }
48 |
49 | .historyPosition {
50 | position: relative;
51 | padding-right: 1rem;
52 | padding-left: 1.5rem;
53 | }
54 |
55 | .ellipsis {
56 | text-overflow: ellipsis;
57 | overflow: hidden;
58 | }
59 |
60 | .selectedHistory {
61 | background-color: #e1f1f6 !important;
62 | border-radius: 4px !important;
63 | }
--------------------------------------------------------------------------------
/annotation-app/src/app/component/projects/annotate-progress-board/annotate-progress-board.component.ts:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2019-2024 VMware, Inc.
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
7 | import * as _ from 'lodash';
8 | import { UserAuthService } from 'src/app/services/user-auth.service';
9 |
10 | @Component({
11 | selector: 'app-annotate-progress-board',
12 | templateUrl: './annotate-progress-board.component.html',
13 | styleUrls: ['./annotate-progress-board.component.scss'],
14 | })
15 | export class AnnotateProgressBoardComponent implements OnInit {
16 | @Input() msg;
17 | @Output('outClickHistory')
18 | outClickHistoryEmitter = new EventEmitter();
19 | @Output('outClickReviewOrder')
20 | outClickReviewOrder = new EventEmitter();
21 | @Output('outSelectReviewee')
22 | outSelectReviewee = new EventEmitter();
23 |
24 | reviewOrder: string;
25 | reviewee: string;
26 | isAllowedAnnotate: boolean;
27 | user: any;
28 | optionList: [];
29 |
30 | constructor(private userAuthService: UserAuthService) {
31 | this.user = this.userAuthService.loggedUser()?.user;
32 | }
33 |
34 | ngOnInit(): void {
35 | this.reviewOrder = this.msg.projectInfo.assignmentLogic;
36 | this.reviewee = this.msg.reviewee;
37 | this.isAllowedAnnotate = this.msg.projectInfo.annotator.indexOf(this.user.email) > -1 ? true : false;
38 | this.optionList = this.msg?.projectInfo?.userCompleteCase;
39 | }
40 |
41 | ngOnChanges() {}
42 |
43 | historyBack(index, id) {
44 | let value = {
45 | index,
46 | id,
47 | };
48 | this.outClickHistoryEmitter.emit(value);
49 | }
50 |
51 | changeReviewOrder(e) {
52 | this.reviewOrder = e.target.value;
53 | this.outClickReviewOrder.emit(this.reviewOrder);
54 | }
55 |
56 | onSelectingReviewee(e) {
57 | this.outSelectReviewee.emit(this.reviewee);
58 | }
59 |
60 | clickUncertain(e) {
61 | if (e.target.innerText === 'Uncertain' && this.reviewOrder !== 'most_uncertain') {
62 | this.changeReviewOrder({ target: { value: 'most_uncertain' } });
63 | }
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/annotation-app/src/app/component/projects/download/download.component.scss:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2019-2023 VMware, Inc.
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | .modal .modal-dialog {
7 | width: inherit !important;
8 | }
9 |
10 | .modal .modal-dialog .modal-content {
11 | width: 800px;
12 | }
13 |
14 | clr-alert {
15 | margin-top: 1rem;
16 | }
17 |
18 | label span {
19 | color: red;
20 | }
21 |
22 | .form-group .select {
23 | width: 100%;
24 | }
25 |
26 | ::ng-deep .dcr-doc-form .select2-class {
27 | width: 100% !important;
28 | }
29 |
30 | .form-group input[type='text'],
31 | .form-group input[type='file'] {
32 | width: 100% !important;
33 | margin-bottom: 0px;
34 | }
35 |
36 | .form-group .select,
37 | .form-group select {
38 | width: 100% !important;
39 | }
40 |
41 | .form-group textarea {
42 | width: 100% !important;
43 | }
44 |
45 | ::ng-deep .btn.btn-sm {
46 | margin-top: 7px !important;
47 | }
48 |
49 | ::ng-deep .md-check {
50 | margin-left: 10px !important;
51 | }
52 |
53 | ::ng-deep .footerLeft .modal-footer {
54 | display: inherit !important;
55 | }
56 |
57 | .uploadLoading {
58 | background-color: rgba(0, 119, 184, 0.2);
59 | border-color: rgba(0, 119, 184, 0.2);
60 | padding-top: 0.2rem;
61 | margin-left: 0.2rem;
62 | }
63 |
64 | .removeEntry {
65 | margin-top: 0.5rem;
66 | margin-left: 0.05rem;
67 | }
--------------------------------------------------------------------------------
/annotation-app/src/app/component/projects/generate/generate.component.scss:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2019-2023 VMware, Inc.
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | .modal .modal-dialog {
7 | width: inherit !important;
8 | }
9 |
10 | .modal .modal-dialog .modal-content {
11 | width: 800px;
12 | }
13 |
14 | clr-alert {
15 | margin-top: 1rem;
16 | }
17 |
18 | label span {
19 | color: red;
20 | }
21 |
22 | .form-group .select {
23 | width: 100%;
24 | }
25 |
26 | ::ng-deep .dcr-doc-form .select2-class {
27 | width: 100% !important;
28 | }
29 |
30 | .form-group input[type='text'],
31 | .form-group input[type='file'] {
32 | width: 100% !important;
33 | margin-bottom: 0px;
34 | }
35 |
36 | .form-group .select,
37 | .form-group select {
38 | width: 100% !important;
39 | }
40 |
41 | .form-group textarea {
42 | width: 100% !important;
43 | }
44 |
45 | ::ng-deep .btn.btn-sm {
46 | margin-top: 7px !important;
47 | }
48 |
49 | ::ng-deep .md-check {
50 | margin-left: 10px !important;
51 | }
52 |
53 | ::ng-deep .footerLeft .modal-footer {
54 | display: inherit !important;
55 | }
56 |
57 | .uploadLoading {
58 | background-color: rgba(0, 119, 184, 0.2);
59 | border-color: rgba(0, 119, 184, 0.2);
60 | padding-top: 0.2rem;
61 | margin-left: 0.2rem;
62 | }
63 |
64 | .removeEntry {
65 | margin-top: 0.5rem;
66 | margin-left: 0.12rem;
67 | }
--------------------------------------------------------------------------------
/annotation-app/src/app/component/projects/generate/generate.component.ts:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2019-2023 VMware, Inc.
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
7 | import { UserAuthService } from '../../../services/user-auth.service';
8 | import { ApiService } from '../../../services/api.service';
9 | import { DownloadService } from 'src/app/services/common/download.service';
10 |
11 | @Component({
12 | selector: 'app-generate',
13 | templateUrl: './generate.component.html',
14 | styleUrls: ['./generate.component.scss'],
15 | })
16 | export class GenerateComponent implements OnInit {
17 | @Input() msg: any;
18 |
19 | @Output('onCloseGenerateDialog')
20 | onCloseGenerateDialogEmitter = new EventEmitter();
21 |
22 | @Output() private refreshProject = new EventEmitter();
23 |
24 | user: any;
25 | loading = false;
26 | errorMessage = '';
27 | infoMessage = '';
28 | format = '';
29 | loadingGenerate = false;
30 | onlyLabelled = true;
31 |
32 | constructor(
33 | private apiService: ApiService,
34 | private userAuthService: UserAuthService,
35 | private downloadService: DownloadService,
36 | ) {
37 | this.user = this.userAuthService.loggedUser()?.user.email;
38 | }
39 |
40 | ngOnInit() {
41 | this.format = 'standard';
42 | }
43 |
44 | onCloseGenerateDialog() {
45 | this.onCloseGenerateDialogEmitter.emit();
46 | }
47 |
48 | generateNewProject() {
49 | this.loadingGenerate = true;
50 | this.apiService.generate(this.msg.id, this.format, this.msg.src, this.onlyLabelled ? 'Yes' : 'No').subscribe(
51 | (res) => {
52 | res.Modal = 'generate';
53 | this.refreshProject.emit(res);
54 | },
55 | (error: any) => {
56 | this.loadingGenerate = false;
57 | this.loading = false;
58 | },
59 | );
60 | }
61 |
62 | removeUnlabel(e) {
63 | this.onlyLabelled = e.target.checked;
64 | }
65 |
66 | downloadOriginal(urls) {
67 | this.downloadService.downloadMultiple(urls);
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/annotation-app/src/app/component/projects/labeling-task-list/projects.component.html:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
Labeling Tasks Lists
8 |
9 |
10 |
11 | REFRESH
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/annotation-app/src/app/component/projects/labeling-task-list/projects.component.scss:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2019-2023 VMware, Inc.
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | .pageTitle {
7 | margin-left: 0.2rem;
8 | align-items: baseline;
9 | justify-content: space-between;
10 | margin-bottom: 1rem;
11 | }
12 |
13 | .h2Title {
14 | margin-top: unset;
15 | }
16 |
17 | .floatRight {
18 | float: right;
19 | margin-right: unset !important;
20 | }
21 |
22 | .refreshBtn {
23 | display: inline-block;
24 | margin-right: 2rem;
25 | color: #0079b8;
26 | font-weight: 600;
27 | font-size: 0.7rem;
28 | font-style: normal;
29 | cursor: pointer;
30 | }
--------------------------------------------------------------------------------
/annotation-app/src/app/component/projects/labeling-task-list/projects.component.ts:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2019-2023 VMware, Inc.
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | import { Component, OnInit } from '@angular/core';
7 | import { UserAuthService } from 'src/app/services/user-auth.service';
8 | import { ActivatedRoute } from '@angular/router';
9 |
10 | @Component({
11 | selector: 'app-projects',
12 | templateUrl: './projects.component.html',
13 | styleUrls: ['./projects.component.scss'],
14 | })
15 | export class ProjectsComponent implements OnInit {
16 | user;
17 | msg;
18 |
19 | constructor(private userAuthService: UserAuthService, private route: ActivatedRoute) {}
20 |
21 | ngOnInit(): void {
22 | this.user = this.userAuthService.loggedUser()?.user;
23 | this.msg = { tab: 'annotate' };
24 | this.route.queryParams.subscribe((queryParams) => {
25 | this.msg.tab = queryParams['tabType'] || 'annotate';
26 | });
27 | }
28 |
29 | clickTaskTab(tab) {
30 | this.msg.tab = tab;
31 | }
32 |
33 | reload() {
34 | if (this.msg.tab == 'annotate') {
35 | this.msg.reload = 'annotate';
36 | } else {
37 | this.msg.reload = 'admin';
38 | }
39 | this.msg = JSON.parse(JSON.stringify(this.msg));
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/annotation-app/src/app/component/projects/project-analyze/latest-annotation-data/latest-annotation-data.component.scss:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2019-2023 VMware, Inc.
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 | .modelChartBox {
6 | border-radius: 8px;
7 | background-color: white;
8 | height: 20rem;
9 | margin-bottom: 3rem;
10 | }
11 |
12 | .studioCell {
13 | min-width: 70% !important
14 | }
15 |
16 | .annotationLoading {
17 | background-color: white;
18 | border-radius: 8px;
19 | min-height: 9rem;
20 | text-align: center;
21 | }
22 |
23 | .loadingSpan {
24 | position: relative;
25 | display: inline-block;
26 | text-align: center;
27 | padding: 0.75rem 1rem;
28 | color: grey;
29 | opacity: 0.65;
30 | font-size: 0.7rem;
31 | }
32 |
33 | .previewHeight {
34 | height: 3.4rem !important;
35 | }
36 |
37 | .btnOutline {
38 | margin-top: 0.3rem;
39 | padding-left: unset;
40 | outline-color: transparent;
41 | }
42 | :host ::ng-deep input.disabled-checkbox+label::before {
43 | background-color: #eee;
44 | cursor: not-allowed;
45 | opacity: 0.3;
46 | }
--------------------------------------------------------------------------------
/annotation-app/src/app/component/projects/project-analyze/user-category-d3/user-category-d3.component.html:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
Number of Assigned Labels
7 |
8 |
18 |
19 |
20 |
# Annotations Per User
21 |
22 |
23 | Loading...
24 |
25 |
26 | NO ANNOTATION
27 |
28 |
36 |
37 |
38 |
39 |
# Annotations Per Category
40 |
# Annotations Per Value Range
41 |
42 |
43 | Loading...
44 |
45 |
46 | NO ANNOTATION
47 |
48 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/annotation-app/src/app/component/projects/project-analyze/user-category-d3/user-category-d3.component.scss:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2019-2023 VMware, Inc.
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | .topBoardBox {
7 | height: 15rem;
8 | background-color: white;
9 | border-radius: 8px;
10 | margin-top: 0.5rem;
11 | position: relative;
12 | }
13 |
14 | .topBoard {
15 | padding: unset;
16 | }
17 |
18 | .floatRight {
19 | text-align: right;
20 | margin-top: 1.2rem;
21 | display: block;
22 | margin-right: unset;
23 |
24 | }
25 |
26 | .loadingD3 {
27 | text-align: center;
28 | padding-top: 5rem;
29 | position: absolute;
30 | transform: translate(-50%);
31 | left: 50%;
32 | }
--------------------------------------------------------------------------------
/annotation-app/src/app/component/projects/projects-routing.module.ts:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2019-2023 VMware, Inc.
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | import { NgModule } from '@angular/core';
7 | import { Routes, RouterModule } from '@angular/router';
8 | import { CreateProjectComponent } from './create-project/create-project.component';
9 | import { ProjectAnalyzeComponent } from './project-analyze/project-analyze.component';
10 | import { ProjectsComponent } from './labeling-task-list/projects.component';
11 | import { AuthGuard } from 'src/app/guards/auth.guard';
12 |
13 | const routes: Routes = [
14 | {
15 | path: 'list',
16 | component: ProjectsComponent,
17 | data: {
18 | title: 'loopProjectList',
19 | },
20 | canActivate: [AuthGuard],
21 | },
22 | {
23 | path: 'create',
24 | component: CreateProjectComponent,
25 | data: {
26 | title: 'loopProjectCreate',
27 | },
28 | canActivate: [AuthGuard],
29 | },
30 | {
31 | path: 'analyze',
32 | component: ProjectAnalyzeComponent,
33 | data: {
34 | title: 'loopProjectAnalyze',
35 | },
36 | canActivate: [AuthGuard],
37 | },
38 | ];
39 |
40 | @NgModule({
41 | imports: [RouterModule.forChild(routes)],
42 | exports: [RouterModule],
43 | declarations: [],
44 | })
45 | export class ProjectsRoutingModule {}
46 |
--------------------------------------------------------------------------------
/annotation-app/src/app/component/projects/projects.module.ts:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2019-2023 VMware, Inc.
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | import { NgModule } from '@angular/core';
7 | import { CommonModule } from '@angular/common';
8 | import { SharedModule } from 'src/app/shared/shared.module';
9 | import { ProjectsRoutingModule } from './projects-routing.module';
10 | import { GenerateComponent } from './generate/generate.component';
11 | import { DownloadComponent } from './download/download.component';
12 | import { TreeviewModalComponent } from './treeview-modal/treeview-modal.component';
13 | import { CdsIconsService } from 'src/app/services/cds-icon.service';
14 | import { CreateProjectComponent } from './create-project/create-project.component';
15 | import { ProjectsComponent } from './labeling-task-list/projects.component';
16 | import { ProjectAnalyzeComponent } from './project-analyze/project-analyze.component';
17 | import { NgxSliderModule } from '@angular-slider/ngx-slider';
18 | import { AnnotateProgressBoardComponent } from './annotate-progress-board/annotate-progress-board.component';
19 | import { LabelStudioService } from 'src/app/services/label-studio.service';
20 | import { LatestAnnotationDataComponent } from './project-analyze/latest-annotation-data/latest-annotation-data.component';
21 | import { UserCategoryD3Component } from './project-analyze/user-category-d3/user-category-d3.component';
22 | import { AppendComponent } from './project-analyze/append/append.component';
23 | import { EditProjectComponent } from './labeling-task-list/edit-project/edit-project.component';
24 | import { NgSelectModule } from '@ng-select/ng-select';
25 | import { TaskDatagridComponent } from './labeling-task-list/task-datagrid/task-datagrid.component';
26 |
27 | @NgModule({
28 | declarations: [
29 | GenerateComponent,
30 | DownloadComponent,
31 | TreeviewModalComponent,
32 | CreateProjectComponent,
33 | ProjectsComponent,
34 | ProjectAnalyzeComponent,
35 | AnnotateProgressBoardComponent,
36 | LatestAnnotationDataComponent,
37 | UserCategoryD3Component,
38 | AppendComponent,
39 | EditProjectComponent,
40 | TaskDatagridComponent,
41 | ],
42 | imports: [CommonModule, ProjectsRoutingModule, SharedModule, NgxSliderModule, NgSelectModule],
43 | providers: [CdsIconsService, LabelStudioService],
44 | exports: [GenerateComponent, DownloadComponent, TreeviewModalComponent],
45 | })
46 | export class ProjectsModule {}
47 |
--------------------------------------------------------------------------------
/annotation-app/src/app/component/projects/treeview-modal/treeview-modal.component.html:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
13 |
14 |
15 |
21 | {{ label.name }}
22 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/annotation-app/src/app/component/projects/treeview-modal/treeview-modal.component.scss:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2019-2023 VMware, Inc.
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 | .disableTree {
6 | ::ng-deep .clr-checkbox-wrapper .clr-control-label {
7 | pointer-events: none;
8 | opacity: 0.5;
9 | }
10 |
11 | ::ng-deep .clr-checkbox-wrapper input[type='checkbox'] {
12 | pointer-events: none;
13 | }
14 | }
--------------------------------------------------------------------------------
/annotation-app/src/app/component/projects/treeview-modal/treeview-modal.component.ts:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2019-2023 VMware, Inc.
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 | import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
6 |
7 | @Component({
8 | selector: 'app-treeview-modal',
9 | templateUrl: './treeview-modal.component.html',
10 | styleUrls: ['./treeview-modal.component.scss'],
11 | })
12 | export class TreeviewModalComponent implements OnInit {
13 | @Input() treeData: any;
14 |
15 | @Output('onCloseTreeDialog')
16 | onCloseTreeDialog = new EventEmitter();
17 | getChildren: any;
18 | constructor() {}
19 |
20 | ngOnInit() {
21 | this.getChildren = (folder) => folder.children;
22 | }
23 |
24 | onCloseDialog() {
25 | this.onCloseTreeDialog.emit();
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/annotation-app/src/app/component/sidenav/sidenav.component.html:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 | Datasets
8 |
9 | Datasets List
10 | Upload New Dataset
11 |
12 |
13 |
14 |
15 | Labeling Tasks
16 |
17 | Labeling Tasks List
18 | Create New Labeling Task
19 |
20 |
21 |
27 |
45 |
46 |
--------------------------------------------------------------------------------
/annotation-app/src/app/component/sidenav/sidenav.component.scss:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2019-2023 VMware, Inc.
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | clr-vertical-nav {
7 | height: 100%;
8 | position: relative;
9 | }
10 |
11 | .bottomHelpLink {
12 | margin-top: 50vh;
13 | }
--------------------------------------------------------------------------------
/annotation-app/src/app/component/sidenav/sidenav.component.ts:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2019-2023 VMware, Inc.
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | import { Component, OnInit } from '@angular/core';
7 | import { EnvironmentsService } from 'src/app/services/environments.service';
8 | import { UserAuthService } from 'src/app/services/user-auth.service';
9 |
10 | @Component({
11 | selector: 'app-sidenav',
12 | templateUrl: './sidenav.component.html',
13 | styleUrls: ['./sidenav.component.scss'],
14 | })
15 | export class SidenavComponent implements OnInit {
16 | navCollapsible: any;
17 | index;
18 | userRole;
19 |
20 | constructor(public env: EnvironmentsService, private userAuthService: UserAuthService) {}
21 |
22 | ngOnInit(): void {
23 | this.navCollapsible = true;
24 | if (!this.env.config.embedded) {
25 | this.userAuthService.loggedUserListener().subscribe((res) => {
26 | if (res) {
27 | this.userRole = res.user.role;
28 | }
29 | });
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/annotation-app/src/app/core.module.ts:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2019-2023 VMware, Inc.
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | import { NgModule, Optional, SkipSelf } from '@angular/core';
7 | import { HttpClientModule } from '@angular/common/http';
8 | import { JwtModule, JWT_OPTIONS } from '@auth0/angular-jwt';
9 | import { UserAuthService } from '../app/services/user-auth.service';
10 | import { EnvironmentsService } from '../app/services/environments.service';
11 |
12 | export function jwtOptionsFactory(authService: UserAuthService, env: EnvironmentsService) {
13 | return {
14 | tokenGetter: () => {
15 | // console.log('tokenGetter: ()---', authService.loggedUser());
16 | if (authService.loggedUser()) {
17 | return authService.loggedUser().token ? authService.loggedUser().token.access_token : null;
18 | }
19 | return null;
20 | },
21 | whitelistedDomains: [
22 | `${env.config.annotationService}`.replace(/(http|https):\/\//, '').split('/')[0],
23 | `${env.config.authUrl}`.replace(/(http|https):\/\//, ''),
24 | `${env.config.inUrl}`.substring(0, `${env.config.inUrl}`.length - 8).replace(/(http|https):\/\//, ''),
25 | `${env.config.hubService}`.substring(0, `${env.config.hubService}`.length - 8).replace(/(http|https):\/\//, ''),
26 | ],
27 | };
28 | }
29 |
30 | @NgModule({
31 | declarations: [],
32 | imports: [
33 | HttpClientModule,
34 | JwtModule.forRoot({
35 | jwtOptionsProvider: {
36 | provide: JWT_OPTIONS,
37 | useFactory: jwtOptionsFactory,
38 | deps: [UserAuthService, EnvironmentsService],
39 | },
40 | }),
41 | ],
42 | exports: [],
43 | })
44 | export class CoreModule {
45 | constructor(@Optional() @SkipSelf() core: CoreModule) {
46 | if (core) {
47 | throw new Error('You should import core module only in the root module');
48 | }
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/annotation-app/src/app/guards/auth.guard.ts:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2019-2023 VMware, Inc.
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | import { Injectable } from '@angular/core';
7 | import { Router, CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
8 | import { UserAuthService } from 'src/app/services/user-auth.service';
9 | import { Observable } from 'rxjs';
10 | import { EnvironmentsService } from 'src/app/services/environments.service';
11 |
12 | @Injectable({ providedIn: 'root' })
13 | export class AuthGuard implements CanActivate {
14 | constructor(private router: Router, private userAuthService: UserAuthService, private env: EnvironmentsService) {}
15 |
16 | canActivate(
17 | route: ActivatedRouteSnapshot,
18 | state: RouterStateSnapshot,
19 | ): Observable | Promise | boolean {
20 | const user = this.userAuthService.loggedUser()?.user;
21 | if (user) {
22 | return true;
23 | }
24 | if (!this.env.config.embedded) {
25 | if (this.userAuthService.isLoggedIn()) {
26 | return this.checkRole(state.url);
27 | } else {
28 | if (this.env.config.authUrl) {
29 | this.userAuthService.redirectToLogin();
30 | return false;
31 | } else {
32 | this.router.navigateByUrl('/login/basic');
33 | }
34 | }
35 | }
36 | return false;
37 | }
38 |
39 | checkRole(url) {
40 | const role = JSON.parse(localStorage.getItem(this.env.config.sessionKey)).user.role;
41 | if (role && role != '') {
42 | if (role != 'Power User' && url.includes('permissions')) {
43 | this.router.navigate(['loop-home']);
44 | return false;
45 | }
46 | return true;
47 | } else {
48 | return false;
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/annotation-app/src/app/model/authentication.ts:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2019-2023 VMware, Inc.
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | export enum SessionStatus {
7 | NOT_AUTHENTICATED,
8 | AUTHENTICATED,
9 | EXPIRED,
10 | }
11 |
12 | export interface AuthRequestToken {
13 | grant_type?: string;
14 | client_id?: string;
15 | redirect_uri?: string;
16 | code?: string;
17 | client_secret?: string;
18 | provider?: string;
19 | username?: string;
20 | password?: string;
21 | refresh_token?: string;
22 | bypass_uri_check?: boolean;
23 | }
24 |
25 | export interface AuthResponseToken {
26 | access_token?: string;
27 | access_type?: string;
28 | expires_in?: number;
29 | refresh_token?: string;
30 | expires_time?: number;
31 | }
32 |
33 | export interface AuthUser {
34 | token?: AuthResponseToken;
35 | user?: {
36 | role?: any;
37 | email?: string;
38 | provider?: string;
39 | sub?: string;
40 | username?: string;
41 | exp?: number;
42 | iat?: number;
43 | iss?: string;
44 | name?: string;
45 | };
46 | }
47 |
48 | export class AuthUtil {
49 | public static isValidUser(user: AuthUser): boolean {
50 | if (user && user.user.email && user.token && user.token.access_token && user.token.refresh_token) {
51 | return true;
52 | }
53 | return false;
54 | }
55 | public static isValidBasicUser(user): boolean {
56 | if (user && user.user.email && user.token && user.token.access_token && user.token.expires_time) {
57 | return true;
58 | }
59 | return false;
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/annotation-app/src/app/model/constant.ts:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2019-2023 VMware, Inc.
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | export interface Incentive {
7 | points: number;
8 | donation: number;
9 | }
10 |
11 | export const ColorsRainbow = [
12 | '#00ffff',
13 | '#ff00ff',
14 | '#00ff7f',
15 | '#ff6347',
16 | '#9B0D54',
17 | '#00bfff',
18 | '#FF0000',
19 | '#ff69b4',
20 | '#7fffd4',
21 | '#ffd700',
22 | '#FBC1DA',
23 | '#4D007A',
24 | '#ffdab9',
25 | '#adff2f',
26 | '#FFA500',
27 | '#FFFF00',
28 | '#583fcf',
29 | '#A32100',
30 | '#0F1E82',
31 | '#F89997',
32 | '#003D79',
33 | '#00D4B8',
34 | '#6C5F59',
35 | '#AADB1E',
36 | '#36C9E1',
37 | '#D0ACE4',
38 | '#798893',
39 | '#ED186F',
40 | '#D87093',
41 | '#DAA520',
42 | '#20B2AA',
43 | '#cb6360',
44 | '#c98886',
45 | '#703d3b',
46 | '#4c0b09',
47 | '#1890ff',
48 | '#189044',
49 | '#36c9d9',
50 | '#40a9ff',
51 | '#ff40a8',
52 | '#673ab7',
53 | '#faad14',
54 | '#03a9f4',
55 | '#9b4f4a',
56 | '#FF1493',
57 | '#228B22',
58 | '#0077b8',
59 | '#ff7875',
60 | '#97d778',
61 | '#2F4F4F',
62 | ];
63 |
64 | export const PopLabelColors = [
65 | '#55b128',
66 | '#d70c3b',
67 | '#3377dd',
68 | '#973633',
69 | '#f7a604',
70 | '#864ac1',
71 | '#09cbe5',
72 | '#a0f709',
73 | '#edf709',
74 | '#e9098f',
75 | ];
76 |
77 | export const ClrTimelineStepState = {
78 | NOT_STARTED: 'not-started',
79 | CURRENT: 'current',
80 | SUCCESS: 'success',
81 | ERROR: 'error',
82 | PROCESSING: 'processing',
83 | };
84 |
85 | export const Classifier = [
86 | { name: 'RandomForestClassifier', value: 'RFC' },
87 | { name: 'KNeighborsClassifier', value: 'KNC' },
88 | { name: 'GradientBoostingClassifier', value: 'GBC' },
89 | ];
90 |
91 | export const Encoder = [
92 | { name: ' One-Hot Encoding', value: 'oneHot' },
93 | { name: 'Categorical Embeddings', value: 'embeddings' },
94 | ];
95 |
96 | export const QueryStrategyBase = [
97 | { name: 'uncertainty_sampling', value: 'PB_UNS' },
98 | { name: 'margin_sampling', value: 'PB_MS' },
99 | { name: 'entropy_sampling', value: 'PB_ES' },
100 | { name: 'uncertainty_batch_sampling', value: 'RBM_UNBS' },
101 | ];
102 |
103 | export const PopLabels = [
104 | { name: 'Positive', value: 'Positive', setLableErrMessage: '' },
105 | { name: 'Negative', value: 'Negative', setLableErrMessage: '' },
106 | { name: 'Neutral', value: 'Neutral', setLableErrMessage: '' },
107 | ];
108 |
--------------------------------------------------------------------------------
/annotation-app/src/app/model/env.ts:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2019-2023 VMware, Inc.
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | export interface Env {
7 | embedded?: boolean;
8 | production?: boolean;
9 | annotationService?: string;
10 | redirectUrl?: string;
11 | serviceTitle?: string;
12 | provider?: string;
13 | USER_KEY?: string;
14 | STATE?: string;
15 | enableSendEmail?: boolean;
16 | authUrl?: string;
17 | tokenUrl?: string;
18 | logoutUrl?: string;
19 | CLIENT_ID?: string;
20 | lumosUrl?: string;
21 | googleTrackId?: any;
22 | enableAWSS3?: boolean;
23 | contactEmail?: string;
24 | contactSlack?: string;
25 | fileSize?: number;
26 | enableSlack?: boolean;
27 | slackAppName?: string;
28 | sessionKey?: string;
29 | inUrl?: string;
30 | videoSrc?: string;
31 | hubService?: string;
32 | }
33 |
--------------------------------------------------------------------------------
/annotation-app/src/app/model/index.ts:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2019-2023 VMware, Inc.
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | export * from './env';
7 | export * from './dataset';
8 | export * from './user';
9 | export * from './constant';
10 |
--------------------------------------------------------------------------------
/annotation-app/src/app/model/sr.ts:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2019-2024 VMware, Inc.
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | export interface SR {
7 | _id?: number;
8 | originalData?: any;
9 | problemCategory?: any;
10 | productName?: string;
11 | issueType?: string;
12 | resoltionCode?: string;
13 | resolution?: string;
14 | caseNumber?: string;
15 | userInputs?: UserInput[];
16 | MSG?: string;
17 | flag?: any;
18 | images?: any;
19 | userInputsLength?: number;
20 | fileInfo?: any;
21 | ticketQuestions?: any;
22 | questionForText?: any;
23 | userInput?: UserInput[];
24 | pid?: number;
25 | }
26 | export interface UserInput {
27 | problemCategory?: any;
28 | timestamp?: string;
29 | tid?: number;
30 | user?: string;
31 | logFreeText?: string;
32 | questionForText?: QaChat[];
33 | }
34 |
35 | export interface SrUserInput {
36 | pid?: number;
37 | user?: string;
38 | userInput?: any;
39 | }
40 |
41 | export interface QaChat {
42 | prompt: string;
43 | response: string;
44 | reference?: any;
45 | followUps?: QaChat[];
46 | }
47 |
48 | export class DatasetUtil {
49 | static initQaChat(): SR {
50 | return {
51 | userInput: [{ questionForText: [{ prompt: '', response: '', reference: [], followUps: [] }] }],
52 | };
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/annotation-app/src/app/model/user.ts:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2019-2023 VMware, Inc.
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | export interface User {
7 | id?: string;
8 | email?: string;
9 | btoa?: string;
10 | fullName?: string;
11 | srs?: number[];
12 | srCount?: number;
13 | optOutProducts?: string[];
14 | points?: number;
15 | percentage?: number;
16 | }
17 |
18 | export const LabelStudio = undefined;
19 |
--------------------------------------------------------------------------------
/annotation-app/src/app/pipes/full-name.pipe.ts:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2019-2023 VMware, Inc.
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | import { Pipe, PipeTransform } from '@angular/core';
7 |
8 | /**
9 | * Remove extra numbers after the full name (those numbers comes fromt the authentication service)
10 | */
11 | @Pipe({ name: 'fullNamePipe' })
12 | export class FullNamePipe implements PipeTransform {
13 | transform(fullName: string): string {
14 | const match = /^([^\d]+)/.exec(fullName);
15 | return match && match[1] ? match[1] : fullName;
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/annotation-app/src/app/pipes/math-round.pipe.ts:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2019-2023 VMware, Inc.
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | import { Pipe, PipeTransform } from '@angular/core';
7 |
8 | /**
9 | * Remove extra numbers after the full name (those numbers comes fromt the authentication service)
10 | */
11 | @Pipe({ name: 'mathRoundPipe' })
12 | export class MathRoundPipe implements PipeTransform {
13 | transform(mathRound: number): string {
14 | const a = Math.round(mathRound);
15 | return String(a);
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/annotation-app/src/app/pipes/sliceText.pipe.ts:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2019-2023 VMware, Inc.
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | import { Pipe, PipeTransform } from '@angular/core';
7 |
8 | @Pipe({ name: 'SliceTextPipe' })
9 | export class SliceTextPipe implements PipeTransform {
10 | transform(fullText: string): string {
11 | const sliceText = fullText.slice(0, 20) + '...';
12 | return sliceText;
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/annotation-app/src/app/services/cds-icon.service.ts:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2019-2024 VMware, Inc.
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | import { Injectable } from '@angular/core';
7 | import '@cds/core/icon/register.js';
8 | import {
9 | ClarityIcons,
10 | userIcon,
11 | unknownIcon,
12 | talkBubblesIcon,
13 | happyFaceIcon,
14 | tagsIcon,
15 | dataClusterIcon,
16 | helpIcon,
17 | infoStandardIcon,
18 | envelopeIcon,
19 | flaskIcon,
20 | boltIcon,
21 | rackServerIcon,
22 | successStandardIcon,
23 | lightbulbIcon,
24 | textIcon,
25 | unknownStatusIcon,
26 | bundleIcon,
27 | imageIcon,
28 | errorStandardIcon,
29 | tableIcon,
30 | uploadCloudIcon,
31 | fileIcon,
32 | windowCloseIcon,
33 | viewListIcon,
34 | downloadIcon,
35 | barsIcon,
36 | flagIcon,
37 | childArrowIcon,
38 | ellipsisVerticalIcon,
39 | exclamationCircleIcon,
40 | angleIcon,
41 | circleIcon,
42 | banIcon,
43 | checkIcon,
44 | noteIcon,
45 | trashIcon,
46 | uploadIcon,
47 | usersIcon,
48 | pencilIcon,
49 | plusIcon,
50 | checkboxListIcon,
51 | refreshIcon,
52 | sadFaceIcon,
53 | circleArrowIcon,
54 | timesCircleIcon,
55 | linkIcon,
56 | } from '@cds/core/icon';
57 | import { ClrSpinner } from '@clr/angular';
58 |
59 | ClarityIcons.addIcons(
60 | unknownIcon,
61 | userIcon,
62 | talkBubblesIcon,
63 | happyFaceIcon,
64 | tagsIcon,
65 | dataClusterIcon,
66 | helpIcon,
67 | infoStandardIcon,
68 | envelopeIcon,
69 | flaskIcon,
70 | boltIcon,
71 | rackServerIcon,
72 | successStandardIcon,
73 | lightbulbIcon,
74 | textIcon,
75 | unknownStatusIcon,
76 | bundleIcon,
77 | imageIcon,
78 | errorStandardIcon,
79 | tableIcon,
80 | uploadCloudIcon,
81 | fileIcon,
82 | windowCloseIcon,
83 | viewListIcon,
84 | downloadIcon,
85 | barsIcon,
86 | flagIcon,
87 | childArrowIcon,
88 | ellipsisVerticalIcon,
89 | exclamationCircleIcon,
90 | angleIcon,
91 | circleIcon,
92 | successStandardIcon,
93 | banIcon,
94 | checkIcon,
95 | noteIcon,
96 | trashIcon,
97 | uploadIcon,
98 | usersIcon,
99 | pencilIcon,
100 | plusIcon,
101 | checkboxListIcon,
102 | refreshIcon,
103 | sadFaceIcon,
104 | circleArrowIcon,
105 | timesCircleIcon,
106 | linkIcon,
107 | );
108 |
109 | @Injectable({
110 | providedIn: 'root',
111 | })
112 | export class CdsIconsService {
113 | constructor() {}
114 | }
115 |
--------------------------------------------------------------------------------
/annotation-app/src/app/services/common/download.service.ts:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2019-2023 VMware, Inc.
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | import { Injectable } from '@angular/core';
7 | import * as _ from 'lodash';
8 | import { EnvironmentsService } from 'src/app/services/environments.service';
9 | import { WebAnalyticsService } from '../web-analytics.service';
10 |
11 | @Injectable()
12 | export class DownloadService {
13 | constructor(public env: EnvironmentsService, private wa: WebAnalyticsService) {}
14 |
15 | downloadMultiple(urls) {
16 | urls.forEach((url, index) => {
17 | let hiddenIFrameID = 'hiddenDownloader' + index;
18 | let iframe = document.createElement('iframe');
19 | iframe.id = hiddenIFrameID;
20 | iframe.style.display = 'none';
21 | document.body.appendChild(iframe);
22 | iframe.src = this.env.config.enableAWSS3
23 | ? url
24 | : `${this.env.config.annotationService}/api/v1.0/datasets/download-from-local-system?file=${url}&token=${
25 | JSON.parse(localStorage.getItem(this.env.config.sessionKey)).token.access_token
26 | }`;
27 | if (this.env.config.embedded && this.env.config.lumosUrl) {
28 | this.wa.toRecordDownloadWebAnalytics(url);
29 | }
30 | });
31 | }
32 |
33 | downloadFile(url) {
34 | if (this.env.config.enableAWSS3) {
35 | window.location.href = url;
36 | if (this.env.config.embedded && this.env.config.lumosUrl) {
37 | this.wa.toRecordDownloadWebAnalytics(url);
38 | }
39 | } else {
40 | window.location.href = `${
41 | this.env.config.annotationService
42 | }/api/v1.0/datasets/download-from-local-system?file=${url}&token=${
43 | JSON.parse(localStorage.getItem(this.env.config.sessionKey)).token.access_token
44 | }`;
45 | }
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/annotation-app/src/app/services/common/email.service.ts:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2019-2023 VMware, Inc.
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | import { Injectable } from '@angular/core';
7 | import * as _ from 'lodash';
8 | import { ToolService } from 'src/app/services/common/tool.service';
9 | import { ApiService } from '../api.service';
10 | import { InternalApiService } from '../internal-api.service';
11 |
12 | @Injectable()
13 | export class EmailService {
14 | constructor(
15 | private toolService: ToolService,
16 | private apiService: ApiService,
17 | private internalApiService: InternalApiService,
18 | ) {}
19 |
20 | public sendEmailToAnnotator(param) {
21 | this.internalApiService.sendEmailToAnnotator(param).subscribe(
22 | (res) => {},
23 | (error: any) => {},
24 | );
25 | }
26 |
27 | public sendEmailToOwner(param) {
28 | this.internalApiService.sendEmailToOwner(param).subscribe(
29 | (res) => {},
30 | (error: any) => {},
31 | );
32 | }
33 |
34 | public sendEmail(inputProjectName, msg, ownerList, assigneeList) {
35 | const param: object = {
36 | pname: inputProjectName,
37 | fileName: msg.dataSource,
38 | };
39 | const ownerDiff = _.difference(ownerList, msg.creator);
40 | let aa = [];
41 | assigneeList.forEach((element) => {
42 | aa.push(element.email);
43 | });
44 | const annotatorDiff = _.difference(aa, msg.annotator);
45 |
46 | if (annotatorDiff.length > 0) {
47 | param['annotator'] = annotatorDiff;
48 | this.sendEmailToAnnotator(param);
49 | }
50 | if (ownerDiff.length > 0) {
51 | param['projectOwner'] = ownerDiff;
52 | this.sendEmailToOwner(param);
53 | }
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/annotation-app/src/app/services/common/markdown-parser.service.ts:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2019-2023 VMware, Inc.
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | import { Injectable } from '@angular/core';
7 | import * as marked from 'marked';
8 |
9 | @Injectable()
10 | export class MarkdownParserService {
11 | private md: any;
12 | constructor() {
13 | this.md = marked;
14 | this.md.setOptions({
15 | renderer: new marked.Renderer(),
16 | pedantic: false,
17 | gfm: true,
18 | breaks: true,
19 | sanitize: false,
20 | smartLists: true,
21 | smartypants: false,
22 | xhtml: false,
23 | });
24 | }
25 |
26 | convert(markdown) {
27 | return this.md.parse(markdown);
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/annotation-app/src/app/services/common/tool.utils.js:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2019-2023 VMware, Inc.
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | function dateTransfer(time) {
7 | let date = new Date(time);
8 | let Y = date.getFullYear() + '-';
9 | let M = (date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1) + '-';
10 | let D = (date.getDate() < 10 ? '0' + date.getDate() : date.getDate()) + ' ';
11 | let h = (date.getHours() < 10 ? '0' + date.getHours() : date.getHours()) + ':';
12 | let m = (date.getMinutes() < 10 ? '0' + date.getMinutes() : date.getMinutes()) + ':';
13 | let s = date.getSeconds() < 10 ? '0' + date.getSeconds() : date.getSeconds();
14 | return Y + M + D + h + m + s;
15 | }
16 |
17 |
--------------------------------------------------------------------------------
/annotation-app/src/app/services/environments.service.ts:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2019-2023 VMware, Inc.
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | import { Injectable } from '@angular/core';
7 | import { NavigationEnd, Router } from '@angular/router';
8 |
9 | declare let gtag: (parameterA: any, parameterB: any, parameterC: any) => void;
10 |
11 | @Injectable({
12 | providedIn: 'root',
13 | })
14 | export class EnvironmentsService {
15 | private configuration = '${APP_CONFIG}';
16 | private env: any;
17 | private nodeEnvironment: string;
18 | constructor(public router: Router) {
19 | console.log('LOOP_APP_CONFIG:', this.configuration);
20 | this.nodeEnvironment =
21 | this.configuration === '' || this.configuration.startsWith('$') ? '' : `.${this.configuration}`;
22 | this.env = require('../../environments/environment' + this.nodeEnvironment);
23 | // Global site tag (gtag.js) - Google Analytics Start
24 | if (this.configuration == 'prod' && this.env.environment.googleTrackId) {
25 | this.router.events.subscribe((event) => {
26 | if (event instanceof NavigationEnd) {
27 | gtag('config', this.env.environment.googleTrackId, {
28 | page_path: event.urlAfterRedirects,
29 | });
30 | }
31 | });
32 | }
33 | }
34 |
35 | get config() {
36 | return this.env.environment;
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/annotation-app/src/app/services/web-analytics.service.ts:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2019-2024 VMware, Inc.
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 | import { Injectable } from '@angular/core';
6 | declare var common: any;
7 |
8 | @Injectable()
9 | export class WebAnalyticsService {
10 | toRecordDownloadWebAnalytics(url: string) {
11 | var _paq = (common.lumos._paq = common.lumos._paq || []);
12 | _paq.push(['trackLink', url, 'download']);
13 | }
14 |
15 | toTrackEventWebAnalytics(category: string, action: string, name?: string, value?: number) {
16 | var _paq = (common.lumos._paq = common.lumos._paq || []);
17 | _paq.push(['trackEvent', category, action, name]);
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/annotation-app/src/app/shared/clr-filter/datagridFilter.component.scss:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2019-2023 VMware, Inc.
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 | .clr-form {
6 | width: 20vw;
7 |
8 | .clr-control-container {
9 | width: 100%;
10 |
11 | .clr-input {
12 | width: 100%;
13 | }
14 | }
15 | }
--------------------------------------------------------------------------------
/annotation-app/src/app/shared/clr-filter/datagridFilter.component.ts:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2019-2024 VMware, Inc.
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 | import { Component, EventEmitter, Input, Output, ViewChild, ElementRef } from '@angular/core';
6 | import { ClrDatagridFilterInterface, ClrDatagridFilter } from '@clr/angular';
7 | import { Subject } from 'rxjs';
8 | import { debounceTime, distinctUntilChanged } from 'rxjs/operators';
9 | import { ClrLoadingState } from '@clr/angular';
10 |
11 | @Component({
12 | selector: 'my-filter',
13 | templateUrl: './datagridFilter.component.html',
14 | styleUrls: ['./datagridFilter.component.scss'],
15 | })
16 | export class MyFilter implements ClrDatagridFilterInterface {
17 | @Input() filterMsg?: any;
18 | @Input() filteredTotal;
19 | @Input() replaceStatus;
20 | @Output() filter = new EventEmitter();
21 | @Output() replace = new EventEmitter();
22 |
23 | inputString: string = '';
24 | inputStringFilter = new Subject();
25 | changes = new Subject();
26 | inputString1: string = '';
27 | loadingReplace: ClrLoadingState = ClrLoadingState.DEFAULT;
28 |
29 | constructor(private filterContainer: ClrDatagridFilter) {
30 | filterContainer.setFilter(this);
31 | this.inputStringFilter.pipe(debounceTime(400), distinctUntilChanged()).subscribe((value) => {
32 | this.loadingReplace = ClrLoadingState.DEFAULT;
33 | this.filter.emit(value.trim());
34 | });
35 | }
36 |
37 | ngOnChanges() {
38 | if (this.replaceStatus == 'succeed') {
39 | this.loadingReplace = ClrLoadingState.SUCCESS;
40 | }
41 | }
42 |
43 | isActive(): boolean {
44 | return !(this.inputString.trim().length == 0);
45 | }
46 |
47 | accepts() {
48 | return true;
49 | }
50 |
51 | change() {
52 | this.loadingReplace = ClrLoadingState.DEFAULT;
53 | }
54 |
55 | replaceAll() {
56 | if (
57 | this.inputString.trim() &&
58 | this.filteredTotal &&
59 | this.filteredTotal > 0 &&
60 | this.inputString1.trim() &&
61 | this.inputString !== this.inputString1
62 | ) {
63 | this.loadingReplace = ClrLoadingState.LOADING;
64 | let data = {
65 | filter: this.inputString.trim(),
66 | replace: this.inputString1.trim(),
67 | };
68 | this.replace.emit(data);
69 | }
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/annotation-app/src/app/shared/form-validators/form-validator-util.ts:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2019-2023 VMware, Inc.
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | import { FormControl, FormGroup, FormArray, AbstractControl } from '@angular/forms';
7 |
8 | export class FormValidatorUtil {
9 | static markControlsAsTouched(formElement: AbstractControl): void {
10 | if (formElement instanceof FormControl) {
11 | formElement.markAsTouched();
12 | } else if (formElement instanceof FormGroup) {
13 | Object.keys(formElement.controls).forEach((key) => {
14 | this.markControlsAsTouched(formElement.get(key)!);
15 | });
16 | } else if (formElement instanceof FormArray) {
17 | formElement.controls.forEach((control) => {
18 | this.markControlsAsTouched(control);
19 | });
20 | }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/annotation-app/src/app/shared/modal-confirm/modal-confirm.component.html:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
13 |
14 |
{{ msg.modalContent }}
15 |
16 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/annotation-app/src/app/shared/modal-confirm/modal-confirm.component.ts:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2019-2023 VMware, Inc.
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | import { Component, Input, OnInit, Output, EventEmitter } from '@angular/core';
7 |
8 | @Component({
9 | selector: 'app-modal-confirm',
10 | templateUrl: './modal-confirm.component.html',
11 | })
12 | export class ModalConfirmComponent implements OnInit {
13 | @Input() msg;
14 | @Output('cancelBtn')
15 | onCloseConfirmDialogEmitter = new EventEmitter();
16 | @Output('okBtn')
17 | okBtnEmitter = new EventEmitter();
18 |
19 | showModal = true;
20 | clickOkBtn = false;
21 | constructor() {}
22 |
23 | ngOnInit(): void {}
24 |
25 | cancelBtn() {
26 | this.onCloseConfirmDialogEmitter.emit(true);
27 | }
28 | okBtn() {
29 | this.clickOkBtn = true;
30 | this.okBtnEmitter.emit(true);
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/annotation-app/src/app/shared/shared.module.ts:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2019-2023 VMware, Inc.
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | import { NgModule } from '@angular/core';
7 | import { CommonModule } from '@angular/common';
8 | import { FormsModule, ReactiveFormsModule } from '@angular/forms';
9 | import { ClarityModule } from '@clr/angular';
10 | import { RouterModule } from '@angular/router';
11 | import { ModalConfirmComponent } from './modal-confirm/modal-confirm.component';
12 | import { MyFilter } from './clr-filter/datagridFilter.component';
13 | import { FullNamePipe } from '../pipes/full-name.pipe';
14 | import { MathRoundPipe } from '../pipes/math-round.pipe';
15 | import { SliceTextPipe } from '../pipes/sliceText.pipe';
16 | import { UploadFileComponent } from '../component/datasets/upload-file/upload-file.component';
17 | import { DndDirective } from '../component/datasets/dnd.directive';
18 | import { CreateNewDatasetModalComponent } from '../component/datasets/create-new-dataset-modal/create-new-dataset-modal.component';
19 | import { CreateNewDatasetComponent } from '../component/datasets/create-new-dataset/create-new-dataset.component';
20 |
21 | @NgModule({
22 | declarations: [
23 | ModalConfirmComponent,
24 | MyFilter,
25 | FullNamePipe,
26 | MathRoundPipe,
27 | SliceTextPipe,
28 | UploadFileComponent,
29 | DndDirective,
30 | CreateNewDatasetComponent,
31 | CreateNewDatasetModalComponent,
32 | ],
33 | imports: [CommonModule, ClarityModule, FormsModule, ReactiveFormsModule, RouterModule],
34 | exports: [
35 | FormsModule,
36 | CommonModule,
37 | ReactiveFormsModule,
38 | ClarityModule,
39 | ModalConfirmComponent,
40 | MyFilter,
41 | FullNamePipe,
42 | MathRoundPipe,
43 | SliceTextPipe,
44 | UploadFileComponent,
45 | DndDirective,
46 | CreateNewDatasetModalComponent,
47 | CreateNewDatasetComponent,
48 | ],
49 | })
50 | export class SharedModule {}
51 |
--------------------------------------------------------------------------------
/annotation-app/src/app/shared/utils/index.es5.ts:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2019-2023 VMware, Inc.
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 | export default function insertAfter(node: any, _ref: any) {
6 | var nextSibling = _ref.nextSibling,
7 | parentNode = _ref.parentNode;
8 |
9 | return parentNode.insertBefore(node, nextSibling);
10 | }
11 |
--------------------------------------------------------------------------------
/annotation-app/src/app/shared/utils/treeView.ts:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2019-2023 VMware, Inc.
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 | export function filterTreeLabel(treeArr: any) {
6 | const findItem = (arr: any) => {
7 | let res = [];
8 | if (arr && arr.length > 0) {
9 | res = arr.filter((item: any) => {
10 | if (item.children && item.children.length > 0) {
11 | item.children = childFilter(item.children);
12 | }
13 | return item && item.children && item.children.length ? (item.enable = 1) : item.enable;
14 | });
15 | }
16 | return res;
17 | };
18 | const childFilter = (childArr: any) => {
19 | return childArr.filter((item: any) => {
20 | if (item.children && item.children.length > 0) {
21 | item.children = childFilter(item.children);
22 | }
23 | return item && item.children && item.children.length ? (item.enable = 1) : item.enable;
24 | });
25 | };
26 | return findItem(treeArr);
27 | }
28 |
--------------------------------------------------------------------------------
/annotation-app/src/assets/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vmware/data-annotator-for-machine-learning/ccc6dbfcc0bd680557f4068df89be5f20c93fcd9/annotation-app/src/assets/.gitkeep
--------------------------------------------------------------------------------
/annotation-app/src/assets/files/taxonomy_sample.json:
--------------------------------------------------------------------------------
1 | {
2 | "data": [
3 | {
4 | "name": "Products",
5 | "children": [
6 | {
7 | "name": "vSphere",
8 | "children": [
9 | {
10 | "name": "vSphere1"
11 | },
12 | {
13 | "name": "vSphere2"
14 | },
15 | {
16 | "name": "vSphere3"
17 | },
18 | {
19 | "name": "vSphere4"
20 | }
21 | ]
22 | },
23 | {
24 | "name": "vMware",
25 | "children": [
26 | {
27 | "name": "vMware1"
28 | },
29 | {
30 | "name": "vMware2"
31 | }
32 | ]
33 | },
34 | {
35 | "name": "FS"
36 | },
37 | {
38 | "name": "Stack"
39 | }
40 | ]
41 | },
42 | {
43 | "name": "Customer1"
44 | },
45 | {
46 | "name": "Customer2"
47 | }
48 | ]
49 | }
50 |
--------------------------------------------------------------------------------
/annotation-app/src/assets/files/taxonomy_sample.yaml:
--------------------------------------------------------------------------------
1 | # Copyright 2019-2023 VMware, Inc.
2 | # SPDX-License-Identifier: Apache-2.0
3 | data:
4 | - name: Products
5 | children:
6 | - name: vSphere
7 | children:
8 | - name: vSphere1
9 | - name: vSphere2
10 | - name: vSphere3
11 | - name: vSphere4
12 | - name: vMware
13 | children:
14 | - name: vMware1
15 | - name: vMware2
16 | - name: FS
17 | - name: Stack
18 | - name: Customer1
19 | - name: Customer2
20 |
--------------------------------------------------------------------------------
/annotation-app/src/assets/images/ava-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vmware/data-annotator-for-machine-learning/ccc6dbfcc0bd680557f4068df89be5f20c93fcd9/annotation-app/src/assets/images/ava-logo.png
--------------------------------------------------------------------------------
/annotation-app/src/assets/images/ava-small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vmware/data-annotator-for-machine-learning/ccc6dbfcc0bd680557f4068df89be5f20c93fcd9/annotation-app/src/assets/images/ava-small.png
--------------------------------------------------------------------------------
/annotation-app/src/assets/images/demo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vmware/data-annotator-for-machine-learning/ccc6dbfcc0bd680557f4068df89be5f20c93fcd9/annotation-app/src/assets/images/demo.png
--------------------------------------------------------------------------------
/annotation-app/src/assets/images/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vmware/data-annotator-for-machine-learning/ccc6dbfcc0bd680557f4068df89be5f20c93fcd9/annotation-app/src/assets/images/favicon.ico
--------------------------------------------------------------------------------
/annotation-app/src/assets/images/polygon.svg:
--------------------------------------------------------------------------------
1 |
3 |
4 |
11 |
--------------------------------------------------------------------------------
/annotation-app/src/assets/images/rect.svg:
--------------------------------------------------------------------------------
1 |
3 |
4 |
11 |
--------------------------------------------------------------------------------
/annotation-app/src/assets/images/refresh.svg:
--------------------------------------------------------------------------------
1 |
3 |
4 |
11 |
--------------------------------------------------------------------------------
/annotation-app/src/assets/images/trash.svg:
--------------------------------------------------------------------------------
1 |
3 |
4 |
11 |
--------------------------------------------------------------------------------
/annotation-app/src/assets/images/vm-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vmware/data-annotator-for-machine-learning/ccc6dbfcc0bd680557f4068df89be5f20c93fcd9/annotation-app/src/assets/images/vm-logo.png
--------------------------------------------------------------------------------
/annotation-app/src/dev-platform/dev-platform.module.ts:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2019-2023 VMware, Inc.
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | import { CommonModule } from '@angular/common';
7 | import { NgModule } from '@angular/core';
8 | import { FormsModule } from '@angular/forms';
9 | import { RouterModule } from '@angular/router';
10 | import { AppModule } from '../app/app.module';
11 | import { DevPlatformComponent } from './dev-platform/dev-platform.component';
12 |
13 | @NgModule({
14 | declarations: [DevPlatformComponent],
15 | imports: [
16 | CommonModule,
17 | FormsModule,
18 | RouterModule.forRoot([
19 | {
20 | path: '',
21 | pathMatch: 'full',
22 | component: DevPlatformComponent,
23 | data: { title: 'loop' },
24 | },
25 | ]),
26 | AppModule,
27 | ],
28 | bootstrap: [DevPlatformComponent],
29 | })
30 | export class DevPlatformModule {}
31 |
--------------------------------------------------------------------------------
/annotation-app/src/dev-platform/dev-platform/dev-platform.component.css:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2019-2024 VMware, Inc.
3 | SPDX-License-Identifier: Apache-2.0
4 | */
--------------------------------------------------------------------------------
/annotation-app/src/dev-platform/dev-platform/dev-platform.component.html:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/annotation-app/src/dev-platform/dev-platform/dev-platform.component.ts:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2019-2023 VMware, Inc.
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | import { Component, OnInit } from '@angular/core';
7 | import { Title } from '@angular/platform-browser';
8 | import { ActivatedRoute, NavigationEnd, Router } from '@angular/router';
9 | import { filter, map } from 'rxjs/operators';
10 |
11 | @Component({
12 | selector: 'mf-dev-platform',
13 | templateUrl: './dev-platform.component.html',
14 | styleUrls: ['./dev-platform.component.css'],
15 | })
16 | export class DevPlatformComponent implements OnInit {
17 | constructor(private router: Router, private titleService: Title) {}
18 |
19 | ngOnInit(): void {
20 | this.updatePageTitleOnRouteChange();
21 | }
22 |
23 | private updatePageTitleOnRouteChange() {
24 | this.router.events
25 | .pipe(
26 | filter((event) => event instanceof NavigationEnd),
27 | map(() => {
28 | let route: ActivatedRoute = this.router.routerState.root;
29 | let routeTitle = '';
30 | while (route!.firstChild) {
31 | route = route.firstChild;
32 | }
33 | if (route.snapshot.data['title']) {
34 | routeTitle = route!.snapshot.data['title'];
35 | }
36 | return routeTitle;
37 | }),
38 | )
39 | .subscribe((title) => {
40 | if (title) {
41 | this.titleService.setTitle(`${title} - Microtrains`);
42 | }
43 | });
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/annotation-app/src/environments/environment.prod.ts:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2019-2023 VMware, Inc.
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | import { Env } from 'src/app/model/index';
7 |
8 | export const environment: Env = {
9 | production: true,
10 | };
11 |
--------------------------------------------------------------------------------
/annotation-app/src/environments/environment.ts:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2019-2023 VMware, Inc.
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | import { Env } from 'src/app/model/index';
7 |
8 | export const environment: Env = {
9 | // This section is required
10 | production: false,
11 | annotationService: 'http://localhost:3000', // Annotation service url
12 | // This section is optional
13 | serviceTitle: 'Data Annotator for Machine Learning', // UI name of annotation-app.
14 | googleTrackId: null, // google track ID
15 | redirectUrl: '/', // redirect URL after logout or token is expired
16 | enableSendEmail: false, // Set to true to enable email notification for project creation, annotator assignment or edit project creator
17 | enableAWSS3: false, // Set to true to upload and download files with AWS S3 that requires some related AWS CONFIG IAM to be configured in annotation-service
18 | enableSlack: false, // Set to true to allow annotator use slack to post message and do annotate. And please follow the path annotation-service/config/app-os.js to set buildSlackApp=true at the same time. While first of all, in order to support this feature you need to create an app from an app manifest which containing basic info, scopes, settings, and features. You can find this yaml file in the path vmware/data-annotator-for-machine-learning/master/docs/manifest.yml.
19 | slackAppName: '', // If enableSlack=true, here should be the slack app name
20 | embedded: false, // Set to true to wrap the service into angular custom element 'mf-loop-entry', and run the script bundle_ to build one complete static js which is required for an micro-front-end app
21 | sessionKey: 'app-session', // All token and user info is saved after this key name in local storage
22 | };
23 |
--------------------------------------------------------------------------------
/annotation-app/src/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vmware/data-annotator-for-machine-learning/ccc6dbfcc0bd680557f4068df89be5f20c93fcd9/annotation-app/src/favicon.ico
--------------------------------------------------------------------------------
/annotation-app/src/index.html:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/annotation-app/src/main.ts:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2019-2023 VMware, Inc.
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
7 | import { DevPlatformModule } from './dev-platform/dev-platform.module';
8 | import { environment } from './environments/environment';
9 | import { MicroFrontendModule } from './micro-frontend/micro-frontend.module';
10 | import { enableProdMode } from '@angular/core';
11 |
12 | if (environment.production && environment.googleTrackId) {
13 | enableProdMode();
14 | // Global site tag (gtag.js) - Google Analytics
15 | const tp = `document.getElementById('track').src ='https://www.googletagmanager.com/gtag/js?id=${environment.googleTrackId}';window.dataLayer=window.dataLayer||[];function gtag(){dataLayer.push(arguments);}gtag('js',new Date());`;
16 | const script1 = document.createElement('script');
17 | script1.async = true;
18 | script1.id = 'track';
19 | document.head.appendChild(script1);
20 | const script2 = document.createElement('script');
21 | script2.innerText = tp;
22 | document.head.appendChild(script2);
23 | }
24 |
25 | const bootstrapModule = environment.embedded ? MicroFrontendModule : DevPlatformModule;
26 |
27 | platformBrowserDynamic()
28 | .bootstrapModule(bootstrapModule)
29 | .catch((err) => console.error('platformBrowserDynamic:::', err));
30 |
--------------------------------------------------------------------------------
/annotation-app/src/micro-frontend/entry.component.ts:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2019-2023 VMware, Inc.
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | import { Component, EventEmitter, Input, OnChanges, OnDestroy, Output, SimpleChanges } from '@angular/core';
7 | import { Router, RoutesRecognized } from '@angular/router';
8 | import { Subscription } from 'rxjs';
9 |
10 | export interface RouterEvent {
11 | url: string;
12 | replaceUrl: boolean;
13 | }
14 |
15 | @Component({
16 | template: '',
17 | })
18 | export class EntryComponent implements OnChanges, OnDestroy {
19 | @Input() route?: string;
20 | @Output() routeChange = new EventEmitter();
21 |
22 | private subscription: Subscription;
23 |
24 | constructor(private router: Router) {
25 | const routingSubscription = this.registerOutgoingRouting();
26 | this.subscription = routingSubscription;
27 | }
28 |
29 | ngOnChanges(changes: SimpleChanges) {
30 | if (changes['route'] && this.route) {
31 | this.router.navigateByUrl(this.route, { state: { fromPlatform: true } });
32 | }
33 | }
34 |
35 | ngOnDestroy(): void {
36 | this.subscription.unsubscribe();
37 | }
38 |
39 | private registerOutgoingRouting(): Subscription {
40 | return this.router.events.subscribe((event) => {
41 | if (event instanceof RoutesRecognized && (!this.isRouteChangeFromPlatform() || this.isRedirect(event))) {
42 | this.routeChange.next({
43 | url: event.urlAfterRedirects,
44 | replaceUrl: this.isRedirect(event),
45 | });
46 | }
47 | });
48 | }
49 |
50 | private isRouteChangeFromPlatform(): boolean {
51 | return this.router.getCurrentNavigation()?.extras?.state?.['fromPlatform'];
52 | }
53 |
54 | private isRedirect(event: RoutesRecognized): boolean {
55 | return event.url !== event.urlAfterRedirects;
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/annotation-app/src/micro-frontend/micro-frontend.module.ts:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2019-2023 VMware, Inc.
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 | import { DoBootstrap, Injector, NgModule } from '@angular/core';
6 | import { createCustomElement } from '@angular/elements';
7 | import { AppModule } from '../app/app.module';
8 | import { EntryComponent } from './entry.component';
9 | @NgModule({
10 | declarations: [EntryComponent],
11 | imports: [AppModule],
12 | })
13 | export class MicroFrontendModule implements DoBootstrap {
14 | constructor(private injector: Injector) {}
15 |
16 | ngDoBootstrap(): void {
17 | const customElement = createCustomElement(EntryComponent, {
18 | injector: this.injector,
19 | });
20 | window.customElements.define('mf-loop-entry', customElement);
21 | console.log('Registered custom element mf-loop-entry');
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/annotation-app/src/polyfills.ts:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2019-2023 VMware, Inc.
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 | /**
6 | * This file includes polyfills needed by Angular and is loaded before the app.
7 | * You can add your own extra polyfills to this file.
8 | *
9 | * This file is divided into 2 sections:
10 | * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers.
11 | * 2. Application imports. Files imported after ZoneJS that should be loaded before your main
12 | * file.
13 | *
14 | * The current setup is for so-called "evergreen" browsers; the last versions of browsers that
15 | * automatically update themselves. This includes recent versions of Safari, Chrome (including
16 | * Opera), Edge on the desktop, and iOS and Chrome on mobile.
17 | *
18 | * Learn more in https://angular.io/guide/browser-support
19 | */
20 |
21 | /***************************************************************************************************
22 | * BROWSER POLYFILLS
23 | */
24 |
25 | /**
26 | * By default, zone.js will patch all possible macroTask and DomEvents
27 | * user can disable parts of macroTask/DomEvents patch by setting following flags
28 | * because those flags need to be set before `zone.js` being loaded, and webpack
29 | * will put import in the top of bundle, so user need to create a separate file
30 | * in this directory (for example: zone-flags.ts), and put the following flags
31 | * into that file, and then add the following code before importing zone.js.
32 | * import './zone-flags';
33 | *
34 | * The flags allowed in zone-flags.ts are listed here.
35 | *
36 | * The following flags will work for all browsers.
37 | *
38 | * (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame
39 | * (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick
40 | * (window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames
41 | *
42 | * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js
43 | * with the following flag, it will bypass `zone.js` patch for IE/Edge
44 | *
45 | * (window as any).__Zone_enable_cross_context_check = true;
46 | *
47 | */
48 |
49 | /***************************************************************************************************
50 | * Zone JS is required by default for Angular itself.
51 | */
52 | import 'zone.js'; // Included with Angular CLI.
53 | (window as any).global = window;
54 |
55 | /***************************************************************************************************
56 | * APPLICATION IMPORTS
57 | */
58 |
--------------------------------------------------------------------------------
/annotation-app/src/styles.scss:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2019-2023 VMware, Inc.
3 | SPDX-License-Identifier: Apache-2.0
4 | */
5 | /* You can add global styles to this file, and also import other style files */
6 | @import '~@ng-select/ng-select/themes/material.theme.css';
7 |
8 | a {
9 | color: currentColor;
10 | }
--------------------------------------------------------------------------------
/annotation-app/tsconfig.app.json:
--------------------------------------------------------------------------------
1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */
2 | {
3 | "extends": "./tsconfig.json",
4 | "compilerOptions": {
5 | "outDir": "./out-tsc/app",
6 | "types": []
7 | },
8 | "files": [
9 | "src/main.ts",
10 | "src/polyfills.ts"
11 | ],
12 | "include": [
13 | "src/environments/*.*.ts",
14 | "src/**/*.d.ts"
15 | ]
16 | }
--------------------------------------------------------------------------------
/annotation-app/tsconfig.json:
--------------------------------------------------------------------------------
1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */
2 | {
3 | "compileOnSave": false,
4 | "compilerOptions": {
5 | "baseUrl": "./",
6 | "outDir": "./dist/out-tsc",
7 | "forceConsistentCasingInFileNames": true,
8 | // "strict": true,
9 | "noImplicitOverride": true,
10 | "noPropertyAccessFromIndexSignature": true,
11 | "noImplicitReturns": false,
12 | "noFallthroughCasesInSwitch": true,
13 | "sourceMap": true,
14 | "declaration": false,
15 | "downlevelIteration": true,
16 | "experimentalDecorators": true,
17 | "moduleResolution": "node",
18 | "importHelpers": true,
19 | "target": "es2020",
20 | "module": "es2020",
21 | "lib": [
22 | "es2020",
23 | "dom"
24 | ]
25 | },
26 | "angularCompilerOptions": {
27 | "enableI18nLegacyMessageIdFormat": false,
28 | // "strictInjectionParameters": true,
29 | // "strictInputAccessModifiers": true,
30 | // "strictTemplates": true
31 | },
32 | }
--------------------------------------------------------------------------------
/annotation-app/tslint.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": ["tslint:recommended", "tslint-angular", "tslint-config-prettier"],
3 | "rules": {
4 | "array-type": false,
5 | "arrow-parens": false,
6 | "deprecation": {
7 | "severity": "warn"
8 | },
9 | "component-class-suffix": true,
10 | "contextual-lifecycle": true,
11 | "directive-class-suffix": true,
12 | "directive-selector": [true, "attribute", "app", "camelCase"],
13 | "component-selector": [true, "element", "app", "kebab-case"],
14 | "import-blacklist": [true, "rxjs/Rx"],
15 | "interface-name": false,
16 | "max-classes-per-file": false,
17 | "max-line-length": [true, 140],
18 | "member-access": false,
19 | "member-ordering": [
20 | true,
21 | {
22 | "order": ["static-field", "instance-field", "static-method", "instance-method"]
23 | }
24 | ],
25 | "no-bitwise": false,
26 | "no-consecutive-blank-lines": false,
27 | "no-console": [true, "debug", "info", "time", "timeEnd", "trace"],
28 | "no-empty": false,
29 | "no-inferrable-types": [true, "ignore-params"],
30 | "no-non-null-assertion": false,
31 | "no-redundant-jsdoc": true,
32 | "no-switch-case-fall-through": true,
33 | "no-var-requires": false,
34 | "object-literal-key-quotes": [true, "as-needed"],
35 | "object-literal-sort-keys": false,
36 | "ordered-imports": false,
37 | "quotemark": [true, "single"],
38 | "trailing-comma": false,
39 | "no-conflicting-lifecycle": true,
40 | "no-host-metadata-property": true,
41 | "no-input-rename": true,
42 | "no-inputs-metadata-property": true,
43 | "no-output-native": true,
44 | "no-output-on-prefix": false,
45 | "no-output-rename": false,
46 | "no-outputs-metadata-property": true,
47 | "template-banana-in-box": true,
48 | "template-no-negated-async": true,
49 | "triple-equals": [false, "allow-null-check"],
50 | "use-lifecycle-interface": true,
51 | "use-pipe-transform-interface": true,
52 | "prefer-for-of": false,
53 | "only-arrow-functions": [false],
54 | "no-shadowed-variable": false,
55 | "prefer-const": false,
56 | "no-eval": false
57 | },
58 | "rulesDirectory": ["codelyzer"]
59 | }
60 |
--------------------------------------------------------------------------------
/annotation-service/Dockerfile:
--------------------------------------------------------------------------------
1 | # Copyright 2019-2021 VMware, Inc.
2 | # SPDX-License-Identifier: Apache-2.0
3 |
4 | # Create image based on the official Node 6 image from the dockerhub
5 | FROM node:16-alpine
6 |
7 | COPY package*.json .
8 |
9 | RUN npm i && mkdir /app && cp -R ./node_modules ./app
10 |
11 | WORKDIR /app
12 |
13 | COPY . .
14 |
15 | # Expose the port the app runs in
16 | EXPOSE 3000
17 |
18 | # Serve the app
19 | CMD ["npm", "run", "serve"]
20 |
--------------------------------------------------------------------------------
/annotation-service/config/config.js:
--------------------------------------------------------------------------------
1 | /***
2 | *
3 | * Copyright 2019-2021 VMware, Inc.
4 | * SPDX-License-Identifier: Apache-2.0
5 | *
6 | ***/
7 |
8 | const sysEnv = process.env.SYS_ENV || "os";
9 | const app = require(`./app-${sysEnv}`);
10 |
11 | module.exports = app
12 |
13 | console.log('----------------------------------------------------------------------------------------');
14 | console.log(`[ CONFIG ] [ SYS_ENV ]=${sysEnv} [app]=`, module.exports);
15 | console.log('----------------------------------------------------------------------------------------');
16 |
--------------------------------------------------------------------------------
/annotation-service/middlewares/jwt.middleware.js:
--------------------------------------------------------------------------------
1 | /***
2 | *
3 | * Copyright 2019-2021 VMware, Inc.
4 | * SPDX-License-Identifier: Apache-2.0
5 | *
6 | ***/
7 |
8 | const jwt = require('express-jwt');
9 | const config = require('../config/config');
10 | const JWTS = require('jsonwebtoken');
11 | const APIs = require('../resources/APIs');
12 |
13 | jwtTokenAuthrization = (data) => {
14 | if (config.ESP) {
15 | return jwt({
16 | secret: data.key.replace(/RSA /g, ''),
17 | algorithms: [data.alg],
18 | issuer: config.tokenIssuer,
19 | getToken: fromHeaderOrQuerystring,
20 | requestProperty: 'auth',
21 | }).unless({
22 | path: [
23 | `${config.API_BASE_PATH}/api/${config.API_VERSION}${APIs.EMAIL_REGULAR_NOTIFICATION}`,
24 | ],
25 | });
26 | } else {
27 | return jwt({
28 | secret: config.TOKEN_SECRET_OR_PRIVATE_KEY,
29 | algorithms: [config.TOKEN_ALGORITHM],
30 | getToken: fromHeaderOrQuerystring,
31 | requestProperty: 'auth',
32 | }).unless({
33 | path: [
34 | `${config.API_BASE_PATH}/api/${config.API_VERSION}${APIs.REGISTER}`,
35 | `${config.API_BASE_PATH}/api/${config.API_VERSION}${APIs.LOGIN}`,
36 | `${config.API_BASE_PATH}/api/${config.API_VERSION}${APIs.EMAIL_REGULAR_NOTIFICATION}`,
37 | ],
38 | });
39 | }
40 |
41 | };
42 |
43 | function fromHeaderOrQuerystring(req) {
44 |
45 | if (req.headers.authorization && req.headers.authorization.split(' ')[0] === 'Bearer') {
46 | return req.headers.authorization.split(' ')[1];
47 | } else if (req.query && req.query.token) {
48 | req.headers.authorization = "Bearer " + req.query.token;
49 | return req.query.token;
50 | }
51 | return null;
52 | }
53 |
54 | async function generateBasicToken(user) {
55 |
56 | const expires_time = Math.floor(Date.now() / 1000) + config.TOKEN_EXPIRE_TIME;
57 | const access_token = await JWTS.sign({
58 | exp: expires_time,
59 | email: user
60 | },
61 | config.TOKEN_SECRET_OR_PRIVATE_KEY,
62 | {
63 | algorithm: config.TOKEN_ALGORITHM
64 | }
65 | );
66 | return {
67 | access_token: access_token,
68 | access_type: "Bearer",
69 | expires_in: config.TOKEN_EXPIRE_TIME,
70 | expires_time: expires_time
71 | }
72 | }
73 |
74 | module.exports = {
75 | jwtTokenAuthrization,
76 | generateBasicToken,
77 | }
--------------------------------------------------------------------------------
/annotation-service/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "annotation-service",
3 | "version": "1.0.0",
4 | "private": true,
5 | "scripts": {
6 | "serve": "node server.js",
7 | "start": "nodemon server.js"
8 | },
9 | "dependencies": {
10 | "@slack/bolt": "^3.11.1",
11 | "@slack/web-api": "^6.7.1",
12 | "aws-sdk": "^2.849.0",
13 | "axios": "^0.24.0",
14 | "body-parser": "^1.19.0",
15 | "compressing": "^1.5.1",
16 | "cors": "2.8.5",
17 | "cron": "^2.0.0",
18 | "csv-writer": "^1.6.0",
19 | "csvtojson": "^2.0.10",
20 | "express": "^4.17.1",
21 | "express-jwt": "^6.0.0",
22 | "hosted-git-info": ">=2.8.9",
23 | "jsonwebtoken": "^8.5.1",
24 | "lodash": "^4.17.21",
25 | "moment": "^2.29.1",
26 | "mongodb": "^3.6.4",
27 | "mongoose": "^5.11.17",
28 | "mongoose-paginate-v2": "^1.8.0",
29 | "multer": "^1.4.2",
30 | "nodemailer": "^6.4.18",
31 | "path": "0.12.7",
32 | "request": "^2.88.2",
33 | "sqs-consumer": "^5.5.0",
34 | "swagger-ui-express": "^4.1.6",
35 | "universal-analytics": "^0.4.23",
36 | "unzip-stream": "^0.3.1"
37 | },
38 | "devDependencies": {
39 | "nodemon": "^2.0.7"
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/annotation-service/resources/template-annotator.html:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
8 |
9 |
Hi,
10 |
A new ${team} annotation task has been assigned to you by
11 | ${projectOwner} for the
12 | ${projectName} project.
13 |
14 |
Click on the link above to view your annotation task. You may need to login first.
15 |
Kind regards,
16 |
${team} Team
17 |
18 |
19 |
--------------------------------------------------------------------------------
/annotation-service/resources/template-generater.html:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
8 |
9 |
Hi,
10 |
You have received a message from ${team} regarding:
11 |
Your dataset ${fileName} is ready for download.
12 |
You may need click the link to login first.
13 |
Kind regards,
14 |
${team} Team
15 |
16 |
17 |
--------------------------------------------------------------------------------
/annotation-service/resources/template-notFinish.html:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
8 |
9 |
Hi ${user},
10 |
Your annotation task ${projectName} assigned to you on ${assignedDate} by ${projectOwner} is nearly complete.
11 |
Please visit the annotations page to finish your task.
12 |
If you don't want to receive such emails in the future, please unsubscribe from here: STOP CURRENT PROJECT REGULAR NOTIFICATION for this project.
13 |
You can also unsubscribe such notification from all projects from here: STOP ALL PROJECTS REGULAR NOTIFICATION.
14 |
Regards,
15 |
${team} Team
16 |
17 |
18 |
--------------------------------------------------------------------------------
/annotation-service/resources/template-notStart.html:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
8 |
9 |
Hi ${user},
10 |
A new annotation task has been assigned to you by ${projectOwner} for the ${projectName} project at ${assignedDate}.
11 |
Please click on the link above and start the annotation task.
12 |
If you don't want to receive such emails in the future, please unsubscribe from here: STOP CURRENT PROJECT REGULAR NOTIFICATION for this project.
13 |
You can also unsubscribe such notification from all projects from here: STOP ALL PROJECTS REGULAR NOTIFICATION.
14 |
Regards,
15 |
${team} Team
16 |
17 |
18 |
--------------------------------------------------------------------------------
/annotation-service/resources/template-owner.html:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
8 |
9 |
Hi,
10 |
You have received a message from ${team} regarding:
11 |
Your project, ${projectName} has been created successfully which generates all annotation cases from ${fileName}
12 |
Click on the link above to view your annotation project. You may need to login first.
13 |
Kind regards,
14 |
${team} Team
15 |
16 |
17 |
--------------------------------------------------------------------------------
/annotation-service/routers/auth-controller.js:
--------------------------------------------------------------------------------
1 | /***
2 | *
3 | * Copyright 2019-2021 VMware, Inc.
4 | * SPDX-License-Identifier: Apache-2.0
5 | *
6 | ***/
7 |
8 |
9 | const express = require("express");
10 | const router = express.Router();
11 | const userService = require("../services/user-service");
12 | const APIs = require('../resources/APIs');
13 | const authService = require("../services/auth.service");
14 |
15 | router.put(APIs.REGISTER, (req, res) => {
16 | console.log(`[ PROJECT ] [ ACCESS ] Router ${req.originalUrl}`);
17 | userService.saveUser(req).then(response => {
18 | console.log(`[ PROJECT ] [ SUCCESS ] Router ${req.originalUrl}`);
19 | res.status(200).json(response);
20 | }).catch(error => {
21 | console.error(`[ PROJECT ] [ ERROR ] Router ${req.originalUrl}`, error);
22 | res.status(500).send(error);
23 | });
24 | });
25 |
26 | router.post(APIs.LOGIN, (req, res) => {
27 | console.log(`[ PROJECT ] [ ACCESS ] Router ${req.originalUrl}`);
28 | authService.login(req).then(response => {
29 | console.log(`[ PROJECT ] [ SUCCESS ] Router ${req.originalUrl}`);
30 | res.status(200).json(response);
31 | }).catch(error => {
32 | console.error(`[ PROJECT ] [ ERROR ] Router ${req.originalUrl}`, error);
33 | res.status(500).send(error);
34 | });
35 | });
36 |
37 | router.get(APIs.TOKEN_REFRESH, (req, res) => {
38 | console.log(`[ PROJECT ] [ ACCESS ] Router ${req.originalUrl} ${req.auth.email}`);
39 | authService.refreshToken(req).then(response => {
40 | console.log(`[ PROJECT ] [ SUCCESS ] Router ${req.originalUrl} ${req.auth.email}`);
41 | res.status(200).json(response);
42 | }).catch(error => {
43 | console.error(`[ PROJECT ] [ ERROR ] Router ${req.originalUrl} ${req.auth.email}`, error);
44 | res.status(500).send(error);
45 | });
46 | });
47 |
48 | module.exports = router;
--------------------------------------------------------------------------------
/annotation-service/routers/community-controller.js:
--------------------------------------------------------------------------------
1 | /***
2 | *
3 | * Copyright 2019-2021 VMware, Inc.
4 | * SPDX-License-Identifier: Apache-2.0
5 | *
6 | ***/
7 |
8 |
9 | const express = require("express");
10 | const router = express.Router();
11 | const APIs = require('../resources/APIs');
12 | const communityService = require('../services/community.service');
13 |
14 |
15 | router.post(APIs.COUNT_COMMUNITY_DOWNLOAD, (req, res) => {
16 | console.log(`[ FILE ] [ ACCESS ] Router ${req.originalUrl} ${req.auth.email}`);
17 | communityService.countCommunityDownload(req).then((response) => {
18 | console.log(`[ FILE ] [ SUCCESS ] Router ${req.originalUrl} ${req.auth.email}`);
19 | res.status(200).json(response);
20 | }).catch(error => {
21 | console.error(`[ FILE ] [ ERROR ] Router ${req.originalUrl} ${req.auth.email}`, error);
22 | res.status(500).send(error);
23 | });
24 | });
25 |
26 | module.exports = router;
--------------------------------------------------------------------------------
/annotation-service/routers/db-controller.js:
--------------------------------------------------------------------------------
1 | /***
2 | *
3 | * Copyright 2019-2021 VMware, Inc.
4 | * SPDX-License-Identifier: Apache-2.0
5 | *
6 | ***/
7 |
8 |
9 | const express = require("express");
10 | const router = express.Router();
11 | const APIs = require('../resources/APIs');
12 | const DBOP = require('../utils/DB.OPERATIONS');
13 |
14 |
15 | router.post(APIs.DB_UPDATE_COLUMN_TYPE, (req, res) => {
16 | console.log(`[ DB ] [ ACCESS ] Router ${req.originalUrl} ${req.auth.email}`);
17 | DBOP.updateDBColumnType(req).then((response) => {
18 | console.log(`[ DB ] [ SUCCESS ] Router ${req.originalUrl} ${req.auth.email}`);
19 | res.status(200).json(response);
20 | }).catch(error => {
21 | console.error(`[ DB ] [ ERROR ] Router ${req.originalUrl} ${req.auth.email}`, error);
22 | res.status(500).send(error);
23 | });
24 | });
25 |
26 |
27 | module.exports = router;
--------------------------------------------------------------------------------
/annotation-service/routers/email-controller.js:
--------------------------------------------------------------------------------
1 | /***
2 | *
3 | * Copyright 2019-2021 VMware, Inc.
4 | * SPDX-License-Identifier: Apache-2.0
5 | *
6 | ***/
7 |
8 |
9 | const express = require("express");
10 | const router = express.Router();
11 | const emailService = require('../services/email-service');
12 | const APIs = require('../resources/APIs');
13 | const taskSchedule = require('../utils/taskSchedule');
14 | const config = require('../config/config');
15 |
16 | router.post(APIs.EMAIL_TO_OWNER, (req, res) => {
17 | console.log(`[ EMAIL ] [ ACCESS ] Router ${req.originalUrl} ${req.auth.email}`);
18 | emailService.sendEmailToOwner(req).then(() => {
19 | console.log(`[ EMAIL ] [ SUCCESS ] Router ${req.originalUrl} ${req.auth.email}`);
20 | res.status(200).json("email ok");
21 | }).catch(error => {
22 | console.error(`[ EMAIL ] [ ERROR ] Router ${req.originalUrl} ${req.auth.email}`, error);
23 | res.status(500).json(error);
24 | });
25 | });
26 |
27 |
28 | router.post(APIs.EMAIL_TO_ANNOTATOR, (req, res) => {
29 | console.log(`[ EMAIL ] [ ACCESS ] Router ${req.originalUrl} ${req.auth.email}`);
30 | emailService.sendEmailToAnnotator(req).then(() => {
31 | console.log(`[ EMAIL ] [ SUCCESS ] Router ${req.originalUrl} ${req.auth.email}`);
32 | res.status(200).json("email ok");
33 | }).catch(error => {
34 | console.error(`[ EMAIL ] [ ERROR ] Router ${req.originalUrl} ${req.auth.email}`, error);
35 | res.status(500).json(error);
36 | });
37 | });
38 |
39 | router.get(APIs.EMAIL_REGULAR_NOTIFICATION, (req, res) => {
40 | console.log(`[ EMAIL ] [ ACCESS ] Router ${req.originalUrl} ${req.query.u}`);
41 | taskSchedule.regularNotificationSubscription(req).then(() => {
42 | console.log(`[ EMAIL ] [ SUCCESS ] Router ${req.originalUrl} ${req.query.u}`);
43 | res.status(200).redirect(`${config.WebClientUrl}/home?o=email&s=1`);
44 | }).catch(error => {
45 | console.error(`[ EMAIL ] [ ERROR ] Router ${req.originalUrl} ${req.query.u}`, error);
46 | res.status(500).redirect(`${config.WebClientUrl}/home?o=email&s=0`);
47 | });
48 | });
49 |
50 | module.exports = router;
--------------------------------------------------------------------------------
/annotation-service/routers/integration-controller.js:
--------------------------------------------------------------------------------
1 | /***
2 | *
3 | * Copyright 2019-2021 VMware, Inc.
4 | * SPDX-License-Identifier: Apache-2.0
5 | *
6 | ***/
7 |
8 |
9 | const express = require("express");
10 | const router = express.Router();
11 | const APIs = require('../resources/APIs');
12 | const IntegrationService = require("../services/integration.service");
13 |
14 | router.post(APIs.INTEGRATION_CSV, (req, res) => {
15 | console.log(`[ INTEGRATION ] [ ACCESS ] Router ${req.originalUrl} ${req.auth.email}`);
16 | IntegrationService.SyncLabelledCaseToInstaML(req).then(response =>{
17 | console.log(`[ INTEGRATION ] [ SUCCESS ] Router ${req.originalUrl} ${req.auth.email}`);
18 | res.status(200).json(response);
19 | }).catch(error =>{
20 | console.error(`[ INTEGRATION ] [ ERROR ] Router ${req.originalUrl} ${req.auth.email}`, error);
21 | res.status(500).send(error);
22 | });
23 | });
24 |
25 | module.exports = router;
--------------------------------------------------------------------------------
/annotation-service/routers/scripts-controller.js:
--------------------------------------------------------------------------------
1 | /***
2 | *
3 | * Copyright 2019-2022 VMware, Inc.
4 | * SPDX-License-Identifier: Apache-2.0
5 | *
6 | ***/
7 |
8 |
9 | const express = require("express");
10 | const router = express.Router();
11 | const APIs = require('../resources/APIs');
12 | const IPDS = require('../utils/ImportDataset.util');
13 | const RIM = require('../scripts/reveiwInfoMigration');
14 |
15 | router.post(APIs.DATASET_IMPORT, (req, res) => {
16 | console.log(`[ SCRIPTE ] [ ACCESS ] Router ${req.originalUrl} ${req.auth.email}`);
17 | IPDS.importDataset(req).then((response) => {
18 | console.log(`[ SCRIPTE ] [ SUCCESS ] Router ${req.originalUrl} ${req.auth.email}`);
19 | res.status(200).json(response);
20 | }).catch(error => {
21 | console.error(`[ SCRIPTE ] [ ERROR ] Router ${req.originalUrl} ${req.auth.email}`, error);
22 | res.status(500).send(error);
23 | });
24 | });
25 |
26 | router.get(APIs.MIGRATION_REVIEW_INFO, (req, res) => {
27 | console.log(`[ SCRIPTE ] [ ACCESS ] Router ${req.originalUrl} ${req.auth.email}`);
28 | RIM.migrationAllTicketsReviewInfo(req).then((response) => {
29 | console.log(`[ SCRIPTE ] [ SUCCESS ] Router ${req.originalUrl} ${req.auth.email}`);
30 | res.status(200).json(response);
31 | }).catch(error => {
32 | console.error(`[ SCRIPTE ] [ ERROR ] Router ${req.originalUrl} ${req.auth.email}`, error);
33 | res.status(500).send(error);
34 | });
35 | });
36 |
37 | module.exports = router;
--------------------------------------------------------------------------------
/annotation-service/routers/slack-controller.js:
--------------------------------------------------------------------------------
1 | /***
2 | *
3 | * Copyright 2019-2021 VMware, Inc.
4 | * SPDX-License-Identifier: Apache-2.0
5 | *
6 | ***/
7 |
8 |
9 | const express = require("express");
10 | const router = express.Router();
11 | const APIs = require('../resources/APIs');
12 | const slackConversations = require("../services/slack/slackConversations.service")
13 |
14 | router.post(APIs.CONVERSATION_LIST, (req, res) => {
15 | console.log(`[ SLACK ] [ ACCESS ] Router ${req.originalUrl} ${req.auth.email}`);
16 | slackConversations.findConversation(req).then(response => {
17 | console.log(`[ SLACK ] [ SUCCESS ] Router ${req.originalUrl} ${req.auth.email}`);
18 | res.status(200).json(response);
19 | }).catch(error => {
20 | console.error(`[ SLACK ] [ ERROR ] Router ${req.originalUrl} ${req.auth.email}`, error);
21 | res.status(500).send(error);
22 | });
23 | });
24 |
25 |
26 |
27 | module.exports = router;
--------------------------------------------------------------------------------
/annotation-service/services/authForNoe.service.js:
--------------------------------------------------------------------------------
1 | /***
2 | *
3 | * Copyright 2019-2021 VMware, Inc.
4 | * SPDX-License-Identifier: Apache-2.0
5 | *
6 | ***/
7 |
8 |
9 | const axios = require('axios');
10 | const config = require('../config/config');
11 | const MESSAGE = require('../config/code_msg');
12 |
13 | let token;
14 | let expirationDate;
15 |
16 | const generateEsp2NoeToken = async() => {
17 |
18 | const response = await axios
19 | .create({
20 | validateStatus: () => {
21 | return true;
22 | },
23 | })
24 | .post(`${config.authServiceUrl}/api/auth/v1/tokens`, {
25 | grant_type: 'client_credentials',
26 | client_id: `${config.esp2NoeClientId}`,
27 | client_secret: `${config.esp2NoeClientSecret}`,
28 | });
29 |
30 | if (response.status === 200) {
31 | console.log('[ ESP-TOKEN ] Utils generateEsp2NoeToken success');
32 | return response.data;
33 | }
34 |
35 | console.error('[ ESP-TOKEN ] [ ERROR ] Utils generateEsp2NoeToken: ', response.data);
36 | MESSAGE.VALIDATION_UNAUTH_TOKEN.DATA = [{ statusText: response.statusText, data: response.data }]
37 | throw MESSAGE.VALIDATION_UNAUTH_TOKEN;
38 | };
39 |
40 | module.exports.getEsp2NoeToken = async() => {
41 | console.log('[ ESP-TOKEN ] Utils getEsp2NoeToken');
42 | if (token === undefined || expirationDate === undefined || expirationDate < new Date()) {
43 | const data = await generateEsp2NoeToken();
44 | token = data.access_token;
45 | expirationDate = new Date(Date.now() + data.expires_in * 1000 - 1000);
46 | }
47 | return token;
48 | };
--------------------------------------------------------------------------------
/annotation-service/services/community.service.js:
--------------------------------------------------------------------------------
1 | /***
2 | *
3 | * Copyright 2019-2021 VMware, Inc.
4 | * SPDX-License-Identifier: Apache-2.0
5 | *
6 | ***/
7 |
8 |
9 | const { DOWNLOADSRC } = require('../config/constant');
10 | const ObjectId = require("mongodb").ObjectID;
11 | const mongoDb = require('../db/mongo.db');
12 | const { ProjectModel } = require('../db/db-connect');
13 |
14 | async function countCommunityDownload(req){
15 |
16 | const src = req.body.src? req.body.src: req.query.src;
17 |
18 | if(src == DOWNLOADSRC.COMMUNITY){
19 |
20 | const pid = req.body.pid? req.body.pid: req.query.pid;
21 |
22 | console.log(`[ COMMUNITY ] service countCommunityDownload proId: ${pid} user: ${req.auth.email}`);
23 |
24 | const conditions = { _id: ObjectId(pid) };
25 | const update = { $inc: {"downloadCount.community": 1 } };
26 | await mongoDb.findOneAndUpdate(ProjectModel, conditions, update);
27 |
28 | }
29 |
30 | }
31 |
32 | module.exports = {
33 | countCommunityDownload,
34 | }
--------------------------------------------------------------------------------
/annotation-service/services/s3.service.js:
--------------------------------------------------------------------------------
1 | /***
2 | *
3 | * Copyright 2019-2021 VMware, Inc.
4 | * SPDX-License-Identifier: Apache-2.0
5 | *
6 | ***/
7 |
8 |
9 | const STS = require('../utils/sts');
10 | const S3 = require('../utils/s3');
11 | const config = require('../config/config');
12 | const localFileSysService = require('./localFileSys.service');
13 | const { ACCESS_TIME_60, AWSRESOURCE } = require('../config/constant');
14 | const mongoDb = require('../db/mongo.db');
15 | const { UserModel } = require('../db/db-connect');
16 | const MESSAGE = require('../config/code_msg');
17 |
18 |
19 | async function prepareS3Configs(req) {
20 | console.log(`[ S3 ] Service prepareS3Configs user: `, req.auth.email);
21 | const user = await mongoDb.findById(UserModel, req.auth.email);
22 | if (!user) {
23 | throw MESSAGE.VALIDATION_PERMITION;
24 | }
25 | console.log(`[ S3 ] Service check if is valid user`);
26 |
27 | let reponse = {
28 | bucket: Buffer.from(config.bucketName).toString('base64'),
29 | region: Buffer.from(config.region).toString('base64'),
30 | key: Buffer.from(`upload/${user._id}`).toString('base64'),
31 | apiVersion: Buffer.from('2006-03-01').toString('base64'),
32 | credentials: ""
33 | }
34 | const data = await STS.prepareCredentials(AWSRESOURCE.S3, ACCESS_TIME_60);
35 | reponse.credentials = {
36 | accessKeyId: Buffer.from(data.Credentials.AccessKeyId).toString('base64'),
37 | secretAccessKey: Buffer.from(data.Credentials.SecretAccessKey).toString('base64'),
38 | sessionToken: Buffer.from(data.Credentials.SessionToken).toString('base64')
39 | }
40 | console.log(`[ S3 ] Service prepare sts access credentials `);
41 | return reponse;
42 | }
43 |
44 |
45 | async function deleteOriginalFile(key) {
46 | console.log(`[ S3 ] Service deleteOriginalFile.S3.deleteAnObject`, key);
47 | return S3.deleteAnObject(key);
48 | }
49 |
50 | async function uploadFileToS3(file, key) {
51 | console.log(`[ S3 ] Service uploadFileToS3 read temp file stream`, file);
52 | let fileStream = await localFileSysService.readFileFromLocalSys(file);
53 |
54 | console.log(`[ S3 ] Service uploadFileToS3.S3.uploadObject`, key);
55 | return S3.uploadObject(key, fileStream);
56 |
57 | }
58 |
59 | module.exports = {
60 | prepareS3Configs,
61 | deleteOriginalFile,
62 | uploadFileToS3,
63 |
64 | }
--------------------------------------------------------------------------------
/annotation-service/services/slack/slack.js:
--------------------------------------------------------------------------------
1 | /***
2 | *
3 | * Copyright 2019-2021 VMware, Inc.
4 | * SPDX-License-Identifier: Apache-2.0
5 | *
6 | ***/
7 |
8 |
9 | const config = require('../../config/config');
10 | const { App: Bolt, LogLevel } = require('@slack/bolt');
11 | const slackBuildAppHome = require('./slackBuildAppHome.service');
12 | const slackAnnotateModalService = require('./slackAnnotateModal.service')
13 |
14 |
15 |
16 | async function newBolt() {
17 | return new Bolt({
18 | token: config.slackBotUserOAuthToken,
19 | signingSecret: config.slackSigningSecret,
20 | socketMode: true,
21 | appToken: config.slackAppToken,
22 | // logLevel: LogLevel.DEBUG
23 | logLevel: LogLevel.ERROR
24 |
25 | });
26 | }
27 |
28 |
29 | async function slackStart() {
30 | // start your app
31 | const bolt = await newBolt();
32 | await bolt.start();
33 | console.log(`⚡️⚡️⚡️ Bolt app is running on localhost:${config.serverPort}`)
34 | await slackBuildAppHome.buildAppHome(bolt);
35 |
36 | // to listening all the start-annotate-btn
37 | bolt.action({ action_id: "click_btn_start_annotate" },
38 | async ({ body, client, ack, logger }) => {
39 | await ack();
40 | try {
41 | if (body.user && body.actions) {
42 | //open modal within 3 seconds
43 | await slackAnnotateModalService.openModal(bolt, client, body)
44 | }
45 | }
46 | catch (error) {
47 | logger.error(error);
48 | }
49 | });
50 |
51 | // to listening all the radio
52 | await slackAnnotateModalService.actionListening(bolt, "annotate_label_radio")
53 | await slackAnnotateModalService.actionListening(bolt, "flag_btn")
54 | await slackAnnotateModalService.actionListening(bolt, "skip_btn")
55 |
56 | }
57 |
58 |
59 |
60 |
61 | module.exports = { slackStart }
--------------------------------------------------------------------------------
/annotation-service/services/slack/slackChat.service.js:
--------------------------------------------------------------------------------
1 | /***
2 | *
3 | * Copyright 2019-2021 VMware, Inc.
4 | * SPDX-License-Identifier: Apache-2.0
5 | *
6 | ***/
7 |
8 | const config = require('../../config/config');
9 | const { WebClient } = require('@slack/web-api');
10 | const web = new WebClient(config.slackBotUserOAuthToken);
11 |
12 |
13 |
14 | async function publishMessage(data) {
15 | try {
16 | let blocks = await generateMessageBlocks(data);
17 | // Call the chat.postMessage method using the built-in WebClient
18 | for (let i = 0; i < data.channels.length; i++) {
19 | await web.chat.postMessage({
20 | channel: data.channels[i].slackName,
21 | text: `:loud_sound:${data.pname} is ready to annotate.`,
22 | blocks: blocks
23 | });
24 | }
25 | }
26 | catch (error) {
27 | console.error(error);
28 | return error;
29 | }
30 | }
31 |
32 |
33 | async function generateMessageBlocks(data) {
34 | return [
35 | {
36 | "type": "header",
37 | "text": {
38 | "type": "plain_text",
39 | "text": `${data.pname} is ready to annotate`
40 | }
41 | },
42 | {
43 | "type": "divider"
44 | },
45 | {
46 | "type": "section",
47 | "text": {
48 | "type": "mrkdwn",
49 | "text": ` >*Project Name:* ${data.pname} \n>*Create Date:* ${data.createdDate}\n>*Creator:* ${data.creator}\n>*Total Tickets:* ${data.totalCase}\n`
50 | }
51 | },
52 | {
53 | "type": "actions",
54 | "elements": [
55 | {
56 | "type": "button",
57 | "text": {
58 | "type": "plain_text",
59 | "text": "Start Annotate"
60 | },
61 | "style": "primary",
62 | "value": `${data.pid}`,
63 | "action_id": "click_btn_start_annotate"
64 | }
65 | ]
66 | },
67 | {
68 | "type": "context",
69 | "elements": [
70 | {
71 | "type": "mrkdwn",
72 | "text": `:information_desk_person: For more detail, please visit <${config.WebClientUrl}|${config.teamTitle}>`
73 | }
74 | ]
75 | }
76 | ]
77 |
78 | }
79 | module.exports = {
80 | publishMessage,
81 | }
82 |
83 |
--------------------------------------------------------------------------------
/annotation-service/services/slack/slackConversations.service.js:
--------------------------------------------------------------------------------
1 | /***
2 | *
3 | * Copyright 2019-2021 VMware, Inc.
4 | * SPDX-License-Identifier: Apache-2.0
5 | *
6 | ***/
7 |
8 | const config = require('../../config/config');
9 | const { WebClient } = require('@slack/web-api');
10 | const web = new WebClient(config.slackBotUserOAuthToken);
11 |
12 |
13 |
14 | async function findConversation(req) {
15 | try {
16 | let id = req.body.slackId
17 | const result = await web.conversations.info({ channel: id });
18 | if (result.ok) {
19 | return { id: result.channel.id, name: result.channel.name, is_member: result.channel.is_member }
20 | } else {
21 | return
22 | }
23 | }
24 | catch (error) {
25 | return
26 | }
27 | }
28 |
29 |
30 |
31 |
32 | module.exports = {
33 | findConversation
34 | }
35 |
36 |
--------------------------------------------------------------------------------
/annotation-service/services/slack/slackUsers.service.js:
--------------------------------------------------------------------------------
1 | /***
2 | *
3 | * Copyright 2019-2021 VMware, Inc.
4 | * SPDX-License-Identifier: Apache-2.0
5 | *
6 | ***/
7 |
8 | const config = require('../../config/config');
9 | const _ = require("lodash");
10 | const { WebClient } = require('@slack/web-api');
11 | const web = new WebClient(config.slackBotUserOAuthToken);
12 |
13 |
14 |
15 | async function findUserInChannels(event, slackIds) {
16 | try {
17 | let params = {
18 | limit: 1000,
19 | user: event.user,
20 | team_id: event.view.team_id,
21 | types: "public_channel,private_channel",
22 | cursor: ''
23 | }
24 | let found = 0;
25 | while (found === 0) {
26 | const result = await web.users.conversations(params);
27 | params.cursor = result.response_metadata.next_cursor;
28 | let arr = _.intersection(slackIds, _.map(result.channels, "id"));
29 | if (arr.length > 0) {
30 | found = 1;
31 | return found;
32 | }
33 | if (result.response_metadata.next_cursor === "") {
34 | found = 2;
35 | return found;
36 | }
37 | }
38 | }
39 | catch (error) {
40 | return error
41 | }
42 | }
43 |
44 |
45 | module.exports = {
46 | findUserInChannels
47 | }
48 |
49 |
--------------------------------------------------------------------------------
/annotation-service/services/slack/utils/accessToken.service.js:
--------------------------------------------------------------------------------
1 | /***
2 | *
3 | * Copyright 2019-2021 VMware, Inc.
4 | * SPDX-License-Identifier: Apache-2.0
5 | *
6 | ***/
7 |
8 |
9 | const axios = require('axios');
10 | const config = require('../../../config/config');
11 | const qs = require('qs');
12 | const { generateBasicToken } = require("../../../middlewares/jwt.middleware")
13 | const MESSAGE = require('../../../config/code_msg');
14 |
15 | let token;
16 | let expirationDate;
17 |
18 |
19 | async function generateEspToken() {
20 | const url = config.espTokenAuthorizeUrl;
21 | const data = qs.stringify({ token: config.espToken });
22 | const configs = { headers: { "Content-Type": "application/x-www-form-urlencoded" } }
23 | try {
24 | const res = await axios.post(url, data, configs);
25 | if (res.status === 200) {
26 | console.log('[ ESP-TOKEN ] Utils generateEspToken success');
27 | return res.data;
28 | }
29 | }
30 | catch (error) {
31 | console.error('[ ESP-TOKEN ] [ ERROR ] Utils generateEspToken: ', error);
32 | MESSAGE.VALIDATION_UNAUTH_TOKEN.DATA = [error.data];
33 | MESSAGE.VALIDATION_UNAUTH_TOKEN.MSG = error.msg;
34 | throw MESSAGE.VALIDATION_UNAUTH_TOKEN;
35 | }
36 | }
37 |
38 |
39 |
40 | async function getEspToken(email) {
41 | console.log('[ ESP-TOKEN ] Utils getEspToken');
42 | if (token === undefined || expirationDate === undefined || expirationDate < new Date()) {
43 | if (config.ESP) {
44 | var dataObj = await generateEspToken();
45 | } else {
46 | var dataObj = await generateBasicToken(email);
47 | }
48 | token = dataObj.access_token;
49 | expirationDate = new Date(Date.now() + dataObj.expires_in * 1000 - 1000);
50 | }
51 | return token;
52 | }
53 |
54 | module.exports = { getEspToken }
--------------------------------------------------------------------------------
/annotation-service/services/slack/utils/slack.utils.js:
--------------------------------------------------------------------------------
1 |
2 | /***
3 | *
4 | * Copyright 2019-2021 VMware, Inc.
5 | * SPDX-License-Identifier: Apache-2.0
6 | *
7 | ***/
8 | const _ = require("lodash");
9 |
10 |
11 |
12 | async function generateObj(type, text, style, value, action_id, block_id) {
13 | let obj = {
14 | "type": type,
15 | "text": text,
16 | "style": style,
17 | "value": value,
18 | "action_id": action_id,
19 | "block_id": block_id
20 |
21 | }
22 | return obj
23 | }
24 |
25 |
26 | async function returnAllPageFunc(pageSize, arr) {
27 | let pageNum = 1
28 | let pageObj = {
29 | pageSize,
30 | total: arr.length,
31 | pageNum: 1,
32 | data: []
33 | }
34 | let pageResult = []
35 |
36 | let newArr = _.cloneDeep(arr);
37 | let totalPage = newArr.length ? Math.ceil(arr.length / pageSize) : 0
38 |
39 | for (let i = 1; i <= totalPage; i++) {
40 | if (totalPage == 1) {
41 | pageNum += 1
42 | pageObj.data = newArr.splice(0, arr.length)
43 | } else if (i <= totalPage) {
44 | pageNum += 1
45 | pageObj.data = newArr.splice(0, pageSize)
46 | } else {
47 | pageObj.data = newArr.splice(0, arr.length % pageSize)
48 | }
49 | pageResult.push(pageObj)
50 | pageObj = {
51 | pageSize,
52 | total: arr.length,
53 | pageNum: pageNum,
54 | data: []
55 | }
56 | }
57 | return pageResult
58 | }
59 |
60 | module.exports = {
61 | generateObj,
62 | returnAllPageFunc
63 | }
64 |
--------------------------------------------------------------------------------
/annotation-service/utils/DB.OPERATIONS.js:
--------------------------------------------------------------------------------
1 | /***
2 | *
3 | * Copyright 2019-2021 VMware, Inc.
4 | * SPDX-License-Identifier: Apache-2.0
5 | *
6 | ***/
7 |
8 |
9 | const { ProjectModel, UserModel, DataSetModel, ImgModel, SrModel } = require("../db/db-connect");
10 | const mongoDb = require("../db/mongo.db");
11 |
12 |
13 | async function updateDBColumnType(req) {
14 | const MODEL = await getProjectModel(req.body.collection);
15 | const column = req.body.column;
16 | const datas = await mongoDb.findByConditions(MODEL, {}, "_id " + column);
17 | console.log(`[ DB.OPERATIONS ] Utils total case ${datas.length}`);
18 | let updateIndex = 0, start = Date.now();
19 | for (const data of datas) {
20 | let update = null;
21 | if (req.body.str2array) {
22 | update = {
23 | $set: {
24 | [column]: data[column]
25 | }
26 | }
27 | }
28 | updateIndex += 1;
29 | await mongoDb.findOneAndUpdate(MODEL, {_id: data._id}, update);
30 | }
31 | console.log(`[ DB.OPERATIONS ] Utils update total case ${updateIndex} time: ${ (Date.now() - start)/1000 }`);
32 | return {TCASE: datas.length, UPCASE: updateIndex};
33 |
34 | }
35 |
36 | async function getProjectModel(collection) {
37 | switch (collection) {
38 | case "projects":
39 | return ProjectModel;
40 | case "srs":
41 | return SrModel;
42 | case "images":
43 | return ImgModel;
44 | case "users":
45 | return UserModel;
46 | case "datasets":
47 | return DataSetModel;
48 | default:
49 | return;
50 | }
51 | }
52 |
53 | module.exports = {
54 | updateDBColumnType,
55 | getProjectModel,
56 | }
--------------------------------------------------------------------------------
/annotation-service/utils/common.utils.js:
--------------------------------------------------------------------------------
1 |
2 | /***
3 | *
4 | * Copyright 2019-2021 VMware, Inc.
5 | * SPDX-License-Identifier: Apache-2.0
6 | *
7 | ***/
8 |
9 |
10 | const _ = require("lodash");
11 |
12 | //Find the most frequent element in the array
13 | async function findFrequentlyElementInArray(arr) {
14 |
15 | let maxEle;
16 | let maxNum = 1;
17 | const obj = arr.reduce(function (p, k) {
18 | p[k] ? p[k]++ : p[k] = 1;
19 | if (p[k] >= maxNum) {
20 | maxEle = k;
21 | maxNum++;
22 | }
23 | return p;
24 | }, {})
25 |
26 | const times = Object.values(obj);
27 | const max = _.max(times);
28 |
29 | if (_.indexOf(times, max) == _.lastIndexOf(times, max)) {
30 | return maxEle;
31 | }
32 | return null;
33 |
34 | }
35 |
36 | async function findFrequentlyElementInObject(obj) {
37 |
38 | const values = Object.values(obj);
39 | const keys = Object.keys(obj);
40 | const maxV = _.max(values);
41 |
42 | if (!_.sum(values)) {
43 | return null;
44 | }
45 | // more than one max value take first
46 | const key = keys[_.indexOf(values, maxV)];
47 | return { [key]: obj[key] };
48 |
49 | //max value is only one
50 | // if(_.indexOf(values, maxV) == _.lastIndexOf(values, maxV)){
51 | // let resp = {};
52 | // resp[keys[_.indexOf(values, maxV)]] = obj[keys[_.indexOf(values, maxV)]];
53 | // return resp;
54 | // }
55 |
56 | }
57 |
58 |
59 | async function probabilisticInObject(obj) {
60 |
61 | const values = Object.values(obj);
62 | const total = (_.sum(values) == 0 ? 1 : _.sum(values));
63 |
64 | let probabilistic = {};
65 | for (const [key, value] of Object.entries(obj)) {
66 | probabilistic[key] = _.round(_.divide(value, total), 2);
67 | }
68 | return probabilistic;
69 | }
70 |
71 | async function formatDate(timestamp) {
72 | let date = new Date(timestamp);
73 | let year = date.getFullYear();
74 | let month = date.getMonth() + 1;
75 | month = month < 10 ? ('0' + month) : month;
76 | let day = date.getDate();
77 | day = day < 10 ? ('0' + day) : day;
78 | let h = date.getHours();
79 | h = h < 10 ? ('0' + h) : h;
80 | let m = date.getMinutes();
81 | m = m < 10 ? ('0' + m) : m;
82 | let s = date.getSeconds();
83 | s = s < 10 ? ('0' + s) : s;
84 | return year + '-' + month + '-' + day + ' ' + h + ':' + m + ':' + s;
85 | }
86 |
87 | module.exports = {
88 | findFrequentlyElementInArray,
89 | findFrequentlyElementInObject,
90 | probabilisticInObject,
91 | formatDate
92 | }
93 |
--------------------------------------------------------------------------------
/annotation-service/utils/fileSystem.utils.js:
--------------------------------------------------------------------------------
1 |
2 | /***
3 | *
4 | * Copyright 2019-2021 VMware, Inc.
5 | * SPDX-License-Identifier: Apache-2.0
6 | *
7 | ***/
8 |
9 | const config = require("../config/config");
10 | const localFileSysService = require('../services/localFileSys.service');
11 | const request = require('request');
12 | const S3Utils = require('./s3');
13 | const { S3OPERATIONS } = require('../config/constant');
14 | const MESSAGE = require('../config/code_msg')
15 |
16 | async function handleFileStream(fileLocation) {
17 |
18 | if (config.ESP || !config.useLocalFileSys && config.useAWS && config.bucketName && config.s3RoleArn) {
19 |
20 | console.log(`[ FILE_SYSTEM ] Utils S3Utils.signedUrlByS3`);
21 | const signedUrl = await S3Utils.signedUrlByS3(S3OPERATIONS.GETOBJECT, fileLocation);
22 | return request.get(signedUrl);
23 |
24 | }else if (config.useLocalFileSys && !config.useAWS) {
25 |
26 | console.log(`[ FILE_SYSTEM ] Utils localFileSysService.readFileFromLocalSys`);
27 | return localFileSysService.readFileFromLocalSys(fileLocation);
28 |
29 | }else{
30 |
31 | throw MESSAGE.VALIDATION_FILE_SYS;
32 |
33 | }
34 |
35 | }
36 |
37 |
38 | module.exports={
39 | handleFileStream,
40 | }
--------------------------------------------------------------------------------
/annotation-service/utils/mongoModel.utils.js:
--------------------------------------------------------------------------------
1 | /***
2 | *
3 | * Copyright 2019-2021 VMware, Inc.
4 | * SPDX-License-Identifier: Apache-2.0
5 | *
6 | ***/
7 |
8 |
9 | const { PROJECTTYPE } = require("../config/constant");
10 | const { ImgModel, SrModel, LogModel } = require("../db/db-connect");
11 | const validator = require("./validator");
12 |
13 |
14 | async function getModelProject(conditions) {
15 | const project = await validator.checkProjectByconditions(conditions, true);
16 | let model = SrModel;
17 | if (project[0].projectType == PROJECTTYPE.IMGAGE) {
18 | model = ImgModel;
19 | }else if (project[0].projectType == PROJECTTYPE.LOG) {
20 | model = LogModel;
21 | }
22 | return {model: model, project: project[0]};
23 | }
24 |
25 |
26 | module.exports = {
27 | getModelProject,
28 | }
--------------------------------------------------------------------------------
/docker-compose-host-db.yml:
--------------------------------------------------------------------------------
1 | # Copyright 2019-2021 VMware, Inc.
2 | # SPDX-License-Identifier: Apache-2.0
3 |
4 | version: '2'
5 | services:
6 | annotation-app:
7 | container_name: app
8 | image: 1107899648/vmware-daml-annotation-app:latest
9 | depends_on:
10 | - annotation-service
11 | ports:
12 | - "4200:4200"
13 | networks:
14 | - bridge
15 | restart: always
16 |
17 | annotation-service:
18 | container_name: as
19 | image: 1107899648/vmware-daml-annotation-service:latest
20 | environment:
21 | - MONGODB_URL=mongodb://host.docker.internal:27017/daml
22 | - LOOP_AL_URL=http://als:8000/api
23 | depends_on:
24 | - active-learning-service
25 | ports:
26 | - "3000:3000"
27 | networks:
28 | - bridge
29 | volumes:
30 | - "./data/as:/app/FILE_SYS"
31 | restart: always
32 |
33 | active-learning-service:
34 | container_name: als
35 | image: 1107899648/vmware-daml-active-learning-service:latest
36 | environment:
37 | - MONGODB_URL=mongodb://host.docker.internal:27017/daml
38 | - SPACY_MODEL=en_core_web_md
39 | ports:
40 | - "8000:8000"
41 | networks:
42 | - bridge
43 | volumes:
44 | - "./data/als:/app/models"
45 | restart: always
46 |
47 | networks:
48 | bridge:
49 | driver: bridge
--------------------------------------------------------------------------------
/docker-compose.yml:
--------------------------------------------------------------------------------
1 | # Copyright 2019-2021 VMware, Inc.
2 | # SPDX-License-Identifier: Apache-2.0
3 |
4 | version: '2'
5 | services:
6 | annotation-app:
7 | container_name: app
8 | image: 1107899648/vmware-daml-annotation-app:latest
9 | depends_on:
10 | - annotation-service
11 | ports:
12 | - "4200:4200"
13 | networks:
14 | - bridge
15 | restart: always
16 |
17 | annotation-service:
18 | container_name: as
19 | image: 1107899648/vmware-daml-annotation-service:latest
20 | environment:
21 | - MONGODB_URL=mongodb://db:27017/daml
22 | - LOOP_AL_URL=http://als:8000/api
23 | depends_on:
24 | - mongo
25 | - active-learning-service
26 | ports:
27 | - "3000:3000"
28 | networks:
29 | - bridge
30 | volumes:
31 | - "./data/as:/app/FILE_SYS"
32 | restart: always
33 |
34 | active-learning-service:
35 | container_name: als
36 | image: 1107899648/vmware-daml-active-learning-service:latest
37 | environment:
38 | - MONGODB_URL=mongodb://db:27017/daml
39 | - SPACY_MODEL=en_core_web_md
40 | depends_on:
41 | - mongo
42 | ports:
43 | - "8000:8000"
44 | networks:
45 | - bridge
46 | volumes:
47 | - "./data/als:/app/models"
48 | restart: always
49 |
50 | mongo:
51 | image: mongo:latest
52 | container_name: db
53 | ports:
54 | - "27017:27017"
55 | networks:
56 | - bridge
57 | volumes:
58 | - "./data/db:/data/db"
59 | restart: always
60 |
61 | networks:
62 | bridge:
63 | driver: bridge
64 |
--------------------------------------------------------------------------------
/docs/AWS-step-by-step-config-with-chart.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vmware/data-annotator-for-machine-learning/ccc6dbfcc0bd680557f4068df89be5f20c93fcd9/docs/AWS-step-by-step-config-with-chart.pdf
--------------------------------------------------------------------------------
/docs/manifest.yml:
--------------------------------------------------------------------------------
1 | display_information:
2 | name: please enter your slack app name here
3 | features:
4 | app_home:
5 | home_tab_enabled: true
6 | messages_tab_enabled: true
7 | messages_tab_read_only_enabled: false
8 | bot_user:
9 | display_name: please enter your slack app name here
10 | always_online: true
11 | oauth_config:
12 | scopes:
13 | user:
14 | - users:read.email
15 | - users:read
16 | bot:
17 | - channels:read
18 | - chat:write
19 | - chat:write.customize
20 | - groups:read
21 | - im:history
22 | - im:read
23 | - incoming-webhook
24 | - mpim:read
25 | - users:read.email
26 | - users:read
27 | settings:
28 | event_subscriptions:
29 | bot_events:
30 | - app_home_opened
31 | - message.im
32 | interactivity:
33 | is_enabled: true
34 | org_deploy_enabled: false
35 | socket_mode_enabled: true
36 | token_rotation_enabled: false
37 |
--------------------------------------------------------------------------------
/docs/tutorial/annotator-screen.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vmware/data-annotator-for-machine-learning/ccc6dbfcc0bd680557f4068df89be5f20c93fcd9/docs/tutorial/annotator-screen.png
--------------------------------------------------------------------------------
/docs/tutorial/project-screen.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vmware/data-annotator-for-machine-learning/ccc6dbfcc0bd680557f4068df89be5f20c93fcd9/docs/tutorial/project-screen.png
--------------------------------------------------------------------------------