Migrated to WXT
1
.gitignore
vendored
@ -40,3 +40,4 @@ keys.json
|
||||
|
||||
# typescript
|
||||
.tsbuildinfo
|
||||
.wxt
|
43
package.json
@ -5,9 +5,14 @@
|
||||
"description": "Use your locally running AI models to assist you in your web browsing.",
|
||||
"author": "n4ze3m",
|
||||
"scripts": {
|
||||
"dev": "plasmo dev",
|
||||
"build": "plasmo build",
|
||||
"package": "plasmo package"
|
||||
"dev": "wxt",
|
||||
"dev:firefox": "wxt -b firefox",
|
||||
"build": "wxt build",
|
||||
"build:firefox": "wxt build -b firefox",
|
||||
"zip": "wxt zip",
|
||||
"zip:firefox": "wxt zip -b firefox",
|
||||
"compile": "tsc --noEmit",
|
||||
"postinstall": "wxt prepare"
|
||||
},
|
||||
"dependencies": {
|
||||
"@ant-design/cssinjs": "^1.18.4",
|
||||
@ -21,6 +26,7 @@
|
||||
"@tailwindcss/forms": "^0.5.7",
|
||||
"@tailwindcss/typography": "^0.5.10",
|
||||
"@tanstack/react-query": "^5.17.19",
|
||||
"@vitejs/plugin-react": "^4.2.1",
|
||||
"antd": "^5.13.3",
|
||||
"axios": "^1.6.7",
|
||||
"dayjs": "^1.11.10",
|
||||
@ -53,34 +59,7 @@
|
||||
"postcss": "^8.4.33",
|
||||
"prettier": "3.2.4",
|
||||
"tailwindcss": "^3.4.1",
|
||||
"typescript": "5.3.3"
|
||||
},
|
||||
"manifest": {
|
||||
"host_permissions": [
|
||||
"http://*/*",
|
||||
"https://*/*"
|
||||
],
|
||||
"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",
|
||||
"action",
|
||||
"unlimitedStorage",
|
||||
"contextMenus"
|
||||
]
|
||||
"typescript": "5.3.3",
|
||||
"wxt": "^0.17.7"
|
||||
}
|
||||
}
|
||||
|
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 2.9 KiB |
@ -1,138 +0,0 @@
|
||||
import { getOllamaURL, isOllamaRunning } from "~services/ollama"
|
||||
|
||||
export {}
|
||||
|
||||
const progressHuman = (completed: number, total: number) => {
|
||||
return ((completed / total) * 100).toFixed(0) + "%"
|
||||
}
|
||||
|
||||
const clearBadge = () => {
|
||||
chrome.action.setBadgeText({ text: "" })
|
||||
chrome.action.setTitle({ title: "" })
|
||||
}
|
||||
|
||||
const streamDownload = async (url: string, model: string) => {
|
||||
url += "/api/pull"
|
||||
const response = await fetch(url, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json"
|
||||
},
|
||||
body: JSON.stringify({ model, stream: true })
|
||||
})
|
||||
|
||||
const reader = response.body?.getReader()
|
||||
|
||||
const decoder = new TextDecoder()
|
||||
|
||||
let isSuccess = true
|
||||
while (true) {
|
||||
const { done, value } = await reader.read()
|
||||
|
||||
if (done) {
|
||||
break
|
||||
}
|
||||
|
||||
const text = decoder.decode(value)
|
||||
try {
|
||||
const json = JSON.parse(text.trim()) as {
|
||||
status: string
|
||||
total?: number
|
||||
completed?: number
|
||||
}
|
||||
if (json.total && json.completed) {
|
||||
chrome.action.setBadgeText({
|
||||
text: progressHuman(json.completed, json.total)
|
||||
})
|
||||
chrome.action.setBadgeBackgroundColor({ color: "#0000FF" })
|
||||
} else {
|
||||
chrome.action.setBadgeText({ text: "🏋️♂️" })
|
||||
chrome.action.setBadgeBackgroundColor({ color: "#FFFFFF" })
|
||||
}
|
||||
|
||||
chrome.action.setTitle({ title: json.status })
|
||||
|
||||
if (json.status === "success") {
|
||||
isSuccess = true
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
}
|
||||
|
||||
if (isSuccess) {
|
||||
chrome.action.setBadgeText({ text: "✅" })
|
||||
chrome.action.setBadgeBackgroundColor({ color: "#00FF00" })
|
||||
chrome.action.setTitle({ title: "Model pulled successfully" })
|
||||
} else {
|
||||
chrome.action.setBadgeText({ text: "❌" })
|
||||
chrome.action.setBadgeBackgroundColor({ color: "#FF0000" })
|
||||
chrome.action.setTitle({ title: "Model pull failed" })
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
clearBadge()
|
||||
}, 5000)
|
||||
}
|
||||
|
||||
chrome.runtime.onMessage.addListener(async (message) => {
|
||||
if (message.type === "sidepanel") {
|
||||
chrome.tabs.query({ active: true, currentWindow: true }, async (tabs) => {
|
||||
const tab = tabs[0]
|
||||
await chrome.sidePanel.open({
|
||||
tabId: tab.id
|
||||
})
|
||||
})
|
||||
} else if (message.type === "pull_model") {
|
||||
const ollamaURL = await getOllamaURL()
|
||||
|
||||
const isRunning = await isOllamaRunning()
|
||||
|
||||
if (!isRunning) {
|
||||
chrome.action.setBadgeText({ text: "E" })
|
||||
chrome.action.setBadgeBackgroundColor({ color: "#FF0000" })
|
||||
chrome.action.setTitle({ title: "Ollama is not running" })
|
||||
setTimeout(() => {
|
||||
clearBadge()
|
||||
}, 5000)
|
||||
}
|
||||
|
||||
await streamDownload(ollamaURL, message.modelName)
|
||||
}
|
||||
})
|
||||
|
||||
chrome.action.onClicked.addListener((tab) => {
|
||||
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
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
@ -14,7 +14,7 @@ import {
|
||||
RunnableMap,
|
||||
RunnableSequence,
|
||||
} from "langchain/schema/runnable";
|
||||
import type { ChatHistory } from "~store";
|
||||
import type { ChatHistory } from "~/store";
|
||||
type RetrievalChainInput = {
|
||||
chat_history: string;
|
||||
question: string;
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { useForm } from "@mantine/form"
|
||||
import React from "react"
|
||||
import useDynamicTextareaSize from "~hooks/useDynamicTextareaSize"
|
||||
import useDynamicTextareaSize from "~/hooks/useDynamicTextareaSize"
|
||||
|
||||
type Props = {
|
||||
value: string
|
||||
|
@ -1,13 +1,13 @@
|
||||
import { Form, Image, Input, Modal, Tooltip, message } from "antd"
|
||||
import { Share } from "lucide-react"
|
||||
import { useState } from "react"
|
||||
import type { Message } from "~store/option"
|
||||
import type { Message } from "~/store/option"
|
||||
import Markdown from "./Markdown"
|
||||
import React from "react"
|
||||
import { useMutation } from "@tanstack/react-query"
|
||||
import { getPageShareUrl } from "~services/ollama"
|
||||
import { cleanUrl } from "~libs/clean-url"
|
||||
import { getUserId, saveWebshare } from "~libs/db"
|
||||
import { getPageShareUrl } from "~/services/ollama"
|
||||
import { cleanUrl } from "~/libs/clean-url"
|
||||
import { getUserId, saveWebshare } from "~/libs/db"
|
||||
|
||||
type Props = {
|
||||
messages: Message[]
|
||||
|
@ -4,8 +4,8 @@ import { useLocation, NavLink } from "react-router-dom"
|
||||
import { Sidebar } from "../Option/Sidebar"
|
||||
import { Drawer, Select, Tooltip } from "antd"
|
||||
import { useQuery } from "@tanstack/react-query"
|
||||
import { getAllModels } from "~services/ollama"
|
||||
import { useMessageOption } from "~hooks/useMessageOption"
|
||||
import { getAllModels } from "~/services/ollama"
|
||||
import { useMessageOption } from "~/hooks/useMessageOption"
|
||||
import {
|
||||
ChevronLeft,
|
||||
CogIcon,
|
||||
@ -15,8 +15,8 @@ import {
|
||||
SquarePen,
|
||||
ZapIcon
|
||||
} from "lucide-react"
|
||||
import { getAllPrompts } from "~libs/db"
|
||||
import { ShareBtn } from "~components/Common/ShareBtn"
|
||||
import { getAllPrompts } from "~/libs/db"
|
||||
import { ShareBtn } from "~/components/Common/ShareBtn"
|
||||
|
||||
export default function OptionLayout({
|
||||
children
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"
|
||||
import { Skeleton, Table, Tag, Tooltip, notification, Modal, Input } from "antd"
|
||||
import { bytePerSecondFormatter } from "~libs/byte-formater"
|
||||
import { deleteModel, getAllModels } from "~services/ollama"
|
||||
import { bytePerSecondFormatter } from "~/libs/byte-formater"
|
||||
import { deleteModel, getAllModels } from "~/services/ollama"
|
||||
import dayjs from "dayjs"
|
||||
import relativeTime from "dayjs/plugin/relativeTime"
|
||||
import { useState } from "react"
|
||||
|
@ -1,7 +1,7 @@
|
||||
import React from "react"
|
||||
import { useMessageOption } from "~hooks/useMessageOption"
|
||||
import { useMessageOption } from "~/hooks/useMessageOption"
|
||||
import { PlaygroundEmpty } from "./PlaygroundEmpty"
|
||||
import { PlaygroundMessage } from "~components/Common/Playground/Message"
|
||||
import { PlaygroundMessage } from "~/components/Common/Playground/Message"
|
||||
|
||||
export const PlaygroundChat = () => {
|
||||
const {
|
||||
|
@ -5,7 +5,7 @@ import {
|
||||
getOllamaURL,
|
||||
isOllamaRunning,
|
||||
setOllamaURL as saveOllamaURL
|
||||
} from "~services/ollama"
|
||||
} from "~/services/ollama"
|
||||
|
||||
export const PlaygroundEmpty = () => {
|
||||
const [ollamaURL, setOllamaURL] = useState<string>("")
|
||||
|
@ -1,16 +1,16 @@
|
||||
import { useForm } from "@mantine/form"
|
||||
import { useMutation, useQueryClient } from "@tanstack/react-query"
|
||||
import React from "react"
|
||||
import useDynamicTextareaSize from "~hooks/useDynamicTextareaSize"
|
||||
import { toBase64 } from "~libs/to-base64"
|
||||
import { useMessageOption } from "~hooks/useMessageOption"
|
||||
import useDynamicTextareaSize from "~/hooks/useDynamicTextareaSize"
|
||||
import { toBase64 } from "~/libs/to-base64"
|
||||
import { useMessageOption } from "~/hooks/useMessageOption"
|
||||
import { Checkbox, Dropdown, Switch, Tooltip } from "antd"
|
||||
import { Image } from "antd"
|
||||
import { useSpeechRecognition } from "~hooks/useSpeechRecognition"
|
||||
import { useWebUI } from "~store/webui"
|
||||
import { defaultEmbeddingModelForRag } from "~services/ollama"
|
||||
import { useSpeechRecognition } from "~/hooks/useSpeechRecognition"
|
||||
import { useWebUI } from "~/store/webui"
|
||||
import { defaultEmbeddingModelForRag } from "~/services/ollama"
|
||||
import { ImageIcon, MicIcon, StopCircleIcon, X } from "lucide-react"
|
||||
import { getVariable } from "~utils/select-varaible"
|
||||
import { getVariable } from "~/utils/select-varaible"
|
||||
|
||||
type Props = {
|
||||
dropedFile: File | undefined
|
||||
|
@ -16,7 +16,7 @@ import {
|
||||
getAllPrompts,
|
||||
savePrompt,
|
||||
updatePrompt
|
||||
} from "~libs/db"
|
||||
} from "~/libs/db"
|
||||
|
||||
export const PromptBody = () => {
|
||||
const queryClient = useQueryClient()
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { useMutation, useQuery } from "@tanstack/react-query"
|
||||
import { Form, InputNumber, Select, Skeleton } from "antd"
|
||||
import { useState } from "react"
|
||||
import { SaveButton } from "~components/Common/SaveButton"
|
||||
import { SaveButton } from "~/components/Common/SaveButton"
|
||||
import {
|
||||
defaultEmbeddingChunkOverlap,
|
||||
defaultEmbeddingChunkSize,
|
||||
@ -10,7 +10,7 @@ import {
|
||||
getOllamaURL,
|
||||
saveForRag,
|
||||
setOllamaURL as saveOllamaURL
|
||||
} from "~services/ollama"
|
||||
} from "~/services/ollama"
|
||||
import { SettingPrompt } from "./prompt"
|
||||
|
||||
export const SettingsOllama = () => {
|
||||
|
@ -1,9 +1,9 @@
|
||||
import { useQueryClient } from "@tanstack/react-query"
|
||||
import { useDarkMode } from "~hooks/useDarkmode"
|
||||
import { useMessageOption } from "~hooks/useMessageOption"
|
||||
import { PageAssitDatabase } from "~libs/db"
|
||||
import { useDarkMode } from "~/hooks/useDarkmode"
|
||||
import { useMessageOption } from "~/hooks/useMessageOption"
|
||||
import { PageAssitDatabase } from "~/libs/db"
|
||||
import { Select } from "antd"
|
||||
import { SUPPORTED_LANGUAGES } from "~utils/supporetd-languages"
|
||||
import { SUPPORTED_LANGUAGES } from "~/utils/supporetd-languages"
|
||||
import { MoonIcon, SunIcon } from "lucide-react"
|
||||
import { SearchModeSettings } from "./search-mode"
|
||||
|
||||
|
@ -1,14 +1,14 @@
|
||||
import { useQuery, useQueryClient } from "@tanstack/react-query"
|
||||
import { Skeleton, Radio, Form, Alert } from "antd"
|
||||
import React from "react"
|
||||
import { SaveButton } from "~components/Common/SaveButton"
|
||||
import { SaveButton } from "~/components/Common/SaveButton"
|
||||
import {
|
||||
getWebSearchPrompt,
|
||||
setSystemPromptForNonRagOption,
|
||||
systemPromptForNonRagOption,
|
||||
geWebSearchFollowUpPrompt,
|
||||
setWebPrompts
|
||||
} from "~services/ollama"
|
||||
} from "~/services/ollama"
|
||||
|
||||
export const SettingPrompt = () => {
|
||||
const [selectedValue, setSelectedValue] = React.useState<"normal" | "web">(
|
||||
|
@ -3,7 +3,7 @@ import { Skeleton, Switch } from "antd"
|
||||
import {
|
||||
getIsSimpleInternetSearch,
|
||||
setIsSimpleInternetSearch
|
||||
} from "~services/ollama"
|
||||
} from "~/services/ollama"
|
||||
|
||||
export const SearchModeSettings = () => {
|
||||
const { data, status } = useQuery({
|
||||
|
@ -1,10 +1,10 @@
|
||||
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"
|
||||
import { Form, Input, Skeleton, Table, Tooltip, message } from "antd"
|
||||
import { Trash2 } from "lucide-react"
|
||||
import { SaveButton } from "~components/Common/SaveButton"
|
||||
import { deleteWebshare, getAllWebshares, getUserId } from "~libs/db"
|
||||
import { getPageShareUrl, setPageShareUrl } from "~services/ollama"
|
||||
import { verifyPageShareURL } from "~utils/verify-page-share"
|
||||
import { SaveButton } from "~/components/Common/SaveButton"
|
||||
import { deleteWebshare, getAllWebshares, getUserId } from "~/libs/db"
|
||||
import { getPageShareUrl, setPageShareUrl } from "~/services/ollama"
|
||||
import { verifyPageShareURL } from "~/utils/verify-page-share"
|
||||
|
||||
export const OptionShareBody = () => {
|
||||
const queryClient = useQueryClient()
|
||||
|
@ -5,9 +5,9 @@ import {
|
||||
formatToMessage,
|
||||
deleteByHistoryId,
|
||||
updateHistory
|
||||
} from "~libs/db"
|
||||
} from "~/libs/db"
|
||||
import { Empty, Skeleton } from "antd"
|
||||
import { useMessageOption } from "~hooks/useMessageOption"
|
||||
import { useMessageOption } from "~/hooks/useMessageOption"
|
||||
import { useState } from "react"
|
||||
import { PencilIcon, Trash2 } from "lucide-react"
|
||||
import { useNavigate } from "react-router-dom"
|
||||
|
@ -1,6 +1,6 @@
|
||||
import React from "react"
|
||||
import { PlaygroundMessage } from "~components/Common/Playground/Message"
|
||||
import { useMessage } from "~hooks/useMessage"
|
||||
import { PlaygroundMessage } from "~/components/Common/Playground/Message"
|
||||
import { useMessage } from "~/hooks/useMessage"
|
||||
import { EmptySidePanel } from "../Chat/empty"
|
||||
|
||||
export const SidePanelBody = () => {
|
||||
|
@ -2,13 +2,13 @@ import { useQuery } from "@tanstack/react-query"
|
||||
import { Select } from "antd"
|
||||
import { RotateCcw } from "lucide-react"
|
||||
import { useEffect, useState } from "react"
|
||||
import { useMessage } from "~hooks/useMessage"
|
||||
import { useMessage } from "~/hooks/useMessage"
|
||||
import {
|
||||
getAllModels,
|
||||
getOllamaURL,
|
||||
isOllamaRunning,
|
||||
setOllamaURL as saveOllamaURL
|
||||
} from "~services/ollama"
|
||||
} from "~/services/ollama"
|
||||
|
||||
export const EmptySidePanel = () => {
|
||||
const [ollamaURL, setOllamaURL] = useState<string>("")
|
||||
|
@ -1,13 +1,13 @@
|
||||
import { useForm } from "@mantine/form"
|
||||
import { useMutation } from "@tanstack/react-query"
|
||||
import React from "react"
|
||||
import useDynamicTextareaSize from "~hooks/useDynamicTextareaSize"
|
||||
import { useMessage } from "~hooks/useMessage"
|
||||
import { toBase64 } from "~libs/to-base64"
|
||||
import useDynamicTextareaSize from "~/hooks/useDynamicTextareaSize"
|
||||
import { useMessage } from "~/hooks/useMessage"
|
||||
import { toBase64 } from "~/libs/to-base64"
|
||||
import { Checkbox, Dropdown, Image, Tooltip } from "antd"
|
||||
import { useSpeechRecognition } from "~hooks/useSpeechRecognition"
|
||||
import { useWebUI } from "~store/webui"
|
||||
import { defaultEmbeddingModelForRag } from "~services/ollama"
|
||||
import { useSpeechRecognition } from "~/hooks/useSpeechRecognition"
|
||||
import { useWebUI } from "~/store/webui"
|
||||
import { defaultEmbeddingModelForRag } from "~/services/ollama"
|
||||
import { ImageIcon, MicIcon, X } from "lucide-react"
|
||||
|
||||
type Props = {
|
||||
|
@ -1,5 +1,5 @@
|
||||
import logoImage from "data-base64:~assets/icon.png"
|
||||
import { useMessage } from "~hooks/useMessage"
|
||||
import logoImage from "~/assets/icon.png"
|
||||
import { useMessage } from "~/hooks/useMessage"
|
||||
import { Link } from "react-router-dom"
|
||||
import { Tooltip } from "antd"
|
||||
import { BoxesIcon, CogIcon, RefreshCcw } from "lucide-react"
|
||||
|
@ -12,13 +12,13 @@ import {
|
||||
defaultEmbeddingChunkSize,
|
||||
defaultEmbeddingModelForRag,
|
||||
saveForRag
|
||||
} from "~services/ollama"
|
||||
} from "~/services/ollama"
|
||||
|
||||
import { Skeleton, Radio, Select, Form, InputNumber } from "antd"
|
||||
import { useDarkMode } from "~hooks/useDarkmode"
|
||||
import { SaveButton } from "~components/Common/SaveButton"
|
||||
import { SUPPORTED_LANGUAGES } from "~utils/supporetd-languages"
|
||||
import { useMessage } from "~hooks/useMessage"
|
||||
import { useDarkMode } from "~/hooks/useDarkmode"
|
||||
import { SaveButton } from "~/components/Common/SaveButton"
|
||||
import { SUPPORTED_LANGUAGES } from "~/utils/supporetd-languages"
|
||||
import { useMessage } from "~/hooks/useMessage"
|
||||
import { MoonIcon, SunIcon } from "lucide-react"
|
||||
|
||||
export const SettingsBody = () => {
|
||||
|
@ -1,6 +1,7 @@
|
||||
import logoImage from "data-base64:~assets/icon.png"
|
||||
import { ChevronLeft } from "lucide-react"
|
||||
import { Link } from "react-router-dom"
|
||||
import logoImage from "~/assets/icon.png"
|
||||
|
||||
export const SidepanelSettingsHeader = () => {
|
||||
return (
|
||||
<div className="flex px-3 justify-start gap-3 bg-white dark:bg-[#171717] border-b border-gray-300 dark:border-gray-700 py-4 items-center">
|
||||
|
@ -1,54 +0,0 @@
|
||||
import type { PlasmoCSConfig } from "plasmo"
|
||||
|
||||
export const config: PlasmoCSConfig = {
|
||||
matches: ["*://ollama.com/library/*"],
|
||||
all_frames: true
|
||||
}
|
||||
|
||||
const downloadModel = async (modelName: string) => {
|
||||
const ok = confirm(
|
||||
`[Page Assist Extension] Do you want to pull ${modelName} model? This has nothing to do with Ollama.com website. The model will be pulled locally once you confirm.`
|
||||
)
|
||||
if (ok) {
|
||||
alert(
|
||||
`[Page Assist Extension] Pulling ${modelName} model. For more details, check the extension icon.`
|
||||
)
|
||||
|
||||
await chrome.runtime.sendMessage({
|
||||
type: "pull_model",
|
||||
modelName
|
||||
})
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
const downloadSVG = `<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="h-5 w-5 pageasssist-icon">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M3 16.5v2.25A2.25 2.25 0 0 0 5.25 21h13.5A2.25 2.25 0 0 0 21 18.75V16.5M16.5 12 12 16.5m0 0L7.5 12m4.5 4.5V3" />
|
||||
</svg>
|
||||
`
|
||||
const codeDiv = document.querySelectorAll("div.language-none")
|
||||
|
||||
for (let i = 0; i < codeDiv.length; i++) {
|
||||
const button = codeDiv[i].querySelector("button")
|
||||
const command = codeDiv[i].querySelector("input")
|
||||
if (button && command) {
|
||||
const newButton = document.createElement("button")
|
||||
newButton.innerHTML = downloadSVG
|
||||
newButton.className = `border-l ${button.className}`
|
||||
newButton.id = `download-${i}-pageassist`
|
||||
const modelName = command?.value
|
||||
.replace("ollama run", "")
|
||||
.replace("ollama pull", "")
|
||||
.trim()
|
||||
newButton.addEventListener("click", () => {
|
||||
downloadModel(modelName)
|
||||
})
|
||||
|
||||
const span = document.createElement("span")
|
||||
span.title = "Download model via Page Assist"
|
||||
span.appendChild(newButton)
|
||||
|
||||
button.parentNode.appendChild(span)
|
||||
}
|
||||
}
|
142
src/entries/background.ts
Normal file
@ -0,0 +1,142 @@
|
||||
|
||||
import { getOllamaURL, isOllamaRunning } from "../services/ollama"
|
||||
const progressHuman = (completed: number, total: number) => {
|
||||
return ((completed / total) * 100).toFixed(0) + "%"
|
||||
}
|
||||
|
||||
const clearBadge = () => {
|
||||
chrome.action.setBadgeText({ text: "" })
|
||||
chrome.action.setTitle({ title: "" })
|
||||
}
|
||||
const streamDownload = async (url: string, model: string) => {
|
||||
url += "/api/pull"
|
||||
const response = await fetch(url, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json"
|
||||
},
|
||||
body: JSON.stringify({ model, stream: true })
|
||||
})
|
||||
|
||||
const reader = response.body?.getReader()
|
||||
|
||||
const decoder = new TextDecoder()
|
||||
|
||||
let isSuccess = true
|
||||
while (true) {
|
||||
if (!reader) {
|
||||
break
|
||||
}
|
||||
const { done, value } = await reader.read()
|
||||
|
||||
if (done) {
|
||||
break
|
||||
}
|
||||
|
||||
const text = decoder.decode(value)
|
||||
try {
|
||||
const json = JSON.parse(text.trim()) as {
|
||||
status: string
|
||||
total?: number
|
||||
completed?: number
|
||||
}
|
||||
if (json.total && json.completed) {
|
||||
chrome.action.setBadgeText({
|
||||
text: progressHuman(json.completed, json.total)
|
||||
})
|
||||
chrome.action.setBadgeBackgroundColor({ color: "#0000FF" })
|
||||
} else {
|
||||
chrome.action.setBadgeText({ text: "🏋️♂️" })
|
||||
chrome.action.setBadgeBackgroundColor({ color: "#FFFFFF" })
|
||||
}
|
||||
|
||||
chrome.action.setTitle({ title: json.status })
|
||||
|
||||
if (json.status === "success") {
|
||||
isSuccess = true
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
}
|
||||
|
||||
if (isSuccess) {
|
||||
chrome.action.setBadgeText({ text: "✅" })
|
||||
chrome.action.setBadgeBackgroundColor({ color: "#00FF00" })
|
||||
chrome.action.setTitle({ title: "Model pulled successfully" })
|
||||
} else {
|
||||
chrome.action.setBadgeText({ text: "❌" })
|
||||
chrome.action.setBadgeBackgroundColor({ color: "#FF0000" })
|
||||
chrome.action.setTitle({ title: "Model pull failed" })
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
clearBadge()
|
||||
}, 5000)
|
||||
}
|
||||
export default defineBackground({
|
||||
main() {
|
||||
chrome.runtime.onMessage.addListener(async (message) => {
|
||||
if (message.type === "sidepanel") {
|
||||
chrome.tabs.query({ active: true, currentWindow: true }, async (tabs) => {
|
||||
const tab = tabs[0]
|
||||
chrome.sidePanel.open({
|
||||
tabId: tab.id!
|
||||
})
|
||||
})
|
||||
} else if (message.type === "pull_model") {
|
||||
const ollamaURL = await getOllamaURL()
|
||||
|
||||
const isRunning = await isOllamaRunning()
|
||||
|
||||
if (!isRunning) {
|
||||
chrome.action.setBadgeText({ text: "E" })
|
||||
chrome.action.setBadgeBackgroundColor({ color: "#FF0000" })
|
||||
chrome.action.setTitle({ title: "Ollama is not running" })
|
||||
setTimeout(() => {
|
||||
clearBadge()
|
||||
}, 5000)
|
||||
}
|
||||
|
||||
await streamDownload(ollamaURL, message.modelName)
|
||||
}
|
||||
})
|
||||
|
||||
chrome.action.onClicked.addListener((tab) => {
|
||||
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]
|
||||
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!
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
persistent: true
|
||||
})
|
56
src/entries/ollama-pull.content.ts
Normal file
@ -0,0 +1,56 @@
|
||||
export default defineContentScript({
|
||||
main(ctx) {
|
||||
const downloadModel = async (modelName: string) => {
|
||||
const ok = confirm(
|
||||
`[Page Assist Extension] Do you want to pull ${modelName} model? This has nothing to do with Ollama.com website. The model will be pulled locally once you confirm.`
|
||||
)
|
||||
if (ok) {
|
||||
alert(
|
||||
`[Page Assist Extension] Pulling ${modelName} model. For more details, check the extension icon.`
|
||||
)
|
||||
|
||||
await chrome.runtime.sendMessage({
|
||||
type: "pull_model",
|
||||
modelName
|
||||
})
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
const downloadSVG = `<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="h-5 w-5 pageasssist-icon">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M3 16.5v2.25A2.25 2.25 0 0 0 5.25 21h13.5A2.25 2.25 0 0 0 21 18.75V16.5M16.5 12 12 16.5m0 0L7.5 12m4.5 4.5V3" />
|
||||
</svg>
|
||||
`
|
||||
const codeDiv = document.querySelectorAll("div.language-none")
|
||||
|
||||
for (let i = 0; i < codeDiv.length; i++) {
|
||||
const button = codeDiv[i].querySelector("button")
|
||||
const command = codeDiv[i].querySelector("input")
|
||||
if (button && command) {
|
||||
const newButton = document.createElement("button")
|
||||
newButton.innerHTML = downloadSVG
|
||||
newButton.className = `border-l ${button.className}`
|
||||
newButton.id = `download-${i}-pageassist`
|
||||
const modelName = command?.value
|
||||
.replace("ollama run", "")
|
||||
.replace("ollama pull", "")
|
||||
.trim()
|
||||
newButton.addEventListener("click", () => {
|
||||
downloadModel(modelName)
|
||||
})
|
||||
|
||||
const span = document.createElement("span")
|
||||
span.title = "Download model via Page Assist"
|
||||
span.appendChild(newButton)
|
||||
|
||||
if (button.parentNode) {
|
||||
button.parentNode.appendChild(span)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
},
|
||||
allFrames: true,
|
||||
matches: ["*://ollama.com/library/*"]
|
||||
})
|
@ -3,11 +3,10 @@ import { MemoryRouter } from "react-router-dom"
|
||||
import { ToastContainer } from "react-toastify"
|
||||
import "react-toastify/dist/ReactToastify.css"
|
||||
const queryClient = new QueryClient()
|
||||
import "./css/tailwind.css"
|
||||
import { ConfigProvider, theme } from "antd"
|
||||
import { StyleProvider } from "@ant-design/cssinjs"
|
||||
import { useDarkMode } from "~hooks/useDarkmode"
|
||||
import { OptionRouting } from "~routes"
|
||||
import { useDarkMode } from "~/hooks/useDarkmode"
|
||||
import { OptionRouting } from "~/routes"
|
||||
function IndexOption() {
|
||||
const { mode } = useDarkMode()
|
||||
return (
|
14
src/entries/options/index.html
Normal file
@ -0,0 +1,14 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Page Assist - Web UI</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<meta name="manifest.type" content="browser_action" />
|
||||
<link href="~/assets/tailwind.css" rel="stylesheet" />
|
||||
<meta charset="utf-8" />
|
||||
</head>
|
||||
<body class="bg-white dark:bg-[#171717]">
|
||||
<div id="root"></div>
|
||||
<script type="module" src="./main.tsx"></script>
|
||||
</body>
|
||||
</html>
|
10
src/entries/options/main.tsx
Normal file
@ -0,0 +1,10 @@
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom/client';
|
||||
import IndexOption from './App';
|
||||
|
||||
|
||||
ReactDOM.createRoot(document.getElementById('root')!).render(
|
||||
<React.StrictMode>
|
||||
<IndexOption />
|
||||
</React.StrictMode>,
|
||||
);
|
@ -1,13 +1,12 @@
|
||||
import { QueryClient, QueryClientProvider } from "@tanstack/react-query"
|
||||
import { MemoryRouter } from "react-router-dom"
|
||||
import { SidepanelRouting } from "~routes"
|
||||
import { SidepanelRouting } from "~/routes"
|
||||
import { ToastContainer } from "react-toastify"
|
||||
import "react-toastify/dist/ReactToastify.css"
|
||||
const queryClient = new QueryClient()
|
||||
import "./css/tailwind.css"
|
||||
import { ConfigProvider, theme } from "antd"
|
||||
import { StyleProvider } from "@ant-design/cssinjs"
|
||||
import { useDarkMode } from "~hooks/useDarkmode"
|
||||
import { useDarkMode } from "~/hooks/useDarkmode"
|
||||
function IndexSidepanel() {
|
||||
const { mode } = useDarkMode()
|
||||
|
14
src/entries/sidepanel/index.html
Normal file
@ -0,0 +1,14 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Page Assist - Web UI</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<meta name="manifest.type" content="browser_action" />
|
||||
<link href="~/assets/tailwind.css" rel="stylesheet" />
|
||||
<meta charset="utf-8" />
|
||||
</head>
|
||||
<body class="bg-white dark:bg-[#171717]">
|
||||
<div id="root"></div>
|
||||
<script type="module" src="./main.tsx"></script>
|
||||
</body>
|
||||
</html>
|
9
src/entries/sidepanel/main.tsx
Normal file
@ -0,0 +1,9 @@
|
||||
import React from "react"
|
||||
import ReactDOM from "react-dom/client"
|
||||
import IndexSidepanel from "./App"
|
||||
|
||||
ReactDOM.createRoot(document.getElementById("root")!).render(
|
||||
<React.StrictMode>
|
||||
<IndexSidepanel />
|
||||
</React.StrictMode>
|
||||
)
|
@ -1,5 +1,5 @@
|
||||
import React from "react"
|
||||
import { cleanUrl } from "~libs/clean-url"
|
||||
import { cleanUrl } from "~/libs/clean-url"
|
||||
import {
|
||||
defaultEmbeddingChunkOverlap,
|
||||
defaultEmbeddingChunkSize,
|
||||
@ -7,8 +7,8 @@ import {
|
||||
getOllamaURL,
|
||||
promptForRag,
|
||||
systemPromptForNonRag
|
||||
} from "~services/ollama"
|
||||
import { useStoreMessage, type ChatHistory, type Message } from "~store"
|
||||
} from "~/services/ollama"
|
||||
import { useStoreMessage, type ChatHistory, type Message } from "~/store"
|
||||
import { ChatOllama } from "@langchain/community/chat_models/ollama"
|
||||
import {
|
||||
HumanMessage,
|
||||
@ -16,16 +16,16 @@ import {
|
||||
type MessageContent,
|
||||
SystemMessage
|
||||
} from "@langchain/core/messages"
|
||||
import { getHtmlOfCurrentTab } from "~libs/get-html"
|
||||
import { PageAssistHtmlLoader } from "~loader/html"
|
||||
import { getHtmlOfCurrentTab } from "~/libs/get-html"
|
||||
import { PageAssistHtmlLoader } from "~/loader/html"
|
||||
import { RecursiveCharacterTextSplitter } from "langchain/text_splitter"
|
||||
import { OllamaEmbeddings } from "@langchain/community/embeddings/ollama"
|
||||
import {
|
||||
createChatWithWebsiteChain,
|
||||
groupMessagesByConversation
|
||||
} from "~chain/chat-with-website"
|
||||
} from "~/chain/chat-with-website"
|
||||
import { MemoryVectorStore } from "langchain/vectorstores/memory"
|
||||
import { chromeRunTime } from "~libs/runtime"
|
||||
import { chromeRunTime } from "~/libs/runtime"
|
||||
export type BotResponse = {
|
||||
bot: {
|
||||
text: string
|
||||
|
@ -1,11 +1,11 @@
|
||||
import React from "react"
|
||||
import { cleanUrl } from "~libs/clean-url"
|
||||
import { cleanUrl } from "~/libs/clean-url"
|
||||
import {
|
||||
geWebSearchFollowUpPrompt,
|
||||
getOllamaURL,
|
||||
systemPromptForNonRagOption
|
||||
} from "~services/ollama"
|
||||
import { type ChatHistory, type Message } from "~store/option"
|
||||
} from "~/services/ollama"
|
||||
import { type ChatHistory, type Message } from "~/store/option"
|
||||
import { ChatOllama } from "@langchain/community/chat_models/ollama"
|
||||
import {
|
||||
HumanMessage,
|
||||
@ -13,7 +13,7 @@ import {
|
||||
type MessageContent,
|
||||
SystemMessage
|
||||
} from "@langchain/core/messages"
|
||||
import { useStoreMessageOption } from "~store/option"
|
||||
import { useStoreMessageOption } from "~/store/option"
|
||||
import {
|
||||
deleteChatForEdit,
|
||||
getPromptById,
|
||||
@ -21,10 +21,10 @@ import {
|
||||
saveHistory,
|
||||
saveMessage,
|
||||
updateMessageByIndex
|
||||
} from "~libs/db"
|
||||
} from "~/libs/db"
|
||||
import { useNavigate } from "react-router-dom"
|
||||
import { notification } from "antd"
|
||||
import { getSystemPromptForWeb } from "~web/web"
|
||||
import { getSystemPromptForWeb } from "~/web/web"
|
||||
|
||||
export type BotResponse = {
|
||||
bot: {
|
||||
|
@ -1,7 +1,7 @@
|
||||
import {
|
||||
type ChatHistory as ChatHistoryType,
|
||||
type Message as MessageType
|
||||
} from "~store/option"
|
||||
} from "~/store/option"
|
||||
|
||||
type HistoryInfo = {
|
||||
id: string
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { BaseDocumentLoader } from "langchain/document_loaders/base"
|
||||
import { Document } from "@langchain/core/documents"
|
||||
import { compile } from "html-to-text"
|
||||
import { chromeRunTime } from "~libs/runtime"
|
||||
import { chromeRunTime } from "~/libs/runtime"
|
||||
import { YtTranscript } from "yt-transcript"
|
||||
|
||||
const YT_REGEX =
|
||||
|
@ -1,8 +0,0 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>__plasmo_static_index_title__</title>
|
||||
<meta charset="utf-8" />
|
||||
</head>
|
||||
<body class="bg-white dark:bg-[#171717]"></body>
|
||||
</html>
|
BIN
src/public/icon.png
Normal file
After Width: | Height: | Size: 2.9 KiB |
BIN
src/public/icon/128.png
Normal file
After Width: | Height: | Size: 2.9 KiB |
BIN
src/public/icon/16.png
Normal file
After Width: | Height: | Size: 345 B |
BIN
src/public/icon/32.png
Normal file
After Width: | Height: | Size: 535 B |
BIN
src/public/icon/48.png
Normal file
After Width: | Height: | Size: 951 B |
BIN
src/public/icon/64.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
@ -1,6 +1,6 @@
|
||||
import { Route, Routes } from "react-router-dom"
|
||||
import { SidepanelChat } from "./sidepanel-chat"
|
||||
import { useDarkMode } from "~hooks/useDarkmode"
|
||||
import { useDarkMode } from "~/hooks/useDarkmode"
|
||||
import { SidepanelSettings } from "./sidepanel-settings"
|
||||
import { OptionIndex } from "./option-index"
|
||||
import { OptionModal } from "./option-settings-model"
|
||||
|
@ -1,5 +1,5 @@
|
||||
import OptionLayout from "~components/Layouts/Layout"
|
||||
import { Playground } from "~components/Option/Playground/Playground"
|
||||
import OptionLayout from "~/components/Layouts/Layout"
|
||||
import { Playground } from "~/components/Option/Playground/Playground"
|
||||
|
||||
export const OptionIndex = () => {
|
||||
return (
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { SettingsLayout } from "~components/Layouts/SettingsOptionLayout"
|
||||
import OptionLayout from "~components/Layouts/Layout"
|
||||
import { ModelsBody } from "~components/Option/Models"
|
||||
import { SettingsLayout } from "~/components/Layouts/SettingsOptionLayout"
|
||||
import OptionLayout from "~/components/Layouts/Layout"
|
||||
import { ModelsBody } from "~/components/Option/Models"
|
||||
|
||||
export const OptionModal = () => {
|
||||
return (
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { SettingsLayout } from "~components/Layouts/SettingsOptionLayout"
|
||||
import OptionLayout from "~components/Layouts/Layout"
|
||||
import { PromptBody } from "~components/Option/Prompt"
|
||||
import { SettingsLayout } from "~/components/Layouts/SettingsOptionLayout"
|
||||
import OptionLayout from "~/components/Layouts/Layout"
|
||||
import { PromptBody } from "~/components/Option/Prompt"
|
||||
|
||||
export const OptionPrompt = () => {
|
||||
return (
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { SettingsLayout } from "~components/Layouts/SettingsOptionLayout"
|
||||
import OptionLayout from "~components/Layouts/Layout"
|
||||
import { OptionShareBody } from "~components/Option/Share"
|
||||
import { SettingsLayout } from "~/components/Layouts/SettingsOptionLayout"
|
||||
import OptionLayout from "~/components/Layouts/Layout"
|
||||
import { OptionShareBody } from "~/components/Option/Share"
|
||||
|
||||
export const OptionShare = () => {
|
||||
return (
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { SettingsLayout } from "~components/Layouts/SettingsOptionLayout"
|
||||
import OptionLayout from "~components/Layouts/Layout"
|
||||
import { SettingOther } from "~components/Option/Settings/other"
|
||||
import { SettingsLayout } from "~/components/Layouts/SettingsOptionLayout"
|
||||
import OptionLayout from "~/components/Layouts/Layout"
|
||||
import { SettingOther } from "~/components/Option/Settings/other"
|
||||
|
||||
export const OptionSettings = () => {
|
||||
return (
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { SettingsLayout } from "~components/Layouts/SettingsOptionLayout"
|
||||
import OptionLayout from "~components/Layouts/Layout"
|
||||
import { SettingsOllama } from "~components/Option/Settings/ollama"
|
||||
import { SettingsLayout } from "~/components/Layouts/SettingsOptionLayout"
|
||||
import OptionLayout from "~/components/Layouts/Layout"
|
||||
import { SettingsOllama } from "~/components/Option/Settings/ollama"
|
||||
|
||||
export const OptionOllamaSettings = () => {
|
||||
return (
|
||||
|
@ -1,8 +1,8 @@
|
||||
import React from "react"
|
||||
import { SidePanelBody } from "~components/Sidepanel/Chat/body"
|
||||
import { SidepanelForm } from "~components/Sidepanel/Chat/form"
|
||||
import { SidepanelHeader } from "~components/Sidepanel/Chat/header"
|
||||
import { useMessage } from "~hooks/useMessage"
|
||||
import { SidePanelBody } from "~/components/Sidepanel/Chat/body"
|
||||
import { SidepanelForm } from "~/components/Sidepanel/Chat/form"
|
||||
import { SidepanelHeader } from "~/components/Sidepanel/Chat/header"
|
||||
import { useMessage } from "~/hooks/useMessage"
|
||||
|
||||
export const SidepanelChat = () => {
|
||||
const drop = React.useRef<HTMLDivElement>(null)
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { SettingsBody } from "~components/Sidepanel/Settings/body"
|
||||
import { SidepanelSettingsHeader } from "~components/Sidepanel/Settings/header"
|
||||
import { SettingsBody } from "~/components/Sidepanel/Settings/body"
|
||||
import { SidepanelSettingsHeader } from "~/components/Sidepanel/Settings/header"
|
||||
|
||||
export const SidepanelSettings = () => {
|
||||
return (
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { Storage } from "@plasmohq/storage"
|
||||
import { cleanUrl } from "~libs/clean-url"
|
||||
import { chromeRunTime } from "~libs/runtime"
|
||||
import { cleanUrl } from "../libs/clean-url"
|
||||
import { chromeRunTime } from "../libs/runtime"
|
||||
|
||||
const storage = new Storage()
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { cleanUrl } from "~libs/clean-url"
|
||||
import { cleanUrl } from "~/libs/clean-url"
|
||||
|
||||
export const verifyPageShareURL = async (url: string) => {
|
||||
const res = await fetch(`${cleanUrl(url)}/api/v1/ping`)
|
||||
|
@ -2,10 +2,10 @@ import { OllamaEmbeddings } from "@langchain/community/embeddings/ollama"
|
||||
import type { Document } from "@langchain/core/documents"
|
||||
import { RecursiveCharacterTextSplitter } from "langchain/text_splitter"
|
||||
import { MemoryVectorStore } from "langchain/vectorstores/memory"
|
||||
import { cleanUrl } from "~libs/clean-url"
|
||||
import { chromeRunTime } from "~libs/runtime"
|
||||
import { PageAssistHtmlLoader } from "~loader/html"
|
||||
import { defaultEmbeddingChunkOverlap, defaultEmbeddingChunkSize, defaultEmbeddingModelForRag, getIsSimpleInternetSearch, getOllamaURL } from "~services/ollama"
|
||||
import { cleanUrl } from "~/libs/clean-url"
|
||||
import { chromeRunTime } from "~/libs/runtime"
|
||||
import { PageAssistHtmlLoader } from "~/loader/html"
|
||||
import { defaultEmbeddingChunkOverlap, defaultEmbeddingChunkSize, defaultEmbeddingModelForRag, getIsSimpleInternetSearch, getOllamaURL } from "~/services/ollama"
|
||||
|
||||
const BLOCKED_HOSTS = [
|
||||
"google.com",
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { getWebSearchPrompt } from "~services/ollama"
|
||||
import { getWebSearchPrompt } from "~/services/ollama"
|
||||
import { webSearch } from "./local-google"
|
||||
|
||||
const getHostName = (url: string) => {
|
||||
|
@ -1,11 +1,13 @@
|
||||
{
|
||||
"extends": "plasmo/templates/tsconfig.base",
|
||||
"exclude": ["node_modules"],
|
||||
"include": [".plasmo/index.d.ts", "./**/*.ts", "./**/*.tsx"],
|
||||
"extends": "./.wxt/tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"paths": {
|
||||
"~*": ["./src/*"]
|
||||
"noEmit": true,
|
||||
"allowImportingTsExtensions": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"esModuleInterop": true,
|
||||
"jsx": "react-jsx"
|
||||
},
|
||||
"baseUrl": "."
|
||||
}
|
||||
"exclude": [
|
||||
"node_modules"
|
||||
],
|
||||
}
|
44
wxt.config.ts
Normal file
@ -0,0 +1,44 @@
|
||||
import { defineConfig } from "wxt"
|
||||
import react from "@vitejs/plugin-react"
|
||||
|
||||
// See https://wxt.dev/api/config.html
|
||||
export default defineConfig({
|
||||
vite: () => ({
|
||||
plugins: [react()],
|
||||
}),
|
||||
entrypointsDir: "entries",
|
||||
srcDir: "src",
|
||||
outDir: "build",
|
||||
manifest: {
|
||||
name: "Page Assist - A Web UI for Local AI Models",
|
||||
version: "1.1.0",
|
||||
description:
|
||||
"Use your locally running AI models to assist you in your web browsing.",
|
||||
action: {},
|
||||
author: "n4ze3m",
|
||||
host_permissions: ["http://*/*", "https://*/*"],
|
||||
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",
|
||||
"sidePanel",
|
||||
"activeTab",
|
||||
"scripting",
|
||||
"declarativeNetRequest",
|
||||
"action",
|
||||
"unlimitedStorage",
|
||||
"contextMenus"
|
||||
]
|
||||
}
|
||||
})
|