From c2308a117804f2b3311b8c89ef76ae6a99337bf8 Mon Sep 17 00:00:00 2001 From: Aakash Singh Date: Fri, 2 Feb 2024 00:41:31 +0530 Subject: [PATCH 1/9] fix issues (#457) --- Pipfile | 1 + Pipfile.lock | 151 +++++++++++++++------------ compose/local/django/Dockerfile | 2 + compose/production/django/Dockerfile | 2 + compose/production/django/entrypoint | 13 +-- compose/production/django/start | 2 +- 6 files changed, 94 insertions(+), 77 deletions(-) diff --git a/Pipfile b/Pipfile index a3f90af0..cf7c9ced 100644 --- a/Pipfile +++ b/Pipfile @@ -8,6 +8,7 @@ pillow = "==10.0.0" argon2-cffi = "==23.1.0" whitenoise = "==6.6.0" redis = "==5.0.1" +beautifulsoup4 = "==4.12.3" celery = "==5.3.6" django = "==4.2.6" djangoql = "==0.17.1" diff --git a/Pipfile.lock b/Pipfile.lock index ae0bf660..403bec11 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "50d61ddb0f3abaccdafb5046892468f6a0dbaf5e8a6544a535e88467c6c37e55" + "sha256": "f7eaea9dba25a601c70a711e0b46fefbee0f7beb7b750012fbd55c55e9bf857f" }, "pipfile-spec": 6, "requires": { @@ -183,6 +183,15 @@ "markers": "python_version >= '3.7'", "version": "==23.2.0" }, + "beautifulsoup4": { + "hashes": [ + "sha256:74e3d1928edc070d21748185c46e3fb33490f22f52a3addee9aee0f4f7781051", + "sha256:b80878c9f40111313e55da8ba20bdba06d8fa3969fc68304167741bbf9e082ed" + ], + "index": "pypi", + "markers": "python_full_version >= '3.6.0'", + "version": "==4.12.3" + }, "billiard": { "hashes": [ "sha256:07aa978b308f334ff8282bd4a746e681b3513db5c9a514cbdd810cbbdc19714d", @@ -702,69 +711,69 @@ }, "grpcio": { "hashes": [ - "sha256:073f959c6f570797272f4ee9464a9997eaf1e98c27cb680225b82b53390d61e6", - "sha256:0fd3b3968ffe7643144580f260f04d39d869fcc2cddb745deef078b09fd2b328", - "sha256:1434ca77d6fed4ea312901122dc8da6c4389738bf5788f43efb19a838ac03ead", - "sha256:1c30bb23a41df95109db130a6cc1b974844300ae2e5d68dd4947aacba5985aa5", - "sha256:20e7a4f7ded59097c84059d28230907cd97130fa74f4a8bfd1d8e5ba18c81491", - "sha256:2199165a1affb666aa24adf0c97436686d0a61bc5fc113c037701fb7c7fceb96", - "sha256:297eef542156d6b15174a1231c2493ea9ea54af8d016b8ca7d5d9cc65cfcc444", - "sha256:2aef56e85901c2397bd557c5ba514f84de1f0ae5dd132f5d5fed042858115951", - "sha256:30943b9530fe3620e3b195c03130396cd0ee3a0d10a66c1bee715d1819001eaf", - "sha256:3b36a2c6d4920ba88fa98075fdd58ff94ebeb8acc1215ae07d01a418af4c0253", - "sha256:428d699c8553c27e98f4d29fdc0f0edc50e9a8a7590bfd294d2edb0da7be3629", - "sha256:43e636dc2ce9ece583b3e2ca41df5c983f4302eabc6d5f9cd04f0562ee8ec1ae", - "sha256:452ca5b4afed30e7274445dd9b441a35ece656ec1600b77fff8c216fdf07df43", - "sha256:467a7d31554892eed2aa6c2d47ded1079fc40ea0b9601d9f79204afa8902274b", - "sha256:4b44d7e39964e808b071714666a812049765b26b3ea48c4434a3b317bac82f14", - "sha256:4c86343cf9ff7b2514dd229bdd88ebba760bd8973dac192ae687ff75e39ebfab", - "sha256:5208a57eae445ae84a219dfd8b56e04313445d146873117b5fa75f3245bc1390", - "sha256:5ff21e000ff2f658430bde5288cb1ac440ff15c0d7d18b5fb222f941b46cb0d2", - "sha256:675997222f2e2f22928fbba640824aebd43791116034f62006e19730715166c0", - "sha256:676e4a44e740deaba0f4d95ba1d8c5c89a2fcc43d02c39f69450b1fa19d39590", - "sha256:6e306b97966369b889985a562ede9d99180def39ad42c8014628dd3cc343f508", - "sha256:6fd9584bf1bccdfff1512719316efa77be235469e1e3295dce64538c4773840b", - "sha256:705a68a973c4c76db5d369ed573fec3367d7d196673fa86614b33d8c8e9ebb08", - "sha256:74d7d9fa97809c5b892449b28a65ec2bfa458a4735ddad46074f9f7d9550ad13", - "sha256:77c8a317f0fd5a0a2be8ed5cbe5341537d5c00bb79b3bb27ba7c5378ba77dbca", - "sha256:79a050889eb8d57a93ed21d9585bb63fca881666fc709f5d9f7f9372f5e7fd03", - "sha256:7db16dd4ea1b05ada504f08d0dca1cd9b926bed3770f50e715d087c6f00ad748", - "sha256:83f2292ae292ed5a47cdcb9821039ca8e88902923198f2193f13959360c01860", - "sha256:87c9224acba0ad8bacddf427a1c2772e17ce50b3042a789547af27099c5f751d", - "sha256:8a97a681e82bc11a42d4372fe57898d270a2707f36c45c6676e49ce0d5c41353", - "sha256:9073513ec380434eb8d21970e1ab3161041de121f4018bbed3146839451a6d8e", - "sha256:90bdd76b3f04bdb21de5398b8a7c629676c81dfac290f5f19883857e9371d28c", - "sha256:91229d7203f1ef0ab420c9b53fe2ca5c1fbeb34f69b3bc1b5089466237a4a134", - "sha256:92f88ca1b956eb8427a11bb8b4a0c0b2b03377235fc5102cb05e533b8693a415", - "sha256:95ae3e8e2c1b9bf671817f86f155c5da7d49a2289c5cf27a319458c3e025c320", - "sha256:9e30be89a75ee66aec7f9e60086fadb37ff8c0ba49a022887c28c134341f7179", - "sha256:a48edde788b99214613e440fce495bbe2b1e142a7f214cce9e0832146c41e324", - "sha256:a7152fa6e597c20cb97923407cf0934e14224af42c2b8d915f48bc3ad2d9ac18", - "sha256:a9c7b71211f066908e518a2ef7a5e211670761651039f0d6a80d8d40054047df", - "sha256:b0571a5aef36ba9177e262dc88a9240c866d903a62799e44fd4aae3f9a2ec17e", - "sha256:b0fb2d4801546598ac5cd18e3ec79c1a9af8b8f2a86283c55a5337c5aeca4b1b", - "sha256:b10241250cb77657ab315270b064a6c7f1add58af94befa20687e7c8d8603ae6", - "sha256:b87efe4a380887425bb15f220079aa8336276398dc33fce38c64d278164f963d", - "sha256:b98f43fcdb16172dec5f4b49f2fece4b16a99fd284d81c6bbac1b3b69fcbe0ff", - "sha256:c193109ca4070cdcaa6eff00fdb5a56233dc7610216d58fb81638f89f02e4968", - "sha256:c826f93050c73e7769806f92e601e0efdb83ec8d7c76ddf45d514fee54e8e619", - "sha256:d020cfa595d1f8f5c6b343530cd3ca16ae5aefdd1e832b777f9f0eb105f5b139", - "sha256:d6a478581b1a1a8fdf3318ecb5f4d0cda41cacdffe2b527c23707c9c1b8fdb55", - "sha256:de2ad69c9a094bf37c1102b5744c9aec6cf74d2b635558b779085d0263166454", - "sha256:e278eafb406f7e1b1b637c2cf51d3ad45883bb5bd1ca56bc05e4fc135dfdaa65", - "sha256:e381fe0c2aa6c03b056ad8f52f8efca7be29fb4d9ae2f8873520843b6039612a", - "sha256:e61e76020e0c332a98290323ecfec721c9544f5b739fab925b6e8cbe1944cf19", - "sha256:f897c3b127532e6befdcf961c415c97f320d45614daf84deba0a54e64ea2457b", - "sha256:fb464479934778d7cc5baf463d959d361954d6533ad34c3a4f1d267e86ee25fd" - ], - "version": "==1.60.0" + "sha256:0250a7a70b14000fa311de04b169cc7480be6c1a769b190769d347939d3232a8", + "sha256:069fe2aeee02dfd2135d562d0663fe70fbb69d5eed6eb3389042a7e963b54de8", + "sha256:082081e6a36b6eb5cf0fd9a897fe777dbb3802176ffd08e3ec6567edd85bc104", + "sha256:0c5807e9152eff15f1d48f6b9ad3749196f79a4a050469d99eecb679be592acc", + "sha256:14e8f2c84c0832773fb3958240c69def72357bc11392571f87b2d7b91e0bb092", + "sha256:2a6087f234cb570008a6041c8ffd1b7d657b397fdd6d26e83d72283dae3527b1", + "sha256:2bb2a2911b028f01c8c64d126f6b632fcd8a9ac975aa1b3855766c94e4107180", + "sha256:2f44c32aef186bbba254129cea1df08a20be414144ac3bdf0e84b24e3f3b2e05", + "sha256:30e980cd6db1088c144b92fe376747328d5554bc7960ce583ec7b7d81cd47287", + "sha256:33aed0a431f5befeffd9d346b0fa44b2c01aa4aeae5ea5b2c03d3e25e0071216", + "sha256:33bdea30dcfd4f87b045d404388469eb48a48c33a6195a043d116ed1b9a0196c", + "sha256:39aa848794b887120b1d35b1b994e445cc028ff602ef267f87c38122c1add50d", + "sha256:4216e67ad9a4769117433814956031cb300f85edc855252a645a9a724b3b6594", + "sha256:49c9b6a510e3ed8df5f6f4f3c34d7fbf2d2cae048ee90a45cd7415abab72912c", + "sha256:4eec8b8c1c2c9b7125508ff7c89d5701bf933c99d3910e446ed531cd16ad5d87", + "sha256:50d56280b482875d1f9128ce596e59031a226a8b84bec88cb2bf76c289f5d0de", + "sha256:53b69e79d00f78c81eecfb38f4516080dc7f36a198b6b37b928f1c13b3c063e9", + "sha256:55ccb7db5a665079d68b5c7c86359ebd5ebf31a19bc1a91c982fd622f1e31ff2", + "sha256:5a1ebbae7e2214f51b1f23b57bf98eeed2cf1ba84e4d523c48c36d5b2f8829ff", + "sha256:61b7199cd2a55e62e45bfb629a35b71fc2c0cb88f686a047f25b1112d3810904", + "sha256:660fc6b9c2a9ea3bb2a7e64ba878c98339abaf1811edca904ac85e9e662f1d73", + "sha256:6d140bdeb26cad8b93c1455fa00573c05592793c32053d6e0016ce05ba267549", + "sha256:6e490fa5f7f5326222cb9f0b78f207a2b218a14edf39602e083d5f617354306f", + "sha256:6ecf21d20d02d1733e9c820fb5c114c749d888704a7ec824b545c12e78734d1c", + "sha256:70c83bb530572917be20c21f3b6be92cd86b9aecb44b0c18b1d3b2cc3ae47df0", + "sha256:72153a0d2e425f45b884540a61c6639436ddafa1829a42056aa5764b84108b8e", + "sha256:73e14acd3d4247169955fae8fb103a2b900cfad21d0c35f0dcd0fdd54cd60367", + "sha256:76eaaba891083fcbe167aa0f03363311a9f12da975b025d30e94b93ac7a765fc", + "sha256:79ae0dc785504cb1e1788758c588c711f4e4a0195d70dff53db203c95a0bd303", + "sha256:7d142bcd604166417929b071cd396aa13c565749a4c840d6c702727a59d835eb", + "sha256:8c9554ca8e26241dabe7951aa1fa03a1ba0856688ecd7e7bdbdd286ebc272e4c", + "sha256:8d488fbdbf04283f0d20742b64968d44825617aa6717b07c006168ed16488804", + "sha256:91422ba785a8e7a18725b1dc40fbd88f08a5bb4c7f1b3e8739cab24b04fa8a03", + "sha256:9a66f4d2a005bc78e61d805ed95dedfcb35efa84b7bba0403c6d60d13a3de2d6", + "sha256:9b106bc52e7f28170e624ba61cc7dc6829566e535a6ec68528f8e1afbed1c41f", + "sha256:9b54577032d4f235452f77a83169b6527bf4b77d73aeada97d45b2aaf1bf5ce0", + "sha256:a09506eb48fa5493c58f946c46754ef22f3ec0df64f2b5149373ff31fb67f3dd", + "sha256:a212e5dea1a4182e40cd3e4067ee46be9d10418092ce3627475e995cca95de21", + "sha256:a731ac5cffc34dac62053e0da90f0c0b8560396a19f69d9703e88240c8f05858", + "sha256:af5ef6cfaf0d023c00002ba25d0751e5995fa0e4c9eec6cd263c30352662cbce", + "sha256:b58b855d0071575ea9c7bc0d84a06d2edfbfccec52e9657864386381a7ce1ae9", + "sha256:bc808924470643b82b14fe121923c30ec211d8c693e747eba8a7414bc4351a23", + "sha256:c557e94e91a983e5b1e9c60076a8fd79fea1e7e06848eb2e48d0ccfb30f6e073", + "sha256:c71be3f86d67d8d1311c6076a4ba3b75ba5703c0b856b4e691c9097f9b1e8bd2", + "sha256:c8754c75f55781515a3005063d9a05878b2cfb3cb7e41d5401ad0cf19de14872", + "sha256:cb0af13433dbbd1c806e671d81ec75bd324af6ef75171fd7815ca3074fe32bfe", + "sha256:cba6209c96828711cb7c8fcb45ecef8c8859238baf15119daa1bef0f6c84bfe7", + "sha256:cf77f8cf2a651fbd869fbdcb4a1931464189cd210abc4cfad357f1cacc8642a6", + "sha256:d7404cebcdb11bb5bd40bf94131faf7e9a7c10a6c60358580fe83913f360f929", + "sha256:dd1d3a8d1d2e50ad9b59e10aa7f07c7d1be2b367f3f2d33c5fade96ed5460962", + "sha256:e5d97c65ea7e097056f3d1ead77040ebc236feaf7f71489383d20f3b4c28412a", + "sha256:f1c3dc536b3ee124e8b24feb7533e5c70b9f2ef833e3b2e5513b2897fd46763a", + "sha256:f2212796593ad1d0235068c79836861f2201fc7137a99aa2fea7beeb3b101177", + "sha256:fead980fbc68512dfd4e0c7b1f5754c2a8e5015a04dea454b9cada54a8423525" + ], + "version": "==1.60.1" }, "grpcio-status": { "hashes": [ - "sha256:7d383fa36e59c1e61d380d91350badd4d12ac56e4de2c2b831b050362c3c572e", - "sha256:f10e0b6db3adc0fdc244b71962814ee982996ef06186446b5695b9fa635aa1ab" + "sha256:3034fdb239185b6e0f3169d08c268c4507481e4b8a434c21311a03d9eb5889a0", + "sha256:61b5aab8989498e8aa142c20b88829ea5d90d18c18c853b9f9e6d407d37bf8b4" ], - "version": "==1.60.0" + "version": "==1.60.1" }, "gunicorn": { "hashes": [ @@ -882,19 +891,19 @@ }, "langchain-community": { "hashes": [ - "sha256:0f1dfc1a6205ce8d39931d3515974a208a9f69c16157c649f83490a7cc830b73", - "sha256:c06512a93013a06fba7679cd5a1254ff8b927cddd2d1fbe0cc444bf7bbdf0b8c" + "sha256:ab957b34a562e0199b2ecf050bdc987c4fe889b2ac9f22b75a9fac8b9e30f53a", + "sha256:d503491bbfb691d1b3d10d74f7a69840cee3caf9b58a9a76f053ff925ea76733" ], "markers": "python_version < '4.0' and python_full_version >= '3.8.1'", - "version": "==0.0.16" + "version": "==0.0.17" }, "langchain-core": { "hashes": [ - "sha256:026155cf97867bde410ab1834799ab4c5ba64c39380f2a4328bcf9c78623ca64", - "sha256:59016e457cd6a1708d83a3a454acc97cf02c2a2c3af95626d13f83894fd4e777" + "sha256:5a60dc3c391b33834fb9c8b072abd7a0df4cbba8ce88eb1bcb288844000ab759", + "sha256:ad470b21cdfdc75e829cd91c8d8eb7e0438ab8ddb5b50828125ff7ada121ee7b" ], "markers": "python_version < '4.0' and python_full_version >= '3.8.1'", - "version": "==0.1.17" + "version": "==0.1.18" }, "langchain-experimental": { "hashes": [ @@ -1681,6 +1690,14 @@ "markers": "python_version >= '3.7'", "version": "==1.3.0" }, + "soupsieve": { + "hashes": [ + "sha256:5663d5a7b3bfaeee0bc4372e7fc48f9cff4940b3eec54a6451cc5299f1097690", + "sha256:eaa337ff55a1579b6549dc679565eac1e3d000563bcb1c8ab0d0fefbc0c2cdc7" + ], + "markers": "python_version >= '3.8'", + "version": "==2.5" + }, "sqlalchemy": { "hashes": [ "sha256:0d3cab3076af2e4aa5693f89622bef7fa770c6fec967143e4da7508b3dceb9b9", @@ -1839,7 +1856,7 @@ "sha256:c97dfde1f7bd43a71c8d2a58e369e9b2bf692d1334ea9f9cae55add7d0dd0f84", "sha256:fdb6d215c776278489906c2f8916e6e7d4f5a9b602ccbcfdf7f016fc8da0596e" ], - "markers": "python_version >= '3.6'", + "markers": "python_version >= '3.7'", "version": "==2.0.7" }, "vine": { diff --git a/compose/local/django/Dockerfile b/compose/local/django/Dockerfile index adfc02af..a4d28829 100644 --- a/compose/local/django/Dockerfile +++ b/compose/local/django/Dockerfile @@ -8,6 +8,8 @@ FROM python as python-build-stage ARG BUILD_ENVIRONMENT=local +ENV PATH /venv/bin:$PATH + # Install apt packages RUN apt-get update && apt-get install --no-install-recommends -y \ # dependencies for building Python packages diff --git a/compose/production/django/Dockerfile b/compose/production/django/Dockerfile index 165933d6..cc860b4b 100644 --- a/compose/production/django/Dockerfile +++ b/compose/production/django/Dockerfile @@ -8,6 +8,8 @@ FROM python as python-build-stage ARG BUILD_ENVIRONMENT=production +ENV PATH /venv/bin:$PATH + # Install apt packages RUN apt-get update && apt-get install --no-install-recommends -y \ # dependencies for building Python packages diff --git a/compose/production/django/entrypoint b/compose/production/django/entrypoint index 599841ed..e61c71aa 100644 --- a/compose/production/django/entrypoint +++ b/compose/production/django/entrypoint @@ -20,17 +20,12 @@ postgres_ready() { python << END import sys -import psycopg2 +import psycopg try: - psycopg2.connect( - dbname="${POSTGRES_DB}", - user="${POSTGRES_USER}", - password="${POSTGRES_PASSWORD}", - host="${POSTGRES_HOST}", - port="${POSTGRES_PORT}", - ) -except psycopg2.OperationalError: + psycopg.connect(conninfo="${DATABASE_URL}") +except psycopg.OperationalError as e: + print(e) sys.exit(-1) sys.exit(0) diff --git a/compose/production/django/start b/compose/production/django/start index 460415c2..db8314ea 100644 --- a/compose/production/django/start +++ b/compose/production/django/start @@ -10,4 +10,4 @@ fi python /app/manage.py collectstatic --noinput python /app/manage.py migrate -/usr/local/bin/gunicorn core.wsgi --bind 0.0.0.0:5000 --timeout 180 --chdir=/app +gunicorn core.wsgi --bind 0.0.0.0:5000 --timeout 180 --chdir=/app From d12d877560698f0689657eec1127b47412e826b6 Mon Sep 17 00:00:00 2001 From: Rithvik Nishad Date: Tue, 6 Feb 2024 19:28:43 +0530 Subject: [PATCH 2/9] Adds workflow to test build docker image (#461) * Adds workflow to test build docker image * fix checkmigrations command * Adds missing `dev-packes` category in pipenv sync for local docker --- .github/workflows/test-base.yaml | 46 ++++++++++++++++++++++++++++++++ .github/workflows/test.yaml | 12 +++++++++ Makefile | 3 +++ compose/local/django/Dockerfile | 2 +- 4 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/test-base.yaml create mode 100644 .github/workflows/test.yaml diff --git a/.github/workflows/test-base.yaml b/.github/workflows/test-base.yaml new file mode 100644 index 00000000..8fe40ca2 --- /dev/null +++ b/.github/workflows/test-base.yaml @@ -0,0 +1,46 @@ +name: Test + +on: + workflow_call: + +jobs: + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Cache Docker layers + uses: actions/cache@v3 + with: + path: /tmp/.buildx-cache + key: ${{ runner.os }}-buildx-${{ hashFiles('Pipfile.lock', 'compose/local/django/Dockerfile') }} + restore-keys: | + ${{ runner.os }}-buildx- + - name: Bake docker images + uses: docker/bake-action@v4 + with: + load: true + set: | + *.cache-from=type=local,src=/tmp/.buildx-cache + *.cache-to=type=local,dest=/tmp/.buildx-cache-new + files: docker-compose.local.yaml + + - name: Start services + run: docker compose -f docker-compose.local.yaml up -d --wait --no-build + + - name: Check migrations + run: make checkmigration + + # - name: Run tests + # run: make test-coverage + + # - name: Upload coverage report + # uses: codecov/codecov-action@v3 + + - name: Move cache + run: | + rm -rf /tmp/.buildx-cache + mv /tmp/.buildx-cache-new /tmp/.buildx-cache diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml new file mode 100644 index 00000000..2ad1168a --- /dev/null +++ b/.github/workflows/test.yaml @@ -0,0 +1,12 @@ +name: Test PR + +on: + pull_request: + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + test: + uses: ./.github/workflows/test-base.yaml diff --git a/Makefile b/Makefile index aa31b0ac..209e88c2 100644 --- a/Makefile +++ b/Makefile @@ -31,6 +31,9 @@ logs: makemigrations: up docker exec django bash -c "python manage.py makemigrations" + +checkmigration: + docker compose -f $(docker_config_file) exec django bash -c "python manage.py makemigrations --check --dry-run" test: up docker exec django bash -c "python manage.py test --keepdb --parallel=$(nproc)" diff --git a/compose/local/django/Dockerfile b/compose/local/django/Dockerfile index a4d28829..432fd92c 100644 --- a/compose/local/django/Dockerfile +++ b/compose/local/django/Dockerfile @@ -22,7 +22,7 @@ RUN pip install pipenv # Requirements are installed here to ensure they will be cached. COPY Pipfile Pipfile.lock ./ -RUN pipenv sync --system --categories "packages" +RUN pipenv sync --system --categories "packages dev-packages" # Python 'run' stage FROM python as python-run-stage From c923da422bbad374adb66f8e74a73c9e38498273 Mon Sep 17 00:00:00 2001 From: Ashesh3 <3626859+Ashesh3@users.noreply.github.com> Date: Fri, 9 Feb 2024 14:42:28 +0530 Subject: [PATCH 3/9] Add support for OpenAI TTS Engine --- ayushma/migrations/0051_project_tts_engine.py | 19 +++++++ ayushma/models/enums.py | 5 ++ ayushma/models/project.py | 5 +- ayushma/serializers/project.py | 1 + ayushma/utils/language_helpers.py | 52 ++++++++++++------- ayushma/utils/openaiapi.py | 11 +++- utils/pagination.py | 1 + 7 files changed, 72 insertions(+), 22 deletions(-) create mode 100644 ayushma/migrations/0051_project_tts_engine.py diff --git a/ayushma/migrations/0051_project_tts_engine.py b/ayushma/migrations/0051_project_tts_engine.py new file mode 100644 index 00000000..4febdac7 --- /dev/null +++ b/ayushma/migrations/0051_project_tts_engine.py @@ -0,0 +1,19 @@ +# Generated by Django 4.2.6 on 2024-02-09 08:58 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("ayushma", "0050_alter_chat_model_alter_project_model"), + ] + + operations = [ + migrations.AddField( + model_name="project", + name="tts_engine", + field=models.IntegerField( + choices=[(1, "Openai"), (2, "Google")], default=2 + ), + ), + ] diff --git a/ayushma/models/enums.py b/ayushma/models/enums.py index 56611c53..66c1e22e 100644 --- a/ayushma/models/enums.py +++ b/ayushma/models/enums.py @@ -19,6 +19,11 @@ class STTEngine(IntegerChoices): SELF_HOSTED = 3 +class TTSEngine(IntegerChoices): + OPENAI = 1 + GOOGLE = 2 + + class FeedBackRating(IntegerChoices): HALLUCINATING = 1 WRONG = 2 diff --git a/ayushma/models/project.py b/ayushma/models/project.py index e2e53531..03aeb5e4 100644 --- a/ayushma/models/project.py +++ b/ayushma/models/project.py @@ -1,7 +1,7 @@ from django.contrib.postgres.fields import ArrayField from django.db import models -from ayushma.models.enums import ModelType, STTEngine +from ayushma.models.enums import ModelType, STTEngine, TTSEngine from ayushma.models.users import User from utils.models.base import BaseModel @@ -16,6 +16,9 @@ class Project(BaseModel): stt_engine = models.IntegerField( choices=STTEngine.choices, default=STTEngine.WHISPER ) + tts_engine = models.IntegerField( + choices=TTSEngine.choices, default=TTSEngine.GOOGLE + ) model = models.IntegerField(choices=ModelType.choices, default=ModelType.GPT_3_5) preset_questions = ArrayField(models.TextField(), null=True, blank=True) is_default = models.BooleanField(default=False) diff --git a/ayushma/serializers/project.py b/ayushma/serializers/project.py index 4a7d0ddf..5681b43a 100644 --- a/ayushma/serializers/project.py +++ b/ayushma/serializers/project.py @@ -25,6 +25,7 @@ class Meta: "modified_at", "description", "stt_engine", + "tts_engine", "model", "is_default", "display_preset_questions", diff --git a/ayushma/utils/language_helpers.py b/ayushma/utils/language_helpers.py index c67e6161..886387ad 100644 --- a/ayushma/utils/language_helpers.py +++ b/ayushma/utils/language_helpers.py @@ -1,7 +1,9 @@ import re +from django.conf import settings from google.cloud import texttospeech from google.cloud import translate_v2 as translate +from openai import OpenAI from rest_framework.exceptions import APIException @@ -37,31 +39,43 @@ def sanitize_text(text): return sanitized_text -def text_to_speech(text, language_code): +def text_to_speech(text, language_code, service): try: # in en-IN neural voice is not available if language_code == "en-IN": language_code = "en-US" - client = texttospeech.TextToSpeechClient() - text = sanitize_text(text) - synthesis_input = texttospeech.SynthesisInput(text=text) - - voice = texttospeech.VoiceSelectionParams( - language_code=language_code, name=language_code_voice_map[language_code] - ) - audio_config = texttospeech.AudioConfig( - audio_encoding=texttospeech.AudioEncoding.MP3 - ) - - response = client.synthesize_speech( - input=synthesis_input, - voice=voice, - audio_config=audio_config, - ) - - return response.audio_content + + if service == "google": + client = texttospeech.TextToSpeechClient() + + synthesis_input = texttospeech.SynthesisInput(text=text) + + voice = texttospeech.VoiceSelectionParams( + language_code=language_code, name=language_code_voice_map[language_code] + ) + audio_config = texttospeech.AudioConfig( + audio_encoding=texttospeech.AudioEncoding.MP3 + ) + + response = client.synthesize_speech( + input=synthesis_input, + voice=voice, + audio_config=audio_config, + ) + + return response.audio_content + elif service == "openai": + client = OpenAI(api_key=settings.OPENAI_API_KEY) + response = client.audio.speech.create( + model="tts-1-hd", + voice="nova", + input=text, + ) + return response.read() + else: + raise APIException("Service not supported") except Exception as e: print(e) return None diff --git a/ayushma/utils/openaiapi.py b/ayushma/utils/openaiapi.py index 10f7956c..9c2c13ef 100644 --- a/ayushma/utils/openaiapi.py +++ b/ayushma/utils/openaiapi.py @@ -15,7 +15,7 @@ from ayushma.models import ChatMessage from ayushma.models.chat import Chat from ayushma.models.document import Document -from ayushma.models.enums import ChatMessageType, ModelType +from ayushma.models.enums import ChatMessageType, ModelType, TTSEngine from ayushma.utils.langchain import LangChainHelper from ayushma.utils.language_helpers import text_to_speech, translate_text from core.settings.base import AI_NAME @@ -203,6 +203,7 @@ def handle_post_response( temperature, stats, language, + tts_engine, generate_audio=True, ): chat_message: ChatMessage = ChatMessage.objects.create( @@ -225,7 +226,9 @@ def handle_post_response( ayushma_voice = None if generate_audio: stats["tts_start_time"] = time.time() - ayushma_voice = text_to_speech(translated_chat_response, user_language) + ayushma_voice = text_to_speech( + translated_chat_response, user_language, tts_engine + ) stats["tts_end_time"] = time.time() url = None @@ -324,6 +327,8 @@ def converse( elif message.messageType == ChatMessageType.AYUSHMA: chat_history.append(AIMessage(content=f"Ayushma: {message.message}")) + tts_engine = TTSEngine(chat.project.tts_engine).name.lower() + if not stream: lang_chain_helper = LangChainHelper( stream=False, @@ -347,6 +352,7 @@ def converse( temperature, stats, language, + tts_engine, generate_audio, ) @@ -404,6 +410,7 @@ def converse( temperature, stats, language, + tts_engine, generate_audio, ) diff --git a/utils/pagination.py b/utils/pagination.py index 05509fe4..c54def1c 100644 --- a/utils/pagination.py +++ b/utils/pagination.py @@ -13,5 +13,6 @@ def get_paginated_response(self, data): "has_previous": self.offset > 0, "has_next": self.offset + self.limit < self.count, "results": data, + "offset": self.offset, } ) From a94271e00bc802113c678a5844e009e4b301c7cb Mon Sep 17 00:00:00 2001 From: ishanExtreme Date: Sat, 10 Feb 2024 03:06:19 +0530 Subject: [PATCH 4/9] OpenAI STT fixed --- ayushma/utils/speech_to_text.py | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/ayushma/utils/speech_to_text.py b/ayushma/utils/speech_to_text.py index 6e906dfc..551ba73e 100644 --- a/ayushma/utils/speech_to_text.py +++ b/ayushma/utils/speech_to_text.py @@ -1,9 +1,9 @@ import os -import openai import requests from django.conf import settings from google.cloud import speech +from openai import OpenAI from ayushma.models.enums import STTEngine @@ -14,19 +14,14 @@ def __init__(self, api_key, language_code): self.language_code = language_code def recognize(self, audio): - # workaround for setting api version ( https://github.com/openai/openai-python/pull/491 ) - current_api_version = openai.api_version - openai.api_version = "2020-11-07" - transcription = openai.Audio.transcribe( - "whisper-1", - file=audio, + client = OpenAI(api_key=self.api_key) + transcription = client.audio.transcriptions.create( + model="whisper-1", + # https://github.com/openai/openai-python/tree/main#file-uploads + file=(audio.name, audio.read()), language=self.language_code.replace("-IN", ""), - api_key=self.api_key, - api_base="https://api.openai.com/v1", - api_type="open_ai", - api_version="2020-11-07", # Bug in openai package, this parameter is ignored + # api_version="2020-11-07", ) - openai.api_version = current_api_version return transcription.text @@ -94,6 +89,7 @@ def speech_to_text(engine_id, audio, language_code): recognized_text = engine.recognize(audio) if not recognized_text: raise ValueError("Failed to detect any speech in provided audio") + return recognized_text except Exception as e: print(f"Failed to recognize speech with {engine_name} engine: {e}") raise e From 4c0744921e4ea8fce51cedcf7c3d05aecd822b7d Mon Sep 17 00:00:00 2001 From: Ashesh <3626859+Ashesh3@users.noreply.github.com> Date: Sun, 11 Feb 2024 20:23:16 +0530 Subject: [PATCH 5/9] Apply suggestions from code review Co-authored-by: Rithvik Nishad --- ayushma/models/enums.py | 4 ++-- ayushma/utils/language_helpers.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ayushma/models/enums.py b/ayushma/models/enums.py index 66c1e22e..a7a7c9cb 100644 --- a/ayushma/models/enums.py +++ b/ayushma/models/enums.py @@ -20,8 +20,8 @@ class STTEngine(IntegerChoices): class TTSEngine(IntegerChoices): - OPENAI = 1 - GOOGLE = 2 + OPENAI = (1, "openai") + GOOGLE = (2, "google") class FeedBackRating(IntegerChoices): diff --git a/ayushma/utils/language_helpers.py b/ayushma/utils/language_helpers.py index 886387ad..35b5cfd2 100644 --- a/ayushma/utils/language_helpers.py +++ b/ayushma/utils/language_helpers.py @@ -47,7 +47,7 @@ def text_to_speech(text, language_code, service): text = sanitize_text(text) - if service == "google": + if service == TTSEngine.GOOGLE: client = texttospeech.TextToSpeechClient() synthesis_input = texttospeech.SynthesisInput(text=text) @@ -66,7 +66,7 @@ def text_to_speech(text, language_code, service): ) return response.audio_content - elif service == "openai": + elif service == TTSEngine.OPENAI: client = OpenAI(api_key=settings.OPENAI_API_KEY) response = client.audio.speech.create( model="tts-1-hd", From 8b99bff5d9e7069e7a09c0a6d1329586235b915c Mon Sep 17 00:00:00 2001 From: Ashesh3 <3626859+Ashesh3@users.noreply.github.com> Date: Sun, 11 Feb 2024 20:26:09 +0530 Subject: [PATCH 6/9] Update tts_engine field to use SmallIntegerField --- ayushma/migrations/0051_project_tts_engine.py | 2 +- ayushma/models/project.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ayushma/migrations/0051_project_tts_engine.py b/ayushma/migrations/0051_project_tts_engine.py index 4febdac7..79ef57ce 100644 --- a/ayushma/migrations/0051_project_tts_engine.py +++ b/ayushma/migrations/0051_project_tts_engine.py @@ -12,7 +12,7 @@ class Migration(migrations.Migration): migrations.AddField( model_name="project", name="tts_engine", - field=models.IntegerField( + field=models.SmallIntegerField( choices=[(1, "Openai"), (2, "Google")], default=2 ), ), diff --git a/ayushma/models/project.py b/ayushma/models/project.py index 03aeb5e4..5ebcc76d 100644 --- a/ayushma/models/project.py +++ b/ayushma/models/project.py @@ -16,7 +16,7 @@ class Project(BaseModel): stt_engine = models.IntegerField( choices=STTEngine.choices, default=STTEngine.WHISPER ) - tts_engine = models.IntegerField( + tts_engine = models.SmallIntegerField( choices=TTSEngine.choices, default=TTSEngine.GOOGLE ) model = models.IntegerField(choices=ModelType.choices, default=ModelType.GPT_3_5) From 1bb3761da1c7c70824fb1e8ce9173c98061fefa5 Mon Sep 17 00:00:00 2001 From: Ashesh3 <3626859+Ashesh3@users.noreply.github.com> Date: Sun, 11 Feb 2024 20:34:05 +0530 Subject: [PATCH 7/9] Update settings.json and language_helpers.py files --- ayushma/utils/language_helpers.py | 2 ++ ayushma/utils/openaiapi.py | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/ayushma/utils/language_helpers.py b/ayushma/utils/language_helpers.py index 35b5cfd2..460e2093 100644 --- a/ayushma/utils/language_helpers.py +++ b/ayushma/utils/language_helpers.py @@ -6,6 +6,8 @@ from openai import OpenAI from rest_framework.exceptions import APIException +from ayushma.models.enums import TTSEngine + def translate_text(target, text): try: diff --git a/ayushma/utils/openaiapi.py b/ayushma/utils/openaiapi.py index 9c2c13ef..2326d5ff 100644 --- a/ayushma/utils/openaiapi.py +++ b/ayushma/utils/openaiapi.py @@ -15,7 +15,7 @@ from ayushma.models import ChatMessage from ayushma.models.chat import Chat from ayushma.models.document import Document -from ayushma.models.enums import ChatMessageType, ModelType, TTSEngine +from ayushma.models.enums import ChatMessageType, ModelType from ayushma.utils.langchain import LangChainHelper from ayushma.utils.language_helpers import text_to_speech, translate_text from core.settings.base import AI_NAME @@ -327,7 +327,7 @@ def converse( elif message.messageType == ChatMessageType.AYUSHMA: chat_history.append(AIMessage(content=f"Ayushma: {message.message}")) - tts_engine = TTSEngine(chat.project.tts_engine).name.lower() + tts_engine = chat.project.tts_engine if not stream: lang_chain_helper = LangChainHelper( From 6c18a39a86e03268332f449954d89df275416751 Mon Sep 17 00:00:00 2001 From: Ashesh3 <3626859+Ashesh3@users.noreply.github.com> Date: Sun, 11 Feb 2024 20:54:00 +0530 Subject: [PATCH 8/9] Update project TTS engine choices --- ayushma/migrations/0051_project_tts_engine.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ayushma/migrations/0051_project_tts_engine.py b/ayushma/migrations/0051_project_tts_engine.py index 79ef57ce..5ddc3372 100644 --- a/ayushma/migrations/0051_project_tts_engine.py +++ b/ayushma/migrations/0051_project_tts_engine.py @@ -1,4 +1,4 @@ -# Generated by Django 4.2.6 on 2024-02-09 08:58 +# Generated by Django 4.2.6 on 2024-02-11 15:23 from django.db import migrations, models @@ -13,7 +13,7 @@ class Migration(migrations.Migration): model_name="project", name="tts_engine", field=models.SmallIntegerField( - choices=[(1, "Openai"), (2, "Google")], default=2 + choices=[(1, "openai"), (2, "google")], default=2 ), ), ] From fba55aa2216d658855b20a396f41b0e0ab0c1c02 Mon Sep 17 00:00:00 2001 From: Ishan Mishra Date: Tue, 20 Feb 2024 13:39:01 +0530 Subject: [PATCH 9/9] immediate display transcribed text added (#472) --- ayushma/models/chat.py | 1 + ayushma/serializers/chat.py | 15 ++++++++++--- ayushma/utils/converse.py | 6 +++++ ayushma/views/chat.py | 44 ++++++++++++++++++++++++++++++++++++- 4 files changed, 62 insertions(+), 4 deletions(-) diff --git a/ayushma/models/chat.py b/ayushma/models/chat.py index c83d005c..425633ca 100644 --- a/ayushma/models/chat.py +++ b/ayushma/models/chat.py @@ -32,6 +32,7 @@ class ChatMessage(BaseModel): original_message = models.TextField(blank=True, null=True) language = models.CharField(max_length=10, blank=False, default="en") reference_documents = models.ManyToManyField(Document, blank=True) + # generated ayushma voice audio via TTS audio = models.FileField(blank=True, null=True) meta = models.JSONField(blank=True, null=True) temperature = models.FloatField(blank=True, null=True) diff --git a/ayushma/serializers/chat.py b/ayushma/serializers/chat.py index ec713884..e133e3cd 100644 --- a/ayushma/serializers/chat.py +++ b/ayushma/serializers/chat.py @@ -110,6 +110,8 @@ class ConverseSerializer(serializers.Serializer): stream = serializers.BooleanField(default=True) generate_audio = serializers.BooleanField(default=True) noonce = serializers.CharField(required=False) + transcript_start_time = serializers.FloatField(required=False) + transcript_end_time = serializers.FloatField(required=False) class ChatDetailSerializer(serializers.ModelSerializer): @@ -146,9 +148,11 @@ def get_chats(self, obj): ) return [ { - "messageType": ChatMessageType.USER - if thread_message.role == "user" - else ChatMessageType.AYUSHMA, + "messageType": ( + ChatMessageType.USER + if thread_message.role == "user" + else ChatMessageType.AYUSHMA + ), "message": thread_message.content[0].text.value, "reference_documents": thread_message.content[0].text.annotations, "language": "en", @@ -159,3 +163,8 @@ def get_chats(self, obj): chatmessages = ChatMessage.objects.filter(chat=obj).order_by("created_at") context = {"request": self.context.get("request")} return ChatMessageSerializer(chatmessages, many=True, context=context).data + + +class SpeechToTextSerializer(serializers.Serializer): + audio = serializers.FileField(required=True) + language = serializers.CharField(default="en") diff --git a/ayushma/utils/converse.py b/ayushma/utils/converse.py index 2dacb0b1..19ea4aca 100644 --- a/ayushma/utils/converse.py +++ b/ayushma/utils/converse.py @@ -33,6 +33,7 @@ def converse_api( audio = request.data.get("audio") text = request.data.get("text") language = request.data.get("language") or "en" + try: service: Service = request.service except AttributeError: @@ -128,6 +129,11 @@ def converse_api( translated_text = transcript elif converse_type == "text": + if request.data.get("transcript_start_time") and request.data.get( + "transcript_end_time" + ): + stats["transcript_start_time"] = request.data["transcript_start_time"] + stats["transcript_end_time"] = request.data["transcript_end_time"] translated_text = text if language != "en": diff --git a/ayushma/views/chat.py b/ayushma/views/chat.py index 7a1cceaf..c6f72163 100644 --- a/ayushma/views/chat.py +++ b/ayushma/views/chat.py @@ -1,7 +1,9 @@ +import time + from django.conf import settings from drf_spectacular.utils import extend_schema from rest_framework import filters, status -from rest_framework.decorators import action +from rest_framework.decorators import action, api_view, permission_classes from rest_framework.exceptions import ValidationError from rest_framework.mixins import ( CreateModelMixin, @@ -20,8 +22,10 @@ ChatFeedbackSerializer, ChatSerializer, ConverseSerializer, + SpeechToTextSerializer, ) from ayushma.utils.converse import converse_api +from ayushma.utils.speech_to_text import speech_to_text from utils.views.base import BaseModelViewSet from utils.views.mixins import PartialUpdateModelMixin @@ -42,6 +46,7 @@ class ChatViewSet( "retrieve": ChatDetailSerializer, "list_all": ChatDetailSerializer, "converse": ConverseSerializer, + "speech_to_text": SpeechToTextSerializer, } permission_classes = (IsTempTokenOrAuthenticated,) lookup_field = "external_id" @@ -100,6 +105,43 @@ def list_all(self, *args, **kwarg): serializer = self.get_serializer(queryset, many=True) return Response(serializer.data) + @extend_schema( + tags=("chats",), + ) + @action(detail=True, methods=["post"]) + def speech_to_text(self, *args, **kwarg): + serializer = self.get_serializer(data=self.request.data) + serializer.is_valid() + + project_id = kwarg["project_external_id"] + audio = serializer.validated_data["audio"] + language = serializer.validated_data.get("language", "en") + + stats = {} + try: + stt_engine = Project.objects.get(external_id=project_id).stt_engine + except Project.DoesNotExist: + return Response( + {"error": "Project not found"}, status=status.HTTP_400_BAD_REQUEST + ) + try: + stats["transcript_start_time"] = time.time() + transcript = speech_to_text(stt_engine, audio, language + "-IN") + stats["transcript_end_time"] = time.time() + translated_text = transcript + except Exception as e: + print(f"Failed to transcribe speech with {stt_engine} engine: {e}") + return Response( + { + "error": "Something went wrong in getting transcription, please try again later" + }, + status=status.HTTP_500_INTERNAL_SERVER_ERROR, + ) + + return Response( + {"transcript": translated_text, "stats": stats}, status=status.HTTP_200_OK + ) + @extend_schema( tags=("chats",), )