@lobehub/lobehub 2.0.0-next.7 → 2.0.0-next.9

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 (127) hide show
  1. package/.github/workflows/desktop-pr-build.yml +8 -8
  2. package/.github/workflows/docker.yml +17 -16
  3. package/.github/workflows/e2e.yml +3 -3
  4. package/.github/workflows/release-desktop-beta.yml +8 -8
  5. package/.github/workflows/release.yml +1 -1
  6. package/.github/workflows/test.yml +4 -4
  7. package/CHANGELOG.md +50 -0
  8. package/changelog/v1.json +18 -0
  9. package/locales/ar/models.json +6 -6
  10. package/locales/bg-BG/models.json +6 -6
  11. package/locales/de-DE/models.json +6 -6
  12. package/locales/en-US/models.json +6 -6
  13. package/locales/es-ES/models.json +6 -6
  14. package/locales/fa-IR/models.json +6 -6
  15. package/locales/fr-FR/models.json +6 -6
  16. package/locales/it-IT/models.json +6 -6
  17. package/locales/ja-JP/models.json +6 -6
  18. package/locales/ko-KR/models.json +6 -6
  19. package/locales/nl-NL/models.json +6 -6
  20. package/locales/pl-PL/models.json +6 -6
  21. package/locales/pt-BR/models.json +6 -6
  22. package/locales/ru-RU/models.json +6 -6
  23. package/locales/tr-TR/models.json +6 -6
  24. package/locales/vi-VN/models.json +6 -6
  25. package/locales/zh-CN/models.json +6 -6
  26. package/locales/zh-TW/models.json +6 -6
  27. package/package.json +1 -1
  28. package/packages/const/src/index.ts +0 -1
  29. package/packages/const/src/url.ts +1 -4
  30. package/packages/context-engine/src/index.ts +1 -6
  31. package/packages/context-engine/src/processors/GroupMessageFlatten.ts +12 -2
  32. package/packages/context-engine/src/processors/__tests__/GroupMessageFlatten.test.ts +73 -9
  33. package/packages/context-engine/src/providers/index.ts +0 -2
  34. package/packages/database/package.json +1 -1
  35. package/packages/database/src/models/__tests__/message.grouping.test.ts +812 -0
  36. package/packages/database/src/models/__tests__/message.test.ts +322 -170
  37. package/packages/database/src/models/message.ts +62 -24
  38. package/packages/database/src/utils/__tests__/groupMessages.test.ts +145 -2
  39. package/packages/database/src/utils/groupMessages.ts +7 -5
  40. package/packages/types/src/message/common/base.ts +13 -0
  41. package/packages/types/src/message/common/image.ts +8 -0
  42. package/packages/types/src/message/common/metadata.ts +39 -0
  43. package/packages/types/src/message/common/tools.ts +10 -0
  44. package/packages/types/src/message/db/params.ts +47 -1
  45. package/packages/types/src/message/ui/chat.ts +4 -1
  46. package/packages/types/src/search.ts +16 -0
  47. package/src/app/[variants]/(main)/chat/(workspace)/@conversation/features/ChatInput/V1Mobile/index.tsx +2 -2
  48. package/src/app/[variants]/(main)/chat/(workspace)/@conversation/features/ChatInput/V1Mobile/useSend.ts +6 -4
  49. package/src/app/[variants]/(main)/chat/(workspace)/@conversation/features/ChatInput/useSend.ts +15 -10
  50. package/src/app/[variants]/(main)/chat/@session/features/SessionListContent/List/Item/index.tsx +4 -2
  51. package/src/components/Thinking/index.tsx +4 -3
  52. package/src/features/AgentSetting/AgentPlugin/index.tsx +2 -2
  53. package/src/features/ChatInput/ActionBar/STT/browser.tsx +2 -2
  54. package/src/features/ChatInput/ActionBar/STT/openai.tsx +2 -2
  55. package/src/features/ChatInput/ActionBar/Tools/useControls.tsx +1 -3
  56. package/src/features/Conversation/Error/ErrorJsonViewer.tsx +4 -3
  57. package/src/features/Conversation/Error/OllamaBizError/index.tsx +7 -2
  58. package/src/features/Conversation/Error/index.tsx +15 -5
  59. package/src/features/Conversation/MarkdownElements/LobeArtifact/Render/index.tsx +2 -2
  60. package/src/features/Conversation/Messages/Assistant/Extra/index.tsx +2 -2
  61. package/src/features/Conversation/Messages/Assistant/MessageContent.tsx +5 -3
  62. package/src/features/Conversation/Messages/Assistant/Tool/Inspector/BuiltinPluginTitle.tsx +2 -2
  63. package/src/features/Conversation/Messages/Assistant/Tool/Inspector/ToolTitle.tsx +4 -2
  64. package/src/features/Conversation/Messages/Assistant/Tool/Render/CustomRender.tsx +2 -2
  65. package/src/features/Conversation/Messages/Assistant/Tool/Render/index.tsx +2 -2
  66. package/src/features/Conversation/Messages/Assistant/Tool/index.tsx +2 -2
  67. package/src/features/Conversation/Messages/Assistant/index.tsx +4 -4
  68. package/src/features/Conversation/Messages/Default.tsx +2 -2
  69. package/src/features/Conversation/Messages/User/Extra.tsx +2 -2
  70. package/src/features/Conversation/Messages/User/index.tsx +4 -4
  71. package/src/features/Conversation/Messages/index.tsx +3 -3
  72. package/src/features/Conversation/components/AutoScroll.tsx +2 -2
  73. package/src/features/Conversation/components/Extras/Usage/UsageDetail/index.tsx +9 -6
  74. package/src/features/PluginTag/index.tsx +1 -3
  75. package/src/features/PluginsUI/Render/BuiltinType/index.test.tsx +37 -28
  76. package/src/features/Portal/Artifacts/Body/index.tsx +2 -2
  77. package/src/server/modules/ModelRuntime/trace.ts +11 -4
  78. package/src/server/routers/lambda/message.ts +14 -3
  79. package/src/services/chat/chat.test.ts +1 -40
  80. package/src/services/chat/contextEngineering.test.ts +0 -30
  81. package/src/services/chat/contextEngineering.ts +1 -12
  82. package/src/services/chat/index.ts +2 -7
  83. package/src/services/chat/types.ts +1 -1
  84. package/src/services/message/_deprecated.ts +1 -1
  85. package/src/services/message/client.ts +8 -2
  86. package/src/services/message/server.ts +7 -2
  87. package/src/services/message/type.ts +6 -1
  88. package/src/store/chat/helpers.test.ts +99 -0
  89. package/src/store/chat/helpers.ts +21 -2
  90. package/src/store/chat/selectors.ts +1 -1
  91. package/src/store/chat/slices/aiChat/actions/generateAIChat.ts +3 -3
  92. package/src/store/chat/slices/builtinTool/actions/index.ts +1 -4
  93. package/src/store/chat/slices/message/action.test.ts +5 -1
  94. package/src/store/chat/slices/message/action.ts +102 -14
  95. package/src/store/chat/slices/message/reducer.test.ts +363 -5
  96. package/src/store/chat/slices/message/reducer.ts +87 -3
  97. package/src/store/chat/slices/message/{selectors.test.ts → selectors/chat.test.ts} +266 -30
  98. package/src/store/chat/slices/message/{selectors.ts → selectors/chat.ts} +29 -79
  99. package/src/store/chat/slices/message/selectors/index.ts +2 -0
  100. package/src/store/chat/slices/message/selectors/messageState.test.ts +36 -0
  101. package/src/store/chat/slices/message/selectors/messageState.ts +80 -0
  102. package/src/store/chat/slices/plugin/action.test.ts +34 -132
  103. package/src/store/chat/slices/plugin/action.ts +1 -44
  104. package/src/store/tool/selectors/tool.test.ts +1 -1
  105. package/src/store/tool/selectors/tool.ts +6 -8
  106. package/src/store/tool/slices/builtin/action.test.ts +83 -35
  107. package/src/store/tool/slices/builtin/action.ts +0 -9
  108. package/src/store/tool/slices/builtin/selectors.test.ts +4 -30
  109. package/src/store/tool/slices/builtin/selectors.ts +15 -21
  110. package/src/tools/index.ts +0 -6
  111. package/src/tools/renders.ts +0 -3
  112. package/src/tools/web-browsing/Portal/Search/Footer.tsx +2 -2
  113. package/packages/const/src/guide.ts +0 -89
  114. package/packages/context-engine/src/providers/InboxGuide.ts +0 -102
  115. package/packages/context-engine/src/providers/__tests__/InboxGuideProvider.test.ts +0 -121
  116. package/src/services/chat/__snapshots__/chat.test.ts.snap +0 -110
  117. package/src/store/chat/slices/builtinTool/actions/__tests__/dalle.test.ts +0 -121
  118. package/src/store/chat/slices/builtinTool/actions/dalle.ts +0 -124
  119. package/src/tools/dalle/Render/GalleyGrid.tsx +0 -60
  120. package/src/tools/dalle/Render/Item/EditMode.tsx +0 -66
  121. package/src/tools/dalle/Render/Item/Error.tsx +0 -49
  122. package/src/tools/dalle/Render/Item/Image.tsx +0 -44
  123. package/src/tools/dalle/Render/Item/ImageFileItem.tsx +0 -57
  124. package/src/tools/dalle/Render/Item/index.tsx +0 -88
  125. package/src/tools/dalle/Render/ToolBar.tsx +0 -56
  126. package/src/tools/dalle/Render/index.tsx +0 -52
  127. package/src/tools/dalle/index.ts +0 -92
