-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
4 changed files
with
116 additions
and
60 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,77 +1,120 @@ | ||
use actix_web::{post, web, App, HttpServer, Responder, Result}; | ||
use askama::Template; | ||
use axum::{ | ||
extract::{Json, State}, | ||
http::StatusCode, | ||
response::{Html, IntoResponse, Response}, | ||
routing::{get, post}, | ||
Router, | ||
}; | ||
use log::info; | ||
use search::query::QueryProcessor; | ||
use serde::{Deserialize, Serialize}; | ||
use std::{env, sync::Mutex, time::Instant}; | ||
use std::{ | ||
env, | ||
sync::{Arc, Mutex}, | ||
time::Instant, | ||
}; | ||
|
||
struct AppState { | ||
query_processor: Mutex<QueryProcessor>, | ||
} | ||
|
||
#[tokio::main] | ||
async fn main() { | ||
// logger | ||
std::env::set_var("RUST_LOG", "info"); | ||
env_logger::init(); | ||
|
||
let args: Vec<String> = env::args().collect(); | ||
|
||
if args.len() < 2 { | ||
println!("Usage: cargo run --bin client <base_path>"); | ||
return; | ||
} | ||
|
||
let base_path = &args[1]; | ||
let index_path = format!("{}/index/index", base_path); | ||
let tokenizer_path = format!("{}/tokenizer/bert-base-uncased", base_path); | ||
|
||
let state = Arc::new(AppState { | ||
query_processor: Mutex::new(QueryProcessor::build_query_processor( | ||
&index_path, | ||
&tokenizer_path, | ||
)), | ||
}); | ||
|
||
let app = Router::new() | ||
.route("/", get(root)) | ||
.route("/query", post(post_query)) | ||
.with_state(state); | ||
|
||
let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap(); | ||
|
||
info!("Application started"); | ||
axum::serve(listener, app).await.unwrap(); | ||
} | ||
|
||
async fn root() {} | ||
|
||
#[derive(Deserialize, Debug)] | ||
struct QueryRequest { | ||
query: String, | ||
limit: usize, | ||
} | ||
|
||
#[derive(Serialize)] | ||
#[derive(Template)] | ||
#[template(path = "query.html")] | ||
struct QueryResponse { | ||
num_results: u32, | ||
time_ms: u128, | ||
documents: Vec<QueryDocumentResponse>, | ||
documents: Vec<Document>, | ||
} | ||
|
||
#[derive(Serialize)] | ||
struct QueryDocumentResponse { | ||
#[derive(Serialize, Deserialize)] | ||
struct Document { | ||
id: u32, | ||
score: f32, | ||
path: String, | ||
} | ||
|
||
#[post("/query")] | ||
async fn query( | ||
r: web::Json<QueryRequest>, | ||
q: web::Data<Mutex<QueryProcessor>>, | ||
) -> Result<impl Responder> { | ||
println!("query: {:?}", r); | ||
struct HtmlTemplate<T>(T); | ||
|
||
let mut local_q = q.lock().unwrap(); | ||
impl<T> IntoResponse for HtmlTemplate<T> | ||
where | ||
T: Template, | ||
{ | ||
fn into_response(self) -> Response { | ||
match self.0.render() { | ||
Ok(html) => Html(html).into_response(), | ||
|
||
let start_time = Instant::now(); | ||
let result = local_q.query(&r.query, r.limit); | ||
let elapsed_time = start_time.elapsed(); | ||
|
||
let response = QueryResponse { | ||
num_results: result.len() as u32, | ||
time_ms: elapsed_time.as_millis(), | ||
documents: result | ||
.iter() | ||
.map(|e| QueryDocumentResponse { | ||
id: e.id, | ||
score: e.score, | ||
path: e.path.clone(), | ||
}) | ||
.collect(), | ||
}; | ||
|
||
Ok(web::Json(response)) | ||
Err(err) => ( | ||
StatusCode::INTERNAL_SERVER_ERROR, | ||
format!("Failed to render template. Error: {}", err), | ||
) | ||
.into_response(), | ||
} | ||
} | ||
} | ||
|
||
#[actix_web::main] | ||
async fn main() -> std::io::Result<()> { | ||
let args: Vec<String> = env::args().collect(); | ||
if args.len() < 2 { | ||
println!("Usage: cargo run --bin client <base_path>"); | ||
return Ok(()); | ||
} | ||
async fn post_query( | ||
State(state): State<Arc<AppState>>, | ||
Json(payload): Json<QueryRequest>, | ||
) -> impl IntoResponse { | ||
info!("Query request: {:?}", payload); | ||
|
||
let base_path = &args[1]; | ||
let index_path = format!("{}/index/index", base_path); | ||
let tokenizer_path = format!("{}/tokenizer/bert-base-uncased", base_path); | ||
let mut q = state.query_processor.lock().unwrap(); | ||
|
||
let start_time = Instant::now(); | ||
let query_result = q.query(&payload.query, payload.limit); | ||
let time_ms = start_time.elapsed().as_millis(); | ||
|
||
let documents = query_result | ||
.iter() | ||
.map(|r| Document { | ||
id: r.id, | ||
score: r.score, | ||
path: r.path.clone(), | ||
}) | ||
.collect(); | ||
|
||
HttpServer::new(move || { | ||
App::new() | ||
.app_data(web::Data::new(Mutex::new( | ||
QueryProcessor::build_query_processor(&index_path, &tokenizer_path), | ||
))) | ||
.service(query) | ||
}) | ||
.bind(("127.0.0.1", 8080))? | ||
.run() | ||
.await | ||
HtmlTemplate(QueryResponse { time_ms, documents }) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
<h1>Query result</h1> | ||
|
||
<p> | ||
Query completed in {{ time_ms }} ms | ||
<p> | ||
|
||
<ul> | ||
{% for doc in documents %} | ||
<li>{{ loop.index }} - {{ doc.path }}</li> | ||
{% endfor %} | ||
</ul> |