@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.
- package/.github/PULL_REQUEST_TEMPLATE.md +1 -0
- package/.github/workflows/release.yml +2 -0
- package/.i18nrc.js +1 -1
- package/CHANGELOG.md +117 -0
- package/changelog/v1.json +21 -0
- package/locales/ar/components.json +12 -0
- package/locales/ar/models.json +3 -0
- package/locales/bg-BG/components.json +12 -0
- package/locales/bg-BG/models.json +3 -0
- package/locales/de-DE/components.json +12 -0
- package/locales/de-DE/models.json +3 -0
- package/locales/en-US/components.json +12 -0
- package/locales/en-US/models.json +3 -0
- package/locales/es-ES/components.json +12 -0
- package/locales/es-ES/models.json +3 -0
- package/locales/fa-IR/components.json +12 -0
- package/locales/fa-IR/models.json +3 -0
- package/locales/fr-FR/components.json +12 -0
- package/locales/fr-FR/models.json +3 -0
- package/locales/it-IT/components.json +12 -0
- package/locales/it-IT/models.json +3 -0
- package/locales/ja-JP/components.json +12 -0
- package/locales/ja-JP/models.json +3 -0
- package/locales/ko-KR/components.json +12 -0
- package/locales/ko-KR/models.json +3 -0
- package/locales/nl-NL/components.json +12 -0
- package/locales/nl-NL/models.json +3 -0
- package/locales/pl-PL/components.json +12 -0
- package/locales/pl-PL/models.json +3 -0
- package/locales/pt-BR/components.json +12 -0
- package/locales/pt-BR/models.json +3 -0
- package/locales/ru-RU/components.json +12 -0
- package/locales/ru-RU/models.json +3 -0
- package/locales/tr-TR/components.json +12 -0
- package/locales/tr-TR/models.json +3 -0
- package/locales/vi-VN/components.json +12 -0
- package/locales/vi-VN/models.json +3 -0
- package/locales/zh-CN/components.json +12 -0
- package/locales/zh-CN/models.json +3 -0
- package/locales/zh-TW/components.json +12 -0
- package/locales/zh-TW/models.json +3 -0
- package/package.json +5 -5
- package/packages/const/src/image.ts +9 -0
- package/packages/const/src/index.ts +2 -1
- package/packages/const/src/meta.ts +3 -2
- package/packages/const/src/settings/agent.ts +9 -4
- package/packages/const/src/settings/systemAgent.ts +0 -3
- package/packages/database/vitest.config.mts +1 -0
- package/packages/database/vitest.config.server.mts +1 -0
- package/packages/file-loaders/package.json +1 -1
- package/packages/file-loaders/vitest.config.mts +3 -7
- package/packages/model-runtime/src/RouterRuntime/createRuntime.ts +11 -9
- package/packages/model-runtime/src/google/createImage.test.ts +657 -0
- package/packages/model-runtime/src/google/createImage.ts +152 -0
- package/packages/model-runtime/src/google/index.test.ts +0 -328
- package/packages/model-runtime/src/google/index.ts +3 -40
- package/packages/model-runtime/src/utils/modelParse.ts +2 -1
- package/packages/model-runtime/src/utils/openaiCompatibleFactory/createImage.ts +239 -0
- package/packages/model-runtime/src/utils/openaiCompatibleFactory/index.test.ts +22 -22
- package/packages/model-runtime/src/utils/openaiCompatibleFactory/index.ts +9 -116
- package/packages/model-runtime/src/utils/postProcessModelList.ts +55 -0
- package/packages/model-runtime/src/utils/streams/google-ai.test.ts +7 -7
- package/packages/model-runtime/src/utils/streams/google-ai.ts +15 -2
- package/packages/model-runtime/src/utils/streams/openai/openai.test.ts +41 -0
- package/packages/model-runtime/src/utils/streams/openai/openai.ts +38 -2
- package/packages/model-runtime/src/utils/streams/protocol.test.ts +32 -0
- package/packages/model-runtime/src/utils/streams/protocol.ts +7 -3
- package/packages/model-runtime/src/utils/usageConverter.test.ts +58 -0
- package/packages/model-runtime/src/utils/usageConverter.ts +5 -1
- package/packages/model-runtime/vitest.config.mts +3 -0
- package/packages/prompts/package.json +0 -1
- package/packages/prompts/src/chains/__tests__/abstractChunk.test.ts +52 -0
- package/packages/prompts/src/chains/__tests__/answerWithContext.test.ts +100 -0
- package/packages/prompts/src/chains/__tests__/rewriteQuery.test.ts +88 -0
- package/packages/prompts/src/chains/__tests__/summaryGenerationTitle.test.ts +107 -0
- package/packages/prompts/src/chains/abstractChunk.ts +0 -2
- package/packages/prompts/src/chains/rewriteQuery.ts +3 -1
- package/packages/prompts/src/index.test.ts +41 -0
- package/packages/prompts/src/prompts/systemRole/index.test.ts +136 -0
- package/packages/prompts/vitest.config.mts +3 -0
- package/packages/types/src/index.ts +2 -0
- package/packages/utils/package.json +5 -1
- package/packages/utils/src/client/index.ts +2 -0
- package/packages/utils/src/server/index.ts +5 -0
- package/packages/utils/vitest.config.mts +4 -0
- package/src/app/(backend)/middleware/auth/index.test.ts +2 -2
- package/src/app/(backend)/middleware/auth/index.ts +1 -1
- package/src/app/(backend)/oidc/consent/route.ts +1 -2
- package/src/app/(backend)/webapi/chat/[provider]/route.test.ts +2 -2
- package/src/app/(backend)/webapi/plugin/gateway/route.ts +1 -1
- package/src/app/[variants]/(main)/files/[id]/page.tsx +1 -1
- package/src/app/[variants]/(main)/settings/sync/page.tsx +1 -1
- package/src/app/[variants]/(main)/settings/system-agent/index.tsx +2 -1
- package/src/components/HtmlPreview/HtmlPreviewAction.tsx +32 -0
- package/src/components/HtmlPreview/PreviewDrawer.tsx +133 -0
- package/src/components/HtmlPreview/index.ts +2 -0
- package/src/config/aiModels/google.ts +42 -22
- package/src/config/aiModels/openrouter.ts +33 -0
- package/src/config/aiModels/vertexai.ts +4 -4
- package/src/features/Conversation/Extras/Usage/UsageDetail/index.tsx +6 -0
- package/src/features/Conversation/Extras/Usage/UsageDetail/tokens.test.ts +38 -0
- package/src/features/Conversation/Extras/Usage/UsageDetail/tokens.ts +13 -1
- package/src/features/Conversation/components/ChatItem/ShareMessageModal/ShareText/index.tsx +1 -1
- package/src/features/Conversation/components/ChatItem/index.tsx +23 -0
- package/src/features/ShareModal/ShareJSON/index.tsx +2 -2
- package/src/features/ShareModal/ShareText/index.tsx +1 -1
- package/src/libs/oidc-provider/adapter.ts +1 -1
- package/src/libs/trpc/edge/middleware/jwtPayload.test.ts +1 -1
- package/src/libs/trpc/edge/middleware/jwtPayload.ts +1 -2
- package/src/libs/trpc/lambda/middleware/keyVaults.ts +1 -2
- package/src/locales/default/chat.ts +1 -0
- package/src/locales/default/components.ts +12 -0
- package/src/middleware.ts +3 -3
- package/src/server/routers/tools/search.test.ts +1 -1
- package/src/services/config.ts +2 -4
- package/src/utils/client/switchLang.ts +1 -1
- package/{packages/utils/src → src/utils}/server/pageProps.ts +2 -1
- package/tsconfig.json +1 -1
- package/vitest.config.mts +1 -0
- package/packages/model-runtime/src/UniformRuntime/index.ts +0 -117
- /package/{packages/const/src → src/const}/locale.ts +0 -0
- /package/{packages/utils/src → src/utils}/locale.test.ts +0 -0
- /package/{packages/utils/src → src/utils}/locale.ts +0 -0
- /package/{packages/utils/src → src/utils}/server/routeVariants.ts +0 -0
@@ -0,0 +1,41 @@
|
|
1
|
+
import { describe, expect, it, vi } from 'vitest';
|
2
|
+
|
3
|
+
import * as chains from './chains';
|
4
|
+
import * as mainExports from './index';
|
5
|
+
import * as prompts from './prompts';
|
6
|
+
|
7
|
+
// Mock the problematic dependency
|
8
|
+
vi.mock('@/locales/resources', () => ({
|
9
|
+
supportLocales: ['en-US', 'zh-CN'],
|
10
|
+
}));
|
11
|
+
|
12
|
+
describe('Main Index Export', () => {
|
13
|
+
it('should export all chains', () => {
|
14
|
+
expect(mainExports).toEqual(expect.objectContaining(chains));
|
15
|
+
});
|
16
|
+
|
17
|
+
it('should export all prompts', () => {
|
18
|
+
expect(mainExports).toEqual(expect.objectContaining(prompts));
|
19
|
+
});
|
20
|
+
|
21
|
+
it('should have all expected chain exports', () => {
|
22
|
+
const chainExports = [
|
23
|
+
'chainAbstractChunkText',
|
24
|
+
'chainAnswerWithContext',
|
25
|
+
'chainLangDetect',
|
26
|
+
'chainPickEmoji',
|
27
|
+
'chainRewriteQuery',
|
28
|
+
'chainSummaryAgentName',
|
29
|
+
'chainSummaryDescription',
|
30
|
+
'chainSummaryGenerationTitle',
|
31
|
+
'chainSummaryHistory',
|
32
|
+
'chainSummaryTags',
|
33
|
+
'chainSummaryTitle',
|
34
|
+
'chainTranslate',
|
35
|
+
];
|
36
|
+
|
37
|
+
chainExports.forEach((exportName) => {
|
38
|
+
expect(mainExports).toHaveProperty(exportName);
|
39
|
+
});
|
40
|
+
});
|
41
|
+
});
|
@@ -0,0 +1,136 @@
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
2
|
+
|
3
|
+
import { BuiltinSystemRolePrompts } from './index';
|
4
|
+
|
5
|
+
describe('BuiltinSystemRolePrompts', () => {
|
6
|
+
it('should return welcome message only when only welcome is provided', () => {
|
7
|
+
const result = BuiltinSystemRolePrompts({
|
8
|
+
welcome: 'Welcome to the assistant!',
|
9
|
+
});
|
10
|
+
|
11
|
+
expect(result).toBe('Welcome to the assistant!');
|
12
|
+
});
|
13
|
+
|
14
|
+
it('should return plugins message only when only plugins is provided', () => {
|
15
|
+
const result = BuiltinSystemRolePrompts({
|
16
|
+
plugins: 'Available plugins: calculator, weather',
|
17
|
+
});
|
18
|
+
|
19
|
+
expect(result).toBe('Available plugins: calculator, weather');
|
20
|
+
});
|
21
|
+
|
22
|
+
it('should return history summary when only history is provided', () => {
|
23
|
+
const result = BuiltinSystemRolePrompts({
|
24
|
+
historySummary: 'User discussed AI topics previously',
|
25
|
+
});
|
26
|
+
|
27
|
+
expect(result).toContain('<chat_history_summary>');
|
28
|
+
expect(result).toContain(
|
29
|
+
'<docstring>Users may have lots of chat messages, here is the summary of the history:</docstring>',
|
30
|
+
);
|
31
|
+
expect(result).toContain('<summary>User discussed AI topics previously</summary>');
|
32
|
+
expect(result).toContain('</chat_history_summary>');
|
33
|
+
expect(result.trim()).toMatch(/^<chat_history_summary>[\s\S]*<\/chat_history_summary>$/);
|
34
|
+
});
|
35
|
+
|
36
|
+
it('should combine all three parts when all are provided', () => {
|
37
|
+
const result = BuiltinSystemRolePrompts({
|
38
|
+
welcome: 'Welcome!',
|
39
|
+
plugins: 'Plugins available',
|
40
|
+
historySummary: 'Previous conversation summary',
|
41
|
+
});
|
42
|
+
|
43
|
+
expect(result).toContain('Welcome!');
|
44
|
+
expect(result).toContain('Plugins available');
|
45
|
+
expect(result).toContain('<chat_history_summary>');
|
46
|
+
expect(result).toContain('Previous conversation summary');
|
47
|
+
expect(result).toContain('</chat_history_summary>');
|
48
|
+
|
49
|
+
// Should be joined with double newlines
|
50
|
+
const parts = result.split('\n\n');
|
51
|
+
expect(parts).toHaveLength(3);
|
52
|
+
});
|
53
|
+
|
54
|
+
it('should combine welcome and plugins when no history is provided', () => {
|
55
|
+
const result = BuiltinSystemRolePrompts({
|
56
|
+
welcome: 'Hello user!',
|
57
|
+
plugins: 'Available tools',
|
58
|
+
});
|
59
|
+
|
60
|
+
expect(result).toBe('Hello user!\n\nAvailable tools');
|
61
|
+
});
|
62
|
+
|
63
|
+
it('should combine welcome and history when no plugins provided', () => {
|
64
|
+
const result = BuiltinSystemRolePrompts({
|
65
|
+
welcome: 'Greetings!',
|
66
|
+
historySummary: 'Chat history here',
|
67
|
+
});
|
68
|
+
|
69
|
+
expect(result).toContain('Greetings!');
|
70
|
+
expect(result).toContain('<chat_history_summary>');
|
71
|
+
expect(result).toContain('Chat history here');
|
72
|
+
});
|
73
|
+
|
74
|
+
it('should combine plugins and history when no welcome provided', () => {
|
75
|
+
const result = BuiltinSystemRolePrompts({
|
76
|
+
plugins: 'Tool list',
|
77
|
+
historySummary: 'Summary of previous chats',
|
78
|
+
});
|
79
|
+
|
80
|
+
expect(result).toContain('Tool list');
|
81
|
+
expect(result).toContain('<chat_history_summary>');
|
82
|
+
expect(result).toContain('Summary of previous chats');
|
83
|
+
});
|
84
|
+
|
85
|
+
it('should return empty string when no parameters provided', () => {
|
86
|
+
const result = BuiltinSystemRolePrompts({});
|
87
|
+
|
88
|
+
expect(result).toBe('');
|
89
|
+
});
|
90
|
+
|
91
|
+
it('should filter out falsy values', () => {
|
92
|
+
const result = BuiltinSystemRolePrompts({
|
93
|
+
welcome: '',
|
94
|
+
plugins: 'Valid plugins',
|
95
|
+
historySummary: undefined,
|
96
|
+
});
|
97
|
+
|
98
|
+
expect(result).toBe('Valid plugins');
|
99
|
+
});
|
100
|
+
|
101
|
+
it('should handle null and undefined values gracefully', () => {
|
102
|
+
const result = BuiltinSystemRolePrompts({
|
103
|
+
welcome: undefined,
|
104
|
+
plugins: null as any,
|
105
|
+
historySummary: 'Valid history',
|
106
|
+
});
|
107
|
+
|
108
|
+
expect(result).toContain('<chat_history_summary>');
|
109
|
+
expect(result).toContain('<summary>Valid history</summary>');
|
110
|
+
expect(result).toContain('</chat_history_summary>');
|
111
|
+
});
|
112
|
+
|
113
|
+
it('should preserve whitespace in individual components', () => {
|
114
|
+
const result = BuiltinSystemRolePrompts({
|
115
|
+
welcome: 'Welcome\nwith newlines',
|
116
|
+
plugins: 'Plugins\twith tabs',
|
117
|
+
});
|
118
|
+
|
119
|
+
expect(result).toContain('Welcome\nwith newlines');
|
120
|
+
expect(result).toContain('Plugins\twith tabs');
|
121
|
+
});
|
122
|
+
|
123
|
+
it('should format history summary with proper XML structure', () => {
|
124
|
+
const historySummary = 'User asked about weather and traffic';
|
125
|
+
const result = BuiltinSystemRolePrompts({
|
126
|
+
historySummary,
|
127
|
+
});
|
128
|
+
|
129
|
+
expect(result).toContain('<chat_history_summary>');
|
130
|
+
expect(result).toContain(
|
131
|
+
'<docstring>Users may have lots of chat messages, here is the summary of the history:</docstring>',
|
132
|
+
);
|
133
|
+
expect(result).toContain('<summary>User asked about weather and traffic</summary>');
|
134
|
+
expect(result).toContain('</chat_history_summary>');
|
135
|
+
});
|
136
|
+
});
|
@@ -1,3 +1,4 @@
|
|
1
|
+
export * from './agent';
|
1
2
|
export * from './artifact';
|
2
3
|
export * from './chunk';
|
3
4
|
export * from './clientDB';
|
@@ -6,6 +7,7 @@ export * from './fetch';
|
|
6
7
|
export * from './knowledgeBase';
|
7
8
|
export * from './llm';
|
8
9
|
export * from './message';
|
10
|
+
export * from './meta';
|
9
11
|
export * from './user';
|
10
12
|
export * from './user/settings';
|
11
13
|
// FIXME: I think we need a refactor for the "openai" types
|
@@ -2,7 +2,11 @@
|
|
2
2
|
"name": "@lobechat/utils",
|
3
3
|
"version": "1.0.0",
|
4
4
|
"private": true,
|
5
|
-
"
|
5
|
+
"exports": {
|
6
|
+
".": "./src/index.ts",
|
7
|
+
"./server": "./src/server/index.ts",
|
8
|
+
"./client": "./src/client/index.ts"
|
9
|
+
},
|
6
10
|
"scripts": {
|
7
11
|
"test": "vitest",
|
8
12
|
"test:coverage": "vitest --coverage"
|
@@ -7,9 +7,13 @@ export default defineConfig({
|
|
7
7
|
/* eslint-disable sort-keys-fix/sort-keys-fix */
|
8
8
|
'@/types': resolve(__dirname, '../types/src'),
|
9
9
|
'@/const': resolve(__dirname, '../const/src'),
|
10
|
+
'@/libs/model-runtime': resolve(__dirname, '../model-runtime/src'),
|
10
11
|
'@': resolve(__dirname, '../../src'),
|
11
12
|
/* eslint-enable */
|
12
13
|
},
|
14
|
+
coverage: {
|
15
|
+
reporter: ['text', 'json', 'lcov', 'text-summary'],
|
16
|
+
},
|
13
17
|
environment: 'happy-dom',
|
14
18
|
setupFiles: join(__dirname, './tests/setup.ts'),
|
15
19
|
},
|
@@ -1,9 +1,9 @@
|
|
1
1
|
import { AgentRuntimeError } from '@lobechat/model-runtime';
|
2
2
|
import { ChatErrorType } from '@lobechat/types';
|
3
|
+
import { getXorPayload } from '@lobechat/utils/server';
|
3
4
|
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
4
5
|
|
5
6
|
import { createErrorResponse } from '@/utils/errorResponse';
|
6
|
-
import { getXorPayload } from '@/utils/server/xor';
|
7
7
|
|
8
8
|
import { RequestHandler, checkAuth } from './index';
|
9
9
|
import { checkAuthMethod } from './utils';
|
@@ -20,7 +20,7 @@ vi.mock('./utils', () => ({
|
|
20
20
|
checkAuthMethod: vi.fn(),
|
21
21
|
}));
|
22
22
|
|
23
|
-
vi.mock('
|
23
|
+
vi.mock('@lobechat/utils/server', () => ({
|
24
24
|
getXorPayload: vi.fn(),
|
25
25
|
}));
|
26
26
|
|
@@ -5,6 +5,7 @@ import {
|
|
5
5
|
ModelRuntime,
|
6
6
|
} from '@lobechat/model-runtime';
|
7
7
|
import { ChatErrorType } from '@lobechat/types';
|
8
|
+
import { getXorPayload } from '@lobechat/utils/server';
|
8
9
|
import { NextRequest } from 'next/server';
|
9
10
|
|
10
11
|
import {
|
@@ -17,7 +18,6 @@ import {
|
|
17
18
|
import { ClerkAuth } from '@/libs/clerk-auth';
|
18
19
|
import { validateOIDCJWT } from '@/libs/oidc-provider/jwt';
|
19
20
|
import { createErrorResponse } from '@/utils/errorResponse';
|
20
|
-
import { getXorPayload } from '@/utils/server/xor';
|
21
21
|
|
22
22
|
import { checkAuthMethod } from './utils';
|
23
23
|
|
@@ -1,9 +1,8 @@
|
|
1
|
+
import { correctOIDCUrl, getUserAuth } from '@lobechat/utils/server';
|
1
2
|
import debug from 'debug';
|
2
3
|
import { NextRequest, NextResponse } from 'next/server';
|
3
4
|
|
4
5
|
import { OIDCService } from '@/server/services/oidc';
|
5
|
-
import { getUserAuth } from '@/utils/server/auth';
|
6
|
-
import { correctOIDCUrl } from '@/utils/server/correctOIDCUrl';
|
7
6
|
|
8
7
|
const log = debug('lobe-oidc:consent');
|
9
8
|
|
@@ -2,11 +2,11 @@
|
|
2
2
|
import { getAuth } from '@clerk/nextjs/server';
|
3
3
|
import { LobeRuntimeAI, ModelRuntime } from '@lobechat/model-runtime';
|
4
4
|
import { ChatErrorType } from '@lobechat/types';
|
5
|
+
import { getXorPayload } from '@lobechat/utils/server';
|
5
6
|
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
6
7
|
|
7
8
|
import { checkAuthMethod } from '@/app/(backend)/middleware/auth/utils';
|
8
9
|
import { LOBE_CHAT_AUTH_HEADER, OAUTH_AUTHORIZED } from '@/const/auth';
|
9
|
-
import { getXorPayload } from '@/utils/server/xor';
|
10
10
|
|
11
11
|
import { POST } from './route';
|
12
12
|
|
@@ -18,7 +18,7 @@ vi.mock('@/app/(backend)/middleware/auth/utils', () => ({
|
|
18
18
|
checkAuthMethod: vi.fn(),
|
19
19
|
}));
|
20
20
|
|
21
|
-
vi.mock('
|
21
|
+
vi.mock('@lobechat/utils/server', () => ({
|
22
22
|
getXorPayload: vi.fn(),
|
23
23
|
}));
|
24
24
|
|
@@ -1,5 +1,6 @@
|
|
1
1
|
import { AgentRuntimeError } from '@lobechat/model-runtime';
|
2
2
|
import { ChatErrorType, ErrorType, TraceNameMap } from '@lobechat/types';
|
3
|
+
import { getXorPayload } from '@lobechat/utils/server';
|
3
4
|
import { PluginRequestPayload } from '@lobehub/chat-plugin-sdk';
|
4
5
|
import { createGatewayOnEdgeRuntime } from '@lobehub/chat-plugins-gateway';
|
5
6
|
|
@@ -8,7 +9,6 @@ import { LOBE_CHAT_TRACE_ID } from '@/const/trace';
|
|
8
9
|
import { getAppConfig } from '@/envs/app';
|
9
10
|
import { TraceClient } from '@/libs/traces';
|
10
11
|
import { createErrorResponse } from '@/utils/errorResponse';
|
11
|
-
import { getXorPayload } from '@/utils/server/xor';
|
12
12
|
import { getTracePayload } from '@/utils/trace';
|
13
13
|
|
14
14
|
import { parserPluginSettings } from './settings';
|
@@ -1,3 +1,4 @@
|
|
1
|
+
import { getUserAuth } from '@lobechat/utils/server';
|
1
2
|
import { notFound } from 'next/navigation';
|
2
3
|
import { Flexbox } from 'react-layout-kit';
|
3
4
|
|
@@ -5,7 +6,6 @@ import FileViewer from '@/features/FileViewer';
|
|
5
6
|
import { createCallerFactory } from '@/libs/trpc/lambda';
|
6
7
|
import { lambdaRouter } from '@/server/routers/lambda';
|
7
8
|
import { PagePropsWithId } from '@/types/next';
|
8
|
-
import { getUserAuth } from '@/utils/server/auth';
|
9
9
|
|
10
10
|
import FileDetail from '../features/FileDetail';
|
11
11
|
import Header from './Header';
|
@@ -1,10 +1,10 @@
|
|
1
|
+
import { gerServerDeviceInfo } from '@lobechat/utils/server';
|
1
2
|
import { notFound } from 'next/navigation';
|
2
3
|
|
3
4
|
import { serverFeatureFlags } from '@/config/featureFlags';
|
4
5
|
import { metadataModule } from '@/server/metadata';
|
5
6
|
import { translation } from '@/server/translation';
|
6
7
|
import { DynamicLayoutProps } from '@/types/next';
|
7
|
-
import { gerServerDeviceInfo } from '@/utils/server/responsive';
|
8
8
|
import { RouteVariants } from '@/utils/server/routeVariants';
|
9
9
|
|
10
10
|
import Page from './index';
|
@@ -1,6 +1,7 @@
|
|
1
1
|
'use client';
|
2
2
|
|
3
|
-
import { DEFAULT_REWRITE_QUERY } from '
|
3
|
+
import { DEFAULT_REWRITE_QUERY } from '@lobechat/prompts';
|
4
|
+
|
4
5
|
import { isServerMode } from '@/const/version';
|
5
6
|
import { featureFlagsSelectors, useServerConfigStore } from '@/store/serverConfig';
|
6
7
|
|
@@ -0,0 +1,32 @@
|
|
1
|
+
import { ActionIcon } from '@lobehub/ui';
|
2
|
+
import { Eye } from 'lucide-react';
|
3
|
+
import { memo, useState } from 'react';
|
4
|
+
import { useTranslation } from 'react-i18next';
|
5
|
+
|
6
|
+
import HtmlPreviewDrawer from './PreviewDrawer';
|
7
|
+
|
8
|
+
interface HtmlPreviewActionProps {
|
9
|
+
content: string;
|
10
|
+
size?: number;
|
11
|
+
}
|
12
|
+
|
13
|
+
const HtmlPreviewAction = memo<HtmlPreviewActionProps>(({ content, size }) => {
|
14
|
+
const { t } = useTranslation('components');
|
15
|
+
const [open, setOpen] = useState(false);
|
16
|
+
|
17
|
+
return (
|
18
|
+
<>
|
19
|
+
<ActionIcon
|
20
|
+
icon={Eye}
|
21
|
+
onClick={() => setOpen(true)}
|
22
|
+
size={size}
|
23
|
+
title={t('HtmlPreview.actions.preview')}
|
24
|
+
/>
|
25
|
+
<HtmlPreviewDrawer content={content} onClose={() => setOpen(false)} open={open} />
|
26
|
+
</>
|
27
|
+
);
|
28
|
+
});
|
29
|
+
|
30
|
+
HtmlPreviewAction.displayName = 'HtmlPreviewAction';
|
31
|
+
|
32
|
+
export default HtmlPreviewAction;
|
@@ -0,0 +1,133 @@
|
|
1
|
+
import { exportFile } from '@lobechat/utils/client';
|
2
|
+
import { Block, Button, Highlighter, Segmented } from '@lobehub/ui';
|
3
|
+
import { Drawer } from 'antd';
|
4
|
+
import { createStyles } from 'antd-style';
|
5
|
+
import { Code2, Download, Eye } from 'lucide-react';
|
6
|
+
import { memo, useCallback, useState } from 'react';
|
7
|
+
import { useTranslation } from 'react-i18next';
|
8
|
+
import { Flexbox } from 'react-layout-kit';
|
9
|
+
|
10
|
+
import { isDesktop } from '@/const/version';
|
11
|
+
import { TITLE_BAR_HEIGHT } from '@/features/ElectronTitlebar';
|
12
|
+
|
13
|
+
const useStyles = createStyles(({ css }) => ({
|
14
|
+
container: css`
|
15
|
+
height: 100%;
|
16
|
+
`,
|
17
|
+
iframe: css`
|
18
|
+
width: 100%;
|
19
|
+
height: 100%;
|
20
|
+
border: none;
|
21
|
+
`,
|
22
|
+
}));
|
23
|
+
|
24
|
+
interface HtmlPreviewDrawerProps {
|
25
|
+
content: string;
|
26
|
+
onClose: () => void;
|
27
|
+
open: boolean;
|
28
|
+
}
|
29
|
+
|
30
|
+
const HtmlPreviewDrawer = memo<HtmlPreviewDrawerProps>(({ content, open, onClose }) => {
|
31
|
+
const { styles } = useStyles();
|
32
|
+
const { t } = useTranslation('components');
|
33
|
+
const [mode, setMode] = useState<'preview' | 'code'>('preview');
|
34
|
+
|
35
|
+
const htmlContent = content;
|
36
|
+
|
37
|
+
const extractTitle = useCallback(() => {
|
38
|
+
const m = htmlContent.match(/<title>([\S\s]*?)<\/title>/i);
|
39
|
+
return m ? m[1].trim() : undefined;
|
40
|
+
}, [htmlContent]);
|
41
|
+
|
42
|
+
const sanitizeFileName = useCallback((name: string) => {
|
43
|
+
return name
|
44
|
+
.replaceAll(/["*/:<>?\\|]/g, '-')
|
45
|
+
.replaceAll(/\s+/g, ' ')
|
46
|
+
.trim()
|
47
|
+
.slice(0, 100);
|
48
|
+
}, []);
|
49
|
+
|
50
|
+
const onDownload = useCallback(() => {
|
51
|
+
const title = extractTitle();
|
52
|
+
const base = title ? sanitizeFileName(title) : `chat-html-preview-${Date.now()}`;
|
53
|
+
exportFile(content, `${base}.html`);
|
54
|
+
}, [content, extractTitle, sanitizeFileName]);
|
55
|
+
|
56
|
+
const Title = (
|
57
|
+
<Flexbox align={'center'} horizontal justify={'space-between'} style={{ width: '100%' }}>
|
58
|
+
{t('HtmlPreview.title')}
|
59
|
+
<Segmented
|
60
|
+
onChange={(v) => setMode(v as 'preview' | 'code')}
|
61
|
+
options={[
|
62
|
+
{
|
63
|
+
label: (
|
64
|
+
<Flexbox align={'center'} gap={6} horizontal>
|
65
|
+
<Eye size={16} />
|
66
|
+
{t('HtmlPreview.mode.preview')}
|
67
|
+
</Flexbox>
|
68
|
+
),
|
69
|
+
value: 'preview',
|
70
|
+
},
|
71
|
+
{
|
72
|
+
label: (
|
73
|
+
<Flexbox align={'center'} gap={6} horizontal>
|
74
|
+
<Code2 size={16} />
|
75
|
+
{t('HtmlPreview.mode.code')}
|
76
|
+
</Flexbox>
|
77
|
+
),
|
78
|
+
value: 'code',
|
79
|
+
},
|
80
|
+
]}
|
81
|
+
value={mode}
|
82
|
+
/>
|
83
|
+
<Button
|
84
|
+
color={'default'}
|
85
|
+
icon={<Download size={16} />}
|
86
|
+
onClick={onDownload}
|
87
|
+
variant={'filled'}
|
88
|
+
>
|
89
|
+
{t('HtmlPreview.actions.download')}
|
90
|
+
</Button>
|
91
|
+
</Flexbox>
|
92
|
+
);
|
93
|
+
|
94
|
+
return (
|
95
|
+
<Drawer
|
96
|
+
destroyOnHidden
|
97
|
+
height={isDesktop ? `calc(100vh - ${TITLE_BAR_HEIGHT}px)` : '100vh'}
|
98
|
+
onClose={onClose}
|
99
|
+
open={open}
|
100
|
+
placement="bottom"
|
101
|
+
styles={{
|
102
|
+
body: { height: '100%', padding: 0 },
|
103
|
+
header: { paddingBlock: 8, paddingInline: 12 },
|
104
|
+
}}
|
105
|
+
title={Title}
|
106
|
+
>
|
107
|
+
{mode === 'preview' ? (
|
108
|
+
<Block className={styles.container}>
|
109
|
+
<iframe
|
110
|
+
className={styles.iframe}
|
111
|
+
sandbox="allow-scripts allow-same-origin"
|
112
|
+
srcDoc={content}
|
113
|
+
title={t('HtmlPreview.iframeTitle')}
|
114
|
+
/>
|
115
|
+
</Block>
|
116
|
+
) : (
|
117
|
+
<Block className={styles.container}>
|
118
|
+
<Highlighter
|
119
|
+
language={'html'}
|
120
|
+
showLanguage={false}
|
121
|
+
style={{ height: '100%', overflow: 'auto' }}
|
122
|
+
>
|
123
|
+
{htmlContent}
|
124
|
+
</Highlighter>
|
125
|
+
</Block>
|
126
|
+
)}
|
127
|
+
</Drawer>
|
128
|
+
);
|
129
|
+
});
|
130
|
+
|
131
|
+
HtmlPreviewDrawer.displayName = 'HtmlPreviewDrawer';
|
132
|
+
|
133
|
+
export default HtmlPreviewDrawer;
|
@@ -1,3 +1,4 @@
|
|
1
|
+
import { CHAT_MODEL_IMAGE_GENERATION_PARAMS } from '@/const/image';
|
1
2
|
import { ModelParamsSchema } from '@/libs/standard-parameters';
|
2
3
|
import { AIChatModelCard, AIImageModelCard } from '@/types/aiModel';
|
3
4
|
|
@@ -194,21 +195,21 @@ const googleChatModels: AIChatModelCard[] = [
|
|
194
195
|
imageOutput: true,
|
195
196
|
vision: true,
|
196
197
|
},
|
197
|
-
contextWindowTokens: 32_768 +
|
198
|
+
contextWindowTokens: 32_768 + 8192,
|
198
199
|
description:
|
199
200
|
'Gemini 2.5 Flash Image Preview 是 Google 最新、最快、最高效的原生多模态模型,它允许您通过对话生成和编辑图像。',
|
200
201
|
displayName: 'Gemini 2.5 Flash Image Preview',
|
201
202
|
enabled: true,
|
202
203
|
id: 'gemini-2.5-flash-image-preview',
|
203
|
-
maxOutput:
|
204
|
+
maxOutput: 8192,
|
204
205
|
pricing: {
|
205
206
|
units: [
|
206
207
|
{ name: 'textInput', rate: 0.3, strategy: 'fixed', unit: 'millionTokens' },
|
207
208
|
{ name: 'textOutput', rate: 2.5, strategy: 'fixed', unit: 'millionTokens' },
|
208
|
-
{ name: 'imageOutput', rate:
|
209
|
+
{ name: 'imageOutput', rate: 30, strategy: 'fixed', unit: 'millionTokens' },
|
209
210
|
],
|
210
211
|
},
|
211
|
-
releasedAt: '2025-08-
|
212
|
+
releasedAt: '2025-08-26',
|
212
213
|
type: 'chat',
|
213
214
|
},
|
214
215
|
{
|
@@ -605,71 +606,90 @@ const imagenBaseParameters: ModelParamsSchema = {
|
|
605
606
|
prompt: { default: '' },
|
606
607
|
};
|
607
608
|
|
609
|
+
/* eslint-disable sort-keys-fix/sort-keys-fix */
|
608
610
|
const googleImageModels: AIImageModelCard[] = [
|
609
611
|
{
|
610
|
-
|
611
|
-
|
612
|
+
displayName: 'Gemini 2.5 Flash Image Preview',
|
613
|
+
id: 'gemini-2.5-flash-image-preview:image',
|
612
614
|
enabled: true,
|
615
|
+
type: 'image',
|
616
|
+
description:
|
617
|
+
'Gemini 2.5 Flash Image Preview 是 Google 最新、最快、最高效的原生多模态模型,它允许您通过对话生成和编辑图像。',
|
618
|
+
releasedAt: '2025-08-26',
|
619
|
+
parameters: CHAT_MODEL_IMAGE_GENERATION_PARAMS,
|
620
|
+
pricing: {
|
621
|
+
units: [
|
622
|
+
{ name: 'textInput', rate: 0.3, strategy: 'fixed', unit: 'millionTokens' },
|
623
|
+
{ name: 'textOutput', rate: 2.5, strategy: 'fixed', unit: 'millionTokens' },
|
624
|
+
{ name: 'imageOutput', rate: 3, strategy: 'fixed', unit: 'millionTokens' },
|
625
|
+
],
|
626
|
+
},
|
627
|
+
},
|
628
|
+
{
|
629
|
+
displayName: 'Imagen 4',
|
613
630
|
id: 'imagen-4.0-generate-001',
|
631
|
+
enabled: true,
|
632
|
+
type: 'image',
|
633
|
+
description: 'Imagen 4th generation text-to-image model series',
|
614
634
|
organization: 'Deepmind',
|
635
|
+
releasedAt: '2025-08-15',
|
615
636
|
parameters: imagenBaseParameters,
|
616
637
|
pricing: {
|
617
638
|
units: [{ name: 'imageGeneration', rate: 0.04, strategy: 'fixed', unit: 'image' }],
|
618
639
|
},
|
619
|
-
releasedAt: '2024-08-14',
|
620
|
-
type: 'image',
|
621
640
|
},
|
622
641
|
{
|
623
|
-
description: 'Imagen 4th generation text-to-image model series Ultra version',
|
624
642
|
displayName: 'Imagen 4 Ultra',
|
625
|
-
enabled: true,
|
626
643
|
id: 'imagen-4.0-ultra-generate-001',
|
644
|
+
enabled: true,
|
645
|
+
type: 'image',
|
646
|
+
description: 'Imagen 4th generation text-to-image model series Ultra version',
|
627
647
|
organization: 'Deepmind',
|
648
|
+
releasedAt: '2025-08-15',
|
628
649
|
parameters: imagenBaseParameters,
|
629
650
|
pricing: {
|
630
651
|
units: [{ name: 'imageGeneration', rate: 0.06, strategy: 'fixed', unit: 'image' }],
|
631
652
|
},
|
632
|
-
releasedAt: '2024-08-14',
|
633
|
-
type: 'image',
|
634
653
|
},
|
635
654
|
{
|
636
|
-
description: 'Imagen 4th generation text-to-image model series Fast version',
|
637
655
|
displayName: 'Imagen 4 Fast',
|
638
|
-
enabled: true,
|
639
656
|
id: 'imagen-4.0-fast-generate-001',
|
657
|
+
enabled: true,
|
658
|
+
type: 'image',
|
659
|
+
description: 'Imagen 4th generation text-to-image model series Fast version',
|
640
660
|
organization: 'Deepmind',
|
661
|
+
releasedAt: '2025-08-15',
|
641
662
|
parameters: imagenBaseParameters,
|
642
663
|
pricing: {
|
643
664
|
units: [{ name: 'imageGeneration', rate: 0.02, strategy: 'fixed', unit: 'image' }],
|
644
665
|
},
|
645
|
-
releasedAt: '2024-08-14',
|
646
|
-
type: 'image',
|
647
666
|
},
|
648
667
|
{
|
649
|
-
description: 'Imagen 4th generation text-to-image model series',
|
650
668
|
displayName: 'Imagen 4 Preview 06-06',
|
651
669
|
id: 'imagen-4.0-generate-preview-06-06',
|
670
|
+
type: 'image',
|
671
|
+
description: 'Imagen 4th generation text-to-image model series',
|
652
672
|
organization: 'Deepmind',
|
673
|
+
releasedAt: '2024-06-06',
|
653
674
|
parameters: imagenBaseParameters,
|
654
675
|
pricing: {
|
655
676
|
units: [{ name: 'imageGeneration', rate: 0.04, strategy: 'fixed', unit: 'image' }],
|
656
677
|
},
|
657
|
-
releasedAt: '2024-06-06',
|
658
|
-
type: 'image',
|
659
678
|
},
|
660
679
|
{
|
661
|
-
description: 'Imagen 4th generation text-to-image model series Ultra version',
|
662
680
|
displayName: 'Imagen 4 Ultra Preview 06-06',
|
663
681
|
id: 'imagen-4.0-ultra-generate-preview-06-06',
|
682
|
+
type: 'image',
|
683
|
+
description: 'Imagen 4th generation text-to-image model series Ultra version',
|
664
684
|
organization: 'Deepmind',
|
685
|
+
releasedAt: '2025-06-11',
|
665
686
|
parameters: imagenBaseParameters,
|
666
687
|
pricing: {
|
667
688
|
units: [{ name: 'imageGeneration', rate: 0.06, strategy: 'fixed', unit: 'image' }],
|
668
689
|
},
|
669
|
-
releasedAt: '2024-06-06',
|
670
|
-
type: 'image',
|
671
690
|
},
|
672
691
|
];
|
692
|
+
/* eslint-enable sort-keys-fix/sort-keys-fix */
|
673
693
|
|
674
694
|
export const allModels = [...googleChatModels, ...googleImageModels];
|
675
695
|
|