diff --git a/Pipfile b/Pipfile index c12a69b..02073f5 100644 --- a/Pipfile +++ b/Pipfile @@ -11,6 +11,7 @@ requests = "*" "flask[async]" = "*" gunicorn = "*" typer = {extras = ["all"], version = "*"} +google-cloud-texttospeech = "*" [dev-packages] pylint = "*" diff --git a/Pipfile.lock b/Pipfile.lock index ec725f5..b56fade 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "d71eed3c158ba0ba42870f4d435a315f5c6acbcc1ed5167f3c2ec09b273dfef2" + "sha256": "472f9dafc5cddba4d0b7bfddc75a013689d65f50c7017097aae83f4f14e672dd" }, "pipfile-spec": 6, "requires": { @@ -23,13 +23,21 @@ ], "version": "==3.5.2" }, + "cachetools": { + "hashes": [ + "sha256:6a94c6402995a99c3970cc7e4884bb60b4a8639938157eeed436098bf9831757", + "sha256:f9f17d2aec496a9aa6b76f53e3b614c965223c061982d434d160f930c698a9db" + ], + "markers": "python_version ~= '3.7'", + "version": "==5.2.0" + }, "certifi": { "hashes": [ - "sha256:84c85a9078b11105f04f3036a9482ae10e4621616db313fe045dd24743a0820d", - "sha256:fe86415d55e84719d75f8b69414f6438ac3547d2078ab91b67e779ef69378412" + "sha256:0d9c601124e5a6ba9712dbc60d9c53c21e34f5f641fe83002317394311bdce14", + "sha256:90c1a32f1d68f940488354e36370f6cca89f0f106db09518524c88d6ed83f382" ], "markers": "python_version >= '3.6'", - "version": "==2022.6.15" + "version": "==2022.9.24" }, "charset-normalizer": { "hashes": [ @@ -77,6 +85,98 @@ "git": "https://github.com/MTG/freesound-python.git", "ref": "59272aa426ea19e795624095e131a3151b56f1e7" }, + "google-api-core": { + "extras": [ + "grpc" + ], + "hashes": [ + "sha256:10c06f7739fe57781f87523375e8e1a3a4674bf6392cd6131a3222182b971320", + "sha256:34f24bd1d5f72a8c4519773d99ca6bf080a6c4e041b4e9f024fe230191dda62e" + ], + "markers": "python_version >= '3.7'", + "version": "==2.10.2" + }, + "google-auth": { + "hashes": [ + "sha256:98f601773978c969e1769f97265e732a81a8e598da3263895023958d456ee625", + "sha256:f12d86502ce0f2c0174e2e70ecc8d36c69593817e67e1d9c5e34489120422e4b" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'", + "version": "==2.12.0" + }, + "google-cloud-texttospeech": { + "hashes": [ + "sha256:1f112bbaf72c9dcd2d5dc5d8dd7912672a33243527faab64d3087950afc216b6", + "sha256:cfface32a43e524265f33c39e493f9e3eb3e424fa01f19ae0438d96b3dd069cb" + ], + "index": "pypi", + "version": "==2.12.2" + }, + "googleapis-common-protos": { + "hashes": [ + "sha256:8eb2cbc91b69feaf23e32452a7ae60e791e09967d81d4fcc7fc388182d1bd394", + "sha256:c25873c47279387cfdcbdafa36149887901d36202cb645a0e4f29686bf6e4417" + ], + "markers": "python_version >= '3.7'", + "version": "==1.56.4" + }, + "grpcio": { + "hashes": [ + "sha256:075f2d06e3db6b48a2157a1bcd52d6cbdca980dd18988fe6afdb41795d51625f", + "sha256:08ff74aec8ff457a89b97152d36cb811dcc1d17cd5a92a65933524e363327394", + "sha256:0b24a74651438d45619ac67004638856f76cc13d78b7478f2457754cbcb1c8ad", + "sha256:0e20d59aafc086b1cc68400463bddda6e41d3e5ed30851d1e2e0f6a2e7e342d3", + "sha256:120fecba2ec5d14b5a15d11063b39783fda8dc8d24addd83196acb6582cabd9b", + "sha256:17bb6fe72784b630728c6cff9c9d10ccc3b6d04e85da6e0a7b27fb1d135fac62", + "sha256:18305d5a082d1593b005a895c10041f833b16788e88b02bb81061f5ebcc465df", + "sha256:196082b9c89ebf0961dcd77cb114bed8171964c8e3063b9da2fb33536a6938ed", + "sha256:1c66a25afc6c71d357867b341da594a5587db5849b48f4b7d5908d236bb62ede", + "sha256:1cc400c8a2173d1c042997d98a9563e12d9bb3fb6ad36b7f355bc77c7663b8af", + "sha256:2070e87d95991473244c72d96d13596c751cb35558e11f5df5414981e7ed2492", + "sha256:2106d9c16527f0a85e2eea6e6b91a74fc99579c60dd810d8690843ea02bc0f5f", + "sha256:221d42c654d2a41fa31323216279c73ed17d92f533bc140a3390cc1bd78bf63c", + "sha256:274ffbb39717918c514b35176510ae9be06e1d93121e84d50b350861dcb9a705", + "sha256:2f2ff7ba0f8f431f32d4b4bc3a3713426949d3533b08466c4ff1b2b475932ca8", + "sha256:34f736bd4d0deae90015c0e383885b431444fe6b6c591dea288173df20603146", + "sha256:46d93a1b4572b461a227f1db6b8d35a88952db1c47e5fadcf8b8a2f0e1dd9201", + "sha256:49b301740cf5bc8fed4fee4c877570189ae3951432d79fa8e524b09353659811", + "sha256:4fcedcab49baaa9db4a2d240ac81f2d57eb0052b1c6a9501b46b8ae912720fbf", + "sha256:5207f4eed1b775d264fcfe379d8541e1c43b878f2b63c0698f8f5c56c40f3d68", + "sha256:52dd02b7e7868233c571b49bc38ebd347c3bb1ff8907bb0cb74cb5f00c790afc", + "sha256:5f8b3a971c7820ea9878f3fd70086240a36aeee15d1b7e9ecbc2743b0e785568", + "sha256:64419cb8a5b612cdb1550c2fd4acbb7d4fb263556cf4625f25522337e461509e", + "sha256:6b6c3a95d27846f4145d6967899b3ab25fffc6ae99544415e1adcacef84842d2", + "sha256:6fd0c9cede9552bf00f8c5791d257d5bf3790d7057b26c59df08be5e7a1e021d", + "sha256:822ceec743d42a627e64ea266059a62d214c5a3cdfcd0d7fe2b7a8e4e82527c7", + "sha256:8a5272061826e6164f96e3255405ef6f73b88fd3e8bef464c7d061af8585ac62", + "sha256:8c9f89c42749890618cd3c2464e1fbf88446e3d2f67f1e334c8e5db2f3272bbd", + "sha256:9b449e966ef518ce9c860d21f8afe0b0f055220d95bc710301752ac1db96dd6a", + "sha256:9fb17ff8c0d56099ac6ebfa84f670c5a62228d6b5c695cf21c02160c2ac1446b", + "sha256:a4f9ba141380abde6c3adc1727f21529137a2552002243fa87c41a07e528245c", + "sha256:a7d0017b92d3850abea87c1bdec6ea41104e71c77bca44c3e17f175c6700af62", + "sha256:aa34d2ad9f24e47fa9a3172801c676e4037d862247e39030165fe83821a7aafd", + "sha256:afbb3475cf7f4f7d380c2ca37ee826e51974f3e2665613996a91d6a58583a534", + "sha256:b6a1b39e59ac5a3067794a0e498911cf2e37e4b19ee9e9977dc5e7051714f13f", + "sha256:cf0a1fb18a7204b9c44623dfbd1465b363236ce70c7a4ed30402f9f60d8b743b", + "sha256:d0d402e158d4e84e49c158cb5204119d55e1baf363ee98d6cb5dce321c3a065d", + "sha256:d4725fc9ec8e8822906ae26bb26f5546891aa7fbc3443de970cc556d43a5c99f", + "sha256:dc79b2b37d779ac42341ddef40ad5bf0966a64af412c89fc2b062e3ddabb093f", + "sha256:e1e83233d4680863a421f3ee4a7a9b80d33cd27ee9ed7593bc93f6128302d3f2", + "sha256:ea9d0172445241ad7cb49577314e39d0af2c5267395b3561d7ced5d70458a9f3", + "sha256:f1a3b88e3c53c1a6e6bed635ec1bbb92201bb6a1f2db186179f7f3f244829788", + "sha256:fa9e6e61391e99708ac87fc3436f6b7b9c6b845dc4639b406e5e61901e1aacde", + "sha256:fd86040232e805b8e6378b2348c928490ee595b058ce9aaa27ed8e4b0f172b20", + "sha256:fe763781669790dc8b9618e7e677c839c87eae6cf28b655ee1fa69ae04eea03f" + ], + "version": "==1.49.1" + }, + "grpcio-status": { + "hashes": [ + "sha256:658f48dc146ee0c7b6eebd302d74e0d45c00727c20035ff51d68750dbaccf5d9", + "sha256:fe4ae9f624f03e50ccf6f6ead60727ab20b17735bb3d0dd506ef355349282378" + ], + "version": "==1.49.1" + }, "gunicorn": { "hashes": [ "sha256:9dcc4547dbb1cb284accfb15ab5667a0e5d1881cc443e0677b4882a4067a807e", @@ -87,11 +187,11 @@ }, "idna": { "hashes": [ - "sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff", - "sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d" + "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4", + "sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2" ], "markers": "python_version >= '3.5'", - "version": "==3.3" + "version": "==3.4" }, "itsdangerous": { "hashes": [ @@ -155,6 +255,70 @@ "markers": "python_version >= '3.7'", "version": "==2.1.1" }, + "proto-plus": { + "hashes": [ + "sha256:6c7dfd122dfef8019ff654746be4f5b1d9c80bba787fe9611b508dd88be3a2fa", + "sha256:ea8982669a23c379f74495bc48e3dcb47c822c484ce8ee1d1d7beb339d4e34c5" + ], + "markers": "python_version >= '3.6'", + "version": "==1.22.1" + }, + "protobuf": { + "hashes": [ + "sha256:3ec85328a35a16463c6f419dbce3c0fc42b3e904d966f17f48bae39597c7a543", + "sha256:58b81358ec6c0b5d50df761460ae2db58405c063fd415e1101209221a0a810e1", + "sha256:71d9dba03ed3432c878a801e2ea51e034b0ea01cf3a4344fb60166cb5f6c8757", + "sha256:8066322588d4b499869bf9f665ebe448e793036b552f68c585a9b28f1e393f66", + "sha256:8e09d1916386eca1ef1353767b6efcebc0a6859ed7f73cb7fb974feba3184830", + "sha256:9643684232b6b340b5e63bb69c9b4904cdd39e4303d498d1a92abddc7e895b7f", + "sha256:9e355f2a839d9930d83971b9f562395e13493f0e9211520f8913bd11efa53c02", + "sha256:a74d96cd960b87b4b712797c741bb3ea3a913f5c2dc4b6cbe9c0f8360b75297d", + "sha256:b019c79e23a80735cc8a71b95f76a49a262f579d6b84fd20a0b82279f40e2cc1", + "sha256:c7cb105d69a87416bd9023e64324e1c089593e6dae64d2536f06bcbe49cd97d8", + "sha256:ca200645d6235ce0df3ccfdff1567acbab35c4db222a97357806e015f85b5744", + "sha256:d3f89ccf7182293feba2de2739c8bf34fed1ed7c65a5cf987be00311acac57c1", + "sha256:db9056b6a11cb5131036d734bcbf91ef3ef9235d6b681b2fc431cbfe5a7f2e56", + "sha256:f370c0a71712f8965023dd5b13277444d3cdfecc96b2c778b0e19acbfd60df6e" + ], + "markers": "python_version >= '3.7'", + "version": "==4.21.7" + }, + "pyasn1": { + "hashes": [ + "sha256:014c0e9976956a08139dc0712ae195324a75e142284d5f87f1a87ee1b068a359", + "sha256:03840c999ba71680a131cfaee6fab142e1ed9bbd9c693e285cc6aca0d555e576", + "sha256:0458773cfe65b153891ac249bcf1b5f8f320b7c2ce462151f8fa74de8934becf", + "sha256:08c3c53b75eaa48d71cf8c710312316392ed40899cb34710d092e96745a358b7", + "sha256:39c7e2ec30515947ff4e87fb6f456dfc6e84857d34be479c9d4a4ba4bf46aa5d", + "sha256:5c9414dcfede6e441f7e8f81b43b34e834731003427e5b09e4e00e3172a10f00", + "sha256:6e7545f1a61025a4e58bb336952c5061697da694db1cae97b116e9c46abcf7c8", + "sha256:78fa6da68ed2727915c4767bb386ab32cdba863caa7dbe473eaae45f9959da86", + "sha256:7ab8a544af125fb704feadb008c99a88805126fb525280b2270bb25cc1d78a12", + "sha256:99fcc3c8d804d1bc6d9a099921e39d827026409a58f2a720dcdb89374ea0c776", + "sha256:aef77c9fb94a3ac588e87841208bdec464471d9871bd5050a287cc9a475cd0ba", + "sha256:e89bf84b5437b532b0803ba5c9a5e054d21fec423a89952a74f87fa2c9b7bce2", + "sha256:fec3e9d8e36808a28efb59b489e4528c10ad0f480e57dcc32b4de5c9d8c9fdf3" + ], + "version": "==0.4.8" + }, + "pyasn1-modules": { + "hashes": [ + "sha256:0845a5582f6a02bb3e1bde9ecfc4bfcae6ec3210dd270522fee602365430c3f8", + "sha256:0fe1b68d1e486a1ed5473f1302bd991c1611d319bba158e98b106ff86e1d7199", + "sha256:15b7c67fabc7fc240d87fb9aabf999cf82311a6d6fb2c70d00d3d0604878c811", + "sha256:426edb7a5e8879f1ec54a1864f16b882c2837bfd06eee62f2c982315ee2473ed", + "sha256:65cebbaffc913f4fe9e4808735c95ea22d7a7775646ab690518c056784bc21b4", + "sha256:905f84c712230b2c592c19470d3ca8d552de726050d1d1716282a1f6146be65e", + "sha256:a50b808ffeb97cb3601dd25981f6b016cbb3d31fbf57a8b8a87428e6158d0c74", + "sha256:a99324196732f53093a84c4369c996713eb8c89d360a496b599fb1a9c47fc3eb", + "sha256:b80486a6c77252ea3a3e9b1e360bc9cf28eaac41263d173c032581ad2f20fe45", + "sha256:c29a5e5cc7a3f05926aff34e097e84f8589cd790ce0ed41b67aed6857b26aafd", + "sha256:cbac4bc38d117f2a49aeedec4407d23e8866ea4ac27ff2cf7fb3e5b570df19e0", + "sha256:f39edd8c4ecaa4556e989147ebf219227e2cd2e8a43c7e7fcb1f1c18c5fd6a3d", + "sha256:fe0644d9ab041506b62782e92b06b8c68cca799e1a9636ec398675459e031405" + ], + "version": "==0.2.8" + }, "pydub": { "hashes": [ "sha256:65617e33033874b59d87db603aa1ed450633288aefead953b30bded59cb599a6", @@ -181,18 +345,26 @@ }, "rich": { "hashes": [ - "sha256:2eb4e6894cde1e017976d2975ac210ef515d7548bc595ba20e195fb9628acdeb", - "sha256:63a5c5ce3673d3d5fbbf23cd87e11ab84b6b451436f1b7f19ec54b6bc36ed7ca" + "sha256:a4eb26484f2c82589bd9a17c73d32a010b1e29d89f1604cd9bf3a2097b81bb5e", + "sha256:ba3a3775974105c221d31141f2c116f4fd65c5ceb0698657a11e9f295ec93fd0" ], - "version": "==12.5.1" + "version": "==12.6.0" + }, + "rsa": { + "hashes": [ + "sha256:90260d9058e514786967344d0ef75fa8727eed8a7d2e43ce9f4bcf1b536174f7", + "sha256:e38464a49c6c85d7f1351b0126661487a7e0a14a50f1675ec50eb34d4f20ef21" + ], + "markers": "python_version >= '3.6'", + "version": "==4.9" }, "setuptools": { "hashes": [ - "sha256:2e24e0bec025f035a2e72cdd1961119f557d78ad331bb00ff82efb2ab8da8e82", - "sha256:7732871f4f7fa58fb6bdcaeadb0161b2bd046c85905dbaa066bdcbcc81953b57" + "sha256:1b6bdc6161661409c5f21508763dc63ab20a9ac2f8ba20029aaaa7fdb9118012", + "sha256:3050e338e5871e70c72983072fe34f6032ae1cdeeeb67338199c2f74e083a80e" ], "markers": "python_version >= '3.7'", - "version": "==65.3.0" + "version": "==65.4.1" }, "shellingham": { "hashes": [ @@ -201,12 +373,21 @@ ], "version": "==1.5.0" }, + "six": { + "hashes": [ + "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", + "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==1.16.0" + }, "termcolor": { "hashes": [ - "sha256:1d6d69ce66211143803fbc56652b41d73b4a400a2891d7bf7a1cdf4c02de613b" + "sha256:6b2cf769e93364a2676e1de56a7c0cff2cf5bd07f37e9cc80b0dd6320ebfe388", + "sha256:7e597f9de8e001a3208c4132938597413b9da45382b6f1d150cff8d062b7aaa3" ], "index": "pypi", - "version": "==1.1.0" + "version": "==2.0.1" }, "typer": { "extras": [ @@ -239,11 +420,11 @@ "develop": { "astroid": { "hashes": [ - "sha256:bf0fe7ff5d28f697f5eddc9f33140ad6086941c472f53e9dbbb9aaa6bc8952cb", - "sha256:cfef6fa5aeba225d01f217e435472da458711bceb949c6eccb07dc93701edd29" + "sha256:81f870105d892e73bf535da77a8261aa5bde838fa4ed12bb2f435291a098c581", + "sha256:997e0c735df60d4a4caff27080a3afc51f9bdd693d3572a4a0b7090b645c36c5" ], "markers": "python_full_version >= '3.7.2'", - "version": "==2.12.6" + "version": "==2.12.10" }, "attrs": { "hashes": [ @@ -255,32 +436,30 @@ }, "black": { "hashes": [ - "sha256:0a12e4e1353819af41df998b02c6742643cfef58282915f781d0e4dd7a200411", - "sha256:0ad827325a3a634bae88ae7747db1a395d5ee02cf05d9aa7a9bd77dfb10e940c", - "sha256:32a4b17f644fc288c6ee2bafdf5e3b045f4eff84693ac069d87b1a347d861497", - "sha256:3b2c25f8dea5e8444bdc6788a2f543e1fb01494e144480bc17f806178378005e", - "sha256:4a098a69a02596e1f2a58a2a1c8d5a05d5a74461af552b371e82f9fa4ada8342", - "sha256:5107ea36b2b61917956d018bd25129baf9ad1125e39324a9b18248d362156a27", - "sha256:53198e28a1fb865e9fe97f88220da2e44df6da82b18833b588b1883b16bb5d41", - "sha256:5594efbdc35426e35a7defa1ea1a1cb97c7dbd34c0e49af7fb593a36bd45edab", - "sha256:5b879eb439094751185d1cfdca43023bc6786bd3c60372462b6f051efa6281a5", - "sha256:78dd85caaab7c3153054756b9fe8c611efa63d9e7aecfa33e533060cb14b6d16", - "sha256:792f7eb540ba9a17e8656538701d3eb1afcb134e3b45b71f20b25c77a8db7e6e", - "sha256:8ce13ffed7e66dda0da3e0b2eb1bdfc83f5812f66e09aca2b0978593ed636b6c", - "sha256:a05da0430bd5ced89176db098567973be52ce175a55677436a271102d7eaa3fe", - "sha256:a983526af1bea1e4cf6768e649990f28ee4f4137266921c2c3cee8116ae42ec3", - "sha256:bc4d4123830a2d190e9cc42a2e43570f82ace35c3aeb26a512a2102bce5af7ec", - "sha256:c3a73f66b6d5ba7288cd5d6dad9b4c9b43f4e8a4b789a94bf5abfb878c663eb3", - "sha256:ce957f1d6b78a8a231b18e0dd2d94a33d2ba738cd88a7fe64f53f659eea49fdd", - "sha256:cea1b2542d4e2c02c332e83150e41e3ca80dc0fb8de20df3c5e98e242156222c", - "sha256:d2c21d439b2baf7aa80d6dd4e3659259be64c6f49dfd0f32091063db0e006db4", - "sha256:d839150f61d09e7217f52917259831fe2b689f5c8e5e32611736351b89bb2a90", - "sha256:dd82842bb272297503cbec1a2600b6bfb338dae017186f8f215c8958f8acf869", - "sha256:e8166b7bfe5dcb56d325385bd1d1e0f635f24aae14b3ae437102dedc0c186747", - "sha256:e981e20ec152dfb3e77418fb616077937378b322d7b26aa1ff87717fb18b4875" + "sha256:14ff67aec0a47c424bc99b71005202045dc09270da44a27848d534600ac64fc7", + "sha256:197df8509263b0b8614e1df1756b1dd41be6738eed2ba9e9769f3880c2b9d7b6", + "sha256:1e464456d24e23d11fced2bc8c47ef66d471f845c7b7a42f3bd77bf3d1789650", + "sha256:2039230db3c6c639bd84efe3292ec7b06e9214a2992cd9beb293d639c6402edb", + "sha256:21199526696b8f09c3997e2b4db8d0b108d801a348414264d2eb8eb2532e540d", + "sha256:2644b5d63633702bc2c5f3754b1b475378fbbfb481f62319388235d0cd104c2d", + "sha256:432247333090c8c5366e69627ccb363bc58514ae3e63f7fc75c54b1ea80fa7de", + "sha256:444ebfb4e441254e87bad00c661fe32df9969b2bf224373a448d8aca2132b395", + "sha256:5b9b29da4f564ba8787c119f37d174f2b69cdfdf9015b7d8c5c16121ddc054ae", + "sha256:5cc42ca67989e9c3cf859e84c2bf014f6633db63d1cbdf8fdb666dcd9e77e3fa", + "sha256:5d8f74030e67087b219b032aa33a919fae8806d49c867846bfacde57f43972ef", + "sha256:72ef3925f30e12a184889aac03d77d031056860ccae8a1e519f6cbb742736383", + "sha256:819dc789f4498ecc91438a7de64427c73b45035e2e3680c92e18795a839ebb66", + "sha256:915ace4ff03fdfff953962fa672d44be269deb2eaf88499a0f8805221bc68c87", + "sha256:9311e99228ae10023300ecac05be5a296f60d2fd10fff31cf5c1fa4ca4b1988d", + "sha256:974308c58d057a651d182208a484ce80a26dac0caef2895836a92dd6ebd725e0", + "sha256:b8b49776299fece66bffaafe357d929ca9451450f5466e997a7285ab0fe28e3b", + "sha256:c957b2b4ea88587b46cf49d1dc17681c1e672864fd7af32fc1e9664d572b3458", + "sha256:e41a86c6c650bcecc6633ee3180d80a025db041a8e2398dcc059b3afa8382cd4", + "sha256:f513588da599943e0cde4e32cc9879e825d58720d6557062d1098c5ad80080e1", + "sha256:fba8a281e570adafb79f7755ac8721b6cf1bbf691186a287e990c7929c7692ff" ], "index": "pypi", - "version": "==22.8.0" + "version": "==22.10.0" }, "click": { "hashes": [ @@ -413,19 +592,19 @@ }, "pyfakefs": { "hashes": [ - "sha256:6df12a7cf657637a1b036bc20059727c642f92990e90fee2fb003daa3cda6ca1", - "sha256:8959fe7058ba7efa65694b7979e123e27921a58f557a88628be93f0a936e6757" + "sha256:29203a7482b25406dd3ea41c8740be2697c6058b0f6577485c3ae9cd4c5e96cd", + "sha256:f22d30d93d2989bf2d2c67b606a14cbab2df0be912c09dcdb590ea4931073ade" ], "index": "pypi", - "version": "==4.6.3" + "version": "==4.7.0" }, "pylint": { "hashes": [ - "sha256:4b124affc198b7f7c9b5f9ab690d85db48282a025ef9333f51d2d7281b92a6c3", - "sha256:4f3f7e869646b0bd63b3dfb79f3c0f28fc3d2d923ea220d52620fd625aed92b0" + "sha256:5fdfd44af182866999e6123139d265334267339f29961f00c89783155eacc60b", + "sha256:7f6aad1d8d50807f7bc64f89ac75256a9baf8e6ed491cc9bc65592bc3f462cf1" ], "index": "pypi", - "version": "==2.15.0" + "version": "==2.15.3" }, "pyparsing": { "hashes": [ @@ -445,27 +624,27 @@ }, "pytest-mock": { "hashes": [ - "sha256:77f03f4554392558700295e05aed0b1096a20d4a60a4f3ddcde58b0c31c8fca2", - "sha256:8a9e226d6c0ef09fcf20c94eb3405c388af438a90f3e39687f84166da82d5948" + "sha256:f4c973eeae0282963eb293eb173ce91b091a79c1334455acfac9ddee8a1c784b", + "sha256:fbbdb085ef7c252a326fd8cdcac0aa3b1333d8811f131bdcc701002e1be7ed4f" ], "index": "pypi", - "version": "==3.8.2" + "version": "==3.10.0" }, "tomli": { "hashes": [ "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc", "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f" ], - "markers": "python_full_version < '3.11.0a7'", + "markers": "python_version >= '3.7'", "version": "==2.0.1" }, "tomlkit": { "hashes": [ - "sha256:25d4e2e446c453be6360c67ddfb88838cfc42026322770ba13d1fbd403a93a5c", - "sha256:3235a9010fae54323e727c3ac06fb720752fe6635b3426e379daec60fbd44a83" + "sha256:571854ebbb5eac89abcb4a2e47d7ea27b89bf29e09c35395da6f03dd4ae23d1c", + "sha256:f2ef9da9cef846ee027947dc99a45d6b68a63b0ebc21944649505bf2e8bc5fe7" ], "markers": "python_version >= '3.6' and python_version < '4.0'", - "version": "==0.11.4" + "version": "==0.11.5" }, "wrapt": { "hashes": [ diff --git a/shabda/dj.py b/shabda/dj.py index bbd322a..4bccd2f 100755 --- a/shabda/dj.py +++ b/shabda/dj.py @@ -14,8 +14,9 @@ from termcolor import colored from shabda.display import print_error from shabda.client import Client -from shabda.sampleset import SampleSet +from shabda.sampleset import FREESOUND, SampleSet, TTS from shabda.sound import Sound +from google.cloud import texttospeech class Dj: @@ -33,7 +34,7 @@ def parse_definition(self, definition): for section in sections: parts = section.split(":") rawword = parts[0] - word = "".join(ch for ch in rawword if ch.isalnum()) + word = "".join(ch for ch in rawword if ch.isalnum() or ch == "_") if len(word) == 0: raise ValueError("A sample name is required") number = None @@ -51,10 +52,73 @@ def parse_definition(self, definition): words[word] = number return words - def list(self, word, max_number=None, licenses=None): + def list( + self, + word, + max_number=None, + licenses=None, + gender=None, + language=None, + soundtype=None, + ): """List files for a sample name""" - sampleset = SampleSet(word) - return sampleset.list(max_number, licenses=licenses) + if soundtype == "tts": + stype = TTS + else: + stype = FREESOUND + sampleset = SampleSet(word, stype) + return sampleset.list( + max_number, licenses=licenses, gender=gender, language=language + ) + + async def speak(self, word, language, gender): + """Speak a word""" + sampleset = SampleSet(word, TTS) + existing_samples = sampleset.list() + if len(existing_samples) > 0: + return True + word_dir = sampleset.dir() + client = texttospeech.TextToSpeechClient() + synthesis_input = texttospeech.SynthesisInput(text=word.replace("_", " ")) + # mini hack + if language == "en-GB" and gender == "f": + voice = texttospeech.VoiceSelectionParams( + name="en-GB-Neural2-A", + language_code="en-GB", + ssml_gender=texttospeech.SsmlVoiceGender.FEMALE, + ) + # speaking_rate=0.85 + # pitch=-4 + else: + if gender == "m": + ssml_gender = texttospeech.SsmlVoiceGender.MALE + else: + ssml_gender = texttospeech.SsmlVoiceGender.FEMALE + voice = texttospeech.VoiceSelectionParams( + language_code=language, + ssml_gender=ssml_gender, + ) + audio_config = texttospeech.AudioConfig( + audio_encoding=texttospeech.AudioEncoding.LINEAR16, + # speaking_rate=0.85, + # pitch=-4, + ) + response = client.synthesize_speech( + input=synthesis_input, voice=voice, audio_config=audio_config + ) + filepath = word_dir + "/" + word + "_0.wav" + with open(filepath, "wb") as out: + out.write(response.audio_content) + sound = Sound( + speechsound={ + "gender": gender, + "language": language, + "file": filepath, + } + ) + sampleset.add(sound) + sampleset.saveconfig() + return True async def fetch(self, word, num, licenses): """Fetch a collection of samples""" diff --git a/shabda/sampleset.py b/shabda/sampleset.py index a96a0cf..04387bf 100644 --- a/shabda/sampleset.py +++ b/shabda/sampleset.py @@ -5,6 +5,9 @@ from glob import glob from shabda.sound import Sound +FREESOUND = 1 +TTS = 2 + class SampleSet: """A set of sample files""" @@ -12,10 +15,12 @@ class SampleSet: word = None master_id = None sounds = [] + type = FREESOUND - def __init__(self, word): + def __init__(self, word, soundtype=FREESOUND): """Initialize the sample set""" self.word = word + self.type = soundtype directory = self.dir() if not os.path.exists(directory): os.makedirs(directory) @@ -31,15 +36,22 @@ def __init__(self, word): def dir(self): """Return the directory for this sample set""" - return "samples/" + self.word + directory = "samples/" + self.word + if self.type == TTS: + directory = "speech_" + directory + return directory - def list(self, max_number=None, licenses=None): + def list(self, max_number=None, licenses=None, gender=None, language=None): """List sounds for a sample name""" # accept None as a max_number sounds = [] for sound in self.sounds: - if licenses is None or sound["license"] in licenses: + if ( + (licenses is None or sound["license"] in licenses) + and (gender is None or sound["gender"] == gender) + and (language is None or sound["language"] == language) + ): sounds.append(Sound(configsound=sound)) if max_number is not None: sounds = sounds[0:max_number] @@ -55,6 +67,8 @@ def add(self, sound): "username": sound.username, "license": sound.licensename, "file": sound.file, + "gender": sound.gender, + "language": sound.language, } ) diff --git a/shabda/sound.py b/shabda/sound.py index 3508aa3..76a9eef 100644 --- a/shabda/sound.py +++ b/shabda/sound.py @@ -9,8 +9,10 @@ class Sound: url = None licensename = None file = None + language = None + gender = None - def __init__(self, freesound=None, configsound=None): + def __init__(self, freesound=None, configsound=None, speechsound=None): if freesound is not None: self.id = freesound.id self.username = freesound.username @@ -22,6 +24,10 @@ def __init__(self, freesound=None, configsound=None): self.url = configsound["url"] self.licensename = configsound["license"] self.file = configsound["file"] + if speechsound is not None: + self.language = speechsound["language"] + self.gender = speechsound["gender"] + self.file = speechsound["file"] def _translate_license(self, licenseurl): """Translate a license URL into a license name""" diff --git a/shabda/web.py b/shabda/web.py index 48ca66e..5253a78 100644 --- a/shabda/web.py +++ b/shabda/web.py @@ -124,8 +124,76 @@ def remove_file(response): return send_file(tmpfile, as_attachment=True) -@bp.route("/samples/") +@bp.route("/speech/") +async def speech(definition): + """Download a spoken word""" + gender = request.args.get("gender", "f") + language = request.args.get("language", "en-GB") + + definition = definition.replace(" ", "_") + try: + words = dj.parse_definition(definition) + except ValueError as ex: + raise BadRequest(ex) from ex + tasks = [] + for word in words: + tasks.append(speak_one(word, language, gender)) + results = await asyncio.gather(*tasks) + global_status = "empty" + for status in results: + if status is True: + global_status = "ok" + + return jsonify( + { + "status": global_status, + "definition": clean_definition(words), + } + ) + + +@bp.route("/speech/.json") +async def speech_json(definition): + """Download a reslist definition""" + gender = request.args.get("gender", "f") + language = request.args.get("language", "en-GB") + definition = definition.replace(" ", "_") + + await speech(definition) + + url = urlparse(request.base_url) + base = url.scheme + "://" + url.hostname + if url.port: + base += ":" + str(url.port) + try: + words = dj.parse_definition(definition) + except ValueError as ex: + raise BadRequest(ex) from ex + reslist = [] + for word in words: + samples = dj.list(word, gender=gender, language=language, soundtype="tts") + sample_num = 0 + for sound in samples: + sound_data = { + "url": sound.file, + "type": "audio", + "bank": word, + "n": sample_num, + } + reslist.append(sound_data) + sample_num += 1 + + return jsonify(reslist) + + +@bp.route("speech/speech_samples/") def serve_sample(path): + """Serve a sample""" + return send_from_directory("../speech_samples/", path, as_attachment=False) + + +@bp.route("/samples/") +def serve_speech_sample(path): """Serve a sample""" return send_from_directory("../samples/", path, as_attachment=False) @@ -160,6 +228,11 @@ def cors_after(response): return response +async def speak_one(word, language, gender): + """Speak a word""" + return await dj.speak(word, language, gender) + + async def fetch_one(word, number, licenses): """Fetch a single sample set""" return await dj.fetch(word, number, licenses) diff --git a/speech_samples/.gitignore b/speech_samples/.gitignore new file mode 100644 index 0000000..0a00d70 --- /dev/null +++ b/speech_samples/.gitignore @@ -0,0 +1 @@ +*/ \ No newline at end of file