@lobehub/lobehub 2.0.0-next.3 → 2.0.0-next.5

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 (55) hide show
  1. package/CHANGELOG.md +58 -0
  2. package/changelog/v1.json +18 -0
  3. package/docs/development/database-schema.dbml +11 -1
  4. package/docs/self-hosting/advanced/online-search.mdx +30 -25
  5. package/docs/self-hosting/advanced/online-search.zh-CN.mdx +25 -23
  6. package/locales/ar/models.json +9 -0
  7. package/locales/bg-BG/models.json +9 -0
  8. package/locales/de-DE/models.json +9 -0
  9. package/locales/en-US/models.json +9 -0
  10. package/locales/es-ES/models.json +9 -0
  11. package/locales/fa-IR/models.json +9 -0
  12. package/locales/fr-FR/models.json +9 -0
  13. package/locales/it-IT/models.json +9 -0
  14. package/locales/ja-JP/models.json +9 -0
  15. package/locales/ko-KR/models.json +9 -0
  16. package/locales/nl-NL/models.json +9 -0
  17. package/locales/pl-PL/models.json +9 -0
  18. package/locales/pt-BR/models.json +9 -0
  19. package/locales/ru-RU/models.json +9 -0
  20. package/locales/tr-TR/models.json +9 -0
  21. package/locales/vi-VN/models.json +9 -0
  22. package/locales/zh-CN/models.json +9 -0
  23. package/locales/zh-TW/models.json +9 -0
  24. package/package.json +1 -1
  25. package/packages/database/migrations/0041_improve_index.sql +10 -0
  26. package/packages/database/migrations/meta/0041_snapshot.json +7784 -0
  27. package/packages/database/migrations/meta/_journal.json +7 -0
  28. package/packages/database/src/core/migrations.json +17 -0
  29. package/packages/database/src/models/session.ts +60 -19
  30. package/packages/database/src/schemas/agent.ts +10 -11
  31. package/packages/database/src/schemas/message.ts +5 -1
  32. package/packages/database/src/schemas/relations.ts +6 -4
  33. package/packages/database/src/schemas/session.ts +2 -0
  34. package/packages/database/src/schemas/topic.ts +6 -1
  35. package/packages/model-bank/src/aiModels/anthropic.ts +0 -63
  36. package/packages/model-bank/src/aiModels/higress.ts +0 -55
  37. package/packages/model-bank/src/aiModels/infiniai.ts +21 -0
  38. package/packages/model-bank/src/aiModels/ollamacloud.ts +13 -0
  39. package/packages/model-bank/src/aiModels/siliconcloud.ts +19 -0
  40. package/packages/model-runtime/src/core/streams/openai/__snapshots__/responsesStream.test.ts.snap +0 -38
  41. package/packages/model-runtime/src/providers/minimax/index.ts +5 -5
  42. package/packages/model-runtime/src/providers/search1api/index.test.ts +2 -2
  43. package/packages/web-crawler/src/crawImpl/firecrawl.ts +39 -12
  44. package/scripts/migrateServerDB/index.ts +2 -1
  45. package/src/config/modelProviders/anthropic.ts +0 -23
  46. package/src/config/modelProviders/higress.ts +0 -23
  47. package/src/config/modelProviders/minimax.ts +1 -1
  48. package/src/config/modelProviders/qiniu.ts +1 -1
  49. package/src/libs/next-auth/sso-providers/index.ts +0 -2
  50. package/src/libs/oidc-provider/provider.ts +1 -1
  51. package/src/server/routers/lambda/session.ts +8 -5
  52. package/src/server/services/search/impls/firecrawl/index.ts +51 -11
  53. package/src/server/services/search/impls/firecrawl/type.ts +60 -9
  54. package/src/services/user/client.test.ts +4 -1
  55. package/src/libs/next-auth/sso-providers/azure-ad.ts +0 -33
@@ -48,29 +48,6 @@ const Anthropic: ModelProviderCard = {
48
48
  maxOutput: 8192,
49
49
  releasedAt: '2024-11-05',
50
50
  },
