@lobehub/chat 1.116.3 → 1.117.0

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.
Files changed (124) hide show
  1. package/.github/PULL_REQUEST_TEMPLATE.md +1 -0
  2. package/.github/workflows/release.yml +2 -0
  3. package/.i18nrc.js +1 -1
  4. package/CHANGELOG.md +117 -0
  5. package/changelog/v1.json +21 -0
  6. package/locales/ar/components.json +12 -0
  7. package/locales/ar/models.json +3 -0
  8. package/locales/bg-BG/components.json +12 -0
  9. package/locales/bg-BG/models.json +3 -0
  10. package/locales/de-DE/components.json +12 -0
  11. package/locales/de-DE/models.json +3 -0
  12. package/locales/en-US/components.json +12 -0
  13. package/locales/en-US/models.json +3 -0
  14. package/locales/es-ES/components.json +12 -0
  15. package/locales/es-ES/models.json +3 -0
  16. package/locales/fa-IR/components.json +12 -0
  17. package/locales/fa-IR/models.json +3 -0
  18. package/locales/fr-FR/components.json +12 -0
  19. package/locales/fr-FR/models.json +3 -0
  20. package/locales/it-IT/components.json +12 -0
  21. package/locales/it-IT/models.json +3 -0
  22. package/locales/ja-JP/components.json +12 -0
  23. package/locales/ja-JP/models.json +3 -0
  24. package/locales/ko-KR/components.json +12 -0
  25. package/locales/ko-KR/models.json +3 -0
  26. package/locales/nl-NL/components.json +12 -0
  27. package/locales/nl-NL/models.json +3 -0
  28. package/locales/pl-PL/components.json +12 -0
  29. package/locales/pl-PL/models.json +3 -0
  30. package/locales/pt-BR/components.json +12 -0
  31. package/locales/pt-BR/models.json +3 -0
  32. package/locales/ru-RU/components.json +12 -0
  33. package/locales/ru-RU/models.json +3 -0
  34. package/locales/tr-TR/components.json +12 -0
  35. package/locales/tr-TR/models.json +3 -0
  36. package/locales/vi-VN/components.json +12 -0
  37. package/locales/vi-VN/models.json +3 -0
  38. package/locales/zh-CN/components.json +12 -0
  39. package/locales/zh-CN/models.json +3 -0
  40. package/locales/zh-TW/components.json +12 -0
  41. package/locales/zh-TW/models.json +3 -0
  42. package/package.json +5 -5
  43. package/packages/const/src/image.ts +9 -0
  44. package/packages/const/src/index.ts +2 -1
  45. package/packages/const/src/meta.ts +3 -2
  46. package/packages/const/src/settings/agent.ts +9 -4
  47. package/packages/const/src/settings/systemAgent.ts +0 -3
  48. package/packages/database/vitest.config.mts +1 -0
  49. package/packages/database/vitest.config.server.mts +1 -0
  50. package/packages/file-loaders/package.json +1 -1
  51. package/packages/file-loaders/vitest.config.mts +3 -7
  52. package/packages/model-runtime/src/RouterRuntime/createRuntime.ts +11 -9
  53. package/packages/model-runtime/src/google/createImage.test.ts +657 -0
  54. package/packages/model-runtime/src/google/createImage.ts +152 -0
  55. package/packages/model-runtime/src/google/index.test.ts +0 -328
  56. package/packages/model-runtime/src/google/index.ts +3 -40
  57. package/packages/model-runtime/src/utils/modelParse.ts +2 -1
  58. package/packages/model-runtime/src/utils/openaiCompatibleFactory/createImage.ts +239 -0
  59. package/packages/model-runtime/src/utils/openaiCompatibleFactory/index.test.ts +22 -22
  60. package/packages/model-runtime/src/utils/openaiCompatibleFactory/index.ts +9 -116
  61. package/packages/model-runtime/src/utils/postProcessModelList.ts +55 -0
  62. package/packages/model-runtime/src/utils/streams/google-ai.test.ts +7 -7
  63. package/packages/model-runtime/src/utils/streams/google-ai.ts +15 -2
  64. package/packages/model-runtime/src/utils/streams/openai/openai.test.ts +41 -0
  65. package/packages/model-runtime/src/utils/streams/openai/openai.ts +38 -2
  66. package/packages/model-runtime/src/utils/streams/protocol.test.ts +32 -0
  67. package/packages/model-runtime/src/utils/streams/protocol.ts +7 -3
  68. package/packages/model-runtime/src/utils/usageConverter.test.ts +58 -0
  69. package/packages/model-runtime/src/utils/usageConverter.ts +5 -1
  70. package/packages/model-runtime/vitest.config.mts +3 -0
  71. package/packages/prompts/package.json +0 -1
  72. package/packages/prompts/src/chains/__tests__/abstractChunk.test.ts +52 -0
  73. package/packages/prompts/src/chains/__tests__/answerWithContext.test.ts +100 -0
  74. package/packages/prompts/src/chains/__tests__/rewriteQuery.test.ts +88 -0
  75. package/packages/prompts/src/chains/__tests__/summaryGenerationTitle.test.ts +107 -0
  76. package/packages/prompts/src/chains/abstractChunk.ts +0 -2
  77. package/packages/prompts/src/chains/rewriteQuery.ts +3 -1
  78. package/packages/prompts/src/index.test.ts +41 -0
  79. package/packages/prompts/src/prompts/systemRole/index.test.ts +136 -0
  80. package/packages/prompts/vitest.config.mts +3 -0
  81. package/packages/types/src/index.ts +2 -0
  82. package/packages/utils/package.json +5 -1
  83. package/packages/utils/src/client/index.ts +2 -0
  84. package/packages/utils/src/server/index.ts +5 -0
  85. package/packages/utils/vitest.config.mts +4 -0
  86. package/src/app/(backend)/middleware/auth/index.test.ts +2 -2
  87. package/src/app/(backend)/middleware/auth/index.ts +1 -1
  88. package/src/app/(backend)/oidc/consent/route.ts +1 -2
  89. package/src/app/(backend)/webapi/chat/[provider]/route.test.ts +2 -2
  90. package/src/app/(backend)/webapi/plugin/gateway/route.ts +1 -1
  91. package/src/app/[variants]/(main)/files/[id]/page.tsx +1 -1
  92. package/src/app/[variants]/(main)/settings/sync/page.tsx +1 -1
  93. package/src/app/[variants]/(main)/settings/system-agent/index.tsx +2 -1
  94. package/src/components/HtmlPreview/HtmlPreviewAction.tsx +32 -0
  95. package/src/components/HtmlPreview/PreviewDrawer.tsx +133 -0
  96. package/src/components/HtmlPreview/index.ts +2 -0
  97. package/src/config/aiModels/google.ts +42 -22
  98. package/src/config/aiModels/openrouter.ts +33 -0
  99. package/src/config/aiModels/vertexai.ts +4 -4
  100. package/src/features/Conversation/Extras/Usage/UsageDetail/index.tsx +6 -0
  101. package/src/features/Conversation/Extras/Usage/UsageDetail/tokens.test.ts +38 -0
  102. package/src/features/Conversation/Extras/Usage/UsageDetail/tokens.ts +13 -1
  103. package/src/features/Conversation/components/ChatItem/ShareMessageModal/ShareText/index.tsx +1 -1
  104. package/src/features/Conversation/components/ChatItem/index.tsx +23 -0
  105. package/src/features/ShareModal/ShareJSON/index.tsx +2 -2
  106. package/src/features/ShareModal/ShareText/index.tsx +1 -1
  107. package/src/libs/oidc-provider/adapter.ts +1 -1
  108. package/src/libs/trpc/edge/middleware/jwtPayload.test.ts +1 -1
  109. package/src/libs/trpc/edge/middleware/jwtPayload.ts +1 -2
  110. package/src/libs/trpc/lambda/middleware/keyVaults.ts +1 -2
  111. package/src/locales/default/chat.ts +1 -0
  112. package/src/locales/default/components.ts +12 -0
  113. package/src/middleware.ts +3 -3
  114. package/src/server/routers/tools/search.test.ts +1 -1
  115. package/src/services/config.ts +2 -4
  116. package/src/utils/client/switchLang.ts +1 -1
  117. package/{packages/utils/src → src/utils}/server/pageProps.ts +2 -1
  118. package/tsconfig.json +1 -1
  119. package/vitest.config.mts +1 -0
  120. package/packages/model-runtime/src/UniformRuntime/index.ts +0 -117
  121. /package/{packages/const/src → src/const}/locale.ts +0 -0
  122. /package/{packages/utils/src → src/utils}/locale.test.ts +0 -0
  123. /package/{packages/utils/src → src/utils}/locale.ts +0 -0
  124. /package/{packages/utils/src → src/utils}/server/routeVariants.ts +0 -0
