feat: summarize any page by right-click menu (#55, #62, #78)

This commit is contained in:
josc146
2023-03-25 20:48:59 +08:00
parent a65cba58d5
commit 57c95d64fc
4 changed files with 92 additions and 64 deletions
+49 -32
View File
@@ -16,7 +16,7 @@ import {
gptApiModelKeys,
} from '../config/index.mjs'
import { isSafari } from '../utils/is-safari'
import { isFirefox } from '../utils/is-firefox'
import { config as menuConfig } from '../content-script/menu-tools'
const KEY_ACCESS_TOKEN = 'accessToken'
const cache = new ExpiryMap(10 * 1000)
@@ -107,41 +107,58 @@ Browser.runtime.onMessage.addListener(async (message) => {
}
})
Browser.contextMenus.removeAll().then(() => {
const menuId = 'ChatGPTBox-Menu'
Browser.contextMenus.create({
id: menuId,
title: 'ChatGPTBox',
contexts: ['all'],
})
Browser.contextMenus.create({
id: menuId + 'new',
parentId: menuId,
title: 'New Chat',
contexts: [isFirefox() ? 'all' : 'selection'],
})
for (const index in defaultConfig.selectionTools) {
const key = defaultConfig.selectionTools[index]
const desc = defaultConfig.selectionToolsDesc[index]
function refreshMenu() {
Browser.contextMenus.removeAll().then(() => {
const menuId = 'ChatGPTBox-Menu'
Browser.contextMenus.create({
id: menuId + key,
parentId: menuId,
title: desc,
contexts: ['selection'],
id: menuId,
title: 'ChatGPTBox',
contexts: ['all'],
})
}
Browser.contextMenus.onClicked.addListener((info, tab) => {
const itemId = info.menuItemId === menuId ? 'new' : info.menuItemId.replace(menuId, '')
const message = {
itemId: itemId,
selectionText: info.selectionText,
for (const [k, v] of Object.entries(menuConfig)) {
Browser.contextMenus.create({
id: menuId + k,
parentId: menuId,
title: v.label,
contexts: ['all'],
})
}
console.debug('menu clicked', message)
Browser.tabs.sendMessage(tab.id, {
type: 'MENU',
data: message,
Browser.contextMenus.create({
id: menuId + 'separator1',
parentId: menuId,
contexts: ['selection'],
type: 'separator',
})
for (const index in defaultConfig.selectionTools) {
const key = defaultConfig.selectionTools[index]
const desc = defaultConfig.selectionToolsDesc[index]
Browser.contextMenus.create({
id: menuId + key,
parentId: menuId,
title: desc,
contexts: ['selection'],
})
}
Browser.contextMenus.onClicked.addListener((info, tab) => {
const message = {
itemId: info.menuItemId.replace(menuId, ''),
selectionText: info.selectionText,
}
console.debug('menu clicked', message)
Browser.tabs.sendMessage(tab.id, {
type: 'CREATE_MENU',
data: message,
})
})
})
}
Browser.runtime.onMessage.addListener(async (message) => {
if (message.type === 'REFRESH_MENU') {
refreshMenu()
}
})
refreshMenu()
+25 -30
View File
@@ -4,9 +4,11 @@ import { render } from 'preact'
import DecisionCard from '../components/DecisionCard'
import { config as siteConfig } from './site-adapters'
import { config as toolsConfig } from './selection-tools'
import { config as menuConfig } from './menu-tools'
import { clearOldAccessToken, getUserConfig, setAccessToken } from '../config/index.mjs'
import {
createElementAtPosition,
cropText,
getClientPosition,
getPossibleElementByQuerySelector,
initSession,
@@ -210,38 +212,31 @@ async function prepareForRightClickMenu() {
})
Browser.runtime.onMessage.addListener(async (message) => {
if (message.type === 'MENU') {
if (message.type === 'CREATE_MENU') {
const data = message.data
if (data.itemId === 'new') {
const position = { x: menuX, y: menuY }
const container = createElementAtPosition(position.x, position.y)
container.className = 'chatgptbox-toolbar-container-not-queryable'
render(
<FloatingToolbar
session={initSession()}
selection=""
container={container}
triggered={true}
closeable={true}
/>,
container,
let prompt = ''
if (data.itemId in toolsConfig)
prompt = await toolsConfig[data.itemId].genPrompt(data.selectionText)
else if (data.itemId in menuConfig)
prompt = cropText(
`Reply in ${await getPreferredLanguage()}.\n` +
(await menuConfig[data.itemId].genPrompt()),
)
} else {
const position = { x: menuX, y: menuY }
const container = createElementAtPosition(position.x, position.y)
container.className = 'chatgptbox-toolbar-container-not-queryable'
render(
<FloatingToolbar
session={initSession()}
selection={data.selectionText}
container={container}
triggered={true}
closeable={true}
prompt={await toolsConfig[data.itemId].genPrompt(data.selectionText)}
/>,
container,
)
}
const position = { x: menuX, y: menuY }
const container = createElementAtPosition(position.x, position.y)
container.className = 'chatgptbox-toolbar-container-not-queryable'
render(
<FloatingToolbar
session={initSession()}
selection={data.selectionText}
container={container}
triggered={true}
closeable={true}
prompt={prompt}
/>,
container,
)
}
})
}
+16
View File
@@ -0,0 +1,16 @@
import { getCoreContentText } from '../../utils/get-core-content-text'
export const config = {
newChat: {
label: 'New Chat',
genPrompt: async () => {
return ''
},
},
summarizePage: {
label: 'Summarize Page',
genPrompt: async () => {
return `The following is the text content of a web page, analyze the core content and summarize:\n${getCoreContentText()}`
},
},
}
+2 -2
View File
@@ -35,10 +35,10 @@ export function getCoreContentText() {
let ret
if (secondLargestElement && getArea(secondLargestElement) > 0.5 * getArea(largestElement)) {
ret = secondLargestElement.textContent
ret = secondLargestElement.innerText || secondLargestElement.textContent
console.log('use second')
} else {
ret = largestElement.textContent
ret = largestElement.innerText || largestElement.textContent
console.log('use first')
}
return ret.trim().replaceAll(' ', '').replaceAll('\n\n', '').replaceAll(',,', '')