@lobehub/chat 1.68.0 → 1.68.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +50 -0
- package/README.md +4 -4
- package/README.zh-CN.md +5 -4
- package/changelog/v1.json +18 -0
- package/package.json +1 -1
- package/packages/web-crawler/README.md +47 -20
- package/packages/web-crawler/README.zh-CN.md +61 -0
- package/packages/web-crawler/src/__test__/crawler.test.ts +6 -3
- package/packages/web-crawler/src/crawler.ts +8 -3
- package/packages/web-crawler/src/type.ts +2 -3
- package/packages/web-crawler/src/urlRules.ts +5 -0
- package/src/config/aiModels/wenxin.ts +32 -0
- package/src/libs/agent-runtime/hunyuan/index.test.ts +137 -2
- package/src/libs/agent-runtime/hunyuan/index.ts +4 -3
- package/src/libs/agent-runtime/qwen/index.ts +1 -1
- package/src/libs/agent-runtime/utils/streams/openai.ts +29 -13
- package/src/libs/agent-runtime/utils/streams/protocol.ts +3 -2
- package/src/libs/agent-runtime/wenxin/index.test.ts +113 -0
- package/src/libs/agent-runtime/wenxin/index.ts +17 -0
- package/src/tools/web-browsing/Portal/PageContent/index.tsx +37 -2
- package/src/tools/web-browsing/Render/PageContent/Result.tsx +36 -3
- package/src/tools/web-browsing/Render/PageContent/index.tsx +11 -1
- package/src/types/tool/crawler.ts +2 -2
package/CHANGELOG.md
CHANGED
@@ -2,6 +2,56 @@
|
|
2
2
|
|
3
3
|
# Changelog
|
4
4
|
|
5
|
+
### [Version 1.68.2](https://github.com/lobehub/lobe-chat/compare/v1.68.1...v1.68.2)
|
6
|
+
|
7
|
+
<sup>Released on **2025-03-03**</sup>
|
8
|
+
|
9
|
+
#### 💄 Styles
|
10
|
+
|
11
|
+
- **misc**: Add build-in web search support for Wenxin & Hunyuan.
|
12
|
+
|
13
|
+
<br/>
|
14
|
+
|
15
|
+
<details>
|
16
|
+
<summary><kbd>Improvements and Fixes</kbd></summary>
|
17
|
+
|
18
|
+
#### Styles
|
19
|
+
|
20
|
+
- **misc**: Add build-in web search support for Wenxin & Hunyuan, closes [#6617](https://github.com/lobehub/lobe-chat/issues/6617) ([dfd1f09](https://github.com/lobehub/lobe-chat/commit/dfd1f09))
|
21
|
+
|
22
|
+
</details>
|
23
|
+
|
24
|
+
<div align="right">
|
25
|
+
|
26
|
+
[](#readme-top)
|
27
|
+
|
28
|
+
</div>
|
29
|
+
|
30
|
+
### [Version 1.68.1](https://github.com/lobehub/lobe-chat/compare/v1.68.0...v1.68.1)
|
31
|
+
|
32
|
+
<sup>Released on **2025-03-03**</sup>
|
33
|
+
|
34
|
+
#### 🐛 Bug Fixes
|
35
|
+
|
36
|
+
- **misc**: Fix page crash with crawler error.
|
37
|
+
|
38
|
+
<br/>
|
39
|
+
|
40
|
+
<details>
|
41
|
+
<summary><kbd>Improvements and Fixes</kbd></summary>
|
42
|
+
|
43
|
+
#### What's fixed
|
44
|
+
|
45
|
+
- **misc**: Fix page crash with crawler error, closes [#6662](https://github.com/lobehub/lobe-chat/issues/6662) ([0c24251](https://github.com/lobehub/lobe-chat/commit/0c24251))
|
46
|
+
|
47
|
+
</details>
|
48
|
+
|
49
|
+
<div align="right">
|
50
|
+
|
51
|
+
[](#readme-top)
|
52
|
+
|
53
|
+
</div>
|
54
|
+
|
5
55
|
## [Version 1.68.0](https://github.com/lobehub/lobe-chat/compare/v1.67.2...v1.68.0)
|
6
56
|
|
7
57
|
<sup>Released on **2025-03-03**</sup>
|
package/README.md
CHANGED
@@ -191,14 +191,14 @@ We have implemented support for the following model service providers:
|
|
191
191
|
- **[Bedrock](https://lobechat.com/discover/provider/bedrock)**: Bedrock is a service provided by Amazon AWS, focusing on delivering advanced AI language and visual models for enterprises. Its model family includes Anthropic's Claude series, Meta's Llama 3.1 series, and more, offering a range of options from lightweight to high-performance, supporting tasks such as text generation, conversation, and image processing for businesses of varying scales and needs.
|
192
192
|
- **[Google](https://lobechat.com/discover/provider/google)**: Google's Gemini series represents its most advanced, versatile AI models, developed by Google DeepMind, designed for multimodal capabilities, supporting seamless understanding and processing of text, code, images, audio, and video. Suitable for various environments from data centers to mobile devices, it significantly enhances the efficiency and applicability of AI models.
|
193
193
|
- **[DeepSeek](https://lobechat.com/discover/provider/deepseek)**: DeepSeek is a company focused on AI technology research and application, with its latest model DeepSeek-V2.5 integrating general dialogue and code processing capabilities, achieving significant improvements in human preference alignment, writing tasks, and instruction following.
|
194
|
+
- **[PPIO](https://lobechat.com/discover/provider/ppio)**: PPIO supports stable and cost-efficient open-source LLM APIs, such as DeepSeek, Llama, Qwen etc.
|
194
195
|
- **[HuggingFace](https://lobechat.com/discover/provider/huggingface)**: The HuggingFace Inference API provides a fast and free way for you to explore thousands of models for various tasks. Whether you are prototyping for a new application or experimenting with the capabilities of machine learning, this API gives you instant access to high-performance models across multiple domains.
|
195
196
|
- **[OpenRouter](https://lobechat.com/discover/provider/openrouter)**: OpenRouter is a service platform providing access to various cutting-edge large model interfaces, supporting OpenAI, Anthropic, LLaMA, and more, suitable for diverse development and application needs. Users can flexibly choose the optimal model and pricing based on their requirements, enhancing the AI experience.
|
196
197
|
- **[Cloudflare Workers AI](https://lobechat.com/discover/provider/cloudflare)**: Run serverless GPU-powered machine learning models on Cloudflare's global network.
|
197
|
-
- **[GitHub](https://lobechat.com/discover/provider/github)**: With GitHub Models, developers can become AI engineers and leverage the industry's leading AI models.
|
198
198
|
|
199
|
-
<details><summary><kbd>See more providers (+
|
199
|
+
<details><summary><kbd>See more providers (+27)</kbd></summary>
|
200
200
|
|
201
|
-
- **[
|
201
|
+
- **[GitHub](https://lobechat.com/discover/provider/github)**: With GitHub Models, developers can become AI engineers and leverage the industry's leading AI models.
|
202
202
|
- **[Novita](https://lobechat.com/discover/provider/novita)**: Novita AI is a platform providing a variety of large language models and AI image generation API services, flexible, reliable, and cost-effective. It supports the latest open-source models like Llama3 and Mistral, offering a comprehensive, user-friendly, and auto-scaling API solution for generative AI application development, suitable for the rapid growth of AI startups.
|
203
203
|
- **[Together AI](https://lobechat.com/discover/provider/togetherai)**: Together AI is dedicated to achieving leading performance through innovative AI models, offering extensive customization capabilities, including rapid scaling support and intuitive deployment processes to meet various enterprise needs.
|
204
204
|
- **[Fireworks AI](https://lobechat.com/discover/provider/fireworksai)**: Fireworks AI is a leading provider of advanced language model services, focusing on functional calling and multimodal processing. Its latest model, Firefunction V2, is based on Llama-3, optimized for function calling, conversation, and instruction following. The visual language model FireLLaVA-13B supports mixed input of images and text. Other notable models include the Llama series and Mixtral series, providing efficient multilingual instruction following and generation support.
|
@@ -228,7 +228,7 @@ We have implemented support for the following model service providers:
|
|
228
228
|
|
229
229
|
</details>
|
230
230
|
|
231
|
-
> 📊 Total providers: [<kbd>**
|
231
|
+
> 📊 Total providers: [<kbd>**37**</kbd>](https://lobechat.com/discover/providers)
|
232
232
|
|
233
233
|
<!-- PROVIDER LIST -->
|
234
234
|
|
package/README.zh-CN.md
CHANGED
@@ -191,13 +191,14 @@ LobeChat 支持文件上传与知识库功能,你可以上传文件、图片
|
|
191
191
|
- **[Bedrock](https://lobechat.com/discover/provider/bedrock)**: Bedrock 是亚马逊 AWS 提供的一项服务,专注于为企业提供先进的 AI 语言模型和视觉模型。其模型家族包括 Anthropic 的 Claude 系列、Meta 的 Llama 3.1 系列等,涵盖从轻量级到高性能的多种选择,支持文本生成、对话、图像处理等多种任务,适用于不同规模和需求的企业应用。
|
192
192
|
- **[Google](https://lobechat.com/discover/provider/google)**: Google 的 Gemini 系列是其最先进、通用的 AI 模型,由 Google DeepMind 打造,专为多模态设计,支持文本、代码、图像、音频和视频的无缝理解与处理。适用于从数据中心到移动设备的多种环境,极大提升了 AI 模型的效率与应用广泛性。
|
193
193
|
- **[DeepSeek](https://lobechat.com/discover/provider/deepseek)**: DeepSeek 是一家专注于人工智能技术研究和应用的公司,其最新模型 DeepSeek-V3 多项评测成绩超越 Qwen2.5-72B 和 Llama-3.1-405B 等开源模型,性能对齐领军闭源模型 GPT-4o 与 Claude-3.5-Sonnet。
|
194
|
+
- **[PPIO](https://lobechat.com/discover/provider/ppio)**: PPIO 派欧云提供稳定、高性价比的开源模型 API 服务,支持 DeepSeek 全系列、Llama、Qwen 等行业领先大模型。
|
194
195
|
- **[HuggingFace](https://lobechat.com/discover/provider/huggingface)**: HuggingFace Inference API 提供了一种快速且免费的方式,让您可以探索成千上万种模型,适用于各种任务。无论您是在为新应用程序进行原型设计,还是在尝试机器学习的功能,这个 API 都能让您即时访问多个领域的高性能模型。
|
195
196
|
- **[OpenRouter](https://lobechat.com/discover/provider/openrouter)**: OpenRouter 是一个提供多种前沿大模型接口的服务平台,支持 OpenAI、Anthropic、LLaMA 及更多,适合多样化的开发和应用需求。用户可根据自身需求灵活选择最优的模型和价格,助力 AI 体验的提升。
|
196
197
|
- **[Cloudflare Workers AI](https://lobechat.com/discover/provider/cloudflare)**: 在 Cloudflare 的全球网络上运行由无服务器 GPU 驱动的机器学习模型。
|
197
|
-
- **[GitHub](https://lobechat.com/discover/provider/github)**: 通过 GitHub 模型,开发人员可以成为 AI 工程师,并使用行业领先的 AI 模型进行构建。
|
198
198
|
|
199
|
-
<details><summary><kbd>See more providers (+
|
200
|
-
|
199
|
+
<details><summary><kbd>See more providers (+27)</kbd></summary>
|
200
|
+
|
201
|
+
- **[GitHub](https://lobechat.com/discover/provider/github)**: 通过 GitHub 模型,开发人员可以成为 AI 工程师,并使用行业领先的 AI 模型进行构建。
|
201
202
|
- **[Novita](https://lobechat.com/discover/provider/novita)**: Novita AI 是一个提供多种大语言模型与 AI 图像生成的 API 服务的平台,灵活、可靠且具有成本效益。它支持 Llama3、Mistral 等最新的开源模型,并为生成式 AI 应用开发提供了全面、用户友好且自动扩展的 API 解决方案,适合 AI 初创公司的快速发展。
|
202
203
|
- **[Together AI](https://lobechat.com/discover/provider/togetherai)**: Together AI 致力于通过创新的 AI 模型实现领先的性能,提供广泛的自定义能力,包括快速扩展支持和直观的部署流程,满足企业的各种需求。
|
203
204
|
- **[Fireworks AI](https://lobechat.com/discover/provider/fireworksai)**: Fireworks AI 是一家领先的高级语言模型服务商,专注于功能调用和多模态处理。其最新模型 Firefunction V2 基于 Llama-3,优化用于函数调用、对话及指令跟随。视觉语言模型 FireLLaVA-13B 支持图像和文本混合输入。其他 notable 模型包括 Llama 系列和 Mixtral 系列,提供高效的多语言指令跟随与生成支持。
|
@@ -227,7 +228,7 @@ LobeChat 支持文件上传与知识库功能,你可以上传文件、图片
|
|
227
228
|
|
228
229
|
</details>
|
229
230
|
|
230
|
-
> 📊 Total providers: [<kbd>**
|
231
|
+
> 📊 Total providers: [<kbd>**37**</kbd>](https://lobechat.com/discover/providers)
|
231
232
|
|
232
233
|
<!-- PROVIDER LIST -->
|
233
234
|
|
package/changelog/v1.json
CHANGED
@@ -1,4 +1,22 @@
|
|
1
1
|
[
|
2
|
+
{
|
3
|
+
"children": {
|
4
|
+
"improvements": [
|
5
|
+
"Add build-in web search support for Wenxin & Hunyuan."
|
6
|
+
]
|
7
|
+
},
|
8
|
+
"date": "2025-03-03",
|
9
|
+
"version": "1.68.2"
|
10
|
+
},
|
11
|
+
{
|
12
|
+
"children": {
|
13
|
+
"fixes": [
|
14
|
+
"Fix page crash with crawler error."
|
15
|
+
]
|
16
|
+
},
|
17
|
+
"date": "2025-03-03",
|
18
|
+
"version": "1.68.1"
|
19
|
+
},
|
2
20
|
{
|
3
21
|
"children": {
|
4
22
|
"features": [
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@lobehub/chat",
|
3
|
-
"version": "1.68.
|
3
|
+
"version": "1.68.2",
|
4
4
|
"description": "Lobe Chat - an open-source, high-performance chatbot framework that supports speech synthesis, multimodal, and extensible Function Call plugin system. Supports one-click free deployment of your private ChatGPT/LLM web application.",
|
5
5
|
"keywords": [
|
6
6
|
"framework",
|
@@ -1,34 +1,61 @@
|
|
1
1
|
# @lobechat/web-crawler
|
2
2
|
|
3
|
-
LobeChat
|
3
|
+
LobeChat's built-in web crawling module for intelligent extraction of web content and conversion to Markdown format.
|
4
4
|
|
5
|
-
## 📝
|
5
|
+
## 📝 Introduction
|
6
6
|
|
7
|
-
`@lobechat/web-crawler`
|
7
|
+
`@lobechat/web-crawler` is a core component of LobeChat responsible for intelligent web content crawling and processing. It extracts valuable content from various webpages, filters out distracting elements, and generates structured Markdown text.
|
8
8
|
|
9
|
-
##
|
9
|
+
## 🛠️ Core Features
|
10
10
|
|
11
|
-
-
|
12
|
-
-
|
13
|
-
-
|
14
|
-
- **Markdown 转换**:将提取的 HTML 内容转换为易于 AI 处理的 Markdown 格式
|
11
|
+
- **Intelligent Content Extraction**: Identifies main content based on Mozilla Readability algorithm
|
12
|
+
- **Multi-level Crawling Strategy**: Supports multiple crawling implementations including basic crawling, Jina, and Browserless rendering
|
13
|
+
- **Custom URL Rules**: Handles specific website crawling logic through a flexible rule system
|
15
14
|
|
16
|
-
##
|
15
|
+
## 🤝 Contribution
|
17
16
|
|
18
|
-
|
17
|
+
Web structures are diverse and complex. We welcome community contributions for specific website crawling rules. You can participate in improvements through:
|
19
18
|
|
20
|
-
|
21
|
-
- **happy-dom**:轻量级的服务端 DOM 实现
|
22
|
-
- **node-html-markdown**:高效的 HTML 到 Markdown 转换工具
|
19
|
+
### How to Contribute URL Rules
|
23
20
|
|
24
|
-
|
21
|
+
1. Add new rules to the [urlRules.ts](https://github.com/lobehub/lobe-chat/blob/main/packages/web-crawler/src/urlRules.ts) file
|
22
|
+
2. Rule example:
|
25
23
|
|
26
|
-
|
24
|
+
```typescript
|
25
|
+
// Example: handling specific websites
|
26
|
+
const url = [
|
27
|
+
// ... other URL matching rules
|
28
|
+
{
|
29
|
+
// URL matching pattern, supports regex
|
30
|
+
urlPattern: 'https://example.com/articles/(.*)',
|
27
31
|
|
28
|
-
|
29
|
-
|
30
|
-
3. 提出针对性的算法或配置调整建议
|
32
|
+
// Optional: URL transformation, redirects to an easier-to-crawl version
|
33
|
+
urlTransform: 'https://example.com/print/$1',
|
31
34
|
|
32
|
-
|
35
|
+
// Optional: specify crawling implementation, supports 'naive', 'jina', and 'browserless'
|
36
|
+
impls: ['naive', 'jina', 'browserless'],
|
33
37
|
|
34
|
-
|
38
|
+
// Optional: content filtering configuration
|
39
|
+
filterOptions: {
|
40
|
+
// Whether to enable Readability algorithm for filtering distracting elements
|
41
|
+
enableReadability: true,
|
42
|
+
// Whether to convert to plain text
|
43
|
+
pureText: false,
|
44
|
+
},
|
45
|
+
},
|
46
|
+
];
|
47
|
+
```
|
48
|
+
|
49
|
+
### Rule Submission Process
|
50
|
+
|
51
|
+
1. Fork the [LobeChat repository](https://github.com/lobehub/lobe-chat)
|
52
|
+
2. Add or modify URL rules
|
53
|
+
3. Submit a Pull Request describing:
|
54
|
+
|
55
|
+
- Target website characteristics
|
56
|
+
- Problems solved by the rule
|
57
|
+
- Test cases (example URLs)
|
58
|
+
|
59
|
+
## 📌 Note
|
60
|
+
|
61
|
+
This is an internal module of LobeHub (`"private": true`), designed specifically for LobeChat and not published as a standalone package.
|
@@ -0,0 +1,61 @@
|
|
1
|
+
# @lobechat/web-crawler
|
2
|
+
|
3
|
+
LobeChat 内置的网页抓取模块,用于智能提取网页内容并转换为 Markdown 格式。
|
4
|
+
|
5
|
+
## 📝 简介
|
6
|
+
|
7
|
+
`@lobechat/web-crawler` 是 LobeChat 的核心组件,负责网页内容的智能抓取与处理。它能够从各类网页中提取有价值的内容,过滤掉干扰元素,并生成结构化的 Markdown 文本。
|
8
|
+
|
9
|
+
## 🛠️ 核心功能
|
10
|
+
|
11
|
+
- **智能内容提取**:基于 Mozilla Readability 算法识别主要内容
|
12
|
+
- **多级抓取策略**:支持多种抓取实现,包括基础抓取、Jina 和 Browserless 渲染抓取
|
13
|
+
- **自定义 URL 规则**:通过灵活的规则系统处理特定网站的抓取逻辑
|
14
|
+
|
15
|
+
## 🤝 参与共建
|
16
|
+
|
17
|
+
网页结构多样复杂,我们欢迎社区贡献特定网站的抓取规则。您可以通过以下方式参与改进:
|
18
|
+
|
19
|
+
### 如何贡献 URL 规则
|
20
|
+
|
21
|
+
1. 在 [urlRules.ts](https://github.com/lobehub/lobe-chat/blob/main/packages/web-crawler/src/urlRules.ts) 文件中添加新规则
|
22
|
+
2. 规则示例:
|
23
|
+
|
24
|
+
```typescript
|
25
|
+
// 示例:处理特定网站
|
26
|
+
const url = [
|
27
|
+
// ... 其他 url 匹配规则
|
28
|
+
{
|
29
|
+
// URL 匹配模式,仅支持正则表达式
|
30
|
+
urlPattern: 'https://example.com/articles/(.*)',
|
31
|
+
|
32
|
+
// 可选:URL 转换,用于重定向到更易抓取的版本
|
33
|
+
urlTransform: 'https://example.com/print/$1',
|
34
|
+
|
35
|
+
// 可选:指定抓取实现方式,支持 'naive'、'jina' 和 'browserless' 三种
|
36
|
+
impls: ['naive', 'jina', 'browserless'],
|
37
|
+
|
38
|
+
// 可选:内容过滤配置
|
39
|
+
filterOptions: {
|
40
|
+
// 是否启用 Readability 算法,用于过滤干扰元素
|
41
|
+
enableReadability: true,
|
42
|
+
// 是否转换为纯文本
|
43
|
+
pureText: false,
|
44
|
+
},
|
45
|
+
},
|
46
|
+
];
|
47
|
+
```
|
48
|
+
|
49
|
+
### 规则提交流程
|
50
|
+
|
51
|
+
1. Fork [LobeChat 仓库](https://github.com/lobehub/lobe-chat)
|
52
|
+
2. 添加或修改 URL 规则
|
53
|
+
3. 提交 Pull Request 并描述:
|
54
|
+
|
55
|
+
- 目标网站特点
|
56
|
+
- 规则解决的问题
|
57
|
+
- 测试用例(示例 URL)
|
58
|
+
|
59
|
+
## 📌 注意事项
|
60
|
+
|
61
|
+
这是 LobeHub 的内部模块(`"private": true`),专为 LobeChat 设计,不作为独立包发布使用。
|
@@ -80,9 +80,12 @@ describe('Crawler', () => {
|
|
80
80
|
});
|
81
81
|
|
82
82
|
expect(result).toEqual({
|
83
|
-
|
84
|
-
|
85
|
-
|
83
|
+
crawler: 'browserless',
|
84
|
+
data: {
|
85
|
+
content: 'Fail to crawl the page. Error type: CrawlError, error message: Crawl failed',
|
86
|
+
errorMessage: 'Crawl failed',
|
87
|
+
errorType: 'CrawlError',
|
88
|
+
},
|
86
89
|
originalUrl: 'https://example.com',
|
87
90
|
transformedUrl: undefined,
|
88
91
|
});
|
@@ -32,6 +32,7 @@ export class Crawler {
|
|
32
32
|
...userFilterOptions,
|
33
33
|
};
|
34
34
|
|
35
|
+
let finalCrawler: string | undefined;
|
35
36
|
let finalError: Error | undefined;
|
36
37
|
|
37
38
|
const systemImpls = (ruleImpls ?? this.impls) as CrawlImplType[];
|
@@ -55,6 +56,7 @@ export class Crawler {
|
|
55
56
|
} catch (error) {
|
56
57
|
console.error(error);
|
57
58
|
finalError = error as Error;
|
59
|
+
finalCrawler = impl;
|
58
60
|
}
|
59
61
|
}
|
60
62
|
|
@@ -62,9 +64,12 @@ export class Crawler {
|
|
62
64
|
const errorMessage = finalError?.message;
|
63
65
|
|
64
66
|
return {
|
65
|
-
|
66
|
-
|
67
|
-
|
67
|
+
crawler: finalCrawler,
|
68
|
+
data: {
|
69
|
+
content: `Fail to crawl the page. Error type: ${errorType}, error message: ${errorMessage}`,
|
70
|
+
errorMessage: errorMessage,
|
71
|
+
errorType,
|
72
|
+
},
|
68
73
|
originalUrl: url,
|
69
74
|
transformedUrl: transformedUrl !== url ? transformedUrl : undefined,
|
70
75
|
};
|
@@ -11,6 +11,7 @@ export interface CrawlSuccessResult {
|
|
11
11
|
export interface CrawlErrorResult {
|
12
12
|
content: string;
|
13
13
|
errorMessage: string;
|
14
|
+
errorType: string;
|
14
15
|
url: string;
|
15
16
|
}
|
16
17
|
|
@@ -36,9 +37,7 @@ export interface CrawlUrlRule {
|
|
36
37
|
// 内容过滤配置(可选)
|
37
38
|
filterOptions?: FilterOptions;
|
38
39
|
impls?: CrawlImplType[];
|
39
|
-
//
|
40
|
-
isRegex?: boolean;
|
41
|
-
// URL匹配模式,支持glob模式或正则表达式
|
40
|
+
// URL匹配模式,仅支持正则表达式
|
42
41
|
urlPattern: string;
|
43
42
|
// URL转换模板(可选),如果提供则进行URL转换
|
44
43
|
urlTransform?: string;
|
@@ -22,6 +22,11 @@ export const crawUrlRules: CrawlUrlRule[] = [
|
|
22
22
|
impls: ['jina'],
|
23
23
|
urlPattern: 'https://(.*).pdf',
|
24
24
|
},
|
25
|
+
// arxiv PDF use jina
|
26
|
+
{
|
27
|
+
impls: ['jina'],
|
28
|
+
urlPattern: 'https://arxiv.org/pdf/(.*)',
|
29
|
+
},
|
25
30
|
// 知乎有爬虫防护,使用 jina
|
26
31
|
{
|
27
32
|
impls: ['jina'],
|
@@ -4,6 +4,7 @@ const wenxinChatModels: AIChatModelCard[] = [
|
|
4
4
|
{
|
5
5
|
abilities: {
|
6
6
|
functionCall: true,
|
7
|
+
search: true,
|
7
8
|
},
|
8
9
|
contextWindowTokens: 8192,
|
9
10
|
description:
|
@@ -16,11 +17,15 @@ const wenxinChatModels: AIChatModelCard[] = [
|
|
16
17
|
input: 0.8,
|
17
18
|
output: 2,
|
18
19
|
},
|
20
|
+
settings: {
|
21
|
+
searchImpl: 'params',
|
22
|
+
},
|
19
23
|
type: 'chat',
|
20
24
|
},
|
21
25
|
{
|
22
26
|
abilities: {
|
23
27
|
functionCall: true,
|
28
|
+
search: true,
|
24
29
|
},
|
25
30
|
contextWindowTokens: 8192,
|
26
31
|
description:
|
@@ -32,11 +37,15 @@ const wenxinChatModels: AIChatModelCard[] = [
|
|
32
37
|
input: 0.8,
|
33
38
|
output: 2,
|
34
39
|
},
|
40
|
+
settings: {
|
41
|
+
searchImpl: 'params',
|
42
|
+
},
|
35
43
|
type: 'chat',
|
36
44
|
},
|
37
45
|
{
|
38
46
|
abilities: {
|
39
47
|
functionCall: true,
|
48
|
+
search: true,
|
40
49
|
},
|
41
50
|
contextWindowTokens: 128_000,
|
42
51
|
description:
|
@@ -49,11 +58,15 @@ const wenxinChatModels: AIChatModelCard[] = [
|
|
49
58
|
input: 0.8,
|
50
59
|
output: 2,
|
51
60
|
},
|
61
|
+
settings: {
|
62
|
+
searchImpl: 'params',
|
63
|
+
},
|
52
64
|
type: 'chat',
|
53
65
|
},
|
54
66
|
{
|
55
67
|
abilities: {
|
56
68
|
functionCall: true,
|
69
|
+
search: true,
|
57
70
|
},
|
58
71
|
contextWindowTokens: 8192,
|
59
72
|
description:
|
@@ -66,11 +79,15 @@ const wenxinChatModels: AIChatModelCard[] = [
|
|
66
79
|
input: 30,
|
67
80
|
output: 90,
|
68
81
|
},
|
82
|
+
settings: {
|
83
|
+
searchImpl: 'params',
|
84
|
+
},
|
69
85
|
type: 'chat',
|
70
86
|
},
|
71
87
|
{
|
72
88
|
abilities: {
|
73
89
|
functionCall: true,
|
90
|
+
search: true,
|
74
91
|
},
|
75
92
|
contextWindowTokens: 8192,
|
76
93
|
description:
|
@@ -82,11 +99,15 @@ const wenxinChatModels: AIChatModelCard[] = [
|
|
82
99
|
input: 30,
|
83
100
|
output: 90,
|
84
101
|
},
|
102
|
+
settings: {
|
103
|
+
searchImpl: 'params',
|
104
|
+
},
|
85
105
|
type: 'chat',
|
86
106
|
},
|
87
107
|
{
|
88
108
|
abilities: {
|
89
109
|
functionCall: true,
|
110
|
+
search: true,
|
90
111
|
},
|
91
112
|
contextWindowTokens: 8192,
|
92
113
|
description:
|
@@ -99,11 +120,15 @@ const wenxinChatModels: AIChatModelCard[] = [
|
|
99
120
|
input: 20,
|
100
121
|
output: 60,
|
101
122
|
},
|
123
|
+
settings: {
|
124
|
+
searchImpl: 'params',
|
125
|
+
},
|
102
126
|
type: 'chat',
|
103
127
|
},
|
104
128
|
{
|
105
129
|
abilities: {
|
106
130
|
functionCall: true,
|
131
|
+
search: true,
|
107
132
|
},
|
108
133
|
contextWindowTokens: 128_000,
|
109
134
|
description:
|
@@ -116,11 +141,15 @@ const wenxinChatModels: AIChatModelCard[] = [
|
|
116
141
|
input: 20,
|
117
142
|
output: 60,
|
118
143
|
},
|
144
|
+
settings: {
|
145
|
+
searchImpl: 'params',
|
146
|
+
},
|
119
147
|
type: 'chat',
|
120
148
|
},
|
121
149
|
{
|
122
150
|
abilities: {
|
123
151
|
functionCall: true,
|
152
|
+
search: true,
|
124
153
|
},
|
125
154
|
contextWindowTokens: 8192,
|
126
155
|
description:
|
@@ -132,6 +161,9 @@ const wenxinChatModels: AIChatModelCard[] = [
|
|
132
161
|
input: 20,
|
133
162
|
output: 60,
|
134
163
|
},
|
164
|
+
settings: {
|
165
|
+
searchImpl: 'params',
|
166
|
+
},
|
135
167
|
type: 'chat',
|
136
168
|
},
|
137
169
|
{
|
@@ -1,7 +1,9 @@
|
|
1
1
|
// @vitest-environment node
|
2
|
-
import {
|
2
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
3
|
+
|
4
|
+
import { LobeOpenAICompatibleRuntime, ModelProvider } from '@/libs/agent-runtime';
|
5
|
+
import { testProvider } from '@/libs/agent-runtime/providerTestUtils';
|
3
6
|
|
4
|
-
import { testProvider } from '../providerTestUtils';
|
5
7
|
import { LobeHunyuanAI } from './index';
|
6
8
|
|
7
9
|
testProvider({
|
@@ -11,3 +13,136 @@ testProvider({
|
|
11
13
|
chatDebugEnv: 'DEBUG_HUNYUAN_CHAT_COMPLETION',
|
12
14
|
chatModel: 'hunyuan-lite',
|
13
15
|
});
|
16
|
+
|
17
|
+
// Mock the console.error to avoid polluting test output
|
18
|
+
vi.spyOn(console, 'error').mockImplementation(() => {});
|
19
|
+
|
20
|
+
let instance: LobeOpenAICompatibleRuntime;
|
21
|
+
|
22
|
+
beforeEach(() => {
|
23
|
+
instance = new LobeHunyuanAI({ apiKey: 'test' });
|
24
|
+
|
25
|
+
// 使用 vi.spyOn 来模拟 chat.completions.create 方法
|
26
|
+
vi.spyOn(instance['client'].chat.completions, 'create').mockResolvedValue(
|
27
|
+
new ReadableStream() as any,
|
28
|
+
);
|
29
|
+
});
|
30
|
+
|
31
|
+
describe('LobeHunyuanAI', () => {
|
32
|
+
describe('chat', () => {
|
33
|
+
it('should with search citations', async () => {
|
34
|
+
const data = [
|
35
|
+
{
|
36
|
+
id: "939fbdb8dbb9b4c5944cbbe687c977c2",
|
37
|
+
object: "chat.completion.chunk",
|
38
|
+
created: 1741000456,
|
39
|
+
model: "hunyuan-turbo",
|
40
|
+
system_fingerprint: "",
|
41
|
+
choices: [
|
42
|
+
{
|
43
|
+
index: 0,
|
44
|
+
delta: { role: "assistant", content: "为您" },
|
45
|
+
finish_reason: null
|
46
|
+
}
|
47
|
+
],
|
48
|
+
note: "以上内容为AI生成,不代表开发者立场,请勿删除或修改本标记",
|
49
|
+
search_info: {
|
50
|
+
search_results: [
|
51
|
+
{
|
52
|
+
index: 1,
|
53
|
+
title: "公务员考试时政热点【2025年3月3日】_公务员考试网_华图教育",
|
54
|
+
url: "http://www.huatu.com/2025/0303/2803685.html",
|
55
|
+
icon: "https://hunyuan-img-1251316161.cos.ap-guangzhou.myqcloud.com/%2Fpublic/img/63ce96deffe0119827f12deaa5ffe7ef.jpg",
|
56
|
+
text: "华图教育官网"
|
57
|
+
},
|
58
|
+
{
|
59
|
+
index: 2,
|
60
|
+
title: "外交部新闻(2025年3月3日)",
|
61
|
+
url: "https://view.inews.qq.com/a/20250303A02NLC00?scene=qqsearch",
|
62
|
+
icon: "https://hunyuan-img-1251316161.cos.ap-guangzhou.myqcloud.com/%2Fpublic/img/00ce40298870d1accb7920d641152722.jpg",
|
63
|
+
text: "腾讯网"
|
64
|
+
}
|
65
|
+
]
|
66
|
+
}
|
67
|
+
},
|
68
|
+
{
|
69
|
+
id: "939fbdb8dbb9b4c5944cbbe687c977c2",
|
70
|
+
object: "chat.completion.chunk",
|
71
|
+
created: 1741000456,
|
72
|
+
model: "hunyuan-turbo",
|
73
|
+
system_fingerprint: "",
|
74
|
+
choices: [
|
75
|
+
{
|
76
|
+
index: 0,
|
77
|
+
delta: { role: "assistant", content: "找到" },
|
78
|
+
finish_reason: null
|
79
|
+
}
|
80
|
+
],
|
81
|
+
note: "以上内容为AI生成,不代表开发者立场,请勿删除或修改本标记",
|
82
|
+
search_info: {
|
83
|
+
search_results: [
|
84
|
+
{
|
85
|
+
index: 1,
|
86
|
+
title: "公务员考试时政热点【2025年3月3日】_公务员考试网_华图教育",
|
87
|
+
url: "http://www.huatu.com/2025/0303/2803685.html",
|
88
|
+
icon: "https://hunyuan-img-1251316161.cos.ap-guangzhou.myqcloud.com/%2Fpublic/img/63ce96deffe0119827f12deaa5ffe7ef.jpg",
|
89
|
+
text: "华图教育官网"
|
90
|
+
},
|
91
|
+
{
|
92
|
+
index: 2,
|
93
|
+
title: "外交部新闻(2025年3月3日)",
|
94
|
+
url: "https://view.inews.qq.com/a/20250303A02NLC00?scene=qqsearch",
|
95
|
+
icon: "https://hunyuan-img-1251316161.cos.ap-guangzhou.myqcloud.com/%2Fpublic/img/00ce40298870d1accb7920d641152722.jpg",
|
96
|
+
text: "腾讯网"
|
97
|
+
}
|
98
|
+
]
|
99
|
+
}
|
100
|
+
}
|
101
|
+
];
|
102
|
+
|
103
|
+
const mockStream = new ReadableStream({
|
104
|
+
start(controller) {
|
105
|
+
data.forEach((chunk) => {
|
106
|
+
controller.enqueue(chunk);
|
107
|
+
});
|
108
|
+
|
109
|
+
controller.close();
|
110
|
+
},
|
111
|
+
});
|
112
|
+
|
113
|
+
vi.spyOn(instance['client'].chat.completions, 'create').mockResolvedValue(mockStream as any);
|
114
|
+
|
115
|
+
const result = await instance.chat({
|
116
|
+
messages: [{ content: 'Hello', role: 'user' }],
|
117
|
+
model: 'mistralai/mistral-7b-instruct:free',
|
118
|
+
temperature: 0,
|
119
|
+
});
|
120
|
+
|
121
|
+
const decoder = new TextDecoder();
|
122
|
+
const reader = result.body!.getReader();
|
123
|
+
const stream: string[] = [];
|
124
|
+
|
125
|
+
while (true) {
|
126
|
+
const { value, done } = await reader.read();
|
127
|
+
if (done) break;
|
128
|
+
stream.push(decoder.decode(value));
|
129
|
+
}
|
130
|
+
|
131
|
+
expect(stream).toEqual(
|
132
|
+
[
|
133
|
+
'id: 939fbdb8dbb9b4c5944cbbe687c977c2',
|
134
|
+
'event: grounding',
|
135
|
+
'data: {"citations":[{"title":"公务员考试时政热点【2025年3月3日】_公务员考试网_华图教育","url":"http://www.huatu.com/2025/0303/2803685.html"},{"title":"外交部新闻(2025年3月3日)","url":"https://view.inews.qq.com/a/20250303A02NLC00?scene=qqsearch"}]}\n',
|
136
|
+
'id: 939fbdb8dbb9b4c5944cbbe687c977c2',
|
137
|
+
'event: text',
|
138
|
+
'data: "为您"\n',
|
139
|
+
'id: 939fbdb8dbb9b4c5944cbbe687c977c2',
|
140
|
+
'event: text',
|
141
|
+
'data: "找到"\n',
|
142
|
+
].map((line) => `${line}\n`),
|
143
|
+
);
|
144
|
+
|
145
|
+
expect((await reader.read()).done).toBe(true);
|
146
|
+
});
|
147
|
+
});
|
148
|
+
});
|
@@ -15,14 +15,15 @@ export const LobeHunyuanAI = LobeOpenAICompatibleFactory({
|
|
15
15
|
|
16
16
|
return {
|
17
17
|
...rest,
|
18
|
+
stream: true,
|
18
19
|
...(enabledSearch && {
|
19
|
-
/*
|
20
20
|
citation: true,
|
21
|
+
enable_enhancement: true,
|
22
|
+
/*
|
21
23
|
enable_multimedia: true,
|
22
|
-
search_info: true
|
23
24
|
*/
|
24
|
-
enable_enhancement: true,
|
25
25
|
enable_speed_search: process.env.HUNYUAN_ENABLE_SPEED_SEARCH === '1',
|
26
|
+
search_info: true,
|
26
27
|
}),
|
27
28
|
} as any;
|
28
29
|
},
|
@@ -35,7 +35,7 @@ export const LobeQwenAI = LobeOpenAICompatibleFactory({
|
|
35
35
|
: presence_penalty !== undefined && presence_penalty >= -2 && presence_penalty <= 2
|
36
36
|
? presence_penalty
|
37
37
|
: undefined,
|
38
|
-
stream:
|
38
|
+
stream: true,
|
39
39
|
temperature:
|
40
40
|
temperature !== undefined && temperature >= 0 && temperature < 2
|
41
41
|
? temperature
|
@@ -127,19 +127,35 @@ export const transformOpenAIStream = (
|
|
127
127
|
}
|
128
128
|
|
129
129
|
if (typeof content === 'string') {
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
130
|
+
if (!streamContext?.returnedCitation) {
|
131
|
+
const citations =
|
132
|
+
// in Perplexity api, the citation is in every chunk, but we only need to return it once
|
133
|
+
('citations' in chunk && chunk.citations) ||
|
134
|
+
// in Hunyuan api, the citation is in every chunk
|
135
|
+
('search_info' in chunk && (chunk.search_info as any)?.search_results) ||
|
136
|
+
// in Wenxin api, the citation is in the first and last chunk
|
137
|
+
('search_results' in chunk && chunk.search_results);
|
138
|
+
|
139
|
+
if (citations) {
|
140
|
+
streamContext.returnedCitation = true;
|
141
|
+
|
142
|
+
return [
|
143
|
+
{
|
144
|
+
data: {
|
145
|
+
citations: (citations as any[]).map(
|
146
|
+
(item) =>
|
147
|
+
({
|
148
|
+
title: typeof item === 'string' ? item : item.title,
|
149
|
+
url: typeof item === 'string' ? item : item.url,
|
150
|
+
}) as CitationItem
|
151
|
+
),
|
152
|
+
},
|
153
|
+
id: chunk.id,
|
154
|
+
type: 'grounding',
|
155
|
+
},
|
156
|
+
{ data: content, id: chunk.id, type: 'text' },
|
157
|
+
];
|
158
|
+
}
|
143
159
|
}
|
144
160
|
|
145
161
|
return { data: content, id: chunk.id, type: 'text' };
|
@@ -9,9 +9,10 @@ export interface StreamContext {
|
|
9
9
|
id: string;
|
10
10
|
/**
|
11
11
|
* As pplx citations is in every chunk, but we only need to return it once
|
12
|
-
* this flag is used to check if the pplx citation is returned,and then not return it again
|
12
|
+
* this flag is used to check if the pplx citation is returned,and then not return it again.
|
13
|
+
* Same as Hunyuan and Wenxin
|
13
14
|
*/
|
14
|
-
|
15
|
+
returnedCitation?: boolean;
|
15
16
|
thinking?: {
|
16
17
|
id: string;
|
17
18
|
name: string;
|
@@ -0,0 +1,113 @@
|
|
1
|
+
// @vitest-environment node
|
2
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
3
|
+
|
4
|
+
import { LobeOpenAICompatibleRuntime, ModelProvider } from '@/libs/agent-runtime';
|
5
|
+
import { testProvider } from '@/libs/agent-runtime/providerTestUtils';
|
6
|
+
|
7
|
+
import { LobeWenxinAI } from './index';
|
8
|
+
|
9
|
+
testProvider({
|
10
|
+
Runtime: LobeWenxinAI,
|
11
|
+
provider: ModelProvider.Wenxin,
|
12
|
+
defaultBaseURL: 'https://qianfan.baidubce.com/v2',
|
13
|
+
chatDebugEnv: 'DEBUG_WENXIN_CHAT_COMPLETION',
|
14
|
+
chatModel: 'ernie-speed-128k',
|
15
|
+
});
|
16
|
+
|
17
|
+
// Mock the console.error to avoid polluting test output
|
18
|
+
vi.spyOn(console, 'error').mockImplementation(() => {});
|
19
|
+
|
20
|
+
let instance: LobeOpenAICompatibleRuntime;
|
21
|
+
|
22
|
+
beforeEach(() => {
|
23
|
+
instance = new LobeWenxinAI({ apiKey: 'test' });
|
24
|
+
|
25
|
+
// 使用 vi.spyOn 来模拟 chat.completions.create 方法
|
26
|
+
vi.spyOn(instance['client'].chat.completions, 'create').mockResolvedValue(
|
27
|
+
new ReadableStream() as any,
|
28
|
+
);
|
29
|
+
});
|
30
|
+
|
31
|
+
describe('LobeWenxinAI', () => {
|
32
|
+
describe('chat', () => {
|
33
|
+
it('should with search citations', async () => {
|
34
|
+
const data = [
|
35
|
+
{
|
36
|
+
id: "as-bhrxwy5fq1",
|
37
|
+
object: "chat.completion.chunk",
|
38
|
+
created: 1741000028,
|
39
|
+
model: "ernie-4.0-8k-latest",
|
40
|
+
choices: [
|
41
|
+
{
|
42
|
+
index: 0,
|
43
|
+
delta: { content: "今天是**", role: "assistant" },
|
44
|
+
flag: 0
|
45
|
+
}
|
46
|
+
],
|
47
|
+
search_results: [
|
48
|
+
{ index: 1, url: "http://www.mnw.cn/news/shehui/", title: "社会新闻" },
|
49
|
+
{ index: 2, url: "https://www.chinanews.com.cn/sh/2025/03-01/10376297.shtml", title: "中越边民共庆“春龙节”" },
|
50
|
+
{ index: 3, url: "https://www.chinanews.com/china/index.shtml", title: "中国新闻网_时政" }
|
51
|
+
]
|
52
|
+
},
|
53
|
+
{
|
54
|
+
id: "as-bhrxwy5fq1",
|
55
|
+
object: "chat.completion.chunk",
|
56
|
+
created: 1741000028,
|
57
|
+
model: "ernie-4.0-8k-latest",
|
58
|
+
choices: [
|
59
|
+
{
|
60
|
+
index: 0,
|
61
|
+
delta: { content: "20" },
|
62
|
+
flag: 0
|
63
|
+
}
|
64
|
+
]
|
65
|
+
}
|
66
|
+
];
|
67
|
+
|
68
|
+
const mockStream = new ReadableStream({
|
69
|
+
start(controller) {
|
70
|
+
data.forEach((chunk) => {
|
71
|
+
controller.enqueue(chunk);
|
72
|
+
});
|
73
|
+
|
74
|
+
controller.close();
|
75
|
+
},
|
76
|
+
});
|
77
|
+
|
78
|
+
vi.spyOn(instance['client'].chat.completions, 'create').mockResolvedValue(mockStream as any);
|
79
|
+
|
80
|
+
const result = await instance.chat({
|
81
|
+
messages: [{ content: 'Hello', role: 'user' }],
|
82
|
+
model: 'mistralai/mistral-7b-instruct:free',
|
83
|
+
temperature: 0,
|
84
|
+
});
|
85
|
+
|
86
|
+
const decoder = new TextDecoder();
|
87
|
+
const reader = result.body!.getReader();
|
88
|
+
const stream: string[] = [];
|
89
|
+
|
90
|
+
while (true) {
|
91
|
+
const { value, done } = await reader.read();
|
92
|
+
if (done) break;
|
93
|
+
stream.push(decoder.decode(value));
|
94
|
+
}
|
95
|
+
|
96
|
+
expect(stream).toEqual(
|
97
|
+
[
|
98
|
+
'id: as-bhrxwy5fq1',
|
99
|
+
'event: grounding',
|
100
|
+
'data: {"citations":[{"title":"社会新闻","url":"http://www.mnw.cn/news/shehui/"},{"title":"中越边民共庆“春龙节”","url":"https://www.chinanews.com.cn/sh/2025/03-01/10376297.shtml"},{"title":"中国新闻网_时政","url":"https://www.chinanews.com/china/index.shtml"}]}\n',
|
101
|
+
'id: as-bhrxwy5fq1',
|
102
|
+
'event: text',
|
103
|
+
'data: "今天是**"\n',
|
104
|
+
'id: as-bhrxwy5fq1',
|
105
|
+
'event: text',
|
106
|
+
'data: "20"\n',
|
107
|
+
].map((line) => `${line}\n`),
|
108
|
+
);
|
109
|
+
|
110
|
+
expect((await reader.read()).done).toBe(true);
|
111
|
+
});
|
112
|
+
});
|
113
|
+
});
|
@@ -3,6 +3,23 @@ import { LobeOpenAICompatibleFactory } from '../utils/openaiCompatibleFactory';
|
|
3
3
|
|
4
4
|
export const LobeWenxinAI = LobeOpenAICompatibleFactory({
|
5
5
|
baseURL: 'https://qianfan.baidubce.com/v2',
|
6
|
+
chatCompletion: {
|
7
|
+
handlePayload: (payload) => {
|
8
|
+
const { enabledSearch, ...rest } = payload;
|
9
|
+
|
10
|
+
return {
|
11
|
+
...rest,
|
12
|
+
stream: true,
|
13
|
+
...(enabledSearch && {
|
14
|
+
web_search: {
|
15
|
+
enable: true,
|
16
|
+
enable_citation: true,
|
17
|
+
enable_trace: true,
|
18
|
+
}
|
19
|
+
}),
|
20
|
+
} as any;
|
21
|
+
},
|
22
|
+
},
|
6
23
|
debug: {
|
7
24
|
chatCompletion: () => process.env.DEBUG_WENXIN_CHAT_COMPLETION === '1',
|
8
25
|
},
|
@@ -1,4 +1,4 @@
|
|
1
|
-
import { Alert, CopyButton, Icon, Markdown } from '@lobehub/ui';
|
1
|
+
import { Alert, CopyButton, Highlighter, Icon, Markdown } from '@lobehub/ui';
|
2
2
|
import { Descriptions, Segmented, Typography } from 'antd';
|
3
3
|
import { createStyles } from 'antd-style';
|
4
4
|
import { ExternalLink } from 'lucide-react';
|
@@ -90,7 +90,42 @@ const PageContent = memo<PageContentProps>(({ result }) => {
|
|
90
90
|
const { styles } = useStyles();
|
91
91
|
const [display, setDisplay] = useState('render');
|
92
92
|
|
93
|
-
if (!result) return undefined;
|
93
|
+
if (!result || !result.data) return undefined;
|
94
|
+
|
95
|
+
if ('errorType' in result.data) {
|
96
|
+
return (
|
97
|
+
<Flexbox className={styles.footer} gap={4}>
|
98
|
+
<div>
|
99
|
+
<Descriptions
|
100
|
+
classNames={{
|
101
|
+
content: styles.footerText,
|
102
|
+
}}
|
103
|
+
column={1}
|
104
|
+
items={[
|
105
|
+
{
|
106
|
+
children: result.crawler,
|
107
|
+
label: t('search.crawPages.meta.crawler'),
|
108
|
+
},
|
109
|
+
]}
|
110
|
+
size="small"
|
111
|
+
/>
|
112
|
+
</div>
|
113
|
+
<Alert
|
114
|
+
extra={
|
115
|
+
<div style={{ maxWidth: 500, overflowX: 'scroll' }}>
|
116
|
+
<Highlighter language={'json'}>{JSON.stringify(result.data, null, 2)}</Highlighter>
|
117
|
+
</div>
|
118
|
+
}
|
119
|
+
message={
|
120
|
+
<div style={{ textAlign: 'start' }}>
|
121
|
+
{result.data.errorMessage || result.data.content}
|
122
|
+
</div>
|
123
|
+
}
|
124
|
+
type={'error'}
|
125
|
+
/>
|
126
|
+
</Flexbox>
|
127
|
+
);
|
128
|
+
}
|
94
129
|
|
95
130
|
const { url, title, description, content } = result.data;
|
96
131
|
return (
|
@@ -1,7 +1,7 @@
|
|
1
1
|
'use client';
|
2
2
|
|
3
|
-
import { CrawlSuccessResult } from '@lobechat/web-crawler';
|
4
|
-
import { Icon } from '@lobehub/ui';
|
3
|
+
import { CrawlErrorResult, CrawlSuccessResult } from '@lobechat/web-crawler';
|
4
|
+
import { Alert, Highlighter, Icon } from '@lobehub/ui';
|
5
5
|
import { Descriptions, Typography } from 'antd';
|
6
6
|
import { createStyles } from 'antd-style';
|
7
7
|
import { ExternalLink } from 'lucide-react';
|
@@ -82,7 +82,7 @@ interface CrawlerData {
|
|
82
82
|
crawler: string;
|
83
83
|
messageId: string;
|
84
84
|
originalUrl: string;
|
85
|
-
result: CrawlSuccessResult;
|
85
|
+
result: CrawlSuccessResult | CrawlErrorResult;
|
86
86
|
}
|
87
87
|
|
88
88
|
const CrawlerResultCard = memo<CrawlerData>(({ result, messageId, crawler, originalUrl }) => {
|
@@ -90,6 +90,39 @@ const CrawlerResultCard = memo<CrawlerData>(({ result, messageId, crawler, origi
|
|
90
90
|
const { styles } = useStyles();
|
91
91
|
const [openToolUI, togglePageContent] = useChatStore((s) => [s.openToolUI, s.togglePageContent]);
|
92
92
|
|
93
|
+
if ('errorType' in result) {
|
94
|
+
return (
|
95
|
+
<Flexbox className={styles.footer} gap={4}>
|
96
|
+
<div>
|
97
|
+
<Descriptions
|
98
|
+
classNames={{
|
99
|
+
content: styles.footerText,
|
100
|
+
}}
|
101
|
+
column={1}
|
102
|
+
items={[
|
103
|
+
{
|
104
|
+
children: crawler,
|
105
|
+
label: t('search.crawPages.meta.crawler'),
|
106
|
+
},
|
107
|
+
]}
|
108
|
+
size="small"
|
109
|
+
/>
|
110
|
+
</div>
|
111
|
+
<Alert
|
112
|
+
extra={
|
113
|
+
<div style={{ maxWidth: 500, overflowX: 'scroll' }}>
|
114
|
+
<Highlighter language={'json'}>{JSON.stringify(result, null, 2)}</Highlighter>
|
115
|
+
</div>
|
116
|
+
}
|
117
|
+
message={
|
118
|
+
<div style={{ textAlign: 'start' }}>{result.errorMessage || result.content}</div>
|
119
|
+
}
|
120
|
+
type={'error'}
|
121
|
+
/>
|
122
|
+
</Flexbox>
|
123
|
+
);
|
124
|
+
}
|
125
|
+
|
93
126
|
const { url, title, description } = result;
|
94
127
|
|
95
128
|
return (
|
@@ -1,3 +1,4 @@
|
|
1
|
+
import { CrawlErrorResult } from '@lobechat/web-crawler';
|
1
2
|
import { memo } from 'react';
|
2
3
|
import { Flexbox } from 'react-layout-kit';
|
3
4
|
|
@@ -31,7 +32,16 @@ const PagesContent = memo<PagesContentProps>(({ results, messageId, urls }) => {
|
|
31
32
|
key={result.originalUrl}
|
32
33
|
messageId={messageId}
|
33
34
|
originalUrl={result.originalUrl}
|
34
|
-
result={
|
35
|
+
result={
|
36
|
+
result.data ||
|
37
|
+
// TODO: Remove this in v2 as it's deprecated
|
38
|
+
({
|
39
|
+
content: (result as any)?.content,
|
40
|
+
errorMessage: (result as any)?.errorMessage,
|
41
|
+
errorType: (result as any)?.errorType,
|
42
|
+
url: result.originalUrl,
|
43
|
+
} as CrawlErrorResult)
|
44
|
+
}
|
35
45
|
/>
|
36
46
|
))}
|
37
47
|
</Flexbox>
|
@@ -1,4 +1,4 @@
|
|
1
|
-
import { CrawlSuccessResult } from '@lobechat/web-crawler';
|
1
|
+
import { CrawlErrorResult, CrawlSuccessResult } from '@lobechat/web-crawler';
|
2
2
|
|
3
3
|
export interface CrawlSinglePageQuery {
|
4
4
|
url: string;
|
@@ -10,7 +10,7 @@ export interface CrawlMultiPagesQuery {
|
|
10
10
|
|
11
11
|
export interface CrawlResult {
|
12
12
|
crawler: string;
|
13
|
-
data: CrawlSuccessResult;
|
13
|
+
data: CrawlSuccessResult | CrawlErrorResult;
|
14
14
|
originalUrl: string;
|
15
15
|
}
|
16
16
|
|