From cd7604c0efcb6990785e4d486c11ae13076dae6f Mon Sep 17 00:00:00 2001 From: Per Stark Date: Tue, 10 Dec 2024 16:46:04 +0100 Subject: [PATCH] wip: query html --- src/bin/server.rs | 2 + src/server/assets/style.css | 80 +++++++++++++++++++++++++ src/server/routes/index.rs | 2 +- src/server/routes/mod.rs | 1 + src/server/routes/query.rs | 8 +-- src/server/routes/search_result.rs | 72 ++++++++++++++++++++++ src/server/templates/index.html | 8 ++- src/server/templates/search_result.html | 7 +++ 8 files changed, 173 insertions(+), 7 deletions(-) create mode 100644 src/server/routes/search_result.rs create mode 100644 src/server/templates/search_result.html diff --git a/src/bin/server.rs b/src/bin/server.rs index b50f5be..57cd448 100644 --- a/src/bin/server.rs +++ b/src/bin/server.rs @@ -13,6 +13,7 @@ use zettle_db::{ routes::{ file::upload_handler, index::index_handler, ingress::ingress_handler, query::query_handler, queue_length::queue_length_handler, + search_result::search_result_handler, }, AppState, }, @@ -73,5 +74,6 @@ fn api_routes_v1() -> Router { fn html_routes() -> Router { Router::new() .route("/", get(index_handler)) + .route("/search", get(search_result_handler)) .nest_service("/assets", ServeDir::new("src/server/assets")) } diff --git a/src/server/assets/style.css b/src/server/assets/style.css index 986c1cb..d5a548e 100644 --- a/src/server/assets/style.css +++ b/src/server/assets/style.css @@ -629,6 +629,14 @@ video { height: 4rem; } +.h-36 { + height: 9rem; +} + +.h-auto { + height: auto; +} + .min-h-screen { min-height: 100vh; } @@ -637,6 +645,14 @@ video { min-height: 80vh; } +.min-h-16 { + min-height: 4rem; +} + +.min-h-36 { + min-height: 9rem; +} + .w-full { width: 100%; } @@ -687,6 +703,16 @@ video { margin-bottom: calc(2rem * var(--tw-space-y-reverse)); } +.space-y-3 > :not([hidden]) ~ :not([hidden]) { + --tw-space-y-reverse: 0; + margin-top: calc(0.75rem * calc(1 - var(--tw-space-y-reverse))); + margin-bottom: calc(0.75rem * var(--tw-space-y-reverse)); +} + +.break-words { + overflow-wrap: break-word; +} + .rounded { border-radius: 0.25rem; } @@ -733,6 +759,11 @@ video { border-color: rgb(168 85 247 / 0.3); } +.border-gray-600 { + --tw-border-opacity: 1; + border-color: rgb(75 85 99 / var(--tw-border-opacity, 1)); +} + .bg-blue-300 { --tw-bg-opacity: 1; background-color: rgb(147 197 253 / var(--tw-bg-opacity, 1)); @@ -785,6 +816,11 @@ video { background-color: rgb(255 255 255 / var(--tw-bg-opacity, 1)); } +.bg-gray-800 { + --tw-bg-opacity: 1; + background-color: rgb(31 41 55 / var(--tw-bg-opacity, 1)); +} + .bg-gradient-to-br { background-image: linear-gradient(to bottom right, var(--tw-gradient-stops)); } @@ -817,6 +853,12 @@ video { --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to); } +.from-pink-500 { + --tw-gradient-from: #ec4899 var(--tw-gradient-from-position); + --tw-gradient-to: rgb(236 72 153 / 0) var(--tw-gradient-to-position); + --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to); +} + .via-purple-900 { --tw-gradient-to: rgb(88 28 135 / 0) var(--tw-gradient-to-position); --tw-gradient-stops: var(--tw-gradient-from), #581c87 var(--tw-gradient-via-position), var(--tw-gradient-to); @@ -842,6 +884,11 @@ video { --tw-gradient-stops: var(--tw-gradient-from), #f3e8ff var(--tw-gradient-via-position), var(--tw-gradient-to); } +.via-red-500 { + --tw-gradient-to: rgb(239 68 68 / 0) var(--tw-gradient-to-position); + --tw-gradient-stops: var(--tw-gradient-from), #ef4444 var(--tw-gradient-via-position), var(--tw-gradient-to); +} + .to-purple-500 { --tw-gradient-to: #a855f7 var(--tw-gradient-to-position); } @@ -874,6 +921,10 @@ video { --tw-gradient-to: #db2777 var(--tw-gradient-to-position); } +.to-yellow-500 { + --tw-gradient-to: #eab308 var(--tw-gradient-to-position); +} + .bg-clip-text { -webkit-background-clip: text; background-clip: text; @@ -887,6 +938,18 @@ video { padding: 0.5rem; } +.p-1 { + padding: 0.25rem; +} + +.p-0\.5 { + padding: 0.125rem; +} + +.p-4 { + padding: 1rem; +} + .py-4 { padding-top: 1rem; padding-bottom: 1rem; @@ -922,6 +985,19 @@ video { padding-bottom: 0.75rem; } +.py-10 { + padding-top: 2.5rem; + padding-bottom: 2.5rem; +} + +.pb-10 { + padding-bottom: 2.5rem; +} + +.pt-4 { + padding-top: 1rem; +} + .text-center { text-align: center; } @@ -968,6 +1044,10 @@ video { font-weight: 500; } +.font-black { + font-weight: 900; +} + .text-gray-300 { --tw-text-opacity: 1; color: rgb(209 213 219 / var(--tw-text-opacity, 1)); diff --git a/src/server/routes/index.rs b/src/server/routes/index.rs index 907081d..7706221 100644 --- a/src/server/routes/index.rs +++ b/src/server/routes/index.rs @@ -8,7 +8,7 @@ use crate::{error::ApiError, server::AppState}; pub async fn index_handler(State(state): State) -> Result, ApiError> { info!("Displaying index page"); - let queue_length = state.rabbitmq_consumer.queue.message_count(); + let queue_length = state.rabbitmq_consumer.get_queue_length().await?; let output = state .tera diff --git a/src/server/routes/mod.rs b/src/server/routes/mod.rs index 2b67058..724e6f7 100644 --- a/src/server/routes/mod.rs +++ b/src/server/routes/mod.rs @@ -3,3 +3,4 @@ pub mod index; pub mod ingress; pub mod query; pub mod queue_length; +pub mod search_result; diff --git a/src/server/routes/query.rs b/src/server/routes/query.rs index 0864b79..97b2356 100644 --- a/src/server/routes/query.rs +++ b/src/server/routes/query.rs @@ -15,16 +15,16 @@ pub struct QueryInput { } #[derive(Debug, Deserialize)] -struct Reference { +pub struct Reference { #[allow(dead_code)] - reference: String, + pub reference: String, } #[derive(Debug, Deserialize)] pub struct LLMResponseFormat { - answer: String, + pub answer: String, #[allow(dead_code)] - references: Vec, + pub references: Vec, } pub async fn query_handler( diff --git a/src/server/routes/search_result.rs b/src/server/routes/search_result.rs new file mode 100644 index 0000000..c563207 --- /dev/null +++ b/src/server/routes/search_result.rs @@ -0,0 +1,72 @@ +use axum::{ + extract::{Query, State}, + response::Html, +}; +use serde::Deserialize; +use serde_json::json; +use tera::Context; +use tracing::info; + +use crate::{ + error::ApiError, + retrieval::combined_knowledge_entity_retrieval, + server::{ + routes::query::helper::{ + create_chat_request, create_user_message, format_entities_json, process_llm_response, + }, + AppState, + }, +}; +#[derive(Deserialize)] +pub struct SearchParams { + query: String, +} + +pub async fn search_result_handler( + State(state): State, + Query(query): Query, +) -> Result, ApiError> { + info!("Displaying search results"); + + let openai_client = async_openai::Client::new(); + + // Retrieve entities + let entities = combined_knowledge_entity_retrieval( + &state.surreal_db_client, + &openai_client, + query.query.clone(), + ) + .await?; + + // Format entities and create message + let entities_json = format_entities_json(&entities); + let user_message = create_user_message(&entities_json, &query.query); + + // Create and send request + let request = create_chat_request(user_message)?; + let response = openai_client + .chat() + .create(request) + .await + .map_err(|e| ApiError::QueryError(e.to_string()))?; + + // Process response + let answer = process_llm_response(response).await?; + + let references: Vec = answer + .references + .into_iter() + .map(|reference| reference.reference) + .collect(); + + let output = state + .tera + .render( + "search_result.html", + &Context::from_value(json!({"result": answer.answer, "references": references})) + .unwrap(), + ) + .unwrap(); + + Ok(output.into()) +} diff --git a/src/server/templates/index.html b/src/server/templates/index.html index 3156b0c..0d7bb8a 100644 --- a/src/server/templates/index.html +++ b/src/server/templates/index.html @@ -10,13 +10,17 @@

An experiment in creating a second brain

+

+ There are {{queue_length}} messages queued for ingression. +

+
- + hx-get="/search" hx-target="#search-results">
diff --git a/src/server/templates/search_result.html b/src/server/templates/search_result.html new file mode 100644 index 0000000..4f93b49 --- /dev/null +++ b/src/server/templates/search_result.html @@ -0,0 +1,7 @@ +
+
+

{{result}}

+
+

{{references}}

+
+
\ No newline at end of file