diff --git a/README.md b/README.md
index 29693ee..f614d23 100644
--- a/README.md
+++ b/README.md
@@ -18,7 +18,7 @@
Introducing Noi: an AI-enhanced, customizable browser designed to streamline your digital experience:
-**AI Support: [ChatGPT](https://chatgpt.com), [Claude](https://claude.ai), [Gemini](https://gemini.google.com), [DeepSeek](https://chat.deepseek.com), [GitHub Copilot](https://github.com/copilot), [HuggingChat](https://huggingface.co/chat), and more.**
+**AI Support: [ChatGPT](https://chatgpt.com), [Claude](https://claude.ai), [Gemini](https://gemini.google.com), [Grok](https://grok.com), [DeepSeek](https://chat.deepseek.com), [GitHub Copilot](https://github.com/copilot), [HuggingChat](https://huggingface.co/chat), and more.**
- **Browser**: Noi not only includes curated AI websites but also allows the addition of any URL, providing a tailored browsing experience ([Noi Configs](./configs)).
- **Prompts Management**: Offers robust customization options including the addition, synchronization, batch tagging, and removal of prompts.
@@ -110,9 +110,8 @@ Learn more: [electronjs/doc](https://www.electronjs.org/docs/latest/api/extensio
| Name | Version | Description |
| --- | --- | --- |
-| [@noi/ask](https://github.com/lencx/Noi/tree/main/extensions/noi-ask) | 0.1.17 | The best assistant for batch asking and quick typing of prompts. |
+| [@noi/ask](https://github.com/lencx/Noi/tree/main/extensions/noi-ask) | 0.1.18 | The best assistant for batch asking and quick typing of prompts. |
| [@noi/ask-custom](https://github.com/lencx/Noi/tree/main/extensions/noi-ask-custom) | 0.1.0 | The best assistant for batch asking and quick typing of prompts. |
-| [@noi/export-chatgpt](https://github.com/lencx/Noi/tree/main/extensions/noi-export-chatgpt) | 0.1.1 | ChatGPT chat history export, supports PDF, Image, and Markdown formats. |
| [@noi/reset](https://github.com/lencx/Noi/tree/main/extensions/noi-reset) | 0.1.3 | Reset certain website styles to enhance compatibility with Noi. |
diff --git a/configs/noi.mode.cn.json b/configs/noi.mode.cn.json
index 37099d0..b39704a 100644
--- a/configs/noi.mode.cn.json
+++ b/configs/noi.mode.cn.json
@@ -51,6 +51,12 @@
"text": "Gemini",
"url": "https://gemini.google.com"
},
+ {
+ "id": "noi:grok",
+ "parent": "noi@ai",
+ "text": "Grok",
+ "url": "https://grok.com"
+ },
{
"id": "noi:deepseek",
"parent": "noi@ai",
diff --git a/configs/noi.mode.json b/configs/noi.mode.json
index 4963163..0120ada 100644
--- a/configs/noi.mode.json
+++ b/configs/noi.mode.json
@@ -57,6 +57,12 @@
"text": "Gemini",
"url": "https://gemini.google.com"
},
+ {
+ "id": "noi:grok",
+ "parent": "noi@ai",
+ "text": "Grok",
+ "url": "https://grok.com"
+ },
{
"id": "noi:deepseek",
"parent": "noi@ai",
diff --git a/extensions/README.md b/extensions/README.md
index 9f2bc99..4b21d8a 100644
--- a/extensions/README.md
+++ b/extensions/README.md
@@ -9,8 +9,7 @@ Learn more: [electronjs/doc](https://www.electronjs.org/docs/latest/api/extensio
| Name | Version | Description |
| --- | --- | --- |
-| [@noi/ask](https://github.com/lencx/Noi/tree/main/extensions/noi-ask) | 0.1.17 | The best assistant for batch asking and quick typing of prompts. |
+| [@noi/ask](https://github.com/lencx/Noi/tree/main/extensions/noi-ask) | 0.1.18 | The best assistant for batch asking and quick typing of prompts. |
| [@noi/ask-custom](https://github.com/lencx/Noi/tree/main/extensions/noi-ask-custom) | 0.1.0 | The best assistant for batch asking and quick typing of prompts. |
-| [@noi/export-chatgpt](https://github.com/lencx/Noi/tree/main/extensions/noi-export-chatgpt) | 0.1.1 | ChatGPT chat history export, supports PDF, Image, and Markdown formats. |
| [@noi/reset](https://github.com/lencx/Noi/tree/main/extensions/noi-reset) | 0.1.3 | Reset certain website styles to enhance compatibility with Noi. |
\ No newline at end of file
diff --git a/extensions/noi-ask/main.js b/extensions/noi-ask/main.js
index 5f25518..274a1ce 100644
--- a/extensions/noi-ask/main.js
+++ b/extensions/noi-ask/main.js
@@ -70,24 +70,13 @@ class OpenAIAsk extends NoiAsk {
}
}
-class SoraAsk extends NoiAsk {
- static name = 'Sora';
- static url = 'https://sora.com';
+class GrokAsk extends NoiAsk {
+ static name = 'Grok';
+ static url = 'https://grok.com';
static submit() {
- const buttons = document.querySelectorAll('.surface-composer button');
- const lastButton = buttons[buttons.length - 1];
- if (lastButton) this.autoClick(lastButton);
- }
-}
-
-class PoeAsk extends NoiAsk {
- static name = 'Poe';
- static url = 'https://poe.com';
-
- static submit() {
- const btn = document.querySelectorAll('button[class*="ChatMessageSendButton_sendButton"]')[0];
- if (btn) this.autoClick(btn);
+ const btn = document.querySelector('button[type="submit"]');
+ if (btn) btn.click();
}
}
@@ -179,6 +168,28 @@ class HuggingChatAsk extends NoiAsk {
}
}
+
+class SoraAsk extends NoiAsk {
+ static name = 'Sora';
+ static url = 'https://sora.com';
+
+ static submit() {
+ const buttons = document.querySelectorAll('.surface-composer button');
+ const lastButton = buttons[buttons.length - 1];
+ if (lastButton) this.autoClick(lastButton);
+ }
+}
+
+class PoeAsk extends NoiAsk {
+ static name = 'Poe';
+ static url = 'https://poe.com';
+
+ static submit() {
+ const btn = document.querySelectorAll('button[class*="ChatMessageSendButton_sendButton"]')[0];
+ if (btn) this.autoClick(btn);
+ }
+}
+
class PerplexityAsk extends NoiAsk {
static name = 'Perplexity';
static url = 'https://www.perplexity.ai';
@@ -243,6 +254,36 @@ class CopilotAsk extends NoiAsk {
}
}
+class GitHubCopilotAsk extends NoiAsk {
+ static name = 'GitHub';
+ static url = 'https://github.com/copilot';
+
+ static sync(message) {
+ const inputElement = document.querySelector('form #copilot-chat-textarea');
+ if (inputElement) {
+ inputElement.focus();
+ document.execCommand('undo');
+ document.execCommand('insertText', false, message);
+ }
+ }
+
+ static submit() {
+ const btns = document.querySelectorAll('form button');
+ const btn = btns[btns.length - 1];
+ if (btn) this.autoClick(btn);
+ }
+}
+
+class NotebooklmAsk extends NoiAsk {
+ static name = 'NotebookLM';
+ static url = 'https://notebooklm.google.com';
+
+ static submit() {
+ const btn = document.querySelector('form button[type="submit"]');
+ if (btn) btn.click();
+ }
+}
+
class PiAsk extends NoiAsk {
static name = 'Pi';
static url = 'https://pi.ai/talk';
@@ -286,6 +327,27 @@ class YouAsk extends NoiAsk {
}
}
+
+class GroqAsk extends NoiAsk {
+ static name = 'Groq';
+ static url = 'https://groq.com';
+
+ static submit() {
+ const btn = document.querySelector('form button[type="submit"]');
+ if (btn) btn.click();
+ }
+}
+
+class SunoAsk extends NoiAsk {
+ static name = 'Suno AI';
+ static url = 'https://suno.com';
+
+ static submit() {
+ const btn = Array.from(document.querySelectorAll('button')).find(i => i.innerText.includes('Create'));
+ if (btn) btn.click();
+ }
+}
+
class CozeCNAsk extends NoiAsk {
static name = 'Coze';
static url = 'https://www.coze.cn/home';
@@ -342,36 +404,6 @@ class TongyiAsk extends NoiAsk {
}
}
-class GroqAsk extends NoiAsk {
- static name = 'Groq';
- static url = 'https://groq.com';
-
- static submit() {
- const btn = document.querySelector('form button[type="submit"]');
- if (btn) btn.click();
- }
-}
-
-class SunoAsk extends NoiAsk {
- static name = 'Suno AI';
- static url = 'https://suno.com';
-
- static submit() {
- const btn = Array.from(document.querySelectorAll('button')).find(i => i.innerText.includes('Create'));
- if (btn) btn.click();
- }
-}
-
-class NotebooklmAsk extends NoiAsk {
- static name = 'NotebookLM';
- static url = 'https://notebooklm.google.com';
-
- static submit() {
- const btn = document.querySelector('form button[type="submit"]');
- if (btn) btn.click();
- }
-}
-
class JimengAsk extends NoiAsk {
static name = 'Jimeng';
static url = 'https://jimeng.jianying.com';
@@ -401,26 +433,6 @@ class JimengAsk extends NoiAsk {
}
}
-class GitHubCopilotAsk extends NoiAsk {
- static name = 'GitHub';
- static url = 'https://github.com/copilot';
-
- static sync(message) {
- const inputElement = document.querySelector('form #copilot-chat-textarea');
- if (inputElement) {
- inputElement.focus();
- document.execCommand('undo');
- document.execCommand('insertText', false, message);
- }
- }
-
- static submit() {
- const btns = document.querySelectorAll('form button');
- const btn = btns[btns.length - 1];
- if (btn) this.autoClick(btn);
- }
-}
-
class MetasoAsk extends NoiAsk {
static name = 'Metaso'; // 秘塔
static url = 'https://metaso.cn';
@@ -433,25 +445,26 @@ class MetasoAsk extends NoiAsk {
window.NoiAsk = {
OpenAIAsk,
- SoraAsk,
- PoeAsk,
ClaudeAsk,
GeminiAsk,
+ GrokAsk,
+ CopilotAsk,
HuggingChatAsk,
PerplexityAsk,
- CopilotAsk,
+ NotebooklmAsk,
+ GitHubCopilotAsk,
PiAsk,
+ GroqAsk,
+ PoeAsk,
+ SoraAsk,
+ SunoAsk,
CozeAsk,
YouAsk,
CozeCNAsk,
DoubaoAsk,
ChatGLMAsk,
TongyiAsk,
- GroqAsk,
- SunoAsk,
- NotebooklmAsk,
JimengAsk,
DeepSeekAsk,
- GitHubCopilotAsk,
MetasoAsk,
};
diff --git a/extensions/noi-ask/manifest.json b/extensions/noi-ask/manifest.json
index 0835fd9..be8fff4 100644
--- a/extensions/noi-ask/manifest.json
+++ b/extensions/noi-ask/manifest.json
@@ -1,7 +1,7 @@
{
"manifest_version": 3,
"name": "@noi/ask",
- "version": "0.1.17",
+ "version": "0.1.18",
"homepage": "https://github.com/lencx/Noi/tree/main/extensions/noi-ask",
"description": "The best assistant for batch asking and quick typing of prompts.",
"content_scripts": [
@@ -10,6 +10,7 @@
"https://chatgpt.com/*",
"https://sora.com/*",
"https://gemini.google.com/*",
+ "https://grok.com/*",
"https://poe.com/*",
"https://claude.ai/*",
"https://huggingface.co/chat/*",
@@ -17,17 +18,17 @@
"https://copilot.microsoft.com/*",
"https://groq.com/*",
"https://pi.ai/talk/*",
- "https://www.coze.com/home/*",
+ "https://suno.com/*",
+ "https://notebooklm.google.com/*",
+ "https://github.com/copilot/*",
"https://you.com/*",
+ "https://www.coze.com/home/*",
"https://www.coze.cn/home/*",
"https://chatglm.cn/*",
"https://www.doubao.com/*",
"https://tongyi.aliyun.com/qianwen/*",
- "https://suno.com/*",
- "https://notebooklm.google.com/*",
"https://jimeng.jianying.com/*",
"https://chat.deepseek.com/*",
- "https://github.com/copilot/*",
"https://metaso.cn/*"
],
"js": ["main.js"],
diff --git a/extensions/noi-export-chatgpt/README.md b/extensions/noi-export-chatgpt/README.md
deleted file mode 100644
index 51fa652..0000000
--- a/extensions/noi-export-chatgpt/README.md
+++ /dev/null
@@ -1,3 +0,0 @@
-# @noi/export-chatgpt
-
-ChatGPT chat history export, supports PDF, Image, and Markdown formats.
diff --git a/extensions/noi-export-chatgpt/main.js b/extensions/noi-export-chatgpt/main.js
deleted file mode 100644
index eb42257..0000000
--- a/extensions/noi-export-chatgpt/main.js
+++ /dev/null
@@ -1,174 +0,0 @@
-const icons = {
- check: ``,
- noCheck: ``,
-}
-
-const QUERY_CHAT_LIST = 'main [role="presentation"] div[data-testid]';
-const QUERY_CHECKBOX_AREA = '.empty\\:hidden div.visible';
-const QUERY_ACTION_BUTTON = '.empty\\:hidden div.visible button';
-
-window.noiExport = function() {
- const allNodes = Array.from(document.querySelectorAll(QUERY_CHAT_LIST));
- if (!allNodes.length) {
- return {
- selected: [],
- all: [],
- };
- }
-
- return {
- selected: window._noiSelectedNodes,
- all: allNodes.map((el) => {
- const node = el.cloneNode(true);
- const msgNode = node.querySelector('[data-message-author-role]');
- if (msgNode) {
- msgNode.className = 'whitespace-pre-wrap break-words';
- }
- return node;
- }),
- };
-}
-
-// ------------------------------
-
-window.addEventListener('load', () => {
- window._noiSelectedNodes = [];
- const debouncedHandleMainChanges = debounce(handleMainChanges, 250);
-
- const observer = new MutationObserver(mutations => {
- mutations.forEach(mutation => {
- if (!mutation.target.form) {
- debouncedHandleMainChanges();
- }
- });
- });
-
- const mainElement = document.querySelector('main');
- observer.observe(mainElement, { childList: true, subtree: true });
-
- debouncedHandleMainChanges();
-
- changeURL(() => {
- window._noiSelectedNodes = [];
- });
-})
-
-function debounce(func, wait) {
- let timeout;
- return function(...args) {
- clearTimeout(timeout);
- timeout = setTimeout(() => {
- func.apply(this, args);
- }, wait);
- };
-}
-
-function createButtonForNode(i, index, nodesMap) {
- i.setAttribute('noi-node-id', index);
- nodesMap.set(index, i);
-
- const btnArea = i.querySelector(QUERY_CHECKBOX_AREA);
- if (!btnArea) return;
-
- if (btnArea.querySelector('button.noi-checkbox')) return;
-
- const defaultBtn = i.querySelector(QUERY_ACTION_BUTTON);
- if (!defaultBtn) return;
-
- const btn = document.createElement('button');
- btn.classList.add(...defaultBtn.classList, 'noi-checkbox');
- btn.innerHTML = icons.noCheck;
- btn.setAttribute('data-checked', 'false');
-
- btn.onclick = () => {
- const isChecked = btn.getAttribute('data-checked') === 'true';
- btn.innerHTML = isChecked ? icons.noCheck : icons.check;
- btn.setAttribute('data-checked', `${!isChecked}`);
- i.classList.toggle('noi-selected', !isChecked);
- updateSelectedNodes(isChecked, i.cloneNode(true), nodesMap);
- }
-
- btnArea.insertBefore(btn, btnArea.firstChild);
-}
-
-function updateSelectedNodes(isChecked, node, nodesMap) {
- const nodeId = node.getAttribute('noi-node-id');
- const indexInAll = nodesMap.get(Number(nodeId));
- const indexInSelected = window._noiSelectedNodes.findIndex(n => n.getAttribute('noi-node-id') === nodeId);
-
- if (!isChecked) {
- if (indexInSelected === -1) {
- let inserted = false;
- for (let i = 0; i < window._noiSelectedNodes.length; i++) {
- const currentId = window._noiSelectedNodes[i].getAttribute('noi-node-id');
- if (nodesMap.get(Number(currentId)) > indexInAll) {
- window._noiSelectedNodes.splice(i, 0, node);
- inserted = true;
- break;
- }
- }
- if (!inserted) {
- const msgNode = node.querySelector('[data-message-author-role]');
- if (msgNode) {
- msgNode.className = 'whitespace-pre-wrap break-words';
- }
- window._noiSelectedNodes.push(node);
- }
- }
- } else {
- if (indexInSelected > -1) {
- window._noiSelectedNodes.splice(indexInSelected, 1);
- }
- }
- window._noiSelectedNodes.sort((a, b) => {
- const nodeIdA = a.getAttribute('noi-node-id');
- const nodeIdB = b.getAttribute('noi-node-id');
- return Number(nodeIdA) - Number(nodeIdB);
- });
- console.log(window._noiSelectedNodes);
-}
-
-function handleMainChanges() {
- const nodesMap = new Map();
- document.querySelectorAll(QUERY_CHAT_LIST)
- .forEach((node, index) => createButtonForNode(node, index, nodesMap));
-}
-
-(function (history) {
- function triggerEvent(eventName, state) {
- if (typeof history[eventName] === 'function') {
- history[eventName]({ state: state, url: window.location.href });
- }
- }
-
- function overrideHistoryMethod(methodName, eventName) {
- const originalMethod = history[methodName];
- history[methodName] = function (state, ...rest) {
- const result = originalMethod.apply(this, [state, ...rest]);
- triggerEvent(eventName, state);
- return result;
- };
- }
-
- overrideHistoryMethod('pushState', 'onpushstate');
- overrideHistoryMethod('replaceState', 'onreplacestate');
-
- window.addEventListener('popstate', () => {
- triggerEvent('onpopstate', null);
- });
-})(window.history);
-
-function changeURL(callback) {
- window.history.onpushstate = (event) => {
- console.log('pushState called:', event.url);
- callback && callback(event);
- };
- window.history.onreplacestate = (event) => {
- console.log('replaceState called:', event.url);
- callback && callback(event);
- };
- window.history.onpopstate = (event) => {
- console.log('popstate event triggered', window.location.href);
- callback && callback(event);
- };
-}
diff --git a/extensions/noi-export-chatgpt/manifest.json b/extensions/noi-export-chatgpt/manifest.json
deleted file mode 100644
index 9968d38..0000000
--- a/extensions/noi-export-chatgpt/manifest.json
+++ /dev/null
@@ -1,16 +0,0 @@
-{
- "manifest_version": 3,
- "name": "@noi/export-chatgpt",
- "version": "0.1.1",
- "homepage": "https://github.com/lencx/Noi/tree/main/extensions/noi-export-chatgpt",
- "description": "ChatGPT chat history export, supports PDF, Image, and Markdown formats.",
- "content_scripts": [
- {
- "matches": ["https://chatgpt.com/*"],
- "js": ["main.js"],
- "css": ["style.css"],
- "run_at": "document_end",
- "world": "MAIN"
- }
- ]
-}
\ No newline at end of file
diff --git a/extensions/noi-export-chatgpt/style.css b/extensions/noi-export-chatgpt/style.css
deleted file mode 100644
index b5fb7f9..0000000
--- a/extensions/noi-export-chatgpt/style.css
+++ /dev/null
@@ -1,3 +0,0 @@
-.noi-selected {
- border: dashed 2px rgb(34 197 94);
-}
\ No newline at end of file
diff --git a/extensions/noi.extensions.json b/extensions/noi.extensions.json
index 42e5f32..4886944 100644
--- a/extensions/noi.extensions.json
+++ b/extensions/noi.extensions.json
@@ -5,7 +5,7 @@
{
"name": "@noi/ask",
"description": "The best assistant for batch asking and quick typing of prompts.",
- "version": "0.1.17",
+ "version": "0.1.18",
"url": "https://github.com/lencx/Noi/tree/main/extensions/noi-ask",
"dirname": "noi-ask",
"disabled": false
@@ -18,14 +18,6 @@
"dirname": "noi-ask-custom",
"disabled": false
},
- {
- "name": "@noi/export-chatgpt",
- "description": "ChatGPT chat history export, supports PDF, Image, and Markdown formats.",
- "version": "0.1.1",
- "url": "https://github.com/lencx/Noi/tree/main/extensions/noi-export-chatgpt",
- "dirname": "noi-export-chatgpt",
- "disabled": false
- },
{
"name": "@noi/reset",
"description": "Reset certain website styles to enhance compatibility with Noi.",