From 69ba87148127326ed511a4e18aa3b3729a6898f0 Mon Sep 17 00:00:00 2001 From: Mathieu Virbel Date: Thu, 27 Jul 2023 15:29:41 +0200 Subject: [PATCH] server: refactor to reflector module - replaced loguru to structlog, to get ability of having open tracing later - moved configuration to pydantic-settings - merged both secrets.ini and config.ini to .env (check reflector/settings.py) --- .env | 1 + server/Dockerfile | 5 +- server/README.md | 4 +- server/pipeline-requirements.txt | 61 ---- server/poetry.lock | 271 +++++++++++++++++- server/pyproject.toml | 8 + server/{ => reflector}/client.py | 14 +- server/reflector/logger.py | 3 + .../models.py} | 4 +- server/{ => reflector}/server.py | 92 +++--- server/reflector/settings.py | 45 +++ server/{ => reflector}/stream_client.py | 8 +- server/{ => reflector/utils}/__init__.py | 0 server/{ => reflector}/utils/file_utils.py | 0 server/{ => reflector}/utils/format_output.py | 0 server/{ => reflector}/utils/run_utils.py | 36 --- server/{ => reflector}/utils/text_utils.py | 0 server/{ => reflector}/utils/viz_utils.py | 0 server/server-requirements.txt | 50 ---- .../whisper-jax}/agenda-headers.txt | 0 server/utils/__init__.py | 0 server/utils/config.ini | 25 -- server/utils/log_utils.py | 27 -- server/utils/secrets.ini.example | 14 - 24 files changed, 385 insertions(+), 283 deletions(-) create mode 100644 .env delete mode 100644 server/pipeline-requirements.txt rename server/{ => reflector}/client.py (82%) create mode 100644 server/reflector/logger.py rename server/{reflector_dataclasses.py => reflector/models.py} (98%) rename server/{ => reflector}/server.py (84%) create mode 100644 server/reflector/settings.py rename server/{ => reflector}/stream_client.py (95%) rename server/{ => reflector/utils}/__init__.py (100%) rename server/{ => reflector}/utils/file_utils.py (100%) rename server/{ => reflector}/utils/format_output.py (100%) rename server/{ => reflector}/utils/run_utils.py (61%) rename server/{ => reflector}/utils/text_utils.py (100%) rename server/{ => reflector}/utils/viz_utils.py (100%) delete mode 100644 server/server-requirements.txt rename server/{ => trials/whisper-jax}/agenda-headers.txt (100%) delete mode 100644 server/utils/__init__.py delete mode 100644 server/utils/config.ini delete mode 100644 server/utils/log_utils.py delete mode 100644 server/utils/secrets.ini.example diff --git a/.env b/.env new file mode 100644 index 00000000..81193fba --- /dev/null +++ b/.env @@ -0,0 +1 @@ +LLM_URL=http://216.153.52.83:7860/api/v1/generate diff --git a/server/Dockerfile b/server/Dockerfile index 470b431c..248bea9b 100644 --- a/server/Dockerfile +++ b/server/Dockerfile @@ -24,7 +24,6 @@ RUN . /venv/bin/activate && poetry install --only main --no-root --no-interactio FROM base AS final COPY --from=builder /venv /venv RUN mkdir -p /app -COPY server.py reflector_dataclasses.py /app/ -COPY utils /app/utils +COPY reflector /app/reflector WORKDIR /app -CMD ["/venv/bin/python", "server.py"] +CMD ["/venv/bin/python", "-m", "reflector.server"] diff --git a/server/README.md b/server/README.md index bd43ac2e..c3004bcb 100644 --- a/server/README.md +++ b/server/README.md @@ -33,12 +33,12 @@ Then run the server: ``` # With a config.ini -$ poetry run python server.py +$ poetry run python -m reflector.server # Within a poetry env $ poetry shell -$ LLM_URL=http://.../api/v1/generate python server.py +$ LLM_URL=http://.../api/v1/generate python -m reflector.server ``` diff --git a/server/pipeline-requirements.txt b/server/pipeline-requirements.txt deleted file mode 100644 index 9a0ffc57..00000000 --- a/server/pipeline-requirements.txt +++ /dev/null @@ -1,61 +0,0 @@ -pyaudio==0.2.13 -keyboard==0.13.5 -pynput==1.7.6 -wave==0.0.2 -async-timeout==4.0.2 -attrs==23.1.0 -certifi==2023.5.7 -charset-normalizer==3.1.0 -decorator==4.4.2 -filelock==3.12.0 -frozenlist==1.3.3 -idna==3.4 -imageio==2.29.0 -imageio-ffmpeg==0.4.8 -Jinja2==3.1.2 -llvmlite==0.40.0 -loguru==0.7.0 -MarkupSafe==2.1.2 -more-itertools==9.1.0 -moviepy==1.0.3 -mpmath==1.3.0 -multidict==6.0.4 -networkx==3.1 -numba==0.57.0 -numpy==1.24.3 -openai==0.27.7 -openai-whisper@ git+https://github.com/openai/whisper.git@248b6cb124225dd263bb9bd32d060b6517e067f8 -Pillow==9.5.0 -proglog==0.1.10 -pytube==15.0.0 -regex==2023.5.5 -six==1.16.0 -sympy==1.12 -tiktoken==0.3.3 -torch==2.0.1 -tqdm==4.65.0 -typing_extensions==4.6.2 -urllib3 -yarl==1.9.2 -boto3==1.26.151 -nltk==3.8.1 -wordcloud==1.9.2 -spacy==3.5.4 -scattertext==0.1.19 -pandas==2.0.3 -jupyter==1.0.0 -seaborn==0.12.2 -matplotlib==3.7.2 -matplotlib-inline==0.1.6 -termcolor==2.3.0 -ffmpeg==1.4 -cached_property==1.5.2 -stamina==23.1.0 -httpx==0.24.1 -https://github.com/yt-dlp/yt-dlp/archive/master.tar.gz -gpt4all==1.0.5 -aiohttp==3.8.5 -aiohttp-cors==0.7.0 -aioice==0.9.0 -aiortc==1.5.0 -aiosignal==1.3.1 \ No newline at end of file diff --git a/server/poetry.lock b/server/poetry.lock index 56e0e183..d9157b1c 100644 --- a/server/poetry.lock +++ b/server/poetry.lock @@ -223,6 +223,17 @@ files = [ [package.dependencies] frozenlist = ">=1.1.0" +[[package]] +name = "annotated-types" +version = "0.5.0" +description = "Reusable constraint types to use with typing.Annotated" +optional = false +python-versions = ">=3.7" +files = [ + {file = "annotated_types-0.5.0-py3-none-any.whl", hash = "sha256:58da39888f92c276ad970249761ebea80ba544b77acddaa1a4d6cf78287d45fd"}, + {file = "annotated_types-0.5.0.tar.gz", hash = "sha256:47cdc3490d9ac1506ce92c7aaa76c579dc3509ff11e098fc867e5130ab7be802"}, +] + [[package]] name = "anyio" version = "3.7.1" @@ -952,6 +963,29 @@ sniffio = "==1.*" http2 = ["h2 (>=3,<5)"] socks = ["socksio (==1.*)"] +[[package]] +name = "httpx" +version = "0.24.1" +description = "The next generation HTTP client." +optional = false +python-versions = ">=3.7" +files = [ + {file = "httpx-0.24.1-py3-none-any.whl", hash = "sha256:06781eb9ac53cde990577af654bd990a4949de37a28bdb4a230d434f3a30b9bd"}, + {file = "httpx-0.24.1.tar.gz", hash = "sha256:5853a43053df830c20f8110c5e69fe44d035d850b2dfe795e196f00fdb774bdd"}, +] + +[package.dependencies] +certifi = "*" +httpcore = ">=0.15.0,<0.18.0" +idna = "*" +sniffio = "*" + +[package.extras] +brotli = ["brotli", "brotlicffi"] +cli = ["click (==8.*)", "pygments (==2.*)", "rich (>=10,<14)"] +http2 = ["h2 (>=3,<5)"] +socks = ["socksio (==1.*)"] + [[package]] name = "huggingface-hub" version = "0.16.4" @@ -1283,6 +1317,29 @@ files = [ {file = "protobuf-4.23.4.tar.gz", hash = "sha256:ccd9430c0719dce806b93f89c91de7977304729e55377f872a92465d548329a9"}, ] +[[package]] +name = "pyaudio" +version = "0.2.13" +description = "Cross-platform audio I/O with PortAudio" +optional = false +python-versions = "*" +files = [ + {file = "PyAudio-0.2.13-cp310-cp310-win32.whl", hash = "sha256:48e29537ea22ae2ae323eebe297bfb2683831cee4f20d96964e131f65ab2161d"}, + {file = "PyAudio-0.2.13-cp310-cp310-win_amd64.whl", hash = "sha256:87137cfd0ef8608a2a383be3f6996f59505e322dab9d16531f14cf542fa294f1"}, + {file = "PyAudio-0.2.13-cp311-cp311-win32.whl", hash = "sha256:13915faaa780e6bbbb6d745ef0e761674fd461b1b1b3f9c1f57042a534bfc0c3"}, + {file = "PyAudio-0.2.13-cp311-cp311-win_amd64.whl", hash = "sha256:59cc3cc5211b729c7854e3989058a145872cc58b1a7b46c6d4d88448a343d890"}, + {file = "PyAudio-0.2.13-cp37-cp37m-win32.whl", hash = "sha256:d294e3f85b2238649b1ff49ce3412459a8a312569975a89d14646536362d7576"}, + {file = "PyAudio-0.2.13-cp37-cp37m-win_amd64.whl", hash = "sha256:ff7f5e44ef51fe61da1e09c6f632f0b5808198edd61b363855cc7dd03bf4a8ac"}, + {file = "PyAudio-0.2.13-cp38-cp38-win32.whl", hash = "sha256:c6b302b048c054b7463936d8ba884b73877dc47012f3c94665dba92dd658ae04"}, + {file = "PyAudio-0.2.13-cp38-cp38-win_amd64.whl", hash = "sha256:1505d766ee718df6f5a18b73ac42307ba1cb4d2c0397873159254a34f67515d6"}, + {file = "PyAudio-0.2.13-cp39-cp39-win32.whl", hash = "sha256:eb128e4a6ea9b98d9a31f33c44978885af27dbe8ae53d665f8790cbfe045517e"}, + {file = "PyAudio-0.2.13-cp39-cp39-win_amd64.whl", hash = "sha256:910ef09225cce227adbba92622d4a3e3c8375117f7dd64039f287d9ffc0e02a1"}, + {file = "PyAudio-0.2.13.tar.gz", hash = "sha256:26bccc81e4243d1c0ff5487e6b481de6329fcd65c79365c267cef38f363a2b56"}, +] + +[package.extras] +test = ["numpy"] + [[package]] name = "pycparser" version = "2.21" @@ -1294,6 +1351,153 @@ files = [ {file = "pycparser-2.21.tar.gz", hash = "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206"}, ] +[[package]] +name = "pydantic" +version = "2.1.1" +description = "Data validation using Python type hints" +optional = false +python-versions = ">=3.7" +files = [ + {file = "pydantic-2.1.1-py3-none-any.whl", hash = "sha256:43bdbf359d6304c57afda15c2b95797295b702948082d4c23851ce752f21da70"}, + {file = "pydantic-2.1.1.tar.gz", hash = "sha256:22d63db5ce4831afd16e7c58b3192d3faf8f79154980d9397d9867254310ba4b"}, +] + +[package.dependencies] +annotated-types = ">=0.4.0" +pydantic-core = "2.4.0" +typing-extensions = ">=4.6.1" + +[package.extras] +email = ["email-validator (>=2.0.0)"] + +[[package]] +name = "pydantic-core" +version = "2.4.0" +description = "" +optional = false +python-versions = ">=3.7" +files = [ + {file = "pydantic_core-2.4.0-cp310-cp310-macosx_10_7_x86_64.whl", hash = "sha256:2ca4687dd996bde7f3c420def450797feeb20dcee2b9687023e3323c73fc14a2"}, + {file = "pydantic_core-2.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:782fced7d61469fd1231b184a80e4f2fa7ad54cd7173834651a453f96f29d673"}, + {file = "pydantic_core-2.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6213b471b68146af97b8551294e59e7392c2117e28ffad9c557c65087f4baee3"}, + {file = "pydantic_core-2.4.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:63797499a219d8e81eb4e0c42222d0a4c8ec896f5c76751d4258af95de41fdf1"}, + {file = "pydantic_core-2.4.0-cp310-cp310-manylinux_2_24_armv7l.whl", hash = "sha256:0455876d575a35defc4da7e0a199596d6c773e20d3d42fa1fc29f6aa640369ed"}, + {file = "pydantic_core-2.4.0-cp310-cp310-manylinux_2_24_ppc64le.whl", hash = "sha256:8c938c96294d983dcf419b54dba2d21056959c22911d41788efbf949a29ae30d"}, + {file = "pydantic_core-2.4.0-cp310-cp310-manylinux_2_24_s390x.whl", hash = "sha256:878a5017d93e776c379af4e7b20f173c82594d94fa073059bcc546789ad50bf8"}, + {file = "pydantic_core-2.4.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:69159afc2f2dc43285725f16143bc5df3c853bc1cb7df6021fce7ef1c69e8171"}, + {file = "pydantic_core-2.4.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:54df7df399b777c1fd144f541c95d351b3aa110535a6810a6a569905d106b6f3"}, + {file = "pydantic_core-2.4.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:e412607ca89a0ced10758dfb8f9adcc365ce4c1c377e637c01989a75e9a9ec8a"}, + {file = "pydantic_core-2.4.0-cp310-none-win32.whl", hash = "sha256:853f103e2b9a58832fdd08a587a51de8b552ae90e1a5d167f316b7eabf8d7dde"}, + {file = "pydantic_core-2.4.0-cp310-none-win_amd64.whl", hash = "sha256:3ba2c9c94a9176f6321a879c8b864d7c5b12d34f549a4c216c72ce213d7d953c"}, + {file = "pydantic_core-2.4.0-cp311-cp311-macosx_10_7_x86_64.whl", hash = "sha256:a8b7acd04896e8f161e1500dc5f218017db05c1d322f054e89cbd089ce5d0071"}, + {file = "pydantic_core-2.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:16468bd074fa4567592d3255bf25528ed41e6b616d69bf07096bdb5b66f947d1"}, + {file = "pydantic_core-2.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cba5ad5eef02c86a1f3da00544cbc59a510d596b27566479a7cd4d91c6187a11"}, + {file = "pydantic_core-2.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b7206e41e04b443016e930e01685bab7a308113c0b251b3f906942c8d4b48fcb"}, + {file = "pydantic_core-2.4.0-cp311-cp311-manylinux_2_24_armv7l.whl", hash = "sha256:c1375025f0bfc9155286ebae8eecc65e33e494c90025cda69e247c3ccd2bab00"}, + {file = "pydantic_core-2.4.0-cp311-cp311-manylinux_2_24_ppc64le.whl", hash = "sha256:3534118289e33130ed3f1cc487002e8d09b9f359be48b02e9cd3de58ce58fba9"}, + {file = "pydantic_core-2.4.0-cp311-cp311-manylinux_2_24_s390x.whl", hash = "sha256:94d2b36a74623caab262bf95f0e365c2c058396082bd9d6a9e825657d0c1e7fa"}, + {file = "pydantic_core-2.4.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:af24ad4fbaa5e4a2000beae0c3b7fd1c78d7819ab90f9370a1cfd8998e3f8a3c"}, + {file = "pydantic_core-2.4.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:bf10963d8aed8bbe0165b41797c9463d4c5c8788ae6a77c68427569be6bead41"}, + {file = "pydantic_core-2.4.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:68199ada7c310ddb8c76efbb606a0de656b40899388a7498954f423e03fc38be"}, + {file = "pydantic_core-2.4.0-cp311-none-win32.whl", hash = "sha256:6f855bcc96ed3dd56da7373cfcc9dcbabbc2073cac7f65c185772d08884790ce"}, + {file = "pydantic_core-2.4.0-cp311-none-win_amd64.whl", hash = "sha256:de39eb3bab93a99ddda1ac1b9aa331b944d8bcc4aa9141148f7fd8ee0299dafc"}, + {file = "pydantic_core-2.4.0-cp312-cp312-macosx_10_7_x86_64.whl", hash = "sha256:f773b39780323a0499b53ebd91a28ad11cde6705605d98d999dfa08624caf064"}, + {file = "pydantic_core-2.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a297c0d6c61963c5c3726840677b798ca5b7dfc71bc9c02b9a4af11d23236008"}, + {file = "pydantic_core-2.4.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:546064c55264156b973b5e65e5fafbe5e62390902ce3cf6b4005765505e8ff56"}, + {file = "pydantic_core-2.4.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:36ba9e728588588f0196deaf6751b9222492331b5552f865a8ff120869d372e0"}, + {file = "pydantic_core-2.4.0-cp312-cp312-manylinux_2_24_armv7l.whl", hash = "sha256:57a53a75010c635b3ad6499e7721eaa3b450e03f6862afe2dbef9c8f66e46ec8"}, + {file = "pydantic_core-2.4.0-cp312-cp312-manylinux_2_24_ppc64le.whl", hash = "sha256:4b262bbc13022f2097c48a21adcc360a81d83dc1d854c11b94953cd46d7d3c07"}, + {file = "pydantic_core-2.4.0-cp312-cp312-manylinux_2_24_s390x.whl", hash = "sha256:01947ad728f426fa07fcb26457ebf90ce29320259938414bc0edd1476e75addb"}, + {file = "pydantic_core-2.4.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b2799c2eaf182769889761d4fb4d78b82bc47dae833799fedbf69fc7de306faa"}, + {file = "pydantic_core-2.4.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:a08fd490ba36d1fbb2cd5dcdcfb9f3892deb93bd53456724389135712b5fc735"}, + {file = "pydantic_core-2.4.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:1e8a7c62d15a5c4b307271e4252d76ebb981d6251c6ecea4daf203ef0179ea4f"}, + {file = "pydantic_core-2.4.0-cp312-none-win32.whl", hash = "sha256:9206c14a67c38de7b916e486ae280017cf394fa4b1aa95cfe88621a4e1d79725"}, + {file = "pydantic_core-2.4.0-cp312-none-win_amd64.whl", hash = "sha256:884235507549a6b2d3c4113fb1877ae263109e787d9e0eb25c35982ab28d0399"}, + {file = "pydantic_core-2.4.0-cp37-cp37m-macosx_10_7_x86_64.whl", hash = "sha256:4cbe929efa77a806e8f1a97793f2dc3ea3475ae21a9ed0f37c21320fe93f6f50"}, + {file = "pydantic_core-2.4.0-cp37-cp37m-macosx_11_0_arm64.whl", hash = "sha256:9137289de8fe845c246a8c3482dd0cb40338846ba683756d8f489a4bd8fddcae"}, + {file = "pydantic_core-2.4.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c5d8e764b5646623e57575f624f8ebb8f7a9f7fd1fae682ef87869ca5fec8dcf"}, + {file = "pydantic_core-2.4.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8fba0aff4c407d0274e43697e785bcac155ad962be57518d1c711f45e72da70f"}, + {file = "pydantic_core-2.4.0-cp37-cp37m-manylinux_2_24_armv7l.whl", hash = "sha256:30527d173e826f2f7651f91c821e337073df1555e3b5a0b7b1e2c39e26e50678"}, + {file = "pydantic_core-2.4.0-cp37-cp37m-manylinux_2_24_ppc64le.whl", hash = "sha256:bd7d1dde70ff3e09e4bc7a1cbb91a7a538add291bfd5b3e70ef1e7b45192440f"}, + {file = "pydantic_core-2.4.0-cp37-cp37m-manylinux_2_24_s390x.whl", hash = "sha256:72f1216ca8cef7b8adacd4c4c6b89c3b0c4f97503197f5284c80f36d6e4edd30"}, + {file = "pydantic_core-2.4.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b013c7861a7c7bfcec48fd709513fea6f9f31727e7a0a93ca0dd12e056740717"}, + {file = "pydantic_core-2.4.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:478f5f6d7e32bd4a04d102160efb2d389432ecf095fe87c555c0a6fc4adfc1a4"}, + {file = "pydantic_core-2.4.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:d9610b47b5fe4aacbbba6a9cb5f12cbe864eec99dbfed5710bd32ef5dd8a5d5b"}, + {file = "pydantic_core-2.4.0-cp37-none-win32.whl", hash = "sha256:ff246c0111076c8022f9ba325c294f2cb5983403506989253e04dbae565e019b"}, + {file = "pydantic_core-2.4.0-cp37-none-win_amd64.whl", hash = "sha256:d0c2b713464a8e263a243ae7980d81ce2de5ac59a9f798a282e44350b42dc516"}, + {file = "pydantic_core-2.4.0-cp38-cp38-macosx_10_7_x86_64.whl", hash = "sha256:12ef6838245569fd60a179fade81ca4b90ae2fa0ef355d616f519f7bb27582db"}, + {file = "pydantic_core-2.4.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:49db206eb8fdc4b4f30e6e3e410584146d813c151928f94ec0db06c4f2595538"}, + {file = "pydantic_core-2.4.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a507d7fa44688bbac76af6521e488b3da93de155b9cba6f2c9b7833ce243d59"}, + {file = "pydantic_core-2.4.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ffe18407a4d000c568182ce5388bbbedeb099896904e43fc14eee76cfae6dec5"}, + {file = "pydantic_core-2.4.0-cp38-cp38-manylinux_2_24_armv7l.whl", hash = "sha256:fa8e48001b39d54d97d7b380a0669fa99fc0feeb972e35a2d677ba59164a9a22"}, + {file = "pydantic_core-2.4.0-cp38-cp38-manylinux_2_24_ppc64le.whl", hash = "sha256:394f12a2671ff8c4dfa2e85be6c08be0651ad85bc1e6aa9c77c21671baaf28cd"}, + {file = "pydantic_core-2.4.0-cp38-cp38-manylinux_2_24_s390x.whl", hash = "sha256:2f9ea0355f90db2a76af530245fa42f04d98f752a1236ed7c6809ec484560d5b"}, + {file = "pydantic_core-2.4.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:61d4e713f467abcdd59b47665d488bb898ad3dd47ce7446522a50e0cbd8e8279"}, + {file = "pydantic_core-2.4.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:453862ab268f6326b01f067ed89cb3a527d34dc46f6f4eeec46a15bbc706d0da"}, + {file = "pydantic_core-2.4.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:56a85fa0dab1567bd0cac10f0c3837b03e8a0d939e6a8061a3a420acd97e9421"}, + {file = "pydantic_core-2.4.0-cp38-none-win32.whl", hash = "sha256:0d726108c1c0380b88b6dd4db559f0280e0ceda9e077f46ff90bc85cd4d03e77"}, + {file = "pydantic_core-2.4.0-cp38-none-win_amd64.whl", hash = "sha256:047580388644c473b934d27849f8ed8dbe45df0adb72104e78b543e13bf69762"}, + {file = "pydantic_core-2.4.0-cp39-cp39-macosx_10_7_x86_64.whl", hash = "sha256:867d3eea954bea807cabba83cfc939c889a18576d66d197c60025b15269d7cc0"}, + {file = "pydantic_core-2.4.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:664402ef0c238a7f8a46efb101789d5f2275600fb18114446efec83cfadb5b66"}, + {file = "pydantic_core-2.4.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:64e8012ad60a5f0da09ed48725e6e923d1be25f2f091a640af6079f874663813"}, + {file = "pydantic_core-2.4.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac2b680de398f293b68183317432b3d67ab3faeba216aec18de0c395cb5e3060"}, + {file = "pydantic_core-2.4.0-cp39-cp39-manylinux_2_24_armv7l.whl", hash = "sha256:8efc1be43b036c2b6bcfb1451df24ee0ddcf69c31351003daf2699ed93f5687b"}, + {file = "pydantic_core-2.4.0-cp39-cp39-manylinux_2_24_ppc64le.whl", hash = "sha256:d93aedbc4614cc21b9ab0d0c4ccd7143354c1f7cffbbe96ae5216ad21d1b21b5"}, + {file = "pydantic_core-2.4.0-cp39-cp39-manylinux_2_24_s390x.whl", hash = "sha256:af788b64e13d52fc3600a68b16d31fa8d8573e3ff2fc9a38f8a60b8d94d1f012"}, + {file = "pydantic_core-2.4.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:97c6349c81cee2e69ef59eba6e6c08c5936e6b01c2d50b9e4ac152217845ae09"}, + {file = "pydantic_core-2.4.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:cc086ddb6dc654a15deeed1d1f2bcb1cb924ebd70df9dca738af19f64229b06c"}, + {file = "pydantic_core-2.4.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:e953353180bec330c3b830891d260b6f8e576e2d18db3c78d314e56bb2276066"}, + {file = "pydantic_core-2.4.0-cp39-none-win32.whl", hash = "sha256:6feb4b64d11d5420e517910d60a907d08d846cacaf4e029668725cd21d16743c"}, + {file = "pydantic_core-2.4.0-cp39-none-win_amd64.whl", hash = "sha256:153a61ac4030fa019b70b31fb7986461119230d3ba0ab661c757cfea652f4332"}, + {file = "pydantic_core-2.4.0-pp310-pypy310_pp73-macosx_10_7_x86_64.whl", hash = "sha256:3fcf529382b282a30b466bd7af05be28e22aa620e016135ac414f14e1ee6b9e1"}, + {file = "pydantic_core-2.4.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2edef05b63d82568b877002dc4cb5cc18f8929b59077120192df1e03e0c633f8"}, + {file = "pydantic_core-2.4.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:da055a1b0bfa8041bb2ff586b2cb0353ed03944a3472186a02cc44a557a0e661"}, + {file = "pydantic_core-2.4.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:77dadc764cf7c5405e04866181c5bd94a447372a9763e473abb63d1dfe9b7387"}, + {file = "pydantic_core-2.4.0-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:a4ea23b07f29487a7bef2a869f68c7ee0e05424d81375ce3d3de829314c6b5ec"}, + {file = "pydantic_core-2.4.0-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:382f0baa044d674ad59455a5eff83d7965572b745cc72df35c52c2ce8c731d37"}, + {file = "pydantic_core-2.4.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:08f89697625e453421401c7f661b9d1eb4c9e4c0a12fd256eeb55b06994ac6af"}, + {file = "pydantic_core-2.4.0-pp37-pypy37_pp73-macosx_10_7_x86_64.whl", hash = "sha256:43a405ce520b45941df9ff55d0cd09762017756a7b413bbad3a6e8178e64a2c2"}, + {file = "pydantic_core-2.4.0-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:584a7a818c84767af16ce8bda5d4f7fedb37d3d231fc89928a192f567e4ef685"}, + {file = "pydantic_core-2.4.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:04922fea7b13cd480586fa106345fe06e43220b8327358873c22d8dfa7a711c7"}, + {file = "pydantic_core-2.4.0-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:17156abac20a9feed10feec867fddd91a80819a485b0107fe61f09f2117fe5f3"}, + {file = "pydantic_core-2.4.0-pp37-pypy37_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:4e562cc63b04636cde361fd47569162f1daa94c759220ff202a8129902229114"}, + {file = "pydantic_core-2.4.0-pp37-pypy37_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:90f3785146f701e053bb6b9e8f53acce2c919aca91df88bd4975be0cb926eb41"}, + {file = "pydantic_core-2.4.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:e40b1e97edd3dc127aa53d8a5e539a3d0c227d71574d3f9ac1af02d58218a122"}, + {file = "pydantic_core-2.4.0-pp38-pypy38_pp73-macosx_10_7_x86_64.whl", hash = "sha256:b27f3e67f6e031f6620655741b7d0d6bebea8b25d415924b3e8bfef2dd7bd841"}, + {file = "pydantic_core-2.4.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:be86c2eb12fb0f846262ace9d8f032dc6978b8cb26a058920ecb723dbcb87d05"}, + {file = "pydantic_core-2.4.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4665f7ed345012a8d2eddf4203ef145f5f56a291d010382d235b94e91813f88a"}, + {file = "pydantic_core-2.4.0-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:79262be5a292d1df060f29b9a7cdd66934801f987a817632d7552534a172709a"}, + {file = "pydantic_core-2.4.0-pp38-pypy38_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:5fd905a69ac74eaba5041e21a1e8b1a479dab2b41c93bdcc4c1cede3c12a8d86"}, + {file = "pydantic_core-2.4.0-pp38-pypy38_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:2ad538b7e07343001934417cdc8584623b4d8823c5b8b258e75ec8d327cec969"}, + {file = "pydantic_core-2.4.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:dd2429f7635ad4857b5881503f9c310be7761dc681c467a9d27787b674d1250a"}, + {file = "pydantic_core-2.4.0-pp39-pypy39_pp73-macosx_10_7_x86_64.whl", hash = "sha256:efff8b6761a1f6e45cebd1b7a6406eb2723d2d5710ff0d1b624fe11313693989"}, + {file = "pydantic_core-2.4.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:32a1e0352558cd7ccc014ffe818c7d87b15ec6145875e2cc5fa4bb7351a1033d"}, + {file = "pydantic_core-2.4.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a027f41c5008571314861744d83aff75a34cf3a07022e0be32b214a5bc93f7f1"}, + {file = "pydantic_core-2.4.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1927f0e15d190f11f0b8344373731e28fd774c6d676d8a6cfadc95c77214a48b"}, + {file = "pydantic_core-2.4.0-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:7aa82d483d5fb867d4fb10a138ffd57b0f1644e99f2f4f336e48790ada9ada5e"}, + {file = "pydantic_core-2.4.0-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:b85778308bf945e9b33ac604e6793df9b07933108d20bdf53811bc7c2798a4af"}, + {file = "pydantic_core-2.4.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:3ded19dcaefe2f6706d81e0db787b59095f4ad0fbadce1edffdf092294c8a23f"}, + {file = "pydantic_core-2.4.0.tar.gz", hash = "sha256:ec3473c9789cc00c7260d840c3db2c16dbfc816ca70ec87a00cddfa3e1a1cdd5"}, +] + +[package.dependencies] +typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0" + +[[package]] +name = "pydantic-settings" +version = "2.0.2" +description = "Settings management using Pydantic" +optional = false +python-versions = ">=3.7" +files = [ + {file = "pydantic_settings-2.0.2-py3-none-any.whl", hash = "sha256:6183a2abeab465d5a3ab69758e9a22d38b0cc2ba193f0b85f6971a252ea630f6"}, + {file = "pydantic_settings-2.0.2.tar.gz", hash = "sha256:342337fff50b23585e807a86dec85037900972364435c55c2fc00d16ff080539"}, +] + +[package.dependencies] +pydantic = ">=2.0.1" +python-dotenv = ">=0.21.0" + [[package]] name = "pyee" version = "11.0.0" @@ -1402,6 +1606,20 @@ files = [ {file = "pyreadline3-3.4.1.tar.gz", hash = "sha256:6f3d1f7b8a31ba32b73917cefc1f28cc660562f39aea8646d30bd6eff21f7bae"}, ] +[[package]] +name = "python-dotenv" +version = "1.0.0" +description = "Read key-value pairs from a .env file and set them as environment variables" +optional = false +python-versions = ">=3.8" +files = [ + {file = "python-dotenv-1.0.0.tar.gz", hash = "sha256:a8df96034aae6d2d50a4ebe8216326c61c3eb64836776504fcca410e5937a3ba"}, + {file = "python_dotenv-1.0.0-py3-none-any.whl", hash = "sha256:f5971a9226b701070a4bf2c38c89e5a3f0d64de8debda981d1db98583009122a"}, +] + +[package.extras] +cli = ["click (>=5.0)"] + [[package]] name = "pyyaml" version = "6.0.1" @@ -1494,6 +1712,43 @@ files = [ {file = "sortedcontainers-2.4.0.tar.gz", hash = "sha256:25caa5a06cc30b6b83d11423433f65d1f9d76c4c6a0c90e3379eaa43b9bfdb88"}, ] +[[package]] +name = "stamina" +version = "23.1.0" +description = "Production-grade retries made easy." +optional = false +python-versions = ">=3.8" +files = [ + {file = "stamina-23.1.0-py3-none-any.whl", hash = "sha256:850de8c2c2469aabf42a4c02e7372eaa12c2eced78f2bfa34162b8676c2846e5"}, + {file = "stamina-23.1.0.tar.gz", hash = "sha256:b16ce3d52d658aa75db813fc6a6661b770abfea915f72cda48e325f2a7854786"}, +] + +[package.dependencies] +tenacity = "*" + +[package.extras] +dev = ["nox", "prometheus-client", "stamina[tests,typing]", "structlog", "tomli"] +docs = ["furo", "myst-parser", "prometheus-client", "sphinx", "sphinx-notfound-page", "structlog"] +tests = ["pytest", "pytest-asyncio"] +typing = ["mypy (>=1.4)"] + +[[package]] +name = "structlog" +version = "23.1.0" +description = "Structured Logging for Python" +optional = false +python-versions = ">=3.7" +files = [ + {file = "structlog-23.1.0-py3-none-any.whl", hash = "sha256:79b9e68e48b54e373441e130fa447944e6f87a05b35de23138e475c05d0f7e0e"}, + {file = "structlog-23.1.0.tar.gz", hash = "sha256:270d681dd7d163c11ba500bc914b2472d2b50a8ef00faa999ded5ff83a2f906b"}, +] + +[package.extras] +dev = ["structlog[docs,tests,typing]"] +docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-mermaid", "twisted"] +tests = ["coverage[toml]", "freezegun (>=0.2.8)", "pretend", "pytest (>=6.0)", "pytest-asyncio (>=0.17)", "simplejson"] +typing = ["mypy", "rich", "twisted"] + [[package]] name = "sympy" version = "1.12" @@ -1508,6 +1763,20 @@ files = [ [package.dependencies] mpmath = ">=0.19" +[[package]] +name = "tenacity" +version = "8.2.2" +description = "Retry code until it succeeds" +optional = false +python-versions = ">=3.6" +files = [ + {file = "tenacity-8.2.2-py3-none-any.whl", hash = "sha256:2f277afb21b851637e8f52e6a613ff08734c347dc19ade928e519d7d2d8569b0"}, + {file = "tenacity-8.2.2.tar.gz", hash = "sha256:43af037822bd0029025877f3b2d97cc4d7bb0c2991000a3d59d71517c5c969e0"}, +] + +[package.extras] +doc = ["reno", "sphinx", "tornado (>=4.5)"] + [[package]] name = "tokenizers" version = "0.13.3" @@ -1714,4 +1983,4 @@ multidict = ">=4.0" [metadata] lock-version = "2.0" python-versions = "^3.11" -content-hash = "e8eb6b4f81c090adb882a1b293d81f32167ea89f4636222d43fe0e9131cb97d6" +content-hash = "32981f838c232fdf2274aadbc933ef107c820d053bc9c2ceec563b2a22c1ea4c" diff --git a/server/pyproject.toml b/server/pyproject.toml index 25f4a9ff..aebb26f2 100644 --- a/server/pyproject.toml +++ b/server/pyproject.toml @@ -16,11 +16,19 @@ aiortc = "^1.5.0" faster-whisper = "^0.7.1" sortedcontainers = "^2.4.0" loguru = "^0.7.0" +pydantic-settings = "^2.0.2" +structlog = "^23.1.0" [tool.poetry.group.dev.dependencies] black = "^23.7.0" + +[tool.poetry.group.client.dependencies] +httpx = "^0.24.1" +pyaudio = "^0.2.13" +stamina = "^23.1.0" + [build-system] requires = ["poetry-core"] build-backend = "poetry.core.masonry.api" diff --git a/server/client.py b/server/reflector/client.py similarity index 82% rename from server/client.py rename to server/reflector/client.py index aa89934e..571da0a7 100644 --- a/server/client.py +++ b/server/reflector/client.py @@ -4,8 +4,8 @@ import signal from aiortc.contrib.signaling import add_signaling_arguments, create_signaling -from utils.log_utils import LOGGER -from stream_client import StreamClient +from reflector.logger import logger +from reflector.stream_client import StreamClient from typing import NoReturn @@ -42,16 +42,16 @@ async def main() -> NoReturn: async def shutdown(signal, loop): """Cleanup tasks tied to the service's shutdown.""" - LOGGER.info(f"Received exit signal {signal.name}...") - LOGGER.info("Closing database connections") - LOGGER.info("Nacking outstanding messages") + logger.info(f"Received exit signal {signal.name}...") + logger.info("Closing database connections") + logger.info("Nacking outstanding messages") tasks = [t for t in asyncio.all_tasks() if t is not asyncio.current_task()] [task.cancel() for task in tasks] - LOGGER.info(f"Cancelling {len(tasks)} outstanding tasks") + logger.info(f"Cancelling {len(tasks)} outstanding tasks") await asyncio.gather(*tasks, return_exceptions=True) - LOGGER.info(f'{"Flushing metrics"}') + logger.info(f'{"Flushing metrics"}') loop.stop() signals = (signal.SIGHUP, signal.SIGTERM, signal.SIGINT) diff --git a/server/reflector/logger.py b/server/reflector/logger.py new file mode 100644 index 00000000..63965a77 --- /dev/null +++ b/server/reflector/logger.py @@ -0,0 +1,3 @@ +import structlog + +logger = structlog.get_logger() diff --git a/server/reflector_dataclasses.py b/server/reflector/models.py similarity index 98% rename from server/reflector_dataclasses.py rename to server/reflector/models.py index d2e91c06..af04ade4 100644 --- a/server/reflector_dataclasses.py +++ b/server/reflector/models.py @@ -198,10 +198,12 @@ class TranscriptionContext: incremental_responses: List[IncrementalResult] sorted_transcripts: dict data_channel: None # FIXME + logger: None - def __init__(self): + def __init__(self, logger): self.transcription_text = "" self.last_transcribed_time = 0.0 self.incremental_responses = [] self.data_channel = None self.sorted_transcripts = SortedDict() + self.logger = logger diff --git a/server/server.py b/server/reflector/server.py similarity index 84% rename from server/server.py rename to server/reflector/server.py index b3939f43..dff8b15b 100644 --- a/server/server.py +++ b/server/reflector/server.py @@ -3,8 +3,8 @@ import asyncio import datetime import json import os -import uuid import wave +import uuid from concurrent.futures import ThreadPoolExecutor from typing import NoReturn, Union @@ -16,7 +16,7 @@ from aiortc import MediaStreamTrack, RTCPeerConnection, RTCSessionDescription from aiortc.contrib.media import MediaRelay from faster_whisper import WhisperModel -from reflector_dataclasses import ( +from reflector.models import ( BlackListedMessages, FinalSummaryResult, ParseLLMResult, @@ -26,8 +26,9 @@ from reflector_dataclasses import ( TranscriptionOutput, TranscriptionContext, ) -from utils.log_utils import LOGGER -from utils.run_utils import CONFIG, run_in_executor, SECRETS +from reflector.logger import logger +from reflector.utils.run_utils import run_in_executor +from reflector.settings import settings # WebRTC components pcs = set() @@ -37,19 +38,12 @@ executor = ThreadPoolExecutor() # Transcription model model = WhisperModel("tiny", device="cpu", compute_type="float32", num_workers=12) -# Audio configurations -CHANNELS = int(CONFIG["AUDIO"]["CHANNELS"]) -RATE = int(CONFIG["AUDIO"]["SAMPLING_RATE"]) -AUDIO_BUFFER_SIZE = 256 * 960 - # LLM -LLM_URL = os.environ.get("LLM_URL") -if LLM_URL: - LOGGER.info(f"Using LLM from environment: {LLM_URL}") -else: - LLM_MACHINE_IP = CONFIG["LLM"]["LLM_MACHINE_IP"] - LLM_MACHINE_PORT = CONFIG["LLM"]["LLM_MACHINE_PORT"] - LLM_URL = f"http://{LLM_MACHINE_IP}:{LLM_MACHINE_PORT}/api/v1/generate" +LLM_URL = settings.LLM_URL +if not LLM_URL: + assert settings.LLM_BACKEND == "oobagooda" + LLM_URL = f"http://{settings.LLM_HOST}:{settings.LLM_PORT}/api/v1/generate" +logger.info(f"Using LLM [{settings.LLM_BACKEND}]: {LLM_URL}") def parse_llm_output( @@ -64,8 +58,8 @@ def parse_llm_output( try: output = json.loads(response.json()["results"][0]["text"]) return ParseLLMResult(param, output) - except Exception as e: - LOGGER.info("Exception" + str(e)) + except Exception: + logger.exception("Exception while parsing LLM output") return None @@ -78,7 +72,7 @@ def get_title_and_summary( :param param: :return: """ - LOGGER.info("Generating title and summary") + logger.info("Generating title and summary") # TODO : Handle unexpected output formats from the model try: @@ -89,21 +83,10 @@ def get_title_and_summary( ctx.incremental_responses.append(result) return TitleSummaryOutput(ctx.incremental_responses) except Exception: - LOGGER.exception("Exception while generating title and summary") + logger.exception("Exception while generating title and summary") return None -def channel_log(channel, t: str, message: str) -> NoReturn: - """ - Add logs - :param channel: - :param t: - :param message: - :return: - """ - LOGGER.info("channel(%s) %s %s" % (channel.label, t, message)) - - def channel_send(channel, message: str) -> NoReturn: """ Send text messages via the data channel @@ -135,7 +118,6 @@ def channel_send_transcript(ctx: TranscriptionContext) -> NoReturn: :param channel: :return: """ - # channel_log(channel, ">", message) if not ctx.data_channel: return try: @@ -151,8 +133,8 @@ def channel_send_transcript(ctx: TranscriptionContext) -> NoReturn: else: if len(ctx.sorted_transcripts) >= 3: del ctx.sorted_transcripts[least_time] - except Exception as exception: - LOGGER.info("Exception", str(exception)) + except Exception: + logger.exception("Exception while sending transcript") def get_transcription( @@ -164,7 +146,7 @@ def get_transcription( :param input_frames: :return: """ - LOGGER.info("Transcribing..") + ctx.logger.info("Transcribing..") ctx.sorted_transcripts[input_frames.frames[0].time] = None # TODO: Find cleaner way, watch "no transcription" issue below @@ -174,9 +156,9 @@ def get_transcription( # https://github.com/guillaumekln/faster-whisper/issues/369 audio_file = "test" + str(datetime.datetime.now()) wf = wave.open(audio_file, "wb") - wf.setnchannels(CHANNELS) - wf.setframerate(RATE) - wf.setsampwidth(2) + wf.setnchannels(settings.AUDIO_CHANNELS) + wf.setframerate(settings.AUDIO_SAMPLING_RATE) + wf.setsampwidth(settings.AUDIO_SAMPLING_WIDTH) for frame in input_frames.frames: wf.writeframes(b"".join(frame.to_ndarray())) @@ -209,8 +191,8 @@ def get_transcription( ctx.last_transcribed_time += duration ctx.transcription_text += result_text - except Exception as exception: - LOGGER.info("Exception" + str(exception)) + except Exception: + logger.exception("Exception while transcribing") result = TranscriptionOutput(result_text) ctx.sorted_transcripts[input_frames.frames[0].time] = result @@ -258,7 +240,7 @@ class AudioStreamTrack(MediaStreamTrack): self.audio_buffer.write(frame) if local_frames := self.audio_buffer.read_many( - AUDIO_BUFFER_SIZE, partial=False + settings.AUDIO_BUFFER_SIZE, partial=False ): whisper_result = run_in_executor( get_transcription, @@ -296,24 +278,30 @@ async def offer(request: requests.Request) -> web.Response: params = await request.json() offer = RTCSessionDescription(sdp=params["sdp"], type=params["type"]) - ctx = TranscriptionContext() + # client identification + peername = request.transport.get_extra_info("peername") + if peername is not None: + clientid = f"{peername[0]}:{peername[1]}" + else: + clientid = uuid.uuid4() + + # create a context for the whole rtc transaction + # add a customised logger to the context + ctx = TranscriptionContext(logger=logger.bind(client=clientid)) + + # handle RTC peer connection pc = RTCPeerConnection() - pc_id = "PeerConnection(%s)" % uuid.uuid4() pcs.add(pc) - def log_info(msg, *args) -> NoReturn: - LOGGER.info(pc_id + " " + msg, *args) - - log_info("Created for " + request.remote) - @pc.on("datachannel") def on_datachannel(channel) -> NoReturn: ctx.data_channel = channel - channel_log(channel, "-", "created by remote party") + ctx.logger = ctx.logger.bind(channel=channel.label) + ctx.logger.info("Channel created by remote party") @channel.on("message") def on_message(message: str) -> NoReturn: - channel_log(channel, "<", message) + ctx.logger.info(f"Message: {message}") if json.loads(message)["cmd"] == "STOP": # Placeholder final summary response = get_final_summary_response() @@ -326,14 +314,14 @@ async def offer(request: requests.Request) -> web.Response: @pc.on("connectionstatechange") async def on_connectionstatechange() -> NoReturn: - log_info("Connection state is " + pc.connectionState) + ctx.logger.info(f"Connection state changed: {pc.connectionState}") if pc.connectionState == "failed": await pc.close() pcs.discard(pc) @pc.on("track") def on_track(track) -> NoReturn: - log_info("Track " + track.kind + " received") + ctx.logger.info(f"Track {track.kind} received") pc.addTrack(AudioStreamTrack(ctx, relay.subscribe(track))) await pc.setRemoteDescription(offer) diff --git a/server/reflector/settings.py b/server/reflector/settings.py new file mode 100644 index 00000000..cbfe4863 --- /dev/null +++ b/server/reflector/settings.py @@ -0,0 +1,45 @@ +from pydantic_settings import BaseSettings, SettingsConfigDict + + +class Settings(BaseSettings): + model_config = SettingsConfigDict(env_file=".env", env_file_encoding="utf-8") + + OPENMP_KMP_DUPLICATE_LIB_OK: bool = False + + # Whisper + WHISPER_MODEL_SIZE: str = "tiny" + whisper_real_time_model_size: str = "tiny" + + # Summarizer + SUMMARIZER_MODEL: str = "facebook/bart-large-cnn" + SUMMARIZER_INPUT_ENCODING_MAX_LENGTH: int = 1024 + SUMMARIZER_MAX_LENGTH: int = 2048 + SUMMARIZER_BEAM_SIZE: int = 6 + SUMMARIZER_MAX_CHUNK_LENGTH: int = 1024 + SUMMARIZER_USING_CHUNKS: bool = True + + # Audio + AUDIO_BLACKHOLE_INPUT_AGGREGATOR_DEVICE_NAME: str = "aggregator" + AUDIO_AV_FOUNDATION_DEVICE_ID: int = 1 + AUDIO_CHANNELS: int = 2 + AUDIO_SAMPLING_RATE: int = 48000 + AUDIO_SAMPLING_WIDTH: int = 2 + AUDIO_BUFFER_SIZE: int = 256 * 960 + + # LLM + LLM_BACKEND: str = "oobagooda" + LLM_URL: str | None = None + LLM_HOST: str = "localhost" + LLM_PORT: int = 7860 + + # Storage + STORAGE_BACKEND: str = "aws" + STORAGE_AWS_ACCESS_KEY: str = "" + STORAGE_AWS_SECRET_KEY: str = "" + STORAGE_AWS_BUCKET: str = "" + + # OpenAI + OPENAI_API_KEY: str = "" + + +settings = Settings() diff --git a/server/stream_client.py b/server/reflector/stream_client.py similarity index 95% rename from server/stream_client.py rename to server/reflector/stream_client.py index 4ec688bc..e6d5f497 100644 --- a/server/stream_client.py +++ b/server/reflector/stream_client.py @@ -9,8 +9,8 @@ import stamina from aiortc import RTCPeerConnection, RTCSessionDescription from aiortc.contrib.media import MediaPlayer, MediaRelay -from utils.log_utils import LOGGER -from utils.run_utils import CONFIG +from reflector.logger import logger +from reflector.settings import settings class StreamClient: @@ -31,7 +31,7 @@ class StreamClient: self.time_start = None self.queue = asyncio.Queue() self.player = MediaPlayer( - ":" + str(CONFIG["AUDIO"]["AV_FOUNDATION_DEVICE_ID"]), + f":{settings.AUDIO_AV_FOUNDATION_DEVICE_ID}", format="avfoundation", options={"channels": "2"}, ) @@ -71,7 +71,7 @@ class StreamClient: self.pcs.add(pc) def log_info(msg, *args): - LOGGER.info(pc_id + " " + msg, *args) + logger.info(pc_id + " " + msg, *args) @pc.on("connectionstatechange") async def on_connectionstatechange(): diff --git a/server/__init__.py b/server/reflector/utils/__init__.py similarity index 100% rename from server/__init__.py rename to server/reflector/utils/__init__.py diff --git a/server/utils/file_utils.py b/server/reflector/utils/file_utils.py similarity index 100% rename from server/utils/file_utils.py rename to server/reflector/utils/file_utils.py diff --git a/server/utils/format_output.py b/server/reflector/utils/format_output.py similarity index 100% rename from server/utils/format_output.py rename to server/reflector/utils/format_output.py diff --git a/server/utils/run_utils.py b/server/reflector/utils/run_utils.py similarity index 61% rename from server/utils/run_utils.py rename to server/reflector/utils/run_utils.py index 3eac353b..f99c2549 100644 --- a/server/utils/run_utils.py +++ b/server/reflector/utils/run_utils.py @@ -3,48 +3,12 @@ Utility file for server side asynchronous task running and config objects """ import asyncio -import configparser import contextlib from functools import partial from threading import Lock from typing import ContextManager, Generic, TypeVar -class ReflectorConfig: - """ - Create a single config object to share across the project - """ - - __config = None - __secrets = None - - @staticmethod - def get_config(): - """ - Load the configurations from the local config.ini file - :return: - """ - if ReflectorConfig.__config is None: - ReflectorConfig.__config = configparser.ConfigParser() - ReflectorConfig.__config.read("utils/config.ini") - return ReflectorConfig.__config - - @staticmethod - def get_secrets(): - """ - Load the configurations from the local config.ini file - :return: - """ - if ReflectorConfig.__secrets is None: - ReflectorConfig.__secrets = configparser.ConfigParser() - ReflectorConfig.__secrets.read("utils/secrets.ini") - return ReflectorConfig.__secrets - - -CONFIG = ReflectorConfig.get_config() -SECRETS = ReflectorConfig.get_secrets() - - def run_in_executor(func, *args, executor=None, **kwargs): """ Run the function in an executor, unblocking the main loop diff --git a/server/utils/text_utils.py b/server/reflector/utils/text_utils.py similarity index 100% rename from server/utils/text_utils.py rename to server/reflector/utils/text_utils.py diff --git a/server/utils/viz_utils.py b/server/reflector/utils/viz_utils.py similarity index 100% rename from server/utils/viz_utils.py rename to server/reflector/utils/viz_utils.py diff --git a/server/server-requirements.txt b/server/server-requirements.txt deleted file mode 100644 index 01d7af38..00000000 --- a/server/server-requirements.txt +++ /dev/null @@ -1,50 +0,0 @@ -aiohttp==3.8.5 -aiohttp-cors==0.7.0 -aioice==0.9.0 -aiortc==1.5.0 -aiosignal==1.3.1 -anyio==3.7.1 -async-timeout==4.0.2 -attrs==23.1.0 -av==10.0.0 -certifi==2023.7.22 -cffi==1.15.1 -charset-normalizer==3.2.0 -coloredlogs==15.0.1 -cryptography==41.0.2 -ctranslate2==3.17.1 -dnspython==2.4.0 -faster-whisper==0.7.1 -filelock==3.12.2 -flatbuffers==23.5.26 -frozenlist==1.4.0 -fsspec==2023.6.0 -google-crc32c==1.5.0 -h11==0.14.0 -httpcore==0.17.3 -huggingface-hub==0.16.4 -humanfriendly==10.0 -idna==3.4 -ifaddr==0.2.0 -loguru==0.7.0 -mpmath==1.3.0 -multidict==6.0.4 -numpy==1.25.1 -onnxruntime==1.15.1 -packaging==23.1 -protobuf==4.23.4 -pycparser==2.21 -pyee==11.0.0 -pylibsrtp==0.8.0 -pyOpenSSL==23.2.0 -PyYAML==6.0.1 -requests==2.31.0 -sniffio==1.3.0 -sortedcontainers==2.4.0 -sympy==1.12 -tokenizers==0.13.3 -tqdm==4.65.0 -typing_extensions==4.7.1 -urllib3==2.0.4 -yarl==1.9.2 -wave==0.0.2 diff --git a/server/agenda-headers.txt b/server/trials/whisper-jax/agenda-headers.txt similarity index 100% rename from server/agenda-headers.txt rename to server/trials/whisper-jax/agenda-headers.txt diff --git a/server/utils/__init__.py b/server/utils/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/server/utils/config.ini b/server/utils/config.ini deleted file mode 100644 index 9f8c1bfc..00000000 --- a/server/utils/config.ini +++ /dev/null @@ -1,25 +0,0 @@ -[DEFAULT] -#Set exception rule for OpenMP error -#to allow duplicate lib initialization -KMP_DUPLICATE_LIB_OK = TRUE - -[WHISPER] -#ExportWhisperModelSize -WHISPER_MODEL_SIZE = tiny -WHISPER_REAL_TIME_MODEL_SIZE = tiny - -[SUMMARIZER] -#Summarizerconfig -SUMMARY_MODEL = facebook/bart-large-cnn -INPUT_ENCODING_MAX_LENGTH = 1024 -MAX_LENGTH = 2048 -BEAM_SIZE = 6 -MAX_CHUNK_LENGTH = 1024 -SUMMARIZE_USING_CHUNKS = YES - -[AUDIO] -# Audiodevice -BLACKHOLE_INPUT_AGGREGATOR_DEVICE_NAME = aggregator -AV_FOUNDATION_DEVICE_ID = 1 -CHANNELS = 2 -SAMPLING_RATE = 48000 \ No newline at end of file diff --git a/server/utils/log_utils.py b/server/utils/log_utils.py deleted file mode 100644 index 6d3056ba..00000000 --- a/server/utils/log_utils.py +++ /dev/null @@ -1,27 +0,0 @@ -""" -Utility file for logging -""" - -import loguru - - -class SingletonLogger: - """ - Use Singleton design pattern to create a logger object and share it - across the entire project - """ - - __instance = None - - @staticmethod - def get_logger(): - """ - Create or return the singleton instance for the SingletonLogger class - :return: SingletonLogger instance - """ - if not SingletonLogger.__instance: - SingletonLogger.__instance = loguru.logger - return SingletonLogger.__instance - - -LOGGER = SingletonLogger.get_logger() diff --git a/server/utils/secrets.ini.example b/server/utils/secrets.ini.example deleted file mode 100644 index 08f47f3d..00000000 --- a/server/utils/secrets.ini.example +++ /dev/null @@ -1,14 +0,0 @@ -[LLM] -# LLM configs -LLM_MACHINE_IP= -LLM_MACHINE_PORT= - -[AWS-S3] -#AWSconfig -AWS_ACCESS_KEY= -AWS_SECRET_KEY= -BUCKET_NAME= - -[OPENAI] -#ExportOpenAIAPIKey -OPENAI_APIKEY=