mirror of
https://github.com/perstarkse/minne.git
synced 2026-06-16 03:04:24 +02:00
fix: leaner error handling by boxing large variants
This commit is contained in:
+56
-6
@@ -9,7 +9,7 @@ use crate::storage::types::file_info::FileError;
|
||||
#[derive(Error, Debug)]
|
||||
pub enum EmbeddingError {
|
||||
#[error("openai error: {0}")]
|
||||
OpenAI(#[from] OpenAIError),
|
||||
OpenAI(Box<OpenAIError>),
|
||||
#[error("fastembed error: {0}")]
|
||||
FastEmbed(String),
|
||||
#[error("task join error: {0}")]
|
||||
@@ -24,6 +24,12 @@ pub enum EmbeddingError {
|
||||
UnknownModel(String),
|
||||
}
|
||||
|
||||
impl From<OpenAIError> for EmbeddingError {
|
||||
fn from(err: OpenAIError) -> Self {
|
||||
Self::OpenAI(Box::new(err))
|
||||
}
|
||||
}
|
||||
|
||||
impl EmbeddingError {
|
||||
pub(crate) fn fastembed(err: impl std::fmt::Display) -> Self {
|
||||
Self::FastEmbed(err.to_string())
|
||||
@@ -39,9 +45,9 @@ impl EmbeddingError {
|
||||
#[derive(Error, Debug)]
|
||||
pub enum AppError {
|
||||
#[error("database error: {0}")]
|
||||
Database(#[from] surrealdb::Error),
|
||||
Database(Box<surrealdb::Error>),
|
||||
#[error("openai error: {0}")]
|
||||
OpenAI(#[from] OpenAIError),
|
||||
OpenAI(Box<OpenAIError>),
|
||||
#[error("embedding error: {0}")]
|
||||
Embedding(#[from] EmbeddingError),
|
||||
#[error("file error: {0}")]
|
||||
@@ -61,17 +67,47 @@ pub enum AppError {
|
||||
#[error("io error: {0}")]
|
||||
Io(#[from] std::io::Error),
|
||||
#[error("reqwest error: {0}")]
|
||||
Reqwest(#[from] reqwest::Error),
|
||||
Reqwest(Box<reqwest::Error>),
|
||||
#[error("storage error: {0}")]
|
||||
Storage(#[from] object_store::Error),
|
||||
Storage(Box<object_store::Error>),
|
||||
#[error("ingestion processing error: {0}")]
|
||||
Processing(String),
|
||||
#[error("dom smoothie error: {0}")]
|
||||
DomSmoothie(#[from] dom_smoothie::ReadabilityError),
|
||||
DomSmoothie(Box<dom_smoothie::ReadabilityError>),
|
||||
#[error("internal service error: {0}")]
|
||||
InternalError(String),
|
||||
}
|
||||
|
||||
impl From<surrealdb::Error> for AppError {
|
||||
fn from(err: surrealdb::Error) -> Self {
|
||||
Self::Database(Box::new(err))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<OpenAIError> for AppError {
|
||||
fn from(err: OpenAIError) -> Self {
|
||||
Self::OpenAI(Box::new(err))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<reqwest::Error> for AppError {
|
||||
fn from(err: reqwest::Error) -> Self {
|
||||
Self::Reqwest(Box::new(err))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<object_store::Error> for AppError {
|
||||
fn from(err: object_store::Error) -> Self {
|
||||
Self::Storage(Box::new(err))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<dom_smoothie::ReadabilityError> for AppError {
|
||||
fn from(err: dom_smoothie::ReadabilityError) -> Self {
|
||||
Self::DomSmoothie(Box::new(err))
|
||||
}
|
||||
}
|
||||
|
||||
impl AppError {
|
||||
/// Builds an [`AppError::InternalError`] from a displayable message.
|
||||
#[must_use]
|
||||
@@ -79,3 +115,17 @@ impl AppError {
|
||||
Self::InternalError(msg.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::AppError;
|
||||
|
||||
#[test]
|
||||
fn app_error_is_reasonably_sized() {
|
||||
assert!(
|
||||
std::mem::size_of::<AppError>() <= 64,
|
||||
"AppError is {} bytes",
|
||||
std::mem::size_of::<AppError>()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ pub enum FileError {
|
||||
|
||||
/// Database operation on the file record failed.
|
||||
#[error("surrealdb error: {0}")]
|
||||
SurrealError(#[from] surrealdb::Error),
|
||||
SurrealError(Box<surrealdb::Error>),
|
||||
|
||||
/// Failed to persist the temporary file to its final location.
|
||||
#[error("failed to persist file: {0}")]
|
||||
@@ -48,7 +48,19 @@ pub enum FileError {
|
||||
|
||||
/// The underlying object store operation failed.
|
||||
#[error("object store error: {0}")]
|
||||
ObjectStore(#[from] ObjectStoreError),
|
||||
ObjectStore(Box<ObjectStoreError>),
|
||||
}
|
||||
|
||||
impl From<surrealdb::Error> for FileError {
|
||||
fn from(err: surrealdb::Error) -> Self {
|
||||
Self::SurrealError(Box::new(err))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ObjectStoreError> for FileError {
|
||||
fn from(err: ObjectStoreError) -> Self {
|
||||
Self::ObjectStore(Box::new(err))
|
||||
}
|
||||
}
|
||||
|
||||
stored_object!(FileInfo, "file", {
|
||||
@@ -163,7 +175,7 @@ impl FileInfo {
|
||||
match db_client.get_item::<FileInfo>(id).await {
|
||||
Ok(Some(file_info)) => Ok(file_info),
|
||||
Ok(None) => Err(FileError::FileNotFound(id.to_string())),
|
||||
Err(e) => Err(FileError::SurrealError(e)),
|
||||
Err(e) => Err(FileError::from(e)),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -233,7 +245,7 @@ impl FileInfo {
|
||||
if let Ok(existing) = Self::get_by_sha(&sha256, user_id, db_client).await {
|
||||
return Ok(existing);
|
||||
}
|
||||
Err(FileError::SurrealError(e))
|
||||
Err(FileError::from(e))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -263,7 +275,7 @@ impl FileInfo {
|
||||
storage
|
||||
.delete_prefix(&parent_prefix)
|
||||
.await
|
||||
.map_err(AppError::Storage)?;
|
||||
.map_err(AppError::from)?;
|
||||
info!(
|
||||
"Removed object prefix {} and its contents via StorageManager",
|
||||
parent_prefix
|
||||
@@ -286,7 +298,7 @@ impl FileInfo {
|
||||
&self,
|
||||
storage: &StorageManager,
|
||||
) -> Result<bytes::Bytes, AppError> {
|
||||
storage.get(&self.path).await.map_err(AppError::Storage)
|
||||
storage.get(&self.path).await.map_err(AppError::from)
|
||||
}
|
||||
|
||||
/// Persist bytes to storage using StorageManager.
|
||||
|
||||
@@ -183,9 +183,9 @@ impl KnowledgeEntity {
|
||||
.bind(("sources", source_ids.to_vec()))
|
||||
.bind(("user_id", user_id.to_owned()))
|
||||
.await
|
||||
.map_err(AppError::Database)?
|
||||
.map_err(AppError::from)?
|
||||
.take(0)
|
||||
.map_err(AppError::Database)?;
|
||||
.map_err(AppError::from)?;
|
||||
|
||||
Ok(entities)
|
||||
}
|
||||
@@ -203,9 +203,9 @@ impl KnowledgeEntity {
|
||||
.bind(("table", Self::table_name()))
|
||||
.bind(("source_id", source_id.to_owned()))
|
||||
.await
|
||||
.map_err(AppError::Database)?
|
||||
.map_err(AppError::from)?
|
||||
.check()
|
||||
.map_err(AppError::Database)?;
|
||||
.map_err(AppError::from)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -248,9 +248,9 @@ impl KnowledgeEntity {
|
||||
.bind(("entity", entity))
|
||||
.bind(("emb", emb))
|
||||
.await
|
||||
.map_err(AppError::Database)?
|
||||
.map_err(AppError::from)?
|
||||
.check()
|
||||
.map_err(AppError::Database)?;
|
||||
.map_err(AppError::from)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -289,11 +289,11 @@ impl KnowledgeEntity {
|
||||
.bind(("embedding", query_embedding))
|
||||
.bind(("user_id", user_id.to_string()))
|
||||
.await
|
||||
.map_err(AppError::Database)?;
|
||||
.map_err(AppError::from)?;
|
||||
|
||||
response = response.check().map_err(AppError::Database)?;
|
||||
response = response.check().map_err(AppError::from)?;
|
||||
|
||||
let rows: Vec<Row> = response.take::<Vec<Row>>(0).map_err(AppError::Database)?;
|
||||
let rows: Vec<Row> = response.take::<Vec<Row>>(0).map_err(AppError::from)?;
|
||||
|
||||
Ok(rows
|
||||
.into_iter()
|
||||
@@ -321,7 +321,7 @@ impl KnowledgeEntity {
|
||||
let entity: KnowledgeEntity = db_client
|
||||
.get_item(id)
|
||||
.await
|
||||
.map_err(AppError::Database)?
|
||||
.map_err(AppError::from)?
|
||||
.ok_or_else(|| AppError::NotFound(format!("entity {id} not found")))?;
|
||||
|
||||
let settings = SystemSettings::get_current(db_client).await?;
|
||||
@@ -355,9 +355,9 @@ impl KnowledgeEntity {
|
||||
.bind(("emb", emb))
|
||||
.bind(("description", description.to_string()))
|
||||
.await
|
||||
.map_err(AppError::Database)?
|
||||
.map_err(AppError::from)?
|
||||
.check()
|
||||
.map_err(AppError::Database)?;
|
||||
.map_err(AppError::from)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -453,9 +453,9 @@ impl KnowledgeEntity {
|
||||
KnowledgeEntityEmbedding::table_name()
|
||||
))
|
||||
.await
|
||||
.map_err(AppError::Database)?
|
||||
.map_err(AppError::from)?
|
||||
.check()
|
||||
.map_err(AppError::Database)?;
|
||||
.map_err(AppError::from)?;
|
||||
|
||||
db.client
|
||||
.query(format!(
|
||||
@@ -463,9 +463,9 @@ impl KnowledgeEntity {
|
||||
KnowledgeEntityEmbedding::table_name()
|
||||
))
|
||||
.await
|
||||
.map_err(AppError::Database)?
|
||||
.map_err(AppError::from)?
|
||||
.check()
|
||||
.map_err(AppError::Database)?;
|
||||
.map_err(AppError::from)?;
|
||||
|
||||
// Perform DB updates in a single transaction
|
||||
info!("Applying embedding updates in a transaction...");
|
||||
@@ -504,9 +504,9 @@ impl KnowledgeEntity {
|
||||
db.client
|
||||
.query(transaction_query)
|
||||
.await
|
||||
.map_err(AppError::Database)?
|
||||
.map_err(AppError::from)?
|
||||
.check()
|
||||
.map_err(AppError::Database)?;
|
||||
.map_err(AppError::from)?;
|
||||
|
||||
info!("Re-embedding process for knowledge entities completed successfully.");
|
||||
Ok(())
|
||||
|
||||
@@ -29,8 +29,8 @@ impl KnowledgeEntityEmbedding {
|
||||
dimension,
|
||||
);
|
||||
|
||||
let res = db.client.query(query).await.map_err(AppError::Database)?;
|
||||
res.check().map_err(AppError::Database)?;
|
||||
let res = db.client.query(query).await.map_err(AppError::from)?;
|
||||
res.check().map_err(AppError::from)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -78,8 +78,8 @@ impl KnowledgeEntityEmbedding {
|
||||
.query(query)
|
||||
.bind(("entity_id", entity_id.clone()))
|
||||
.await
|
||||
.map_err(AppError::Database)?;
|
||||
let embeddings: Vec<Self> = result.take(0).map_err(AppError::Database)?;
|
||||
.map_err(AppError::from)?;
|
||||
let embeddings: Vec<Self> = result.take(0).map_err(AppError::from)?;
|
||||
Ok(embeddings.into_iter().next())
|
||||
}
|
||||
|
||||
@@ -101,8 +101,8 @@ impl KnowledgeEntityEmbedding {
|
||||
.query(query)
|
||||
.bind(("entity_ids", entity_ids.to_vec()))
|
||||
.await
|
||||
.map_err(AppError::Database)?;
|
||||
let embeddings: Vec<Self> = result.take(0).map_err(AppError::Database)?;
|
||||
.map_err(AppError::from)?;
|
||||
let embeddings: Vec<Self> = result.take(0).map_err(AppError::from)?;
|
||||
|
||||
Ok(embeddings
|
||||
.into_iter()
|
||||
@@ -123,9 +123,9 @@ impl KnowledgeEntityEmbedding {
|
||||
.query(query)
|
||||
.bind(("entity_id", entity_id.clone()))
|
||||
.await
|
||||
.map_err(AppError::Database)?
|
||||
.map_err(AppError::from)?
|
||||
.check()
|
||||
.map_err(AppError::Database)?;
|
||||
.map_err(AppError::from)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -142,9 +142,9 @@ impl KnowledgeEntityEmbedding {
|
||||
.query(query)
|
||||
.bind(("source_id", source_id.to_owned()))
|
||||
.await
|
||||
.map_err(AppError::Database)?
|
||||
.map_err(AppError::from)?
|
||||
.check()
|
||||
.map_err(AppError::Database)?;
|
||||
.map_err(AppError::from)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,9 +69,9 @@ impl KnowledgeRelationship {
|
||||
.bind(("source_id", self.metadata.source_id.clone()))
|
||||
.bind(("relationship_type", self.metadata.relationship_type.clone()))
|
||||
.await
|
||||
.map_err(AppError::Database)?
|
||||
.map_err(AppError::from)?
|
||||
.check()
|
||||
.map_err(AppError::Database)?;
|
||||
.map_err(AppError::from)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -89,9 +89,9 @@ impl KnowledgeRelationship {
|
||||
.bind(("source_id", source_id.to_owned()))
|
||||
.bind(("user_id", user_id.to_owned()))
|
||||
.await
|
||||
.map_err(AppError::Database)?
|
||||
.map_err(AppError::from)?
|
||||
.check()
|
||||
.map_err(AppError::Database)?;
|
||||
.map_err(AppError::from)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -109,9 +109,9 @@ impl KnowledgeRelationship {
|
||||
.bind(("id", id.to_owned()))
|
||||
.bind(("user_id", user_id.to_owned()))
|
||||
.await
|
||||
.map_err(AppError::Database)?;
|
||||
.map_err(AppError::from)?;
|
||||
let deleted: Vec<KnowledgeRelationship> =
|
||||
delete_result.take(0).map_err(AppError::Database)?;
|
||||
delete_result.take(0).map_err(AppError::from)?;
|
||||
|
||||
if !deleted.is_empty() {
|
||||
return Ok(());
|
||||
@@ -122,9 +122,9 @@ impl KnowledgeRelationship {
|
||||
.query("SELECT * FROM type::thing('relates_to', $id)")
|
||||
.bind(("id", id.to_owned()))
|
||||
.await
|
||||
.map_err(AppError::Database)?;
|
||||
.map_err(AppError::from)?;
|
||||
let existing: Option<KnowledgeRelationship> =
|
||||
exists_result.take(0).map_err(AppError::Database)?;
|
||||
exists_result.take(0).map_err(AppError::from)?;
|
||||
|
||||
if existing.is_some() {
|
||||
Err(AppError::Auth(
|
||||
|
||||
@@ -55,9 +55,9 @@ impl TextChunk {
|
||||
.bind(("source_id", source_id.to_owned()))
|
||||
.bind(("table", Self::table_name()))
|
||||
.await
|
||||
.map_err(AppError::Database)?
|
||||
.map_err(AppError::from)?
|
||||
.check()
|
||||
.map_err(AppError::Database)?;
|
||||
.map_err(AppError::from)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -97,9 +97,9 @@ impl TextChunk {
|
||||
.bind(("chunk", chunk))
|
||||
.bind(("emb", emb))
|
||||
.await
|
||||
.map_err(AppError::Database)?
|
||||
.map_err(AppError::from)?
|
||||
.check()
|
||||
.map_err(AppError::Database)?;
|
||||
.map_err(AppError::from)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -140,11 +140,11 @@ impl TextChunk {
|
||||
.bind(("embedding", query_embedding))
|
||||
.bind(("user_id", user_id.to_string()))
|
||||
.await
|
||||
.map_err(AppError::Database)?;
|
||||
.map_err(AppError::from)?;
|
||||
|
||||
response = response.check().map_err(AppError::Database)?;
|
||||
response = response.check().map_err(AppError::from)?;
|
||||
|
||||
let rows: Vec<Row> = response.take::<Vec<Row>>(0).map_err(AppError::Database)?;
|
||||
let rows: Vec<Row> = response.take::<Vec<Row>>(0).map_err(AppError::from)?;
|
||||
|
||||
Ok(rows
|
||||
.into_iter()
|
||||
@@ -208,11 +208,11 @@ impl TextChunk {
|
||||
.bind(("user_id", user_id.to_owned()))
|
||||
.bind(("limit", limit))
|
||||
.await
|
||||
.map_err(AppError::Database)?;
|
||||
.map_err(AppError::from)?;
|
||||
|
||||
response = response.check().map_err(AppError::Database)?;
|
||||
response = response.check().map_err(AppError::from)?;
|
||||
|
||||
let rows: Vec<Row> = response.take::<Vec<Row>>(0).map_err(AppError::Database)?;
|
||||
let rows: Vec<Row> = response.take::<Vec<Row>>(0).map_err(AppError::from)?;
|
||||
|
||||
Ok(rows
|
||||
.into_iter()
|
||||
@@ -314,16 +314,16 @@ impl TextChunk {
|
||||
TextChunkEmbedding::table_name()
|
||||
))
|
||||
.await
|
||||
.map_err(AppError::Database)?
|
||||
.map_err(AppError::from)?
|
||||
.check()
|
||||
.map_err(AppError::Database)?;
|
||||
.map_err(AppError::from)?;
|
||||
|
||||
db.client
|
||||
.query(format!("DELETE FROM {};", TextChunkEmbedding::table_name()))
|
||||
.await
|
||||
.map_err(AppError::Database)?
|
||||
.map_err(AppError::from)?
|
||||
.check()
|
||||
.map_err(AppError::Database)?;
|
||||
.map_err(AppError::from)?;
|
||||
|
||||
// Perform DB updates in a single transaction against the embedding table
|
||||
info!("Applying embedding updates in a transaction...");
|
||||
@@ -366,9 +366,9 @@ impl TextChunk {
|
||||
db.client
|
||||
.query(transaction_query)
|
||||
.await
|
||||
.map_err(AppError::Database)?
|
||||
.map_err(AppError::from)?
|
||||
.check()
|
||||
.map_err(AppError::Database)?;
|
||||
.map_err(AppError::from)?;
|
||||
|
||||
info!("Re-embedding process for text chunks completed successfully.");
|
||||
Ok(())
|
||||
|
||||
@@ -33,8 +33,8 @@ impl TextChunkEmbedding {
|
||||
dimension,
|
||||
);
|
||||
|
||||
let res = db.client.query(query).await.map_err(AppError::Database)?;
|
||||
res.check().map_err(AppError::Database)?;
|
||||
let res = db.client.query(query).await.map_err(AppError::from)?;
|
||||
res.check().map_err(AppError::from)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -85,9 +85,9 @@ impl TextChunkEmbedding {
|
||||
.query(query)
|
||||
.bind(("chunk_id", chunk_id.clone()))
|
||||
.await
|
||||
.map_err(AppError::Database)?;
|
||||
.map_err(AppError::from)?;
|
||||
|
||||
let embeddings: Vec<Self> = result.take(0).map_err(AppError::Database)?;
|
||||
let embeddings: Vec<Self> = result.take(0).map_err(AppError::from)?;
|
||||
|
||||
Ok(embeddings.into_iter().next())
|
||||
}
|
||||
@@ -106,9 +106,9 @@ impl TextChunkEmbedding {
|
||||
.query(query)
|
||||
.bind(("chunk_id", chunk_id.clone()))
|
||||
.await
|
||||
.map_err(AppError::Database)?
|
||||
.map_err(AppError::from)?
|
||||
.check()
|
||||
.map_err(AppError::Database)?;
|
||||
.map_err(AppError::from)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -129,9 +129,9 @@ impl TextChunkEmbedding {
|
||||
.query(query)
|
||||
.bind(("source_id", source_id.to_owned()))
|
||||
.await
|
||||
.map_err(AppError::Database)?
|
||||
.map_err(AppError::from)?
|
||||
.check()
|
||||
.map_err(AppError::Database)?;
|
||||
.map_err(AppError::from)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -115,7 +115,7 @@ impl TextContent {
|
||||
surrealdb::Datetime::from(now),
|
||||
))
|
||||
.await
|
||||
.map_err(AppError::Database)?;
|
||||
.map_err(AppError::from)?;
|
||||
|
||||
if updated.is_none() {
|
||||
return Err(AppError::NotFound(format!("text content {id} not found")));
|
||||
@@ -138,10 +138,10 @@ impl TextContent {
|
||||
.bind(("file_id", file_id.to_owned()))
|
||||
.bind(("exclude_id", exclude_id.to_owned()))
|
||||
.await
|
||||
.map_err(AppError::Database)?;
|
||||
.map_err(AppError::from)?;
|
||||
|
||||
let existing: Option<surrealdb::sql::Thing> =
|
||||
response.take(0).map_err(AppError::Database)?;
|
||||
response.take(0).map_err(AppError::from)?;
|
||||
|
||||
Ok(existing.is_some())
|
||||
}
|
||||
@@ -193,9 +193,9 @@ impl TextContent {
|
||||
.bind(("user_id", user_id.to_owned()))
|
||||
.bind(("limit", limit))
|
||||
.await
|
||||
.map_err(AppError::Database)?
|
||||
.map_err(AppError::from)?
|
||||
.take(0)
|
||||
.map_err(AppError::Database)
|
||||
.map_err(AppError::from)
|
||||
}
|
||||
|
||||
/// Builds a fallback display label for a source id when no matching content row exists.
|
||||
@@ -239,9 +239,9 @@ impl TextContent {
|
||||
.bind(("user_id", user_id.to_owned()))
|
||||
.bind(("record_ids", record_ids))
|
||||
.await
|
||||
.map_err(AppError::Database)?;
|
||||
.map_err(AppError::from)?;
|
||||
|
||||
let contents: Vec<SourceLabelRow> = response.take(0).map_err(AppError::Database)?;
|
||||
let contents: Vec<SourceLabelRow> = response.take(0).map_err(AppError::from)?;
|
||||
|
||||
tracing::debug!(
|
||||
source_id_count = source_ids.len(),
|
||||
|
||||
@@ -688,7 +688,7 @@ impl User {
|
||||
|
||||
db.delete_item::<IngestionTask>(id)
|
||||
.await
|
||||
.map_err(AppError::Database)?;
|
||||
.map_err(AppError::from)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -44,6 +44,7 @@
|
||||
--leading-snug: 1.375;
|
||||
--leading-relaxed: 1.625;
|
||||
--ease-out: cubic-bezier(0, 0, 0.2, 1);
|
||||
--ease-in-out: cubic-bezier(0.4, 0, 0.2, 1);
|
||||
--animate-pulse: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
|
||||
--default-transition-duration: 150ms;
|
||||
--default-transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
||||
@@ -284,6 +285,37 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
.drawer-open {
|
||||
> .drawer-side {
|
||||
overflow-y: auto;
|
||||
}
|
||||
> .drawer-toggle {
|
||||
display: none;
|
||||
& ~ .drawer-side {
|
||||
pointer-events: auto;
|
||||
visibility: visible;
|
||||
position: sticky;
|
||||
display: block;
|
||||
width: auto;
|
||||
overscroll-behavior: auto;
|
||||
opacity: 100%;
|
||||
& > .drawer-overlay {
|
||||
cursor: default;
|
||||
background-color: transparent;
|
||||
}
|
||||
& > *:not(.drawer-overlay) {
|
||||
translate: 0%;
|
||||
[dir="rtl"] & {
|
||||
translate: 0%;
|
||||
}
|
||||
}
|
||||
}
|
||||
&:checked ~ .drawer-side {
|
||||
pointer-events: auto;
|
||||
visibility: visible;
|
||||
}
|
||||
}
|
||||
}
|
||||
.drawer-toggle {
|
||||
position: fixed;
|
||||
height: calc(0.25rem * 0);
|
||||
@@ -1042,6 +1074,22 @@
|
||||
grid-row-start: 1;
|
||||
min-width: calc(0.25rem * 0);
|
||||
}
|
||||
.chat-image {
|
||||
grid-row: span 2 / span 2;
|
||||
align-self: flex-end;
|
||||
}
|
||||
.chat-footer {
|
||||
grid-row-start: 3;
|
||||
display: flex;
|
||||
gap: calc(0.25rem * 1);
|
||||
font-size: 0.6875rem;
|
||||
}
|
||||
.chat-header {
|
||||
grid-row-start: 1;
|
||||
display: flex;
|
||||
gap: calc(0.25rem * 1);
|
||||
font-size: 0.6875rem;
|
||||
}
|
||||
.container {
|
||||
width: 100%;
|
||||
@media (width >= 40rem) {
|
||||
@@ -1748,6 +1796,9 @@
|
||||
.w-10 {
|
||||
width: calc(var(--spacing) * 10);
|
||||
}
|
||||
.w-11 {
|
||||
width: calc(var(--spacing) * 11);
|
||||
}
|
||||
.w-11\/12 {
|
||||
width: calc(11/12 * 100%);
|
||||
}
|
||||
@@ -1811,6 +1862,9 @@
|
||||
.flex-none {
|
||||
flex: none;
|
||||
}
|
||||
.flex-shrink {
|
||||
flex-shrink: 1;
|
||||
}
|
||||
.flex-shrink-0 {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
@@ -1823,6 +1877,13 @@
|
||||
.grow {
|
||||
flex-grow: 1;
|
||||
}
|
||||
.border-collapse {
|
||||
border-collapse: collapse;
|
||||
}
|
||||
.-translate-y-1 {
|
||||
--tw-translate-y: calc(var(--spacing) * -1);
|
||||
translate: var(--tw-translate-x) var(--tw-translate-y);
|
||||
}
|
||||
.-translate-y-1\/2 {
|
||||
--tw-translate-y: calc(calc(1/2 * 100%) * -1);
|
||||
translate: var(--tw-translate-x) var(--tw-translate-y);
|
||||
@@ -1895,6 +1956,9 @@
|
||||
.justify-start {
|
||||
justify-content: flex-start;
|
||||
}
|
||||
.gap-0 {
|
||||
gap: calc(var(--spacing) * 0);
|
||||
}
|
||||
.gap-0\.5 {
|
||||
gap: calc(var(--spacing) * 0.5);
|
||||
}
|
||||
@@ -2027,6 +2091,9 @@
|
||||
.border-base-200 {
|
||||
border-color: var(--color-base-200);
|
||||
}
|
||||
.border-base-content {
|
||||
border-color: var(--color-base-content);
|
||||
}
|
||||
.border-base-content\/10 {
|
||||
border-color: var(--color-base-content);
|
||||
@supports (color: color-mix(in lab, red, red)) {
|
||||
@@ -2063,6 +2130,9 @@
|
||||
.bg-transparent {
|
||||
background-color: transparent;
|
||||
}
|
||||
.bg-warning {
|
||||
background-color: var(--color-warning);
|
||||
}
|
||||
.bg-warning\/10 {
|
||||
background-color: var(--color-warning);
|
||||
@supports (color: color-mix(in lab, red, red)) {
|
||||
@@ -2081,6 +2151,9 @@
|
||||
.loading-spinner {
|
||||
mask-image: url("data:image/svg+xml,%3Csvg width='24' height='24' stroke='black' viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cg transform-origin='center'%3E%3Ccircle cx='12' cy='12' r='9.5' fill='none' stroke-width='3' stroke-linecap='round'%3E%3CanimateTransform attributeName='transform' type='rotate' from='0 12 12' to='360 12 12' dur='2s' repeatCount='indefinite'/%3E%3Canimate attributeName='stroke-dasharray' values='0,150;42,150;42,150' keyTimes='0;0.475;1' dur='1.5s' repeatCount='indefinite'/%3E%3Canimate attributeName='stroke-dashoffset' values='0;-16;-59' keyTimes='0;0.475;1' dur='1.5s' repeatCount='indefinite'/%3E%3C/circle%3E%3C/g%3E%3C/svg%3E");
|
||||
}
|
||||
.mask-repeat {
|
||||
mask-repeat: repeat;
|
||||
}
|
||||
.fill-current {
|
||||
fill: currentcolor;
|
||||
}
|
||||
@@ -2111,6 +2184,9 @@
|
||||
.p-8 {
|
||||
padding: calc(var(--spacing) * 8);
|
||||
}
|
||||
.px-1 {
|
||||
padding-inline: calc(var(--spacing) * 1);
|
||||
}
|
||||
.px-1\.5 {
|
||||
padding-inline: calc(var(--spacing) * 1.5);
|
||||
}
|
||||
@@ -2265,6 +2341,9 @@
|
||||
--tw-tracking: var(--tracking-widest);
|
||||
letter-spacing: var(--tracking-widest);
|
||||
}
|
||||
.text-wrap {
|
||||
text-wrap: wrap;
|
||||
}
|
||||
.break-words {
|
||||
overflow-wrap: break-word;
|
||||
}
|
||||
@@ -2331,6 +2410,17 @@
|
||||
.italic {
|
||||
font-style: italic;
|
||||
}
|
||||
.underline {
|
||||
text-decoration-line: underline;
|
||||
}
|
||||
.swap-active {
|
||||
.swap-off {
|
||||
opacity: 0%;
|
||||
}
|
||||
.swap-on {
|
||||
opacity: 100%;
|
||||
}
|
||||
}
|
||||
.opacity-0 {
|
||||
opacity: 0%;
|
||||
}
|
||||
@@ -2424,6 +2514,10 @@
|
||||
--tw-duration: 300ms;
|
||||
transition-duration: 300ms;
|
||||
}
|
||||
.ease-in-out {
|
||||
--tw-ease: var(--ease-in-out);
|
||||
transition-timing-function: var(--ease-in-out);
|
||||
}
|
||||
.ease-out {
|
||||
--tw-ease: var(--ease-out);
|
||||
transition-timing-function: var(--ease-out);
|
||||
|
||||
@@ -233,8 +233,7 @@ fn plan_embedding_settings_update(
|
||||
.as_deref()
|
||||
.map(str::trim)
|
||||
.filter(|value| !value.is_empty())
|
||||
.map(ToOwned::to_owned)
|
||||
.unwrap_or_else(|| current.embedding_model.clone());
|
||||
.map_or_else(|| current.embedding_model.clone(), ToOwned::to_owned);
|
||||
|
||||
if !is_valid_fastembed_model_code(&embedding_model) {
|
||||
return Err(AppError::Validation(format!(
|
||||
|
||||
@@ -77,7 +77,7 @@ pub async fn extract_text_from_file(
|
||||
let file_bytes = storage
|
||||
.get(&file_info.path)
|
||||
.await
|
||||
.map_err(AppError::Storage)?;
|
||||
.map_err(AppError::from)?;
|
||||
let local_path = resolve_existing_local_path(storage, &file_info.path).await;
|
||||
|
||||
match file_info.mime_type.as_str() {
|
||||
|
||||
Reference in New Issue
Block a user