tokeye 0.9.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. tokeye-0.9.0/PKG-INFO +138 -0
  2. tokeye-0.9.0/README.md +106 -0
  3. tokeye-0.9.0/pyproject.toml +91 -0
  4. tokeye-0.9.0/src/tokeye/__init__.py +0 -0
  5. tokeye-0.9.0/src/tokeye/analysis/__init__.py +4 -0
  6. tokeye-0.9.0/src/tokeye/analysis/batch_analysis.py +240 -0
  7. tokeye-0.9.0/src/tokeye/app/__init__.py +0 -0
  8. tokeye-0.9.0/src/tokeye/app/__main__.py +84 -0
  9. tokeye-0.9.0/src/tokeye/app/analyze/__init__.py +0 -0
  10. tokeye-0.9.0/src/tokeye/app/analyze/analyze.py +296 -0
  11. tokeye-0.9.0/src/tokeye/app/analyze/load.py +185 -0
  12. tokeye-0.9.0/src/tokeye/app/analyze/transforms.py +37 -0
  13. tokeye-0.9.0/src/tokeye/app/analyze/visualize.py +194 -0
  14. tokeye-0.9.0/src/tokeye/app/processing/QUICKSTART.md +310 -0
  15. tokeye-0.9.0/src/tokeye/app/processing/README.md +459 -0
  16. tokeye-0.9.0/src/tokeye/app/processing/__init__.py +0 -0
  17. tokeye-0.9.0/src/tokeye/app/processing/inference.py +66 -0
  18. tokeye-0.9.0/src/tokeye/app/processing/postprocess.py +386 -0
  19. tokeye-0.9.0/src/tokeye/app/processing/tiling.py +292 -0
  20. tokeye-0.9.0/src/tokeye/app/tabs/__init__.py +0 -0
  21. tokeye-0.9.0/src/tokeye/app/tabs/annotate.py +553 -0
  22. tokeye-0.9.0/src/tokeye/app/tabs/utilities.py +536 -0
  23. tokeye-0.9.0/src/tokeye/app/utils/__init__.py +0 -0
  24. tokeye-0.9.0/src/tokeye/app/utils/analyze.py +391 -0
  25. tokeye-0.9.0/src/tokeye/app/utils/theme.py +151 -0
  26. tokeye-0.9.0/src/tokeye/extra/D3D/__init__.py +0 -0
  27. tokeye-0.9.0/src/tokeye/extra/D3D/ece_rolloff.py +66 -0
  28. tokeye-0.9.0/src/tokeye/extra/eval/D3D/__init__.py +0 -0
  29. tokeye-0.9.0/src/tokeye/extra/eval/D3D/methods_pcg.py +70 -0
  30. tokeye-0.9.0/src/tokeye/extra/eval/silbidopy/__init__.py +0 -0
  31. tokeye-0.9.0/src/tokeye/extra/eval/silbidopy/data.py +674 -0
  32. tokeye-0.9.0/src/tokeye/extra/eval/silbidopy/eval.py +59 -0
  33. tokeye-0.9.0/src/tokeye/extra/eval/silbidopy/readBinaries.py +277 -0
  34. tokeye-0.9.0/src/tokeye/extra/eval/silbidopy/render.py +403 -0
  35. tokeye-0.9.0/src/tokeye/extra/eval/silbidopy/sigproc.py +53 -0
  36. tokeye-0.9.0/src/tokeye/extra/eval/silbidopy/writeBinaries.py +275 -0
  37. tokeye-0.9.0/src/tokeye/models/__init__.py +0 -0
  38. tokeye-0.9.0/src/tokeye/models/ae_tf_boxrcnn/config_ae_tf_boxrcnn.py +0 -0
  39. tokeye-0.9.0/src/tokeye/models/ae_tf_boxrcnn/model_ae_tf_boxrcnn.py +24 -0
  40. tokeye-0.9.0/src/tokeye/models/ae_tf_maskrcnn/config_ae_tf_maskrcnn.py +26 -0
  41. tokeye-0.9.0/src/tokeye/models/ae_tf_maskrcnn/model_ae_tf_maskrcnn.py +73 -0
  42. tokeye-0.9.0/src/tokeye/models/big_tf_unet/config_big_tf_unet.py +18 -0
  43. tokeye-0.9.0/src/tokeye/models/big_tf_unet/model_big_tf_unet.py +206 -0
  44. tokeye-0.9.0/src/tokeye/models/modules/__init__.py +9 -0
  45. tokeye-0.9.0/src/tokeye/models/modules/bsn.py +441 -0
  46. tokeye-0.9.0/src/tokeye/models/modules/nn.py +138 -0
  47. tokeye-0.9.0/src/tokeye/models/modules/unet.py +137 -0
  48. tokeye-0.9.0/src/tokeye/training/big_tf_unet/README.md +3 -0
  49. tokeye-0.9.0/src/tokeye/training/big_tf_unet/__init__.py +0 -0
  50. tokeye-0.9.0/src/tokeye/training/big_tf_unet/config/paths.yaml +0 -0
  51. tokeye-0.9.0/src/tokeye/training/big_tf_unet/step_0a_extract_faithdata.py +77 -0
  52. tokeye-0.9.0/src/tokeye/training/big_tf_unet/step_0b_filter_faithdata.py +71 -0
  53. tokeye-0.9.0/src/tokeye/training/big_tf_unet/step_0c_convert_faithdata.py +104 -0
  54. tokeye-0.9.0/src/tokeye/training/big_tf_unet/step_1a_make_timeseries.py +72 -0
  55. tokeye-0.9.0/src/tokeye/training/big_tf_unet/step_2a_make_spectrogram.py +89 -0
  56. tokeye-0.9.0/src/tokeye/training/big_tf_unet/step_2b_filter_spectrogram.py +147 -0
  57. tokeye-0.9.0/src/tokeye/training/big_tf_unet/step_3a_correlation_analysis.py +402 -0
  58. tokeye-0.9.0/src/tokeye/training/big_tf_unet/step_3b_extract_correlation.py +51 -0
  59. tokeye-0.9.0/src/tokeye/training/big_tf_unet/step_3c_coherence.py +69 -0
  60. tokeye-0.9.0/src/tokeye/training/big_tf_unet/step_4a_threshold.py +333 -0
  61. tokeye-0.9.0/src/tokeye/training/big_tf_unet/step_5a_combine_spectrogram.py +190 -0
  62. tokeye-0.9.0/src/tokeye/training/big_tf_unet/step_5b_manual_fix_spectrogram.py +1046 -0
  63. tokeye-0.9.0/src/tokeye/training/big_tf_unet/step_6a_convert_tif.py +473 -0
  64. tokeye-0.9.0/src/tokeye/training/big_tf_unet/step_6b_refiner.py +726 -0
  65. tokeye-0.9.0/src/tokeye/training/big_tf_unet/step_6c_convert_predictions.py +228 -0
  66. tokeye-0.9.0/src/tokeye/training/big_tf_unet/step_6d_final.py +434 -0
  67. tokeye-0.9.0/src/tokeye/training/big_tf_unet/step_7a_make_multiscale.py +200 -0
  68. tokeye-0.9.0/src/tokeye/training/big_tf_unet/step_7b_train_multiscale.py +557 -0
  69. tokeye-0.9.0/src/tokeye/training/big_tf_unet/utils/augmentations.py +528 -0
  70. tokeye-0.9.0/src/tokeye/training/big_tf_unet/utils/configuration.py +54 -0
  71. tokeye-0.9.0/src/tokeye/training/big_tf_unet/utils/convert_for_software.py +193 -0
  72. tokeye-0.9.0/src/tokeye/training/big_tf_unet/utils/generate_images.py +256 -0
  73. tokeye-0.9.0/src/tokeye/training/big_tf_unet/utils/hdf5_io.py +232 -0
  74. tokeye-0.9.0/src/tokeye/training/big_tf_unet/utils/inference_export.py +307 -0
  75. tokeye-0.9.0/src/tokeye/training/big_tf_unet/utils/losses.py +511 -0
  76. tokeye-0.9.0/src/tokeye/training/big_tf_unet/utils/measurements.py +69 -0
  77. tokeye-0.9.0/src/tokeye/training/big_tf_unet/utils/parmap.py +213 -0
  78. tokeye-0.9.0/src/tokeye/training/big_tf_unet/utils/visualize.py +56 -0
