From 4c70ad9b9b0652a4495c898710d769bb866e0f9a Mon Sep 17 00:00:00 2001 From: nathan Date: Fri, 28 Jun 2024 15:48:13 +0800 Subject: [PATCH] chore: config chat --- frontend/appflowy_tauri/src-tauri/Cargo.lock | 67 ++++--- frontend/appflowy_tauri/src-tauri/Cargo.toml | 2 +- frontend/appflowy_web/wasm-libs/Cargo.lock | 29 +-- frontend/appflowy_web/wasm-libs/Cargo.toml | 2 +- .../appflowy_web_app/src-tauri/Cargo.lock | 56 ++++-- .../appflowy_web_app/src-tauri/Cargo.toml | 2 +- frontend/rust-lib/Cargo.lock | 38 ++-- frontend/rust-lib/Cargo.toml | 4 +- .../tests/chat/chat_message_test.rs | 16 +- frontend/rust-lib/flowy-chat-pub/src/cloud.rs | 26 +-- frontend/rust-lib/flowy-chat/Cargo.toml | 11 ++ .../{flowy-sidecar => flowy-chat}/dev.env | 2 +- frontend/rust-lib/flowy-chat/src/chat.rs | 4 +- frontend/rust-lib/flowy-chat/src/entities.rs | 38 ++++ .../rust-lib/flowy-chat/src/event_handler.rs | 51 +++++ frontend/rust-lib/flowy-chat/src/event_map.rs | 11 ++ frontend/rust-lib/flowy-chat/src/lib.rs | 1 + .../flowy-chat/src/local_ai/chat_plugin.rs | 116 ++++++++++++ .../src/local_ai}/embedding_plugin.rs | 24 ++- .../flowy-chat/src/local_ai/manager.rs | 176 ++++++++++++++++++ .../src/local_ai}/mod.rs | 2 + frontend/rust-lib/flowy-chat/src/manager.rs | 161 +++++++++++----- .../tests/chat_test/mod.rs | 17 +- .../tests/main.rs | 0 .../tests/util.rs | 24 +-- .../flowy-config/src/event_handler.rs | 8 +- .../rust-lib/flowy-config/src/event_map.rs | 4 +- .../flowy-core/src/deps_resolve/chat_deps.rs | 8 +- .../src/deps_resolve/folder_deps.rs | 4 +- .../flowy-core/src/deps_resolve/user_deps.rs | 4 +- .../flowy-core/src/integrate/server.rs | 6 +- .../flowy-core/src/integrate/trait_impls.rs | 28 +-- frontend/rust-lib/flowy-core/src/lib.rs | 13 +- frontend/rust-lib/flowy-folder/src/manager.rs | 6 +- .../flowy-server/src/af_cloud/impls/chat.rs | 72 +++---- .../rust-lib/flowy-server/src/default_impl.rs | 14 +- frontend/rust-lib/flowy-sidecar/Cargo.toml | 6 - .../rust-lib/flowy-sidecar/src/core/parser.rs | 62 ------ .../rust-lib/flowy-sidecar/src/core/plugin.rs | 4 +- .../flowy-sidecar/src/core/rpc_loop.rs | 2 +- .../flowy-sidecar/src/core/rpc_object.rs | 4 +- .../flowy-sidecar/src/core/rpc_peer.rs | 30 +-- frontend/rust-lib/flowy-sidecar/src/lib.rs | 1 - .../flowy-sidecar/src/plugins/chat_plugin.rs | 70 ------- frontend/rust-lib/flowy-sqlite/src/kv/kv.rs | 10 +- .../rust-lib/flowy-user/src/event_handler.rs | 24 +-- .../src/migrations/session_migration.rs | 4 +- .../src/services/authenticate_user.rs | 6 +- .../flowy-user/src/services/cloud_config.rs | 12 +- .../data_import/appflowy_data_import.rs | 4 +- .../flowy-user/src/user_manager/manager.rs | 8 +- 51 files changed, 822 insertions(+), 472 deletions(-) rename frontend/rust-lib/{flowy-sidecar => flowy-chat}/dev.env (78%) create mode 100644 frontend/rust-lib/flowy-chat/src/local_ai/chat_plugin.rs rename frontend/rust-lib/{flowy-sidecar/src/plugins => flowy-chat/src/local_ai}/embedding_plugin.rs (53%) create mode 100644 frontend/rust-lib/flowy-chat/src/local_ai/manager.rs rename frontend/rust-lib/{flowy-sidecar/src/plugins => flowy-chat/src/local_ai}/mod.rs (72%) rename frontend/rust-lib/{flowy-sidecar => flowy-chat}/tests/chat_test/mod.rs (72%) rename frontend/rust-lib/{flowy-sidecar => flowy-chat}/tests/main.rs (100%) rename frontend/rust-lib/{flowy-sidecar => flowy-chat}/tests/util.rs (87%) delete mode 100644 frontend/rust-lib/flowy-sidecar/src/plugins/chat_plugin.rs diff --git a/frontend/appflowy_tauri/src-tauri/Cargo.lock b/frontend/appflowy_tauri/src-tauri/Cargo.lock index aa07be5eeb..e85feb9663 100644 --- a/frontend/appflowy_tauri/src-tauri/Cargo.lock +++ b/frontend/appflowy_tauri/src-tauri/Cargo.lock @@ -172,7 +172,7 @@ checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" [[package]] name = "app-error" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=6262816043efeede8823d7a7ea252083adf407e9#6262816043efeede8823d7a7ea252083adf407e9" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" dependencies = [ "anyhow", "bincode", @@ -192,7 +192,7 @@ dependencies = [ [[package]] name = "appflowy-ai-client" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=6262816043efeede8823d7a7ea252083adf407e9#6262816043efeede8823d7a7ea252083adf407e9" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" dependencies = [ "anyhow", "bytes", @@ -772,7 +772,7 @@ dependencies = [ [[package]] name = "client-api" version = "0.2.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=6262816043efeede8823d7a7ea252083adf407e9#6262816043efeede8823d7a7ea252083adf407e9" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" dependencies = [ "again", "anyhow", @@ -787,6 +787,7 @@ dependencies = [ "collab", "collab-rt-entity", "collab-rt-protocol", + "futures", "futures-core", "futures-util", "getrandom 0.2.10", @@ -794,6 +795,8 @@ dependencies = [ "infra", "mime", "parking_lot 0.12.1", + "percent-encoding", + "pin-project", "prost", "reqwest", "scraper 0.17.1", @@ -818,7 +821,7 @@ dependencies = [ [[package]] name = "client-api-entity" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=6262816043efeede8823d7a7ea252083adf407e9#6262816043efeede8823d7a7ea252083adf407e9" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" dependencies = [ "collab-entity", "collab-rt-entity", @@ -830,7 +833,7 @@ dependencies = [ [[package]] name = "client-websocket" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=6262816043efeede8823d7a7ea252083adf407e9#6262816043efeede8823d7a7ea252083adf407e9" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" dependencies = [ "futures-channel", "futures-util", @@ -1070,7 +1073,7 @@ dependencies = [ [[package]] name = "collab-rt-entity" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=6262816043efeede8823d7a7ea252083adf407e9#6262816043efeede8823d7a7ea252083adf407e9" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" dependencies = [ "anyhow", "bincode", @@ -1095,7 +1098,7 @@ dependencies = [ [[package]] name = "collab-rt-protocol" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=6262816043efeede8823d7a7ea252083adf407e9#6262816043efeede8823d7a7ea252083adf407e9" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" dependencies = [ "anyhow", "async-trait", @@ -1291,12 +1294,9 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.16" +version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" -dependencies = [ - "cfg-if", -] +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" [[package]] name = "crunchy" @@ -1452,10 +1452,11 @@ checksum = "c2e66c9d817f1720209181c316d28635c050fa304f9c79e47a520882661b7308" [[package]] name = "database-entity" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=6262816043efeede8823d7a7ea252083adf407e9#6262816043efeede8823d7a7ea252083adf407e9" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" dependencies = [ "anyhow", "app-error", + "appflowy-ai-client", "bincode", "chrono", "collab-entity", @@ -1852,6 +1853,7 @@ dependencies = [ "flowy-derive", "flowy-error", "flowy-notification", + "flowy-sidecar", "flowy-sqlite", "futures", "lib-dispatch", @@ -2315,6 +2317,24 @@ dependencies = [ "serde_repr", ] +[[package]] +name = "flowy-sidecar" +version = "0.1.0" +dependencies = [ + "anyhow", + "crossbeam-utils", + "lib-infra", + "log", + "once_cell", + "parking_lot 0.12.1", + "serde", + "serde_json", + "thiserror", + "tokio", + "tokio-stream", + "tracing", +] + [[package]] name = "flowy-sqlite" version = "0.1.0" @@ -2894,7 +2914,7 @@ dependencies = [ [[package]] name = "gotrue" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=6262816043efeede8823d7a7ea252083adf407e9#6262816043efeede8823d7a7ea252083adf407e9" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" dependencies = [ "anyhow", "futures-util", @@ -2911,7 +2931,7 @@ dependencies = [ [[package]] name = "gotrue-entity" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=6262816043efeede8823d7a7ea252083adf407e9#6262816043efeede8823d7a7ea252083adf407e9" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" dependencies = [ "anyhow", "app-error", @@ -3343,7 +3363,7 @@ dependencies = [ [[package]] name = "infra" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=6262816043efeede8823d7a7ea252083adf407e9#6262816043efeede8823d7a7ea252083adf407e9" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" dependencies = [ "anyhow", "bytes", @@ -3591,6 +3611,7 @@ dependencies = [ "async-trait", "atomic_refcell", "bytes", + "cfg-if", "chrono", "futures", "futures-core", @@ -4211,9 +4232,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.18.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "oneshot" @@ -5685,9 +5706,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.111" +version = "1.0.118" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "176e46fa42316f18edd598015a5166857fc835ec732f5215eac6b7bdbf0a84f4" +checksum = "d947f6b3163d8857ea16c4fa0dd4840d52f3041039a85decd46867eb1abef2e4" dependencies = [ "itoa 1.0.6", "ryu", @@ -5835,7 +5856,7 @@ dependencies = [ [[package]] name = "shared-entity" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=6262816043efeede8823d7a7ea252083adf407e9#6262816043efeede8823d7a7ea252083adf407e9" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" dependencies = [ "anyhow", "app-error", @@ -6842,9 +6863,9 @@ dependencies = [ [[package]] name = "tokio-stream" -version = "0.1.14" +version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "397c988d37662c7dda6d2208364a706264bf3d6138b11d436cbac0ad38832842" +checksum = "267ac89e0bec6e691e5813911606935d77c476ff49024f98abcea3e7b15e37af" dependencies = [ "futures-core", "pin-project-lite", diff --git a/frontend/appflowy_tauri/src-tauri/Cargo.toml b/frontend/appflowy_tauri/src-tauri/Cargo.toml index bae84180da..6dd8b25b86 100644 --- a/frontend/appflowy_tauri/src-tauri/Cargo.toml +++ b/frontend/appflowy_tauri/src-tauri/Cargo.toml @@ -52,7 +52,7 @@ collab-user = { version = "0.2" } # Run the script: # scripts/tool/update_client_api_rev.sh new_rev_id # ⚠️⚠️⚠️️ -client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "6262816043efeede8823d7a7ea252083adf407e9" } +client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "9884d93aa2805013f36a79c1757174a0b5063065" } [dependencies] serde_json.workspace = true diff --git a/frontend/appflowy_web/wasm-libs/Cargo.lock b/frontend/appflowy_web/wasm-libs/Cargo.lock index 42fefea9ac..ecde57219d 100644 --- a/frontend/appflowy_web/wasm-libs/Cargo.lock +++ b/frontend/appflowy_web/wasm-libs/Cargo.lock @@ -215,7 +215,7 @@ checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" [[package]] name = "app-error" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=6262816043efeede8823d7a7ea252083adf407e9#6262816043efeede8823d7a7ea252083adf407e9" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" dependencies = [ "anyhow", "bincode", @@ -235,7 +235,7 @@ dependencies = [ [[package]] name = "appflowy-ai-client" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=6262816043efeede8823d7a7ea252083adf407e9#6262816043efeede8823d7a7ea252083adf407e9" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" dependencies = [ "anyhow", "bytes", @@ -561,7 +561,7 @@ dependencies = [ [[package]] name = "client-api" version = "0.2.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=6262816043efeede8823d7a7ea252083adf407e9#6262816043efeede8823d7a7ea252083adf407e9" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" dependencies = [ "again", "anyhow", @@ -576,6 +576,7 @@ dependencies = [ "collab", "collab-rt-entity", "collab-rt-protocol", + "futures", "futures-core", "futures-util", "getrandom 0.2.12", @@ -583,6 +584,8 @@ dependencies = [ "infra", "mime", "parking_lot 0.12.1", + "percent-encoding", + "pin-project", "prost", "reqwest", "scraper 0.17.1", @@ -607,7 +610,7 @@ dependencies = [ [[package]] name = "client-api-entity" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=6262816043efeede8823d7a7ea252083adf407e9#6262816043efeede8823d7a7ea252083adf407e9" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" dependencies = [ "collab-entity", "collab-rt-entity", @@ -619,7 +622,7 @@ dependencies = [ [[package]] name = "client-websocket" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=6262816043efeede8823d7a7ea252083adf407e9#6262816043efeede8823d7a7ea252083adf407e9" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" dependencies = [ "futures-channel", "futures-util", @@ -797,7 +800,7 @@ dependencies = [ [[package]] name = "collab-rt-entity" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=6262816043efeede8823d7a7ea252083adf407e9#6262816043efeede8823d7a7ea252083adf407e9" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" dependencies = [ "anyhow", "bincode", @@ -822,7 +825,7 @@ dependencies = [ [[package]] name = "collab-rt-protocol" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=6262816043efeede8823d7a7ea252083adf407e9#6262816043efeede8823d7a7ea252083adf407e9" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" dependencies = [ "anyhow", "async-trait", @@ -1036,10 +1039,11 @@ checksum = "7e962a19be5cfc3f3bf6dd8f61eb50107f356ad6270fbb3ed41476571db78be5" [[package]] name = "database-entity" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=6262816043efeede8823d7a7ea252083adf407e9#6262816043efeede8823d7a7ea252083adf407e9" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" dependencies = [ "anyhow", "app-error", + "appflowy-ai-client", "bincode", "chrono", "collab-entity", @@ -1919,7 +1923,7 @@ dependencies = [ [[package]] name = "gotrue" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=6262816043efeede8823d7a7ea252083adf407e9#6262816043efeede8823d7a7ea252083adf407e9" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" dependencies = [ "anyhow", "futures-util", @@ -1936,7 +1940,7 @@ dependencies = [ [[package]] name = "gotrue-entity" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=6262816043efeede8823d7a7ea252083adf407e9#6262816043efeede8823d7a7ea252083adf407e9" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" dependencies = [ "anyhow", "app-error", @@ -2237,7 +2241,7 @@ dependencies = [ [[package]] name = "infra" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=6262816043efeede8823d7a7ea252083adf407e9#6262816043efeede8823d7a7ea252083adf407e9" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" dependencies = [ "anyhow", "bytes", @@ -2378,6 +2382,7 @@ dependencies = [ "async-trait", "atomic_refcell", "bytes", + "cfg-if 1.0.0", "chrono", "futures", "futures-core", @@ -3951,7 +3956,7 @@ dependencies = [ [[package]] name = "shared-entity" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=6262816043efeede8823d7a7ea252083adf407e9#6262816043efeede8823d7a7ea252083adf407e9" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" dependencies = [ "anyhow", "app-error", diff --git a/frontend/appflowy_web/wasm-libs/Cargo.toml b/frontend/appflowy_web/wasm-libs/Cargo.toml index 9816e6ef94..a3578b9cb3 100644 --- a/frontend/appflowy_web/wasm-libs/Cargo.toml +++ b/frontend/appflowy_web/wasm-libs/Cargo.toml @@ -54,7 +54,7 @@ yrs = "0.18.8" # Run the script: # scripts/tool/update_client_api_rev.sh new_rev_id # ⚠️⚠️⚠️️ -client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "6262816043efeede8823d7a7ea252083adf407e9" } +client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "9884d93aa2805013f36a79c1757174a0b5063065" } [profile.dev] opt-level = 0 diff --git a/frontend/appflowy_web_app/src-tauri/Cargo.lock b/frontend/appflowy_web_app/src-tauri/Cargo.lock index a4a230c514..05a7af34e6 100644 --- a/frontend/appflowy_web_app/src-tauri/Cargo.lock +++ b/frontend/appflowy_web_app/src-tauri/Cargo.lock @@ -163,7 +163,7 @@ checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" [[package]] name = "app-error" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=6262816043efeede8823d7a7ea252083adf407e9#6262816043efeede8823d7a7ea252083adf407e9" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" dependencies = [ "anyhow", "bincode", @@ -183,7 +183,7 @@ dependencies = [ [[package]] name = "appflowy-ai-client" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=6262816043efeede8823d7a7ea252083adf407e9#6262816043efeede8823d7a7ea252083adf407e9" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" dependencies = [ "anyhow", "bytes", @@ -746,7 +746,7 @@ dependencies = [ [[package]] name = "client-api" version = "0.2.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=6262816043efeede8823d7a7ea252083adf407e9#6262816043efeede8823d7a7ea252083adf407e9" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" dependencies = [ "again", "anyhow", @@ -761,6 +761,7 @@ dependencies = [ "collab", "collab-rt-entity", "collab-rt-protocol", + "futures", "futures-core", "futures-util", "getrandom 0.2.12", @@ -768,6 +769,8 @@ dependencies = [ "infra", "mime", "parking_lot 0.12.1", + "percent-encoding", + "pin-project", "prost", "reqwest", "scraper 0.17.1", @@ -792,7 +795,7 @@ dependencies = [ [[package]] name = "client-api-entity" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=6262816043efeede8823d7a7ea252083adf407e9#6262816043efeede8823d7a7ea252083adf407e9" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" dependencies = [ "collab-entity", "collab-rt-entity", @@ -804,7 +807,7 @@ dependencies = [ [[package]] name = "client-websocket" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=6262816043efeede8823d7a7ea252083adf407e9#6262816043efeede8823d7a7ea252083adf407e9" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" dependencies = [ "futures-channel", "futures-util", @@ -1053,7 +1056,7 @@ dependencies = [ [[package]] name = "collab-rt-entity" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=6262816043efeede8823d7a7ea252083adf407e9#6262816043efeede8823d7a7ea252083adf407e9" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" dependencies = [ "anyhow", "bincode", @@ -1078,7 +1081,7 @@ dependencies = [ [[package]] name = "collab-rt-protocol" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=6262816043efeede8823d7a7ea252083adf407e9#6262816043efeede8823d7a7ea252083adf407e9" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" dependencies = [ "anyhow", "async-trait", @@ -1281,9 +1284,9 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.19" +version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" [[package]] name = "crunchy" @@ -1439,10 +1442,11 @@ checksum = "7e962a19be5cfc3f3bf6dd8f61eb50107f356ad6270fbb3ed41476571db78be5" [[package]] name = "database-entity" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=6262816043efeede8823d7a7ea252083adf407e9#6262816043efeede8823d7a7ea252083adf407e9" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" dependencies = [ "anyhow", "app-error", + "appflowy-ai-client", "bincode", "chrono", "collab-entity", @@ -1889,6 +1893,7 @@ dependencies = [ "flowy-derive", "flowy-error", "flowy-notification", + "flowy-sidecar", "flowy-sqlite", "futures", "lib-dispatch", @@ -2352,6 +2357,24 @@ dependencies = [ "serde_repr", ] +[[package]] +name = "flowy-sidecar" +version = "0.1.0" +dependencies = [ + "anyhow", + "crossbeam-utils", + "lib-infra", + "log", + "once_cell", + "parking_lot 0.12.1", + "serde", + "serde_json", + "thiserror", + "tokio", + "tokio-stream", + "tracing", +] + [[package]] name = "flowy-sqlite" version = "0.1.0" @@ -2968,7 +2991,7 @@ dependencies = [ [[package]] name = "gotrue" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=6262816043efeede8823d7a7ea252083adf407e9#6262816043efeede8823d7a7ea252083adf407e9" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" dependencies = [ "anyhow", "futures-util", @@ -2985,7 +3008,7 @@ dependencies = [ [[package]] name = "gotrue-entity" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=6262816043efeede8823d7a7ea252083adf407e9#6262816043efeede8823d7a7ea252083adf407e9" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" dependencies = [ "anyhow", "app-error", @@ -3422,7 +3445,7 @@ dependencies = [ [[package]] name = "infra" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=6262816043efeede8823d7a7ea252083adf407e9#6262816043efeede8823d7a7ea252083adf407e9" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" dependencies = [ "anyhow", "bytes", @@ -3675,6 +3698,7 @@ dependencies = [ "async-trait", "atomic_refcell", "bytes", + "cfg-if", "chrono", "futures", "futures-core", @@ -5777,9 +5801,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.114" +version = "1.0.118" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0" +checksum = "d947f6b3163d8857ea16c4fa0dd4840d52f3041039a85decd46867eb1abef2e4" dependencies = [ "indexmap 2.2.6", "itoa 1.0.10", @@ -5930,7 +5954,7 @@ dependencies = [ [[package]] name = "shared-entity" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=6262816043efeede8823d7a7ea252083adf407e9#6262816043efeede8823d7a7ea252083adf407e9" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" dependencies = [ "anyhow", "app-error", diff --git a/frontend/appflowy_web_app/src-tauri/Cargo.toml b/frontend/appflowy_web_app/src-tauri/Cargo.toml index ddf01dabc5..c87aa9e925 100644 --- a/frontend/appflowy_web_app/src-tauri/Cargo.toml +++ b/frontend/appflowy_web_app/src-tauri/Cargo.toml @@ -52,7 +52,7 @@ collab-user = { version = "0.2" } # Run the script: # scripts/tool/update_client_api_rev.sh new_rev_id # ⚠️⚠️⚠️️ -client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "6262816043efeede8823d7a7ea252083adf407e9" } +client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "9884d93aa2805013f36a79c1757174a0b5063065" } [dependencies] serde_json.workspace = true diff --git a/frontend/rust-lib/Cargo.lock b/frontend/rust-lib/Cargo.lock index dc53e80e38..4eb912bb2a 100644 --- a/frontend/rust-lib/Cargo.lock +++ b/frontend/rust-lib/Cargo.lock @@ -163,7 +163,7 @@ checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" [[package]] name = "app-error" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=6262816043efeede8823d7a7ea252083adf407e9#6262816043efeede8823d7a7ea252083adf407e9" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" dependencies = [ "anyhow", "bincode", @@ -183,7 +183,7 @@ dependencies = [ [[package]] name = "appflowy-ai-client" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=6262816043efeede8823d7a7ea252083adf407e9#6262816043efeede8823d7a7ea252083adf407e9" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" dependencies = [ "anyhow", "bytes", @@ -664,7 +664,7 @@ dependencies = [ [[package]] name = "client-api" version = "0.2.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=6262816043efeede8823d7a7ea252083adf407e9#6262816043efeede8823d7a7ea252083adf407e9" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" dependencies = [ "again", "anyhow", @@ -679,6 +679,7 @@ dependencies = [ "collab", "collab-rt-entity", "collab-rt-protocol", + "futures", "futures-core", "futures-util", "getrandom 0.2.10", @@ -686,6 +687,8 @@ dependencies = [ "infra", "mime", "parking_lot 0.12.1", + "percent-encoding", + "pin-project", "prost", "reqwest", "scraper 0.17.1", @@ -710,7 +713,7 @@ dependencies = [ [[package]] name = "client-api-entity" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=6262816043efeede8823d7a7ea252083adf407e9#6262816043efeede8823d7a7ea252083adf407e9" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" dependencies = [ "collab-entity", "collab-rt-entity", @@ -722,7 +725,7 @@ dependencies = [ [[package]] name = "client-websocket" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=6262816043efeede8823d7a7ea252083adf407e9#6262816043efeede8823d7a7ea252083adf407e9" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" dependencies = [ "futures-channel", "futures-util", @@ -931,7 +934,7 @@ dependencies = [ [[package]] name = "collab-rt-entity" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=6262816043efeede8823d7a7ea252083adf407e9#6262816043efeede8823d7a7ea252083adf407e9" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" dependencies = [ "anyhow", "bincode", @@ -956,7 +959,7 @@ dependencies = [ [[package]] name = "collab-rt-protocol" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=6262816043efeede8823d7a7ea252083adf407e9#6262816043efeede8823d7a7ea252083adf407e9" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" dependencies = [ "anyhow", "async-trait", @@ -1273,10 +1276,11 @@ checksum = "c2e66c9d817f1720209181c316d28635c050fa304f9c79e47a520882661b7308" [[package]] name = "database-entity" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=6262816043efeede8823d7a7ea252083adf407e9#6262816043efeede8823d7a7ea252083adf407e9" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" dependencies = [ "anyhow", "app-error", + "appflowy-ai-client", "bincode", "chrono", "collab-entity", @@ -1662,8 +1666,10 @@ name = "flowy-chat" version = "0.1.0" dependencies = [ "allo-isolate", + "anyhow", "bytes", "dashmap", + "dotenv", "flowy-chat-pub", "flowy-codegen", "flowy-derive", @@ -1675,10 +1681,15 @@ dependencies = [ "lib-dispatch", "lib-infra", "log", + "parking_lot 0.12.1", "protobuf", + "serde", + "serde_json", "strum_macros 0.21.1", "tokio", + "tokio-stream", "tracing", + "tracing-subscriber", "uuid", "validator", ] @@ -2147,7 +2158,6 @@ version = "0.1.0" dependencies = [ "anyhow", "crossbeam-utils", - "dotenv", "lib-infra", "log", "once_cell", @@ -2158,8 +2168,6 @@ dependencies = [ "tokio", "tokio-stream", "tracing", - "tracing-subscriber", - "uuid", ] [[package]] @@ -2586,7 +2594,7 @@ dependencies = [ [[package]] name = "gotrue" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=6262816043efeede8823d7a7ea252083adf407e9#6262816043efeede8823d7a7ea252083adf407e9" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" dependencies = [ "anyhow", "futures-util", @@ -2603,7 +2611,7 @@ dependencies = [ [[package]] name = "gotrue-entity" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=6262816043efeede8823d7a7ea252083adf407e9#6262816043efeede8823d7a7ea252083adf407e9" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" dependencies = [ "anyhow", "app-error", @@ -2968,7 +2976,7 @@ dependencies = [ [[package]] name = "infra" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=6262816043efeede8823d7a7ea252083adf407e9#6262816043efeede8823d7a7ea252083adf407e9" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" dependencies = [ "anyhow", "bytes", @@ -5069,7 +5077,7 @@ dependencies = [ [[package]] name = "shared-entity" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=6262816043efeede8823d7a7ea252083adf407e9#6262816043efeede8823d7a7ea252083adf407e9" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" dependencies = [ "anyhow", "app-error", diff --git a/frontend/rust-lib/Cargo.toml b/frontend/rust-lib/Cargo.toml index 5f721c120b..70b6b5e7e2 100644 --- a/frontend/rust-lib/Cargo.toml +++ b/frontend/rust-lib/Cargo.toml @@ -99,8 +99,8 @@ validator = { version = "0.16.1", features = ["derive"] } # Run the script.add_workspace_members: # scripts/tool/update_client_api_rev.sh new_rev_id # ⚠️⚠️⚠️️ -client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "6262816043efeede8823d7a7ea252083adf407e9" } -client-api-entity = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "6262816043efeede8823d7a7ea252083adf407e9" } +client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "9884d93aa2805013f36a79c1757174a0b5063065" } +client-api-entity = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "9884d93aa2805013f36a79c1757174a0b5063065" } [profile.dev] opt-level = 1 diff --git a/frontend/rust-lib/event-integration-test/tests/chat/chat_message_test.rs b/frontend/rust-lib/event-integration-test/tests/chat/chat_message_test.rs index 8594193ab6..8e84dfe827 100644 --- a/frontend/rust-lib/event-integration-test/tests/chat/chat_message_test.rs +++ b/frontend/rust-lib/event-integration-test/tests/chat/chat_message_test.rs @@ -5,7 +5,7 @@ use flowy_chat::entities::ChatMessageListPB; use flowy_chat::notification::ChatNotification; use flowy_chat_pub::cloud::ChatMessageType; -use futures_util::StreamExt; + use std::time::Duration; #[tokio::test] @@ -19,8 +19,8 @@ async fn af_cloud_create_chat_message_test() { let chat_id = view.id.clone(); let chat_service = test.server_provider.get_server().unwrap().chat_service(); for i in 0..10 { - let mut stream = chat_service - .send_chat_message( + let _ = chat_service + .save_question( ¤t_workspace.id, &chat_id, &format!("hello world {}", i), @@ -28,9 +28,6 @@ async fn af_cloud_create_chat_message_test() { ) .await .unwrap(); - while let Some(message) = stream.next().await { - message.unwrap(); - } } let rx = test .notification_sender @@ -77,8 +74,8 @@ async fn af_cloud_load_remote_system_message_test() { let chat_service = test.server_provider.get_server().unwrap().chat_service(); for i in 0..10 { - let mut stream = chat_service - .send_chat_message( + let _ = chat_service + .save_question( ¤t_workspace.id, &chat_id, &format!("hello server {}", i), @@ -86,9 +83,6 @@ async fn af_cloud_load_remote_system_message_test() { ) .await .unwrap(); - while let Some(message) = stream.next().await { - message.unwrap(); - } } let rx = test diff --git a/frontend/rust-lib/flowy-chat-pub/src/cloud.rs b/frontend/rust-lib/flowy-chat-pub/src/cloud.rs index 8ab60069a5..115ee2b2d4 100644 --- a/frontend/rust-lib/flowy-chat-pub/src/cloud.rs +++ b/frontend/rust-lib/flowy-chat-pub/src/cloud.rs @@ -20,15 +20,7 @@ pub trait ChatCloudService: Send + Sync + 'static { chat_id: &str, ) -> FutureResult<(), FlowyError>; - async fn send_chat_message( - &self, - workspace_id: &str, - chat_id: &str, - message: &str, - message_type: ChatMessageType, - ) -> Result; - - fn send_question( + fn save_question( &self, workspace_id: &str, chat_id: &str, @@ -44,13 +36,20 @@ pub trait ChatCloudService: Send + Sync + 'static { question_id: i64, ) -> FutureResult; - async fn stream_answer( + async fn ask_question( &self, workspace_id: &str, chat_id: &str, message_id: i64, ) -> Result; + fn generate_answer( + &self, + workspace_id: &str, + chat_id: &str, + question_message_id: i64, + ) -> FutureResult; + fn get_chat_messages( &self, workspace_id: &str, @@ -65,11 +64,4 @@ pub trait ChatCloudService: Send + Sync + 'static { chat_id: &str, message_id: i64, ) -> FutureResult; - - fn generate_answer( - &self, - workspace_id: &str, - chat_id: &str, - question_message_id: i64, - ) -> FutureResult; } diff --git a/frontend/rust-lib/flowy-chat/Cargo.toml b/frontend/rust-lib/flowy-chat/Cargo.toml index 05608a284e..fcd8bb0037 100644 --- a/frontend/rust-lib/flowy-chat/Cargo.toml +++ b/frontend/rust-lib/flowy-chat/Cargo.toml @@ -28,6 +28,17 @@ futures.workspace = true allo-isolate = { version = "^0.1", features = ["catch-unwind"] } log = "0.4.21" flowy-sidecar = { workspace = true } +serde = { workspace = true, features = ["derive"] } +serde_json = { workspace = true } +anyhow = "1.0.86" +tokio-stream = "0.1.15" +parking_lot.workspace = true + +[dev-dependencies] +dotenv = "0.15.0" +uuid.workspace = true +tracing-subscriber = { version = "0.3.17", features = ["registry", "env-filter", "ansi", "json"] } + [build-dependencies] flowy-codegen.workspace = true diff --git a/frontend/rust-lib/flowy-sidecar/dev.env b/frontend/rust-lib/flowy-chat/dev.env similarity index 78% rename from frontend/rust-lib/flowy-sidecar/dev.env rename to frontend/rust-lib/flowy-chat/dev.env index 60562f76d7..5cff5dd858 100644 --- a/frontend/rust-lib/flowy-sidecar/dev.env +++ b/frontend/rust-lib/flowy-chat/dev.env @@ -1,5 +1,5 @@ CHAT_BIN_PATH= -LOCAL_AI_ROOT_PATH= +LOCAL_AI_MODEL_DIR= LOCAL_AI_CHAT_MODEL_NAME= LOCAL_AI_EMBEDDING_MODEL_NAME= diff --git a/frontend/rust-lib/flowy-chat/src/chat.rs b/frontend/rust-lib/flowy-chat/src/chat.rs index ad461d50da..840cd3b636 100644 --- a/frontend/rust-lib/flowy-chat/src/chat.rs +++ b/frontend/rust-lib/flowy-chat/src/chat.rs @@ -93,7 +93,7 @@ impl Chat { let question = self .chat_service - .send_question(&workspace_id, &self.chat_id, message, message_type) + .save_question(&workspace_id, &self.chat_id, message, message_type) .await .map_err(|err| { error!("Failed to send question: {}", err); @@ -114,7 +114,7 @@ impl Chat { tokio::spawn(async move { let mut text_sink = IsolateSink::new(Isolate::new(text_stream_port)); match cloud_service - .stream_answer(&workspace_id, &chat_id, question_id) + .ask_question(&workspace_id, &chat_id, question_id) .await { Ok(mut stream) => { diff --git a/frontend/rust-lib/flowy-chat/src/entities.rs b/frontend/rust-lib/flowy-chat/src/entities.rs index 4ef687c3c4..8b30e83504 100644 --- a/frontend/rust-lib/flowy-chat/src/entities.rs +++ b/frontend/rust-lib/flowy-chat/src/entities.rs @@ -1,3 +1,4 @@ +use crate::local_ai::manager::LocalAISetting; use flowy_chat_pub::cloud::{ ChatMessage, RelatedQuestion, RepeatedChatMessage, RepeatedRelatedQuestion, }; @@ -205,3 +206,40 @@ impl From for RepeatedRelatedQuestionPB { } } } + +#[derive(Debug, Clone, Default, ProtoBuf)] +pub struct LocalAIChatSettingPB { + #[pb(index = 1)] + pub bin_dir: String, + + #[pb(index = 2)] + pub chat_bin: String, + + #[pb(index = 3)] + pub chat_model: String, + + #[pb(index = 4)] + pub enabled: bool, +} + +impl From for LocalAIChatSettingPB { + fn from(value: LocalAISetting) -> Self { + LocalAIChatSettingPB { + bin_dir: value.chat_bin, + chat_bin: value.bin_dir, + chat_model: value.chat_model, + enabled: value.enabled, + } + } +} + +impl From for LocalAISetting { + fn from(value: LocalAIChatSettingPB) -> Self { + LocalAISetting { + chat_bin: value.bin_dir, + bin_dir: value.chat_bin, + chat_model: value.chat_model, + enabled: value.enabled, + } + } +} diff --git a/frontend/rust-lib/flowy-chat/src/event_handler.rs b/frontend/rust-lib/flowy-chat/src/event_handler.rs index 1d4499c6b2..8af7e6ddc8 100644 --- a/frontend/rust-lib/flowy-chat/src/event_handler.rs +++ b/frontend/rust-lib/flowy-chat/src/event_handler.rs @@ -1,4 +1,5 @@ use flowy_chat_pub::cloud::ChatMessageType; +use std::path::Path; use std::sync::{Arc, Weak}; use validator::Validate; @@ -110,3 +111,53 @@ pub(crate) async fn stop_stream_handler( chat_manager.stop_stream(&data.chat_id).await?; Ok(()) } + +#[tracing::instrument(level = "debug", skip_all, err)] +pub(crate) async fn get_local_ai_setting_handler( + chat_manager: AFPluginState>, +) -> DataResult { + let chat_manager = upgrade_chat_manager(chat_manager)?; + let setting = chat_manager.get_local_ai_setting()?; + let pb = setting.into(); + data_result_ok(pb) +} + +#[tracing::instrument(level = "debug", skip_all, err)] +pub(crate) async fn update_local_ai_setting_handler( + data: AFPluginData, + chat_manager: AFPluginState>, +) -> Result<(), FlowyError> { + let data = data.into_inner(); + let chat_bin_path = Path::new(&data.bin_dir); + if !chat_bin_path.exists() { + return Err( + FlowyError::invalid_data() + .with_context(format!("Chat binary path does not exist: {}", data.bin_dir)), + ); + } + if !chat_bin_path.is_file() { + return Err( + FlowyError::invalid_data() + .with_context(format!("Chat binary path is not a file: {}", data.bin_dir)), + ); + } + + // Check if local_model_dir exists and is a directory + let local_model_dir = Path::new(&data.chat_bin); + if !local_model_dir.exists() { + return Err(FlowyError::invalid_data().with_context(format!( + "Local model directory does not exist: {}", + data.chat_bin + ))); + } + if !local_model_dir.is_dir() { + return Err(FlowyError::invalid_data().with_context(format!( + "Local model directory is not a directory: {}", + data.chat_bin + ))); + } + + let chat_manager = upgrade_chat_manager(chat_manager)?; + chat_manager.update_local_ai_setting(data.into())?; + Ok(()) +} diff --git a/frontend/rust-lib/flowy-chat/src/event_map.rs b/frontend/rust-lib/flowy-chat/src/event_map.rs index e3b7828936..b38f36a8f2 100644 --- a/frontend/rust-lib/flowy-chat/src/event_map.rs +++ b/frontend/rust-lib/flowy-chat/src/event_map.rs @@ -18,6 +18,11 @@ pub fn init(chat_manager: Weak) -> AFPlugin { .event(ChatEvent::GetRelatedQuestion, get_related_question_handler) .event(ChatEvent::GetAnswerForQuestion, get_answer_handler) .event(ChatEvent::StopStream, stop_stream_handler) + .event(ChatEvent::GetLocalAISetting, get_local_ai_setting_handler) + .event( + ChatEvent::UpdateLocalAISetting, + update_local_ai_setting_handler, + ) } #[derive(Clone, Copy, PartialEq, Eq, Debug, Display, Hash, ProtoBuf_Enum, Flowy_Event)] @@ -41,4 +46,10 @@ pub enum ChatEvent { #[event(input = "ChatMessageIdPB", output = "ChatMessagePB")] GetAnswerForQuestion = 5, + + #[event(input = "LocalAIChatSettingPB")] + UpdateLocalAISetting = 6, + + #[event(output = "LocalAIChatSettingPB")] + GetLocalAISetting = 7, } diff --git a/frontend/rust-lib/flowy-chat/src/lib.rs b/frontend/rust-lib/flowy-chat/src/lib.rs index 2244af5802..8b2cbb8291 100644 --- a/frontend/rust-lib/flowy-chat/src/lib.rs +++ b/frontend/rust-lib/flowy-chat/src/lib.rs @@ -3,6 +3,7 @@ pub mod event_map; mod chat; pub mod entities; +pub mod local_ai; pub mod manager; pub mod notification; mod persistence; diff --git a/frontend/rust-lib/flowy-chat/src/local_ai/chat_plugin.rs b/frontend/rust-lib/flowy-chat/src/local_ai/chat_plugin.rs new file mode 100644 index 0000000000..3dc78447cb --- /dev/null +++ b/frontend/rust-lib/flowy-chat/src/local_ai/chat_plugin.rs @@ -0,0 +1,116 @@ +use anyhow::anyhow; +use flowy_error::FlowyError; +use flowy_sidecar::core::parser::ResponseParser; +use flowy_sidecar::core::plugin::{Plugin, PluginId}; +use flowy_sidecar::error::{RemoteError, SidecarError}; +use serde_json::json; +use serde_json::Value as JsonValue; +use std::sync::Weak; +use tokio_stream::wrappers::ReceiverStream; + +pub struct ChatPluginOperation { + plugin: Weak, +} + +impl ChatPluginOperation { + pub fn new(plugin: Weak) -> Self { + ChatPluginOperation { plugin } + } + + pub async fn send_message( + &self, + chat_id: &str, + _plugin_id: PluginId, + message: &str, + ) -> Result { + let plugin = self + .plugin + .upgrade() + .ok_or(SidecarError::Internal(anyhow!("Plugin is dropped")))?; + + let params = json!({"chat_id": chat_id, "method": "answer", "params": {"content": message}}); + let resp = plugin + .async_request::("handle", ¶ms) + .await?; + Ok(resp) + } + + pub async fn stream_message( + &self, + chat_id: &str, + _plugin_id: PluginId, + message: &str, + ) -> Result>, FlowyError> { + let plugin = self + .plugin + .upgrade() + .ok_or(FlowyError::internal().with_context("Plugin is dropped"))?; + + let params = + json!({"chat_id": chat_id, "method": "stream_answer", "params": {"content": message}}); + let stream = plugin + .stream_request::("handle", ¶ms) + .map_err(|err| FlowyError::internal().with_context(err.to_string()))?; + Ok(stream) + } + + pub async fn get_related_questions( + &self, + chat_id: &str, + ) -> Result, SidecarError> { + let plugin = self + .plugin + .upgrade() + .ok_or(SidecarError::Internal(anyhow!("Plugin is dropped")))?; + + let params = json!({"chat_id": chat_id, "method": "related_question"}); + let resp = plugin + .async_request::("handle", ¶ms) + .await?; + Ok(resp) + } +} + +pub struct ChatResponseParser; +impl ResponseParser for ChatResponseParser { + type ValueType = String; + + fn parse_json(json: JsonValue) -> Result { + if json.is_object() { + if let Some(data) = json.get("data") { + if let Some(message) = data.as_str() { + return Ok(message.to_string()); + } + } + } + return Err(RemoteError::ParseResponse(json)); + } +} + +pub struct ChatStreamResponseParser; +impl ResponseParser for ChatStreamResponseParser { + type ValueType = String; + + fn parse_json(json: JsonValue) -> Result { + if let Some(message) = json.as_str() { + return Ok(message.to_string()); + } + return Err(RemoteError::ParseResponse(json)); + } +} + +pub struct ChatRelatedQuestionsResponseParser; +impl ResponseParser for ChatRelatedQuestionsResponseParser { + type ValueType = Vec; + + fn parse_json(json: JsonValue) -> Result { + if json.is_object() { + if let Some(data) = json.get("data") { + if let Some(values) = data.as_array() { + return Ok(values.clone()); + } + } + } + return Err(RemoteError::ParseResponse(json)); + } +} diff --git a/frontend/rust-lib/flowy-sidecar/src/plugins/embedding_plugin.rs b/frontend/rust-lib/flowy-chat/src/local_ai/embedding_plugin.rs similarity index 53% rename from frontend/rust-lib/flowy-sidecar/src/plugins/embedding_plugin.rs rename to frontend/rust-lib/flowy-chat/src/local_ai/embedding_plugin.rs index 93b2a8717c..f3e8093e4e 100644 --- a/frontend/rust-lib/flowy-sidecar/src/plugins/embedding_plugin.rs +++ b/frontend/rust-lib/flowy-chat/src/local_ai/embedding_plugin.rs @@ -1,8 +1,9 @@ -use crate::core::parser::SimilarityResponseParser; -use crate::core::plugin::Plugin; -use crate::error::SidecarError; use anyhow::anyhow; +use flowy_sidecar::core::parser::ResponseParser; +use flowy_sidecar::core::plugin::Plugin; +use flowy_sidecar::error::{RemoteError, SidecarError}; use serde_json::json; +use serde_json::Value as JsonValue; use std::sync::Weak; pub struct EmbeddingPluginOperation { @@ -30,3 +31,20 @@ impl EmbeddingPluginOperation { .await } } + +pub struct SimilarityResponseParser; +impl ResponseParser for SimilarityResponseParser { + type ValueType = f64; + + fn parse_json(json: JsonValue) -> Result { + if json.is_object() { + if let Some(data) = json.get("data") { + if let Some(score) = data.get("score").and_then(|v| v.as_f64()) { + return Ok(score); + } + } + } + + return Err(RemoteError::ParseResponse(json)); + } +} diff --git a/frontend/rust-lib/flowy-chat/src/local_ai/manager.rs b/frontend/rust-lib/flowy-chat/src/local_ai/manager.rs new file mode 100644 index 0000000000..2f8c137255 --- /dev/null +++ b/frontend/rust-lib/flowy-chat/src/local_ai/manager.rs @@ -0,0 +1,176 @@ +use crate::local_ai::chat_plugin::ChatPluginOperation; +use dashmap::DashMap; +use flowy_error::{FlowyError, FlowyResult}; +use flowy_sidecar::core::plugin::{PluginId, PluginInfo}; +use flowy_sidecar::error::SidecarError; +use flowy_sidecar::manager::SidecarManager; +use log::error; +use serde::{Deserialize, Serialize}; +use std::path::PathBuf; +use std::sync::Arc; +use tokio::sync::RwLock; +use tokio_stream::wrappers::ReceiverStream; +use tracing::trace; + +#[derive(Debug, Clone, Serialize, Deserialize, Default)] +pub struct LocalAISetting { + pub bin_dir: String, + pub chat_bin: String, + pub chat_model: String, + pub enabled: bool, +} + +impl LocalAISetting { + pub fn validate(&self) -> FlowyResult<()> { + ChatPluginConfig::new(&self.bin_dir, &self.chat_bin, &self.chat_model)?; + Ok(()) + } + pub fn get_chat_plugin_config(&self) -> FlowyResult { + let config = ChatPluginConfig::new(&self.bin_dir, &self.chat_bin, &self.chat_model)?; + Ok(config) + } +} + +pub struct LocalAIManager { + sidecar_manager: Arc, + chat_plugin_config: RwLock>, + plugin_map: DashMap, + chat_plugin_id: RwLock>, +} + +impl LocalAIManager { + pub fn new(sidecar_manager: Arc) -> Self { + Self { + sidecar_manager, + chat_plugin_config: RwLock::new(None), + plugin_map: Default::default(), + chat_plugin_id: Default::default(), + } + } + + pub async fn stream_chat_message( + &self, + chat_id: &str, + message: &str, + ) -> FlowyResult>> { + let plugin_id = self + .chat_plugin_id + .read() + .await + .ok_or_else(|| FlowyError::internal().with_context("chat plugin not set"))?; + + let plugin = self + .sidecar_manager + .get_plugin(plugin_id) + .await + .map_err(|err| FlowyError::internal().with_context(err.to_string()))?; + + let operation = ChatPluginOperation::new(plugin); + let stream = operation + .stream_message(chat_id, plugin_id, message) + .await?; + + Ok(stream) + } + + pub async fn setup_chat_plugin(&self, config: ChatPluginConfig) -> FlowyResult<()> { + // If the chat_bin_path is different, remove the old plugin + if let Some(chat_plugin_config) = self.chat_plugin_config.read().await.as_ref() { + if chat_plugin_config.chat_bin_path != config.chat_bin_path { + trace!("remove old plugin: {:?}", chat_plugin_config.chat_bin_path); + if let Some(entry) = self.plugin_map.remove(&chat_plugin_config.chat_bin_path) { + if let Err(err) = self.sidecar_manager.remove_plugin(entry.1).await { + error!("remove plugin failed: {:?}", err); + } + } + } + } + + // create new plugin + let plugin_info = PluginInfo { + name: "chat_plugin".to_string(), + exec_path: config.chat_bin_path.clone(), + }; + let plugin = self + .sidecar_manager + .create_plugin(plugin_info) + .await + .unwrap(); + + // init plugin + let model_path = config.chat_model_path; + self + .sidecar_manager + .init_plugin( + plugin, + serde_json::json!({ + "absolute_chat_model_path": model_path, + }), + ) + .map_err(|err| FlowyError::internal().with_context(err.to_string()))?; + + self.chat_plugin_id.write().await.replace(plugin); + self.plugin_map.insert(config.chat_bin_path, plugin); + Ok(()) + } +} + +#[derive(Debug, Clone)] +pub struct ChatPluginConfig { + bin_dir: PathBuf, + chat_bin_path: PathBuf, + chat_model_path: PathBuf, +} + +impl ChatPluginConfig { + pub fn new(bin_dir: &str, chat_bin: &str, chat_model_name: &str) -> FlowyResult { + // check bin_dir exists and is a directory + let bin_dir = PathBuf::from(bin_dir); + if !bin_dir.exists() { + return Err( + FlowyError::invalid_data().with_context(format!("bin path not exists: {:?}", bin_dir)), + ); + } + if !bin_dir.is_dir() { + return Err( + FlowyError::invalid_data() + .with_context(format!("bin path is not directory: {:?}", bin_dir)), + ); + } + + let chat_bin_path = bin_dir.join(chat_bin); + if !chat_bin_path.exists() { + return Err(FlowyError::invalid_data().with_context(format!( + "Chat binary path does not exist: {:?}", + chat_bin_path + ))); + } + if !chat_bin_path.is_file() { + return Err(FlowyError::invalid_data().with_context(format!( + "Chat binary path is not a file: {:?}", + chat_bin_path + ))); + } + + // Check if local_model_dir exists and is a directory + let chat_model_path = bin_dir.join(&chat_model_name); + if !chat_model_path.exists() { + return Err( + FlowyError::invalid_data() + .with_context(format!("Local model does not exist: {:?}", chat_model_path)), + ); + } + if !chat_model_path.is_file() { + return Err( + FlowyError::invalid_data() + .with_context(format!("Local model is not a file: {:?}", chat_model_path)), + ); + } + + Ok(Self { + bin_dir, + chat_bin_path, + chat_model_path, + }) + } +} diff --git a/frontend/rust-lib/flowy-sidecar/src/plugins/mod.rs b/frontend/rust-lib/flowy-chat/src/local_ai/mod.rs similarity index 72% rename from frontend/rust-lib/flowy-sidecar/src/plugins/mod.rs rename to frontend/rust-lib/flowy-chat/src/local_ai/mod.rs index 1688717c79..8bdfbefd58 100644 --- a/frontend/rust-lib/flowy-sidecar/src/plugins/mod.rs +++ b/frontend/rust-lib/flowy-chat/src/local_ai/mod.rs @@ -1,2 +1,4 @@ pub mod chat_plugin; +pub mod manager; + pub mod embedding_plugin; diff --git a/frontend/rust-lib/flowy-chat/src/manager.rs b/frontend/rust-lib/flowy-chat/src/manager.rs index 4a4f1b4131..18ca36609b 100644 --- a/frontend/rust-lib/flowy-chat/src/manager.rs +++ b/frontend/rust-lib/flowy-chat/src/manager.rs @@ -3,8 +3,8 @@ use crate::entities::{ChatMessageListPB, ChatMessagePB, RepeatedRelatedQuestionP use crate::persistence::{insert_chat, ChatTable}; use dashmap::DashMap; use flowy_chat_pub::cloud::{ - ChatCloudService, ChatMessage, ChatMessageStream, ChatMessageType, MessageCursor, - RepeatedChatMessage, RepeatedRelatedQuestion, StreamAnswer, + ChatCloudService, ChatMessage, ChatMessageType, MessageCursor, RepeatedChatMessage, + RepeatedRelatedQuestion, StreamAnswer, }; use flowy_error::{FlowyError, FlowyResult}; use flowy_sidecar::manager::SidecarManager; @@ -12,8 +12,13 @@ use flowy_sqlite::DBConnection; use lib_infra::future::FutureResult; use lib_infra::util::timestamp; +use crate::local_ai::manager::{LocalAIManager, LocalAISetting}; +use flowy_sqlite::kv::KVStorePreferences; +use lib_infra::async_trait::async_trait; +use parking_lot::RwLock; + use std::sync::Arc; -use tracing::trace; +use tracing::{error, info, trace}; pub trait ChatUserService: Send + Sync + 'static { fn user_id(&self) -> Result; @@ -26,24 +31,56 @@ pub struct ChatManager { chat_service: Arc, user_service: Arc, chats: Arc>>, + store_preferences: Arc, } +const LOCAL_AI_SETTING_KEY: &str = "local_ai_setting"; impl ChatManager { pub fn new( cloud_service: Arc, user_service: impl ChatUserService, + store_preferences: Arc, ) -> ChatManager { + let local_ai_setting = store_preferences + .get_object::(LOCAL_AI_SETTING_KEY) + .unwrap_or_default(); let sidecar_manager = Arc::new(SidecarManager::new()); - let chat_service = Arc::new(ChatService::new(cloud_service, sidecar_manager)); + + // Setup local AI chat plugin + let local_ai_manager = Arc::new(LocalAIManager::new(sidecar_manager)); + setup_local_ai(&local_ai_setting, local_ai_manager.clone()); + + // + let chat_service = Arc::new(ChatService::new( + cloud_service, + local_ai_manager, + local_ai_setting, + )); let user_service = Arc::new(user_service); Self { chat_service, user_service, chats: Arc::new(DashMap::new()), + store_preferences, } } + pub fn update_local_ai_setting(&self, setting: LocalAISetting) -> FlowyResult<()> { + setting.validate()?; + + self + .store_preferences + .set_object(LOCAL_AI_SETTING_KEY, setting.clone())?; + *self.chat_service.local_ai_setting.write() = setting; + Ok(()) + } + + pub fn get_local_ai_setting(&self) -> FlowyResult { + let setting = self.chat_service.local_ai_setting.read().clone(); + Ok(setting) + } + pub async fn open_chat(&self, chat_id: &str) -> Result<(), FlowyError> { trace!("open chat: {}", chat_id); self.chats.entry(chat_id.to_string()).or_insert_with(|| { @@ -186,6 +223,21 @@ impl ChatManager { } } +fn setup_local_ai(local_ai_setting: &LocalAISetting, local_ai_manager: Arc) { + if let Ok(config) = local_ai_setting.get_chat_plugin_config() { + tokio::spawn(async move { + match local_ai_manager.setup_chat_plugin(config).await { + Ok(_) => { + info!("Local AI chat plugin setup successfully"); + }, + Err(err) => { + error!("Failed to setup local AI chat plugin: {:?}", err); + }, + } + }); + } +} + fn save_chat(conn: DBConnection, chat_id: &str) -> FlowyResult<()> { let row = ChatTable { chat_id: chat_id.to_string(), @@ -203,21 +255,25 @@ fn save_chat(conn: DBConnection, chat_id: &str) -> FlowyResult<()> { pub struct ChatService { cloud_service: Arc, - sidecar_manager: Arc, + local_ai_manager: Arc, + local_ai_setting: Arc>, } impl ChatService { pub fn new( cloud_service: Arc, - sidecar_manager: Arc, + local_ai_manager: Arc, + local_ai_setting: LocalAISetting, ) -> Self { Self { cloud_service, - sidecar_manager, + local_ai_manager, + local_ai_setting: Arc::new(RwLock::new(local_ai_setting)), } } } +#[async_trait] impl ChatCloudService for ChatService { fn create_chat( &self, @@ -228,27 +284,16 @@ impl ChatCloudService for ChatService { self.cloud_service.create_chat(uid, workspace_id, chat_id) } - async fn send_chat_message( - &self, - workspace_id: &str, - chat_id: &str, - message: &str, - message_type: ChatMessageType, - ) -> Result { - self - .cloud_service - .send_chat_message(workspace_id, chat_id, message, message_type) - .await - } - - fn send_question( + fn save_question( &self, workspace_id: &str, chat_id: &str, message: &str, message_type: ChatMessageType, ) -> FutureResult { - todo!() + self + .cloud_service + .save_question(workspace_id, chat_id, message, message_type) } fn save_answer( @@ -258,16 +303,41 @@ impl ChatCloudService for ChatService { message: &str, question_id: i64, ) -> FutureResult { - todo!() + self + .cloud_service + .save_answer(workspace_id, chat_id, message, question_id) } - async fn stream_answer( + async fn ask_question( &self, - _workspace_id: &str, - _chat_id: &str, - _message_id: i64, + workspace_id: &str, + chat_id: &str, + message_id: i64, ) -> Result { - todo!() + if self.local_ai_setting.read().enabled { + // self.local_ai_manager.stream_chat_message(chat_id, "", message_id).await + todo!() + } else { + self + .cloud_service + .ask_question(workspace_id, chat_id, message_id) + .await + } + } + + fn generate_answer( + &self, + workspace_id: &str, + chat_id: &str, + question_message_id: i64, + ) -> FutureResult { + if self.local_ai_setting.read().enabled { + todo!() + } else { + self + .cloud_service + .generate_answer(workspace_id, chat_id, question_message_id) + } } fn get_chat_messages( @@ -277,13 +347,9 @@ impl ChatCloudService for ChatService { offset: MessageCursor, limit: u64, ) -> FutureResult { - FutureResult::new(async move { - Ok(RepeatedChatMessage { - messages: vec![], - has_more: false, - total: 0, - }) - }) + self + .cloud_service + .get_chat_messages(workspace_id, chat_id, offset, limit) } fn get_related_message( @@ -292,20 +358,17 @@ impl ChatCloudService for ChatService { chat_id: &str, message_id: i64, ) -> FutureResult { - FutureResult::new(async move { - Ok(RepeatedRelatedQuestion { - message_id, - items: vec![], + if self.local_ai_setting.read().enabled { + FutureResult::new(async move { + Ok(RepeatedRelatedQuestion { + message_id, + items: vec![], + }) }) - }) - } - - fn generate_answer( - &self, - workspace_id: &str, - chat_id: &str, - question_message_id: i64, - ) -> FutureResult { - todo!() + } else { + self + .cloud_service + .get_related_message(workspace_id, chat_id, message_id) + } } } diff --git a/frontend/rust-lib/flowy-sidecar/tests/chat_test/mod.rs b/frontend/rust-lib/flowy-chat/tests/chat_test/mod.rs similarity index 72% rename from frontend/rust-lib/flowy-sidecar/tests/chat_test/mod.rs rename to frontend/rust-lib/flowy-chat/tests/chat_test/mod.rs index e6de70abcf..01363abeab 100644 --- a/frontend/rust-lib/flowy-sidecar/tests/chat_test/mod.rs +++ b/frontend/rust-lib/flowy-chat/tests/chat_test/mod.rs @@ -29,18 +29,13 @@ async fn stream_local_model_test() { let mut resp = test .stream_chat_message(&chat_id, plugin_id, "hello world") .await; - let a = resp.next().await.unwrap().unwrap(); - eprintln!("chat response: {:?}", a); + let mut list = vec![]; + while let Some(s) = resp.next().await { + list.push(s.unwrap()); + } + let answer = list.join(""); + eprintln!("chat response: {:?}", answer); tokio::time::sleep(tokio::time::Duration::from_secs(5)).await; - - // let mut resp = test - // .stream_chat_message(&chat_id, plugin_id, "How are you") - // .await; - // let a = resp.next().await.unwrap().unwrap(); - // eprintln!("chat response: {:?}", a); - // let questions = test.related_question(&chat_id, plugin_id).await; - // assert_eq!(questions.len(), 3); - // eprintln!("related questions: {:?}", questions); } } diff --git a/frontend/rust-lib/flowy-sidecar/tests/main.rs b/frontend/rust-lib/flowy-chat/tests/main.rs similarity index 100% rename from frontend/rust-lib/flowy-sidecar/tests/main.rs rename to frontend/rust-lib/flowy-chat/tests/main.rs diff --git a/frontend/rust-lib/flowy-sidecar/tests/util.rs b/frontend/rust-lib/flowy-chat/tests/util.rs similarity index 87% rename from frontend/rust-lib/flowy-sidecar/tests/util.rs rename to frontend/rust-lib/flowy-chat/tests/util.rs index 17d90e0514..6df74e54ca 100644 --- a/frontend/rust-lib/flowy-sidecar/tests/util.rs +++ b/frontend/rust-lib/flowy-chat/tests/util.rs @@ -1,14 +1,14 @@ use anyhow::Result; use flowy_sidecar::manager::SidecarManager; use serde_json::json; +use std::path::PathBuf; use std::sync::Once; use tokio_stream::wrappers::ReceiverStream; -use tokio_stream::Stream; +use flowy_chat::local_ai::chat_plugin::ChatPluginOperation; +use flowy_chat::local_ai::embedding_plugin::EmbeddingPluginOperation; use flowy_sidecar::core::plugin::{PluginId, PluginInfo}; use flowy_sidecar::error::SidecarError; -use flowy_sidecar::plugins::chat_plugin::ChatPluginOperation; -use flowy_sidecar::plugins::embedding_plugin::EmbeddingPluginOperation; use tracing_subscriber::fmt::Subscriber; use tracing_subscriber::util::SubscriberInitExt; use tracing_subscriber::EnvFilter; @@ -120,10 +120,10 @@ impl LocalAITest { } pub struct LocalAIConfiguration { - root: String, - chat_bin_path: String, + model_dir: String, + chat_bin_path: PathBuf, chat_model_name: String, - embedding_bin_path: String, + embedding_bin_path: PathBuf, embedding_model_name: String, } @@ -133,15 +133,15 @@ impl LocalAIConfiguration { setup_log(); // load from .env - let root = dotenv::var("LOCAL_AI_ROOT_PATH")?; - let chat_bin_path = dotenv::var("CHAT_BIN_PATH")?; + let model_dir = dotenv::var("LOCAL_AI_MODEL_DIR")?; + let chat_bin_path = PathBuf::from(dotenv::var("CHAT_BIN_PATH")?); let chat_model_name = dotenv::var("LOCAL_AI_CHAT_MODEL_NAME")?; - let embedding_bin_path = dotenv::var("EMBEDDING_BIN_PATH")?; + let embedding_bin_path = PathBuf::from(dotenv::var("EMBEDDING_BIN_PATH")?); let embedding_model_name = dotenv::var("LOCAL_AI_EMBEDDING_MODEL_NAME")?; Ok(Self { - root, + model_dir, chat_bin_path, chat_model_name, embedding_bin_path, @@ -150,11 +150,11 @@ impl LocalAIConfiguration { } pub fn chat_model_absolute_path(&self) -> String { - format!("{}/{}", self.root, self.chat_model_name) + format!("{}/{}", self.model_dir, self.chat_model_name) } pub fn embedding_model_absolute_path(&self) -> String { - format!("{}/{}", self.root, self.embedding_model_name) + format!("{}/{}", self.model_dir, self.embedding_model_name) } } diff --git a/frontend/rust-lib/flowy-config/src/event_handler.rs b/frontend/rust-lib/flowy-config/src/event_handler.rs index 46cd1262c3..3bd97f8cb5 100644 --- a/frontend/rust-lib/flowy-config/src/event_handler.rs +++ b/frontend/rust-lib/flowy-config/src/event_handler.rs @@ -1,13 +1,13 @@ use std::sync::Weak; use flowy_error::{FlowyError, FlowyResult}; -use flowy_sqlite::kv::StorePreferences; +use flowy_sqlite::kv::KVStorePreferences; use lib_dispatch::prelude::{data_result_ok, AFPluginData, AFPluginState, DataResult}; use crate::entities::{KeyPB, KeyValuePB}; pub(crate) async fn set_key_value_handler( - store_preferences: AFPluginState>, + store_preferences: AFPluginState>, data: AFPluginData, ) -> FlowyResult<()> { let data = data.into_inner(); @@ -25,7 +25,7 @@ pub(crate) async fn set_key_value_handler( } pub(crate) async fn get_key_value_handler( - store_preferences: AFPluginState>, + store_preferences: AFPluginState>, data: AFPluginData, ) -> DataResult { match store_preferences.upgrade() { @@ -42,7 +42,7 @@ pub(crate) async fn get_key_value_handler( } pub(crate) async fn remove_key_value_handler( - store_preferences: AFPluginState>, + store_preferences: AFPluginState>, data: AFPluginData, ) -> FlowyResult<()> { match store_preferences.upgrade() { diff --git a/frontend/rust-lib/flowy-config/src/event_map.rs b/frontend/rust-lib/flowy-config/src/event_map.rs index 68c6ceb454..801dbdd75d 100644 --- a/frontend/rust-lib/flowy-config/src/event_map.rs +++ b/frontend/rust-lib/flowy-config/src/event_map.rs @@ -3,12 +3,12 @@ use std::sync::Weak; use strum_macros::Display; use flowy_derive::{Flowy_Event, ProtoBuf_Enum}; -use flowy_sqlite::kv::StorePreferences; +use flowy_sqlite::kv::KVStorePreferences; use lib_dispatch::prelude::AFPlugin; use crate::event_handler::*; -pub fn init(store_preferences: Weak) -> AFPlugin { +pub fn init(store_preferences: Weak) -> AFPlugin { AFPlugin::new() .name(env!("CARGO_PKG_NAME")) .state(store_preferences) diff --git a/frontend/rust-lib/flowy-core/src/deps_resolve/chat_deps.rs b/frontend/rust-lib/flowy-core/src/deps_resolve/chat_deps.rs index 9ba1604182..e44d23419f 100644 --- a/frontend/rust-lib/flowy-core/src/deps_resolve/chat_deps.rs +++ b/frontend/rust-lib/flowy-core/src/deps_resolve/chat_deps.rs @@ -1,6 +1,7 @@ use flowy_chat::manager::{ChatManager, ChatUserService}; use flowy_chat_pub::cloud::ChatCloudService; use flowy_error::FlowyError; +use flowy_sqlite::kv::KVStorePreferences; use flowy_sqlite::DBConnection; use flowy_user::services::authenticate_user::AuthenticateUser; use std::sync::{Arc, Weak}; @@ -11,9 +12,14 @@ impl ChatDepsResolver { pub fn resolve( authenticate_user: Weak, cloud_service: Arc, + store_preferences: Arc, ) -> Arc { let user_service = ChatUserServiceImpl(authenticate_user); - Arc::new(ChatManager::new(cloud_service, user_service)) + Arc::new(ChatManager::new( + cloud_service, + user_service, + store_preferences, + )) } } diff --git a/frontend/rust-lib/flowy-core/src/deps_resolve/folder_deps.rs b/frontend/rust-lib/flowy-core/src/deps_resolve/folder_deps.rs index e3a86d4fc7..6566259cd9 100644 --- a/frontend/rust-lib/flowy-core/src/deps_resolve/folder_deps.rs +++ b/frontend/rust-lib/flowy-core/src/deps_resolve/folder_deps.rs @@ -18,7 +18,7 @@ use flowy_folder::view_operation::{ use flowy_folder::ViewLayout; use flowy_folder_pub::folder_builder::NestedViewBuilder; use flowy_search::folder::indexer::FolderIndexManagerImpl; -use flowy_sqlite::kv::StorePreferences; +use flowy_sqlite::kv::KVStorePreferences; use flowy_user::services::authenticate_user::AuthenticateUser; use lib_dispatch::prelude::ToBytes; use lib_infra::future::FutureResult; @@ -37,7 +37,7 @@ impl FolderDepsResolver { collab_builder: Arc, server_provider: Arc, folder_indexer: Arc, - store_preferences: Arc, + store_preferences: Arc, operation_handlers: FolderOperationHandlers, ) -> Arc { let user: Arc = Arc::new(FolderUserImpl { diff --git a/frontend/rust-lib/flowy-core/src/deps_resolve/user_deps.rs b/frontend/rust-lib/flowy-core/src/deps_resolve/user_deps.rs index 1d580e6cee..823ef63445 100644 --- a/frontend/rust-lib/flowy-core/src/deps_resolve/user_deps.rs +++ b/frontend/rust-lib/flowy-core/src/deps_resolve/user_deps.rs @@ -4,7 +4,7 @@ use flowy_database2::DatabaseManager; use flowy_error::FlowyResult; use flowy_folder::manager::FolderManager; use flowy_folder_pub::folder_builder::ParentChildViews; -use flowy_sqlite::kv::StorePreferences; +use flowy_sqlite::kv::KVStorePreferences; use flowy_user::services::authenticate_user::AuthenticateUser; use flowy_user::user_manager::UserManager; use flowy_user_pub::workspace_service::UserWorkspaceService; @@ -19,7 +19,7 @@ impl UserDepsResolver { authenticate_user: Arc, collab_builder: Arc, server_provider: Arc, - store_preference: Arc, + store_preference: Arc, database_manager: Arc, folder_manager: Arc, ) -> Arc { diff --git a/frontend/rust-lib/flowy-core/src/integrate/server.rs b/frontend/rust-lib/flowy-core/src/integrate/server.rs index 2959ae7f21..86b85f16af 100644 --- a/frontend/rust-lib/flowy-core/src/integrate/server.rs +++ b/frontend/rust-lib/flowy-core/src/integrate/server.rs @@ -14,7 +14,7 @@ use flowy_server::{AppFlowyEncryption, AppFlowyServer, EncryptionImpl}; use flowy_server_pub::af_cloud_config::AFCloudConfiguration; use flowy_server_pub::supabase_config::SupabaseConfiguration; use flowy_server_pub::AuthenticatorType; -use flowy_sqlite::kv::StorePreferences; +use flowy_sqlite::kv::KVStorePreferences; use flowy_user_pub::entities::*; use crate::AppFlowyCoreConfig; @@ -59,7 +59,7 @@ pub struct ServerProvider { providers: RwLock>>, pub(crate) encryption: RwLock>, #[allow(dead_code)] - pub(crate) store_preferences: Weak, + pub(crate) store_preferences: Weak, pub(crate) user_enable_sync: RwLock, /// The authenticator type of the user. @@ -72,7 +72,7 @@ impl ServerProvider { pub fn new( config: AppFlowyCoreConfig, server: Server, - store_preferences: Weak, + store_preferences: Weak, server_user: impl ServerUser + 'static, ) -> Self { let user = Arc::new(server_user); diff --git a/frontend/rust-lib/flowy-core/src/integrate/trait_impls.rs b/frontend/rust-lib/flowy-core/src/integrate/trait_impls.rs index 8228531d38..30f9fec432 100644 --- a/frontend/rust-lib/flowy-core/src/integrate/trait_impls.rs +++ b/frontend/rust-lib/flowy-core/src/integrate/trait_impls.rs @@ -18,8 +18,7 @@ use collab_integrate::collab_builder::{ CollabCloudPluginProvider, CollabPluginProviderContext, CollabPluginProviderType, }; use flowy_chat_pub::cloud::{ - ChatCloudService, ChatMessage, ChatMessageStream, MessageCursor, RepeatedChatMessage, - StreamAnswer, + ChatCloudService, ChatMessage, MessageCursor, RepeatedChatMessage, StreamAnswer, }; use flowy_database_pub::cloud::{ CollabDocStateByOid, DatabaseCloudService, DatabaseSnapshot, SummaryRowContent, @@ -545,24 +544,7 @@ impl ChatCloudService for ServerProvider { }) } - async fn send_chat_message( - &self, - workspace_id: &str, - chat_id: &str, - message: &str, - message_type: ChatMessageType, - ) -> Result { - let workspace_id = workspace_id.to_string(); - let chat_id = chat_id.to_string(); - let message = message.to_string(); - let server = self.get_server()?; - server - .chat_service() - .send_chat_message(&workspace_id, &chat_id, &message, message_type) - .await - } - - fn send_question( + fn save_question( &self, workspace_id: &str, chat_id: &str, @@ -577,7 +559,7 @@ impl ChatCloudService for ServerProvider { FutureResult::new(async move { server? .chat_service() - .send_question(&workspace_id, &chat_id, &message, message_type) + .save_question(&workspace_id, &chat_id, &message, message_type) .await }) } @@ -601,7 +583,7 @@ impl ChatCloudService for ServerProvider { }) } - async fn stream_answer( + async fn ask_question( &self, workspace_id: &str, chat_id: &str, @@ -612,7 +594,7 @@ impl ChatCloudService for ServerProvider { let server = self.get_server()?; server .chat_service() - .stream_answer(&workspace_id, &chat_id, message_id) + .ask_question(&workspace_id, &chat_id, message_id) .await } diff --git a/frontend/rust-lib/flowy-core/src/lib.rs b/frontend/rust-lib/flowy-core/src/lib.rs index 6511724914..69ae487ce2 100644 --- a/frontend/rust-lib/flowy-core/src/lib.rs +++ b/frontend/rust-lib/flowy-core/src/lib.rs @@ -16,7 +16,7 @@ use flowy_error::{FlowyError, FlowyResult}; use flowy_folder::manager::FolderManager; use flowy_server::af_cloud::define::ServerUser; -use flowy_sqlite::kv::StorePreferences; +use flowy_sqlite::kv::KVStorePreferences; use flowy_storage::manager::StorageManager; use flowy_user::services::authenticate_user::AuthenticateUser; use flowy_user::services::entities::UserConfig; @@ -57,7 +57,7 @@ pub struct AppFlowyCore { pub event_dispatcher: Arc, pub server_provider: Arc, pub task_dispatcher: Arc>, - pub store_preference: Arc, + pub store_preference: Arc, pub search_manager: Arc, pub chat_manager: Arc, pub storage_manager: Arc, @@ -102,7 +102,7 @@ impl AppFlowyCore { #[instrument(skip(config, runtime))] async fn init(config: AppFlowyCoreConfig, runtime: Arc) -> Self { // Init the key value database - let store_preference = Arc::new(StorePreferences::new(&config.storage_path).unwrap()); + let store_preference = Arc::new(KVStorePreferences::new(&config.storage_path).unwrap()); info!("🔥{:?}", &config); let task_scheduler = TaskDispatcher::new(Duration::from_secs(2)); @@ -175,8 +175,11 @@ impl AppFlowyCore { Arc::downgrade(&storage_manager.storage_service), ); - let chat_manager = - ChatDepsResolver::resolve(Arc::downgrade(&authenticate_user), server_provider.clone()); + let chat_manager = ChatDepsResolver::resolve( + Arc::downgrade(&authenticate_user), + server_provider.clone(), + store_preference.clone(), + ); let folder_indexer = Arc::new(FolderIndexManagerImpl::new(Some(Arc::downgrade( &authenticate_user, diff --git a/frontend/rust-lib/flowy-folder/src/manager.rs b/frontend/rust-lib/flowy-folder/src/manager.rs index fc39940569..4a27d65825 100644 --- a/frontend/rust-lib/flowy-folder/src/manager.rs +++ b/frontend/rust-lib/flowy-folder/src/manager.rs @@ -30,7 +30,7 @@ use flowy_error::{ErrorCode, FlowyError, FlowyResult}; use flowy_folder_pub::cloud::{gen_view_id, FolderCloudService}; use flowy_folder_pub::folder_builder::ParentChildViews; use flowy_search_pub::entities::FolderIndexManager; -use flowy_sqlite::kv::StorePreferences; +use flowy_sqlite::kv::KVStorePreferences; use parking_lot::RwLock; use std::fmt::{Display, Formatter}; use std::ops::Deref; @@ -51,7 +51,7 @@ pub struct FolderManager { pub(crate) operation_handlers: FolderOperationHandlers, pub cloud_service: Arc, pub(crate) folder_indexer: Arc, - pub(crate) store_preferences: Arc, + pub(crate) store_preferences: Arc, } impl FolderManager { @@ -61,7 +61,7 @@ impl FolderManager { operation_handlers: FolderOperationHandlers, cloud_service: Arc, folder_indexer: Arc, - store_preferences: Arc, + store_preferences: Arc, ) -> FlowyResult { let mutex_folder = Arc::new(MutexFolder::default()); let manager = Self { diff --git a/frontend/rust-lib/flowy-server/src/af_cloud/impls/chat.rs b/frontend/rust-lib/flowy-server/src/af_cloud/impls/chat.rs index 09469f5b35..5638e3b9e3 100644 --- a/frontend/rust-lib/flowy-server/src/af_cloud/impls/chat.rs +++ b/frontend/rust-lib/flowy-server/src/af_cloud/impls/chat.rs @@ -4,9 +4,7 @@ use client_api::entity::{ CreateAnswerMessageParams, CreateChatMessageParams, CreateChatParams, MessageCursor, RepeatedChatMessage, }; -use flowy_chat_pub::cloud::{ - ChatCloudService, ChatMessage, ChatMessageStream, ChatMessageType, StreamAnswer, -}; +use flowy_chat_pub::cloud::{ChatCloudService, ChatMessage, ChatMessageType, StreamAnswer}; use flowy_error::FlowyError; use futures_util::StreamExt; use lib_infra::async_trait::async_trait; @@ -46,27 +44,7 @@ where }) } - async fn send_chat_message( - &self, - workspace_id: &str, - chat_id: &str, - message: &str, - message_type: ChatMessageType, - ) -> Result { - let try_get_client = self.inner.try_get_client(); - let params = CreateChatMessageParams { - content: message.to_string(), - message_type, - }; - let stream = try_get_client? - .create_chat_qa_message(workspace_id, chat_id, params) - .await - .map_err(FlowyError::from)?; - - Ok(stream.boxed()) - } - - fn send_question( + fn save_question( &self, workspace_id: &str, chat_id: &str, @@ -83,7 +61,7 @@ where FutureResult::new(async move { let message = try_get_client? - .create_question(&workspace_id, &chat_id, params) + .save_question(&workspace_id, &chat_id, params) .await .map_err(FlowyError::from)?; Ok(message) @@ -107,14 +85,14 @@ where FutureResult::new(async move { let message = try_get_client? - .create_answer(&workspace_id, &chat_id, params) + .save_answer(&workspace_id, &chat_id, params) .await .map_err(FlowyError::from)?; Ok(message) }) } - async fn stream_answer( + async fn ask_question( &self, workspace_id: &str, chat_id: &str, @@ -122,12 +100,31 @@ where ) -> Result { let try_get_client = self.inner.try_get_client(); let stream = try_get_client? - .stream_answer(workspace_id, chat_id, message_id) + .ask_question(workspace_id, chat_id, message_id) .await .map_err(FlowyError::from)?; Ok(stream.boxed()) } + fn generate_answer( + &self, + workspace_id: &str, + chat_id: &str, + question_message_id: i64, + ) -> FutureResult { + let workspace_id = workspace_id.to_string(); + let chat_id = chat_id.to_string(); + let try_get_client = self.inner.try_get_client(); + + FutureResult::new(async move { + let resp = try_get_client? + .generate_answer(&workspace_id, &chat_id, question_message_id) + .await + .map_err(FlowyError::from)?; + Ok(resp) + }) + } + fn get_chat_messages( &self, workspace_id: &str, @@ -168,23 +165,4 @@ where Ok(resp) }) } - - fn generate_answer( - &self, - workspace_id: &str, - chat_id: &str, - question_message_id: i64, - ) -> FutureResult { - let workspace_id = workspace_id.to_string(); - let chat_id = chat_id.to_string(); - let try_get_client = self.inner.try_get_client(); - - FutureResult::new(async move { - let resp = try_get_client? - .get_answer(&workspace_id, &chat_id, question_message_id) - .await - .map_err(FlowyError::from)?; - Ok(resp) - }) - } } diff --git a/frontend/rust-lib/flowy-server/src/default_impl.rs b/frontend/rust-lib/flowy-server/src/default_impl.rs index 90d9bf15a7..b1728b4f47 100644 --- a/frontend/rust-lib/flowy-server/src/default_impl.rs +++ b/frontend/rust-lib/flowy-server/src/default_impl.rs @@ -20,17 +20,7 @@ impl ChatCloudService for DefaultChatCloudServiceImpl { }) } - async fn send_chat_message( - &self, - _workspace_id: &str, - _chat_id: &str, - _message: &str, - _message_type: ChatMessageType, - ) -> Result { - Err(FlowyError::not_support().with_context("Chat is not supported in local server.")) - } - - fn send_question( + fn save_question( &self, _workspace_id: &str, _chat_id: &str, @@ -54,7 +44,7 @@ impl ChatCloudService for DefaultChatCloudServiceImpl { }) } - async fn stream_answer( + async fn ask_question( &self, _workspace_id: &str, _chat_id: &str, diff --git a/frontend/rust-lib/flowy-sidecar/Cargo.toml b/frontend/rust-lib/flowy-sidecar/Cargo.toml index b7467dce69..a635067a81 100644 --- a/frontend/rust-lib/flowy-sidecar/Cargo.toml +++ b/frontend/rust-lib/flowy-sidecar/Cargo.toml @@ -18,9 +18,3 @@ log = "0.4.21" parking_lot.workspace = true tokio-stream = "0.1.15" lib-infra.workspace = true - - -[dev-dependencies] -dotenv = "0.15.0" -uuid.workspace = true -tracing-subscriber = { version = "0.3.17", features = ["registry", "env-filter", "ansi", "json"] } diff --git a/frontend/rust-lib/flowy-sidecar/src/core/parser.rs b/frontend/rust-lib/flowy-sidecar/src/core/parser.rs index 9e8178d44d..9a2f2d89fb 100644 --- a/frontend/rust-lib/flowy-sidecar/src/core/parser.rs +++ b/frontend/rust-lib/flowy-sidecar/src/core/parser.rs @@ -3,7 +3,6 @@ use crate::core::rpc_object::RpcObject; use crate::error::{ReadError, RemoteError}; use serde_json::{json, Value as JsonValue}; use std::io::BufRead; -use tracing::error; #[derive(Debug, Default)] pub struct MessageReader(String); @@ -61,64 +60,3 @@ pub trait ResponseParser { type ValueType: Send + Sync + 'static; fn parse_json(payload: JsonValue) -> Result; } - -pub struct ChatResponseParser; -impl ResponseParser for ChatResponseParser { - type ValueType = String; - - fn parse_json(json: JsonValue) -> Result { - if json.is_object() { - if let Some(data) = json.get("data") { - if let Some(message) = data.as_str() { - return Ok(message.to_string()); - } - } - } - return Err(RemoteError::ParseResponse(json)); - } -} - -pub struct ChatStreamResponseParser; -impl ResponseParser for ChatStreamResponseParser { - type ValueType = String; - - fn parse_json(json: JsonValue) -> Result { - if let Some(message) = json.as_str() { - return Ok(message.to_string()); - } - return Err(RemoteError::ParseResponse(json)); - } -} - -pub struct ChatRelatedQuestionsResponseParser; -impl ResponseParser for ChatRelatedQuestionsResponseParser { - type ValueType = Vec; - - fn parse_json(json: JsonValue) -> Result { - if json.is_object() { - if let Some(data) = json.get("data") { - if let Some(values) = data.as_array() { - return Ok(values.clone()); - } - } - } - return Err(RemoteError::ParseResponse(json)); - } -} - -pub struct SimilarityResponseParser; -impl ResponseParser for SimilarityResponseParser { - type ValueType = f64; - - fn parse_json(json: JsonValue) -> Result { - if json.is_object() { - if let Some(data) = json.get("data") { - if let Some(score) = data.get("score").and_then(|v| v.as_f64()) { - return Ok(score); - } - } - } - - return Err(RemoteError::ParseResponse(json)); - } -} diff --git a/frontend/rust-lib/flowy-sidecar/src/core/plugin.rs b/frontend/rust-lib/flowy-sidecar/src/core/plugin.rs index db18e68661..16b0ff221a 100644 --- a/frontend/rust-lib/flowy-sidecar/src/core/plugin.rs +++ b/frontend/rust-lib/flowy-sidecar/src/core/plugin.rs @@ -8,12 +8,12 @@ use anyhow::anyhow; use serde::{Deserialize, Serialize}; use serde_json::{json, Value as JsonValue}; use std::io::BufReader; +use std::path::PathBuf; use std::process::{Child, Stdio}; use std::sync::Arc; use std::thread; use std::time::Instant; use tokio_stream::wrappers::ReceiverStream; -use tokio_stream::Stream; use tracing::{error, info}; @@ -126,7 +126,7 @@ impl Plugin { pub struct PluginInfo { pub name: String, - pub exec_path: String, + pub exec_path: PathBuf, } pub(crate) async fn start_plugin_process( diff --git a/frontend/rust-lib/flowy-sidecar/src/core/rpc_loop.rs b/frontend/rust-lib/flowy-sidecar/src/core/rpc_loop.rs index 8712349cc2..caddcc98c6 100644 --- a/frontend/rust-lib/flowy-sidecar/src/core/rpc_loop.rs +++ b/frontend/rust-lib/flowy-sidecar/src/core/rpc_loop.rs @@ -9,7 +9,7 @@ use std::io::{BufRead, Write}; use std::sync::Arc; use std::thread; use std::time::Duration; -use tracing::{error, info, trace}; +use tracing::{error, trace}; const MAX_IDLE_WAIT: Duration = Duration::from_millis(5); diff --git a/frontend/rust-lib/flowy-sidecar/src/core/rpc_object.rs b/frontend/rust-lib/flowy-sidecar/src/core/rpc_object.rs index 253e400e45..7f4e46864c 100644 --- a/frontend/rust-lib/flowy-sidecar/src/core/rpc_object.rs +++ b/frontend/rust-lib/flowy-sidecar/src/core/rpc_object.rs @@ -1,8 +1,8 @@ use crate::core::parser::{Call, RequestId}; use crate::core::rpc_peer::{Response, ResponsePayload}; -use crate::error::RemoteError; + use serde::de::{DeserializeOwned, Error}; -use serde_json::{json, Value}; +use serde_json::Value; #[derive(Debug, Clone)] pub struct RpcObject(pub Value); diff --git a/frontend/rust-lib/flowy-sidecar/src/core/rpc_peer.rs b/frontend/rust-lib/flowy-sidecar/src/core/rpc_peer.rs index 5d8d277f47..e61bb5ff9d 100644 --- a/frontend/rust-lib/flowy-sidecar/src/core/rpc_peer.rs +++ b/frontend/rust-lib/flowy-sidecar/src/core/rpc_peer.rs @@ -200,7 +200,19 @@ impl RawPeer { } } let json = resp.map(|resp| resp.into_json()); - response_handler.invoke(json); + match json { + Ok(Some(json)) => { + response_handler.invoke(Ok(json)); + }, + Ok(None) => { + if !is_stream { + warn!("[RPC] only stream response can be None"); + } + }, + Err(err) => { + response_handler.invoke(Err(err)); + }, + } }, None => error!("[RPC] id {}'s handle not found", request_id), } @@ -306,19 +318,11 @@ impl ResponsePayload { matches!(self, ResponsePayload::StreamEnd(_)) } - pub fn json(&self) -> &JsonValue { + pub fn into_json(self) -> Option { match self { - ResponsePayload::Json(v) => v, - ResponsePayload::Streaming(v) => v, - ResponsePayload::StreamEnd(v) => v, - } - } - - pub fn into_json(self) -> JsonValue { - match self { - ResponsePayload::Json(v) => v, - ResponsePayload::Streaming(v) => v, - ResponsePayload::StreamEnd(v) => v, + ResponsePayload::Json(v) => Some(v), + ResponsePayload::Streaming(v) => Some(v), + ResponsePayload::StreamEnd(_) => None, } } } diff --git a/frontend/rust-lib/flowy-sidecar/src/lib.rs b/frontend/rust-lib/flowy-sidecar/src/lib.rs index 7d77790307..3eabd6918a 100644 --- a/frontend/rust-lib/flowy-sidecar/src/lib.rs +++ b/frontend/rust-lib/flowy-sidecar/src/lib.rs @@ -1,4 +1,3 @@ pub mod core; pub mod error; pub mod manager; -pub mod plugins; diff --git a/frontend/rust-lib/flowy-sidecar/src/plugins/chat_plugin.rs b/frontend/rust-lib/flowy-sidecar/src/plugins/chat_plugin.rs deleted file mode 100644 index f346b62933..0000000000 --- a/frontend/rust-lib/flowy-sidecar/src/plugins/chat_plugin.rs +++ /dev/null @@ -1,70 +0,0 @@ -use crate::core::parser::{ - ChatRelatedQuestionsResponseParser, ChatResponseParser, ChatStreamResponseParser, -}; -use crate::core::plugin::{Plugin, PluginId}; -use crate::error::SidecarError; -use anyhow::anyhow; -use serde_json::json; -use std::sync::Weak; -use tokio_stream::wrappers::ReceiverStream; -use tokio_stream::Stream; - -pub struct ChatPluginOperation { - plugin: Weak, -} - -impl ChatPluginOperation { - pub fn new(plugin: Weak) -> Self { - ChatPluginOperation { plugin } - } - - pub async fn send_message( - &self, - chat_id: &str, - _plugin_id: PluginId, - message: &str, - ) -> Result { - let plugin = self - .plugin - .upgrade() - .ok_or(SidecarError::Internal(anyhow!("Plugin is dropped")))?; - - let params = json!({"chat_id": chat_id, "method": "answer", "params": {"content": message}}); - let resp = plugin - .async_request::("handle", ¶ms) - .await?; - Ok(resp) - } - - pub async fn stream_message( - &self, - chat_id: &str, - _plugin_id: PluginId, - message: &str, - ) -> Result>, SidecarError> { - let plugin = self - .plugin - .upgrade() - .ok_or(SidecarError::Internal(anyhow!("Plugin is dropped")))?; - - let params = - json!({"chat_id": chat_id, "method": "stream_answer", "params": {"content": message}}); - plugin.stream_request::("handle", ¶ms) - } - - pub async fn get_related_questions( - &self, - chat_id: &str, - ) -> Result, SidecarError> { - let plugin = self - .plugin - .upgrade() - .ok_or(SidecarError::Internal(anyhow!("Plugin is dropped")))?; - - let params = json!({"chat_id": chat_id, "method": "related_question"}); - let resp = plugin - .async_request::("handle", ¶ms) - .await?; - Ok(resp) - } -} diff --git a/frontend/rust-lib/flowy-sqlite/src/kv/kv.rs b/frontend/rust-lib/flowy-sqlite/src/kv/kv.rs index 1ec71688c5..d10da70823 100644 --- a/frontend/rust-lib/flowy-sqlite/src/kv/kv.rs +++ b/frontend/rust-lib/flowy-sqlite/src/kv/kv.rs @@ -11,13 +11,13 @@ use crate::sqlite_impl::{Database, PoolConfig}; const DB_NAME: &str = "cache.db"; -/// [StorePreferences] uses a sqlite database to store key value pairs. +/// [KVStorePreferences] uses a sqlite database to store key value pairs. /// Most of the time, it used to storage AppFlowy configuration. #[derive(Clone)] -pub struct StorePreferences { +pub struct KVStorePreferences { database: Option, } -impl StorePreferences { +impl KVStorePreferences { #[tracing::instrument(level = "trace", err)] pub fn new(root: &str) -> Result { if !Path::new(root).exists() { @@ -138,7 +138,7 @@ mod tests { use serde::{Deserialize, Serialize}; use tempfile::TempDir; - use crate::kv::StorePreferences; + use crate::kv::KVStorePreferences; #[derive(Serialize, Deserialize, Clone, Eq, PartialEq, Debug)] struct Person { @@ -150,7 +150,7 @@ mod tests { fn kv_store_test() { let tempdir = TempDir::new().unwrap(); let path = tempdir.into_path(); - let store = StorePreferences::new(path.to_str().unwrap()).unwrap(); + let store = KVStorePreferences::new(path.to_str().unwrap()).unwrap(); store.set_str("1", "hello".to_string()); assert_eq!(store.get_str("1").unwrap(), "hello"); diff --git a/frontend/rust-lib/flowy-user/src/event_handler.rs b/frontend/rust-lib/flowy-user/src/event_handler.rs index b2c36d8c6b..93936e3db1 100644 --- a/frontend/rust-lib/flowy-user/src/event_handler.rs +++ b/frontend/rust-lib/flowy-user/src/event_handler.rs @@ -1,5 +1,5 @@ use flowy_error::{ErrorCode, FlowyError, FlowyResult}; -use flowy_sqlite::kv::StorePreferences; +use flowy_sqlite::kv::KVStorePreferences; use flowy_user_pub::cloud::UserCloudConfig; use flowy_user_pub::entities::*; use lib_dispatch::prelude::*; @@ -25,8 +25,8 @@ fn upgrade_manager(manager: AFPluginState>) -> FlowyResult>, -) -> FlowyResult> { + store: AFPluginState>, +) -> FlowyResult> { let store = store .upgrade() .ok_or(FlowyError::internal().with_context("The store preferences is already drop"))?; @@ -151,7 +151,7 @@ const APPEARANCE_SETTING_CACHE_KEY: &str = "appearance_settings"; #[tracing::instrument(level = "debug", skip_all, err)] pub async fn set_appearance_setting( - store_preferences: AFPluginState>, + store_preferences: AFPluginState>, data: AFPluginData, ) -> Result<(), FlowyError> { let store_preferences = upgrade_store_preferences(store_preferences)?; @@ -165,7 +165,7 @@ pub async fn set_appearance_setting( #[tracing::instrument(level = "debug", skip_all, err)] pub async fn get_appearance_setting( - store_preferences: AFPluginState>, + store_preferences: AFPluginState>, ) -> DataResult { let store_preferences = upgrade_store_preferences(store_preferences)?; match store_preferences.get_str(APPEARANCE_SETTING_CACHE_KEY) { @@ -187,7 +187,7 @@ const DATE_TIME_SETTINGS_CACHE_KEY: &str = "date_time_settings"; #[tracing::instrument(level = "debug", skip_all, err)] pub async fn set_date_time_settings( - store_preferences: AFPluginState>, + store_preferences: AFPluginState>, data: AFPluginData, ) -> Result<(), FlowyError> { let store_preferences = upgrade_store_preferences(store_preferences)?; @@ -202,7 +202,7 @@ pub async fn set_date_time_settings( #[tracing::instrument(level = "debug", skip_all, err)] pub async fn get_date_time_settings( - store_preferences: AFPluginState>, + store_preferences: AFPluginState>, ) -> DataResult { let store_preferences = upgrade_store_preferences(store_preferences)?; match store_preferences.get_str(DATE_TIME_SETTINGS_CACHE_KEY) { @@ -227,7 +227,7 @@ const NOTIFICATION_SETTINGS_CACHE_KEY: &str = "notification_settings"; #[tracing::instrument(level = "debug", skip_all, err)] pub async fn set_notification_settings( - store_preferences: AFPluginState>, + store_preferences: AFPluginState>, data: AFPluginData, ) -> Result<(), FlowyError> { let store_preferences = upgrade_store_preferences(store_preferences)?; @@ -238,7 +238,7 @@ pub async fn set_notification_settings( #[tracing::instrument(level = "debug", skip_all, err)] pub async fn get_notification_settings( - store_preferences: AFPluginState>, + store_preferences: AFPluginState>, ) -> DataResult { let store_preferences = upgrade_store_preferences(store_preferences)?; match store_preferences.get_str(NOTIFICATION_SETTINGS_CACHE_KEY) { @@ -348,7 +348,7 @@ pub async fn sign_in_with_provider_handler( pub async fn set_encrypt_secret_handler( manager: AFPluginState>, data: AFPluginData, - store_preferences: AFPluginState>, + store_preferences: AFPluginState>, ) -> Result<(), FlowyError> { let manager = upgrade_manager(manager)?; let store_preferences = upgrade_store_preferences(store_preferences)?; @@ -408,7 +408,7 @@ pub async fn check_encrypt_secret_handler( pub async fn set_cloud_config_handler( manager: AFPluginState>, data: AFPluginData, - store_preferences: AFPluginState>, + store_preferences: AFPluginState>, ) -> Result<(), FlowyError> { let manager = upgrade_manager(manager)?; let session = manager.get_session()?; @@ -468,7 +468,7 @@ pub async fn set_cloud_config_handler( #[tracing::instrument(level = "info", skip_all, err)] pub async fn get_cloud_config_handler( manager: AFPluginState>, - store_preferences: AFPluginState>, + store_preferences: AFPluginState>, ) -> DataResult { let manager = upgrade_manager(manager)?; let session = manager.get_session()?; diff --git a/frontend/rust-lib/flowy-user/src/migrations/session_migration.rs b/frontend/rust-lib/flowy-user/src/migrations/session_migration.rs index 77376e1c6c..172f88209f 100644 --- a/frontend/rust-lib/flowy-user/src/migrations/session_migration.rs +++ b/frontend/rust-lib/flowy-user/src/migrations/session_migration.rs @@ -1,4 +1,4 @@ -use flowy_sqlite::kv::StorePreferences; +use flowy_sqlite::kv::KVStorePreferences; use flowy_user_pub::session::Session; use serde_json::{json, Value}; use std::sync::Arc; @@ -8,7 +8,7 @@ const MIGRATION_USER_NO_USER_UUID: &str = "migration_user_no_user_uuid"; pub fn migrate_session_with_user_uuid( session_cache_key: &str, - store_preferences: &Arc, + store_preferences: &Arc, ) -> Option { if !store_preferences.get_bool(MIGRATION_USER_NO_USER_UUID) && store_preferences diff --git a/frontend/rust-lib/flowy-user/src/services/authenticate_user.rs b/frontend/rust-lib/flowy-user/src/services/authenticate_user.rs index dc7b9c1b9c..420ffdeda6 100644 --- a/frontend/rust-lib/flowy-user/src/services/authenticate_user.rs +++ b/frontend/rust-lib/flowy-user/src/services/authenticate_user.rs @@ -5,7 +5,7 @@ use crate::services::sqlite_sql::user_sql::vacuum_database; use collab_integrate::CollabKVDB; use flowy_error::{internal_error, ErrorCode, FlowyError, FlowyResult}; -use flowy_sqlite::kv::StorePreferences; +use flowy_sqlite::kv::KVStorePreferences; use flowy_sqlite::DBConnection; use flowy_user_pub::entities::UserWorkspace; use flowy_user_pub::session::Session; @@ -19,12 +19,12 @@ pub struct AuthenticateUser { pub user_config: UserConfig, pub(crate) database: Arc, pub(crate) user_paths: UserPaths, - store_preferences: Arc, + store_preferences: Arc, session: Arc>>, } impl AuthenticateUser { - pub fn new(user_config: UserConfig, store_preferences: Arc) -> Self { + pub fn new(user_config: UserConfig, store_preferences: Arc) -> Self { let user_paths = UserPaths::new(user_config.storage_path.clone()); let database = Arc::new(UserDB::new(user_paths.clone())); let session = Arc::new(parking_lot::RwLock::new(None)); diff --git a/frontend/rust-lib/flowy-user/src/services/cloud_config.rs b/frontend/rust-lib/flowy-user/src/services/cloud_config.rs index 6772ac7ab5..62ab5a5e72 100644 --- a/frontend/rust-lib/flowy-user/src/services/cloud_config.rs +++ b/frontend/rust-lib/flowy-user/src/services/cloud_config.rs @@ -2,12 +2,12 @@ use std::sync::Arc; use flowy_encrypt::generate_encryption_secret; use flowy_error::FlowyResult; -use flowy_sqlite::kv::StorePreferences; +use flowy_sqlite::kv::KVStorePreferences; use flowy_user_pub::cloud::UserCloudConfig; const CLOUD_CONFIG_KEY: &str = "af_user_cloud_config"; -fn generate_cloud_config(uid: i64, store_preference: &Arc) -> UserCloudConfig { +fn generate_cloud_config(uid: i64, store_preference: &Arc) -> UserCloudConfig { let config = UserCloudConfig::new(generate_encryption_secret()); let key = cache_key_for_cloud_config(uid); store_preference.set_object(&key, config.clone()).unwrap(); @@ -16,7 +16,7 @@ fn generate_cloud_config(uid: i64, store_preference: &Arc) -> pub fn save_cloud_config( uid: i64, - store_preference: &Arc, + store_preference: &Arc, config: UserCloudConfig, ) -> FlowyResult<()> { tracing::info!("save user:{} cloud config: {}", uid, config); @@ -31,7 +31,7 @@ fn cache_key_for_cloud_config(uid: i64) -> String { pub fn get_cloud_config( uid: i64, - store_preference: &Arc, + store_preference: &Arc, ) -> Option { let key = cache_key_for_cloud_config(uid); store_preference.get_object::(&key) @@ -39,7 +39,7 @@ pub fn get_cloud_config( pub fn get_or_create_cloud_config( uid: i64, - store_preferences: &Arc, + store_preferences: &Arc, ) -> UserCloudConfig { let key = cache_key_for_cloud_config(uid); store_preferences @@ -47,7 +47,7 @@ pub fn get_or_create_cloud_config( .unwrap_or_else(|| generate_cloud_config(uid, store_preferences)) } -pub fn get_encrypt_secret(uid: i64, store_preference: &Arc) -> Option { +pub fn get_encrypt_secret(uid: i64, store_preference: &Arc) -> Option { let key = cache_key_for_cloud_config(uid); store_preference .get_object::(&key) diff --git a/frontend/rust-lib/flowy-user/src/services/data_import/appflowy_data_import.rs b/frontend/rust-lib/flowy-user/src/services/data_import/appflowy_data_import.rs index f60f07deac..41d9d25a34 100644 --- a/frontend/rust-lib/flowy-user/src/services/data_import/appflowy_data_import.rs +++ b/frontend/rust-lib/flowy-user/src/services/data_import/appflowy_data_import.rs @@ -26,7 +26,7 @@ use flowy_error::FlowyError; use flowy_folder_pub::cloud::gen_view_id; use flowy_folder_pub::entities::{AppFlowyData, ImportData}; use flowy_folder_pub::folder_builder::{ParentChildViews, ViewBuilder}; -use flowy_sqlite::kv::StorePreferences; +use flowy_sqlite::kv::KVStorePreferences; use flowy_user_pub::cloud::{UserCloudService, UserCollabParams}; use flowy_user_pub::entities::{user_awareness_object_id, Authenticator}; use flowy_user_pub::session::Session; @@ -62,7 +62,7 @@ pub(crate) fn prepare_import(path: &str) -> anyhow::Result { return Err(anyhow!("The path: {} is not exist", path)); } let user_paths = UserPaths::new(path.to_string()); - let other_store_preferences = Arc::new(StorePreferences::new(path)?); + let other_store_preferences = Arc::new(KVStorePreferences::new(path)?); migrate_session_with_user_uuid("appflowy_session_cache", &other_store_preferences); let imported_session = other_store_preferences .get_object::("appflowy_session_cache") diff --git a/frontend/rust-lib/flowy-user/src/user_manager/manager.rs b/frontend/rust-lib/flowy-user/src/user_manager/manager.rs index 9a8a95181c..a4bfb1d31a 100644 --- a/frontend/rust-lib/flowy-user/src/user_manager/manager.rs +++ b/frontend/rust-lib/flowy-user/src/user_manager/manager.rs @@ -4,7 +4,7 @@ use collab_user::core::MutexUserAwareness; use flowy_error::{internal_error, ErrorCode, FlowyResult}; use flowy_server_pub::AuthenticatorType; -use flowy_sqlite::kv::StorePreferences; +use flowy_sqlite::kv::KVStorePreferences; use flowy_sqlite::schema::user_table; use flowy_sqlite::ConnectionPool; use flowy_sqlite::{query_dsl::*, DBConnection, ExpressionMethods}; @@ -48,7 +48,7 @@ use super::manager_user_workspace::save_user_workspace; pub struct UserManager { pub(crate) cloud_services: Arc, - pub(crate) store_preferences: Arc, + pub(crate) store_preferences: Arc, pub(crate) user_awareness: Arc>>, pub(crate) user_status_callback: RwLock>, pub(crate) collab_builder: Weak, @@ -63,7 +63,7 @@ pub struct UserManager { impl UserManager { pub fn new( cloud_services: Arc, - store_preferences: Arc, + store_preferences: Arc, collab_builder: Weak, authenticate_user: Arc, user_workspace_service: Arc, @@ -110,7 +110,7 @@ impl UserManager { } } - pub fn get_store_preferences(&self) -> Weak { + pub fn get_store_preferences(&self) -> Weak { Arc::downgrade(&self.store_preferences) }