Improve code readability

This commit is contained in:
Mubelotix
2025-07-21 16:06:07 +02:00
parent 6825d917f4
commit b1d3a8c58f

View File

@ -14,10 +14,13 @@ use meilisearch_types::error::deserr_codes::{
}; };
use meilisearch_types::error::Code; use meilisearch_types::error::Code;
use meilisearch_types::error::ResponseError; use meilisearch_types::error::ResponseError;
use meilisearch_types::heed::RoTxn;
use meilisearch_types::index_uid::IndexUid; use meilisearch_types::index_uid::IndexUid;
use meilisearch_types::keys::actions; use meilisearch_types::keys::actions;
use meilisearch_types::milli::prompt::{get_document, get_inline_document_fields}; use meilisearch_types::milli::prompt::{get_document, get_inline_document_fields};
use meilisearch_types::milli::vector::db::IndexEmbeddingConfig;
use meilisearch_types::milli::vector::json_template::{self, JsonTemplate}; use meilisearch_types::milli::vector::json_template::{self, JsonTemplate};
use meilisearch_types::milli::vector::EmbedderOptions;
use meilisearch_types::{heed, milli, Index}; use meilisearch_types::{heed, milli, Index};
use serde::Serialize; use serde::Serialize;
use serde_json::Value; use serde_json::Value;
@ -109,20 +112,21 @@ pub async fn render_post(
Ok(HttpResponse::Ok().json(result)) Ok(HttpResponse::Ok().json(result))
} }
#[derive(Clone, Copy)]
enum FragmentKind { enum FragmentKind {
Indexing, Indexing,
Search, Search,
} }
impl FragmentKind { impl FragmentKind {
fn adjective(&self) -> &'static str { fn as_str(&self) -> &'static str {
match self { match self {
FragmentKind::Indexing => "indexing", FragmentKind::Indexing => "indexing",
FragmentKind::Search => "search", FragmentKind::Search => "search",
} }
} }
fn adjective_capitalized(&self) -> &'static str { fn capitalized(&self) -> &'static str {
match self { match self {
FragmentKind::Indexing => "Indexing", FragmentKind::Indexing => "Indexing",
FragmentKind::Search => "Search", FragmentKind::Search => "Search",
@ -139,32 +143,32 @@ enum RenderError {
available: Vec<String>, available: Vec<String>,
}, },
EmbedderDoesNotExist { EmbedderDoesNotExist {
embedder_name: String, embedder: String,
available: Vec<String>, available: Vec<String>,
}, },
EmbedderUsesFragments { EmbedderUsesFragments {
embedder_name: String, embedder: String,
}, },
MissingTemplateAfterEmbedder { MissingTemplateAfterEmbedder {
embedder_name: String, embedder: String,
available_indexing_fragments: Vec<String>, indexing: Vec<String>,
available_search_fragments: Vec<String>, search: Vec<String>,
}, },
UnknownTemplatePrefix { UnknownTemplatePrefix {
embedder_name: String, embedder: String,
found: String, found: String,
available_indexing_fragments: Vec<String>, indexing: Vec<String>,
available_search_fragments: Vec<String>, search: Vec<String>,
}, },
ReponseError(ResponseError), ReponseError(ResponseError),
MissingFragment { MissingFragment {
embedder_name: String, embedder: String,
kind: FragmentKind, kind: FragmentKind,
available: Vec<String>, available: Vec<String>,
}, },
FragmentDoesNotExist { FragmentDoesNotExist {
embedder_name: String, embedder: String,
fragment_name: String, fragment: String,
kind: FragmentKind, kind: FragmentKind,
available: Vec<String>, available: Vec<String>,
}, },
@ -225,69 +229,69 @@ impl From<RenderError> for ResponseError {
Code::InvalidRenderTemplateId, Code::InvalidRenderTemplateId,
) )
}, },
EmbedderDoesNotExist { embedder_name, mut available } => { EmbedderDoesNotExist { embedder, mut available } => {
available.sort_unstable(); available.sort_unstable();
ResponseError::from_msg( ResponseError::from_msg(
format!("Embedder `{embedder_name}` does not exist.\n Hint: Available embedders are {}.", format!("Embedder `{embedder}` does not exist.\n Hint: Available embedders are {}.",
available.iter().map(|s| format!("`{s}`")).collect::<Vec<_>>().join(", ")), available.iter().map(|s| format!("`{s}`")).collect::<Vec<_>>().join(", ")),
Code::InvalidRenderTemplateId, Code::InvalidRenderTemplateId,
) )
}, },
EmbedderUsesFragments { embedder_name } => ResponseError::from_msg( EmbedderUsesFragments { embedder } => ResponseError::from_msg(
format!("Requested document template for embedder `{embedder_name}` but it uses fragments.\n Hint: Use `indexingFragments` or `searchFragments` instead."), format!("Requested document template for embedder `{embedder}` but it uses fragments.\n Hint: Use `indexingFragments` or `searchFragments` instead."),
Code::InvalidRenderTemplateId, Code::InvalidRenderTemplateId,
), ),
MissingTemplateAfterEmbedder { embedder_name, mut available_indexing_fragments, mut available_search_fragments } => { MissingTemplateAfterEmbedder { embedder, mut indexing, mut search } => {
if available_indexing_fragments.is_empty() && available_search_fragments.is_empty() { if indexing.is_empty() && search.is_empty() {
ResponseError::from_msg( ResponseError::from_msg(
format!("Missing template id after embedder `{embedder_name}`.\n Hint: Available fragments: `documentTemplate`."), format!("Missing template id after embedder `{embedder}`.\n Hint: Available fragments: `documentTemplate`."),
Code::InvalidRenderTemplateId, Code::InvalidRenderTemplateId,
) )
} else { } else {
available_indexing_fragments.sort_unstable(); indexing.sort_unstable();
available_search_fragments.sort_unstable(); search.sort_unstable();
ResponseError::from_msg( ResponseError::from_msg(
format!("Template ID configured with `embedders.{embedder_name}` but no template kind provided.\n Hint: Available fragments are {}.", format!("Template ID configured with `embedders.{embedder}` but no template kind provided.\n Hint: Available fragments are {}.",
available_indexing_fragments.iter().map(|s| format!("`indexingFragments.{s}`")).chain( indexing.iter().map(|s| format!("`indexingFragments.{s}`")).chain(
available_search_fragments.iter().map(|s| format!("`searchFragments.{s}`"))).collect::<Vec<_>>().join(", ")), search.iter().map(|s| format!("`searchFragments.{s}`"))).collect::<Vec<_>>().join(", ")),
Code::InvalidRenderTemplateId, Code::InvalidRenderTemplateId,
) )
} }
}, },
UnknownTemplatePrefix { embedder_name, found, mut available_indexing_fragments, mut available_search_fragments } => { UnknownTemplatePrefix { embedder, found, mut indexing, mut search } => {
if available_indexing_fragments.is_empty() && available_search_fragments.is_empty() { if indexing.is_empty() && search.is_empty() {
ResponseError::from_msg( ResponseError::from_msg(
format!("Wrong template `{found}` after embedder `{embedder_name}`.\n Hint: Available fragments: `documentTemplate`."), format!("Wrong template `{found}` after embedder `{embedder}`.\n Hint: Available fragments: `documentTemplate`."),
Code::InvalidRenderTemplateId, Code::InvalidRenderTemplateId,
) )
} else { } else {
available_indexing_fragments.sort_unstable(); indexing.sort_unstable();
available_search_fragments.sort_unstable(); search.sort_unstable();
ResponseError::from_msg( ResponseError::from_msg(
format!("Wrong template `{found}` after embedder `{embedder_name}`.\n Hint: Available fragments are {}.", format!("Wrong template `{found}` after embedder `{embedder}`.\n Hint: Available fragments are {}.",
available_indexing_fragments.iter().map(|s| format!("`indexingFragments.{s}`")).chain( indexing.iter().map(|s| format!("`indexingFragments.{s}`")).chain(
available_search_fragments.iter().map(|s| format!("`searchFragments.{s}`"))).collect::<Vec<_>>().join(", ")), search.iter().map(|s| format!("`searchFragments.{s}`"))).collect::<Vec<_>>().join(", ")),
Code::InvalidRenderTemplateId, Code::InvalidRenderTemplateId,
) )
} }
}, },
ReponseError(response_error) => response_error, ReponseError(response_error) => response_error,
MissingFragment { embedder_name, kind, mut available } => { MissingFragment { embedder, kind, mut available } => {
available.sort_unstable(); available.sort_unstable();
ResponseError::from_msg( ResponseError::from_msg(
format!("{} fragment name was not provided.\n Hint: Available {} fragments for embedder `{embedder_name}` are {}.", format!("{} fragment name was not provided.\n Hint: Available {} fragments for embedder `{embedder}` are {}.",
kind.adjective_capitalized(), kind.capitalized(),
kind.adjective(), kind.as_str(),
available.iter().map(|s| format!("`{s}`")).collect::<Vec<_>>().join(", ")), available.iter().map(|s| format!("`{s}`")).collect::<Vec<_>>().join(", ")),
Code::InvalidRenderTemplateId, Code::InvalidRenderTemplateId,
) )
}, },
FragmentDoesNotExist { embedder_name, fragment_name, kind, mut available } => { FragmentDoesNotExist { embedder, fragment, kind, mut available } => {
available.sort_unstable(); available.sort_unstable();
ResponseError::from_msg( ResponseError::from_msg(
format!("{} fragment `{fragment_name}` does not exist for embedder `{embedder_name}`.\n Hint: Available {} fragments are {}.", format!("{} fragment `{fragment}` does not exist for embedder `{embedder}`.\n Hint: Available {} fragments are {}.",
kind.adjective_capitalized(), kind.capitalized(),
kind.adjective(), kind.as_str(),
available.iter().map(|s| format!("`{s}`")).collect::<Vec<_>>().join(", ")), available.iter().map(|s| format!("`{s}`")).collect::<Vec<_>>().join(", ")),
Code::InvalidRenderTemplateId, Code::InvalidRenderTemplateId,
) )
@ -340,12 +344,39 @@ impl From<RenderError> for ResponseError {
} }
} }
async fn render(index: Index, query: RenderQuery) -> Result<RenderResult, RenderError> { fn parse_template_id_fragment(
let rtxn = index.read_txn()?; name: Option<&str>,
kind: FragmentKind,
embedding_config: &IndexEmbeddingConfig,
embedder_name: &str,
) -> Result<serde_json::Value, RenderError> {
let get_available =
[EmbedderOptions::indexing_fragments, EmbedderOptions::search_fragments][kind as usize];
let get_specific =
[EmbedderOptions::indexing_fragment, EmbedderOptions::search_fragment][kind as usize];
let (template, fields_available) = match (query.template.inline, query.template.id) { let fragment_name = name.ok_or_else(|| MissingFragment {
(Some(inline), None) => (inline, true), embedder: embedder_name.to_string(),
(None, Some(id)) => { kind,
available: get_available(&embedding_config.config.embedder_options),
})?;
let fragment = get_specific(&embedding_config.config.embedder_options, fragment_name)
.ok_or_else(|| FragmentDoesNotExist {
embedder: embedder_name.to_string(),
fragment: fragment_name.to_string(),
kind,
available: get_available(&embedding_config.config.embedder_options),
})?;
Ok(fragment.clone())
}
fn parse_template_id(
index: &Index,
rtxn: &RoTxn<'_>,
id: &str,
) -> Result<(serde_json::Value, bool), RenderError> {
let mut parts = id.split('.'); let mut parts = id.split('.');
let root = parts.next().ok_or(EmptyTemplateId)?; let root = parts.next().ok_or(EmptyTemplateId)?;
@ -353,111 +384,62 @@ async fn render(index: Index, query: RenderQuery) -> Result<RenderResult, Render
let template = match root { let template = match root {
"embedders" => { "embedders" => {
let index_embedding_configs = index.embedding_configs(); let index_embedding_configs = index.embedding_configs();
let embedding_configs = index_embedding_configs.embedding_configs(&rtxn)?; let embedding_configs = index_embedding_configs.embedding_configs(rtxn)?;
let get_embedders = || embedding_configs.iter().map(|c| c.name.clone()).collect();
let embedder_name = parts.next().ok_or_else(|| MissingEmbedderName { let embedder =
available: embedding_configs.iter().map(|c| c.name.clone()).collect(), parts.next().ok_or_else(|| MissingEmbedderName { available: get_embedders() })?;
})?;
let embedding_config = embedding_configs let embedding_config = embedding_configs
.iter() .iter()
.find(|config| config.name == embedder_name) .find(|config| config.name == embedder)
.ok_or_else(|| EmbedderDoesNotExist { .ok_or_else(|| EmbedderDoesNotExist {
embedder_name: embedder_name.to_string(), embedder: embedder.to_string(),
available: embedding_configs.iter().map(|c| c.name.clone()).collect(), available: get_embedders(),
})?; })?;
let template_kind = let get_indexing = || embedding_config.config.embedder_options.indexing_fragments();
parts.next().ok_or_else(|| MissingTemplateAfterEmbedder { let get_search = || embedding_config.config.embedder_options.search_fragments();
embedder_name: embedder_name.to_string(),
available_indexing_fragments: embedding_config let template_kind = parts.next().ok_or_else(|| MissingTemplateAfterEmbedder {
.config embedder: embedder.to_string(),
.embedder_options indexing: get_indexing(),
.indexing_fragments(), search: get_search(),
available_search_fragments: embedding_config
.config
.embedder_options
.search_fragments(),
})?; })?;
match template_kind { match template_kind {
"documentTemplate" | "documenttemplate" => { "documentTemplate" | "documenttemplate"
if !embedding_config.fragments.as_slice().is_empty() { if !embedding_config.fragments.as_slice().is_empty() =>
return Err(EmbedderUsesFragments { {
embedder_name: embedder_name.to_string(), return Err(EmbedderUsesFragments { embedder: embedder.to_string() });
});
} }
"documentTemplate" | "documenttemplate" => (
( serde_json::Value::String(embedding_config.config.prompt.template.clone()),
serde_json::Value::String(
embedding_config.config.prompt.template.clone(),
),
true, true,
) ),
} "indexingFragments" | "indexingfragments" => (
"indexingFragments" | "indexingfragments" => { parse_template_id_fragment(
let fragment_name = parts.next().ok_or_else(|| MissingFragment { parts.next(),
embedder_name: embedder_name.to_string(), FragmentKind::Indexing,
kind: FragmentKind::Indexing, embedding_config,
available: embedding_config embedder,
.config )?,
.embedder_options false,
.indexing_fragments(), ),
})?; "searchFragments" | "searchfragments" => (
parse_template_id_fragment(
let fragment = embedding_config parts.next(),
.config FragmentKind::Search,
.embedder_options embedding_config,
.indexing_fragment(fragment_name) embedder,
.ok_or_else(|| FragmentDoesNotExist { )?,
embedder_name: embedder_name.to_string(), false,
fragment_name: fragment_name.to_string(), ),
kind: FragmentKind::Indexing,
available: embedding_config
.config
.embedder_options
.indexing_fragments(),
})?;
(fragment.clone(), false)
}
"searchFragments" | "searchfragments" => {
let fragment_name = parts.next().ok_or_else(|| MissingFragment {
embedder_name: embedder_name.to_string(),
kind: FragmentKind::Search,
available: embedding_config
.config
.embedder_options
.search_fragments(),
})?;
let fragment = embedding_config
.config
.embedder_options
.search_fragment(fragment_name)
.ok_or_else(|| FragmentDoesNotExist {
embedder_name: embedder_name.to_string(),
fragment_name: fragment_name.to_string(),
kind: FragmentKind::Search,
available: embedding_config
.config
.embedder_options
.search_fragments(),
})?;
(fragment.clone(), false)
}
found => { found => {
return Err(UnknownTemplatePrefix { return Err(UnknownTemplatePrefix {
embedder_name: embedder_name.to_string(), embedder: embedder.to_string(),
found: found.to_string(), found: found.to_string(),
available_indexing_fragments: embedding_config indexing: get_indexing(),
.config search: get_search(),
.embedder_options
.indexing_fragments(),
available_search_fragments: embedding_config
.config
.embedder_options
.search_fragments(),
}) })
} }
} }
@ -469,7 +451,7 @@ async fn render(index: Index, query: RenderQuery) -> Result<RenderResult, Render
return Err(UnknownChatCompletionTemplate(template_name.to_string())); return Err(UnknownChatCompletionTemplate(template_name.to_string()));
} }
let chat_config = index.chat_config(&rtxn)?; let chat_config = index.chat_config(rtxn)?;
(serde_json::Value::String(chat_config.prompt.template.clone()), true) (serde_json::Value::String(chat_config.prompt.template.clone()), true)
} }
@ -483,8 +465,15 @@ async fn render(index: Index, query: RenderQuery) -> Result<RenderResult, Render
return Err(LeftOverToken(next.to_string())); return Err(LeftOverToken(next.to_string()));
} }
template Ok(template)
} }
async fn render(index: Index, query: RenderQuery) -> Result<RenderResult, RenderError> {
let rtxn = index.read_txn()?;
let (template, fields_available) = match (query.template.inline, query.template.id) {
(Some(inline), None) => (inline, true),
(None, Some(id)) => parse_template_id(&index, &rtxn, &id)?,
(Some(_), Some(_)) => return Err(MultipleTemplates), (Some(_), Some(_)) => return Err(MultipleTemplates),
(None, None) => return Err(MissingTemplate), (None, None) => return Err(MissingTemplate),
}; };