mirror of
https://github.com/open-webui/open-webui.git
synced 2026-10-24 05:44:07 +00:00
feat: add per-group knowledge base file count and size limits
Adds optional per-group (and global default) limits on the number of
files and maximum file size for knowledge base uploads, enforced both
in the backend and early in the frontend upload pipeline.
- `WorkspacePermissions` extended with `knowledge_max_count` and
`knowledge_max_size` (nullable int) so the group permissions endpoint
persists and returns these values
- `DEFAULT_PERMISSIONS` in `permissions.ts` gains the two nullable fields
- Group Permissions UI shows numeric inputs for both limits beneath the
Knowledge Access toggle (0 / empty = unlimited)
- `combine_permissions` extended to handle integer-valued permissions
using most-permissive semantics (0 = unlimited always wins, otherwise
max across groups)
- New `get_permission_value()` utility mirrors `has_permission` but
returns the raw value (int/bool/None) rather than a boolean
- `/api/config` resolves and exposes `knowledge.max_count` and
`knowledge.max_size` per-user so the frontend can gate uploads before
any processing begins
- `KnowledgeBase.svelte` and `Models/Knowledge.svelte` check limits
before calling `uploadFile`, preventing unnecessary text-extraction
work on oversized files
- Backend enforces limits in both `/{id}/file/add` and
`/{id}/files/batch/add`; admins always bypass
This commit is contained in:
parent
f162d4de90
commit
464a2dd58d
13 changed files with 346 additions and 25 deletions
|
|
@ -1357,6 +1357,24 @@ USER_PERMISSIONS_WORKSPACE_KNOWLEDGE_ACCESS = (
|
|||
os.environ.get('USER_PERMISSIONS_WORKSPACE_KNOWLEDGE_ACCESS', 'False').lower() == 'true'
|
||||
)
|
||||
|
||||
_knowledge_max_count_raw = os.environ.get('USER_PERMISSIONS_WORKSPACE_KNOWLEDGE_MAX_COUNT', '').strip()
|
||||
if _knowledge_max_count_raw:
|
||||
_knowledge_max_count_val = int(_knowledge_max_count_raw)
|
||||
if _knowledge_max_count_val < 0:
|
||||
raise ValueError(f"USER_PERMISSIONS_WORKSPACE_KNOWLEDGE_MAX_COUNT must be >= 0, got {_knowledge_max_count_val}")
|
||||
USER_PERMISSIONS_WORKSPACE_KNOWLEDGE_MAX_COUNT = _knowledge_max_count_val
|
||||
else:
|
||||
USER_PERMISSIONS_WORKSPACE_KNOWLEDGE_MAX_COUNT = None
|
||||
|
||||
_knowledge_max_size_raw = os.environ.get('USER_PERMISSIONS_WORKSPACE_KNOWLEDGE_MAX_SIZE', '').strip()
|
||||
if _knowledge_max_size_raw:
|
||||
_knowledge_max_size_val = int(_knowledge_max_size_raw)
|
||||
if _knowledge_max_size_val < 0:
|
||||
raise ValueError(f"USER_PERMISSIONS_WORKSPACE_KNOWLEDGE_MAX_SIZE must be >= 0, got {_knowledge_max_size_val}")
|
||||
USER_PERMISSIONS_WORKSPACE_KNOWLEDGE_MAX_SIZE = _knowledge_max_size_val
|
||||
else:
|
||||
USER_PERMISSIONS_WORKSPACE_KNOWLEDGE_MAX_SIZE = None
|
||||
|
||||
USER_PERMISSIONS_WORKSPACE_PROMPTS_ACCESS = (
|
||||
os.environ.get('USER_PERMISSIONS_WORKSPACE_PROMPTS_ACCESS', 'False').lower() == 'true'
|
||||
)
|
||||
|
|
@ -1534,6 +1552,8 @@ DEFAULT_USER_PERMISSIONS = {
|
|||
'workspace': {
|
||||
'models': USER_PERMISSIONS_WORKSPACE_MODELS_ACCESS,
|
||||
'knowledge': USER_PERMISSIONS_WORKSPACE_KNOWLEDGE_ACCESS,
|
||||
'knowledge_max_count': USER_PERMISSIONS_WORKSPACE_KNOWLEDGE_MAX_COUNT,
|
||||
'knowledge_max_size': USER_PERMISSIONS_WORKSPACE_KNOWLEDGE_MAX_SIZE,
|
||||
'prompts': USER_PERMISSIONS_WORKSPACE_PROMPTS_ACCESS,
|
||||
'tools': USER_PERMISSIONS_WORKSPACE_TOOLS_ACCESS,
|
||||
'skills': USER_PERMISSIONS_WORKSPACE_SKILLS_ACCESS,
|
||||
|
|
|
|||
|
|
@ -916,7 +916,7 @@ app.state.config.ENABLE_EVALUATION_ARENA_MODELS = ENABLE_EVALUATION_ARENA_MODELS
|
|||
app.state.config.EVALUATION_ARENA_MODELS = EVALUATION_ARENA_MODELS
|
||||
|
||||
# Migrate legacy access_control → access_grants on boot
|
||||
from open_webui.utils.access_control import migrate_access_control
|
||||
from open_webui.utils.access_control import migrate_access_control, get_permission_value
|
||||
|
||||
connections = app.state.config.TOOL_SERVER_CONNECTIONS
|
||||
if any('access_control' in c.get('config', {}) for c in connections):
|
||||
|
|
@ -1387,6 +1387,18 @@ app.add_middleware(AuthTokenMiddleware, fastapi_app=app)
|
|||
app.add_middleware(WebsocketUpgradeGuardMiddleware)
|
||||
|
||||
|
||||
async def _resolve_knowledge_limit(user, permission_key: str, user_permissions: dict):
|
||||
"""Return the effective knowledge file limit for a user.
|
||||
|
||||
Admin users get None (unlimited). For regular users, group/default permissions
|
||||
are checked; 0 means unlimited (returns None).
|
||||
"""
|
||||
if user is None or user.role == 'admin':
|
||||
return None
|
||||
value = await get_permission_value(user.id, permission_key, user_permissions)
|
||||
return None if (value is None or value == 0) else value
|
||||
|
||||
|
||||
app.add_middleware(
|
||||
CORSMiddleware,
|
||||
allow_origins=CORS_ALLOW_ORIGIN,
|
||||
|
|
@ -2282,6 +2294,16 @@ async def get_app_config(request: Request):
|
|||
'height': app.state.config.FILE_IMAGE_COMPRESSION_HEIGHT,
|
||||
},
|
||||
},
|
||||
'knowledge': {
|
||||
'max_size': await _resolve_knowledge_limit(
|
||||
user, 'workspace.knowledge_max_size',
|
||||
app.state.config.USER_PERMISSIONS,
|
||||
),
|
||||
'max_count': await _resolve_knowledge_limit(
|
||||
user, 'workspace.knowledge_max_count',
|
||||
app.state.config.USER_PERMISSIONS,
|
||||
),
|
||||
},
|
||||
'permissions': {**app.state.config.USER_PERMISSIONS},
|
||||
'google_drive': {
|
||||
'client_id': GOOGLE_DRIVE_CLIENT_ID.value,
|
||||
|
|
|
|||
|
|
@ -537,6 +537,18 @@ class KnowledgeTable:
|
|||
except Exception:
|
||||
return []
|
||||
|
||||
async def get_file_count_by_id(
|
||||
self, knowledge_id: str, db: Optional[AsyncSession] = None
|
||||
) -> int:
|
||||
try:
|
||||
async with get_async_db_context(db) as db:
|
||||
result = await db.execute(
|
||||
select(func.count()).select_from(KnowledgeFile).filter_by(knowledge_id=knowledge_id)
|
||||
)
|
||||
return result.scalar() or 0
|
||||
except Exception:
|
||||
return 0
|
||||
|
||||
async def add_file_to_knowledge_by_id(
|
||||
self,
|
||||
knowledge_id: str,
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ from open_webui.storage.provider import Storage
|
|||
|
||||
from open_webui.constants import ERROR_MESSAGES
|
||||
from open_webui.utils.auth import get_verified_user, get_admin_user
|
||||
from open_webui.utils.access_control import has_permission, filter_allowed_access_grants
|
||||
from open_webui.utils.access_control import has_permission, filter_allowed_access_grants, get_permission_value
|
||||
from open_webui.models.access_grants import AccessGrants
|
||||
|
||||
|
||||
|
|
@ -656,6 +656,29 @@ async def add_file_to_knowledge_by_id(
|
|||
detail=ERROR_MESSAGES.FILE_NOT_PROCESSED,
|
||||
)
|
||||
|
||||
if user.role != 'admin':
|
||||
max_count = await get_permission_value(
|
||||
user.id, 'workspace.knowledge_max_count',
|
||||
request.app.state.config.USER_PERMISSIONS, db=db,
|
||||
)
|
||||
if max_count is not None and max_count != 0:
|
||||
current_count = await Knowledges.get_file_count_by_id(id, db=db)
|
||||
if current_count >= max_count:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
detail=f'Knowledge base file limit reached ({max_count} files maximum).',
|
||||
)
|
||||
|
||||
max_size = await get_permission_value(
|
||||
user.id, 'workspace.knowledge_max_size',
|
||||
request.app.state.config.USER_PERMISSIONS, db=db,
|
||||
)
|
||||
if max_size is not None and max_size != 0 and file.meta and file.meta.get('size', 0) > max_size * 1024 * 1024:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
detail=f'File size exceeds the {max_size} MB limit for knowledge base uploads.',
|
||||
)
|
||||
|
||||
# Add content to the vector database
|
||||
try:
|
||||
await process_file(
|
||||
|
|
@ -1008,6 +1031,33 @@ async def add_files_to_knowledge_batch(
|
|||
file_ids = [form.file_id for form in form_data]
|
||||
files = await Files.get_files_by_ids(file_ids, db=db)
|
||||
|
||||
if user.role != 'admin':
|
||||
max_count = await get_permission_value(
|
||||
user.id, 'workspace.knowledge_max_count',
|
||||
request.app.state.config.USER_PERMISSIONS, db=db,
|
||||
)
|
||||
if max_count is not None and max_count != 0:
|
||||
current_count = await Knowledges.get_file_count_by_id(id, db=db)
|
||||
if current_count + len(files) > max_count:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
detail=f'Knowledge base file limit exceeded: adding {len(files)} file(s) would exceed the {max_count} file maximum (currently {current_count}).',
|
||||
)
|
||||
|
||||
max_size = await get_permission_value(
|
||||
user.id, 'workspace.knowledge_max_size',
|
||||
request.app.state.config.USER_PERMISSIONS, db=db,
|
||||
)
|
||||
if max_size is not None and max_size != 0:
|
||||
oversized = [
|
||||
f.filename for f in files if f.meta and f.meta.get('size', 0) > max_size * 1024 * 1024
|
||||
]
|
||||
if oversized:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
detail=f'File(s) exceed the {max_size} MB limit for knowledge base uploads: {", ".join(oversized)}',
|
||||
)
|
||||
|
||||
# Verify all requested files were found
|
||||
found_ids = {file.id for file in files}
|
||||
missing_ids = [fid for fid in file_ids if fid not in found_ids]
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import io
|
|||
|
||||
from fastapi import APIRouter, Depends, HTTPException, Request, status
|
||||
from fastapi.responses import Response, StreamingResponse, FileResponse
|
||||
from pydantic import BaseModel, ConfigDict
|
||||
from pydantic import BaseModel, ConfigDict, Field
|
||||
|
||||
|
||||
from open_webui.models.auths import Auths
|
||||
|
|
@ -169,6 +169,8 @@ async def get_user_permissisions(
|
|||
class WorkspacePermissions(BaseModel):
|
||||
models: bool = False
|
||||
knowledge: bool = False
|
||||
knowledge_max_count: Optional[int] = Field(default=None, ge=0)
|
||||
knowledge_max_size: Optional[int] = Field(default=None, ge=0)
|
||||
prompts: bool = False
|
||||
tools: bool = False
|
||||
skills: bool = False
|
||||
|
|
|
|||
5
backend/open_webui/test/util/conftest.py
Normal file
5
backend/open_webui/test/util/conftest.py
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
import os
|
||||
|
||||
# Set required env vars before any open_webui modules are imported during collection.
|
||||
if not os.environ.get('WEBUI_SECRET_KEY'):
|
||||
os.environ['WEBUI_SECRET_KEY'] = 'test-secret-key-for-unit-tests'
|
||||
125
backend/open_webui/test/util/test_access_control.py
Normal file
125
backend/open_webui/test/util/test_access_control.py
Normal file
|
|
@ -0,0 +1,125 @@
|
|||
from types import SimpleNamespace
|
||||
from unittest.mock import AsyncMock, patch
|
||||
|
||||
import pytest
|
||||
|
||||
from open_webui.utils.access_control import get_permission_value, get_permissions
|
||||
|
||||
|
||||
def _group(permissions: dict):
|
||||
return SimpleNamespace(permissions=permissions)
|
||||
|
||||
|
||||
GROUPS_PATH = 'open_webui.utils.access_control.Groups.get_groups_by_member_id'
|
||||
|
||||
|
||||
class TestCombinePermissionsIntegers:
|
||||
"""get_permissions merges integer-valued permissions using most-permissive semantics."""
|
||||
|
||||
@pytest.mark.anyio
|
||||
@patch(GROUPS_PATH, new_callable=AsyncMock)
|
||||
async def test_single_group_integer_limit(self, mock_groups):
|
||||
mock_groups.return_value = [_group({'workspace': {'knowledge_max_count': 10}})]
|
||||
result = await get_permissions('user1', {'workspace': {'knowledge_max_count': None}})
|
||||
assert result['workspace']['knowledge_max_count'] == 10
|
||||
|
||||
@pytest.mark.anyio
|
||||
@patch(GROUPS_PATH, new_callable=AsyncMock)
|
||||
async def test_most_permissive_takes_higher_limit(self, mock_groups):
|
||||
mock_groups.return_value = [
|
||||
_group({'workspace': {'knowledge_max_count': 10}}),
|
||||
_group({'workspace': {'knowledge_max_count': 25}}),
|
||||
]
|
||||
result = await get_permissions('user1', {'workspace': {'knowledge_max_count': None}})
|
||||
assert result['workspace']['knowledge_max_count'] == 25
|
||||
|
||||
@pytest.mark.anyio
|
||||
@patch(GROUPS_PATH, new_callable=AsyncMock)
|
||||
async def test_zero_means_unlimited_always_wins(self, mock_groups):
|
||||
mock_groups.return_value = [
|
||||
_group({'workspace': {'knowledge_max_count': 10}}),
|
||||
_group({'workspace': {'knowledge_max_count': 0}}),
|
||||
]
|
||||
result = await get_permissions('user1', {'workspace': {'knowledge_max_count': None}})
|
||||
assert result['workspace']['knowledge_max_count'] == 0
|
||||
|
||||
@pytest.mark.anyio
|
||||
@patch(GROUPS_PATH, new_callable=AsyncMock)
|
||||
async def test_none_group_value_is_skipped(self, mock_groups):
|
||||
mock_groups.return_value = [
|
||||
_group({'workspace': {'knowledge_max_count': None}}),
|
||||
_group({'workspace': {'knowledge_max_count': 15}}),
|
||||
]
|
||||
result = await get_permissions('user1', {'workspace': {'knowledge_max_count': None}})
|
||||
assert result['workspace']['knowledge_max_count'] == 15
|
||||
|
||||
@pytest.mark.anyio
|
||||
@patch(GROUPS_PATH, new_callable=AsyncMock)
|
||||
async def test_boolean_permissions_unaffected(self, mock_groups):
|
||||
mock_groups.return_value = [
|
||||
_group({'workspace': {'knowledge': True, 'knowledge_max_count': 10}}),
|
||||
_group({'workspace': {'knowledge': False, 'knowledge_max_count': 5}}),
|
||||
]
|
||||
result = await get_permissions('user1', {'workspace': {'knowledge': False, 'knowledge_max_count': None}})
|
||||
assert result['workspace']['knowledge'] is True
|
||||
assert result['workspace']['knowledge_max_count'] == 10
|
||||
|
||||
|
||||
class TestGetPermissionValue:
|
||||
"""get_permission_value returns the raw resolved value for a permission key."""
|
||||
|
||||
@pytest.mark.anyio
|
||||
@patch(GROUPS_PATH, new_callable=AsyncMock)
|
||||
async def test_returns_none_when_no_groups_and_no_default(self, mock_groups):
|
||||
mock_groups.return_value = []
|
||||
assert await get_permission_value('user1', 'workspace.knowledge_max_count') is None
|
||||
|
||||
@pytest.mark.anyio
|
||||
@patch(GROUPS_PATH, new_callable=AsyncMock)
|
||||
async def test_falls_back_to_default_permissions(self, mock_groups):
|
||||
mock_groups.return_value = []
|
||||
result = await get_permission_value(
|
||||
'user1', 'workspace.knowledge_max_count',
|
||||
{'workspace': {'knowledge_max_count': 20}},
|
||||
)
|
||||
assert result == 20
|
||||
|
||||
@pytest.mark.anyio
|
||||
@patch(GROUPS_PATH, new_callable=AsyncMock)
|
||||
async def test_group_value_overrides_default(self, mock_groups):
|
||||
mock_groups.return_value = [_group({'workspace': {'knowledge_max_count': 5}})]
|
||||
result = await get_permission_value(
|
||||
'user1', 'workspace.knowledge_max_count',
|
||||
{'workspace': {'knowledge_max_count': 20}},
|
||||
)
|
||||
assert result == 5
|
||||
|
||||
@pytest.mark.anyio
|
||||
@patch(GROUPS_PATH, new_callable=AsyncMock)
|
||||
async def test_most_permissive_across_groups(self, mock_groups):
|
||||
mock_groups.return_value = [
|
||||
_group({'workspace': {'knowledge_max_count': 5}}),
|
||||
_group({'workspace': {'knowledge_max_count': 30}}),
|
||||
]
|
||||
assert await get_permission_value('user1', 'workspace.knowledge_max_count') == 30
|
||||
|
||||
@pytest.mark.anyio
|
||||
@patch(GROUPS_PATH, new_callable=AsyncMock)
|
||||
async def test_zero_unlimited_wins_over_any_limit(self, mock_groups):
|
||||
mock_groups.return_value = [
|
||||
_group({'workspace': {'knowledge_max_count': 5}}),
|
||||
_group({'workspace': {'knowledge_max_count': 0}}),
|
||||
]
|
||||
assert await get_permission_value('user1', 'workspace.knowledge_max_count') == 0
|
||||
|
||||
@pytest.mark.anyio
|
||||
@patch(GROUPS_PATH, new_callable=AsyncMock)
|
||||
async def test_missing_key_returns_none(self, mock_groups):
|
||||
mock_groups.return_value = [_group({'workspace': {'knowledge': True}})]
|
||||
assert await get_permission_value('user1', 'workspace.knowledge_max_count') is None
|
||||
|
||||
@pytest.mark.anyio
|
||||
@patch(GROUPS_PATH, new_callable=AsyncMock)
|
||||
async def test_size_limit_key(self, mock_groups):
|
||||
mock_groups.return_value = [_group({'workspace': {'knowledge_max_size': 50}})]
|
||||
assert await get_permission_value('user1', 'workspace.knowledge_max_size') == 50
|
||||
|
|
@ -42,10 +42,21 @@ async def get_permissions(
|
|||
def combine_permissions(permissions: dict[str, Any], group_permissions: dict[str, Any]) -> dict[str, Any]:
|
||||
"""Combine permissions from multiple groups by taking the most permissive value."""
|
||||
for key, value in group_permissions.items():
|
||||
if value is None:
|
||||
continue # None means "not configured for this group", skip
|
||||
if isinstance(value, dict):
|
||||
if key not in permissions:
|
||||
permissions[key] = {}
|
||||
permissions[key] = combine_permissions(permissions[key], value)
|
||||
elif isinstance(value, int) and not isinstance(value, bool):
|
||||
if key not in permissions or permissions[key] is None:
|
||||
permissions[key] = value
|
||||
elif isinstance(permissions[key], int) and not isinstance(permissions[key], bool):
|
||||
# 0 = unlimited (most permissive), otherwise take the highest limit
|
||||
if permissions[key] == 0 or value == 0:
|
||||
permissions[key] = 0
|
||||
else:
|
||||
permissions[key] = max(permissions[key], value)
|
||||
else:
|
||||
if key not in permissions:
|
||||
permissions[key] = value
|
||||
|
|
@ -104,6 +115,53 @@ async def has_permission(
|
|||
return get_permission(default_permissions, permission_hierarchy)
|
||||
|
||||
|
||||
async def get_permission_value(
|
||||
user_id: str,
|
||||
permission_key: str,
|
||||
default_permissions: dict[str, Any] = {},
|
||||
db: AsyncSession | None = None,
|
||||
) -> Any:
|
||||
"""
|
||||
Return the raw value of a permission for a user (int, bool, None, etc.).
|
||||
|
||||
For integer-valued permissions across multiple groups the most permissive
|
||||
value is returned: 0 means unlimited (always wins), otherwise the maximum.
|
||||
Returns None when no group or default has a value for the key.
|
||||
"""
|
||||
|
||||
def traverse(permissions: dict[str, Any], keys: list[str]) -> Any:
|
||||
for key in keys:
|
||||
if not isinstance(permissions, dict) or key not in permissions:
|
||||
return None
|
||||
permissions = permissions[key]
|
||||
return permissions
|
||||
|
||||
permission_hierarchy = permission_key.split('.')
|
||||
user_groups = await Groups.get_groups_by_member_id(user_id, db=db)
|
||||
|
||||
best: Any = None
|
||||
for group in user_groups:
|
||||
value = traverse(group.permissions or {}, permission_hierarchy)
|
||||
if value is None:
|
||||
continue
|
||||
if isinstance(value, int) and not isinstance(value, bool):
|
||||
if best is None:
|
||||
best = value
|
||||
elif best == 0 or value == 0:
|
||||
best = 0 # 0 = unlimited, always wins
|
||||
else:
|
||||
best = max(best, value)
|
||||
elif value and best is None:
|
||||
best = value
|
||||
|
||||
if best is not None:
|
||||
return best
|
||||
|
||||
# Fall back to default permissions
|
||||
merged = fill_missing_permissions({}, default_permissions)
|
||||
return traverse(merged, permission_hierarchy)
|
||||
|
||||
|
||||
async def has_access(
|
||||
user_id: str,
|
||||
permission: str = 'read',
|
||||
|
|
|
|||
|
|
@ -81,7 +81,34 @@
|
|||
</div>
|
||||
<Switch bind:state={permissions.workspace.knowledge} />
|
||||
</div>
|
||||
{#if defaultPermissions?.workspace?.knowledge && !permissions.workspace.knowledge}
|
||||
{#if permissions.workspace.knowledge}
|
||||
<div class="ml-2 flex flex-col gap-2 pt-0.5 pb-1">
|
||||
<div class="flex w-full justify-between">
|
||||
<div class="self-center text-xs">
|
||||
{$i18n.t('Max Files per Knowledge Base')}
|
||||
</div>
|
||||
<input
|
||||
class="w-20 text-xs text-right bg-transparent outline-hidden border-b border-gray-300 dark:border-gray-600"
|
||||
type="number"
|
||||
min="0"
|
||||
placeholder={$i18n.t('Unlimited')}
|
||||
bind:value={permissions.workspace.knowledge_max_count}
|
||||
/>
|
||||
</div>
|
||||
<div class="flex w-full justify-between">
|
||||
<div class="self-center text-xs">
|
||||
{$i18n.t('Max File Size (MB)')}
|
||||
</div>
|
||||
<input
|
||||
class="w-20 text-xs text-right bg-transparent outline-hidden border-b border-gray-300 dark:border-gray-600"
|
||||
type="number"
|
||||
min="0"
|
||||
placeholder={$i18n.t('Unlimited')}
|
||||
bind:value={permissions.workspace.knowledge_max_size}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
{:else if defaultPermissions?.workspace?.knowledge}
|
||||
<div>
|
||||
<div class="text-xs text-gray-500">
|
||||
{$i18n.t('This is a default user permission and will remain enabled.')}
|
||||
|
|
|
|||
|
|
@ -281,17 +281,19 @@
|
|||
return null;
|
||||
}
|
||||
|
||||
if (
|
||||
($config?.file?.max_size ?? null) !== null &&
|
||||
file.size > ($config?.file?.max_size ?? 0) * 1024 * 1024
|
||||
) {
|
||||
console.log('File exceeds max size limit:', {
|
||||
fileSize: file.size,
|
||||
maxSize: ($config?.file?.max_size ?? 0) * 1024 * 1024
|
||||
});
|
||||
const knowledgeMaxSize = $config?.knowledge?.max_size ?? null;
|
||||
if (knowledgeMaxSize !== null && file.size > knowledgeMaxSize * 1024 * 1024) {
|
||||
toast.error(
|
||||
$i18n.t(`File size should not exceed {{maxSize}} MB.`, {
|
||||
maxSize: $config?.file?.max_size
|
||||
$i18n.t(`File size should not exceed {{maxSize}} MB.`, { maxSize: knowledgeMaxSize })
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
const knowledgeMaxCount = $config?.knowledge?.max_count ?? null;
|
||||
if (knowledgeMaxCount !== null && (fileItemsTotal ?? 0) >= knowledgeMaxCount) {
|
||||
toast.error(
|
||||
$i18n.t(`Knowledge base file limit reached ({{maxCount}} files maximum).`, {
|
||||
maxCount: knowledgeMaxCount
|
||||
})
|
||||
);
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -107,18 +107,10 @@
|
|||
extension: file.name.split('.').at(-1)
|
||||
});
|
||||
|
||||
if (
|
||||
($config?.file?.max_size ?? null) !== null &&
|
||||
file.size > ($config?.file?.max_size ?? 0) * 1024 * 1024
|
||||
) {
|
||||
console.log('File exceeds max size limit:', {
|
||||
fileSize: file.size,
|
||||
maxSize: ($config?.file?.max_size ?? 0) * 1024 * 1024
|
||||
});
|
||||
const knowledgeMaxSize = $config?.knowledge?.max_size ?? null;
|
||||
if (knowledgeMaxSize !== null && file.size > knowledgeMaxSize * 1024 * 1024) {
|
||||
toast.error(
|
||||
$i18n.t(`File size should not exceed {{maxSize}} MB.`, {
|
||||
maxSize: $config?.file?.max_size
|
||||
})
|
||||
$i18n.t(`File size should not exceed {{maxSize}} MB.`, { maxSize: knowledgeMaxSize })
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@ export const DEFAULT_PERMISSIONS = {
|
|||
workspace: {
|
||||
models: false,
|
||||
knowledge: false,
|
||||
knowledge_max_count: null as number | null,
|
||||
knowledge_max_size: null as number | null,
|
||||
prompts: false,
|
||||
tools: false,
|
||||
skills: false,
|
||||
|
|
|
|||
|
|
@ -1166,6 +1166,7 @@
|
|||
"Keyboard Shortcuts": "",
|
||||
"Knowledge": "",
|
||||
"Knowledge Access": "",
|
||||
"Knowledge base file limit reached ({{maxCount}} files maximum).": "",
|
||||
"Knowledge Base": "",
|
||||
"Knowledge created successfully.": "",
|
||||
"Knowledge deleted successfully.": "",
|
||||
|
|
@ -1252,6 +1253,8 @@
|
|||
"March": "",
|
||||
"Markdown": "",
|
||||
"Markdown Header Text Splitter": "",
|
||||
"Max File Size (MB)": "",
|
||||
"Max Files per Knowledge Base": "",
|
||||
"Max Speakers": "",
|
||||
"Max Upload Count": "",
|
||||
"Max Upload Size": "",
|
||||
|
|
@ -2108,6 +2111,7 @@
|
|||
"Underline": "",
|
||||
"Unknown": "",
|
||||
"Unknown User": "",
|
||||
"Unlimited": "",
|
||||
"Unloads {{FROM_NOW}}": "",
|
||||
"Unlock mysteries": "",
|
||||
"Unpin": "",
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue