move_webui #35
@@ -14,7 +14,7 @@ from torchvision.transforms.functional import pad
|
||||
from torchvision.transforms.functional import resize
|
||||
from torchvision.transforms.functional import rotate
|
||||
|
||||
from core.database import connect
|
||||
from shared.database import connect
|
||||
|
||||
# resnet18 original normalization values
|
||||
RESNET_NORMALIZE_MEAN = [0.485, 0.456, 0.406]
|
||||
|
||||
@@ -14,17 +14,17 @@ from .point_of_view import PointOfViewTail
|
||||
from .resnet18_head import ResNet18Head
|
||||
from .salience import SalienceTail
|
||||
from .visual_syntax import VisualSyntaxTail
|
||||
from core.dto import AngleData
|
||||
from core.dto import ContactData
|
||||
from core.dto import DistanceData
|
||||
from core.dto import FramingData
|
||||
from core.dto import InformationValueData
|
||||
from core.dto import ModalityColorData
|
||||
from core.dto import ModalityDepthData
|
||||
from core.dto import ModalityLightingData
|
||||
from core.dto import PointOfViewData
|
||||
from core.dto import SalienceData
|
||||
from core.dto import VisualSyntaxData
|
||||
from shared.dto import AngleData
|
||||
from shared.dto import ContactData
|
||||
from shared.dto import DistanceData
|
||||
from shared.dto import FramingData
|
||||
from shared.dto import InformationValueData
|
||||
from shared.dto import ModalityColorData
|
||||
from shared.dto import ModalityDepthData
|
||||
from shared.dto import ModalityLightingData
|
||||
from shared.dto import PointOfViewData
|
||||
from shared.dto import SalienceData
|
||||
from shared.dto import VisualSyntaxData
|
||||
|
||||
|
||||
class VisualCommunicationModel(nn.Module):
|
||||
|
||||
Generated
+108
-104
@@ -32,13 +32,13 @@ tests-no-zope = ["attrs[tests-mypy]", "cloudpickle", "hypothesis", "pympler", "p
|
||||
|
||||
[[package]]
|
||||
name = "blinker"
|
||||
version = "1.8.1"
|
||||
version = "1.8.2"
|
||||
description = "Fast, simple object-to-object and broadcast signaling"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "blinker-1.8.1-py3-none-any.whl", hash = "sha256:5f1cdeff423b77c31b89de0565cd03e5275a03028f44b2b15f912632a58cced6"},
|
||||
{file = "blinker-1.8.1.tar.gz", hash = "sha256:da44ec748222dcd0105ef975eed946da197d5bdf8bafb6aa92f5bc89da63fa25"},
|
||||
{file = "blinker-1.8.2-py3-none-any.whl", hash = "sha256:1779309f71bf239144b9399d06ae925637cf6634cf6bd131104184531bf67c01"},
|
||||
{file = "blinker-1.8.2.tar.gz", hash = "sha256:8f77b09d3bf7c795e969e9486f39c2c5e9c39d4ee07424be2bc594ece9642d83"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -242,13 +242,13 @@ files = [
|
||||
|
||||
[[package]]
|
||||
name = "dash"
|
||||
version = "2.16.1"
|
||||
version = "2.17.0"
|
||||
description = "A Python framework for building reactive web-apps. Developed by Plotly."
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "dash-2.16.1-py3-none-any.whl", hash = "sha256:8a9d2a618e415113c0b2a4d25d5dc4df5cb921f733b33dde75559db2316b1df1"},
|
||||
{file = "dash-2.16.1.tar.gz", hash = "sha256:b2871d6b8d4c9dfd0a64f89f22d001c93292910b41d92d9ff2bb424a28283976"},
|
||||
{file = "dash-2.17.0-py3-none-any.whl", hash = "sha256:2421569023b2cd46ea2d4b2c14fe72c71b7436527a3102219b2265fa361e7c67"},
|
||||
{file = "dash-2.17.0.tar.gz", hash = "sha256:d065cd88771e45d0485993be0d27565e08918cb7edd18e31ee1c5b41252fc2fa"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
@@ -267,7 +267,7 @@ Werkzeug = "<3.1"
|
||||
|
||||
[package.extras]
|
||||
celery = ["celery[redis] (>=5.1.2)", "redis (>=3.5.3)"]
|
||||
ci = ["black (==22.3.0)", "dash-dangerously-set-inner-html", "dash-flow-example (==0.0.5)", "flake8 (==7.0.0)", "flaky (==3.7.0)", "flask-talisman (==1.0.0)", "jupyterlab (<4.0.0)", "mimesis (<=11.1.0)", "mock (==4.0.3)", "numpy (<=1.26.3)", "openpyxl", "orjson (==3.9.12)", "pandas (>=1.4.0)", "pyarrow", "pylint (==3.0.3)", "pytest-mock", "pytest-rerunfailures", "pytest-sugar (==0.9.6)", "pyzmq (==25.1.2)", "xlrd (>=2.0.1)"]
|
||||
ci = ["black (==22.3.0)", "dash-dangerously-set-inner-html", "dash-flow-example (==0.0.5)", "flake8 (==7.0.0)", "flaky (==3.8.1)", "flask-talisman (==1.0.0)", "jupyterlab (<4.0.0)", "mimesis (<=11.1.0)", "mock (==4.0.3)", "numpy (<=1.26.3)", "openpyxl", "orjson (==3.9.12)", "pandas (>=1.4.0)", "pyarrow", "pylint (==3.0.3)", "pytest-mock", "pytest-rerunfailures", "pytest-sugar (==0.9.6)", "pyzmq (==25.1.2)", "xlrd (>=2.0.1)"]
|
||||
compress = ["flask-compress"]
|
||||
dev = ["PyYAML (>=5.4.1)", "coloredlogs (>=15.0.1)", "fire (>=0.4.0)"]
|
||||
diskcache = ["diskcache (>=5.2.1)", "multiprocess (>=0.70.12)", "psutil (>=5.8.0)"]
|
||||
@@ -440,13 +440,13 @@ dotenv = ["python-dotenv"]
|
||||
|
||||
[[package]]
|
||||
name = "fsspec"
|
||||
version = "2024.3.1"
|
||||
version = "2024.5.0"
|
||||
description = "File-system specification"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "fsspec-2024.3.1-py3-none-any.whl", hash = "sha256:918d18d41bf73f0e2b261824baeb1b124bcf771767e3a26425cd7dec3332f512"},
|
||||
{file = "fsspec-2024.3.1.tar.gz", hash = "sha256:f39780e282d7d117ffb42bb96992f8a90795e4d0fb0f661a70ca39fe9c43ded9"},
|
||||
{file = "fsspec-2024.5.0-py3-none-any.whl", hash = "sha256:e0fdbc446d67e182f49a70b82cf7889028a63588fde6b222521f10937b2b670c"},
|
||||
{file = "fsspec-2024.5.0.tar.gz", hash = "sha256:1d021b0b0f933e3b3029ed808eb400c08ba101ca2de4b3483fbc9ca23fcee94a"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
@@ -454,7 +454,7 @@ abfs = ["adlfs"]
|
||||
adl = ["adlfs"]
|
||||
arrow = ["pyarrow (>=1)"]
|
||||
dask = ["dask", "distributed"]
|
||||
devel = ["pytest", "pytest-cov"]
|
||||
dev = ["pre-commit", "ruff"]
|
||||
dropbox = ["dropbox", "dropboxdrivefs", "requests"]
|
||||
full = ["adlfs", "aiohttp (!=4.0.0a0,!=4.0.0a1)", "dask", "distributed", "dropbox", "dropboxdrivefs", "fusepy", "gcsfs", "libarchive-c", "ocifs", "panel", "paramiko", "pyarrow (>=1)", "pygit2", "requests", "s3fs", "smbprotocol", "tqdm"]
|
||||
fuse = ["fusepy"]
|
||||
@@ -471,6 +471,9 @@ s3 = ["s3fs"]
|
||||
sftp = ["paramiko"]
|
||||
smb = ["smbprotocol"]
|
||||
ssh = ["paramiko"]
|
||||
test = ["aiohttp (!=4.0.0a0,!=4.0.0a1)", "numpy", "pytest", "pytest-asyncio (!=0.22.0)", "pytest-benchmark", "pytest-cov", "pytest-mock", "pytest-recording", "pytest-rerunfailures", "requests"]
|
||||
test-downstream = ["aiobotocore (>=2.5.4,<3.0.0)", "dask-expr", "dask[dataframe,test]", "moto[server] (>4,<5)", "pytest-timeout", "xarray"]
|
||||
test-full = ["adlfs", "aiohttp (!=4.0.0a0,!=4.0.0a1)", "cloudpickle", "dask", "distributed", "dropbox", "dropboxdrivefs", "fastparquet", "fusepy", "gcsfs", "jinja2", "kerchunk", "libarchive-c", "lz4", "notebook", "numpy", "ocifs", "pandas", "panel", "paramiko", "pyarrow", "pyarrow (>=1)", "pyftpdlib", "pygit2", "pytest", "pytest-asyncio (!=0.22.0)", "pytest-benchmark", "pytest-cov", "pytest-mock", "pytest-recording", "pytest-rerunfailures", "python-snappy", "requests", "smbprotocol", "tqdm", "urllib3", "zarr", "zstandard"]
|
||||
tqdm = ["tqdm"]
|
||||
|
||||
[[package]]
|
||||
@@ -547,13 +550,13 @@ files = [
|
||||
|
||||
[[package]]
|
||||
name = "jinja2"
|
||||
version = "3.1.3"
|
||||
version = "3.1.4"
|
||||
description = "A very fast and expressive template engine."
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "Jinja2-3.1.3-py3-none-any.whl", hash = "sha256:7d6d50dd97d52cbc355597bd845fabfbac3f551e1f99619e39a35ce8c370b5fa"},
|
||||
{file = "Jinja2-3.1.3.tar.gz", hash = "sha256:ac8bd6544d4bb2c9792bf3a159e80bba8fda7f07e81bc3aed565432d5925ba90"},
|
||||
{file = "jinja2-3.1.4-py3-none-any.whl", hash = "sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d"},
|
||||
{file = "jinja2-3.1.4.tar.gz", hash = "sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
@@ -1113,13 +1116,13 @@ xmp = ["defusedxml"]
|
||||
|
||||
[[package]]
|
||||
name = "plotly"
|
||||
version = "5.21.0"
|
||||
version = "5.22.0"
|
||||
description = "An open-source, interactive data visualization library for Python"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "plotly-5.21.0-py3-none-any.whl", hash = "sha256:a33f41fd5922e45b2b253f795b200d14452eb625790bb72d0a72cf1328a6abbf"},
|
||||
{file = "plotly-5.21.0.tar.gz", hash = "sha256:69243f8c165d4be26c0df1c6f0b7b258e2dfeefe032763404ad7e7fb7d7c2073"},
|
||||
{file = "plotly-5.22.0-py3-none-any.whl", hash = "sha256:68fc1901f098daeb233cc3dd44ec9dc31fb3ca4f4e53189344199c43496ed006"},
|
||||
{file = "plotly-5.22.0.tar.gz", hash = "sha256:859fdadbd86b5770ae2466e542b761b247d1c6b49daed765b95bb8c7063e7469"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
@@ -1282,71 +1285,71 @@ files = [
|
||||
|
||||
[[package]]
|
||||
name = "pymongo"
|
||||
version = "4.7.1"
|
||||
version = "4.7.2"
|
||||
description = "Python driver for MongoDB <http://www.mongodb.org>"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "pymongo-4.7.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f8822614975038e0cece47d12e7634a79c2ee590a0ae78ae64c37b9c6610a14c"},
|
||||
{file = "pymongo-4.7.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:57b5b485ef89270ed2e603814f43f0fdd9b8ba5d4039124d90878cdc2327000c"},
|
||||
{file = "pymongo-4.7.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9e99dac3c7c2cb498937cc1767361851099da38861e921113318c87d71e3d127"},
|
||||
{file = "pymongo-4.7.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:253ed8fd6e7f4b2a1caa89e6b287b9e04f42613319ee1e1240c2db2afe1637e7"},
|
||||
{file = "pymongo-4.7.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8cee62188127a126f59ea45d3981868a5e35343be4ef4ad8712eaf42be37a00b"},
|
||||
{file = "pymongo-4.7.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:31ed8ba3da0366346264604b3a443f5a4232cab5ed45f520bead6184cf0851a1"},
|
||||
{file = "pymongo-4.7.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:887d043ecc0c7d5591925bbc7abb67caf21c94d6e6e5d442cb49eb5d9d8ee76b"},
|
||||
{file = "pymongo-4.7.1-cp310-cp310-win32.whl", hash = "sha256:bfd5c7e5bb87171a5296fa32205adb50b27704a612036ec4395c3cd316fc0e91"},
|
||||
{file = "pymongo-4.7.1-cp310-cp310-win_amd64.whl", hash = "sha256:5ae1aeeb405c29885266666dc7115792d647ed68cfdb6ed02e2e211d12f2e1c8"},
|
||||
{file = "pymongo-4.7.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:e4a63ba6813a2168ebd35ea5369f6c33f7787525986cd77668b7956acc3d2a38"},
|
||||
{file = "pymongo-4.7.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:811a07bba9d35f1e34159ede632ac71dbc429b372a20004e32d6578af872db1a"},
|
||||
{file = "pymongo-4.7.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4d227555be35078b53f506f6b58bd0b0e8fd4513e89e6f29e83a97efab439250"},
|
||||
{file = "pymongo-4.7.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:daf35ab13b86aba7cc8c4b019882f1fa8d287a26f586ef5eaf60a5233d3eaa52"},
|
||||
{file = "pymongo-4.7.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:aa354933a158e57494c98b592f46d5d24d1b109e6ba05a05179cde719d9f7fd3"},
|
||||
{file = "pymongo-4.7.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ad360630c221aee7c0841a51851496a3ca6fdea87007098a982c1aa26e34083a"},
|
||||
{file = "pymongo-4.7.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5119c66af8c4197c8757b4b7d98c443e5b127c224ac92fb657dbe2b512ae2713"},
|
||||
{file = "pymongo-4.7.1-cp311-cp311-win32.whl", hash = "sha256:11f74dafde63ad2dc30c01f40b4c69d9af157f8ba5224b0c9d4de7158537266f"},
|
||||
{file = "pymongo-4.7.1-cp311-cp311-win_amd64.whl", hash = "sha256:ec94d29103317aa920dae59ed385de9604cb0ef840b5b7137b5eaa7a2042580a"},
|
||||
{file = "pymongo-4.7.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:b8b95e2163b73d03a913efa89b0f7c5012be82efd4e9dbce8aa62010a75a277c"},
|
||||
{file = "pymongo-4.7.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fb1a884b1c6aeac5ffeb8ccb696fbc242a7ae1bba36f2328c01f76fab7221b94"},
|
||||
{file = "pymongo-4.7.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2ccc8dd4fe9aac18dde27c33a53271c6c90159b74c43fbdab1d33d5efc36c2f5"},
|
||||
{file = "pymongo-4.7.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7247c1dc7d8eed4e24eb1dd92c4c58ebf1e5159500015652552acfdebdeed256"},
|
||||
{file = "pymongo-4.7.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:45ac46f0d6bdc2baac34ced60aae27b2083170d77397330eff0ac5689ea29d38"},
|
||||
{file = "pymongo-4.7.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a848249d5b4763497add62f7dd7bd0ce1538129bf42f4cb132a76d24c61bf98d"},
|
||||
{file = "pymongo-4.7.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5ff6d56ca1f0cd3687a13ce90a32a8efb3cc3a53728e5ac160c4c30d10385a72"},
|
||||
{file = "pymongo-4.7.1-cp312-cp312-win32.whl", hash = "sha256:e175d74c52b6c8414a4b4504a2dd42b0202d101b2eb9508a34c137357683864e"},
|
||||
{file = "pymongo-4.7.1-cp312-cp312-win_amd64.whl", hash = "sha256:263c169302df636f9086b584994a51d0adfc8738fe27d7b8e2aacf46fd68b6cb"},
|
||||
{file = "pymongo-4.7.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:337d99f88d32a5f8056d6d2bc365ccf09d09583f3942882c50cf11b459e8fbc0"},
|
||||
{file = "pymongo-4.7.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:30a9d891631d7e847b24f551b1d89ff2033539e7cd8e9af29714b4d0db7abb06"},
|
||||
{file = "pymongo-4.7.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:73bf96ece4999b0bbab7169cb2b9c60918b434487009e48be4bd47eeb2aa7b14"},
|
||||
{file = "pymongo-4.7.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3ef32a7cfe748c0c72fdad9e51459de5e0c6b16c5288b39f863abfff23503847"},
|
||||
{file = "pymongo-4.7.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:24c8f1dd545360ec1b79007a3ba6573af565df6fde49f6dfc53813f3f475a751"},
|
||||
{file = "pymongo-4.7.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b897b60b2d55c26f3efea0effc11b655db68125c3731274bc3953375e9ccab73"},
|
||||
{file = "pymongo-4.7.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5a58b6cd7c423ba49db10d8445756062c931ad2246ba0da1e705bf22962fd9e9"},
|
||||
{file = "pymongo-4.7.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:ed6b3a0740efe98bb03ccf054578e9788ebcd06d021d548b8217ab2c82e45975"},
|
||||
{file = "pymongo-4.7.1-cp37-cp37m-win32.whl", hash = "sha256:85b8dd3756b73993b1e3ab6b1cba826b9e4987a094a5d5b6d37313776458cd94"},
|
||||
{file = "pymongo-4.7.1-cp37-cp37m-win_amd64.whl", hash = "sha256:297cdc87c4b4168782b571c8643540e9b0ad1d09266b43d2f5954f8632280835"},
|
||||
{file = "pymongo-4.7.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:7b10603ba64af08f5af7eb9a69d6b24e3c69d91fdd48c54b95e284686c1c582d"},
|
||||
{file = "pymongo-4.7.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:64b69b9cd8a6d23881a80490d575e92918f9afca43096a7d6c1013d6b3e5c75c"},
|
||||
{file = "pymongo-4.7.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4c7e05454cdc5aa4702e03cad0df4205daccd6fd631bbbf0a85bbe598129a6cc"},
|
||||
{file = "pymongo-4.7.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9e0a30a022ac8a9164ee5a4b761e13dbb3d10a21845f7258011e3415151fb645"},
|
||||
{file = "pymongo-4.7.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:13fc201e073644acd77860d9e91ccfc27addf510563e07381cadc9a55ac3a894"},
|
||||
{file = "pymongo-4.7.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4dd998e9f0f7694032c1648c7f57fccaa78903df6329b8f8ae20cfa7c4ceca34"},
|
||||
{file = "pymongo-4.7.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:455f9d603ed0990a787773d5718e871300bddf585ce543baf129c9f5ca3adb02"},
|
||||
{file = "pymongo-4.7.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d804eaf19a65211cc2c8c5db75be685c3f31c64cdab639794f66f13f8e258ba6"},
|
||||
{file = "pymongo-4.7.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:a46c08ef0b273c415b1e8933f6739596be264ae700a4927f84e0b84e70fdf0eb"},
|
||||
{file = "pymongo-4.7.1-cp38-cp38-win32.whl", hash = "sha256:58989bcb94233233a71645236b972835d4f87a6bb1b7e818d38a7e6e6d4630de"},
|
||||
{file = "pymongo-4.7.1-cp38-cp38-win_amd64.whl", hash = "sha256:d63f38454a2e23c117d3ceab3b661568f2418536825787256ad24e5baaedfd27"},
|
||||
{file = "pymongo-4.7.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d50969de00d3522b2c394f7e59b843871e2be4b525af92066da7f3bd02799fdc"},
|
||||
{file = "pymongo-4.7.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f2a720e787c9b9b912db5bb4c3e7123ccff1352d6c3ac0cb2c7ee392cdc95c00"},
|
||||
{file = "pymongo-4.7.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c808098f2cdb87d4035144e536ba5fa7709d0420c17b68e6ace5da18c38ded5f"},
|
||||
{file = "pymongo-4.7.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d1829a7db720ff586aaf59c806e89e0a388548063aa844d21a570a231ad8ca87"},
|
||||
{file = "pymongo-4.7.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:615c7573d7a9c4837332a673fdc5a5f214b474dd52d846bcf4cc3d011550bee1"},
|
||||
{file = "pymongo-4.7.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e935712b17e7a42831022353bac91a346a792658a54e12bec907ec11695cc899"},
|
||||
{file = "pymongo-4.7.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dbc32217c81d87750401fa1c2bc9450e854b23e6e30243c82d3514b8e58f39e3"},
|
||||
{file = "pymongo-4.7.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5bc87db2e9563295c4e45602ab978a2fcbaba3ab89e745503b24f895cddeb755"},
|
||||
{file = "pymongo-4.7.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:65c45682d5ed8c6618bde22cd6716b47a197f4ef800a025213b28d13a59e5fca"},
|
||||
{file = "pymongo-4.7.1-cp39-cp39-win32.whl", hash = "sha256:67cbee427c263a4483e3249fef480788ccc16edb1a4fc330c4c6cb0cb9db94a8"},
|
||||
{file = "pymongo-4.7.1-cp39-cp39-win_amd64.whl", hash = "sha256:1bd1eef70c1eda838b26397ef75c9580d7a97fd94b6324971d7f3d2ad3552e9a"},
|
||||
{file = "pymongo-4.7.1.tar.gz", hash = "sha256:811c41c6227b7548afcb53e1b996c25262d837b5e5f519e2ddc2c7e59d8728a5"},
|
||||
{file = "pymongo-4.7.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:268d8578c0500012140c5460755ea405cbfe541ef47c81efa9d6744f0f99aeca"},
|
||||
{file = "pymongo-4.7.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:827611beb6c483260d520cfa6a49662d980dfa5368a04296f65fa39e78fccea7"},
|
||||
{file = "pymongo-4.7.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a754e366c404d19ff3f077ddeed64be31e0bb515e04f502bf11987f1baa55a16"},
|
||||
{file = "pymongo-4.7.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c44efab10d9a3db920530f7bcb26af8f408b7273d2f0214081d3891979726328"},
|
||||
{file = "pymongo-4.7.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:35b3f0c7d49724859d4df5f0445818d525824a6cd55074c42573d9b50764df67"},
|
||||
{file = "pymongo-4.7.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1e37faf298a37ffb3e0809e77fbbb0a32b6a2d18a83c59cfc2a7b794ea1136b0"},
|
||||
{file = "pymongo-4.7.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d1bcd58669e56c08f1e72c5758868b5df169fe267501c949ee83c418e9df9155"},
|
||||
{file = "pymongo-4.7.2-cp310-cp310-win32.whl", hash = "sha256:c72d16fede22efe7cdd1f422e8da15760e9498024040429362886f946c10fe95"},
|
||||
{file = "pymongo-4.7.2-cp310-cp310-win_amd64.whl", hash = "sha256:12d1fef77d25640cb78893d07ff7d2fac4c4461d8eec45bd3b9ad491a1115d6e"},
|
||||
{file = "pymongo-4.7.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:fc5af24fcf5fc6f7f40d65446400d45dd12bea933d0299dc9e90c5b22197f1e9"},
|
||||
{file = "pymongo-4.7.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:730778b6f0964b164c187289f906bbc84cb0524df285b7a85aa355bbec43eb21"},
|
||||
{file = "pymongo-4.7.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:47a1a4832ef2f4346dcd1a10a36ade7367ad6905929ddb476459abb4fd1b98cb"},
|
||||
{file = "pymongo-4.7.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e6eab12c6385526d386543d6823b07187fefba028f0da216506e00f0e1855119"},
|
||||
{file = "pymongo-4.7.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:37e9ea81fa59ee9274457ed7d59b6c27f6f2a5fe8e26f184ecf58ea52a019cb8"},
|
||||
{file = "pymongo-4.7.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e9d9d2c0aae73aa4369bd373ac2ac59f02c46d4e56c4b6d6e250cfe85f76802"},
|
||||
{file = "pymongo-4.7.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cb6e00a79dff22c9a72212ad82021b54bdb3b85f38a85f4fc466bde581d7d17a"},
|
||||
{file = "pymongo-4.7.2-cp311-cp311-win32.whl", hash = "sha256:02efd1bb3397e24ef2af45923888b41a378ce00cb3a4259c5f4fc3c70497a22f"},
|
||||
{file = "pymongo-4.7.2-cp311-cp311-win_amd64.whl", hash = "sha256:87bb453ac3eb44db95cb6d5a616fbc906c1c00661eec7f55696253a6245beb8a"},
|
||||
{file = "pymongo-4.7.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:12c466e02133b7f8f4ff1045c6b5916215c5f7923bc83fd6e28e290cba18f9f6"},
|
||||
{file = "pymongo-4.7.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f91073049c43d14e66696970dd708d319b86ee57ef9af359294eee072abaac79"},
|
||||
{file = "pymongo-4.7.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:87032f818bf5052ab742812c715eff896621385c43f8f97cdd37d15b5d394e95"},
|
||||
{file = "pymongo-4.7.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6a87eef394039765679f75c6a47455a4030870341cb76eafc349c5944408c882"},
|
||||
{file = "pymongo-4.7.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d275596f840018858757561840767b39272ac96436fcb54f5cac6d245393fd97"},
|
||||
{file = "pymongo-4.7.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:82102e353be13f1a6769660dd88115b1da382447672ba1c2662a0fbe3df1d861"},
|
||||
{file = "pymongo-4.7.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:194065c9d445017b3c82fb85f89aa2055464a080bde604010dc8eb932a6b3c95"},
|
||||
{file = "pymongo-4.7.2-cp312-cp312-win32.whl", hash = "sha256:db4380d1e69fdad1044a4b8f3bb105200542c49a0dde93452d938ff9db1d6d29"},
|
||||
{file = "pymongo-4.7.2-cp312-cp312-win_amd64.whl", hash = "sha256:fadc6e8db7707c861ebe25b13ad6aca19ea4d2c56bf04a26691f46c23dadf6e4"},
|
||||
{file = "pymongo-4.7.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:2cb77d09bd012cb4b30636e7e38d00b5f9be5eb521c364bde66490c45ee6c4b4"},
|
||||
{file = "pymongo-4.7.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:56bf8b706946952acdea0fe478f8e44f1ed101c4b87f046859e6c3abe6c0a9f4"},
|
||||
{file = "pymongo-4.7.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bcf337d1b252405779d9c79978d6ca15eab3cdaa2f44c100a79221bddad97c8a"},
|
||||
{file = "pymongo-4.7.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4ffd1519edbe311df73c74ec338de7d294af535b2748191c866ea3a7c484cd15"},
|
||||
{file = "pymongo-4.7.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d4d59776f435564159196d971aa89422ead878174aff8fe18e06d9a0bc6d648c"},
|
||||
{file = "pymongo-4.7.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:347c49cf7f0ba49ea87c1a5a1984187ecc5516b7c753f31938bf7b37462824fd"},
|
||||
{file = "pymongo-4.7.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:84bc00200c3cbb6c98a2bb964c9e8284b641e4a33cf10c802390552575ee21de"},
|
||||
{file = "pymongo-4.7.2-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:fcaf8c911cb29316a02356f89dbc0e0dfcc6a712ace217b6b543805690d2aefd"},
|
||||
{file = "pymongo-4.7.2-cp37-cp37m-win32.whl", hash = "sha256:b48a5650ee5320d59f6d570bd99a8d5c58ac6f297a4e9090535f6561469ac32e"},
|
||||
{file = "pymongo-4.7.2-cp37-cp37m-win_amd64.whl", hash = "sha256:5239ef7e749f1326ea7564428bf861d5250aa39d7f26d612741b1b1273227062"},
|
||||
{file = "pymongo-4.7.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d2dcf608d35644e8d276d61bf40a93339d8d66a0e5f3e3f75b2c155a421a1b71"},
|
||||
{file = "pymongo-4.7.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:25eeb2c18ede63891cbd617943dd9e6b9cbccc54f276e0b2e693a0cc40f243c5"},
|
||||
{file = "pymongo-4.7.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9349f0bb17a31371d4cacb64b306e4ca90413a3ad1fffe73ac7cd495570d94b5"},
|
||||
{file = "pymongo-4.7.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ffd4d7cb2e6c6e100e2b39606d38a9ffc934e18593dc9bb326196afc7d93ce3d"},
|
||||
{file = "pymongo-4.7.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9a8bd37f5dabc86efceb8d8cbff5969256523d42d08088f098753dba15f3b37a"},
|
||||
{file = "pymongo-4.7.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1c78f156edc59b905c80c9003e022e1a764c54fd40ac4fea05b0764f829790e2"},
|
||||
{file = "pymongo-4.7.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9d892fb91e81cccb83f507cdb2ea0aa026ec3ced7f12a1d60f6a5bf0f20f9c1f"},
|
||||
{file = "pymongo-4.7.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:87832d6076c2c82f42870157414fd876facbb6554d2faf271ffe7f8f30ce7bed"},
|
||||
{file = "pymongo-4.7.2-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:ce1a374ea0e49808e0380ffc64284c0ce0f12bd21042b4bef1af3eb7bdf49054"},
|
||||
{file = "pymongo-4.7.2-cp38-cp38-win32.whl", hash = "sha256:eb0642e5f0dd7e86bb358749cc278e70b911e617f519989d346f742dc9520dfb"},
|
||||
{file = "pymongo-4.7.2-cp38-cp38-win_amd64.whl", hash = "sha256:4bdb5ffe1cd3728c9479671a067ef44dacafc3743741d4dc700c377c4231356f"},
|
||||
{file = "pymongo-4.7.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:743552033c63f0afdb56b9189ab04b5c1dbffd7310cf7156ab98eebcecf24621"},
|
||||
{file = "pymongo-4.7.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:5239776633f7578b81207e5646245415a5a95f6ae5ef5dff8e7c2357e6264bfc"},
|
||||
{file = "pymongo-4.7.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:727ad07952c155cd20045f2ce91143c7dc4fb01a5b4e8012905a89a7da554b0c"},
|
||||
{file = "pymongo-4.7.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9385654f01a90f73827af4db90c290a1519f7d9102ba43286e187b373e9a78e9"},
|
||||
{file = "pymongo-4.7.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0d833651f1ba938bb7501f13e326b96cfbb7d98867b2d545ca6d69c7664903e0"},
|
||||
{file = "pymongo-4.7.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cf17ea9cea14d59b0527403dd7106362917ced7c4ec936c4ba22bd36c912c8e0"},
|
||||
{file = "pymongo-4.7.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cecd2df037249d1c74f0af86fb5b766104a5012becac6ff63d85d1de53ba8b98"},
|
||||
{file = "pymongo-4.7.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:65b4c00dedbd333698b83cd2095a639a6f0d7c4e2a617988f6c65fb46711f028"},
|
||||
{file = "pymongo-4.7.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:d9b6cbc037108ff1a0a867e7670d8513c37f9bcd9ee3d2464411bfabf70ca002"},
|
||||
{file = "pymongo-4.7.2-cp39-cp39-win32.whl", hash = "sha256:cf28430ec1924af1bffed37b69a812339084697fd3f3e781074a0148e6475803"},
|
||||
{file = "pymongo-4.7.2-cp39-cp39-win_amd64.whl", hash = "sha256:e004527ea42a6b99a8b8d5b42b42762c3bdf80f88fbdb5c3a9d47f3808495b86"},
|
||||
{file = "pymongo-4.7.2.tar.gz", hash = "sha256:9024e1661c6e40acf468177bf90ce924d1bc681d2b244adda3ed7b2f4c4d17d7"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
@@ -1414,13 +1417,13 @@ files = [
|
||||
|
||||
[[package]]
|
||||
name = "requests"
|
||||
version = "2.31.0"
|
||||
version = "2.32.0"
|
||||
description = "Python HTTP for Humans."
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "requests-2.31.0-py3-none-any.whl", hash = "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f"},
|
||||
{file = "requests-2.31.0.tar.gz", hash = "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1"},
|
||||
{file = "requests-2.32.0-py3-none-any.whl", hash = "sha256:f2c3881dddb70d056c5bd7600a4fae312b2a300e39be6a118d30b90bd27262b5"},
|
||||
{file = "requests-2.32.0.tar.gz", hash = "sha256:fa5490319474c82ef1d2c9bc459d3652e3ae4ef4c4ebdd18a21145a47ca4b6b8"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
@@ -1464,13 +1467,13 @@ six = ">=1.7.0"
|
||||
|
||||
[[package]]
|
||||
name = "selenium"
|
||||
version = "4.20.0"
|
||||
version = "4.21.0"
|
||||
description = ""
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "selenium-4.20.0-py3-none-any.whl", hash = "sha256:b1d0c33b38ca27d0499183e48e1dd09ff26973481f5d3ef2983073813ae6588d"},
|
||||
{file = "selenium-4.20.0.tar.gz", hash = "sha256:0bd564ee166980d419a8aaf4ac00289bc152afcf2eadca5efe8c8e36711853fd"},
|
||||
{file = "selenium-4.21.0-py3-none-any.whl", hash = "sha256:4770ffe5a5264e609de7dc914be6b89987512040d5a8efb2abb181330d097993"},
|
||||
{file = "selenium-4.21.0.tar.gz", hash = "sha256:650dbfa5159895ff00ad16e5ddb6ceecb86b90c7ed2012b3f041f64e6e4904fe"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
@@ -1545,17 +1548,18 @@ mpmath = ">=0.19"
|
||||
|
||||
[[package]]
|
||||
name = "tenacity"
|
||||
version = "8.2.3"
|
||||
version = "8.3.0"
|
||||
description = "Retry code until it succeeds"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "tenacity-8.2.3-py3-none-any.whl", hash = "sha256:ce510e327a630c9e1beaf17d42e6ffacc88185044ad85cf74c0a8887c6a0f88c"},
|
||||
{file = "tenacity-8.2.3.tar.gz", hash = "sha256:5398ef0d78e63f40007c1fb4c0bff96e1911394d2fa8d194f77619c05ff6cc8a"},
|
||||
{file = "tenacity-8.3.0-py3-none-any.whl", hash = "sha256:3649f6443dbc0d9b01b9d8020a9c4ec7a1ff5f6f3c6c8a036ef371f573fe9185"},
|
||||
{file = "tenacity-8.3.0.tar.gz", hash = "sha256:953d4e6ad24357bceffbc9707bc74349aca9d245f68eb65419cf0c249a1949a2"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
doc = ["reno", "sphinx", "tornado (>=4.5)"]
|
||||
doc = ["reno", "sphinx"]
|
||||
test = ["pytest", "tornado (>=4.5)", "typeguard"]
|
||||
|
||||
[[package]]
|
||||
name = "torch"
|
||||
@@ -1658,13 +1662,13 @@ scipy = ["scipy"]
|
||||
|
||||
[[package]]
|
||||
name = "trio"
|
||||
version = "0.25.0"
|
||||
version = "0.25.1"
|
||||
description = "A friendly Python library for async concurrency and I/O"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "trio-0.25.0-py3-none-any.whl", hash = "sha256:e6458efe29cc543e557a91e614e2b51710eba2961669329ce9c862d50c6e8e81"},
|
||||
{file = "trio-0.25.0.tar.gz", hash = "sha256:9b41f5993ad2c0e5f62d0acca320ec657fdb6b2a2c22b8c7aed6caf154475c4e"},
|
||||
{file = "trio-0.25.1-py3-none-any.whl", hash = "sha256:e42617ba091e7b2e50c899052e83a3c403101841de925187f61e7b7eaebdf3fb"},
|
||||
{file = "trio-0.25.1.tar.gz", hash = "sha256:9f5314f014ea3af489e77b001861c535005c3858d38ec46b6b071ebfa339d7fb"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
@@ -1692,13 +1696,13 @@ wsproto = ">=0.14"
|
||||
|
||||
[[package]]
|
||||
name = "types-pillow"
|
||||
version = "10.2.0.20240423"
|
||||
version = "10.2.0.20240520"
|
||||
description = "Typing stubs for Pillow"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "types-Pillow-10.2.0.20240423.tar.gz", hash = "sha256:696e68b9b6a58548fc307a8669830469237c5b11809ddf978ac77fafa79251cd"},
|
||||
{file = "types_Pillow-10.2.0.20240423-py3-none-any.whl", hash = "sha256:bd12923093b96c91d523efcdb66967a307f1a843bcfaf2d5a529146c10a9ced3"},
|
||||
{file = "types-Pillow-10.2.0.20240520.tar.gz", hash = "sha256:130b979195465fa1e1676d8e81c9c7c30319e8e95b12fae945e8f0d525213107"},
|
||||
{file = "types_Pillow-10.2.0.20240520-py3-none-any.whl", hash = "sha256:33c36494b380e2a269bb742181bea5d9b00820367822dbd3760f07210a1da23d"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1761,13 +1765,13 @@ requests = "*"
|
||||
|
||||
[[package]]
|
||||
name = "werkzeug"
|
||||
version = "3.0.2"
|
||||
version = "3.0.3"
|
||||
description = "The comprehensive WSGI web application library."
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "werkzeug-3.0.2-py3-none-any.whl", hash = "sha256:3aac3f5da756f93030740bc235d3e09449efcf65f2f55e3602e1d851b8f48795"},
|
||||
{file = "werkzeug-3.0.2.tar.gz", hash = "sha256:e39b645a6ac92822588e7b39a692e7828724ceae0b0d702ef96701f90e70128d"},
|
||||
{file = "werkzeug-3.0.3-py3-none-any.whl", hash = "sha256:fc9645dc43e03e4d630d23143a04a7f947a9a3b5727cd535fdfe155a17cc48c8"},
|
||||
{file = "werkzeug-3.0.3.tar.gz", hash = "sha256:097e5bfda9f0aba8da6b8545146def481d06aa7d3266e7448e2cccf67dd8bd18"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
@@ -1792,20 +1796,20 @@ h11 = ">=0.9.0,<1"
|
||||
|
||||
[[package]]
|
||||
name = "zipp"
|
||||
version = "3.18.1"
|
||||
version = "3.18.2"
|
||||
description = "Backport of pathlib-compatible object wrapper for zip files"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "zipp-3.18.1-py3-none-any.whl", hash = "sha256:206f5a15f2af3dbaee80769fb7dc6f249695e940acca08dfb2a4769fe61e538b"},
|
||||
{file = "zipp-3.18.1.tar.gz", hash = "sha256:2884ed22e7d8961de1c9a05142eb69a247f120291bc0206a00a7642f09b5b715"},
|
||||
{file = "zipp-3.18.2-py3-none-any.whl", hash = "sha256:dce197b859eb796242b0622af1b8beb0a722d52aa2f57133ead08edd5bf5374e"},
|
||||
{file = "zipp-3.18.2.tar.gz", hash = "sha256:6278d9ddbcfb1f1089a88fde84481528b07b0e10474e09dcfe53dad4069fa059"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"]
|
||||
testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-ignore-flaky", "pytest-mypy", "pytest-ruff (>=0.2.1)"]
|
||||
testing = ["big-O", "jaraco.functools", "jaraco.itertools", "jaraco.test", "more-itertools", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-ignore-flaky", "pytest-mypy", "pytest-ruff (>=0.2.1)"]
|
||||
|
||||
[metadata]
|
||||
lock-version = "2.0"
|
||||
python-versions = "^3.12"
|
||||
content-hash = "6c4bb66c774e93a08e4180f3148942edf91e2b5620ea1f6c3e4c30045bb643e5"
|
||||
content-hash = "2db221a28d46b210a8fa0b78ad2fa3ac606a52052ad5e02b50d5b07db1e1c5b7"
|
||||
|
||||
+15
-10
@@ -5,20 +5,11 @@ description = ""
|
||||
authors = ["Brian Bjarke Jensen <[email protected]>"]
|
||||
readme = "README.md"
|
||||
packages = [
|
||||
{ include = "core" },
|
||||
{ include = "shared" },
|
||||
]
|
||||
|
||||
[tool.poetry.dependencies]
|
||||
python = "^3.12"
|
||||
gunicorn = "^21.2.0"
|
||||
python-dotenv = "^1.0.1"
|
||||
dash = "^2.15.0"
|
||||
dash-bootstrap-components = "^1.5.0"
|
||||
dash-mantine-components = "^0.12.1"
|
||||
pydantic = "^2.6.1"
|
||||
pillow = "^10.2.0"
|
||||
pymongo = "^4.6.1"
|
||||
dash-auth = "^2.2.0"
|
||||
|
||||
|
||||
[tool.poetry.group.test.dependencies]
|
||||
@@ -38,6 +29,20 @@ retry = "^0.9.2"
|
||||
torch = "^2.2.1"
|
||||
torchvision = "^0.17.1"
|
||||
|
||||
|
||||
[tool.poetry.group.shared.dependencies]
|
||||
pymongo = "^4.7.2"
|
||||
pydantic = "^2.6.1"
|
||||
pillow = "^10.2.0"
|
||||
|
||||
|
||||
[tool.poetry.group.web_ui.dependencies]
|
||||
dash = "^2.17.0"
|
||||
gunicorn = "^21.2.0"
|
||||
dash-bootstrap-components = "^1.5.0"
|
||||
dash-mantine-components = "^0.12.1"
|
||||
dash-auth = "^2.2.0"
|
||||
|
||||
[build-system]
|
||||
requires = ["poetry-core"]
|
||||
build-backend = "poetry.core.masonry.api"
|
||||
|
||||
+1
-1
@@ -12,7 +12,7 @@ from pydantic import BaseModel
|
||||
from pydantic import field_serializer
|
||||
from pydantic import field_validator
|
||||
|
||||
from core.dto import ModelData
|
||||
from shared.dto import ModelData
|
||||
|
||||
|
||||
class VisualCommunication(BaseModel):
|
||||
+2
-2
@@ -5,8 +5,8 @@ import logging
|
||||
|
||||
from pymongo.collection import Collection
|
||||
|
||||
from core.database import NoDocumentFoundException
|
||||
from core.database import VisualCommunication
|
||||
from shared.database import NoDocumentFoundException
|
||||
from shared.database import VisualCommunication
|
||||
|
||||
|
||||
def get_visual_communication(
|
||||
@@ -4,7 +4,7 @@ import logging
|
||||
|
||||
from pymongo.collection import Collection
|
||||
|
||||
from core.database import Dataset
|
||||
from shared.database import Dataset
|
||||
|
||||
|
||||
def save_dataset(
|
||||
@@ -21,7 +21,7 @@ def save_dataset(
|
||||
if __name__ == '__main__':
|
||||
from dotenv import load_dotenv
|
||||
load_dotenv('local.env')
|
||||
from core.database import list_names, connect
|
||||
from shared.database import list_names, connect
|
||||
# connect to database
|
||||
collection, db, client = connect()
|
||||
print(client.server_info())
|
||||
+1
-1
@@ -4,7 +4,7 @@ import logging
|
||||
|
||||
from pymongo.collection import Collection
|
||||
|
||||
from core.dto import ModelData
|
||||
from shared.dto import ModelData
|
||||
|
||||
|
||||
def upsert_annotation(
|
||||
+1
-1
@@ -4,7 +4,7 @@ import logging
|
||||
|
||||
from pymongo.collection import Collection
|
||||
|
||||
from core.dto import ModelData
|
||||
from shared.dto import ModelData
|
||||
|
||||
|
||||
def upsert_prediction(
|
||||
+1
-1
@@ -2,7 +2,7 @@ from __future__ import annotations
|
||||
|
||||
from pymongo.collection import Collection
|
||||
|
||||
from core.database import VisualCommunication
|
||||
from shared.database import VisualCommunication
|
||||
|
||||
|
||||
def upsert_visual_communication(
|
||||
@@ -0,0 +1,4 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from .check_env import check_env
|
||||
from .setup_logging import setup_logging
|
||||
@@ -0,0 +1,24 @@
|
||||
"""Definition of check_env function."""
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
|
||||
|
||||
def check_env() -> None:
|
||||
"""Check necessary environment variables are set."""
|
||||
necesasary_var_list = {
|
||||
'MONGO_HOST',
|
||||
'MONGO_DB',
|
||||
'MONGO_COLLECTION',
|
||||
'MONGO_USER',
|
||||
'MONGO_PASSWORD',
|
||||
'DASH_AUTH_USERNAME',
|
||||
'DASH_AUTH_PASSWORD',
|
||||
}
|
||||
for env_var in necesasary_var_list:
|
||||
# ensure env var set
|
||||
assert (
|
||||
env_var in os.environ
|
||||
), (
|
||||
f"environment variable not set: {env_var}"
|
||||
)
|
||||
@@ -0,0 +1,21 @@
|
||||
"""Definition of setup_logging function."""
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
import os
|
||||
|
||||
|
||||
def setup_logging() -> None:
|
||||
"""Setup logging."""
|
||||
requested_log_level = os.getenv('LOG_LEVEL', default='info')
|
||||
level = getattr(logging, requested_log_level.upper())
|
||||
fmt = (
|
||||
'%(asctime)s | '
|
||||
'%(levelname)s | '
|
||||
'%(filename)s | '
|
||||
'%(funcName)s | '
|
||||
'%(message)s'
|
||||
)
|
||||
datefmt = '%Y-%m-%d %H:%M:%S'
|
||||
logging.basicConfig(format=fmt, datefmt=datefmt, level=level)
|
||||
logging.debug('finished')
|
||||
@@ -2,7 +2,7 @@ from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
from core.database.classes import VisualCommunication
|
||||
from shared.database.classes import VisualCommunication
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -5,8 +5,8 @@ from pathlib import Path
|
||||
|
||||
from dotenv import load_dotenv
|
||||
|
||||
from core.database import connect
|
||||
from core.database import get_visual_communication
|
||||
from shared.database import connect
|
||||
from shared.database import get_visual_communication
|
||||
|
||||
if __name__ == '__main__':
|
||||
# prepare env vars
|
||||
|
||||
@@ -5,8 +5,8 @@ from pathlib import Path
|
||||
|
||||
from dotenv import load_dotenv
|
||||
|
||||
from core.database import connect
|
||||
from core.database.classes import VisualCommunication
|
||||
from shared.database import connect
|
||||
from shared.database.classes import VisualCommunication
|
||||
|
||||
if __name__ == '__main__':
|
||||
# prepare env vars
|
||||
|
||||
@@ -6,8 +6,8 @@ from pathlib import Path
|
||||
from dotenv import load_dotenv
|
||||
from pymongo.errors import DuplicateKeyError
|
||||
|
||||
from core.database import connect
|
||||
from core.database.classes import VisualCommunication
|
||||
from shared.database import connect
|
||||
from shared.database.classes import VisualCommunication
|
||||
|
||||
if __name__ == '__main__':
|
||||
# get list of image paths
|
||||
|
||||
@@ -5,8 +5,8 @@ from pathlib import Path
|
||||
from dotenv import load_dotenv
|
||||
from pymongo.errors import DuplicateKeyError
|
||||
|
||||
from core.database import connect
|
||||
from core.database import VisualCommunication
|
||||
from shared.database import connect
|
||||
from shared.database import VisualCommunication
|
||||
|
||||
if __name__ == '__main__':
|
||||
# get list of image paths
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from core.dto import ModelData
|
||||
from shared.dto import ModelData
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -6,9 +6,9 @@ from pathlib import Path
|
||||
|
||||
from dotenv import load_dotenv
|
||||
|
||||
from core.database import connect
|
||||
from core.database import upsert_prediction
|
||||
from core.database.classes import VisualCommunication
|
||||
from shared.database import connect
|
||||
from shared.database import upsert_prediction
|
||||
from shared.database.classes import VisualCommunication
|
||||
|
||||
if __name__ == '__main__':
|
||||
# setup logging
|
||||
|
||||
@@ -5,8 +5,8 @@ from pathlib import Path
|
||||
|
||||
from dotenv import load_dotenv
|
||||
|
||||
from core.database import connect
|
||||
from core.database import count_documents
|
||||
from shared.database import connect
|
||||
from shared.database import count_documents
|
||||
|
||||
if __name__ == '__main__':
|
||||
# prepare env vars
|
||||
|
||||
@@ -5,8 +5,8 @@ from pathlib import Path
|
||||
|
||||
from dotenv import load_dotenv
|
||||
|
||||
from core.database import connect
|
||||
from core.database import count_documents
|
||||
from shared.database import connect
|
||||
from shared.database import count_documents
|
||||
|
||||
if __name__ == '__main__':
|
||||
# prepare env vars
|
||||
|
||||
+3
-2
@@ -30,7 +30,8 @@ ENV PATH="${POETRY_HOME}/bin:$PATH"
|
||||
# install runtime dependencies
|
||||
WORKDIR ${APP_HOME}
|
||||
COPY poetry.lock pyproject.toml ./
|
||||
RUN --mount=type=cache,target=${POETRY_CACHE_DIR} poetry install --without model
|
||||
RUN --mount=type=cache,target=${POETRY_CACHE_DIR} poetry install \
|
||||
--with shared,web_ui
|
||||
|
||||
# final stage
|
||||
FROM python:3.12-slim-bookworm
|
||||
@@ -48,7 +49,7 @@ RUN mkdir -p /home/app && \
|
||||
|
||||
# add code while changing ownership
|
||||
WORKDIR $APP_HOME
|
||||
COPY --chown=app:app ./core ./core
|
||||
COPY --chown=app:app ./shared ./shared
|
||||
COPY --chown=app:app ./web_ui/src ./src
|
||||
|
||||
# change to the app user
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
services:
|
||||
web:
|
||||
image: visual_critical_discourse_analysis:test
|
||||
container_name: visual_critical_discourse_analysis_alone
|
||||
build:
|
||||
context: ../
|
||||
dockerfile: ./web_ui/Dockerfile
|
||||
ports:
|
||||
- 8050:8050
|
||||
env_file:
|
||||
- ../server.env
|
||||
environment:
|
||||
- ENV=TEST
|
||||
@@ -1,3 +1,3 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from .app import app
|
||||
from .init_app import init_app
|
||||
|
||||
@@ -1,251 +0,0 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
import os
|
||||
|
||||
import dash_bootstrap_components as dbc
|
||||
from dash import ALL
|
||||
from dash import Dash
|
||||
from dash import Input
|
||||
from dash import Output
|
||||
from dash import State
|
||||
from dash_auth import BasicAuth
|
||||
from pydantic import ValidationError
|
||||
|
||||
from .layout import app_layout
|
||||
from core.database import connect
|
||||
from core.database import count_documents
|
||||
from core.database import get_visual_communication
|
||||
from core.database import NoDocumentFoundException
|
||||
from core.database import upsert_annotation
|
||||
from core.database import upsert_visual_communication
|
||||
from core.database import VisualCommunication
|
||||
from core.dto import ModelData
|
||||
|
||||
# setup app
|
||||
app = Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP])
|
||||
app.title = 'visual critical discourse analysis'.title()
|
||||
app.layout = app_layout
|
||||
server = app.server
|
||||
|
||||
# setup authentication
|
||||
AUTH_DICT = {
|
||||
os.getenv('DASH_AUTH_USERNAME'): os.getenv('DASH_AUTH_PASSWORD'),
|
||||
}
|
||||
BasicAuth(app, AUTH_DICT)
|
||||
|
||||
# connect to database
|
||||
collection, db, client = connect()
|
||||
|
||||
|
||||
# define callbacks
|
||||
@app.callback(
|
||||
Output('alert-element', 'is_open'),
|
||||
Output('alert-element', 'children'),
|
||||
Input('alert-message', 'data'),
|
||||
)
|
||||
def show_alert(
|
||||
msg: str | None,
|
||||
):
|
||||
if msg is None or msg == '':
|
||||
return False, ''
|
||||
logging.info(f'updated alert message: {msg}')
|
||||
return True, msg
|
||||
|
||||
|
||||
@app.callback(
|
||||
Output('success-element', 'is_open'),
|
||||
Output('success-element', 'children'),
|
||||
Input('success-message', 'data'),
|
||||
)
|
||||
def show_success(
|
||||
msg: str | None,
|
||||
):
|
||||
if msg is None or msg == '':
|
||||
return False, ''
|
||||
logging.info(f"updated success message: {msg}")
|
||||
return True, msg
|
||||
|
||||
|
||||
@app.callback(
|
||||
Output('progress-bar', 'value'),
|
||||
Output('progress-bar', 'max'),
|
||||
Output('progress-bar', 'label'),
|
||||
Input('next-button', 'n_clicks'),
|
||||
Input('upload-data', 'filename'),
|
||||
)
|
||||
def update_progress_bar(
|
||||
n_clicks: int,
|
||||
filename_list: list[str] | None,
|
||||
):
|
||||
logging.info('began updating progress bar')
|
||||
global collection
|
||||
# get values from database
|
||||
num_total = count_documents(
|
||||
collection=collection,
|
||||
only_with_annotation=False,
|
||||
)
|
||||
num_handled = count_documents(
|
||||
collection=collection,
|
||||
only_with_annotation=True,
|
||||
)
|
||||
limit = int(num_total/20)
|
||||
label_str = f"{num_handled}/{num_total}" if num_handled >= limit else ''
|
||||
return num_handled, num_total, label_str
|
||||
|
||||
|
||||
@app.callback(
|
||||
Output('success-message', 'data', allow_duplicate=True),
|
||||
Output('alert-message', 'data', allow_duplicate=True),
|
||||
Input('upload-data', 'contents'),
|
||||
State('upload-data', 'filename'),
|
||||
prevent_initial_call=True,
|
||||
)
|
||||
def upload_images(
|
||||
content_list: list[str] | None,
|
||||
filename_list: list[str] | None,
|
||||
):
|
||||
logging.info('began uploading images')
|
||||
global collection
|
||||
# stop early if possible
|
||||
if content_list is None or filename_list is None:
|
||||
logging.warning('content_list is None -> nothing to upload')
|
||||
return None, 'nothing selected to upload'.title()
|
||||
# build list of visual communication
|
||||
visual_communication_list = []
|
||||
for content, filename in zip(content_list, filename_list):
|
||||
try:
|
||||
image = VisualCommunication.decode_image(content)
|
||||
vis_com = VisualCommunication(
|
||||
name=filename,
|
||||
image=image,
|
||||
)
|
||||
except Exception as exc:
|
||||
logging.warning(
|
||||
(
|
||||
'failed creating VisualCommunication object '
|
||||
f"from file {filename}"
|
||||
),
|
||||
exc,
|
||||
)
|
||||
else:
|
||||
visual_communication_list.append(vis_com)
|
||||
# upsert documents
|
||||
success = upsert_visual_communication(
|
||||
collection=collection,
|
||||
visual_communication_list=visual_communication_list,
|
||||
)
|
||||
if success:
|
||||
logging.info(f"succesfully uploaded {len(filename_list)} images")
|
||||
return 'successfully uploaded images'.title(), None
|
||||
logging.warning('failed inserting images into database')
|
||||
return None, 'failed uploading images'.title()
|
||||
|
||||
|
||||
@app.callback(
|
||||
Output('alert-message', 'data', allow_duplicate=True),
|
||||
Output('vis-com-name', 'data'),
|
||||
Output('image-container', 'src'),
|
||||
Output({'type': 'annotation', 'index': ALL}, 'value'),
|
||||
Input('next-button', 'n_clicks'),
|
||||
State('vis-com-name', 'data'),
|
||||
State('image-container', 'src'),
|
||||
State({'type': 'annotation', 'index': ALL}, 'id'),
|
||||
State({'type': 'annotation', 'index': ALL}, 'value'),
|
||||
prevent_initial_call=True,
|
||||
)
|
||||
def cycle_visual_communication_data(
|
||||
n_clicks: int,
|
||||
vis_com_name: str,
|
||||
image_src: str,
|
||||
annotation_keys: list,
|
||||
annotation_values: list,
|
||||
):
|
||||
logging.info('began cycling visual communication data')
|
||||
global collection
|
||||
# prepare default response
|
||||
response = [
|
||||
'',
|
||||
vis_com_name,
|
||||
image_src,
|
||||
annotation_values,
|
||||
]
|
||||
# check if next-button clicked
|
||||
if n_clicks == 0:
|
||||
logging.info('stopping early: next-button has not yet been clicked')
|
||||
return response
|
||||
# check if visual communication name is set
|
||||
if len(vis_com_name) > 0:
|
||||
logging.info('saving annotations to database: %s', vis_com_name)
|
||||
try:
|
||||
# extract option keys
|
||||
annotation_keys = [
|
||||
elem['index']
|
||||
for elem in annotation_keys
|
||||
]
|
||||
# ensure all options are set
|
||||
logging.info(annotation_keys)
|
||||
for option, value in zip(annotation_keys, annotation_values):
|
||||
if value is None:
|
||||
raise ValueError(f"{option} is not set")
|
||||
# prepare data to save
|
||||
annotation_keys = [
|
||||
elem.replace(' ', '_')
|
||||
for elem
|
||||
in annotation_keys
|
||||
]
|
||||
annotation_values = [
|
||||
elem.replace(' ', '_').lower()
|
||||
for elem
|
||||
in annotation_values
|
||||
]
|
||||
annotation_map = {
|
||||
key: value
|
||||
for key, value
|
||||
in zip(annotation_keys, annotation_values)
|
||||
}
|
||||
# instantiate ModelOutputs object
|
||||
annotations = ModelData.from_annotations(**annotation_map)
|
||||
# save data to database
|
||||
upsert_annotation(
|
||||
collection=collection,
|
||||
vis_com_name=vis_com_name,
|
||||
annotations=annotations,
|
||||
)
|
||||
except (ValueError, ValidationError) as exc:
|
||||
msg = f"failed saving annotation: {exc}"
|
||||
logging.warning(msg)
|
||||
response[0] = msg
|
||||
return tuple(response)
|
||||
# get new visual communication
|
||||
logging.info('trying to get new visual communication')
|
||||
try:
|
||||
# get data
|
||||
vis_com = get_visual_communication(
|
||||
collection=collection,
|
||||
with_annotation=False,
|
||||
)
|
||||
# set variables
|
||||
vis_com_name = vis_com.name
|
||||
image_src = vis_com.webencoded_image()
|
||||
if vis_com.prediction is not None:
|
||||
# TODO: update to use optional predictions
|
||||
pass
|
||||
else:
|
||||
# reset annotations
|
||||
annotation_values = [None for elem in annotation_values]
|
||||
except NoDocumentFoundException:
|
||||
msg = 'no unannotated data in database'
|
||||
logging.warning(msg)
|
||||
response[0] = msg
|
||||
return tuple(response)
|
||||
else:
|
||||
response[1] = vis_com_name
|
||||
response[2] = image_src
|
||||
response[3] = annotation_values
|
||||
logging.info('finished getting visual communication: %s', vis_com_name)
|
||||
return tuple(response)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
app.run(debug=True)
|
||||
@@ -0,0 +1,260 @@
|
||||
"""Definition of init_app function."""
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
import os
|
||||
|
||||
import dash_bootstrap_components as dbc
|
||||
from dash import ALL
|
||||
from dash import Dash
|
||||
from dash import Input
|
||||
from dash import Output
|
||||
from dash import State
|
||||
from dash_auth import BasicAuth
|
||||
from pydantic import ValidationError
|
||||
from pymongo.collection import Collection
|
||||
|
||||
from .layout import app_layout
|
||||
from shared.database import count_documents
|
||||
from shared.database import get_visual_communication
|
||||
from shared.database import NoDocumentFoundException
|
||||
from shared.database import upsert_annotation
|
||||
from shared.database import upsert_visual_communication
|
||||
from shared.database import VisualCommunication
|
||||
from shared.dto import ModelData
|
||||
|
||||
|
||||
def init_app(
|
||||
collection: Collection,
|
||||
) -> Dash:
|
||||
"""Initialise web UI application."""
|
||||
# setup app
|
||||
app = Dash(
|
||||
name='visual_critical_discourse_analysis_web_ui',
|
||||
external_stylesheets=[
|
||||
dbc.themes.BOOTSTRAP,
|
||||
],
|
||||
)
|
||||
app.title = 'visual critical discourse analysis'.title()
|
||||
app.layout = app_layout
|
||||
|
||||
# setup authentication
|
||||
auth_dict = {
|
||||
os.getenv('DASH_AUTH_USERNAME'): os.getenv('DASH_AUTH_PASSWORD'),
|
||||
}
|
||||
BasicAuth(app, auth_dict)
|
||||
|
||||
# define callback: show warning
|
||||
@app.callback(
|
||||
Output('warning-element', 'is_open'),
|
||||
Output('warning-element', 'children'),
|
||||
Input('warning-message', 'data'),
|
||||
)
|
||||
def show_warning(
|
||||
msg: str | None,
|
||||
) -> tuple[bool, str]:
|
||||
"""Show warning message in web ui."""
|
||||
if msg is None or msg == '':
|
||||
return False, ''
|
||||
logging.debug('updated warning message: %s', msg)
|
||||
return True, msg
|
||||
|
||||
# define callback: show info
|
||||
@app.callback(
|
||||
Output('info-element', 'is_open'),
|
||||
Output('info-element', 'children'),
|
||||
Input('info-message', 'data'),
|
||||
)
|
||||
def show_info(
|
||||
msg: str | None,
|
||||
) -> tuple[bool, str]:
|
||||
"""Show info message in web ui."""
|
||||
if msg is None or msg == '':
|
||||
return False, ''
|
||||
logging.debug('updated info message: %s', msg)
|
||||
return True, msg
|
||||
|
||||
# define callback: update progress bar
|
||||
@app.callback(
|
||||
Output('progress-bar', 'value'),
|
||||
Output('progress-bar', 'max'),
|
||||
Output('progress-bar', 'label'),
|
||||
Input('next-button', 'n_clicks'),
|
||||
Input('upload-data', 'filename'),
|
||||
)
|
||||
def update_progress_bar(
|
||||
n_clicks: int,
|
||||
filename_list: list[str] | None,
|
||||
) -> tuple[int, int, str]:
|
||||
"""Update progress bar in web ui."""
|
||||
assert isinstance(n_clicks, int)
|
||||
if filename_list is not None:
|
||||
assert isinstance(filename_list, list)
|
||||
# get values from database
|
||||
num_total = count_documents(
|
||||
collection=collection,
|
||||
only_with_annotation=False,
|
||||
)
|
||||
num_handled = count_documents(
|
||||
collection=collection,
|
||||
only_with_annotation=True,
|
||||
)
|
||||
limit = int(num_total/20)
|
||||
label_str = f"{
|
||||
num_handled
|
||||
}/{num_total}" if num_handled >= limit else ''
|
||||
return num_handled, num_total, label_str
|
||||
|
||||
# define callback: upload image
|
||||
@app.callback(
|
||||
Output('info-message', 'data', allow_duplicate=True),
|
||||
Output('warning-message', 'data', allow_duplicate=True),
|
||||
Input('upload-data', 'contents'),
|
||||
State('upload-data', 'filename'),
|
||||
prevent_initial_call=True,
|
||||
)
|
||||
def upload_images(
|
||||
content_list: list[str] | None,
|
||||
filename_list: list[str] | None,
|
||||
) -> tuple[str | None, str | None]:
|
||||
"""Upload image to database through web ui."""
|
||||
# stop early if possible
|
||||
if content_list is None or filename_list is None:
|
||||
logging.info('nothing to upload.')
|
||||
return None, 'nothing to upload'.title()
|
||||
# build list of visual communication
|
||||
vis_com_list = []
|
||||
for content, filename in zip(content_list, filename_list):
|
||||
try:
|
||||
image = VisualCommunication.decode_image(content=content)
|
||||
vis_com = VisualCommunication(
|
||||
name=filename,
|
||||
image=image,
|
||||
)
|
||||
except Exception as exc:
|
||||
logging.error('failed handling data from file: %s', filename)
|
||||
logging.debug(exc)
|
||||
continue
|
||||
vis_com_list.append(vis_com)
|
||||
# upsert documents
|
||||
success = upsert_visual_communication(
|
||||
collection=collection,
|
||||
visual_communication_list=vis_com_list,
|
||||
)
|
||||
if success:
|
||||
logging.info('uploaded %s files to database', len(vis_com_list))
|
||||
return 'successfully uploaded images'.title(), None
|
||||
logging.error('failed uploading images to database')
|
||||
return None, 'failed uploading images'.title()
|
||||
|
||||
# define callback: cycle visual communication data
|
||||
@app.callback(
|
||||
Output('warning-message', 'data', allow_duplicate=True),
|
||||
Output('vis-com-name', 'data'),
|
||||
Output('image-container', 'src'),
|
||||
Output({'type': 'annotation', 'index': ALL}, 'value'),
|
||||
Input('next-button', 'n_clicks'),
|
||||
State('vis-com-name', 'data'),
|
||||
State('image-container', 'src'),
|
||||
State({'type': 'annotation', 'index': ALL}, 'id'),
|
||||
State({'type': 'annotation', 'index': ALL}, 'value'),
|
||||
prevent_initial_call=True,
|
||||
)
|
||||
def cycle_vis_com_data(
|
||||
n_clicks: int,
|
||||
vis_com_name: str,
|
||||
image_src: str,
|
||||
annotation_keys: list,
|
||||
annotation_values: list,
|
||||
) -> tuple:
|
||||
"""Cycle visual communcation data."""
|
||||
assert isinstance(n_clicks, int)
|
||||
assert isinstance(vis_com_name, str)
|
||||
assert isinstance(image_src, str)
|
||||
assert isinstance(annotation_keys, list)
|
||||
assert isinstance(annotation_values, list)
|
||||
# prepare default response
|
||||
response = [
|
||||
'',
|
||||
vis_com_name,
|
||||
image_src,
|
||||
annotation_values,
|
||||
]
|
||||
# stop early if possible
|
||||
if n_clicks == 0:
|
||||
return tuple(response)
|
||||
# check if visual communication name is set
|
||||
if len(vis_com_name) > 0:
|
||||
logging.info('saving annotations to database: %s', vis_com_name)
|
||||
try:
|
||||
# extract option keys
|
||||
annotation_keys = [
|
||||
elem['index']
|
||||
for elem in annotation_keys
|
||||
]
|
||||
# ensure all options are set
|
||||
logging.info(annotation_keys)
|
||||
for option, value in zip(annotation_keys, annotation_values):
|
||||
if value is None:
|
||||
raise ValueError(f"{option} is not set")
|
||||
# prepare data to save
|
||||
annotation_keys = [
|
||||
elem.replace(' ', '_')
|
||||
for elem
|
||||
in annotation_keys
|
||||
]
|
||||
annotation_values = [
|
||||
elem.replace(' ', '_').lower()
|
||||
for elem
|
||||
in annotation_values
|
||||
]
|
||||
annotation_map = {
|
||||
key: value
|
||||
for key, value
|
||||
in zip(annotation_keys, annotation_values)
|
||||
}
|
||||
# instantiate ModelOutputs object
|
||||
annotations = ModelData.from_annotations(**annotation_map)
|
||||
# save data to database
|
||||
upsert_annotation(
|
||||
collection=collection,
|
||||
vis_com_name=vis_com_name,
|
||||
annotations=annotations,
|
||||
)
|
||||
except (ValueError, ValidationError) as exc:
|
||||
msg = f"failed saving annotation: {exc}"
|
||||
logging.warning(msg)
|
||||
response[0] = msg
|
||||
return tuple(response)
|
||||
# get new visual communication
|
||||
logging.info('trying to get new visual communication')
|
||||
try:
|
||||
# get data
|
||||
vis_com = get_visual_communication(
|
||||
collection=collection,
|
||||
with_annotation=False,
|
||||
)
|
||||
# set variables
|
||||
vis_com_name = vis_com.name
|
||||
image_src = vis_com.webencoded_image()
|
||||
if vis_com.prediction is not None:
|
||||
# TODO: update to use optional predictions
|
||||
pass
|
||||
else:
|
||||
# reset annotations
|
||||
annotation_values = [None for elem in annotation_values]
|
||||
except NoDocumentFoundException:
|
||||
msg = 'no unannotated data in database'
|
||||
logging.warning(msg)
|
||||
response[0] = msg
|
||||
return tuple(response)
|
||||
else:
|
||||
response[1] = vis_com_name
|
||||
response[2] = image_src
|
||||
response[3] = annotation_values
|
||||
logging.info(
|
||||
'finished getting visual communication: %s', vis_com_name,
|
||||
)
|
||||
return tuple(response)
|
||||
logging.info('initialised app')
|
||||
return app
|
||||
@@ -4,17 +4,17 @@ import dash_mantine_components as dmc
|
||||
from dash import dcc
|
||||
from dash import html
|
||||
|
||||
from core.dto import AngleData
|
||||
from core.dto import ContactData
|
||||
from core.dto import DistanceData
|
||||
from core.dto import FramingData
|
||||
from core.dto import InformationValueData
|
||||
from core.dto import ModalityColorData
|
||||
from core.dto import ModalityDepthData
|
||||
from core.dto import ModalityLightingData
|
||||
from core.dto import PointOfViewData
|
||||
from core.dto import SalienceData
|
||||
from core.dto import VisualSyntaxData
|
||||
from shared.dto import AngleData
|
||||
from shared.dto import ContactData
|
||||
from shared.dto import DistanceData
|
||||
from shared.dto import FramingData
|
||||
from shared.dto import InformationValueData
|
||||
from shared.dto import ModalityColorData
|
||||
from shared.dto import ModalityDepthData
|
||||
from shared.dto import ModalityLightingData
|
||||
from shared.dto import PointOfViewData
|
||||
from shared.dto import SalienceData
|
||||
from shared.dto import VisualSyntaxData
|
||||
|
||||
|
||||
def generate_visual_syntax_options_map():
|
||||
|
||||
@@ -6,8 +6,8 @@ from dash import html
|
||||
|
||||
stores_element = html.Div(
|
||||
children=[
|
||||
dcc.Store(id='alert-message', data=''),
|
||||
dcc.Store(id='success-message', data=''),
|
||||
dcc.Store(id='warning-message', data=''),
|
||||
dcc.Store(id='info-message', data=''),
|
||||
dcc.Store(id='vis-com-name', data=''),
|
||||
],
|
||||
)
|
||||
|
||||
+12
-42
@@ -1,53 +1,23 @@
|
||||
"""Definition of web_ui main script."""
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
from dotenv import load_dotenv
|
||||
|
||||
from .app import app
|
||||
|
||||
# prepare optional local setup
|
||||
env_path = Path(__file__).parent.parent.parent / 'local.env'
|
||||
load_dotenv(env_path)
|
||||
from .app import init_app
|
||||
from shared.database import connect
|
||||
from shared.utils import check_env
|
||||
from shared.utils import setup_logging
|
||||
|
||||
# ensure env vars set
|
||||
necesasary_var_list = {
|
||||
'MONGO_HOST',
|
||||
'MONGO_DB',
|
||||
'MONGO_COLLECTION',
|
||||
'MONGO_USER',
|
||||
'MONGO_PASSWORD',
|
||||
'DASH_AUTH_USERNAME',
|
||||
'DASH_AUTH_PASSWORD',
|
||||
}
|
||||
for env_var in necesasary_var_list:
|
||||
# ensure env var set
|
||||
assert (
|
||||
env_var in os.environ
|
||||
), (
|
||||
f"environment variable not set: {env_var}"
|
||||
)
|
||||
check_env()
|
||||
|
||||
# setup logging stream handler
|
||||
FMT = (
|
||||
'%(asctime)s | '
|
||||
'%(levelname)s | '
|
||||
'%(filename)s | '
|
||||
'%(funcName)s | '
|
||||
'%(message)s'
|
||||
)
|
||||
DATEFMT = '%Y-%m-%d %H:%M:%S'
|
||||
logging.basicConfig(format=FMT, datefmt=DATEFMT, level=logging.INFO)
|
||||
setup_logging()
|
||||
|
||||
logging.info('initialized app')
|
||||
# connect to database
|
||||
collection, db, client = connect()
|
||||
|
||||
# initialise application
|
||||
app = init_app(collection=collection)
|
||||
server = app.server
|
||||
server.config.update(SECRET_KEY=os.urandom(24))
|
||||
|
||||
if __name__ == '__main__':
|
||||
# prepare local env vars
|
||||
os.environ['MONGO_HOST'] = 'localhost'
|
||||
# run app
|
||||
app.run(debug=True)
|
||||
logging.info('started app')
|
||||
|
||||
Reference in New Issue
Block a user