51
- {
52
- contextWindowTokens: 200_000,
53
- description:
54
- 'Claude 3.5 Sonnet 提供了超越 Opus 的能力和比 Sonnet 更快的速度,同时保持与 Sonnet 相同的价格。Sonnet 特别擅长编程、数据科学、视觉处理、代理任务。',
55
- displayName: 'Claude 3.5 Sonnet',
56
- enabled: true,
57
- functionCall: true,
58
- id: 'claude-3-5-sonnet-20241022',
59
- maxOutput: 8192,
60
- releasedAt: '2024-10-22',
61
- vision: true,
62
- },
63
- {
64
- contextWindowTokens: 200_000,
65
- description:
66
- 'Claude 3.5 Sonnet 提供了超越 Opus 的能力和比 Sonnet 更快的速度,同时保持与 Sonnet 相同的价格。Sonnet 特别擅长编程、数据科学、视觉处理、代理任务。',
67
- displayName: 'Claude 3.5 Sonnet 0620',
68
- functionCall: true,
69
- id: 'claude-3-5-sonnet-20240620',
70
- maxOutput: 8192,
71
- releasedAt: '2024-06-20',
72
- vision: true,
73
- },
74
51
  {
75
52
  contextWindowTokens: 200_000,
76
53
  description:
@@ -1298,29 +1298,6 @@ const Higress: ModelProviderCard = {
1298
1298
  maxOutput: 8192,
1299
1299
  releasedAt: '2024-11-05',
1300
1300
  },
1301
- {
1302
- contextWindowTokens: 200_000,
1303
- description:
1304
- 'Claude 3.5 Sonnet 提供了超越 Opus 的能力和比 Sonnet 更快的速度,同时保持与 Sonnet 相同的价格。Sonnet 特别擅长编程、数据科学、视觉处理、代理任务。',
1305
- displayName: 'Claude 3.5 Sonnet',
1306
- enabled: true,
1307
- functionCall: true,
1308
- id: 'claude-3-5-sonnet-20241022',
1309
- maxOutput: 8192,
1310
- releasedAt: '2024-10-22',
1311
- vision: true,
1312
- },
1313
- {
1314
- contextWindowTokens: 200_000,
1315
- description:
1316
- 'Claude 3.5 Sonnet 提供了超越 Opus 的能力和比 Sonnet 更快的速度,同时保持与 Sonnet 相同的价格。Sonnet 特别擅长编程、数据科学、视觉处理、代理任务。',
1317
- displayName: 'Claude 3.5 Sonnet 0620',
1318
- functionCall: true,
1319
- id: 'claude-3-5-sonnet-20240620',
1320
- maxOutput: 8192,
1321
- releasedAt: '2024-06-20',
1322
- vision: true,
1323
- },
1324
1301
  {
1325
1302
  contextWindowTokens: 200_000,
1326
1303
  description:
@@ -12,7 +12,7 @@ const Minimax: ModelProviderCard = {
12
12
  settings: {
13
13
  disableBrowserRequest: true, // CORS error
14
14
  proxyUrl: {
15
- placeholder: 'https://api.minimax.chat/v1',
15
+ placeholder: 'https://api.minimaxi.com/v1',
16
16
  },
17
17
  responseAnimation: {
18
18
  speed: 2,
@@ -28,7 +28,7 @@ const Qiniu: ModelProviderCard = {
28
28
  name: 'Qiniu',
29
29
  settings: {
30
30
  proxyUrl: {
31
- placeholder: 'https://api.qnaigc.com/v1',
31
+ placeholder: 'https://openai.qiniu.com/v1',
32
32
  },
33
33
  sdkType: 'openai',
34
34
  showModelFetcher: true,
@@ -1,7 +1,6 @@
1
1
  import Auth0 from './auth0';
2
2
  import Authelia from './authelia';
3
3
  import Authentik from './authentik';
4
- import AzureAD from './azure-ad';
5
4
  import Casdoor from './casdoor';
6
5
  import CloudflareZeroTrust from './cloudflare-zero-trust';
7
6
  import Cognito from './cognito';
@@ -19,7 +18,6 @@ import Zitadel from './zitadel';
19
18
  export const ssoProviders = [
20
19
  Auth0,
21
20
  Authentik,
22
- AzureAD,
23
21
  GenericOIDC,
24
22
  Github,
25
23
  Zitadel,
@@ -340,7 +340,7 @@ export const createOIDCProvider = async (db: LobeChatDatabase): Promise<Provider
340
340
 
341
341
  // 8. 令牌有效期
342
342
  ttl: {
343
- AccessToken: 25 * 3600, // 25 hour
343
+ AccessToken: 7 * 24 * 3600, // 7 days
344
344
  AuthorizationCode: 600, // 10 minutes
345
345
  DeviceCode: 600, // 10 minutes (if enabled)
346
346
 
@@ -97,14 +97,17 @@ export const sessionRouter = router({
97
97
  }),
98
98
 
99
99
  getGroupedSessions: publicProcedure.query(async ({ ctx }): Promise<ChatSessionList> => {
100
- if (!ctx.userId) return { sessionGroups: [], sessions: [] };
100
+ const userId = ctx.userId;
101
+ if (!userId) return { sessionGroups: [], sessions: [] };
101
102
 
102
103
  const serverDB = await getServerDB();
103
- const sessionModel = new SessionModel(serverDB, ctx.userId!);
104
- const chatGroupModel = new ChatGroupModel(serverDB, ctx.userId!);
104
+ const sessionModel = new SessionModel(serverDB, userId);
105
+ const chatGroupModel = new ChatGroupModel(serverDB, userId);
105
106
 
106
- const { sessions, sessionGroups } = await sessionModel.queryWithGroups();
107
- const chatGroups = await chatGroupModel.queryWithMemberDetails();
107
+ const [{ sessions, sessionGroups }, chatGroups] = await Promise.all([
108
+ sessionModel.queryWithGroups(),
109
+ chatGroupModel.queryWithMemberDetails(),
110
+ ]);
108
111
 
109
112
  const groupSessions: LobeGroupSession[] = chatGroups.map((group) => {
110
113
  const { title, description, avatar, backgroundColor, groupId, ...rest } = group;
@@ -26,7 +26,7 @@ export class FirecrawlImpl implements SearchServiceImpl {
26
26
 
27
27
  private get baseUrl(): string {
28
28
  // Assuming the base URL is consistent with the crawl endpoint
29
- return process.env.FIRECRAWL_URL || 'https://api.firecrawl.dev/v1';
29
+ return process.env.FIRECRAWL_URL || 'https://api.firecrawl.dev/v2';
30
30
  }
31
31
 
32
32
  async query(query: string, params: SearchParams = {}): Promise<UniformSearchResponse> {
@@ -34,13 +34,14 @@ export class FirecrawlImpl implements SearchServiceImpl {
34
34
  const endpoint = urlJoin(this.baseUrl, '/search');
35
35
 
36
36
  const defaultQueryParams: FirecrawlSearchParameters = {
37
- limit: 15,
37
+ limit: 20,
38
38
  query,
39
39
  /*
40
40
  scrapeOptions: {
41
41
  formats: ["markdown"]
42
42
  },
43
43
  */
44
+ sources: [{ type: 'web' }, { type: 'news' }],
44
45
  };
45
46
 
46
47
  let body: FirecrawlSearchParameters = {
@@ -95,25 +96,64 @@ export class FirecrawlImpl implements SearchServiceImpl {
95
96
 
96
97
  log('Parsed Firecrawl response: %o', firecrawlResponse);
97
98
 
98
- const mappedResults = (firecrawlResponse.data || []).map(
99
+ // V2 API returns data as object with web/images/news arrays
100
+ const webResults = firecrawlResponse.data.web || [];
101
+ const imageResults = firecrawlResponse.data.images || [];
102
+ const newsResults = firecrawlResponse.data.news || [];
103
+
104
+ // Map web results
105
+ const mappedWebResults = webResults.map(
106
+ (result): UniformSearchResult => ({
107
+ category: 'general',
108
+ content: result.description || result.markdown || '',
109
+ engines: ['firecrawl'],
110
+ parsedUrl: result.url ? new URL(result.url).hostname : '',
111
+ score: 1,
112
+ title: result.title || '',
113
+ url: result.url,
114
+ }),
115
+ );
116
+
117
+ // Map news results
118
+ const mappedNewsResults = newsResults.map(
99
119
  (result): UniformSearchResult => ({
100
- category: 'general', // Default category
101
- content: result.description || '', // Prioritize content, fallback to snippet
102
- engines: ['firecrawl'], // Use 'firecrawl' as the engine name
103
- parsedUrl: result.url ? new URL(result.url).hostname : '', // Basic URL parsing
104
- score: 1, // Default score to 1
120
+ category: 'news',
121
+ content: result.snippet || result.markdown || '',
122
+ engines: ['firecrawl'],
123
+ parsedUrl: result.url ? new URL(result.url).hostname : '',
124
+ score: 1,
105
125
  title: result.title || '',
106
126
  url: result.url,
107
127
  }),
108
128
  );
109
129
 
110
- log('Mapped %d results to SearchResult format', mappedResults.length);
130
+ // Map image results
131
+ const mappedImageResults = imageResults.map(
132
+ (result): UniformSearchResult => ({
133
+ category: 'images',
134
+ content: result.title || '',
135
+ engines: ['firecrawl'],
136
+ parsedUrl: result.url ? new URL(result.url).hostname : '',
137
+ score: 1,
138
+ title: result.title || '',
139
+ url: result.imageUrl, // Use imageUrl for images
140
+ }),
141
+ );
142
+
143
+ // Combine all results
144
+ const allResults = [...mappedWebResults, ...mappedNewsResults, ...mappedImageResults];
145
+
146
+ log('Mapped %d results to SearchResult format', allResults.length);
147
+
148
+ if (firecrawlResponse.warning) {
149
+ log.extend('warn')('Firecrawl warning: %s', firecrawlResponse.warning);
150
+ }
111
151
 
112
152
  return {
113
153
  costTime,
114
154
  query: query,
115
- resultNumbers: mappedResults.length,
116
- results: mappedResults,
155
+ resultNumbers: allResults.length,
156
+ results: allResults,
117
157
  };
118
158
  } catch (error) {
119
159
  log.extend('error')('Error parsing Firecrawl response: %o', error);
@@ -1,35 +1,86 @@
1
+ // V2 API Types
1
2
  interface FirecrawlScrapeOptions {
2
- formats: string[];
3
+ blockAds?: boolean;
4
+ formats?: string[];
5
+ maxAge?: number;
6
+ onlyMainContent?: boolean;
7
+ removeBase64Images?: boolean;
3
8
  }
4
9
 
10
+ type FirecrawlSource =
11
+ | { location?: string; tbs?: string; type: 'web' }
12
+ | { type: 'images' }
13
+ | { type: 'news' };
14
+
15
+ type FirecrawlCategory = { type: 'github' } | { type: 'research' } | { type: 'pdf' };
16
+
5
17
  export interface FirecrawlSearchParameters {
18
+ categories?: FirecrawlCategory[];
6
19
  country?: string;
7
- lang?: string;
20
+ ignoreInvalidURLs?: boolean;
8
21
  limit?: number;
22
+ location?: string;
9
23
  query: string;
10
24
  scrapeOptions?: FirecrawlScrapeOptions;
25
+ sources?: FirecrawlSource[];
11
26
  tbs?: string;
12
27
  timeout?: number;
13
28
  }
14
29
 
15
30
  interface FirecrawlMetadata {
16
31
  description?: string;
32
+ error?: string | null;
17
33
  sourceURL?: string;
18
34
  statusCode?: number;
35
+ title?: string;
36
+ }
37
+
38
+ // Web search result
39
+ interface FirecrawlWebResult {
40
+ description: string;
41
+ html?: string | null;
42
+ links?: string[];
43
+ markdown?: string | null;
44
+ metadata?: FirecrawlMetadata;
45
+ rawHtml?: string | null;
46
+ screenshot?: string | null;
19
47
  title: string;
48
+ url: string;
20
49
  }
21
50
 
22
- interface FirecrawlData {
23
- description?: string;
24
- html?: string;
51
+ // Image search result
52
+ interface FirecrawlImageResult {
53
+ imageHeight: number;
54
+ imageUrl: string;
55
+ imageWidth: number;
56
+ position: number;
57
+ title: string;
58
+ url: string;
59
+ }
60
+
61
+ // News search result
62
+ interface FirecrawlNewsResult {
63
+ date: string;
64
+ html?: string | null;
65
+ imageUrl?: string;
25
66
  links?: string[];
26
- markdown?: string;
67
+ markdown?: string | null;
27
68
  metadata?: FirecrawlMetadata;
28
- title?: string;
69
+ position: number;
70
+ rawHtml?: string | null;
71
+ screenshot?: string | null;
72
+ snippet: string;
73
+ title: string;
29
74
  url: string;
30
75
  }
31
76
 
77
+ // V2 Response structure
32
78
  export interface FirecrawlResponse {
33
- data: FirecrawlData[];
34
- success?: boolean;
79
+ data: {
80
+ images?: FirecrawlImageResult[];
81
+ news?: FirecrawlNewsResult[];
82
+ web?: FirecrawlWebResult[];
83
+ };
84
+ success: boolean;
85
+ warning?: string | null;
35
86
  }
@@ -26,7 +26,10 @@ beforeEach(async () => {
26
26
  await initializeDB();
27
27
  await clientDB.delete(users);
28
28
 
29
- await clientDB.insert(users).values({ id: mockUser.uuid, avatar: 'avatar.png' });
29
+ await clientDB
30
+ .insert(users)
31
+ .values({ id: mockUser.uuid, avatar: 'avatar.png' })
32
+ .onConflictDoNothing();
30
33
  await clientDB
31
34
  .insert(userSettings)
32
35
  .values({ id: mockUser.uuid, general: { themeMode: 'light' } });
@@ -1,33 +0,0 @@
1
- import AzureAD from 'next-auth/providers/azure-ad';
2
-
3
- import { authEnv } from '@/envs/auth';
4
-
5
- import { getMicrosoftEntraIdIssuer } from './microsoft-entra-id-helper';
6
- import { CommonProviderConfig } from './sso.config';
7
-
8
- const provider = {
9
- id: 'azure-ad',
10
- provider: AzureAD({
11
- ...CommonProviderConfig,
12
- // Specify auth scope, at least include 'openid email'
13
- // all scopes in Azure AD ref: https://learn.microsoft.com/en-us/entra/identity-platform/scopes-oidc#openid-connect-scopes
14
- authorization: { params: { scope: 'openid email profile' } },
15
- // TODO(NextAuth ENVs Migration): Remove once nextauth envs migration time end
16
- clientId: authEnv.AZURE_AD_CLIENT_ID ?? process.env.AUTH_AZURE_AD_ID,
17
- clientSecret: authEnv.AZURE_AD_CLIENT_SECRET ?? process.env.AUTH_AZURE_AD_SECRET,
18
- issuer: getMicrosoftEntraIdIssuer(),
19
- // Remove end
20
- // TODO(NextAuth): map unique user id to `providerAccountId` field
21
- // profile(profile) {
22
- // return {
23
- // email: profile.email,
24
- // image: profile.picture,
25
- // name: profile.name,
26
- // providerAccountId: profile.user_id,
27
- // id: profile.user_id,
28
- // };
29
- // },
30
- }),
31
- };
32
-
33
- export default provider;