chat history added to context and patching text content

This commit is contained in:
Per Stark
2025-03-16 21:24:24 +01:00
parent f2a434a071
commit 2931724009
13 changed files with 141 additions and 166 deletions

View File

@@ -1,139 +0,0 @@
// use axum::{
// http::StatusCode,
// response::{Html, IntoResponse, Response},
// };
// use common::error::AppError;
// use minijinja::context;
// use minijinja_autoreload::AutoReloader;
// use std::sync::Arc;
// pub type TemplateResult<T> = Result<T, HtmlError>;
// // Helper trait for converting to HtmlError with templates
// pub trait IntoHtmlError {
// fn with_template(self, templates: Arc<AutoReloader>) -> HtmlError;
// }
// // // Implement for AppError
// impl IntoHtmlError for AppError {
// fn with_template(self, templates: Arc<AutoReloader>) -> HtmlError {
// HtmlError::new(self, templates)
// }
// }
// // // Implement for minijinja::Error directly
// impl IntoHtmlError for minijinja::Error {
// fn with_template(self, templates: Arc<AutoReloader>) -> HtmlError {
// HtmlError::from_template_error(self, templates)
// }
// }
// pub enum HtmlError {
// ServerError(Arc<AutoReloader>),
// NotFound(Arc<AutoReloader>),
// Unauthorized(Arc<AutoReloader>),
// BadRequest(String, Arc<AutoReloader>),
// Template(String, Arc<AutoReloader>),
// }
// impl HtmlError {
// pub fn new(error: AppError, templates: Arc<AutoReloader>) -> Self {
// match error {
// AppError::NotFound(_msg) => HtmlError::NotFound(templates),
// AppError::Auth(_msg) => HtmlError::Unauthorized(templates),
// AppError::Validation(msg) => HtmlError::BadRequest(msg, templates),
// _ => {
// tracing::error!("Internal error: {:?}", error);
// HtmlError::ServerError(templates)
// }
// }
// }
// pub fn from_template_error(error: minijinja::Error, templates: Arc<AutoReloader>) -> Self {
// tracing::error!("Template error: {:?}", error);
// HtmlError::Template(error.to_string(), templates)
// }
// }
// impl IntoResponse for HtmlError {
// fn into_response(self) -> Response {
// let (status, context, templates) = match self {
// HtmlError::ServerError(templates) | HtmlError::Template(_, templates) => (
// StatusCode::INTERNAL_SERVER_ERROR,
// context! {
// status_code => 500,
// title => "Internal Server Error",
// error => "Internal Server Error",
// description => "Something went wrong on our end."
// },
// templates,
// ),
// HtmlError::NotFound(templates) => (
// StatusCode::NOT_FOUND,
// context! {
// status_code => 404,
// title => "Page Not Found",
// error => "Not Found",
// description => "The page you're looking for doesn't exist or was removed."
// },
// templates,
// ),
// HtmlError::Unauthorized(templates) => (
// StatusCode::UNAUTHORIZED,
// context! {
// status_code => 401,
// title => "Unauthorized",
// error => "Access Denied",
// description => "You need to be logged in to access this page."
// },
// templates,
// ),
// HtmlError::BadRequest(msg, templates) => (
// StatusCode::BAD_REQUEST,
// context! {
// status_code => 400,
// title => "Bad Request",
// error => "Bad Request",
// description => msg
// },
// templates,
// ),
// };
// let html = match templates.acquire_env() {
// Ok(env) => match env.get_template("errors/error.html") {
// Ok(tmpl) => match tmpl.render(context) {
// Ok(output) => output,
// Err(e) => {
// tracing::error!("Template render error: {:?}", e);
// Self::fallback_html()
// }
// },
// Err(e) => {
// tracing::error!("Template get error: {:?}", e);
// Self::fallback_html()
// }
// },
// Err(e) => {
// tracing::error!("Environment acquire error: {:?}", e);
// Self::fallback_html()
// }
// };
// (status, Html(html)).into_response()
// }
// }
// impl HtmlError {
// fn fallback_html() -> String {
// r#"
// <html>
// <body>
// <div class="container mx-auto p-4">
// <h1 class="text-4xl text-error">Error</h1>
// <p class="mt-4">Sorry, something went wrong displaying this page.</p>
// </div>
// </body>
// </html>
// "#
// .to_string()
// }
// }

View File

@@ -1,4 +1,3 @@
pub mod error;
pub mod html_state;
mod middleware_analytics;
mod middleware_auth;

View File

