mirror of
https://github.com/zhayujie/chatgpt-on-wechat.git
synced 2026-07-17 11:07:11 +08:00
feat(browser): reuse system Chrome/Edge, bundle playwright for desktop
This commit is contained in:
@@ -105,6 +105,14 @@ hiddenimports += collect_submodules('docx')
|
||||
hiddenimports += collect_submodules('pptx')
|
||||
hiddenimports += collect_submodules('openpyxl')
|
||||
|
||||
# Playwright powers the browser tool. Only the pure-Python package + its bundled
|
||||
# Node driver are shipped (~10-15MB); the ~150MB Chromium binary is NOT bundled
|
||||
# and is either satisfied by the user's system Chrome/Edge (preferred, zero
|
||||
# download) or downloaded on demand into ~/.cow/ms-playwright at first use.
|
||||
# Playwright imports its transport/driver lazily, so list submodules explicitly.
|
||||
hiddenimports += ['playwright', 'playwright.sync_api', 'playwright._impl']
|
||||
hiddenimports += collect_submodules('playwright')
|
||||
|
||||
# --- Data files -----------------------------------------------------------
|
||||
# Runtime-read files/dirs that must travel with the executable. Paths are
|
||||
# (source, dest_dir_in_bundle).
|
||||
@@ -134,6 +142,12 @@ datas += collect_data_files('tiktoken_ext', include_py_files=False)
|
||||
datas += collect_data_files('docx')
|
||||
datas += collect_data_files('pptx')
|
||||
|
||||
# Playwright ships its Node.js driver + package.json under playwright/driver/.
|
||||
# These are NOT Python modules, so hiddenimports won't pull them in — collect
|
||||
# them as data or `playwright install` / launching fails in the frozen build.
|
||||
# include_py_files=True is required: the driver dir contains .py entrypoints.
|
||||
datas += collect_data_files('playwright', include_py_files=True)
|
||||
|
||||
# --- Excludes -------------------------------------------------------------
|
||||
# Keep the bundle lean: drop Feishu's heavy SDK, plugins (disabled in desktop
|
||||
# mode), tests/docs, and dev-only packages.
|
||||
@@ -143,7 +157,10 @@ excludes = [
|
||||
'pip',
|
||||
'wheel',
|
||||
'pytest',
|
||||
'playwright', # browser tool is opt-in, not bundled
|
||||
# NOTE: playwright is now BUNDLED (pure-Python package + Node driver, ~10-15MB)
|
||||
# so the browser tool works out of the box on desktop. The heavy Chromium
|
||||
# binary is still NOT bundled: it comes from the user's system Chrome/Edge or
|
||||
# is downloaded on demand into ~/.cow/ms-playwright. See browser_env.py.
|
||||
]
|
||||
|
||||
block_cipher = None
|
||||
|
||||
@@ -42,6 +42,12 @@ python-docx
|
||||
openpyxl
|
||||
python-pptx
|
||||
|
||||
# ---- browser tool ----
|
||||
# Only the pure-Python package + Node driver are bundled by PyInstaller (~10-15MB).
|
||||
# The Chromium binary is NOT bundled: the browser tool drives the user's system
|
||||
# Chrome/Edge, or downloads Chromium on demand into ~/.cow at first use.
|
||||
playwright==1.52.0
|
||||
|
||||
# ---- IM channels (kept; lightweight). Feishu/lark-oapi intentionally excluded. ----
|
||||
wechatpy
|
||||
pycryptodome
|
||||
|
||||
@@ -53,6 +53,7 @@ const ChatInput = forwardRef<ChatInputHandle, ChatInputProps>(function ChatInput
|
||||
{ cmd: '/memory dream ', desc: t('slash_memory_dream') },
|
||||
{ cmd: '/knowledge', desc: t('slash_knowledge') },
|
||||
{ cmd: '/knowledge list', desc: t('slash_knowledge_list') },
|
||||
{ cmd: '/install-browser', desc: t('slash_install_browser') },
|
||||
{ cmd: '/config', desc: t('slash_config') },
|
||||
{ cmd: '/cancel', desc: t('slash_cancel') },
|
||||
{ cmd: '/logs', desc: t('slash_logs') },
|
||||
|
||||
@@ -30,6 +30,34 @@ const md: MarkdownIt = new MarkdownIt({
|
||||
},
|
||||
})
|
||||
|
||||
// Fix greedy linkify: markdown-it's linkify swallows markdown emphasis (`*`)
|
||||
// and CJK full-width punctuation glued to a URL (common in LLM output like
|
||||
// `**https://x**,中文`), turning the whole tail into one broken link. Cut the
|
||||
// URL at the first such char and spill the remainder back as plain text.
|
||||
const _GREEDY_LINK_CUT = /[*\u3000-\u303F\uFF00-\uFFEF]/
|
||||
md.core.ruler.after('linkify', 'fix_greedy_linkify', (state) => {
|
||||
for (const blk of state.tokens) {
|
||||
if (blk.type !== 'inline' || !blk.children) continue
|
||||
const ch = blk.children
|
||||
for (let i = 0; i < ch.length; i++) {
|
||||
const open = ch[i]
|
||||
if (open.type !== 'link_open' || open.markup !== 'linkify') continue
|
||||
const textTok = ch[i + 1]
|
||||
const close = ch[i + 2]
|
||||
if (!textTok || textTok.type !== 'text' || !close || close.type !== 'link_close') continue
|
||||
const idx = textTok.content.search(_GREEDY_LINK_CUT)
|
||||
if (idx < 0) continue
|
||||
const keep = textTok.content.slice(0, idx)
|
||||
const spill = textTok.content.slice(idx)
|
||||
textTok.content = keep
|
||||
open.attrSet('href', keep)
|
||||
const spillTok = new state.Token('text', '', 0)
|
||||
spillTok.content = spill
|
||||
ch.splice(i + 3, 0, spillTok)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// Open links in a new tab safely.
|
||||
const defaultLinkOpen =
|
||||
md.renderer.rules.link_open ||
|
||||
|
||||
@@ -376,6 +376,7 @@ const translations: Record<string, Record<string, string>> = {
|
||||
slash_memory_dream: '手动触发记忆蒸馏 (可指定天数, 默认3)',
|
||||
slash_knowledge: '查看知识库统计',
|
||||
slash_knowledge_list: '查看知识库文件树',
|
||||
slash_install_browser: '安装浏览器工具',
|
||||
slash_config: '查看当前配置',
|
||||
slash_cancel: '中止当前正在运行的 Agent 任务',
|
||||
slash_logs: '查看最近日志',
|
||||
@@ -758,6 +759,7 @@ const translations: Record<string, Record<string, string>> = {
|
||||
slash_memory_dream: 'Trigger memory distillation (optional days, default 3)',
|
||||
slash_knowledge: 'Show knowledge base stats',
|
||||
slash_knowledge_list: 'Show knowledge base file tree',
|
||||
slash_install_browser: 'Install browser tool',
|
||||
slash_config: 'Show current config',
|
||||
slash_cancel: 'Abort the running agent task',
|
||||
slash_logs: 'Show recent logs',
|
||||
|
||||
Reference in New Issue
Block a user