Skip to content

Commit

Permalink
Merge pull request #149 from Endle/llm_candidate
Browse files Browse the repository at this point in the history
  • Loading branch information
Endle authored Sep 25, 2024
2 parents e76423d + 7bebf8c commit fec3cd2
Show file tree
Hide file tree
Showing 27 changed files with 1,222 additions and 547 deletions.
8 changes: 3 additions & 5 deletions .github/workflows/quality.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,15 @@ jobs:
cargo-deny:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Install Rust
- uses: actions/checkout@v4
- name: Install Rust
uses: actions-rs/toolchain@v1
with:
toolchain: stable
profile: minimal
override: true
- name: Run sccache-cache
uses: Xuanwo/sccache-action@c94e27bef21ab3fb4a5152c8a878c53262b4abb0
with:
version: "v0.4.0-pre.6"
uses: mozilla-actions/[email protected]
- name: Get Date
id: get-date
run: |
Expand Down
17 changes: 7 additions & 10 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ name: Linux and macOS
# Template Reference: https://www.infinyon.com/blog/2021/04/github-actions-best-practices/
on:
push:
branches: [ master ]
branches: [ master, llm_candidate ]
pull_request:
branches: [ master ]
branches: [ master, llm_candidate ]

env:
CARGO_TERM_COLOR: always
Expand All @@ -22,17 +22,17 @@ jobs:
os: [ubuntu-latest, macos-13, macos-14]
rust: [stable]
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4
- name: Run sccache-cache
uses: mozilla-actions/[email protected]
- name: Install Rust ${{ matrix.rust }}
uses: actions-rs/toolchain@v1
with:
toolchain: ${{ matrix.rust }}
profile: minimal
override: true
- name: Run sccache-cache
uses: mozilla-actions/sccache-action@c94e27bef21ab3fb4a5152c8a878c53262b4abb0
with:
version: "v0.4.0-pre.6"
uses: mozilla-actions/[email protected]
- name: Get Date
id: get-date
run: |
Expand Down Expand Up @@ -74,7 +74,6 @@ jobs:
- name: Run sccache stat for check
shell: bash
run: ${SCCACHE_PATH} --show-stats



release:
Expand All @@ -89,9 +88,7 @@ jobs:
profile: minimal
override: true
- name: Run sccache-cache
uses: Xuanwo/sccache-action@c94e27bef21ab3fb4a5152c8a878c53262b4abb0
with:
version: "v0.4.0-pre.6"
uses: mozilla-actions/[email protected]
- name: Get Date
id: get-date
run: |
Expand Down
6 changes: 6 additions & 0 deletions docs/examples.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
## LLM

2024 Sept 22

https://github.com/user-attachments/assets/b0a4ca66-0a33-401a-a916-af7a69f2ae7b

## ObsidianMD

[obsidian_example_2023-Feb-05.mp4](
Expand Down
29 changes: 29 additions & 0 deletions docs/release_notes_0.2_2024Sep.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
### 0.2.1

New feature: Note Summarization with Local LLM.

What happens locally, what stays locally.

#### Run server with local LLM
fireSeqSearch facilitates [llamafile](https://github.com/Mozilla-Ocho/llamafile) by [Mozilla](https://github.com/Mozilla-Ocho).

```
mkdir -pv ~/.llamafile && cd ~/.llamafile
wget https://huggingface.co/Mozilla/Mistral-7B-Instruct-v0.2-llamafile/resolve/main/mistral-7b-instruct-v0.2.Q4_0.llamafile?download=true
chmod +x mistral-7b-instruct-v0.2.Q4_0.llamafile
```

After that, compile and run fireSeqSearch with LLM
```
cargo build --features llm
target/debug/fire_seq_search_server --notebook_path ~/logseq
# Obsidian users
target/debug/fire_seq_search_server --notebook_path ~/obsidian --obsidian-md
```

Finally, update the [Firefox Addon](https://addons.mozilla.org/en-US/firefox/addon/fireseqsearch/).

#### Demo Video
https://github.com/user-attachments/assets/b0a4ca66-0a33-401a-a916-af7a69f2ae7b

This demo used [AstroWiki](https://github.com/AYelland/AstroWiki_2.0), which is licensed under MIT license.
185 changes: 135 additions & 50 deletions fireSeqSearch_addon/main.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// MIT License
// Copyright (c) 2021-2023 Zhenbo Li
// Copyright (c) 2021-2024 Zhenbo Li

const fireSeqSearchDomId = "fireSeqSearchDom";

Expand Down Expand Up @@ -128,79 +128,151 @@ function checkUserOptions() {
ShowHighlight: res[2].ShowHighlight,
ShowScore: res[3].ShowScore
}
consoleLogForDebug(options);
return options;
});
}


async function appendResultToSearchResult(fetchResultArray, _container) {
const serverInfo = fetchResultArray[0];
const rawSearchResult = fetchResultArray[1];
const firefoxExtensionUserOption = await checkUserOptions();
function parseRawList(rawSearchResult) {
const hits = [];
for (const rawRecord of rawSearchResult) {
const record = JSON.parse(rawRecord);
hits.push(record);
}
return hits;
}

consoleLogForDebug('Loaded user option: ' + JSON.stringify(firefoxExtensionUserOption));
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;
}
}
return null;
};
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;
}

