Spaces:
Sleeping
Sleeping
Aryan Jain commited on
Commit ·
e1fb2f2
1
Parent(s): 94e433b
add tool calls and implemented knowledge base
Browse files- .env.example +12 -1
- poetry.lock +212 -1
- pyproject.toml +4 -0
- scrapped.txt +0 -0
- src/app.py +3 -2
- src/controllers/__init__.py +3 -0
- src/controllers/_database_controller.py +7 -2
- src/controllers/_file_controller.py +33 -0
- src/crawler/_database_updater.py +56 -5
- src/services/__init__.py +3 -1
- src/services/_chat_service.py +1 -6
- src/services/_database_service.py +16 -7
- src/services/_file_service.py +17 -0
- src/utils/__init__.py +6 -0
- src/utils/_chat_client.py +139 -23
- src/utils/_email_client.py +54 -0
- src/utils/_pinecone_client.py +5 -2
- src/utils/_sharepoint_client.py +55 -0
- src/utils/_tool_call.py +21 -0
.env.example
CHANGED
|
@@ -1,4 +1,15 @@
|
|
| 1 |
LOG_FILE=
|
| 2 |
PINECONE_API_KEY=
|
| 3 |
PINECONE_INDEX_NAME=
|
| 4 |
-
GROQ_API_KEY=
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
LOG_FILE=
|
| 2 |
PINECONE_API_KEY=
|
| 3 |
PINECONE_INDEX_NAME=
|
| 4 |
+
GROQ_API_KEY=
|
| 5 |
+
RECIPIENT_EMAIL=
|
| 6 |
+
SENDER_EMAIL=
|
| 7 |
+
SMTP_HOST=
|
| 8 |
+
SMTP_PORT=
|
| 9 |
+
SMTP_USERNAME=
|
| 10 |
+
SMTP_PASSWORD=
|
| 11 |
+
AZURE_TENANT_ID=
|
| 12 |
+
AZURE_CLIENT_ID=
|
| 13 |
+
AZURE_CLIENT_SECRET=
|
| 14 |
+
AZURE_SCOPE=https://graph.microsoft.com/.default
|
| 15 |
+
AZURE_DRIVE_ID=
|
poetry.lock
CHANGED
|
@@ -827,6 +827,160 @@ win32-setctime = {version = ">=1.0.0", markers = "sys_platform == \"win32\""}
|
|
| 827 |
[package.extras]
|
| 828 |
dev = ["Sphinx (==7.2.5)", "colorama (==0.4.5)", "colorama (==0.4.6)", "exceptiongroup (==1.1.3)", "freezegun (==1.1.0)", "freezegun (==1.2.2)", "mypy (==v0.910)", "mypy (==v0.971)", "mypy (==v1.4.1)", "mypy (==v1.5.1)", "pre-commit (==3.4.0)", "pytest (==6.1.2)", "pytest (==7.4.0)", "pytest-cov (==2.12.1)", "pytest-cov (==4.1.0)", "pytest-mypy-plugins (==1.9.3)", "pytest-mypy-plugins (==3.0.0)", "sphinx-autobuild (==2021.3.14)", "sphinx-rtd-theme (==1.3.0)", "tox (==3.27.1)", "tox (==4.11.0)"]
|
| 829 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 830 |
[[package]]
|
| 831 |
name = "lz4"
|
| 832 |
version = "4.3.3"
|
|
@@ -1233,6 +1387,37 @@ files = [
|
|
| 1233 |
[package.dependencies]
|
| 1234 |
typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0"
|
| 1235 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1236 |
[[package]]
|
| 1237 |
name = "pysocks"
|
| 1238 |
version = "1.7.1"
|
|
@@ -1245,6 +1430,21 @@ files = [
|
|
| 1245 |
{file = "PySocks-1.7.1.tar.gz", hash = "sha256:3f8804571ebe159c380ac6de37643bb4685970655d3bba243530d6558b799aa0"},
|
| 1246 |
]
|
| 1247 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1248 |
[[package]]
|
| 1249 |
name = "python-dotenv"
|
| 1250 |
version = "1.0.1"
|
|
@@ -1259,6 +1459,17 @@ files = [
|
|
| 1259 |
[package.extras]
|
| 1260 |
cli = ["click (>=5.0)"]
|
| 1261 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1262 |
[[package]]
|
| 1263 |
name = "pyyaml"
|
| 1264 |
version = "6.0.2"
|
|
@@ -2040,4 +2251,4 @@ h11 = ">=0.9.0,<1"
|
|
| 2040 |
[metadata]
|
| 2041 |
lock-version = "2.0"
|
| 2042 |
python-versions = "3.11.*"
|
| 2043 |
-
content-hash = "
|
|
|
|
| 827 |
[package.extras]
|
| 828 |
dev = ["Sphinx (==7.2.5)", "colorama (==0.4.5)", "colorama (==0.4.6)", "exceptiongroup (==1.1.3)", "freezegun (==1.1.0)", "freezegun (==1.2.2)", "mypy (==v0.910)", "mypy (==v0.971)", "mypy (==v1.4.1)", "mypy (==v1.5.1)", "pre-commit (==3.4.0)", "pytest (==6.1.2)", "pytest (==7.4.0)", "pytest-cov (==2.12.1)", "pytest-cov (==4.1.0)", "pytest-mypy-plugins (==1.9.3)", "pytest-mypy-plugins (==3.0.0)", "sphinx-autobuild (==2021.3.14)", "sphinx-rtd-theme (==1.3.0)", "tox (==3.27.1)", "tox (==4.11.0)"]
|
| 829 |
|
| 830 |
+
[[package]]
|
| 831 |
+
name = "lxml"
|
| 832 |
+
version = "5.3.0"
|
| 833 |
+
description = "Powerful and Pythonic XML processing library combining libxml2/libxslt with the ElementTree API."
|
| 834 |
+
optional = false
|
| 835 |
+
python-versions = ">=3.6"
|
| 836 |
+
files = [
|
| 837 |
+
{file = "lxml-5.3.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:dd36439be765e2dde7660212b5275641edbc813e7b24668831a5c8ac91180656"},
|
| 838 |
+
{file = "lxml-5.3.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ae5fe5c4b525aa82b8076c1a59d642c17b6e8739ecf852522c6321852178119d"},
|
| 839 |
+
{file = "lxml-5.3.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:501d0d7e26b4d261fca8132854d845e4988097611ba2531408ec91cf3fd9d20a"},
|
| 840 |
+
{file = "lxml-5.3.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb66442c2546446944437df74379e9cf9e9db353e61301d1a0e26482f43f0dd8"},
|
| 841 |
+
{file = "lxml-5.3.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9e41506fec7a7f9405b14aa2d5c8abbb4dbbd09d88f9496958b6d00cb4d45330"},
|
| 842 |
+
{file = "lxml-5.3.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f7d4a670107d75dfe5ad080bed6c341d18c4442f9378c9f58e5851e86eb79965"},
|
| 843 |
+
{file = "lxml-5.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:41ce1f1e2c7755abfc7e759dc34d7d05fd221723ff822947132dc934d122fe22"},
|
| 844 |
+
{file = "lxml-5.3.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:44264ecae91b30e5633013fb66f6ddd05c006d3e0e884f75ce0b4755b3e3847b"},
|
| 845 |
+
{file = "lxml-5.3.0-cp310-cp310-manylinux_2_28_ppc64le.whl", hash = "sha256:3c174dc350d3ec52deb77f2faf05c439331d6ed5e702fc247ccb4e6b62d884b7"},
|
| 846 |
+
{file = "lxml-5.3.0-cp310-cp310-manylinux_2_28_s390x.whl", hash = "sha256:2dfab5fa6a28a0b60a20638dc48e6343c02ea9933e3279ccb132f555a62323d8"},
|
| 847 |
+
{file = "lxml-5.3.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:b1c8c20847b9f34e98080da785bb2336ea982e7f913eed5809e5a3c872900f32"},
|
| 848 |
+
{file = "lxml-5.3.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:2c86bf781b12ba417f64f3422cfc302523ac9cd1d8ae8c0f92a1c66e56ef2e86"},
|
| 849 |
+
{file = "lxml-5.3.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:c162b216070f280fa7da844531169be0baf9ccb17263cf5a8bf876fcd3117fa5"},
|
| 850 |
+
{file = "lxml-5.3.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:36aef61a1678cb778097b4a6eeae96a69875d51d1e8f4d4b491ab3cfb54b5a03"},
|
| 851 |
+
{file = "lxml-5.3.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f65e5120863c2b266dbcc927b306c5b78e502c71edf3295dfcb9501ec96e5fc7"},
|
| 852 |
+
{file = "lxml-5.3.0-cp310-cp310-win32.whl", hash = "sha256:ef0c1fe22171dd7c7c27147f2e9c3e86f8bdf473fed75f16b0c2e84a5030ce80"},
|
| 853 |
+
{file = "lxml-5.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:052d99051e77a4f3e8482c65014cf6372e61b0a6f4fe9edb98503bb5364cfee3"},
|
| 854 |
+
{file = "lxml-5.3.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:74bcb423462233bc5d6066e4e98b0264e7c1bed7541fff2f4e34fe6b21563c8b"},
|
| 855 |
+
{file = "lxml-5.3.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a3d819eb6f9b8677f57f9664265d0a10dd6551d227afb4af2b9cd7bdc2ccbf18"},
|
| 856 |
+
{file = "lxml-5.3.0-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5b8f5db71b28b8c404956ddf79575ea77aa8b1538e8b2ef9ec877945b3f46442"},
|
| 857 |
+
{file = "lxml-5.3.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2c3406b63232fc7e9b8783ab0b765d7c59e7c59ff96759d8ef9632fca27c7ee4"},
|
| 858 |
+
{file = "lxml-5.3.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2ecdd78ab768f844c7a1d4a03595038c166b609f6395e25af9b0f3f26ae1230f"},
|
| 859 |
+
{file = "lxml-5.3.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:168f2dfcfdedf611eb285efac1516c8454c8c99caf271dccda8943576b67552e"},
|
| 860 |
+
{file = "lxml-5.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa617107a410245b8660028a7483b68e7914304a6d4882b5ff3d2d3eb5948d8c"},
|
| 861 |
+
{file = "lxml-5.3.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:69959bd3167b993e6e710b99051265654133a98f20cec1d9b493b931942e9c16"},
|
| 862 |
+
{file = "lxml-5.3.0-cp311-cp311-manylinux_2_28_ppc64le.whl", hash = "sha256:bd96517ef76c8654446fc3db9242d019a1bb5fe8b751ba414765d59f99210b79"},
|
| 863 |
+
{file = "lxml-5.3.0-cp311-cp311-manylinux_2_28_s390x.whl", hash = "sha256:ab6dd83b970dc97c2d10bc71aa925b84788c7c05de30241b9e96f9b6d9ea3080"},
|
| 864 |
+
{file = "lxml-5.3.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:eec1bb8cdbba2925bedc887bc0609a80e599c75b12d87ae42ac23fd199445654"},
|
| 865 |
+
{file = "lxml-5.3.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6a7095eeec6f89111d03dabfe5883a1fd54da319c94e0fb104ee8f23616b572d"},
|
| 866 |
+
{file = "lxml-5.3.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:6f651ebd0b21ec65dfca93aa629610a0dbc13dbc13554f19b0113da2e61a4763"},
|
| 867 |
+
{file = "lxml-5.3.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:f422a209d2455c56849442ae42f25dbaaba1c6c3f501d58761c619c7836642ec"},
|
| 868 |
+
{file = "lxml-5.3.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:62f7fdb0d1ed2065451f086519865b4c90aa19aed51081979ecd05a21eb4d1be"},
|
| 869 |
+
{file = "lxml-5.3.0-cp311-cp311-win32.whl", hash = "sha256:c6379f35350b655fd817cd0d6cbeef7f265f3ae5fedb1caae2eb442bbeae9ab9"},
|
| 870 |
+
{file = "lxml-5.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:9c52100e2c2dbb0649b90467935c4b0de5528833c76a35ea1a2691ec9f1ee7a1"},
|
| 871 |
+
{file = "lxml-5.3.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:e99f5507401436fdcc85036a2e7dc2e28d962550afe1cbfc07c40e454256a859"},
|
| 872 |
+
{file = "lxml-5.3.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:384aacddf2e5813a36495233b64cb96b1949da72bef933918ba5c84e06af8f0e"},
|
| 873 |
+
{file = "lxml-5.3.0-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:874a216bf6afaf97c263b56371434e47e2c652d215788396f60477540298218f"},
|
| 874 |
+
{file = "lxml-5.3.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:65ab5685d56914b9a2a34d67dd5488b83213d680b0c5d10b47f81da5a16b0b0e"},
|
| 875 |
+
{file = "lxml-5.3.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:aac0bbd3e8dd2d9c45ceb82249e8bdd3ac99131a32b4d35c8af3cc9db1657179"},
|
| 876 |
+
{file = "lxml-5.3.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b369d3db3c22ed14c75ccd5af429086f166a19627e84a8fdade3f8f31426e52a"},
|
| 877 |
+
{file = "lxml-5.3.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c24037349665434f375645fa9d1f5304800cec574d0310f618490c871fd902b3"},
|
| 878 |
+
{file = "lxml-5.3.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:62d172f358f33a26d6b41b28c170c63886742f5b6772a42b59b4f0fa10526cb1"},
|
| 879 |
+
{file = "lxml-5.3.0-cp312-cp312-manylinux_2_28_ppc64le.whl", hash = "sha256:c1f794c02903c2824fccce5b20c339a1a14b114e83b306ff11b597c5f71a1c8d"},
|
| 880 |
+
{file = "lxml-5.3.0-cp312-cp312-manylinux_2_28_s390x.whl", hash = "sha256:5d6a6972b93c426ace71e0be9a6f4b2cfae9b1baed2eed2006076a746692288c"},
|
| 881 |
+
{file = "lxml-5.3.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:3879cc6ce938ff4eb4900d901ed63555c778731a96365e53fadb36437a131a99"},
|
| 882 |
+
{file = "lxml-5.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:74068c601baff6ff021c70f0935b0c7bc528baa8ea210c202e03757c68c5a4ff"},
|
| 883 |
+
{file = "lxml-5.3.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:ecd4ad8453ac17bc7ba3868371bffb46f628161ad0eefbd0a855d2c8c32dd81a"},
|
| 884 |
+
{file = "lxml-5.3.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:7e2f58095acc211eb9d8b5771bf04df9ff37d6b87618d1cbf85f92399c98dae8"},
|
| 885 |
+
{file = "lxml-5.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e63601ad5cd8f860aa99d109889b5ac34de571c7ee902d6812d5d9ddcc77fa7d"},
|
| 886 |
+
{file = "lxml-5.3.0-cp312-cp312-win32.whl", hash = "sha256:17e8d968d04a37c50ad9c456a286b525d78c4a1c15dd53aa46c1d8e06bf6fa30"},
|
| 887 |
+
{file = "lxml-5.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:c1a69e58a6bb2de65902051d57fde951febad631a20a64572677a1052690482f"},
|
| 888 |
+
{file = "lxml-5.3.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:8c72e9563347c7395910de6a3100a4840a75a6f60e05af5e58566868d5eb2d6a"},
|
| 889 |
+
{file = "lxml-5.3.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e92ce66cd919d18d14b3856906a61d3f6b6a8500e0794142338da644260595cd"},
|
| 890 |
+
{file = "lxml-5.3.0-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1d04f064bebdfef9240478f7a779e8c5dc32b8b7b0b2fc6a62e39b928d428e51"},
|
| 891 |
+
{file = "lxml-5.3.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5c2fb570d7823c2bbaf8b419ba6e5662137f8166e364a8b2b91051a1fb40ab8b"},
|
| 892 |
+
{file = "lxml-5.3.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0c120f43553ec759f8de1fee2f4794452b0946773299d44c36bfe18e83caf002"},
|
| 893 |
+
{file = "lxml-5.3.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:562e7494778a69086f0312ec9689f6b6ac1c6b65670ed7d0267e49f57ffa08c4"},
|
| 894 |
+
{file = "lxml-5.3.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:423b121f7e6fa514ba0c7918e56955a1d4470ed35faa03e3d9f0e3baa4c7e492"},
|
| 895 |
+
{file = "lxml-5.3.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:c00f323cc00576df6165cc9d21a4c21285fa6b9989c5c39830c3903dc4303ef3"},
|
| 896 |
+
{file = "lxml-5.3.0-cp313-cp313-manylinux_2_28_ppc64le.whl", hash = "sha256:1fdc9fae8dd4c763e8a31e7630afef517eab9f5d5d31a278df087f307bf601f4"},
|
| 897 |
+
{file = "lxml-5.3.0-cp313-cp313-manylinux_2_28_s390x.whl", hash = "sha256:658f2aa69d31e09699705949b5fc4719cbecbd4a97f9656a232e7d6c7be1a367"},
|
| 898 |
+
{file = "lxml-5.3.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:1473427aff3d66a3fa2199004c3e601e6c4500ab86696edffdbc84954c72d832"},
|
| 899 |
+
{file = "lxml-5.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a87de7dd873bf9a792bf1e58b1c3887b9264036629a5bf2d2e6579fe8e73edff"},
|
| 900 |
+
{file = "lxml-5.3.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:0d7b36afa46c97875303a94e8f3ad932bf78bace9e18e603f2085b652422edcd"},
|
| 901 |
+
{file = "lxml-5.3.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:cf120cce539453ae086eacc0130a324e7026113510efa83ab42ef3fcfccac7fb"},
|
| 902 |
+
{file = "lxml-5.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:df5c7333167b9674aa8ae1d4008fa4bc17a313cc490b2cca27838bbdcc6bb15b"},
|
| 903 |
+
{file = "lxml-5.3.0-cp313-cp313-win32.whl", hash = "sha256:c802e1c2ed9f0c06a65bc4ed0189d000ada8049312cfeab6ca635e39c9608957"},
|
| 904 |
+
{file = "lxml-5.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:406246b96d552e0503e17a1006fd27edac678b3fcc9f1be71a2f94b4ff61528d"},
|
| 905 |
+
{file = "lxml-5.3.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:8f0de2d390af441fe8b2c12626d103540b5d850d585b18fcada58d972b74a74e"},
|
| 906 |
+
{file = "lxml-5.3.0-cp36-cp36m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1afe0a8c353746e610bd9031a630a95bcfb1a720684c3f2b36c4710a0a96528f"},
|
| 907 |
+
{file = "lxml-5.3.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:56b9861a71575f5795bde89256e7467ece3d339c9b43141dbdd54544566b3b94"},
|
| 908 |
+
{file = "lxml-5.3.0-cp36-cp36m-manylinux_2_28_x86_64.whl", hash = "sha256:9fb81d2824dff4f2e297a276297e9031f46d2682cafc484f49de182aa5e5df99"},
|
| 909 |
+
{file = "lxml-5.3.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:2c226a06ecb8cdef28845ae976da407917542c5e6e75dcac7cc33eb04aaeb237"},
|
| 910 |
+
{file = "lxml-5.3.0-cp36-cp36m-musllinux_1_2_x86_64.whl", hash = "sha256:7d3d1ca42870cdb6d0d29939630dbe48fa511c203724820fc0fd507b2fb46577"},
|
| 911 |
+
{file = "lxml-5.3.0-cp36-cp36m-win32.whl", hash = "sha256:094cb601ba9f55296774c2d57ad68730daa0b13dc260e1f941b4d13678239e70"},
|
| 912 |
+
{file = "lxml-5.3.0-cp36-cp36m-win_amd64.whl", hash = "sha256:eafa2c8658f4e560b098fe9fc54539f86528651f61849b22111a9b107d18910c"},
|
| 913 |
+
{file = "lxml-5.3.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:cb83f8a875b3d9b458cada4f880fa498646874ba4011dc974e071a0a84a1b033"},
|
| 914 |
+
{file = "lxml-5.3.0-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:25f1b69d41656b05885aa185f5fdf822cb01a586d1b32739633679699f220391"},
|
| 915 |
+
{file = "lxml-5.3.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:23e0553b8055600b3bf4a00b255ec5c92e1e4aebf8c2c09334f8368e8bd174d6"},
|
| 916 |
+
{file = "lxml-5.3.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9ada35dd21dc6c039259596b358caab6b13f4db4d4a7f8665764d616daf9cc1d"},
|
| 917 |
+
{file = "lxml-5.3.0-cp37-cp37m-manylinux_2_28_aarch64.whl", hash = "sha256:81b4e48da4c69313192d8c8d4311e5d818b8be1afe68ee20f6385d0e96fc9512"},
|
| 918 |
+
{file = "lxml-5.3.0-cp37-cp37m-manylinux_2_28_x86_64.whl", hash = "sha256:2bc9fd5ca4729af796f9f59cd8ff160fe06a474da40aca03fcc79655ddee1a8b"},
|
| 919 |
+
{file = "lxml-5.3.0-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:07da23d7ee08577760f0a71d67a861019103e4812c87e2fab26b039054594cc5"},
|
| 920 |
+
{file = "lxml-5.3.0-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:ea2e2f6f801696ad7de8aec061044d6c8c0dd4037608c7cab38a9a4d316bfb11"},
|
| 921 |
+
{file = "lxml-5.3.0-cp37-cp37m-win32.whl", hash = "sha256:5c54afdcbb0182d06836cc3d1be921e540be3ebdf8b8a51ee3ef987537455f84"},
|
| 922 |
+
{file = "lxml-5.3.0-cp37-cp37m-win_amd64.whl", hash = "sha256:f2901429da1e645ce548bf9171784c0f74f0718c3f6150ce166be39e4dd66c3e"},
|
| 923 |
+
{file = "lxml-5.3.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:c56a1d43b2f9ee4786e4658c7903f05da35b923fb53c11025712562d5cc02753"},
|
| 924 |
+
{file = "lxml-5.3.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ee8c39582d2652dcd516d1b879451500f8db3fe3607ce45d7c5957ab2596040"},
|
| 925 |
+
{file = "lxml-5.3.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0fdf3a3059611f7585a78ee10399a15566356116a4288380921a4b598d807a22"},
|
| 926 |
+
{file = "lxml-5.3.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:146173654d79eb1fc97498b4280c1d3e1e5d58c398fa530905c9ea50ea849b22"},
|
| 927 |
+
{file = "lxml-5.3.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:0a7056921edbdd7560746f4221dca89bb7a3fe457d3d74267995253f46343f15"},
|
| 928 |
+
{file = "lxml-5.3.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:9e4b47ac0f5e749cfc618efdf4726269441014ae1d5583e047b452a32e221920"},
|
| 929 |
+
{file = "lxml-5.3.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:f914c03e6a31deb632e2daa881fe198461f4d06e57ac3d0e05bbcab8eae01945"},
|
| 930 |
+
{file = "lxml-5.3.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:213261f168c5e1d9b7535a67e68b1f59f92398dd17a56d934550837143f79c42"},
|
| 931 |
+
{file = "lxml-5.3.0-cp38-cp38-win32.whl", hash = "sha256:218c1b2e17a710e363855594230f44060e2025b05c80d1f0661258142b2add2e"},
|
| 932 |
+
{file = "lxml-5.3.0-cp38-cp38-win_amd64.whl", hash = "sha256:315f9542011b2c4e1d280e4a20ddcca1761993dda3afc7a73b01235f8641e903"},
|
| 933 |
+
{file = "lxml-5.3.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:1ffc23010330c2ab67fac02781df60998ca8fe759e8efde6f8b756a20599c5de"},
|
| 934 |
+
{file = "lxml-5.3.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2b3778cb38212f52fac9fe913017deea2fdf4eb1a4f8e4cfc6b009a13a6d3fcc"},
|
| 935 |
+
{file = "lxml-5.3.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4b0c7a688944891086ba192e21c5229dea54382f4836a209ff8d0a660fac06be"},
|
| 936 |
+
{file = "lxml-5.3.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:747a3d3e98e24597981ca0be0fd922aebd471fa99d0043a3842d00cdcad7ad6a"},
|
| 937 |
+
{file = "lxml-5.3.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:86a6b24b19eaebc448dc56b87c4865527855145d851f9fc3891673ff97950540"},
|
| 938 |
+
{file = "lxml-5.3.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b11a5d918a6216e521c715b02749240fb07ae5a1fefd4b7bf12f833bc8b4fe70"},
|
| 939 |
+
{file = "lxml-5.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:68b87753c784d6acb8a25b05cb526c3406913c9d988d51f80adecc2b0775d6aa"},
|
| 940 |
+
{file = "lxml-5.3.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:109fa6fede314cc50eed29e6e56c540075e63d922455346f11e4d7a036d2b8cf"},
|
| 941 |
+
{file = "lxml-5.3.0-cp39-cp39-manylinux_2_28_ppc64le.whl", hash = "sha256:02ced472497b8362c8e902ade23e3300479f4f43e45f4105c85ef43b8db85229"},
|
| 942 |
+
{file = "lxml-5.3.0-cp39-cp39-manylinux_2_28_s390x.whl", hash = "sha256:6b038cc86b285e4f9fea2ba5ee76e89f21ed1ea898e287dc277a25884f3a7dfe"},
|
| 943 |
+
{file = "lxml-5.3.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:7437237c6a66b7ca341e868cda48be24b8701862757426852c9b3186de1da8a2"},
|
| 944 |
+
{file = "lxml-5.3.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:7f41026c1d64043a36fda21d64c5026762d53a77043e73e94b71f0521939cc71"},
|
| 945 |
+
{file = "lxml-5.3.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:482c2f67761868f0108b1743098640fbb2a28a8e15bf3f47ada9fa59d9fe08c3"},
|
| 946 |
+
{file = "lxml-5.3.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:1483fd3358963cc5c1c9b122c80606a3a79ee0875bcac0204149fa09d6ff2727"},
|
| 947 |
+
{file = "lxml-5.3.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:2dec2d1130a9cda5b904696cec33b2cfb451304ba9081eeda7f90f724097300a"},
|
| 948 |
+
{file = "lxml-5.3.0-cp39-cp39-win32.whl", hash = "sha256:a0eabd0a81625049c5df745209dc7fcef6e2aea7793e5f003ba363610aa0a3ff"},
|
| 949 |
+
{file = "lxml-5.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:89e043f1d9d341c52bf2af6d02e6adde62e0a46e6755d5eb60dc6e4f0b8aeca2"},
|
| 950 |
+
{file = "lxml-5.3.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:7b1cd427cb0d5f7393c31b7496419da594fe600e6fdc4b105a54f82405e6626c"},
|
| 951 |
+
{file = "lxml-5.3.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:51806cfe0279e06ed8500ce19479d757db42a30fd509940b1701be9c86a5ff9a"},
|
| 952 |
+
{file = "lxml-5.3.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ee70d08fd60c9565ba8190f41a46a54096afa0eeb8f76bd66f2c25d3b1b83005"},
|
| 953 |
+
{file = "lxml-5.3.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:8dc2c0395bea8254d8daebc76dcf8eb3a95ec2a46fa6fae5eaccee366bfe02ce"},
|
| 954 |
+
{file = "lxml-5.3.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:6ba0d3dcac281aad8a0e5b14c7ed6f9fa89c8612b47939fc94f80b16e2e9bc83"},
|
| 955 |
+
{file = "lxml-5.3.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:6e91cf736959057f7aac7adfc83481e03615a8e8dd5758aa1d95ea69e8931dba"},
|
| 956 |
+
{file = "lxml-5.3.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:94d6c3782907b5e40e21cadf94b13b0842ac421192f26b84c45f13f3c9d5dc27"},
|
| 957 |
+
{file = "lxml-5.3.0-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c300306673aa0f3ed5ed9372b21867690a17dba38c68c44b287437c362ce486b"},
|
| 958 |
+
{file = "lxml-5.3.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78d9b952e07aed35fe2e1a7ad26e929595412db48535921c5013edc8aa4a35ce"},
|
| 959 |
+
{file = "lxml-5.3.0-pp37-pypy37_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:01220dca0d066d1349bd6a1726856a78f7929f3878f7e2ee83c296c69495309e"},
|
| 960 |
+
{file = "lxml-5.3.0-pp37-pypy37_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:2d9b8d9177afaef80c53c0a9e30fa252ff3036fb1c6494d427c066a4ce6a282f"},
|
| 961 |
+
{file = "lxml-5.3.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:20094fc3f21ea0a8669dc4c61ed7fa8263bd37d97d93b90f28fc613371e7a875"},
|
| 962 |
+
{file = "lxml-5.3.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:ace2c2326a319a0bb8a8b0e5b570c764962e95818de9f259ce814ee666603f19"},
|
| 963 |
+
{file = "lxml-5.3.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:92e67a0be1639c251d21e35fe74df6bcc40cba445c2cda7c4a967656733249e2"},
|
| 964 |
+
{file = "lxml-5.3.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd5350b55f9fecddc51385463a4f67a5da829bc741e38cf689f38ec9023f54ab"},
|
| 965 |
+
{file = "lxml-5.3.0-pp38-pypy38_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:4c1fefd7e3d00921c44dc9ca80a775af49698bbfd92ea84498e56acffd4c5469"},
|
| 966 |
+
{file = "lxml-5.3.0-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:71a8dd38fbd2f2319136d4ae855a7078c69c9a38ae06e0c17c73fd70fc6caad8"},
|
| 967 |
+
{file = "lxml-5.3.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:97acf1e1fd66ab53dacd2c35b319d7e548380c2e9e8c54525c6e76d21b1ae3b1"},
|
| 968 |
+
{file = "lxml-5.3.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:68934b242c51eb02907c5b81d138cb977b2129a0a75a8f8b60b01cb8586c7b21"},
|
| 969 |
+
{file = "lxml-5.3.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b710bc2b8292966b23a6a0121f7a6c51d45d2347edcc75f016ac123b8054d3f2"},
|
| 970 |
+
{file = "lxml-5.3.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:18feb4b93302091b1541221196a2155aa296c363fd233814fa11e181adebc52f"},
|
| 971 |
+
{file = "lxml-5.3.0-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:3eb44520c4724c2e1a57c0af33a379eee41792595023f367ba3952a2d96c2aab"},
|
| 972 |
+
{file = "lxml-5.3.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:609251a0ca4770e5a8768ff902aa02bf636339c5a93f9349b48eb1f606f7f3e9"},
|
| 973 |
+
{file = "lxml-5.3.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:516f491c834eb320d6c843156440fe7fc0d50b33e44387fcec5b02f0bc118a4c"},
|
| 974 |
+
{file = "lxml-5.3.0.tar.gz", hash = "sha256:4e109ca30d1edec1ac60cdbe341905dc3b8f55b16855e03a54aaf59e51ec8c6f"},
|
| 975 |
+
]
|
| 976 |
+
|
| 977 |
+
[package.extras]
|
| 978 |
+
cssselect = ["cssselect (>=0.7)"]
|
| 979 |
+
html-clean = ["lxml-html-clean"]
|
| 980 |
+
html5 = ["html5lib"]
|
| 981 |
+
htmlsoup = ["BeautifulSoup4"]
|
| 982 |
+
source = ["Cython (>=3.0.11)"]
|
| 983 |
+
|
| 984 |
[[package]]
|
| 985 |
name = "lz4"
|
| 986 |
version = "4.3.3"
|
|
|
|
| 1387 |
[package.dependencies]
|
| 1388 |
typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0"
|
| 1389 |
|
| 1390 |
+
[[package]]
|
| 1391 |
+
name = "pymupdf"
|
| 1392 |
+
version = "1.24.13"
|
| 1393 |
+
description = "A high performance Python library for data extraction, analysis, conversion & manipulation of PDF (and other) documents."
|
| 1394 |
+
optional = false
|
| 1395 |
+
python-versions = ">=3.9"
|
| 1396 |
+
files = [
|
| 1397 |
+
{file = "PyMuPDF-1.24.13-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:c11bb9198af69d490b4b346421db827d875a28fbc760d239e691d4b3ed12b5ad"},
|
| 1398 |
+
{file = "PyMuPDF-1.24.13-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:240d5c43daa9278db50d609162b48f673ab256d7e5c73eea67af517c1fc2d47c"},
|
| 1399 |
+
{file = "PyMuPDF-1.24.13-cp39-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:e4c8808e62afbbde0f7b9c4151c4b1a5735911c2d39c34332860df600dba76f8"},
|
| 1400 |
+
{file = "PyMuPDF-1.24.13-cp39-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c830610e4fde237fcf0532f1f8c1381453f48c164a5eadd0c6e5fd0bea1ca8e3"},
|
| 1401 |
+
{file = "PyMuPDF-1.24.13-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:4520558580ac6b5a7164fda29fbc14e39d3114fd803420721500edbf47d04872"},
|
| 1402 |
+
{file = "PyMuPDF-1.24.13-cp39-abi3-win32.whl", hash = "sha256:ab22828d4fc205791ef1332a64893cbfc38cd9c331c5f46ae4537372ffee6fc1"},
|
| 1403 |
+
{file = "PyMuPDF-1.24.13-cp39-abi3-win_amd64.whl", hash = "sha256:ec17914e4a560f4070212a2e84db5cc8b561d85d1ead193605a22f9561b03148"},
|
| 1404 |
+
{file = "PyMuPDF-1.24.13.tar.gz", hash = "sha256:6ec3ab3c6d5cba60bfcf58daaa2d1a5b700b0366ce52be666445007351461fa4"},
|
| 1405 |
+
]
|
| 1406 |
+
|
| 1407 |
+
[[package]]
|
| 1408 |
+
name = "pymupdf4llm"
|
| 1409 |
+
version = "0.0.17"
|
| 1410 |
+
description = "PyMuPDF Utilities for LLM/RAG"
|
| 1411 |
+
optional = false
|
| 1412 |
+
python-versions = "*"
|
| 1413 |
+
files = [
|
| 1414 |
+
{file = "pymupdf4llm-0.0.17-py3-none-any.whl", hash = "sha256:26de9996945f15e3ca507908f80dc18a959f5b5214bb2e302c7f7034089665a0"},
|
| 1415 |
+
{file = "pymupdf4llm-0.0.17.tar.gz", hash = "sha256:27287ef9fe0217cf37841a3ef2bcf70da2553c43d95ea39b664a6de6485678c3"},
|
| 1416 |
+
]
|
| 1417 |
+
|
| 1418 |
+
[package.dependencies]
|
| 1419 |
+
pymupdf = ">=1.24.10"
|
| 1420 |
+
|
| 1421 |
[[package]]
|
| 1422 |
name = "pysocks"
|
| 1423 |
version = "1.7.1"
|
|
|
|
| 1430 |
{file = "PySocks-1.7.1.tar.gz", hash = "sha256:3f8804571ebe159c380ac6de37643bb4685970655d3bba243530d6558b799aa0"},
|
| 1431 |
]
|
| 1432 |
|
| 1433 |
+
[[package]]
|
| 1434 |
+
name = "python-docx"
|
| 1435 |
+
version = "1.1.2"
|
| 1436 |
+
description = "Create, read, and update Microsoft Word .docx files."
|
| 1437 |
+
optional = false
|
| 1438 |
+
python-versions = ">=3.7"
|
| 1439 |
+
files = [
|
| 1440 |
+
{file = "python_docx-1.1.2-py3-none-any.whl", hash = "sha256:08c20d6058916fb19853fcf080f7f42b6270d89eac9fa5f8c15f691c0017fabe"},
|
| 1441 |
+
{file = "python_docx-1.1.2.tar.gz", hash = "sha256:0cf1f22e95b9002addca7948e16f2cd7acdfd498047f1941ca5d293db7762efd"},
|
| 1442 |
+
]
|
| 1443 |
+
|
| 1444 |
+
[package.dependencies]
|
| 1445 |
+
lxml = ">=3.1.0"
|
| 1446 |
+
typing-extensions = ">=4.9.0"
|
| 1447 |
+
|
| 1448 |
[[package]]
|
| 1449 |
name = "python-dotenv"
|
| 1450 |
version = "1.0.1"
|
|
|
|
| 1459 |
[package.extras]
|
| 1460 |
cli = ["click (>=5.0)"]
|
| 1461 |
|
| 1462 |
+
[[package]]
|
| 1463 |
+
name = "python-multipart"
|
| 1464 |
+
version = "0.0.17"
|
| 1465 |
+
description = "A streaming multipart parser for Python"
|
| 1466 |
+
optional = false
|
| 1467 |
+
python-versions = ">=3.8"
|
| 1468 |
+
files = [
|
| 1469 |
+
{file = "python_multipart-0.0.17-py3-none-any.whl", hash = "sha256:15dc4f487e0a9476cc1201261188ee0940165cffc94429b6fc565c4d3045cb5d"},
|
| 1470 |
+
{file = "python_multipart-0.0.17.tar.gz", hash = "sha256:41330d831cae6e2f22902704ead2826ea038d0419530eadff3ea80175aec5538"},
|
| 1471 |
+
]
|
| 1472 |
+
|
| 1473 |
[[package]]
|
| 1474 |
name = "pyyaml"
|
| 1475 |
version = "6.0.2"
|
|
|
|
| 2251 |
[metadata]
|
| 2252 |
lock-version = "2.0"
|
| 2253 |
python-versions = "3.11.*"
|
| 2254 |
+
content-hash = "03a23ed4d0df7d827033ee798432d2a443968853c9002926bfde5556e0d5455c"
|
pyproject.toml
CHANGED
|
@@ -22,6 +22,10 @@ selenium = "^4.25.0"
|
|
| 22 |
webdriver-manager = "^4.0.2"
|
| 23 |
bs4 = "^0.0.2"
|
| 24 |
tiktoken = "^0.8.0"
|
|
|
|
|
|
|
|
|
|
|
|
|
| 25 |
|
| 26 |
|
| 27 |
[build-system]
|
|
|
|
| 22 |
webdriver-manager = "^4.0.2"
|
| 23 |
bs4 = "^0.0.2"
|
| 24 |
tiktoken = "^0.8.0"
|
| 25 |
+
python-multipart = "^0.0.17"
|
| 26 |
+
pymupdf = "^1.24.13"
|
| 27 |
+
pymupdf4llm = "^0.0.17"
|
| 28 |
+
python-docx = "^1.1.2"
|
| 29 |
|
| 30 |
|
| 31 |
[build-system]
|
scrapped.txt
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
src/app.py
CHANGED
|
@@ -5,7 +5,7 @@ from fastapi.middleware.cors import CORSMiddleware
|
|
| 5 |
|
| 6 |
from src.utils import logger
|
| 7 |
|
| 8 |
-
from src.controllers import ws_router, api_router
|
| 9 |
|
| 10 |
|
| 11 |
@asynccontextmanager
|
|
@@ -38,4 +38,5 @@ async def check_health():
|
|
| 38 |
return {"response": "Service is healthy!"}
|
| 39 |
|
| 40 |
app.include_router(ws_router)
|
| 41 |
-
app.include_router(api_router, prefix="/api/v1")
|
|
|
|
|
|
| 5 |
|
| 6 |
from src.utils import logger
|
| 7 |
|
| 8 |
+
from src.controllers import ws_router, api_router, file_router
|
| 9 |
|
| 10 |
|
| 11 |
@asynccontextmanager
|
|
|
|
| 38 |
return {"response": "Service is healthy!"}
|
| 39 |
|
| 40 |
app.include_router(ws_router)
|
| 41 |
+
app.include_router(api_router, prefix="/api/v1")
|
| 42 |
+
app.include_router(file_router, prefix="/api/v1")
|
src/controllers/__init__.py
CHANGED
|
@@ -1,12 +1,15 @@
|
|
| 1 |
from ._chat_controller import ChatController
|
| 2 |
from ._database_controller import DatabaseController
|
|
|
|
| 3 |
|
| 4 |
ws_router = ChatController().router
|
| 5 |
api_router = DatabaseController().router
|
|
|
|
| 6 |
|
| 7 |
__all__ = [
|
| 8 |
"ws_router",
|
| 9 |
"api_router",
|
|
|
|
| 10 |
]
|
| 11 |
__version__ = "0.1.0"
|
| 12 |
__author__ = "Aryan Jain"
|
|
|
|
| 1 |
from ._chat_controller import ChatController
|
| 2 |
from ._database_controller import DatabaseController
|
| 3 |
+
from ._file_controller import FileController
|
| 4 |
|
| 5 |
ws_router = ChatController().router
|
| 6 |
api_router = DatabaseController().router
|
| 7 |
+
file_router = FileController().router
|
| 8 |
|
| 9 |
__all__ = [
|
| 10 |
"ws_router",
|
| 11 |
"api_router",
|
| 12 |
+
"file_router",
|
| 13 |
]
|
| 14 |
__version__ = "0.1.0"
|
| 15 |
__author__ = "Aryan Jain"
|
src/controllers/_database_controller.py
CHANGED
|
@@ -1,4 +1,5 @@
|
|
| 1 |
from fastapi import APIRouter, HTTPException
|
|
|
|
| 2 |
|
| 3 |
from src.utils import logger
|
| 4 |
|
|
@@ -10,10 +11,14 @@ class DatabaseController:
|
|
| 10 |
self.router = APIRouter(prefix="/update_database", tags=["database"])
|
| 11 |
self.router.add_api_route("/", self.update_database, methods=["POST"])
|
| 12 |
|
| 13 |
-
async def update_database(self,
|
| 14 |
try:
|
| 15 |
async with self.database_service() as database_service:
|
| 16 |
-
await database_service._update_database(
|
|
|
|
|
|
|
|
|
|
|
|
|
| 17 |
except Exception as e:
|
| 18 |
logger.error(e)
|
| 19 |
raise HTTPException(status_code=500, detail=str(e))
|
|
|
|
| 1 |
from fastapi import APIRouter, HTTPException
|
| 2 |
+
from fastapi.responses import JSONResponse
|
| 3 |
|
| 4 |
from src.utils import logger
|
| 5 |
|
|
|
|
| 11 |
self.router = APIRouter(prefix="/update_database", tags=["database"])
|
| 12 |
self.router.add_api_route("/", self.update_database, methods=["POST"])
|
| 13 |
|
| 14 |
+
async def update_database(self, urls: list[str] = ["https://sifars.com/"], knowledge_base: bool = False):
|
| 15 |
try:
|
| 16 |
async with self.database_service() as database_service:
|
| 17 |
+
response = await database_service._update_database(urls=urls, knowledge_base=knowledge_base)
|
| 18 |
+
return JSONResponse({
|
| 19 |
+
"status": "success",
|
| 20 |
+
"data": {"message": response}
|
| 21 |
+
})
|
| 22 |
except Exception as e:
|
| 23 |
logger.error(e)
|
| 24 |
raise HTTPException(status_code=500, detail=str(e))
|
src/controllers/_file_controller.py
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
from fastapi import APIRouter, HTTPException, UploadFile
|
| 3 |
+
from fastapi.responses import JSONResponse
|
| 4 |
+
|
| 5 |
+
from src.utils import logger
|
| 6 |
+
|
| 7 |
+
from src.services import FileService
|
| 8 |
+
|
| 9 |
+
import aiofiles
|
| 10 |
+
|
| 11 |
+
class FileController:
|
| 12 |
+
def __init__(self):
|
| 13 |
+
self.file_service = FileService
|
| 14 |
+
self.router = APIRouter(prefix="/upload_file", tags=["file_upload"])
|
| 15 |
+
self.router.add_api_route("/", self.upload_file, methods=["POST"])
|
| 16 |
+
|
| 17 |
+
async def upload_file(self, file: UploadFile):
|
| 18 |
+
try:
|
| 19 |
+
async with aiofiles.tempfile.TemporaryDirectory() as temp_dir:
|
| 20 |
+
temp_file_path = os.path.join(temp_dir, file.filename)
|
| 21 |
+
async with aiofiles.open(temp_file_path, "wb") as f:
|
| 22 |
+
await f.write(file.file.read())
|
| 23 |
+
async with self.file_service() as file_service:
|
| 24 |
+
response = await file_service.upload_file(temp_file_path)
|
| 25 |
+
return JSONResponse(
|
| 26 |
+
{
|
| 27 |
+
"status": "success",
|
| 28 |
+
"data": {"web_url": response},
|
| 29 |
+
}
|
| 30 |
+
)
|
| 31 |
+
except Exception as e:
|
| 32 |
+
logger.error(e)
|
| 33 |
+
raise HTTPException(status_code=500, detail=str(e))
|
src/crawler/_database_updater.py
CHANGED
|
@@ -1,13 +1,19 @@
|
|
|
|
|
| 1 |
import aiofiles
|
| 2 |
-
|
|
|
|
| 3 |
from src.crawler import WebCrawler
|
| 4 |
import tiktoken
|
|
|
|
|
|
|
|
|
|
| 5 |
|
| 6 |
class DatabaseUpdater:
|
| 7 |
def __init__(self):
|
| 8 |
self.model_name = 'gpt-3.5-turbo'
|
| 9 |
self.pinecone_client = PineconeClient
|
| 10 |
self.web_crawler = WebCrawler
|
|
|
|
| 11 |
|
| 12 |
async def __aenter__(self):
|
| 13 |
self.tokenizer = tiktoken.encoding_for_model(self.model_name)
|
|
@@ -38,11 +44,55 @@ class DatabaseUpdater:
|
|
| 38 |
await pinecone_client._delete_index()
|
| 39 |
return
|
| 40 |
|
| 41 |
-
async def
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 42 |
async with self.web_crawler(url) as crawler:
|
| 43 |
await crawler.crawl(url)
|
| 44 |
return
|
| 45 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 46 |
async def _update_database_from_file(self, file_paths):
|
| 47 |
for file_path in file_paths:
|
| 48 |
async with aiofiles.open(file_path, 'r', encoding='utf-8') as f:
|
|
@@ -51,7 +101,8 @@ class DatabaseUpdater:
|
|
| 51 |
await self._update_database(sentences)
|
| 52 |
return
|
| 53 |
|
| 54 |
-
async def
|
| 55 |
-
|
| 56 |
-
|
|
|
|
| 57 |
return
|
|
|
|
| 1 |
+
import os
|
| 2 |
import aiofiles
|
| 3 |
+
import httpx
|
| 4 |
+
from src.utils import PineconeClient, SharepointClient
|
| 5 |
from src.crawler import WebCrawler
|
| 6 |
import tiktoken
|
| 7 |
+
import pymupdf4llm
|
| 8 |
+
from docx import Document
|
| 9 |
+
from src.utils import logger
|
| 10 |
|
| 11 |
class DatabaseUpdater:
|
| 12 |
def __init__(self):
|
| 13 |
self.model_name = 'gpt-3.5-turbo'
|
| 14 |
self.pinecone_client = PineconeClient
|
| 15 |
self.web_crawler = WebCrawler
|
| 16 |
+
self.sharepoint_client = SharepointClient
|
| 17 |
|
| 18 |
async def __aenter__(self):
|
| 19 |
self.tokenizer = tiktoken.encoding_for_model(self.model_name)
|
|
|
|
| 44 |
await pinecone_client._delete_index()
|
| 45 |
return
|
| 46 |
|
| 47 |
+
async def process_text_file(self, file_path):
|
| 48 |
+
async with aiofiles.open(file_path, 'r', encoding='utf-8') as f:
|
| 49 |
+
content = await f.read()
|
| 50 |
+
async with aiofiles.open("knowledge_base.txt", 'a+', encoding='utf-8') as f:
|
| 51 |
+
await f.write(content)
|
| 52 |
+
await f.write("\n")
|
| 53 |
+
return
|
| 54 |
+
|
| 55 |
+
async def process_pdf_file(self, file_path):
|
| 56 |
+
docs = pymupdf4llm.to_markdown(file_path, page_chunks=True)
|
| 57 |
+
async with aiofiles.open("knowledge_base.txt", 'a+', encoding='utf-8') as f:
|
| 58 |
+
for doc in docs:
|
| 59 |
+
await f.write(doc.get("text"))
|
| 60 |
+
await f.write("\n")
|
| 61 |
+
return
|
| 62 |
+
|
| 63 |
+
async def process_docx_file(self, file_path):
|
| 64 |
+
doc = Document(file_path)
|
| 65 |
+
async with aiofiles.open("knowledge_base.txt", 'a+', encoding='utf-8') as f:
|
| 66 |
+
for paragraph in doc.paragraphs:
|
| 67 |
+
await f.write(paragraph.text)
|
| 68 |
+
await f.write("\n")
|
| 69 |
+
|
| 70 |
+
async def _extract_scraped_data(self, url):
|
| 71 |
async with self.web_crawler(url) as crawler:
|
| 72 |
await crawler.crawl(url)
|
| 73 |
return
|
| 74 |
|
| 75 |
+
async def _extract_knowledge_base(self):
|
| 76 |
+
async with self.sharepoint_client() as sharepoint_client:
|
| 77 |
+
files = await sharepoint_client.get_files()
|
| 78 |
+
async with aiofiles.tempfile.TemporaryDirectory() as temp_dir:
|
| 79 |
+
for file in files["value"]:
|
| 80 |
+
file_path = os.path.join(temp_dir, file['name'])
|
| 81 |
+
async with httpx.AsyncClient() as client:
|
| 82 |
+
response = await client.get(file['@microsoft.graph.downloadUrl'])
|
| 83 |
+
async with aiofiles.open(file_path, 'wb') as f:
|
| 84 |
+
await f.write(response.content)
|
| 85 |
+
if file["name"].endswith(".txt") or file["name"].endswith(".md"):
|
| 86 |
+
await self.process_text_file(file_path)
|
| 87 |
+
elif file["name"].endswith(".pdf"):
|
| 88 |
+
await self.process_pdf_file(file_path)
|
| 89 |
+
elif file["name"].endswith("docx"):
|
| 90 |
+
await self.process_docx_file(file_path)
|
| 91 |
+
else:
|
| 92 |
+
logger.error(f"Unsupported file format: {file['name']}")
|
| 93 |
+
return
|
| 94 |
+
|
| 95 |
+
|
| 96 |
async def _update_database_from_file(self, file_paths):
|
| 97 |
for file_path in file_paths:
|
| 98 |
async with aiofiles.open(file_path, 'r', encoding='utf-8') as f:
|
|
|
|
| 101 |
await self._update_database(sentences)
|
| 102 |
return
|
| 103 |
|
| 104 |
+
async def _clear_old_files(self, file_paths):
|
| 105 |
+
for file_path in file_paths:
|
| 106 |
+
async with aiofiles.open(file_path, 'w', encoding='utf-8') as f:
|
| 107 |
+
await f.write("")
|
| 108 |
return
|
src/services/__init__.py
CHANGED
|
@@ -1,11 +1,13 @@
|
|
| 1 |
from ._connection_service import ConnectionService
|
| 2 |
from ._chat_service import ChatService
|
| 3 |
from ._database_service import DatabaseService
|
|
|
|
| 4 |
|
| 5 |
__all__ = [
|
| 6 |
"ConnectionService",
|
| 7 |
"ChatService",
|
| 8 |
-
"DatabaseService"
|
|
|
|
| 9 |
]
|
| 10 |
__version__ = "0.1.0"
|
| 11 |
__author__ = "Aryan Jain"
|
|
|
|
| 1 |
from ._connection_service import ConnectionService
|
| 2 |
from ._chat_service import ChatService
|
| 3 |
from ._database_service import DatabaseService
|
| 4 |
+
from ._file_service import FileService
|
| 5 |
|
| 6 |
__all__ = [
|
| 7 |
"ConnectionService",
|
| 8 |
"ChatService",
|
| 9 |
+
"DatabaseService",
|
| 10 |
+
"FileService",
|
| 11 |
]
|
| 12 |
__version__ = "0.1.0"
|
| 13 |
__author__ = "Aryan Jain"
|
src/services/_chat_service.py
CHANGED
|
@@ -17,11 +17,6 @@ class ChatService:
|
|
| 17 |
pass
|
| 18 |
|
| 19 |
async def create_response_message(self, messages: list):
|
| 20 |
-
async with self.pinecone_client() as pinecone_client:
|
| 21 |
-
context = []
|
| 22 |
-
async for text in pinecone_client._get_similar_texts(messages[-1]["content"], top_k=2):
|
| 23 |
-
context.append(text)
|
| 24 |
-
context = " ".join(context)
|
| 25 |
async with self.chat_client() as chat_client:
|
| 26 |
-
async for response in chat_client.
|
| 27 |
yield response
|
|
|
|
| 17 |
pass
|
| 18 |
|
| 19 |
async def create_response_message(self, messages: list):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 20 |
async with self.chat_client() as chat_client:
|
| 21 |
+
async for response in chat_client.create_chat_completions(messages[1:][-11:]):
|
| 22 |
yield response
|
src/services/_database_service.py
CHANGED
|
@@ -5,7 +5,7 @@ from src.utils import logger
|
|
| 5 |
class DatabaseService:
|
| 6 |
def __init__(self):
|
| 7 |
self.database_updater = DatabaseUpdater
|
| 8 |
-
self.file_paths = ["scrapped.txt", "sifars.md"]
|
| 9 |
|
| 10 |
async def __aenter__(self):
|
| 11 |
return self
|
|
@@ -13,9 +13,18 @@ class DatabaseService:
|
|
| 13 |
async def __aexit__(self, exc_type, exc_val, exc_tb):
|
| 14 |
pass
|
| 15 |
|
| 16 |
-
async def _update_database(self,
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 5 |
class DatabaseService:
|
| 6 |
def __init__(self):
|
| 7 |
self.database_updater = DatabaseUpdater
|
| 8 |
+
self.file_paths = ["knowledge_base.txt", "scrapped.txt", "sifars.md"]
|
| 9 |
|
| 10 |
async def __aenter__(self):
|
| 11 |
return self
|
|
|
|
| 13 |
async def __aexit__(self, exc_type, exc_val, exc_tb):
|
| 14 |
pass
|
| 15 |
|
| 16 |
+
async def _update_database(self, urls: list[str], knowledge_base: bool):
|
| 17 |
+
if not urls and not knowledge_base:
|
| 18 |
+
return "Nothing to update"
|
| 19 |
+
if urls:
|
| 20 |
+
async with self.database_updater() as database_updater:
|
| 21 |
+
await database_updater._clear_old_files(file_paths=self.file_paths[1:2])
|
| 22 |
+
for url in urls:
|
| 23 |
+
await database_updater._extract_scraped_data(url=url)
|
| 24 |
+
if knowledge_base:
|
| 25 |
+
async with self.database_updater() as database_updater:
|
| 26 |
+
await database_updater._clear_old_files(file_paths=self.file_paths[:1])
|
| 27 |
+
await database_updater._extract_knowledge_base()
|
| 28 |
+
await database_updater._delete_old_database()
|
| 29 |
+
await database_updater._update_database_from_file(file_paths=self.file_paths)
|
| 30 |
+
return "Database updated"
|
src/services/_file_service.py
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from src.utils import logger, SharepointClient
|
| 2 |
+
|
| 3 |
+
class FileService:
|
| 4 |
+
def __init__(self):
|
| 5 |
+
pass
|
| 6 |
+
|
| 7 |
+
async def __aenter__(self):
|
| 8 |
+
return self
|
| 9 |
+
|
| 10 |
+
async def __aexit__(self, exc_type, exc_val, exc_tb):
|
| 11 |
+
pass
|
| 12 |
+
|
| 13 |
+
async def upload_file(self, file_path: str):
|
| 14 |
+
async with SharepointClient() as sharepoint_client:
|
| 15 |
+
web_url = await sharepoint_client.upload_file(file_path)
|
| 16 |
+
logger.info(f"File uploaded to Sharepoint. Web URL: {web_url}")
|
| 17 |
+
return web_url
|
src/utils/__init__.py
CHANGED
|
@@ -1,11 +1,17 @@
|
|
| 1 |
from ._config import logger
|
| 2 |
from ._chat_client import ChatClient
|
| 3 |
from ._pinecone_client import PineconeClient
|
|
|
|
|
|
|
|
|
|
| 4 |
|
| 5 |
__all__ = [
|
| 6 |
"logger",
|
| 7 |
"ChatClient",
|
| 8 |
"PineconeClient",
|
|
|
|
|
|
|
|
|
|
| 9 |
]
|
| 10 |
__version__ = "0.1.0"
|
| 11 |
__author__ = "Aryan Jain"
|
|
|
|
| 1 |
from ._config import logger
|
| 2 |
from ._chat_client import ChatClient
|
| 3 |
from ._pinecone_client import PineconeClient
|
| 4 |
+
from ._email_client import EmailClient
|
| 5 |
+
from ._tool_call import ToolCall
|
| 6 |
+
from ._sharepoint_client import SharepointClient
|
| 7 |
|
| 8 |
__all__ = [
|
| 9 |
"logger",
|
| 10 |
"ChatClient",
|
| 11 |
"PineconeClient",
|
| 12 |
+
"EmailClient",
|
| 13 |
+
"ToolCall",
|
| 14 |
+
"SharepointClient"
|
| 15 |
]
|
| 16 |
__version__ = "0.1.0"
|
| 17 |
__author__ = "Aryan Jain"
|
src/utils/_chat_client.py
CHANGED
|
@@ -1,19 +1,37 @@
|
|
| 1 |
import os
|
| 2 |
from groq import AsyncGroq
|
| 3 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 4 |
INSTRUCTIONS="""
|
|
|
|
| 5 |
You are an AI assistant designed by Sifars, a web development company, who gives answers to queries regarding Sifars, to the best of your ability.
|
| 6 |
-
You
|
| 7 |
-
Match the question with the context and according to that answer the user query.
|
| 8 |
|
| 9 |
# Here is a bit of information about Sifars:
|
| 10 |
-
Sifars, a pioneering web service provider, emerged onto the tech landscape in 2018 with a vision to revolutionize the digital sphere. Founded by visionary entrepreneurs Jatin Sethi, Munish Kumar, and Sukhwinder Singh, Sifars set its sights on empowering businesses worldwide with cutting-edge technology solutions. With its global headquarters nestled in the vibrant city of Patiala, Punjab, India, Sifars quickly garnered recognition as a leading application development company, committed to propelling businesses towards success in the ever-evolving tech landscape.
|
| 11 |
|
| 12 |
Email: [contact@sifars.com](mailto:contact@sifars.com)
|
| 13 |
Address: SCO 6, First Floor, Phulkian Enclave, Near Mini Secretariat, Patiala, Punjab 147001, India
|
|
|
|
|
|
|
|
|
|
| 14 |
|
| 15 |
-
|
|
|
|
| 16 |
- It is mandatory for you to keep your responses extremely brief and to the point. Avoid repeating the same information multiple times.
|
|
|
|
|
|
|
| 17 |
- It is mandatory to use only one or two sentences in response. These sentences should be short and concise, and should use simple and non-repititive words.
|
| 18 |
- It is mandatory to split the responses into extremely short paragraphs when using more than two short sentences to increase readability and engagement.
|
| 19 |
- All links should be properly formatted in markdown. When listing items in your response use markdown bullet points instead to ensure readability.
|
|
@@ -24,17 +42,63 @@ Address: SCO 6, First Floor, Phulkian Enclave, Near Mini Secretariat, Patiala, P
|
|
| 24 |
- It is mandatory for you to not mention the context provided, or the contents of the context, for any reason in your message.
|
| 25 |
- Avoid including extra information not asked for in the user query.
|
| 26 |
- Use plural first person pronouns when talking about sifars.
|
| 27 |
-
- Try to answer the query from the context
|
| 28 |
-
- If someone asks
|
| 29 |
-
- If someone asks about sifars, give them only the necessary details and then ask them to visit our about page [here](https://www.sifars.com/en/about/).
|
| 30 |
-
- If someone asks about the services we provide, give them a bit of idea according to the interest of their query and then direct them to our services page [here](https://www.sifars.com/en/services/).
|
| 31 |
-
- If someone asks about our projects or portfolio, provide them details of any three projects with minimal overview of those projects, according to the interest of their query and then direct them to our portfolio page [here](https://www.sifars.com/en/portfolio/).
|
| 32 |
-
- If someone asks about our technology or tech stack that we use, give them a bit of idea according to the interest of their query and then direct them to our technology page [here](https://www.sifars.com/en/technology/).
|
| 33 |
-
- If someone asks about career opportunities, direct them to our career page [here](https://www.sifars.com/en/career/).
|
| 34 |
-
- It is mandatory for you to not make up any links on your own. Only use the links provided above.
|
| 35 |
-
</RULES>
|
| 36 |
"""
|
| 37 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 38 |
class ChatClient:
|
| 39 |
def __init__(
|
| 40 |
self,
|
|
@@ -57,21 +121,73 @@ class ChatClient:
|
|
| 57 |
async def __aexit__(self, exc_type, exc, traceback):
|
| 58 |
pass
|
| 59 |
|
| 60 |
-
async def
|
| 61 |
self,
|
| 62 |
-
messages: list
|
| 63 |
-
context: str
|
| 64 |
):
|
| 65 |
-
|
| 66 |
messages=[
|
| 67 |
{"role": "system", "content": self.system_message},
|
| 68 |
-
*messages
|
| 69 |
-
{"role": "user", "content": f"Context is {context} and User query is {messages[-1]['content']}"}
|
| 70 |
],
|
| 71 |
model=self.model,
|
| 72 |
max_tokens=self.max_tokens,
|
| 73 |
stream=self.stream,
|
| 74 |
-
temperature=0.7
|
| 75 |
-
|
| 76 |
-
|
| 77 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
import os
|
| 2 |
from groq import AsyncGroq
|
| 3 |
|
| 4 |
+
import json
|
| 5 |
+
|
| 6 |
+
from ._tool_call import ToolCall
|
| 7 |
+
|
| 8 |
+
from ._config import logger
|
| 9 |
+
|
| 10 |
+
|
| 11 |
+
AVAILABLE_FUNCTIONS = {
|
| 12 |
+
"contact_us": ToolCall.send_email.__name__,
|
| 13 |
+
"get_context_for_user_query": ToolCall.get_context_for_user_query.__name__
|
| 14 |
+
}
|
| 15 |
+
|
| 16 |
INSTRUCTIONS="""
|
| 17 |
+
# Objective
|
| 18 |
You are an AI assistant designed by Sifars, a web development company, who gives answers to queries regarding Sifars, to the best of your ability.
|
| 19 |
+
You can get additional context to answer the user query by calling the tool 'get_context_for_user_query', which you can then use to answer their query. Be smart about when to use the tool to get the context for the query.
|
|
|
|
| 20 |
|
| 21 |
# Here is a bit of information about Sifars:
|
| 22 |
+
Sifars, a pioneering web service provider, emerged onto the tech landscape in 2018 with a vision to revolutionize the digital sphere. Founded by visionary entrepreneurs Jatin Sethi, Munish Kumar, and Sukhwinder Singh, Sifars set its sights on empowering businesses worldwide with cutting-edge technology solutions. With its global headquarters nestled in the vibrant city of Patiala, Punjab, India, Sifars quickly garnered recognition as a leading application development company, committed to propelling businesses towards success in the ever-evolving tech landscape. The company leverages a diverse stack of technologies, including Python, JavaScript, React, Node.js, and AWS, ensuring robust and scalable solutions. Sifars also fosters a culture of innovation and work-life balance, enabling its team to thrive professionally and personally.
|
| 23 |
|
| 24 |
Email: [contact@sifars.com](mailto:contact@sifars.com)
|
| 25 |
Address: SCO 6, First Floor, Phulkian Enclave, Near Mini Secretariat, Patiala, Punjab 147001, India
|
| 26 |
+
Phone: [+91 8106 455 950](tel:+918106455950), [+91 8008 296 463](tel:+918008296463), [+91 8896 720 000](tel:+918896720000)
|
| 27 |
+
|
| 28 |
+
---
|
| 29 |
|
| 30 |
+
# Rules
|
| 31 |
+
- If you need context about the query then use tool call 'get_context_for_user_query'. Do not ask from the user.
|
| 32 |
- It is mandatory for you to keep your responses extremely brief and to the point. Avoid repeating the same information multiple times.
|
| 33 |
+
- It is mandatory when calling the 'contact_us' tool, to not assume tool call parameters by yourself. You must ask the user to drop the neccessary details in the chat and use that information. You must use the reason for contact that the user provides to dynamically construct the subject of the email. It is mandatory for you do not mention the subject of the email and how you are creating it in the response. So first ask tool call parameters and then call the tool. Do not pass empty values in the tool call.
|
| 34 |
+
- Do not assume any parameter of 'contact_us' tool by yourself. All parameters must be provided by user. When user wants to connect us for any query then ask the required parameters and then call the tool "contact us". If required variables are not there then collect required parameters from user and call the tool "contact us". Only after asking all the required parameteres then call the tool "contact us".
|
| 35 |
- It is mandatory to use only one or two sentences in response. These sentences should be short and concise, and should use simple and non-repititive words.
|
| 36 |
- It is mandatory to split the responses into extremely short paragraphs when using more than two short sentences to increase readability and engagement.
|
| 37 |
- All links should be properly formatted in markdown. When listing items in your response use markdown bullet points instead to ensure readability.
|
|
|
|
| 42 |
- It is mandatory for you to not mention the context provided, or the contents of the context, for any reason in your message.
|
| 43 |
- Avoid including extra information not asked for in the user query.
|
| 44 |
- Use plural first person pronouns when talking about sifars.
|
| 45 |
+
- Try to answer the query from the context you get from the tool 'get_context_for_user_query'. Even if the context does not directly answer the question, try to relate it to the question and formulate an answer.
|
| 46 |
+
- If someone asks about career opportunities and there is no information regarding it in the context provided by the tool 'get_context_for_user_query', direct them to our career page [here](https://www.sifars.com/en/career/). Only provided the link if it does not already exist in the chat history.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 47 |
"""
|
| 48 |
|
| 49 |
+
CONTACT_TOOL={
|
| 50 |
+
"type": "function",
|
| 51 |
+
"function": {
|
| 52 |
+
"name": "contact_us",
|
| 53 |
+
"description": "Collect the information dropped by user in the chat to contact the sifars team",
|
| 54 |
+
"parameters": {
|
| 55 |
+
"type": "object",
|
| 56 |
+
"properties": {
|
| 57 |
+
"name": {
|
| 58 |
+
"type": "string",
|
| 59 |
+
"description": "This field is the name of the user which you will collect from the user"
|
| 60 |
+
},
|
| 61 |
+
"email": {
|
| 62 |
+
"type": "string",
|
| 63 |
+
"description": "This field is the email of the user which you will collect from the user"
|
| 64 |
+
},
|
| 65 |
+
"phone_number": {
|
| 66 |
+
"type": "string",
|
| 67 |
+
"description": "This field is the phone number of the user which you will collect from the user"
|
| 68 |
+
},
|
| 69 |
+
"reason_for_contact": {
|
| 70 |
+
"type": "string",
|
| 71 |
+
"description": "This field is the reason for contact of the user which you will collect. This is seperate from the subject of the email. Keep it same that user has given in the chat. Do not change it."
|
| 72 |
+
},
|
| 73 |
+
"subject": {
|
| 74 |
+
"type": "string",
|
| 75 |
+
"description": "This is the subject of the email which will be dynamically contructed by you using the reason for contact provided. It is mandatory that you do not mention this field to the user."
|
| 76 |
+
}
|
| 77 |
+
},
|
| 78 |
+
"required": ["name", "email", "phone_number","reason_for_contact", "subject"]
|
| 79 |
+
}
|
| 80 |
+
}
|
| 81 |
+
}
|
| 82 |
+
|
| 83 |
+
GET_CONTEXT_FOR_USER_QUERY_TOOL={
|
| 84 |
+
"type": "function",
|
| 85 |
+
"function": {
|
| 86 |
+
"name": "get_context_for_user_query",
|
| 87 |
+
"description": "This function will give the similar texts from the database based on the user query",
|
| 88 |
+
"parameters": {
|
| 89 |
+
"type": "object",
|
| 90 |
+
"properties": {
|
| 91 |
+
"query": {
|
| 92 |
+
"type": "string",
|
| 93 |
+
"description": "This is the user query. Do not reformulate the query. Pass the query as it is."
|
| 94 |
+
}
|
| 95 |
+
},
|
| 96 |
+
"required": ["query"]
|
| 97 |
+
}
|
| 98 |
+
}
|
| 99 |
+
}
|
| 100 |
+
|
| 101 |
+
|
| 102 |
class ChatClient:
|
| 103 |
def __init__(
|
| 104 |
self,
|
|
|
|
| 121 |
async def __aexit__(self, exc_type, exc, traceback):
|
| 122 |
pass
|
| 123 |
|
| 124 |
+
async def create_chat_completions(
|
| 125 |
self,
|
| 126 |
+
messages: list
|
|
|
|
| 127 |
):
|
| 128 |
+
response = await self.client.chat.completions.create(
|
| 129 |
messages=[
|
| 130 |
{"role": "system", "content": self.system_message},
|
| 131 |
+
*messages
|
|
|
|
| 132 |
],
|
| 133 |
model=self.model,
|
| 134 |
max_tokens=self.max_tokens,
|
| 135 |
stream=self.stream,
|
| 136 |
+
temperature=0.7,
|
| 137 |
+
tools=[CONTACT_TOOL, GET_CONTEXT_FOR_USER_QUERY_TOOL],
|
| 138 |
+
tool_choice="auto",
|
| 139 |
+
)
|
| 140 |
+
tool_call_response = None
|
| 141 |
+
async for chunk in response:
|
| 142 |
+
delta = chunk.choices[0].delta
|
| 143 |
+
if delta and delta.content:
|
| 144 |
+
yield delta.content
|
| 145 |
+
elif delta:
|
| 146 |
+
if not tool_call_response:
|
| 147 |
+
tool_call_response = delta
|
| 148 |
+
if not tool_call_response.tool_calls and delta.tool_calls:
|
| 149 |
+
tool_call_response.tool_calls = delta.tool_calls
|
| 150 |
+
if (
|
| 151 |
+
tool_call_response
|
| 152 |
+
and delta.tool_calls
|
| 153 |
+
and len(tool_call_response.tool_calls)
|
| 154 |
+
< delta.tool_calls[0].index + 1
|
| 155 |
+
):
|
| 156 |
+
tool_call_response.tool_calls.append(delta.tool_calls[0])
|
| 157 |
+
if tool_call_response and tool_call_response.tool_calls:
|
| 158 |
+
tool_calls_output = await self._handle_required_action(
|
| 159 |
+
tool_calls=tool_call_response.tool_calls,
|
| 160 |
+
)
|
| 161 |
+
messages.append(tool_call_response)
|
| 162 |
+
messages.extend(tool_calls_output)
|
| 163 |
+
async for chunk in self.create_chat_completions(messages=messages):
|
| 164 |
+
yield chunk
|
| 165 |
+
|
| 166 |
+
async def _handle_required_action(self, tool_calls: list[dict]):
|
| 167 |
+
tool_calls_output = []
|
| 168 |
+
for tool in tool_calls:
|
| 169 |
+
if tool.type == "function":
|
| 170 |
+
try:
|
| 171 |
+
function_to_call = AVAILABLE_FUNCTIONS[tool.function.name]
|
| 172 |
+
function_arguments = json.loads(str(tool.function.arguments)) if tool.function.arguments else {}
|
| 173 |
+
async with ToolCall() as tool_call:
|
| 174 |
+
function_response = await getattr(tool_call, function_to_call)(
|
| 175 |
+
function_arguments
|
| 176 |
+
)
|
| 177 |
+
except Exception as e:
|
| 178 |
+
logger.error(e)
|
| 179 |
+
function_response = "Unable to call the tool."
|
| 180 |
+
tool_calls_output.append(
|
| 181 |
+
{
|
| 182 |
+
"role": "tool",
|
| 183 |
+
"tool_call_id": tool.id,
|
| 184 |
+
"name": tool.function.name,
|
| 185 |
+
"content": (
|
| 186 |
+
str(function_response)
|
| 187 |
+
if function_response
|
| 188 |
+
else "No results found."
|
| 189 |
+
),
|
| 190 |
+
}
|
| 191 |
+
)
|
| 192 |
+
return tool_calls_output
|
| 193 |
+
|
src/utils/_email_client.py
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
from email.message import EmailMessage
|
| 3 |
+
|
| 4 |
+
import aiosmtplib
|
| 5 |
+
|
| 6 |
+
from ._config import logger
|
| 7 |
+
|
| 8 |
+
|
| 9 |
+
class EmailClient:
|
| 10 |
+
def __init__(self):
|
| 11 |
+
self.message = EmailMessage()
|
| 12 |
+
self.message["From"] = os.getenv("SENDER_EMAIL")
|
| 13 |
+
self.message["To"] = os.getenv("RECIPIENT_EMAIL")
|
| 14 |
+
self.smtp_host = os.getenv("SMTP_HOST")
|
| 15 |
+
self.smtp_port = int(os.getenv("SMTP_PORT"))
|
| 16 |
+
self.smtp_username = os.getenv("SMTP_USERNAME")
|
| 17 |
+
self.smtp_password = os.getenv("SMTP_PASSWORD")
|
| 18 |
+
|
| 19 |
+
async def __aenter__(self):
|
| 20 |
+
return self
|
| 21 |
+
|
| 22 |
+
async def __aexit__(self, exc_type, exc_val, exc_tb):
|
| 23 |
+
pass
|
| 24 |
+
|
| 25 |
+
async def send_email(self, details: dict, attachment_paths=[]):
|
| 26 |
+
subject = details.get("subject")
|
| 27 |
+
name = details.get("name")
|
| 28 |
+
email = details.get("email")
|
| 29 |
+
phone_number = details.get("phone_number")
|
| 30 |
+
reason_for_contact = details.get("reason_for_contact")
|
| 31 |
+
subject = details.get("subject")
|
| 32 |
+
self.message["Subject"] = subject
|
| 33 |
+
content = f"""Hello Team, \n\n{name} wants to connect with us regarding the following reason: \n{reason_for_contact}. \n\nContact Details:\nEmail: {email}\nPhone Number: {phone_number}\n\nThanks for your consideration."""
|
| 34 |
+
self.message.set_content(content)
|
| 35 |
+
if attachment_paths:
|
| 36 |
+
for attachment_path in attachment_paths:
|
| 37 |
+
with open(attachment_path, "rb") as f:
|
| 38 |
+
file_data = f.read()
|
| 39 |
+
file_name = os.path.basename(attachment_path)
|
| 40 |
+
self.message.add_attachment(
|
| 41 |
+
file_data,
|
| 42 |
+
maintype="application",
|
| 43 |
+
subtype="octet-stream",
|
| 44 |
+
filename=file_name,
|
| 45 |
+
)
|
| 46 |
+
response = await aiosmtplib.send(
|
| 47 |
+
self.message,
|
| 48 |
+
hostname=self.smtp_host,
|
| 49 |
+
port=self.smtp_port,
|
| 50 |
+
start_tls=True,
|
| 51 |
+
username=self.smtp_username,
|
| 52 |
+
password=self.smtp_password,
|
| 53 |
+
)
|
| 54 |
+
logger.info(response)
|
src/utils/_pinecone_client.py
CHANGED
|
@@ -82,7 +82,8 @@ class PineconeClient:
|
|
| 82 |
)
|
| 83 |
return
|
| 84 |
|
| 85 |
-
async def
|
|
|
|
| 86 |
if not index_name:
|
| 87 |
index_name = self.index_name
|
| 88 |
embeddings = await self._create_embeddings([query_text])
|
|
@@ -92,8 +93,10 @@ class PineconeClient:
|
|
| 92 |
top_k=top_k,
|
| 93 |
include_metadata=True
|
| 94 |
)
|
|
|
|
| 95 |
for metadata in results['matches']:
|
| 96 |
-
|
|
|
|
| 97 |
|
| 98 |
async def _delete_index(self, index_name=None):
|
| 99 |
if not index_name:
|
|
|
|
| 82 |
)
|
| 83 |
return
|
| 84 |
|
| 85 |
+
async def get_context_for_user_query(self, details: dict, top_k=2, index_name=None):
|
| 86 |
+
query_text = details['query']
|
| 87 |
if not index_name:
|
| 88 |
index_name = self.index_name
|
| 89 |
embeddings = await self._create_embeddings([query_text])
|
|
|
|
| 93 |
top_k=top_k,
|
| 94 |
include_metadata=True
|
| 95 |
)
|
| 96 |
+
content = []
|
| 97 |
for metadata in results['matches']:
|
| 98 |
+
content.append(metadata["metadata"]["text"])
|
| 99 |
+
return "\n".join(content)
|
| 100 |
|
| 101 |
async def _delete_index(self, index_name=None):
|
| 102 |
if not index_name:
|
src/utils/_sharepoint_client.py
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
|
| 3 |
+
import aiofiles
|
| 4 |
+
import httpx
|
| 5 |
+
|
| 6 |
+
|
| 7 |
+
class SharepointClient:
|
| 8 |
+
def __init__(self):
|
| 9 |
+
self.access_token_url = f"https://login.microsoftonline.com/{os.getenv('AZURE_TENANT_ID')}/oauth2/v2.0/token"
|
| 10 |
+
self.access_token_data = {
|
| 11 |
+
"grant_type": "client_credentials",
|
| 12 |
+
"client_id": os.getenv("AZURE_CLIENT_ID"),
|
| 13 |
+
"client_secret": os.getenv("AZURE_CLIENT_SECRET"),
|
| 14 |
+
"scope": os.getenv("AZURE_SCOPE"),
|
| 15 |
+
}
|
| 16 |
+
self.token = None
|
| 17 |
+
|
| 18 |
+
async def __aenter__(self):
|
| 19 |
+
async with httpx.AsyncClient() as client:
|
| 20 |
+
token_response = await client.post(
|
| 21 |
+
self.access_token_url, data=self.access_token_data
|
| 22 |
+
)
|
| 23 |
+
self.token = token_response.json()["access_token"]
|
| 24 |
+
return self
|
| 25 |
+
|
| 26 |
+
async def __aexit__(self, exc_type, exc_val, exc_tb):
|
| 27 |
+
pass
|
| 28 |
+
|
| 29 |
+
async def upload_file(self, file_path: str):
|
| 30 |
+
async with httpx.AsyncClient() as client:
|
| 31 |
+
headers = {
|
| 32 |
+
"Authorization": f"Bearer {self.token}",
|
| 33 |
+
"Content-Type": "application/json",
|
| 34 |
+
}
|
| 35 |
+
file_name = os.path.basename(file_path)
|
| 36 |
+
async with aiofiles.open(file_path, "rb") as file:
|
| 37 |
+
file_data = await file.read()
|
| 38 |
+
upload_url = f"https://graph.microsoft.com/v1.0/drives/{os.getenv('AZURE_DRIVE_ID')}/root:/{file_name}:/content"
|
| 39 |
+
response = await client.put(
|
| 40 |
+
upload_url, headers=headers, content=file_data
|
| 41 |
+
)
|
| 42 |
+
uploaded_response = response.json()
|
| 43 |
+
web_url = uploaded_response["webUrl"]
|
| 44 |
+
return web_url
|
| 45 |
+
|
| 46 |
+
async def get_files(self):
|
| 47 |
+
async with httpx.AsyncClient() as client:
|
| 48 |
+
headers = {
|
| 49 |
+
"Authorization": f"Bearer {self.token}",
|
| 50 |
+
"Content-Type": "application/json",
|
| 51 |
+
}
|
| 52 |
+
files_url = f"https://graph.microsoft.com/v1.0/drives/{os.getenv('AZURE_DRIVE_ID')}/root/children"
|
| 53 |
+
response = await client.get(files_url, headers=headers)
|
| 54 |
+
files = response.json()
|
| 55 |
+
return files
|
src/utils/_tool_call.py
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from ._email_client import EmailClient
|
| 2 |
+
from ._pinecone_client import PineconeClient
|
| 3 |
+
|
| 4 |
+
class ToolCall:
|
| 5 |
+
def __init__(self):
|
| 6 |
+
pass
|
| 7 |
+
|
| 8 |
+
async def __aenter__(self):
|
| 9 |
+
return self
|
| 10 |
+
|
| 11 |
+
async def __aexit__(self, exc_type, exc_val, exc_tb):
|
| 12 |
+
pass
|
| 13 |
+
|
| 14 |
+
async def send_email(self, details: dict):
|
| 15 |
+
async with EmailClient() as email_client:
|
| 16 |
+
await email_client.send_email(details)
|
| 17 |
+
return "Email sent successfully"
|
| 18 |
+
|
| 19 |
+
async def get_context_for_user_query(self, details: dict):
|
| 20 |
+
async with PineconeClient() as pinecone_client:
|
| 21 |
+
return await pinecone_client.get_context_for_user_query(details)
|