@@ -11,6 +11,39 @@ const openrouterChatModels: AIChatModelCard[] = [
11
11
  id: 'openrouter/auto',
12
12
  type: 'chat',
13
13
  },
14
+ {
15
+ abilities: {
16
+ imageOutput: true,
17
+ vision: true,
18
+ },
19
+ contextWindowTokens: 32_768 + 8192,
20
+ description: 'Gemini 2.5 Flash 实验模型,支持图像生成',
21
+ displayName: 'Gemini 2.5 Flash Image Preview',
22
+ id: 'google/gemini-2.5-flash-image-preview',
23
+ maxOutput: 8192,
24
+ pricing: {
25
+ units: [
26
+ { name: 'imageOutput', rate: 30, strategy: 'fixed', unit: 'millionTokens' },
27
+ { name: 'textInput', rate: 0.3, strategy: 'fixed', unit: 'millionTokens' },
28
+ { name: 'textOutput', rate: 2.5, strategy: 'fixed', unit: 'millionTokens' },
29
+ ],
30
+ },
31
+ releasedAt: '2025-08-26',
32
+ type: 'chat',
33
+ },
34
+ {
35
+ abilities: {
36
+ imageOutput: true,
37
+ vision: true,
38
+ },
39
+ contextWindowTokens: 32_768 + 8192,
40
+ description: 'Gemini 2.5 Flash 实验模型,支持图像生成',
41
+ displayName: 'Gemini 2.5 Flash Image Preview (free)',
42
+ id: 'google/gemini-2.5-flash-image-preview:free',
43
+ maxOutput: 8192,
44
+ releasedAt: '2025-08-26',
45
+ type: 'chat',
46
+ },
14
47
  {
15
48
  abilities: {
16
49
  reasoning: true,
@@ -126,21 +126,21 @@ const vertexaiChatModels: AIChatModelCard[] = [
126
126
  imageOutput: true,
127
127
  vision: true,
128
128
  },
129
- contextWindowTokens: 32_768 + 32_768,
129
+ contextWindowTokens: 32_768 + 8192,
130
130
  description:
131
131
  'Gemini 2.5 Flash Image Preview 是 Google 最新、最快、最高效的原生多模态模型,它允许您通过对话生成和编辑图像。',
132
132
  displayName: 'Gemini 2.5 Flash Image Preview',
133
133
  enabled: true,
134
134
  id: 'gemini-2.5-flash-image-preview',
135
- maxOutput: 32_768,
135
+ maxOutput: 8192,
136
136
  pricing: {
137
137
  units: [
138
138
  { name: 'textInput', rate: 0.3, strategy: 'fixed', unit: 'millionTokens' },
139
139
  { name: 'textOutput', rate: 2.5, strategy: 'fixed', unit: 'millionTokens' },
140
- { name: 'imageOutput', rate: 3, strategy: 'fixed', unit: 'millionTokens' },
140
+ { name: 'imageOutput', rate: 30, strategy: 'fixed', unit: 'millionTokens' },
141
141
  ],
142
142
  },
143
- releasedAt: '2025-08-27',
143
+ releasedAt: '2025-08-26',
144
144
  type: 'chat',
145
145
  },
146
146
  {
@@ -61,6 +61,12 @@ const TokenDetail = memo<TokenDetailProps>(({ meta, model, provider }) => {
61
61
  ? detailTokens.outputReasoning.credit
62
62
  : detailTokens.outputReasoning.token,
63
63
  },
64
+ !!detailTokens.outputImage && {
65
+ color: theme.purple,
66
+ id: 'outputImage',
67
+ title: t('messages.tokenDetails.outputImage'),
68
+ value: isShowCredit ? detailTokens.outputImage.credit : detailTokens.outputImage.token,
69
+ },
64
70
  !!detailTokens.outputAudio && {
65
71
  color: theme.cyan9,
66
72
  id: 'outputAudio',
@@ -143,6 +143,44 @@ describe('getDetailsToken', () => {
143
143
  });
144
144
  });
145
145
 
146
+ it('should handle outputImageTokens correctly', () => {
147
+ const usage = {
148
+ inputTextTokens: 100,
149
+ outputImageTokens: 60,
150
+ outputReasoningTokens: 30,
151
+ totalOutputTokens: 200,
152
+ totalTokens: 300,
153
+ } as ModelTokensUsage;
154
+
155
+ const result = getDetailsToken(usage, mockModelCard);
156
+
157
+ expect(result.outputImage).toEqual({
158
+ credit: 1, // 60 * 0.02 = 1.2 -> 1
159
+ id: 'outputImage',
160
+ token: 60,
161
+ });
162
+
163
+ expect(result.outputReasoning).toEqual({
164
+ credit: 1, // 30 * 0.02 = 0.6 -> 1
165
+ token: 30,
166
+ });
167
+
168
+ expect(result.outputText).toEqual({
169
+ credit: 2, // (200 - 30 - 60) * 0.02 = 2.2 -> 2
170
+ token: 110,
171
+ });
172
+
173
+ expect(result.totalOutput).toEqual({
174
+ credit: 4, // 200 * 0.02 = 4
175
+ token: 200,
176
+ });
177
+
178
+ expect(result.totalTokens).toEqual({
179
+ credit: 4, // total credit equals totalOutputCredit here
180
+ token: 300,
181
+ });
182
+ });
183
+
146
184
  it('should handle inputCitationTokens correctly', () => {
147
185
  const usage: ModelTokensUsage = {
148
186
  inputCitationTokens: 75,
@@ -21,9 +21,14 @@ export const getDetailsToken = (
21
21
 
22
22
  const outputReasoningTokens = usage.outputReasoningTokens || (usage as any).reasoningTokens || 0;
23
23
 
24
+ const outputImageTokens = usage.outputImageTokens || (usage as any).imageTokens || 0;
25
+
24
26
  const outputTextTokens = usage.outputTextTokens
25
27
  ? usage.outputTextTokens
26
- : totalOutputTokens - outputReasoningTokens - (usage.outputAudioTokens || 0);
28
+ : totalOutputTokens -
29
+ outputReasoningTokens -
30
+ (usage.outputAudioTokens || 0) -
31
+ outputImageTokens;
27
32
 
28
33
  const inputWriteCacheTokens = usage.inputWriteCacheTokens || 0;
29
34
  const inputCacheTokens = usage.inputCachedTokens || (usage as any).cachedTokens || 0;
@@ -93,6 +98,13 @@ export const getDetailsToken = (
93
98
  token: usage.outputAudioTokens,
94
99
  }
95
100
  : undefined,
101
+ outputImage: !!outputImageTokens
102
+ ? {
103
+ credit: calcCredit(outputImageTokens, formatPrice.output),
104
+ id: 'outputImage',
105
+ token: outputImageTokens,
106
+ }
107
+ : undefined,
96
108
  outputReasoning: !!outputReasoningTokens
97
109
  ? {
98
110
  credit: calcCredit(outputReasoningTokens, formatPrice.output),
@@ -1,3 +1,4 @@
1
+ import { exportFile } from '@lobechat/utils/client';
1
2
  import { Button, copyToClipboard } from '@lobehub/ui';
2
3
  import { App } from 'antd';
3
4
  import isEqual from 'fast-deep-equal';
@@ -10,7 +11,6 @@ import { useIsMobile } from '@/hooks/useIsMobile';
10
11
  import { useChatStore } from '@/store/chat';
11
12
  import { topicSelectors } from '@/store/chat/selectors';
12
13
  import { ChatMessage } from '@/types/message';
13
- import { exportFile } from '@/utils/client/exportFile';
14
14
 
15
15
  import { useStyles } from '../style';
16
16
  import Preview from './Preview';
@@ -6,6 +6,7 @@ import { MouseEventHandler, ReactNode, memo, use, useCallback, useMemo } from 'r
6
6
  import { useTranslation } from 'react-i18next';
7
7
  import { Flexbox } from 'react-layout-kit';
8
8
 
9
+ import { HtmlPreviewAction } from '@/components/HtmlPreview';
9
10
  import { isDesktop } from '@/const/version';
10
11
  import ChatItem from '@/features/ChatItem';
11
12
  import { VirtuosoContext } from '@/features/Conversation/components/VirtualizedList/VirtuosoContext';
@@ -33,6 +34,14 @@ import { normalizeThinkTags, processWithArtifact } from './utils';
33
34
  const rehypePlugins = markdownElements.map((element) => element.rehypePlugin).filter(Boolean);
34
35
  const remarkPlugins = markdownElements.map((element) => element.remarkPlugin).filter(Boolean);
35
36
 
37
+ const isHtmlCode = (content: string, language: string) => {
38
+ return (
39
+ language === 'html' ||
40
+ (language === '' && content.includes('<html>')) ||
41
+ (language === '' && content.includes('<!DOCTYPE html>'))
42
+ );
43
+ };
44
+
36
45
  const useStyles = createStyles(({ css, prefixCls }) => ({
37
46
  loading: css`
38
47
  opacity: 0.6;
@@ -175,6 +184,20 @@ const Item = memo<ChatListItemProps>(
175
184
  () => ({
176
185
  animated,
177
186
  citations: item?.role === 'user' ? undefined : item?.search?.citations,
187
+ componentProps: {
188
+ highlight: {
189
+ actionsRender: ({ content, actionIconSize, language, originalNode }: any) => {
190
+ const showHtmlPreview = isHtmlCode(content, language);
191
+
192
+ return (
193
+ <>
194
+ {showHtmlPreview && <HtmlPreviewAction content={content} size={actionIconSize} />}
195
+ {originalNode}
196
+ </>
197
+ );
198
+ },
199
+ },
200
+ },
178
201
  components,
179
202
  customRender: markdownCustomRender,
180
203
  enableCustomFootnotes: item?.role === 'assistant',
@@ -1,3 +1,5 @@
1
+ import { FORM_STYLE } from '@lobechat/const';
2
+ import { exportFile } from '@lobechat/utils/client';
1
3
  import { Button, Form, type FormItemProps, copyToClipboard } from '@lobehub/ui';
2
4
  import { App, Switch } from 'antd';
3
5
  import isEqual from 'fast-deep-equal';
@@ -6,13 +8,11 @@ import { memo, useState } from 'react';
6
8
  import { useTranslation } from 'react-i18next';
7
9
  import { Flexbox } from 'react-layout-kit';
8
10
 
9
- import { FORM_STYLE } from '@/const/layoutTokens';
10
11
  import { useIsMobile } from '@/hooks/useIsMobile';
11
12
  import { useAgentStore } from '@/store/agent';
12
13
  import { agentSelectors } from '@/store/agent/selectors';
13
14
  import { useChatStore } from '@/store/chat';
14
15
  import { chatSelectors, topicSelectors } from '@/store/chat/selectors';
15
- import { exportFile } from '@/utils/client/exportFile';
16
16
 
17
17
  import { useStyles } from '../style';
18
18
  import Preview from './Preview';
@@ -1,3 +1,4 @@
1
+ import { exportFile } from '@lobechat/utils/client';
1
2
  import { Button, Form, type FormItemProps, copyToClipboard } from '@lobehub/ui';
2
3
  import { App, Switch } from 'antd';
3
4
  import isEqual from 'fast-deep-equal';
@@ -12,7 +13,6 @@ import { useAgentStore } from '@/store/agent';
12
13
  import { agentSelectors } from '@/store/agent/selectors';
13
14
  import { useChatStore } from '@/store/chat';
14
15
  import { chatSelectors, topicSelectors } from '@/store/chat/selectors';
15
- import { exportFile } from '@/utils/client/exportFile';
16
16
 
17
17
  import { useStyles } from '../style';
18
18
  import Preview from './Preview';
@@ -164,7 +164,7 @@ class OIDCAdapter {
164
164
  log('[%s] Setting userId: %s', this.name, payload.accountId);
165
165
  } else {
166
166
  try {
167
- const { getUserAuth } = await import('@/utils/server/auth');
167
+ const { getUserAuth } = await import('@lobechat/utils/server');
168
168
  try {
169
169
  const { userId } = await getUserAuth();
170
170
  if (userId) {
@@ -1,11 +1,11 @@
1
1
  // @vitest-environment node
2
+ import * as utils from '@lobechat/utils/server';
2
3
  import { TRPCError } from '@trpc/server';
3
4
  import { beforeEach, describe, expect, it, vi } from 'vitest';
4
5
 
5
6
  import { createCallerFactory } from '@/libs/trpc/edge';
6
7
  import { AuthContext, createContextInner } from '@/libs/trpc/edge/context';
7
8
  import { edgeTrpc as trpc } from '@/libs/trpc/edge/init';
8
- import * as utils from '@/utils/server/xor';
9
9
 
10
10
  import { jwtPayloadChecker } from './jwtPayload';
11
11
 
@@ -1,7 +1,6 @@
1
+ import { getXorPayload } from '@lobechat/utils/server';
1
2
  import { TRPCError } from '@trpc/server';
2
3
 
3
- import { getXorPayload } from '@/utils/server/xor';
4
-
5
4
  import { edgeTrpc } from '../init';
6
5
 
7
6
  export const jwtPayloadChecker = edgeTrpc.middleware(async (opts) => {
@@ -1,7 +1,6 @@
1
+ import { getXorPayload } from '@lobechat/utils/server';
1
2
  import { TRPCError } from '@trpc/server';
2
3
 
3
- import { getXorPayload } from '@/utils/server/xor';
4
-
5
4
  import { trpc } from '../init';
6
5
 
7
6
  export const keyVaults = trpc.middleware(async (opts) => {
@@ -128,6 +128,7 @@ export default {
128
128
  inputWriteCached: '输入缓存写入',
129
129
  output: '输出',
130
130
  outputAudio: '音频输出',
131
+ outputImage: '图像输出',
131
132
  outputText: '文本输出',
132
133
  outputTitle: '输出明细',
133
134
  reasoning: '深度思考',
@@ -75,6 +75,18 @@ export default {
75
75
  GoBack: {
76
76
  back: '返回',
77
77
  },
78
+ HtmlPreview: {
79
+ actions: {
80
+ download: '下载',
81
+ preview: '预览',
82
+ },
83
+ iframeTitle: 'HTML 预览',
84
+ mode: {
85
+ code: '代码',
86
+ preview: '预览',
87
+ },
88
+ title: 'HTML 预览',
89
+ },
78
90
  ImageUpload: {
79
91
  actions: {
80
92
  changeImage: '点击更换图片',
package/src/middleware.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { clerkMiddleware, createRouteMatcher } from '@clerk/nextjs/server';
2
+ import { parseDefaultThemeFromCountry } from '@lobechat/utils/server';
2
3
  import debug from 'debug';
3
4
  import { NextRequest, NextResponse } from 'next/server';
4
5
  import { UAParser } from 'ua-parser-js';
@@ -11,11 +12,10 @@ import { LOBE_THEME_APPEARANCE } from '@/const/theme';
11
12
  import { appEnv } from '@/envs/app';
12
13
  import NextAuthEdge from '@/libs/next-auth/edge';
13
14
  import { Locales } from '@/locales/resources';
14
- import { parseBrowserLanguage } from '@/utils/locale';
15
- import { parseDefaultThemeFromCountry } from '@/utils/server/geo';
16
- import { RouteVariants } from '@/utils/server/routeVariants';
17
15
 
18
16
  import { oidcEnv } from './envs/oidc';
17
+ import { parseBrowserLanguage } from './utils/locale';
18
+ import { RouteVariants } from './utils/server/routeVariants';
19
19
 
20
20
  // Create debug logger instances
21
21
  const logDefault = debug('middleware:default');
@@ -9,7 +9,7 @@ import { SEARCH_SEARXNG_NOT_CONFIG } from '@/types/tool/search';
9
9
  import { searchRouter } from './search';
10
10
 
11
11
  // Mock JWT verification
12
- vi.mock('@/utils/server/xor', () => ({
12
+ vi.mock('@lobechat/utils/server', () => ({
13
13
  getXorPayload: vi.fn().mockReturnValue({ userId: '1' }),
14
14
  }));
15
15
 
@@ -1,11 +1,9 @@
1
+ import { BRANDING_NAME, isDeprecatedEdition, isServerMode } from '@lobechat/const';
2
+ import { downloadFile, exportJSONFile } from '@lobechat/utils/client';
1
3
  import dayjs from 'dayjs';
2
4
 
3
- import { BRANDING_NAME } from '@/const/branding';
4
- import { isDeprecatedEdition, isServerMode } from '@/const/version';
5
5
  import { CURRENT_CONFIG_VERSION } from '@/migrations';
6
6
  import { ImportPgDataStructure } from '@/types/export';
7
- import { downloadFile } from '@/utils/client/downloadFile';
8
- import { exportJSONFile } from '@/utils/client/exportFile';
9
7
 
10
8
  import { exportService } from './export';
11
9
  import { configService as deprecatedExportService } from './export/_deprecated';
@@ -1,7 +1,7 @@
1
- import { LOBE_LOCALE_COOKIE } from '@lobechat/const';
2
1
  import { setCookie } from '@lobechat/utils';
3
2
  import { changeLanguage } from 'i18next';
4
3
 
4
+ import { LOBE_LOCALE_COOKIE } from '@/const/locale';
5
5
  import { LocaleMode } from '@/types/locale';
6
6
 
7
7
  export const switchLang = (locale: LocaleMode) => {
@@ -1,6 +1,7 @@
1
1
  import { translation } from '@/server/translation';
2
2
  import { DynamicLayoutProps } from '@/types/next';
3
- import { RouteVariants } from '@/utils/server/routeVariants';
3
+
4
+ import { RouteVariants } from './routeVariants';
4
5
 
5
6
  export const parsePageMetaProps = async (props: DynamicLayoutProps) => {
6
7
  const { locale: hl, isMobile } = await RouteVariants.getVariantsFromProps(props);
package/tsconfig.json CHANGED
@@ -21,7 +21,7 @@
21
21
  "@/libs/model-runtime": ["./packages/model-runtime/src/index.ts"],
22
22
  "@/libs/model-runtime/*": ["./packages/model-runtime/src/*"],
23
23
  "@/database/*": ["./packages/database/src/*", "./src/database/*"],
24
- "@/const/*": ["./packages/const/src/*"],
24
+ "@/const/*": ["./packages/const/src/*", "./src/const/*"],
25
25
  "@/utils/*": ["./packages/utils/src/*", "./src/utils/*"],
26
26
  "@/types/*": ["./packages/types/src/*", "./src/types/*"],
27
27
  "@/*": ["./src/*"],
package/vitest.config.mts CHANGED
@@ -13,6 +13,7 @@ export default defineConfig({
13
13
  '@/database/_deprecated': resolve(__dirname, './src/database/_deprecated'),
14
14
  '@/database': resolve(__dirname, './packages/database/src'),
15
15
  '@/utils/client/switchLang': resolve(__dirname, './src/utils/client/switchLang'),
16
+ '@/const/locale': resolve(__dirname, './src/const/locale'),
16
17
  // TODO: after refactor the errorResponse, we can remove it
17
18
  '@/utils/errorResponse': resolve(__dirname, './src/utils/errorResponse'),
18
19
  '@/utils': resolve(__dirname, './packages/utils/src'),
@@ -1,117 +0,0 @@
1
- /**
2
- * @see https://github.com/lobehub/lobe-chat/discussions/6563
3
- */
4
- import { LobeRuntimeAI } from '../BaseAI';
5
- import { LobeOpenAI } from '../openai';
6
- import { providerRuntimeMap } from '../runtimeMap';
7
- import {
8
- type ChatCompletionErrorPayload,
9
- ChatMethodOptions,
10
- ChatStreamPayload,
11
- EmbeddingsOptions,
12
- EmbeddingsPayload,
13
- TextToImagePayload,
14
- TextToSpeechPayload,
15
- } from '../types';
16
-
17
- export interface RuntimeItem {
18
- id: string;
19
- models?: string[];
20
- runtime: LobeRuntimeAI;
21
- }
22
-
23
- interface ProviderInitParams extends Record<string, any> {
24
- accessKeyId?: string;
25
- accessKeySecret?: string;
26
- apiKey?: string;
27
- apiVersion?: string;
28
- baseURL?: string;
29
- baseURLOrAccountID?: string;
30
- dangerouslyAllowBrowser?: boolean;
31
- region?: string;
32
- sessionToken?: string;
33
- }
34
-
35
- interface ProviderInstance {
36
- apiType: keyof typeof providerRuntimeMap;
37
- models?: string[];
38
- params: ProviderInitParams;
39
- runtime?: typeof LobeOpenAI;
40
- }
41
-
42
- interface UniformRuntimeOptions {
43
- chat?: {
44
- handleError?: (error: any) => Omit<ChatCompletionErrorPayload, 'provider'> | undefined;
45
- };
46
- }
47
-
48
- class UniformRuntime {
49
- private _runtimes: RuntimeItem[];
50
- private _options: UniformRuntimeOptions;
51
-
52
- constructor(id: string, providers: ProviderInstance[], options: UniformRuntimeOptions) {
53
- if (providers.length === 0) {
54
- throw new Error('empty providers');
55
- }
56
-
57
- this._runtimes = providers.map((options) => {
58
- const providerAI = options.runtime ?? providerRuntimeMap[options.apiType] ?? LobeOpenAI;
59
- const runtime: LobeRuntimeAI = new providerAI({ ...options.params, id });
60
-
61
- return { id: options.apiType, models: options.models, runtime };
62
- });
63
-
64
- this._options = options;
65
- }
66
-
67
- // 检查下是否能匹配到特定模型,否则默认使用第一个 runtime
68
- getRuntimeByModel(model: string) {
69
- const runtimeItem =
70
- this._runtimes.find((runtime) => runtime.models && runtime.models.includes(model)) ||
71
- this._runtimes[0];
72
-
73
- return runtimeItem.runtime;
74
- }
75
-
76
- async chat(payload: ChatStreamPayload, options?: ChatMethodOptions) {
77
- try {
78
- const runtime = this.getRuntimeByModel(payload.model);
79
-
80
- return await runtime.chat!(payload, options);
81
- } catch (e) {
82
- if (this._options.chat?.handleError) {
83
- const error = this._options.chat.handleError(e);
84
-
85
- if (error) {
86
- throw error;
87
- }
88
- }
89
-
90
- throw e;
91
- }
92
- }
93
-
94
- async textToImage(payload: TextToImagePayload) {
95
- const runtime = this.getRuntimeByModel(payload.model);
96
-
97
- return runtime.textToImage?.(payload);
98
- }
99
-
100
- async models() {
101
- return this._runtimes[0].runtime.models?.();
102
- }
103
-
104
- async embeddings(payload: EmbeddingsPayload, options?: EmbeddingsOptions) {
105
- const runtime = this.getRuntimeByModel(payload.model);
106
-
107
- return runtime.embeddings?.(payload, options);
108
- }
109
-
110
- async textToSpeech(payload: TextToSpeechPayload, options?: EmbeddingsOptions) {
111
- const runtime = this.getRuntimeByModel(payload.model);
112
-
113
- return runtime.textToSpeech?.(payload, options);
114
- }
115
- }
116
-
117
- export default UniformRuntime;
File without changes
File without changes