mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2025-12-25 06:05:47 +00:00
chore: select message
This commit is contained in:
parent
98b835227e
commit
af91a72187
1
frontend/rust-lib/Cargo.lock
generated
1
frontend/rust-lib/Cargo.lock
generated
@ -2564,6 +2564,7 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"client-api",
|
||||
"flowy-error",
|
||||
"flowy-sqlite",
|
||||
"futures",
|
||||
"lib-infra",
|
||||
"serde",
|
||||
|
||||
@ -12,4 +12,5 @@ client-api = { workspace = true }
|
||||
futures.workspace = true
|
||||
serde_json.workspace = true
|
||||
serde.workspace = true
|
||||
uuid.workspace = true
|
||||
uuid.workspace = true
|
||||
flowy-sqlite = { workspace = true }
|
||||
@ -85,6 +85,8 @@ pub trait ChatCloudService: Send + Sync + 'static {
|
||||
workspace_id: &Uuid,
|
||||
chat_id: &Uuid,
|
||||
rag_ids: Vec<Uuid>,
|
||||
name: &str,
|
||||
metadata: serde_json::Value,
|
||||
) -> Result<(), FlowyError>;
|
||||
|
||||
async fn create_question(
|
||||
|
||||
@ -1 +1,2 @@
|
||||
pub mod cloud;
|
||||
pub mod persistence;
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
use crate::cloud::MessageCursor;
|
||||
use flowy_error::{FlowyError, FlowyResult};
|
||||
use flowy_sqlite::upsert::excluded;
|
||||
use flowy_sqlite::{
|
||||
@ -51,19 +52,25 @@ pub fn select_chat_messages(
|
||||
mut conn: DBConnection,
|
||||
chat_id_val: &str,
|
||||
limit_val: i64,
|
||||
after_message_id: Option<i64>,
|
||||
before_message_id: Option<i64>,
|
||||
offset: MessageCursor,
|
||||
) -> QueryResult<Vec<ChatMessageTable>> {
|
||||
let mut query = dsl::chat_message_table
|
||||
.filter(chat_message_table::chat_id.eq(chat_id_val))
|
||||
.into_boxed();
|
||||
if let Some(after_message_id) = after_message_id {
|
||||
query = query.filter(chat_message_table::message_id.gt(after_message_id));
|
||||
|
||||
match offset {
|
||||
MessageCursor::AfterMessageId(after_message_id) => {
|
||||
query = query.filter(chat_message_table::message_id.gt(after_message_id));
|
||||
},
|
||||
MessageCursor::BeforeMessageId(before_message_id) => {
|
||||
query = query.filter(chat_message_table::message_id.lt(before_message_id));
|
||||
},
|
||||
MessageCursor::Offset(offset_val) => {
|
||||
query = query.offset(offset_val as i64);
|
||||
},
|
||||
MessageCursor::NextBack => {},
|
||||
}
|
||||
|
||||
if let Some(before_message_id) = before_message_id {
|
||||
query = query.filter(chat_message_table::message_id.lt(before_message_id));
|
||||
}
|
||||
query = query
|
||||
.order((
|
||||
chat_message_table::created_at.desc(),
|
||||
@ -75,7 +82,7 @@ pub fn select_chat_messages(
|
||||
Ok(messages)
|
||||
}
|
||||
|
||||
pub fn select_single_message(
|
||||
pub fn select_message(
|
||||
mut conn: DBConnection,
|
||||
message_id_val: i64,
|
||||
) -> QueryResult<Option<ChatMessageTable>> {
|
||||
@ -86,6 +93,18 @@ pub fn select_single_message(
|
||||
Ok(message)
|
||||
}
|
||||
|
||||
pub fn select_message_content(
|
||||
mut conn: DBConnection,
|
||||
message_id_val: i64,
|
||||
) -> QueryResult<Option<String>> {
|
||||
let message = dsl::chat_message_table
|
||||
.filter(chat_message_table::message_id.eq(message_id_val))
|
||||
.select(chat_message_table::content)
|
||||
.first::<String>(&mut *conn)
|
||||
.optional()?;
|
||||
Ok(message)
|
||||
}
|
||||
|
||||
pub fn select_message_where_match_reply_message_id(
|
||||
mut conn: DBConnection,
|
||||
answer_message_id_val: i64,
|
||||
@ -16,10 +16,8 @@ pub struct ChatTable {
|
||||
pub chat_id: String,
|
||||
pub created_at: i64,
|
||||
pub name: String,
|
||||
pub local_files: String,
|
||||
pub metadata: String,
|
||||
pub local_enabled: bool,
|
||||
pub sync_to_cloud: bool,
|
||||
pub rag_ids: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
|
||||
@ -49,22 +47,57 @@ pub struct ChatTableFile {
|
||||
pub struct ChatTableChangeset {
|
||||
pub chat_id: String,
|
||||
pub name: Option<String>,
|
||||
pub local_files: Option<String>,
|
||||
pub metadata: Option<String>,
|
||||
pub local_enabled: Option<bool>,
|
||||
pub sync_to_cloud: Option<bool>,
|
||||
pub rag_ids: Option<String>,
|
||||
}
|
||||
|
||||
impl ChatTableChangeset {
|
||||
pub fn from_metadata(metadata: ChatTableMetadata) -> Self {
|
||||
ChatTableChangeset {
|
||||
chat_id: Default::default(),
|
||||
metadata: serde_json::to_string(&metadata).ok(),
|
||||
..Default::default()
|
||||
name: None,
|
||||
rag_ids: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_rag_ids(rag_ids: Vec<String>) -> Self {
|
||||
ChatTableChangeset {
|
||||
chat_id: Default::default(),
|
||||
// Serialize the Vec<String> to a JSON array string
|
||||
rag_ids: Some(serde_json::to_string(&rag_ids).unwrap_or_default()),
|
||||
name: None,
|
||||
metadata: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn insert_chat(mut conn: DBConnection, new_chat: &ChatTable) -> QueryResult<usize> {
|
||||
pub fn serialize_rag_ids(rag_ids: &[String]) -> String {
|
||||
serde_json::to_string(rag_ids).unwrap_or_default()
|
||||
}
|
||||
|
||||
pub fn deserialize_rag_ids(rag_ids_str: &Option<String>) -> Vec<String> {
|
||||
match rag_ids_str {
|
||||
Some(str) => serde_json::from_str(str).unwrap_or_default(),
|
||||
None => Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn deserialize_chat_metadata<T>(metadata: &str) -> T
|
||||
where
|
||||
T: serde::de::DeserializeOwned + Default,
|
||||
{
|
||||
serde_json::from_str(metadata).unwrap_or_default()
|
||||
}
|
||||
|
||||
pub fn serialize_chat_metadata<T>(metadata: &T) -> String
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
serde_json::to_string(metadata).unwrap_or_default()
|
||||
}
|
||||
|
||||
pub fn upsert_chat(mut conn: DBConnection, new_chat: &ChatTable) -> QueryResult<usize> {
|
||||
diesel::insert_into(chat_table::table)
|
||||
.values(new_chat)
|
||||
.on_conflict(chat_table::chat_id)
|
||||
@ -72,6 +105,8 @@ pub fn insert_chat(mut conn: DBConnection, new_chat: &ChatTable) -> QueryResult<
|
||||
.set((
|
||||
chat_table::created_at.eq(excluded(chat_table::created_at)),
|
||||
chat_table::name.eq(excluded(chat_table::name)),
|
||||
chat_table::metadata.eq(excluded(chat_table::metadata)),
|
||||
chat_table::rag_ids.eq(excluded(chat_table::rag_ids)),
|
||||
))
|
||||
.execute(&mut *conn)
|
||||
}
|
||||
@ -85,7 +120,6 @@ pub fn update_chat(
|
||||
Ok(affected_row)
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn read_chat(mut conn: DBConnection, chat_id_val: &str) -> QueryResult<ChatTable> {
|
||||
let row = dsl::chat_table
|
||||
.filter(chat_table::chat_id.eq(chat_id_val))
|
||||
@ -93,7 +127,17 @@ pub fn read_chat(mut conn: DBConnection, chat_id_val: &str) -> QueryResult<ChatT
|
||||
Ok(row)
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn read_chat_rag_ids(
|
||||
conn: &mut SqliteConnection,
|
||||
chat_id_val: &str,
|
||||
) -> FlowyResult<Vec<String>> {
|
||||
let chat = dsl::chat_table
|
||||
.filter(chat_table::chat_id.eq(chat_id_val))
|
||||
.first::<ChatTable>(conn)?;
|
||||
|
||||
Ok(deserialize_rag_ids(&chat.rag_ids))
|
||||
}
|
||||
|
||||
pub fn read_chat_metadata(
|
||||
conn: &mut SqliteConnection,
|
||||
chat_id_val: &str,
|
||||
@ -102,8 +146,7 @@ pub fn read_chat_metadata(
|
||||
.select(chat_table::metadata)
|
||||
.filter(chat_table::chat_id.eq(chat_id_val))
|
||||
.first::<String>(&mut *conn)?;
|
||||
let value = serde_json::from_str(&metadata_str).unwrap_or_default();
|
||||
Ok(value)
|
||||
Ok(deserialize_chat_metadata(&metadata_str))
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
@ -5,7 +5,9 @@ use crate::entities::{
|
||||
};
|
||||
use crate::local_ai::controller::{LocalAIController, LocalAISetting};
|
||||
use crate::middleware::chat_service_mw::AICloudServiceMiddleware;
|
||||
use crate::persistence::{insert_chat, read_chat_metadata, ChatTable};
|
||||
use flowy_ai_pub::persistence::{
|
||||
read_chat_metadata, serialize_chat_metadata, serialize_rag_ids, upsert_chat, ChatTable,
|
||||
};
|
||||
use std::collections::HashMap;
|
||||
|
||||
use dashmap::DashMap;
|
||||
@ -25,6 +27,7 @@ use flowy_ai_pub::cloud::ai_dto::AvailableModel;
|
||||
use flowy_storage_pub::storage::StorageService;
|
||||
use lib_infra::async_trait::async_trait;
|
||||
use lib_infra::util::timestamp;
|
||||
use serde_json::json;
|
||||
use std::path::PathBuf;
|
||||
use std::str::FromStr;
|
||||
use std::sync::{Arc, Weak};
|
||||
@ -221,11 +224,17 @@ impl AIManager {
|
||||
.unwrap_or_default();
|
||||
info!("[Chat] create chat with rag_ids: {:?}", rag_ids);
|
||||
|
||||
save_chat(
|
||||
self.user_service.sqlite_connection(*uid)?,
|
||||
chat_id,
|
||||
"",
|
||||
rag_ids.iter().map(|v| v.to_string()).collect(),
|
||||
json!({}),
|
||||
)?;
|
||||
self
|
||||
.cloud_service_wm
|
||||
.create_chat(uid, &workspace_id, chat_id, rag_ids)
|
||||
.create_chat(uid, &workspace_id, chat_id, rag_ids, "", json!({}))
|
||||
.await?;
|
||||
save_chat(self.user_service.sqlite_connection(*uid)?, chat_id)?;
|
||||
|
||||
let chat = Arc::new(Chat::new(
|
||||
self.user_service.user_id()?,
|
||||
@ -705,18 +714,22 @@ async fn sync_chat_documents(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn save_chat(conn: DBConnection, chat_id: &Uuid) -> FlowyResult<()> {
|
||||
fn save_chat(
|
||||
conn: DBConnection,
|
||||
chat_id: &Uuid,
|
||||
name: &str,
|
||||
rag_ids: Vec<String>,
|
||||
metadata: serde_json::Value,
|
||||
) -> FlowyResult<()> {
|
||||
let row = ChatTable {
|
||||
chat_id: chat_id.to_string(),
|
||||
created_at: timestamp(),
|
||||
name: "".to_string(),
|
||||
local_files: "".to_string(),
|
||||
metadata: "".to_string(),
|
||||
local_enabled: false,
|
||||
sync_to_cloud: false,
|
||||
name: name.to_string(),
|
||||
metadata: serialize_chat_metadata(&metadata),
|
||||
rag_ids: Some(serialize_rag_ids(&rag_ids)),
|
||||
};
|
||||
|
||||
insert_chat(conn, &row)?;
|
||||
upsert_chat(conn, &row)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
@ -5,15 +5,15 @@ use crate::entities::{
|
||||
};
|
||||
use crate::middleware::chat_service_mw::AICloudServiceMiddleware;
|
||||
use crate::notification::{chat_notification_builder, ChatNotification};
|
||||
use crate::persistence::{
|
||||
insert_chat_messages, select_chat_messages, select_message_where_match_reply_message_id,
|
||||
ChatMessageTable,
|
||||
};
|
||||
use crate::stream_message::StreamMessage;
|
||||
use allo_isolate::Isolate;
|
||||
use flowy_ai_pub::cloud::{
|
||||
AIModel, ChatCloudService, ChatMessage, MessageCursor, QuestionStreamValue, ResponseFormat,
|
||||
};
|
||||
use flowy_ai_pub::persistence::{
|
||||
insert_chat_messages, select_chat_messages, select_message_where_match_reply_message_id,
|
||||
ChatMessageTable,
|
||||
};
|
||||
use flowy_error::{ErrorCode, FlowyError, FlowyResult};
|
||||
use flowy_sqlite::DBConnection;
|
||||
use futures::{SinkExt, StreamExt};
|
||||
@ -349,9 +349,9 @@ impl Chat {
|
||||
limit,
|
||||
before_message_id
|
||||
);
|
||||
let messages = self
|
||||
.load_local_chat_messages(limit, None, before_message_id)
|
||||
.await?;
|
||||
|
||||
let offset = before_message_id.map_or(MessageCursor::NextBack, MessageCursor::BeforeMessageId);
|
||||
let messages = self.load_local_chat_messages(limit, offset).await?;
|
||||
|
||||
// If the number of messages equals the limit, then no need to load more messages from remote
|
||||
if messages.len() == limit as usize {
|
||||
@ -397,9 +397,8 @@ impl Chat {
|
||||
limit,
|
||||
after_message_id,
|
||||
);
|
||||
let messages = self
|
||||
.load_local_chat_messages(limit, after_message_id, None)
|
||||
.await?;
|
||||
let offset = after_message_id.map_or(MessageCursor::NextBack, MessageCursor::AfterMessageId);
|
||||
let messages = self.load_local_chat_messages(limit, offset).await?;
|
||||
|
||||
trace!(
|
||||
"[Chat] Loaded local chat messages: chat_id={}, messages={}",
|
||||
@ -562,17 +561,10 @@ impl Chat {
|
||||
async fn load_local_chat_messages(
|
||||
&self,
|
||||
limit: i64,
|
||||
after_message_id: Option<i64>,
|
||||
before_message_id: Option<i64>,
|
||||
offset: MessageCursor,
|
||||
) -> Result<Vec<ChatMessagePB>, FlowyError> {
|
||||
let conn = self.user_service.sqlite_connection(self.uid)?;
|
||||
let records = select_chat_messages(
|
||||
conn,
|
||||
&self.chat_id.to_string(),
|
||||
limit,
|
||||
after_message_id,
|
||||
before_message_id,
|
||||
)?;
|
||||
let records = select_chat_messages(conn, &self.chat_id.to_string(), limit, offset)?;
|
||||
let messages = records
|
||||
.into_iter()
|
||||
.map(|record| ChatMessagePB {
|
||||
|
||||
@ -12,7 +12,6 @@ pub mod local_ai;
|
||||
|
||||
mod middleware;
|
||||
pub mod notification;
|
||||
mod persistence;
|
||||
mod protobuf;
|
||||
mod stream_message;
|
||||
mod util;
|
||||
|
||||
@ -4,8 +4,8 @@ use crate::local_ai::controller::LocalAIController;
|
||||
use crate::notification::{
|
||||
chat_notification_builder, ChatNotification, APPFLOWY_AI_NOTIFICATION_KEY,
|
||||
};
|
||||
use crate::persistence::{select_single_message, ChatMessageTable};
|
||||
use af_plugin::error::PluginError;
|
||||
use flowy_ai_pub::persistence::{select_message, select_message_content, ChatMessageTable};
|
||||
use std::collections::HashMap;
|
||||
|
||||
use flowy_ai_pub::cloud::{
|
||||
@ -78,14 +78,13 @@ impl AICloudServiceMiddleware {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_message_record(&self, message_id: i64) -> FlowyResult<ChatMessageTable> {
|
||||
fn get_message_content(&self, message_id: i64) -> FlowyResult<String> {
|
||||
let uid = self.user_service.user_id()?;
|
||||
let conn = self.user_service.sqlite_connection(uid)?;
|
||||
let row = select_single_message(conn, message_id)?.ok_or_else(|| {
|
||||
let content = select_message_content(conn, message_id)?.ok_or_else(|| {
|
||||
FlowyError::record_not_found().with_context(format!("Message not found: {}", message_id))
|
||||
})?;
|
||||
|
||||
Ok(row)
|
||||
Ok(content)
|
||||
}
|
||||
|
||||
fn handle_plugin_error(&self, err: PluginError) {
|
||||
@ -114,10 +113,12 @@ impl ChatCloudService for AICloudServiceMiddleware {
|
||||
workspace_id: &Uuid,
|
||||
chat_id: &Uuid,
|
||||
rag_ids: Vec<Uuid>,
|
||||
name: &str,
|
||||
metadata: serde_json::Value,
|
||||
) -> Result<(), FlowyError> {
|
||||
self
|
||||
.cloud_service
|
||||
.create_chat(uid, workspace_id, chat_id, rag_ids)
|
||||
.create_chat(uid, workspace_id, chat_id, rag_ids, name, metadata)
|
||||
.await
|
||||
}
|
||||
|
||||
@ -165,12 +166,12 @@ impl ChatCloudService for AICloudServiceMiddleware {
|
||||
info!("stream_answer use model: {:?}", ai_model);
|
||||
if use_local_ai {
|
||||
if self.local_ai.is_running() {
|
||||
let row = self.get_message_record(message_id)?;
|
||||
let content = self.get_message_content(message_id)?;
|
||||
match self
|
||||
.local_ai
|
||||
.stream_question(
|
||||
&chat_id.to_string(),
|
||||
&row.content,
|
||||
&content,
|
||||
Some(json!(format)),
|
||||
json!({}),
|
||||
)
|
||||
@ -202,7 +203,7 @@ impl ChatCloudService for AICloudServiceMiddleware {
|
||||
question_message_id: i64,
|
||||
) -> Result<ChatMessage, FlowyError> {
|
||||
if self.local_ai.is_running() {
|
||||
let content = self.get_message_record(question_message_id)?.content;
|
||||
let content = self.get_message_content(question_message_id)?;
|
||||
match self
|
||||
.local_ai
|
||||
.ask_question(&chat_id.to_string(), &content)
|
||||
|
||||
@ -667,11 +667,13 @@ impl ChatCloudService for ServerProvider {
|
||||
workspace_id: &Uuid,
|
||||
chat_id: &Uuid,
|
||||
rag_ids: Vec<Uuid>,
|
||||
name: &str,
|
||||
metadata: serde_json::Value,
|
||||
) -> Result<(), FlowyError> {
|
||||
let server = self.get_server();
|
||||
server?
|
||||
.chat_service()
|
||||
.create_chat(uid, workspace_id, chat_id, rag_ids)
|
||||
.create_chat(uid, workspace_id, chat_id, rag_ids, name, metadata)
|
||||
.await
|
||||
}
|
||||
|
||||
|
||||
@ -128,7 +128,7 @@ impl ServerProvider {
|
||||
|
||||
let server = match server_type {
|
||||
Server::Local => {
|
||||
let server = Arc::new(LocalServer::new(self.user.clone()));
|
||||
let server = Arc::new(LocalServer::new(self.user.clone(), self.local_ai.clone()));
|
||||
Ok::<Arc<dyn AppFlowyServer>, FlowyError>(server)
|
||||
},
|
||||
Server::AppFlowyCloud => {
|
||||
|
||||
@ -35,12 +35,14 @@ where
|
||||
workspace_id: &Uuid,
|
||||
chat_id: &Uuid,
|
||||
rag_ids: Vec<Uuid>,
|
||||
name: &str,
|
||||
metadata: serde_json::Value,
|
||||
) -> Result<(), FlowyError> {
|
||||
let chat_id = chat_id.to_string();
|
||||
let try_get_client = self.inner.try_get_client();
|
||||
let params = CreateChatParams {
|
||||
chat_id,
|
||||
name: "".to_string(),
|
||||
name: name.to_string(),
|
||||
rag_ids,
|
||||
};
|
||||
try_get_client?
|
||||
|
||||
@ -1,14 +1,22 @@
|
||||
use crate::af_cloud::define::ServerUser;
|
||||
use client_api::entity::ai_dto::RepeatedRelatedQuestion;
|
||||
use flowy_ai::local_ai::controller::LocalAIController;
|
||||
use flowy_ai::local_ai::stream_util::QuestionStream;
|
||||
use flowy_ai_pub::cloud::{
|
||||
AIModel, ChatCloudService, ChatMessage, ChatMessageMetadata, ChatMessageType, ChatSettings,
|
||||
CompleteTextParams, MessageCursor, ModelList, RepeatedChatMessage, ResponseFormat, StreamAnswer,
|
||||
StreamComplete, SubscriptionPlan, UpdateChatParams,
|
||||
};
|
||||
use flowy_error::FlowyError;
|
||||
use flowy_ai_pub::persistence::{
|
||||
deserialize_chat_metadata, deserialize_rag_ids, read_chat, select_message_content,
|
||||
serialize_chat_metadata, serialize_rag_ids, update_chat, upsert_chat, ChatTable,
|
||||
ChatTableChangeset,
|
||||
};
|
||||
use flowy_error::{FlowyError, FlowyResult};
|
||||
use futures_util::{stream, FutureExt, StreamExt};
|
||||
use lib_infra::async_trait::async_trait;
|
||||
use lib_infra::util::timestamp;
|
||||
use serde_json::Value;
|
||||
use serde_json::{json, Value};
|
||||
use std::collections::HashMap;
|
||||
use std::path::Path;
|
||||
use std::sync::Arc;
|
||||
@ -16,6 +24,18 @@ use uuid::Uuid;
|
||||
|
||||
pub struct LocalServerChatServiceImpl {
|
||||
pub user: Arc<dyn ServerUser>,
|
||||
pub local_ai: Arc<LocalAIController>,
|
||||
}
|
||||
|
||||
impl LocalServerChatServiceImpl {
|
||||
fn get_message_content(&self, message_id: i64) -> FlowyResult<String> {
|
||||
let uid = self.user.user_id()?;
|
||||
let db = self.user.get_sqlite_db(uid)?;
|
||||
let content = select_message_content(db, message_id)?.ok_or_else(|| {
|
||||
FlowyError::record_not_found().with_context(format!("Message not found: {}", message_id))
|
||||
})?;
|
||||
Ok(content)
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
@ -24,9 +44,28 @@ impl ChatCloudService for LocalServerChatServiceImpl {
|
||||
&self,
|
||||
_uid: &i64,
|
||||
_workspace_id: &Uuid,
|
||||
_chat_id: &Uuid,
|
||||
_rag_ids: Vec<Uuid>,
|
||||
chat_id: &Uuid,
|
||||
rag_ids: Vec<Uuid>,
|
||||
name: &str,
|
||||
metadata: Value,
|
||||
) -> Result<(), FlowyError> {
|
||||
let uid = self.user.user_id()?;
|
||||
let db = self.user.get_sqlite_db(uid)?;
|
||||
|
||||
let rag_ids = rag_ids
|
||||
.iter()
|
||||
.map(|v| v.to_string())
|
||||
.collect::<Vec<String>>();
|
||||
|
||||
let row = ChatTable {
|
||||
chat_id: chat_id.to_string(),
|
||||
created_at: timestamp(),
|
||||
name: name.to_string(),
|
||||
metadata: serialize_chat_metadata(&metadata),
|
||||
rag_ids: Some(serialize_rag_ids(&rag_ids)),
|
||||
};
|
||||
|
||||
upsert_chat(db, &row)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -66,21 +105,52 @@ impl ChatCloudService for LocalServerChatServiceImpl {
|
||||
async fn stream_answer(
|
||||
&self,
|
||||
_workspace_id: &Uuid,
|
||||
_chat_id: &Uuid,
|
||||
_message_id: i64,
|
||||
_format: ResponseFormat,
|
||||
chat_id: &Uuid,
|
||||
message_id: i64,
|
||||
format: ResponseFormat,
|
||||
_ai_model: Option<AIModel>,
|
||||
) -> Result<StreamAnswer, FlowyError> {
|
||||
if self.local_ai.is_running() {
|
||||
let content = self.get_message_content(message_id)?;
|
||||
match self
|
||||
.local_ai
|
||||
.stream_question(
|
||||
&chat_id.to_string(),
|
||||
&content,
|
||||
Some(json!(format)),
|
||||
json!({}),
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(stream) => Ok(QuestionStream::new(stream).boxed()),
|
||||
Err(err) => Ok(
|
||||
stream::once(async { Err(FlowyError::local_ai_unavailable().with_context(err)) }).boxed(),
|
||||
),
|
||||
}
|
||||
} else {
|
||||
Err(FlowyError::local_ai_not_ready())
|
||||
}
|
||||
}
|
||||
|
||||
async fn get_answer(
|
||||
&self,
|
||||
_workspace_id: &Uuid,
|
||||
_chat_id: &Uuid,
|
||||
_question_message_id: i64,
|
||||
) -> Result<ChatMessage, FlowyError> {
|
||||
Err(FlowyError::not_support().with_context("Chat is not supported in local server."))
|
||||
}
|
||||
|
||||
async fn get_chat_messages(
|
||||
&self,
|
||||
_workspace_id: &Uuid,
|
||||
_chat_id: &Uuid,
|
||||
_offset: MessageCursor,
|
||||
_limit: u64,
|
||||
chat_id: &Uuid,
|
||||
offset: MessageCursor,
|
||||
limit: u64,
|
||||
) -> Result<RepeatedChatMessage, FlowyError> {
|
||||
let uid = self.user.user_id()?;
|
||||
let db = self.user.get_sqlite_db(uid)?;
|
||||
|
||||
Err(FlowyError::not_support().with_context("Chat is not supported in local server."))
|
||||
}
|
||||
|
||||
@ -106,15 +176,6 @@ impl ChatCloudService for LocalServerChatServiceImpl {
|
||||
})
|
||||
}
|
||||
|
||||
async fn get_answer(
|
||||
&self,
|
||||
_workspace_id: &Uuid,
|
||||
_chat_id: &Uuid,
|
||||
_question_message_id: i64,
|
||||
) -> Result<ChatMessage, FlowyError> {
|
||||
Err(FlowyError::not_support().with_context("Chat is not supported in local server."))
|
||||
}
|
||||
|
||||
async fn stream_complete(
|
||||
&self,
|
||||
_workspace_id: &Uuid,
|
||||
@ -137,18 +198,40 @@ impl ChatCloudService for LocalServerChatServiceImpl {
|
||||
async fn get_chat_settings(
|
||||
&self,
|
||||
_workspace_id: &Uuid,
|
||||
_chat_id: &Uuid,
|
||||
chat_id: &Uuid,
|
||||
) -> Result<ChatSettings, FlowyError> {
|
||||
Err(FlowyError::not_support().with_context("Chat is not supported in local server."))
|
||||
let chat_id = chat_id.to_string();
|
||||
let uid = self.user.user_id()?;
|
||||
let db = self.user.get_sqlite_db(uid)?;
|
||||
let row = read_chat(db, &chat_id)?;
|
||||
let rag_ids = deserialize_rag_ids(&row.rag_ids);
|
||||
let metadata = deserialize_chat_metadata::<serde_json::Value>(&row.metadata);
|
||||
let setting = ChatSettings {
|
||||
name: row.name,
|
||||
rag_ids,
|
||||
metadata,
|
||||
};
|
||||
|
||||
Ok(setting)
|
||||
}
|
||||
|
||||
async fn update_chat_settings(
|
||||
&self,
|
||||
_workspace_id: &Uuid,
|
||||
_id: &Uuid,
|
||||
_s: UpdateChatParams,
|
||||
id: &Uuid,
|
||||
s: UpdateChatParams,
|
||||
) -> Result<(), FlowyError> {
|
||||
Err(FlowyError::not_support().with_context("Chat is not supported in local server."))
|
||||
let uid = self.user.user_id()?;
|
||||
let mut db = self.user.get_sqlite_db(uid)?;
|
||||
let changeset = ChatTableChangeset {
|
||||
chat_id: id.to_string(),
|
||||
name: s.name,
|
||||
metadata: s.metadata.map(|s| serialize_chat_metadata(&s)),
|
||||
rag_ids: s.rag_ids.map(|s| serialize_rag_ids(&s)),
|
||||
};
|
||||
|
||||
update_chat(&mut db, changeset)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn get_available_models(&self, _workspace_id: &Uuid) -> Result<ModelList, FlowyError> {
|
||||
|
||||
@ -8,6 +8,7 @@ use crate::local_server::impls::{
|
||||
LocalServerUserServiceImpl,
|
||||
};
|
||||
use crate::AppFlowyServer;
|
||||
use flowy_ai::local_ai::controller::LocalAIController;
|
||||
use flowy_ai_pub::cloud::ChatCloudService;
|
||||
use flowy_database_pub::cloud::{DatabaseAIService, DatabaseCloudService};
|
||||
use flowy_document_pub::cloud::DocumentCloudService;
|
||||
@ -18,13 +19,15 @@ use tokio::sync::mpsc;
|
||||
|
||||
pub struct LocalServer {
|
||||
user: Arc<dyn ServerUser>,
|
||||
local_ai: Arc<LocalAIController>,
|
||||
stop_tx: Option<mpsc::Sender<()>>,
|
||||
}
|
||||
|
||||
impl LocalServer {
|
||||
pub fn new(user: Arc<dyn ServerUser>) -> Self {
|
||||
pub fn new(user: Arc<dyn ServerUser>, local_ai: Arc<LocalAIController>) -> Self {
|
||||
Self {
|
||||
user,
|
||||
local_ai,
|
||||
stop_tx: Default::default(),
|
||||
}
|
||||
}
|
||||
@ -61,6 +64,7 @@ impl AppFlowyServer for LocalServer {
|
||||
fn chat_service(&self) -> Arc<dyn ChatCloudService> {
|
||||
Arc::new(LocalServerChatServiceImpl {
|
||||
user: self.user.clone(),
|
||||
local_ai: self.local_ai.clone(),
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@ -0,0 +1,9 @@
|
||||
-- This file should undo anything in `up.sql`
|
||||
ALTER TABLE chat_table
|
||||
ADD COLUMN local_enabled INTEGER;
|
||||
ALTER TABLE chat_table
|
||||
ADD COLUMN sync_to_cloud INTEGER;
|
||||
ALTER TABLE chat_table
|
||||
ADD COLUMN local_files TEXT;
|
||||
|
||||
ALTER TABLE chat_table DROP COLUMN rag_ids;
|
||||
@ -0,0 +1,4 @@
|
||||
ALTER TABLE chat_table DROP COLUMN local_enabled;
|
||||
ALTER TABLE chat_table DROP COLUMN local_files;
|
||||
ALTER TABLE chat_table DROP COLUMN sync_to_cloud;
|
||||
ALTER TABLE chat_table ADD COLUMN rag_ids TEXT;
|
||||
@ -35,10 +35,8 @@ diesel::table! {
|
||||
chat_id -> Text,
|
||||
created_at -> BigInt,
|
||||
name -> Text,
|
||||
local_files -> Text,
|
||||
metadata -> Text,
|
||||
local_enabled -> Bool,
|
||||
sync_to_cloud -> Bool,
|
||||
rag_ids -> Nullable<Text>,
|
||||
}
|
||||
}
|
||||
|
||||
@ -128,15 +126,15 @@ diesel::table! {
|
||||
}
|
||||
|
||||
diesel::allow_tables_to_appear_in_same_query!(
|
||||
af_collab_metadata,
|
||||
chat_local_setting_table,
|
||||
chat_message_table,
|
||||
chat_table,
|
||||
collab_snapshot,
|
||||
upload_file_part,
|
||||
upload_file_table,
|
||||
user_data_migration_records,
|
||||
user_table,
|
||||
user_workspace_table,
|
||||
workspace_members_table,
|
||||
af_collab_metadata,
|
||||
chat_local_setting_table,
|
||||
chat_message_table,
|
||||
chat_table,
|
||||
collab_snapshot,
|
||||
upload_file_part,
|
||||
upload_file_table,
|
||||
user_data_migration_records,
|
||||
user_table,
|
||||
user_workspace_table,
|
||||
workspace_members_table,
|
||||
);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user