@@ -1,124 +0,0 @@
1
- import { produce } from 'immer';
2
- import pMap from 'p-map';
3
- import { SWRResponse } from 'swr';
4
- import { StateCreator } from 'zustand/vanilla';
5
-
6
- import { useClientDataSWR } from '@/libs/swr';
7
- import { fileService } from '@/services/file';
8
- import { imageGenerationService } from '@/services/textToImage';
9
- import { uploadService } from '@/services/upload';
10
- import { chatSelectors } from '@/store/chat/selectors';
11
- import { ChatStore } from '@/store/chat/store';
12
- import { useFileStore } from '@/store/file';
13
- import { DallEImageItem } from '@/types/tool/dalle';
14
- import { setNamespace } from '@/utils/storeDebug';
15
-
16
- const n = setNamespace('tool');
17
-
18
- const SWR_FETCH_KEY = 'FetchImageItem';
19
-
20
- export interface ChatDallEAction {
21
- generateImageFromPrompts: (items: DallEImageItem[], id: string) => Promise<void>;
22
- text2image: (id: string, data: DallEImageItem[]) => Promise<void>;
23
- toggleDallEImageLoading: (key: string, value: boolean) => void;
24
- updateImageItem: (id: string, updater: (data: DallEImageItem[]) => void) => Promise<void>;
25
- useFetchDalleImageItem: (id: string) => SWRResponse;
26
- }
27
-
28
- export const dalleSlice: StateCreator<
29
- ChatStore,
30
- [['zustand/devtools', never]],
31
- [],
32
- ChatDallEAction
33
- > = (set, get) => ({
34
- generateImageFromPrompts: async (items, messageId) => {
35
- const { toggleDallEImageLoading, updateImageItem } = get();
36
- // eslint-disable-next-line unicorn/consistent-function-scoping
37
- const getMessageById = (id: string) => chatSelectors.getMessageById(id)(get());
38
-
39
- const message = getMessageById(messageId);
40
- if (!message) return;
41
-
42
- const parent = getMessageById(message!.parentId!);
43
- const originPrompt = parent?.content;
44
- let errorArray: any[] = [];
45
-
46
- await pMap(items, async (params, index) => {
47
- toggleDallEImageLoading(messageId + params.prompt, true);
48
-
49
- let url = '';
50
- try {
51
- url = await imageGenerationService.generateImage(params);
52
- } catch (e) {
53
- toggleDallEImageLoading(messageId + params.prompt, false);
54
- errorArray[index] = e;
55
-
56
- await get().updatePluginState(messageId, { error: errorArray });
57
- }
58
-
59
- if (!url) return;
60
-
61
- await updateImageItem(messageId, (draft) => {
62
- draft[index].previewUrl = url;
63
- });
64
-
65
- toggleDallEImageLoading(messageId + params.prompt, false);
66
- const imageFile = await uploadService.getImageFileByUrlWithCORS(
67
- url,
68
- `${originPrompt || params.prompt}_${index}.png`,
69
- );
70
-
71
- const data = await useFileStore.getState().uploadWithProgress({
72
- file: imageFile,
73
- });
74
-
75
- if (!data) return;
76
-
77
- await updateImageItem(messageId, (draft) => {
78
- draft[index].imageId = data.id;
79
- draft[index].previewUrl = undefined;
80
- });
81
- });
82
- },
83
- text2image: async (id, data) => {
84
- // const isAutoGen = settingsSelectors.isDalleAutoGenerating(useGlobalStore.getState());
85
- // if (!isAutoGen) return;
86
-
87
- await get().generateImageFromPrompts(data, id);
88
- },
89
-
90
- toggleDallEImageLoading: (key, value) => {
91
- set(
92
- { dalleImageLoading: { ...get().dalleImageLoading, [key]: value } },
93
- false,
94
- n('toggleDallEImageLoading'),
95
- );
96
- },
97
-
98
- updateImageItem: async (id, updater) => {
99
- const message = chatSelectors.getMessageById(id)(get());
100
- if (!message) return;
101
-
102
- const data: DallEImageItem[] = JSON.parse(message.content);
103
-
104
- const nextContent = produce(data, updater);
105
- await get().internal_updateMessageContent(id, JSON.stringify(nextContent));
106
- },
107
-
108
- useFetchDalleImageItem: (id) =>
109
- useClientDataSWR([SWR_FETCH_KEY, id], async () => {
110
- const item = await fileService.getFile(id);
111
-
112
- set(
113
- produce((draft) => {
114
- if (draft.dalleImageMap[id]) return;
115
-
116
- draft.dalleImageMap[id] = item;
117
- }),
118
- false,
119
- n('useFetchFile'),
120
- );
121
-
122
- return item;
123
- }),
124
- });
@@ -1,60 +0,0 @@
1
- import { useResponsive } from 'antd-style';
2
- import { ReactNode, memo, useMemo } from 'react';
3
- import { Flexbox } from 'react-layout-kit';
4
-
5
- import Grid from '@/components/GalleyGrid/Grid';
6
-
7
- const MAX_SIZE_DESKTOP = 640;
8
- const MAX_SIZE_MOBILE = 280;
9
-
10
- interface GalleyGridProps<T = any> {
11
- items: T[];
12
- renderItem: (props: T) => ReactNode;
13
- }
14
-
15
- const GalleyGrid = memo<GalleyGridProps>(({ items, renderItem: Render }) => {
16
- const { mobile } = useResponsive();
17
-
18
- const { firstRow, lastRow } = useMemo(() => {
19
- if (items.length === 4) {
20
- return {
21
- firstRow: items.slice(0, 2),
22
- lastRow: items.slice(2, 4),
23
- };
24
- }
25
-
26
- const firstCol = items.length % 3 === 0 ? 3 : items.length % 3;
27
-
28
- return {
29
- firstRow: items.slice(0, firstCol),
30
- lastRow: items.slice(firstCol, items.length),
31
- };
32
- }, [items]);
33
-
34
- const { gap, max } = useMemo(
35
- () => ({
36
- gap: mobile ? 4 : 6,
37
- max: (mobile ? MAX_SIZE_MOBILE : MAX_SIZE_DESKTOP) * firstRow.length,
38
- }),
39
- [mobile],
40
- );
41
-
42
- return (
43
- <Flexbox gap={gap}>
44
- <Grid col={firstRow.length} gap={gap} max={max}>
45
- {firstRow.map((i, index) => (
46
- <Render {...i} index={index} key={index} />
47
- ))}
48
- </Grid>
49
- {lastRow.length > 0 && (
50
- <Grid col={lastRow.length > 2 ? 3 : lastRow.length} gap={gap} max={max}>
51
- {lastRow.map((i, index) => (
52
- <Render {...i} index={index} key={index} />
53
- ))}
54
- </Grid>
55
- )}
56
- </Flexbox>
57
- );
58
- });
59
-
60
- export default GalleyGrid;
@@ -1,66 +0,0 @@
1
- import { Button, Select, TextArea } from '@lobehub/ui';
2
- import { Radio } from 'antd';
3
- import { memo } from 'react';
4
- import { useTranslation } from 'react-i18next';
5
- import { Flexbox } from 'react-layout-kit';
6
-
7
- import { DallEImageItem } from '@/types/tool/dalle';
8
-
9
- interface EditModeProps extends DallEImageItem {
10
- setEdit: (edit: boolean) => void;
11
- }
12
-
13
- const EditMode = memo<EditModeProps>(({ prompt, setEdit, style, size, quality }) => {
14
- const { t } = useTranslation('tool');
15
-
16
- return (
17
- <Flexbox gap={16}>
18
- <TextArea style={{ minHeight: 120 }} value={prompt} variant={'filled'} />
19
- <Flexbox horizontal justify={'space-between'}>
20
- 风格
21
- <Radio.Group
22
- defaultValue={style}
23
- options={[
24
- { label: 'vivid', value: 'vivid' },
25
- { label: 'natural', value: 'natural' },
26
- ]}
27
- />
28
- </Flexbox>
29
- <Flexbox horizontal justify={'space-between'}>
30
- 质量
31
- <Radio.Group
32
- defaultValue={quality}
33
- options={[
34
- { label: 'standard', value: 'standard' },
35
- { label: 'hd', value: 'hd' },
36
- ]}
37
- />
38
- </Flexbox>
39
- <Flexbox horizontal justify={'space-between'}>
40
- 尺寸
41
- <Select
42
- defaultValue={size}
43
- options={[
44
- { label: '1792x1024', value: '1792x1024' },
45
- { label: '1024x1024', value: '1024x1024' },
46
- { label: '1024x1792', value: '1024x1792' },
47
- ]}
48
- size={'small'}
49
- />
50
- </Flexbox>
51
-
52
- <Flexbox direction={'horizontal-reverse'} gap={12}>
53
- <Button type={'primary'}>{t('dalle.generate')}</Button>
54
- <Button
55
- onClick={() => {
56
- setEdit(false);
57
- }}
58
- >
59
- {t('cancel', { ns: 'common' })}
60
- </Button>
61
- </Flexbox>
62
- </Flexbox>
63
- );
64
- });
65
-
66
- export default EditMode;
@@ -1,49 +0,0 @@
1
- import { Alert, Button, Highlighter } from '@lobehub/ui';
2
- import { LucideRefreshCw } from 'lucide-react';
3
- import { memo } from 'react';
4
- import { useTranslation } from 'react-i18next';
5
- import { Flexbox } from 'react-layout-kit';
6
-
7
- import { useChatStore } from '@/store/chat';
8
- import { chatSelectors } from '@/store/chat/selectors';
9
-
10
- interface ErrorProps {
11
- index: number;
12
- messageId: string;
13
- }
14
-
15
- const Error = memo<ErrorProps>(({ messageId, index }) => {
16
- const { t } = useTranslation('error');
17
- const { t: ct } = useTranslation('common');
18
-
19
- const error = useChatStore(
20
- (s) => chatSelectors.getMessageById(messageId)(s)?.pluginState?.['error']?.[index],
21
- );
22
- const [reInvokeToolMessage] = useChatStore((s) => [s.reInvokeToolMessage]);
23
-
24
- return (
25
- error && (
26
- <Flexbox gap={12}>
27
- <Alert
28
- extra={
29
- <Highlighter actionIconSize={'small'} language={'json'}>
30
- {JSON.stringify(error?.body || error, null, 2)}
31
- </Highlighter>
32
- }
33
- extraDefaultExpand
34
- message={t(`response.${error.errorType}` as any)}
35
- type={'error'}
36
- />
37
- <Button
38
- icon={LucideRefreshCw}
39
- onClick={() => reInvokeToolMessage(messageId)}
40
- type={'primary'}
41
- >
42
- {ct('retry')}
43
- </Button>
44
- </Flexbox>
45
- )
46
- );
47
- });
48
-
49
- export default Error;
@@ -1,44 +0,0 @@
1
- import { Icon, Image, Tooltip } from '@lobehub/ui';
2
- import { Loader2 } from 'lucide-react';
3
- import { memo } from 'react';
4
- import { useTranslation } from 'react-i18next';
5
- import { Flexbox } from 'react-layout-kit';
6
-
7
- import ImageFileItem from './ImageFileItem';
8
-
9
- interface ImagePreviewProps {
10
- imageId?: string;
11
- previewUrl?: string;
12
- prompt: string;
13
- }
14
-
15
- const ImagePreview = memo<ImagePreviewProps>(({ imageId, previewUrl, prompt }) => {
16
- const { t } = useTranslation('tool');
17
-
18
- return imageId ? (
19
- // <Flexbox className={styles.action}>
20
- // <ActionIconGroup
21
- // items={[{ icon: LucideEdit, key: 'edit', label: t('edit', { ns: 'common' }) }]}
22
- // onActionClick={(e) => {
23
- // if (e.key === 'edit') {
24
- // setEdit(true);
25
- // }
26
- // }}
27
- // />
28
- // </Flexbox>
29
- <ImageFileItem id={imageId} />
30
- ) : (
31
- previewUrl && (
32
- <Flexbox style={{ position: 'relative' }}>
33
- <div style={{ position: 'absolute', right: 8, top: 8, zIndex: 10 }}>
34
- <Tooltip title={t('dalle.downloading')}>
35
- <Icon icon={Loader2} size={'large'} spin />
36
- </Tooltip>
37
- </div>
38
- <Image alt={prompt} size={'100%'} src={previewUrl} />
39
- </Flexbox>
40
- )
41
- );
42
- });
43
-
44
- export default ImagePreview;
@@ -1,57 +0,0 @@
1
- import { Image } from '@lobehub/ui';
2
- import { createStyles } from 'antd-style';
3
- import { CSSProperties, memo } from 'react';
4
-
5
- import { usePlatform } from '@/hooks/usePlatform';
6
- import { useChatStore } from '@/store/chat';
7
-
8
- const MIN_IMAGE_SIZE = 64;
9
-
10
- export const useStyles = createStyles(({ css, token }) => ({
11
- deleteButton: css`
12
- color: #fff;
13
- background: ${token.colorBgMask};
14
-
15
- &:hover {
16
- background: ${token.colorError};
17
- }
18
- `,
19
- editableImage: css`
20
- background: ${token.colorBgContainer};
21
- box-shadow: 0 0 0 1px ${token.colorFill} inset;
22
- `,
23
- image: css`
24
- margin-block: 0 !important;
25
- `,
26
- }));
27
-
28
- interface FileItemProps {
29
- alwaysShowClose?: boolean;
30
- className?: string;
31
- editable?: boolean;
32
- id: string;
33
- onClick?: () => void;
34
- style?: CSSProperties;
35
- }
36
- const ImageFileItem = memo<FileItemProps>(({ editable, id, alwaysShowClose }) => {
37
- const [useFetchDalleImageItem] = useChatStore((s) => [s.useFetchDalleImageItem]);
38
- const IMAGE_SIZE = editable ? MIN_IMAGE_SIZE : '100%';
39
- const { data, isLoading } = useFetchDalleImageItem(id);
40
- const { styles, cx } = useStyles();
41
- const { isSafari } = usePlatform();
42
-
43
- return (
44
- <Image
45
- alt={data?.name || id || ''}
46
- alwaysShowActions={alwaysShowClose}
47
- height={isSafari ? 'auto' : '100%'}
48
- isLoading={isLoading}
49
- size={IMAGE_SIZE as any}
50
- src={data?.url}
51
- style={{ height: isSafari ? 'auto' : '100%' }}
52
- wrapperClassName={cx(styles.image, editable && styles.editableImage)}
53
- />
54
- );
55
- });
56
-
57
- export default ImageFileItem;
@@ -1,88 +0,0 @@
1
- import { Highlighter, Icon } from '@lobehub/ui';
2
- import { Spin } from 'antd';
3
- import { createStyles } from 'antd-style';
4
- import { Loader2 } from 'lucide-react';
5
- import { memo, useState } from 'react';
6
- import { useTranslation } from 'react-i18next';
7
- import { Flexbox } from 'react-layout-kit';
8
-
9
- import { useChatStore } from '@/store/chat';
10
- import { chatToolSelectors } from '@/store/chat/selectors';
11
- import { DallEImageItem } from '@/types/tool/dalle';
12
-
13
- import EditMode from './EditMode';
14
- import Error from './Error';
15
- import ImagePreview from './Image';
16
-
17
- const useStyles = createStyles(({ css, token, prefixCls }) => ({
18
- action: css`
19
- position: absolute;
20
- z-index: 100;
21
- inset-block-start: 4px;
22
- inset-inline-end: 4px;
23
- `,
24
- container: css`
25
- overflow: scroll;
26
- aspect-ratio: 1;
27
- border: 1px solid ${token.colorBorder};
28
- border-radius: 8px;
29
-
30
- .${prefixCls}-spin-nested-loading {
31
- height: 100%;
32
- }
33
- `,
34
- }));
35
-
36
- const ImageItem = memo<DallEImageItem & { index: number; messageId: string }>(
37
- ({ prompt, messageId, imageId, previewUrl, index, style, size, quality }) => {
38
- const { t } = useTranslation('tool');
39
- const { styles } = useStyles();
40
-
41
- const [edit, setEdit] = useState(false);
42
- const loading = useChatStore(chatToolSelectors.isDallEImageGenerating(messageId + prompt));
43
-
44
- if (edit)
45
- return (
46
- <Flexbox className={styles.container} padding={8}>
47
- <EditMode
48
- imageId={imageId}
49
- prompt={prompt}
50
- quality={quality}
51
- setEdit={setEdit}
52
- size={size}
53
- style={style}
54
- />
55
- </Flexbox>
56
- );
57
-
58
- if (imageId || previewUrl)
59
- return <ImagePreview imageId={imageId} previewUrl={previewUrl} prompt={prompt} />;
60
-
61
- return (
62
- <Flexbox className={styles.container} padding={8}>
63
- {loading ? (
64
- <Spin indicator={<Icon icon={Loader2} spin />} size={'large'} tip={t('dalle.generating')}>
65
- {prompt}
66
- </Spin>
67
- ) : (
68
- <Flexbox gap={12}>
69
- <Flexbox>
70
- <Highlighter
71
- actionIconSize={'small'}
72
- fileName={t('dalle.prompt')}
73
- fullFeatured
74
- language={'prompt'}
75
- showLanguage
76
- >
77
- {prompt}
78
- </Highlighter>
79
- </Flexbox>
80
- <Error index={index} messageId={messageId} />
81
- </Flexbox>
82
- )}
83
- </Flexbox>
84
- );
85
- },
86
- );
87
-
88
- export default ImageItem;
@@ -1,56 +0,0 @@
1
- import { Button } from '@lobehub/ui';
2
- import { Checkbox } from 'antd';
3
- import { memo } from 'react';
4
- import { useTranslation } from 'react-i18next';
5
- import { Flexbox } from 'react-layout-kit';
6
-
7
- import { useChatStore } from '@/store/chat';
8
- import { chatToolSelectors } from '@/store/chat/selectors';
9
- import { useUserStore } from '@/store/user';
10
- import { settingsSelectors } from '@/store/user/selectors';
11
- import { DallEImageItem } from '@/types/tool/dalle';
12
-
13
- interface ToolBarProps {
14
- content: DallEImageItem[];
15
- messageId: string;
16
- }
17
-
18
- const ToolBar = memo<ToolBarProps>(({ content, messageId }) => {
19
- const { t } = useTranslation('tool');
20
- const generateImageFromPrompts = useChatStore((s) => s.generateImageFromPrompts);
21
- const isLoading = useChatStore(chatToolSelectors.isGeneratingDallEImage);
22
-
23
- const [isAutoGenerate, setSettings] = useUserStore((s) => [
24
- settingsSelectors.isDalleAutoGenerating(s),
25
- s.setSettings,
26
- ]);
27
-
28
- const genImages = () => {
29
- generateImageFromPrompts(content, messageId);
30
- };
31
-
32
- const canGen = content.some((i) => !i.imageId);
33
-
34
- return (
35
- <Flexbox align={'center'} height={28} horizontal justify={'space-between'}>
36
- {t('dalle.images')}
37
- <Flexbox align={'center'} gap={8} horizontal>
38
- <Checkbox
39
- checked={isAutoGenerate}
40
- onChange={(e) => {
41
- setSettings({ tool: { dalle: { autoGenerate: e.target.checked } } });
42
- }}
43
- >
44
- {t('dalle.autoGenerate')}
45
- </Checkbox>
46
- {canGen && (
47
- <Button loading={isLoading} onClick={genImages} size={'small'} type={'primary'}>
48
- {t('dalle.generate')}
49
- </Button>
50
- )}
51
- </Flexbox>
52
- </Flexbox>
53
- );
54
- });
55
-
56
- export default ToolBar;
@@ -1,52 +0,0 @@
1
- import { BuiltinRenderProps } from '@lobechat/types';
2
- import { ActionIcon, PreviewGroup } from '@lobehub/ui';
3
- import { Download } from 'lucide-react';
4
- import { memo, useRef } from 'react';
5
- import { Flexbox } from 'react-layout-kit';
6
-
7
- import { fileService } from '@/services/file';
8
- import { DallEImageItem } from '@/types/tool/dalle';
9
-
10
- import GalleyGrid from './GalleyGrid';
11
- import ImageItem from './Item';
12
-
13
- const DallE = memo<BuiltinRenderProps<DallEImageItem[]>>(({ content, messageId }) => {
14
- const currentRef = useRef(0);
15
-
16
- const handleDownload = async () => {
17
- // 1. Retrieve the blob URL of an image by its imageId
18
- const id = content[currentRef.current]?.imageId;
19
- if (!id) return;
20
- const { url, name } = await fileService.getFile(id);
21
- // 2. Download the image
22
- const link = document.createElement('a');
23
- link.href = url;
24
- link.download = name; // 设置下载的文件名
25
- link.click();
26
- };
27
-
28
- return (
29
- <Flexbox gap={16}>
30
- {/* 没想好工具条的作用 */}
31
- {/*<ToolBar content={content} messageId={messageId} />*/}
32
- <PreviewGroup
33
- preview={{
34
- // 切换图片时设置
35
- onChange: (current: number) => {
36
- currentRef.current = current;
37
- },
38
- // 点击预览显示时设置
39
-
40
- onVisibleChange: (visible: boolean, _prevVisible: boolean, current: number) => {
41
- currentRef.current = current;
42
- },
43
- toolbarAddon: <ActionIcon color={'#fff'} icon={Download} onClick={handleDownload} />,
44
- }}
45
- >
46
- <GalleyGrid items={content.map((c) => ({ ...c, messageId }))} renderItem={ImageItem} />
47
- </PreviewGroup>
48
- </Flexbox>
49
- );
50
- });
51
-
52
- export default DallE;