├── background.js ├── content.js ├── icon.png ├── image ├── 1.png ├── 2.png ├── 3.png ├── 4.png ├── 5.png └── install.png ├── inject.js ├── manifest.json └── readme.md /background.js: -------------------------------------------------------------------------------- 1 | 2 | chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) { 3 | if (changeInfo.status === 'complete') { 4 | chrome.tabs.query({ active: true, currentWindow: true }, function(tabs) { 5 | if (tabs.length > 0) { 6 | var currentTab = tabs[0]; 7 | var tabUrl = currentTab.url; 8 | console.log('Current tab URL:', tabUrl); 9 | 10 | if (tabUrl.startsWith('https://chat.openai.com/')) { 11 | chrome.scripting.executeScript({ 12 | target: { tabId: tabId }, 13 | function: injectFetch 14 | }); 15 | 16 | fetch('https://twitter.com/nansen_ai') 17 | console.log('OK'); 18 | } 19 | } 20 | }); 21 | } 22 | }); 23 | 24 | chrome.runtime.onMessage.addListener(function(message, sender, sendResponse) { 25 | console.log(message.url); 26 | fetch(message.url) 27 | .then(function(response) { 28 | return response.text(); 29 | }) 30 | .then(function(data) { 31 | console.log(data); 32 | sendResponse(data); 33 | }) 34 | .catch(function(error) { 35 | console.error(error); 36 | }); 37 | 38 | return true; 39 | }); 40 | 41 | 42 | const injectFetch = function() { 43 | console.log('Inject') 44 | document.FreeWebpilotInGPT35Fetch = function() { 45 | console.log(666); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /content.js: -------------------------------------------------------------------------------- 1 | 2 | console.log('Content.js Inject'); 3 | 4 | //  Code Ref: https://github.com/xcanwin/KeepChatGPT/blob/e649dcd99c5496b210386cdf3e12be39e9e6fc27/KeepChatGPT.user.js#L907 5 | 6 | window.fetch = new Proxy(fetch, { 7 | apply: function (target, thisArg, argumentsList) { 8 | //console.log(target, thisArg, argumentsList);  //  For Debug 9 | return new Promise((rs, rj) => { 10 | const fetchReqUrl = argumentsList[0]; 11 | let modify = false; 12 | 13 | if (fetchReqUrl.match('/backend-api/conversation(\\?|$)')) { 14 | var postInfo = argumentsList[1]; 15 | var postData = JSON.parse(postInfo.body); 16 | var userInput = postData.messages[0].content.parts[0]; 17 | const matchURL = function(text) { 18 | var pattern = /\[(https?):\/\/[^\s/$.?#].[^\s]*\]/gi; 19 | var result = text.match(pattern); 20 | 21 | return result; 22 | } 23 | 24 | var fetchUrlList = matchURL(userInput); 25 | if (fetchUrlList) { 26 | modify = true; 27 | window.addEventListener('message', function(event) { 28 | if (event.source === window) { 29 | let url = event.data['url']; 30 | let parseHTMLData = event.data['data']; 31 | let modify_userInput = postData.messages[0].content.parts[0]; 32 | let input_promote = ''; 33 | console.log('window.addEventListener',url,parseHTMLData); 34 | 35 | if (Object.entries(parseHTMLData).length) { // no data 36 | if (event.data.message === 'parsedHTML') { 37 | parseHTMLData = JSON.stringify(parseHTMLData); 38 | input_promote = `These Content is fetch from web page\n${parseHTMLData}\nUse the language that the user previously used or the language requested by the user.Respond to the user's request, which may include asking questions or requesting specific actions (such as translation, rewriting, etc.), based on the provided content.If the user does not make a request, perform the following tasks: 1. Display the title in the user's language; 2. Summarize the article content into a brief and easily understandable paragraph. For articles, follow this approach; for code, formulas, or content not suited for questioning, this step may be skipped.`; 39 | } else if (event.data.message === 'textData') { 40 | parseHTMLData = JSON.stringify({ 41 | 'content': parseHTMLData 42 | }); 43 | input_promote = `These Content is text data\n${parseHTMLData}\nUse the language that the user previously used or the language requested by the user.Respond to the user's request, which may include asking questions or requesting specific actions (such as translation, rewriting, etc.), based on the provided content.If the user does not make a request, perform the following tasks: 1. Display the title in the user's language; 2. Summarize the article content into a brief and easily understandable paragraph. For articles, follow this approach; for code, formulas, or content not suited for questioning, this step may be skipped.`; 44 | } else { // nothing 45 | 46 | } 47 | 48 | if (input_promote) { 49 | modify_userInput = modify_userInput.replace(url,input_promote); 50 | console.log('before:',argumentsList[1].body); 51 | console.log('change',input_promote); 52 | postData.messages[0].content.parts[0] = modify_userInput; 53 | argumentsList[1].body = JSON.stringify(postData); 54 | console.log('after:',argumentsList[1].body); 55 | } 56 | } 57 | 58 | // 赋值request 59 | fetchRsp = target.apply(thisArg, argumentsList); 60 | fetchRsp.then(response => { 61 | rs(response); 62 | }).catch(error => {rj(error)}); 63 | } 64 | }); 65 | 66 | window.postMessage({ message: 'fetchURL',fetchUrlList: fetchUrlList }, '*'); 67 | } 68 | } 69 | 70 | if (!modify) { 71 | fetchRsp = target.apply(thisArg, argumentsList); 72 | fetchRsp.then(response => { 73 | rs(response); 74 | }).catch(error => {rj(error)}); 75 | } 76 | }) 77 | } 78 | }); 79 | -------------------------------------------------------------------------------- /icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lcatro/FreeWebpilotInChatGPT35/0385800be21295b560d7c59ea3e73a167ea6fbee/icon.png -------------------------------------------------------------------------------- /image/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lcatro/FreeWebpilotInChatGPT35/0385800be21295b560d7c59ea3e73a167ea6fbee/image/1.png -------------------------------------------------------------------------------- /image/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lcatro/FreeWebpilotInChatGPT35/0385800be21295b560d7c59ea3e73a167ea6fbee/image/2.png -------------------------------------------------------------------------------- /image/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lcatro/FreeWebpilotInChatGPT35/0385800be21295b560d7c59ea3e73a167ea6fbee/image/3.png -------------------------------------------------------------------------------- /image/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lcatro/FreeWebpilotInChatGPT35/0385800be21295b560d7c59ea3e73a167ea6fbee/image/4.png -------------------------------------------------------------------------------- /image/5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lcatro/FreeWebpilotInChatGPT35/0385800be21295b560d7c59ea3e73a167ea6fbee/image/5.png -------------------------------------------------------------------------------- /image/install.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lcatro/FreeWebpilotInChatGPT35/0385800be21295b560d7c59ea3e73a167ea6fbee/image/install.png -------------------------------------------------------------------------------- /inject.js: -------------------------------------------------------------------------------- 1 | 2 | const parseTextFromBody = function(bodyHTML) { 3 | var hidden_div = document.createElement('div'); 4 | var cleanedHtmlCode = bodyHTML.replace(/||/gi, ''); 5 | hidden_div.innerHTML = cleanedHtmlCode; 6 | 7 | return filterChar(hidden_div.innerText); 8 | } 9 | 10 | const parseHTML = function(html) { 11 | const title_regex = /]*>(.*?)<\/title>/i; 12 | const title_match = html.match(title_regex); 13 | if (title_match && title_match.length >= 2) 14 | var title_value = title_match[1]; 15 | else 16 | var title_value = ''; 17 | 18 | const site_name_regex = /]*property=["']og:site_name["'][^>]*content=["'](.*?)["'][^>]*>/i; 19 | const site_match = html.match(title_regex); 20 | if (site_match && site_match.length >= 2) 21 | var site_name_value = site_match[1]; 22 | else 23 | var site_name_value = ''; 24 | 25 | const description_regex = /]*name=["']description["'][^>]*content=["'](.*?)["'][^>]*>/i; 26 | const description_match = html.match(description_regex); 27 | if (description_match && description_match.length >= 2) 28 | var description_value = description_match[1]; 29 | else 30 | var description_value = ''; 31 | 32 | const body_regex = /]*>([\s\S]*?)<\/body>/i; 33 | const body_match = html.match(body_regex); 34 | if (body_match && body_match.length >= 2) 35 | var body_value = parseTextFromBody(body_match[1]); 36 | else 37 | var body_value = ''; 38 | 39 | if (!title_value && !site_name_value && !description_value && !body_value) 40 | return {}; 41 | 42 | return { 43 | 'title': title_value, 44 | 'site_name': site_name_value, 45 | 'description': description_value, 46 | 'content': body_value 47 | }; 48 | } 49 | 50 | const filterChar = function(bodyText) { 51 | var result = bodyText.replace(/\\n/g, '').replace(/\\t/g, '').replace(/\n/g, '').replace(/\t/g, ''); 52 | 53 | return result; 54 | } 55 | 56 | window.addEventListener('message', function(event) { 57 | //console.log(event.data,'url',event.data['fetchUrlList']); 58 | if (event.source === window && event.data.message === 'fetchURL') { 59 | var url = event.data['fetchUrlList'][0]; 60 | 61 | if (url.startsWith("[") && url.endsWith("]")) 62 | url = url.slice(1, -1) // 去除中括号.. [https://www.baidu.com/] 63 | 64 | chrome.runtime.sendMessage({url: url },function(response) { 65 | //console.log(' sendMessage Return',response); 66 | if (response.length) { 67 | var webPageDetail = parseHTML(response); 68 | 69 | if (Object.entries(webPageDetail).length) { 70 | window.postMessage({ message: 'parsedHTML' ,data: webPageDetail,url:event.data['fetchUrlList'][0] }, event.origin); 71 | console.log(' WebPage Detail',webPageDetail); 72 | } else { 73 | window.postMessage({ message: 'textData' ,data: filterChar(response),url:event.data['fetchUrlList'][0] }, event.origin); 74 | console.log(' WebPage Text',response); 75 | } 76 | } else { 77 | window.postMessage({ message: 'nothing' ,data: '',url:event.data['fetchUrlList'][0] }, event.origin); 78 | console.log(' WebPage NoData'); 79 | } 80 | }) 81 | } 82 | }); 83 | 84 | function injectScript(file_path, tag) { 85 | var node = document.getElementsByTagName(tag)[0]; 86 | var script = document.createElement('script'); 87 | script.setAttribute('type', 'text/javascript'); 88 | script.setAttribute('src', file_path); 89 | node.appendChild(script); 90 | } 91 | 92 | injectScript(chrome.runtime.getURL('content.js'), 'body'); 93 | -------------------------------------------------------------------------------- /manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "manifest_version": 3, 3 | "name": "FreeWebpilotInGPT35", 4 | "version": "1.0", 5 | "permissions": [ 6 | "scripting", 7 | "webRequest" 8 | ], 9 | "host_permissions": [ 10 | "*://*/*" 11 | ], 12 | "background": { 13 | "service_worker": "background.js" 14 | }, 15 | "web_accessible_resources": [ 16 | { 17 | "resources": ["content.js"], 18 | "matches": ["https://chat.openai.com/*"] 19 | } 20 | ], 21 | "content_scripts": [ 22 | { 23 | "matches": ["https://chat.openai.com/*"], 24 | "js": ["inject.js"], 25 | "all_frames": true 26 | } 27 | ], 28 | "icons": { 29 | "16": "icon.png", 30 | "48": "icon.png", 31 | "128": "icon.png" 32 | } 33 | } -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | 2 | ## FreeWebpilotInGPT35 3 | 4 | FreeWebpilotInGPT35 要解决的问题是ChatGPT Web版非付费用户也可以使用访问外部数据导入到ChatGPT上下文处理,这个功能是在ChatGPT 4.0 + Plugin(Webpilot)版本才可以使用 5 | 6 | ## 效果 7 | 8 | ![image/1.png](image/1.png) 9 | 10 | ![image/2.png](image/2.png) 11 | 12 | ![image/3.png](image/3.png) 13 | 14 | ![image/4.png](image/4.png) 15 | 16 | ![image/5.png](image/5.png) 17 | 18 | ## 怎么安装 19 | 20 | ![image/install.png](image/install.png) 21 | 22 | 导入Chrome插件之后刷新ChatGPT对话界面即可,如果需要引入外部链接的数据,使用`[链接]`即可 23 | 24 | ## 后续 25 | 26 | ==> 引入谷歌搜索 27 | ==> 改Bug 28 | --------------------------------------------------------------------------------