@@ -12,7 +12,8 @@ use axum_session_auth::AuthSession;
use axum_session_surreal::SessionSurrealPool;
use composite_retrieval::{
answer_retrieval::{
create_chat_request, create_user_message, format_entities_json, LLMResponseFormat,
create_chat_request, create_user_message_with_history, format_entities_json,
LLMResponseFormat,
},
retrieve_entities,
};
@@ -30,6 +31,7 @@ use tracing::{error, info};
use common::storage::{
db::SurrealDbClient,
types::{
conversation::Conversation,
message::{Message, MessageRole},
user::User,
},
@@ -50,7 +52,10 @@ async fn get_message_and_user(
db: &SurrealDbClient,
current_user: Option<User>,
message_id: &str,
) -> Result<(Message, User), Sse<Pin<Box<dyn Stream<Item = Result<Event, axum::Error>> + Send>>>> {
) -> Result<
(Message, User, Conversation, Vec<Message>),
Sse<Pin<Box<dyn Stream<Item = Result<Event, axum::Error>> + Send>>>,
> {
// Check authentication
let user = match current_user {
Some(user) => user,
@@ -77,7 +82,23 @@ async fn get_message_and_user(
}
};
Ok((message, user))
// Get conversation history
let (conversation, mut history) =
match Conversation::get_complete_conversation(&message.conversation_id, &user.id, db).await
{
Err(e) => {
error!("Database error retrieving message {}: {:?}", message_id, e);
return Err(Sse::new(create_error_stream(
"Failed to retrieve message: database error",
)));
}
Ok((conversation, history)) => (conversation, history),
};
// Remove the last message, its the same as the message
history.pop();
Ok((message, user, conversation, history))
}
#[derive(Deserialize)]
@@ -91,9 +112,11 @@ pub async fn get_response_stream(
Query(params): Query<QueryParams>,
) -> Sse<Pin<Box<dyn Stream<Item = Result<Event, axum::Error>> + Send>>> {
// 1. Authentication and initial data validation
let (user_message, user) =
let (user_message, user, _conversation, history) =
match get_message_and_user(&state.db, auth.current_user, &params.message_id).await {
Ok((user_message, user)) => (user_message, user),
Ok((user_message, user, conversation, history)) => {
(user_message, user, conversation, history)
}
Err(error_stream) => return error_stream,
};
@@ -114,7 +137,8 @@ pub async fn get_response_stream(
// 3. Create the OpenAI request
let entities_json = format_entities_json(&entities);
let formatted_user_message = create_user_message(&entities_json, &user_message.content);
let formatted_user_message =
create_user_message_with_history(&entities_json, &history, &user_message.content);
let request = match create_chat_request(formatted_user_message) {
Ok(req) => req,
Err(..) => {

View File

@@ -1,8 +1,9 @@
use axum::{
extract::{Path, State},
response::IntoResponse,
Form,
};
use serde::Serialize;
use serde::{Deserialize, Serialize};
use common::storage::types::{text_content::TextContent, user::User};
@@ -33,12 +34,6 @@ pub async fn show_content_page(
))
}
#[derive(Serialize)]
pub struct TextContentEditModal {
pub user: User,
pub text_content: TextContent,
}
pub async fn show_text_content_edit_form(
State(state): State<HtmlState>,
RequireUser(user): RequireUser,
@@ -46,20 +41,40 @@ pub async fn show_text_content_edit_form(
) -> Result<impl IntoResponse, HtmlError> {
let text_content = User::get_and_validate_text_content(&id, &user.id, &state.db).await?;
#[derive(Serialize)]
pub struct TextContentEditModal {
pub user: User,
pub text_content: TextContent,
}
Ok(TemplateResponse::new_template(
"content/edit_text_content_modal.html",
TextContentEditModal { user, text_content },
))
}
#[derive(Deserialize)]
pub struct PatchTextContentParams {
instructions: String,
category: String,
text: String,
}
pub async fn patch_text_content(
State(state): State<HtmlState>,
RequireUser(user): RequireUser,
Path(id): Path<String>,
Form(form): Form<PatchTextContentParams>,
) -> Result<impl IntoResponse, HtmlError> {
let text_content = User::get_and_validate_text_content(&id, &user.id, &state.db).await?;
User::get_and_validate_text_content(&id, &user.id, &state.db).await?;
// ADD FUNCTION TO PATCH CONTENT
TextContent::patch(
&id,
&form.instructions,
&form.category,
&form.text,
&state.db,
)
.await?;
let text_contents = User::get_text_contents(&user.id, &state.db).await?;

View File

@@ -261,7 +261,6 @@ impl From<surrealdb::Error> for HtmlError {
}
}
// Now implement IntoResponse for HtmlError
impl IntoResponse for HtmlError {
fn into_response(self) -> Response {
match self {