diff --git a/Cargo.lock b/Cargo.lock index f60f2a3d71..ed935c9cd8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -241,9 +241,9 @@ dependencies = [ [[package]] name = "async-broadcast" -version = "0.7.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20cd0e2e25ea8e5f7e9df04578dc6cf5c83577fd09b1a46aaf5c85e1c33f2a7e" +checksum = "435a87a52755b8f27fcf321ac4f04b2802e337c8c4872923137471ec39c37532" dependencies = [ "event-listener 5.3.1", "event-listener-strategy", @@ -351,7 +351,7 @@ dependencies = [ "eventsource-stream", "futures", "rand 0.8.5", - "reqwest 0.12.9", + "reqwest 0.12.10", "reqwest-eventsource", "secrecy", "serde", @@ -369,7 +369,7 @@ version = "0.2.3" source = "git+https://github.com/shuttle-hq/posthog-rs?rev=f20f60de7eb786ea80d7a276073fecdfc697bc61#f20f60de7eb786ea80d7a276073fecdfc697bc61" dependencies = [ "posthog-core", - "reqwest 0.12.9", + "reqwest 0.12.10", "serde", "serde_json", "thiserror 1.0.69", @@ -403,7 +403,7 @@ checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" dependencies = [ "proc-macro2", "quote", - "syn 2.0.91", + "syn 2.0.92", ] [[package]] @@ -443,7 +443,7 @@ checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.91", + "syn 2.0.92", ] [[package]] @@ -485,7 +485,7 @@ checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" dependencies = [ "proc-macro2", "quote", - "syn 2.0.91", + "syn 2.0.92", ] [[package]] @@ -797,9 +797,9 @@ dependencies = [ [[package]] name = "aws-smithy-async" -version = "1.2.2" +version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8aa8ff1492fd9fb99ae28e8467af0dbbb7c31512b16fabf1a0f10d7bb6ef78bb" +checksum = "427cb637d15d63d6f9aae26358e1c9a9c09d5aa490d64b09354c8217cfef0f28" dependencies = [ "futures-util", "pin-project-lite", @@ -880,9 +880,9 @@ dependencies = [ [[package]] name = "aws-smithy-runtime" -version = "1.7.5" +version = "1.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "431a10d0e07e09091284ef04453dae4069283aa108d209974d67e77ae1caa658" +checksum = "a05dd41a70fc74051758ee75b5c4db2c0ca070ed9229c3df50e9475cda1cb985" dependencies = [ "aws-smithy-async", "aws-smithy-http", @@ -924,9 +924,9 @@ dependencies = [ [[package]] name = "aws-smithy-types" -version = "1.2.10" +version = "1.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ecbf4d5dfb169812e2b240a4350f15ad3c6b03a54074e5712818801615f2dc5" +checksum = "38ddc9bd6c28aeb303477170ddd183760a956a03e083b3902a990238a7e3792d" dependencies = [ "base64-simd", "bytes", @@ -1219,7 +1219,7 @@ dependencies = [ "regex", "rustc-hash 1.1.0", "shlex 1.3.0", - "syn 2.0.91", + "syn 2.0.92", "which 4.4.2", ] @@ -1241,7 +1241,7 @@ dependencies = [ "regex", "rustc-hash 1.1.0", "shlex 1.3.0", - "syn 2.0.91", + "syn 2.0.92", ] [[package]] @@ -1259,7 +1259,7 @@ dependencies = [ "regex", "rustc-hash 1.1.0", "shlex 1.3.0", - "syn 2.0.91", + "syn 2.0.92", ] [[package]] @@ -1391,7 +1391,7 @@ dependencies = [ "proc-macro-crate 2.0.2", "proc-macro2", "quote", - "syn 2.0.91", + "syn 2.0.92", "syn_derive", ] @@ -1482,7 +1482,7 @@ checksum = "3fa76293b4f7bb636ab88fd78228235b5248b4d05cc589aed610f954af5d7c7a" dependencies = [ "proc-macro2", "quote", - "syn 2.0.91", + "syn 2.0.92", ] [[package]] @@ -1667,7 +1667,7 @@ dependencies = [ "log", "num_cpus", "rand 0.8.5", - "reqwest 0.12.9", + "reqwest 0.12.10", "serde", "serde_json", "thiserror 1.0.69", @@ -1896,9 +1896,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.5" +version = "1.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c31a0499c1dc64f458ad13872de75c0eb7e3fdb0e67964610c914b034fc5956e" +checksum = "8d6dbb628b8f8555f86d0323c2eb39e3ec81901f4b83e091db8a6a76d316a333" dependencies = [ "jobserver", "libc", @@ -2073,7 +2073,7 @@ dependencies = [ "futures-util", "jsonwebtoken 9.3.0", "regex", - "reqwest 0.12.9", + "reqwest 0.12.10", "serde", "serde_derive", "serde_json", @@ -2089,7 +2089,7 @@ dependencies = [ "anyhow", "db-client", "futures-util", - "reqwest 0.12.9", + "reqwest 0.12.10", "tokio", "tokio-tungstenite 0.26.1", "url", @@ -2719,7 +2719,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331" dependencies = [ "quote", - "syn 2.0.91", + "syn 2.0.92", ] [[package]] @@ -2750,7 +2750,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a2785755761f3ddc1492979ce1e48d2c00d09311c39e4466429188f3dd6501" dependencies = [ "quote", - "syn 2.0.91", + "syn 2.0.92", ] [[package]] @@ -2785,7 +2785,7 @@ dependencies = [ "proc-macro2", "quote", "strsim 0.11.1", - "syn 2.0.91", + "syn 2.0.92", ] [[package]] @@ -2796,7 +2796,7 @@ checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ "darling_core", "quote", - "syn 2.0.91", + "syn 2.0.92", ] [[package]] @@ -3062,7 +3062,7 @@ checksum = "30542c1ad912e0e3d22a1935c290e12e8a29d704a420177a31faad4a601a0800" dependencies = [ "proc-macro2", "quote", - "syn 2.0.91", + "syn 2.0.92", ] [[package]] @@ -3083,7 +3083,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.91", + "syn 2.0.92", ] [[package]] @@ -3093,7 +3093,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c" dependencies = [ "derive_builder_core", - "syn 2.0.91", + "syn 2.0.92", ] [[package]] @@ -3106,7 +3106,7 @@ dependencies = [ "proc-macro2", "quote", "rustc_version", - "syn 2.0.91", + "syn 2.0.92", ] [[package]] @@ -3124,7 +3124,7 @@ dependencies = [ "futures", "log", "objc", - "reqwest 0.12.9", + "reqwest 0.12.10", "serde", "serde_json", "specta", @@ -3159,7 +3159,7 @@ dependencies = [ "hound", "ndarray", "ort", - "reqwest 0.12.9", + "reqwest 0.12.10", "tokio", ] @@ -3198,7 +3198,7 @@ dependencies = [ "diesel_table_macro_syntax", "proc-macro2", "quote", - "syn 2.0.91", + "syn 2.0.92", ] [[package]] @@ -3207,7 +3207,7 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc5557efc453706fed5e4fa85006fe9817c224c3f480a34c7e5959fd700921c5" dependencies = [ - "syn 2.0.91", + "syn 2.0.92", ] [[package]] @@ -3298,7 +3298,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.91", + "syn 2.0.92", ] [[package]] @@ -3330,7 +3330,7 @@ checksum = "f2b99bf03862d7f545ebc28ddd33a665b50865f4dfd84031a393823879bd4c54" dependencies = [ "proc-macro2", "quote", - "syn 2.0.91", + "syn 2.0.92", ] [[package]] @@ -3524,7 +3524,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.91", + "syn 2.0.92", ] [[package]] @@ -3545,7 +3545,7 @@ checksum = "de0d48a183585823424a4ce1aa132d174a6a81bd540895822eb4c8373a8e49e8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.91", + "syn 2.0.92", ] [[package]] @@ -3880,7 +3880,7 @@ checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" dependencies = [ "proc-macro2", "quote", - "syn 2.0.91", + "syn 2.0.92", ] [[package]] @@ -4015,7 +4015,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.91", + "syn 2.0.92", ] [[package]] @@ -4407,7 +4407,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.91", + "syn 2.0.92", ] [[package]] @@ -4622,7 +4622,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.91", + "syn 2.0.92", ] [[package]] @@ -5589,7 +5589,7 @@ checksum = "8828421bb7804381c17dda1924f2fe7275d029f53d64e5424ff08756b412312f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.91", + "syn 2.0.92", ] [[package]] @@ -6286,7 +6286,7 @@ checksum = "a7ce64b975ed4f123575d11afd9491f2e37bbd5813fbfbc0f09ae1fbddea74e0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.91", + "syn 2.0.92", ] [[package]] @@ -6408,7 +6408,7 @@ dependencies = [ "openssl-probe", "openssl-sys", "schannel", - "security-framework", + "security-framework 2.11.1", "security-framework-sys", "tempfile", ] @@ -6685,7 +6685,7 @@ checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" dependencies = [ "proc-macro2", "quote", - "syn 2.0.91", + "syn 2.0.92", ] [[package]] @@ -6757,7 +6757,7 @@ dependencies = [ "proc-macro-crate 2.0.2", "proc-macro2", "quote", - "syn 2.0.91", + "syn 2.0.92", ] [[package]] @@ -7166,7 +7166,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.91", + "syn 2.0.92", ] [[package]] @@ -7615,7 +7615,7 @@ dependencies = [ "phf_shared 0.11.2", "proc-macro2", "quote", - "syn 2.0.91", + "syn 2.0.92", ] [[package]] @@ -7663,7 +7663,7 @@ checksum = "3c0f5fad0874fc7abcd4d750e76917eaebbecaa2c20bde22e1dbeeba8beb758c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.91", + "syn 2.0.92", ] [[package]] @@ -7825,11 +7825,11 @@ dependencies = [ [[package]] name = "postgres-protocol" -version = "0.6.6" +version = "0.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49b6c5ef183cd3ab4ba005f1ca64c21e8bd97ce4699cfea9e8d9a2c4958ca520" +checksum = "acda0ebdebc28befa84bee35e651e4c5f09073d668c7aed4cf7e23c3cda84b23" dependencies = [ - "base64 0.21.7", + "base64 0.22.1", "byteorder", "bytes", "fallible-iterator 0.2.0", @@ -7843,9 +7843,9 @@ dependencies = [ [[package]] name = "postgres-types" -version = "0.2.6" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d2234cdee9408b523530a9b6d2d6b373d1db34f6a8e51dc03ded1828d7fb67c" +checksum = "f66ea23a2d0e5734297357705193335e0a957696f34bed2f2faefacb2fec336f" dependencies = [ "bytes", "fallible-iterator 0.2.0", @@ -7897,7 +7897,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "64d1ec885c64d0457d564db4ec299b2dae3f9c02808b8ad9c3a089c591b18033" dependencies = [ "proc-macro2", - "syn 2.0.91", + "syn 2.0.92", ] [[package]] @@ -8001,7 +8001,7 @@ dependencies = [ "prost 0.13.4", "prost-types 0.13.4", "regex", - "syn 2.0.91", + "syn 2.0.92", "tempfile", ] @@ -8015,7 +8015,7 @@ dependencies = [ "itertools 0.12.1", "proc-macro2", "quote", - "syn 2.0.91", + "syn 2.0.92", ] [[package]] @@ -8028,7 +8028,7 @@ dependencies = [ "itertools 0.13.0", "proc-macro2", "quote", - "syn 2.0.91", + "syn 2.0.92", ] [[package]] @@ -8171,9 +8171,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.37" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" dependencies = [ "proc-macro2", ] @@ -8385,7 +8385,7 @@ checksum = "bcc303e793d3734489387d205e9b186fac9c6cfacedd98cbb2e8a5943595f3e6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.91", + "syn 2.0.92", ] [[package]] @@ -8502,9 +8502,9 @@ dependencies = [ [[package]] name = "reqwest" -version = "0.12.9" +version = "0.12.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a77c62af46e79de0a562e1a9849205ffcb7fc1238876e9bd743357570e04046f" +checksum = "3d3536321cfc54baa8cf3e273d5e1f63f889067829c4b410fcdbac8ca7b80994" dependencies = [ "base64 0.22.1", "bytes", @@ -8542,6 +8542,7 @@ dependencies = [ "tokio-native-tls", "tokio-rustls 0.26.1", "tokio-util", + "tower 0.5.2", "tower-service", "url", "wasm-bindgen", @@ -8576,7 +8577,7 @@ dependencies = [ "mime", "nom 7.1.3", "pin-project-lite", - "reqwest 0.12.9", + "reqwest 0.12.10", "thiserror 1.0.69", ] @@ -8942,7 +8943,7 @@ dependencies = [ "openssl-probe", "rustls-pemfile 1.0.4", "schannel", - "security-framework", + "security-framework 2.11.1", ] [[package]] @@ -8955,7 +8956,19 @@ dependencies = [ "rustls-pemfile 2.2.0", "rustls-pki-types", "schannel", - "security-framework", + "security-framework 2.11.1", +] + +[[package]] +name = "rustls-native-certs" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fcff2dd52b58a8d98a70243663a0d234c4e2b79235637849d15913394a247d3" +dependencies = [ + "openssl-probe", + "rustls-pki-types", + "schannel", + "security-framework 3.1.0", ] [[package]] @@ -9008,9 +9021,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.18" +version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e819f2bc632f285be6d7cd36e25940d45b2391dd6d9b939e79de557f7014248" +checksum = "f7c45b9784283f1b2e7fb61b42047c2fd678ef0960d4f6f1eba131594cc369d4" [[package]] name = "rwhisper" @@ -9151,7 +9164,7 @@ dependencies = [ "proc-macro2", "quote", "serde_derive_internals", - "syn 2.0.91", + "syn 2.0.92", ] [[package]] @@ -9163,7 +9176,7 @@ dependencies = [ "proc-macro2", "quote", "serde_derive_internals", - "syn 2.0.91", + "syn 2.0.92", ] [[package]] @@ -9269,6 +9282,19 @@ dependencies = [ "security-framework-sys", ] +[[package]] +name = "security-framework" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81d3f8c9bfcc3cbb6b0179eb57042d75b1582bdc65c3cb95f3fa999509c03cbc" +dependencies = [ + "bitflags 2.6.0", + "core-foundation 0.10.0", + "core-foundation-sys 0.8.7", + "libc", + "security-framework-sys", +] + [[package]] name = "security-framework-sys" version = "2.13.0" @@ -9316,7 +9342,7 @@ checksum = "016958f51b96861dead7c1e02290f138411d05e94fad175c8636a835dee6e51e" dependencies = [ "httpdate", "native-tls", - "reqwest 0.12.9", + "reqwest 0.12.10", "sentry-backtrace", "sentry-contexts", "sentry-core", @@ -9450,7 +9476,7 @@ checksum = "46f859dbbf73865c6627ed570e78961cd3ac92407a2d117204c49232485da55e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.91", + "syn 2.0.92", ] [[package]] @@ -9461,7 +9487,7 @@ checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" dependencies = [ "proc-macro2", "quote", - "syn 2.0.91", + "syn 2.0.92", ] [[package]] @@ -9526,7 +9552,7 @@ checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.91", + "syn 2.0.92", ] [[package]] @@ -9568,9 +9594,9 @@ dependencies = [ [[package]] name = "serde_with" -version = "3.11.0" +version = "3.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e28bdad6db2b8340e449f7108f020b3b092e8583a9e3fb82713e1d4e71fe817" +checksum = "d6b6f7f2fcb69f747921f79f3926bd1e203fce4fef62c268dd3abfb6d86029aa" dependencies = [ "base64 0.22.1", "chrono", @@ -9580,7 +9606,7 @@ dependencies = [ "serde", "serde_derive", "serde_json", - "serde_with_macros 3.11.0", + "serde_with_macros 3.12.0", "time", ] @@ -9593,19 +9619,19 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.91", + "syn 2.0.92", ] [[package]] name = "serde_with_macros" -version = "3.11.0" +version = "3.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d846214a9854ef724f3da161b426242d8de7c1fc7de2f89bb1efcb154dca79d" +checksum = "8d00caa5193a3c8362ac2b73be6b9e768aa5a4b2f721d8f4b339600c3cb51f8e" dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.91", + "syn 2.0.92", ] [[package]] @@ -9630,7 +9656,7 @@ checksum = "5d69265a08751de7844521fd15003ae0a888e035773ba05695c5c759a6f89eef" dependencies = [ "proc-macro2", "quote", - "syn 2.0.91", + "syn 2.0.92", ] [[package]] @@ -9666,7 +9692,7 @@ dependencies = [ "bridge", "db-server", "futures", - "reqwest 0.12.9", + "reqwest 0.12.10", "s3", "schemars 1.0.0-alpha.17", "sentry", @@ -9677,8 +9703,8 @@ dependencies = [ "shuttle-posthog", "shuttle-runtime", "shuttle-shared-db", - "shuttle-stt", "sqlx", + "stt", "tokio", "tower-http 0.6.2", ] @@ -9812,7 +9838,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.91", + "syn 2.0.92", ] [[package]] @@ -9923,17 +9949,6 @@ dependencies = [ "sqlx", ] -[[package]] -name = "shuttle-stt" -version = "0.1.0" -dependencies = [ - "async-trait", - "serde", - "serde_json", - "shuttle-service", - "stt", -] - [[package]] name = "signal-hook" version = "0.3.17" @@ -10152,7 +10167,7 @@ dependencies = [ "Inflector", "proc-macro2", "quote", - "syn 2.0.91", + "syn 2.0.92", ] [[package]] @@ -10319,7 +10334,7 @@ dependencies = [ "quote", "sqlx-core", "sqlx-macros-core", - "syn 2.0.91", + "syn 2.0.92", ] [[package]] @@ -10342,7 +10357,7 @@ dependencies = [ "sqlx-mysql", "sqlx-postgres", "sqlx-sqlite", - "syn 2.0.91", + "syn 2.0.92", "tempfile", "tokio", "url", @@ -10562,7 +10577,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.91", + "syn 2.0.92", ] [[package]] @@ -10572,9 +10587,9 @@ dependencies = [ "anyhow", "bytes", "clova", - "cpal", "deepgram", "futures", + "kalosm-sound", "serde", "serde_json", "serial_test", @@ -10660,9 +10675,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.91" +version = "2.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d53cbcb5a243bd33b7858b1d7f4aca2153490815872d86d955d6ea29f743c035" +checksum = "70ae51629bf965c5c098cc9e87908a3df5301051a9e087d6f9bef5c9771ed126" dependencies = [ "proc-macro2", "quote", @@ -10678,7 +10693,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.91", + "syn 2.0.92", ] [[package]] @@ -10704,7 +10719,7 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" dependencies = [ "proc-macro2", "quote", - "syn 2.0.91", + "syn 2.0.92", ] [[package]] @@ -10850,7 +10865,7 @@ checksum = "f4e16beb8b2ac17db28eab8bca40e62dbfbb34c0fcdc6d9826b11b7b5d047dfd" dependencies = [ "proc-macro2", "quote", - "syn 2.0.91", + "syn 2.0.92", ] [[package]] @@ -10914,7 +10929,7 @@ dependencies = [ "percent-encoding", "plist", "raw-window-handle", - "reqwest 0.12.9", + "reqwest 0.12.10", "serde", "serde_json", "serde_repr", @@ -10977,7 +10992,7 @@ dependencies = [ "serde", "serde_json", "sha2", - "syn 2.0.91", + "syn 2.0.92", "tauri-utils", "thiserror 2.0.9", "time", @@ -10995,7 +11010,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.91", + "syn 2.0.92", "tauri-codegen", "tauri-utils", ] @@ -11249,7 +11264,7 @@ dependencies = [ "infer 0.16.0", "minisign-verify", "percent-encoding", - "reqwest 0.12.9", + "reqwest 0.12.10", "semver", "serde", "serde_json", @@ -11335,7 +11350,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.91", + "syn 2.0.92", ] [[package]] @@ -11365,7 +11380,7 @@ dependencies = [ "serde", "serde-untagged", "serde_json", - "serde_with 3.11.0", + "serde_with 3.12.0", "swift-rs", "thiserror 2.0.9", "toml 0.8.2", @@ -11470,7 +11485,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.91", + "syn 2.0.92", ] [[package]] @@ -11481,7 +11496,7 @@ checksum = "7b50fa271071aae2e6ee85f842e2e28ba8cd2c5fb67f11fcb1fd70b276f9e7d4" dependencies = [ "proc-macro2", "quote", - "syn 2.0.91", + "syn 2.0.92", ] [[package]] @@ -11631,7 +11646,7 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", - "syn 2.0.91", + "syn 2.0.92", ] [[package]] @@ -11646,9 +11661,9 @@ dependencies = [ [[package]] name = "tokio-postgres" -version = "0.7.10" +version = "0.7.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d340244b32d920260ae7448cb72b6e238bddc3d4f7603394e7dd46ed8e48f5b8" +checksum = "3b5d3742945bc7d7f210693b0c58ae542c6fd47b17adbbda0885f3dcb34a6bdb" dependencies = [ "async-trait", "byteorder", @@ -11900,6 +11915,7 @@ dependencies = [ "percent-encoding", "pin-project", "prost 0.13.4", + "rustls-native-certs 0.8.1", "rustls-pemfile 2.2.0", "socket2", "tokio", @@ -11922,7 +11938,7 @@ dependencies = [ "prost-build", "prost-types 0.13.4", "quote", - "syn 2.0.91", + "syn 2.0.92", ] [[package]] @@ -12058,7 +12074,7 @@ checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.91", + "syn 2.0.92", ] [[package]] @@ -12225,7 +12241,7 @@ dependencies = [ name = "turso" version = "0.1.0" dependencies = [ - "reqwest 0.12.9", + "reqwest 0.12.10", ] [[package]] @@ -12259,7 +12275,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a615d6c2764852a2e88a4f16e9ce1ea49bb776b5872956309e170d63a042a34f" dependencies = [ "quote", - "syn 2.0.91", + "syn 2.0.92", ] [[package]] @@ -12362,9 +12378,9 @@ dependencies = [ [[package]] name = "unicase" -version = "2.8.0" +version = "2.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e51b68083f157f853b6379db119d1c1be0e6e4dec98101079dec41f6f5cf6df" +checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539" [[package]] name = "unicode-bidi" @@ -12671,7 +12687,7 @@ dependencies = [ "log", "proc-macro2", "quote", - "syn 2.0.91", + "syn 2.0.92", "wasm-bindgen-shared", ] @@ -12706,7 +12722,7 @@ checksum = "30d7a95b763d3c45903ed6c81f156801839e5ee968bb07e534c44df0fcd330c2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.91", + "syn 2.0.92", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -12916,7 +12932,7 @@ checksum = "1d228f15bba3b9d56dde8bddbee66fa24545bd17b48d5128ccf4a8742b18e431" dependencies = [ "proc-macro2", "quote", - "syn 2.0.91", + "syn 2.0.92", ] [[package]] @@ -13244,7 +13260,7 @@ checksum = "f6fc35f58ecd95a9b71c4f2329b911016e6bec66b3f2e6a4aad86bd2e99e2f9b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.91", + "syn 2.0.92", ] [[package]] @@ -13255,7 +13271,7 @@ checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.91", + "syn 2.0.92", ] [[package]] @@ -13266,7 +13282,7 @@ checksum = "08990546bf4edef8f431fa6326e032865f27138718c587dc21bc0265bbcb57cc" dependencies = [ "proc-macro2", "quote", - "syn 2.0.91", + "syn 2.0.92", ] [[package]] @@ -13277,7 +13293,7 @@ checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515" dependencies = [ "proc-macro2", "quote", - "syn 2.0.91", + "syn 2.0.92", ] [[package]] @@ -13735,7 +13751,7 @@ checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" dependencies = [ "proc-macro2", "quote", - "syn 2.0.91", + "syn 2.0.92", "synstructure", ] @@ -13849,7 +13865,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.91", + "syn 2.0.92", ] [[package]] @@ -13869,7 +13885,7 @@ checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808" dependencies = [ "proc-macro2", "quote", - "syn 2.0.91", + "syn 2.0.92", "synstructure", ] diff --git a/Cargo.toml b/Cargo.toml index fc615049c2..d666fb5052 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,9 +20,10 @@ time = "0.3.37" pin-project = "1" sentry = "0.35.0" bytes = "1.9.0" +dotenvy = "0.15.7" +dotenvy_macro = "0.15.7" ndarray = "0.16.1" -ort = "2.0.0-rc.9" tokenizers = "0.19.1" candle-examples = { git = "https://github.com/huggingface/candle", tag = "0.8.1" } candle-core = "0.8.1" diff --git a/apps/desktop/src-tauri/Cargo.lock b/apps/desktop/src-tauri/Cargo.lock index 32bd1de3f7..5a52bff897 100644 --- a/apps/desktop/src-tauri/Cargo.lock +++ b/apps/desktop/src-tauri/Cargo.lock @@ -5639,7 +5639,7 @@ dependencies = [ [[package]] name = "ort" -version = "2.0.0-rc.9" +version = "2.0.0-rc.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "52afb44b6b0cffa9bf45e4d37e5a4935b0334a51570658e279e9e3e6cf324aa5" dependencies = [ @@ -5651,7 +5651,7 @@ dependencies = [ [[package]] name = "ort-sys" -version = "2.0.0-rc.9" +version = "2.0.0-rc.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c41d7757331aef2d04b9cb09b45583a59217628beaf91895b7e76187b6e8c088" dependencies = [ diff --git a/apps/desktop/src-tauri/Cargo.toml b/apps/desktop/src-tauri/Cargo.toml index 106cd22371..be7dbfbae6 100644 --- a/apps/desktop/src-tauri/Cargo.toml +++ b/apps/desktop/src-tauri/Cargo.toml @@ -47,7 +47,7 @@ thiserror = { workspace = true } serde = { workspace = true, features = ["derive"] } serde_json = { workspace = true } uuid = { workspace = true } -dotenvy_macro = "0.15.7" +dotenvy_macro = { workspace = true } log = "0.4.22" reqwest = { workspace = true, features = ["json", "stream"] } diff --git a/apps/server/Cargo.toml b/apps/server/Cargo.toml index 77a0644c0e..5b83654b87 100644 --- a/apps/server/Cargo.toml +++ b/apps/server/Cargo.toml @@ -7,13 +7,13 @@ edition = "2021" hypr-bridge = { path = "../../crates/bridge", package = "bridge" } hypr-db-server = { path = "../../crates/db-server", package = "db-server" } hypr-s3 = { path = "../../crates/s3", package = "s3" } +hypr-stt = { path = "../../crates/stt", package = "stt" } shuttle-axum = "0.49.0" shuttle-runtime = "0.49.0" shuttle-shared-db = { version = "0.49.0", features = ["postgres", "sqlx"] } shuttle-posthog = { path = "../../crates/shuttle-posthog" } shuttle-clerk = { path = "../../crates/shuttle-clerk" } -shuttle-stt = { path = "../../crates/shuttle-stt" } tokio = { workspace = true, features = ["macros", "rt-multi-thread"] } futures = { workspace = true } diff --git a/apps/server/src/main.rs b/apps/server/src/main.rs index 09dc241a33..054ba320fa 100644 --- a/apps/server/src/main.rs +++ b/apps/server/src/main.rs @@ -9,7 +9,6 @@ use axum::{ use shuttle_clerk::{ClerkClient as Clerk, ClerkLayer, MemoryCacheJwksProvider}; use shuttle_posthog::posthog::Client as Posthog; use shuttle_runtime::SecretStore; -use shuttle_stt::STTClient as STT; use sqlx::PgPool; use std::time::Duration; @@ -34,11 +33,6 @@ async fn main( api_key = "{secrets.POSTHOG_API_KEY}" )] posthog: Posthog, - #[shuttle_stt::STT( - deepgram_api_key = "{secrets.DEEPGRAM_API_KEY}", - clova_api_key = "{secrets.CLOVA_API_KEY}" - )] - _stt: STT, ) -> shuttle_axum::ShuttleAxum { hypr_db_server::migrate(&db).await.unwrap(); diff --git a/crates/aec/Cargo.toml b/crates/aec/Cargo.toml index 6773845e27..409cb605c4 100644 --- a/crates/aec/Cargo.toml +++ b/crates/aec/Cargo.toml @@ -7,4 +7,4 @@ edition = "2021" anyhow = { workspace = true } tokio = { workspace = true, features = ["rt", "macros"] } ndarray = { workspace = true } -ort = { workspace = true, features = ["coreml"] } +ort = { version = "2.0.0-rc.9", features = ["coreml"] } diff --git a/crates/clova/Cargo.toml b/crates/clova/Cargo.toml index 5162831a15..ab9a30654e 100644 --- a/crates/clova/Cargo.toml +++ b/crates/clova/Cargo.toml @@ -16,4 +16,4 @@ tokio = { workspace = true } futures = { workspace = true } prost = "0.13.4" -tonic = { version = "0.12.3", features = ["tls"] } +tonic = { version = "0.12.3", features = ["channel", "tls-native-roots"] } diff --git a/crates/clova/build.rs b/crates/clova/build.rs index 217f69672d..66a2eba650 100644 --- a/crates/clova/build.rs +++ b/crates/clova/build.rs @@ -1,7 +1,7 @@ fn main() -> Result<(), Box> { tonic_build::configure() .build_server(false) - .out_dir("./src") + .out_dir("./src/interface") .compile_protos(&["proto/nest.proto"], &["proto"])?; Ok(()) diff --git a/crates/clova/src/com.nbp.cdncp.nest.grpc.proto.v1.rs b/crates/clova/src/interface/com.nbp.cdncp.nest.grpc.proto.v1.rs similarity index 100% rename from crates/clova/src/com.nbp.cdncp.nest.grpc.proto.v1.rs rename to crates/clova/src/interface/com.nbp.cdncp.nest.grpc.proto.v1.rs diff --git a/crates/clova/src/interface/mod.rs b/crates/clova/src/interface/mod.rs new file mode 100644 index 0000000000..cc06baf4bc --- /dev/null +++ b/crates/clova/src/interface/mod.rs @@ -0,0 +1,7 @@ +mod types; +mod nest { + include!("./com.nbp.cdncp.nest.grpc.proto.v1.rs"); +} + +pub use nest::*; +pub use types::*; diff --git a/crates/clova/src/interface.rs b/crates/clova/src/interface/types.rs similarity index 50% rename from crates/clova/src/interface.rs rename to crates/clova/src/interface/types.rs index 6bc33f1b14..9028574269 100644 --- a/crates/clova/src/interface.rs +++ b/crates/clova/src/interface/types.rs @@ -1,3 +1,4 @@ +use serde::de::Error as _; use serde::{Deserialize, Serialize}; // https://api.ncloud-docs.com/docs/en/ai-application-service-clovaspeech-grpc#3-request-config-json @@ -21,98 +22,74 @@ pub enum Language { #[derive(Debug, Deserialize, Serialize)] pub struct ConfigResponse { + pub uid: String, pub config: ConfigResponseInner, } #[derive(Debug, Deserialize, Serialize)] pub struct ConfigResponseInner { - pub status: ConfigResponseStatus, -} - -#[derive(Debug, PartialEq, Deserialize, Serialize)] -pub enum ConfigResponseStatus { - Success, - Failure, + pub status: String, } // https://api.ncloud-docs.com/docs/ai-application-service-clovaspeech-grpc#%EC%9D%91%EB%8B%B5-%EC%98%88%EC%8B%9C1 #[derive(Debug, Deserialize, Serialize)] +#[serde(try_from = "StreamResponseRaw")] pub enum StreamResponse { - Success(StreamResponseSuccess), - Failure(StreamResponseFailure), + Config(ConfigResponse), + TranscribeSuccess(StreamResponseSuccess), + TranscribeFailure(StreamResponseFailure), +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +struct StreamResponseRaw { + response_type: Vec, + #[serde(flatten)] + raw: serde_json::Value, +} + +impl TryFrom for StreamResponse { + type Error = serde_json::Error; + + fn try_from(raw: StreamResponseRaw) -> Result { + let response_type = raw + .response_type + .first() + .ok_or_else(|| serde_json::Error::custom("missing response_type"))?; + + match response_type.as_str() { + "config" => serde_json::from_value(raw.raw).map(StreamResponse::Config), + "recognize" => serde_json::from_value(raw.raw).map(StreamResponse::TranscribeFailure), + "transcription" => { + serde_json::from_value(raw.raw).map(StreamResponse::TranscribeSuccess) + } + _ => Err(serde_json::Error::custom("invalid response_type")), + } + } } #[derive(Debug, Deserialize, Serialize)] pub struct StreamResponseSuccess { pub uid: String, - pub response_type: Vec, pub transcription: TranscriptionResponse, } #[derive(Debug, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] pub struct TranscriptionResponse { pub text: String, - pub position: i32, - pub period_positions: Vec, - pub period_align_indices: Vec, - pub ep_flag: bool, - pub seq_id: i32, - pub epd_type: EpdType, pub start_timestamp: i64, pub end_timestamp: i64, pub confidence: f64, - pub align_infos: Vec, -} - -#[derive(Debug, Deserialize, Serialize)] -pub struct AlignInfo { - pub word: String, - pub start: i64, - pub end: i64, - pub confidence: f64, } #[derive(Debug, Deserialize, Serialize)] pub struct StreamResponseFailure { pub uid: String, - pub response_type: Vec, pub recognize: RecognizeError, } #[derive(Debug, Deserialize, Serialize)] pub struct RecognizeError { pub status: String, - #[serde(skip_serializing_if = "Option::is_none")] - pub ep_flag: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub seq_id: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub audio: Option, -} - -#[derive(Debug, Deserialize, Serialize)] -pub struct StatusInfo { - pub status: String, -} - -mod nest { - include!("./com.nbp.cdncp.nest.grpc.proto.v1.rs"); -} - -pub use nest::*; - -#[derive(Debug, Deserialize, Serialize)] -pub enum EpdType { - #[serde(rename = "gap")] - Gap, - #[serde(rename = "endPoint")] - EndPoint, - #[serde(rename = "durationThreshold")] - DurationThreshold, - #[serde(rename = "period")] - Period, - #[serde(rename = "syllableThreshold")] - SyllableThreshold, - #[serde(rename = "unvoice")] - Unvoice, } diff --git a/crates/clova/src/lib.rs b/crates/clova/src/lib.rs index 878736554d..2080e863cd 100644 --- a/crates/clova/src/lib.rs +++ b/crates/clova/src/lib.rs @@ -1,28 +1,27 @@ -use anyhow::Result; -use bytes::Bytes; - mod handle; pub mod interface; +use anyhow::Result; +use bytes::Bytes; use futures::{Stream, StreamExt}; use serde::{Deserialize, Serialize}; -use std::{error::Error, str::FromStr}; -use tonic::{ - metadata::{MetadataMap, MetadataValue}, - Request, -}; +use std::error::Error; use interface::nest_service_client::NestServiceClient; +use tonic::{service::interceptor::InterceptedService, transport::Channel, Request, Status}; + +// https://docs.rs/tonic/latest/tonic/service/trait.Interceptor.html +type Interceptor = Box) -> Result, Status>>; pub struct Client { - inner: NestServiceClient, + inner: NestServiceClient>, config: Config, } #[derive(Debug, Deserialize, Serialize)] pub struct Config { - secret_key: String, - config: interface::ConfigRequest, + pub secret_key: String, + pub config: interface::ConfigRequest, } impl Config { @@ -40,60 +39,23 @@ impl Client { pub async fn new(config: Config) -> Result { let channel = tonic::transport::Channel::from_static("https://clovaspeech-gw.ncloud.com:50051") - .tls_config(tonic::transport::ClientTlsConfig::new())? + .tls_config(tonic::transport::ClientTlsConfig::new().with_native_roots())? .connect() .await?; - let inner = NestServiceClient::new(channel); + let key = config.secret_key.clone(); + let inner = NestServiceClient::with_interceptor(channel, Self::make_interceptor(key)); Ok(Self { inner, config }) } - fn auth(&self, request: T) -> Request { - let mut req = Request::new(request); - let mut metadata = MetadataMap::new(); - - let auth_header = format!("Bearer {}", self.config.secret_key); - let auth_value = MetadataValue::from_str(&auth_header).unwrap(); - - // never capitalize authorization - metadata.insert("authorization", auth_value); - - *req.metadata_mut() = metadata; - req - } - - async fn config_request(&mut self) -> Result<()> { - let config = self.config.config.clone(); - - let request = interface::NestRequest { - r#type: interface::RequestType::Config.into(), - part: Some(interface::nest_request::Part::Config( - interface::NestConfig { - config: serde_json::to_string(&config).unwrap(), - }, - )), - }; - - let request = self.auth(request); - let response = self - .inner - .recognize(tonic::Request::new(futures::stream::once(async { - request.into_inner() - }))) - .await?; - - let mut stream = response.into_inner(); - - while let Some(message) = stream.message().await? { - let res: interface::ConfigResponse = serde_json::from_str(&message.contents)?; - - if res.config.status != interface::ConfigResponseStatus::Success { - return Err(anyhow::anyhow!("config request failed")); - } - } - - Ok(()) + fn make_interceptor(secret_key: String) -> Interceptor { + Box::new(move |mut req: Request<()>| { + req.metadata_mut() + // lowercase is required + .insert("authorization", secret_key.parse().unwrap()); + Ok(req) + }) } pub async fn stream( @@ -104,15 +66,22 @@ impl Client { S: Stream> + Send + Unpin + 'static, E: Error + Send + Sync + 'static, { - self.config_request().await?; + let config = serde_json::to_string(&self.config.config).unwrap(); + let config_request = interface::NestRequest { + r#type: interface::RequestType::Config.into(), + part: Some(interface::nest_request::Part::Config( + interface::NestConfig { config }, + )), + }; + let config_stream = futures::stream::once(async move { config_request }); - let request_stream = stream.filter_map(|chunk| async { + let audio_request_stream = stream.filter_map(|chunk| async { if let Ok(chunk) = chunk { Some(interface::NestRequest { r#type: interface::RequestType::Data.into(), part: Some(interface::nest_request::Part::Data(interface::NestData { - chunk: chunk.to_vec(), - extra_contents: "".to_string(), + chunk: chunk.into(), + extra_contents: r#"{"seqId": 0, "epFlag": false}"#.to_string(), })), }) } else { @@ -122,10 +91,11 @@ impl Client { let response = self .inner - .recognize(request_stream) + .recognize(config_stream.chain(audio_request_stream)) .await? .into_inner() .map(|message| { + println!("message: {:?}", message); let res = serde_json::from_str::(&message?.contents)?; Ok(res) }); diff --git a/crates/diarizer/Cargo.toml b/crates/diarizer/Cargo.toml index d8f19f281f..9b60c8d711 100644 --- a/crates/diarizer/Cargo.toml +++ b/crates/diarizer/Cargo.toml @@ -7,7 +7,7 @@ edition = "2021" anyhow = { workspace = true } tokio = { workspace = true, features = ["rt", "macros"] } ndarray = { workspace = true } -ort = { workspace = true, features = ["coreml"] } +ort = { version = "2.0.0-rc.9", features = ["coreml"] } [dev-dependencies] reqwest = { workspace = true } diff --git a/crates/shuttle-stt/Cargo.toml b/crates/shuttle-stt/Cargo.toml deleted file mode 100644 index 8a467fda47..0000000000 --- a/crates/shuttle-stt/Cargo.toml +++ /dev/null @@ -1,11 +0,0 @@ -[package] -name = "shuttle-stt" -version = "0.1.0" -edition = "2021" - -[dependencies] -serde = { workspace = true, features = ["derive"] } -serde_json = { workspace = true } -async-trait = "0.1.83" -shuttle-service = "0.49.0" -hypr-stt = { path = "../stt", package = "stt" } diff --git a/crates/shuttle-stt/src/lib.rs b/crates/shuttle-stt/src/lib.rs deleted file mode 100644 index 221f2398fa..0000000000 --- a/crates/shuttle-stt/src/lib.rs +++ /dev/null @@ -1,58 +0,0 @@ -use async_trait::async_trait; -use serde::{Deserialize, Serialize}; -use shuttle_service::{CustomError, Error, IntoResource, ResourceFactory, ResourceInputBuilder}; - -pub use hypr_stt; -pub use hypr_stt::{Client as STTClient, Config as STTConfig}; - -#[derive(Default, Serialize)] -pub struct STT { - deepgram_api_key: Option, - clova_api_key: Option, -} - -impl STT { - pub fn deepgram_api_key(mut self, api_key: &str) -> Self { - self.deepgram_api_key = Some(api_key.to_string()); - self - } - - pub fn clova_api_key(mut self, api_key: &str) -> Self { - self.clova_api_key = Some(api_key.to_string()); - self - } -} - -#[derive(Serialize, Deserialize)] -pub struct Config { - deepgram_api_key: String, - clova_api_key: String, -} - -#[async_trait] -impl ResourceInputBuilder for STT { - type Input = Config; - type Output = Config; - - async fn build(self, _factory: &ResourceFactory) -> Result { - let deepgram_api_key = self - .deepgram_api_key - .ok_or(Error::Custom(CustomError::msg("Deepgram API key required")))?; - - let clova_api_key = self - .clova_api_key - .ok_or(Error::Custom(CustomError::msg("Clova API key required")))?; - - Ok(Config { - deepgram_api_key, - clova_api_key, - }) - } -} - -#[async_trait] -impl IntoResource for Config { - async fn into_resource(self) -> Result { - Ok(STTClient {}) - } -} diff --git a/crates/stt/Cargo.toml b/crates/stt/Cargo.toml index 1df1bb807a..f22eace981 100644 --- a/crates/stt/Cargo.toml +++ b/crates/stt/Cargo.toml @@ -16,4 +16,4 @@ hypr-clova = { path = "../clova", package = "clova" } [dev-dependencies] serial_test = "3" -cpal = { workspace = true } +kalosm-sound = { version = "0.3.5", default-features = false } diff --git a/crates/stt/src/clova.rs b/crates/stt/src/clova.rs index c5e0521b0f..13eb84201f 100644 --- a/crates/stt/src/clova.rs +++ b/crates/stt/src/clova.rs @@ -5,8 +5,7 @@ use std::error::Error; use crate::{RealtimeSpeechToText, StreamResponse}; -#[allow(unused)] -use hypr_clova::{interface as clova, Client as ClovaClient, Config as ClovaConfig}; +pub use hypr_clova::{interface as clova, Client as ClovaClient, Config as ClovaConfig}; impl RealtimeSpeechToText for ClovaClient { async fn transcribe(&mut self, audio: S) -> Result>> @@ -17,12 +16,12 @@ impl RealtimeSpeechToText for ClovaClient { let transcription = self.stream(audio).await?; return Ok(transcription.map(|r| match r { - Ok(clova::StreamResponse::Success(r)) => Ok(StreamResponse { + Ok(clova::StreamResponse::TranscribeSuccess(r)) => Ok(StreamResponse { text: r.transcription.text, }), - Ok(clova::StreamResponse::Failure(r)) => { - Err(anyhow::anyhow!("Failed to transcribe: {:?}", r)) - } + Ok(_) => Ok(StreamResponse { + text: "".to_string(), + }), Err(e) => Err(e.into()), })); } diff --git a/crates/stt/src/deep.rs b/crates/stt/src/deep.rs index d533c16195..a706027797 100644 --- a/crates/stt/src/deep.rs +++ b/crates/stt/src/deep.rs @@ -38,32 +38,41 @@ impl RealtimeSpeechToText for DeepgramClient { ) .unwrap(); - let stream = deepgram + let deepgram_stream = deepgram .transcription() .stream_request() .keep_alive() - .sample_rate(16000) + .sample_rate(16 * 1000) .channels(1) .encoding(Encoding::Linear16) .stream(stream) - .await? - .map(|result| result.map(Into::into).map_err(Into::into)); + .await?; - Ok(stream) + let transformed_stream = deepgram_stream.map(|result| { + result + .map_err(Into::into) + .and_then(|resp| StreamResponse::try_from(resp)) + }); + + Ok(transformed_stream) } } -impl From for StreamResponse { - fn from(response: DeepgramStreamResponse) -> Self { - let text = match response { +impl TryFrom for StreamResponse { + type Error = anyhow::Error; + + fn try_from(response: DeepgramStreamResponse) -> Result { + match response { DeepgramStreamResponse::TranscriptResponse { channel, .. } => { - channel.alternatives.first().unwrap().transcript.clone() + let text = channel + .alternatives + .first() + .map(|alt| alt.transcript.clone()) + .unwrap_or_default(); + + Ok(StreamResponse { text }) } - DeepgramStreamResponse::TerminalResponse { .. } => "".to_string(), - DeepgramStreamResponse::SpeechStartedResponse { .. } => "".to_string(), - DeepgramStreamResponse::UtteranceEndResponse { .. } => "".to_string(), - _ => "".to_string(), - }; - StreamResponse { text } + _ => Err(anyhow::anyhow!("no conversion defined")), + } } } diff --git a/crates/stt/src/lib.rs b/crates/stt/src/lib.rs index fcc8e39437..5edcb36d6c 100644 --- a/crates/stt/src/lib.rs +++ b/crates/stt/src/lib.rs @@ -4,11 +4,12 @@ use futures::Stream; use std::error::Error; mod clova; -pub use clova::*; +pub use clova::{ClovaClient, ClovaConfig}; mod deep; -pub use deep::*; +pub use deep::{DeepgramClient, DeepgramConfig}; +#[allow(dead_code)] trait RealtimeSpeechToText { async fn transcribe(&mut self, stream: S) -> Result>> where @@ -16,13 +17,44 @@ trait RealtimeSpeechToText { E: Error + Send + Sync + 'static; } +#[derive(Debug)] pub struct StreamResponse { pub text: String, } -pub struct Client {} +pub struct Client { + config: Config, +} + +pub struct Config { + pub deepgram_api_key: String, + pub clova_secret_key: String, +} + +impl Client { + pub fn new(config: Config) -> Self { + Self { config } + } + + pub async fn for_korean(&self) -> ClovaClient { + let config = ClovaConfig { + secret_key: self.config.clova_secret_key.clone(), + config: clova::clova::ConfigRequest { + transcription: clova::clova::Transcription { + language: clova::clova::Language::Korean, + }, + }, + }; + ClovaClient::new(config).await.unwrap() + } -pub struct Config {} + pub fn for_english(&self) -> DeepgramClient { + let config = DeepgramConfig { + api_key: self.config.deepgram_api_key.clone(), + }; + DeepgramClient::new(config) + } +} #[cfg(test)] mod tests { @@ -30,66 +62,64 @@ mod tests { use serial_test::serial; use anyhow::Result; - use bytes::{BufMut, Bytes, BytesMut}; - use cpal::traits::{DeviceTrait, HostTrait, StreamTrait}; - use cpal::Sample; - use futures::SinkExt; - use std::thread; - - fn microphone_as_stream() -> futures::channel::mpsc::Receiver> { - let (sync_tx, sync_rx) = std::sync::mpsc::channel(); - let (mut async_tx, async_rx) = futures::channel::mpsc::channel(1); - - thread::spawn(move || { - let host = cpal::default_host(); - let device = host.default_input_device().unwrap(); - let config = device.default_input_config().unwrap(); - - let stream = match config.sample_format() { - cpal::SampleFormat::F32 => device - .build_input_stream( - &config.into(), - move |data: &[f32], _: &_| { - let mut bytes = BytesMut::with_capacity(data.len() * 2); - for s in data { - let sample = s.to_sample::(); - bytes.put_i16_le(sample); - } - sync_tx.send(bytes.freeze()).unwrap(); - }, - |_| panic!(), - None, - ) - .unwrap(), - _ => panic!(), - }; - - stream.play().unwrap(); - - loop { - thread::park(); + use bytes::{BufMut, Bytes}; + use futures::StreamExt; + use kalosm_sound::AsyncSource; + + fn microphone_as_stream( + ) -> impl Stream> + Send + Unpin + 'static { + let mic_input = kalosm_sound::MicInput::default(); + let mic_stream = mic_input.stream().unwrap().resample(16 * 1000).chunks(128); + + mic_stream.map(|chunk| { + let mut buf = bytes::BytesMut::with_capacity(chunk.len() * 4); + for sample in chunk { + let scaled = (sample * 32767.0).clamp(-32768.0, 32767.0); + buf.put_i16_le(scaled as i16); } - }); - - tokio::spawn(async move { - loop { - let data = sync_rx.recv().unwrap(); - async_tx.send(Ok(data)).await.unwrap(); - } - }); - - async_rx + Ok(buf.freeze()) + }) } + // cargo test test_deepgram -p stt -- --ignored --nocapture + #[ignore] #[tokio::test] #[serial] - async fn test_transcribe() { + async fn test_deepgram() { + let audio_stream = microphone_as_stream(); + let config = DeepgramConfig { - api_key: "".to_string(), + api_key: std::env::var("DEEPGRAM_API_KEY").unwrap(), }; let mut client = DeepgramClient::new(config); - let stream = microphone_as_stream(); - let _ = client.transcribe(stream).await.unwrap(); - assert!(true); + let mut transcript_stream = client.transcribe(audio_stream).await.unwrap(); + + while let Some(result) = transcript_stream.next().await { + println!("deepgram: {:?}", result.unwrap()); + } + } + + // cargo test test_clova -p stt -- --ignored --nocapture + #[ignore] + #[tokio::test] + #[serial] + async fn test_clova() { + let audio_stream = microphone_as_stream(); + + let config = ClovaConfig { + secret_key: std::env::var("CLOVA_SECRET_KEY").unwrap(), + config: clova::clova::ConfigRequest { + transcription: clova::clova::Transcription { + language: clova::clova::Language::Korean, + }, + }, + }; + + let mut client = ClovaClient::new(config).await.unwrap(); + let mut transcript_stream = client.transcribe(audio_stream).await.unwrap(); + + while let Some(result) = transcript_stream.next().await { + println!("clova: {:?}", result.unwrap()); + } } }