mirror of
https://github.com/perstarkse/minne.git
synced 2026-03-13 05:45:35 +01:00
refactor: html routes finished
This commit is contained in:
@@ -9,10 +9,9 @@ use axum::{
|
||||
};
|
||||
use axum_session_auth::AuthSession;
|
||||
use axum_session_surreal::SessionSurrealPool;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use surrealdb::{engine::any::Any, Surreal};
|
||||
use tracing::info;
|
||||
|
||||
use crate::routes::HtmlError;
|
||||
use common::{
|
||||
error::AppError,
|
||||
storage::types::{
|
||||
@@ -22,7 +21,11 @@ use common::{
|
||||
},
|
||||
};
|
||||
|
||||
use crate::{html_state::HtmlState, page_data, routes::render_template};
|
||||
use crate::{
|
||||
html_state::HtmlState,
|
||||
middleware_auth::RequireUser,
|
||||
template_response::{HtmlError, TemplateResponse},
|
||||
};
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct ChatStartParams {
|
||||
@@ -41,25 +44,19 @@ where
|
||||
serde_json::from_str(&s).map_err(serde::de::Error::custom)
|
||||
}
|
||||
|
||||
page_data!(ChatData, "chat/base.html", {
|
||||
#[derive(Serialize)]
|
||||
pub struct ChatPageData {
|
||||
user: User,
|
||||
history: Vec<Message>,
|
||||
conversation: Option<Conversation>,
|
||||
conversation_archive: Vec<Conversation>
|
||||
});
|
||||
conversation_archive: Vec<Conversation>,
|
||||
}
|
||||
|
||||
pub async fn show_initialized_chat(
|
||||
State(state): State<HtmlState>,
|
||||
auth: AuthSession<User, String, SessionSurrealPool<Any>, Surreal<Any>>,
|
||||
RequireUser(user): RequireUser,
|
||||
Form(form): Form<ChatStartParams>,
|
||||
) -> Result<impl IntoResponse, HtmlError> {
|
||||
info!("Displaying chat start");
|
||||
|
||||
let user = match auth.current_user {
|
||||
Some(user) => user,
|
||||
None => return Ok(Redirect::to("/").into_response()),
|
||||
};
|
||||
|
||||
let conversation = Conversation::new(user.id.clone(), "Test".to_owned());
|
||||
|
||||
let user_message = Message::new(
|
||||
@@ -76,69 +73,48 @@ pub async fn show_initialized_chat(
|
||||
Some(form.references),
|
||||
);
|
||||
|
||||
let (conversation_result, ai_message_result, user_message_result) = futures::join!(
|
||||
state.db.store_item(conversation.clone()),
|
||||
state.db.store_item(ai_message.clone()),
|
||||
state.db.store_item(user_message.clone())
|
||||
);
|
||||
state.db.store_item(conversation.clone()).await?;
|
||||
state.db.store_item(ai_message.clone()).await?;
|
||||
state.db.store_item(user_message.clone()).await?;
|
||||
|
||||
// Check each result individually
|
||||
conversation_result.map_err(|e| HtmlError::new(AppError::from(e), state.templates.clone()))?;
|
||||
user_message_result.map_err(|e| HtmlError::new(AppError::from(e), state.templates.clone()))?;
|
||||
ai_message_result.map_err(|e| HtmlError::new(AppError::from(e), state.templates.clone()))?;
|
||||
|
||||
let conversation_archive = User::get_user_conversations(&user.id, &state.db)
|
||||
.await
|
||||
.map_err(|e| HtmlError::new(e, state.templates.clone()))?;
|
||||
let conversation_archive = User::get_user_conversations(&user.id, &state.db).await?;
|
||||
|
||||
let messages = vec![user_message, ai_message];
|
||||
|
||||
let output = render_template(
|
||||
ChatData::template_name(),
|
||||
ChatData {
|
||||
let mut response = TemplateResponse::new_template(
|
||||
"chat/base.html",
|
||||
ChatPageData {
|
||||
history: messages,
|
||||
user,
|
||||
conversation_archive,
|
||||
conversation: Some(conversation.clone()),
|
||||
},
|
||||
state.templates.clone(),
|
||||
)?;
|
||||
)
|
||||
.into_response();
|
||||
|
||||
let mut response = output.into_response();
|
||||
response.headers_mut().insert(
|
||||
"HX-Push",
|
||||
HeaderValue::from_str(&format!("/chat/{}", conversation.id)).unwrap(),
|
||||
);
|
||||
|
||||
Ok(response)
|
||||
}
|
||||
|
||||
pub async fn show_chat_base(
|
||||
State(state): State<HtmlState>,
|
||||
auth: AuthSession<User, String, SessionSurrealPool<Any>, Surreal<Any>>,
|
||||
RequireUser(user): RequireUser,
|
||||
) -> Result<impl IntoResponse, HtmlError> {
|
||||
info!("Displaying empty chat start");
|
||||
let conversation_archive = User::get_user_conversations(&user.id, &state.db).await?;
|
||||
|
||||
let user = match auth.current_user {
|
||||
Some(user) => user,
|
||||
None => return Ok(Redirect::to("/").into_response()),
|
||||
};
|
||||
|
||||
let conversation_archive = User::get_user_conversations(&user.id, &state.db)
|
||||
.await
|
||||
.map_err(|e| HtmlError::new(e, state.templates.clone()))?;
|
||||
|
||||
let output = render_template(
|
||||
ChatData::template_name(),
|
||||
ChatData {
|
||||
Ok(TemplateResponse::new_template(
|
||||
"chat/base.html",
|
||||
ChatPageData {
|
||||
history: vec![],
|
||||
user,
|
||||
conversation_archive,
|
||||
conversation: None,
|
||||
},
|
||||
state.templates.clone(),
|
||||
)?;
|
||||
|
||||
Ok(output.into_response())
|
||||
))
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
@@ -149,92 +125,61 @@ pub struct NewMessageForm {
|
||||
pub async fn show_existing_chat(
|
||||
Path(conversation_id): Path<String>,
|
||||
State(state): State<HtmlState>,
|
||||
auth: AuthSession<User, String, SessionSurrealPool<Any>, Surreal<Any>>,
|
||||
RequireUser(user): RequireUser,
|
||||
) -> Result<impl IntoResponse, HtmlError> {
|
||||
info!("Displaying initialized chat with id: {}", conversation_id);
|
||||
|
||||
let user = match auth.current_user {
|
||||
Some(user) => user,
|
||||
None => return Ok(Redirect::to("/").into_response()),
|
||||
};
|
||||
|
||||
let conversation_archive = User::get_user_conversations(&user.id, &state.db)
|
||||
.await
|
||||
.map_err(|e| HtmlError::new(e, state.templates.clone()))?;
|
||||
let conversation_archive = User::get_user_conversations(&user.id, &state.db).await?;
|
||||
|
||||
let (conversation, messages) =
|
||||
Conversation::get_complete_conversation(conversation_id.as_str(), &user.id, &state.db)
|
||||
.await
|
||||
.map_err(|e| HtmlError::new(e, state.templates.clone()))?;
|
||||
.await?;
|
||||
|
||||
let output = render_template(
|
||||
ChatData::template_name(),
|
||||
ChatData {
|
||||
Ok(TemplateResponse::new_template(
|
||||
"chat/base.html",
|
||||
ChatPageData {
|
||||
history: messages,
|
||||
user,
|
||||
conversation: Some(conversation.clone()),
|
||||
conversation_archive,
|
||||
},
|
||||
state.templates.clone(),
|
||||
)?;
|
||||
|
||||
Ok(output.into_response())
|
||||
))
|
||||
}
|
||||
|
||||
pub async fn new_user_message(
|
||||
Path(conversation_id): Path<String>,
|
||||
State(state): State<HtmlState>,
|
||||
auth: AuthSession<User, String, SessionSurrealPool<Any>, Surreal<Any>>,
|
||||
RequireUser(user): RequireUser,
|
||||
Form(form): Form<NewMessageForm>,
|
||||
) -> Result<impl IntoResponse, HtmlError> {
|
||||
let user = match auth.current_user {
|
||||
Some(user) => user,
|
||||
None => return Ok(Redirect::to("/").into_response()),
|
||||
};
|
||||
|
||||
let conversation: Conversation = state
|
||||
.db
|
||||
.get_item(&conversation_id)
|
||||
.await
|
||||
.map_err(|e| HtmlError::new(AppError::from(e), state.templates.clone()))?
|
||||
.ok_or_else(|| {
|
||||
HtmlError::new(
|
||||
AppError::NotFound("Conversation was not found".to_string()),
|
||||
state.templates.clone(),
|
||||
)
|
||||
})?;
|
||||
.await?
|
||||
.ok_or_else(|| AppError::NotFound("Conversation was not found".into()))?;
|
||||
|
||||
if conversation.user_id != user.id {
|
||||
return Err(HtmlError::new(
|
||||
AppError::Auth("The user does not have permission for this conversation".to_string()),
|
||||
state.templates.clone(),
|
||||
));
|
||||
return Ok(TemplateResponse::unauthorized().into_response());
|
||||
};
|
||||
|
||||
let user_message = Message::new(conversation_id, MessageRole::User, form.content, None);
|
||||
|
||||
state
|
||||
.db
|
||||
.store_item(user_message.clone())
|
||||
.await
|
||||
.map_err(|e| HtmlError::new(AppError::from(e), state.templates.clone()))?;
|
||||
state.db.store_item(user_message.clone()).await?;
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct SSEResponseInitData {
|
||||
user_message: Message,
|
||||
}
|
||||
|
||||
let output = render_template(
|
||||
let mut response = TemplateResponse::new_template(
|
||||
"chat/streaming_response.html",
|
||||
SSEResponseInitData { user_message },
|
||||
state.templates.clone(),
|
||||
)?;
|
||||
)
|
||||
.into_response();
|
||||
|
||||
let mut response = output.into_response();
|
||||
response.headers_mut().insert(
|
||||
"HX-Push",
|
||||
HeaderValue::from_str(&format!("/chat/{}", conversation.id)).unwrap(),
|
||||
);
|
||||
|
||||
Ok(response)
|
||||
}
|
||||
|
||||
@@ -256,36 +201,27 @@ pub async fn new_chat_user_message(
|
||||
None,
|
||||
);
|
||||
|
||||
state
|
||||
.db
|
||||
.store_item(conversation.clone())
|
||||
.await
|
||||
.map_err(|e| HtmlError::new(AppError::from(e), state.templates.clone()))?;
|
||||
state
|
||||
.db
|
||||
.store_item(user_message.clone())
|
||||
.await
|
||||
.map_err(|e| HtmlError::new(AppError::from(e), state.templates.clone()))?;
|
||||
state.db.store_item(conversation.clone()).await?;
|
||||
state.db.store_item(user_message.clone()).await?;
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct SSEResponseInitData {
|
||||
user_message: Message,
|
||||
conversation: Conversation,
|
||||
}
|
||||
|
||||
let output = render_template(
|
||||
let mut response = TemplateResponse::new_template(
|
||||
"chat/new_chat_first_response.html",
|
||||
SSEResponseInitData {
|
||||
user_message,
|
||||
conversation: conversation.clone(),
|
||||
},
|
||||
state.templates.clone(),
|
||||
)?;
|
||||
)
|
||||
.into_response();
|
||||
|
||||
let mut response = output.into_response();
|
||||
response.headers_mut().insert(
|
||||
"HX-Push",
|
||||
HeaderValue::from_str(&format!("/chat/{}", conversation.id)).unwrap(),
|
||||
);
|
||||
|
||||
Ok(response)
|
||||
}
|
||||
|
||||
@@ -1,50 +1,33 @@
|
||||
use axum::{
|
||||
extract::{Path, State},
|
||||
response::{IntoResponse, Redirect},
|
||||
response::IntoResponse,
|
||||
};
|
||||
use axum_session_auth::AuthSession;
|
||||
use axum_session_surreal::SessionSurrealPool;
|
||||
use serde::Serialize;
|
||||
use surrealdb::{engine::any::Any, Surreal};
|
||||
use tracing::info;
|
||||
|
||||
use crate::routes::HtmlError;
|
||||
use common::{
|
||||
error::AppError,
|
||||
storage::types::{knowledge_entity::KnowledgeEntity, user::User},
|
||||
};
|
||||
|
||||
use crate::{html_state::HtmlState, routes::render_template};
|
||||
use crate::{
|
||||
html_state::HtmlState,
|
||||
middleware_auth::RequireUser,
|
||||
template_response::{HtmlError, TemplateResponse},
|
||||
};
|
||||
|
||||
pub async fn show_reference_tooltip(
|
||||
State(state): State<HtmlState>,
|
||||
auth: AuthSession<User, String, SessionSurrealPool<Any>, Surreal<Any>>,
|
||||
RequireUser(user): RequireUser,
|
||||
Path(reference_id): Path<String>,
|
||||
) -> Result<impl IntoResponse, HtmlError> {
|
||||
info!("Showing reference");
|
||||
|
||||
let user = match auth.current_user {
|
||||
Some(user) => user,
|
||||
None => return Ok(Redirect::to("/").into_response()),
|
||||
};
|
||||
|
||||
let entity: KnowledgeEntity = state
|
||||
.db
|
||||
.get_item(&reference_id)
|
||||
.await
|
||||
.map_err(|e| HtmlError::new(AppError::from(e), state.templates.clone()))?
|
||||
.ok_or_else(|| {
|
||||
HtmlError::new(
|
||||
AppError::NotFound("Item was not found".to_string()),
|
||||
state.templates.clone(),
|
||||
)
|
||||
})?;
|
||||
.await?
|
||||
.ok_or_else(|| AppError::NotFound("Item was not found".to_string()))?;
|
||||
|
||||
if entity.user_id != user.id {
|
||||
return Err(HtmlError::new(
|
||||
AppError::Auth("You dont have access to this entity".to_string()),
|
||||
state.templates.clone(),
|
||||
));
|
||||
return Ok(TemplateResponse::unauthorized());
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
@@ -53,11 +36,8 @@ pub async fn show_reference_tooltip(
|
||||
user: User,
|
||||
}
|
||||
|
||||
let output = render_template(
|
||||
Ok(TemplateResponse::new_template(
|
||||
"chat/reference_tooltip.html",
|
||||
ReferenceTooltipData { entity, user },
|
||||
state.templates.clone(),
|
||||
)?;
|
||||
|
||||
Ok(output.into_response())
|
||||
))
|
||||
}
|
||||
|
||||
@@ -1,46 +1,36 @@
|
||||
use axum::{
|
||||
extract::{Path, State},
|
||||
response::{IntoResponse, Redirect},
|
||||
response::IntoResponse,
|
||||
};
|
||||
use axum_session_auth::AuthSession;
|
||||
use axum_session_surreal::SessionSurrealPool;
|
||||
use surrealdb::{engine::any::Any, Surreal};
|
||||
use serde::Serialize;
|
||||
|
||||
use common::storage::types::{text_content::TextContent, user::User};
|
||||
|
||||
use crate::{error::HtmlError, html_state::HtmlState, page_data};
|
||||
use crate::{
|
||||
html_state::HtmlState,
|
||||
middleware_auth::RequireUser,
|
||||
template_response::{HtmlError, TemplateResponse},
|
||||
};
|
||||
|
||||
use super::render_template;
|
||||
|
||||
page_data!(ContentPageData, "content/base.html", {
|
||||
#[derive(Serialize)]
|
||||
pub struct ContentPageData {
|
||||
user: User,
|
||||
text_contents: Vec<TextContent>
|
||||
});
|
||||
text_contents: Vec<TextContent>,
|
||||
}
|
||||
|
||||
pub async fn show_content_page(
|
||||
State(state): State<HtmlState>,
|
||||
auth: AuthSession<User, String, SessionSurrealPool<Any>, Surreal<Any>>,
|
||||
RequireUser(user): RequireUser,
|
||||
) -> Result<impl IntoResponse, HtmlError> {
|
||||
// Early return if the user is not authenticated
|
||||
let user = match auth.current_user {
|
||||
Some(user) => user,
|
||||
None => return Ok(Redirect::to("/signin").into_response()),
|
||||
};
|
||||
let text_contents = User::get_text_contents(&user.id, &state.db).await?;
|
||||
|
||||
let text_contents = User::get_text_contents(&user.id, &state.db)
|
||||
.await
|
||||
.map_err(|e| HtmlError::new(e, state.templates.clone()))?;
|
||||
|
||||
let output = render_template(
|
||||
ContentPageData::template_name(),
|
||||
Ok(TemplateResponse::new_template(
|
||||
"content/base.html",
|
||||
ContentPageData {
|
||||
user,
|
||||
text_contents,
|
||||
},
|
||||
state.templates,
|
||||
)?;
|
||||
|
||||
Ok(output.into_response())
|
||||
))
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
@@ -51,57 +41,33 @@ pub struct TextContentEditModal {
|
||||
|
||||
pub async fn show_text_content_edit_form(
|
||||
State(state): State<HtmlState>,
|
||||
auth: AuthSession<User, String, SessionSurrealPool<Any>, Surreal<Any>>,
|
||||
RequireUser(user): RequireUser,
|
||||
Path(id): Path<String>,
|
||||
) -> Result<impl IntoResponse, HtmlError> {
|
||||
// Early return if the user is not authenticated
|
||||
let user = match auth.current_user {
|
||||
Some(user) => user,
|
||||
None => return Ok(Redirect::to("/signin").into_response()),
|
||||
};
|
||||
let text_content = User::get_and_validate_text_content(&id, &user.id, &state.db).await?;
|
||||
|
||||
let text_content = User::get_and_validate_text_content(&id, &user.id, &state.db)
|
||||
.await
|
||||
.map_err(|e| HtmlError::new(e, state.templates.clone()))?;
|
||||
|
||||
let output = render_template(
|
||||
Ok(TemplateResponse::new_template(
|
||||
"content/edit_text_content_modal.html",
|
||||
TextContentEditModal { user, text_content },
|
||||
state.templates,
|
||||
)?;
|
||||
|
||||
Ok(output.into_response())
|
||||
))
|
||||
}
|
||||
|
||||
pub async fn patch_text_content(
|
||||
State(state): State<HtmlState>,
|
||||
auth: AuthSession<User, String, SessionSurrealPool<Any>, Surreal<Any>>,
|
||||
RequireUser(user): RequireUser,
|
||||
Path(id): Path<String>,
|
||||
) -> Result<impl IntoResponse, HtmlError> {
|
||||
// Early return if the user is not authenticated
|
||||
let user = match auth.current_user {
|
||||
Some(user) => user,
|
||||
None => return Ok(Redirect::to("/signin").into_response()),
|
||||
};
|
||||
|
||||
let text_content = User::get_and_validate_text_content(&id, &user.id, &state.db)
|
||||
.await
|
||||
.map_err(|e| HtmlError::new(e, state.templates.clone()))?;
|
||||
let text_content = User::get_and_validate_text_content(&id, &user.id, &state.db).await?;
|
||||
|
||||
// ADD FUNCTION TO PATCH CONTENT
|
||||
|
||||
let text_contents = User::get_text_contents(&user.id, &state.db)
|
||||
.await
|
||||
.map_err(|e| HtmlError::new(e, state.templates.clone()))?;
|
||||
let text_contents = User::get_text_contents(&user.id, &state.db).await?;
|
||||
|
||||
let output = render_template(
|
||||
Ok(TemplateResponse::new_template(
|
||||
"content/content_list.html",
|
||||
ContentPageData {
|
||||
user,
|
||||
text_contents,
|
||||
},
|
||||
state.templates,
|
||||
)?;
|
||||
|
||||
Ok(output.into_response())
|
||||
))
|
||||
}
|
||||
|
||||
@@ -83,7 +83,7 @@ pub async fn delete_text_content(
|
||||
let text_content = get_and_validate_text_content(&state, &id, &user).await?;
|
||||
|
||||
// Perform concurrent deletions
|
||||
join!(
|
||||
let (_res1, _res2, _res3, _res4, _res5) = join!(
|
||||
async {
|
||||
if let Some(file_info) = text_content.file_info {
|
||||
FileInfo::delete_by_id(&file_info.id, &state.db).await
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
use axum::{
|
||||
extract::State,
|
||||
response::{Html, IntoResponse, Redirect},
|
||||
response::{Html, IntoResponse},
|
||||
};
|
||||
use axum_session_auth::AuthSession;
|
||||
use axum_session_surreal::SessionSurrealPool;
|
||||
use axum_typed_multipart::{FieldData, TryFromMultipart, TypedMultipart};
|
||||
use futures::{future::try_join_all, TryFutureExt};
|
||||
use surrealdb::{engine::any::Any, Surreal};
|
||||
use serde::Serialize;
|
||||
use tempfile::NamedTempFile;
|
||||
use tracing::info;
|
||||
|
||||
@@ -19,47 +17,32 @@ use common::{
|
||||
};
|
||||
|
||||
use crate::{
|
||||
error::{HtmlError, IntoHtmlError},
|
||||
html_state::HtmlState,
|
||||
page_data,
|
||||
routes::{index::ActiveJobsData, render_block},
|
||||
middleware_auth::RequireUser,
|
||||
routes::index::ActiveJobsData,
|
||||
template_response::{HtmlError, TemplateResponse},
|
||||
};
|
||||
|
||||
use super::render_template;
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct ShowIngressFormData {
|
||||
user_categories: Vec<String>,
|
||||
}
|
||||
|
||||
pub async fn show_ingress_form(
|
||||
State(state): State<HtmlState>,
|
||||
auth: AuthSession<User, String, SessionSurrealPool<Any>, Surreal<Any>>,
|
||||
RequireUser(user): RequireUser,
|
||||
) -> Result<impl IntoResponse, HtmlError> {
|
||||
if !auth.is_authenticated() {
|
||||
return Ok(Redirect::to("/").into_response());
|
||||
let user_categories = User::get_user_categories(&user.id, &state.db).await?;
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct ShowIngressFormData {
|
||||
user_categories: Vec<String>,
|
||||
}
|
||||
|
||||
let user_categories = User::get_user_categories(&auth.id, &state.db)
|
||||
.await
|
||||
.map_err(|e| HtmlError::new(e, state.templates.clone()))?;
|
||||
|
||||
let output = render_template(
|
||||
Ok(TemplateResponse::new_template(
|
||||
"index/signed_in/ingress_modal.html",
|
||||
ShowIngressFormData { user_categories },
|
||||
state.templates.clone(),
|
||||
)?;
|
||||
|
||||
Ok(output.into_response())
|
||||
))
|
||||
}
|
||||
|
||||
pub async fn hide_ingress_form(
|
||||
auth: AuthSession<User, String, SessionSurrealPool<Any>, Surreal<Any>>,
|
||||
RequireUser(_user): RequireUser,
|
||||
) -> Result<impl IntoResponse, HtmlError> {
|
||||
if !auth.is_authenticated() {
|
||||
return Ok(Redirect::to("/").into_response());
|
||||
}
|
||||
|
||||
Ok(Html(
|
||||
"<a class='btn btn-primary' hx-get='/ingress-form' hx-swap='outerHTML'>Add Content</a>",
|
||||
)
|
||||
@@ -76,43 +59,39 @@ pub struct IngressParams {
|
||||
pub files: Vec<FieldData<NamedTempFile>>,
|
||||
}
|
||||
|
||||
page_data!(IngressFormData, "ingress_form.html", {
|
||||
instructions: String,
|
||||
content: String,
|
||||
category: String,
|
||||
error: String,
|
||||
});
|
||||
|
||||
pub async fn process_ingress_form(
|
||||
State(state): State<HtmlState>,
|
||||
auth: AuthSession<User, String, SessionSurrealPool<Any>, Surreal<Any>>,
|
||||
RequireUser(user): RequireUser,
|
||||
TypedMultipart(input): TypedMultipart<IngressParams>,
|
||||
) -> Result<impl IntoResponse, HtmlError> {
|
||||
let user = auth.current_user.ok_or_else(|| {
|
||||
AppError::Auth("You must be signed in".to_string()).with_template(state.templates.clone())
|
||||
})?;
|
||||
#[derive(Serialize)]
|
||||
pub struct IngressFormData {
|
||||
instructions: String,
|
||||
content: String,
|
||||
category: String,
|
||||
error: String,
|
||||
}
|
||||
|
||||
if input.content.clone().is_some_and(|c| c.len() < 2) && input.files.is_empty() {
|
||||
let output = render_template(
|
||||
IngressFormData::template_name(),
|
||||
if input.content.as_ref().map_or(true, |c| c.len() < 2) && input.files.is_empty() {
|
||||
return Ok(TemplateResponse::new_template(
|
||||
"index/signed_in/ingress_form.html",
|
||||
IngressFormData {
|
||||
instructions: input.instructions.clone(),
|
||||
content: input.content.clone().unwrap(),
|
||||
content: input.content.clone().unwrap_or_default(),
|
||||
category: input.category.clone(),
|
||||
error: "You need to either add files or content".to_string(),
|
||||
},
|
||||
state.templates.clone(),
|
||||
)?;
|
||||
|
||||
return Ok(output.into_response());
|
||||
));
|
||||
}
|
||||
|
||||
info!("{:?}", input);
|
||||
|
||||
let file_infos = try_join_all(input.files.into_iter().map(|file| {
|
||||
FileInfo::new(file, &state.db, &user.id)
|
||||
.map_err(|e| HtmlError::new(AppError::from(e), state.templates.clone()))
|
||||
}))
|
||||
let file_infos = try_join_all(
|
||||
input
|
||||
.files
|
||||
.into_iter()
|
||||
.map(|file| FileInfo::new(file, &state.db, &user.id).map_err(|e| AppError::from(e))),
|
||||
)
|
||||
.await?;
|
||||
|
||||
let payloads = IngestionPayload::create_ingestion_payload(
|
||||
@@ -121,8 +100,7 @@ pub async fn process_ingress_form(
|
||||
input.category,
|
||||
file_infos,
|
||||
user.id.as_str(),
|
||||
)
|
||||
.map_err(|e| HtmlError::new(e, state.templates.clone()))?;
|
||||
)?;
|
||||
|
||||
let futures: Vec<_> = payloads
|
||||
.into_iter()
|
||||
@@ -131,25 +109,17 @@ pub async fn process_ingress_form(
|
||||
})
|
||||
.collect();
|
||||
|
||||
try_join_all(futures)
|
||||
.await
|
||||
.map_err(AppError::from)
|
||||
.map_err(|e| HtmlError::new(e, state.templates.clone()))?;
|
||||
try_join_all(futures).await?;
|
||||
|
||||
// Update the active jobs page with the newly created job
|
||||
let active_jobs = User::get_unfinished_ingestion_tasks(&user.id, &state.db)
|
||||
.await
|
||||
.map_err(|e| HtmlError::new(e, state.templates.clone()))?;
|
||||
let active_jobs = User::get_unfinished_ingestion_tasks(&user.id, &state.db).await?;
|
||||
|
||||
let output = render_block(
|
||||
Ok(TemplateResponse::new_partial(
|
||||
"index/signed_in/active_jobs.html",
|
||||
"active_jobs_section",
|
||||
ActiveJobsData {
|
||||
user: user.clone(),
|
||||
active_jobs,
|
||||
},
|
||||
state.templates.clone(),
|
||||
)?;
|
||||
|
||||
Ok(output.into_response())
|
||||
))
|
||||
}
|
||||
|
||||
@@ -1,55 +1,42 @@
|
||||
use axum::{
|
||||
extract::{Path, State},
|
||||
response::{IntoResponse, Redirect},
|
||||
response::IntoResponse,
|
||||
Form,
|
||||
};
|
||||
use axum_session_auth::AuthSession;
|
||||
use axum_session_surreal::SessionSurrealPool;
|
||||
use plotly::{
|
||||
common::{Line, Marker, Mode},
|
||||
layout::{Axis, Camera, LayoutScene, ProjectionType},
|
||||
Layout, Plot, Scatter3D,
|
||||
};
|
||||
use surrealdb::{engine::any::Any, Surreal};
|
||||
use tracing::info;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use common::{
|
||||
error::AppError,
|
||||
storage::types::{
|
||||
knowledge_entity::{KnowledgeEntity, KnowledgeEntityType},
|
||||
knowledge_relationship::KnowledgeRelationship,
|
||||
user::User,
|
||||
},
|
||||
use common::storage::types::{
|
||||
knowledge_entity::{KnowledgeEntity, KnowledgeEntityType},
|
||||
knowledge_relationship::KnowledgeRelationship,
|
||||
user::User,
|
||||
};
|
||||
|
||||
use crate::{error::HtmlError, html_state::HtmlState, page_data, routes::render_template};
|
||||
|
||||
page_data!(KnowledgeBaseData, "knowledge/base.html", {
|
||||
entities: Vec<KnowledgeEntity>,
|
||||
relationships: Vec<KnowledgeRelationship>,
|
||||
user: User,
|
||||
plot_html: String
|
||||
});
|
||||
use crate::{
|
||||
html_state::HtmlState,
|
||||
middleware_auth::RequireUser,
|
||||
template_response::{HtmlError, TemplateResponse},
|
||||
};
|
||||
|
||||
pub async fn show_knowledge_page(
|
||||
State(state): State<HtmlState>,
|
||||
auth: AuthSession<User, String, SessionSurrealPool<Any>, Surreal<Any>>,
|
||||
RequireUser(user): RequireUser,
|
||||
) -> Result<impl IntoResponse, HtmlError> {
|
||||
// Early return if the user is not authenticated
|
||||
let user = match auth.current_user {
|
||||
Some(user) => user,
|
||||
None => return Ok(Redirect::to("/signin").into_response()),
|
||||
};
|
||||
#[derive(Serialize)]
|
||||
pub struct KnowledgeBaseData {
|
||||
entities: Vec<KnowledgeEntity>,
|
||||
relationships: Vec<KnowledgeRelationship>,
|
||||
user: User,
|
||||
plot_html: String,
|
||||
}
|
||||
|
||||
let entities = User::get_knowledge_entities(&user.id, &state.db)
|
||||
.await
|
||||
.map_err(|e| HtmlError::new(e, state.templates.clone()))?;
|
||||
let entities = User::get_knowledge_entities(&user.id, &state.db).await?;
|
||||
|
||||
info!("Got entities ok");
|
||||
|
||||
let relationships = User::get_knowledge_relationships(&user.id, &state.db)
|
||||
.await
|
||||
.map_err(|e| HtmlError::new(e, state.templates.clone()))?;
|
||||
let relationships = User::get_knowledge_relationships(&user.id, &state.db).await?;
|
||||
|
||||
let mut plot = Plot::new();
|
||||
|
||||
@@ -124,40 +111,32 @@ pub async fn show_knowledge_page(
|
||||
.plot_background_color("rbga(0,0,0,0)");
|
||||
|
||||
plot.set_layout(layout);
|
||||
|
||||
// Convert to HTML
|
||||
let html = plot.to_html();
|
||||
|
||||
let output = render_template(
|
||||
KnowledgeBaseData::template_name(),
|
||||
Ok(TemplateResponse::new_template(
|
||||
"knowledge/base.html",
|
||||
KnowledgeBaseData {
|
||||
entities,
|
||||
relationships,
|
||||
user,
|
||||
plot_html: html,
|
||||
},
|
||||
state.templates,
|
||||
)?;
|
||||
|
||||
Ok(output.into_response())
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct EntityData {
|
||||
entity: KnowledgeEntity,
|
||||
entity_types: Vec<String>,
|
||||
user: User,
|
||||
))
|
||||
}
|
||||
|
||||
pub async fn show_edit_knowledge_entity_form(
|
||||
State(state): State<HtmlState>,
|
||||
auth: AuthSession<User, String, SessionSurrealPool<Any>, Surreal<Any>>,
|
||||
RequireUser(user): RequireUser,
|
||||
Path(id): Path<String>,
|
||||
) -> Result<impl IntoResponse, HtmlError> {
|
||||
// Early return if the user is not authenticated
|
||||
let user = match auth.current_user {
|
||||
Some(user) => user,
|
||||
None => return Ok(Redirect::to("/signin").into_response()),
|
||||
};
|
||||
#[derive(Serialize)]
|
||||
pub struct EntityData {
|
||||
entity: KnowledgeEntity,
|
||||
entity_types: Vec<String>,
|
||||
user: User,
|
||||
}
|
||||
|
||||
// Get entity types
|
||||
let entity_types: Vec<String> = KnowledgeEntityType::variants()
|
||||
@@ -166,27 +145,16 @@ pub async fn show_edit_knowledge_entity_form(
|
||||
.collect();
|
||||
|
||||
// Get the entity and validate ownership
|
||||
let entity = User::get_and_validate_knowledge_entity(&id, &user.id, &state.db)
|
||||
.await
|
||||
.map_err(|e| HtmlError::new(e, state.templates.clone()))?;
|
||||
let entity = User::get_and_validate_knowledge_entity(&id, &user.id, &state.db).await?;
|
||||
|
||||
let output = render_template(
|
||||
Ok(TemplateResponse::new_template(
|
||||
"knowledge/edit_knowledge_entity_modal.html",
|
||||
EntityData {
|
||||
entity,
|
||||
user,
|
||||
entity_types,
|
||||
},
|
||||
state.templates,
|
||||
)?;
|
||||
|
||||
Ok(output.into_response())
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct EntityListData {
|
||||
entities: Vec<KnowledgeEntity>,
|
||||
user: User,
|
||||
))
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
@@ -197,21 +165,19 @@ pub struct PatchKnowledgeEntityParams {
|
||||
pub description: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct EntityListData {
|
||||
entities: Vec<KnowledgeEntity>,
|
||||
user: User,
|
||||
}
|
||||
|
||||
pub async fn patch_knowledge_entity(
|
||||
State(state): State<HtmlState>,
|
||||
auth: AuthSession<User, String, SessionSurrealPool<Any>, Surreal<Any>>,
|
||||
RequireUser(user): RequireUser,
|
||||
Form(form): Form<PatchKnowledgeEntityParams>,
|
||||
) -> Result<impl IntoResponse, HtmlError> {
|
||||
// Early return if the user is not authenticated
|
||||
let user = match auth.current_user {
|
||||
Some(user) => user,
|
||||
None => return Ok(Redirect::to("/signin").into_response()),
|
||||
};
|
||||
|
||||
// Get the existing entity and validate that the user is allowed
|
||||
User::get_and_validate_knowledge_entity(&form.id, &user.id, &state.db)
|
||||
.await
|
||||
.map_err(|e| HtmlError::new(e, state.templates.clone()))?;
|
||||
User::get_and_validate_knowledge_entity(&form.id, &user.id, &state.db).await?;
|
||||
|
||||
let entity_type: KnowledgeEntityType = KnowledgeEntityType::from(form.entity_type);
|
||||
|
||||
@@ -224,60 +190,36 @@ pub async fn patch_knowledge_entity(
|
||||
&state.db,
|
||||
&state.openai_client,
|
||||
)
|
||||
.await
|
||||
.map_err(|e| HtmlError::new(AppError::from(e), state.templates.clone()))?;
|
||||
.await?;
|
||||
|
||||
// Get updated list of entities
|
||||
let entities = User::get_knowledge_entities(&user.id, &state.db)
|
||||
.await
|
||||
.map_err(|e| HtmlError::new(e, state.templates.clone()))?;
|
||||
let entities = User::get_knowledge_entities(&user.id, &state.db).await?;
|
||||
|
||||
// Render updated list
|
||||
let output = render_template(
|
||||
Ok(TemplateResponse::new_template(
|
||||
"knowledge/entity_list.html",
|
||||
EntityListData { entities, user },
|
||||
state.templates,
|
||||
)?;
|
||||
|
||||
Ok(output.into_response())
|
||||
))
|
||||
}
|
||||
|
||||
pub async fn delete_knowledge_entity(
|
||||
State(state): State<HtmlState>,
|
||||
auth: AuthSession<User, String, SessionSurrealPool<Any>, Surreal<Any>>,
|
||||
RequireUser(user): RequireUser,
|
||||
Path(id): Path<String>,
|
||||
) -> Result<impl IntoResponse, HtmlError> {
|
||||
// Early return if the user is not authenticated
|
||||
let user = match auth.current_user {
|
||||
Some(user) => user,
|
||||
None => return Ok(Redirect::to("/signin").into_response()),
|
||||
};
|
||||
|
||||
// Get the existing entity and validate that the user is allowed
|
||||
User::get_and_validate_knowledge_entity(&id, &user.id, &state.db)
|
||||
.await
|
||||
.map_err(|e| HtmlError::new(e, state.templates.clone()))?;
|
||||
User::get_and_validate_knowledge_entity(&id, &user.id, &state.db).await?;
|
||||
|
||||
// Delete the entity
|
||||
state
|
||||
.db
|
||||
.delete_item::<KnowledgeEntity>(&id)
|
||||
.await
|
||||
.map_err(|e| HtmlError::new(AppError::from(e), state.templates.clone()))?;
|
||||
state.db.delete_item::<KnowledgeEntity>(&id).await?;
|
||||
|
||||
// Get updated list of entities
|
||||
let entities = User::get_knowledge_entities(&user.id, &state.db)
|
||||
.await
|
||||
.map_err(|e| HtmlError::new(e, state.templates.clone()))?;
|
||||
let entities = User::get_knowledge_entities(&user.id, &state.db).await?;
|
||||
|
||||
// Render updated list
|
||||
let output = render_template(
|
||||
Ok(TemplateResponse::new_template(
|
||||
"knowledge/entity_list.html",
|
||||
EntityListData { entities, user },
|
||||
state.templates,
|
||||
)?;
|
||||
|
||||
Ok(output.into_response())
|
||||
))
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
@@ -288,40 +230,25 @@ pub struct RelationshipTableData {
|
||||
|
||||
pub async fn delete_knowledge_relationship(
|
||||
State(state): State<HtmlState>,
|
||||
auth: AuthSession<User, String, SessionSurrealPool<Any>, Surreal<Any>>,
|
||||
RequireUser(user): RequireUser,
|
||||
Path(id): Path<String>,
|
||||
) -> Result<impl IntoResponse, HtmlError> {
|
||||
// Early return if the user is not authenticated
|
||||
let user = match auth.current_user {
|
||||
Some(user) => user,
|
||||
None => return Ok(Redirect::to("/signin").into_response()),
|
||||
};
|
||||
|
||||
// GOTTA ADD AUTH VALIDATION
|
||||
|
||||
KnowledgeRelationship::delete_relationship_by_id(&id, &state.db)
|
||||
.await
|
||||
.map_err(|e| HtmlError::new(e, state.templates.clone()))?;
|
||||
KnowledgeRelationship::delete_relationship_by_id(&id, &state.db).await?;
|
||||
|
||||
let entities = User::get_knowledge_entities(&user.id, &state.db)
|
||||
.await
|
||||
.map_err(|e| HtmlError::new(e, state.templates.clone()))?;
|
||||
let entities = User::get_knowledge_entities(&user.id, &state.db).await?;
|
||||
|
||||
let relationships = User::get_knowledge_relationships(&user.id, &state.db)
|
||||
.await
|
||||
.map_err(|e| HtmlError::new(e, state.templates.clone()))?;
|
||||
let relationships = User::get_knowledge_relationships(&user.id, &state.db).await?;
|
||||
|
||||
// Render updated list
|
||||
let output = render_template(
|
||||
Ok(TemplateResponse::new_template(
|
||||
"knowledge/relationship_table.html",
|
||||
RelationshipTableData {
|
||||
entities,
|
||||
relationships,
|
||||
},
|
||||
state.templates,
|
||||
)?;
|
||||
|
||||
Ok(output.into_response())
|
||||
))
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
@@ -333,15 +260,9 @@ pub struct SaveKnowledgeRelationshipInput {
|
||||
|
||||
pub async fn save_knowledge_relationship(
|
||||
State(state): State<HtmlState>,
|
||||
auth: AuthSession<User, String, SessionSurrealPool<Any>, Surreal<Any>>,
|
||||
RequireUser(user): RequireUser,
|
||||
Form(form): Form<SaveKnowledgeRelationshipInput>,
|
||||
) -> Result<impl IntoResponse, HtmlError> {
|
||||
// Early return if the user is not authenticated
|
||||
let user = match auth.current_user {
|
||||
Some(user) => user,
|
||||
None => return Ok(Redirect::to("/signin").into_response()),
|
||||
};
|
||||
|
||||
// Construct relationship
|
||||
let relationship = KnowledgeRelationship::new(
|
||||
form.in_,
|
||||
@@ -351,28 +272,18 @@ pub async fn save_knowledge_relationship(
|
||||
form.relationship_type,
|
||||
);
|
||||
|
||||
relationship
|
||||
.store_relationship(&state.db)
|
||||
.await
|
||||
.map_err(|e| HtmlError::new(e, state.templates.clone()))?;
|
||||
relationship.store_relationship(&state.db).await?;
|
||||
|
||||
let entities = User::get_knowledge_entities(&user.id, &state.db)
|
||||
.await
|
||||
.map_err(|e| HtmlError::new(e, state.templates.clone()))?;
|
||||
let entities = User::get_knowledge_entities(&user.id, &state.db).await?;
|
||||
|
||||
let relationships = User::get_knowledge_relationships(&user.id, &state.db)
|
||||
.await
|
||||
.map_err(|e| HtmlError::new(e, state.templates.clone()))?;
|
||||
let relationships = User::get_knowledge_relationships(&user.id, &state.db).await?;
|
||||
|
||||
// Render updated list
|
||||
let output = render_template(
|
||||
Ok(TemplateResponse::new_template(
|
||||
"knowledge/relationship_table.html",
|
||||
RelationshipTableData {
|
||||
entities,
|
||||
relationships,
|
||||
},
|
||||
state.templates,
|
||||
)?;
|
||||
|
||||
Ok(output.into_response())
|
||||
))
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ use std::sync::Arc;
|
||||
use axum::response::Html;
|
||||
use minijinja_autoreload::AutoReloader;
|
||||
|
||||
use crate::error::{HtmlError, IntoHtmlError};
|
||||
use crate::template_response::HtmlError;
|
||||
|
||||
pub mod account;
|
||||
pub mod admin_panel;
|
||||
@@ -19,73 +19,19 @@ pub mod signin;
|
||||
pub mod signout;
|
||||
pub mod signup;
|
||||
|
||||
// pub trait PageData {
|
||||
// fn template_name() -> &'static str;
|
||||
// }
|
||||
// Helper function for render_template
|
||||
pub fn render_template<T>(
|
||||
template_name: &str,
|
||||
context: T,
|
||||
templates: Arc<AutoReloader>,
|
||||
) -> Result<Html<String>, HtmlError>
|
||||
where
|
||||
T: serde::Serialize,
|
||||
{
|
||||
let env = templates.acquire_env().unwrap();
|
||||
let tmpl = env.get_template(template_name).unwrap();
|
||||
let context = minijinja::Value::from_serialize(&context);
|
||||
let output = tmpl.render(context).unwrap();
|
||||
|
||||
// // Helper function for render_template
|
||||
// pub fn render_template<T>(
|
||||
// template_name: &str,
|
||||
// context: T,
|
||||
// templates: Arc<AutoReloader>,
|
||||
// ) -> Result<Html<String>, HtmlError>
|
||||
// where
|
||||
// T: serde::Serialize,
|
||||
// {
|
||||
// let env = templates
|
||||
// .acquire_env()
|
||||
// .map_err(|e| e.with_template(templates.clone()))?;
|
||||
// let tmpl = env
|
||||
// .get_template(template_name)
|
||||
// .map_err(|e| e.with_template(templates.clone()))?;
|
||||
// let context = minijinja::Value::from_serialize(&context);
|
||||
// let output = tmpl
|
||||
// .render(context)
|
||||
// .map_err(|e| e.with_template(templates.clone()))?;
|
||||
// Ok(Html(output))
|
||||
// }
|
||||
|
||||
// pub fn render_block<T>(
|
||||
// template_name: &str,
|
||||
// block: &str,
|
||||
// context: T,
|
||||
// templates: Arc<AutoReloader>,
|
||||
// ) -> Result<Html<String>, HtmlError>
|
||||
// where
|
||||
// T: serde::Serialize,
|
||||
// {
|
||||
// let env = templates
|
||||
// .acquire_env()
|
||||
// .map_err(|e| e.with_template(templates.clone()))?;
|
||||
// let tmpl = env
|
||||
// .get_template(template_name)
|
||||
// .map_err(|e| e.with_template(templates.clone()))?;
|
||||
|
||||
// let context = minijinja::Value::from_serialize(&context);
|
||||
// let output = tmpl
|
||||
// .eval_to_state(context)
|
||||
// .map_err(|e| e.with_template(templates.clone()))?
|
||||
// .render_block(block)
|
||||
// .map_err(|e| e.with_template(templates.clone()))?;
|
||||
|
||||
// Ok(output.into())
|
||||
// }
|
||||
|
||||
// #[macro_export]
|
||||
// macro_rules! page_data {
|
||||
// ($name:ident, $template_name:expr, {$($(#[$attr:meta])* $field:ident: $ty:ty),*$(,)?}) => {
|
||||
// use serde::{Serialize, Deserialize};
|
||||
// use $crate::routes::PageData;
|
||||
|
||||
// #[derive(Debug, Deserialize, Serialize)]
|
||||
// pub struct $name {
|
||||
// $($(#[$attr])* pub $field: $ty),*
|
||||
// }
|
||||
|
||||
// impl PageData for $name {
|
||||
// fn template_name() -> &'static str {
|
||||
// $template_name
|
||||
// }
|
||||
// }
|
||||
// };
|
||||
// }
|
||||
Ok(Html(output))
|
||||
}
|
||||
|
||||
@@ -1,69 +1,42 @@
|
||||
use axum::{
|
||||
extract::{Query, State},
|
||||
response::{IntoResponse, Redirect},
|
||||
response::IntoResponse,
|
||||
};
|
||||
use axum_session_auth::AuthSession;
|
||||
use axum_session_surreal::SessionSurrealPool;
|
||||
use composite_retrieval::answer_retrieval::get_answer_with_references;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use surrealdb::{engine::any::Any, Surreal};
|
||||
use tracing::info;
|
||||
|
||||
use crate::routes::HtmlError;
|
||||
use common::storage::types::user::User;
|
||||
use crate::{
|
||||
html_state::HtmlState,
|
||||
middleware_auth::RequireUser,
|
||||
template_response::{HtmlError, TemplateResponse},
|
||||
};
|
||||
|
||||
use crate::{html_state::HtmlState, routes::render_template};
|
||||
#[derive(Deserialize)]
|
||||
pub struct SearchParams {
|
||||
query: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct AnswerData {
|
||||
user_query: String,
|
||||
answer_content: String,
|
||||
answer_references: Vec<String>,
|
||||
}
|
||||
|
||||
pub async fn search_result_handler(
|
||||
State(state): State<HtmlState>,
|
||||
Query(query): Query<SearchParams>,
|
||||
auth: AuthSession<User, String, SessionSurrealPool<Any>, Surreal<Any>>,
|
||||
RequireUser(user): RequireUser,
|
||||
) -> Result<impl IntoResponse, HtmlError> {
|
||||
info!("Displaying search results");
|
||||
#[derive(Serialize)]
|
||||
pub struct AnswerData {
|
||||
user_query: String,
|
||||
answer_content: String,
|
||||
answer_references: Vec<String>,
|
||||
}
|
||||
|
||||
let user = match auth.current_user {
|
||||
Some(user) => user,
|
||||
None => return Ok(Redirect::to("/signin").into_response()),
|
||||
};
|
||||
let answer =
|
||||
get_answer_with_references(&state.db, &state.openai_client, &query.query, &user.id).await?;
|
||||
|
||||
// let answer = get_answer_with_references(
|
||||
// &state.surreal_db_client,
|
||||
// &state.openai_client,
|
||||
// &query.query,
|
||||
// &user.id,
|
||||
// )
|
||||
// .await
|
||||
// .map_err(|e| HtmlError::new(e, state.templates.clone()))?;
|
||||
|
||||
let answer = "The Minne project is focused on simplifying knowledge management through features such as easy capture, smart analysis, and visualization of connections between ideas. It includes various functionalities like the Smart Analysis Feature, which provides content analysis and organization, and the Easy Capture Feature, which allows users to effortlessly capture and retrieve knowledge in various formats. Additionally, it offers tools like Knowledge Graph Visualization to enhance understanding and organization of knowledge. The project also emphasizes a user-friendly onboarding experience and mobile-friendly options for accessing its services.".to_string();
|
||||
|
||||
let references = vec![
|
||||
"i81cd5be8-557c-4b2b-ba3a-4b8d28e74b9b".to_string(),
|
||||
"5f72a724-d7a3-467d-8783-7cca6053ddc7".to_string(),
|
||||
"ad106a1f-ccda-415e-9e87-c3a34e202624".to_string(),
|
||||
"8797b57d-094d-4ee9-a3a7-c3195b246254".to_string(),
|
||||
"69763f43-82e6-4cb5-ba3e-f6da13777dab".to_string(),
|
||||
];
|
||||
|
||||
let output = render_template(
|
||||
Ok(TemplateResponse::new_template(
|
||||
"index/signed_in/search_response.html",
|
||||
AnswerData {
|
||||
user_query: query.query,
|
||||
answer_content: answer,
|
||||
answer_references: references,
|
||||
answer_content: answer.content,
|
||||
answer_references: answer.references,
|
||||
},
|
||||
state.templates,
|
||||
)?;
|
||||
|
||||
Ok(output.into_response())
|
||||
))
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ use minijinja_autoreload::AutoReloader;
|
||||
use serde::Serialize;
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::{html_state::HtmlState, AuthSessionType};
|
||||
use crate::html_state::HtmlState;
|
||||
|
||||
// Enum for template types
|
||||
#[derive(Clone)]
|
||||
@@ -113,10 +113,8 @@ impl IntoResponse for TemplateResponse {
|
||||
}
|
||||
}
|
||||
|
||||
// Wrapper to avoid recursion
|
||||
struct TemplateStateWrapper {
|
||||
state: HtmlState,
|
||||
auth: AuthSessionType,
|
||||
template_response: TemplateResponse,
|
||||
}
|
||||
|
||||
@@ -228,7 +226,6 @@ fn fallback_error() -> Html<String> {
|
||||
|
||||
pub async fn with_template_response(
|
||||
State(state): State<HtmlState>,
|
||||
auth: AuthSessionType,
|
||||
response: Response,
|
||||
) -> Response {
|
||||
// Clone the TemplateResponse from extensions
|
||||
@@ -237,7 +234,6 @@ pub async fn with_template_response(
|
||||
if let Some(template_response) = template_response {
|
||||
TemplateStateWrapper {
|
||||
state,
|
||||
auth,
|
||||
template_response,
|
||||
}
|
||||
.into_response()
|
||||
@@ -249,7 +245,6 @@ pub async fn with_template_response(
|
||||
// Define HtmlError
|
||||
pub enum HtmlError {
|
||||
AppError(AppError),
|
||||
TemplateError(String),
|
||||
}
|
||||
|
||||
// Conversion from AppError to HtmlError
|
||||
@@ -282,7 +277,6 @@ impl IntoResponse for HtmlError {
|
||||
};
|
||||
template_response.into_response()
|
||||
}
|
||||
HtmlError::TemplateError(_) => TemplateResponse::server_error().into_response(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user