Skip to content

Commit

Permalink
Append LLM result into DOM (#144)
Browse files Browse the repository at this point in the history
  • Loading branch information
Endle authored Sep 7, 2024
1 parent d7e6911 commit b0b7b76
Show file tree
Hide file tree
Showing 5 changed files with 151 additions and 93 deletions.
165 changes: 95 additions & 70 deletions fireSeqSearch_addon/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -142,72 +142,120 @@ function parseRawList(rawSearchResult) {
return hits;
}

function createTitleBarDom(count) {
const titleBar = createElementWithText("div");
titleBar.classList.add('fireSeqSearchTitleBar');
const hitCount = `<span>We found <b>${count.toString()}</b> results in your logseq notebook</span>`;
titleBar.insertAdjacentHTML("afterbegin",hitCount);

function setSummaryState(cl, state) {
let prop = 'none';
if (state) { prop = ''; }
for (const el of document.querySelectorAll(cl)) {
el.style.display=prop;
async function processLlmSummary(serverInfo, parsedSearchResult, fireDom) {

const doneListApi = "http://127.0.0.1:3030/llm_done_list";
let list = await fetch(doneListApi);
list = await list.text();
list = JSON.parse(list);

const findByTitle = function(title) {
const ul = fireDom.querySelector( ".fireSeqSearchHitList" );
if (ul === null) return null;
for (const child of ul.children) {
const liTitle = child.firstChild.text;
if (title === liTitle) {
return child;
}
}
}

let btn = document.createElement("button");
btn.classList.add("hideSummary");
let text = document.createTextNode("Hide Summary");
btn.appendChild(text);
btn.onclick = function () {
setSummaryState(".fireSeqSearchHitSummary", false);
setSummaryState(".fireSeqSearchLlmSummary", false);
};
titleBar.appendChild(btn);

btn = document.createElement("button");
btn.classList.add("showSummary");
text = document.createTextNode("Summary");
btn.appendChild(text);
btn.onclick = function () {
setSummaryState(".fireSeqSearchHitSummary", true);
setSummaryState(".fireSeqSearchLlmSummary", false);
return null;
};
titleBar.appendChild(btn);

const setLlmResult = function (title, llmSummary) {
const targetRow = findByTitle(title);
if (targetRow === null) {
consoleLogForDebug("Error! Can't find dom for ", title);
return;
}
if (targetRow.querySelector( ".fireSeqSearchLlmSummary" ) != null) {
consoleLogForDebug("Skip. We have the summary for ", title);
return;
}

btn = document.createElement("button");
btn.classList.add("showLlm");
text = document.createTextNode("LLM");
btn.appendChild(text);
btn.onclick = function () {
setSummaryState(".fireSeqSearchHitSummary", false);
setSummaryState(".fireSeqSearchLlmSummary", true);
const summary = createElementWithText("span", "");
summary.innerHTML = llmSummary;
summary.classList.add('fireSeqSearchLlmSummary');
targetRow.appendChild(summary);
};
titleBar.appendChild(btn);
for (const record of parsedSearchResult) {
const title = record.title;
if (!list.includes(title)) {
consoleLogForDebug("Not ready, skip" + title);
continue;
}
// TODO remove hard code port
const llm_api = "http://127.0.0.1:3030/summarize/" + title;
let sum = await fetch(llm_api);
sum = await sum.text();
setLlmResult(title, sum);
}
}


return titleBar;
}
function createFireSeqDom(count) {
function createFireSeqDom(serverInfo, parsedSearchResult) {
const count = parsedSearchResult.length;
const div = document.createElement("div");
div.setAttribute("id", fireSeqSearchDomId);
const bar = createTitleBarDom(count);

const createTitleBarDom = function () {
const titleBar = createElementWithText("div");
titleBar.classList.add('fireSeqSearchTitleBar');
const hitCount = `<span>We found <b>${count.toString()}</b> results in your logseq notebook</span>`;
titleBar.insertAdjacentHTML("afterbegin",hitCount);

function setSummaryState(cl, state) {
let prop = 'none';
if (state) { prop = ''; }
for (const el of document.querySelectorAll(cl)) {
el.style.display=prop;
}
}
let btn = document.createElement("button");
btn.classList.add("hideSummary");
let text = document.createTextNode("Hide Summary");
btn.appendChild(text);
btn.onclick = function () {
setSummaryState(".fireSeqSearchHitSummary", false);
setSummaryState(".fireSeqSearchLlmSummary", false);
};
titleBar.appendChild(btn);

btn = document.createElement("button");
btn.classList.add("showSummary");
text = document.createTextNode("Summary");
btn.appendChild(text);
btn.onclick = function () {
setSummaryState(".fireSeqSearchHitSummary", true);
setSummaryState(".fireSeqSearchLlmSummary", false);
};
titleBar.appendChild(btn);

btn = document.createElement("button");
btn.classList.add("showLlm");
text = document.createTextNode("LLM");
btn.appendChild(text);
btn.onclick = function () {
setSummaryState(".fireSeqSearchHitSummary", false);
setSummaryState(".fireSeqSearchLlmSummary", true);
processLlmSummary(serverInfo, parsedSearchResult, div);
};
titleBar.appendChild(btn);
return titleBar;
};
const bar = createTitleBarDom();
div.appendChild(bar);
return div;
}

async function appendResultToSearchResult(serverInfo, parsedSearchResult, dom) {
const firefoxExtensionUserOption = await checkUserOptions();

consoleLogForDebug('Loaded user option: ' + JSON.stringify(firefoxExtensionUserOption));


function buildListItems(parsedSearchResult) {
const hitList = document.createElement("ul");
hitList.classList.add('fireSeqSearchHitList');
for (const record of parsedSearchResult) {
const li = createElementWithText("li", "");
li.classList.add('fireSeqSearchHitListItem');
if (firefoxExtensionUserOption.ShowScore) {
const score = createElementWithText("span", String(record.score));
li.appendChild(score);
Expand Down Expand Up @@ -252,18 +300,6 @@ async function appendResultToSearchResult(serverInfo, parsedSearchResult, dom) {
insertDivToWebpage(dom);
}

async function processLlmSummary(serverInfo, parsedSearchResult, dom) {
for (const record of parsedSearchResult) {
// TODO remove hard code port
const llm_api = "http://127.0.0.1:3030/summarize/" + record.title;
console.log("llm called");
console.log(record.title);
const response = await fetch(llm_api);
const text = await response.text();
console.log(text);
}
}

async function mainProcess(fetchResultArray) {
consoleLogForDebug("main process");

Expand All @@ -272,18 +308,10 @@ async function mainProcess(fetchResultArray) {
consoleLogForDebug(serverInfo);
const parsedSearchResult = parseRawList(rawSearchResult);

console.log("in main");
console.log(rawSearchResult);
console.log(parsedSearchResult);

const fireDom = createFireSeqDom(parsedSearchResult.length);
const fireDom = createFireSeqDom(serverInfo, parsedSearchResult);

appendResultToSearchResult(serverInfo, parsedSearchResult, fireDom);

if (serverInfo.llm_enabled) {
consoleLogForDebug("llm");
processLlmSummary(serverInfo, parsedSearchResult, fireDom);
}
}


Expand Down Expand Up @@ -318,7 +346,6 @@ function getSearchParameterFromCurrentPage() {
(function() {
const searchParameter = getSearchParameterFromCurrentPage();


addGlobalStyle(fireSeqSearchScriptCSS);

//https://gomakethings.com/waiting-for-multiple-all-api-responses-to-complete-with-the-vanilla-js-promise.all-method/
Expand All @@ -328,9 +355,7 @@ function getSearchParameterFromCurrentPage() {
]).then(function (responses) {
return Promise.all(responses.map(function (response) {return response.json();}));
}).then(function (data) {
//consoleLogForDebug(data);
mainProcess(data);
//return appendResultToSearchResult(data);
}).then((_e) => {
const highlightedItems = document.querySelectorAll('.fireSeqSearchHighlight');
consoleLogForDebug(highlightedItems);
Expand Down
11 changes: 10 additions & 1 deletion fire_seq_search_server/src/http_client/endpoints.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use std::sync::Arc;
use log::debug;
use log::{debug, info};

use crate::query_engine::{QueryEngine, ServerInformation};
use axum::Json;
Expand Down Expand Up @@ -30,6 +30,15 @@ pub async fn summarize(
Html(r.await)
}

pub async fn get_llm_done_list(
State(engine_arc): State<Arc<QueryEngine>>
) -> Html<String>{

info!("get list endpoint called");
let r = engine_arc.get_llm_done_list();
Html(r.await)
}

pub async fn generate_word_cloud(State(engine_arc): State<Arc<QueryEngine>>)
-> Html<String> {
let div_id = "fireSeqSearchWordcloudRawJson";
Expand Down
55 changes: 35 additions & 20 deletions fire_seq_search_server/src/local_llm/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,13 @@ pub struct Usage {
pub total_tokens: i64,
}

#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct HealthCheck {
pub slots_idle: i64,
pub slots_processing: i64,
pub status: String,
}

// End genereated

const LLM_SERVER_PORT: &str = "8081"; // TODO Remove this magic number
Expand Down Expand Up @@ -165,7 +172,6 @@ impl LlmEngine {

impl LlmEngine{
pub async fn summarize(&self, full_text: &str) -> String {
info!("summarize called");
//http://localhost:8080/completion
let ep = self.endpoint.to_owned() + "/v1/chat/completions";
let data = Self::build_data(full_text);
Expand All @@ -175,17 +181,12 @@ impl LlmEngine{
.send()
.await
.unwrap();
//info!(" response {:?}", &res);
let content = res.text().await.unwrap();
//info!(" text {:?}", &content);
let parsed: LlamaResponse = serde_json::from_str(&content).unwrap();
//info!(" parsed {:?}", &parsed);
let v = parsed.choices;
let v0 = v.into_iter().next().unwrap();
v0.message.content


//TODO remove unwrap
//TODO remove unwrap
}

pub async fn post_summarize_job(&self, doc: DocData) {
Expand All @@ -196,13 +197,19 @@ impl LlmEngine{
}

pub async fn call_llm_engine(&self) {

let health = self.health().await.unwrap();
if health.slots_idle == 0 {
info!("No valid slot, continue");
return;
}

let mut next_job: Option<DocData> = None;

let mut jcache = self.job_cache.lock().await;//.unwrap();
next_job = jcache.job_queue.pop_front();
drop(jcache);


let doc = match next_job {
Some(x) => x,
None => { return; },
Expand All @@ -216,31 +223,39 @@ impl LlmEngine{
}
drop(jcache);

info!("Start summarize job: {}", &title);
let summarize_result = self.summarize(&doc.body).await;
info!("Finished summarize job: {}", &title);

let mut jcache = self.job_cache.lock().await;//.unwrap();
next_job = jcache.job_queue.pop_front();
info!("get summarize result {}", &title);
jcache.done_job.insert(title, summarize_result);
drop(jcache);

}

pub async fn quick_fetch(&self, title: &str) -> Option<String> {
let jcache = self.job_cache.lock().await;
return jcache.done_job.get(title).cloned();
}

pub async fn health(&self) -> Result<(), Box<dyn std::error::Error>> {
info!("Calling health check");
let resp = reqwest::get(self.endpoint.to_owned() + "/health")
.await?
.headers().to_owned()
//.status()
//.text().await?
;
info!("Health check: {:#?}", resp);
Ok(())
pub async fn get_llm_done_list(&self) -> Vec<String> {
let mut r = Vec::new();
let jcache = self.job_cache.lock().await;
for (title, _text) in &jcache.done_job {
info!("already done : {}", &title);
r.push(title.to_owned());
}
return r;
}

pub async fn health(&self) -> Result<HealthCheck, Box<dyn std::error::Error>> {
let res = self.client.get(self.endpoint.to_owned() + "/health")
.send()
.await
.unwrap();
let content = res.text().await.unwrap();
let parsed: HealthCheck = serde_json::from_str(&content).unwrap();
Ok(parsed)
}
}

Expand Down
3 changes: 1 addition & 2 deletions fire_seq_search_server/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,12 +78,10 @@ async fn main() {
engine.llm = Some(llm_arc);

let poll_handle = tokio::spawn( async move {
info!("inside main loop");
loop {
llm_poll.call_llm_engine().await;
let wait_llm = tokio::time::Duration::from_millis(500);
tokio::time::sleep(wait_llm).await;
info!("main loop: poll again");
}
});
// poll_handle.await;
Expand All @@ -97,6 +95,7 @@ async fn main() {
.route("/server_info", get(endpoints::get_server_info))
.route("/wordcloud", get(endpoints::generate_word_cloud))
.route("/summarize/:title", get(endpoints::summarize))
.route("/llm_done_list", get(endpoints::get_llm_done_list))
.with_state(engine_arc.clone());

let listener = tokio::net::TcpListener::bind(&engine_arc.server_info.host)
Expand Down
10 changes: 10 additions & 0 deletions fire_seq_search_server/src/query_engine/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,16 @@ impl QueryEngine {
"LLM turned off".to_owned()
}
}
pub async fn get_llm_done_list(&self) -> String {
if cfg!(feature="llm") {
let llm = self.llm.as_ref().unwrap();
let result = &llm.get_llm_done_list().await;
let json = serde_json::to_string(&result).unwrap();
return json;
} else {
"LLM turned off".to_owned()
}
}
}

fn term_preprocess(term:String) -> String {
Expand Down

0 comments on commit b0b7b76

Please sign in to comment.