mirror of
https://github.com/perstarkse/minne.git
synced 2026-04-21 08:21:25 +02:00
wip: query html
This commit is contained in:
@@ -13,6 +13,7 @@ use zettle_db::{
|
|||||||
routes::{
|
routes::{
|
||||||
file::upload_handler, index::index_handler, ingress::ingress_handler,
|
file::upload_handler, index::index_handler, ingress::ingress_handler,
|
||||||
query::query_handler, queue_length::queue_length_handler,
|
query::query_handler, queue_length::queue_length_handler,
|
||||||
|
search_result::search_result_handler,
|
||||||
},
|
},
|
||||||
AppState,
|
AppState,
|
||||||
},
|
},
|
||||||
@@ -73,5 +74,6 @@ fn api_routes_v1() -> Router<AppState> {
|
|||||||
fn html_routes() -> Router<AppState> {
|
fn html_routes() -> Router<AppState> {
|
||||||
Router::new()
|
Router::new()
|
||||||
.route("/", get(index_handler))
|
.route("/", get(index_handler))
|
||||||
|
.route("/search", get(search_result_handler))
|
||||||
.nest_service("/assets", ServeDir::new("src/server/assets"))
|
.nest_service("/assets", ServeDir::new("src/server/assets"))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -629,6 +629,14 @@ video {
|
|||||||
height: 4rem;
|
height: 4rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.h-36 {
|
||||||
|
height: 9rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.h-auto {
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
|
||||||
.min-h-screen {
|
.min-h-screen {
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
}
|
}
|
||||||
@@ -637,6 +645,14 @@ video {
|
|||||||
min-height: 80vh;
|
min-height: 80vh;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.min-h-16 {
|
||||||
|
min-height: 4rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.min-h-36 {
|
||||||
|
min-height: 9rem;
|
||||||
|
}
|
||||||
|
|
||||||
.w-full {
|
.w-full {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
@@ -687,6 +703,16 @@ video {
|
|||||||
margin-bottom: calc(2rem * var(--tw-space-y-reverse));
|
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 {
|
.rounded {
|
||||||
border-radius: 0.25rem;
|
border-radius: 0.25rem;
|
||||||
}
|
}
|
||||||
@@ -733,6 +759,11 @@ video {
|
|||||||
border-color: rgb(168 85 247 / 0.3);
|
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 {
|
.bg-blue-300 {
|
||||||
--tw-bg-opacity: 1;
|
--tw-bg-opacity: 1;
|
||||||
background-color: rgb(147 197 253 / var(--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));
|
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 {
|
.bg-gradient-to-br {
|
||||||
background-image: linear-gradient(to bottom right, var(--tw-gradient-stops));
|
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);
|
--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 {
|
.via-purple-900 {
|
||||||
--tw-gradient-to: rgb(88 28 135 / 0) var(--tw-gradient-to-position);
|
--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);
|
--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);
|
--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 {
|
.to-purple-500 {
|
||||||
--tw-gradient-to: #a855f7 var(--tw-gradient-to-position);
|
--tw-gradient-to: #a855f7 var(--tw-gradient-to-position);
|
||||||
}
|
}
|
||||||
@@ -874,6 +921,10 @@ video {
|
|||||||
--tw-gradient-to: #db2777 var(--tw-gradient-to-position);
|
--tw-gradient-to: #db2777 var(--tw-gradient-to-position);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.to-yellow-500 {
|
||||||
|
--tw-gradient-to: #eab308 var(--tw-gradient-to-position);
|
||||||
|
}
|
||||||
|
|
||||||
.bg-clip-text {
|
.bg-clip-text {
|
||||||
-webkit-background-clip: text;
|
-webkit-background-clip: text;
|
||||||
background-clip: text;
|
background-clip: text;
|
||||||
@@ -887,6 +938,18 @@ video {
|
|||||||
padding: 0.5rem;
|
padding: 0.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.p-1 {
|
||||||
|
padding: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.p-0\.5 {
|
||||||
|
padding: 0.125rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.p-4 {
|
||||||
|
padding: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
.py-4 {
|
.py-4 {
|
||||||
padding-top: 1rem;
|
padding-top: 1rem;
|
||||||
padding-bottom: 1rem;
|
padding-bottom: 1rem;
|
||||||
@@ -922,6 +985,19 @@ video {
|
|||||||
padding-bottom: 0.75rem;
|
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-center {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
@@ -968,6 +1044,10 @@ video {
|
|||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.font-black {
|
||||||
|
font-weight: 900;
|
||||||
|
}
|
||||||
|
|
||||||
.text-gray-300 {
|
.text-gray-300 {
|
||||||
--tw-text-opacity: 1;
|
--tw-text-opacity: 1;
|
||||||
color: rgb(209 213 219 / var(--tw-text-opacity, 1));
|
color: rgb(209 213 219 / var(--tw-text-opacity, 1));
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ use crate::{error::ApiError, server::AppState};
|
|||||||
pub async fn index_handler(State(state): State<AppState>) -> Result<Html<String>, ApiError> {
|
pub async fn index_handler(State(state): State<AppState>) -> Result<Html<String>, ApiError> {
|
||||||
info!("Displaying index page");
|
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
|
let output = state
|
||||||
.tera
|
.tera
|
||||||
|
|||||||
@@ -3,3 +3,4 @@ pub mod index;
|
|||||||
pub mod ingress;
|
pub mod ingress;
|
||||||
pub mod query;
|
pub mod query;
|
||||||
pub mod queue_length;
|
pub mod queue_length;
|
||||||
|
pub mod search_result;
|
||||||
|
|||||||
@@ -15,16 +15,16 @@ pub struct QueryInput {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
struct Reference {
|
pub struct Reference {
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
reference: String,
|
pub reference: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
pub struct LLMResponseFormat {
|
pub struct LLMResponseFormat {
|
||||||
answer: String,
|
pub answer: String,
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
references: Vec<Reference>,
|
pub references: Vec<Reference>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn query_handler(
|
pub async fn query_handler(
|
||||||
|
|||||||
72
src/server/routes/search_result.rs
Normal file
72
src/server/routes/search_result.rs
Normal file
@@ -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<AppState>,
|
||||||
|
Query(query): Query<SearchParams>,
|
||||||
|
) -> Result<Html<String>, 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<String> = 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())
|
||||||
|
}
|
||||||
@@ -10,13 +10,17 @@
|
|||||||
<p class="text-gray-400 text-xl">
|
<p class="text-gray-400 text-xl">
|
||||||
An experiment in creating a second brain
|
An experiment in creating a second brain
|
||||||
</p>
|
</p>
|
||||||
|
<p class="text-gray-400 text-lg">
|
||||||
|
There are {{queue_length}} messages queued for ingression.
|
||||||
|
</p>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Search Bar -->
|
<!-- Search Bar -->
|
||||||
<div class="w-full max-w-2xl">
|
<div class="w-full max-w-2xl">
|
||||||
<input type="text" placeholder="Search..."
|
<input type="text" placeholder="Search..." name="query"
|
||||||
class="w-full px-6 py-4 bg-black/30 backdrop-blur-md text-white placeholder-gray-400 outline-none rounded-xl"
|
class="w-full px-6 py-4 bg-black/30 backdrop-blur-md text-white placeholder-gray-400 outline-none rounded-xl"
|
||||||
hx-get="/search" hx-trigger="keyup changed delay:500ms" hx-target="#search-results">
|
hx-get="/search" hx-target="#search-results">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Search Results -->
|
<!-- Search Results -->
|
||||||
|
|||||||
7
src/server/templates/search_result.html
Normal file
7
src/server/templates/search_result.html
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
<div class="h-auto min-h-36 w-full rounded-md bg-gradient-to-r from-pink-500 via-red-500 to-yellow-500 p-0.5">
|
||||||
|
<div class="flex flex-col h-full w-full items-center justify-center bg-gray-800 rounded-md p-4 space-y-3">
|
||||||
|
<p class="font-black text-white text-center break-words">{{result}}</p>
|
||||||
|
<hr class="w-full border-gray-600" />
|
||||||
|
<p class="font-black text-white text-center text-sm">{{references}}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
Reference in New Issue
Block a user