@lobehub/chat 1.102.2 → 1.102.4
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 +58 -0
- package/Dockerfile.pglite +2 -0
- package/apps/desktop/README.md +322 -36
- package/apps/desktop/README.zh-CN.md +353 -0
- package/apps/desktop/package.json +1 -0
- package/apps/desktop/resources/tray-dark.png +0 -0
- package/apps/desktop/resources/tray-light.png +0 -0
- package/apps/desktop/resources/tray.png +0 -0
- package/apps/desktop/src/main/const/env.ts +25 -0
- package/apps/desktop/src/main/core/TrayManager.ts +7 -1
- package/changelog/v1.json +18 -0
- package/locales/ar/subscription.json +24 -0
- package/locales/bg-BG/subscription.json +24 -0
- package/locales/de-DE/subscription.json +24 -0
- package/locales/en-US/subscription.json +24 -0
- package/locales/es-ES/subscription.json +24 -0
- package/locales/fa-IR/subscription.json +24 -0
- package/locales/fr-FR/subscription.json +24 -0
- package/locales/it-IT/subscription.json +24 -0
- package/locales/ja-JP/subscription.json +24 -0
- package/locales/ko-KR/subscription.json +24 -0
- package/locales/nl-NL/subscription.json +24 -0
- package/locales/pl-PL/subscription.json +24 -0
- package/locales/pt-BR/subscription.json +24 -0
- package/locales/ru-RU/subscription.json +24 -0
- package/locales/tr-TR/subscription.json +24 -0
- package/locales/vi-VN/subscription.json +24 -0
- package/locales/zh-CN/subscription.json +24 -0
- package/locales/zh-TW/subscription.json +24 -0
- package/package.json +1 -1
- package/packages/electron-client-ipc/README.md +55 -30
- package/packages/electron-client-ipc/README.zh-CN.md +73 -0
- package/packages/electron-server-ipc/README.md +42 -20
- package/packages/electron-server-ipc/README.zh-CN.md +76 -0
- package/packages/file-loaders/README.md +77 -51
- package/packages/file-loaders/README.zh-CN.md +89 -0
- package/src/app/[variants]/(main)/chat/(workspace)/_layout/Desktop/ChatHeader/HeaderAction.tsx +11 -8
- package/src/app/[variants]/(main)/chat/(workspace)/features/SettingButton.tsx +11 -8
- package/src/app/[variants]/(main)/chat/(workspace)/features/ShareButton/index.tsx +3 -0
- package/src/app/[variants]/(main)/chat/@session/_layout/Desktop/SessionHeader.tsx +3 -0
- package/src/features/PlanIcon/index.tsx +126 -0
- package/src/features/User/PlanTag.tsx +33 -25
- package/src/libs/model-runtime/ModelRuntime.ts +0 -8
- package/src/locales/default/index.ts +2 -0
- package/src/locales/default/subscription.ts +24 -0
- package/src/server/routers/async/caller.ts +0 -6
- package/src/types/subscription.ts +7 -0
- package/apps/desktop/resources/tray-icon.png +0 -0
@@ -1,63 +1,89 @@
|
|
1
|
-
# @
|
1
|
+
# @lobechat/file-loaders
|
2
2
|
|
3
|
-
`@
|
3
|
+
`@lobechat/file-loaders` is a toolkit within the LobeChat project, specifically designed for loading various types of files from local file paths and converting their content into standardized `Document` object arrays.
|
4
4
|
|
5
|
-
|
5
|
+
Its primary purpose is to provide a unified interface for reading different file formats, extracting their core text content, and preparing them for subsequent processing (such as file preview, content extraction, or serving as knowledge base data sources in LobeChat).
|
6
6
|
|
7
|
-
## ✨
|
7
|
+
## ✨ Features
|
8
8
|
|
9
|
-
-
|
10
|
-
-
|
11
|
-
-
|
12
|
-
-
|
13
|
-
- **PDF**: `.pdf`
|
14
|
-
- **Word**: `.docx`
|
15
|
-
- **Excel**: `.xlsx`, `.xls`
|
16
|
-
- **PowerPoint**: `.pptx`
|
17
|
-
-
|
18
|
-
-
|
19
|
-
-
|
9
|
+
- **Unified Interface**: Provides `loadFile(filePath: string)` function as the core entry point.
|
10
|
+
- **Automatic Type Detection**: Automatically selects appropriate loading methods based on file extensions.
|
11
|
+
- **Extensive Format Support**:
|
12
|
+
- **Plain Text**: `.txt`, `.csv`, `.md`, `.json`, `.xml`, `.yaml`, `.html` and various code and configuration file formats.
|
13
|
+
- **PDF**: `.pdf` files.
|
14
|
+
- **Word**: `.docx` files.
|
15
|
+
- **Excel**: `.xlsx`, `.xls` files, with each worksheet as a `Page`.
|
16
|
+
- **PowerPoint**: `.pptx` files, with each slide as a `Page`.
|
17
|
+
- **Standardized Output**: Always returns `Promise<Document>`. A `Document` object represents a loaded file, containing an array of `Page` objects that represent the logical units of the file (pages, slides, worksheets, text blocks, etc.).
|
18
|
+
- **Hierarchical Structure**: Uses a structure where `Document` contains `Page[]`, better reflecting the original organization of the file.
|
19
|
+
- **Rich Metadata**: Provides detailed metadata at both `Document` and `Page` levels, including file information, content statistics, and structural information.
|
20
20
|
|
21
|
-
##
|
21
|
+
## Core Data Structures
|
22
22
|
|
23
|
-
`loadFile`
|
23
|
+
The `loadFile` function returns a `FileDocument` object containing file-level information and all its logical pages/blocks (`DocumentPage`).
|
24
24
|
|
25
25
|
### `FileDocument` Interface
|
26
26
|
|
27
|
-
|
|
28
|
-
| :---------------- | :---------------- |
|
29
|
-
| `content` | `string` |
|
30
|
-
| `createdTime` | `Date` |
|
31
|
-
| `fileType` | `string` |
|
32
|
-
| `filename` | `string` |
|
33
|
-
| `metadata` | `object` |
|
34
|
-
| `metadata.author` | `string?` |
|
35
|
-
| `metadata.error` | `string?` |
|
36
|
-
| `metadata.title` | `string?` |
|
37
|
-
| `...` | `any` |
|
38
|
-
| `modifiedTime` | `Date` |
|
39
|
-
| `pages` | `DocumentPage[]?` |
|
40
|
-
| `source` | `string` |
|
41
|
-
| `totalCharCount` | `number` |
|
42
|
-
| `totalLineCount` | `number` |
|
27
|
+
| Field | Type | Description |
|
28
|
+
| :---------------- | :---------------- | :------------------------------------------------------------------------------------ |
|
29
|
+
| `content` | `string` | File content (aggregated content) |
|
30
|
+
| `createdTime` | `Date` | File creation timestamp. |
|
31
|
+
| `fileType` | `string` | File type or extension. |
|
32
|
+
| `filename` | `string` | Original filename. |
|
33
|
+
| `metadata` | `object` | File-level metadata. |
|
34
|
+
| `metadata.author` | `string?` | Document author (if available). |
|
35
|
+
| `metadata.error` | `string?` | Error information if the entire file loading failed. |
|
36
|
+
| `metadata.title` | `string?` | Document title (if available). |
|
37
|
+
| `...` | `any` | Other file-level metadata. |
|
38
|
+
| `modifiedTime` | `Date` | File last modified timestamp. |
|
39
|
+
| `pages` | `DocumentPage[]?` | Array containing all logical pages/blocks in the document (optional). |
|
40
|
+
| `source` | `string` | Full path of the original file. |
|
41
|
+
| `totalCharCount` | `number` | Total character count of the entire document (sum of all `DocumentPage` `charCount`). |
|
42
|
+
| `totalLineCount` | `number` | Total line count of the entire document (sum of all `DocumentPage` `lineCount`). |
|
43
43
|
|
44
44
|
### `DocumentPage` Interface
|
45
45
|
|
46
|
-
|
|
47
|
-
| :------------------------- | :-------- |
|
48
|
-
| `charCount` | `number` |
|
49
|
-
| `lineCount` | `number` |
|
50
|
-
| `metadata` | `object` |
|
51
|
-
| `metadata.chunkIndex` | `number?` |
|
52
|
-
| `metadata.error` | `string?` |
|
53
|
-
| `metadata.lineNumberEnd` | `number?` |
|
54
|
-
| `metadata.lineNumberStart` | `number?` |
|
55
|
-
| `metadata.pageNumber` | `number?` |
|
56
|
-
| `metadata.sectionTitle` | `string?` |
|
57
|
-
| `metadata.sheetName` | `string?` |
|
58
|
-
| `metadata.slideNumber` | `number?` |
|
59
|
-
| `metadata.totalChunks` | `number?` |
|
60
|
-
| `...` | `any` |
|
61
|
-
| `pageContent` | `string` |
|
62
|
-
|
63
|
-
|
46
|
+
| Field | Type | Description |
|
47
|
+
| :------------------------- | :-------- | :---------------------------------------------- |
|
48
|
+
| `charCount` | `number` | Character count of this page/block content. |
|
49
|
+
| `lineCount` | `number` | Line count of this page/block content. |
|
50
|
+
| `metadata` | `object` | Metadata related to this page/block. |
|
51
|
+
| `metadata.chunkIndex` | `number?` | Current chunk index if split into chunks. |
|
52
|
+
| `metadata.error` | `string?` | Error occurred when processing this page/block. |
|
53
|
+
| `metadata.lineNumberEnd` | `number?` | End line number in the original file. |
|
54
|
+
| `metadata.lineNumberStart` | `number?` | Start line number in the original file. |
|
55
|
+
| `metadata.pageNumber` | `number?` | Page number (applicable to PDF, DOCX). |
|
56
|
+
| `metadata.sectionTitle` | `string?` | Related section title. |
|
57
|
+
| `metadata.sheetName` | `string?` | Worksheet name (applicable to XLSX). |
|
58
|
+
| `metadata.slideNumber` | `number?` | Slide number (applicable to PPTX). |
|
59
|
+
| `metadata.totalChunks` | `number?` | Total chunks if split into chunks. |
|
60
|
+
| `...` | `any` | Other page/block-specific metadata. |
|
61
|
+
| `pageContent` | `string` | Core text content of this page/block. |
|
62
|
+
|
63
|
+
## 🤝 Contribution
|
64
|
+
|
65
|
+
File formats and parsing requirements are constantly evolving. We welcome community contributions to expand format support and improve parsing accuracy. You can participate in improvements through:
|
66
|
+
|
67
|
+
### How to Contribute
|
68
|
+
|
69
|
+
1. **New File Format Support**: Add support for additional file types
|
70
|
+
2. **Parser Improvements**: Enhance existing parsers for better content extraction
|
71
|
+
3. **Metadata Enhancement**: Improve metadata extraction capabilities
|
72
|
+
4. **Performance Optimization**: Optimize file loading and processing performance
|
73
|
+
|
74
|
+
### Contribution Process
|
75
|
+
|
76
|
+
1. Fork the [LobeChat repository](https://github.com/lobehub/lobe-chat)
|
77
|
+
2. Add new format support or improve existing parsers
|
78
|
+
3. Submit a Pull Request describing:
|
79
|
+
|
80
|
+
- New file formats supported or improvements made
|
81
|
+
- Testing with various file samples
|
82
|
+
- Performance impact analysis
|
83
|
+
- Documentation updates
|
84
|
+
|
85
|
+
## 📌 Note
|
86
|
+
|
87
|
+
This is an internal module of LobeHub (`"private": true`), designed specifically for LobeChat and not published as a standalone package.
|
88
|
+
|
89
|
+
If you're interested in our project, feel free to check it out, star it, or contribute code on [GitHub](https://github.com/lobehub/lobe-chat)!
|
@@ -0,0 +1,89 @@
|
|
1
|
+
# @lobechat/file-loaders
|
2
|
+
|
3
|
+
`@lobechat/file-loaders` 是 LobeChat 项目中的一个工具包,专门用于从本地文件路径加载各种类型的文件,并将其内容转换为标准化的 `Document` 对象数组。
|
4
|
+
|
5
|
+
它的主要目的是提供一个统一的接口来读取不同的文件格式,提取其核心文本内容,并为后续处理(例如在 LobeChat 中进行文件预览、内容提取或将其作为知识库数据源)做好准备。
|
6
|
+
|
7
|
+
## ✨ 功能特性
|
8
|
+
|
9
|
+
- **统一接口**: 提供 `loadFile(filePath: string)` 函数作为核心入口点。
|
10
|
+
- **自动类型检测**: 根据文件扩展名自动选择合适的加载方式。
|
11
|
+
- **广泛的格式支持**:
|
12
|
+
- **纯文本类**: `.txt`, `.csv`, `.md`, `.json`, `.xml`, `.yaml`, `.html` 以及多种代码和配置文件格式。
|
13
|
+
- **PDF**: `.pdf` 文件。
|
14
|
+
- **Word**: `.docx` 文件。
|
15
|
+
- **Excel**: `.xlsx`, `.xls` 文件,每个工作表作为一个 `Page`。
|
16
|
+
- **PowerPoint**: `.pptx` 文件,每个幻灯片作为一个 `Page`。
|
17
|
+
- **标准化输出**: 始终返回 `Promise<Document>`。 `Document` 对象代表一个加载的文件,其内部包含一个 `Page` 数组,代表文件的各个逻辑单元(页、幻灯片、工作表、文本块等)。
|
18
|
+
- **层级结构**: 采用 `Document` 包含 `Page[]` 的结构,更好地反映文件原始组织方式。
|
19
|
+
- **丰富的元数据**: 在 `Document` 和 `Page` 层面提供详细的元数据,包括文件信息、内容统计和结构信息。
|
20
|
+
|
21
|
+
## 核心数据结构
|
22
|
+
|
23
|
+
`loadFile` 函数返回一个 `FileDocument` 对象,包含文件级信息和其所有逻辑页面 / 块 (`DocumentPage`)。
|
24
|
+
|
25
|
+
### `FileDocument` Interface
|
26
|
+
|
27
|
+
| 字段 | 类型 | 描述 |
|
28
|
+
| :---------------- | :---------------- | :------------------------------------------------------------- |
|
29
|
+
| `content` | `string` | 文件内容 (聚合后的内容) |
|
30
|
+
| `createdTime` | `Date` | 文件创建时间戳。 |
|
31
|
+
| `fileType` | `string` | 文件类型或扩展名。 |
|
32
|
+
| `filename` | `string` | 原始文件名。 |
|
33
|
+
| `metadata` | `object` | 文件级别的元数据。 |
|
34
|
+
| `metadata.author` | `string?` | 文档作者 (如果可用)。 |
|
35
|
+
| `metadata.error` | `string?` | 如果整个文件加载失败,记录错误信息。 |
|
36
|
+
| `metadata.title` | `string?` | 文档标题 (如果可用)。 |
|
37
|
+
| `...` | `any` | 其他文件级别的元数据。 |
|
38
|
+
| `modifiedTime` | `Date` | 文件最后修改时间戳。 |
|
39
|
+
| `pages` | `DocumentPage[]?` | 包含文档中所有逻辑页面 / 块的数组 (可选)。 |
|
40
|
+
| `source` | `string` | 原始文件的完整路径。 |
|
41
|
+
| `totalCharCount` | `number` | 整个文档的总字符数 (所有 `DocumentPage` 的 `charCount` 之和)。 |
|
42
|
+
| `totalLineCount` | `number` | 整个文档的总行数 (所有 `DocumentPage` 的 `lineCount` 之和)。 |
|
43
|
+
|
44
|
+
### `DocumentPage` Interface
|
45
|
+
|
46
|
+
| 字段 | 类型 | 描述 |
|
47
|
+
| :------------------------- | :-------- | :--------------------------- |
|
48
|
+
| `charCount` | `number` | 此页 / 块内容的字符数。 |
|
49
|
+
| `lineCount` | `number` | 此页 / 块内容的行数。 |
|
50
|
+
| `metadata` | `object` | 与此页 / 块相关的元数据。 |
|
51
|
+
| `metadata.chunkIndex` | `number?` | 如果分割成块,当前块的索引。 |
|
52
|
+
| `metadata.error` | `string?` | 处理此页 / 块时发生的错误。 |
|
53
|
+
| `metadata.lineNumberEnd` | `number?` | 在原始文件中的结束行号。 |
|
54
|
+
| `metadata.lineNumberStart` | `number?` | 在原始文件中的起始行号。 |
|
55
|
+
| `metadata.pageNumber` | `number?` | 页码 (适用于 PDF, DOCX)。 |
|
56
|
+
| `metadata.sectionTitle` | `string?` | 相关的章节标题。 |
|
57
|
+
| `metadata.sheetName` | `string?` | 工作表名称 (适用于 XLSX)。 |
|
58
|
+
| `metadata.slideNumber` | `number?` | 幻灯片编号 (适用于 PPTX)。 |
|
59
|
+
| `metadata.totalChunks` | `number?` | 如果分割成块,总块数。 |
|
60
|
+
| `...` | `any` | 其他特定于页 / 块的元数据。 |
|
61
|
+
| `pageContent` | `string` | 此页 / 块的核心文本内容。 |
|
62
|
+
|
63
|
+
## 🤝 参与贡献
|
64
|
+
|
65
|
+
文件格式和解析需求在不断发展。我们欢迎社区贡献来扩展格式支持和提高解析准确性。您可以通过以下方式参与改进:
|
66
|
+
|
67
|
+
### 如何贡献
|
68
|
+
|
69
|
+
1. **新文件格式支持**:添加对其他文件类型的支持
|
70
|
+
2. **解析器改进**:增强现有解析器以更好地提取内容
|
71
|
+
3. **元数据增强**:改进元数据提取能力
|
72
|
+
4. **性能优化**:优化文件加载和处理性能
|
73
|
+
|
74
|
+
### 贡献流程
|
75
|
+
|
76
|
+
1. Fork [LobeChat 仓库](https://github.com/lobehub/lobe-chat)
|
77
|
+
2. 添加新格式支持或改进现有解析器
|
78
|
+
3. 提交 Pull Request 并描述:
|
79
|
+
|
80
|
+
- 支持的新文件格式或所做的改进
|
81
|
+
- 使用各种文件样本进行测试
|
82
|
+
- 性能影响分析
|
83
|
+
- 文档更新
|
84
|
+
|
85
|
+
## 📌 说明
|
86
|
+
|
87
|
+
这是 LobeHub 的内部模块(`"private": true`),专为 LobeChat 设计,不作为独立包发布。
|
88
|
+
|
89
|
+
如果你对我们的项目感兴趣,欢迎在 [GitHub](https://github.com/lobehub/lobe-chat) 上查看、点赞或贡献代码!
|
package/src/app/[variants]/(main)/chat/(workspace)/_layout/Desktop/ChatHeader/HeaderAction.tsx
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
'use client';
|
2
2
|
|
3
|
-
import { ActionIcon
|
3
|
+
import { ActionIcon } from '@lobehub/ui';
|
4
4
|
import { PanelRightClose, PanelRightOpen } from 'lucide-react';
|
5
5
|
import { memo } from 'react';
|
6
6
|
import { useTranslation } from 'react-i18next';
|
@@ -30,13 +30,16 @@ const HeaderAction = memo<{ className?: string }>(({ className }) => {
|
|
30
30
|
return (
|
31
31
|
<Flexbox className={className} gap={4} horizontal>
|
32
32
|
<ShareButton />
|
33
|
-
<
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
33
|
+
<ActionIcon
|
34
|
+
icon={showAgentSettings ? PanelRightClose : PanelRightOpen}
|
35
|
+
onClick={() => toggleConfig()}
|
36
|
+
size={DESKTOP_HEADER_ICON_SIZE}
|
37
|
+
title={t('toggleRightPanel.title', { ns: 'hotkey' })}
|
38
|
+
tooltipProps={{
|
39
|
+
hotkey,
|
40
|
+
placement: 'bottom',
|
41
|
+
}}
|
42
|
+
/>
|
40
43
|
{isAgentEditable && <SettingButton />}
|
41
44
|
</Flexbox>
|
42
45
|
);
|
@@ -1,6 +1,6 @@
|
|
1
1
|
'use client';
|
2
2
|
|
3
|
-
import { ActionIcon
|
3
|
+
import { ActionIcon } from '@lobehub/ui';
|
4
4
|
import { AlignJustify } from 'lucide-react';
|
5
5
|
import dynamic from 'next/dynamic';
|
6
6
|
import { memo } from 'react';
|
@@ -25,13 +25,16 @@ const SettingButton = memo<{ mobile?: boolean }>(({ mobile }) => {
|
|
25
25
|
|
26
26
|
return (
|
27
27
|
<>
|
28
|
-
<
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
28
|
+
<ActionIcon
|
29
|
+
icon={AlignJustify}
|
30
|
+
onClick={() => openChatSettings()}
|
31
|
+
size={mobile ? MOBILE_HEADER_ICON_SIZE : DESKTOP_HEADER_ICON_SIZE}
|
32
|
+
title={t('openChatSettings.title', { ns: 'hotkey' })}
|
33
|
+
tooltipProps={{
|
34
|
+
hotkey,
|
35
|
+
placement: 'bottom',
|
36
|
+
}}
|
37
|
+
/>
|
35
38
|
<AgentSettings key={id} />
|
36
39
|
</>
|
37
40
|
);
|
@@ -31,6 +31,9 @@ const ShareButton = memo<ShareButtonProps>(({ mobile, setOpen, open }) => {
|
|
31
31
|
onClick={() => setIsModalOpen(true)}
|
32
32
|
size={mobile ? MOBILE_HEADER_ICON_SIZE : DESKTOP_HEADER_ICON_SIZE}
|
33
33
|
title={t('share')}
|
34
|
+
tooltipProps={{
|
35
|
+
placement: 'bottom',
|
36
|
+
}}
|
34
37
|
/>
|
35
38
|
<ShareModal onCancel={() => setIsModalOpen(false)} open={isModalOpen} />
|
36
39
|
</>
|
@@ -0,0 +1,126 @@
|
|
1
|
+
import { Icon } from '@lobehub/ui';
|
2
|
+
import { Tag } from 'antd';
|
3
|
+
import { createStyles } from 'antd-style';
|
4
|
+
import { Atom, Box, CircleSlash, Sparkle, Zap } from 'lucide-react';
|
5
|
+
import { CSSProperties, MouseEvent, memo } from 'react';
|
6
|
+
import { useTranslation } from 'react-i18next';
|
7
|
+
import { Center, Flexbox } from 'react-layout-kit';
|
8
|
+
|
9
|
+
import { Plans } from '@/types/subscription';
|
10
|
+
|
11
|
+
export const themes = {
|
12
|
+
[Plans.Free]: {
|
13
|
+
icon: CircleSlash,
|
14
|
+
theme: {
|
15
|
+
background: undefined,
|
16
|
+
color: undefined,
|
17
|
+
},
|
18
|
+
},
|
19
|
+
[Plans.Hobby]: {
|
20
|
+
icon: Box,
|
21
|
+
theme: {
|
22
|
+
background: 'linear-gradient(45deg, #21B2EE, #2271ED)',
|
23
|
+
color: '#E5F8FF',
|
24
|
+
},
|
25
|
+
},
|
26
|
+
[Plans.Starter]: {
|
27
|
+
icon: Sparkle,
|
28
|
+
theme: {
|
29
|
+
background: 'linear-gradient(45deg, #C57948, #803718)',
|
30
|
+
color: '#FFC385',
|
31
|
+
},
|
32
|
+
},
|
33
|
+
[Plans.Premium]: {
|
34
|
+
icon: Zap,
|
35
|
+
theme: {
|
36
|
+
background: 'linear-gradient(45deg, #A5B4C2, #606E7B)',
|
37
|
+
color: '#FCFDFF',
|
38
|
+
},
|
39
|
+
},
|
40
|
+
[Plans.Ultimate]: {
|
41
|
+
icon: Atom,
|
42
|
+
theme: {
|
43
|
+
background: 'linear-gradient(45deg, #F7A82F, #BB7227)',
|
44
|
+
color: '#FCFA6E',
|
45
|
+
},
|
46
|
+
},
|
47
|
+
};
|
48
|
+
|
49
|
+
const useStyles = createStyles(({ css, token }) => ({
|
50
|
+
icon: css`
|
51
|
+
flex: none;
|
52
|
+
border-radius: ${token.borderRadiusLG}px;
|
53
|
+
box-shadow: 0 0 0 1px ${token.colorFillSecondary};
|
54
|
+
`,
|
55
|
+
}));
|
56
|
+
|
57
|
+
interface PlanIconProps {
|
58
|
+
className?: string;
|
59
|
+
mono?: boolean;
|
60
|
+
onClick?: (e: MouseEvent) => void;
|
61
|
+
plan: Plans;
|
62
|
+
size?: number;
|
63
|
+
style?: CSSProperties;
|
64
|
+
type?: 'icon' | 'tag' | 'combine';
|
65
|
+
}
|
66
|
+
|
67
|
+
const PlanIcon = memo<PlanIconProps>(
|
68
|
+
({ type = 'icon', plan, size = 36, mono, style, className, onClick }) => {
|
69
|
+
const { icon, theme } = themes[plan];
|
70
|
+
const { cx, styles, theme: token } = useStyles();
|
71
|
+
const { t } = useTranslation('subscription');
|
72
|
+
const isTag = type === 'tag';
|
73
|
+
const isCombine = type === 'combine';
|
74
|
+
const isFree = plan === Plans.Free;
|
75
|
+
|
76
|
+
if (isTag) {
|
77
|
+
return (
|
78
|
+
<Tag
|
79
|
+
bordered={false}
|
80
|
+
className={className}
|
81
|
+
onClick={onClick}
|
82
|
+
style={{
|
83
|
+
...(theme || { background: token.colorFillSecondary, color: token.colorText }),
|
84
|
+
border: 'none',
|
85
|
+
borderRadius: 12,
|
86
|
+
cursor: 'pointer',
|
87
|
+
flex: 'none',
|
88
|
+
margin: 0,
|
89
|
+
...style,
|
90
|
+
}}
|
91
|
+
>
|
92
|
+
{t(`plans.plan.${plan}.title`)}
|
93
|
+
</Tag>
|
94
|
+
);
|
95
|
+
}
|
96
|
+
|
97
|
+
const iconContent = (
|
98
|
+
<Center
|
99
|
+
className={cx(styles.icon, className)}
|
100
|
+
height={size}
|
101
|
+
onClick={onClick}
|
102
|
+
style={
|
103
|
+
mono
|
104
|
+
? style
|
105
|
+
: { ...theme, border: isFree ? undefined : `2px solid ${theme.color}`, ...style }
|
106
|
+
}
|
107
|
+
width={size}
|
108
|
+
>
|
109
|
+
<Icon color={mono ? undefined : theme.color} icon={icon} size={size / 2} />
|
110
|
+
</Center>
|
111
|
+
);
|
112
|
+
|
113
|
+
if (isCombine) {
|
114
|
+
return (
|
115
|
+
<Flexbox align={'center'} gap={8} horizontal>
|
116
|
+
{iconContent}
|
117
|
+
<span>{t(`plans.plan.${plan}.title`)}</span>
|
118
|
+
</Flexbox>
|
119
|
+
);
|
120
|
+
}
|
121
|
+
|
122
|
+
return iconContent;
|
123
|
+
},
|
124
|
+
);
|
125
|
+
|
126
|
+
export default PlanIcon;
|
@@ -1,43 +1,51 @@
|
|
1
|
-
import { Tag
|
1
|
+
import { Tag } from '@lobehub/ui';
|
2
2
|
import { useTheme } from 'antd-style';
|
3
|
-
import
|
3
|
+
import Link from 'next/link';
|
4
|
+
import { memo } from 'react';
|
4
5
|
import { useTranslation } from 'react-i18next';
|
6
|
+
import urlJoin from 'url-join';
|
7
|
+
|
8
|
+
import { OFFICIAL_URL } from '@/const/url';
|
9
|
+
import { isDesktop } from '@/const/version';
|
10
|
+
import PlanIcon from '@/features/PlanIcon';
|
11
|
+
import { Plans } from '@/types/subscription';
|
5
12
|
|
6
13
|
export enum PlanType {
|
7
14
|
Preview = 'preview',
|
8
15
|
}
|
9
16
|
|
10
17
|
export interface PlanTagProps {
|
11
|
-
type?: PlanType;
|
18
|
+
type?: PlanType | Plans;
|
12
19
|
}
|
13
20
|
|
14
21
|
const PlanTag = memo<PlanTagProps>(({ type = PlanType.Preview }) => {
|
15
22
|
const { t } = useTranslation('common');
|
16
23
|
const theme = useTheme();
|
17
|
-
const tag: {
|
18
|
-
desc: string;
|
19
|
-
style: CSSProperties;
|
20
|
-
title: string;
|
21
|
-
} = useMemo(() => {
|
22
|
-
switch (type) {
|
23
|
-
case PlanType.Preview: {
|
24
|
-
return {
|
25
|
-
desc: t('userPanel.community'),
|
26
|
-
style: {
|
27
|
-
background: theme.colorFill,
|
28
|
-
},
|
29
|
-
title: 'Community',
|
30
|
-
};
|
31
|
-
}
|
32
|
-
}
|
33
|
-
}, []);
|
34
24
|
|
35
|
-
|
36
|
-
|
37
|
-
<Tag
|
38
|
-
{
|
25
|
+
if (type === PlanType.Preview) {
|
26
|
+
return (
|
27
|
+
<Tag
|
28
|
+
bordered={false}
|
29
|
+
style={{ background: theme.colorFill, borderRadius: 12, cursor: 'pointer' }}
|
30
|
+
>
|
31
|
+
{t('userPanel.community')}
|
39
32
|
</Tag>
|
40
|
-
|
33
|
+
);
|
34
|
+
}
|
35
|
+
|
36
|
+
const isFree = type === Plans.Free;
|
37
|
+
|
38
|
+
return (
|
39
|
+
<Link
|
40
|
+
href={urlJoin(
|
41
|
+
isDesktop ? OFFICIAL_URL : '/',
|
42
|
+
isFree ? '/subscription/plans' : '/subscription/usage',
|
43
|
+
)}
|
44
|
+
style={{ cursor: 'pointer' }}
|
45
|
+
target={isDesktop ? '_blank' : undefined}
|
46
|
+
>
|
47
|
+
<PlanIcon plan={type} size={22} type={'tag'} />
|
48
|
+
</Link>
|
41
49
|
);
|
42
50
|
});
|
43
51
|
|
@@ -1,4 +1,3 @@
|
|
1
|
-
import { log } from 'debug';
|
2
1
|
import { ClientOptions } from 'openai';
|
3
2
|
|
4
3
|
import type { TracePayload } from '@/const/trace';
|
@@ -112,13 +111,6 @@ class ModelRuntime {
|
|
112
111
|
LobeCloudflareParams & { apiKey?: string; apiVersion?: string; baseURL?: string }
|
113
112
|
>,
|
114
113
|
) {
|
115
|
-
// @ts-expect-error ignore
|
116
|
-
if (providerRuntimeMap[provider]) {
|
117
|
-
log('Provider runtime map found for provider: %s', provider);
|
118
|
-
} else {
|
119
|
-
log('Provider runtime map not found for provider: %s', provider);
|
120
|
-
}
|
121
|
-
|
122
114
|
// @ts-expect-error runtime map not include vertex so it will be undefined
|
123
115
|
const providerAI = providerRuntimeMap[provider] ?? LobeOpenAI;
|
124
116
|
const runtimeModel: LobeRuntimeAI = new providerAI(params);
|
@@ -22,6 +22,7 @@ import portal from './portal';
|
|
22
22
|
import providers from './providers';
|
23
23
|
import ragEval from './ragEval';
|
24
24
|
import setting from './setting';
|
25
|
+
import subscription from './subscription';
|
25
26
|
import thread from './thread';
|
26
27
|
import tool from './tool';
|
27
28
|
import topic from './topic';
|
@@ -52,6 +53,7 @@ const resources = {
|
|
52
53
|
providers,
|
53
54
|
ragEval,
|
54
55
|
setting,
|
56
|
+
subscription,
|
55
57
|
thread,
|
56
58
|
tool,
|
57
59
|
topic,
|
@@ -0,0 +1,24 @@
|
|
1
|
+
export default {
|
2
|
+
plans: {
|
3
|
+
plan: {
|
4
|
+
enterprise: {
|
5
|
+
title: '企业版',
|
6
|
+
},
|
7
|
+
free: {
|
8
|
+
title: '免费版',
|
9
|
+
},
|
10
|
+
hobby: {
|
11
|
+
title: '自助版',
|
12
|
+
},
|
13
|
+
premium: {
|
14
|
+
title: '进阶版',
|
15
|
+
},
|
16
|
+
starter: {
|
17
|
+
title: '基础版',
|
18
|
+
},
|
19
|
+
ultimate: {
|
20
|
+
title: '专业版',
|
21
|
+
},
|
22
|
+
},
|
23
|
+
},
|
24
|
+
};
|
@@ -1,5 +1,4 @@
|
|
1
1
|
import { createTRPCClient, httpLink } from '@trpc/client';
|
2
|
-
import debug from 'debug';
|
3
2
|
import superjson from 'superjson';
|
4
3
|
import urlJoin from 'url-join';
|
5
4
|
|
@@ -14,11 +13,7 @@ import { KeyVaultsGateKeeper } from '@/server/modules/KeyVaultsEncrypt';
|
|
14
13
|
import { asyncRouter } from './index';
|
15
14
|
import type { AsyncRouter } from './index';
|
16
15
|
|
17
|
-
const log = debug('lobe-image:async-caller');
|
18
|
-
|
19
16
|
export const createAsyncServerClient = async (userId: string, payload: JWTPayload) => {
|
20
|
-
log('Creating async server client for userId: %s', userId);
|
21
|
-
|
22
17
|
const gateKeeper = await KeyVaultsGateKeeper.initWithEnvKey();
|
23
18
|
const headers: Record<string, string> = {
|
24
19
|
Authorization: `Bearer ${serverDBEnv.KEY_VAULTS_SECRET}`,
|
@@ -39,7 +34,6 @@ export const createAsyncServerClient = async (userId: string, payload: JWTPayloa
|
|
39
34
|
],
|
40
35
|
});
|
41
36
|
|
42
|
-
log('Async server client created successfully for userId: %s', userId);
|
43
37
|
return client;
|
44
38
|
};
|
45
39
|
|
Binary file
|