diff --git a/entrypoints/background.js b/entrypoints/background.js
index 56c9c74..c7c0791 100644
--- a/entrypoints/background.js
+++ b/entrypoints/background.js
@@ -3,13 +3,13 @@ import { browser } from "wxt/browser";
export default defineBackground(() => {
browser.contextMenus.create({
id: "explain",
- title: "解释:%s",
+ title: `${browser.i18n.getMessage("explain")}`,
contexts: ["selection"]
});
browser.contextMenus.create({
- id: "summarize",
- title: "总结全文",
+ id: "copilot",
+ title: `${browser.i18n.getMessage("copilot")}`,
contexts: ["page"]
});
diff --git a/entrypoints/content/App.jsx b/entrypoints/content/App.jsx
index 6622c96..7347214 100644
--- a/entrypoints/content/App.jsx
+++ b/entrypoints/content/App.jsx
@@ -31,9 +31,10 @@ export default ({ ctx }) => {
registerContentMessage(async payload => {
const { menuItemId, selectionText } = payload;
setPayload({
- message: menuItemId === 'explain' ? selectionText : '总结全文',
+ message: menuItemId === 'explain' ? selectionText : '',
type: menuItemId,
context: getPageContext(),
+ from: 'silo:extension',
});
setShowPage(true);
});
diff --git a/entrypoints/content/components/Modal.jsx b/entrypoints/content/components/Modal.jsx
index 7c1c47a..5a6b4e4 100644
--- a/entrypoints/content/components/Modal.jsx
+++ b/entrypoints/content/components/Modal.jsx
@@ -6,6 +6,21 @@ export default function ({ close, payload, visible }) {
const [loaded, setLoaded] = useState(false);
const iframeRef = useRef(null);
+ useEffect(() => {
+ const listener = event => {
+ const message = JSON.parse(event.data);
+ console.log(message);
+
+ if (message.type === 'silo:web-copilot-close') {
+ close();
+ }
+ };
+ window.addEventListener('message', listener);
+ return () => {
+ window.removeEventListener('message', listener);
+ };
+ }, []);
+
useEffect(() => {
if (payload.type) {
iframeRef.current.contentWindow.postMessage(JSON.stringify(payload), '*');
diff --git a/package.json b/package.json
index 30532cf..52afd3a 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "silo",
"private": true,
- "version": "1.6.3",
+ "version": "1.6.4",
"type": "module",
"scripts": {
"dev": "vite",
diff --git a/public/_locales/en/messages.json b/public/_locales/en/messages.json
new file mode 100644
index 0000000..df841a4
--- /dev/null
+++ b/public/_locales/en/messages.json
@@ -0,0 +1,13 @@
+{
+ "extName": {
+ "message": "Silo - Multi-model chat, text-to-images"
+ },
+ "explain": {
+ "message": "Explain: %s",
+ "description": "Explain the selected text"
+ },
+ "copilot": {
+ "message": "Ask Silo",
+ "description": "Ask Silo"
+ }
+}
\ No newline at end of file
diff --git a/public/_locales/zh/messages.json b/public/_locales/zh/messages.json
new file mode 100644
index 0000000..5cb9823
--- /dev/null
+++ b/public/_locales/zh/messages.json
@@ -0,0 +1,13 @@
+{
+ "extName": {
+ "message": "Silo - 多模型对话,文生图"
+ },
+ "explain": {
+ "message": "解释:%s",
+ "description": "Explain the selected text"
+ },
+ "copilot": {
+ "message": "问问 Silo",
+ "description": "Ask Silo"
+ }
+}
\ No newline at end of file
diff --git a/src/components/MarkdownRenderer.jsx b/src/components/MarkdownRenderer.jsx
index d9c23d3..4f0c945 100644
--- a/src/components/MarkdownRenderer.jsx
+++ b/src/components/MarkdownRenderer.jsx
@@ -103,7 +103,7 @@ export default function MarkdownRenderer({ content, loading = false }) {
children={content}
remarkPlugins={[remarkGfm, remarkMath]}
rehypePlugins={[rehypeKatex]}
- className="silo-markdown prose !max-w-none prose-pre:bg-transparent prose-slate prose-red prose-sm dark:prose-invert prose-headings:text-primary dark:prose-headings:text-[#2ddaff]"
+ className="silo-markdown prose !max-w-none prose-pre:bg-transparent prose-slate prose-red prose-sm dark:prose-invert prose-headings:text-primary dark:prose-headings:text-[#2ddaff] group"
components={{
code(props) {
let { children, className, node, ...rest } = props;
diff --git a/src/main.jsx b/src/main.jsx
index d79467d..7820060 100644
--- a/src/main.jsx
+++ b/src/main.jsx
@@ -1,14 +1,14 @@
import './utils/exception.js';
-import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';
import App from './App.jsx';
import './index.css';
import './i18n';
import { Analytics } from '@vercel/analytics/react';
+import { isBrowserExtension } from './utils/utils.js';
createRoot(document.getElementById('root')).render(
<>
-
+ {!isBrowserExtension ? : null}
>
);
diff --git a/src/pages/chat/components/AiMessage.jsx b/src/pages/chat/components/AiMessage.jsx
index d0df19b..7ab623f 100644
--- a/src/pages/chat/components/AiMessage.jsx
+++ b/src/pages/chat/components/AiMessage.jsx
@@ -80,16 +80,21 @@ export default function AiMessage({
)}
-
-
message.success(t('common.copied'))}
+ {!loading && (
+
-
-
-
+ message.success(t('common.copied'))}
+ >
+
+
+
+ )}
{formattedInfo && (
{formattedInfo}
)}
diff --git a/src/pages/chat/components/ChatInput/index.jsx b/src/pages/chat/components/ChatInput/index.jsx
index 27071f9..6aaa842 100644
--- a/src/pages/chat/components/ChatInput/index.jsx
+++ b/src/pages/chat/components/ChatInput/index.jsx
@@ -40,7 +40,10 @@ export default function ({
onStop(true);
} else if (action === SHORTCUTS_ACTIONS.STOP) {
onStop(false);
- } else if (action === SHORTCUTS_ACTIONS.RESEND_LAST) {
+ } else if (
+ action === SHORTCUTS_ACTIONS.RESEND_LAST &&
+ messageHistory.length > 0
+ ) {
const { message, image, chatId } =
messageHistory[messageHistory.length - 1];
removeUserMessage(chatId);
diff --git a/src/pages/chat/components/MultiPanelMessages/SingleChatPanel/index.jsx b/src/pages/chat/components/MultiPanelMessages/SingleChatPanel/index.jsx
index a503c67..36ea1d6 100644
--- a/src/pages/chat/components/MultiPanelMessages/SingleChatPanel/index.jsx
+++ b/src/pages/chat/components/MultiPanelMessages/SingleChatPanel/index.jsx
@@ -20,7 +20,7 @@ import { Dropdown } from 'tdesign-react';
import ChatModelSelector from './ChatModelSelector';
import { message } from 'tdesign-react';
import { GUIDE_STEP } from '@src/utils/types';
-export default function ({ model, plain = false }) {
+export default function ({ model, plain = false, className = '' }) {
const { t } = useTranslation();
const messages = useChatMessages(model);
const { activeModels, removeActiveModel } = useActiveModels();
diff --git a/src/pages/web-copilot/components/WordExplainer.jsx b/src/pages/web-copilot/components/WordExplainer.jsx
index 4e0a3a2..90522ef 100644
--- a/src/pages/web-copilot/components/WordExplainer.jsx
+++ b/src/pages/web-copilot/components/WordExplainer.jsx
@@ -41,13 +41,14 @@ export default function ({ context, word }) {
)
: `${prompt}\n${context}\n`;
- const { loading, onSubmit, onStop } = useSiloChat(systemPrompt, activeModels);
+ const { loading, onSubmit, onStop, messageHistory } = useSiloChat(
+ systemPrompt,
+ activeModels
+ );
useEffect(() => {
if (!isModelInit) return;
- console.log(appActiveModels);
- onStop(true);
if (word) {
setTimeout(() => {
onSubmit(word);
@@ -72,8 +73,6 @@ export default function ({ context, word }) {
});
};
- console.log(isModelInit);
-
if (!isModelInit || !filteredResponses.length) return null;
return (
@@ -114,7 +113,7 @@ export default function ({ context, word }) {
onCursor(-1)}
@@ -122,6 +121,7 @@ export default function ({ context, word }) {
onStop={onStop}
onSubmit={onSubmit}
loading={filteredResponses[activeIndex]?.loading}
+ messageHistory={messageHistory}
/>
diff --git a/src/pages/web-copilot/index.jsx b/src/pages/web-copilot/index.jsx
index 041ad53..05e4b55 100644
--- a/src/pages/web-copilot/index.jsx
+++ b/src/pages/web-copilot/index.jsx
@@ -1,18 +1,26 @@
-import { useState } from 'react';
+import { useState, useRef } from 'react';
import mockData from './mock.json';
import { useEffect } from 'react';
import WordExplainer from './components/WordExplainer';
import { isBrowserExtension } from '@src/utils/utils';
+import WebCopilotSettings from '@src/components/Header/WebCopilotSettingsModal';
+import { useDarkMode } from '@src/utils/use';
+
+const commonIconClass =
+ ' cursor-pointer opacity-50 hover:opacity-100 transition-opacity duration-300 text-xl ml-2';
+
export default function () {
+ const settingsRef = useRef(null);
const [message, setMessage] = useState(!isBrowserExtension ? mockData : null);
-
- console.log(message);
+ const [isDark, setDarkMode] = useDarkMode();
useEffect(() => {
const handleMessage = event => {
if (event.data && typeof event.data === 'string') {
- console.log(event.data);
- setMessage(JSON.parse(event.data));
+ const message = JSON.parse(event.data);
+ if (message.from === 'silo:extension') {
+ setMessage(message);
+ }
}
};
@@ -21,14 +29,52 @@ export default function () {
window.removeEventListener('message', handleMessage);
};
}, []);
+
return (
-
- {message && (
-
+
+
+
})
{
+ window.open(browser.runtime.getURL('ext.html'), '_blank');
+ }}
/>
- )}
+
setDarkMode(!isDark)}
+ >
+
{
+ settingsRef.current?.open();
+ }}
+ >
+
{
+ window.parent?.postMessage(
+ JSON.stringify({ type: 'silo:web-copilot-close' }),
+ '*'
+ );
+ }}
+ >
+
+
+ {message && (
+
+ )}
+
);
}
diff --git a/src/utils/models.js b/src/utils/models.js
index b708a92..fb04a3d 100644
--- a/src/utils/models.js
+++ b/src/utils/models.js
@@ -154,7 +154,8 @@ const SILICON_MODELS = [
textModelOf("Vendor-A/Qwen/Qwen2-72B-Instruct", 1, 32, false),
// textModelOf("nvidia/Llama-3.1-Nemotron-70B-Instruct", 4.13, 32, true),
textModelOf("google/gemma-2-27b-it", 1.26, 8, true),
- textModelOf("meta-llama/Meta-Llama-3.1-70B-Instruct", 4.13, 8, true),
+ textModelOf("meta-llama/Llama-3.3-70B-Instruct", 4.13, 32, true),
+ textModelOf("meta-llama/Meta-Llama-3.1-70B-Instruct", 4.13, 32, true),
// textModelOf("meta-llama/Meta-Llama-3-70B-Instruct", 4.13, 8, true),
textModelOf("meta-llama/Meta-Llama-3.1-405B-Instruct", 21, 32, true),
textModelOf("Qwen/Qwen2-VL-72B-Instruct", 4.13, 32, false, true),
diff --git a/src/utils/utils.js b/src/utils/utils.js
index f556a60..6736188 100644
--- a/src/utils/utils.js
+++ b/src/utils/utils.js
@@ -3,7 +3,6 @@ import { getChatResolver, isLimitedModel } from './models';
import { fmtBaseUrl } from "./format";
import { isExperienceSK } from "@src/store/storage";
import { LOCAL_STORAGE_KEY } from "./types";
-import { getLocalStorage } from "./helpers";
export function createOpenAICompatibleRequestOptions (sk, model, messages, options = {}) {
return {
method: 'POST',
@@ -38,7 +37,10 @@ const defaultModelIdResolver = modelId => {
export function openAiCompatibleChat (baseUrl, sk, modelIdResolver, model, messages, chatOptions, controller, onChunk, onEnd, onError) {
const modelId = (modelIdResolver || defaultModelIdResolver)(model) // 取出模型ID
if (!sk) {
- return onError(new Error('API Key未配置'))
+ if (isBrowserExtension) {
+ return onError(new Error('Please configure the API key in the extension main page and reload this page'))
+ }
+ return onError(new Error('API Key is missing'))
}
const startTime = Date.now()
fetch(`${fmtBaseUrl(baseUrl)}/chat/completions`, { ...createOpenAICompatibleRequestOptions(sk, modelId, messages, chatOptions), signal: controller.current.signal })
diff --git a/wxt.config.js b/wxt.config.js
index bb62a68..e6c6f72 100644
--- a/wxt.config.js
+++ b/wxt.config.js
@@ -5,7 +5,7 @@ console.log(path.resolve(__dirname, './src'));
export default defineConfig({
modules: ['@wxt-dev/module-react'],
manifest: {
- name: 'Silo - Multi-model chat, text-to-image',
+ name: '__MSG_extName__',
permissions: ['contextMenus'],
action: {},
"web_accessible_resources": [
@@ -13,7 +13,8 @@ export default defineConfig({
"resources": ["ext.html"],
"matches": ['*://*/*']
}
- ]
+ ],
+ default_locale: 'en',
},
vite: () => ({
esbuild: {