tokeye-0.9.0/PKG-INFO ADDED
@@ -0,0 +1,138 @@
1
+ Metadata-Version: 2.3
2
+ Name: tokeye
3
+ Version: 0.9.0
4
+ Summary: Add your description here
5
+ Requires-Dist: gradio
6
+ Requires-Dist: numpy
7
+ Requires-Dist: scipy
8
+ Requires-Dist: torch
9
+ Requires-Dist: torchcodec
10
+ Requires-Dist: torchvision
11
+ Requires-Dist: torchinfo
12
+ Requires-Dist: omegaconf
13
+ Requires-Dist: tables
14
+ Requires-Dist: pydantic
15
+ Requires-Dist: mypy ; extra == 'dev'
16
+ Requires-Dist: pytest ; extra == 'dev'
17
+ Requires-Dist: pytest-cov ; extra == 'dev'
18
+ Requires-Dist: pytest-xdist ; extra == 'dev'
19
+ Requires-Dist: ruff ; extra == 'dev'
20
+ Requires-Dist: ipykernel ; extra == 'dev'
21
+ Requires-Dist: ipywidgets ; extra == 'dev'
22
+ Requires-Dist: matplotlib ; extra == 'dev'
23
+ Requires-Dist: wavio ; extra == 'dev'
24
+ Requires-Dist: h5py ; extra == 'dev'
25
+ Requires-Dist: fusionaihub ; extra == 'dev'
26
+ Requires-Dist: scikit-learn ; extra == 'dev'
27
+ Requires-Dist: lightning ; extra == 'train'
28
+ Requires-Python: >=3.13
29
+ Provides-Extra: dev
30
+ Provides-Extra: train
31
+ Description-Content-Type: text/markdown
32
+
33
+ <p align="center">
34
+ <img src="assets/logo.png" alt="TokEye Logo" width="400">
35
+ </p>
36
+
37
+ # TokEye
38
+
39
+ [![Python package](https://github.com/PlasmaControl/tokeye/actions/workflows/python-package.yml/badge.svg)](https://github.com/PlasmaControl/tokeye/actions/workflows/python-package.yml)
40
+
41
+ TokEye is a open-source Python-based application for automatic classification and localization of fluctuating signals.
42
+ It is designed to be used in the context of plasma physics, but can be used for any type of fluctuating signal.
43
+
44
+ Check out [this poster from APS DPP 2025](assets/aps_dpp_2025.pdf) for more information.
45
+
46
+ ## Example Demonstration
47
+ ![Example Demonstration](assets/example.gif)
48
+
49
+ Expected processing time:
50
+ - A100: < 0.5 seconds on any size spectrogram after warmup.
51
+ - CPU: not yet tested.
52
+
53
+ ## Verified Datatypes
54
+ - DIII-D Fast Magnetics (cite)
55
+ - DIII-D CO2 Interferometer (cite)
56
+ - DIII-D Electron Cyclotron Emission (cite)
57
+ - DIII-D Beam Emission Spectroscopy (cite)
58
+
59
+ ## Evaluation
60
+ Recall Scores:
61
+ - TJII2021: 0.8254
62
+ - DCLDE2011 (Delphinus capensis): 0.7708
63
+ - DCLDE2011 (Delphinus delphis): 0.7953
64
+
65
+ With more data, comes better models. Please contribute to the project!
66
+
67
+ ## Installation
68
+
69
+ [uv](https://docs.astral.sh/uv/) (recommended)
70
+ ```bash
71
+ git clone git@github.com:PlasmaControl/TokEye.git
72
+ cd TokEye
73
+ uv sync
74
+ ```
75
+
76
+ pip (from source)
77
+ ```bash
78
+ git clone git@github.com:PlasmaControl/TokEye.git
79
+ cd TokEye
80
+ python3 -m venv .venv
81
+ source venv/bin/activate
82
+ pip install uv
83
+ uv sync
84
+ ```
85
+
86
+ pip (from PyPI)
87
+ ```bash
88
+ pip install tokeye
89
+ ```
90
+ Coming soon.
91
+
92
+ Containerized installation (Docker)
93
+ Coming soon.
94
+
95
+
96
+ ## Usage
97
+ ```bash
98
+ python -m TokEye.app
99
+ ```
100
+
101
+ This will start a web app on `http://localhost:8888`.
102
+
103
+ If you are on a remote server, you can use SSH port forwarding to access the web app on your local machine:
104
+ ```bash
105
+ ssh -L 8888:localhost:7860 user@remote_server
106
+ ```
107
+ Then open your web browser and navigate to `http://localhost:8888`.
108
+
109
+ ## Models
110
+ Pre-trained models are available at [this link](https://drive.google.com/drive/folders/1rXllPXB3eWhMvSIlp0CDSFx68lJOQG1u?usp=drive_link).
111
+ Copy them into the `models/` directory after downloading them.
112
+ - big_mode_v1.pt: Original training regime (window = 1024, hop = 128)
113
+ - big_mode_v2.pt: Trained on multiscale (multiwindow, multihop) spectrograms
114
+
115
+ Input should be a tensor that has shape (B, 1, H, W) where B, H, and W can vary
116
+ Output will be a tensor of shape (B, 2, H, W)
117
+
118
+ Best performance when spectrograms are oriented so that when they are plotted with matplotlib, the lowest frequency bin is oriented with the bottom when `origin='lower'`. Spectrograms should be standardized (mean = 0, std = 1). If baseline activity is very strong, clipping the input may help, but is generally not needed.
119
+
120
+ The first channel of the output will return preferential measurements of coherent activity (useful for most tasks)
121
+ THe second channel of the output will return preferential measurements of transient activity
122
+
123
+ ## Data
124
+ Right now, keep all data as 1d numpy float arrays. No need to normalize or preprocess them.
125
+ Copy them into the `data/` directory.
126
+
127
+ ## Citation
128
+ If you use this code in your research, please cite:
129
+ ```bibtex
130
+ @article{NaN,
131
+ title={Paper not yet published},
132
+ author={Nathaniel Chen},
133
+ year={2025}
134
+ }
135
+ ```
136
+
137
+ ## Contact
138
+ Please check back for updates or reach out to Nathaniel Chen at nathaniel@princeton.edu.
tokeye-0.9.0/README.md ADDED
@@ -0,0 +1,106 @@
1
+ <p align="center">
2
+ <img src="assets/logo.png" alt="TokEye Logo" width="400">
3
+ </p>
4
+
5
+ # TokEye
6
+
7
+ [![Python package](https://github.com/PlasmaControl/tokeye/actions/workflows/python-package.yml/badge.svg)](https://github.com/PlasmaControl/tokeye/actions/workflows/python-package.yml)
8
+
9
+ TokEye is a open-source Python-based application for automatic classification and localization of fluctuating signals.
10
+ It is designed to be used in the context of plasma physics, but can be used for any type of fluctuating signal.
11
+
12
+ Check out [this poster from APS DPP 2025](assets/aps_dpp_2025.pdf) for more information.
13
+
14
+ ## Example Demonstration
15
+ ![Example Demonstration](assets/example.gif)
16
+
17
+ Expected processing time:
18
+ - A100: < 0.5 seconds on any size spectrogram after warmup.
19
+ - CPU: not yet tested.
20
+
21
+ ## Verified Datatypes
22
+ - DIII-D Fast Magnetics (cite)
23
+ - DIII-D CO2 Interferometer (cite)
24
+ - DIII-D Electron Cyclotron Emission (cite)
25
+ - DIII-D Beam Emission Spectroscopy (cite)
26
+
27
+ ## Evaluation
28
+ Recall Scores:
29
+ - TJII2021: 0.8254
30
+ - DCLDE2011 (Delphinus capensis): 0.7708
31
+ - DCLDE2011 (Delphinus delphis): 0.7953
32
+
33
+ With more data, comes better models. Please contribute to the project!
34
+
35
+ ## Installation
36
+
37
+ [uv](https://docs.astral.sh/uv/) (recommended)
38
+ ```bash
39
+ git clone git@github.com:PlasmaControl/TokEye.git
40
+ cd TokEye
41
+ uv sync
42
+ ```
43
+
44
+ pip (from source)
45
+ ```bash
46
+ git clone git@github.com:PlasmaControl/TokEye.git
47
+ cd TokEye
48
+ python3 -m venv .venv
49
+ source venv/bin/activate
50
+ pip install uv
51
+ uv sync
52
+ ```
53
+
54
+ pip (from PyPI)
55
+ ```bash
56
+ pip install tokeye
57
+ ```
58
+ Coming soon.
59
+
60
+ Containerized installation (Docker)
61
+ Coming soon.
62
+
63
+
64
+ ## Usage
65
+ ```bash
66
+ python -m TokEye.app
67
+ ```
68
+
69
+ This will start a web app on `http://localhost:8888`.
70
+
71
+ If you are on a remote server, you can use SSH port forwarding to access the web app on your local machine:
72
+ ```bash
73
+ ssh -L 8888:localhost:7860 user@remote_server
74
+ ```
75
+ Then open your web browser and navigate to `http://localhost:8888`.
76
+
77
+ ## Models
78
+ Pre-trained models are available at [this link](https://drive.google.com/drive/folders/1rXllPXB3eWhMvSIlp0CDSFx68lJOQG1u?usp=drive_link).
79
+ Copy them into the `models/` directory after downloading them.
80
+ - big_mode_v1.pt: Original training regime (window = 1024, hop = 128)
81
+ - big_mode_v2.pt: Trained on multiscale (multiwindow, multihop) spectrograms
82
+
83
+ Input should be a tensor that has shape (B, 1, H, W) where B, H, and W can vary
84
+ Output will be a tensor of shape (B, 2, H, W)
85
+
86
+ Best performance when spectrograms are oriented so that when they are plotted with matplotlib, the lowest frequency bin is oriented with the bottom when `origin='lower'`. Spectrograms should be standardized (mean = 0, std = 1). If baseline activity is very strong, clipping the input may help, but is generally not needed.
87
+
88
+ The first channel of the output will return preferential measurements of coherent activity (useful for most tasks)
89
+ THe second channel of the output will return preferential measurements of transient activity
90
+
91
+ ## Data
92
+ Right now, keep all data as 1d numpy float arrays. No need to normalize or preprocess them.
93
+ Copy them into the `data/` directory.
94
+
95
+ ## Citation
96
+ If you use this code in your research, please cite:
97
+ ```bibtex
98
+ @article{NaN,
99
+ title={Paper not yet published},
100
+ author={Nathaniel Chen},
101
+ year={2025}
102
+ }
103
+ ```
104
+
105
+ ## Contact
106
+ Please check back for updates or reach out to Nathaniel Chen at nathaniel@princeton.edu.
@@ -0,0 +1,91 @@
1
+ [build-system]
2
+ requires = ["uv_build"]
3
+ build-backend = "uv_build"
4
+
5
+ [project]
6
+ name = "tokeye"
7
+ version = "0.9.0"
8
+ description = "Add your description here"
9
+ readme = "README.md"
10
+ requires-python = ">=3.13"
11
+ dependencies = [
12
+ "gradio",
13
+
14
+ "numpy",
15
+ "scipy",
16
+
17
+ "torch",
18
+ "torchcodec",
19
+ "torchvision",
20
+ "torchinfo",
21
+
22
+ "omegaconf",
23
+ "tables",
24
+ "pydantic",
25
+ ]
26
+
27
+ [project.optional-dependencies]
28
+ dev = [
29
+ "mypy",
30
+ "pytest",
31
+ "pytest-cov",
32
+ "pytest-xdist",
33
+ "ruff",
34
+
35
+ "ipykernel",
36
+ "ipywidgets",
37
+ "matplotlib",
38
+ "wavio",
39
+ "h5py",
40
+ "fusionaihub",
41
+ "scikit-learn",
42
+ ]
43
+ train = [
44
+ "lightning",
45
+ ]
46
+
47
+ [tool.ruff]
48
+ line-length = 88
49
+
50
+ [tool.ruff.lint]
51
+ extend-select = [
52
+ "F", # Pyflakes rules
53
+ "W", # PyCodeStyle warnings
54
+ "E", # PyCodeStyle errors
55
+ "I", # Sort imports properly
56
+ "UP", # Warn if certain things can changed due to newer Python versions
57
+ "C4", # Catch incorrect use of comprehensions, dict, list, etc
58
+ "FA", # Enforce from __future__ import annotations
59
+ "ISC", # Good use of string concatenation
60
+ "ICN", # Use common import conventions
61
+ "RET", # Good return practices
62
+ "SIM", # Common simplification rules
63
+ "TID", # Some good import practices
64
+ "TC", # Enforce importing certain types in a TYPE_CHECKING block
65
+ "PTH", # Use pathlib instead of os.path
66
+ "TD", # Be diligent with TODO comments
67
+ "NPY", # Some numpy-specific things
68
+ ]
69
+ ignore = [
70
+ "E501",
71
+ "B008",
72
+ ]
73
+
74
+ [tool.ruff.lint.per-file-ignores]
75
+ "__init__.py" = ["F401"]
76
+ "tests/*" = ["ARG"]
77
+ "*.ipynb" = ["E402"]
78
+
79
+ [tool.uv]
80
+ package = true
81
+
82
+ [tool.uv.build-backend]
83
+ module-name = "tokeye"
84
+ module-root = "src"
85
+
86
+ [pytest]
87
+ minversion = "9.0"
88
+ addopts = ["-ra", "-q"]
89
+ testpaths = [
90
+ "tests",
91
+ ]
File without changes
@@ -0,0 +1,4 @@
1
+ from .batch_analysis import default_settings, run_batch_analysis
2
+
3
+ __all__ = ["run_batch_analysis", "default_settings"]
4
+
@@ -0,0 +1,240 @@
1
+ import logging
2
+ import time
3
+ from pathlib import Path
4
+
5
+ import numpy as np
6
+ import torch
7
+ import torch.nn as nn
8
+
9
+ # Import model loading function from the analyze module
10
+ from TokEye.app.analyze.load import model_load
11
+ from tqdm.auto import tqdm
12
+
13
+ # Configure logging
14
+ logging.basicConfig(
15
+ level=logging.INFO,
16
+ format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
17
+ )
18
+ logger = logging.getLogger(__name__)
19
+
20
+ # Default settings
21
+ default_settings = {
22
+ "model_path": "data/models/big_mode_v1.pth",
23
+ "input_path": "data/batch_inputs",
24
+ "output_path": "data/batch_outputs",
25
+ "analysis_mode": "amplitude",
26
+ "threshold": 0.5,
27
+ "polling_interval": 5, # seconds between directory scans
28
+ }
29
+
30
+
31
+ def load_spectrogram(filepath: Path) -> np.ndarray | None:
32
+ """Load a 2D spectrogram from a numpy file.
33
+
34
+ Args:
35
+ filepath: Path to the .npy file containing a 2D spectrogram
36
+
37
+ Returns:
38
+ 2D numpy array or None if loading fails
39
+ """
40
+ try:
41
+ spec = np.load(filepath)
42
+ if spec.ndim != 2:
43
+ logger.error(f"Expected 2D array, got {spec.ndim}D: {filepath.name}")
44
+ return None
45
+ if spec.size == 0:
46
+ logger.error(f"Empty array: {filepath.name}")
47
+ return None
48
+ return spec
49
+ except Exception as e:
50
+ logger.error(f"Failed to load {filepath.name}: {e}")
51
+ return None
52
+
53
+
54
+ def run_inference(
55
+ spec: np.ndarray,
56
+ model: nn.Module | torch.export.ExportedProgram,
57
+ ) -> np.ndarray | None:
58
+ """Run inference on a 2D spectrogram.
59
+
60
+ Args:
61
+ spec: 2D numpy array (H, W)
62
+ model: Loaded PyTorch model
63
+
64
+ Returns:
65
+ 3D numpy array (2, H, W) with two output channels or None if inference fails
66
+ """
67
+ try:
68
+ device = next(model.parameters()).device
69
+
70
+ # Normalize input
71
+ spec_norm = (spec - spec.mean()) / (spec.std() + 1e-6)
72
+
73
+ # Convert to tensor: (1, 1, H, W)
74
+ inp_tensor = torch.from_numpy(spec_norm)
75
+ inp_tensor = inp_tensor.unsqueeze(0).unsqueeze(0).float()
76
+ inp_tensor = inp_tensor.to(device)
77
+
78
+ # Run inference
79
+ with torch.no_grad():
80
+ out_tensor = model(inp_tensor)
81
+
82
+ # Remove batch dimension: (1, 2, H, W) -> (2, H, W)
83
+ out_tensor = out_tensor[0]
84
+
85
+ # Apply sigmoid activation
86
+ out_tensor = torch.sigmoid(out_tensor)
87
+
88
+ # Convert to numpy
89
+ return out_tensor.cpu().numpy()
90
+
91
+ except Exception as e:
92
+ logger.error(f"Inference failed: {e}")
93
+ return None
94
+
95
+
96
+ def process_file(
97
+ input_path: Path,
98
+ output_path: Path,
99
+ model: nn.Module | torch.export.ExportedProgram,
100
+ ) -> bool:
101
+ """Process a single file: load, infer, save.
102
+
103
+ Args:
104
+ input_path: Path to input .npy file
105
+ output_path: Path to output .npy file
106
+ model: Loaded PyTorch model
107
+
108
+ Returns:
109
+ True if successful, False otherwise
110
+ """
111
+ # Load spectrogram
112
+ spec = load_spectrogram(input_path)
113
+ if spec is None:
114
+ return False
115
+
116
+ # Run inference
117
+ result = run_inference(spec, model)
118
+ if result is None:
119
+ return False
120
+
121
+ # Save result
122
+ try:
123
+ output_path.parent.mkdir(parents=True, exist_ok=True)
124
+ np.save(output_path, result)
125
+ return True
126
+ except Exception as e:
127
+ logger.error(f"Failed to save {output_path.name}: {e}")
128
+ return False
129
+
130
+
131
+ def scan_directory(input_dir: Path) -> set[str]:
132
+ """Scan directory for .npy files.
133
+
134
+ Args:
135
+ input_dir: Directory to scan
136
+
137
+ Returns:
138
+ Set of filenames (not full paths)
139
+ """
140
+ if not input_dir.exists():
141
+ return set()
142
+
143
+ npy_files = input_dir.glob("*.npy")
144
+ return {f.name for f in npy_files}
145
+
146
+
147
+ def run_batch_analysis(settings: dict):
148
+ """Main batch analysis loop.
149
+
150
+ Continuously monitors input directory for new spectrogram files,
151
+ runs inference, and saves results. Runs until interrupted with Ctrl+C.
152
+
153
+ Args:
154
+ settings: Dictionary with configuration:
155
+ - model_path: Path to model file
156
+ - input_path: Input directory to monitor
157
+ - output_path: Output directory for results
158
+ - polling_interval: Seconds between directory scans
159
+ """
160
+ # Extract settings
161
+ model_path = Path(settings["model_path"])
162
+ input_dir = Path(settings["input_path"])
163
+ output_dir = Path(settings["output_path"])
164
+ polling_interval = settings.get("polling_interval", 5)
165
+
166
+ # Ensure directories exist
167
+ input_dir.mkdir(parents=True, exist_ok=True)
168
+ output_dir.mkdir(parents=True, exist_ok=True)
169
+
170
+ # Load model
171
+ logger.info("=" * 60)
172
+ logger.info("Starting Batch Analysis System")
173
+ logger.info("=" * 60)
174
+ logger.info(f"Model: {model_path}")
175
+ logger.info(f"Input directory: {input_dir}")
176
+ logger.info(f"Output directory: {output_dir}")
177
+ logger.info(f"Polling interval: {polling_interval}s")
178
+ logger.info("=" * 60)
179
+
180
+ try:
181
+ model = model_load(model_path)
182
+ except Exception as e:
183
+ logger.error(f"Failed to load model: {e}")
184
+ return
185
+
186
+ # Initialize tracking
187
+ processed_files = set()
188
+
189
+ logger.info("Monitoring for new files... (Press Ctrl+C to stop)")
190
+ logger.info("")
191
+
192
+ # Main loop
193
+ try:
194
+ while True:
195
+ # Scan for all files in directory
196
+ current_files = scan_directory(input_dir)
197
+
198
+ # Update tracking: remove deleted files
199
+ deleted_files = processed_files - current_files
200
+ if deleted_files:
201
+ for fname in deleted_files:
202
+ processed_files.discard(fname)
203
+ logger.info(f"File deleted, will reprocess if added again: {fname}")
204
+
205
+ # Find new files to process
206
+ new_files = current_files - processed_files
207
+
208
+ if new_files:
209
+ logger.info(f"Found {len(new_files)} new file(s)")
210
+
211
+ # Process files with progress bar
212
+ new_files_list = sorted(new_files)
213
+ for fname in tqdm(new_files_list, desc="Processing", unit="file"):
214
+ input_path = input_dir / fname
215
+ output_path = output_dir / fname
216
+
217
+ # Process the file
218
+ success = process_file(input_path, output_path, model)
219
+
220
+ if success:
221
+ processed_files.add(fname)
222
+ logger.info(f"✓ Processed: {fname}")
223
+ else:
224
+ logger.warning(f"✗ Failed: {fname}")
225
+
226
+ logger.info("")
227
+
228
+ # Sleep before next scan
229
+ time.sleep(polling_interval)
230
+
231
+ except KeyboardInterrupt:
232
+ logger.info("")
233
+ logger.info("=" * 60)
234
+ logger.info("Shutting down gracefully...")
235
+ logger.info(f"Total files processed: {len(processed_files)}")
236
+ logger.info("=" * 60)
237
+
238
+
239
+ if __name__ == "__main__":
240
+ run_batch_analysis(default_settings)
File without changes
@@ -0,0 +1,84 @@
1
+ """
2
+ TokEye Main Inference
3
+ """
4
+
5
+ import logging
6
+ import sys
7
+ from pathlib import Path
8
+
9
+ import gradio as gr
10
+
11
+ # Import tabs
12
+ from .analyze.analyze import analyze_tab
13
+ from .tabs.annotate import annotate_tab
14
+ from .tabs.utilities import utilities_tab
15
+ from .utils.theme import make_theme
16
+
17
+ # Constants
18
+ APP_TITLE = "TokEye"
19
+ DEFAULT_PORT = 7860
20
+ MAX_PORT_ATTEMPTS = 10
21
+
22
+ # Set up logging
23
+ logging.getLogger("uvicorn").setLevel(logging.WARNING)
24
+ logging.getLogger("httpx").setLevel(logging.WARNING)
25
+
26
+ # Current working directory
27
+ cwd = Path.cwd()
28
+
29
+
30
+ def create_app() -> gr.Blocks:
31
+ with gr.Blocks(
32
+ title=APP_TITLE,
33
+ theme=make_theme(),
34
+ css="footer{display:none !important}",
35
+ ) as app:
36
+ gr.Image(
37
+ str(Path.cwd() / "assets" / "logo.png"),
38
+ height=300,
39
+ interactive=False,
40
+ container=False,
41
+ show_download_button=False,
42
+ show_fullscreen_button=False,
43
+ )
44
+ with gr.Tab("Analyze"):
45
+ analyze_tab()
46
+ with gr.Tab("Annotate"):
47
+ annotate_tab()
48
+ with gr.Tab("Utilities"):
49
+ utilities_tab()
50
+ return app
51
+
52
+
53
+ def get_port():
54
+ if "--port" in sys.argv:
55
+ port_index = sys.argv.index("--port") + 1
56
+ if port_index < len(sys.argv):
57
+ return int(sys.argv[port_index])
58
+ return DEFAULT_PORT
59
+
60
+
61
+ def launch(app, port):
62
+ app.launch(
63
+ # favicon_path="assets/ICON.ico", # Set up favicon later
64
+ share="--share" in sys.argv,
65
+ inbrowser="--open" in sys.argv,
66
+ server_port=port,
67
+ )
68
+
69
+
70
+ if __name__ == "__main__":
71
+ logging.info(f"Initializing TokEye in: {cwd}")
72
+ # Set up
73
+ app = create_app()
74
+ # Launch application
75
+ port = get_port()
76
+ for _ in range(MAX_PORT_ATTEMPTS):
77
+ try:
78
+ launch(app, port)
79
+ except OSError:
80
+ print(f"Failed on port {port}")
81
+ port -= 1
82
+ except Exception as error:
83
+ print(f"{error}")
84
+ break
File without changes