diff --git a/Cargo.lock b/Cargo.lock index 27bb375..ccae82b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -295,9 +295,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.72" +version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b13c32d80ecc7ab747b80c3784bce54ee8a7a0cc4fbda9bf4cda2cf6fe90854" +checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca" [[package]] name = "ascii-canvas" @@ -318,6 +318,16 @@ dependencies = [ "serde_json", ] +[[package]] +name = "async-attributes" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3203e79f4dd9bdda415ed03cf14dae5a2bf775c683a00f94e9cd1faf0f596e5" +dependencies = [ + "quote", + "syn 1.0.109", +] + [[package]] name = "async-channel" version = "1.9.0" @@ -329,6 +339,15 @@ dependencies = [ "futures-core", ] +[[package]] +name = "async-convert" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d416feee97712e43152cd42874de162b8f9b77295b1c85e5d92725cc8310bae" +dependencies = [ + "async-trait", +] + [[package]] name = "async-executor" version = "1.5.1" @@ -398,39 +417,20 @@ dependencies = [ [[package]] name = "async-openai" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5d5e93aca1b2f0ca772c76cadd43e965809df87ef98e25e47244c7f006c85d2" -dependencies = [ - "backoff", - "base64", - "derive_builder", - "futures", - "rand", - "reqwest", - "reqwest-eventsource", - "serde", - "serde_json", - "thiserror", - "tokio", - "tokio-stream", - "tokio-util", - "tracing", -] - -[[package]] -name = "async-openai" -version = "0.11.1" +version = "0.16.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fb81e98a73c697e72e6bd0b92714b00fc0ffa8871beedeb8c14ab4d1e27ff79" +checksum = "f49befca6fce02518292854f986151b70bb1c0a32e402c5efe52c3aa75f2e183" dependencies = [ + "async-convert", "backoff", "base64", + "bytes", "derive_builder", "futures", "rand", "reqwest", "reqwest-eventsource", + "secrecy", "serde", "serde_json", "thiserror", @@ -464,6 +464,7 @@ version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62565bb4402e926b29953c785397c6dc0391b7b446e45008b0049eb43cec6f5d" dependencies = [ + "async-attributes", "async-channel", "async-global-executor", "async-io", @@ -485,6 +486,28 @@ dependencies = [ "wasm-bindgen-futures", ] +[[package]] +name = "async-stream" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd56dd203fef61ac097dd65721a419ddccb106b2d2b70ba60a6b529f03961a51" +dependencies = [ + "async-stream-impl", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-stream-impl" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.28", +] + [[package]] name = "async-task" version = "4.4.0" @@ -514,6 +537,51 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +[[package]] +name = "axum" +version = "0.6.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b829e4e32b91e643de6eafe82b1d90675f5874230191a4ffbc1b336dec4d6bf" +dependencies = [ + "async-trait", + "axum-core", + "bitflags 1.3.2", + "bytes", + "futures-util", + "http", + "http-body", + "hyper", + "itoa", + "matchit", + "memchr", + "mime", + "percent-encoding", + "pin-project-lite", + "rustversion", + "serde", + "sync_wrapper", + "tower", + "tower-layer", + "tower-service", +] + +[[package]] +name = "axum-core" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "759fa577a247914fd3f7f76d62972792636412fbfd634cd452f6a385a74d2d2c" +dependencies = [ + "async-trait", + "bytes", + "futures-util", + "http", + "http-body", + "mime", + "rustversion", + "tower-layer", + "tower-service", +] + [[package]] name = "backoff" version = "0.4.0" @@ -545,9 +613,9 @@ dependencies = [ [[package]] name = "base64" -version = "0.21.2" +version = "0.21.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" [[package]] name = "basic-cookies" @@ -643,12 +711,12 @@ dependencies = [ [[package]] name = "bstr" -version = "1.6.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6798148dccfbff0fae41c7574d2fa8f1ef3492fba0face179de5d8d447d67b05" +checksum = "c48f0051a4b4c5e0b6d365cd04af53aeaa209e3cc15ec2cdb69e73cc87fbd0dc" dependencies = [ "memchr", - "regex-automata 0.3.6", + "regex-automata 0.4.3", "serde", ] @@ -660,9 +728,9 @@ checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1" [[package]] name = "bytes" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" +checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" [[package]] name = "bytestring" @@ -673,12 +741,6 @@ dependencies = [ "bytes", ] -[[package]] -name = "castaway" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2698f953def977c68f935bb0dfa959375ad4638570e969e2f1e9f433cbf1af6" - [[package]] name = "cc" version = "1.0.82" @@ -818,37 +880,6 @@ dependencies = [ "typenum", ] -[[package]] -name = "curl" -version = "0.4.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "509bd11746c7ac09ebd19f0b17782eae80aadee26237658a6b4808afb5c11a22" -dependencies = [ - "curl-sys", - "libc", - "openssl-probe", - "openssl-sys", - "schannel", - "socket2 0.4.9", - "winapi", -] - -[[package]] -name = "curl-sys" -version = "0.4.65+curl-8.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "961ba061c9ef2fe34bbd12b807152d96f0badd2bebe7b90ce6c8c8b7572a0986" -dependencies = [ - "cc", - "libc", - "libnghttp2-sys", - "libz-sys", - "openssl-sys", - "pkg-config", - "vcpkg", - "winapi", -] - [[package]] name = "darling" version = "0.14.4" @@ -919,6 +950,19 @@ dependencies = [ "syn 2.0.28", ] +[[package]] +name = "dashmap" +version = "5.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "907076dfda823b0b36d2a1bb5f90c96660a5bbcd7729e10727f07858f22c4edc" +dependencies = [ + "cfg-if", + "hashbrown 0.12.3", + "lock_api", + "once_cell", + "parking_lot_core", +] + [[package]] name = "deranged" version = "0.3.7" @@ -1097,9 +1141,9 @@ dependencies = [ [[package]] name = "fancy-regex" -version = "0.11.0" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b95f7c0680e4142284cf8b22c14a476e87d61b004a3a0861872b32ef7ead40a2" +checksum = "7493d4c459da9f84325ad297371a6b2b8a162800873a22e3b6b6512e61d18c05" dependencies = [ "bit-set", "regex", @@ -1166,6 +1210,16 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "futf" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df420e2e84819663797d1ec6544b13c5be84629e7bb00dc960d6917db2987843" +dependencies = [ + "mac", + "new_debug_unreachable", +] + [[package]] name = "futures" version = "0.3.28" @@ -1409,10 +1463,14 @@ dependencies = [ "chrono", "enum_dispatch", "futures", + "html2text", "httpmock", + "influxdb", "llm-chain", "llm-chain-openai", + "llm-chain-qdrant", "openssl", + "qdrant-client", "rand", "reqwest", "serde", @@ -1428,6 +1486,35 @@ dependencies = [ "tracing-subscriber", ] +[[package]] +name = "html2text" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d21a727ee791bce84d364a69b0f84a5d99f06278adfe4dbd431d475ea28e338" +dependencies = [ + "dashmap", + "html5ever", + "markup5ever", + "tendril", + "thiserror", + "unicode-width", + "xml5ever", +] + +[[package]] +name = "html5ever" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bea68cab48b8459f17cf1c944c67ddc572d272d9f2b274140f223ecb1da4a3b7" +dependencies = [ + "log", + "mac", + "markup5ever", + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "http" version = "0.2.9" @@ -1464,12 +1551,13 @@ checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" [[package]] name = "httpmock" -version = "0.6.8" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b02e044d3b4c2f94936fb05f9649efa658ca788f44eb6b87554e2033fc8ce93" +checksum = "08ec9586ee0910472dec1a1f0f8acf52f0fdde93aea74d70d4a3107b4be0fd5b" dependencies = [ "assert-json-diff", "async-object-pool", + "async-std", "async-trait", "base64", "basic-cookies", @@ -1477,7 +1565,6 @@ dependencies = [ "form_urlencoded", "futures-util", "hyper", - "isahc", "lazy_static", "levenshtein", "log", @@ -1537,6 +1624,18 @@ dependencies = [ "tokio-rustls", ] +[[package]] +name = "hyper-timeout" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbb958482e8c7be4bc3cf272a766a2b0bf1a6755e7a6ae777f017a31d11b13b1" +dependencies = [ + "hyper", + "pin-project-lite", + "tokio", + "tokio-io-timeout", +] + [[package]] name = "hyper-tls" version = "0.5.0" @@ -1628,6 +1727,35 @@ dependencies = [ "serde", ] +[[package]] +name = "influxdb" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77763a6985cbf3f3251fd0725511b6eb81967bfb50763e7a88097ff8e8504fb0" +dependencies = [ + "chrono", + "futures-util", + "http", + "influxdb_derive", + "lazy_static", + "regex", + "reqwest", + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "influxdb_derive" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ac96b3660efd0cde32b0b20bc86cc93f33269cd9f6c97e759e0b0259b2133fb" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.28", +] + [[package]] name = "instant" version = "0.1.12" @@ -1665,33 +1793,6 @@ dependencies = [ "windows-sys", ] -[[package]] -name = "isahc" -version = "1.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "334e04b4d781f436dc315cb1e7515bd96826426345d498149e4bde36b67f8ee9" -dependencies = [ - "async-channel", - "castaway", - "crossbeam-utils", - "curl", - "curl-sys", - "encoding_rs", - "event-listener", - "futures-lite", - "http", - "log", - "mime", - "once_cell", - "polling", - "slab", - "sluice", - "tracing", - "tracing-futures", - "url", - "waker-fn", -] - [[package]] name = "itertools" version = "0.10.5" @@ -1795,28 +1896,6 @@ version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f7012b1bbb0719e1097c47611d3898568c546d597c2e74d66f6087edd5233ff4" -[[package]] -name = "libnghttp2-sys" -version = "0.1.8+1.55.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fae956c192dadcdb5dace96db71fa0b827333cce7c7b38dc71446f024d8a340" -dependencies = [ - "cc", - "libc", -] - -[[package]] -name = "libz-sys" -version = "1.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d97137b25e321a73eef1418d1d5d2eda4d77e12813f8e6dead84bc52c5870a7b" -dependencies = [ - "cc", - "libc", - "pkg-config", - "vcpkg", -] - [[package]] name = "linux-raw-sys" version = "0.3.8" @@ -1831,9 +1910,9 @@ checksum = "57bcfdad1b858c2db7c38303a6d2ad4dfaf5eb53dfeb0910128b2c26d6158503" [[package]] name = "llm-chain" -version = "0.12.3" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "441d783a2388f22afa1cc74e2299dfc91b48683f49e9ccc5fd43e8075f0814cb" +checksum = "0921c2c333c11d9806c650237e9a345562767afec314035dabc073fbc14e60f4" dependencies = [ "anyhow", "async-trait", @@ -1846,8 +1925,8 @@ dependencies = [ "serde", "serde_json", "serde_yaml", - "strum", - "strum_macros", + "strum 0.25.0", + "strum_macros 0.25.3", "tera", "thiserror", "tokio", @@ -1857,22 +1936,38 @@ dependencies = [ [[package]] name = "llm-chain-openai" -version = "0.12.3" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5de076c89d981fe15a6645f3ea4cceb341960f44e0adb0449a69f787f0367cc8" +checksum = "738bdfe657582e6fcaa976b5d32626337d6039526219c5cd0ba0bbc0744ab9b2" dependencies = [ - "async-openai 0.10.3", + "async-openai", "async-trait", "futures", "llm-chain", "serde", - "strum", - "strum_macros", + "strum 0.24.1", + "strum_macros 0.24.3", "thiserror", "tiktoken-rs", "tokio", ] +[[package]] +name = "llm-chain-qdrant" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3ff02585591dcbdf153bfcf0a8689745e72eee62e8fd84223cc37d1424aefc" +dependencies = [ + "anyhow", + "async-trait", + "llm-chain", + "qdrant-client", + "serde", + "serde_json", + "thiserror", + "uuid", +] + [[package]] name = "local-channel" version = "0.1.3" @@ -1910,6 +2005,12 @@ dependencies = [ "value-bag", ] +[[package]] +name = "mac" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4" + [[package]] name = "markdown" version = "1.0.0-alpha.11" @@ -1919,6 +2020,20 @@ dependencies = [ "unicode-id", ] +[[package]] +name = "markup5ever" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a2629bb1404f3d34c2e921f21fd34ba00b206124c81f65c50b43b6aaefeb016" +dependencies = [ + "log", + "phf", + "phf_codegen", + "string_cache", + "string_cache_codegen", + "tendril", +] + [[package]] name = "matchers" version = "0.1.0" @@ -1928,11 +2043,17 @@ dependencies = [ "regex-automata 0.1.10", ] +[[package]] +name = "matchit" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed1202b2a6f884ae56f04cff409ab315c5ce26b5e58d7412e484f01fd52f52ef" + [[package]] name = "memchr" -version = "2.5.0" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" [[package]] name = "mime" @@ -2323,6 +2444,54 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "prost" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b82eaa1d779e9a4bc1c3217db8ffbeabaae1dca241bf70183242128d48681cd" +dependencies = [ + "bytes", + "prost-derive", +] + +[[package]] +name = "prost-derive" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5d2d8d10f3c6ded6da8b05b5fb3b8a5082514344d56c9f871412d29b4e075b4" +dependencies = [ + "anyhow", + "itertools", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "prost-types" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "213622a1460818959ac1181aaeb2dc9c7f63df720db7d788b3e24eacd1983e13" +dependencies = [ + "prost", +] + +[[package]] +name = "qdrant-client" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "694735737d702d104d7b9aa1cc83933fcaf97c1fc490d090ca3e71451ce60fad" +dependencies = [ + "anyhow", + "futures-util", + "prost", + "prost-types", + "reqwest", + "serde", + "serde_json", + "tonic", +] + [[package]] name = "quote" version = "1.0.33" @@ -2393,14 +2562,14 @@ dependencies = [ [[package]] name = "regex" -version = "1.9.3" +version = "1.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81bc1d4caf89fac26a70747fe603c130093b53c773888797a6329091246d651a" +checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.3.6", - "regex-syntax 0.7.4", + "regex-automata 0.4.3", + "regex-syntax 0.8.2", ] [[package]] @@ -2414,13 +2583,13 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.3.6" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fed1ceff11a1dddaee50c9dc8e4938bd106e9d89ae372f192311e7da498e3b69" +checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.7.4", + "regex-syntax 0.8.2", ] [[package]] @@ -2431,9 +2600,9 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" -version = "0.7.4" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2" +checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" [[package]] name = "reqwest" @@ -2477,6 +2646,7 @@ dependencies = [ "wasm-bindgen-futures", "wasm-streams", "web-sys", + "webpki-roots", "winreg", ] @@ -2648,6 +2818,16 @@ dependencies = [ "untrusted", ] +[[package]] +name = "secrecy" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bd1c54ea06cfd2f6b63219704de0b9b4f72dcc2b8fdef820be6cd799780e91e" +dependencies = [ + "serde", + "zeroize", +] + [[package]] name = "security-framework" version = "2.9.2" @@ -2679,18 +2859,18 @@ checksum = "b0293b4b29daaf487284529cc2f5675b8e57c61f70167ba415a463651fd6a918" [[package]] name = "serde" -version = "1.0.183" +version = "1.0.193" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32ac8da02677876d532745a130fc9d8e6edfa81a269b107c5b00829b91d8eb3c" +checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.183" +version = "1.0.193" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aafe972d60b0b9bee71a91b92fee2d4fb3c9d7e8f6b179aa99f27203d99a4816" +checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" dependencies = [ "proc-macro2", "quote", @@ -2720,9 +2900,9 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "0.6.3" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96426c9936fd7a0124915f9185ea1d20aa9445cc9821142f0a73bc9207a2e186" +checksum = "eb3622f419d1296904700073ea6cc23ad690adbd66f13ea683df73298736f0c1" dependencies = [ "serde", ] @@ -2770,9 +2950,9 @@ dependencies = [ [[package]] name = "serde_yaml" -version = "0.9.25" +version = "0.9.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a49e178e4452f45cb61d0cd8cebc1b0fafd3e41929e996cef79aa3aca91f574" +checksum = "a15e0ef66bf939a7c890a0bf6d5a733c70202225f9888a89ed5c62298b019129" dependencies = [ "indexmap 2.0.0", "itoa", @@ -2833,9 +3013,9 @@ dependencies = [ [[package]] name = "similar" -version = "2.2.1" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "420acb44afdae038210c99e69aae24109f32f15500aa708e81d46c9f29d55fcf" +checksum = "32fea41aca09ee824cc9724996433064c89f7777e60762749a4170a14abbfa21" [[package]] name = "siphasher" @@ -2861,17 +3041,6 @@ dependencies = [ "deunicode", ] -[[package]] -name = "sluice" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d7400c0eff44aa2fcb5e31a5f24ba9716ed90138769e4977a2ba6014ae63eb5" -dependencies = [ - "async-channel", - "futures-core", - "futures-io", -] - [[package]] name = "smallvec" version = "1.11.0" @@ -2915,6 +3084,19 @@ dependencies = [ "parking_lot", "phf_shared", "precomputed-hash", + "serde", +] + +[[package]] +name = "string_cache_codegen" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bb30289b722be4ff74a408c3cc27edeaad656e06cb1fe8fa9231fa59c728988" +dependencies = [ + "phf_generator", + "phf_shared", + "proc-macro2", + "quote", ] [[package]] @@ -2923,6 +3105,12 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" +[[package]] +name = "strum" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f" + [[package]] name = "strum" version = "0.25.0" @@ -2942,6 +3130,19 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "strum_macros" +version = "0.25.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23dc1fa9ac9c169a78ba62f0b841814b7abae11bdd047b9c58f893439e309ea0" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "rustversion", + "syn 2.0.28", +] + [[package]] name = "syn" version = "1.0.109" @@ -2964,6 +3165,12 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "sync_wrapper" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" + [[package]] name = "tempfile" version = "3.7.1" @@ -2977,6 +3184,17 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "tendril" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d24a120c5fc464a3458240ee02c299ebcb9d67b5249c8848b09d639dca8d7bb0" +dependencies = [ + "futf", + "mac", + "utf-8", +] + [[package]] name = "tera" version = "1.19.0" @@ -3013,18 +3231,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.44" +version = "1.0.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "611040a08a0439f8248d1990b111c95baa9c704c805fa1f62104b39655fd7f90" +checksum = "6e3de26b0965292219b4287ff031fcba86837900fe9cd2b34ea8ad893c0953d2" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.44" +version = "1.0.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "090198534930841fab3a5d1bb637cde49e339654e606195f8d9c76eeb081dc96" +checksum = "268026685b2be38d7103e9e507c938a1fcb3d7e6eb15e87870b617bf37b6d581" dependencies = [ "proc-macro2", "quote", @@ -3042,12 +3260,11 @@ dependencies = [ [[package]] name = "tiktoken-rs" -version = "0.4.5" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52aacc1cff93ba9d5f198c62c49c77fa0355025c729eed3326beaf7f33bc8614" +checksum = "40894b788eb28bbb7e36bdc8b7b1b1488b9c93fa3730f315ab965330c94c0842" dependencies = [ "anyhow", - "async-openai 0.11.1", "base64", "bstr", "fancy-regex", @@ -3121,9 +3338,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.30.0" +version = "1.33.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d3ce25f50619af8b0aec2eb23deebe84249e19e2ddd393a6e16e3300a6dadfd" +checksum = "4f38200e3ef7995e5ef13baec2f432a6da0aa9ac495b2c0e8f3b7eec2c92d653" dependencies = [ "backtrace", "bytes", @@ -3138,6 +3355,16 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "tokio-io-timeout" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30b74022ada614a1b4834de765f9bb43877f910cc8ce4be40e89042c9223a8bf" +dependencies = [ + "pin-project-lite", + "tokio", +] + [[package]] name = "tokio-macros" version = "2.1.0" @@ -3208,9 +3435,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.7.6" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c17e963a819c331dcacd7ab957d80bc2b9a9c1e71c804826d2f283dd65306542" +checksum = "a1a195ec8c9da26928f773888e0742ca3ca1040c6cd859c919c9f59c1954ab35" dependencies = [ "serde", "serde_spanned", @@ -3220,18 +3447,18 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.3" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" +checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" dependencies = [ "serde", ] [[package]] name = "toml_edit" -version = "0.19.14" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8123f27e969974a3dfba720fdb560be359f57b44302d280ba72e76a74480e8a" +checksum = "d34d383cd00a163b4a5b85053df514d45bc330f6de7737edfe0a93311d1eaa03" dependencies = [ "indexmap 2.0.0", "serde", @@ -3240,6 +3467,64 @@ dependencies = [ "winnow", ] +[[package]] +name = "tonic" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3082666a3a6433f7f511c7192923fa1fe07c69332d3c6a2e6bb040b569199d5a" +dependencies = [ + "async-stream", + "async-trait", + "axum", + "base64", + "bytes", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "hyper", + "hyper-timeout", + "percent-encoding", + "pin-project", + "prost", + "rustls-native-certs", + "rustls-pemfile", + "tokio", + "tokio-rustls", + "tokio-stream", + "tower", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" +dependencies = [ + "futures-core", + "futures-util", + "indexmap 1.9.3", + "pin-project", + "pin-project-lite", + "rand", + "slab", + "tokio", + "tokio-util", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-layer" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" + [[package]] name = "tower-service" version = "0.3.2" @@ -3292,16 +3577,6 @@ dependencies = [ "valuable", ] -[[package]] -name = "tracing-futures" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2" -dependencies = [ - "pin-project", - "tracing", -] - [[package]] name = "tracing-log" version = "0.1.3" @@ -3444,6 +3719,12 @@ dependencies = [ "tinyvec", ] +[[package]] +name = "unicode-width" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" + [[package]] name = "unicode-xid" version = "0.2.4" @@ -3452,9 +3733,9 @@ checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" [[package]] name = "unsafe-libyaml" -version = "0.2.9" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f28467d3e1d3c6586d8f25fa243f544f5800fec42d97032474e17222c2b75cfa" +checksum = "ab4c90930b95a82d00dc9e9ac071b4991924390d46cbd0dfe566148667605e4b" [[package]] name = "untrusted" @@ -3473,6 +3754,12 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "utf-8" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" + [[package]] name = "uuid" version = "1.4.1" @@ -3632,6 +3919,25 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "webpki" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f095d78192e208183081cc07bc5515ef55216397af48b873e5edcd72637fa1bd" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "webpki-roots" +version = "0.22.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c71e40d7d2c34a5106301fb632274ca37242cd0c9d3e64dbece371a40a2d87" +dependencies = [ + "webpki", +] + [[package]] name = "winapi" version = "0.3.9" @@ -3756,6 +4062,23 @@ dependencies = [ "winapi", ] +[[package]] +name = "xml5ever" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4034e1d05af98b51ad7214527730626f019682d797ba38b51689212118d8e650" +dependencies = [ + "log", + "mac", + "markup5ever", +] + +[[package]] +name = "zeroize" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" + [[package]] name = "zstd" version = "0.12.4" diff --git a/Cargo.toml b/Cargo.toml index e8daa60..e6f79d9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,7 +13,7 @@ anyhow = "1.0" serde = { version = "1.0.2", features = ["derive"] } actix-web = { version = "4", features = ["openssl"] } openssl = "0.10" -toml = "0.7.1" +toml = "0.8.8" serde_with = { version = "3.0.0", features = ["chrono"] } chrono = "0.4.26" async-trait = "0.1.72" @@ -27,10 +27,14 @@ tracing-actix-web = "0.7.6" actix-server = "2.2.0" socket2 = "0.5.3" futures = "0.3.28" -llm-chain = "0.12.3" -llm-chain-openai = "0.12.3" +llm-chain = "0.13.0" +llm-chain-openai = "0.13.0" bot_commands_macro = { path = "./bot_commands_macro" } enum_dispatch = "0.3.12" +llm-chain-qdrant = "0.13.0" +qdrant-client = "1.4.0" +html2text = "0.11.0" +influxdb = { version = "0.7.1", features = ["derive"] } [[bin]] name = "homebot" @@ -42,5 +46,5 @@ path = "src/lib/lib.rs" [dev-dependencies] actix-rt = "2.8.0" -httpmock = "0.6.8" +httpmock = "0.7.0" tempfile = "3.7.1" diff --git a/bot_commands_macro/src/lib.rs b/bot_commands_macro/src/lib.rs index 2f26d82..ada6616 100644 --- a/bot_commands_macro/src/lib.rs +++ b/bot_commands_macro/src/lib.rs @@ -67,7 +67,7 @@ pub fn bot_commands(_args: TokenStream, input: TokenStream) -> TokenStream { } } - let attrs_count = vec![&chat_start_cmd, &chat_exit_cmd, &llm_request_cmd] + let attrs_count = [&chat_start_cmd, &chat_exit_cmd, &llm_request_cmd] .iter() .filter(|&x| x.is_some()) .count(); @@ -77,7 +77,7 @@ pub fn bot_commands(_args: TokenStream, input: TokenStream) -> TokenStream { } let handler_structs = commands.iter().map(|(command_name, _, _, _, _)| { - let struct_name = get_cmd_struct_name(&command_name); + let struct_name = get_cmd_struct_name(command_name); quote! { #[derive(Default)] @@ -89,7 +89,7 @@ pub fn bot_commands(_args: TokenStream, input: TokenStream) -> TokenStream { let handler_impls = commands .iter() .map(|(command_name, func_name, _, chat_start, chat_exit)| { - let struct_name = get_cmd_struct_name(&command_name); + let struct_name = get_cmd_struct_name(command_name); let state = if chat_start == &Some(true) { quote! { user.set_chat_mode(true).await; @@ -114,7 +114,7 @@ pub fn bot_commands(_args: TokenStream, input: TokenStream) -> TokenStream { }); let command_insert = commands.iter().map(|(command_name, _, _, _, _)| { - let struct_name = get_cmd_struct_name(&command_name); + let struct_name = get_cmd_struct_name(command_name); quote! { handlers.insert(#command_name.to_string(), Box::new(#struct_name))} }); @@ -209,7 +209,7 @@ pub fn bot_commands(_args: TokenStream, input: TokenStream) -> TokenStream { new_items.push(Item::Impl(parsed_impl)); // Create new content with the original brace token and the new items - let new_content = Some((brace.clone(), new_items)); + let new_content = Some((*brace, new_items)); let new_module = ItemMod { attrs: module.attrs.clone(), vis: module.vis.clone(), @@ -271,7 +271,7 @@ pub fn handler(args: TokenStream, input: TokenStream) -> TokenStream { // for now, only check that cmd is present. let is_cmd_in_args = args.into_iter().any(|e| { if let proc_macro::TokenTree::Ident(x) = e { - x.to_string() == "cmd".to_string() + x.to_string() == *"cmd" } else { false } diff --git a/src/bot_commands.rs b/src/bot_commands.rs index 1166dc1..3a611a8 100644 --- a/src/bot_commands.rs +++ b/src/bot_commands.rs @@ -9,6 +9,7 @@ pub mod commands { use polybot::types::{BotUserActions, WeatherProvider}; use polybot::utils::{get_affirmation, get_ip}; use rand::Rng; + use std::io::Cursor; #[handler(cmd = "/ip")] async fn ip(_user_tx: impl BotUserActions, _: String) -> String { @@ -94,4 +95,31 @@ pub mod commands { async fn dice(_: impl BotUserActions, _: String) -> String { rand::thread_rng().gen_range(1..=6).to_string() } + + #[handler(cmd = "/docsearch")] + async fn retrieval(_: impl BotUserActions, request: String) -> String { + if let Ok(agent) = OpenAiModel::try_new() { + if let Ok(answer) = agent.retrieval("mohamed", &request).await { + return answer; + } + "Problem getting the agent response".to_string() + } else { + "Could not create the llm agent, check the API key".to_string() + } + } + + #[handler(cmd = "/url")] + async fn url(_: impl BotUserActions, request: String) -> String { + tracing::debug!("getting {}", request); + if let Ok(resp) = reqwest::get(request).await { + let body = resp.text().await.unwrap(); + let cursor = Cursor::new(body.into_bytes()); + let out = html2text::from_read(cursor, 200); + tracing::debug!("{out}"); + // out + "printed it".to_string() + } else { + "Problem getting the url!".to_string() + } + } } diff --git a/src/lib/lib.rs b/src/lib/lib.rs index 4489212..d2920b4 100644 --- a/src/lib/lib.rs +++ b/src/lib/lib.rs @@ -2,6 +2,7 @@ pub mod server; pub mod telegram; pub mod types; pub use types::{Bot, BotConfig, Config, ServerConfig}; +pub mod plant; pub mod polybot; pub mod services; pub mod utils; diff --git a/src/lib/plant.rs b/src/lib/plant.rs new file mode 100644 index 0000000..3b19789 --- /dev/null +++ b/src/lib/plant.rs @@ -0,0 +1,89 @@ +use std::sync::Arc; + +use crate::Bot; +use actix_web::cookie::time::format_description::parse; +use anyhow::Result; +use chrono::{DateTime, Utc}; +use influxdb::InfluxDbWriteable; +use influxdb::{Client, Query, ReadQuery, Timestamp}; +use serde::Deserialize; +use tokio::net::UdpSocket; + +#[derive(Deserialize, Debug)] +pub struct PlantData { + moisture: u32, + is_watering: bool, +} + +struct Plant { + name: String, + moisture_level: u32, + last_watering: DateTime, +} + +#[derive(InfluxDbWriteable)] +struct PlantReading { + time: DateTime, + moisture: u32, + is_watering: bool, + #[influxdb(tag)] + plant_name: String, +} + +pub struct PlantServer { + host: String, + port: u32, + chat_id: String, + db_client: Client, +} + +impl PlantServer { + pub fn new(host: &str, chat_id: &str, port: u32, db_token: &str) -> Self { + Self { + host: host.to_string(), + chat_id: chat_id.to_string(), + port, + db_client: Client::new("http://localhost:8086", "homebucket").with_token(db_token), + } + } + + pub async fn start(&self, bot: Arc) -> Result<()> { + let socket = UdpSocket::bind(format!("{}:{}", self.host, self.port)).await?; + let mut buf = [0u8; 2048]; + + let mut avg_moisture: Vec = vec![]; + + loop { + let (len, _) = socket.recv_from(&mut buf).await?; + let data = &buf[..len]; + + match serde_json::from_slice::(data) { + Ok(parsed_json) => { + let write_query = PlantReading { + time: Utc::now(), + moisture: parsed_json.moisture, + is_watering: parsed_json.is_watering, + plant_name: "flowery".to_string(), + } + .into_query("moisture"); + + self.db_client.query(write_query).await?; + + avg_moisture.push(parsed_json.moisture); + tracing::info!("Received {:?}", parsed_json); + if avg_moisture.len() == 12 { + bot.send_message( + &self.chat_id, + &format!("Moisture now is {}.", avg_moisture.iter().sum::() / 12), + ) + .await?; + avg_moisture.clear(); + } + } + Err(e) => { + tracing::error!("Error parsing json {}", e); + } + } + } + } +} diff --git a/src/lib/polybot.rs b/src/lib/polybot.rs index 4f2cca3..05ec0f9 100644 --- a/src/lib/polybot.rs +++ b/src/lib/polybot.rs @@ -1,3 +1,4 @@ +use crate::plant::PlantServer; use crate::server::BotServer; use crate::utils::{generate_certificate, get_ip}; use crate::{Bot, Config}; @@ -45,12 +46,16 @@ impl Polybot { // explicity handle the result as we are in async block if let Ok(current_ip) = get_ip().await { debug!("Current ip = {:?}", current_ip); - if !bot_clone.is_webhook_configured(¤t_ip).await.unwrap() { - info!("Certificate is not correclty configured, configuring ..."); + if let Ok(configured) = bot_clone.is_webhook_configured(¤t_ip).await { + if !configured { + info!("Certificate is not correclty configured, configuring ..."); + } else { + // the webhook is already set + tokio::time::sleep(timeout).await; + continue; + } } else { - // the webhook is already set - tokio::time::sleep(timeout).await; - continue; + error!("Issue with getting the webhook status."); } // generate new certificate @@ -84,9 +89,14 @@ impl Polybot { } }); } - loop { let mut server = BotServer::new(self.config.server.clone(), self.bot.clone()); + let plant = PlantServer::new( + "192.168.2.132", + &self.config.bot.chat_id, + 3333, + &self.config.bot.db_token, + ); // the flow will block here, until one of the branches terminates, which is due to: // - The server terminates by itself (e.g crash ..) @@ -99,6 +109,10 @@ impl Polybot { server.stop().await; continue; } + e = plant.start(self.bot.clone()) => { + tracing::info!("Plant Server exited {:?}", e); + continue; + } } } Ok(()) diff --git a/src/lib/server.rs b/src/lib/server.rs index 7782cb8..b12efa0 100644 --- a/src/lib/server.rs +++ b/src/lib/server.rs @@ -27,9 +27,16 @@ async fn handler(body: web::Bytes, bot: web::Data>) -> impl Respond error!("Wrong message format received! {:#?}", body.to_vec()); return HttpResponse::BadRequest(); }; - if bot.into_inner().handle_message(update).await.is_err() { - error!("Failed to handle the message!"); - return HttpResponse::InternalServerError(); + if bot + .into_inner() + .handle_message(update.clone()) + .await + .is_err() + { + error!( + "Failed to handle the message! {}, continuing anyway!", + update + ); } HttpResponse::Ok() } diff --git a/src/lib/services/llm.rs b/src/lib/services/llm.rs index e2531c5..1c141ba 100644 --- a/src/lib/services/llm.rs +++ b/src/lib/services/llm.rs @@ -2,8 +2,19 @@ use std::sync::Arc; use anyhow::{bail, Result}; use async_trait::async_trait; +use llm_chain::document_stores::document_store::DocumentStore; +use llm_chain::tools::tools::VectorStoreTool; use llm_chain::{chains::conversation::Chain, executor, parameters, prompt, step::Step}; +use llm_chain::{ + schema::{Document, EmptyMetadata}, + traits::{Embeddings, VectorStore}, +}; use llm_chain_openai::chatgpt::Executor; +use llm_chain_qdrant::Qdrant; +use qdrant_client::{ + prelude::{QdrantClient, QdrantClientConfig}, + qdrant::{CreateCollection, Distance, VectorParams, VectorsConfig}, +}; use tokio::sync::Mutex; use tracing::debug; @@ -13,6 +24,7 @@ pub trait Agent: Send + Sync { async fn conversation(&self, req: &str, chain: Arc>) -> Result; async fn chain_requests(&self, steps: Vec<&str>) -> Result; async fn map_reduce_chain(&self, steps: Vec<&str>) -> Result; + async fn retrieval(&self, collection: &str, req: &str) -> Result; } pub struct OpenAiModel { @@ -21,11 +33,13 @@ pub struct OpenAiModel { } impl OpenAiModel { + const EMBEDDING_SIZE: u64 = 1536; pub fn try_new() -> Result { // check if the OPENAI_API_KEY variable exists if let Ok(token) = std::env::var("OPENAI_API_KEY") { if !token.is_empty() { debug!("OPENAI_API_KEY found!"); + Ok(Self { _api_token: None, executor: executor!().unwrap(), @@ -70,4 +84,72 @@ impl Agent for OpenAiModel { .await? .to_string()) } + + async fn retrieval(&self, collection: &str, req: &str) -> Result { + let collection_name = collection.to_string(); + + let db_config = QdrantClientConfig::from_url("http://localhost:6334"); + let client = Arc::new(QdrantClient::new(Some(db_config))?); + let embeddings = llm_chain_openai::embeddings::Embeddings::default(); + if !client.has_collection(collection_name.clone()).await? { + client + .create_collection(&CreateCollection { + collection_name: collection_name.clone(), + vectors_config: Some(VectorsConfig { + config: Some(qdrant_client::qdrant::vectors_config::Config::Params( + VectorParams { + size: Self::EMBEDDING_SIZE, + distance: Distance::Cosine.into(), + hnsw_config: None, + quantization_config: None, + on_disk: None, + }, + )), + }), + ..Default::default() + }) + .await?; + } + + // Store the documents + let qdrant: Qdrant = Qdrant::new( + client.clone(), + collection_name.clone(), + embeddings, + None, + None, + ); + + let doc_dog_definition = r#"The dog (Canis familiaris[4][5] or Canis lupus familiaris[5]) is a domesticated descendant of the wolf. Also called the domestic dog, it is derived from the extinct Pleistocene wolf,[6][7] and the modern wolf is the dog's nearest living relative.[8] Dogs were the first species to be domesticated[9][8] by hunter-gatherers over 15,000 years ago[7] before the development of agriculture.[1] Due to their long association with humans, dogs have expanded to a large number of domestic individuals[10] and gained the ability to thrive on a starch-rich diet that would be inadequate for other canids.[11] + The dog has been selectively bred over millennia for various behaviors, sensory capabilities, and physical attributes.[12] Dog breeds vary widely in shape, size, and color. They perform many roles for humans, such as hunting, herding, pulling loads, protection, assisting police and the military, companionship, therapy, and aiding disabled people. Over the millennia, dogs became uniquely adapted to human behavior, and the human–canine bond has been a topic of frequent study.[13] This influence on human society has given them the sobriquet of "man's best friend"."#.to_string(); + let doc_woodstock_sound = r#"Sound for the concert was engineered by sound engineer Bill Hanley. "It worked very well", he says of the event. "I built special speaker columns on the hills and had 16 loudspeaker arrays in a square platform going up to the hill on 70-foot [21 m] towers. We set it up for 150,000 to 200,000 people. Of course, 500,000 showed up."[48] ALTEC designed marine plywood cabinets that weighed half a ton apiece and stood 6 feet (1.8 m) tall, almost 4 feet (1.2 m) deep, and 3 feet (0.91 m) wide. Each of these enclosures carried four 15-inch (380 mm) JBL D140 loudspeakers. The tweeters consisted of 4×2-Cell & 2×10-Cell Altec Horns. Behind the stage were three transformers providing 2,000 amperes of current to power the amplification setup.[49][page needed] For many years this system was collectively referred to as the Woodstock Bins.[50] The live performances were captured on two 8-track Scully recorders in a tractor trailer back stage by Edwin Kramer and Lee Osbourne on 1-inch Scotch recording tape at 15 ips, then mixed at the Record Plant studio in New York.[51]"#.to_string(); + let doc_reddit_creep_shots = r#"A year after the closure of r/jailbait, another subreddit called r/CreepShots drew controversy in the press for hosting sexualized images of women without their knowledge.[34] In the wake of this media attention, u/violentacrez was added to r/CreepShots as a moderator;[35] reports emerged that Gawker reporter Adrian Chen was planning an exposé that would reveal the real-life identity of this user, who moderated dozens of controversial subreddits, as well as a few hundred general-interest communities. Several major subreddits banned links to Gawker in response to the impending exposé, and the account u/violentacrez was deleted.[36][37][38] Moderators defended their decisions to block the site from these sections of Reddit on the basis that the impending report was "doxing" (a term for exposing the identity of a pseudonymous person), and that such exposure threatened the site's structural integrity.[38]"#.to_string(); + + let doc_ids = qdrant + .add_documents( + vec![ + doc_dog_definition, + doc_woodstock_sound, + doc_reddit_creep_shots, + ] + .into_iter() + .map(Document::new) + .collect(), + ) + .await?; + + debug!("Documents stored under IDs: {:?}", doc_ids); + let response: String = qdrant + .similarity_search(req.to_string(), 1) + .await? + .iter() + .map(|x| x.page_content.to_string()) + .collect(); + + let res = prompt!("Given this text as the context: {{txt}}, can you try to answer briefly this question {{question}}." + ) + .run(¶meters!("txt"=>response, "question"=>req), &self.executor) + .await?; + Ok(res.to_string()) + } } diff --git a/src/lib/telegram/bot.rs b/src/lib/telegram/bot.rs index 397e158..6ab7988 100644 --- a/src/lib/telegram/bot.rs +++ b/src/lib/telegram/bot.rs @@ -17,7 +17,7 @@ use tokio::fs; use tokio::sync::Mutex; use tracing::debug; -use super::types::{BotCommand, BotCommandsParams, BotCommandsSet}; +use super::types::{BotCommand, BotCommandsParams, BotCommandsSet, SendMessage}; pub struct TelegramBot { client: reqwest::Client, @@ -211,4 +211,28 @@ impl Bot for TelegramBot { self.set_my_commands(commands).await?; Ok(()) } + + async fn send_message(&self, dest: &str, msg: &str) -> Result<()> { + let payload = SendMessage { + chat_id: dest.to_string(), + text: msg.to_string(), + ..Default::default() + }; + + let url = format!( + "https://api.telegram.org/bot{}/sendMessage", + self.config.token + ); + + let to_send = serde_json::to_string(&payload)?; + self.client + .post(url) + .header(CONTENT_TYPE, "application/json") + .body(to_send) + .send() + .await + .context("could not send the message")?; + + Ok(()) + } } diff --git a/src/lib/telegram/types.rs b/src/lib/telegram/types.rs index f5baf9f..39abb78 100644 --- a/src/lib/telegram/types.rs +++ b/src/lib/telegram/types.rs @@ -1,7 +1,9 @@ +use core::panic; + use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; use serde_with::TimestampSeconds; -use tracing::debug; +use tracing::{debug, info}; use crate::types::BotMessage; @@ -108,9 +110,13 @@ impl Deserialize<'a>> From for Response { impl From for Update { fn from(value: String) -> Self { - let update_str = serde_json::from_str(&value).unwrap(); - debug!("{:#?}", update_str); - update_str + if let Ok(update_str) = serde_json::from_str(&value) { + debug!("{:#?}", update_str); + update_str + } else { + info!("Invalid request state: {value}"); + panic!() + } } } @@ -174,3 +180,25 @@ pub struct BotCommand { pub command: String, pub description: String, } + +#[derive(Serialize, Default)] +pub struct SendMessage { + pub chat_id: String, + #[serde(skip)] + pub _message_thread_id: Option, + pub text: String, + #[serde(skip)] + pub _parse_mode: Option, + #[serde(skip)] + pub _entities: Option, + #[serde(skip)] + pub _link_preview_options: Option, + #[serde(skip)] + pub _disable_notification: Option, + #[serde(skip)] + pub _protect_content: Option, + #[serde(skip)] + pub _reply_parameters: Option, + #[serde(skip)] + pub _reply_markup: Option, +} diff --git a/src/lib/types.rs b/src/lib/types.rs index a32414c..257ae58 100644 --- a/src/lib/types.rs +++ b/src/lib/types.rs @@ -26,6 +26,8 @@ pub struct Config { pub struct BotConfig { pub name: String, pub token: String, + pub chat_id: String, + pub db_token: String, } #[derive(Deserialize, Debug, Clone)] @@ -59,6 +61,7 @@ pub type CommandHashMap = HashMap Result<()>; + async fn send_message(&self, dest: &str, msg: &str) -> Result<()>; async fn handle_message(&self, msg: String) -> Result<()>; async fn is_webhook_configured(&self, ip: &str) -> Result; async fn update_webhook_cert(&self, cert: PathBuf, ip: &str) -> Result<()>; @@ -84,7 +87,6 @@ pub trait BotCommandHandler { pub struct BotUser { chat_mode: AtomicBool, last_activity: DateTime, - // chain: Arc>, chain: Arc>, }