[RFC] 091 - 联网搜索支持深度爬取 #6595
Replies: 5 comments 12 replies
-
话说触发深度爬取的策略是什么呢?搜索引擎得到的网页都会爬取吗 |
Beta Was this translation helpful? Give feedback.
-
赞!刚想到这一点准备提一个 feature request 就看见 RFC 了。 有一个建议,现在有两个预装插件,一个是 Artifacts 另一个是 Web Browsing。由于应用已经为网络搜索在快捷栏中设置了一级公民地位,是否考虑将 Web Browsing 这个插件在插件列表中隐藏掉? |
Beta Was this translation helpful? Give feedback.
-
这一层收集一些同类产品情况 |
Beta Was this translation helpful? Give feedback.
-
一个测试用例: query: 给我分析下 follow 的 electron 自动更新是怎么做的. 调用了 20 轮工具,耗费 1.2 美金,调研结果如下: 根据我收集的信息,现在我可以为你分析 Follow 应用的 Electron 自动更新实现机制。 Follow 应用的 Electron 自动更新机制分析Follow 是一个基于 Electron 的开源 RSS 阅读器应用,它实现了完善的自动更新机制。以下是其自动更新实现的详细分析: 1. 核心更新技术栈Follow 应用使用了以下核心技术来实现自动更新:
2. 更新架构设计Follow 应用的更新系统设计了两种更新方式:
这种设计使得轻量级的 UI 和功能更新可以通过热更新快速部署,而涉及到底层变更的更新则通过完整应用更新进行。 3. 更新检测和下载流程3.1 更新初始化在主进程文件 app.whenReady().then(async () => {
// ...其他初始化代码
registerUpdater()
// ...
}) 3.2 更新配置在 export const appUpdaterConfig = {
// 是否启用渲染层热更新
enableRenderHotUpdate: !isDev,
// 是否启用应用更新
enableAppUpdate: !isDev,
app: {
autoCheckUpdate: true,
autoDownloadUpdate: true,
checkUpdateInterval: 15 * 60 * 1000, // 15分钟检查一次更新
},
} 3.3 更新器注册在
export const registerUpdater = async () => {
if (disabled) {
return
}
// 禁用自动下载,通过事件控制
autoUpdater.autoDownload = false
autoUpdater.allowPrerelease = channel !== "stable"
autoUpdater.autoInstallOnAppQuit = true
autoUpdater.autoRunAppAfterInstall = true
// 设置更新源
const feedUrl = {
channel,
provider: "custom" as "github",
repo: GITHUB_REPO,
owner: GITHUB_OWNER,
releaseType: channel === "stable" ? "release" : "prerelease",
updateProvider: CustomGitHubProvider,
}
autoUpdater.setFeedURL(feedUrl)
// 注册更新事件
autoUpdater.on("checking-for-update", () => {
logger.info("Checking for update")
})
autoUpdater.on("update-available", async (info) => {
// 先尝试渲染层热更新
if (appUpdaterConfig.enableRenderHotUpdate) {
const isRenderUpgraded = await upgradeRenderIfNeeded()
if (isRenderUpgraded) {
return
}
}
// 如果配置了自动下载,则下载更新
if (appUpdaterConfig.app.autoDownloadUpdate) {
downloadAppUpdate()
}
})
// 其他事件处理...
// 设置定期检查更新
setInterval(() => {
if (appUpdaterConfig.app.autoCheckUpdate) {
checkForAppUpdates()
}
}, appUpdaterConfig.app.checkUpdateInterval)
} 4. 自定义 GitHub ProviderFollow 应用实现了自定义的 GitHub Provider (
5. 渲染层热更新机制在
热更新的判断逻辑: export const canUpdateRender = async (): Promise<[CanUpdateRenderState, Manifest | null]> => {
const manifest = await getLatestReleaseManifest()
// 检查应用是否支持该版本的渲染层
const appSupport = mainHash === manifest.mainHash
if (!appSupport) {
return [CanUpdateRenderState.APP_NOT_SUPPORT, null]
}
// 检查版本是否相同
const isVersionEqual = appVersion === manifest.version
if (isVersionEqual) {
return [CanUpdateRenderState.NO_NEEDED, null]
}
// 检查提交是否相同
const isCommitEqual = GIT_COMMIT_HASH === manifest.commit
if (isCommitEqual) {
return [CanUpdateRenderState.NO_NEEDED, null]
}
// 需要更新
return [CanUpdateRenderState.NEEDED, manifest]
} 6. 版本更新策略Follow 应用使用语义化版本号来控制更新策略:
export const shouldUpdateApp = (currentVersion: string, nextVersion: string) => {
if (nextVersion.includes("app")) {
return true
}
// x.y.z 的 x 或 y 不同,需要更新应用
const [x1, x2] = [safeMajor(currentVersion), safeMajor(nextVersion)]
const [y1, y2] = [safeMinor(currentVersion), safeMinor(nextVersion)]
if (x1 !== x2 || y1 !== y2) {
return true
}
return false
} 7. 更新安装流程当更新下载完成后,Follow 应用会通知用户并提供安装选项: autoUpdater.on("update-downloaded", () => {
downloading = false
logger.info("Update downloaded, ready to install")
const mainWindow = getMainWindow()
if (!mainWindow) return
const handlers = getRendererHandlers<RendererHandlers>(mainWindow.webContents)
// 通知渲染进程更新已下载
handlers.updateDownloaded.send()
}) 用户确认后,调用 export const quitAndInstall = () => {
const mainWindow = getMainWindow()
destroyMainWindow()
logger.info("Quit and install update, close main window, ", mainWindow?.id)
setTimeout(() => {
logger.info("Window is closed, quit and install update")
autoUpdater.quitAndInstall()
}, 1000)
} 8. 发布配置Follow 应用使用 electron-forge 进行构建和发布,在
总结Follow 应用的 Electron 自动更新机制具有以下特点:
这种设计使得 Follow 应用能够灵活高效地进行更新,既保证了用户体验,又提高了开发和部署效率。 |
Beta Was this translation helpful? Give feedback.
-
我看Dify对接的是https://www.firecrawl.dev/ ,也是自己部署社区版或用官方的实例。 |
Beta Was this translation helpful? Give feedback.
-
背景
自 #6447 上线以来,大家对于搜索功能提出了诸多新的期待,本 RFC 将实现其中一个提到次数极多的需求:网页内容抓取。
早在两年前,我就做了 LobeChat 当时的第 3 个插件:网页爬虫。这个插件虽然我们很少宣传,其貌不扬,但是在我长达近 2 年的日用过程中保持了非常好的稳定性与使用体验,因此本 RFC 将会把该插件的核心实现思路预置进应用本体中,通过进一步的优化来提升抓取成功率和抓取性能。
爬虫插件的核心思路很简单,就 2 步:
但中间其实有一些开发的门槛。
获取网页 html
比如获取网页 html 这个事情虽然听起来很简单,但是目前市面上存在的网页很多是 SPA 的,都没法正常获取到 html 内容。以及有些网站是用了 Cloudflare 做了反爬保护,因此工程实现上难度还是有的。
而我当年的实现思路非常简单粗暴,通过服务端起一个 puppeteer 实例仿真一个浏览器环境,这样所有的 SPA 都能正常读取到,能解决 90% 以上的问题(Cloudflare墙的问题就忽略了,这个应该无解)。而服务端 puppeteer 实例有非常专业的解决方案就是 browserless 。当年做完那个插件以后在我的 2c8g 机器上启动了 browserless 镜像,到现在都没出现过任何问题,很稳定地供整个 LobeChat 社区免费使用到现在
但这个方案存在的问题就是整个请求速度会较慢,因为走 puppeteer 启动页面可能就要1 ~ 2秒,然后等页面资源完全加载完毕(确保 spa 下页面能完全显示出来)也有 1 ~ 10 秒不等,因此本次实现会做一轮优化升级。补充一个性能更加的 naive 获取方案。
html 转 markdown
这里用的库是 Readability, 可以智能地识别到页面中的关键元素,尽量减少干扰的 html 元素。然后利用
node-html-markdown
库就可以轻松完成 html 到 markdown 的解析转换。但在过去的使用中我发现这个方案也存在一些问题,比如某些网站 Readability 可能无法正常识别准( 比较典型的是 github 的代码文件页面),需要中间做一些工程转换。
社区优秀读取器方案集成
此外,还有需要搞的一个事情是例如 jina 提供了
https://r.jina.ai/
这样开箱即用的免费读取器,我也希望在 LobeChat 中有效利用起来。设计思路
综合上述要点,本 RFC 的设计思路关键包含以下部分:
multi crawl impl 模式
通过实现不同的 crawl impl (Implement),来集不同抓取实现的优势,目前准备实现的模式有:
然后通过定义 crawl 的调度顺序,即可顺序式地进行页面抓取。本次实现的抓取顺序为
['naive','jina','browserless']
,未来也会允许用户进行自定义配置。如果社区中更多更好的 craw 实现也欢迎提出和贡献。
URL 转换规则
针对类似 github 文件页面的场景,比较合适的是提供一种 url 转换的功能,例如原始链接为
https://github.com/lobehub/chat-plugin-web-crawler/blob/main/api/v1/_utils.ts
,通过访问https://github.com/lobehub/chat-plugin-web-crawler/raw/refs/heads/main/api/v1/_utils.ts
即可看到源代码。因此内置一些网站的转换解析规则,即可大大提升这类页面的解析效果。https://github.com/$org/$repo/blob/$branch
->https://github.com/$org/$repo/raw/refs/heads/$branch
此类规则比较适合遇到后一起进行完善。
智能过滤开关
Readability 的实现其实是做了一层页面元素的智能过滤,但是某些场景下这个解析又会造成关键页面的内容丢失,例如 https://www.qiumiwu.com/standings/yingchao 这个页面的解析就有问题,如果回退到全 html 解析则正常。因此还是需要一个规则配置用于做开关控制。
实施进展
Beta Was this translation helpful? Give feedback.
All reactions