171 lines
4.5 KiB
TypeScript
171 lines
4.5 KiB
TypeScript
import { getOllamaURL, isOllamaRunning } from "../services/ollama"
|
|
import { browser } from "wxt/browser"
|
|
import { setBadgeBackgroundColor, setBadgeText, setTitle } from "@/utils/action"
|
|
const progressHuman = (completed: number, total: number) => {
|
|
return ((completed / total) * 100).toFixed(0) + "%"
|
|
}
|
|
|
|
const clearBadge = () => {
|
|
setBadgeText({ text: "" })
|
|
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) {
|
|
setBadgeText({
|
|
text: progressHuman(json.completed, json.total)
|
|
})
|
|
setBadgeBackgroundColor({ color: "#0000FF" })
|
|
} else {
|
|
setBadgeText({ text: "🏋️♂️" })
|
|
setBadgeBackgroundColor({ color: "#FFFFFF" })
|
|
}
|
|
|
|
setTitle({ title: json.status })
|
|
|
|
if (json.status === "success") {
|
|
isSuccess = true
|
|
}
|
|
} catch (e) {
|
|
console.error(e)
|
|
}
|
|
}
|
|
|
|
if (isSuccess) {
|
|
setBadgeText({ text: "✅" })
|
|
setBadgeBackgroundColor({ color: "#00FF00" })
|
|
setTitle({ title: "Model pulled successfully" })
|
|
} else {
|
|
setBadgeText({ text: "❌" })
|
|
setBadgeBackgroundColor({ color: "#FF0000" })
|
|
setTitle({ title: "Model pull failed" })
|
|
}
|
|
|
|
setTimeout(() => {
|
|
clearBadge()
|
|
}, 5000)
|
|
}
|
|
export default defineBackground({
|
|
main() {
|
|
browser.runtime.onMessage.addListener(async (message) => {
|
|
if (message.type === "sidepanel") {
|
|
browser.sidebarAction.open()
|
|
} else if (message.type === "pull_model") {
|
|
const ollamaURL = await getOllamaURL()
|
|
|
|
const isRunning = await isOllamaRunning()
|
|
|
|
if (!isRunning) {
|
|
setBadgeText({ text: "E" })
|
|
setBadgeBackgroundColor({ color: "#FF0000" })
|
|
setTitle({ title: "Ollama is not running" })
|
|
setTimeout(() => {
|
|
clearBadge()
|
|
}, 5000)
|
|
}
|
|
|
|
await streamDownload(ollamaURL, message.modelName)
|
|
}
|
|
})
|
|
|
|
if (import.meta.env.BROWSER === "chrome") {
|
|
chrome.action.onClicked.addListener((tab) => {
|
|
browser.tabs.create({ url: browser.runtime.getURL("/options.html") })
|
|
})
|
|
} else {
|
|
browser.browserAction.onClicked.addListener((tab) => {
|
|
console.log("browser.browserAction.onClicked.addListener")
|
|
browser.tabs.create({ url: browser.runtime.getURL("/options.html") })
|
|
})
|
|
}
|
|
|
|
browser.contextMenus.create({
|
|
id: "open-side-panel-pa",
|
|
title: browser.i18n.getMessage("openSidePanelToChat"),
|
|
contexts: ["all"]
|
|
})
|
|
if (import.meta.env.BROWSER === "chrome") {
|
|
browser.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]
|
|
chrome.sidePanel.open({
|
|
tabId: tab.id!
|
|
})
|
|
}
|
|
)
|
|
}
|
|
})
|
|
|
|
browser.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
|
|
}
|
|
})
|
|
}
|
|
|
|
if (import.meta.env.BROWSER === "firefox") {
|
|
browser.contextMenus.onClicked.addListener((info, tab) => {
|
|
if (info.menuItemId === "open-side-panel-pa") {
|
|
browser.sidebarAction.toggle()
|
|
}
|
|
})
|
|
|
|
browser.commands.onCommand.addListener((command) => {
|
|
switch (command) {
|
|
case "execute_side_panel":
|
|
browser.sidebarAction.toggle()
|
|
break
|
|
default:
|
|
break
|
|
}
|
|
})
|
|
}
|
|
},
|
|
persistent: true
|
|
})
|