Compare commits
No commits in common. "main" and "v4.14.2" have entirely different histories.
|
|
@ -0,0 +1,384 @@
|
|||
# Lexical Editor 文本解析一致性分析报告
|
||||
|
||||
## 执行摘要
|
||||
|
||||
通过对 `textToEditorState` 和 `editorStateToText` 函数的全面分析,发现了 **3 个确认的不一致性问题**,会导致用户保存后重新加载时看到与编辑器显示不同的内容。
|
||||
|
||||
### 严重问题总览
|
||||
|
||||
| 问题 | 严重性 | 影响 | 位置 |
|
||||
|------|--------|------|------|
|
||||
| 列表项尾部空格丢失 | 🔴 高 | 用户有意添加的空格被删除 | utils.ts:255 |
|
||||
| 有序列表序号重置 | 🔴 高 | 自定义序号变成连续序号 | utils.ts:257 |
|
||||
| 列表项内换行不对称 | 🟡 中 | 编辑器支持但无法往返 | processListItem |
|
||||
|
||||
---
|
||||
|
||||
## 问题 1: 列表项尾部空格丢失 🔴(已处理)
|
||||
|
||||
### 问题描述
|
||||
|
||||
在 `processListItem` 函数中使用了 `trim()` 处理列表项文本:
|
||||
|
||||
```typescript
|
||||
// utils.ts:255
|
||||
const itemTextString = itemText.join('').trim();
|
||||
```
|
||||
|
||||
### 不一致性演示
|
||||
|
||||
**用户输入:**
|
||||
```
|
||||
- hello world
|
||||
```
|
||||
(注意 "world" 后面有 2 个空格)
|
||||
|
||||
**EditorState:**
|
||||
```json
|
||||
{
|
||||
"type": "listitem",
|
||||
"children": [
|
||||
{ "type": "text", "text": "hello world " }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
**输出文本:**
|
||||
```
|
||||
- hello world
|
||||
```
|
||||
(尾部空格被 trim 删除)
|
||||
|
||||
**重新加载:**
|
||||
```
|
||||
- hello world
|
||||
```
|
||||
(用户的空格永久丢失)
|
||||
|
||||
### 影响分析
|
||||
|
||||
- **用户体验**: 用户有意添加的尾部空格(可能用于格式对齐)会丢失
|
||||
- **数据完整性**: 每次保存/加载循环都会丢失尾部空格
|
||||
- **严重程度**: 高 - 直接影响用户输入的完整性
|
||||
|
||||
### 解决方案
|
||||
|
||||
**方案 1: 移除 trim()**
|
||||
```typescript
|
||||
const itemTextString = itemText.join(''); // 不使用 trim
|
||||
```
|
||||
|
||||
**方案 2: 只移除前导空格**
|
||||
```typescript
|
||||
const itemTextString = itemText.join('').trimStart(); // 只移除开头空格
|
||||
```
|
||||
|
||||
**推荐**: 方案 1,完全保留用户输入的空格
|
||||
|
||||
---
|
||||
|
||||
## 问题 2: 有序列表序号重置 🔴
|
||||
|
||||
### 问题描述
|
||||
|
||||
在输出有序列表时,使用 `index + 1` 而不是列表项自身的 `value`:
|
||||
|
||||
```typescript
|
||||
// utils.ts:257
|
||||
const prefix = listType === 'bullet' ? '- ' : `${index + 1}. `;
|
||||
```
|
||||
|
||||
但在解析时,`numberValue` 被正确提取并存储到 `listItem.value`。
|
||||
|
||||
### 不一致性演示
|
||||
|
||||
**用户输入:**
|
||||
```
|
||||
1. first
|
||||
2. second
|
||||
5. fifth
|
||||
10. tenth
|
||||
```
|
||||
|
||||
**解析 (textToEditorState):**
|
||||
```javascript
|
||||
items = [
|
||||
{ numberValue: 1, text: "first" },
|
||||
{ numberValue: 2, text: "second" },
|
||||
{ numberValue: 5, text: "fifth" },
|
||||
{ numberValue: 10, text: "tenth" }
|
||||
]
|
||||
```
|
||||
|
||||
**EditorState:**
|
||||
```json
|
||||
[
|
||||
{ "value": 1, "text": "first" },
|
||||
{ "value": 2, "text": "second" },
|
||||
{ "value": 5, "text": "fifth" },
|
||||
{ "value": 10, "text": "tenth" }
|
||||
]
|
||||
```
|
||||
|
||||
**输出文本 (editorStateToText):**
|
||||
```
|
||||
1. first (index=0, 0+1=1) ✓
|
||||
2. second (index=1, 1+1=2) ✓
|
||||
3. fifth (index=2, 2+1=3) ✗ 应该是 5
|
||||
4. tenth (index=3, 3+1=4) ✗ 应该是 10
|
||||
```
|
||||
|
||||
**重新加载:**
|
||||
用户的自定义序号 5 和 10 永久丢失,变成连续的 3 和 4。
|
||||
|
||||
### 影响分析
|
||||
|
||||
- **用户体验**: 用户有意设置的序号被强制改为连续序号
|
||||
- **数据完整性**: 有序列表的语义丢失(如章节编号 1.1, 1.2, 2.1)
|
||||
- **严重程度**: 高 - 改变了用户的语义表达
|
||||
|
||||
### 解决方案
|
||||
|
||||
```typescript
|
||||
// utils.ts:257
|
||||
const prefix = listType === 'bullet'
|
||||
? '- '
|
||||
: `${listItem.value || index + 1}. `;
|
||||
```
|
||||
|
||||
使用 `listItem.value` 而不是 `index + 1`,保留原始序号。
|
||||
|
||||
---
|
||||
|
||||
## 问题 3: 列表项内换行不对称 🟡
|
||||
|
||||
### 问题描述
|
||||
|
||||
Lexical 编辑器允许在列表项内插入换行符 (`linebreak` 节点),但 `textToEditorState` 无法将包含换行的文本重新解析为列表项内换行。
|
||||
|
||||
### 不一致性演示
|
||||
|
||||
**用户在编辑器中操作:**
|
||||
```
|
||||
1. 输入: "- item1"
|
||||
2. 按 Shift+Enter (插入软换行)
|
||||
3. 继续输入: "continued content"
|
||||
```
|
||||
|
||||
**EditorState:**
|
||||
```json
|
||||
{
|
||||
"type": "listitem",
|
||||
"children": [
|
||||
{ "type": "text", "text": "item1" },
|
||||
{ "type": "linebreak" },
|
||||
{ "type": "text", "text": "continued content" }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
**输出文本 (editorStateToText):**
|
||||
```
|
||||
- item1
|
||||
continued content
|
||||
```
|
||||
|
||||
**重新加载 (textToEditorState):**
|
||||
```
|
||||
行1: "- item1" → 列表项
|
||||
行2: "continued content" → 段落 (不再是列表项的一部分!)
|
||||
```
|
||||
|
||||
**最终结构变化:**
|
||||
```
|
||||
原来: 1个列表项(包含换行)
|
||||
现在: 1个列表项 + 1个段落
|
||||
```
|
||||
|
||||
### 影响分析
|
||||
|
||||
- **结构完整性**: 列表项的内部结构在保存/加载后改变
|
||||
- **语义丢失**: 原本属于列表项的内容变成了独立段落
|
||||
- **严重程度**: 中 - 影响文档结构,但可能符合 Markdown 语义
|
||||
|
||||
### 解决方案
|
||||
|
||||
**方案 1: 在输出时将换行转为空格**
|
||||
```typescript
|
||||
if (child.type === 'linebreak') {
|
||||
itemText.push(' '); // 使用空格而不是 \n
|
||||
}
|
||||
```
|
||||
|
||||
**方案 2: 在编辑器中禁止列表项内换行**
|
||||
- 配置 Lexical 不允许在列表项内插入 linebreak
|
||||
- 用户只能通过创建新列表项来换行
|
||||
|
||||
**方案 3: 支持 Markdown 风格的列表项多行**
|
||||
```typescript
|
||||
// 识别缩进的行为列表项的继续内容
|
||||
parseTextLine:
|
||||
if (line.startsWith(' ') && prevLine.wasListItem) {
|
||||
// 作为列表项的继续内容
|
||||
}
|
||||
```
|
||||
|
||||
**推荐**: 方案 1 (最简单) 或方案 2 (最明确)
|
||||
|
||||
---
|
||||
|
||||
## 其他潜在问题
|
||||
|
||||
### 问题 4: 变量节点保存后变成普通文本 🟡
|
||||
|
||||
**现象**:
|
||||
```
|
||||
EditorState: { type: 'variableLabel', variableKey: '{{var1}}' }
|
||||
↓
|
||||
输出文本: "{{var1}}"
|
||||
↓
|
||||
重新加载: { type: 'text', text: "{{var1}}" }
|
||||
```
|
||||
|
||||
**影响**: 变量节点的功能性丢失
|
||||
|
||||
**分析**: 这可能是设计决策 - 变量只在编辑会话中有效,保存到文本后变成普通占位符。如果需要保持变量功能,应该使用其他存储格式(如 JSON)而不是纯文本。
|
||||
|
||||
### 问题 5: 非连续缩进级别可能导致结构错误 🟡
|
||||
|
||||
**现象**:
|
||||
```
|
||||
输入:
|
||||
- level 0
|
||||
- level 2 (跳过 level 1)
|
||||
- level 1
|
||||
```
|
||||
|
||||
**问题**: `buildListStructure` 可能无法正确处理非连续的缩进级别
|
||||
|
||||
**影响**: 列表嵌套结构可能不符合预期
|
||||
|
||||
**建议**: 规范化缩进级别,或在文档中说明只支持连续缩进
|
||||
|
||||
---
|
||||
|
||||
## 正常运作的部分 ✅
|
||||
|
||||
经过分析,以下功能**正常运作**,不存在一致性问题:
|
||||
|
||||
1. **空行处理** - 空行被正确保留和还原
|
||||
2. **段落前导空格** - 修复后完全保留
|
||||
3. **列表和段落边界** - 正确识别和分离
|
||||
4. **特殊字符在段落中** - 只有行首的 `- ` 和 `\d+. ` 被识别为列表
|
||||
5. **混合列表类型** - bullet 和 number 列表正确分离
|
||||
6. **列表缩进** - 使用 TabStr 统一为 2 个空格
|
||||
|
||||
---
|
||||
|
||||
## 测试用例建议
|
||||
|
||||
### 测试用例 1: 列表项尾部空格
|
||||
```typescript
|
||||
const input = "- hello world "; // 2个尾部空格
|
||||
const state = textToEditorState(input, true);
|
||||
const editor = createEditorWithState(state);
|
||||
const output = editorStateToText(editor);
|
||||
expect(output).toBe("- hello world "); // 应保留空格
|
||||
```
|
||||
|
||||
### 测试用例 2: 自定义列表序号
|
||||
```typescript
|
||||
const input = "1. first\n5. fifth\n10. tenth";
|
||||
const state = textToEditorState(input, true);
|
||||
const editor = createEditorWithState(state);
|
||||
const output = editorStateToText(editor);
|
||||
expect(output).toBe("1. first\n5. fifth\n10. tenth"); // 应保留序号
|
||||
```
|
||||
|
||||
### 测试用例 3: 列表项换行
|
||||
```typescript
|
||||
// 在编辑器中创建列表项并插入 linebreak
|
||||
const editor = createEditor();
|
||||
// ... 创建列表项
|
||||
// ... 插入 linebreak
|
||||
const output = editorStateToText(editor);
|
||||
const reloadedState = textToEditorState(output, true);
|
||||
const reloadedEditor = createEditorWithState(reloadedState);
|
||||
// 验证结构是否一致
|
||||
expect(getStructure(editor)).toEqual(getStructure(reloadedEditor));
|
||||
```
|
||||
|
||||
### 测试用例 4: 往返对称性
|
||||
```typescript
|
||||
const testCases = [
|
||||
"simple text",
|
||||
" indented text",
|
||||
"- bullet list\n - nested",
|
||||
"1. first\n2. second\n5. fifth",
|
||||
"text\n\n\nwith\n\nempty\n\nlines",
|
||||
"- item ", // 尾部空格
|
||||
];
|
||||
|
||||
testCases.forEach(input => {
|
||||
const state = textToEditorState(input, true);
|
||||
const editor = createEditorWithState(state);
|
||||
const output = editorStateToText(editor);
|
||||
expect(output).toBe(input); // 应完全一致
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 修复优先级建议
|
||||
|
||||
### P0 - 立即修复
|
||||
1. ✅ **列表项尾部空格丢失** - 影响数据完整性
|
||||
2. ✅ **有序列表序号重置** - 影响语义表达
|
||||
|
||||
### P1 - 高优先级
|
||||
3. ⚠️ **列表项内换行不对称** - 影响结构一致性
|
||||
|
||||
### P2 - 按需修复
|
||||
4. 📝 **变量节点** - 根据产品需求决定
|
||||
5. 📝 **非连续缩进** - 文档说明或规范化处理
|
||||
|
||||
---
|
||||
|
||||
## 代码修改建议
|
||||
|
||||
### 修改 1: 保留列表项空格
|
||||
```diff
|
||||
// utils.ts:255
|
||||
- const itemTextString = itemText.join('').trim();
|
||||
+ const itemTextString = itemText.join('');
|
||||
```
|
||||
|
||||
### 修改 2: 使用原始列表序号
|
||||
```diff
|
||||
// utils.ts:257
|
||||
- const prefix = listType === 'bullet' ? '- ' : `${index + 1}. `;
|
||||
+ const prefix = listType === 'bullet' ? '- ' : `${listItem.value || index + 1}. `;
|
||||
```
|
||||
|
||||
### 修改 3: 处理列表项换行(方案1)
|
||||
```diff
|
||||
// utils.ts:242
|
||||
if (child.type === 'linebreak') {
|
||||
- itemText.push('\n');
|
||||
+ itemText.push(' '); // 转为空格而不是换行
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 总结
|
||||
|
||||
通过全面分析,确认了 **3 个会导致编辑器显示与解析文本不一致的问题**:
|
||||
|
||||
1. 🔴 列表项尾部空格丢失 → 修复: 移除 trim()
|
||||
2. 🔴 有序列表序号重置 → 修复: 使用 listItem.value
|
||||
3. 🟡 列表项内换行不对称 → 修复: 转换为空格或禁止
|
||||
|
||||
其他方面(空行、前导空格、边界处理)都运作正常。
|
||||
|
||||
建议优先修复前两个 P0 问题,确保用户数据的完整性和语义准确性。
|
||||
|
|
@ -608,6 +608,136 @@ function App({ Component, pageProps }: AppPropsWithLayout) {
|
|||
|
||||
---
|
||||
|
||||
### 🔴 H9. instrumentation.ts 初始化失败未处理,导致静默失败
|
||||
|
||||
**位置**: `projects/app/src/instrumentation.ts:81-84`
|
||||
|
||||
**问题描述**:
|
||||
```typescript
|
||||
} catch (error) {
|
||||
console.log('Init system error', error);
|
||||
exit(1);
|
||||
}
|
||||
```
|
||||
- 初始化失败直接退出进程
|
||||
- 部分初始化错误被 `.catch()` 吞没
|
||||
- 缺少初始化状态检查
|
||||
|
||||
**风险等级**: 🔴 高危
|
||||
|
||||
**影响**:
|
||||
- 应用启动失败但无明确错误信息
|
||||
- 部分服务未初始化导致运行时错误
|
||||
- 调试困难
|
||||
|
||||
**建议方案**:
|
||||
```typescript
|
||||
// 1. 详细的初始化错误处理
|
||||
export async function register() {
|
||||
const initSteps: Array<{
|
||||
name: string;
|
||||
fn: () => Promise<void>;
|
||||
required: boolean;
|
||||
}> = [];
|
||||
|
||||
try {
|
||||
if (process.env.NEXT_RUNTIME !== 'nodejs') {
|
||||
return;
|
||||
}
|
||||
|
||||
const results = {
|
||||
success: [] as string[],
|
||||
failed: [] as Array<{ name: string; error: any }>
|
||||
};
|
||||
|
||||
// 阶段 1: 基础连接 (必需)
|
||||
try {
|
||||
console.log('Connecting to MongoDB...');
|
||||
await connectMongo({ db: connectionMongo, url: MONGO_URL });
|
||||
results.success.push('MongoDB Main');
|
||||
} catch (error) {
|
||||
console.error('Fatal: MongoDB connection failed', error);
|
||||
throw error;
|
||||
}
|
||||
|
||||
try {
|
||||
await connectMongo({ db: connectionLogMongo, url: MONGO_LOG_URL });
|
||||
results.success.push('MongoDB Log');
|
||||
} catch (error) {
|
||||
console.warn('Non-fatal: MongoDB Log connection failed', error);
|
||||
results.failed.push({ name: 'MongoDB Log', error });
|
||||
}
|
||||
|
||||
// 阶段 2: 系统初始化 (必需)
|
||||
try {
|
||||
console.log('Initializing system config...');
|
||||
await Promise.all([
|
||||
getInitConfig(),
|
||||
initVectorStore(),
|
||||
initRootUser(),
|
||||
loadSystemModels()
|
||||
]);
|
||||
results.success.push('System Config');
|
||||
} catch (error) {
|
||||
console.error('Fatal: System initialization failed', error);
|
||||
throw error;
|
||||
}
|
||||
|
||||
// 阶段 3: 可选服务
|
||||
await Promise.allSettled([
|
||||
preLoadWorker().catch(e => {
|
||||
console.warn('Worker preload failed (non-fatal)', e);
|
||||
results.failed.push({ name: 'Worker Preload', error: e });
|
||||
}),
|
||||
getSystemTools().catch(e => {
|
||||
console.warn('System tools init failed (non-fatal)', e);
|
||||
results.failed.push({ name: 'System Tools', error: e });
|
||||
}),
|
||||
initSystemPluginGroups().catch(e => {
|
||||
console.warn('Plugin groups init failed (non-fatal)', e);
|
||||
results.failed.push({ name: 'Plugin Groups', error: e });
|
||||
})
|
||||
]);
|
||||
|
||||
// 阶段 4: 后台任务
|
||||
startCron();
|
||||
startTrainingQueue(true);
|
||||
trackTimerProcess();
|
||||
|
||||
console.log('Init system success', {
|
||||
success: results.success,
|
||||
failed: results.failed.map(f => f.name)
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error('Init system critical error', error);
|
||||
console.error('Stack:', error.stack);
|
||||
|
||||
// 发送告警通知
|
||||
if (process.env.ERROR_WEBHOOK_URL) {
|
||||
try {
|
||||
await fetch(process.env.ERROR_WEBHOOK_URL, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
type: 'INIT_ERROR',
|
||||
error: error.message,
|
||||
stack: error.stack,
|
||||
timestamp: new Date().toISOString()
|
||||
})
|
||||
});
|
||||
} catch (webhookError) {
|
||||
console.error('Failed to send error webhook', webhookError);
|
||||
}
|
||||
}
|
||||
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 二、中危问题 (Medium Priority)
|
||||
|
||||
### 🟡 M1. Next.js 未启用 SWC 编译优化完整特性
|
||||
|
|
|
|||
|
|
@ -934,6 +934,28 @@ export const authCertWithCSRF = async (props: AuthModeType) => {
|
|||
|
||||
## 新增中危问题 (Additional Medium Priority)
|
||||
|
||||
### 🟡 M20. 向量查询缓存策略过于激进
|
||||
|
||||
**位置**: `packages/service/common/vectorDB/controller.ts:29-35`
|
||||
|
||||
**问题描述**:
|
||||
```typescript
|
||||
const onDelCache = throttle((teamId: string) => delRedisCache(getChcheKey(teamId)), 30000, {
|
||||
leading: true,
|
||||
trailing: true
|
||||
});
|
||||
```
|
||||
- 删除操作使用 throttle,30 秒内只执行一次
|
||||
- 可能导致缓存计数不准确
|
||||
- 未考虑高频删除场景
|
||||
|
||||
**建议**:
|
||||
- 删除操作直接更新缓存
|
||||
- 定期全量同步缓存和数据库
|
||||
- 添加缓存一致性校验
|
||||
|
||||
---
|
||||
|
||||
### 🟡 M21. 训练队列缺少优先级机制
|
||||
|
||||
**位置**: `packages/service/common/bullmq/index.ts:20-26`
|
||||
|
|
|
|||
|
|
@ -1,672 +0,0 @@
|
|||
---
|
||||
name: workflow-stop-design
|
||||
description: 工作流暂停逻辑设计方案
|
||||
---
|
||||
|
||||
## 1. Redis 状态管理方案
|
||||
|
||||
### 1.1 状态键设计
|
||||
|
||||
**Redis Key 结构:**
|
||||
```typescript
|
||||
// Key 格式: agent_runtime_stopping:{appId}:{chatId}
|
||||
const WORKFLOW_STATUS_PREFIX = 'agent_runtime_stopping';
|
||||
|
||||
type WorkflowStatusKey = `${typeof WORKFLOW_STATUS_PREFIX}:${string}:${string}`;
|
||||
|
||||
// 示例: agent_runtime_stopping:app_123456:chat_789012
|
||||
```
|
||||
|
||||
**状态值设计:**
|
||||
- **存在键 (值为 1)**: 工作流应该停止
|
||||
- **不存在键**: 工作流正常运行
|
||||
- **设计简化**: 不使用状态枚举,仅通过键的存在与否判断
|
||||
|
||||
**参数类型定义:**
|
||||
```typescript
|
||||
type WorkflowStatusParams = {
|
||||
appId: string;
|
||||
chatId: string;
|
||||
};
|
||||
```
|
||||
|
||||
### 1.2 状态生命周期管理
|
||||
|
||||
**状态转换流程:**
|
||||
```
|
||||
正常运行(无键) → 停止中(键存在) → 完成(删除键)
|
||||
```
|
||||
|
||||
**TTL 设置:**
|
||||
- **停止标志 TTL**: 60 秒
|
||||
- 原因: 避免因意外情况导致的键泄漏
|
||||
- 正常情况下会在工作流完成时主动删除
|
||||
- **工作流完成后**: 直接删除 Redis 键
|
||||
- 原因: 不需要保留终态,减少 Redis 内存占用
|
||||
|
||||
### 1.3 核心函数说明
|
||||
|
||||
**1. setAgentRuntimeStop**
|
||||
- **功能**: 设置停止标志
|
||||
- **参数**: `{ appId, chatId }`
|
||||
- **实现**: 使用 `SETEX` 命令,设置键值为 1,TTL 60 秒
|
||||
|
||||
**2. shouldWorkflowStop**
|
||||
- **功能**: 检查工作流是否应该停止
|
||||
- **参数**: `{ appId, chatId }`
|
||||
- **返回**: `Promise<boolean>` - true=应该停止, false=继续运行
|
||||
- **实现**: GET 命令获取键值,存在则返回 true
|
||||
|
||||
**3. delAgentRuntimeStopSign**
|
||||
- **功能**: 删除停止标志
|
||||
- **参数**: `{ appId, chatId }`
|
||||
- **实现**: DEL 命令删除键
|
||||
|
||||
**4. waitForWorkflowComplete**
|
||||
- **功能**: 等待工作流完成(停止标志被删除)
|
||||
- **参数**: `{ appId, chatId, timeout?, pollInterval? }`
|
||||
- **实现**: 轮询检查停止标志是否被删除,超时返回
|
||||
|
||||
### 1.4 边界情况处理
|
||||
|
||||
**1. Redis 操作失败**
|
||||
- **错误处理**: 所有 Redis 操作都包含 `.catch()` 错误处理
|
||||
- **降级策略**:
|
||||
- `shouldWorkflowStop`: 出错时返回 `false` (认为不需要停止,继续运行)
|
||||
- `delAgentRuntimeStopSign`: 出错时记录错误日志,但不影响主流程
|
||||
- **设计原因**: Redis 异常不应阻塞工作流运行,降级到继续执行策略
|
||||
|
||||
**2. TTL 自动清理**
|
||||
- **TTL 设置**: 60 秒
|
||||
- **清理时机**: Redis 自动清理过期键
|
||||
- **设计原因**:
|
||||
- 避免因异常情况导致的 Redis 键泄漏
|
||||
- 自动清理减少手动维护成本
|
||||
- 60 秒足够大多数工作流完成停止操作
|
||||
|
||||
**3. stop 接口等待超时**
|
||||
- **超时时间**: 5 秒
|
||||
- **超时策略**: `waitForWorkflowComplete` 在 5 秒内轮询检查停止标志是否被删除
|
||||
- **超时处理**: 5 秒后直接返回,不影响工作流继续执行
|
||||
- **设计原因**:
|
||||
- 避免前端长时间等待
|
||||
- 5 秒足够大多数节点完成当前操作
|
||||
- 用户体验优先,超时后前端可选择重试或放弃
|
||||
|
||||
**4. 并发停止请求**
|
||||
- **处理方式**: 多次调用 `setAgentRuntimeStop` 是安全的,Redis SETEX 是幂等操作
|
||||
- **设计原因**: 避免用户多次点击停止按钮导致的问题
|
||||
|
||||
---
|
||||
|
||||
## 2. Redis 工具函数实现
|
||||
|
||||
**位置**: `packages/service/core/workflow/dispatch/workflowStatus.ts`
|
||||
|
||||
```typescript
|
||||
import { addLog } from '../../../common/system/log';
|
||||
import { getGlobalRedisConnection } from '../../../common/redis/index';
|
||||
import { delay } from '@fastgpt/global/common/system/utils';
|
||||
|
||||
const WORKFLOW_STATUS_PREFIX = 'agent_runtime_stopping';
|
||||
const TTL = 60; // 60秒
|
||||
|
||||
export const StopStatus = 'STOPPING';
|
||||
|
||||
export type WorkflowStatusParams = {
|
||||
appId: string;
|
||||
chatId: string;
|
||||
};
|
||||
|
||||
// 获取工作流状态键
|
||||
export const getRuntimeStatusKey = (params: WorkflowStatusParams): string => {
|
||||
return `${WORKFLOW_STATUS_PREFIX}:${params.appId}:${params.chatId}`;
|
||||
};
|
||||
|
||||
// 设置停止标志
|
||||
export const setAgentRuntimeStop = async (params: WorkflowStatusParams): Promise<void> => {
|
||||
const redis = getGlobalRedisConnection();
|
||||
const key = getRuntimeStatusKey(params);
|
||||
await redis.setex(key, TTL, 1);
|
||||
};
|
||||
|
||||
// 删除停止标志
|
||||
export const delAgentRuntimeStopSign = async (params: WorkflowStatusParams): Promise<void> => {
|
||||
const redis = getGlobalRedisConnection();
|
||||
const key = getRuntimeStatusKey(params);
|
||||
await redis.del(key).catch((err) => {
|
||||
addLog.error(`[Agent Runtime Stop] Delete stop sign error`, err);
|
||||
});
|
||||
};
|
||||
|
||||
// 检查工作流是否应该停止
|
||||
export const shouldWorkflowStop = (params: WorkflowStatusParams): Promise<boolean> => {
|
||||
const redis = getGlobalRedisConnection();
|
||||
const key = getRuntimeStatusKey(params);
|
||||
return redis
|
||||
.get(key)
|
||||
.then((res) => !!res)
|
||||
.catch(() => false);
|
||||
};
|
||||
|
||||
/**
|
||||
* 等待工作流完成(停止标志被删除)
|
||||
* @param params 工作流参数
|
||||
* @param timeout 超时时间(毫秒),默认5秒
|
||||
* @param pollInterval 轮询间隔(毫秒),默认50毫秒
|
||||
*/
|
||||
export const waitForWorkflowComplete = async ({
|
||||
appId,
|
||||
chatId,
|
||||
timeout = 5000,
|
||||
pollInterval = 50
|
||||
}: {
|
||||
appId: string;
|
||||
chatId: string;
|
||||
timeout?: number;
|
||||
pollInterval?: number;
|
||||
}) => {
|
||||
const startTime = Date.now();
|
||||
|
||||
while (Date.now() - startTime < timeout) {
|
||||
const sign = await shouldWorkflowStop({ appId, chatId });
|
||||
|
||||
// 如果停止标志已被删除,说明工作流已完成
|
||||
if (!sign) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 等待下一次轮询
|
||||
await delay(pollInterval);
|
||||
}
|
||||
|
||||
// 超时后直接返回
|
||||
return;
|
||||
};
|
||||
```
|
||||
|
||||
**测试用例位置**: `test/cases/service/core/app/workflow/workflowStatus.test.ts`
|
||||
|
||||
```typescript
|
||||
import { describe, test, expect, beforeEach } from 'vitest';
|
||||
import {
|
||||
setAgentRuntimeStop,
|
||||
delAgentRuntimeStopSign,
|
||||
shouldWorkflowStop,
|
||||
waitForWorkflowComplete
|
||||
} from '@fastgpt/service/core/workflow/dispatch/workflowStatus';
|
||||
|
||||
describe('Workflow Status Redis Functions', () => {
|
||||
const testAppId = 'test_app_123';
|
||||
const testChatId = 'test_chat_456';
|
||||
|
||||
beforeEach(async () => {
|
||||
// 清理测试数据
|
||||
await delAgentRuntimeStopSign({ appId: testAppId, chatId: testChatId });
|
||||
});
|
||||
|
||||
test('should set stopping sign', async () => {
|
||||
await setAgentRuntimeStop({ appId: testAppId, chatId: testChatId });
|
||||
const shouldStop = await shouldWorkflowStop({ appId: testAppId, chatId: testChatId });
|
||||
expect(shouldStop).toBe(true);
|
||||
});
|
||||
|
||||
test('should return false for non-existent status', async () => {
|
||||
const shouldStop = await shouldWorkflowStop({ appId: testAppId, chatId: testChatId });
|
||||
expect(shouldStop).toBe(false);
|
||||
});
|
||||
|
||||
test('should return false after deleting stop sign', async () => {
|
||||
await setAgentRuntimeStop({ appId: testAppId, chatId: testChatId });
|
||||
await delAgentRuntimeStopSign({ appId: testAppId, chatId: testChatId });
|
||||
const shouldStop = await shouldWorkflowStop({ appId: testAppId, chatId: testChatId });
|
||||
expect(shouldStop).toBe(false);
|
||||
});
|
||||
|
||||
test('should wait for workflow completion', async () => {
|
||||
// 设置初始停止标志
|
||||
await setAgentRuntimeStop({ appId: testAppId, chatId: testChatId });
|
||||
|
||||
// 模拟异步完成(删除停止标志)
|
||||
setTimeout(async () => {
|
||||
await delAgentRuntimeStopSign({ appId: testAppId, chatId: testChatId });
|
||||
}, 500);
|
||||
|
||||
// 等待完成
|
||||
await waitForWorkflowComplete({
|
||||
appId: testAppId,
|
||||
chatId: testChatId,
|
||||
timeout: 2000
|
||||
});
|
||||
|
||||
// 验证停止标志已被删除
|
||||
const shouldStop = await shouldWorkflowStop({ appId: testAppId, chatId: testChatId });
|
||||
expect(shouldStop).toBe(false);
|
||||
});
|
||||
|
||||
test('should timeout when waiting too long', async () => {
|
||||
await setAgentRuntimeStop({ appId: testAppId, chatId: testChatId });
|
||||
|
||||
// 等待超时(不删除标志)
|
||||
await waitForWorkflowComplete({
|
||||
appId: testAppId,
|
||||
chatId: testChatId,
|
||||
timeout: 100
|
||||
});
|
||||
|
||||
// 验证停止标志仍然存在
|
||||
const shouldStop = await shouldWorkflowStop({ appId: testAppId, chatId: testChatId });
|
||||
expect(shouldStop).toBe(true);
|
||||
});
|
||||
|
||||
test('should handle concurrent stop sign operations', async () => {
|
||||
// 并发设置停止标志
|
||||
await Promise.all([
|
||||
setAgentRuntimeStop({ appId: testAppId, chatId: testChatId }),
|
||||
setAgentRuntimeStop({ appId: testAppId, chatId: testChatId })
|
||||
]);
|
||||
|
||||
// 停止标志应该存在
|
||||
const shouldStop = await shouldWorkflowStop({ appId: testAppId, chatId: testChatId });
|
||||
expect(shouldStop).toBe(true);
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
## 3. 工作流停止检测机制改造
|
||||
|
||||
### 3.1 修改位置
|
||||
|
||||
**文件**: `packages/service/core/workflow/dispatch/index.ts`
|
||||
|
||||
### 3.2 工作流启动时的停止检测机制
|
||||
|
||||
**改造点 1: 停止检测逻辑 (行 196-216)**
|
||||
|
||||
使用内存变量 + 定时轮询 Redis 的方式:
|
||||
|
||||
```typescript
|
||||
import { delAgentRuntimeStopSign, shouldWorkflowStop } from './workflowStatus';
|
||||
|
||||
// 初始化停止检测
|
||||
let stopping = false;
|
||||
const checkIsStopping = (): boolean => {
|
||||
if (apiVersion === 'v2') {
|
||||
return stopping;
|
||||
}
|
||||
if (apiVersion === 'v1') {
|
||||
if (!res) return false;
|
||||
return res.closed || !!res.errored;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
// v2 版本: 启动定时器定期检查 Redis
|
||||
const checkStoppingTimer =
|
||||
apiVersion === 'v2'
|
||||
? setInterval(async () => {
|
||||
stopping = await shouldWorkflowStop({
|
||||
appId: runningAppInfo.id,
|
||||
chatId
|
||||
});
|
||||
}, 100)
|
||||
: undefined;
|
||||
```
|
||||
|
||||
**设计要点**:
|
||||
- v2 版本使用内存变量 `stopping` + 100ms 定时器轮询 Redis
|
||||
- v1 版本仍使用原有的 `res.closed/res.errored` 检测
|
||||
- 轮询频率 100ms,平衡性能和响应速度
|
||||
|
||||
**改造点 2: 工作流完成后清理 (行 232-249)**
|
||||
|
||||
```typescript
|
||||
return runWorkflow({
|
||||
...data,
|
||||
checkIsStopping, // 传递检测函数
|
||||
query,
|
||||
histories,
|
||||
// ... 其他参数
|
||||
}).finally(async () => {
|
||||
// 清理定时器
|
||||
if (streamCheckTimer) {
|
||||
clearInterval(streamCheckTimer);
|
||||
}
|
||||
if (checkStoppingTimer) {
|
||||
clearInterval(checkStoppingTimer);
|
||||
}
|
||||
|
||||
// Close mcpClient connections
|
||||
Object.values(mcpClientMemory).forEach((client) => {
|
||||
client.closeConnection();
|
||||
});
|
||||
|
||||
// 工作流完成后删除 Redis 记录
|
||||
await delAgentRuntimeStopSign({
|
||||
appId: runningAppInfo.id,
|
||||
chatId
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
### 3.3 节点执行前的停止检测
|
||||
|
||||
**位置**: `packages/service/core/workflow/dispatch/index.ts:861-868`
|
||||
|
||||
在 `checkNodeCanRun` 方法中,每个节点执行前检查:
|
||||
|
||||
```typescript
|
||||
private async checkNodeCanRun(
|
||||
node: RuntimeNodeItemType,
|
||||
skippedNodeIdList = new Set<string>()
|
||||
) {
|
||||
// ... 其他检查逻辑 ...
|
||||
|
||||
// Check queue status
|
||||
if (data.maxRunTimes <= 0) {
|
||||
addLog.error('Max run times is 0', {
|
||||
appId: data.runningAppInfo.id
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// 停止检测
|
||||
if (checkIsStopping()) {
|
||||
addLog.warn('Workflow stopped', {
|
||||
appId: data.runningAppInfo.id,
|
||||
nodeId: node.nodeId,
|
||||
nodeName: node.name
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// ... 执行节点逻辑 ...
|
||||
}
|
||||
```
|
||||
|
||||
**说明**:
|
||||
- 直接调用 `checkIsStopping()` 同步方法
|
||||
- 内部会检查内存变量 `stopping`
|
||||
- 定时器每 100ms 更新一次该变量
|
||||
- 检测到停止时记录日志并直接返回,不执行节点
|
||||
|
||||
## 4. v2/chat/stop 接口设计
|
||||
|
||||
### 4.1 接口规范
|
||||
|
||||
**接口路径**: `/api/v2/chat/stop`
|
||||
|
||||
**Schema 位置**: `packages/global/openapi/core/chat/api.ts`
|
||||
|
||||
**接口文档位置**: `packages/global/openapi/core/chat/index.ts`
|
||||
|
||||
**请求方法**: POST
|
||||
|
||||
**请求参数**:
|
||||
```typescript
|
||||
// packages/global/openapi/core/chat/api.ts
|
||||
export const StopV2ChatSchema = z
|
||||
.object({
|
||||
appId: ObjectIdSchema.describe('应用ID'),
|
||||
chatId: z.string().min(1).describe('对话ID'),
|
||||
outLinkAuthData: OutLinkChatAuthSchema.optional().describe('外链鉴权数据')
|
||||
});
|
||||
|
||||
export type StopV2ChatParams = z.infer<typeof StopV2ChatSchema>;
|
||||
```
|
||||
|
||||
**响应格式**:
|
||||
```typescript
|
||||
export const StopV2ChatResponseSchema = z
|
||||
.object({
|
||||
success: z.boolean().describe('是否成功停止')
|
||||
});
|
||||
|
||||
export type StopV2ChatResponse = z.infer<typeof StopV2ChatResponseSchema>;
|
||||
```
|
||||
|
||||
### 4.2 接口实现
|
||||
|
||||
**文件位置**: `projects/app/src/pages/api/v2/chat/stop.ts`
|
||||
|
||||
```typescript
|
||||
import type { NextApiRequest, NextApiResponse } from 'next';
|
||||
import { NextAPI } from '@/service/middleware/entry';
|
||||
import { authChatCrud } from '@/service/support/permission/auth/chat';
|
||||
import {
|
||||
setAgentRuntimeStop,
|
||||
waitForWorkflowComplete
|
||||
} from '@fastgpt/service/core/workflow/dispatch/workflowStatus';
|
||||
import { StopV2ChatSchema, type StopV2ChatResponse } from '@fastgpt/global/openapi/core/chat/controler/api';
|
||||
|
||||
async function handler(req: NextApiRequest, res: NextApiResponse): Promise<StopV2ChatResponse> {
|
||||
const { appId, chatId, outLinkAuthData } = StopV2ChatSchema.parse(req.body);
|
||||
|
||||
// 鉴权 (复用聊天 CRUD 鉴权)
|
||||
await authChatCrud({
|
||||
req,
|
||||
authToken: true,
|
||||
authApiKey: true,
|
||||
appId,
|
||||
chatId,
|
||||
...outLinkAuthData
|
||||
});
|
||||
|
||||
// 设置停止标志
|
||||
await setAgentRuntimeStop({
|
||||
appId,
|
||||
chatId
|
||||
});
|
||||
|
||||
// 等待工作流完成 (最多等待 5 秒)
|
||||
await waitForWorkflowComplete({ appId, chatId, timeout: 5000 });
|
||||
|
||||
return {
|
||||
success: true
|
||||
};
|
||||
}
|
||||
|
||||
export default NextAPI(handler);
|
||||
```
|
||||
|
||||
**接口文档** (`packages/global/openapi/core/chat/index.ts`):
|
||||
|
||||
```typescript
|
||||
export const ChatPath: OpenAPIPath = {
|
||||
// ... 其他路径
|
||||
|
||||
'/v2/chat/stop': {
|
||||
post: {
|
||||
summary: '停止 Agent 运行',
|
||||
description: `优雅停止正在运行的 Agent, 会尝试等待当前节点结束后返回,最长 5s,超过 5s 仍未结束,则会返回成功。
|
||||
LLM 节点,流输出时会同时被终止,但 HTTP 请求节点这种可能长时间运行的,不会被终止。`,
|
||||
tags: [TagsMap.chatPage],
|
||||
requestBody: {
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: StopV2ChatSchema
|
||||
}
|
||||
}
|
||||
},
|
||||
responses: {
|
||||
200: {
|
||||
description: '成功停止工作流',
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: StopV2ChatResponseSchema
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
**说明**:
|
||||
- 接口使用 `authChatCrud` 进行鉴权,支持 Token 和 API Key
|
||||
- 支持分享链接和团队空间的鉴权数据
|
||||
- 设置停止标志后等待最多 5 秒
|
||||
- 无论是否超时,都返回 `success: true`
|
||||
|
||||
## 5. 前端改造
|
||||
|
||||
由于当前代码已经能够正常工作,且 v2 版本的后端已经实现了基于 Redis 的停止机制,前端可以保持现有的简单实现:
|
||||
|
||||
**保持现有实现的原因**:
|
||||
1. 后端已经通过定时器轮询 Redis 实现了停止检测
|
||||
2. 前端调用 `abort()` 后,后端会在下个检测周期(100ms内)发现停止标志
|
||||
3. 简化前端逻辑,避免增加复杂性
|
||||
4. 用户体验上,立即中断连接响应更快
|
||||
|
||||
**可选的增强方案**:
|
||||
|
||||
如果需要在前端显示更详细的停止状态,可以添加 API 客户端函数:
|
||||
|
||||
**文件位置**: `projects/app/src/web/core/chat/api.ts`
|
||||
|
||||
```typescript
|
||||
import { POST } from '@/web/common/api/request';
|
||||
import type { StopV2ChatParams, StopV2ChatResponse } from '@fastgpt/global/openapi/core/chat/controler/api';
|
||||
|
||||
/**
|
||||
* 停止 v2 版本工作流运行
|
||||
*/
|
||||
export const stopV2Chat = (data: StopV2ChatParams) =>
|
||||
POST<StopV2ChatResponse>('/api/v2/chat/stop', data);
|
||||
```
|
||||
|
||||
**增强的 abortRequest 函数**:
|
||||
|
||||
```typescript
|
||||
/* Abort chat completions, questionGuide */
|
||||
const abortRequest = useMemoizedFn(async (reason: string = 'stop') => {
|
||||
// 先调用 abort 中断连接
|
||||
chatController.current?.abort(new Error(reason));
|
||||
questionGuideController.current?.abort(new Error(reason));
|
||||
pluginController.current?.abort(new Error(reason));
|
||||
|
||||
// v2 版本: 可选地通知后端优雅停止
|
||||
if (chatBoxData?.app?.version === 'v2' && appId && chatId) {
|
||||
try {
|
||||
await stopV2Chat({
|
||||
appId,
|
||||
chatId,
|
||||
outLinkAuthData
|
||||
});
|
||||
} catch (error) {
|
||||
// 静默失败,不影响用户体验
|
||||
console.warn('Failed to notify backend to stop workflow', error);
|
||||
}
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
**建议**:
|
||||
- **推荐**: 保持当前简单实现,后端已经足够健壮
|
||||
- **可选**: 如果需要更精确的停止状态追踪,可以实现上述增强方案
|
||||
|
||||
## 6. 完整调用流程
|
||||
|
||||
### 6.1 正常停止流程
|
||||
|
||||
```
|
||||
用户点击停止按钮
|
||||
↓
|
||||
前端: abortRequest()
|
||||
↓
|
||||
前端: chatController.abort() [立即中断 HTTP 连接]
|
||||
↓
|
||||
[可选] 前端: POST /api/v2/chat/stop
|
||||
↓
|
||||
后端: setAgentRuntimeStop(appId, chatId) [设置停止标志]
|
||||
↓
|
||||
后端: 定时器检测到 Redis 停止标志,更新内存变量 stopping = true
|
||||
↓
|
||||
后端: 下个节点执行前 checkIsStopping() 返回 true
|
||||
↓
|
||||
后端: 停止处理新节点,记录日志
|
||||
↓
|
||||
后端: 工作流 finally 块删除 Redis 停止标志
|
||||
↓
|
||||
[可选] 后端: waitForWorkflowComplete() 检测到停止标志被删除
|
||||
↓
|
||||
[可选] 前端: 显示停止成功提示
|
||||
```
|
||||
|
||||
### 6.2 超时流程
|
||||
|
||||
```
|
||||
[可选] 前端: POST /api/v2/chat/stop
|
||||
↓
|
||||
后端: setAgentRuntimeStop(appId, chatId)
|
||||
↓
|
||||
后端: waitForWorkflowComplete(timeout=5s)
|
||||
↓
|
||||
后端: 5秒后停止标志仍存在
|
||||
↓
|
||||
后端: 返回成功响应 (不区分超时)
|
||||
↓
|
||||
[可选] 前端: 显示成功提示
|
||||
↓
|
||||
后端: 工作流继续运行,最终完成后删除停止标志
|
||||
```
|
||||
|
||||
### 6.3 工作流自然完成流程
|
||||
|
||||
```
|
||||
工作流运行中
|
||||
↓
|
||||
所有节点执行完成
|
||||
↓
|
||||
dispatchWorkFlow.finally()
|
||||
↓
|
||||
删除 Redis 停止标志
|
||||
↓
|
||||
清理定时器
|
||||
↓
|
||||
60秒 TTL 确保即使删除失败也会自动清理
|
||||
```
|
||||
|
||||
### 6.4 时序说明
|
||||
|
||||
**关键时间点**:
|
||||
- **100ms**: 后端定时器检查 Redis 停止标志的频率
|
||||
- **5s**: stop 接口等待工作流完成的超时时间
|
||||
- **60s**: Redis 键的 TTL,自动清理时间
|
||||
|
||||
**响应时间**:
|
||||
- 用户点击停止 → HTTP 连接中断: **立即** (前端 abort)
|
||||
- 停止标志写入 Redis: **< 50ms** (Redis SETEX 操作)
|
||||
- 后端检测到停止: **< 100ms** (定时器轮询周期)
|
||||
- 当前节点停止执行: **取决于节点类型**
|
||||
- LLM 流式输出: **立即**中断流
|
||||
- HTTP 请求节点: **等待请求完成**
|
||||
- 其他节点: **等待当前操作完成**
|
||||
|
||||
## 7. 测试策略
|
||||
|
||||
### 7.1 单元测试
|
||||
|
||||
**Redis 工具函数测试**:
|
||||
- `setAgentRuntimeStop` / `shouldWorkflowStop` 基本功能
|
||||
- `delAgentRuntimeStopSign` 删除功能
|
||||
- `waitForWorkflowComplete` 等待机制和超时
|
||||
- 并发操作安全性
|
||||
|
||||
**文件位置**: `test/cases/service/core/app/workflow/workflowStatus.test.ts`
|
||||
|
||||
**测试用例**:
|
||||
```typescript
|
||||
describe('Workflow Status Redis Functions', () => {
|
||||
test('should set stopping sign')
|
||||
test('should return false for non-existent status')
|
||||
test('should detect stopping status')
|
||||
test('should return false after deleting stop sign')
|
||||
test('should wait for workflow completion')
|
||||
test('should timeout when waiting too long')
|
||||
test('should delete workflow stop sign')
|
||||
test('should handle concurrent stop sign operations')
|
||||
});
|
||||
```
|
||||
|
||||
|
|
@ -73,6 +73,7 @@ jobs:
|
|||
--label "org.opencontainers.image.description=${{ steps.config.outputs.DESCRIPTION }}" \
|
||||
--push \
|
||||
--cache-from=type=local,src=/tmp/.buildx-cache \
|
||||
--cache-to=type=local,dest=/tmp/.buildx-cache \
|
||||
-t ${{ steps.config.outputs.DOCKER_REPO_TAGGED }} \
|
||||
.
|
||||
|
||||
|
|
|
|||
|
|
@ -1,33 +1,35 @@
|
|||
{
|
||||
// Place your FastGPT 工作区 snippets here. Each snippet is defined under a snippet name and has a scope, prefix, body and
|
||||
// description. Add comma separated ids of the languages where the snippet is applicable in the scope field. If scope
|
||||
// is left empty or omitted, the snippet gets applied to all languages. The prefix is what is
|
||||
// used to trigger the snippet and the body will be expanded and inserted. Possible variables are:
|
||||
// $1, $2 for tab stops, $0 for the final cursor position, and ${1:label}, ${2:another} for placeholders.
|
||||
// Place your FastGPT 工作区 snippets here. Each snippet is defined under a snippet name and has a scope, prefix, body and
|
||||
// description. Add comma separated ids of the languages where the snippet is applicable in the scope field. If scope
|
||||
// is left empty or omitted, the snippet gets applied to all languages. The prefix is what is
|
||||
// used to trigger the snippet and the body will be expanded and inserted. Possible variables are:
|
||||
// $1, $2 for tab stops, $0 for the final cursor position, and ${1:label}, ${2:another} for placeholders.
|
||||
// Placeholders with the same ids are connected.
|
||||
// Example:
|
||||
"Next api template": {
|
||||
"scope": "javascript,typescript",
|
||||
"prefix": "nextapi",
|
||||
"body": [
|
||||
"import { NextAPI } from '@/service/middleware/entry';",
|
||||
"import type { ApiRequestProps, ApiResponseType } from '@fastgpt/service/type/next';",
|
||||
"",
|
||||
"async function handler(",
|
||||
" req: ApiRequestProps,",
|
||||
" res: ApiResponseType<${1}ResponseType>",
|
||||
"): Promise<${1}ResponseType> {",
|
||||
" const body = ${1}BodySchema.parse(req.body);",
|
||||
" const query = ${1}QuerySchema.parse(req.query);",
|
||||
"",
|
||||
" ${2}",
|
||||
"",
|
||||
" return {};",
|
||||
"}",
|
||||
"",
|
||||
"export default NextAPI(handler);"
|
||||
"import type { ApiRequestProps, ApiResponseType } from '@fastgpt/service/type/next';",
|
||||
"import { NextAPI } from '@/service/middleware/entry';",
|
||||
"",
|
||||
"export type ${TM_FILENAME_BASE}Query = {};",
|
||||
"",
|
||||
"export type ${TM_FILENAME_BASE}Body = {};",
|
||||
"",
|
||||
"export type ${TM_FILENAME_BASE}Response = {};",
|
||||
"",
|
||||
"async function handler(",
|
||||
" req: ApiRequestProps<${TM_FILENAME_BASE}Body, ${TM_FILENAME_BASE}Query>,",
|
||||
" res: ApiResponseType<any>",
|
||||
"): Promise<${TM_FILENAME_BASE}Response> {",
|
||||
" $1",
|
||||
" return {}",
|
||||
"}",
|
||||
"",
|
||||
"export default NextAPI(handler);"
|
||||
],
|
||||
"description": "FastGPT Next API template with Zod validation"
|
||||
"description": "FastGPT Next API template"
|
||||
},
|
||||
"use context template": {
|
||||
"scope": "typescriptreact",
|
||||
|
|
@ -36,7 +38,7 @@
|
|||
"import React, { ReactNode } from 'react';",
|
||||
"import { createContext } from 'use-context-selector';",
|
||||
"",
|
||||
"type ContextType = {${1}};",
|
||||
"type ContextType = {$1};",
|
||||
"",
|
||||
"export const Context = createContext<ContextType>({});",
|
||||
"",
|
||||
|
|
@ -63,4 +65,4 @@
|
|||
"});"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -5,7 +5,7 @@
|
|||
如果您发现了 FastGPT 的安全漏洞,请按照以下步骤进行报告:
|
||||
|
||||
1. **报告方式**
|
||||
发送邮件至:archer@fastgpt.io
|
||||
发送邮件至:yujinlong@sealos.io
|
||||
请备注版本以及您的 GitHub 账号
|
||||
|
||||
3. **响应时间**
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
{
|
||||
"tags": {
|
||||
"fastgpt": "v4.14.4",
|
||||
"fastgpt-sandbox": "v4.14.4",
|
||||
"fastgpt-mcp_server": "v4.14.4",
|
||||
"fastgpt-plugin": "v0.3.4",
|
||||
"fastgpt": "v4.14.1",
|
||||
"fastgpt-sandbox": "v4.14.1",
|
||||
"fastgpt-mcp_server": "v4.14.1",
|
||||
"fastgpt-plugin": "v0.3.1",
|
||||
"aiproxy": "v0.3.2",
|
||||
"aiproxy-pg": "0.8.0-pg15",
|
||||
"mongo": "5.0.18",
|
||||
|
|
|
|||
|
|
@ -136,7 +136,7 @@ services:
|
|||
retries: 3
|
||||
sandbox:
|
||||
container_name: sandbox
|
||||
image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-sandbox:v4.14.4
|
||||
image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-sandbox:v4.14.1
|
||||
ports:
|
||||
- 3002:3000
|
||||
networks:
|
||||
|
|
@ -144,7 +144,7 @@ services:
|
|||
restart: always
|
||||
fastgpt-mcp-server:
|
||||
container_name: fastgpt-mcp-server
|
||||
image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-mcp_server:v4.14.4
|
||||
image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-mcp_server:v4.14.1
|
||||
ports:
|
||||
- 3005:3000
|
||||
networks:
|
||||
|
|
@ -153,7 +153,7 @@ services:
|
|||
environment:
|
||||
- FASTGPT_ENDPOINT=http://fastgpt:3000
|
||||
fastgpt-plugin:
|
||||
image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-plugin:v0.3.4
|
||||
image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-plugin:v0.3.1
|
||||
container_name: fastgpt-plugin
|
||||
restart: always
|
||||
ports:
|
||||
|
|
@ -162,7 +162,6 @@ services:
|
|||
- fastgpt
|
||||
environment:
|
||||
- AUTH_TOKEN=token
|
||||
- S3_EXTERNAL_BASE_URL=http://127.0.0.1:9000 # TODO: 改为你 Minio 的实际的 ip 地址
|
||||
- S3_ENDPOINT=fastgpt-minio
|
||||
- S3_PORT=9000
|
||||
- S3_USE_SSL=false
|
||||
|
|
|
|||
|
|
@ -136,7 +136,7 @@ services:
|
|||
retries: 3
|
||||
sandbox:
|
||||
container_name: sandbox
|
||||
image: ghcr.io/labring/fastgpt-sandbox:v4.14.4
|
||||
image: ghcr.io/labring/fastgpt-sandbox:v4.14.1
|
||||
ports:
|
||||
- 3002:3000
|
||||
networks:
|
||||
|
|
@ -144,7 +144,7 @@ services:
|
|||
restart: always
|
||||
fastgpt-mcp-server:
|
||||
container_name: fastgpt-mcp-server
|
||||
image: ghcr.io/labring/fastgpt-mcp_server:v4.14.4
|
||||
image: ghcr.io/labring/fastgpt-mcp_server:v4.14.1
|
||||
ports:
|
||||
- 3005:3000
|
||||
networks:
|
||||
|
|
@ -153,7 +153,7 @@ services:
|
|||
environment:
|
||||
- FASTGPT_ENDPOINT=http://fastgpt:3000
|
||||
fastgpt-plugin:
|
||||
image: ghcr.io/labring/fastgpt-plugin:v0.3.4
|
||||
image: ghcr.io/labring/fastgpt-plugin:v0.3.1
|
||||
container_name: fastgpt-plugin
|
||||
restart: always
|
||||
ports:
|
||||
|
|
@ -162,7 +162,6 @@ services:
|
|||
- fastgpt
|
||||
environment:
|
||||
- AUTH_TOKEN=token
|
||||
- S3_EXTERNAL_BASE_URL=http://127.0.0.1:9000 # TODO: 改为你 Minio 的实际的 ip 地址
|
||||
- S3_ENDPOINT=fastgpt-minio
|
||||
- S3_PORT=9000
|
||||
- S3_USE_SSL=false
|
||||
|
|
|
|||
|
|
@ -177,7 +177,7 @@ services:
|
|||
|
||||
fastgpt:
|
||||
container_name: fastgpt
|
||||
image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.14.4 # git
|
||||
image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.14.1 # git
|
||||
ports:
|
||||
- 3000:3000
|
||||
networks:
|
||||
|
|
@ -227,13 +227,13 @@ services:
|
|||
- ./config.json:/app/data/config.json
|
||||
sandbox:
|
||||
container_name: sandbox
|
||||
image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-sandbox:v4.14.4
|
||||
image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-sandbox:v4.14.1
|
||||
networks:
|
||||
- fastgpt
|
||||
restart: always
|
||||
fastgpt-mcp-server:
|
||||
container_name: fastgpt-mcp-server
|
||||
image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-mcp_server:v4.14.4
|
||||
image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-mcp_server:v4.14.1
|
||||
networks:
|
||||
- fastgpt
|
||||
ports:
|
||||
|
|
@ -242,7 +242,7 @@ services:
|
|||
environment:
|
||||
- FASTGPT_ENDPOINT=http://fastgpt:3000
|
||||
fastgpt-plugin:
|
||||
image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-plugin:v0.3.4
|
||||
image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-plugin:v0.3.1
|
||||
container_name: fastgpt-plugin
|
||||
restart: always
|
||||
networks:
|
||||
|
|
|
|||
|
|
@ -154,7 +154,7 @@ services:
|
|||
|
||||
fastgpt:
|
||||
container_name: fastgpt
|
||||
image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.14.4 # git
|
||||
image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.14.1 # git
|
||||
ports:
|
||||
- 3000:3000
|
||||
networks:
|
||||
|
|
@ -204,13 +204,13 @@ services:
|
|||
- ./config.json:/app/data/config.json
|
||||
sandbox:
|
||||
container_name: sandbox
|
||||
image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-sandbox:v4.14.4
|
||||
image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-sandbox:v4.14.1
|
||||
networks:
|
||||
- fastgpt
|
||||
restart: always
|
||||
fastgpt-mcp-server:
|
||||
container_name: fastgpt-mcp-server
|
||||
image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-mcp_server:v4.14.4
|
||||
image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-mcp_server:v4.14.1
|
||||
networks:
|
||||
- fastgpt
|
||||
ports:
|
||||
|
|
@ -219,7 +219,7 @@ services:
|
|||
environment:
|
||||
- FASTGPT_ENDPOINT=http://fastgpt:3000
|
||||
fastgpt-plugin:
|
||||
image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-plugin:v0.3.4
|
||||
image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-plugin:v0.3.1
|
||||
container_name: fastgpt-plugin
|
||||
restart: always
|
||||
networks:
|
||||
|
|
|
|||
|
|
@ -135,7 +135,7 @@ services:
|
|||
|
||||
fastgpt:
|
||||
container_name: fastgpt
|
||||
image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.14.4 # git
|
||||
image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.14.1 # git
|
||||
ports:
|
||||
- 3000:3000
|
||||
networks:
|
||||
|
|
@ -185,13 +185,13 @@ services:
|
|||
- ./config.json:/app/data/config.json
|
||||
sandbox:
|
||||
container_name: sandbox
|
||||
image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-sandbox:v4.14.4
|
||||
image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-sandbox:v4.14.1
|
||||
networks:
|
||||
- fastgpt
|
||||
restart: always
|
||||
fastgpt-mcp-server:
|
||||
container_name: fastgpt-mcp-server
|
||||
image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-mcp_server:v4.14.4
|
||||
image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-mcp_server:v4.14.1
|
||||
networks:
|
||||
- fastgpt
|
||||
ports:
|
||||
|
|
@ -200,7 +200,7 @@ services:
|
|||
environment:
|
||||
- FASTGPT_ENDPOINT=http://fastgpt:3000
|
||||
fastgpt-plugin:
|
||||
image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-plugin:v0.3.4
|
||||
image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-plugin:v0.3.1
|
||||
container_name: fastgpt-plugin
|
||||
restart: always
|
||||
networks:
|
||||
|
|
|
|||
|
|
@ -118,7 +118,7 @@ services:
|
|||
|
||||
fastgpt:
|
||||
container_name: fastgpt
|
||||
image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.14.4 # git
|
||||
image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.14.1 # git
|
||||
ports:
|
||||
- 3000:3000
|
||||
networks:
|
||||
|
|
@ -168,13 +168,13 @@ services:
|
|||
- ./config.json:/app/data/config.json
|
||||
sandbox:
|
||||
container_name: sandbox
|
||||
image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-sandbox:v4.14.4
|
||||
image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-sandbox:v4.14.1
|
||||
networks:
|
||||
- fastgpt
|
||||
restart: always
|
||||
fastgpt-mcp-server:
|
||||
container_name: fastgpt-mcp-server
|
||||
image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-mcp_server:v4.14.4
|
||||
image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-mcp_server:v4.14.1
|
||||
networks:
|
||||
- fastgpt
|
||||
ports:
|
||||
|
|
@ -183,7 +183,7 @@ services:
|
|||
environment:
|
||||
- FASTGPT_ENDPOINT=http://fastgpt:3000
|
||||
fastgpt-plugin:
|
||||
image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-plugin:v0.3.4
|
||||
image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-plugin:v0.3.1
|
||||
container_name: fastgpt-plugin
|
||||
restart: always
|
||||
networks:
|
||||
|
|
|
|||
|
|
@ -177,7 +177,7 @@ services:
|
|||
|
||||
fastgpt:
|
||||
container_name: fastgpt
|
||||
image: ghcr.io/labring/fastgpt:v4.14.4 # git
|
||||
image: ghcr.io/labring/fastgpt:v4.14.1 # git
|
||||
ports:
|
||||
- 3000:3000
|
||||
networks:
|
||||
|
|
@ -227,13 +227,13 @@ services:
|
|||
- ./config.json:/app/data/config.json
|
||||
sandbox:
|
||||
container_name: sandbox
|
||||
image: ghcr.io/labring/fastgpt-sandbox:v4.14.4
|
||||
image: ghcr.io/labring/fastgpt-sandbox:v4.14.1
|
||||
networks:
|
||||
- fastgpt
|
||||
restart: always
|
||||
fastgpt-mcp-server:
|
||||
container_name: fastgpt-mcp-server
|
||||
image: ghcr.io/labring/fastgpt-mcp_server:v4.14.4
|
||||
image: ghcr.io/labring/fastgpt-mcp_server:v4.14.1
|
||||
networks:
|
||||
- fastgpt
|
||||
ports:
|
||||
|
|
@ -242,7 +242,7 @@ services:
|
|||
environment:
|
||||
- FASTGPT_ENDPOINT=http://fastgpt:3000
|
||||
fastgpt-plugin:
|
||||
image: ghcr.io/labring/fastgpt-plugin:v0.3.4
|
||||
image: ghcr.io/labring/fastgpt-plugin:v0.3.1
|
||||
container_name: fastgpt-plugin
|
||||
restart: always
|
||||
networks:
|
||||
|
|
|
|||
|
|
@ -154,7 +154,7 @@ services:
|
|||
|
||||
fastgpt:
|
||||
container_name: fastgpt
|
||||
image: ghcr.io/labring/fastgpt:v4.14.4 # git
|
||||
image: ghcr.io/labring/fastgpt:v4.14.1 # git
|
||||
ports:
|
||||
- 3000:3000
|
||||
networks:
|
||||
|
|
@ -204,13 +204,13 @@ services:
|
|||
- ./config.json:/app/data/config.json
|
||||
sandbox:
|
||||
container_name: sandbox
|
||||
image: ghcr.io/labring/fastgpt-sandbox:v4.14.4
|
||||
image: ghcr.io/labring/fastgpt-sandbox:v4.14.1
|
||||
networks:
|
||||
- fastgpt
|
||||
restart: always
|
||||
fastgpt-mcp-server:
|
||||
container_name: fastgpt-mcp-server
|
||||
image: ghcr.io/labring/fastgpt-mcp_server:v4.14.4
|
||||
image: ghcr.io/labring/fastgpt-mcp_server:v4.14.1
|
||||
networks:
|
||||
- fastgpt
|
||||
ports:
|
||||
|
|
@ -219,7 +219,7 @@ services:
|
|||
environment:
|
||||
- FASTGPT_ENDPOINT=http://fastgpt:3000
|
||||
fastgpt-plugin:
|
||||
image: ghcr.io/labring/fastgpt-plugin:v0.3.4
|
||||
image: ghcr.io/labring/fastgpt-plugin:v0.3.1
|
||||
container_name: fastgpt-plugin
|
||||
restart: always
|
||||
networks:
|
||||
|
|
|
|||
|
|
@ -135,7 +135,7 @@ services:
|
|||
|
||||
fastgpt:
|
||||
container_name: fastgpt
|
||||
image: ghcr.io/labring/fastgpt:v4.14.4 # git
|
||||
image: ghcr.io/labring/fastgpt:v4.14.1 # git
|
||||
ports:
|
||||
- 3000:3000
|
||||
networks:
|
||||
|
|
@ -185,13 +185,13 @@ services:
|
|||
- ./config.json:/app/data/config.json
|
||||
sandbox:
|
||||
container_name: sandbox
|
||||
image: ghcr.io/labring/fastgpt-sandbox:v4.14.4
|
||||
image: ghcr.io/labring/fastgpt-sandbox:v4.14.1
|
||||
networks:
|
||||
- fastgpt
|
||||
restart: always
|
||||
fastgpt-mcp-server:
|
||||
container_name: fastgpt-mcp-server
|
||||
image: ghcr.io/labring/fastgpt-mcp_server:v4.14.4
|
||||
image: ghcr.io/labring/fastgpt-mcp_server:v4.14.1
|
||||
networks:
|
||||
- fastgpt
|
||||
ports:
|
||||
|
|
@ -200,7 +200,7 @@ services:
|
|||
environment:
|
||||
- FASTGPT_ENDPOINT=http://fastgpt:3000
|
||||
fastgpt-plugin:
|
||||
image: ghcr.io/labring/fastgpt-plugin:v0.3.4
|
||||
image: ghcr.io/labring/fastgpt-plugin:v0.3.1
|
||||
container_name: fastgpt-plugin
|
||||
restart: always
|
||||
networks:
|
||||
|
|
|
|||
|
|
@ -118,7 +118,7 @@ services:
|
|||
|
||||
fastgpt:
|
||||
container_name: fastgpt
|
||||
image: ghcr.io/labring/fastgpt:v4.14.4 # git
|
||||
image: ghcr.io/labring/fastgpt:v4.14.1 # git
|
||||
ports:
|
||||
- 3000:3000
|
||||
networks:
|
||||
|
|
@ -168,13 +168,13 @@ services:
|
|||
- ./config.json:/app/data/config.json
|
||||
sandbox:
|
||||
container_name: sandbox
|
||||
image: ghcr.io/labring/fastgpt-sandbox:v4.14.4
|
||||
image: ghcr.io/labring/fastgpt-sandbox:v4.14.1
|
||||
networks:
|
||||
- fastgpt
|
||||
restart: always
|
||||
fastgpt-mcp-server:
|
||||
container_name: fastgpt-mcp-server
|
||||
image: ghcr.io/labring/fastgpt-mcp_server:v4.14.4
|
||||
image: ghcr.io/labring/fastgpt-mcp_server:v4.14.1
|
||||
networks:
|
||||
- fastgpt
|
||||
ports:
|
||||
|
|
@ -183,7 +183,7 @@ services:
|
|||
environment:
|
||||
- FASTGPT_ENDPOINT=http://fastgpt:3000
|
||||
fastgpt-plugin:
|
||||
image: ghcr.io/labring/fastgpt-plugin:v0.3.4
|
||||
image: ghcr.io/labring/fastgpt-plugin:v0.3.1
|
||||
container_name: fastgpt-plugin
|
||||
restart: always
|
||||
networks:
|
||||
|
|
|
|||
|
|
@ -162,7 +162,6 @@ services:
|
|||
- fastgpt
|
||||
environment:
|
||||
- AUTH_TOKEN=token
|
||||
- S3_EXTERNAL_BASE_URL=http://127.0.0.1:9000 # TODO: 改为你 Minio 的实际的 ip 地址
|
||||
- S3_ENDPOINT=fastgpt-minio
|
||||
- S3_PORT=9000
|
||||
- S3_USE_SSL=false
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
# FastGPT 文档
|
||||
|
||||
这是FastGPT的官方文档,采用 fumadoc 框架。
|
||||
这是FastGPT的官方文档,采用fumadoc框架。
|
||||
## 运行项目
|
||||
|
||||
要运行文档,首先需要进行环境变量配置,在文档的根目录下创建`.env.local`文件,填写以下环境变量:
|
||||
|
|
@ -12,7 +12,7 @@ FASTGPT_HOME_DOMAIN = #要跳转的FastGPT项目的域名,默认海外版
|
|||
你可以在FastGPT项目根目录下执行以下命令来运行文档。
|
||||
|
||||
```bash
|
||||
npm install # 只能 npm install,不能 pnpm
|
||||
npm install #只能npm install,不能pnpm
|
||||
npm run dev
|
||||
```
|
||||
项目会默认跑在`http:localhost:3000`端口
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ title: 报错
|
|||
|
||||
1. ### 当前分组上游负载已饱和,请稍后再试(request id:202407100753411462086782835521)
|
||||
|
||||
是oneapi渠道的问题,可以换个模型用或者换一家中转站
|
||||
是oneapi渠道的问题,可以换个模型用or换一家中转站
|
||||
|
||||
1. ### 使用API时在日志中报错Connection Error
|
||||
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ import { Alert } from '@/components/docs/Alert';
|
|||
### 2. 配置介绍
|
||||
|
||||
<Alert icon="🤖" context="success">
|
||||
注意: 1. 目前语音识别模型仅会生效一个,所以配置时候,只需要配置一个即可。 2.
|
||||
注意: 1. 目前语音识别模型和重排模型仅会生效一个,所以配置时候,只需要配置一个即可。 2.
|
||||
系统至少需要一个语言模型和一个索引模型才能正常使用。
|
||||
</Alert>
|
||||
|
||||
|
|
|
|||
|
|
@ -616,7 +616,7 @@ event取值:
|
|||
<Tab value="请求示例">
|
||||
|
||||
```bash
|
||||
curl --location --request POST 'http://localhost:3000/api/core/chat/history/getHistories' \
|
||||
curl --location --request POST 'http://localhost:3000/api/core/chat/getHistories' \
|
||||
--header 'Authorization: Bearer [apikey]' \
|
||||
--header 'Content-Type: application/json' \
|
||||
--data-raw '{
|
||||
|
|
@ -679,7 +679,7 @@ curl --location --request POST 'http://localhost:3000/api/core/chat/history/getH
|
|||
<Tab value="请求示例">
|
||||
|
||||
```bash
|
||||
curl --location --request POST 'http://localhost:3000/api/core/chat/history/updateHistory' \
|
||||
curl --location --request POST 'http://localhost:3000/api/core/chat/updateHistory' \
|
||||
--header 'Authorization: Bearer [apikey]' \
|
||||
--header 'Content-Type: application/json' \
|
||||
--data-raw '{
|
||||
|
|
@ -721,7 +721,7 @@ curl --location --request POST 'http://localhost:3000/api/core/chat/history/upda
|
|||
<Tab value="请求示例">
|
||||
|
||||
```bash
|
||||
curl --location --request POST 'http://localhost:3000/api/core/chat/history/updateHistory' \
|
||||
curl --location --request POST 'http://localhost:3000/api/core/chat/updateHistory' \
|
||||
--header 'Authorization: Bearer [apikey]' \
|
||||
--header 'Content-Type: application/json' \
|
||||
--data-raw '{
|
||||
|
|
@ -763,7 +763,7 @@ curl --location --request POST 'http://localhost:3000/api/core/chat/history/upda
|
|||
<Tab value="请求示例">
|
||||
|
||||
```bash
|
||||
curl --location --request DELETE 'http://localhost:3000/api/core/chat/history/delHistory?chatId=[chatId]&appId=[appId]' \
|
||||
curl --location --request DELETE 'http://localhost:3000/api/core/chat/delHistory?chatId=[chatId]&appId=[appId]' \
|
||||
--header 'Authorization: Bearer [apikey]'
|
||||
```
|
||||
|
||||
|
|
@ -800,7 +800,7 @@ curl --location --request DELETE 'http://localhost:3000/api/core/chat/history/de
|
|||
<Tab value="请求示例">
|
||||
|
||||
```bash
|
||||
curl --location --request DELETE 'http://localhost:3000/api/core/chat/history/clearHistories?appId=[appId]' \
|
||||
curl --location --request DELETE 'http://localhost:3000/api/core/chat/clearHistories?appId=[appId]' \
|
||||
--header 'Authorization: Bearer [apikey]'
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -15,20 +15,20 @@ description: FastGPT 分享链接身份鉴权
|
|||
|
||||
### 接口统一响应格式
|
||||
|
||||
```jsonc
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "错误提示",
|
||||
"msg": "同message, 错误提示",
|
||||
"data": {
|
||||
"uid": "用户唯一凭证" // 必须返回
|
||||
"uid": "用户唯一凭证"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
`FastGPT` 将会判断`success`是否为`true`决定是允许用户继续操作。`message`与`msg`是等同的,你可以选择返回其中一个,当`success`不为`true`时,将会提示这个错误。
|
||||
|
||||
`uid` 是用户的唯一凭证,必须返回该 ID 且 ID 的格式为不包含 "|"、"/“、"\\" 字符的、小于等于 255 **字节长度**的字符串,否则会返回 `Invalid UID` 的错误。`uid` 将会用于拉取对话记录以及保存对话记录,可参考下方实践案例。
|
||||
`uid`是用户的唯一凭证,将会用于拉取对话记录以及保存对话记录。可参考下方实践案例。
|
||||
|
||||
### 触发流程
|
||||
|
||||
|
|
|
|||
|
|
@ -1,42 +0,0 @@
|
|||
---
|
||||
title: 配置自定义域名
|
||||
description: 如何在 FastGPT 中配置自定义域名
|
||||
---
|
||||
|
||||
FastGPT 云服务版自 v4.14.4 后支持配置自定义域名。
|
||||
|
||||
## 如何配置自定义域名
|
||||
|
||||
### 1. 打开“自定义域名”页面
|
||||
|
||||
在侧边栏选择“账号” -> “自定义域名”,打开自定义域名配置页。
|
||||
|
||||
如果您的套餐等级不支持配置,请根据页面的指引升级套餐。
|
||||
|
||||

|
||||
|
||||
### 2. 添加自定义域名
|
||||
|
||||
1. 准备好您的域名。您的域名必须先经过备案,目前支持“阿里云”、“腾讯云”、“火山引擎”三家服务商的备案域名。
|
||||
2. 点击“编辑”按钮,进入编辑状态。
|
||||
3. 填入您的域名,例如 www.example.com
|
||||
4. 在域名服务商的域名解析处,添加界面中提示的 DNS 记录,注意记录类型为 CNAME。
|
||||
5. 添加解析记录后,点击"保存"按钮。系统将自动检查 DNS 解析情况,一般情况下,在一分钟内就可以获取到解析记录。如果长时间没有获取到记录,可以重试一次。
|
||||
6. 待状态提示显示为“已生效”后,点击“确认”按钮即可。
|
||||
|
||||

|
||||
|
||||
现在您可以通过您自己的域名访问 fastgpt 服务、调用 fastgpt 的 API 了。
|
||||
|
||||
## 域名解析失效
|
||||
|
||||
系统会每天对 DNS 解析进行检查,如果发现 DNS 解析记录失效,则会停用该自定义域名,可以在"自定义域名"管理界面中点击"编辑"进行重新解析。
|
||||
|
||||

|
||||
|
||||
如果您需要修改自定义域名、或修改服务商,则需要删除自定义域名配置后进行重新配置。
|
||||
|
||||
|
||||
## 使用案例
|
||||
|
||||
- [接入企业微信智能机器人](/docs/use-cases/external-integration/wecom)
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"title": "团队与权限",
|
||||
"description": "团队管理、成员组与权限设置,确保团队协作中的数据安全和权限分配合理。",
|
||||
"pages": ["team_roles_permissions","invitation_link", "customDomain"]
|
||||
}
|
||||
"pages": ["team_roles_permissions","invitation_link"]
|
||||
}
|
||||
|
|
@ -58,5 +58,5 @@ Due to servers potentially being located in different countries/regions, you agr
|
|||
|
||||
**Contact Us**
|
||||
|
||||
1. For any questions, suggestions, or complaints about this policy, contact us at: archer@fastgpt.io.
|
||||
1. For any questions, suggestions, or complaints about this policy, contact us at: yujinlong@sealos.io.
|
||||
2. We will respond promptly and address your concerns.
|
||||
|
|
|
|||
|
|
@ -58,5 +58,5 @@ description: ' FastGPT 隐私政策'
|
|||
|
||||
**联系我们**
|
||||
|
||||
1. 如您对本隐私政策有任何疑问、建议或投诉,请通过以下方式与我们联系:archer@fastgpt.io。
|
||||
1. 如您对本隐私政策有任何疑问、建议或投诉,请通过以下方式与我们联系:yujinlong@sealos.io。
|
||||
2. 我们将尽快回复并解决您提出的问题。
|
||||
|
|
|
|||
|
|
@ -72,4 +72,4 @@ This FastGPT Service Agreement constitutes the terms and conditions agreed betwe
|
|||
**Article 7 Additional Provisions**
|
||||
|
||||
1. If any clause is deemed unlawful or invalid, the remaining provisions shall remain enforceable.
|
||||
2. Sealos retains final authority in interpreting this Agreement and privacy policies. For any inquiries, please contact us at archer@fastgpt.io.
|
||||
2. Sealos retains final authority in interpreting this Agreement and privacy policies. For any inquiries, please contact us at yujinlong@sealos.io.
|
||||
|
|
|
|||
|
|
@ -67,4 +67,4 @@ FastGPT 服务协议是您与珠海环界云计算有限公司(以下简称“
|
|||
**第7条 其他条款**
|
||||
|
||||
1. 如本协议中部分条款因违反法律法规而被视为无效,不影响其他条款的效力。
|
||||
2. 本公司保留对本协议及隐私政策的最终解释权。如您对本协议或隐私政策有任何疑问,请联系我们:archer@fastgpt.io。
|
||||
2. 本公司保留对本协议及隐私政策的最终解释权。如您对本协议或隐私政策有任何疑问,请联系我们:yujinlong@sealos.io。
|
||||
|
|
|
|||
|
|
@ -92,7 +92,6 @@ description: FastGPT 文档目录
|
|||
- [/docs/introduction/guide/plugins/google_search_plugin_guide](/docs/introduction/guide/plugins/google_search_plugin_guide)
|
||||
- [/docs/introduction/guide/plugins/searxng_plugin_guide](/docs/introduction/guide/plugins/searxng_plugin_guide)
|
||||
- [/docs/introduction/guide/plugins/upload_system_tool](/docs/introduction/guide/plugins/upload_system_tool)
|
||||
- [/docs/introduction/guide/team_permissions/customDomain](/docs/introduction/guide/team_permissions/customDomain)
|
||||
- [/docs/introduction/guide/team_permissions/invitation_link](/docs/introduction/guide/team_permissions/invitation_link)
|
||||
- [/docs/introduction/guide/team_permissions/team_roles_permissions](/docs/introduction/guide/team_permissions/team_roles_permissions)
|
||||
- [/docs/introduction/index](/docs/introduction/index)
|
||||
|
|
@ -114,9 +113,6 @@ description: FastGPT 文档目录
|
|||
- [/docs/upgrading/4-14/4140](/docs/upgrading/4-14/4140)
|
||||
- [/docs/upgrading/4-14/4141](/docs/upgrading/4-14/4141)
|
||||
- [/docs/upgrading/4-14/4142](/docs/upgrading/4-14/4142)
|
||||
- [/docs/upgrading/4-14/4143](/docs/upgrading/4-14/4143)
|
||||
- [/docs/upgrading/4-14/4144](/docs/upgrading/4-14/4144)
|
||||
- [/docs/upgrading/4-14/4145](/docs/upgrading/4-14/4145)
|
||||
- [/docs/upgrading/4-8/40](/docs/upgrading/4-8/40)
|
||||
- [/docs/upgrading/4-8/41](/docs/upgrading/4-8/41)
|
||||
- [/docs/upgrading/4-8/42](/docs/upgrading/4-8/42)
|
||||
|
|
|
|||
|
|
@ -17,8 +17,8 @@ description: 'FastGPT V4.13.2 更新说明'
|
|||
### 2. 增加 FastGPT/FastGPT-pro 环境变量
|
||||
|
||||
```
|
||||
S3_PUBLIC_BUCKET=fastgpt-public #(公开读公开桶名称,对应原来 plugin 项目的S3_TOOL_BUCKET)
|
||||
S3_PRIVATE_BUCKET=fastgpt-private #(私有读私有写桶名称,对应原来 plugin 项目的S3_PLUGIN_BUCKET)
|
||||
S3_PUBLIC_BUCKET=fastgpt_public #(公开读公开桶名称,对应原来 plugin 项目的S3_TOOL_BUCKET)
|
||||
S3_PRIVATE_BUCKET=fastgpt_private #(私有读私有写桶名称,对应原来 plugin 项目的S3_PLUGIN_BUCKET)
|
||||
```
|
||||
|
||||
### 3. 修复 fastgpt-plugin 环境变量
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
---
|
||||
title: 'V4.14.1(包含升级脚本)'
|
||||
title: 'V4.14.1'
|
||||
description: 'FastGPT V4.14.1 更新说明'
|
||||
---
|
||||
|
||||
|
|
@ -29,7 +29,7 @@ curl --location --request POST 'https://{{host}}/api/admin/initv4141' \
|
|||
|
||||
## 🚀 新增内容
|
||||
|
||||
1. 新工作台交互。原插件,改名"工作流工具",并移动到我的工具分类下。
|
||||
1. 新工作台交互。
|
||||
2. 工作流运行欠费后提供继续运行按键,无需从头开始。
|
||||
|
||||
## ⚙️ 优化
|
||||
|
|
|
|||
|
|
@ -1,22 +1,13 @@
|
|||
---
|
||||
title: 'V4.14.2'
|
||||
title: 'V4.14.2(进行中)'
|
||||
description: 'FastGPT V4.14.2 更新说明'
|
||||
---
|
||||
|
||||
## 更新指南
|
||||
|
||||
### 1. 更新镜像:
|
||||
|
||||
- 更新 FastGPT 镜像tag: v4.14.2
|
||||
- 更新 FastGPT 商业版镜像tag: v4.14.2
|
||||
- 更新 fastgpt-plugin 镜像 tag: v0.3.2
|
||||
- mcp_server 无需更新
|
||||
- Sandbox 无需更新
|
||||
- AIProxy 无需更新
|
||||
|
||||
## 🚀 新增内容
|
||||
|
||||
1. 封装底层 Agent Call 方式,支持工具连续调用时上下文的压缩。
|
||||
1. 封装底层 Agent Call 方式,支持工具连续调用时上下文的压缩,以及单个工具长响应的压缩。
|
||||
2. 模板市场新 UI。
|
||||
3. 支持 Agent 编辑页快速创建知识库。
|
||||
|
||||
|
|
@ -24,7 +15,6 @@ description: 'FastGPT V4.14.2 更新说明'
|
|||
|
||||
1. 30 分钟模板市场缓存时长。
|
||||
2. 自定义分隔符块大小采用最大块大小。
|
||||
3. 避免日志记录触发递归日志风暴,排除日志模型的性能监控中间件。
|
||||
|
||||
## 🐛 修复
|
||||
|
||||
|
|
|
|||
|
|
@ -1,55 +0,0 @@
|
|||
---
|
||||
title: 'V4.14.3'
|
||||
description: 'FastGPT V4.14.3 更新说明'
|
||||
---
|
||||
|
||||
|
||||
## 更新指南
|
||||
|
||||
### 1. 更新镜像:
|
||||
|
||||
- 更新 FastGPT 镜像tag: v4.14.3
|
||||
- 更新 FastGPT 商业版镜像tag: v4.14.3
|
||||
- 更新 fastgpt-plugin 镜像 tag: v0.3.3
|
||||
- mcp_server 无需更新
|
||||
- Sandbox 无需更新
|
||||
- AIProxy 无需更新
|
||||
|
||||
### 2. 执行升级脚本
|
||||
|
||||
从任意终端,发起 1 个 HTTP 请求。其中 `{{rootkey}}` 替换成环境变量里的 `rootkey`;`{{host}}` 替换成**FastGPT 域名**。
|
||||
|
||||
```bash
|
||||
curl --location --request POST 'https://{{host}}/api/admin/initv4143' \
|
||||
--header 'rootkey: {{rootkey}}' \
|
||||
--header 'Content-Type: application/json'
|
||||
```
|
||||
|
||||
会将原系统 MongoDB 的 GridFS 中的所有知识库文件迁移到 S3 中,包含文本数据集和图片数据集,但不包括文档(如 .docx)里解析出来的图片。
|
||||
|
||||
## 🚀 新增内容
|
||||
|
||||
1. 知识库文件迁移至 S3(全部使用文件的地方均已迁移)。
|
||||
2. 全局变量支持文件上传。
|
||||
3. 表单输入节点支持密码、开关、时间点、时间范围、文件上传、对话模型选择。
|
||||
4. 插件输入支持多选、时间点、时间范围、内部变量。
|
||||
5. 系统插件,插件市场中会提示是否有新版本,并提供更新按键。
|
||||
6. 工作流运行 QPM 限制。
|
||||
|
||||
## ⚙️ 优化
|
||||
|
||||
1. 工作流工具,文件上传输入 UX 优化。
|
||||
2. 添加权限表校验中间件,增强权限表鲁棒性。
|
||||
|
||||
## 🐛 修复
|
||||
|
||||
1. 工作流调试预览窗口,重新渲染导致输入丢失。
|
||||
2. S3 服务与主服务相同 Origin 的域名会导致对 S3 的文件请求 URL 被错误替换,产生 404 报错。
|
||||
|
||||
## 插件
|
||||
|
||||
1. 工具更新逻辑,提供一个计算的 version 值来判断更新
|
||||
2. 微信公众号工具集:允许同时上传多篇文档到草稿箱
|
||||
3. 修复工具缓存没有被正确刷新
|
||||
4. 修复开发模式下刷新缓存导致静态文件重新上传
|
||||
5. 修复修复上传 pkg 后图片没有被正确上传的问题
|
||||
|
|
@ -1,88 +0,0 @@
|
|||
---
|
||||
title: 'V4.14.4'
|
||||
description: 'FastGPT V4.14.4 更新说明'
|
||||
---
|
||||
|
||||
## 更新指南
|
||||
|
||||
### 1. 更新镜像:
|
||||
|
||||
- 更新 FastGPT 镜像tag: v4.14.4
|
||||
- 更新 FastGPT 商业版镜像tag: v4.14.4
|
||||
- 更新 fastgpt-plugin 镜像 tag: v0.3.4
|
||||
- mcp_server 无需更新
|
||||
- Sandbox 无需更新
|
||||
- AIProxy 无需更新
|
||||
|
||||
### 2. 执行升级脚本
|
||||
|
||||
从任意终端,发起 1 个 HTTP 请求。其中 `{{rootkey}}` 替换成环境变量里的 `rootkey`;`{{host}}` 替换成**FastGPT 域名**。
|
||||
|
||||
```bash
|
||||
curl --location --request POST 'https://{{host}}/api/admin/initv4144' \
|
||||
--header 'rootkey: {{rootkey}}' \
|
||||
--header 'Content-Type: application/json'
|
||||
```
|
||||
|
||||
1. 将 4.14.3 中,遗留的 Dataset/local 接口上传的文件,也迁移到 S3 中。
|
||||
2. 全量计算旧的 chat 中的反馈,增加 flags 值便于筛选。该函数执行较慢,所以放到异步执行,接口不会返回结果,请关注日志中是否打印:Migration feedback completed!
|
||||
|
||||
## 🚀 新增内容
|
||||
|
||||
1. 工具调用支持配置流输出
|
||||
2. AI 积分告警通知。
|
||||
3. 对话日志支持展示 IP 地址归属地。
|
||||
4. 对话日志支持展示应用版本名(如果对话中途修改成最新版本,则会被修改成最新版本)
|
||||
5. 对话日志支持按点赞点踩过滤,并在对话详情里可以快速定位到赞/踩的记录。
|
||||
6. 通过 API 上传本地文件至知识库,保存至 S3。同时将旧版 Gridfs 代码全部移除。
|
||||
7. 新版订阅套餐逻辑。
|
||||
8. 支持配置对话文件白名单。
|
||||
9. S3 支持 pathStyle 和 region 配置。
|
||||
10. 支持通过 Sealos 来进行多租户自定义域名配置。
|
||||
11. 工作流中引用工具时,文件输入支持手动填写(原本只支持变量引用)。
|
||||
12. 支持网络代理(HTTP_PROXY,HTTPS_PROXY)
|
||||
|
||||
## ⚙️ 优化
|
||||
|
||||
1. 增加 S3 上传文件超时时长为 5 分钟。
|
||||
2. 问题优化采用 JinaAI 的边际收益公式,获取最大边际收益的检索词。
|
||||
3. 用户通知,支持中英文,以及优化模板。
|
||||
4. 删除知识库采用队列异步删除模式。
|
||||
5. LLM 请求时,图片无效报错提示。
|
||||
6. completions 接口,非 stream 模式, detail=false 时,增加返回 reason_content。
|
||||
7. 增加对于无效的 S3 key 检测。
|
||||
8. 删除应用和知识库时,强制要求输入名称校验。
|
||||
9. Mongo 慢操作日志,可以准确打印集合名和操作内容。
|
||||
10. 分享链接,自定义鉴权返回的 uid,强制要求长度小于 200(太长会影响文件上传)。
|
||||
|
||||
## 🐛 修复
|
||||
|
||||
1. 循环节点数组,取消过滤空内容。
|
||||
2. 工作流工具,未传递自定义 DataId,导致测试运行时,查看知识库提示无权限。
|
||||
3. 对话 Agent 工具配置中,非必填的布尔和数字类型无法直接确认。
|
||||
4. 工作台卡片在名字过长时错位。
|
||||
5. 分享链接中url query 中携带全局变量时,前端 UI 不会加载该值。
|
||||
6. window 下判断 CSV 文件异常。
|
||||
7. 模型测试时,如果模型未启动,会导致无法被测试。
|
||||
8. MCP header 中带特殊内容时,会抛错。
|
||||
9. 工作流引用其他 Agent 时,切换版本号后未及时更新 UI。
|
||||
10. http 节点使用值为空字符串的全局变量时,值会被替换为 null。
|
||||
11. 判断器节点折叠时,连线断开。
|
||||
12. 节点调试时,单选和多选类型的变量无法展示选项。
|
||||
13. 发布渠道文档链接定位错误。
|
||||
14. Checkbox 在禁用状态时,hover 样式错误。
|
||||
15. 模型头像缺失情况下,默认 huggingface.svg 图标显示错误。
|
||||
16. 日志导出时,结束时间会多出一天。
|
||||
17. 表单输入,前端默认值未传递到实体值。
|
||||
18. 工具调用时,未传递 max_tokens 参数。
|
||||
19. 工作流判断器 value 值,未结合 condition 来综合获取数据类型。
|
||||
20. 非直接分块模式的知识库数据,引用阅读器导航顺序异常。引用阅读器只会加载同一页。
|
||||
|
||||
## 插件
|
||||
|
||||
1. 新增 - GLM4.6 与 DS3.2 系列模型预设。
|
||||
2. 修复 - MinerU SaaS 插件模型版本不能选择 vlm 的问题
|
||||
3. 修复 - 微信公众号插件批量上传 markdown 参数传递问题
|
||||
4. 新增 - 获取微信公众号草稿箱列表工具
|
||||
5. 优化 - markdown 转文件支持自定义文件名
|
||||
6. 修复 - import cache 导致的插件无法被更新的问题
|
||||
|
|
@ -1,27 +0,0 @@
|
|||
---
|
||||
title: 'V4.14.5(进行中)'
|
||||
description: 'FastGPT V4.14.5 更新说明'
|
||||
---
|
||||
|
||||
|
||||
## 🚀 新增内容
|
||||
|
||||
1. 对话记录使用侧改成软删除,增加从日志管理里删除对话记录。
|
||||
2. 更新Agent/工具时,会更新其上层所有目录的更新时间,以便其会排在列表前面。
|
||||
3. 门户页支持配置单个应用运行可见度配。
|
||||
|
||||
## ⚙️ 优化
|
||||
|
||||
1. 优化获取 redis 所有 key 的逻辑,避免大量获取时导致阻塞。
|
||||
2. MongoDB, Redis 和 MQ 的重连逻辑优化。
|
||||
|
||||
## 🐛 修复
|
||||
|
||||
1. MCP 工具创建时,使用自定义鉴权头会报错。
|
||||
2. 获取对话日志列表时,如果用户头像为空,会抛错。
|
||||
3. chatAgent 未开启问题优化时,前端 UI 显示开启。
|
||||
4. 加载默认模型时,maxTokens 字段未赋值,导致模型最大响应值配置为空。
|
||||
5. S3 文件清理队列因网络稳定问题出现阻塞,导致删除任务不再执行。
|
||||
|
||||
|
||||
## 插件
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"title": "4.14.x",
|
||||
"description": "",
|
||||
"pages": ["4145", "4144", "4143", "4142", "4141", "4140"]
|
||||
"pages": ["4142", "4141", "4140"]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ import { Alert } from '@/components/docs/Alert';
|
|||
背景知识中,引导模型调用工具去执行不通的操作。
|
||||
|
||||
<Alert icon="🤗" context="success">
|
||||
**Tips:** 这里需要增加适当的上下文,方便模型结合历史记录进行判断和决策~
|
||||
**Tips:** 这里需要增加适当的上下文,方便模型结合历史纪录进行判断和决策~
|
||||
</Alert>
|
||||
|
||||
## 3. HTTP 模块
|
||||
|
|
|
|||
|
|
@ -3,70 +3,119 @@ title: 接入企微机器人教程
|
|||
description: FastGPT 接入企微机器人教程
|
||||
---
|
||||
|
||||
- 从 4.12.4 版本起,FastGPT 商业版支持直接接入企微机器人,无需额外的 API。
|
||||
- 从 4.14.4 版本起,FastGPT 云服务版支持通过配置自定义域名的方式接入企微智能机器人。
|
||||
从 4.12.4 版本起,FastGPT 商业版支持直接接入企微机器人,无需额外的 API。
|
||||
|
||||
## 1. (云服务版必须)配置自定义域名
|
||||
## 1. 配置可信域名和可信IP
|
||||
|
||||
企微要求智能机器人消息推送地址必须使用企业主体域名,因此云服务版本用户必须先配置自定义域名才能使用企微机器人。
|
||||
点击企微头像,打开管理企业
|
||||
|
||||
- [配置自定义域名](/docs/introduction/guide/team_permissions/customDomain)
|
||||

|
||||
|
||||
若您是商业版用户,请继续使用您企业的域名。
|
||||
在应用管理中找到"自建"-"创建应用"
|
||||
|
||||
## 2. 创建智能机器人
|
||||

|
||||
|
||||
### 2.1 超级管理员登录
|
||||
创建好应用后, 下拉, 依次配置"网页授权及JS-SDK"和"企业可信IP"
|
||||
|
||||
[点击打开企业微信管理后台](https://work.weixin.qq.com/)
|
||||

|
||||
|
||||
### 2.2 找到智能机器人入口
|
||||
其中, 网页授权及JS-SDK要求按照企微指引,完成域名归属认证
|
||||
|
||||
在"安全与管理" - "管理工具"页面点击"智能机器人" ( 注意: 只有企业创建者或超级管理员才有权限看到这个入口 )
|
||||

|
||||
|
||||

|
||||
企业可信IP要求为企业服务器IP, 后续企微的回调URL将请求到此IP
|
||||
|
||||
### 2.3 选择 “API模式创建” 智能机器人
|
||||

|
||||
|
||||
在创建机器人页面, 下拉, 点击 "API模式创建"
|
||||
## 2. 创建企业自建应用
|
||||
|
||||

|
||||
前往 FastGPT ,选择想要接入的应用,在 发布渠道 页面,新建一个接入企微智能机器人的发布渠道,填写好基础信息。
|
||||
|
||||
### 2.4 获取关键密钥
|
||||

|
||||
|
||||
随机生成或者手动输入 Token 和 Encoding-AESKey,并且记录下来
|
||||
现在回到企业微信平台,找到 Corp ID, Secret, Agent ID, Token, AES Key 信息并填写回 FastGPT 平台
|
||||
|
||||

|
||||

|
||||
|
||||
### 2.5 创建企微机器人发布渠道
|
||||
在"我的企业"里找到企业 ID, 填写到 FastGPT 的 Corp ID 中
|
||||
|
||||
在 FastGPT 中,选择要使用 Agent,在发布渠道页面,选择“企业微信机器人”,点击“创建”
|
||||

|
||||
|
||||

|
||||
在应用中找到 Agent Id 和 Secret, 并填写回 FastGPT
|
||||
|
||||
### 2.6 配置发布渠道信息
|
||||

|
||||
|
||||
配置该发布渠道的信息,需要填入 Token 和 AESKey,也就是第四步中记录下来的 Token 和 Encoding-AESKey
|
||||
点击"消息接收"-"设置API接收"
|
||||
|
||||

|
||||

|
||||
|
||||
### 2.7 复制回调地址
|
||||
随机生成或者手动输入 Token 和 Encoding-Key, 分别填写到 FastGPT 的 Token 和 AES Key 中
|
||||
|
||||
点击“确认”后,选择您配置的自定义域名,复制回调地址,填回企微智能机器人配置页中。
|
||||

|
||||
|
||||

|
||||
填写完成后确认创建
|
||||
|
||||
## 3. 使用智能机器人
|
||||
然后点击请求地址, 复制页面中的链接
|
||||
|
||||

|
||||
|
||||
回到刚才的配置详情, 将刚才复制的链接填入 URL 框中, 并点击下方的保存 ,即可完成自建应用的创建
|
||||
|
||||
注意: 若复制的链接是以 "http://localhost" 开头, 需要将本地地址改为企业主体域名
|
||||
|
||||
因为企微会给填写的 URL 发送验证密文, 若 URL 为本地地址, 则本地接收不到企微的密文
|
||||
|
||||
若 URL 不是企业主体域名, 则验证会失败
|
||||
|
||||
## 3. 创建智能机器人
|
||||
|
||||
第二步创建企业自建应用是为了验证域名和IP的合规性, 并获取 secret 参数, 下面创建智能机器人才是正式的配置流程
|
||||
|
||||
在"安全与管理" - "管理工具"页面找到"智能机器人" ( 注意: 只有企业创建者或超级管理员才有权限看到这个入口 )
|
||||
|
||||

|
||||
|
||||
创建机器人页面,下拉,找到,点击"API模式创建"
|
||||
|
||||

|
||||
|
||||
与刚才配置自建应用同理, 在 FastGPT 平台再新增一个发布渠道, 并回到企业微信配置参数
|
||||
|
||||

|
||||
|
||||
随机生成或者手动输入 Token 和 Encoding-AESKey, 分别填写到 FastGPT 的 Token 和 AES Key 中
|
||||
|
||||

|
||||
|
||||
Corp ID 和 Secret 这两个参数和刚才的自建应用保持一致
|
||||
|
||||
Agent ID 和自建应用的不同, 需要先填写一个自定义值, 后续会根据企业微信提供的数据重新更改
|
||||
|
||||
在 FastGPT 将Corp ID, Secret, Agent ID, Token, AES Key 等参数都填写完毕后, 点击确认
|
||||
|
||||
然后点击请求地址, 复制页面中的链接
|
||||
|
||||
回到企业微信, 将链接粘贴到智能机器人的 URL 配置栏, 点击创建
|
||||
|
||||
创建完成后, 找到智能机器人的配置详情
|
||||
|
||||

|
||||
|
||||
复制 Bot ID, 填写到 FastGPT 的 Agent ID 中, 即可完成智能机器人配置
|
||||
|
||||

|
||||
|
||||
## 4. 使用智能机器人
|
||||
|
||||
在企业微信平台的"通讯录",即可找到创建的机器人,就可以发送消息了
|
||||
|
||||

|
||||

|
||||
|
||||
## FAQ
|
||||
|
||||
### 发送了消息,没响应
|
||||
|
||||
1. 检查可信域名是否配置正确。
|
||||
2. 检查 Token 和 Encoding-AESKey 是否正确。
|
||||
3. 查看 FastGPT 对话日志,是否有对应的提问记录。
|
||||
4. 如果没记录,则可能是应用运行报错了,可以先试试最简单的机器人。
|
||||
1. 检查可信域名和可信IP是否配置正确。
|
||||
2. 检查自建应用的 Secret 参数是否与智能机器人一致。
|
||||
3. 查看 FastGPT 对话日志,是否有对应的提问记录
|
||||
4. 如果没记录,则可能是应用运行报错了,可以先试试最简单的机器人.
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
"document/content/docs/faq/app.mdx": "2025-08-02T19:38:37+08:00",
|
||||
"document/content/docs/faq/chat.mdx": "2025-08-02T19:38:37+08:00",
|
||||
"document/content/docs/faq/dataset.mdx": "2025-08-02T19:38:37+08:00",
|
||||
"document/content/docs/faq/error.mdx": "2025-12-10T20:07:05+08:00",
|
||||
"document/content/docs/faq/error.mdx": "2025-08-02T19:38:37+08:00",
|
||||
"document/content/docs/faq/external_channel_integration.mdx": "2025-08-02T19:38:37+08:00",
|
||||
"document/content/docs/faq/index.mdx": "2025-08-02T19:38:37+08:00",
|
||||
"document/content/docs/faq/other.mdx": "2025-08-04T22:07:52+08:00",
|
||||
|
|
@ -26,15 +26,15 @@
|
|||
"document/content/docs/introduction/development/migration/docker_db.mdx": "2025-07-23T21:35:03+08:00",
|
||||
"document/content/docs/introduction/development/migration/docker_mongo.mdx": "2025-07-23T21:35:03+08:00",
|
||||
"document/content/docs/introduction/development/modelConfig/ai-proxy.mdx": "2025-08-05T23:20:39+08:00",
|
||||
"document/content/docs/introduction/development/modelConfig/intro.mdx": "2025-12-03T08:36:19+08:00",
|
||||
"document/content/docs/introduction/development/modelConfig/intro.mdx": "2025-08-12T22:22:18+08:00",
|
||||
"document/content/docs/introduction/development/modelConfig/one-api.mdx": "2025-07-23T21:35:03+08:00",
|
||||
"document/content/docs/introduction/development/modelConfig/ppio.mdx": "2025-09-29T11:52:39+08:00",
|
||||
"document/content/docs/introduction/development/modelConfig/siliconCloud.mdx": "2025-08-05T23:20:39+08:00",
|
||||
"document/content/docs/introduction/development/openapi/app.mdx": "2025-09-26T13:18:51+08:00",
|
||||
"document/content/docs/introduction/development/openapi/chat.mdx": "2025-12-18T13:49:45+08:00",
|
||||
"document/content/docs/introduction/development/openapi/chat.mdx": "2025-11-14T13:21:17+08:00",
|
||||
"document/content/docs/introduction/development/openapi/dataset.mdx": "2025-09-29T11:34:11+08:00",
|
||||
"document/content/docs/introduction/development/openapi/intro.mdx": "2025-09-29T11:34:11+08:00",
|
||||
"document/content/docs/introduction/development/openapi/share.mdx": "2025-12-09T23:33:32+08:00",
|
||||
"document/content/docs/introduction/development/openapi/share.mdx": "2025-08-05T23:20:39+08:00",
|
||||
"document/content/docs/introduction/development/proxy/cloudflare.mdx": "2025-07-23T21:35:03+08:00",
|
||||
"document/content/docs/introduction/development/proxy/http_proxy.mdx": "2025-07-23T21:35:03+08:00",
|
||||
"document/content/docs/introduction/development/proxy/nginx.mdx": "2025-07-23T21:35:03+08:00",
|
||||
|
|
@ -89,7 +89,6 @@
|
|||
"document/content/docs/introduction/guide/plugins/google_search_plugin_guide.mdx": "2025-07-23T21:35:03+08:00",
|
||||
"document/content/docs/introduction/guide/plugins/searxng_plugin_guide.mdx": "2025-07-23T21:35:03+08:00",
|
||||
"document/content/docs/introduction/guide/plugins/upload_system_tool.mdx": "2025-11-04T16:58:12+08:00",
|
||||
"document/content/docs/introduction/guide/team_permissions/customDomain.mdx": "2025-12-10T20:07:05+08:00",
|
||||
"document/content/docs/introduction/guide/team_permissions/invitation_link.mdx": "2025-07-23T21:35:03+08:00",
|
||||
"document/content/docs/introduction/guide/team_permissions/team_roles_permissions.mdx": "2025-07-23T21:35:03+08:00",
|
||||
"document/content/docs/introduction/index.en.mdx": "2025-07-23T21:35:03+08:00",
|
||||
|
|
@ -97,12 +96,12 @@
|
|||
"document/content/docs/protocol/index.mdx": "2025-07-30T15:38:30+08:00",
|
||||
"document/content/docs/protocol/open-source.en.mdx": "2025-08-05T23:20:39+08:00",
|
||||
"document/content/docs/protocol/open-source.mdx": "2025-08-05T23:20:39+08:00",
|
||||
"document/content/docs/protocol/privacy.en.mdx": "2025-12-15T23:36:54+08:00",
|
||||
"document/content/docs/protocol/privacy.mdx": "2025-12-15T23:36:54+08:00",
|
||||
"document/content/docs/protocol/terms.en.mdx": "2025-12-15T23:36:54+08:00",
|
||||
"document/content/docs/protocol/terms.mdx": "2025-12-15T23:36:54+08:00",
|
||||
"document/content/docs/protocol/privacy.en.mdx": "2025-08-03T22:37:45+08:00",
|
||||
"document/content/docs/protocol/privacy.mdx": "2025-08-03T22:37:45+08:00",
|
||||
"document/content/docs/protocol/terms.en.mdx": "2025-08-03T22:37:45+08:00",
|
||||
"document/content/docs/protocol/terms.mdx": "2025-08-03T22:37:45+08:00",
|
||||
"document/content/docs/toc.en.mdx": "2025-08-04T13:42:36+08:00",
|
||||
"document/content/docs/toc.mdx": "2025-12-17T17:44:38+08:00",
|
||||
"document/content/docs/toc.mdx": "2025-11-14T13:21:17+08:00",
|
||||
"document/content/docs/upgrading/4-10/4100.mdx": "2025-08-02T19:38:37+08:00",
|
||||
"document/content/docs/upgrading/4-10/4101.mdx": "2025-09-08T20:07:20+08:00",
|
||||
"document/content/docs/upgrading/4-11/4110.mdx": "2025-08-05T23:20:39+08:00",
|
||||
|
|
@ -114,13 +113,10 @@
|
|||
"document/content/docs/upgrading/4-12/4124.mdx": "2025-09-17T22:29:56+08:00",
|
||||
"document/content/docs/upgrading/4-13/4130.mdx": "2025-11-04T15:06:39+08:00",
|
||||
"document/content/docs/upgrading/4-13/4131.mdx": "2025-09-30T15:47:06+08:00",
|
||||
"document/content/docs/upgrading/4-13/4132.mdx": "2025-12-15T11:50:00+08:00",
|
||||
"document/content/docs/upgrading/4-13/4132.mdx": "2025-10-21T11:46:53+08:00",
|
||||
"document/content/docs/upgrading/4-14/4140.mdx": "2025-11-06T15:43:00+08:00",
|
||||
"document/content/docs/upgrading/4-14/4141.mdx": "2025-11-19T10:15:27+08:00",
|
||||
"document/content/docs/upgrading/4-14/4142.mdx": "2025-11-18T19:27:14+08:00",
|
||||
"document/content/docs/upgrading/4-14/4143.mdx": "2025-11-26T20:52:05+08:00",
|
||||
"document/content/docs/upgrading/4-14/4144.mdx": "2025-12-16T14:56:04+08:00",
|
||||
"document/content/docs/upgrading/4-14/4145.mdx": "2025-12-21T23:28:19+08:00",
|
||||
"document/content/docs/upgrading/4-14/4141.mdx": "2025-11-12T12:19:02+08:00",
|
||||
"document/content/docs/upgrading/4-14/4142.mdx": "2025-11-17T21:02:39+08:00",
|
||||
"document/content/docs/upgrading/4-8/40.mdx": "2025-08-02T19:38:37+08:00",
|
||||
"document/content/docs/upgrading/4-8/41.mdx": "2025-08-02T19:38:37+08:00",
|
||||
"document/content/docs/upgrading/4-8/42.mdx": "2025-08-02T19:38:37+08:00",
|
||||
|
|
@ -192,7 +188,7 @@
|
|||
"document/content/docs/use-cases/app-cases/feishu_webhook.mdx": "2025-07-23T21:35:03+08:00",
|
||||
"document/content/docs/use-cases/app-cases/fixingEvidence.mdx": "2025-07-23T21:35:03+08:00",
|
||||
"document/content/docs/use-cases/app-cases/google_search.mdx": "2025-07-23T21:35:03+08:00",
|
||||
"document/content/docs/use-cases/app-cases/lab_appointment.mdx": "2025-12-10T20:07:05+08:00",
|
||||
"document/content/docs/use-cases/app-cases/lab_appointment.mdx": "2025-07-23T21:35:03+08:00",
|
||||
"document/content/docs/use-cases/app-cases/multi_turn_translation_bot.mdx": "2025-07-23T21:35:03+08:00",
|
||||
"document/content/docs/use-cases/app-cases/submit_application_template.mdx": "2025-08-05T23:20:39+08:00",
|
||||
"document/content/docs/use-cases/app-cases/translate-subtitle-using-gpt.mdx": "2025-07-23T21:35:03+08:00",
|
||||
|
|
@ -200,6 +196,6 @@
|
|||
"document/content/docs/use-cases/external-integration/feishu.mdx": "2025-07-24T14:23:04+08:00",
|
||||
"document/content/docs/use-cases/external-integration/official_account.mdx": "2025-08-05T23:20:39+08:00",
|
||||
"document/content/docs/use-cases/external-integration/openapi.mdx": "2025-09-29T11:34:11+08:00",
|
||||
"document/content/docs/use-cases/external-integration/wecom.mdx": "2025-12-10T20:07:05+08:00",
|
||||
"document/content/docs/use-cases/external-integration/wecom.mdx": "2025-09-16T14:22:28+08:00",
|
||||
"document/content/docs/use-cases/index.mdx": "2025-07-24T14:23:04+08:00"
|
||||
}
|
||||
|
|
@ -18,7 +18,7 @@
|
|||
"fumadocs-ui": "15.6.3",
|
||||
"gray-matter": "^4.0.3",
|
||||
"lucide-react": "^0.525.0",
|
||||
"next": "15.5.9",
|
||||
"next": "15.3.5",
|
||||
"react": "^19.1.0",
|
||||
"react-dom": "^19.1.0",
|
||||
"react-responsive": "^10.0.1",
|
||||
|
|
@ -41,6 +41,212 @@
|
|||
"zod": "^4.0.5"
|
||||
}
|
||||
},
|
||||
"node_modules/@algolia/client-abtesting": {
|
||||
"version": "5.34.0",
|
||||
"resolved": "https://registry.npmjs.org/@algolia/client-abtesting/-/client-abtesting-5.34.0.tgz",
|
||||
"integrity": "sha512-d6ardhDtQsnMpyr/rPrS3YuIE9NYpY4rftkC7Ap9tyuhZ/+V3E/LH+9uEewPguKzVqduApdwJzYq2k+vAXVEbQ==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@algolia/client-common": "5.34.0",
|
||||
"@algolia/requester-browser-xhr": "5.34.0",
|
||||
"@algolia/requester-fetch": "5.34.0",
|
||||
"@algolia/requester-node-http": "5.34.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 14.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@algolia/client-analytics": {
|
||||
"version": "5.34.0",
|
||||
"resolved": "https://registry.npmjs.org/@algolia/client-analytics/-/client-analytics-5.34.0.tgz",
|
||||
"integrity": "sha512-WXIByjHNA106JO1Dj6b4viSX/yMN3oIB4qXr2MmyEmNq0MgfuPfPw8ayLRIZPa9Dp27hvM3G8MWJ4RG978HYFw==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@algolia/client-common": "5.34.0",
|
||||
"@algolia/requester-browser-xhr": "5.34.0",
|
||||
"@algolia/requester-fetch": "5.34.0",
|
||||
"@algolia/requester-node-http": "5.34.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 14.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@algolia/client-common": {
|
||||
"version": "5.34.0",
|
||||
"resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-5.34.0.tgz",
|
||||
"integrity": "sha512-JeN1XJLZIkkv6yK0KT93CIXXk+cDPUGNg5xeH4fN9ZykYFDWYRyqgaDo+qvg4RXC3WWkdQ+hogQuuCk4Y3Eotw==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">= 14.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@algolia/client-insights": {
|
||||
"version": "5.34.0",
|
||||
"resolved": "https://registry.npmjs.org/@algolia/client-insights/-/client-insights-5.34.0.tgz",
|
||||
"integrity": "sha512-gdFlcQa+TWXJUsihHDlreFWniKPFIQ15i5oynCY4m9K3DCex5g5cVj9VG4Hsquxf2t6Y0yv8w6MvVTGDO8oRLw==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@algolia/client-common": "5.34.0",
|
||||
"@algolia/requester-browser-xhr": "5.34.0",
|
||||
"@algolia/requester-fetch": "5.34.0",
|
||||
"@algolia/requester-node-http": "5.34.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 14.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@algolia/client-personalization": {
|
||||
"version": "5.34.0",
|
||||
"resolved": "https://registry.npmjs.org/@algolia/client-personalization/-/client-personalization-5.34.0.tgz",
|
||||
"integrity": "sha512-g91NHhIZDkh1IUeNtsUd8V/ZxuBc2ByOfDqhCkoQY3Z/mZszhpn3Czn6AR5pE81fx793vMaiOZvQVB5QttArkQ==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@algolia/client-common": "5.34.0",
|
||||
"@algolia/requester-browser-xhr": "5.34.0",
|
||||
"@algolia/requester-fetch": "5.34.0",
|
||||
"@algolia/requester-node-http": "5.34.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 14.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@algolia/client-query-suggestions": {
|
||||
"version": "5.34.0",
|
||||
"resolved": "https://registry.npmjs.org/@algolia/client-query-suggestions/-/client-query-suggestions-5.34.0.tgz",
|
||||
"integrity": "sha512-cvRApDfFrlJ3Vcn37U4Nd/7S6T8cx7FW3mVLJPqkkzixv8DQ/yV+x4VLirxOtGDdq3KohcIbIGWbg1QuyOZRvQ==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@algolia/client-common": "5.34.0",
|
||||
"@algolia/requester-browser-xhr": "5.34.0",
|
||||
"@algolia/requester-fetch": "5.34.0",
|
||||
"@algolia/requester-node-http": "5.34.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 14.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@algolia/client-search": {
|
||||
"version": "5.34.0",
|
||||
"resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-5.34.0.tgz",
|
||||
"integrity": "sha512-m9tK4IqJmn+flEPRtuxuHgiHmrKV0su5fuVwVpq8/es4DMjWMgX1a7Lg1PktvO8AbKaTp9kTtBAPnwXpuCwmEg==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@algolia/client-common": "5.34.0",
|
||||
"@algolia/requester-browser-xhr": "5.34.0",
|
||||
"@algolia/requester-fetch": "5.34.0",
|
||||
"@algolia/requester-node-http": "5.34.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 14.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@algolia/ingestion": {
|
||||
"version": "1.34.0",
|
||||
"resolved": "https://registry.npmjs.org/@algolia/ingestion/-/ingestion-1.34.0.tgz",
|
||||
"integrity": "sha512-2rxy4XoeRtIpzxEh5u5UgDC5HY4XbNdjzNgFx1eDrfFkSHpEVjirtLhISMy2N5uSFqYu1uUby5/NC1Soq8J7iw==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@algolia/client-common": "5.34.0",
|
||||
"@algolia/requester-browser-xhr": "5.34.0",
|
||||
"@algolia/requester-fetch": "5.34.0",
|
||||
"@algolia/requester-node-http": "5.34.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 14.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@algolia/monitoring": {
|
||||
"version": "1.34.0",
|
||||
"resolved": "https://registry.npmjs.org/@algolia/monitoring/-/monitoring-1.34.0.tgz",
|
||||
"integrity": "sha512-OJiDhlJX8ZdWAndc50Z6aUEW/YmnhFK2ul3rahMw5/c9Damh7+oY9SufoK2LimJejy+65Qka06YPG29v2G/vww==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@algolia/client-common": "5.34.0",
|
||||
"@algolia/requester-browser-xhr": "5.34.0",
|
||||
"@algolia/requester-fetch": "5.34.0",
|
||||
"@algolia/requester-node-http": "5.34.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 14.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@algolia/recommend": {
|
||||
"version": "5.34.0",
|
||||
"resolved": "https://registry.npmjs.org/@algolia/recommend/-/recommend-5.34.0.tgz",
|
||||
"integrity": "sha512-fzNQZAdVxu/Gnbavy8KW5gurApwdYcPW6+pjO7Pw8V5drCR3eSqnOxSvp79rhscDX8ezwqMqqK4F3Hsq+KpRzg==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@algolia/client-common": "5.34.0",
|
||||
"@algolia/requester-browser-xhr": "5.34.0",
|
||||
"@algolia/requester-fetch": "5.34.0",
|
||||
"@algolia/requester-node-http": "5.34.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 14.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@algolia/requester-browser-xhr": {
|
||||
"version": "5.34.0",
|
||||
"resolved": "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-5.34.0.tgz",
|
||||
"integrity": "sha512-gEI0xjzA/xvMpEdYmgQnf6AQKllhgKRtnEWmwDrnct+YPIruEHlx1dd7nRJTy/33MiYcCxkB4khXpNrHuqgp3Q==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@algolia/client-common": "5.34.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 14.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@algolia/requester-fetch": {
|
||||
"version": "5.34.0",
|
||||
"resolved": "https://registry.npmjs.org/@algolia/requester-fetch/-/requester-fetch-5.34.0.tgz",
|
||||
"integrity": "sha512-5SwGOttpbACT4jXzfSJ3mnTcF46SVNSnZ1JjxC3qBa3qKi4U0CJGzuVVy3L798u8dG5H0SZ2MAB5v7180Gnqew==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@algolia/client-common": "5.34.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 14.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@algolia/requester-node-http": {
|
||||
"version": "5.34.0",
|
||||
"resolved": "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-5.34.0.tgz",
|
||||
"integrity": "sha512-409XlyIyEXrxyGjWxd0q5RASizHSRVUU0AXPCEdqnbcGEzbCgL1n7oYI8YxzE/RqZLha+PNwWCcTVn7EE5tyyQ==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@algolia/client-common": "5.34.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 14.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@alloc/quick-lru": {
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz",
|
||||
|
|
@ -1104,15 +1310,15 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@next/env": {
|
||||
"version": "15.5.9",
|
||||
"resolved": "https://registry.npmjs.org/@next/env/-/env-15.5.9.tgz",
|
||||
"integrity": "sha512-4GlTZ+EJM7WaW2HEZcyU317tIQDjkQIyENDLxYJfSWlfqguN+dHkZgyQTV/7ykvobU7yEH5gKvreNrH4B6QgIg==",
|
||||
"version": "15.3.5",
|
||||
"resolved": "https://registry.npmjs.org/@next/env/-/env-15.3.5.tgz",
|
||||
"integrity": "sha512-7g06v8BUVtN2njAX/r8gheoVffhiKFVt4nx74Tt6G4Hqw9HCLYQVx/GkH2qHvPtAHZaUNZ0VXAa0pQP6v1wk7g==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@next/swc-darwin-arm64": {
|
||||
"version": "15.5.7",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-15.5.7.tgz",
|
||||
"integrity": "sha512-IZwtxCEpI91HVU/rAUOOobWSZv4P2DeTtNaCdHqLcTJU4wdNXgAySvKa/qJCgR5m6KI8UsKDXtO2B31jcaw1Yw==",
|
||||
"version": "15.3.5",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-15.3.5.tgz",
|
||||
"integrity": "sha512-lM/8tilIsqBq+2nq9kbTW19vfwFve0NR7MxfkuSUbRSgXlMQoJYg+31+++XwKVSXk4uT23G2eF/7BRIKdn8t8w==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
|
|
@ -1126,9 +1332,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@next/swc-darwin-x64": {
|
||||
"version": "15.5.7",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-15.5.7.tgz",
|
||||
"integrity": "sha512-UP6CaDBcqaCBuiq/gfCEJw7sPEoX1aIjZHnBWN9v9qYHQdMKvCKcAVs4OX1vIjeE+tC5EIuwDTVIoXpUes29lg==",
|
||||
"version": "15.3.5",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-15.3.5.tgz",
|
||||
"integrity": "sha512-WhwegPQJ5IfoUNZUVsI9TRAlKpjGVK0tpJTL6KeiC4cux9774NYE9Wu/iCfIkL/5J8rPAkqZpG7n+EfiAfidXA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
|
|
@ -1142,9 +1348,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@next/swc-linux-arm64-gnu": {
|
||||
"version": "15.5.7",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-15.5.7.tgz",
|
||||
"integrity": "sha512-NCslw3GrNIw7OgmRBxHtdWFQYhexoUCq+0oS2ccjyYLtcn1SzGzeM54jpTFonIMUjNbHmpKpziXnpxhSWLcmBA==",
|
||||
"version": "15.3.5",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-15.3.5.tgz",
|
||||
"integrity": "sha512-LVD6uMOZ7XePg3KWYdGuzuvVboxujGjbcuP2jsPAN3MnLdLoZUXKRc6ixxfs03RH7qBdEHCZjyLP/jBdCJVRJQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
|
|
@ -1158,9 +1364,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@next/swc-linux-arm64-musl": {
|
||||
"version": "15.5.7",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-15.5.7.tgz",
|
||||
"integrity": "sha512-nfymt+SE5cvtTrG9u1wdoxBr9bVB7mtKTcj0ltRn6gkP/2Nu1zM5ei8rwP9qKQP0Y//umK+TtkKgNtfboBxRrw==",
|
||||
"version": "15.3.5",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-15.3.5.tgz",
|
||||
"integrity": "sha512-k8aVScYZ++BnS2P69ClK7v4nOu702jcF9AIHKu6llhHEtBSmM2zkPGl9yoqbSU/657IIIb0QHpdxEr0iW9z53A==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
|
|
@ -1174,9 +1380,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@next/swc-linux-x64-gnu": {
|
||||
"version": "15.5.7",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-15.5.7.tgz",
|
||||
"integrity": "sha512-hvXcZvCaaEbCZcVzcY7E1uXN9xWZfFvkNHwbe/n4OkRhFWrs1J1QV+4U1BN06tXLdaS4DazEGXwgqnu/VMcmqw==",
|
||||
"version": "15.3.5",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-15.3.5.tgz",
|
||||
"integrity": "sha512-2xYU0DI9DGN/bAHzVwADid22ba5d/xrbrQlr2U+/Q5WkFUzeL0TDR963BdrtLS/4bMmKZGptLeg6282H/S2i8A==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
|
|
@ -1190,9 +1396,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@next/swc-linux-x64-musl": {
|
||||
"version": "15.5.7",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-15.5.7.tgz",
|
||||
"integrity": "sha512-4IUO539b8FmF0odY6/SqANJdgwn1xs1GkPO5doZugwZ3ETF6JUdckk7RGmsfSf7ws8Qb2YB5It33mvNL/0acqA==",
|
||||
"version": "15.3.5",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-15.3.5.tgz",
|
||||
"integrity": "sha512-TRYIqAGf1KCbuAB0gjhdn5Ytd8fV+wJSM2Nh2is/xEqR8PZHxfQuaiNhoF50XfY90sNpaRMaGhF6E+qjV1b9Tg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
|
|
@ -1206,9 +1412,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@next/swc-win32-arm64-msvc": {
|
||||
"version": "15.5.7",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-15.5.7.tgz",
|
||||
"integrity": "sha512-CpJVTkYI3ZajQkC5vajM7/ApKJUOlm6uP4BknM3XKvJ7VXAvCqSjSLmM0LKdYzn6nBJVSjdclx8nYJSa3xlTgQ==",
|
||||
"version": "15.3.5",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-15.3.5.tgz",
|
||||
"integrity": "sha512-h04/7iMEUSMY6fDGCvdanKqlO1qYvzNxntZlCzfE8i5P0uqzVQWQquU1TIhlz0VqGQGXLrFDuTJVONpqGqjGKQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
|
|
@ -1222,9 +1428,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@next/swc-win32-x64-msvc": {
|
||||
"version": "15.5.7",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-15.5.7.tgz",
|
||||
"integrity": "sha512-gMzgBX164I6DN+9/PGA+9dQiwmTkE4TloBNx8Kv9UiGARsr9Nba7IpcBRA1iTV9vwlYnrE3Uy6I7Aj6qLjQuqw==",
|
||||
"version": "15.3.5",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-15.3.5.tgz",
|
||||
"integrity": "sha512-5fhH6fccXxnX2KhllnGhkYMndhOiLOLEiVGYjP2nizqeGWkN10sA9taATlXwake2E2XMvYZjjz0Uj7T0y+z1yw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
|
|
@ -2128,6 +2334,12 @@
|
|||
"integrity": "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@swc/counter": {
|
||||
"version": "0.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz",
|
||||
"integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==",
|
||||
"license": "Apache-2.0"
|
||||
},
|
||||
"node_modules/@swc/helpers": {
|
||||
"version": "0.5.15",
|
||||
"resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz",
|
||||
|
|
@ -2543,7 +2755,6 @@
|
|||
"integrity": "sha512-AwAfQ2Wa5bCx9WP8nZL2uMZWod7J7/JSplxbTmBQ5ms6QpqNYm672H0Vu9ZVKVngQ+ii4R/byguVEUZQyeg44g==",
|
||||
"devOptional": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"csstype": "^3.0.2"
|
||||
}
|
||||
|
|
@ -2554,7 +2765,6 @@
|
|||
"integrity": "sha512-4hOiT/dwO8Ko0gV1m/TJZYk3y0KBnY9vzDh7W+DH17b2HFSOGgdj33dhihPeuy3l0q23+4e+hoXHV6hCC4dCXw==",
|
||||
"devOptional": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"peerDependencies": {
|
||||
"@types/react": "^19.0.0"
|
||||
}
|
||||
|
|
@ -2576,7 +2786,6 @@
|
|||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
|
||||
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"acorn": "bin/acorn"
|
||||
},
|
||||
|
|
@ -2593,6 +2802,32 @@
|
|||
"acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/algoliasearch": {
|
||||
"version": "5.34.0",
|
||||
"resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-5.34.0.tgz",
|
||||
"integrity": "sha512-wioVnf/8uuG8Bmywhk5qKIQ3wzCCtmdvicPRb0fa3kKYGGoewfgDqLEaET1MV2NbTc3WGpPv+AgauLVBp1nB9A==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@algolia/client-abtesting": "5.34.0",
|
||||
"@algolia/client-analytics": "5.34.0",
|
||||
"@algolia/client-common": "5.34.0",
|
||||
"@algolia/client-insights": "5.34.0",
|
||||
"@algolia/client-personalization": "5.34.0",
|
||||
"@algolia/client-query-suggestions": "5.34.0",
|
||||
"@algolia/client-search": "5.34.0",
|
||||
"@algolia/ingestion": "1.34.0",
|
||||
"@algolia/monitoring": "1.34.0",
|
||||
"@algolia/recommend": "5.34.0",
|
||||
"@algolia/requester-browser-xhr": "5.34.0",
|
||||
"@algolia/requester-fetch": "5.34.0",
|
||||
"@algolia/requester-node-http": "5.34.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 14.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/argparse": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
|
||||
|
|
@ -2642,6 +2877,17 @@
|
|||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/busboy": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz",
|
||||
"integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==",
|
||||
"dependencies": {
|
||||
"streamsearch": "^1.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.16.0"
|
||||
}
|
||||
},
|
||||
"node_modules/camelcase": {
|
||||
"version": "8.0.0",
|
||||
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-8.0.0.tgz",
|
||||
|
|
@ -3244,7 +3490,6 @@
|
|||
"resolved": "https://registry.npmjs.org/fumadocs-core/-/fumadocs-core-15.6.3.tgz",
|
||||
"integrity": "sha512-71IPC6Y0ZLPHlavYormnF1r2uX/lNrTFTYCEh6Akll8hWxRNbKG9Hk4xpFJDTkU83c8eLtHk2iow/ccQkcV6Hw==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@formatjs/intl-localematcher": "^0.6.1",
|
||||
"@orama/orama": "^3.1.9",
|
||||
|
|
@ -4295,9 +4540,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/mdast-util-to-hast": {
|
||||
"version": "13.2.1",
|
||||
"resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.2.1.tgz",
|
||||
"integrity": "sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA==",
|
||||
"version": "13.2.0",
|
||||
"resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.2.0.tgz",
|
||||
"integrity": "sha512-QGYKEuUsYT9ykKBCMOEDLsU5JRObWQusAolFMeko/tYPufNkRffBAQjIE+99jbA87xv6FgmjLtwjh9wBWajwAA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/hast": "^3.0.0",
|
||||
|
|
@ -5173,14 +5418,15 @@
|
|||
}
|
||||
},
|
||||
"node_modules/next": {
|
||||
"version": "15.5.9",
|
||||
"resolved": "https://registry.npmjs.org/next/-/next-15.5.9.tgz",
|
||||
"integrity": "sha512-agNLK89seZEtC5zUHwtut0+tNrc0Xw4FT/Dg+B/VLEo9pAcS9rtTKpek3V6kVcVwsB2YlqMaHdfZL4eLEVYuCg==",
|
||||
"version": "15.3.5",
|
||||
"resolved": "https://registry.npmjs.org/next/-/next-15.3.5.tgz",
|
||||
"integrity": "sha512-RkazLBMMDJSJ4XZQ81kolSpwiCt907l0xcgcpF4xC2Vml6QVcPNXW0NQRwQ80FFtSn7UM52XN0anaw8TEJXaiw==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@next/env": "15.5.9",
|
||||
"@next/env": "15.3.5",
|
||||
"@swc/counter": "0.1.3",
|
||||
"@swc/helpers": "0.5.15",
|
||||
"busboy": "1.6.0",
|
||||
"caniuse-lite": "^1.0.30001579",
|
||||
"postcss": "8.4.31",
|
||||
"styled-jsx": "5.1.6"
|
||||
|
|
@ -5192,19 +5438,19 @@
|
|||
"node": "^18.18.0 || ^19.8.0 || >= 20.0.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@next/swc-darwin-arm64": "15.5.7",
|
||||
"@next/swc-darwin-x64": "15.5.7",
|
||||
"@next/swc-linux-arm64-gnu": "15.5.7",
|
||||
"@next/swc-linux-arm64-musl": "15.5.7",
|
||||
"@next/swc-linux-x64-gnu": "15.5.7",
|
||||
"@next/swc-linux-x64-musl": "15.5.7",
|
||||
"@next/swc-win32-arm64-msvc": "15.5.7",
|
||||
"@next/swc-win32-x64-msvc": "15.5.7",
|
||||
"sharp": "^0.34.3"
|
||||
"@next/swc-darwin-arm64": "15.3.5",
|
||||
"@next/swc-darwin-x64": "15.3.5",
|
||||
"@next/swc-linux-arm64-gnu": "15.3.5",
|
||||
"@next/swc-linux-arm64-musl": "15.3.5",
|
||||
"@next/swc-linux-x64-gnu": "15.3.5",
|
||||
"@next/swc-linux-x64-musl": "15.3.5",
|
||||
"@next/swc-win32-arm64-msvc": "15.3.5",
|
||||
"@next/swc-win32-x64-msvc": "15.3.5",
|
||||
"sharp": "^0.34.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@opentelemetry/api": "^1.1.0",
|
||||
"@playwright/test": "^1.51.1",
|
||||
"@playwright/test": "^1.41.2",
|
||||
"babel-plugin-react-compiler": "*",
|
||||
"react": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0",
|
||||
"react-dom": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0",
|
||||
|
|
@ -5353,7 +5599,6 @@
|
|||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
|
||||
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
|
|
@ -5469,7 +5714,6 @@
|
|||
"resolved": "https://registry.npmjs.org/react/-/react-19.1.0.tgz",
|
||||
"integrity": "sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
|
|
@ -5479,7 +5723,6 @@
|
|||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.0.tgz",
|
||||
"integrity": "sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"scheduler": "^0.26.0"
|
||||
},
|
||||
|
|
@ -6022,6 +6265,14 @@
|
|||
"integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==",
|
||||
"license": "BSD-3-Clause"
|
||||
},
|
||||
"node_modules/streamsearch": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz",
|
||||
"integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==",
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/stringify-entities": {
|
||||
"version": "4.0.4",
|
||||
"resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-4.0.4.tgz",
|
||||
|
|
@ -6101,8 +6352,7 @@
|
|||
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.11.tgz",
|
||||
"integrity": "sha512-2E9TBm6MDD/xKYe+dvJZAmg3yxIEDNRc0jwlNyDg/4Fil2QcSLjFKGVff0lAf1jjeaArlG/M75Ey/EYr/OJtBA==",
|
||||
"devOptional": true,
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/tapable": {
|
||||
"version": "2.2.2",
|
||||
|
|
@ -6198,7 +6448,6 @@
|
|||
"integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"tsc": "bin/tsc",
|
||||
"tsserver": "bin/tsserver"
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@
|
|||
"fumadocs-ui": "15.6.3",
|
||||
"gray-matter": "^4.0.3",
|
||||
"lucide-react": "^0.525.0",
|
||||
"next": "15.5.9",
|
||||
"next": "15.3.5",
|
||||
"react": "^19.1.0",
|
||||
"react-dom": "^19.1.0",
|
||||
"react-responsive": "^10.0.1",
|
||||
|
|
|
|||
|
|
@ -16,8 +16,6 @@
|
|||
"url": "", // 自定义 PDF 解析服务地址
|
||||
"key": "", // 自定义 PDF 解析服务密钥
|
||||
"doc2xKey": "", // doc2x 服务密钥
|
||||
"textinAppId": "", // 合合信息 Textin 服务 App ID
|
||||
"textinSecretCode": "", // 合合信息 Textin 服务 Secret Code
|
||||
"price": 0 // PDF 解析服务价格
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -177,7 +177,7 @@ services:
|
|||
|
||||
fastgpt:
|
||||
container_name: fastgpt
|
||||
image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.14.4 # git
|
||||
image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.14.1 # git
|
||||
ports:
|
||||
- 3000:3000
|
||||
networks:
|
||||
|
|
@ -227,13 +227,13 @@ services:
|
|||
- ./config.json:/app/data/config.json
|
||||
sandbox:
|
||||
container_name: sandbox
|
||||
image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-sandbox:v4.14.4
|
||||
image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-sandbox:v4.14.1
|
||||
networks:
|
||||
- fastgpt
|
||||
restart: always
|
||||
fastgpt-mcp-server:
|
||||
container_name: fastgpt-mcp-server
|
||||
image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-mcp_server:v4.14.4
|
||||
image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-mcp_server:v4.14.1
|
||||
networks:
|
||||
- fastgpt
|
||||
ports:
|
||||
|
|
@ -242,7 +242,7 @@ services:
|
|||
environment:
|
||||
- FASTGPT_ENDPOINT=http://fastgpt:3000
|
||||
fastgpt-plugin:
|
||||
image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-plugin:v0.3.4
|
||||
image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-plugin:v0.3.1
|
||||
container_name: fastgpt-plugin
|
||||
restart: always
|
||||
networks:
|
||||
|
|
|
|||
|
|
@ -154,7 +154,7 @@ services:
|
|||
|
||||
fastgpt:
|
||||
container_name: fastgpt
|
||||
image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.14.4 # git
|
||||
image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.14.1 # git
|
||||
ports:
|
||||
- 3000:3000
|
||||
networks:
|
||||
|
|
@ -204,13 +204,13 @@ services:
|
|||
- ./config.json:/app/data/config.json
|
||||
sandbox:
|
||||
container_name: sandbox
|
||||
image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-sandbox:v4.14.4
|
||||
image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-sandbox:v4.14.1
|
||||
networks:
|
||||
- fastgpt
|
||||
restart: always
|
||||
fastgpt-mcp-server:
|
||||
container_name: fastgpt-mcp-server
|
||||
image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-mcp_server:v4.14.4
|
||||
image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-mcp_server:v4.14.1
|
||||
networks:
|
||||
- fastgpt
|
||||
ports:
|
||||
|
|
@ -219,7 +219,7 @@ services:
|
|||
environment:
|
||||
- FASTGPT_ENDPOINT=http://fastgpt:3000
|
||||
fastgpt-plugin:
|
||||
image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-plugin:v0.3.4
|
||||
image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-plugin:v0.3.1
|
||||
container_name: fastgpt-plugin
|
||||
restart: always
|
||||
networks:
|
||||
|
|
|
|||
|
|
@ -135,7 +135,7 @@ services:
|
|||
|
||||
fastgpt:
|
||||
container_name: fastgpt
|
||||
image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.14.4 # git
|
||||
image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.14.1 # git
|
||||
ports:
|
||||
- 3000:3000
|
||||
networks:
|
||||
|
|
@ -185,13 +185,13 @@ services:
|
|||
- ./config.json:/app/data/config.json
|
||||
sandbox:
|
||||
container_name: sandbox
|
||||
image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-sandbox:v4.14.4
|
||||
image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-sandbox:v4.14.1
|
||||
networks:
|
||||
- fastgpt
|
||||
restart: always
|
||||
fastgpt-mcp-server:
|
||||
container_name: fastgpt-mcp-server
|
||||
image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-mcp_server:v4.14.4
|
||||
image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-mcp_server:v4.14.1
|
||||
networks:
|
||||
- fastgpt
|
||||
ports:
|
||||
|
|
@ -200,7 +200,7 @@ services:
|
|||
environment:
|
||||
- FASTGPT_ENDPOINT=http://fastgpt:3000
|
||||
fastgpt-plugin:
|
||||
image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-plugin:v0.3.4
|
||||
image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-plugin:v0.3.1
|
||||
container_name: fastgpt-plugin
|
||||
restart: always
|
||||
networks:
|
||||
|
|
|
|||
|
|
@ -118,7 +118,7 @@ services:
|
|||
|
||||
fastgpt:
|
||||
container_name: fastgpt
|
||||
image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.14.4 # git
|
||||
image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.14.1 # git
|
||||
ports:
|
||||
- 3000:3000
|
||||
networks:
|
||||
|
|
@ -168,13 +168,13 @@ services:
|
|||
- ./config.json:/app/data/config.json
|
||||
sandbox:
|
||||
container_name: sandbox
|
||||
image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-sandbox:v4.14.4
|
||||
image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-sandbox:v4.14.1
|
||||
networks:
|
||||
- fastgpt
|
||||
restart: always
|
||||
fastgpt-mcp-server:
|
||||
container_name: fastgpt-mcp-server
|
||||
image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-mcp_server:v4.14.4
|
||||
image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-mcp_server:v4.14.1
|
||||
networks:
|
||||
- fastgpt
|
||||
ports:
|
||||
|
|
@ -183,7 +183,7 @@ services:
|
|||
environment:
|
||||
- FASTGPT_ENDPOINT=http://fastgpt:3000
|
||||
fastgpt-plugin:
|
||||
image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-plugin:v0.3.4
|
||||
image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-plugin:v0.3.1
|
||||
container_name: fastgpt-plugin
|
||||
restart: always
|
||||
networks:
|
||||
|
|
|
|||
|
|
@ -177,7 +177,7 @@ services:
|
|||
|
||||
fastgpt:
|
||||
container_name: fastgpt
|
||||
image: ghcr.io/labring/fastgpt:v4.14.4 # git
|
||||
image: ghcr.io/labring/fastgpt:v4.14.1 # git
|
||||
ports:
|
||||
- 3000:3000
|
||||
networks:
|
||||
|
|
@ -227,13 +227,13 @@ services:
|
|||
- ./config.json:/app/data/config.json
|
||||
sandbox:
|
||||
container_name: sandbox
|
||||
image: ghcr.io/labring/fastgpt-sandbox:v4.14.4
|
||||
image: ghcr.io/labring/fastgpt-sandbox:v4.14.1
|
||||
networks:
|
||||
- fastgpt
|
||||
restart: always
|
||||
fastgpt-mcp-server:
|
||||
container_name: fastgpt-mcp-server
|
||||
image: ghcr.io/labring/fastgpt-mcp_server:v4.14.4
|
||||
image: ghcr.io/labring/fastgpt-mcp_server:v4.14.1
|
||||
networks:
|
||||
- fastgpt
|
||||
ports:
|
||||
|
|
@ -242,7 +242,7 @@ services:
|
|||
environment:
|
||||
- FASTGPT_ENDPOINT=http://fastgpt:3000
|
||||
fastgpt-plugin:
|
||||
image: ghcr.io/labring/fastgpt-plugin:v0.3.4
|
||||
image: ghcr.io/labring/fastgpt-plugin:v0.3.1
|
||||
container_name: fastgpt-plugin
|
||||
restart: always
|
||||
networks:
|
||||
|
|
|
|||
|
|
@ -154,7 +154,7 @@ services:
|
|||
|
||||
fastgpt:
|
||||
container_name: fastgpt
|
||||
image: ghcr.io/labring/fastgpt:v4.14.4 # git
|
||||
image: ghcr.io/labring/fastgpt:v4.14.1 # git
|
||||
ports:
|
||||
- 3000:3000
|
||||
networks:
|
||||
|
|
@ -204,13 +204,13 @@ services:
|
|||
- ./config.json:/app/data/config.json
|
||||
sandbox:
|
||||
container_name: sandbox
|
||||
image: ghcr.io/labring/fastgpt-sandbox:v4.14.4
|
||||
image: ghcr.io/labring/fastgpt-sandbox:v4.14.1
|
||||
networks:
|
||||
- fastgpt
|
||||
restart: always
|
||||
fastgpt-mcp-server:
|
||||
container_name: fastgpt-mcp-server
|
||||
image: ghcr.io/labring/fastgpt-mcp_server:v4.14.4
|
||||
image: ghcr.io/labring/fastgpt-mcp_server:v4.14.1
|
||||
networks:
|
||||
- fastgpt
|
||||
ports:
|
||||
|
|
@ -219,7 +219,7 @@ services:
|
|||
environment:
|
||||
- FASTGPT_ENDPOINT=http://fastgpt:3000
|
||||
fastgpt-plugin:
|
||||
image: ghcr.io/labring/fastgpt-plugin:v0.3.4
|
||||
image: ghcr.io/labring/fastgpt-plugin:v0.3.1
|
||||
container_name: fastgpt-plugin
|
||||
restart: always
|
||||
networks:
|
||||
|
|
|
|||
|
|
@ -135,7 +135,7 @@ services:
|
|||
|
||||
fastgpt:
|
||||
container_name: fastgpt
|
||||
image: ghcr.io/labring/fastgpt:v4.14.4 # git
|
||||
image: ghcr.io/labring/fastgpt:v4.14.1 # git
|
||||
ports:
|
||||
- 3000:3000
|
||||
networks:
|
||||
|
|
@ -185,13 +185,13 @@ services:
|
|||
- ./config.json:/app/data/config.json
|
||||
sandbox:
|
||||
container_name: sandbox
|
||||
image: ghcr.io/labring/fastgpt-sandbox:v4.14.4
|
||||
image: ghcr.io/labring/fastgpt-sandbox:v4.14.1
|
||||
networks:
|
||||
- fastgpt
|
||||
restart: always
|
||||
fastgpt-mcp-server:
|
||||
container_name: fastgpt-mcp-server
|
||||
image: ghcr.io/labring/fastgpt-mcp_server:v4.14.4
|
||||
image: ghcr.io/labring/fastgpt-mcp_server:v4.14.1
|
||||
networks:
|
||||
- fastgpt
|
||||
ports:
|
||||
|
|
@ -200,7 +200,7 @@ services:
|
|||
environment:
|
||||
- FASTGPT_ENDPOINT=http://fastgpt:3000
|
||||
fastgpt-plugin:
|
||||
image: ghcr.io/labring/fastgpt-plugin:v0.3.4
|
||||
image: ghcr.io/labring/fastgpt-plugin:v0.3.1
|
||||
container_name: fastgpt-plugin
|
||||
restart: always
|
||||
networks:
|
||||
|
|
|
|||
|
|
@ -118,7 +118,7 @@ services:
|
|||
|
||||
fastgpt:
|
||||
container_name: fastgpt
|
||||
image: ghcr.io/labring/fastgpt:v4.14.4 # git
|
||||
image: ghcr.io/labring/fastgpt:v4.14.1 # git
|
||||
ports:
|
||||
- 3000:3000
|
||||
networks:
|
||||
|
|
@ -168,13 +168,13 @@ services:
|
|||
- ./config.json:/app/data/config.json
|
||||
sandbox:
|
||||
container_name: sandbox
|
||||
image: ghcr.io/labring/fastgpt-sandbox:v4.14.4
|
||||
image: ghcr.io/labring/fastgpt-sandbox:v4.14.1
|
||||
networks:
|
||||
- fastgpt
|
||||
restart: always
|
||||
fastgpt-mcp-server:
|
||||
container_name: fastgpt-mcp-server
|
||||
image: ghcr.io/labring/fastgpt-mcp_server:v4.14.4
|
||||
image: ghcr.io/labring/fastgpt-mcp_server:v4.14.1
|
||||
networks:
|
||||
- fastgpt
|
||||
ports:
|
||||
|
|
@ -183,7 +183,7 @@ services:
|
|||
environment:
|
||||
- FASTGPT_ENDPOINT=http://fastgpt:3000
|
||||
fastgpt-plugin:
|
||||
image: ghcr.io/labring/fastgpt-plugin:v0.3.4
|
||||
image: ghcr.io/labring/fastgpt-plugin:v0.3.1
|
||||
container_name: fastgpt-plugin
|
||||
restart: always
|
||||
networks:
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 92 KiB |
|
Before Width: | Height: | Size: 176 KiB |
|
Before Width: | Height: | Size: 62 KiB |
|
Before Width: | Height: | Size: 55 KiB |
|
Before Width: | Height: | Size: 48 KiB |
|
Before Width: | Height: | Size: 41 KiB |
|
Before Width: | Height: | Size: 74 KiB |
|
Before Width: | Height: | Size: 31 KiB |
|
Before Width: | Height: | Size: 135 KiB |
|
Before Width: | Height: | Size: 33 KiB |
|
After Width: | Height: | Size: 111 KiB |
|
After Width: | Height: | Size: 114 KiB |
|
After Width: | Height: | Size: 162 KiB |
|
After Width: | Height: | Size: 160 KiB |
|
After Width: | Height: | Size: 166 KiB |
|
After Width: | Height: | Size: 144 KiB |
|
After Width: | Height: | Size: 124 KiB |
|
After Width: | Height: | Size: 132 KiB |
|
After Width: | Height: | Size: 89 KiB |
|
After Width: | Height: | Size: 83 KiB |
|
After Width: | Height: | Size: 62 KiB |
|
After Width: | Height: | Size: 192 KiB |
|
After Width: | Height: | Size: 141 KiB |
|
After Width: | Height: | Size: 114 KiB |
|
After Width: | Height: | Size: 97 KiB |
|
After Width: | Height: | Size: 99 KiB |
|
After Width: | Height: | Size: 98 KiB |
|
After Width: | Height: | Size: 90 KiB |
|
After Width: | Height: | Size: 108 KiB |
|
|
@ -11,10 +11,8 @@ export enum TeamErrEnum {
|
|||
datasetAmountNotEnough = 'datasetAmountNotEnough',
|
||||
appAmountNotEnough = 'appAmountNotEnough',
|
||||
pluginAmountNotEnough = 'pluginAmountNotEnough',
|
||||
appFolderAmountNotEnough = 'appFolderAmountNotEnough',
|
||||
websiteSyncNotEnough = 'websiteSyncNotEnough',
|
||||
reRankNotEnough = 'reRankNotEnough',
|
||||
ticketNotAvailable = 'ticketNotAvailable',
|
||||
groupNameEmpty = 'groupNameEmpty',
|
||||
groupNameDuplicate = 'groupNameDuplicate',
|
||||
groupNotExist = 'groupNotExist',
|
||||
|
|
@ -67,10 +65,6 @@ const teamErr = [
|
|||
statusText: TeamErrEnum.pluginAmountNotEnough,
|
||||
message: i18nT('common:code_error.team_error.plugin_amount_not_enough')
|
||||
},
|
||||
{
|
||||
statusText: TeamErrEnum.appFolderAmountNotEnough,
|
||||
message: i18nT('common:code_error.team_error.app_folder_amount_not_enough')
|
||||
},
|
||||
{
|
||||
statusText: TeamErrEnum.websiteSyncNotEnough,
|
||||
message: i18nT('common:code_error.team_error.website_sync_not_enough')
|
||||
|
|
@ -79,10 +73,6 @@ const teamErr = [
|
|||
statusText: TeamErrEnum.reRankNotEnough,
|
||||
message: i18nT('common:code_error.team_error.re_rank_not_enough')
|
||||
},
|
||||
{
|
||||
statusText: TeamErrEnum.ticketNotAvailable,
|
||||
message: i18nT('common:code_error.team_error.ticket_not_available')
|
||||
},
|
||||
{
|
||||
statusText: TeamErrEnum.groupNameEmpty,
|
||||
message: i18nT('common:code_error.team_error.group_name_empty')
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import type { OutLinkChatAuthProps } from '../../support/permission/chat';
|
||||
import type { OutLinkChatAuthProps } from '../../support/permission/chat.d';
|
||||
|
||||
export type preUploadImgProps = OutLinkChatAuthProps & {
|
||||
// expiredTime?: Date;
|
||||
|
|
|
|||
|
|
@ -1,8 +1,20 @@
|
|||
import { i18nT } from '../../../web/i18n/utils';
|
||||
|
||||
/* mongo fs bucket */
|
||||
export enum BucketNameEnum {
|
||||
dataset = 'dataset',
|
||||
chat = 'chat'
|
||||
}
|
||||
export const bucketNameMap = {
|
||||
[BucketNameEnum.dataset]: {
|
||||
label: i18nT('file:bucket_file'),
|
||||
previewExpireMinutes: 30 // 30 minutes
|
||||
},
|
||||
[BucketNameEnum.chat]: {
|
||||
label: i18nT('file:bucket_chat'),
|
||||
previewExpireMinutes: 7 * 24 * 60 // 7 days
|
||||
}
|
||||
};
|
||||
|
||||
export const EndpointUrl = `${process.env.FILE_DOMAIN || process.env.FE_DOMAIN || ''}${process.env.NEXT_PUBLIC_BASE_URL || ''}`;
|
||||
export const ReadFileBaseUrl = `${EndpointUrl}/api/common/file/read`;
|
||||
|
|
|
|||
|
|
@ -4,4 +4,3 @@ export const FolderIcon = 'file/fill/folder';
|
|||
export const FolderImgUrl = '/imgs/files/folder.svg';
|
||||
export const HttpPluginImgUrl = '/imgs/app/httpPluginFill.svg';
|
||||
export const HttpImgUrl = '/imgs/workflow/http.png';
|
||||
export const TempFileURL = '/api/file/temp';
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { detect } from 'jschardet';
|
||||
import { imageFileType } from './constants';
|
||||
import { documentFileType } from './constants';
|
||||
import { ChatFileTypeEnum } from '../../core/chat/constants';
|
||||
import { type UserChatItemFileItemType } from '../../core/chat/type';
|
||||
import * as fs from 'fs';
|
||||
|
|
@ -66,17 +66,18 @@ export const parseUrlToFileType = (url: string): UserChatItemFileItemType | unde
|
|||
})();
|
||||
const extension = filename?.split('.').pop()?.toLowerCase() || '';
|
||||
|
||||
if (extension && imageFileType.includes(extension)) {
|
||||
// Default to file type for non-extension files
|
||||
// If it's a document type, return as file, otherwise treat as image
|
||||
if (extension && documentFileType.includes(extension)) {
|
||||
return {
|
||||
type: ChatFileTypeEnum.image,
|
||||
type: ChatFileTypeEnum.file,
|
||||
name: filename || 'null',
|
||||
url
|
||||
};
|
||||
}
|
||||
// If it's a document type, return as file, otherwise treat as image
|
||||
|
||||
// Default to image type for non-document files
|
||||
return {
|
||||
type: ChatFileTypeEnum.file,
|
||||
type: ChatFileTypeEnum.image,
|
||||
name: filename || 'null',
|
||||
url
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,28 +0,0 @@
|
|||
import path from 'path';
|
||||
|
||||
export const isCSVFile = (filename: string) => {
|
||||
const extension = path.extname(filename).toLowerCase();
|
||||
return extension === '.csv';
|
||||
};
|
||||
|
||||
export function detectImageContentType(buffer: Buffer) {
|
||||
if (!buffer || buffer.length < 12) return 'text/plain';
|
||||
|
||||
// JPEG
|
||||
if (buffer[0] === 0xff && buffer[1] === 0xd8 && buffer[2] === 0xff) return 'image/jpeg';
|
||||
|
||||
// PNG
|
||||
const pngSig = [0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a];
|
||||
if (pngSig.every((v, i) => buffer.readUInt8(i) === v)) return 'image/png';
|
||||
|
||||
// GIF
|
||||
const gifSig = buffer.subarray(0, 6).toString('ascii');
|
||||
if (gifSig === 'GIF87a' || gifSig === 'GIF89a') return 'image/gif';
|
||||
|
||||
// WEBP
|
||||
const riff = buffer.subarray(0, 4).toString('ascii');
|
||||
const webp = buffer.subarray(8, 12).toString('ascii');
|
||||
if (riff === 'RIFF' && webp === 'WEBP') return 'image/webp';
|
||||
|
||||
return 'text/plain';
|
||||
}
|
||||
|
|
@ -16,10 +16,3 @@ export const parseI18nString = (str: I18nStringType | string = '', lang = 'en')
|
|||
// 最后回退到英文
|
||||
return str['en'] || '';
|
||||
};
|
||||
|
||||
export const formatI18nLocationToZhEn = (locale: localeType = 'zh-CN'): 'zh' | 'en' => {
|
||||
if (locale.toLocaleLowerCase().startsWith('zh')) {
|
||||
return 'zh';
|
||||
}
|
||||
return 'en';
|
||||
};
|
||||
|
|
|
|||
|
|
@ -9,15 +9,5 @@ export enum TrackEnum {
|
|||
datasetSearch = 'datasetSearch',
|
||||
readSystemAnnouncement = 'readSystemAnnouncement',
|
||||
clickOperationalAd = 'clickOperationalAd',
|
||||
closeOperationalAd = 'closeOperationalAd',
|
||||
teamChatQPM = 'teamChatQPM',
|
||||
|
||||
// Admin cron job tracks
|
||||
subscriptionDeleted = 'subscriptionDeleted',
|
||||
freeAccountCleanup = 'freeAccountCleanup',
|
||||
auditLogCleanup = 'auditLogCleanup',
|
||||
chatHistoryCleanup = 'chatHistoryCleanup',
|
||||
|
||||
// web tracks
|
||||
clientError = 'clientError'
|
||||
closeOperationalAd = 'closeOperationalAd'
|
||||
}
|
||||
|
|
|
|||
|
|
@ -184,7 +184,7 @@ export const sliceStrStartEnd = (str: string, start: number, end: number) => {
|
|||
return `${startContent}${overSize ? `\n\n...[hide ${str.length - start - end} chars]...\n\n` : ''}${endContent}`;
|
||||
};
|
||||
|
||||
/*
|
||||
/*
|
||||
Parse file extension from url
|
||||
Test:
|
||||
1. https://xxx.com/file.pdf?token=123
|
||||
|
|
@ -201,32 +201,3 @@ export const parseFileExtensionFromUrl = (url = '') => {
|
|||
const extension = fileName.split('.').pop();
|
||||
return (extension || '').toLowerCase();
|
||||
};
|
||||
|
||||
export const formatNumberWithUnit = (num: number, locale: string = 'zh-CN'): string => {
|
||||
if (num === 0) return '0';
|
||||
if (!num || isNaN(num)) return '-';
|
||||
const absNum = Math.abs(num);
|
||||
const isNegative = num < 0;
|
||||
const prefix = isNegative ? '-' : '';
|
||||
|
||||
if (locale === 'zh-CN') {
|
||||
if (absNum >= 10000) {
|
||||
const value = absNum / 10000;
|
||||
const formatted = Number(value.toFixed(2)).toString();
|
||||
return `${prefix}${formatted}万`;
|
||||
}
|
||||
return num.toLocaleString(locale);
|
||||
} else {
|
||||
if (absNum >= 1000000) {
|
||||
const value = absNum / 1000000;
|
||||
const formatted = Number(value.toFixed(2)).toString();
|
||||
return `${prefix}${formatted}M`;
|
||||
}
|
||||
if (absNum >= 1000) {
|
||||
const value = absNum / 1000;
|
||||
const formatted = Number(value.toFixed(2)).toString();
|
||||
return `${prefix}${formatted}K`;
|
||||
}
|
||||
return num.toLocaleString(locale);
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -3,8 +3,7 @@ export enum SystemConfigsTypeEnum {
|
|||
fastgptPro = 'fastgptPro',
|
||||
systemMsgModal = 'systemMsgModal',
|
||||
license = 'license',
|
||||
operationalAd = 'operationalAd',
|
||||
activityAd = 'activityAd'
|
||||
operationalAd = 'operationalAd'
|
||||
}
|
||||
|
||||
export const SystemConfigsTypeMap = {
|
||||
|
|
@ -22,8 +21,5 @@ export const SystemConfigsTypeMap = {
|
|||
},
|
||||
[SystemConfigsTypeEnum.operationalAd]: {
|
||||
label: 'operationalAd'
|
||||
},
|
||||
[SystemConfigsTypeEnum.activityAd]: {
|
||||
label: 'activityAd'
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -65,7 +65,6 @@ export type FastGPTFeConfigsType = {
|
|||
show_compliance_copywriting?: boolean;
|
||||
show_aiproxy?: boolean;
|
||||
show_coupon?: boolean;
|
||||
show_discount_coupon?: boolean;
|
||||
concatMd?: string;
|
||||
|
||||
show_dataset_feishu?: boolean;
|
||||
|
|
@ -128,18 +127,6 @@ export type FastGPTFeConfigsType = {
|
|||
alipay?: boolean;
|
||||
bank?: boolean;
|
||||
};
|
||||
payFormUrl?: string;
|
||||
fileUrlWhitelist?: string[];
|
||||
customDomain?: {
|
||||
enable?: boolean;
|
||||
domain?: {
|
||||
aliyun?: string;
|
||||
tencent?: string;
|
||||
volcengine?: string;
|
||||
};
|
||||
};
|
||||
|
||||
ip_whitelist?: string;
|
||||
};
|
||||
|
||||
export type SystemEnvType = {
|
||||
|
|
@ -158,39 +145,12 @@ export type SystemEnvType = {
|
|||
chatApiKey?: string;
|
||||
|
||||
customPdfParse?: customPdfParseType;
|
||||
fileUrlWhitelist?: string[];
|
||||
customDomain?: customDomainType;
|
||||
};
|
||||
|
||||
export type customDomainType = {
|
||||
kc?: {
|
||||
aliyun?: string;
|
||||
tencent?: string;
|
||||
volcengine?: string;
|
||||
};
|
||||
domain?: {
|
||||
aliyun?: string;
|
||||
tencent?: string;
|
||||
volcengine?: string;
|
||||
};
|
||||
issuerServiceName?: {
|
||||
aliyun?: string;
|
||||
tencent?: string;
|
||||
volcengine?: string;
|
||||
};
|
||||
nginxServiceName?: {
|
||||
aliyun?: string;
|
||||
tencent?: string;
|
||||
volcengine?: string;
|
||||
};
|
||||
};
|
||||
|
||||
export type customPdfParseType = {
|
||||
url?: string;
|
||||
key?: string;
|
||||
doc2xKey?: string;
|
||||
textinAppId?: string;
|
||||
textinSecretCode?: string;
|
||||
price?: number;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,29 @@
|
|||
import type { AppLogTimespanEnum } from './constants';
|
||||
import type { AppChatLogAppData, AppChatLogChatData, AppChatLogUserData } from './type';
|
||||
|
||||
export type getChartDataBody = {
|
||||
appId: string;
|
||||
dateStart: Date;
|
||||
dateEnd: Date;
|
||||
source?: ChatSourceEnum[];
|
||||
offset: number;
|
||||
userTimespan: AppLogTimespanEnum;
|
||||
chatTimespan: AppLogTimespanEnum;
|
||||
appTimespan: AppLogTimespanEnum;
|
||||
};
|
||||
|
||||
export type getChartDataResponse = {
|
||||
userData: AppChatLogUserData;
|
||||
chatData: AppChatLogChatData;
|
||||
appData: AppChatLogAppData;
|
||||
};
|
||||
|
||||
export type getTotalDataQuery = {
|
||||
appId: string;
|
||||
};
|
||||
|
||||
export type getTotalDataResponse = {
|
||||
totalUsers: number;
|
||||
totalChats: number;
|
||||
totalPoints: number;
|
||||
};
|
||||
|
|
@ -13,9 +13,7 @@ export enum AppLogKeysEnum {
|
|||
ANNOTATED_COUNT = 'annotatedCount',
|
||||
POINTS = 'points',
|
||||
RESPONSE_TIME = 'responseTime',
|
||||
ERROR_COUNT = 'errorCount',
|
||||
REGION = 'region',
|
||||
VERSION_NAME = 'versionName'
|
||||
ERROR_COUNT = 'errorCount'
|
||||
}
|
||||
|
||||
export const AppLogKeysEnumMap = {
|
||||
|
|
@ -31,13 +29,11 @@ export const AppLogKeysEnumMap = {
|
|||
[AppLogKeysEnum.ANNOTATED_COUNT]: i18nT('app:logs_keys_annotatedCount'),
|
||||
[AppLogKeysEnum.POINTS]: i18nT('app:logs_keys_points'),
|
||||
[AppLogKeysEnum.RESPONSE_TIME]: i18nT('app:logs_keys_responseTime'),
|
||||
[AppLogKeysEnum.ERROR_COUNT]: i18nT('app:logs_keys_errorCount'),
|
||||
[AppLogKeysEnum.REGION]: i18nT('app:logs_keys_region'),
|
||||
[AppLogKeysEnum.VERSION_NAME]: i18nT('app:logs_keys_versionName')
|
||||
[AppLogKeysEnum.ERROR_COUNT]: i18nT('app:logs_keys_errorCount')
|
||||
};
|
||||
|
||||
export const DefaultAppLogKeys = [
|
||||
{ key: AppLogKeysEnum.SOURCE, enable: false },
|
||||
{ key: AppLogKeysEnum.SOURCE, enable: true },
|
||||
{ key: AppLogKeysEnum.USER, enable: true },
|
||||
{ key: AppLogKeysEnum.TITLE, enable: true },
|
||||
{ key: AppLogKeysEnum.SESSION_ID, enable: false },
|
||||
|
|
@ -49,9 +45,7 @@ export const DefaultAppLogKeys = [
|
|||
{ key: AppLogKeysEnum.ANNOTATED_COUNT, enable: false },
|
||||
{ key: AppLogKeysEnum.POINTS, enable: false },
|
||||
{ key: AppLogKeysEnum.RESPONSE_TIME, enable: false },
|
||||
{ key: AppLogKeysEnum.ERROR_COUNT, enable: false },
|
||||
{ key: AppLogKeysEnum.REGION, enable: true },
|
||||
{ key: AppLogKeysEnum.VERSION_NAME, enable: false }
|
||||
{ key: AppLogKeysEnum.ERROR_COUNT, enable: false }
|
||||
];
|
||||
|
||||
export enum AppLogTimespanEnum {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,65 @@
|
|||
import type { ChatSourceEnum } from '../../core/chat/constants';
|
||||
import type { AppLogKeysEnum } from './constants';
|
||||
|
||||
export type AppLogKeysType = {
|
||||
key: AppLogKeysEnum;
|
||||
enable: boolean;
|
||||
};
|
||||
|
||||
export type AppLogKeysSchemaType = {
|
||||
teamId: string;
|
||||
appId: string;
|
||||
logKeys: AppLogKeysType[];
|
||||
};
|
||||
|
||||
export type AppChatLogSchema = {
|
||||
_id: string;
|
||||
appId: string;
|
||||
teamId: string;
|
||||
chatId: string;
|
||||
userId: string;
|
||||
source: string;
|
||||
sourceName?: string;
|
||||
createTime: Date;
|
||||
updateTime: Date;
|
||||
|
||||
chatItemCount: number;
|
||||
errorCount: number;
|
||||
totalPoints: number;
|
||||
goodFeedbackCount: number;
|
||||
badFeedbackCount: number;
|
||||
totalResponseTime: number;
|
||||
|
||||
isFirstChat: boolean; // whether this is the user's first session in the app
|
||||
};
|
||||
|
||||
export type AppChatLogUserData = {
|
||||
timestamp: number;
|
||||
summary: {
|
||||
userCount: number;
|
||||
newUserCount: number;
|
||||
retentionUserCount: number;
|
||||
points: number;
|
||||
sourceCountMap: Record<ChatSourceEnum, number>;
|
||||
};
|
||||
}[];
|
||||
|
||||
export type AppChatLogChatData = {
|
||||
timestamp: number;
|
||||
summary: {
|
||||
chatItemCount: number;
|
||||
chatCount: number;
|
||||
errorCount: number;
|
||||
points: number;
|
||||
};
|
||||
}[];
|
||||
|
||||
export type AppChatLogAppData = {
|
||||
timestamp: number;
|
||||
summary: {
|
||||
goodFeedBackCount: number;
|
||||
badFeedBackCount: number;
|
||||
chatCount: number;
|
||||
totalResponseTime: number;
|
||||
};
|
||||
}[];
|
||||
|
|
@ -1,39 +0,0 @@
|
|||
import { ObjectIdSchema } from '../../../common/type/mongo';
|
||||
import { ChatSourceEnum } from '../../chat/constants';
|
||||
import { AppLogKeysEnum } from './constants';
|
||||
import { z } from 'zod';
|
||||
|
||||
export const AppLogKeysSchema = z.object({
|
||||
key: z.enum(AppLogKeysEnum),
|
||||
enable: z.boolean()
|
||||
});
|
||||
export type AppLogKeysType = z.infer<typeof AppLogKeysSchema>;
|
||||
|
||||
export const AppLogKeysSchemaType = z.object({
|
||||
teamId: z.string(),
|
||||
appId: z.string(),
|
||||
logKeys: z.array(AppLogKeysSchema)
|
||||
});
|
||||
export type AppLogKeysSchemaType = z.infer<typeof AppLogKeysSchemaType>;
|
||||
|
||||
export const AppChatLogSchema = z.object({
|
||||
_id: ObjectIdSchema,
|
||||
appId: ObjectIdSchema,
|
||||
teamId: ObjectIdSchema,
|
||||
chatId: z.string(),
|
||||
userId: z.string(),
|
||||
source: z.enum(ChatSourceEnum),
|
||||
sourceName: z.string().optional(),
|
||||
createTime: z.date(),
|
||||
updateTime: z.date(),
|
||||
|
||||
chatItemCount: z.number(),
|
||||
errorCount: z.number(),
|
||||
totalPoints: z.number(),
|
||||
goodFeedbackCount: z.number(),
|
||||
badFeedbackCount: z.number(),
|
||||
totalResponseTime: z.number(),
|
||||
|
||||
isFirstChat: z.boolean() // whether this is the user's first session in the app
|
||||
});
|
||||
export type AppChatLogSchema = z.infer<typeof AppChatLogSchema>;
|
||||
|
|
@ -59,9 +59,6 @@ export type AppSchema = {
|
|||
inited?: boolean;
|
||||
/** @deprecated */
|
||||
teamTags: string[];
|
||||
|
||||
// 软删除字段
|
||||
deleteTime?: Date | null;
|
||||
};
|
||||
|
||||
export type AppListItemType = {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,68 @@
|
|||
import type { OutLinkChatAuthType } from '../../support/permission/chat/type';
|
||||
import { OutLinkChatAuthSchema } from '../../support/permission/chat/type';
|
||||
import { ObjectIdSchema } from '../../common/type/mongo';
|
||||
import z from 'zod';
|
||||
|
||||
export const PresignChatFileGetUrlSchema = z
|
||||
.object({
|
||||
key: z.string().min(1),
|
||||
appId: ObjectIdSchema,
|
||||
outLinkAuthData: OutLinkChatAuthSchema.optional()
|
||||
})
|
||||
.meta({
|
||||
description: '获取对话文件预览链接',
|
||||
example: {
|
||||
key: '1234567890',
|
||||
appId: '1234567890',
|
||||
outLinkAuthData: {
|
||||
shareId: '1234567890',
|
||||
outLinkUid: '1234567890'
|
||||
}
|
||||
}
|
||||
});
|
||||
export type PresignChatFileGetUrlParams = z.infer<typeof PresignChatFileGetUrlSchema> & {
|
||||
outLinkAuthData?: OutLinkChatAuthType;
|
||||
};
|
||||
|
||||
export const PresignChatFilePostUrlSchema = z
|
||||
.object({
|
||||
filename: z.string().min(1),
|
||||
appId: ObjectIdSchema,
|
||||
chatId: ObjectIdSchema,
|
||||
outLinkAuthData: OutLinkChatAuthSchema.optional()
|
||||
})
|
||||
.meta({
|
||||
description: '获取上传对话文件预签名 URL',
|
||||
example: {
|
||||
filename: '1234567890',
|
||||
appId: '1234567890',
|
||||
chatId: '1234567890',
|
||||
outLinkAuthData: {
|
||||
shareId: '1234567890',
|
||||
outLinkUid: '1234567890'
|
||||
}
|
||||
}
|
||||
});
|
||||
export type PresignChatFilePostUrlParams = z.infer<typeof PresignChatFilePostUrlSchema> & {
|
||||
outLinkAuthData?: OutLinkChatAuthType;
|
||||
};
|
||||
|
||||
export const UpdateChatFeedbackSchema = z
|
||||
.object({
|
||||
appId: z.string().min(1),
|
||||
chatId: z.string().min(1),
|
||||
dataId: z.string().min(1),
|
||||
userBadFeedback: z.string().optional(),
|
||||
userGoodFeedback: z.string().optional()
|
||||
})
|
||||
.meta({
|
||||
description: '更新对话反馈',
|
||||
example: {
|
||||
appId: '1234567890',
|
||||
chatId: '1234567890',
|
||||
dataId: '1234567890',
|
||||
userBadFeedback: '1234567890',
|
||||
userGoodFeedback: '1234567890'
|
||||
}
|
||||
});
|
||||
export type UpdateChatFeedbackProps = z.infer<typeof UpdateChatFeedbackSchema>;
|
||||
|
|
@ -28,7 +28,6 @@ export type ChatSchemaType = {
|
|||
teamId: string;
|
||||
tmbId: string;
|
||||
appId: string;
|
||||
appVersionId?: string;
|
||||
createTime: Date;
|
||||
updateTime: Date;
|
||||
title: string;
|
||||
|
|
@ -45,14 +44,6 @@ export type ChatSchemaType = {
|
|||
variables: Record<string, any>;
|
||||
pluginInputs?: FlowNodeInputItemType[];
|
||||
metadata?: Record<string, any>;
|
||||
|
||||
// Boolean flags for efficient filtering
|
||||
hasGoodFeedback?: boolean;
|
||||
hasBadFeedback?: boolean;
|
||||
hasUnreadGoodFeedback?: boolean;
|
||||
hasUnreadBadFeedback?: boolean;
|
||||
|
||||
deleteTime?: Date | null;
|
||||
};
|
||||
|
||||
export type ChatWithAppSchema = Omit<ChatSchemaType, 'appId'> & {
|
||||
|
|
@ -114,7 +105,6 @@ export type AIChatItemType = {
|
|||
userBadFeedback?: string;
|
||||
customFeedbacks?: string[];
|
||||
adminFeedback?: AdminFbkType;
|
||||
isFeedbackRead?: boolean;
|
||||
|
||||
durationSeconds?: number;
|
||||
errorMsg?: string;
|
||||
|
|
@ -162,7 +152,6 @@ export type ChatItemType = ChatItemMergeType & {
|
|||
// Frontend type
|
||||
export type ChatSiteItemType = ChatItemMergeType & {
|
||||
_id?: string;
|
||||
id: string;
|
||||
dataId: string;
|
||||
status: `${ChatStatusEnum}`;
|
||||
moduleName?: string;
|
||||
|
|
@ -199,7 +188,7 @@ export type HistoryItemType = {
|
|||
};
|
||||
export type ChatHistoryItemType = HistoryItemType & {
|
||||
appId: string;
|
||||
top?: boolean;
|
||||
top: boolean;
|
||||
};
|
||||
|
||||
/* ------- response data ------------ */
|
||||
|
|
|
|||
|
|
@ -59,6 +59,7 @@ export const getHistoryPreview = (
|
|||
return `}...)`;
|
||||
return '';
|
||||
})
|
||||
.filter(Boolean)
|
||||
.join('\n') || ''
|
||||
);
|
||||
} else if (item.obj === ChatRoleEnum.AI) {
|
||||
|
|
@ -69,8 +70,7 @@ export const getHistoryPreview = (
|
|||
item.text?.content || item?.tools?.map((item) => item.toolName).join(',') || ''
|
||||
);
|
||||
})
|
||||
.join('')
|
||||
.trim() || ''
|
||||
.join('') || ''
|
||||
);
|
||||
}
|
||||
return '';
|
||||
|
|
|
|||