diff --git a/crates/index-scheduler/src/features.rs b/crates/index-scheduler/src/features.rs index 109e6b867..78ffc0766 100644 --- a/crates/index-scheduler/src/features.rs +++ b/crates/index-scheduler/src/features.rs @@ -131,6 +131,19 @@ impl RoFeatures { .into()) } } + + pub fn check_chat_completions(&self, disabled_action: &'static str) -> Result<()> { + if self.runtime.chat_completions { + Ok(()) + } else { + Err(FeatureNotEnabledError { + disabled_action, + feature: "chat completions", + issue_link: "https://github.com/orgs/meilisearch/discussions/835", + } + .into()) + } + } } impl FeatureData { diff --git a/crates/meilisearch-types/src/features.rs b/crates/meilisearch-types/src/features.rs index f12cbcfc9..10c39e09c 100644 --- a/crates/meilisearch-types/src/features.rs +++ b/crates/meilisearch-types/src/features.rs @@ -19,6 +19,7 @@ pub struct RuntimeTogglableFeatures { pub network: bool, pub get_task_documents_route: bool, pub composite_embedders: bool, + pub chat_completions: bool, } #[derive(Default, Debug, Clone, Copy)] diff --git a/crates/meilisearch/src/analytics/segment_analytics.rs b/crates/meilisearch/src/analytics/segment_analytics.rs index ee8a9ee20..c7e0634f4 100644 --- a/crates/meilisearch/src/analytics/segment_analytics.rs +++ b/crates/meilisearch/src/analytics/segment_analytics.rs @@ -197,6 +197,7 @@ struct Infos { experimental_max_number_of_batched_tasks: usize, experimental_limit_batched_tasks_total_size: u64, experimental_network: bool, + experimental_chat_completions: bool, experimental_get_task_documents_route: bool, experimental_composite_embedders: bool, experimental_embedding_cache_entries: usize, @@ -296,6 +297,7 @@ impl Infos { network, get_task_documents_route, composite_embedders, + chat_completions, } = features; // We're going to override every sensible information. @@ -314,6 +316,7 @@ impl Infos { experimental_enable_logs_route: experimental_enable_logs_route | logs_route, experimental_reduce_indexing_memory_usage, experimental_network: network, + experimental_chat_completions: chat_completions, experimental_get_task_documents_route: get_task_documents_route, experimental_composite_embedders: composite_embedders, experimental_embedding_cache_entries, diff --git a/crates/meilisearch/src/routes/chats/chat_completions.rs b/crates/meilisearch/src/routes/chats/chat_completions.rs index a923d2ff9..c82e29524 100644 --- a/crates/meilisearch/src/routes/chats/chat_completions.rs +++ b/crates/meilisearch/src/routes/chats/chat_completions.rs @@ -74,9 +74,6 @@ async fn chat( search_queue: web::Data, web::Json(chat_completion): web::Json, ) -> impl Responder { - // To enable later on, when the feature will be experimental - // index_scheduler.features().check_chat("Using the /chat route")?; - let ChatsParam { workspace_uid } = chats_param.into_inner(); assert_eq!( @@ -317,6 +314,7 @@ async fn non_streamed_chat( req: HttpRequest, mut chat_completion: CreateChatCompletionRequest, ) -> Result { + index_scheduler.features().check_chat_completions("Using the /chats chat completions route")?; let filters = index_scheduler.filters(); let rtxn = index_scheduler.read_txn()?; @@ -414,6 +412,7 @@ async fn streamed_chat( req: HttpRequest, mut chat_completion: CreateChatCompletionRequest, ) -> Result { + index_scheduler.features().check_chat_completions("Using the /chats chat completions route")?; let filters = index_scheduler.filters(); let rtxn = index_scheduler.read_txn()?; diff --git a/crates/meilisearch/src/routes/chats/mod.rs b/crates/meilisearch/src/routes/chats/mod.rs index 86feb14aa..0fa0d54b4 100644 --- a/crates/meilisearch/src/routes/chats/mod.rs +++ b/crates/meilisearch/src/routes/chats/mod.rs @@ -70,6 +70,8 @@ pub async fn list_workspaces( index_scheduler: GuardedData, Data>, paginate: AwebQueryParameter, ) -> Result { + index_scheduler.features().check_chat_completions("Using the /chats settings route")?; + debug!(parameters = ?paginate, "List chat workspaces"); let filters = index_scheduler.filters(); let (total, workspaces) = index_scheduler.paginated_chat_workspace_uids( diff --git a/crates/meilisearch/src/routes/chats/settings.rs b/crates/meilisearch/src/routes/chats/settings.rs index 68ad2d45e..e118a3ef1 100644 --- a/crates/meilisearch/src/routes/chats/settings.rs +++ b/crates/meilisearch/src/routes/chats/settings.rs @@ -38,6 +38,8 @@ async fn get_settings( >, chats_param: web::Path, ) -> Result { + index_scheduler.features().check_chat_completions("Using the /chats settings route")?; + let ChatsParam { workspace_uid } = chats_param.into_inner(); // TODO do a spawn_blocking here ??? @@ -63,6 +65,7 @@ async fn patch_settings( chats_param: web::Path, web::Json(new): web::Json, ) -> Result { + index_scheduler.features().check_chat_completions("Using the /chats settings route")?; let ChatsParam { workspace_uid } = chats_param.into_inner(); // TODO do a spawn_blocking here @@ -143,6 +146,8 @@ async fn delete_settings( >, chats_param: web::Path, ) -> Result { + index_scheduler.features().check_chat_completions("Using the /chats settings route")?; + let ChatsParam { workspace_uid } = chats_param.into_inner(); // TODO do a spawn_blocking here diff --git a/crates/meilisearch/src/routes/features.rs b/crates/meilisearch/src/routes/features.rs index eb8e7ac04..179b9cf68 100644 --- a/crates/meilisearch/src/routes/features.rs +++ b/crates/meilisearch/src/routes/features.rs @@ -53,6 +53,7 @@ pub fn configure(cfg: &mut web::ServiceConfig) { network: Some(false), get_task_documents_route: Some(false), composite_embedders: Some(false), + chat_completions: Some(false), })), (status = 401, description = "The authorization header is missing", body = ResponseError, content_type = "application/json", example = json!( { @@ -97,6 +98,8 @@ pub struct RuntimeTogglableFeatures { pub get_task_documents_route: Option, #[deserr(default)] pub composite_embedders: Option, + #[deserr(default)] + pub chat_completions: Option, } impl From for RuntimeTogglableFeatures { @@ -109,6 +112,7 @@ impl From for RuntimeTogg network, get_task_documents_route, composite_embedders, + chat_completions, } = value; Self { @@ -119,6 +123,7 @@ impl From for RuntimeTogg network: Some(network), get_task_documents_route: Some(get_task_documents_route), composite_embedders: Some(composite_embedders), + chat_completions: Some(chat_completions), } } } @@ -132,6 +137,7 @@ pub struct PatchExperimentalFeatureAnalytics { network: bool, get_task_documents_route: bool, composite_embedders: bool, + chat_completions: bool, } impl Aggregate for PatchExperimentalFeatureAnalytics { @@ -148,6 +154,7 @@ impl Aggregate for PatchExperimentalFeatureAnalytics { network: new.network, get_task_documents_route: new.get_task_documents_route, composite_embedders: new.composite_embedders, + chat_completions: new.chat_completions, }) } @@ -173,6 +180,7 @@ impl Aggregate for PatchExperimentalFeatureAnalytics { network: Some(false), get_task_documents_route: Some(false), composite_embedders: Some(false), + chat_completions: Some(false), })), (status = 401, description = "The authorization header is missing", body = ResponseError, content_type = "application/json", example = json!( { @@ -214,6 +222,7 @@ async fn patch_features( .0 .composite_embedders .unwrap_or(old_features.composite_embedders), + chat_completions: new_features.0.chat_completions.unwrap_or(old_features.chat_completions), }; // explicitly destructure for analytics rather than using the `Serialize` implementation, because @@ -227,6 +236,7 @@ async fn patch_features( network, get_task_documents_route, composite_embedders, + chat_completions, } = new_features; analytics.publish( @@ -238,6 +248,7 @@ async fn patch_features( network, get_task_documents_route, composite_embedders, + chat_completions, }, &req, );