Compare commits
11 Commits
5688769437
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
79f4156ffa
|
|||
|
7f4b559644
|
|||
|
98b5ab1f1c
|
|||
|
e628816ea8
|
|||
|
4e4389a03f
|
|||
|
2c0cffe16a
|
|||
|
98fc0596d4
|
|||
|
7059ebda4c
|
|||
|
46215a8aef
|
|||
|
809145f53a
|
|||
|
58b9cb586c
|
175
poetry.lock
generated
175
poetry.lock
generated
@@ -1,5 +1,17 @@
|
|||||||
# This file is automatically @generated by Poetry 2.1.2 and should not be changed by hand.
|
# This file is automatically @generated by Poetry 2.1.2 and should not be changed by hand.
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "annotated-types"
|
||||||
|
version = "0.7.0"
|
||||||
|
description = "Reusable constraint types to use with typing.Annotated"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.8"
|
||||||
|
groups = ["main"]
|
||||||
|
files = [
|
||||||
|
{file = "annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53"},
|
||||||
|
{file = "annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89"},
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "certifi"
|
name = "certifi"
|
||||||
version = "2025.4.26"
|
version = "2025.4.26"
|
||||||
@@ -518,6 +530,140 @@ files = [
|
|||||||
{file = "pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6"},
|
{file = "pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6"},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pydantic"
|
||||||
|
version = "2.11.4"
|
||||||
|
description = "Data validation using Python type hints"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.9"
|
||||||
|
groups = ["main"]
|
||||||
|
files = [
|
||||||
|
{file = "pydantic-2.11.4-py3-none-any.whl", hash = "sha256:d9615eaa9ac5a063471da949c8fc16376a84afb5024688b3ff885693506764eb"},
|
||||||
|
{file = "pydantic-2.11.4.tar.gz", hash = "sha256:32738d19d63a226a52eed76645a98ee07c1f410ee41d93b4afbfa85ed8111c2d"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
annotated-types = ">=0.6.0"
|
||||||
|
pydantic-core = "2.33.2"
|
||||||
|
typing-extensions = ">=4.12.2"
|
||||||
|
typing-inspection = ">=0.4.0"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
email = ["email-validator (>=2.0.0)"]
|
||||||
|
timezone = ["tzdata ; python_version >= \"3.9\" and platform_system == \"Windows\""]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pydantic-core"
|
||||||
|
version = "2.33.2"
|
||||||
|
description = "Core functionality for Pydantic validation and serialization"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.9"
|
||||||
|
groups = ["main"]
|
||||||
|
files = [
|
||||||
|
{file = "pydantic_core-2.33.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:2b3d326aaef0c0399d9afffeb6367d5e26ddc24d351dbc9c636840ac355dc5d8"},
|
||||||
|
{file = "pydantic_core-2.33.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0e5b2671f05ba48b94cb90ce55d8bdcaaedb8ba00cc5359f6810fc918713983d"},
|
||||||
|
{file = "pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0069c9acc3f3981b9ff4cdfaf088e98d83440a4c7ea1bc07460af3d4dc22e72d"},
|
||||||
|
{file = "pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d53b22f2032c42eaaf025f7c40c2e3b94568ae077a606f006d206a463bc69572"},
|
||||||
|
{file = "pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0405262705a123b7ce9f0b92f123334d67b70fd1f20a9372b907ce1080c7ba02"},
|
||||||
|
{file = "pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4b25d91e288e2c4e0662b8038a28c6a07eaac3e196cfc4ff69de4ea3db992a1b"},
|
||||||
|
{file = "pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6bdfe4b3789761f3bcb4b1ddf33355a71079858958e3a552f16d5af19768fef2"},
|
||||||
|
{file = "pydantic_core-2.33.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:efec8db3266b76ef9607c2c4c419bdb06bf335ae433b80816089ea7585816f6a"},
|
||||||
|
{file = "pydantic_core-2.33.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:031c57d67ca86902726e0fae2214ce6770bbe2f710dc33063187a68744a5ecac"},
|
||||||
|
{file = "pydantic_core-2.33.2-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:f8de619080e944347f5f20de29a975c2d815d9ddd8be9b9b7268e2e3ef68605a"},
|
||||||
|
{file = "pydantic_core-2.33.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:73662edf539e72a9440129f231ed3757faab89630d291b784ca99237fb94db2b"},
|
||||||
|
{file = "pydantic_core-2.33.2-cp310-cp310-win32.whl", hash = "sha256:0a39979dcbb70998b0e505fb1556a1d550a0781463ce84ebf915ba293ccb7e22"},
|
||||||
|
{file = "pydantic_core-2.33.2-cp310-cp310-win_amd64.whl", hash = "sha256:b0379a2b24882fef529ec3b4987cb5d003b9cda32256024e6fe1586ac45fc640"},
|
||||||
|
{file = "pydantic_core-2.33.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:4c5b0a576fb381edd6d27f0a85915c6daf2f8138dc5c267a57c08a62900758c7"},
|
||||||
|
{file = "pydantic_core-2.33.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e799c050df38a639db758c617ec771fd8fb7a5f8eaaa4b27b101f266b216a246"},
|
||||||
|
{file = "pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dc46a01bf8d62f227d5ecee74178ffc448ff4e5197c756331f71efcc66dc980f"},
|
||||||
|
{file = "pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a144d4f717285c6d9234a66778059f33a89096dfb9b39117663fd8413d582dcc"},
|
||||||
|
{file = "pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:73cf6373c21bc80b2e0dc88444f41ae60b2f070ed02095754eb5a01df12256de"},
|
||||||
|
{file = "pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3dc625f4aa79713512d1976fe9f0bc99f706a9dee21dfd1810b4bbbf228d0e8a"},
|
||||||
|
{file = "pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:881b21b5549499972441da4758d662aeea93f1923f953e9cbaff14b8b9565aef"},
|
||||||
|
{file = "pydantic_core-2.33.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:bdc25f3681f7b78572699569514036afe3c243bc3059d3942624e936ec93450e"},
|
||||||
|
{file = "pydantic_core-2.33.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:fe5b32187cbc0c862ee201ad66c30cf218e5ed468ec8dc1cf49dec66e160cc4d"},
|
||||||
|
{file = "pydantic_core-2.33.2-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:bc7aee6f634a6f4a95676fcb5d6559a2c2a390330098dba5e5a5f28a2e4ada30"},
|
||||||
|
{file = "pydantic_core-2.33.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:235f45e5dbcccf6bd99f9f472858849f73d11120d76ea8707115415f8e5ebebf"},
|
||||||
|
{file = "pydantic_core-2.33.2-cp311-cp311-win32.whl", hash = "sha256:6368900c2d3ef09b69cb0b913f9f8263b03786e5b2a387706c5afb66800efd51"},
|
||||||
|
{file = "pydantic_core-2.33.2-cp311-cp311-win_amd64.whl", hash = "sha256:1e063337ef9e9820c77acc768546325ebe04ee38b08703244c1309cccc4f1bab"},
|
||||||
|
{file = "pydantic_core-2.33.2-cp311-cp311-win_arm64.whl", hash = "sha256:6b99022f1d19bc32a4c2a0d544fc9a76e3be90f0b3f4af413f87d38749300e65"},
|
||||||
|
{file = "pydantic_core-2.33.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:a7ec89dc587667f22b6a0b6579c249fca9026ce7c333fc142ba42411fa243cdc"},
|
||||||
|
{file = "pydantic_core-2.33.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3c6db6e52c6d70aa0d00d45cdb9b40f0433b96380071ea80b09277dba021ddf7"},
|
||||||
|
{file = "pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e61206137cbc65e6d5256e1166f88331d3b6238e082d9f74613b9b765fb9025"},
|
||||||
|
{file = "pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:eb8c529b2819c37140eb51b914153063d27ed88e3bdc31b71198a198e921e011"},
|
||||||
|
{file = "pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c52b02ad8b4e2cf14ca7b3d918f3eb0ee91e63b3167c32591e57c4317e134f8f"},
|
||||||
|
{file = "pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:96081f1605125ba0855dfda83f6f3df5ec90c61195421ba72223de35ccfb2f88"},
|
||||||
|
{file = "pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f57a69461af2a5fa6e6bbd7a5f60d3b7e6cebb687f55106933188e79ad155c1"},
|
||||||
|
{file = "pydantic_core-2.33.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:572c7e6c8bb4774d2ac88929e3d1f12bc45714ae5ee6d9a788a9fb35e60bb04b"},
|
||||||
|
{file = "pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:db4b41f9bd95fbe5acd76d89920336ba96f03e149097365afe1cb092fceb89a1"},
|
||||||
|
{file = "pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:fa854f5cf7e33842a892e5c73f45327760bc7bc516339fda888c75ae60edaeb6"},
|
||||||
|
{file = "pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:5f483cfb75ff703095c59e365360cb73e00185e01aaea067cd19acffd2ab20ea"},
|
||||||
|
{file = "pydantic_core-2.33.2-cp312-cp312-win32.whl", hash = "sha256:9cb1da0f5a471435a7bc7e439b8a728e8b61e59784b2af70d7c169f8dd8ae290"},
|
||||||
|
{file = "pydantic_core-2.33.2-cp312-cp312-win_amd64.whl", hash = "sha256:f941635f2a3d96b2973e867144fde513665c87f13fe0e193c158ac51bfaaa7b2"},
|
||||||
|
{file = "pydantic_core-2.33.2-cp312-cp312-win_arm64.whl", hash = "sha256:cca3868ddfaccfbc4bfb1d608e2ccaaebe0ae628e1416aeb9c4d88c001bb45ab"},
|
||||||
|
{file = "pydantic_core-2.33.2-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:1082dd3e2d7109ad8b7da48e1d4710c8d06c253cbc4a27c1cff4fbcaa97a9e3f"},
|
||||||
|
{file = "pydantic_core-2.33.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f517ca031dfc037a9c07e748cefd8d96235088b83b4f4ba8939105d20fa1dcd6"},
|
||||||
|
{file = "pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a9f2c9dd19656823cb8250b0724ee9c60a82f3cdf68a080979d13092a3b0fef"},
|
||||||
|
{file = "pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2b0a451c263b01acebe51895bfb0e1cc842a5c666efe06cdf13846c7418caa9a"},
|
||||||
|
{file = "pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ea40a64d23faa25e62a70ad163571c0b342b8bf66d5fa612ac0dec4f069d916"},
|
||||||
|
{file = "pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0fb2d542b4d66f9470e8065c5469ec676978d625a8b7a363f07d9a501a9cb36a"},
|
||||||
|
{file = "pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9fdac5d6ffa1b5a83bca06ffe7583f5576555e6c8b3a91fbd25ea7780f825f7d"},
|
||||||
|
{file = "pydantic_core-2.33.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:04a1a413977ab517154eebb2d326da71638271477d6ad87a769102f7c2488c56"},
|
||||||
|
{file = "pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:c8e7af2f4e0194c22b5b37205bfb293d166a7344a5b0d0eaccebc376546d77d5"},
|
||||||
|
{file = "pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:5c92edd15cd58b3c2d34873597a1e20f13094f59cf88068adb18947df5455b4e"},
|
||||||
|
{file = "pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:65132b7b4a1c0beded5e057324b7e16e10910c106d43675d9bd87d4f38dde162"},
|
||||||
|
{file = "pydantic_core-2.33.2-cp313-cp313-win32.whl", hash = "sha256:52fb90784e0a242bb96ec53f42196a17278855b0f31ac7c3cc6f5c1ec4811849"},
|
||||||
|
{file = "pydantic_core-2.33.2-cp313-cp313-win_amd64.whl", hash = "sha256:c083a3bdd5a93dfe480f1125926afcdbf2917ae714bdb80b36d34318b2bec5d9"},
|
||||||
|
{file = "pydantic_core-2.33.2-cp313-cp313-win_arm64.whl", hash = "sha256:e80b087132752f6b3d714f041ccf74403799d3b23a72722ea2e6ba2e892555b9"},
|
||||||
|
{file = "pydantic_core-2.33.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:61c18fba8e5e9db3ab908620af374db0ac1baa69f0f32df4f61ae23f15e586ac"},
|
||||||
|
{file = "pydantic_core-2.33.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95237e53bb015f67b63c91af7518a62a8660376a6a0db19b89acc77a4d6199f5"},
|
||||||
|
{file = "pydantic_core-2.33.2-cp313-cp313t-win_amd64.whl", hash = "sha256:c2fc0a768ef76c15ab9238afa6da7f69895bb5d1ee83aeea2e3509af4472d0b9"},
|
||||||
|
{file = "pydantic_core-2.33.2-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:a2b911a5b90e0374d03813674bf0a5fbbb7741570dcd4b4e85a2e48d17def29d"},
|
||||||
|
{file = "pydantic_core-2.33.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:6fa6dfc3e4d1f734a34710f391ae822e0a8eb8559a85c6979e14e65ee6ba2954"},
|
||||||
|
{file = "pydantic_core-2.33.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c54c939ee22dc8e2d545da79fc5381f1c020d6d3141d3bd747eab59164dc89fb"},
|
||||||
|
{file = "pydantic_core-2.33.2-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:53a57d2ed685940a504248187d5685e49eb5eef0f696853647bf37c418c538f7"},
|
||||||
|
{file = "pydantic_core-2.33.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:09fb9dd6571aacd023fe6aaca316bd01cf60ab27240d7eb39ebd66a3a15293b4"},
|
||||||
|
{file = "pydantic_core-2.33.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0e6116757f7959a712db11f3e9c0a99ade00a5bbedae83cb801985aa154f071b"},
|
||||||
|
{file = "pydantic_core-2.33.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d55ab81c57b8ff8548c3e4947f119551253f4e3787a7bbc0b6b3ca47498a9d3"},
|
||||||
|
{file = "pydantic_core-2.33.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c20c462aa4434b33a2661701b861604913f912254e441ab8d78d30485736115a"},
|
||||||
|
{file = "pydantic_core-2.33.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:44857c3227d3fb5e753d5fe4a3420d6376fa594b07b621e220cd93703fe21782"},
|
||||||
|
{file = "pydantic_core-2.33.2-cp39-cp39-musllinux_1_1_armv7l.whl", hash = "sha256:eb9b459ca4df0e5c87deb59d37377461a538852765293f9e6ee834f0435a93b9"},
|
||||||
|
{file = "pydantic_core-2.33.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:9fcd347d2cc5c23b06de6d3b7b8275be558a0c90549495c699e379a80bf8379e"},
|
||||||
|
{file = "pydantic_core-2.33.2-cp39-cp39-win32.whl", hash = "sha256:83aa99b1285bc8f038941ddf598501a86f1536789740991d7d8756e34f1e74d9"},
|
||||||
|
{file = "pydantic_core-2.33.2-cp39-cp39-win_amd64.whl", hash = "sha256:f481959862f57f29601ccced557cc2e817bce7533ab8e01a797a48b49c9692b3"},
|
||||||
|
{file = "pydantic_core-2.33.2-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:5c4aa4e82353f65e548c476b37e64189783aa5384903bfea4f41580f255fddfa"},
|
||||||
|
{file = "pydantic_core-2.33.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:d946c8bf0d5c24bf4fe333af284c59a19358aa3ec18cb3dc4370080da1e8ad29"},
|
||||||
|
{file = "pydantic_core-2.33.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:87b31b6846e361ef83fedb187bb5b4372d0da3f7e28d85415efa92d6125d6e6d"},
|
||||||
|
{file = "pydantic_core-2.33.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa9d91b338f2df0508606f7009fde642391425189bba6d8c653afd80fd6bb64e"},
|
||||||
|
{file = "pydantic_core-2.33.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2058a32994f1fde4ca0480ab9d1e75a0e8c87c22b53a3ae66554f9af78f2fe8c"},
|
||||||
|
{file = "pydantic_core-2.33.2-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:0e03262ab796d986f978f79c943fc5f620381be7287148b8010b4097f79a39ec"},
|
||||||
|
{file = "pydantic_core-2.33.2-pp310-pypy310_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:1a8695a8d00c73e50bff9dfda4d540b7dee29ff9b8053e38380426a85ef10052"},
|
||||||
|
{file = "pydantic_core-2.33.2-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:fa754d1850735a0b0e03bcffd9d4b4343eb417e47196e4485d9cca326073a42c"},
|
||||||
|
{file = "pydantic_core-2.33.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:a11c8d26a50bfab49002947d3d237abe4d9e4b5bdc8846a63537b6488e197808"},
|
||||||
|
{file = "pydantic_core-2.33.2-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:dd14041875d09cc0f9308e37a6f8b65f5585cf2598a53aa0123df8b129d481f8"},
|
||||||
|
{file = "pydantic_core-2.33.2-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:d87c561733f66531dced0da6e864f44ebf89a8fba55f31407b00c2f7f9449593"},
|
||||||
|
{file = "pydantic_core-2.33.2-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2f82865531efd18d6e07a04a17331af02cb7a651583c418df8266f17a63c6612"},
|
||||||
|
{file = "pydantic_core-2.33.2-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bfb5112df54209d820d7bf9317c7a6c9025ea52e49f46b6a2060104bba37de7"},
|
||||||
|
{file = "pydantic_core-2.33.2-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:64632ff9d614e5eecfb495796ad51b0ed98c453e447a76bcbeeb69615079fc7e"},
|
||||||
|
{file = "pydantic_core-2.33.2-pp311-pypy311_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:f889f7a40498cc077332c7ab6b4608d296d852182211787d4f3ee377aaae66e8"},
|
||||||
|
{file = "pydantic_core-2.33.2-pp311-pypy311_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:de4b83bb311557e439b9e186f733f6c645b9417c84e2eb8203f3f820a4b988bf"},
|
||||||
|
{file = "pydantic_core-2.33.2-pp311-pypy311_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:82f68293f055f51b51ea42fafc74b6aad03e70e191799430b90c13d643059ebb"},
|
||||||
|
{file = "pydantic_core-2.33.2-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:329467cecfb529c925cf2bbd4d60d2c509bc2fb52a20c1045bf09bb70971a9c1"},
|
||||||
|
{file = "pydantic_core-2.33.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:87acbfcf8e90ca885206e98359d7dca4bcbb35abdc0ff66672a293e1d7a19101"},
|
||||||
|
{file = "pydantic_core-2.33.2-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:7f92c15cd1e97d4b12acd1cc9004fa092578acfa57b67ad5e43a197175d01a64"},
|
||||||
|
{file = "pydantic_core-2.33.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d3f26877a748dc4251cfcfda9dfb5f13fcb034f5308388066bcfe9031b63ae7d"},
|
||||||
|
{file = "pydantic_core-2.33.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dac89aea9af8cd672fa7b510e7b8c33b0bba9a43186680550ccf23020f32d535"},
|
||||||
|
{file = "pydantic_core-2.33.2-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:970919794d126ba8645f3837ab6046fb4e72bbc057b3709144066204c19a455d"},
|
||||||
|
{file = "pydantic_core-2.33.2-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:3eb3fe62804e8f859c49ed20a8451342de53ed764150cb14ca71357c765dc2a6"},
|
||||||
|
{file = "pydantic_core-2.33.2-pp39-pypy39_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:3abcd9392a36025e3bd55f9bd38d908bd17962cc49bc6da8e7e96285336e2bca"},
|
||||||
|
{file = "pydantic_core-2.33.2-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:3a1c81334778f9e3af2f8aeb7a960736e5cab1dfebfb26aabca09afd2906c039"},
|
||||||
|
{file = "pydantic_core-2.33.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:2807668ba86cb38c6817ad9bc66215ab8584d1d304030ce4f0887336f28a5e27"},
|
||||||
|
{file = "pydantic_core-2.33.2.tar.gz", hash = "sha256:7cb8bc3605c29176e1b105350d2e6474142d7c1bd1d9327c4a9bdb46bf827acc"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pygments"
|
name = "pygments"
|
||||||
version = "2.19.1"
|
version = "2.19.1"
|
||||||
@@ -745,6 +891,33 @@ urllib3 = ">=1.26.0"
|
|||||||
[package.extras]
|
[package.extras]
|
||||||
keyring = ["keyring (>=15.1)"]
|
keyring = ["keyring (>=15.1)"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "typing-extensions"
|
||||||
|
version = "4.13.2"
|
||||||
|
description = "Backported and Experimental Type Hints for Python 3.8+"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.8"
|
||||||
|
groups = ["main"]
|
||||||
|
files = [
|
||||||
|
{file = "typing_extensions-4.13.2-py3-none-any.whl", hash = "sha256:a439e7c04b49fec3e5d3e2beaa21755cadbbdc391694e28ccdd36ca4a1408f8c"},
|
||||||
|
{file = "typing_extensions-4.13.2.tar.gz", hash = "sha256:e6c81219bd689f51865d9e372991c540bda33a0379d5573cddb9a3a23f7caaef"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "typing-inspection"
|
||||||
|
version = "0.4.0"
|
||||||
|
description = "Runtime typing introspection tools"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.9"
|
||||||
|
groups = ["main"]
|
||||||
|
files = [
|
||||||
|
{file = "typing_inspection-0.4.0-py3-none-any.whl", hash = "sha256:50e72559fcd2a6367a19f7a7e610e6afcb9fac940c650290eed893d61386832f"},
|
||||||
|
{file = "typing_inspection-0.4.0.tar.gz", hash = "sha256:9765c87de36671694a67904bf2c96e395be9c6439bb6c87b5142569dcdd65122"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
typing-extensions = ">=4.12.0"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "urllib3"
|
name = "urllib3"
|
||||||
version = "2.4.0"
|
version = "2.4.0"
|
||||||
@@ -766,4 +939,4 @@ zstd = ["zstandard (>=0.18.0)"]
|
|||||||
[metadata]
|
[metadata]
|
||||||
lock-version = "2.1"
|
lock-version = "2.1"
|
||||||
python-versions = ">=3.12"
|
python-versions = ">=3.12"
|
||||||
content-hash = "33d6dddddf6b4c9ff020272b1e39c87ac4b85a53683a2929b7e0673ef4a09e0b"
|
content-hash = "095dc8efb8ce84ac67e84e537fe81f42eca53375ddcc2bd267be592efb9232cf"
|
||||||
|
|||||||
@@ -1,12 +1,16 @@
|
|||||||
[project]
|
[project]
|
||||||
name = "pyvtt"
|
name = "pyvtt"
|
||||||
version = "0.4.2"
|
version = "0.6.0"
|
||||||
description = "Python Voice to Text + LLMA"
|
description = "Python Voice to Text + LLMA"
|
||||||
authors = [{ name = "Max P.", email = "Mail@MPassarello.de" }]
|
authors = [{ name = "Max P.", email = "Mail@MPassarello.de" }]
|
||||||
license = { text = "MIT" }
|
license = { text = "MIT" }
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
requires-python = ">=3.12"
|
requires-python = ">=3.12"
|
||||||
dependencies = ["pyqt5 (>=5.15.11,<6.0.0)", "requests (>=2.32.3,<3.0.0)"]
|
dependencies = [
|
||||||
|
"pyqt5 (>=5.15.11,<6.0.0)",
|
||||||
|
"requests (>=2.32.3,<3.0.0)",
|
||||||
|
"pydantic (>=2.11.4,<3.0.0)",
|
||||||
|
]
|
||||||
|
|
||||||
[tool.poetry]
|
[tool.poetry]
|
||||||
packages = [{ include = "pyvtt", from = "src" }]
|
packages = [{ include = "pyvtt", from = "src" }]
|
||||||
|
|||||||
@@ -2,23 +2,26 @@
|
|||||||
"audio_file": "/tmp/pyvtt_recording.wav",
|
"audio_file": "/tmp/pyvtt_recording.wav",
|
||||||
"output_file": "/tmp/pyvtt_transcript.txt",
|
"output_file": "/tmp/pyvtt_transcript.txt",
|
||||||
"whisper_path": "/path/to/whisper-cli",
|
"whisper_path": "/path/to/whisper-cli",
|
||||||
"language": "en",
|
|
||||||
"socket_path": "/tmp/pyvtt.sock",
|
"socket_path": "/tmp/pyvtt.sock",
|
||||||
"ollama_url": "http://localhost",
|
"ollama_url": "http://localhost",
|
||||||
|
"ollama_path": "/api/chat",
|
||||||
"ollama_port": 12345,
|
"ollama_port": 12345,
|
||||||
"presets": [
|
"presets": [
|
||||||
{
|
{
|
||||||
"name": "Default",
|
"name": "Default",
|
||||||
"language": "en",
|
"language": "en",
|
||||||
"whisper_model": "/path/to/default-whisper-model.bin",
|
"whisper_model": "/path/to/default-whisper-model.bin",
|
||||||
"ollama_model": "default-model",
|
"ollama": "disable"
|
||||||
"ollama_prompt": "Provide a detailed response to the following text:\n\n"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Quick English",
|
"name": "Quick English",
|
||||||
"whisper_model": "/path/to/quick-whisper-model.bin",
|
"whisper_model": "/path/to/quick-whisper-model.bin",
|
||||||
"ollama_model": "quick-model",
|
"ollama_model": "gemma3:4b",
|
||||||
"ollama_prompt": "Quickly correct the following English text for grammar and punctuation:\n\n"
|
"ollama_context": 131072,
|
||||||
|
"ollama_prompt": [
|
||||||
|
"Quickly correct the following English text for grammar and punctuation:\n",
|
||||||
|
"\n"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "German Correction",
|
"name": "German Correction",
|
||||||
|
|||||||
@@ -2,9 +2,11 @@ import json
|
|||||||
import os
|
import os
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
|
from pyvtt.models.config import AppConfig
|
||||||
|
|
||||||
DEFAULT_CONFIG_PATH = Path.home() / ".pyvtt.json"
|
DEFAULT_CONFIG_PATH = Path.home() / ".pyvtt.json"
|
||||||
|
|
||||||
def read_configurations():
|
def read_configurations() -> AppConfig:
|
||||||
"""
|
"""
|
||||||
Reads the configuration settings from a JSON file named 'pyvtt.settings.json'
|
Reads the configuration settings from a JSON file named 'pyvtt.settings.json'
|
||||||
located in the same directory as the script.
|
located in the same directory as the script.
|
||||||
@@ -18,7 +20,8 @@ def read_configurations():
|
|||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
with open(DEFAULT_CONFIG_PATH) as f:
|
with open(DEFAULT_CONFIG_PATH) as f:
|
||||||
return json.load(f)
|
raw_config = json.load(f)
|
||||||
|
return AppConfig(**raw_config)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Error reading configurations: {e}")
|
print(f"Error reading configurations: {e}")
|
||||||
raise Exception(f"Error reading configurations: {e}")
|
raise Exception(f"Error reading configurations: {e}")
|
||||||
103
src/pyvtt/libs/ollama.py
Normal file
103
src/pyvtt/libs/ollama.py
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
import json
|
||||||
|
import requests
|
||||||
|
from typing import Union, List, Optional
|
||||||
|
|
||||||
|
from pyvtt.libs.notify import notify
|
||||||
|
from pyvtt.models.config import AppConfig, PresetConfig
|
||||||
|
|
||||||
|
|
||||||
|
class OllamaClient:
|
||||||
|
def __init__(self, config: AppConfig):
|
||||||
|
"""
|
||||||
|
Initialisiert den API-Client (Ollama oder llama-swap) mit Basis-Konfiguration.
|
||||||
|
"""
|
||||||
|
self.base_url = config.ollama_url.rstrip("/")
|
||||||
|
self.port = config.ollama_port
|
||||||
|
self.path = config.ollama_path or "/api/chat"
|
||||||
|
# Falls llama-swap (OpenAI-API-Kompatibel), verwende den OpenAI-Pfad
|
||||||
|
if "v1" in self.path or "completions" in self.path:
|
||||||
|
self.is_llama_swap = True
|
||||||
|
else:
|
||||||
|
self.is_llama_swap = False
|
||||||
|
|
||||||
|
def send_chat(self, user_message: str, config: PresetConfig) -> str:
|
||||||
|
"""
|
||||||
|
Sendet eine Chat-Anfrage an Ollama oder llama-swap.
|
||||||
|
"""
|
||||||
|
if config.ollama and config.ollama.lower() == "disable":
|
||||||
|
print("[OllamaClient] Ollama ist im Preset deaktiviert.")
|
||||||
|
return user_message
|
||||||
|
|
||||||
|
# Prompt aufbereiten
|
||||||
|
prompt_str = (
|
||||||
|
"\n".join(config.ollama_prompt)
|
||||||
|
if isinstance(config.ollama_prompt, list)
|
||||||
|
else str(config.ollama_prompt)
|
||||||
|
)
|
||||||
|
|
||||||
|
# === Payload vorbereiten ===
|
||||||
|
if self.is_llama_swap:
|
||||||
|
# OpenAI-/llama-swap-kompatibles Format
|
||||||
|
payload = {
|
||||||
|
"model": config.ollama_model,
|
||||||
|
"messages": [
|
||||||
|
{"role": "system", "content": prompt_str},
|
||||||
|
{"role": "user", "content": user_message},
|
||||||
|
],
|
||||||
|
"stream": False,
|
||||||
|
}
|
||||||
|
# Kontextgröße optional hinzufügen
|
||||||
|
if config.ollama_context:
|
||||||
|
payload["num_ctx"] = config.ollama_context
|
||||||
|
else:
|
||||||
|
# Klassisches Ollama-Format
|
||||||
|
payload = {
|
||||||
|
"model": config.ollama_model,
|
||||||
|
"messages": [
|
||||||
|
{"role": "system", "content": prompt_str},
|
||||||
|
{"role": "user", "content": user_message},
|
||||||
|
],
|
||||||
|
"options": (
|
||||||
|
{"num_ctx": config.ollama_context}
|
||||||
|
if config.ollama_context
|
||||||
|
else {}
|
||||||
|
),
|
||||||
|
"stream": False,
|
||||||
|
}
|
||||||
|
|
||||||
|
endpoint = f"{self.base_url}:{self.port}{self.path}"
|
||||||
|
|
||||||
|
# === Anfrage senden ===
|
||||||
|
try:
|
||||||
|
headers = {"Content-Type": "application/json"}
|
||||||
|
if self.is_llama_swap:
|
||||||
|
headers["Authorization"] = "Bearer no-key"
|
||||||
|
|
||||||
|
response = requests.post(endpoint, headers=headers, data=json.dumps(payload))
|
||||||
|
response.raise_for_status()
|
||||||
|
|
||||||
|
json_response = response.json()
|
||||||
|
|
||||||
|
# === Antwort extrahieren ===
|
||||||
|
if self.is_llama_swap:
|
||||||
|
# OpenAI-kompatible Struktur
|
||||||
|
content = (
|
||||||
|
json_response.get("choices", [{}])[0]
|
||||||
|
.get("message", {})
|
||||||
|
.get("content", "")
|
||||||
|
.strip()
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
# Ollama-eigene Struktur
|
||||||
|
content = (
|
||||||
|
json_response.get("message", {})
|
||||||
|
.get("content", "")
|
||||||
|
.strip()
|
||||||
|
)
|
||||||
|
|
||||||
|
return "\n".join(line.strip() for line in content.splitlines())
|
||||||
|
|
||||||
|
except requests.exceptions.RequestException as e:
|
||||||
|
print(f"[OllamaClient] HTTP-Fehler: {e}")
|
||||||
|
notify("Fehler", "Kommunikationsfehler mit Ollama / llama-swap!")
|
||||||
|
return ""
|
||||||
50
src/pyvtt/libs/whisper.py
Normal file
50
src/pyvtt/libs/whisper.py
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
import subprocess
|
||||||
|
from typing import Optional
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
from pyvtt.libs.notify import notify
|
||||||
|
from pyvtt.models.config import AppConfig, PresetConfig
|
||||||
|
|
||||||
|
|
||||||
|
class WhisperClient:
|
||||||
|
def __init__(self, config: AppConfig):
|
||||||
|
"""
|
||||||
|
Initialisiert den Whisper-Client mit der globalen Anwendungskonfiguration.
|
||||||
|
|
||||||
|
:param config: AppConfig-Instanz mit Pfaden zur Whisper-Binary, Audio- und Ausgabedatei.
|
||||||
|
"""
|
||||||
|
self.whisper_path = config.whisper_path
|
||||||
|
self.audio_file = config.audio_file
|
||||||
|
self.output_file = config.output_file
|
||||||
|
|
||||||
|
def transcribe(self, config: PresetConfig) -> str:
|
||||||
|
"""
|
||||||
|
Führt Whisper (CLI) zur Transkription der Audiodatei aus und gibt das Transkript zurück.
|
||||||
|
|
||||||
|
:param config: PresetConfig-Instanz mit Whisper-Modell und Spracheinstellungen.
|
||||||
|
:return: Das rohe Transkript als String – oder None bei Fehlern.
|
||||||
|
"""
|
||||||
|
output_base = self.output_file.replace(".txt", "")
|
||||||
|
whisper_cmd = [
|
||||||
|
self.whisper_path,
|
||||||
|
"-m", config.whisper_model,
|
||||||
|
"-f", self.audio_file,
|
||||||
|
"-l", config.language,
|
||||||
|
"-otxt",
|
||||||
|
"-of", output_base
|
||||||
|
]
|
||||||
|
|
||||||
|
try:
|
||||||
|
subprocess.run(whisper_cmd, check=True)
|
||||||
|
except subprocess.CalledProcessError as e:
|
||||||
|
print(f"[WhisperClient] Whisper-Ausführungsfehler: {e}")
|
||||||
|
notify("Fehler", "Ein Fehler mit 'Whisper' ist aufgetreten!")
|
||||||
|
return ""
|
||||||
|
|
||||||
|
try:
|
||||||
|
with open(self.output_file, "r", encoding="utf-8") as f:
|
||||||
|
return "\n".join(line.strip() for line in f.readlines())
|
||||||
|
except Exception as e:
|
||||||
|
print(f"[WhisperClient] Fehler beim Einlesen der Ausgabedatei: {e}")
|
||||||
|
notify("Fehler", "Ein Fehler beim Lesen der Whisper-Ausgabe ist aufgetreten!")
|
||||||
|
return ""
|
||||||
26
src/pyvtt/models/config.py
Normal file
26
src/pyvtt/models/config.py
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
from typing import List, Optional, Union
|
||||||
|
from pydantic import BaseModel, HttpUrl, Field
|
||||||
|
|
||||||
|
|
||||||
|
class PresetConfig(BaseModel):
|
||||||
|
name: str
|
||||||
|
language: str
|
||||||
|
whisper_model: str
|
||||||
|
ollama: Optional[str] = None
|
||||||
|
ollama_model: Optional[str] = None
|
||||||
|
ollama_context: Optional[int] = None
|
||||||
|
ollama_prompt: Optional[Union[str, List[str]]] = None
|
||||||
|
mode: Optional[str] = None
|
||||||
|
journal_name: Optional[str] = None
|
||||||
|
|
||||||
|
|
||||||
|
class AppConfig(BaseModel):
|
||||||
|
audio_file: str
|
||||||
|
output_file: str
|
||||||
|
whisper_path: str
|
||||||
|
socket_path: str
|
||||||
|
ollama_url: str
|
||||||
|
ollama_path: str
|
||||||
|
ollama_port: int
|
||||||
|
journal_path: str
|
||||||
|
presets: List[PresetConfig]
|
||||||
@@ -4,7 +4,7 @@ import argparse
|
|||||||
from pyvtt.configuration import read_configurations
|
from pyvtt.configuration import read_configurations
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
CONFIGURATION = read_configurations()
|
CONFIG = read_configurations()
|
||||||
|
|
||||||
|
|
||||||
def send_cmd(cmd: str, socket_path: str, preset: Optional[str] = None) -> None:
|
def send_cmd(cmd: str, socket_path: str, preset: Optional[str] = None) -> None:
|
||||||
@@ -62,4 +62,4 @@ def main():
|
|||||||
|
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
send_cmd(args.command, CONFIGURATION["socket_path"], args.preset)
|
send_cmd(args.command, CONFIG.socket_path, args.preset)
|
||||||
@@ -10,10 +10,12 @@ from PyQt5.QtWidgets import QApplication, QSystemTrayIcon, QMenu, QAction
|
|||||||
from PyQt5.QtGui import QIcon
|
from PyQt5.QtGui import QIcon
|
||||||
from PyQt5.QtCore import QThread, pyqtSignal
|
from PyQt5.QtCore import QThread, pyqtSignal
|
||||||
from pyvtt.configuration import read_configurations
|
from pyvtt.configuration import read_configurations
|
||||||
from pyvtt.notify import notify, play_sound
|
from pyvtt.libs.notify import notify, play_sound
|
||||||
|
from pyvtt.libs.ollama import OllamaClient
|
||||||
|
from pyvtt.libs.whisper import WhisperClient
|
||||||
|
|
||||||
CONFIGURATION = read_configurations()
|
CONFIG = read_configurations()
|
||||||
CURRENT_PRESET = CONFIGURATION["presets"][0] # Default to first preset
|
CURRENT_PRESET = CONFIG.presets[0] # Default to first preset
|
||||||
|
|
||||||
class WhisperWorker(QThread):
|
class WhisperWorker(QThread):
|
||||||
"""
|
"""
|
||||||
@@ -31,82 +33,28 @@ class WhisperWorker(QThread):
|
|||||||
"""
|
"""
|
||||||
finished = pyqtSignal(str)
|
finished = pyqtSignal(str)
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
self.whisper = WhisperClient(CONFIG)
|
||||||
|
self.ollama = OllamaClient(CONFIG)
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
CURENT_CONFIGURATION_LOCALE = CONFIGURATION
|
CURENT_CONFIG_LOCALE = CONFIG
|
||||||
CURRENT_PRESET_LOCALE = CURRENT_PRESET
|
CURRENT_PRESET_LOCALE = CURRENT_PRESET
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Whisper ausführen
|
raw_result = self.whisper.transcribe(CURRENT_PRESET_LOCALE)
|
||||||
whisper_cmd = [
|
formatted_result = self.ollama.send_chat(raw_result, CURRENT_PRESET_LOCALE)
|
||||||
CURENT_CONFIGURATION_LOCALE["whisper_path"],
|
|
||||||
"-m", CURRENT_PRESET_LOCALE["whisper_model"],
|
|
||||||
"-f", CURENT_CONFIGURATION_LOCALE["audio_file"],
|
|
||||||
"-l", CURRENT_PRESET_LOCALE["language"],
|
|
||||||
"-otxt",
|
|
||||||
"-of", CURENT_CONFIGURATION_LOCALE["output_file"].replace(".txt", "")
|
|
||||||
]
|
|
||||||
try:
|
|
||||||
subprocess.run(whisper_cmd, check=True)
|
|
||||||
except subprocess.CalledProcessError as e:
|
|
||||||
print(f"Whisper Fehler: {e}")
|
|
||||||
notify("Fehler", "Ein Fehler mit 'Whisper' ist aufgetreten!")
|
|
||||||
return
|
|
||||||
|
|
||||||
try:
|
|
||||||
with open(CURENT_CONFIGURATION_LOCALE["output_file"], "r") as f:
|
|
||||||
raw_result = "\n".join(line.strip() for line in f.readlines())
|
|
||||||
except Exception as e:
|
|
||||||
print(f"Datei Fehler: {e}")
|
|
||||||
notify("Fehler", "Ein Fehler beim Lesen der Whisper-Ausgabe ist aufgetreten!")
|
|
||||||
return
|
|
||||||
|
|
||||||
print("Whisper Transkript erhalten.")
|
|
||||||
|
|
||||||
# --- An Ollama schicken ---
|
|
||||||
if CURRENT_PRESET_LOCALE["ollama"] != "disable":
|
|
||||||
if isinstance(CURRENT_PRESET_LOCALE["ollama_prompt"], list):
|
|
||||||
prompt = "\n".join(CURRENT_PRESET_LOCALE["ollama_prompt"])
|
|
||||||
else:
|
|
||||||
prompt = CURRENT_PRESET_LOCALE["ollama_prompt"]
|
|
||||||
|
|
||||||
payload = {
|
|
||||||
"model": CURRENT_PRESET_LOCALE["ollama_model"],
|
|
||||||
"messages": [
|
|
||||||
{"role": "system", "content": prompt},
|
|
||||||
{"role": "user", "content": raw_result}
|
|
||||||
],
|
|
||||||
"options": {
|
|
||||||
"num_ctx": CURRENT_PRESET_LOCALE["ollama_context"]
|
|
||||||
},
|
|
||||||
"stream": False
|
|
||||||
}
|
|
||||||
ollama_endpoint = f"{CURENT_CONFIGURATION_LOCALE['ollama_url']}:{CURENT_CONFIGURATION_LOCALE['ollama_port']}/api/chat"
|
|
||||||
response = requests.post(ollama_endpoint, json=payload)
|
|
||||||
|
|
||||||
try:
|
|
||||||
response.raise_for_status()
|
|
||||||
except requests.exceptions.HTTPError as e:
|
|
||||||
print(f"HTTP Fehler: {e}")
|
|
||||||
notify("Fehler", "Ein Fehler bei der Kommunikation mit 'Ollama' ist aufgetreten!")
|
|
||||||
return
|
|
||||||
|
|
||||||
json_response = response.json()
|
|
||||||
formatted_result = json_response.get("message", {}).get("content", "").strip()
|
|
||||||
formatted_result = "\n".join(line.strip() for line in formatted_result.splitlines())
|
|
||||||
print("Ollama Antwort erhalten.")
|
|
||||||
else:
|
|
||||||
formatted_result = raw_result
|
|
||||||
print("Kein Ollama Prompt angegeben, nur Whisper Ergebnis verwendet.")
|
|
||||||
|
|
||||||
# Ergebnis ins Clipboard kopieren
|
# Ergebnis ins Clipboard kopieren
|
||||||
if CURRENT_PRESET_LOCALE.get("mode") == "journal":
|
if CURRENT_PRESET_LOCALE.mode == "journal":
|
||||||
today = datetime.date.today().strftime("%Y.%m.%d")
|
today = datetime.date.today().strftime("%Y.%m.%d")
|
||||||
journal_path = os.path.join(CURENT_CONFIGURATION_LOCALE["journal_path"], f"{today} - {CURRENT_PRESET_LOCALE['journal_name']}.md")
|
journal_path = os.path.join(CURENT_CONFIG_LOCALE.journal_path, f"{today} - {CURRENT_PRESET_LOCALE.journal_name}.md")
|
||||||
now = datetime.datetime.now().strftime("%H:%M:%S")
|
now = datetime.datetime.now().strftime("%H:%M")
|
||||||
if not os.path.exists(journal_path):
|
if not os.path.exists(journal_path):
|
||||||
try:
|
try:
|
||||||
with open(journal_path, "w") as f:
|
with open(journal_path, "w") as f:
|
||||||
f.write(f"# {CURRENT_PRESET_LOCALE['journal_name']} - {today}\n\n")
|
f.write(f"# {CURRENT_PRESET_LOCALE.journal_name} - {today}\n\n")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Journal Erstellungsfehler: {e}")
|
print(f"Journal Erstellungsfehler: {e}")
|
||||||
notify("Fehler", "Ein Fehler beim Erstellen des Journals ist aufgetreten!")
|
notify("Fehler", "Ein Fehler beim Erstellen des Journals ist aufgetreten!")
|
||||||
@@ -157,11 +105,11 @@ class SocketListener(threading.Thread):
|
|||||||
def __init__(self, tray_app):
|
def __init__(self, tray_app):
|
||||||
super().__init__(daemon=True)
|
super().__init__(daemon=True)
|
||||||
self.tray_app = tray_app
|
self.tray_app = tray_app
|
||||||
if os.path.exists(CONFIGURATION["socket_path"]):
|
if os.path.exists(CONFIG.socket_path):
|
||||||
os.remove(CONFIGURATION["socket_path"])
|
os.remove(CONFIG.socket_path)
|
||||||
self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
||||||
self.sock.bind(CONFIGURATION["socket_path"])
|
self.sock.bind(CONFIG.socket_path)
|
||||||
os.chmod(CONFIGURATION["socket_path"], 0o666)
|
os.chmod(CONFIG.socket_path, 0o666)
|
||||||
self.sock.listen(1)
|
self.sock.listen(1)
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
@@ -174,8 +122,8 @@ class SocketListener(threading.Thread):
|
|||||||
if len(cmd) > 1:
|
if len(cmd) > 1:
|
||||||
data = cmd[0]
|
data = cmd[0]
|
||||||
preset = cmd[1]
|
preset = cmd[1]
|
||||||
if preset in [p["name"] for p in CONFIGURATION["presets"]]:
|
if preset in [p.name for p in CONFIG.presets]:
|
||||||
self.tray_app.set_preset([p["name"] for p in CONFIGURATION["presets"]].index(preset))
|
self.tray_app.set_preset([p.name for p in CONFIG.presets].index(preset))
|
||||||
else:
|
else:
|
||||||
data = cmd[0]
|
data = cmd[0]
|
||||||
if data == "toggle":
|
if data == "toggle":
|
||||||
@@ -224,8 +172,8 @@ class TrayApp:
|
|||||||
# Preset Menü
|
# Preset Menü
|
||||||
self.preset_actions = []
|
self.preset_actions = []
|
||||||
self.preset_group = QMenu("Presets")
|
self.preset_group = QMenu("Presets")
|
||||||
for i, preset in enumerate(CONFIGURATION["presets"]):
|
for i, preset in enumerate(CONFIG.presets):
|
||||||
action = QAction(preset["name"], self.menu)
|
action = QAction(preset.name, self.menu)
|
||||||
action.setCheckable(True)
|
action.setCheckable(True)
|
||||||
if i == 0:
|
if i == 0:
|
||||||
action.setChecked(True)
|
action.setChecked(True)
|
||||||
@@ -255,8 +203,9 @@ class TrayApp:
|
|||||||
|
|
||||||
def set_preset(self, index):
|
def set_preset(self, index):
|
||||||
global CURRENT_PRESET
|
global CURRENT_PRESET
|
||||||
print(f"Preset gewechselt: {CONFIGURATION['presets'][index]['name']}")
|
selected_preset = CONFIG.presets[index]
|
||||||
CURRENT_PRESET = CONFIGURATION["presets"][index]
|
print(f"Preset gewechselt: {selected_preset.name}")
|
||||||
|
CURRENT_PRESET = selected_preset
|
||||||
# Nur einer darf gecheckt sein
|
# Nur einer darf gecheckt sein
|
||||||
for i, action in enumerate(self.preset_actions):
|
for i, action in enumerate(self.preset_actions):
|
||||||
action.setChecked(i == index)
|
action.setChecked(i == index)
|
||||||
@@ -266,7 +215,7 @@ class TrayApp:
|
|||||||
print("Starte Aufnahme...")
|
print("Starte Aufnahme...")
|
||||||
self.recording_process = subprocess.Popen([
|
self.recording_process = subprocess.Popen([
|
||||||
"ffmpeg", "-f", "pulse", "-i", "default", "-ar", "16000",
|
"ffmpeg", "-f", "pulse", "-i", "default", "-ar", "16000",
|
||||||
"-ac", "1", CONFIGURATION["audio_file"], "-y", "-loglevel", "quiet"
|
"-ac", "1", CONFIG.audio_file, "-y", "-loglevel", "quiet"
|
||||||
])
|
])
|
||||||
notify("Aufnahme", "Aufnahme gestartet!")
|
notify("Aufnahme", "Aufnahme gestartet!")
|
||||||
|
|
||||||
@@ -294,15 +243,15 @@ class TrayApp:
|
|||||||
print(f"Fertig:\n{text}")
|
print(f"Fertig:\n{text}")
|
||||||
|
|
||||||
def reload_configurations(self):
|
def reload_configurations(self):
|
||||||
global CONFIGURATION, CURRENT_PRESET
|
global CONFIG, CURRENT_PRESET
|
||||||
print("Lade Einstellungen neu...")
|
print("Lade Einstellungen neu...")
|
||||||
CONFIGURATION = read_configurations()
|
CONFIG = read_configurations()
|
||||||
CURRENT_PRESET = CONFIGURATION["presets"][0] # Default to first preset
|
CURRENT_PRESET = CONFIG.presets[0] # Default to first preset
|
||||||
# Update preset menu
|
# Update preset menu
|
||||||
self.preset_group.clear()
|
self.preset_group.clear()
|
||||||
self.preset_actions = []
|
self.preset_actions = []
|
||||||
for i, preset in enumerate(CONFIGURATION["presets"]):
|
for i, preset in enumerate(CONFIG.presets):
|
||||||
action = QAction(preset["name"], self.menu)
|
action = QAction(preset.name, self.menu)
|
||||||
action.setCheckable(True)
|
action.setCheckable(True)
|
||||||
if i == 0:
|
if i == 0:
|
||||||
action.setChecked(True)
|
action.setChecked(True)
|
||||||
@@ -312,8 +261,8 @@ class TrayApp:
|
|||||||
print("Einstellungen erfolgreich neu geladen.")
|
print("Einstellungen erfolgreich neu geladen.")
|
||||||
|
|
||||||
def cleanup(self):
|
def cleanup(self):
|
||||||
if os.path.exists(CONFIGURATION["socket_path"]):
|
if os.path.exists(CONFIG.socket_path):
|
||||||
os.remove(CONFIGURATION["socket_path"])
|
os.remove(CONFIG.socket_path)
|
||||||
print("Socket sauber entfernt.")
|
print("Socket sauber entfernt.")
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
|
|||||||
Reference in New Issue
Block a user