diff --git a/backend/app/services/system_config_service.py b/backend/app/services/system_config_service.py
index a8056ce..a876120 100644
--- a/backend/app/services/system_config_service.py
+++ b/backend/app/services/system_config_service.py
@@ -614,6 +614,13 @@ class SystemConfigService:
@classmethod
def get_branding_config(cls) -> Dict[str, str]:
+ max_audio_size_mb = cls.get_max_audio_size(100)
+ max_image_size_mb = cls.get_config("max_image_size", "10")
+ try:
+ max_image_size_mb = int(max_image_size_mb)
+ except (ValueError, TypeError):
+ max_image_size_mb = 10
+
return {
"app_name": str(cls.get_config(cls.BRANDING_APP_NAME, "智听云平台") or "智听云平台"),
"home_headline": str(cls.get_config(cls.BRANDING_HOME_HEADLINE, "智听云平台") or "智听云平台"),
@@ -622,6 +629,10 @@ class SystemConfigService:
"preview_title": str(cls.get_config(cls.BRANDING_PREVIEW_TITLE, "会议预览") or "会议预览"),
"login_welcome": str(cls.get_config(cls.BRANDING_LOGIN_WELCOME, "欢迎回来,请输入您的登录凭证。") or "欢迎回来,请输入您的登录凭证。"),
"footer_text": str(cls.get_config(cls.BRANDING_FOOTER_TEXT, "©2026 智听云平台") or "©2026 智听云平台"),
+ "max_audio_size": str(max_audio_size_mb),
+ "MAX_FILE_SIZE": max_audio_size_mb * 1024 * 1024,
+ "max_image_size": str(max_image_size_mb),
+ "MAX_IMAGE_SIZE": max_image_size_mb * 1024 * 1024,
}
# LLM模型配置获取方法(直接使用通用方法)
diff --git a/frontend/src/components/AudioPlayerBar.jsx b/frontend/src/components/AudioPlayerBar.jsx
index 8938f30..9582163 100644
--- a/frontend/src/components/AudioPlayerBar.jsx
+++ b/frontend/src/components/AudioPlayerBar.jsx
@@ -22,6 +22,7 @@ const AudioPlayerBar = ({
moreMenuItems = [],
emptyText = '暂无音频',
showMoreButton = true,
+ moreButtonDisabled = false,
rateOptions = DEFAULT_RATE_OPTIONS,
}) => {
const [isPlaying, setIsPlaying] = useState(false);
@@ -124,6 +125,18 @@ const AudioPlayerBar = ({
return (
{emptyText}
+ {showMoreButton ? (
+ <>
+
+ {!moreButtonDisabled && moreMenuItems.length > 0 ? (
+
+ } />
+
+ ) : (
+ } />
+ )}
+ >
+ ) : null}
);
}
@@ -169,7 +182,7 @@ const AudioPlayerBar = ({
{showMoreButton ? (
<>
- {moreMenuItems.length > 0 ? (
+ {!moreButtonDisabled && moreMenuItems.length > 0 ? (
} />
diff --git a/frontend/src/components/MeetingFormDrawer.jsx b/frontend/src/components/MeetingFormDrawer.jsx
index e303fa1..95f709a 100644
--- a/frontend/src/components/MeetingFormDrawer.jsx
+++ b/frontend/src/components/MeetingFormDrawer.jsx
@@ -1,11 +1,13 @@
import React, { useState, useEffect } from 'react';
-import { Drawer, Form, Input, Button, DatePicker, Select, Space, App } from 'antd';
-import { SaveOutlined } from '@ant-design/icons';
+import { Drawer, Form, Input, Button, DatePicker, Select, Space, App, Upload, Card, Progress, Typography } from 'antd';
+import { SaveOutlined, UploadOutlined, DeleteOutlined, AudioOutlined } from '@ant-design/icons';
import dayjs from 'dayjs';
import apiClient from '../utils/apiClient';
import { buildApiUrl, API_ENDPOINTS } from '../config/api';
+import configService from '../utils/configService';
+import { AUDIO_UPLOAD_ACCEPT, uploadMeetingAudio, validateMeetingAudioFile } from '../services/meetingAudioService';
-const { TextArea } = Input;
+const { Text } = Typography;
const MeetingFormDrawer = ({ open, onClose, onSuccess, meetingId = null }) => {
const { message } = App.useApp();
@@ -14,17 +16,27 @@ const MeetingFormDrawer = ({ open, onClose, onSuccess, meetingId = null }) => {
const [fetching, setFetching] = useState(false);
const [users, setUsers] = useState([]);
const [prompts, setPrompts] = useState([]);
+ const [selectedAudioFile, setSelectedAudioFile] = useState(null);
+ const [audioUploading, setAudioUploading] = useState(false);
+ const [audioUploadProgress, setAudioUploadProgress] = useState(0);
+ const [audioUploadMessage, setAudioUploadMessage] = useState('');
+ const [maxAudioSize, setMaxAudioSize] = useState(100 * 1024 * 1024);
const isEdit = Boolean(meetingId);
useEffect(() => {
if (!open) return;
fetchOptions();
+ loadAudioUploadConfig();
if (isEdit) {
fetchMeeting();
} else {
form.resetFields();
form.setFieldsValue({ meeting_time: dayjs() });
+ setSelectedAudioFile(null);
+ setAudioUploading(false);
+ setAudioUploadProgress(0);
+ setAudioUploadMessage('');
}
}, [open, meetingId]);
@@ -39,6 +51,15 @@ const MeetingFormDrawer = ({ open, onClose, onSuccess, meetingId = null }) => {
} catch {}
};
+ const loadAudioUploadConfig = async () => {
+ try {
+ const nextMaxAudioSize = await configService.getMaxAudioSize();
+ setMaxAudioSize(nextMaxAudioSize || 100 * 1024 * 1024);
+ } catch (error) {
+ setMaxAudioSize(100 * 1024 * 1024);
+ }
+ };
+
const fetchMeeting = async () => {
setFetching(true);
try {
@@ -50,7 +71,6 @@ const MeetingFormDrawer = ({ open, onClose, onSuccess, meetingId = null }) => {
attendee_ids: meeting.attendee_ids || meeting.attendees?.map((a) => a.user_id).filter(Boolean) || [],
prompt_id: meeting.prompt_id,
tags: meeting.tags?.map((t) => t.name) || [],
- description: meeting.description,
});
} catch {
message.error('加载会议数据失败');
@@ -59,6 +79,23 @@ const MeetingFormDrawer = ({ open, onClose, onSuccess, meetingId = null }) => {
}
};
+ const handleAudioBeforeUpload = (file) => {
+ const validationMessage = validateMeetingAudioFile(file, maxAudioSize, configService.formatFileSize.bind(configService));
+ if (validationMessage) {
+ message.warning(validationMessage);
+ return Upload.LIST_IGNORE;
+ }
+
+ setSelectedAudioFile(file);
+ return false;
+ };
+
+ const clearSelectedAudio = () => {
+ setSelectedAudioFile(null);
+ setAudioUploadProgress(0);
+ setAudioUploadMessage('');
+ };
+
const handleSubmit = async () => {
try {
const values = await form.validateFields();
@@ -76,7 +113,35 @@ const MeetingFormDrawer = ({ open, onClose, onSuccess, meetingId = null }) => {
} else {
const res = await apiClient.post(buildApiUrl(API_ENDPOINTS.MEETINGS.CREATE), payload);
if (res.code === '200') {
- message.success('会议创建成功');
+ const newMeetingId = res.data.meeting_id;
+ if (selectedAudioFile) {
+ setAudioUploading(true);
+ setAudioUploadProgress(0);
+ setAudioUploadMessage('正在上传音频文件...');
+ try {
+ await uploadMeetingAudio({
+ meetingId: newMeetingId,
+ file: selectedAudioFile,
+ promptId: values.prompt_id,
+ onUploadProgress: (progressEvent) => {
+ if (progressEvent.total) {
+ setAudioUploadProgress(Math.min(100, Math.round((progressEvent.loaded * 100) / progressEvent.total)));
+ }
+ setAudioUploadMessage('正在上传音频文件...');
+ },
+ });
+ setAudioUploadProgress(100);
+ setAudioUploadMessage('上传完成,正在启动转录任务...');
+ message.success('会议创建成功,音频已开始上传处理');
+ } catch (uploadError) {
+ message.warning(uploadError?.response?.data?.message || uploadError?.response?.data?.detail || '会议已创建,但音频上传失败,请在详情页重试');
+ } finally {
+ setAudioUploading(false);
+ }
+ } else {
+ message.success('会议创建成功');
+ }
+
onSuccess?.(res.data.meeting_id);
onClose();
return;
@@ -103,7 +168,7 @@ const MeetingFormDrawer = ({ open, onClose, onSuccess, meetingId = null }) => {
destroyOnClose
extra={
- } loading={loading} onClick={handleSubmit}>
+ } loading={loading || audioUploading} onClick={handleSubmit}>
{isEdit ? '保存修改' : '创建会议'}
@@ -138,9 +203,105 @@ const MeetingFormDrawer = ({ open, onClose, onSuccess, meetingId = null }) => {
-
-
-
+ {!isEdit ? (
+
+
+
+
+
+
+ 支持 {AUDIO_UPLOAD_ACCEPT.replace(/\./g, '').toUpperCase()};
+
音频文件最大 {configService.formatFileSize(maxAudioSize)}。
+
+
+
+ } disabled={audioUploading}>选择音频
+
+
+
+ {selectedAudioFile ? (
+
+
+
+
+ {selectedAudioFile.name}
+ {configService.formatFileSize(selectedAudioFile.size)}
+
+
+
} onClick={clearSelectedAudio} disabled={audioUploading}>
+ 移除
+
+
+ ) : (
+
+ 可在会议详情中补传。
+
+ )}
+
+ {audioUploading ? (
+
+
+ 音频上传中
+ {audioUploadProgress}%
+
+
+ {audioUploadMessage || '正在上传音频文件...'}
+
+
+
+ ) : null}
+
+
+
+ ) : null}
);
diff --git a/frontend/src/pages/CreateMeeting.jsx b/frontend/src/pages/CreateMeeting.jsx
index 60dd3b5..28ba9e6 100644
--- a/frontend/src/pages/CreateMeeting.jsx
+++ b/frontend/src/pages/CreateMeeting.jsx
@@ -1,21 +1,20 @@
import React, { useState, useEffect } from 'react';
import {
- Card, Form, Input, Button, DatePicker, Select, Space,
- Typography, App, Divider, Row, Col, Tag
+ Card, Form, Input, Button, DatePicker, Select,
+ Typography, App, Divider, Row, Col, Upload, Space, Progress
} from 'antd';
import {
- ArrowLeftOutlined, UserOutlined, CalendarOutlined,
- TeamOutlined, FileTextOutlined, PlusOutlined,
- UploadOutlined, SaveOutlined,
- VideoCameraAddOutlined, TagOutlined
+ ArrowLeftOutlined, UploadOutlined, SaveOutlined, DeleteOutlined,
+ VideoCameraAddOutlined, AudioOutlined
} from '@ant-design/icons';
import { useNavigate } from 'react-router-dom';
import dayjs from 'dayjs';
import apiClient from '../utils/apiClient';
import { buildApiUrl, API_ENDPOINTS } from '../config/api';
+import configService from '../utils/configService';
+import { AUDIO_UPLOAD_ACCEPT, uploadMeetingAudio, validateMeetingAudioFile } from '../services/meetingAudioService';
const { Title, Text } = Typography;
-const { TextArea } = Input;
const CreateMeeting = () => {
const navigate = useNavigate();
@@ -24,10 +23,16 @@ const CreateMeeting = () => {
const [loading, setLoading] = useState(false);
const [users, setUsers] = useState([]);
const [prompts, setPrompts] = useState([]);
+ const [selectedAudioFile, setSelectedAudioFile] = useState(null);
+ const [audioUploading, setAudioUploading] = useState(false);
+ const [audioUploadProgress, setAudioUploadProgress] = useState(0);
+ const [audioUploadMessage, setAudioUploadMessage] = useState('');
+ const [maxAudioSize, setMaxAudioSize] = useState(100 * 1024 * 1024);
useEffect(() => {
fetchUsers();
fetchPrompts();
+ loadAudioUploadConfig();
}, []);
const fetchUsers = async () => {
@@ -44,18 +49,74 @@ const CreateMeeting = () => {
} catch (e) {}
};
+ const loadAudioUploadConfig = async () => {
+ try {
+ const nextMaxAudioSize = await configService.getMaxAudioSize();
+ setMaxAudioSize(nextMaxAudioSize || 100 * 1024 * 1024);
+ } catch (error) {
+ setMaxAudioSize(100 * 1024 * 1024);
+ }
+ };
+
+ const handleAudioBeforeUpload = (file) => {
+ const validationMessage = validateMeetingAudioFile(file, maxAudioSize, configService.formatFileSize.bind(configService));
+ if (validationMessage) {
+ message.warning(validationMessage);
+ return Upload.LIST_IGNORE;
+ }
+
+ setSelectedAudioFile(file);
+ return false;
+ };
+
+ const clearSelectedAudio = () => {
+ setSelectedAudioFile(null);
+ setAudioUploadProgress(0);
+ setAudioUploadMessage('');
+ };
+
const onFinish = async (values) => {
setLoading(true);
try {
const payload = {
...values,
meeting_time: values.meeting_time.format('YYYY-MM-DD HH:mm:ss'),
- attendee_ids: values.attendee_ids
+ attendee_ids: values.attendee_ids,
+ tags: values.tags?.join(',') || ''
};
const res = await apiClient.post(buildApiUrl(API_ENDPOINTS.MEETINGS.CREATE), payload);
if (res.code === '200') {
- message.success('会议创建成功');
- navigate(`/meetings/${res.data.meeting_id}`);
+ const meetingId = res.data.meeting_id;
+
+ if (selectedAudioFile) {
+ setAudioUploading(true);
+ setAudioUploadProgress(0);
+ setAudioUploadMessage('正在上传音频文件...');
+ try {
+ await uploadMeetingAudio({
+ meetingId,
+ file: selectedAudioFile,
+ promptId: values.prompt_id,
+ onUploadProgress: (progressEvent) => {
+ if (progressEvent.total) {
+ setAudioUploadProgress(Math.min(100, Math.round((progressEvent.loaded * 100) / progressEvent.total)));
+ }
+ setAudioUploadMessage('正在上传音频文件...');
+ },
+ });
+ setAudioUploadProgress(100);
+ setAudioUploadMessage('上传完成,正在启动转录任务...');
+ message.success('会议创建成功,音频已开始上传处理');
+ } catch (uploadError) {
+ message.warning(uploadError.response?.data?.message || uploadError.response?.data?.detail || '会议已创建,但音频上传失败,请在详情页重试');
+ } finally {
+ setAudioUploading(false);
+ }
+ } else {
+ message.success('会议创建成功');
+ }
+
+ navigate(`/meetings/${meetingId}`);
}
} catch (error) {
message.error(error.response?.data?.message || error.response?.data?.detail || '创建失败');
@@ -102,15 +163,115 @@ const CreateMeeting = () => {
-
-
+
+
+
+
+
+ 上传会议音频
+
+ 创建后会自动沿用会议详情页同一套上传与转录逻辑。支持 {AUDIO_UPLOAD_ACCEPT.replace(/\./g, '').toUpperCase()},
+ 最大 {configService.formatFileSize(maxAudioSize)}。
+
+
+
+ } disabled={audioUploading}>选择音频
+
+
+
+ {selectedAudioFile ? (
+
+
+
+
+ {selectedAudioFile.name}
+ {configService.formatFileSize(selectedAudioFile.size)}
+
+
+
}
+ onClick={clearSelectedAudio}
+ disabled={audioUploading}
+ >
+ 移除
+
+
+ ) : (
+
+ 可选。若现在不上传,也可以创建后在会议详情中补传。
+
+ )}
+
+ {audioUploading ? (
+
+
+ 音频上传中
+ {audioUploadProgress}%
+
+
+ {audioUploadMessage || '正在上传音频文件...'}
+
+
+
+ ) : null}
+
+
- } loading={loading} block style={{ height: 50, fontSize: 16, borderRadius: 8 }}>
- 创建并进入详情
+ } loading={loading || audioUploading} block style={{ height: 50, fontSize: 16, borderRadius: 8 }}>
+ {selectedAudioFile ? '创建并上传音频' : '创建并进入详情'}
diff --git a/frontend/src/pages/EditMeeting.jsx b/frontend/src/pages/EditMeeting.jsx
index 546e48f..f4c2523 100644
--- a/frontend/src/pages/EditMeeting.jsx
+++ b/frontend/src/pages/EditMeeting.jsx
@@ -1,11 +1,10 @@
import React, { useState, useEffect } from 'react';
import {
- Card, Form, Input, Button, DatePicker, Select, Space,
+ Card, Form, Input, Button, DatePicker, Select,
Typography, App, Divider, Row, Col
} from 'antd';
import {
- ArrowLeftOutlined, TeamOutlined, SaveOutlined,
- VideoCameraAddOutlined, TagOutlined
+ ArrowLeftOutlined, SaveOutlined, VideoCameraAddOutlined
} from '@ant-design/icons';
import { useNavigate, useParams } from 'react-router-dom';
import dayjs from 'dayjs';
@@ -13,7 +12,6 @@ import apiClient from '../utils/apiClient';
import { buildApiUrl, API_ENDPOINTS } from '../config/api';
const { Title } = Typography;
-const { TextArea } = Input;
const EditMeeting = () => {
const { meeting_id } = useParams();
@@ -111,10 +109,6 @@ const EditMeeting = () => {
-
-
-
-
diff --git a/frontend/src/pages/MeetingDetails.jsx b/frontend/src/pages/MeetingDetails.jsx
index 481bc7e..10519ec 100644
--- a/frontend/src/pages/MeetingDetails.jsx
+++ b/frontend/src/pages/MeetingDetails.jsx
@@ -27,6 +27,8 @@ import tools from '../utils/tools';
import { buildApiUrl, API_ENDPOINTS } from '../config/api';
import QRCodeModal from '../components/QRCodeModal';
import MeetingFormDrawer from '../components/MeetingFormDrawer';
+import configService from '../utils/configService';
+import { AUDIO_UPLOAD_ACCEPT, uploadMeetingAudio, validateMeetingAudioFile } from '../services/meetingAudioService';
const { Title, Text } = Typography;
const { TextArea } = Input;
@@ -115,6 +117,7 @@ const MeetingDetails = ({ user }) => {
const [accessPasswordEnabled, setAccessPasswordEnabled] = useState(false);
const [accessPasswordDraft, setAccessPasswordDraft] = useState('');
const [savingAccessPassword, setSavingAccessPassword] = useState(false);
+ const [maxAudioSize, setMaxAudioSize] = useState(100 * 1024 * 1024);
// 转录编辑 Drawer
const [showTranscriptEditDrawer, setShowTranscriptEditDrawer] = useState(false);
@@ -159,6 +162,7 @@ const MeetingDetails = ({ user }) => {
useEffect(() => {
fetchMeetingDetails();
fetchTranscript();
+ loadAudioUploadConfig();
return () => {
if (statusCheckIntervalRef.current) clearInterval(statusCheckIntervalRef.current);
if (summaryPollIntervalRef.current) clearInterval(summaryPollIntervalRef.current);
@@ -166,6 +170,15 @@ const MeetingDetails = ({ user }) => {
};
}, [meeting_id]);
+ const loadAudioUploadConfig = async () => {
+ try {
+ const nextMaxAudioSize = await configService.getMaxAudioSize();
+ setMaxAudioSize(nextMaxAudioSize || 100 * 1024 * 1024);
+ } catch (error) {
+ setMaxAudioSize(100 * 1024 * 1024);
+ }
+ };
+
useEffect(() => {
if (!showSummaryDrawer) {
return;
@@ -490,27 +503,27 @@ const MeetingDetails = ({ user }) => {
};
const handleUploadAudio = async (file) => {
- const formData = new FormData();
- formData.append('audio_file', file);
- formData.append('meeting_id', meeting_id);
- formData.append('force_replace', 'true');
- if (meeting?.prompt_id) {
- formData.append('prompt_id', String(meeting.prompt_id));
- }
- if (selectedModelCode) {
- formData.append('model_code', selectedModelCode);
+ const validationMessage = validateMeetingAudioFile(file, maxAudioSize, configService.formatFileSize.bind(configService));
+ if (validationMessage) {
+ message.warning(validationMessage);
+ throw new Error(validationMessage);
}
+
setIsUploading(true);
setUploadProgress(0);
setUploadStatusMessage('正在上传音频文件...');
try {
- await apiClient.post(buildApiUrl(API_ENDPOINTS.MEETINGS.UPLOAD_AUDIO), formData, {
+ await uploadMeetingAudio({
+ meetingId: meeting_id,
+ file,
+ promptId: meeting?.prompt_id,
+ modelCode: selectedModelCode,
onUploadProgress: (progressEvent) => {
if (progressEvent.total) {
setUploadProgress(Math.min(100, Math.round((progressEvent.loaded * 100) / progressEvent.total)));
}
setUploadStatusMessage('正在上传音频文件...');
- }
+ },
});
setUploadProgress(100);
setUploadStatusMessage('上传完成,正在启动转录任务...');
@@ -944,6 +957,15 @@ const MeetingDetails = ({ user }) => {
{
+ const validationMessage = validateMeetingAudioFile(file, maxAudioSize, configService.formatFileSize.bind(configService));
+ if (validationMessage) {
+ message.warning(validationMessage);
+ return Upload.LIST_IGNORE;
+ }
+ return true;
+ }}
customRequest={async ({ file, onSuccess, onError }) => {
try {
await handleUploadAudio(file);
@@ -989,7 +1011,8 @@ const MeetingDetails = ({ user }) => {
}
}}
moreMenuItems={audioMoreMenuItems}
- emptyText="暂无音频,可通过右侧更多操作上传音频"
+ moreButtonDisabled={!isMeetingOwner}
+ emptyText="暂无音频,可通过'更多'上传音频"
/>
diff --git a/frontend/src/services/meetingAudioService.js b/frontend/src/services/meetingAudioService.js
new file mode 100644
index 0000000..d844872
--- /dev/null
+++ b/frontend/src/services/meetingAudioService.js
@@ -0,0 +1,48 @@
+import apiClient from '../utils/apiClient';
+import { buildApiUrl, API_ENDPOINTS } from '../config/api';
+
+export const AUDIO_UPLOAD_ACCEPT = '.mp3,.wav,.m4a,.mpeg,.mp4';
+const AUDIO_EXTENSIONS = ['.mp3', '.wav', '.m4a', '.mpeg', '.mp4'];
+
+export const validateMeetingAudioFile = (file, maxAudioSize, formatFileSize) => {
+ if (!file) {
+ return '请选择音频文件';
+ }
+
+ const fileName = String(file.name || '').toLowerCase();
+ const isAllowed = AUDIO_EXTENSIONS.some((ext) => fileName.endsWith(ext));
+ if (!isAllowed) {
+ return `仅支持 ${AUDIO_EXTENSIONS.join(' / ').toUpperCase().replace(/\./g, '')} 格式音频`;
+ }
+
+ if (maxAudioSize && file.size > maxAudioSize) {
+ const readableSize = formatFileSize ? formatFileSize(maxAudioSize) : `${Math.round(maxAudioSize / 1024 / 1024)} MB`;
+ return `音频大小不能超过 ${readableSize}`;
+ }
+
+ return null;
+};
+
+export const uploadMeetingAudio = async ({
+ meetingId,
+ file,
+ promptId,
+ modelCode,
+ onUploadProgress,
+}) => {
+ const formData = new FormData();
+ formData.append('audio_file', file);
+ formData.append('meeting_id', meetingId);
+
+ if (promptId) {
+ formData.append('prompt_id', String(promptId));
+ }
+
+ if (modelCode) {
+ formData.append('model_code', modelCode);
+ }
+
+ return apiClient.post(buildApiUrl(API_ENDPOINTS.MEETINGS.UPLOAD_AUDIO), formData, {
+ onUploadProgress,
+ });
+};
diff --git a/frontend/src/utils/configService.js b/frontend/src/utils/configService.js
index 2d59dc0..82d96dc 100644
--- a/frontend/src/utils/configService.js
+++ b/frontend/src/utils/configService.js
@@ -36,7 +36,7 @@ class ConfigService {
async loadConfigsFromServer() {
try {
- const response = await apiClient.get(buildApiUrl(API_ENDPOINTS.ADMIN.SYSTEM_CONFIG));
+ const response = await apiClient.get(buildApiUrl(API_ENDPOINTS.PUBLIC.SYSTEM_CONFIG));
return response.data;
} catch (error) {
console.warn('Failed to load system configs, using defaults:', error);
@@ -53,6 +53,10 @@ class ConfigService {
return configs.MAX_FILE_SIZE || 100 * 1024 * 1024;
}
+ async getMaxAudioSize() {
+ return this.getMaxFileSize();
+ }
+
async getMaxImageSize() {
const configs = await this.getConfigs();
return configs.MAX_IMAGE_SIZE || 10 * 1024 * 1024;