From b54527cab54402ebd4dd076729f3f3c6b6f78598 Mon Sep 17 00:00:00 2001 From: n4ze3m Date: Wed, 7 Feb 2024 21:07:41 +0530 Subject: [PATCH] Add deleteChatHistory method to PageAssitDatabase class and systemPromptForNonRagOption functions to ollama service --- package.json | 40 ++++----- src/background.ts | 36 +++++++- src/components/Option/Layout.tsx | 30 +++++-- .../Option/Playground/PlaygroundChat.tsx | 7 +- .../Option/Playground/PlaygroundEmpty.tsx | 86 +++++++++++++++++++ .../Option/Playground/PlaygroundForm.tsx | 8 +- src/components/Option/Settings.tsx | 39 +++++++++ src/components/Option/Settings/ollama.tsx | 55 ++++++++++++ src/components/Option/Settings/other.tsx | 52 +++++++++++ src/components/Option/Settings/prompt.tsx | 56 ++++++++++++ src/content.ts | 29 ------- src/hooks/useMessageOption.tsx | 4 +- src/libs/db.ts | 8 ++ src/services/ollama.ts | 9 ++ 14 files changed, 393 insertions(+), 66 deletions(-) create mode 100644 src/components/Option/Playground/PlaygroundEmpty.tsx create mode 100644 src/components/Option/Settings.tsx create mode 100644 src/components/Option/Settings/ollama.tsx create mode 100644 src/components/Option/Settings/other.tsx create mode 100644 src/components/Option/Settings/prompt.tsx delete mode 100644 src/content.ts diff --git a/package.json b/package.json index 926fa77..3c7e891 100644 --- a/package.json +++ b/package.json @@ -1,8 +1,8 @@ { "name": "pageassist", - "displayName": "Page Assist - AI Powered Browser Assistant", - "version": "0.0.1", - "description": "Use your local AI models to assist you in your daily browsing.", + "displayName": "Page Assist - Browse the Internet with Your Local AI Models", + "version": "1.0.0", + "description": "Page Assist is a browser extension that allows you to browse the internet with your local AI models. It is a privacy-focused and open-source project.", "author": "n4ze3m", "scripts": { "dev": "plasmo dev", @@ -55,32 +55,30 @@ }, "manifest": { "host_permissions": [ - "https://*/*", "http://*/*", - "http://*:11434/api/tags", - "http://*:11434/api/chat", - "https://*:11434/api/tags", - "https://*:11434/api/chat" + "https://*/*" ], - "web_accessible_resources": [ - { - "resources": [ - "popup.html" - ], - "matches": [ - "https://*/*", - "http://*/*" - ] + "commands": { + "_execute_action": { + "suggested_key": { + "default": "Ctrl+Shift+L" + } + }, + "execute_side_panel": { + "description": "Open the side panel", + "suggested_key": { + "default": "Ctrl+Shift+P" + } } - ], + }, "permissions": [ "storage", "activeTab", "scripting", "declarativeNetRequest", - "declarativeNetRequestFeedback", "action", - "unlimitedStorage" + "unlimitedStorage", + "contextMenus" ] } -} +} \ No newline at end of file diff --git a/src/background.ts b/src/background.ts index 172269e..add4d6b 100644 --- a/src/background.ts +++ b/src/background.ts @@ -12,5 +12,37 @@ chrome.runtime.onMessage.addListener(async (message) => { }) chrome.action.onClicked.addListener((tab) => { - chrome.tabs.create({url: chrome.runtime.getURL("options.html")}); -}); \ No newline at end of file + chrome.tabs.create({ url: chrome.runtime.getURL("options.html") }) +}) + +chrome.commands.onCommand.addListener((command) => { + switch (command) { + case "execute_side_panel": + chrome.tabs.query({ active: true, currentWindow: true }, async (tabs) => { + const tab = tabs[0] + await chrome.sidePanel.open({ + tabId: tab.id + }) + }) + break + default: + break + } +}) + +chrome.contextMenus.create({ + id: "open-side-panel-pa", + title: "Open Side Panel to Chat", + contexts: ["all"] +}) + +chrome.contextMenus.onClicked.addListener((info, tab) => { + if (info.menuItemId === "open-side-panel-pa") { + chrome.tabs.query({ active: true, currentWindow: true }, async (tabs) => { + const tab = tabs[0] + await chrome.sidePanel.open({ + tabId: tab.id + }) + }) + } +}) diff --git a/src/components/Option/Layout.tsx b/src/components/Option/Layout.tsx index 99b9422..6c7dd4a 100644 --- a/src/components/Option/Layout.tsx +++ b/src/components/Option/Layout.tsx @@ -15,11 +15,13 @@ import logoImage from "data-base64:~assets/icon.png" import { Link, useParams, useLocation, useNavigate } from "react-router-dom" import { Sidebar } from "./Sidebar" -import { Drawer, Layout, Select } from "antd" +import { Drawer, Layout, Modal, Select } from "antd" import { useQuery } from "@tanstack/react-query" import { fetchModels } from "~services/ollama" import { useMessageOption } from "~hooks/useMessageOption" import { PanelLeftIcon, Settings2 } from "lucide-react" +import { Settings } from "./Settings" +import { useDarkMode } from "~hooks/useDarkmode" const navigation = [ { name: "Embed", href: "/bot/:id", icon: TagIcon }, @@ -51,8 +53,7 @@ export default function OptionLayout({ children: React.ReactNode }) { const [sidebarOpen, setSidebarOpen] = useState(false) - const params = useParams<{ id: string }>() - const location = useLocation() + const [open, setOpen] = useState(false) const { data: models, @@ -66,9 +67,10 @@ export default function OptionLayout({ const { selectedModel, setSelectedModel } = useMessageOption() + return ( -
+
- +
@@ -104,10 +111,19 @@ export default function OptionLayout({ placement="left" closeIcon={null} onClose={() => setSidebarOpen(false)} - open={sidebarOpen} - > + open={sidebarOpen}> + + setOpen(false)} + footer={null} + onCancel={() => setOpen(false)}> + setOpen(false)} /> + ) } diff --git a/src/components/Option/Playground/PlaygroundChat.tsx b/src/components/Option/Playground/PlaygroundChat.tsx index 4eacd62..9e1c42c 100644 --- a/src/components/Option/Playground/PlaygroundChat.tsx +++ b/src/components/Option/Playground/PlaygroundChat.tsx @@ -2,6 +2,7 @@ import React from "react" import { useMessage } from "~hooks/useMessage" import { useMessageOption } from "~hooks/useMessageOption" import { PlaygroundMessage } from "./PlaygroundMessage" +import { PlaygroundEmpty } from "./PlaygroundEmpty" export const PlaygroundChat = () => { const { messages } = useMessageOption() @@ -13,7 +14,11 @@ export const PlaygroundChat = () => { }) return (
- {/* {messages.length === 0 &&
no message
} */} + {messages.length === 0 && ( +
+ +
+ )} {messages.length > 0 &&
} {messages.map((message, index) => ( { + const [ollamaURL, setOllamaURL] = useState("") + const { + data: ollamaInfo, + status: ollamaStatus, + refetch, + isRefetching + } = useQuery({ + queryKey: ["ollamaStatus"], + queryFn: async () => { + const ollamaURL = await getOllamaURL() + const isOk = await isOllamaRunning() + + return { + isOk, + ollamaURL + } + } + }) + + useEffect(() => { + if (ollamaInfo?.ollamaURL) { + setOllamaURL(ollamaInfo.ollamaURL) + } + }, [ollamaInfo]) + + return ( +
+
+ {(ollamaStatus === "pending" || isRefetching) && ( +
+
+

+ Searching for Your Ollama 🦙 +

+
+ )} + {!isRefetching && ollamaStatus === "success" ? ( + ollamaInfo.isOk ? ( +
+
+

+ Ollama is running 🦙 +

+
+ ) : ( +
+
+
+

+ Unable to connect to Ollama 🦙 +

+
+ + setOllamaURL(e.target.value)} + /> + + +
+ ) + ) : null} +
+
+ ) +} diff --git a/src/components/Option/Playground/PlaygroundForm.tsx b/src/components/Option/Playground/PlaygroundForm.tsx index dd6b96c..3b7e64a 100644 --- a/src/components/Option/Playground/PlaygroundForm.tsx +++ b/src/components/Option/Playground/PlaygroundForm.tsx @@ -66,7 +66,7 @@ export const PlaygroundForm = ({ dropedFile }: Props) => { }) return ( -
+
{ onClick={() => { form.setFieldValue("image", "") }} - className="absolute top-2 right-2 bg-white dark:bg-black p-1 rounded-full hover:bg-gray-100 dark:hover:bg-gray-600 text-black dark:text-gray-100"> + className="absolute top-2 right-2 bg-white dark:bg-[#262626] p-1 rounded-full hover:bg-gray-100 dark:hover:bg-gray-600 text-black dark:text-gray-100">
@@ -109,7 +109,7 @@ export const PlaygroundForm = ({ dropedFile }: Props) => { }) })} className="shrink-0 flex-grow flex items-center "> -
+
+
+
+ + Delete Chat History + + + +
+
+ ) +} diff --git a/src/components/Option/Settings/prompt.tsx b/src/components/Option/Settings/prompt.tsx new file mode 100644 index 0000000..71294e2 --- /dev/null +++ b/src/components/Option/Settings/prompt.tsx @@ -0,0 +1,56 @@ +import { useQuery } from "@tanstack/react-query" +import { useEffect, useState } from "react" +import { SaveButton } from "~components/Common/SaveButton" +import { + setSystemPromptForNonRagOption, + systemPromptForNonRagOption +} from "~services/ollama" + +export const SettingPrompt = () => { + const [ollamaPrompt, setOllamaPrompt] = useState("") + const { data: ollamaInfo } = useQuery({ + queryKey: ["fetchOllaPrompt"], + queryFn: async () => { + const prompt = await systemPromptForNonRagOption() + + return { + prompt + } + } + }) + + useEffect(() => { + if (ollamaInfo?.prompt) { + setOllamaPrompt(ollamaInfo.prompt) + } + }, [ollamaInfo]) + + return ( +
+
+ +