@blocklet/aigne-hub 0.4.56 → 0.4.57

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.
@@ -10,6 +10,7 @@ const isNil_1 = __importDefault(require("lodash/isNil"));
10
10
  const react_1 = require("react");
11
11
  const alert_1 = __importDefault(require("../credit/alert"));
12
12
  const image_preview_1 = __importDefault(require("../image-preview"));
13
+ const video_preview_1 = __importDefault(require("../video-preview"));
13
14
  const message_1 = __importDefault(require("./message"));
14
15
  const prompt_1 = __importDefault(require("./prompt"));
15
16
  function Conversation({ ref, messages, onSubmit, customActions = () => [], renderAvatar = undefined, maxWidth = 1000, scrollContainer = undefined, promptProps = {}, chatLayout = 'left-right', ...props }) {
@@ -32,9 +33,7 @@ function Conversation({ ref, messages, onSubmit, customActions = () => [], rende
32
33
  typeof msg.response === 'object' &&
33
34
  'images' in msg.response &&
34
35
  Array.isArray(msg.response.images) &&
35
- msg.response.images.length > 0 && ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [msg.response.images.some((img) => img.url && img.url.startsWith('data:')) && ((0, jsx_runtime_1.jsx)(image_preview_1.default, { itemWidth: 200, borderRadius: 12, dataSource: msg.response.images
36
- .filter((img) => img.url && img.url.startsWith('data:'))
37
- .map(({ url }) => ({
36
+ msg.response.images.length > 0 && ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [msg.response.images.some((img) => img.url && img.url !== '[IMAGE_PLACEHOLDER]') && ((0, jsx_runtime_1.jsx)(image_preview_1.default, { itemWidth: 200, borderRadius: 12, dataSource: msg.response.images.map(({ url }) => ({
38
37
  src: url,
39
38
  onLoad: () => scrollToBottom(),
40
39
  })) })), msg.response.images.some((img) => !img.url || img.url === '[IMAGE_PLACEHOLDER]') && ((0, jsx_runtime_1.jsxs)(material_1.Box, { sx: {
@@ -58,7 +57,34 @@ function Conversation({ ref, messages, onSubmit, customActions = () => [], rende
58
57
  }, children: msg.response.images.filter((img) => !img.url || img.url === '[IMAGE_PLACEHOLDER]')
59
58
  .length === 1
60
59
  ? 'Image (Not Cached)'
61
- : `${msg.response.images.filter((img) => !img.url || img.url === '[IMAGE_PLACEHOLDER]').length} Images (Not Cached)` })] }))] })), msg.error ? (
60
+ : `${msg.response.images.filter((img) => !img.url || img.url === '[IMAGE_PLACEHOLDER]').length} Images (Not Cached)` })] }))] })), msg.response &&
61
+ typeof msg.response === 'object' &&
62
+ 'videos' in msg.response &&
63
+ Array.isArray(msg.response.videos) &&
64
+ msg.response.videos.length > 0 && ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [msg.response.videos.some((video) => (video.data && video.data.startsWith('data:')) || video.url) && ((0, jsx_runtime_1.jsx)(video_preview_1.default, { itemWidth: 300, borderRadius: 12, dataSource: msg.response.videos.map(({ data, url, type }) => ({
65
+ src: type === 'file' && data ? data : url,
66
+ onLoad: () => scrollToBottom(),
67
+ })) })), msg.response.videos.some((video) => video.data === '[VIDEO_PLACEHOLDER]') && ((0, jsx_runtime_1.jsxs)(material_1.Box, { sx: {
68
+ margin: '8px 0',
69
+ minHeight: '200px',
70
+ background: '#f5f5f5',
71
+ borderRadius: '8px',
72
+ padding: '16px',
73
+ display: 'flex',
74
+ alignItems: 'center',
75
+ justifyContent: 'center',
76
+ flexDirection: 'column',
77
+ gap: '12px',
78
+ border: '2px dashed #ddd',
79
+ }, children: [(0, jsx_runtime_1.jsx)(material_1.Box, { sx: { fontSize: '48px', opacity: 0.4 }, children: "\uD83D\uDDBC\uFE0F" }), (0, jsx_runtime_1.jsx)(material_1.Box, { sx: {
80
+ fontSize: '14px',
81
+ color: '#666',
82
+ textAlign: 'center',
83
+ fontWeight: 500,
84
+ minWidth: 200,
85
+ }, children: msg.response.videos.filter((video) => !video.url || video.data === '[VIDEO_PLACEHOLDER]').length === 1
86
+ ? 'Video (Not Cached)'
87
+ : `${msg.response.videos.filter((video) => !video.url || video.data === '[VIDEO_PLACEHOLDER]').length} Videos (Not Cached)` })] }))] })), msg.error ? (
62
88
  // @ts-ignore
63
89
  (0, jsx_runtime_1.jsx)(alert_1.default, { error: msg.error })) : (msg.loading &&
64
90
  !msg.response && ((0, jsx_runtime_1.jsxs)(material_1.Box, { sx: {
@@ -39,17 +39,26 @@ const saveMessages = async (messages) => {
39
39
  .filter((msg) => !msg.loading)
40
40
  .slice(-MAX_CACHED_MESSAGES) // Keep only last N messages
41
41
  .map((msg) => {
42
- var _a;
43
42
  // Replace image data URLs with placeholders to save storage space
44
- const response = msg.response && typeof msg.response === 'object' && 'images' in msg.response
45
- ? {
46
- ...msg.response,
47
- images: ((_a = msg.response.images) === null || _a === void 0 ? void 0 : _a.map((img) => ({
43
+ let response = msg === null || msg === void 0 ? void 0 : msg.response;
44
+ if (response && typeof response === 'object' && 'images' in response && response.images) {
45
+ response = {
46
+ ...response,
47
+ images: (response.images || []).map((img) => ({
48
48
  ...img,
49
- url: img.url && img.url.startsWith('data:') ? '[IMAGE_PLACEHOLDER]' : img.url,
50
- }))) || [],
51
- }
52
- : msg.response;
49
+ url: (img === null || img === void 0 ? void 0 : img.url) && img.url.startsWith('data:') ? '[IMAGE_PLACEHOLDER]' : img.url,
50
+ })),
51
+ };
52
+ }
53
+ if (response && typeof response === 'object' && 'videos' in response && response.videos) {
54
+ response = {
55
+ ...response,
56
+ videos: (response.videos || []).map((video) => ({
57
+ ...video,
58
+ data: (video === null || video === void 0 ? void 0 : video.data) && video.data.startsWith('data:') ? '[VIDEO_PLACEHOLDER]' : video.data,
59
+ })),
60
+ };
61
+ }
53
62
  return {
54
63
  id: msg.id,
55
64
  prompt: msg.prompt,
@@ -161,6 +170,7 @@ function useConversation({ scrollToBottom, textCompletions, imageGenerations, en
161
170
  const result = await textCompletions(prompt, { meta });
162
171
  const isText = (i) => i.type === 'text';
163
172
  const isImages = (i) => i.type === 'images';
173
+ const isVideo = (i) => i.type === 'video';
164
174
  const reader = result.getReader();
165
175
  const decoder = new TextDecoder();
166
176
  let response = '';
@@ -178,6 +188,9 @@ function useConversation({ scrollToBottom, textCompletions, imageGenerations, en
178
188
  else if (isImages(value)) {
179
189
  response = { images: value.images };
180
190
  }
191
+ else if (isVideo(value)) {
192
+ response = { videos: value.videos };
193
+ }
181
194
  else {
182
195
  delta = decoder.decode(value);
183
196
  }
@@ -18,11 +18,13 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
18
18
  return (mod && mod.__esModule) ? mod : { "default": mod };
19
19
  };
20
20
  Object.defineProperty(exports, "__esModule", { value: true });
21
- exports.FormLabel = exports.UserCreditCard = exports.Table = exports.Switch = exports.CreditErrorAlert = exports.CreditBalance = exports.CreditButton = exports.SubscribeErrorAlert = exports.SubscribeButton = exports.Conversation = exports.ImagePreview = exports.LoadingImage = void 0;
21
+ exports.FormLabel = exports.UserCreditCard = exports.Table = exports.Switch = exports.CreditErrorAlert = exports.CreditBalance = exports.CreditButton = exports.SubscribeErrorAlert = exports.SubscribeButton = exports.Conversation = exports.VideoPreview = exports.ImagePreview = exports.LoadingImage = void 0;
22
22
  var loading_image_1 = require("./loading-image");
23
23
  Object.defineProperty(exports, "LoadingImage", { enumerable: true, get: function () { return __importDefault(loading_image_1).default; } });
24
24
  var image_preview_1 = require("./image-preview");
25
25
  Object.defineProperty(exports, "ImagePreview", { enumerable: true, get: function () { return __importDefault(image_preview_1).default; } });
26
+ var video_preview_1 = require("./video-preview");
27
+ Object.defineProperty(exports, "VideoPreview", { enumerable: true, get: function () { return __importDefault(video_preview_1).default; } });
26
28
  var conversation_1 = require("./conversation");
27
29
  Object.defineProperty(exports, "Conversation", { enumerable: true, get: function () { return __importDefault(conversation_1).default; } });
28
30
  __exportStar(require("./conversation"), exports);
@@ -0,0 +1,91 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.default = VideoPreview;
7
+ const jsx_runtime_1 = require("react/jsx-runtime");
8
+ const CloudDownloadOutlined_1 = __importDefault(require("@mui/icons-material/CloudDownloadOutlined"));
9
+ const material_1 = require("@mui/material");
10
+ const ahooks_1 = require("ahooks");
11
+ const renderIconButton = (children, onClick, { key, ...extraProps } = {}) => {
12
+ return ((0, jsx_runtime_1.jsx)(material_1.IconButton, { sx: {
13
+ transition: 'all 0.3s',
14
+ color: 'rgba(255,255,255,0.75)',
15
+ '&:hover': {
16
+ color: 'rgba(255,255,255,1)',
17
+ },
18
+ }, onClick: onClick, ...extraProps, children: children }, key));
19
+ };
20
+ function getExtFromBase64(base64) {
21
+ var _a;
22
+ // eslint-disable-next-line prefer-regex-literals
23
+ const re = new RegExp('data:video/([a-z]+);base64,.+');
24
+ const res = re.exec(base64);
25
+ if ((_a = res === null || res === void 0 ? void 0 : res.groups) === null || _a === void 0 ? void 0 : _a.ext) {
26
+ return res.groups.ext;
27
+ }
28
+ return '';
29
+ }
30
+ function VideoPreview({ dataSource = [], itemWidth = undefined, itemHeight = undefined, spacing = 1, transition = 'all 0.3s', borderRadius = 8, showDownloadButton = true, }) {
31
+ const state = (0, ahooks_1.useReactive)({
32
+ downloadingIndexMap: {},
33
+ });
34
+ const getDownloadButton = (currentIndex, extraProps = {}) => renderIconButton((0, jsx_runtime_1.jsx)(CloudDownloadOutlined_1.default, { fontSize: "inherit" }), async () => {
35
+ const { src } = (dataSource === null || dataSource === void 0 ? void 0 : dataSource[currentIndex]) || {};
36
+ state.downloadingIndexMap = {
37
+ ...state.downloadingIndexMap,
38
+ [currentIndex]: true,
39
+ };
40
+ if (src) {
41
+ // download base64 video
42
+ if (src === null || src === void 0 ? void 0 : src.startsWith('data:video/')) {
43
+ const link = document.createElement('a');
44
+ link.href = src;
45
+ link.download = `video-${currentIndex}.${getExtFromBase64(src) || 'mp4'}`;
46
+ link.click();
47
+ }
48
+ state.downloadingIndexMap = {
49
+ ...state.downloadingIndexMap,
50
+ [currentIndex]: false,
51
+ };
52
+ }
53
+ }, {
54
+ key: 'download',
55
+ disabled: !!state.downloadingIndexMap[currentIndex],
56
+ ...extraProps,
57
+ });
58
+ return ((0, jsx_runtime_1.jsx)(material_1.Grid, { spacing: spacing, container: true, className: "video-wrapper", children: dataSource === null || dataSource === void 0 ? void 0 : dataSource.map((item, index) => {
59
+ const { width, height } = item;
60
+ return ((0, jsx_runtime_1.jsx)(material_1.Grid
61
+ // eslint-disable-next-line react/no-array-index-key
62
+ , { className: "video-item", sx: {
63
+ transition,
64
+ '&:hover': {
65
+ cursor: 'pointer',
66
+ '& .video-toolbar': {
67
+ transition,
68
+ opacity: 1,
69
+ },
70
+ },
71
+ }, children: (0, jsx_runtime_1.jsxs)(material_1.Box, { sx: { position: 'relative' }, children: [(0, jsx_runtime_1.jsx)("video", { src: item.src, controls: true, style: {
72
+ transition,
73
+ borderRadius,
74
+ objectFit: 'cover',
75
+ width: width || itemWidth || '100%',
76
+ height: height || itemHeight || 'auto',
77
+ backgroundColor: '#000',
78
+ maxWidth: '400px',
79
+ }, preload: "metadata", children: (0, jsx_runtime_1.jsx)("track", { kind: "captions" }) }), (0, jsx_runtime_1.jsx)(material_1.Box, { className: "video-toolbar", sx: {
80
+ position: 'absolute',
81
+ right: 8,
82
+ top: 8,
83
+ opacity: 0,
84
+ background: 'rgba(0,0,0,0.7)',
85
+ borderRadius: '4px',
86
+ }, children: showDownloadButton &&
87
+ getDownloadButton(index, {
88
+ size: 'small',
89
+ }) })] }) }, index));
90
+ }) }));
91
+ }
@@ -4,6 +4,7 @@ import isNil from 'lodash/isNil';
4
4
  import { useCallback, useEffect, useImperativeHandle, useRef } from 'react';
5
5
  import CreditErrorAlert from '../credit/alert';
6
6
  import ImagePreview from '../image-preview';
7
+ import VideoPreview from '../video-preview';
7
8
  import Message from './message';
8
9
  import Prompt from './prompt';
9
10
  export default function Conversation({ ref, messages, onSubmit, customActions = () => [], renderAvatar = undefined, maxWidth = 1000, scrollContainer = undefined, promptProps = {}, chatLayout = 'left-right', ...props }) {
@@ -26,9 +27,7 @@ export default function Conversation({ ref, messages, onSubmit, customActions =
26
27
  typeof msg.response === 'object' &&
27
28
  'images' in msg.response &&
28
29
  Array.isArray(msg.response.images) &&
29
- msg.response.images.length > 0 && (_jsxs(_Fragment, { children: [msg.response.images.some((img) => img.url && img.url.startsWith('data:')) && (_jsx(ImagePreview, { itemWidth: 200, borderRadius: 12, dataSource: msg.response.images
30
- .filter((img) => img.url && img.url.startsWith('data:'))
31
- .map(({ url }) => ({
30
+ msg.response.images.length > 0 && (_jsxs(_Fragment, { children: [msg.response.images.some((img) => img.url && img.url !== '[IMAGE_PLACEHOLDER]') && (_jsx(ImagePreview, { itemWidth: 200, borderRadius: 12, dataSource: msg.response.images.map(({ url }) => ({
32
31
  src: url,
33
32
  onLoad: () => scrollToBottom(),
34
33
  })) })), msg.response.images.some((img) => !img.url || img.url === '[IMAGE_PLACEHOLDER]') && (_jsxs(Box, { sx: {
@@ -52,7 +51,34 @@ export default function Conversation({ ref, messages, onSubmit, customActions =
52
51
  }, children: msg.response.images.filter((img) => !img.url || img.url === '[IMAGE_PLACEHOLDER]')
53
52
  .length === 1
54
53
  ? 'Image (Not Cached)'
55
- : `${msg.response.images.filter((img) => !img.url || img.url === '[IMAGE_PLACEHOLDER]').length} Images (Not Cached)` })] }))] })), msg.error ? (
54
+ : `${msg.response.images.filter((img) => !img.url || img.url === '[IMAGE_PLACEHOLDER]').length} Images (Not Cached)` })] }))] })), msg.response &&
55
+ typeof msg.response === 'object' &&
56
+ 'videos' in msg.response &&
57
+ Array.isArray(msg.response.videos) &&
58
+ msg.response.videos.length > 0 && (_jsxs(_Fragment, { children: [msg.response.videos.some((video) => (video.data && video.data.startsWith('data:')) || video.url) && (_jsx(VideoPreview, { itemWidth: 300, borderRadius: 12, dataSource: msg.response.videos.map(({ data, url, type }) => ({
59
+ src: type === 'file' && data ? data : url,
60
+ onLoad: () => scrollToBottom(),
61
+ })) })), msg.response.videos.some((video) => video.data === '[VIDEO_PLACEHOLDER]') && (_jsxs(Box, { sx: {
62
+ margin: '8px 0',
63
+ minHeight: '200px',
64
+ background: '#f5f5f5',
65
+ borderRadius: '8px',
66
+ padding: '16px',
67
+ display: 'flex',
68
+ alignItems: 'center',
69
+ justifyContent: 'center',
70
+ flexDirection: 'column',
71
+ gap: '12px',
72
+ border: '2px dashed #ddd',
73
+ }, children: [_jsx(Box, { sx: { fontSize: '48px', opacity: 0.4 }, children: "\uD83D\uDDBC\uFE0F" }), _jsx(Box, { sx: {
74
+ fontSize: '14px',
75
+ color: '#666',
76
+ textAlign: 'center',
77
+ fontWeight: 500,
78
+ minWidth: 200,
79
+ }, children: msg.response.videos.filter((video) => !video.url || video.data === '[VIDEO_PLACEHOLDER]').length === 1
80
+ ? 'Video (Not Cached)'
81
+ : `${msg.response.videos.filter((video) => !video.url || video.data === '[VIDEO_PLACEHOLDER]').length} Videos (Not Cached)` })] }))] })), msg.error ? (
56
82
  // @ts-ignore
57
83
  _jsx(CreditErrorAlert, { error: msg.error })) : (msg.loading &&
58
84
  !msg.response && (_jsxs(Box, { sx: {
@@ -36,17 +36,26 @@ const saveMessages = async (messages) => {
36
36
  .filter((msg) => !msg.loading)
37
37
  .slice(-MAX_CACHED_MESSAGES) // Keep only last N messages
38
38
  .map((msg) => {
39
- var _a;
40
39
  // Replace image data URLs with placeholders to save storage space
41
- const response = msg.response && typeof msg.response === 'object' && 'images' in msg.response
42
- ? {
43
- ...msg.response,
44
- images: ((_a = msg.response.images) === null || _a === void 0 ? void 0 : _a.map((img) => ({
40
+ let response = msg === null || msg === void 0 ? void 0 : msg.response;
41
+ if (response && typeof response === 'object' && 'images' in response && response.images) {
42
+ response = {
43
+ ...response,
44
+ images: (response.images || []).map((img) => ({
45
45
  ...img,
46
- url: img.url && img.url.startsWith('data:') ? '[IMAGE_PLACEHOLDER]' : img.url,
47
- }))) || [],
48
- }
49
- : msg.response;
46
+ url: (img === null || img === void 0 ? void 0 : img.url) && img.url.startsWith('data:') ? '[IMAGE_PLACEHOLDER]' : img.url,
47
+ })),
48
+ };
49
+ }
50
+ if (response && typeof response === 'object' && 'videos' in response && response.videos) {
51
+ response = {
52
+ ...response,
53
+ videos: (response.videos || []).map((video) => ({
54
+ ...video,
55
+ data: (video === null || video === void 0 ? void 0 : video.data) && video.data.startsWith('data:') ? '[VIDEO_PLACEHOLDER]' : video.data,
56
+ })),
57
+ };
58
+ }
50
59
  return {
51
60
  id: msg.id,
52
61
  prompt: msg.prompt,
@@ -158,6 +167,7 @@ export default function useConversation({ scrollToBottom, textCompletions, image
158
167
  const result = await textCompletions(prompt, { meta });
159
168
  const isText = (i) => i.type === 'text';
160
169
  const isImages = (i) => i.type === 'images';
170
+ const isVideo = (i) => i.type === 'video';
161
171
  const reader = result.getReader();
162
172
  const decoder = new TextDecoder();
163
173
  let response = '';
@@ -175,6 +185,9 @@ export default function useConversation({ scrollToBottom, textCompletions, image
175
185
  else if (isImages(value)) {
176
186
  response = { images: value.images };
177
187
  }
188
+ else if (isVideo(value)) {
189
+ response = { videos: value.videos };
190
+ }
178
191
  else {
179
192
  delta = decoder.decode(value);
180
193
  }
@@ -1,6 +1,7 @@
1
1
  /// <reference path="../env.d.ts" />
2
2
  export { default as LoadingImage } from './loading-image';
3
3
  export { default as ImagePreview } from './image-preview';
4
+ export { default as VideoPreview } from './video-preview';
4
5
  export { default as Conversation } from './conversation';
5
6
  export * from './conversation';
6
7
  export { default as SubscribeButton } from './subscribe/button';
@@ -0,0 +1,85 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import CloudDownloadOutlinedIcon from '@mui/icons-material/CloudDownloadOutlined';
3
+ import { Box, Grid, IconButton } from '@mui/material';
4
+ import { useReactive } from 'ahooks';
5
+ const renderIconButton = (children, onClick, { key, ...extraProps } = {}) => {
6
+ return (_jsx(IconButton, { sx: {
7
+ transition: 'all 0.3s',
8
+ color: 'rgba(255,255,255,0.75)',
9
+ '&:hover': {
10
+ color: 'rgba(255,255,255,1)',
11
+ },
12
+ }, onClick: onClick, ...extraProps, children: children }, key));
13
+ };
14
+ function getExtFromBase64(base64) {
15
+ var _a;
16
+ // eslint-disable-next-line prefer-regex-literals
17
+ const re = new RegExp('data:video/([a-z]+);base64,.+');
18
+ const res = re.exec(base64);
19
+ if ((_a = res === null || res === void 0 ? void 0 : res.groups) === null || _a === void 0 ? void 0 : _a.ext) {
20
+ return res.groups.ext;
21
+ }
22
+ return '';
23
+ }
24
+ export default function VideoPreview({ dataSource = [], itemWidth = undefined, itemHeight = undefined, spacing = 1, transition = 'all 0.3s', borderRadius = 8, showDownloadButton = true, }) {
25
+ const state = useReactive({
26
+ downloadingIndexMap: {},
27
+ });
28
+ const getDownloadButton = (currentIndex, extraProps = {}) => renderIconButton(_jsx(CloudDownloadOutlinedIcon, { fontSize: "inherit" }), async () => {
29
+ const { src } = (dataSource === null || dataSource === void 0 ? void 0 : dataSource[currentIndex]) || {};
30
+ state.downloadingIndexMap = {
31
+ ...state.downloadingIndexMap,
32
+ [currentIndex]: true,
33
+ };
34
+ if (src) {
35
+ // download base64 video
36
+ if (src === null || src === void 0 ? void 0 : src.startsWith('data:video/')) {
37
+ const link = document.createElement('a');
38
+ link.href = src;
39
+ link.download = `video-${currentIndex}.${getExtFromBase64(src) || 'mp4'}`;
40
+ link.click();
41
+ }
42
+ state.downloadingIndexMap = {
43
+ ...state.downloadingIndexMap,
44
+ [currentIndex]: false,
45
+ };
46
+ }
47
+ }, {
48
+ key: 'download',
49
+ disabled: !!state.downloadingIndexMap[currentIndex],
50
+ ...extraProps,
51
+ });
52
+ return (_jsx(Grid, { spacing: spacing, container: true, className: "video-wrapper", children: dataSource === null || dataSource === void 0 ? void 0 : dataSource.map((item, index) => {
53
+ const { width, height } = item;
54
+ return (_jsx(Grid
55
+ // eslint-disable-next-line react/no-array-index-key
56
+ , { className: "video-item", sx: {
57
+ transition,
58
+ '&:hover': {
59
+ cursor: 'pointer',
60
+ '& .video-toolbar': {
61
+ transition,
62
+ opacity: 1,
63
+ },
64
+ },
65
+ }, children: _jsxs(Box, { sx: { position: 'relative' }, children: [_jsx("video", { src: item.src, controls: true, style: {
66
+ transition,
67
+ borderRadius,
68
+ objectFit: 'cover',
69
+ width: width || itemWidth || '100%',
70
+ height: height || itemHeight || 'auto',
71
+ backgroundColor: '#000',
72
+ maxWidth: '400px',
73
+ }, preload: "metadata", children: _jsx("track", { kind: "captions" }) }), _jsx(Box, { className: "video-toolbar", sx: {
74
+ position: 'absolute',
75
+ right: 8,
76
+ top: 8,
77
+ opacity: 0,
78
+ background: 'rgba(0,0,0,0.7)',
79
+ borderRadius: '4px',
80
+ }, children: showDownloadButton &&
81
+ getDownloadButton(index, {
82
+ size: 'small',
83
+ }) })] }) }, index));
84
+ }) }));
85
+ }
@@ -2,12 +2,24 @@ import { BoxProps } from '@mui/material';
2
2
  import { ChatCompletionMessageParam } from 'openai/resources/index';
3
3
  import { ReactNode } from 'react';
4
4
  import { PromptProps } from './prompt';
5
+ export interface VideoResponse {
6
+ data?: string;
7
+ path?: string;
8
+ type?: string;
9
+ url?: string;
10
+ }
5
11
  export interface MessageItem {
6
12
  id: string;
7
13
  prompt?: string | ChatCompletionMessageParam[];
8
14
  response?: string | {
9
15
  url: string;
10
- }[];
16
+ }[] | {
17
+ videos: VideoResponse[];
18
+ } | {
19
+ images: {
20
+ url?: string;
21
+ }[];
22
+ };
11
23
  loading?: boolean;
12
24
  error?: {
13
25
  message: string;
@@ -1,5 +1,5 @@
1
1
  import { ChatCompletionMessageParam } from 'openai/resources/index';
2
- import { MessageItem } from './conversation';
2
+ import type { MessageItem, VideoResponse } from './conversation';
3
3
  export default function useConversation({ scrollToBottom, textCompletions, imageGenerations, enableCache, }: {
4
4
  scrollToBottom?: (options?: {
5
5
  force?: boolean;
@@ -14,6 +14,9 @@ export default function useConversation({ scrollToBottom, textCompletions, image
14
14
  images: {
15
15
  url: string;
16
16
  }[];
17
+ } | {
18
+ type: 'video';
19
+ videos: VideoResponse[];
17
20
  }>>;
18
21
  imageGenerations?: (prompt: {
19
22
  prompt: string;
@@ -36,8 +39,12 @@ export default function useConversation({ scrollToBottom, textCompletions, image
36
39
  } | {
37
40
  id: string;
38
41
  text: string | {
39
- url: string;
40
- }[] | undefined;
42
+ videos: VideoResponse[];
43
+ } | {
44
+ images: {
45
+ url?: string;
46
+ }[];
47
+ };
41
48
  data?: undefined;
42
49
  } | null>;
43
50
  cancel: ({ id }: Pick<MessageItem, "id">) => void;
@@ -1,5 +1,6 @@
1
1
  export { default as LoadingImage } from './loading-image';
2
2
  export { default as ImagePreview } from './image-preview';
3
+ export { default as VideoPreview } from './video-preview';
3
4
  export { default as Conversation } from './conversation';
4
5
  export * from './conversation';
5
6
  export { default as SubscribeButton } from './subscribe/button';
@@ -0,0 +1,16 @@
1
+ interface VideoPreviewProps {
2
+ dataSource?: Array<{
3
+ src: string;
4
+ alt?: string;
5
+ width?: number;
6
+ height?: number;
7
+ }>;
8
+ spacing?: number;
9
+ itemWidth?: number;
10
+ itemHeight?: number;
11
+ transition?: string;
12
+ borderRadius?: number;
13
+ showDownloadButton?: boolean;
14
+ }
15
+ export default function VideoPreview({ dataSource, itemWidth, itemHeight, spacing, transition, borderRadius, showDownloadButton, }: VideoPreviewProps): import("react/jsx-runtime").JSX.Element;
16
+ export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blocklet/aigne-hub",
3
- "version": "0.4.56",
3
+ "version": "0.4.57",
4
4
  "description": "The react.js component library for AIGNE Hub",
5
5
  "publishConfig": {
6
6
  "access": "public"