mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
feat: integrated openAI rust plugin (#3302)
* feat: create flowy-plugins * feat: integrated openai service with interface * feat: integrated openai api call * fix: response in api * fix: removed unused imports * fix: remove parse.rs * fix: macos version + removed print * fix: removed debugPrint + changed deployment target * fix: android project+removed gesture detector * fix: removed unused imports * chore: fix compile * chore: rever changes * chore: rever changes * chore: fix clippy warnings * chore: rename * chore: fix compile error * chore: remove dart ai --------- Co-authored-by: nathan <nathan@appflowy.io>
This commit is contained in:
parent
124d435f09
commit
e3f11ea9c0
@ -22,12 +22,12 @@
|
|||||||
</natures>
|
</natures>
|
||||||
<filteredResources>
|
<filteredResources>
|
||||||
<filter>
|
<filter>
|
||||||
<id>1626576261667</id>
|
<id>1693395487121</id>
|
||||||
<name></name>
|
<name></name>
|
||||||
<type>30</type>
|
<type>30</type>
|
||||||
<matcher>
|
<matcher>
|
||||||
<id>org.eclipse.core.resources.regexFilterMatcher</id>
|
<id>org.eclipse.core.resources.regexFilterMatcher</id>
|
||||||
<arguments>node_modules|.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__</arguments>
|
<arguments>node_modules|\.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__</arguments>
|
||||||
</matcher>
|
</matcher>
|
||||||
</filter>
|
</filter>
|
||||||
</filteredResources>
|
</filteredResources>
|
||||||
|
@ -1,2 +1,13 @@
|
|||||||
|
arguments=--init-script /var/folders/th/tfqrqcp12kvgzs3c3z0xqxlc0000gn/T/d146c9752a26f79b52047fb6dc6ed385d064e120494f96f08ca63a317c41f94c.gradle --init-script /var/folders/th/tfqrqcp12kvgzs3c3z0xqxlc0000gn/T/52cde0cfcf3e28b8b7510e992210d9614505e0911af0c190bd590d7158574963.gradle
|
||||||
|
auto.sync=false
|
||||||
|
build.scans.enabled=false
|
||||||
|
connection.gradle.distribution=GRADLE_DISTRIBUTION(VERSION(7.4.2))
|
||||||
connection.project.dir=
|
connection.project.dir=
|
||||||
eclipse.preferences.version=1
|
eclipse.preferences.version=1
|
||||||
|
gradle.user.home=
|
||||||
|
java.home=/Library/Java/JavaVirtualMachines/temurin-17.jdk/Contents/Home
|
||||||
|
jvm.arguments=
|
||||||
|
offline.mode=false
|
||||||
|
override.workspace.settings=true
|
||||||
|
show.console.view=true
|
||||||
|
show.executions.view=true
|
||||||
|
@ -1,2 +1,13 @@
|
|||||||
connection.project.dir=..
|
arguments=
|
||||||
|
auto.sync=false
|
||||||
|
build.scans.enabled=false
|
||||||
|
connection.gradle.distribution=GRADLE_DISTRIBUTION(WRAPPER)
|
||||||
|
connection.project.dir=
|
||||||
eclipse.preferences.version=1
|
eclipse.preferences.version=1
|
||||||
|
gradle.user.home=
|
||||||
|
java.home=/Library/Java/JavaVirtualMachines/jdk11.0.5-zulu.jdk/Contents/Home
|
||||||
|
jvm.arguments=
|
||||||
|
offline.mode=false
|
||||||
|
override.workspace.settings=true
|
||||||
|
show.console.view=true
|
||||||
|
show.executions.view=true
|
||||||
|
18
frontend/appflowy_tauri/src-tauri/Cargo.lock
generated
18
frontend/appflowy_tauri/src-tauri/Cargo.lock
generated
@ -1569,6 +1569,23 @@ dependencies = [
|
|||||||
"miniz_oxide 0.7.1",
|
"miniz_oxide 0.7.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "flowy-ai"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"bytes",
|
||||||
|
"flowy-derive",
|
||||||
|
"flowy-error",
|
||||||
|
"flowy-notification",
|
||||||
|
"lib-dispatch",
|
||||||
|
"lib-infra",
|
||||||
|
"protobuf",
|
||||||
|
"reqwest",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
"strum_macros 0.21.1",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "flowy-ast"
|
name = "flowy-ast"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
@ -1627,6 +1644,7 @@ dependencies = [
|
|||||||
"collab-integrate",
|
"collab-integrate",
|
||||||
"collab-plugins",
|
"collab-plugins",
|
||||||
"diesel",
|
"diesel",
|
||||||
|
"flowy-ai",
|
||||||
"flowy-config",
|
"flowy-config",
|
||||||
"flowy-database-deps",
|
"flowy-database-deps",
|
||||||
"flowy-database2",
|
"flowy-database2",
|
||||||
|
18
frontend/rust-lib/Cargo.lock
generated
18
frontend/rust-lib/Cargo.lock
generated
@ -1317,6 +1317,23 @@ dependencies = [
|
|||||||
"miniz_oxide",
|
"miniz_oxide",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "flowy-ai"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"bytes",
|
||||||
|
"flowy-derive",
|
||||||
|
"flowy-error",
|
||||||
|
"flowy-notification",
|
||||||
|
"lib-dispatch",
|
||||||
|
"lib-infra",
|
||||||
|
"protobuf",
|
||||||
|
"reqwest",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
"strum_macros 0.21.1",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "flowy-ast"
|
name = "flowy-ast"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
@ -1376,6 +1393,7 @@ dependencies = [
|
|||||||
"collab-plugins",
|
"collab-plugins",
|
||||||
"console-subscriber",
|
"console-subscriber",
|
||||||
"diesel",
|
"diesel",
|
||||||
|
"flowy-ai",
|
||||||
"flowy-config",
|
"flowy-config",
|
||||||
"flowy-database-deps",
|
"flowy-database-deps",
|
||||||
"flowy-database2",
|
"flowy-database2",
|
||||||
|
@ -23,6 +23,7 @@ members = [
|
|||||||
"flowy-encrypt",
|
"flowy-encrypt",
|
||||||
"flowy-storage",
|
"flowy-storage",
|
||||||
"collab-integrate",
|
"collab-integrate",
|
||||||
|
"flowy-ai",
|
||||||
]
|
]
|
||||||
|
|
||||||
[workspace.dependencies]
|
[workspace.dependencies]
|
||||||
@ -48,6 +49,7 @@ flowy-config = { workspace = true, path = "flowy-config" }
|
|||||||
flowy-encrypt = { workspace = true, path = "flowy-encrypt" }
|
flowy-encrypt = { workspace = true, path = "flowy-encrypt" }
|
||||||
flowy-storage = { workspace = true, path = "flowy-storage" }
|
flowy-storage = { workspace = true, path = "flowy-storage" }
|
||||||
collab-integrate = { workspace = true, path = "collab-integrate" }
|
collab-integrate = { workspace = true, path = "collab-integrate" }
|
||||||
|
flowy-ai = { workspace = true, path = "flowy-ai" }
|
||||||
|
|
||||||
[profile.dev]
|
[profile.dev]
|
||||||
opt-level = 0
|
opt-level = 0
|
||||||
|
20
frontend/rust-lib/flowy-ai/Cargo.toml
Normal file
20
frontend/rust-lib/flowy-ai/Cargo.toml
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
[package]
|
||||||
|
name = "flowy-ai"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
flowy-derive = { path = "../../../shared-lib/flowy-derive" }
|
||||||
|
flowy-notification = { path = "../flowy-notification" }
|
||||||
|
flowy-error = { path = "../flowy-error", features = ["impl_from_serde", "impl_from_dispatch_error"] }
|
||||||
|
lib-dispatch = { path = "../lib-dispatch" }
|
||||||
|
lib-infra = { path = "../../../shared-lib/lib-infra" }
|
||||||
|
|
||||||
|
protobuf = {version = "2.28.0"}
|
||||||
|
bytes = { version = "1.4" }
|
||||||
|
strum_macros = "0.21"
|
||||||
|
reqwest = { version = "0.11", features = ["json"] }
|
||||||
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
|
serde_json = "1.0"
|
71
frontend/rust-lib/flowy-ai/src/entities.rs
Normal file
71
frontend/rust-lib/flowy-ai/src/entities.rs
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
use flowy_error::ErrorCode;
|
||||||
|
|
||||||
|
/*
|
||||||
|
model="text-davinci-003",
|
||||||
|
prompt="Write a tagline for an ice cream shop."
|
||||||
|
*/
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct TextCompletionPayloadPB {
|
||||||
|
pub request_id: String,
|
||||||
|
|
||||||
|
// Model: Either text-davinci-003 or gpt-3.5-turbo
|
||||||
|
pub model: String,
|
||||||
|
|
||||||
|
// Prompt to query gpt
|
||||||
|
pub prompt: String,
|
||||||
|
|
||||||
|
// User open_ai_key for authentication
|
||||||
|
pub open_ai_key: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct TextCompletionParams {
|
||||||
|
pub request_id: String,
|
||||||
|
pub model: String,
|
||||||
|
pub prompt: String,
|
||||||
|
pub open_ai_key: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryInto<TextCompletionParams> for TextCompletionPayloadPB {
|
||||||
|
type Error = ErrorCode;
|
||||||
|
fn try_into(self) -> Result<TextCompletionParams, Self::Error> {
|
||||||
|
Ok(TextCompletionParams {
|
||||||
|
request_id: self.request_id,
|
||||||
|
model: self.model,
|
||||||
|
prompt: self.prompt,
|
||||||
|
open_ai_key: self.open_ai_key,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
{
|
||||||
|
"id": "chatcmpl-123",
|
||||||
|
"object": "chat.completion",
|
||||||
|
"created": 1677652288,
|
||||||
|
"model": "gpt-3.5-turbo-0613",
|
||||||
|
"choices": [{
|
||||||
|
"index": 0,
|
||||||
|
"message": {
|
||||||
|
"role": "assistant",
|
||||||
|
"content": "\n\nHello there, how may I assist you today?",
|
||||||
|
},
|
||||||
|
"finish_reason": "stop"
|
||||||
|
}],
|
||||||
|
"usage": {
|
||||||
|
"prompt_tokens": 9,
|
||||||
|
"completion_tokens": 12,
|
||||||
|
"total_tokens": 21
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*/
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct TextCompletionDataPB {
|
||||||
|
pub request_id: String,
|
||||||
|
|
||||||
|
pub model: String,
|
||||||
|
|
||||||
|
pub index: i32,
|
||||||
|
|
||||||
|
pub content: String,
|
||||||
|
}
|
71
frontend/rust-lib/flowy-ai/src/event_handler.rs
Normal file
71
frontend/rust-lib/flowy-ai/src/event_handler.rs
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
use crate::entities::{TextCompletionDataPB, TextCompletionParams, TextCompletionPayloadPB};
|
||||||
|
use flowy_error::FlowyError;
|
||||||
|
use lib_dispatch::prelude::{data_result_ok, AFPluginData, DataResult};
|
||||||
|
use reqwest;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
struct Message {
|
||||||
|
role: String,
|
||||||
|
content: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize)]
|
||||||
|
struct RequestBody {
|
||||||
|
model: String,
|
||||||
|
messages: Vec<Message>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
struct ResponseChoice {
|
||||||
|
index: i32,
|
||||||
|
message: Message,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
struct ApiResponse {
|
||||||
|
choices: Vec<ResponseChoice>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) async fn request_text_completion(
|
||||||
|
data: AFPluginData<TextCompletionPayloadPB>,
|
||||||
|
) -> DataResult<TextCompletionDataPB, FlowyError> {
|
||||||
|
// Set up the request body
|
||||||
|
let body = RequestBody {
|
||||||
|
model: "gpt-3.5-turbo".to_string(),
|
||||||
|
messages: vec![
|
||||||
|
Message {
|
||||||
|
role: "system".to_string(),
|
||||||
|
content: "You are a helpful assistant.".to_string(),
|
||||||
|
},
|
||||||
|
Message {
|
||||||
|
role: "user".to_string(),
|
||||||
|
content: data.prompt.to_string(),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
// Make the API call
|
||||||
|
let client = reqwest::Client::new();
|
||||||
|
let response: ApiResponse = client
|
||||||
|
.post("https://api.openai.com/v1/chat/completions")
|
||||||
|
.header("Content-Type", "application/json")
|
||||||
|
.header("Authorization", format!("Bearer {}", data.open_ai_key))
|
||||||
|
.json(&body)
|
||||||
|
.send()
|
||||||
|
.await?
|
||||||
|
.json()
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
// Extract index and content
|
||||||
|
let _choice = &response.choices[0];
|
||||||
|
|
||||||
|
let params: TextCompletionParams = data.into_inner().try_into()?;
|
||||||
|
|
||||||
|
data_result_ok(TextCompletionDataPB {
|
||||||
|
request_id: params.request_id,
|
||||||
|
model: params.model,
|
||||||
|
index: response.choices[0].index,
|
||||||
|
content: response.choices[0].message.content.to_string(),
|
||||||
|
})
|
||||||
|
}
|
18
frontend/rust-lib/flowy-ai/src/event_map.rs
Normal file
18
frontend/rust-lib/flowy-ai/src/event_map.rs
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
use flowy_derive::{Flowy_Event, ProtoBuf_Enum};
|
||||||
|
use lib_dispatch::prelude::AFPlugin;
|
||||||
|
use strum_macros::Display;
|
||||||
|
|
||||||
|
use crate::event_handler::request_text_completion;
|
||||||
|
|
||||||
|
pub fn init() -> AFPlugin {
|
||||||
|
AFPlugin::new()
|
||||||
|
.name(env!("CARGO_PKG_NAME"))
|
||||||
|
.event(OpenAIEvent::RequestTextCompletion, request_text_completion)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Hash, Display, ProtoBuf_Enum, Flowy_Event)]
|
||||||
|
#[event_err = "FlowyError"]
|
||||||
|
pub enum OpenAIEvent {
|
||||||
|
#[event(input = "TextCompletionPayloadPB", output = "TextCompletionDataPB")]
|
||||||
|
RequestTextCompletion = 0,
|
||||||
|
}
|
4
frontend/rust-lib/flowy-ai/src/lib.rs
Normal file
4
frontend/rust-lib/flowy-ai/src/lib.rs
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
// pub mod entities;
|
||||||
|
// pub mod event_handler;
|
||||||
|
// pub mod event_map;
|
||||||
|
// pub mod notification;
|
21
frontend/rust-lib/flowy-ai/src/notification.rs
Normal file
21
frontend/rust-lib/flowy-ai/src/notification.rs
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
use flowy_derive::ProtoBuf_Enum;
|
||||||
|
use flowy_notification::NotificationBuilder;
|
||||||
|
|
||||||
|
const OPEN_AI_NOTIFICATION: &str = "OpenAI";
|
||||||
|
|
||||||
|
#[derive(ProtoBuf_Enum, Debug, Default)]
|
||||||
|
pub(crate) enum OpenAINotification {
|
||||||
|
#[default]
|
||||||
|
Unknown = 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::convert::From<OpenAINotification> for i32 {
|
||||||
|
fn from(notification: OpenAINotification) -> Self {
|
||||||
|
notification as i32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub(crate) fn send_notification(id: &str, ty: OpenAINotification) -> NotificationBuilder {
|
||||||
|
NotificationBuilder::new(id, ty, OPEN_AI_NOTIFICATION)
|
||||||
|
}
|
@ -23,6 +23,7 @@ flowy-server = { workspace = true }
|
|||||||
flowy-server-config = { workspace = true }
|
flowy-server-config = { workspace = true }
|
||||||
flowy-config = { workspace = true }
|
flowy-config = { workspace = true }
|
||||||
collab-integrate = { workspace = true, features = ["supabase_integrate", "appflowy_cloud_integrate", "snapshot_plugin"] }
|
collab-integrate = { workspace = true, features = ["supabase_integrate", "appflowy_cloud_integrate", "snapshot_plugin"] }
|
||||||
|
flowy-ai = { workspace = true }
|
||||||
collab-define = { version = "0.1.0" }
|
collab-define = { version = "0.1.0" }
|
||||||
collab-plugins = { version = "0.1.0", features = ["sync_plugin"] }
|
collab-plugins = { version = "0.1.0", features = ["sync_plugin"] }
|
||||||
collab = { version = "0.1.0" }
|
collab = { version = "0.1.0" }
|
||||||
|
@ -70,6 +70,7 @@ pub async fn sync_user_data_to_cloud(
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
fn sync_views(
|
fn sync_views(
|
||||||
uid: i64,
|
uid: i64,
|
||||||
folder: Arc<MutexFolder>,
|
folder: Arc<MutexFolder>,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user