feat: Add Chrome AI support
This commit is contained in:
parent
52f9a2953a
commit
d41ec2a89c
13
src/assets/locale/en/chrome.json
Normal file
13
src/assets/locale/en/chrome.json
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"heading": "Configure Chrome AI",
|
||||||
|
"status": {
|
||||||
|
"label": "Enable or Disable Chrome AI Support on Page Assist"
|
||||||
|
},
|
||||||
|
"error": {
|
||||||
|
"browser_not_supported": "This version of Chrome is not supported by the Gemini Nano model. Please update to version 127 or later",
|
||||||
|
"ai_not_supported": "The setting chrome://flags/#prompt-api-for-gemini-nano is not enabled. Please enable it.",
|
||||||
|
"ai_not_ready": "Gemini Nano is not ready yet; you need to double-check Chrome settings.",
|
||||||
|
"internal_error": "An internal error occurred. Please try again later."
|
||||||
|
},
|
||||||
|
"errorDescription": "In order to use Chrome AI, you need a browser version greater than 127, which is currently in the Dev and Canary channels. After downloading the supported version, follow these steps:\n\n1. Go to `chrome://flags/#prompt-api-for-gemini-nano` and select \"Enable\".\n2. Go to `chrome://flags/#optimization-guide-on-device-model` and select \"EnabledBypassPrefRequirement\".\n3. Go to `chrome://components`, search for \"Optimization Guide On Device Model\", and click \"Check for Update\". This will download the model. If you don't see the settings, repeat steps 1 and 2 and relaunch your browser."
|
||||||
|
}
|
@ -300,5 +300,8 @@
|
|||||||
"webSearchFollowUpPromptError": "Please input your Web Search Follow Up Prompt!",
|
"webSearchFollowUpPromptError": "Please input your Web Search Follow Up Prompt!",
|
||||||
"webSearchFollowUpPromptPlaceholder": "Your Web Search Follow Up Prompt"
|
"webSearchFollowUpPromptPlaceholder": "Your Web Search Follow Up Prompt"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"chromeAiSettings": {
|
||||||
|
"title": "Chrome AI Settings"
|
||||||
}
|
}
|
||||||
}
|
}
|
13
src/assets/locale/es/chrome.json
Normal file
13
src/assets/locale/es/chrome.json
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"heading": "Configurar Chrome AI",
|
||||||
|
"status": {
|
||||||
|
"label": "Habilitar o deshabilitar el soporte de Chrome AI en Page Assist"
|
||||||
|
},
|
||||||
|
"error": {
|
||||||
|
"browser_not_supported": "Esta versión de Chrome no es compatible con el modelo Gemini Nano. Por favor, actualice a la versión 127 o posterior.",
|
||||||
|
"ai_not_supported": "La configuración chrome://flags/#prompt-api-for-gemini-nano no está habilitada. Por favor, habilítela.",
|
||||||
|
"ai_not_ready": "Gemini Nano aún no está listo; necesita verificar la configuración de Chrome.",
|
||||||
|
"internal_error": "Ocurrió un error interno. Por favor, inténtelo de nuevo más tarde."
|
||||||
|
},
|
||||||
|
"errorDescription": "Para usar Chrome AI, necesita una versión del navegador mayor a la 127, que actualmente está en los canales Dev y Canary. Después de descargar la versión compatible, siga estos pasos:\n\n1. Vaya a `chrome://flags/#prompt-api-for-gemini-nano` y seleccione \"Habilitar\".\n2. Vaya a `chrome://flags/#optimization-guide-on-device-model` y seleccione \"EnabledBypassPrefRequirement\".\n3. Vaya a `chrome://components`, busque \"Optimization Guide On Device Model\" y haga clic en \"Buscar actualización\". Esto descargará el modelo. Si no ve la configuración, repita los pasos 1 y 2 y reinicie su navegador."
|
||||||
|
}
|
13
src/assets/locale/fr/chrome.json
Normal file
13
src/assets/locale/fr/chrome.json
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"heading": "Configurer Chrome AI",
|
||||||
|
"status": {
|
||||||
|
"label": "Activer ou désactiver la prise en charge de Chrome AI sur Page Assist"
|
||||||
|
},
|
||||||
|
"error": {
|
||||||
|
"browser_not_supported": "Cette version de Chrome n'est pas supportée par le modèle Gemini Nano. Veuillez mettre à jour vers la version 127 ou ultérieure.",
|
||||||
|
"ai_not_supported": "Le paramètre chrome://flags/#prompt-api-for-gemini-nano n'est pas activé. Veuillez l'activer.",
|
||||||
|
"ai_not_ready": "Gemini Nano n'est pas encore prêt; vous devez vérifier les paramètres de Chrome.",
|
||||||
|
"internal_error": "Une erreur interne est survenue. Veuillez réessayer plus tard."
|
||||||
|
},
|
||||||
|
"errorDescription": "Pour utiliser Chrome AI, vous avez besoin d'une version du navigateur supérieure à 127, actuellement disponible dans les canaux Dev et Canary. Après avoir téléchargé la version prise en charge, suivez ces étapes:\n\n1. Allez à `chrome://flags/#prompt-api-for-gemini-nano` et sélectionnez \"Activer\".\n2. Allez à `chrome://flags/#optimization-guide-on-device-model` et sélectionnez \"EnabledBypassPrefRequirement\".\n3. Allez à `chrome://components`, recherchez \"Optimization Guide On Device Model\" et cliquez sur \"Vérifier la mise à jour\". Cela téléchargera le modèle. Si vous ne voyez pas les paramètres, répétez les étapes 1 et 2 et relancez votre navigateur."
|
||||||
|
}
|
13
src/assets/locale/it/chrome.json
Normal file
13
src/assets/locale/it/chrome.json
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"heading": "Configura Chrome AI",
|
||||||
|
"status": {
|
||||||
|
"label": "Abilita o disabilita il supporto di Chrome AI su Page Assist"
|
||||||
|
},
|
||||||
|
"error": {
|
||||||
|
"browser_not_supported": "Questa versione di Chrome non è supportata dal modello Gemini Nano. Si prega di aggiornare alla versione 127 o successiva.",
|
||||||
|
"ai_not_supported": "L'impostazione chrome://flags/#prompt-api-for-gemini-nano non è abilitata. Si prega di abilitarla.",
|
||||||
|
"ai_not_ready": "Gemini Nano non è ancora pronto; è necessario verificare le impostazioni di Chrome.",
|
||||||
|
"internal_error": "Si è verificato un errore interno. Si prega di riprovare più tardi."
|
||||||
|
},
|
||||||
|
"errorDescription": "Per utilizzare Chrome AI, è necessaria una versione del browser superiore alla 127, attualmente disponibile nei canali Dev e Canary. Dopo aver scaricato la versione supportata, segui questi passaggi:\n\n1. Vai a `chrome://flags/#prompt-api-for-gemini-nano` e seleziona \"Abilita\".\n2. Vai a `chrome://flags/#optimization-guide-on-device-model` e seleziona \"EnabledBypassPrefRequirement\".\n3. Vai a `chrome://components`, cerca \"Optimization Guide On Device Model\" e clicca su \"Controlla aggiornamenti\". Questo scaricherà il modello. Se non vedi le impostazioni, ripeti i passaggi 1 e 2 e riavvia il browser."
|
||||||
|
}
|
13
src/assets/locale/ja-JP/chrome.json
Normal file
13
src/assets/locale/ja-JP/chrome.json
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"heading": "Chrome AIの設定",
|
||||||
|
"status": {
|
||||||
|
"label": "Page AssistでChrome AIサポートを有効または無効にする"
|
||||||
|
},
|
||||||
|
"error": {
|
||||||
|
"browser_not_supported": "このバージョンのChromeはGemini Nanoモデルに対応していません。バージョン127以降に更新してください。",
|
||||||
|
"ai_not_supported": "設定chrome://flags/#prompt-api-for-gemini-nanoが有効になっていません。有効にしてください。",
|
||||||
|
"ai_not_ready": "Gemini Nanoはまだ準備ができていません。Chromeの設定を再確認する必要があります。",
|
||||||
|
"internal_error": "内部エラーが発生しました。後でもう一度お試しください。"
|
||||||
|
},
|
||||||
|
"errorDescription": "Chrome AIを使用するには、現在DevおよびCanaryチャンネルにあるバージョン127以上のブラウザが必要です。サポートされているバージョンをダウンロードした後、次の手順に従ってください:\n\n1. `chrome://flags/#prompt-api-for-gemini-nano`にアクセスし、「有効」を選択します。\n2. `chrome://flags/#optimization-guide-on-device-model`にアクセスし、「EnabledBypassPrefRequirement」を選択します。\n3. `chrome://components`にアクセスし、「Optimization Guide On Device Model」を検索して、「アップデートを確認」をクリックします。これにより、モデルがダウンロードされます。設定が表示されない場合は、手順1および2を繰り返し、ブラウザを再起動してください。"
|
||||||
|
}
|
13
src/assets/locale/ml/chrome.json
Normal file
13
src/assets/locale/ml/chrome.json
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"heading": "ക്രോം എഐ കോൺഫിഗർ ചെയ്യുക",
|
||||||
|
"status": {
|
||||||
|
"label": "പേജ് അസിസ്റ്റിൽ ക്രോം എഐ പിന്തുണ സജ്ജമാക്കുക അല്ലെങ്കിൽ ഡിസബിൾ ചെയ്യുക"
|
||||||
|
},
|
||||||
|
"error": {
|
||||||
|
"browser_not_supported": "ക്രോത്തിന്റെ ഈ പതിപ്പ് ജെമിനി നാനോ മോഡലിനെ പിന്തുണയ്ക്കുന്നില്ല. പതിപ്പ് 127 അല്ലെങ്കിൽ അതിനുശേഷം അപ്ഡേറ്റ് ചെയ്യുക.",
|
||||||
|
"ai_not_supported": "ക്രമീകരണം chrome://flags/#prompt-api-for-gemini-nano സജ്ജമാക്കപ്പെട്ടിട്ടില്ല. ദയവായി അതിനെ സജ്ജമാക്കുക.",
|
||||||
|
"ai_not_ready": "ജെമിനി നാനോ ഇപ്പോഴും സജ്ജമല്ല; നിങ്ങൾ ക്രോം ക്രമീകരണങ്ങൾ രണ്ടുതവണ പരിശോധിക്കണം.",
|
||||||
|
"internal_error": "ഒരു ആന്തരിക പിശക് സംഭവിച്ചു. ദയവായി കുറച്ചുദിവസം ശേഷം വീണ്ടും ശ്രമിക്കുക."
|
||||||
|
},
|
||||||
|
"errorDescription": "ക്രോം എഐ ഉപയോഗിക്കുന്നതിന്, നിലവിൽ ഡെവ്, കാനറി ചാനലുകളിൽ ലഭ്യമായ 127-നെക്കാൾ ഉയർന്ന ബ്രൗസർ പതിപ്പ് ആവശ്യമാണ്. പിന്തുണയ്ക്കുന്ന പതിപ്പ് ഡൗൺലോഡ് ചെയ്ത ശേഷം, ഈ ചുവടുപടികൾ പിന്തുടരുക:\n\n1. `chrome://flags/#prompt-api-for-gemini-nano`-ലേക്ക് പോയി \"എനേബിൾ\" തിരഞ്ഞെടുക്കുക.\n2. `chrome://flags/#optimization-guide-on-device-model`-ലേക്ക് പോയി \"EnabledBypassPrefRequirement\" തിരഞ്ഞെടുക്കുക.\n3. `chrome://components`-ലേക്ക് പോയി, \"Optimization Guide On Device Model\" തിരയുക, \"അപ്ഡേറ്റ് പരിശോധിക്കുക\" ക്ലിക്ക് ചെയ്യുക. ഇത് മോഡൽ ഡൗൺലോഡ് ചെയ്യും. ക്രമീകരണങ്ങൾ കാണുന്നില്ലെങ്കിൽ, ചുവടുപടികൾ 1, 2 ആവർത്തിച്ച് ബ്രൗസർ വീണ്ടും തുറക്കുക."
|
||||||
|
}
|
13
src/assets/locale/pt-BR/chrome.json
Normal file
13
src/assets/locale/pt-BR/chrome.json
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"heading": "Configurar IA do Chrome",
|
||||||
|
"status": {
|
||||||
|
"label": "Ativar ou Desativar o Suporte de IA do Chrome no Assistente de Página"
|
||||||
|
},
|
||||||
|
"error": {
|
||||||
|
"browser_not_supported": "Esta versão do Chrome não é suportada pelo modelo Gemini Nano. Por favor, atualize para a versão 127 ou posterior",
|
||||||
|
"ai_not_supported": "A configuração chrome://flags/#prompt-api-for-gemini-nano não está ativada. Por favor, ative-a.",
|
||||||
|
"ai_not_ready": "O Gemini Nano ainda não está pronto; você precisa verificar novamente as configurações do Chrome.",
|
||||||
|
"internal_error": "Ocorreu um erro interno. Por favor, tente novamente mais tarde."
|
||||||
|
},
|
||||||
|
"errorDescription": "Para usar a IA do Chrome, você precisa de uma versão do navegador superior a 127, que atualmente está nos canais Dev e Canary. Após baixar a versão suportada, siga estes passos:\n\n1. Vá para `chrome://flags/#prompt-api-for-gemini-nano` e selecione \"Ativar\".\n2. Vá para `chrome://flags/#optimization-guide-on-device-model` e selecione \"EnabledBypassPrefRequirement\".\n3. Vá para `chrome://components`, procure por \"Optimization Guide On Device Model\" e clique em \"Verificar atualizações\". Isso baixará o modelo. Se você não vir as configurações, repita os passos 1 e 2 e reinicie seu navegador."
|
||||||
|
}
|
13
src/assets/locale/ru/chrome.json
Normal file
13
src/assets/locale/ru/chrome.json
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"heading": "Настройка Chrome AI",
|
||||||
|
"status": {
|
||||||
|
"label": "Включить или отключить поддержку Chrome AI в помощнике страницы"
|
||||||
|
},
|
||||||
|
"error": {
|
||||||
|
"browser_not_supported": "Эта версия Chrome не поддерживается моделью Gemini Nano. Пожалуйста, обновите до версии 127 или выше",
|
||||||
|
"ai_not_supported": "Настройка chrome://flags/#prompt-api-for-gemini-nano не включена. Пожалуйста, включите её.",
|
||||||
|
"ai_not_ready": "Gemini Nano ещё не готов; вам нужно перепроверить настройки Chrome.",
|
||||||
|
"internal_error": "Произошла внутренняя ошибка. Пожалуйста, повторите попытку позже."
|
||||||
|
},
|
||||||
|
"errorDescription": "Чтобы использовать Chrome AI, вам нужна версия браузера выше 127, которая в настоящее время доступна в каналах Dev и Canary. После загрузки поддерживаемой версии выполните следующие шаги:\n\n1. Перейдите на `chrome://flags/#prompt-api-for-gemini-nano` и выберите \"Включить\".\n2. Перейдите на `chrome://flags/#optimization-guide-on-device-model` и выберите \"EnabledBypassPrefRequirement\".\n3. Перейдите на `chrome://components`, найдите \"Optimization Guide On Device Model\" и нажмите \"Проверить наличие обновлений\". Это загрузит модель. Если вы не видите настройки, повторите шаги 1 и 2 и перезапустите браузер."
|
||||||
|
}
|
13
src/assets/locale/zh/chrome.json
Normal file
13
src/assets/locale/zh/chrome.json
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"heading": "配置Chrome人工智能",
|
||||||
|
"status": {
|
||||||
|
"label": "在页面辅助功能中启用或禁用Chrome人工智能支持"
|
||||||
|
},
|
||||||
|
"error": {
|
||||||
|
"browser_not_supported": "此版本的Chrome不受Gemini Nano模型支持。请更新到127版本或更高版本",
|
||||||
|
"ai_not_supported": "设置chrome://flags/#prompt-api-for-gemini-nano未启用。请启用它。",
|
||||||
|
"ai_not_ready": "Gemini Nano尚未准备就绪;您需要再次检查Chrome设置。",
|
||||||
|
"internal_error": "发生内部错误。请稍后重试。"
|
||||||
|
},
|
||||||
|
"errorDescription": "为了使用Chrome人工智能,您需要127版本以上的浏览器,目前该版本在Dev和Canary渠道中。下载支持的版本后,请按照以下步骤操作:\n\n1. 前往`chrome://flags/#prompt-api-for-gemini-nano`并选择\"启用\",\n2. 前往`chrome://flags/#optimization-guide-on-device-model`并选择\"EnabledBypassPrefRequirement\",\n3. 前往`chrome://components`,搜索\"Optimization Guide On Device Model\",然后点击\"检查更新\"。这将下载模型。如果您没有看到这些设置,请重复步骤1和2,然后重新启动浏览器。"
|
||||||
|
}
|
@ -6,11 +6,17 @@ import "property-information"
|
|||||||
import React from "react"
|
import React from "react"
|
||||||
import { CodeBlock } from "./CodeBlock"
|
import { CodeBlock } from "./CodeBlock"
|
||||||
|
|
||||||
export default function Markdown({ message }: { message: string }) {
|
export default function Markdown({
|
||||||
|
message,
|
||||||
|
className = "prose break-words dark:prose-invert prose-p:leading-relaxed prose-pre:p-0 dark:prose-dark"
|
||||||
|
}: {
|
||||||
|
message: string
|
||||||
|
className?: string
|
||||||
|
}) {
|
||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
<ReactMarkdown
|
<ReactMarkdown
|
||||||
className="prose break-words dark:prose-invert prose-p:leading-relaxed prose-pre:p-0 dark:prose-dark"
|
className={className}
|
||||||
remarkPlugins={[remarkGfm, remarkMath]}
|
remarkPlugins={[remarkGfm, remarkMath]}
|
||||||
components={{
|
components={{
|
||||||
code({ node, inline, className, children, ...props }) {
|
code({ node, inline, className, children, ...props }) {
|
||||||
|
@ -3,9 +3,9 @@ import { Dropdown, Tooltip } from "antd"
|
|||||||
import { LucideBrain } from "lucide-react"
|
import { LucideBrain } from "lucide-react"
|
||||||
import React from "react"
|
import React from "react"
|
||||||
import { useTranslation } from "react-i18next"
|
import { useTranslation } from "react-i18next"
|
||||||
import { OllamaIcon } from "../Icons/Ollama"
|
|
||||||
import { fetchChatModels } from "@/services/ollama"
|
import { fetchChatModels } from "@/services/ollama"
|
||||||
import { useMessage } from "@/hooks/useMessage"
|
import { useMessage } from "@/hooks/useMessage"
|
||||||
|
import { ProviderIcons } from "./ProviderIcon"
|
||||||
|
|
||||||
export const ModelSelect: React.FC = () => {
|
export const ModelSelect: React.FC = () => {
|
||||||
const { t } = useTranslation("common")
|
const { t } = useTranslation("common")
|
||||||
@ -29,7 +29,10 @@ export const ModelSelect: React.FC = () => {
|
|||||||
label: (
|
label: (
|
||||||
<div className="w-52 gap-2 text-lg truncate inline-flex line-clamp-3 items-center dark:border-gray-700">
|
<div className="w-52 gap-2 text-lg truncate inline-flex line-clamp-3 items-center dark:border-gray-700">
|
||||||
<div>
|
<div>
|
||||||
<OllamaIcon className="h-6 w-6 text-gray-400" />
|
<ProviderIcons
|
||||||
|
provider={d?.provider}
|
||||||
|
className="h-6 w-6 text-gray-400"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
{d.name}
|
{d.name}
|
||||||
</div>
|
</div>
|
||||||
@ -53,7 +56,7 @@ export const ModelSelect: React.FC = () => {
|
|||||||
trigger={["click"]}>
|
trigger={["click"]}>
|
||||||
<Tooltip title={t("selectAModel")}>
|
<Tooltip title={t("selectAModel")}>
|
||||||
<button type="button" className="dark:text-gray-300">
|
<button type="button" className="dark:text-gray-300">
|
||||||
<LucideBrain className="h-5 w-5"/>
|
<LucideBrain className="h-5 w-5" />
|
||||||
</button>
|
</button>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</Dropdown>
|
</Dropdown>
|
||||||
|
@ -64,7 +64,11 @@ export const PlaygroundMessage = (props: Props) => {
|
|||||||
</div>
|
</div>
|
||||||
<div className="flex w-[calc(100%-50px)] flex-col gap-3 lg:w-[calc(100%-115px)]">
|
<div className="flex w-[calc(100%-50px)] flex-col gap-3 lg:w-[calc(100%-115px)]">
|
||||||
<span className="text-xs font-bold text-gray-800 dark:text-white">
|
<span className="text-xs font-bold text-gray-800 dark:text-white">
|
||||||
{props.isBot ? props.name : "You"}
|
{props.isBot
|
||||||
|
? props.name === "chrome::gemini-nano::page-assist"
|
||||||
|
? "Gemini Nano"
|
||||||
|
: props.name
|
||||||
|
: "You"}
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
{props.isBot &&
|
{props.isBot &&
|
||||||
|
17
src/components/Common/ProviderIcon.tsx
Normal file
17
src/components/Common/ProviderIcon.tsx
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
import { ChromeIcon } from "lucide-react"
|
||||||
|
import { OllamaIcon } from "../Icons/Ollama"
|
||||||
|
|
||||||
|
export const ProviderIcons = ({
|
||||||
|
provider,
|
||||||
|
className
|
||||||
|
}: {
|
||||||
|
provider: string
|
||||||
|
className?: string
|
||||||
|
}) => {
|
||||||
|
switch (provider) {
|
||||||
|
case "chrome":
|
||||||
|
return <ChromeIcon className={className} />
|
||||||
|
default:
|
||||||
|
return <OllamaIcon className={className} />
|
||||||
|
}
|
||||||
|
}
|
@ -21,6 +21,7 @@ import { useMessageOption } from "~/hooks/useMessageOption"
|
|||||||
import { Select, Tooltip } from "antd"
|
import { Select, Tooltip } from "antd"
|
||||||
import { getAllPrompts } from "@/db"
|
import { getAllPrompts } from "@/db"
|
||||||
import { ShareBtn } from "~/components/Common/ShareBtn"
|
import { ShareBtn } from "~/components/Common/ShareBtn"
|
||||||
|
import { ProviderIcons } from "../Common/ProviderIcon"
|
||||||
type Props = {
|
type Props = {
|
||||||
setSidebarOpen: (open: boolean) => void
|
setSidebarOpen: (open: boolean) => void
|
||||||
setOpenModelSettings: (open: boolean) => void
|
setOpenModelSettings: (open: boolean) => void
|
||||||
@ -132,7 +133,10 @@ export const Header: React.FC<Props> = ({
|
|||||||
<span
|
<span
|
||||||
key={model.model}
|
key={model.model}
|
||||||
className="flex flex-row gap-3 items-center truncate">
|
className="flex flex-row gap-3 items-center truncate">
|
||||||
<OllamaIcon className="w-5 h-5" />
|
<ProviderIcons
|
||||||
|
provider={model?.provider}
|
||||||
|
className="w-5 h-5"
|
||||||
|
/>
|
||||||
<span className="truncate">{model.name}</span>
|
<span className="truncate">{model.name}</span>
|
||||||
</span>
|
</span>
|
||||||
),
|
),
|
||||||
|
@ -6,11 +6,13 @@ import {
|
|||||||
BlocksIcon,
|
BlocksIcon,
|
||||||
InfoIcon,
|
InfoIcon,
|
||||||
CombineIcon,
|
CombineIcon,
|
||||||
|
ChromeIcon
|
||||||
} from "lucide-react"
|
} from "lucide-react"
|
||||||
import { useTranslation } from "react-i18next"
|
import { useTranslation } from "react-i18next"
|
||||||
import { Link, useLocation } from "react-router-dom"
|
import { Link, useLocation } from "react-router-dom"
|
||||||
import { OllamaIcon } from "../Icons/Ollama"
|
import { OllamaIcon } from "../Icons/Ollama"
|
||||||
import { Tag } from "antd"
|
import { Tag } from "antd"
|
||||||
|
import { BetaTag } from "../Common/Beta"
|
||||||
|
|
||||||
function classNames(...classes: string[]) {
|
function classNames(...classes: string[]) {
|
||||||
return classes.filter(Boolean).join(" ")
|
return classes.filter(Boolean).join(" ")
|
||||||
@ -20,10 +22,12 @@ const LinkComponent = (item: {
|
|||||||
href: string
|
href: string
|
||||||
name: string | JSX.Element
|
name: string | JSX.Element
|
||||||
icon: any
|
icon: any
|
||||||
current: string
|
current: string,
|
||||||
|
beta?: boolean
|
||||||
}) => {
|
}) => {
|
||||||
return (
|
return (
|
||||||
<li>
|
<li className="inline-flex items-center">
|
||||||
|
|
||||||
<Link
|
<Link
|
||||||
to={item.href}
|
to={item.href}
|
||||||
className={classNames(
|
className={classNames(
|
||||||
@ -43,6 +47,9 @@ const LinkComponent = (item: {
|
|||||||
/>
|
/>
|
||||||
{item.name}
|
{item.name}
|
||||||
</Link>
|
</Link>
|
||||||
|
{
|
||||||
|
item.beta && <BetaTag />
|
||||||
|
}
|
||||||
</li>
|
</li>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -65,7 +72,7 @@ export const SettingsLayout = ({ children }: { children: React.ReactNode }) => {
|
|||||||
icon={OrbitIcon}
|
icon={OrbitIcon}
|
||||||
current={location.pathname}
|
current={location.pathname}
|
||||||
/>
|
/>
|
||||||
<LinkComponent
|
<LinkComponent
|
||||||
href="/settings/rag"
|
href="/settings/rag"
|
||||||
name={t("rag.title")}
|
name={t("rag.title")}
|
||||||
icon={CombineIcon}
|
icon={CombineIcon}
|
||||||
@ -77,6 +84,15 @@ export const SettingsLayout = ({ children }: { children: React.ReactNode }) => {
|
|||||||
icon={OllamaIcon}
|
icon={OllamaIcon}
|
||||||
current={location.pathname}
|
current={location.pathname}
|
||||||
/>
|
/>
|
||||||
|
{import.meta.env.BROWSER === "chrome" && (
|
||||||
|
<LinkComponent
|
||||||
|
href="/settings/chrome"
|
||||||
|
name={t("chromeAiSettings.title")}
|
||||||
|
icon={ChromeIcon}
|
||||||
|
current={location.pathname}
|
||||||
|
beta
|
||||||
|
/>
|
||||||
|
)}
|
||||||
<LinkComponent
|
<LinkComponent
|
||||||
href="/settings/model"
|
href="/settings/model"
|
||||||
name={t("manageModels.title")}
|
name={t("manageModels.title")}
|
||||||
|
73
src/components/Option/Settings/chrome.tsx
Normal file
73
src/components/Option/Settings/chrome.tsx
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
import { useStorage } from "@plasmohq/storage/hook"
|
||||||
|
import { useQuery } from "@tanstack/react-query"
|
||||||
|
import { Alert, Skeleton, Switch } from "antd"
|
||||||
|
import { useTranslation } from "react-i18next"
|
||||||
|
import { getChromeAISupported } from "@/utils/chrome"
|
||||||
|
import Markdown from "@/components/Common/Markdown"
|
||||||
|
|
||||||
|
export const ChromeApp = () => {
|
||||||
|
const { t } = useTranslation("chrome")
|
||||||
|
const [chromeAIStatus, setChromeAIStatus] = useStorage(
|
||||||
|
"chromeAIStatus",
|
||||||
|
false
|
||||||
|
)
|
||||||
|
const [selectedModel, setSelectedModel] = useStorage("selectedModel")
|
||||||
|
|
||||||
|
const { status, data } = useQuery({
|
||||||
|
queryKey: ["fetchChromeAIInfo"],
|
||||||
|
queryFn: async () => {
|
||||||
|
const data = await getChromeAISupported()
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return (
|
||||||
|
<div className="flex flex-col space-y-3">
|
||||||
|
{status === "pending" && <Skeleton paragraph={{ rows: 4 }} active />}
|
||||||
|
{status === "success" && (
|
||||||
|
<div className="flex flex-col space-y-6">
|
||||||
|
<div>
|
||||||
|
<div>
|
||||||
|
<h2 className="text-base font-semibold leading-7 text-gray-900 dark:text-white">
|
||||||
|
{t("heading")}
|
||||||
|
</h2>
|
||||||
|
<div className="border border-b border-gray-200 dark:border-gray-600 mt-3 mb-6"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex mb-3 flex-row justify-between">
|
||||||
|
<div className="inline-flex items-center gap-2">
|
||||||
|
<span className="text-gray-700 text-sm dark:text-neutral-50">
|
||||||
|
{t("status.label")}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Switch
|
||||||
|
disabled={data !== "success"}
|
||||||
|
checked={chromeAIStatus}
|
||||||
|
onChange={(value) => {
|
||||||
|
setChromeAIStatus(value)
|
||||||
|
if (
|
||||||
|
!value &&
|
||||||
|
selectedModel === "chrome::gemini-nano::page-assist"
|
||||||
|
) {
|
||||||
|
setSelectedModel(null)
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
{data !== "success" && (
|
||||||
|
<div className="space-y-3">
|
||||||
|
<Alert message={t(`error.${data}`)} type="error" showIcon />
|
||||||
|
<div className=" w-full">
|
||||||
|
<Markdown
|
||||||
|
className="text-sm text-gray-700 dark:text-neutral-50 leading-7 text-justify"
|
||||||
|
message={t("errorDescription")}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
@ -13,7 +13,6 @@ import {
|
|||||||
exportPageAssistData,
|
exportPageAssistData,
|
||||||
importPageAssistData
|
importPageAssistData
|
||||||
} from "@/libs/export-import"
|
} from "@/libs/export-import"
|
||||||
import { BetaTag } from "@/components/Common/Beta"
|
|
||||||
import { useStorage } from "@plasmohq/storage/hook"
|
import { useStorage } from "@plasmohq/storage/hook"
|
||||||
|
|
||||||
export const GeneralSettings = () => {
|
export const GeneralSettings = () => {
|
||||||
@ -87,7 +86,6 @@ export const GeneralSettings = () => {
|
|||||||
</div>
|
</div>
|
||||||
<div className="flex flex-row justify-between">
|
<div className="flex flex-row justify-between">
|
||||||
<div className="inline-flex items-center gap-2">
|
<div className="inline-flex items-center gap-2">
|
||||||
<BetaTag />
|
|
||||||
<span className="text-gray-700 dark:text-neutral-50">
|
<span className="text-gray-700 dark:text-neutral-50">
|
||||||
{t("generalSettings.settings.copilotResumeLastChat.label")}
|
{t("generalSettings.settings.copilotResumeLastChat.label")}
|
||||||
</span>
|
</span>
|
||||||
@ -99,7 +97,6 @@ export const GeneralSettings = () => {
|
|||||||
</div>
|
</div>
|
||||||
<div className="flex flex-row justify-between">
|
<div className="flex flex-row justify-between">
|
||||||
<div className="inline-flex items-center gap-2">
|
<div className="inline-flex items-center gap-2">
|
||||||
<BetaTag />
|
|
||||||
<span className="text-gray-700 dark:text-neutral-50">
|
<span className="text-gray-700 dark:text-neutral-50">
|
||||||
{t("generalSettings.settings.hideCurrentChatModelSettings.label")}
|
{t("generalSettings.settings.hideCurrentChatModelSettings.label")}
|
||||||
</span>
|
</span>
|
||||||
|
@ -28,9 +28,9 @@ import { formatDocs } from "@/chain/chat-with-x"
|
|||||||
import { OllamaEmbeddingsPageAssist } from "@/models/OllamaEmbedding"
|
import { OllamaEmbeddingsPageAssist } from "@/models/OllamaEmbedding"
|
||||||
import { useStorage } from "@plasmohq/storage/hook"
|
import { useStorage } from "@plasmohq/storage/hook"
|
||||||
import { useStoreChatModelSettings } from "@/store/model"
|
import { useStoreChatModelSettings } from "@/store/model"
|
||||||
import { ChatOllama } from "@/models/ChatOllama"
|
|
||||||
import { getAllDefaultModelSettings } from "@/services/model-settings"
|
import { getAllDefaultModelSettings } from "@/services/model-settings"
|
||||||
import { getSystemPromptForWeb } from "@/web/web"
|
import { getSystemPromptForWeb } from "@/web/web"
|
||||||
|
import { pageAssistModel } from "@/models"
|
||||||
|
|
||||||
export const useMessage = () => {
|
export const useMessage = () => {
|
||||||
const {
|
const {
|
||||||
@ -98,7 +98,7 @@ export const useMessage = () => {
|
|||||||
const url = await getOllamaURL()
|
const url = await getOllamaURL()
|
||||||
const userDefaultModelSettings = await getAllDefaultModelSettings()
|
const userDefaultModelSettings = await getAllDefaultModelSettings()
|
||||||
|
|
||||||
const ollama = new ChatOllama({
|
const ollama = await pageAssistModel({
|
||||||
model: selectedModel!,
|
model: selectedModel!,
|
||||||
baseUrl: cleanUrl(url),
|
baseUrl: cleanUrl(url),
|
||||||
keepAlive:
|
keepAlive:
|
||||||
@ -225,7 +225,7 @@ export const useMessage = () => {
|
|||||||
const promptForQuestion = questionPrompt
|
const promptForQuestion = questionPrompt
|
||||||
.replaceAll("{chat_history}", chat_history)
|
.replaceAll("{chat_history}", chat_history)
|
||||||
.replaceAll("{question}", message)
|
.replaceAll("{question}", message)
|
||||||
const questionOllama = new ChatOllama({
|
const questionOllama = await pageAssistModel({
|
||||||
model: selectedModel!,
|
model: selectedModel!,
|
||||||
baseUrl: cleanUrl(url),
|
baseUrl: cleanUrl(url),
|
||||||
keepAlive:
|
keepAlive:
|
||||||
@ -388,7 +388,7 @@ export const useMessage = () => {
|
|||||||
image = `data:image/jpeg;base64,${image.split(",")[1]}`
|
image = `data:image/jpeg;base64,${image.split(",")[1]}`
|
||||||
}
|
}
|
||||||
|
|
||||||
const ollama = new ChatOllama({
|
const ollama = await pageAssistModel({
|
||||||
model: selectedModel!,
|
model: selectedModel!,
|
||||||
baseUrl: cleanUrl(url),
|
baseUrl: cleanUrl(url),
|
||||||
keepAlive:
|
keepAlive:
|
||||||
@ -591,7 +591,7 @@ export const useMessage = () => {
|
|||||||
image = `data:image/jpeg;base64,${image.split(",")[1]}`
|
image = `data:image/jpeg;base64,${image.split(",")[1]}`
|
||||||
}
|
}
|
||||||
|
|
||||||
const ollama = new ChatOllama({
|
const ollama = await pageAssistModel({
|
||||||
model: selectedModel!,
|
model: selectedModel!,
|
||||||
baseUrl: cleanUrl(url),
|
baseUrl: cleanUrl(url),
|
||||||
keepAlive:
|
keepAlive:
|
||||||
@ -661,7 +661,7 @@ export const useMessage = () => {
|
|||||||
const promptForQuestion = questionPrompt
|
const promptForQuestion = questionPrompt
|
||||||
.replaceAll("{chat_history}", chat_history)
|
.replaceAll("{chat_history}", chat_history)
|
||||||
.replaceAll("{question}", message)
|
.replaceAll("{question}", message)
|
||||||
const questionOllama = new ChatOllama({
|
const questionOllama = await pageAssistModel({
|
||||||
model: selectedModel!,
|
model: selectedModel!,
|
||||||
baseUrl: cleanUrl(url),
|
baseUrl: cleanUrl(url),
|
||||||
keepAlive:
|
keepAlive:
|
||||||
|
@ -31,7 +31,7 @@ import { useWebUI } from "@/store/webui"
|
|||||||
import { useStorage } from "@plasmohq/storage/hook"
|
import { useStorage } from "@plasmohq/storage/hook"
|
||||||
import { useStoreChatModelSettings } from "@/store/model"
|
import { useStoreChatModelSettings } from "@/store/model"
|
||||||
import { getAllDefaultModelSettings } from "@/services/model-settings"
|
import { getAllDefaultModelSettings } from "@/services/model-settings"
|
||||||
import { ChatOllama } from "@/models/ChatOllama"
|
import { pageAssistModel } from "@/models"
|
||||||
|
|
||||||
export const useMessageOption = () => {
|
export const useMessageOption = () => {
|
||||||
const {
|
const {
|
||||||
@ -104,7 +104,7 @@ export const useMessageOption = () => {
|
|||||||
image = `data:image/jpeg;base64,${image.split(",")[1]}`
|
image = `data:image/jpeg;base64,${image.split(",")[1]}`
|
||||||
}
|
}
|
||||||
|
|
||||||
const ollama = new ChatOllama({
|
const ollama = await pageAssistModel({
|
||||||
model: selectedModel!,
|
model: selectedModel!,
|
||||||
baseUrl: cleanUrl(url),
|
baseUrl: cleanUrl(url),
|
||||||
keepAlive:
|
keepAlive:
|
||||||
@ -174,7 +174,7 @@ export const useMessageOption = () => {
|
|||||||
const promptForQuestion = questionPrompt
|
const promptForQuestion = questionPrompt
|
||||||
.replaceAll("{chat_history}", chat_history)
|
.replaceAll("{chat_history}", chat_history)
|
||||||
.replaceAll("{question}", message)
|
.replaceAll("{question}", message)
|
||||||
const questionOllama = new ChatOllama({
|
const questionOllama = await pageAssistModel({
|
||||||
model: selectedModel!,
|
model: selectedModel!,
|
||||||
baseUrl: cleanUrl(url),
|
baseUrl: cleanUrl(url),
|
||||||
keepAlive:
|
keepAlive:
|
||||||
@ -347,7 +347,7 @@ export const useMessageOption = () => {
|
|||||||
image = `data:image/jpeg;base64,${image.split(",")[1]}`
|
image = `data:image/jpeg;base64,${image.split(",")[1]}`
|
||||||
}
|
}
|
||||||
|
|
||||||
const ollama = new ChatOllama({
|
const ollama = await pageAssistModel({
|
||||||
model: selectedModel!,
|
model: selectedModel!,
|
||||||
baseUrl: cleanUrl(url),
|
baseUrl: cleanUrl(url),
|
||||||
keepAlive:
|
keepAlive:
|
||||||
@ -463,6 +463,7 @@ export const useMessageOption = () => {
|
|||||||
signal: signal
|
signal: signal
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
let count = 0
|
let count = 0
|
||||||
for await (const chunk of chunks) {
|
for await (const chunk of chunks) {
|
||||||
contentToSave += chunk.content
|
contentToSave += chunk.content
|
||||||
@ -562,7 +563,7 @@ export const useMessageOption = () => {
|
|||||||
const url = await getOllamaURL()
|
const url = await getOllamaURL()
|
||||||
const userDefaultModelSettings = await getAllDefaultModelSettings()
|
const userDefaultModelSettings = await getAllDefaultModelSettings()
|
||||||
|
|
||||||
const ollama = new ChatOllama({
|
const ollama = await pageAssistModel({
|
||||||
model: selectedModel!,
|
model: selectedModel!,
|
||||||
baseUrl: cleanUrl(url),
|
baseUrl: cleanUrl(url),
|
||||||
keepAlive:
|
keepAlive:
|
||||||
@ -648,7 +649,7 @@ export const useMessageOption = () => {
|
|||||||
const promptForQuestion = questionPrompt
|
const promptForQuestion = questionPrompt
|
||||||
.replaceAll("{chat_history}", chat_history)
|
.replaceAll("{chat_history}", chat_history)
|
||||||
.replaceAll("{question}", message)
|
.replaceAll("{question}", message)
|
||||||
const questionOllama = new ChatOllama({
|
const questionOllama = await pageAssistModel({
|
||||||
model: selectedModel!,
|
model: selectedModel!,
|
||||||
baseUrl: cleanUrl(url),
|
baseUrl: cleanUrl(url),
|
||||||
keepAlive:
|
keepAlive:
|
||||||
|
@ -4,6 +4,7 @@ import common from "@/assets/locale/en/common.json";
|
|||||||
import sidepanel from "@/assets/locale/en/sidepanel.json";
|
import sidepanel from "@/assets/locale/en/sidepanel.json";
|
||||||
import settings from "@/assets/locale/en/settings.json";
|
import settings from "@/assets/locale/en/settings.json";
|
||||||
import knowledge from "@/assets/locale/en/knowledge.json";
|
import knowledge from "@/assets/locale/en/knowledge.json";
|
||||||
|
import chrome from "@/assets/locale/en/chrome.json";
|
||||||
|
|
||||||
export const en = {
|
export const en = {
|
||||||
option,
|
option,
|
||||||
@ -11,5 +12,6 @@ export const en = {
|
|||||||
common,
|
common,
|
||||||
sidepanel,
|
sidepanel,
|
||||||
settings,
|
settings,
|
||||||
knowledge
|
knowledge,
|
||||||
|
chrome
|
||||||
}
|
}
|
@ -4,6 +4,7 @@ import common from "@/assets/locale/es/common.json";
|
|||||||
import sidepanel from "@/assets/locale/es/sidepanel.json";
|
import sidepanel from "@/assets/locale/es/sidepanel.json";
|
||||||
import settings from "@/assets/locale/es/settings.json";
|
import settings from "@/assets/locale/es/settings.json";
|
||||||
import knowledge from "@/assets/locale/es/knowledge.json";
|
import knowledge from "@/assets/locale/es/knowledge.json";
|
||||||
|
import chrome from "@/assets/locale/es/chrome.json";
|
||||||
|
|
||||||
export const es = {
|
export const es = {
|
||||||
option,
|
option,
|
||||||
@ -11,5 +12,6 @@ export const es = {
|
|||||||
common,
|
common,
|
||||||
sidepanel,
|
sidepanel,
|
||||||
settings,
|
settings,
|
||||||
knowledge
|
knowledge,
|
||||||
|
chrome
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ import common from "@/assets/locale/fr/common.json";
|
|||||||
import sidepanel from "@/assets/locale/fr/sidepanel.json";
|
import sidepanel from "@/assets/locale/fr/sidepanel.json";
|
||||||
import settings from "@/assets/locale/fr/settings.json";
|
import settings from "@/assets/locale/fr/settings.json";
|
||||||
import knowledge from "@/assets/locale/fr/knowledge.json";
|
import knowledge from "@/assets/locale/fr/knowledge.json";
|
||||||
|
import chrome from "@/assets/locale/fr/chrome.json";
|
||||||
|
|
||||||
export const fr = {
|
export const fr = {
|
||||||
option,
|
option,
|
||||||
@ -11,5 +12,6 @@ export const fr = {
|
|||||||
common,
|
common,
|
||||||
sidepanel,
|
sidepanel,
|
||||||
settings,
|
settings,
|
||||||
knowledge
|
knowledge,
|
||||||
|
chrome
|
||||||
}
|
}
|
@ -4,6 +4,7 @@ import common from "@/assets/locale/it/common.json";
|
|||||||
import sidepanel from "@/assets/locale/it/sidepanel.json";
|
import sidepanel from "@/assets/locale/it/sidepanel.json";
|
||||||
import settings from "@/assets/locale/it/settings.json";
|
import settings from "@/assets/locale/it/settings.json";
|
||||||
import knowledge from "@/assets/locale/it/knowledge.json";
|
import knowledge from "@/assets/locale/it/knowledge.json";
|
||||||
|
import chrome from "@/assets/locale/it/chrome.json";
|
||||||
|
|
||||||
export const it = {
|
export const it = {
|
||||||
option,
|
option,
|
||||||
@ -11,5 +12,6 @@ export const it = {
|
|||||||
common,
|
common,
|
||||||
sidepanel,
|
sidepanel,
|
||||||
settings,
|
settings,
|
||||||
knowledge
|
knowledge,
|
||||||
|
chrome
|
||||||
}
|
}
|
@ -4,6 +4,7 @@ import common from "@/assets/locale/ja-JP/common.json";
|
|||||||
import sidepanel from "@/assets/locale/ja-JP/sidepanel.json";
|
import sidepanel from "@/assets/locale/ja-JP/sidepanel.json";
|
||||||
import settings from "@/assets/locale/ja-JP/settings.json";
|
import settings from "@/assets/locale/ja-JP/settings.json";
|
||||||
import knowledge from "@/assets/locale/ja-JP/knowledge.json";
|
import knowledge from "@/assets/locale/ja-JP/knowledge.json";
|
||||||
|
import chrome from "@/assets/locale/ja-JP/chrome.json";
|
||||||
|
|
||||||
|
|
||||||
export const ja = {
|
export const ja = {
|
||||||
@ -12,5 +13,6 @@ export const ja = {
|
|||||||
common,
|
common,
|
||||||
sidepanel,
|
sidepanel,
|
||||||
settings,
|
settings,
|
||||||
knowledge
|
knowledge,
|
||||||
|
chrome
|
||||||
}
|
}
|
@ -4,6 +4,7 @@ import common from "@/assets/locale/ml/common.json";
|
|||||||
import sidepanel from "@/assets/locale/ml/sidepanel.json";
|
import sidepanel from "@/assets/locale/ml/sidepanel.json";
|
||||||
import settings from "@/assets/locale/ml/settings.json";
|
import settings from "@/assets/locale/ml/settings.json";
|
||||||
import knowledge from "@/assets/locale/ml/knowledge.json";
|
import knowledge from "@/assets/locale/ml/knowledge.json";
|
||||||
|
import chrome from "@/assets/locale/ml/chrome.json";
|
||||||
|
|
||||||
export const ml = {
|
export const ml = {
|
||||||
option,
|
option,
|
||||||
@ -11,5 +12,6 @@ export const ml = {
|
|||||||
common,
|
common,
|
||||||
sidepanel,
|
sidepanel,
|
||||||
settings,
|
settings,
|
||||||
knowledge
|
knowledge,
|
||||||
|
chrome
|
||||||
}
|
}
|
@ -4,6 +4,7 @@ import common from "@/assets/locale/pt-BR/common.json";
|
|||||||
import sidepanel from "@/assets/locale/pt-BR/sidepanel.json";
|
import sidepanel from "@/assets/locale/pt-BR/sidepanel.json";
|
||||||
import settings from "@/assets/locale/pt-BR/settings.json";
|
import settings from "@/assets/locale/pt-BR/settings.json";
|
||||||
import knowledge from "@/assets/locale/pt-BR/knowledge.json";
|
import knowledge from "@/assets/locale/pt-BR/knowledge.json";
|
||||||
|
import chrome from "@/assets/locale/pt-BR/chrome.json";
|
||||||
|
|
||||||
export const pt = {
|
export const pt = {
|
||||||
option,
|
option,
|
||||||
@ -11,5 +12,6 @@ export const pt = {
|
|||||||
common,
|
common,
|
||||||
sidepanel,
|
sidepanel,
|
||||||
settings,
|
settings,
|
||||||
knowledge
|
knowledge,
|
||||||
|
chrome
|
||||||
}
|
}
|
@ -4,6 +4,7 @@ import common from "@/assets/locale/ru/common.json";
|
|||||||
import sidepanel from "@/assets/locale/ru/sidepanel.json";
|
import sidepanel from "@/assets/locale/ru/sidepanel.json";
|
||||||
import settings from "@/assets/locale/ru/settings.json";
|
import settings from "@/assets/locale/ru/settings.json";
|
||||||
import knowledge from "@/assets/locale/ru/knowledge.json";
|
import knowledge from "@/assets/locale/ru/knowledge.json";
|
||||||
|
import chrome from "@/assets/locale/ru/chrome.json";
|
||||||
|
|
||||||
export const ru = {
|
export const ru = {
|
||||||
option,
|
option,
|
||||||
@ -11,5 +12,6 @@ export const ru = {
|
|||||||
common,
|
common,
|
||||||
sidepanel,
|
sidepanel,
|
||||||
settings,
|
settings,
|
||||||
knowledge
|
knowledge,
|
||||||
|
chrome
|
||||||
}
|
}
|
@ -4,6 +4,7 @@ import common from "@/assets/locale/zh/common.json";
|
|||||||
import sidepanel from "@/assets/locale/zh/sidepanel.json";
|
import sidepanel from "@/assets/locale/zh/sidepanel.json";
|
||||||
import settings from "@/assets/locale/zh/settings.json";
|
import settings from "@/assets/locale/zh/settings.json";
|
||||||
import knowledge from "@/assets/locale/zh/knowledge.json";
|
import knowledge from "@/assets/locale/zh/knowledge.json";
|
||||||
|
import chrome from "@/assets/locale/zh/chrome.json";
|
||||||
|
|
||||||
|
|
||||||
export const zh = {
|
export const zh = {
|
||||||
@ -12,5 +13,6 @@ export const zh = {
|
|||||||
common,
|
common,
|
||||||
sidepanel,
|
sidepanel,
|
||||||
settings,
|
settings,
|
||||||
knowledge
|
knowledge,
|
||||||
|
chrome
|
||||||
}
|
}
|
@ -50,9 +50,16 @@ function formatPrompt(messages: BaseMessage[]): string {
|
|||||||
return messages
|
return messages
|
||||||
.map((message) => {
|
.map((message) => {
|
||||||
if (typeof message.content !== "string") {
|
if (typeof message.content !== "string") {
|
||||||
throw new Error(
|
// console.log(message.content)
|
||||||
"ChatChromeAI does not support non-string message content."
|
// throw new Error(
|
||||||
)
|
// "ChatChromeAI does not support non-string message content."
|
||||||
|
// )
|
||||||
|
if (message.content.length > 0) {
|
||||||
|
//@ts-ignore
|
||||||
|
return message.content[0]?.text || ""
|
||||||
|
}
|
||||||
|
|
||||||
|
return ""
|
||||||
}
|
}
|
||||||
return `${message._getType()}: ${message.content}`
|
return `${message._getType()}: ${message.content}`
|
||||||
})
|
})
|
||||||
@ -147,10 +154,9 @@ export class ChatChromeAI extends SimpleChatModel<ChromeAICallOptions> {
|
|||||||
runManager?: CallbackManagerForLLMRun
|
runManager?: CallbackManagerForLLMRun
|
||||||
): AsyncGenerator<ChatGenerationChunk> {
|
): AsyncGenerator<ChatGenerationChunk> {
|
||||||
if (!this.session) {
|
if (!this.session) {
|
||||||
throw new Error("Session not found. Please call `.initialize()` first.")
|
await this.initialize()
|
||||||
}
|
}
|
||||||
const textPrompt = this.promptFormatter(messages)
|
const textPrompt = this.promptFormatter(messages)
|
||||||
|
|
||||||
const stream = this.session.promptStreaming(textPrompt)
|
const stream = this.session.promptStreaming(textPrompt)
|
||||||
const iterableStream = IterableReadableStream.fromReadableStream(stream)
|
const iterableStream = IterableReadableStream.fromReadableStream(stream)
|
||||||
|
|
||||||
|
41
src/models/index.ts
Normal file
41
src/models/index.ts
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
import { ChatChromeAI } from "./ChatChromeAi"
|
||||||
|
import { ChatOllama } from "./ChatOllama"
|
||||||
|
|
||||||
|
export const pageAssistModel = async ({
|
||||||
|
model,
|
||||||
|
baseUrl,
|
||||||
|
keepAlive,
|
||||||
|
temperature,
|
||||||
|
topK,
|
||||||
|
topP,
|
||||||
|
numCtx,
|
||||||
|
seed
|
||||||
|
}: {
|
||||||
|
model: string
|
||||||
|
baseUrl: string
|
||||||
|
keepAlive: string
|
||||||
|
temperature: number
|
||||||
|
topK: number
|
||||||
|
topP: number
|
||||||
|
numCtx: number
|
||||||
|
seed: number
|
||||||
|
}) => {
|
||||||
|
switch (model) {
|
||||||
|
case "chrome::gemini-nano::page-assist":
|
||||||
|
return new ChatChromeAI({
|
||||||
|
temperature,
|
||||||
|
topK
|
||||||
|
})
|
||||||
|
default:
|
||||||
|
return new ChatOllama({
|
||||||
|
baseUrl,
|
||||||
|
keepAlive,
|
||||||
|
temperature,
|
||||||
|
topK,
|
||||||
|
topP,
|
||||||
|
numCtx,
|
||||||
|
seed,
|
||||||
|
model
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
@ -10,6 +10,7 @@ import OptionAbout from "./option-settings-about"
|
|||||||
import SidepanelChat from "./sidepanel-chat"
|
import SidepanelChat from "./sidepanel-chat"
|
||||||
import SidepanelSettings from "./sidepanel-settings"
|
import SidepanelSettings from "./sidepanel-settings"
|
||||||
import OptionRagSettings from "./option-rag"
|
import OptionRagSettings from "./option-rag"
|
||||||
|
import OptionChrome from "./option-settings-chrome"
|
||||||
|
|
||||||
export const OptionRoutingChrome = () => {
|
export const OptionRoutingChrome = () => {
|
||||||
return (
|
return (
|
||||||
@ -19,6 +20,7 @@ export const OptionRoutingChrome = () => {
|
|||||||
<Route path="/settings/model" element={<OptionModal />} />
|
<Route path="/settings/model" element={<OptionModal />} />
|
||||||
<Route path="/settings/prompt" element={<OptionPrompt />} />
|
<Route path="/settings/prompt" element={<OptionPrompt />} />
|
||||||
<Route path="/settings/ollama" element={<OptionOllamaSettings />} />
|
<Route path="/settings/ollama" element={<OptionOllamaSettings />} />
|
||||||
|
<Route path="/settings/chrome" element={<OptionChrome />} />
|
||||||
<Route path="/settings/share" element={<OptionShare />} />
|
<Route path="/settings/share" element={<OptionShare />} />
|
||||||
<Route path="/settings/knowledge" element={<OptionKnowledgeBase />} />
|
<Route path="/settings/knowledge" element={<OptionKnowledgeBase />} />
|
||||||
<Route path="/settings/rag" element={<OptionRagSettings />} />
|
<Route path="/settings/rag" element={<OptionRagSettings />} />
|
||||||
|
15
src/routes/option-settings-chrome.tsx
Normal file
15
src/routes/option-settings-chrome.tsx
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
import { SettingsLayout } from "~/components/Layouts/SettingsOptionLayout"
|
||||||
|
import OptionLayout from "~/components/Layouts/Layout"
|
||||||
|
import { ChromeApp } from "@/components/Option/Settings/chrome"
|
||||||
|
|
||||||
|
const OptionChrome = () => {
|
||||||
|
return (
|
||||||
|
<OptionLayout>
|
||||||
|
<SettingsLayout>
|
||||||
|
<ChromeApp />
|
||||||
|
</SettingsLayout>
|
||||||
|
</OptionLayout>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default OptionChrome
|
38
src/services/chrome.ts
Normal file
38
src/services/chrome.ts
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
import { Storage } from "@plasmohq/storage"
|
||||||
|
|
||||||
|
const storage = new Storage()
|
||||||
|
|
||||||
|
const DEFAULT_CHROME_AI_MODEL = {
|
||||||
|
name: "Gemini Nano",
|
||||||
|
model: "chrome::gemini-nano::page-assist",
|
||||||
|
modified_at: "",
|
||||||
|
provider: "chrome",
|
||||||
|
size: 0,
|
||||||
|
digest: "",
|
||||||
|
details: {
|
||||||
|
parent_model: "",
|
||||||
|
format: "",
|
||||||
|
family: "",
|
||||||
|
families: [],
|
||||||
|
parameter_size: "",
|
||||||
|
quantization_level: ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getChromeAIStatus = async (): Promise<boolean> => {
|
||||||
|
const aiStatus = await storage.get<boolean | undefined>("chromeAIStatus")
|
||||||
|
return aiStatus ?? false
|
||||||
|
}
|
||||||
|
|
||||||
|
export const setChromeAIStatus = async (status: boolean): Promise<void> => {
|
||||||
|
await storage.set("chromeAIStatus", status)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getChromeAIModel = async () => {
|
||||||
|
const isEnable = await getChromeAIStatus()
|
||||||
|
if (isEnable) {
|
||||||
|
return [DEFAULT_CHROME_AI_MODEL]
|
||||||
|
} else {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,7 @@
|
|||||||
import { Storage } from "@plasmohq/storage"
|
import { Storage } from "@plasmohq/storage"
|
||||||
import { cleanUrl } from "../libs/clean-url"
|
import { cleanUrl } from "../libs/clean-url"
|
||||||
import { urlRewriteRuntime } from "../libs/runtime"
|
import { urlRewriteRuntime } from "../libs/runtime"
|
||||||
|
import { getChromeAIModel } from "./chrome"
|
||||||
|
|
||||||
const storage = new Storage()
|
const storage = new Storage()
|
||||||
|
|
||||||
@ -144,6 +145,7 @@ export const deleteModel = async (model: string) => {
|
|||||||
return response.json()
|
return response.json()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export const fetchChatModels = async ({
|
export const fetchChatModels = async ({
|
||||||
returnEmpty = false
|
returnEmpty = false
|
||||||
}: {
|
}: {
|
||||||
@ -174,15 +176,39 @@ export const fetchChatModels = async ({
|
|||||||
quantization_level: string
|
quantization_level: string
|
||||||
}
|
}
|
||||||
}[]
|
}[]
|
||||||
return models?.filter((model) => {
|
const chatModels = models
|
||||||
return (
|
?.filter((model) => {
|
||||||
!model?.details?.families?.includes("bert") &&
|
return (
|
||||||
!model?.details?.families?.includes("nomic-bert")
|
!model?.details?.families?.includes("bert") &&
|
||||||
)
|
!model?.details?.families?.includes("nomic-bert")
|
||||||
})
|
)
|
||||||
|
})
|
||||||
|
.map((model) => {
|
||||||
|
return {
|
||||||
|
...model,
|
||||||
|
provider: "ollama"
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const chromeModel = await getChromeAIModel()
|
||||||
|
return [
|
||||||
|
...chatModels,
|
||||||
|
...chromeModel
|
||||||
|
]
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e)
|
console.error(e)
|
||||||
return await getAllModels({ returnEmpty })
|
const allModels = await getAllModels({ returnEmpty })
|
||||||
|
const models = allModels.map((model) => {
|
||||||
|
return {
|
||||||
|
...model,
|
||||||
|
provider: "ollama"
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const chromeModel = await getChromeAIModel()
|
||||||
|
|
||||||
|
return [
|
||||||
|
...models,
|
||||||
|
...chromeModel
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -345,4 +371,3 @@ export const getPageShareUrl = async () => {
|
|||||||
export const setPageShareUrl = async (pageShareUrl: string) => {
|
export const setPageShareUrl = async (pageShareUrl: string) => {
|
||||||
await storage.set("pageShareUrl", pageShareUrl)
|
await storage.set("pageShareUrl", pageShareUrl)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
30
src/utils/chrome.ts
Normal file
30
src/utils/chrome.ts
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
export const getChromeAISupported = async () => {
|
||||||
|
try {
|
||||||
|
let browserInfo = navigator.userAgent.match(/Chrom(e|ium)\/([0-9]+)\./)
|
||||||
|
let version = browserInfo ? parseInt(browserInfo[2], 10) : 0
|
||||||
|
|
||||||
|
if (version < 127) {
|
||||||
|
return "browser_not_supported"
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!("ai" in globalThis)) {
|
||||||
|
return "ai_not_supported"
|
||||||
|
}
|
||||||
|
|
||||||
|
//@ts-ignore
|
||||||
|
const createSession = await ai?.canCreateGenericSession()
|
||||||
|
if (createSession !== "readily") {
|
||||||
|
return "ai_not_ready"
|
||||||
|
}
|
||||||
|
|
||||||
|
return "success"
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e)
|
||||||
|
return "internal_error"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const isChromeAISupported = async () => {
|
||||||
|
const result = await getChromeAISupported()
|
||||||
|
return result === "success"
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user