Skip to content

Commit

Permalink
Merge pull request #165 from andrewnguonly/1.0.14
Browse files Browse the repository at this point in the history
PR for app version `1.0.14`
  • Loading branch information
andrewnguonly authored Apr 14, 2024
2 parents b5fafbc + 7f8383a commit a68ebda
Show file tree
Hide file tree
Showing 12 changed files with 102 additions and 37 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

A RAG LLM co-pilot for browsing the web, powered by local LLMs.

![Screenshot of Lumos](./screenshots/lumos_screenshot_4.png)
![Screenshot of Lumos](./screenshots/lumos_screenshot_5.png)

This Chrome extension is powered by [Ollama](https://ollama.ai/). Inference is done on your local machine without any _remote_ server support. However, due to security constraints in the Chrome extension platform, the app does rely on _local_ server support to run the LLM. This app is inspired by the [Chrome extension example](https://github.com/mlc-ai/web-llm/tree/main/examples/chrome-extension) provided by the [Web LLM project](https://webllm.mlc.ai/) and the [local LLM examples](https://js.langchain.com/docs/use_cases/question_answering/local_retrieval_qa) provided by [LangChain](https://github.com/langchain-ai/langchainjs).

Expand Down Expand Up @@ -220,6 +220,7 @@ Note: Content that is highlighted will not be cached in the vector store cache.
- `cmd + ;`: Open/close Chat History panel.
- `ctrl + c`: Cancel request (LLM request/streaming or embeddings generation)
- `ctrl + x`: Remove file attachment.
- `ctrl + r`: Regenerate last LLM response.

## Multimodal

Expand Down
2 changes: 1 addition & 1 deletion manifest.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"version": "1.0.13",
"version": "1.0.14",
"manifest_version": 3,
"name": "Lumos",
"description": "An LLM co-pilot for browsing the web, powered by local LLMs. Your prompts never leave the browser.",
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "lumos",
"version": "1.0.13",
"version": "1.0.14",
"private": true,
"dependencies": {
"@chatscope/chat-ui-kit-react": "^1.10.1",
Expand Down
Binary file removed screenshots/lumos_screenshot_4.png
Binary file not shown.
Binary file added screenshots/lumos_screenshot_5.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 5 additions & 5 deletions src/components/ChatBar.css
Original file line number Diff line number Diff line change
@@ -1,24 +1,24 @@
.chat-container {
.lumos-chat-container {
height: 200px;
}

.chat-bar {
.lumos-chat-bar {
display: flex;
justify-content: space-between;
width: 100%;
}

.input-field {
.lumos-input-field {
flex: 1;
}

.submit-button {
.lumos-submit-button {
flex: 1;
width: 40px;
height: 40px;
}

.clear-button {
.lumos-clear-button {
flex: 1;
width: 40px;
height: 40px;
Expand Down
91 changes: 74 additions & 17 deletions src/components/ChatBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ import AttachmentIcon from "@mui/icons-material/Attachment";
import HistoryIcon from "@mui/icons-material/History";
import InfoIcon from "@mui/icons-material/Info";
import PlaylistRemoveIcon from "@mui/icons-material/PlaylistRemove";
import RefreshIcon from "@mui/icons-material/Refresh";
import SaveAltIcon from "@mui/icons-material/SaveAlt";
import SettingsIcon from "@mui/icons-material/Settings";
import {
Alert,
Box,
Expand Down Expand Up @@ -111,8 +113,7 @@ const ChatBar: React.FC = () => {
};

const handlePromptChange = (event: ChangeEvent<HTMLInputElement>) => {
setPrompt(event.target.value);
chrome.storage.session.set({ prompt: event.target.value });
savePrompt(event.target.value);
};

const handleParsingDisabledChange = (
Expand Down Expand Up @@ -181,6 +182,11 @@ const ChatBar: React.FC = () => {
chrome.storage.session.set({ messages: messages });
};

const savePrompt = (prompt: string) => {
setPrompt(prompt);
chrome.storage.session.set({ prompt: prompt });
};

const saveCurrentChatId = (chatId: string) => {
setCurrentChatId(chatId);
chrome.storage.session.set({ currentChatId: chatId });
Expand Down Expand Up @@ -224,15 +230,15 @@ const ChatBar: React.FC = () => {
// add new chat to chat history
newChatHistory[newChatId] = {
updatedAt: Date.now(),
preview: messages[0].message,
preview: messages[1].message.slice(0, 50),
messages: messages,
};
} else {
// create new chat history in local storage
newChatHistory = {
[newChatId]: {
updatedAt: Date.now(),
preview: messages[0].message,
preview: messages[1].message.slice(0, 50),
messages: messages,
},
};
Expand Down Expand Up @@ -265,7 +271,14 @@ const ChatBar: React.FC = () => {
}
};

const promptWithContent = async () => {
const setLoading = () => {
setLoading1(true);
setLoading1Text("Raise your wand...");
setSubmitDisabled(true);
setPromptPlaceholderText("Press ctrl + c to cancel the request");
};

const promptWithContent = async (prompt: string) => {
// get default options
const options = await getLumosOptions();
const contentConfig = options.contentConfig;
Expand Down Expand Up @@ -331,10 +344,7 @@ const ChatBar: React.FC = () => {
};

const handleSendButtonClick = async () => {
setLoading1(true);
setLoading1Text("Raise your wand...");
setSubmitDisabled(true);
setPromptPlaceholderText("Press ctrl + c to cancel the request");
setLoading();

// save user message to messages list
const newMessages = [...messages, new LumosMessage("user", prompt)];
Expand All @@ -343,18 +353,37 @@ const ChatBar: React.FC = () => {
if (parsingDisabled) {
chrome.runtime.sendMessage({ prompt: prompt, skipRAG: true });
} else {
promptWithContent();
promptWithContent(prompt);
}

// clear prompt after sending it to the background script
setPrompt("");
chrome.storage.session.set({ prompt: "" });
savePrompt("");
};

const cancelRequest = () => {
chrome.runtime.sendMessage({ cancelRequest: true });
};

const regenerate = () => {
setLoading();

// delete last message (assistant/tool message)
const newMessages = messages.slice(0, messages.length - 1);
saveMessages(newMessages);

// get last message (user message)
const lastUserPrompt = newMessages[newMessages.length - 1].message;

if (parsingDisabled) {
chrome.runtime.sendMessage({ prompt: lastUserPrompt, skipRAG: true });
} else {
promptWithContent(lastUserPrompt);
}

// clear prompt after sending it to the background script
savePrompt("");
};

const handleAvatarClick = (message: string) => {
navigator.clipboard.writeText(message);
setShowSnackbar(true);
Expand Down Expand Up @@ -404,6 +433,10 @@ const ChatBar: React.FC = () => {
// remove attachment
handleAttachmentDelete();
break;
case "r":
// regenerate last LLM response
regenerate();
break;
}
}
};
Expand Down Expand Up @@ -562,7 +595,10 @@ const ChatBar: React.FC = () => {
<Drawer open={openChatHistory} onClose={() => setOpenChatHistory(false)}>
<ChatHistory loadChat={loadChat} />
</Drawer>
<Box className="chat-container" sx={{ height: chatContainerHeight }}>
<Box
className="lumos-chat-container"
sx={{ height: chatContainerHeight }}
>
<Snackbar
anchorOrigin={{ vertical: "top", horizontal: "center" }}
open={showSnackbar}
Expand Down Expand Up @@ -623,6 +659,20 @@ const ChatBar: React.FC = () => {
>
{message.message.trim()}
</Markdown>
{message.sender === "assistant" &&
index === messages.length - 1 && (
<Box sx={{ display: "flex", alignItems: "center" }}>
<div style={{ flex: 1 }}></div>
<IconButton
sx={{ padding: 0 }}
size="small"
color="secondary"
onClick={regenerate}
>
<RefreshIcon />
</IconButton>
</Box>
)}
</Message.CustomContent>
</Message>
))}
Expand Down Expand Up @@ -678,11 +728,18 @@ const ChatBar: React.FC = () => {
<Button onClick={() => handleChangeHeight(-50)}>
<Typography sx={{ fontWeight: "bold", fontSize: 14 }}>-</Typography>
</Button>
<Button
onClick={() => {
chrome.runtime.openOptionsPage();
}}
>
<SettingsIcon sx={{ fontWeight: "bold", fontSize: 20 }} />
</Button>
</ButtonGroup>
</Box>
<Box className="chat-bar">
<Box className="lumos-chat-bar">
<TextField
className="input-field"
className="lumos-input-field"
multiline
maxRows={5}
placeholder={promptPlaceholderText}
Expand Down Expand Up @@ -721,7 +778,7 @@ const ChatBar: React.FC = () => {
}}
/>
<IconButton
className="submit-button"
className="lumos-submit-button"
disabled={submitDisabled || prompt === ""}
onClick={handleSendButtonClick}
style={imageStyle}
Expand All @@ -730,7 +787,7 @@ const ChatBar: React.FC = () => {
</IconButton>
<Tooltip title="Clear messages (cmd + k)">
<IconButton
className="clear-button"
className="lumos-clear-button"
disabled={submitDisabled}
onClick={handleClearButtonClick}
style={imageStyle}
Expand Down
4 changes: 2 additions & 2 deletions src/pages/Options.css
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
.options-popup {
.lumos-options-popup {
width: 100%;
height: 450px;
box-sizing: border-box;
padding: 10px;
overflow-x: hidden;
}

.options-input {
.lumos-options-input {
width: 100%;
}
18 changes: 11 additions & 7 deletions src/pages/Options.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,11 @@ export const DEFAULT_TOOL_CONFIG: ToolConfig = {
},
};
export const MULTIMODAL_MODELS = ["llava", "bakllava"];
export const EMBEDDING_MODELS = ["nomic-embed-text", "all-minilm"];
export const EMBEDDING_MODELS = [
"nomic-embed-text",
"all-minilm",
"mxbai-embed-large",
];
export const SUPPORTED_IMG_FORMATS = ["jpeg", "jpg", "png"];
export const CHAT_CONTAINER_HEIGHT_MIN = 200;
export const CHAT_CONTAINER_HEIGHT_MAX = 500;
Expand Down Expand Up @@ -281,8 +285,8 @@ const Options: React.FC = () => {

return (
<ThemeProvider theme={theme}>
<Box className="options-popup">
<FormControl className="options-input" size="small">
<Box className="lumos-options-popup">
<FormControl className="lumos-options-input" size="small">
<InputLabel id="ollama-model-select-label">Ollama Model</InputLabel>
<Select
sx={{ "margin-bottom": "15px" }}
Expand All @@ -309,7 +313,7 @@ const Options: React.FC = () => {
})}
</Select>
</FormControl>
<FormControl className="options-input" size="small">
<FormControl className="lumos-options-input" size="small">
<InputLabel id="ollama-embedding-select-label">
Ollama Embedding Model
</InputLabel>
Expand All @@ -335,7 +339,7 @@ const Options: React.FC = () => {
</Select>
</FormControl>
<TextField
className="options-input"
className="lumos-options-input"
sx={{ "margin-bottom": "15px" }}
label="Ollama Host"
value={host}
Expand All @@ -344,7 +348,7 @@ const Options: React.FC = () => {
onChange={handleHostChange}
/>
<TextField
className="options-input"
className="lumos-options-input"
sx={{ "margin-bottom": "15px" }}
type="number"
label="Vector Store TTL (minutes)"
Expand All @@ -353,7 +357,7 @@ const Options: React.FC = () => {
onChange={handleVectorStoreTTLMinsChange}
/>
<TextField
className="options-input"
className="lumos-options-input"
sx={{ "margin-bottom": "15px" }}
label="Content Parser Config"
multiline
Expand Down
2 changes: 1 addition & 1 deletion src/pages/Popup.css
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
.popup {
.lumos-popup {
width: 550px;
padding: 10px;
}
2 changes: 1 addition & 1 deletion src/pages/Popup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import "./Popup.css";

const Popup: React.FC = () => {
return (
<div className="popup">
<div className="lumos-popup">
<ChatBar />
</div>
);
Expand Down
5 changes: 4 additions & 1 deletion src/themes/AppTheme.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
import { amber, lightGreen } from "@mui/material/colors";
import { amber, blue, lightGreen, purple } from "@mui/material/colors";
import { createTheme, Theme } from "@mui/material/styles";

const getAppTheme = (darkMode: boolean): Theme => {
return createTheme({
palette: {
mode: darkMode ? "dark" : "light",
primary: darkMode ? lightGreen : amber,
secondary: {
main: darkMode ? blue[800] : purple[300],
},
text: {
primary: darkMode ? "#aed581" : "#212121",
},
Expand Down

0 comments on commit a68ebda

Please sign in to comment.