function createTitleBarDom(count) {
const summary = createElementWithText("span", "");
summary.innerHTML = llmSummary;
summary.classList.add('fireSeqSearchLlmSummary');
targetRow.appendChild(summary);
};
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);
}
}


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

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);
const btn = document.createElement("button");

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");
const text = document.createTextNode("Hide Summary (Tmp)");
let text = document.createTextNode("Hide Summary");
btn.appendChild(text);
btn.onclick = function () {
// alert("Button is clicked");
for (const el of document.querySelectorAll('.fireSeqSearchHitSummary')) {
// el.style.visibility = 'hidden';
el.remove();
}
setSummaryState(".fireSeqSearchHitSummary", false);
setSummaryState(".fireSeqSearchLlmSummary", false);
};
titleBar.appendChild(btn);
return titleBar;
}
function createFireSeqDom() {
const div = document.createElement("div");
div.setAttribute("id", fireSeqSearchDomId);
return div;
}

const dom = createFireSeqDom();
dom.appendChild(createTitleBarDom(rawSearchResult.length));
consoleLogForDebug(dom);

const hitList = document.createElement("ul");
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);

consoleLogForDebug(rawSearchResult);
for (const rawRecord of rawSearchResult) {
// const e = document.createTextNode(record);
consoleLogForDebug(rawRecord);
const record = JSON.parse(rawRecord);
consoleLogForDebug(typeof record);
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;
}

const li = createElementWithText("li", "");
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);
}
const href = createHrefToLogseq(record, serverInfo);
li.appendChild(href);

if (firefoxExtensionUserOption.ShowScore) {
const score = createElementWithText("span", String(record.score));
li.appendChild(score);
}
const href = createHrefToLogseq(record, serverInfo);
li.appendChild(href);
li.append(' ')
if (firefoxExtensionUserOption.ShowHighlight) {
const summary = createElementWithText("span", "");
summary.innerHTML = record.summary;
summary.classList.add('fireSeqSearchHitSummary');
li.appendChild(summary);
}
// let e = wrapRawRecordIntoElement(record, serverInfo);

// e.style.
hitList.appendChild(li);
// consoleLogForDebug("Added an element to the list");
hitList.appendChild(li);
}
return hitList;
}
const hitList = buildListItems(parsedSearchResult);
dom.appendChild(hitList);

if (firefoxExtensionUserOption.ExperimentalLayout) {
Expand Down Expand Up @@ -228,6 +300,21 @@ async function appendResultToSearchResult(fetchResultArray, _container) {
insertDivToWebpage(dom);
}

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

const serverInfo = fetchResultArray[0];
const rawSearchResult = fetchResultArray[1];
consoleLogForDebug(serverInfo);
const parsedSearchResult = parseRawList(rawSearchResult);

const fireDom = createFireSeqDom(serverInfo, parsedSearchResult);

appendResultToSearchResult(serverInfo, parsedSearchResult, fireDom);

}


function getSearchParameterFromCurrentPage() {
let searchParam = "";

Expand Down Expand Up @@ -259,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 @@ -269,8 +355,7 @@ function getSearchParameterFromCurrentPage() {
]).then(function (responses) {
return Promise.all(responses.map(function (response) {return response.json();}));
}).then(function (data) {
consoleLogForDebug(data);
return appendResultToSearchResult(data);
mainProcess(data);
}).then((_e) => {
const highlightedItems = document.querySelectorAll('.fireSeqSearchHighlight');
consoleLogForDebug(highlightedItems);
Expand Down
2 changes: 1 addition & 1 deletion fireSeqSearch_addon/manifest.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"manifest_version": 2,
"name": "fireSeqSearch",
"version": "0.1.4",
"version": "0.2.2",

"description": "Everytime you use the search engine, this plugin will search against your personal logseq notes.",

Expand Down
Loading

0 comments on commit fec3cd2

Please sign in to comment.