@lobehub/chat 1.26.6 → 1.26.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,56 @@
2
2
 
3
3
  # Changelog
4
4
 
5
+ ### [Version 1.26.8](https://github.com/lobehub/lobe-chat/compare/v1.26.7...v1.26.8)
6
+
7
+ <sup>Released on **2024-10-29**</sup>
8
+
9
+ #### 🐛 Bug Fixes
10
+
11
+ - **misc**: Update zhipu param process.
12
+
13
+ <br/>
14
+
15
+ <details>
16
+ <summary><kbd>Improvements and Fixes</kbd></summary>
17
+
18
+ #### What's fixed
19
+
20
+ - **misc**: Update zhipu param process, closes [#4523](https://github.com/lobehub/lobe-chat/issues/4523) ([3317fbd](https://github.com/lobehub/lobe-chat/commit/3317fbd))
21
+
22
+ </details>
23
+
24
+ <div align="right">
25
+
26
+ [![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)
27
+
28
+ </div>
29
+
30
+ ### [Version 1.26.7](https://github.com/lobehub/lobe-chat/compare/v1.26.6...v1.26.7)
31
+
32
+ <sup>Released on **2024-10-29**</sup>
33
+
34
+ #### 🐛 Bug Fixes
35
+
36
+ - **misc**: Remove PWA Install in Firefox and Arc.
37
+
38
+ <br/>
39
+
40
+ <details>
41
+ <summary><kbd>Improvements and Fixes</kbd></summary>
42
+
43
+ #### What's fixed
44
+
45
+ - **misc**: Remove PWA Install in Firefox and Arc, closes [#4532](https://github.com/lobehub/lobe-chat/issues/4532) ([4a380c5](https://github.com/lobehub/lobe-chat/commit/4a380c5))
46
+
47
+ </details>
48
+
49
+ <div align="right">
50
+
51
+ [![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)
52
+
53
+ </div>
54
+
5
55
  ### [Version 1.26.6](https://github.com/lobehub/lobe-chat/compare/v1.26.5...v1.26.6)
6
56
 
7
57
  <sup>Released on **2024-10-29**</sup>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lobehub/chat",
3
- "version": "1.26.6",
3
+ "version": "1.26.8",
4
4
  "description": "Lobe Chat - an open-source, high-performance chatbot framework that supports speech synthesis, multimodal, and extensible Function Call plugin system. Supports one-click free deployment of your private ChatGPT/LLM web application.",
5
5
  "keywords": [
6
6
  "framework",
@@ -47,8 +47,6 @@ const manifest = async (): Promise<MetadataRoute.Manifest | any> => {
47
47
  },
48
48
  {
49
49
  form_factor: 'narrow',
50
- sizes: '640x1138',
51
-
52
50
  url: '/screenshots/shot-3.mobile.png',
53
51
  },
54
52
  {
@@ -11,10 +11,10 @@ const Install: any = dynamic(() => import('./Install'), {
11
11
  });
12
12
 
13
13
  const PWAInstall = memo(() => {
14
- const { isPWA } = usePlatform();
14
+ const { isPWA, isSupportInstallPWA } = usePlatform();
15
15
  const isShowPWAGuide = useUserStore((s) => s.isShowPWAGuide);
16
16
 
17
- if (isPWA || !isShowPWAGuide) return null;
17
+ if (isPWA || !isShowPWAGuide || !isSupportInstallPWA) return null;
18
18
 
19
19
  // only when the user is suitable for the pwa install and not install the pwa
20
20
  // then show the installation guide
@@ -38,6 +38,7 @@ describe('usePWAInstall', () => {
38
38
  });
39
39
 
40
40
  it('should return canInstall based on canInstall state when support PWA', () => {
41
+ document.body.innerHTML = `<div id="${PWA_INSTALL_ID}"></div>`;
41
42
  vi.mocked(usePlatform).mockReturnValue({ isSupportInstallPWA: true, isPWA: false } as any);
42
43
 
43
44
  const { result, rerender } = renderHook(() => usePWAInstall());
@@ -53,12 +54,12 @@ describe('usePWAInstall', () => {
53
54
  expect(result.current.canInstall).toBe(true);
54
55
  });
55
56
 
56
- it('should return canInstall as true when not support PWA', () => {
57
+ it('should return canInstall as false when not support PWA', () => {
57
58
  vi.mocked(usePlatform).mockReturnValue({ isSupportInstallPWA: false, isPWA: false } as any);
58
59
 
59
60
  const { result } = renderHook(() => usePWAInstall());
60
61
 
61
- expect(result.current.canInstall).toBe(true);
62
+ expect(result.current.canInstall).toBe(false);
62
63
  });
63
64
 
64
65
  it('should call pwa.showDialog when install is called', () => {
@@ -19,12 +19,11 @@ export const usePWAInstall = () => {
19
19
  }, []);
20
20
 
21
21
  const installCheck = () => {
22
- // 当在 PWA 中时,不显示安装按钮
23
- if (isPWA) return false;
24
- // 其他情况下,根据是否可以安装来显示安装按钮 (如已经安装则不显示)
25
- if (isSupportInstallPWA) return canInstall;
26
- // 当在不支持 PWA 的环境中时,安装按钮 (此时为安装教程)
27
- return true;
22
+ // 当在 PWA 或不支持 PWA 的环境中时,不显示安装按钮
23
+ if (isPWA || !isSupportInstallPWA) return false;
24
+ const pwa: any = document.querySelector(`#${PWA_INSTALL_ID}`);
25
+ if (!pwa) return false;
26
+ return canInstall;
28
27
  };
29
28
 
30
29
  return {
@@ -11,12 +11,14 @@ vi.mock('@/utils/platform', () => ({
11
11
  getPlatform: vi.fn(),
12
12
  isInStandaloneMode: vi.fn(),
13
13
  isSonomaOrLaterSafari: vi.fn(),
14
+ isArc: vi.fn(),
14
15
  }));
15
16
 
16
17
  describe('usePlatform', () => {
17
18
  it('should return correct platform info for Mac OS and Chrome', () => {
18
19
  vi.mocked(platformUtils.getPlatform).mockReturnValue('Mac OS');
19
20
  vi.mocked(platformUtils.getBrowser).mockReturnValue('Chrome');
21
+ vi.mocked(platformUtils.isArc).mockReturnValue(false);
20
22
  vi.mocked(platformUtils.isInStandaloneMode).mockReturnValue(false);
21
23
  vi.mocked(platformUtils.isSonomaOrLaterSafari).mockReturnValue(false);
22
24
 
@@ -27,10 +29,12 @@ describe('usePlatform', () => {
27
29
  isChrome: true,
28
30
  isChromium: true,
29
31
  isEdge: false,
32
+ isFirefox: false,
30
33
  isIOS: false,
31
34
  isMacOS: true,
32
35
  isPWA: false,
33
36
  isSafari: false,
37
+ isArc: false,
34
38
  isSonomaOrLaterSafari: false,
35
39
  isSupportInstallPWA: true,
36
40
  });
@@ -39,6 +43,7 @@ describe('usePlatform', () => {
39
43
  it('should return correct platform info for iOS and Safari', () => {
40
44
  vi.mocked(platformUtils.getPlatform).mockReturnValue('iOS');
41
45
  vi.mocked(platformUtils.getBrowser).mockReturnValue('Safari');
46
+ vi.mocked(platformUtils.isArc).mockReturnValue(false);
42
47
  vi.mocked(platformUtils.isInStandaloneMode).mockReturnValue(true);
43
48
  vi.mocked(platformUtils.isSonomaOrLaterSafari).mockReturnValue(true);
44
49
 
@@ -49,6 +54,8 @@ describe('usePlatform', () => {
49
54
  isChrome: false,
50
55
  isChromium: false,
51
56
  isEdge: false,
57
+ isArc: false,
58
+ isFirefox: false,
52
59
  isIOS: true,
53
60
  isMacOS: false,
54
61
  isPWA: true,
@@ -61,6 +68,7 @@ describe('usePlatform', () => {
61
68
  it('should return correct platform info for Windows and Edge', () => {
62
69
  vi.mocked(platformUtils.getPlatform).mockReturnValue('Windows');
63
70
  vi.mocked(platformUtils.getBrowser).mockReturnValue('Edge');
71
+ vi.mocked(platformUtils.isArc).mockReturnValue(false);
64
72
  vi.mocked(platformUtils.isInStandaloneMode).mockReturnValue(false);
65
73
  vi.mocked(platformUtils.isSonomaOrLaterSafari).mockReturnValue(false);
66
74
 
@@ -71,12 +79,64 @@ describe('usePlatform', () => {
71
79
  isChrome: false,
72
80
  isChromium: true,
73
81
  isEdge: true,
82
+ isFirefox: false,
74
83
  isIOS: false,
75
84
  isMacOS: false,
85
+ isArc: false,
76
86
  isPWA: false,
77
87
  isSafari: false,
78
88
  isSonomaOrLaterSafari: false,
79
89
  isSupportInstallPWA: true,
80
90
  });
81
91
  });
92
+
93
+ it('should return correct platform info for Firefox', () => {
94
+ vi.mocked(platformUtils.getPlatform).mockReturnValue('Windows');
95
+ vi.mocked(platformUtils.getBrowser).mockReturnValue('Firefox');
96
+ vi.mocked(platformUtils.isArc).mockReturnValue(false);
97
+ vi.mocked(platformUtils.isInStandaloneMode).mockReturnValue(false);
98
+ vi.mocked(platformUtils.isSonomaOrLaterSafari).mockReturnValue(false);
99
+
100
+ const { result } = renderHook(() => usePlatform());
101
+
102
+ expect(result.current).toEqual({
103
+ isApple: false,
104
+ isChrome: false,
105
+ isChromium: false,
106
+ isEdge: false,
107
+ isFirefox: true,
108
+ isIOS: false,
109
+ isMacOS: false,
110
+ isArc: false,
111
+ isPWA: false,
112
+ isSafari: false,
113
+ isSonomaOrLaterSafari: false,
114
+ isSupportInstallPWA: false,
115
+ });
116
+ });
117
+
118
+ it('should return correct platform info for Arc', () => {
119
+ vi.mocked(platformUtils.getPlatform).mockReturnValue('Mac OS');
120
+ vi.mocked(platformUtils.getBrowser).mockReturnValue('Chrome');
121
+ vi.mocked(platformUtils.isArc).mockReturnValue(true);
122
+ vi.mocked(platformUtils.isInStandaloneMode).mockReturnValue(false);
123
+ vi.mocked(platformUtils.isSonomaOrLaterSafari).mockReturnValue(false);
124
+
125
+ const { result } = renderHook(() => usePlatform());
126
+
127
+ expect(result.current).toEqual({
128
+ isApple: true,
129
+ isChrome: true,
130
+ isChromium: true,
131
+ isEdge: false,
132
+ isFirefox: false,
133
+ isIOS: false,
134
+ isMacOS: true,
135
+ isArc: true,
136
+ isPWA: false,
137
+ isSafari: false,
138
+ isSonomaOrLaterSafari: false,
139
+ isSupportInstallPWA: false,
140
+ });
141
+ });
82
142
  });
@@ -1,8 +1,9 @@
1
- import { useRef } from 'react';
1
+ import { useMemo, useRef } from 'react';
2
2
 
3
3
  import {
4
4
  getBrowser,
5
5
  getPlatform,
6
+ isArc,
6
7
  isInStandaloneMode,
7
8
  isSonomaOrLaterSafari,
8
9
  } from '@/utils/platform';
@@ -12,21 +13,30 @@ export const usePlatform = () => {
12
13
  const browser = useRef(getBrowser());
13
14
 
14
15
  const platformInfo = {
15
- isApple: platform.current && ['Mac OS', 'iOS'].includes(platform.current),
16
- isChrome: browser.current === 'Chrome',
17
- isChromium: browser.current && ['Chrome', 'Edge', 'Opera', 'Brave'].includes(browser.current),
18
- isEdge: browser.current === 'Edge',
19
- isIOS: platform.current === 'iOS',
20
- isMacOS: platform.current === 'Mac OS',
16
+ isApple: platform.current && ['mac os', 'ios'].includes(platform.current?.toLowerCase()),
17
+ isArc: isArc(),
18
+ isChrome: browser.current?.toLowerCase() === 'chrome',
19
+ isChromium:
20
+ browser.current &&
21
+ ['chrome', 'edge', 'opera', 'brave'].includes(browser.current?.toLowerCase()),
22
+ isEdge: browser.current?.toLowerCase() === 'edge',
23
+ isFirefox: browser.current?.toLowerCase() === 'firefox',
24
+ isIOS: platform.current?.toLowerCase() === 'ios',
25
+ isMacOS: platform.current?.toLowerCase() === 'mac os',
21
26
  isPWA: isInStandaloneMode(),
22
- isSafari: browser.current === 'Safari',
27
+ isSafari: browser.current?.toLowerCase() === 'safari',
23
28
  isSonomaOrLaterSafari: isSonomaOrLaterSafari(),
24
29
  };
25
30
 
26
- return {
27
- ...platformInfo,
28
- isSupportInstallPWA:
29
- (platformInfo.isChromium && !platformInfo.isIOS) ||
30
- (platformInfo.isMacOS && platformInfo.isSonomaOrLaterSafari),
31
- };
31
+ return useMemo(
32
+ () => ({
33
+ ...platformInfo,
34
+ isSupportInstallPWA:
35
+ !platformInfo.isArc &&
36
+ !platformInfo.isFirefox &&
37
+ ((platformInfo.isChromium && !platformInfo.isIOS) ||
38
+ (platformInfo.isMacOS && platformInfo.isSonomaOrLaterSafari)),
39
+ }),
40
+ [platformInfo],
41
+ );
32
42
  };
@@ -107,6 +107,26 @@ describe('LobeZhipuAI', () => {
107
107
  { content: [{ type: 'text', text: 'Hello again' }], role: 'user' },
108
108
  ],
109
109
  model: 'glm-4',
110
+ temperature: 1.6,
111
+ top_p: 1,
112
+ });
113
+
114
+ const calledWithParams = spyOn.mock.calls[0][0];
115
+
116
+ expect(calledWithParams.messages[1].content).toEqual([{ type: 'text', text: 'Hello again' }]);
117
+ expect(calledWithParams.temperature).toBe(0.8); // temperature should be divided by two
118
+ expect(calledWithParams.top_p).toEqual(1);
119
+ });
120
+
121
+ it('should pass arameters correctly', async () => {
122
+ const spyOn = vi.spyOn(instance['client'].chat.completions, 'create');
123
+
124
+ await instance.chat({
125
+ messages: [
126
+ { content: 'Hello', role: 'user' },
127
+ { content: [{ type: 'text', text: 'Hello again' }], role: 'user' },
128
+ ],
129
+ model: 'glm-4-alltools',
110
130
  temperature: 0,
111
131
  top_p: 1,
112
132
  });
@@ -114,9 +134,8 @@ describe('LobeZhipuAI', () => {
114
134
  const calledWithParams = spyOn.mock.calls[0][0];
115
135
 
116
136
  expect(calledWithParams.messages[1].content).toEqual([{ type: 'text', text: 'Hello again' }]);
117
- expect(calledWithParams.temperature).toBe(0); // temperature 0 should be undefined
118
- expect((calledWithParams as any).do_sample).toBeTruthy(); // temperature 0 should be undefined
119
- expect(calledWithParams.top_p).toEqual(1); // top_p should be transformed correctly
137
+ expect(calledWithParams.temperature).toBe(0.01);
138
+ expect(calledWithParams.top_p).toEqual(0.99);
120
139
  });
121
140
 
122
141
  describe('Error', () => {
@@ -6,12 +6,24 @@ import { LobeOpenAICompatibleFactory } from '../utils/openaiCompatibleFactory';
6
6
  export const LobeZhipuAI = LobeOpenAICompatibleFactory({
7
7
  baseURL: 'https://open.bigmodel.cn/api/paas/v4',
8
8
  chatCompletion: {
9
- handlePayload: ({ temperature, ...payload }: ChatStreamPayload) =>
9
+ handlePayload: ({ model, temperature, top_p, ...payload }: ChatStreamPayload) =>
10
10
  ({
11
11
  ...payload,
12
- do_sample: temperature === 0,
12
+ model,
13
13
  stream: true,
14
- temperature,
14
+ ...(model === "glm-4-alltools" ? {
15
+ temperature: temperature !== undefined
16
+ ? Math.max(0.01, Math.min(0.99, temperature / 2))
17
+ : undefined,
18
+ top_p: top_p !== undefined
19
+ ? Math.max(0.01, Math.min(0.99, top_p))
20
+ : undefined,
21
+ } : {
22
+ temperature: temperature !== undefined
23
+ ? temperature / 2
24
+ : undefined,
25
+ top_p,
26
+ }),
15
27
  }) as OpenAI.ChatCompletionCreateParamsStreaming,
16
28
  },
17
29
  debug: {
@@ -1,6 +1,6 @@
1
1
  import { describe, expect, it, vi } from 'vitest';
2
2
 
3
- import { isSonomaOrLaterSafari } from './platform';
3
+ import { isArc, isSonomaOrLaterSafari } from './platform';
4
4
 
5
5
  describe('isSonomaOrLaterSafari', () => {
6
6
  beforeEach(() => {
@@ -80,4 +80,58 @@ describe('isSonomaOrLaterSafari', () => {
80
80
  );
81
81
  expect(isSonomaOrLaterSafari()).toBe(true);
82
82
  });
83
+
84
+ describe('isArc', () => {
85
+ // 保存原始的 window 对象
86
+ const originalWindow = { ...window };
87
+
88
+ beforeEach(() => {
89
+ // 重置 window 对象
90
+ vi.stubGlobal('window', { ...originalWindow });
91
+ // 模拟 matchMedia
92
+ window.matchMedia = vi.fn().mockReturnValue({ matches: false });
93
+ });
94
+
95
+ afterEach(() => {
96
+ // 清理所有模拟
97
+ vi.restoreAllMocks();
98
+ });
99
+
100
+ it('should return false when on server side', () => {
101
+ vi.mock('./platform', async (importOriginal) => {
102
+ const mod = await importOriginal();
103
+
104
+ return {
105
+ // @ts-ignore
106
+ ...mod,
107
+ isOnServerSide: true,
108
+ };
109
+ });
110
+ expect(isArc()).toBe(false);
111
+ });
112
+
113
+ it('should return true when CSS custom property matches', () => {
114
+ window.matchMedia = vi.fn().mockReturnValue({ matches: true });
115
+ expect(isArc()).toBe(true);
116
+ });
117
+
118
+ it('should return true when "arc" is in window', () => {
119
+ (window as any).arc = {};
120
+ expect(isArc()).toBe(true);
121
+ });
122
+
123
+ it('should return true when "ArcControl" is in window', () => {
124
+ (window as any).ArcControl = {};
125
+ expect(isArc()).toBe(true);
126
+ });
127
+
128
+ it('should return true when "ARCControl" is in window', () => {
129
+ (window as any).ARCControl = {};
130
+ expect(isArc()).toBe(true);
131
+ });
132
+
133
+ it('should return false when none of the conditions are met', () => {
134
+ expect(isArc()).toBe(false);
135
+ });
136
+ });
83
137
  });
@@ -25,6 +25,15 @@ export const browserInfo = {
25
25
 
26
26
  export const isMacOS = () => getPlatform() === 'Mac OS';
27
27
 
28
+ export const isArc = () => {
29
+ if (isOnServerSide) return false;
30
+ return (
31
+ window.matchMedia('(--arc-palette-focus: var(--arc-background-simple-color))').matches ||
32
+ Boolean('arc' in window || 'ArcControl' in window || 'ARCControl' in window) ||
33
+ Boolean(getComputedStyle(document.documentElement).getPropertyValue('--arc-palette-title'))
34
+ );
35
+ };
36
+
28
37
  export const isInStandaloneMode = () => {
29
38
  if (isOnServerSide) return false;
30
39
  return (