Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
98 commits
Select commit Hold shift + click to select a range
5bdd704
Initial UI setup for Geti Inspect
MarkRedeman Aug 29, 2025
918ba83
πŸš€ feat(geti-inspect): add initial backend code (#2930)
maxxgx Sep 8, 2025
82dd6b0
πŸ§ͺ test(get-inspect): add unit tests for endpoints (#2942)
maxxgx Sep 8, 2025
1588d72
Add openapi spec to gitignore
MarkRedeman Sep 4, 2025
22f8f8f
Use error page
MarkRedeman Sep 4, 2025
978a895
Delete nginx and Dockerfile
MarkRedeman Sep 4, 2025
cbb0a46
πŸ”§ chore(geti-inspect): Update Geti Inspect to react 19 (#2948)
MarkRedeman Sep 10, 2025
644f594
πŸš€ feat(geti-inspect): add training worker and predict endpoint (#2945)
maxxgx Sep 16, 2025
072ef38
πŸ”§ chore(inspect): Add Githbu Action workflows for geti inspect (#2961)
MarkRedeman Sep 18, 2025
0614756
πŸ”§ chore(inspect): Update route structure and add openapi route (#2963)
MarkRedeman Sep 22, 2025
e07a955
chore: Update package lock (#2967)
dwesolow Sep 25, 2025
61d2481
feat(geti-inspect): add pipelines (#2969)
maxxgx Sep 26, 2025
e04ef66
feat: Add sidebar with dataset, models and stats (#2970)
dwesolow Sep 29, 2025
3489422
πŸš€ feat(inspect): Add dataset list (#2971)
dwesolow Sep 29, 2025
4e160a1
πŸ”§ chore(inspect): Update UI scripts (#2974)
dwesolow Sep 29, 2025
7437855
πŸ”§ chore(inspect): Configure project(s) mocks for playwright tests (#2…
dwesolow Sep 29, 2025
590ece3
πŸš€ feat(inspect): Add project management (#2977)
dwesolow Sep 30, 2025
d9a613d
πŸ”§ chore(inspect): Update allowed origins so server can receive reques…
dwesolow Sep 30, 2025
6d51c68
πŸš€ feat(inspect): Allow user to upload images, train model and display…
dwesolow Oct 1, 2025
1baa2eb
πŸ”§ chore(inspect): Update openapi page (#2985)
dwesolow Oct 1, 2025
0a2af70
πŸ”§ chore(inspect): Rename folder structure from app to application (#2…
dwesolow Oct 3, 2025
8f1ef19
refactor(inspect): Update photo placeholder to use indicator instead …
dwesolow Oct 3, 2025
f0339cd
chore(inspect): Improve error and suspense handling in router (#2991)
MarkRedeman Oct 3, 2025
237731d
Fix path (#2993)
ashwinvaidya17 Oct 3, 2025
2a4f257
πŸ”„ refactor(inspect): Improvements to the jobs management and training…
dwesolow Oct 6, 2025
7653915
πŸ”§ chore(inspect): Add more models to be used for training (#2994)
dwesolow Oct 6, 2025
f0a7643
πŸ› fix(inspect): Use null pool for async engine (#2998)
MarkRedeman Oct 6, 2025
df8eb42
πŸ”§ chore(inspect): Update uv.lock (#2995)
dwesolow Oct 8, 2025
9fc19c1
πŸš€ feat(geti-inspect): add trainable models (#3005)
maxxgx Oct 8, 2025
3a446de
πŸš€ feat(geti-inspect): add thumbnails media endpoint (#3004)
maxxgx Oct 8, 2025
a2df1cb
chore(gitattributes): Remove uv.lock LFS entry (#3007)
MarkRedeman Oct 9, 2025
dc08cf0
πŸ”§ chore(dataset): Use thumnbail suffix to get the dataset items (#3013)
dwesolow Oct 9, 2025
b84f44c
πŸ”§ chore(inspect): Add dev command to run server and ui concurrently (…
dwesolow Oct 9, 2025
d63f53d
πŸ”„refactor(trainable models): Use trainable models from the server (#3…
dwesolow Oct 9, 2025
fed89a3
ci(inspect): Exclude application/ for geti-inspect (#3009)
MarkRedeman Oct 9, 2025
390f97f
πŸ› fix(geti-inspect): daemon worker error (#3016)
maxxgx Oct 9, 2025
f6ae55f
πŸ› fix(metrics): disable mps for torch metrics (#3018)
maxxgx Oct 10, 2025
3da55dd
πŸš€ feat(geti-inspect): add inference device selection (#3011)
maxxgx Oct 13, 2025
42c5541
πŸ”§ chore(normal images): Add `Normal images` heading (#3028)
dwesolow Oct 15, 2025
4339b78
πŸš€ feat(inference): Allow user to select media and get the inference (…
dwesolow Oct 15, 2025
931af9c
πŸ”§ chore(inference): convert to jet and add opacity (#3029)
ashwinvaidya17 Oct 15, 2025
cdeeaff
πŸš€ feat(inference): Display inference on top of the image + opacity (#…
dwesolow Oct 16, 2025
6ddb323
πŸ”§ chore(geti-inspect): configure loggers (#3039)
maxxgx Oct 21, 2025
be6fe07
chore(inspect): minor UI improvements (#3040)
MarkRedeman Oct 22, 2025
31c3d2f
chore (inspect): improve logs (add uvicorn handler) and add job_id to…
maxxgx Oct 22, 2025
701aca5
feat(inspect): add training device selection (#3056)
maxxgx Oct 27, 2025
6bf1e55
feat(inspect): Add train model dialog, job logs and models dataset (#…
MarkRedeman Oct 27, 2025
71ca2c1
chore(inspect): improve SSE generator (#3060)
maxxgx Oct 28, 2025
1d14bf1
bug(inspect): add missing db commit (#3075)
maxxgx Oct 28, 2025
dace0f0
Refactor(inspect): sources and sinks under project (#3079)
maxxgx Nov 3, 2025
cf91762
feat(inspect): delete media endpoint (#3082)
maxxgx Nov 4, 2025
9096eb7
Merge branch 'main' into feature/geti-inspect
maxxgx Nov 5, 2025
87a1efe
feat(inspect): add, remove list and connect sources (#3078)
camiloHimura Nov 5, 2025
19a3461
chore(inspect): fix pre commit and GHA (#3084)
maxxgx Nov 5, 2025
64fe8ea
feat(inspect): add, remove list and connect sinks (#3087)
camiloHimura Nov 5, 2025
32f527a
πŸš€ feat(inspect): Add progressbar (#3045)
ashwinvaidya17 Nov 6, 2025
1d7b9c7
fix(inspect): fix pipeline conflict (#3090)
maxxgx Nov 7, 2025
1a08bee
chore(inspect): improve openapi spec (#3100)
maxxgx Nov 10, 2025
22aa6df
feat(inspect): Pipeline enable/disable (#3097)
camiloHimura Nov 11, 2025
5008712
feat(inspeect): add alembic migration (#3103)
maxxgx Nov 11, 2025
0500abf
feat(inspect): Inference devices (#3106)
camiloHimura Nov 12, 2025
48365ba
🐞 fix(application): set validation split to synthetic (#3111)
ashwinvaidya17 Nov 13, 2025
ab12f0e
feat(inspect): Stream autoplay (#3110)
camiloHimura Nov 13, 2025
12fa1a4
feat(inspect): Device selection in training model dialog (#3094)
ActiveChooN Nov 14, 2025
e8476dc
feat(inspect): allow webRTC streaming passthrough (#3114)
maxxgx Nov 14, 2025
0202e60
refactor(inspect): update metrics service to be up to date with Geti …
maxxgx Nov 14, 2025
80e459a
feat(inspect): Enable/Disable project (#3117)
camiloHimura Nov 18, 2025
bdad999
feat(inspect): add stop pipeline endpoint (#3124)
maxxgx Nov 19, 2025
0b08527
feat(inspect): exported model size (#3126)
ActiveChooN Nov 19, 2025
8adc3a1
feat(inspect): Fix backend job cancellation (#3122)
ActiveChooN Nov 19, 2025
0773110
feat(inspect): Enable/Disable inference (#3127)
camiloHimura Nov 19, 2025
9990aca
feat(inspect): Model deletion endpoint (#3128)
ActiveChooN Nov 20, 2025
5cb2bc6
Add docker files
ashwinvaidya17 Nov 21, 2025
a9c5f70
Fix non-root user mounting issues
ashwinvaidya17 Nov 21, 2025
09d9f27
feat(inspect): enhance ModelsView (#3135)
ActiveChooN Nov 21, 2025
40c5e5a
Merge branch 'feature/geti-inspect' into ashwin/feature/dockerfile_2
ashwinvaidya17 Nov 24, 2025
4d09a21
Update Dockerfile to include g++ and modify CORS settings in main.py …
ashwinvaidya17 Nov 24, 2025
0a232b8
fix proxy issue
ashwinvaidya17 Nov 24, 2025
c7ebce5
cuda build
ashwinvaidya17 Nov 25, 2025
ef63ed2
Add XPU build
ashwinvaidya17 Nov 27, 2025
f0ef85b
Merge branch 'feature/geti-inspect' into ashwin/feature/dockerfile_2
ashwinvaidya17 Nov 27, 2025
c0d3c78
Fix conflicts
ashwinvaidya17 Nov 27, 2025
438a499
Comment XPU settings
ashwinvaidya17 Nov 27, 2025
70f05fa
Merge branch 'feature/geti-inspect' into ashwin/feature/dockerfile_2
ashwinvaidya17 Dec 1, 2025
39209fc
Merge branch 'feature/geti-inspect' into ashwin/feature/dockerfile_2
ashwinvaidya17 Dec 1, 2025
5cf0ad6
chore: update dependencies in pyproject.toml
ashwinvaidya17 Dec 2, 2025
83a7c16
Update prek references
ashwinvaidya17 Dec 2, 2025
85d4860
Update uv.lock
ashwinvaidya17 Dec 2, 2025
54501fb
update dockerfile
ashwinvaidya17 Dec 3, 2025
5d3a63c
Merge branch 'feature/geti-inspect' into ashwin/feature/dockerfile_2
ashwinvaidya17 Dec 3, 2025
bdac68a
Revert formatting
ashwinvaidya17 Dec 3, 2025
3af24ca
Revert formatting
ashwinvaidya17 Dec 3, 2025
0e450d1
Update actions
ashwinvaidya17 Dec 3, 2025
86e137a
fix typo
ashwinvaidya17 Dec 3, 2025
0740a18
Serve UI from fastapi in prod
ashwinvaidya17 Dec 6, 2025
be206fe
move dir
ashwinvaidya17 Dec 6, 2025
9ae1a10
Merge branch 'feature/geti-inspect' into ashwin/feature/dockerfile_2
ashwinvaidya17 Dec 6, 2025
bada298
fix context path
ashwinvaidya17 Dec 8, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
100 changes: 100 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
# Git
.git
.gitignore
.gitattributes

# Python
__pycache__/
*.py[cod]
*$py.class
*.so
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg
.pytest_cache/
.coverage
htmlcov/
.tox/
.nox/
.hypothesis/

# Virtual environments
venv/
env/
ENV/
.venv

# IDEs
.vscode/
.idea/
*.swp
*.swo
*~
.DS_Store

# Node
node_modules/
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# Application data (will be mounted as volumes)
application/backend/data/**
application/backend/logs/**
application/backend/openvino_cache/**
application/backend/tests/**
application/backend/**/__pycache__/**
application/backend/.*_cache/**
application/backend/.tmp/**
application/backend/.venv/**
application/ui/dist/
application/ui/build/
application/ui/node_modules/
data/

# Documentation and examples
docs/
examples/
*.md
!README.md

# CI/CD
.github/
.gitlab-ci.yml
.travis.yml

# Testing
tests/
*.test.js
*.spec.js
coverage/

# Temporary files
tmp/
temp/
*.tmp
*.log

# Datasets and model artifacts
datasets/
pre_trained/
results/
openvino_cache/

# Experiment tracking and logs
wandb/
lightning_logs/
mlruns/
4 changes: 2 additions & 2 deletions .github/workflows/geti-inspect.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ jobs:
working-directory: application/backend
run: |
uv lock --check
uv sync --frozen --all-extras
uv sync --frozen --extra cpu --extra mqtt

- name: Get OpenAPI spec
working-directory: application/backend
Expand Down Expand Up @@ -86,7 +86,7 @@ jobs:
working-directory: application/backend
run: |
uv lock --check
uv sync --frozen --all-extras
uv sync --frozen --extra cpu --extra mqtt

- name: Check formatting with ruff
working-directory: application/backend
Expand Down
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -176,3 +176,7 @@ docs/source/_build/
wandb/
lightning_logs/
mlruns

# application data
data/
logs/
13 changes: 12 additions & 1 deletion application/backend/.pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ repos:
- id: mypy
alias: mypy-application-backend
name: mypy (application-backend)
additional_dependencies: [types-PyYAML, types-setuptools, types-requests, alembic]
additional_dependencies:
[types-PyYAML, types-setuptools, types-requests, alembic]

# Markdown linting
- repo: https://github.com/igorshubovych/markdownlint-cli
Expand All @@ -34,3 +35,13 @@ repos:
alias: markdownlint-application-backend
name: markdownlint (application-backend)
args: [--config=.markdownlint.yaml]

# Dockerfile linting
- repo: https://github.com/AleksaC/hadolint-py
rev: v2.12.0.2
hooks:
- id: hadolint
files: Dockerfile$
args:
- "--ignore=DL3008" # Pin versions in apt-get install
- "--ignore=DL4006" # Use bash in scripts
24 changes: 22 additions & 2 deletions application/backend/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@ dependencies = [
"openvino==2025.2.0",
"pydantic-settings~=2.10.1",
"aiortc~=1.13.0",
"anomalib[full]",
"torchmetrics>=1.8.2",
"opencv-python-headless~=4.12",
"watchdog==6.0.0",
"uvloop==0.21.0",
Expand Down Expand Up @@ -51,9 +49,31 @@ mqtt = [
"paho-mqtt~=2.1.0",
]

# Explicit versions are needed as we can't propagate extra dependencies to anomalib
cpu = ["anomalib[cpu,full]"]
cu124 = ["anomalib[cu124,full]"]
xpu = ["anomalib[xpu,full]"]

[tool.uv]
conflicts = [
[
{ extra = "cpu" },
{ extra = "cu124" },
{ extra = "xpu" },
],
# redeclare library conflicts to workaround bug with uv dependency resolution
# For details, see: https://github.com/astral-sh/uv/issues/9942
[
{ package = "anomalib", extra = "cpu" },
{ package = "anomalib", extra = "cu124" },
{ package = "anomalib", extra = "xpu" },
],
]

[tool.uv.sources]
anomalib = { path = "../../", editable = true }


[tool.ruff]
extend = "../../pyproject.toml"
target-version = "py313"
Expand Down
20 changes: 20 additions & 0 deletions application/backend/src/api/endpoints/webui_endpoints.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Copyright (C) 2025 Intel Corporation
# SPDX-License-Identifier: Apache-2.0

from pathlib import Path

from fastapi import APIRouter, HTTPException
from fastapi.responses import FileResponse

from settings import get_settings

settings = get_settings()
webui_router = APIRouter(tags=["Webui"])


@webui_router.get("/", include_in_schema=False)
async def get_webui(full_path: str = "") -> FileResponse: # noqa: ARG001
Copy link

Copilot AI Dec 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The function parameter full_path is declared but never used, and there's no logic to prevent potential path traversal attacks or handle different routes. If this endpoint is meant to handle multiple paths, the implementation should use full_path to serve the appropriate files. If it only serves index.html, the parameter should be removed.

Suggested change
async def get_webui(full_path: str = "") -> FileResponse: # noqa: ARG001
async def get_webui() -> FileResponse:

Copilot uses AI. Check for mistakes.
"""Get the webui index.html file."""
if settings.static_files_dir and not (file_path := Path(settings.static_files_dir) / "index.html").exists():
Copy link

Copilot AI Dec 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If settings.static_files_dir is None or empty, file_path will not be defined, causing an UnboundLocalError on line 20. The condition should ensure file_path is always defined before the return statement, or raise an appropriate error when static_files_dir is not configured.

Suggested change
if settings.static_files_dir and not (file_path := Path(settings.static_files_dir) / "index.html").exists():
if not settings.static_files_dir:
raise HTTPException(status_code=500, detail="Static files directory is not configured")
file_path = Path(settings.static_files_dir) / "index.html"
if not file_path.exists():

Copilot uses AI. Check for mistakes.
raise HTTPException(status_code=404, detail="File not found")
return FileResponse(file_path)
29 changes: 22 additions & 7 deletions application/backend/src/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@
# SPDX-License-Identifier: Apache-2.0

import os
from pathlib import Path

import uvicorn
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from fastapi.staticfiles import StaticFiles

from api.endpoints.active_pipeline_endpoints import router as active_pipeline_router
from api.endpoints.capture_endpoints import router as capture_router
Expand All @@ -20,6 +22,7 @@
from api.endpoints.source_endpoints import router as source_router
from api.endpoints.trainable_models_endpoints import router as trainable_model_router
from api.endpoints.webrtc import router as webrtc_router
from api.endpoints.webui_endpoints import webui_router
from core.lifecycle import lifespan
from settings import get_settings

Expand All @@ -34,15 +37,11 @@

_ = exception_handlers # to avoid import being removed by linters

# TODO: check if middleware is required
# Enable CORS for local test UI
app.add_middleware(
CORSMiddleware,
allow_origins=[
"http://localhost:3000",
"http://localhost:9000",
"http://127.0.0.1:9000",
],
allow_origins=["*"],
Copy link

Copilot AI Dec 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changing CORS from specific origins to allow all origins (*) introduces a security risk. This allows any website to make requests to your API. Consider using environment variables to configure allowed origins for different deployment environments, or maintain the original restrictive list for production.

Copilot uses AI. Check for mistakes.

Check warning

Code scanning / Semgrep OSS

Semgrep Finding: python.fastapi.security.wildcard-cors.wildcard-cors Warning

CORS policy allows any origin (using wildcard '*'). This is insecure and should be avoided.
Copy link

Copilot AI Dec 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Allowing all origins with allow_origins=['*'] creates a security vulnerability by permitting cross-origin requests from any domain. This bypasses CORS protection and could enable malicious sites to access the API. Restrict allow_origins to specific trusted domains or use environment variables to configure allowed origins.

Copilot uses AI. Check for mistakes.
Copy link

Copilot AI Dec 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Allowing all origins with allow_origins=[\"*\"] is a security risk in production environments as it permits any domain to make requests to the API. Consider making this configurable through settings and restricting it to specific trusted origins in production.

Copilot uses AI. Check for mistakes.
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
Expand All @@ -61,8 +60,24 @@
app.include_router(capture_router)
app.include_router(snapshot_router)

settings = get_settings()

if __name__ == "__main__":
settings = get_settings()
# In docker deployment, the UI is built and served statically
if (
settings.static_files_dir
and Path(settings.static_files_dir).is_dir()
and (Path(settings.static_files_dir) / "index.html").exists()
):
static_dir = Path(settings.static_files_dir)
app.mount("/static", StaticFiles(directory=static_dir / "static"), name="static")
app.include_router(webui_router)


def main() -> None:
"""Main function to run the Geti Inspect server"""
uvicorn_port = int(os.environ.get("HTTP_SERVER_PORT", settings.port))
uvicorn.run("main:app", loop="uvloop", host=settings.host, port=uvicorn_port, log_config=None)


if __name__ == "__main__":
main()
10 changes: 7 additions & 3 deletions application/backend/src/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@
from pydantic import Field
from pydantic_settings import BaseSettings, SettingsConfigDict

# Get the directory where this settings module is located
_MODULE_DIR = Path(__file__).parent


class Settings(BaseSettings):
"""Application settings with environment variable support"""
Expand All @@ -26,6 +29,7 @@ class Settings(BaseSettings):
environment: Literal["dev", "prod"] = "dev"
data_dir: Path = Field(default=Path("data"), alias="DATA_DIR")
log_dir: Path = Field(default=Path("logs"), alias="LOG_DIR")
static_files_dir: str | None = Field(default=None, alias="STATIC_FILES_DIR")

# Server
host: str = Field(default="0.0.0.0", alias="HOST") # noqa: S104
Expand All @@ -36,16 +40,16 @@ class Settings(BaseSettings):
db_echo: bool = Field(default=False, alias="DB_ECHO")

# Alembic
alembic_config_path: str = "src/alembic.ini"
alembic_script_location: str = "src/alembic"
alembic_config_path: str = str(_MODULE_DIR / "alembic.ini")
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be adjusted further when we introduce Pyinstaller

alembic_script_location: str = str(_MODULE_DIR / "alembic")

# Proxy settings
no_proxy: str = Field(default="localhost,127.0.0.1,::1", alias="no_proxy")

@property
def database_url(self) -> str:
"""Get database URL"""
return f"sqlite+aiosqlite:///./{self.data_dir / self.database_file}?journal_mode=WAL"
return f"sqlite+aiosqlite:///{self.data_dir / self.database_file}?journal_mode=WAL"

@property
def sync_database_url(self) -> str:
Expand Down
Loading
Loading