diff --git a/CHANGELOG.md b/CHANGELOG.md
index 97aa264e31e28..75014afba8ea8 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,74 @@
# Changelog
+### [Version 1.46.7](https://github.com/lobehub/lobe-chat/compare/v1.46.6...v1.46.7)
+
+Released on **2025-01-17**
+
+#### 🐛 Bug Fixes
+
+- **misc**: Improve validation for provider and model in parseFilesConfig, temporarily disable S3 client integrity check for Cloudflare R2.
+
+
+
+
+Improvements and Fixes
+
+#### What's fixed
+
+- **misc**: Improve validation for provider and model in parseFilesConfig, closes [#5454](https://github.com/lobehub/lobe-chat/issues/5454) ([b4808f8](https://github.com/lobehub/lobe-chat/commit/b4808f8))
+- **misc**: Temporarily disable S3 client integrity check for Cloudflare R2, closes [#5479](https://github.com/lobehub/lobe-chat/issues/5479) ([a638238](https://github.com/lobehub/lobe-chat/commit/a638238))
+
+
+
+
+
+[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)
+
+
+
+### [Version 1.46.6](https://github.com/lobehub/lobe-chat/compare/v1.46.5...v1.46.6)
+
+Released on **2025-01-16**
+
+#### 🐛 Bug Fixes
+
+- **misc**: Gemini models HarmBlockThreshold.
+
+
+
+
+Improvements and Fixes
+
+#### What's fixed
+
+- **misc**: Gemini models HarmBlockThreshold, closes [#5477](https://github.com/lobehub/lobe-chat/issues/5477) ([f98375c](https://github.com/lobehub/lobe-chat/commit/f98375c))
+
+
+
+
+
+[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)
+
+
+
+### [Version 1.46.5](https://github.com/lobehub/lobe-chat/compare/v1.46.4...v1.46.5)
+
+Released on **2025-01-16**
+
+
+
+
+Improvements and Fixes
+
+
+
+
+
+[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)
+
+
+
### [Version 1.46.4](https://github.com/lobehub/lobe-chat/compare/v1.46.3...v1.46.4)
Released on **2025-01-16**
diff --git a/changelog/v1.json b/changelog/v1.json
index 4cf588ab80406..f80d570b54d2f 100644
--- a/changelog/v1.json
+++ b/changelog/v1.json
@@ -1,4 +1,25 @@
[
+ {
+ "children": {
+ "fixes": [
+ "Improve validation for provider and model in parseFilesConfig, temporarily disable S3 client integrity check for Cloudflare R2."
+ ]
+ },
+ "date": "2025-01-17",
+ "version": "1.46.7"
+ },
+ {
+ "children": {
+ "fixes": ["Gemini models HarmBlockThreshold."]
+ },
+ "date": "2025-01-16",
+ "version": "1.46.6"
+ },
+ {
+ "children": {},
+ "date": "2025-01-16",
+ "version": "1.46.5"
+ },
{
"children": {
"improvements": ["Refactor some implement for the next performance improvement."]
diff --git a/netlify.toml b/netlify.toml
index 411a59cac5441..0546e7e2c2ee5 100644
--- a/netlify.toml
+++ b/netlify.toml
@@ -1,5 +1,5 @@
[build]
-command = "pnpm run build"
+command = "rm -rf .next node_modules/.cache && pnpm run build"
publish = ".next"
[build.environment]
diff --git a/package.json b/package.json
index 57cb45d2b9262..c5148745550a4 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@lobehub/chat",
- "version": "1.46.4",
+ "version": "1.46.7",
"description": "Lobe Chat - an open-source, high-performance chatbot framework that supports speech synthesis, multimodal, and extensible Function Call plugin system. Supports one-click free deployment of your private ChatGPT/LLM web application.",
"keywords": [
"framework",
diff --git a/src/const/settings/knowledge.ts b/src/const/settings/knowledge.ts
index 7593358525ced..de74f4929b707 100644
--- a/src/const/settings/knowledge.ts
+++ b/src/const/settings/knowledge.ts
@@ -20,6 +20,6 @@ export const DEFAULT_FILE_RERANK_MODEL_ITEM: FilesConfigItem = {
export const DEFAULT_FILES_CONFIG: FilesConfig = {
embeddingModel: DEFAULT_FILE_EMBEDDING_MODEL_ITEM,
- queryModel: DEFAULT_RERANK_QUERY_MODE,
+ queryMode: DEFAULT_RERANK_QUERY_MODE,
rerankerModel: DEFAULT_FILE_RERANK_MODEL_ITEM,
};
diff --git a/src/libs/agent-runtime/google/index.ts b/src/libs/agent-runtime/google/index.ts
index 55a8f99474df2..3354a3a8bf35d 100644
--- a/src/libs/agent-runtime/google/index.ts
+++ b/src/libs/agent-runtime/google/index.ts
@@ -36,7 +36,14 @@ enum HarmCategory {
enum HarmBlockThreshold {
BLOCK_NONE = 'BLOCK_NONE',
- OFF = 'OFF', // https://discuss.ai.google.dev/t/59352
+}
+
+function getThreshold(model: string): HarmBlockThreshold {
+ const useOFF = ['gemini-2.0-flash-exp'];
+ if (useOFF.includes(model)) {
+ return 'OFF' as HarmBlockThreshold; // https://discuss.ai.google.dev/t/59352
+ }
+ return HarmBlockThreshold.BLOCK_NONE;
}
export class LobeGoogleAI implements LobeRuntimeAI {
@@ -71,19 +78,19 @@ export class LobeGoogleAI implements LobeRuntimeAI {
safetySettings: [
{
category: HarmCategory.HARM_CATEGORY_HATE_SPEECH,
- threshold: model.includes('2.0') ? (HarmBlockThreshold.OFF as any) : HarmBlockThreshold.BLOCK_NONE,
+ threshold: getThreshold(model),
},
{
category: HarmCategory.HARM_CATEGORY_SEXUALLY_EXPLICIT,
- threshold: model.includes('2.0') ? (HarmBlockThreshold.OFF as any) : HarmBlockThreshold.BLOCK_NONE,
+ threshold: getThreshold(model),
},
{
category: HarmCategory.HARM_CATEGORY_HARASSMENT,
- threshold: model.includes('2.0') ? (HarmBlockThreshold.OFF as any) : HarmBlockThreshold.BLOCK_NONE,
+ threshold: getThreshold(model),
},
{
category: HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT,
- threshold: model.includes('2.0') ? (HarmBlockThreshold.OFF as any) : HarmBlockThreshold.BLOCK_NONE,
+ threshold: getThreshold(model),
},
],
},
diff --git a/src/server/globalConfig/parseFilesConfig.test.ts b/src/server/globalConfig/parseFilesConfig.test.ts
index c001ead1748ca..798d70163d1b0 100644
--- a/src/server/globalConfig/parseFilesConfig.test.ts
+++ b/src/server/globalConfig/parseFilesConfig.test.ts
@@ -3,15 +3,134 @@ import { describe, expect, it } from 'vitest';
import { parseFilesConfig } from './parseFilesConfig';
describe('parseFilesConfig', () => {
+ it('parses full configuration correctly', () => {
+ const envStr =
+ 'embedding_model=openai/embedding-text-3-small,reranker_model=cohere/rerank-english-v3.0,query_mode=full_text';
+ const expected = {
+ embeddingModel: { provider: 'openai', model: 'embedding-text-3-small' },
+ rerankerModel: { provider: 'cohere', model: 'rerank-english-v3.0' },
+ queryMode: 'full_text',
+ };
+ expect(parseFilesConfig(envStr)).toEqual(expected);
+ });
+
// 测试embeddings配置是否被正确解析
it('parses embeddings configuration correctly', () => {
- const envStr =
- 'embedding_model=openai/embedding-text-3-large,reranker_model=cohere/rerank-english-v3.0,query_model=full_text';
+ const envStr = 'embedding_model=openai/embedding-text-3-large';
const expected = {
embeddingModel: { provider: 'openai', model: 'embedding-text-3-large' },
+ };
+ expect(parseFilesConfig(envStr)).toEqual(expected);
+ });
+
+ it('parses rerank configuration correctly', () => {
+ const envStr = 'reranker_model=cohere/rerank-english-v3.0';
+ const expected = {
+ rerankerModel: { provider: 'cohere', model: 'rerank-english-v3.0' },
+ };
+ expect(parseFilesConfig(envStr)).toEqual(expected);
+ });
+
+ it('parses queryMode configuration correctly', () => {
+ const envStr = 'query_mode=full_text';
+ const expected = {
+ queryMode: 'full_text',
+ };
+ expect(parseFilesConfig(envStr)).toEqual(expected);
+ });
+
+ it('parses queryMode rerank configuration correctly', () => {
+ const envStr = 'reranker_model=cohere/rerank-english-v3.0,query_mode=full_text';
+ const expected = {
+ queryMode: 'full_text',
+ rerankerModel: { provider: 'cohere', model: 'rerank-english-v3.0' },
+ };
+ expect(parseFilesConfig(envStr)).toEqual(expected);
+ });
+
+ it('parses queryMode embeddings configuration correctly', () => {
+ const envStr = 'embedding_model=openai/embedding-text-3-small,query_mode=full_text';
+ const expected = {
+ queryMode: 'full_text',
+ embeddingModel: { provider: 'openai', model: 'embedding-text-3-small' },
+ };
+ expect(parseFilesConfig(envStr)).toEqual(expected);
+ });
+
+ it('parses rerank embeddings configuration correctly', () => {
+ const envStr =
+ 'reranker_model=cohere/rerank-english-v3.0,embedding_model=openai/embedding-text-3-small';
+ const expected = {
+ embeddingModel: { provider: 'openai', model: 'embedding-text-3-small' },
rerankerModel: { provider: 'cohere', model: 'rerank-english-v3.0' },
- queryModel: 'full_text',
};
expect(parseFilesConfig(envStr)).toEqual(expected);
});
+
+ it('should throw an error for invalid embedding_model format', () => {
+ const envStr =
+ 'reranker_model=cohere/rerank-english-v3.0,embedding_model=/embedding-text-3-small';
+ expect(() => {
+ parseFilesConfig(envStr);
+ }).toThrow(
+ new Error(
+ 'Invalid environment variable format. expected of the form embedding_model=provider/model',
+ ),
+ );
+ });
+
+ it('should throw an error for invalid embedding_model format', () => {
+ const envStr = 'reranker_model=cohere/rerank-english-v3.0,embedding_model=openai';
+ expect(() => {
+ parseFilesConfig(envStr);
+ }).toThrow(
+ new Error(
+ 'Invalid environment variable format. expected of the form embedding_model=provider/model',
+ ),
+ );
+ });
+
+ it('should throw an error for invalid embedding_model format', () => {
+ const envStr = 'reranker_model=cohere/rerank-english-v3.0,embedding_model=';
+ expect(() => {
+ parseFilesConfig(envStr);
+ }).toThrowError(new Error('Invalid environment variable format.'));
+ });
+
+ it('should throw an error for invalid reranker_model format', () => {
+ const envStr =
+ 'reranker_model=/rerank-english-v3.0,embedding_model=openai/embedding-text-3-small';
+ expect(() => {
+ parseFilesConfig(envStr);
+ }).toThrow(
+ new Error(
+ 'Invalid environment variable format. expected of the form reranker_model=provider/model',
+ ),
+ );
+ });
+
+ it('should throw an error for invalid reranker_model format', () => {
+ const envStr = 'reranker_model=cohere/,embedding_model=openai/embedding-text-3-small';
+ expect(() => {
+ parseFilesConfig(envStr);
+ }).toThrow(
+ new Error(
+ 'Invalid environment variable format. expected of the form reranker_model=provider/model',
+ ),
+ );
+ });
+
+ it('should throw an error for invalid reranker_model format', () => {
+ const envStr = 'reranker_model=,embedding_model=openai/embedding-text-3-small';
+ expect(() => {
+ parseFilesConfig(envStr);
+ }).toThrow(new Error('Invalid environment variable format.'));
+ });
+
+ it('should throw an error for invalid query_mode format', () => {
+ const envStr = 'query_mode=';
+ expect(() => {
+ parseFilesConfig(envStr);
+ }).toThrow(new Error('Invalid environment variable format.'));
+ });
});
diff --git a/src/server/globalConfig/parseFilesConfig.ts b/src/server/globalConfig/parseFilesConfig.ts
index 7175b3206448f..bea497b772bb9 100644
--- a/src/server/globalConfig/parseFilesConfig.ts
+++ b/src/server/globalConfig/parseFilesConfig.ts
@@ -4,7 +4,7 @@ import { FilesConfig } from '@/types/user/settings/filesConfig';
const protectedKeys = Object.keys({
embedding_model: null,
- query_model: null,
+ query_mode: null,
reranker_model: null,
});
@@ -24,34 +24,40 @@ export const parseFilesConfig = (envString: string = ''): SystemEmbeddingConfig
const [provider, ...modelParts] = value.split('/');
const model = modelParts.join('/');
- if ((!provider || !model) && key !== 'query_model') {
- throw new Error('Missing model or provider value');
- }
-
- if (key === 'query_model' && value === '') {
- throw new Error('Missing query mode value');
- }
-
if (protectedKeys.includes(key)) {
switch (key) {
case 'embedding_model': {
+ if (!provider || !model) {
+ throw new Error(
+ 'Invalid environment variable format. expected of the form embedding_model=provider/model',
+ );
+ }
config.embeddingModel = { model: model.trim(), provider: provider.trim() };
break;
}
case 'reranker_model': {
+ if (!provider || !model) {
+ throw new Error(
+ 'Invalid environment variable format. expected of the form reranker_model=provider/model',
+ );
+ }
config.rerankerModel = { model: model.trim(), provider: provider.trim() };
break;
}
- case 'query_model': {
- config.queryModel = value;
+ case 'query_mode': {
+ config.queryMode = value;
break;
}
+ default: {
+ throw new Error(
+ 'Invalid environment variable format. expected one of embedding_model, reranker_model, query_mode',
+ );
+ }
}
}
} else {
- throw new Error('Invalid environment variable format');
+ throw new Error('Invalid environment variable format.');
}
}
-
return config;
};
diff --git a/src/server/modules/S3/index.ts b/src/server/modules/S3/index.ts
index 10bc512472ca8..07f09cd95a512 100644
--- a/src/server/modules/S3/index.ts
+++ b/src/server/modules/S3/index.ts
@@ -44,6 +44,9 @@ export class S3 {
endpoint: fileEnv.S3_ENDPOINT,
forcePathStyle: fileEnv.S3_ENABLE_PATH_STYLE,
region: fileEnv.S3_REGION || DEFAULT_S3_REGION,
+ // refs: https://github.com/lobehub/lobe-chat/pull/5479
+ requestChecksumCalculation: 'WHEN_REQUIRED',
+ responseChecksumValidation: 'WHEN_REQUIRED',
});
}
diff --git a/src/types/knowledgeBase/index.ts b/src/types/knowledgeBase/index.ts
index 20355071c9ff2..d87319f1222e5 100644
--- a/src/types/knowledgeBase/index.ts
+++ b/src/types/knowledgeBase/index.ts
@@ -48,6 +48,6 @@ export interface KnowledgeItem {
export interface SystemEmbeddingConfig {
embeddingModel: FilesConfigItem;
- queryModel: string;
+ queryMode: string;
rerankerModel: FilesConfigItem;
}
diff --git a/src/types/user/settings/filesConfig.ts b/src/types/user/settings/filesConfig.ts
index ecfb3b6e3290e..77c35c8dbd578 100644
--- a/src/types/user/settings/filesConfig.ts
+++ b/src/types/user/settings/filesConfig.ts
@@ -4,6 +4,6 @@ export interface FilesConfigItem {
}
export interface FilesConfig {
embeddingModel: FilesConfigItem;
- queryModel: string;
+ queryMode: string;
rerankerModel: FilesConfigItem;
}
diff --git a/vercel.json b/vercel.json
index 78c7b37970236..3c364a1878bb4 100644
--- a/vercel.json
+++ b/vercel.json
@@ -1,3 +1,4 @@
{
+ "buildCommand": "NODE_OPTIONS=--max-old-space-size=6144 next build",
"installCommand": "bun install"
}